@blamejs/pki 0.6.14 → 0.6.15
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 +14 -1
- package/lib/acme.js +59 -815
- package/lib/asn1-der.js +7 -245
- package/lib/attrcert-sign.js +12 -260
- package/lib/attrcert-verify.js +1 -7
- package/lib/byte-reader.js +0 -8
- package/lib/byte-writer.js +0 -11
- package/lib/cbor-det.js +0 -54
- package/lib/cmc-build.js +15 -357
- package/lib/cmc-verify.js +6 -239
- package/lib/cmp-build.js +41 -317
- package/lib/cmp-session.js +73 -760
- package/lib/cmp-verify.js +32 -488
- package/lib/cms-compress.js +3 -32
- package/lib/cms-decrypt.js +29 -294
- package/lib/cms-encrypt.js +14 -234
- package/lib/cms-sign.js +29 -324
- package/lib/cms-verify.js +9 -500
- package/lib/composite-kem.js +2 -102
- package/lib/composite-sig.js +1 -77
- package/lib/constants.js +0 -249
- package/lib/crl-sign.js +9 -237
- package/lib/crl-verify.js +1 -10
- package/lib/crmf-sign.js +19 -198
- package/lib/crmf-verify.js +1 -12
- package/lib/csr-sign.js +3 -34
- package/lib/csr-verify.js +1 -12
- package/lib/ct.js +28 -253
- package/lib/edwards-point.js +10 -44
- package/lib/est.js +28 -764
- package/lib/framework-error.js +4 -182
- package/lib/guard-all.js +1 -58
- package/lib/guard-async.js +1 -36
- package/lib/guard-bytes.js +6 -650
- package/lib/guard-compress.js +5 -102
- package/lib/guard-crypto.js +1 -40
- package/lib/guard-der.js +2 -93
- package/lib/guard-encoding.js +2 -60
- package/lib/guard-header.js +1 -36
- package/lib/guard-identifier.js +7 -531
- package/lib/guard-intrinsic.js +1 -150
- package/lib/guard-json.js +10 -73
- package/lib/guard-limits.js +1 -77
- package/lib/guard-list.js +1 -49
- package/lib/guard-name.js +3 -209
- package/lib/guard-parsed.js +7 -335
- package/lib/guard-range.js +1 -71
- package/lib/guard-secret.js +1 -102
- package/lib/guard-text.js +1 -64
- package/lib/guard-time.js +1 -97
- package/lib/hpke.js +3 -105
- package/lib/http-digest.js +14 -142
- package/lib/http-retry-after.js +1 -47
- package/lib/http-transport.js +21 -131
- package/lib/inspect.js +30 -284
- package/lib/ip-utils.js +6 -47
- package/lib/jose.js +7 -142
- package/lib/key.js +2 -67
- package/lib/lint.js +9 -194
- package/lib/merkle.js +1 -27
- package/lib/mime.js +9 -82
- package/lib/ocsp-request-verify.js +1 -14
- package/lib/ocsp-verify.js +1 -82
- package/lib/ocsp.js +11 -169
- package/lib/oid.js +5 -337
- package/lib/path-validate.js +103 -1492
- package/lib/pbes2.js +2 -89
- package/lib/pkcs12-build.js +31 -379
- package/lib/pki-build.js +64 -290
- package/lib/rc2.js +2 -18
- package/lib/rfc3339.js +4 -27
- package/lib/scep.js +8 -252
- package/lib/schema-all.js +0 -122
- package/lib/schema-attrcert.js +4 -146
- package/lib/schema-c509.js +153 -802
- package/lib/schema-cmc.js +5 -220
- package/lib/schema-cmp.js +2 -223
- package/lib/schema-cms.js +13 -427
- package/lib/schema-crl.js +5 -68
- package/lib/schema-crmf.js +6 -167
- package/lib/schema-csr.js +1 -54
- package/lib/schema-csrattrs.js +2 -87
- package/lib/schema-engine.js +0 -152
- package/lib/schema-ocsp.js +0 -117
- package/lib/schema-pkcs12.js +2 -93
- package/lib/schema-pkcs8.js +3 -35
- package/lib/schema-pkix.js +24 -655
- package/lib/schema-smime.js +0 -54
- package/lib/schema-tsp.js +3 -99
- package/lib/schema-x509.js +4 -63
- package/lib/shbs.js +11 -95
- package/lib/sign-scheme.js +2 -97
- package/lib/sigstore.js +9 -169
- package/lib/sleep.js +2 -8
- package/lib/smime.js +15 -408
- package/lib/tls-cert-compress.js +0 -62
- package/lib/trust.js +19 -185
- package/lib/tsp-sign.js +16 -270
- package/lib/validator-all.js +1 -30
- package/lib/validator-attcert.js +2 -46
- package/lib/validator-cose.js +2 -153
- package/lib/validator-keydesc.js +1 -37
- package/lib/validator-sig.js +1 -46
- package/lib/validator-tls.js +1 -88
- package/lib/validator-tpm.js +19 -122
- package/lib/verify-seam.js +1 -24
- package/lib/webauthn-mds.js +3 -400
- package/lib/webauthn.js +12 -833
- package/lib/webcrypto.js +5 -485
- package/lib/x509-sign.js +4 -108
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/x509-sign.js
CHANGED
|
@@ -15,12 +15,6 @@
|
|
|
15
15
|
* @spec RFC 5280
|
|
16
16
|
* @card Build and sign an X.509 certificate, self-signed or CA-signed, over any registry algorithm.
|
|
17
17
|
*/
|
|
18
|
-
//
|
|
19
|
-
// The whole algorithm matrix comes from the shared sign-scheme resolver (the same registry
|
|
20
|
-
// pki.cms.sign / pki.tsp.sign drive), so a new algorithm is a registry row, never a branch here. The
|
|
21
|
-
// TBS + extension DER is hand-assembled through the canonical asn1.build.* layer (the shipped
|
|
22
|
-
// cms/tsp/ocsp producing pattern); the strict schema-x509 decoder round-trips it, and that round-trip
|
|
23
|
-
// (plus OpenSSL interop) is the divergence guard.
|
|
24
18
|
|
|
25
19
|
var asn1 = require("./asn1-der");
|
|
26
20
|
var oid = require("./oid");
|
|
@@ -28,9 +22,6 @@ var x509 = require("./schema-x509");
|
|
|
28
22
|
var signScheme = require("./sign-scheme");
|
|
29
23
|
var guard = require("./guard-all");
|
|
30
24
|
var intrinsic = require("./guard-intrinsic");
|
|
31
|
-
// This test picks which FORM the caller's extension spec is in, so it decides which fields are read
|
|
32
|
-
// and therefore what is signed into the certificate. Read live, a replacement answering true sends
|
|
33
|
-
// an object down the list arm and the extensions it carries are never seen.
|
|
34
25
|
var _isArray = intrinsic.isArray;
|
|
35
26
|
var frameworkError = require("./framework-error");
|
|
36
27
|
var schema = require("./schema-engine");
|
|
@@ -38,43 +29,20 @@ var pkix = require("./schema-pkix");
|
|
|
38
29
|
var pkiBuild = require("./pki-build");
|
|
39
30
|
|
|
40
31
|
var CertificateError = frameworkError.CertificateError;
|
|
41
|
-
// The x509 schema namespace and Name parser: the same RDNSequence parser pki.schema.x509.parse uses, so
|
|
42
|
-
// a raw Name DER is validated fully (structure, DirectoryString types) with the frozen x509/* codes.
|
|
43
32
|
var NS = pkix.makeNS("x509", CertificateError, oid);
|
|
44
33
|
var NAME_SCHEMA = pkix.name(NS);
|
|
45
34
|
var SPKI_SCHEMA = pkix.spki(NS);
|
|
46
|
-
// The same RFC 5280 sec. 4.2.1 extension value decoders pki.schema.x509.parse uses, so a recognized
|
|
47
|
-
// pre-encoded (array-form) extension is fully validated with the frozen x509/* codes.
|
|
48
35
|
var EXT_DECODERS = pkix.certExtensionDecoders(NS).byOid;
|
|
49
36
|
var b = asn1.build;
|
|
50
|
-
// Two error factories (cms-sign.js pattern): `_err` takes a full x509/* code; `_signE` prepends the
|
|
51
|
-
// domain so the shared sign-scheme resolver/signer faults keep the x509/* codes. Both are FACTORIES
|
|
52
|
-
// -- guard.time.assertValid and resolveSignScheme invoke them as `E(code, msg)` with no `new`.
|
|
53
37
|
function _err(code, message, cause) { return new CertificateError(code, message, cause); }
|
|
54
38
|
function _signE(kind, message, cause) { return new CertificateError("x509/" + kind, message, cause); }
|
|
55
39
|
function O(n) { return oid.byName(n); }
|
|
56
40
|
|
|
57
41
|
var OID_SKI = O("subjectKeyIdentifier");
|
|
58
42
|
|
|
59
|
-
// The recognized keys of the `extensions` spec object; an unknown key is a typo and throws at
|
|
60
|
-
// config-time (a custom extension is passed as pre-encoded DER via the array form).
|
|
61
|
-
// The three caller-owned objects pki.x509.sign reads, each with its own door. A key nothing here
|
|
62
|
-
// names is a typo or a misplaced argument, and the failure it causes is invisible: the certificate
|
|
63
|
-
// builds, signs, and simply does not carry what was asked for. `spec.extension` (one letter short
|
|
64
|
-
// of `extensions`) emitted a certificate with NO extensions at all -- no basicConstraints on an
|
|
65
|
-
// intended CA, no keyUsage on an intended constrained leaf. `spec.issuer` is the other shape: the
|
|
66
|
-
// issuer is argument TWO, and nesting it in the spec left the certificate SELF-SIGNED with nothing
|
|
67
|
-
// to read as a failure.
|
|
68
|
-
//
|
|
69
|
-
// Every table is derived from what the function actually reads, not from the doc block, because a
|
|
70
|
-
// table naming a key nothing reads reopens the hole it was added to close.
|
|
71
43
|
var KNOWN_SPEC_KEYS = {
|
|
72
44
|
subject: 1, subjectPublicKey: 1, notBefore: 1, notAfter: 1, serialNumber: 1, extensions: 1,
|
|
73
45
|
};
|
|
74
|
-
// The issuer names itself in one of two FORMS, and the cert form wins unconditionally: when
|
|
75
|
-
// `issuer.cert` is present the builder takes the DN and the public key from it and never reads
|
|
76
|
-
// `name` or `publicKey`. A union accepted `{ key, cert, name: "Different CA", publicKey }` and
|
|
77
|
-
// signed under the certificate's identity while discarding the identity the caller wrote out.
|
|
78
46
|
var KNOWN_ISSUER_CERT_KEYS = { key: 1, cert: 1 };
|
|
79
47
|
var KNOWN_ISSUER_EXPLICIT_KEYS = { key: 1, name: 1, publicKey: 1 };
|
|
80
48
|
var KNOWN_SIGN_OPTS = { digestAlgorithm: 1, pem: 1, pss: 1 };
|
|
@@ -85,9 +53,6 @@ var KNOWN_EXT_KEYS = {
|
|
|
85
53
|
certificatePolicies: 1, certificatePoliciesCritical: 1,
|
|
86
54
|
};
|
|
87
55
|
|
|
88
|
-
// The shared PKIX producing primitives (lib/pki-build.js), bound to the x509 namespace so they keep the
|
|
89
|
-
// frozen x509/* codes. Thin local aliases let the x509 call sites read unchanged. csr-sign binds the same
|
|
90
|
-
// builder to its own namespace: one encode definition, no per-format hand-roll.
|
|
91
56
|
var _b = pkiBuild.makeBuilder({ ErrorClass: CertificateError, prefix: "x509", O: O, NS: NS, NAME_SCHEMA: NAME_SCHEMA, SPKI_SCHEMA: SPKI_SCHEMA, EXT_DECODERS: EXT_DECODERS });
|
|
92
57
|
var _encodeName = _b.encodeName, _isEmptyName = _b.isEmptyName, _reqDer = _b.reqDer,
|
|
93
58
|
_assertValidSpki = _b.assertValidSpki, _assertValidExtension = _b.assertValidExtension,
|
|
@@ -97,11 +62,10 @@ var _encodeName = _b.encodeName, _isEmptyName = _b.isEmptyName, _reqDer = _b.req
|
|
|
97
62
|
_extAki = _b.extAki, _extSan = _b.extSan, _extCertPolicies = _b.extCertPolicies,
|
|
98
63
|
_skiKeyId = _b.skiKeyId, _spkiKeyId = _b.spkiKeyId, _serialInteger = _b.serialInteger;
|
|
99
64
|
|
|
100
|
-
// ---- issuer-side extension helpers (subjectKeyIdentifier lookup + authorityKeyIdentifier) ----
|
|
101
65
|
|
|
102
66
|
function _skiValueOf(caCert) {
|
|
103
67
|
var ext = (caCert.extensions || []).filter(function (e) { return e.oid === OID_SKI; })[0];
|
|
104
|
-
if (ext) { try { return asn1.read.octetString(asn1.decode(ext.value)); } catch (_e) {
|
|
68
|
+
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
|
|
105
69
|
return null;
|
|
106
70
|
}
|
|
107
71
|
function _akiKeyId(val, ctx) {
|
|
@@ -113,14 +77,9 @@ function _akiKeyId(val, ctx) {
|
|
|
113
77
|
throw _err("x509/bad-input", "authorityKeyIdentifier must be true (auto-derive from the issuer) or a Buffer key id");
|
|
114
78
|
}
|
|
115
79
|
|
|
116
|
-
// Build the extensions [3] block from the spec object (or pass through an array of pre-encoded
|
|
117
|
-
// Extension DER buffers). Enforces the RFC 5280 CA cross-field gates, then emits a deterministic order.
|
|
118
80
|
function _buildExtensions(extSpec, ctx) {
|
|
119
81
|
if (extSpec == null) return [];
|
|
120
82
|
if (_isArray(extSpec)) {
|
|
121
|
-
// Validate each pre-encoded extension, reject a duplicate extnID (RFC 5280 sec. 4.2 allows at most one
|
|
122
|
-
// instance of an extension), and decode basicConstraints + keyUsage to apply the same CA
|
|
123
|
-
// cross-field rules the object form enforces (below), so the array escape hatch cannot bypass them.
|
|
124
83
|
var seenExt = {}, arrCa = false, arrKeyCertSign = false, arrPathLen = false;
|
|
125
84
|
var oidBc = O("basicConstraints"), oidKu = O("keyUsage");
|
|
126
85
|
var arr = extSpec.map(function (e, i) {
|
|
@@ -130,9 +89,6 @@ function _buildExtensions(extSpec, ctx) {
|
|
|
130
89
|
var extnId = asn1.read.oid(n.children[0]);
|
|
131
90
|
if (seenExt[extnId]) throw _err("x509/bad-input", "duplicate extension " + extnId + " in the extensions array (RFC 5280 sec. 4.2 -- at most one instance of an extension)");
|
|
132
91
|
seenExt[extnId] = true;
|
|
133
|
-
// Fully validate a RECOGNIZED extension by running its real value decoder (which enforces the
|
|
134
|
-
// RFC 5280 sec. 4.2.1 rules and throws a typed x509/* on malformed), and take the CA cross-field
|
|
135
|
-
// inputs from the decoded value; an unrecognized extension is opaque (the caller's own concern).
|
|
136
92
|
var dec = EXT_DECODERS[extnId];
|
|
137
93
|
if (dec) {
|
|
138
94
|
var decoded;
|
|
@@ -143,8 +99,6 @@ function _buildExtensions(extSpec, ctx) {
|
|
|
143
99
|
}
|
|
144
100
|
if (extnId === oidBc) {
|
|
145
101
|
arrCa = decoded.cA === true; arrPathLen = decoded.pathLenConstraint != null;
|
|
146
|
-
// RFC 5280 sec. 4.2.1.9 -- a CA's basicConstraints MUST be critical (3 children = an explicit
|
|
147
|
-
// TRUE critical flag, since _assertValidExtension already rejects an explicit FALSE).
|
|
148
102
|
if (arrCa && n.children.length !== 3) throw _err("x509/bad-input", "a CA certificate's basicConstraints MUST be critical (RFC 5280 sec. 4.2.1.9)");
|
|
149
103
|
}
|
|
150
104
|
else if (extnId === oidKu) { arrKeyCertSign = decoded.keyCertSign === true; }
|
|
@@ -156,8 +110,6 @@ function _buildExtensions(extSpec, ctx) {
|
|
|
156
110
|
return arr;
|
|
157
111
|
}
|
|
158
112
|
if (typeof extSpec !== "object") throw _err("x509/bad-input", "extensions must be an object or an array of pre-encoded Extension DER");
|
|
159
|
-
// Reject a typo'd or unsupported extension key at config-time instead of silently dropping it (a
|
|
160
|
-
// misspelled `keyUsag` would otherwise omit keyUsage). A custom extension goes in the array form.
|
|
161
113
|
guard.identifier.assertKnownKeys(extSpec, KNOWN_EXT_KEYS, _err, "x509/bad-input", function (k) {
|
|
162
114
|
return "unknown extension " + JSON.stringify(k) + " in the extensions spec; pass a pre-encoded Extension DER via the array form for a custom extension";
|
|
163
115
|
});
|
|
@@ -167,9 +119,7 @@ function _buildExtensions(extSpec, ctx) {
|
|
|
167
119
|
var caTrue = !!(bc && bc.cA === true);
|
|
168
120
|
var ku = extSpec.keyUsage;
|
|
169
121
|
var assertsKeyCertSign = _isArray(ku) && ku.indexOf("keyCertSign") >= 0;
|
|
170
|
-
// RFC 5280 sec. 4.2.1.3 -- keyCertSign requires basicConstraints cA=TRUE.
|
|
171
122
|
if (assertsKeyCertSign && !caTrue) throw _err("x509/bad-input", "keyUsage keyCertSign requires basicConstraints cA=TRUE (RFC 5280 sec. 4.2.1.3)");
|
|
172
|
-
// RFC 5280 sec. 4.2.1.9 -- pathLenConstraint requires cA=TRUE AND keyCertSign.
|
|
173
123
|
if (bc && bc.pathLen != null) {
|
|
174
124
|
if (!caTrue) throw _err("x509/bad-input", "basicConstraints pathLenConstraint requires cA=TRUE (RFC 5280 sec. 4.2.1.9)");
|
|
175
125
|
if (!assertsKeyCertSign) throw _err("x509/bad-input", "basicConstraints pathLenConstraint requires keyUsage keyCertSign (RFC 5280 sec. 4.2.1.9)");
|
|
@@ -181,7 +131,6 @@ function _buildExtensions(extSpec, ctx) {
|
|
|
181
131
|
if (ku != null) out.push(_ext(O("keyUsage"), extSpec.keyUsageCritical !== false, _extKeyUsage(ku)));
|
|
182
132
|
if (extSpec.extendedKeyUsage != null) out.push(_ext(O("extKeyUsage"), !!extSpec.extendedKeyUsageCritical, _extExtKeyUsage(extSpec.extendedKeyUsage)));
|
|
183
133
|
if (bc != null) {
|
|
184
|
-
// RFC 5280 sec. 4.2.1.9 -- a CA certificate's basicConstraints MUST be critical.
|
|
185
134
|
if (bc.cA === true && bc.critical === false) throw _err("x509/bad-input", "a CA certificate's basicConstraints MUST be critical (RFC 5280 sec. 4.2.1.9)");
|
|
186
135
|
out.push(_ext(O("basicConstraints"), bc.critical !== false, _extBasicConstraints(bc)));
|
|
187
136
|
}
|
|
@@ -190,15 +139,8 @@ function _buildExtensions(extSpec, ctx) {
|
|
|
190
139
|
return out;
|
|
191
140
|
}
|
|
192
141
|
|
|
193
|
-
// ---- serial + validity + key plumbing --------------------------------------
|
|
194
142
|
|
|
195
|
-
// RFC 5280 sec. 4.1.2.5 UTCTime/GeneralizedTime cutover -- the shared builder primitive (pki-build), a
|
|
196
|
-
// thin wrapper here so the certificate validity label reads "certificate notBefore/notAfter".
|
|
197
143
|
function _timeDer(date, which) { return _b.timeDer(date, "certificate " + which); }
|
|
198
|
-
// A supplied issuer certificate MUST be a CA that may sign certificates: basicConstraints present AND
|
|
199
|
-
// critical AND cA=TRUE (RFC 5280 sec. 4.2.1.9), plus, when a keyUsage extension is present, the
|
|
200
|
-
// keyCertSign bit (sec. 4.2.1.3). Refuse a non-CA issuer instead of minting a certificate that will not
|
|
201
|
-
// chain. Returns the issuer's pathLenConstraint (or null) so the caller can honor it.
|
|
202
144
|
function _assertIssuerIsCa(issuerCert) {
|
|
203
145
|
var exts = issuerCert.extensions || [];
|
|
204
146
|
function ext(name) { return exts.filter(function (x) { return x.oid === O(name); })[0] || null; }
|
|
@@ -216,10 +158,8 @@ function _assertIssuerIsCa(issuerCert) {
|
|
|
216
158
|
catch (e) { if (e instanceof CertificateError) throw e; throw _err("x509/bad-input", "the issuer certificate keyUsage is malformed", e); }
|
|
217
159
|
if (ku.keyCertSign !== true) throw _err("x509/bad-input", "the issuer certificate keyUsage does not assert keyCertSign -- it cannot sign certificates (RFC 5280 sec. 4.2.1.3)");
|
|
218
160
|
}
|
|
219
|
-
return bc.pathLenConstraint;
|
|
161
|
+
return bc.pathLenConstraint;
|
|
220
162
|
}
|
|
221
|
-
// The cA flag + pathLenConstraint of the certificate being issued, from either the object or the
|
|
222
|
-
// pre-encoded array extensions form (used to honor a supplied issuer's pathLenConstraint).
|
|
223
163
|
function _issuedCaInfo(extSpec) {
|
|
224
164
|
if (extSpec == null) return { cA: false, pathLen: null };
|
|
225
165
|
if (!_isArray(extSpec)) {
|
|
@@ -234,9 +174,6 @@ function _issuedCaInfo(extSpec) {
|
|
|
234
174
|
}
|
|
235
175
|
return { cA: false, pathLen: null };
|
|
236
176
|
}
|
|
237
|
-
// Does the extensions spec carry a subjectAltName that will be emitted critical? The object form forces
|
|
238
|
-
// SAN critical when the subject is empty (so any subjectAltName qualifies); the pre-encoded array form
|
|
239
|
-
// is decoded to look for an Extension whose extnID is subjectAltName with a TRUE critical flag.
|
|
240
177
|
function _hasCriticalSan(extSpec) {
|
|
241
178
|
if (extSpec == null) return false;
|
|
242
179
|
if (!_isArray(extSpec)) return !!extSpec.subjectAltName;
|
|
@@ -248,7 +185,6 @@ function _hasCriticalSan(extSpec) {
|
|
|
248
185
|
return false;
|
|
249
186
|
}
|
|
250
187
|
|
|
251
|
-
// ---- the primitive ---------------------------------------------------------
|
|
252
188
|
|
|
253
189
|
/**
|
|
254
190
|
* @primitive pki.x509.sign
|
|
@@ -296,13 +232,6 @@ function _hasCriticalSan(extSpec) {
|
|
|
296
232
|
* pki.schema.x509.parse(root).subject.dn; // "CN=Example Root CA"
|
|
297
233
|
*/
|
|
298
234
|
function sign(spec, issuer, opts) {
|
|
299
|
-
// EVERY caller-owned argument is copied before a field of any of them is read, and every copy is
|
|
300
|
-
// cleared when the call settles. The checks below run NOW, and the values they approved are
|
|
301
|
-
// encoded, signed and emitted several promise turns afterwards, while the caller still owns all
|
|
302
|
-
// three objects -- so a spec, an option or a signer read again after the first turn need not be
|
|
303
|
-
// the one that passed. Copying only some of them leaves the rest reachable; copying without the
|
|
304
|
-
// release leaves a duplicate of whatever secret was nested in them. guard.bytes.fixArguments is
|
|
305
|
-
// both halves, and is what every producing verb in the toolkit opens with.
|
|
306
235
|
return guard.bytes.fixedCall(CertificateError, "x509/bad-input", [
|
|
307
236
|
[spec, "the certificate spec"], [issuer, "the issuer"], [opts, "pki.x509.sign options"],
|
|
308
237
|
], _sign);
|
|
@@ -312,9 +241,6 @@ function _sign(spec, issuer, opts) {
|
|
|
312
241
|
opts = opts || {};
|
|
313
242
|
if (!spec || typeof spec !== "object" || Buffer.isBuffer(spec)) throw _err("x509/bad-input", "the certificate spec must be an object");
|
|
314
243
|
issuer = issuer || {};
|
|
315
|
-
// Before a single field is read, so a misspelling is a refusal rather than an omission carried
|
|
316
|
-
// into a signed certificate. The issuer message names its own argument because the mistake this
|
|
317
|
-
// catches most often is putting the issuer inside the spec, where it self-signed in silence.
|
|
318
244
|
guard.identifier.assertKnownKeys(spec, KNOWN_SPEC_KEYS, _err, "x509/bad-input", function (k) {
|
|
319
245
|
return "unknown certificate spec field " + JSON.stringify(k) +
|
|
320
246
|
(k === "issuer" ? "; the issuer is the SECOND argument to pki.x509.sign, not a spec field" : "") +
|
|
@@ -335,18 +261,12 @@ function _sign(spec, issuer, opts) {
|
|
|
335
261
|
var subjectDer = _encodeName(spec.subject == null ? [] : spec.subject);
|
|
336
262
|
var subjectEmpty = _isEmptyName(subjectDer);
|
|
337
263
|
|
|
338
|
-
// Resolve the issuer name + signing-key SPKI. `{ key }` alone -> self-signed.
|
|
339
264
|
var issuerDer, issuerSpki, issuerCert = null, issuerPathLen = null;
|
|
340
265
|
var selfSigned = issuer.name == null && issuer.cert == null && issuer.publicKey == null;
|
|
341
266
|
if (selfSigned) {
|
|
342
267
|
issuerDer = subjectDer;
|
|
343
268
|
issuerSpki = spki;
|
|
344
269
|
} else if (issuer.cert != null) {
|
|
345
|
-
// The CA-ness gate, the issuer name and the signing key are all read off this object, so a
|
|
346
|
-
// partial one decides them on fields that are not there.
|
|
347
|
-
// Re-derived from the bytes its parser read. The issuer certificate's subject and key identifier
|
|
348
|
-
// are copied into the certificate being signed, so they are a claim about who issued it -- an
|
|
349
|
-
// assembled object could name an issuer whose bytes the signer never saw.
|
|
350
270
|
issuerCert = guard.parsed.acceptDerived(issuer.cert, "certificate", x509.parse, _err, "x509/bad-input", "issuer.cert");
|
|
351
271
|
issuerPathLen = _assertIssuerIsCa(issuerCert);
|
|
352
272
|
issuerDer = pkiBuild.tbsNameField(issuerCert, "subject");
|
|
@@ -356,41 +276,24 @@ function _sign(spec, issuer, opts) {
|
|
|
356
276
|
issuerSpki = _reqDer(issuer.publicKey, "issuer.publicKey (the issuer SPKI DER)");
|
|
357
277
|
_assertValidSpki(issuerSpki, "issuer.publicKey");
|
|
358
278
|
}
|
|
359
|
-
// RFC 5280 sec. 4.1.2.4 -- the issuer MUST be a non-empty distinguished name.
|
|
360
279
|
if (_isEmptyName(issuerDer)) throw _err("x509/bad-issuer", "issuer must be a non-empty distinguished name");
|
|
361
280
|
|
|
362
|
-
// Resolve the signature scheme from the SIGNING key's SPKI algorithm (the whole registry, for free).
|
|
363
281
|
var scheme = signScheme.resolveSignScheme(_certLikeFromSpki(issuerSpki), { combinedRsaSig: true, pss: opts.pss, digestAlgorithm: opts.digestAlgorithm }, true, _signE);
|
|
364
282
|
|
|
365
283
|
var serialTlv = _serialInteger(spec.serialNumber);
|
|
366
|
-
// Validate both instants, then reject an inverted window before encoding (a notBefore after notAfter
|
|
367
|
-
// is a nonsensical validity period, RFC 5280 sec. 4.1.2.5).
|
|
368
284
|
guard.time.assertValid(spec.notBefore, _err, "x509/bad-input", "notBefore");
|
|
369
285
|
guard.time.assertValid(spec.notAfter, _err, "x509/bad-input", "notAfter");
|
|
370
286
|
// allow:nan-date-comparison-unguarded -- both operands are guard.time.assertValid'd on the two lines above (an Invalid Date throws before this comparison).
|
|
371
287
|
if (guard.time.instantOf(spec.notBefore) > guard.time.instantOf(spec.notAfter)) throw _err("x509/bad-input", "notBefore must not be after notAfter (RFC 5280 sec. 4.1.2.5)");
|
|
372
288
|
var validityDer = b.sequence([_timeDer(spec.notBefore, "notBefore"), _timeDer(spec.notAfter, "notAfter")]);
|
|
373
289
|
|
|
374
|
-
// Read ONCE. Three separate consumers test which form this spec is in -- the encoder, the
|
|
375
|
-
// empty-subject rule below and the path-length rule under it -- and each answering for its own
|
|
376
|
-
// read is three chances to answer differently about one certificate. The door deep-copies the
|
|
377
|
-
// spec, so today they cannot disagree; taking the value once means they still cannot if the
|
|
378
|
-
// shape of that door ever changes.
|
|
379
290
|
var extSpec = spec.extensions;
|
|
380
291
|
var exts = _buildExtensions(extSpec, { spki: spki, issuerSpki: issuerSpki, issuerCert: issuerCert, subjectEmpty: subjectEmpty });
|
|
381
|
-
// RFC 5280 sec. 4.1.2.6 -- an empty subject requires a critical subjectAltName (recognized in both the
|
|
382
|
-
// object form and a pre-encoded array-form extension).
|
|
383
292
|
if (subjectEmpty && !_hasCriticalSan(extSpec)) {
|
|
384
293
|
throw _err("x509/bad-input", "an empty subject requires a critical subjectAltName (RFC 5280 sec. 4.1.2.6)");
|
|
385
294
|
}
|
|
386
|
-
// Honor a supplied issuer's pathLenConstraint (RFC 5280 sec. 4.2.1.9): a CA certificate issued below
|
|
387
|
-
// it consumes one unit of path length, so pathLen=0 forbids issuing a CA below it, and an issued CA's
|
|
388
|
-
// own pathLenConstraint must leave room within the issuer's remaining depth.
|
|
389
295
|
if (issuerPathLen != null) {
|
|
390
296
|
var issued = _issuedCaInfo(extSpec);
|
|
391
|
-
// A self-issued CA certificate (subject == issuer, e.g. a CA key rollover) does NOT consume path
|
|
392
|
-
// length (RFC 5280 sec. 6.1 counts only non-self-issued intermediates), so it is permitted even at
|
|
393
|
-
// pathLen 0. Compare canonically (sec. 7.1) via the parsed RDN sequences.
|
|
394
297
|
var selfIssued = guard.name.dnEqual(
|
|
395
298
|
schema.walk(NAME_SCHEMA, asn1.decode(subjectDer), NS).result.rdns,
|
|
396
299
|
schema.walk(NAME_SCHEMA, asn1.decode(issuerDer), NS).result.rdns,
|
|
@@ -400,14 +303,12 @@ function _sign(spec, issuer, opts) {
|
|
|
400
303
|
if (issued.pathLen != null && issued.pathLen > issuerPathLen - 1) throw _err("x509/bad-input", "the issued CA certificate pathLenConstraint exceeds the issuer's remaining path length (RFC 5280 sec. 4.2.1.9)");
|
|
401
304
|
}
|
|
402
305
|
}
|
|
403
|
-
// Version is derived from the emitted field set (RFC 5280 sec. 4.1.2.1); the builder never emits
|
|
404
|
-
// unique identifiers, so extensions => v3, otherwise v1 (the [0] tag is omitted under DER DEFAULT).
|
|
405
306
|
var version = exts.length ? 3 : 1;
|
|
406
307
|
|
|
407
308
|
var tbsChildren = [];
|
|
408
|
-
if (version !== 1) tbsChildren.push(b.explicit(0, b.integer(BigInt(version - 1))));
|
|
309
|
+
if (version !== 1) tbsChildren.push(b.explicit(0, b.integer(BigInt(version - 1))));
|
|
409
310
|
tbsChildren.push(serialTlv);
|
|
410
|
-
tbsChildren.push(scheme.sigAlgId);
|
|
311
|
+
tbsChildren.push(scheme.sigAlgId);
|
|
411
312
|
tbsChildren.push(issuerDer);
|
|
412
313
|
tbsChildren.push(validityDer);
|
|
413
314
|
tbsChildren.push(subjectDer);
|
|
@@ -416,16 +317,11 @@ function _sign(spec, issuer, opts) {
|
|
|
416
317
|
var tbsDer = b.sequence(tbsChildren);
|
|
417
318
|
|
|
418
319
|
return signScheme.signOverTbs(scheme, issuer.key, tbsDer, _signE).then(function (sig) {
|
|
419
|
-
// The signature MUST verify under the issuer public key, or the certificate would not chain (the
|
|
420
|
-
// composite arm returns a promise; the classical/PQC path throws synchronously on a mismatch).
|
|
421
320
|
return Promise.resolve(_assertCertVerifies(tbsDer, sig, issuerSpki, scheme)).then(function () {
|
|
422
321
|
var certDer = b.sequence([tbsDer, scheme.sigAlgId, b.bitString(sig, 0)]);
|
|
423
322
|
return opts.pem ? x509.pemEncode(certDer, "CERTIFICATE") : certDer;
|
|
424
323
|
});
|
|
425
324
|
}, function (e) {
|
|
426
|
-
// A signing failure at a well-formed tbs is a bad signing key or a key/algorithm mismatch; keep a
|
|
427
|
-
// typed CertificateError (composite key-shape faults already are), and re-type a raw WebCrypto
|
|
428
|
-
// rejection to x509/bad-input rather than leaking a DOMException from the boundary.
|
|
429
325
|
if (e instanceof CertificateError) throw e;
|
|
430
326
|
throw _err("x509/bad-input", "signing the certificate failed -- the signing key does not match the resolved algorithm or is invalid", e);
|
|
431
327
|
});
|
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:b21c243d-9b6e-49ab-9c19-3427ff43e9bc",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-09-
|
|
8
|
+
"timestamp": "2026-09-01T08:58:18.522Z",
|
|
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.6.
|
|
22
|
+
"bom-ref": "@blamejs/pki@0.6.15",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "pki",
|
|
25
|
-
"version": "0.6.
|
|
25
|
+
"version": "0.6.15",
|
|
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.6.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/pki@0.6.15",
|
|
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.6.
|
|
57
|
+
"ref": "@blamejs/pki@0.6.15",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|