1 /*! x509-1.1.12.js (c) 2012-2017 Kenji Urushima | kjur.github.com/jsrsasign/license
  2  */
  3 /*
  4  * x509.js - X509 class to read subject public key from certificate.
  5  *
  6  * Copyright (c) 2010-2017 Kenji Urushima (kenji.urushima@gmail.com)
  7  *
  8  * This software is licensed under the terms of the MIT License.
  9  * http://kjur.github.com/jsrsasign/license
 10  *
 11  * The above copyright and license notice shall be
 12  * included in all copies or substantial portions of the Software.
 13  */
 14 
 15 /**
 16  * @fileOverview
 17  * @name x509-1.1.js
 18  * @author Kenji Urushima kenji.urushima@gmail.com
 19  * @version x509 1.1.12 (2017-Mar-12)
 20  * @since jsrsasign 1.x.x
 21  * @license <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
 22  */
 23 
 24 /**
 25  * hexadecimal X.509 certificate ASN.1 parser class.<br/>
 26  * @class hexadecimal X.509 certificate ASN.1 parser class
 27  * @property {RSAKey} subjectPublicKeyRSA Tom Wu's RSAKey object
 28  * @property {String} subjectPublicKeyRSA_hN hexadecimal string for modulus of RSA public key
 29  * @property {String} subjectPublicKeyRSA_hE hexadecimal string for public exponent of RSA public key
 30  * @property {String} hex hexacedimal string for X.509 certificate.
 31  * @author Kenji Urushima
 32  * @version 1.0.1 (08 May 2012)
 33  * @see <a href="http://kjur.github.com/jsrsasigns/">'jsrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
 34  * @description
 35  * X509 class provides following functionality:
 36  * <ul>
 37  * <li>parse X.509 certificate ASN.1 structure</li>
 38  * <li>get basic fields, extensions, signature algorithms and signature values</li>
 39  * <li>read PEM certificate</li>
 40  * </ul>
 41  *
 42  * <ul>
 43  * <li><b>TO GET FIELDS</b>
 44  *   <ul>
 45  *   <li>serial - {@link X509#getSerialNumberHex}</li>
 46  *   <li>issuer - {@link X509#getIssuerHex}</li>
 47  *   <li>issuer - {@link X509#getIssuerString}</li>
 48  *   <li>notBefore - {@link X509#getNotBefore}</li>
 49  *   <li>notAfter - {@link X509#getNotAfter}</li>
 50  *   <li>subject - {@link X509#getSubjectHex}</li>
 51  *   <li>subject - {@link X509#getSubjectString}</li>
 52  *   <li>subjectPublicKeyInfo - {@link X509.getSubjectPublicKeyPosFromCertHex}</li>
 53  *   <li>subjectPublicKeyInfo - {@link X509.getSubjectPublicKeyInfoPosFromCertHex}</li>
 54  *   <li>subjectPublicKeyInfo - {@link X509.getPublicKeyFromCertPEM}</li>
 55  *   <li>signature algorithm - {@link X509.getSignatureAlgorithmName}</li>
 56  *   <li>signature value - {@link X509.getSignatureValueHex}</li>
 57  *   </ul>
 58  * </li>
 59  * <li><b>TO GET EXTENSIONS</b>
 60  *   <ul>
 61  *   <li>basicConstraints - {@link X509.getExtBasicConstraints}</li>
 62  *   <li>keyUsage - {@link X509.getExtKeyUsageBin}</li>
 63  *   <li>keyUsage - {@link X509.getExtKeyUsageString}</li>
 64  *   <li>subjectKeyIdentifier - {@link X509.getExtSubjectKeyIdentifier}</li>
 65  *   <li>authorityKeyIdentifier - {@link X509.getExtAuthorityKeyIdentifier}</li>
 66  *   <li>extKeyUsage - {@link X509.getExtExtKeyUsageName}</li>
 67  *   <li>subjectAltName - {@link X509.getExtSubjectAltName}</li>
 68  *   <li>cRLDistributionPoints - {@link X509.getExtCRLDistributionPointsURI}</li>
 69  *   <li>authorityInfoAccess - {@link X509.getExtAIAInfo}</li>
 70  *   </ul>
 71  * </li>
 72  * <li><b>UTILITIES</b>
 73  *   <ul>
 74  *   <li>reading PEM certificate - {@link X509#readCertPEM}</li>
 75  *   <li>get all certificate information - {@link X509#getInfo}</li>
 76  *   <li>get Base64 from PEM certificate - {@link X509.pemToBase64}</li>
 77  *   <li>verify signature value - {@link X509.verifySignature}</li>
 78  *   <li>get hexadecimal string from PEM certificate - {@link X509.pemToHex} (DEPRECATED)</li>
 79  *   </ul>
 80  * </li>
 81  * </ul>
 82  */
 83 function X509() {
 84     this.subjectPublicKeyRSA = null;
 85     this.subjectPublicKeyRSA_hN = null;
 86     this.subjectPublicKeyRSA_hE = null;
 87     this.hex = null;
 88 
 89     // ===== get basic fields from hex =====================================
 90 
 91     /**
 92      * get hexadecimal string of serialNumber field of certificate.<br/>
 93      * @name getSerialNumberHex
 94      * @memberOf X509#
 95      * @function
 96      * @return {String} hexadecimal string of certificate serial number
 97      * @example
 98      * var x = new X509();
 99      * x.readCertPEM(sCertPEM);
100      * var sn = x.getSerialNumberHex(); // return string like "01ad..."
101      */
102     this.getSerialNumberHex = function() {
103         return ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 1]);
104     };
105 
106 
107     /**
108      * get signature algorithm name in basic field
109      * @name getSignatureAlgorithmField
110      * @memberOf X509#
111      * @function
112      * @return {String} signature algorithm name (ex. SHA1withRSA, SHA256withECDSA)
113      * @since x509 1.1.8
114      * @description
115      * This method will get a name of signature algorithm field of certificate:
116      * @example
117      * var x = new X509();
118      * x.readCertPEM(sCertPEM);
119      * algName = x.getSignatureAlgorithmField();
120      */
121     this.getSignatureAlgorithmField = function() {
122 	var sigAlgOidHex = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 2, 0]);
123 	var sigAlgOidInt = KJUR.asn1.ASN1Util.oidHexToInt(sigAlgOidHex);
124 	var sigAlgName = KJUR.asn1.x509.OID.oid2name(sigAlgOidInt);
125 	return sigAlgName;
126     };
127 
128     /**
129      * get hexadecimal string of issuer field TLV of certificate.<br/>
130      * @name getIssuerHex
131      * @memberOf X509#
132      * @function
133      * @return {String} hexadecial string of issuer DN ASN.1
134      * @example
135      * var x = new X509();
136      * x.readCertPEM(sCertPEM);
137      * var issuer = x.getIssuerHex(); // return string like "3013..."
138      */
139     this.getIssuerHex = function() {
140         return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]);
141     };
142 
143     /**
144      * get string of issuer field of certificate.<br/>
145      * @name getIssuerString
146      * @memberOf X509#
147      * @function
148      * @return {String} issuer DN string
149      * @example
150      * var x = new X509();
151      * x.readCertPEM(sCertPEM);
152      * var issuer = x.getIssuerString(); // return string like "/C=US/O=TEST"
153      */
154     this.getIssuerString = function() {
155         return X509.hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]));
156     };
157 
158     /**
159      * get hexadecimal string of subject field of certificate.<br/>
160      * @name getSubjectHex
161      * @memberOf X509#
162      * @function
163      * @return {String} hexadecial string of subject DN ASN.1
164      * @example
165      * var x = new X509();
166      * x.readCertPEM(sCertPEM);
167      * var subject = x.getSubjectHex(); // return string like "3013..."
168      */
169     this.getSubjectHex = function() {
170         return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]);
171     };
172 
173     /**
174      * get string of subject field of certificate.<br/>
175      * @name getSubjectString
176      * @memberOf X509#
177      * @function
178      * @return {String} subject DN string
179      * @example
180      * var x = new X509();
181      * x.readCertPEM(sCertPEM);
182      * var subject = x.getSubjectString(); // return string like "/C=US/O=TEST"
183      */
184     this.getSubjectString = function() {
185         return X509.hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]));
186     };
187 
188     /**
189      * get notBefore field string of certificate.<br/>
190      * @name getNotBefore
191      * @memberOf X509#
192      * @function
193      * @return {String} not before time value (ex. "151231235959Z")
194      * @example
195      * var x = new X509();
196      * x.readCertPEM(sCertPEM);
197      * var notBefore = x.getNotBefore(); // return string like "151231235959Z"
198      */
199     this.getNotBefore = function() {
200         var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 0]);
201         s = s.replace(/(..)/g, "%$1");
202         s = decodeURIComponent(s);
203         return s;
204     };
205 
206     /**
207      * get notAfter field string of certificate.<br/>
208      * @name getNotAfter
209      * @memberOf X509#
210      * @function
211      * @return {String} not after time value (ex. "151231235959Z")
212      * @example
213      * var x = new X509();
214      * x.readCertPEM(sCertPEM);
215      * var notAfter = x.getNotAfter(); // return string like "151231235959Z"
216      */
217     this.getNotAfter = function() {
218         var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 1]);
219         s = s.replace(/(..)/g, "%$1");
220         s = decodeURIComponent(s);
221         return s;
222     };
223 
224     // ===== read certificate public key ==========================
225 
226     // ===== read certificate =====================================
227     /**
228      * read PEM formatted X.509 certificate from string.<br/>
229      * @name readCertPEM
230      * @memberOf X509#
231      * @function
232      * @param {String} sCertPEM string for PEM formatted X.509 certificate
233      * @example
234      * x = new X509();
235      * x.readCertPEM(sCertPEM); // read certificate
236      */
237     this.readCertPEM = function(sCertPEM) {
238         var hCert = ASN1HEX.pemToHex(sCertPEM);
239         var a = X509.getPublicKeyHexArrayFromCertHex(hCert);
240         var rsa = new RSAKey();
241         rsa.setPublic(a[0], a[1]);
242         this.subjectPublicKeyRSA = rsa;
243         this.subjectPublicKeyRSA_hN = a[0];
244         this.subjectPublicKeyRSA_hE = a[1];
245         this.hex = hCert;
246     };
247 
248     this.readCertPEMWithoutRSAInit = function(sCertPEM) {
249         var hCert = ASN1HEX.pemToHex(sCertPEM);
250         var a = X509.getPublicKeyHexArrayFromCertHex(hCert);
251         if (typeof this.subjectPublicKeyRSA.setPublic === "function") {
252             this.subjectPublicKeyRSA.setPublic(a[0], a[1]);
253         }
254         this.subjectPublicKeyRSA_hN = a[0];
255         this.subjectPublicKeyRSA_hE = a[1];
256         this.hex = hCert;
257     };
258 
259     /**
260      * get certificate information as string.<br/>
261      * @name getInfo
262      * @memberOf X509#
263      * @function
264      * @return {String} certificate information string
265      * @since jsrsasign 5.0.10 x509 1.1.8
266      * @example
267      * x = new X509();
268      * x.readCertPEM(certPEM);
269      * console.log(x.getInfo());
270      * // this shows as following
271      * Basic Fields
272      *   serial number: 02ac5c266a0b409b8f0b79f2ae462577
273      *   signature algorithm: SHA1withRSA
274      *   issuer: /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA
275      *   notBefore: 061110000000Z
276      *   notAfter: 311110000000Z
277      *   subject: /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA
278      *   subject public key info:
279      *     key algorithm: RSA
280      *     n=c6cce573e6fbd4bb...
281      *     e=10001
282      * X509v3 Extensions:
283      *   keyUsage CRITICAL:
284      *     digitalSignature,keyCertSign,cRLSign
285      *   basicConstraints CRITICAL:
286      *     cA=true
287      *   subjectKeyIdentifier :
288      *     b13ec36903f8bf4701d498261a0802ef63642bc3
289      *   authorityKeyIdentifier :
290      *     kid=b13ec36903f8bf4701d498261a0802ef63642bc3
291      * signature algorithm: SHA1withRSA
292      * signature: 1c1a0697dcd79c9f...
293      */
294     this.getInfo = function() {
295 	var s = "Basic Fields\n";
296         s += "  serial number: " + this.getSerialNumberHex() + "\n";
297 	s += "  signature algorithm: " + this.getSignatureAlgorithmField() + "\n";
298 	s += "  issuer: " + this.getIssuerString() + "\n";
299 	s += "  notBefore: " + this.getNotBefore() + "\n";
300 	s += "  notAfter: " + this.getNotAfter() + "\n";
301 	s += "  subject: " + this.getSubjectString() + "\n";
302 	s += "  subject public key info: " + "\n";
303 
304 	// subject public key info
305 	var pSPKI = X509.getSubjectPublicKeyInfoPosFromCertHex(this.hex);
306 	var hSPKI = ASN1HEX.getHexOfTLV_AtObj(this.hex, pSPKI);
307 	var keyObj = KEYUTIL.getKey(hSPKI, null, "pkcs8pub");
308 	//s += "    " + JSON.stringify(keyObj) + "\n";
309 	if (keyObj instanceof RSAKey) {
310 	    s += "    key algorithm: RSA\n";
311 	    s += "    n=" + keyObj.n.toString(16).substr(0, 16) + "...\n";
312 	    s += "    e=" + keyObj.e.toString(16) + "\n";
313 	}
314 
315         s += "X509v3 Extensions:\n";
316 
317 	var aExt = X509.getV3ExtInfoListOfCertHex(this.hex);
318         for (var i = 0; i < aExt.length; i++) {
319 	    var info = aExt[i];
320 
321 	    // show extension name and critical flag
322 	    var extName = KJUR.asn1.x509.OID.oid2name(info["oid"]);
323 	    if (extName === '') extName = info["oid"];
324 
325 	    var critical = '';
326 	    if (info["critical"] === true) critical = "CRITICAL";
327 
328 	    s += "  " + extName + " " + critical + ":\n";
329 
330 	    // show extension value if supported
331 	    if (extName === "basicConstraints") {
332 		var bc = X509.getExtBasicConstraints(this.hex);
333 		if (bc.cA === undefined) {
334 		    s += "    {}\n";
335 		} else {
336 		    s += "    cA=true";
337 		    if (bc.pathLen !== undefined)
338 			s += ", pathLen=" + bc.pathLen;
339 		    s += "\n";
340 		}
341 	    } else if (extName === "keyUsage") {
342 		s += "    " + X509.getExtKeyUsageString(this.hex) + "\n";
343 	    } else if (extName === "subjectKeyIdentifier") {
344 		s += "    " + X509.getExtSubjectKeyIdentifier(this.hex) + "\n";
345 	    } else if (extName === "authorityKeyIdentifier") {
346 		var akid = X509.getExtAuthorityKeyIdentifier(this.hex);
347 		if (akid.kid !== undefined)
348 		    s += "    kid=" + akid.kid + "\n";
349 	    } else if (extName === "extKeyUsage") {
350 		var eku = X509.getExtExtKeyUsageName(this.hex);
351 		s += "    " + eku.join(", ") + "\n";
352 	    } else if (extName === "subjectAltName") {
353 		var san = X509.getExtSubjectAltName(this.hex);
354 		s += "    " + san.join(", ") + "\n";
355 	    } else if (extName === "cRLDistributionPoints") {
356 		var cdp = X509.getExtCRLDistributionPointsURI(this.hex);
357 		s += "    " + cdp + "\n";
358 	    } else if (extName === "authorityInfoAccess") {
359 		var aia = X509.getExtAIAInfo(this.hex);
360 		if (aia.ocsp !== undefined)
361 		    s += "    ocsp: " + aia.ocsp.join(",") + "\n";
362 		if (aia.caissuer !== undefined)
363 		    s += "    caissuer: " + aia.caissuer.join(",") + "\n";
364 	    }
365         }
366 
367 	s += "signature algorithm: " + X509.getSignatureAlgorithmName(this.hex) + "\n";
368 	s += "signature: " + X509.getSignatureValueHex(this.hex).substr(0, 16) + "...\n";
369 	return s;
370     };
371 };
372 
373 /**
374  * get Base64 string from PEM certificate string
375  * @name pemToBase64
376  * @memberOf X509
377  * @function
378  * @param {String} sCertPEM PEM formatted RSA/ECDSA/DSA X.509 certificate
379  * @return {String} Base64 string of PEM certificate
380  * @example
381  * b64 = X509.pemToBase64(certPEM);
382  */
383 X509.pemToBase64 = function(sCertPEM) {
384     var s = sCertPEM;
385     s = s.replace("-----BEGIN CERTIFICATE-----", "");
386     s = s.replace("-----END CERTIFICATE-----", "");
387     s = s.replace(/[ \n]+/g, "");
388     return s;
389 };
390 
391 /**
392  * (DEPRECATED) get a hexa decimal string from PEM certificate string
393  * @name pemToHex
394  * @memberOf X509
395  * @function
396  * @param {String} sCertPEM PEM formatted RSA/ECDSA/DSA X.509 certificate
397  * @return {String} hexadecimal string of PEM certificate
398  * @deprecated from x509 1.1.11 jsrsasign 7.0.1. please move to {@link ASN1HEX.pemToHex}
399  * @description
400  * CAUTION: now X509.pemToHex deprecated and is planed to remove in jsrsasign 8.0.0.
401  * @example
402  * hex = X509.pemToHex(certPEM);
403  */
404 X509.pemToHex = function(sCertPEM) {
405     return ASN1HEX.pemToHex(sCertPEM);
406 };
407 
408 /**
409  * get a string index of contents of subjectPublicKeyInfo BITSTRING value from hexadecimal certificate<br/>
410  * @name getSubjectPublicKeyPosFromCertHex
411  * @memberOf X509
412  * @function
413  * @param {String} hexadecimal string of DER RSA/ECDSA/DSA X.509 certificate
414  * @return {Integer} string index of key contents
415  * @example
416  * idx = X509.getSubjectPublicKeyPosFromCertHex("3082...");
417  */
418 // NOTE: Without BITSTRING encapsulation.
419 X509.getSubjectPublicKeyPosFromCertHex = function(hCert) {
420     var pInfo = X509.getSubjectPublicKeyInfoPosFromCertHex(hCert);
421     if (pInfo == -1) return -1;
422     var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pInfo);
423     if (a.length != 2) return -1;
424     var pBitString = a[1];
425     if (hCert.substring(pBitString, pBitString + 2) != '03') return -1;
426     var pBitStringV = ASN1HEX.getStartPosOfV_AtObj(hCert, pBitString);
427 
428     if (hCert.substring(pBitStringV, pBitStringV + 2) != '00') return -1;
429     return pBitStringV + 2;
430 };
431 
432 /**
433  * get a string index of subjectPublicKeyInfo field from hexadecimal certificate<br/>
434  * @name getSubjectPublicKeyInfoPosFromCertHex
435  * @memberOf X509
436  * @function
437  * @param {String} hexadecimal string of DER RSA/ECDSA/DSA X.509 certificate
438  * @return {Integer} string index of subjectPublicKeyInfo field
439  * @description
440  * This static method gets a string index of subjectPublicKeyInfo field from hexadecimal certificate.<br/>
441  * NOTE1: privateKeyUsagePeriod field of X509v2 not supported.<br/>
442  * NOTE2: X.509v1 and X.509v3 certificate are supported.<br/>
443  * @example
444  * idx = X509.getSubjectPublicKeyInfoPosFromCertHex("3082...");
445  */
446 X509.getSubjectPublicKeyInfoPosFromCertHex = function(hCert) {
447     var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
448     var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pTbsCert);
449     if (a.length < 1) return -1;
450     if (hCert.substring(a[0], a[0] + 10) == "a003020102") { // v3
451         if (a.length < 6) return -1;
452         return a[6];
453     } else {
454         if (a.length < 5) return -1;
455         return a[5];
456     }
457 };
458 
459 X509.getPublicKeyHexArrayFromCertHex = function(hCert) {
460     var p = X509.getSubjectPublicKeyPosFromCertHex(hCert);
461     var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p);
462     if (a.length != 2) return [];
463     var hN = ASN1HEX.getHexOfV_AtObj(hCert, a[0]);
464     var hE = ASN1HEX.getHexOfV_AtObj(hCert, a[1]);
465     if (hN != null && hE != null) {
466         return [hN, hE];
467     } else {
468         return [];
469     }
470 };
471 
472 X509.getHexTbsCertificateFromCert = function(hCert) {
473     var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
474     return pTbsCert;
475 };
476 
477 X509.getPublicKeyHexArrayFromCertPEM = function(sCertPEM) {
478     var hCert = ASN1HEX.pemToHex(sCertPEM);
479     var a = X509.getPublicKeyHexArrayFromCertHex(hCert);
480     return a;
481 };
482 
483 /**
484  * get distinguished name string in OpenSSL online format from hexadecimal string of ASN.1 DER X.500 name<br/>
485  * @name hex2dn
486  * @memberOf X509
487  * @function
488  * @param {String} hex hexadecimal string of ASN.1 DER distinguished name
489  * @param {Integer} idx index of hexadecimal string (DEFAULT=0)
490  * @return {String} OpenSSL online format distinguished name
491  * @description
492  * This static method converts from a hexadecimal string of 
493  * distinguished name (DN)
494  * specified by 'hex' and 'idx' to OpenSSL oneline string representation (ex. /C=US/O=a).
495  * @example
496  * X509.hex2dn("3031310b3...") → /C=US/O=a/CN=b2+OU=b1
497  */
498 X509.hex2dn = function(hex, idx) {
499     if (idx === undefined) idx = 0;
500     if (hex.substr(idx, 2) !== "30") throw "malformed DN";
501 
502     var a = new Array();
503 
504     var aIdx = ASN1HEX.getPosArrayOfChildren_AtObj(hex, idx);
505     for (var i = 0; i < aIdx.length; i++) {
506 	a.push(X509.hex2rdn(hex, aIdx[i]));
507     }
508 
509     a = a.map(function(s) { return s.replace("/", "\\/"); });
510     return "/" + a.join("/");
511 };
512 
513 /**
514  * get relative distinguished name string in OpenSSL online format from hexadecimal string of ASN.1 DER RDN<br/>
515  * @name hex2rdn
516  * @memberOf X509
517  * @function
518  * @param {String} hex hexadecimal string of ASN.1 DER concludes relative distinguished name
519  * @param {Integer} idx index of hexadecimal string (DEFAULT=0)
520  * @return {String} OpenSSL online format relative distinguished name
521  * @description
522  * This static method converts from a hexadecimal string of 
523  * relative distinguished name (RDN)
524  * specified by 'hex' and 'idx' to LDAP string representation (ex. O=test+CN=test).<br/>
525  * NOTE: Multi-valued RDN is supported since jsnrsasign 6.2.2 x509 1.1.10.
526  * @example
527  * X509.hex2rdn("310a3008060355040a0c0161") → O=a
528  * X509.hex2rdn("31143008060355040a0c01613008060355040a0c0162") → O=a+O=b
529  */
530 X509.hex2rdn = function(hex, idx) {
531     if (idx === undefined) idx = 0;
532     if (hex.substr(idx, 2) !== "31") throw "malformed RDN";
533 
534     var a = new Array();
535 
536     var aIdx = ASN1HEX.getPosArrayOfChildren_AtObj(hex, idx);
537     for (var i = 0; i < aIdx.length; i++) {
538 	a.push(X509.hex2attrTypeValue(hex, aIdx[i]));
539     }
540 
541     a = a.map(function(s) { return s.replace("+", "\\+"); });
542     return a.join("+");
543 };
544 
545 /**
546  * get string from hexadecimal string of ASN.1 DER AttributeTypeAndValue<br/>
547  * @name hex2attrTypeValue
548  * @memberOf X509
549  * @function
550  * @param {String} hex hexadecimal string of ASN.1 DER concludes AttributeTypeAndValue
551  * @param {Integer} idx index of hexadecimal string (DEFAULT=0)
552  * @return {String} string representation of AttributeTypeAndValue (ex. C=US)
553  * @description
554  * This static method converts from a hexadecimal string of AttributeTypeAndValue
555  * specified by 'hex' and 'idx' to LDAP string representation (ex. C=US).
556  * @example
557  * X509.hex2attrTypeValue("3008060355040a0c0161") → O=a
558  * X509.hex2attrTypeValue("300806035504060c0161") → C=a
559  * X509.hex2attrTypeValue("...3008060355040a0c0161...", 128) → O=a
560  */
561 X509.hex2attrTypeValue = function(hex, idx) {
562     if (idx === undefined) idx = 0;
563     if (hex.substr(idx, 2) !== "30") throw "malformed attribute type and value";
564 
565     var aIdx = ASN1HEX.getPosArrayOfChildren_AtObj(hex, idx);
566     if (aIdx.length !== 2 || hex.substr(aIdx[0], 2) !== "06")
567 	"malformed attribute type and value";
568 
569     var oidHex = ASN1HEX.getHexOfV_AtObj(hex, aIdx[0]);
570     var oidInt = KJUR.asn1.ASN1Util.oidHexToInt(oidHex);
571     var atype = KJUR.asn1.x509.OID.oid2atype(oidInt);
572 
573     var hV = ASN1HEX.getHexOfV_AtObj(hex, aIdx[1]);
574     var rawV = hextorstr(hV);
575 
576     return atype + "=" + rawV;
577 };
578 
579 /**
580  * get RSA/DSA/ECDSA public key object from X.509 certificate hexadecimal string<br/>
581  * @name getPublicKeyFromCertHex
582  * @memberOf X509
583  * @function
584  * @param {String} h hexadecimal string of X.509 certificate for RSA/ECDSA/DSA public key
585  * @return returns RSAKey/KJUR.crypto.{ECDSA,DSA} object of public key
586  * @since jsrasign 7.1.0 x509 1.1.11
587  */
588 X509.getPublicKeyFromCertHex = function(h) {
589     var key, hKEYOID, hItem1;
590     var nthPKI = 6; // for publicKeyInfo index is 6 for v3 or 5 for v1
591     var _ASN1HEX = ASN1HEX;
592     var _getVbyList = _ASN1HEX.getVbyList;
593 
594     hItem1 = _ASN1HEX.getDecendantHexTLVByNthList(h, 0, [0, 0]);
595     if (hItem1 !== "a003020102") { // tbsCert first item is version(=v3)
596 	nthPKI = 5;
597     }
598 
599     hKEYOID = _getVbyList(h, 0, [0, nthPKI, 0, 0], "06");
600     if (hKEYOID === "2a864886f70d010101") {    // RSA
601         key = new RSAKey();
602     } else if (hKEYOID === "2a8648ce380401") { // DSA
603         key = new KJUR.crypto.DSA();
604     } else if (hKEYOID === "2a8648ce3d0201") { // CC
605         key = new KJUR.crypto.ECDSA();
606     } else {
607         throw "unsupported public key in X.509 cert";
608     }
609     key.readCertPubKeyHex(h, nthPKI);
610     return key;
611 };
612 
613 /**
614  * get RSA/DSA/ECDSA public key object from PEM certificate string
615  * @name getPublicKeyFromCertPEM
616  * @memberOf X509
617  * @function
618  * @param {String} sCertPEM PEM formatted RSA/ECDSA/DSA X.509 certificate
619  * @return returns RSAKey/KJUR.crypto.{ECDSA,DSA} object of public key
620  * @since x509 1.1.1
621  * @description
622  * NOTE: DSA is also supported since x509 1.1.2.
623  */
624 X509.getPublicKeyFromCertPEM = function(sCertPEM) {
625     var _ASN1HEX = ASN1HEX;
626     var h = _ASN1HEX.pemToHex(sCertPEM);
627     return X509.getPublicKeyFromCertHex(h);
628 };
629 
630 /**
631  * get public key information from PEM certificate
632  * @name getPublicKeyInfoPropOfCertPEM
633  * @memberOf X509
634  * @function
635  * @param {String} sCertPEM string of PEM formatted certificate
636  * @return {Hash} hash of information for public key
637  * @since x509 1.1.1
638  * @description
639  * Resulted associative array has following properties:<br/>
640  * <ul>
641  * <li>algoid - hexadecimal string of OID of asymmetric key algorithm</li>
642  * <li>algparam - hexadecimal string of OID of ECC curve name or null</li>
643  * <li>keyhex - hexadecimal string of key in the certificate</li>
644  * </ul>
645  * NOTE: X509v1 certificate is also supported since x509.js 1.1.9.
646  */
647 X509.getPublicKeyInfoPropOfCertPEM = function(sCertPEM) {
648     var result = {};
649     result.algparam = null;
650     var hCert = ASN1HEX.pemToHex(sCertPEM);
651 
652     // 1. Certificate ASN.1
653     var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, 0);
654     if (a1.length != 3)
655         throw "malformed X.509 certificate PEM (code:001)"; // not 3 item of seq Cert
656 
657     // 2. tbsCertificate
658     if (hCert.substr(a1[0], 2) != "30")
659         throw "malformed X.509 certificate PEM (code:002)"; // tbsCert not seq
660 
661     var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a1[0]);
662 
663     // 3. subjectPublicKeyInfo
664     var idx_spi = 6; // subjectPublicKeyInfo index in tbsCert for v3 cert
665     if (hCert.substr(a2[0], 2) !== "a0") idx_spi = 5;
666 
667     if (a2.length < idx_spi + 1)
668         throw "malformed X.509 certificate PEM (code:003)"; // no subjPubKeyInfo
669 
670     var a3 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a2[idx_spi]);
671 
672     if (a3.length != 2)
673         throw "malformed X.509 certificate PEM (code:004)"; // not AlgId and PubKey
674 
675     // 4. AlgId
676     var a4 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a3[0]);
677 
678     if (a4.length != 2)
679         throw "malformed X.509 certificate PEM (code:005)"; // not 2 item in AlgId
680 
681     result.algoid = ASN1HEX.getHexOfV_AtObj(hCert, a4[0]);
682 
683     if (hCert.substr(a4[1], 2) == "06") { // EC
684         result.algparam = ASN1HEX.getHexOfV_AtObj(hCert, a4[1]);
685     } else if (hCert.substr(a4[1], 2) == "30") { // DSA
686         result.algparam = ASN1HEX.getHexOfTLV_AtObj(hCert, a4[1]);
687     }
688 
689     // 5. Public Key Hex
690     if (hCert.substr(a3[1], 2) != "03")
691         throw "malformed X.509 certificate PEM (code:006)"; // not bitstring
692 
693     var unusedBitAndKeyHex = ASN1HEX.getHexOfV_AtObj(hCert, a3[1]);
694     result.keyhex = unusedBitAndKeyHex.substr(2);
695 
696     return result;
697 };
698 
699 /**
700  * get position of subjectPublicKeyInfo field from HEX certificate
701  * @name getPublicKeyInfoPosOfCertHEX
702  * @memberOf X509
703  * @function
704  * @param {String} hCert hexadecimal string of certificate
705  * @return {Integer} position in hexadecimal string
706  * @since x509 1.1.4
707  * @description
708  * get position for SubjectPublicKeyInfo field in the hexadecimal string of
709  * certificate.
710  */
711 X509.getPublicKeyInfoPosOfCertHEX = function(hCert) {
712     // 1. Certificate ASN.1
713     var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, 0);
714     if (a1.length != 3)
715         throw "malformed X.509 certificate PEM (code:001)"; // not 3 item of seq Cert
716 
717     // 2. tbsCertificate
718     if (hCert.substr(a1[0], 2) != "30")
719         throw "malformed X.509 certificate PEM (code:002)"; // tbsCert not seq
720 
721     var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a1[0]);
722 
723     // 3. subjectPublicKeyInfo
724     if (a2.length < 7)
725         throw "malformed X.509 certificate PEM (code:003)"; // no subjPubKeyInfo
726 
727     return a2[6];
728 };
729 
730 /**
731  * get array of X.509 V3 extension value information in hex string of certificate
732  * @name getV3ExtInfoListOfCertHex
733  * @memberOf X509
734  * @function
735  * @param {String} hCert hexadecimal string of X.509 certificate binary
736  * @return {Array} array of result object by {@link X509.getV3ExtInfoListOfCertHex}
737  * @since x509 1.1.5
738  * @description
739  * This method will get all extension information of a X.509 certificate.
740  * Items of resulting array has following properties:
741  * <ul>
742  * <li>posTLV - index of ASN.1 TLV for the extension. same as 'pos' argument.</li>
743  * <li>oid - dot noted string of extension oid (ex. 2.5.29.14)</li>
744  * <li>critical - critical flag value for this extension</li>
745  * <li>posV - index of ASN.1 TLV for the extension value.
746  * This is a position of a content of ENCAPSULATED OCTET STRING.</li>
747  * </ul>
748  * @example
749  * hCert = ASN1HEX.pemToHex(certGithubPEM);
750  * a = X509.getV3ExtInfoListOfCertHex(hCert);
751  * // Then a will be an array of like following:
752  * [{posTLV: 1952, oid: "2.5.29.35", critical: false, posV: 1968},
753  *  {posTLV: 1974, oid: "2.5.29.19", critical: true, posV: 1986}, ...]
754  */
755 X509.getV3ExtInfoListOfCertHex = function(hCert) {
756     // 1. Certificate ASN.1
757     var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, 0);
758     if (a1.length != 3)
759         throw "malformed X.509 certificate PEM (code:001)"; // not 3 item of seq Cert
760 
761     // 2. tbsCertificate
762     if (hCert.substr(a1[0], 2) != "30")
763         throw "malformed X.509 certificate PEM (code:002)"; // tbsCert not seq
764 
765     var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a1[0]);
766 
767     // 3. v3Extension EXPLICIT Tag [3]
768     // ver, seri, alg, iss, validity, subj, spki, (iui,) (sui,) ext
769     if (a2.length < 8)
770         throw "malformed X.509 certificate PEM (code:003)"; // tbsCert num field too short
771 
772     if (hCert.substr(a2[7], 2) != "a3")
773         throw "malformed X.509 certificate PEM (code:004)"; // not [3] tag
774 
775     var a3 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a2[7]);
776     if (a3.length != 1)
777         throw "malformed X.509 certificate PEM (code:005)"; // [3]tag numChild!=1
778 
779     // 4. v3Extension SEQUENCE
780     if (hCert.substr(a3[0], 2) != "30")
781         throw "malformed X.509 certificate PEM (code:006)"; // not SEQ
782 
783     var a4 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a3[0]);
784 
785     // 5. v3Extension item position
786     var numExt = a4.length;
787     var aInfo = new Array(numExt);
788     for (var i = 0; i < numExt; i++) {
789 	aInfo[i] = X509.getV3ExtItemInfo_AtObj(hCert, a4[i]);
790     }
791     return aInfo;
792 };
793 
794 /**
795  * get X.509 V3 extension value information at the specified position
796  * @name getV3ExtItemInfo_AtObj
797  * @memberOf X509
798  * @function
799  * @param {String} hCert hexadecimal string of X.509 certificate binary
800  * @param {Integer} pos index of hexadecimal string for the extension
801  * @return {Object} properties for the extension
802  * @since x509 1.1.5
803  * @description
804  * This method will get some information of a X.509 V extension
805  * which is referred by an index of hexadecimal string of X.509
806  * certificate.
807  * Resulting object has following properties:
808  * <ul>
809  * <li>posTLV - index of ASN.1 TLV for the extension. same as 'pos' argument.</li>
810  * <li>oid - dot noted string of extension oid (ex. 2.5.29.14)</li>
811  * <li>critical - critical flag value for this extension</li>
812  * <li>posV - index of ASN.1 TLV for the extension value.
813  * This is a position of a content of ENCAPSULATED OCTET STRING.</li>
814  * </ul>
815  * This method is used by {@link X509.getV3ExtInfoListOfCertHex} internally.
816  */
817 X509.getV3ExtItemInfo_AtObj = function(hCert, pos) {
818     var info = {};
819 
820     // posTLV - extension TLV
821     info.posTLV = pos;
822 
823     var a  = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pos);
824     if (a.length != 2 && a.length != 3)
825         throw "malformed X.509v3 Ext (code:001)"; // oid,(critical,)val
826 
827     // oid - extension OID
828     if (hCert.substr(a[0], 2) != "06")
829         throw "malformed X.509v3 Ext (code:002)"; // not OID "06"
830     var valueHex = ASN1HEX.getHexOfV_AtObj(hCert, a[0]);
831     info.oid = ASN1HEX.hextooidstr(valueHex);
832 
833     // critical - extension critical flag
834     info.critical = false; // critical false by default
835     if (a.length == 3) info.critical = true;
836 
837     // posV - content TLV position of encapsulated
838     //        octet string of V3 extension value.
839     var posExtV = a[a.length - 1];
840     if (hCert.substr(posExtV, 2) != "04")
841         throw "malformed X.509v3 Ext (code:003)"; // not EncapOctet "04"
842     info.posV = ASN1HEX.getStartPosOfV_AtObj(hCert, posExtV);
843 
844     return info;
845 };
846 
847 /**
848  * get X.509 V3 extension value ASN.1 TLV for specified oid or name
849  * @name getHexOfTLV_V3ExtValue
850  * @memberOf X509
851  * @function
852  * @param {String} hCert hexadecimal string of X.509 certificate binary
853  * @param {String} oidOrName oid or name for extension (ex. 'keyUsage' or '2.5.29.15')
854  * @return {String} hexadecimal string of extension ASN.1 TLV
855  * @since x509 1.1.6
856  * @description
857  * This method will get X.509v3 extension value of ASN.1 TLV
858  * which is specifyed by extension name or oid.
859  * If there is no such extension in the certificate, it returns null.
860  * @example
861  * hExtValue = X509.getHexOfTLV_V3ExtValue(hCert, "keyUsage");
862  * // hExtValue will be such like '030205a0'.
863  */
864 X509.getHexOfTLV_V3ExtValue = function(hCert, oidOrName) {
865     var pos = X509.getPosOfTLV_V3ExtValue(hCert, oidOrName);
866     if (pos == -1) return null;
867     return ASN1HEX.getHexOfTLV_AtObj(hCert, pos);
868 };
869 
870 /**
871  * get X.509 V3 extension value ASN.1 V for specified oid or name
872  * @name getHexOfV_V3ExtValue
873  * @memberOf X509
874  * @function
875  * @param {String} hCert hexadecimal string of X.509 certificate binary
876  * @param {String} oidOrName oid or name for extension (ex. 'keyUsage' or '2.5.29.15')
877  * @return {String} hexadecimal string of extension ASN.1 TLV
878  * @since x509 1.1.6
879  * @description
880  * This method will get X.509v3 extension value of ASN.1 value
881  * which is specifyed by extension name or oid.
882  * If there is no such extension in the certificate, it returns null.
883  * Available extension names and oids are defined
884  * in the {@link KJUR.asn1.x509.OID} class.
885  * @example
886  * hExtValue = X509.getHexOfV_V3ExtValue(hCert, "keyUsage");
887  * // hExtValue will be such like '05a0'.
888  */
889 X509.getHexOfV_V3ExtValue = function(hCert, oidOrName) {
890     var pos = X509.getPosOfTLV_V3ExtValue(hCert, oidOrName);
891     if (pos == -1) return null;
892     return ASN1HEX.getHexOfV_AtObj(hCert, pos);
893 };
894 
895 /**
896  * get index in the certificate hexa string for specified oid or name specified extension
897  * @name getPosOfTLV_V3ExtValue
898  * @memberOf X509
899  * @function
900  * @param {String} hCert hexadecimal string of X.509 certificate binary
901  * @param {String} oidOrName oid or name for extension (ex. 'keyUsage' or '2.5.29.15')
902  * @return {Integer} index in the hexadecimal string of certficate for specified extension
903  * @since x509 1.1.6
904  * @description
905  * This method will get X.509v3 extension value of ASN.1 V(value)
906  * which is specifyed by extension name or oid.
907  * If there is no such extension in the certificate,
908  * it returns -1.
909  * Available extension names and oids are defined
910  * in the {@link KJUR.asn1.x509.OID} class.
911  * @example
912  * idx = X509.getPosOfV_V3ExtValue(hCert, "keyUsage");
913  * // The 'idx' will be index in the string for keyUsage value ASN.1 TLV.
914  */
915 X509.getPosOfTLV_V3ExtValue = function(hCert, oidOrName) {
916     var oid = oidOrName;
917     if (! oidOrName.match(/^[0-9.]+$/)) oid = KJUR.asn1.x509.OID.name2oid(oidOrName);
918     if (oid == '') return -1;
919 
920     var infoList = X509.getV3ExtInfoListOfCertHex(hCert);
921     for (var i = 0; i < infoList.length; i++) {
922 	var info = infoList[i];
923 	if (info.oid == oid) return info.posV;
924     }
925     return -1;
926 };
927 
928 /* ======================================================================
929  *   Specific V3 Extensions
930  * ====================================================================== */
931 
932 /**
933  * get BasicConstraints extension value as object in the certificate
934  * @name getExtBasicConstraints
935  * @memberOf X509
936  * @function
937  * @param {String} hCert hexadecimal string of X.509 certificate binary
938  * @return {Object} associative array which may have "cA" and "pathLen" parameters
939  * @since x509 1.1.7
940  * @description
941  * This method will get basic constraints extension value as object with following paramters.
942  * <ul>
943  * <li>cA - CA flag whether CA or not</li>
944  * <li>pathLen - maximum intermediate certificate length</li>
945  * </ul>
946  * There are use cases for return values:
947  * <ul>
948  * <li>{cA:true, pathLen:3} - cA flag is true and pathLen is 3</li>
949  * <li>{cA:true} - cA flag is true and no pathLen</li>
950  * <li>{} - basic constraints has no value in case of end entity certificate</li>
951  * <li>null - there is no basic constraints extension</li>
952  * </ul>
953  * @example
954  * obj = X509.getExtBasicConstraints(hCert);
955  */
956 X509.getExtBasicConstraints = function(hCert) {
957     var hBC = X509.getHexOfV_V3ExtValue(hCert, "basicConstraints");
958     if (hBC === null) return null;
959     if (hBC === '') return {};
960     if (hBC === '0101ff') return { "cA": true };
961     if (hBC.substr(0, 8) === '0101ff02') {
962 	var pathLexHex = ASN1HEX.getHexOfV_AtObj(hBC, 6);
963 	var pathLen = parseInt(pathLexHex, 16);
964 	return { "cA": true, "pathLen": pathLen };
965     }
966     throw "unknown error";
967 };
968 
969 X509.KEYUSAGE_NAME = [
970     "digitalSignature",
971     "nonRepudiation",
972     "keyEncipherment",
973     "dataEncipherment",
974     "keyAgreement",
975     "keyCertSign",
976     "cRLSign",
977     "encipherOnly",
978     "decipherOnly"
979 ];
980 
981 /**
982  * get KeyUsage extension value as binary string in the certificate
983  * @name getExtKeyUsageBin
984  * @memberOf X509
985  * @function
986  * @param {String} hCert hexadecimal string of X.509 certificate binary
987  * @return {String} binary string of key usage bits (ex. '101')
988  * @since x509 1.1.6
989  * @description
990  * This method will get key usage extension value
991  * as binary string such like '101'.
992  * Key usage bits definition is in the RFC 5280.
993  * If there is no key usage extension in the certificate,
994  * it returns empty string (i.e. '').
995  * @example
996  * bKeyUsage = X509.getExtKeyUsageBin(hCert);
997  * // bKeyUsage will be such like '101'.
998  * // 1 - digitalSignature
999  * // 0 - nonRepudiation
1000  * // 1 - keyEncipherment
1001  */
1002 X509.getExtKeyUsageBin = function(hCert) {
1003     var hKeyUsage = X509.getHexOfV_V3ExtValue(hCert, "keyUsage");
1004     if (hKeyUsage == '') return '';
1005     if (hKeyUsage.length % 2 != 0 || hKeyUsage.length <= 2)
1006 	throw "malformed key usage value";
1007     var unusedBits = parseInt(hKeyUsage.substr(0, 2));
1008     var bKeyUsage = parseInt(hKeyUsage.substr(2), 16).toString(2);
1009     return bKeyUsage.substr(0, bKeyUsage.length - unusedBits);
1010 };
1011 
1012 /**
1013  * get KeyUsage extension value as names in the certificate
1014  * @name getExtKeyUsageString
1015  * @memberOf X509
1016  * @function
1017  * @param {String} hCert hexadecimal string of X.509 certificate binary
1018  * @return {String} comma separated string of key usage
1019  * @since x509 1.1.6
1020  * @description
1021  * This method will get key usage extension value
1022  * as comma separated string of usage names.
1023  * If there is no key usage extension in the certificate,
1024  * it returns empty string (i.e. '').
1025  * @example
1026  * sKeyUsage = X509.getExtKeyUsageString(hCert);
1027  * // sKeyUsage will be such like 'digitalSignature,keyEncipherment'.
1028  */
1029 X509.getExtKeyUsageString = function(hCert) {
1030     var bKeyUsage = X509.getExtKeyUsageBin(hCert);
1031     var a = new Array();
1032     for (var i = 0; i < bKeyUsage.length; i++) {
1033 	if (bKeyUsage.substr(i, 1) == "1") a.push(X509.KEYUSAGE_NAME[i]);
1034     }
1035     return a.join(",");
1036 };
1037 
1038 /**
1039  * get subjectKeyIdentifier value as hexadecimal string in the certificate
1040  * @name getExtSubjectKeyIdentifier
1041  * @memberOf X509
1042  * @function
1043  * @param {String} hCert hexadecimal string of X.509 certificate binary
1044  * @return {String} hexadecimal string of subject key identifier or null
1045  * @since jsrsasign 5.0.10 x509 1.1.8
1046  * @description
1047  * This method will get subject key identifier extension value
1048  * as hexadecimal string.
1049  * If there is no its extension in the certificate,
1050  * it returns null.
1051  * @example
1052  * skid = X509.getExtSubjectKeyIdentifier(hCert);
1053  */
1054 X509.getExtSubjectKeyIdentifier = function(hCert) {
1055     var hSKID = X509.getHexOfV_V3ExtValue(hCert, "subjectKeyIdentifier");
1056     return hSKID;
1057 };
1058 
1059 /**
1060  * get authorityKeyIdentifier value as JSON object in the certificate
1061  * @name getExtAuthorityKeyIdentifier
1062  * @memberOf X509
1063  * @function
1064  * @param {String} hCert hexadecimal string of X.509 certificate binary
1065  * @return {Object} JSON object of authority key identifier or null
1066  * @since jsrsasign 5.0.10 x509 1.1.8
1067  * @description
1068  * This method will get authority key identifier extension value
1069  * as JSON object.
1070  * If there is no its extension in the certificate,
1071  * it returns null.
1072  * <br>
1073  * NOTE: Currently this method only supports keyIdentifier so that
1074  * authorityCertIssuer and authorityCertSerialNumber will not
1075  * be return in the JSON object.
1076  * @example
1077  * akid = X509.getExtAuthorityKeyIdentifier(hCert);
1078  * // returns following JSON object
1079  * { kid: "1234abcd..." }
1080  */
1081 X509.getExtAuthorityKeyIdentifier = function(hCert) {
1082     var result = {};
1083     var hAKID = X509.getHexOfTLV_V3ExtValue(hCert, "authorityKeyIdentifier");
1084     if (hAKID === null) return null;
1085 
1086     var a = ASN1HEX.getPosArrayOfChildren_AtObj(hAKID, 0);
1087     for (var i = 0; i < a.length; i++) {
1088 	if (hAKID.substr(a[i], 2) === "80")
1089 	    result.kid = ASN1HEX.getHexOfV_AtObj(hAKID, a[i]);
1090     }
1091 
1092     return result;
1093 };
1094 
1095 /**
1096  * get extKeyUsage value as array of name string in the certificate
1097  * @name getExtExtKeyUsageName
1098  * @memberOf X509
1099  * @function
1100  * @param {String} hCert hexadecimal string of X.509 certificate binary
1101  * @return {Object} array of extended key usage ID name or oid
1102  * @since jsrsasign 5.0.10 x509 1.1.8
1103  * @description
1104  * This method will get extended key usage extension value
1105  * as array of name or OID string.
1106  * If there is no its extension in the certificate,
1107  * it returns null.
1108  * <br>
1109  * NOTE: Supported extended key usage ID names are defined in
1110  * name2oidList parameter in asn1x509.js file.
1111  * @example
1112  * eku = X509.getExtExtKeyUsageName(hCert);
1113  * // returns following array:
1114  * ["serverAuth", "clientAuth", "0.1.2.3.4.5"]
1115  */
1116 X509.getExtExtKeyUsageName = function(hCert) {
1117     var result = new Array();
1118     var h = X509.getHexOfTLV_V3ExtValue(hCert, "extKeyUsage");
1119     if (h === null) return null;
1120 
1121     var a = ASN1HEX.getPosArrayOfChildren_AtObj(h, 0);
1122     for (var i = 0; i < a.length; i++) {
1123 	var hex = ASN1HEX.getHexOfV_AtObj(h, a[i]);
1124 	var oid = KJUR.asn1.ASN1Util.oidHexToInt(hex);
1125 	var name = KJUR.asn1.x509.OID.oid2name(oid);
1126 	result.push(name);
1127     }
1128 
1129     return result;
1130 };
1131 
1132 /**
1133  * get subjectAltName value as array of string in the certificate
1134  * @name getExtSubjectAltName
1135  * @memberOf X509
1136  * @function
1137  * @param {String} hCert hexadecimal string of X.509 certificate binary
1138  * @return {Object} array of alt names
1139  * @since jsrsasign 5.0.10 x509 1.1.8
1140  * @description
1141  * This method will get subject alt name extension value
1142  * as array of name.
1143  * If there is no its extension in the certificate,
1144  * it returns null.
1145  * <br>
1146  * NOTE: Currently this method supports only dNSName so that
1147  * other name type such like iPAddress or generalName will not be returned.
1148  * @example
1149  * san = X509.getExtSubjectAltName(hCert);
1150  * // returns following array:
1151  * ["example.com", "example.org"]
1152  */
1153 X509.getExtSubjectAltName = function(hCert) {
1154     var result = new Array();
1155     var h = X509.getHexOfTLV_V3ExtValue(hCert, "subjectAltName");
1156 
1157     var a = ASN1HEX.getPosArrayOfChildren_AtObj(h, 0);
1158     for (var i = 0; i < a.length; i++) {
1159 	if (h.substr(a[i], 2) === "82") {
1160 	    var fqdn = hextoutf8(ASN1HEX.getHexOfV_AtObj(h, a[i]));
1161 	    result.push(fqdn);
1162 	}
1163     }
1164 
1165     return result;
1166 };
1167 
1168 /**
1169  * get array of string for fullName URIs in cRLDistributionPoints(CDP) in the certificate
1170  * @name getExtCRLDistributionPointsURI
1171  * @memberOf X509
1172  * @function
1173  * @param {String} hCert hexadecimal string of X.509 certificate binary
1174  * @return {Object} array of fullName URIs of CDP of the certificate
1175  * @since jsrsasign 5.0.10 x509 1.1.8
1176  * @description
1177  * This method will get all fullName URIs of cRLDistributionPoints extension
1178  * in the certificate as array of URI string.
1179  * If there is no its extension in the certificate,
1180  * it returns null.
1181  * <br>
1182  * NOTE: Currently this method supports only fullName URI so that
1183  * other parameters will not be returned.
1184  * @example
1185  * cdpuri = X509.getExtCRLDistributionPointsURI(hCert);
1186  * // returns following array:
1187  * ["http://example.com/aaa.crl", "http://example.org/aaa.crl"]
1188  */
1189 X509.getExtCRLDistributionPointsURI = function(hCert) {
1190     var result = new Array();
1191     var h = X509.getHexOfTLV_V3ExtValue(hCert, "cRLDistributionPoints");
1192 
1193     var a = ASN1HEX.getPosArrayOfChildren_AtObj(h, 0);
1194     for (var i = 0; i < a.length; i++) {
1195 	var hDP = ASN1HEX.getHexOfTLV_AtObj(h, a[i]);
1196 
1197 	var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(hDP, 0);
1198 	for (var j = 0; j < a1.length; j++) {
1199 	    if (hDP.substr(a1[j], 2) === "a0") {
1200 		var hDPN = ASN1HEX.getHexOfV_AtObj(hDP, a1[j]);
1201 		if (hDPN.substr(0, 2) === "a0") {
1202 		    var hFullName = ASN1HEX.getHexOfV_AtObj(hDPN, 0);
1203 		    if (hFullName.substr(0, 2) === "86") {
1204 			var hURI = ASN1HEX.getHexOfV_AtObj(hFullName, 0);
1205 			var uri = hextoutf8(hURI);
1206 			result.push(uri);
1207 		    }
1208 		}
1209 	    }
1210 	}
1211     }
1212 
1213     return result;
1214 };
1215 
1216 /**
1217  * get AuthorityInfoAccess extension value in the certificate as associative array
1218  * @name getExtAIAInfo
1219  * @memberOf X509
1220  * @function
1221  * @param {String} hCert hexadecimal string of X.509 certificate binary
1222  * @return {Object} associative array of AIA extension properties
1223  * @since x509 1.1.6
1224  * @description
1225  * This method will get authority info access value
1226  * as associate array which has following properties:
1227  * <ul>
1228  * <li>ocsp - array of string for OCSP responder URL</li>
1229  * <li>caissuer - array of string for caIssuer value (i.e. CA certificates URL)</li>
1230  * </ul>
1231  * If there is no key usage extension in the certificate,
1232  * it returns null;
1233  * @example
1234  * oAIA = X509.getExtAIAInfo(hCert);
1235  * // result will be such like:
1236  * // oAIA.ocsp = ["http://ocsp.foo.com"];
1237  * // oAIA.caissuer = ["http://rep.foo.com/aaa.p8m"];
1238  */
1239 X509.getExtAIAInfo = function(hCert) {
1240     var result = {};
1241     result.ocsp = [];
1242     result.caissuer = [];
1243     var pos1 = X509.getPosOfTLV_V3ExtValue(hCert, "authorityInfoAccess");
1244     if (pos1 == -1) return null;
1245     if (hCert.substr(pos1, 2) != "30") // extnValue SEQUENCE
1246 	throw "malformed AIA Extn Value";
1247 
1248     var posAccDescList = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pos1);
1249     for (var i = 0; i < posAccDescList.length; i++) {
1250 	var p = posAccDescList[i];
1251 	var posAccDescChild = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p);
1252 	if (posAccDescChild.length != 2)
1253 	    throw "malformed AccessDescription of AIA Extn";
1254 	var pOID = posAccDescChild[0];
1255 	var pName = posAccDescChild[1];
1256 	if (ASN1HEX.getHexOfV_AtObj(hCert, pOID) == "2b06010505073001") {
1257 	    if (hCert.substr(pName, 2) == "86") {
1258 		result.ocsp.push(hextoutf8(ASN1HEX.getHexOfV_AtObj(hCert, pName)));
1259 	    }
1260 	}
1261 	if (ASN1HEX.getHexOfV_AtObj(hCert, pOID) == "2b06010505073002") {
1262 	    if (hCert.substr(pName, 2) == "86") {
1263 		result.caissuer.push(hextoutf8(ASN1HEX.getHexOfV_AtObj(hCert, pName)));
1264 	    }
1265 	}
1266     }
1267     return result;
1268 };
1269 
1270 /**
1271  * get signature algorithm name from hexadecimal certificate data
1272  * @name getSignatureAlgorithmName
1273  * @memberOf X509
1274  * @function
1275  * @param {String} hCert hexadecimal string of X.509 certificate binary
1276  * @return {String} signature algorithm name (ex. SHA1withRSA, SHA256withECDSA)
1277  * @since x509 1.1.7
1278  * @description
1279  * This method will get signature algorithm name of certificate:
1280  * @example
1281  * algName = X509.getSignatureAlgorithmName(hCert);
1282  */
1283 X509.getSignatureAlgorithmName = function(hCert) {
1284     var sigAlgOidHex = ASN1HEX.getDecendantHexVByNthList(hCert, 0, [1, 0]);
1285     var sigAlgOidInt = KJUR.asn1.ASN1Util.oidHexToInt(sigAlgOidHex);
1286     var sigAlgName = KJUR.asn1.x509.OID.oid2name(sigAlgOidInt);
1287     return sigAlgName;
1288 };
1289 
1290 /**
1291  * get signature value in hexadecimal string
1292  * @name getSignatureValueHex
1293  * @memberOf X509
1294  * @function
1295  * @param {String} hCert hexadecimal string of X.509 certificate binary
1296  * @return {String} signature value hexadecimal string without BitString unused bits
1297  * @since x509 1.1.7
1298  * @description
1299  * This method will get signature value of certificate:
1300  * @example
1301  * sigHex = X509.getSignatureValueHex(hCert);
1302  */
1303 X509.getSignatureValueHex = function(hCert) {
1304     var h = ASN1HEX.getDecendantHexVByNthList(hCert, 0, [2]);
1305     if (h.substr(0, 2) !== "00")
1306 	throw "can't get signature value";
1307     return h.substr(2);
1308 };
1309 
1310 X509.getSerialNumberHex = function(hCert) {
1311     return ASN1HEX.getDecendantHexVByNthList(hCert, 0, [0, 1]);
1312 };
1313 
1314 /**
1315  * verifies signature value by public key
1316  * @name verifySignature
1317  * @memberOf X509
1318  * @function
1319  * @param {String} hCert hexadecimal string of X.509 certificate binary
1320  * @param {Object} pubKey public key object
1321  * @return {Boolean} true if signature value is valid otherwise false
1322  * @since jsrsasign 7.1.1 x509 1.1.12
1323  * @description
1324  * This method verifies signature value of hexadecimal string of 
1325  * X.509 certificate by specified public key object.
1326  * @example
1327  * pubKey = KEYUTIL.getKey(pemPublicKey); // or certificate
1328  * hCert = ASN1HEX.pemToHex(pemCert);
1329  * isValid = X509.verifySignature(hCert, pubKey);
1330  */
1331 X509.verifySignature = function(hCert, pubKey) {
1332     var algName = X509.getSignatureAlgorithmName(hCert);
1333     var hSigVal = X509.getSignatureValueHex(hCert);
1334     var hTbsCert = ASN1HEX.getDecendantHexTLVByNthList(hCert, 0, [0]);
1335 
1336     var sig = new KJUR.crypto.Signature({alg: algName});
1337     sig.init(pubKey);
1338     sig.updateHex(hTbsCert);
1339     return sig.verify(hSigVal);
1340 };
1341