@blamejs/pki 0.2.31 → 0.2.32
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 +12 -0
- package/README.md +1 -1
- package/lib/inspect.js +15 -0
- package/lib/lint.js +27 -18
- package/lib/oid.js +7 -0
- package/lib/path-validate.js +15 -0
- package/lib/schema-pkix.js +56 -0
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ All notable changes to `@blamejs/pki` are documented here. The format
|
|
|
4
4
|
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this
|
|
5
5
|
project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## v0.2.32 — 2026-07-16
|
|
8
|
+
|
|
9
|
+
X.509 certificates now decode the Microsoft Active Directory Certificate Services enrollment extensions, and pki.lint's critical-extension check is aligned with certification-path validation.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- pki.schema.x509.parse decodes the Microsoft Active Directory Certificate Services enrollment extensions ([MS-WCCE] / [MS-CRTD]): the v2 certificate template (szOID-CERTIFICATE_TEMPLATE -- template OID plus major/minor version), the legacy v1 template name (szOID-ENROLL_CERTTYPE_EXTENSION), the CA version (szOID-CERTSRV_CA_VERSION, surfaced as the raw value and as the CA key index / certificate index split), the previous-CA-certificate hash (szOID-CERTSRV_PREVIOUS_CERT_HASH), and the application policies (szOID-APPLICATION_CERT_POLICIES, decoded as RFC 5280 certificate policies). Each is rendered by pki.inspect and fails closed with a typed error on a malformed shape. The version fields accept the full 32-bit range Active Directory uses, not a signed subset.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- pki.lint's unrecognized-critical-extension check now mirrors certification-path validation: it reports a critical extension whose semantics the path validator does not process -- an authority/subject key identifier, a freshest-CRL pointer, an SCT list, a qualified-certificate statement, or a Microsoft enterprise-CA extension -- rather than treating any extension it can merely decode as processed. precertificatePoison, which RFC 6962 requires to be critical, is not reported. A conforming relying party must reject a critical extension it cannot process, so a certificate whose critical enterprise or qualified-certificate constraints this toolkit does not enforce is now surfaced by the linter.
|
|
18
|
+
|
|
7
19
|
## v0.2.31 — 2026-07-16
|
|
8
20
|
|
|
9
21
|
X.509 certificates now decode the RFC 3739 / ETSI EN 319 412-5 qualified-certificate qcStatements extension, and the sigstore verifier gains a low-order EdDSA public-key gate.
|
package/README.md
CHANGED
|
@@ -203,7 +203,7 @@ is callable today; nothing below is a stub.
|
|
|
203
203
|
| `pki.oid` | Two-way OID ↔ name registry — `name`, `byName`, `register`, `toArcs`/`fromArcs`, `toDER`/`fromDER`; seeded with RFC 5280 + NIST PQC arcs |
|
|
204
204
|
| `pki.webcrypto` | A W3C WebCrypto (`SubtleCrypto`) engine over `node:crypto` — `sign`/`verify`/`encrypt`/`decrypt`/`deriveBits`/`digest`/`generateKey`/`importKey`/`exportKey` across RSA, ECDSA, ECDH, Ed25519/Ed448, AES, HMAC, HKDF, PBKDF2, SHA — **and** post-quantum ML-DSA-44/65/87 and SLH-DSA signatures, plus ML-KEM-512/768/1024 key generation and certificate/PKCS#8 import — the RFC 9935 seed / expandedKey / both private-key CHOICE is validated fail-closed, so an OpenSSL-legacy bare-seed or an internally inconsistent key is rejected with a typed error (KEM encapsulation lands with CMS KEM-decrypt). Zero-dependency, OpenSSL-interoperable |
|
|
205
205
|
| `pki.schema` | The schema family — `parse` detects which PKI format DER / PEM encodes and routes to the right parser, `all` enumerates the registered formats, and the engine + per-format members are grouped here |
|
|
206
|
-
| `pki.schema.x509` | Parse DER / PEM certificates into structured, validated fields, with named + partly-decoded extensions — including the RFC 3739 / ETSI EN 319 412-5 qualified-certificate `qcStatements` (EU-qualified declaration, reliance limit, QSCD flag, certificate type, retention, PDS URLs, country of qualification; unknown statements preserved opaque), fail-closed — `parse`, `pemDecode`, `pemEncode` |
|
|
206
|
+
| `pki.schema.x509` | Parse DER / PEM certificates into structured, validated fields, with named + partly-decoded extensions — including the RFC 3739 / ETSI EN 319 412-5 qualified-certificate `qcStatements` (EU-qualified declaration, reliance limit, QSCD flag, certificate type, retention, PDS URLs, country of qualification; unknown statements preserved opaque) and the Microsoft Active Directory Certificate Services enrollment extensions (certificate template, CA version, previous-CA-certificate hash, application policies), fail-closed — `parse`, `pemDecode`, `pemEncode` |
|
|
207
207
|
| `pki.schema.c509` | Parse C509 CBOR-encoded certificates (draft-ietf-cose-cbor-encoded-cert) — the compact CBOR profile of X.509, decoded fail-closed under deterministic CBOR; an explicit `parse` call (CBOR, not DER, so not auto-routed) |
|
|
208
208
|
| `pki.schema.crl` | Parse DER / PEM X.509 CRLs per RFC 5280 §5 — revoked serials with real-`Date` revocation times, named + partly-decoded extensions, fail-closed — `parse`, `pemDecode`, `pemEncode` |
|
|
209
209
|
| `pki.schema.csr` | Parse DER / PEM PKCS#10 certification requests per RFC 2986 — subject DN, public key, requested attributes, signature, fail-closed — `parse`, `pemDecode`, `pemEncode` |
|
package/lib/inspect.js
CHANGED
|
@@ -335,6 +335,19 @@ var EXT_RENDERERS = {
|
|
|
335
335
|
return label;
|
|
336
336
|
}).join("\n");
|
|
337
337
|
},
|
|
338
|
+
msCertificateTemplate: function (decoded, inner) {
|
|
339
|
+
var v = decoded.templateMajorVersion === null ? "" : " v" + decoded.templateMajorVersion + "." + (decoded.templateMinorVersion === null ? 0 : decoded.templateMinorVersion);
|
|
340
|
+
return inner + "Template: " + (decoded.name || decoded.templateID) + v;
|
|
341
|
+
},
|
|
342
|
+
msEnrollCertType: function (decoded, inner) {
|
|
343
|
+
return inner + "Cert Type: " + _clean(String(decoded));
|
|
344
|
+
},
|
|
345
|
+
msCaVersion: function (decoded, inner) {
|
|
346
|
+
return inner + "CA Version: V" + decoded.caKeyIndex + "." + decoded.certIndex;
|
|
347
|
+
},
|
|
348
|
+
msPreviousCertHash: function (decoded, inner) {
|
|
349
|
+
return inner + _hexColon(Buffer.isBuffer(decoded) ? decoded : Buffer.alloc(0), { upper: true });
|
|
350
|
+
},
|
|
338
351
|
subjectAltName: _renderAltName,
|
|
339
352
|
issuerAltName: _renderAltName,
|
|
340
353
|
certificatePolicies: function (decoded, inner) {
|
|
@@ -422,6 +435,8 @@ var EXT_RENDERERS = {
|
|
|
422
435
|
return akiLines.length ? akiLines.join("\n") : inner + "keyid:(none)";
|
|
423
436
|
},
|
|
424
437
|
};
|
|
438
|
+
// [MS-WCCE] szOID-APPLICATION_CERT_POLICIES decodes as certificatePolicies, so it renders identically.
|
|
439
|
+
EXT_RENDERERS.msApplicationPolicies = EXT_RENDERERS.certificatePolicies;
|
|
425
440
|
|
|
426
441
|
// Coverage residual -- the EXT_RENDERERS entry fallbacks are unreachable because each shared
|
|
427
442
|
// decoder (and asn1.read.oid) already narrows the shape before the renderer runs:
|
package/lib/lint.js
CHANGED
|
@@ -29,6 +29,7 @@ var guard = require("./guard-all");
|
|
|
29
29
|
var oid = require("./oid");
|
|
30
30
|
var x509 = require("./schema-x509");
|
|
31
31
|
var pkix = require("./schema-pkix");
|
|
32
|
+
var path = require("./path-validate");
|
|
32
33
|
var C = require("./constants");
|
|
33
34
|
var ipUtils = require("./ip-utils");
|
|
34
35
|
|
|
@@ -237,24 +238,32 @@ function _subjectCNs(cert) {
|
|
|
237
238
|
return out;
|
|
238
239
|
}
|
|
239
240
|
|
|
240
|
-
// An extension is
|
|
241
|
-
// it
|
|
242
|
-
//
|
|
243
|
-
//
|
|
244
|
-
//
|
|
245
|
-
//
|
|
246
|
-
//
|
|
247
|
-
//
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
//
|
|
251
|
-
//
|
|
252
|
-
//
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
241
|
+
// An extension's CRITICALITY is honoured (RFC 5280 4.2: a consumer MUST reject a critical extension
|
|
242
|
+
// it cannot PROCESS) only when this toolkit actually processes its semantics. That authority is
|
|
243
|
+
// path-validate's PROCESSED_EXTENSIONS (the RFC 5280 sec. 6.1 path-processing set), NOT the decoder
|
|
244
|
+
// table: certExtensionDecoders also DECODES many extensions purely for display (qcStatements, the MS
|
|
245
|
+
// enterprise-CA extensions, the SCT list, the *KeyIdentifiers, freshestCRL, issuerAltName) whose
|
|
246
|
+
// critical semantics are not enforced -- path-validate rejects a critical instance of any of those
|
|
247
|
+
// as unrecognized-critical, so the linter flags them too (structural decodability is not validation
|
|
248
|
+
// processing). The one decode-only extension that is LEGITIMATELY critical is precertificatePoison
|
|
249
|
+
// (RFC 6962 sec. 3.1 REQUIRES it critical), so it is allow-listed. Everything else -- a processed
|
|
250
|
+
// extension, or an unregistered OID (algorithm / EKU-purpose OID the name registry resolves but that
|
|
251
|
+
// is no extension) -- falls out correctly: processed -> recognized, unregistered -> unknown. Driving
|
|
252
|
+
// this off the validator's set (not the decoder table) means a newly-decoded extension is
|
|
253
|
+
// flagged-when-critical automatically until its semantics are actually processed.
|
|
254
|
+
var _CRITICAL_LEGIT = {};
|
|
255
|
+
_CRITICAL_LEGIT[oid.byName("precertificatePoison")] = true;
|
|
256
|
+
// Mirrors path-validate's unrecognizedCriticalExtension. An extension not in PROCESSED_EXTENSIONS is
|
|
257
|
+
// unknown everywhere (precertificatePoison is the one legitimately-critical exception). An extension
|
|
258
|
+
// that IS processed for an intermediate but is unprocessed on the TARGET (policyMappings) is also
|
|
259
|
+
// flagged: path-validate decides target status purely by path position (i === n), so ANY certificate
|
|
260
|
+
// -- a CA included -- can be validated as the final/target certificate, where a critical instance is
|
|
261
|
+
// rejected. A linter has no path context and cannot rule that out, so it flags these regardless of
|
|
262
|
+
// cA-ness (policyMappings is SHOULD-be-non-critical everywhere, so this never mis-flags conformant input).
|
|
263
|
+
function _isUnknownExtension(extOid) {
|
|
264
|
+
if (path.PROCESSED_EXTENSIONS[extOid] !== true) return _CRITICAL_LEGIT[extOid] !== true;
|
|
265
|
+
return path.TARGET_UNPROCESSED_IF_CRITICAL[extOid] === true;
|
|
266
|
+
}
|
|
258
267
|
|
|
259
268
|
// RSA-modulus / EC-curve helpers for the weak-key lint. Each returns null when the key
|
|
260
269
|
// material cannot be read as expected (a malformed RSA modulus, or EC parameters that are
|
package/lib/oid.js
CHANGED
|
@@ -95,6 +95,13 @@ var FAMILIES = {
|
|
|
95
95
|
// ETSI EN 319 412-5 QcType member OIDs (the certificate-purpose types) on the id-etsi-qct arc.
|
|
96
96
|
etsiQcType: { base: [0, 4, 0, 1862, 1, 6], of: { qctEsign: 1, qctEseal: 2, qctWeb: 3 } },
|
|
97
97
|
|
|
98
|
+
// [MS-WCCE] AD CS enrollment extensions on the id-microsoft-21 arc (szOID-CERTSRV / szOID-CERTIFICATE_TEMPLATE / szOID-APPLICATION_CERT_POLICIES).
|
|
99
|
+
msEnrollment: { base: [1, 3, 6, 1, 4, 1, 311, 21], of: {
|
|
100
|
+
msCaVersion: 1, msPreviousCertHash: 2, msCertificateTemplate: 7, msApplicationPolicies: 10 } },
|
|
101
|
+
|
|
102
|
+
// [MS-CRTD] legacy v1 enroll cert-type name on the id-microsoft-20 arc (szOID-ENROLL_CERTTYPE_EXTENSION).
|
|
103
|
+
msEnrollmentLegacy: { base: [1, 3, 6, 1, 4, 1, 311, 20], of: { msEnrollCertType: 2 } },
|
|
104
|
+
|
|
98
105
|
// id-aca -- RFC 5755 attribute-certificate attribute types on the id-pkix 10 arc:
|
|
99
106
|
// authenticationInfo sec. 4.4.1 .. group sec. 4.4.4, plus encAttrs sec. 7.1 (the encrypted-
|
|
100
107
|
// attribute wrapper, syntax ContentInfo). { id-aca 5 } is reserved.
|
package/lib/path-validate.js
CHANGED
|
@@ -101,6 +101,11 @@ var PROCESSED_EXTENSIONS = {};
|
|
|
101
101
|
OID.policyMappings, OID.policyConstraints, OID.inhibitAnyPolicy, OID.subjectAltName,
|
|
102
102
|
OID.extKeyUsage, OID.cRLDistributionPoints].
|
|
103
103
|
forEach(function (o) { PROCESSED_EXTENSIONS[o] = true; });
|
|
104
|
+
// Frozen after seeding: this exact object is both consulted by the critical-extension check here and
|
|
105
|
+
// exported (for pki.lint to stay consistent). A caller must not be able to add an OID -- doing so
|
|
106
|
+
// would make an attacker's critical, decoder-less extension pass as "processed" and skip both the
|
|
107
|
+
// unrecognized-critical check and structural validation. Freezing makes any such write a no-op.
|
|
108
|
+
Object.freeze(PROCESSED_EXTENSIONS);
|
|
104
109
|
|
|
105
110
|
// ---- signature verify bridge (NEW 6) ---------------------------------------
|
|
106
111
|
|
|
@@ -1061,6 +1066,7 @@ function applyPolicyMappings(state, mappings, i) {
|
|
|
1061
1066
|
// a terminal CA cert is conforming and is NOT treated as unprocessed here.)
|
|
1062
1067
|
var TARGET_UNPROCESSED_IF_CRITICAL = {};
|
|
1063
1068
|
TARGET_UNPROCESSED_IF_CRITICAL[OID.policyMappings] = true;
|
|
1069
|
+
Object.freeze(TARGET_UNPROCESSED_IF_CRITICAL);
|
|
1064
1070
|
|
|
1065
1071
|
function unrecognizedCriticalExtension(cert, isTarget) {
|
|
1066
1072
|
for (var i = 0; i < cert.extensions.length; i++) {
|
|
@@ -2023,4 +2029,13 @@ module.exports = {
|
|
|
2023
2029
|
crlChecker: crlChecker,
|
|
2024
2030
|
ocspChecker: ocspChecker,
|
|
2025
2031
|
verifyOcspResponse: verifyOcspResponse,
|
|
2032
|
+
// The set of extension OIDs whose CRITICAL semantics this validator processes (RFC 5280 sec. 6.1).
|
|
2033
|
+
// Exposed so a linter can distinguish "processed" from "merely decoded" and stay consistent with
|
|
2034
|
+
// the path-validation verdict on a critical extension -- a decoder in certExtensionDecoders is NOT
|
|
2035
|
+
// by itself proof the criticality is honoured. Both sets are frozen so a caller cannot mutate them.
|
|
2036
|
+
PROCESSED_EXTENSIONS: PROCESSED_EXTENSIONS,
|
|
2037
|
+
// Extensions that ARE processed for an intermediate CA but are unprocessed on the target/leaf, so a
|
|
2038
|
+
// critical instance on the target fails closed (RFC 5280 sec. 6.1.5(f)) -- policyMappings is
|
|
2039
|
+
// prepare-next-only and SHOULD-be-non-critical. A linter mirrors this for a leaf certificate.
|
|
2040
|
+
TARGET_UNPROCESSED_IF_CRITICAL: TARGET_UNPROCESSED_IF_CRITICAL,
|
|
2026
2041
|
};
|
package/lib/schema-pkix.js
CHANGED
|
@@ -1031,6 +1031,57 @@ function certExtensionDecoders(ns) {
|
|
|
1031
1031
|
return out;
|
|
1032
1032
|
}
|
|
1033
1033
|
|
|
1034
|
+
// [MS-WCCE] szOID-CERTIFICATE_TEMPLATE -- CertificateTemplateOID ::= SEQUENCE {
|
|
1035
|
+
// templateID OID, templateMajorVersion INTEGER OPTIONAL, templateMinorVersion INTEGER OPTIONAL }.
|
|
1036
|
+
// The two versions are DWORDs (0..2^32-1), NOT uint31 -- a CA key/template revision with bit 31
|
|
1037
|
+
// set is a legal DWORD, so bound to the whole safe-integer range, never guard.range.uint31.
|
|
1038
|
+
function msCertificateTemplate(buf) {
|
|
1039
|
+
var C = ns.prefix + "/bad-ms-certificate-template";
|
|
1040
|
+
var kids = seqChildren(buf, C, "CertificateTemplate");
|
|
1041
|
+
if (!kids.length || kids.length > 3) throw ns.E(C, "CertificateTemplateOID must be a SEQUENCE of a templateID and up to two version INTEGERs");
|
|
1042
|
+
if (kids[0].tagClass !== "universal" || kids[0].tagNumber !== _T.OBJECT_IDENTIFIER) throw ns.E(C, "CertificateTemplateOID templateID must be an OBJECT IDENTIFIER");
|
|
1043
|
+
var id;
|
|
1044
|
+
try { id = asn1.read.oid(kids[0]); } catch (e) { throw ns.E(C, "CertificateTemplateOID templateID must be an OBJECT IDENTIFIER", e); }
|
|
1045
|
+
function ver(i, what) {
|
|
1046
|
+
if (!kids[i]) return null;
|
|
1047
|
+
if (kids[i].tagClass !== "universal" || kids[i].tagNumber !== _T.INTEGER) throw ns.E(C, what + " must be an INTEGER");
|
|
1048
|
+
return guard.range.int(readInt(kids[i], C, what), 0n, 4294967295n, ns.E, C, what);
|
|
1049
|
+
}
|
|
1050
|
+
return { templateID: id, name: ns.oid.name(id) || null, templateMajorVersion: ver(1, "templateMajorVersion"), templateMinorVersion: ver(2, "templateMinorVersion") };
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
// [MS-CRTD] szOID-ENROLL_CERTTYPE_EXTENSION -- the legacy v1 template name as a BARE BMPString.
|
|
1054
|
+
// asn1.read.string accepts any universal string tag, so the explicit BMP_STRING assert is the guard.
|
|
1055
|
+
function msEnrollCertType(buf) {
|
|
1056
|
+
var C = ns.prefix + "/bad-ms-enroll-cert-type";
|
|
1057
|
+
var n = decodeTop(buf, C, "EnrollCertType");
|
|
1058
|
+
if (n.tagClass !== "universal" || n.tagNumber !== _T.BMP_STRING) throw ns.E(C, "the enroll cert-type name must be a BMPString");
|
|
1059
|
+
try { return asn1.read.string(n); } catch (e) { throw ns.E(C, "the enroll cert-type name must be a well-formed BMPString", e); }
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
// [MS-WCCE] szOID-CERTSRV_CA_VERSION -- INTEGER (0..2^32-1) = (caKeyIndex << 16) | certIndex.
|
|
1063
|
+
function msCaVersion(buf) {
|
|
1064
|
+
var C = ns.prefix + "/bad-ms-ca-version";
|
|
1065
|
+
var n = decodeTop(buf, C, "CACertVersion");
|
|
1066
|
+
if (n.tagClass !== "universal" || n.tagNumber !== _T.INTEGER) throw ns.E(C, "CACertVersion must be an INTEGER");
|
|
1067
|
+
var v = guard.range.int(readInt(n, C, "CACertVersion"), 0n, 4294967295n, ns.E, C, "CACertVersion (DWORD)");
|
|
1068
|
+
return { caVersion: v, caKeyIndex: v >>> 16, certIndex: v & 0xffff };
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
// [MS-WCCE] szOID-CERTSRV_PREVIOUS_CERT_HASH -- the SHA-1 thumbprint of the prior CA certificate.
|
|
1072
|
+
// AD CS stamps the Windows certificate THUMBPRINT here, which Windows computes with SHA-1 regardless
|
|
1073
|
+
// of the certificate's signature algorithm, so the OCTET STRING is exactly 20 octets. An empty or
|
|
1074
|
+
// other-length value is malformed renewal metadata and fails closed.
|
|
1075
|
+
function msPreviousCertHash(buf) {
|
|
1076
|
+
var C = ns.prefix + "/bad-ms-previous-cert-hash";
|
|
1077
|
+
var n = decodeTop(buf, C, "CAPrevCertHash");
|
|
1078
|
+
var hash;
|
|
1079
|
+
try { hash = Buffer.concat([asn1.read.octetString(n)]); }
|
|
1080
|
+
catch (e) { throw ns.E(C, "CAPrevCertHash must be an OCTET STRING", e); }
|
|
1081
|
+
if (hash.length !== 20) throw ns.E(C, "CAPrevCertHash must be a 20-octet SHA-1 certificate thumbprint");
|
|
1082
|
+
return hash;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1034
1085
|
var byOid = {};
|
|
1035
1086
|
byOid[O("qcStatements")] = qcStatements;
|
|
1036
1087
|
byOid[O("basicConstraints")] = basicConstraints;
|
|
@@ -1049,6 +1100,11 @@ function certExtensionDecoders(ns) {
|
|
|
1049
1100
|
byOid[O("precertificatePoison")] = precertPoison;
|
|
1050
1101
|
byOid[O("cRLDistributionPoints")] = crlDistributionPoints;
|
|
1051
1102
|
byOid[O("freshestCRL")] = crlDistributionPoints;
|
|
1103
|
+
byOid[O("msCertificateTemplate")] = msCertificateTemplate;
|
|
1104
|
+
byOid[O("msEnrollCertType")] = msEnrollCertType;
|
|
1105
|
+
byOid[O("msCaVersion")] = msCaVersion;
|
|
1106
|
+
byOid[O("msPreviousCertHash")] = msPreviousCertHash;
|
|
1107
|
+
byOid[O("msApplicationPolicies")] = certificatePolicies; // [MS-WCCE] = RFC 5280 certificatePolicies, reused not re-implemented
|
|
1052
1108
|
return { byOid: byOid };
|
|
1053
1109
|
}
|
|
1054
1110
|
|
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:c1caa29b-a81a-443d-9296-76988e159993",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-07-
|
|
8
|
+
"timestamp": "2026-07-16T23:57:14.646Z",
|
|
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.2.
|
|
22
|
+
"bom-ref": "@blamejs/pki@0.2.32",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "pki",
|
|
25
|
-
"version": "0.2.
|
|
25
|
+
"version": "0.2.32",
|
|
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.2.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/pki@0.2.32",
|
|
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.2.
|
|
57
|
+
"ref": "@blamejs/pki@0.2.32",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|