@blamejs/pki 0.7.35 → 0.7.37
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 +26 -0
- package/README.md +2 -2
- package/lib/attrcert-sign.js +184 -33
- package/lib/cmp-verify.js +2 -9
- package/lib/cms-sign.js +3 -0
- package/lib/crl-sign.js +1 -9
- package/lib/csr-sign.js +4 -1
- package/lib/ct.js +10 -1
- package/lib/guard-name.js +10 -1
- package/lib/lint.js +1 -13
- package/lib/ocsp.js +96 -31
- package/lib/pki-build.js +41 -11
- package/lib/schema-attrcert.js +7 -0
- package/lib/schema-ocsp.js +4 -2
- package/lib/x509-sign.js +1 -8
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/cms-sign.js
CHANGED
|
@@ -84,8 +84,11 @@ function _buildSignedAttrs(pairs) {
|
|
|
84
84
|
return { setOf: setOf, wire: wire };
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
var KNOWN_ATTRIBUTE_KEYS = intrinsic.assign(intrinsic.create(null), { type: 1, values: 1 });
|
|
87
88
|
function _resolveAttrPairs(list, what) {
|
|
88
89
|
return intrinsic.map(list || [], function (a) {
|
|
90
|
+
if (!a || typeof a !== "object") throw _err("cms/bad-input", "an attribute must be { type, values }");
|
|
91
|
+
guard.identifier.assertKnownKeys(a, KNOWN_ATTRIBUTE_KEYS, _err, "cms/bad-input", "unknown attribute field (an attribute is { type, values }): ");
|
|
89
92
|
var vals = intrinsic.map(a.values || [], function (v) { return _toBuf(v, what); });
|
|
90
93
|
if (!vals.length) throw _err("cms/bad-input", "a signed attribute must carry at least one value (RFC 5652 -- Attribute values is SET SIZE (1..MAX))");
|
|
91
94
|
return { type: oid.isDottedDecimal(a.type) ? a.type : O(a.type), values: vals };
|
package/lib/crl-sign.js
CHANGED
|
@@ -72,8 +72,6 @@ function _assertExtensionValueDecodes(node, extnId, what) {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
var OID_SKI = O("subjectKeyIdentifier");
|
|
76
|
-
|
|
77
75
|
var CRL_REASON = constants.NAMES.CRL_REASON;
|
|
78
76
|
var REASON_BY_NAME = intrinsic.create(null);
|
|
79
77
|
Object.keys(CRL_REASON).forEach(function (v) { REASON_BY_NAME[CRL_REASON[v]] = Number(v); });
|
|
@@ -146,14 +144,8 @@ function _resolveReason(reason, isDelta) {
|
|
|
146
144
|
return codeNum;
|
|
147
145
|
}
|
|
148
146
|
|
|
149
|
-
function _issuerSkiOf(ctx) {
|
|
150
|
-
if (!ctx.issuerCert) return null;
|
|
151
|
-
var ski = (ctx.issuerCert.extensions || []).filter(function (e) { return e.oid === OID_SKI; })[0];
|
|
152
|
-
if (ski) { try { return asn1.read.octetString(asn1.decode(ski.value)); } catch (_e) { } } // allow:swallow-unverified -- a malformed issuer SKI is read as absent; the authorityKeyIdentifier keyIdentifier is then derived from the issuer public key
|
|
153
|
-
return null;
|
|
154
|
-
}
|
|
155
147
|
function _akiKeyId(val, ctx) {
|
|
156
|
-
var issuerSki =
|
|
148
|
+
var issuerSki = ctx.issuerCert ? _b.skiValueOf(ctx.issuerCert) : null;
|
|
157
149
|
if (guard.bytes.isByteSource(val)) {
|
|
158
150
|
var given = guard.bytes.snapshotSource(val, CrlError, "crl/bad-input", "the authorityKeyIdentifier keyIdentifier");
|
|
159
151
|
/** @internal Sec. 5.2.1 names the CRL signer certificate's subject key identifier as the value,
|
package/lib/csr-sign.js
CHANGED
|
@@ -34,6 +34,7 @@ var KNOWN_SPEC_KEYS = Object.assign(Object.create(null), { subject: 1, subjectPu
|
|
|
34
34
|
* them was accepted and dropped, so asking for PEM and misspelling the option returned DER and
|
|
35
35
|
* reported nothing. */
|
|
36
36
|
var KNOWN_SIGN_OPTS = Object.assign(Object.create(null), { digestAlgorithm: 1, pem: 1, pss: 1 });
|
|
37
|
+
var KNOWN_KEY_WRAPPER_KEYS = Object.assign(Object.create(null), { key: 1 });
|
|
37
38
|
var b = asn1.build;
|
|
38
39
|
function _err(code, message, cause) { return new CsrError(code, message, cause); }
|
|
39
40
|
function _signE(kind, message, cause) { return new CsrError("csr/" + kind, message, cause); }
|
|
@@ -109,7 +110,9 @@ function _sign(spec, key, opts) {
|
|
|
109
110
|
if (!spec || typeof spec !== "object" || Buffer.isBuffer(spec)) throw _err("csr/bad-input", "the certification-request spec must be an object");
|
|
110
111
|
guard.identifier.assertKnownKeys(spec, KNOWN_SPEC_KEYS, _err, "csr/bad-input", "unknown spec field ");
|
|
111
112
|
guard.identifier.assertKnownKeys(opts, KNOWN_SIGN_OPTS, _err, "csr/bad-input", "pki.csr.sign has an unknown option ");
|
|
112
|
-
var
|
|
113
|
+
var wrapped = key && typeof key === "object" && !Buffer.isBuffer(key) && !(key instanceof Uint8Array) && key.type == null && "key" in key;
|
|
114
|
+
if (wrapped) guard.identifier.assertKnownKeys(key, KNOWN_KEY_WRAPPER_KEYS, _err, "csr/bad-input", "unknown field in the { key } wrapper (a signing option belongs in the third argument): ");
|
|
115
|
+
var signingKey = wrapped ? key.key : key;
|
|
113
116
|
if (signingKey == null) throw _err("csr/bad-input", "a signing key (the subject's private key) is required");
|
|
114
117
|
|
|
115
118
|
var subjectSpki = _b.reqDer(spec.subjectPublicKey, "spec.subjectPublicKey (the SPKI DER of the requested key)");
|
package/lib/ct.js
CHANGED
|
@@ -255,12 +255,19 @@ function _u24Bytes(n) {
|
|
|
255
255
|
* var preimage = pki.ct.reconstructSignedData({ entryType: 0, leafCert: der }, sct);
|
|
256
256
|
* // hash `preimage` + verify against the log's public key at the verify layer
|
|
257
257
|
*/
|
|
258
|
+
/** @internal The two log-entry arms read different fields, and a field belonging to the other arm
|
|
259
|
+
* is refused the same way a misspelled one is: a value the arm never reads cannot be in the entry. */
|
|
260
|
+
var _X509_ENTRY_KEYS = intrinsic.assign(intrinsic.create(null), { entryType: 1, leafCert: 1 });
|
|
261
|
+
var _PRECERT_ENTRY_KEYS = intrinsic.assign(intrinsic.create(null), { entryType: 1, tbsCertificate: 1, issuerKeyHash: 1 });
|
|
258
262
|
function reconstructSignedData(entry, sct) {
|
|
259
263
|
entry = entry || {};
|
|
264
|
+
if (typeof entry !== "object") throw new CtError("ct/bad-input", "the log entry must be an object { entryType, ... } (RFC 6962 sec. 3.1)");
|
|
260
265
|
var entryType = entry.entryType;
|
|
261
266
|
if (entryType !== 0 && entryType !== 1) {
|
|
262
267
|
throw new CtError("ct/bad-entry-type", "entryType must be x509_entry(0) or precert_entry(1), got " + guard.text.showValue(entryType) + " (RFC 6962 sec. 3.1)");
|
|
263
268
|
}
|
|
269
|
+
guard.identifier.assertKnownKeys(entry, entryType === 0 ? _X509_ENTRY_KEYS : _PRECERT_ENTRY_KEYS, _ctErr, "ct/bad-input",
|
|
270
|
+
entryType === 0 ? "unknown x509_entry field (accepted: entryType, leafCert): " : "unknown precert_entry field (accepted: entryType, tbsCertificate, issuerKeyHash): ");
|
|
264
271
|
if (!sct || typeof sct.timestamp !== "bigint" || sct.version !== 0) {
|
|
265
272
|
throw new CtError("ct/bad-input", "reconstructSignedData expects a decoded v1 SCT from parseSctList().scts[]");
|
|
266
273
|
}
|
|
@@ -522,8 +529,10 @@ function _logKeyMaterial(logKey) {
|
|
|
522
529
|
* var sct = await pki.ct.signSct({ entryType: 0, leafCert: der }, signerKeyPkcs8);
|
|
523
530
|
* var ext = pki.ct.encodeSctList([sct]);
|
|
524
531
|
*/
|
|
532
|
+
var _SIGN_SCT_OPTS = intrinsic.assign(intrinsic.create(null), { timestamp: 1, extensions: 1, logId: 1 });
|
|
525
533
|
async function signSct(entry, logKey, opts) {
|
|
526
|
-
opts = opts
|
|
534
|
+
opts = guard.identifier.optionsObject(opts, _ctErr, "ct/bad-input", "pki.ct.signSct options");
|
|
535
|
+
guard.identifier.assertKnownKeys(opts, _SIGN_SCT_OPTS, _ctErr, "ct/bad-input", "unknown pki.ct.signSct option (accepted: timestamp, extensions, logId): ");
|
|
527
536
|
var mat = _logKeyMaterial(logKey);
|
|
528
537
|
var alg = _spkiAlg(mat.spki);
|
|
529
538
|
var hashAlg = 4, sigAlg, imp, sign, ecdsaDer = false, coordLen;
|
package/lib/guard-name.js
CHANGED
|
@@ -218,6 +218,15 @@ function _allCharsIn(s, table) {
|
|
|
218
218
|
|
|
219
219
|
function stripTrailingDot(s) { return _charAt(s, s.length - 1) === "." ? _strSlice(s, 0, -1) : s; }
|
|
220
220
|
|
|
221
|
+
/** @internal Whether `s` opens with `scheme` followed by a colon, the scheme compared without
|
|
222
|
+
* regard to ASCII case (RFC 3986 sec. 3.1). `scheme` is given in lower case. */
|
|
223
|
+
// @enforced-by behavioral -- a scheme comparison has no rename-proof code shape; the vectors refusing a location under the wrong scheme are the guard
|
|
224
|
+
function uriSchemeIs(s, scheme) {
|
|
225
|
+
if (typeof s !== "string" || s.length <= scheme.length) return false;
|
|
226
|
+
if (_charCodeAt(s, scheme.length) !== 0x3a) return false;
|
|
227
|
+
return lowerAscii(_strSlice(s, 0, scheme.length)) === scheme;
|
|
228
|
+
}
|
|
229
|
+
|
|
221
230
|
/** @internal A host name of two or more labels that is not an address, which is the form a URI
|
|
222
231
|
* name constraint is compared by (RFC 5280 sec. 4.2.1.10). */
|
|
223
232
|
function isFqdnHost(host) {
|
|
@@ -527,7 +536,7 @@ module.exports = intrinsic.freeze({
|
|
|
527
536
|
assertNoControlBytes: assertNoControlBytes, assertPrintableIa5: assertPrintableIa5,
|
|
528
537
|
dnEqual: dnEqual, rdnEqual: rdnEqual, emailEqual: emailEqual, dpnCorresponds: dpnCorresponds,
|
|
529
538
|
escapeControlBytes: escapeControlBytes, escapeDnValue: escapeDnValue,
|
|
530
|
-
lowerAscii: lowerAscii,
|
|
539
|
+
lowerAscii: lowerAscii, uriSchemeIs: uriSchemeIs,
|
|
531
540
|
stripTrailingDot: stripTrailingDot, isFqdnHost: isFqdnHost, splitMailbox: splitMailbox,
|
|
532
541
|
constraintBaseRefusal: constraintBaseRefusal,
|
|
533
542
|
constraintBaseUnreadable: constraintBaseUnreadable,
|
package/lib/lint.js
CHANGED
|
@@ -749,18 +749,6 @@ function _crlDecodedExtension(crl, name) {
|
|
|
749
749
|
}
|
|
750
750
|
}
|
|
751
751
|
|
|
752
|
-
/** @internal Whether a string opens with the given URI scheme followed by a colon, compared
|
|
753
|
-
* without regard to case by scanning character codes. */
|
|
754
|
-
function _uriSchemeIs(s, scheme) {
|
|
755
|
-
if (typeof s !== "string" || s.length <= scheme.length) return false;
|
|
756
|
-
for (var i = 0; i < scheme.length; i++) {
|
|
757
|
-
var c = s.charCodeAt(i);
|
|
758
|
-
if (c >= 65 && c <= 90) c += 32;
|
|
759
|
-
if (c !== scheme.charCodeAt(i)) return false;
|
|
760
|
-
}
|
|
761
|
-
return s.charCodeAt(scheme.length) === 58;
|
|
762
|
-
}
|
|
763
|
-
|
|
764
752
|
/** @internal The schemes that satisfy the section 5.2.7 recommendation. The secured forms count:
|
|
765
753
|
* warning about an https or ldaps location would report the more protected spelling of the two the
|
|
766
754
|
* clause names. */
|
|
@@ -1201,7 +1189,7 @@ var RFC5280_CRL_RULES = [
|
|
|
1201
1189
|
var reachable = descs.some(function (d) {
|
|
1202
1190
|
var loc = d.accessLocation;
|
|
1203
1191
|
if (!loc || loc.tag !== 6) return false;
|
|
1204
|
-
return AIA_RECOMMENDED_SCHEMES.some(function (s) { return
|
|
1192
|
+
return AIA_RECOMMENDED_SCHEMES.some(function (s) { return guard.name.uriSchemeIs(loc.value, s); });
|
|
1205
1193
|
});
|
|
1206
1194
|
return reachable ? null : true;
|
|
1207
1195
|
},
|
package/lib/ocsp.js
CHANGED
|
@@ -84,11 +84,15 @@ function _toDer(input, what) {
|
|
|
84
84
|
}
|
|
85
85
|
function _keyValue(spkiDer) { return ocspVerify.ocspKeyValue(spkiDer); }
|
|
86
86
|
function _nonceExt(nonceBytes) { return b.sequence([b.oid(OID_OCSP_NONCE), b.octetString(b.octetString(nonceBytes))]); }
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
/** @internal RFC 9654 sec. 2.1 bounds a nonce at 1..128 octets, and adds for the requester: "An OCSP
|
|
88
|
+
* requester that implements the extension in this document MUST use a minimum length of 32
|
|
89
|
+
* octets". A responder echoes what it was sent, so its floor stays at the section's 1. */
|
|
90
|
+
function _assertNonce(nonceBytes, floor) {
|
|
91
|
+
if (!Buffer.isBuffer(nonceBytes) || nonceBytes.length < floor || nonceBytes.length > 128) {
|
|
92
|
+
throw _err("ocsp/bad-input", "a nonce must be a Buffer of " + floor + "..128 octets (RFC 9654 sec. 2.1)");
|
|
90
93
|
}
|
|
91
94
|
}
|
|
95
|
+
var REQUESTER_NONCE_FLOOR = 32, RESPONDER_NONCE_FLOOR = 1;
|
|
92
96
|
function _buildCertID(cert, issuer, hashName) {
|
|
93
97
|
var wc = HASH_WC[guard.text.keyOf(hashName)];
|
|
94
98
|
if (!wc) throw _err("ocsp/bad-input", "unsupported CertID hashAlgorithm " + guard.text.showValue(hashName) + " (sha1 / sha256 / sha384 / sha512)");
|
|
@@ -122,9 +126,12 @@ function _buildCertID(cert, issuer, hashName) {
|
|
|
122
126
|
*
|
|
123
127
|
* @opts
|
|
124
128
|
* hashAlgorithm `"sha1"` (default) / `"sha256"` / `"sha384"` / `"sha512"`; the CertID identity hash.
|
|
125
|
-
* nonce `true` for a fresh 32-octet CSPRNG nonce (RFC 9654), or a caller Buffer
|
|
126
|
-
*
|
|
127
|
-
*
|
|
129
|
+
* nonce `true` for a fresh 32-octet CSPRNG nonce (RFC 9654), or a caller Buffer of 32..128
|
|
130
|
+
* octets (RFC 9654 sec. 2.1: a requester MUST use at least 32).
|
|
131
|
+
* requestorName a Name (DER `BufferSource`, or a parsed Name) placed in the [1] requestorName as a
|
|
132
|
+
* directoryName. With `signer`, the signer certificate's subject is taken when none
|
|
133
|
+
* is stated (RFC 6960 sec. 4.1.2: a requestor that signs SHALL specify its name).
|
|
134
|
+
* signer `{ cert, key }` to sign the request.
|
|
128
135
|
* profile `"lightweight"`: one Request, SHA-1 CertID, nonce-only extensions (RFC 5019).
|
|
129
136
|
* pem emit a PEM `OCSP REQUEST` string instead of DER.
|
|
130
137
|
* @example
|
|
@@ -148,6 +155,8 @@ function buildRequest(query, opts) {
|
|
|
148
155
|
var _BUILD_REQUEST_OPTS = Object.assign(Object.create(null), {
|
|
149
156
|
hashAlgorithm: 1, nonce: 1, pem: 1, profile: 1, requestorName: 1, signer: 1
|
|
150
157
|
});
|
|
158
|
+
var _QUERY_KEYS = Object.assign(Object.create(null), { cert: 1, issuer: 1, singleRequestExtensions: 1 });
|
|
159
|
+
var _REQUEST_SIGNER_KEYS = Object.assign(Object.create(null), { cert: 1, key: 1 });
|
|
151
160
|
|
|
152
161
|
function _buildRequest(query, opts) {
|
|
153
162
|
opts = guard.identifier.optionsObject(opts, _err, "ocsp/bad-input", "pki.ocsp.buildRequest options");
|
|
@@ -159,10 +168,27 @@ function _buildRequest(query, opts) {
|
|
|
159
168
|
var queries = Array.isArray(query) ? pkiBuild.reqDenseArray(query, "queries", _err, "ocsp/bad-input") : [query];
|
|
160
169
|
if (!queries.length) throw _err("ocsp/bad-input", "buildRequest needs at least one { cert, issuer } query");
|
|
161
170
|
if (lightweight && queries.length !== 1) throw _err("ocsp/bad-input", "the lightweight profile permits exactly one Request (RFC 5019 sec. 2.1.1)");
|
|
162
|
-
|
|
171
|
+
var signerCertDer = null, signerCert = null;
|
|
172
|
+
if (opts.signer) {
|
|
173
|
+
guard.identifier.assertKnownKeys(opts.signer, _REQUEST_SIGNER_KEYS, _err, "ocsp/bad-input", "unknown request signer field (the signer is { cert, key }): ");
|
|
174
|
+
signerCertDer = _normCertDer(opts.signer.cert, "the request signer certificate");
|
|
175
|
+
signerCert = _certOf(signerCertDer, "the request signer certificate");
|
|
176
|
+
}
|
|
177
|
+
/** @internal Sec. 4.1.2: "If the request is signed, the requestor SHALL specify its name in the
|
|
178
|
+
* requestorName field." The signer certificate names the requestor, so its subject is the name
|
|
179
|
+
* when none is stated. A certificate with an empty subject names its holder in a critical
|
|
180
|
+
* subjectAltName (RFC 5280 sec. 4.1.2.6); an empty Name names nobody, so it is not derived. */
|
|
181
|
+
var requestorNameDer = null;
|
|
182
|
+
if (opts.requestorName != null) requestorNameDer = _nameDer(opts.requestorName);
|
|
183
|
+
else if (signerCert !== null) {
|
|
184
|
+
if (!signerCert.subject.rdns.length) throw _err("ocsp/bad-input", "the request signer certificate has an empty subject, so no requestorName can be taken from it; state requestorName (RFC 6960 sec. 4.1.2)");
|
|
185
|
+
requestorNameDer = signerCert.subject.bytes;
|
|
186
|
+
}
|
|
163
187
|
|
|
164
188
|
return Promise.all(queries.map(function (q) {
|
|
165
|
-
if (!q ||
|
|
189
|
+
if (!q || typeof q !== "object") throw _err("ocsp/bad-input", "each query must be { cert, issuer }");
|
|
190
|
+
guard.identifier.assertKnownKeys(q, _QUERY_KEYS, _err, "ocsp/bad-input", "unknown query field (a query is { cert, issuer, singleRequestExtensions? }): ");
|
|
191
|
+
if (q.cert == null || q.issuer == null) throw _err("ocsp/bad-input", "each query must be { cert, issuer }");
|
|
166
192
|
var cert = _certOf(q.cert, "the query certificate");
|
|
167
193
|
var issuer = _certOf(q.issuer, "the issuer certificate");
|
|
168
194
|
return _buildCertID(cert, issuer, hashName).then(function (certID) {
|
|
@@ -175,22 +201,17 @@ function _buildRequest(query, opts) {
|
|
|
175
201
|
});
|
|
176
202
|
})).then(function (requests) {
|
|
177
203
|
var tbsChildren = [];
|
|
178
|
-
if (
|
|
179
|
-
var nameDer = _nameDer(opts.requestorName);
|
|
180
|
-
tbsChildren.push(b.explicit(1, b.contextConstructed(4, nameDer)));
|
|
181
|
-
}
|
|
204
|
+
if (requestorNameDer !== null) tbsChildren.push(b.explicit(1, b.contextConstructed(4, requestorNameDer)));
|
|
182
205
|
tbsChildren.push(b.sequence(requests));
|
|
183
206
|
var reqExts = [];
|
|
184
207
|
if (opts.nonce) {
|
|
185
208
|
var nonceBytes = opts.nonce === true ? nodeCrypto.randomBytes(32) : opts.nonce;
|
|
186
|
-
_assertNonce(nonceBytes);
|
|
209
|
+
_assertNonce(nonceBytes, REQUESTER_NONCE_FLOOR);
|
|
187
210
|
reqExts.push(_nonceExt(nonceBytes));
|
|
188
211
|
}
|
|
189
212
|
if (reqExts.length) tbsChildren.push(b.explicit(2, b.sequence(reqExts)));
|
|
190
213
|
var tbsRequest = b.sequence(tbsChildren);
|
|
191
|
-
if (
|
|
192
|
-
var signerCertDer = _normCertDer(opts.signer.cert, "the request signer certificate");
|
|
193
|
-
var signerCert = _certOf(signerCertDer, "the request signer certificate");
|
|
214
|
+
if (signerCert === null) return _emitReq(b.sequence([tbsRequest]), opts);
|
|
194
215
|
var scheme = signScheme.resolveSignScheme(signerCert, { combinedRsaSig: true }, true, _signE);
|
|
195
216
|
return signScheme.signOverTbs(scheme, opts.signer.key, tbsRequest, _signE).then(function (sig) {
|
|
196
217
|
var optionalSignature = b.sequence([scheme.sigAlgId, b.bitString(sig, 0), b.explicit(0, b.sequence([b.raw(signerCertDer)]))]);
|
|
@@ -275,13 +296,21 @@ function sign(responseData, responder, opts) {
|
|
|
275
296
|
}
|
|
276
297
|
|
|
277
298
|
var _SIGN_OPTS = Object.assign(Object.create(null), { embedCert: 1, extendedRevoke: 1, nonce: 1, pem: 1 });
|
|
299
|
+
var _RESPONSE_DATA_KEYS = Object.assign(Object.create(null), { responderID: 1, responses: 1, producedAt: 1 });
|
|
300
|
+
var _SINGLE_RESPONSE_KEYS = Object.assign(Object.create(null), { cert: 1, issuer: 1, certID: 1, hashAlgorithm: 1, status: 1, thisUpdate: 1, nextUpdate: 1, singleExtensions: 1 });
|
|
301
|
+
var _RESPONDER_KEYS = Object.assign(Object.create(null), { cert: 1, key: 1 });
|
|
302
|
+
var _STATUS_KEYS = Object.assign(Object.create(null), { revoked: 1, revocationReason: 1 });
|
|
278
303
|
|
|
279
304
|
function _sign(responseData, responder, opts) {
|
|
280
305
|
opts = guard.identifier.optionsObject(opts, _err, "ocsp/bad-input", "pki.ocsp.sign options");
|
|
281
306
|
guard.identifier.assertKnownKeys(opts, _SIGN_OPTS, _err, "ocsp/bad-input",
|
|
282
307
|
"pki.ocsp.sign has an unknown option (the nonce to echo back is `nonce`): ");
|
|
283
308
|
responseData = responseData || {};
|
|
284
|
-
if (
|
|
309
|
+
if (typeof responseData !== "object") throw _err("ocsp/bad-input", "the responseData must be an object { responderID, responses, producedAt? }");
|
|
310
|
+
guard.identifier.assertKnownKeys(responseData, _RESPONSE_DATA_KEYS, _err, "ocsp/bad-input", "unknown responseData field (accepted: responderID, responses, producedAt): ");
|
|
311
|
+
if (!responder || typeof responder !== "object") throw _err("ocsp/bad-input", "a responder must be { cert, key }");
|
|
312
|
+
guard.identifier.assertKnownKeys(responder, _RESPONDER_KEYS, _err, "ocsp/bad-input", "unknown responder field (the responder is { cert, key }; a signing option belongs in the third argument): ");
|
|
313
|
+
if (responder.cert == null || responder.key == null) throw _err("ocsp/bad-input", "a responder must be { cert, key }");
|
|
285
314
|
var respCertDer = _normCertDer(responder.cert, "the responder certificate");
|
|
286
315
|
var respCert = _certOf(respCertDer, "the responder certificate");
|
|
287
316
|
var ownedKeyBytes = [];
|
|
@@ -314,7 +343,7 @@ function _signResponse(responseData, responder, respCert, respCertDer, responder
|
|
|
314
343
|
}
|
|
315
344
|
var rdChildren = [ridNode, b.generalizedTime(_asEncodableDate(responseData.producedAt, "producedAt") || new Date()), b.sequence(srNodes)];
|
|
316
345
|
var respExts = [];
|
|
317
|
-
if (opts.nonce != null) { _assertNonce(opts.nonce); respExts.push(_nonceExt(opts.nonce)); }
|
|
346
|
+
if (opts.nonce != null) { _assertNonce(opts.nonce, RESPONDER_NONCE_FLOOR); respExts.push(_nonceExt(opts.nonce)); }
|
|
318
347
|
if (opts.extendedRevoke || anyNonIssued) respExts.push(b.sequence([b.oid(OID_EXTENDED_REVOKE), b.octetString(b.nullValue())]));
|
|
319
348
|
if (respExts.length) rdChildren.push(b.explicit(1, b.sequence(respExts)));
|
|
320
349
|
var responseDataDer = b.sequence(rdChildren);
|
|
@@ -362,6 +391,9 @@ function _responderID(rid, respCert) {
|
|
|
362
391
|
function _buildSingleResponse(r, opts) {
|
|
363
392
|
r = r || {};
|
|
364
393
|
var certIdP;
|
|
394
|
+
if (typeof r !== "object") return Promise.reject(_err("ocsp/bad-input", "each response entry must be an object"));
|
|
395
|
+
try { guard.identifier.assertKnownKeys(r, _SINGLE_RESPONSE_KEYS, _err, "ocsp/bad-input", "unknown response entry field (accepted: cert, issuer, certID, hashAlgorithm, status, thisUpdate, nextUpdate, singleExtensions): "); }
|
|
396
|
+
catch (e) { return Promise.reject(e); }
|
|
365
397
|
if (r.certID != null) certIdP = Promise.resolve(b.raw(guard.bytes.view(r.certID, OcspError, "ocsp/bad-input", "a response entry's certID")));
|
|
366
398
|
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");
|
|
367
399
|
else return Promise.reject(_err("ocsp/bad-input", "each response entry needs { certID } or { cert, issuer }"));
|
|
@@ -505,6 +537,7 @@ function _certStatusNode(status, opts) {
|
|
|
505
537
|
if (status == null || status === "good") return b.contextPrimitive(0, Buffer.alloc(0));
|
|
506
538
|
if (status === "unknown") return b.contextPrimitive(2, Buffer.alloc(0));
|
|
507
539
|
if (typeof status === "object" && status.revoked != null) {
|
|
540
|
+
guard.identifier.assertKnownKeys(status, _STATUS_KEYS, _err, "ocsp/bad-input", "unknown revoked status field (a revoked status is { revoked, revocationReason? }): ");
|
|
508
541
|
var ri = [b.generalizedTime(_asEncodableDate(status.revoked, "the revocation time"))];
|
|
509
542
|
if (status.revocationReason != null) {
|
|
510
543
|
var code = typeof status.revocationReason === "number" ? status.revocationReason : REASON_CODE[guard.text.keyOf(status.revocationReason)];
|
|
@@ -638,8 +671,8 @@ function _requestFromBytes(request) {
|
|
|
638
671
|
}
|
|
639
672
|
function _reqVerdict(parsed, extra) {
|
|
640
673
|
return guard.verdict.of({
|
|
641
|
-
valid: extra.signed === true && extra.signatureValid === true,
|
|
642
|
-
signed: extra.signed, signatureValid: extra.signatureValid,
|
|
674
|
+
valid: extra.signed === true && extra.signatureValid === true && extra.requestorNamed === true,
|
|
675
|
+
signed: extra.signed, signatureValid: extra.signatureValid, requestorNamed: extra.requestorNamed === true,
|
|
643
676
|
signerCert: extra.signerCert != null ? extra.signerCert : null,
|
|
644
677
|
signerCerts: extra.signerCerts != null ? extra.signerCerts : [],
|
|
645
678
|
certs: extra.certs != null ? extra.certs : [],
|
|
@@ -664,18 +697,44 @@ async function _findRequestSigners(candidates, strict, parsed, sig, sigBits) {
|
|
|
664
697
|
}
|
|
665
698
|
return { matches: matches, parseable: parseable };
|
|
666
699
|
}
|
|
700
|
+
/** @internal RFC 6960 sec. 4.1.2: "If the request is signed, the requestor SHALL specify its name
|
|
701
|
+
* in the requestorName field." The requestor is whoever holds the key that signed, so the name is
|
|
702
|
+
* held to the subject of a certificate that verified the signature, compared as a distinguished
|
|
703
|
+
* name (RFC 5280 sec. 7.1). The parser refuses a signed request that names nobody
|
|
704
|
+
* (ocsp/missing-requestor-name); one naming its requestor by a GeneralName form other than
|
|
705
|
+
* directoryName leaves the check unperformed and never a pass. */
|
|
706
|
+
function _requestorNamed(parsed, matches) {
|
|
707
|
+
var rn = parsed.requestorName;
|
|
708
|
+
if (rn.tagNumber !== 4) {
|
|
709
|
+
return { named: [], reason: "the signed OCSP request names its requestor by a GeneralName form [" + rn.tagNumber + "] this responder does not compare to a certificate subject; a directoryName is compared (RFC 6960 sec. 4.1.2)" };
|
|
710
|
+
}
|
|
711
|
+
if (!rn.value.rdns.length) return { named: [], reason: "the signed OCSP request's requestorName is an empty distinguished name, which names nobody (RFC 6960 sec. 4.1.2)" };
|
|
712
|
+
var named = [];
|
|
713
|
+
for (var i = 0; i < matches.length; i++) {
|
|
714
|
+
if (guard.name.dnEqual(matches[i].subject.rdns, rn.value.rdns, _err, "ocsp/bad-input", "the requestorName")) named.push(matches[i]);
|
|
715
|
+
}
|
|
716
|
+
if (named.length) return { named: named, reason: null };
|
|
717
|
+
return { named: [], reason: "the requestorName " + guard.text.showValue(rn.value.dn) + " is not the subject of a certificate that signed the request (RFC 6960 sec. 4.1.2)" };
|
|
718
|
+
}
|
|
719
|
+
/** @internal Several certificates can carry the signing key (a renewal beside the certificate it
|
|
720
|
+
* replaced), and one of them may carry another subject. The signer the verdict names, and the set
|
|
721
|
+
* the responder builds its trusted path from, are the certificates that both verified the signature
|
|
722
|
+
* AND carry the name the request states; a same-key certificate under another name is not the
|
|
723
|
+
* requestor, whatever order the request embeds them in. */
|
|
667
724
|
function _signerVerdict(parsed, found, failReason) {
|
|
668
725
|
if (!found.matches.length) return _reqVerdict(parsed, { signed: true, signatureValid: false, certs: found.parseable, reason: failReason });
|
|
726
|
+
var bound = _requestorNamed(parsed, found.matches);
|
|
727
|
+
var signers = bound.named.length ? bound.named : found.matches;
|
|
669
728
|
return _reqVerdict(parsed, {
|
|
670
|
-
signed: true, signatureValid: true, signerCert:
|
|
671
|
-
signerCerts:
|
|
672
|
-
signerSubject: { dn:
|
|
729
|
+
signed: true, signatureValid: true, requestorNamed: bound.reason === null, signerCert: signers[0].der,
|
|
730
|
+
signerCerts: signers.map(function (m) { return m.der; }), certs: found.parseable,
|
|
731
|
+
signerSubject: { dn: signers[0].subject.dn, rdns: signers[0].subject.rdns }, reason: bound.reason,
|
|
673
732
|
});
|
|
674
733
|
}
|
|
675
734
|
|
|
676
735
|
/**
|
|
677
736
|
* @primitive pki.ocsp.verifyRequest
|
|
678
|
-
* @signature pki.ocsp.verifyRequest(request, opts?) -> Promise<{ valid, signed, signatureValid, signerCert, signerCerts, certs, signerSubject, requestorName, requestList, requestExtensions, version, reason }>
|
|
737
|
+
* @signature pki.ocsp.verifyRequest(request, opts?) -> Promise<{ valid, signed, signatureValid, requestorNamed, signerCert, signerCerts, certs, signerSubject, requestorName, requestList, requestExtensions, version, reason }>
|
|
679
738
|
* @since 0.6.0
|
|
680
739
|
* @status stable
|
|
681
740
|
* @spec RFC 6960
|
|
@@ -692,18 +751,24 @@ function _signerVerdict(parsed, found, failReason) {
|
|
|
692
751
|
*
|
|
693
752
|
* `signatureValid` means only that a certificate's key made this signature over this request. It
|
|
694
753
|
* says nothing about whether that certificate is trusted: `signerCerts` is every certificate the
|
|
695
|
-
* request carries whose key verified the signature
|
|
696
|
-
*
|
|
697
|
-
*
|
|
698
|
-
*
|
|
754
|
+
* request carries whose key verified the signature AND whose subject is the `requestorName` the
|
|
755
|
+
* request states (RFC 6960 sec. 4.1.1 certs is unordered, and a key may appear under an expired
|
|
756
|
+
* certificate beside its renewal; a same-key certificate under another name is not the requestor),
|
|
757
|
+
* so the responder builds a trusted path to one of them rather than depend on ordering. `signerCert`
|
|
758
|
+
* and the decoded `signerSubject` are the first of those, the common single-signer case; when no
|
|
759
|
+
* verifying certificate carries the name, they fall back to the verifying ones and `valid` is
|
|
760
|
+
* false. `certs` is every parseable certificate the
|
|
699
761
|
* request carried (or opts.certs supplied), including intermediates that do not sign and so are absent
|
|
700
762
|
* from `signerCerts`: the responder passes it as the `opts.candidates` pool to `pki.path.build`, which
|
|
701
763
|
* discovers and validates the ordered path from a `signerCerts` entry (leaf) up to a trust anchor.
|
|
702
764
|
* The responder then confirms that certificate is authorized to sign the request: its `keyUsage`,
|
|
703
765
|
* where present, must assert `digitalSignature` (RFC 5280 sec. 4.2.1.3, since the certificate signed
|
|
704
|
-
* the request).
|
|
705
|
-
*
|
|
706
|
-
*
|
|
766
|
+
* the request). The `requestorName` a signed request carries (RFC 6960 sec. 4.1.2: a requestor that
|
|
767
|
+
* signs SHALL specify its name) is held to the subject of a certificate that verified the signature,
|
|
768
|
+
* compared as a distinguished name (RFC 5280 sec. 7.1): `requestorNamed` is true when it is, `valid`
|
|
769
|
+
* requires it, and a name given as a GeneralName form other than directoryName is not compared and
|
|
770
|
+
* never passes. The decoded `requestorName` (with its `value` for a directoryName), `requestList`,
|
|
771
|
+
* `requestExtensions` and `version` are returned so the CertIDs being asked about need no re-parse.
|
|
707
772
|
*
|
|
708
773
|
* @opts
|
|
709
774
|
* - `certs` An array of certificates (DER `Buffer` / `Uint8Array` or PEM strings) supplying the
|
package/lib/pki-build.js
CHANGED
|
@@ -28,6 +28,7 @@ var _isBufferChk = intrinsic.isBuffer;
|
|
|
28
28
|
var _stringify = intrinsic.stringify;
|
|
29
29
|
var _mapIntrinsic = intrinsic.map;
|
|
30
30
|
var _bufferConcatIntrinsic = intrinsic.bufferConcat;
|
|
31
|
+
var OID_SKI = oid.byName("subjectKeyIdentifier");
|
|
31
32
|
|
|
32
33
|
function _isAlphaCode(c) { return (c >= 65 && c <= 90) || (c >= 97 && c <= 122); }
|
|
33
34
|
function _isDigitCode(c) { return c >= 48 && c <= 57; }
|
|
@@ -81,14 +82,14 @@ function _componentBytesOk(s, from, to, byteOk) {
|
|
|
81
82
|
return true;
|
|
82
83
|
}
|
|
83
84
|
|
|
84
|
-
function _validUriHost(s, from, to) {
|
|
85
|
+
function _validUriHost(s, from, to, singleLabel) {
|
|
85
86
|
if (to <= from) return false;
|
|
86
87
|
var host = _sliceStr(s, from, to), len = host.length;
|
|
87
88
|
if (_looksLikeIPv4Shape(host)) return _packIpLiteral(host) !== null;
|
|
88
89
|
var end = _charCodeAt(host, len - 1) === 46 ? len - 1 : len;
|
|
89
90
|
if (end > 253) return false;
|
|
90
91
|
var firstDot = _stringIndexOf(host, ".", 0);
|
|
91
|
-
if (firstDot === -1 || firstDot >= end) return false;
|
|
92
|
+
if (!singleLabel && (firstDot === -1 || firstDot >= end)) return false;
|
|
92
93
|
return _labelsValid(host, 0, len, _isHostLabelRange, true);
|
|
93
94
|
}
|
|
94
95
|
|
|
@@ -98,11 +99,11 @@ function _validUriIp6Host(s, from, to) {
|
|
|
98
99
|
return packed !== null && intrinsic.sizeOf(packed) === 16;
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
function _validUriAuthority(s, from, to) {
|
|
102
|
+
function _validUriAuthority(s, from, to, shape) {
|
|
102
103
|
var i, c, at = -1;
|
|
103
104
|
for (i = from; i < to; i += 1) {
|
|
104
105
|
c = _charCodeAt(s, i);
|
|
105
|
-
if (c === 64) { if (at !== -1) return false; at = i; }
|
|
106
|
+
if (c === 64) { if (at !== -1 || !shape.userinfo) return false; at = i; }
|
|
106
107
|
}
|
|
107
108
|
var hostStart = at === -1 ? from : at + 1;
|
|
108
109
|
if (at !== -1 && !_componentBytesOk(s, from, at, _isUserinfoByte)) return false;
|
|
@@ -120,14 +121,31 @@ function _validUriAuthority(s, from, to) {
|
|
|
120
121
|
var colon = -1;
|
|
121
122
|
for (i = hostStart; i < to; i += 1) { if (_charCodeAt(s, i) === 58) { colon = i; break; } }
|
|
122
123
|
var hostEnd = colon === -1 ? to : colon;
|
|
123
|
-
|
|
124
|
+
var portAlone = hostEnd === hostStart && colon !== -1 && shape.emptyHost;
|
|
125
|
+
if (!portAlone && !_validUriHost(s, hostStart, hostEnd, shape.singleLabel)) return false;
|
|
124
126
|
if (colon !== -1) {
|
|
125
127
|
for (i = colon + 1; i < to; i += 1) { if (!_isDigitCode(_charCodeAt(s, i))) return false; }
|
|
126
128
|
}
|
|
127
129
|
return true;
|
|
128
130
|
}
|
|
129
131
|
|
|
130
|
-
|
|
132
|
+
/** @internal The shape a bare string must have to be read as a URI GeneralName without being told:
|
|
133
|
+
* a scheme, "//", an authority naming a multi-label host (a single label reads as a dNSName), and
|
|
134
|
+
* a well-formed remainder, a fragment included. */
|
|
135
|
+
var _URI_SHAPE = intrinsic.assign(intrinsic.create(null), { singleLabel: false, userinfo: true, emptyAuthority: false, emptyHost: false, queryNeedsPath: false, fragment: true });
|
|
136
|
+
/** @internal An HTTP URL (RFC 2616 sec. 3.2.2: "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]):
|
|
137
|
+
* no userinfo, a host of one label or many, a query only after an absolute path, no fragment. */
|
|
138
|
+
var _HTTP_URL_SHAPE = intrinsic.assign(intrinsic.create(null), { singleLabel: true, userinfo: false, emptyAuthority: false, emptyHost: false, queryNeedsPath: true, fragment: false });
|
|
139
|
+
/** @internal An LDAP URL (RFC 4516 sec. 2: scheme "://" [host [":" port]] ["/" dn ...]): no
|
|
140
|
+
* userinfo, a host of any label count that may be left out, with or without a port, and no
|
|
141
|
+
* fragment. The dn, attributes, scope and filter after the "/" are not parsed. */
|
|
142
|
+
var _LDAP_URL_SHAPE = intrinsic.assign(intrinsic.create(null), { singleLabel: true, userinfo: false, emptyAuthority: true, emptyHost: true, queryNeedsPath: false, fragment: false });
|
|
143
|
+
|
|
144
|
+
function _looksLikeUri(s) { return _uriShape(s, _URI_SHAPE); }
|
|
145
|
+
function isHttpUrl(s) { return typeof s === "string" && guard.name.uriSchemeIs(s, "http") && _uriShape(s, _HTTP_URL_SHAPE); }
|
|
146
|
+
function isLdapUrl(s) { return typeof s === "string" && guard.name.uriSchemeIs(s, "ldap") && _uriShape(s, _LDAP_URL_SHAPE); }
|
|
147
|
+
|
|
148
|
+
function _uriShape(s, shape) {
|
|
131
149
|
var n = s.length, i, c;
|
|
132
150
|
if (n === 0 || !_isAlphaCode(_charCodeAt(s, 0))) return false;
|
|
133
151
|
i = 1;
|
|
@@ -140,8 +158,9 @@ function _looksLikeUri(s) {
|
|
|
140
158
|
i += 3;
|
|
141
159
|
var authStart = i, authEnd = n;
|
|
142
160
|
for (; i < n; i += 1) { c = _charCodeAt(s, i); if (c === 47 || c === 63 || c === 35) { authEnd = i; break; } }
|
|
143
|
-
if (authEnd === authStart) return false;
|
|
144
|
-
if (!_validUriAuthority(s, authStart, authEnd)) return false;
|
|
161
|
+
if (authEnd === authStart) { if (!shape.emptyAuthority) return false; }
|
|
162
|
+
else if (!_validUriAuthority(s, authStart, authEnd, shape)) return false;
|
|
163
|
+
if (authEnd < n && shape.queryNeedsPath && _charCodeAt(s, authEnd) === 63) return false;
|
|
145
164
|
var sawHash = false;
|
|
146
165
|
i = authEnd;
|
|
147
166
|
while (i < n) {
|
|
@@ -151,7 +170,7 @@ function _looksLikeUri(s) {
|
|
|
151
170
|
i += 3;
|
|
152
171
|
continue;
|
|
153
172
|
}
|
|
154
|
-
if (c === 35) { if (sawHash) return false; sawHash = true; }
|
|
173
|
+
if (c === 35) { if (sawHash || !shape.fragment) return false; sawHash = true; }
|
|
155
174
|
if (!_isUriByte(c)) return false;
|
|
156
175
|
i += 1;
|
|
157
176
|
}
|
|
@@ -1268,7 +1287,7 @@ function makeBuilder(ctx) {
|
|
|
1268
1287
|
extSubjectInfoAccess: extSubjectInfoAccess, extSubjectDirectoryAttributes: extSubjectDirectoryAttributes,
|
|
1269
1288
|
extMsCertificateTemplate: extMsCertificateTemplate, extMsCaVersion: extMsCaVersion,
|
|
1270
1289
|
extMsPreviousCertHash: extMsPreviousCertHash, extMsEnrollCertType: extMsEnrollCertType,
|
|
1271
|
-
spkiKeyId: spkiKeyId, skiKeyId: skiKeyId,
|
|
1290
|
+
spkiKeyId: spkiKeyId, skiKeyId: skiKeyId, skiValueOf: skiValueOf,
|
|
1272
1291
|
reqDer: reqDer, reqDenseArray: reqDenseArray, reqDerSequence: reqDerSequence, assertValidSpki: assertValidSpki, assertValidExtension: assertValidExtension,
|
|
1273
1292
|
assertExtnValueIsDer: assertExtnValueIsDer,
|
|
1274
1293
|
assertCertCriticality: assertCertCriticality,
|
|
@@ -1289,4 +1308,15 @@ function tbsSerialNumber(cert) {
|
|
|
1289
1308
|
return asn1.read.integer(tbs.children[hasVersion ? 1 : 0]);
|
|
1290
1309
|
}
|
|
1291
1310
|
|
|
1292
|
-
|
|
1311
|
+
/** @internal The subjectKeyIdentifier a parsed certificate carries, or null without one. RFC 5280
|
|
1312
|
+
* sec. 4.2.1.1 names it as the authorityKeyIdentifier keyIdentifier of everything issued under
|
|
1313
|
+
* that certificate, so a signer reads it here before deriving one from the key, and a verifier
|
|
1314
|
+
* matches a signer by it. */
|
|
1315
|
+
function skiValueOf(parsedCert) {
|
|
1316
|
+
var exts = intrinsic.filter(parsedCert.extensions, function (e) { return e.oid === OID_SKI; });
|
|
1317
|
+
if (!exts.length) return null;
|
|
1318
|
+
try { return asn1.read.octetString(asn1.decode(exts[0].value)); }
|
|
1319
|
+
catch (_e) { return null; } // allow:swallow-unverified -- a malformed SKI is read as absent; a signer then derives the authorityKeyIdentifier keyIdentifier from the public key, and a verifier matches on nothing
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
module.exports = intrinsic.freeze({ makeBuilder: makeBuilder, reqDenseArray: reqDenseArrayImpl, KU_BIT: KU_BIT, tbsNameField: tbsNameField, tbsSerialNumber: tbsSerialNumber, randomSerial: randomSerial, skiValueOf: skiValueOf, isHttpUrl: isHttpUrl, isLdapUrl: isLdapUrl });
|
package/lib/schema-attrcert.js
CHANGED
|
@@ -577,6 +577,13 @@ _AC_EXT_DECODERS[_Oav("targetInformation")] = _targetInformation;
|
|
|
577
577
|
_AC_EXT_DECODERS[_Oav("noRevAvail")] = _noRevAvail;
|
|
578
578
|
_AC_EXT_DECODERS[_Oav("aaControls")] = _aaControls;
|
|
579
579
|
_AC_EXT_DECODERS[_Oav("acProxying")] = _acProxying;
|
|
580
|
+
/** @internal The three RFC 5280 extensions RFC 5755 sec. 4.3.3 to 4.3.5 profile for an AC are read
|
|
581
|
+
* through the certificate decoders, so a relying party running the sec. 6 "pointer in AC" scheme
|
|
582
|
+
* reads the distribution point and the OCSP location off the parse rather than off raw bytes. */
|
|
583
|
+
var _CERT_EXT_DECODERS = pkix.certExtensionDecoders(NS).byOid;
|
|
584
|
+
_AC_EXT_DECODERS[_Oav("authorityKeyIdentifier")] = _CERT_EXT_DECODERS[_Oav("authorityKeyIdentifier")];
|
|
585
|
+
_AC_EXT_DECODERS[_Oav("authorityInfoAccess")] = _CERT_EXT_DECODERS[_Oav("authorityInfoAccess")];
|
|
586
|
+
_AC_EXT_DECODERS[_Oav("cRLDistributionPoints")] = _CERT_EXT_DECODERS[_Oav("cRLDistributionPoints")];
|
|
580
587
|
|
|
581
588
|
// @internal
|
|
582
589
|
function validateAttributeValue(type, valueDer) {
|
package/lib/schema-ocsp.js
CHANGED
|
@@ -85,7 +85,9 @@ function certificateBytes() {
|
|
|
85
85
|
return pkix.rawNonEmptySequence(NS, { code: "ocsp/bad-certs", message: "each certs element must be a non-empty Certificate SEQUENCE (RFC 6960 sec. 4.1.1/sec. 4.2.1)" });
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
/** @internal The requestorName is read with its value decoded, so a responder compares a
|
|
89
|
+
* directoryName to the signer certificate's subject (RFC 6960 sec. 4.1.2) off the parse. */
|
|
90
|
+
var GENERAL_NAME_RAW = pkix.generalName(NS, { code: "ocsp/bad-requestor-name", decodeValue: true });
|
|
89
91
|
|
|
90
92
|
function _rawSignature(field) {
|
|
91
93
|
var sig = field.value;
|
|
@@ -388,7 +390,7 @@ var TBS_REQUEST = schema.seq([
|
|
|
388
390
|
var rn = m.fields.requestorName;
|
|
389
391
|
return {
|
|
390
392
|
version: m.fields.version.value,
|
|
391
|
-
requestorName: rn.present ? { bytes: rn.value.bytes, tagClass: rn.value.tagClass, tagNumber: rn.value.tagNumber } : null,
|
|
393
|
+
requestorName: rn.present ? { bytes: rn.value.bytes, tagClass: rn.value.tagClass, tagNumber: rn.value.tagNumber, value: rn.value.value } : null,
|
|
392
394
|
requestList: m.fields.requestList.value.items.map(function (it) { return it.value.result; }),
|
|
393
395
|
requestExtensions: m.fields.requestExtensions.present ? _validateOcspExtensions(m.fields.requestExtensions.value.result) : null,
|
|
394
396
|
};
|
package/lib/x509-sign.js
CHANGED
|
@@ -39,8 +39,6 @@ function _err(code, message, cause) { return new CertificateError(code, message,
|
|
|
39
39
|
function _signE(kind, message, cause) { return new CertificateError("x509/" + kind, message, cause); }
|
|
40
40
|
function O(n) { return oid.byName(n); }
|
|
41
41
|
|
|
42
|
-
var OID_SKI = O("subjectKeyIdentifier");
|
|
43
|
-
|
|
44
42
|
var KNOWN_SPEC_KEYS = intrinsic.assign(intrinsic.create(null), {
|
|
45
43
|
subject: 1, subjectPublicKey: 1, notBefore: 1, notAfter: 1, serialNumber: 1, extensions: 1,
|
|
46
44
|
});
|
|
@@ -77,13 +75,8 @@ var _encodeName = _b.encodeName, _isEmptyName = _b.isEmptyName, _reqDer = _b.req
|
|
|
77
75
|
_skiKeyId = _b.skiKeyId, _spkiKeyId = _b.spkiKeyId, _serialInteger = _b.serialInteger;
|
|
78
76
|
|
|
79
77
|
|
|
80
|
-
function _skiValueOf(caCert) {
|
|
81
|
-
var ext = (caCert.extensions || []).filter(function (e) { return e.oid === OID_SKI; })[0];
|
|
82
|
-
if (ext) { try { return asn1.read.octetString(asn1.decode(ext.value)); } catch (_e) { } } // allow:swallow-unverified -- a malformed CA SKI is read as absent; _akiKeyId then derives the authorityKeyIdentifier keyIdentifier from the issuer public key
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
78
|
function _akiKeyId(val, ctx) {
|
|
86
|
-
var issuerSki = ctx.issuerCert ?
|
|
79
|
+
var issuerSki = ctx.issuerCert ? _b.skiValueOf(ctx.issuerCert) : null;
|
|
87
80
|
if (guard.bytes.isByteSource(val)) {
|
|
88
81
|
var given = guard.bytes.snapshotSource(val, CertificateError, "x509/bad-input", "the authorityKeyIdentifier keyIdentifier");
|
|
89
82
|
/** @internal Sec. 4.2.1.2: the issuer certificate's subjectKeyIdentifier MUST be the value
|
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:6602edcd-778a-4204-8e53-1bc40ccb396c",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-09-
|
|
8
|
+
"timestamp": "2026-09-12T13:27:30.472Z",
|
|
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.37",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "pki",
|
|
25
|
-
"version": "0.7.
|
|
25
|
+
"version": "0.7.37",
|
|
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.37",
|
|
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.37",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|