1 /* asn1hex-1.2.0.js (c) 2012-2017 Kenji Urushima | kjur.github.com/jsrsasign/license
  2  */
  3 /*
  4  * asn1hex.js - Hexadecimal represented ASN.1 string library
  5  *
  6  * Copyright (c) 2010-2017 Kenji Urushima (kenji.urushima@gmail.com)
  7  *
  8  * This software is licensed under the terms of the MIT License.
  9  * https://kjur.github.io/jsrsasign/license/
 10  *
 11  * The above copyright and license notice shall be 
 12  * included in all copies or substantial portions of the Software.
 13  */
 14 
 15 /**
 16  * @fileOverview
 17  * @name asn1hex-1.1.js
 18  * @author Kenji Urushima kenji.urushima@gmail.com
 19  * @version asn1hex 1.2.0 (2017-Jun-24)
 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.getV} - get ASN.1 V at specified position</li>
 50  *   <li>{@link ASN1HEX.getVlen} - get integer ASN.1 L at specified position</li>
 51  *   <li>{@link ASN1HEX.getVidx} - get ASN.1 V position from its ASN.1 TLV position</li>
 52  *   <li>{@link ASN1HEX.getL} - get hexadecimal ASN.1 L at specified position</li>
 53  *   <li>{@link ASN1HEX.getLblen} - get byte length for ASN.1 L(length) bytes</li>
 54  *   </ul>
 55  * </li>
 56  * <li><b>ACCESS FOR CHILD ITEM</b>
 57  *   <ul>
 58  *   <li>{@link ASN1HEX.getNthChildIndex_AtObj} - get nth child index at specified position</li>
 59  *   <li>{@link ASN1HEX.getPosArrayOfChildren_AtObj} - get indexes of children</li>
 60  *   <li>{@link ASN1HEX.getPosOfNextSibling_AtObj} - get position of next sibling</li>
 61  *   </ul>
 62  * </li>
 63  * <li><b>ACCESS NESTED ASN.1 STRUCTURE</b>
 64  *   <ul>
 65  *   <li>{@link ASN1HEX.getTLVbyList} - get ASN.1 TLV at specified list index</li>
 66  *   <li>{@link ASN1HEX.getVbyList} - get ASN.1 V at specified nth list index with checking expected tag</li>
 67  *   <li>{@link ASN1HEX.getIdxbyList} - get index at specified list index</li>
 68  *   </ul>
 69  * </li>
 70  * <li><b>UTILITIES</b>
 71  *   <ul>
 72  *   <li>{@link ASN1HEX.dump} - dump ASN.1 structure</li>
 73  *   <li>{@link ASN1HEX.isASN1HEX} - check whether ASN.1 hexadecimal string or not</li>
 74  *   <li>{@link ASN1HEX.hextooidstr} - convert hexadecimal string of OID to dotted integer list</li>
 75  *   </ul>
 76  * </li>
 77  * </ul>
 78  */
 79 var ASN1HEX = new function() {
 80 };
 81 
 82 /**
 83  * get byte length for ASN.1 L(length) bytes<br/>
 84  * @name getLblen
 85  * @memberOf ASN1HEX
 86  * @function
 87  * @param {String} s hexadecimal string of ASN.1 DER encoded data
 88  * @param {Number} idx string index
 89  * @return byte length for ASN.1 L(length) bytes
 90  * @since jsrsasign 7.2.0 asn1hex 1.1.11
 91  * @example
 92  * ASN1HEX.getLblen('020100', 0) → 1 for '01'
 93  * ASN1HEX.getLblen('020200', 0) → 1 for '02'
 94  * ASN1HEX.getLblen('02818003...', 0) → 2 for '8180'
 95  * ASN1HEX.getLblen('0282025b03...', 0) → 3 for '82025b'
 96  * ASN1HEX.getLblen('0280020100...', 0) → -1 for '80' BER indefinite length
 97  * ASN1HEX.getLblen('02ffab...', 0) → -2 for malformed ASN.1 length
 98  */
 99 ASN1HEX.getLblen = function(s, idx) {
100     if (s.substr(idx + 2, 1) != '8') return 1;
101     var i = parseInt(s.substr(idx + 3, 1));
102     if (i == 0) return -1;             // length octet '80' indefinite length
103     if (0 < i && i < 10) return i + 1; // including '8?' octet;
104     return -2;                         // malformed format
105 };
106 
107 /**
108  * get hexadecimal string for ASN.1 L(length) bytes<br/>
109  * @name getL
110  * @memberOf ASN1HEX
111  * @function
112  * @param {String} s hexadecimal string of ASN.1 DER encoded data
113  * @param {Number} idx string index to get L of ASN.1 object
114  * @return {String} hexadecimal string for ASN.1 L(length) bytes
115  * @since jsrsasign 7.2.0 asn1hex 1.1.11
116  */
117 ASN1HEX.getL = function(s, idx) {
118     var len = ASN1HEX.getLblen(s, idx);
119     if (len < 1) return '';
120     return s.substr(idx + 2, len * 2);
121 };
122 
123 /**
124  * get integer value of ASN.1 length for ASN.1 data<br/>
125  * @name getVblen
126  * @memberOf ASN1HEX
127  * @function
128  * @param {String} s hexadecimal string of ASN.1 DER encoded data
129  * @param {Number} idx string index
130  * @return ASN.1 L(length) integer value
131  * @since jsrsasign 7.2.0 asn1hex 1.1.11
132  */
133 /*
134  getting ASN.1 length value at the position 'idx' of
135  hexa decimal string 's'.
136  f('3082025b02...', 0) ... 82025b ... ???
137  f('020100', 0) ... 01 ... 1
138  f('0203001...', 0) ... 03 ... 3
139  f('02818003...', 0) ... 8180 ... 128
140  */
141 ASN1HEX.getVblen = function(s, idx) {
142     var hLen, bi;
143     hLen = ASN1HEX.getL(s, idx);
144     if (hLen == '') return -1;
145     if (hLen.substr(0, 1) === '8') {
146         bi = new BigInteger(hLen.substr(2), 16);
147     } else {
148         bi = new BigInteger(hLen, 16);
149     }
150     return bi.intValue();
151 };
152 
153 /**
154  * get ASN.1 value starting string position for ASN.1 object refered by index 'idx'.
155  * @name getVidx
156  * @memberOf ASN1HEX
157  * @function
158  * @param {String} s hexadecimal string of ASN.1 DER encoded data
159  * @param {Number} idx string index
160  * @since jsrsasign 7.2.0 asn1hex 1.1.11
161  */
162 ASN1HEX.getVidx = function(s, idx) {
163     var l_len = ASN1HEX.getLblen(s, idx);
164     if (l_len < 0) return l_len;
165     return idx + (l_len + 1) * 2;
166 };
167 
168 /**
169  * get hexadecimal string of ASN.1 V(value)<br/>
170  * @name getV
171  * @memberOf ASN1HEX
172  * @function
173  * @param {String} s hexadecimal string of ASN.1 DER encoded data
174  * @param {Number} idx string index
175  * @return {String} hexadecimal string of ASN.1 value.
176  * @since jsrsasign 7.2.0 asn1hex 1.1.11
177  */
178 ASN1HEX.getV = function(s, idx) {
179     var idx1 = ASN1HEX.getVidx(s, idx);
180     var blen = ASN1HEX.getVblen(s, idx);
181     return s.substr(idx1, blen * 2);
182 };
183 
184 /**
185  * get hexadecimal string of ASN.1 TLV at<br/>
186  * @name getTLV
187  * @memberOf ASN1HEX
188  * @function
189  * @param {String} s hexadecimal string of ASN.1 DER encoded data
190  * @param {Number} idx string index
191  * @return {String} hexadecimal string of ASN.1 TLV.
192  * @since jsrsasign 7.2.0 asn1hex 1.1.11
193  */
194 ASN1HEX.getTLV = function(s, idx) {
195     return s.substr(idx, 2) + ASN1HEX.getL(s, idx) + ASN1HEX.getV(s, idx);
196 };
197 
198 // ========== sibling methods ================================
199 
200 /**
201  * get next sibling starting index for ASN.1 object string<br/>
202  * @name getNextSiblingIdx
203  * @memberOf ASN1HEX
204  * @function
205  * @param {String} s hexadecimal string of ASN.1 DER encoded data
206  * @param {Number} idx string index
207  * @return next sibling starting index for ASN.1 object string
208  * @since jsrsasign 7.2.0 asn1hex 1.1.11
209  * @example
210  * SEQUENCE { INTEGER 3, INTEGER 4 }
211  * 3006
212  *     020103 :idx=4
213  *           020104 :next sibling idx=10
214  * getNextSiblingIdx("3006020103020104", 4) & rarr 10
215  */
216 ASN1HEX.getNextSiblingIdx = function(s, idx) {
217     var idx1 = ASN1HEX.getVidx(s, idx);
218     var blen = ASN1HEX.getVblen(s, idx);
219     return idx1 + blen * 2;
220 };
221 
222 // ========== children methods ===============================
223 /**
224  * get array of string indexes of child ASN.1 objects<br/>
225  * @name getChildIdx
226  * @memberOf ASN1HEX
227  * @function
228  * @param {String} h hexadecimal string of ASN.1 DER encoded data
229  * @param {Number} pos start string index of ASN.1 object
230  * @return {Array of Number} array of indexes for childen of ASN.1 objects
231  * @since jsrsasign 7.2.0 asn1hex 1.1.11
232  * @description
233  * This method returns array of integers for a concatination of ASN.1 objects
234  * in a ASN.1 value. As for BITSTRING, one byte of unusedbits is skipped.
235  * As for other ASN.1 simple types such as INTEGER, OCTET STRING or PRINTABLE STRING,
236  * it returns a array of a string index of its ASN.1 value.<br/>
237  * NOTE: Since asn1hex 1.1.7 of jsrsasign 6.1.2, Encapsulated BitString is supported.
238  * @example
239  * ASN1HEX.getChildIdx("0203012345", 0) ⇒ [4] // INTEGER 012345
240  * ASN1HEX.getChildIdx("1303616161", 0) ⇒ [4] // PrintableString aaa
241  * ASN1HEX.getChildIdx("030300ffff", 0) ⇒ [6] // BITSTRING ffff (unusedbits=00a)
242  * ASN1HEX.getChildIdx("3006020104020105", 0) ⇒ [4, 10] // SEQUENCE(INT4,INT5)
243  */
244 ASN1HEX.getChildIdx = function(h, pos) {
245     var _ASN1HEX = ASN1HEX;
246     var a = new Array();
247     var p0 = _ASN1HEX.getVidx(h, pos);
248     if (h.substr(pos, 2) == "03") {
249 	a.push(p0 + 2); // BITSTRING value without unusedbits
250     } else {
251 	a.push(p0);
252     }
253 
254     var blen = _ASN1HEX.getVblen(h, pos);
255     var p = p0;
256     var k = 0;
257     while (1) {
258         var pNext = _ASN1HEX.getNextSiblingIdx(h, p);
259         if (pNext == null || (pNext - p0  >= (blen * 2))) break;
260         if (k >= 200) break;
261             
262         a.push(pNext);
263         p = pNext;
264             
265         k++;
266     }
267     
268     return a;
269 };
270 
271 /**
272  * get string index of nth child object of ASN.1 object refered by h, idx<br/>
273  * @name getNthChildIdx
274  * @memberOf ASN1HEX
275  * @function
276  * @param {String} h hexadecimal string of ASN.1 DER encoded data
277  * @param {Number} idx start string index of ASN.1 object
278  * @param {Number} nth for child
279  * @return {Number} string index of nth child.
280  * @since jsrsasign 7.2.0 asn1hex 1.1.11
281  */
282 ASN1HEX.getNthChildIdx = function(h, idx, nth) {
283     var a = ASN1HEX.getChildIdx(h, idx);
284     return a[nth];
285 };
286 
287 // ========== decendant methods ==============================
288 /**
289  * get string index of nth child object of ASN.1 object refered by h, idx<br/>
290  * @name getIdxbyList
291  * @memberOf ASN1HEX
292  * @function
293  * @param {String} h hexadecimal string of ASN.1 DER encoded data
294  * @param {Number} currentIndex start string index of ASN.1 object
295  * @param {Array of Number} nthList array list of nth
296  * @param {String} checkingTag (OPTIONAL) string of expected ASN.1 tag for nthList 
297  * @return {Number} string index refered by nthList
298  * @since jsrsasign 7.1.4 asn1hex 1.1.10.
299  * @description
300  * @example
301  * The "nthList" is a index list of structured ASN.1 object
302  * reference. Here is a sample structure and "nthList"s which
303  * refers each objects.
304  *
305  * SQUENCE               - 
306  *   SEQUENCE            - [0]
307  *     IA5STRING 000     - [0, 0]
308  *     UTF8STRING 001    - [0, 1]
309  *   SET                 - [1]
310  *     IA5STRING 010     - [1, 0]
311  *     UTF8STRING 011    - [1, 1]
312  */
313 ASN1HEX.getIdxbyList = function(h, currentIndex, nthList, checkingTag) {
314     var _ASN1HEX = ASN1HEX;
315     var firstNth, a;
316     if (nthList.length == 0) {
317 	if (checkingTag !== undefined) {
318             if (h.substr(currentIndex, 2) !== checkingTag) {
319 		throw "checking tag doesn't match: " + 
320                     h.substr(currentIndex, 2) + "!=" + checkingTag;
321             }
322 	}
323         return currentIndex;
324     }
325     firstNth = nthList.shift();
326     a = _ASN1HEX.getChildIdx(h, currentIndex);
327     return _ASN1HEX.getIdxbyList(h, a[firstNth], nthList, checkingTag);
328 };
329 
330 /**
331  * get ASN.1 TLV by nthList<br/>
332  * @name getTLVbyList
333  * @memberOf ASN1HEX
334  * @function
335  * @param {String} h hexadecimal string of ASN.1 structure
336  * @param {Integer} currentIndex string index to start searching in hexadecimal string "h"
337  * @param {Array} nthList array of nth list index
338  * @param {String} checkingTag (OPTIONAL) string of expected ASN.1 tag for nthList 
339  * @since jsrsasign 7.1.4 asn1hex 1.1.10
340  * @description
341  * This static method is to get a ASN.1 value which specified "nthList" position
342  * with checking expected tag "checkingTag".
343  */
344 ASN1HEX.getTLVbyList = function(h, currentIndex, nthList, checkingTag) {
345     var _ASN1HEX = ASN1HEX;
346     var idx = _ASN1HEX.getIdxbyList(h, currentIndex, nthList);
347     if (idx === undefined) {
348         throw "can't find nthList object";
349     }
350     if (checkingTag !== undefined) {
351         if (h.substr(idx, 2) != checkingTag) {
352             throw "checking tag doesn't match: " + 
353                 h.substr(idx,2) + "!=" + checkingTag;
354         }
355     }
356     return _ASN1HEX.getTLV(h, idx);
357 };
358 
359 /**
360  * get ASN.1 value by nthList<br/>
361  * @name getVbyList
362  * @memberOf ASN1HEX
363  * @function
364  * @param {String} h hexadecimal string of ASN.1 structure
365  * @param {Integer} currentIndex string index to start searching in hexadecimal string "h"
366  * @param {Array} nthList array of nth list index
367  * @param {String} checkingTag (OPTIONAL) string of expected ASN.1 tag for nthList 
368  * @param {Boolean} removeUnusedbits (OPTIONAL) flag for remove first byte for value (DEFAULT false)
369  * @since asn1hex 1.1.4
370  * @description
371  * This static method is to get a ASN.1 value which specified "nthList" position
372  * with checking expected tag "checkingTag".
373  * NOTE: 'removeUnusedbits' flag has been supported since
374  * jsrsasign 7.1.14 asn1hex 1.1.10.
375  */
376 ASN1HEX.getVbyList = function(h, currentIndex, nthList, checkingTag, removeUnusedbits) {
377     var _ASN1HEX = ASN1HEX;
378     var idx, v;
379     idx = _ASN1HEX.getIdxbyList(h, currentIndex, nthList, checkingTag);
380     
381     if (idx === undefined) {
382         throw "can't find nthList object";
383     }
384 
385     v = _ASN1HEX.getV(h, idx);
386     if (removeUnusedbits === true) v = v.substr(2);
387     return v;
388 };
389 
390 /**
391  * get OID string from hexadecimal encoded value<br/>
392  * @name hextooidstr
393  * @memberOf ASN1HEX
394  * @function
395  * @param {String} hex hexadecmal string of ASN.1 DER encoded OID value
396  * @return {String} OID string (ex. '1.2.3.4.567')
397  * @since asn1hex 1.1.5
398  */
399 ASN1HEX.hextooidstr = function(hex) {
400     var zeroPadding = function(s, len) {
401         if (s.length >= len) return s;
402         return new Array(len - s.length + 1).join('0') + s;
403     };
404 
405     var a = [];
406 
407     // a[0], a[1]
408     var hex0 = hex.substr(0, 2);
409     var i0 = parseInt(hex0, 16);
410     a[0] = new String(Math.floor(i0 / 40));
411     a[1] = new String(i0 % 40);
412 
413     // a[2]..a[n]
414    var hex1 = hex.substr(2);
415     var b = [];
416     for (var i = 0; i < hex1.length / 2; i++) {
417     b.push(parseInt(hex1.substr(i * 2, 2), 16));
418     }
419     var c = [];
420     var cbin = "";
421     for (var i = 0; i < b.length; i++) {
422         if (b[i] & 0x80) {
423             cbin = cbin + zeroPadding((b[i] & 0x7f).toString(2), 7);
424         } else {
425             cbin = cbin + zeroPadding((b[i] & 0x7f).toString(2), 7);
426             c.push(new String(parseInt(cbin, 2)));
427             cbin = "";
428         }
429     }
430 
431     var s = a.join(".");
432     if (c.length > 0) s = s + "." + c.join(".");
433     return s;
434 };
435 
436 /**
437  * get string of simple ASN.1 dump from hexadecimal ASN.1 data<br/>
438  * @name dump
439  * @memberOf ASN1HEX
440  * @function
441  * @param {Object} hexOrObj hexadecmal string of ASN.1 data or ASN1Object object
442  * @param {Array} flags associative array of flags for dump (OPTION)
443  * @param {Number} idx string index for starting dump (OPTION)
444  * @param {String} indent indent string (OPTION)
445  * @return {String} string of simple ASN.1 dump
446  * @since jsrsasign 4.8.3 asn1hex 1.1.6
447  * @description
448  * This method will get an ASN.1 dump from
449  * hexadecmal string of ASN.1 DER encoded data.
450  * Here are features:
451  * <ul>
452  * <li>ommit long hexadecimal string</li>
453  * <li>dump encapsulated OCTET STRING (good for X.509v3 extensions)</li>
454  * <li>structured/primitive context specific tag support (i.e. [0], [3] ...)</li>
455  * <li>automatic decode for implicit primitive context specific tag 
456  * (good for X.509v3 extension value)
457  *   <ul>
458  *   <li>if hex starts '68747470'(i.e. http) it is decoded as utf8 encoded string.</li>
459  *   <li>if it is in 'subjectAltName' extension value and is '[2]'(dNSName) tag
460  *   value will be encoded as utf8 string</li>
461  *   <li>otherwise it shows as hexadecimal string</li>
462  *   </ul>
463  * </li>
464  * </ul>
465  * NOTE1: Argument {@link KJUR.asn1.ASN1Object} object is supported since
466  * jsrsasign 6.2.4 asn1hex 1.0.8
467  * @example
468  * // 1) ASN.1 INTEGER
469  * ASN1HEX.dump('0203012345')
470  * ↓
471  * INTEGER 012345
472  *
473  * // 2) ASN.1 Object Identifier
474  * ASN1HEX.dump('06052b0e03021a')
475  * ↓
476  * ObjectIdentifier sha1 (1 3 14 3 2 26)
477  *
478  * // 3) ASN.1 SEQUENCE
479  * ASN1HEX.dump('3006020101020102')
480  * ↓
481  * SEQUENCE
482  *   INTEGER 01
483  *   INTEGER 02
484  *
485  * // 4) ASN.1 SEQUENCE since jsrsasign 6.2.4
486  * o = KJUR.asn1.ASN1Util.newObject({seq: [{int: 1}, {int: 2}]});
487  * ASN1HEX.dump(o)
488  * ↓
489  * SEQUENCE
490  *   INTEGER 01
491  *   INTEGER 02
492  * // 5) ASN.1 DUMP FOR X.509 CERTIFICATE
493  * ASN1HEX.dump(pemtohex(certPEM))
494  * ↓
495  * SEQUENCE
496  *   SEQUENCE
497  *     [0]
498  *       INTEGER 02
499  *     INTEGER 0c009310d206dbe337553580118ddc87
500  *     SEQUENCE
501  *       ObjectIdentifier SHA256withRSA (1 2 840 113549 1 1 11)
502  *       NULL
503  *     SEQUENCE
504  *       SET
505  *         SEQUENCE
506  *           ObjectIdentifier countryName (2 5 4 6)
507  *           PrintableString 'US'
508  *             :
509  */
510 ASN1HEX.dump = function(hexOrObj, flags, idx, indent) {
511     var _ASN1HEX = ASN1HEX;
512     var _getV = _ASN1HEX.getV;
513     var _dump = _ASN1HEX.dump;
514     var _getChildIdx = _ASN1HEX.getChildIdx;
515 
516     var hex = hexOrObj;
517     if (hexOrObj instanceof KJUR.asn1.ASN1Object)
518 	hex = hexOrObj.getEncodedHex();
519 
520     var _skipLongHex = function(hex, limitNumOctet) {
521 	if (hex.length <= limitNumOctet * 2) {
522 	    return hex;
523 	} else {
524 	    var s = hex.substr(0, limitNumOctet) + 
525 		    "..(total " + hex.length / 2 + "bytes).." +
526 		    hex.substr(hex.length - limitNumOctet, limitNumOctet);
527 	    return s;
528 	};
529     };
530 
531     if (flags === undefined) flags = { "ommit_long_octet": 32 };
532     if (idx === undefined) idx = 0;
533     if (indent === undefined) indent = "";
534     var skipLongHex = flags.ommit_long_octet;
535 
536     if (hex.substr(idx, 2) == "01") {
537 	var v = _getV(hex, idx);
538 	if (v == "00") {
539 	    return indent + "BOOLEAN FALSE\n";
540 	} else {
541 	    return indent + "BOOLEAN TRUE\n";
542 	}
543     }
544     if (hex.substr(idx, 2) == "02") {
545 	var v = _getV(hex, idx);
546 	return indent + "INTEGER " + _skipLongHex(v, skipLongHex) + "\n";
547     }
548     if (hex.substr(idx, 2) == "03") {
549 	var v = _getV(hex, idx);
550 	return indent + "BITSTRING " + _skipLongHex(v, skipLongHex) + "\n";
551     }
552     if (hex.substr(idx, 2) == "04") {
553 	var v = _getV(hex, idx);
554 	if (_ASN1HEX.isASN1HEX(v)) {
555 	    var s = indent + "OCTETSTRING, encapsulates\n";
556 	    s = s + _dump(v, flags, 0, indent + "  ");
557 	    return s;
558 	} else {
559 	    return indent + "OCTETSTRING " + _skipLongHex(v, skipLongHex) + "\n";
560 	}
561     }
562     if (hex.substr(idx, 2) == "05") {
563 	return indent + "NULL\n";
564     }
565     if (hex.substr(idx, 2) == "06") {
566 	var hV = _getV(hex, idx);
567         var oidDot = KJUR.asn1.ASN1Util.oidHexToInt(hV);
568         var oidName = KJUR.asn1.x509.OID.oid2name(oidDot);
569 	var oidSpc = oidDot.replace(/\./g, ' ');
570         if (oidName != '') {
571   	    return indent + "ObjectIdentifier " + oidName + " (" + oidSpc + ")\n";
572 	} else {
573   	    return indent + "ObjectIdentifier (" + oidSpc + ")\n";
574 	}
575     }
576     if (hex.substr(idx, 2) == "0c") {
577 	return indent + "UTF8String '" + hextoutf8(_getV(hex, idx)) + "'\n";
578     }
579     if (hex.substr(idx, 2) == "13") {
580 	return indent + "PrintableString '" + hextoutf8(_getV(hex, idx)) + "'\n";
581     }
582     if (hex.substr(idx, 2) == "14") {
583 	return indent + "TeletexString '" + hextoutf8(_getV(hex, idx)) + "'\n";
584     }
585     if (hex.substr(idx, 2) == "16") {
586 	return indent + "IA5String '" + hextoutf8(_getV(hex, idx)) + "'\n";
587     }
588     if (hex.substr(idx, 2) == "17") {
589 	return indent + "UTCTime " + hextoutf8(_getV(hex, idx)) + "\n";
590     }
591     if (hex.substr(idx, 2) == "18") {
592 	return indent + "GeneralizedTime " + hextoutf8(_getV(hex, idx)) + "\n";
593     }
594     if (hex.substr(idx, 2) == "30") {
595 	if (hex.substr(idx, 4) == "3000") {
596 	    return indent + "SEQUENCE {}\n";
597 	}
598 
599 	var s = indent + "SEQUENCE\n";
600 	var aIdx = _getChildIdx(hex, idx);
601 
602 	var flagsTemp = flags;
603 	
604 	if ((aIdx.length == 2 || aIdx.length == 3) &&
605 	    hex.substr(aIdx[0], 2) == "06" &&
606 	    hex.substr(aIdx[aIdx.length - 1], 2) == "04") { // supposed X.509v3 extension
607 	    var oidName = _ASN1HEX.oidname(_getV(hex, aIdx[0]));
608 	    var flagsClone = JSON.parse(JSON.stringify(flags));
609 	    flagsClone.x509ExtName = oidName;
610 	    flagsTemp = flagsClone;
611 	}
612 	
613 	for (var i = 0; i < aIdx.length; i++) {
614 	    s = s + _dump(hex, flagsTemp, aIdx[i], indent + "  ");
615 	}
616 	return s;
617     }
618     if (hex.substr(idx, 2) == "31") {
619 	var s = indent + "SET\n";
620 	var aIdx = _getChildIdx(hex, idx);
621 	for (var i = 0; i < aIdx.length; i++) {
622 	    s = s + _dump(hex, flags, aIdx[i], indent + "  ");
623 	}
624 	return s;
625     }
626     var tag = parseInt(hex.substr(idx, 2), 16);
627     if ((tag & 128) != 0) { // context specific 
628 	var tagNumber = tag & 31;
629 	if ((tag & 32) != 0) { // structured tag
630 	    var s = indent + "[" + tagNumber + "]\n";
631 	    var aIdx = _getChildIdx(hex, idx);
632 	    for (var i = 0; i < aIdx.length; i++) {
633 		s = s + _dump(hex, flags, aIdx[i], indent + "  ");
634 	    }
635 	    return s;
636 	} else { // primitive tag
637 	    var v = _getV(hex, idx);
638 	    if (v.substr(0, 8) == "68747470") { // http
639 		v = hextoutf8(v);
640 	    }
641 	    if (flags.x509ExtName === "subjectAltName" &&
642 		tagNumber == 2) {
643 		v = hextoutf8(v);
644 	    }
645 	    
646 	    var s = indent + "[" + tagNumber + "] " + v + "\n";
647 	    return s;
648 	}
649     }
650     return indent + "UNKNOWN(" + hex.substr(idx, 2) + ") " + 
651 	   _getV(hex, idx) + "\n";
652 };
653 
654 /**
655  * check wheather the string is ASN.1 hexadecimal string or not
656  * @name isASN1HEX
657  * @memberOf ASN1HEX
658  * @function
659  * @param {String} hex string to check whether it is hexadecmal string for ASN.1 DER or not
660  * @return {Boolean} true if it is hexadecimal string of ASN.1 data otherwise false
661  * @since jsrsasign 4.8.3 asn1hex 1.1.6
662  * @description
663  * This method checks wheather the argument 'hex' is a hexadecimal string of
664  * ASN.1 data or not.
665  * @example
666  * ASN1HEX.isASN1HEX('0203012345') → true // PROPER ASN.1 INTEGER
667  * ASN1HEX.isASN1HEX('0203012345ff') → false // TOO LONG VALUE
668  * ASN1HEX.isASN1HEX('02030123') → false // TOO SHORT VALUE
669  * ASN1HEX.isASN1HEX('fa3bcd') → false // WRONG FOR ASN.1
670  */
671 ASN1HEX.isASN1HEX = function(hex) {
672     var _ASN1HEX = ASN1HEX;
673     if (hex.length % 2 == 1) return false;
674 
675     var intL = _ASN1HEX.getVblen(hex, 0);
676     var tV = hex.substr(0, 2);
677     var lV = _ASN1HEX.getL(hex, 0);
678     var hVLength = hex.length - tV.length - lV.length;
679     if (hVLength == intL * 2) return true;
680 
681     return false;
682 };
683 
684 /**
685  * get hexacedimal string from PEM format data<br/>
686  * @name oidname
687  * @memberOf ASN1HEX
688  * @function
689  * @param {String} oidDotOrHex number dot notation(i.e. 1.2.3) or hexadecimal string for OID
690  * @return {String} name for OID
691  * @since jsrsasign 7.2.0 asn1hex 1.1.11
692  * @description
693  * This static method gets a OID name for
694  * a specified string of number dot notation (i.e. 1.2.3) or
695  * hexadecimal string.
696  * @example
697  * ASN1HEX.oidname("2.5.29.37") → extKeyUsage
698  * ASN1HEX.oidname("551d25") → extKeyUsage
699  * ASN1HEX.oidname("0.1.2.3") → 0.1.2.3 // unknown
700  */
701 ASN1HEX.oidname = function(oidDotOrHex) {
702     var _KJUR_asn1 = KJUR.asn1;
703     if (KJUR.lang.String.isHex(oidDotOrHex))
704 	oidDotOrHex = _KJUR_asn1.ASN1Util.oidHexToInt(oidDotOrHex);
705     var name = _KJUR_asn1.x509.OID.oid2name(oidDotOrHex);
706     if (name === "") name = oidDotOrHex;
707     return name;
708 };
709 
710