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