@blamejs/pki 0.6.29 → 0.6.31
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 +29 -0
- package/README.md +1 -1
- package/lib/acme.js +8 -7
- package/lib/asn1-der.js +9 -7
- package/lib/attrcert-sign.js +8 -8
- package/lib/byte-reader.js +1 -1
- package/lib/byte-writer.js +1 -1
- package/lib/cmc-verify.js +4 -4
- package/lib/cmp-build.js +3 -3
- package/lib/cmp-session.js +3 -3
- package/lib/cmp-verify.js +2 -1
- package/lib/cms-verify.js +22 -17
- package/lib/composite-kem.js +2 -2
- package/lib/crl-sign.js +5 -5
- package/lib/crmf-sign.js +3 -3
- package/lib/csr-sign.js +2 -2
- package/lib/ct.js +3 -3
- package/lib/est.js +40 -8
- package/lib/framework-error.js +2 -2
- package/lib/hpke.js +2 -2
- package/lib/http-transport.js +61 -14
- package/lib/inspect.js +1 -1
- package/lib/jose.js +1 -1
- package/lib/key.js +7 -7
- package/lib/lint.js +1 -1
- package/lib/merkle.js +2 -6
- package/lib/mime.js +2 -2
- package/lib/ocsp.js +6 -6
- package/lib/oid.js +1 -1
- package/lib/path-validate.js +13 -13
- package/lib/pkcs12-build.js +4 -4
- package/lib/rfc3339.js +2 -2
- package/lib/scep.js +2 -2
- package/lib/schema-all.js +1 -1
- package/lib/schema-attrcert.js +1 -1
- package/lib/schema-cmc.js +2 -2
- package/lib/schema-cmp.js +8 -9
- package/lib/schema-cms.js +3 -3
- package/lib/schema-crmf.js +3 -3
- package/lib/schema-csr.js +1 -1
- package/lib/schema-csrattrs.js +1 -1
- package/lib/schema-engine.js +4 -4
- package/lib/schema-ocsp.js +1 -1
- package/lib/schema-pkcs12.js +2 -2
- package/lib/schema-pkcs8.js +2 -2
- package/lib/schema-smime.js +1 -1
- package/lib/schema-tsp.js +6 -6
- package/lib/schema-x509.js +2 -2
- package/lib/shbs.js +3 -4
- package/lib/sign-scheme.js +1 -1
- package/lib/sigstore.js +2 -2
- package/lib/smime.js +16 -16
- package/lib/tls-cert-compress.js +7 -7
- package/lib/trust.js +5 -5
- package/lib/tsp-sign.js +8 -6
- package/lib/webauthn.js +23 -19
- package/lib/webcrypto.js +3 -3
- package/lib/x509-sign.js +5 -5
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/webauthn.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* `pki.path.validate` is the caller's step: this module verifies the statement, not
|
|
18
18
|
* the certificate chain. A verifier, not a ceremony client: the relying party
|
|
19
19
|
* supplies the clientDataHash + any trust anchors; this module never touches a
|
|
20
|
-
* socket. Fail-closed
|
|
20
|
+
* socket. Fail-closed: every malformed shape or failed check throws a typed
|
|
21
21
|
* `WebauthnError`, never a partial verdict.
|
|
22
22
|
* @spec W3C WebAuthn Level 3 sec. 6.5 / 8, RFC 9052 (COSE)
|
|
23
23
|
* @card Verify a WebAuthn / passkey attestation (packed / tpm / android-key / apple / fido-u2f / none).
|
|
@@ -119,8 +119,8 @@ function _decodeCoseKey(node) {
|
|
|
119
119
|
* @spec RFC 9052, W3C WebAuthn Level 3 sec. 6.5.1
|
|
120
120
|
* @related pki.webauthn.verify, pki.webauthn.verifyAssertion
|
|
121
121
|
*
|
|
122
|
-
* Decode a bare COSE_Key
|
|
123
|
-
* registration
|
|
122
|
+
* Decode a bare COSE_Key, the credential public key a relying party stored at
|
|
123
|
+
* registration, back into the object `verifyAssertion` takes. `pki.webauthn.verify`
|
|
124
124
|
* returns that object, but the durable form is bytes: the object carries `Buffer`
|
|
125
125
|
* values, so a JSON round trip through a datastore yields
|
|
126
126
|
* `{"type":"Buffer","data":[...]}` in place of the object that went in, and existing
|
|
@@ -279,7 +279,7 @@ function _findExt(cert, oidName) {
|
|
|
279
279
|
* authData}`) and its authenticatorData, fail-closed. `authData` carries the decoded
|
|
280
280
|
* rpIdHash / flags / signCount and, when the AT flag is set, the attestedCredentialData
|
|
281
281
|
* (aaguid, credentialId, and the decoded COSE `credentialPublicKey`). `authDataBytes`
|
|
282
|
-
* is the raw authenticatorData
|
|
282
|
+
* is the raw authenticatorData, the exact bytes an attestation signature covers.
|
|
283
283
|
* A malformed object throws `webauthn/bad-attestation-object`.
|
|
284
284
|
*
|
|
285
285
|
* @example
|
|
@@ -820,7 +820,7 @@ function _checkAndroidKeyDescription(cert, clientDataHash) {
|
|
|
820
820
|
* The verdict field is `attestationVerified`, and the name is the point: a sound
|
|
821
821
|
* attestation statement is not the same claim as an acceptable registration. The
|
|
822
822
|
* statement says nothing about which relying party asked for it, or whether a user
|
|
823
|
-
* was present
|
|
823
|
+
* was present, so an attestation naming another origin's RP ID, with user presence
|
|
824
824
|
* clear, is perfectly sound and must not be registered. Supply `expectedRpId`,
|
|
825
825
|
* `requireUserPresence`, `requireUserVerification` and `allowedAlgorithms` and those
|
|
826
826
|
* are checked here; `bindingChecked` reports which ran, so a check that passed can be
|
|
@@ -834,18 +834,18 @@ function _checkAndroidKeyDescription(cert, clientDataHash) {
|
|
|
834
834
|
* The verdict also carries what a relying party must STORE to run a later login:
|
|
835
835
|
* `credentialId`, `credentialPublicKey` and the initial `signCount`. The credential key
|
|
836
836
|
* comes back in both forms: the decoded object, and `credentialPublicKeyBytes`, which is
|
|
837
|
-
* what a credential row should hold
|
|
837
|
+
* what a credential row should hold. The object carries `Buffer` values, so a JSON round
|
|
838
838
|
* trip through a datastore returns `{"type":"Buffer","data":[...]}` in place of the object
|
|
839
839
|
* that went in. `pki.webauthn.parseCoseKey` reads those bytes back, and
|
|
840
840
|
* `verifyAssertion` accepts either form.
|
|
841
841
|
*
|
|
842
|
-
* @intro This verifies the attestation STATEMENT
|
|
842
|
+
* @intro This verifies the attestation STATEMENT: the signature and the format's
|
|
843
843
|
* structural bindings (the x5c leaf key == credential key, the apple nonce, the tpm
|
|
844
844
|
* certInfo Name/extraData, the android KeyDescription, the fido-u2f verificationData).
|
|
845
845
|
* Chaining the returned `trustPath` (the x5c certificates in `pki.path.validate`
|
|
846
|
-
* order
|
|
846
|
+
* order: anchor-adjacent first, leaf last) to a trusted root is a separate step,
|
|
847
847
|
* and there are three ways to take it. Pass `opts.metadata`, a
|
|
848
|
-
* `pki.webauthn.verifyMetadataBlob` result
|
|
848
|
+
* `pki.webauthn.verifyMetadataBlob` result. The authenticator's registered
|
|
849
849
|
* attestation roots are resolved from its own identifier and the trust path is
|
|
850
850
|
* required to reach one, so an unlisted or revoked model is refused and never
|
|
851
851
|
* reported as verified. Pass `opts.rootCertificates` and the path is required to
|
|
@@ -858,7 +858,7 @@ function _checkAndroidKeyDescription(cert, clientDataHash) {
|
|
|
858
858
|
* roots are a stronger claim than a static pin and its status reports can
|
|
859
859
|
* disqualify a model those roots would still accept. `anchoredTo` reports which
|
|
860
860
|
* route ran, naming every route that contributed and joining them with `+` when more
|
|
861
|
-
* than one did
|
|
861
|
+
* than one did: `"metadata"`, `"rootCertificates"`, and `"safetyNetRoots"` for the
|
|
862
862
|
* android-safetynet chain, which anchors through the roots that format requires whether
|
|
863
863
|
* or not either other route was asked for. It is `null` only when nothing anchored the
|
|
864
864
|
* path. On the mixed metadata/pinned-root route `metadata` still carries the
|
|
@@ -1091,14 +1091,14 @@ void constants;
|
|
|
1091
1091
|
* @spec FIDO Metadata Service v3.0 sec. 3.1, RFC 7515
|
|
1092
1092
|
* @related pki.webauthn.verify, pki.webauthn.metadataFor
|
|
1093
1093
|
*
|
|
1094
|
-
* Verify a FIDO Metadata Service BLOB
|
|
1095
|
-
* authenticator model, its attestation roots, and its certification status, and
|
|
1094
|
+
* Verify a FIDO Metadata Service BLOB (the signed catalogue of every registered
|
|
1095
|
+
* authenticator model, its attestation roots, and its certification status), and
|
|
1096
1096
|
* return its entries indexed by aaguid for lookup. `blob` is caller-supplied bytes or
|
|
1097
1097
|
* a string; retrieval is out of scope, so this never touches the network.
|
|
1098
1098
|
*
|
|
1099
1099
|
* The BLOB is a JWS. Its signature is checked under the certificate in its own header,
|
|
1100
1100
|
* that chain is validated to one of `opts.rootCertificates`, and only THEN is the
|
|
1101
|
-
* payload read
|
|
1101
|
+
* payload read. A BLOB that does not verify never reaches the JSON parser. `no` must
|
|
1102
1102
|
* exceed `opts.previousNo` (rollback) and `nextUpdate` must not have passed
|
|
1103
1103
|
* (freshness). Every failure is a typed `webauthn/metadata-*` throw, never a partial
|
|
1104
1104
|
* result.
|
|
@@ -1224,7 +1224,7 @@ var CLIENT_DATA_TYPE = Object.assign(Object.create(null), { "webauthn.create": 1
|
|
|
1224
1224
|
* @defends webauthn-ceremony-confusion (CWE-345)
|
|
1225
1225
|
* @related pki.webauthn.verify, pki.webauthn.verifyAssertion
|
|
1226
1226
|
*
|
|
1227
|
-
* Decode the `clientDataJSON` a ceremony returns
|
|
1227
|
+
* Decode the `clientDataJSON` a ceremony returns, the half of a WebAuthn response
|
|
1228
1228
|
* the signature covers by digest but that no signature check ever looks inside.
|
|
1229
1229
|
* Parsed through the shared fail-closed JSON guard (bounded bytes and depth,
|
|
1230
1230
|
* fatal UTF-8, duplicate members refused, no prototype pollution), because these
|
|
@@ -1233,7 +1233,7 @@ var CLIENT_DATA_TYPE = Object.assign(Object.create(null), { "webauthn.create": 1
|
|
|
1233
1233
|
* value; `type`, `origin`, `crossOrigin` and `topOrigin` come back as they were.
|
|
1234
1234
|
*
|
|
1235
1235
|
* Supply `expectedType`, `expectedChallenge`, `expectedOrigin` and
|
|
1236
|
-
* `expectedTopOrigin` and each is checked here
|
|
1236
|
+
* `expectedTopOrigin` and each is checked here: the challenge in constant time
|
|
1237
1237
|
* and by full value, the origins whole and case-sensitively. `checked`
|
|
1238
1238
|
* reports which ran, so a check that passed is distinguishable from one that never
|
|
1239
1239
|
* happened. `expectedType` is worth setting on every call: the ceremony a response
|
|
@@ -1418,7 +1418,7 @@ var _ASSERT_OPTS = Object.assign(Object.create(null), {
|
|
|
1418
1418
|
*
|
|
1419
1419
|
* Verify an authentication assertion's signature: the authenticator signs
|
|
1420
1420
|
* `authenticatorData || SHA-256(clientDataJSON)` as raw bytes with the credential
|
|
1421
|
-
* key registered earlier
|
|
1421
|
+
* key registered earlier: no COSE_Sign1 wrapper, so a COSE message verifier is
|
|
1422
1422
|
* the wrong tool and fails on structure before it ever reaches the signature. An
|
|
1423
1423
|
* ES256 assertion signature is an ASN.1 DER `SEQUENCE { r, s }`, converted here
|
|
1424
1424
|
* with the same order-aware reader the attestation path uses, so an r or s outside
|
|
@@ -1428,10 +1428,13 @@ var _ASSERT_OPTS = Object.assign(Object.create(null), {
|
|
|
1428
1428
|
* registered credential key produced this response. What makes the response
|
|
1429
1429
|
* ACCEPTABLE is the sec. 7.2 binding, and the caller owns most of it. Supply
|
|
1430
1430
|
* `expectedRpId`, `requireUserPresence`, `requireUserVerification` and
|
|
1431
|
-
* `allowedAlgorithms` and they are checked here
|
|
1431
|
+
* `allowedAlgorithms` and they are checked here. `bindingChecked` reports which
|
|
1432
1432
|
* ones ran, so a check that passed is distinguishable from one that never
|
|
1433
|
-
* happened.
|
|
1434
|
-
* clientDataJSON and
|
|
1433
|
+
* happened. Supply `expectedChallenge`, `expectedOrigin`, or `expectedTopOrigin`
|
|
1434
|
+
* together with `clientDataJSON` and the challenge and origin are checked here
|
|
1435
|
+
* against it; omit them and they stay with the caller to compare against the
|
|
1436
|
+
* clientDataJSON this call surfaces. Passing them with only `clientDataHash`
|
|
1437
|
+
* throws, because there is no clientDataJSON to check them against.
|
|
1435
1438
|
*
|
|
1436
1439
|
* Pass `previousSignCount` (the value stored at registration or the last login) and
|
|
1437
1440
|
* the sec. 7.2 step 21 counter rule is applied: a counter that fails to advance is
|
|
@@ -1447,6 +1450,7 @@ var _ASSERT_OPTS = Object.assign(Object.create(null), {
|
|
|
1447
1450
|
* credentialPublicKey -- the stored COSE key (as parseAttestationObject surfaced it)
|
|
1448
1451
|
* previousSignCount -- the stored counter, enabling the sec. 7.2 step 21 rule
|
|
1449
1452
|
* expectedRpId, requireUserPresence, requireUserVerification, allowedAlgorithms: the bindings above
|
|
1453
|
+
* expectedChallenge, expectedOrigin, expectedTopOrigin -- checked against clientDataJSON when supplied (needs clientDataJSON, not clientDataHash)
|
|
1450
1454
|
*
|
|
1451
1455
|
* @example
|
|
1452
1456
|
* // requires: `assertion` -- credential.response from navigator.credentials.get();
|
package/lib/webcrypto.js
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* Unlike the browser's built-in `crypto.subtle`, this engine is
|
|
21
21
|
* **PQC-first without being PQC-only**: the FIPS 204 ML-DSA and FIPS
|
|
22
22
|
* 205 SLH-DSA signature suites sit alongside the full classical set PKI
|
|
23
|
-
* still runs on
|
|
23
|
+
* still runs on: RSASSA-PKCS1-v1_5, RSA-PSS, RSA-OAEP, ECDSA, ECDH,
|
|
24
24
|
* Ed25519 / Ed448, AES-GCM / CBC / KW, HMAC, HKDF, PBKDF2, the SHA family
|
|
25
25
|
* (including legacy SHA-1 for old certificates and signatures), and the
|
|
26
26
|
* SHAKE128 / SHAKE256 extendable-output functions as message digests.
|
|
@@ -193,8 +193,8 @@ var SECRET_KEY_NAMES = intrinsic.assign(intrinsic.create(null), { "AES-GCM": tru
|
|
|
193
193
|
*
|
|
194
194
|
* Opaque handle to key material, matching the W3C `CryptoKey` shape:
|
|
195
195
|
* `{ type, extractable, algorithm, usages }`. The underlying
|
|
196
|
-
* `node:crypto` KeyObject is non-enumerable and never serialized
|
|
197
|
-
*
|
|
196
|
+
* `node:crypto` KeyObject is non-enumerable and never serialized.
|
|
197
|
+
* Extract material only through `subtle.exportKey`, and only when the key
|
|
198
198
|
* was created `extractable`. Instances are produced by
|
|
199
199
|
* `subtle.generateKey` / `subtle.importKey`; the constructor is rarely
|
|
200
200
|
* called directly.
|
package/lib/x509-sign.js
CHANGED
|
@@ -195,13 +195,13 @@ function _hasCriticalSan(extSpec) {
|
|
|
195
195
|
* @defends forged-certificate-issuance (CWE-347)
|
|
196
196
|
* @related pki.schema.x509.parse, pki.path.validate, pki.cms.sign
|
|
197
197
|
*
|
|
198
|
-
* Build, sign, and DER-encode an X.509 certificate. `spec` describes the certificate to issue
|
|
198
|
+
* Build, sign, and DER-encode an X.509 certificate. `spec` describes the certificate to issue:
|
|
199
199
|
* `subject` (a string CN, an array of RDNs, or raw Name DER), `subjectPublicKey` (the SPKI DER of the
|
|
200
200
|
* key being certified), `notBefore` / `notAfter` (`Date`s), an optional `serialNumber`, and an optional
|
|
201
201
|
* `extensions` object. `issuer` is the signing side: `{ key }` alone issues a self-signed certificate
|
|
202
202
|
* (issuer = subject, signed with the subject's own key); `{ name, publicKey, key }` or `{ cert, key }`
|
|
203
|
-
* issues a CA-signed one. The signing key `key` is a WebCrypto `CryptoKey`
|
|
204
|
-
* private key passed directly, without exporting
|
|
203
|
+
* issues a CA-signed one. The signing key `key` is a WebCrypto `CryptoKey` (a `pki.key.generate`
|
|
204
|
+
* private key passed directly, without exporting) or a PKCS#8 private key as DER (`Buffer`) or PEM
|
|
205
205
|
* (`string`); a public or secret CryptoKey, or a `node:crypto` KeyObject, is refused. A `subjectAltName`
|
|
206
206
|
* (or any `GeneralName`) entry may be a form object (`{ dNSName: "..." }`) or a bare string classified
|
|
207
207
|
* fail-closed into its form (`"host.example"`, `"a@b.example"`, `"10.0.0.1"`, `"https://host.example/"`).
|
|
@@ -213,8 +213,8 @@ function _hasCriticalSan(extSpec) {
|
|
|
213
213
|
* (positive, <= 20 octets), the validity UTCTime/GeneralizedTime cutover, the DER DEFAULT omissions
|
|
214
214
|
* (v1 tag, `critical=FALSE`, `cA=FALSE`), and the CA cross-field rules (keyCertSign and
|
|
215
215
|
* pathLenConstraint require cA=TRUE) are all enforced; a violation throws a typed `CertificateError`.
|
|
216
|
-
* Where the spec carries raw DER
|
|
217
|
-
* SPKI
|
|
216
|
+
* Where the spec carries raw DER (a `Name` Buffer, a pre-encoded `Extension`, an issuer `publicKey`
|
|
217
|
+
* SPKI), a structural fault throws `CertificateError`, while a malformed leaf inside those bytes
|
|
218
218
|
* throws `Asn1Error`, the same two-error contract the parsers present.
|
|
219
219
|
*
|
|
220
220
|
* @opts
|
package/package.json
CHANGED
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:692adf4f-5fb7-41cd-94f6-da6509e828d9",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-09-
|
|
8
|
+
"timestamp": "2026-09-04T15:47:45.151Z",
|
|
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.6.
|
|
22
|
+
"bom-ref": "@blamejs/pki@0.6.31",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "pki",
|
|
25
|
-
"version": "0.6.
|
|
25
|
+
"version": "0.6.31",
|
|
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.6.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/pki@0.6.31",
|
|
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.6.
|
|
57
|
+
"ref": "@blamejs/pki@0.6.31",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|