@attest-it/core 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -27,6 +27,9 @@ async function runOpenSSL(args, stdin) {
27
27
  stderr
28
28
  });
29
29
  });
30
+ if (stdin) {
31
+ child.stdin.write(stdin);
32
+ }
30
33
  child.stdin.end();
31
34
  });
32
35
  }
@@ -62,6 +65,14 @@ function getDefaultPrivateKeyPath() {
62
65
  function getDefaultPublicKeyPath() {
63
66
  return path.join(process.cwd(), "attest-it-public.pem");
64
67
  }
68
+ function getDefaultYubiKeyEncryptedKeyPath() {
69
+ const homeDir = os.homedir();
70
+ if (process.platform === "win32") {
71
+ const appData = process.env.APPDATA ?? path.join(homeDir, "AppData", "Roaming");
72
+ return path.join(appData, "attest-it", "yubikey-private.enc");
73
+ }
74
+ return path.join(homeDir, ".config", "attest-it", "yubikey-private.enc");
75
+ }
65
76
  async function ensureDir(dirPath) {
66
77
  try {
67
78
  await fs.mkdir(dirPath, { recursive: true });
@@ -92,7 +103,8 @@ async function generateKeyPair(options = {}) {
92
103
  const {
93
104
  privatePath = getDefaultPrivateKeyPath(),
94
105
  publicPath = getDefaultPublicKeyPath(),
95
- force = false
106
+ force = false,
107
+ passphrase
96
108
  } = options;
97
109
  const privateExists = await fileExists(privatePath);
98
110
  const publicExists = await fileExists(publicPath);
@@ -116,12 +128,25 @@ async function generateKeyPair(options = {}) {
116
128
  "-out",
117
129
  privatePath
118
130
  ];
119
- const genResult = await runOpenSSL(genArgs);
131
+ if (passphrase) {
132
+ genArgs.push("-aes256", "-pass", "stdin");
133
+ }
134
+ const genResult = await runOpenSSL(
135
+ genArgs,
136
+ passphrase ? Buffer.from(passphrase + "\n") : void 0
137
+ );
120
138
  if (genResult.exitCode !== 0) {
121
139
  throw new Error(`Failed to generate private key: ${genResult.stderr}`);
122
140
  }
123
141
  await setKeyPermissions(privatePath);
124
- const pubResult = await runOpenSSL(["pkey", "-in", privatePath, "-pubout", "-out", publicPath]);
142
+ const pubArgs = ["pkey", "-in", privatePath, "-pubout", "-out", publicPath];
143
+ if (passphrase) {
144
+ pubArgs.push("-passin", "stdin");
145
+ }
146
+ const pubResult = await runOpenSSL(
147
+ pubArgs,
148
+ passphrase ? Buffer.from(passphrase + "\n") : void 0
149
+ );
125
150
  if (pubResult.exitCode !== 0) {
126
151
  throw new Error(`Failed to extract public key: ${pubResult.stderr}`);
127
152
  }
@@ -136,7 +161,7 @@ async function generateKeyPair(options = {}) {
136
161
  }
137
162
  async function sign(options) {
138
163
  await ensureOpenSSLAvailable();
139
- const { privateKeyPath, keyProvider, keyRef, data } = options;
164
+ const { privateKeyPath, keyProvider, keyRef, data, passphrase } = options;
140
165
  let effectiveKeyPath;
141
166
  let cleanup;
142
167
  if (keyProvider && keyRef) {
@@ -161,9 +186,22 @@ async function sign(options) {
161
186
  const sigFile = path.join(tmpDir, "sig.bin");
162
187
  try {
163
188
  await fs.writeFile(dataFile, processBuffer);
164
- const signArgs = ["dgst", "-sha256", "-sign", effectiveKeyPath, "-out", sigFile, dataFile];
165
- const result = await runOpenSSL(signArgs);
189
+ const signArgs = ["dgst", "-sha256"];
190
+ if (passphrase) {
191
+ signArgs.push("-passin", "stdin");
192
+ }
193
+ signArgs.push("-sign", effectiveKeyPath, "-out", sigFile, dataFile);
194
+ const result = await runOpenSSL(
195
+ signArgs,
196
+ passphrase ? Buffer.from(passphrase + "\n") : void 0
197
+ );
166
198
  if (result.exitCode !== 0) {
199
+ const stderr = result.stderr.toLowerCase();
200
+ if (stderr.includes("bad decrypt") || stderr.includes("bad password") || stderr.includes("unable to load key") || stderr.includes("wrong password")) {
201
+ throw new Error(
202
+ "Failed to decrypt private key. Please check that the passphrase is correct."
203
+ );
204
+ }
167
205
  throw new Error(`Failed to sign data: ${result.stderr}`);
168
206
  }
169
207
  const sigBuffer = await fs.readFile(sigFile);
@@ -221,6 +259,6 @@ async function setKeyPermissions(keyPath) {
221
259
  }
222
260
  }
223
261
 
224
- export { checkOpenSSL, generateKeyPair, getDefaultPrivateKeyPath, getDefaultPublicKeyPath, setKeyPermissions, sign, verify };
225
- //# sourceMappingURL=chunk-VC3BBBBO.js.map
226
- //# sourceMappingURL=chunk-VC3BBBBO.js.map
262
+ export { checkOpenSSL, generateKeyPair, getDefaultPrivateKeyPath, getDefaultPublicKeyPath, getDefaultYubiKeyEncryptedKeyPath, setKeyPermissions, sign, verify };
263
+ //# sourceMappingURL=chunk-FGYLU2HL.js.map
264
+ //# sourceMappingURL=chunk-FGYLU2HL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/crypto.ts"],"names":[],"mappings":"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","file":"chunk-FGYLU2HL.js","sourcesContent":["/**\n * Cryptographic utilities for key generation, signing, and verification.\n *\n * @remarks\n * This module provides cryptographic operations using OpenSSL for key management\n * and signature verification. It uses RSA-2048 with SHA-256 for signatures,\n * which is universally supported across all OpenSSL and LibreSSL versions.\n *\n * @packageDocumentation\n */\n\nimport { spawn } from 'node:child_process'\nimport * as fs from 'node:fs/promises'\nimport * as path from 'node:path'\nimport * as os from 'node:os'\n\n/**\n * Paths to a generated keypair.\n * @public\n */\nexport interface KeyPaths {\n /** Path to the private key file */\n privatePath: string\n /** Path to the public key file */\n publicPath: string\n}\n\n/**\n * Options for key generation.\n * @public\n */\nexport interface KeygenOptions {\n /** Path for private key (default: OS-specific config dir) */\n privatePath?: string\n /** Path for public key (default: repo root) */\n publicPath?: string\n /** Overwrite existing keys (default: false) */\n force?: boolean\n /** Passphrase to encrypt the private key with AES-256 (optional) */\n passphrase?: string\n}\n\n/**\n * Options for signing data.\n * @public\n */\nexport interface SignOptions {\n /** Path to the private key file (legacy) */\n privateKeyPath?: string\n /** Key provider to use for retrieving the private key */\n keyProvider?: import('./key-provider/types.js').KeyProvider\n /** Key reference for the provider */\n keyRef?: string\n /** Data to sign (string or Buffer) */\n data: string | Buffer\n /** Passphrase for encrypted private keys (optional) */\n passphrase?: string\n}\n\n/**\n * Options for verifying signatures.\n * @public\n */\nexport interface VerifyOptions {\n /** Path to the public key file */\n publicKeyPath: string\n /** Original data that was signed */\n data: string | Buffer\n /** Base64-encoded signature to verify */\n signature: string\n}\n\n/**\n * Result from spawning an OpenSSL process.\n * @internal\n */\ninterface SpawnResult {\n /** Process exit code */\n exitCode: number\n /** Standard output as Buffer */\n stdout: Buffer\n /** Standard error as string */\n stderr: string\n}\n\n/**\n * Run OpenSSL with the given arguments.\n * @param args - Command-line arguments for OpenSSL\n * @param stdin - Optional data to write to stdin\n * @returns Process result with exit code and outputs\n * @internal\n */\nasync function runOpenSSL(args: string[], stdin?: Buffer): Promise<SpawnResult> {\n return new Promise((resolve, reject) => {\n const child = spawn('openssl', args, {\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n\n const stdoutChunks: Buffer[] = []\n let stderr = ''\n\n child.stdout.on('data', (chunk: Buffer) => {\n stdoutChunks.push(chunk)\n })\n\n child.stderr.on('data', (chunk: Buffer) => {\n stderr += chunk.toString()\n })\n\n child.on('error', (err) => {\n reject(new Error(`Failed to spawn OpenSSL: ${err.message}`))\n })\n\n child.on('close', (code) => {\n resolve({\n exitCode: code ?? 1,\n stdout: Buffer.concat(stdoutChunks),\n stderr,\n })\n })\n\n if (stdin) {\n child.stdin.write(stdin)\n }\n child.stdin.end()\n })\n}\n\n/**\n * Check if OpenSSL is available and get version info.\n * @returns OpenSSL version string\n * @throws Error if OpenSSL is not available\n * @public\n */\nexport async function checkOpenSSL(): Promise<string> {\n const result = await runOpenSSL(['version'])\n\n if (result.exitCode !== 0) {\n throw new Error(`OpenSSL check failed: ${result.stderr}`)\n }\n\n return result.stdout.toString().trim()\n}\n\n/**\n * Cached result of OpenSSL availability check.\n * @internal\n */\nlet openSSLChecked = false\n\n/**\n * Ensure OpenSSL is available before performing cryptographic operations.\n * @throws Error with installation instructions if OpenSSL is not available\n * @internal\n */\nasync function ensureOpenSSLAvailable(): Promise<void> {\n if (openSSLChecked) {\n return\n }\n\n try {\n await checkOpenSSL()\n openSSLChecked = true\n } catch {\n throw new Error(\n 'OpenSSL is not installed or not in PATH. ' +\n 'Please install OpenSSL to use attest-it. ' +\n 'On macOS: brew install openssl. ' +\n 'On Ubuntu: apt-get install openssl',\n )\n }\n}\n\n/**\n * Get the default private key path based on OS.\n * - macOS/Linux: ~/.config/attest-it/private.pem\n * - Windows: %APPDATA%\\attest-it\\private.pem\n * @public\n */\nexport function getDefaultPrivateKeyPath(): string {\n const homeDir = os.homedir()\n\n if (process.platform === 'win32') {\n const appData = process.env.APPDATA ?? path.join(homeDir, 'AppData', 'Roaming')\n return path.join(appData, 'attest-it', 'private.pem')\n }\n\n return path.join(homeDir, '.config', 'attest-it', 'private.pem')\n}\n\n/**\n * Get the default public key path (in repo).\n * @public\n */\nexport function getDefaultPublicKeyPath(): string {\n return path.join(process.cwd(), 'attest-it-public.pem')\n}\n\n/**\n * Get the default YubiKey encrypted key path based on OS.\n * - macOS/Linux: ~/.config/attest-it/yubikey-private.enc\n * - Windows: %APPDATA%\\attest-it\\yubikey-private.enc\n * @public\n */\nexport function getDefaultYubiKeyEncryptedKeyPath(): string {\n const homeDir = os.homedir()\n\n if (process.platform === 'win32') {\n const appData = process.env.APPDATA ?? path.join(homeDir, 'AppData', 'Roaming')\n return path.join(appData, 'attest-it', 'yubikey-private.enc')\n }\n\n return path.join(homeDir, '.config', 'attest-it', 'yubikey-private.enc')\n}\n\n/**\n * Ensure a directory exists, creating it and parent directories if needed.\n * @param dirPath - Directory path to create\n * @internal\n */\nasync function ensureDir(dirPath: string): Promise<void> {\n try {\n await fs.mkdir(dirPath, { recursive: true })\n } catch (err) {\n if (err instanceof Error && 'code' in err && err.code !== 'EEXIST') {\n throw err\n }\n }\n}\n\n/**\n * Check if a file exists.\n * @param filePath - File path to check\n * @returns true if file exists\n * @internal\n */\nasync function fileExists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath)\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Clean up one or more files, ignoring errors if files don't exist.\n * @param paths - File paths to delete\n * @internal\n */\nasync function cleanupFiles(...paths: string[]): Promise<void> {\n for (const filePath of paths) {\n try {\n await fs.unlink(filePath)\n } catch {\n // Ignore cleanup errors - file may not exist\n }\n }\n}\n\n/**\n * Generate a new RSA-2048 keypair using OpenSSL.\n *\n * RSA-2048 with SHA-256 is used because it's universally supported across\n * all OpenSSL and LibreSSL versions, including older macOS systems.\n *\n * @param options - Generation options\n * @returns Paths to generated keys\n * @throws Error if OpenSSL fails or keys exist without force\n * @public\n */\nexport async function generateKeyPair(options: KeygenOptions = {}): Promise<KeyPaths> {\n // Ensure OpenSSL is available before proceeding\n await ensureOpenSSLAvailable()\n\n const {\n privatePath = getDefaultPrivateKeyPath(),\n publicPath = getDefaultPublicKeyPath(),\n force = false,\n passphrase,\n } = options\n\n // Check if keys already exist\n const privateExists = await fileExists(privatePath)\n const publicExists = await fileExists(publicPath)\n\n if ((privateExists || publicExists) && !force) {\n const existing = [privateExists ? privatePath : null, publicExists ? publicPath : null].filter(\n Boolean,\n )\n throw new Error(\n `Key files already exist: ${existing.join(', ')}. Use force: true to overwrite.`,\n )\n }\n\n // Ensure parent directories exist\n await ensureDir(path.dirname(privatePath))\n await ensureDir(path.dirname(publicPath))\n\n try {\n // Generate RSA-2048 private key\n const genArgs = [\n 'genpkey',\n '-algorithm',\n 'RSA',\n '-pkeyopt',\n 'rsa_keygen_bits:2048',\n '-out',\n privatePath,\n ]\n\n // Add encryption if passphrase is provided\n if (passphrase) {\n genArgs.push('-aes256', '-pass', 'stdin')\n }\n\n // Note: OpenSSL reads passphrase from stdin. While OpenSSL accepts passphrases\n // with or without trailing newlines, we consistently use newline terminators\n // across all operations for predictable behavior.\n const genResult = await runOpenSSL(\n genArgs,\n passphrase ? Buffer.from(passphrase + '\\n') : undefined,\n )\n if (genResult.exitCode !== 0) {\n throw new Error(`Failed to generate private key: ${genResult.stderr}`)\n }\n\n // Set restrictive permissions on private key\n await setKeyPermissions(privatePath)\n\n // Extract public key (need passphrase if key is encrypted)\n const pubArgs = ['pkey', '-in', privatePath, '-pubout', '-out', publicPath]\n if (passphrase) {\n pubArgs.push('-passin', 'stdin')\n }\n const pubResult = await runOpenSSL(\n pubArgs,\n passphrase ? Buffer.from(passphrase + '\\n') : undefined,\n )\n\n if (pubResult.exitCode !== 0) {\n throw new Error(`Failed to extract public key: ${pubResult.stderr}`)\n }\n\n return {\n privatePath,\n publicPath,\n }\n } catch (err) {\n // Clean up both key files on any failure\n await cleanupFiles(privatePath, publicPath)\n throw err\n }\n}\n\n/**\n * Sign data using an RSA private key with SHA-256.\n *\n * Uses `openssl dgst -sha256 -sign` which is universally supported across\n * all OpenSSL and LibreSSL versions.\n *\n * @param options - Signing options\n * @returns Base64-encoded signature\n * @throws Error if signing fails\n * @public\n */\nexport async function sign(options: SignOptions): Promise<string> {\n // Ensure OpenSSL is available before proceeding\n await ensureOpenSSLAvailable()\n\n const { privateKeyPath, keyProvider, keyRef, data, passphrase } = options\n\n // Determine which key path to use\n let effectiveKeyPath: string\n let cleanup: (() => Promise<void>) | undefined\n\n if (keyProvider && keyRef) {\n // Use key provider to retrieve the key\n const result = await keyProvider.getPrivateKey(keyRef)\n effectiveKeyPath = result.keyPath\n cleanup = result.cleanup\n } else if (privateKeyPath) {\n // Legacy path: use privateKeyPath directly\n effectiveKeyPath = privateKeyPath\n } else {\n throw new Error(\n 'Either privateKeyPath or both keyProvider and keyRef must be provided for signing',\n )\n }\n\n try {\n // Check if private key exists\n if (!(await fileExists(effectiveKeyPath))) {\n throw new Error(`Private key not found: ${effectiveKeyPath}`)\n }\n\n // Convert data to Buffer\n const dataBuffer = typeof data === 'string' ? Buffer.from(data, 'utf8') : data\n\n // OpenSSL dgst cannot handle empty files, so we need to add a single byte\n // for empty data and document this limitation\n const processBuffer = dataBuffer.length === 0 ? Buffer.from([0x00]) : dataBuffer\n\n // Create temporary directory with OS-level uniqueness guarantees\n // This prevents TOCTOU race conditions that Math.random() would allow\n const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'attest-it-'))\n const dataFile = path.join(tmpDir, 'data.bin')\n const sigFile = path.join(tmpDir, 'sig.bin')\n\n try {\n // Write data to temp file\n await fs.writeFile(dataFile, processBuffer)\n\n // Sign using openssl dgst -sha256 (cross-platform compatible)\n // Note: -passin must come before -sign for encrypted keys\n const signArgs = ['dgst', '-sha256']\n\n // Add passphrase support for encrypted keys\n if (passphrase) {\n signArgs.push('-passin', 'stdin')\n }\n\n signArgs.push('-sign', effectiveKeyPath, '-out', sigFile, dataFile)\n\n // Note: We consistently use newline terminators for passphrases passed via stdin\n const result = await runOpenSSL(\n signArgs,\n passphrase ? Buffer.from(passphrase + '\\n') : undefined,\n )\n\n if (result.exitCode !== 0) {\n // Detect passphrase-related errors and provide a clearer message\n const stderr = result.stderr.toLowerCase()\n if (\n stderr.includes('bad decrypt') ||\n stderr.includes('bad password') ||\n stderr.includes('unable to load key') ||\n stderr.includes('wrong password')\n ) {\n throw new Error(\n 'Failed to decrypt private key. Please check that the passphrase is correct.',\n )\n }\n throw new Error(`Failed to sign data: ${result.stderr}`)\n }\n\n // Read the signature\n const sigBuffer = await fs.readFile(sigFile)\n return sigBuffer.toString('base64')\n } finally {\n // Clean up temp directory and all files within it\n try {\n await fs.rm(tmpDir, { recursive: true, force: true })\n } catch {\n // Ignore cleanup errors - OS will eventually clean tmpdir\n }\n }\n } finally {\n // Always call cleanup function if provided\n if (cleanup) {\n await cleanup()\n }\n }\n}\n\n/**\n * Verify a signature using an RSA public key with SHA-256.\n *\n * Uses `openssl dgst -sha256 -verify` which is universally supported across\n * all OpenSSL and LibreSSL versions.\n *\n * @param options - Verification options\n * @returns true if signature is valid\n * @throws Error if verification fails (not just invalid signature)\n * @public\n */\nexport async function verify(options: VerifyOptions): Promise<boolean> {\n // Ensure OpenSSL is available before proceeding\n await ensureOpenSSLAvailable()\n\n const { publicKeyPath, data, signature } = options\n\n // Check if public key exists\n if (!(await fileExists(publicKeyPath))) {\n throw new Error(`Public key not found: ${publicKeyPath}`)\n }\n\n // Convert data to Buffer\n const dataBuffer = typeof data === 'string' ? Buffer.from(data, 'utf8') : data\n\n // OpenSSL dgst cannot handle empty files, so we use the same workaround\n // as in sign() - add a single byte for empty data\n const processBuffer = dataBuffer.length === 0 ? Buffer.from([0x00]) : dataBuffer\n\n // Decode signature from base64\n const sigBuffer = Buffer.from(signature, 'base64')\n\n // Create temporary directory with OS-level uniqueness guarantees\n // This prevents TOCTOU race conditions that Math.random() would allow\n const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'attest-it-'))\n const dataFile = path.join(tmpDir, 'data.bin')\n const sigFile = path.join(tmpDir, 'sig.bin')\n\n try {\n // Write data and signature to temp files\n await fs.writeFile(dataFile, processBuffer)\n await fs.writeFile(sigFile, sigBuffer)\n\n // Verify using openssl dgst -sha256 (cross-platform compatible)\n const verifyArgs = [\n 'dgst',\n '-sha256',\n '-verify',\n publicKeyPath,\n '-signature',\n sigFile,\n dataFile,\n ]\n const result = await runOpenSSL(verifyArgs)\n\n // dgst -verify: Exit code 0 means valid, non-0 means invalid\n // Output contains \"Verified OK\" on success\n return result.exitCode === 0 && result.stdout.toString().includes('Verified OK')\n } finally {\n // Clean up temp directory and all files within it\n try {\n await fs.rm(tmpDir, { recursive: true, force: true })\n } catch {\n // Ignore cleanup errors - OS will eventually clean tmpdir\n }\n }\n}\n\n/**\n * Set restrictive permissions on a private key file.\n * @param keyPath - Path to the private key\n * @public\n */\nexport async function setKeyPermissions(keyPath: string): Promise<void> {\n // On Windows, use fs.chmod which has limited effect\n // On Unix, set to 0o600 (read/write for owner only)\n if (process.platform === 'win32') {\n // Windows doesn't support Unix-style permissions in the same way\n // But we still call chmod for consistency\n await fs.chmod(keyPath, 0o600)\n } else {\n await fs.chmod(keyPath, 0o600)\n }\n}\n"]}
@@ -62,6 +62,8 @@ export declare interface AttestItSettings {
62
62
  publicKeyPath: string;
63
63
  /** Path to the attestations file */
64
64
  attestationsPath: string;
65
+ /** Path to the seals file */
66
+ sealsPath: string;
65
67
  /** Default command to execute for attestation (can be overridden per suite) */
66
68
  defaultCommand?: string;
67
69
  /** Key provider configuration for signing attestations */
@@ -226,6 +228,7 @@ declare const configSchema: z.ZodObject<{
226
228
  }>>;
227
229
  maxAgeDays: z.ZodDefault<z.ZodNumber>;
228
230
  publicKeyPath: z.ZodDefault<z.ZodString>;
231
+ sealsPath: z.ZodDefault<z.ZodString>;
229
232
  }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
230
233
  attestationsPath: z.ZodDefault<z.ZodString>;
231
234
  defaultCommand: z.ZodOptional<z.ZodString>;
@@ -266,6 +269,7 @@ declare const configSchema: z.ZodObject<{
266
269
  }>>;
267
270
  maxAgeDays: z.ZodDefault<z.ZodNumber>;
268
271
  publicKeyPath: z.ZodDefault<z.ZodString>;
272
+ sealsPath: z.ZodDefault<z.ZodString>;
269
273
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
270
274
  attestationsPath: z.ZodDefault<z.ZodString>;
271
275
  defaultCommand: z.ZodOptional<z.ZodString>;
@@ -306,6 +310,7 @@ declare const configSchema: z.ZodObject<{
306
310
  }>>;
307
311
  maxAgeDays: z.ZodDefault<z.ZodNumber>;
308
312
  publicKeyPath: z.ZodDefault<z.ZodString>;
313
+ sealsPath: z.ZodDefault<z.ZodString>;
309
314
  }, z.ZodTypeAny, "passthrough">>>;
310
315
  suites: z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodEffects<z.ZodObject<{
311
316
  command: z.ZodOptional<z.ZodString>;
@@ -428,6 +433,7 @@ declare const configSchema: z.ZodObject<{
428
433
  } | undefined;
429
434
  maxAgeDays: number;
430
435
  publicKeyPath: string;
436
+ sealsPath: string;
431
437
  } & { [k: string]: unknown };
432
438
  suites: Record<string, {
433
439
  command?: string | undefined;
@@ -500,6 +506,7 @@ declare const configSchema: z.ZodObject<{
500
506
  }>>;
501
507
  maxAgeDays: z.ZodDefault<z.ZodNumber>;
502
508
  publicKeyPath: z.ZodDefault<z.ZodString>;
509
+ sealsPath: z.ZodDefault<z.ZodString>;
503
510
  }, z.ZodTypeAny, "passthrough">;
504
511
  suites: Record<string, {
505
512
  command?: string | undefined;
@@ -817,6 +824,14 @@ export declare function getDefaultPrivateKeyPath(): string;
817
824
  */
818
825
  export declare function getDefaultPublicKeyPath(): string;
819
826
 
827
+ /**
828
+ * Get the default YubiKey encrypted key path based on OS.
829
+ * - macOS/Linux: ~/.config/attest-it/yubikey-private.enc
830
+ * - Windows: %APPDATA%\attest-it\yubikey-private.enc
831
+ * @public
832
+ */
833
+ export declare function getDefaultYubiKeyEncryptedKeyPath(): string;
834
+
820
835
  /**
821
836
  * Get the gate configuration for a given gate ID.
822
837
  *
@@ -827,6 +842,18 @@ export declare function getDefaultPublicKeyPath(): string;
827
842
  */
828
843
  export declare function getGate(config: AttestItConfig, gateId: string): GateConfig | undefined;
829
844
 
845
+ /**
846
+ * Get the user's home public keys directory.
847
+ *
848
+ * This returns ~/.attest-it/public-keys, which is different from the
849
+ * config directory (~/.config/attest-it). The public keys directory
850
+ * is designed to be easily shareable and discoverable.
851
+ *
852
+ * @returns Path to the user's home public keys directory
853
+ * @public
854
+ */
855
+ export declare function getHomePublicKeysDir(): string;
856
+
830
857
  /**
831
858
  * Get the path to the local config file.
832
859
  *
@@ -855,6 +882,19 @@ export declare function getPreference<K extends keyof UserPreferences>(key: K):
855
882
  */
856
883
  export declare function getPreferencesPath(): string;
857
884
 
885
+ /**
886
+ * Get the project public keys directory.
887
+ *
888
+ * This returns .attest-it/public-keys relative to the given project root.
889
+ * The project public keys directory is used for CI/GitHub Actions to
890
+ * verify attestation seals.
891
+ *
892
+ * @param projectRoot - The project root directory (defaults to cwd)
893
+ * @returns Path to the project public keys directory
894
+ * @public
895
+ */
896
+ export declare function getProjectPublicKeysDir(projectRoot?: string): string;
897
+
858
898
  /**
859
899
  * Extract the public key from an Ed25519 private key.
860
900
  *
@@ -865,6 +905,15 @@ export declare function getPreferencesPath(): string;
865
905
  */
866
906
  export declare function getPublicKeyFromPrivate(privateKeyPem: string): string;
867
907
 
908
+ /**
909
+ * Check if a project has attest-it configuration.
910
+ *
911
+ * @param projectRoot - The project root directory (defaults to cwd)
912
+ * @returns True if the project has .attest-it/config.yaml or similar
913
+ * @public
914
+ */
915
+ export declare function hasProjectConfig(projectRoot?: string): boolean;
916
+
868
917
  /**
869
918
  * A single identity configuration.
870
919
  * @public
@@ -904,6 +953,8 @@ export declare interface KeyGenerationResult {
904
953
  publicKeyPath: string;
905
954
  /** Human-readable storage location description */
906
955
  storageDescription: string;
956
+ /** Whether the private key is encrypted with a passphrase */
957
+ encrypted?: boolean;
907
958
  }
908
959
 
909
960
  /**
@@ -917,6 +968,8 @@ export declare interface KeygenOptions {
917
968
  publicPath?: string;
918
969
  /** Overwrite existing keys (default: false) */
919
970
  force?: boolean;
971
+ /** Passphrase to encrypt the private key with AES-256 (optional) */
972
+ passphrase?: string;
920
973
  }
921
974
 
922
975
  /**
@@ -928,6 +981,8 @@ export declare interface KeygenProviderOptions {
928
981
  publicKeyPath: string;
929
982
  /** Overwrite existing keys */
930
983
  force?: boolean;
984
+ /** Passphrase to encrypt the private key (filesystem provider only) */
985
+ passphrase?: string;
931
986
  }
932
987
 
933
988
  /**
@@ -1229,7 +1284,7 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1229
1284
  * The merge strategy prioritizes security-critical fields from the policy
1230
1285
  * configuration while combining operational fields from both sources:
1231
1286
  *
1232
- * - **Policy settings** (maxAgeDays, publicKeyPath, attestationsPath) are used as-is
1287
+ * - **Policy settings** (maxAgeDays, publicKeyPath, attestationsPath, sealsPath) are used as-is
1233
1288
  * - **Operational settings** (defaultCommand, keyProvider) are added from operational config
1234
1289
  * - **Team and gates** come exclusively from policy config
1235
1290
  * - **Suites and groups** come exclusively from operational config
@@ -1262,6 +1317,8 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1262
1317
  url: string;
1263
1318
  /** User UUID */
1264
1319
  user_uuid: string;
1320
+ /** Human-readable account name (e.g., "North Family") */
1321
+ name?: string;
1265
1322
  }
1266
1323
 
1267
1324
  /**
@@ -1292,7 +1349,7 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1292
1349
  static isInstalled(): Promise<boolean>;
1293
1350
  /**
1294
1351
  * List all 1Password accounts.
1295
- * @returns Array of account information
1352
+ * @returns Array of account information including human-readable names
1296
1353
  */
1297
1354
  static listAccounts(): Promise<OnePasswordAccount[]>;
1298
1355
  /**
@@ -1664,14 +1721,17 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1664
1721
  attestationsPath: z.ZodDefault<z.ZodString>;
1665
1722
  maxAgeDays: z.ZodDefault<z.ZodNumber>;
1666
1723
  publicKeyPath: z.ZodDefault<z.ZodString>;
1724
+ sealsPath: z.ZodDefault<z.ZodString>;
1667
1725
  }, "strict", z.ZodTypeAny, {
1668
1726
  attestationsPath: string;
1669
1727
  maxAgeDays: number;
1670
1728
  publicKeyPath: string;
1729
+ sealsPath: string;
1671
1730
  }, {
1672
1731
  attestationsPath?: string | undefined;
1673
1732
  maxAgeDays?: number | undefined;
1674
1733
  publicKeyPath?: string | undefined;
1734
+ sealsPath?: string | undefined;
1675
1735
  }>>;
1676
1736
  team: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
1677
1737
  email: z.ZodOptional<z.ZodString>;
@@ -1705,6 +1765,7 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1705
1765
  attestationsPath: string;
1706
1766
  maxAgeDays: number;
1707
1767
  publicKeyPath: string;
1768
+ sealsPath: string;
1708
1769
  };
1709
1770
  team?: Record<string, {
1710
1771
  email?: string | undefined;
@@ -1728,6 +1789,7 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1728
1789
  attestationsPath?: string | undefined;
1729
1790
  maxAgeDays?: number | undefined;
1730
1791
  publicKeyPath?: string | undefined;
1792
+ sealsPath?: string | undefined;
1731
1793
  } | undefined;
1732
1794
  team?: Record<string, {
1733
1795
  email?: string | undefined;
@@ -1811,21 +1873,23 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1811
1873
  * Read seals from the seals.json file (async).
1812
1874
  *
1813
1875
  * @param dir - Directory containing .attest-it/seals.json
1876
+ * @param sealsPathOverride - Optional explicit path to seals file (from config.settings.sealsPath)
1814
1877
  * @returns The seals file contents, or an empty seals file if the file doesn't exist
1815
1878
  * @throws Error if file exists but cannot be read or parsed
1816
1879
  * @public
1817
1880
  */
1818
- export declare function readSeals(dir: string): Promise<SealsFile>;
1881
+ export declare function readSeals(dir: string, sealsPathOverride?: string): Promise<SealsFile>;
1819
1882
 
1820
1883
  /**
1821
1884
  * Read seals from the seals.json file (sync).
1822
1885
  *
1823
1886
  * @param dir - Directory containing .attest-it/seals.json
1887
+ * @param sealsPathOverride - Optional explicit path to seals file (from config.settings.sealsPath)
1824
1888
  * @returns The seals file contents, or an empty seals file if the file doesn't exist
1825
1889
  * @throws Error if file exists but cannot be read or parsed
1826
1890
  * @public
1827
1891
  */
1828
- export declare function readSealsSync(dir: string): SealsFile;
1892
+ export declare function readSealsSync(dir: string, sealsPathOverride?: string): SealsFile;
1829
1893
 
1830
1894
  /**
1831
1895
  * Options for reading and verifying signed attestations.
@@ -1891,6 +1955,49 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1891
1955
  */
1892
1956
  export declare function savePreferences(preferences: UserPreferences): Promise<void>;
1893
1957
 
1958
+ /**
1959
+ * Save a public key to the user's home directory and optionally to the project directory.
1960
+ *
1961
+ * This saves the public key as a base64-encoded string (matching the format in config.yaml)
1962
+ * to:
1963
+ * 1. ~/.attest-it/public-keys/<slug>.pem (always)
1964
+ * 2. ./.attest-it/public-keys/<slug>.pem (if project has attest-it config)
1965
+ *
1966
+ * @param slug - The identity slug (used for the filename)
1967
+ * @param publicKey - The base64-encoded public key
1968
+ * @param projectRoot - The project root directory (defaults to cwd)
1969
+ * @returns Paths where the key was saved
1970
+ * @public
1971
+ */
1972
+ export declare function savePublicKey(slug: string, publicKey: string, projectRoot?: string): Promise<SavePublicKeyResult>;
1973
+
1974
+ /**
1975
+ * Result from saving public keys.
1976
+ * @public
1977
+ */
1978
+ export declare interface SavePublicKeyResult {
1979
+ /** Path where the key was saved in the user's home directory */
1980
+ homePath: string;
1981
+ /** Path where the key was saved in the project directory, if applicable */
1982
+ projectPath?: string;
1983
+ }
1984
+
1985
+ /**
1986
+ * Save a public key to the user's home directory and optionally to the project directory (sync).
1987
+ *
1988
+ * This saves the public key as a base64-encoded string (matching the format in config.yaml)
1989
+ * to:
1990
+ * 1. ~/.attest-it/public-keys/<slug>.pem (always)
1991
+ * 2. ./.attest-it/public-keys/<slug>.pem (if project has attest-it config)
1992
+ *
1993
+ * @param slug - The identity slug (used for the filename)
1994
+ * @param publicKey - The base64-encoded public key
1995
+ * @param projectRoot - The project root directory (defaults to cwd)
1996
+ * @returns Paths where the key was saved
1997
+ * @public
1998
+ */
1999
+ export declare function savePublicKeySync(slug: string, publicKey: string, projectRoot?: string): SavePublicKeyResult;
2000
+
1894
2001
  /**
1895
2002
  * A seal represents a cryptographic attestation that a gate's fingerprint
1896
2003
  * was signed by an authorized team member.
@@ -2020,6 +2127,8 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
2020
2127
  keyRef?: string;
2021
2128
  /** Data to sign (string or Buffer) */
2022
2129
  data: Buffer | string;
2130
+ /** Passphrase for encrypted private keys (optional) */
2131
+ passphrase?: string;
2023
2132
  }
2024
2133
 
2025
2134
  /**
@@ -2332,20 +2441,22 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
2332
2441
  *
2333
2442
  * @param dir - Directory containing .attest-it/seals.json
2334
2443
  * @param sealsFile - The seals file to write
2444
+ * @param sealsPathOverride - Optional explicit path to seals file (from config.settings.sealsPath)
2335
2445
  * @throws Error if file cannot be written
2336
2446
  * @public
2337
2447
  */
2338
- export declare function writeSeals(dir: string, sealsFile: SealsFile): Promise<void>;
2448
+ export declare function writeSeals(dir: string, sealsFile: SealsFile, sealsPathOverride?: string): Promise<void>;
2339
2449
 
2340
2450
  /**
2341
2451
  * Write seals to the seals.json file (sync).
2342
2452
  *
2343
2453
  * @param dir - Directory containing .attest-it/seals.json
2344
2454
  * @param sealsFile - The seals file to write
2455
+ * @param sealsPathOverride - Optional explicit path to seals file (from config.settings.sealsPath)
2345
2456
  * @throws Error if file cannot be written
2346
2457
  * @public
2347
2458
  */
2348
- export declare function writeSealsSync(dir: string, sealsFile: SealsFile): void;
2459
+ export declare function writeSealsSync(dir: string, sealsFile: SealsFile, sealsPathOverride?: string): void;
2349
2460
 
2350
2461
  /**
2351
2462
  * Write attestations with a cryptographic signature.