From e5ba3d4b7edc49e19d0c0fee4cacfba3d6983baa Mon Sep 17 00:00:00 2001 From: Leon Zandman Date: Sun, 17 May 2026 00:24:39 +0200 Subject: [PATCH] Setup + ASN.1 utilities (PublicKey bundle) --- package-lock.json | 43 +-- package.json | 3 + plan-jsrsasign.md | 14 +- src/core/lib/Asn1.mjs | 338 ++++++++++++++++++ src/core/operations/HexToObjectIdentifier.mjs | 4 +- src/core/operations/HexToPEM.mjs | 4 +- src/core/operations/ObjectIdentifierToHex.mjs | 4 +- src/core/operations/ParseASN1HexString.mjs | 9 +- tests/node/tests/nodeApi.mjs | 8 +- tests/node/tests/operations.mjs | 15 +- tests/operations/index.mjs | 1 + tests/operations/tests/ASN1.mjs | 95 +++++ 12 files changed, 497 insertions(+), 41 deletions(-) create mode 100644 src/core/lib/Asn1.mjs create mode 100644 tests/operations/tests/ASN1.mjs diff --git a/package-lock.json b/package-lock.json index ea1a82bf..9e3799a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,11 +13,14 @@ "@alexaltea/capstone-js": "^3.0.5", "@astronautlabs/amf": "^0.0.6", "@blu3r4y/lzma": "^2.3.3", + "@noble/curves": "^2.2.0", "@noble/hashes": "2.2.0", + "@peculiar/x509": "^1.14.3", "@wavesenterprise/crypto-gost-js": "^2.1.0-RC1", "@xmldom/xmldom": "^0.8.13", "argon2-browser": "^1.18.0", "arrive": "^2.5.3", + "asn1js": "^3.0.10", "assert": "^2.1.0", "avsc": "^5.7.9", "bcryptjs": "^3.0.3", @@ -4237,6 +4240,21 @@ "archiver": "^5.3.1" } }, + "node_modules/@noble/curves": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.2.0.tgz", + "integrity": "sha512-T/BoHgFXirb0ENSPBquzX0rcjXeM6Lo892a2jlYJkqk83LqZx0l1Of7DzlKJ6jkpvMrkHSnAcgb5JegL8SeIkQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "2.2.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@noble/hashes": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", @@ -4253,7 +4271,6 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.6.1.tgz", "integrity": "sha512-vdG4fBF6Lkirkcl53q6eOdn3XYKt+kJTG59edgRZORlg/3atWWEReRCx5rYE1ZzTTX6vLK5zDMjHh7vbrcXGtw==", - "dev": true, "license": "MIT", "dependencies": { "@peculiar/asn1-schema": "^2.6.0", @@ -4267,7 +4284,6 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.6.1.tgz", "integrity": "sha512-WRWnKfIocHyzFYQTka8O/tXCiBquAPSrRjXbOkHbO4qdmS6loffCEGs+rby6WxxGdJCuunnhS2duHURhjyio6w==", - "dev": true, "license": "MIT", "dependencies": { "@peculiar/asn1-schema": "^2.6.0", @@ -4280,7 +4296,6 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.6.1.tgz", "integrity": "sha512-+Vqw8WFxrtDIN5ehUdvlN2m73exS2JVG0UAyfVB31gIfor3zWEAQPD+K9ydCxaj3MLen9k0JhKpu9LqviuCE1g==", - "dev": true, "license": "MIT", "dependencies": { "@peculiar/asn1-schema": "^2.6.0", @@ -4293,7 +4308,6 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.6.1.tgz", "integrity": "sha512-nB5jVQy3MAAWvq0KY0R2JUZG8bO/bTLpnwyOzXyEh/e54ynGTatAR+csOnXkkVD9AFZ2uL8Z7EV918+qB1qDvw==", - "dev": true, "license": "MIT", "dependencies": { "@peculiar/asn1-cms": "^2.6.1", @@ -4308,7 +4322,6 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.6.1.tgz", "integrity": "sha512-JB5iQ9Izn5yGMw3ZG4Nw3Xn/hb/G38GYF3lf7WmJb8JZUydhVGEjK/ZlFSWhnlB7K/4oqEs8HnfFIKklhR58Tw==", - "dev": true, "license": "MIT", "dependencies": { "@peculiar/asn1-schema": "^2.6.0", @@ -4321,7 +4334,6 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.6.1.tgz", "integrity": "sha512-5EV8nZoMSxeWmcxWmmcolg22ojZRgJg+Y9MX2fnE2bGRo5KQLqV5IL9kdSQDZxlHz95tHvIq9F//bvL1OeNILw==", - "dev": true, "license": "MIT", "dependencies": { "@peculiar/asn1-cms": "^2.6.1", @@ -4338,7 +4350,6 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.6.1.tgz", "integrity": "sha512-1nVMEh46SElUt5CB3RUTV4EG/z7iYc7EoaDY5ECwganibQPkZ/Y2eMsTKB/LeyrUJ+W/tKoD9WUqIy8vB+CEdA==", - "dev": true, "license": "MIT", "dependencies": { "@peculiar/asn1-schema": "^2.6.0", @@ -4351,7 +4362,6 @@ "version": "2.6.0", "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.6.0.tgz", "integrity": "sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==", - "dev": true, "license": "MIT", "dependencies": { "asn1js": "^3.0.6", @@ -4363,7 +4373,6 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.6.1.tgz", "integrity": "sha512-O9jT5F1A2+t3r7C4VT7LYGXqkGLK7Kj1xFpz7U0isPrubwU5PbDoyYtx6MiGst29yq7pXN5vZbQFKRCP+lLZlA==", - "dev": true, "license": "MIT", "dependencies": { "@peculiar/asn1-schema": "^2.6.0", @@ -4376,7 +4385,6 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.6.1.tgz", "integrity": "sha512-tlW6cxoHwgcQghnJwv3YS+9OO1737zgPogZ+CgWRUK4roEwIPzRH4JEiG770xe5HX2ATfCpmX60gurfWIF9dcQ==", - "dev": true, "license": "MIT", "dependencies": { "@peculiar/asn1-schema": "^2.6.0", @@ -4389,7 +4397,6 @@ "version": "1.14.3", "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.3.tgz", "integrity": "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==", - "dev": true, "license": "MIT", "dependencies": { "@peculiar/asn1-cms": "^2.6.0", @@ -5489,14 +5496,13 @@ "license": "MIT" }, "node_modules/asn1js": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.7.tgz", - "integrity": "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==", - "dev": true, + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.10.tgz", + "integrity": "sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==", "license": "BSD-3-Clause", "dependencies": { "pvtsutils": "^1.3.6", - "pvutils": "^1.1.3", + "pvutils": "^1.1.5", "tslib": "^2.8.1" }, "engines": { @@ -15323,7 +15329,6 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", - "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.8.1" @@ -15333,7 +15338,6 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", - "dev": true, "license": "MIT", "engines": { "node": ">=16.0.0" @@ -17418,14 +17422,12 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, "license": "0BSD" }, "node_modules/tsyringe": { "version": "4.10.0", "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz", "integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==", - "dev": true, "license": "MIT", "dependencies": { "tslib": "^1.9.3" @@ -17438,7 +17440,6 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, "license": "0BSD" }, "node_modules/tweetnacl": { diff --git a/package.json b/package.json index e923a5b9..473e5fb2 100644 --- a/package.json +++ b/package.json @@ -96,11 +96,14 @@ "@alexaltea/capstone-js": "^3.0.5", "@astronautlabs/amf": "^0.0.6", "@blu3r4y/lzma": "^2.3.3", + "@noble/curves": "^2.2.0", "@noble/hashes": "2.2.0", + "@peculiar/x509": "^1.14.3", "@wavesenterprise/crypto-gost-js": "^2.1.0-RC1", "@xmldom/xmldom": "^0.8.13", "argon2-browser": "^1.18.0", "arrive": "^2.5.3", + "asn1js": "^3.0.10", "assert": "^2.1.0", "avsc": "^5.7.9", "bcryptjs": "^3.0.3", diff --git a/plan-jsrsasign.md b/plan-jsrsasign.md index 10df27eb..000ab149 100644 --- a/plan-jsrsasign.md +++ b/plan-jsrsasign.md @@ -4,14 +4,16 @@ ## Status -- [ ] PR 1 — Setup + ASN.1 utilities +- [x] PR 1 — Setup + ASN.1 utilities - [ ] PR 2 — SM2 rewrite - [ ] PR 3 — ECDSA primitives - [ ] PR 4 — PEM/JWK conversion + key extraction - [ ] PR 5 — X.509 / CSR / CRL parsing - [ ] PR 6 — Removal -_Notes for next session:_ (none yet) +_Notes for next session:_ +- **PR 2 blocker:** `@noble/curves` v2 dropped the `/sm2` subpath. v2 exposes only `nist`, `secp256k1`, `bls12-381`, `bn254`, `ed25519`, `ed448` and the `abstract/*` primitives. Before starting PR 2, either pin `@noble/curves` to v1 (which still ships sm2 — but check what other v1→v2 API gaps that introduces) or build SM2 on top of the abstract Weierstrass primitive in `@noble/curves/abstract/weierstrass.js` (curve parameters published in GM/T 0003-2012). +- **PR 5 blocker:** `@peculiar/x509` v2 needs a `reflect-metadata` polyfill at every entry point — PR 1 pinned to `^1.14.3` to avoid that. Stay on v1 unless the polyfill cost gets resolved. ## Context @@ -236,6 +238,14 @@ After **PR 6:** Record deviations from the original plan here, newest at the top. One bullet per change: what changed, why, and which PR. +### PR 1 — 2026-05-17 +- Pinned `@peculiar/x509` to `^1.14.3` instead of the latest (`2.x`). v2 hard-requires a `reflect-metadata` import at every entry point and the plan didn't budget for polyfilling every webpack chunk. Sticking with v1 keeps the bundle changes scoped to this PR. +- `@noble/curves` installed at `^2.2.0`. v2 no longer exports an `/sm2` subpath — see PR 2 note in "Notes for next session" above. +- `derToPem` was deliberately made lenient (whitespace stripped, odd length left-padded with `0`, non-hex chars treated as nibble `0`) to preserve the recipe-API tests that piped non-hex output from `To Morse Code` through `Hex to PEM`. The actual base64 emitted now follows standard byte-pair semantics, not jsrsasign's quirky `hex2b64` (3-hex-chars-→-2-base64-chars) layout — so the expected outputs in `tests/node/tests/nodeApi.mjs` for those recipe-format tests were regenerated. +- `dumpAsn1Hex` returns a plain `ASN.1 parse error: …` string when asn1js can't make sense of the input, rather than throwing. jsrsasign produced a best-effort `UNKNOWN() ` dump in this case; replicating that on asn1js would be a meaningful chunk of code and the operation has no automated-fixture exposure of the difference, so we accepted the drift. +- PEM line endings switched from `\r\n` to `\n` (per the cross-PR convention in [AGENTS.md](AGENTS.md)). Updated the `Hex to PEM` and `Parse ASN.1 hex string` golden tests in `tests/node/tests/operations.mjs`. +- New per-op fixture file [tests/operations/tests/ASN1.mjs](tests/operations/tests/ASN1.mjs) covers OID round-trips, the multi-byte OID arc edge case, PEM line wrapping, and basic ASN.1 dumps. Wired in via `tests/operations/index.mjs`. +