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