@blamejs/pki 0.5.9 → 0.5.11
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 +80 -19
- package/README.md +1 -1
- package/lib/acme.js +5 -5
- package/lib/asn1-der.js +1 -1
- package/lib/attrcert-sign.js +1 -1
- package/lib/cbor-det.js +4 -4
- package/lib/cmc-build.js +5 -5
- package/lib/cmc-verify.js +14 -11
- package/lib/cms-decrypt.js +2 -2
- package/lib/cms-sign.js +3 -5
- package/lib/cms-verify.js +9 -6
- package/lib/constants.js +1 -1
- package/lib/crl-sign.js +1 -1
- package/lib/crmf-sign.js +1 -1
- package/lib/ct.js +8 -5
- package/lib/est.js +20 -14
- package/lib/guard-all.js +12 -12
- package/lib/guard-bytes.js +568 -82
- package/lib/guard-compress.js +2 -2
- package/lib/guard-der.js +1 -1
- package/lib/guard-identifier.js +694 -6
- package/lib/guard-limits.js +2 -2
- package/lib/guard-parsed.js +10 -6
- package/lib/guard-range.js +1 -1
- package/lib/guard-secret.js +1 -1
- package/lib/guard-text.js +1 -1
- package/lib/guard-time.js +65 -4
- package/lib/hpke.js +1 -1
- package/lib/http-digest.js +1 -1
- package/lib/inspect.js +8 -3
- package/lib/jose.js +1 -1
- package/lib/key.js +48 -6
- package/lib/lint.js +15 -8
- package/lib/ocsp-verify.js +10 -4
- package/lib/ocsp.js +35 -6
- package/lib/oid.js +1 -1
- package/lib/path-validate.js +99 -22
- package/lib/schema-c509.js +5 -5
- package/lib/schema-cmp.js +1 -1
- package/lib/schema-crl.js +1 -1
- package/lib/schema-engine.js +2 -2
- package/lib/schema-pkix.js +1 -1
- package/lib/sigstore.js +6 -2
- package/lib/smime.js +1 -1
- package/lib/trust.js +2 -2
- package/lib/tsp-sign.js +2 -2
- package/lib/validator-attcert.js +3 -3
- package/lib/validator-cose.js +3 -3
- package/lib/webauthn-mds.js +17 -17
- package/lib/webauthn.js +12 -12
- package/lib/webcrypto.js +16 -7
- package/lib/x509-sign.js +1 -1
- package/package.json +4 -2
- package/sbom.cdx.json +6 -6
package/lib/webauthn.js
CHANGED
|
@@ -474,8 +474,8 @@ var ATT_STMT_MAJOR = { compound: 4 };
|
|
|
474
474
|
var _AAGUID_SIGNED_BY_FMT = Object.assign(Object.create(null), { "fido-u2f": false });
|
|
475
475
|
function _aaguidIsSigned(fmt) { return _AAGUID_SIGNED_BY_FMT[fmt] !== false; }
|
|
476
476
|
|
|
477
|
-
// The options pki.webauthn.verify
|
|
478
|
-
// resolve to an inherited Object member and read as
|
|
477
|
+
// The options pki.webauthn.verify recognizes. Null-prototype, so a caller-supplied key cannot
|
|
478
|
+
// resolve to an inherited Object member and read as recognized.
|
|
479
479
|
var _VERIFY_OPTS = Object.assign(Object.create(null), {
|
|
480
480
|
time: 1, metadata: 1, tpmPolicy: 1, safetyNetRoots: 1, verifySafetyNetJws: 1, requireCtsProfileMatch: 1,
|
|
481
481
|
expectedRpId: 1, requireUserPresence: 1, requireUserVerification: 1, allowedAlgorithms: 1,
|
|
@@ -511,7 +511,7 @@ var _FORMAT_SCOPED_BOOLEAN_OPTS = ["verifySafetyNetJws", "requireCtsProfileMatch
|
|
|
511
511
|
// so a caller that recycles the array or overwrites a certificate's bytes in between
|
|
512
512
|
// would have the attestation anchored against the replacement roots while the verdict
|
|
513
513
|
// still reports `anchoredTo: "rootCertificates"` (CWE-367 reaching a wrong trust
|
|
514
|
-
// decision). Same
|
|
514
|
+
// decision). Same defense, and the same reason, as the assertion input's snapshot.
|
|
515
515
|
// Shape faults are NOT raised here: the array is validated where it is consumed, so
|
|
516
516
|
// supplying a malformed pin alongside a metadata catalogue that answers keeps failing
|
|
517
517
|
// exactly where it did before.
|
|
@@ -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
|
|
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); });
|
|
@@ -645,7 +645,7 @@ function _applyCallerRoots(res, supplied, vopts, onlyPaths) {
|
|
|
645
645
|
var at = vopts.time !== undefined ? vopts.time : new Date();
|
|
646
646
|
// EVERY path, not merely one: a compound's elements are independent claims, and
|
|
647
647
|
// accepting the whole because one element anchored would let an unanchored element
|
|
648
|
-
// ride along on its
|
|
648
|
+
// ride along on its neighbor's trust.
|
|
649
649
|
return paths.reduce(function (p, info) {
|
|
650
650
|
return p.then(function () {
|
|
651
651
|
var pathAt = vopts.time !== undefined ? vopts.time : (info.at || at);
|
|
@@ -1114,7 +1114,7 @@ var VERIFIERS = {
|
|
|
1114
1114
|
});
|
|
1115
1115
|
});
|
|
1116
1116
|
}, Promise.resolve()).then(function () {
|
|
1117
|
-
// sec. 8.9 lists the supported attestation type as "Any" and
|
|
1117
|
+
// sec. 8.9 lists the supported attestation type as "Any" and authorizes returning
|
|
1118
1118
|
// "implementation-specific values representing any combination of outputs". A distinct type
|
|
1119
1119
|
// rather than a merge: collapsing to the strongest element would let a wrapper upgrade a
|
|
1120
1120
|
// caller's attestationType check, and collapsing to the weakest would spuriously fail one.
|
|
@@ -1388,7 +1388,7 @@ function verify(attestationObject, clientDataHash, opts) {
|
|
|
1388
1388
|
// Every option here either GATES the verdict or supplies the trust material a gate needs, so a
|
|
1389
1389
|
// misspelled key is not a harmless no-op: `metdata` leaves the metadata gate switched off and the
|
|
1390
1390
|
// call returns a pass the caller believes was checked against the catalogue. Reject an
|
|
1391
|
-
//
|
|
1391
|
+
// unrecognized key at the boundary, and validate the one shared option every arm reads, so a bad
|
|
1392
1392
|
// instant is a config fault here rather than a trust failure reported from deep inside a chain.
|
|
1393
1393
|
try {
|
|
1394
1394
|
if (!_isPlainObject(opts)) throw _err("webauthn/bad-input", "opts must be an object");
|
|
@@ -1406,7 +1406,7 @@ function verify(attestationObject, clientDataHash, opts) {
|
|
|
1406
1406
|
// The boolean switches are typed HERE rather than in the arm that reads them. Validated only
|
|
1407
1407
|
// inside the android-safetynet arm, `requireCtsProfileMatch: "true"` reaching any other format
|
|
1408
1408
|
// is never examined at all -- a truthy string that demands nothing, silently accepted. A
|
|
1409
|
-
//
|
|
1409
|
+
// recognized key with an unusable value is the same class of caller mistake as an unrecognized
|
|
1410
1410
|
// key, and belongs at the same boundary.
|
|
1411
1411
|
_FORMAT_SCOPED_BOOLEAN_OPTS.forEach(function (k) {
|
|
1412
1412
|
if (opts[k] !== undefined && typeof opts[k] !== "boolean") throw _err("webauthn/bad-input", "opts." + k + " must be a boolean");
|
|
@@ -1597,7 +1597,7 @@ function verify(attestationObject, clientDataHash, opts) {
|
|
|
1597
1597
|
function _applyMetadata(res, att, opts) {
|
|
1598
1598
|
var md = opts.metadata;
|
|
1599
1599
|
// Provenance, not shape: only a catalogue this toolkit actually verified may decide which roots
|
|
1600
|
-
// an authenticator is allowed to chain to.
|
|
1600
|
+
// an authenticator is allowed to chain to. Recognizing it by its property names would accept a
|
|
1601
1601
|
// hand-built object, or one restored from a cache an attacker can write -- neither of which has
|
|
1602
1602
|
// been through the signature and chain checks that give the catalogue its authority.
|
|
1603
1603
|
if (!mds.isVerifiedResult(md)) {
|
|
@@ -1703,7 +1703,7 @@ function _applyMetadata(res, att, opts) {
|
|
|
1703
1703
|
mds.assertFresh(md, at, "the metadata supplied as opts.metadata");
|
|
1704
1704
|
// EVERY path must pass, not merely one of them: for a compound attestation each element is an
|
|
1705
1705
|
// independent claim, and accepting the whole because one element anchored would let an
|
|
1706
|
-
// unanchored -- or revoked -- element ride along on its
|
|
1706
|
+
// unanchored -- or revoked -- element ride along on its neighbor's trust.
|
|
1707
1707
|
// Govern EVERY path BEFORE any is chain-validated, and let the SEVEREST outcome decide
|
|
1708
1708
|
// rather than the first one reached. A compound's elements are independent claims and
|
|
1709
1709
|
// its element order is NOT signed, so aborting on the first failure lets that order pick
|
|
@@ -1836,7 +1836,7 @@ void constants;
|
|
|
1836
1836
|
* (the default; any disqualifying report ever filed), `"latest-by-date"` (only the
|
|
1837
1837
|
* most recent report counts, so a later remediation clears an earlier revocation),
|
|
1838
1838
|
* or a function receiving the raw report array and returning true to deny.
|
|
1839
|
-
* - `rejectUnknownStatus` -- treat a status this toolkit does not
|
|
1839
|
+
* - `rejectUnknownStatus` -- treat a status this toolkit does not recognize as
|
|
1840
1840
|
* disqualifying. Off by default: the specification requires an unknown status be
|
|
1841
1841
|
* ignored, never failed on.
|
|
1842
1842
|
*
|
|
@@ -2146,7 +2146,7 @@ function parseAuthenticatorData(bytes) {
|
|
|
2146
2146
|
return _parseAuthData(_bytesArg(bytes, "authenticatorData"), _err);
|
|
2147
2147
|
}
|
|
2148
2148
|
|
|
2149
|
-
// The options pki.webauthn.verifyAssertion
|
|
2149
|
+
// The options pki.webauthn.verifyAssertion recognizes, null-prototype for the same
|
|
2150
2150
|
// reason _VERIFY_OPTS is.
|
|
2151
2151
|
var _ASSERT_OPTS = Object.assign(Object.create(null), {
|
|
2152
2152
|
authenticatorData: 1, clientDataHash: 1, clientDataJSON: 1, signature: 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
|
-
|
|
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
|
-
|
|
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
|
|
|
@@ -1344,7 +1353,7 @@ function exportAnyKey(key, E, code) {
|
|
|
1344
1353
|
// A separately-installed copy of this engine is the same code under a different class identity, so
|
|
1345
1354
|
// its keys fail the `instanceof` above while carrying the very handle this engine reads -- and no
|
|
1346
1355
|
// WebCrypto implementation but that copy would accept them. Read the handle directly. The
|
|
1347
|
-
// extractable check above stays AHEAD of this: the handle can always be read, so
|
|
1356
|
+
// extractable check above stays AHEAD of this: the handle can always be read, so honoring the
|
|
1348
1357
|
// key's own extractable promise is this branch's responsibility, not the crypto library's.
|
|
1349
1358
|
var handle = key._handle;
|
|
1350
1359
|
if (handle instanceof nodeCrypto.KeyObject && handle.type === key.type) {
|
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
|
|
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.
|
|
3
|
+
"version": "0.5.11",
|
|
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",
|
|
@@ -68,9 +68,11 @@
|
|
|
68
68
|
"test": "node test/smoke.js",
|
|
69
69
|
"lint": "eslint --max-warnings 0 .",
|
|
70
70
|
"fuzz": "npm ci --prefix fuzz && npx --prefix fuzz jazzer fuzz/asn1-der.fuzz.js -- -max_total_time=60",
|
|
71
|
-
"gates": "node test/layer-0-primitives/codebase-patterns.test.js && node scripts/validate-source-comment-blocks.js && node scripts/check-api-snapshot.js",
|
|
71
|
+
"gates": "node test/layer-0-primitives/codebase-patterns.test.js && node scripts/validate-source-comment-blocks.js && node scripts/check-api-snapshot.js && node scripts/check-spelling-consistency.js",
|
|
72
|
+
"check:spelling": "node scripts/check-spelling-consistency.js",
|
|
72
73
|
"coverage": "c8 --include=lib/** --include=index.js --reporter=text-summary --reporter=lcov node test/smoke.js",
|
|
73
74
|
"check:prose": "node scripts/check-operator-prose.js",
|
|
75
|
+
"check:prose:all": "node -e \"process.env.PKI_PROSE_CHECKS='all';var r=require('child_process').spawnSync(process.execPath,['scripts/check-operator-prose.js'],{stdio:'inherit'});if(r.error)throw r.error;process.exit(r.signal?1:r.status)\"",
|
|
74
76
|
"check:swallows": "node scripts/check-swallow-coverage.js",
|
|
75
77
|
"coverage:gated": "npm run coverage && npm run check:swallows",
|
|
76
78
|
"coverage:unified": "node scripts/coverage-unified.js",
|
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:
|
|
5
|
+
"serialNumber": "urn:uuid:70c8692d-688f-45e6-a4af-49916d0b01c7",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-08-
|
|
8
|
+
"timestamp": "2026-08-19T06:52:36.445Z",
|
|
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.
|
|
22
|
+
"bom-ref": "@blamejs/pki@0.5.11",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "pki",
|
|
25
|
-
"version": "0.5.
|
|
25
|
+
"version": "0.5.11",
|
|
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.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/pki@0.5.11",
|
|
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.
|
|
57
|
+
"ref": "@blamejs/pki@0.5.11",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|