JavaScript generic ASN.1 parser (mirror)

Compare changes

Choose any two refs to compare.

+3156 -398
+5 -3
.github/workflows/node.js.yml
··· 12 13 strategy: 14 matrix: 15 - node-version: [ 6.4.0, latest ] 16 17 steps: 18 - - uses: actions/checkout@v3 19 - name: Use Node.js ${{ matrix.node-version }} 20 - uses: actions/setup-node@v3 21 with: 22 node-version: ${{ matrix.node-version }} 23 - run: npm test all 24 - run: npm run lint 25 if: matrix.node-version == 'latest'
··· 12 13 strategy: 14 matrix: 15 + node-version: [ 12.20.0, latest ] 16 17 steps: 18 + - uses: actions/checkout@v4 19 - name: Use Node.js ${{ matrix.node-version }} 20 + uses: actions/setup-node@v4 21 with: 22 node-version: ${{ matrix.node-version }} 23 - run: npm test all 24 + - run: npm install 25 + if: matrix.node-version == 'latest' 26 - run: npm run lint 27 if: matrix.node-version == 'latest'
+2
.gitignore
··· 2 .DS_Store/ 3 .vscode/ 4 node_modules/ 5 package-lock.json 6 pnpm-lock.yaml 7 # Artifacts from release.sh 8 sha256sums.asc 9 asn1js.zip 10 # Artifacts from mirror_to_github.sh
··· 2 .DS_Store/ 3 .vscode/ 4 node_modules/ 5 + dist/ 6 package-lock.json 7 pnpm-lock.yaml 8 # Artifacts from release.sh 9 + index-local.html 10 sha256sums.asc 11 asn1js.zip 12 # Artifacts from mirror_to_github.sh
+2
.mtn-ignore
··· 1 [.]DS_Store$ 2 [.]vscode$ 3 node_modules$ 4 package-lock[.]json 5 pnpm-lock[.]yaml 6 # Artifacts from release.sh 7 sha256sums[.]asc 8 asn1js[.]zip 9 # Artifacts from mirror_to_github.sh
··· 1 [.]DS_Store$ 2 [.]vscode$ 3 node_modules$ 4 + dist$ 5 package-lock[.]json 6 pnpm-lock[.]yaml 7 # Artifacts from release.sh 8 + index-local.html 9 sha256sums[.]asc 10 asn1js[.]zip 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 ISC License 2 3 - Copyright (c) 2008-2022 Lapo Luchini <lapo@lapo.it> 4 5 Permission to use, copy, modify, and/or distribute this software for any 6 purpose with or without fee is hereby granted, provided that the above
··· 1 ISC License 2 3 + Copyright (c) 2008-2025 Lapo Luchini <lapo@lapo.it> 4 5 Permission to use, copy, modify, and/or distribute this software for any 6 purpose with or without fee is hereby granted, provided that the above
+51 -22
README.md
··· 3 4 asn1js is a JavaScript generic ASN.1 parser/decoder that can decode any valid ASN.1 DER or BER structures. 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). 7 8 - Usage with `npm` / `yarn` 9 - ------------------------- 10 11 This package can be installed with either npm or yarn via the following commands: 12 13 ```sh 14 npm install @lapo/asn1js 15 - # or with yarn 16 yarn add @lapo/asn1js 17 ``` 18 19 - Assuming a standard javascript bundler is setup you can import it like so: 20 21 ```js 22 - const ASN1 = require('@lapo/asn1js'); 23 - // or with ES modules 24 - import ASN1 from '@lapo/asn1js'; 25 ``` 26 27 A submodule of this package can also be imported: 28 29 ```js 30 - const Hex = require('@lapo/asn1js/hex'); 31 - // or with ES modules 32 - import Hex from '@lapo/asn1js/hex'; 33 ``` 34 35 - Usage with RequireJS 36 -------------------- 37 38 - Can be [tested on JSFiddle](https://jsfiddle.net/lapo/tmdq35ug/). 39 40 ```html 41 - <script type="text/javascript" src="https://unpkg.com/requirejs/require.js"></script> 42 <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 - }); 49 </script> 50 ``` 51 52 ISC license 53 ----------- 54 55 - ASN.1 JavaScript decoder Copyright (c) 2008-2023 Lapo Luchini <lapo@lapo.it> 56 57 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 ··· 66 - extended tag support added by [Pรฉter Budai](https://www.peterbudai.eu/) 67 - patches by [Gergely Nagy](https://github.com/ngg) 68 - Relative OID support added by [Mistial Developer](https://github.com/mistial-dev) 69 - - dark mode support added by [Oliver Burgmaier](https://github.com/olibu/) 70 - patches by [Nicolai Sรธborg](https://github.com/NicolaiSoeborg) 71 72 links
··· 3 4 asn1js is a JavaScript generic ASN.1 parser/decoder that can decode any valid ASN.1 DER or BER structures. 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://asn1js.eu/) or [offline (ZIP file)](https://lapo.it/asn1js/asn1js.zip) by opening `index-local.html`. 7 8 + Usage with `nodejs` 9 + ------------------- 10 11 This package can be installed with either npm or yarn via the following commands: 12 13 ```sh 14 npm install @lapo/asn1js 15 + # or other tools 16 + pnpm install @lapo/asn1js 17 yarn add @lapo/asn1js 18 ``` 19 20 + You can import the classes like this: 21 22 ```js 23 + import { ASN1 } from '@lapo/asn1js'; 24 ``` 25 26 A submodule of this package can also be imported: 27 28 ```js 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(); 51 ``` 52 53 + Usage on the web 54 -------------------- 55 56 + Can be [tested on JSFiddle](https://jsfiddle.net/lapo/y6t2wo7q/). 57 58 ```html 59 <script> 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(); 64 </script> 65 ``` 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 + 81 ISC license 82 ----------- 83 84 + ASN.1 JavaScript decoder Copyright (c) 2008-2025 Lapo Luchini <lapo@lapo.it> 85 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. 87 ··· 95 - extended tag support added by [Pรฉter Budai](https://www.peterbudai.eu/) 96 - patches by [Gergely Nagy](https://github.com/ngg) 97 - Relative OID support added by [Mistial Developer](https://github.com/mistial-dev) 98 + - dark mode and other UI improvements by [Oliver Burgmaier](https://github.com/olibu/) 99 - patches by [Nicolai Sรธborg](https://github.com/NicolaiSoeborg) 100 101 links
+89 -39
asn1.js
··· 1 // ASN.1 JavaScript decoder 2 - // Copyright (c) 2008-2023 Lapo Luchini <lapo@lapo.it> 3 4 // Permission to use, copy, modify, and/or distribute this software for any 5 // purpose with or without fee is hereby granted, provided that the above 6 // copyright notice and this permission notice appear in all copies. 7 - // 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ··· 21 reTimeS = /^(\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|(-(?:0\d|1[0-2])|[+](?:0\d|1[0-4]))([0-5]\d)?)?$/, 22 reTimeL = /^(\d\d\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|(-(?:0\d|1[0-2])|[+](?:0\d|1[0-4]))([0-5]\d)?)?$/, 23 hexDigits = '0123456789ABCDEF', 24 - b64Safe = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', 25 tableT61 = [ 26 ['', ''], 27 ['AEIOUaeiou', 'ร€รˆรŒร’ร™ร รจรฌรฒรน'], // Grave ··· 38 ['', ''], 39 ['OUou', 'ลลฐล‘ลฑ'], // Double Acute 40 ['AEIUaeiu', 'ฤ„ฤ˜ฤฎลฒฤ…ฤ™ฤฏลณ'], // Ogonek 41 - ['CDELNRSTZcdelnrstz', 'ฤŒฤŽฤšฤฝล‡ล˜ล ลคลฝฤฤฤ›ฤพลˆล™ลกลฅลพ'] // Caron 42 ]; 43 44 function stringCut(str, len) { ··· 56 } 57 } 58 59 - class Stream { 60 61 constructor(enc, pos) { 62 if (enc instanceof Stream) { 63 this.enc = enc.enc; 64 this.pos = enc.pos; 65 } else { 66 - // enc should be an array or a binary string 67 this.enc = enc; 68 this.pos = pos; 69 } 70 } 71 get(pos) { 72 if (pos === undefined) 73 pos = this.pos++; 74 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]; 77 } 78 - hexByte(b) { 79 return hexDigits.charAt((b >> 4) & 0xF) + hexDigits.charAt(b & 0xF); 80 } 81 - hexDump(start, end, raw) { 82 let s = ''; 83 for (let i = start; i < end; ++i) { 84 - s += this.hexByte(this.get(i)); 85 - if (raw !== true) 86 switch (i & 0xF) { 87 case 0x7: s += ' '; break; 88 case 0xF: s += '\n'; break; ··· 91 } 92 return s; 93 } 94 - b64Dump(start, end) { 95 let extra = (end - start) % 3, 96 s = '', 97 i, c; 98 for (i = start; i + 2 < end; i += 3) { 99 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); 104 } 105 if (extra > 0) { 106 c = this.get(i) << 16; 107 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); 111 } 112 return s; 113 } ··· 190 let s = this.parseStringISO(start, end).str, 191 m = (shortYear ? reTimeS : reTimeL).exec(s); 192 if (!m) 193 - return 'Unrecognized time: ' + s; 194 if (shortYear) { 195 // to avoid querying the timer, use the fixed range [1970, 2069] 196 // it will conform with ITU X.400 [-10, +40] sliding window until 2030 ··· 245 parseBitString(start, end, maxLength) { 246 let unusedBits = this.get(start); 247 if (unusedBits > 7) 248 - throw 'Invalid BitString with unusedBits=' + unusedBits; 249 let lenBit = ((end - start - 1) << 3) - unusedBits, 250 s = ''; 251 for (let i = start + 1; i < end; ++i) { ··· 273 end = start + maxLength; 274 s = ''; 275 for (let i = start; i < end; ++i) 276 - s += this.hexByte(this.get(i)); 277 if (len > maxLength) 278 s += ellipsis; 279 return { size: len, str: s }; ··· 368 369 export class ASN1 { 370 constructor(stream, header, length, tag, tagLen, sub) { 371 - if (!(tag instanceof ASN1Tag)) throw 'Invalid tag value.'; 372 this.stream = stream; 373 this.header = header; 374 this.length = length; ··· 485 } 486 toPrettyString(indent) { 487 if (indent === undefined) indent = ''; 488 - let s = indent + this.typeName() + ' @' + this.stream.pos; 489 if (this.length >= 0) 490 s += '+'; 491 s += this.length; ··· 517 posLen() { 518 return this.stream.pos + this.tagLen; 519 } 520 - toHexString() { 521 - return this.stream.hexDump(this.posStart(), this.posEnd(), true); 522 } 523 - toB64String() { 524 - return this.stream.b64Dump(this.posStart(), this.posEnd()); 525 } 526 static decodeLength(stream) { 527 let buf = stream.get(), ··· 531 if (len === 0) // long form with length 0 is a special case 532 return null; // undefined length 533 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); 535 buf = 0; 536 for (let i = 0; i < len; ++i) 537 buf = (buf * 256) + stream.get(); ··· 539 } 540 static decode(stream, offset, type = ASN1) { 541 if (!(type == ASN1 || type.prototype instanceof ASN1)) 542 - throw 'Must pass a class that extends ASN1'; 543 if (!(stream instanceof Stream)) 544 stream = new Stream(stream, offset || 0); 545 let streamStart = new Stream(stream), ··· 555 // definite length 556 let end = start + len; 557 if (end > stream.enc.length) 558 - throw 'Container at offset ' + start + ' has a length of ' + len + ', which is past the end of the stream'; 559 while (stream.pos < end) 560 sub[sub.length] = type.decode(stream); 561 if (stream.pos != end) 562 - throw 'Content size is not correct for container at offset ' + start; 563 } else { 564 // undefined length 565 try { ··· 571 } 572 len = start - stream.pos; // undefined lengths are represented as negative values 573 } catch (e) { 574 - throw 'Exception while decoding undefined length content at offset ' + start + ': ' + e; 575 } 576 } 577 }; ··· 583 try { 584 if (tag.tagNumber == 0x03) 585 if (stream.get() != 0) 586 - throw 'BIT STRINGs with unused bits cannot encapsulate.'; 587 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.'; 591 } catch (e) { 592 // but silently ignore when they don't 593 sub = null; ··· 596 } 597 if (sub === null) { 598 if (len === null) 599 - throw "We can't skip over an invalid tag with undefined length at offset " + start; 600 stream.pos = start + Math.abs(len); 601 } 602 return new type(streamStart, header, len, tag, tagLen, sub);
··· 1 // ASN.1 JavaScript decoder 2 + // Copyright (c) 2008 Lapo Luchini <lapo@lapo.it> 3 4 // Permission to use, copy, modify, and/or distribute this software for any 5 // purpose with or without fee is hereby granted, provided that the above 6 // copyright notice and this permission notice appear in all copies. 7 + // 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ··· 21 reTimeS = /^(\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|(-(?:0\d|1[0-2])|[+](?:0\d|1[0-4]))([0-5]\d)?)?$/, 22 reTimeL = /^(\d\d\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|(-(?:0\d|1[0-2])|[+](?:0\d|1[0-4]))([0-5]\d)?)?$/, 23 hexDigits = '0123456789ABCDEF', 24 + b64Std = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', 25 + b64URL = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', 26 tableT61 = [ 27 ['', ''], 28 ['AEIOUaeiou', 'ร€รˆรŒร’ร™ร รจรฌรฒรน'], // Grave ··· 39 ['', ''], 40 ['OUou', 'ลลฐล‘ลฑ'], // Double Acute 41 ['AEIUaeiu', 'ฤ„ฤ˜ฤฎลฒฤ…ฤ™ฤฏลณ'], // Ogonek 42 + ['CDELNRSTZcdelnrstz', 'ฤŒฤŽฤšฤฝล‡ล˜ล ลคลฝฤฤฤ›ฤพลˆล™ลกลฅลพ'], // Caron 43 ]; 44 45 function stringCut(str, len) { ··· 57 } 58 } 59 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 { 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 + */ 68 constructor(enc, pos) { 69 if (enc instanceof Stream) { 70 this.enc = enc.enc; 71 this.pos = enc.pos; 72 } else { 73 this.enc = enc; 74 this.pos = pos; 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'); 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) */ 87 get(pos) { 88 if (pos === undefined) 89 pos = this.pos++; 90 if (pos >= this.enc.length) 91 + throw new Error('Requesting byte offset ' + pos + ' on a stream of length ' + this.enc.length); 92 + return this.getRaw(pos); 93 } 94 + /** Convert a single byte to an hexadcimal string (of length 2). 95 + * @param {number} b */ 96 + static hexByte(b) { 97 return hexDigits.charAt((b >> 4) & 0xF) + hexDigits.charAt(b & 0xF); 98 } 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') { 104 let s = ''; 105 for (let i = start; i < end; ++i) { 106 + if (type == 'byte' && i > start) 107 + s += ' '; 108 + s += Stream.hexByte(this.get(i)); 109 + if (type == 'dump') 110 switch (i & 0xF) { 111 case 0x7: s += ' '; break; 112 case 0xF: s += '\n'; break; ··· 115 } 116 return s; 117 } 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; 124 let extra = (end - start) % 3, 125 s = '', 126 i, c; 127 for (i = start; i + 2 < end; i += 3) { 128 c = this.get(i) << 16 | this.get(i + 1) << 8 | this.get(i + 2); 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); 133 } 134 if (extra > 0) { 135 c = this.get(i) << 16; 136 if (extra > 1) c |= this.get(i + 1) << 8; 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); 141 } 142 return s; 143 } ··· 220 let s = this.parseStringISO(start, end).str, 221 m = (shortYear ? reTimeS : reTimeL).exec(s); 222 if (!m) 223 + throw new Error('Unrecognized time: ' + s); 224 if (shortYear) { 225 // to avoid querying the timer, use the fixed range [1970, 2069] 226 // it will conform with ITU X.400 [-10, +40] sliding window until 2030 ··· 275 parseBitString(start, end, maxLength) { 276 let unusedBits = this.get(start); 277 if (unusedBits > 7) 278 + throw new Error('Invalid BitString with unusedBits=' + unusedBits); 279 let lenBit = ((end - start - 1) << 3) - unusedBits, 280 s = ''; 281 for (let i = start + 1; i < end; ++i) { ··· 303 end = start + maxLength; 304 s = ''; 305 for (let i = start; i < end; ++i) 306 + s += Stream.hexByte(this.get(i)); 307 if (len > maxLength) 308 s += ellipsis; 309 return { size: len, str: s }; ··· 398 399 export class ASN1 { 400 constructor(stream, header, length, tag, tagLen, sub) { 401 + if (!(tag instanceof ASN1Tag)) throw new Error('Invalid tag value.'); 402 this.stream = stream; 403 this.header = header; 404 this.length = length; ··· 515 } 516 toPrettyString(indent) { 517 if (indent === undefined) indent = ''; 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; 528 if (this.length >= 0) 529 s += '+'; 530 s += this.length; ··· 556 posLen() { 557 return this.stream.pos + this.tagLen; 558 } 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); 563 } 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); 569 } 570 static decodeLength(stream) { 571 let buf = stream.get(), ··· 575 if (len === 0) // long form with length 0 is a special case 576 return null; // undefined length 577 if (len > 6) // no reason to use Int10, as it would be a huge buffer anyways 578 + throw new Error('Length over 48 bits not supported at position ' + (stream.pos - 1)); 579 buf = 0; 580 for (let i = 0; i < len; ++i) 581 buf = (buf * 256) + stream.get(); ··· 583 } 584 static decode(stream, offset, type = ASN1) { 585 if (!(type == ASN1 || type.prototype instanceof ASN1)) 586 + throw new Error('Must pass a class that extends ASN1'); 587 if (!(stream instanceof Stream)) 588 stream = new Stream(stream, offset || 0); 589 let streamStart = new Stream(stream), ··· 599 // definite length 600 let end = start + len; 601 if (end > stream.enc.length) 602 + throw new Error('Container at offset ' + start + ' has a length of ' + len + ', which is past the end of the stream'); 603 while (stream.pos < end) 604 sub[sub.length] = type.decode(stream); 605 if (stream.pos != end) 606 + throw new Error('Content size is not correct for container at offset ' + start); 607 } else { 608 // undefined length 609 try { ··· 615 } 616 len = start - stream.pos; // undefined lengths are represented as negative values 617 } catch (e) { 618 + throw new Error('Exception while decoding undefined length content at offset ' + start + ': ' + e); 619 } 620 } 621 }; ··· 627 try { 628 if (tag.tagNumber == 0x03) 629 if (stream.get() != 0) 630 + throw new Error('BIT STRINGs with unused bits cannot encapsulate.'); 631 getSub(); 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 + } 641 } catch (e) { 642 // but silently ignore when they don't 643 sub = null; ··· 646 } 647 if (sub === null) { 648 if (len === null) 649 + throw new Error("We can't skip over an invalid tag with undefined length at offset " + start); 650 stream.pos = start + Math.abs(len); 651 } 652 return new type(streamStart, header, len, tag, tagLen, sub);
+8 -7
base64.js
··· 1 // Base64 JavaScript decoder 2 - // Copyright (c) 2008-2023 Lapo Luchini <lapo@lapo.it> 3 4 // Permission to use, copy, modify, and/or distribute this software for any 5 // purpose with or without fee is hereby granted, provided that the above 6 // copyright notice and this permission notice appear in all copies. 7 - // 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ··· 31 decoder[b64.charCodeAt(i)] = i; 32 for (i = 0; i < ignore.length; ++i) 33 decoder[ignore.charCodeAt(i)] = -1; 34 - // RFC 3548 URL & file safe encoding 35 decoder['-'.charCodeAt(0)] = decoder['+'.charCodeAt(0)]; 36 decoder['_'.charCodeAt(0)] = decoder['/'.charCodeAt(0)]; 37 } ··· 75 76 static pretty(str) { 77 // fix padding 78 - if (str.length % 4 > 0) 79 - str = (str + '===').slice(0, str.length + str.length % 4); 80 - // convert RFC 3548 to standard Base64 81 str = str.replace(/-/g, '+').replace(/_/g, '/'); 82 // 80 column width 83 - return str.replace(/(.{80})/g, '$1\n'); 84 } 85 86 static unarmor(a) {
··· 1 // Base64 JavaScript decoder 2 + // Copyright (c) 2008 Lapo Luchini <lapo@lapo.it> 3 4 // Permission to use, copy, modify, and/or distribute this software for any 5 // purpose with or without fee is hereby granted, provided that the above 6 // copyright notice and this permission notice appear in all copies. 7 + // 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ··· 31 decoder[b64.charCodeAt(i)] = i; 32 for (i = 0; i < ignore.length; ++i) 33 decoder[ignore.charCodeAt(i)] = -1; 34 + // also support decoding Base64url (RFC 4648 section 5) 35 decoder['-'.charCodeAt(0)] = decoder['+'.charCodeAt(0)]; 36 decoder['_'.charCodeAt(0)] = decoder['/'.charCodeAt(0)]; 37 } ··· 75 76 static pretty(str) { 77 // fix padding 78 + let pad = 4 - str.length % 4; 79 + if (pad < 4) 80 + str += '==='.slice(0, pad); 81 + // convert Base64url (RFC 4648 section 5) to standard Base64 (RFC 4648 section 4) 82 str = str.replace(/-/g, '+').replace(/_/g, '/'); 83 // 80 column width 84 + return str.replace(/.{80}/g, '$&\n'); 85 } 86 87 static unarmor(a) {
+1 -1
check.sh
··· 1 #!/bin/sh 2 - type gsha256sum >/dev/null && SHA256=gsha256sum || SHA256=sha256sum 3 gpg --verify -o - sha256sums.asc | $SHA256 -c --quiet
··· 1 #!/bin/sh 2 + type gsha256sum >/dev/null 2>/dev/null && SHA256=gsha256sum || SHA256=sha256sum 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 // ASN.1 RFC definitions matcher 2 - // Copyright (c) 2023-2023 Lapo Luchini <lapo@lapo.it> 3 4 // Permission to use, copy, modify, and/or distribute this software for any 5 // purpose with or without fee is hereby granted, provided that the above 6 // copyright notice and this permission notice appear in all copies. 7 - // 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ··· 23 try { 24 // hope current OIDs contain the type name (will need to parse from RFC itself) 25 def = Defs.searchType(firstUpper(stats.defs[def.definedBy][1])); 26 - } catch (e) {} 27 while (def?.type == 'defined' || def?.type?.type == 'defined') { 28 const name = def?.type?.type ? def.type.name : def.name; 29 def = Object.assign({}, def); 30 def.type = Defs.searchType(name).type; 31 } 32 - if (def?.type?.name == 'CHOICE') { 33 - for (let c of def.type.content) { 34 - c = translate(c); 35 if (tn == c.type.name || tn == c.name) { 36 def = Object.assign({}, def); 37 def.type = c.type.name ? c.type : c; 38 break; 39 } ··· 62 // return r.types[name]; 63 return Defs.moduleAndType(mod, name); 64 } 65 - throw 'Type not found: ' + name; 66 } 67 68 static match(value, def, stats = { total: 0, recognized: 0, defs: {} }) { ··· 89 type = def.content[0]; 90 else { 91 let tn = subval.typeName().replaceAll('_', ' '); 92 - do { 93 type = def.content[j++]; 94 - // type = translate(type, tn); 95 if (type?.type?.type) 96 type = type.type; 97 - } while (type && typeof type == 'object' && ('optional' in type || 'default' in type) && type.name != 'ANY' && type.name != tn); 98 if (type?.type == 'builtin' || type?.type == 'defined') { 99 let v = subval.content(); 100 if (typeof v == 'string') ··· 103 } else if (type?.definedBy && stats.defs?.[type.definedBy]?.[1]) { // hope current OIDs contain the type name (will need to parse from RFC itself) 104 try { 105 type = Defs.searchType(firstUpper(stats.defs[type.definedBy][1])); 106 - } catch (e) {} 107 } 108 } 109 } ··· 118 Defs.RFC = rfcdef; 119 120 Defs.commonTypes = [ 121 - [ 'X.509 certificate', '1.3.6.1.5.5.7.0.18', 'Certificate' ], 122 [ 'CMS / PKCS#7 envelope', '1.2.840.113549.1.9.16.0.14', 'ContentInfo' ], 123 [ 'PKCS#8 encrypted private key', '1.2.840.113549.1.8.1.1', 'EncryptedPrivateKeyInfo' ], 124 [ 'PKCS#8 private key', '1.2.840.113549.1.8.1.1', 'PrivateKeyInfo' ], 125 [ 'PKCS#10 certification request', '1.2.840.113549.1.10.1.1', 'CertificationRequest' ], 126 [ 'CMP PKI Message', '1.3.6.1.5.5.7.0.16', 'PKIMessage' ], 127 ].map(arr => ({ description: arr[0], ...Defs.moduleAndType(rfcdef[arr[1]], arr[2]) }));
··· 1 // ASN.1 RFC definitions matcher 2 + // Copyright (c) 2023 Lapo Luchini <lapo@lapo.it> 3 4 // Permission to use, copy, modify, and/or distribute this software for any 5 // purpose with or without fee is hereby granted, provided that the above 6 // copyright notice and this permission notice appear in all copies. 7 + // 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ··· 23 try { 24 // hope current OIDs contain the type name (will need to parse from RFC itself) 25 def = Defs.searchType(firstUpper(stats.defs[def.definedBy][1])); 26 + } catch (e) { /*ignore*/ } 27 while (def?.type == 'defined' || def?.type?.type == 'defined') { 28 const name = def?.type?.type ? def.type.name : def.name; 29 def = Object.assign({}, def); 30 def.type = Defs.searchType(name).type; 31 } 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); 36 if (tn == c.type.name || tn == c.name) { 37 def = Object.assign({}, def); 38 + if (c.id) def.id = c.id; 39 def.type = c.type.name ? c.type : c; 40 break; 41 } ··· 64 // return r.types[name]; 65 return Defs.moduleAndType(mod, name); 66 } 67 + throw new Error('Type not found: ' + name); 68 } 69 70 static match(value, def, stats = { total: 0, recognized: 0, defs: {} }) { ··· 91 type = def.content[0]; 92 else { 93 let tn = subval.typeName().replaceAll('_', ' '); 94 + for (;;) { 95 type = def.content[j++]; 96 + if (!type || typeof type != 'object') break; 97 if (type?.type?.type) 98 type = type.type; 99 + if (type.type == 'defined') { 100 + let t2 = translate(type, tn); 101 + if (t2.type.name == tn) break; // exact match 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 + } 108 if (type?.type == 'builtin' || type?.type == 'defined') { 109 let v = subval.content(); 110 if (typeof v == 'string') ··· 113 } else if (type?.definedBy && stats.defs?.[type.definedBy]?.[1]) { // hope current OIDs contain the type name (will need to parse from RFC itself) 114 try { 115 type = Defs.searchType(firstUpper(stats.defs[type.definedBy][1])); 116 + } catch (e) { /*ignore*/ } 117 } 118 } 119 } ··· 128 Defs.RFC = rfcdef; 129 130 Defs.commonTypes = [ 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' ], 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' ], 136 [ 'PKCS#8 encrypted private key', '1.2.840.113549.1.8.1.1', 'EncryptedPrivateKeyInfo' ], 137 [ 'PKCS#8 private key', '1.2.840.113549.1.8.1.1', 'PrivateKeyInfo' ], 138 [ 'PKCS#10 certification request', '1.2.840.113549.1.10.1.1', 'CertificationRequest' ], 139 [ 'CMP PKI Message', '1.3.6.1.5.5.7.0.16', 'PKIMessage' ], 140 + [ 'LDAP Message', '1.3.6.1.1.18', 'LDAPMessage' ], 141 ].map(arr => ({ description: arr[0], ...Defs.moduleAndType(rfcdef[arr[1]], arr[2]) }));
+42 -22
dom.js
··· 1 // ASN.1 JavaScript decoder 2 - // Copyright (c) 2008-2023 Lapo Luchini <lapo@lapo.it> 3 4 // Permission to use, copy, modify, and/or distribute this software for any 5 // purpose with or without fee is hereby granted, provided that the above 6 // copyright notice and this permission notice appear in all copies. 7 - // 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ··· 15 16 import { ASN1 } from './asn1.js'; 17 import { oids } from './oids.js'; 18 19 const 20 lineLength = 80, ··· 23 ellipsis: '\u2026', 24 tag: function (tagName, className, text) { 25 let t = document.createElement(tagName); 26 - t.className = className; 27 if (text) t.innerText = text; 28 return t; 29 }, ··· 47 o += line; 48 } 49 return o; 50 - } 51 }; 52 53 export class ASN1DOM extends ASN1 { ··· 55 toDOM(spaces) { 56 spaces = spaces || ''; 57 let isOID = (typeof oids === 'object') && (this.tag.isUniversal() && (this.tag.tagNumber == 0x06) || (this.tag.tagNumber == 0x0D)); 58 - let node = DOM.tag('div', 'node'); 59 node.asn1 = this; 60 - let head = DOM.tag('div', 'head'); 61 - head.appendChild(DOM.tag('span', 'spaces', spaces)); 62 const typeName = this.typeName().replace(/_/g, ' '); 63 if (this.def) { 64 if (this.def.id) { ··· 75 } 76 } 77 head.appendChild(DOM.text(typeName)); 78 - let content = this.content(contentLength); 79 let oid; 80 if (content !== null) { 81 let preview = DOM.tag('span', 'preview'), ··· 105 content = content.replace(/</g, '&lt;'); 106 content = content.replace(/\n/g, '<br>'); 107 } 108 - node.appendChild(head); 109 - this.node = node; 110 this.head = head; 111 let value = DOM.tag('div', 'value'); 112 let s = 'Offset: ' + this.stream.pos + '<br>'; ··· 129 } 130 } 131 value.innerHTML = s; 132 - node.appendChild(value); 133 - let sub = DOM.tag('div', 'sub'); 134 if (this.sub !== null) { 135 spaces += '\xA0 '; 136 for (let i = 0, max = this.sub.length; i < max; ++i) 137 sub.appendChild(this.sub[i].toDOM(spaces)); 138 } 139 - node.appendChild(sub); 140 - head.onclick = function () { 141 - node.className = (node.className == 'node collapsed') ? 'node' : 'node collapsed'; 142 - }; 143 return node; 144 } 145 fakeHover(current) { 146 - this.node.className += ' hover'; 147 if (current) 148 - this.head.className += ' hover'; 149 } 150 fakeOut(current) { 151 - let re = / ?hover/; 152 - this.node.className = this.node.className.replace(re, ''); 153 if (current) 154 - this.head.className = this.head.className.replace(re, ''); 155 } 156 toHexDOM_sub(node, className, stream, start, end) { 157 if (start >= end) ··· 166 this.head.onmouseover = function () { this.hexNode.className = 'hexCurrent'; }; 167 this.head.onmouseout = function () { this.hexNode.className = 'hex'; }; 168 node.asn1 = this; 169 - node.onmouseover = function () { 170 let current = !root.selected; 171 if (current) { 172 root.selected = this.asn1; 173 this.className = 'hexCurrent'; 174 } 175 this.asn1.fakeHover(current); 176 }; 177 node.onmouseout = function () { 178 let current = (root.selected == this.asn1); ··· 182 this.className = 'hex'; 183 } 184 }; 185 if (root == node) { 186 let lineStart = this.posStart() & 0xF; 187 if (lineStart != 0) {
··· 1 // ASN.1 JavaScript decoder 2 + // Copyright (c) 2008 Lapo Luchini <lapo@lapo.it> 3 4 // Permission to use, copy, modify, and/or distribute this software for any 5 // purpose with or without fee is hereby granted, provided that the above 6 // copyright notice and this permission notice appear in all copies. 7 + // 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ··· 15 16 import { ASN1 } from './asn1.js'; 17 import { oids } from './oids.js'; 18 + import { bindContextMenu } from './context.js'; 19 20 const 21 lineLength = 80, ··· 24 ellipsis: '\u2026', 25 tag: function (tagName, className, text) { 26 let t = document.createElement(tagName); 27 + if (className) t.className = className; 28 if (text) t.innerText = text; 29 return t; 30 }, ··· 48 o += line; 49 } 50 return o; 51 + }, 52 }; 53 54 export class ASN1DOM extends ASN1 { ··· 56 toDOM(spaces) { 57 spaces = spaces || ''; 58 let isOID = (typeof oids === 'object') && (this.tag.isUniversal() && (this.tag.tagNumber == 0x06) || (this.tag.tagNumber == 0x0D)); 59 + let node = DOM.tag('li'); 60 node.asn1 = this; 61 + let head = DOM.tag('span', 'head'); 62 const typeName = this.typeName().replace(/_/g, ' '); 63 if (this.def) { 64 if (this.def.id) { ··· 75 } 76 } 77 head.appendChild(DOM.text(typeName)); 78 + let content; 79 + try { 80 + content = this.content(contentLength); 81 + } catch (e) { 82 + content = 'Cannot decode: ' + e; 83 + } 84 let oid; 85 if (content !== null) { 86 let preview = DOM.tag('span', 'preview'), ··· 110 content = content.replace(/</g, '&lt;'); 111 content = content.replace(/\n/g, '<br>'); 112 } 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; 131 this.head = head; 132 let value = DOM.tag('div', 'value'); 133 let s = 'Offset: ' + this.stream.pos + '<br>'; ··· 150 } 151 } 152 value.innerHTML = s; 153 + contentNode.appendChild(value); 154 if (this.sub !== null) { 155 + let sub = DOM.tag('ul'); 156 + childNode.appendChild(sub); 157 spaces += '\xA0 '; 158 for (let i = 0, max = this.sub.length; i < max; ++i) 159 sub.appendChild(this.sub[i].toDOM(spaces)); 160 } 161 + bindContextMenu(node); 162 return node; 163 } 164 fakeHover(current) { 165 + this.node.classList.add('hover'); 166 if (current) 167 + this.head.classList.add('hover'); 168 } 169 fakeOut(current) { 170 + this.node.classList.remove('hover'); 171 if (current) 172 + this.head.classList.remove('hover'); 173 } 174 toHexDOM_sub(node, className, stream, start, end) { 175 if (start >= end) ··· 184 this.head.onmouseover = function () { this.hexNode.className = 'hexCurrent'; }; 185 this.head.onmouseout = function () { this.hexNode.className = 'hex'; }; 186 node.asn1 = this; 187 + node.onmouseover = function (event) { 188 let current = !root.selected; 189 if (current) { 190 root.selected = this.asn1; 191 this.className = 'hexCurrent'; 192 } 193 this.asn1.fakeHover(current); 194 + event.stopPropagation(); 195 }; 196 node.onmouseout = function () { 197 let current = (root.selected == this.asn1); ··· 201 this.className = 'hex'; 202 } 203 }; 204 + bindContextMenu(node); 205 if (root == node) { 206 let lineStart = this.posStart() & 0xF; 207 if (lineStart != 0) {
+31 -19
dumpASN1.js
··· 1 #!/usr/bin/env node 2 - 'use strict'; 3 4 import * as fs from 'node:fs'; 5 import { Base64 } from './base64.js'; ··· 9 const 10 colYellow = '\x1b[33m', 11 colBlue = '\x1b[34m', 12 - colReset = '\x1b[0m'; 13 14 function print(value, indent) { 15 if (indent === undefined) indent = ''; ··· 41 return s; 42 } 43 44 - let content = fs.readFileSync(process.argv[2]); 45 try { // try PEM first 46 content = Base64.unarmor(content); 47 } catch (e) { // try DER/BER then ··· 49 let result = ASN1.decode(content); 50 content = null; 51 const t0 = performance.now(); 52 - const types = Defs.commonTypes 53 - .map(type => { 54 - const stats = Defs.match(result, type); 55 - return { type, match: stats.recognized / stats.total }; 56 - }) 57 - .sort((a, b) => b.match - a.match); 58 - const t1 = performance.now(); 59 - console.log('Parsed in ' + (t1 - t0).toFixed(2) + ' ms; possible types:'); 60 - for (const t of types) 61 - console.log((t.match * 100).toFixed(2).padStart(6) + '% ' + t.type.description); 62 - Defs.match(result, types[0].type); 63 - // const stats = Defs.match(result, types[0].type); 64 - // console.log('Stats:', stats); 65 - console.log('Parsed as:', result.def); 66 - // const type = searchType(process.argv[2]); 67 - // const stats = applyDef(result, type); 68 console.log(print(result)); 69 // console.log('Stats:', (stats.recognized * 100 / stats.total).toFixed(2) + '%'); 70 // // print(result, searchType(process.argv[2]), stats);
··· 1 #!/usr/bin/env node 2 + 3 + // usage: 4 + // ./dumpASN1.js filename 5 + // ./dumpASN1.js data:base64,MDMCAQFjLgQACgEACgEAAgEAAgEAAQEAoA+jDQQFTnRWZXIEBAEAAAAwCgQITmV0bG9nb24=== 6 7 import * as fs from 'node:fs'; 8 import { Base64 } from './base64.js'; ··· 12 const 13 colYellow = '\x1b[33m', 14 colBlue = '\x1b[34m', 15 + colReset = '\x1b[0m', 16 + reDataURI = /^data:(?:[a-z-]+[/][a-z.+-]+;)?base64,([A-Za-z0-9+/=\s]+)$/; 17 18 function print(value, indent) { 19 if (indent === undefined) indent = ''; ··· 45 return s; 46 } 47 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); 53 try { // try PEM first 54 content = Base64.unarmor(content); 55 } catch (e) { // try DER/BER then ··· 57 let result = ASN1.decode(content); 58 content = null; 59 const t0 = performance.now(); 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 + } 80 console.log(print(result)); 81 // console.log('Stats:', (stats.recognized * 100 / stats.total).toFixed(2) + '%'); 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 // Hex JavaScript decoder 2 - // Copyright (c) 2008-2023 Lapo Luchini <lapo@lapo.it> 3 4 // Permission to use, copy, modify, and/or distribute this software for any 5 // purpose with or without fee is hereby granted, provided that the above 6 // copyright notice and this permission notice appear in all copies. 7 - // 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
··· 1 // Hex JavaScript decoder 2 + // Copyright (c) 2008 Lapo Luchini <lapo@lapo.it> 3 4 // Permission to use, copy, modify, and/or distribute this software for any 5 // purpose with or without fee is hereby granted, provided that the above 6 // copyright notice and this permission notice appear in all copies. 7 + // 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-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 { 2 --main-bg-color: #C0C0C0; 3 --main-text-color: #000000; 4 --headline-text-color: #8be9fd; 5 --button-border-color: #767676; 6 --button-bg-color: #efefef; ··· 18 --preview-border-color: #505050; 19 --dump-bg-color: #C0C0C0; 20 --dump-border-color: #E0E0E0; 21 } 22 html, body { 23 background-color: var(--page-bg-color); ··· 83 #main-page { 84 background-color: var(--main-bg-color); 85 border: 0px; 86 - padding: 15px; 87 } 88 #main-page > div { 89 position: relative; ··· 115 /*display: block;*/ 116 visibility: visible; 117 } 118 - .node { 119 - position: relative; 120 - } 121 - .sub { 122 - padding-left: 1.5em; 123 - border-left: solid 1px var(--sub-border-color); 124 - } 125 .head { 126 height: 1em; 127 white-space: nowrap; 128 } 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 .node:hover > .head, .node.hover > .head { 139 color: var(--link-color); 140 - font-weight: bold; 141 } 142 .node:hover > .head:hover, .node.hover > .head.hover { 143 color: var(--link-hover-color); ··· 156 color: var(--preview-border-color); 157 } 158 .name.id { 159 - color: var(--main-text-color); 160 } 161 .value { 162 display: none; 163 position: absolute; 164 z-index: 2; 165 top: 1.2em; 166 - left: 0; 167 background-color: #efefef; /*minimal support for IE11*/ 168 background-color: var(--button-bg-color); 169 border: solid 1px var(--button-border-color); ··· 201 white-space: pre; 202 padding: 5px; 203 } 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; } 213 #file { display: none; } 214 #area { width: 100%; }
··· 1 + html { 2 --main-bg-color: #C0C0C0; 3 --main-text-color: #000000; 4 + --id-text-color: #7d5900; 5 --headline-text-color: #8be9fd; 6 --button-border-color: #767676; 7 --button-bg-color: #efefef; ··· 19 --preview-border-color: #505050; 20 --dump-bg-color: #C0C0C0; 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; 69 } 70 html, body { 71 background-color: var(--page-bg-color); ··· 131 #main-page { 132 background-color: var(--main-bg-color); 133 border: 0px; 134 + padding: 5px; 135 } 136 #main-page > div { 137 position: relative; ··· 163 /*display: block;*/ 164 visibility: visible; 165 } 166 .head { 167 height: 1em; 168 white-space: nowrap; 169 } 170 .node:hover > .head, .node.hover > .head { 171 color: var(--link-color); 172 + background-color: var(--hover-bg-color); 173 } 174 .node:hover > .head:hover, .node.hover > .head.hover { 175 color: var(--link-hover-color); ··· 188 color: var(--preview-border-color); 189 } 190 .name.id { 191 + color: var(--id-text-color); 192 } 193 .value { 194 display: none; 195 position: absolute; 196 z-index: 2; 197 top: 1.2em; 198 + left: 30px; 199 background-color: #efefef; /*minimal support for IE11*/ 200 background-color: var(--button-bg-color); 201 border: solid 1px var(--button-border-color); ··· 233 white-space: pre; 234 padding: 5px; 235 } 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); } 245 #file { display: none; } 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 <!DOCTYPE html> 2 - <html> 3 <head> 4 - <meta charset="US-ASCII"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> 6 <title>ASN.1 JavaScript decoder</title> 7 - <link rel="stylesheet" href="index.css" type="text/css" id="theme-base"> 8 <link rel="icon" type="image/svg+xml" sizes="192x192" href="favicon.svg"> 9 </head> 10 <body> 11 <header> 12 <div class="title"> 13 <h1>ASN.1 JavaScript decoder</h1> ··· 29 <div id="tree"></div> 30 </div> 31 <form> 32 - <textarea id="area" rows="8"></textarea> 33 <br> 34 <br> 35 <label title="can be slow with big files"><input type="checkbox" id="wantHex" checked="checked"> with hex dump</label> ··· 39 <br><br> 40 <table> 41 <tr><td>Drag or load file:</td><td><input type="file" id="file"></td></tr> 42 - <tr><td>Load examples:</td><td> 43 <select id="examples"> 44 <option value="sig-p256-der.p7m">PKCS#7/CMS attached signature (DER)</option> 45 <option value="sig-p256-ber.p7m">PKCS#7/CMS attached signature (BER)</option> 46 <option value="sig-rsa1024-sha1.p7s">PKCS#7/CMS detached signature (old)</option> 47 <option value="letsencrypt-x3.cer">X.509 certificate: Let's Encrypt X3</option> 48 <option value="ed25519.cer">X.509 certificate: ed25519 (RFC 8410)</option> 49 <option value="pkcs10.pem">PKCS#10 certification request (RFC 2986)</option> 50 <option value="cmpv2.b64">CMP PKI message (RFC 4210)</option> 51 </select> 52 <input id="butExample" type="button" value="load"><br> 53 </td></tr> ··· 59 <div id="help"> 60 <h2>Instructions</h2> 61 <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> 63 <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 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 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> 68 <div class="license"> 69 <h3>Copyright</h3> 70 <div><p class="hidden"> 71 ASN.1 JavaScript decoder<br> 72 - Copyright &copy; 2008-2023 Lapo Luchini <a href="mailto:lapo@lapo.it?subject=ASN1js">&lt;lapo@lapo.it&gt;</a><br> 73 <br> 74 Permission to use, copy, modify, and/or distribute this software for any 75 purpose with or without fee is hereby granted, provided that the above ··· 83 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 84 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 85 </p></div> 86 - <p>ASN.1 JavaScript decoder Copyright &copy; 2008-2023 <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> 87 </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> 89 <h3>Links</h3> 90 <ul> 91 - <li><a href="http://lapo.it/asn1js/">official website</a></li> 92 - <li><a href="http://asn1js.eu/">dedicated domain</a></li> 93 <li>previous versions on githack: <select id="tags"><option>[select tag]</option></select></li> 94 <li><a href="http://idf.lapo.it/p/asn1js/">InDefero tracker</a> (currently offline)</li> 95 <li><a href="https://github.com/lapo-luchini/asn1js">github mirror</a></li> 96 <li><a href="https://www.openhub.net/p/asn1js">OpenHub code stats</a></li> 97 </ul> 98 </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 <script type="module" src="index.js"></script> 110 </body> 111 </html>
··· 1 <!DOCTYPE html> 2 + <html data-theme="dark"> 3 <head> 4 + <meta charset="UTF-8"> 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)"> 8 <title>ASN.1 JavaScript decoder</title> 9 + <link rel="stylesheet" href="index.css" type="text/css"> 10 <link rel="icon" type="image/svg+xml" sizes="192x192" href="favicon.svg"> 11 </head> 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> 19 <header> 20 <div class="title"> 21 <h1>ASN.1 JavaScript decoder</h1> ··· 37 <div id="tree"></div> 38 </div> 39 <form> 40 + <textarea id="area" rows="8" placeholder="Paste hex or base64 or PEM encoded ASN.1 BER or DER structures here, or load a file."></textarea> 41 <br> 42 <br> 43 <label title="can be slow with big files"><input type="checkbox" id="wantHex" checked="checked"> with hex dump</label> ··· 47 <br><br> 48 <table> 49 <tr><td>Drag or load file:</td><td><input type="file" id="file"></td></tr> 50 + <tr id="rowExamples"><td>Load examples:</td><td> 51 <select id="examples"> 52 <option value="sig-p256-der.p7m">PKCS#7/CMS attached signature (DER)</option> 53 <option value="sig-p256-ber.p7m">PKCS#7/CMS attached signature (BER)</option> 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> 56 <option value="letsencrypt-x3.cer">X.509 certificate: Let's Encrypt X3</option> 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> 60 <option value="pkcs10.pem">PKCS#10 certification request (RFC 2986)</option> 61 + <option value="crl-rfc5280.b64">CRL example (RFC 5280)</option> 62 <option value="cmpv2.b64">CMP PKI message (RFC 4210)</option> 63 + <option value="ldapmessage.b64">LDAP message (RFC 4511)</option> 64 </select> 65 <input id="butExample" type="button" value="load"><br> 66 </td></tr> ··· 72 <div id="help"> 73 <h2>Instructions</h2> 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> 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> 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> 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> 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> 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> 81 <div class="license"> 82 <h3>Copyright</h3> 83 <div><p class="hidden"> 84 ASN.1 JavaScript decoder<br> 85 + Copyright &copy; 2008-2025 Lapo Luchini <a href="mailto:lapo@lapo.it?subject=ASN1js">&lt;lapo@lapo.it&gt;</a><br> 86 <br> 87 Permission to use, copy, modify, and/or distribute this software for any 88 purpose with or without fee is hereby granted, provided that the above ··· 96 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 97 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 98 </p></div> 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> 100 </div> 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> 102 <h3>Links</h3> 103 <ul> 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> 107 <li>previous versions on githack: <select id="tags"><option>[select tag]</option></select></li> 108 <li><a href="http://idf.lapo.it/p/asn1js/">InDefero tracker</a> (currently offline)</li> 109 <li><a href="https://github.com/lapo-luchini/asn1js">github mirror</a></li> 110 <li><a href="https://www.openhub.net/p/asn1js">OpenHub code stats</a></li> 111 </ul> 112 </div> 113 <script type="module" src="index.js"></script> 114 </body> 115 </html>
+39 -56
index.js
··· 1 import { ASN1DOM } from './dom.js'; 2 import { Base64 } from './base64.js'; 3 import { Hex } from './hex.js'; ··· 15 area = id('area'), 16 file = id('file'), 17 examples = id('examples'), 18 - selectTheme = id('theme-select'), 19 selectDefs = id('definitions'), 20 selectTag = id('tags'); 21 ··· 41 function show(asn1) { 42 tree.innerHTML = ''; 43 dump.innerHTML = ''; 44 - tree.appendChild(asn1.toDOM()); 45 if (wantHex.checked) dump.appendChild(asn1.toHexDOM(undefined, trimHex.checked)); 46 } 47 - function decode(der, offset) { 48 offset = offset || 0; 49 try { 50 const asn1 = ASN1DOM.decode(der, offset); ··· 103 text(tree, e); 104 } 105 } 106 - function decodeText(val) { 107 try { 108 let der = reHex.test(val) ? Hex.decode(val) : Base64.unarmor(val); 109 decode(der); ··· 112 dump.innerHTML = ''; 113 } 114 } 115 - function decodeBinaryString(str) { 116 let der; 117 try { 118 if (reHex.test(str)) der = Hex.decode(str); ··· 125 } 126 } 127 // set up buttons 128 - id('butDecode').onclick = function () { 129 - decodeText(area.value); 130 }; 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 - } 175 } 176 - setTheme(); 177 - selectTheme.addEventListener('change', function () { 178 - localStorage.setItem('theme', selectTheme.value); 179 - setTheme(); 180 - }); 181 // this is only used if window.FileReader 182 function read(f) { 183 area.value = ''; // clear text area, will get b64 content
··· 1 + import './theme.js'; 2 import { ASN1DOM } from './dom.js'; 3 import { Base64 } from './base64.js'; 4 import { Hex } from './hex.js'; ··· 16 area = id('area'), 17 file = id('file'), 18 examples = id('examples'), 19 selectDefs = id('definitions'), 20 selectTag = id('tags'); 21 ··· 41 function show(asn1) { 42 tree.innerHTML = ''; 43 dump.innerHTML = ''; 44 + let ul = document.createElement('ul'); 45 + ul.className = 'treecollapse'; 46 + tree.appendChild(ul); 47 + ul.appendChild(asn1.toDOM()); 48 if (wantHex.checked) dump.appendChild(asn1.toHexDOM(undefined, trimHex.checked)); 49 } 50 + export function decode(der, offset) { 51 offset = offset || 0; 52 try { 53 const asn1 = ASN1DOM.decode(der, offset); ··· 106 text(tree, e); 107 } 108 } 109 + export function decodeText(val) { 110 try { 111 let der = reHex.test(val) ? Hex.decode(val) : Base64.unarmor(val); 112 decode(der); ··· 115 dump.innerHTML = ''; 116 } 117 } 118 + export function decodeBinaryString(str) { 119 let der; 120 try { 121 if (reHex.test(str)) der = Hex.decode(str); ··· 128 } 129 } 130 // set up buttons 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 + }, 158 }; 159 + for (const [name, onClick] of Object.entries(butClickHandlers)) { 160 + let elem = id(name); 161 + if (elem) 162 + elem.onclick = onClick; 163 } 164 // this is only used if window.FileReader 165 function read(f) { 166 area.value = ''; // clear text area, will get b64 content
+15 -9
int10.js
··· 1 // Big integer base-10 printing library 2 - // Copyright (c) 2008-2023 Lapo Luchini <lapo@lapo.it> 3 4 // Permission to use, copy, modify, and/or distribute this software for any 5 // purpose with or without fee is hereby granted, provided that the above 6 // copyright notice and this permission notice appear in all copies. 7 - // 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ··· 13 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 16 - let max = 10000000000000; // biggest 10^n integer that can still fit 2^53 when multiplied by 256 17 18 export class Int10 { 19 /** ··· 26 27 /** 28 * Multiply value by m and add c. 29 - * @param {number} m - multiplier, must be < =256 30 - * @param {number} c - value to add 31 */ 32 mulAdd(m, c) { 33 // assert(m <= 256) 34 let b = this.buf, 35 l = b.length, 36 i, t; ··· 71 72 /** 73 * Convert to decimal string representation. 74 - * @param {*} base - optional value, only value accepted is 10 75 */ 76 - toString(base) { 77 - if ((base || 10) != 10) 78 - throw 'only base 10 is supported'; 79 let b = this.buf, 80 s = b[b.length - 1].toString(); 81 for (let i = b.length - 2; i >= 0; --i) ··· 86 /** 87 * Convert to Number value representation. 88 * Will probably overflow 2^53 and thus become approximate. 89 */ 90 valueOf() { 91 let b = this.buf, ··· 97 98 /** 99 * Return value as a simple Number (if it is <= 10000000000000), or return this. 100 */ 101 simplify() { 102 let b = this.buf;
··· 1 // Big integer base-10 printing library 2 + // Copyright (c) 2008 Lapo Luchini <lapo@lapo.it> 3 4 // Permission to use, copy, modify, and/or distribute this software for any 5 // purpose with or without fee is hereby granted, provided that the above 6 // copyright notice and this permission notice appear in all copies. 7 + // 8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ··· 13 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 16 + /** Biggest 10^n integer that can still fit 2^53 when multiplied by 256. */ 17 + const max = 10000000000000; 18 19 export class Int10 { 20 /** ··· 27 28 /** 29 * Multiply value by m and add c. 30 + * @param {number} m - multiplier, must be 0<m<=256 31 + * @param {number} c - value to add, must be c>=0 32 */ 33 mulAdd(m, c) { 34 + // assert(m > 0) 35 // assert(m <= 256) 36 + // assert(c >= 0) 37 let b = this.buf, 38 l = b.length, 39 i, t; ··· 74 75 /** 76 * Convert to decimal string representation. 77 + * @param {number} [base=10] - optional value, only value accepted is 10 78 + * @returns {string} The decimal string representation. 79 */ 80 + toString(base = 10) { 81 + if (base != 10) 82 + throw new Error('only base 10 is supported'); 83 let b = this.buf, 84 s = b[b.length - 1].toString(); 85 for (let i = b.length - 2; i >= 0; --i) ··· 90 /** 91 * Convert to Number value representation. 92 * Will probably overflow 2^53 and thus become approximate. 93 + * @returns {number} The numeric value. 94 */ 95 valueOf() { 96 let b = this.buf, ··· 102 103 /** 104 * Return value as a simple Number (if it is <= 10000000000000), or return this. 105 + * @returns {number | Int10} The simplified value. 106 */ 107 simplify() { 108 let b = this.buf;
-1
oids.js
··· 2722 "1.3.6.1.4.1.40869.1.1.22.3": { "d": "TWCA EV policy", "c": "TWCA Root Certification Authority" }, 2723 "2.16.840.1.113733.1.7.23.6": { "d": "VeriSign EV policy", "c": "VeriSign Class 3 Public Primary Certification Authority" }, 2724 "2.16.840.1.114171.500.9": { "d": "Wells Fargo EV policy", "c": "Wells Fargo WellsSecure Public Root Certificate Authority" }, 2725 - "END": "" 2726 };
··· 2722 "1.3.6.1.4.1.40869.1.1.22.3": { "d": "TWCA EV policy", "c": "TWCA Root Certification Authority" }, 2723 "2.16.840.1.113733.1.7.23.6": { "d": "VeriSign EV policy", "c": "VeriSign Class 3 Public Primary Certification Authority" }, 2724 "2.16.840.1.114171.500.9": { "d": "Wells Fargo EV policy", "c": "Wells Fargo WellsSecure Public Root Certificate Authority" }, 2725 };
+41 -11
package.json
··· 1 { 2 "name": "@lapo/asn1js", 3 - "version": "1.3.0", 4 "description": "Generic ASN.1 parser/decoder that can decode any valid ASN.1 DER or BER structures.", 5 "type": "module", 6 "main": "asn1.js", ··· 13 "license": "ISC", 14 "bugs": { "url": "https://github.com/lapo-luchini/asn1js/issues" }, 15 "homepage": "https://lapo.it/asn1js/", 16 - "files": [ "asn1.js", "base64.js", "hex.js", "int10.js", "oids.js" ], 17 "scripts": { 18 - "lint": "npx eslint asn1.js base64.js hex.js int10.js oids.js tags.js index.js parseRFC.js dumpASN1.js", 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" 22 }, 23 "engines": { 24 "node": ">=12.20.0" 25 }, 26 "devDependencies": { 27 - "eslint": "^8.34.0" 28 }, 29 "eslintConfig": { 30 "env": { ··· 43 "rules": { 44 "strict": [ "error", "function" ], 45 "indent": [ "error", 4 ], 46 "linebreak-style": [ "error", "unix" ], 47 "semi": [ "warn", "always" ], 48 "quotes": [ "error", "single", { "avoidEscape": true } ], 49 "no-var": [ "warn" ], 50 - "comma-dangle": [ "error", "never" ] 51 }, 52 "overrides": [ 53 { 54 "files": [ "test.js", "parseRFC.js", "dumpASN1.js" ], 55 "parserOptions": { 56 "ecmaVersion": 2021 57 }, 58 "rules": { 59 - "strict": [ "error", "global" ], 60 - "comma-dangle": [ "error", "always-multiline" ] 61 } 62 }, { 63 "files": [ "oids.js" ], ··· 66 "quotes": [ "warn", "double" ] 67 } 68 }, { 69 - "files": [ "tags.js" ], 70 "rules": { 71 - "comma-dangle": [ "error", "always-multiline" ], 72 "quotes": [ "warn", "double" ] 73 } 74 }, { 75 "files": [ "defs.js" ], 76 "parserOptions": { 77 "ecmaVersion": 2021 78 } 79 } 80 ]
··· 1 { 2 "name": "@lapo/asn1js", 3 + "version": "2.0.6", 4 "description": "Generic ASN.1 parser/decoder that can decode any valid ASN.1 DER or BER structures.", 5 "type": "module", 6 "main": "asn1.js", ··· 13 "license": "ISC", 14 "bugs": { "url": "https://github.com/lapo-luchini/asn1js/issues" }, 15 "homepage": "https://lapo.it/asn1js/", 16 + "files": [ "asn1.js", "base64.js", "hex.js", "int10.js", "dom.js", "defs.js", "oids.js", "rfcdef.js", "dumpASN1.js" ], 17 "scripts": { 18 + "lint": "npx eslint asn1.js base64.js hex.js int10.js dom.js defs.js oids.js rfcdef.js tags.js context.js index.js parseRFC.js dumpASN1.js test.js testDefs.js vite.config.js theme.js", 19 "lint-action": "npx @action-validator/cli .github/workflows/node.js.yml", 20 + "build": "vite build", 21 + "serve": "npx -p local-web-server ws", 22 + "test": "node test", 23 + "testdefs": "node testDefs" 24 + }, 25 + "bin": { 26 + "dumpASN1": "./dumpASN1.js" 27 }, 28 "engines": { 29 "node": ">=12.20.0" 30 }, 31 "devDependencies": { 32 + "@rollup/wasm-node": "^4.25.0", 33 + "eslint": "^8.57.1", 34 + "htmlparser2": "^9.1.0", 35 + "vite": "^5.4.10", 36 + "vite-plugin-dom": "^1.0.4", 37 + "vite-plugin-singlefile": "^2.0.3" 38 + }, 39 + "overrides": { 40 + "rollup": "npm:@rollup/wasm-node" 41 + }, 42 + "pnpm": { 43 + "overrides": { 44 + "rollup": "npm:@rollup/wasm-node" 45 + } 46 }, 47 "eslintConfig": { 48 "env": { ··· 61 "rules": { 62 "strict": [ "error", "function" ], 63 "indent": [ "error", 4 ], 64 + "no-trailing-spaces": [ "error" ], 65 "linebreak-style": [ "error", "unix" ], 66 + "eol-last": [ "error", "always" ], 67 "semi": [ "warn", "always" ], 68 "quotes": [ "error", "single", { "avoidEscape": true } ], 69 "no-var": [ "warn" ], 70 + "comma-dangle": [ "error", "always-multiline" ] 71 }, 72 "overrides": [ 73 { 74 + "files": [ "defs.js" ], 75 + "parserOptions": { 76 + "ecmaVersion": 2020 77 + } 78 + }, { 79 "files": [ "test.js", "parseRFC.js", "dumpASN1.js" ], 80 "parserOptions": { 81 "ecmaVersion": 2021 82 }, 83 "rules": { 84 + "strict": [ "error", "global" ] 85 } 86 }, { 87 "files": [ "oids.js" ], ··· 90 "quotes": [ "warn", "double" ] 91 } 92 }, { 93 + "files": [ "tags.js", "rfcdef.js" ], 94 "rules": { 95 + "indent": [ "error", 2, { "ignoredNodes": [ "Program > ExpressionStatement > CallExpression > FunctionExpression > BlockStatement > ExpressionStatement[directive='use strict']:first-child" ] } ], 96 + "comma-dangle": "off", 97 "quotes": [ "warn", "double" ] 98 } 99 }, { 100 "files": [ "defs.js" ], 101 "parserOptions": { 102 "ecmaVersion": 2021 103 + } 104 + }, { 105 + "files": [ "testDefs.js" ], 106 + "parserOptions": { 107 + "ecmaVersion": 2022 108 } 109 } 110 ]
+73 -8
parseRFC.js
··· 1 #! /usr/bin/env node 2 - 'use strict'; 3 4 import * as fs from 'node:fs'; 5 ··· 46 4210: [ 47 [ /^\s+-- .*\r?\n/mg, '' ], // comments 48 ], 49 }; 50 51 // const reWhitespace = /(?:\s|--(?:[}-]?[^\n}-])*(?:\n|--))*/y; ··· 53 const reIdentifier = /[a-zA-Z](?:[-]?[a-zA-Z0-9])*/y; 54 const reNumber = /0|[1-9][0-9]*/y; 55 const reToken = /[(){},[\];]|::=|OPTIONAL|DEFAULT|NULL|TRUE|FALSE|\.\.|OF|SIZE|MIN|MAX|DEFINED BY|DEFINITIONS|TAGS|BEGIN|EXPORTS|IMPORTS|FROM|END/y; 56 - 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; 57 const reTagClass = /UNIVERSAL|APPLICATION|PRIVATE|/y; 58 const reTagType = /IMPLICIT|EXPLICIT|/y; 59 const reTagDefault = /(AUTOMATIC|IMPLICIT|EXPLICIT) TAGS|/y; ··· 214 if (this.tryToken('DEFINED BY')) 215 x.definedBy = this.parseIdentifier(); 216 break; 217 case 'BOOLEAN': 218 case 'OCTET STRING': 219 case 'OBJECT IDENTIFIER': ··· 278 this.expectToken(')'); 279 } 280 break; 281 default: 282 - x.content = 'TODO:unknown'; 283 } 284 } catch (e) { 285 console.log('[debug] parseBuiltinType content', e); 286 - x.content = 'TODO:exception'; 287 } 288 return x; 289 } ··· 295 let plicit = this.getRegEx('explicit/implicit', reTagType); 296 if (plicit == '') plicit = currentMod.tagDefault; 297 let x = this.parseType(); 298 return { 299 - name: '[' + t + ']', 300 type: 'tag', 301 'class': tagClass, 302 explicit: (plicit == 'EXPLICIT'), ··· 350 } else { 351 if (id in currentMod.values) // defined in local module 352 val = currentMod.values[id].value; 353 - else 354 val = searchImportedValue(id); 355 } 356 } 357 if (v.length) v += '.'; ··· 502 asn1[currentMod.oid] = currentMod; 503 } 504 /*asn1 = Object.keys(asn1).sort().reduce( 505 - (obj, key) => { 506 obj[key] = asn1[key]; 507 return obj; 508 - }, 509 {} 510 );*/ 511 fs.writeFileSync(process.argv[3], JSON.stringify(asn1, null, 2) + '\n', 'utf8');
··· 1 #! /usr/bin/env node 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 18 import * as fs from 'node:fs'; 19 ··· 60 4210: [ 61 [ /^\s+-- .*\r?\n/mg, '' ], // comments 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 + ], 93 }; 94 95 // const reWhitespace = /(?:\s|--(?:[}-]?[^\n}-])*(?:\n|--))*/y; ··· 97 const reIdentifier = /[a-zA-Z](?:[-]?[a-zA-Z0-9])*/y; 98 const reNumber = /0|[1-9][0-9]*/y; 99 const reToken = /[(){},[\];]|::=|OPTIONAL|DEFAULT|NULL|TRUE|FALSE|\.\.|OF|SIZE|MIN|MAX|DEFINED BY|DEFINITIONS|TAGS|BEGIN|EXPORTS|IMPORTS|FROM|END/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; 101 const reTagClass = /UNIVERSAL|APPLICATION|PRIVATE|/y; 102 const reTagType = /IMPLICIT|EXPLICIT|/y; 103 const reTagDefault = /(AUTOMATIC|IMPLICIT|EXPLICIT) TAGS|/y; ··· 258 if (this.tryToken('DEFINED BY')) 259 x.definedBy = this.parseIdentifier(); 260 break; 261 + case 'NULL': 262 case 'BOOLEAN': 263 case 'OCTET STRING': 264 case 'OBJECT IDENTIFIER': ··· 323 this.expectToken(')'); 324 } 325 break; 326 + case 'UTCTime': 327 + case 'GeneralizedTime': 328 + break; 329 default: 330 + x.warning = 'type unknown'; 331 } 332 } catch (e) { 333 console.log('[debug] parseBuiltinType content', e); 334 + x.warning = 'type exception'; 335 } 336 return x; 337 } ··· 343 let plicit = this.getRegEx('explicit/implicit', reTagType); 344 if (plicit == '') plicit = currentMod.tagDefault; 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 + } 360 return { 361 + name, 362 type: 'tag', 363 'class': tagClass, 364 explicit: (plicit == 'EXPLICIT'), ··· 412 } else { 413 if (id in currentMod.values) // defined in local module 414 val = currentMod.values[id].value; 415 + else try { 416 val = searchImportedValue(id); 417 + } catch (e) { 418 + this.exception(e.message); 419 + } 420 } 421 } 422 if (v.length) v += '.'; ··· 567 asn1[currentMod.oid] = currentMod; 568 } 569 /*asn1 = Object.keys(asn1).sort().reduce( 570 + (obj, key) => { 571 obj[key] = asn1[key]; 572 return obj; 573 + }, 574 {} 575 );*/ 576 fs.writeFileSync(process.argv[3], JSON.stringify(asn1, null, 2) + '\n', 'utf8');
+13 -13
release.sh
··· 1 #!/bin/sh 2 set -e 3 FILES=" 4 - asn1.js oids.js defs.js base64.js hex.js int10.js dom.js rfcdef.js test.js tags.js 5 - index.css index-dark.css index.js index.html favicon.svg 6 README.md LICENSE 7 updateOID.sh check.sh 8 examples 9 " 10 - mtn automate tags it.lapo.asn1js | \ 11 awk '/^revision/ { print substr($2, 2, length($2) - 2)}' | \ 12 while read rev; do 13 mtn automate certs $rev | awk -v q='"' ' ··· 19 ' 20 done | sort -r | awk -v q='"' ' 21 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 {" 28 } 29 - { print " " q $2 q ":" q $1 q "," } 30 - END { print "};});" } 31 ' > tags.js 32 - type gsha256sum >/dev/null && SHA256=gsha256sum || SHA256=sha256sum 33 - $SHA256 -t $FILES | gpg --clearsign > sha256sums.asc 34 7z a -tzip -mx=9 asn1js.zip $FILES sha256sums.asc 35 rsync -Pvrtz asn1js.zip $FILES lapo.it:www/asn1js/
··· 1 #!/bin/sh 2 set -e 3 FILES=" 4 + asn1.js oids.js defs.js base64.js hex.js int10.js dom.js context.js theme.js 5 + rfcdef.js test.js tags.js 6 + index.html index.css index.js index-local.html 7 + favicon.svg tree-icon-light.svg tree-icon-dark.svg 8 README.md LICENSE 9 updateOID.sh check.sh 10 examples 11 " 12 + mtn automate tags 'it.lapo.asn1js{,.*}' | \ 13 awk '/^revision/ { print substr($2, 2, length($2) - 2)}' | \ 14 while read rev; do 15 mtn automate certs $rev | awk -v q='"' ' ··· 21 ' 22 done | sort -r | awk -v q='"' ' 23 BEGIN { 24 + print "export const tags = {" 25 } 26 + { print " " q $2 q ": " q $1 q "," } 27 + END { print "};" } 28 ' > tags.js 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 7z a -tzip -mx=9 asn1js.zip $FILES sha256sums.asc 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 2 // Copyright (C) The IETF Trust (2008) 3 // as far as I can tell this file is allowed under the following clause: 4 // It is acceptable under the current IETF rules (RFC 5378) to modify extracted code if necessary. ··· 1606 { 1607 "id": "utcTime", 1608 "name": "UTCTime", 1609 - "type": "builtin", 1610 - "content": "TODO:unknown" 1611 }, 1612 { 1613 "id": "generalTime", 1614 "name": "GeneralizedTime", 1615 - "type": "builtin", 1616 - "content": "TODO:unknown" 1617 } 1618 ] 1619 } ··· 1985 "CountryName": { 1986 "name": "CountryName", 1987 "type": { 1988 - "name": "[1]", 1989 "type": "tag", 1990 "class": "APPLICATION", 1991 "explicit": true, ··· 2017 "AdministrationDomainName": { 2018 "name": "AdministrationDomainName", 2019 "type": { 2020 - "name": "[2]", 2021 "type": "tag", 2022 "class": "APPLICATION", 2023 "explicit": true, ··· 3382 "name": "", 3383 "type": { 3384 "name": "GeneralizedTime", 3385 - "type": "builtin", 3386 - "content": "TODO:unknown" 3387 } 3388 } 3389 ], ··· 3400 "name": "", 3401 "type": { 3402 "name": "GeneralizedTime", 3403 - "type": "builtin", 3404 - "content": "TODO:unknown" 3405 } 3406 } 3407 ], ··· 4494 "name": "InvalidityDate", 4495 "type": { 4496 "name": "GeneralizedTime", 4497 - "type": "builtin", 4498 - "content": "TODO:unknown" 4499 } 4500 } 4501 } ··· 5566 "id": "date", 5567 "name": "GeneralizedTime", 5568 "type": "builtin", 5569 - "content": "TODO:unknown", 5570 "optional": true 5571 }, 5572 { ··· 5629 "id": "date", 5630 "name": "GeneralizedTime", 5631 "type": "builtin", 5632 - "content": "TODO:unknown", 5633 "optional": true 5634 }, 5635 { ··· 6142 { 6143 "id": "utcTime", 6144 "name": "UTCTime", 6145 - "type": "builtin", 6146 - "content": "TODO:unknown" 6147 }, 6148 { 6149 "id": "generalTime", 6150 "name": "GeneralizedTime", 6151 - "type": "builtin", 6152 - "content": "TODO:unknown" 6153 } 6154 ] 6155 } ··· 6664 { 6665 "id": "genTime", 6666 "name": "GeneralizedTime", 6667 - "type": "builtin", 6668 - "content": "TODO:unknown" 6669 }, 6670 { 6671 "id": "accuracy", ··· 7464 "name": "", 7465 "type": { 7466 "name": "NULL", 7467 - "type": "defined" 7468 } 7469 } 7470 ] ··· 8345 "name": "", 8346 "type": { 8347 "name": "GeneralizedTime", 8348 - "type": "builtin", 8349 - "content": "TODO:unknown" 8350 } 8351 } 8352 ], ··· 9649 { 9650 "id": "willBeRevokedAt", 9651 "name": "GeneralizedTime", 9652 - "type": "builtin", 9653 - "content": "TODO:unknown" 9654 }, 9655 { 9656 "id": "badSinceDate", 9657 "name": "GeneralizedTime", 9658 - "type": "builtin", 9659 - "content": "TODO:unknown" 9660 }, 9661 { 9662 "id": "crlDetails", ··· 9724 "name": "PKIConfirmContent", 9725 "type": { 9726 "name": "NULL", 9727 - "type": "defined" 9728 } 9729 }, 9730 "InfoTypeAndValue": { ··· 9851 "optional": true 9852 } 9853 ] 9854 } 9855 ] 9856 }
··· 1 + // content parsed from ASN.1 definitions as found in the following RFCs: 5280 5208 3369 3161 2986 4211 4210 8017 4511 2 // Copyright (C) The IETF Trust (2008) 3 // as far as I can tell this file is allowed under the following clause: 4 // It is acceptable under the current IETF rules (RFC 5378) to modify extracted code if necessary. ··· 1606 { 1607 "id": "utcTime", 1608 "name": "UTCTime", 1609 + "type": "builtin" 1610 }, 1611 { 1612 "id": "generalTime", 1613 "name": "GeneralizedTime", 1614 + "type": "builtin" 1615 } 1616 ] 1617 } ··· 1983 "CountryName": { 1984 "name": "CountryName", 1985 "type": { 1986 + "name": "Application 1", 1987 "type": "tag", 1988 "class": "APPLICATION", 1989 "explicit": true, ··· 2015 "AdministrationDomainName": { 2016 "name": "AdministrationDomainName", 2017 "type": { 2018 + "name": "Application 2", 2019 "type": "tag", 2020 "class": "APPLICATION", 2021 "explicit": true, ··· 3380 "name": "", 3381 "type": { 3382 "name": "GeneralizedTime", 3383 + "type": "builtin" 3384 } 3385 } 3386 ], ··· 3397 "name": "", 3398 "type": { 3399 "name": "GeneralizedTime", 3400 + "type": "builtin" 3401 } 3402 } 3403 ], ··· 4490 "name": "InvalidityDate", 4491 "type": { 4492 "name": "GeneralizedTime", 4493 + "type": "builtin" 4494 } 4495 } 4496 } ··· 5561 "id": "date", 5562 "name": "GeneralizedTime", 5563 "type": "builtin", 5564 "optional": true 5565 }, 5566 { ··· 5623 "id": "date", 5624 "name": "GeneralizedTime", 5625 "type": "builtin", 5626 "optional": true 5627 }, 5628 { ··· 6135 { 6136 "id": "utcTime", 6137 "name": "UTCTime", 6138 + "type": "builtin" 6139 }, 6140 { 6141 "id": "generalTime", 6142 "name": "GeneralizedTime", 6143 + "type": "builtin" 6144 } 6145 ] 6146 } ··· 6655 { 6656 "id": "genTime", 6657 "name": "GeneralizedTime", 6658 + "type": "builtin" 6659 }, 6660 { 6661 "id": "accuracy", ··· 7454 "name": "", 7455 "type": { 7456 "name": "NULL", 7457 + "type": "builtin" 7458 } 7459 } 7460 ] ··· 8335 "name": "", 8336 "type": { 8337 "name": "GeneralizedTime", 8338 + "type": "builtin" 8339 } 8340 } 8341 ], ··· 9638 { 9639 "id": "willBeRevokedAt", 9640 "name": "GeneralizedTime", 9641 + "type": "builtin" 9642 }, 9643 { 9644 "id": "badSinceDate", 9645 "name": "GeneralizedTime", 9646 + "type": "builtin" 9647 }, 9648 { 9649 "id": "crlDetails", ··· 9711 "name": "PKIConfirmContent", 9712 "type": { 9713 "name": "NULL", 9714 + "type": "builtin" 9715 } 9716 }, 9717 "InfoTypeAndValue": { ··· 9838 "optional": true 9839 } 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 + } 11870 } 11871 ] 11872 }
+16 -9
tags.js
··· 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", 11 };
··· 1 export const tags = { 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", 18 };
+135 -35
test.js
··· 1 #!/usr/bin/env node 2 3 - import { ASN1 } from './asn1.js'; 4 import { Hex } from './hex.js'; 5 6 - const 7 - all = (process.argv[2] == 'all'); 8 9 - const tests = [ 10 // RSA Laboratories technical notes from https://luca.ntop.org/Teaching/Appunti/asn1.html 11 ['0304066E5DC0', '(18 bit)\n011011100101110111', 'ntop, bit string: DER encoding'], 12 ['0304066E5DE0', '(18 bit)\n011011100101110111', 'ntop, bit string: padded with "100000"'], ··· 36 ['170D3931303530363233343534305A', '1991-05-06 23:45:40 UTC', 'ntop, utc time: UTC'], 37 ['17113931303530363136343534302D30373030', '1991-05-06 16:45:40 UTC-07:00', 'ntop, utc time: PDT'], 38 // inspired by http://luca.ntop.org/Teaching/Appunti/asn1.html 39 - ['0304086E5DC0', 'Exception:\nInvalid BitString with unusedBits=8', 'bit string: invalid unusedBits'], 40 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa379076(v=vs.85).aspx 41 ['30820319308202820201003023310F300D0603550403130654657374434E3110300E060355040A1307546573744F726730819F300D06092A864886F70D010101050003818D00308189028181008FE2412A08E851A88CB3E853E7D54950B3278A2BCBEAB54273EA0257CC6533EE882061A11756C12418E3A808D3BED931F3370B94B8CC43080B7024F79CB18D5DD66D82D0540984F89F970175059C89D4D5C91EC913D72A6B309119D6D442E0C49D7C9271E1B22F5C8DEEF0F1171ED25F315BB19CBC2055BF3A37424575DC90650203010001A08201B4301A060A2B0601040182370D0203310C160A362E302E353336312E323042060A2B0601040182370D0201313430321E260043006500720074006900660069006300610074006500540065006D0070006C0061007400651E080055007300650072305706092B0601040182371514314A30480201090C237669636833642E6A646F6D6373632E6E74746573742E6D6963726F736F66742E636F6D0C154A444F4D4353435C61646D696E6973747261746F720C07636572747265713074060A2B0601040182370D0202316630640201011E5C004D006900630072006F0073006F0066007400200045006E00680061006E006300650064002000430072007900700074006F0067007200610070006800690063002000500072006F00760069006400650072002000760031002E003003010030818206092A864886F70D01090E31753073301706092B0601040182371402040A1E08005500730065007230290603551D2504223020060A2B0601040182370A030406082B0601050507030406082B06010505070302300E0603551D0F0101FF0404030205A0301D0603551D0E041604143C0F73DAF8EF41D83AEABE922A5D2C966A7B9454300D06092A864886F70D01010505000381810047EB995ADF9E700DFBA73132C15F5C24C2E0BFC624AF15660EB86A2EAB2BC4971FE3CBDC63A525ECC7B428616636A1311BBFDDD0FCBF1794901DE55EC7115EC9559FEBA33E14C799A6CBBAA1460F39D444C4C84B760E205D6DA9349ED4D58742EB2426511490B40F065E5288327A9520A0FDF7E57D60DD72689BF57B058F6D1E', 42 '(3 elem)', 'PKCS#10 request'], ··· 86 ['0420041EE4E3B7ED350CC24D034E436D9A1CB15BB1E328D37062FB82E84618AB0A3C', '(32 byte)\n041EE4E3B7ED350CC24D034E436D9A1CB15BB1E328D37062FB82E84618AB0A3C', 'Do not mix encapsulated and structured octet strings'], // GitHub issue #47 87 ['181531393835313130363231303632372E332D31323334', '1985-11-06 21:06:27.3 UTC-12:34', 'UTC offsets with minutes'], // GitHub issue #54 88 ['181331393835313130363231303632372E332B3134', '1985-11-06 21:06:27.3 UTC+14:00', 'UTC offset +13 and +14'], // GitHub issue #54 89 - ]; 90 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);
··· 1 #!/usr/bin/env node 2 3 + import { ASN1, Stream } from './asn1.js'; 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'); 9 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 + } 51 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 + }, [ 90 // RSA Laboratories technical notes from https://luca.ntop.org/Teaching/Appunti/asn1.html 91 ['0304066E5DC0', '(18 bit)\n011011100101110111', 'ntop, bit string: DER encoding'], 92 ['0304066E5DE0', '(18 bit)\n011011100101110111', 'ntop, bit string: padded with "100000"'], ··· 116 ['170D3931303530363233343534305A', '1991-05-06 23:45:40 UTC', 'ntop, utc time: UTC'], 117 ['17113931303530363136343534302D30373030', '1991-05-06 16:45:40 UTC-07:00', 'ntop, utc time: PDT'], 118 // inspired by http://luca.ntop.org/Teaching/Appunti/asn1.html 119 + ['0304086E5DC0', 'Exception:\nError: Invalid BitString with unusedBits=8', 'bit string: invalid unusedBits'], 120 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa379076(v=vs.85).aspx 121 ['30820319308202820201003023310F300D0603550403130654657374434E3110300E060355040A1307546573744F726730819F300D06092A864886F70D010101050003818D00308189028181008FE2412A08E851A88CB3E853E7D54950B3278A2BCBEAB54273EA0257CC6533EE882061A11756C12418E3A808D3BED931F3370B94B8CC43080B7024F79CB18D5DD66D82D0540984F89F970175059C89D4D5C91EC913D72A6B309119D6D442E0C49D7C9271E1B22F5C8DEEF0F1171ED25F315BB19CBC2055BF3A37424575DC90650203010001A08201B4301A060A2B0601040182370D0203310C160A362E302E353336312E323042060A2B0601040182370D0201313430321E260043006500720074006900660069006300610074006500540065006D0070006C0061007400651E080055007300650072305706092B0601040182371514314A30480201090C237669636833642E6A646F6D6373632E6E74746573742E6D6963726F736F66742E636F6D0C154A444F4D4353435C61646D696E6973747261746F720C07636572747265713074060A2B0601040182370D0202316630640201011E5C004D006900630072006F0073006F0066007400200045006E00680061006E006300650064002000430072007900700074006F0067007200610070006800690063002000500072006F00760069006400650072002000760031002E003003010030818206092A864886F70D01090E31753073301706092B0601040182371402040A1E08005500730065007230290603551D2504223020060A2B0601040182370A030406082B0601050507030406082B06010505070302300E0603551D0F0101FF0404030205A0301D0603551D0E041604143C0F73DAF8EF41D83AEABE922A5D2C966A7B9454300D06092A864886F70D01010505000381810047EB995ADF9E700DFBA73132C15F5C24C2E0BFC624AF15660EB86A2EAB2BC4971FE3CBDC63A525ECC7B428616636A1311BBFDDD0FCBF1794901DE55EC7115EC9559FEBA33E14C799A6CBBAA1460F39D444C4C84B760E205D6DA9349ED4D58742EB2426511490B40F065E5288327A9520A0FDF7E57D60DD72689BF57B058F6D1E', 122 '(3 elem)', 'PKCS#10 request'], ··· 166 ['0420041EE4E3B7ED350CC24D034E436D9A1CB15BB1E328D37062FB82E84618AB0A3C', '(32 byte)\n041EE4E3B7ED350CC24D034E436D9A1CB15BB1E328D37062FB82E84618AB0A3C', 'Do not mix encapsulated and structured octet strings'], // GitHub issue #47 167 ['181531393835313130363231303632372E332D31323334', '1985-11-06 21:06:27.3 UTC-12:34', 'UTC offsets with minutes'], // GitHub issue #54 168 ['181331393835313130363231303632372E332B3134', '1985-11-06 21:06:27.3 UTC+14:00', 'UTC offset +13 and +14'], // GitHub issue #54 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 + ])); 214 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 } 44 } 45 END { 46 - print "\"END\": \"\"" 47 print "};" 48 } 49 ' >oids.js
··· 43 } 44 } 45 END { 46 print "};" 47 } 48 ' >oids.js
+1 -1
updateRFC.sh
··· 1 #/bin/sh 2 - RFCs="5280 5208 3369 3161 2986 4211 4210" 3 downloadRFC() { 4 URL="https://www.ietf.org/rfc/rfc$1.txt" 5 if [ -x /usr/bin/fetch ]; then
··· 1 #/bin/sh 2 + RFCs="5280 5208 3369 3161 2986 4211 4210 8017 4511" 3 downloadRFC() { 4 URL="https://www.ietf.org/rfc/rfc$1.txt" 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 + });