@blamejs/pki 0.8.31 → 0.8.49
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 +401 -0
- package/README.md +66 -15
- package/bin/pki.js +716 -30
- package/examples/issue-a-certificate.js +90 -0
- package/examples/post-quantum.js +66 -0
- package/examples/read-a-certificate.js +56 -0
- package/examples/revoke-and-check.js +86 -0
- package/examples/sign-and-verify-cms.js +63 -0
- package/index.js +18 -5
- package/lib/acme.js +223 -74
- package/lib/alt-sig.js +441 -0
- package/lib/asn1-der.js +48 -25
- package/lib/attrcert-sign.js +27 -19
- package/lib/cbor-det.js +24 -14
- package/lib/cmc-build.js +9 -2
- package/lib/cmc-verify.js +14 -3
- package/lib/cmp-build.js +17 -5
- package/lib/cmp-session.js +24 -11
- package/lib/cmp-verify.js +28 -19
- package/lib/cms-compress.js +3 -1
- package/lib/cms-decrypt.js +102 -7
- package/lib/cms-encrypt.js +59 -7
- package/lib/cms-sign.js +31 -9
- package/lib/cms-verify.js +22 -18
- package/lib/composite-kem.js +30 -18
- package/lib/composite-sig.js +29 -14
- package/lib/constants.js +26 -0
- package/lib/crl-sign.js +111 -19
- package/lib/crmf-sign.js +167 -15
- package/lib/csr-sign.js +117 -6
- package/lib/ct.js +1008 -58
- package/lib/est.js +29 -16
- package/lib/framework-error.js +12 -0
- package/lib/guard-async.js +1 -1
- package/lib/guard-bytes.js +103 -20
- package/lib/guard-crypto.js +205 -3
- package/lib/guard-encoding.js +6 -1
- package/lib/guard-identifier.js +55 -8
- package/lib/guard-intrinsic.js +43 -0
- package/lib/guard-json.js +122 -9
- package/lib/guard-limits.js +12 -1
- package/lib/guard-list.js +63 -8
- package/lib/guard-name.js +167 -20
- package/lib/guard-range.js +43 -5
- package/lib/guard-text.js +41 -0
- package/lib/guard-verdict.js +39 -8
- package/lib/hpke.js +688 -42
- package/lib/http-transport.js +156 -4
- package/lib/identity-match.js +4 -4
- package/lib/inspect.js +33 -6
- package/lib/jose.js +93 -25
- package/lib/key.js +18 -13
- package/lib/lint.js +165 -1
- package/lib/merkle.js +233 -27
- package/lib/ocsp.js +27 -14
- package/lib/oid.js +14 -4
- package/lib/path-validate.js +143 -61
- package/lib/pkcs12-build.js +7 -2
- package/lib/pki-build.js +31 -7
- package/lib/possession.js +575 -0
- package/lib/related-cert.js +708 -0
- package/lib/revocation-fetch.js +6 -6
- package/lib/scep.js +15 -5
- package/lib/schema-c509.js +5 -2
- package/lib/schema-cmc.js +1 -1
- package/lib/schema-cmp.js +8 -8
- package/lib/schema-cms.js +2 -15
- package/lib/schema-csr.js +69 -0
- package/lib/schema-engine.js +10 -3
- package/lib/schema-pkix.js +228 -2
- package/lib/schema-tsp.js +7 -6
- package/lib/sign-scheme.js +22 -9
- package/lib/sigstore.js +684 -168
- package/lib/sleep.js +8 -1
- package/lib/smime.js +22 -1
- package/lib/tlog.js +1235 -0
- package/lib/tls-cert-compress.js +25 -8
- package/lib/tsp-sign.js +120 -35
- package/lib/tuf.js +1395 -0
- package/lib/validator-tpm.js +4 -1
- package/lib/verify-seam.js +7 -1
- package/lib/webauthn-mds.js +41 -4
- package/lib/webauthn.js +43 -25
- package/lib/webcrypto.js +48 -46
- package/lib/x509-sign.js +225 -19
- package/package.json +2 -1
- package/sbom.cdx.json +6 -6
package/lib/revocation-fetch.js
CHANGED
|
@@ -352,8 +352,8 @@ async function _tryOcsp(state, cert, issuer, ctx, candidate) {
|
|
|
352
352
|
if (!state.nonce && v.nextUpdate && v.thisUpdate) {
|
|
353
353
|
state.cache.put(key, hit, v.thisUpdate, v.nextUpdate, hit.length);
|
|
354
354
|
}
|
|
355
|
-
return { status: v.status, reason: "an OCSP response from " + candidate.url,
|
|
356
|
-
revocationReason: v.revocationReason, revocationTime: v.revocationTime };
|
|
355
|
+
return guard.verdict.of({ status: v.status, reason: "an OCSP response from " + candidate.url,
|
|
356
|
+
revocationReason: v.revocationReason, revocationTime: v.revocationTime });
|
|
357
357
|
}
|
|
358
358
|
|
|
359
359
|
/** @internal The bytes the nonce extension carries, which is what the response echoes. The
|
|
@@ -490,14 +490,14 @@ async function _tryCrl(state, cert, issuer, ctx, candidates, certDeltas) {
|
|
|
490
490
|
var interim = await state.crlChecker(gathered, { useDeltas: state.useDeltas }).check(cert, issuer, ctx);
|
|
491
491
|
if (interim && (interim.status === "good" || interim.status === "revoked")) {
|
|
492
492
|
if (authentic) _keep(state, url, parsed, fetchedBytes, cert.issuer.bytes, issuer.workingPublicKey);
|
|
493
|
-
return { status: interim.status, reason: "a CRL from " + url,
|
|
494
|
-
revocationReason: _reasonCodeOf(interim), revocationTime: interim.revocationTime };
|
|
493
|
+
return guard.verdict.of({ status: interim.status, reason: "a CRL from " + url,
|
|
494
|
+
revocationReason: _reasonCodeOf(interim), revocationTime: interim.revocationTime });
|
|
495
495
|
}
|
|
496
496
|
}
|
|
497
497
|
if (gathered.length === 0) throw E("path/revocation-fetch-failed", "no CRL was fetched");
|
|
498
498
|
var last = await state.crlChecker(gathered, { useDeltas: state.useDeltas }).check(cert, issuer, ctx);
|
|
499
|
-
return { status: (last && last.status) || "unknown", reason: (last && last.reason) || "the fetched CRLs did not settle the status",
|
|
500
|
-
revocationReason: _reasonCodeOf(last), revocationTime: last && last.revocationTime };
|
|
499
|
+
return guard.verdict.of({ status: (last && last.status) || "unknown", reason: (last && last.reason) || "the fetched CRLs did not settle the status",
|
|
500
|
+
revocationReason: _reasonCodeOf(last), revocationTime: last && last.revocationTime });
|
|
501
501
|
}
|
|
502
502
|
|
|
503
503
|
/** @internal `crlChecker` names the CRLReason integer `reasonCode` and `verifyOcspResponse` names it
|
package/lib/scep.js
CHANGED
|
@@ -473,7 +473,7 @@ function _buildIssuerAndSerial(spec) {
|
|
|
473
473
|
*
|
|
474
474
|
* @opts
|
|
475
475
|
* - `recipientKey` -- `{ cert, key }` for the recipient, to decrypt the pkcsPKIEnvelope into `messageData`.
|
|
476
|
-
* - `signerCert` -- the expected signer certificate DER (the CA certificate for a CertRep); the message signer's public key must match it, or the message is refused.
|
|
476
|
+
* - `signerCert` -- the expected signer certificate DER (the CA certificate for a CertRep); the message signer's public key must match it, or the message is refused. It also decides whether an envelope using RSAES-PKCS1-v1_5 key transport over a content with no integrity tag is read: that combination is refused for a signer this option has not authenticated.
|
|
477
477
|
* - `expectedSenderNonce` -- a 16-byte Buffer; a message whose `recipientNonce` does not echo it is refused.
|
|
478
478
|
* @example
|
|
479
479
|
* // requires: pkiMessage -- a SCEP pkiMessage DER (from pki.scep.build, or a CA's response)
|
|
@@ -571,7 +571,17 @@ async function parse(bytes, opts) {
|
|
|
571
571
|
}
|
|
572
572
|
if (recipientKey != null && carriesEnvelope && v.eContent != null) {
|
|
573
573
|
var dec;
|
|
574
|
-
|
|
574
|
+
/** @internal The opt-in is passed only once the signer has been authenticated, which is what the
|
|
575
|
+
* premise rests on. `pki.cms.decrypt` refuses RSAES-PKCS1-v1_5 key transport over a content with no
|
|
576
|
+
* integrity tag because acceptance tells an attacker submitting chosen ciphertexts that theirs
|
|
577
|
+
* decoded. With `opts.signerCert` matched, the envelope arrived inside a signature an authorized
|
|
578
|
+
* peer made, and an attacker who cannot sign as that peer cannot submit one. Without it the
|
|
579
|
+
* signature is any signer's, this verb reports `signerAuthenticated: false`, and the caller
|
|
580
|
+
* authenticates the surfaced certificate after the decrypt has already produced its outcome, so the
|
|
581
|
+
* refusal stands. RFC 8894 sec. 3.1 puts the envelope there, and v1.5 over a CBC content is what
|
|
582
|
+
* deployed SCEP peers send, so an authenticated exchange still reads them. */
|
|
583
|
+
var decOpts = signerAuthenticated ? { allowUnauthenticatedRsa15: true } : {};
|
|
584
|
+
try { dec = await cmsDecrypt.decrypt(v.eContent, recipientKey, decOpts); }
|
|
575
585
|
catch (e) {
|
|
576
586
|
if (e && e.isPkiError) throw _err("scep/decrypt-failed", "the pkcsPKIEnvelope could not be decrypted with the recipient key: " + e.message, e);
|
|
577
587
|
throw e;
|
|
@@ -606,7 +616,7 @@ async function parse(bytes, opts) {
|
|
|
606
616
|
if (isnCh[1].content.length > 20) throw _err("scep/bad-request-payload", "a " + messageType + " messageData serialNumber must not exceed 20 octets (RFC 5280 sec. 4.1.2.2)");
|
|
607
617
|
}
|
|
608
618
|
}
|
|
609
|
-
return out;
|
|
619
|
+
return guard.verdict.shield(out);
|
|
610
620
|
}
|
|
611
621
|
var _PARSE_KEYS = Object.assign(Object.create(null), { recipientKey: 1, expectedSenderNonce: 1, signerCert: 1 });
|
|
612
622
|
|
|
@@ -1006,7 +1016,7 @@ function _dispatchCertRep(rep, transactionId, spki) {
|
|
|
1006
1016
|
if (findIssuedCert(repCerts.filter(function (c) { return c !== issued; }), spki.bytes) != null) {
|
|
1007
1017
|
throw _err("scep/ambiguous-issued-cert", "the SUCCESS CertRep carried more than one certificate matching the request public key; the issued certificate is ambiguous (RFC 8894 sec. 3.3)");
|
|
1008
1018
|
}
|
|
1009
|
-
return { pending: false, result: { status: "SUCCESS", certificate: issued, certificates: repCerts, transactionId: rep.transactionId } };
|
|
1019
|
+
return guard.verdict.of({ pending: false, result: guard.verdict.of({ status: "SUCCESS", certificate: issued, certificates: repCerts, transactionId: rep.transactionId }) });
|
|
1010
1020
|
}
|
|
1011
1021
|
|
|
1012
1022
|
function _pollExhausted(which, transactionId, senderNonce) {
|
|
@@ -1089,7 +1099,7 @@ async function _pkiOperation(messageType, baseUrl, opts, verbName) {
|
|
|
1089
1099
|
var rep = await parse(body, { signerCert: signerCert, expectedSenderNonce: senderNonce, recipientKey: recipientKey });
|
|
1090
1100
|
var d = _dispatchCertRep(rep, transactionId, spki);
|
|
1091
1101
|
if (!d.pending) return d.result;
|
|
1092
|
-
if (pollCount <= 0) return { status: "PENDING", transactionId: rep.transactionId, senderNonce: senderNonce };
|
|
1102
|
+
if (pollCount <= 0) return guard.verdict.of({ status: "PENDING", transactionId: rep.transactionId, senderNonce: senderNonce });
|
|
1093
1103
|
return _pollForIssuance({
|
|
1094
1104
|
firstResponse: res, firstSenderNonce: senderNonce, postUrl: postUrl, httpMethod: httpMethod, clientOpts: clientOpts,
|
|
1095
1105
|
caCert: caCert, csrSubject: csrSubject, issuerCert: issuerCert, signer: signer, signerCert: signerCert, recipientKey: recipientKey,
|
package/lib/schema-c509.js
CHANGED
|
@@ -1282,7 +1282,7 @@ function _requireStrictDerTlv(content, code, label) {
|
|
|
1282
1282
|
|
|
1283
1283
|
function _derSetInDeclaredOrder(vals) {
|
|
1284
1284
|
for (var i = 1; i < vals.length; i++) {
|
|
1285
|
-
if (
|
|
1285
|
+
if (guard.bytes.compare(vals[i - 1], vals[i]) > 0) throw _err("c509/bad-extensions", "a subjectDirectoryAttributes attributeValue list must be in DER ascending order (X.690 sec. 11.6)");
|
|
1286
1286
|
}
|
|
1287
1287
|
return b.set(vals);
|
|
1288
1288
|
}
|
|
@@ -2033,7 +2033,10 @@ function encode(input, opts) {
|
|
|
2033
2033
|
var origDer = pkix.coerceToDer(input, { pemLabel: "CERTIFICATE", PemError: frameworkError.PemError, ErrorClass: C509Error, prefix: "c509" });
|
|
2034
2034
|
var encoded = _encodeC509Array(_derToType3(origDer, opts));
|
|
2035
2035
|
var recon = parse(encoded).reconstructedDer;
|
|
2036
|
-
|
|
2036
|
+
/** @internal Through the captured comparator: this IS the byte-for-byte claim a type-3 C509 makes
|
|
2037
|
+
* about the certificate it re-encodes, so a replacement answering zero asserts it over bytes that
|
|
2038
|
+
* do not match. */
|
|
2039
|
+
if (!recon || guard.bytes.compare(recon, origDer) !== 0) throw _err("c509/non-invertible", "the type-3 C509 does not reconstruct the source certificate byte-for-byte");
|
|
2037
2040
|
return encoded;
|
|
2038
2041
|
}
|
|
2039
2042
|
|
package/lib/schema-cmc.js
CHANGED
|
@@ -245,7 +245,7 @@ function parseStatusInfo(valueDer, version, bodyPartID, ctx) {
|
|
|
245
245
|
extendedFailInfo: other ? other.extendedFailInfo : null,
|
|
246
246
|
};
|
|
247
247
|
_assertStatusCoherent(out);
|
|
248
|
-
return out;
|
|
248
|
+
return guard.verdict.shield(out);
|
|
249
249
|
}
|
|
250
250
|
|
|
251
251
|
function _assertStatusCoherent(s) {
|
package/lib/schema-cmp.js
CHANGED
|
@@ -231,11 +231,11 @@ var PKI_STATUS_INFO = schema.seq([
|
|
|
231
231
|
], {
|
|
232
232
|
assert: "sequence", code: "cmp/bad-status-info", what: "PKIStatusInfo",
|
|
233
233
|
build: function (m) {
|
|
234
|
-
return {
|
|
234
|
+
return guard.verdict.of({
|
|
235
235
|
status: m.fields.status.value,
|
|
236
236
|
statusString: m.fields.statusString.present ? m.fields.statusString.value.result : null,
|
|
237
237
|
failInfo: m.fields.failInfo.present ? m.fields.failInfo.value : null,
|
|
238
|
-
};
|
|
238
|
+
});
|
|
239
239
|
},
|
|
240
240
|
});
|
|
241
241
|
|
|
@@ -329,11 +329,11 @@ var REV_REP_CONTENT = schema.seq([
|
|
|
329
329
|
], {
|
|
330
330
|
assert: "sequence", code: "cmp/bad-rev-rep", what: "RevRepContent",
|
|
331
331
|
build: function (m) {
|
|
332
|
-
return {
|
|
332
|
+
return guard.verdict.of({
|
|
333
333
|
status: m.fields.status.value.result,
|
|
334
334
|
revCerts: m.fields.revCerts.present ? m.fields.revCerts.value.result : null,
|
|
335
335
|
crls: m.fields.crls.present ? m.fields.crls.value.result : null,
|
|
336
|
-
};
|
|
336
|
+
});
|
|
337
337
|
},
|
|
338
338
|
});
|
|
339
339
|
|
|
@@ -411,12 +411,12 @@ var CERT_RESPONSE = schema.seq([
|
|
|
411
411
|
throw ctx.E("cmp/bad-cert-response",
|
|
412
412
|
"a CertResponse certifiedKeyPair is allowed only under a granting status (accepted or grantedWithMods) (RFC 9810 sec. 5.3.4)");
|
|
413
413
|
}
|
|
414
|
-
return {
|
|
414
|
+
return guard.verdict.of({
|
|
415
415
|
certReqId: m.fields.certReqId.value,
|
|
416
416
|
status: status,
|
|
417
417
|
certifiedKeyPair: certifiedKeyPair,
|
|
418
418
|
rspInfo: m.fields.rspInfo.present ? m.fields.rspInfo.value : null,
|
|
419
|
-
};
|
|
419
|
+
});
|
|
420
420
|
},
|
|
421
421
|
});
|
|
422
422
|
|
|
@@ -455,12 +455,12 @@ var KEY_REC_REP_CONTENT = schema.seq([
|
|
|
455
455
|
], {
|
|
456
456
|
assert: "sequence", code: "cmp/bad-key-rec-rep", what: "KeyRecRepContent",
|
|
457
457
|
build: function (m) {
|
|
458
|
-
return {
|
|
458
|
+
return guard.verdict.of({
|
|
459
459
|
status: m.fields.status.value.result,
|
|
460
460
|
newSigCert: m.fields.newSigCert.present ? m.fields.newSigCert.value : null,
|
|
461
461
|
caCerts: m.fields.caCerts.present ? m.fields.caCerts.value.result : null,
|
|
462
462
|
keyPairHist: m.fields.keyPairHist.present ? m.fields.keyPairHist.value.result : null,
|
|
463
|
-
};
|
|
463
|
+
});
|
|
464
464
|
},
|
|
465
465
|
});
|
|
466
466
|
|
package/lib/schema-cms.js
CHANGED
|
@@ -60,7 +60,6 @@ var NS = pkix.makeNS("cms", CmsError, oid);
|
|
|
60
60
|
|
|
61
61
|
var ALGORITHM_IDENTIFIER = pkix.algorithmIdentifier(NS);
|
|
62
62
|
var ATTRIBUTE = pkix.attribute(NS);
|
|
63
|
-
var NAME = pkix.name(NS);
|
|
64
63
|
|
|
65
64
|
var SIGNED_DATA_VERSION = pkix.versionReader(NS, { "1": 1, "3": 3, "4": 4, "5": 5 });
|
|
66
65
|
var SIGNER_VERSION = pkix.versionReader(NS, { "1": 1, "3": 3 });
|
|
@@ -179,7 +178,7 @@ function _readsAsTime(vals) {
|
|
|
179
178
|
|
|
180
179
|
function _ascendingDer(nodes) {
|
|
181
180
|
for (var i = 1; i < nodes.length; i++) {
|
|
182
|
-
if (
|
|
181
|
+
if (guard.bytes.compare(nodes[i - 1].bytes, nodes[i].bytes) > 0) return false;
|
|
183
182
|
}
|
|
184
183
|
return true;
|
|
185
184
|
}
|
|
@@ -330,19 +329,7 @@ var ENCAP_CONTENT_INFO = schema.seq([
|
|
|
330
329
|
},
|
|
331
330
|
});
|
|
332
331
|
|
|
333
|
-
var ISSUER_AND_SERIAL =
|
|
334
|
-
schema.field("issuer", NAME),
|
|
335
|
-
schema.field("serialNumber", schema.integerLeaf()),
|
|
336
|
-
], {
|
|
337
|
-
assert: "sequence", arity: { exact: 2 }, code: "cms/bad-issuer-and-serial", what: "IssuerAndSerialNumber",
|
|
338
|
-
build: function (m) {
|
|
339
|
-
return {
|
|
340
|
-
issuer: m.fields.issuer.value.result,
|
|
341
|
-
serialNumber: m.fields.serialNumber.value,
|
|
342
|
-
serialNumberHex: m.fields.serialNumber.node.content.toString("hex"),
|
|
343
|
-
};
|
|
344
|
-
},
|
|
345
|
-
});
|
|
332
|
+
var ISSUER_AND_SERIAL = pkix.issuerAndSerialNumber(NS, { code: "cms/bad-issuer-and-serial" });
|
|
346
333
|
|
|
347
334
|
var SIGNER_IDENTIFIER = schema.choice([
|
|
348
335
|
{ when: { tagClass: "universal", tagNumber: asn1.TAGS.SEQUENCE }, schema: ISSUER_AND_SERIAL },
|
package/lib/schema-csr.js
CHANGED
|
@@ -35,6 +35,7 @@ var pkix = require("./schema-pkix");
|
|
|
35
35
|
var oid = require("./oid");
|
|
36
36
|
var frameworkError = require("./framework-error");
|
|
37
37
|
var intrinsic = require("./guard-intrinsic");
|
|
38
|
+
var constants = require("./constants");
|
|
38
39
|
|
|
39
40
|
var CsrError = frameworkError.CsrError;
|
|
40
41
|
var PemError = frameworkError.PemError;
|
|
@@ -73,6 +74,74 @@ RECOGNIZED_ATTRIBUTE_VALUE[oid.byName("challengePassword")] = function (node, ct
|
|
|
73
74
|
}
|
|
74
75
|
};
|
|
75
76
|
|
|
77
|
+
/** @internal RequesterCertificate ::= SEQUENCE { certID IssuerAndSerialNumber, requestTime BinaryTime,
|
|
78
|
+
* locationInfo UniformResourceIdentifiers, signature BIT STRING } (RFC 9763 sec. 3.1), where
|
|
79
|
+
* UniformResourceIdentifiers ::= SEQUENCE SIZE (1..MAX) OF URI and URI ::= IA5String. locationInfo is
|
|
80
|
+
* a SEQUENCE OF rather than one URI, and it is the one field the signature does not cover. */
|
|
81
|
+
var REQUESTER_CERTIFICATE = schema.seq([
|
|
82
|
+
schema.field("certID", pkix.issuerAndSerialNumber(NS, { code: "csr/bad-attribute-value" })),
|
|
83
|
+
schema.field("requestTime", schema.integerLeaf()),
|
|
84
|
+
/** @internal A SEQUENCE OF, so the DER SET-OF ordering rule does not apply and the URIs keep the
|
|
85
|
+
* order the requester wrote them in. */
|
|
86
|
+
schema.field("locationInfo", schema.seqOf(schema.decode(function (n, ctx) {
|
|
87
|
+
if (n.tagClass !== "universal" || n.tagNumber !== asn1.TAGS.IA5_STRING) {
|
|
88
|
+
throw ctx.E("csr/bad-attribute-value", "a RequesterCertificate locationInfo entry must be an IA5String URI (RFC 9763 sec. 3.1)");
|
|
89
|
+
}
|
|
90
|
+
return asn1.read.string(n);
|
|
91
|
+
}), { assert: "sequence", min: 1, max: constants.LIMITS.ATTRIBUTE_MAX_VALUES,
|
|
92
|
+
code: "csr/bad-attribute-value", what: "RequesterCertificate locationInfo" })),
|
|
93
|
+
schema.field("signature", schema.bitString()),
|
|
94
|
+
], {
|
|
95
|
+
assert: "sequence", arity: { exact: 4 }, code: "csr/bad-attribute-value", what: "RequesterCertificate",
|
|
96
|
+
build: function (m, ctx) {
|
|
97
|
+
var t = m.fields.requestTime.value;
|
|
98
|
+
if (t < 0n) throw ctx.E("csr/bad-attribute-value", "a RequesterCertificate requestTime must not be negative (BinaryTime is INTEGER (0..MAX), RFC 6019 sec. 2)");
|
|
99
|
+
var bits = m.fields.signature.value;
|
|
100
|
+
if (bits.unusedBits !== 0) throw ctx.E("csr/bad-attribute-value", "a RequesterCertificate signature BIT STRING must be octet-aligned");
|
|
101
|
+
if (bits.bytes.length === 0) throw ctx.E("csr/bad-attribute-value", "a RequesterCertificate signature must not be empty");
|
|
102
|
+
return {
|
|
103
|
+
certID: m.fields.certID.value.result,
|
|
104
|
+
requestTime: t,
|
|
105
|
+
locationInfo: intrinsic.map(m.fields.locationInfo.value.items, function (it) { return it.value; }),
|
|
106
|
+
signature: { unusedBits: bits.unusedBits, bytes: bits.bytes },
|
|
107
|
+
};
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
/** @internal PrivateKeyPossessionStatement ::= SEQUENCE { signer IssuerAndSerialNumber,
|
|
111
|
+
* cert Certificate OPTIONAL } (RFC 9883 sec. 3). The signer is the shared IssuerAndSerialNumber; the
|
|
112
|
+
* certificate is surfaced as raw DER, because it is a whole Certificate a caller parses and verifies
|
|
113
|
+
* rather than a field read here. */
|
|
114
|
+
var POSSESSION_STATEMENT = schema.seq([
|
|
115
|
+
schema.field("signer", pkix.issuerAndSerialNumber(NS, { code: "csr/bad-attribute-value" })),
|
|
116
|
+
schema.optional("certificate", schema.any(), { whenUniversal: [asn1.TAGS.SEQUENCE] }),
|
|
117
|
+
], {
|
|
118
|
+
assert: "sequence", arity: { min: 1, max: 2 },
|
|
119
|
+
code: "csr/bad-attribute-value", what: "PrivateKeyPossessionStatement",
|
|
120
|
+
build: function (m) {
|
|
121
|
+
return {
|
|
122
|
+
signer: m.fields.signer.value.result,
|
|
123
|
+
certificate: m.fields.certificate.present ? m.fields.certificate.node.bytes : null,
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
RECOGNIZED_ATTRIBUTE_VALUE[oid.byName("statementOfPossession")] = function (node, ctx) {
|
|
128
|
+
try { return { privateKeyPossessionStatement: schema.walk(POSSESSION_STATEMENT, node, ctx).result }; }
|
|
129
|
+
catch (e) {
|
|
130
|
+
if (e instanceof CsrError) throw e;
|
|
131
|
+
throw ctx.E("csr/bad-attribute-value",
|
|
132
|
+
"statementOfPossession value must be a well-formed PrivateKeyPossessionStatement SEQUENCE (RFC 9883 sec. 3): " + ((e && e.message) || intrinsic.String(e)), e);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
RECOGNIZED_ATTRIBUTE_VALUE[oid.byName("relatedCertRequest")] = function (node, ctx) {
|
|
137
|
+
try { return { relatedCertRequest: schema.walk(REQUESTER_CERTIFICATE, node, ctx).result }; }
|
|
138
|
+
catch (e) {
|
|
139
|
+
if (e instanceof CsrError) throw e;
|
|
140
|
+
throw ctx.E("csr/bad-attribute-value",
|
|
141
|
+
"relatedCertRequest value must be a well-formed RequesterCertificate SEQUENCE (RFC 9763 sec. 3.1): " + ((e && e.message) || intrinsic.String(e)), e);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
76
145
|
var CERTIFICATION_REQUEST_INFO = schema.seq([
|
|
77
146
|
schema.field("version", CSR_VERSION),
|
|
78
147
|
schema.field("subject", NAME),
|
package/lib/schema-engine.js
CHANGED
|
@@ -28,6 +28,10 @@
|
|
|
28
28
|
|
|
29
29
|
var asn1 = require("./asn1-der.js");
|
|
30
30
|
var intrinsic = require("./guard-intrinsic");
|
|
31
|
+
/** @internal Just the list guard, not the whole family: this module sits below the format layer and
|
|
32
|
+
* takes the one primitive it needs. The copy-and-sort it provides reads `length` once and orders
|
|
33
|
+
* through operations captured at load, which is what a DER SET ordering rests on. */
|
|
34
|
+
var guardList = require("./guard-list");
|
|
31
35
|
|
|
32
36
|
var TAGS = asn1.TAGS;
|
|
33
37
|
|
|
@@ -310,7 +314,7 @@ function _walkRepeat(schema, node, ctx) {
|
|
|
310
314
|
}
|
|
311
315
|
if (schema.derSetOrder) {
|
|
312
316
|
for (var s = 1; s < kids.length; s++) {
|
|
313
|
-
if (
|
|
317
|
+
if (intrinsic.compare(kids[s - 1].bytes, kids[s].bytes) > 0) {
|
|
314
318
|
_fail(ctx, schema.code, (schema.what || "value") + " components must be in ascending DER order (X.690 sec. 11.6)");
|
|
315
319
|
}
|
|
316
320
|
}
|
|
@@ -474,7 +478,7 @@ function _encodeSeq(schema, value, ctx) {
|
|
|
474
478
|
if (!isDefault) parts.push(fld.explicit ? asn1.build.explicit(fld.tag, enc) : enc);
|
|
475
479
|
}
|
|
476
480
|
} else if (fld.fkind === "trailing") {
|
|
477
|
-
var members = fld.members
|
|
481
|
+
var members = guardList.sortedCopy(fld.members, function (a, b) { return a.tag - b.tag; });
|
|
478
482
|
for (var i = 0; i < members.length; i++) {
|
|
479
483
|
var mm = members[i];
|
|
480
484
|
if (_present(value[mm.name])) {
|
|
@@ -509,7 +513,10 @@ function _encodeRepeat(schema, items, ctx) {
|
|
|
509
513
|
seen.add(key);
|
|
510
514
|
});
|
|
511
515
|
}
|
|
512
|
-
|
|
516
|
+
/** @internal The comparator goes through the captured operation, as the copy and the sort do. This
|
|
517
|
+
* is the engine's own SET OF emission, so whatever decides "before" decides the bytes every schema
|
|
518
|
+
* built on it emits. */
|
|
519
|
+
if (schema.derSetOrder) parts = guardList.sortedCopy(parts, intrinsic.compare);
|
|
513
520
|
if (schema.implicitTag != null) return asn1.build.contextConstructed(schema.implicitTag, Buffer.concat(parts));
|
|
514
521
|
return schema.assert === "set" ? asn1.build.set(parts) : asn1.build.sequence(parts);
|
|
515
522
|
}
|
package/lib/schema-pkix.js
CHANGED
|
@@ -741,6 +741,68 @@ function algorithmIdentifier(ns, opts) {
|
|
|
741
741
|
});
|
|
742
742
|
}
|
|
743
743
|
|
|
744
|
+
/** @internal IssuerAndSerialNumber ::= SEQUENCE { issuer Name, serialNumber CertificateSerialNumber }
|
|
745
|
+
* (RFC 5652 sec. 10.2.4). CMS names the type and RFC 9763 sec. 3.1 reuses it inside a CSR attribute,
|
|
746
|
+
* so the shape is defined once and each caller supplies its own code and name for the refusal. */
|
|
747
|
+
function issuerAndSerialNumber(ns, opts) {
|
|
748
|
+
opts = opts || {};
|
|
749
|
+
return schema.seq([
|
|
750
|
+
schema.field("issuer", name(ns)),
|
|
751
|
+
schema.field("serialNumber", schema.integerLeaf()),
|
|
752
|
+
], {
|
|
753
|
+
assert: "sequence", arity: { exact: 2 },
|
|
754
|
+
code: opts.code || (ns.prefix + "/bad-issuer-and-serial"), what: opts.what || "IssuerAndSerialNumber",
|
|
755
|
+
build: function (m) {
|
|
756
|
+
return {
|
|
757
|
+
issuer: m.fields.issuer.value.result,
|
|
758
|
+
serialNumber: m.fields.serialNumber.value,
|
|
759
|
+
serialNumberHex: _bufToString(m.fields.serialNumber.node.content, "hex"),
|
|
760
|
+
};
|
|
761
|
+
},
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/** @internal The digest a signature algorithm OID names, where it names one. RFC 9763 sec. 4.1 reads
|
|
766
|
+
* this relation directly ("a hash algorithm explicitly indicated by the related certificate's
|
|
767
|
+
* signature OID"), and an algorithm whose OID fixes no digest, such as Ed25519 or ML-DSA, is absent
|
|
768
|
+
* rather than mapped to a default. The value is the registry name, so a caller that needs its own
|
|
769
|
+
* spelling maps from one table instead of carrying a second copy of the relation. */
|
|
770
|
+
var SIG_OID_DIGEST_ROWS = [
|
|
771
|
+
["sha1WithRSAEncryption", "sha1"], ["sha256WithRSAEncryption", "sha256"],
|
|
772
|
+
["sha384WithRSAEncryption", "sha384"], ["sha512WithRSAEncryption", "sha512"],
|
|
773
|
+
["ecdsaWithSHA1", "sha1"], ["ecdsaWithSHA256", "sha256"],
|
|
774
|
+
["ecdsaWithSHA384", "sha384"], ["ecdsaWithSHA512", "sha512"],
|
|
775
|
+
["sha1", "sha1"], ["sha256", "sha256"], ["sha384", "sha384"], ["sha512", "sha512"],
|
|
776
|
+
["sha3-256", "sha3-256"], ["sha3-512", "sha3-512"],
|
|
777
|
+
["id-RSASSA-PSS-SHAKE128", "shake128"], ["id-RSASSA-PSS-SHAKE256", "shake256"],
|
|
778
|
+
];
|
|
779
|
+
/** @internal The digest output length in octets, for the readers that hold a hash value to the length
|
|
780
|
+
* of the algorithm named beside it. A SHAKE is absent: its output length is a parameter of the use,
|
|
781
|
+
* not of the algorithm, so there is no single length to hold a value to. */
|
|
782
|
+
var DIGEST_LENGTH_ROWS = [
|
|
783
|
+
["sha1", 20], ["sha256", 32], ["sha384", 48], ["sha512", 64],
|
|
784
|
+
["sha3-256", 32], ["sha3-512", 64],
|
|
785
|
+
];
|
|
786
|
+
function digestLengths() {
|
|
787
|
+
var out = _create(null);
|
|
788
|
+
_forEach(DIGEST_LENGTH_ROWS, function (r) { out[r[0]] = r[1]; });
|
|
789
|
+
return out;
|
|
790
|
+
}
|
|
791
|
+
var DIGEST_LENGTHS = digestLengths();
|
|
792
|
+
/** @internal Keyed by dotted OID through the registry the caller passes, this module taking its
|
|
793
|
+
* registry as a parameter rather than requiring it. A row whose name the registry does not carry
|
|
794
|
+
* throws rather than being skipped: a skipped row is a digest the readers silently stop deriving,
|
|
795
|
+
* which reads as "this certificate names no hash" on a certificate that names one. */
|
|
796
|
+
function signatureDigestNames(oidRegistry) {
|
|
797
|
+
var out = _create(null);
|
|
798
|
+
_forEach(SIG_OID_DIGEST_ROWS, function (r) {
|
|
799
|
+
var dotted = oidRegistry.byName(r[0]);
|
|
800
|
+
if (!dotted) throw new Error("schema-pkix: the signature-digest table names " + r[0] + ", which the OID registry does not carry");
|
|
801
|
+
out[dotted] = r[1];
|
|
802
|
+
});
|
|
803
|
+
return out;
|
|
804
|
+
}
|
|
805
|
+
|
|
744
806
|
function pbkdf2Params(ns) {
|
|
745
807
|
return schema.seq([
|
|
746
808
|
schema.field("salt", schema.octetString()),
|
|
@@ -1386,7 +1448,12 @@ function crlExtensionDecoders(ns) {
|
|
|
1386
1448
|
var doorScope = _create(null);
|
|
1387
1449
|
doorScope.crl = _assign(_create(null), byScope.crl);
|
|
1388
1450
|
doorScope.entry = _assign(_create(null), byScope.entry);
|
|
1389
|
-
|
|
1451
|
+
/** @internal ITU-T X.509 (2019) clause 9.8 states altSignatureAlgorithm and altSignatureValue as CRL
|
|
1452
|
+
* extensions as well as certificate ones, and clause 7.10.3 gives the CRL the same procedure, so the
|
|
1453
|
+
* two share one decoder with the certificate scope. subjectAltPublicKeyInfo is absent: the NOTE in
|
|
1454
|
+
* clause 7.2.2 says it "is only used as a public-key certificate extension". */
|
|
1455
|
+
_forEach(["authorityKeyIdentifier", "issuerAltName", "authorityInfoAccess", "freshestCRL",
|
|
1456
|
+
"altSignatureAlgorithm", "altSignatureValue"], function (n) {
|
|
1390
1457
|
doorScope.crl[O(n)] = scopedCertDecoder(ns, n);
|
|
1391
1458
|
});
|
|
1392
1459
|
doorScope.entry[O("certificateIssuer")] = _generalNamesDecoder(ns);
|
|
@@ -1707,10 +1774,93 @@ function _acceptExtensionRecord(ext, E, code, key) {
|
|
|
1707
1774
|
record.oid = checked.oid;
|
|
1708
1775
|
record.name = typeof checked.name === "string" ? checked.name : null;
|
|
1709
1776
|
record.critical = checked.critical === true;
|
|
1710
|
-
|
|
1777
|
+
/** @internal Normalized to a byte view before it is copied. The check above admits what
|
|
1778
|
+
* `guard.bytes.isByteSource` admits, which includes a DataView and an ArrayBuffer, and
|
|
1779
|
+
* `guard.bytes.snapshot` takes neither: a value this verb had just called acceptable was then refused
|
|
1780
|
+
* for being the wrong kind of container, so the two messages contradicted each other about one value.
|
|
1781
|
+
* `snapshotSource` views and copies in one call, and the view shares the caller's store rather than
|
|
1782
|
+
* copying it, so the copy is still the only allocation. */
|
|
1783
|
+
record.value = guard.bytes.snapshotSource(checked.value, E, code, "the extension value");
|
|
1711
1784
|
return record;
|
|
1712
1785
|
}
|
|
1713
1786
|
|
|
1787
|
+
/** @internal Whether a parsed certificate's keyUsage permits a named set of purposes, as one definition
|
|
1788
|
+
* three verifiers share. RFC 5280 sec. 4.2.1.3 confines a key to the purposes a present keyUsage asserts,
|
|
1789
|
+
* so a verifier checking a signature under a certificate's key owes this check: a certificate confined to
|
|
1790
|
+
* `keyAgreement` does not authorize a signature. Absent keyUsage is unconfined and permits; a keyUsage that
|
|
1791
|
+
* does not DECODE denies rather than permits, since an extension nothing could read has not been satisfied.
|
|
1792
|
+
* `allowed` is the set each caller's own specification names, which is the only thing that differs between
|
|
1793
|
+
* them: RFC 9483 sec. 3.2 requires `digitalSignature` alone, while a signature over content is also
|
|
1794
|
+
* authorized by `contentCommitment` or `nonRepudiation`. */
|
|
1795
|
+
function keyUsagePermits(ns, allowed) {
|
|
1796
|
+
var kuOid = ns.oid.byName("keyUsage");
|
|
1797
|
+
var decoders = certExtensionDecoders(ns).byOid;
|
|
1798
|
+
return function (parsedCert) {
|
|
1799
|
+
var exts = (parsedCert && parsedCert.extensions) || [];
|
|
1800
|
+
for (var i = 0; i < exts.length; i++) {
|
|
1801
|
+
if (exts[i].oid !== kuOid) continue;
|
|
1802
|
+
var ku;
|
|
1803
|
+
try { ku = decoders[kuOid](exts[i].value); }
|
|
1804
|
+
catch (e) { void e; return false; }
|
|
1805
|
+
for (var a = 0; a < allowed.length; a++) if (ku[allowed[a]] === true) return true;
|
|
1806
|
+
return false;
|
|
1807
|
+
}
|
|
1808
|
+
return true;
|
|
1809
|
+
};
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
/** @internal The subject-key algorithms that can only ever SIGN, as one table the linter and the verifier
|
|
1813
|
+
* share. RFC 9883 sec. 6 states "The privateKeyPossessionStatement attribute MUST NOT be used to obtain a
|
|
1814
|
+
* signature certificate", and sec. 4 states the same requirement as a property of the request: "the
|
|
1815
|
+
* subjectPKInfo MUST contain the public key for the key establishment algorithm". The mechanism exists
|
|
1816
|
+
* because a key-establishment key cannot sign and so cannot prove possession the PKCS#10 way. A key that
|
|
1817
|
+
* can only sign has no such problem, so a request to certify one through that attribute asks for the
|
|
1818
|
+
* certificate those sentences forbid, whether or not the request names a key usage. Read off the requested
|
|
1819
|
+
* usages alone, the rule missed every request that omitted the keyUsage extension; read off this table
|
|
1820
|
+
* too, the two doors that apply it reach the same verdict on the same request.
|
|
1821
|
+
*
|
|
1822
|
+
* Only the signature-ONLY families are here. RSA and EC can do either, so an RSA or EC subject key says
|
|
1823
|
+
* nothing on its own and is left to the usages a request asks for. `rsassaPss` IS here and
|
|
1824
|
+
* `rsaEncryption` is NOT, which is the distinction the rule turns on: a bare RSA key can do key
|
|
1825
|
+
* transport, while an id-RSASSA-PSS SPKI is restricted to signing and can no more establish a key than
|
|
1826
|
+
* an EdDSA one. `dsa` and the stateful hash-based algorithms sign by construction. */
|
|
1827
|
+
var SIGNATURE_ONLY_KEY_NAMES = [
|
|
1828
|
+
"Ed25519", "Ed448", "rsassaPss", "dsa",
|
|
1829
|
+
"id-alg-hss-lms-hashsig", "id-alg-xmss-hashsig", "id-alg-xmssmt-hashsig",
|
|
1830
|
+
];
|
|
1831
|
+
/** @internal The families, matched by the prefix the registry files them under rather than listed one at a
|
|
1832
|
+
* time: three ML-DSA sets, twelve SLH-DSA sets and eighteen composite ML-DSA arms, all of which sign and
|
|
1833
|
+
* none of which establishes a key. Taking them by family means a set the registry gains later belongs to
|
|
1834
|
+
* this rule without a second edit, which is what kept RSASSA-PSS out of an earlier hand-written list. */
|
|
1835
|
+
var SIGNATURE_ONLY_KEY_PREFIXES = ["id-ml-dsa-", "id-slh-dsa-", "id-MLDSA"];
|
|
1836
|
+
|
|
1837
|
+
var _signatureOnlyByNs = new _WeakMapI();
|
|
1838
|
+
|
|
1839
|
+
/** @internal Whether a dotted subject-key algorithm OID names a signature-only family. Built once per
|
|
1840
|
+
* OID registry and memoized on it, since the registry is enumerated to pick the families up by prefix. */
|
|
1841
|
+
function signatureOnlyKeyOid(ns) {
|
|
1842
|
+
var table = _weakGet(_signatureOnlyByNs, ns.oid);
|
|
1843
|
+
if (table === undefined) {
|
|
1844
|
+
table = _assign(_create(null), {});
|
|
1845
|
+
_forEach(SIGNATURE_ONLY_KEY_NAMES, function (n) {
|
|
1846
|
+
var dotted = ns.oid.byName(n);
|
|
1847
|
+
if (dotted !== undefined && dotted !== null) table[dotted] = n;
|
|
1848
|
+
});
|
|
1849
|
+
var registry = ns.oid.all();
|
|
1850
|
+
_forEach(intrinsic.keys(registry), function (dotted) {
|
|
1851
|
+
var n = registry[dotted];
|
|
1852
|
+
if (typeof n !== "string") return;
|
|
1853
|
+
_forEach(SIGNATURE_ONLY_KEY_PREFIXES, function (p) {
|
|
1854
|
+
if (_strIndexOf(n, p) === 0) table[dotted] = n;
|
|
1855
|
+
});
|
|
1856
|
+
});
|
|
1857
|
+
_weakSet(_signatureOnlyByNs, ns.oid, table);
|
|
1858
|
+
}
|
|
1859
|
+
return function (dotted) {
|
|
1860
|
+
return typeof dotted === "string" && _hasOwn(table, dotted);
|
|
1861
|
+
};
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1714
1864
|
function certExtensionDecoders(ns) {
|
|
1715
1865
|
var GN_SUBTREE = generalName(ns, { decodeValue: true, subtreeBase: true, code: ns.prefix + "/bad-name-constraints" });
|
|
1716
1866
|
var _h = _decodeHelpers(ns), decodeTop = _h.decodeTop, seqChildren = _h.seqChildren, readInt = _h.readInt, O = _h.O;
|
|
@@ -1913,6 +2063,67 @@ function certExtensionDecoders(ns) {
|
|
|
1913
2063
|
return null;
|
|
1914
2064
|
}
|
|
1915
2065
|
|
|
2066
|
+
/** @internal RelatedCertificate ::= SEQUENCE { hashAlgorithm DigestAlgorithmIdentifier,
|
|
2067
|
+
* hashValue OCTET STRING } (RFC 9763 sec. 4.1), the digest of "the entire related certificate".
|
|
2068
|
+
* The value is held to the length of the algorithm it names, since a hash of the wrong length for
|
|
2069
|
+
* its own algorithm identifies no certificate and would otherwise be carried forward as an
|
|
2070
|
+
* identity to compare against. */
|
|
2071
|
+
function relatedCertificate(buf) {
|
|
2072
|
+
var C = ns.prefix + "/bad-extension-value";
|
|
2073
|
+
var kids = seqChildren(buf, C, "RelatedCertificate");
|
|
2074
|
+
if (kids.length !== 2) throw ns.E(C, "RelatedCertificate must be a SEQUENCE { hashAlgorithm, hashValue } (RFC 9763 sec. 4.1)");
|
|
2075
|
+
var alg;
|
|
2076
|
+
try { alg = schema.walk(algorithmIdentifier(ns), kids[0], ns).result; }
|
|
2077
|
+
catch (e) { throw ns.E(C, "RelatedCertificate hashAlgorithm must be a DigestAlgorithmIdentifier (RFC 9763 sec. 4.1)", e); }
|
|
2078
|
+
var value;
|
|
2079
|
+
try { value = _bufferFrom(asn1.read.octetString(kids[1])); }
|
|
2080
|
+
catch (e) { throw ns.E(C, "RelatedCertificate hashValue must be an OCTET STRING (RFC 9763 sec. 4.1)", e); }
|
|
2081
|
+
if (value.length === 0) throw ns.E(C, "RelatedCertificate hashValue must not be empty (RFC 9763 sec. 4.1)");
|
|
2082
|
+
var want = DIGEST_LENGTHS[alg.name];
|
|
2083
|
+
if (want !== undefined && value.length !== want) {
|
|
2084
|
+
throw ns.E(C, "RelatedCertificate hashValue is " + value.length + " octets, and " + alg.name + " produces " + want);
|
|
2085
|
+
}
|
|
2086
|
+
return { hashAlgorithm: alg.name, hashAlgorithmOid: alg.oid, hashValue: value };
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
/** @internal SubjectAltPublicKeyInfo ::= SEQUENCE { algorithm AlgorithmIdentifier,
|
|
2090
|
+
* subjectAltPublicKey BIT STRING } (ITU-T X.509 (2019) clause 9.8.2). Those are the two components
|
|
2091
|
+
* SubjectPublicKeyInfo has, in that order, and a field name is not encoded, so the two types share
|
|
2092
|
+
* one encoding and this reads through the shared SPKI sub-schema. The whole value is surfaced as
|
|
2093
|
+
* `bytes` because it IS an SPKI on the wire: an importer takes it unchanged. */
|
|
2094
|
+
function subjectAltPublicKeyInfo(buf) {
|
|
2095
|
+
var C = ns.prefix + "/bad-extension-value";
|
|
2096
|
+
var n = decodeTop(buf, C, "SubjectAltPublicKeyInfo");
|
|
2097
|
+
var v;
|
|
2098
|
+
try { v = schema.walk(spki(ns), n, ns).result; }
|
|
2099
|
+
catch (e) { throw ns.E(C, "SubjectAltPublicKeyInfo must be a SEQUENCE { algorithm, subjectAltPublicKey BIT STRING } (ITU-T X.509 (2019) clause 9.8.2)", e); }
|
|
2100
|
+
if (v.publicKey.unusedBits !== 0) throw ns.E(C, "the subjectAltPublicKey BIT STRING must hold whole octets");
|
|
2101
|
+
if (v.publicKey.bytes.length === 0) throw ns.E(C, "the subjectAltPublicKey must not be empty");
|
|
2102
|
+
return { algorithm: v.algorithm, subjectAltPublicKey: v.publicKey.bytes, bytes: v.bytes };
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
/** @internal AltSignatureAlgorithm ::= AlgorithmIdentifier (clause 9.8.3). The extension value is the
|
|
2106
|
+
* AlgorithmIdentifier itself, not a SEQUENCE wrapping one. */
|
|
2107
|
+
function altSignatureAlgorithm(buf) {
|
|
2108
|
+
var C = ns.prefix + "/bad-extension-value";
|
|
2109
|
+
var n = decodeTop(buf, C, "AltSignatureAlgorithm");
|
|
2110
|
+
try { return schema.walk(algorithmIdentifier(ns), n, ns).result; }
|
|
2111
|
+
catch (e) { throw ns.E(C, "AltSignatureAlgorithm must be an AlgorithmIdentifier (ITU-T X.509 (2019) clause 9.8.3)", e); }
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
/** @internal AltSignatureValue ::= BIT STRING (clause 9.8.4). Held to whole octets, a signature being
|
|
2115
|
+
* an octet string of bits and every algorithm here producing one. */
|
|
2116
|
+
function altSignatureValue(buf) {
|
|
2117
|
+
var C = ns.prefix + "/bad-extension-value";
|
|
2118
|
+
var n = decodeTop(buf, C, "AltSignatureValue");
|
|
2119
|
+
var bs;
|
|
2120
|
+
try { bs = asn1.read.bitString(n); }
|
|
2121
|
+
catch (e) { throw ns.E(C, "AltSignatureValue must be a BIT STRING (ITU-T X.509 (2019) clause 9.8.4)", e); }
|
|
2122
|
+
if (bs.unusedBits !== 0) throw ns.E(C, "the AltSignatureValue BIT STRING must hold whole octets");
|
|
2123
|
+
if (bs.bytes.length === 0) throw ns.E(C, "the AltSignatureValue must not be empty");
|
|
2124
|
+
return { unusedBits: bs.unusedBits, bytes: _bufferFrom(bs.bytes) };
|
|
2125
|
+
}
|
|
2126
|
+
|
|
1916
2127
|
function extKeyUsage(buf) {
|
|
1917
2128
|
var C = ns.prefix + "/bad-extension-value";
|
|
1918
2129
|
var kids = seqChildren(buf, C, "ExtKeyUsage");
|
|
@@ -2270,6 +2481,10 @@ function certExtensionDecoders(ns) {
|
|
|
2270
2481
|
byOid[O("subjectInfoAccess")] = subjectInfoAccess;
|
|
2271
2482
|
byOid[O("subjectDirectoryAttributes")] = subjectDirectoryAttributes;
|
|
2272
2483
|
byOid[O("ocspNoCheck")] = ocspNoCheck;
|
|
2484
|
+
byOid[O("relatedCertificate")] = relatedCertificate;
|
|
2485
|
+
byOid[O("subjectAltPublicKeyInfo")] = subjectAltPublicKeyInfo;
|
|
2486
|
+
byOid[O("altSignatureAlgorithm")] = altSignatureAlgorithm;
|
|
2487
|
+
byOid[O("altSignatureValue")] = altSignatureValue;
|
|
2273
2488
|
byOid[O("msCertificateTemplate")] = msCertificateTemplate;
|
|
2274
2489
|
byOid[O("msEnrollCertType")] = msEnrollCertType;
|
|
2275
2490
|
byOid[O("msCaVersion")] = msCaVersion;
|
|
@@ -2377,6 +2592,12 @@ function signedEnvelope(ns, tbsSchema, opts) {
|
|
|
2377
2592
|
schema.field("signatureAlgorithm", algorithmIdentifier(ns)),
|
|
2378
2593
|
schema.field("signatureValue", schema.bitString()),
|
|
2379
2594
|
], {
|
|
2595
|
+
/** @internal Exactly three, with no trailing element. X.509 (2019) extended the SIGNED
|
|
2596
|
+
* parameterized type with optional `altAlgorithmIdentifier` and `altSignature` components after
|
|
2597
|
+
* the signature, and then forbade them for every structure it profiles: "only one digital
|
|
2598
|
+
* signature shall be generated, i.e., the altAlgorithmIdentifier and the altSignature components
|
|
2599
|
+
* shall be absent" (clauses 7.2.1, 7.10.2, 11.3 and 14.2). Declaring either as an optional field
|
|
2600
|
+
* here would admit a second signature the text excludes, in every format that composes this. */
|
|
2380
2601
|
assert: "sequence", arity: { exact: 3 }, code: opts.code, what: opts.what,
|
|
2381
2602
|
build: function (m, ctx) {
|
|
2382
2603
|
var tbsMatch = m.fields.toBeSigned.value;
|
|
@@ -2452,6 +2673,9 @@ module.exports = {
|
|
|
2452
2673
|
DN_SHORT: DN_SHORT,
|
|
2453
2674
|
time: time,
|
|
2454
2675
|
algorithmIdentifier: algorithmIdentifier,
|
|
2676
|
+
issuerAndSerialNumber: issuerAndSerialNumber,
|
|
2677
|
+
digestLengths: digestLengths,
|
|
2678
|
+
signatureDigestNames: signatureDigestNames,
|
|
2455
2679
|
pbkdf2Params: pbkdf2Params,
|
|
2456
2680
|
pbmac1Params: pbmac1Params,
|
|
2457
2681
|
spki: spki,
|
|
@@ -2484,6 +2708,8 @@ module.exports = {
|
|
|
2484
2708
|
crlFixedCriticality: crlFixedCriticality,
|
|
2485
2709
|
crlEntryFixedCriticality: crlEntryFixedCriticality,
|
|
2486
2710
|
certExtensionDecoders: certExtensionDecoders,
|
|
2711
|
+
keyUsagePermits: keyUsagePermits,
|
|
2712
|
+
signatureOnlyKeyOid: signatureOnlyKeyOid,
|
|
2487
2713
|
scopedCertDecoder: scopedCertDecoder,
|
|
2488
2714
|
crlExtensionDecoders: crlExtensionDecoders,
|
|
2489
2715
|
decodeExtensionList: decodeExtensionList,
|