PKIjs is a JavaScript PKI (Public Key Infrastructure) library used for decoding and parsing SSL certificates directly on the client or browser, eliminating in many cases the need to do this work on the server side. PKIjs is built on top of the Web Cryptography API. The PKIjs library goes almost hand in hand with the ASN1.js JavaScript Library.
PKIjs was used to create our Certificate Decoder.
Install PKIjs
PKIjs is available in the Node Package Manager (npm). To install, simply run npm i pkijs
, assuming npm has already been installed.
ASN1js is also available in the Node Package Manager (npm) and can be installed similarily. This package is required for some of the examples below. npm i ans1js
PKIjs Examples
The following are examples of how to use this PKI JavaScript in your code. The list of examples is not exhaustive so please let us know in the comments if we have not covered an example that will help you in your project.
PKIjs parse certificate
To parse an x509 certificate with JavaScript, it’s first important to understand what data you are looking for. The library is based on RFC-5280 for more information on each component of an X509 SSL Certificate.
In order to parse specific components of the certificate, it is first necessary to convert the PEM encoded certificate to the PKIjs Certificate object.
// 1. Strip off the header and footer of the PEM encoding
const b64 = pem.replace(/(-----(BEGIN|END) CERTIFICATE-----|[\n\r])/g, '');
// 2. Convert to the binary DER format
const der = Buffer.from(b64, 'base64');
// 3. Convert to BER encoding
const ber = new Uint8Array(der).buffer;
// 4. Create the asn1js Certificate object
const asn1 = asn1js.fromBER(ber);
const { Certificate } = pkijs;
return new Certificate({ schema: asn1.result });
After creating the Certificate object, you can begin to parse each component of the certificate.
Example of how to parse the the Subject DN (distinguished name):
The Subject DN may consist of many different parts. This example will focus on a few of them, based on their OID (Object Identifier). For this example, the following object identifiers and their DN value will be used:
2.5.4.3 | Common Name |
2.5.4.6 | Country |
2.5.4.10 | Organizational Unit |
2.5.4.11 | Organization |
2.5.4.7 | Locality |
2.5.4.8 | State |
2.5.4.9 | Street |
2.5.4.17 | Postal Code |
Here is an example function of how to decode the subject dn:
subject = decodeDn(certificate.subject.typesAndValues);
decodeDn(subject) {
const localSubject = {};
subject.forEach((item) => {
if (item.type === '2.5.4.3') {
localSubject.commonName = item.value.valueBlock.value;
} else if (item.type === '2.5.4.6') {
localSubject.country = item.value.valueBlock.value;
} else if (item.type === '2.5.4.10') {
localSubject.orgUnit = item.value.valueBlock.value;
} else if (item.type === '2.5.4.11') {
localSubject.org = item.value.valueBlock.value;
} else if (item.type === '2.5.4.7') {
localSubject.locality = item.value.valueBlock.value;
} else if (item.type === '2.5.4.8') {
localSubject.state = item.value.valueBlock.value;
} else if (item.type === '2.5.4.9') {
localSubject.street = item.value.valueBlock.value;
} else if (item.type === '2.5.4.17') {
localSubject.postalCode = item.value.valueBlock.value;
}
});
return localSubject;
Note that the Issuer DN may be decoded the same way. The decodeDn function above is general purpose for any DN.
PKIjs fingerprint
The fingerprint is a complex example and requires use of the Web Crypto API. It is an async function and takes in the BER encoded PKIjs Certificate object to compute the fingerprint of.
async computeFingerprint(certificate) {
const hash = async (algo, buffer) => {
const hashBuffer = await crypto.subtle.digest(algo, buffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray
.map((b) => (`00${b.toString(16)}`).slice(-2))
.join(':')
.toUpperCase();
};
this.fingerprint256 = await hash('SHA-256', certificate);
this.fingerprint128 = await hash('SHA-1', certificate);
}
Validate the before and after (expiration) date of the certificate
The notAfter and notBefore values hang directly on the PKIjs Certificate object. The following example will compute whether or not the certificate validity is valid based on these values. The moment package is required for this computation. npm install moment
notAfter = certificate.notAfter.value.toUTCString();
notBefore = certificate.notBefore.value.toUTCString();
if (!moment(certificate.notBefore.value).isBefore(new Date())) {
preValid = true;
} else if (!moment(certificate.notAfter.value).isAfter(new Date())) {
expired = true;
}
Please let us know of any additional PKIjs examples you would like to see.
Read more of our content on secure web technologies including our crypto-js article.
Leave a Reply