1 /*! x509-1.1.6.js (c) 2012-2015 Kenji Urushima | kjur.github.com/jsrsasign/license
  2  */
  3 /* 
  4  * x509.js - X509 class to read subject public key from certificate.
  5  *
  6  * Copyright (c) 2010-2015 Kenji Urushima (kenji.urushima@gmail.com)
  7  *
  8  * This software is licensed under the terms of the MIT License.
  9  * http://kjur.github.com/jsrsasign/license
 10  *
 11  * The above copyright and license notice shall be 
 12  * included in all copies or substantial portions of the Software.
 13  */
 14 
 15 /**
 16  * @fileOverview
 17  * @name x509-1.1.js
 18  * @author Kenji Urushima kenji.urushima@gmail.com
 19  * @version x509 1.1.6 (2015-May-20)
 20  * @since jsrsasign 1.x.x
 21  * @license <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
 22  */
 23 
 24 /*
 25  * Depends:
 26  *   base64.js
 27  *   rsa.js
 28  *   asn1hex.js
 29  */
 30 
 31 /**
 32  * X.509 certificate class.<br/>
 33  * @class X.509 certificate class
 34  * @property {RSAKey} subjectPublicKeyRSA Tom Wu's RSAKey object
 35  * @property {String} subjectPublicKeyRSA_hN hexadecimal string for modulus of RSA public key
 36  * @property {String} subjectPublicKeyRSA_hE hexadecimal string for public exponent of RSA public key
 37  * @property {String} hex hexacedimal string for X.509 certificate.
 38  * @author Kenji Urushima
 39  * @version 1.0.1 (08 May 2012)
 40  * @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
 41  */
 42 function X509() {
 43     this.subjectPublicKeyRSA = null;
 44     this.subjectPublicKeyRSA_hN = null;
 45     this.subjectPublicKeyRSA_hE = null;
 46     this.hex = null;
 47 
 48     // ===== get basic fields from hex =====================================
 49 
 50     /**
 51      * get hexadecimal string of serialNumber field of certificate.<br/>
 52      * @name getSerialNumberHex
 53      * @memberOf X509#
 54      * @function
 55      */
 56     this.getSerialNumberHex = function() {
 57         return ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 1]);
 58     };
 59 
 60     /**
 61      * get hexadecimal string of issuer field TLV of certificate.<br/>
 62      * @name getIssuerHex
 63      * @memberOf X509#
 64      * @function
 65      */
 66     this.getIssuerHex = function() {
 67         return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]);
 68     };
 69 
 70     /**
 71      * get string of issuer field of certificate.<br/>
 72      * @name getIssuerString
 73      * @memberOf X509#
 74      * @function
 75      */
 76     this.getIssuerString = function() {
 77         return X509.hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]));
 78     };
 79 
 80     /**
 81      * get hexadecimal string of subject field of certificate.<br/>
 82      * @name getSubjectHex
 83      * @memberOf X509#
 84      * @function
 85      */
 86     this.getSubjectHex = function() {
 87         return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]);
 88     };
 89 
 90     /**
 91      * get string of subject field of certificate.<br/>
 92      * @name getSubjectString
 93      * @memberOf X509#
 94      * @function
 95      */
 96     this.getSubjectString = function() {
 97         return X509.hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]));
 98     };
 99 
100     /**
101      * get notBefore field string of certificate.<br/>
102      * @name getNotBefore
103      * @memberOf X509#
104      * @function
105      */
106     this.getNotBefore = function() {
107         var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 0]);
108         s = s.replace(/(..)/g, "%$1");
109         s = decodeURIComponent(s);
110         return s;
111     };
112 
113     /**
114      * get notAfter field string of certificate.<br/>
115      * @name getNotAfter
116      * @memberOf X509#
117      * @function
118      */
119     this.getNotAfter = function() {
120         var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 1]);
121         s = s.replace(/(..)/g, "%$1");
122         s = decodeURIComponent(s);
123         return s;
124     };
125 
126     // ===== read certificate public key ==========================
127 
128     // ===== read certificate =====================================
129     /**
130      * read PEM formatted X.509 certificate from string.<br/>
131      * @name readCertPEM
132      * @memberOf X509#
133      * @function
134      * @param {String} sCertPEM string for PEM formatted X.509 certificate
135      */
136     this.readCertPEM = function(sCertPEM) {
137         var hCert = X509.pemToHex(sCertPEM);
138         var a = X509.getPublicKeyHexArrayFromCertHex(hCert);
139         var rsa = new RSAKey();
140         rsa.setPublic(a[0], a[1]);
141         this.subjectPublicKeyRSA = rsa;
142         this.subjectPublicKeyRSA_hN = a[0];
143         this.subjectPublicKeyRSA_hE = a[1];
144         this.hex = hCert;
145     };
146 
147     this.readCertPEMWithoutRSAInit = function(sCertPEM) {
148         var hCert = X509.pemToHex(sCertPEM);
149         var a = X509.getPublicKeyHexArrayFromCertHex(hCert);
150         this.subjectPublicKeyRSA.setPublic(a[0], a[1]);
151         this.subjectPublicKeyRSA_hN = a[0];
152         this.subjectPublicKeyRSA_hE = a[1];
153         this.hex = hCert;
154     };
155 };
156 
157 X509.pemToBase64 = function(sCertPEM) {
158     var s = sCertPEM;
159     s = s.replace("-----BEGIN CERTIFICATE-----", "");
160     s = s.replace("-----END CERTIFICATE-----", "");
161     s = s.replace(/[ \n]+/g, "");
162     return s;
163 };
164 
165 X509.pemToHex = function(sCertPEM) {
166     var b64Cert = X509.pemToBase64(sCertPEM);
167     var hCert = b64tohex(b64Cert);
168     return hCert;
169 };
170 
171 // NOTE: Without BITSTRING encapsulation.
172 X509.getSubjectPublicKeyPosFromCertHex = function(hCert) {
173     var pInfo = X509.getSubjectPublicKeyInfoPosFromCertHex(hCert);
174     if (pInfo == -1) return -1;    
175     var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pInfo); 
176     if (a.length != 2) return -1;
177     var pBitString = a[1];
178     if (hCert.substring(pBitString, pBitString + 2) != '03') return -1;
179     var pBitStringV = ASN1HEX.getStartPosOfV_AtObj(hCert, pBitString);
180     
181     if (hCert.substring(pBitStringV, pBitStringV + 2) != '00') return -1;
182     return pBitStringV + 2;
183 };
184 
185 // NOTE: privateKeyUsagePeriod field of X509v2 not supported.
186 // NOTE: v1 and v3 supported
187 X509.getSubjectPublicKeyInfoPosFromCertHex = function(hCert) {
188     var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
189     var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pTbsCert); 
190     if (a.length < 1) return -1;
191     if (hCert.substring(a[0], a[0] + 10) == "a003020102") { // v3
192         if (a.length < 6) return -1;
193         return a[6];
194     } else {
195         if (a.length < 5) return -1;
196         return a[5];
197     }
198 };
199 
200 X509.getPublicKeyHexArrayFromCertHex = function(hCert) {
201     var p = X509.getSubjectPublicKeyPosFromCertHex(hCert);
202     var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p); 
203     if (a.length != 2) return [];
204     var hN = ASN1HEX.getHexOfV_AtObj(hCert, a[0]);
205     var hE = ASN1HEX.getHexOfV_AtObj(hCert, a[1]);
206     if (hN != null && hE != null) {
207         return [hN, hE];
208     } else {
209         return [];
210     }
211 };
212 
213 X509.getHexTbsCertificateFromCert = function(hCert) {
214     var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0);
215     return pTbsCert;
216 };
217 
218 X509.getPublicKeyHexArrayFromCertPEM = function(sCertPEM) {
219     var hCert = X509.pemToHex(sCertPEM);
220     var a = X509.getPublicKeyHexArrayFromCertHex(hCert);
221     return a;
222 };
223 
224 X509.hex2dn = function(hDN) {
225     var s = "";
226     var a = ASN1HEX.getPosArrayOfChildren_AtObj(hDN, 0);
227     for (var i = 0; i < a.length; i++) {
228         var hRDN = ASN1HEX.getHexOfTLV_AtObj(hDN, a[i]);
229         s = s + "/" + X509.hex2rdn(hRDN);
230     }
231     return s;
232 };
233 
234 X509.hex2rdn = function(hRDN) {
235     var hType = ASN1HEX.getDecendantHexTLVByNthList(hRDN, 0, [0, 0]);
236     var hValue = ASN1HEX.getDecendantHexVByNthList(hRDN, 0, [0, 1]);
237     var type = "";
238     try { type = X509.DN_ATTRHEX[hType]; } catch (ex) { type = hType; }
239     hValue = hValue.replace(/(..)/g, "%$1");
240     var value = decodeURIComponent(hValue);
241     return type + "=" + value;
242 };
243 
244 X509.DN_ATTRHEX = {
245     "0603550406": "C",
246     "060355040a": "O",
247     "060355040b": "OU",
248     "0603550403": "CN",
249     "0603550405": "SN",
250     "0603550408": "ST",
251     "0603550407": "L",
252 };
253 
254 /**
255  * get RSAKey/ECDSA public key object from PEM certificate string
256  * @name getPublicKeyFromCertPEM
257  * @memberOf X509
258  * @function
259  * @param {String} sCertPEM PEM formatted RSA/ECDSA/DSA X.509 certificate
260  * @return returns RSAKey/KJUR.crypto.{ECDSA,DSA} object of public key
261  * @since x509 1.1.1
262  * @description
263  * NOTE: DSA is also supported since x509 1.1.2.
264  */
265 X509.getPublicKeyFromCertPEM = function(sCertPEM) {
266     var info = X509.getPublicKeyInfoPropOfCertPEM(sCertPEM);
267 
268     if (info.algoid == "2a864886f70d010101") { // RSA
269         var aRSA = KEYUTIL.parsePublicRawRSAKeyHex(info.keyhex);
270         var key = new RSAKey();
271         key.setPublic(aRSA.n, aRSA.e);
272         return key;
273     } else if (info.algoid == "2a8648ce3d0201") { // ECC
274         var curveName = KJUR.crypto.OID.oidhex2name[info.algparam];
275         var key = new KJUR.crypto.ECDSA({'curve': curveName, 'info': info.keyhex});
276         key.setPublicKeyHex(info.keyhex);
277         return key;
278     } else if (info.algoid == "2a8648ce380401") { // DSA 1.2.840.10040.4.1
279         var p = ASN1HEX.getVbyList(info.algparam, 0, [0], "02");
280         var q = ASN1HEX.getVbyList(info.algparam, 0, [1], "02");
281         var g = ASN1HEX.getVbyList(info.algparam, 0, [2], "02");
282         var y = ASN1HEX.getHexOfV_AtObj(info.keyhex, 0);
283         y = y.substr(2);
284         var key = new KJUR.crypto.DSA();
285         key.setPublic(new BigInteger(p, 16),
286                       new BigInteger(q, 16),
287                       new BigInteger(g, 16),
288                       new BigInteger(y, 16));
289         return key;
290     } else {
291         throw "unsupported key";
292     }
293 };
294 
295 /**
296  * get public key information from PEM certificate
297  * @name getPublicKeyInfoPropOfCertPEM
298  * @memberOf X509
299  * @function
300  * @param {String} sCertPEM string of PEM formatted certificate
301  * @return {Hash} hash of information for public key
302  * @since x509 1.1.1
303  * @description
304  * Resulted associative array has following properties:
305  * <ul>
306  * <li>algoid - hexadecimal string of OID of asymmetric key algorithm</li>
307  * <li>algparam - hexadecimal string of OID of ECC curve name or null</li>
308  * <li>keyhex - hexadecimal string of key in the certificate</li>
309  * </ul>
310  * @since x509 1.1.1
311  */
312 X509.getPublicKeyInfoPropOfCertPEM = function(sCertPEM) {
313     var result = {};
314     result.algparam = null;
315     var hCert = X509.pemToHex(sCertPEM);
316 
317     // 1. Certificate ASN.1
318     var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, 0); 
319     if (a1.length != 3)
320         throw "malformed X.509 certificate PEM (code:001)"; // not 3 item of seq Cert
321 
322     // 2. tbsCertificate
323     if (hCert.substr(a1[0], 2) != "30")
324         throw "malformed X.509 certificate PEM (code:002)"; // tbsCert not seq 
325 
326     var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a1[0]); 
327 
328     // 3. subjectPublicKeyInfo
329     if (a2.length < 7)
330         throw "malformed X.509 certificate PEM (code:003)"; // no subjPubKeyInfo
331 
332     var a3 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a2[6]); 
333 
334     if (a3.length != 2)
335         throw "malformed X.509 certificate PEM (code:004)"; // not AlgId and PubKey
336 
337     // 4. AlgId
338     var a4 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a3[0]); 
339 
340     if (a4.length != 2)
341         throw "malformed X.509 certificate PEM (code:005)"; // not 2 item in AlgId
342 
343     result.algoid = ASN1HEX.getHexOfV_AtObj(hCert, a4[0]);
344 
345     if (hCert.substr(a4[1], 2) == "06") { // EC
346         result.algparam = ASN1HEX.getHexOfV_AtObj(hCert, a4[1]);
347     } else if (hCert.substr(a4[1], 2) == "30") { // DSA
348         result.algparam = ASN1HEX.getHexOfTLV_AtObj(hCert, a4[1]);
349     }
350 
351     // 5. Public Key Hex
352     if (hCert.substr(a3[1], 2) != "03")
353         throw "malformed X.509 certificate PEM (code:006)"; // not bitstring
354 
355     var unusedBitAndKeyHex = ASN1HEX.getHexOfV_AtObj(hCert, a3[1]);
356     result.keyhex = unusedBitAndKeyHex.substr(2);
357 
358     return result;
359 };
360 
361 /**
362  * get position of subjectPublicKeyInfo field from HEX certificate
363  * @name getPublicKeyInfoPosOfCertHEX
364  * @memberOf X509
365  * @function
366  * @param {String} hCert hexadecimal string of certificate
367  * @return {Integer} position in hexadecimal string
368  * @since x509 1.1.4
369  * @description
370  * get position for SubjectPublicKeyInfo field in the hexadecimal string of
371  * certificate.
372  */
373 X509.getPublicKeyInfoPosOfCertHEX = function(hCert) {
374     // 1. Certificate ASN.1
375     var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, 0); 
376     if (a1.length != 3)
377         throw "malformed X.509 certificate PEM (code:001)"; // not 3 item of seq Cert
378 
379     // 2. tbsCertificate
380     if (hCert.substr(a1[0], 2) != "30")
381         throw "malformed X.509 certificate PEM (code:002)"; // tbsCert not seq 
382 
383     var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a1[0]); 
384 
385     // 3. subjectPublicKeyInfo
386     if (a2.length < 7)
387         throw "malformed X.509 certificate PEM (code:003)"; // no subjPubKeyInfo
388     
389     return a2[6];
390 };
391 
392 /**
393  * get array of X.509 V3 extension value information in hex string of certificate
394  * @name getV3ExtInfoListOfCertHex
395  * @memberOf X509
396  * @function
397  * @param {String} hCert hexadecimal string of X.509 certificate binary
398  * @return {Array} array of result object by {@link X509.getV3ExtInfoListOfCertHex}
399  * @since x509 1.1.5
400  * @description
401  * This method will get all extension information of a X.509 certificate.
402  * Items of resulting array has following properties:
403  * <ul>
404  * <li>posTLV - index of ASN.1 TLV for the extension. same as 'pos' argument.</li>
405  * <li>oid - dot noted string of extension oid (ex. 2.5.29.14)</li>
406  * <li>critical - critical flag value for this extension</li>
407  * <li>posV - index of ASN.1 TLV for the extension value.
408  * This is a position of a content of ENCAPSULATED OCTET STRING.</li>
409  * </ul>
410  * @example
411  * hCert = X509.pemToHex(certGithubPEM);
412  * a = X509.getV3ExtInfoListOfCertHex(hCert);
413  * // Then a will be an array of like following:
414  * [{posTLV: 1952, oid: "2.5.29.35", critical: false, posV: 1968},
415  *  {posTLV: 1974, oid: "2.5.29.19", critical: true, posV: 1986}, ...]
416  */
417 X509.getV3ExtInfoListOfCertHex = function(hCert) {
418     // 1. Certificate ASN.1
419     var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, 0); 
420     if (a1.length != 3)
421         throw "malformed X.509 certificate PEM (code:001)"; // not 3 item of seq Cert
422 
423     // 2. tbsCertificate
424     if (hCert.substr(a1[0], 2) != "30")
425         throw "malformed X.509 certificate PEM (code:002)"; // tbsCert not seq 
426 
427     var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a1[0]); 
428 
429     // 3. v3Extension EXPLICIT Tag [3]
430     // ver, seri, alg, iss, validity, subj, spki, (iui,) (sui,) ext
431     if (a2.length < 8)
432         throw "malformed X.509 certificate PEM (code:003)"; // tbsCert num field too short
433 
434     if (hCert.substr(a2[7], 2) != "a3")
435         throw "malformed X.509 certificate PEM (code:004)"; // not [3] tag
436 
437     var a3 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a2[7]);
438     if (a3.length != 1)
439         throw "malformed X.509 certificate PEM (code:005)"; // [3]tag numChild!=1
440 
441     // 4. v3Extension SEQUENCE
442     if (hCert.substr(a3[0], 2) != "30")
443         throw "malformed X.509 certificate PEM (code:006)"; // not SEQ
444 
445     var a4 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a3[0]);
446 
447     // 5. v3Extension item position
448     var numExt = a4.length;
449     var aInfo = new Array(numExt);
450     for (var i = 0; i < numExt; i++) {
451 	aInfo[i] = X509.getV3ExtItemInfo_AtObj(hCert, a4[i]);
452     }
453     return aInfo;
454 };
455 
456 /**
457  * get X.509 V3 extension value information at the specified position
458  * @name getV3ExtItemInfo_AtObj
459  * @memberOf X509
460  * @function
461  * @param {String} hCert hexadecimal string of X.509 certificate binary
462  * @param {Integer} pos index of hexadecimal string for the extension
463  * @return {Object} properties for the extension
464  * @since x509 1.1.5
465  * @description
466  * This method will get some information of a X.509 V extension 
467  * which is referred by an index of hexadecimal string of X.509 
468  * certificate. 
469  * Resulting object has following properties:
470  * <ul>
471  * <li>posTLV - index of ASN.1 TLV for the extension. same as 'pos' argument.</li>
472  * <li>oid - dot noted string of extension oid (ex. 2.5.29.14)</li>
473  * <li>critical - critical flag value for this extension</li>
474  * <li>posV - index of ASN.1 TLV for the extension value.
475  * This is a position of a content of ENCAPSULATED OCTET STRING.</li>
476  * </ul>
477  * This method is used by {@link X509.getV3ExtInfoListOfCertHex} internally.
478  */
479 X509.getV3ExtItemInfo_AtObj = function(hCert, pos) {
480     var info = {};
481 
482     // posTLV - extension TLV
483     info.posTLV = pos;
484 
485     var a  = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pos);
486     if (a.length != 2 && a.length != 3)
487         throw "malformed X.509v3 Ext (code:001)"; // oid,(critical,)val
488 
489     // oid - extension OID
490     if (hCert.substr(a[0], 2) != "06")
491         throw "malformed X.509v3 Ext (code:002)"; // not OID "06"
492     var valueHex = ASN1HEX.getHexOfV_AtObj(hCert, a[0]);
493     info.oid = ASN1HEX.hextooidstr(valueHex); 
494 
495     // critical - extension critical flag
496     info.critical = false; // critical false by default
497     if (a.length == 3) info.critical = true;
498 
499     // posV - content TLV position of encapsulated
500     //        octet string of V3 extension value.
501     var posExtV = a[a.length - 1];
502     if (hCert.substr(posExtV, 2) != "04")
503         throw "malformed X.509v3 Ext (code:003)"; // not EncapOctet "04"
504     info.posV = ASN1HEX.getStartPosOfV_AtObj(hCert, posExtV);
505     
506     return info;
507 };
508 
509 /**
510  * get X.509 V3 extension value ASN.1 TLV for specified oid or name
511  * @name getHexOfTLV_V3ExtValue
512  * @memberOf X509
513  * @function
514  * @param {String} hCert hexadecimal string of X.509 certificate binary
515  * @param {String} oidOrName oid or name for extension (ex. 'keyUsage' or '2.5.29.15')
516  * @return {String} hexadecimal string of extension ASN.1 TLV
517  * @since x509 1.1.6
518  * @description
519  * This method will get X.509v3 extension value of ASN.1 TLV
520  * which is specifyed by extension name or oid. 
521  * @example
522  * hExtValue = X509.getHexOfTLV_V3ExtValue(hCert, "keyUsage");
523  * // hExtValue will be such like '030205a0'.
524  */
525 X509.getHexOfTLV_V3ExtValue = function(hCert, oidOrName) {
526     var pos = X509.getPosOfTLV_V3ExtValue(hCert, oidOrName);
527     if (pos == -1) return '';
528     return ASN1HEX.getHexOfTLV_AtObj(hCert, pos);
529 };
530 
531 /**
532  * get X.509 V3 extension value ASN.1 V for specified oid or name
533  * @name getHexOfV_V3ExtValue
534  * @memberOf X509
535  * @function
536  * @param {String} hCert hexadecimal string of X.509 certificate binary
537  * @param {String} oidOrName oid or name for extension (ex. 'keyUsage' or '2.5.29.15')
538  * @return {String} hexadecimal string of extension ASN.1 TLV
539  * @since x509 1.1.6
540  * @description
541  * This method will get X.509v3 extension value of ASN.1 value
542  * which is specifyed by extension name or oid. 
543  * If there is no such extension in the certificate,
544  * it returns empty string (i.e. '').
545  * Available extension names and oids are defined
546  * in the {@link KJUR.asn1.x509.OID} class.
547  * @example
548  * hExtValue = X509.getHexOfV_V3ExtValue(hCert, "keyUsage");
549  * // hExtValue will be such like '05a0'.
550  */
551 X509.getHexOfV_V3ExtValue = function(hCert, oidOrName) {
552     var pos = X509.getPosOfTLV_V3ExtValue(hCert, oidOrName);
553     if (pos == -1) return '';
554     return ASN1HEX.getHexOfV_AtObj(hCert, pos);
555 };
556 
557 /**
558  * get index in the certificate hexa string for specified oid or name specified extension
559  * @name getPosOfTLV_V3ExtValue
560  * @memberOf X509
561  * @function
562  * @param {String} hCert hexadecimal string of X.509 certificate binary
563  * @param {String} oidOrName oid or name for extension (ex. 'keyUsage' or '2.5.29.15')
564  * @return {Integer} index in the hexadecimal string of certficate for specified extension
565  * @since x509 1.1.6
566  * @description
567  * This method will get X.509v3 extension value of ASN.1 V(value)
568  * which is specifyed by extension name or oid. 
569  * If there is no such extension in the certificate,
570  * it returns empty string (i.e. '').
571  * Available extension names and oids are defined
572  * in the {@link KJUR.asn1.x509.OID} class.
573  * @example
574  * idx = X509.getPosOfV_V3ExtValue(hCert, "keyUsage");
575  * // The 'idx' will be index in the string for keyUsage value ASN.1 TLV.
576  */
577 X509.getPosOfTLV_V3ExtValue = function(hCert, oidOrName) {
578     var oid = oidOrName;
579     if (! oidOrName.match(/^[0-9.]+$/)) oid = KJUR.asn1.x509.OID.name2oid(oidOrName);
580     if (oid == '') return -1;
581 
582     var infoList = X509.getV3ExtInfoListOfCertHex(hCert);
583     for (var i = 0; i < infoList.length; i++) {
584 	var info = infoList[i];
585 	if (info.oid == oid) return info.posV;
586     }
587     return -1;
588 };
589 
590 X509.KEYUSAGE_NAME = [
591     "digitalSignature",
592     "nonRepudiation",
593     "keyEncipherment",
594     "dataEncipherment",
595     "keyAgreement",
596     "keyCertSign",
597     "cRLSign",
598     "encipherOnly",
599     "decipherOnly"
600 ];
601 
602 /**
603  * get KeyUsage extension value as binary string in the certificate
604  * @name getExtKeyUsageBin
605  * @memberOf X509
606  * @function
607  * @param {String} hCert hexadecimal string of X.509 certificate binary
608  * @return {String} binary string of key usage bits (ex. '101')
609  * @since x509 1.1.6
610  * @description
611  * This method will get key usage extension value
612  * as binary string such like '101'.
613  * Key usage bits definition is in the RFC 5280.
614  * If there is no key usage extension in the certificate,
615  * it returns empty string (i.e. '').
616  * @example
617  * bKeyUsage = X509.getExtKeyUsageBin(hCert);
618  * // bKeyUsage will be such like '101'.
619  * // 1 - digitalSignature 
620  * // 0 - nonRepudiation
621  * // 1 - keyEncipherment
622  */
623 X509.getExtKeyUsageBin = function(hCert) {
624     var hKeyUsage = X509.getHexOfV_V3ExtValue(hCert, "keyUsage");
625     if (hKeyUsage == '') return '';
626     if (hKeyUsage.length % 2 != 0 || hKeyUsage.length <= 2)
627 	throw "malformed key usage value";
628     var unusedBits = parseInt(hKeyUsage.substr(0, 2));
629     var bKeyUsage = parseInt(hKeyUsage.substr(2), 16).toString(2);
630     return bKeyUsage.substr(0, bKeyUsage.length - unusedBits);
631 };
632 
633 /**
634  * get KeyUsage extension value as names in the certificate
635  * @name getExtKeyUsageString
636  * @memberOf X509
637  * @function
638  * @param {String} hCert hexadecimal string of X.509 certificate binary
639  * @return {String} comma separated string of key usage
640  * @since x509 1.1.6
641  * @description
642  * This method will get key usage extension value
643  * as comma separated string of usage names.
644  * If there is no key usage extension in the certificate,
645  * it returns empty string (i.e. '').
646  * @example
647  * sKeyUsage = X509.getExtKeyUsageString(hCert);
648  * // sKeyUsage will be such like 'digitalSignature,keyEncipherment'.
649  */
650 X509.getExtKeyUsageString = function(hCert) {
651     var bKeyUsage = X509.getExtKeyUsageBin(hCert);
652     var a = new Array();
653     for (var i = 0; i < bKeyUsage.length; i++) {
654 	if (bKeyUsage.substr(i, 1) == "1") a.push(X509.KEYUSAGE_NAME[i]);
655     }
656     return a.join(",");
657 };
658 
659 /**
660  * get AuthorityInfoAccess extension value in the certificate as associative array
661  * @name getExtAIAInfo
662  * @memberOf X509
663  * @function
664  * @param {String} hCert hexadecimal string of X.509 certificate binary
665  * @return {Object} associative array of AIA extension properties
666  * @since x509 1.1.6
667  * @description
668  * This method will get authority info access value
669  * as associate array which has following properties:
670  * <ul>
671  * <li>ocsp - array of string for OCSP responder URL</li>
672  * <li>caissuer - array of string for caIssuer value (i.e. CA certificates URL)</li>
673  * </ul>
674  * If there is no key usage extension in the certificate,
675  * it returns null;
676  * @example
677  * oAIA = X509.getExtAIAInfo(hCert);
678  * // result will be such like:
679  * // oAIA.ocsp = ["http://ocsp.foo.com"];
680  * // oAIA.caissuer = ["http://rep.foo.com/aaa.p8m"];
681  */
682 X509.getExtAIAInfo = function(hCert) {
683     var result = {};
684     result.ocsp = [];
685     result.caissuer = [];
686     var pos1 = X509.getPosOfTLV_V3ExtValue(hCert, "authorityInfoAccess");
687     if (pos1 == -1) return null;
688     if (hCert.substr(pos1, 2) != "30") // extnValue SEQUENCE
689 	throw "malformed AIA Extn Value";
690     
691     var posAccDescList = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pos1);
692     for (var i = 0; i < posAccDescList.length; i++) {
693 	var p = posAccDescList[i];
694 	var posAccDescChild = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p);
695 	if (posAccDescChild.length != 2)
696 	    throw "malformed AccessDescription of AIA Extn";
697 	var pOID = posAccDescChild[0];
698 	var pName = posAccDescChild[1];
699 	if (ASN1HEX.getHexOfV_AtObj(hCert, pOID) == "2b06010505073001") {
700 	    if (hCert.substr(pName, 2) == "86") {
701 		result.ocsp.push(hextoutf8(ASN1HEX.getHexOfV_AtObj(hCert, pName)));
702 	    }
703 	}
704 	if (ASN1HEX.getHexOfV_AtObj(hCert, pOID) == "2b06010505073002") {
705 	    if (hCert.substr(pName, 2) == "86") {
706 		result.caissuer.push(hextoutf8(ASN1HEX.getHexOfV_AtObj(hCert, pName)));
707 	    }
708 	}
709     }
710     return result;
711 };
712 
713 /*
714   X509.prototype.readCertPEM = _x509_readCertPEM;
715   X509.prototype.readCertPEMWithoutRSAInit = _x509_readCertPEMWithoutRSAInit;
716   X509.prototype.getSerialNumberHex = _x509_getSerialNumberHex;
717   X509.prototype.getIssuerHex = _x509_getIssuerHex;
718   X509.prototype.getSubjectHex = _x509_getSubjectHex;
719   X509.prototype.getIssuerString = _x509_getIssuerString;
720   X509.prototype.getSubjectString = _x509_getSubjectString;
721   X509.prototype.getNotBefore = _x509_getNotBefore;
722   X509.prototype.getNotAfter = _x509_getNotAfter;
723 */
724