@blamejs/pki 0.5.10 → 0.5.12

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.
@@ -2205,14 +2205,14 @@ function _requireResultShape(r) {
2205
2205
  if (r.serialNumber == null && r.serialNumberHex == null) throw _err("c509/bad-input", "a C509 result must carry serialNumber or serialNumberHex");
2206
2206
  if (!r.signatureAlgorithm || typeof r.signatureAlgorithm.name !== "string") throw _err("c509/bad-input", "a C509 result must carry signatureAlgorithm.name");
2207
2207
  if (!r.subjectPublicKeyAlgorithm || typeof r.subjectPublicKeyAlgorithm.name !== "string") throw _err("c509/bad-input", "a C509 result must carry subjectPublicKeyAlgorithm.name");
2208
- if (!r.validity || !(r.validity.notBefore instanceof Date) || (r.validity.notAfter !== null && !(r.validity.notAfter instanceof Date))) throw _err("c509/bad-input", "a C509 result must carry validity.notBefore (Date) and notAfter (Date or null)");
2208
+ if (!r.validity || !guard.time.isDate(r.validity.notBefore) || (r.validity.notAfter !== null && !guard.time.isDate(r.validity.notAfter))) throw _err("c509/bad-input", "a C509 result must carry validity.notBefore (Date) and notAfter (Date or null)");
2209
2209
  if (!Array.isArray(r.extensions)) throw _err("c509/bad-input", "a C509 result must carry an extensions array");
2210
2210
  if (!Buffer.isBuffer(r.signatureValue)) throw _err("c509/bad-input", "a C509 result must carry a Buffer signatureValue");
2211
2211
  }
2212
2212
  // A validity Date -> its C509 ~time (a non-negative CBOR epoch uint). A pre-epoch date cannot be
2213
2213
  // represented (the parser accepts only an unwrapped major-type-0 integer) and fails closed here.
2214
2214
  function _validityUint(date, label) {
2215
- var secs = Math.floor(date.getTime() / 1000);
2215
+ var secs = Math.floor(guard.time.instantOf(date) / 1000);
2216
2216
  if (!isFinite(secs) || secs < 0) throw _err("c509/bad-validity", label + " is before the Unix epoch or not a valid date; C509 ~time is a non-negative CBOR epoch");
2217
2217
  return cbor.build.uint(BigInt(secs));
2218
2218
  }
@@ -2433,7 +2433,7 @@ _derToType3 = function (input, opts) {
2433
2433
  // against a UTF8String of the same characters) would rebuild different bytes and break the
2434
2434
  // signature that covers them. Byte-identical is exactly the condition under which that is safe.
2435
2435
  issuer: c.issuer.bytes.equals(c.subject.bytes) ? null : _c509NameFromDer(c.issuer.bytes),
2436
- validity: { notBefore: c.validity.notBefore, notAfter: c.validity.notAfter.getTime() === _NO_EXPIRY ? null : c.validity.notAfter },
2436
+ validity: { notBefore: c.validity.notBefore, notAfter: guard.time.instantOf(c.validity.notAfter) === _NO_EXPIRY ? null : c.validity.notAfter },
2437
2437
  subject: _c509NameFromDer(c.subject.bytes),
2438
2438
  subjectPublicKeyAlgorithm: { name: "ecPublicKey", oid: c.subjectPublicKeyInfo.algorithm.oid, curve: curve },
2439
2439
  subjectPublicKey: _compressEcPoint(asn1.read.bitString(spkiNode.children[1]).bytes, coordLen), // 0x04||X||Y -> C509 compressed marker
package/lib/sigstore.js CHANGED
@@ -228,7 +228,7 @@ function _toMs(x) {
228
228
  // Coverage residual -- _inWindow gates every _toMs call behind a != null check; the null guard is dead defensive code.
229
229
  if (x == null) return null;
230
230
  if (typeof x === "number") return Number.isFinite(x) ? x : null;
231
- if (x instanceof Date) { var d = x.getTime(); return isNaN(d) ? null : d; }
231
+ if (guard.time.isDate(x)) { var d = guard.time.instantOf(x); return isNaN(d) ? null : d; }
232
232
  if (typeof x === "string") { var t = Date.parse(x); return isNaN(t) ? null : t; }
233
233
  return null;
234
234
  }
@@ -671,7 +671,11 @@ async function verifyBundle(bundle, opts) {
671
671
  if (integratedTime === null) throw lastErr;
672
672
 
673
673
  // Leg 3 -- Fulcio chain, validated as of the (trusted) log time; then identity.
674
- var checkTime = (opts.time instanceof Date) ? opts.time.getTime() : C.TIME.seconds(integratedTime);
674
+ // The instant comes through the time guard's intrinsic read. `getTime` is an ordinary method a
675
+ // subclass answers, and the slot predicate above accepts a subclass from any realm, so reading
676
+ // the method off the value let a caller name the moment the Fulcio chain is validated at --
677
+ // epoch zero, say, where every certificate in it is still unissued.
678
+ var checkTime = guard.time.isDate(opts.time) ? guard.time.instantOf(opts.time) : C.TIME.seconds(integratedTime);
675
679
  await _verifyChain(leaf, _chainDers(vm), fulcioRoots, checkTime);
676
680
  var identity = _identity(leaf);
677
681
  var identityChecked = _checkIdentity(identity, opts.identity);
package/lib/trust.js CHANGED
@@ -347,7 +347,7 @@ function _copyDistrustAfter(src) {
347
347
  var out = {};
348
348
  if (!src || typeof src !== "object") return out;
349
349
  Object.keys(src).forEach(function (k) {
350
- out[k] = src[k] instanceof Date ? new Date(src[k].getTime()) : src[k];
350
+ out[k] = guard.time.isDate(src[k]) ? new Date(guard.time.instantOf(src[k])) : src[k];
351
351
  });
352
352
  return out;
353
353
  }
@@ -375,7 +375,7 @@ function _copyName(name) {
375
375
  function _datesEqual(x, y) {
376
376
  var kx = Object.keys(x).sort(), ky = Object.keys(y).sort();
377
377
  if (kx.join(",") !== ky.join(",")) return false;
378
- return kx.every(function (k) { return x[k].getTime() === y[k].getTime(); });
378
+ return kx.every(function (k) { return guard.time.instantOf(x[k]) === guard.time.instantOf(y[k]); });
379
379
  }
380
380
 
381
381
  function _purposesEqual(x, y) {
package/lib/tsp-sign.js CHANGED
@@ -161,7 +161,7 @@ function _sign(messageImprint, tsa, opts) {
161
161
  // genTime defaults to now; a supplied value MUST be a valid Date (never a silently-ignored
162
162
  // non-Date or an Invalid Date that would encode a garbage GeneralizedTime).
163
163
  if (opts.genTime != null) guard.time.assertValid(opts.genTime, _err, "tsp/bad-input", "genTime");
164
- var genTime = opts.genTime instanceof Date ? opts.genTime : new Date();
164
+ var genTime = guard.time.isDate(opts.genTime) ? opts.genTime : new Date();
165
165
  // A caller-authored INTEGER is coerced through the shared guard, so a value that is not one is a
166
166
  // typed tsp/bad-input rather than a raw SyntaxError or RangeError out of BigInt() -- an untyped
167
167
  // fault escaping a public verb, which a caller cannot catch by code.
@@ -761,7 +761,7 @@ async function verify(token, data, opts) {
761
761
  // notBefore is rejected at the floor (ceil >= notBefore but floor < notBefore). Certificate
762
762
  // validity is seconds-precise (RFC 5280 sec. 4.1.2.5), so this never over-rejects a valid token.
763
763
  var floorT = tst.genTime;
764
- var ceilT = (tst.genTimeFraction != null && /[1-9]/.test(tst.genTimeFraction.slice(3))) ? new Date(floorT.getTime() + 1) : floorT;
764
+ var ceilT = (tst.genTimeFraction != null && /[1-9]/.test(tst.genTimeFraction.slice(3))) ? new Date(guard.time.instantOf(floorT) + 1) : floorT;
765
765
  try {
766
766
  // parseToken surfaces each embedded cert as { bytes, tagClass, ... }; take the X.509 certs
767
767
  // (universal SEQUENCE), skipping any attribute-certificate choices, and parse their raw bytes.
@@ -7,9 +7,9 @@
7
7
  //
8
8
  // validator-attcert -- the SINGLE home for "does this X.509 leaf meet the WebAuthn
9
9
  // attestation-certificate profile" (WebAuthn sec. 8.2.1 packed, sec. 8.3.1 TPM AIK).
10
- // Sibling to the guard family: a validator owns a decoded TYPE's COMPLETE conformance rule
11
- // set once, so the packed and AIK profiles cannot drift apart or lose a gate (e.g. the v3
12
- // check that previously lived split out in the tpm verifier, away from the profile).
10
+ // Sibling to the guard family: a validator owns a decoded type's complete conformance rule
11
+ // set once, so the packed and AIK profiles cannot drift apart or lose a gate. The version
12
+ // check belongs to the profile, not to whichever verifier reaches it first.
13
13
  //
14
14
  // The caller supplies its parsed certificate + an extension-accessor object `exts`
15
15
  // { find(cert, oidName) -> rawExt|null, decode(cert, oidName) -> {critical, value}|null }
@@ -502,7 +502,7 @@ function _chainToAnchor(chain, anchors, at, what, code) {
502
502
  function _staleAfter(nextUpdate) {
503
503
  var d = rfc3339.parseDate(nextUpdate, function (c, m) { return _err("webauthn/bad-metadata-blob", m); },
504
504
  "webauthn/bad-metadata-blob", "the metadata BLOB nextUpdate");
505
- return d.getTime() + constants.TIME.days(1);
505
+ return guard.time.instantOf(d) + constants.TIME.days(1);
506
506
  }
507
507
 
508
508
  // A verified result is a plain object the caller may hold for as long as it likes, so its freshness
@@ -513,7 +513,7 @@ function _staleAfter(nextUpdate) {
513
513
  // here, so opting out stays opted out and never silently reappears at the point of use.
514
514
  function assertFresh(metadata, at, label) {
515
515
  if (!metadata || metadata.allowStale === true || typeof metadata.nextUpdate !== "string") return;
516
- var atMs = at instanceof Date ? at.getTime() : NaN;
516
+ var atMs = guard.time.isDate(at) ? guard.time.instantOf(at) : NaN;
517
517
  var limit = _staleAfter(metadata.nextUpdate);
518
518
  if (!isFinite(atMs) || !isFinite(limit)) return;
519
519
  if (atMs >= limit) {
@@ -547,7 +547,7 @@ function _parsePayload(seg, at, opts) {
547
547
  throw _err("webauthn/metadata-rollback", "the metadata BLOB no " + payload.no + " does not exceed the previously held " + opts.previousNo);
548
548
  }
549
549
  var staleAfter = _staleAfter(payload.nextUpdate);
550
- var atMs = at.getTime();
550
+ var atMs = guard.time.instantOf(at);
551
551
  // An unusable comparison instant must not read as "fresh": without this, a NaN date makes every
552
552
  // comparison false and the staleness check silently passes.
553
553
  //
@@ -791,7 +791,7 @@ function _reportInForceAt(report, atMs) {
791
791
  // parseDate throws and never returns an Invalid Date, so d is finite; atMs was isFinite-
792
792
  // checked by the caller before this runs.
793
793
  // allow:nan-date-comparison-unguarded -- both operands are source-validated, as described above.
794
- return d.getTime() <= atMs;
794
+ return guard.time.instantOf(d) <= atMs;
795
795
  }
796
796
 
797
797
  function statusDenied(entry, metadata, leaf, at) {
@@ -817,7 +817,7 @@ function statusDenied(entry, metadata, leaf, at) {
817
817
  // after the time it asks about. When every dated report is still in the future, the answer is
818
818
  // that none of them is in force, not that all of them are.
819
819
  var isDated = function (r) { return r && typeof r.effectiveDate === "string" && rfc3339.isValidDate(r.effectiveDate); };
820
- var atMs = (at instanceof Date && isFinite(at.getTime())) ? at.getTime() : null;
820
+ var atMs = (guard.time.isDate(at) && isFinite(guard.time.instantOf(at))) ? guard.time.instantOf(at) : null;
821
821
  if (atMs !== null) {
822
822
  reports = reports.filter(function (r) { return !isDated(r) || _reportInForceAt(r, atMs); });
823
823
  }
package/lib/webauthn.js CHANGED
@@ -533,7 +533,7 @@ function _cloneParsed(v, depth) {
533
533
  if (depth > 64) throw _err("webauthn/bad-input", "opts.rootCertificates[] is nested too deeply to be a parsed certificate");
534
534
  if (Buffer.isBuffer(v) || v instanceof Uint8Array) return guard.bytes.snapshot(v, _err, "webauthn/bad-input", "a byte field of opts.rootCertificates[]");
535
535
  if (Array.isArray(v)) return v.map(function (x) { return _cloneParsed(x, depth + 1); });
536
- if (v instanceof Date) return new Date(v.getTime());
536
+ if (guard.time.isDate(v)) return new Date(guard.time.instantOf(v));
537
537
  if (v && typeof v === "object") {
538
538
  var out = {};
539
539
  Object.keys(v).forEach(function (k) { out[k] = _cloneParsed(v[k], depth + 1); });
package/lib/webcrypto.js CHANGED
@@ -1275,14 +1275,23 @@ Crypto.prototype.getRandomValues = function getRandomValues(typedArray) {
1275
1275
  if (!ArrayBuffer.isView(typedArray) || typedArray instanceof Float32Array || typedArray instanceof Float64Array || typedArray instanceof DataView) {
1276
1276
  throw new WebCryptoError("webcrypto/data", "getRandomValues: expected an integer TypedArray");
1277
1277
  }
1278
- if (typedArray.byteLength > MAX_RANDOM_BYTES) {
1278
+ // Re-view the (already integer-TypedArray-validated) output buffer through the OUTPUT door --
1279
+ // any TypedArray, not just Uint8Array -- so a detached backing store fails closed here; the
1280
+ // returned Buffer aliases typedArray, so randomFillSync writes through to the caller's array.
1281
+ //
1282
+ // The output door, because the input one refuses shared memory: bytes another thread can rewrite
1283
+ // after they have been checked cannot be checked. That answers a question about input. Here the
1284
+ // caller is asking for random bytes in memory they chose, and a `SharedArrayBuffer`-backed view
1285
+ // is a supported W3C argument that the platform fills; refusing it made a working call an error.
1286
+ var out = guard.bytes.outputView(typedArray, WebCryptoError, "webcrypto/data", "getRandomValues");
1287
+ // The ceiling is measured on that view, and never on `typedArray.byteLength`. `byteLength` is an
1288
+ // accessor on the shared typed-array prototype, so a caller's subclass answers it: one reporting
1289
+ // 0 passed the ceiling while the fill below wrote the array's real length, which is the bound
1290
+ // being bypassed rather than enforced. The view is built from the internal slot.
1291
+ if (out.length > MAX_RANDOM_BYTES) {
1279
1292
  throw new WebCryptoError("webcrypto/data", "getRandomValues: byteLength exceeds " + MAX_RANDOM_BYTES);
1280
1293
  }
1281
- // Re-view the (already integer-TypedArray-validated) output buffer via
1282
- // guard.bytes.source -- any TypedArray, not just Uint8Array -- so a detached
1283
- // backing store fails closed here; the returned Buffer aliases typedArray, so
1284
- // randomFillSync writes through to the caller's array.
1285
- nodeCrypto.randomFillSync(guard.bytes.source(typedArray, WebCryptoError, "webcrypto/data", "getRandomValues"));
1294
+ nodeCrypto.randomFillSync(out);
1286
1295
  return typedArray;
1287
1296
  };
1288
1297
 
package/lib/x509-sign.js CHANGED
@@ -321,7 +321,7 @@ function _sign(spec, issuer, opts) {
321
321
  guard.time.assertValid(spec.notBefore, _err, "x509/bad-input", "notBefore");
322
322
  guard.time.assertValid(spec.notAfter, _err, "x509/bad-input", "notAfter");
323
323
  // allow:nan-date-comparison-unguarded -- both operands are guard.time.assertValid'd on the two lines above (an Invalid Date throws before this comparison).
324
- if (spec.notBefore.getTime() > spec.notAfter.getTime()) throw _err("x509/bad-input", "notBefore must not be after notAfter (RFC 5280 sec. 4.1.2.5)");
324
+ if (guard.time.instantOf(spec.notBefore) > guard.time.instantOf(spec.notAfter)) throw _err("x509/bad-input", "notBefore must not be after notAfter (RFC 5280 sec. 4.1.2.5)");
325
325
  var validityDer = b.sequence([_timeDer(spec.notBefore, "notBefore"), _timeDer(spec.notAfter, "notAfter")]);
326
326
 
327
327
  var exts = _buildExtensions(spec.extensions, { spki: spki, issuerSpki: issuerSpki, issuerCert: issuerCert, subjectEmpty: subjectEmpty });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/pki",
3
- "version": "0.5.10",
3
+ "version": "0.5.12",
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:b51c65a4-3df8-4dec-af37-301d0b285af6",
5
+ "serialNumber": "urn:uuid:6ebd5615-4e36-40ba-85f5-0b2b1cb013fd",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-08-18T10:39:56.596Z",
8
+ "timestamp": "2026-08-19T07:54:19.360Z",
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.10",
22
+ "bom-ref": "@blamejs/pki@0.5.12",
23
23
  "type": "application",
24
24
  "name": "pki",
25
- "version": "0.5.10",
25
+ "version": "0.5.12",
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.10",
29
+ "purl": "pkg:npm/%40blamejs/pki@0.5.12",
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.10",
57
+ "ref": "@blamejs/pki@0.5.12",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]