Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 29 additions & 9 deletions src/certificate-authority.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,43 @@ export default async function installCertificateAuthority(options: Options = {})
uninstall();
ensureConfigDirs();

debug(`Making a temp working directory for files to copied in`);
let rootKeyPath = mktmp();

debug(`Generating the OpenSSL configuration needed to setup the certificate authority`);
seedConfigFiles();

// Generate the root key + CA cert into TEMP paths first, so a failed/declined
// trust-store install does not leave behind canonical files that make
// certificateFor's `!existsSync(rootCAKeyPath)` guard skip re-installation
// on subsequent runs.
debug(`Making a temp working directory for files to be copied in`);
let tmpRootKeyPath = mktmp();
let tmpRootCertPath = mktmp();

debug(`Generating a private key`);
generateKey(rootKeyPath);
generateKey(tmpRootKeyPath);

debug(`Generating a CA certificate`);
openssl(['req', '-new', '-x509', '-config', caSelfSignConfig, '-key', rootKeyPath, '-out', rootCACertPath, '-days', '825']);

debug('Saving certificate authority credentials');
await saveCertificateAuthorityCredentials(rootKeyPath);
openssl(['req', '-new', '-x509', '-config', caSelfSignConfig, '-key', tmpRootKeyPath, '-out', tmpRootCertPath, '-days', '825']);

// Install into the OS trust store BEFORE persisting to the canonical paths.
// If addToTrustStores throws (e.g. user declines the Windows Security Warning,
// or `sudo security add-trusted-cert` fails on macOS), the canonical files
// are never written and the next certificateFor() call will retry the whole
// install — including the user-facing prompt.
debug(`Adding the root certificate authority to trust stores`);
await currentPlatform.addToTrustStores(rootCACertPath, options);
try {
await currentPlatform.addToTrustStores(tmpRootCertPath, options);
} catch (e) {
rm(tmpRootKeyPath);
rm(tmpRootCertPath);
throw e;
}

debug(`Persisting root CA certificate and key to their canonical paths`);
writeFile(rootCACertPath, readFile(tmpRootCertPath));
await saveCertificateAuthorityCredentials(tmpRootKeyPath);

rm(tmpRootKeyPath);
rm(tmpRootCertPath);
}

/**
Expand Down
16 changes: 11 additions & 5 deletions src/platforms/win32.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,17 @@ export default class WindowsPlatform implements Platform {
try {
run('certutil', ['-addstore', '-user', 'root', certificatePath]);
} catch (e) {
e.output.map((buffer: Buffer) => {
if (buffer) {
console.log(buffer.toString());
}
});
if (e.output) {
e.output.map((buffer: Buffer) => {
if (buffer) {
console.log(buffer.toString());
}
});
}
// certutil non-zero exit means the user declined the Windows Security
// Warning, or the store is otherwise unwritable. Propagate so the caller
// can avoid persisting on-disk state that would block future retries.
throw e;
}
debug('adding devcert root to Firefox trust store')
// Firefox (don't even try NSS certutil, no easy install for Windows)
Expand Down