node-easy-cert-secure
Version:
A tool for managing self-signed certifications
114 lines (93 loc) • 3.55 kB
JavaScript
'use strict';
var forge = require('node-forge');
var Util = require('./util');
var defaultAttrs = [{ name: 'countryName', value: 'CN' }, { name: 'organizationName', value: 'EasyCert' }, { shortName: 'ST', value: 'SH' }, { shortName: 'OU', value: 'EasyCert SSL' }];
/**
* different domain format needs different SAN
*
*/
function getExtensionSAN() {
var domain = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var isIpDomain = Util.isIpDomain(domain);
if (isIpDomain) {
return {
name: 'subjectAltName',
altNames: [{ type: 7, ip: domain }]
};
} else {
return {
name: 'subjectAltName',
altNames: [{ type: 2, value: domain }]
};
}
}
function getKeysAndCert(serialNumber) {
var keys = forge.pki.rsa.generateKeyPair(2048);
var cert = forge.pki.createCertificate();
cert.publicKey = keys.publicKey;
cert.serialNumber = serialNumber || Math.floor(Math.random() * 100000) + '';
var now = Date.now();
// compatible with apple's updated cert policy: https://support.apple.com/en-us/HT210176
cert.validity.notBefore = new Date(now - 24 * 60 * 60 * 1000); // 1 day before
cert.validity.notAfter = new Date(now + 824 * 24 * 60 * 60 * 1000); // 824 days after
return {
keys: keys,
cert: cert
};
}
function generateRootCA(commonName) {
var keysAndCert = getKeysAndCert();
var keys = keysAndCert.keys;
var cert = keysAndCert.cert;
commonName = commonName || 'CertManager';
var attrs = defaultAttrs.concat([{
name: 'commonName',
value: commonName
}]);
cert.setSubject(attrs);
cert.setIssuer(attrs);
cert.setExtensions([{ name: 'basicConstraints', cA: true }]
// { name: 'keyUsage', keyCertSign: true, digitalSignature: true, nonRepudiation: true, keyEncipherment: true, dataEncipherment: true },
// { name: 'extKeyUsage', serverAuth: true, clientAuth: true, codeSigning: true, emailProtection: true, timeStamping: true },
// { name: 'nsCertType', client: true, server: true, email: true, objsign: true, sslCA: true, emailCA: true, objCA: true },
// { name: 'subjectKeyIdentifier' }
);
cert.sign(keys.privateKey, forge.md.sha256.create());
return {
privateKey: forge.pki.privateKeyToPem(keys.privateKey),
publicKey: forge.pki.publicKeyToPem(keys.publicKey),
certificate: forge.pki.certificateToPem(cert)
};
}
function generateCertsForHostname(domain, rootCAConfig) {
// generate a serialNumber for domain
var md = forge.md.md5.create();
md.update(domain);
var keysAndCert = getKeysAndCert(md.digest().toHex());
var keys = keysAndCert.keys;
var cert = keysAndCert.cert;
var caCert = forge.pki.certificateFromPem(rootCAConfig.cert);
var caKey = forge.pki.privateKeyFromPem(rootCAConfig.key);
// issuer from CA
cert.setIssuer(caCert.subject.attributes);
var attrs = defaultAttrs.concat([{
name: 'commonName',
value: domain
}]);
var extensions = [{ name: 'basicConstraints', cA: false }, getExtensionSAN(domain)];
cert.setSubject(attrs);
cert.setExtensions(extensions);
cert.sign(caKey, forge.md.sha256.create());
return {
privateKey: forge.pki.privateKeyToPem(keys.privateKey),
publicKey: forge.pki.publicKeyToPem(keys.publicKey),
certificate: forge.pki.certificateToPem(cert)
};
}
// change the default attrs
function setDefaultAttrs(attrs) {
defaultAttrs = attrs;
}
module.exports.generateRootCA = generateRootCA;
module.exports.generateCertsForHostname = generateCertsForHostname;
module.exports.setDefaultAttrs = setDefaultAttrs;