@blamejs/pki 0.5.27 → 0.5.28

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,7 +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
7
+ ## v0.5.28 — 2026-08-23
8
+
9
+ Importing the toolkit is now silent, and a key's WebCrypto algorithm can no longer change under a signature once the key has been created.
10
+
11
+ ### Changed
12
+
13
+ - `require("@blamejs/pki")` no longer prints Node experimental-feature warnings on load. The engine's typed-array scan reads each global's property descriptor and uses only a data value, so it never touches a host's lazy accessor (Node's `localStorage` and `WASI` emit an `ExperimentalWarning` the moment they are read). Recognition of the concrete typed-array kinds -- the reason for the scan -- is unchanged, since those are ordinary data properties.
14
+
15
+ ### Security
16
+
17
+ - A `CryptoKey`'s `algorithm` is immutable once the key is created: the property is non-writable so it cannot be replaced, and its value is frozen so its fields cannot be changed. This engine reads `key.algorithm.hash` at sign time, and a mutable algorithm let the hash checked against a JWS `alg` (an `RS256` header signs under SHA-256) be rewritten between that check and the signature -- by swapping the whole object or a field of it, including from a microtask during the signing await -- producing a JWS whose signature does not match the algorithm its header advertises. The frozen value is a copy, so a caller's own `importKey` parameters object is left untouched. A key adopted from another WebCrypto implementation is re-imported from its own algorithm; the keys this engine mints, which is what the enrollment builders sign with, carry the immutable one.
18
+
19
+ ## v0.5.27 — 2026-08-22
8
20
 
9
21
  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
22
 
@@ -433,13 +433,17 @@ var _INTRINSIC_HOLDERS = (function () {
433
433
  // built over `%TypedArray%.prototype`, and a bag inheriting `BYTES_PER_ELEMENT` from such an
434
434
  // object then read as an intrinsic member rather than as the unknown option it was.
435
435
  //
436
- // Reading a global can run a getter, and a deprecated one can throw; a fault here would break
437
- // this module's load over a name it does not need.
436
+ // Read the DESCRIPTOR, never the value through the runtime. `globalThis[n]` invokes a getter, and a
437
+ // host may define one that warns on read -- Node exposes `localStorage` and `WASI` as lazy accessors
438
+ // that emit an ExperimentalWarning the moment they are touched, so a plain read here printed that
439
+ // warning on every import -- or one that throws. A typed-array constructor is a plain data property, so
440
+ // taking `d.value` finds every concrete kind without ever invoking an accessor, which also means such
441
+ // an accessor can neither warn nor fault this load over a name it does not need.
438
442
  _forEach(_getOwnPropertyNames(globalThis), function (n) {
439
- var C;
440
- try { C = globalThis[n]; }
441
- catch (_e) { /* allow:swallow-unverified this runs once at load over whatever globals the host defines, and no global in a supported runtime throws on read, so no test drives it; it is here so an embedder's throwing accessor cannot stop this module loading over a name it does not need */ return; }
442
- if (typeof C !== "function" || typeof C.BYTES_PER_ELEMENT !== "number") return;
443
+ var d = _getOwnPropertyDescriptor(globalThis, n);
444
+ if (!d || typeof d.value !== "function") return;
445
+ var C = d.value;
446
+ if (typeof C.BYTES_PER_ELEMENT !== "number") return;
443
447
  if (!C.prototype || _getPrototypeOf(C.prototype) !== _TYPED_ARRAY_PROTO) return;
444
448
  _mapSet(m, C.prototype, _CONCRETE_TYPED_MEMBERS);
445
449
  });
package/lib/webcrypto.js CHANGED
@@ -254,7 +254,20 @@ var SECRET_KEY_NAMES = { "AES-GCM": true, "AES-CBC": true, "AES-CTR": true, "AES
254
254
  function CryptoKey(type, extractable, algorithm, usages, handle) {
255
255
  this.type = type;
256
256
  this.extractable = !!extractable;
257
- this.algorithm = algorithm;
257
+ // The algorithm is immutable both ways. The PROPERTY is defined non-writable and non-configurable so
258
+ // it cannot be REPLACED wholesale (`key.algorithm = { hash: "SHA-512" }`), and its value is a frozen
259
+ // COPY -- a caller's importKey params object is left untouched -- so its fields, the nested `hash` an
260
+ // RSA/HMAC signature reads among them, cannot be MUTATED. This engine reads key.algorithm.hash live
261
+ // when it signs, and a W3C CryptoKey's [[algorithm]] is immutable for exactly this reason: neither
262
+ // swapping the object nor a field of it (e.g. from a microtask during a signing await) can make the
263
+ // hash the signature is computed under differ from the one checked against a header algorithm.
264
+ var frozenAlg = algorithm;
265
+ if (frozenAlg && typeof frozenAlg === "object") {
266
+ frozenAlg = _assign({}, algorithm);
267
+ if (frozenAlg.hash && typeof frozenAlg.hash === "object") frozenAlg.hash = intrinsic.freeze(_assign({}, frozenAlg.hash));
268
+ frozenAlg = intrinsic.freeze(frozenAlg);
269
+ }
270
+ _defineProperty(this, "algorithm", { value: frozenAlg, enumerable: true });
258
271
  // The copy is what the key will be asked about for the rest of its life, so the method that makes
259
272
  // it is the captured one: a replaced `slice` hands back a list the caller still controls. The
260
273
  // list-ness is checked rather than left to the copy to discover -- `Array.prototype.slice` on a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/pki",
3
- "version": "0.5.27",
3
+ "version": "0.5.28",
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:3e85b1a0-56f6-459d-a525-da732c14e1d6",
5
+ "serialNumber": "urn:uuid:c0564356-6da6-47da-a75d-a05ee2125d32",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-08-23T02:01:07.534Z",
8
+ "timestamp": "2026-08-23T03:34:40.100Z",
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.27",
22
+ "bom-ref": "@blamejs/pki@0.5.28",
23
23
  "type": "application",
24
24
  "name": "pki",
25
- "version": "0.5.27",
25
+ "version": "0.5.28",
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.27",
29
+ "purl": "pkg:npm/%40blamejs/pki@0.5.28",
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.27",
57
+ "ref": "@blamejs/pki@0.5.28",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]