@blamejs/pki 0.8.50 → 0.8.52
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 +37 -0
- package/README.md +4 -4
- package/index.js +2 -1
- package/lib/acme.js +33 -13
- package/lib/cmp-build.js +9 -3
- package/lib/cms-sign.js +254 -0
- package/lib/cms-verify.js +456 -8
- package/lib/constants.js +18 -2
- package/lib/est.js +31 -14
- package/lib/guard-intrinsic.js +4 -0
- package/lib/guard-time.js +98 -0
- package/lib/http-digest.js +7 -2
- package/lib/inspect.js +3 -2
- package/lib/lint.js +105 -2
- package/lib/path-validate.js +89 -8
- package/lib/pki-build.js +40 -0
- package/lib/revocation-fetch.js +11 -5
- package/lib/scep.js +26 -12
- package/lib/schema-all.js +1 -1
- package/lib/schema-smime.js +215 -5
- package/lib/tsp-sign.js +58 -95
- package/lib/x509-sign.js +22 -2
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/tsp-sign.js
CHANGED
|
@@ -25,7 +25,6 @@ var smime = require("./schema-smime");
|
|
|
25
25
|
var schemaTsp = require("./schema-tsp");
|
|
26
26
|
var guard = require("./guard-all");
|
|
27
27
|
var intrinsic = require("./guard-intrinsic");
|
|
28
|
-
var _charCodeAt = intrinsic.uncurry(String.prototype.charCodeAt);
|
|
29
28
|
var _compare = intrinsic.compare;
|
|
30
29
|
var _pop = intrinsic.pop;
|
|
31
30
|
var _reverse = intrinsic.reverse;
|
|
@@ -44,10 +43,6 @@ var _EXT_DECODERS = pkix.certExtensionDecoders(_NS).byOid;
|
|
|
44
43
|
var b = asn1.build;
|
|
45
44
|
function _err(code, message, cause) { return new TspError(code, message, cause); }
|
|
46
45
|
|
|
47
|
-
function _hasNonZeroDigit(s) {
|
|
48
|
-
for (var i = 0; i < s.length; i++) { var c = _charCodeAt(s, i); if (c >= 49 && c <= 57) return true; }
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
46
|
function O(name) { return oid.byName(name); }
|
|
52
47
|
|
|
53
48
|
var _b = pkiBuild.makeBuilder({
|
|
@@ -67,9 +62,15 @@ function _moreEstablished(candidate, current) {
|
|
|
67
62
|
return _rankRevocation(candidate) > _rankRevocation(current);
|
|
68
63
|
}
|
|
69
64
|
|
|
65
|
+
/** @internal The message imprint's algorithm identifier, emitted with the parameters field ABSENT.
|
|
66
|
+
* RFC 5754 sec. 2: "Implementations MUST generate SHA2 AlgorithmIdentifiers with absent
|
|
67
|
+
* parameters", and it is a SHA-2 digest here because that is the whole set this verb signs under.
|
|
68
|
+
* Both forms are still read: a request or token from elsewhere carrying NULL parameters verifies,
|
|
69
|
+
* and nothing compares the identifier's bytes, since an imprint is matched by the algorithm it
|
|
70
|
+
* names and the digest it carries. */
|
|
70
71
|
function _hashAlgId(name) {
|
|
71
72
|
if (!NODE_DIGEST[guard.text.keyOf(name)]) throw _err("tsp/unsupported-algorithm", "unsupported hash algorithm " + guard.text.showValue(name));
|
|
72
|
-
return b.sequence([b.oid(O(name))
|
|
73
|
+
return b.sequence([b.oid(O(name))]);
|
|
73
74
|
}
|
|
74
75
|
function _policy(p) {
|
|
75
76
|
if (typeof p !== "string") throw _err("tsp/bad-input", "the timestamp policy must be an OID name or dotted string");
|
|
@@ -88,12 +89,12 @@ function _certDer(c) {
|
|
|
88
89
|
return der;
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
/** @internal The sec. 2.4.2 binding, encoded by the one builder that owns the ESS domain. A second
|
|
93
|
+
* encoder here would be a second answer to "which bytes bind this certificate", and the two can
|
|
94
|
+
* drift: the SHA-384 and SHA-512 algorithm identifiers are generated with the parameters field
|
|
95
|
+
* absent (RFC 5754 sec. 2), and the SHA-256 field omitted as the RFC 5035 sec. 4 DEFAULT. */
|
|
91
96
|
function _signingCertV2(certDer, hashName) {
|
|
92
|
-
|
|
93
|
-
var essCertId = hashName === "sha256"
|
|
94
|
-
? b.sequence([b.octetString(certHash)])
|
|
95
|
-
: b.sequence([_hashAlgId(hashName), b.octetString(certHash)]);
|
|
96
|
-
return b.sequence([b.sequence([essCertId])]);
|
|
97
|
+
return smime.buildSigningCertificateV2(certDer, { hashAlgorithm: hashName });
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
/**
|
|
@@ -432,17 +433,21 @@ function response(token, opts) {
|
|
|
432
433
|
function parseResponse(input) { return schemaTsp.parse(input); }
|
|
433
434
|
|
|
434
435
|
|
|
435
|
-
var _VERIFY_DIGEST =
|
|
436
|
+
var _VERIFY_DIGEST = constants.NAMES.TIMESTAMP_IMPRINT_DIGESTS;
|
|
436
437
|
var _VERIFY_DIGEST_LEN = constants.NAMES.DIGEST_OCTETS;
|
|
437
|
-
var _BIND_DIGEST = intrinsic.assign(intrinsic.create(null), { sha256: "sha256", sha384: "sha384", sha512: "sha512" });
|
|
438
438
|
/** @internal The digests admitted for an imprint that are not collision resistant, so a token under one
|
|
439
439
|
* binds nothing an attacker with a collision cannot move. They verify only under `allowWeakDigests`. */
|
|
440
|
-
var _WEAK_IMPRINT_DIGEST =
|
|
440
|
+
var _WEAK_IMPRINT_DIGEST = constants.NAMES.WEAK_DIGESTS;
|
|
441
441
|
|
|
442
442
|
function _imprintMatches(mi, data, allowWeakDigests) {
|
|
443
443
|
var name = mi.hashAlgorithm && mi.hashAlgorithm.name;
|
|
444
444
|
var nodeAlg = (name && intrinsic.hasOwn(_VERIFY_DIGEST, name)) ? _VERIFY_DIGEST[name] : null;
|
|
445
445
|
if (!nodeAlg) return "tsp/unsupported-algorithm";
|
|
446
|
+
/** @internal The identifier is held to its own encoding as well as to its name. A digest
|
|
447
|
+
* AlgorithmIdentifier carries absent or DER NULL parameters (RFC 5754 clause 2), and the ANY
|
|
448
|
+
* field reaches here unvalidated from the generic PKIX decoder, so an imprint naming sha256
|
|
449
|
+
* beside arbitrary bytes would otherwise be hashed as a well-formed one. */
|
|
450
|
+
if (!guard.der.paramsAbsentOrNull(mi.hashAlgorithm.parameters)) return "tsp/unsupported-algorithm";
|
|
446
451
|
/** @internal The imprint is the ONLY thing binding a token to the data it timestamps, so the digest
|
|
447
452
|
* that computes it carries the whole binding and a collision in it substitutes the data under a
|
|
448
453
|
* genuine token. `allowWeakDigests` used to reach only the token's own signature digest, through
|
|
@@ -452,7 +457,11 @@ function _imprintMatches(mi, data, allowWeakDigests) {
|
|
|
452
457
|
* already does with a signature digest, and the opt-in is the same option an archived token needs. */
|
|
453
458
|
if (!allowWeakDigests && intrinsic.hasOwn(_WEAK_IMPRINT_DIGEST, name)) return "tsp/weak-digest";
|
|
454
459
|
var wantLen = _VERIFY_DIGEST_LEN[name];
|
|
455
|
-
|
|
460
|
+
/** @internal An imprint whose length is not the output length of the algorithm it names cannot be
|
|
461
|
+
* a digest under that algorithm, which is a different fault from a digest that covers other
|
|
462
|
+
* bytes, and it gets a code of its own: the first says the token is malformed, the second that it
|
|
463
|
+
* is well formed and stamps something else (RFC 3161 sec. 2.4.2). */
|
|
464
|
+
if (mi.hashedMessage.length !== wantLen) return "tsp/imprint-length";
|
|
456
465
|
var actual;
|
|
457
466
|
if (guard.bytes.isByteSource(data)) {
|
|
458
467
|
var dataBytes = guard.bytes.source(data, TspError, "tsp/bad-input", "data");
|
|
@@ -468,104 +477,57 @@ function _imprintMatches(mi, data, allowWeakDigests) {
|
|
|
468
477
|
return _compare(actual, _bufferFrom(mi.hashedMessage)) === 0 ? true : "tsp/imprint-mismatch";
|
|
469
478
|
}
|
|
470
479
|
|
|
471
|
-
/** @internal
|
|
472
|
-
*
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
*
|
|
477
|
-
* ABSENT IS NOT THE SAME AS UNRECOGNIZED: a v1 ESSCertID omits the field, so absent carries the type's
|
|
478
|
-
* default of SHA-1; an ESSCertIDv2 naming an OID this build does not know carries an algorithm that
|
|
479
|
-
* genuinely cannot be computed, and that one is `tsp/unsupported-algorithm`.
|
|
480
|
-
* Returns a refusal code, or the ESSCertID with the digest resolved. SHA-1 resolves rather than
|
|
481
|
-
* refusing, because whether a weak binding is a refusal depends on what the caller is doing with it:
|
|
482
|
-
* the attribute the verdict rests on is held to it, and an attribute read only for agreement is not. */
|
|
483
|
-
function _readBinding(attr) {
|
|
484
|
-
var decoded;
|
|
485
|
-
try { decoded = smime.decodeAttribute(attr); }
|
|
486
|
-
catch (_e) { return "tsp/bad-signing-certificate"; }
|
|
487
|
-
var essCert = decoded.certs && decoded.certs[0];
|
|
488
|
-
if (!essCert) return "tsp/bad-signing-certificate";
|
|
489
|
-
var name = essCert.hashAlgorithm == null ? "sha1" : essCert.hashAlgorithm.name;
|
|
490
|
-
if (name === "sha1") return { essCert: essCert, nodeDigest: "sha1", weak: true };
|
|
491
|
-
if (!name || !intrinsic.hasOwn(_BIND_DIGEST, name)) return "tsp/unsupported-algorithm";
|
|
492
|
-
return { essCert: essCert, nodeDigest: _BIND_DIGEST[name], weak: false };
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
/** @internal Whether one ESSCertID names the certificate that signed the token, by every claim it
|
|
496
|
-
* carries: the hash under its own digest, and the issuer and serial where it states them. Returns
|
|
497
|
-
* true or the refusal code. An ESSCertID states the signer in two independent ways and both are
|
|
498
|
-
* compared, because a hash that agrees beside an issuer and serial that name another certificate is
|
|
499
|
-
* the same contradiction as two attributes disagreeing. Certificate identifiers after the first are
|
|
500
|
-
* not read: RFC 2634 sec. 5.4 makes the first the signing certificate and leaves the rest as the
|
|
501
|
-
* chain, so they say nothing about the signer. */
|
|
502
|
-
function _bindingNamesCert(read, tsaCertDer) {
|
|
503
|
-
/** @internal Through the captured digest: this comparison IS the binding between a token and the
|
|
504
|
-
* certificate its signing-certificate attribute names, so what the digest covers is not the
|
|
505
|
-
* caller's to choose. */
|
|
506
|
-
if (_compare(guard.crypto.digest(read.nodeDigest, tsaCertDer),
|
|
507
|
-
_bufferFrom(read.essCert.certHash)) !== 0) return "tsp/cert-binding-mismatch";
|
|
508
|
-
var issuerSerial = read.essCert.issuerSerial;
|
|
509
|
-
if (!issuerSerial) return true;
|
|
510
|
-
var signerCert;
|
|
511
|
-
try { signerCert = pkiX509.parse(tsaCertDer); }
|
|
512
|
-
catch (_e) { return "tsp/bad-signing-certificate"; }
|
|
513
|
-
if (issuerSerial.serialNumber !== signerCert.serialNumber) return "tsp/cert-binding-mismatch";
|
|
514
|
-
var names = issuerSerial.issuer.names || [];
|
|
515
|
-
var gn = null;
|
|
516
|
-
try { if (names.length === 1) gn = schemaTsp.decodeGeneralName(names[0].bytes); }
|
|
517
|
-
catch (_e2) { return "tsp/cert-binding-mismatch"; }
|
|
518
|
-
if (!gn || gn.tagNumber !== 4 || !gn.value || !guard.name.dnEqual(gn.value.rdns, signerCert.issuer.rdns, _err, "tsp/cert-binding-mismatch", "the ESSCertID issuer")) {
|
|
519
|
-
return "tsp/cert-binding-mismatch";
|
|
520
|
-
}
|
|
521
|
-
return true;
|
|
522
|
-
}
|
|
480
|
+
/** @internal An ESSCertID v1 carries NO hashAlgorithm field: it is SHA-1 by definition (RFC 2634
|
|
481
|
+
* sec. 5.4.1), and EN 319 122-1 clause 5.2.2.2 says the v1 attribute "shall be used if the SHA-1 hash
|
|
482
|
+
* algorithm is used", so these tokens exist. The reader therefore reports SHA-1 as WEAK rather than as
|
|
483
|
+
* unsupported, which is a different refusal: the algorithm is known and the binding is deliberately
|
|
484
|
+
* weak, where an ESSCertIDv2 naming an OID this build does not know carries one that genuinely cannot
|
|
485
|
+
* be computed. Which of the two a caller refuses on is the caller's policy, applied below. */
|
|
523
486
|
|
|
524
487
|
function _checkCertBinding(signerInfo, tsaCertDer) {
|
|
525
|
-
var
|
|
526
|
-
|
|
527
|
-
for (var i = 0; i < attrs.length; i++) {
|
|
528
|
-
if (attrs[i].type === O("signingCertificateV2") || attrs[i].type === O("signingCertificate")) {
|
|
529
|
-
intrinsic.push(binding, attrs[i]);
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
if (!binding.length) return "tsp/missing-signing-certificate";
|
|
488
|
+
var facts = smime.certBindingFacts((signerInfo && signerInfo.signedAttrs) || [], tsaCertDer);
|
|
489
|
+
if (!facts.present) return "tsp/missing-signing-certificate";
|
|
533
490
|
/** @internal A v2 binding supersedes a v1 one (RFC 5035), and that is why the verdict rests on the v2
|
|
534
491
|
* where there is one. But the v1 attribute does not stop existing: a token carrying both used to be
|
|
535
492
|
* checked against the v2 alone, so one naming the real signer in v2 and a DIFFERENT certificate in v1
|
|
536
493
|
* verified, and a legacy verifier reading only v1 resolves a certificate this one never checked. Both
|
|
537
494
|
* sit in signedAttrs, so the TSA signed the contradiction. One structure making two incompatible
|
|
538
495
|
* claims about one fact is refused rather than resolved in favor of whichever attribute a reader
|
|
539
|
-
* prefers.
|
|
540
|
-
*
|
|
541
|
-
*
|
|
542
|
-
* and the producer of a hostile token chooses it: a scan that stopped at the v2 caught the
|
|
543
|
-
* contradiction in one ordering and missed it in the other, and an ordering-dependent check is no
|
|
544
|
-
* check. The same applies to a repeated instance of either type, which `pki.cms.verify` refuses
|
|
545
|
-
* before this runs and which is not relied on here.
|
|
496
|
+
* prefers. Which attribute is `chosen` and which is `superseded` is decided over EVERY binding
|
|
497
|
+
* attribute rather than the first of each type, because signedAttrs is a DER SET OF and a hostile
|
|
498
|
+
* producer picks the order through the encodings.
|
|
546
499
|
* THE SHA-1 ON A SUPERSEDED ATTRIBUTE PINS NOTHING. It detects a disagreement, while the binding the
|
|
547
500
|
* verdict rests on is the v2 one. A collision would let a disagreeing v1 pass for an agreeing one,
|
|
548
501
|
* which costs an attacker the refusal and gains them nothing: the certificate the token is held to is
|
|
549
502
|
* the one v2 names, under its own digest. */
|
|
550
|
-
var
|
|
551
|
-
|
|
552
|
-
if (binding[j].type === O("signingCertificateV2")) { chosen = j; break; }
|
|
553
|
-
}
|
|
554
|
-
for (var k = 0; k < binding.length; k++) {
|
|
555
|
-
if (k === chosen) continue;
|
|
556
|
-
var alt = _readBinding(binding[k]);
|
|
557
|
-
if (typeof alt === "string") return alt;
|
|
558
|
-
var altCode = _bindingNamesCert(alt, tsaCertDer);
|
|
503
|
+
for (var k = 0; k < facts.superseded.length; k++) {
|
|
504
|
+
var altCode = _bindingClaimCode(facts.superseded[k]);
|
|
559
505
|
if (altCode !== true) return altCode;
|
|
560
506
|
}
|
|
561
|
-
var read =
|
|
562
|
-
if (
|
|
507
|
+
var read = facts.chosen;
|
|
508
|
+
if (!read.readable) return "tsp/bad-signing-certificate";
|
|
509
|
+
if (!read.supported) return "tsp/unsupported-algorithm";
|
|
563
510
|
/** @internal The refusal of a weak binding stands whatever `allowWeakDigests` says, because a binding
|
|
564
511
|
* is not the archived-signature case the option exists for. Whether it should follow the imprint and
|
|
565
512
|
* become an opt-in is a posture question, and the refusal was pinned deliberately, so it is left as
|
|
566
513
|
* it was. */
|
|
567
514
|
if (read.weak) return "tsp/weak-digest";
|
|
568
|
-
return
|
|
515
|
+
return _bindingClaimCode(read);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/** @internal The refusal one binding attribute's claims earn, in the order the claims are decided:
|
|
519
|
+
* an attribute that does not decode, then a digest this build does not bind with, then the hash,
|
|
520
|
+
* then the certificate the issuer and serial would be read off, then those two. The hash is
|
|
521
|
+
* compared before the certificate is parsed, because a hash that disagrees is a mismatch whatever
|
|
522
|
+
* the certificate turns out to be. The weak-digest refusal is the caller's, since it applies to the
|
|
523
|
+
* attribute the verdict rests on and not to one read only for agreement. */
|
|
524
|
+
function _bindingClaimCode(e) {
|
|
525
|
+
if (!e.readable) return "tsp/bad-signing-certificate";
|
|
526
|
+
if (!e.supported) return "tsp/unsupported-algorithm";
|
|
527
|
+
if (e.matches !== true) return "tsp/cert-binding-mismatch";
|
|
528
|
+
if (e.certUnreadable) return "tsp/bad-signing-certificate";
|
|
529
|
+
if (e.issuerSerialMatches === false) return "tsp/cert-binding-mismatch";
|
|
530
|
+
return true;
|
|
569
531
|
}
|
|
570
532
|
|
|
571
533
|
function _checkTsaCertUsage(tsaCertDer) {
|
|
@@ -755,7 +717,8 @@ async function verify(token, data, opts) {
|
|
|
755
717
|
if (opts.trustAnchors) {
|
|
756
718
|
var pathRes = null;
|
|
757
719
|
var floorT = tst.genTime;
|
|
758
|
-
var
|
|
720
|
+
var ceilAt = guard.time.ceilInstantOf(floorT, tst.genTimeFraction);
|
|
721
|
+
var ceilT = ceilAt === guard.time.instantOf(floorT) ? floorT : new Date(ceilAt);
|
|
759
722
|
try {
|
|
760
723
|
var pool = (parsed.certificates || []).filter(function (c) { return c.tagClass === "universal"; }).map(function (c) { return pkiX509.parse(c.bytes); });
|
|
761
724
|
(opts.certs || []).forEach(function (c) { guard.list.append(pool, pkiX509.parse(c)); });
|
package/lib/x509-sign.js
CHANGED
|
@@ -71,6 +71,7 @@ var KNOWN_EXT_KEYS = intrinsic.assign(intrinsic.create(null), {
|
|
|
71
71
|
authorityInfoAccess: 1, cRLDistributionPoints: 1, freshestCRL: 1,
|
|
72
72
|
policyConstraints: 1, inhibitAnyPolicy: 1, policyMappings: 1, policyMappingsCritical: 1,
|
|
73
73
|
issuerAltName: 1, qcStatements: 1, qcStatementsCritical: 1,
|
|
74
|
+
tlsFeature: 1, tlsFeatureCritical: 1,
|
|
74
75
|
precertificatePoison: 1, signedCertificateTimestampList: 1,
|
|
75
76
|
msCertificateTemplate: 1, msEnrollCertType: 1, msCaVersion: 1, msPreviousCertHash: 1,
|
|
76
77
|
msApplicationPolicies: 1,
|
|
@@ -279,6 +280,9 @@ function _buildExtensions(extSpec, ctx) {
|
|
|
279
280
|
* unrecognized critical extension; the default is the form that validates and the knob reaches
|
|
280
281
|
* the other, as policyMappings and certificatePolicies do. */
|
|
281
282
|
if (extSpec.qcStatements != null) guard.list.append(out, _ext(O("qcStatements"), !!extSpec.qcStatementsCritical, _extQcStatements(extSpec.qcStatements)));
|
|
283
|
+
/** @internal RFC 7633 sec. 4: SHOULD NOT be critical, and the clause names the case where critical
|
|
284
|
+
* is the desired behavior, so the knob exists and the default is the compatible form. */
|
|
285
|
+
if (extSpec.tlsFeature != null) guard.list.append(out, _ext(O("tlsFeature"), !!extSpec.tlsFeatureCritical, _b.extTlsFeature(extSpec.tlsFeature)));
|
|
282
286
|
if (extSpec.nameConstraints != null) {
|
|
283
287
|
if (!caTrue) throw _err("x509/bad-input", "nameConstraints appears only in a CA certificate, so it requires basicConstraints cA=TRUE (RFC 5280 sec. 4.2.1.10)");
|
|
284
288
|
guard.list.append(out, _ext(O("nameConstraints"), true, _extNameConstraints(extSpec.nameConstraints)));
|
|
@@ -628,6 +632,18 @@ function _hasCriticalSan(extSpec) {
|
|
|
628
632
|
* know an unknown syntax. `pki.path.validate` does not process this extension, so it is emitted
|
|
629
633
|
* non-critical unless `qcStatementsCritical` is set.
|
|
630
634
|
*
|
|
635
|
+
* `extensions.tlsFeature` builds the RFC 7633 TLS Feature extension, the "must-staple" declaration,
|
|
636
|
+
* from a list of TLS ExtensionType values. Each is a number, a bigint, or one of the registry names
|
|
637
|
+
* this build knows, `status_request` and `status_request_v2`. The values come from the IANA TLS
|
|
638
|
+
* Extensions registry that RFC 7633 sec. 4.1 points at, and the type states no range, so a value
|
|
639
|
+
* outside that registry's width encodes and `pki.lint.certificate(der, { profile: "rfc7633" })`
|
|
640
|
+
* reports it rather than the encoder refusing it; the same holds for a repeated value, which the
|
|
641
|
+
* syntax permits. An EMPTY list is refused, because the extension it would emit advertises nothing.
|
|
642
|
+
* Emitted non-critical unless `tlsFeatureCritical` is set: sec. 4 says it SHOULD NOT be critical and
|
|
643
|
+
* names the case where critical is the caller's intent. `pki.path.validate` enforces sec. 4.2.2 over
|
|
644
|
+
* a built path, so a certificate issued under a CA that advertises features must offer the same set
|
|
645
|
+
* or a superset.
|
|
646
|
+
*
|
|
631
647
|
* `extensions.subjectInfoAccess` takes the same `{ accessMethod, accessLocation }` list
|
|
632
648
|
* `authorityInfoAccess` takes, since RFC 5280 sec. 4.2.2.2 gives it sec. 4.2.2.1's syntax; the two
|
|
633
649
|
* access methods that section defines are the registered names `id-ad-caRepository` and
|
|
@@ -910,6 +926,10 @@ var EXTENSION_ROWS = [
|
|
|
910
926
|
["cRLDistributionPoints", "cRLDistributionPoints", { fixed: false, cite: "RFC 5280 sec. 4.2.1.13" }, function (v) { return _extCrlDp(v, "cRLDistributionPoints"); }],
|
|
911
927
|
["freshestCRL", "freshestCRL", { fixed: false, cite: "RFC 5280 sec. 4.2.1.15" }, function (v) { return _extCrlDp(v, "freshestCRL"); }],
|
|
912
928
|
["qcStatements", "qcStatements", { knob: true, dflt: false }, function (v) { return _extQcStatements(v); }],
|
|
929
|
+
/** @internal RFC 7633 sec. 4 reads "SHOULD NOT be marked critical" and then names the case where
|
|
930
|
+
* the critical form is what the caller wants, so this takes a knob defaulting to the compatible
|
|
931
|
+
* form rather than refusing one: `fixed: false` would promote that SHOULD NOT into a refusal. */
|
|
932
|
+
["tlsFeature", "tlsFeature", { knob: true, dflt: false }, function (v) { return _b.extTlsFeature(v); }],
|
|
913
933
|
["subjectDirectoryAttributes", "subjectDirectoryAttributes", { fixed: false, cite: "RFC 5280 sec. 4.2.1.8" }, function (v) { return _b.extSubjectDirectoryAttributes(v); }],
|
|
914
934
|
["msCertificateTemplate", "msCertificateTemplate", { fixed: false, cite: "the toolkit issues the form its readers accept" }, function (v) { return _b.extMsCertificateTemplate(v); }],
|
|
915
935
|
["msEnrollCertType", "msEnrollCertType", { fixed: false, cite: "the toolkit issues the form its readers accept" }, function (v) { return _b.extMsEnrollCertType(v); }],
|
|
@@ -971,8 +991,8 @@ function _extensionCritical(row, opts) {
|
|
|
971
991
|
* (the key identifiers, the constraint and policy-constraint extensions, the access and
|
|
972
992
|
* distribution extensions), or the toolkit issues one form only, `opts.critical` may only restate
|
|
973
993
|
* that value. `keyUsage` (default critical), `extendedKeyUsage`, `certificatePolicies`,
|
|
974
|
-
* `policyMappings`, `qcStatements` (default non-critical), and `subjectAltName`
|
|
975
|
-
* when the subject is empty, which the caller knows) take `opts.critical`; `basicConstraints`
|
|
994
|
+
* `policyMappings`, `qcStatements` and `tlsFeature` (default non-critical), and `subjectAltName`
|
|
995
|
+
* (critical exactly when the subject is empty, which the caller knows) take `opts.critical`; `basicConstraints`
|
|
976
996
|
* carries `critical` inside its value. An unregistered OID takes `opts.critical` as stated.
|
|
977
997
|
*
|
|
978
998
|
* @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:4d4aadb5-0f2b-4564-b30c-638343b637e8",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-10-
|
|
8
|
+
"timestamp": "2026-10-05T18:37:07.808Z",
|
|
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.8.
|
|
22
|
+
"bom-ref": "@blamejs/pki@0.8.52",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "pki",
|
|
25
|
-
"version": "0.8.
|
|
25
|
+
"version": "0.8.52",
|
|
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.8.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/pki@0.8.52",
|
|
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.8.
|
|
57
|
+
"ref": "@blamejs/pki@0.8.52",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|