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