/*! x509-1.1.3.js (c) 2012-2014 Kenji Urushima | kjur.github.com/jsrsasign/license
*/
/*
* x509.js - X509 class to read subject public key from certificate.
*
* Copyright (c) 2010-2014 Kenji Urushima (kenji.urushima@gmail.com)
*
* This software is licensed under the terms of the MIT License.
* http://kjur.github.com/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 x509 1.1.3 (2014-May-17)
* @since jsrsasign 1.x.x
* @license MIT License
*/
/*
* Depends:
* base64.js
* rsa.js
* asn1hex.js
*/
/**
* X.509 certificate class.
* @class X.509 certificate class
* @property {RSAKey} subjectPublicKeyRSA Tom Wu's RSAKey object
* @property {String} subjectPublicKeyRSA_hN hexadecimal string for modulus of RSA public key
* @property {String} subjectPublicKeyRSA_hE hexadecimal string for public exponent of RSA public key
* @property {String} hex hexacedimal string for X.509 certificate.
* @author Kenji Urushima
* @version 1.0.1 (08 May 2012)
* @see 'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/
*/
function X509() {
this.subjectPublicKeyRSA = null;
this.subjectPublicKeyRSA_hN = null;
this.subjectPublicKeyRSA_hE = null;
this.hex = null;
// ===== get basic fields from hex =====================================
/**
* get hexadecimal string of serialNumber field of certificate.
* @name getSerialNumberHex
* @memberOf X509#
* @function
*/
this.getSerialNumberHex = function() {
return ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 1]);
};
/**
* get hexadecimal string of issuer field TLV of certificate.
* @name getIssuerHex
* @memberOf X509#
* @function
*/
this.getIssuerHex = function() {
return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]);
};
/**
* get string of issuer field of certificate.
* @name getIssuerString
* @memberOf X509#
* @function
*/
this.getIssuerString = function() {
return X509.hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]));
};
/**
* get hexadecimal string of subject field of certificate.
* @name getSubjectHex
* @memberOf X509#
* @function
*/
this.getSubjectHex = function() {
return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]);
};
/**
* get string of subject field of certificate.
* @name getSubjectString
* @memberOf X509#
* @function
*/
this.getSubjectString = function() {
return X509.hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]));
};
/**
* get notBefore field string of certificate.
* @name getNotBefore
* @memberOf X509#
* @function
*/
this.getNotBefore = function() {
var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 0]);
s = s.replace(/(..)/g, "%$1");
s = decodeURIComponent(s);
return s;
};
/**
* get notAfter field string of certificate.
* @name getNotAfter
* @memberOf X509#
* @function
*/
this.getNotAfter = function() {
var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 1]);
s = s.replace(/(..)/g, "%$1");
s = decodeURIComponent(s);
return s;
};
// ===== read certificate public key ==========================
// ===== read certificate =====================================
/**
* read PEM formatted X.509 certificate from string.
* @name readCertPEM
* @memberOf X509#
* @function
* @param {String} sCertPEM string for PEM formatted X.509 certificate
*/
this.readCertPEM = function(sCertPEM) {
var hCert = X509.pemToHex(sCertPEM);
var a = X509.getPublicKeyHexArrayFromCertHex(hCert);
var rsa = new RSAKey();
rsa.setPublic(a[0], a[1]);
this.subjectPublicKeyRSA = rsa;
this.subjectPublicKeyRSA_hN = a[0];
this.subjectPublicKeyRSA_hE = a[1];
this.hex = hCert;
};
this.readCertPEMWithoutRSAInit = function(sCertPEM) {
var hCert = X509.pemToHex(sCertPEM);
var a = X509.getPublicKeyHexArrayFromCertHex(hCert);
this.subjectPublicKeyRSA.setPublic(a[0], a[1]);
this.subjectPublicKeyRSA_hN = a[0];
this.subjectPublicKeyRSA_hE = a[1];
this.hex = hCert;
};
};
X509.pemToBase64 = function(sCertPEM) {
var s = sCertPEM;
s = s.replace("-----BEGIN CERTIFICATE-----", "");
s = s.replace("-----END CERTIFICATE-----", "");
s = s.replace(/[ \n]+/g, "");
return s;
};
X509.pemToHex = function(sCertPEM) {
var b64Cert = X509.pemToBase64(sCertPEM);
var hCert = b64tohex(b64Cert);
return hCert;
};
// NOTE: Without BITSTRING encapsulation.
X509.getSubjectPublicKeyPosFromCertHex = function(hCert) {
var pInfo = X509.getSubjectPublicKeyInfoPosFromCertHex(hCert);
if (pInfo == -1) return -1;
var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pInfo);
if (a.length != 2) return -1;
var pBitString = a[1];
if (hCert.substring(pBitString, pBitString + 2) != '03') return -1;
var pBitStringV = ASN1HEX.getStartPosOfV_AtObj(hCert, pBitString);
if (hCert.substring(pBitStringV, pBitStringV + 2) != '00') return -1;
return pBitStringV + 2;
};
// NOTE: privateKeyUsagePeriod field of X509v2 not supported.
// NOTE: v1 and v3 supported
X509.getSubjectPublicKeyInfoPosFromCertHex = function(hCert) {
var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pTbsCert);
if (a.length < 1) return -1;
if (hCert.substring(a[0], a[0] + 10) == "a003020102") { // v3
if (a.length < 6) return -1;
return a[6];
} else {
if (a.length < 5) return -1;
return a[5];
}
};
X509.getPublicKeyHexArrayFromCertHex = function(hCert) {
var p = X509.getSubjectPublicKeyPosFromCertHex(hCert);
var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p);
if (a.length != 2) return [];
var hN = ASN1HEX.getHexOfV_AtObj(hCert, a[0]);
var hE = ASN1HEX.getHexOfV_AtObj(hCert, a[1]);
if (hN != null && hE != null) {
return [hN, hE];
} else {
return [];
}
};
X509.getHexTbsCertificateFromCert = function(hCert) {
var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
return pTbsCert;
};
X509.getPublicKeyHexArrayFromCertPEM = function(sCertPEM) {
var hCert = X509.pemToHex(sCertPEM);
var a = X509.getPublicKeyHexArrayFromCertHex(hCert);
return a;
};
X509.hex2dn = function(hDN) {
var s = "";
var a = ASN1HEX.getPosArrayOfChildren_AtObj(hDN, 0);
for (var i = 0; i < a.length; i++) {
var hRDN = ASN1HEX.getHexOfTLV_AtObj(hDN, a[i]);
s = s + "/" + X509.hex2rdn(hRDN);
}
return s;
};
X509.hex2rdn = function(hRDN) {
var hType = ASN1HEX.getDecendantHexTLVByNthList(hRDN, 0, [0, 0]);
var hValue = ASN1HEX.getDecendantHexVByNthList(hRDN, 0, [0, 1]);
var type = "";
try { type = X509.DN_ATTRHEX[hType]; } catch (ex) { type = hType; }
hValue = hValue.replace(/(..)/g, "%$1");
var value = decodeURIComponent(hValue);
return type + "=" + value;
};
X509.DN_ATTRHEX = {
"0603550406": "C",
"060355040a": "O",
"060355040b": "OU",
"0603550403": "CN",
"0603550405": "SN",
"0603550408": "ST",
"0603550407": "L",
};
/**
* get RSAKey/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 info = X509.getPublicKeyInfoPropOfCertPEM(sCertPEM);
if (info.algoid == "2a864886f70d010101") { // RSA
var aRSA = KEYUTIL.parsePublicRawRSAKeyHex(info.keyhex);
var key = new RSAKey();
key.setPublic(aRSA.n, aRSA.e);
return key;
} else if (info.algoid == "2a8648ce3d0201") { // ECC
var curveName = KJUR.crypto.OID.oidhex2name[info.algparam];
var key = new KJUR.crypto.ECDSA({'curve': curveName, 'info': info.keyhex});
key.setPublicKeyHex(info.keyhex);
return key;
} else if (info.algoid == "2a8648ce380401") { // DSA 1.2.840.10040.4.1
var p = ASN1HEX.getVbyList(info.algparam, 0, [0], "02");
var q = ASN1HEX.getVbyList(info.algparam, 0, [1], "02");
var g = ASN1HEX.getVbyList(info.algparam, 0, [2], "02");
var y = ASN1HEX.getHexOfV_AtObj(info.keyhex, 0);
y = y.substr(2);
var key = new KJUR.crypto.DSA();
key.setPublic(new BigInteger(p, 16),
new BigInteger(q, 16),
new BigInteger(g, 16),
new BigInteger(y, 16));
return key;
} else {
throw "unsupported key";
}
};
/**
* 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:
*