@blamejs/pki 0.6.28 → 0.6.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +1 -1
  3. package/lib/acme.js +10 -8
  4. package/lib/asn1-der.js +9 -7
  5. package/lib/attrcert-sign.js +8 -8
  6. package/lib/byte-reader.js +1 -1
  7. package/lib/byte-writer.js +1 -1
  8. package/lib/cmc-verify.js +4 -4
  9. package/lib/cmp-build.js +9 -5
  10. package/lib/cmp-session.js +9 -4
  11. package/lib/cms-verify.js +22 -17
  12. package/lib/composite-kem.js +2 -2
  13. package/lib/constants.js +1 -0
  14. package/lib/crl-sign.js +5 -5
  15. package/lib/crmf-sign.js +3 -3
  16. package/lib/csr-sign.js +2 -2
  17. package/lib/ct.js +3 -3
  18. package/lib/est.js +34 -22
  19. package/lib/framework-error.js +2 -2
  20. package/lib/guard-identifier.js +18 -1
  21. package/lib/hpke.js +2 -2
  22. package/lib/http-transport.js +82 -10
  23. package/lib/inspect.js +1 -1
  24. package/lib/jose.js +1 -1
  25. package/lib/key.js +7 -7
  26. package/lib/lint.js +1 -1
  27. package/lib/merkle.js +2 -6
  28. package/lib/mime.js +2 -2
  29. package/lib/ocsp.js +6 -6
  30. package/lib/oid.js +1 -1
  31. package/lib/path-validate.js +13 -13
  32. package/lib/pkcs12-build.js +4 -4
  33. package/lib/rfc3339.js +2 -2
  34. package/lib/scep.js +3 -15
  35. package/lib/schema-all.js +1 -1
  36. package/lib/schema-attrcert.js +1 -1
  37. package/lib/schema-cmc.js +2 -2
  38. package/lib/schema-cmp.js +8 -9
  39. package/lib/schema-cms.js +3 -3
  40. package/lib/schema-crmf.js +3 -3
  41. package/lib/schema-csr.js +1 -1
  42. package/lib/schema-csrattrs.js +1 -1
  43. package/lib/schema-engine.js +4 -4
  44. package/lib/schema-ocsp.js +1 -1
  45. package/lib/schema-pkcs12.js +2 -2
  46. package/lib/schema-pkcs8.js +2 -2
  47. package/lib/schema-smime.js +1 -1
  48. package/lib/schema-tsp.js +6 -6
  49. package/lib/schema-x509.js +2 -2
  50. package/lib/shbs.js +3 -4
  51. package/lib/sign-scheme.js +1 -1
  52. package/lib/sigstore.js +2 -2
  53. package/lib/smime.js +16 -16
  54. package/lib/tls-cert-compress.js +7 -7
  55. package/lib/trust.js +5 -5
  56. package/lib/tsp-sign.js +8 -6
  57. package/lib/webauthn.js +23 -19
  58. package/lib/webcrypto.js +3 -3
  59. package/lib/x509-sign.js +5 -5
  60. package/package.json +1 -1
  61. package/sbom.cdx.json +6 -6
package/lib/lint.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * @nav Tooling
7
7
  * @title Lint
8
8
  * @fullname Certificate linting against CA/Browser Forum requirements
9
- * @intro The certificate LINTING engine -- the zlint / pkilint of JavaScript. It walks an
9
+ * @intro The certificate LINTING engine, the zlint / pkilint of JavaScript. It walks an
10
10
  * ALREADY-PARSED certificate (from `pki.schema.x509.parse`, whose extension values it
11
11
  * decodes with the shared RFC 5280 decoders) and emits graded, advisory FINDINGS: each
12
12
  * with a stable id, a severity (`fatal` > `error` > `warn` > `notice` > `pass`), a source,
package/lib/merkle.js CHANGED
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * @intro
13
13
  * RFC 6962 (Certificate Transparency) / RFC 9162 (CT 2.0) Merkle-tree hash
14
- * and proof-verification core -- the load-bearing primitive a static-CT
14
+ * and proof-verification core: the load-bearing primitive a static-CT
15
15
  * client, a Merkle-Tree-Certificates relying party, and a sigstore / Rekor
16
16
  * inclusion check all compose. Every verb is strict verification over
17
17
  * SHA-256: zero new crypto.
@@ -234,11 +234,7 @@ function verifyInclusion(opts) {
234
234
  * `merkle/no-consistency-claim`. RFC 6962 sec. 2.1.2 defines the proof for
235
235
  * `0 < oldSize < newSize`: the empty tree is a prefix of every tree by
236
236
  * definition, so there is no proof to check and nothing at all binds `newRoot`.
237
- * Returning `true` there would say a step was proven append-only when nothing had
238
- * been proven, and a monitor written `if (!verifyConsistency(...)) alarm()` would
239
- * take that silence for evidence. A caller with no prior tree has an inclusion
240
- * question about the new one, or should start from a checkpoint it already
241
- * trusts. Two empty trees are still answered:
237
+ * Two empty trees are still answered:
242
238
  * that is the degenerate identity case, and both roots must be `emptyRootHash()`.
243
239
  *
244
240
  * A malformed input throws a typed `merkle/*` error: `oldSize > newSize`, a
package/lib/mime.js CHANGED
@@ -3,11 +3,11 @@
3
3
  "use strict";
4
4
  /**
5
5
  * @internal
6
- * lib/mime.js -- a minimal MIME entity framer + canonicalizer, the message-layer engine primitive
6
+ * lib/mime.js: a minimal MIME entity framer + canonicalizer, the message-layer engine primitive
7
7
  * under pki.smime (RFC 8551 S/MIME) and any future MIME-carrying feature. It parses an entity into
8
8
  * its headers + body, canonicalizes a text entity to the RFC 8551 sec. 3.1.1 form (CRLF line endings),
9
9
  * splits a multipart body on its boundary, and builds an entity/multipart back. There is NO crypto
10
- * here -- the CMS layer signs/verifies the canonical bytes this module produces.
10
+ * here. The CMS layer signs/verifies the canonical bytes this module produces.
11
11
  *
12
12
  * The load-bearing rule is canonicalization: the detached signature over a multipart/signed first part
13
13
  * is computed over that part's canonical MIME form, so the signer and verifier MUST share one
package/lib/ocsp.js CHANGED
@@ -352,14 +352,14 @@ function _certStatusNode(status, opts) {
352
352
 
353
353
  /**
354
354
  * @primitive pki.ocsp.buildErrorResponse
355
- * @signature pki.ocsp.buildErrorResponse(status) -> Buffer | string
355
+ * @signature pki.ocsp.buildErrorResponse(status) -> Buffer
356
356
  * @since 0.2.22
357
357
  * @status stable
358
358
  * @spec RFC 6960
359
359
  * @related pki.ocsp.sign
360
360
  *
361
- * Build an UNSIGNED error OCSPResponse -- `malformedRequest` / `internalError` / `tryLater` /
362
- * `sigRequired` / `unauthorized` -- carrying only the responseStatus and no responseBytes (RFC 6960
361
+ * Build an UNSIGNED error OCSPResponse, one of `malformedRequest` / `internalError` / `tryLater` /
362
+ * `sigRequired` / `unauthorized`, carrying only the responseStatus and no responseBytes (RFC 6960
363
363
  * sec. 2.3: an error message conveys no certificate status and is not signed).
364
364
  *
365
365
  * @example
@@ -374,7 +374,7 @@ function buildErrorResponse(status) {
374
374
 
375
375
  /**
376
376
  * @primitive pki.ocsp.verify
377
- * @signature pki.ocsp.verify(response, opts) -> Promise<{ status, responderAuthorized, signatureValid, thisUpdate, nextUpdate, revocationReason?, revocationTime?, nonceMatched?, reason }>
377
+ * @signature pki.ocsp.verify(response, opts) -> Promise<{ status, responderAuthorized, signatureValid, matched, thisUpdate, nextUpdate, revocationReason?, revocationTime?, nonceMatched?, reason }>
378
378
  * @since 0.2.22
379
379
  * @status stable
380
380
  * @spec RFC 6960, RFC 9654, RFC 5019
@@ -524,9 +524,9 @@ function _signerVerdict(parsed, found, failReason) {
524
524
  * request carried (or opts.certs supplied), including intermediates that do not sign and so are absent
525
525
  * from `signerCerts`: the responder passes it as the `opts.candidates` pool to `pki.path.build`, which
526
526
  * discovers and validates the ordered path from a `signerCerts` entry (leaf) up to a trust anchor.
527
- * The responder then confirms that certificate is authorized to sign the request -- its `keyUsage`,
527
+ * The responder then confirms that certificate is authorized to sign the request: its `keyUsage`,
528
528
  * where present, must assert `digitalSignature` (RFC 5280 sec. 4.2.1.3, since the certificate signed
529
- * the request) -- and compares its subject to the `requestorName` it expects. The decoded
529
+ * the request). It also compares the certificate's subject to the `requestorName` it expects. The decoded
530
530
  * `requestList`, `requestExtensions` and `version` are
531
531
  * returned so the CertIDs being asked about need no re-parse.
532
532
  *
package/lib/oid.js CHANGED
@@ -446,7 +446,7 @@ function register(dotted, n) {
446
446
  *
447
447
  * Register a whole OID family in one call. `base` is the shared arc prefix
448
448
  * (the starting variable a class of OIDs has in common) and `members` maps
449
- * each name to its trailing arc -- a number, or a short arc array for a
449
+ * each name to its trailing arc: a number, or a short arc array for a
450
450
  * multi-level leaf. Each full OID is derived as `base` followed by the leaf,
451
451
  * so a family is declared as its hierarchy and no full path is re-spelled.
452
452
  * This is the primitive the built-in seed set itself is built from.
@@ -10,9 +10,9 @@
10
10
  * @intro
11
11
  * RFC 5280 6 certification-path validation as a pure, re-entrant algorithm
12
12
  * over already-parsed certificates. `pki.path.validate(path, opts)` runs the
13
- * 6.1 state machine -- signature chaining, validity windows, name chaining,
13
+ * 6.1 state machine (signature chaining, validity windows, name chaining,
14
14
  * basic constraints and path length, key usage, name constraints, and the
15
- * certificate-policy tree -- and returns a structured verdict with a per-check
15
+ * certificate-policy tree) and returns a structured verdict with a per-check
16
16
  * reason code for every step. Validity-window enforcement is always on, with
17
17
  * the check date an explicit input; the trust anchor is an input, never one of
18
18
  * the validated certificates, and no input object is mutated.
@@ -20,12 +20,12 @@
20
20
  * Revocation is a pluggable hook: `pki.path.crlChecker(crls)` ships a CRL
21
21
  * consultation built on `pki.schema.crl.parse`; an OCSP checker satisfies the
22
22
  * same interface. Signature verification derives its algorithm from the
23
- * certificate and the issuer key -- never from a value the message controls --
23
+ * certificate and the issuer key, never from a value the message controls,
24
24
  * and fails closed on an unknown critical extension, an undetermined
25
25
  * revocation status, or any structural fault.
26
26
  *
27
27
  * @card
28
- * RFC 5280 6 certification-path validation -- run the 6.1 state machine over
28
+ * RFC 5280 6 certification-path validation: run the 6.1 state machine over
29
29
  * an ordered path and a trust anchor for a structured, fail-closed verdict
30
30
  * with per-check reason codes. Pure and re-entrant.
31
31
  */
@@ -836,7 +836,7 @@ function validateCriticalExtensionStructure(cert) {
836
836
  * inputs (`initialExplicitPolicy`,
837
837
  * `initialAnyPolicyInhibit`, `initialPolicyMappingInhibit`,
838
838
  * `userInitialPolicySet`, and `initialPermittedSubtrees` /
839
- * `initialExcludedSubtrees` -- arrays of `{ tag, base }` where `tag` is the
839
+ * `initialExcludedSubtrees`: arrays of `{ tag, base }` where `tag` is the
840
840
  * GeneralName tag number and `base` that form's constraint value), an
841
841
  * optional `requiredEku` (key purposes the target's extendedKeyUsage must
842
842
  * assert, given as registered OID names or dotted OID strings; an absent
@@ -846,9 +846,9 @@ function validateCriticalExtensionStructure(cert) {
846
846
  * are validated at the entry point. A mis-shaped value throws `path/bad-input`,
847
847
  * so it cannot silently go unapplied. Returns `{ valid, revocationChecked, anchorConstraints,
848
848
  * path, results, workingPublicKey, workingPublicKeyAlgorithm,
849
- * workingPublicKeyParameters, validPolicyTree }` where `results[i].checks`
849
+ * workingPublicKeyParameters, validPolicyTree, userConstrainedPolicySet }` where `results[i].checks`
850
850
  * carries a per-check reason code (`path/*`) for every step. Pure and
851
- * re-entrant -- no input object is mutated. An empty path or a missing anchor
851
+ * re-entrant: no input object is mutated. An empty path or a missing anchor
852
852
  * throws a typed `PathError`.
853
853
  *
854
854
  * `valid` alone cannot say whether revocation was ever established, so
@@ -1365,7 +1365,7 @@ function selectDelta(candidates) {
1365
1365
  * (`thisUpdate`/`nextUpdate`), and reports `{ status: "good"|"revoked"|
1366
1366
  * "unknown" }`. A partitioned/sharded CRL (a critical IDP naming a
1367
1367
  * distribution point) establishes "good" when it corresponds to one of the
1368
- * certificate's own cRLDistributionPoints -- at least one identically-encoded
1368
+ * certificate's own cRLDistributionPoints: at least one identically-encoded
1369
1369
  * name in common (RFC 5280 sec. 6.3.3). Reason-sharded CRLs ACCUMULATE: each
1370
1370
  * corresponding CRL contributes its interim reason mask (sec. 6.3.3(d)) and the
1371
1371
  * certificate is "good" once the shards together cover all eight revocation
@@ -1713,21 +1713,21 @@ function ocspChecker(responses) {
1713
1713
  * directly, or a CA-issued delegate bearing both id-kp-OCSPSigning and
1714
1714
  * id-pkix-ocsp-nocheck and passing the full out-of-path certificate gates),
1715
1715
  * verifies the response signature over `tbsResponseDataBytes`, and checks
1716
- * currency (`thisUpdate`/`nextUpdate`) -- there is no weaker second OCSP verify
1716
+ * currency (`thisUpdate`/`nextUpdate`). There is no weaker second OCSP verify
1717
1717
  * path. It is fail-closed and never throws on an unauthorized, stale, or
1718
1718
  * unverifiable response: those yield `{ status: "unknown" }` with the granular
1719
1719
  * `responderAuthorized`/`signatureValid`/`matched` flags and a `reason`; a
1720
1720
  * `revoked` status surfaces its `revocationReason`. Setting `opts.historicalMode`
1721
1721
  * treats a revocation whose `revocationTime` is strictly after `time` as not-yet-
1722
- * revoked (`good`) -- for validating a signature as of a past `time`, before the
1722
+ * revoked (`good`): for validating a signature as of a past `time`, before the
1723
1723
  * certificate was later revoked; the responder certificate is still validated at
1724
1724
  * `time` either way. `time` must be a valid `Date`. A malformed response's parse
1725
1725
  * fault surfaces as the parser's typed `ocsp/*` / `asn1/*` error.
1726
1726
  *
1727
1727
  * The response is its DER bytes, a PEM string, or an unmodified
1728
1728
  * `pki.schema.ocsp.parseResponse` result. A REBUILT parsed response is refused. A
1729
- * signature check has three parts -- the signature, the algorithm that verifies it,
1730
- * and the bytes it covers -- and on a parsed object all three are separate properties:
1729
+ * signature check has three parts (the signature, the algorithm that verifies it,
1730
+ * and the bytes it covers) and on a parsed object all three are separate properties:
1731
1731
  * a genuine CA signature over a certificate that CA issued, relabeled, verifies as a
1732
1732
  * ResponseData signature for a response that never existed. The parser marks what it
1733
1733
  * returns, so those three are known to have been derived together from one byte
@@ -2285,7 +2285,7 @@ async function _fetchAiaIssuers(current, aia) {
2285
2285
  * from a certificate's Authority Information Access `caIssuers` URL (RFC 5280 sec. 4.2.2.1) over
2286
2286
  * `pki.transport`: the fetch triggers only on a pool miss, every fetched certificate is UNTRUSTED pool material
2287
2287
  * that still flows through `validate` when validation is on (never a trust anchor), and the whole surface is
2288
- * SSRF/amplification bounded -- https-only, a total fetch budget (a SILENT cap, never a throw that denies a
2288
+ * SSRF/amplification bounded: https-only, a total fetch budget (a SILENT cap, never a throw that denies a
2289
2289
  * buildable path), a per-cert URL cap, a build-wide URL dedupe, a response size + certificate-count cap, and no
2290
2290
  * redirect following; every fetch fault is a silent skip. `aiaFetches` reports how many network GETs the build
2291
2291
  * performed (`0` when `fetchAia` is off). NOTE: with `opts.validate:false` (pure-builder mode) a fetched cert is
@@ -7,7 +7,7 @@
7
7
  * @title PKCS#12
8
8
  * @fullname PKCS#12 keystores (.p12 and .pfx): build and open
9
9
  * @intro The PKCS#12 (.p12 / .pfx) producing side (RFC 7292, RFC 9579). `pki.pkcs12.build` assembles a
10
- * password-integrity PFX -- key, certificate, CRL, and secret bags (shrouded keys and cert safes encrypted
10
+ * password-integrity PFX: key, certificate, CRL, and secret bags (shrouded keys and cert safes encrypted
11
11
  * under RFC 8018 PBES2) wrapped in an AuthenticatedSafe, protected by either a classic Appendix B HMAC or
12
12
  * an RFC 9579 PBMAC1 (PBKDF2 + HMAC) MAC, over AES-128/192/256-CBC and SHA-256/384/512. Every password is
13
13
  * encoded the PKCS#12 way (BMPString + NULL, Appendix B.1), so a file it emits opens in OpenSSL and NSS.
@@ -427,7 +427,7 @@ function _normalizeSpec(spec, opts, form) {
427
427
  *
428
428
  * @opts
429
429
  * - `password` -- the shared privacy + integrity password (string / Buffer / Uint8Array).
430
- * - `mac` -- `false` for a MAC-less store, or `{ algorithm: 'hmac'(default)|'pbmac1', hash: 'sha256'(default)|'sha1'|'sha384'|'sha512', salt?, iterations? }`. `keyLength` is a `pbmac1` field: the classic Appendix B derivation produces a key at the hash's own output length, and naming one under `hmac` is refused.
430
+ * - `mac` -- `false` for a MAC-less store, or `{ algorithm: 'hmac'(default)|'pbmac1', hash: 'sha256'(default)|'sha1'|'sha384'|'sha512', salt?, iterations?, password? }`. `password` overrides the shared integrity password for the MAC. `keyLength` is a `pbmac1` field: the classic Appendix B derivation produces a key at the hash's own output length, and naming one under `hmac` is refused.
431
431
  * - `integrity` -- `{ mode: 'public-key', signer: { cert, key, digestAlgorithm?, pss? } | signers: [ ... ], sid?, signingTime?, certificates? }` for public-key integrity (a CMS SignedData authSafe over any `pki.cms.sign` signer algorithm, no MacData). Combining it with a truthy `mac` is rejected.
432
432
  * - `recipientCerts` -- (public-key privacy convenience) `[certDer|PEM, ...]`; the convenience-form cert + key are placed in one recipient-enveloped safe (a plaintext keyBag). For the full form, set per-`safeContents` `recipients: [{ cert }, ...]` -- CERTIFICATE recipients only (RSA-OAEP / ECDH / X25519 / X448 / ML-KEM, dispatched off the cert key); a password or KEK recipient is not public-key privacy and is rejected -- with an optional `contentEncryptionAlgorithm` (`aes-128|192|256-cbc`, default 256; GCM/AEAD rejected). `encrypt` (password) and `recipients` (public-key) on the same safe is rejected; privacy is independent of integrity.
433
433
  * - `pem` (boolean) -- return a PEM `PKCS12` string instead of DER.
@@ -534,7 +534,7 @@ async function _build(spec, opts) {
534
534
  * a byte range the object carries, and the parser's mark is what says that range and the store it describes
535
535
  * came from one place. `Object.assign`, spread and a JSON round-trip drop the mark. The password is BMPString+NULL encoded (RFC 7292 App. B.1), the MAC is
536
536
  * recomputed over the store's exact AuthenticatedSafe byte range (`macedBytes`) using the store's own MAC
537
- * parameters -- the classic Appendix B (ID=3) HMAC or the RFC 9579 PBMAC1 -- and constant-time-compared to
537
+ * parameters, the classic Appendix B (ID=3) HMAC or the RFC 9579 PBMAC1, and constant-time-compared to
538
538
  * the stored MAC value. The verdict's `valid` is the password match, and `macAlgorithm` (`hmac` or `pbmac1`),
539
539
  * `macAlgorithmName` (the digest / scheme, e.g. `sha1`, `sha256`), and `iterationCount` name the integrity
540
540
  * algorithm the store used, so a caller can reject a legacy SHA-1 MAC by inspecting them rather than
@@ -617,7 +617,7 @@ function _capWork(iterations, salt, opts, keyLength, hardCap) {
617
617
  * SignedData signature, per RFC 7292 sec. 4 / 5.1, so no bag from a store whose integrity check fails is trusted),
618
618
  * then decrypt every PBES2 privacy safe and pkcs8ShroudedKeyBag with the password, and every id-envelopedData
619
619
  * (public-key privacy) safe with `opts.recipientKey` (RFC 7292 sec. 3.1, via `pki.cms.decrypt`), returning a
620
- * structured bundle `{ integrityMode, macVerified, signers, keys, certs, crls, secrets }` with each private key as PKCS#8
620
+ * structured bundle `{ valid, integrityMode, macVerified, signers, keys, certs, crls, secrets }` with each private key as PKCS#8
621
621
  * `PrivateKeyInfo` DER (re-validated), each certificate / CRL / secret as raw DER, all carrying their
622
622
  * `friendlyName` / `localKeyId` for pairing. `pfx` is the store's DER `Buffer`, a PEM string, or an
623
623
  * unmodified `pki.schema.pkcs12.parse` result; a rebuilt parsed store is refused, since the bytes whose
package/lib/rfc3339.js CHANGED
@@ -3,10 +3,10 @@
3
3
  "use strict";
4
4
  /**
5
5
  * @internal
6
- * lib/rfc3339.js -- RFC 3339 date-time parsing + validation, a fail-closed engine primitive shared by
6
+ * lib/rfc3339.js: RFC 3339 date-time parsing + validation, a fail-closed engine primitive shared by
7
7
  * pki.acme (a boolean field-validator over server-supplied JSON) and pki.ct (parse a CT log-list
8
8
  * timestamp / temporal-interval bound to a comparable Date). Beyond the grammar it enforces CALENDAR
9
- * validity -- a syntactically well-formed but impossible instant (month 13, February 30, hour 25, a
9
+ * validity: a syntactically well-formed but impossible instant (month 13, February 30, hour 25, a
10
10
  * :60 leap second, a +25:00 offset) is rejected, so a downstream expiry / window comparison never runs
11
11
  * on a value JS `Date` would silently roll over or `Date.parse` would NaN. Like the byte-reader / guard
12
12
  * family, `parse` takes the caller's `(code, message) -> error` factory so every consumer keeps its own
package/lib/scep.js CHANGED
@@ -14,7 +14,7 @@
14
14
  * issued certificate) in two nested CMS layers: an inner EnvelopedData
15
15
  * (`pkcsPKIEnvelope`) that encrypts the messageData to the recipient, and an
16
16
  * outer SignedData that signs it under a set of authenticated transaction
17
- * attributes -- messageType, transactionID, pkiStatus, failInfo, and the
17
+ * attributes: messageType, transactionID, pkiStatus, failInfo, and the
18
18
  * sender/recipient nonces (RFC 8894 sec. 3). `pki.scep.build` assembles a
19
19
  * request pkiMessage (PKCSReq, RenewalReq, CertPoll, GetCert, or GetCRL) or a
20
20
  * CA-side CertRep response; `pki.scep.parse` verifies the
@@ -520,7 +520,7 @@ async function parse(bytes, opts) {
520
520
  var messageType = MESSAGE_TYPE_BY_CODE[messageTypeCode];
521
521
  if (messageType == null) throw _err("scep/bad-message-type", "unknown messageType " + JSON.stringify(messageTypeCode) + " (RFC 8894 sec. 3.2.1.2)");
522
522
  if (_PARSE_SUPPORTED[messageType] !== 1) {
523
- throw _err("scep/unsupported-message-type", "pki.scep.parse reads PKCSReq, RenewalReq, and CertRep; " + messageType + " is not read in this release");
523
+ throw _err("scep/unsupported-message-type", "pki.scep.parse reads " + Object.keys(_PARSE_SUPPORTED).join(", ") + "; " + messageType + " is not read in this release");
524
524
  }
525
525
  var out = {
526
526
  signatureValid: true, signerAuthenticated: signerAuthenticated, signerCert: signer.cert,
@@ -717,19 +717,7 @@ function _drive(method, url, body, headers, opts, transport, budgets) {
717
717
  }
718
718
  return step(url);
719
719
  }
720
- function _copyAnchor(a) { return Buffer.isBuffer(a) ? Buffer.from(a) : a; }
721
- function _snapshotProxy(p) {
722
- if (p == null || typeof p !== "object" || Array.isArray(p)) return p;
723
- var out = Object.assign({}, p);
724
- if (p.auth != null && typeof p.auth === "object" && !Array.isArray(p.auth)) out.auth = Object.assign({}, p.auth);
725
- if (p.tls != null && typeof p.tls === "object" && !Array.isArray(p.tls)) {
726
- out.tls = Object.assign({}, p.tls);
727
- var a = p.tls.anchors;
728
- if (Array.isArray(a)) out.tls.anchors = a.map(_copyAnchor);
729
- else if (a != null) out.tls.anchors = _copyAnchor(a);
730
- }
731
- return out;
732
- }
720
+ function _snapshotProxy(p) { return httpTransport.snapshotProxy(p); }
733
721
  function _client(method, url, body, headers, opts) {
734
722
  var transport = opts.transport || httpTransport.https({ E: _err, errPrefix: "scep" });
735
723
  var budgets = {
package/lib/schema-all.js CHANGED
@@ -153,7 +153,7 @@ var FORMATS = [
153
153
  * The names of every registered format, in detection order.
154
154
  *
155
155
  * @example
156
- * pki.schema.all(); // -> ["cms", "tsp", "crmf", "cmp", "ocsp-request", "ocsp-response", "pkcs12", "pkcs8", "csr", "attrcert", "attrcert-v1", "crl", "x509"]
156
+ * pki.schema.all(); // -> ["cms", "tsp", "crmf", "cmp", "csrattrs", "ocsp-request", "ocsp-response", "pkcs12", "pkcs8", "csr", "attrcert", "attrcert-v1", "crl", "x509"]
157
157
  */
158
158
  function all() { return FORMATS.map(function (f) { return f.name; }); }
159
159
 
@@ -11,7 +11,7 @@
11
11
  * @intro
12
12
  * X.509 Attribute Certificate handling per RFC 5755. An attribute certificate
13
13
  * binds a holder to a set of privilege attributes (role, group, clearance)
14
- * without carrying a public key -- the authorization counterpart to an identity
14
+ * without carrying a public key, the authorization counterpart to an identity
15
15
  * certificate. `parse` decodes a v2 `AttributeCertificate` into its holder,
16
16
  * issuer, validity window (real `Date`s), attributes, and extensions, reusing
17
17
  * the shared signed-envelope so the raw `tbsBytes` (the exact signed region) and
package/lib/schema-cmc.js CHANGED
@@ -12,7 +12,7 @@
12
12
  * RFC 5272 CMC message-layer decoding, as updated by RFC 6402. A Full PKI
13
13
  * Request (`PKIData`) and a Full PKI Response (`PKIResponse`) both ride inside
14
14
  * a CMS SignedData (or AuthenticatedData) as the encapsulated content, named by
15
- * the eContentType `id-cct-PKIData` / `id-cct-PKIResponse` -- so `parse` peels
15
+ * the eContentType `id-cct-PKIData` / `id-cct-PKIResponse`, so `parse` peels
16
16
  * the CMS layer, dispatches on that content type, and decodes the message.
17
17
  *
18
18
  * Every body part carries a `BodyPartID`, and the identifier MUST be unique
@@ -22,7 +22,7 @@
22
22
  * unrecognized control is data, not a fault, because the rule that a server
23
23
  * fails an unrecognized control binds the server, not the client reading a
24
24
  * response. The status controls (`CMCStatusInfo` v1 and `CMCStatusInfoV2`) are
25
- * collected in wire order -- a response may carry several verdicts, and the
25
+ * collected in wire order. A response may carry several verdicts, and the
26
26
  * ABSENCE of one means success.
27
27
  *
28
28
  * The `reqSequence` byte range is surfaced exactly as it appeared on the wire,
package/lib/schema-cmp.js CHANGED
@@ -22,7 +22,7 @@
22
22
  * CRMF parser; response, revocation, confirmation, error, general-message,
23
23
  * and polling arms decode structurally (an encrypted certificate's
24
24
  * EnvelopedData decodes via the CMS parser); every other defined arm is
25
- * recognized and surfaced raw -- `nested` messages are never auto-recursed.
25
+ * recognized and surfaced raw; `nested` messages are never auto-recursed.
26
26
  * Protection is surfaced, not verified: the exact `headerBytes` and
27
27
  * `bodyBytes` wire slices are exposed so an external verifier reconstructs
28
28
  * the virtual ProtectedPart `SEQUENCE { header, body }` and checks the MAC
@@ -725,7 +725,7 @@ var readName = _valueParser("Name", pkix.name(NS));
725
725
  * Parse a DER `Buffer` or a PEM string into a structured PKIMessage:
726
726
  * `{ header, headerBytes, body, bodyBytes, protection, extraCerts }`.
727
727
  * `header` carries `pvno` (1..3), `sender` / `recipient` (validated
728
- * GeneralNames -- the anonymous NULL-DN form included), and the optional
728
+ * GeneralNames, the anonymous NULL-DN form included), and the optional
729
729
  * `messageTime`, `protectionAlg`, `senderKID` / `recipKID`,
730
730
  * `transactionID`, `senderNonce` / `recipNonce`, `freeText`, and
731
731
  * `generalInfo` (recognized id-it types value-checked: implicitConfirm is
@@ -734,14 +734,14 @@ var readName = _valueParser("Name", pkix.name(NS));
734
734
  * (`ir` / `cr` / `kur` / `krr` / `ccr`) decode via the CRMF parser;
735
735
  * `ip` / `cp` / `kup` / `ccp` decode to `{ caPubs, response }` (an encrypted
736
736
  * certificate's EnvelopedData decodes via the CMS parser; the deprecated
737
- * EncryptedValue arm and `caPubs` surface raw -- the parser confers no
737
+ * EncryptedValue arm and `caPubs` surface raw; the parser confers no
738
738
  * trust); `krp` decodes to `{ status, newSigCert, caCerts, keyPairHist }`;
739
739
  * `rr` / `rp`, `genm` / `genp`, `error`, `certConf` (an empty
740
740
  * confirmation is the legal reject-all), and `pollReq` / `pollRep` decode
741
- * structurally; `pkiconf` decodes to `null`; every other defined arm --
742
- * `p10cr` (feed `body.bytes` to `pki.schema.csr.parse`), the
743
- * challenge-response and announcement arms, and `nested` (never
744
- * auto-recursed) surfaces raw with `decoded` absent. `certReqId` values
741
+ * structurally; `pkiconf` decodes to `null`; every other defined arm
742
+ * surfaces raw with `decoded` absent: `p10cr` (feed `body.bytes` to
743
+ * `pki.schema.csr.parse`), the challenge-response and announcement arms,
744
+ * and `nested` (never auto-recursed). `certReqId` values
745
745
  * are BigInt and accept the protocol's -1 sentinel.
746
746
  *
747
747
  * Protection is surfaced, not verified: `protection` carries the raw,
@@ -785,8 +785,7 @@ var parse = pkix.makeParser({
785
785
  * @related pki.schema.cmp.parse
786
786
  *
787
787
  * Extract the DER bytes from a PEM block (default label `CMP`). CMP is
788
- * wire-DER over HTTP (RFC 9811) -- the PEM path is a convenience for
789
- * messages that transit text channels.
788
+ * wire-DER over HTTP (RFC 9811).
790
789
  *
791
790
  * @example
792
791
  * var pair = await pki.key.generate("Ed25519");
package/lib/schema-cms.js CHANGED
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * @intro
12
12
  * CMS handling per RFC 5652 (sec. 3 ContentInfo envelope). `parse` turns a DER or PEM
13
- * (`CMS`) message into a structured object and is an OID-dispatch envelope --
13
+ * (`CMS`) message into a structured object and is an OID-dispatch envelope:
14
14
  * ContentInfo reads its `contentType` and structurally decodes SignedData (sec. 5),
15
15
  * EnvelopedData (sec. 6, with all five RecipientInfo kinds: key-transport,
16
16
  * key-agreement per RFC 5753, KEK, password, and other, including the RFC 9629
@@ -38,8 +38,8 @@
38
38
  * parse but an out-of-set element does. DER-only, fail-closed.
39
39
  *
40
40
  * @card
41
- * Parse DER / PEM CMS (RFC 5652 / 5083 / 9629) into structured, validated fields
42
- * -- signed, enveloped, encrypted, authenticated, and auth-enveloped content;
41
+ * Parse DER / PEM CMS (RFC 5652 / 5083 / 9629) into structured, validated fields:
42
+ * signed, enveloped, encrypted, authenticated, and auth-enveloped content;
43
43
  * raw attribute bytes for external verification; certificates/CRLs kept raw,
44
44
  * fail-closed.
45
45
  */
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * @intro
12
12
  * Certificate Request Message Format handling per RFC 4211. `parse` decodes a
13
- * `CertReqMessages` -- the request body CMP and EST enrollment carry -- into an
13
+ * `CertReqMessages`, the request body CMP and EST enrollment carry, into an
14
14
  * array of messages, each with its `CertRequest` (certReqId, a `CertTemplate`
15
15
  * of the requested certificate fields, and any registration controls), an
16
16
  * optional proof-of-possession, and optional registration info.
@@ -327,7 +327,7 @@ var CERT_REQ_MESSAGES = schema.seqOf(CERT_REQ_MSG, {
327
327
  * surfaced. `popo` is
328
328
  * `null`, `{ type: "raVerified" }`, `{ type: "signature", poposkInput,
329
329
  * algorithmIdentifier, signature }`, or `{ type: "keyEncipherment" |
330
- * "keyAgreement", method, bytes }` (where `method` is the POPOPrivKey alternative --
330
+ * "keyAgreement", method, bytes }` (where `method` is the POPOPrivKey alternative:
331
331
  * `thisMessage` / `subsequentMessage` / `dhMAC` / `agreeMAC` / `encryptedKey`, each
332
332
  * structurally validated, the `encryptedKey` EnvelopedData included). When present, `poposkInput` is
333
333
  * `{ bytes, signedBytes, publicKey }`, where `bytes` is the raw wire `[0]` TLV,
@@ -385,7 +385,7 @@ function pemDecode(text, label) { return pkix.pemDecode(text, label || null, Pem
385
385
  * @related pki.schema.crmf.pemDecode
386
386
  *
387
387
  * Wrap DER bytes in a PEM envelope. RFC 4211 registers no RFC 7468 label, so
388
- * `label` is REQUIRED -- the operator names the envelope explicitly (mirroring
388
+ * `label` is REQUIRED: the operator names the envelope explicitly (mirroring
389
389
  * `pemDecode`, which accepts any label). Omitting it throws `pem/bad-label`.
390
390
  *
391
391
  * @example
package/lib/schema-csr.js CHANGED
@@ -21,7 +21,7 @@
21
21
  * A CSR is self-signed only in the sense that the requester proves possession of
22
22
  * the private key; unlike a certificate or CRL there is no inner signature
23
23
  * algorithm to agree with, the subject MAY be empty, and the attribute set has
24
- * no uniqueness constraint -- the parser deliberately omits those three
24
+ * no uniqueness constraint: the parser deliberately omits those three
25
25
  * certificate/CRL guards.
26
26
  *
27
27
  * @card
@@ -24,7 +24,7 @@
24
24
  * and `id-aa-certificationRequestInfoTemplate` -> a fully-decoded `template`.
25
25
  *
26
26
  * Structure is strict-DER throughout, but UNKNOWN OIDs and attribute types
27
- * are TOLERATED -- surfaced raw, never a parse fault ("the client MUST ignore
27
+ * are TOLERATED: surfaced raw, never a parse fault ("the client MUST ignore
28
28
  * any OID or attribute it does not recognize", RFC 8951 sec. 4.5.2). The
29
29
  * RFC 9908 semantic MUSTs that ARE enforced fail closed with a typed
30
30
  * `csrattrs/*` code: at most one `id-ExtensionReq` attribute, its values a SET
@@ -9,7 +9,7 @@
9
9
  * @order 60
10
10
  *
11
11
  * @intro
12
- * L2 of the ASN.1 stack -- a declarative structure-schema engine. A schema is
12
+ * L2 of the ASN.1 stack: a declarative structure-schema engine. A schema is
13
13
  * plain data (`{kind, ...}` descriptors built by the combinators here) and
14
14
  * `walk(schema, node, ctx)` interprets it against a decoded DER node. The
15
15
  * engine is where every cross-cutting structural rule lives ONCE: the shape
@@ -179,7 +179,7 @@ function implicitSeqOf(tag, item, opts) {
179
179
  * Interpret a declarative schema against a decoded DER node, enforcing the
180
180
  * schema's structural rules (shape assertion, arity, optional / context-tagged
181
181
  * fields in increasing tag order, SET-OF uniqueness) and returning the built
182
- * value -- or the match tree (`{ node, fields | items }`, with the build output
182
+ * value, or the match tree (`{ node, fields | items }`, with the build output
183
183
  * on `.result`) for a structure with no build fn. `ctx = { E, prefix, oid }`
184
184
  * supplies the typed-error constructor, the error-code family prefix, and the
185
185
  * OID registry a build fn resolves names through.
@@ -464,8 +464,8 @@ function _encodeChoice(schema, value, ctx) {
464
464
  * @related pki.schema.engine.walk, pki.asn1.decode
465
465
  *
466
466
  * Decode a fresh DER (or, with `ber: true`, BER) blob carried inside an
467
- * already-decoded value -- an OCTET STRING whose content is itself an encoded
468
- * structure -- and walk it against a schema. A codec failure is wrapped in the
467
+ * already-decoded value (an OCTET STRING whose content is itself an encoded
468
+ * structure) and walk it against a schema. A codec failure is wrapped in the
469
469
  * caller's typed `code`; a schema rejection keeps its own code. This is the
470
470
  * one named form of the re-decode idiom, so the caps that a fresh
471
471
  * `pki.asn1.decode` would restart from zero can be carried across re-decode
@@ -29,7 +29,7 @@
29
29
  *
30
30
  * @card
31
31
  * Parse DER / PEM OCSP requests and responses (RFC 6960) into structured,
32
- * validated fields -- per-certificate status, responder identity, raw tbs bytes for
32
+ * validated fields: per-certificate status, responder identity, raw tbs bytes for
33
33
  * external verification, certificates kept raw, fail-closed.
34
34
  */
35
35
 
@@ -27,7 +27,7 @@
27
27
  * MAC-less store surfaces `integrityMode: "none"` for the caller's policy
28
28
  * to judge. RFC 7292
29
29
  * sec. 4.1 encodes content in BER, so parsing this one format accepts exactly
30
- * two BER shapes -- indefinite lengths and constructed OCTET STRINGs --
30
+ * two BER shapes (indefinite lengths and constructed OCTET STRINGs)
31
31
  * anywhere in the store; every other strictness verdict, and every other
32
32
  * format, stays strict DER, fail-closed.
33
33
  *
@@ -406,7 +406,7 @@ function _buildBag(rec, state, ctx) {
406
406
  * Parse a DER / BER `Buffer` or a PEM string into a structured PFX:
407
407
  * `{ version, integrityMode, mac, macedBytes, authSafeSigned, safeBags,
408
408
  * encryptedSafes }`. `integrityMode` is `"password"` (id-data authSafe with
409
- * MacData -- `mac` carries `{ kind, hashOid, hashName, hashParameters,
409
+ * MacData: `mac` carries `{ kind, hashOid, hashName, hashParameters,
410
410
  * pbmac1, macValue, macSalt, iterations }`, where `kind` distinguishes the
411
411
  * RFC 9579 PBMAC1 arm; for PBMAC1 the required parameters are validated and
412
412
  * decoded onto `pbmac1` (`{ kdf: { salt, iterationCount, keyLength, prfOid,
@@ -19,7 +19,7 @@
19
19
  *
20
20
  * A PKCS#8 key is a container, not a signed structure: it has no signature, no
21
21
  * distinguished name, and no to-be-signed region. The private-key OCTET STRING
22
- * content is kept raw -- the algorithm-specific inner key (an RSAPrivateKey, an
22
+ * content is kept raw: the algorithm-specific inner key (an RSAPrivateKey, an
23
23
  * ECPrivateKey, a CurvePrivateKey) is decoded by the caller using the surfaced
24
24
  * algorithm OID, so an unknown or future key type never fails the parse. An
25
25
  * `ENCRYPTED PRIVATE KEY` (EncryptedPrivateKeyInfo, RFC 5958 sec. 3) is recognized
@@ -28,7 +28,7 @@
28
28
  *
29
29
  * @card
30
30
  * Parse DER / PEM PKCS#8 private keys (RFC 5208 / 5958) into structured,
31
- * validated fields -- algorithm, raw key bytes, attributes, optional public key,
31
+ * validated fields: algorithm, raw key bytes, attributes, optional public key,
32
32
  * fail-closed. Encrypted keys are recognized, not decrypted.
33
33
  */
34
34
 
@@ -37,7 +37,7 @@
37
37
  *
38
38
  * @card
39
39
  * Decode RFC 5035 ESS SigningCertificate / SigningCertificateV2 and RFC 8551
40
- * SMIMECapabilities signed-attribute values -- cert-hash binding, validated
40
+ * SMIMECapabilities signed-attribute values: cert-hash binding, validated
41
41
  * issuer GeneralNames, ordered capability list, OID-dispatched, fail-closed.
42
42
  */
43
43
 
package/lib/schema-tsp.js CHANGED
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * @intro
13
13
  * RFC 3161 Time-Stamp Protocol handling. A `TimeStampResp` is what a client
14
- * receives from a TSA -- a `PKIStatusInfo` plus, on success, a `TimeStampToken`;
14
+ * receives from a TSA: a `PKIStatusInfo` plus, on success, a `TimeStampToken`;
15
15
  * `parse` decodes it and enforces the status-to-token coupling (a granted
16
16
  * response carries a token, a rejection does not). A `TimeStampToken` is itself a
17
17
  * CMS SignedData whose encapsulated content is a `TSTInfo`, so `parseToken`
@@ -279,8 +279,8 @@ var parseRequest = pkix.makeParser({ pemLabel: null, PemError: PemError, ErrorCl
279
279
  * @spec RFC 3161
280
280
  * @related pki.schema.tsp.parseToken, pki.schema.tsp.parse
281
281
  *
282
- * Parse a bare `TSTInfo` payload (a DER `Buffer`) -- the structure a timestamp token
283
- * encapsulates -- into `{ version, policy, messageImprint, serialNumber, genTime,
282
+ * Parse a bare `TSTInfo` payload (a DER `Buffer`, the structure a timestamp token
283
+ * encapsulates) into `{ version, policy, messageImprint, serialNumber, genTime,
284
284
  * accuracy, ordering, nonce, tsa, extensions }`. `messageImprint.hashedMessage` is
285
285
  * the raw digest; `serialNumber` / `nonce` are lossless (BigInt + hex); `genTime` is
286
286
  * a `Date` with sub-second precision. A malformed structure throws a typed
@@ -312,7 +312,7 @@ var parseTstInfo = pkix.makeParser({ pemLabel: null, PemError: PemError, ErrorCl
312
312
  *
313
313
  * Parse a DER `Buffer` or a PEM string into a `TimeStampResp`: `{ status,
314
314
  * statusString, failInfo, timeStampToken }`. The status-to-token coupling is
315
- * enforced -- a granted response (status 0/1) carries `timeStampToken` (surfaced raw
315
+ * enforced: a granted response (status 0/1) carries `timeStampToken` (surfaced raw
316
316
  * for `parseToken`), any other status does not. `failInfo` decodes the
317
317
  * `PKIFailureInfo` named bits. A malformed structure throws a typed `TspError`.
318
318
  *
@@ -340,7 +340,7 @@ var parse = pkix.makeParser({ pemLabel: null, PemError: PemError, ErrorClass: Ts
340
340
  * @spec RFC 3161, RFC 5652
341
341
  * @related pki.schema.tsp.parse, pki.schema.cms.parse
342
342
  *
343
- * Parse a `TimeStampToken` (a DER `Buffer` or PEM) -- a CMS SignedData whose
343
+ * Parse a `TimeStampToken` (a DER `Buffer` or PEM): a CMS SignedData whose
344
344
  * encapsulated content is a `TSTInfo`. Composes `pki.schema.cms.parse`, asserts the
345
345
  * `id-ct-TSTInfo` content type (`tsp/wrong-econtent-type`), that the content is
346
346
  * attached (`tsp/detached-token`), the single-signer rule (`tsp/multi-signer`,
@@ -434,7 +434,7 @@ function pemDecode(text, label) { return pkix.pemDecode(text, label || null, Pem
434
434
  * @related pki.schema.tsp.pemDecode
435
435
  *
436
436
  * Wrap DER bytes in a PEM envelope. RFC 3161 defines no standard PEM label, so
437
- * `label` is REQUIRED -- the operator names the envelope explicitly (mirroring
437
+ * `label` is REQUIRED: the operator names the envelope explicitly (mirroring
438
438
  * `pemDecode`, which accepts any label). Omitting it throws `pem/bad-label`.
439
439
  *
440
440
  * @example
@@ -12,7 +12,7 @@
12
12
  *
13
13
  * @intro
14
14
  * X.509 certificate handling per RFC 5280. The seed surface is
15
- * `parse` -- turn a DER or PEM certificate into a structured,
15
+ * `parse`, which turns a DER or PEM certificate into a structured,
16
16
  * fully-decoded object: version, serial, signature algorithm, issuer
17
17
  * and subject distinguished names, validity window (as real `Date`s),
18
18
  * subject public-key info, and the extension list. The parser composes
@@ -49,7 +49,7 @@ var PemError = frameworkError.PemError;
49
49
  * @related pki.schema.x509.pemEncode
50
50
  *
51
51
  * Extract the DER bytes from a PEM block (default label `CERTIFICATE`, the
52
- * RFC 7468 sec. 5 armor -- the canonical-label default every sibling format
52
+ * RFC 7468 sec. 5 armor, the canonical-label default every sibling format
53
53
  * applies). Pass a `label` to enforce a different block type, or an explicit
54
54
  * `null` to take the first block of any type. Throws `PemError` on a
55
55
  * missing / mismatched envelope or a non-base64 body.
package/lib/shbs.js CHANGED
@@ -6,10 +6,9 @@
6
6
  * @nav Signatures
7
7
  * @title Stateful hash-based
8
8
  * @fullname Stateful hash-based signatures: LMS and XMSS
9
- * @intro Stateful hash-based signature VERIFICATION -- HSS/LMS (RFC 8554),
9
+ * @intro Stateful hash-based signature VERIFICATION: HSS/LMS (RFC 8554),
10
10
  * carried in X.509 by RFC 9802 and in CMS by RFC 9708, profiled by NIST
11
- * SP 800-208. Verify only, by deliberate design: stateful hash-based signing
12
- * is catastrophic to get wrong. Each one-time key must be used exactly once,
11
+ * SP 800-208. Verify only. Each one-time key must be used exactly once,
13
12
  * so the private key embeds a monotonic index whose state must advance and
14
13
  * persist atomically across every signature and every process restart. A single
15
14
  * index reuse (a restored VM snapshot, a crashed writer, a concurrent signer)
@@ -222,7 +221,7 @@ function _asBytes(x, label) { return guard.bytes.source(x, ShbsError, "shbs/bad-
222
221
  * @related pki.shbs.verifyLms
223
222
  *
224
223
  * Verify an HSS (Hierarchical Signature System) signature over `message` under
225
- * `publicKey` -- the wire form RFC 9802 (X.509) and RFC 9708 (CMS) carry for
224
+ * `publicKey`, the wire form RFC 9802 (X.509) and RFC 9708 (CMS) carry for
226
225
  * `id-alg-hss-lms-hashsig`. The public key and signature are the raw HSS octet
227
226
  * blobs the certificate / CMS parsers already surface (no ASN.1 wrapping). Every
228
227
  * level of the hierarchy must verify: a single failing level yields false.
@@ -46,7 +46,7 @@ var MLDSA_SUITABLE_DIGEST = {
46
46
  "ML-DSA-65": { sha384: 1, sha512: 1, shake256: 1 },
47
47
  "ML-DSA-87": { sha512: 1, shake256: 1 },
48
48
  };
49
- // @enforced-by behavioral -- an own-property table read has no rename-proof shape distinct from a
49
+ // @enforced-by behavioral -- an own-property table read has no rename-proof shape distinct from a legitimate lookup, so a RED conformance vector is the guard
50
50
  function mldsaDigestSuitable(mlName, md) {
51
51
  if (!intrinsic.hasOwn(MLDSA_SUITABLE_DIGEST, mlName)) return false;
52
52
  var row = MLDSA_SUITABLE_DIGEST[mlName];