JavaScript generic ASN.1 parser (mirror)

Compare changes

Choose any two refs to compare.

+3155 -395
+4 -2
.github/workflows/node.js.yml
··· 15 15 node-version: [ 12.20.0, latest ] 16 16 17 17 steps: 18 - - uses: actions/checkout@v3 18 + - uses: actions/checkout@v4 19 19 - name: Use Node.js ${{ matrix.node-version }} 20 - uses: actions/setup-node@v3 20 + uses: actions/setup-node@v4 21 21 with: 22 22 node-version: ${{ matrix.node-version }} 23 23 - run: npm test all 24 + - run: npm install 25 + if: matrix.node-version == 'latest' 24 26 - run: npm run lint 25 27 if: matrix.node-version == 'latest'
+2
.gitignore
··· 2 2 .DS_Store/ 3 3 .vscode/ 4 4 node_modules/ 5 + dist/ 5 6 package-lock.json 6 7 pnpm-lock.yaml 7 8 # Artifacts from release.sh 9 + index-local.html 8 10 sha256sums.asc 9 11 asn1js.zip 10 12 # Artifacts from mirror_to_github.sh
+2
.mtn-ignore
··· 1 1 [.]DS_Store$ 2 2 [.]vscode$ 3 3 node_modules$ 4 + dist$ 4 5 package-lock[.]json 5 6 pnpm-lock[.]yaml 6 7 # Artifacts from release.sh 8 + index-local.html 7 9 sha256sums[.]asc 8 10 asn1js[.]zip 9 11 # Artifacts from mirror_to_github.sh
+75
.vscode/launch.json
··· 1 + { 2 + // Use IntelliSense to learn about possible attributes. 3 + // Hover to view descriptions of existing attributes. 4 + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 + "version": "0.2.0", 6 + "configurations": [ 7 + { 8 + "type": "node", 9 + "request": "launch", 10 + "name": "dumpASN1", 11 + "skipFiles": [ 12 + "<node_internals>/**" 13 + ], 14 + "program": "${workspaceFolder}/dumpASN1.js", 15 + "args": [ 16 + "examples/ed25519.cer" 17 + ] 18 + }, 19 + { 20 + "type": "node", 21 + "request": "launch", 22 + "name": "parseRFC", 23 + "skipFiles": [ 24 + "<node_internals>/**" 25 + ], 26 + "program": "${workspaceFolder}/parseRFC.js", 27 + "args": [ 28 + "rfc/rfc4511.txt", 29 + "rfcdef.json" 30 + ] 31 + }, 32 + { 33 + "type": "node", 34 + "request": "launch", 35 + "name": "dumpASN1 cert", 36 + "skipFiles": [ 37 + "<node_internals>/**" 38 + ], 39 + "program": "${workspaceFolder}/dumpASN1.js", 40 + "args": [ 41 + "data:base64,MIG9AgEBMA0GCSqGSIb3DQEBCwUAMEExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxUUjM0IFNhbXBsZXMxGzAZBgNVBAMTElRSMzQgU2FtcGxlIENBIEtESBcNMTAxMTAyMTczMzMwWhcNMTAxMjAyMTczMzMwWjBIMBYCBTQAAAAIFw0xMDExMDIxNzI4MTNaMBYCBTQAAAAKFw0xMDExMDIxNzMxNDZaMBYCBTQAAAALFw0xMDExMDIxNzMzMjVa", 42 + "1.3.6.1.5.5.7.0.18", 43 + "TBSCertList" 44 + ] 45 + }, 46 + { 47 + "type": "node", 48 + "request": "launch", 49 + "name": "dumpASN1 CMS", 50 + "skipFiles": [ 51 + "<node_internals>/**" 52 + ], 53 + "program": "${workspaceFolder}/dumpASN1.js", 54 + "args": [ 55 + "examples/cms-password.p7m", 56 + "1.2.840.113549.1.9.16.0.14", 57 + "ContentInfo" 58 + ] 59 + }, 60 + { 61 + "type": "node", 62 + "request": "launch", 63 + "name": "dumpASN1 LDAP", 64 + "skipFiles": [ 65 + "<node_internals>/**" 66 + ], 67 + "program": "${workspaceFolder}/dumpASN1.js", 68 + "args": [ 69 + "data:base64,MDMCAQFjLgQACgEACgEAAgEAAgEAAQEAoA+jDQQFTnRWZXIEBAEAAAAwCgQITmV0bG9nb24===", 70 + "1.3.6.1.1.18", 71 + "LDAPMessage" 72 + ] 73 + } 74 + ] 75 + }
+9
.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 -1
LICENSE
··· 1 1 ISC License 2 2 3 - Copyright (c) 2008-2024 Lapo Luchini <lapo@lapo.it> 3 + Copyright (c) 2008-2025 Lapo Luchini <lapo@lapo.it> 4 4 5 5 Permission to use, copy, modify, and/or distribute this software for any 6 6 purpose with or without fee is hereby granted, provided that the above
+51 -22
README.md
··· 3 3 4 4 asn1js is a JavaScript generic ASN.1 parser/decoder that can decode any valid ASN.1 DER or BER structures. 5 5 6 - An example page that can decode Base64-encoded (raw base64, PEM armoring and `begin-base64` are recognized) or Hex-encoded (or local files with some browsers) is included and can be used both [online on the official website](https://lapo.it/asn1js/) or [offline (ZIP file)](https://lapo.it/asn1js/asn1js.zip). 6 + An example page that can decode Base64-encoded (raw base64, PEM armoring and `begin-base64` are recognized) or Hex-encoded (or local files with some browsers) is included and can be used both [online on the official website](https://asn1js.eu/) or [offline (ZIP file)](https://lapo.it/asn1js/asn1js.zip) by opening `index-local.html`. 7 7 8 - Usage with `npm` / `yarn` 9 - ------------------------- 8 + Usage with `nodejs` 9 + ------------------- 10 10 11 11 This package can be installed with either npm or yarn via the following commands: 12 12 13 13 ```sh 14 14 npm install @lapo/asn1js 15 - # or with yarn 15 + # or other tools 16 + pnpm install @lapo/asn1js 16 17 yarn add @lapo/asn1js 17 18 ``` 18 19 19 - Assuming a standard javascript bundler is setup you can import it like so: 20 + You can import the classes like this: 20 21 21 22 ```js 22 - const ASN1 = require('@lapo/asn1js'); 23 - // or with ES modules 24 - import ASN1 from '@lapo/asn1js'; 23 + import { ASN1 } from '@lapo/asn1js'; 25 24 ``` 26 25 27 26 A submodule of this package can also be imported: 28 27 29 28 ```js 30 - const Hex = require('@lapo/asn1js/hex'); 31 - // or with ES modules 32 - import Hex from '@lapo/asn1js/hex'; 29 + import { Hex } from '@lapo/asn1js/hex.js'; 30 + ``` 31 + 32 + If your code is still not using ES6 Modules (and is using CommonJS) you can `require` it normally [since NodeJS 22](https://joyeecheung.github.io/blog/2024/03/18/require-esm-in-node-js/) (with parameter `--experimental-require-module`): 33 + 34 + ```js 35 + const 36 + { ASN1 } = require('@lapo/asn1js'), 37 + { Hex } = require('@lapo/asn1js/hex.js'); 38 + console.log(ASN1.decode(Hex.decode('06032B6570')).content()); 39 + ``` 40 + 41 + On older NodeJS you instead need to use async `import`: 42 + 43 + ```js 44 + async function main() { 45 + const 46 + { ASN1 } = await import('@lapo/asn1js'), 47 + { Hex } = await import('@lapo/asn1js/hex.js'); 48 + console.log(ASN1.decode(Hex.decode('06032B6570')).content()); 49 + } 50 + main(); 33 51 ``` 34 52 35 - Usage with RequireJS 53 + Usage on the web 36 54 -------------------- 37 55 38 - Can be [tested on JSFiddle](https://jsfiddle.net/lapo/tmdq35ug/). 56 + Can be [tested on JSFiddle](https://jsfiddle.net/lapo/y6t2wo7q/). 39 57 40 58 ```html 41 - <script type="text/javascript" src="https://unpkg.com/requirejs/require.js"></script> 42 59 <script> 43 - require([ 44 - 'https://unpkg.com/@lapo/asn1js/asn1.js', 45 - 'https://unpkg.com/@lapo/asn1js/hex.js' 46 - ], function(ASN1, Hex) { 47 - document.body.innerText = ASN1.decode(Hex.decode('06032B6570')).content(); 48 - }); 60 + import { ASN1 } from 'https://unpkg.com/@lapo/asn1js@2.0.0/asn1.js'; 61 + import { Hex } from 'https://unpkg.com/@lapo/asn1js@2.0.0/hex.js'; 62 + 63 + document.body.innerText = ASN1.decode(Hex.decode('06032B6570')).content(); 49 64 </script> 50 65 ``` 51 66 67 + Local usage 68 + -------------------- 69 + 70 + Since unfortunately ESM modules are not working on `file:` protocol due to [CORS issues](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules#other_differences_between_modules_and_standard_scripts), there is a bundled [single-file version working locally](https://asn1js.eu/index-local.html). It doesn't work online (due to [CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) restrictions about inline content) but can be saved locally and opened in a browser. 71 + 72 + Usage from CLI 73 + -------------------- 74 + 75 + You can dump an ASN.1 structure from the command line using the following command (no need to even install it): 76 + 77 + ```sh 78 + npx @lapo/asn1js ed25519.cer 79 + ``` 80 + 52 81 ISC license 53 82 ----------- 54 83 55 - ASN.1 JavaScript decoder Copyright (c) 2008-2024 Lapo Luchini <lapo@lapo.it> 84 + ASN.1 JavaScript decoder Copyright (c) 2008-2025 Lapo Luchini <lapo@lapo.it> 56 85 57 86 Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. 58 87 ··· 66 95 - extended tag support added by [Pรฉter Budai](https://www.peterbudai.eu/) 67 96 - patches by [Gergely Nagy](https://github.com/ngg) 68 97 - Relative OID support added by [Mistial Developer](https://github.com/mistial-dev) 69 - - dark mode support added by [Oliver Burgmaier](https://github.com/olibu/) 98 + - dark mode and other UI improvements by [Oliver Burgmaier](https://github.com/olibu/) 70 99 - patches by [Nicolai Sรธborg](https://github.com/NicolaiSoeborg) 71 100 72 101 links
+89 -39
asn1.js
··· 1 1 // ASN.1 JavaScript decoder 2 - // Copyright (c) 2008-2024 Lapo Luchini <lapo@lapo.it> 2 + // Copyright (c) 2008 Lapo Luchini <lapo@lapo.it> 3 3 4 4 // Permission to use, copy, modify, and/or distribute this software for any 5 5 // purpose with or without fee is hereby granted, provided that the above 6 6 // copyright notice and this permission notice appear in all copies. 7 - // 7 + // 8 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ··· 21 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 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 23 hexDigits = '0123456789ABCDEF', 24 - b64Safe = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', 24 + b64Std = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', 25 + b64URL = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', 25 26 tableT61 = [ 26 27 ['', ''], 27 28 ['AEIOUaeiou', 'ร€รˆรŒร’ร™ร รจรฌรฒรน'], // Grave ··· 38 39 ['', ''], 39 40 ['OUou', 'ลลฐล‘ลฑ'], // Double Acute 40 41 ['AEIUaeiu', 'ฤ„ฤ˜ฤฎลฒฤ…ฤ™ฤฏลณ'], // Ogonek 41 - ['CDELNRSTZcdelnrstz', 'ฤŒฤŽฤšฤฝล‡ล˜ล ลคลฝฤฤฤ›ฤพลˆล™ลกลฅลพ'] // Caron 42 + ['CDELNRSTZcdelnrstz', 'ฤŒฤŽฤšฤฝล‡ล˜ล ลคลฝฤฤฤ›ฤพลˆล™ลกลฅลพ'], // Caron 42 43 ]; 43 44 44 45 function stringCut(str, len) { ··· 56 57 } 57 58 } 58 59 59 - class Stream { 60 + /** Class to manage a stream of bytes, with a zero-copy approach. 61 + * It uses an existing array or binary string and advances a position index. */ 62 + export class Stream { 60 63 64 + /** 65 + * @param {Stream|array|string} enc data (will not be copied) 66 + * @param {?number} pos starting position (mandatory when `end` is not a Stream) 67 + */ 61 68 constructor(enc, pos) { 62 69 if (enc instanceof Stream) { 63 70 this.enc = enc.enc; 64 71 this.pos = enc.pos; 65 72 } else { 66 - // enc should be an array or a binary string 67 73 this.enc = enc; 68 74 this.pos = pos; 69 75 } 76 + if (typeof this.pos != 'number') 77 + throw new Error('"pos" must be a numeric value'); 78 + if (typeof this.enc == 'string') 79 + this.getRaw = pos => this.enc.charCodeAt(pos); 80 + else if (typeof this.enc[0] == 'number') 81 + this.getRaw = pos => this.enc[pos]; 82 + else 83 + throw new Error('"enc" must be a numeric array or a string'); 70 84 } 85 + /** Get the byte at current position (and increment it) or at a specified position (and avoid moving current position). 86 + * @param {?number} pos read position if specified, else current position (and increment it) */ 71 87 get(pos) { 72 88 if (pos === undefined) 73 89 pos = this.pos++; 74 90 if (pos >= this.enc.length) 75 - throw 'Requesting byte offset ' + pos + ' on a stream of length ' + this.enc.length; 76 - return (typeof this.enc == 'string') ? this.enc.charCodeAt(pos) : this.enc[pos]; 91 + throw new Error('Requesting byte offset ' + pos + ' on a stream of length ' + this.enc.length); 92 + return this.getRaw(pos); 77 93 } 78 - hexByte(b) { 94 + /** Convert a single byte to an hexadcimal string (of length 2). 95 + * @param {number} b */ 96 + static hexByte(b) { 79 97 return hexDigits.charAt((b >> 4) & 0xF) + hexDigits.charAt(b & 0xF); 80 98 } 81 - hexDump(start, end, raw) { 99 + /** Hexadecimal dump of a specified region of the stream. 100 + * @param {number} start starting position (included) 101 + * @param {number} end ending position (excluded) 102 + * @param {string} type 'raw', 'byte' or 'dump' (default) */ 103 + hexDump(start, end, type = 'dump') { 82 104 let s = ''; 83 105 for (let i = start; i < end; ++i) { 84 - s += this.hexByte(this.get(i)); 85 - if (raw !== true) 106 + if (type == 'byte' && i > start) 107 + s += ' '; 108 + s += Stream.hexByte(this.get(i)); 109 + if (type == 'dump') 86 110 switch (i & 0xF) { 87 111 case 0x7: s += ' '; break; 88 112 case 0xF: s += '\n'; break; ··· 91 115 } 92 116 return s; 93 117 } 94 - b64Dump(start, end) { 118 + /** Base64url dump of a specified region of the stream (according to RFC 4648 section 5). 119 + * @param {number} start starting position (included) 120 + * @param {number} end ending position (excluded) 121 + * @param {string} type 'url' (default, section 5 without padding) or 'std' (section 4 with padding) */ 122 + b64Dump(start, end, type = 'url') { 123 + const b64 = type === 'url' ? b64URL : b64Std; 95 124 let extra = (end - start) % 3, 96 125 s = '', 97 126 i, c; 98 127 for (i = start; i + 2 < end; i += 3) { 99 128 c = this.get(i) << 16 | this.get(i + 1) << 8 | this.get(i + 2); 100 - s += b64Safe.charAt(c >> 18 & 0x3F); 101 - s += b64Safe.charAt(c >> 12 & 0x3F); 102 - s += b64Safe.charAt(c >> 6 & 0x3F); 103 - s += b64Safe.charAt(c & 0x3F); 129 + s += b64.charAt(c >> 18 & 0x3F); 130 + s += b64.charAt(c >> 12 & 0x3F); 131 + s += b64.charAt(c >> 6 & 0x3F); 132 + s += b64.charAt(c & 0x3F); 104 133 } 105 134 if (extra > 0) { 106 135 c = this.get(i) << 16; 107 136 if (extra > 1) c |= this.get(i + 1) << 8; 108 - s += b64Safe.charAt(c >> 18 & 0x3F); 109 - s += b64Safe.charAt(c >> 12 & 0x3F); 110 - if (extra == 2) s += b64Safe.charAt(c >> 6 & 0x3F); 137 + s += b64.charAt(c >> 18 & 0x3F); 138 + s += b64.charAt(c >> 12 & 0x3F); 139 + if (extra == 2) s += b64.charAt(c >> 6 & 0x3F); 140 + if (b64 === b64Std) s += '==='.slice(0, 3 - extra); 111 141 } 112 142 return s; 113 143 } ··· 190 220 let s = this.parseStringISO(start, end).str, 191 221 m = (shortYear ? reTimeS : reTimeL).exec(s); 192 222 if (!m) 193 - return 'Unrecognized time: ' + s; 223 + throw new Error('Unrecognized time: ' + s); 194 224 if (shortYear) { 195 225 // to avoid querying the timer, use the fixed range [1970, 2069] 196 226 // it will conform with ITU X.400 [-10, +40] sliding window until 2030 ··· 245 275 parseBitString(start, end, maxLength) { 246 276 let unusedBits = this.get(start); 247 277 if (unusedBits > 7) 248 - throw 'Invalid BitString with unusedBits=' + unusedBits; 278 + throw new Error('Invalid BitString with unusedBits=' + unusedBits); 249 279 let lenBit = ((end - start - 1) << 3) - unusedBits, 250 280 s = ''; 251 281 for (let i = start + 1; i < end; ++i) { ··· 273 303 end = start + maxLength; 274 304 s = ''; 275 305 for (let i = start; i < end; ++i) 276 - s += this.hexByte(this.get(i)); 306 + s += Stream.hexByte(this.get(i)); 277 307 if (len > maxLength) 278 308 s += ellipsis; 279 309 return { size: len, str: s }; ··· 368 398 369 399 export class ASN1 { 370 400 constructor(stream, header, length, tag, tagLen, sub) { 371 - if (!(tag instanceof ASN1Tag)) throw 'Invalid tag value.'; 401 + if (!(tag instanceof ASN1Tag)) throw new Error('Invalid tag value.'); 372 402 this.stream = stream; 373 403 this.header = header; 374 404 this.length = length; ··· 485 515 } 486 516 toPrettyString(indent) { 487 517 if (indent === undefined) indent = ''; 488 - let s = indent + this.typeName() + ' @' + this.stream.pos; 518 + let s = indent; 519 + if (this.def) { 520 + if (this.def.id) 521 + s += this.def.id + ' '; 522 + if (this.def.name && this.def.name != this.typeName().replace(/_/g, ' ')) 523 + s+= this.def.name + ' '; 524 + if (this.def.mismatch) 525 + s += '[?] '; 526 + } 527 + s += this.typeName() + ' @' + this.stream.pos; 489 528 if (this.length >= 0) 490 529 s += '+'; 491 530 s += this.length; ··· 517 556 posLen() { 518 557 return this.stream.pos + this.tagLen; 519 558 } 520 - toHexString() { 521 - return this.stream.hexDump(this.posStart(), this.posEnd(), true); 559 + /** Hexadecimal dump of the node. 560 + * @param type 'raw', 'byte' or 'dump' */ 561 + toHexString(type = 'raw') { 562 + return this.stream.hexDump(this.posStart(), this.posEnd(), type); 522 563 } 523 - toB64String() { 524 - return this.stream.b64Dump(this.posStart(), this.posEnd()); 564 + /** Base64url dump of the node (according to RFC 4648 section 5). 565 + * @param {string} type 'url' (default, section 5 without padding) or 'std' (section 4 with padding) 566 + */ 567 + toB64String(type = 'url') { 568 + return this.stream.b64Dump(this.posStart(), this.posEnd(), type); 525 569 } 526 570 static decodeLength(stream) { 527 571 let buf = stream.get(), ··· 531 575 if (len === 0) // long form with length 0 is a special case 532 576 return null; // undefined length 533 577 if (len > 6) // no reason to use Int10, as it would be a huge buffer anyways 534 - throw 'Length over 48 bits not supported at position ' + (stream.pos - 1); 578 + throw new Error('Length over 48 bits not supported at position ' + (stream.pos - 1)); 535 579 buf = 0; 536 580 for (let i = 0; i < len; ++i) 537 581 buf = (buf * 256) + stream.get(); ··· 539 583 } 540 584 static decode(stream, offset, type = ASN1) { 541 585 if (!(type == ASN1 || type.prototype instanceof ASN1)) 542 - throw 'Must pass a class that extends ASN1'; 586 + throw new Error('Must pass a class that extends ASN1'); 543 587 if (!(stream instanceof Stream)) 544 588 stream = new Stream(stream, offset || 0); 545 589 let streamStart = new Stream(stream), ··· 555 599 // definite length 556 600 let end = start + len; 557 601 if (end > stream.enc.length) 558 - throw 'Container at offset ' + start + ' has a length of ' + len + ', which is past the end of the stream'; 602 + throw new Error('Container at offset ' + start + ' has a length of ' + len + ', which is past the end of the stream'); 559 603 while (stream.pos < end) 560 604 sub[sub.length] = type.decode(stream); 561 605 if (stream.pos != end) 562 - throw 'Content size is not correct for container at offset ' + start; 606 + throw new Error('Content size is not correct for container at offset ' + start); 563 607 } else { 564 608 // undefined length 565 609 try { ··· 571 615 } 572 616 len = start - stream.pos; // undefined lengths are represented as negative values 573 617 } catch (e) { 574 - throw 'Exception while decoding undefined length content at offset ' + start + ': ' + e; 618 + throw new Error('Exception while decoding undefined length content at offset ' + start + ': ' + e); 575 619 } 576 620 } 577 621 }; ··· 583 627 try { 584 628 if (tag.tagNumber == 0x03) 585 629 if (stream.get() != 0) 586 - throw 'BIT STRINGs with unused bits cannot encapsulate.'; 630 + throw new Error('BIT STRINGs with unused bits cannot encapsulate.'); 587 631 getSub(); 588 - for (let i = 0; i < sub.length; ++i) 589 - if (sub[i].tag.isEOC()) 590 - throw 'EOC is not supposed to be actual content.'; 632 + for (let s of sub) { 633 + if (s.tag.isEOC()) 634 + throw new Error('EOC is not supposed to be actual content.'); 635 + try { 636 + s.content(); 637 + } catch (e) { 638 + throw new Error('Unable to parse content: ' + e); 639 + } 640 + } 591 641 } catch (e) { 592 642 // but silently ignore when they don't 593 643 sub = null; ··· 596 646 } 597 647 if (sub === null) { 598 648 if (len === null) 599 - throw "We can't skip over an invalid tag with undefined length at offset " + start; 649 + throw new Error("We can't skip over an invalid tag with undefined length at offset " + start); 600 650 stream.pos = start + Math.abs(len); 601 651 } 602 652 return new type(streamStart, header, len, tag, tagLen, sub);
+8 -7
base64.js
··· 1 1 // Base64 JavaScript decoder 2 - // Copyright (c) 2008-2024 Lapo Luchini <lapo@lapo.it> 2 + // Copyright (c) 2008 Lapo Luchini <lapo@lapo.it> 3 3 4 4 // Permission to use, copy, modify, and/or distribute this software for any 5 5 // purpose with or without fee is hereby granted, provided that the above 6 6 // copyright notice and this permission notice appear in all copies. 7 - // 7 + // 8 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ··· 31 31 decoder[b64.charCodeAt(i)] = i; 32 32 for (i = 0; i < ignore.length; ++i) 33 33 decoder[ignore.charCodeAt(i)] = -1; 34 - // RFC 3548 URL & file safe encoding 34 + // also support decoding Base64url (RFC 4648 section 5) 35 35 decoder['-'.charCodeAt(0)] = decoder['+'.charCodeAt(0)]; 36 36 decoder['_'.charCodeAt(0)] = decoder['/'.charCodeAt(0)]; 37 37 } ··· 75 75 76 76 static pretty(str) { 77 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 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) 81 82 str = str.replace(/-/g, '+').replace(/_/g, '/'); 82 83 // 80 column width 83 - return str.replace(/(.{80})/g, '$1\n'); 84 + return str.replace(/.{80}/g, '$&\n'); 84 85 } 85 86 86 87 static unarmor(a) {
+1 -1
check.sh
··· 1 1 #!/bin/sh 2 - type gsha256sum >/dev/null && SHA256=gsha256sum || SHA256=sha256sum 2 + type gsha256sum >/dev/null 2>/dev/null && SHA256=gsha256sum || SHA256=sha256sum 3 3 gpg --verify -o - sha256sums.asc | $SHA256 -c --quiet
+53
context.js
··· 1 + const 2 + id = (elem) => document.getElementById(elem), 3 + contextMenu = id('contextmenu'), 4 + btnCopyHex = id('btnCopyHex'), 5 + btnCopyB64 = id('btnCopyB64'), 6 + btnCopyTree = id('btnCopyTree'), 7 + btnCopyValue = id('btnCopyValue'); 8 + 9 + export function bindContextMenu(node) { 10 + const type = node.asn1.typeName(); 11 + const valueEnabled = type != 'SET' && type != 'SEQUENCE'; 12 + node.onclick = function (event) { 13 + // do not show the menu in case of clicking the icon 14 + if (event.srcElement.nodeName != 'SPAN') return; 15 + contextMenu.style.left = event.pageX + 'px'; 16 + contextMenu.style.top = event.pageY + 'px'; 17 + contextMenu.style.visibility = 'visible'; 18 + contextMenu.node = this; 19 + btnCopyValue.style.display = valueEnabled ? 'block' : 'none'; 20 + event.preventDefault(); 21 + event.stopPropagation(); 22 + }; 23 + } 24 + 25 + function close(event) { 26 + contextMenu.style.visibility = 'hidden'; 27 + event.stopPropagation(); 28 + } 29 + 30 + contextMenu.onmouseleave = close; 31 + 32 + btnCopyHex.onclick = function (event) { 33 + navigator.clipboard.writeText(contextMenu.node.asn1.toHexString('byte')); 34 + close(event); 35 + }; 36 + 37 + btnCopyB64.onclick = function (event) { 38 + event.stopPropagation(); 39 + navigator.clipboard.writeText(contextMenu.node.asn1.toB64String()); 40 + close(event); 41 + }; 42 + 43 + btnCopyTree.onclick = function (event) { 44 + event.stopPropagation(); 45 + navigator.clipboard.writeText(contextMenu.node.asn1.toPrettyString()); 46 + close(event); 47 + }; 48 + 49 + btnCopyValue.onclick = function (event) { 50 + event.stopPropagation(); 51 + navigator.clipboard.writeText(contextMenu.node.asn1.content()); 52 + close(event); 53 + };
+26 -12
defs.js
··· 1 1 // ASN.1 RFC definitions matcher 2 - // Copyright (c) 2023-2024 Lapo Luchini <lapo@lapo.it> 2 + // Copyright (c) 2023 Lapo Luchini <lapo@lapo.it> 3 3 4 4 // Permission to use, copy, modify, and/or distribute this software for any 5 5 // purpose with or without fee is hereby granted, provided that the above 6 6 // copyright notice and this permission notice appear in all copies. 7 - // 7 + // 8 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ··· 23 23 try { 24 24 // hope current OIDs contain the type name (will need to parse from RFC itself) 25 25 def = Defs.searchType(firstUpper(stats.defs[def.definedBy][1])); 26 - } catch (e) {} 26 + } catch (e) { /*ignore*/ } 27 27 while (def?.type == 'defined' || def?.type?.type == 'defined') { 28 28 const name = def?.type?.type ? def.type.name : def.name; 29 29 def = Object.assign({}, def); 30 30 def.type = Defs.searchType(name).type; 31 31 } 32 - if (def?.type?.name == 'CHOICE') { 33 - for (let c of def.type.content) { 34 - c = translate(c); 32 + if (def?.name == 'CHOICE' || def?.type?.name == 'CHOICE') { 33 + for (let c of def.content ?? def.type.content) { 34 + if (tn != c.type.name && tn != c.name) 35 + c = translate(c); 35 36 if (tn == c.type.name || tn == c.name) { 36 37 def = Object.assign({}, def); 38 + if (c.id) def.id = c.id; 37 39 def.type = c.type.name ? c.type : c; 38 40 break; 39 41 } ··· 62 64 // return r.types[name]; 63 65 return Defs.moduleAndType(mod, name); 64 66 } 65 - throw 'Type not found: ' + name; 67 + throw new Error('Type not found: ' + name); 66 68 } 67 69 68 70 static match(value, def, stats = { total: 0, recognized: 0, defs: {} }) { ··· 89 91 type = def.content[0]; 90 92 else { 91 93 let tn = subval.typeName().replaceAll('_', ' '); 92 - do { 94 + for (;;) { 93 95 type = def.content[j++]; 94 - // type = translate(type, tn); 96 + if (!type || typeof type != 'object') break; 95 97 if (type?.type?.type) 96 98 type = type.type; 97 - } while (type && typeof type == 'object' && ('optional' in type || 'default' in type) && type.name != 'ANY' && type.name != tn); 99 + if (type.type == 'defined') { 100 + let t2 = translate(type, tn); 101 + if (t2.type.name == tn) break; // exact match 102 + if (t2.type.name == 'ANY') break; // good enough 103 + } 104 + if (type.name == tn) break; // exact match 105 + if (type.name == 'ANY') break; // good enough 106 + if (!('optional' in type || 'default' in type)) break; 107 + } 98 108 if (type?.type == 'builtin' || type?.type == 'defined') { 99 109 let v = subval.content(); 100 110 if (typeof v == 'string') ··· 103 113 } else if (type?.definedBy && stats.defs?.[type.definedBy]?.[1]) { // hope current OIDs contain the type name (will need to parse from RFC itself) 104 114 try { 105 115 type = Defs.searchType(firstUpper(stats.defs[type.definedBy][1])); 106 - } catch (e) {} 116 + } catch (e) { /*ignore*/ } 107 117 } 108 118 } 109 119 } ··· 118 128 Defs.RFC = rfcdef; 119 129 120 130 Defs.commonTypes = [ 121 - [ 'X.509 certificate', '1.3.6.1.5.5.7.0.18', 'Certificate' ], 131 + [ 'X.509 certificate', '1.3.6.1.5.5.7.0.18', 'Certificate' ], 132 + [ 'X.509 public key info', '1.3.6.1.5.5.7.0.18', 'SubjectPublicKeyInfo' ], 133 + [ 'X.509 certificate revocation list', '1.3.6.1.5.5.7.0.18', 'CertificateList' ], 122 134 [ 'CMS / PKCS#7 envelope', '1.2.840.113549.1.9.16.0.14', 'ContentInfo' ], 135 + [ 'PKCS#1 RSA private key', '1.2.840.113549.1.1.0.1', 'RSAPrivateKey' ], 123 136 [ 'PKCS#8 encrypted private key', '1.2.840.113549.1.8.1.1', 'EncryptedPrivateKeyInfo' ], 124 137 [ 'PKCS#8 private key', '1.2.840.113549.1.8.1.1', 'PrivateKeyInfo' ], 125 138 [ 'PKCS#10 certification request', '1.2.840.113549.1.10.1.1', 'CertificationRequest' ], 126 139 [ 'CMP PKI Message', '1.3.6.1.5.5.7.0.16', 'PKIMessage' ], 140 + [ 'LDAP Message', '1.3.6.1.1.18', 'LDAPMessage' ], 127 141 ].map(arr => ({ description: arr[0], ...Defs.moduleAndType(rfcdef[arr[1]], arr[2]) }));
+42 -22
dom.js
··· 1 1 // ASN.1 JavaScript decoder 2 - // Copyright (c) 2008-2024 Lapo Luchini <lapo@lapo.it> 2 + // Copyright (c) 2008 Lapo Luchini <lapo@lapo.it> 3 3 4 4 // Permission to use, copy, modify, and/or distribute this software for any 5 5 // purpose with or without fee is hereby granted, provided that the above 6 6 // copyright notice and this permission notice appear in all copies. 7 - // 7 + // 8 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ··· 15 15 16 16 import { ASN1 } from './asn1.js'; 17 17 import { oids } from './oids.js'; 18 + import { bindContextMenu } from './context.js'; 18 19 19 20 const 20 21 lineLength = 80, ··· 23 24 ellipsis: '\u2026', 24 25 tag: function (tagName, className, text) { 25 26 let t = document.createElement(tagName); 26 - t.className = className; 27 + if (className) t.className = className; 27 28 if (text) t.innerText = text; 28 29 return t; 29 30 }, ··· 47 48 o += line; 48 49 } 49 50 return o; 50 - } 51 + }, 51 52 }; 52 53 53 54 export class ASN1DOM extends ASN1 { ··· 55 56 toDOM(spaces) { 56 57 spaces = spaces || ''; 57 58 let isOID = (typeof oids === 'object') && (this.tag.isUniversal() && (this.tag.tagNumber == 0x06) || (this.tag.tagNumber == 0x0D)); 58 - let node = DOM.tag('div', 'node'); 59 + let node = DOM.tag('li'); 59 60 node.asn1 = this; 60 - let head = DOM.tag('div', 'head'); 61 - head.appendChild(DOM.tag('span', 'spaces', spaces)); 61 + let head = DOM.tag('span', 'head'); 62 62 const typeName = this.typeName().replace(/_/g, ' '); 63 63 if (this.def) { 64 64 if (this.def.id) { ··· 75 75 } 76 76 } 77 77 head.appendChild(DOM.text(typeName)); 78 - let content = this.content(contentLength); 78 + let content; 79 + try { 80 + content = this.content(contentLength); 81 + } catch (e) { 82 + content = 'Cannot decode: ' + e; 83 + } 79 84 let oid; 80 85 if (content !== null) { 81 86 let preview = DOM.tag('span', 'preview'), ··· 105 110 content = content.replace(/</g, '&lt;'); 106 111 content = content.replace(/\n/g, '<br>'); 107 112 } 108 - node.appendChild(head); 109 - this.node = node; 113 + // add the li and details section for this node 114 + let contentNode; 115 + let childNode; 116 + if (this.sub !== null) { 117 + let details = DOM.tag('details'); 118 + details.setAttribute('open', ''); 119 + node.appendChild(details); 120 + let summary = DOM.tag('summary', 'node'); 121 + details.appendChild(summary); 122 + summary.appendChild(head); 123 + contentNode = summary; 124 + childNode = details; 125 + } else { 126 + contentNode = node; 127 + contentNode.classList.add('node'); 128 + contentNode.appendChild(head); 129 + } 130 + this.node = contentNode; 110 131 this.head = head; 111 132 let value = DOM.tag('div', 'value'); 112 133 let s = 'Offset: ' + this.stream.pos + '<br>'; ··· 129 150 } 130 151 } 131 152 value.innerHTML = s; 132 - node.appendChild(value); 133 - let sub = DOM.tag('div', 'sub'); 153 + contentNode.appendChild(value); 134 154 if (this.sub !== null) { 155 + let sub = DOM.tag('ul'); 156 + childNode.appendChild(sub); 135 157 spaces += '\xA0 '; 136 158 for (let i = 0, max = this.sub.length; i < max; ++i) 137 159 sub.appendChild(this.sub[i].toDOM(spaces)); 138 160 } 139 - node.appendChild(sub); 140 - head.onclick = function () { 141 - node.className = (node.className == 'node collapsed') ? 'node' : 'node collapsed'; 142 - }; 161 + bindContextMenu(node); 143 162 return node; 144 163 } 145 164 fakeHover(current) { 146 - this.node.className += ' hover'; 165 + this.node.classList.add('hover'); 147 166 if (current) 148 - this.head.className += ' hover'; 167 + this.head.classList.add('hover'); 149 168 } 150 169 fakeOut(current) { 151 - let re = / ?hover/; 152 - this.node.className = this.node.className.replace(re, ''); 170 + this.node.classList.remove('hover'); 153 171 if (current) 154 - this.head.className = this.head.className.replace(re, ''); 172 + this.head.classList.remove('hover'); 155 173 } 156 174 toHexDOM_sub(node, className, stream, start, end) { 157 175 if (start >= end) ··· 166 184 this.head.onmouseover = function () { this.hexNode.className = 'hexCurrent'; }; 167 185 this.head.onmouseout = function () { this.hexNode.className = 'hex'; }; 168 186 node.asn1 = this; 169 - node.onmouseover = function () { 187 + node.onmouseover = function (event) { 170 188 let current = !root.selected; 171 189 if (current) { 172 190 root.selected = this.asn1; 173 191 this.className = 'hexCurrent'; 174 192 } 175 193 this.asn1.fakeHover(current); 194 + event.stopPropagation(); 176 195 }; 177 196 node.onmouseout = function () { 178 197 let current = (root.selected == this.asn1); ··· 182 201 this.className = 'hex'; 183 202 } 184 203 }; 204 + bindContextMenu(node); 185 205 if (root == node) { 186 206 let lineStart = this.posStart() & 0xF; 187 207 if (lineStart != 0) {
+31 -18
dumpASN1.js
··· 1 1 #!/usr/bin/env node 2 2 3 + // usage: 4 + // ./dumpASN1.js filename 5 + // ./dumpASN1.js data:base64,MDMCAQFjLgQACgEACgEAAgEAAgEAAQEAoA+jDQQFTnRWZXIEBAEAAAAwCgQITmV0bG9nb24=== 6 + 3 7 import * as fs from 'node:fs'; 4 8 import { Base64 } from './base64.js'; 5 9 import { ASN1 } from './asn1.js'; ··· 8 12 const 9 13 colYellow = '\x1b[33m', 10 14 colBlue = '\x1b[34m', 11 - colReset = '\x1b[0m'; 15 + colReset = '\x1b[0m', 16 + reDataURI = /^data:(?:[a-z-]+[/][a-z.+-]+;)?base64,([A-Za-z0-9+/=\s]+)$/; 12 17 13 18 function print(value, indent) { 14 19 if (indent === undefined) indent = ''; ··· 40 45 return s; 41 46 } 42 47 43 - let content = fs.readFileSync(process.argv[2]); 48 + const filename = process.argv[2]; 49 + const match = reDataURI.exec(filename); 50 + let content = match 51 + ? Buffer.from(match[1]) 52 + : fs.readFileSync(filename); 44 53 try { // try PEM first 45 54 content = Base64.unarmor(content); 46 55 } catch (e) { // try DER/BER then ··· 48 57 let result = ASN1.decode(content); 49 58 content = null; 50 59 const t0 = performance.now(); 51 - const types = Defs.commonTypes 52 - .map(type => { 53 - const stats = Defs.match(result, type); 54 - return { type, match: stats.recognized / stats.total }; 55 - }) 56 - .sort((a, b) => b.match - a.match); 57 - const t1 = performance.now(); 58 - console.log('Parsed in ' + (t1 - t0).toFixed(2) + ' ms; possible types:'); 59 - for (const t of types) 60 - console.log((t.match * 100).toFixed(2).padStart(6) + '% ' + t.type.description); 61 - Defs.match(result, types[0].type); 62 - // const stats = Defs.match(result, types[0].type); 63 - // console.log('Stats:', stats); 64 - console.log('Parsed as:', result.def); 65 - // const type = searchType(process.argv[2]); 66 - // const stats = applyDef(result, type); 60 + if (process.argv.length == 5) { 61 + Defs.match(result, Defs.moduleAndType(Defs.RFC[process.argv[3]], process.argv[4])); 62 + } else { 63 + const types = Defs.commonTypes 64 + .map(type => { 65 + const stats = Defs.match(result, type); 66 + return { type, match: stats.recognized / stats.total }; 67 + }) 68 + .sort((a, b) => b.match - a.match); 69 + const t1 = performance.now(); 70 + console.log('Parsed in ' + (t1 - t0).toFixed(2) + ' ms; possible types:'); 71 + for (const t of types) 72 + console.log((t.match * 100).toFixed(2).padStart(6) + '% ' + t.type.description); 73 + Defs.match(result, types[0].type); 74 + // const stats = Defs.match(result, types[0].type); 75 + // console.log('Stats:', stats); 76 + console.log('Parsed as:', result.def); 77 + // const type = searchType(process.argv[2]); 78 + // const stats = applyDef(result, type); 79 + } 67 80 console.log(print(result)); 68 81 // console.log('Stats:', (stats.recognized * 100 / stats.total).toFixed(2) + '%'); 69 82 // // print(result, searchType(process.argv[2]), stats);
+9
examples/cms-password.p7m
··· 1 + This is a PKCS#7/CMS encrypted with passwod. 2 + $ echo content | openssl cms -encrypt -pwri_password test -aes256 -outform pem -out examples/cms-password.p7m 3 + -----BEGIN CMS----- 4 + MIHYBgkqhkiG9w0BBwOggcowgccCAQMxgYOjgYACAQCgGwYJKoZIhvcNAQUMMA4E 5 + CED/DSxXMtH6AgIIADAsBgsqhkiG9w0BCRADCTAdBglghkgBZQMEASoEEDIQbJMC 6 + Sfb3LpwHduj/meQEMKwrwq5M4V0stztm6OUTAsFY2zKDY20SApwSEeEcAh9TM42E 7 + 1palnHeqHTBpC8pIpjA8BgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBByt+scPrdM 8 + giR7WUOJyB3hgBDcD3UDMtZSep8X/3yy1/Yq 9 + -----END CMS-----
+12
examples/crl-rfc5280.b64
··· 1 + CRL example from RFC5280 as found here: 2 + https://csrc.nist.gov/projects/pki-testing/sample-certificates-and-crls 3 + 4 + begin-base64 644 crl-rfc5280.der 5 + MIIBYDCBygIBATANBgkqhkiG9w0BAQUFADBDMRMwEQYKCZImiZPyLGQBGRYDY29tMRcwFQYKCZIm 6 + iZPyLGQBGRYHZXhhbXBsZTETMBEGA1UEAxMKRXhhbXBsZSBDQRcNMDUwMjA1MTIwMDAwWhcNMDUw 7 + MjA2MTIwMDAwWjAiMCACARIXDTA0MTExOTE1NTcwM1owDDAKBgNVHRUEAwoBAaAvMC0wHwYDVR0j 8 + BBgwFoAUCGivhTPIOUp6+IKTjnBqSiCELDIwCgYDVR0UBAMCAQwwDQYJKoZIhvcNAQEFBQADgYEA 9 + ItwYffcIzsx10NBqm60Q9HYjtIFutW2+DvsVFGzIF20f7pAXom9g5L2qjFXejoRvkvifEBInr0rU 10 + L4XiNkR9qqNMJTgV/wD9Pn7uPSYS69jnK2LiK8NGgO94gtEVxtCccmrLznrtZ5mLbnCBfUNCdMGm 11 + r8FVF6IzTNYGmCuk/C4= 12 + ====
+8
examples/ldapmessage.b64
··· 1 + LDAPMessage example as found on ldap.com. 2 + 3 + Original link: 4 + https://ldap.com/ldapv3-wire-protocol-reference-ldap-message/ 5 + 6 + begin-base64 644 ldapmessage.der 7 + MDUCAQVKEWRjPWV4YW1wbGUsZGM9Y29toB0wGwQWMS4yLjg0MC4xMTM1NTYuMS40LjgwNQEB/w== 8 + ====
+18
examples/pkcs1.pem
··· 1 + PKCS#1 RSA key 2 + $ openssl genrsa -out examples/pkcs8-rsa.pem 1024 3 + $ openssl rsa -in examples/pkcs8-rsa.pem -out examples/pkcs1.pem -traditional 4 + -----BEGIN RSA PRIVATE KEY----- 5 + MIICXQIBAAKBgQCmy23ifN9pi5LO4MR3LUhU0v+LZmv78H+jd+R6kFcWZf1qW4yf 6 + KTDkryjjLlIhYqxmzXCqGyaIjj7uJoorWf7KfkxpOuJrh4swJ/WGhCn9i+voW/7T 7 + sOXfDp1yqrEhaQKwdPot1ZAB78TNsecwX/SODTEMCk95jvx1j5cDxPlskwIDAQAB 8 + AoGBAINn4bp+BsVwYMj768y4sDOjyBBbMNfcMbLn0el9rh7HW09fsPnzycFg/iV9 9 + aNdEle6oDAr4OPN8nbeiRVjCHijEnVdHCwAtkKODyuu1ghpZWD0VUC8AEskjX4Bs 10 + Ysl/HjyvvHIRj89gdDFoElgB4GzHKTzeZNJBM5qtUW57zBCBAkEA0A6N5l98MglL 11 + cypWKM7+3DXteWt86mKXYUVF33HY28Z+oUVlU0v8m8XxpoAjkicYnC1JOSSlvWRk 12 + EWlTMgHW5QJBAM06yIHMR6p3apgpwOUp49DbtaQ8NmhCV4NBoFHa+vT2Fk8twOcq 13 + O9OzP4svhKbPNfB4HnxGbmd/+OVT3lySxhcCQHRPPpqD1K0wLwKxrzrfBPDcIOaY 14 + 5VsuRIw3KqmQPngWTiIf5lYbi5sVnFLFHZ2Nx58/XcjZKOJopdxp8f1ps9UCQQC3 15 + rOqSsF9bg3DVKllHQAxyepDAolsXSHjGMk/nspJz9mLVDl/dBAFzYLN4QFj6ae0e 16 + gILYOrjIzNHXfQ4/z+SVAkBPebkAzpGFgzVzu6VOGx0Vft/ow3/DKNJSDM58yASp 17 + ootY2TdibrrV/ellNLvuTiku6AEM/8jbHlRsmfxRe0xn 18 + -----END RSA PRIVATE KEY-----
+18
examples/pkcs8-rsa.pem
··· 1 + PKCS#8 RSA key 2 + $ openssl genrsa -out examples/pkcs8-rsa.pem 1024 3 + -----BEGIN PRIVATE KEY----- 4 + MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKbLbeJ832mLks7g 5 + xHctSFTS/4tma/vwf6N35HqQVxZl/WpbjJ8pMOSvKOMuUiFirGbNcKobJoiOPu4m 6 + iitZ/sp+TGk64muHizAn9YaEKf2L6+hb/tOw5d8OnXKqsSFpArB0+i3VkAHvxM2x 7 + 5zBf9I4NMQwKT3mO/HWPlwPE+WyTAgMBAAECgYEAg2fhun4GxXBgyPvrzLiwM6PI 8 + EFsw19wxsufR6X2uHsdbT1+w+fPJwWD+JX1o10SV7qgMCvg483ydt6JFWMIeKMSd 9 + V0cLAC2Qo4PK67WCGllYPRVQLwASySNfgGxiyX8ePK+8chGPz2B0MWgSWAHgbMcp 10 + PN5k0kEzmq1RbnvMEIECQQDQDo3mX3wyCUtzKlYozv7cNe15a3zqYpdhRUXfcdjb 11 + xn6hRWVTS/ybxfGmgCOSJxicLUk5JKW9ZGQRaVMyAdblAkEAzTrIgcxHqndqmCnA 12 + 5Snj0Nu1pDw2aEJXg0GgUdr69PYWTy3A5yo707M/iy+Eps818HgefEZuZ3/45VPe 13 + XJLGFwJAdE8+moPUrTAvArGvOt8E8Nwg5pjlWy5EjDcqqZA+eBZOIh/mVhuLmxWc 14 + UsUdnY3Hnz9dyNko4mil3Gnx/Wmz1QJBALes6pKwX1uDcNUqWUdADHJ6kMCiWxdI 15 + eMYyT+eyknP2YtUOX90EAXNgs3hAWPpp7R6Agtg6uMjM0dd9Dj/P5JUCQE95uQDO 16 + kYWDNXO7pU4bHRV+3+jDf8Mo0lIMznzIBKmii1jZN2JuutX96WU0u+5OKS7oAQz/ 17 + yNseVGyZ/FF7TGc= 18 + -----END PRIVATE KEY-----
+1 -2
favicon.svg
··· 1 - <?xml version="1.0" encoding="UTF-8"?> 2 - <svg width="192" height="192" version="1.1" viewBox="0 0 50.8 50.8" xmlns="http://www.w3.org/2000/svg"><rect width="50.8" height="50.8" stroke-width=".25275"/><g transform="translate(0 .23698)"><g transform="translate(0 -.30431)"><path transform="matrix(.26458 0 0 .26458 .72192 -3.1337)" d="m65.411 87.986h-31.354l-4.9479 14.167h-20.156l28.802-77.761h23.906l28.802 77.761h-20.156zm-26.354-14.427h21.302l-10.625-30.938zm125.83-46.719v16.458q-6.4063-2.8646-12.5-4.3229t-11.51-1.4583q-7.1875 0-10.625 1.9792t-3.4375 6.1459q0 3.125 2.2917 4.8958 2.3438 1.7188 8.4375 2.9688l8.5417 1.7188q12.969 2.6042 18.438 7.9167 5.4688 5.3125 5.4688 15.104 0 12.865-7.6563 19.167-7.6042 6.25-23.281 6.25-7.3958 0-14.844-1.4062-7.4479-1.4063-14.896-4.1667v-16.927q7.4479 3.9583 14.375 5.9896 6.9792 1.9792 13.438 1.9792 6.5625 0 10.052-2.1875t3.4896-6.25q0-3.6458-2.3958-5.625-2.3438-1.9792-9.4271-3.5417l-7.7604-1.7188q-11.667-2.5-17.083-7.9688-5.3646-5.4688-5.3646-14.74 0-11.615 7.5-17.865 7.5-6.25 21.563-6.25 6.4063 0 13.177 0.98959 6.7708 0.9375 14.01 2.8646z" fill="#58a6ff" aria-label="AS"/><g transform="matrix(.26458 0 0 .26458 2.807 20.959)" style="white-space:pre" aria-label="N1"><path d="m7.2136 24.392h22.396l28.281 53.334v-53.334h19.01v77.761h-22.396l-28.281-53.334v53.334h-19.01z" fill="#58a6ff"/><path d="m109.19 88.298h17.708v-50.261l-18.177 3.75v-13.646l18.073-3.75h19.063v63.906h17.708v13.854h-54.375z" fill="#fffe58"/></g></g></g></svg> 1 + <svg xmlns="http://www.w3.org/2000/svg" width="192" height="192" viewBox="0 0 50.8 50.8"><path d="M0 0h50.8v50.8H0z"/><path fill="#58a6ff" d="M18.028 20.078H9.733l-1.31 3.749H3.092l7.62-20.574h6.325l7.62 20.574h-5.332zm-6.972-3.817h5.636L13.88 8.076zm33.292-12.36v4.354q-1.695-.758-3.308-1.144t-3.045-.386q-1.902 0-2.811.524t-.91 1.626q0 .827.607 1.295.62.455 2.232.786l2.26.454q3.432.69 4.879 2.095t1.446 3.996q0 3.404-2.025 5.072-2.012 1.653-6.16 1.653-1.957 0-3.927-.372t-3.942-1.102v-4.479q1.971 1.047 3.804 1.585 1.846.523 3.555.523 1.737 0 2.66-.578t.923-1.654q0-.965-.634-1.488-.62-.524-2.494-.937l-2.053-.455q-3.087-.661-4.52-2.108-1.42-1.447-1.42-3.9 0-3.073 1.985-4.727 1.984-1.654 5.705-1.654 1.695 0 3.486.262 1.792.248 3.707.758z" aria-label="AS"/><g aria-label="N1" style="white-space:pre"><path fill="#58a6ff" d="M4.716 27.345h5.925l7.483 14.111v-14.11h5.03v20.573h-5.926L9.745 33.81v14.11h-5.03z"/><path fill="#fffe58" d="M31.696 44.254h4.686V30.955l-4.81.993v-3.61l4.782-.993h5.044v16.908h4.685v3.666H31.696z"/></g></svg>
+2 -2
hex.js
··· 1 1 // Hex JavaScript decoder 2 - // Copyright (c) 2008-2024 Lapo Luchini <lapo@lapo.it> 2 + // Copyright (c) 2008 Lapo Luchini <lapo@lapo.it> 3 3 4 4 // Permission to use, copy, modify, and/or distribute this software for any 5 5 // purpose with or without fee is hereby granted, provided that the above 6 6 // copyright notice and this permission notice appear in all copies. 7 - // 7 + // 8 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-42
index-dark.css
··· 1 - :root { 2 - --main-bg-color: #0d1116; 3 - --main-text-color: #f8f8f2; 4 - --headline-text-color: #8be9fd; 5 - --button-border-color: #505050; 6 - --button-bg-color: #303030; 7 - --button-bghover-color: #404040; 8 - --input-border-color: #505050; 9 - --input-bg-color: #0c0e11; 10 - --link-color: #58a6ff; 11 - --link-hover-color: #9b9bea; 12 - --header-bg-color: #161b22; 13 - --page-bg-color: #000000; 14 - --license-bg-color: #4b4a4a; 15 - --license-border-color: black; 16 - --sub-border-color: #383838; 17 - --preview-bg-color: #989797; 18 - --preview-border-color: #b5b3b3; 19 - --dump-bg-color: #0c0e11; 20 - --dump-border-color: #505050; 21 - } 22 - h1 { 23 - font-weight: 200; 24 - } 25 - .license .hidden { 26 - background-color: #4b4a4a; /*minimal support for IE11*/ 27 - background-color: var(--license-bg-color); 28 - } 29 - .value { 30 - background-color: #303030; /*minimal support for IE11*/ 31 - background-color: var(--button-bg-color); 32 - } 33 - #dump .tag { color: #58a6ff; } 34 - #dump .dlen { color: darkcyan; } 35 - #dump .ulen { color: #00b6b6; } 36 - #dump .intro { color: #58a6ff; } 37 - #dump .outro { color: #00b6b6; } 38 - #dump .skip { color: #707070; background-color: #222222; } 39 - #dump .hexCurrent { background-color: #727272; } 40 - #dump .hexCurrent .hex { background-color: #474747; } 41 - #dump .hexCurrent .tag { color: #6db0fc; } 42 - #dump .hexCurrent .dlen { color: #00b6b6; }
+180 -30
index.css
··· 1 - :root { 1 + html { 2 2 --main-bg-color: #C0C0C0; 3 3 --main-text-color: #000000; 4 + --id-text-color: #7d5900; 4 5 --headline-text-color: #8be9fd; 5 6 --button-border-color: #767676; 6 7 --button-bg-color: #efefef; ··· 18 19 --preview-border-color: #505050; 19 20 --dump-bg-color: #C0C0C0; 20 21 --dump-border-color: #E0E0E0; 22 + --dump-tag: blue; 23 + --dump-dlen: darkcyan; 24 + --dump-ulen: darkgreen; 25 + --dump-intro: blue; 26 + --dump-outro: darkgreen; 27 + --dump-skip: #666666; 28 + --dump-skip-bg: #C0C0C0; 29 + --dump-hex-current: #808080; 30 + --dump-hex-current-hex: #A0A0A0; 31 + --dump-hex-current-dlen: #004040; 32 + --hover-bg-color: #E0E0E0; 33 + --tree-zoom-fix: -1px; 34 + --tree-line: #999; 35 + } 36 + html[data-theme="dark"] { 37 + --main-bg-color: #0d1116; 38 + --main-text-color: #f8f8f2; 39 + --id-text-color: #9d7c2d; 40 + --headline-text-color: #8be9fd; 41 + --button-border-color: #505050; 42 + --button-bg-color: #303030; 43 + --button-bghover-color: #404040; 44 + --input-border-color: #505050; 45 + --input-bg-color: #0c0e11; 46 + --link-color: #58a6ff; 47 + --link-hover-color: #9b9bea; 48 + --header-bg-color: #161b22; 49 + --page-bg-color: #000000; 50 + --license-bg-color: #4b4a4a; 51 + --license-border-color: black; 52 + --sub-border-color: #383838; 53 + --preview-bg-color: #989797; 54 + --preview-border-color: #b5b3b3; 55 + --dump-bg-color: #0c0e11; 56 + --dump-border-color: #505050; 57 + --dump-tag: #58a6ff; 58 + --dump-dlen: darkcyan; 59 + --dump-ulen: #00b6b6; 60 + --dump-intro: #58a6ff; 61 + --dump-outro: #00b6b6; 62 + --dump-skip: #707070; 63 + --dump-skip-bg: #222222; 64 + --dump-hex-current: #727272; 65 + --dump-hex-current-hex: #474747; 66 + --dump-hex-current-dlen: #00b6b6; 67 + --hover-bg-color: #505050; 68 + --tree-line: #333; 21 69 } 22 70 html, body { 23 71 background-color: var(--page-bg-color); ··· 83 131 #main-page { 84 132 background-color: var(--main-bg-color); 85 133 border: 0px; 86 - padding: 15px; 134 + padding: 5px; 87 135 } 88 136 #main-page > div { 89 137 position: relative; ··· 115 163 /*display: block;*/ 116 164 visibility: visible; 117 165 } 118 - .node { 119 - position: relative; 120 - } 121 - .sub { 122 - padding-left: 1.5em; 123 - border-left: solid 1px var(--sub-border-color); 124 - } 125 166 .head { 126 167 height: 1em; 127 168 white-space: nowrap; 128 169 } 129 - .head:hover::before { 130 - position: absolute; 131 - content: '-'; 132 - color: red; 133 - border: solid 1px red; 134 - border-radius: 20px; 135 - background-color: black; 136 - /*TODO: use vars instead of hex*/ 137 - } 138 170 .node:hover > .head, .node.hover > .head { 139 171 color: var(--link-color); 140 - font-weight: bold; 172 + background-color: var(--hover-bg-color); 141 173 } 142 174 .node:hover > .head:hover, .node.hover > .head.hover { 143 175 color: var(--link-hover-color); ··· 156 188 color: var(--preview-border-color); 157 189 } 158 190 .name.id { 159 - color: var(--main-text-color); 191 + color: var(--id-text-color); 160 192 } 161 193 .value { 162 194 display: none; 163 195 position: absolute; 164 196 z-index: 2; 165 197 top: 1.2em; 166 - left: 0; 198 + left: 30px; 167 199 background-color: #efefef; /*minimal support for IE11*/ 168 200 background-color: var(--button-bg-color); 169 201 border: solid 1px var(--button-border-color); ··· 201 233 white-space: pre; 202 234 padding: 5px; 203 235 } 204 - #dump .tag { color: blue; } 205 - #dump .dlen { color: darkcyan; } 206 - #dump .ulen { color: darkgreen; } 207 - #dump .intro { color: blue; } 208 - #dump .outro { color: darkgreen; } 209 - #dump .skip { color: #666666; background-color: #C0C0C0; } 210 - #dump .hexCurrent { background-color: #808080; } 211 - #dump .hexCurrent .hex { background-color: #A0A0A0; } 212 - #dump .hexCurrent .dlen { color: #004040; } 236 + #dump .tag { color: var(--dump-tag); } 237 + #dump .dlen { color: var(--dump-dlen); } 238 + #dump .ulen { color: var(--dump-ulen); } 239 + #dump .intro { color: var(--dump-intro); } 240 + #dump .outro { color: var(--dump-outro); } 241 + #dump .skip { color: var(--dump-skip); background-color: var(--dump-skip-bg); } 242 + #dump .hexCurrent { background-color: var(--dump-hex-current); } 243 + #dump .hexCurrent .hex { background-color: var(--dump-hex-current-hex); } 244 + #dump .hexCurrent .dlen { color: var(--dump-hex-current-dlen); } 213 245 #file { display: none; } 214 246 #area { width: 100%; } 247 + #contextmenu { 248 + position: absolute; 249 + visibility: hidden; 250 + top: 0; 251 + left: 0; 252 + padding: 2px; 253 + background-color: var(--button-bg-color); 254 + border: 1px solid var(--button-bg-color); 255 + z-index: 2; 256 + } 257 + #contextmenu > button { 258 + display: block; 259 + width: 120px; 260 + background-color: var(--button-bg-color); 261 + color: var(--main-text-color); 262 + border: 1px solid var(--button-border-color); 263 + text-align: left; 264 + } 265 + #contextmenu > button:hover { 266 + background-color: var(--button-bghover-color); 267 + } 268 + 269 + .treecollapse { 270 + --spacing: 1.5rem; 271 + --radius: 7px; 272 + padding-inline-start: 0px; 273 + } 274 + .treecollapse li{ 275 + display: block; 276 + position: relative; 277 + padding-left: calc(2 * var(--spacing) - var(--radius) - 2px); 278 + } 279 + .treecollapse ul{ 280 + padding-left: 0; 281 + margin-left: calc(var(--radius) - var(--spacing)); 282 + } 283 + .treecollapse ul li{ 284 + border-left: 1px solid var(--tree-line); 285 + } 286 + .treecollapse ul li:last-child{ 287 + border-color: transparent; 288 + } 289 + .treecollapse ul li::before{ 290 + content: ''; 291 + display: block; 292 + position: absolute; 293 + top: calc(var(--spacing) / -1.6); 294 + left: var(--tree-zoom-fix); 295 + width: calc(var(--spacing) + 2px); 296 + height: calc(var(--spacing) + 1px); 297 + border: solid var(--tree-line); 298 + border-width: 0 0 1px 1px; 299 + } 300 + .treecollapse summary{ 301 + display : block; 302 + cursor : pointer; 303 + } 304 + .treecollapse summary::marker, 305 + .treecollapse summary::-webkit-details-marker{ 306 + display : none; 307 + } 308 + .treecollapse summary:focus{ 309 + outline : none; 310 + } 311 + .treecollapse summary:focus-visible{ 312 + outline : 1px dotted #000; 313 + } 314 + .treecollapse summary::before{ 315 + content: ''; 316 + display: block; 317 + position: absolute; 318 + top: calc(var(--spacing) / 2 - var(--radius)); 319 + left: calc(var(--spacing) - var(--radius) - 1px); 320 + width: calc(2 * var(--radius)); 321 + height: calc(2 * var(--radius)); 322 + } 323 + .treecollapse summary::before{ 324 + z-index: 1; 325 + top: 1px; 326 + background: url('tree-icon-light.svg'); 327 + } 328 + html[data-theme="dark"] .treecollapse summary::before{ 329 + background: url('tree-icon-dark.svg'); 330 + } 331 + .treecollapse details[open] > summary::before{ 332 + background-position : calc(-2 * var(--radius)) 0; 333 + } 334 + 335 + /* 336 + Zoom fix to have straight lines in treeview 337 + Zoom level and dpi resolution: 338 + - 175%: 336dpi 339 + - 150%: 288dpi 340 + - 110%: 212dpi 341 + - 100%: 192dpi 342 + - 90%: 173dpi 343 + - 80%: 154dpi 344 + */ 345 + @media (resolution <= 154dpi) { 346 + :root{ 347 + --tree-zoom-fix: -0.6px; 348 + } 349 + } 350 + @media (155dpi <= resolution < 192dpi) { 351 + :root{ 352 + --tree-zoom-fix: -0.7px; 353 + } 354 + } 355 + @media (192dpi <= resolution < 336dpi) { 356 + :root{ 357 + --tree-zoom-fix: -1px; 358 + } 359 + } 360 + @media (336dpi <= resolution) { 361 + :root{ 362 + --tree-zoom-fix: -0.9px; 363 + } 364 + }
+27 -23
index.html
··· 1 1 <!DOCTYPE html> 2 - <html> 2 + <html data-theme="dark"> 3 3 <head> 4 - <meta charset="US-ASCII"> 4 + <meta charset="UTF-8"> 5 5 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> 6 + <meta name="theme-color" content="#0d1116" media="(prefers-color-scheme: dark)"> 7 + <meta name="theme-color" content="#C0C0C0" media="(prefers-color-scheme: light)"> 6 8 <title>ASN.1 JavaScript decoder</title> 7 - <link rel="stylesheet" href="index.css" type="text/css" id="theme-base"> 9 + <link rel="stylesheet" href="index.css" type="text/css"> 8 10 <link rel="icon" type="image/svg+xml" sizes="192x192" href="favicon.svg"> 9 11 </head> 10 12 <body> 13 + <div id="contextmenu"> 14 + <button id="btnCopyHex">Copy hex dump</button> 15 + <button id="btnCopyB64">Copy Base64</button> 16 + <button id="btnCopyTree">Copy subtree</button> 17 + <button id="btnCopyValue">Copy value</button> 18 + </div> 11 19 <header> 12 20 <div class="title"> 13 21 <h1>ASN.1 JavaScript decoder</h1> ··· 29 37 <div id="tree"></div> 30 38 </div> 31 39 <form> 32 - <textarea id="area" rows="8"></textarea> 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> 33 41 <br> 34 42 <br> 35 43 <label title="can be slow with big files"><input type="checkbox" id="wantHex" checked="checked"> with hex dump</label> ··· 39 47 <br><br> 40 48 <table> 41 49 <tr><td>Drag or load file:</td><td><input type="file" id="file"></td></tr> 42 - <tr><td>Load examples:</td><td> 50 + <tr id="rowExamples"><td>Load examples:</td><td> 43 51 <select id="examples"> 44 52 <option value="sig-p256-der.p7m">PKCS#7/CMS attached signature (DER)</option> 45 53 <option value="sig-p256-ber.p7m">PKCS#7/CMS attached signature (BER)</option> 46 54 <option value="sig-rsa1024-sha1.p7s">PKCS#7/CMS detached signature (old)</option> 55 + <option value="cms-password.p7m">PKCS#7/CMS encrypted with password</option> 47 56 <option value="letsencrypt-x3.cer">X.509 certificate: Let's Encrypt X3</option> 48 57 <option value="ed25519.cer">X.509 certificate: ed25519 (RFC 8410)</option> 58 + <option value="pkcs1.pem">PKCS#1 RSA key (RFC 8017)</option> 59 + <option value="pkcs8-rsa.pem">PKCS#8 RSA key (RFC 5208)</option> 49 60 <option value="pkcs10.pem">PKCS#10 certification request (RFC 2986)</option> 61 + <option value="crl-rfc5280.b64">CRL example (RFC 5280)</option> 50 62 <option value="cmpv2.b64">CMP PKI message (RFC 4210)</option> 63 + <option value="ldapmessage.b64">LDAP message (RFC 4511)</option> 51 64 </select> 52 65 <input id="butExample" type="button" value="load"><br> 53 66 </td></tr> ··· 59 72 <div id="help"> 60 73 <h2>Instructions</h2> 61 74 <p>This page contains a JavaScript generic ASN.1 parser that can decode any valid ASN.1 DER or BER structure whether Base64-encoded (raw base64, PEM armoring and <span class="tt">begin-base64</span> are recognized) or Hex-encoded. </p> 62 - <p>This tool can be used online at the address <a href="http://lapo.it/asn1js/"><span class="tt">http://lapo.it/asn1js/</span></a> or offline, unpacking <a href="http://lapo.it/asn1js/asn1js.zip">the ZIP file</a> in a directory and opening <span class="tt">index.html</span> in a browser</p> 75 + <p>This tool can be used online at the address <a href="https://asn1js.eu/"><span class="tt">https://asn1js.eu/</span></a> or offline, unpacking <a href="https://asn1js.eu/asn1js.zip">the ZIP file</a> in a directory and opening <span class="tt">index-local.html</span> in a browser.</p> 63 76 <p>On the left of the page will be printed a tree representing the hierarchical structure, on the right side an hex dump will be shown. <br> 64 77 Hovering on the tree highlights ancestry (the hovered node and all its ancestors get colored) and the position of the hovered node gets highlighted in the hex dump (with header and content in a different colors). <br> 65 78 Clicking a node in the tree will hide its sub-nodes (collapsed nodes can be noticed because they will become <i>italic</i>).</p> 66 - <p><b>WARNING:</b> starting from 2023-02-26 this website is using some ES6 features, which can break it for older browsers (though it is <a href="https://www.browserling.com/browse/win7/ie11/https://asn1js.eu/">still working on IE11</a>).<br> 67 - You can access <a href="https://rawcdn.githack.com/lapo-luchini/asn1js/1.2.4/index.html">last version before ES6 on githack</a>.</p> 79 + <p><b>WARNING:</b> starting from 2024-03-28 this website is using ES6 features (and modules), which can break it for <a href="https://caniuse.com/es6-module">very old browsers</a>.<br> 80 + You can access <a href="https://rawcdn.githack.com/lapo-luchini/asn1js/1.2.4/index.html">last version before ES6 on githack</a> (which <a href="https://www.browserling.com/browse/win7/ie11/https://rawcdn.githack.com/lapo-luchini/asn1js/1.2.4/index.html">still works on IE11</a>).</p> 68 81 <div class="license"> 69 82 <h3>Copyright</h3> 70 83 <div><p class="hidden"> 71 84 ASN.1 JavaScript decoder<br> 72 - Copyright &copy; 2008-2024 Lapo Luchini <a href="mailto:lapo@lapo.it?subject=ASN1js">&lt;lapo@lapo.it&gt;</a><br> 85 + Copyright &copy; 2008-2025 Lapo Luchini <a href="mailto:lapo@lapo.it?subject=ASN1js">&lt;lapo@lapo.it&gt;</a><br> 73 86 <br> 74 87 Permission to use, copy, modify, and/or distribute this software for any 75 88 purpose with or without fee is hereby granted, provided that the above ··· 83 96 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 84 97 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 85 98 </p></div> 86 - <p>ASN.1 JavaScript decoder Copyright &copy; 2008-2024 <a href="http://lapo.it/">Lapo Luchini</a>; released as <a href="http://opensource.org/licenses/isc-license.txt">opensource</a> under the <a href="http://en.wikipedia.org/wiki/ISC_licence">ISC license</a>.</p> 99 + <p>ASN.1 JavaScript decoder Copyright &copy; 2008-2025 <a href="https://lapo.it/">Lapo Luchini</a>; released as <a href="https://opensource.org/licenses/isc-license.txt">opensource</a> under the <a href="https://en.wikipedia.org/wiki/ISC_licence">ISC license</a>.</p> 87 100 </div> 88 - <p><span class="tt">OBJECT&nbsp;IDENTIFIER</span> values are recognized using data taken from Peter Gutmann's <a href="http://www.cs.auckland.ac.nz/~pgut001/#standards">dumpasn1</a> program.</p> 101 + <p><span class="tt">OBJECT&nbsp;IDENTIFIER</span> values are recognized using data taken from Peter Gutmann's <a href="https://www.cs.auckland.ac.nz/~pgut001/#standards">dumpasn1</a> program.</p> 89 102 <h3>Links</h3> 90 103 <ul> 91 - <li><a href="http://lapo.it/asn1js/">official website</a></li> 92 - <li><a href="http://asn1js.eu/">dedicated domain</a></li> 104 + <li><a href="https://asn1js.eu/">official website</a></li> 105 + <li><a href="https://lapo.it/asn1js/">alternate website</a></li> 106 + <li><a href="https://asn1js.eu/index-local.html">single-file version working locally</a> (just save this link)</li> 93 107 <li>previous versions on githack: <select id="tags"><option>[select tag]</option></select></li> 94 108 <li><a href="http://idf.lapo.it/p/asn1js/">InDefero tracker</a> (currently offline)</li> 95 109 <li><a href="https://github.com/lapo-luchini/asn1js">github mirror</a></li> 96 110 <li><a href="https://www.openhub.net/p/asn1js">OpenHub code stats</a></li> 97 111 </ul> 98 112 </div> 99 - 100 - <script type="module" src="tags.js"></script> 101 - <script type="module" src="hex.js"></script> 102 - <script type="module" src="base64.js"></script> 103 - <script type="module" src="oids.js"></script> 104 - <script type="module" src="rfcdef.js"></script> 105 - <script type="module" src="defs.js"></script> 106 - <script type="module" src="int10.js"></script> 107 - <script type="module" src="asn1.js"></script> 108 - <script type="module" src="dom.js"></script> 109 113 <script type="module" src="index.js"></script> 110 114 </body> 111 115 </html>
+39 -56
index.js
··· 1 + import './theme.js'; 1 2 import { ASN1DOM } from './dom.js'; 2 3 import { Base64 } from './base64.js'; 3 4 import { Hex } from './hex.js'; ··· 15 16 area = id('area'), 16 17 file = id('file'), 17 18 examples = id('examples'), 18 - selectTheme = id('theme-select'), 19 19 selectDefs = id('definitions'), 20 20 selectTag = id('tags'); 21 21 ··· 41 41 function show(asn1) { 42 42 tree.innerHTML = ''; 43 43 dump.innerHTML = ''; 44 - tree.appendChild(asn1.toDOM()); 44 + let ul = document.createElement('ul'); 45 + ul.className = 'treecollapse'; 46 + tree.appendChild(ul); 47 + ul.appendChild(asn1.toDOM()); 45 48 if (wantHex.checked) dump.appendChild(asn1.toHexDOM(undefined, trimHex.checked)); 46 49 } 47 - function decode(der, offset) { 50 + export function decode(der, offset) { 48 51 offset = offset || 0; 49 52 try { 50 53 const asn1 = ASN1DOM.decode(der, offset); ··· 103 106 text(tree, e); 104 107 } 105 108 } 106 - function decodeText(val) { 109 + export function decodeText(val) { 107 110 try { 108 111 let der = reHex.test(val) ? Hex.decode(val) : Base64.unarmor(val); 109 112 decode(der); ··· 112 115 dump.innerHTML = ''; 113 116 } 114 117 } 115 - function decodeBinaryString(str) { 118 + export function decodeBinaryString(str) { 116 119 let der; 117 120 try { 118 121 if (reHex.test(str)) der = Hex.decode(str); ··· 125 128 } 126 129 } 127 130 // set up buttons 128 - id('butDecode').onclick = function () { 129 - decodeText(area.value); 131 + const butClickHandlers = { 132 + butDecode: () => { 133 + decodeText(area.value); 134 + }, 135 + butClear: () => { 136 + area.value = ''; 137 + file.value = ''; 138 + tree.innerHTML = ''; 139 + dump.innerHTML = ''; 140 + selectDefs.innerHTML = ''; 141 + hash = window.location.hash = ''; 142 + }, 143 + butExample: () => { 144 + console.log('Loading example:', examples.value); 145 + let request = new XMLHttpRequest(); 146 + request.open('GET', 'examples/' + examples.value, true); 147 + request.onreadystatechange = function () { 148 + if (this.readyState !== 4) return; 149 + if (this.status >= 200 && this.status < 400) { 150 + area.value = this.responseText; 151 + decodeText(this.responseText); 152 + } else { 153 + console.log('Error loading example.'); 154 + } 155 + }; 156 + request.send(); 157 + }, 130 158 }; 131 - id('butClear').onclick = function () { 132 - area.value = ''; 133 - file.value = ''; 134 - tree.innerHTML = ''; 135 - dump.innerHTML = ''; 136 - selectDefs.innerHTML = ''; 137 - hash = window.location.hash = ''; 138 - }; 139 - id('butExample').onclick = function () { 140 - console.log('Loading example:', examples.value); 141 - let request = new XMLHttpRequest(); 142 - request.open('GET', 'examples/' + examples.value, true); 143 - request.onreadystatechange = function () { 144 - if (this.readyState !== 4) return; 145 - if (this.status >= 200 && this.status < 400) { 146 - area.value = this.responseText; 147 - decodeText(this.responseText); 148 - } else { 149 - console.log('Error loading example.'); 150 - } 151 - }; 152 - request.send(); 153 - }; 154 - // set dark theme depending on OS settings 155 - function setTheme() { 156 - let storedTheme = localStorage.getItem('theme'); 157 - let theme = 'os'; 158 - if (storedTheme) 159 - theme = storedTheme; 160 - selectTheme.value = theme; 161 - if (theme == 'os') { 162 - let prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)'); 163 - theme = prefersDarkScheme.matches ? 'dark': 'light'; 164 - } 165 - if (theme == 'dark') { 166 - const css1 = id('theme-base'); 167 - const css2 = css1.cloneNode(); 168 - css2.id = 'theme-override'; 169 - css2.href = 'index-' + theme + '.css'; 170 - css1.parentElement.appendChild(css2); 171 - } else { 172 - const css2 = id('theme-override'); 173 - if (css2) css2.remove(); 174 - } 159 + for (const [name, onClick] of Object.entries(butClickHandlers)) { 160 + let elem = id(name); 161 + if (elem) 162 + elem.onclick = onClick; 175 163 } 176 - setTheme(); 177 - selectTheme.addEventListener('change', function () { 178 - localStorage.setItem('theme', selectTheme.value); 179 - setTheme(); 180 - }); 181 164 // this is only used if window.FileReader 182 165 function read(f) { 183 166 area.value = ''; // clear text area, will get b64 content
+15 -9
int10.js
··· 1 1 // Big integer base-10 printing library 2 - // Copyright (c) 2008-2024 Lapo Luchini <lapo@lapo.it> 2 + // Copyright (c) 2008 Lapo Luchini <lapo@lapo.it> 3 3 4 4 // Permission to use, copy, modify, and/or distribute this software for any 5 5 // purpose with or without fee is hereby granted, provided that the above 6 6 // copyright notice and this permission notice appear in all copies. 7 - // 7 + // 8 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ··· 13 13 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 14 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 15 16 - let max = 10000000000000; // biggest 10^n integer that can still fit 2^53 when multiplied by 256 16 + /** Biggest 10^n integer that can still fit 2^53 when multiplied by 256. */ 17 + const max = 10000000000000; 17 18 18 19 export class Int10 { 19 20 /** ··· 26 27 27 28 /** 28 29 * Multiply value by m and add c. 29 - * @param {number} m - multiplier, must be < =256 30 - * @param {number} c - value to add 30 + * @param {number} m - multiplier, must be 0<m<=256 31 + * @param {number} c - value to add, must be c>=0 31 32 */ 32 33 mulAdd(m, c) { 34 + // assert(m > 0) 33 35 // assert(m <= 256) 36 + // assert(c >= 0) 34 37 let b = this.buf, 35 38 l = b.length, 36 39 i, t; ··· 71 74 72 75 /** 73 76 * Convert to decimal string representation. 74 - * @param {*} base - optional value, only value accepted is 10 77 + * @param {number} [base=10] - optional value, only value accepted is 10 78 + * @returns {string} The decimal string representation. 75 79 */ 76 - toString(base) { 77 - if ((base || 10) != 10) 78 - throw 'only base 10 is supported'; 80 + toString(base = 10) { 81 + if (base != 10) 82 + throw new Error('only base 10 is supported'); 79 83 let b = this.buf, 80 84 s = b[b.length - 1].toString(); 81 85 for (let i = b.length - 2; i >= 0; --i) ··· 86 90 /** 87 91 * Convert to Number value representation. 88 92 * Will probably overflow 2^53 and thus become approximate. 93 + * @returns {number} The numeric value. 89 94 */ 90 95 valueOf() { 91 96 let b = this.buf, ··· 97 102 98 103 /** 99 104 * Return value as a simple Number (if it is <= 10000000000000), or return this. 105 + * @returns {number | Int10} The simplified value. 100 106 */ 101 107 simplify() { 102 108 let b = this.buf;
-1
oids.js
··· 2722 2722 "1.3.6.1.4.1.40869.1.1.22.3": { "d": "TWCA EV policy", "c": "TWCA Root Certification Authority" }, 2723 2723 "2.16.840.1.113733.1.7.23.6": { "d": "VeriSign EV policy", "c": "VeriSign Class 3 Public Primary Certification Authority" }, 2724 2724 "2.16.840.1.114171.500.9": { "d": "Wells Fargo EV policy", "c": "Wells Fargo WellsSecure Public Root Certificate Authority" }, 2725 - "END": "" 2726 2725 };
+41 -11
package.json
··· 1 1 { 2 2 "name": "@lapo/asn1js", 3 - "version": "2.0.0", 3 + "version": "2.0.6", 4 4 "description": "Generic ASN.1 parser/decoder that can decode any valid ASN.1 DER or BER structures.", 5 5 "type": "module", 6 6 "main": "asn1.js", ··· 13 13 "license": "ISC", 14 14 "bugs": { "url": "https://github.com/lapo-luchini/asn1js/issues" }, 15 15 "homepage": "https://lapo.it/asn1js/", 16 - "files": [ "asn1.js", "base64.js", "hex.js", "int10.js", "oids.js" ], 16 + "files": [ "asn1.js", "base64.js", "hex.js", "int10.js", "dom.js", "defs.js", "oids.js", "rfcdef.js", "dumpASN1.js" ], 17 17 "scripts": { 18 - "lint": "npx eslint asn1.js base64.js hex.js int10.js oids.js tags.js index.js parseRFC.js dumpASN1.js", 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 19 "lint-action": "npx @action-validator/cli .github/workflows/node.js.yml", 20 - "serve": "echo 'Connect to http://localhost:3000/' ; npx statik --port 3000 .", 21 - "test": "node test" 20 + "build": "vite build", 21 + "serve": "npx -p local-web-server ws", 22 + "test": "node test", 23 + "testdefs": "node testDefs" 24 + }, 25 + "bin": { 26 + "dumpASN1": "./dumpASN1.js" 22 27 }, 23 28 "engines": { 24 29 "node": ">=12.20.0" 25 30 }, 26 31 "devDependencies": { 27 - "eslint": "^8.34.0" 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" 41 + }, 42 + "pnpm": { 43 + "overrides": { 44 + "rollup": "npm:@rollup/wasm-node" 45 + } 28 46 }, 29 47 "eslintConfig": { 30 48 "env": { ··· 43 61 "rules": { 44 62 "strict": [ "error", "function" ], 45 63 "indent": [ "error", 4 ], 64 + "no-trailing-spaces": [ "error" ], 46 65 "linebreak-style": [ "error", "unix" ], 66 + "eol-last": [ "error", "always" ], 47 67 "semi": [ "warn", "always" ], 48 68 "quotes": [ "error", "single", { "avoidEscape": true } ], 49 69 "no-var": [ "warn" ], 50 - "comma-dangle": [ "error", "never" ] 70 + "comma-dangle": [ "error", "always-multiline" ] 51 71 }, 52 72 "overrides": [ 53 73 { 74 + "files": [ "defs.js" ], 75 + "parserOptions": { 76 + "ecmaVersion": 2020 77 + } 78 + }, { 54 79 "files": [ "test.js", "parseRFC.js", "dumpASN1.js" ], 55 80 "parserOptions": { 56 81 "ecmaVersion": 2021 57 82 }, 58 83 "rules": { 59 - "strict": [ "error", "global" ], 60 - "comma-dangle": [ "error", "always-multiline" ] 84 + "strict": [ "error", "global" ] 61 85 } 62 86 }, { 63 87 "files": [ "oids.js" ], ··· 66 90 "quotes": [ "warn", "double" ] 67 91 } 68 92 }, { 69 - "files": [ "tags.js" ], 93 + "files": [ "tags.js", "rfcdef.js" ], 70 94 "rules": { 71 - "comma-dangle": [ "error", "always-multiline" ], 95 + "indent": [ "error", 2, { "ignoredNodes": [ "Program > ExpressionStatement > CallExpression > FunctionExpression > BlockStatement > ExpressionStatement[directive='use strict']:first-child" ] } ], 96 + "comma-dangle": "off", 72 97 "quotes": [ "warn", "double" ] 73 98 } 74 99 }, { 75 100 "files": [ "defs.js" ], 76 101 "parserOptions": { 77 102 "ecmaVersion": 2021 103 + } 104 + }, { 105 + "files": [ "testDefs.js" ], 106 + "parserOptions": { 107 + "ecmaVersion": 2022 78 108 } 79 109 } 80 110 ]
+73 -7
parseRFC.js
··· 1 1 #! /usr/bin/env node 2 2 3 + // RFC ASN.1 definition parser 4 + // Copyright (c) 2021 Lapo Luchini <lapo@lapo.it> 5 + 6 + // Permission to use, copy, modify, and/or distribute this software for any 7 + // purpose with or without fee is hereby granted, provided that the above 8 + // copyright notice and this permission notice appear in all copies. 9 + // 10 + // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 + // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 + // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 + // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 + // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 + // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 + // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 + 3 18 import * as fs from 'node:fs'; 4 19 5 20 const ··· 45 60 4210: [ 46 61 [ /^\s+-- .*\r?\n/mg, '' ], // comments 47 62 ], 63 + 8017: [ // this RFC uses a lot of currently unsupported syntax 64 + [ /ALGORITHM-IDENTIFIER ::= CLASS[^-]+--/, '--' ], 65 + [ /\n +\S+ +ALGORITHM-IDENTIFIER[^\n]+(\n {6}[^\n]+)+\n {3}[}]/g, '' ], 66 + [ /AlgorithmIdentifier [{] ALGORITHM-IDENTIFIER:InfoObjectSet [}] ::=(\n {6}[^\n]+)+\n {3}[}]/, 'AlgorithmIdentifier ::= ANY'], 67 + [ /algorithm +id-[^,\n]+,/g, 'algorithm ANY,' ], 68 + [ / (sha1 {4}HashAlgorithm|mgf1SHA1 {4}MaskGenAlgorithm|pSpecifiedEmpty {4}PSourceAlgorithm|rSAES-OAEP-Default-Identifier {4}RSAES-AlgorithmIdentifier|rSASSA-PSS-Default-Identifier {4}RSASSA-AlgorithmIdentifier) ::= [{](\n( {6}[^\n]+)?)+\n {3}[}]/g, '' ], 69 + [ / ::= AlgorithmIdentifier [{]\s+[{][^}]+[}]\s+[}]/g, ' ::= AlgorithmIdentifier' ], 70 + [ /OCTET STRING[(]SIZE[(]0..MAX[)][)]/g, 'OCTET STRING' ], 71 + [ /emptyString {4}EncodingParameters ::= ''H/g, '' ], 72 + [ /[(]CONSTRAINED BY[^)]+[)]/g, '' ], 73 + ], 74 + 4511: [ 75 + [ /^\s+-- .*\r?\n/mg, '' ], // comments 76 + [ 'EXTENSIBILITY IMPLIED', '' ], 77 + [ /\.\.\.(,| {2})/g, '' ], 78 + [ /value AttributeValue/g, 'AttributeValue' ], 79 + [ /control Control/g, 'Control' ], 80 + [ /Attribute ::= PartialAttribute\(WITH COMPONENTS \{[^}]+\}\)/g, 'PartialAttribute ::= SEQUENCE { type AttributeDescription, vals SET SIZE (1..MAX) OF AttributeValue }' ], 81 + [ /,\s+\}/g, '}' ], 82 + [ /SaslCredentials,/g, 'SaslCredentials' ], 83 + [ /(BindResponse|ExtendedResponse) ::= \[APPLICATION [0-9]+\] SEQUENCE \{[^}]+\}/g, '$1 ::= ANY' ], 84 + [ /selector LDAPString/g, 'LDAPString' ], 85 + [ /filter Filter/g, 'Filter' ], 86 + [ /MatchingRuleAssertion,/g, 'MatchingRuleAssertion' ], 87 + [ /OF substring CHOICE/g, 'OF CHOICE' ], 88 + [ /partialAttribute PartialAttribute/g, 'PartialAttribute' ], 89 + [ /uri URI/g, 'URI' ], 90 + [ /OF change SEQUENCE/g, 'OF SEQUENCE' ], 91 + [ /attribute Attribute/g, 'Attribute' ], 92 + ], 48 93 }; 49 94 50 95 // const reWhitespace = /(?:\s|--(?:[}-]?[^\n}-])*(?:\n|--))*/y; ··· 52 97 const reIdentifier = /[a-zA-Z](?:[-]?[a-zA-Z0-9])*/y; 53 98 const reNumber = /0|[1-9][0-9]*/y; 54 99 const reToken = /[(){},[\];]|::=|OPTIONAL|DEFAULT|NULL|TRUE|FALSE|\.\.|OF|SIZE|MIN|MAX|DEFINED BY|DEFINITIONS|TAGS|BEGIN|EXPORTS|IMPORTS|FROM|END/y; 55 - const reType = /ANY|BOOLEAN|INTEGER|(?:BIT|OCTET)\s+STRING|OBJECT\s+IDENTIFIER|SEQUENCE|SET|CHOICE|ENUMERATED|(?:Generalized|UTC)Time|(?:BMP|General|Graphic|IA5|ISO64|Numeric|Printable|Teletex|T61|Universal|UTF8|Videotex|Visible)String/y; 100 + const reType = /ANY|NULL|BOOLEAN|INTEGER|(?:BIT|OCTET)\s+STRING|OBJECT\s+IDENTIFIER|SEQUENCE|SET|CHOICE|ENUMERATED|(?:Generalized|UTC)Time|(?:BMP|General|Graphic|IA5|ISO64|Numeric|Printable|Teletex|T61|Universal|UTF8|Videotex|Visible)String/y; 56 101 const reTagClass = /UNIVERSAL|APPLICATION|PRIVATE|/y; 57 102 const reTagType = /IMPLICIT|EXPLICIT|/y; 58 103 const reTagDefault = /(AUTOMATIC|IMPLICIT|EXPLICIT) TAGS|/y; ··· 213 258 if (this.tryToken('DEFINED BY')) 214 259 x.definedBy = this.parseIdentifier(); 215 260 break; 261 + case 'NULL': 216 262 case 'BOOLEAN': 217 263 case 'OCTET STRING': 218 264 case 'OBJECT IDENTIFIER': ··· 277 323 this.expectToken(')'); 278 324 } 279 325 break; 326 + case 'UTCTime': 327 + case 'GeneralizedTime': 328 + break; 280 329 default: 281 - x.content = 'TODO:unknown'; 330 + x.warning = 'type unknown'; 282 331 } 283 332 } catch (e) { 284 333 console.log('[debug] parseBuiltinType content', e); 285 - x.content = 'TODO:exception'; 334 + x.warning = 'type exception'; 286 335 } 287 336 return x; 288 337 } ··· 294 343 let plicit = this.getRegEx('explicit/implicit', reTagType); 295 344 if (plicit == '') plicit = currentMod.tagDefault; 296 345 let x = this.parseType(); 346 + let name; 347 + switch (tagClass) { // keep in sync with ASN1.typeName 348 + case 'APPLICATION': 349 + name = 'Application ' + t; 350 + break; 351 + case 'PRIVATE': 352 + name = 'Private ' + t; 353 + break; 354 + case 'CONTEXT': 355 + // fall through 356 + default: 357 + name = '[' + t + ']'; 358 + break; 359 + } 297 360 return { 298 - name: '[' + t + ']', 361 + name, 299 362 type: 'tag', 300 363 'class': tagClass, 301 364 explicit: (plicit == 'EXPLICIT'), ··· 349 412 } else { 350 413 if (id in currentMod.values) // defined in local module 351 414 val = currentMod.values[id].value; 352 - else 415 + else try { 353 416 val = searchImportedValue(id); 417 + } catch (e) { 418 + this.exception(e.message); 419 + } 354 420 } 355 421 } 356 422 if (v.length) v += '.'; ··· 501 567 asn1[currentMod.oid] = currentMod; 502 568 } 503 569 /*asn1 = Object.keys(asn1).sort().reduce( 504 - (obj, key) => { 570 + (obj, key) => { 505 571 obj[key] = asn1[key]; 506 572 return obj; 507 - }, 573 + }, 508 574 {} 509 575 );*/ 510 576 fs.writeFileSync(process.argv[3], JSON.stringify(asn1, null, 2) + '\n', 'utf8');
+13 -13
release.sh
··· 1 1 #!/bin/sh 2 2 set -e 3 3 FILES=" 4 - asn1.js oids.js defs.js base64.js hex.js int10.js dom.js rfcdef.js test.js tags.js 5 - index.css index-dark.css index.js index.html favicon.svg 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 6 8 README.md LICENSE 7 9 updateOID.sh check.sh 8 10 examples 9 11 " 10 - mtn automate tags it.lapo.asn1js | \ 12 + mtn automate tags 'it.lapo.asn1js{,.*}' | \ 11 13 awk '/^revision/ { print substr($2, 2, length($2) - 2)}' | \ 12 14 while read rev; do 13 15 mtn automate certs $rev | awk -v q='"' ' ··· 19 21 ' 20 22 done | sort -r | awk -v q='"' ' 21 23 BEGIN { 22 - print "(typeof define != " q "undefined" q " ? define : function (factory) { " q "use strict" q ";"; 23 - print " if (typeof module == " q "object" q ") module.exports = factory();"; 24 - print " else window.tags = factory();"; 25 - print "})(function () {"; 26 - print q "use strict" q ";"; 27 - print "return {" 24 + print "export const tags = {" 28 25 } 29 - { print " " q $2 q ":" q $1 q "," } 30 - END { print "};});" } 26 + { print " " q $2 q ": " q $1 q "," } 27 + END { print "};" } 31 28 ' > tags.js 32 - type gsha256sum >/dev/null && SHA256=gsha256sum || SHA256=sha256sum 33 - $SHA256 -t $FILES | gpg --clearsign > sha256sums.asc 29 + chmod 644 examples/* 30 + type gsha256sum >/dev/null 2>/dev/null && SHA256=gsha256sum || SHA256=sha256sum 31 + pnpm build 32 + cp dist/index.html index-local.html 33 + $SHA256 -t $FILES examples/* | gpg --clearsign > sha256sums.asc 34 34 7z a -tzip -mx=9 asn1js.zip $FILES sha256sums.asc 35 35 rsync -Pvrtz asn1js.zip $FILES lapo.it:www/asn1js/
+2045 -29
rfcdef.js
··· 1 - // content parsed from ASN.1 definitions as found in the following RFCs: 5280 5208 3369 3161 2986 4211 4210 1 + // content parsed from ASN.1 definitions as found in the following RFCs: 5280 5208 3369 3161 2986 4211 4210 8017 4511 2 2 // Copyright (C) The IETF Trust (2008) 3 3 // as far as I can tell this file is allowed under the following clause: 4 4 // It is acceptable under the current IETF rules (RFC 5378) to modify extracted code if necessary. ··· 1606 1606 { 1607 1607 "id": "utcTime", 1608 1608 "name": "UTCTime", 1609 - "type": "builtin", 1610 - "content": "TODO:unknown" 1609 + "type": "builtin" 1611 1610 }, 1612 1611 { 1613 1612 "id": "generalTime", 1614 1613 "name": "GeneralizedTime", 1615 - "type": "builtin", 1616 - "content": "TODO:unknown" 1614 + "type": "builtin" 1617 1615 } 1618 1616 ] 1619 1617 } ··· 1985 1983 "CountryName": { 1986 1984 "name": "CountryName", 1987 1985 "type": { 1988 - "name": "[1]", 1986 + "name": "Application 1", 1989 1987 "type": "tag", 1990 1988 "class": "APPLICATION", 1991 1989 "explicit": true, ··· 2017 2015 "AdministrationDomainName": { 2018 2016 "name": "AdministrationDomainName", 2019 2017 "type": { 2020 - "name": "[2]", 2018 + "name": "Application 2", 2021 2019 "type": "tag", 2022 2020 "class": "APPLICATION", 2023 2021 "explicit": true, ··· 3382 3380 "name": "", 3383 3381 "type": { 3384 3382 "name": "GeneralizedTime", 3385 - "type": "builtin", 3386 - "content": "TODO:unknown" 3383 + "type": "builtin" 3387 3384 } 3388 3385 } 3389 3386 ], ··· 3400 3397 "name": "", 3401 3398 "type": { 3402 3399 "name": "GeneralizedTime", 3403 - "type": "builtin", 3404 - "content": "TODO:unknown" 3400 + "type": "builtin" 3405 3401 } 3406 3402 } 3407 3403 ], ··· 4494 4490 "name": "InvalidityDate", 4495 4491 "type": { 4496 4492 "name": "GeneralizedTime", 4497 - "type": "builtin", 4498 - "content": "TODO:unknown" 4493 + "type": "builtin" 4499 4494 } 4500 4495 } 4501 4496 } ··· 5566 5561 "id": "date", 5567 5562 "name": "GeneralizedTime", 5568 5563 "type": "builtin", 5569 - "content": "TODO:unknown", 5570 5564 "optional": true 5571 5565 }, 5572 5566 { ··· 5629 5623 "id": "date", 5630 5624 "name": "GeneralizedTime", 5631 5625 "type": "builtin", 5632 - "content": "TODO:unknown", 5633 5626 "optional": true 5634 5627 }, 5635 5628 { ··· 6142 6135 { 6143 6136 "id": "utcTime", 6144 6137 "name": "UTCTime", 6145 - "type": "builtin", 6146 - "content": "TODO:unknown" 6138 + "type": "builtin" 6147 6139 }, 6148 6140 { 6149 6141 "id": "generalTime", 6150 6142 "name": "GeneralizedTime", 6151 - "type": "builtin", 6152 - "content": "TODO:unknown" 6143 + "type": "builtin" 6153 6144 } 6154 6145 ] 6155 6146 } ··· 6664 6655 { 6665 6656 "id": "genTime", 6666 6657 "name": "GeneralizedTime", 6667 - "type": "builtin", 6668 - "content": "TODO:unknown" 6658 + "type": "builtin" 6669 6659 }, 6670 6660 { 6671 6661 "id": "accuracy", ··· 7464 7454 "name": "", 7465 7455 "type": { 7466 7456 "name": "NULL", 7467 - "type": "defined" 7457 + "type": "builtin" 7468 7458 } 7469 7459 } 7470 7460 ] ··· 8345 8335 "name": "", 8346 8336 "type": { 8347 8337 "name": "GeneralizedTime", 8348 - "type": "builtin", 8349 - "content": "TODO:unknown" 8338 + "type": "builtin" 8350 8339 } 8351 8340 } 8352 8341 ], ··· 9649 9638 { 9650 9639 "id": "willBeRevokedAt", 9651 9640 "name": "GeneralizedTime", 9652 - "type": "builtin", 9653 - "content": "TODO:unknown" 9641 + "type": "builtin" 9654 9642 }, 9655 9643 { 9656 9644 "id": "badSinceDate", 9657 9645 "name": "GeneralizedTime", 9658 - "type": "builtin", 9659 - "content": "TODO:unknown" 9646 + "type": "builtin" 9660 9647 }, 9661 9648 { 9662 9649 "id": "crlDetails", ··· 9724 9711 "name": "PKIConfirmContent", 9725 9712 "type": { 9726 9713 "name": "NULL", 9727 - "type": "defined" 9714 + "type": "builtin" 9728 9715 } 9729 9716 }, 9730 9717 "InfoTypeAndValue": { ··· 9851 9838 "optional": true 9852 9839 } 9853 9840 ] 9841 + } 9842 + ] 9843 + } 9844 + } 9845 + } 9846 + }, 9847 + "1.2.840.113549.1.1.0.1": { 9848 + "name": "PKCS-1", 9849 + "oid": "1.2.840.113549.1.1.0.1", 9850 + "source": "rfc8017.txt", 9851 + "tagDefault": "EXPLICIT", 9852 + "imports": { 9853 + "2.16.840.1.101.3.4.2": { 9854 + "name": "NIST-SHA2", 9855 + "oid": "2.16.840.1.101.3.4.2", 9856 + "types": [ 9857 + "id-sha224", 9858 + "id-sha256", 9859 + "id-sha384", 9860 + "id-sha512", 9861 + "id-sha512-224", 9862 + "id-sha512-256" 9863 + ] 9864 + } 9865 + }, 9866 + "values": { 9867 + "pkcs-1": { 9868 + "name": "pkcs-1", 9869 + "type": { 9870 + "name": "OBJECT IDENTIFIER", 9871 + "type": "builtin" 9872 + }, 9873 + "value": "1.2.840.113549.1.1" 9874 + }, 9875 + "rsaEncryption": { 9876 + "name": "rsaEncryption", 9877 + "type": { 9878 + "name": "OBJECT IDENTIFIER", 9879 + "type": "builtin" 9880 + }, 9881 + "value": "1.2.840.113549.1.1.1" 9882 + }, 9883 + "id-RSAES-OAEP": { 9884 + "name": "id-RSAES-OAEP", 9885 + "type": { 9886 + "name": "OBJECT IDENTIFIER", 9887 + "type": "builtin" 9888 + }, 9889 + "value": "1.2.840.113549.1.1.7" 9890 + }, 9891 + "id-pSpecified": { 9892 + "name": "id-pSpecified", 9893 + "type": { 9894 + "name": "OBJECT IDENTIFIER", 9895 + "type": "builtin" 9896 + }, 9897 + "value": "1.2.840.113549.1.1.9" 9898 + }, 9899 + "id-RSASSA-PSS": { 9900 + "name": "id-RSASSA-PSS", 9901 + "type": { 9902 + "name": "OBJECT IDENTIFIER", 9903 + "type": "builtin" 9904 + }, 9905 + "value": "1.2.840.113549.1.1.10" 9906 + }, 9907 + "md2WithRSAEncryption": { 9908 + "name": "md2WithRSAEncryption", 9909 + "type": { 9910 + "name": "OBJECT IDENTIFIER", 9911 + "type": "builtin" 9912 + }, 9913 + "value": "1.2.840.113549.1.1.2" 9914 + }, 9915 + "md5WithRSAEncryption": { 9916 + "name": "md5WithRSAEncryption", 9917 + "type": { 9918 + "name": "OBJECT IDENTIFIER", 9919 + "type": "builtin" 9920 + }, 9921 + "value": "1.2.840.113549.1.1.4" 9922 + }, 9923 + "sha1WithRSAEncryption": { 9924 + "name": "sha1WithRSAEncryption", 9925 + "type": { 9926 + "name": "OBJECT IDENTIFIER", 9927 + "type": "builtin" 9928 + }, 9929 + "value": "1.2.840.113549.1.1.5" 9930 + }, 9931 + "sha224WithRSAEncryption": { 9932 + "name": "sha224WithRSAEncryption", 9933 + "type": { 9934 + "name": "OBJECT IDENTIFIER", 9935 + "type": "builtin" 9936 + }, 9937 + "value": "1.2.840.113549.1.1.14" 9938 + }, 9939 + "sha256WithRSAEncryption": { 9940 + "name": "sha256WithRSAEncryption", 9941 + "type": { 9942 + "name": "OBJECT IDENTIFIER", 9943 + "type": "builtin" 9944 + }, 9945 + "value": "1.2.840.113549.1.1.11" 9946 + }, 9947 + "sha384WithRSAEncryption": { 9948 + "name": "sha384WithRSAEncryption", 9949 + "type": { 9950 + "name": "OBJECT IDENTIFIER", 9951 + "type": "builtin" 9952 + }, 9953 + "value": "1.2.840.113549.1.1.12" 9954 + }, 9955 + "sha512WithRSAEncryption": { 9956 + "name": "sha512WithRSAEncryption", 9957 + "type": { 9958 + "name": "OBJECT IDENTIFIER", 9959 + "type": "builtin" 9960 + }, 9961 + "value": "1.2.840.113549.1.1.13" 9962 + }, 9963 + "sha512-224WithRSAEncryption": { 9964 + "name": "sha512-224WithRSAEncryption", 9965 + "type": { 9966 + "name": "OBJECT IDENTIFIER", 9967 + "type": "builtin" 9968 + }, 9969 + "value": "1.2.840.113549.1.1.15" 9970 + }, 9971 + "sha512-256WithRSAEncryption": { 9972 + "name": "sha512-256WithRSAEncryption", 9973 + "type": { 9974 + "name": "OBJECT IDENTIFIER", 9975 + "type": "builtin" 9976 + }, 9977 + "value": "1.2.840.113549.1.1.16" 9978 + }, 9979 + "id-sha1": { 9980 + "name": "id-sha1", 9981 + "type": { 9982 + "name": "OBJECT IDENTIFIER", 9983 + "type": "builtin" 9984 + }, 9985 + "value": "1.3.14.3.2.26" 9986 + }, 9987 + "id-md2": { 9988 + "name": "id-md2", 9989 + "type": { 9990 + "name": "OBJECT IDENTIFIER", 9991 + "type": "builtin" 9992 + }, 9993 + "value": "1.2.840.113549.2.2" 9994 + }, 9995 + "id-md5": { 9996 + "name": "id-md5", 9997 + "type": { 9998 + "name": "OBJECT IDENTIFIER", 9999 + "type": "builtin" 10000 + }, 10001 + "value": "1.2.840.113549.2.5" 10002 + }, 10003 + "id-mgf1": { 10004 + "name": "id-mgf1", 10005 + "type": { 10006 + "name": "OBJECT IDENTIFIER", 10007 + "type": "builtin" 10008 + }, 10009 + "value": "1.2.840.113549.1.1.8" 10010 + } 10011 + }, 10012 + "types": { 10013 + "AlgorithmIdentifier": { 10014 + "name": "AlgorithmIdentifier", 10015 + "type": { 10016 + "name": "ANY", 10017 + "type": "builtin" 10018 + } 10019 + }, 10020 + "HashAlgorithm": { 10021 + "name": "HashAlgorithm", 10022 + "type": { 10023 + "name": "AlgorithmIdentifier", 10024 + "type": "defined" 10025 + } 10026 + }, 10027 + "SHA1Parameters": { 10028 + "name": "SHA1Parameters", 10029 + "type": { 10030 + "name": "NULL", 10031 + "type": "builtin" 10032 + } 10033 + }, 10034 + "MaskGenAlgorithm": { 10035 + "name": "MaskGenAlgorithm", 10036 + "type": { 10037 + "name": "AlgorithmIdentifier", 10038 + "type": "defined" 10039 + } 10040 + }, 10041 + "EncodingParameters": { 10042 + "name": "EncodingParameters", 10043 + "type": { 10044 + "name": "OCTET STRING", 10045 + "type": "builtin" 10046 + } 10047 + }, 10048 + "PSourceAlgorithm": { 10049 + "name": "PSourceAlgorithm", 10050 + "type": { 10051 + "name": "AlgorithmIdentifier", 10052 + "type": "defined" 10053 + } 10054 + }, 10055 + "RSAPublicKey": { 10056 + "name": "RSAPublicKey", 10057 + "type": { 10058 + "name": "SEQUENCE", 10059 + "type": "builtin", 10060 + "content": [ 10061 + { 10062 + "id": "modulus", 10063 + "name": "INTEGER", 10064 + "type": "builtin" 10065 + }, 10066 + { 10067 + "id": "publicExponent", 10068 + "name": "INTEGER", 10069 + "type": "builtin" 10070 + } 10071 + ] 10072 + } 10073 + }, 10074 + "RSAPrivateKey": { 10075 + "name": "RSAPrivateKey", 10076 + "type": { 10077 + "name": "SEQUENCE", 10078 + "type": "builtin", 10079 + "content": [ 10080 + { 10081 + "id": "version", 10082 + "name": "Version", 10083 + "type": "defined" 10084 + }, 10085 + { 10086 + "id": "modulus", 10087 + "name": "INTEGER", 10088 + "type": "builtin" 10089 + }, 10090 + { 10091 + "id": "publicExponent", 10092 + "name": "INTEGER", 10093 + "type": "builtin" 10094 + }, 10095 + { 10096 + "id": "privateExponent", 10097 + "name": "INTEGER", 10098 + "type": "builtin" 10099 + }, 10100 + { 10101 + "id": "prime1", 10102 + "name": "INTEGER", 10103 + "type": "builtin" 10104 + }, 10105 + { 10106 + "id": "prime2", 10107 + "name": "INTEGER", 10108 + "type": "builtin" 10109 + }, 10110 + { 10111 + "id": "exponent1", 10112 + "name": "INTEGER", 10113 + "type": "builtin" 10114 + }, 10115 + { 10116 + "id": "exponent2", 10117 + "name": "INTEGER", 10118 + "type": "builtin" 10119 + }, 10120 + { 10121 + "id": "coefficient", 10122 + "name": "INTEGER", 10123 + "type": "builtin" 10124 + }, 10125 + { 10126 + "id": "otherPrimeInfos", 10127 + "name": "OtherPrimeInfos", 10128 + "type": "defined", 10129 + "optional": true 10130 + } 10131 + ] 10132 + } 10133 + }, 10134 + "Version": { 10135 + "name": "Version", 10136 + "type": { 10137 + "name": "INTEGER", 10138 + "type": "builtin", 10139 + "content": { 10140 + "two-prime": 0, 10141 + "multi": 1 10142 + } 10143 + } 10144 + }, 10145 + "OtherPrimeInfos": { 10146 + "name": "OtherPrimeInfos", 10147 + "type": { 10148 + "name": "SEQUENCE", 10149 + "type": "builtin", 10150 + "typeOf": 1, 10151 + "size": [ 10152 + 1, 10153 + "MAX" 10154 + ], 10155 + "content": [ 10156 + { 10157 + "name": "OtherPrimeInfo", 10158 + "type": "defined" 10159 + } 10160 + ] 10161 + } 10162 + }, 10163 + "OtherPrimeInfo": { 10164 + "name": "OtherPrimeInfo", 10165 + "type": { 10166 + "name": "SEQUENCE", 10167 + "type": "builtin", 10168 + "content": [ 10169 + { 10170 + "id": "prime", 10171 + "name": "INTEGER", 10172 + "type": "builtin" 10173 + }, 10174 + { 10175 + "id": "exponent", 10176 + "name": "INTEGER", 10177 + "type": "builtin" 10178 + }, 10179 + { 10180 + "id": "coefficient", 10181 + "name": "INTEGER", 10182 + "type": "builtin" 10183 + } 10184 + ] 10185 + } 10186 + }, 10187 + "RSAES-OAEP-params": { 10188 + "name": "RSAES-OAEP-params", 10189 + "type": { 10190 + "name": "SEQUENCE", 10191 + "type": "builtin", 10192 + "content": [ 10193 + { 10194 + "id": "hashAlgorithm", 10195 + "name": "[0]", 10196 + "type": "tag", 10197 + "class": "CONTEXT", 10198 + "explicit": true, 10199 + "content": [ 10200 + { 10201 + "name": "", 10202 + "type": { 10203 + "name": "HashAlgorithm", 10204 + "type": "defined" 10205 + } 10206 + } 10207 + ], 10208 + "default": "sha1" 10209 + }, 10210 + { 10211 + "id": "maskGenAlgorithm", 10212 + "name": "[1]", 10213 + "type": "tag", 10214 + "class": "CONTEXT", 10215 + "explicit": true, 10216 + "content": [ 10217 + { 10218 + "name": "", 10219 + "type": { 10220 + "name": "MaskGenAlgorithm", 10221 + "type": "defined" 10222 + } 10223 + } 10224 + ], 10225 + "default": "mgf1SHA1" 10226 + }, 10227 + { 10228 + "id": "pSourceAlgorithm", 10229 + "name": "[2]", 10230 + "type": "tag", 10231 + "class": "CONTEXT", 10232 + "explicit": true, 10233 + "content": [ 10234 + { 10235 + "name": "", 10236 + "type": { 10237 + "name": "PSourceAlgorithm", 10238 + "type": "defined" 10239 + } 10240 + } 10241 + ], 10242 + "default": "pSpecifiedEmpty" 10243 + } 10244 + ] 10245 + } 10246 + }, 10247 + "RSAES-AlgorithmIdentifier": { 10248 + "name": "RSAES-AlgorithmIdentifier", 10249 + "type": { 10250 + "name": "AlgorithmIdentifier", 10251 + "type": "defined" 10252 + } 10253 + }, 10254 + "RSASSA-PSS-params": { 10255 + "name": "RSASSA-PSS-params", 10256 + "type": { 10257 + "name": "SEQUENCE", 10258 + "type": "builtin", 10259 + "content": [ 10260 + { 10261 + "id": "hashAlgorithm", 10262 + "name": "[0]", 10263 + "type": "tag", 10264 + "class": "CONTEXT", 10265 + "explicit": true, 10266 + "content": [ 10267 + { 10268 + "name": "", 10269 + "type": { 10270 + "name": "HashAlgorithm", 10271 + "type": "defined" 10272 + } 10273 + } 10274 + ], 10275 + "default": "sha1" 10276 + }, 10277 + { 10278 + "id": "maskGenAlgorithm", 10279 + "name": "[1]", 10280 + "type": "tag", 10281 + "class": "CONTEXT", 10282 + "explicit": true, 10283 + "content": [ 10284 + { 10285 + "name": "", 10286 + "type": { 10287 + "name": "MaskGenAlgorithm", 10288 + "type": "defined" 10289 + } 10290 + } 10291 + ], 10292 + "default": "mgf1SHA1" 10293 + }, 10294 + { 10295 + "id": "saltLength", 10296 + "name": "[2]", 10297 + "type": "tag", 10298 + "class": "CONTEXT", 10299 + "explicit": true, 10300 + "content": [ 10301 + { 10302 + "name": "", 10303 + "type": { 10304 + "name": "INTEGER", 10305 + "type": "builtin" 10306 + } 10307 + } 10308 + ], 10309 + "default": 20 10310 + }, 10311 + { 10312 + "id": "trailerField", 10313 + "name": "[3]", 10314 + "type": "tag", 10315 + "class": "CONTEXT", 10316 + "explicit": true, 10317 + "content": [ 10318 + { 10319 + "name": "", 10320 + "type": { 10321 + "name": "TrailerField", 10322 + "type": "defined" 10323 + } 10324 + } 10325 + ], 10326 + "default": "trailerFieldBC" 10327 + } 10328 + ] 10329 + } 10330 + }, 10331 + "TrailerField": { 10332 + "name": "TrailerField", 10333 + "type": { 10334 + "name": "INTEGER", 10335 + "type": "builtin", 10336 + "content": { 10337 + "trailerFieldBC": 1 10338 + } 10339 + } 10340 + }, 10341 + "RSASSA-AlgorithmIdentifier": { 10342 + "name": "RSASSA-AlgorithmIdentifier", 10343 + "type": { 10344 + "name": "AlgorithmIdentifier", 10345 + "type": "defined" 10346 + } 10347 + }, 10348 + "DigestInfo": { 10349 + "name": "DigestInfo", 10350 + "type": { 10351 + "name": "SEQUENCE", 10352 + "type": "builtin", 10353 + "content": [ 10354 + { 10355 + "id": "digestAlgorithm", 10356 + "name": "DigestAlgorithm", 10357 + "type": "defined" 10358 + }, 10359 + { 10360 + "id": "digest", 10361 + "name": "OCTET STRING", 10362 + "type": "builtin" 10363 + } 10364 + ] 10365 + } 10366 + }, 10367 + "DigestAlgorithm": { 10368 + "name": "DigestAlgorithm", 10369 + "type": { 10370 + "name": "AlgorithmIdentifier", 10371 + "type": "defined" 10372 + } 10373 + } 10374 + } 10375 + }, 10376 + "1.3.6.1.1.18": { 10377 + "name": "Lightweight-Directory-Access-Protocol-V3", 10378 + "oid": "1.3.6.1.1.18", 10379 + "source": "rfc4511.txt", 10380 + "tagDefault": "IMPLICIT", 10381 + "values": { 10382 + "maxInt": { 10383 + "name": "maxInt", 10384 + "type": { 10385 + "name": "INTEGER", 10386 + "type": "builtin" 10387 + }, 10388 + "value": 2147483647 10389 + } 10390 + }, 10391 + "types": { 10392 + "LDAPMessage": { 10393 + "name": "LDAPMessage", 10394 + "type": { 10395 + "name": "SEQUENCE", 10396 + "type": "builtin", 10397 + "content": [ 10398 + { 10399 + "id": "messageID", 10400 + "name": "MessageID", 10401 + "type": "defined" 10402 + }, 10403 + { 10404 + "id": "protocolOp", 10405 + "name": "CHOICE", 10406 + "type": "builtin", 10407 + "content": [ 10408 + { 10409 + "id": "bindRequest", 10410 + "name": "BindRequest", 10411 + "type": "defined" 10412 + }, 10413 + { 10414 + "id": "bindResponse", 10415 + "name": "BindResponse", 10416 + "type": "defined" 10417 + }, 10418 + { 10419 + "id": "unbindRequest", 10420 + "name": "UnbindRequest", 10421 + "type": "defined" 10422 + }, 10423 + { 10424 + "id": "searchRequest", 10425 + "name": "SearchRequest", 10426 + "type": "defined" 10427 + }, 10428 + { 10429 + "id": "searchResEntry", 10430 + "name": "SearchResultEntry", 10431 + "type": "defined" 10432 + }, 10433 + { 10434 + "id": "searchResDone", 10435 + "name": "SearchResultDone", 10436 + "type": "defined" 10437 + }, 10438 + { 10439 + "id": "searchResRef", 10440 + "name": "SearchResultReference", 10441 + "type": "defined" 10442 + }, 10443 + { 10444 + "id": "modifyRequest", 10445 + "name": "ModifyRequest", 10446 + "type": "defined" 10447 + }, 10448 + { 10449 + "id": "modifyResponse", 10450 + "name": "ModifyResponse", 10451 + "type": "defined" 10452 + }, 10453 + { 10454 + "id": "addRequest", 10455 + "name": "AddRequest", 10456 + "type": "defined" 10457 + }, 10458 + { 10459 + "id": "addResponse", 10460 + "name": "AddResponse", 10461 + "type": "defined" 10462 + }, 10463 + { 10464 + "id": "delRequest", 10465 + "name": "DelRequest", 10466 + "type": "defined" 10467 + }, 10468 + { 10469 + "id": "delResponse", 10470 + "name": "DelResponse", 10471 + "type": "defined" 10472 + }, 10473 + { 10474 + "id": "modDNRequest", 10475 + "name": "ModifyDNRequest", 10476 + "type": "defined" 10477 + }, 10478 + { 10479 + "id": "modDNResponse", 10480 + "name": "ModifyDNResponse", 10481 + "type": "defined" 10482 + }, 10483 + { 10484 + "id": "compareRequest", 10485 + "name": "CompareRequest", 10486 + "type": "defined" 10487 + }, 10488 + { 10489 + "id": "compareResponse", 10490 + "name": "CompareResponse", 10491 + "type": "defined" 10492 + }, 10493 + { 10494 + "id": "abandonRequest", 10495 + "name": "AbandonRequest", 10496 + "type": "defined" 10497 + }, 10498 + { 10499 + "id": "extendedReq", 10500 + "name": "ExtendedRequest", 10501 + "type": "defined" 10502 + }, 10503 + { 10504 + "id": "extendedResp", 10505 + "name": "ExtendedResponse", 10506 + "type": "defined" 10507 + }, 10508 + { 10509 + "id": "intermediateResponse", 10510 + "name": "IntermediateResponse", 10511 + "type": "defined" 10512 + } 10513 + ] 10514 + }, 10515 + { 10516 + "id": "controls", 10517 + "name": "[0]", 10518 + "type": "tag", 10519 + "class": "CONTEXT", 10520 + "explicit": false, 10521 + "content": [ 10522 + { 10523 + "name": "", 10524 + "type": { 10525 + "name": "Controls", 10526 + "type": "defined" 10527 + } 10528 + } 10529 + ], 10530 + "optional": true 10531 + } 10532 + ] 10533 + } 10534 + }, 10535 + "MessageID": { 10536 + "name": "MessageID", 10537 + "type": { 10538 + "name": "INTEGER", 10539 + "type": "builtin", 10540 + "range": [ 10541 + 0, 10542 + "maxInt" 10543 + ] 10544 + } 10545 + }, 10546 + "LDAPString": { 10547 + "name": "LDAPString", 10548 + "type": { 10549 + "name": "OCTET STRING", 10550 + "type": "builtin" 10551 + } 10552 + }, 10553 + "LDAPOID": { 10554 + "name": "LDAPOID", 10555 + "type": { 10556 + "name": "OCTET STRING", 10557 + "type": "builtin" 10558 + } 10559 + }, 10560 + "LDAPDN": { 10561 + "name": "LDAPDN", 10562 + "type": { 10563 + "name": "LDAPString", 10564 + "type": "defined" 10565 + } 10566 + }, 10567 + "RelativeLDAPDN": { 10568 + "name": "RelativeLDAPDN", 10569 + "type": { 10570 + "name": "LDAPString", 10571 + "type": "defined" 10572 + } 10573 + }, 10574 + "AttributeDescription": { 10575 + "name": "AttributeDescription", 10576 + "type": { 10577 + "name": "LDAPString", 10578 + "type": "defined" 10579 + } 10580 + }, 10581 + "AttributeValue": { 10582 + "name": "AttributeValue", 10583 + "type": { 10584 + "name": "OCTET STRING", 10585 + "type": "builtin" 10586 + } 10587 + }, 10588 + "AttributeValueAssertion": { 10589 + "name": "AttributeValueAssertion", 10590 + "type": { 10591 + "name": "SEQUENCE", 10592 + "type": "builtin", 10593 + "content": [ 10594 + { 10595 + "id": "attributeDesc", 10596 + "name": "AttributeDescription", 10597 + "type": "defined" 10598 + }, 10599 + { 10600 + "id": "assertionValue", 10601 + "name": "AssertionValue", 10602 + "type": "defined" 10603 + } 10604 + ] 10605 + } 10606 + }, 10607 + "AssertionValue": { 10608 + "name": "AssertionValue", 10609 + "type": { 10610 + "name": "OCTET STRING", 10611 + "type": "builtin" 10612 + } 10613 + }, 10614 + "PartialAttribute": { 10615 + "name": "PartialAttribute", 10616 + "type": { 10617 + "name": "SEQUENCE", 10618 + "type": "builtin", 10619 + "content": [ 10620 + { 10621 + "id": "type", 10622 + "name": "AttributeDescription", 10623 + "type": "defined" 10624 + }, 10625 + { 10626 + "id": "vals", 10627 + "name": "SET", 10628 + "type": "builtin", 10629 + "typeOf": 1, 10630 + "size": [ 10631 + 1, 10632 + "MAX" 10633 + ], 10634 + "content": [ 10635 + { 10636 + "name": "AttributeValue", 10637 + "type": "defined" 10638 + } 10639 + ] 10640 + } 10641 + ] 10642 + } 10643 + }, 10644 + "MatchingRuleId": { 10645 + "name": "MatchingRuleId", 10646 + "type": { 10647 + "name": "LDAPString", 10648 + "type": "defined" 10649 + } 10650 + }, 10651 + "LDAPResult": { 10652 + "name": "LDAPResult", 10653 + "type": { 10654 + "name": "SEQUENCE", 10655 + "type": "builtin", 10656 + "content": [ 10657 + { 10658 + "id": "resultCode", 10659 + "name": "ENUMERATED", 10660 + "type": "builtin", 10661 + "content": { 10662 + "success": 0, 10663 + "operationsError": 1, 10664 + "protocolError": 2, 10665 + "timeLimitExceeded": 3, 10666 + "sizeLimitExceeded": 4, 10667 + "compareFalse": 5, 10668 + "compareTrue": 6, 10669 + "authMethodNotSupported": 7, 10670 + "strongerAuthRequired": 8, 10671 + "referral": 10, 10672 + "adminLimitExceeded": 11, 10673 + "unavailableCriticalExtension": 12, 10674 + "confidentialityRequired": 13, 10675 + "saslBindInProgress": 14, 10676 + "noSuchAttribute": 16, 10677 + "undefinedAttributeType": 17, 10678 + "inappropriateMatching": 18, 10679 + "constraintViolation": 19, 10680 + "attributeOrValueExists": 20, 10681 + "invalidAttributeSyntax": 21, 10682 + "noSuchObject": 32, 10683 + "aliasProblem": 33, 10684 + "invalidDNSyntax": 34, 10685 + "aliasDereferencingProblem": 36, 10686 + "inappropriateAuthentication": 48, 10687 + "invalidCredentials": 49, 10688 + "insufficientAccessRights": 50, 10689 + "busy": 51, 10690 + "unavailable": 52, 10691 + "unwillingToPerform": 53, 10692 + "loopDetect": 54, 10693 + "namingViolation": 64, 10694 + "objectClassViolation": 65, 10695 + "notAllowedOnNonLeaf": 66, 10696 + "notAllowedOnRDN": 67, 10697 + "entryAlreadyExists": 68, 10698 + "objectClassModsProhibited": 69, 10699 + "affectsMultipleDSAs": 71, 10700 + "other": 80 10701 + } 10702 + }, 10703 + { 10704 + "id": "matchedDN", 10705 + "name": "LDAPDN", 10706 + "type": "defined" 10707 + }, 10708 + { 10709 + "id": "diagnosticMessage", 10710 + "name": "LDAPString", 10711 + "type": "defined" 10712 + }, 10713 + { 10714 + "id": "referral", 10715 + "name": "[3]", 10716 + "type": "tag", 10717 + "class": "CONTEXT", 10718 + "explicit": false, 10719 + "content": [ 10720 + { 10721 + "name": "", 10722 + "type": { 10723 + "name": "Referral", 10724 + "type": "defined" 10725 + } 10726 + } 10727 + ], 10728 + "optional": true 10729 + } 10730 + ] 10731 + } 10732 + }, 10733 + "Referral": { 10734 + "name": "Referral", 10735 + "type": { 10736 + "name": "SEQUENCE", 10737 + "type": "builtin", 10738 + "typeOf": 1, 10739 + "size": [ 10740 + 1, 10741 + "MAX" 10742 + ], 10743 + "content": [ 10744 + { 10745 + "name": "URI", 10746 + "type": "defined" 10747 + } 10748 + ] 10749 + } 10750 + }, 10751 + "URI": { 10752 + "name": "URI", 10753 + "type": { 10754 + "name": "LDAPString", 10755 + "type": "defined" 10756 + } 10757 + }, 10758 + "Controls": { 10759 + "name": "Controls", 10760 + "type": { 10761 + "name": "SEQUENCE", 10762 + "type": "builtin", 10763 + "typeOf": 1, 10764 + "content": [ 10765 + { 10766 + "name": "Control", 10767 + "type": "defined" 10768 + } 10769 + ] 10770 + } 10771 + }, 10772 + "Control": { 10773 + "name": "Control", 10774 + "type": { 10775 + "name": "SEQUENCE", 10776 + "type": "builtin", 10777 + "content": [ 10778 + { 10779 + "id": "controlType", 10780 + "name": "LDAPOID", 10781 + "type": "defined" 10782 + }, 10783 + { 10784 + "id": "criticality", 10785 + "name": "BOOLEAN", 10786 + "type": "builtin", 10787 + "default": false 10788 + }, 10789 + { 10790 + "id": "controlValue", 10791 + "name": "OCTET STRING", 10792 + "type": "builtin", 10793 + "optional": true 10794 + } 10795 + ] 10796 + } 10797 + }, 10798 + "BindRequest": { 10799 + "name": "BindRequest", 10800 + "type": { 10801 + "name": "Application 0", 10802 + "type": "tag", 10803 + "class": "APPLICATION", 10804 + "explicit": false, 10805 + "content": [ 10806 + { 10807 + "name": "", 10808 + "type": { 10809 + "name": "SEQUENCE", 10810 + "type": "builtin", 10811 + "content": [ 10812 + { 10813 + "id": "version", 10814 + "name": "INTEGER", 10815 + "type": "builtin", 10816 + "range": [ 10817 + 1, 10818 + 127 10819 + ] 10820 + }, 10821 + { 10822 + "id": "name", 10823 + "name": "LDAPDN", 10824 + "type": "defined" 10825 + }, 10826 + { 10827 + "id": "authentication", 10828 + "name": "AuthenticationChoice", 10829 + "type": "defined" 10830 + } 10831 + ] 10832 + } 10833 + } 10834 + ] 10835 + } 10836 + }, 10837 + "AuthenticationChoice": { 10838 + "name": "AuthenticationChoice", 10839 + "type": { 10840 + "name": "CHOICE", 10841 + "type": "builtin", 10842 + "content": [ 10843 + { 10844 + "id": "simple", 10845 + "name": "[0]", 10846 + "type": "tag", 10847 + "class": "CONTEXT", 10848 + "explicit": false, 10849 + "content": [ 10850 + { 10851 + "name": "", 10852 + "type": { 10853 + "name": "OCTET STRING", 10854 + "type": "builtin" 10855 + } 10856 + } 10857 + ] 10858 + }, 10859 + { 10860 + "id": "sasl", 10861 + "name": "[3]", 10862 + "type": "tag", 10863 + "class": "CONTEXT", 10864 + "explicit": false, 10865 + "content": [ 10866 + { 10867 + "name": "", 10868 + "type": { 10869 + "name": "SaslCredentials", 10870 + "type": "defined" 10871 + } 10872 + } 10873 + ] 10874 + } 10875 + ] 10876 + } 10877 + }, 10878 + "SaslCredentials": { 10879 + "name": "SaslCredentials", 10880 + "type": { 10881 + "name": "SEQUENCE", 10882 + "type": "builtin", 10883 + "content": [ 10884 + { 10885 + "id": "mechanism", 10886 + "name": "LDAPString", 10887 + "type": "defined" 10888 + }, 10889 + { 10890 + "id": "credentials", 10891 + "name": "OCTET STRING", 10892 + "type": "builtin", 10893 + "optional": true 10894 + } 10895 + ] 10896 + } 10897 + }, 10898 + "BindResponse": { 10899 + "name": "BindResponse", 10900 + "type": { 10901 + "name": "ANY", 10902 + "type": "builtin" 10903 + } 10904 + }, 10905 + "UnbindRequest": { 10906 + "name": "UnbindRequest", 10907 + "type": { 10908 + "name": "Application 2", 10909 + "type": "tag", 10910 + "class": "APPLICATION", 10911 + "explicit": false, 10912 + "content": [ 10913 + { 10914 + "name": "", 10915 + "type": { 10916 + "name": "NULL", 10917 + "type": "builtin" 10918 + } 10919 + } 10920 + ] 10921 + } 10922 + }, 10923 + "SearchRequest": { 10924 + "name": "SearchRequest", 10925 + "type": { 10926 + "name": "Application 3", 10927 + "type": "tag", 10928 + "class": "APPLICATION", 10929 + "explicit": false, 10930 + "content": [ 10931 + { 10932 + "name": "", 10933 + "type": { 10934 + "name": "SEQUENCE", 10935 + "type": "builtin", 10936 + "content": [ 10937 + { 10938 + "id": "baseObject", 10939 + "name": "LDAPDN", 10940 + "type": "defined" 10941 + }, 10942 + { 10943 + "id": "scope", 10944 + "name": "ENUMERATED", 10945 + "type": "builtin", 10946 + "content": { 10947 + "baseObject": 0, 10948 + "singleLevel": 1, 10949 + "wholeSubtree": 2 10950 + } 10951 + }, 10952 + { 10953 + "id": "derefAliases", 10954 + "name": "ENUMERATED", 10955 + "type": "builtin", 10956 + "content": { 10957 + "neverDerefAliases": 0, 10958 + "derefInSearching": 1, 10959 + "derefFindingBaseObj": 2, 10960 + "derefAlways": 3 10961 + } 10962 + }, 10963 + { 10964 + "id": "sizeLimit", 10965 + "name": "INTEGER", 10966 + "type": "builtin", 10967 + "range": [ 10968 + 0, 10969 + "maxInt" 10970 + ] 10971 + }, 10972 + { 10973 + "id": "timeLimit", 10974 + "name": "INTEGER", 10975 + "type": "builtin", 10976 + "range": [ 10977 + 0, 10978 + "maxInt" 10979 + ] 10980 + }, 10981 + { 10982 + "id": "typesOnly", 10983 + "name": "BOOLEAN", 10984 + "type": "builtin" 10985 + }, 10986 + { 10987 + "id": "filter", 10988 + "name": "Filter", 10989 + "type": "defined" 10990 + }, 10991 + { 10992 + "id": "attributes", 10993 + "name": "AttributeSelection", 10994 + "type": "defined" 10995 + } 10996 + ] 10997 + } 10998 + } 10999 + ] 11000 + } 11001 + }, 11002 + "AttributeSelection": { 11003 + "name": "AttributeSelection", 11004 + "type": { 11005 + "name": "SEQUENCE", 11006 + "type": "builtin", 11007 + "typeOf": 1, 11008 + "content": [ 11009 + { 11010 + "name": "LDAPString", 11011 + "type": "defined" 11012 + } 11013 + ] 11014 + } 11015 + }, 11016 + "Filter": { 11017 + "name": "Filter", 11018 + "type": { 11019 + "name": "CHOICE", 11020 + "type": "builtin", 11021 + "content": [ 11022 + { 11023 + "id": "and", 11024 + "name": "[0]", 11025 + "type": "tag", 11026 + "class": "CONTEXT", 11027 + "explicit": false, 11028 + "content": [ 11029 + { 11030 + "name": "", 11031 + "type": { 11032 + "name": "SET", 11033 + "type": "builtin", 11034 + "typeOf": 1, 11035 + "size": [ 11036 + 1, 11037 + "MAX" 11038 + ], 11039 + "content": [ 11040 + { 11041 + "name": "Filter", 11042 + "type": "defined" 11043 + } 11044 + ] 11045 + } 11046 + } 11047 + ] 11048 + }, 11049 + { 11050 + "id": "or", 11051 + "name": "[1]", 11052 + "type": "tag", 11053 + "class": "CONTEXT", 11054 + "explicit": false, 11055 + "content": [ 11056 + { 11057 + "name": "", 11058 + "type": { 11059 + "name": "SET", 11060 + "type": "builtin", 11061 + "typeOf": 1, 11062 + "size": [ 11063 + 1, 11064 + "MAX" 11065 + ], 11066 + "content": [ 11067 + { 11068 + "name": "Filter", 11069 + "type": "defined" 11070 + } 11071 + ] 11072 + } 11073 + } 11074 + ] 11075 + }, 11076 + { 11077 + "id": "not", 11078 + "name": "[2]", 11079 + "type": "tag", 11080 + "class": "CONTEXT", 11081 + "explicit": false, 11082 + "content": [ 11083 + { 11084 + "name": "", 11085 + "type": { 11086 + "name": "Filter", 11087 + "type": "defined" 11088 + } 11089 + } 11090 + ] 11091 + }, 11092 + { 11093 + "id": "equalityMatch", 11094 + "name": "[3]", 11095 + "type": "tag", 11096 + "class": "CONTEXT", 11097 + "explicit": false, 11098 + "content": [ 11099 + { 11100 + "name": "", 11101 + "type": { 11102 + "name": "AttributeValueAssertion", 11103 + "type": "defined" 11104 + } 11105 + } 11106 + ] 11107 + }, 11108 + { 11109 + "id": "substrings", 11110 + "name": "[4]", 11111 + "type": "tag", 11112 + "class": "CONTEXT", 11113 + "explicit": false, 11114 + "content": [ 11115 + { 11116 + "name": "", 11117 + "type": { 11118 + "name": "SubstringFilter", 11119 + "type": "defined" 11120 + } 11121 + } 11122 + ] 11123 + }, 11124 + { 11125 + "id": "greaterOrEqual", 11126 + "name": "[5]", 11127 + "type": "tag", 11128 + "class": "CONTEXT", 11129 + "explicit": false, 11130 + "content": [ 11131 + { 11132 + "name": "", 11133 + "type": { 11134 + "name": "AttributeValueAssertion", 11135 + "type": "defined" 11136 + } 11137 + } 11138 + ] 11139 + }, 11140 + { 11141 + "id": "lessOrEqual", 11142 + "name": "[6]", 11143 + "type": "tag", 11144 + "class": "CONTEXT", 11145 + "explicit": false, 11146 + "content": [ 11147 + { 11148 + "name": "", 11149 + "type": { 11150 + "name": "AttributeValueAssertion", 11151 + "type": "defined" 11152 + } 11153 + } 11154 + ] 11155 + }, 11156 + { 11157 + "id": "present", 11158 + "name": "[7]", 11159 + "type": "tag", 11160 + "class": "CONTEXT", 11161 + "explicit": false, 11162 + "content": [ 11163 + { 11164 + "name": "", 11165 + "type": { 11166 + "name": "AttributeDescription", 11167 + "type": "defined" 11168 + } 11169 + } 11170 + ] 11171 + }, 11172 + { 11173 + "id": "approxMatch", 11174 + "name": "[8]", 11175 + "type": "tag", 11176 + "class": "CONTEXT", 11177 + "explicit": false, 11178 + "content": [ 11179 + { 11180 + "name": "", 11181 + "type": { 11182 + "name": "AttributeValueAssertion", 11183 + "type": "defined" 11184 + } 11185 + } 11186 + ] 11187 + }, 11188 + { 11189 + "id": "extensibleMatch", 11190 + "name": "[9]", 11191 + "type": "tag", 11192 + "class": "CONTEXT", 11193 + "explicit": false, 11194 + "content": [ 11195 + { 11196 + "name": "", 11197 + "type": { 11198 + "name": "MatchingRuleAssertion", 11199 + "type": "defined" 11200 + } 11201 + } 11202 + ] 11203 + } 11204 + ] 11205 + } 11206 + }, 11207 + "SubstringFilter": { 11208 + "name": "SubstringFilter", 11209 + "type": { 11210 + "name": "SEQUENCE", 11211 + "type": "builtin", 11212 + "content": [ 11213 + { 11214 + "id": "type", 11215 + "name": "AttributeDescription", 11216 + "type": "defined" 11217 + }, 11218 + { 11219 + "id": "substrings", 11220 + "name": "SEQUENCE", 11221 + "type": "builtin", 11222 + "typeOf": 1, 11223 + "size": [ 11224 + 1, 11225 + "MAX" 11226 + ], 11227 + "content": [ 11228 + { 11229 + "name": "CHOICE", 11230 + "type": "builtin", 11231 + "content": [ 11232 + { 11233 + "id": "initial", 11234 + "name": "[0]", 11235 + "type": "tag", 11236 + "class": "CONTEXT", 11237 + "explicit": false, 11238 + "content": [ 11239 + { 11240 + "name": "", 11241 + "type": { 11242 + "name": "AssertionValue", 11243 + "type": "defined" 11244 + } 11245 + } 11246 + ] 11247 + }, 11248 + { 11249 + "id": "any", 11250 + "name": "[1]", 11251 + "type": "tag", 11252 + "class": "CONTEXT", 11253 + "explicit": false, 11254 + "content": [ 11255 + { 11256 + "name": "", 11257 + "type": { 11258 + "name": "AssertionValue", 11259 + "type": "defined" 11260 + } 11261 + } 11262 + ] 11263 + }, 11264 + { 11265 + "id": "final", 11266 + "name": "[2]", 11267 + "type": "tag", 11268 + "class": "CONTEXT", 11269 + "explicit": false, 11270 + "content": [ 11271 + { 11272 + "name": "", 11273 + "type": { 11274 + "name": "AssertionValue", 11275 + "type": "defined" 11276 + } 11277 + } 11278 + ] 11279 + } 11280 + ] 11281 + } 11282 + ] 11283 + } 11284 + ] 11285 + } 11286 + }, 11287 + "MatchingRuleAssertion": { 11288 + "name": "MatchingRuleAssertion", 11289 + "type": { 11290 + "name": "SEQUENCE", 11291 + "type": "builtin", 11292 + "content": [ 11293 + { 11294 + "id": "matchingRule", 11295 + "name": "[1]", 11296 + "type": "tag", 11297 + "class": "CONTEXT", 11298 + "explicit": false, 11299 + "content": [ 11300 + { 11301 + "name": "", 11302 + "type": { 11303 + "name": "MatchingRuleId", 11304 + "type": "defined" 11305 + } 11306 + } 11307 + ], 11308 + "optional": true 11309 + }, 11310 + { 11311 + "id": "type", 11312 + "name": "[2]", 11313 + "type": "tag", 11314 + "class": "CONTEXT", 11315 + "explicit": false, 11316 + "content": [ 11317 + { 11318 + "name": "", 11319 + "type": { 11320 + "name": "AttributeDescription", 11321 + "type": "defined" 11322 + } 11323 + } 11324 + ], 11325 + "optional": true 11326 + }, 11327 + { 11328 + "id": "matchValue", 11329 + "name": "[3]", 11330 + "type": "tag", 11331 + "class": "CONTEXT", 11332 + "explicit": false, 11333 + "content": [ 11334 + { 11335 + "name": "", 11336 + "type": { 11337 + "name": "AssertionValue", 11338 + "type": "defined" 11339 + } 11340 + } 11341 + ] 11342 + }, 11343 + { 11344 + "id": "dnAttributes", 11345 + "name": "[4]", 11346 + "type": "tag", 11347 + "class": "CONTEXT", 11348 + "explicit": false, 11349 + "content": [ 11350 + { 11351 + "name": "", 11352 + "type": { 11353 + "name": "BOOLEAN", 11354 + "type": "builtin" 11355 + } 11356 + } 11357 + ], 11358 + "default": false 11359 + } 11360 + ] 11361 + } 11362 + }, 11363 + "SearchResultEntry": { 11364 + "name": "SearchResultEntry", 11365 + "type": { 11366 + "name": "Application 4", 11367 + "type": "tag", 11368 + "class": "APPLICATION", 11369 + "explicit": false, 11370 + "content": [ 11371 + { 11372 + "name": "", 11373 + "type": { 11374 + "name": "SEQUENCE", 11375 + "type": "builtin", 11376 + "content": [ 11377 + { 11378 + "id": "objectName", 11379 + "name": "LDAPDN", 11380 + "type": "defined" 11381 + }, 11382 + { 11383 + "id": "attributes", 11384 + "name": "PartialAttributeList", 11385 + "type": "defined" 11386 + } 11387 + ] 11388 + } 11389 + } 11390 + ] 11391 + } 11392 + }, 11393 + "PartialAttributeList": { 11394 + "name": "PartialAttributeList", 11395 + "type": { 11396 + "name": "SEQUENCE", 11397 + "type": "builtin", 11398 + "typeOf": 1, 11399 + "content": [ 11400 + { 11401 + "name": "PartialAttribute", 11402 + "type": "defined" 11403 + } 11404 + ] 11405 + } 11406 + }, 11407 + "SearchResultReference": { 11408 + "name": "SearchResultReference", 11409 + "type": { 11410 + "name": "Application 19", 11411 + "type": "tag", 11412 + "class": "APPLICATION", 11413 + "explicit": false, 11414 + "content": [ 11415 + { 11416 + "name": "", 11417 + "type": { 11418 + "name": "SEQUENCE", 11419 + "type": "builtin", 11420 + "typeOf": 1, 11421 + "size": [ 11422 + 1, 11423 + "MAX" 11424 + ], 11425 + "content": [ 11426 + { 11427 + "name": "URI", 11428 + "type": "defined" 11429 + } 11430 + ] 11431 + } 11432 + } 11433 + ] 11434 + } 11435 + }, 11436 + "SearchResultDone": { 11437 + "name": "SearchResultDone", 11438 + "type": { 11439 + "name": "Application 5", 11440 + "type": "tag", 11441 + "class": "APPLICATION", 11442 + "explicit": false, 11443 + "content": [ 11444 + { 11445 + "name": "", 11446 + "type": { 11447 + "name": "LDAPResult", 11448 + "type": "defined" 11449 + } 11450 + } 11451 + ] 11452 + } 11453 + }, 11454 + "ModifyRequest": { 11455 + "name": "ModifyRequest", 11456 + "type": { 11457 + "name": "Application 6", 11458 + "type": "tag", 11459 + "class": "APPLICATION", 11460 + "explicit": false, 11461 + "content": [ 11462 + { 11463 + "name": "", 11464 + "type": { 11465 + "name": "SEQUENCE", 11466 + "type": "builtin", 11467 + "content": [ 11468 + { 11469 + "id": "object", 11470 + "name": "LDAPDN", 11471 + "type": "defined" 11472 + }, 11473 + { 11474 + "id": "changes", 11475 + "name": "SEQUENCE", 11476 + "type": "builtin", 11477 + "typeOf": 1, 11478 + "content": [ 11479 + { 11480 + "name": "SEQUENCE", 11481 + "type": "builtin", 11482 + "content": [ 11483 + { 11484 + "id": "operation", 11485 + "name": "ENUMERATED", 11486 + "type": "builtin", 11487 + "content": { 11488 + "add": 0, 11489 + "delete": 1, 11490 + "replace": 2 11491 + } 11492 + }, 11493 + { 11494 + "id": "modification", 11495 + "name": "PartialAttribute", 11496 + "type": "defined" 11497 + } 11498 + ] 11499 + } 11500 + ] 11501 + } 11502 + ] 11503 + } 11504 + } 11505 + ] 11506 + } 11507 + }, 11508 + "ModifyResponse": { 11509 + "name": "ModifyResponse", 11510 + "type": { 11511 + "name": "Application 7", 11512 + "type": "tag", 11513 + "class": "APPLICATION", 11514 + "explicit": false, 11515 + "content": [ 11516 + { 11517 + "name": "", 11518 + "type": { 11519 + "name": "LDAPResult", 11520 + "type": "defined" 11521 + } 11522 + } 11523 + ] 11524 + } 11525 + }, 11526 + "AddRequest": { 11527 + "name": "AddRequest", 11528 + "type": { 11529 + "name": "Application 8", 11530 + "type": "tag", 11531 + "class": "APPLICATION", 11532 + "explicit": false, 11533 + "content": [ 11534 + { 11535 + "name": "", 11536 + "type": { 11537 + "name": "SEQUENCE", 11538 + "type": "builtin", 11539 + "content": [ 11540 + { 11541 + "id": "entry", 11542 + "name": "LDAPDN", 11543 + "type": "defined" 11544 + }, 11545 + { 11546 + "id": "attributes", 11547 + "name": "AttributeList", 11548 + "type": "defined" 11549 + } 11550 + ] 11551 + } 11552 + } 11553 + ] 11554 + } 11555 + }, 11556 + "AttributeList": { 11557 + "name": "AttributeList", 11558 + "type": { 11559 + "name": "SEQUENCE", 11560 + "type": "builtin", 11561 + "typeOf": 1, 11562 + "content": [ 11563 + { 11564 + "name": "Attribute", 11565 + "type": "defined" 11566 + } 11567 + ] 11568 + } 11569 + }, 11570 + "AddResponse": { 11571 + "name": "AddResponse", 11572 + "type": { 11573 + "name": "Application 9", 11574 + "type": "tag", 11575 + "class": "APPLICATION", 11576 + "explicit": false, 11577 + "content": [ 11578 + { 11579 + "name": "", 11580 + "type": { 11581 + "name": "LDAPResult", 11582 + "type": "defined" 11583 + } 11584 + } 11585 + ] 11586 + } 11587 + }, 11588 + "DelRequest": { 11589 + "name": "DelRequest", 11590 + "type": { 11591 + "name": "Application 10", 11592 + "type": "tag", 11593 + "class": "APPLICATION", 11594 + "explicit": false, 11595 + "content": [ 11596 + { 11597 + "name": "", 11598 + "type": { 11599 + "name": "LDAPDN", 11600 + "type": "defined" 11601 + } 11602 + } 11603 + ] 11604 + } 11605 + }, 11606 + "DelResponse": { 11607 + "name": "DelResponse", 11608 + "type": { 11609 + "name": "Application 11", 11610 + "type": "tag", 11611 + "class": "APPLICATION", 11612 + "explicit": false, 11613 + "content": [ 11614 + { 11615 + "name": "", 11616 + "type": { 11617 + "name": "LDAPResult", 11618 + "type": "defined" 11619 + } 11620 + } 11621 + ] 11622 + } 11623 + }, 11624 + "ModifyDNRequest": { 11625 + "name": "ModifyDNRequest", 11626 + "type": { 11627 + "name": "Application 12", 11628 + "type": "tag", 11629 + "class": "APPLICATION", 11630 + "explicit": false, 11631 + "content": [ 11632 + { 11633 + "name": "", 11634 + "type": { 11635 + "name": "SEQUENCE", 11636 + "type": "builtin", 11637 + "content": [ 11638 + { 11639 + "id": "entry", 11640 + "name": "LDAPDN", 11641 + "type": "defined" 11642 + }, 11643 + { 11644 + "id": "newrdn", 11645 + "name": "RelativeLDAPDN", 11646 + "type": "defined" 11647 + }, 11648 + { 11649 + "id": "deleteoldrdn", 11650 + "name": "BOOLEAN", 11651 + "type": "builtin" 11652 + }, 11653 + { 11654 + "id": "newSuperior", 11655 + "name": "[0]", 11656 + "type": "tag", 11657 + "class": "CONTEXT", 11658 + "explicit": false, 11659 + "content": [ 11660 + { 11661 + "name": "", 11662 + "type": { 11663 + "name": "LDAPDN", 11664 + "type": "defined" 11665 + } 11666 + } 11667 + ], 11668 + "optional": true 11669 + } 11670 + ] 11671 + } 11672 + } 11673 + ] 11674 + } 11675 + }, 11676 + "ModifyDNResponse": { 11677 + "name": "ModifyDNResponse", 11678 + "type": { 11679 + "name": "Application 13", 11680 + "type": "tag", 11681 + "class": "APPLICATION", 11682 + "explicit": false, 11683 + "content": [ 11684 + { 11685 + "name": "", 11686 + "type": { 11687 + "name": "LDAPResult", 11688 + "type": "defined" 11689 + } 11690 + } 11691 + ] 11692 + } 11693 + }, 11694 + "CompareRequest": { 11695 + "name": "CompareRequest", 11696 + "type": { 11697 + "name": "Application 14", 11698 + "type": "tag", 11699 + "class": "APPLICATION", 11700 + "explicit": false, 11701 + "content": [ 11702 + { 11703 + "name": "", 11704 + "type": { 11705 + "name": "SEQUENCE", 11706 + "type": "builtin", 11707 + "content": [ 11708 + { 11709 + "id": "entry", 11710 + "name": "LDAPDN", 11711 + "type": "defined" 11712 + }, 11713 + { 11714 + "id": "ava", 11715 + "name": "AttributeValueAssertion", 11716 + "type": "defined" 11717 + } 11718 + ] 11719 + } 11720 + } 11721 + ] 11722 + } 11723 + }, 11724 + "CompareResponse": { 11725 + "name": "CompareResponse", 11726 + "type": { 11727 + "name": "Application 15", 11728 + "type": "tag", 11729 + "class": "APPLICATION", 11730 + "explicit": false, 11731 + "content": [ 11732 + { 11733 + "name": "", 11734 + "type": { 11735 + "name": "LDAPResult", 11736 + "type": "defined" 11737 + } 11738 + } 11739 + ] 11740 + } 11741 + }, 11742 + "AbandonRequest": { 11743 + "name": "AbandonRequest", 11744 + "type": { 11745 + "name": "Application 16", 11746 + "type": "tag", 11747 + "class": "APPLICATION", 11748 + "explicit": false, 11749 + "content": [ 11750 + { 11751 + "name": "", 11752 + "type": { 11753 + "name": "MessageID", 11754 + "type": "defined" 11755 + } 11756 + } 11757 + ] 11758 + } 11759 + }, 11760 + "ExtendedRequest": { 11761 + "name": "ExtendedRequest", 11762 + "type": { 11763 + "name": "Application 23", 11764 + "type": "tag", 11765 + "class": "APPLICATION", 11766 + "explicit": false, 11767 + "content": [ 11768 + { 11769 + "name": "", 11770 + "type": { 11771 + "name": "SEQUENCE", 11772 + "type": "builtin", 11773 + "content": [ 11774 + { 11775 + "id": "requestName", 11776 + "name": "[0]", 11777 + "type": "tag", 11778 + "class": "CONTEXT", 11779 + "explicit": false, 11780 + "content": [ 11781 + { 11782 + "name": "", 11783 + "type": { 11784 + "name": "LDAPOID", 11785 + "type": "defined" 11786 + } 11787 + } 11788 + ] 11789 + }, 11790 + { 11791 + "id": "requestValue", 11792 + "name": "[1]", 11793 + "type": "tag", 11794 + "class": "CONTEXT", 11795 + "explicit": false, 11796 + "content": [ 11797 + { 11798 + "name": "", 11799 + "type": { 11800 + "name": "OCTET STRING", 11801 + "type": "builtin" 11802 + } 11803 + } 11804 + ], 11805 + "optional": true 11806 + } 11807 + ] 11808 + } 11809 + } 11810 + ] 11811 + } 11812 + }, 11813 + "ExtendedResponse": { 11814 + "name": "ExtendedResponse", 11815 + "type": { 11816 + "name": "ANY", 11817 + "type": "builtin" 11818 + } 11819 + }, 11820 + "IntermediateResponse": { 11821 + "name": "IntermediateResponse", 11822 + "type": { 11823 + "name": "Application 25", 11824 + "type": "tag", 11825 + "class": "APPLICATION", 11826 + "explicit": false, 11827 + "content": [ 11828 + { 11829 + "name": "", 11830 + "type": { 11831 + "name": "SEQUENCE", 11832 + "type": "builtin", 11833 + "content": [ 11834 + { 11835 + "id": "responseName", 11836 + "name": "[0]", 11837 + "type": "tag", 11838 + "class": "CONTEXT", 11839 + "explicit": false, 11840 + "content": [ 11841 + { 11842 + "name": "", 11843 + "type": { 11844 + "name": "LDAPOID", 11845 + "type": "defined" 11846 + } 11847 + } 11848 + ], 11849 + "optional": true 11850 + }, 11851 + { 11852 + "id": "responseValue", 11853 + "name": "[1]", 11854 + "type": "tag", 11855 + "class": "CONTEXT", 11856 + "explicit": false, 11857 + "content": [ 11858 + { 11859 + "name": "", 11860 + "type": { 11861 + "name": "OCTET STRING", 11862 + "type": "builtin" 11863 + } 11864 + } 11865 + ], 11866 + "optional": true 11867 + } 11868 + ] 11869 + } 9854 11870 } 9855 11871 ] 9856 11872 }
+16 -9
tags.js
··· 1 1 export const tags = { 2 - "1.2.4":"2022-11-14", 3 - "1.2.3":"2021-10-21", 4 - "1.2.2":"2021-10-21", 5 - "1.2.1":"2020-09-06", 6 - "1.2.0":"2020-07-20", 7 - "1.1.0":"2019-07-13", 8 - "1.0.2":"2018-08-23", 9 - "1.0.1":"2018-08-14", 10 - "1.0.0":"2018-08-14", 2 + "2.0.5": "2025-04-12", 3 + "2.0.4": "2024-05-08", 4 + "2.0.3": "2024-05-06", 5 + "2.0.2": "2024-04-20", 6 + "2.0.1": "2024-03-28", 7 + "2.0.0": "2024-03-26", 8 + "1.3.0": "2024-03-26", 9 + "1.2.4": "2022-11-14", 10 + "1.2.3": "2021-10-21", 11 + "1.2.2": "2021-10-21", 12 + "1.2.1": "2020-09-06", 13 + "1.2.0": "2020-07-20", 14 + "1.1.0": "2019-07-13", 15 + "1.0.2": "2018-08-23", 16 + "1.0.1": "2018-08-14", 17 + "1.0.0": "2018-08-14", 11 18 };
+135 -35
test.js
··· 1 1 #!/usr/bin/env node 2 2 3 - import { ASN1 } from './asn1.js'; 3 + import { ASN1, Stream } from './asn1.js'; 4 4 import { Hex } from './hex.js'; 5 + import { Base64 } from './base64.js'; 6 + import { Int10 } from './int10.js'; 7 + 8 + const all = (process.argv[2] == 'all'); 5 9 6 - const 7 - all = (process.argv[2] == 'all'); 10 + /** @type {Array<Tests>} */ 11 + const tests = []; 12 + 13 + const stats = { 14 + run: 0, 15 + error: 0, 16 + }; 17 + 18 + /** 19 + * A class for managing and executing tests. 20 + */ 21 + class Tests { 22 + /** 23 + * An array to store test data. 24 + * @type {Array<unknown>} 25 + */ 26 + data; 27 + 28 + /** 29 + * Checks a row of test data. 30 + * @param {Function} t - How to test a row of data. 31 + */ 32 + checkRow; 33 + 34 + /** 35 + * Constructs a new Tests instance. 36 + * @param {Function} checkRow - A function to check each row of data. 37 + * @param {Array<unknown>} data - The test data to be processed. 38 + */ 39 + constructor(checkRow, data) { 40 + this.checkRow = checkRow; 41 + this.data = data; 42 + } 43 + 44 + /** 45 + * Executes the tests and checks their results for all rows. 46 + */ 47 + checkAll() { 48 + for (const t of this.data) 49 + this.checkRow(t); 50 + } 8 51 9 - const tests = [ 52 + /** 53 + * Prints the result of a test, indicating if it passed or failed. 54 + * @param {unknown} result The actual result of the test. 55 + * @param {unknown} expected The expected result of the test. 56 + * @param {string} comment A comment describing the test. 57 + */ 58 + checkResult(result, expected, comment) { 59 + ++stats.run; 60 + if (!result || result == expected) { 61 + if (all) console.log('\x1B[1m\x1B[32mOK \x1B[39m\x1B[22m ' + comment); 62 + } else { 63 + ++stats.error; 64 + console.log('\x1B[1m\x1B[31mERR\x1B[39m\x1B[22m ' + comment); 65 + console.log(' \x1B[1m\x1B[34mEXP\x1B[39m\x1B[22m ' + expected.toString().replace(/\n/g, '\n ')); 66 + console.log(' \x1B[1m\x1B[33mGOT\x1B[39m\x1B[22m ' + result.replace(/\n/g, '\n ')); 67 + } 68 + } 69 + } 70 + 71 + tests.push(new Tests(function (t) { 72 + const input = t[0], 73 + expected = t[1], 74 + comment = t[2]; 75 + let result; 76 + try { 77 + let node = ASN1.decode(Hex.decode(input)); 78 + if (typeof expected == 'function') 79 + result = expected(node); 80 + else 81 + result = node.content(); 82 + //TODO: check structure, not only first level content 83 + } catch (e) { 84 + result = 'Exception:\n' + e; 85 + } 86 + if (expected instanceof RegExp) 87 + result = expected.test(result) ? null : 'does not match'; 88 + this.checkResult(result, expected, comment); 89 + }, [ 10 90 // RSA Laboratories technical notes from https://luca.ntop.org/Teaching/Appunti/asn1.html 11 91 ['0304066E5DC0', '(18 bit)\n011011100101110111', 'ntop, bit string: DER encoding'], 12 92 ['0304066E5DE0', '(18 bit)\n011011100101110111', 'ntop, bit string: padded with "100000"'], ··· 36 116 ['170D3931303530363233343534305A', '1991-05-06 23:45:40 UTC', 'ntop, utc time: UTC'], 37 117 ['17113931303530363136343534302D30373030', '1991-05-06 16:45:40 UTC-07:00', 'ntop, utc time: PDT'], 38 118 // inspired by http://luca.ntop.org/Teaching/Appunti/asn1.html 39 - ['0304086E5DC0', 'Exception:\nInvalid BitString with unusedBits=8', 'bit string: invalid unusedBits'], 119 + ['0304086E5DC0', 'Exception:\nError: Invalid BitString with unusedBits=8', 'bit string: invalid unusedBits'], 40 120 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa379076(v=vs.85).aspx 41 121 ['30820319308202820201003023310F300D0603550403130654657374434E3110300E060355040A1307546573744F726730819F300D06092A864886F70D010101050003818D00308189028181008FE2412A08E851A88CB3E853E7D54950B3278A2BCBEAB54273EA0257CC6533EE882061A11756C12418E3A808D3BED931F3370B94B8CC43080B7024F79CB18D5DD66D82D0540984F89F970175059C89D4D5C91EC913D72A6B309119D6D442E0C49D7C9271E1B22F5C8DEEF0F1171ED25F315BB19CBC2055BF3A37424575DC90650203010001A08201B4301A060A2B0601040182370D0203310C160A362E302E353336312E323042060A2B0601040182370D0201313430321E260043006500720074006900660069006300610074006500540065006D0070006C0061007400651E080055007300650072305706092B0601040182371514314A30480201090C237669636833642E6A646F6D6373632E6E74746573742E6D6963726F736F66742E636F6D0C154A444F4D4353435C61646D696E6973747261746F720C07636572747265713074060A2B0601040182370D0202316630640201011E5C004D006900630072006F0073006F0066007400200045006E00680061006E006300650064002000430072007900700074006F0067007200610070006800690063002000500072006F00760069006400650072002000760031002E003003010030818206092A864886F70D01090E31753073301706092B0601040182371402040A1E08005500730065007230290603551D2504223020060A2B0601040182370A030406082B0601050507030406082B06010505070302300E0603551D0F0101FF0404030205A0301D0603551D0E041604143C0F73DAF8EF41D83AEABE922A5D2C966A7B9454300D06092A864886F70D01010505000381810047EB995ADF9E700DFBA73132C15F5C24C2E0BFC624AF15660EB86A2EAB2BC4971FE3CBDC63A525ECC7B428616636A1311BBFDDD0FCBF1794901DE55EC7115EC9559FEBA33E14C799A6CBBAA1460F39D444C4C84B760E205D6DA9349ED4D58742EB2426511490B40F065E5288327A9520A0FDF7E57D60DD72689BF57B058F6D1E', 42 122 '(3 elem)', 'PKCS#10 request'], ··· 86 166 ['0420041EE4E3B7ED350CC24D034E436D9A1CB15BB1E328D37062FB82E84618AB0A3C', '(32 byte)\n041EE4E3B7ED350CC24D034E436D9A1CB15BB1E328D37062FB82E84618AB0A3C', 'Do not mix encapsulated and structured octet strings'], // GitHub issue #47 87 167 ['181531393835313130363231303632372E332D31323334', '1985-11-06 21:06:27.3 UTC-12:34', 'UTC offsets with minutes'], // GitHub issue #54 88 168 ['181331393835313130363231303632372E332B3134', '1985-11-06 21:06:27.3 UTC+14:00', 'UTC offset +13 and +14'], // GitHub issue #54 89 - ]; 169 + ['032100171E83C1B251803F86DD01E9CFA886BE89A7316D8372649AC2231EC669F81A84', n => { if (n.sub != null) return 'Should not decode content: ' + n.sub[0].content(); }, 'Key that resembles an UTCTime'], // GitHub issue #79 170 + ['171E83C1B251803F86DD01E9CFA886BE89A7316D8372649AC2231EC669F81A84', /^Exception:\nError: Unrecognized time: /, 'Invalid UTCTime'], // GitHub issue #79 171 + ])); 172 + 173 + tests.push(new Tests(function (t) { 174 + let bin = Base64.decode(t); 175 + let url = new Stream(bin, 0).b64Dump(0, bin.length); 176 + // check base64url encoding 177 + this.checkResult(url, t.replace(/\n/g, '').replace(/=*$/g, ''), 'Base64url: ' + bin.length + ' bytes'); 178 + // check conversion from base64url to base64 179 + let pretty = Base64.pretty(url); 180 + this.checkResult(pretty, t, 'Base64pretty: ' + bin.length + ' bytes'); 181 + let std = new Stream(bin, 0).b64Dump(0, bin.length, 'std'); 182 + // check direct base64 encoding 183 + this.checkResult(std, t.replace(/\n/g, ''), 'Base64: ' + bin.length + ' bytes'); 184 + }, [ 185 + 'AA==', 186 + 'ABA=', 187 + 'ABCD', 188 + 'ABCDEA==', 189 + 'ABCDEFE=', 190 + 'ABCDEFGH', 191 + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQR\nSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456w==', 192 + ])); 193 + 194 + tests.push(new Tests(function (t) { 195 + this.row = (0|this.row) + 1; 196 + this.num = this.num || new Int10(); 197 + this.num.mulAdd(t[0], t[1]); 198 + this.checkResult(this.num.toString(), t[2], 'Int10 row ' + this.row); 199 + }, [ 200 + [0, 1000000000, '1000000000'], 201 + [256, 23, '256000000023'], 202 + [256, 23, '65536000005911'], 203 + [256, 23, '16777216001513239'], 204 + [256, 23, '4294967296387389207'], 205 + [256, 23, '1099511627875171637015'], 206 + [256, 23, '281474976736043939075863'], 207 + [253, 1, '71213169114219116586193340'], 208 + [253, 1, '18016931785897436496306915021'], 209 + [253, 1, '4558283741832051433565649500314'], 210 + [253, 1, '1153245786683509012692109323579443'], 211 + [253, 1, '291771184030927780211103658865599080'], 212 + [1, 0, '291771184030927780211103658865599080'], 213 + ])); 90 214 91 - let 92 - run = 0, 93 - expErr = 0, 94 - error = 0; 95 - tests.forEach(function (t) { 96 - const input = t[0], 97 - expected = t[1], 98 - comment = t[2], 99 - errorReason = t[3]; 100 - let result; 101 - try { 102 - result = ASN1.decode(Hex.decode(input)).content(); 103 - //TODO: check structure, not only first level content 104 - } catch (e) { 105 - result = 'Exception:\n' + e; 106 - } 107 - ++run; 108 - if (result == expected) { 109 - if (all) console.log('\x1B[1m\x1B[32mOK \x1B[39m\x1B[22m ' + comment); 110 - } else if (errorReason) { 111 - ++expErr; 112 - console.log('\x1B[1m\x1B[33mEXP\x1B[39m\x1B[22m ' + comment + ' (' + errorReason + ')' + '\n' + result); 113 - } else { 114 - ++error; 115 - console.log('\x1B[1m\x1B[31mERR\x1B[39m\x1B[22m ' + comment + '\n' + result); 116 - } 117 - }); 118 - console.log(run + ' tested, ' + expErr + ' expected, ' + error + ' errors.'); 119 - process.exit(error ? 1 : 0); 215 + for (const t of tests) 216 + t.checkAll(); 217 + 218 + console.log(stats.run + ' tested, ' + stats.error + ' errors.'); 219 + process.exit(stats.error ? 1 : 0);
+32
testDefs.js
··· 1 + #!/usr/bin/env node 2 + 3 + import { promises as fs } from 'node:fs'; 4 + import { ASN1 } from './asn1.js'; 5 + import { Base64 } from './base64.js'; 6 + import { Defs } from './defs.js'; 7 + 8 + const tot = []; 9 + for await (const file of await fs.opendir('examples')) { 10 + let content = await fs.readFile('examples/' + file.name); 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; 18 + const types = Defs.commonTypes 19 + .map(type => { 20 + const stats = Defs.match(result, type); 21 + return { type, match: stats.recognized / stats.total }; 22 + }) 23 + .sort((a, b) => b.match - a.match); 24 + tot.push([ types[0].match, file.name, types[0].type.description ]); 25 + } catch (e) { 26 + tot.push([ 0, file.name, e.message ]); 27 + } 28 + } 29 + for (const f of tot) 30 + console.log(f[0].toFixed(3) + '\t' + f[1] + '\t' + f[2]); 31 + const avg = tot.map(f => f[0]).reduce((sum, val) => sum + val) / tot.length; 32 + console.log('\x1B[1m\x1B[32m' + (avg * 100).toFixed(3) + '\x1B[39m\x1B[22m%\tAVERAGE');
+37
theme.js
··· 1 + // set dark theme depending on OS settings 2 + function setTheme(theme) { 3 + if (theme == 'os') { 4 + let prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)'); 5 + if (prefersDarkScheme.matches) { 6 + theme = 'dark'; 7 + } else { 8 + theme = 'light'; 9 + } 10 + } 11 + document.documentElement.style['color-scheme'] = theme; 12 + document.querySelector('html').setAttribute('data-theme', theme); 13 + // set the theme-color for iOS devices 14 + let bgColor = getComputedStyle(document.documentElement).getPropertyValue('--main-bg-color'); 15 + let metaThemeColor = document.querySelector('meta[name=theme-color]'); 16 + metaThemeColor.setAttribute('content', bgColor); 17 + } 18 + // activate selected theme 19 + let theme = 'os'; 20 + const localStorageTheme = localStorage.getItem('theme'); 21 + if (localStorageTheme) { 22 + theme = localStorageTheme; 23 + } 24 + setTheme(theme); 25 + // add handler to theme selection element 26 + const selectTheme = document.getElementById('theme-select'); 27 + if (selectTheme) { 28 + selectTheme.addEventListener ('change', function () { 29 + localStorage.setItem('theme', selectTheme.value); 30 + setTheme(selectTheme.value); 31 + }); 32 + if (theme == 'light') { 33 + selectTheme.selectedIndex = 2; 34 + } else if (theme == 'dark') { 35 + selectTheme.selectedIndex = 1; 36 + } 37 + }
+1
tree-icon-dark.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" width="28" height="14"><circle cx="6.903" cy="7.102" r="5.165" style="fill:#000;fill-opacity:1;stroke:#555;stroke-width:1.03676;stroke-dasharray:none;stroke-opacity:1"/><circle cx="21.133" cy="7.029" r="5.165" style="fill:#000;fill-opacity:1;stroke:#555;stroke-width:1.03676;stroke-dasharray:none;stroke-opacity:1"/><path d="M17.908 7.071h6.783" style="opacity:1;fill:none;fill-opacity:1;stroke:#555;stroke-width:1.03676;stroke-dasharray:none;stroke-opacity:1"/><g style="fill:none;fill-opacity:1;stroke:#555;stroke-width:.518375;stroke-dasharray:none;stroke-opacity:1"><path d="M5.231 9.992h9.466" style="opacity:.992268;fill:none;fill-opacity:1;stroke:#555;stroke-width:1.44663;stroke-dasharray:none;stroke-opacity:1" transform="translate(-.289 -.083)scale(.71667)"/><path d="M10.006 5.242v9.465" style="opacity:1;fill:none;fill-opacity:1;stroke:#555;stroke-width:1.44663;stroke-dasharray:none;stroke-opacity:1" transform="translate(-.289 -.083)scale(.71667)"/></g></svg>
+1
tree-icon-light.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" width="28" height="14"><circle cx="6.936" cy="7.247" r="5.165" style="fill:silver;fill-opacity:1;stroke:#999;stroke-width:1.03676;stroke-dasharray:none;stroke-opacity:1"/><circle cx="21.166" cy="7.174" r="5.165" style="fill:silver;fill-opacity:1;stroke:#999;stroke-width:1.03676;stroke-dasharray:none;stroke-opacity:1"/><path d="M17.94 7.216h6.784" style="fill:none;fill-opacity:1;stroke:#999;stroke-width:1.03676;stroke-dasharray:none;stroke-opacity:1"/><g style="fill:none;fill-opacity:1;stroke:#999;stroke-width:.518375;stroke-dasharray:none;stroke-opacity:1"><path d="M5.231 9.992h9.466" style="opacity:.992268;fill:none;fill-opacity:1;stroke:#999;stroke-width:1.44663;stroke-dasharray:none;stroke-opacity:1" transform="translate(-.256 .062)scale(.71667)"/><path d="M10.006 5.242v9.465" style="opacity:1;fill:none;fill-opacity:1;stroke:#999;stroke-width:1.44663;stroke-dasharray:none;stroke-opacity:1" transform="translate(-.256 .062)scale(.71667)"/></g></svg>
-1
updateOID.sh
··· 43 43 } 44 44 } 45 45 END { 46 - print "\"END\": \"\"" 47 46 print "};" 48 47 } 49 48 ' >oids.js
+1 -1
updateRFC.sh
··· 1 1 #/bin/sh 2 - RFCs="5280 5208 3369 3161 2986 4211 4210" 2 + RFCs="5280 5208 3369 3161 2986 4211 4210 8017 4511" 3 3 downloadRFC() { 4 4 URL="https://www.ietf.org/rfc/rfc$1.txt" 5 5 if [ -x /usr/bin/fetch ]; then
+37
vite.config.js
··· 1 + import fs from 'node:fs'; 2 + import { defineConfig } from 'vite'; 3 + import { viteSingleFile } from 'vite-plugin-singlefile'; 4 + import pluginDom from 'vite-plugin-dom'; 5 + import { DomUtils } from 'htmlparser2'; 6 + 7 + const removeNodes = [ 'rowExamples' ]; 8 + 9 + const preventSVGEmit = () => { 10 + return { 11 + generateBundle(opts, bundle) { 12 + for (const key in bundle) 13 + if (key.endsWith('.svg')) 14 + delete bundle[key]; 15 + }, 16 + }; 17 + }; 18 + 19 + export default defineConfig({ 20 + plugins: [ 21 + preventSVGEmit(), 22 + pluginDom({ 23 + applyOnMode: true, // all modes 24 + handler: node => { 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(), 32 + ], 33 + build: { 34 + minify: false, 35 + cssMinify: false, 36 + }, 37 + });