# Certificate Module

This module defines the certificate API for Scytl's JavaScript cryptographic library. The starting point for using this module is the instantiation of a certificate service.

## How to view, build and test the source code of this module

Start by git cloning the project `comm/scytl-cryptolib` from `Stash`.

The source code of this module will be found in the directory `scytl-cryptolib/cryptolib-js-certificate/lib`.

To build this module, change to the directory `scytl-cryptolib/cryptolib-js-certificate` and do the following:

```java
npm install
--or--
mvn clean install -DskipTests
```
The unit tests of this module will be found in the directory `scytl-cryptolib/cryptolib-js-certificate/spec`. To run the tests, change to the directory `scytl-cryptolib/cryptolib-js-certificate` and do the following:

```javascript
karma test
--or--
mvn test
```
To only run a chosen test suite, add an `f` in front of the corresponding `describe` statement. For example:

```javascript
fdescribe('create a certificate service that should be able to ..', function()
...
```
To only run a chosen test, add an `f` in front of the corresponding `it` statement. For example:

```javascript
fit('load a root X.509 certificate into a new X509Certificate object and retrieve its contents',
...
```
**Note:** To build and test the entire `scytl-cryptolib` project, change to the directory `scytl-cryptolib` and do the following:

```javascript
mvn clean install
```
## How to generate the JSDoc for this module

To generate the JSDoc for this module, change to the directory `scytl-cryptolib/cryptolib-js-certificate`, build the module (if not already done) and do the following:

```javascript
node_modules/.bin/jsdoc lib
```
This will generate a file called `out`. Double click on the file `out/index.html` to view the JSDoc.

## How to `npm` install this module

To `npm` install this module in standalone mode, do the following:

```javascript
npm install --registry https://nexus.scytl.net/content/groups/public-npm/ scytl-certificate
```
To `npm` install this module as a dependency of your own module, do the following:

1. Add the following lines to the `dependencies` section of your module's `package.json` file.
    ```javascript
    "scytl-codec": "^2.1.0",
    "scytl-certificate": "^2.1.0",
    ```
2. Make sure that the `.npmrc` file of your module contains the following line.
    ```javascript
    registry=https://nexus.scytl.net/content/groups/public-npm/
    ```
3. Install all dependencies.
    ```javascript
    npm install
    ```
## How to instantiate a certificate service

The following example shows how to create a new instance of a certificate service.

```javascriptscript
var certificate = require('scytl-certificate');

var certificateService = certificate.newService();
```
## How to load an X.509 certificate and access its contents

The following example shows how to create a new `X509Certificate` object and load it with an existing X.509 certificate. The X.509 certificate is provided in PEM format.

```javascript
var certificate = certficateService.newX509Certificate(certificatePem);
```

The `X509Certificate` object defines the following properties and functions.

```java
@property publicKey The publicKey of the certificate, in PEM format.
@property notBefore The starting time of the certificate validity.
@property notAfter The ending time of the certificate validity.
@property serialNumber The serial number of the certificate.
@property subjectCommonName The subject common name of the certificate.
@property subjectOrganizationalUnit The subject organizational unit of the certificate.
@property subjectOrganization The subject organization of the certificate.
@property subjectLocality The subject locality of the certificate.
@property subjectCountry The subject country of the certificate.
@property issuerCommonName The issuer common name of the certificate.
@property issuerOrganizationalUnit The issuer organizational unit of the certificate.
@property issuerOrganization The issuer organization of the certificate.
@property issuerLocality The issuer locality of the certificate.
@property issuerCountry The issuer country of the certificate.
@property basicConstraints The basic constraints of the certificate.
@property keyUsageExtension The key usage extension of the certificate.

@function verify Verifies that the certificate provided as input was signed by the object certificate.
@function toPem Serializes the object certificate into its PEM string representation.
```
The basic constraints object defines the following properties.

```java
@property ca true if the 'CA' flag is set, false otherwise.
```
The key usage extension object defines the following properties.

```java
@property digitalSignature true if the 'digital signature' flag is set, false otherwise.
@property nonRepudiation true if the 'non-repudiation' flag is set, false otherwise.
@property keyEncipherment true if the 'key encipherment' flag is set, false otherwise.
@property dataEncipherment true if the 'data encipherment' flag is set, false otherwise.
@property keyAgreement true if the 'key agreement' flag is set, false otherwise.
@property keyCertSign true if the 'certificate signature' flag is set, false otherwise.
@property crlSign true if the 'CRL signature' flag is set, false otherwise.
@property encipherOnly true if the 'encipher only' flag is set, false otherwise.
@property decipherOnly true if the 'decipher only' flag is set, false otherwise.
```
## How to validate the content of a certificate

The following example shows how to validate the content of an existing certificate. The certificate is provided in PEM format.

```javascript
  var certificateValidator = certificateService.newValidator();

  var validationData = {
    issuer: {
      commonName: 'Test issuer CN',
      organizationalUnit: 'Test issuer Org Unit',
      organization: 'Test Org',
      country: 'Test Country'
    },
    subject: {
      commonName: 'Test subject CN',
      organizationalUnit: 'Test subject Org Unit',
      organization: 'Test subject Org',
      country: 'Test subject Country'
    },
    time: '2017-11-18\'T\'10:23:28Z',
    keyType: 'Sign',
    issuerCertificatePem: '<Issuer certificate in PEM format>'
  };

  var failedValidations = certificateValidator.validate(certificatePem, validationData);
```
The fields `issuer` and `subject` in the `validationData` object contain the issuer distinguished name (DN) and subject DN, respectively, that are expected to be found in the certificate. The `time` field contains a time reference that is expected to be within the certificate's period of validity. The `keyType` field contains the expected type of private key used by the certificate. It can have one of the following values: 'CA', 'Sign' or 'Encryption'. The `issuerCertificatePem` field contains the issuer certificate, in PEM format, that was used to sign the certificate.

If the resulting array, called `failedValidations` here, is empty, then the certificate validation passed. Otherwise, the array will contain one or more string elements indicating which types of validation failed. If the expected issuer DN could not be found in the certificate then the array will contain the string 'ISSUER'. Similarily, it will contain the string 'SUBJECT' if the expected subject DN could not be found. If the time reference is outside of the certificate's period of validity then the array will contain the string 'TIME'. If the private key of the certificate is different from that expected, then the array will contain the string 'KEY_TYPE'. If the issuer certificate provided by the validation data cannot be used to verify the signature of the certificate then the array will contain the string 'SIGNATURE'.

## How to validate the content of a certificate chain

The following example shows how to validate the content of a certificate chain.

```javascript
  var certificateValidator = certificateService.newValidator();

  var chain = {
    leaf: {
      pem: '<Leaf certificate, in PEM format>',
      keyType: 'Sign',
      subject: {
        commonName: 'Test Leaf common name',
        organizationalUnit: 'Test organizational unit',
        organization: 'Test organization',
        country: 'Test country'
      },
      time: '2017-12-25\'T\'00:00:00Z'
    },
    intermediates: {
      pems: [
        '<Intermediate certificate 1, in PEM format>',
        '<Intermediate certificate 2, in PEM format>',
        '<Intermediate certificate 3, in PEM format>',
      ],
      subjects: [{
        commonName: 'Test Intermediate certificate 1 common name',
        organizationalUnit: 'Test organizational unit',
        organization: 'Test organization',
        country: 'Test country'
      }, {
        commonName: 'Intermediate certificate 2 common name',
        organizationalUnit: 'Test organizational unit',
        organization: 'Test organization',
        country: 'Test Country'
      }, {
        commonName: 'Intermediate certificate 3 common name',
        organizationalUnit: 'Test organizational unit',
        organization: 'Test organization',
        country: 'Test Country'
      }]
    },
    root: {
      pem: '<Root certificate, in PEM format>'
    }
  };

  var failedValidations = certificateValidator.validateChain(chain);
```
The result will be a two-dimensional array of strings. If this array is empty, then the validation was successful.
Otherwise, each element in the first dimension of the array will correspond to a single certificate that failed
the validation, in ascending order of certificate authority. Each element in the second dimension will consist of
an array of failed validation types for a given certificate.

For example, for a certificate chain consisting of a leaf certificate, a single intermediate certificate and a root certificate,
the following failed validation two-dimensional array will be produced if the signature of the leaf certificate cannot be verified by the
intermediate certificate, its ending time of validity is after that of the intermediate certificate and the intermediate certificate's starting
time of validity is before that of the root certificate:

*[['SIGNATURE', 'NOT_AFTER'], ['NOT_BEFORE']]*

## How to flatten the results of a certificate chain validation

The following example shows how to flatten the two-dimensional array representing the failed validations of a
certificate chain validation into a one-dimensional array.

```javascript
  var flattenedFailedValidations = certificateValidator.flattenFailedValidations(failedValidations);
```
For the example described in the previous section, the flattened failed validations would be represented by the following one-dimensional array:

*['signature_0', 'not_after_0', 'not_before_1']*
