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