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