@blamejs/pki 0.5.26 → 0.5.27

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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,19 @@ All notable changes to `@blamejs/pki` are documented here. The format
4
4
  follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this
5
5
  project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## v0.5.27 — 2026-08-23
8
+
9
+ A mistyped option passed to pki.trust.anchor or the pki.acme.client constructor is now refused, naming it, instead of being read as absent and silently defaulted.
10
+
11
+ ### Changed
12
+
13
+ - `pki.trust.anchor(entry, opts)` rejects an option it does not recognize, naming it, instead of ignoring it and applying the default. The one option it reads is `purpose`.
14
+ - The `pki.acme.client(directoryUrl, opts)` constructor rejects an unrecognized option the same way. The options it reads are `accountKey`, `accountJwk`, `alg`, `transport`, `tls`, `timeout`, `maxResponseBytes`, `maxRedirects`, `maxNonceRetries`, `maxPolls`, `maxTotalWait`, `sleep`, and `clock`; each method the client returns validates its own per-call options separately.
15
+
16
+ ### Security
17
+
18
+ - An unrecognized option is a fail-closed error rather than a silent default. The prior behavior meant a security-relevant option -- a shorter redirect budget, a specific trust purpose -- that was misspelled took no effect and raised no error, so a caller could believe a stricter setting was in force when the default was.
19
+
7
20
  ## v0.5.26 — 2026-08-22
8
21
 
9
22
  Revoking a certificate and asking a certification authority what it offers now go through the same verified CMP transaction as enrollment.
package/lib/acme.js CHANGED
@@ -1947,8 +1947,17 @@ function _parseLinkAlternates(headers, base) {
1947
1947
  * var acct = await acme.newAccount({ termsOfServiceAgreed: true });
1948
1948
  * var ord = await acme.newOrder({ identifiers: [{ type: "dns", value: "example.org" }] });
1949
1949
  */
1950
+ // The options pki.acme.client reads at construction. A near-miss spelling (a plural, a sibling verb's
1951
+ // word, a dropped letter) must be refused with a message naming it, not read as undefined and silently
1952
+ // defaulted -- a mistyped `maxRedirects` or `transport` would otherwise change the client's behavior with
1953
+ // no error. The per-request options each returned method takes are checked in those methods, not here.
1954
+ var _CLIENT_OPTS = {
1955
+ accountKey: 1, accountJwk: 1, alg: 1, transport: 1, tls: 1, timeout: 1, maxResponseBytes: 1,
1956
+ maxRedirects: 1, maxNonceRetries: 1, maxPolls: 1, maxTotalWait: 1, sleep: 1, clock: 1,
1957
+ };
1950
1958
  function client(directoryUrl, opts) {
1951
- opts = opts || {};
1959
+ opts = guard.identifier.optionsObject(opts, E, "acme/bad-input", "pki.acme.client options");
1960
+ guard.identifier.assertKnownKeys(opts, _CLIENT_OPTS, E, "acme/bad-input", "unknown pki.acme.client option ");
1952
1961
  if (!opts.accountKey) throw E("acme/bad-input", "client requires opts.accountKey (the account private key)");
1953
1962
  if (!_isObject(opts.accountJwk)) throw E("acme/bad-input", "client requires opts.accountJwk (the account public JWK)");
1954
1963
  if (!_isString(opts.alg)) throw E("acme/bad-input", "client requires opts.alg (the account-key JWS alg)");
package/lib/trust.js CHANGED
@@ -629,6 +629,9 @@ function _csvDate(cell, label) {
629
629
  if (!m) throw E("trust/bad-csv", label + " must be a Y-M-D date, got " + JSON.stringify(s));
630
630
  var pad = function (x) { return x.length === 1 ? "0" + x : x; };
631
631
  var payload = Buffer.from(m[1] + pad(m[2]) + pad(m[3]) + "235959Z", "latin1");
632
+ // _strictTime tags every rejection (a rolled-over month/day among them) with the code passed here,
633
+ // so the re-throw carries it unchanged; the wrap normalizes any other failure to the same typed code
634
+ // so a bad row is always trust/bad-csv, never an untyped exception escaping parseCcadbCsv.
632
635
  try { return _strictTime(payload, "trust/bad-csv", label); }
633
636
  catch (e) {
634
637
  if (e && e.code === "trust/bad-csv") throw e;
@@ -774,11 +777,16 @@ function parseCcadbCsv(text) {
774
777
  * await pki.path.validate([pki.schema.x509.parse(der)],
775
778
  * { time: new Date("2026-06-01T00:00:00Z"), trustAnchor: anchor, checkPurpose: "serverAuth" });
776
779
  */
780
+ // `purpose` is the only option, and it gates the authorization itself, so a near-miss spelling must not
781
+ // pass silently: a caller who wrote the plural `purposes` (or carried a sibling's word) would otherwise get
782
+ // the anchor with NO purpose restriction rather than an error naming the option they meant.
783
+ var _ANCHOR_OPTS = { purpose: 1 };
777
784
  function anchor(entry, opts) {
778
785
  if (!entry || typeof entry !== "object") {
779
786
  throw E("trust/bad-input", "anchor expects a trust-store entry ({ name, publicKey, algorithm, ... })");
780
787
  }
781
- opts = opts || {};
788
+ opts = guard.identifier.optionsObject(opts, E, "trust/bad-input", "pki.trust.anchor options");
789
+ guard.identifier.assertKnownKeys(opts, _ANCHOR_OPTS, E, "trust/bad-input", "unknown pki.trust.anchor option ");
782
790
  // Where this entry came from a store, everything the anchor asserts is read from the record the
783
791
  // store minted, not from the entry -- the entry is a plain object the caller holds and can write
784
792
  // to. `purposes` is the authorization itself, so an entry whose serverAuth bit was flipped after
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/pki",
3
- "version": "0.5.26",
3
+ "version": "0.5.27",
4
4
  "description": "Pure-JavaScript PKI toolkit that owns its stack — X.509, ASN.1/DER, CMS, PQC-first.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "blamejs contributors",
package/sbom.cdx.json CHANGED
@@ -2,10 +2,10 @@
2
2
  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
3
3
  "bomFormat": "CycloneDX",
4
4
  "specVersion": "1.5",
5
- "serialNumber": "urn:uuid:af65ad7a-ef35-4bc4-8aef-24a43cb8ece0",
5
+ "serialNumber": "urn:uuid:3e85b1a0-56f6-459d-a525-da732c14e1d6",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-08-23T00:05:35.940Z",
8
+ "timestamp": "2026-08-23T02:01:07.534Z",
9
9
  "lifecycles": [
10
10
  {
11
11
  "phase": "build"
@@ -19,14 +19,14 @@
19
19
  }
20
20
  ],
21
21
  "component": {
22
- "bom-ref": "@blamejs/pki@0.5.26",
22
+ "bom-ref": "@blamejs/pki@0.5.27",
23
23
  "type": "application",
24
24
  "name": "pki",
25
- "version": "0.5.26",
25
+ "version": "0.5.27",
26
26
  "scope": "required",
27
27
  "author": "blamejs contributors",
28
28
  "description": "Pure-JavaScript PKI toolkit that owns its stack — X.509, ASN.1/DER, CMS, PQC-first.",
29
- "purl": "pkg:npm/%40blamejs/pki@0.5.26",
29
+ "purl": "pkg:npm/%40blamejs/pki@0.5.27",
30
30
  "properties": [],
31
31
  "externalReferences": [
32
32
  {
@@ -54,7 +54,7 @@
54
54
  "components": [],
55
55
  "dependencies": [
56
56
  {
57
- "ref": "@blamejs/pki@0.5.26",
57
+ "ref": "@blamejs/pki@0.5.27",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]