UNPKG

selfsigned

Version:

Generate self signed certificates private and public keys

318 lines (241 loc) 8.99 kB
# selfsigned Generate self-signed X.509 certificates using Node.js native crypto. ## Install ```bash npm install selfsigned ``` ## Requirements - **Node.js >= 15.6.0** (for native WebCrypto support) ## Usage **Version 5.0 is async-only.** The `generate()` function now returns a Promise. ```js const selfsigned = require('selfsigned'); const attrs = [{ name: 'commonName', value: 'contoso.com' }]; const pems = await selfsigned.generate(attrs); console.log(pems); ``` ### Output ```js { private: '-----BEGIN PRIVATE KEY-----\n...', public: '-----BEGIN PUBLIC KEY-----\n...', cert: '-----BEGIN CERTIFICATE-----\n...', fingerprint: 'XX:XX:XX:...' } ``` ## Options ```js const pems = await selfsigned.generate(null, { keySize: 2048, // the size for the private key in bits (default: 2048) notBeforeDate: new Date(), // start of certificate validity (default: now) notAfterDate: new Date('2026-01-01'), // end of certificate validity (default: notBeforeDate + 365 days) algorithm: 'sha256', // sign the certificate with specified algorithm (default: 'sha1') extensions: [{ name: 'basicConstraints', cA: true }], // certificate extensions array clientCertificate: true, // generate client cert (default: false) - can also be an options object ca: { key: '...', cert: '...' }, // CA key and cert for signing (default: self-signed) passphrase: 'secret' // encrypt the private key with a passphrase (default: none) }); ``` ### Setting Custom Validity Period Use `notBeforeDate` and `notAfterDate` to control certificate validity: ```js // Using date-fns const { addDays, addYears } = require('date-fns'); const pems = await selfsigned.generate(null, { notBeforeDate: new Date(), notAfterDate: addDays(new Date(), 30) // Valid for 30 days }); // Or with vanilla JS const notBefore = new Date(); const notAfter = new Date(notBefore); notAfter.setFullYear(notAfter.getFullYear() + 2); // Valid for 2 years const pems = await selfsigned.generate(null, { notBeforeDate: notBefore, notAfterDate: notAfter }); ``` ### Supported Algorithms - `sha1` (default) - `sha256` - `sha384` - `sha512` ### Using Your Own Keys You can avoid key pair generation by specifying your own keys: ```js const pems = await selfsigned.generate(null, { keyPair: { publicKey: '-----BEGIN PUBLIC KEY-----...', privateKey: '-----BEGIN PRIVATE KEY-----...' } }); ``` ### Encrypting the Private Key You can encrypt the private key with a passphrase using AES-256-CBC: ```js const pems = await selfsigned.generate(null, { passphrase: 'my-secret-passphrase' }); // The private key will be in encrypted PKCS#8 format: // -----BEGIN ENCRYPTED PRIVATE KEY----- // ... // -----END ENCRYPTED PRIVATE KEY----- ``` To use the encrypted key, provide the passphrase: ```js const crypto = require('crypto'); // Decrypt the key const privateKey = crypto.createPrivateKey({ key: pems.private, passphrase: 'my-secret-passphrase' }); // Or use directly with HTTPS server const https = require('https'); https.createServer({ key: pems.private, passphrase: 'my-secret-passphrase', cert: pems.cert }, app).listen(443); ``` ### Signing with a CA You can generate certificates signed by an existing Certificate Authority instead of self-signed certificates. This is useful for development environments where you want browsers to trust your certificates. ```js const fs = require('fs'); const selfsigned = require('selfsigned'); const pems = await selfsigned.generate([ { name: 'commonName', value: 'localhost' } ], { algorithm: 'sha256', ca: { key: fs.readFileSync('/path/to/ca.key', 'utf8'), cert: fs.readFileSync('/path/to/ca.crt', 'utf8') } }); ``` The generated certificate will be signed by the provided CA and will include: - Subject Alternative Name (SAN) extension with DNS name matching the commonName - For `localhost`, an additional IP SAN for `127.0.0.1` - Key Usage: digitalSignature, keyEncipherment - Extended Key Usage: serverAuth, clientAuth #### Using with mkcert [mkcert](https://github.com/FiloSottile/mkcert) is a simple tool for making locally-trusted development certificates. Combining it with `selfsigned` provides an excellent developer experience: - **No certificate files to manage** - generate trusted certificates on-the-fly at server startup - **No git-ignored cert files** - nothing to store, share, or accidentally commit - **Browsers trust the certificates automatically** - no security warnings during development ```js const https = require('https'); const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); const selfsigned = require('selfsigned'); // Get mkcert's CA (requires: brew install mkcert && mkcert -install) const caroot = execSync('mkcert -CAROOT', { encoding: 'utf8' }).trim(); const pems = await selfsigned.generate([ { name: 'commonName', value: 'localhost' } ], { algorithm: 'sha256', ca: { key: fs.readFileSync(path.join(caroot, 'rootCA-key.pem'), 'utf8'), cert: fs.readFileSync(path.join(caroot, 'rootCA.pem'), 'utf8') } }); // Start server with browser-trusted certificate - no files written to disk https.createServer({ key: pems.private, cert: pems.cert }, app).listen(443); ``` See [examples/https-server-mkcert.js](examples/https-server-mkcert.js) for a complete working example. ## Attributes Attributes follow the X.509 standard: ```js const attrs = [ { name: 'commonName', value: 'example.org' }, { name: 'countryName', value: 'US' }, { shortName: 'ST', value: 'Virginia' }, { name: 'localityName', value: 'Blacksburg' }, { name: 'organizationName', value: 'Test' }, { shortName: 'OU', value: 'Test' } ]; ``` ## Generate Client Certificates For environments where servers require client certificates, you can generate client keys signed by the original (server) key: ```js const pems = await selfsigned.generate(null, { clientCertificate: true }); console.log(pems); ``` Output includes additional client certificate fields: ```js { private: '-----BEGIN PRIVATE KEY-----\n...', public: '-----BEGIN PUBLIC KEY-----\n...', cert: '-----BEGIN CERTIFICATE-----\n...', fingerprint: 'XX:XX:XX:...', clientprivate: '-----BEGIN PRIVATE KEY-----\n...', clientpublic: '-----BEGIN PUBLIC KEY-----\n...', clientcert: '-----BEGIN CERTIFICATE-----\n...' } ``` ### Client Certificate Options The `clientCertificate` option can be `true` for defaults, or an options object for full control: ```js const pems = await selfsigned.generate(null, { clientCertificate: { cn: 'jdoe', // common name (default: 'John Doe jdoe123') keySize: 4096, // key size in bits (default: 2048) algorithm: 'sha256', // signature algorithm (default: inherits from parent or 'sha1') notBeforeDate: new Date(), // validity start (default: now) notAfterDate: new Date('2026-01-01') // validity end (default: notBeforeDate + 1 year) } }); ``` Simple example with just a custom CN: ```js const pems = await selfsigned.generate(null, { clientCertificate: { cn: 'FooBar' } }); ``` ## PKCS#7 Support PKCS#7 formatting is available through a separate module for better tree-shaking: ```js const selfsigned = require('selfsigned'); const { createPkcs7 } = require('selfsigned/pkcs7'); const pems = await selfsigned.generate(attrs); const pkcs7 = createPkcs7(pems.cert); console.log(pkcs7); // PKCS#7 formatted certificate ``` You can also create PKCS#7 for client certificates: ```js const pems = await selfsigned.generate(null, { clientCertificate: true }); const clientPkcs7 = createPkcs7(pems.clientcert); ``` ## Migration from v4.x Version 5.0 introduces breaking changes: ### Breaking Changes 1. **Async-only API**: The `generate()` function is now async and returns a Promise. Synchronous generation is no longer supported. 2. **No callback support**: Callbacks have been removed. Use `async`/`await` or `.then()`. 3. **Minimum Node.js version**: Now requires Node.js >= 15.6.0 (was >= 10). 4. **Dependencies**: Replaced `node-forge` with `@peculiar/x509` and `pkijs` (66% smaller bundle size). 5. **`days` option removed**: Use `notAfterDate` instead. Default validity is 365 days from `notBeforeDate`. ### Migration Examples **Old (v4.x):** ```js // Sync const pems = selfsigned.generate(attrs, { days: 365 }); // Callback selfsigned.generate(attrs, { days: 365 }, function(err, pems) { if (err) throw err; console.log(pems); }); ``` **New (v5.x):** ```js // Async/await (default 365 days validity) const pems = await selfsigned.generate(attrs); // Custom validity with notAfterDate const notAfter = new Date(); notAfter.setDate(notAfter.getDate() + 30); // 30 days const pems = await selfsigned.generate(attrs, { notAfterDate: notAfter }); // Or with .then() selfsigned.generate(attrs) .then(pems => console.log(pems)) .catch(err => console.error(err)); ``` ## License MIT