| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958 | 
							- /*
 
-  * 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
 
-  */
 
- /** @namespace certificates */
 
- cryptolib.modules.certificates = function(box) {
 
-   'use strict';
 
-   if (box.certificates) {
 
-     return;
 
-   }
 
-   box.certificates = {};
 
-   /**
 
-    * Provides an API that can be used to perform operations with certificates.
 
-    *
 
-    * @exports certificates/service
 
-    */
 
-   box.certificates.service = {};
 
-   var converters;
 
-   var exceptions;
 
-   cryptolib('commons', function(box) {
 
-     converters = new box.commons.utils.Converters();
 
-     exceptions = box.commons.exceptions;
 
-   });
 
-   /**
 
-    * Loads a certificate in pem format.
 
-    *
 
-    * @function
 
-    * @param {string}
 
-    *            certificatePem certificate as string in PEM format.
 
-    * @returns {certificates.box.certificates.CryptoX509Certificate} the
 
-    *          certificate.
 
-    */
 
-   box.certificates.service.load = function(certificatePem) {
 
-     return new box.certificates.CryptoX509Certificate(certificatePem);
 
-   };
 
-   /**
 
-    * Provides methods to access X509 certificate data.
 
-    *
 
-    * @class
 
-    * @param certificatePem
 
-    *            certificate as string in PEM format.
 
-    * @memberof certificates
 
-    */
 
-   box.certificates.CryptoX509Certificate = function(certificatePem) {
 
-     /** @property {object} certificate the certificate. * */
 
-     this.certificate = forge.pki.certificateFromPem(certificatePem, true);
 
-   };
 
-   box.certificates.CryptoX509Certificate.prototype = {
 
-     /**
 
-      * Retrieves the public key of the certificate.
 
-      *
 
-      * @function
 
-      * @returns public key, as string in PEM format.
 
-      * @memberof certificates.box.certificates.CryptoX509Certificate
 
-      */
 
-     getPublicKey: function() {
 
-       var publicKey = this.certificate.publicKey;
 
-       if (publicKey !== null) {
 
-         return forge.pki.publicKeyToPem(publicKey);
 
-       } else {
 
-         throw new exceptions.CryptoLibException(
 
-             'Could not find public key in certificate.');
 
-       }
 
-     },
 
-     /**
 
-      * Retrieves the start time of the certificate's validity.
 
-      *
 
-      * @function
 
-      * @returns start time of certificate validity, as Date object.
 
-      * @memberof certificates.box.certificates.CryptoX509Certificate
 
-      */
 
-     getNotBefore: function() {
 
-       var notBeforeField = this.certificate.validity.notBefore;
 
-       if (notBeforeField !== null) {
 
-         return notBeforeField;
 
-       } else {
 
-         throw new exceptions.CryptoLibException(
 
-             'Could not find validity start time in certificate.');
 
-       }
 
-     },
 
-     /**
 
-      * Retrieves the end time of the certificate's validity.
 
-      *
 
-      * @function
 
-      * @returns end time of certificate validity, as Date object.
 
-      * @memberof certificates.box.certificates.CryptoX509Certificate
 
-      */
 
-     getNotAfter: function() {
 
-       var notAfterField = this.certificate.validity.notAfter;
 
-       if (notAfterField !== null) {
 
-         return notAfterField;
 
-       } else {
 
-         throw new exceptions.CryptoLibException(
 
-             'Could not find validity end time in certificate.');
 
-       }
 
-     },
 
-     /**
 
-      * Retrieves the serial number of the certificate.
 
-      *
 
-      * @function
 
-      * @returns serial number of certificate, as hexadecimal string.
 
-      * @memberof certificates.box.certificates.CryptoX509Certificate
 
-      */
 
-     getSerialNumber: function() {
 
-       var serialNumber = this.certificate.serialNumber;
 
-       if (serialNumber !== null) {
 
-         return serialNumber;
 
-       } else {
 
-         return '';
 
-       }
 
-     },
 
-     /**
 
-      * Retrieves the issuer common name of the certificate.
 
-      *
 
-      * @function
 
-      * @returns issuer common name of certificate, as string.
 
-      * @memberof certificates.box.certificates.CryptoX509Certificate
 
-      */
 
-     getIssuerCN: function() {
 
-       var issuerCNField =
 
-           this.certificate.issuer.getField({name: 'commonName'});
 
-       if (issuerCNField !== null) {
 
-         return issuerCNField.value;
 
-       } else {
 
-         return '';
 
-       }
 
-     },
 
-     /**
 
-      * Retrieves the issuer organizational unit of the certificate.
 
-      *
 
-      * @function
 
-      * @returns issuer organizational unit of certificate, as string.
 
-      * @memberof certificates.box.certificates.CryptoX509Certificate
 
-      */
 
-     getIssuerOrgUnit: function() {
 
-       var orgUnitField = this.certificate.issuer.getField({shortName: 'OU'});
 
-       if (orgUnitField !== null) {
 
-         return orgUnitField.value;
 
-       } else {
 
-         return '';
 
-       }
 
-     },
 
-     /**
 
-      * Retrieves the issuer organization name of the certificate.
 
-      *
 
-      * @function
 
-      * @returns Issuer organization name of certificate, as string.
 
-      * @memberof certificates.box.certificates.CryptoX509Certificate
 
-      */
 
-     getIssuerOrg: function() {
 
-       var orgNameField =
 
-           this.certificate.issuer.getField({name: 'organizationName'});
 
-       if (orgNameField !== null) {
 
-         return orgNameField.value;
 
-       } else {
 
-         return '';
 
-       }
 
-     },
 
-     /**
 
-      * Retrieves the issuer locality name of the certificate.
 
-      *
 
-      * @function
 
-      * @returns Locality name of certificate, as string.
 
-      * @memberof certificates.box.certificates.CryptoX509Certificate
 
-      */
 
-     getIssuerLocality: function() {
 
-       var localityField =
 
-           this.certificate.issuer.getField({name: 'localityName'});
 
-       if (localityField !== null) {
 
-         return localityField.value;
 
-       } else {
 
-         return '';
 
-       }
 
-     },
 
-     /**
 
-      * Retrieves the issuer country name of the certificate.
 
-      *
 
-      * @function
 
-      * @returns Issuer country name of certificate, as string.
 
-      * @memberof certificates.box.certificates.CryptoX509Certificate
 
-      */
 
-     getIssuerCountry: function() {
 
-       var countryField =
 
-           this.certificate.issuer.getField({name: 'countryName'});
 
-       if (countryField !== null) {
 
-         return countryField.value;
 
-       } else {
 
-         return '';
 
-       }
 
-     },
 
-     /**
 
-      * Retrieves the subject common name of the certificate.
 
-      *
 
-      * @function
 
-      * @returns Subject common name of certificate, as string.
 
-      * @memberof certificates.box.certificates.CryptoX509Certificate
 
-      */
 
-     getSubjectCN: function() {
 
-       var subjectCNField =
 
-           this.certificate.subject.getField({name: 'commonName'});
 
-       if (subjectCNField !== null) {
 
-         return subjectCNField.value;
 
-       } else {
 
-         return '';
 
-       }
 
-     },
 
-     /**
 
-      * Retrieves the subject organizational unit of the certificate.
 
-      *
 
-      * @function
 
-      * @returns Subject organizational unit of certificate, as string.
 
-      * @memberof certificates.box.certificates.CryptoX509Certificate
 
-      */
 
-     getSubjectOrgUnit: function() {
 
-       var orgUnitField = this.certificate.subject.getField({shortName: 'OU'});
 
-       if (orgUnitField !== null) {
 
-         return orgUnitField.value;
 
-       } else {
 
-         return '';
 
-       }
 
-     },
 
-     /**
 
-      * Retrieves the subject organization name of the certificate.
 
-      *
 
-      * @function
 
-      * @return Subject organization name of certificate, as string.
 
-      * @memberof certificates.box.certificates.CryptoX509Certificate
 
-      */
 
-     getSubjectOrg: function() {
 
-       var organizationNameField =
 
-           this.certificate.subject.getField({name: 'organizationName'});
 
-       if (organizationNameField !== null) {
 
-         return organizationNameField.value;
 
-       } else {
 
-         return '';
 
-       }
 
-     },
 
-     /**
 
-      * Retrieves the subject locality name of the certificate.
 
-      *
 
-      * @function
 
-      * @returns Subject locality name of certificate, as string.
 
-      * @memberof certificates.box.certificates.CryptoX509Certificate
 
-      */
 
-     getSubjectLocality: function() {
 
-       var localityField =
 
-           this.certificate.subject.getField({name: 'localityName'});
 
-       if (localityField !== null) {
 
-         return localityField.value;
 
-       } else {
 
-         return '';
 
-       }
 
-     },
 
-     /**
 
-      * Retrieves the subject country name of the certificate.
 
-      *
 
-      * @function
 
-      * @returns Subject country name of certificate, as string.
 
-      * @memberof certificates.box.certificates.CryptoX509Certificate
 
-      */
 
-     getSubjectCountry: function() {
 
-       var countryField =
 
-           this.certificate.subject.getField({name: 'countryName'});
 
-       if (countryField !== null) {
 
-         return countryField.value;
 
-       } else {
 
-         return '';
 
-       }
 
-     },
 
-     /**
 
-      * Retrieves the key usage extension of the certificate.
 
-      *
 
-      * @function
 
-      * @return KeyUsageExtension key usage extension, as KeyUsageExtension
 
-      *         object.
 
-      * @memberof certificates.box.certificates.CryptoX509Certificate
 
-      */
 
-     getKeyUsageExtension: function() {
 
-       var keyUsageExt = this.certificate.getExtension({name: 'keyUsage'});
 
-       if (keyUsageExt !== null) {
 
-         var keyUsageMap = {};
 
-         keyUsageMap.digitalSignature = keyUsageExt.digitalSignature;
 
-         keyUsageMap.nonRepudiation = keyUsageExt.nonRepudiation;
 
-         keyUsageMap.keyEncipherment = keyUsageExt.keyEncipherment;
 
-         keyUsageMap.dataEncipherment = keyUsageExt.dataEncipherment;
 
-         keyUsageMap.keyAgreement = keyUsageExt.keyAgreement;
 
-         keyUsageMap.keyCertSign = keyUsageExt.keyCertSign;
 
-         keyUsageMap.crlSign = keyUsageExt.cRLSign;
 
-         keyUsageMap.encipherOnly = keyUsageExt.encipherOnly;
 
-         keyUsageMap.decipherOnly = keyUsageExt.decipherOnly;
 
-         return new box.certificates.KeyUsageExtension(keyUsageMap);
 
-       } else {
 
-         return null;
 
-       }
 
-     },
 
-     /**
 
-      * Retrieves the basic constraints of the certificate.
 
-      *
 
-      * @function
 
-      * @returns map containing the basic constraints.
 
-      * @memberof certificates.box.certificates.CryptoX509Certificate
 
-      */
 
-     getBasicConstraints: function() {
 
-       var basicConstraints =
 
-           this.certificate.getExtension({name: 'basicConstraints'});
 
-       if (basicConstraints !== null) {
 
-         var basicConstraintsMap = {};
 
-         basicConstraintsMap.ca = basicConstraints.cA;
 
-         return basicConstraintsMap;
 
-       } else {
 
-         return null;
 
-       }
 
-     },
 
-     /**
 
-      * Retrieves the digital signature of the certificate.
 
-      *
 
-      * @function
 
-      * @returns digital signature of certificate, as string in Base64
 
-      *          encoded format.
 
-      * @memberof certificates.box.certificates.CryptoX509Certificate
 
-      */
 
-     getSignature: function() {
 
-       var signature = this.certificate.signature;
 
-       if (signature !== null) {
 
-         var signatureB64 =
 
-             converters.base64Encode(signature, box.RSA_LINE_LENGTH);
 
-         if (signatureB64 !== null) {
 
-           return signatureB64;
 
-         } else {
 
-           throw new exceptions.CryptoLibException(
 
-               'Base64 encoding of signature is null.');
 
-         }
 
-       } else {
 
-         throw new exceptions.CryptoLibException('Signature is null.');
 
-       }
 
-     },
 
-     /**
 
-      * Verifies the digital signature of the certificate provided as input,
 
-      * using this certificate's public key.
 
-      *
 
-      * @function
 
-      * @param certificatePem
 
-      *            certificate whose signature is to be verified, as string
 
-      *            in PEM format.
 
-      * @returns boolean indicating whether signature was verified.
 
-      * @memberof certificates.box.certificates.CryptoX509Certificate
 
-      */
 
-     verify: function(certificatePem) {
 
-       var certificate = forge.pki.certificateFromPem(certificatePem);
 
-       if (certificate !== null) {
 
-         return this.certificate.verify(certificate);
 
-       } else {
 
-         throw new exceptions.CryptoLibException('Certificate is null.');
 
-       }
 
-     },
 
-     /**
 
-      * Retrieves the certificate, in PEM format.
 
-      *
 
-      * @function
 
-      * @returns certificate, as string in PEM format
 
-      * @memberof certificates.box.certificates.CryptoX509Certificate
 
-      */
 
-     toPem: function() {
 
-       if (this.certificate !== null) {
 
-         return forge.pki.certificateToPem(
 
-             this.certificate, box.RSA_LINE_LENGTH);
 
-       } else {
 
-         throw new exceptions.CryptoLibException('Certificate is null.');
 
-       }
 
-     }
 
-   };
 
-   /**
 
-    * Container class for the key usage extension flags of a digital
 
-    * certificate.
 
-    *
 
-    * @class
 
-    * @param keyUsageMap
 
-    *            map containing name-value pairs of key usage extension flags.
 
-    * @memberof certificates
 
-    */
 
-   box.certificates.KeyUsageExtension = function(keyUsageMap) {
 
-     this.keyUsageMap = keyUsageMap;
 
-   };
 
-   box.certificates.KeyUsageExtension.prototype = {
 
-     /**
 
-      * Retrieves the digital signature flag of the key usage extension.
 
-      *
 
-      * @function
 
-      * @returns boolean indicating whether digital signature flag is set.
 
-      * @memberof certificates.box.certificates.KeyUsageExtension
 
-      */
 
-     digitalSignature: function() {
 
-       return this.keyUsageMap.digitalSignature;
 
-     },
 
-     /**
 
-      * Retrieves the non-repudiation flag of the key usage extension.
 
-      *
 
-      * @function
 
-      * @return boolean indicating whether non-repudiation flag is set.
 
-      * @memberof certificates.box.certificates.KeyUsageExtension
 
-      */
 
-     nonRepudiation: function() {
 
-       return this.keyUsageMap.nonRepudiation;
 
-     },
 
-     /**
 
-      * Retrieves the key encipherment flag of the key usage extension.
 
-      *
 
-      * @function
 
-      * @returns boolean indicating whether key encipherment flag is set.
 
-      * @memberof certificates.box.certificates.KeyUsageExtension
 
-      */
 
-     keyEncipherment: function() {
 
-       return this.keyUsageMap.keyEncipherment;
 
-     },
 
-     /**
 
-      * Retrieves the data encipherment flag of the key usage extension.
 
-      *
 
-      * @function
 
-      * @returns boolean indicating whether data encipherment flag is set.
 
-      * @memberof certificates.box.certificates.KeyUsageExtension
 
-      */
 
-     dataEncipherment: function() {
 
-       return this.keyUsageMap.dataEncipherment;
 
-     },
 
-     /**
 
-      * Retrieves the key agreement flag of the key usage extension.
 
-      *
 
-      * @function
 
-      * @returns boolean indicating whether key agreement flag is set.
 
-      * @memberof certificates.box.certificates.KeyUsageExtension
 
-      */
 
-     keyAgreement: function() {
 
-       return this.keyUsageMap.keyAgreement;
 
-     },
 
-     /**
 
-      * Retrieves the key certificate sign flag of the key usage extension.
 
-      *
 
-      * @function
 
-      * @returns Boolean indicating whether key certificate sign flag is set.
 
-      * @memberof certificates.box.certificates.KeyUsageExtension
 
-      */
 
-     keyCertSign: function() {
 
-       return this.keyUsageMap.keyCertSign;
 
-     },
 
-     /**
 
-      * Retrieves the CRL sign flag of the key usage extension.
 
-      *
 
-      * @function
 
-      * @returns boolean indicating whether CRL sign flag is set.
 
-      * @memberof certificates.box.certificates.KeyUsageExtension
 
-      */
 
-     crlSign: function() {
 
-       return this.keyUsageMap.crlSign;
 
-     },
 
-     /**
 
-      * Retrieves the encipher only flag of the key usage extension.
 
-      *
 
-      * @function
 
-      * @returns boolean indicating whether encipher only flag is set.
 
-      * @memberof certificates.box.certificates.KeyUsageExtension
 
-      */
 
-     encipherOnly: function() {
 
-       return this.keyUsageMap.encipherOnly;
 
-     },
 
-     /**
 
-      * Retrieves the decipher only flag of the key usage extension.
 
-      *
 
-      * @function
 
-      * @returns boolean indicating whether decipher only flag is set.
 
-      * @memberof certificates.box.certificates.KeyUsageExtension
 
-      */
 
-     decipherOnly: function() {
 
-       return this.keyUsageMap.decipherOnly;
 
-     },
 
-     /**
 
-      * Retrieves the CA flag of the key usage extension.
 
-      *
 
-      * @function
 
-      * @return boolean indicating whether CA flag is set.
 
-      * @memberof certificates.box.certificates.KeyUsageExtension
 
-      */
 
-     ca: function() {
 
-       return this.keyUsageMap.ca;
 
-     }
 
-   };
 
-   /**
 
-    * Class that validates the content of a CryptoX509Certificate.
 
-    *
 
-    * @class
 
-    * @param validationData
 
-    * @param {string}
 
-    *            validationData.subject
 
-    * @param {string}
 
-    *            validationData.subject.commonName
 
-    * @param {string}
 
-    *            validationData.subject.organization
 
-    * @param {string}
 
-    *            validationData.subject.organizationUnit
 
-    * @param {string}
 
-    *            validationData.subject.country
 
-    * @param {string}
 
-    *            validationData.issuer
 
-    * @param {string}
 
-    *            validationData.issuer.commonName
 
-    * @param {string}
 
-    *            validationData.issuer.organization
 
-    * @param {string}
 
-    *            validationData.issuer.organizationUnit
 
-    * @param {string}
 
-    *            validationData.issuer.country
 
-    * @param {string}
 
-    *            validationData.time
 
-    * @param {string}
 
-    *            validationData.keytype CA, Sign or Encryption
 
-    * @param {string}
 
-    *            validationData.caCertificatePem
 
-    * @memberof certificates
 
-    */
 
-   box.certificates.CryptoX509CertificateValidator = function(validationData) {
 
-     var parseIsoDate = function(isoDate) {
 
-       var dateChunks = isoDate.split(/\D/);
 
-       return new Date(Date.UTC(
 
-           +dateChunks[0], --dateChunks[1], +dateChunks[2], +dateChunks[5],
 
-           +dateChunks[6], +dateChunks[7], 0));
 
-     };
 
-     /**
 
-      * Validates the content of the X.509 certificate.
 
-      *
 
-      * @function
 
-      * @param certificatePem
 
-      *            certificate as string in PEM format.
 
-      * @return an array containing the errors type, if any.
 
-      */
 
-     this.validate = function(x509CertificatePem) {
 
-       var cryptoX509Certificate =
 
-           new box.certificates.CryptoX509Certificate(x509CertificatePem);
 
-       var failedValidations = [];
 
-       var validateSubject = function(subject) {
 
-         if (subject.commonName !== cryptoX509Certificate.getSubjectCN() ||
 
-             subject.organization !== cryptoX509Certificate.getSubjectOrg() ||
 
-             subject.organizationUnit !==
 
-                 cryptoX509Certificate.getSubjectOrgUnit() ||
 
-             subject.country !== cryptoX509Certificate.getSubjectCountry()) {
 
-           failedValidations.push('SUBJECT');
 
-         }
 
-       };
 
-       var validateIssuer = function(issuer) {
 
-         if (issuer.commonName !== cryptoX509Certificate.getIssuerCN() ||
 
-             issuer.organization !== cryptoX509Certificate.getIssuerOrg() ||
 
-             issuer.organizationUnit !==
 
-                 cryptoX509Certificate.getIssuerOrgUnit() ||
 
-             issuer.country !== cryptoX509Certificate.getIssuerCountry()) {
 
-           failedValidations.push('ISSUER');
 
-         }
 
-       };
 
-       var validateTime = function(isoDate) {
 
-         var time = parseIsoDate(isoDate);
 
-         if (time.toString() === 'Invalid Date' ||
 
-             time - cryptoX509Certificate.getNotBefore() < 0 ||
 
-             time - cryptoX509Certificate.getNotAfter() > 0) {
 
-           failedValidations.push('TIME');
 
-         }
 
-       };
 
-       var areBasicConstraintsValid = function(keyType) {
 
-         var returnValue = true;
 
-         var basicConstraints = cryptoX509Certificate.getBasicConstraints();
 
-         if (keyType === 'CA' &&
 
-             (!basicConstraints || basicConstraints.ca !== true)) {
 
-           returnValue = false;
 
-         }
 
-         return returnValue;
 
-       };
 
-       var isKeyUsageValid = function(keyType) {
 
-         var returnValue = true;
 
-         var keyUsageExtension = cryptoX509Certificate.getKeyUsageExtension();
 
-         if (!keyUsageExtension) {
 
-           return false;
 
-         }
 
-         switch (keyType) {
 
-           case 'CA':
 
-             if (keyUsageExtension.keyCertSign() !== true ||
 
-                 keyUsageExtension.crlSign() !== true) {
 
-               returnValue = false;
 
-             }
 
-             break;
 
-           case 'Sign':
 
-             if (keyUsageExtension.digitalSignature() !== true ||
 
-                 keyUsageExtension.nonRepudiation() !== true) {
 
-               returnValue = false;
 
-             }
 
-             break;
 
-           case 'Encryption':
 
-             if (keyUsageExtension.keyEncipherment() !== true ||
 
-                 keyUsageExtension.dataEncipherment() !== true) {
 
-               returnValue = false;
 
-             }
 
-             break;
 
-           default:
 
-             returnValue = false;
 
-         }
 
-         return returnValue;
 
-       };
 
-       var validateKeyType = function(keyType) {
 
-         if (!areBasicConstraintsValid(keyType) || !isKeyUsageValid(keyType)) {
 
-           failedValidations.push('KEY_TYPE');
 
-         }
 
-       };
 
-       var validateSignature = function(caCertificatePem) {
 
-         var caCryptoX509Certificate =
 
-             new box.certificates.CryptoX509Certificate(caCertificatePem);
 
-         if (caCryptoX509Certificate === null) {
 
-           failedValidations.push('SIGNATURE');
 
-           throw new exceptions.CryptoLibException('CA certificate is null.');
 
-         }
 
-         try {
 
-           if (!caCryptoX509Certificate.verify(x509CertificatePem)) {
 
-             failedValidations.push('SIGNATURE');
 
-           }
 
-         } catch (error) {
 
-           failedValidations.push('SIGNATURE');
 
-           throw new exceptions.CryptoLibException(
 
-               'Signature verification process failed.');
 
-         }
 
-       };
 
-       if (validationData.subject) {
 
-         validateSubject(validationData.subject);
 
-       }
 
-       if (validationData.issuer) {
 
-         validateIssuer(validationData.issuer);
 
-       }
 
-       if (validationData.time) {
 
-         validateTime(validationData.time);
 
-       }
 
-       if (validationData.keyType) {
 
-         validateKeyType(validationData.keyType);
 
-       }
 
-       if (validationData.caCertificatePem) {
 
-         validateSignature(validationData.caCertificatePem);
 
-       }
 
-       return failedValidations;
 
-     };
 
-   };
 
-   /**
 
-    * Class that validates the content of a CryptoX509Certificate.
 
-    *
 
-    * @function
 
-    * @param validationData
 
-    *            {json}
 
-    * @param {string}
 
-    *            validationData.subject the subject data.
 
-    * @param {string}
 
-    *            validationData.subject.commonName
 
-    * @param {string}
 
-    *            validationData.subject.organization
 
-    * @param {string}
 
-    *            validationData.subject.organizationUnit
 
-    * @param {string}
 
-    *            validationData.subject.country
 
-    * @param {string}
 
-    *            validationData.issuer the issuer data.
 
-    * @param {string}
 
-    *            validationData.issuer.commonName
 
-    * @param {string}
 
-    *            validationData.issuer.organization
 
-    * @param {string}
 
-    *            validationData.issuer.organizationUnit
 
-    * @param {string}
 
-    *            validationData.issuer.country
 
-    * @param {string}
 
-    *            validationData.time time to be checked.
 
-    * @param {string}
 
-    *            validationData.keyType CA, Sign or Encryption.
 
-    * @param {string}
 
-    *            validationData.caCertificatePem
 
-    * @param certificate
 
-    *            certificate as string in PEM format.
 
-    * @returns {Array} an array that contains the error types occurred, if any.
 
-    */
 
-   box.certificates.service.validateCertificate = function(
 
-       validationData, certificate) {
 
-     if (validationData === null) {
 
-       throw new exceptions.CryptoLibException('Validation data is null.');
 
-     }
 
-     if (Object.getOwnPropertyNames(validationData).length) {
 
-       throw new exceptions.CryptoLibException('Validation data is empty.');
 
-     }
 
-     if (certificate === null) {
 
-       throw new exceptions.CryptoLibException('Certificate is null.');
 
-     }
 
-     return (new box.certificates.CryptoX509CertificateValidator(validationData))
 
-         .validate(certificate);
 
-   };
 
-   /**
 
-    * Validates the certificate information provided to the constructor. The
 
-    * validation process loops through all certificates, starting with the leaf
 
-    * certificate, until it reaches the trusted certificate. For each
 
-    * certificate, except the trusted certificate, it checks that the following
 
-    * conditions hold:
 
-    * <ul>
 
-    * <li>Subject DN is that expected for given certificate.</li>
 
-    * <li>Issuer DN is same as subject DN of next certificate in chain.</li>
 
-    * <li>Key type is that expected: "signing" or "encryption" for leaf
 
-    * certificate and "CA" for rest of certificates in chain.</li>
 
-    * <li>Signature can be verified with public key of next certificate in
 
-    * chain.</li>
 
-    * <li>Starting time is earlier than ending time.</li>
 
-    * <li>Starting time is equal to or later than starting time of next
 
-    * certificate in chain.</li>
 
-    * <li>Ending time is equal to or earlier than ending time of next
 
-    * certificate in chain.</li>
 
-    * </ul>
 
-    * In addition, if a non-null value is provided to the constructor for the
 
-    * time reference, it will be checked whether this time reference is within
 
-    * the dates of validity of the leaf certificate. After the validation
 
-    * process has completed, a list of strings will be returned. If this list
 
-    * is empty, then the validation was successful. Otherwise, the list will
 
-    * contain string identifiers for each type of validation that failed.
 
-    *
 
-    * @function
 
-    * @param {json}
 
-    *            chain certificate chain.
 
-    * @param {json}
 
-    *            chain.leaf leaf certificate.
 
-    * @param {string}
 
-    *            chain.leaf.pem X.509 certificate.
 
-    * @param {string}
 
-    *            chain.leaf.keyType keyType.
 
-    * @param {string}
 
-    *            chain.leaf.subject subject.
 
-    * @param {string}
 
-    *            chain.leaf.time time reference (Optional). Only mandatory if
 
-    *            the 'Time' validation is going to be performed.
 
-    * @param {json}
 
-    *            chain.certificates chain of certificates.
 
-    * @param {Array}
 
-    *            chain.certificates.pems list of X.509 Certificates as string
 
-    *            in pem format. The list starts by the one closer to the root.
 
-    * @param {Array}
 
-    *            chain.certificates.subjects list of subjects
 
-    * @param {Array}
 
-    *            chain.root X.509 trusted Certificate.
 
-    * @returns {Array} a two dimension array where the first dimension is the
 
-    *          index of the element starting by 1 -leaf certificate - and the
 
-    *          second dimension holds the error types.
 
-    */
 
-   box.certificates.service.validateX509CertificateChain = function(chain) {
 
-     var validateDateRange = function(certificate, failedValidation) {
 
-       if (certificate.getNotBefore() > certificate.getNotAfter()) {
 
-         failedValidation.push('VALIDITY_PERIOD');
 
-       }
 
-     };
 
-     var validateNotBefore = function(
 
-         notBefore, previousNotBefore, failedValidation) {
 
-       if (notBefore < previousNotBefore) {
 
-         failedValidation.push('NOT_BEFORE');
 
-       }
 
-     };
 
-     var validateNotAfter = function(
 
-         notAfter, previousNotAfter, failedValidation) {
 
-       if (notAfter > previousNotAfter) {
 
-         failedValidation.push('NOT_AFTER');
 
-       }
 
-     };
 
-     var validateLeafCertificate = function(
 
-         issuer, signature, previousNotBefore, previousNotAfter) {
 
-       var validationData = {
 
-         subject: chain.leaf.subject,
 
-         issuer: issuer,
 
-         keyType: chain.leaf.keyType,
 
-         caCertificatePem: signature
 
-       };
 
-       if (chain.leaf.time) {
 
-         validationData.time = chain.leaf.time;
 
-       }
 
-       var certificateValidator =
 
-           new box.certificates.CryptoX509CertificateValidator(validationData);
 
-       var failedValidations = certificateValidator.validate(chain.leaf.pem);
 
-       var certificate =
 
-           new box.certificates.CryptoX509Certificate(chain.leaf.pem);
 
-       validateDateRange(certificate, failedValidations);
 
-       validateNotBefore(
 
-           certificate.getNotBefore(), previousNotBefore, failedValidations);
 
-       validateNotAfter(
 
-           certificate.getNotAfter(), previousNotAfter, failedValidations);
 
-       return failedValidations;
 
-     };
 
-     var rootCertificate =
 
-         new box.certificates.CryptoX509Certificate(chain.root);
 
-     var issuer = {
 
-       commonName: rootCertificate.getSubjectCN(),
 
-       organization: rootCertificate.getSubjectOrg(),
 
-       organizationUnit: rootCertificate.getSubjectOrgUnit(),
 
-       country: rootCertificate.getSubjectCountry()
 
-     };
 
-     var signature = chain.root;
 
-     var failedValidation = [];
 
-     var previousNotBefore = rootCertificate.getNotBefore();
 
-     var previousNotAfter = rootCertificate.getNotAfter();
 
-     var certificateValidator;
 
-     chain.certificates.pems.reverse();
 
-     chain.certificates.subjects.reverse();
 
-     for (var i = 0; i < chain.certificates.pems.length; i++) {
 
-       var certificate = new box.certificates.CryptoX509Certificate(
 
-           chain.certificates.pems[i]);
 
-       var validationData = {
 
-         subject: chain.certificates.subjects[i],
 
-         issuer: issuer,
 
-         keyType: 'CA',
 
-         signature: signature
 
-       };
 
-       certificateValidator =
 
-           new box.certificates.CryptoX509CertificateValidator(validationData);
 
-       failedValidation[i] =
 
-           certificateValidator.validate(chain.certificates.pems[i]);
 
-       validateDateRange(certificate, failedValidation[i]);
 
-       validateNotBefore(
 
-           certificate.getNotBefore(), previousNotBefore, failedValidation[i]);
 
-       validateNotAfter(
 
-           certificate.getNotAfter(), previousNotAfter, failedValidation[i]);
 
-       issuer = {
 
-         commonName: certificate.getSubjectCN(),
 
-         organization: certificate.getSubjectOrg(),
 
-         organizationUnit: certificate.getSubjectOrgUnit(),
 
-         country: certificate.getSubjectCountry()
 
-       };
 
-       signature = chain.certificates.pems[i];
 
-       previousNotBefore = certificate.getNotBefore();
 
-       previousNotAfter = certificate.getNotAfter();
 
-     }
 
-     failedValidation.push(validateLeafCertificate(
 
-         issuer, signature, previousNotBefore, previousNotAfter));
 
-     failedValidation.reverse();
 
-     return failedValidation;
 
-   };
 
-   /**
 
-    * Flattens failed validations to a one dimensional array to a one
 
-    * dimensional array.
 
-    *
 
-    * @function
 
-    * @param {array}
 
-    *            failedValidations a two-dimensional failed validations array.
 
-    * @returns {array} a flat array in which each element contains the error
 
-    *          type message piped with the index of the element, i.e.
 
-    * ERROR_<element index>.
 
-    */
 
-   box.certificates.service.flattenFailedValidations = function(
 
-       failedValidations) {
 
-     var flattenFailedValidations = Array();
 
-     for (var i = 0; i < failedValidations.length; i++) {
 
-       if (failedValidations[i] !== undefined) {
 
-         for (var j = 0; j < failedValidations[i].length; j++) {
 
-           flattenFailedValidations.push(
 
-               failedValidations[i][j].toLowerCase() + '_' + (i));
 
-         }
 
-       }
 
-     }
 
-     return flattenFailedValidations;
 
-   };
 
- };
 
- cryptolib.modules.certificates.service = cryptolib.modules.certificates;
 
 
  |