@blamejs/pki 0.8.31 → 0.8.48
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 +393 -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 +939 -48
- 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/csr-sign.js
CHANGED
|
@@ -25,12 +25,22 @@ var pkix = require("./schema-pkix");
|
|
|
25
25
|
var pkiBuild = require("./pki-build");
|
|
26
26
|
var frameworkError = require("./framework-error");
|
|
27
27
|
var guard = require("./guard-all");
|
|
28
|
+
var intrinsic = require("./guard-intrinsic");
|
|
29
|
+
/** @internal The promise a self-check is awaited through, built from the constructor captured at load.
|
|
30
|
+
* `Promise.resolve` builds from its RECEIVER, so reading the global binding at the call hands the
|
|
31
|
+
* construction to whatever that binding holds, and a constructor settling without awaiting its
|
|
32
|
+
* argument runs the continuation before the check has finished. */
|
|
33
|
+
var _Promise = intrinsic.Promise;
|
|
34
|
+
var _promiseResolve = intrinsic.uncurry(intrinsic.promiseResolve);
|
|
28
35
|
require("./path-validate");
|
|
29
36
|
var csrVerify = require("./csr-verify");
|
|
37
|
+
var relatedCert = require("./related-cert");
|
|
38
|
+
var possession = require("./possession");
|
|
39
|
+
var x509Schema = require("./schema-x509");
|
|
30
40
|
var lint = require("./lint");
|
|
31
41
|
|
|
32
42
|
var CsrError = frameworkError.CsrError;
|
|
33
|
-
var KNOWN_SPEC_KEYS = Object.assign(Object.create(null), { subject: 1, subjectPublicKey: 1, extensionRequest: 1, challengePassword: 1, attributes: 1 });
|
|
43
|
+
var KNOWN_SPEC_KEYS = Object.assign(Object.create(null), { subject: 1, subjectPublicKey: 1, extensionRequest: 1, challengePassword: 1, relatedCertRequest: 1, privateKeyPossessionStatement: 1, attributes: 1 });
|
|
34
44
|
/** @internal The four this verb reads, which are the four `pki.x509.sign` reads. A name outside
|
|
35
45
|
* them was accepted and dropped, so asking for PEM and misspelling the option returned DER and
|
|
36
46
|
* reported nothing. */
|
|
@@ -53,7 +63,11 @@ var _b = pkiBuild.makeBuilder({
|
|
|
53
63
|
});
|
|
54
64
|
|
|
55
65
|
function _implicitSetOf0(members) {
|
|
56
|
-
|
|
66
|
+
/** @internal The copy, the DER SET-OF ordering AND the comparator go through captured operations.
|
|
67
|
+
* Read off their own homes, `slice`, `sort` and `Buffer.compare` each decide the bytes emitted:
|
|
68
|
+
* measured, replacing any of them made this set encode an attribute other than the one just
|
|
69
|
+
* validated, on bytes this verb then signs. */
|
|
70
|
+
return b.contextConstructed(0, Buffer.concat(guard.list.sortedCopy(members, guard.bytes.compare)));
|
|
57
71
|
}
|
|
58
72
|
|
|
59
73
|
function _buildRequestedExtensions(extSpec, subjectSpki) { return _b.requestedExtensions(extSpec, subjectSpki); }
|
|
@@ -63,6 +77,80 @@ function _challengePassword(pw) {
|
|
|
63
77
|
return asn1.isPrintableString(pw) ? b.printable(pw) : b.utf8(pw);
|
|
64
78
|
}
|
|
65
79
|
|
|
80
|
+
var KNOWN_POSSESSION_KEYS = Object.assign(Object.create(null), { signer: 1, certificate: 1, includeCertificate: 1 });
|
|
81
|
+
/** @internal PrivateKeyPossessionStatement ::= SEQUENCE { signer IssuerAndSerialNumber,
|
|
82
|
+
* cert Certificate OPTIONAL } (RFC 9883 sec. 3). The statement declares that this request is signed by
|
|
83
|
+
* a key OTHER than the one being certified, which is what lets a key-establishment key be certified at
|
|
84
|
+
* all: it cannot sign, so it cannot prove possession the PKCS#10 way. A carried certificate must be the
|
|
85
|
+
* one the signer names, since the two would otherwise describe different keys and only one of them
|
|
86
|
+
* signed. */
|
|
87
|
+
function _possessionStatement(spec) {
|
|
88
|
+
if (spec === null || typeof spec !== "object" || Buffer.isBuffer(spec)) {
|
|
89
|
+
throw _err("csr/bad-input", "privateKeyPossessionStatement must be an object { signer, certificate? }");
|
|
90
|
+
}
|
|
91
|
+
guard.identifier.assertKnownKeys(spec, KNOWN_POSSESSION_KEYS, _err, "csr/bad-input",
|
|
92
|
+
"privateKeyPossessionStatement has an unknown field: ");
|
|
93
|
+
var signer = spec.signer;
|
|
94
|
+
if (signer === null || typeof signer !== "object" || Buffer.isBuffer(signer)) {
|
|
95
|
+
throw _err("csr/bad-input", "privateKeyPossessionStatement needs a signer naming the signature certificate's issuer and serial (RFC 9883 sec. 3)");
|
|
96
|
+
}
|
|
97
|
+
var issuerRaw = (signer.issuer !== null && typeof signer.issuer === "object" && !Buffer.isBuffer(signer.issuer) &&
|
|
98
|
+
signer.issuer.bytes !== undefined) ? signer.issuer.bytes : signer.issuer;
|
|
99
|
+
var issuerDer = _b.reqDer(issuerRaw, "privateKeyPossessionStatement signer.issuer (the signature certificate's issuer Name DER)");
|
|
100
|
+
var serial = guard.range.authoredInteger(signer.serialNumber, _err, "csr/bad-input",
|
|
101
|
+
"privateKeyPossessionStatement signer.serialNumber");
|
|
102
|
+
if (serial < 1n) throw _err("csr/bad-input", "privateKeyPossessionStatement signer.serialNumber must be a positive integer (RFC 5280 sec. 4.1.2.2)");
|
|
103
|
+
|
|
104
|
+
/** @internal The certificate is required HERE even though RFC 9883 sec. 3 lets the wire form omit it,
|
|
105
|
+
* because this verb has to know which key signs: it resolves the signature algorithm from that key and
|
|
106
|
+
* checks its own signature against it. The omission the RFC allows is for the CA's benefit, and a
|
|
107
|
+
* requester holding the signing key holds its certificate too, so `includeCertificate: false` emits
|
|
108
|
+
* the compact form while the builder still knows the key. */
|
|
109
|
+
if (spec.certificate == null) {
|
|
110
|
+
throw _err("csr/bad-input",
|
|
111
|
+
"privateKeyPossessionStatement needs the certificate: this verb resolves the signature algorithm from its key and checks the signature against it. Pass includeCertificate: false to leave it off the wire, which RFC 9883 sec. 3 allows");
|
|
112
|
+
}
|
|
113
|
+
var certDer = _b.reqDer(spec.certificate, "privateKeyPossessionStatement certificate");
|
|
114
|
+
var include = spec.includeCertificate === undefined ? true : spec.includeCertificate;
|
|
115
|
+
if (include !== true && include !== false) {
|
|
116
|
+
throw _err("csr/bad-input", "privateKeyPossessionStatement includeCertificate is a flag, so it is true, false or omitted");
|
|
117
|
+
}
|
|
118
|
+
var signerIsn = b.sequence([b.raw(issuerDer), b.integer(serial)]);
|
|
119
|
+
/** @internal Read back through the one statement reader with the certificate ALWAYS present, so the
|
|
120
|
+
* shape rule and the signer-names-the-certificate rule are applied by the same code a consumer
|
|
121
|
+
* applies. The emitted form may then drop it; dropping it cannot make a checked statement wrong. */
|
|
122
|
+
try { possession.parse(b.sequence([signerIsn, b.raw(certDer)])); }
|
|
123
|
+
catch (e) { throw _err("csr/bad-input", "privateKeyPossessionStatement: " + ((e && e.message) || String(e)), e); }
|
|
124
|
+
return { der: b.sequence(include ? [signerIsn, b.raw(certDer)] : [signerIsn]), certificate: certDer };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
var KNOWN_RELATED_CERT_KEYS = Object.assign(Object.create(null), { certID: 1, requestTime: 1, locationInfo: 1, signature: 1 });
|
|
128
|
+
/** @internal RequesterCertificate ::= SEQUENCE { certID IssuerAndSerialNumber, requestTime BinaryTime,
|
|
129
|
+
* locationInfo UniformResourceIdentifiers, signature BIT STRING } (RFC 9763 sec. 3.1), where
|
|
130
|
+
* UniformResourceIdentifiers ::= SEQUENCE SIZE (1..MAX) OF IA5String. The first two fields are the
|
|
131
|
+
* ones the signature covers, so they are encoded by the module that defines that preimage rather than
|
|
132
|
+
* a second time here: an encoder that disagreed with it would produce a proof no verifier accepts. */
|
|
133
|
+
function _relatedCertRequest(spec) {
|
|
134
|
+
if (spec === null || typeof spec !== "object" || Buffer.isBuffer(spec)) throw _err("csr/bad-input", "relatedCertRequest must be an object { certID, requestTime, locationInfo, signature }");
|
|
135
|
+
guard.identifier.assertKnownKeys(spec, KNOWN_RELATED_CERT_KEYS, _err, "csr/bad-input", "relatedCertRequest has an unknown field: ");
|
|
136
|
+
var signed;
|
|
137
|
+
try { signed = relatedCert.requestSignedData({ certID: spec.certID, requestTime: spec.requestTime }); }
|
|
138
|
+
catch (e) { throw _err("csr/bad-input", "relatedCertRequest certID and requestTime: " + ((e && e.message) || String(e)), e); }
|
|
139
|
+
|
|
140
|
+
var locations = spec.locationInfo;
|
|
141
|
+
if (!Array.isArray(locations)) throw _err("csr/bad-input", "relatedCertRequest locationInfo must be an array of URI strings (RFC 9763 sec. 3.1)");
|
|
142
|
+
if (locations.length < 1) throw _err("csr/bad-input", "relatedCertRequest locationInfo must name at least one URI (SEQUENCE SIZE (1..MAX))");
|
|
143
|
+
var uris = guard.list.copyMap(locations, function (u, i) {
|
|
144
|
+
if (typeof u !== "string" || u.length === 0) throw _err("csr/bad-input", "relatedCertRequest locationInfo[" + i + "] must be a non-empty URI string");
|
|
145
|
+
if (!guard.encoding.isAsciiText(u)) throw _err("csr/bad-input", "relatedCertRequest locationInfo[" + i + "] must be an IA5String, so every character is ASCII (RFC 9763 sec. 3.1)");
|
|
146
|
+
return b.ia5(u);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
var sig = _b.reqDer(spec.signature, "relatedCertRequest signature (the proof of possession over pki.relatedCert.requestSignedData)");
|
|
150
|
+
if (sig.length === 0) throw _err("csr/bad-input", "relatedCertRequest signature must not be empty");
|
|
151
|
+
return b.sequence([b.raw(signed), b.sequence(uris), b.bitString(sig, 0)]);
|
|
152
|
+
}
|
|
153
|
+
|
|
66
154
|
/**
|
|
67
155
|
* @primitive pki.csr.sign
|
|
68
156
|
* @signature pki.csr.sign(spec, key, opts?) -> Promise<Buffer|string>
|
|
@@ -140,9 +228,22 @@ function _sign(spec, key, opts) {
|
|
|
140
228
|
}
|
|
141
229
|
if (spec.extensionRequest != null) addAttr(O("extensionRequest"), _buildRequestedExtensions(spec.extensionRequest, subjectSpki));
|
|
142
230
|
if (spec.challengePassword != null) addAttr(O("challengePassword"), _challengePassword(spec.challengePassword));
|
|
231
|
+
if (spec.relatedCertRequest != null) addAttr(O("relatedCertRequest"), _relatedCertRequest(spec.relatedCertRequest));
|
|
232
|
+
/** @internal The statement, and the key its certificate carries: the signature is made by that key, so
|
|
233
|
+
* the scheme below resolves from it. A statement that omits the certificate leaves the signing key
|
|
234
|
+
* unverifiable here, since there is nothing to check it against, so the certificate is required at
|
|
235
|
+
* build time even though RFC 9883 sec. 3 lets the wire form omit it. */
|
|
236
|
+
var possessionCertSpki = null;
|
|
237
|
+
if (spec.privateKeyPossessionStatement != null) {
|
|
238
|
+
var statement = _possessionStatement(spec.privateKeyPossessionStatement);
|
|
239
|
+
addAttr(O("statementOfPossession"), b.raw(statement.der));
|
|
240
|
+
possessionCertSpki = x509Schema.parse(statement.certificate).subjectPublicKeyInfo.bytes;
|
|
241
|
+
}
|
|
143
242
|
if (spec.attributes != null) {
|
|
144
243
|
if (!Array.isArray(spec.attributes)) throw _err("csr/bad-input", "spec.attributes must be an array of pre-encoded Attribute DER");
|
|
145
|
-
|
|
244
|
+
/** @internal Through the captured walk, never the caller's own `forEach`: a request's attributes are
|
|
245
|
+
* signed content, and a replaced walk hands the callback a list it never validated. */
|
|
246
|
+
guard.list.copyMap(spec.attributes, function (a, i) {
|
|
146
247
|
var der = _b.reqDer(a, "attribute [" + i + "]");
|
|
147
248
|
var n;
|
|
148
249
|
try { n = asn1.decode(der); }
|
|
@@ -153,6 +254,8 @@ function _sign(spec, key, opts) {
|
|
|
153
254
|
catch (e) { throw _err("csr/bad-input", "pre-encoded attribute [" + i + "] type is not an OBJECT IDENTIFIER", e); }
|
|
154
255
|
if (at === O("extensionRequest")) throw _err("csr/bad-input", "pass requested extensions via spec.extensionRequest, not a pre-encoded extensionRequest attribute");
|
|
155
256
|
if (at === O("challengePassword")) throw _err("csr/bad-input", "pass the challenge password via spec.challengePassword, not a pre-encoded challengePassword attribute");
|
|
257
|
+
if (at === O("relatedCertRequest")) throw _err("csr/bad-input", "pass the related-certificate request via spec.relatedCertRequest, not a pre-encoded relatedCertRequest attribute");
|
|
258
|
+
if (at === O("statementOfPossession")) throw _err("csr/bad-input", "pass the possession statement via spec.privateKeyPossessionStatement, not a pre-encoded statementOfPossession attribute");
|
|
156
259
|
if (!n.children[1].children || n.children[1].children.length === 0) throw _err("csr/bad-input", "pre-encoded attribute [" + i + "] value SET must contain at least one value (RFC 2986 SET SIZE(1..MAX))");
|
|
157
260
|
if (seenAttr[at]) throw _err("csr/bad-input", "duplicate " + (oid.name(at) || at) + " attribute");
|
|
158
261
|
seenAttr[at] = true;
|
|
@@ -160,7 +263,15 @@ function _sign(spec, key, opts) {
|
|
|
160
263
|
});
|
|
161
264
|
}
|
|
162
265
|
|
|
163
|
-
|
|
266
|
+
/** @internal Which key signs, and therefore which key the scheme resolves from. Normally the subject's
|
|
267
|
+
* own, because a PKCS#10 signature IS the proof of possession of the key being certified. With an
|
|
268
|
+
* RFC 9883 statement of possession the signature is made by the key of the certificate the statement
|
|
269
|
+
* names, which is the whole mechanism: a key-establishment key cannot sign, so it cannot prove
|
|
270
|
+
* possession that way. The relaxation is scoped to a request that declares the statement, so a
|
|
271
|
+
* request without one is still held to signing with the key it certifies. */
|
|
272
|
+
var provingSpki = subjectSpki;
|
|
273
|
+
if (possessionCertSpki !== null) provingSpki = possessionCertSpki;
|
|
274
|
+
var scheme = signScheme.resolveSignScheme(_b.certLikeFromSpki(provingSpki), { combinedRsaSig: true, pss: opts.pss, digestAlgorithm: opts.digestAlgorithm }, true, _signE);
|
|
164
275
|
|
|
165
276
|
var criDer = b.sequence([b.integer(0n), subjectDer, b.raw(subjectSpki), _implicitSetOf0(attrs)]);
|
|
166
277
|
lint.assertBuildClean("csr",
|
|
@@ -168,7 +279,7 @@ function _sign(spec, key, opts) {
|
|
|
168
279
|
opts.profile, _err, "csr/profile-violation");
|
|
169
280
|
|
|
170
281
|
return signScheme.signOverTbs(scheme, signingKey, criDer, _signE).then(function (sig) {
|
|
171
|
-
return
|
|
282
|
+
return _promiseResolve(_Promise, _b.assertSignatureVerifies(criDer, sig, provingSpki, scheme)).then(function () {
|
|
172
283
|
var der = b.sequence([criDer, scheme.sigAlgId, b.bitString(sig, 0)]);
|
|
173
284
|
return opts.pem ? csr.pemEncode(der, "CERTIFICATE REQUEST") : der;
|
|
174
285
|
});
|
|
@@ -233,7 +344,7 @@ function _coerceCsr(request) {
|
|
|
233
344
|
function verify(request) { return guard.async.deferred(function () { return _verify(request); }); }
|
|
234
345
|
function _verify(request) {
|
|
235
346
|
var parsed = _coerceCsr(request);
|
|
236
|
-
return
|
|
347
|
+
return _promiseResolve(_Promise, csrVerify.verifyCsrSignature(parsed)).then(function (ok) {
|
|
237
348
|
return guard.verdict.of({
|
|
238
349
|
valid: ok === true,
|
|
239
350
|
verified: ok === true,
|