123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- /*
- * Copyright 2018 Scytl Secure Electronic Voting SA
- *
- * All rights reserved
- *
- * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
- */
- cryptolib.modules.stores = cryptolib.modules.stores || {};
- /**
- * Defines a pkcs12 store.
- */
- cryptolib.modules.stores.pkcs12 = function(box) {
- 'use strict';
- box.stores = box.stores || {};
- box.stores.pkcs12 = {};
- var converters;
- var exceptions;
- cryptolib('commons', function(box) {
- converters = new box.commons.utils.Converters();
- exceptions = box.commons.exceptions;
- });
- /**
- * Defines a PKCS12.
- *
- * @param pkcs12DerB64
- * PKCS12, as string in Base64 encoded DER format.
- */
- box.stores.pkcs12.Pkcs12 = function(pkcs12DerB64) {
- this.pkcs12Der = converters.base64Decode(pkcs12DerB64);
- this.pkcs12Asn1 = forge.asn1.fromDer(this.pkcs12Der, false);
- };
- box.stores.pkcs12.Pkcs12.prototype = {
- /**
- * Retrieves the private key of the PKCS12.
- *
- * @param passwordB64
- * Password as string in Base64 encoded format.
- * @return Private key of PKCS12, as string in PEM format.
- */
- getPrivateKey: function(passwordB64) {
- var aliases = Array.prototype.slice.call(arguments, 1);
- function isAliasInList(alias) {
- var returnValue = false;
- if (aliases.indexOf(alias) >= 0) {
- returnValue = true;
- }
- return returnValue;
- }
- var privateKeyAlias = '';
- try {
- var password = converters.base64Decode(passwordB64);
- var pkcs12 =
- forge.pkcs12.pkcs12FromAsn1(this.pkcs12Asn1, false, password);
- // Retrieve private key safe bag from PKCS12.
- var privateKeys = {};
- for (var i = 0; i < pkcs12.safeContents.length; i++) {
- var safeContents = pkcs12.safeContents[i];
- for (var j = 0; j < safeContents.safeBags.length; j++) {
- var safeBag = safeContents.safeBags[j];
- if (safeBag.type === forge.pki.oids.pkcs8ShroudedKeyBag) {
- privateKeyAlias = safeBag.attributes.friendlyName[0];
- if (aliases.length === 0 || isAliasInList(privateKeyAlias)) {
- privateKeys[privateKeyAlias] =
- forge.pki.privateKeyToPem(safeBag.key);
- }
- }
- }
- }
- // Check whether any private key safe bags were found.
- if (Object.getOwnPropertyNames(privateKeys).length === 0) {
- throw new exceptions.CryptoLibException(
- 'Could not find any private key safe bags in PKCS12.');
- }
- return privateKeys;
- } catch (error) {
- var errorMsg = 'Could not retrieve private key from PKCS12.';
- if (privateKeyAlias.length > 0) {
- errorMsg = 'Could not retrieve private key with alias ' +
- privateKeyAlias + ' from PKCS12.';
- }
- throw new exceptions.CryptoLibException(errorMsg);
- }
- },
- /**
- * Retrieves the private key chain from the PKCS12.
- *
- * @param passwordB64
- * Password as string in Base64 encoded format.
- * @return Private key chain of PKCS12, as PrivateKeyChain object.
- */
- getPrivateKeyChain: function(passwordB64) {
- try {
- var password = converters.base64Decode(passwordB64);
- var pkcs12 =
- forge.pkcs12.pkcs12FromAsn1(this.pkcs12Asn1, false, password);
- // Retrieve private key safe bags from PKCS12.
- var privateKeyChain = new box.stores.pkcs12.PrivateKeyChain();
- for (var i = 0; i < pkcs12.safeContents.length; i++) {
- var safeContents = pkcs12.safeContents[i];
- for (var j = 0; j < safeContents.safeBags.length; j++) {
- var safeBag = safeContents.safeBags[j];
- if (safeBag.type === forge.pki.oids.pkcs8ShroudedKeyBag) {
- var alias = safeBag.attributes.friendlyName[0];
- var privateKeyPem = forge.pki.privateKeyToPem(safeBag.key);
- privateKeyChain.add(alias, privateKeyPem);
- }
- }
- }
- // Check whether any private key safe bags were found.
- if (privateKeyChain.length === 0) {
- throw new exceptions.CryptoLibException(
- 'Could not find any private key safe bags in PKCS12.');
- }
- return privateKeyChain;
- } catch (error) {
- throw new exceptions.CryptoLibException(
- 'Could not retrieve private key chain from PKCS12.', error);
- }
- },
- /**
- * Retrieves the certificate chain of the PKCS12.
- *
- * @param passwordB64
- * Password as string in Base64 encoded format.
- * @return Certificate chain of PKCS12, as array of strings in PEM
- * format.
- */
- getCertificateChain: function(passwordB64) {
- try {
- var password = converters.base64Decode(passwordB64);
- var pkcs12 =
- forge.pkcs12.pkcs12FromAsn1(this.pkcs12Asn1, false, password);
- // Retrieve certificate safe bags from PKCS12.
- var certificatePemChain = [];
- for (var i = 0; i < pkcs12.safeContents.length; i++) {
- var safeContents = pkcs12.safeContents[i];
- for (var j = 0; j < safeContents.safeBags.length; j++) {
- var safeBag = safeContents.safeBags[j];
- if (safeBag.type === forge.pki.oids.certBag) {
- var certificatePem = forge.pki.certificateToPem(safeBag.cert);
- certificatePemChain.push(certificatePem);
- }
- }
- }
- // Check whether any certificate safe bags were found.
- if (certificatePemChain.length === 0) {
- throw new exceptions.CryptoLibException(
- 'Could not find any certificate safe bags in PKCS12.');
- }
- return certificatePemChain;
- } catch (error) {
- throw new exceptions.CryptoLibException(
- 'Could not retrieve certificate chain from PKCS12.', error);
- }
- },
- /**
- * Retrieves the certificate chain of the PKCS12 filtered by alias.
- *
- * @param passwordB64
- * Password as string in Base64 encoded format.
- * @param alias
- * Alias to filter
- * @return Certificate chain of PKCS12, as array of strings in PEM
- * format.
- */
- getCertificateChainByAlias: function(passwordB64, alias) {
- try {
- var password = converters.base64Decode(passwordB64);
- var pkcs12 =
- forge.pkcs12.pkcs12FromAsn1(this.pkcs12Asn1, false, password);
- var discardedBags = {};
- var nextBagId = null;
- // Retrieve certificate safe bags from PKCS12.
- var certificatePemChain = [];
- for (var i = 0; i < pkcs12.safeContents.length; i++) {
- var safeContents = pkcs12.safeContents[i];
- for (var j = 0; j < safeContents.safeBags.length; j++) {
- var safeBag = safeContents.safeBags[j];
- if (safeBag.type === forge.pki.oids.certBag) {
- var bagFound = null;
- // if not initializated the chain, find the one with alias
- // or if is the one that goes next into the list take it
- if ((!nextBagId && safeBag.attributes &&
- safeBag.attributes.friendlyName &&
- safeBag.attributes.friendlyName[0] === alias) ||
- (nextBagId && nextBagId === safeBag.cert.subject.hash)) {
- bagFound = safeBag;
- }
- // otherwise, if not initializated and it's not the alias, save it
- // for later use
- else {
- discardedBags[safeBag.cert.subject.hash] = safeBag;
- }
- // add the bag and check if we have the next one in the list we
- // had
- while (bagFound) {
- // transform the current to PEM and save it
- var certificatePem = forge.pki.certificateToPem(bagFound.cert);
- certificatePemChain.push(certificatePem);
- // we arrived to the root so we are done!
- if (bagFound.cert.subject.hash === bagFound.cert.issuer.hash) {
- return certificatePemChain;
- }
- // save which is the next bag we need
- nextBagId = bagFound.cert.issuer.hash;
- // go for the next in the list of discarded ones
- bagFound = discardedBags[nextBagId];
- }
- }
- }
- }
- // Check whether any certificate safe bags were found.
- if (certificatePemChain.length === 0) {
- throw new exceptions.CryptoLibException(
- 'Could not find any certificates for that alias.');
- }
- return certificatePemChain;
- } catch (error) {
- throw new exceptions.CryptoLibException(
- 'Could not retrieve certificate chain from PKCS12.', error);
- }
- },
- /**
- * Retrieves an issuer certificate from the certificate chain of the
- * PKCS12, given the issuer common name.
- *
- * @param passwordB64
- * Password as string in Base64 encoded format.
- * @param issuerCn
- * Issuer common name of certificate to retrieve, as string.
- * @return Certificate with given issuer common name, as string in PEM
- * format.
- */
- getCertificateByIssuer: function(passwordB64, issuerCn) {
- try {
- var password = converters.base64Decode(passwordB64);
- var pkcs12 =
- forge.pkcs12.pkcs12FromAsn1(this.pkcs12Asn1, false, password);
- // Retrieve certificate from PKCS12.
- var certificate = null;
- var certificateFound = false;
- for (var i = 0; i < pkcs12.safeContents.length; i++) {
- var safeContents = pkcs12.safeContents[i];
- for (var j = 0; j < safeContents.safeBags.length; j++) {
- var safeBag = safeContents.safeBags[j];
- if (safeBag.type === forge.pki.oids.certBag &&
- safeBag.cert.issuer.getField('CN').value === issuerCn) {
- certificate = safeBag.cert;
- certificateFound = true;
- break;
- }
- }
- if (certificateFound) {
- break;
- }
- }
- // Check whether certificate was found.
- if (certificate === null) {
- throw new exceptions.CryptoLibException(
- 'Could not find certificate in PKCS12 with issuer common name ' +
- issuerCn);
- }
- return forge.pki.certificateToPem(certificate);
- } catch (error) {
- throw new exceptions.CryptoLibException(
- 'Could not retrieve certificate with issuer common name ' +
- issuerCn + ' from PKCS12.',
- error);
- }
- },
- /**
- * Retrieves the subject certificate from the certificate chain of the
- * PKCS12, given the subject common name.
- *
- * @param passwordB64
- * Password as string in Base64 encoded format.
- * @param subjectCn
- * Subject common name of certificate to retrieve, as string.
- * @return Certificate with given issuer common name, as string in PEM
- * format.
- */
- getCertificateBySubject: function(passwordB64, subjectCn) {
- try {
- var password = converters.base64Decode(passwordB64);
- var pkcs12 =
- forge.pkcs12.pkcs12FromAsn1(this.pkcs12Asn1, false, password);
- // Retrieve subject certificate from PKCS12.
- var certificate = null;
- var certificateFound = false;
- for (var i = 0; i < pkcs12.safeContents.length; i++) {
- var safeContents = pkcs12.safeContents[i];
- for (var j = 0; j < safeContents.safeBags.length; j++) {
- var safeBag = safeContents.safeBags[j];
- if (safeBag.type === forge.pki.oids.certBag &&
- safeBag.cert.subject.getField('CN').value === subjectCn) {
- certificate = safeBag.cert;
- certificateFound = true;
- break;
- }
- }
- if (certificateFound) {
- break;
- }
- }
- // Check whether certificate was found.
- if (certificate === null) {
- throw new exceptions.CryptoLibException(
- 'Could not find certificate in PKCS12 with subject common name ' +
- subjectCn);
- }
- return forge.pki.certificateToPem(certificate);
- } catch (error) {
- throw new exceptions.CryptoLibException(
- 'Could not retrieve certificate with subject common name ' +
- subjectCn + ' from PKCS12.',
- error);
- }
- },
- /**
- * Retrieves the PKCS12 as a Base64 encoded DER string.
- *
- * @return PKCS12, as Base64 encoded DER string.
- */
- getBase64Encoded: function() {
- return converters.base64Encode(this.pkcs12Der);
- }
- };
- /**
- * Container class for a chain of private keys to be inserted in a key
- * store.
- */
- box.stores.pkcs12.PrivateKeyChain = function() {
- this.map = {};
- };
- box.stores.pkcs12.PrivateKeyChain.prototype = {
- /**
- * Adds a private key to the chain.
- *
- * @param alias
- * Alias of private key, as string.
- * @param privateKeyPem
- * Private key to add, as string in PEM format.
- */
- add: function(alias, privateKeyPem) {
- this.map[alias] = privateKeyPem;
- },
- /**
- * Retrieves a private key from the chain.
- *
- * @return Private key chain, as array of strings in PEM format.
- */
- get: function(alias) {
- return this.map[alias];
- }
- };
- };
|