* Generate a self-signed certificate for testing
(
tempDir: string,
name: string,
options: { cn: string; san: string[]; org: string },
)
| 42 | * Generate a self-signed certificate for testing |
| 43 | */ |
| 44 | async function generateCertificate( |
| 45 | tempDir: string, |
| 46 | name: string, |
| 47 | options: { cn: string; san: string[]; org: string }, |
| 48 | ): Promise<{ certPath: string; keyPath: string; caCertPath: string }> { |
| 49 | const certPath = path.join(tempDir, `${name}.crt`); |
| 50 | const keyPath = path.join(tempDir, `${name}.key`); |
| 51 | const caCertPath = path.join(tempDir, `${name}-ca.crt`); |
| 52 | |
| 53 | try { |
| 54 | // Generate a private key |
| 55 | execSync(`openssl genrsa -out "${keyPath}" 2048`, { stdio: "pipe" }); |
| 56 | |
| 57 | // Create config file for certificate |
| 58 | const configPath = path.join(tempDir, `${name}.conf`); |
| 59 | const altNames = options.san |
| 60 | .map((san, i) => { |
| 61 | return san.match(/^\d+\.\d+\.\d+\.\d+$/) |
| 62 | ? `IP.${i + 1} = ${san}` |
| 63 | : `DNS.${i + 1} = ${san}`; |
| 64 | }) |
| 65 | .join("\n"); |
| 66 | |
| 67 | const configContent = ` |
| 68 | [req] |
| 69 | distinguished_name = req_distinguished_name |
| 70 | req_extensions = v3_req |
| 71 | prompt = no |
| 72 | |
| 73 | [req_distinguished_name] |
| 74 | C = US |
| 75 | ST = Test |
| 76 | L = Test |
| 77 | O = ${options.org} |
| 78 | CN = ${options.cn} |
| 79 | |
| 80 | [v3_req] |
| 81 | keyUsage = keyEncipherment, dataEncipherment |
| 82 | extendedKeyUsage = serverAuth |
| 83 | subjectAltName = @alt_names |
| 84 | |
| 85 | [alt_names] |
| 86 | ${altNames} |
| 87 | `; |
| 88 | fs.writeFileSync(configPath, configContent); |
| 89 | |
| 90 | // Generate a self-signed certificate |
| 91 | execSync( |
| 92 | `openssl req -new -x509 -key "${keyPath}" -out "${certPath}" -days 365 -config "${configPath}" -extensions v3_req`, |
| 93 | { stdio: "pipe" }, |
| 94 | ); |
| 95 | |
| 96 | // Copy the certificate as CA (for testing custom CA scenarios) |
| 97 | fs.copyFileSync(certPath, caCertPath); |
| 98 | |
| 99 | return { certPath, keyPath, caCertPath }; |
| 100 | } catch (error) { |
| 101 | // Fallback: create minimal test certificates if OpenSSL not available |