@blamejs/pki 0.7.9 → 0.7.10
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 +10 -0
- package/lib/ocsp.js +25 -2
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,16 @@ 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.7.10 — 2026-09-10
|
|
8
|
+
|
|
9
|
+
An OCSP response is no longer signed with a status window that runs backwards.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- pki.ocsp.sign raises ocsp/bad-input for a response entry whose thisUpdate is after its nextUpdate, before anything is signed. RFC 6960 section 4.2.2.1 makes the pair a validity interval corresponding to the {thisUpdate, nextUpdate} interval in CRLs, and pki.crl.sign, pki.x509.sign, pki.attrcert.sign and pki.crmf.build each already refuse their own reversed window. Every entry in a batch is measured, not the first alone, and a nextUpdate that came from the default is held to the rule a supplied one is.
|
|
14
|
+
- An entry whose thisUpdate equals its nextUpdate still signs, as the equivalent CRL does: a zero-length window is not forbidden. A response entry that names no certificate still reports that first. The times are compared as given, so a thisUpdate later than its nextUpdate is refused even where the two fall inside one second and would encode to the same GeneralizedTime, which is how pki.x509.sign, pki.crl.sign and pki.crmf.build read their own.
|
|
15
|
+
- A pre-produced response still signs. RFC 6960 section 2.5 lets a responder sign a response ahead of the window it certifies, where producedAt is when the response was signed and thisUpdate is when the status was known correct, so a producedAt earlier than thisUpdate is conforming and is left alone.
|
|
16
|
+
|
|
7
17
|
## v0.7.9 — 2026-09-10
|
|
8
18
|
|
|
9
19
|
Certificate revocation lists can now be linted against the RFC 5280 profile.
|
package/lib/ocsp.js
CHANGED
|
@@ -326,10 +326,33 @@ function _buildSingleResponse(r, opts) {
|
|
|
326
326
|
if (r.certID != null) certIdP = Promise.resolve(b.raw(guard.bytes.view(r.certID, OcspError, "ocsp/bad-input", "a response entry's certID")));
|
|
327
327
|
else if (r.cert != null && r.issuer != null) certIdP = _buildCertID(_certOf(r.cert, "a response certificate"), _certOf(r.issuer, "a response issuer"), r.hashAlgorithm || "sha1");
|
|
328
328
|
else return Promise.reject(_err("ocsp/bad-input", "each response entry needs { certID } or { cert, issuer }"));
|
|
329
|
+
/** @internal Every per-entry refusal stays INSIDE this chain. These entries are built through a
|
|
330
|
+
* map into Promise.all, so a synchronous throw here would abort the map before Promise.all
|
|
331
|
+
* attached handlers, and an earlier entry's rejection would be orphaned: the caller catches
|
|
332
|
+
* sign()'s failure and the process still sees an unhandled rejection. */
|
|
329
333
|
return certIdP.then(function (certID) {
|
|
334
|
+
var thisUpdate = _asDate(r.thisUpdate) || new Date();
|
|
335
|
+
var nextUpdate = r.nextUpdate === null ? null : (_asDate(r.nextUpdate) || _defaultNextUpdate());
|
|
336
|
+
/** @internal RFC 6960 sec. 4.2.2.1 makes thisUpdate and nextUpdate a validity interval, and says
|
|
337
|
+
* it corresponds to the {thisUpdate, nextUpdate} interval in CRLs. An interval whose end
|
|
338
|
+
* precedes its start states a status window that closed before it opened, and pki.ocsp.verify
|
|
339
|
+
* reports such a response unknown, so signing one emits what nothing can act on. pki.x509.sign,
|
|
340
|
+
* pki.crl.sign, pki.attrcert.sign and pki.crmf.build each refuse their own reversed window; this
|
|
341
|
+
* is that rule in the one place it was missing. The RESOLVED values are compared rather than the
|
|
342
|
+
* caller's, since a defaulted nextUpdate reaches a relying party the same way a supplied one
|
|
343
|
+
* does. An equal pair is left alone, as it is for a CRL: a zero-length window is not forbidden.
|
|
344
|
+
*
|
|
345
|
+
* The CALLER's instants are compared, at their full precision, which is what the four sibling
|
|
346
|
+
* verbs do. Two instants inside one second encode to the same whole-second GeneralizedTime, so
|
|
347
|
+
* comparing the encoded values instead would accept a descending pair and quietly emit the
|
|
348
|
+
* zero-length window it truncates to. A caller naming a later thisUpdate than nextUpdate has
|
|
349
|
+
* stated a reversed one whatever the seconds round to, and hears so here. */
|
|
350
|
+
if (nextUpdate !== null && guard.time.instantOf(thisUpdate) > guard.time.instantOf(nextUpdate)) {
|
|
351
|
+
throw _err("ocsp/bad-input", "thisUpdate must not be after nextUpdate (RFC 6960 sec. 4.2.2.1)");
|
|
352
|
+
}
|
|
330
353
|
var statusNode = _certStatusNode(r.status, opts);
|
|
331
|
-
var srChildren = [certID, statusNode, b.generalizedTime(
|
|
332
|
-
if (
|
|
354
|
+
var srChildren = [certID, statusNode, b.generalizedTime(thisUpdate)];
|
|
355
|
+
if (nextUpdate !== null) srChildren.push(b.explicit(0, b.generalizedTime(nextUpdate)));
|
|
333
356
|
if (r.singleExtensions && r.singleExtensions.length) srChildren.push(b.explicit(1, b.sequence(r.singleExtensions)));
|
|
334
357
|
return b.sequence(srChildren);
|
|
335
358
|
});
|
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:34b0c9f8-e610-4b07-817f-7e260dc2355a",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-09-
|
|
8
|
+
"timestamp": "2026-09-10T21:28:40.246Z",
|
|
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.7.
|
|
22
|
+
"bom-ref": "@blamejs/pki@0.7.10",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "pki",
|
|
25
|
-
"version": "0.7.
|
|
25
|
+
"version": "0.7.10",
|
|
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.7.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/pki@0.7.10",
|
|
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.7.
|
|
57
|
+
"ref": "@blamejs/pki@0.7.10",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|