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