diff options
Diffstat (limited to 'debian/tests/test_modules/selfsigned/index.js')
-rw-r--r-- | debian/tests/test_modules/selfsigned/index.js | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/debian/tests/test_modules/selfsigned/index.js b/debian/tests/test_modules/selfsigned/index.js new file mode 100644 index 0000000..f114d20 --- /dev/null +++ b/debian/tests/test_modules/selfsigned/index.js @@ -0,0 +1,205 @@ +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(); + } +} + +/** + * + * @param {forge.pki.CertificateField[]} attrs Attributes used for subject and issuer. + * @param {object} options + * @param {number} [options.days=365] the number of days before expiration + * @param {number} [options.keySize=1024] the size for the private key in bits + * @param {object} [options.extensions] additional extensions for the certificate + * @param {string} [options.algorithm="sha1"] The signature algorithm sha256 or sha1 + * @param {boolean} [options.pkcs7=false] include PKCS#7 as part of the output + * @param {boolean} [options.clientCertificate=false] generate client cert signed by the original key + * @param {string} [options.clientCertificateCN="John Doe jdoe123"] client certificate's common name + * @param {function} [done] Optional callback, if not provided the generation is synchronous + * @returns + */ +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); +}; |