diff options
Diffstat (limited to 'debian/tests/test_modules/selfsigned')
-rw-r--r-- | debian/tests/test_modules/selfsigned/LICENSE | 22 | ||||
-rw-r--r-- | debian/tests/test_modules/selfsigned/index.d.ts | 57 | ||||
-rw-r--r-- | debian/tests/test_modules/selfsigned/index.js | 205 | ||||
-rw-r--r-- | debian/tests/test_modules/selfsigned/package.json | 44 |
4 files changed, 328 insertions, 0 deletions
diff --git a/debian/tests/test_modules/selfsigned/LICENSE b/debian/tests/test_modules/selfsigned/LICENSE new file mode 100644 index 0000000..d17477e --- /dev/null +++ b/debian/tests/test_modules/selfsigned/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2013 José F. Romaniello + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/debian/tests/test_modules/selfsigned/index.d.ts b/debian/tests/test_modules/selfsigned/index.d.ts new file mode 100644 index 0000000..e5b368e --- /dev/null +++ b/debian/tests/test_modules/selfsigned/index.d.ts @@ -0,0 +1,57 @@ +import { pki } from 'node-forge' + +declare interface SelfsignedOptions { + /** + * The number of days before expiration + * + * @default 365 */ + days?: number + /** + * the size for the private key in bits + * @default 1024 + */ + keySize?: number + /** + * additional extensions for the certificate + */ + extensions?: any[]; + /** + * The signature algorithm sha256 or sha1 + * @default "sha1" + */ + algorithm?: string + /** + * include PKCS#7 as part of the output + * @default false + */ + pkcs7?: boolean + /** + * generate client cert signed by the original key + * @default false + */ + clientCertificate?: undefined + /** + * client certificate's common name + * @default "John Doe jdoe123" + */ + clientCertificateCN?: string +} + +declare interface GenerateResult { + private: string + public: string + cert: string + fingerprint: string +} + +declare function generate( + attrs?: pki.CertificateField[], + opts?: SelfsignedOptions +): GenerateResult + +declare function generate( + attrs?: pki.CertificateField[], + opts?: SelfsignedOptions, + /** Optional callback, if not provided the generation is synchronous */ + done?: (err: undefined | Error, result: GenerateResult) => any +): void 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); +}; diff --git a/debian/tests/test_modules/selfsigned/package.json b/debian/tests/test_modules/selfsigned/package.json new file mode 100644 index 0000000..9dd1b0d --- /dev/null +++ b/debian/tests/test_modules/selfsigned/package.json @@ -0,0 +1,44 @@ +{ + "name": "selfsigned", + "version": "2.1.1", + "description": "Generate self signed certificates private and public keys", + "main": "index.js", + "types": "index.d.ts", + "scripts": { + "test": "mocha -t 5000" + }, + "repository": { + "type": "git", + "url": "git://github.com/jfromaniello/selfsigned.git" + }, + "keywords": [ + "openssl", + "self", + "signed", + "certificates" + ], + "author": "José F. Romaniello <jfromaniello@gmail.com> (http://joseoncode.com)", + "contributors": [ + { + "name": "Paolo Fragomeni", + "email": "paolo@async.ly", + "url": "http://async.ly" + }, + { + "name": "Charles Bushong", + "email": "bushong1@gmail.com", + "url": "http://github.com/bushong1" + } + ], + "license": "MIT", + "dependencies": { + "node-forge": "^1" + }, + "devDependencies": { + "chai": "^4.3.4", + "mocha": "^9.1.1" + }, + "engines": { + "node": ">=10" + } +} |