|
|
- var forge = require('node-forge');
-
- // a hexString is considered negative if it's most significant bit is 1
- // because serial numbers use ones' complement notation
- // this RFC in section 4.1.2.2 requires serial numbers to be positive
- // http://www.ietf.org/rfc/rfc5280.txt
- function toPositiveHex(hexString){
- var mostSiginficativeHexAsInt = parseInt(hexString[0], 16);
- if (mostSiginficativeHexAsInt < 8){
- return hexString;
- }
-
- mostSiginficativeHexAsInt -= 8;
- return mostSiginficativeHexAsInt.toString() + hexString.substring(1);
- }
-
- function getAlgorithm(key) {
- switch (key) {
- case 'sha256':
- return forge.md.sha256.create();
- default:
- return forge.md.sha1.create();
- }
- }
-
- exports.generate = function generate(attrs, options, done) {
- if (typeof attrs === 'function') {
- done = attrs;
- attrs = undefined;
- } else if (typeof options === 'function') {
- done = options;
- options = {};
- }
-
- options = options || {};
-
- var generatePem = function (keyPair) {
- var cert = forge.pki.createCertificate();
-
- cert.serialNumber = toPositiveHex(forge.util.bytesToHex(forge.random.getBytesSync(9))); // the serial number can be decimal or hex (if preceded by 0x)
-
- cert.validity.notBefore = new Date();
- cert.validity.notAfter = new Date();
- cert.validity.notAfter.setDate(cert.validity.notBefore.getDate() + (options.days || 365));
-
- attrs = 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'
- }];
-
- cert.setSubject(attrs);
- cert.setIssuer(attrs);
-
- cert.publicKey = keyPair.publicKey;
-
- cert.setExtensions(options.extensions || [{
- name: 'basicConstraints',
- cA: true
- }, {
- name: 'keyUsage',
- keyCertSign: true,
- digitalSignature: true,
- nonRepudiation: true,
- keyEncipherment: true,
- dataEncipherment: true
- }, {
- name: 'subjectAltName',
- altNames: [{
- type: 6, // URI
- value: 'http://example.org/webid#me'
- }]
- }]);
-
- cert.sign(keyPair.privateKey, getAlgorithm(options && options.algorithm));
-
- const fingerprint = forge.md.sha1
- .create()
- .update(forge.asn1.toDer(forge.pki.certificateToAsn1(cert)).getBytes())
- .digest()
- .toHex()
- .match(/.{2}/g)
- .join(':');
-
- var pem = {
- private: forge.pki.privateKeyToPem(keyPair.privateKey),
- public: forge.pki.publicKeyToPem(keyPair.publicKey),
- cert: forge.pki.certificateToPem(cert),
- fingerprint: fingerprint,
- };
-
- if (options && options.pkcs7) {
- var p7 = forge.pkcs7.createSignedData();
- p7.addCertificate(cert);
- pem.pkcs7 = forge.pkcs7.messageToPem(p7);
- }
-
- if (options && options.clientCertificate) {
- var clientkeys = forge.pki.rsa.generateKeyPair(1024);
- var clientcert = forge.pki.createCertificate();
- clientcert.serialNumber = toPositiveHex(forge.util.bytesToHex(forge.random.getBytesSync(9)));
- clientcert.validity.notBefore = new Date();
- clientcert.validity.notAfter = new Date();
- clientcert.validity.notAfter.setFullYear(clientcert.validity.notBefore.getFullYear() + 1);
-
- var clientAttrs = JSON.parse(JSON.stringify(attrs));
-
- for(var i = 0; i < clientAttrs.length; i++) {
- if(clientAttrs[i].name === 'commonName') {
- if( options.clientCertificateCN )
- clientAttrs[i] = { name: 'commonName', value: options.clientCertificateCN };
- else
- clientAttrs[i] = { name: 'commonName', value: 'John Doe jdoe123' };
- }
- }
-
- clientcert.setSubject(clientAttrs);
-
- // Set the issuer to the parent key
- clientcert.setIssuer(attrs);
-
- clientcert.publicKey = clientkeys.publicKey;
-
- // Sign client cert with root cert
- clientcert.sign(keyPair.privateKey);
-
- pem.clientprivate = forge.pki.privateKeyToPem(clientkeys.privateKey);
- pem.clientpublic = forge.pki.publicKeyToPem(clientkeys.publicKey);
- pem.clientcert = forge.pki.certificateToPem(clientcert);
-
- if (options.pkcs7) {
- var clientp7 = forge.pkcs7.createSignedData();
- clientp7.addCertificate(clientcert);
- pem.clientpkcs7 = forge.pkcs7.messageToPem(clientp7);
- }
- }
-
- var caStore = forge.pki.createCaStore();
- caStore.addCertificate(cert);
-
- try {
- forge.pki.verifyCertificateChain(caStore, [cert],
- function (vfd, depth, chain) {
- if (vfd !== true) {
- throw new Error('Certificate could not be verified.');
- }
- return true;
- });
- }
- catch(ex) {
- throw new Error(ex);
- }
-
- return pem;
- };
-
- var keySize = options.keySize || 1024;
-
- if (done) { // async scenario
- return forge.pki.rsa.generateKeyPair({ bits: keySize }, function (err, keyPair) {
- if (err) { return done(err); }
-
- try {
- return done(null, generatePem(keyPair));
- } catch (ex) {
- return done(ex);
- }
- });
- }
-
- var keyPair = options.keyPair ? {
- privateKey: forge.pki.privateKeyFromPem(options.keyPair.privateKey),
- publicKey: forge.pki.publicKeyFromPem(options.keyPair.publicKey)
- } : forge.pki.rsa.generateKeyPair(keySize);
-
- return generatePem(keyPair);
- };
|