diff --git a/README.md b/README.md index 7e55cc8..8c34ff2 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,47 @@ To override the default client CN of `john doe jdoe123`, add another option for var pems = selfsigned.generate(null, { clientCertificate: true, clientCertificateCN: 'FooBar' }); ``` +### Generate certificates signed by your own CA + +Provide your private certificate authority root certificate and private key in PEM format in `ca` option object (under `cert` and `private` keys respectively): + +```js +const cert = selfsigned.generate( + [{ name: 'commonName', value: 'example.com' }], + { + keySize: 2048, + ca: { + cert: "-----BEGIN CERTIFICATE-----\r\n…\r\n-----END CERTIFICATE-----\r\n", + private: "-----BEGIN RSA PRIVATE KEY-----\r\n…\r\n-----END RSA PRIVATE KEY-----\r\n", + }, + algorithm: 'sha256', + extensions: [ + { + name: 'basicConstraints', + cA: false, + }, + { + name: "keyUsage", + keyCertSign: false, // Must be set to false or Chrome won't accept this certificate otherwise + digitalSignature: true, + nonRepudiation: true, + keyEncipherment: true, + dataEncipherment: true, + }, + { + name: "extKeyUsage", + serverAuth: true, + clientAuth: true, + codeSigning: true, + timeStamping: true, + }, + ], + } +) +``` + +And yes, you can generate CA certificate with selfsigned itself and just provide output of `selfsigned.generate` into `ca` option. + ## License MIT diff --git a/index.js b/index.js index 7356dc2..b1bdcaa 100644 --- a/index.js +++ b/index.js @@ -43,6 +43,18 @@ exports.generate = function generate(attrs, options, done) { cert.validity.notAfter = new Date(); cert.validity.notAfter.setDate(cert.validity.notBefore.getDate() + (options.days || 365)); + var caPrivateKey, caCert, issuerAttrs; + if (options && options.ca) { + caPrivateKey = forge.pki.privateKeyFromPem(options.ca.private), + caCert = forge.pki.certificateFromPem(options.ca.cert); + issuerAttrs = caCert.subject.attributes; + } else { + // Self-signed certificate: use our own key for signing + caPrivateKey = keyPair.privateKey; + caCert = cert; + issuerAttrs = attrs; + } + attrs = attrs || [{ name: 'commonName', value: 'example.org' @@ -64,7 +76,7 @@ exports.generate = function generate(attrs, options, done) { }]; cert.setSubject(attrs); - cert.setIssuer(attrs); + cert.setIssuer(issuerAttrs); cert.publicKey = keyPair.publicKey; @@ -86,7 +98,7 @@ exports.generate = function generate(attrs, options, done) { }] }]); - cert.sign(keyPair.privateKey, getAlgorithm(options && options.algorithm)); + cert.sign(caPrivateKey, getAlgorithm(options && options.algorithm)); const fingerprint = forge.md.sha1 .create() @@ -150,7 +162,7 @@ exports.generate = function generate(attrs, options, done) { } var caStore = forge.pki.createCaStore(); - caStore.addCertificate(cert); + caStore.addCertificate(caCert); try { forge.pki.verifyCertificateChain(caStore, [cert],