JavaScript generic ASN.1 parser (mirror)

Compare changes

Choose any two refs to compare.

+2101 -336
+10
.editorconfig
···
··· 1 + root = true 2 + end_of_line = lf 3 + max_line_length = 120 4 + 5 + [*.{js,css}] 6 + charset = utf-8 7 + indent_size = 4 8 + indent_style = space 9 + insert_final_newline = true 10 + trim_trailing_whitespace = true
+9 -5
.github/workflows/node.js.yml
··· 12 13 strategy: 14 matrix: 15 - node-version: [ 12.20.0, latest ] 16 17 steps: 18 - uses: actions/checkout@v4 19 - name: Use Node.js ${{ matrix.node-version }} 20 uses: actions/setup-node@v4 21 with: 22 node-version: ${{ matrix.node-version }} 23 - - run: npm test all 24 - - run: npm install 25 - if: matrix.node-version == 'latest' 26 - - run: npm run lint 27 if: matrix.node-version == 'latest'
··· 12 13 strategy: 14 matrix: 15 + node-version: [ 14.6.0, latest ] 16 17 steps: 18 - uses: actions/checkout@v4 19 + - name: Use pnpm 20 + uses: pnpm/action-setup@v4 21 + with: 22 + run_install: false 23 - name: Use Node.js ${{ matrix.node-version }} 24 uses: actions/setup-node@v4 25 with: 26 node-version: ${{ matrix.node-version }} 27 + cache: pnpm 28 + - run: pnpm install 29 + - run: node test all 30 + - run: pnpm run lint 31 if: matrix.node-version == 'latest'
-1
.gitignore
··· 4 node_modules/ 5 dist/ 6 package-lock.json 7 - pnpm-lock.yaml 8 # Artifacts from release.sh 9 index-local.html 10 sha256sums.asc
··· 4 node_modules/ 5 dist/ 6 package-lock.json 7 # Artifacts from release.sh 8 index-local.html 9 sha256sums.asc
+1 -2
.mtn-ignore
··· 3 node_modules$ 4 dist$ 5 package-lock[.]json 6 - pnpm-lock[.]yaml 7 # Artifacts from release.sh 8 index-local.html 9 sha256sums[.]asc ··· 12 git-[^.]*[.]txt 13 # Artifacts from updateOID.sh 14 dumpasn1[.]cfg 15 - # Artifacts from parseRFC.js 16 rfc$ 17 rfcdef[.]json
··· 3 node_modules$ 4 dist$ 5 package-lock[.]json 6 # Artifacts from release.sh 7 index-local.html 8 sha256sums[.]asc ··· 11 git-[^.]*[.]txt 12 # Artifacts from updateOID.sh 13 dumpasn1[.]cfg 14 + # Artifacts from updateRFC.sh / parseRFC.js 15 rfc$ 16 rfcdef[.]json
+64
.vscode/launch.json
··· 7 { 8 "type": "node", 9 "request": "launch", 10 "name": "parseRFC", 11 "skipFiles": [ 12 "<node_internals>/**" ··· 15 "args": [ 16 "rfc/rfc4511.txt", 17 "rfcdef.json" 18 ] 19 }, 20 {
··· 7 { 8 "type": "node", 9 "request": "launch", 10 + "name": "test", 11 + "skipFiles": [ 12 + "<node_internals>/**" 13 + ], 14 + "program": "${workspaceFolder}/test.js", 15 + "args": [] 16 + }, 17 + { 18 + "type": "node", 19 + "request": "launch", 20 + "name": "dumpASN1", 21 + "skipFiles": [ 22 + "<node_internals>/**" 23 + ], 24 + "program": "${workspaceFolder}/dumpASN1.js", 25 + "args": [ 26 + "examples/ed25519.cer" 27 + ] 28 + }, 29 + { 30 + "type": "node", 31 + "request": "launch", 32 "name": "parseRFC", 33 "skipFiles": [ 34 "<node_internals>/**" ··· 37 "args": [ 38 "rfc/rfc4511.txt", 39 "rfcdef.json" 40 + ] 41 + }, 42 + { 43 + "type": "node", 44 + "request": "launch", 45 + "name": "dumpASN1 X.509", 46 + "skipFiles": [ 47 + "<node_internals>/**" 48 + ], 49 + "program": "${workspaceFolder}/dumpASN1.js", 50 + "args": [ 51 + "examples/ed25519.cer", 52 + "1.3.6.1.5.5.7.0.18", 53 + "Certificate" 54 + ] 55 + }, 56 + { 57 + "type": "node", 58 + "request": "launch", 59 + "name": "dumpASN1 CRL", 60 + "skipFiles": [ 61 + "<node_internals>/**" 62 + ], 63 + "program": "${workspaceFolder}/dumpASN1.js", 64 + "args": [ 65 + "data:base64,MIG9AgEBMA0GCSqGSIb3DQEBCwUAMEExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxUUjM0IFNhbXBsZXMxGzAZBgNVBAMTElRSMzQgU2FtcGxlIENBIEtESBcNMTAxMTAyMTczMzMwWhcNMTAxMjAyMTczMzMwWjBIMBYCBTQAAAAIFw0xMDExMDIxNzI4MTNaMBYCBTQAAAAKFw0xMDExMDIxNzMxNDZaMBYCBTQAAAALFw0xMDExMDIxNzMzMjVa", 66 + "1.3.6.1.5.5.7.0.18", 67 + "TBSCertList" 68 + ] 69 + }, 70 + { 71 + "type": "node", 72 + "request": "launch", 73 + "name": "dumpASN1 CMS", 74 + "skipFiles": [ 75 + "<node_internals>/**" 76 + ], 77 + "program": "${workspaceFolder}/dumpASN1.js", 78 + "args": [ 79 + "examples/cms-password.p7m", 80 + "1.2.840.113549.1.9.16.0.14", 81 + "ContentInfo" 82 ] 83 }, 84 {
+2 -2
.vscode/settings.json
··· 1 { 2 "editor.insertSpaces": true, 3 "editor.tabSize": 8, 4 - "editor.indentSize": 2, 5 "editor.stickyScroll.enabled": true, 6 "explorer.excludeGitIgnore": true, 7 "files.eol": "\n", 8 "git.openRepositoryInParentFolders": "never" 9 - }
··· 1 { 2 "editor.insertSpaces": true, 3 "editor.tabSize": 8, 4 + "editor.indentSize": 4, 5 "editor.stickyScroll.enabled": true, 6 "explorer.excludeGitIgnore": true, 7 "files.eol": "\n", 8 "git.openRepositoryInParentFolders": "never" 9 + }
+38
CHANGELOG.md
···
··· 1 + # ChangeLog 2 + 3 + ## 2.1.1 - 2025-10-24 4 + 5 + ### Changed 6 + 7 + - update dev dependencies 8 + - fix test suite that was reporting no error with empty responses 9 + 10 + ### Added 11 + 12 + - add content length check for BOOLEAN, INTEGER, OID ([GitHub #104](https://github.com/lapo-luchini/asn1js/pull/104)) 13 + 14 + ## 2.1.0 - 2025-08-03 15 + 16 + ### Changed 17 + 18 + - when fields are CHOICEs now both the field name and the choice name are shown (fixes [GitHub #102](https://github.com/lapo-luchini/asn1js/issues/102)) 19 + - upgrade minimum NodeJS version supported from 12.20.0 to 14.6.0 due to usage of ?. and ?? operators in defs.js (ECMAScript 2020); older code is still linted against ECMAScript 2015 for now 20 + 21 + ### Added 22 + 23 + - add tests to check expected decoding 24 + 25 + ## 2.0.6 - 2025-07-29 26 + 27 + ### Added 28 + 29 + - add proper support for standard Base64 (we previously only supported Base64url) (fixes [GitHub #99](https://github.com/lapo-luchini/asn1js/pull/99)) 30 + - improve test harness 31 + 32 + ## 2.0.5 - 2025-04-12 33 + 34 + ### Added 35 + 36 + - add `index-local.html` for local `file://` usage without needing a web server 37 + - add definitions support for `LDAPMessage` 38 + - #TODO continue producing old ChangeLog entries
+5 -3
README.md
··· 101 links 102 ----- 103 104 - - [official website](https://lapo.it/asn1js/) 105 - - [dedicated domain](https://asn1js.eu/) 106 - - [InDefero tracker](http://idf.lapo.it/p/asn1js/) 107 - [GitHub mirror](https://github.com/lapo-luchini/asn1js) 108 - [Ohloh code stats](https://www.openhub.net/p/asn1js)
··· 101 links 102 ----- 103 104 + - [official website](https://asn1js.eu/) 105 + - [alternate website](https://lapo.it/asn1js/) 106 + - [single-file version working locally](https://asn1js.eu/index-local.html) (just save this link) 107 + - [InDefero tracker](http://idf.lapo.it/p/asn1js/) (currently offline) 108 - [GitHub mirror](https://github.com/lapo-luchini/asn1js) 109 + - [ChangeLog on GitHub](https://github.com/lapo-luchini/asn1js/blob/trunk/CHANGELOG.md) 110 - [Ohloh code stats](https://www.openhub.net/p/asn1js)
+289 -79
asn1.js
··· 13 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 16 - import { Int10 } from './int10.js'; 17 import { oids } from './oids.js'; 18 19 const ··· 21 reTimeS = /^(\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|(-(?:0\d|1[0-2])|[+](?:0\d|1[0-4]))([0-5]\d)?)?$/, 22 reTimeL = /^(\d\d\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|(-(?:0\d|1[0-2])|[+](?:0\d|1[0-4]))([0-5]\d)?)?$/, 23 hexDigits = '0123456789ABCDEF', 24 - b64Safe = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', 25 tableT61 = [ 26 ['', ''], 27 ['AEIOUaeiou', 'ร€รˆรŒร’ร™ร รจรฌรฒรน'], // Grave ··· 41 ['CDELNRSTZcdelnrstz', 'ฤŒฤŽฤšฤฝล‡ล˜ล ลคลฝฤฤฤ›ฤพลˆล™ลกลฅลพ'], // Caron 42 ]; 43 44 function stringCut(str, len) { 45 if (str.length > len) 46 str = str.substring(0, len) + ellipsis; 47 return str; 48 } 49 50 function checkPrintable(s) { 51 let i, v; 52 for (i = 0; i < s.length; ++i) { ··· 56 } 57 } 58 59 - /** Class to manage a stream of bytes, with a zero-copy approach. 60 - * It uses an existing array or binary string and advances a position index. */ 61 - class Stream { 62 63 /** 64 * @param {Stream|array|string} enc data (will not be copied) 65 * @param {?number} pos starting position (mandatory when `end` is not a Stream) 66 */ ··· 74 } 75 if (typeof this.pos != 'number') 76 throw new Error('"pos" must be a numeric value'); 77 if (typeof this.enc == 'string') 78 this.getRaw = pos => this.enc.charCodeAt(pos); 79 else if (typeof this.enc[0] == 'number') ··· 81 else 82 throw new Error('"enc" must be a numeric array or a string'); 83 } 84 - /** Get the byte at current position (and increment it) or at a specified position (and avoid moving current position). 85 - * @param {?number} pos read position if specified, else current position (and increment it) */ 86 get(pos) { 87 if (pos === undefined) 88 pos = this.pos++; ··· 90 throw new Error('Requesting byte offset ' + pos + ' on a stream of length ' + this.enc.length); 91 return this.getRaw(pos); 92 } 93 - /** Convert a single byte to an hexadcimal string (of length 2). 94 - * @param {number} b */ 95 static hexByte(b) { 96 return hexDigits.charAt((b >> 4) & 0xF) + hexDigits.charAt(b & 0xF); 97 } 98 - /** Hexadecimal dump of a specified region of the stream. 99 - * @param {number} start starting position (included) 100 - * @param {number} end ending position (excluded) 101 - * @param {string} type 'raw', 'byte' or 'dump' */ 102 hexDump(start, end, type = 'dump') { 103 let s = ''; 104 for (let i = start; i < end; ++i) { ··· 114 } 115 return s; 116 } 117 - /** Base-64 dump of a specified region of the stream. 118 - * @param {number} start starting position (included) 119 - * @param {number} end ending position (excluded) */ 120 - b64Dump(start, end) { 121 - let extra = (end - start) % 3, 122 - s = '', 123 i, c; 124 for (i = start; i + 2 < end; i += 3) { 125 c = this.get(i) << 16 | this.get(i + 1) << 8 | this.get(i + 2); 126 - s += b64Safe.charAt(c >> 18 & 0x3F); 127 - s += b64Safe.charAt(c >> 12 & 0x3F); 128 - s += b64Safe.charAt(c >> 6 & 0x3F); 129 - s += b64Safe.charAt(c & 0x3F); 130 } 131 if (extra > 0) { 132 c = this.get(i) << 16; 133 if (extra > 1) c |= this.get(i + 1) << 8; 134 - s += b64Safe.charAt(c >> 18 & 0x3F); 135 - s += b64Safe.charAt(c >> 12 & 0x3F); 136 - if (extra == 2) s += b64Safe.charAt(c >> 6 & 0x3F); 137 } 138 return s; 139 } 140 isASCII(start, end) { 141 for (let i = start; i < end; ++i) { 142 let c = this.get(i); ··· 145 } 146 return true; 147 } 148 parseStringISO(start, end, maxLength) { 149 let s = ''; 150 for (let i = start; i < end; ++i) 151 s += String.fromCharCode(this.get(i)); 152 return { size: s.length, str: stringCut(s, maxLength) }; 153 } 154 parseStringT61(start, end, maxLength) { 155 // warning: this code is not very well tested so far 156 function merge(c, d) { 157 - let t = tableT61[c - 0xC0]; 158 - let i = t[0].indexOf(String.fromCharCode(d)); 159 return (i < 0) ? '\0' : t[1].charAt(i); 160 } 161 let s = '', c; ··· 172 } 173 return { size: s.length, str: stringCut(s, maxLength) }; 174 } 175 parseStringUTF(start, end, maxLength) { 176 function ex(c) { // must be 10xxxxxx 177 if ((c < 0x80) || (c >= 0xC0)) 178 throw new Error('Invalid UTF-8 continuation byte: ' + c); 179 return (c & 0x3F); 180 } 181 function surrogate(cp) { 182 if (cp < 0x10000) 183 throw new Error('UTF-8 overlong encoding, codepoint encoded in 4 bytes: ' + cp); ··· 187 } 188 let s = ''; 189 for (let i = start; i < end; ) { 190 - let c = this.get(i++); 191 if (c < 0x80) // 0xxxxxxx (7 bit) 192 s += String.fromCharCode(c); 193 else if (c < 0xC0) ··· 203 } 204 return { size: s.length, str: stringCut(s, maxLength) }; 205 } 206 parseStringBMP(start, end, maxLength) { 207 let s = '', hi, lo; 208 for (let i = start; i < end; ) { ··· 212 } 213 return { size: s.length, str: stringCut(s, maxLength) }; 214 } 215 parseTime(start, end, shortYear) { 216 let s = this.parseStringISO(start, end).str, 217 m = (shortYear ? reTimeS : reTimeL).exec(s); ··· 239 } 240 return s; 241 } 242 parseInteger(start, end) { 243 let v = this.get(start), 244 - neg = (v > 127), 245 - pad = neg ? 255 : 0, 246 - len, 247 s = ''; 248 // skip unuseful bits (not allowed in DER) 249 while (v == pad && ++start < end) 250 v = this.get(start); 251 - len = end - start; 252 if (len === 0) 253 return neg ? '-1' : '0'; 254 // show bit length of huge integers 255 if (len > 4) { 256 - s = v; 257 - len <<= 3; 258 - while (((s ^ pad) & 0x80) == 0) { 259 - s <<= 1; 260 - --len; 261 } 262 - s = '(' + len + ' bit)\n'; 263 } 264 // decode the integer 265 if (neg) v = v - 256; 266 - let n = new Int10(v); 267 for (let i = start + 1; i < end; ++i) 268 - n.mulAdd(256, this.get(i)); 269 - return s + n.toString(); 270 } 271 parseBitString(start, end, maxLength) { 272 - let unusedBits = this.get(start); 273 if (unusedBits > 7) 274 throw new Error('Invalid BitString with unusedBits=' + unusedBits); 275 - let lenBit = ((end - start - 1) << 3) - unusedBits, 276 - s = ''; 277 for (let i = start + 1; i < end; ++i) { 278 let b = this.get(i), 279 skip = (i == end - 1) ? unusedBits : 0; ··· 284 } 285 return { size: lenBit, str: s }; 286 } 287 parseOctetString(start, end, maxLength) { 288 - let len = end - start, 289 - s; 290 try { 291 - s = this.parseStringUTF(start, end, maxLength); 292 checkPrintable(s.str); 293 return { size: end - start, str: s.str }; 294 - } catch (e) { 295 - // ignore 296 } 297 maxLength /= 2; // we work in bytes 298 if (len > maxLength) 299 end = start + maxLength; 300 - s = ''; 301 for (let i = start; i < end; ++i) 302 s += Stream.hexByte(this.get(i)); 303 if (len > maxLength) 304 s += ellipsis; 305 return { size: len, str: s }; 306 } 307 parseOID(start, end, maxLength, isRelative) { 308 let s = '', 309 - n = new Int10(), 310 bits = 0; 311 for (let i = start; i < end; ++i) { 312 let v = this.get(i); 313 - n.mulAdd(128, v & 0x7F); 314 bits += 7; 315 if (!(v & 0x80)) { // finished 316 if (s === '') { 317 - n = n.simplify(); 318 if (isRelative) { 319 - s = (n instanceof Int10) ? n.toString() : '' + n; 320 - } else if (n instanceof Int10) { 321 - n.sub(80); 322 - s = '2.' + n.toString(); 323 } else { 324 - let m = n < 80 ? n < 40 ? 0 : 1 : 2; 325 - s = m + '.' + (n - m * 40); 326 } 327 } else 328 - s += '.' + n.toString(); 329 if (s.length > maxLength) 330 return stringCut(s, maxLength); 331 - n = new Int10(); 332 bits = 0; 333 } 334 } 335 if (bits > 0) 336 s += '.incomplete'; 337 if (typeof oids === 'object' && !isRelative) { 338 let oid = oids[s]; 339 if (oid) { ··· 344 } 345 return s; 346 } 347 parseRelativeOID(start, end, maxLength) { 348 return this.parseOID(start, end, maxLength, true); 349 } ··· 376 this.tagConstructed = ((buf & 0x20) !== 0); 377 this.tagNumber = buf & 0x1F; 378 if (this.tagNumber == 0x1F) { // long tag 379 - let n = new Int10(); 380 do { 381 buf = stream.get(); 382 - n.mulAdd(128, buf & 0x7F); 383 } while (buf & 0x80); 384 - this.tagNumber = n.simplify(); 385 } 386 } 387 isUniversal() { ··· 392 } 393 } 394 395 export class ASN1 { 396 constructor(stream, header, length, tag, tagLen, sub) { 397 if (!(tag instanceof ASN1Tag)) throw new Error('Invalid tag value.'); 398 this.stream = stream; ··· 402 this.tagLen = tagLen; 403 this.sub = sub; 404 } 405 typeName() { 406 switch (this.tag.tagClass) { 407 case 0: // universal ··· 441 case 3: return 'Private_' + this.tag.tagNumber.toString(); 442 } 443 } 444 - /** A string preview of the content (intended for humans). */ 445 content(maxLength) { 446 if (this.tag === undefined) 447 return null; 448 if (maxLength === undefined) 449 maxLength = Infinity; 450 - let content = this.posContent(), 451 len = Math.abs(this.length); 452 if (!this.tag.isUniversal()) { 453 if (this.sub !== null) ··· 457 } 458 switch (this.tag.tagNumber) { 459 case 0x01: // BOOLEAN 460 return (this.stream.get(content) === 0) ? 'false' : 'true'; 461 case 0x02: // INTEGER 462 return this.stream.parseInteger(content, content + len); 463 case 0x03: { // BIT_STRING 464 let d = recurse(this, 'parseBitString', maxLength); ··· 470 } 471 //case 0x05: // NULL 472 case 0x06: // OBJECT_IDENTIFIER 473 return this.stream.parseOID(content, content + len, maxLength); 474 //case 0x07: // ObjectDescriptor 475 //case 0x08: // EXTERNAL ··· 506 } 507 return null; 508 } 509 toString() { 510 return this.typeName() + '@' + this.stream.pos + '[header:' + this.header + ',length:' + this.length + ',sub:' + ((this.sub === null) ? 'null' : this.sub.length) + ']'; 511 } 512 toPrettyString(indent) { 513 if (indent === undefined) indent = ''; 514 let s = indent; ··· 539 } 540 return s; 541 } 542 posStart() { 543 return this.stream.pos; 544 } 545 posContent() { 546 return this.stream.pos + this.header; 547 } 548 posEnd() { 549 return this.stream.pos + this.header + Math.abs(this.length); 550 } 551 - /** Position of the length. */ 552 posLen() { 553 return this.stream.pos + this.tagLen; 554 } 555 - /** Hexadecimal dump of the node. 556 - * @param type 'raw', 'byte' or 'dump' */ 557 toHexString(type = 'raw') { 558 return this.stream.hexDump(this.posStart(), this.posEnd(), type); 559 } 560 - /** Base64 dump of the node. */ 561 - toB64String() { 562 - return this.stream.b64Dump(this.posStart(), this.posEnd()); 563 } 564 static decodeLength(stream) { 565 - let buf = stream.get(), 566 len = buf & 0x7F; 567 if (len == buf) // first bit was 0, short form 568 return len; 569 if (len === 0) // long form with length 0 is a special case 570 return null; // undefined length 571 - if (len > 6) // no reason to use Int10, as it would be a huge buffer anyways 572 throw new Error('Length over 48 bits not supported at position ' + (stream.pos - 1)); 573 - buf = 0; 574 for (let i = 0; i < len; ++i) 575 - buf = (buf * 256) + stream.get(); 576 - return buf; 577 } 578 static decode(stream, offset, type = ASN1) { 579 if (!(type == ASN1 || type.prototype instanceof ASN1)) 580 throw new Error('Must pass a class that extends ASN1'); ··· 632 throw new Error('Unable to parse content: ' + e); 633 } 634 } 635 - } catch (e) { 636 // but silently ignore when they don't 637 sub = null; 638 //DEBUG console.log('Could not decode structure at ' + start + ':', e);
··· 13 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 16 import { oids } from './oids.js'; 17 18 const ··· 20 reTimeS = /^(\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|(-(?:0\d|1[0-2])|[+](?:0\d|1[0-4]))([0-5]\d)?)?$/, 21 reTimeL = /^(\d\d\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|(-(?:0\d|1[0-2])|[+](?:0\d|1[0-4]))([0-5]\d)?)?$/, 22 hexDigits = '0123456789ABCDEF', 23 + b64Std = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', 24 + b64URL = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', 25 tableT61 = [ 26 ['', ''], 27 ['AEIOUaeiou', 'ร€รˆรŒร’ร™ร รจรฌรฒรน'], // Grave ··· 41 ['CDELNRSTZcdelnrstz', 'ฤŒฤŽฤšฤฝล‡ล˜ล ลคลฝฤฤฤ›ฤพลˆล™ลกลฅลพ'], // Caron 42 ]; 43 44 + /** 45 + * Truncates a string to a specified length and adds an ellipsis if needed. 46 + * @param {string} str - The input string to truncate 47 + * @param {number} len - The maximum length of the string 48 + * @returns {string} The truncated string 49 + */ 50 function stringCut(str, len) { 51 if (str.length > len) 52 str = str.substring(0, len) + ellipsis; 53 return str; 54 } 55 56 + /** 57 + * Checks if a string contains only printable characters (ASCII 32-126, plus tab, newline, carriage return) 58 + * @param {string} s - The string to check 59 + * @throws {Error} If an unprintable character is found 60 + */ 61 function checkPrintable(s) { 62 let i, v; 63 for (i = 0; i < s.length; ++i) { ··· 67 } 68 } 69 70 + /** 71 + * Class to manage a stream of bytes, with a zero-copy approach. 72 + * It uses an existing array or binary string and advances a position index. 73 + */ 74 + export class Stream { 75 76 /** 77 + * Creates a new Stream object. 78 * @param {Stream|array|string} enc data (will not be copied) 79 * @param {?number} pos starting position (mandatory when `end` is not a Stream) 80 */ ··· 88 } 89 if (typeof this.pos != 'number') 90 throw new Error('"pos" must be a numeric value'); 91 + // Set up the raw byte access function based on the type of data 92 if (typeof this.enc == 'string') 93 this.getRaw = pos => this.enc.charCodeAt(pos); 94 else if (typeof this.enc[0] == 'number') ··· 96 else 97 throw new Error('"enc" must be a numeric array or a string'); 98 } 99 + 100 + /** 101 + * Get the byte at current position (and increment it) or at a specified position (and avoid moving current position). 102 + * @param {?number} pos read position if specified, else current position (and increment it) 103 + * @returns {number} The byte value at the specified position 104 + */ 105 get(pos) { 106 if (pos === undefined) 107 pos = this.pos++; ··· 109 throw new Error('Requesting byte offset ' + pos + ' on a stream of length ' + this.enc.length); 110 return this.getRaw(pos); 111 } 112 + 113 + /** 114 + * Convert a single byte to a hexadecimal string (of length 2). 115 + * @param {number} b - The byte to convert 116 + * @returns {string} Hexadecimal representation of the byte 117 + */ 118 static hexByte(b) { 119 return hexDigits.charAt((b >> 4) & 0xF) + hexDigits.charAt(b & 0xF); 120 } 121 + 122 + /** 123 + * Hexadecimal dump of a specified region of the stream. 124 + * @param {number} start - starting position (included) 125 + * @param {number} end - ending position (excluded) 126 + * @param {string} type - 'raw', 'byte' or 'dump' (default) 127 + * @returns {string} Hexadecimal representation of the data 128 + */ 129 hexDump(start, end, type = 'dump') { 130 let s = ''; 131 for (let i = start; i < end; ++i) { ··· 141 } 142 return s; 143 } 144 + 145 + /** 146 + * Base64url dump of a specified region of the stream (according to RFC 4648 section 5). 147 + * @param {number} start - starting position (included) 148 + * @param {number} end - ending position (excluded) 149 + * @param {string} type - 'url' (default, section 5 without padding) or 'std' (section 4 with padding) 150 + * @returns {string} Base64 encoded representation of the data 151 + */ 152 + b64Dump(start, end, type = 'url') { 153 + const b64 = type === 'url' ? b64URL : b64Std, 154 + extra = (end - start) % 3; 155 + let s = '', 156 i, c; 157 for (i = start; i + 2 < end; i += 3) { 158 c = this.get(i) << 16 | this.get(i + 1) << 8 | this.get(i + 2); 159 + s += b64.charAt(c >> 18 & 0x3F); 160 + s += b64.charAt(c >> 12 & 0x3F); 161 + s += b64.charAt(c >> 6 & 0x3F); 162 + s += b64.charAt(c & 0x3F); 163 } 164 if (extra > 0) { 165 c = this.get(i) << 16; 166 if (extra > 1) c |= this.get(i + 1) << 8; 167 + s += b64.charAt(c >> 18 & 0x3F); 168 + s += b64.charAt(c >> 12 & 0x3F); 169 + if (extra == 2) s += b64.charAt(c >> 6 & 0x3F); 170 + if (b64 === b64Std) s += '==='.slice(0, 3 - extra); 171 } 172 return s; 173 } 174 + 175 + /** 176 + * Check if a region of the stream contains only ASCII characters (32-176) 177 + * @param {number} start - starting position (included) 178 + * @param {number} end - ending position (excluded) 179 + * @returns {boolean} True if all characters are ASCII, false otherwise 180 + */ 181 isASCII(start, end) { 182 for (let i = start; i < end; ++i) { 183 let c = this.get(i); ··· 186 } 187 return true; 188 } 189 + 190 + /** 191 + * Parse a region of the stream as an ISO string 192 + * @param {number} start - starting position (included) 193 + * @param {number} end - ending position (excluded) 194 + * @param {number} maxLength - maximum length of the output string 195 + * @returns {Object} Object with size and str properties 196 + */ 197 parseStringISO(start, end, maxLength) { 198 let s = ''; 199 for (let i = start; i < end; ++i) 200 s += String.fromCharCode(this.get(i)); 201 return { size: s.length, str: stringCut(s, maxLength) }; 202 } 203 + 204 + /** 205 + * Parse a region of the stream as a T.61 string 206 + * @param {number} start - starting position (included) 207 + * @param {number} end - ending position (excluded) 208 + * @param {number} maxLength - maximum length of the output string 209 + * @returns {Object} Object with size and str properties 210 + */ 211 parseStringT61(start, end, maxLength) { 212 // warning: this code is not very well tested so far 213 function merge(c, d) { 214 + const t = tableT61[c - 0xC0]; 215 + const i = t[0].indexOf(String.fromCharCode(d)); 216 return (i < 0) ? '\0' : t[1].charAt(i); 217 } 218 let s = '', c; ··· 229 } 230 return { size: s.length, str: stringCut(s, maxLength) }; 231 } 232 + 233 + /** 234 + * Parse a region of the stream as a UTF-8 string 235 + * @param {number} start - starting position (included) 236 + * @param {number} end - ending position (excluded) 237 + * @param {number} maxLength - maximum length of the output string 238 + * @returns {Object} Object with size and str properties 239 + */ 240 parseStringUTF(start, end, maxLength) { 241 + /** 242 + * Helper function to process UTF-8 continuation bytes 243 + * @param {number} c - The continuation byte 244 + * @returns {number} The extracted data bits 245 + */ 246 function ex(c) { // must be 10xxxxxx 247 if ((c < 0x80) || (c >= 0xC0)) 248 throw new Error('Invalid UTF-8 continuation byte: ' + c); 249 return (c & 0x3F); 250 } 251 + /** 252 + * Helper function to convert a code point to a surrogate pair 253 + * @param {number} cp - The code point to convert 254 + * @returns {string} The surrogate pair as a string 255 + */ 256 function surrogate(cp) { 257 if (cp < 0x10000) 258 throw new Error('UTF-8 overlong encoding, codepoint encoded in 4 bytes: ' + cp); ··· 262 } 263 let s = ''; 264 for (let i = start; i < end; ) { 265 + const c = this.get(i++); 266 if (c < 0x80) // 0xxxxxxx (7 bit) 267 s += String.fromCharCode(c); 268 else if (c < 0xC0) ··· 278 } 279 return { size: s.length, str: stringCut(s, maxLength) }; 280 } 281 + 282 + /** 283 + * Parse a region of the stream as a BMP (Basic Multilingual Plane) string 284 + * @param {number} start - starting position (included) 285 + * @param {number} end - ending position (excluded) 286 + * @param {number} maxLength - maximum length of the output string 287 + * @returns {Object} Object with size and str properties 288 + */ 289 parseStringBMP(start, end, maxLength) { 290 let s = '', hi, lo; 291 for (let i = start; i < end; ) { ··· 295 } 296 return { size: s.length, str: stringCut(s, maxLength) }; 297 } 298 + 299 + /** 300 + * Parse a region of the stream as a time string 301 + * @param {number} start - starting position (included) 302 + * @param {number} end - ending position (excluded) 303 + * @param {boolean} shortYear - Whether to parse as short year (2-digit) 304 + * @returns {string} Formatted time string 305 + */ 306 parseTime(start, end, shortYear) { 307 let s = this.parseStringISO(start, end).str, 308 m = (shortYear ? reTimeS : reTimeL).exec(s); ··· 330 } 331 return s; 332 } 333 + 334 + /** 335 + * Parse a region of the stream as an integer 336 + * @param {number} start - starting position (included) 337 + * @param {number} end - ending position (excluded) 338 + * @returns {string} Formatted integer string 339 + */ 340 parseInteger(start, end) { 341 let v = this.get(start), 342 s = ''; 343 + const neg = (v > 127), 344 + pad = neg ? 255 : 0; 345 // skip unuseful bits (not allowed in DER) 346 while (v == pad && ++start < end) 347 v = this.get(start); 348 + const len = end - start; 349 if (len === 0) 350 return neg ? '-1' : '0'; 351 // show bit length of huge integers 352 if (len > 4) { 353 + let v2 = v, 354 + lenBit = len << 3; 355 + while (((v2 ^ pad) & 0x80) == 0) { 356 + v2 <<= 1; 357 + --lenBit; 358 } 359 + s = '(' + lenBit + ' bit)\n'; 360 } 361 // decode the integer 362 if (neg) v = v - 256; 363 + let n = BigInt(v); 364 for (let i = start + 1; i < end; ++i) 365 + n = (n << 8n) | BigInt(this.get(i)); 366 + return s + n; 367 } 368 + 369 + /** 370 + * Parse a region of the stream as a bit string. 371 + * @param {number} start - starting position (included) 372 + * @param {number} end - ending position (excluded) 373 + * @param {number} maxLength - maximum length of the output string 374 + * @returns {Object} Object with size and str properties 375 + */ 376 parseBitString(start, end, maxLength) { 377 + const unusedBits = this.get(start); 378 if (unusedBits > 7) 379 throw new Error('Invalid BitString with unusedBits=' + unusedBits); 380 + const lenBit = ((end - start - 1) << 3) - unusedBits; 381 + let s = ''; 382 for (let i = start + 1; i < end; ++i) { 383 let b = this.get(i), 384 skip = (i == end - 1) ? unusedBits : 0; ··· 389 } 390 return { size: lenBit, str: s }; 391 } 392 + 393 + /** 394 + * Parse a region of the stream as an octet string. 395 + * @param {number} start - starting position (included) 396 + * @param {number} end - ending position (excluded) 397 + * @param {number} maxLength - maximum length of the output string 398 + * @returns {Object} Object with size and str properties 399 + */ 400 parseOctetString(start, end, maxLength) { 401 try { 402 + let s = this.parseStringUTF(start, end, maxLength); 403 checkPrintable(s.str); 404 return { size: end - start, str: s.str }; 405 + } catch (ignore) { 406 + // If UTF-8 parsing fails, fall back to hexadecimal dump 407 } 408 + const len = end - start; 409 maxLength /= 2; // we work in bytes 410 if (len > maxLength) 411 end = start + maxLength; 412 + let s = ''; 413 for (let i = start; i < end; ++i) 414 s += Stream.hexByte(this.get(i)); 415 if (len > maxLength) 416 s += ellipsis; 417 return { size: len, str: s }; 418 } 419 + 420 + /** 421 + * Parse a region of the stream as an OID (Object Identifier). 422 + * @param {number} start - starting position (included) 423 + * @param {number} end - ending position (excluded) 424 + * @param {number} maxLength - maximum length of the output string 425 + * @param {boolean} isRelative - Whether the OID is relative 426 + * @returns {string} Formatted OID string 427 + */ 428 parseOID(start, end, maxLength, isRelative) { 429 let s = '', 430 + n = 0n, 431 bits = 0; 432 for (let i = start; i < end; ++i) { 433 let v = this.get(i); 434 + // Shift bits and add the lower 7 bits of the byte 435 + n = (n << 7n) | BigInt(v & 0x7F); 436 bits += 7; 437 + // If the most significant bit is 0, this is the last byte of the OID component 438 if (!(v & 0x80)) { // finished 439 + // If this is the first component, handle it specially 440 if (s === '') { 441 if (isRelative) { 442 + s = n.toString(); 443 } else { 444 + let m = n < 80 ? n < 40 ? 0n : 1n : 2n; 445 + s = m + '.' + (n - m * 40n); 446 } 447 } else 448 + s += '.' + n; 449 if (s.length > maxLength) 450 return stringCut(s, maxLength); 451 + n = 0n; 452 bits = 0; 453 } 454 } 455 if (bits > 0) 456 s += '.incomplete'; 457 + // If OIDs mapping is available and the OID is absolute, try to resolve it 458 if (typeof oids === 'object' && !isRelative) { 459 let oid = oids[s]; 460 if (oid) { ··· 465 } 466 return s; 467 } 468 + 469 + /** 470 + * Parse a region of the stream as a relative OID (Object Identifier). 471 + * @param {number} start - starting position (included) 472 + * @param {number} end - ending position (excluded) 473 + * @param {number} maxLength - maximum length of the output string 474 + * @returns {string} Formatted relative OID string 475 + */ 476 parseRelativeOID(start, end, maxLength) { 477 return this.parseOID(start, end, maxLength, true); 478 } ··· 505 this.tagConstructed = ((buf & 0x20) !== 0); 506 this.tagNumber = buf & 0x1F; 507 if (this.tagNumber == 0x1F) { // long tag 508 + let n = 0n; 509 do { 510 buf = stream.get(); 511 + n = (n << 7n) | BigInt(buf & 0x7F); 512 } while (buf & 0x80); 513 + this.tagNumber = n <= Number.MAX_SAFE_INTEGER ? Number(n) : n; 514 } 515 } 516 isUniversal() { ··· 521 } 522 } 523 524 + /** 525 + * ASN1 class for parsing ASN.1 encoded data. 526 + * Instances of this class represent an ASN.1 element and provides methods to parse and display its content. 527 + */ 528 export class ASN1 { 529 + /** 530 + * Creates an ASN1 parser object. 531 + * @param {Stream} stream - The stream containing the ASN.1 data. 532 + * @param {number} header - The header length. 533 + * @param {number} length - The length of the data. 534 + * @param {ASN1Tag} tag - The ASN.1 tag. 535 + * @param {number} tagLen - The length of the tag. 536 + * @param {Array} sub - The sub-elements. 537 + */ 538 constructor(stream, header, length, tag, tagLen, sub) { 539 if (!(tag instanceof ASN1Tag)) throw new Error('Invalid tag value.'); 540 this.stream = stream; ··· 544 this.tagLen = tagLen; 545 this.sub = sub; 546 } 547 + 548 + /** 549 + * Get the type name of the ASN.1 element. 550 + * @returns {string} The type name. 551 + */ 552 typeName() { 553 switch (this.tag.tagClass) { 554 case 0: // universal ··· 588 case 3: return 'Private_' + this.tag.tagNumber.toString(); 589 } 590 } 591 + 592 + /** 593 + * Get a string preview of the content (intended for humans). 594 + * @param {number} maxLength - The maximum length of the content. 595 + * @returns {string|null} The content preview or null if not supported. 596 + */ 597 content(maxLength) { 598 if (this.tag === undefined) 599 return null; 600 if (maxLength === undefined) 601 maxLength = Infinity; 602 + const content = this.posContent(), 603 len = Math.abs(this.length); 604 if (!this.tag.isUniversal()) { 605 if (this.sub !== null) ··· 609 } 610 switch (this.tag.tagNumber) { 611 case 0x01: // BOOLEAN 612 + if (len != 1) return 'invalid length ' + len; 613 return (this.stream.get(content) === 0) ? 'false' : 'true'; 614 case 0x02: // INTEGER 615 + if (len < 1) return 'invalid length ' + len; 616 return this.stream.parseInteger(content, content + len); 617 case 0x03: { // BIT_STRING 618 let d = recurse(this, 'parseBitString', maxLength); ··· 624 } 625 //case 0x05: // NULL 626 case 0x06: // OBJECT_IDENTIFIER 627 + if (len < 1) return 'invalid length ' + len; // pgut001's dumpasn1.c enforces a minimum lenght of 3 628 return this.stream.parseOID(content, content + len, maxLength); 629 //case 0x07: // ObjectDescriptor 630 //case 0x08: // EXTERNAL ··· 661 } 662 return null; 663 } 664 + 665 + /** 666 + * Get a string representation of the ASN.1 element. 667 + * @returns {string} The string representation. 668 + */ 669 toString() { 670 return this.typeName() + '@' + this.stream.pos + '[header:' + this.header + ',length:' + this.length + ',sub:' + ((this.sub === null) ? 'null' : this.sub.length) + ']'; 671 } 672 + 673 + /** 674 + * Get a pretty string representation of the ASN.1 element. 675 + * @param {string} indent - The indentation string. 676 + * @returns {string} The pretty string representation. 677 + */ 678 toPrettyString(indent) { 679 if (indent === undefined) indent = ''; 680 let s = indent; ··· 705 } 706 return s; 707 } 708 + 709 + /** 710 + * Get the starting position of the element in the stream. 711 + * @returns {number} The starting position. 712 + */ 713 posStart() { 714 return this.stream.pos; 715 } 716 + 717 + /** 718 + * Get the position of the content in the stream. 719 + * @returns {number} The content position. 720 + */ 721 posContent() { 722 return this.stream.pos + this.header; 723 } 724 + 725 + /** 726 + * Get the ending position of the element in the stream. 727 + * @returns {number} The ending position. 728 + */ 729 posEnd() { 730 return this.stream.pos + this.header + Math.abs(this.length); 731 } 732 + 733 + /** 734 + * Get the position of the length in the stream. 735 + * @returns {number} The length position. 736 + */ 737 posLen() { 738 return this.stream.pos + this.tagLen; 739 } 740 + 741 + /** 742 + * Get a hexadecimal dump of the node. 743 + * @param {string} [type='raw'] - The dump type: 'raw', 'byte', or 'dump'. 744 + * @returns {string} The hexadecimal dump. 745 + */ 746 toHexString(type = 'raw') { 747 return this.stream.hexDump(this.posStart(), this.posEnd(), type); 748 } 749 + 750 + /** 751 + * Get a base64url dump of the node (according to RFC 4648 section 5). 752 + * @param {string} [type='url'] - The dump type: 'url' (section 5 without padding) or 'std' (section 4 with padding). 753 + * @returns {string} The base64 encoded representation. 754 + */ 755 + toB64String(type = 'url') { 756 + return this.stream.b64Dump(this.posStart(), this.posEnd(), type); 757 } 758 + 759 + /** 760 + * Decode the length field of an ASN.1 element. 761 + * @param {Stream} stream - The stream to read from. 762 + * @returns {number|null} The decoded length, or null for indefinite length. 763 + * @throws {Error} If the length is invalid or exceeds 48 bits. 764 + */ 765 static decodeLength(stream) { 766 + const buf = stream.get(), 767 len = buf & 0x7F; 768 if (len == buf) // first bit was 0, short form 769 return len; 770 if (len === 0) // long form with length 0 is a special case 771 return null; // undefined length 772 + if (len > 6) // no reason to use BigInt, as it would be a huge buffer anyways 773 throw new Error('Length over 48 bits not supported at position ' + (stream.pos - 1)); 774 + let value = 0; 775 for (let i = 0; i < len; ++i) 776 + value = (value << 8) | stream.get(); 777 + return value; 778 } 779 + 780 + /** 781 + * Decode an ASN.1 element from a stream. 782 + * @param {Stream|array|string} stream - The input data. 783 + * @param {number} [offset=0] - The offset to start decoding from. 784 + * @param {Function} [type=ASN1] - The class to instantiate. 785 + * @returns {ASN1} The decoded ASN.1 element. 786 + * @throws {Error} If the decoding fails. 787 + */ 788 static decode(stream, offset, type = ASN1) { 789 if (!(type == ASN1 || type.prototype instanceof ASN1)) 790 throw new Error('Must pass a class that extends ASN1'); ··· 842 throw new Error('Unable to parse content: ' + e); 843 } 844 } 845 + } catch (ignore) { 846 // but silently ignore when they don't 847 sub = null; 848 //DEBUG console.log('Could not decode structure at ' + start + ':', e);
+6 -5
base64.js
··· 31 decoder[b64.charCodeAt(i)] = i; 32 for (i = 0; i < ignore.length; ++i) 33 decoder[ignore.charCodeAt(i)] = -1; 34 - // RFC 3548 URL & file safe encoding 35 decoder['-'.charCodeAt(0)] = decoder['+'.charCodeAt(0)]; 36 decoder['_'.charCodeAt(0)] = decoder['/'.charCodeAt(0)]; 37 } ··· 75 76 static pretty(str) { 77 // fix padding 78 - if (str.length % 4 > 0) 79 - str = (str + '===').slice(0, str.length + str.length % 4); 80 - // convert RFC 3548 to standard Base64 81 str = str.replace(/-/g, '+').replace(/_/g, '/'); 82 // 80 column width 83 - return str.replace(/(.{80})/g, '$1\n'); 84 } 85 86 static unarmor(a) {
··· 31 decoder[b64.charCodeAt(i)] = i; 32 for (i = 0; i < ignore.length; ++i) 33 decoder[ignore.charCodeAt(i)] = -1; 34 + // also support decoding Base64url (RFC 4648 section 5) 35 decoder['-'.charCodeAt(0)] = decoder['+'.charCodeAt(0)]; 36 decoder['_'.charCodeAt(0)] = decoder['/'.charCodeAt(0)]; 37 } ··· 75 76 static pretty(str) { 77 // fix padding 78 + let pad = 4 - str.length % 4; 79 + if (pad < 4) 80 + str += '==='.slice(0, pad); 81 + // convert Base64url (RFC 4648 section 5) to standard Base64 (RFC 4648 section 4) 82 str = str.replace(/-/g, '+').replace(/_/g, '/'); 83 // 80 column width 84 + return str.replace(/.{80}/g, '$&\n'); 85 } 86 87 static unarmor(a) {
+9 -6
defs.js
··· 23 try { 24 // hope current OIDs contain the type name (will need to parse from RFC itself) 25 def = Defs.searchType(firstUpper(stats.defs[def.definedBy][1])); 26 - } catch (e) { /*ignore*/ } 27 while (def?.type == 'defined' || def?.type?.type == 'defined') { 28 const name = def?.type?.type ? def.type.name : def.name; 29 def = Object.assign({}, def); ··· 35 c = translate(c); 36 if (tn == c.type.name || tn == c.name) { 37 def = Object.assign({}, def); 38 - if (c.id) def.id = c.id; 39 def.type = c.type.name ? c.type : c; 40 break; 41 } ··· 69 70 static match(value, def, stats = { total: 0, recognized: 0, defs: {} }) { 71 value.def = {}; 72 - let tn = value.typeName().replaceAll('_', ' '); 73 def = translate(def, tn, stats); 74 ++stats.total; 75 if (def?.type) { ··· 90 if (def.typeOf) 91 type = def.content[0]; 92 else { 93 - let tn = subval.typeName().replaceAll('_', ' '); 94 for (;;) { 95 type = def.content[j++]; 96 if (!type || typeof type != 'object') break; 97 if (type?.type?.type) 98 - type = type.type; 99 if (type.type == 'defined') { 100 let t2 = translate(type, tn); 101 if (t2.type.name == tn) break; // exact match ··· 113 } else if (type?.definedBy && stats.defs?.[type.definedBy]?.[1]) { // hope current OIDs contain the type name (will need to parse from RFC itself) 114 try { 115 type = Defs.searchType(firstUpper(stats.defs[type.definedBy][1])); 116 - } catch (e) { /*ignore*/ } 117 } 118 } 119 } ··· 138 [ 'PKCS#10 certification request', '1.2.840.113549.1.10.1.1', 'CertificationRequest' ], 139 [ 'CMP PKI Message', '1.3.6.1.5.5.7.0.16', 'PKIMessage' ], 140 [ 'LDAP Message', '1.3.6.1.1.18', 'LDAPMessage' ], 141 ].map(arr => ({ description: arr[0], ...Defs.moduleAndType(rfcdef[arr[1]], arr[2]) }));
··· 23 try { 24 // hope current OIDs contain the type name (will need to parse from RFC itself) 25 def = Defs.searchType(firstUpper(stats.defs[def.definedBy][1])); 26 + } catch (ignore) { /*ignore*/ } 27 while (def?.type == 'defined' || def?.type?.type == 'defined') { 28 const name = def?.type?.type ? def.type.name : def.name; 29 def = Object.assign({}, def); ··· 35 c = translate(c); 36 if (tn == c.type.name || tn == c.name) { 37 def = Object.assign({}, def); 38 + if (c.id) // show the CHOICE id, but add it to existing one if present 39 + def.id = def.id ? def.id + ' ' + c.id : c.id; 40 def.type = c.type.name ? c.type : c; 41 break; 42 } ··· 70 71 static match(value, def, stats = { total: 0, recognized: 0, defs: {} }) { 72 value.def = {}; 73 + let tn = value.typeName().replace(/_/g, ' '); 74 def = translate(def, tn, stats); 75 ++stats.total; 76 if (def?.type) { ··· 91 if (def.typeOf) 92 type = def.content[0]; 93 else { 94 + let tn = subval.typeName().replace(/_/g, ' '); 95 for (;;) { 96 type = def.content[j++]; 97 if (!type || typeof type != 'object') break; 98 if (type?.type?.type) 99 + // type = type.type; 100 + type = Object.assign({}, type.type, {id: type.id}); 101 if (type.type == 'defined') { 102 let t2 = translate(type, tn); 103 if (t2.type.name == tn) break; // exact match ··· 115 } else if (type?.definedBy && stats.defs?.[type.definedBy]?.[1]) { // hope current OIDs contain the type name (will need to parse from RFC itself) 116 try { 117 type = Defs.searchType(firstUpper(stats.defs[type.definedBy][1])); 118 + } catch (ignore) { /*ignore*/ } 119 } 120 } 121 } ··· 140 [ 'PKCS#10 certification request', '1.2.840.113549.1.10.1.1', 'CertificationRequest' ], 141 [ 'CMP PKI Message', '1.3.6.1.5.5.7.0.16', 'PKIMessage' ], 142 [ 'LDAP Message', '1.3.6.1.1.18', 'LDAPMessage' ], 143 + [ 'Time Stamp Request', '1.3.6.1.5.5.7.0.13', 'TimeStampReq' ], 144 ].map(arr => ({ description: arr[0], ...Defs.moduleAndType(rfcdef[arr[1]], arr[2]) }));
+1 -1
dumpASN1.js
··· 52 : fs.readFileSync(filename); 53 try { // try PEM first 54 content = Base64.unarmor(content); 55 - } catch (e) { // try DER/BER then 56 } 57 let result = ASN1.decode(content); 58 content = null;
··· 52 : fs.readFileSync(filename); 53 try { // try PEM first 54 content = Base64.unarmor(content); 55 + } catch (ignore) { // try DER/BER then 56 } 57 let result = ASN1.decode(content); 58 content = null;
+63
eslint.config.js
···
··· 1 + import globals from 'globals'; 2 + import js from '@eslint/js'; 3 + 4 + export default [ 5 + js.configs.recommended, 6 + { 7 + languageOptions: { 8 + globals: { 9 + ...globals.browser, 10 + ...globals.node, 11 + Uint8Array: 'readonly', 12 + }, 13 + ecmaVersion: 2020, 14 + }, 15 + rules: { 16 + indent: ['error', 4], 17 + 'no-trailing-spaces': ['error'], 18 + 'linebreak-style': ['error', 'unix'], 19 + 'eol-last': ['error', 'always'], 20 + semi: ['warn', 'always'], 21 + quotes: [ 'error', 'single', { 22 + avoidEscape: true, 23 + }], 24 + 'no-var': ['warn'], 25 + 'comma-dangle': ['error', 'always-multiline'], 26 + 'no-unused-vars': ['error', { 27 + caughtErrorsIgnorePattern: 'ignore', 28 + }], 29 + }, 30 + }, 31 + { 32 + files: ['oids.js'], 33 + rules: { 34 + indent: 'off', 35 + quotes: ['warn', 'double'], 36 + }, 37 + }, 38 + { 39 + files: ['tags.js', 'rfcdef.js'], 40 + rules: { 41 + indent: [ 42 + 'error', 43 + 2, 44 + { 45 + ignoredNodes: [ 46 + "Program > ExpressionStatement > CallExpression > FunctionExpression > BlockStatement > ExpressionStatement[directive='use strict']:first-child", 47 + ], 48 + }, 49 + ], 50 + 'comma-dangle': 'off', 51 + quotes: ['warn', 'double'], 52 + }, 53 + }, 54 + { 55 + files: ['test.js', 'parseRFC.js', 'dumpASN1.js', 'testDefs.js', 'eslint.config.js'], 56 + languageOptions: { 57 + ecmaVersion: 'latest', 58 + }, 59 + rules: { 60 + strict: ['error', 'global'], 61 + }, 62 + }, 63 + ];
+45
examples/crl-rfc5280.b64.dump
···
··· 1 + CertificateList SEQUENCE @0+352 (constructed): (3 elem) 2 + tbsCertList TBSCertList SEQUENCE @4+202 (constructed): (7 elem) 3 + version Version INTEGER @7+1: 1 4 + signature AlgorithmIdentifier SEQUENCE @10+13 (constructed): (2 elem) 5 + algorithm OBJECT_IDENTIFIER @12+9: 1.2.840.113549.1.1.5|sha1WithRSAEncryption|PKCS #1 6 + parameters ANY NULL @23+0 7 + issuer rdnSequence Name SEQUENCE @25+67 (constructed): (3 elem) 8 + RelativeDistinguishedName SET @27+19 (constructed): (1 elem) 9 + AttributeTypeAndValue SEQUENCE @29+17 (constructed): (2 elem) 10 + type AttributeType OBJECT_IDENTIFIER @31+10: 0.9.2342.19200300.100.1.25|domainComponent|Men are from Mars, this OID is from Pluto 11 + value AttributeValue [?] IA5String @43+3: com 12 + RelativeDistinguishedName SET @48+23 (constructed): (1 elem) 13 + AttributeTypeAndValue SEQUENCE @50+21 (constructed): (2 elem) 14 + type AttributeType OBJECT_IDENTIFIER @52+10: 0.9.2342.19200300.100.1.25|domainComponent|Men are from Mars, this OID is from Pluto 15 + value AttributeValue [?] IA5String @64+7: example 16 + RelativeDistinguishedName SET @73+19 (constructed): (1 elem) 17 + AttributeTypeAndValue SEQUENCE @75+17 (constructed): (2 elem) 18 + type AttributeType OBJECT_IDENTIFIER @77+3: 2.5.4.3|commonName|X.520 DN component 19 + value AttributeValue [?] PrintableString @82+10: Example CA 20 + thisUpdate utcTime Time UTCTime @94+13: 2005-02-05 12:00:00 UTC 21 + nextUpdate utcTime Time UTCTime @109+13: 2005-02-06 12:00:00 UTC 22 + revokedCertificates SEQUENCE @124+34 (constructed): (1 elem) 23 + SEQUENCE @126+32 (constructed): (3 elem) 24 + userCertificate CertificateSerialNumber INTEGER @128+1: 18 25 + revocationDate utcTime Time UTCTime @131+13: 2004-11-19 15:57:03 UTC 26 + crlEntryExtensions Extensions SEQUENCE @146+12 (constructed): (1 elem) 27 + Extension SEQUENCE @148+10 (constructed): (2 elem) 28 + extnID OBJECT_IDENTIFIER @150+3: 2.5.29.21|cRLReason|X.509 extension 29 + extnValue OCTET_STRING @155+3 (encapsulates): (3 byte)|0A0101 30 + ENUMERATED @157+1: 1 31 + crlExtensions [0] @160+47 (constructed): (1 elem) 32 + Extensions SEQUENCE @162+45 (constructed): (2 elem) 33 + Extension SEQUENCE @164+31 (constructed): (2 elem) 34 + extnID OBJECT_IDENTIFIER @166+3: 2.5.29.35|authorityKeyIdentifier|X.509 extension 35 + extnValue OCTET_STRING @171+24 (encapsulates): (24 byte)|301680140868AF8533C8394A7AF882938E706A4A20842C32 36 + SEQUENCE @173+22 (constructed): (1 elem) 37 + [0] @175+20: (20 byte)|0868AF8533C8394A7AF882938E706A4A20842C32 38 + Extension SEQUENCE @197+10 (constructed): (2 elem) 39 + extnID OBJECT_IDENTIFIER @199+3: 2.5.29.20|cRLNumber|X.509 extension 40 + extnValue OCTET_STRING @204+3 (encapsulates): (3 byte)|02010C 41 + INTEGER @206+1: 12 42 + signatureAlgorithm AlgorithmIdentifier SEQUENCE @209+13 (constructed): (2 elem) 43 + algorithm OBJECT_IDENTIFIER @211+9: 1.2.840.113549.1.1.5|sha1WithRSAEncryption|PKCS #1 44 + parameters ANY NULL @222+0 45 + signature BIT_STRING @224+129: (1024 bit)|0010001011011100000110000111110111110111000010001100111011001100011101011101000011010000011010101001101110101101000100001111010001110110001000111011010010000001011011101011010101101101101111100000111011111011000101010001010001101100110010000001011101101101000111111110111010010000000101111010001001101111011000001110010010111101101010101000110001010101110111101000111010000100011011111001001011111000100111110001000000010010001001111010111101001010110101000010111110000101111000100011011001000100011111011010101010100011010011000010010100111000000101011111111100000000111111010011111001111110111011100011110100100110000100101110101111011000111001110010101101100010111000100010101111000011010001101000000011101111011110001000001011010001000101011100011011010000100111000111001001101010110010111100111001111010111011010110011110011001100010110110111001110000100000010111110101000011010000100111010011000001101001101010111111000001010101010001011110100010001100110100110011010110000001101001100000101011101001001111110000101110
+60
examples/ed25519.cer.dump
···
··· 1 + Certificate SEQUENCE @0+383 (constructed): (3 elem) 2 + tbsCertificate TBSCertificate SEQUENCE @4+305 (constructed): (8 elem) 3 + version [0] @8+3 (constructed): (1 elem) 4 + Version INTEGER @10+1: 2 5 + serialNumber CertificateSerialNumber INTEGER @13+20: (159 bit)|711090297755414526861352146244170174161660335942 6 + signature AlgorithmIdentifier SEQUENCE @35+5 (constructed): (1 elem) 7 + algorithm OBJECT_IDENTIFIER @37+3: 1.3.101.112|curveEd25519|EdDSA 25519 signature algorithm 8 + issuer rdnSequence Name SEQUENCE @42+53 (constructed): (3 elem) 9 + RelativeDistinguishedName SET @44+11 (constructed): (1 elem) 10 + AttributeTypeAndValue SEQUENCE @46+9 (constructed): (2 elem) 11 + type AttributeType OBJECT_IDENTIFIER @48+3: 2.5.4.6|countryName|X.520 DN component 12 + value AttributeValue [?] PrintableString @53+2: IT 13 + RelativeDistinguishedName SET @57+15 (constructed): (1 elem) 14 + AttributeTypeAndValue SEQUENCE @59+13 (constructed): (2 elem) 15 + type AttributeType OBJECT_IDENTIFIER @61+3: 2.5.4.7|localityName|X.520 DN component 16 + value AttributeValue [?] UTF8String @66+6: Milano 17 + RelativeDistinguishedName SET @74+21 (constructed): (1 elem) 18 + AttributeTypeAndValue SEQUENCE @76+19 (constructed): (2 elem) 19 + type AttributeType OBJECT_IDENTIFIER @78+3: 2.5.4.3|commonName|X.520 DN component 20 + value AttributeValue [?] UTF8String @83+12: Test ed25519 21 + validity Validity SEQUENCE @97+30 (constructed): (2 elem) 22 + notBefore utcTime Time UTCTime @99+13: 2020-09-02 13:25:26 UTC 23 + notAfter utcTime Time UTCTime @114+13: 2030-09-02 13:25:26 UTC 24 + subject rdnSequence Name SEQUENCE @129+53 (constructed): (3 elem) 25 + RelativeDistinguishedName SET @131+11 (constructed): (1 elem) 26 + AttributeTypeAndValue SEQUENCE @133+9 (constructed): (2 elem) 27 + type AttributeType OBJECT_IDENTIFIER @135+3: 2.5.4.6|countryName|X.520 DN component 28 + value AttributeValue [?] PrintableString @140+2: IT 29 + RelativeDistinguishedName SET @144+15 (constructed): (1 elem) 30 + AttributeTypeAndValue SEQUENCE @146+13 (constructed): (2 elem) 31 + type AttributeType OBJECT_IDENTIFIER @148+3: 2.5.4.7|localityName|X.520 DN component 32 + value AttributeValue [?] UTF8String @153+6: Milano 33 + RelativeDistinguishedName SET @161+21 (constructed): (1 elem) 34 + AttributeTypeAndValue SEQUENCE @163+19 (constructed): (2 elem) 35 + type AttributeType OBJECT_IDENTIFIER @165+3: 2.5.4.3|commonName|X.520 DN component 36 + value AttributeValue [?] UTF8String @170+12: Test ed25519 37 + subjectPublicKeyInfo SubjectPublicKeyInfo SEQUENCE @184+42 (constructed): (2 elem) 38 + algorithm AlgorithmIdentifier SEQUENCE @186+5 (constructed): (1 elem) 39 + algorithm OBJECT_IDENTIFIER @188+3: 1.3.101.112|curveEd25519|EdDSA 25519 signature algorithm 40 + subjectPublicKey BIT_STRING @193+33: (256 bit)|0011101110101001001011111111110111001011000101110110011011011110010000001010001010010010111101111001001111011110001100001111100000001010001000111010100000110001001000010101110111010000000001111101100001100011001001000010111011111111011010000010000110000101 41 + extensions [3] @228+83 (constructed): (1 elem) 42 + Extensions SEQUENCE @230+81 (constructed): (3 elem) 43 + Extension SEQUENCE @232+29 (constructed): (2 elem) 44 + extnID OBJECT_IDENTIFIER @234+3: 2.5.29.14|subjectKeyIdentifier|X.509 extension 45 + extnValue OCTET_STRING @239+22 (encapsulates): (22 byte)|04146BA5BDCF9DFA235978126417AE1E72D89A804AE8 46 + OCTET_STRING @241+20: (20 byte)|6BA5BDCF9DFA235978126417AE1E72D89A804AE8 47 + Extension SEQUENCE @263+31 (constructed): (2 elem) 48 + extnID OBJECT_IDENTIFIER @265+3: 2.5.29.35|authorityKeyIdentifier|X.509 extension 49 + extnValue OCTET_STRING @270+24 (encapsulates): (24 byte)|301680146BA5BDCF9DFA235978126417AE1E72D89A804AE8 50 + SEQUENCE @272+22 (constructed): (1 elem) 51 + [0] @274+20: (20 byte)|6BA5BDCF9DFA235978126417AE1E72D89A804AE8 52 + Extension SEQUENCE @296+15 (constructed): (3 elem) 53 + extnID OBJECT_IDENTIFIER @298+3: 2.5.29.19|basicConstraints|X.509 extension 54 + critical BOOLEAN @303+1: true 55 + extnValue OCTET_STRING @306+5 (encapsulates): (5 byte)|30030101FF 56 + SEQUENCE @308+3 (constructed): (1 elem) 57 + BOOLEAN @310+1: true 58 + signatureAlgorithm AlgorithmIdentifier SEQUENCE @313+5 (constructed): (1 elem) 59 + algorithm OBJECT_IDENTIFIER @315+3: 1.3.101.112|curveEd25519|EdDSA 25519 signature algorithm 60 + signature BIT_STRING @320+65: (512 bit)|01101111011100110111011110111110001010001001011001011010001100110011011011010111111001010011010011111101100100001111001111111101010000000111111100011111000000101111100100000000010101111111001000010110000011110001011001101011000001001011111101100101100001001011011010011000110100101101000011010010101111110100110011010110011011110000111010110110111000101110100010011101000001001010001111100000100110010101000011111001110000100110110111011110011100111010110100011101001101010101011110000101011001011000011000000110
+7
examples/ldapmessage.b64.dump
···
··· 1 + LDAPMessage SEQUENCE @0+53 (constructed): (3 elem) 2 + messageID MessageID INTEGER @2+1: 5 3 + protocolOp delRequest CHOICE Application_10 @5+17: (17 byte)|dc=example,dc=com 4 + Controls [?] [0] @24+29 (constructed): (1 elem) 5 + AttributeTypeAndValue SEQUENCE @26+27 (constructed): (2 elem) 6 + type AttributeType [?] OCTET_STRING @28+22: (22 byte)|1.2.840.113556.1.4.805 7 + value AttributeValue [?] BOOLEAN @52+1: true
+10
examples/pkcs1.pem.dump
···
··· 1 + RSAPrivateKey SEQUENCE @0+605 (constructed): (9 elem) 2 + version Version INTEGER @4+1: 0 3 + modulus INTEGER @7+129: (1024 bit)|117127183230921204401013393277767517103803021018182691416238029726599496957198017684901559383009459523071384847726671610377559004781710040051270748910270447756432733966622455162759462672603884318432883204215291756888413811504344870556870978773843838353155520698675084344179957236491745093327422201227604749459 4 + publicExponent INTEGER @139+3: 65537 5 + privateExponent INTEGER @144+129: (1024 bit)|92276282475226568589241550905865273709561889943250510752753436239739158443231274686159532997597455087892667385718350070754140814118578097684166368734227728473322161416664690885212698653195373932779792506838124961141214987311742627151011567342689730655630521241854903774681567286735997541758916977964830429313 6 + prime1 INTEGER @276+65: (512 bit)|10896821561662485361386011233938116142526936125648167362054539174681694465821232677159478832161550957167298418313068706031799276527005193877616679381489381 7 + prime2 INTEGER @343+65: (512 bit)|10748747473575365133625210720374663113238804836624829882840358384492696273600075746246298849279878235356215808273663889910189484797595139778277124898735639 8 + exponent1 INTEGER @410+64: (511 bit)|6091625365131581796315047890165719534213640521161662994088715561328917102465668272778610952193459304175325574129665657306361751287362700277617869028176853 9 + exponent2 INTEGER @476+65: (512 bit)|9619864112105977791898517014707043200694399482542575521432448550956476604540013165392532656448448632323473488540572223305800601817570919153380021725291669 10 + coefficient INTEGER @543+64: (511 bit)|4162468593383244686217782691133418477400302049612992866028022118893358867845916127581019785866484075341057799618361552573853678007698434146811407259880551
+16
examples/pkcs8-rsa.pem.dump
···
··· 1 + PrivateKeyInfo SEQUENCE @0+631 (constructed): (3 elem) 2 + version Version INTEGER @4+1: 0 3 + privateKeyAlgorithm AlgorithmIdentifier SEQUENCE @7+13 (constructed): (2 elem) 4 + algorithm OBJECT_IDENTIFIER @9+9: 1.2.840.113549.1.1.1|rsaEncryption|PKCS #1 5 + parameters ANY NULL @20+0 6 + privateKey PrivateKey OCTET_STRING @22+609 (encapsulates): (609 byte)|3082025D02010002818100A6CB6DE27CDF698B92CEE0C4772D4854D2FF8B666BFBF07FA377E47A90571665FD6A5B8C9F2930E4AF28E32E522162AC66CD70AA1B26888E3EEE268A2B59FECA7E4C693AE26B878B3027F5868429FD8BEBE85BFED3B0E5DF0E9D72AAB1216902B074FA2DD59001EFC4CDB1E7305FF48E0D310C0A4F798EFC758F9703C4F96C930203010001028181008367E1BA7E06C57060C8FBEBCCB8B033A3C8105B30D7DC31B2E7D1E97DAE1EC75B4F5FB0F9F3C9C160FE257D68D74495EEA80C0AF838F37C9DB7A24558C21E28C49D57470B002D90A383CAEBB5821A59583D15502F0012C9235F806C62C97F1E3CAFBC72118FCF60743168125801E06CC7293CDE64D241339AAD516E7BCC1081024100D00E8DE65F7C32094B732A5628CEFEDC35ED796B7CEA6297614545DF71D8DBC67EA14565534BFC9BC5F1A680239227189C2D493924A5BD64641169533201D6E5024100CD3AC881CC47AA776A9829C0E529E3D0DBB5A43C366842578341A051DAFAF4F6164F2DC0E72A3BD3B33F8B2F84A6CF35F0781E7C466E677FF8E553DE5C92C6170240744F3E9A83D4AD302F02B1AF3ADF04F0DC20E698E55B2E448C372AA9903E78164E221FE6561B8B9B159C52C51D9D8DC79F3F5DC8D928E268A5DC69F1FD69B3D5024100B7ACEA92B05F5B8370D52A5947400C727A90C0A25B174878C6324FE7B29273F662D50E5FDD04017360B3784058FA69ED1E8082D83AB8C8CCD1D77D0E3FCFE49502404F79B900CE9185833573BBA54E1B1D157EDFE8C37FC328D2520CCE7CC804A9A28B58D937626EBAD5FDE96534BBEE4E292EE8010CFFC8DB1E546C99FC517B4C67 7 + SEQUENCE @26+605 (constructed): (9 elem) 8 + INTEGER @30+1: 0 9 + INTEGER @33+129: (1024 bit)|117127183230921204401013393277767517103803021018182691416238029726599496957198017684901559383009459523071384847726671610377559004781710040051270748910270447756432733966622455162759462672603884318432883204215291756888413811504344870556870978773843838353155520698675084344179957236491745093327422201227604749459 10 + INTEGER @165+3: 65537 11 + INTEGER @170+129: (1024 bit)|92276282475226568589241550905865273709561889943250510752753436239739158443231274686159532997597455087892667385718350070754140814118578097684166368734227728473322161416664690885212698653195373932779792506838124961141214987311742627151011567342689730655630521241854903774681567286735997541758916977964830429313 12 + INTEGER @302+65: (512 bit)|10896821561662485361386011233938116142526936125648167362054539174681694465821232677159478832161550957167298418313068706031799276527005193877616679381489381 13 + INTEGER @369+65: (512 bit)|10748747473575365133625210720374663113238804836624829882840358384492696273600075746246298849279878235356215808273663889910189484797595139778277124898735639 14 + INTEGER @436+64: (511 bit)|6091625365131581796315047890165719534213640521161662994088715561328917102465668272778610952193459304175325574129665657306361751287362700277617869028176853 15 + INTEGER @502+65: (512 bit)|9619864112105977791898517014707043200694399482542575521432448550956476604540013165392532656448448632323473488540572223305800601817570919153380021725291669 16 + INTEGER @569+64: (511 bit)|4162468593383244686217782691133418477400302049612992866028022118893358867845916127581019785866484075341057799618361552573853678007698434146811407259880551
+118
examples/sig-p256-der.p7m.dump
···
··· 1 + ContentInfo SEQUENCE @0+10868 (constructed): (2 elem) 2 + contentType ContentType OBJECT_IDENTIFIER @4+9: 1.2.840.113549.1.7.2|signedData|PKCS #7 3 + content [0] @15+10853 (constructed): (1 elem) 4 + SignedData SEQUENCE @19+10849 (constructed): (5 elem) 5 + version CMSVersion INTEGER @23+1: 1 6 + digestAlgorithms DigestAlgorithmIdentifiers SET @26+15 (constructed): (1 elem) 7 + DigestAlgorithmIdentifier SEQUENCE @28+13 (constructed): (2 elem) 8 + algorithm OBJECT_IDENTIFIER @30+9: 2.16.840.1.101.3.4.2.1|sha-256|NIST Algorithm 9 + parameters ANY NULL @41+0 10 + encapContentInfo EncapsulatedContentInfo SEQUENCE @43+10053 (constructed): (2 elem) 11 + eContentType ContentType OBJECT_IDENTIFIER @47+9: 1.2.840.113549.1.7.1|data|PKCS #7 12 + eContent [0] @58+10038 (constructed): (1 elem) 13 + OCTET_STRING @62+10034: (10034 byte)|Inizio contenuto.|AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|Fine contenuto. 14 + CertificateSet [?] [0] @10100+370 (constructed): (1 elem) 15 + certificate CertificateChoices SEQUENCE @10104+366 (constructed): (3 elem) 16 + tbsCertificate TBSCertificate SEQUENCE @10108+276 (constructed): (8 elem) 17 + version [0] @10112+3 (constructed): (1 elem) 18 + Version INTEGER @10114+1: 2 19 + serialNumber CertificateSerialNumber INTEGER @10117+16: (127 bit)|128087855099855233032551836648087377254 20 + signature AlgorithmIdentifier SEQUENCE @10135+10 (constructed): (1 elem) 21 + algorithm OBJECT_IDENTIFIER @10137+8: 1.2.840.10045.4.3.2|ecdsaWithSHA256|ANSI X9.62 ECDSA algorithm with SHA256 22 + issuer rdnSequence Name SEQUENCE @10147+15 (constructed): (1 elem) 23 + RelativeDistinguishedName SET @10149+13 (constructed): (1 elem) 24 + AttributeTypeAndValue SEQUENCE @10151+11 (constructed): (2 elem) 25 + type AttributeType OBJECT_IDENTIFIER @10153+3: 2.5.4.3|commonName|X.520 DN component 26 + value AttributeValue [?] UTF8String @10158+4: Test 27 + validity Validity SEQUENCE @10164+30 (constructed): (2 elem) 28 + notBefore utcTime Time UTCTime @10166+13: 2018-07-16 14:56:35 UTC 29 + notAfter utcTime Time UTCTime @10181+13: 2019-07-16 14:56:35 UTC 30 + subject rdnSequence Name SEQUENCE @10196+15 (constructed): (1 elem) 31 + RelativeDistinguishedName SET @10198+13 (constructed): (1 elem) 32 + AttributeTypeAndValue SEQUENCE @10200+11 (constructed): (2 elem) 33 + type AttributeType OBJECT_IDENTIFIER @10202+3: 2.5.4.3|commonName|X.520 DN component 34 + value AttributeValue [?] UTF8String @10207+4: Test 35 + subjectPublicKeyInfo SubjectPublicKeyInfo SEQUENCE @10213+89 (constructed): (2 elem) 36 + algorithm AlgorithmIdentifier SEQUENCE @10215+19 (constructed): (2 elem) 37 + algorithm OBJECT_IDENTIFIER @10217+7: 1.2.840.10045.2.1|ecPublicKey|ANSI X9.62 public key type 38 + parameters ANY OBJECT_IDENTIFIER @10226+8: 1.2.840.10045.3.1.7|prime256v1|ANSI X9.62 named elliptic curve 39 + subjectPublicKey BIT_STRING @10236+66: (520 bit)|0000010000100100010011001011011011001100000111000110100100100001111111110100100111011000101111100010011000111110000010110111110011010000010110100010100001100101010110101000010001101100100000100101111011001010111001101110110011100110100110100110101000100001110001001110010011110010001000000010010011000000111010011111010011100100011101001001110010011000101000011010110111110010010111111001000011011110011011101111100101001000001010110110011100011000100000111010011100001110101101001011011110101011100111110000011001000011 40 + extensions [3] @10304+82 (constructed): (1 elem) 41 + Extensions SEQUENCE @10306+80 (constructed): (3 elem) 42 + Extension SEQUENCE @10308+14 (constructed): (3 elem) 43 + extnID OBJECT_IDENTIFIER @10310+3: 2.5.29.15|keyUsage|X.509 extension 44 + critical BOOLEAN @10315+1: true 45 + extnValue OCTET_STRING @10318+4 (encapsulates): (4 byte)|030204F0 46 + BIT_STRING @10320+2: (4 bit)|1111 47 + Extension SEQUENCE @10324+29 (constructed): (2 elem) 48 + extnID OBJECT_IDENTIFIER @10326+3: 2.5.29.14|subjectKeyIdentifier|X.509 extension 49 + extnValue OCTET_STRING @10331+22 (encapsulates): (22 byte)|0414C3C084DF7B040DB038AF518CE397F6EC20D626E6 50 + OCTET_STRING @10333+20: (20 byte)|C3C084DF7B040DB038AF518CE397F6EC20D626E6 51 + Extension SEQUENCE @10355+31 (constructed): (2 elem) 52 + extnID OBJECT_IDENTIFIER @10357+3: 2.5.29.35|authorityKeyIdentifier|X.509 extension 53 + extnValue OCTET_STRING @10362+24 (encapsulates): (24 byte)|30168014C3C084DF7B040DB038AF518CE397F6EC20D626E6 54 + SEQUENCE @10364+22 (constructed): (1 elem) 55 + [0] @10366+20: (20 byte)|C3C084DF7B040DB038AF518CE397F6EC20D626E6 56 + signatureAlgorithm AlgorithmIdentifier SEQUENCE @10388+10 (constructed): (1 elem) 57 + algorithm OBJECT_IDENTIFIER @10390+8: 1.2.840.10045.4.3.2|ecdsaWithSHA256|ANSI X9.62 ECDSA algorithm with SHA256 58 + signature BIT_STRING @10400+72 (encapsulates): (568 bit)|0011000001000101000000100010000100000000110111100110000000011110010101110011110110101111101101011001101111000101010100011101010110001110001111100111101110011110110110100000011000010010110111010000000100010010100000000101101000100010000101111011011100110100011101011001101110001000010001000001011100000010001000000110011111000011111111011110011000000111100000001101010000011100000111010111101000111011100100000010100100011111001111010011100111000100110111000010111100100000011011011100110010111010001011111001100000101100000001101011011001111100000010011011001000110010 59 + SEQUENCE @10403+69 (constructed): (2 elem) 60 + INTEGER @10405+33: (256 bit)|100583279108105959323277080420227859612360091217401498640290749528265835693079 61 + INTEGER @10440+32: (255 bit)|46934510925111877438867701170553238261516280994969183555881415710868278719026 62 + signerInfos SignerInfos SET @10474+394 (constructed): (1 elem) 63 + SignerInfo SEQUENCE @10478+390 (constructed): (6 elem) 64 + version CMSVersion INTEGER @10482+1: 1 65 + sid issuerAndSerialNumber SignerIdentifier SEQUENCE @10485+35 (constructed): (2 elem) 66 + issuer rdnSequence Name SEQUENCE @10487+15 (constructed): (1 elem) 67 + RelativeDistinguishedName SET @10489+13 (constructed): (1 elem) 68 + AttributeTypeAndValue SEQUENCE @10491+11 (constructed): (2 elem) 69 + type AttributeType OBJECT_IDENTIFIER @10493+3: 2.5.4.3|commonName|X.520 DN component 70 + value AttributeValue [?] UTF8String @10498+4: Test 71 + serialNumber CertificateSerialNumber INTEGER @10504+16: (127 bit)|128087855099855233032551836648087377254 72 + digestAlgorithm DigestAlgorithmIdentifier SEQUENCE @10522+13 (constructed): (2 elem) 73 + algorithm OBJECT_IDENTIFIER @10524+9: 2.16.840.1.101.3.4.2.1|sha-256|NIST Algorithm 74 + parameters ANY NULL @10535+0 75 + SignedAttributes [?] [0] @10537+247 (constructed): (5 elem) 76 + Attribute SEQUENCE @10540+24 (constructed): (2 elem) 77 + type AttributeType OBJECT_IDENTIFIER @10542+9: 1.2.840.113549.1.9.3|contentType|PKCS #9 78 + values SET @10553+11 (constructed): (1 elem) 79 + AttributeValue [?] OBJECT_IDENTIFIER @10555+9: 1.2.840.113549.1.7.1|data|PKCS #7 80 + Attribute SEQUENCE @10566+28 (constructed): (2 elem) 81 + type AttributeType OBJECT_IDENTIFIER @10568+9: 1.2.840.113549.1.9.5|signingTime|PKCS #9 82 + values SET @10579+15 (constructed): (1 elem) 83 + AttributeValue [?] UTCTime @10581+13: 2018-07-16 14:56:35 UTC 84 + Attribute SEQUENCE @10596+42 (constructed): (2 elem) 85 + type AttributeType OBJECT_IDENTIFIER @10598+9: 1.2.840.113549.1.9.52|cmsAlgorithmProtection|RFC 6211 86 + values SET @10609+29 (constructed): (1 elem) 87 + AttributeValue [?] SEQUENCE @10611+27 (constructed): (2 elem) 88 + SEQUENCE @10613+13 (constructed): (2 elem) 89 + OBJECT_IDENTIFIER @10615+9: 2.16.840.1.101.3.4.2.1|sha-256|NIST Algorithm 90 + NULL @10626+0 91 + [1] @10628+10 (constructed): (1 elem) 92 + OBJECT_IDENTIFIER @10630+8: 1.2.840.10045.4.3.2|ecdsaWithSHA256|ANSI X9.62 ECDSA algorithm with SHA256 93 + Attribute SEQUENCE @10640+47 (constructed): (2 elem) 94 + type AttributeType OBJECT_IDENTIFIER @10642+9: 1.2.840.113549.1.9.4|messageDigest|PKCS #9 95 + values SET @10653+34 (constructed): (1 elem) 96 + AttributeValue [?] OCTET_STRING @10655+32: (32 byte)|724C51BBE76DA05AFB20CBE8EB037CDAE1AFD713125D2DC13D552DA9F442D24D 97 + Attribute SEQUENCE @10689+96 (constructed): (2 elem) 98 + type AttributeType OBJECT_IDENTIFIER @10691+11: 1.2.840.113549.1.9.16.2.47|signingCertificateV2|S/MIME Authenticated Attributes 99 + values SET @10704+81 (constructed): (1 elem) 100 + AttributeValue [?] SEQUENCE @10706+79 (constructed): (1 elem) 101 + SEQUENCE @10708+77 (constructed): (1 elem) 102 + SEQUENCE @10710+75 (constructed): (2 elem) 103 + OCTET_STRING @10712+32: (32 byte)|BABC08434C58267301E006861D27ECA125670E792797248E76A5717A5BF993C2 104 + SEQUENCE @10746+39 (constructed): (2 elem) 105 + SEQUENCE @10748+19 (constructed): (1 elem) 106 + [4] @10750+17 (constructed): (1 elem) 107 + SEQUENCE @10752+15 (constructed): (1 elem) 108 + SET @10754+13 (constructed): (1 elem) 109 + SEQUENCE @10756+11 (constructed): (2 elem) 110 + OBJECT_IDENTIFIER @10758+3: 2.5.4.3|commonName|X.520 DN component 111 + UTF8String @10763+4: Test 112 + INTEGER @10769+16: (127 bit)|128087855099855233032551836648087377254 113 + signatureAlgorithm SignatureAlgorithmIdentifier SEQUENCE @10787+10 (constructed): (1 elem) 114 + algorithm OBJECT_IDENTIFIER @10789+8: 1.2.840.10045.4.3.2|ecdsaWithSHA256|ANSI X9.62 ECDSA algorithm with SHA256 115 + signature SignatureValue OCTET_STRING @10799+71 (encapsulates): (71 byte)|3045022100F104302EABB428ECC8E71CE2E38F6CBED848A8E9A2B5D5DA19933E485C83CC7102200CBB40A0B7B9B2E048920622FB286FD14695F24CF650BDAA40B885F84C34BBB9 116 + SEQUENCE @10801+69 (constructed): (2 elem) 117 + INTEGER @10803+33: (256 bit)|109014796438891021115527318269695135443977065935278579101750090430030910049393 118 + INTEGER @10838+32: (252 bit)|5758600628818957274240888478952309319266088628943097300803726649607194983353
+5
examples/timestamp-req.b64
···
··· 1 + RFC3161 TimeStamp Request 2 + 3 + begin-base64 644 timestamp-req.der 4 + ME4CAQEwLzALBglghkgBZQMEAgEEIEbUJK38SA8/2dz78XnG7DJfIYsSer3shYMmZa1VLFIRAhUA 5 + /1AduFa4EwRirIpvChE2VrV/JWYBAf8=
+3 -1
index.html
··· 37 <div id="tree"></div> 38 </div> 39 <form> 40 - <textarea id="area" rows="8"></textarea> 41 <br> 42 <br> 43 <label title="can be slow with big files"><input type="checkbox" id="wantHex" checked="checked"> with hex dump</label> ··· 61 <option value="crl-rfc5280.b64">CRL example (RFC 5280)</option> 62 <option value="cmpv2.b64">CMP PKI message (RFC 4210)</option> 63 <option value="ldapmessage.b64">LDAP message (RFC 4511)</option> 64 </select> 65 <input id="butExample" type="button" value="load"><br> 66 </td></tr> ··· 107 <li>previous versions on githack: <select id="tags"><option>[select tag]</option></select></li> 108 <li><a href="http://idf.lapo.it/p/asn1js/">InDefero tracker</a> (currently offline)</li> 109 <li><a href="https://github.com/lapo-luchini/asn1js">github mirror</a></li> 110 <li><a href="https://www.openhub.net/p/asn1js">OpenHub code stats</a></li> 111 </ul> 112 </div>
··· 37 <div id="tree"></div> 38 </div> 39 <form> 40 + <textarea id="area" rows="8" placeholder="Paste hex or base64 or PEM encoded ASN.1 BER or DER structures here, or load a file."></textarea> 41 <br> 42 <br> 43 <label title="can be slow with big files"><input type="checkbox" id="wantHex" checked="checked"> with hex dump</label> ··· 61 <option value="crl-rfc5280.b64">CRL example (RFC 5280)</option> 62 <option value="cmpv2.b64">CMP PKI message (RFC 4210)</option> 63 <option value="ldapmessage.b64">LDAP message (RFC 4511)</option> 64 + <option value="timestamp-req.b64">TimeStamp request (RFC 3161)</option> 65 </select> 66 <input id="butExample" type="button" value="load"><br> 67 </td></tr> ··· 108 <li>previous versions on githack: <select id="tags"><option>[select tag]</option></select></li> 109 <li><a href="http://idf.lapo.it/p/asn1js/">InDefero tracker</a> (currently offline)</li> 110 <li><a href="https://github.com/lapo-luchini/asn1js">github mirror</a></li> 111 + <li><a href="https://github.com/lapo-luchini/asn1js/blob/trunk/CHANGELOG.md">ChangeLog on GitHub</a></li> 112 <li><a href="https://www.openhub.net/p/asn1js">OpenHub code stats</a></li> 113 </ul> 114 </div>
+2 -2
index.js
··· 86 if (area.value === '') area.value = Base64.pretty(b64); 87 try { 88 window.location.hash = hash = '#' + b64; 89 - } catch (e) { 90 // fails with "Access Denied" on IE with URLs longer than ~2048 chars 91 window.location.hash = hash = '#'; 92 } ··· 122 else if (Base64.re.test(str)) der = Base64.unarmor(str); 123 else der = str; 124 decode(der); 125 - } catch (e) { 126 text(tree, 'Cannot decode file.'); 127 dump.innerHTML = ''; 128 }
··· 86 if (area.value === '') area.value = Base64.pretty(b64); 87 try { 88 window.location.hash = hash = '#' + b64; 89 + } catch (ignore) { 90 // fails with "Access Denied" on IE with URLs longer than ~2048 chars 91 window.location.hash = hash = '#'; 92 } ··· 122 else if (Base64.re.test(str)) der = Base64.unarmor(str); 123 else der = str; 124 decode(der); 125 + } catch (ignore) { 126 text(tree, 'Cannot decode file.'); 127 dump.innerHTML = ''; 128 }
-106
int10.js
··· 1 - // Big integer base-10 printing library 2 - // Copyright (c) 2008 Lapo Luchini <lapo@lapo.it> 3 - 4 - // Permission to use, copy, modify, and/or distribute this software for any 5 - // purpose with or without fee is hereby granted, provided that the above 6 - // copyright notice and this permission notice appear in all copies. 7 - // 8 - // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 - // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 - // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 - // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 - // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 - // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 - // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 - 16 - let max = 10000000000000; // biggest 10^n integer that can still fit 2^53 when multiplied by 256 17 - 18 - export class Int10 { 19 - /** 20 - * Arbitrary length base-10 value. 21 - * @param {number} value - Optional initial value (will be 0 otherwise). 22 - */ 23 - constructor(value) { 24 - this.buf = [+value || 0]; 25 - } 26 - 27 - /** 28 - * Multiply value by m and add c. 29 - * @param {number} m - multiplier, must be < =256 30 - * @param {number} c - value to add 31 - */ 32 - mulAdd(m, c) { 33 - // assert(m <= 256) 34 - let b = this.buf, 35 - l = b.length, 36 - i, t; 37 - for (i = 0; i < l; ++i) { 38 - t = b[i] * m + c; 39 - if (t < max) 40 - c = 0; 41 - else { 42 - c = 0|(t / max); 43 - t -= c * max; 44 - } 45 - b[i] = t; 46 - } 47 - if (c > 0) 48 - b[i] = c; 49 - } 50 - 51 - /** 52 - * Subtract value. 53 - * @param {number} c - value to subtract 54 - */ 55 - sub(c) { 56 - let b = this.buf, 57 - l = b.length, 58 - i, t; 59 - for (i = 0; i < l; ++i) { 60 - t = b[i] - c; 61 - if (t < 0) { 62 - t += max; 63 - c = 1; 64 - } else 65 - c = 0; 66 - b[i] = t; 67 - } 68 - while (b[b.length - 1] === 0) 69 - b.pop(); 70 - } 71 - 72 - /** 73 - * Convert to decimal string representation. 74 - * @param {*} base - optional value, only value accepted is 10 75 - */ 76 - toString(base) { 77 - if ((base || 10) != 10) 78 - throw 'only base 10 is supported'; 79 - let b = this.buf, 80 - s = b[b.length - 1].toString(); 81 - for (let i = b.length - 2; i >= 0; --i) 82 - s += (max + b[i]).toString().substring(1); 83 - return s; 84 - } 85 - 86 - /** 87 - * Convert to Number value representation. 88 - * Will probably overflow 2^53 and thus become approximate. 89 - */ 90 - valueOf() { 91 - let b = this.buf, 92 - v = 0; 93 - for (let i = b.length - 1; i >= 0; --i) 94 - v = v * max + b[i]; 95 - return v; 96 - } 97 - 98 - /** 99 - * Return value as a simple Number (if it is <= 10000000000000), or return this. 100 - */ 101 - simplify() { 102 - let b = this.buf; 103 - return (b.length == 1) ? b[0] : this; 104 - } 105 - 106 - }
···
+33 -77
package.json
··· 1 { 2 "name": "@lapo/asn1js", 3 - "version": "2.0.5", 4 "description": "Generic ASN.1 parser/decoder that can decode any valid ASN.1 DER or BER structures.", 5 "type": "module", 6 "main": "asn1.js", ··· 8 "type": "git", 9 "url": "git+https://github.com/lapo-luchini/asn1js.git" 10 }, 11 - "keywords": [ "asn1", "ber", "der", "pem" ], 12 "author": "Lapo Luchini <lapo@lapo.it>", 13 "license": "ISC", 14 - "bugs": { "url": "https://github.com/lapo-luchini/asn1js/issues" }, 15 "homepage": "https://lapo.it/asn1js/", 16 - "files": [ "asn1.js", "base64.js", "hex.js", "int10.js", "dom.js", "defs.js", "oids.js", "rfcdef.js", "dumpASN1.js" ], 17 "scripts": { 18 - "lint": "npx eslint asn1.js base64.js hex.js int10.js dom.js defs.js oids.js rfcdef.js tags.js context.js index.js parseRFC.js dumpASN1.js test.js testDefs.js vite.config.js theme.js", 19 "lint-action": "npx @action-validator/cli .github/workflows/node.js.yml", 20 "build": "vite build", 21 - "serve": "echo 'Connect to http://localhost:3000/' ; npx statik --port 3000 .", 22 "test": "node test", 23 "testdefs": "node testDefs" 24 }, ··· 26 "dumpASN1": "./dumpASN1.js" 27 }, 28 "engines": { 29 - "node": ">=12.20.0" 30 }, 31 "devDependencies": { 32 - "@rollup/wasm-node": "^4.25.0", 33 - "eslint": "^8.57.1", 34 "htmlparser2": "^9.1.0", 35 - "vite": "^5.4.10", 36 - "vite-plugin-dom": "^1.0.4", 37 - "vite-plugin-singlefile": "^2.0.3" 38 }, 39 "overrides": { 40 "rollup": "npm:@rollup/wasm-node" ··· 43 "overrides": { 44 "rollup": "npm:@rollup/wasm-node" 45 } 46 - }, 47 - "eslintConfig": { 48 - "env": { 49 - "es6": true, 50 - "browser": true, 51 - "node": true 52 - }, 53 - "parserOptions": { 54 - "ecmaVersion": 2015, 55 - "sourceType": "module" 56 - }, 57 - "extends": [ "eslint:recommended" ], 58 - "globals": { 59 - "Uint8Array": "readonly" 60 - }, 61 - "rules": { 62 - "strict": [ "error", "function" ], 63 - "indent": [ "error", 4 ], 64 - "no-trailing-spaces": [ "error" ], 65 - "linebreak-style": [ "error", "unix" ], 66 - "eol-last": [ "error", "always" ], 67 - "semi": [ "warn", "always" ], 68 - "quotes": [ "error", "single", { "avoidEscape": true } ], 69 - "no-var": [ "warn" ], 70 - "comma-dangle": [ "error", "always-multiline" ] 71 - }, 72 - "overrides": [ 73 - { 74 - "files": [ "defs.js" ], 75 - "parserOptions": { 76 - "ecmaVersion": 2020 77 - } 78 - }, { 79 - "files": [ "test.js", "parseRFC.js", "dumpASN1.js" ], 80 - "parserOptions": { 81 - "ecmaVersion": 2021 82 - }, 83 - "rules": { 84 - "strict": [ "error", "global" ] 85 - } 86 - }, { 87 - "files": [ "oids.js" ], 88 - "rules": { 89 - "indent": "off", 90 - "quotes": [ "warn", "double" ] 91 - } 92 - }, { 93 - "files": [ "tags.js", "rfcdef.js" ], 94 - "rules": { 95 - "indent": [ "error", 2, { "ignoredNodes": [ "Program > ExpressionStatement > CallExpression > FunctionExpression > BlockStatement > ExpressionStatement[directive='use strict']:first-child" ] } ], 96 - "comma-dangle": "off", 97 - "quotes": [ "warn", "double" ] 98 - } 99 - }, { 100 - "files": [ "defs.js" ], 101 - "parserOptions": { 102 - "ecmaVersion": 2021 103 - } 104 - }, { 105 - "files": [ "testDefs.js" ], 106 - "parserOptions": { 107 - "ecmaVersion": 2022 108 - } 109 - } 110 - ] 111 } 112 }
··· 1 { 2 "name": "@lapo/asn1js", 3 + "version": "2.1.1", 4 "description": "Generic ASN.1 parser/decoder that can decode any valid ASN.1 DER or BER structures.", 5 "type": "module", 6 "main": "asn1.js", ··· 8 "type": "git", 9 "url": "git+https://github.com/lapo-luchini/asn1js.git" 10 }, 11 + "keywords": [ 12 + "asn1", 13 + "ber", 14 + "der", 15 + "pem" 16 + ], 17 "author": "Lapo Luchini <lapo@lapo.it>", 18 "license": "ISC", 19 + "bugs": { 20 + "url": "https://github.com/lapo-luchini/asn1js/issues" 21 + }, 22 "homepage": "https://lapo.it/asn1js/", 23 + "files": [ 24 + "asn1.js", 25 + "base64.js", 26 + "hex.js", 27 + "dom.js", 28 + "defs.js", 29 + "oids.js", 30 + "rfcdef.js", 31 + "dumpASN1.js" 32 + ], 33 "scripts": { 34 + "lint": "npx eslint asn1.js base64.js hex.js dom.js defs.js oids.js rfcdef.js tags.js context.js index.js parseRFC.js dumpASN1.js test.js testDefs.js vite.config.js theme.js", 35 "lint-action": "npx @action-validator/cli .github/workflows/node.js.yml", 36 "build": "vite build", 37 + "serve": "npx -p local-web-server ws", 38 "test": "node test", 39 "testdefs": "node testDefs" 40 }, ··· 42 "dumpASN1": "./dumpASN1.js" 43 }, 44 "engines": { 45 + "node": ">=14.6.0" 46 }, 47 + "packageManager": "pnpm@7.33.7", 48 "devDependencies": { 49 + "@eslint/eslintrc": "^3.3.1", 50 + "@eslint/js": "^9.38.0", 51 + "@rollup/wasm-node": "^4.52.5", 52 + "diff": "^8.0.2", 53 + "eslint": "^9.38.0", 54 + "globals": "^16.4.0", 55 "htmlparser2": "^9.1.0", 56 + "vite": "^7.1.12", 57 + "vite-plugin-dom": "^1.0.5", 58 + "vite-plugin-singlefile": "^2.3.0" 59 }, 60 "overrides": { 61 "rollup": "npm:@rollup/wasm-node" ··· 64 "overrides": { 65 "rollup": "npm:@rollup/wasm-node" 66 } 67 } 68 }
+4 -4
parseRFC.js
··· 213 tryToken(expect) { 214 let p = this.pos; 215 let t; 216 - try { t = this.parseToken(); } catch (e) { /*ignore*/ } 217 // console.log('[debug] tryToken(' + expect + ') = ' + t); 218 if (t == expect) 219 return true; ··· 371 let p = this.pos; 372 try { 373 return this.parseBuiltinType(); 374 - } catch (e) { 375 // console.log('[debug] parseAssignment failed on parseType', e); 376 this.pos = p; 377 let x = { ··· 442 case 'NULL': 443 return null; 444 } 445 - } catch (e) { 446 this.pos = p; 447 } 448 p = this.pos; 449 try { 450 return this.parseIdentifier(); 451 - } catch (e) { 452 this.pos = p; 453 } 454 this.exception('Unknown value type.');
··· 213 tryToken(expect) { 214 let p = this.pos; 215 let t; 216 + try { t = this.parseToken(); } catch (ignore) { /*ignore*/ } 217 // console.log('[debug] tryToken(' + expect + ') = ' + t); 218 if (t == expect) 219 return true; ··· 371 let p = this.pos; 372 try { 373 return this.parseBuiltinType(); 374 + } catch (ignore) { 375 // console.log('[debug] parseAssignment failed on parseType', e); 376 this.pos = p; 377 let x = { ··· 442 case 'NULL': 443 return null; 444 } 445 + } catch (ignore) { 446 this.pos = p; 447 } 448 p = this.pos; 449 try { 450 return this.parseIdentifier(); 451 + } catch (ignore) { 452 this.pos = p; 453 } 454 this.exception('Unknown value type.');
+1115
pnpm-lock.yaml
···
··· 1 + lockfileVersion: 5.4 2 + 3 + overrides: 4 + rollup: npm:@rollup/wasm-node 5 + 6 + specifiers: 7 + '@eslint/eslintrc': ^3.3.1 8 + '@eslint/js': ^9.38.0 9 + '@rollup/wasm-node': ^4.52.5 10 + diff: ^8.0.2 11 + eslint: ^9.38.0 12 + globals: ^16.4.0 13 + htmlparser2: ^9.1.0 14 + vite: ^7.1.12 15 + vite-plugin-dom: ^1.0.5 16 + vite-plugin-singlefile: ^2.3.0 17 + 18 + devDependencies: 19 + '@eslint/eslintrc': 3.3.1 20 + '@eslint/js': 9.38.0 21 + '@rollup/wasm-node': 4.52.5 22 + diff: 8.0.2 23 + eslint: 9.38.0 24 + globals: 16.4.0 25 + htmlparser2: 9.1.0 26 + vite: 7.1.12 27 + vite-plugin-dom: 1.0.5_vite@7.1.12 28 + vite-plugin-singlefile: 2.3.0_vite@7.1.12 29 + 30 + packages: 31 + 32 + /@esbuild/aix-ppc64/0.25.11: 33 + resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==} 34 + engines: {node: '>=18'} 35 + cpu: [ppc64] 36 + os: [aix] 37 + requiresBuild: true 38 + dev: true 39 + optional: true 40 + 41 + /@esbuild/android-arm/0.25.11: 42 + resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==} 43 + engines: {node: '>=18'} 44 + cpu: [arm] 45 + os: [android] 46 + requiresBuild: true 47 + dev: true 48 + optional: true 49 + 50 + /@esbuild/android-arm64/0.25.11: 51 + resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==} 52 + engines: {node: '>=18'} 53 + cpu: [arm64] 54 + os: [android] 55 + requiresBuild: true 56 + dev: true 57 + optional: true 58 + 59 + /@esbuild/android-x64/0.25.11: 60 + resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==} 61 + engines: {node: '>=18'} 62 + cpu: [x64] 63 + os: [android] 64 + requiresBuild: true 65 + dev: true 66 + optional: true 67 + 68 + /@esbuild/darwin-arm64/0.25.11: 69 + resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==} 70 + engines: {node: '>=18'} 71 + cpu: [arm64] 72 + os: [darwin] 73 + requiresBuild: true 74 + dev: true 75 + optional: true 76 + 77 + /@esbuild/darwin-x64/0.25.11: 78 + resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==} 79 + engines: {node: '>=18'} 80 + cpu: [x64] 81 + os: [darwin] 82 + requiresBuild: true 83 + dev: true 84 + optional: true 85 + 86 + /@esbuild/freebsd-arm64/0.25.11: 87 + resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==} 88 + engines: {node: '>=18'} 89 + cpu: [arm64] 90 + os: [freebsd] 91 + requiresBuild: true 92 + dev: true 93 + optional: true 94 + 95 + /@esbuild/freebsd-x64/0.25.11: 96 + resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==} 97 + engines: {node: '>=18'} 98 + cpu: [x64] 99 + os: [freebsd] 100 + requiresBuild: true 101 + dev: true 102 + optional: true 103 + 104 + /@esbuild/linux-arm/0.25.11: 105 + resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==} 106 + engines: {node: '>=18'} 107 + cpu: [arm] 108 + os: [linux] 109 + requiresBuild: true 110 + dev: true 111 + optional: true 112 + 113 + /@esbuild/linux-arm64/0.25.11: 114 + resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==} 115 + engines: {node: '>=18'} 116 + cpu: [arm64] 117 + os: [linux] 118 + requiresBuild: true 119 + dev: true 120 + optional: true 121 + 122 + /@esbuild/linux-ia32/0.25.11: 123 + resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==} 124 + engines: {node: '>=18'} 125 + cpu: [ia32] 126 + os: [linux] 127 + requiresBuild: true 128 + dev: true 129 + optional: true 130 + 131 + /@esbuild/linux-loong64/0.25.11: 132 + resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==} 133 + engines: {node: '>=18'} 134 + cpu: [loong64] 135 + os: [linux] 136 + requiresBuild: true 137 + dev: true 138 + optional: true 139 + 140 + /@esbuild/linux-mips64el/0.25.11: 141 + resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==} 142 + engines: {node: '>=18'} 143 + cpu: [mips64el] 144 + os: [linux] 145 + requiresBuild: true 146 + dev: true 147 + optional: true 148 + 149 + /@esbuild/linux-ppc64/0.25.11: 150 + resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==} 151 + engines: {node: '>=18'} 152 + cpu: [ppc64] 153 + os: [linux] 154 + requiresBuild: true 155 + dev: true 156 + optional: true 157 + 158 + /@esbuild/linux-riscv64/0.25.11: 159 + resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==} 160 + engines: {node: '>=18'} 161 + cpu: [riscv64] 162 + os: [linux] 163 + requiresBuild: true 164 + dev: true 165 + optional: true 166 + 167 + /@esbuild/linux-s390x/0.25.11: 168 + resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==} 169 + engines: {node: '>=18'} 170 + cpu: [s390x] 171 + os: [linux] 172 + requiresBuild: true 173 + dev: true 174 + optional: true 175 + 176 + /@esbuild/linux-x64/0.25.11: 177 + resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==} 178 + engines: {node: '>=18'} 179 + cpu: [x64] 180 + os: [linux] 181 + requiresBuild: true 182 + dev: true 183 + optional: true 184 + 185 + /@esbuild/netbsd-arm64/0.25.11: 186 + resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==} 187 + engines: {node: '>=18'} 188 + cpu: [arm64] 189 + os: [netbsd] 190 + requiresBuild: true 191 + dev: true 192 + optional: true 193 + 194 + /@esbuild/netbsd-x64/0.25.11: 195 + resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==} 196 + engines: {node: '>=18'} 197 + cpu: [x64] 198 + os: [netbsd] 199 + requiresBuild: true 200 + dev: true 201 + optional: true 202 + 203 + /@esbuild/openbsd-arm64/0.25.11: 204 + resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==} 205 + engines: {node: '>=18'} 206 + cpu: [arm64] 207 + os: [openbsd] 208 + requiresBuild: true 209 + dev: true 210 + optional: true 211 + 212 + /@esbuild/openbsd-x64/0.25.11: 213 + resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==} 214 + engines: {node: '>=18'} 215 + cpu: [x64] 216 + os: [openbsd] 217 + requiresBuild: true 218 + dev: true 219 + optional: true 220 + 221 + /@esbuild/openharmony-arm64/0.25.11: 222 + resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==} 223 + engines: {node: '>=18'} 224 + cpu: [arm64] 225 + os: [openharmony] 226 + requiresBuild: true 227 + dev: true 228 + optional: true 229 + 230 + /@esbuild/sunos-x64/0.25.11: 231 + resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==} 232 + engines: {node: '>=18'} 233 + cpu: [x64] 234 + os: [sunos] 235 + requiresBuild: true 236 + dev: true 237 + optional: true 238 + 239 + /@esbuild/win32-arm64/0.25.11: 240 + resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==} 241 + engines: {node: '>=18'} 242 + cpu: [arm64] 243 + os: [win32] 244 + requiresBuild: true 245 + dev: true 246 + optional: true 247 + 248 + /@esbuild/win32-ia32/0.25.11: 249 + resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==} 250 + engines: {node: '>=18'} 251 + cpu: [ia32] 252 + os: [win32] 253 + requiresBuild: true 254 + dev: true 255 + optional: true 256 + 257 + /@esbuild/win32-x64/0.25.11: 258 + resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==} 259 + engines: {node: '>=18'} 260 + cpu: [x64] 261 + os: [win32] 262 + requiresBuild: true 263 + dev: true 264 + optional: true 265 + 266 + /@eslint-community/eslint-utils/4.9.0_eslint@9.38.0: 267 + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} 268 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 269 + peerDependencies: 270 + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 271 + dependencies: 272 + eslint: 9.38.0 273 + eslint-visitor-keys: 3.4.3 274 + dev: true 275 + 276 + /@eslint-community/regexpp/4.12.2: 277 + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} 278 + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} 279 + dev: true 280 + 281 + /@eslint/config-array/0.21.1: 282 + resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} 283 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 284 + dependencies: 285 + '@eslint/object-schema': 2.1.7 286 + debug: 4.4.3 287 + minimatch: 3.1.2 288 + transitivePeerDependencies: 289 + - supports-color 290 + dev: true 291 + 292 + /@eslint/config-helpers/0.4.2: 293 + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} 294 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 295 + dependencies: 296 + '@eslint/core': 0.17.0 297 + dev: true 298 + 299 + /@eslint/core/0.16.0: 300 + resolution: {integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==} 301 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 302 + dependencies: 303 + '@types/json-schema': 7.0.15 304 + dev: true 305 + 306 + /@eslint/core/0.17.0: 307 + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} 308 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 309 + dependencies: 310 + '@types/json-schema': 7.0.15 311 + dev: true 312 + 313 + /@eslint/eslintrc/3.3.1: 314 + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} 315 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 316 + dependencies: 317 + ajv: 6.12.6 318 + debug: 4.4.3 319 + espree: 10.4.0 320 + globals: 14.0.0 321 + ignore: 5.3.2 322 + import-fresh: 3.3.1 323 + js-yaml: 4.1.0 324 + minimatch: 3.1.2 325 + strip-json-comments: 3.1.1 326 + transitivePeerDependencies: 327 + - supports-color 328 + dev: true 329 + 330 + /@eslint/js/9.38.0: 331 + resolution: {integrity: sha512-UZ1VpFvXf9J06YG9xQBdnzU+kthors6KjhMAl6f4gH4usHyh31rUf2DLGInT8RFYIReYXNSydgPY0V2LuWgl7A==} 332 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 333 + dev: true 334 + 335 + /@eslint/object-schema/2.1.7: 336 + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} 337 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 338 + dev: true 339 + 340 + /@eslint/plugin-kit/0.4.1: 341 + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} 342 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 343 + dependencies: 344 + '@eslint/core': 0.17.0 345 + levn: 0.4.1 346 + dev: true 347 + 348 + /@humanfs/core/0.19.1: 349 + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} 350 + engines: {node: '>=18.18.0'} 351 + dev: true 352 + 353 + /@humanfs/node/0.16.7: 354 + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} 355 + engines: {node: '>=18.18.0'} 356 + dependencies: 357 + '@humanfs/core': 0.19.1 358 + '@humanwhocodes/retry': 0.4.3 359 + dev: true 360 + 361 + /@humanwhocodes/module-importer/1.0.1: 362 + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} 363 + engines: {node: '>=12.22'} 364 + dev: true 365 + 366 + /@humanwhocodes/retry/0.4.3: 367 + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} 368 + engines: {node: '>=18.18'} 369 + dev: true 370 + 371 + /@rollup/wasm-node/4.52.5: 372 + resolution: {integrity: sha512-ldY4tEzSMBHNwB8TfRpi7RRRjjyfKlwjdebw5pS1lu0xaY3g4RDc6ople2wEYulVOKVeH7ZJwRx0iw4pGtjMHg==} 373 + engines: {node: '>=18.0.0', npm: '>=8.0.0'} 374 + hasBin: true 375 + dependencies: 376 + '@types/estree': 1.0.8 377 + optionalDependencies: 378 + fsevents: 2.3.3 379 + dev: true 380 + 381 + /@types/estree/1.0.8: 382 + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} 383 + dev: true 384 + 385 + /@types/json-schema/7.0.15: 386 + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} 387 + dev: true 388 + 389 + /acorn-jsx/5.3.2_acorn@8.15.0: 390 + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} 391 + peerDependencies: 392 + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 393 + dependencies: 394 + acorn: 8.15.0 395 + dev: true 396 + 397 + /acorn/8.15.0: 398 + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} 399 + engines: {node: '>=0.4.0'} 400 + hasBin: true 401 + dev: true 402 + 403 + /ajv/6.12.6: 404 + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} 405 + dependencies: 406 + fast-deep-equal: 3.1.3 407 + fast-json-stable-stringify: 2.1.0 408 + json-schema-traverse: 0.4.1 409 + uri-js: 4.4.1 410 + dev: true 411 + 412 + /ansi-styles/4.3.0: 413 + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 414 + engines: {node: '>=8'} 415 + dependencies: 416 + color-convert: 2.0.1 417 + dev: true 418 + 419 + /argparse/2.0.1: 420 + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} 421 + dev: true 422 + 423 + /balanced-match/1.0.2: 424 + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 425 + dev: true 426 + 427 + /brace-expansion/1.1.12: 428 + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} 429 + dependencies: 430 + balanced-match: 1.0.2 431 + concat-map: 0.0.1 432 + dev: true 433 + 434 + /braces/3.0.3: 435 + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} 436 + engines: {node: '>=8'} 437 + dependencies: 438 + fill-range: 7.1.1 439 + dev: true 440 + 441 + /callsites/3.1.0: 442 + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 443 + engines: {node: '>=6'} 444 + dev: true 445 + 446 + /chalk/4.1.2: 447 + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 448 + engines: {node: '>=10'} 449 + dependencies: 450 + ansi-styles: 4.3.0 451 + supports-color: 7.2.0 452 + dev: true 453 + 454 + /color-convert/2.0.1: 455 + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 456 + engines: {node: '>=7.0.0'} 457 + dependencies: 458 + color-name: 1.1.4 459 + dev: true 460 + 461 + /color-name/1.1.4: 462 + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 463 + dev: true 464 + 465 + /concat-map/0.0.1: 466 + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 467 + dev: true 468 + 469 + /cross-spawn/7.0.6: 470 + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 471 + engines: {node: '>= 8'} 472 + dependencies: 473 + path-key: 3.1.1 474 + shebang-command: 2.0.0 475 + which: 2.0.2 476 + dev: true 477 + 478 + /debug/4.4.3: 479 + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} 480 + engines: {node: '>=6.0'} 481 + peerDependencies: 482 + supports-color: '*' 483 + peerDependenciesMeta: 484 + supports-color: 485 + optional: true 486 + dependencies: 487 + ms: 2.1.3 488 + dev: true 489 + 490 + /deep-is/0.1.4: 491 + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} 492 + dev: true 493 + 494 + /diff/8.0.2: 495 + resolution: {integrity: sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==} 496 + engines: {node: '>=0.3.1'} 497 + dev: true 498 + 499 + /dom-serializer/2.0.0: 500 + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} 501 + dependencies: 502 + domelementtype: 2.3.0 503 + domhandler: 5.0.3 504 + entities: 4.5.0 505 + dev: true 506 + 507 + /domelementtype/2.3.0: 508 + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} 509 + dev: true 510 + 511 + /domhandler/5.0.3: 512 + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} 513 + engines: {node: '>= 4'} 514 + dependencies: 515 + domelementtype: 2.3.0 516 + dev: true 517 + 518 + /domutils/3.2.2: 519 + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} 520 + dependencies: 521 + dom-serializer: 2.0.0 522 + domelementtype: 2.3.0 523 + domhandler: 5.0.3 524 + dev: true 525 + 526 + /entities/4.5.0: 527 + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} 528 + engines: {node: '>=0.12'} 529 + dev: true 530 + 531 + /entities/6.0.1: 532 + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} 533 + engines: {node: '>=0.12'} 534 + dev: true 535 + 536 + /esbuild/0.25.11: 537 + resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==} 538 + engines: {node: '>=18'} 539 + hasBin: true 540 + requiresBuild: true 541 + optionalDependencies: 542 + '@esbuild/aix-ppc64': 0.25.11 543 + '@esbuild/android-arm': 0.25.11 544 + '@esbuild/android-arm64': 0.25.11 545 + '@esbuild/android-x64': 0.25.11 546 + '@esbuild/darwin-arm64': 0.25.11 547 + '@esbuild/darwin-x64': 0.25.11 548 + '@esbuild/freebsd-arm64': 0.25.11 549 + '@esbuild/freebsd-x64': 0.25.11 550 + '@esbuild/linux-arm': 0.25.11 551 + '@esbuild/linux-arm64': 0.25.11 552 + '@esbuild/linux-ia32': 0.25.11 553 + '@esbuild/linux-loong64': 0.25.11 554 + '@esbuild/linux-mips64el': 0.25.11 555 + '@esbuild/linux-ppc64': 0.25.11 556 + '@esbuild/linux-riscv64': 0.25.11 557 + '@esbuild/linux-s390x': 0.25.11 558 + '@esbuild/linux-x64': 0.25.11 559 + '@esbuild/netbsd-arm64': 0.25.11 560 + '@esbuild/netbsd-x64': 0.25.11 561 + '@esbuild/openbsd-arm64': 0.25.11 562 + '@esbuild/openbsd-x64': 0.25.11 563 + '@esbuild/openharmony-arm64': 0.25.11 564 + '@esbuild/sunos-x64': 0.25.11 565 + '@esbuild/win32-arm64': 0.25.11 566 + '@esbuild/win32-ia32': 0.25.11 567 + '@esbuild/win32-x64': 0.25.11 568 + dev: true 569 + 570 + /escape-string-regexp/4.0.0: 571 + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 572 + engines: {node: '>=10'} 573 + dev: true 574 + 575 + /eslint-scope/8.4.0: 576 + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} 577 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 578 + dependencies: 579 + esrecurse: 4.3.0 580 + estraverse: 5.3.0 581 + dev: true 582 + 583 + /eslint-visitor-keys/3.4.3: 584 + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} 585 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 586 + dev: true 587 + 588 + /eslint-visitor-keys/4.2.1: 589 + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} 590 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 591 + dev: true 592 + 593 + /eslint/9.38.0: 594 + resolution: {integrity: sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==} 595 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 596 + hasBin: true 597 + peerDependencies: 598 + jiti: '*' 599 + peerDependenciesMeta: 600 + jiti: 601 + optional: true 602 + dependencies: 603 + '@eslint-community/eslint-utils': 4.9.0_eslint@9.38.0 604 + '@eslint-community/regexpp': 4.12.2 605 + '@eslint/config-array': 0.21.1 606 + '@eslint/config-helpers': 0.4.2 607 + '@eslint/core': 0.16.0 608 + '@eslint/eslintrc': 3.3.1 609 + '@eslint/js': 9.38.0 610 + '@eslint/plugin-kit': 0.4.1 611 + '@humanfs/node': 0.16.7 612 + '@humanwhocodes/module-importer': 1.0.1 613 + '@humanwhocodes/retry': 0.4.3 614 + '@types/estree': 1.0.8 615 + ajv: 6.12.6 616 + chalk: 4.1.2 617 + cross-spawn: 7.0.6 618 + debug: 4.4.3 619 + escape-string-regexp: 4.0.0 620 + eslint-scope: 8.4.0 621 + eslint-visitor-keys: 4.2.1 622 + espree: 10.4.0 623 + esquery: 1.6.0 624 + esutils: 2.0.3 625 + fast-deep-equal: 3.1.3 626 + file-entry-cache: 8.0.0 627 + find-up: 5.0.0 628 + glob-parent: 6.0.2 629 + ignore: 5.3.2 630 + imurmurhash: 0.1.4 631 + is-glob: 4.0.3 632 + json-stable-stringify-without-jsonify: 1.0.1 633 + lodash.merge: 4.6.2 634 + minimatch: 3.1.2 635 + natural-compare: 1.4.0 636 + optionator: 0.9.4 637 + transitivePeerDependencies: 638 + - supports-color 639 + dev: true 640 + 641 + /espree/10.4.0: 642 + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} 643 + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 644 + dependencies: 645 + acorn: 8.15.0 646 + acorn-jsx: 5.3.2_acorn@8.15.0 647 + eslint-visitor-keys: 4.2.1 648 + dev: true 649 + 650 + /esquery/1.6.0: 651 + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} 652 + engines: {node: '>=0.10'} 653 + dependencies: 654 + estraverse: 5.3.0 655 + dev: true 656 + 657 + /esrecurse/4.3.0: 658 + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} 659 + engines: {node: '>=4.0'} 660 + dependencies: 661 + estraverse: 5.3.0 662 + dev: true 663 + 664 + /estraverse/5.3.0: 665 + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} 666 + engines: {node: '>=4.0'} 667 + dev: true 668 + 669 + /esutils/2.0.3: 670 + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} 671 + engines: {node: '>=0.10.0'} 672 + dev: true 673 + 674 + /fast-deep-equal/3.1.3: 675 + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 676 + dev: true 677 + 678 + /fast-json-stable-stringify/2.1.0: 679 + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 680 + dev: true 681 + 682 + /fast-levenshtein/2.0.6: 683 + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} 684 + dev: true 685 + 686 + /fdir/6.5.0_picomatch@4.0.3: 687 + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} 688 + engines: {node: '>=12.0.0'} 689 + peerDependencies: 690 + picomatch: ^3 || ^4 691 + peerDependenciesMeta: 692 + picomatch: 693 + optional: true 694 + dependencies: 695 + picomatch: 4.0.3 696 + dev: true 697 + 698 + /file-entry-cache/8.0.0: 699 + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} 700 + engines: {node: '>=16.0.0'} 701 + dependencies: 702 + flat-cache: 4.0.1 703 + dev: true 704 + 705 + /fill-range/7.1.1: 706 + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} 707 + engines: {node: '>=8'} 708 + dependencies: 709 + to-regex-range: 5.0.1 710 + dev: true 711 + 712 + /find-up/5.0.0: 713 + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} 714 + engines: {node: '>=10'} 715 + dependencies: 716 + locate-path: 6.0.0 717 + path-exists: 4.0.0 718 + dev: true 719 + 720 + /flat-cache/4.0.1: 721 + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} 722 + engines: {node: '>=16'} 723 + dependencies: 724 + flatted: 3.3.3 725 + keyv: 4.5.4 726 + dev: true 727 + 728 + /flatted/3.3.3: 729 + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} 730 + dev: true 731 + 732 + /fsevents/2.3.3: 733 + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 734 + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 735 + os: [darwin] 736 + requiresBuild: true 737 + dev: true 738 + optional: true 739 + 740 + /glob-parent/6.0.2: 741 + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} 742 + engines: {node: '>=10.13.0'} 743 + dependencies: 744 + is-glob: 4.0.3 745 + dev: true 746 + 747 + /globals/14.0.0: 748 + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} 749 + engines: {node: '>=18'} 750 + dev: true 751 + 752 + /globals/16.4.0: 753 + resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} 754 + engines: {node: '>=18'} 755 + dev: true 756 + 757 + /has-flag/4.0.0: 758 + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 759 + engines: {node: '>=8'} 760 + dev: true 761 + 762 + /htmlparser2/10.0.0: 763 + resolution: {integrity: sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==} 764 + dependencies: 765 + domelementtype: 2.3.0 766 + domhandler: 5.0.3 767 + domutils: 3.2.2 768 + entities: 6.0.1 769 + dev: true 770 + 771 + /htmlparser2/9.1.0: 772 + resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} 773 + dependencies: 774 + domelementtype: 2.3.0 775 + domhandler: 5.0.3 776 + domutils: 3.2.2 777 + entities: 4.5.0 778 + dev: true 779 + 780 + /ignore/5.3.2: 781 + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} 782 + engines: {node: '>= 4'} 783 + dev: true 784 + 785 + /import-fresh/3.3.1: 786 + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} 787 + engines: {node: '>=6'} 788 + dependencies: 789 + parent-module: 1.0.1 790 + resolve-from: 4.0.0 791 + dev: true 792 + 793 + /imurmurhash/0.1.4: 794 + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} 795 + engines: {node: '>=0.8.19'} 796 + dev: true 797 + 798 + /is-extglob/2.1.1: 799 + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 800 + engines: {node: '>=0.10.0'} 801 + dev: true 802 + 803 + /is-glob/4.0.3: 804 + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 805 + engines: {node: '>=0.10.0'} 806 + dependencies: 807 + is-extglob: 2.1.1 808 + dev: true 809 + 810 + /is-number/7.0.0: 811 + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 812 + engines: {node: '>=0.12.0'} 813 + dev: true 814 + 815 + /isexe/2.0.0: 816 + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 817 + dev: true 818 + 819 + /js-yaml/4.1.0: 820 + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} 821 + hasBin: true 822 + dependencies: 823 + argparse: 2.0.1 824 + dev: true 825 + 826 + /json-buffer/3.0.1: 827 + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} 828 + dev: true 829 + 830 + /json-schema-traverse/0.4.1: 831 + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 832 + dev: true 833 + 834 + /json-stable-stringify-without-jsonify/1.0.1: 835 + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} 836 + dev: true 837 + 838 + /keyv/4.5.4: 839 + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} 840 + dependencies: 841 + json-buffer: 3.0.1 842 + dev: true 843 + 844 + /levn/0.4.1: 845 + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} 846 + engines: {node: '>= 0.8.0'} 847 + dependencies: 848 + prelude-ls: 1.2.1 849 + type-check: 0.4.0 850 + dev: true 851 + 852 + /locate-path/6.0.0: 853 + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} 854 + engines: {node: '>=10'} 855 + dependencies: 856 + p-locate: 5.0.0 857 + dev: true 858 + 859 + /lodash.merge/4.6.2: 860 + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} 861 + dev: true 862 + 863 + /micromatch/4.0.8: 864 + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} 865 + engines: {node: '>=8.6'} 866 + dependencies: 867 + braces: 3.0.3 868 + picomatch: 2.3.1 869 + dev: true 870 + 871 + /minimatch/3.1.2: 872 + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 873 + dependencies: 874 + brace-expansion: 1.1.12 875 + dev: true 876 + 877 + /ms/2.1.3: 878 + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 879 + dev: true 880 + 881 + /nanoid/3.3.11: 882 + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} 883 + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 884 + hasBin: true 885 + dev: true 886 + 887 + /natural-compare/1.4.0: 888 + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} 889 + dev: true 890 + 891 + /optionator/0.9.4: 892 + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} 893 + engines: {node: '>= 0.8.0'} 894 + dependencies: 895 + deep-is: 0.1.4 896 + fast-levenshtein: 2.0.6 897 + levn: 0.4.1 898 + prelude-ls: 1.2.1 899 + type-check: 0.4.0 900 + word-wrap: 1.2.5 901 + dev: true 902 + 903 + /p-limit/3.1.0: 904 + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} 905 + engines: {node: '>=10'} 906 + dependencies: 907 + yocto-queue: 0.1.0 908 + dev: true 909 + 910 + /p-locate/5.0.0: 911 + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} 912 + engines: {node: '>=10'} 913 + dependencies: 914 + p-limit: 3.1.0 915 + dev: true 916 + 917 + /parent-module/1.0.1: 918 + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} 919 + engines: {node: '>=6'} 920 + dependencies: 921 + callsites: 3.1.0 922 + dev: true 923 + 924 + /path-exists/4.0.0: 925 + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 926 + engines: {node: '>=8'} 927 + dev: true 928 + 929 + /path-key/3.1.1: 930 + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 931 + engines: {node: '>=8'} 932 + dev: true 933 + 934 + /picocolors/1.1.1: 935 + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 936 + dev: true 937 + 938 + /picomatch/2.3.1: 939 + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 940 + engines: {node: '>=8.6'} 941 + dev: true 942 + 943 + /picomatch/4.0.3: 944 + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} 945 + engines: {node: '>=12'} 946 + dev: true 947 + 948 + /postcss/8.5.6: 949 + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} 950 + engines: {node: ^10 || ^12 || >=14} 951 + dependencies: 952 + nanoid: 3.3.11 953 + picocolors: 1.1.1 954 + source-map-js: 1.2.1 955 + dev: true 956 + 957 + /prelude-ls/1.2.1: 958 + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} 959 + engines: {node: '>= 0.8.0'} 960 + dev: true 961 + 962 + /punycode/2.3.1: 963 + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 964 + engines: {node: '>=6'} 965 + dev: true 966 + 967 + /resolve-from/4.0.0: 968 + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} 969 + engines: {node: '>=4'} 970 + dev: true 971 + 972 + /shebang-command/2.0.0: 973 + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 974 + engines: {node: '>=8'} 975 + dependencies: 976 + shebang-regex: 3.0.0 977 + dev: true 978 + 979 + /shebang-regex/3.0.0: 980 + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 981 + engines: {node: '>=8'} 982 + dev: true 983 + 984 + /source-map-js/1.2.1: 985 + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 986 + engines: {node: '>=0.10.0'} 987 + dev: true 988 + 989 + /strip-json-comments/3.1.1: 990 + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 991 + engines: {node: '>=8'} 992 + dev: true 993 + 994 + /supports-color/7.2.0: 995 + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 996 + engines: {node: '>=8'} 997 + dependencies: 998 + has-flag: 4.0.0 999 + dev: true 1000 + 1001 + /tinyglobby/0.2.15: 1002 + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} 1003 + engines: {node: '>=12.0.0'} 1004 + dependencies: 1005 + fdir: 6.5.0_picomatch@4.0.3 1006 + picomatch: 4.0.3 1007 + dev: true 1008 + 1009 + /to-regex-range/5.0.1: 1010 + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 1011 + engines: {node: '>=8.0'} 1012 + dependencies: 1013 + is-number: 7.0.0 1014 + dev: true 1015 + 1016 + /type-check/0.4.0: 1017 + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} 1018 + engines: {node: '>= 0.8.0'} 1019 + dependencies: 1020 + prelude-ls: 1.2.1 1021 + dev: true 1022 + 1023 + /uri-js/4.4.1: 1024 + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 1025 + dependencies: 1026 + punycode: 2.3.1 1027 + dev: true 1028 + 1029 + /vite-plugin-dom/1.0.5_vite@7.1.12: 1030 + resolution: {integrity: sha512-G3MbuH30FpBD800I26xlB6lUiDm7sCxvQkHPt9OAJyUEbyiO9UWrKADxVUhWbO65WqL/TGtH1OEez+w++TlfMw==} 1031 + peerDependencies: 1032 + vite: '>=4.0.0' 1033 + dependencies: 1034 + htmlparser2: 10.0.0 1035 + vite: 7.1.12 1036 + dev: true 1037 + 1038 + /vite-plugin-singlefile/2.3.0_vite@7.1.12: 1039 + resolution: {integrity: sha512-DAcHzYypM0CasNLSz/WG0VdKOCxGHErfrjOoyIPiNxTPTGmO6rRD/te93n1YL/s+miXq66ipF1brMBikf99c6A==} 1040 + engines: {node: '>18.0.0'} 1041 + peerDependencies: 1042 + rollup: ^4.44.1 1043 + vite: ^5.4.11 || ^6.0.0 || ^7.0.0 1044 + dependencies: 1045 + micromatch: 4.0.8 1046 + vite: 7.1.12 1047 + dev: true 1048 + 1049 + /vite/7.1.12: 1050 + resolution: {integrity: sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==} 1051 + engines: {node: ^20.19.0 || >=22.12.0} 1052 + hasBin: true 1053 + peerDependencies: 1054 + '@types/node': ^20.19.0 || >=22.12.0 1055 + jiti: '>=1.21.0' 1056 + less: ^4.0.0 1057 + lightningcss: ^1.21.0 1058 + sass: ^1.70.0 1059 + sass-embedded: ^1.70.0 1060 + stylus: '>=0.54.8' 1061 + sugarss: ^5.0.0 1062 + terser: ^5.16.0 1063 + tsx: ^4.8.1 1064 + yaml: ^2.4.2 1065 + peerDependenciesMeta: 1066 + '@types/node': 1067 + optional: true 1068 + jiti: 1069 + optional: true 1070 + less: 1071 + optional: true 1072 + lightningcss: 1073 + optional: true 1074 + sass: 1075 + optional: true 1076 + sass-embedded: 1077 + optional: true 1078 + stylus: 1079 + optional: true 1080 + sugarss: 1081 + optional: true 1082 + terser: 1083 + optional: true 1084 + tsx: 1085 + optional: true 1086 + yaml: 1087 + optional: true 1088 + dependencies: 1089 + esbuild: 0.25.11 1090 + fdir: 6.5.0_picomatch@4.0.3 1091 + picomatch: 4.0.3 1092 + postcss: 8.5.6 1093 + rollup: /@rollup/wasm-node/4.52.5 1094 + tinyglobby: 0.2.15 1095 + optionalDependencies: 1096 + fsevents: 2.3.3 1097 + dev: true 1098 + 1099 + /which/2.0.2: 1100 + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1101 + engines: {node: '>= 8'} 1102 + hasBin: true 1103 + dependencies: 1104 + isexe: 2.0.0 1105 + dev: true 1106 + 1107 + /word-wrap/1.2.5: 1108 + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} 1109 + engines: {node: '>=0.10.0'} 1110 + dev: true 1111 + 1112 + /yocto-queue/0.1.0: 1113 + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} 1114 + engines: {node: '>=10'} 1115 + dev: true
+2 -2
release.sh
··· 1 #!/bin/sh 2 set -e 3 FILES=" 4 - asn1.js oids.js defs.js base64.js hex.js int10.js dom.js context.js theme.js 5 rfcdef.js test.js tags.js 6 index.html index.css index.js index-local.html 7 favicon.svg tree-icon-light.svg tree-icon-dark.svg 8 - README.md LICENSE 9 updateOID.sh check.sh 10 examples 11 "
··· 1 #!/bin/sh 2 set -e 3 FILES=" 4 + asn1.js oids.js defs.js base64.js hex.js dom.js context.js theme.js 5 rfcdef.js test.js tags.js 6 index.html index.css index.js index-local.html 7 favicon.svg tree-icon-light.svg tree-icon-dark.svg 8 + README.md LICENSE CHANGELOG.md 9 updateOID.sh check.sh 10 examples 11 "
+4
tags.js
··· 1 export const tags = { 2 "2.0.4": "2024-05-08", 3 "2.0.3": "2024-05-06", 4 "2.0.2": "2024-04-20",
··· 1 export const tags = { 2 + "2.1.1": "2025-10-24", 3 + "2.1.0": "2025-08-03", 4 + "2.0.6": "2025-07-28", 5 + "2.0.5": "2025-04-12", 6 "2.0.4": "2024-05-08", 7 "2.0.3": "2024-05-06", 8 "2.0.2": "2024-04-20",
+172 -38
test.js
··· 1 #!/usr/bin/env node 2 3 - import { ASN1 } from './asn1.js'; 4 import { Hex } from './hex.js'; 5 6 - const 7 - all = (process.argv[2] == 'all'); 8 9 - const tests = [ 10 // RSA Laboratories technical notes from https://luca.ntop.org/Teaching/Appunti/asn1.html 11 ['0304066E5DC0', '(18 bit)\n011011100101110111', 'ntop, bit string: DER encoding'], 12 ['0304066E5DE0', '(18 bit)\n011011100101110111', 'ntop, bit string: padded with "100000"'], ··· 75 ['0D04C27B0302','8571.3.2', 'Relative OID from ISO/IEC 8825-1:2002 8.20.5'], 76 // UTF-8 77 ['0C0E4C61706FE280997320F09F9A972E', 'Lapoโ€™s ๐Ÿš—.', 'UTF-8 4-byte sequence'], 78 - // T-REC-X.690-201508 79 ['0307040A3B5F291CD0', '(44 bit)\n00001010001110110101111100101001000111001101', 'Example 8.6.4.2: bit string (primitive encoding)'], 80 ['23800303000A3B0305045F291CD00000', '(44 bit)\n00001010001110110101111100101001000111001101', 'Example 8.6.4.2: bit string (constructed encoding)'], 81 // avoid past bugs 82 ['23800303000A3B230A0302005F030404291CD00000', '(44 bit)\n00001010001110110101111100101001000111001101', 'Bit string (recursive constructed)'], 83 ['0348003045022100DE601E573DAFB59BC551D58E3E7B9EDA0612DD0112805A2217B734759B884417022067C3FDE60780D41C1D7A3B90291F3D39C4DC2F206DCCBA2F982C06B67C09B232', '(568 bit)\n0011000001000101000000100010000100000000110111100110000000011110010101110011110110101111101101011001101111000101010100011101010110001110001111100111101110011110110110100000011000010010110111010000000100010010100000000101101000100010000101111011011100110100011101011001101110001000010001000001011100000010001000000110011111000011111111011110011000000111100000001101010000011100000111010111101000111011100100000010100100011111001111010011100111000100110111000010111100100000011011011100110010111010001011111001100000101100000001101011011001111100000010011011001000110010', 'not constructed, but contains structures'], ··· 88 ['181331393835313130363231303632372E332B3134', '1985-11-06 21:06:27.3 UTC+14:00', 'UTC offset +13 and +14'], // GitHub issue #54 89 ['032100171E83C1B251803F86DD01E9CFA886BE89A7316D8372649AC2231EC669F81A84', n => { if (n.sub != null) return 'Should not decode content: ' + n.sub[0].content(); }, 'Key that resembles an UTCTime'], // GitHub issue #79 90 ['171E83C1B251803F86DD01E9CFA886BE89A7316D8372649AC2231EC669F81A84', /^Exception:\nError: Unrecognized time: /, 'Invalid UTCTime'], // GitHub issue #79 91 - ]; 92 93 - let 94 - run = 0, 95 - expErr = 0, 96 - error = 0; 97 - tests.forEach(function (t) { 98 - const input = t[0], 99 - expected = t[1], 100 - comment = t[2]; 101 - let result; 102 - try { 103 - let node = ASN1.decode(Hex.decode(input)); 104 - if (typeof expected == 'function') 105 - result = expected(node); 106 - else 107 - result = node.content(); 108 - //TODO: check structure, not only first level content 109 - } catch (e) { 110 - result = 'Exception:\n' + e; 111 } 112 - if (expected instanceof RegExp) 113 - result = expected.test(result) ? null : 'does not match'; 114 - ++run; 115 - if (!result || result == expected) { 116 - if (all) console.log('\x1B[1m\x1B[32mOK \x1B[39m\x1B[22m ' + comment); 117 - } else { 118 - ++error; 119 - console.log('\x1B[1m\x1B[31mERR\x1B[39m\x1B[22m ' + comment); 120 - console.log(' \x1B[1m\x1B[34mEXP\x1B[39m\x1B[22m ' + expected.toString().replace(/\n/g, '\n ')); 121 - console.log(' \x1B[1m\x1B[33mGOT\x1B[39m\x1B[22m ' + result.replace(/\n/g, '\n ')); 122 - } 123 - }); 124 - console.log(run + ' tested, ' + expErr + ' expected, ' + error + ' errors.'); 125 - process.exit(error ? 1 : 0);
··· 1 #!/usr/bin/env node 2 3 + import * as fs from 'fs'; // 'node:fs' doesn't work on NodeJS 14.5.0 4 + import { ASN1, Stream } from './asn1.js'; 5 + import { Defs } from './defs.js'; 6 import { Hex } from './hex.js'; 7 + import { Base64 } from './base64.js'; 8 + import { createPatch } from 'diff'; 9 10 + const all = (process.argv[2] == 'all'); 11 + 12 + /** @type {Array<Tests>} */ 13 + const tests = []; 14 + 15 + const stats = { 16 + run: 0, 17 + error: 0, 18 + }; 19 + 20 + function diff(str1, str2) { 21 + let s = createPatch('test', str1, str2, null, null, { context: 2 }); 22 + s = s.slice(s.indexOf('@@'), -1); 23 + s = s.replace(/^@@.*/mg, '\x1B[34m$&\x1B[39m'); 24 + s = s.replace(/^-.*/mg, '\x1B[31m$&\x1B[39m'); 25 + s = s.replace(/^\+.*/mg, '\x1B[32m$&\x1B[39m'); 26 + return s; 27 + } 28 + 29 + /** 30 + * A class for managing and executing tests. 31 + */ 32 + class Tests { 33 + /** 34 + * The title of the test suite. 35 + * @type {string} 36 + */ 37 + title; 38 + 39 + /** 40 + * An array to store test data. 41 + * @type {Array<unknown>} 42 + */ 43 + data; 44 + 45 + /** 46 + * Checks a row of test data. 47 + * @param {Function} t - How to test a row of data. 48 + */ 49 + checkRow; 50 + 51 + /** 52 + * Constructs a new Tests instance. 53 + * @param {string} title - The title of the test suite. 54 + * @param {Function} checkRow - A function to check each row of data. 55 + * @param {Array<unknown>} data - The test data to be processed. 56 + */ 57 + constructor(title, checkRow, data) { 58 + this.title = title; 59 + this.checkRow = checkRow; 60 + this.data = data; 61 + } 62 63 + /** 64 + * Executes the tests and checks their results for all rows. 65 + */ 66 + checkAll() { 67 + if (all) console.log('\x1B[1m\x1B[34m' + this.title + '\x1B[39m\x1B[22m'); 68 + for (const t of this.data) 69 + this.checkRow(t); 70 + } 71 + 72 + /** 73 + * Prints the result of a test, indicating if it passed or failed. 74 + * @param {unknown} result The actual result of the test. 75 + * @param {unknown} expected The expected result of the test. 76 + * @param {string} comment A comment describing the test. 77 + */ 78 + checkResult(result, expected, comment) { 79 + ++stats.run; 80 + if ((typeof expected != 'string' && !result) || result == expected) { 81 + if (all) console.log('\x1B[1m\x1B[32mOK \x1B[39m\x1B[22m ' + comment); 82 + } else { 83 + ++stats.error; 84 + console.log('\x1B[1m\x1B[31mERR\x1B[39m\x1B[22m ' + comment); 85 + if (!result) result = '(empty)'; 86 + if (typeof expected != 'string') { 87 + console.log(' ' + result); 88 + } else if (result.length > 100) { 89 + console.log(' \x1B[1m\x1B[34mDIF\x1B[39m\x1B[22m ' + diff(result, expected.toString()).replace(/\n/g, '\n ')); 90 + } else { 91 + console.log(' \x1B[1m\x1B[34mEXP\x1B[39m\x1B[22m ' + expected.toString().replace(/\n/g, '\n ')); 92 + console.log(' \x1B[1m\x1B[33mGOT\x1B[39m\x1B[22m ' + result.replace(/\n/g, '\n ')); 93 + } 94 + } 95 + } 96 + } 97 + 98 + tests.push(new Tests('ASN.1', function (t) { 99 + const input = t[0], 100 + expected = t[1], 101 + comment = t[2]; 102 + let result; 103 + try { 104 + let node = ASN1.decode(Hex.decode(input)); 105 + if (typeof expected == 'function') 106 + result = expected(node); 107 + else 108 + result = node.content(); 109 + //TODO: check structure, not only first level content 110 + } catch (e) { 111 + result = 'Exception:\n' + e; 112 + } 113 + if (expected instanceof RegExp) 114 + result = expected.test(result) ? null : 'does not match'; 115 + this.checkResult(result, expected, comment); 116 + }, [ 117 // RSA Laboratories technical notes from https://luca.ntop.org/Teaching/Appunti/asn1.html 118 ['0304066E5DC0', '(18 bit)\n011011100101110111', 'ntop, bit string: DER encoding'], 119 ['0304066E5DE0', '(18 bit)\n011011100101110111', 'ntop, bit string: padded with "100000"'], ··· 182 ['0D04C27B0302','8571.3.2', 'Relative OID from ISO/IEC 8825-1:2002 8.20.5'], 183 // UTF-8 184 ['0C0E4C61706FE280997320F09F9A972E', 'Lapoโ€™s ๐Ÿš—.', 'UTF-8 4-byte sequence'], 185 + // T-REC-X.690-202102 186 ['0307040A3B5F291CD0', '(44 bit)\n00001010001110110101111100101001000111001101', 'Example 8.6.4.2: bit string (primitive encoding)'], 187 ['23800303000A3B0305045F291CD00000', '(44 bit)\n00001010001110110101111100101001000111001101', 'Example 8.6.4.2: bit string (constructed encoding)'], 188 + ['0603883703', '2.999.3', 'Example 8.19.5: object identifier'], 189 + // X.690 section 8.2.1 โ€œThe contents octets shall consist of a single octet.โ€ 190 + ['010100', 'false', 'Boolean with correct length (false)'], 191 + ['010101', 'true', 'Boolean with correct length (true)'], 192 + ['0100', 'invalid length 0', 'Boolean with zero length'], 193 + ['01020000', 'invalid length 2', 'Boolean with excessive length'], 194 + // X.690 section 8.3.1 โ€œThe contents octets shall consist of one or more octets.โ€ 195 + ['020100', '0', 'Integer with correct length'], 196 + ['0200', 'invalid length 0', 'Integer with zero length'], 197 + // X.690 section 8.19.4 kinda imples that the minimum number of components is 2 198 + ['0600', 'invalid length 0', 'Object identifier with zero length'], 199 + ['060100', '0.0', 'Object identifier with minimal (?) length'], 200 // avoid past bugs 201 ['23800303000A3B230A0302005F030404291CD00000', '(44 bit)\n00001010001110110101111100101001000111001101', 'Bit string (recursive constructed)'], 202 ['0348003045022100DE601E573DAFB59BC551D58E3E7B9EDA0612DD0112805A2217B734759B884417022067C3FDE60780D41C1D7A3B90291F3D39C4DC2F206DCCBA2F982C06B67C09B232', '(568 bit)\n0011000001000101000000100010000100000000110111100110000000011110010101110011110110101111101101011001101111000101010100011101010110001110001111100111101110011110110110100000011000010010110111010000000100010010100000000101101000100010000101111011011100110100011101011001101110001000010001000001011100000010001000000110011111000011111111011110011000000111100000001101010000011100000111010111101000111011100100000010100100011111001111010011100111000100110111000010111100100000011011011100110010111010001011111001100000101100000001101011011001111100000010011011001000110010', 'not constructed, but contains structures'], ··· 207 ['181331393835313130363231303632372E332B3134', '1985-11-06 21:06:27.3 UTC+14:00', 'UTC offset +13 and +14'], // GitHub issue #54 208 ['032100171E83C1B251803F86DD01E9CFA886BE89A7316D8372649AC2231EC669F81A84', n => { if (n.sub != null) return 'Should not decode content: ' + n.sub[0].content(); }, 'Key that resembles an UTCTime'], // GitHub issue #79 209 ['171E83C1B251803F86DD01E9CFA886BE89A7316D8372649AC2231EC669F81A84', /^Exception:\nError: Unrecognized time: /, 'Invalid UTCTime'], // GitHub issue #79 210 + ])); 211 212 + tests.push(new Tests('Dump of examples', function () { 213 + const examples = fs.readdirSync('examples/').filter(f => f.endsWith('.dump')); 214 + for (const example of examples) { 215 + const filename = example.slice(0, -5); // Remove '.dump' suffix 216 + const expected = fs.readFileSync('examples/' + example, 'utf8'); 217 + let data = fs.readFileSync('examples/' + filename); 218 + data = Base64.unarmor(data); 219 + let node = ASN1.decode(data); 220 + const types = Defs.commonTypes 221 + .map(type => { 222 + const stats = Defs.match(node, type); 223 + return { type, match: stats.recognized / stats.total }; 224 + }) 225 + .sort((a, b) => b.match - a.match); 226 + Defs.match(node, types[0].type); 227 + let result = node.toPrettyString(); 228 + this.checkResult(result, expected, 'Dump of examples/' + filename); 229 } 230 + }, [ 231 + [0], 232 + ])); 233 + 234 + tests.push(new Tests('Base64', function (t) { 235 + let bin = Base64.decode(t); 236 + let url = new Stream(bin, 0).b64Dump(0, bin.length); 237 + // check base64url encoding 238 + this.checkResult(url, t.replace(/\n/g, '').replace(/=*$/g, ''), 'Base64url: ' + bin.length + ' bytes'); 239 + // check conversion from base64url to base64 240 + let pretty = Base64.pretty(url); 241 + this.checkResult(pretty, t, 'Base64pretty: ' + bin.length + ' bytes'); 242 + let std = new Stream(bin, 0).b64Dump(0, bin.length, 'std'); 243 + // check direct base64 encoding 244 + this.checkResult(std, t.replace(/\n/g, ''), 'Base64: ' + bin.length + ' bytes'); 245 + }, [ 246 + 'AA==', 247 + 'ABA=', 248 + 'ABCD', 249 + 'ABCDEA==', 250 + 'ABCDEFE=', 251 + 'ABCDEFGH', 252 + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQR\nSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456w==', 253 + ])); 254 + 255 + for (const t of tests) 256 + t.checkAll(); 257 + 258 + console.log(stats.run + ' tested, ' + stats.error + ' errors.'); 259 + process.exit(stats.error ? 1 : 0);
+1 -1
testDefs.js
··· 11 try { 12 try { // try PEM first 13 content = Base64.unarmor(content); 14 - } catch (e) { // try DER/BER then 15 } 16 let result = ASN1.decode(content); 17 content = null;
··· 11 try { 12 try { // try PEM first 13 content = Base64.unarmor(content); 14 + } catch (ignore) { // try DER/BER then 15 } 16 let result = ASN1.decode(content); 17 content = null;
+7 -1
vite.config.js
··· 16 }; 17 }; 18 19 export default defineConfig({ 20 plugins: [ 21 preventSVGEmit(), ··· 25 if (removeNodes.includes(node.attribs.id)) 26 DomUtils.removeElement(node); 27 else if (node.name == 'link' && node.attribs.rel == 'icon') 28 - node.attribs.href = 'data:image/svg+xml;base64,' + btoa(fs.readFileSync('favicon.svg', 'ascii').replace(/^([^<]+|<[^s]|<s[^v]|<sv[^g])+/, '').trim()); 29 }, 30 }), 31 viteSingleFile(),
··· 16 }; 17 }; 18 19 + function massageSVG(str) { 20 + return str.replace(/["<>#]/g, (c) => { 21 + return '%' + c.charCodeAt(0).toString(16).toUpperCase().padStart(2, '0'); 22 + }); 23 + } 24 + 25 export default defineConfig({ 26 plugins: [ 27 preventSVGEmit(), ··· 31 if (removeNodes.includes(node.attribs.id)) 32 DomUtils.removeElement(node); 33 else if (node.name == 'link' && node.attribs.rel == 'icon') 34 + node.attribs.href = 'data:image/svg+xml,' + massageSVG(fs.readFileSync('favicon.svg', 'ascii').replace(/^([^<]+|<[^s]|<s[^v]|<sv[^g])+/, '').trim()); 35 }, 36 }), 37 viteSingleFile(),