1 /* asn1hex-1.2.15.js (c) 2012-2022 Kenji Urushima | kjur.github.io/jsrsasign/license
  2  */
  3 /*
  4  * asn1hex.js - Hexadecimal represented ASN.1 string library
  5  *
  6  * Copyright (c) 2010-2022 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 asn1hex-1.1.js
 18  * @author Kenji Urushima kenji.urushima@gmail.com
 19  * @version jsrsasign 10.5.23 asn1hex 1.2.15 (2022-May-27)
 20  * @license <a href="https://kjur.github.io/jsrsasign/license/">MIT License</a>
 21  */
 22 
 23 /*
 24  * MEMO:
 25  *   f('3082025b02...', 2) ... 82025b ... 3bytes
 26  *   f('020100', 2) ... 01 ... 1byte
 27  *   f('0203001...', 2) ... 03 ... 1byte
 28  *   f('02818003...', 2) ... 8180 ... 2bytes
 29  *   f('3080....0000', 2) ... 80 ... -1
 30  *
 31  *   Requirements:
 32  *   - ASN.1 type octet length MUST be 1. 
 33  *     (i.e. ASN.1 primitives like SET, SEQUENCE, INTEGER, OCTETSTRING ...)
 34  */
 35 
 36 /**
 37  * ASN.1 DER encoded hexadecimal string utility class
 38  * @name ASN1HEX
 39  * @class ASN.1 DER encoded hexadecimal string utility class
 40  * @since jsrsasign 1.1
 41  * @description
 42  * This class provides a parser for hexadecimal string of
 43  * DER encoded ASN.1 binary data.
 44  * Here are major methods of this class.
 45  * <ul>
 46  * <li><b>ACCESS BY POSITION</b>
 47  *   <ul>
 48  *   <li>{@link ASN1HEX.getTLV} - get ASN.1 TLV at specified position</li>
 49  *   <li>{@link ASN1HEX.getTLVblen} - get byte length of ASN.1 TLV at specified position</li>
 50  *   <li>{@link ASN1HEX.getV} - get ASN.1 V at specified position</li>
 51  *   <li>{@link ASN1HEX.getVblen} - get integer ASN.1 L at specified position</li>
 52  *   <li>{@link ASN1HEX.getVidx} - get ASN.1 V position from its ASN.1 TLV position</li>
 53  *   <li>{@link ASN1HEX.getL} - get hexadecimal ASN.1 L at specified position</li>
 54  *   <li>{@link ASN1HEX.getLblen} - get byte length for ASN.1 L(length) bytes</li>
 55  *   </ul>
 56  * </li>
 57  * <li><b>ACCESS FOR CHILD ITEM</b>
 58  *   <ul>
 59  *   <li>{@link ASN1HEX.getNthChildIdx} - get nth child index at specified position</li>
 60  *   <li>{@link ASN1HEX.getChildIdx} - get indexes of children</li>
 61  *   <li>{@link ASN1HEX.getNextSiblingIdx} - get position of next sibling (DEPRECATED)</li>
 62  *   </ul>
 63  * </li>
 64  * <li><b>ACCESS NESTED ASN.1 STRUCTURE</b>
 65  *   <ul>
 66  *   <li>{@link ASN1HEX.getTLVbyList} - get ASN.1 TLV at specified list index</li>
 67  *   <li>{@link ASN1HEX.getVbyList} - get ASN.1 V at specified nth list index with checking expected tag</li>
 68  *   <li>{@link ASN1HEX.getIdxbyList} - get index at specified list index</li>
 69  *   </ul>
 70  * </li>
 71  * <li><b>(NEW)ACCESS NESTED ASN.1 STRUCTURE</b>
 72  *   <ul>
 73  *   <li>{@link ASN1HEX.getTLVbyListEx} - get ASN.1 TLV at specified list index</li>
 74  *   <li>{@link ASN1HEX.getVbyListEx} - get ASN.1 V at specified nth list index with checking expected tag</li>
 75  *   <li>{@link ASN1HEX.getIdxbyListEx} - get index at specified list index</li>
 76  *   </ul>
 77  * </li>
 78  * <li><b>UTILITIES</b>
 79  *   <ul>
 80  *   <li>{@link ASN1HEX.dump} - dump ASN.1 structure</li>
 81  *   <li>{@link ASN1HEX.isContextTag} - check if a hexadecimal tag is a specified ASN.1 context specific tag</li>
 82  *   <li>{@link ASN1HEX.isASN1HEX} - simple ASN.1 DER hexadecimal string checker</li>
 83  *   <li>{@link ASN1HEX.checkStrictDER} - strict ASN.1 DER hexadecimal string checker</li>
 84  *   <li>{@link ASN1HEX.hextooidstr} - convert hexadecimal string of OID to dotted integer list</li>
 85  *   </ul>
 86  * </li>
 87  * </ul>
 88  */
 89 var ASN1HEX = new function() {
 90 };
 91 
 92 /**
 93  * get byte length for ASN.1 L(length) bytes<br/>
 94  * @name getLblen
 95  * @memberOf ASN1HEX
 96  * @function
 97  * @param {String} s hexadecimal string of ASN.1 DER encoded data
 98  * @param {Number} idx string index
 99  * @return byte length for ASN.1 L(length) bytes
100  * @since jsrsasign 7.2.0 asn1hex 1.1.11
101  * @example
102  * ASN1HEX.getLblen('020100', 0) → 1 for '01'
103  * ASN1HEX.getLblen('020200', 0) → 1 for '02'
104  * ASN1HEX.getLblen('02818003...', 0) → 2 for '8180'
105  * ASN1HEX.getLblen('0282025b03...', 0) → 3 for '82025b'
106  * ASN1HEX.getLblen('0280020100...', 0) → -1 for '80' BER indefinite length
107  * ASN1HEX.getLblen('02ffab...', 0) → -2 for malformed ASN.1 length
108  */
109 ASN1HEX.getLblen = function(s, idx) {
110     if (s.substr(idx + 2, 1) != '8') return 1;
111     var i = parseInt(s.substr(idx + 3, 1));
112     if (i == 0) return -1;             // length octet '80' indefinite length
113     if (0 < i && i < 10) return i + 1; // including '8?' octet;
114     return -2;                         // malformed format
115 };
116 
117 /**
118  * get hexadecimal string for ASN.1 L(length) bytes<br/>
119  * @name getL
120  * @memberOf ASN1HEX
121  * @function
122  * @param {String} s hexadecimal string of ASN.1 DER encoded data
123  * @param {Number} idx string index to get L of ASN.1 object
124  * @return {String} hexadecimal string for ASN.1 L(length) bytes
125  * @since jsrsasign 7.2.0 asn1hex 1.1.11
126  */
127 ASN1HEX.getL = function(s, idx) {
128     var len = ASN1HEX.getLblen(s, idx);
129     if (len < 1) return '';
130     return s.substr(idx + 2, len * 2);
131 };
132 
133 /**
134  * get integer value of ASN.1 length for ASN.1 data<br/>
135  * @name getVblen
136  * @memberOf ASN1HEX
137  * @function
138  * @param {String} s hexadecimal string of ASN.1 DER encoded data
139  * @param {Number} idx string index
140  * @return {Number} ASN.1 L(length) integer value
141  * @since jsrsasign 7.2.0 asn1hex 1.1.11
142  */
143 /*
144  getting ASN.1 length value at the position 'idx' of
145  hexa decimal string 's'.
146  f('3082025b02...', 0) ... 82025b ... ???
147  f('020100', 0) ... 01 ... 1
148  f('0203001...', 0) ... 03 ... 3
149  f('02818003...', 0) ... 8180 ... 128
150  */
151 ASN1HEX.getVblen = function(s, idx) {
152     var hLen, bi;
153     hLen = ASN1HEX.getL(s, idx);
154     if (hLen == '') return -1;
155     if (hLen.substr(0, 1) === '8') {
156         bi = new BigInteger(hLen.substr(2), 16);
157     } else {
158         bi = new BigInteger(hLen, 16);
159     }
160     return bi.intValue();
161 };
162 
163 /**
164  * get ASN.1 value starting string position for ASN.1 object refered by index 'idx'.
165  * @name getVidx
166  * @memberOf ASN1HEX
167  * @function
168  * @param {String} s hexadecimal string of ASN.1 DER encoded data
169  * @param {Number} idx string index
170  * @since jsrsasign 7.2.0 asn1hex 1.1.11
171  */
172 ASN1HEX.getVidx = function(s, idx) {
173     var l_len = ASN1HEX.getLblen(s, idx);
174     if (l_len < 0) return l_len;
175     return idx + (l_len + 1) * 2;
176 };
177 
178 /**
179  * get hexadecimal string of ASN.1 V(value)<br/>
180  * @name getV
181  * @memberOf ASN1HEX
182  * @function
183  * @param {String} s hexadecimal string of ASN.1 DER encoded data
184  * @param {Number} idx string index
185  * @return {String} hexadecimal string of ASN.1 value.
186  * @since jsrsasign 7.2.0 asn1hex 1.1.11
187  */
188 ASN1HEX.getV = function(s, idx) {
189     var idx1 = ASN1HEX.getVidx(s, idx);
190     var blen = ASN1HEX.getVblen(s, idx);
191     return s.substr(idx1, blen * 2);
192 };
193 
194 /**
195  * get hexadecimal string of ASN.1 TLV at<br/>
196  * @name getTLV
197  * @memberOf ASN1HEX
198  * @function
199  * @param {String} s hexadecimal string of ASN.1 DER encoded data
200  * @param {Number} idx string index
201  * @return {String} hexadecimal string of ASN.1 TLV.
202  * @since jsrsasign 7.2.0 asn1hex 1.1.11
203  */
204 ASN1HEX.getTLV = function(s, idx) {
205     return s.substr(idx, 2) + ASN1HEX.getL(s, idx) + ASN1HEX.getV(s, idx);
206 };
207 
208 /**
209  * get byte length of ASN.1 TLV at specified string index<br/>
210  * @name getTLVblen
211  * @memberOf ASN1HEX
212  * @function
213  * @param {String} h hexadecimal string of ASN.1 DER encoded data
214  * @param {Number} idx string index to get ASN.1 TLV byte length
215  * @return {Number} byte length of ASN.1 TLV
216  * @since jsrsasign 9.1.5 asn1hex 1.1.11
217  *
218  * @description
219  * This method returns a byte length of ASN.1 TLV at
220  * specified string index.
221  *
222  * @example
223  *                        v string indx=42
224  * ASN1HEX.getTLVblen("...1303616161...", 42) → 10 (PrintableString 'aaa')
225  */
226 ASN1HEX.getTLVblen = function(h, idx) {
227     return 2 + ASN1HEX.getLblen(h, idx) * 2 + ASN1HEX.getVblen(h, idx) * 2;
228 };
229 
230 // ========== sibling methods ================================
231 
232 /**
233  * get next sibling starting index for ASN.1 object string (DEPRECATED)<br/>
234  * @name getNextSiblingIdx
235  * @memberOf ASN1HEX
236  * @function
237  * @param {String} s hexadecimal string of ASN.1 DER encoded data
238  * @param {Number} idx string index
239  * @return {Number} next sibling starting index for ASN.1 object string
240  * @since jsrsasign 7.2.0 asn1hex 1.1.11
241  * @deprecated jsrsasign 9.1.5 asn1hex 1.2.5 Please use {@link ASN1HEX.getTLVblen}
242  *
243  * @example
244  * SEQUENCE { INTEGER 3, INTEGER 4 }
245  * 3006
246  *     020103 :idx=4
247  *           020104 :next sibling idx=10
248  * getNextSiblingIdx("3006020103020104", 4) & rarr 10
249  */
250 ASN1HEX.getNextSiblingIdx = function(s, idx) {
251     var idx1 = ASN1HEX.getVidx(s, idx);
252     var blen = ASN1HEX.getVblen(s, idx);
253     return idx1 + blen * 2;
254 };
255 
256 // ========== children methods ===============================
257 /**
258  * get array of string indexes of child ASN.1 objects<br/>
259  * @name getChildIdx
260  * @memberOf ASN1HEX
261  * @function
262  * @param {String} h hexadecimal string of ASN.1 DER encoded data
263  * @param {Number} idx start string index of ASN.1 object
264  * @return {Array of Number} array of indexes for childen of ASN.1 objects
265  * @since jsrsasign 7.2.0 asn1hex 1.1.11
266  * @description
267  * This method returns array of integers for a concatination of ASN.1 objects
268  * in a ASN.1 value. As for BITSTRING, one byte of unusedbits is skipped.
269  * As for other ASN.1 simple types such as INTEGER, OCTET STRING or PRINTABLE STRING,
270  * it returns a array of a string index of its ASN.1 value.<br/>
271  * NOTE: Since asn1hex 1.1.7 of jsrsasign 6.1.2, Encapsulated BitString is supported.
272  * @example
273  * ASN1HEX.getChildIdx("0203012345", 0) ⇒ [4] // INTEGER 012345
274  * ASN1HEX.getChildIdx("1303616161", 0) ⇒ [4] // PrintableString aaa
275  * ASN1HEX.getChildIdx("030300ffff", 0) ⇒ [6] // BITSTRING ffff (unusedbits=00a)
276  * ASN1HEX.getChildIdx("3006020104020105", 0) ⇒ [4, 10] // SEQUENCE(INT4,INT5)
277  * ASN1HEX.getChildIdx("30841084107730030101ff", 0) ⇒ raise error for lacking vaule
278  */
279 ASN1HEX.getChildIdx = function(h, idx) {
280     var _ASN1HEX = ASN1HEX;
281     var a = [];
282     var idxStart, totalChildBlen, currentChildBlen;
283 
284     idxStart = _ASN1HEX.getVidx(h, idx);
285     totalChildBlen = _ASN1HEX.getVblen(h, idx) * 2;
286 
287     if (idxStart + totalChildBlen > h.length) {
288         throw new Error("too short ASN.1 value");
289     }
290 
291     if (h.substr(idx, 2) == "03") {  // BITSTRING without unusedbits
292 	idxStart += 2;
293 	totalChildBlen -= 2;
294     }
295 
296     currentChildBlen = 0;
297     var i = idxStart;
298     while (currentChildBlen <= totalChildBlen) {
299 	var tlvBlen = _ASN1HEX.getTLVblen(h, i);
300         if (tlvBlen <= 0) throw new Error("malformed ASN.1: invalid TLV length");
301 	currentChildBlen += tlvBlen;
302 	if (currentChildBlen <= totalChildBlen) a.push(i);
303 	i += tlvBlen;
304 	if (currentChildBlen >= totalChildBlen) break;
305     }
306     return a;
307 };
308 
309 /**
310  * get string index of nth child object of ASN.1 object refered by h, idx<br/>
311  * @name getNthChildIdx
312  * @memberOf ASN1HEX
313  * @function
314  * @param {String} h hexadecimal string of ASN.1 DER encoded data
315  * @param {Number} idx start string index of ASN.1 object
316  * @param {Number} nth for child
317  * @return {Number} string index of nth child.
318  * @since jsrsasign 7.2.0 asn1hex 1.1.11
319  */
320 ASN1HEX.getNthChildIdx = function(h, idx, nth) {
321     var a = ASN1HEX.getChildIdx(h, idx);
322     return a[nth];
323 };
324 
325 // ========== decendant methods ==============================
326 /**
327  * get string index of nth child object of ASN.1 object refered by h, idx<br/>
328  * @name getIdxbyList
329  * @memberOf ASN1HEX
330  * @function
331  * @param {String} h hexadecimal string of ASN.1 DER encoded data
332  * @param {Number} currentIndex start string index of ASN.1 object
333  * @param {Array of Number} nthList array list of nth
334  * @param {String} checkingTag (OPTIONAL) string of expected ASN.1 tag for nthList 
335  * @return {Number} string index refered by nthList
336  * @since jsrsasign 7.1.4 asn1hex 1.1.10.
337  * @description
338  * @example
339  * The "nthList" is a index list of structured ASN.1 object
340  * reference. Here is a sample structure and "nthList"s which
341  * refers each objects.
342  *
343  * SQUENCE               - 
344  *   SEQUENCE            - [0]
345  *     IA5STRING 000     - [0, 0]
346  *     UTF8STRING 001    - [0, 1]
347  *   SET                 - [1]
348  *     IA5STRING 010     - [1, 0]
349  *     UTF8STRING 011    - [1, 1]
350  */
351 ASN1HEX.getIdxbyList = function(h, currentIndex, nthList, checkingTag) {
352     var _ASN1HEX = ASN1HEX;
353     var firstNth, a;
354     if (nthList.length == 0) {
355 	if (checkingTag !== undefined) {
356             if (h.substr(currentIndex, 2) !== checkingTag) return -1;
357 	}
358         return currentIndex;
359     }
360     firstNth = nthList.shift();
361     a = _ASN1HEX.getChildIdx(h, currentIndex);
362     if (firstNth >= a.length) return -1;
363 
364     return _ASN1HEX.getIdxbyList(h, a[firstNth], nthList, checkingTag);
365 };
366 
367 /**
368  * get string index of nth child object of ASN.1 object refered by h, idx<br/>
369  * @name getIdxbyListEx
370  * @memberOf ASN1HEX
371  * @function
372  * @param {String} h hexadecimal string of ASN.1 DER encoded data
373  * @param {Number} currentIndex start string index of ASN.1 object
374  * @param {Array of Object} nthList array list of nth index value or context specific tag string (ex. "[0]")
375  * @param {String} checkingTag (OPTIONAL) string of expected ASN.1 tag for nthList 
376  * @return {Number} string index refered by nthList. return -1 if not found
377  * @since jsrsasign 8.0.21 asn1hex 1.2.2
378  * @see <a href="https://github.com/kjur/jsrsasign/wiki/Tutorial-for-accessing-deep-inside-of-ASN.1-structure-by-using-new-ASN1HEX.getIdxbyListEx">ASN1HEX.getIdxbyListEx tutorial wiki page</a>
379  *
380  * @description
381  * This method returns the string index in h specified by currentIndex and
382  * nthList. This is useful to dig into a deep structured ASN.1 object
383  * by indexes called nthList. 
384  * <br/>
385  * A nthList consists of a position number in children of ASN.1
386  * structured data or a context specific tag string (ex. "[1]").
387  * Here is a sample deep structured ASN.1 data and
388  * nthLists referring decendent objects.
389  * <blockquote><pre>
390  * SQUENCE               - referring nthList is below:
391  *   SEQUENCE            - [0]
392  *     IA5STRING "a1"    - [0, 0]
393  *     UTF8STRING "a2"   - [0, 1]
394  *   SET                 - [1]
395  *     IA5STRING "b1"    - [1, 0]
396  *     UTF8STRING "b2"   - [1, 1]
397  *     [0] "b3"          - [1, "[0]"] // optional since context tag
398  *     [1] "b4"          - [1, "[1]"] // optional since context tag
399  *     IA5STRING "b5"    - [1, 2] // context is skipped. next is 2
400  *     UTF8STRING "b6"   - [1, 3]
401  * </pre></blockquote>
402  *
403  * <br/>
404  * This method can dig into ASN.1 object encapsulated by
405  * OctetString or BitString with unused bits.
406  *
407  * @example
408  * 3014 seq idx=0
409  *   3012 seq idx=4
410  *     020101 int:1 idx=8
411  *     020102 int:2 idx=14
412  *     800103 [0]:3 idx=20
413  *     810104 [1]:4 idx=26
414  *     020105 int:5 idx=32
415  *     020106 int:6 idx=38
416  * h = "30140412020101020102800103810104020105020106";
417  * ASN1HEX.getIdxbyListEx(h, 0, [0, "[0]"]) → 16
418  * ASN1HEX.getIdxbyListEx(h, 0, [0, 2]) → 28
419  * ASN1HEX.getIdxbyListEx(h, 0, [0, 2], "0c") → -1 //not UTF8String(0c)
420  */
421 ASN1HEX.getIdxbyListEx = function(h, currentIndex, nthList, checkingTag) {
422     var _ASN1HEX = ASN1HEX;
423     var firstNth, a;
424     if (nthList.length == 0) {
425 	if (checkingTag !== undefined) {
426             if (h.substr(currentIndex, 2) !== checkingTag) {
427 		return -1;
428             }
429 	}
430         return currentIndex;
431     }
432     firstNth = nthList.shift();
433     a = _ASN1HEX.getChildIdx(h, currentIndex);
434 
435     var count = 0;
436     for (var i = 0; i < a.length; i++) {
437 	var childTag = h.substr(a[i], 2);
438 
439 	if ((typeof firstNth == "number" &&
440 	     (! _ASN1HEX.isContextTag(childTag)) &&
441 	     count == firstNth) ||
442 	    (typeof firstNth == "string" &&
443 	     _ASN1HEX.isContextTag(childTag, firstNth))) {
444 	    return _ASN1HEX.getIdxbyListEx(h, a[i], nthList, checkingTag);
445 	}
446 	if (! _ASN1HEX.isContextTag(childTag)) count++;
447     }
448     return -1;
449 };
450 
451 /**
452  * get ASN.1 TLV by nthList<br/>
453  * @name getTLVbyList
454  * @memberOf ASN1HEX
455  * @function
456  * @param {String} h hexadecimal string of ASN.1 structure
457  * @param {Integer} currentIndex string index to start searching in hexadecimal string "h"
458  * @param {Array} nthList array of nth list index
459  * @param {String} checkingTag (OPTIONAL) string of expected ASN.1 tag for nthList 
460  * @return {String} referred hexadecimal string of ASN.1 TLV or null
461  * @since jsrsasign 7.1.4 asn1hex 1.1.10
462  *
463  * @description
464  * This static method is to get a ASN.1 value which specified "nthList" position
465  * with checking expected tag "checkingTag".
466  * <br/>
467  * When referring value can't be found, this returns null.
468  */
469 ASN1HEX.getTLVbyList = function(h, currentIndex, nthList, checkingTag) {
470     var _ASN1HEX = ASN1HEX;
471     var idx = _ASN1HEX.getIdxbyList(h, currentIndex, nthList, checkingTag);
472 
473     if (idx == -1) return null;
474     if (idx >= h.length) return null;
475 
476     return _ASN1HEX.getTLV(h, idx);
477 };
478 
479 /**
480  * get ASN.1 TLV by nthList<br/>
481  * @name getTLVbyListEx
482  * @memberOf ASN1HEX
483  * @function
484  * @param {String} h hexadecimal string of ASN.1 structure
485  * @param {Integer} currentIndex string index to start searching in hexadecimal string "h"
486  * @param {Array of Object} nthList array list of nth index value or context specific tag string (ex. "[0]")
487  * @param {String} checkingTag (OPTIONAL) string of expected ASN.1 tag for nthList 
488  * @return {String} hexadecimal ASN.1 TLV string refered by nthList. return null if not found
489  * @since jsrsasign 8.0.21 asn1hex 1.2.2
490  * @see <a href="https://github.com/kjur/jsrsasign/wiki/Tutorial-for-accessing-deep-inside-of-ASN.1-structure-by-using-new-ASN1HEX.getIdxbyListEx">ASN1HEX.getIdxbyListEx tutorial wiki page</a>
491  * @see {@link ASN1HEX.getIdxbyListEx}
492  * @description
493  * This static method is to get a ASN.1 value which specified "nthList" position
494  * with checking expected tag "checkingTag".
495  * This method can dig into ASN.1 object encapsulated by
496  * OctetString or BitString with unused bits.
497  * @example
498  * 3014 seq idx=0
499  *   0312 seq idx=4
500  *     020101 int:1 idx=8
501  *     020102 int:2 idx=14
502  *     800103 [0]:3 idx=20
503  *     810104 [1]:4 idx=26
504  *     020105 int:5 idx=32
505  *     020106 int:6 idx=38
506  * h = "30140412020101020102800103810104020105020106";
507  * ASN1HEX.getTLVbyList(h, 0, [0, "[0]"]) → 800103
508  * ASN1HEX.getTLVbyList(h, 0, [0, 2]) → 020105
509  * ASN1HEX.getTLVbyList(h, 0, [0, 2], "0c") → null //not UTF8String(0c)
510  */
511 ASN1HEX.getTLVbyListEx = function(h, currentIndex, nthList, checkingTag) {
512     var _ASN1HEX = ASN1HEX;
513     var idx = _ASN1HEX.getIdxbyListEx(h, currentIndex, nthList, checkingTag);
514     if (idx == -1) return null;
515     return _ASN1HEX.getTLV(h, idx);
516 };
517 
518 /**
519  * get ASN.1 value by nthList<br/>
520  * @name getVbyList
521  * @memberOf ASN1HEX
522  * @function
523  * @param {String} h hexadecimal string of ASN.1 structure
524  * @param {Integer} currentIndex string index to start searching in hexadecimal string "h"
525  * @param {Array} nthList array of nth list index
526  * @param {String} checkingTag (OPTIONAL) string of expected ASN.1 tag for nthList 
527  * @param {Boolean} removeUnusedbits (OPTIONAL) flag for remove first byte for value (DEFAULT false)
528  * @return {String} referred hexadecimal string of ASN.1 value(V) or null
529  * @since asn1hex 1.1.4
530  * @see ASN1HEX.getIdxbyList
531  * @see ASN1HEX.getVbyListEx
532  *
533  * @description
534  * This static method is to get a ASN.1 value which specified "nthList" position
535  * with checking expected tag "checkingTag".
536  * <br/>
537  * When referring value can't be found, this returns null.
538  * <br/>
539  * NOTE: 'removeUnusedbits' flag has been supported since
540  * jsrsasign 7.1.14 asn1hex 1.1.10.
541  */
542 ASN1HEX.getVbyList = function(h, currentIndex, nthList, checkingTag, removeUnusedbits) {
543     var _ASN1HEX = ASN1HEX;
544     var idx, v;
545     idx = _ASN1HEX.getIdxbyList(h, currentIndex, nthList, checkingTag);
546     
547     if (idx == -1) return null;
548     if (idx >= h.length) return null;
549 
550     v = _ASN1HEX.getV(h, idx);
551     if (removeUnusedbits === true) v = v.substr(2);
552     return v;
553 };
554 
555 /**
556  * get ASN.1 V by nthList<br/>
557  * @name getVbyListEx
558  * @memberOf ASN1HEX
559  * @function
560  * @param {String} h hexadecimal string of ASN.1 structure
561  * @param {Integer} currentIndex string index to start searching in hexadecimal string "h"
562  * @param {Array of Object} nthList array list of nth index value or context specific tag string (ex. "[0]")
563  * @param {String} checkingTag (OPTIONAL) string of expected ASN.1 tag for nthList (default is undefined)
564  * @param {Boolean} removeUnusedbits (OPTIONAL) flag for trim unused bit from result value (default is undefined)
565  * @return {String} hexadecimal ASN.1 V string refered by nthList. return null if not found
566  * @since jsrsasign 8.0.21 asn1hex 1.2.2
567  * @see <a href="https://github.com/kjur/jsrsasign/wiki/Tutorial-for-accessing-deep-inside-of-ASN.1-structure-by-using-new-ASN1HEX.getIdxbyListEx">ASN1HEX.getIdxbyListEx tutorial wiki page</a>
568  * @see {@link ASN1HEX.getIdxbyListEx}
569  *
570  * @description
571  * This static method is to get a ASN.1 value which specified "nthList" position
572  * with checking expected tag "checkingTag".
573  * This method can dig into ASN.1 object encapsulated by
574  * OctetString or BitString with unused bits.
575  *
576  * @example
577  * 3014 seq idx=0
578  *   3012 seq idx=4
579  *     020101 int:1 idx=8
580  *     020102 int:2 idx=14
581  *     800103 [0]:3 idx=20
582  *     810104 [1]:4 idx=26
583  *     020105 int:5 idx=32
584  *     020106 int:6 idx=38
585  * h = "30140412020101020102800103810104020105020106";
586  * ASN1HEX.getTLVbyList(h, 0, [0, "[0]"]) → 03
587  * ASN1HEX.getTLVbyList(h, 0, [0, 2]) → 05
588  * ASN1HEX.getTLVbyList(h, 0, [0, 2], "0c") → null //not UTF8String(0c)
589  */
590 ASN1HEX.getVbyListEx = function(h, currentIndex, nthList, checkingTag, removeUnusedbits) {
591     var _ASN1HEX = ASN1HEX;
592     var idx, tlv, v;
593     idx = _ASN1HEX.getIdxbyListEx(h, currentIndex, nthList, checkingTag);
594     if (idx == -1) return null;
595     v = _ASN1HEX.getV(h, idx);
596     if (h.substr(idx, 2) == "03" && removeUnusedbits !== false) v = v.substr(2);
597     return v;
598 };
599 
600 /**
601  * get integer value from ASN.1 V(value) of Integer or BitString<br/>
602  * @name getInt
603  * @memberOf ASN1HEX
604  * @function
605  * @param {String} h hexadecimal string
606  * @param {Number} idx string index in h to get ASN.1 DER Integer or BitString
607  * @param {Object} errorReturn (OPTION) error return value (DEFAULT: -1)
608  * @return {Number} ASN.1 DER Integer or BitString value
609  * @since jsrsasign 10.1.0 asn1hex 1.2.7
610  * @see bitstrtoint
611  *
612  * @example
613  * ASN1HEX.getInt("xxxx020103xxxxxx", 4) &rarr 3 // DER Integer
614  * ASN1HEX.getInt("xxxx03020780xxxxxx", 4) &rarr 1 // DER BitStringx
615  * ASN1HEX.getInt("xxxx030203c8xxxxxx", 4) &rarr 25 // DER BitStringx
616  */
617 ASN1HEX.getInt = function(h, idx, errorReturn) {
618     if (errorReturn == undefined) errorReturn = -1;
619     try {
620 	var hTag = h.substr(idx, 2);
621 	if (hTag != "02" && hTag != "03") return errorReturn;
622 	var hV = ASN1HEX.getV(h, idx);
623 	if (hTag == "02") {
624 	    return parseInt(hV, 16);
625 	} else {
626 	    return bitstrtoint(hV);
627 	}
628     } catch(ex) {
629 	return errorReturn;
630     }
631 };
632 
633 /**
634  * get object identifier string from ASN.1 V(value)<br/>
635  * @name getOID
636  * @memberOf ASN1HEX
637  * @function
638  * @param {String} h hexadecimal string
639  * @param {Number} idx string index in h to get ASN.1 DER ObjectIdentifier
640  * @param {Object} errorReturn (OPTION) error return value (DEFAULT: null)
641  * @return {String} object identifier string (ex. "1.2.3.4")
642  * @since jsrsasign 10.1.0 asn1hex 1.2.7
643  *
644  * @example
645  * ASN1HEX.getInt("xxxx06032a0304xxxxxx", 4) &rarr "1.2.3.4"
646  */
647 ASN1HEX.getOID = function(h, idx, errorReturn) {
648     if (errorReturn == undefined) errorReturn = null;
649     try {
650 	if (h.substr(idx, 2) != "06") return errorReturn;
651 	var hOID = ASN1HEX.getV(h, idx);
652 	return hextooid(hOID);
653     } catch(ex) {
654 	return errorReturn;
655     }
656 };
657 
658 /**
659  * get object identifier name from ASN.1 V(value)<br/>
660  * @name getOIDName
661  * @memberOf ASN1HEX
662  * @function
663  * @param {String} h hexadecimal string
664  * @param {Number} idx string index in h to get ASN.1 DER ObjectIdentifier
665  * @param {Object} errorReturn (OPTION) error return value (DEFAULT: null)
666  * @return {String} object identifier name (ex. "sha256") oir OID string
667  * @since jsrsasign 10.1.0 asn1hex 1.2.7
668  *
669  * @description
670  * This static method returns object identifier name such as "sha256"
671  * if registered. If not registered, it returns OID string. 
672  * (ex. "1.2.3.4")
673  *
674  * @example
675  * ASN1HEX.getOIDName("xxxx0609608648016503040201xxxxxx", 4) &rarr "sha256"
676  * ASN1HEX.getOIDName("xxxx06032a0304xxxxxx", 4) &rarr "1.2.3.4"
677  */
678 ASN1HEX.getOIDName = function(h, idx, errorReturn) {
679     if (errorReturn == undefined) errorReturn = null;
680     try {
681 	var oid = ASN1HEX.getOID(h, idx, errorReturn);
682 	if (oid == errorReturn) return errorReturn;
683 	var name = KJUR.asn1.x509.OID.oid2name(oid);
684 	if (name == '') return oid;
685 	return name;
686     } catch(ex) {
687 	return errorReturn;
688     }
689 };
690 
691 /**
692  * get raw string from ASN.1 V(value)<br/>
693  * @name getString
694  * @memberOf ASN1HEX
695  * @function
696  * @param {String} h hexadecimal string
697  * @param {Number} idx string index in h to get any ASN.1 DER String
698  * @param {Object} errorReturn (OPTION) error return value (DEFAULT: null)
699  * @return {String} raw string
700  * @since jsrsasign 10.1.3 asn1hex 1.2.8
701  *
702  * @description
703  * This static method returns a raw string from
704  * any ASN.1 DER primitives.
705  *
706  * @example
707  * ASN1HEX.getString("xxxx1303616161xxxxxx", 4) &rarr "aaa"
708  * ASN1HEX.getString("xxxx0c03616161xxxxxx", 4) &rarr "aaa"
709  */
710 ASN1HEX.getString = function(h, idx, errorReturn) {
711     if (errorReturn == undefined) errorReturn = null;
712     try {
713 	var hV = ASN1HEX.getV(h, idx);
714 	return hextorstr(hV);
715     } catch(ex) {
716 	return errorReturn;
717     }
718 };
719 
720 /**
721  * get OID string from hexadecimal encoded value<br/>
722  * @name hextooidstr
723  * @memberOf ASN1HEX
724  * @function
725  * @param {String} hex hexadecmal string of ASN.1 DER encoded OID value
726  * @return {String} OID string (ex. '1.2.3.4.567')
727  * @since asn1hex 1.1.5
728  * @see {@link KJUR.asn1.ASN1Util.oidIntToHex}
729  * @description
730  * This static method converts from ASN.1 DER encoded 
731  * hexadecimal object identifier value to dot concatinated OID value.
732  * {@link KJUR.asn1.ASN1Util.oidIntToHex} is a reverse function of this.
733  * @example
734  * ASN1HEX.hextooidstr("550406") → "2.5.4.6"
735  */
736 ASN1HEX.hextooidstr = function(hex) {
737     var zeroPadding = function(s, len) {
738         if (s.length >= len) return s;
739         return new Array(len - s.length + 1).join('0') + s;
740     };
741 
742     var a = [];
743 
744     // a[0], a[1]
745     var hex0 = hex.substr(0, 2);
746     var i0 = parseInt(hex0, 16);
747     a[0] = new String(Math.floor(i0 / 40));
748     a[1] = new String(i0 % 40);
749 
750     // a[2]..a[n]
751    var hex1 = hex.substr(2);
752     var b = [];
753     for (var i = 0; i < hex1.length / 2; i++) {
754     b.push(parseInt(hex1.substr(i * 2, 2), 16));
755     }
756     var c = [];
757     var cbin = "";
758     for (var i = 0; i < b.length; i++) {
759         if (b[i] & 0x80) {
760             cbin = cbin + zeroPadding((b[i] & 0x7f).toString(2), 7);
761         } else {
762             cbin = cbin + zeroPadding((b[i] & 0x7f).toString(2), 7);
763             c.push(new String(parseInt(cbin, 2)));
764             cbin = "";
765         }
766     }
767 
768     var s = a.join(".");
769     if (c.length > 0) s = s + "." + c.join(".");
770     return s;
771 };
772 
773 /**
774  * get string of simple ASN.1 dump from hexadecimal ASN.1 data<br/>
775  * @name dump
776  * @memberOf ASN1HEX
777  * @function
778  * @param {Object} hexOrObj hexadecmal string of ASN.1 data or ASN1Object object
779  * @param {Array} flags associative array of flags for dump (OPTION)
780  * @param {Number} idx string index for starting dump (OPTION)
781  * @param {String} indent indent string (OPTION)
782  * @return {String} string of simple ASN.1 dump
783  * @since jsrsasign 4.8.3 asn1hex 1.1.6
784  * @description
785  * This method will get an ASN.1 dump from
786  * hexadecmal string of ASN.1 DER encoded data.
787  * Here are features:
788  * <ul>
789  * <li>ommit long hexadecimal string</li>
790  * <li>dump encapsulated OCTET STRING (good for X.509v3 extensions)</li>
791  * <li>structured/primitive context specific tag support (i.e. [0], [3] ...)</li>
792  * <li>automatic decode for implicit primitive context specific tag 
793  * (good for X.509v3 extension value)
794  *   <ul>
795  *   <li>if hex starts '68747470'(i.e. http) it is decoded as utf8 encoded string.</li>
796  *   <li>if it is in 'subjectAltName' extension value and is '[2]'(dNSName) tag
797  *   value will be encoded as utf8 string</li>
798  *   <li>otherwise it shows as hexadecimal string</li>
799  *   </ul>
800  * </li>
801  * </ul>
802  * NOTE1: Argument {@link KJUR.asn1.ASN1Object} object is supported since
803  * jsrsasign 6.2.4 asn1hex 1.0.8
804  * @example
805  * // 1) ASN.1 INTEGER
806  * ASN1HEX.dump('0203012345')
807  * ↓
808  * INTEGER 012345
809  *
810  * // 2) ASN.1 Object Identifier
811  * ASN1HEX.dump('06052b0e03021a')
812  * ↓
813  * ObjectIdentifier sha1 (1 3 14 3 2 26)
814  *
815  * // 3) ASN.1 SEQUENCE
816  * ASN1HEX.dump('3006020101020102')
817  * ↓
818  * SEQUENCE
819  *   INTEGER 01
820  *   INTEGER 02
821  *
822  * // 4) ASN.1 SEQUENCE since jsrsasign 6.2.4
823  * o = KJUR.asn1.ASN1Util.newObject({seq: [{int: 1}, {int: 2}]});
824  * ASN1HEX.dump(o)
825  * ↓
826  * SEQUENCE
827  *   INTEGER 01
828  *   INTEGER 02
829  * // 5) ASN.1 DUMP FOR X.509 CERTIFICATE
830  * ASN1HEX.dump(pemtohex(certPEM))
831  * ↓
832  * SEQUENCE
833  *   SEQUENCE
834  *     [0]
835  *       INTEGER 02
836  *     INTEGER 0c009310d206dbe337553580118ddc87
837  *     SEQUENCE
838  *       ObjectIdentifier SHA256withRSA (1 2 840 113549 1 1 11)
839  *       NULL
840  *     SEQUENCE
841  *       SET
842  *         SEQUENCE
843  *           ObjectIdentifier countryName (2 5 4 6)
844  *           PrintableString 'US'
845  *             :
846  */
847 ASN1HEX.dump = function(hexOrObj, flags, idx, indent) {
848     var _ASN1HEX = ASN1HEX;
849     var _getV = _ASN1HEX.getV;
850     var _dump = _ASN1HEX.dump;
851     var _getChildIdx = _ASN1HEX.getChildIdx;
852 
853     var hex = hexOrObj;
854     if (hexOrObj instanceof KJUR.asn1.ASN1Object)
855 	hex = hexOrObj.tohex();
856 
857     var _skipLongHex = function(hex, limitNumOctet) {
858 	if (hex.length <= limitNumOctet * 2) {
859 	    return hex;
860 	} else {
861 	    var s = hex.substr(0, limitNumOctet) + 
862 		    "..(total " + hex.length / 2 + "bytes).." +
863 		    hex.substr(hex.length - limitNumOctet, limitNumOctet);
864 	    return s;
865 	};
866     };
867 
868     if (flags === undefined) flags = { "ommit_long_octet": 32 };
869     if (idx === undefined) idx = 0;
870     if (indent === undefined) indent = "";
871     var skipLongHex = flags.ommit_long_octet;
872 
873     var tag = hex.substr(idx, 2);
874 
875     if (tag == "01") {
876 	var v = _getV(hex, idx);
877 	if (v == "00") {
878 	    return indent + "BOOLEAN FALSE\n";
879 	} else {
880 	    return indent + "BOOLEAN TRUE\n";
881 	}
882     }
883     if (tag == "02") {
884 	var v = _getV(hex, idx);
885         return indent + "INTEGER " + _skipLongHex(v, skipLongHex) + "\n";
886     }
887     if (tag == "03") {
888 	var v = _getV(hex, idx);
889 	if (_ASN1HEX.isASN1HEX(v.substr(2))) {
890   	    var s = indent + "BITSTRING, encapsulates\n";
891             s = s + _dump(v.substr(2), flags, 0, indent + "  ");
892             return s;
893 	} else {
894             return indent + "BITSTRING " + _skipLongHex(v, skipLongHex) + "\n";
895 	}
896     }
897     if (tag == "04") {
898 	var v = _getV(hex, idx);
899 	if (_ASN1HEX.isASN1HEX(v)) {
900 	    var s = indent + "OCTETSTRING, encapsulates\n";
901 	    s = s + _dump(v, flags, 0, indent + "  ");
902 	    return s;
903 	} else {
904 	    return indent + "OCTETSTRING " + _skipLongHex(v, skipLongHex) + "\n";
905 	}
906     }
907     if (tag == "05") {
908 	return indent + "NULL\n";
909     }
910     if (tag == "06") {
911 	var hV = _getV(hex, idx);
912         var oidDot = KJUR.asn1.ASN1Util.oidHexToInt(hV);
913         var oidName = KJUR.asn1.x509.OID.oid2name(oidDot);
914 	var oidSpc = oidDot.replace(/\./g, ' ');
915         if (oidName != '') {
916   	    return indent + "ObjectIdentifier " + oidName + " (" + oidSpc + ")\n";
917 	} else {
918   	    return indent + "ObjectIdentifier (" + oidSpc + ")\n";
919 	}
920     }
921     if (tag == "0a") {
922 	return indent + "ENUMERATED " + parseInt(_getV(hex, idx)) + "\n";
923     }
924     if (tag == "0c") {
925 	return indent + "UTF8String '" + hextoutf8(_getV(hex, idx)) + "'\n";
926     }
927     if (tag == "13") {
928 	return indent + "PrintableString '" + hextoutf8(_getV(hex, idx)) + "'\n";
929     }
930     if (tag == "14") {
931 	return indent + "TeletexString '" + hextoutf8(_getV(hex, idx)) + "'\n";
932     }
933     if (tag == "16") {
934 	return indent + "IA5String '" + hextoutf8(_getV(hex, idx)) + "'\n";
935     }
936     if (tag == "17") {
937 	return indent + "UTCTime " + hextoutf8(_getV(hex, idx)) + "\n";
938     }
939     if (tag == "18") {
940 	return indent + "GeneralizedTime " + hextoutf8(_getV(hex, idx)) + "\n";
941     }
942     if (tag == "1a") {
943 	return indent + "VisualString '" + hextoutf8(_getV(hex, idx)) + "'\n";
944     }
945     if (tag == "1e") {
946 	return indent + "BMPString '" + ucs2hextoutf8(_getV(hex, idx)) + "'\n";
947     }
948     if (tag == "30") {
949 	if (hex.substr(idx, 4) == "3000") {
950 	    return indent + "SEQUENCE {}\n";
951 	}
952 
953 	var s = indent + "SEQUENCE\n";
954 	var aIdx = _getChildIdx(hex, idx);
955 
956 	var flagsTemp = flags;
957 	
958 	if ((aIdx.length == 2 || aIdx.length == 3) &&
959 	    hex.substr(aIdx[0], 2) == "06" &&
960 	    hex.substr(aIdx[aIdx.length - 1], 2) == "04") { // supposed X.509v3 extension
961 	    var oidName = _ASN1HEX.oidname(_getV(hex, aIdx[0]));
962 	    var flagsClone = JSON.parse(JSON.stringify(flags));
963 	    flagsClone.x509ExtName = oidName;
964 	    flagsTemp = flagsClone;
965 	}
966 	
967 	for (var i = 0; i < aIdx.length; i++) {
968 	    s = s + _dump(hex, flagsTemp, aIdx[i], indent + "  ");
969 	}
970 	return s;
971     }
972     if (tag == "31") {
973 	var s = indent + "SET\n";
974 	var aIdx = _getChildIdx(hex, idx);
975 	for (var i = 0; i < aIdx.length; i++) {
976 	    s = s + _dump(hex, flags, aIdx[i], indent + "  ");
977 	}
978 	return s;
979     }
980     var tag = parseInt(tag, 16);
981     if ((tag & 128) != 0) { // context specific 
982 	var tagNumber = tag & 31;
983 	if ((tag & 32) != 0) { // structured tag
984 	    var s = indent + "[" + tagNumber + "]\n";
985 	    var aIdx = _getChildIdx(hex, idx);
986 	    for (var i = 0; i < aIdx.length; i++) {
987 		s = s + _dump(hex, flags, aIdx[i], indent + "  ");
988 	    }
989 	    return s;
990 	} else { // primitive tag
991 	    var v = _getV(hex, idx);
992 	    if (ASN1HEX.isASN1HEX(v)) {
993 		var s = indent + "[" + tagNumber + "]\n";
994 		s = s + _dump(v, flags, 0, indent + "  ");
995 		return s;
996 	    } else if (v.substr(0, 8) == "68747470") { // http
997 		v = hextoutf8(v);
998 	    } else if (flags.x509ExtName === "subjectAltName" &&
999 		       tagNumber == 2) {
1000 		v = hextoutf8(v);
1001 	    }
1002 	    // else if (ASN1HEX.isASN1HEX(v))
1003 
1004 	    var s = indent + "[" + tagNumber + "] " + v + "\n";
1005 	    return s;
1006 	}
1007     }
1008     return indent + "UNKNOWN(" + tag + ") " + 
1009 	   _getV(hex, idx) + "\n";
1010 };
1011 
1012 /**
1013  * parse ASN.1 DER hexadecimal string<br/>
1014  * @name parse
1015  * @memberOf ASN1HEX
1016  * @function
1017  * @param {String} h hexadecimal string of ASN1. DER
1018  * @return {Object} associative array of ASN.1 parsed result
1019  * @since jsrsasign 10.5.3 asn1hex 1.1.x
1020  * @see KJUR.asn1.ASN1Util.newOjbect
1021  *
1022  * @description
1023  * This method parses ASN.1 DER hexadecimal string.
1024  * Its result can be applied to {@link KJUR.asn1.ASN1Util.newOjbect}.
1025  *
1026  * @example
1027  * ASN1HEX.parse("31193017...") → // RDN
1028  * {set: [{seq: [{oid: "localityName"}, {utf8str: {str: "Test"}}] }]}
1029  */
1030 ASN1HEX.parse = function(h) {
1031     var _ASN1HEX = ASN1HEX,
1032 	_parse = _ASN1HEX.parse,
1033 	_isASN1HEX = _ASN1HEX.isASN1HEX,
1034 	_getV = _ASN1HEX.getV,
1035 	_getTLV = _ASN1HEX.getTLV,
1036 	_getChildIdx = _ASN1HEX.getChildIdx,
1037 	_KJUR_asn1 = KJUR.asn1,
1038 	_oidHexToInt = _KJUR_asn1.ASN1Util.oidHexToInt,
1039 	_oid2name = _KJUR_asn1.x509.OID.oid2name,
1040 	_hextoutf8 = hextoutf8,
1041 	_ucs2hextoutf8 = ucs2hextoutf8,
1042 	_iso88591hextoutf8 = iso88591hextoutf8;
1043 
1044     var tagName = {
1045 	"0c": "utf8str", "12": "numstr", "13": "prnstr", 
1046 	"14": "telstr", "16": "ia5str", "17": "utctime", 
1047 	"18": "gentime", "1a": "visstr", "1e": "bmpstr", 
1048 	"30": "seq", "31": "set"
1049     };
1050 
1051     var _parseChild = function(h) {
1052 	var result = [];
1053 	var aIdx = _getChildIdx(h, 0);
1054 	for (var i = 0; i < aIdx.length; i++) {
1055 	    var idx = aIdx[i];
1056 	    var hTLV = _getTLV(h, idx);
1057 	    var pItem = _parse(hTLV);
1058 	    result.push(pItem);
1059 	}
1060 	return result;
1061     };
1062 
1063     var tag = h.substr(0, 2);
1064     var result = {};
1065     var hV = _getV(h, 0);
1066     if (tag == "01") {
1067 	if (h == "0101ff") return {bool: true};
1068 	return {bool: false};
1069     } else if (tag == "02") {
1070 	return {"int": {hex: hV}};
1071     } else if (tag == "03") {
1072 	try {
1073 	    if (hV.substr(0, 2) != "00") throw "not encap";
1074 	    var hV1 = hV.substr(2);
1075 	    if (! _isASN1HEX(hV1)) throw "not encap";
1076 	    return {bitstr: {obj: _parse(hV1)}};
1077 	} catch(ex) {
1078 	    var bV = null;
1079 	    if (hV.length <= 10) bV = bitstrtobinstr(hV);
1080 	    if (bV == null) {
1081 		return {bitstr: {hex: hV}};
1082 	    } else {
1083 		return {bitstr: {bin: bV}};
1084 	    }
1085 	}
1086     } else if (tag == "04") {
1087 	try {
1088 	    if (! _isASN1HEX(hV)) throw "not encap";
1089 	    return {octstr: {obj: _parse(hV)}};
1090 	} catch(ex) {
1091 	    return {octstr: {hex: hV}};
1092 	}
1093     } else if (tag == "05") {
1094 	return {"null": ''};
1095     } else if (tag == "06") {
1096 	var oidDot = _oidHexToInt(hV);
1097 	var oidName = _oid2name(oidDot);
1098 	if (oidName == "") {
1099 	    return {oid: oidDot};
1100 	} else {
1101 	    return {oid: oidName};
1102 	}
1103     } else if (tag == "0a") {
1104 	if (hV.length > 4) {
1105 	    return {"enum": {hex: hV}};
1106 	} else {
1107 	    return {"enum": parseInt(hV, 16)};
1108 	}
1109     } else if (tag == "30" || tag == "31") {
1110 	result[tagName[tag]] = _parseChild(h);
1111 	return result;
1112     } else if (tag == "14") { // TeletexString
1113 	var s = _iso88591hextoutf8(hV);
1114 	result[tagName[tag]] = {str: s};
1115 	return result;
1116     } else if (tag == "1e") { // BMPString
1117 	var s = _ucs2hextoutf8(hV);
1118 	result[tagName[tag]] = {str: s};
1119 	return result;
1120     } else if (":0c:12:13:16:17:18:1a:".indexOf(tag) != -1) { // Other Strings types
1121 	var s = _hextoutf8(hV);
1122 	result[tagName[tag]] = {str: s};
1123 	return result;
1124     } else if (tag.match(/^8[0-9]$/)) {
1125 	var s = _hextoutf8(hV);
1126 	if (s == null | s == "") {
1127 	    return {"tag": {"tag": tag, explicit: false, hex: hV}};
1128 	} else if (s.match(/[\x00-\x1F\x7F-\x9F]/) != null ||
1129 		   s.match(/[\u0000-\u001F\u0080–\u009F]/) != null) {
1130 	    return {"tag": {"tag": tag, explicit: false, hex: hV}};
1131 	} else {
1132 	    return {"tag": {"tag": tag, explicit: false, str: s}};
1133 	}
1134     } else if (tag.match(/^a[0-9]$/)) {
1135 	try {
1136 	    if (! _isASN1HEX(hV)) throw new Error("not encap");
1137 	    return {"tag": {"tag": tag, 
1138 			    explicit: true,
1139 			    obj: _parse(hV)}};
1140 	} catch(ex) {
1141 	    return {"tag": {"tag": tag, explicit: true, hex: hV}};
1142 	}
1143     } else {
1144 	var d = new KJUR.asn1.ASN1Object();
1145 	d.hV = hV;
1146 	var hL = d.getLengthHexFromValue();
1147 	return {"asn1": {"tlv": tag + hL + hV}};
1148     }
1149 };
1150 
1151 /**
1152  * check if a hexadecimal tag is a specified ASN.1 context specific tag
1153  * @name isContextTag
1154  * @memberOf ASN1HEX
1155  * @function
1156  * @param {hTag} hex string of a hexadecimal ASN.1 tag consists by two characters (e.x. "a0")
1157  * @param {sTag} context specific tag in string represention (OPTION) (e.x. "[0]")
1158  * @return {Boolean} true if hTag is a ASN.1 context specific tag specified by sTag value.
1159  * @since jsrsasign 8.0.21 asn1hex 1.2.2
1160  * @description
1161  * This method checks if a hexadecimal tag is a specified ASN.1 context specific tag.
1162  * Structured and non-structured type of tag have the same string representation
1163  * of context specific tag. For example tag "a0" and "80" have the same string
1164  * representation "[0]".
1165  * The sTag has a range from from "[0]" to "[31]".
1166  * @example
1167  * ASN1HEX.isContextTag('a0', '[0]') → true // structured
1168  * ASN1HEX.isContextTag('a1', '[1]') → true // structured
1169  * ASN1HEX.isContextTag('a2', '[2]') → true // structured
1170  * ASN1HEX.isContextTag('80', '[0]') → true // non structured
1171  * ASN1HEX.isContextTag('81', '[1]') → true // non structured
1172  * ASN1HEX.isContextTag('82', '[2]') → true // non structured
1173  * ASN1HEX.isContextTag('a0', '[3]') → false
1174  * ASN1HEX.isContextTag('80', '[15]') → false
1175  *
1176  * ASN.1 tag bits
1177  * 12345679
1178  * ++        tag class(universal:00, context specific:10)
1179  *   +       structured:1, primitive:0
1180  *    +++++  tag number (0 - 31)
1181  */
1182 ASN1HEX.isContextTag = function(hTag, sTag) {
1183     hTag = hTag.toLowerCase();
1184     var ihtag, istag;
1185 
1186     try {
1187 	ihtag = parseInt(hTag, 16);
1188     } catch (ex) {
1189 	return -1;
1190     }
1191 	
1192     if (sTag === undefined) {
1193 	if ((ihtag & 192) == 128) {
1194 	    return true;
1195 	} else {
1196 	    return false;
1197 	}
1198     }
1199 
1200     try {
1201 	var result = sTag.match(/^\[[0-9]+\]$/);
1202 	if (result == null) return false;
1203 	istag = parseInt(sTag.substr(1,sTag.length - 1), 10);
1204 	if (istag > 31) return false;
1205 	if (((ihtag & 192) == 128) &&   // ihtag & b11000000 == b10000000
1206 	    ((ihtag & 31) == istag)) {  // ihtag & b00011111 == istag (0-31)
1207 	    return true;
1208 	}
1209 	return false;
1210     } catch (ex) {
1211 	return false;
1212     }
1213 };
1214 
1215 /**
1216  * simple ASN.1 DER hexadecimal string checker<br/>
1217  * @name isASN1HEX
1218  * @memberOf ASN1HEX
1219  * @function
1220  * @param {String} hex string to check whether it is hexadecmal string for ASN.1 DER or not
1221  * @return {Boolean} true if it is hexadecimal string of ASN.1 data otherwise false
1222  * @since jsrsasign 4.8.3 asn1hex 1.1.6
1223  * @description
1224  * This method checks wheather the argument 'hex' is a hexadecimal string of
1225  * ASN.1 data or not.
1226  * @example
1227  * ASN1HEX.isASN1HEX('0203012345') → true // PROPER ASN.1 INTEGER
1228  * ASN1HEX.isASN1HEX('0203012345ff') → false // TOO LONG VALUE
1229  * ASN1HEX.isASN1HEX('02030123') → false // TOO SHORT VALUE
1230  * ASN1HEX.isASN1HEX('fa3bcd') → false // WRONG FOR ASN.1
1231  */
1232 ASN1HEX.isASN1HEX = function(hex) {
1233     var _ASN1HEX = ASN1HEX;
1234     if (hex.length % 2 == 1) return false;
1235 
1236     var intL = _ASN1HEX.getVblen(hex, 0);
1237     var hT = hex.substr(0, 2);
1238     var hL = _ASN1HEX.getL(hex, 0);
1239     var hVLength = hex.length - hT.length - hL.length;
1240     if (hVLength == intL * 2) return true;
1241 
1242     return false;
1243 };
1244 
1245 /**
1246  * strict ASN.1 DER hexadecimal string checker
1247  * @name checkStrictDER
1248  * @memberOf ASN1HEX
1249  * @function
1250  * @param {String} hex string to check whether it is hexadecmal string for ASN.1 DER or not
1251  * @return unspecified
1252  * @since jsrsasign 8.0.19 asn1hex 1.2.1
1253  * @throws Error when malformed ASN.1 DER hexadecimal string
1254  * @description
1255  * This method checks wheather the argument 'hex' is a hexadecimal string of
1256  * ASN.1 data or not. If the argument is not DER string, this 
1257  * raise an exception.
1258  * @example
1259  * ASN1HEX.checkStrictDER('0203012345') → NO EXCEPTION FOR PROPER ASN.1 INTEGER
1260  * ASN1HEX.checkStrictDER('0203012345ff') → RAISE EXCEPTION FOR TOO LONG VALUE
1261  * ASN1HEX.checkStrictDER('02030123') → false RAISE EXCEPITON FOR TOO SHORT VALUE
1262  * ASN1HEX.checkStrictDER('fa3bcd') → false RAISE EXCEPTION FOR WRONG ASN.1
1263  */
1264 ASN1HEX.checkStrictDER = function(h, idx, maxHexLen, maxByteLen, maxLbyteLen) {
1265     var _ASN1HEX = ASN1HEX;
1266 
1267     if (maxHexLen === undefined) {
1268 	// 1. hex string check
1269 	if (typeof h != "string") throw new Error("not hex string");
1270 	h = h.toLowerCase();
1271 	if (! KJUR.lang.String.isHex(h)) throw new Error("not hex string");
1272 
1273 	// 2. set max if needed
1274 	// max length of hexadecimal string
1275 	maxHexLen = h.length;
1276 	// max length of octets
1277 	maxByteLen = h.length / 2;
1278 	// max length of L octets of TLV
1279 	if (maxByteLen < 0x80) {
1280 	    maxLbyteLen = 1;
1281 	} else {
1282 	    maxLbyteLen = Math.ceil(maxByteLen.toString(16)) + 1;
1283 	}
1284     }
1285     //console.log(maxHexLen + ":" + maxByteLen + ":" + maxLbyteLen);
1286 
1287     // 3. check if L(length) string not exceeds maxLbyteLen
1288     var hL = _ASN1HEX.getL(h, idx);
1289     if (hL.length > maxLbyteLen * 2)
1290 	throw new Error("L of TLV too long: idx=" + idx);
1291 
1292     // 4. check if V(value) octet length (i.e. L(length) value) 
1293     //    not exceeds maxByteLen
1294     var vblen = _ASN1HEX.getVblen(h, idx);
1295     if (vblen > maxByteLen) 
1296 	throw new Error("value of L too long than hex: idx=" + idx);
1297 
1298     // 5. check V string length and L's value are the same
1299     var hTLV = _ASN1HEX.getTLV(h, idx);
1300     var hVLength = 
1301 	hTLV.length - 2 - _ASN1HEX.getL(h, idx).length;
1302     if (hVLength !== (vblen * 2))
1303 	throw new Error("V string length and L's value not the same:" +
1304 		        hVLength + "/" + (vblen * 2));
1305 
1306     // 6. check appending garbled string
1307     if (idx === 0) {
1308 	if (h.length != hTLV.length)
1309 	    throw new Error("total length and TLV length unmatch:" +
1310 			    h.length + "!=" + hTLV.length);
1311     }
1312 
1313     // 7. check if there isn't prepending zeros in DER INTEGER value
1314     var hT = h.substr(idx, 2);
1315     if (hT === '02') {
1316 	var vidx = _ASN1HEX.getVidx(h, idx);
1317 	// check if DER INTEGER VALUE have least leading zeros 
1318 	// for two's complement
1319 	// GOOD - 3fabde... 008fad...
1320 	// BAD  - 000012... 007fad...
1321 	if (h.substr(vidx, 2) == "00" && h.charCodeAt(vidx + 2) < 56) // '8'=56
1322 	    throw new Error("not least zeros for DER INTEGER");
1323     }
1324 
1325     // 8. check if all of elements in a structured item are conformed to
1326     //    strict DER encoding rules.
1327     if (parseInt(hT, 16) & 32) { // structured tag?
1328 	var intL = _ASN1HEX.getVblen(h, idx);
1329 	var sum = 0;
1330 	var aIdx = _ASN1HEX.getChildIdx(h, idx);
1331 	for (var i = 0; i < aIdx.length; i++) {
1332 	    var tlv = _ASN1HEX.getTLV(h, aIdx[i]);
1333 	    sum += tlv.length;
1334 	    _ASN1HEX.checkStrictDER(h, aIdx[i], 
1335 				   maxHexLen, maxByteLen, maxLbyteLen);
1336 	}
1337 	if ((intL * 2) != sum)
1338 	    throw new Error("sum of children's TLV length and L unmatch: " +
1339 			    (intL * 2) + "!=" + sum);
1340     }
1341 };
1342 
1343 /**
1344  * get hexacedimal string from PEM format data<br/>
1345  * @name oidname
1346  * @memberOf ASN1HEX
1347  * @function
1348  * @param {String} oidDotOrHex number dot notation(i.e. 1.2.3) or hexadecimal string for OID
1349  * @return {String} name for OID
1350  * @since jsrsasign 7.2.0 asn1hex 1.1.11
1351  * @description
1352  * This static method gets a OID name for
1353  * a specified string of number dot notation (i.e. 1.2.3) or
1354  * hexadecimal string.
1355  * @example
1356  * ASN1HEX.oidname("2.5.29.37") → extKeyUsage
1357  * ASN1HEX.oidname("551d25") → extKeyUsage
1358  * ASN1HEX.oidname("0.1.2.3") → 0.1.2.3 // unknown
1359  */
1360 ASN1HEX.oidname = function(oidDotOrHex) {
1361     var _KJUR_asn1 = KJUR.asn1;
1362     if (KJUR.lang.String.isHex(oidDotOrHex))
1363 	oidDotOrHex = _KJUR_asn1.ASN1Util.oidHexToInt(oidDotOrHex);
1364     var name = _KJUR_asn1.x509.OID.oid2name(oidDotOrHex);
1365     if (name === "") name = oidDotOrHex;
1366     return name;
1367 };
1368 
1369