From 2c66e413bf45ea19159b9516d02f42a0595649bf Mon Sep 17 00:00:00 2001 From: Leon Zandman Date: Sun, 17 May 2026 19:31:38 +0200 Subject: [PATCH] Removal of `jsrsasign` package and mentions. --- CHANGELOG.md | 4 +++- package-lock.json | 7 ------- package.json | 1 - plan-jsrsasign.md | 9 ++++++-- src/core/lib/Asn1.mjs | 21 ++++++++----------- src/core/lib/Ecdsa.mjs | 11 +++++----- src/core/lib/KeyConvert.mjs | 5 ++--- src/core/lib/PublicKey.mjs | 4 ++-- src/core/lib/SM2.mjs | 4 ++-- src/core/lib/X509.mjs | 7 +++---- src/core/operations/ParseX509Certificate.mjs | 8 +++---- tests/node/tests/operations.mjs | 3 +-- tests/operations/tests/ASN1.mjs | 3 +-- .../operations/tests/ParseX509Certificate.mjs | 4 ++-- 14 files changed, 41 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cec4ea57..1d757816 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ All major and minor version changes will be documented in this file. Details of ## Details +## [Unreleased] +- Removed the unmaintained `jsrsasign` dependency. ASN.1/OID/PEM utilities, SM2, ECDSA, PEM/JWK key conversion, and X.509/CSR/CRL parsing now use `@noble/curves`, `@peculiar/x509`, and `asn1js`; related golden text fixtures were updated during the migration for accepted cosmetic output-format drift. + ## [11.0.0] - 2026-04-28 - Revert sitemap to v8.0.X to fix build/deploy on master [@GCHQDeveloper581] | [#2348] - Node version update from 22 to 24 [@lzandman] [@GCHQDeveloper581] | [#2347] @@ -1220,4 +1223,3 @@ Breaking changes: [#2273]: https://github.com/gchq/CyberChef/pull/2273 [#2342]: https://github.com/gchq/CyberChef/pull/2342 [#1922]: https://github.com/gchq/CyberChef/pull/1922 - diff --git a/package-lock.json b/package-lock.json index 9e3799a0..a0d44da5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,7 +65,6 @@ "jsonpath-plus": "^10.4.0", "jsonwebtoken": "9.0.3", "jsqr": "^1.4.0", - "jsrsasign": "^11.1.3", "kbpgp": "^2.1.17", "libbzip2-wasm": "0.0.4", "libyara-wasm": "^1.2.1", @@ -12569,12 +12568,6 @@ "integrity": "sha512-dxLob7q65Xg2DvstYkRpkYtmKm2sPJ9oFhrhmudT1dZvNFFTlroai3AWSpLey/w5vMcLBXRgOJsbXpdN9HzU/A==", "license": "Apache-2.0" }, - "node_modules/jsrsasign": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-11.1.3.tgz", - "integrity": "sha512-nPnK5D/4lv0Dwr7TlzrKtAd8JlLZwFTqTUUB3NQCbtdobcRcohGFxjbPySDVh74iWUudcCsapYT6OxoyhJLhhA==", - "license": "MIT" - }, "node_modules/jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", diff --git a/package.json b/package.json index 473e5fb2..4e8919cd 100644 --- a/package.json +++ b/package.json @@ -148,7 +148,6 @@ "jsonpath-plus": "^10.4.0", "jsonwebtoken": "9.0.3", "jsqr": "^1.4.0", - "jsrsasign": "^11.1.3", "kbpgp": "^2.1.17", "libbzip2-wasm": "0.0.4", "libyara-wasm": "^1.2.1", diff --git a/plan-jsrsasign.md b/plan-jsrsasign.md index 9bd394dc..a561bba0 100644 --- a/plan-jsrsasign.md +++ b/plan-jsrsasign.md @@ -9,9 +9,10 @@ - [x] PR 3 — ECDSA primitives - [x] PR 4 — PEM/JWK conversion + key extraction - [x] PR 5 — X.509 / CSR / CRL parsing -- [ ] PR 6 — Removal +- [x] PR 6 — Removal _Notes for next session:_ +- **PR 6 complete:** dependency removed, source tree is free of runtime references, and the remaining migration references are documentation/changelog only. - **PR 2 resolved:** SM2 is now built on `weierstrass(...)` + `ecdh(...)` from `@noble/curves/abstract/weierstrass.js` (curve params per GM/T 0003-2012). No `/sm2` subpath needed. - **PR 3 resolved:** ECDSA primitives migrated; new [src/core/lib/Ecdsa.mjs](src/core/lib/Ecdsa.mjs) is the shared helper module. Existing ECDSA fixture set passes unchanged (sign↔verify round-trips and the canned P-256 signature fixtures both verify against `lowS: false`). - **PR 4 resolved:** Key-conversion ops migrated; new [src/core/lib/KeyConvert.mjs](src/core/lib/KeyConvert.mjs) wraps RSA/EC/DSA PEM⇄JWK⇄SPKI/PKCS#8. DSA private-key parsing/building goes through `asn1js` directly (no peculiar `asn1-dsa` package and `node-forge` doesn't expose DSA), reusing the existing EC helpers from `Ecdsa.mjs`. @@ -241,6 +242,11 @@ 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 6 — 2026-05-17 +- Removed `jsrsasign` from [package.json](package.json) and [package-lock.json](package-lock.json). No runtime code changes were needed because PRs 1-5 had already moved operations to `@noble/curves`, `@peculiar/x509`, and `asn1js`. +- Removed stale dependency-name mentions from `src/` comments so `rg -n "jsrsasign" src/` is clean. Remaining mentions are intentionally limited to migration documentation and [CHANGELOG.md](CHANGELOG.md). +- Added a top-level [CHANGELOG.md](CHANGELOG.md) entry noting the removal and the accepted cosmetic output drift across the migrated ASN.1, ECDSA, key conversion, and X.509-family operations. + ### PR 5 — 2026-05-17 - New [src/core/lib/X509.mjs](src/core/lib/X509.mjs) holds the shared X.509 helpers (`decodeX509Input`, `sigAlgOidToName`, `describeSpki`, `parseDerEcdsaSignature`, `isDerEcdsaSignature`, `formatJsonName`, `formatGeneralName`, `formatHexByteLines`/`formatHexColonWrapped`, `asnNameToJson`). [src/core/lib/PublicKey.mjs](src/core/lib/PublicKey.mjs)'s `formatDnObj` now accepts both the legacy jsrsasign shape and `@peculiar/x509`'s `JsonName` (array-of-records) shape. Migrated ops: [ParseX509Certificate.mjs](src/core/operations/ParseX509Certificate.mjs), [PubKeyFromCert.mjs](src/core/operations/PubKeyFromCert.mjs), [ParseCSR.mjs](src/core/operations/ParseCSR.mjs), [ParseX509CRL.mjs](src/core/operations/ParseX509CRL.mjs). - **`X509Certificate` v1.14.3 doesn't expose `.version`.** Plan called for `cert.version`, but on the pinned v1 the property is missing. Worked around by parsing `cert.rawData` with the asn1-x509 `Certificate` schema and reading `tbsCertificate.version` + `signatureAlgorithm.algorithm` directly. The same approach is used in `ParseCSR` (with `CertificationRequest` from `@peculiar/asn1-csr`) and `ParseX509CRL` (with `CertificateList` from `@peculiar/asn1-x509`) — bypassing the WebCrypto algorithm mapping is necessary for DSA anyway (peculiar's algorithm provider doesn't know it). @@ -294,4 +300,3 @@ Record deviations from the original plan here, newest at the top. One bullet per - Added `@noble/hashes` peer-dep bump (was on ^1.x, needed ^2 for the `legacy` subpath). No code impact. - SM2 ciphertext fixture #3 was already wrong (decoded to the wrong plaintext under jsrsasign too) — confirmed via independent SM2 implementation, regenerated fixture. --> - diff --git a/src/core/lib/Asn1.mjs b/src/core/lib/Asn1.mjs index cbe0038d..06780342 100644 --- a/src/core/lib/Asn1.mjs +++ b/src/core/lib/Asn1.mjs @@ -1,9 +1,8 @@ /** * ASN.1 / OID / PEM helpers. * - * Replacements for the small jsrsasign utilities used by the - * HexToObjectIdentifier, ObjectIdentifierToHex, HexToPEM and - * ParseASN1HexString operations. + * Helpers used by the HexToObjectIdentifier, ObjectIdentifierToHex, + * HexToPEM and ParseASN1HexString operations. * * @author n1474335 [n1474335@gmail.com] * @copyright Crown Copyright 2016 @@ -109,14 +108,13 @@ export function oidIntToHex(oid) { /** * Wrap a hex-encoded DER blob in a PEM envelope. * - * Uses LF line endings only (the old jsrsasign output used CRLF). + * Uses LF line endings only. * - * Input parsing is intentionally lenient to match the previous jsrsasign - * behaviour: whitespace is stripped, an odd-length string is left-padded - * with a zero, and characters that are not hex digits are treated as the - * nibble `0`. This keeps the operation usable as a generic byte-emitter - * inside larger recipes where the upstream stage may not produce strict - * hex. + * Input parsing is intentionally lenient: whitespace is stripped, an + * odd-length string is left-padded with a zero, and characters that are not + * hex digits are treated as the nibble `0`. This keeps the operation usable + * as a generic byte-emitter inside larger recipes where the upstream stage + * may not produce strict hex. * * @param {string} hex * @param {string} label @@ -146,8 +144,7 @@ export function derToPem(hex, label) { } /** - * Walk an asn1js parse tree and produce an indented dump similar to the - * one jsrsasign's ASN1HEX.dump produced. + * Walk an asn1js parse tree and produce an indented dump. * * @param {string} hex * @param {Object} [options] diff --git a/src/core/lib/Ecdsa.mjs b/src/core/lib/Ecdsa.mjs index 9614a904..0b1b5921 100644 --- a/src/core/lib/Ecdsa.mjs +++ b/src/core/lib/Ecdsa.mjs @@ -2,7 +2,7 @@ * Shared ECDSA helpers built on @noble/curves and @peculiar/asn1-*. * * Used by the ECDSA Sign/Verify/Signature Conversion/Generate Key Pair - * operations. Migrated from jsrsasign. + * operations. * * @author n1474335 [n1474335@gmail.com] * @copyright Crown Copyright 2016 @@ -72,8 +72,7 @@ export function digestBytes(algo, bytes) { /** * Convert a JS string to bytes by Latin-1 truncation of each code unit (i.e. - * `charCodeAt(i) & 0xff`). This matches how jsrsasign / CryptoJS fed strings - * into MessageDigest.update — keeping signatures interoperable for inputs + * `charCodeAt(i) & 0xff`). This keeps signatures interoperable for inputs * coming out of upstream byte-producing ops, while preserving the * (questionable) UTF-16-truncating behaviour for free-text inputs. * @@ -162,7 +161,7 @@ export function verifyEcdsa(keyInfo, digest, asn1Hex) { /** * Quick test for whether a hex string parses as a single DER-encoded ASN.1 - * value. Mirrors jsrsasign's ASN1HEX.isASN1HEX. + * value. * * @param {string} hex * @returns {boolean} @@ -182,8 +181,8 @@ export function isAsn1Hex(hex) { /** * Parse an ASN.1 DER-encoded ECDSA signature and return the raw r/s INTEGER * bytes as hex. Preserves the DER 2's-complement leading 0x00 when present - * (i.e. r/s may have a leading "00" pair) — this matches the legacy - * jsrsasign ECDSA.parseSigHexInHexRS behaviour that existing tests assume. + * (i.e. r/s may have a leading "00" pair). Existing tests assume this + * compatibility behaviour. * * @param {string} asn1Hex * @returns {{r: string, s: string}} diff --git a/src/core/lib/KeyConvert.mjs b/src/core/lib/KeyConvert.mjs index 47e9f1ab..29637907 100644 --- a/src/core/lib/KeyConvert.mjs +++ b/src/core/lib/KeyConvert.mjs @@ -2,7 +2,7 @@ * Asymmetric key conversion helpers built on @peculiar/asn1-* and asn1js. * * Shared by the PEM to JWK / JWK to PEM / Public Key from Private Key - * operations. Replaces the jsrsasign key-format-conversion plumbing. + * operations. * * @author n1474335 [n1474335@gmail.com] * @copyright Crown Copyright 2016 @@ -370,8 +370,7 @@ function parsePkcs8(bytes) { } if (alg === ID_DSA) { // DSA PKCS#8 carries only x (with p/q/g in the algorithm - // parameters). jsrsasign rejected this layout because no y was - // present and the existing tests assert that we do the same — we + // parameters). Without y, deriving the public key is unsupported; // mark the info accordingly and let derivePublicKeyInfo throw. return { kty: "DSA", isPrivate: true, y: null }; } diff --git a/src/core/lib/PublicKey.mjs b/src/core/lib/PublicKey.mjs index 749f3bb4..5cff67a6 100644 --- a/src/core/lib/PublicKey.mjs +++ b/src/core/lib/PublicKey.mjs @@ -11,8 +11,8 @@ import { toHex, fromHex } from "./Hex.mjs"; /** * Formats Distinguished Name (DN) objects to strings. * - * Accepts either the legacy jsrsasign-style `{ array: [[{type, value}, ...], ...] }` - * shape OR `@peculiar/x509`'s `JsonName` shape — an array of records keyed by + * Accepts either the legacy `{ array: [[{type, value}, ...], ...] }` shape + * OR `@peculiar/x509`'s `JsonName` shape — an array of records keyed by * RDN short-name (`[{ CN: ["foo"], OU: ["bar"] }, ...]`). * * @param {Object|Array} dnObj diff --git a/src/core/lib/SM2.mjs b/src/core/lib/SM2.mjs index 6533c7a5..a2f219bb 100644 --- a/src/core/lib/SM2.mjs +++ b/src/core/lib/SM2.mjs @@ -58,8 +58,8 @@ function getCurve(name) { Point, n: params.n, coordCharLen: params.coordCharLen, - // Uniform-ish random scalar in [1, n-1] — matches the bias profile of - // the previous jsrsasign-based getBigRandom. + // Uniform-ish random scalar in [1, n-1], matching the previous bias + // profile for compatibility with existing SM2 behaviour. randomScalar: () => bytesToNumberBE(dh.utils.randomSecretKey()) % (params.n - 1n) + 1n, }; curveCache[name] = cached; diff --git a/src/core/lib/X509.mjs b/src/core/lib/X509.mjs index 5bbbc8d4..e5f2e970 100644 --- a/src/core/lib/X509.mjs +++ b/src/core/lib/X509.mjs @@ -2,7 +2,6 @@ * Shared X.509 / CSR / CRL helpers built on @peculiar/x509 + @peculiar/asn1-*. * * Used by ParseX509Certificate / PubKeyFromCert / ParseCSR / ParseX509CRL. - * Replaces the jsrsasign X.509 plumbing. * * @author n1474335 [n1474335@gmail.com] * @copyright Crown Copyright 2016 @@ -116,9 +115,9 @@ export function decodeX509Input(input, format) { // ----- signature algorithm -------------------------------------------------- /** - * Map a signature-algorithm OID to the jsrsasign-style display name - * (e.g. "1.2.840.113549.1.1.11" -> "SHA256withRSA"). Falls back to the - * raw OID if unknown. + * Map a signature-algorithm OID to the compact display name used by these + * operations (e.g. "1.2.840.113549.1.1.11" -> "SHA256withRSA"). Falls back + * to the raw OID if unknown. * * @param {string} oid * @returns {string} diff --git a/src/core/operations/ParseX509Certificate.mjs b/src/core/operations/ParseX509Certificate.mjs index 5222112a..9fede294 100644 --- a/src/core/operations/ParseX509Certificate.mjs +++ b/src/core/operations/ParseX509Certificate.mjs @@ -165,8 +165,8 @@ ${extensionsText}`; } /** - * Format the algorithm label for the Public Key block. Mirrors the legacy - * jsrsasign labelling: "EC", "DSA", "RSA". + * Format the algorithm label for the Public Key block. Mirrors the legacy + * labels: "EC", "DSA", "RSA". * * @param {object} spki * @returns {string} @@ -233,8 +233,8 @@ function formatExtensions(cert) { } /** - * Format a JS Date as the jsrsasign UTCTime/GeneralizedTime string - * `yymmddHHMMSSZ` (or `yyyymmddHHMMSSZ` for dates past 2049). + * Format a JS Date as an ASN.1 UTCTime/GeneralizedTime string: `yymmddHHMMSSZ` + * or `yyyymmddHHMMSSZ` for dates past 2049. * * @param {Date} date * @returns {string} diff --git a/tests/node/tests/operations.mjs b/tests/node/tests/operations.mjs index 1691f53b..2f5aadef 100644 --- a/tests/node/tests/operations.mjs +++ b/tests/node/tests/operations.mjs @@ -650,7 +650,7 @@ WWFkYSBZYWRh it("Parse ASN.1 Hex string", () => { // The bytes for "Mouth-watering" don't form a well-formed ASN.1 structure // (tag 0x4d declares length 0x6f but only 12 bytes follow), so we report - // a parse error rather than the partial best-effort dump jsrsasign emitted. + // a parse error rather than a partial best-effort dump. assert.strictEqual( chef.parseASN1HexString(chef.toHex("Mouth-watering")).toString(), "ASN.1 parse error: End of input reached before message was fully decoded (inconsistent offset and length values)" @@ -1146,4 +1146,3 @@ ExifImageHeight: 57`); ]); - diff --git a/tests/operations/tests/ASN1.mjs b/tests/operations/tests/ASN1.mjs index 5d794688..baadd851 100644 --- a/tests/operations/tests/ASN1.mjs +++ b/tests/operations/tests/ASN1.mjs @@ -1,8 +1,7 @@ /** * ASN.1 / OID / PEM tests. * - * Covers the four operations migrated from jsrsasign to the in-house - * Asn1.mjs helper: + * Covers the four operations migrated to the in-house Asn1.mjs helper: * - Hex to Object Identifier * - Object Identifier to Hex * - Hex to PEM diff --git a/tests/operations/tests/ParseX509Certificate.mjs b/tests/operations/tests/ParseX509Certificate.mjs index 0a584868..f2b278bf 100644 --- a/tests/operations/tests/ParseX509Certificate.mjs +++ b/tests/operations/tests/ParseX509Certificate.mjs @@ -1,8 +1,8 @@ /** * Parse X.509 Certificate tests. * - * Added as part of the jsrsasign → @peculiar/x509 migration (PR 5) to give - * the operation regression coverage it previously lacked. The certificate + * Added as part of the @peculiar/x509 migration (PR 5) to give the + * operation regression coverage it previously lacked. The certificate * fixtures are reused from PubKeyFromCert.mjs. * * @author n1474335 [n1474335@gmail.com]