api-console-assets
Version:
This repo only exists to publish api console components to npm
1,259 lines (1,155 loc) • 43.5 kB
JavaScript
/* x509-1.1.20.js (c) 2012-2018 Kenji Urushima | kjur.github.io/jsrsasign/license
*/
/*
* x509.js - X509 class to read subject public key from certificate.
*
* Copyright (c) 2010-2018 Kenji Urushima (kenji.urushima@gmail.com)
*
* This software is licensed under the terms of the MIT License.
* https://kjur.github.io/jsrsasign/license
*
* The above copyright and license notice shall be
* included in all copies or substantial portions of the Software.
*/
/**
* @fileOverview
* @name x509-1.1.js
* @author Kenji Urushima kenji.urushima@gmail.com
* @version jsrsasign 8.0.10 x509 1.1.20 (2018-Apr-09)
* @since jsrsasign 1.x.x
* @license <a href="https://kjur.github.io/jsrsasign/license/">MIT License</a>
*/
/**
* hexadecimal X.509 certificate ASN.1 parser class.<br/>
* @class hexadecimal X.509 certificate ASN.1 parser class
* @property {String} hex hexacedimal string for X.509 certificate.
* @property {Number} version format version (1: X509v1, 3: X509v3, otherwise: unknown) since jsrsasign 7.1.4
* @author Kenji Urushima
* @version 1.0.1 (08 May 2012)
* @see <a href="https://kjur.github.io/jsrsasigns/">'jsrsasign'(RSA Sign JavaScript Library) home page https://kjur.github.io/jsrsasign/</a>
* @description
* X509 class provides following functionality:
* <ul>
* <li>parse X.509 certificate ASN.1 structure</li>
* <li>get basic fields, extensions, signature algorithms and signature values</li>
* <li>read PEM certificate</li>
* </ul>
*
* <ul>
* <li><b>TO GET FIELDS</b>
* <ul>
* <li>serial - {@link X509#getSerialNumberHex}</li>
* <li>signature algorithm field - {@link X509#getSignatureAlgorithmField}</li>
* <li>issuer - {@link X509#getIssuerHex}</li>
* <li>issuer - {@link X509#getIssuerString}</li>
* <li>notBefore - {@link X509#getNotBefore}</li>
* <li>notAfter - {@link X509#getNotAfter}</li>
* <li>subject - {@link X509#getSubjectHex}</li>
* <li>subject - {@link X509#getSubjectString}</li>
* <li>subjectPublicKeyInfo - {@link X509#getPublicKey}</li>
* <li>subjectPublicKeyInfo - {@link X509#getPublicKeyHex}</li>
* <li>subjectPublicKeyInfo - {@link X509#getPublicKeyIdx}</li>
* <li>subjectPublicKeyInfo - {@link X509.getPublicKeyFromCertPEM}</li>
* <li>subjectPublicKeyInfo - {@link X509.getPublicKeyFromCertHex}</li>
* <li>subjectPublicKeyInfo - {@link X509#getPublicKeyContentIdx}</li>
* <li>signature algorithm - {@link X509#getSignatureAlgorithmName}</li>
* <li>signature value - {@link X509#getSignatureValueHex}</li>
* </ul>
* </li>
* <li><b>X509 METHODS TO GET EXTENSIONS</b>
* <ul>
* <li>basicConstraints - {@link X509#getExtBasicConstraints}</li>
* <li>keyUsage - {@link X509#getExtKeyUsageBin}</li>
* <li>keyUsage - {@link X509#getExtKeyUsageString}</li>
* <li>subjectKeyIdentifier - {@link X509#getExtSubjectKeyIdentifier}</li>
* <li>authorityKeyIdentifier - {@link X509#getExtAuthorityKeyIdentifier}</li>
* <li>extKeyUsage - {@link X509#getExtExtKeyUsageName}</li>
* <li>subjectAltName(DEPRECATED) - {@link X509#getExtSubjectAltName}</li>
* <li>subjectAltName2 - {@link X509#getExtSubjectAltName2}</li>
* <li>cRLDistributionPoints - {@link X509#getExtCRLDistributionPointsURI}</li>
* <li>authorityInfoAccess - {@link X509#getExtAIAInfo}</li>
* <li>certificatePolicies - {@link X509#getExtCertificatePolicies}</li>
* </ul>
* </li>
* <li><b>UTILITIES</b>
* <ul>
* <li>reading PEM X.509 certificate - {@link X509#readCertPEM}</li>
* <li>reading hexadecimal string of X.509 certificate - {@link X509#readCertHex}</li>
* <li>get all certificate information - {@link X509#getInfo}</li>
* <li>get specified extension information - {@link X509#getExtInfo}</li>
* <li>verify signature value - {@link X509#verifySignature}</li>
* </ul>
* </li>
* </ul>
*/
function X509() {
var _ASN1HEX = ASN1HEX,
_getChildIdx = _ASN1HEX.getChildIdx,
_getV = _ASN1HEX.getV,
_getTLV = _ASN1HEX.getTLV,
_getVbyList = _ASN1HEX.getVbyList,
_getTLVbyList = _ASN1HEX.getTLVbyList,
_getIdxbyList = _ASN1HEX.getIdxbyList,
_getVidx = _ASN1HEX.getVidx,
_oidname = _ASN1HEX.oidname,
_X509 = X509,
_pemtohex = pemtohex;
this.hex = null;
this.version = 0; // version (1: X509v1, 3: X509v3, others: unspecified)
this.foffset = 0; // field index offset (-1: for X509v1, 0: for X509v3)
this.aExtInfo = null;
// ===== get basic fields from hex =====================================
/**
* get format version (X.509v1 or v3 certificate)<br/>
* @name getVersion
* @memberOf X509#
* @function
* @return {Number} 1 for X509v1, 3 for X509v3, otherwise 0
* @since jsrsasign 7.1.14 x509 1.1.13
* @description
* This method returns a format version of X.509 certificate.
* It returns 1 for X.509v1 certificate and 3 for v3 certificate.
* Otherwise returns 0.
* This method will be automatically called in
* {@link X509#readCertPEM}. After then, you can use
* {@link X509.version} parameter.
* @example
* var x = new X509();
* x.readCertPEM(sCertPEM);
* version = x.getVersion(); // 1 or 3
* sn = x.getSerialNumberHex(); // return string like "01ad..."
*/
this.getVersion = function() {
if (this.hex === null || this.version !== 0) return this.version;
// check if the first item of tbsCertificate "[0] { INTEGER 2 }"
if (_getTLVbyList(this.hex, 0, [0, 0]) !==
"a003020102") {
this.version = 1;
this.foffset = -1;
return 1;
}
this.version = 3;
return 3;
};
/**
* get hexadecimal string of serialNumber field of certificate.<br/>
* @name getSerialNumberHex
* @memberOf X509#
* @function
* @return {String} hexadecimal string of certificate serial number
* @example
* var x = new X509();
* x.readCertPEM(sCertPEM);
* var sn = x.getSerialNumberHex(); // return string like "01ad..."
*/
this.getSerialNumberHex = function() {
return _getVbyList(this.hex, 0, [0, 1 + this.foffset], "02");
};
/**
* get signature algorithm name in basic field
* @name getSignatureAlgorithmField
* @memberOf X509#
* @function
* @return {String} signature algorithm name (ex. SHA1withRSA, SHA256withECDSA)
* @since x509 1.1.8
* @description
* This method will get a name of signature algorithm field of certificate:
* @example
* var x = new X509();
* x.readCertPEM(sCertPEM);
* algName = x.getSignatureAlgorithmField();
*/
this.getSignatureAlgorithmField = function() {
return _oidname(_getVbyList(this.hex, 0, [0, 2 + this.foffset, 0], "06"));
};
/**
* get hexadecimal string of issuer field TLV of certificate.<br/>
* @name getIssuerHex
* @memberOf X509#
* @function
* @return {String} hexadecial string of issuer DN ASN.1
* @example
* var x = new X509();
* x.readCertPEM(sCertPEM);
* var issuer = x.getIssuerHex(); // return string like "3013..."
*/
this.getIssuerHex = function() {
return _getTLVbyList(this.hex, 0, [0, 3 + this.foffset], "30");
};
/**
* get string of issuer field of certificate.<br/>
* @name getIssuerString
* @memberOf X509#
* @function
* @return {String} issuer DN string
* @example
* var x = new X509();
* x.readCertPEM(sCertPEM);
* var issuer = x.getIssuerString(); // return string like "/C=US/O=TEST"
*/
this.getIssuerString = function() {
return _X509.hex2dn(this.getIssuerHex());
};
/**
* get hexadecimal string of subject field of certificate.<br/>
* @name getSubjectHex
* @memberOf X509#
* @function
* @return {String} hexadecial string of subject DN ASN.1
* @example
* var x = new X509();
* x.readCertPEM(sCertPEM);
* var subject = x.getSubjectHex(); // return string like "3013..."
*/
this.getSubjectHex = function() {
return _getTLVbyList(this.hex, 0, [0, 5 + this.foffset], "30");
};
/**
* get string of subject field of certificate.<br/>
* @name getSubjectString
* @memberOf X509#
* @function
* @return {String} subject DN string
* @example
* var x = new X509();
* x.readCertPEM(sCertPEM);
* var subject = x.getSubjectString(); // return string like "/C=US/O=TEST"
*/
this.getSubjectString = function() {
return _X509.hex2dn(this.getSubjectHex());
};
/**
* get notBefore field string of certificate.<br/>
* @name getNotBefore
* @memberOf X509#
* @function
* @return {String} not before time value (ex. "151231235959Z")
* @example
* var x = new X509();
* x.readCertPEM(sCertPEM);
* var notBefore = x.getNotBefore(); // return string like "151231235959Z"
*/
this.getNotBefore = function() {
var s = _getVbyList(this.hex, 0, [0, 4 + this.foffset, 0]);
s = s.replace(/(..)/g, "%$1");
s = decodeURIComponent(s);
return s;
};
/**
* get notAfter field string of certificate.<br/>
* @name getNotAfter
* @memberOf X509#
* @function
* @return {String} not after time value (ex. "151231235959Z")
* @example
* var x = new X509();
* x.readCertPEM(sCertPEM);
* var notAfter = x.getNotAfter(); // return string like "151231235959Z"
*/
this.getNotAfter = function() {
var s = _getVbyList(this.hex, 0, [0, 4 + this.foffset, 1]);
s = s.replace(/(..)/g, "%$1");
s = decodeURIComponent(s);
return s;
};
/**
* get a hexadecimal string of subjectPublicKeyInfo field.<br/>
* @name getPublicKeyHex
* @memberOf X509#
* @function
* @return {String} ASN.1 SEQUENCE hexadecimal string of subjectPublicKeyInfo field
* @since jsrsasign 7.1.4 x509 1.1.13
* @example
* x = new X509();
* x.readCertPEM(sCertPEM);
* hSPKI = x.getPublicKeyHex(); // return string like "30820122..."
*/
this.getPublicKeyHex = function() {
return _ASN1HEX.getTLVbyList(this.hex, 0, [0, 6 + this.foffset], "30");
};
/**
* get a string index of subjectPublicKeyInfo field for hexadecimal string certificate.<br/>
* @name getPublicKeyIdx
* @memberOf X509#
* @function
* @return {Number} string index of subjectPublicKeyInfo field for hexadecimal string certificate.
* @since jsrsasign 7.1.4 x509 1.1.13
* @example
* x = new X509();
* x.readCertPEM(sCertPEM);
* idx = x.getPublicKeyIdx(); // return string index in x.hex parameter
*/
this.getPublicKeyIdx = function() {
return _getIdxbyList(this.hex, 0, [0, 6 + this.foffset], "30");
};
/**
* get a string index of contents of subjectPublicKeyInfo BITSTRING value from hexadecimal certificate<br/>
* @name getPublicKeyContentIdx
* @memberOf X509#
* @function
* @return {Integer} string index of key contents
* @since jsrsasign 8.0.0 x509 1.2.0
* @example
* x = new X509();
* x.readCertPEM(sCertPEM);
* idx = x.getPublicKeyContentIdx(); // return string index in x.hex parameter
*/
// NOTE: Without BITSTRING encapsulation.
this.getPublicKeyContentIdx = function() {
var idx = this.getPublicKeyIdx();
return _getIdxbyList(this.hex, idx, [1, 0], "30");
};
/**
* get a RSAKey/ECDSA/DSA public key object of subjectPublicKeyInfo field.<br/>
* @name getPublicKey
* @memberOf X509#
* @function
* @return {Object} RSAKey/ECDSA/DSA public key object of subjectPublicKeyInfo field
* @since jsrsasign 7.1.4 x509 1.1.13
* @example
* x = new X509();
* x.readCertPEM(sCertPEM);
* pubkey= x.getPublicKey();
*/
this.getPublicKey = function() {
return KEYUTIL.getKey(this.getPublicKeyHex(), null, "pkcs8pub");
};
/**
* get signature algorithm name from hexadecimal certificate data
* @name getSignatureAlgorithmName
* @memberOf X509#
* @function
* @param {String} hCert hexadecimal string of X.509 certificate binary
* @return {String} signature algorithm name (ex. SHA1withRSA, SHA256withECDSA)
* @since jsrsasign 7.2.0 x509 1.1.14
* @description
* This method will get signature algorithm name of certificate:
* @example
* var x = new X509();
* x.readCertPEM(sCertPEM);
* x.getSignatureAlgorithmName() → "SHA256withRSA"
*/
this.getSignatureAlgorithmName = function() {
return _oidname(_getVbyList(this.hex, 0, [1, 0], "06"));
};
/**
* get signature value in hexadecimal string<br/>
* @name getSignatureValueHex
* @memberOf X509#
* @function
* @return {String} signature value hexadecimal string without BitString unused bits
* @since jsrsasign 7.2.0 x509 1.1.14
* @description
* This method will get signature value of certificate:
* @example
* var x = new X509();
* x.readCertPEM(sCertPEM);
* x.getSignatureValueHex() &rarr "8a4c47913..."
*/
this.getSignatureValueHex = function() {
return _getVbyList(this.hex, 0, [2], "03", true);
};
/**
* verifies signature value by public key<br/>
* @name verifySignature
* @memberOf X509#
* @function
* @param {Object} pubKey public key object
* @return {Boolean} true if signature value is valid otherwise false
* @since jsrsasign 7.2.0 x509 1.1.14
* @description
* This method verifies signature value of hexadecimal string of
* X.509 certificate by specified public key object.
* @example
* pubKey = KEYUTIL.getKey(pemPublicKey); // or certificate
* x = new X509();
* x.readCertPEM(pemCert);
* x.verifySignature(pubKey) → true, false or raising exception
*/
this.verifySignature = function(pubKey) {
var algName = this.getSignatureAlgorithmName();
var hSigVal = this.getSignatureValueHex();
var hTbsCert = _getTLVbyList(this.hex, 0, [0], "30");
var sig = new KJUR.crypto.Signature({alg: algName});
sig.init(pubKey);
sig.updateHex(hTbsCert);
return sig.verify(hSigVal);
};
// ===== parse extension ======================================
/**
* set array of X.509v3 extesion information such as extension OID, criticality and value index.<br/>
* @name parseExt
* @memberOf X509#
* @function
* @since jsrsasign 7.2.0 x509 1.1.14
* @description
* This method will set an array of X.509v3 extension information having
* following parameters:
* <ul>
* <li>oid - extension OID (ex. 2.5.29.19)</li>
* <li>critical - true or false</li>
* <li>vidx - string index for extension value</li>
* @example
* x = new X509();
* x.readCertPEM(sCertPEM); // parseExt() will also be called internally.
*
* x.aExtInfo →
* [ { oid: "2.5.29,19", critical: true, vidx: 2504 }, ... ]
*/
this.parseExt = function() {
if (this.version !== 3) return -1;
var iExtSeq = _getIdxbyList(this.hex, 0, [0, 7, 0], "30");
var aExtIdx = _getChildIdx(this.hex, iExtSeq);
this.aExtInfo = new Array();
for (var i = 0; i < aExtIdx.length; i++) {
var item = {};
item.critical = false;
var a = _getChildIdx(this.hex, aExtIdx[i]);
var offset = 0;
if (a.length === 3) {
item.critical = true;
offset = 1;
}
item.oid = _ASN1HEX.hextooidstr(_getVbyList(this.hex, aExtIdx[i], [0], "06"));
var octidx = _getIdxbyList(this.hex, aExtIdx[i], [1 + offset]);
item.vidx = _getVidx(this.hex, octidx);
this.aExtInfo.push(item);
}
};
/**
* get a X.509v3 extesion information such as extension OID, criticality and value index for specified oid or name.<br/>
* @name getExtInfo
* @memberOf X509#
* @function
* @param {String} oidOrName X.509 extension oid or name (ex. keyUsage or 2.5.29.19)
* @return X.509 extension information such as extension OID or value indx (see {@link X509#parseExt})
* @since jsrsasign 7.2.0 x509 1.1.14
* @description
* This method will get an X.509v3 extension information JSON object
* having extension OID, criticality and value idx for specified
* extension OID or name.
* If there is no such extension, this returns undefined.
* @example
* x = new X509();
* x.readCertPEM(sCertPEM); // parseExt() will also be called internally.
*
* x.getExtInfo("keyUsage") → { oid: "2.5.29.15", critical: true, vidx: 1714 }
* x.getExtInfo("unknownExt") → undefined
*/
this.getExtInfo = function(oidOrName) {
var a = this.aExtInfo;
var oid = oidOrName;
if (! oidOrName.match(/^[0-9.]+$/)) {
oid = KJUR.asn1.x509.OID.name2oid(oidOrName);
}
if (oid === '') return undefined;
for (var i = 0; i < a.length; i++) {
if (a[i].oid === oid) return a[i];
}
return undefined;
};
/**
* get BasicConstraints extension value as object in the certificate
* @name getExtBasicConstraints
* @memberOf X509#
* @function
* @return {Object} associative array which may have "cA" and "pathLen" parameters
* @since jsrsasign 7.2.0 x509 1.1.14
* @description
* This method will get basic constraints extension value as object with following paramters.
* <ul>
* <li>cA - CA flag whether CA or not</li>
* <li>pathLen - maximum intermediate certificate length</li>
* </ul>
* There are use cases for return values:
* <ul>
* <li>{cA:true, pathLen:3} - cA flag is true and pathLen is 3</li>
* <li>{cA:true} - cA flag is true and no pathLen</li>
* <li>{} - basic constraints has no value in case of end entity certificate</li>
* <li>undefined - there is no basic constraints extension</li>
* </ul>
* @example
* x = new X509();
* x.readCertPEM(sCertPEM); // parseExt() will also be called internally.
* x.getExtBasicConstraints() → { cA: true, pathLen: 3 };
*/
this.getExtBasicConstraints = function() {
var info = this.getExtInfo("basicConstraints");
if (info === undefined) return info;
var hBC = _getV(this.hex, info.vidx);
if (hBC === '') return {};
if (hBC === '0101ff') return { cA: true };
if (hBC.substr(0, 8) === '0101ff02') {
var pathLexHex = _getV(hBC, 6);
var pathLen = parseInt(pathLexHex, 16);
return { cA: true, pathLen: pathLen };
}
throw "basicConstraints parse error";
};
/**
* get KeyUsage extension value as binary string in the certificate<br/>
* @name getExtKeyUsageBin
* @memberOf X509#
* @function
* @return {String} binary string of key usage bits (ex. '101')
* @since jsrsasign 7.2.0 x509 1.1.14
* @description
* This method will get key usage extension value
* as binary string such like '101'.
* Key usage bits definition is in the RFC 5280.
* If there is no key usage extension in the certificate,
* it returns empty string (i.e. '').
* @example
* x = new X509();
* x.readCertPEM(sCertPEM); // parseExt() will also be called internally.
* x.getExtKeyUsageBin() → '101'
* // 1 - digitalSignature
* // 0 - nonRepudiation
* // 1 - keyEncipherment
*/
this.getExtKeyUsageBin = function() {
var info = this.getExtInfo("keyUsage");
if (info === undefined) return '';
var hKeyUsage = _getV(this.hex, info.vidx);
if (hKeyUsage.length % 2 != 0 || hKeyUsage.length <= 2)
throw "malformed key usage value";
var unusedBits = parseInt(hKeyUsage.substr(0, 2));
var bKeyUsage = parseInt(hKeyUsage.substr(2), 16).toString(2);
return bKeyUsage.substr(0, bKeyUsage.length - unusedBits);
};
/**
* get KeyUsage extension value as names in the certificate<br/>
* @name getExtKeyUsageString
* @memberOf X509#
* @function
* @return {String} comma separated string of key usage
* @since jsrsasign 7.2.0 x509 1.1.14
* @description
* This method will get key usage extension value
* as comma separated string of usage names.
* If there is no key usage extension in the certificate,
* it returns empty string (i.e. '').
* @example
* x = new X509();
* x.readCertPEM(sCertPEM); // parseExt() will also be called internally.
* x.getExtKeyUsageString() → "digitalSignature,keyEncipherment"
*/
this.getExtKeyUsageString = function() {
var bKeyUsage = this.getExtKeyUsageBin();
var a = new Array();
for (var i = 0; i < bKeyUsage.length; i++) {
if (bKeyUsage.substr(i, 1) == "1") a.push(X509.KEYUSAGE_NAME[i]);
}
return a.join(",");
};
/**
* get subjectKeyIdentifier value as hexadecimal string in the certificate<br/>
* @name getExtSubjectKeyIdentifier
* @memberOf X509#
* @function
* @return {String} hexadecimal string of subject key identifier or null
* @since jsrsasign 7.2.0 x509 1.1.14
* @description
* This method will get subject key identifier extension value
* as hexadecimal string.
* If there is this in the certificate, it returns undefined;
* @example
* x = new X509();
* x.readCertPEM(sCertPEM); // parseExt() will also be called internally.
* x.getExtSubjectKeyIdentifier() → "1b3347ab...";
*/
this.getExtSubjectKeyIdentifier = function() {
var info = this.getExtInfo("subjectKeyIdentifier");
if (info === undefined) return info;
return _getV(this.hex, info.vidx);
};
/**
* get authorityKeyIdentifier value as JSON object in the certificate<br/>
* @name getExtAuthorityKeyIdentifier
* @memberOf X509#
* @function
* @return {Object} JSON object of authority key identifier or null
* @since jsrsasign 7.2.0 x509 1.1.14
* @description
* This method will get authority key identifier extension value
* as JSON object.
* If there is this in the certificate, it returns undefined;
* <br>
* NOTE: Currently this method only supports keyIdentifier so that
* authorityCertIssuer and authorityCertSerialNumber will not
* be return in the JSON object.
* @example
* x = new X509();
* x.readCertPEM(sCertPEM); // parseExt() will also be called internally.
* x.getExtAuthorityKeyIdentifier() → { kid: "1234abcd..." }
*/
this.getExtAuthorityKeyIdentifier = function() {
var info = this.getExtInfo("authorityKeyIdentifier");
if (info === undefined) return info;
var result = {};
var hAKID = _getTLV(this.hex, info.vidx);
var a = _getChildIdx(hAKID, 0);
for (var i = 0; i < a.length; i++) {
if (hAKID.substr(a[i], 2) === "80")
result.kid = _getV(hAKID, a[i]);
}
return result;
};
/**
* get extKeyUsage value as array of name string in the certificate<br/>
* @name getExtExtKeyUsageName
* @memberOf X509#
* @function
* @return {Object} array of extended key usage ID name or oid
* @since jsrsasign 7.2.0 x509 1.1.14
* @description
* This method will get extended key usage extension value
* as array of name or OID string.
* If there is this in the certificate, it returns undefined;
* <br>
* NOTE: Supported extended key usage ID names are defined in
* name2oidList parameter in asn1x509.js file.
* @example
* x = new X509();
* x.readCertPEM(sCertPEM); // parseExt() will also be called internally.
* x.getExtExtKeyUsageName() → ["serverAuth", "clientAuth", "0.1.2.3.4.5"]
*/
this.getExtExtKeyUsageName = function() {
var info = this.getExtInfo("extKeyUsage");
if (info === undefined) return info;
var result = new Array();
var h = _getTLV(this.hex, info.vidx);
if (h === '') return result;
var a = _getChildIdx(h, 0);
for (var i = 0; i < a.length; i++) {
result.push(_oidname(_getV(h, a[i])));
}
return result;
};
/**
* (DEPRECATED) get subjectAltName value as array of string in the certificate
* @name getExtSubjectAltName
* @memberOf X509#
* @function
* @return {Object} array of alt names
* @since jsrsasign 7.2.0 x509 1.1.14
* @deprecated since jsrsasign 8.0.1 x509 1.1.17. Please move to {@link X509#getExtSubjectAltName2}
* @description
* This method will get subject alt name extension value
* as array of name.
* If there is this in the certificate, it returns undefined;
* <br>
* NOTE: Currently this method supports only dNSName so that
* other name type such like iPAddress or generalName will not be returned.
* @example
* x = new X509();
* x.readCertPEM(sCertPEM); // parseExt() will also be called internally.
* x.getExtSubjectAltName() → ["example.com", "example.org"]
*/
this.getExtSubjectAltName = function() {
var a = this.getExtSubjectAltName2();
var result = new Array();
for (var i = 0; i < a.length; i++) {
if (a[i][0] === "DNS") result.push(a[i][1]);
}
return result;
};
/**
* get subjectAltName value as array of string in the certificate
* @name getExtSubjectAltName2
* @memberOf X509#
* @function
* @return {Object} array of alt name array
* @since jsrsasign 8.0.1 x509 1.1.17
* @description
* This method will get subject alt name extension value
* as array of type and name.
* If there is this in the certificate, it returns undefined;
* Type of GeneralName will be shown as following:
* <ul>
* <li>"MAIL" - [1]rfc822Name</li>
* <li>"DNS" - [2]dNSName</li>
* <li>"DN" - [4]directoryName</li>
* <li>"URI" - [6]uniformResourceIdentifier</li>
* <li>"IP" - [7]iPAddress</li>
* </ul>
* @example
* x = new X509();
* x.readCertPEM(sCertPEM); // parseExt() will also be called internally.
* x.getExtSubjectAltName2() →
* [["DNS", "example.com"],
* ["DNS", "example.org"],
* ["MAIL", "foo@example.com"],
* ["IP", "192.168.1.1"],
* ["IP", "2001:db8::2:1"],
* ["DN", "/C=US/O=TEST1"]]
*/
this.getExtSubjectAltName2 = function() {
var gnValueHex, gnValueStr, gnTag;
var info = this.getExtInfo("subjectAltName");
if (info === undefined) return info;
var result = new Array();
var h = _getTLV(this.hex, info.vidx);
var a = _getChildIdx(h, 0);
for (var i = 0; i < a.length; i++) {
gnTag = h.substr(a[i], 2);
gnValueHex = _getV(h, a[i]);
if (gnTag === "81") { // rfc822Name [1]
gnValueStr = hextoutf8(gnValueHex);
result.push(["MAIL", gnValueStr]);
}
if (gnTag === "82") { // dNSName [2]
gnValueStr = hextoutf8(gnValueHex);
result.push(["DNS", gnValueStr]);
}
if (gnTag === "84") { // directoryName [4]
gnValueStr = X509.hex2dn(gnValueHex, 0);
result.push(["DN", gnValueStr]);
}
if (gnTag === "86") { // uniformResourceIdentifier [6]
gnValueStr = hextoutf8(gnValueHex);
result.push(["URI", gnValueStr]);
}
if (gnTag === "87") { // iPAddress [7]
gnValueStr = hextoip(gnValueHex);
result.push(["IP", gnValueStr]);
}
}
return result;
};
/**
* get array of string for fullName URIs in cRLDistributionPoints(CDP) in the certificate
* @name getExtCRLDistributionPointsURI
* @memberOf X509#
* @function
* @return {Object} array of fullName URIs of CDP of the certificate
* @since jsrsasign 7.2.0 x509 1.1.14
* @description
* This method will get all fullName URIs of cRLDistributionPoints extension
* in the certificate as array of URI string.
* If there is this in the certificate, it returns undefined;
* <br>
* NOTE: Currently this method supports only fullName URI so that
* other parameters will not be returned.
* @example
* x = new X509();
* x.readCertPEM(sCertPEM); // parseExt() will also be called internally.
* x.getExtCRLDistributionPointsURI() →
* ["http://example.com/aaa.crl", "http://example.org/aaa.crl"]
*/
this.getExtCRLDistributionPointsURI = function() {
var info = this.getExtInfo("cRLDistributionPoints");
if (info === undefined) return info;
var result = new Array();
var a = _getChildIdx(this.hex, info.vidx);
for (var i = 0; i < a.length; i++) {
try {
var hURI = _getVbyList(this.hex, a[i], [0, 0, 0], "86");
var uri = hextoutf8(hURI);
result.push(uri);
} catch(ex) {};
}
return result;
};
/**
* get AuthorityInfoAccess extension value in the certificate as associative array
* @name getExtAIAInfo
* @memberOf X509#
* @function
* @return {Object} associative array of AIA extension properties
* @since jsrsasign 7.2.0 x509 1.1.14
* @description
* This method will get authority info access value
* as associate array which has following properties:
* <ul>
* <li>ocsp - array of string for OCSP responder URL</li>
* <li>caissuer - array of string for caIssuer value (i.e. CA certificates URL)</li>
* </ul>
* If there is this in the certificate, it returns undefined;
* @example
* x = new X509();
* x.readCertPEM(sCertPEM); // parseExt() will also be called internally.
* x.getExtAIAInfo(hCert) →
* { ocsp: ["http://ocsp.foo.com"],
* caissuer: ["http://rep.foo.com/aaa.p8m"] }
*/
this.getExtAIAInfo = function() {
var info = this.getExtInfo("authorityInfoAccess");
if (info === undefined) return info;
var result = { ocsp: [], caissuer: [] };
var a = _getChildIdx(this.hex, info.vidx);
for (var i = 0; i < a.length; i++) {
var hOID = _getVbyList(this.hex, a[i], [0], "06");
var hName = _getVbyList(this.hex, a[i], [1], "86");
if (hOID === "2b06010505073001") {
result.ocsp.push(hextoutf8(hName));
}
if (hOID === "2b06010505073002") {
result.caissuer.push(hextoutf8(hName));
}
}
return result;
};
/**
* get CertificatePolicies extension value in the certificate as array
* @name getExtCertificatePolicies
* @memberOf X509#
* @function
* @return {Object} array of PolicyInformation JSON object
* @since jsrsasign 7.2.0 x509 1.1.14
* @description
* This method will get certificate policies value
* as an array of JSON object which has following properties:
* <ul>
* <li>id - </li>
* <li>cps - URI of certification practice statement</li>
* <li>unotice - string of UserNotice explicitText</li>
* </ul>
* If there is this extension in the certificate,
* it returns undefined;
* @example
* x = new X509();
* x.readCertPEM(sCertPEM); // parseExt() will also be called internally.
* x.getExtCertificatePolicies →
* [{ id: 1.2.3.4,
* cps: "http://example.com/cps",
* unotice: "explicit text" }]
*/
this.getExtCertificatePolicies = function() {
var info = this.getExtInfo("certificatePolicies");
if (info === undefined) return info;
var hExt = _getTLV(this.hex, info.vidx);
var result = [];
var a = _getChildIdx(hExt, 0);
for (var i = 0; i < a.length; i++) {
var policyInfo = {};
var a1 = _getChildIdx(hExt, a[i]);
policyInfo.id = _oidname(_getV(hExt, a1[0]));
if (a1.length === 2) {
var a2 = _getChildIdx(hExt, a1[1]);
for (var j = 0; j < a2.length; j++) {
var hQualifierId = _getVbyList(hExt, a2[j], [0], "06");
if (hQualifierId === "2b06010505070201") { // cps
policyInfo.cps = hextoutf8(_getVbyList(hExt, a2[j], [1]));
} else if (hQualifierId === "2b06010505070202") { // unotice
policyInfo.unotice =
hextoutf8(_getVbyList(hExt, a2[j], [1, 0]));
}
}
}
result.push(policyInfo);
}
return result;
}
// ===== read certificate =====================================
/**
* read PEM formatted X.509 certificate from string.<br/>
* @name readCertPEM
* @memberOf X509#
* @function
* @param {String} sCertPEM string for PEM formatted X.509 certificate
* @example
* x = new X509();
* x.readCertPEM(sCertPEM); // read certificate
*/
this.readCertPEM = function(sCertPEM) {
this.readCertHex(_pemtohex(sCertPEM));
};
/**
* read a hexadecimal string of X.509 certificate<br/>
* @name readCertHex
* @memberOf X509#
* @function
* @param {String} sCertHex hexadecimal string of X.509 certificate
* @since jsrsasign 7.1.4 x509 1.1.13
* @description
* NOTE: {@link X509#parseExt} will called internally since jsrsasign 7.2.0.
* @example
* x = new X509();
* x.readCertHex("3082..."); // read certificate
*/
this.readCertHex = function(sCertHex) {
this.hex = sCertHex;
this.getVersion(); // set version parameter
try {
_getIdxbyList(this.hex, 0, [0, 7], "a3"); // has [3] v3ext
this.parseExt();
} catch(ex) {};
};
/**
* get certificate information as string.<br/>
* @name getInfo
* @memberOf X509#
* @function
* @return {String} certificate information string
* @since jsrsasign 5.0.10 x509 1.1.8
* @example
* x = new X509();
* x.readCertPEM(certPEM);
* console.log(x.getInfo());
* // this shows as following
* Basic Fields
* serial number: 02ac5c266a0b409b8f0b79f2ae462577
* signature algorithm: SHA1withRSA
* issuer: /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA
* notBefore: 061110000000Z
* notAfter: 311110000000Z
* subject: /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA
* subject public key info:
* key algorithm: RSA
* n=c6cce573e6fbd4bb...
* e=10001
* X509v3 Extensions:
* keyUsage CRITICAL:
* digitalSignature,keyCertSign,cRLSign
* basicConstraints CRITICAL:
* cA=true
* subjectKeyIdentifier :
* b13ec36903f8bf4701d498261a0802ef63642bc3
* authorityKeyIdentifier :
* kid=b13ec36903f8bf4701d498261a0802ef63642bc3
* signature algorithm: SHA1withRSA
* signature: 1c1a0697dcd79c9f...
*/
this.getInfo = function() {
var _X509 = X509;
var s, pubkey, aExt;
s = "Basic Fields\n";
s += " serial number: " + this.getSerialNumberHex() + "\n";
s += " signature algorithm: " + this.getSignatureAlgorithmField() + "\n";
s += " issuer: " + this.getIssuerString() + "\n";
s += " notBefore: " + this.getNotBefore() + "\n";
s += " notAfter: " + this.getNotAfter() + "\n";
s += " subject: " + this.getSubjectString() + "\n";
s += " subject public key info: " + "\n";
// subject public key info
pubkey = this.getPublicKey();
s += " key algorithm: " + pubkey.type + "\n";
if (pubkey.type === "RSA") {
s += " n=" + hextoposhex(pubkey.n.toString(16)).substr(0, 16) + "...\n";
s += " e=" + hextoposhex(pubkey.e.toString(16)) + "\n";
}
// X.509v3 Extensions
aExt = this.aExtInfo;
if (aExt !== undefined && aExt !== null) {
s += "X509v3 Extensions:\n";
for (var i = 0; i < aExt.length; i++) {
var info = aExt[i];
// show extension name and critical flag
var extName = KJUR.asn1.x509.OID.oid2name(info["oid"]);
if (extName === '') extName = info["oid"];
var critical = '';
if (info["critical"] === true) critical = "CRITICAL";
s += " " + extName + " " + critical + ":\n";
// show extension value if supported
if (extName === "basicConstraints") {
var bc = this.getExtBasicConstraints();
if (bc.cA === undefined) {
s += " {}\n";
} else {
s += " cA=true";
if (bc.pathLen !== undefined)
s += ", pathLen=" + bc.pathLen;
s += "\n";
}
} else if (extName === "keyUsage") {
s += " " + this.getExtKeyUsageString() + "\n";
} else if (extName === "subjectKeyIdentifier") {
s += " " + this.getExtSubjectKeyIdentifier() + "\n";
} else if (extName === "authorityKeyIdentifier") {
var akid = this.getExtAuthorityKeyIdentifier();
if (akid.kid !== undefined)
s += " kid=" + akid.kid + "\n";
} else if (extName === "extKeyUsage") {
var eku = this.getExtExtKeyUsageName();
s += " " + eku.join(", ") + "\n";
} else if (extName === "subjectAltName") {
var san = this.getExtSubjectAltName2();
s += " " + san + "\n";
} else if (extName === "cRLDistributionPoints") {
var cdp = this.getExtCRLDistributionPointsURI();
s += " " + cdp + "\n";
} else if (extName === "authorityInfoAccess") {
var aia = this.getExtAIAInfo();
if (aia.ocsp !== undefined)
s += " ocsp: " + aia.ocsp.join(",") + "\n";
if (aia.caissuer !== undefined)
s += " caissuer: " + aia.caissuer.join(",") + "\n";
} else if (extName === "certificatePolicies") {
var aCP = this.getExtCertificatePolicies();
for (var j = 0; j < aCP.length; j++) {
if (aCP[j].id !== undefined)
s += " policy oid: " + aCP[j].id + "\n";
if (aCP[j].cps !== undefined)
s += " cps: " + aCP[j].cps + "\n";
}
}
}
}
s += "signature algorithm: " + this.getSignatureAlgorithmName() + "\n";
s += "signature: " + this.getSignatureValueHex().substr(0, 16) + "...\n";
return s;
};
};
/**
* get distinguished name string in OpenSSL online format from hexadecimal string of ASN.1 DER X.500 name<br/>
* @name hex2dn
* @memberOf X509
* @function
* @param {String} hex hexadecimal string of ASN.1 DER distinguished name
* @param {Integer} idx index of hexadecimal string (DEFAULT=0)
* @return {String} OpenSSL online format distinguished name
* @description
* This static method converts from a hexadecimal string of
* distinguished name (DN)
* specified by 'hex' and 'idx' to OpenSSL oneline string representation (ex. /C=US/O=a).
* @example
* X509.hex2dn("3031310b3...") → /C=US/O=a/CN=b2+OU=b1
*/
X509.hex2dn = function(hex, idx) {
if (idx === undefined) idx = 0;
if (hex.substr(idx, 2) !== "30") throw "malformed DN";
var a = new Array();
var aIdx = ASN1HEX.getChildIdx(hex, idx);
for (var i = 0; i < aIdx.length; i++) {
a.push(X509.hex2rdn(hex, aIdx[i]));
}
a = a.map(function(s) { return s.replace("/", "\\/"); });
return "/" + a.join("/");
};
/**
* get relative distinguished name string in OpenSSL online format from hexadecimal string of ASN.1 DER RDN<br/>
* @name hex2rdn
* @memberOf X509
* @function
* @param {String} hex hexadecimal string of ASN.1 DER concludes relative distinguished name
* @param {Integer} idx index of hexadecimal string (DEFAULT=0)
* @return {String} OpenSSL online format relative distinguished name
* @description
* This static method converts from a hexadecimal string of
* relative distinguished name (RDN)
* specified by 'hex' and 'idx' to LDAP string representation (ex. O=test+CN=test).<br/>
* NOTE: Multi-valued RDN is supported since jsnrsasign 6.2.2 x509 1.1.10.
* @example
* X509.hex2rdn("310a3008060355040a0c0161") → O=a
* X509.hex2rdn("31143008060355040a0c01613008060355040a0c0162") → O=a+O=b
*/
X509.hex2rdn = function(hex, idx) {
if (idx === undefined) idx = 0;
if (hex.substr(idx, 2) !== "31") throw "malformed RDN";
var a = new Array();
var aIdx = ASN1HEX.getChildIdx(hex, idx);
for (var i = 0; i < aIdx.length; i++) {
a.push(X509.hex2attrTypeValue(hex, aIdx[i]));
}
a = a.map(function(s) { return s.replace("+", "\\+"); });
return a.join("+");
};
/**
* get string from hexadecimal string of ASN.1 DER AttributeTypeAndValue<br/>
* @name hex2attrTypeValue
* @memberOf X509
* @function
* @param {String} hex hexadecimal string of ASN.1 DER concludes AttributeTypeAndValue
* @param {Integer} idx index of hexadecimal string (DEFAULT=0)
* @return {String} string representation of AttributeTypeAndValue (ex. C=US)
* @description
* This static method converts from a hexadecimal string of AttributeTypeAndValue
* specified by 'hex' and 'idx' to LDAP string representation (ex. C=US).
* @example
* X509.hex2attrTypeValue("3008060355040a0c0161") → O=a
* X509.hex2attrTypeValue("300806035504060c0161") → C=a
* X509.hex2attrTypeValue("...3008060355040a0c0161...", 128) → O=a
*/
X509.hex2attrTypeValue = function(hex, idx) {
var _ASN1HEX = ASN1HEX;
var _getV = _ASN1HEX.getV;
if (idx === undefined) idx = 0;
if (hex.substr(idx, 2) !== "30") throw "malformed attribute type and value";
var aIdx = _ASN1HEX.getChildIdx(hex, idx);
if (aIdx.length !== 2 || hex.substr(aIdx[0], 2) !== "06")
"malformed attribute type and value";
var oidHex = _getV(hex, aIdx[0]);
var oidInt = KJUR.asn1.ASN1Util.oidHexToInt(oidHex);
var atype = KJUR.asn1.x509.OID.oid2atype(oidInt);
var hV = _getV(hex, aIdx[1]);
var rawV = hextorstr(hV);
return atype + "=" + rawV;
};
/**
* get RSA/DSA/ECDSA public key object from X.509 certificate hexadecimal string<br/>
* @name getPublicKeyFromCertHex
* @memberOf X509
* @function
* @param {String} h hexadecimal string of X.509 certificate for RSA/ECDSA/DSA public key
* @return returns RSAKey/KJUR.crypto.{ECDSA,DSA} object of public key
* @since jsrasign 7.1.0 x509 1.1.11
*/
X509.getPublicKeyFromCertHex = function(h) {
var x = new X509();
x.readCertHex(h);
return x.getPublicKey();
};
/**
* get RSA/DSA/ECDSA public key object from PEM certificate string
* @name getPublicKeyFromCertPEM
* @memberOf X509
* @function
* @param {String} sCertPEM PEM formatted RSA/ECDSA/DSA X.509 certificate
* @return returns RSAKey/KJUR.crypto.{ECDSA,DSA} object of public key
* @since x509 1.1.1
* @description
* NOTE: DSA is also supported since x509 1.1.2.
*/
X509.getPublicKeyFromCertPEM = function(sCertPEM) {
var x = new X509();
x.readCertPEM(sCertPEM);
return x.getPublicKey();
};
/**
* get public key information from PEM certificate
* @name getPublicKeyInfoPropOfCertPEM
* @memberOf X509
* @function
* @param {String} sCertPEM string of PEM formatted certificate
* @return {Hash} hash of information for public key
* @since x509 1.1.1
* @description
* Resulted associative array has following properties:<br/>
* <ul>
* <li>algoid - hexadecimal string of OID of asymmetric key algorithm</li>
* <li>algparam - hexadecimal string of OID of ECC curve name or null</li>
* <li>keyhex - hexadecimal string of key in the certificate</li>
* </ul>
* NOTE: X509v1 certificate is also supported since x509.js 1.1.9.
*/
X509.getPublicKeyInfoPropOfCertPEM = function(sCertPEM) {
var _ASN1HEX = ASN1HEX;
var _getVbyList = _ASN1HEX.getVbyList;
var result = {};
var x, hSPKI, pubkey;
result.algparam = null;
x = new X509();
x.readCertPEM(sCertPEM);
hSPKI = x.getPublicKeyHex();
result.keyhex = _getVbyList(hSPKI, 0, [1], "03").substr(2);
result.algoid = _getVbyList(hSPKI, 0, [0, 0], "06");
if (result.algoid === "2a8648ce3d0201") { // ecPublicKey
result.algparam = _getVbyList(hSPKI, 0, [0, 1], "06");
};
return result;
};
/* ======================================================================
* Specific V3 Extensions
* ====================================================================== */
X509.KEYUSAGE_NAME = [
"digitalSignature",
"nonRepudiation",
"keyEncipherment",
"dataEncipherment",
"keyAgreement",
"keyCertSign",
"cRLSign",
"encipherOnly",
"decipherOnly"
];