@blamejs/pki 0.6.28 → 0.6.30
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 +25 -0
- package/README.md +1 -1
- package/lib/acme.js +10 -8
- 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 +9 -5
- package/lib/cmp-session.js +9 -4
- package/lib/cms-verify.js +22 -17
- package/lib/composite-kem.js +2 -2
- package/lib/constants.js +1 -0
- 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 +34 -22
- package/lib/framework-error.js +2 -2
- package/lib/guard-identifier.js +18 -1
- package/lib/hpke.js +2 -2
- package/lib/http-transport.js +82 -10
- 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 +3 -15
- 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/sigstore.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* ephemeral, ~10 minutes); the Rekor inclusion proof folded to a Rekor-signed
|
|
18
18
|
* tree root; the log entry binding to this exact signature; and the in-toto
|
|
19
19
|
* subject digest the caller confirms against the published artifact. Verify-only
|
|
20
|
-
* and offline
|
|
20
|
+
* and offline: every input is in the bundle or a caller argument. Reuses the
|
|
21
21
|
* shipped X.509 parser, RFC 5280 path validator, RFC 9162 Merkle verifier, and
|
|
22
22
|
* native crypto engine; the net-new codecs are the DSSE PAE byte-builder and a
|
|
23
23
|
* fail-closed JSON bundle reader.
|
|
@@ -102,7 +102,7 @@ function _jsonParse(input, code, label) {
|
|
|
102
102
|
* LEN(body) SP body`, where `LEN` is the ASCII-decimal byte length (no leading
|
|
103
103
|
* zeros) and `type` is the UTF-8 `payloadType`. This is the exact preimage a DSSE
|
|
104
104
|
* signature covers; `LEN` is over the decoded body byte length, never the base64
|
|
105
|
-
* length
|
|
105
|
+
* length. Any deviation is a signature-verify bypass.
|
|
106
106
|
*
|
|
107
107
|
* @example
|
|
108
108
|
* var b = pki.sigstore.pae("application/vnd.in-toto+json", Buffer.from("{}"));
|
package/lib/smime.js
CHANGED
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
* @intro
|
|
13
13
|
* RFC 8551 S/MIME assembly + verification + encryption over the shipped CMS
|
|
14
14
|
* layer. `sign` wraps a MIME entity as a signed S/MIME message and `verify`
|
|
15
|
-
* unwraps and verifies one, in both forms: `multipart/signed` (clear-signed
|
|
15
|
+
* unwraps and verifies one, in both forms: `multipart/signed` (clear-signed:
|
|
16
16
|
* the content stays readable, a detached CMS signature rides alongside) and
|
|
17
17
|
* `application/pkcs7-mime` (opaque, where the whole entity is a base64 CMS
|
|
18
18
|
* SignedData). `encrypt` envelopes a MIME entity as an opaque
|
|
19
|
-
* `application/pkcs7-mime` message and `decrypt` opens one
|
|
19
|
+
* `application/pkcs7-mime` message and `decrypt` opens one: `authEnveloped-data`
|
|
20
20
|
* (AES-GCM, confidentiality AND integrity, the default) or `enveloped-data`
|
|
21
21
|
* (AES-CBC, confidentiality only, so `decrypt` surfaces `authenticated:false`,
|
|
22
22
|
* the EFAIL / RFC 8551 sec. 3.3 no-integrity caveat). The crypto is entirely
|
|
@@ -469,7 +469,7 @@ function _base64Body(der) {
|
|
|
469
469
|
* Assemble a signed S/MIME message (RFC 8551). `content` is the payload: a raw body wrapped as a
|
|
470
470
|
* `text/plain` entity by default, or the caller's own complete MIME entity when `opts.entity` is set;
|
|
471
471
|
* `signers` is the `pki.cms.sign` signer array (any RSA / RSASSA-PSS / ECDSA / EdDSA / ML-DSA / SLH-DSA
|
|
472
|
-
* signer
|
|
472
|
+
* signer: the S/MIME layer is algorithm-agnostic). Two forms via `opts.form`:
|
|
473
473
|
* - `"multipart"` (default, clear-signed): a `multipart/signed` message carrying the canonical entity
|
|
474
474
|
* verbatim in the first part and a DETACHED CMS SignedData (`application/pkcs7-signature`) over its
|
|
475
475
|
* canonical form in the second, with `protocol="application/pkcs7-signature"` + a matching `micalg`.
|
|
@@ -490,7 +490,7 @@ function _base64Body(der) {
|
|
|
490
490
|
* @opts hcp the Header Confidentiality Policy applied to the OUTER display copies: `"hcp_baseline"` (default) or `"hcp_no_confidentiality"`. A signed message's payload is not encrypted, so this governs presentation, not secrecy; used with `protectHeaders`.
|
|
491
491
|
* @opts sid forwarded to cms.sign: the SignerIdentifier form, `"issuerAndSerial"` (default) or `"subjectKeyIdentifier"`.
|
|
492
492
|
* @opts signedAttributes forwarded: `false` omits the signed-attributes set entirely (a bare-signature SignedData).
|
|
493
|
-
* @opts additionalSignedAttributes forwarded: extra signed attributes to carry, as `[{
|
|
493
|
+
* @opts additionalSignedAttributes forwarded: extra signed attributes to carry, as `[{ type, values }]`.
|
|
494
494
|
* @example
|
|
495
495
|
* var pair = await pki.key.generate("Ed25519");
|
|
496
496
|
* var signerKeyPkcs8 = await pki.key.export(pair.privateKey);
|
|
@@ -547,7 +547,7 @@ function _capped(msg) {
|
|
|
547
547
|
*
|
|
548
548
|
* `valid` and `trusted` are separate claims, exactly as in `cms.verify`: a SignedData carries its own
|
|
549
549
|
* certificates, so `valid` says the signature is sound under one of them and nothing about who signed.
|
|
550
|
-
* Name the roots you accept in `opts.trustAnchors` and `trusted` says every signer chained to one
|
|
550
|
+
* Name the roots you accept in `opts.trustAnchors` and `trusted` says every signer chained to one,
|
|
551
551
|
* validated for EMAIL, at both ends of the chain. The signer certificate must carry the
|
|
552
552
|
* `emailProtection` key purpose (RFC 8551 sec. 4.4.4), because a certificate restricted to `serverAuth`
|
|
553
553
|
* chains to its root perfectly well and is still the wrong key to have signed a message; and the anchor's
|
|
@@ -557,8 +557,8 @@ function _capped(msg) {
|
|
|
557
557
|
* A `micalg`
|
|
558
558
|
* that disagrees with the actual digest is advisory unless `opts.strictMicalg` (then `smime/micalg-mismatch`).
|
|
559
559
|
* If the message is header-protected (RFC 9788), `protectedHeaders` is the AUTHENTICATED inner header set (a
|
|
560
|
-
* tampered outer header cannot alter it) and `headerProtection` is `{ present, mode, fromMismatch, confidential, legacy }
|
|
561
|
-
*
|
|
560
|
+
* tampered outer header cannot alter it) and `headerProtection` is `{ present, mode, fromMismatch, confidential, legacy }`.
|
|
561
|
+
* `present` is `true` only for cryptographically-DECLARED (`hp=`) protection you may trust; `fromMismatch` is
|
|
562
562
|
* `true` when the outer From differs from the protected one, `false` when they agree, and `null` when there was
|
|
563
563
|
* no protected From to compare against, which is every message without header protection. Test it against
|
|
564
564
|
* `false` rather than for falsiness: `!fromMismatch` treats the unanswered case as a passed check, and that is
|
|
@@ -569,7 +569,7 @@ function _capped(msg) {
|
|
|
569
569
|
* whose declared `hp` is malformed, invalid, or contradicts the envelope fails closed (`smime/bad-header-protection`),
|
|
570
570
|
* never a silent downgrade. `legacy` is `null` unless `opts.legacyHeaderProtection` detected a legacy RFC 8551
|
|
571
571
|
* `message/rfc822` wrap (see that option), in which case it is its own `{ headers, mode, fromMismatch, confidential }`
|
|
572
|
-
* object (`headers` an ordered `[{ name, value }]` array that retains legally-repeated fields like `Received`)
|
|
572
|
+
* object (`headers` an ordered `[{ name, value }]` array that retains legally-repeated fields like `Received`). A
|
|
573
573
|
* legacy inference is never placed in `protectedHeaders` and never sets `present: true`, because it is
|
|
574
574
|
* indistinguishable from an ordinary forwarded `message/rfc822`, so a caller keying trust off `present` /
|
|
575
575
|
* `protectedHeaders` cannot mistake the opt-in heuristic for authenticated headers.
|
|
@@ -582,12 +582,12 @@ function _capped(msg) {
|
|
|
582
582
|
* extension carries none, from the subject DN's PKCS #9 `emailAddress` attribute, which RFC 8550 sec. 3
|
|
583
583
|
* requires a receiving agent to recognize. Where both are present the extension wins. Only a signer
|
|
584
584
|
* whose signature verified contributes an identity, so a tampered message cannot report a binding. `match` is THREE-valued and a caller enforcing sender binding tests
|
|
585
|
-
* `match === true
|
|
585
|
+
* `match === true`; `false` means every identity was comparable and none matched, and `null` means the
|
|
586
586
|
* question was not answered (no `expectedSender` and no single outer `From`, a signer certificate
|
|
587
587
|
* asserting no readable email identity, or an internationalized address needing an IDNA transform this
|
|
588
588
|
* toolkit does not perform). `null` is not a pass. `sender.identities` lists what the certificate
|
|
589
589
|
* actually asserts, `sender.checked` whether a comparison ran, and `sender.source` which input it ran
|
|
590
|
-
* against
|
|
590
|
+
* against. `"from"` is ADVISORY, because on a message without header protection the outer From is
|
|
591
591
|
* attacker-controlled.
|
|
592
592
|
*
|
|
593
593
|
* @opts certs extra signer certificates (DER `Buffer`s) to match, forwarded to `cms.verify`.
|
|
@@ -687,7 +687,7 @@ function _cmsEncryptOpts(opts) {
|
|
|
687
687
|
* @related pki.smime.decrypt, pki.cms.encrypt
|
|
688
688
|
*
|
|
689
689
|
* Envelope a MIME entity as an encrypted S/MIME message (RFC 8551 sec. 3.3 / sec. 3.4). `content` is the
|
|
690
|
-
* payload
|
|
690
|
+
* payload: a raw body wrapped as a `text/plain` entity by default, or the caller's own complete MIME
|
|
691
691
|
* entity when `opts.entity` is set; `recipients` is the `pki.cms.encrypt` recipient array (any RSA-OAEP
|
|
692
692
|
* ktri / EC or X25519/X448 kari / ML-KEM ori-KEM / password pwri / kek kekri: the S/MIME layer is
|
|
693
693
|
* recipient-agnostic; a single descriptor is accepted and normalized to a one-element array). Enveloping
|
|
@@ -697,7 +697,7 @@ function _cmsEncryptOpts(opts) {
|
|
|
697
697
|
* with `smime-type=enveloped-data` (confidentiality only, no integrity, RFC 8551 sec. 3.3). With
|
|
698
698
|
* `opts.protectHeaders`, the message is header-protected (RFC 9788): the real `opts.headers` are inlined
|
|
699
699
|
* inside the ciphertext (the payload Content-Type gains `hp="cipher"`), and only the Header-Confidentiality-
|
|
700
|
-
* Policy-processed display copies appear outside
|
|
700
|
+
* Policy-processed display copies appear outside. The default `hcp_baseline` obscures Subject to `[...]`
|
|
701
701
|
* and removes Comments / Keywords, so those values live only in the ciphertext; `decrypt` recovers the real
|
|
702
702
|
* inner set. Returns the assembled message bytes. Fail-closed with `SmimeError`.
|
|
703
703
|
*
|
|
@@ -740,7 +740,7 @@ async function encrypt(content, recipients, opts) {
|
|
|
740
740
|
* @spec RFC 8551, RFC 5652, RFC 5083, RFC 9788
|
|
741
741
|
* @related pki.smime.encrypt, pki.cms.decrypt, pki.smime.verify
|
|
742
742
|
*
|
|
743
|
-
* Open an encrypted S/MIME message (RFC 8551 sec. 3.3 / sec. 3.4)
|
|
743
|
+
* Open an encrypted S/MIME message (RFC 8551 sec. 3.3 / sec. 3.4), an `application/pkcs7-mime` entity
|
|
744
744
|
* whose base64 body is a CMS EnvelopedData or AuthEnvelopedData. `keyMaterial` is the `pki.cms.decrypt`
|
|
745
745
|
* key material (`{ key, cert }`, `{ password }`, or `{ kek, kekId? }`). Returns the recovered inner MIME
|
|
746
746
|
* entity as `content`, the `smimeType`, `authenticated` (true only for AuthEnvelopedData; a CBC
|
|
@@ -753,7 +753,7 @@ async function encrypt(content, recipients, opts) {
|
|
|
753
753
|
* (RFC 9788, `hp="cipher"`), `protectedHeaders` is the recovered real inner header set (the values the outer
|
|
754
754
|
* Header Confidentiality Policy hid) and `headerProtection` is `{ present, mode, fromMismatch, confidential, legacy }`,
|
|
755
755
|
* where `present` is `true` only for a declared `hp=` payload, and `confidential` names the fields the composer
|
|
756
|
-
* kept end-to-end confidential (via the authenticated HP-Outer records, RFC 9788 sec. 4.3)
|
|
756
|
+
* kept end-to-end confidential (via the authenticated HP-Outer records, RFC 9788 sec. 4.3), so a caller can
|
|
757
757
|
* reply/forward without leaking them (sec. 6.1); a payload whose `hp` is malformed or contradicts the envelope
|
|
758
758
|
* fails closed (`smime/bad-header-protection`). `legacy` is `null` unless `opts.legacyHeaderProtection` detected a
|
|
759
759
|
* legacy RFC 8551 `message/rfc822` wrap (its own `{ headers, mode, fromMismatch, confidential }` object, where `headers`
|
|
@@ -806,7 +806,7 @@ async function decrypt(message, keyMaterial, opts) {
|
|
|
806
806
|
* @related pki.smime.decompress, pki.cms.compress
|
|
807
807
|
*
|
|
808
808
|
* Compress a MIME entity as an opaque compressed S/MIME message (RFC 8551 sec. 3.6). `content` is the
|
|
809
|
-
* payload
|
|
809
|
+
* payload: a raw body wrapped as a `text/plain` entity by default, or the caller's own complete MIME
|
|
810
810
|
* entity when `opts.entity` is set. The entity is canonicalized (RFC 8551 sec. 3.1) and ZLIB-compressed
|
|
811
811
|
* into a CMS `CompressedData` (`pki.cms.compress`), carried opaque in one `application/pkcs7-mime;
|
|
812
812
|
* smime-type=compressed-data; name=smime.p7z` entity (base64). Compression is a size transform with NO
|
|
@@ -838,7 +838,7 @@ async function compress(content, opts) {
|
|
|
838
838
|
* @spec RFC 8551, RFC 3274
|
|
839
839
|
* @related pki.smime.compress, pki.cms.decompress, pki.smime.verify, pki.smime.decrypt
|
|
840
840
|
*
|
|
841
|
-
* Decompress a compressed S/MIME message (RFC 8551 sec. 3.6)
|
|
841
|
+
* Decompress a compressed S/MIME message (RFC 8551 sec. 3.6), an `application/pkcs7-mime` entity whose
|
|
842
842
|
* base64 body is a CMS `CompressedData`. Returns the recovered inner MIME entity as `content` plus the
|
|
843
843
|
* inner `contentType` / `contentTypeName` and the `compressionAlgorithm`. The inflate is BOUNDED (a
|
|
844
844
|
* decompression-bomb defense, `cms/decompress-too-large`; `opts.maxOutputBytes` tightens it downward).
|
package/lib/tls-cert-compress.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* @intro
|
|
13
13
|
* TLS handshake structures that carry certificates. `decompressCertificate`
|
|
14
|
-
* and `compressCertificate` are the RFC 8879 `CompressedCertificate` codec
|
|
14
|
+
* and `compressCertificate` are the RFC 8879 `CompressedCertificate` codec:
|
|
15
15
|
* the compressed form of a TLS 1.3 `Certificate` message, which shrinks the
|
|
16
16
|
* largest thing a handshake sends and matters most for post-quantum chains,
|
|
17
17
|
* where certificates grow by kilobytes. `parseCertificateMessage` decodes the
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
* allocated), and the output must then equal that length exactly (which catches
|
|
31
31
|
* the under-length direction a cap cannot see). The caller's policy cap applies
|
|
32
32
|
* independently, so a peer declaring 16 MiB does not get 16 MiB. This module
|
|
33
|
-
* decodes structure only
|
|
33
|
+
* decodes structure only. It never verifies a certificate, builds a path, or
|
|
34
34
|
* speaks the handshake.
|
|
35
35
|
*
|
|
36
|
-
* All three registered algorithms
|
|
36
|
+
* All three registered algorithms (zlib, brotli and zstd) are implemented,
|
|
37
37
|
* and each is offered only where the running Node can decompress it safely. A
|
|
38
38
|
* decompressor must fault on a frame it could not finish; where one instead
|
|
39
39
|
* returns a short result and reports the whole input consumed, a peer could cut
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
*
|
|
45
45
|
* @card
|
|
46
46
|
* Encode and decode RFC 8879 TLS compressed certificate messages and the
|
|
47
|
-
* RFC 8446 Certificate message inside them
|
|
47
|
+
* RFC 8446 Certificate message inside them: a two-sided decompression
|
|
48
48
|
* bound, exact-length enforcement, per-entry certificate DER surfaced raw,
|
|
49
49
|
* fail-closed. All three registered algorithms are implemented; each is
|
|
50
50
|
* offered only where the running Node decompresses it safely.
|
|
@@ -138,7 +138,7 @@ function _resolveAllowed(opts) {
|
|
|
138
138
|
* body is a framing violation (`opaque<1..2^24-1>`), not an empty certificate list.
|
|
139
139
|
*
|
|
140
140
|
* Throws `TlsError` with a stable `tls/*` code on any malformed input, never a raw
|
|
141
|
-
* `TypeError`. Structure only
|
|
141
|
+
* `TypeError`. Structure only: no certificate here is verified or path-built.
|
|
142
142
|
*
|
|
143
143
|
* @opts
|
|
144
144
|
* maxOutputBytes - tighten the decompression cap DOWNWARD from the RFC 8446 sec. 4
|
|
@@ -221,8 +221,8 @@ function decompressCertificate(bytes, opts) {
|
|
|
221
221
|
*
|
|
222
222
|
* Decode an RFC 8446 sec. 4.4.2 `Certificate` message into its
|
|
223
223
|
* `certificateRequestContext` (raw, empty in a server's handshake certificate) and its
|
|
224
|
-
* `entries`. Each entry surfaces `certData`
|
|
225
|
-
* on the wire, ready for `pki.schema.x509.parse` and never re-serialized, plus the raw
|
|
224
|
+
* `entries`. Each entry surfaces `certData` (the certificate DER exactly as it appeared
|
|
225
|
+
* on the wire, ready for `pki.schema.x509.parse` and never re-serialized), plus the raw
|
|
226
226
|
* `extensions` bytes that follow it and `extensionList`, those bytes decoded to their
|
|
227
227
|
* RFC 8446 sec. 4.2 records (`type` and raw `data` per extension). The vector's framing is
|
|
228
228
|
* validated and not accepted opaquely, so a vector that cannot be a whole number of
|
package/lib/trust.js
CHANGED
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
* Everything is fail-closed and offline: the caller supplies the text (no
|
|
25
25
|
* network fetch); every malformed or oversized input throws a typed
|
|
26
26
|
* `trust/*` error before the offending allocation; a certificate object and
|
|
27
|
-
* its trust object are paired by byte-exact (CKA_ISSUER, CKA_SERIAL_NUMBER)
|
|
28
|
-
*
|
|
27
|
+
* its trust object are paired by byte-exact (CKA_ISSUER, CKA_SERIAL_NUMBER),
|
|
28
|
+
* never by adjacency, and cross-checked against the parsed DER, so
|
|
29
29
|
* trust metadata can never attach to the wrong root; only
|
|
30
30
|
* `CKT_NSS_TRUSTED_DELEGATOR` grants a purpose (everything else, including
|
|
31
31
|
* an absent bit, is untrusted).
|
|
@@ -441,9 +441,9 @@ function _dedupAnchors(anchors) {
|
|
|
441
441
|
* Parse the Mozilla/NSS `certdata.txt` root-store object stream into
|
|
442
442
|
* constraint-carrying trust anchors. Each CKO_CERTIFICATE object's
|
|
443
443
|
* MULTILINE_OCTAL `CKA_VALUE` is decoded and parsed as a DER certificate; the
|
|
444
|
-
* paired CKO_NSS_TRUST object
|
|
444
|
+
* paired CKO_NSS_TRUST object (joined by byte-exact CKA_ISSUER +
|
|
445
445
|
* CKA_SERIAL_NUMBER, never adjacency, and cross-checked against the parsed
|
|
446
|
-
* DER
|
|
446
|
+
* DER) contributes the purpose trust bits (only CKT_NSS_TRUSTED_DELEGATOR
|
|
447
447
|
* grants a purpose); the per-purpose distrust-after dates ride in the
|
|
448
448
|
* certificate object as bare ASCII times routed through the strict DER time
|
|
449
449
|
* reader. Every anchor carries the exact `{ name, publicKey, algorithm,
|
|
@@ -641,7 +641,7 @@ function _pemCell(cell) {
|
|
|
641
641
|
* (`Common Name or Certificate Name`, `Trust Bits`, `Distrust for TLS After
|
|
642
642
|
* Date`, `Distrust for S/MIME After Date`, `PEM Info`) fails closed with
|
|
643
643
|
* `trust/bad-csv`. Fields follow RFC 4180 quoting (embedded commas, newlines,
|
|
644
|
-
* doubled-quote escapes
|
|
644
|
+
* doubled-quote escapes; the PEM Info column depends on it). `Trust Bits`
|
|
645
645
|
* is set-valued (Websites -> serverAuth, Email -> emailProtection, Code ->
|
|
646
646
|
* codeSigning; absent -> untrusted). A DATE-only distrust cell expands to the
|
|
647
647
|
* end-of-day `...T23:59:59Z` instant, matching the NSS `...235959Z`
|
package/lib/tsp-sign.js
CHANGED
|
@@ -96,8 +96,8 @@ function _signingCertV2(certDer, hashName) {
|
|
|
96
96
|
* @spec RFC 3161
|
|
97
97
|
* @related pki.schema.tsp.parseToken, pki.cms.sign
|
|
98
98
|
*
|
|
99
|
-
* Create an RFC 3161 TimeStampToken over `messageImprint` (`{ hashAlgorithm, hashedMessage }
|
|
100
|
-
*
|
|
99
|
+
* Create an RFC 3161 TimeStampToken over `messageImprint` (`{ hashAlgorithm, hashedMessage }`:
|
|
100
|
+
* the hash of the data being timestamped, computed by the requester). `tsa` is the
|
|
101
101
|
* timestamp authority's `{ cert, key }` (as `pki.cms.sign` takes them). The token is a CMS
|
|
102
102
|
* SignedData whose content is a `TSTInfo` carrying the imprint, the TSA policy, a serial
|
|
103
103
|
* number, and `genTime`; the RFC 3161 sec. 2.4.2 signing-certificate attribute binding the
|
|
@@ -110,6 +110,8 @@ function _signingCertV2(certDer, hashName) {
|
|
|
110
110
|
* @opts accuracy The genTime +/- accuracy, as `{ seconds?, millis?, micros? }`.
|
|
111
111
|
* @opts ordering Whether tokens from this TSA are strictly ordered in time (boolean).
|
|
112
112
|
* @opts certHashAlgorithm The ESSCertIDv2 hash algorithm name. Default `sha256`.
|
|
113
|
+
* @opts digestAlgorithm / pss Passed through to `pki.cms.sign` (the signer digest algorithm, RSA-PSS padding).
|
|
114
|
+
* @opts additionalSignedAttributes Extra signed attributes to carry on the token, as `[{ type, values }]` (forwarded to `pki.cms.sign`).
|
|
113
115
|
* @opts sid / pem Passed through to `pki.cms.sign` (signer identifier, PEM output).
|
|
114
116
|
* @example
|
|
115
117
|
* var pair = await pki.key.generate("Ed25519");
|
|
@@ -303,7 +305,7 @@ function request(messageImprint, opts) {
|
|
|
303
305
|
* @spec RFC 3161
|
|
304
306
|
* @related pki.tsp.request, pki.schema.tsp.parseRequest
|
|
305
307
|
*
|
|
306
|
-
* Parse a `TimeStampReq` (DER `Buffer` or PEM)
|
|
308
|
+
* Parse a `TimeStampReq` (DER `Buffer` or PEM), the `pki.schema.tsp.parseRequest` decoder on the
|
|
307
309
|
* `pki.tsp` namespace. Returns `{ version, messageImprint, reqPolicy, reqPolicyName, nonce,
|
|
308
310
|
* nonceHex, certReq, extensions }`; a malformed structure throws a typed `TspError`.
|
|
309
311
|
*
|
|
@@ -382,7 +384,7 @@ function response(token, opts) {
|
|
|
382
384
|
* @spec RFC 3161
|
|
383
385
|
* @related pki.tsp.response, pki.schema.tsp.parse
|
|
384
386
|
*
|
|
385
|
-
* Parse a `TimeStampResp` (DER `Buffer` or PEM)
|
|
387
|
+
* Parse a `TimeStampResp` (DER `Buffer` or PEM), the shipped `pki.schema.tsp.parse` decoder on
|
|
386
388
|
* the `pki.tsp` namespace. Returns `{ status, statusString, failInfo, timeStampToken }` with the
|
|
387
389
|
* status-to-token coupling enforced; a granted response's token is decoded via `parseToken`.
|
|
388
390
|
*
|
|
@@ -535,7 +537,7 @@ function _buildTsaChains(leaf, pool) {
|
|
|
535
537
|
* original bytes (hashed under the token's messageImprint algorithm) or a precomputed
|
|
536
538
|
* `{ hashAlgorithm, hashedMessage }`. Returns `{ valid, trusted, revocationChecked,
|
|
537
539
|
* anchorConstraints, genTime, accuracy, serialNumber,
|
|
538
|
-
* serialNumberHex, policy, nonce, tsa, tstInfo, signer, code?, reason? }`. `valid` is true only
|
|
540
|
+
* serialNumberHex, policy, policyName, nonce, tsa, tstInfo, signer, code?, reason? }`. `valid` is true only
|
|
539
541
|
* when the CMS signature, the imprint match, the eContentType, the ESSCertID(V2) binding, the
|
|
540
542
|
* RFC 3161 sec. 2.3 critical single-`timeStamping` extendedKeyUsage rule, the requested nonce (when
|
|
541
543
|
* supplied), and, when `trustAnchors` is supplied, the full out-of-path TSA-cert path
|
|
@@ -603,7 +605,7 @@ async function verify(token, data, opts) {
|
|
|
603
605
|
var revocationChecked = false;
|
|
604
606
|
var anchorConstraints = null;
|
|
605
607
|
function fail(code, reason) {
|
|
606
|
-
return { valid: false, trusted: false, revocationChecked: revocationChecked, anchorConstraints: anchorConstraints, code: code, reason: reason || null, genTime: tst.genTime, accuracy: tst.accuracy, serialNumber: tst.serialNumber, serialNumberHex: tst.serialNumberHex, policy: tst.policy, nonce: tst.nonce, tsa: tst.tsa, tstInfo: tst, signer: null };
|
|
608
|
+
return { valid: false, trusted: false, revocationChecked: revocationChecked, anchorConstraints: anchorConstraints, code: code, reason: reason || null, genTime: tst.genTime, accuracy: tst.accuracy, serialNumber: tst.serialNumber, serialNumberHex: tst.serialNumberHex, policy: tst.policy, policyName: tst.policyName, nonce: tst.nonce, tsa: tst.tsa, tstInfo: tst, signer: null };
|
|
607
609
|
}
|
|
608
610
|
var cmsRes = await cmsVerify.verify(tokenDer, { certs: opts.certs });
|
|
609
611
|
var signer = cmsRes.signers[0];
|
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:7606eb0a-d4b1-46ef-ab6c-eae467d83dd7",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-09-
|
|
8
|
+
"timestamp": "2026-09-04T06:04:55.759Z",
|
|
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.30",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "pki",
|
|
25
|
-
"version": "0.6.
|
|
25
|
+
"version": "0.6.30",
|
|
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.30",
|
|
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.30",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|