@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/crl-sign.js CHANGED
@@ -9,7 +9,7 @@
9
9
  * @fullname CRLs (certificate revocation lists): read, sign and shard
10
10
  * @intro The X.509 CRL producing side. `pki.crl.sign` builds a `TBSCertList`, signs it, and emits a
11
11
  * `CertificateList` (RFC 5280 sec. 5) that `pki.schema.crl.parse`, `pki.path.crlChecker`, and OpenSSL
12
- * all accept -- over any signature algorithm the toolkit registry resolves: RSA (PKCS#1 v1.5 / PSS),
12
+ * all accept, over any signature algorithm the toolkit registry resolves: RSA (PKCS#1 v1.5 / PSS),
13
13
  * ECDSA, EdDSA, ML-DSA, SLH-DSA, and the composite (hybrid) arms. `pki.crl.verify` checks a CRL
14
14
  * signature through the one path-validation signature engine, and `pki.crl.isRevoked` looks a serial up
15
15
  * in a parsed CRL. Parsing lives at `pki.schema.crl.parse`.
@@ -413,7 +413,7 @@ function _sign(spec, issuer, opts) {
413
413
  * @defends crl-forgery (CWE-347)
414
414
  * @related pki.schema.crl.parse, pki.crl.verify, pki.path.crlChecker
415
415
  *
416
- * Build, sign, and DER-encode an X.509 certificate revocation list. `spec` describes the CRL --
416
+ * Build, sign, and DER-encode an X.509 certificate revocation list. `spec` describes the CRL:
417
417
  * `thisUpdate` / `nextUpdate` (`Date`s), an optional `crlNumber`, a `revoked` array (each entry a
418
418
  * `serialNumber` + `revocationDate` with an optional `reason` or `invalidityDate`),
419
419
  * and an optional `extensions` object (`authorityKeyIdentifier`, `issuingDistributionPoint`,
@@ -491,8 +491,8 @@ function _issuerMaySign(parsed, cert) {
491
491
  * Verify a CRL's signature over its exact parsed `tbsCertList` bytes under the issuer public key. `crl`
492
492
  * is a DER `Buffer`, a PEM string, or a parsed CRL; `issuer` is `{ cert }` (DER/PEM/parsed), `{ publicKey }`
493
493
  * (SPKI DER), or a raw SPKI `Buffer`. Verification composes the one path-validation signature engine
494
- * `pki.path.crlChecker` uses -- the same algorithm-confusion (RFC 9814 sec. 4 key-OID == sig-OID) and
495
- * EdDSA low-order-point gates -- so there is no second, weaker CRL verifier. The verdict's `valid` is
494
+ * `pki.path.crlChecker` uses, the same algorithm-confusion (RFC 9814 sec. 4 key-OID == sig-OID) and
495
+ * EdDSA low-order-point gates, so there is no second, weaker CRL verifier. The verdict's `valid` is
496
496
  * `false` on any verification fault, and `signatureValid` reports the signature check on its own; malformed
497
497
  * input throws a typed `CrlError`.
498
498
  *
@@ -571,7 +571,7 @@ function _serialHexOf(serial) {
571
571
  * refused rather than answered from (`crl/not-current`): one whose `thisUpdate` is later, one whose
572
572
  * `nextUpdate` has passed, and one carrying no `nextUpdate` at all, which states no window and so cannot
573
573
  * be told from a replayed copy. Without `opts.time` currency goes unasked and the verb is the structural
574
- * lookup it has always been -- `null` then means "not listed on this CRL", which is weaker than "not
574
+ * lookup it has always been; `null` then means "not listed on this CRL", which is weaker than "not
575
575
  * revoked". `pki.path.crlChecker` decides currency against the material it fetched and is the verb to
576
576
  * reach for when the answer has to mean the stronger thing.
577
577
  *
package/lib/crmf-sign.js CHANGED
@@ -8,7 +8,7 @@
8
8
  * @title Certificate request messages
9
9
  * @fullname CRMF (Certificate Request Message Format, RFC 4211)
10
10
  * @intro The RFC 4211 certificate-request-message producing side. `pki.crmf.build` assembles a
11
- * `CertReqMessages` -- one or more `CertReqMsg`, each a `CertRequest` (a `CertTemplate` of the requested
11
+ * `CertReqMessages`: one or more `CertReqMsg`, each a `CertRequest` (a `CertTemplate` of the requested
12
12
  * certificate fields plus optional controls) paired with a proof of possession. The common proof is a
13
13
  * `POPOSigningKey` signature over the `CertRequest`, made with the private half of the key being
14
14
  * certified (the requester proves possession, exactly as a PKCS#10 CSR does). The message drops into a
@@ -355,7 +355,7 @@ function _buildProofOfPossession(pop, certReqDer, template, signingKey, opts) {
355
355
  * subjectKeyIdentifier, or pre-encoded Extension DER), and an optional `version` (2)), optional `controls`
356
356
  * and `regInfo` (an object of regToken / authenticator / utf8Pairs / oldCertID / protocolEncrKey, or
357
357
  * pre-encoded AttributeTypeAndValue DER), and an optional `pop` selector. `key` (or `{ key }`) is the
358
- * REQUESTER's private key -- the private half of `certTemplate.publicKey`; the message carries a
358
+ * REQUESTER's private key, the private half of `certTemplate.publicKey`; the message carries a
359
359
  * `POPOSigningKey` proof of possession signed with it (verified before the message is returned), exactly
360
360
  * as a PKCS#10 CSR proves possession. The signature algorithm is resolved from the requested public key
361
361
  * (RSA PKCS#1 v1.5 / PSS, ECDSA, EdDSA, ML-DSA, SLH-DSA, or a composite arm). `key` is optional: omit it
@@ -373,7 +373,7 @@ function _buildProofOfPossession(pop, certReqDer, template, signingKey, opts) {
373
373
  * content type is `id-ct-encKeyWithID`. RFC 9810 sec. 5.2.8.3.1 permits it only where archival is
374
374
  * intended, so it takes `pop.archive: true`; `pop.privateKey` is the PKCS#8 DER, `pop.recipients` the CMS
375
375
  * recipients to envelope it to, and `pop.identifier` (a string or GeneralName) is required, because
376
- * sec. 4.2.1 makes it mandatory whenever the purpose is proving possession -- without it a decrypting
376
+ * sec. 4.2.1 makes it mandatory whenever the purpose is proving possession: without it a decrypting
377
377
  * agent cannot tell whose key it holds. `pop.contentEncryptionAlgorithm` defaults to `aes-256-cbc`; an
378
378
  * AEAD algorithm is refused, since it would produce an `AuthEnvelopedData` this field cannot carry.
379
379
  *
package/lib/csr-sign.js CHANGED
@@ -179,8 +179,8 @@ function _coerceCsr(request) {
179
179
  * requested extension, so none of them were altered after signing. It says nothing about who the
180
180
  * producer is: the key is self-asserted, the name is self-asserted, and a requester free to choose
181
181
  * both can prove possession of a key they generated a moment ago under any name they like. Binding
182
- * that name to an identity is the enrollment protocol's job -- `pki.est`, `pki.cmc`, `pki.cmp`, or
183
- * an out-of-band check -- and remains one after this returns `true`.
182
+ * that name to an identity is the enrollment protocol's job (`pki.est`, `pki.cmc`, `pki.cmp`, or
183
+ * an out-of-band check), and remains one after this returns `true`.
184
184
  *
185
185
  * Verification composes the one path-validation signature engine, with the same algorithm-confusion
186
186
  * (RFC 9814 sec. 4 key-OID == sig-OID) and EdDSA low-order-point gates, rather than the self-check
package/lib/ct.js CHANGED
@@ -34,7 +34,7 @@
34
34
  *
35
35
  * @card
36
36
  * Parse RFC 6962 Certificate Transparency SCT lists from a certificate or OCSP
37
- * extension -- per-SCT logId / timestamp (BigInt) / algorithm / raw signature,
37
+ * extension: per-SCT logId / timestamp (BigInt) / algorithm / raw signature,
38
38
  * the signed-preimage reconstruction surfaced for external verification,
39
39
  * bounded TLS-struct decode, fail-closed.
40
40
  */
@@ -230,13 +230,13 @@ function _u24Bytes(n) {
230
230
  * `entry` selects the log-entry arm:
231
231
  * - `{ entryType: 0, leafCert: <DER Buffer> }`, an SCT delivered over TLS /
232
232
  * OCSP, signed over `x509_entry(0)` with the leaf certificate.
233
- * - `{ entryType: 1, tbsCertificate: <DER Buffer>, issuerKeyHash: <32B> }` --
233
+ * - `{ entryType: 1, tbsCertificate: <DER Buffer>, issuerKeyHash: <32B> }`,
234
234
  * an SCT EMBEDDED in a certificate, signed over `precert_entry(1)` with the
235
235
  * issuer key hash + the precertificate TBS (the TBS with only the SCT
236
236
  * extension removed). `issuerKeyHash` is SHA-256 of the issuer's SPKI DER.
237
237
  *
238
238
  * The preimage reuses the parsed SCT's raw `extensions` byte-for-byte and
239
- * re-emits the fixed-width scalars canonically. This never verifies anything --
239
+ * re-emits the fixed-width scalars canonically. This never verifies anything;
240
240
  * a verifier hashes the returned bytes and checks the signature with the log's
241
241
  * public key (compose `webcrypto`). Throws `CtError` (`ct/bad-entry-type`,
242
242
  * `ct/bad-issuer-key-hash`, `ct/bad-tbs-length`) on a malformed entry, and
package/lib/est.js CHANGED
@@ -11,15 +11,15 @@
11
11
  *
12
12
  * @intro
13
13
  * Enrollment over Secure Transport (RFC 7030, updated by RFC 8951 and RFC 9908).
14
- * The network verbs -- `cacerts`, `simpleenroll`, `simplereenroll` -- run the thin
14
+ * The network verbs (`cacerts`, `simpleenroll`, `simplereenroll`) run the thin
15
15
  * RFC 7030 client: they compose the codecs below over the shared `pki.transport`
16
16
  * (a caller MAY inject `opts.transport`; the default is a fail-closed
17
17
  * `pki.transport.https`). This module opens no socket itself: the sole socket
18
18
  * choke point is `pki.transport`, so the verbs stay a thin, fail-closed shell:
19
19
  * https-only (`est/insecure-url`), an explicit trust anchor required
20
20
  * (`est/no-trust-anchors`), same-origin redirects followed but a downgrade / loop
21
- * refused, a 202 Retry-After SURFACED and never slept, HTTP Basic answered only
22
- * after the transport authenticated the server, and the issued certificate chosen
21
+ * refused, a 202 Retry-After SURFACED and never slept, HTTP Basic or Digest answered
22
+ * only after the transport authenticated the server, and the issued certificate chosen
23
23
  * by public-key match. Under them sit the transport-agnostic codecs, validators, and
24
24
  * request builders over the shipped CMS / CSR / PKCS#8 / X.509 parsers:
25
25
  * `transferDecode` / `transferEncode` are the RFC 8951
@@ -30,9 +30,9 @@
30
30
  * `parseServerKeygenResponse` dispatches the two-part key + certificate
31
31
  * response with recipient-arm coherence; `classifyResponse` is the HTTP status
32
32
  * / content-type / Retry-After state machine (202 accepted-not-ready surfaces
33
- * `retryAfterSeconds` -- never an internal sleep; 204/404 on /csrattrs is a
33
+ * `retryAfterSeconds`, never an internal sleep; 204/404 on /csrattrs is a
34
34
  * "none available" verdict, not an error). The builders assemble the CSR
35
- * attributes EST adds -- a channel-binding challengePassword, the
35
+ * attributes EST adds: a channel-binding challengePassword, the
36
36
  * out-of-band-key identifiers, SMIMECapabilities, and the RFC 9908
37
37
  * template-priority enroll plan.
38
38
  *
@@ -100,7 +100,7 @@ var OPERATIONS = ["cacerts", "simpleenroll", "simplereenroll", "fullcmc", "serve
100
100
 
101
101
  var CLIENT_OPTS = {
102
102
  transport: 1, tls: 1, label: 1, timeout: 1, maxResponseBytes: 1, maxRedirects: 1, now: 1,
103
- auth: 1, username: 1, password: 1, allowCrossOriginRedirect: 1,
103
+ auth: 1, username: 1, password: 1, allowCrossOriginRedirect: 1, proxy: 1,
104
104
  };
105
105
  function _withClient(extra) {
106
106
  var out = {};
@@ -133,6 +133,9 @@ function _knownOpts(opts, known, verb) {
133
133
  });
134
134
  }
135
135
 
136
+ function _snapProxy(opts) { return httpTransport.snapshotProxy(opts.proxy); }
137
+ function _rej(e) { return Promise.reject(e); }
138
+
136
139
 
137
140
  /**
138
141
  * @primitive pki.est.transferDecode
@@ -533,7 +536,7 @@ var NOT_IMPLEMENTED_OPS = { fullcmc: 1 };
533
536
  *
534
537
  * Classify an EST HTTP response into a verdict or a typed fault. A 200 requires
535
538
  * the operation's exact content-type (`est/bad-content-type`); a 202 requires a
536
- * Retry-After (absent -> `est/missing-retry-after`) -- a delay-seconds value is
539
+ * Retry-After (absent -> `est/missing-retry-after`): a delay-seconds value is
537
540
  * surfaced as bounded `retryAfterSeconds`, an HTTP-date as absolute
538
541
  * `retryAfterDate` (epoch ms; `retryAfterSeconds` too when `opts.now` is given),
539
542
  * and any other value is `est/bad-retry-after` (never slept on either way);
@@ -846,7 +849,7 @@ function _drive(method, url, body, headers, opts, transport, budgets) {
846
849
  return hh;
847
850
  }
848
851
  function step() {
849
- return transport({ method: method, url: url.href, headers: _headersFor(url), body: body, tls: _tlsFor(url), timeout: budgets.timeout, maxResponseBytes: budgets.maxResponseBytes }).then(function (res) {
852
+ return transport({ method: method, url: url.href, headers: _headersFor(url), body: body, tls: _tlsFor(url), proxy: budgets.proxy, timeout: budgets.timeout, maxResponseBytes: budgets.maxResponseBytes }).then(function (res) {
850
853
  res = res || {};
851
854
  var blen = _bodyLen(res);
852
855
  if (blen > budgets.maxResponseBytes) throw E("est/response-too-large", "the response body (" + blen + " bytes) exceeds the " + budgets.maxResponseBytes + "-byte cap (RFC 7030 sec. 6)");
@@ -909,7 +912,7 @@ function _drive(method, url, body, headers, opts, transport, budgets) {
909
912
  return step();
910
913
  }
911
914
 
912
- function _client(op, method, baseUrl, body, headers, opts) {
915
+ function _client(op, method, baseUrl, body, headers, opts, proxySnap) {
913
916
  var base;
914
917
  try { base = new URL(String(baseUrl)); }
915
918
  catch (e) { throw E("est/bad-url", "the EST base URL did not parse: " + guard.text.showValue(baseUrl), e); }
@@ -924,6 +927,7 @@ function _client(op, method, baseUrl, body, headers, opts) {
924
927
  }
925
928
  var budgets = {
926
929
  tls: _tlsForRequest(opts),
930
+ proxy: proxySnap,
927
931
  timeout: guard.limits.cap(opts.timeout, "timeout", DEFAULT_TIMEOUT, { E: E, code: "est/bad-input", min: 1, max: MAX_TIMEOUT }),
928
932
  maxResponseBytes: guard.limits.cap(opts.maxResponseBytes, "maxResponseBytes", constants.LIMITS.HTTP_MAX_RESPONSE_BYTES, { E: E, code: "est/bad-input", min: 1, max: constants.LIMITS.HTTP_MAX_RESPONSE_BYTES }),
929
933
  maxRedirects: guard.limits.cap(opts.maxRedirects, "maxRedirects", 5, { E: E, code: "est/bad-input", min: 0, max: 32 }),
@@ -1002,7 +1006,7 @@ function _certsResult(op, res, opts, csrSpki) {
1002
1006
  * surfaced as `issuedCertificates` (with `certificate` the first), distinct from `certificates`,
1003
1007
  * which is the whole returned bag including any chain. Where the requested keys are distinct that
1004
1008
  * list is in request order; where several requests deliberately SHARE one key it is not, and does
1005
- * not claim to be -- the public key is the only identification sec. 4.1 sanctions, so when it is
1009
+ * not claim to be: the public key is the only identification sec. 4.1 sanctions, so when it is
1006
1010
  * shared nothing in the response says which of those requests a given certificate answers. That arm reports `signatureVerified: false`: a certs-only body is
1007
1011
  * a degenerate SignedData with no signers by definition, so its security rests on the authenticated
1008
1012
  * TLS channel, not on a signature.
@@ -1012,7 +1016,7 @@ function _certsResult(op, res, opts, csrSpki) {
1012
1016
  * response is SURFACED, never acted on (RFC 5272 sec. 6.15 makes accepting one a manual decision).
1013
1017
  *
1014
1018
  * @opts
1015
- * - `transport` / `tls` / `label` / `timeout` / `maxResponseBytes` / `maxRedirects` / `now`, as in pki.est.cacerts.
1019
+ * - `transport` / `tls` / `label` / `timeout` / `maxResponseBytes` / `maxRedirects` / `proxy` / `now`, as in pki.est.cacerts.
1016
1020
  * - `transactionId` / `senderNonce` / `dataReturn`: what the request sent. The values are read out
1017
1021
  * of the request itself; supplying them here cross-checks that, and a disagreement is refused.
1018
1022
  * - `responderCerts`: extra certificates for CMC signer lookup, for a response that does not carry
@@ -1049,16 +1053,18 @@ function fullcmc(baseUrl, request, opts) {
1049
1053
  try {
1050
1054
  if (typeof opts !== "object" || Buffer.isBuffer(opts)) throw E("est/bad-input", "pki.est.fullcmc options must be an object");
1051
1055
  _knownOpts(opts, FULLCMC_OPTS, "fullcmc");
1056
+ var proxySnap;
1057
+ try { proxySnap = _snapProxy(opts); } catch (_pe) { throw E("est/bad-input", "the options object could not be read", _pe); }
1052
1058
  der = _cmcRequestDer(request);
1053
1059
  wanted = _requestedPublicKeys(der);
1054
1060
  sent = _cmcSent(opts, der);
1055
1061
  opts = _shallowCopy(opts);
1056
1062
  var body = transferEncode(der);
1057
1063
  return _client("fullcmc", "POST", baseUrl, body,
1058
- { accept: "application/pkcs7-mime", "content-type": "application/pkcs7-mime; smime-type=CMC-request" }, opts)
1064
+ { accept: "application/pkcs7-mime", "content-type": "application/pkcs7-mime; smime-type=CMC-request" }, opts, proxySnap)
1059
1065
  .then(function (res) { return _fullcmcResult(res, opts, wanted, sent); });
1060
1066
  } catch (e) {
1061
- return Promise.reject(e);
1067
+ return _rej(e);
1062
1068
  }
1063
1069
  }
1064
1070
 
@@ -1357,11 +1363,11 @@ function _tryDecodeCmcFault(res, sent) {
1357
1363
  }).then(null, function () { return null; });
1358
1364
  }
1359
1365
 
1360
- function _enroll(op, baseUrl, csrInput, opts) {
1366
+ function _enroll(op, baseUrl, csrInput, opts, proxySnap) {
1361
1367
  var csrDer = _csrDer(csrInput);
1362
1368
  var spki = csr.parse(csrDer).subjectPublicKeyInfo;
1363
1369
  var body = transferEncode(csrDer);
1364
- return _client(op, "POST", baseUrl, body, { accept: "application/pkcs7-mime", "content-type": "application/pkcs10" }, opts)
1370
+ return _client(op, "POST", baseUrl, body, { accept: "application/pkcs7-mime", "content-type": "application/pkcs10" }, opts, proxySnap)
1365
1371
  .then(function (res) { return _certsResult(op, res, opts, spki); });
1366
1372
  }
1367
1373
 
@@ -1386,6 +1392,7 @@ function _enroll(op, baseUrl, csrInput, opts) {
1386
1392
  * - `transport`: an injected transport(request) -> {status, headers, body, tls}; default pki.transport.https.
1387
1393
  * - `tls` -- { anchors, useSystemStore, cert, key, minVersion, servername, checkServerIdentity }.
1388
1394
  * - `label` -- an OPTIONAL CA label path segment; `timeout` / `maxResponseBytes` / `maxRedirects` -- budgets.
1395
+ * - `proxy` -- reach the CA through a forward HTTP proxy (`{ url, auth?, tls? }`; see pki.transport).
1389
1396
  * - `now` -- receipt time (epoch ms) to render a 202 Retry-After HTTP-date as seconds.
1390
1397
  * - `auth` -- HTTP authentication: `{ scheme: "basic" | "digest", username, password, allowMD5, allowLegacyQop, maxStaleRetries }`.
1391
1398
  * There is no `"auto"`: the scheme is chosen here, not by whatever a server offers. `username` / `password`
@@ -1399,9 +1406,10 @@ function _enroll(op, baseUrl, csrInput, opts) {
1399
1406
  */
1400
1407
  function cacerts(baseUrl, opts) {
1401
1408
  opts = opts || {};
1409
+ var proxySnap; try { proxySnap = _snapProxy(opts); } catch (_pe) { return _rej(E("est/bad-input", "the options object could not be read", _pe)); }
1402
1410
  return Promise.resolve().then(function () {
1403
1411
  _knownOpts(opts, CACERTS_OPTS, "cacerts");
1404
- return _client("cacerts", "GET", baseUrl, null, { accept: "application/pkcs7-mime" }, opts);
1412
+ return _client("cacerts", "GET", baseUrl, null, { accept: "application/pkcs7-mime" }, opts, proxySnap);
1405
1413
  }).then(function (res) { return _certsResult("cacerts", res, opts, null); });
1406
1414
  }
1407
1415
 
@@ -1424,9 +1432,9 @@ function cacerts(baseUrl, opts) {
1424
1432
  * the transport already authenticated the server.
1425
1433
  *
1426
1434
  * @opts
1427
- * - `transport` / `tls` / `label` / `timeout` / `maxResponseBytes` / `maxRedirects` / `now`, as in pki.est.cacerts.
1435
+ * - `transport` / `tls` / `label` / `timeout` / `maxResponseBytes` / `maxRedirects` / `proxy` / `now`, as in pki.est.cacerts.
1428
1436
  * - `strict`: reject an enroll response that carries more than the single issued certificate.
1429
- * - `username` / `password` -- HTTP Basic credentials, answered only after server authorization (empty username allowed).
1437
+ * - `username` / `password` / `auth` -- HTTP credentials: top-level `username` / `password` mean Basic; `auth` (`{ scheme: "basic" | "digest", username, password, ... }`, as in pki.est.cacerts) selects Basic or Digest. Answered only after server authorization (empty username allowed).
1430
1438
  * - `allowCrossOriginRedirect` -- opt in to following a cross-origin redirect on this POST.
1431
1439
  * @example
1432
1440
  * var req = await pki.csr.sign({ subject: "device.example", subjectPublicKey: signerSpki }, { key: signerKeyPkcs8 });
@@ -1437,9 +1445,10 @@ function cacerts(baseUrl, opts) {
1437
1445
  */
1438
1446
  function simpleenroll(baseUrl, csrInput, opts) {
1439
1447
  opts = opts || {};
1448
+ var proxySnap; try { proxySnap = _snapProxy(opts); } catch (_pe) { return _rej(E("est/bad-input", "the options object could not be read", _pe)); }
1440
1449
  return Promise.resolve().then(function () {
1441
1450
  _knownOpts(opts, SIMPLEENROLL_OPTS, "simpleenroll");
1442
- return _enroll("simpleenroll", baseUrl, csrInput, opts);
1451
+ return _enroll("simpleenroll", baseUrl, csrInput, opts, proxySnap);
1443
1452
  });
1444
1453
  }
1445
1454
 
@@ -1470,11 +1479,12 @@ function simpleenroll(baseUrl, csrInput, opts) {
1470
1479
  */
1471
1480
  function simplereenroll(baseUrl, csrInput, opts) {
1472
1481
  opts = opts || {};
1482
+ var proxySnap; try { proxySnap = _snapProxy(opts); } catch (_pe) { return _rej(E("est/bad-input", "the options object could not be read", _pe)); }
1473
1483
  return Promise.resolve().then(function () {
1474
1484
  _knownOpts(opts, SIMPLEREENROLL_OPTS, "simplereenroll");
1475
1485
  if (!opts.oldCert) throw E("est/bad-input", "simplereenroll requires opts.oldCert (the certificate being renewed, RFC 7030 sec. 4.2.2)");
1476
1486
  reenrollGuard(opts.oldCert, _csrDer(csrInput));
1477
- return _enroll("simplereenroll", baseUrl, csrInput, opts);
1487
+ return _enroll("simplereenroll", baseUrl, csrInput, opts, proxySnap);
1478
1488
  });
1479
1489
  }
1480
1490
 
@@ -1613,6 +1623,7 @@ async function _serverkeygenResult(res, opts, derived) {
1613
1623
  */
1614
1624
  function serverkeygen(baseUrl, csrInput, opts) {
1615
1625
  opts = opts || {};
1626
+ var proxySnap; try { proxySnap = _snapProxy(opts); } catch (_pe) { return _rej(E("est/bad-input", "the options object could not be read", _pe)); }
1616
1627
  return Promise.resolve().then(function () {
1617
1628
  _knownOpts(opts, SERVERKEYGEN_OPTS, "serverkeygen");
1618
1629
  var csrDer = _csrDer(csrInput);
@@ -1631,7 +1642,7 @@ function serverkeygen(baseUrl, csrInput, opts) {
1631
1642
  if ((opts.expectedRecipientKeyId !== undefined || opts.expectedRecipientIssuerSerial != null) && !derived.requestedEncryption) {
1632
1643
  throw E("est/bad-input", "a recipient expectation (expectedRecipientKeyId / expectedRecipientIssuerSerial) implies an encrypted key, but the CSR advertised no DecryptKeyIdentifier / AsymmetricDecryptKeyIdentifier attribute (RFC 7030 sec. 4.4.1)");
1633
1644
  }
1634
- return _client("serverkeygen", "POST", baseUrl, transferEncode(csrDer), { accept: "multipart/mixed", "content-type": "application/pkcs10" }, opts)
1645
+ return _client("serverkeygen", "POST", baseUrl, transferEncode(csrDer), { accept: "multipart/mixed", "content-type": "application/pkcs10" }, opts, proxySnap)
1635
1646
  .then(function (res) { return _serverkeygenResult(res, opts, derived); });
1636
1647
  });
1637
1648
  }
@@ -1673,9 +1684,10 @@ function _csrattrsResult(res, opts) {
1673
1684
  */
1674
1685
  function csrattrs(baseUrl, opts) {
1675
1686
  opts = opts || {};
1687
+ var proxySnap; try { proxySnap = _snapProxy(opts); } catch (_pe) { return _rej(E("est/bad-input", "the options object could not be read", _pe)); }
1676
1688
  return Promise.resolve().then(function () {
1677
1689
  _knownOpts(opts, CSRATTRS_OPTS, "csrattrs");
1678
- return _client("csrattrs", "GET", baseUrl, null, { accept: "application/csrattrs" }, opts);
1690
+ return _client("csrattrs", "GET", baseUrl, null, { accept: "application/csrattrs" }, opts, proxySnap);
1679
1691
  }).then(function (res) { return _csrattrsResult(res, opts); });
1680
1692
  }
1681
1693
 
@@ -90,8 +90,8 @@ class PkiError extends Error {
90
90
  * @status stable
91
91
  * @spec internal (design: error-class factory)
92
92
  *
93
- * Factory that produces a `PkiError` subclass with the standard shape --
94
- * eliminating the per-domain boilerplate. The returned constructor takes
93
+ * Factory that produces a `PkiError` subclass with the standard shape. The
94
+ * returned constructor takes
95
95
  * `(code, message)`, stamps `name`, sets an `is<Name>` flag, and exposes
96
96
  * a `.factory` static for the common `var _err = XxxError.factory` shape.
97
97
  * The `code` must be a `domain/reason` string (the base-class contract);
@@ -309,11 +309,27 @@ function _isBuiltinExotic(v) {
309
309
  t.isBoxedPrimitive(v) || t.isNativeError(v) || t.isArgumentsObject(v) || t.isGeneratorObject(v);
310
310
  }
311
311
 
312
+ function _proxyInChain(v) {
313
+ if (v === null || typeof v !== "object") return false;
314
+ var visited = new _Set();
315
+ for (var o = v; o && !_setHas(visited, o); o = _getPrototypeOf(o)) {
316
+ _setAdd(visited, o);
317
+ if (util.types.isProxy(o)) return true;
318
+ }
319
+ return false;
320
+ }
321
+ function isPlainRecord(v) {
322
+ if (v === null || typeof v !== "object") return false;
323
+ if (_proxyInChain(v)) return false;
324
+ if (_isNodeBuffer(v) || _isArray(v)) return false;
325
+ return !_isBuiltinExotic(v);
326
+ }
312
327
  // @enforced-by behavioral -- a plain-record refusal has no single rename-proof code shape worth a
313
328
  function assertPlainRecord(v, E, code, label) {
314
329
  _requireFactory(E);
315
- if (v === null || typeof v !== "object" || _isNodeBuffer(v) || _isArray(v)) throw E(code, label + " must be a plain object");
330
+ if (v === null || typeof v !== "object") throw E(code, label + " must be a plain object");
316
331
  _refuseUnenumerable(v, E, code, label);
332
+ if (_isNodeBuffer(v) || _isArray(v)) throw E(code, label + " must be a plain object");
317
333
  if (_isBuiltinExotic(v)) throw E(code, label + " must be a plain object (a built-in exotic such as a Date or Map is refused)");
318
334
  }
319
335
 
@@ -378,6 +394,7 @@ module.exports = intrinsic.freeze({
378
394
  assertCanonicalOid: assertCanonicalOid,
379
395
  assertKnownKeys: assertKnownKeys,
380
396
  assertPlainRecord: assertPlainRecord,
397
+ isPlainRecord: isPlainRecord,
381
398
  optionsObject: optionsObject,
382
399
  refuseAccessorFields: refuseAccessorFields,
383
400
  readableNames: readableNames,
package/lib/hpke.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * @nav Protocols
7
7
  * @title HPKE
8
8
  * @fullname HPKE (Hybrid Public Key Encryption, RFC 9180)
9
- * @intro Hybrid Public Key Encryption (RFC 9180) -- the standard construction
9
+ * @intro Hybrid Public Key Encryption (RFC 9180): the standard construction
10
10
  * behind TLS Encrypted Client Hello, MLS, and OHTTP that turns a recipient KEM
11
11
  * public key into an encapsulated key plus an AEAD-encrypting context. This is
12
12
  * the RFC 9180 base construction: the DHKEM suites P-256, P-521, X25519, and
@@ -358,7 +358,7 @@ var suites = {
358
358
 
359
359
  /**
360
360
  * @primitive pki.hpke.setupS
361
- * @signature pki.hpke.setupS(suiteIds, recipientPublicKey, opts?) -> { enc, context }
361
+ * @signature pki.hpke.setupS(suiteIds, recipientPublicKey, opts?) -> { enc, context, sharedSecret }
362
362
  * @since 0.2.2
363
363
  * @status stable
364
364
  * @spec RFC 9180
@@ -16,10 +16,10 @@
16
16
  * composes it (or an injected substitute) through one contract:
17
17
  * `transport(request) -> Promise<{ status, headers, body, tls }>`. The first three are
18
18
  * exactly what a message layer's classifier consumes, so no protocol semantics leak
19
- * into the socket layer -- the transport owns socket lifecycle, the TLS trust policy,
19
+ * into the socket layer: the transport owns socket lifecycle, the TLS trust policy,
20
20
  * the streaming size cap, and the timeout budget; the caller owns HTTP status,
21
21
  * content-type, redirect, and authentication decisions. `tls` reports the negotiated
22
- * channel -- `{ protocol, cipher, peerCertificate }` -- which is the one fact a caller
22
+ * channel, `{ protocol, cipher, peerCertificate }`, which is the one fact a caller
23
23
  * cannot recover from the response bytes. An INJECTED substitute should return it too:
24
24
  * `pki.est.serverkeygen` asserts the negotiated cipher can protect the private key it
25
25
  * is about to accept, and a transport that reports no cipher is trusted instead of
@@ -40,7 +40,7 @@
40
40
  * @card
41
41
  * The shared fail-closed node:https transport (est / acme / cmp): explicit trust
42
42
  * anchors, rejectUnauthorized always on, a TLS floor, a streaming response-size cap,
43
- * and a timeout -- behind one `transport(request) -> {status, headers, body, tls}` seam.
43
+ * and a timeout, behind one `transport(request) -> {status, headers, body, tls}` seam.
44
44
  */
45
45
 
46
46
  var nodeHttps = require("node:https");
@@ -48,6 +48,7 @@ var nodeHttp = require("node:http");
48
48
  var nodeNet = require("node:net");
49
49
  var nodeTls = require("node:tls");
50
50
  var nodeDns = require("node:dns");
51
+ var nodeUtil = require("node:util");
51
52
  var constants = require("./constants");
52
53
  var guard = require("./guard-all");
53
54
  var frameworkError = require("./framework-error");
@@ -197,13 +198,70 @@ var PROXY_KEYS = _keySet(["url", "auth", "tls"]);
197
198
  var PROXY_AUTH_KEYS = _keySet(["scheme", "username", "password"]);
198
199
  var PROXY_TLS_KEYS = _keySet(["anchors", "useSystemStore", "servername", "minVersion"]);
199
200
 
201
+ function _copyAnchor(a) { return (a !== null && typeof a === "object" && nodeUtil.types.isProxy(a)) ? a : (Buffer.isBuffer(a) ? Buffer.from(a) : a); }
202
+ function _noopProxyErr(code, message) { var e = new Error(message); e.code = code; e.isPkiError = true; return e; }
203
+ function _copyableRecord(p) {
204
+ if (!guard.identifier.isPlainRecord(p)) return false;
205
+ var proto = Object.getPrototypeOf(p);
206
+ if (proto !== Object.prototype && proto !== null) return false;
207
+ if (Object.getOwnPropertySymbols(p).length !== 0) return false;
208
+ var ownEnumData = 0;
209
+ var names = Object.getOwnPropertyNames(p);
210
+ for (var i = 0; i < names.length; i++) {
211
+ var d = Object.getOwnPropertyDescriptor(p, names[i]);
212
+ if (!d.enumerable || d.get || d.set) return false;
213
+ ownEnumData++;
214
+ }
215
+ var readable = guard.identifier.readableNames(p, _noopProxyErr, "transport/bad-proxy", "opts.proxy");
216
+ if (readable.length !== ownEnumData) return false;
217
+ for (var j = 0; j < readable.length; j++) {
218
+ var rd = Object.getOwnPropertyDescriptor(p, readable[j]);
219
+ if (!rd || !rd.enumerable || rd.get || rd.set) return false;
220
+ }
221
+ return true;
222
+ }
223
+ function _copyableArray(a) {
224
+ if (a === null || typeof a !== "object" || nodeUtil.types.isProxy(a) || !Array.isArray(a) || Object.getPrototypeOf(a) !== Array.prototype) return false;
225
+ if (a.length > constants.LIMITS.PROXY_MAX_TLS_ANCHORS) return false;
226
+ if (Object.getOwnPropertySymbols(a).length !== 0) return false;
227
+ var names = Object.getOwnPropertyNames(a);
228
+ for (var i = 0; i < names.length; i++) {
229
+ var d = Object.getOwnPropertyDescriptor(a, names[i]);
230
+ if (d.get || d.set) return false;
231
+ }
232
+ return true;
233
+ }
234
+ function snapshotProxy(p) {
235
+ try {
236
+ if (!_copyableRecord(p)) return p;
237
+ var out = Object.assign(Object.create(null), p);
238
+ if (_copyableRecord(p.auth)) out.auth = Object.assign(Object.create(null), p.auth);
239
+ if (_copyableRecord(p.tls)) {
240
+ out.tls = Object.assign(Object.create(null), p.tls);
241
+ var a = p.tls.anchors;
242
+ if (_copyableArray(a)) {
243
+ var copied = [];
244
+ for (var i = 0; i < a.length; i++) copied[i] = _copyAnchor(a[i]);
245
+ out.tls.anchors = copied;
246
+ } else if (typeof a === "string") out.tls.anchors = a;
247
+ else if (a !== null && typeof a === "object" && !nodeUtil.types.isProxy(a) && Buffer.isBuffer(a)) out.tls.anchors = Buffer.from(a);
248
+ }
249
+ return out;
250
+ } catch (_e) {
251
+ // allow:swallow-unverified an input whose introspection throws (a revoked Proxy, a throwing trap) returns unchanged for _validateProxy to refuse
252
+ return p;
253
+ }
254
+ }
255
+
200
256
  function _validateProxy(request, defaults, E, C, url) {
201
257
  var proxy = request.proxy !== undefined ? request.proxy : defaults.proxy;
202
258
  if (proxy === undefined || proxy === null) return null;
203
259
  guard.identifier.assertPlainRecord(proxy, E, C("bad-proxy"), "opts.proxy");
260
+ if (!_copyableRecord(proxy)) throw E(C("bad-proxy"), "opts.proxy must be a plain object with only own enumerable data properties");
204
261
  guard.identifier.assertKnownKeys(proxy, PROXY_KEYS, E, C("bad-proxy"), "opts.proxy has an unknown option ");
262
+ if (typeof proxy.url !== "string") throw E(C("bad-proxy"), "opts.proxy.url must be a string, got " + guard.text.showValue(proxy.url));
205
263
  var purl;
206
- try { purl = new URL(String(proxy.url)); }
264
+ try { purl = new URL(proxy.url); }
207
265
  catch (e) { throw E(C("bad-proxy"), "opts.proxy.url did not parse: " + guard.text.showValue(proxy.url), e); }
208
266
  if (purl.protocol !== "http:" && purl.protocol !== "https:") throw E(C("bad-proxy"), "opts.proxy.url must be an http or https URL, got " + purl.protocol);
209
267
  if (purl.username || purl.password) throw E(C("bad-proxy"), "opts.proxy.url must not carry credentials in its userinfo; supply opts.proxy.auth over an https proxy");
@@ -214,6 +272,7 @@ function _validateProxy(request, defaults, E, C, url) {
214
272
  if (proxy.auth !== undefined && proxy.auth !== null) {
215
273
  if (!secure) throw E(C("proxy-auth-requires-tls"), "proxy credentials cannot be sent over a plaintext http proxy, where the proxy hop would expose them; use an https proxy URL");
216
274
  guard.identifier.assertPlainRecord(proxy.auth, E, C("bad-proxy"), "opts.proxy.auth");
275
+ if (!_copyableRecord(proxy.auth)) throw E(C("bad-proxy"), "opts.proxy.auth must be a plain object with only own enumerable data properties");
217
276
  guard.identifier.assertKnownKeys(proxy.auth, PROXY_AUTH_KEYS, E, C("bad-proxy"), "opts.proxy.auth has an unknown option ");
218
277
  var scheme = proxy.auth.scheme;
219
278
  if (scheme === "digest") throw E(C("proxy-unsupported-scheme"), "Digest proxy authentication is not supported in this release; use 'basic' over an https proxy");
@@ -228,22 +287,25 @@ function _validateProxy(request, defaults, E, C, url) {
228
287
  var ptls = proxy.tls;
229
288
  if (ptls !== undefined && ptls !== null) {
230
289
  guard.identifier.assertPlainRecord(ptls, E, C("bad-proxy"), "opts.proxy.tls");
290
+ if (!_copyableRecord(ptls)) throw E(C("bad-proxy"), "opts.proxy.tls must be a plain object with only own enumerable data properties");
231
291
  guard.identifier.assertKnownKeys(ptls, PROXY_TLS_KEYS, E, C("bad-proxy"), "opts.proxy.tls has an unknown option ");
232
292
  if (ptls.servername !== undefined && ptls.servername !== null && typeof ptls.servername !== "string") throw E(C("bad-proxy"), "opts.proxy.tls.servername must be a string");
233
293
  }
234
294
  var pAnchors = ptls ? ptls.anchors : undefined;
295
+ if (pAnchors !== undefined && pAnchors !== null && typeof pAnchors === "object" && nodeUtil.types.isProxy(pAnchors)) throw E(C("bad-proxy"), "opts.proxy.tls.anchors must not be a Proxy");
235
296
  var pUseSystem = ptls ? ptls.useSystemStore === true : false;
236
297
  var pHasAnchors = pAnchors !== undefined && pAnchors !== null && !(Array.isArray(pAnchors) && pAnchors.length === 0);
237
298
  if (!pHasAnchors && !pUseSystem) throw E(C("bad-proxy"), "an https proxy requires explicit tls trust: set proxy.tls.anchors or proxy.tls.useSystemStore");
238
299
  if (pHasAnchors) {
300
+ if (Array.isArray(pAnchors) && !_copyableArray(pAnchors)) throw E(C("bad-proxy"), "opts.proxy.tls.anchors must be a plain array of PEM strings or DER Buffers");
239
301
  var pAnchorList = Array.isArray(pAnchors) ? pAnchors : [pAnchors];
240
302
  for (var pai = 0; pai < pAnchorList.length; pai++) {
241
303
  var pan = pAnchorList[pai];
242
- if (typeof pan !== "string" && !Buffer.isBuffer(pan)) throw E(C("bad-proxy"), "opts.proxy.tls.anchors must be a PEM string or a DER Buffer (or an array of them)");
304
+ if ((pan !== null && typeof pan === "object" && nodeUtil.types.isProxy(pan)) || (typeof pan !== "string" && !Buffer.isBuffer(pan))) throw E(C("bad-proxy"), "opts.proxy.tls.anchors must be a PEM string or a DER Buffer (or an array of them)");
243
305
  }
244
306
  }
245
- var pMinVersion = (ptls && ptls.minVersion) || DEFAULT_MIN_VERSION;
246
- if (pMinVersion !== "TLSv1.2" && pMinVersion !== "TLSv1.3") throw E(C("bad-proxy"), "proxy.tls.minVersion must be 'TLSv1.2' or 'TLSv1.3', got " + pMinVersion);
307
+ var pMinVersion = (ptls && ptls.minVersion !== undefined && ptls.minVersion !== null) ? ptls.minVersion : DEFAULT_MIN_VERSION;
308
+ if (pMinVersion !== "TLSv1.2" && pMinVersion !== "TLSv1.3") throw E(C("bad-proxy"), "proxy.tls.minVersion must be 'TLSv1.2' or 'TLSv1.3', got " + guard.text.showValue(pMinVersion));
247
309
  var pCa = [];
248
310
  if (pHasAnchors) pCa = pCa.concat(_pemifyAnchors(pAnchors));
249
311
  if (pUseSystem) pCa = pCa.concat(_systemCa());
@@ -289,7 +351,7 @@ function _proxyErrorClass(e, C) {
289
351
  * (`transport/server-auth-failed`) all fail closed; `rejectUnauthorized` is always on.
290
352
  * A protocol client passes its own error factory (`defaults.E`) + `defaults.errPrefix`
291
353
  * to surface domain codes (`est/...`). The transport owns no HTTP/redirect/auth
292
- * semantics -- those live in the message layer that consumes the response triple.
354
+ * semantics; those live in the message layer that consumes the response triple.
293
355
  *
294
356
  * @opts
295
357
  * - `tls.anchors` -- Explicit trust anchor(s): a DER/PEM Buffer, an array, or PEM string(s) (node `ca`).
@@ -370,7 +432,17 @@ function httpsTransport(defaults) {
370
432
  return callerCsi(host, cert2);
371
433
  };
372
434
  }
373
- var proxyInfo = _validateProxy(request, defaults, E, C, url);
435
+ var proxyInfo;
436
+ try { proxyInfo = _validateProxy(request, defaults, E, C, url); }
437
+ catch (e) {
438
+ var typedProxyError = false;
439
+ try {
440
+ var ec = (e instanceof Error) && !nodeUtil.types.isProxy(e) ? e.code : undefined;
441
+ typedProxyError = ec === C("bad-proxy") || ec === C("proxy-auth-requires-tls") || ec === C("proxy-unsupported-scheme");
442
+ } catch (_ie) { /* allow:swallow-unverified reading .code on a hostile error object can throw; treat any such failure as untyped */ }
443
+ if (typedProxyError) throw e;
444
+ throw E(C("bad-proxy"), "opts.proxy could not be validated", e);
445
+ }
374
446
  var blockPrivate = (request.blockPrivateAddresses !== undefined ? request.blockPrivateAddresses : defaults.blockPrivateAddresses) === true;
375
447
  if (blockPrivate && proxyInfo) throw E(C("bad-proxy"), "blockPrivateAddresses cannot be enforced through a forward proxy, which resolves the origin itself and would reach a private origin the transport never checks; use a direct connection for a private-address-blocked fetch");
376
448
  if (blockPrivate) {
@@ -526,4 +598,4 @@ function httpsTransport(defaults) {
526
598
  return _transportFn;
527
599
  }
528
600
 
529
- module.exports = { https: httpsTransport, isBlockedIp: _isBlockedIp, _makeGuardedLookup: _makeGuardedLookup, MAX_TIMEOUT: MAX_TIMEOUT };
601
+ module.exports = { https: httpsTransport, isBlockedIp: _isBlockedIp, _makeGuardedLookup: _makeGuardedLookup, MAX_TIMEOUT: MAX_TIMEOUT, snapshotProxy: snapshotProxy };
package/lib/inspect.js CHANGED
@@ -795,7 +795,7 @@ var _INSPECT_BY_FORMAT = { x509: certificate, crl: crlReport, csr: csrReport, cm
795
795
  * @related pki.schema.detectFormat, pki.inspect.certificate
796
796
  *
797
797
  * Detect which PKI format `input` (a PEM string or DER Buffer) encodes and render
798
- * it with the matching report -- the inspect analogue of `pki.schema.parse`. Routes
798
+ * it with the matching report, the inspect analogue of `pki.schema.parse`. Routes
799
799
  * a certificate / CRL / CSR / CMS to `certificate` / `crl` / `csr` / `cms`; a
800
800
  * detected but out-of-scope format (OCSP, TSP, PKCS#8/#12, CRMF, CMP, ...) throws
801
801
  * `inspect/unsupported-format` naming it, and an unrecognized input
package/lib/jose.js CHANGED
@@ -294,7 +294,7 @@ function assertPublicJwk(jwk) {
294
294
  * or the message is refused with `jose/key-mismatch`. They are compared as RFC 7638
295
295
  * thumbprints, so member order and members outside the key itself cannot make equal
296
296
  * keys look different. Without `opts.key` the embedded `jwk` is used where the
297
- * profile permits one -- which verifies that the message is internally consistent,
297
+ * profile permits one, which verifies that the message is internally consistent,
298
298
  * not that any particular signer produced it. `keySource` reports which of the two
299
299
  * answered, so a signature checked against a caller-named key is distinguishable
300
300
  * from one checked against the key the message brought with it.
package/lib/key.js CHANGED
@@ -12,7 +12,7 @@
12
12
  * `publicFromPrivate` over every algorithm the WebCrypto engine drives: RSA, EC, Ed25519/Ed448,
13
13
  * X25519/X448, and the FIPS post-quantum ML-DSA / ML-KEM. Unencrypted export / import DELEGATES to the
14
14
  * WebCrypto `exportKey` / `importKey` PKCS#8 / SPKI encoders (which already emit each algorithm's
15
- * `AlgorithmIdentifier.parameters` correctly -- RSA NULL, EC namedCurve, Ed/X ABSENT), so the wrapper
15
+ * `AlgorithmIdentifier.parameters` correctly: RSA NULL, EC namedCurve, Ed/X ABSENT), so the wrapper
16
16
  * never re-encodes an AlgorithmIdentifier. PBES2 encrypt / decrypt composes the one shared `lib/pbes2.js`
17
17
  * home (the same PBKDF2 + AES-CBC primitives `pki.cms` uses). Parsing lives at `pki.schema.pkcs8.parse`.
18
18
  * @spec RFC 5958, RFC 8018, RFC 5280
@@ -73,8 +73,8 @@ async function _toPrivateKeyDer(input) {
73
73
  * (never encrypt opaque bytes), and the produced `EncryptedPrivateKeyInfo` is re-parsed before return.
74
74
  *
75
75
  * The PBKDF2 `prf` equal to the default (`hmacWithSHA1`) is omitted from the parameters (X.690 sec. 11.5),
76
- * `keyLength` is omitted (the AES cipher OID fixes the key size), and the salt / iteration count are bounded
77
- * -- so the output is byte-exact with OpenSSL's `pkcs8 -topk8 -v2`. A bad input throws a typed `KeyError`.
76
+ * `keyLength` is omitted (the AES cipher OID fixes the key size), and the salt / iteration count are bounded,
77
+ * so the output is byte-exact with OpenSSL's `pkcs8 -topk8 -v2`. A bad input throws a typed `KeyError`.
78
78
  *
79
79
  * @opts
80
80
  * - `cipher` (string) -- `aes-256-cbc` (default), `aes-192-cbc`, or `aes-128-cbc`.
@@ -187,13 +187,13 @@ function _decryptPbes2(encAlg, ciphertext, password, opts) {
187
187
  *
188
188
  * Export an extractable `CryptoKey` to DER (or PEM): a private key as PKCS#8 `OneAsymmetricKey`, a public
189
189
  * key as SubjectPublicKeyInfo. The encoding is delegated to the WebCrypto `exportKey` PKCS#8 / SPKI encoder,
190
- * so the algorithm-specific `AlgorithmIdentifier.parameters` are byte-correct -- RSA carries an explicit
190
+ * so the algorithm-specific `AlgorithmIdentifier.parameters` are byte-correct: RSA carries an explicit
191
191
  * NULL, EC a namedCurve OID, and Ed25519 / Ed448 / X25519 / X448 omit parameters (RFC 8410 sec. 3); the
192
192
  * wrapper never re-encodes the AlgorithmIdentifier.
193
193
  *
194
194
  * The key need not have been created by this toolkit's own WebCrypto: one from the platform's, or from a
195
- * separately-installed copy of this toolkit, is exported through whichever of them holds its material,
196
- * since neither can read the other's. A key created non-extractable is refused with that as the reason,
195
+ * separately-installed copy of this toolkit, is exported through whichever of them holds its material.
196
+ * A key created non-extractable is refused with that as the reason,
197
197
  * as is one whose implementation keeps its material out of this process's reach entirely.
198
198
  *
199
199
  * @opts
@@ -231,7 +231,7 @@ async function export_(key, opts) {
231
231
  * @related pki.key.export, pki.key.decrypt
232
232
  *
233
233
  * Import a DER / PEM PKCS#8 private key, SPKI public key, or (with `opts.password`) an `ENCRYPTED PRIVATE
234
- * KEY` -- auto-detecting the structure -- into a `CryptoKey`. The WebCrypto algorithm is inferred from the
234
+ * KEY`, auto-detecting the structure, into a `CryptoKey`. The WebCrypto algorithm is inferred from the
235
235
  * key's OID for the algorithms that name exactly one (Ed25519 / Ed448 / X25519 / X448 / ML-DSA / ML-KEM /
236
236
  * SLH-DSA); RSA and EC are ambiguous between signing and key agreement, so `opts.algorithm` must be supplied
237
237
  * for them (without it the import fails closed). Default key usages follow the algorithm and key type.