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