@blamejs/pki 0.6.14 → 0.6.16

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.
Files changed (112) hide show
  1. package/CHANGELOG.md +27 -1
  2. package/lib/acme.js +59 -815
  3. package/lib/asn1-der.js +7 -245
  4. package/lib/attrcert-sign.js +12 -260
  5. package/lib/attrcert-verify.js +1 -7
  6. package/lib/byte-reader.js +0 -8
  7. package/lib/byte-writer.js +0 -11
  8. package/lib/cbor-det.js +0 -54
  9. package/lib/cmc-build.js +15 -357
  10. package/lib/cmc-verify.js +6 -239
  11. package/lib/cmp-build.js +41 -317
  12. package/lib/cmp-session.js +73 -760
  13. package/lib/cmp-verify.js +32 -488
  14. package/lib/cms-compress.js +3 -32
  15. package/lib/cms-decrypt.js +29 -294
  16. package/lib/cms-encrypt.js +14 -234
  17. package/lib/cms-sign.js +29 -324
  18. package/lib/cms-verify.js +9 -500
  19. package/lib/composite-kem.js +2 -102
  20. package/lib/composite-sig.js +1 -77
  21. package/lib/constants.js +0 -249
  22. package/lib/crl-sign.js +9 -237
  23. package/lib/crl-verify.js +1 -10
  24. package/lib/crmf-sign.js +19 -198
  25. package/lib/crmf-verify.js +1 -12
  26. package/lib/csr-sign.js +3 -34
  27. package/lib/csr-verify.js +1 -12
  28. package/lib/ct.js +28 -253
  29. package/lib/edwards-point.js +10 -44
  30. package/lib/est.js +28 -764
  31. package/lib/framework-error.js +4 -182
  32. package/lib/guard-all.js +1 -58
  33. package/lib/guard-async.js +1 -36
  34. package/lib/guard-bytes.js +6 -650
  35. package/lib/guard-compress.js +5 -102
  36. package/lib/guard-crypto.js +1 -40
  37. package/lib/guard-der.js +2 -93
  38. package/lib/guard-encoding.js +2 -60
  39. package/lib/guard-header.js +1 -36
  40. package/lib/guard-identifier.js +7 -531
  41. package/lib/guard-intrinsic.js +1 -150
  42. package/lib/guard-json.js +10 -73
  43. package/lib/guard-limits.js +1 -77
  44. package/lib/guard-list.js +1 -49
  45. package/lib/guard-name.js +3 -209
  46. package/lib/guard-parsed.js +7 -335
  47. package/lib/guard-range.js +1 -71
  48. package/lib/guard-secret.js +1 -102
  49. package/lib/guard-text.js +1 -64
  50. package/lib/guard-time.js +1 -97
  51. package/lib/hpke.js +3 -105
  52. package/lib/http-digest.js +14 -142
  53. package/lib/http-retry-after.js +1 -47
  54. package/lib/http-transport.js +21 -131
  55. package/lib/inspect.js +30 -284
  56. package/lib/ip-utils.js +6 -47
  57. package/lib/jose.js +7 -142
  58. package/lib/key.js +2 -67
  59. package/lib/lint.js +9 -194
  60. package/lib/merkle.js +1 -27
  61. package/lib/mime.js +9 -82
  62. package/lib/ocsp-request-verify.js +1 -14
  63. package/lib/ocsp-verify.js +1 -82
  64. package/lib/ocsp.js +11 -169
  65. package/lib/oid.js +5 -337
  66. package/lib/path-validate.js +103 -1492
  67. package/lib/pbes2.js +2 -89
  68. package/lib/pkcs12-build.js +31 -379
  69. package/lib/pki-build.js +64 -290
  70. package/lib/rc2.js +2 -18
  71. package/lib/rfc3339.js +4 -27
  72. package/lib/scep.js +140 -286
  73. package/lib/schema-all.js +0 -122
  74. package/lib/schema-attrcert.js +4 -146
  75. package/lib/schema-c509.js +153 -802
  76. package/lib/schema-cmc.js +5 -220
  77. package/lib/schema-cmp.js +2 -223
  78. package/lib/schema-cms.js +13 -427
  79. package/lib/schema-crl.js +5 -68
  80. package/lib/schema-crmf.js +6 -167
  81. package/lib/schema-csr.js +1 -54
  82. package/lib/schema-csrattrs.js +2 -87
  83. package/lib/schema-engine.js +0 -152
  84. package/lib/schema-ocsp.js +0 -117
  85. package/lib/schema-pkcs12.js +2 -93
  86. package/lib/schema-pkcs8.js +3 -35
  87. package/lib/schema-pkix.js +24 -655
  88. package/lib/schema-smime.js +0 -54
  89. package/lib/schema-tsp.js +3 -99
  90. package/lib/schema-x509.js +4 -63
  91. package/lib/shbs.js +11 -95
  92. package/lib/sign-scheme.js +2 -97
  93. package/lib/sigstore.js +9 -169
  94. package/lib/sleep.js +2 -8
  95. package/lib/smime.js +15 -408
  96. package/lib/tls-cert-compress.js +0 -62
  97. package/lib/trust.js +19 -185
  98. package/lib/tsp-sign.js +16 -270
  99. package/lib/validator-all.js +1 -30
  100. package/lib/validator-attcert.js +2 -46
  101. package/lib/validator-cose.js +2 -153
  102. package/lib/validator-keydesc.js +1 -37
  103. package/lib/validator-sig.js +1 -46
  104. package/lib/validator-tls.js +1 -88
  105. package/lib/validator-tpm.js +19 -122
  106. package/lib/verify-seam.js +1 -24
  107. package/lib/webauthn-mds.js +3 -400
  108. package/lib/webauthn.js +12 -833
  109. package/lib/webcrypto.js +5 -485
  110. package/lib/x509-sign.js +4 -108
  111. package/package.json +1 -1
  112. package/sbom.cdx.json +6 -6
package/lib/cms-sign.js CHANGED
@@ -1,17 +1,8 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  // Copyright (c) blamejs contributors
3
3
  "use strict";
4
- //
5
- // @internal -- the pki.cms.sign implementation. So the pki.cms namespace has one @module home,
4
+ // @internal
6
5
  // the operator-facing @module pki.cms + the @primitive pki.cms.sign documentation block live in
7
- // cms-verify.js, which re-exports this sign function.
8
- //
9
- // CMS SignedData signing (RFC 5652 sec. 5), the producing side of pki.cms.verify: composes the
10
- // strict asn1 build layer (canonical DER, and build.set SET-OF-sorts the signed attributes for
11
- // free), the WebCrypto sign surface over node:crypto, and the shared validator.sig.rawToEcdsaDer
12
- // DER-ECDSA home -- emitting exactly the shapes cms.verify checks (NULL params for RSA, absent
13
- // for ECDSA/EdDSA, the RSASSA-PSS params SEQUENCE), with the sign->verify round-trip (and OpenSSL
14
- // cms -verify) as the guard.
15
6
 
16
7
  var asn1 = require("./asn1-der");
17
8
  var oid = require("./oid");
@@ -24,73 +15,48 @@ var webcrypto = require("./webcrypto");
24
15
  var signScheme = require("./sign-scheme");
25
16
  var guard = require("./guard-all");
26
17
  var intrinsic = require("./guard-intrinsic");
27
- var pkiBuild = require("./pki-build"); // the shared post-sign self-check, among other producing helpers
18
+ var pkiBuild = require("./pki-build");
28
19
  var cms = require("./schema-cms");
29
20
 
30
21
  var subtle = webcrypto.webcrypto.subtle;
31
22
  var CmsError = frameworkError.CmsError;
32
23
  var b = asn1.build;
33
24
  function _err(code, message, cause) { return new CmsError(code, message, cause); }
34
- // The domain error factory the shared sign-scheme resolver/signer throws through (kind ->
35
- // cms/<kind>), so its faults keep the cms/* codes.
36
25
  function _signE(kind, message, cause) { return new CmsError("cms/" + kind, message, cause); }
37
26
  function O(name) { return oid.byName(name); }
38
27
 
39
- // Every option each verb READS, and nothing else. Derived from the signing paths themselves rather
40
- // than from what callers happen to pass: an option this list omits is one the verb would ignore in
41
- // silence, and the ones that matter most are the ones a caller would most expect to work.
42
- // A misspelled option name is the shape this closes: it does not select the mode the caller meant,
43
- // and without the gate the message is signed the other way with nothing said about it.
44
28
  var KNOWN_SIGN_OPTS = {
45
29
  signedAttributes: 1, signingTime: 1, additionalSignedAttributes: 1, unsignedAttributes: 1,
46
30
  sid: 1, eContentType: 1, detached: 1, certificates: 1, pem: 1,
47
31
  };
48
- // The SIGNER descriptor has two forms, and every field it reads is named here so a caller that
49
- // authors one can be held to the form it selects: a certificate signer, and the key-only signer
50
- // RFC 5272 sec. 3.2 requires for a Full PKI Request, whose identity comes from `spki` +
51
- // `keyIdentifier` instead. The signature parameters are read by both. Exported for the verbs that
52
- // take signer descriptors as AUTHORING input and gate them at their own door -- pki.cms.sign takes
53
- // them straight from its caller, where a bag carrying extra handles is an ordinary shape.
54
32
  var KNOWN_SIGNER_CERT_KEYS = { cert: 1, key: 1, pss: 1, digestAlgorithm: 1, combinedRsaSig: 1 };
55
33
  var KNOWN_SIGNER_KEY_ONLY_KEYS = { spki: 1, keyIdentifier: 1, key: 1, pss: 1, digestAlgorithm: 1, combinedRsaSig: 1 };
56
- // Countersign has its own set: it takes signerIndex and countersignatureOf to SELECT which
57
- // signature it attaches to, and has no content of its own, so eContentType, detached and
58
- // unsignedAttributes are not among the options it reads.
59
34
  var KNOWN_COUNTERSIGN_OPTS = {
60
35
  signerIndex: 1, countersignatureOf: 1, signingTime: 1, certificates: 1, pem: 1,
61
36
  signedAttributes: 1, additionalSignedAttributes: 1, sid: 1,
62
37
  };
63
- // The shared producing-side helpers, bound to this domain's error class. Only the
64
- // post-sign self-check is used here (the same one every other signer in the
65
- // toolkit runs), so a key-only signer's declared public key is bound by evidence
66
- // and never by the caller's word.
67
38
  var NS = pkix.makeNS("cms", CmsError, oid);
68
39
  var _b = pkiBuild.makeBuilder({
69
40
  ErrorClass: CmsError, prefix: "cms", O: O, NS: NS,
70
41
  NAME_SCHEMA: pkix.name(NS), SPKI_SCHEMA: pkix.spki(NS), EXT_DECODERS: {},
71
42
  });
72
43
 
73
- // A digest-algorithm name -> the engine's hash name. The FIPS 202 extendable-output
74
- // functions are message digests here at the lengths RFC 8702 sec. 4 fixes for that use,
75
- // which the engine applies from the name alone.
76
44
  var DIGEST_HASH = {
77
45
  sha256: "SHA-256", sha384: "SHA-384", sha512: "SHA-512",
78
46
  shake128: "SHAKE128", shake256: "SHAKE256",
79
47
  };
80
48
 
81
49
  var OID_DATA = O("data");
82
- var OID_PKI_DATA = O("id-cct-PKIData"); // the content type RFC 5272 sec. 3.2's signer rules govern
50
+ var OID_PKI_DATA = O("id-cct-PKIData");
83
51
  var OID_SIGNED_DATA = O("signedData");
84
52
  var OID_SKI = O("subjectKeyIdentifier");
85
53
 
86
54
 
87
- // The message digest of the content under the digest algorithm, resolved to a Buffer.
88
55
  function _digest(digestName, content) {
89
56
  return subtle.digest(DIGEST_HASH[digestName], content).then(function (d) { return Buffer.from(d); });
90
57
  }
91
58
 
92
59
 
93
- // The cert's subjectKeyIdentifier extension value (the raw key id), or throws.
94
60
  function _skiValue(cert) {
95
61
  var ext = (cert.extensions || []).filter(function (e) { return e.oid === OID_SKI; })[0];
96
62
  if (!ext) throw _err("cms/no-ski", "a subjectKeyIdentifier signer identifier requires the signer certificate to carry an SKI extension");
@@ -99,23 +65,13 @@ function _skiValue(cert) {
99
65
  }
100
66
 
101
67
 
102
- // The SignerInfo SignerIdentifier + its coupled CMSVersion (RFC 5652 sec. 5.3): a [0] IMPLICIT
103
- // subjectKeyIdentifier => version 3, else an IssuerAndSerialNumber => version 1. Shared by the
104
- // top-level signer and the sec. 11.4 countersignature (a countersignature IS a SignerInfo).
105
68
  function _buildSid(cert, useSki) {
106
69
  var sid = useSki
107
- ? b.contextPrimitive(0, _skiValue(cert)) // [0] IMPLICIT SubjectKeyIdentifier
108
- : b.sequence([b.raw(pkiBuild.tbsNameField(cert, "issuer")), b.integer(cert.serialNumber)]); // IssuerAndSerialNumber
70
+ ? b.contextPrimitive(0, _skiValue(cert))
71
+ : b.sequence([b.raw(pkiBuild.tbsNameField(cert, "issuer")), b.integer(cert.serialNumber)]);
109
72
  return { sid: sid, version: useSki ? 3 : 1 };
110
73
  }
111
74
 
112
- // Assemble a SignedAttributes SET from resolved attribute pairs (each { type: <dotted OID>, values:
113
- // [<build node or DER Buffer>] }), returning { setOf, wire }: `setOf` is the canonical DER SET OF
114
- // (tag 0x31, build.set SET-OF-sorts) the signature covers (RFC 5652 sec. 5.4); `wire` is the same
115
- // bytes with the on-wire [0] IMPLICIT tag (0xA0). Each attribute type appears at most once (sec.
116
- // 5.3), so a duplicate throws. Shared by the top-level signer (content-type + message-digest +
117
- // signing-time + caller attrs) and the countersignature builder (message-digest over the target
118
- // signature octets + signing-time, content-type omitted per sec. 11.4).
119
75
  function _buildSignedAttrs(pairs) {
120
76
  var seenTypes = {};
121
77
  var attrs = intrinsic.map(pairs, function (p) {
@@ -123,14 +79,11 @@ function _buildSignedAttrs(pairs) {
123
79
  seenTypes[p.type] = 1;
124
80
  return b.sequence([b.oid(p.type), b.set(p.values)]);
125
81
  });
126
- var setOf = b.set(attrs); // SET OF (tag 0x31) -- the exact bytes the signature covers (sec. 5.4)
127
- var wire = intrinsic.bufferFrom(setOf); wire[0] = 0xA0; // the on-wire [0] IMPLICIT tag
82
+ var setOf = b.set(attrs);
83
+ var wire = intrinsic.bufferFrom(setOf); wire[0] = 0xA0;
128
84
  return { setOf: setOf, wire: wire };
129
85
  }
130
86
 
131
- // Resolve caller-supplied additional signed attributes ({ type: OID name or dotted, values: [DER] })
132
- // into the pair shape _buildSignedAttrs consumes; each MUST carry >= 1 value (Attribute values is
133
- // SET SIZE (1..MAX)).
134
87
  function _resolveAttrPairs(list, what) {
135
88
  return intrinsic.map(list || [], function (a) {
136
89
  var vals = intrinsic.map(a.values || [], function (v) { return _toBuf(v, what); });
@@ -139,17 +92,11 @@ function _resolveAttrPairs(list, what) {
139
92
  });
140
93
  }
141
94
 
142
- // content-type / message-digest / signing-time are content-binding signed attributes and MUST NOT
143
- // appear as unsigned attributes (RFC 5652 sec. 11.1/11.2/11.3, the parser's ATTR_FORBIDDEN_IN).
144
95
  var UNSIGNED_FORBIDDEN = {};
145
96
  UNSIGNED_FORBIDDEN[O("contentType")] = "content-type";
146
97
  UNSIGNED_FORBIDDEN[O("messageDigest")] = "message-digest";
147
98
  UNSIGNED_FORBIDDEN[O("signingTime")] = "signing-time";
148
99
 
149
- // Build the [1] IMPLICIT unsignedAttrs SET OF (on-wire tag 0xA1) from opts.unsignedAttributes
150
- // (each { type, values: [DER] }, such as a countersignature or an RFC 3161 timestamp token), or null when
151
- // absent/empty. Unsigned attributes sit outside the signature; a placement-forbidden type or a
152
- // duplicate type (RFC 5652 sec. 11 / sec. 5.3) is a config-time cms/bad-input.
153
100
  function _buildUnsignedAttrs(list) {
154
101
  if (list == null) return null;
155
102
  if (!intrinsic.isArray(list)) throw _err("cms/bad-input", "opts.unsignedAttributes must be an array of { type, values }");
@@ -162,67 +109,30 @@ function _buildUnsignedAttrs(list) {
162
109
  seen[p.type] = 1;
163
110
  });
164
111
  var setOf = b.set(intrinsic.map(pairs, function (p) { return b.sequence([b.oid(p.type), b.set(p.values)]); }));
165
- var wire = intrinsic.bufferFrom(setOf); wire[0] = 0xA1; // SET OF -> [1] IMPLICIT UnsignedAttributes
112
+ var wire = intrinsic.bufferFrom(setOf); wire[0] = 0xA1;
166
113
  return wire;
167
114
  }
168
115
 
169
- // Resolve, at entry and once, every field an emitted SignerInfo depends on (RFC 5652 sec. 5.3):
170
- // the SignerIdentifier + version, the signature scheme, the private key reference, the declared
171
- // public bytes, and the signer certificate DER. Nothing here defers, so the values are captured
172
- // before any promise turn; the digest, the signature, and the self-check happen a turn later in
173
- // _finishSignerInfo, off exactly these captured values. Buffered and streamed signing share this.
174
116
  function _resolveSignerContext(signer, opts) {
175
117
  var so = signer || {};
176
- // A key-only signer: `{ key, spki, keyIdentifier }` with no certificate. RFC
177
- // 5272 sec. 3.2 requires exactly this when a Full PKI Request is signed with the
178
- // key of a certification request it carries: there is no certificate yet, the
179
- // sid MUST be the subjectKeyIdentifier form, and its value MUST be the SKI the
180
- // request itself declares. The scheme resolver only ever reads
181
- // `cert.subjectPublicKeyInfo.algorithm`, so the request's own parsed SPKI stands
182
- // in for the certificate that does not exist.
183
118
  var keyOnly = so.cert == null && so.spki != null;
184
- // Every field the emitted SignerInfo depends on is read ONCE, HERE, while
185
- // nothing has deferred yet. The SignerIdentifier is built from the certificate
186
- // or the key identifier on the lines below; the key signs, and is matched
187
- // against `spki`, a promise turn later. A descriptor whose `key` and `spki`
188
- // were swapped in that gap would emit a SignerInfo that names one public key
189
- // and carries a signature by another -- coherent to the match check, since
190
- // both halves moved together, and unverifiable to everyone else.
191
- //
192
- // The public bytes are COPIED, so an in-place rewrite cannot reach them
193
- // either. The private key is captured by reference: copying it would put a
194
- // second copy of key material in this function's hands, a secret it would then
195
- // own for the rest of the call, and the reference already pins which key
196
- // signs against the identifier that names it.
197
119
  var soKey = so.key;
198
120
  var soSpki = keyOnly ? guard.bytes.snapshotSource(so.spki, CmsError, "cms/bad-input", "a key-only signer's spki") : null;
199
121
  var certDer = keyOnly ? null : _normCertDer(so.cert);
200
122
  var cert = keyOnly ? _keyOnlyCertStandIn(soSpki) : x509.parse(certDer);
201
123
  var scheme = signScheme.resolveSignScheme(cert, so, opts.signedAttributes === false, _signE);
202
124
  var sidv = keyOnly
203
- ? { sid: b.contextPrimitive(0, _keyOnlyKeyId(so)), version: 3 } // [0] IMPLICIT SubjectKeyIdentifier
125
+ ? { sid: b.contextPrimitive(0, _keyOnlyKeyId(so)), version: 3 }
204
126
  : _buildSid(cert, opts.sid === "ski");
205
127
  return { keyOnly: keyOnly, soKey: soKey, soSpki: soSpki, certDer: certDer, cert: cert,
206
128
  scheme: scheme, sid: sidv.sid, version: sidv.version };
207
129
  }
208
130
 
209
- // Finish a SignerInfo (RFC 5652 sec. 5.3) from a resolved context: build the SignedAttributes (or
210
- // sign the content directly), sign them, self-check the signature against the declared key, and
211
- // assemble the SignerInfo. `md` is the message digest of the content under `rc.scheme.digest`,
212
- // already computed -- over a buffered content by _digest, or over a streamed content's chunks by the
213
- // engine's single-pass digest. `content` is read ONLY on the signedAttributes:false path, where the
214
- // signature covers the content directly and there is no digest attribute.
215
131
  async function _finishSignerInfo(rc, md, content, eContentType, opts) {
216
- // await throughout, never a live Promise.resolve()/.then lookup: on the streamed path this runs after
217
- // the content's iterator has driven the digest, so a replaced global Promise.resolve or a replaced
218
- // Promise.prototype.then would otherwise let it disrupt the signing that completes here. await hooks
219
- // onto a native promise through the internal job, not the caller-replaceable prototype method.
220
132
  var toSign;
221
133
  if (opts.signedAttributes === false) {
222
- toSign = content; // sign the content directly (no signed attributes)
134
+ toSign = content;
223
135
  } else {
224
- // Signed attributes (RFC 5652 sec. 5.3): content-type == eContentType, message-digest ==
225
- // digest(content), and (by default) signing-time, plus any caller-supplied attribute.
226
136
  var pairs = [
227
137
  { type: O("contentType"), values: [b.oid(eContentType)] },
228
138
  { type: O("messageDigest"), values: [b.octetString(md)] },
@@ -231,21 +141,17 @@ async function _finishSignerInfo(rc, md, content, eContentType, opts) {
231
141
  pairs = intrinsic.concat(pairs, _resolveAttrPairs(opts.additionalSignedAttributes, "a signed attribute value"));
232
142
  toSign = _buildSignedAttrs(pairs);
233
143
  }
234
- var signedBytes = toSign.setOf ? toSign.setOf : toSign; // SET-OF form for signing (sec. 5.4)
144
+ var signedBytes = toSign.setOf ? toSign.setOf : toSign;
235
145
  var sig = await signScheme.signOverTbs(rc.scheme, rc.soKey, signedBytes, _signE);
236
146
  await _assertKeyMatchesSpki(rc.keyOnly, rc.soKey, rc.soSpki, rc.scheme, sig, signedBytes, rc.cert);
237
147
  var fields = [b.integer(BigInt(rc.version)), rc.sid, rc.scheme.digestAlgId];
238
- if (toSign.wire) intrinsic.push(fields, toSign.wire); // [0] IMPLICIT signedAttrs
148
+ if (toSign.wire) intrinsic.push(fields, toSign.wire);
239
149
  intrinsic.push(fields, rc.scheme.sigAlgId, b.octetString(sig));
240
150
  var ua = _buildUnsignedAttrs(opts.unsignedAttributes);
241
- if (ua) intrinsic.push(fields, ua); // [1] IMPLICIT unsignedAttrs
242
- // certDer is null for a key-only signer, and the certificates [0] embedding below filters it out --
243
- // there is nothing to embed, which is the point.
151
+ if (ua) intrinsic.push(fields, ua);
244
152
  return { si: b.sequence(fields), digestAlgId: rc.scheme.digestAlgId, version: rc.version, certDer: rc.certDer };
245
153
  }
246
154
 
247
- // Build one SignerInfo (RFC 5652 sec. 5.3) over a buffered content and sign it: resolve the context,
248
- // digest the content (unless it is signed directly), then finish.
249
155
  function _buildSignerInfo(signer, content, eContentType, opts) {
250
156
  var rc = _resolveSignerContext(signer, opts);
251
157
  var mdP = opts.signedAttributes === false ? Promise.resolve(null) : _digest(rc.scheme.digest, content);
@@ -254,35 +160,13 @@ function _buildSignerInfo(signer, content, eContentType, opts) {
254
160
 
255
161
 
256
162
 
257
- // A SignerInfo names a public key -- as `spki` when the signer is key-only, and as
258
- // the certificate it embeds otherwise -- while the signature comes from `key`. Two
259
- // different keys make a well-formed SignerInfo nobody can verify: the recipient
260
- // resolves the identifier to the declared key and checks a signature made by
261
- // another. Neither form catches that by itself, so both are checked here.
262
- //
263
- // Proven from the SIGNATURE, not from the key. Deriving the public half and
264
- // comparing it works only for key material this process can export, and the keys
265
- // this signer serves are often exactly the ones that cannot be: a non-extractable
266
- // CryptoKey, an HSM handle, or a composite `{ mldsa, trad }` pair that is two keys
267
- // and not one. Every one of those can still be checked the direct way: the
268
- // signature it just produced either verifies under the declared public key or it
269
- // does not, so there is no key kind this has to take on trust.
270
- //
271
- // This is the same post-sign self-check every other signer in the toolkit runs,
272
- // through the same shared helper. It costs one verification per SignerInfo, which
273
- // is what a certificate, a CRL, a CSR and a CMP message have always paid here.
274
163
  async function _assertKeyMatchesSpki(keyOnly, soKey, soSpki, scheme, sig, signedBytes, cert) {
275
164
  var declared = keyOnly ? soSpki : (cert && cert.subjectPublicKeyInfo && cert.subjectPublicKeyInfo.bytes);
276
- // A parsed certificate that does not retain its SPKI bytes cannot be checked this
277
- // way. That is not a shape x509.parse produces, and if it ever were, refusing is
278
- // the answer, never skipping, since a skip is the fail-open this prevents.
279
165
  if (!declared) {
280
166
  throw _signE("bad-input",
281
167
  "a signer certificate did not surface its subjectPublicKeyInfo, so the signature it produced could " +
282
168
  "not be checked against the key the SignerInfo declares");
283
169
  }
284
- // await, never Promise.resolve()/.then: reached from _finishSignerInfo after a streamed content's
285
- // iterator ran, so a replaced global Promise.resolve would otherwise disrupt this self-check.
286
170
  try {
287
171
  await _b.assertSignatureVerifies(signedBytes, sig, declared, scheme);
288
172
  } catch (e) {
@@ -293,35 +177,14 @@ async function _assertKeyMatchesSpki(keyOnly, soKey, soSpki, scheme, sig, signed
293
177
  }
294
178
  }
295
179
 
296
- // A signing-time Time value: UTCTime before 2050, GeneralizedTime from 2050 (RFC 5652 sec. 11.3 /
297
- // RFC 5280 sec. 4.1.2.5). A caller Date overrides; false omits the attribute (handled above). The
298
- // DEFAULT instant is read from the captured Date intrinsic, never the live global: a streamed content's
299
- // iterator runs during the digest, one turn before this attribute is built, and a replaced global Date
300
- // would otherwise let it stamp the signature with an attacker-chosen instant (byte-identical, under a
301
- // deterministic scheme, to signing with that instant explicitly).
302
180
  function _timeValue(when) {
303
181
  var d = guard.time.isDate(when) ? when : new intrinsic.Date();
304
182
  return d.getUTCFullYear() < 2050 ? b.utcTime(d) : b.generalizedTime(d);
305
183
  }
306
184
 
307
- // Normalize a signer certificate input to its raw DER (DER Buffer / PEM string / Uint8Array).
308
- // The same bytes drive scheme resolution and the certificates [0] embedding, so a parsed
309
- // certificate (which does not retain its full DER) is rejected; pass DER or PEM.
310
- // The stand-in a key-only signer resolves its signature scheme from: the parsed
311
- // SubjectPublicKeyInfo of the key that will sign. Only `.subjectPublicKeyInfo` is
312
- // read downstream, so this deliberately carries nothing else; a fuller fake
313
- // would invite code to start trusting fields no certificate actually backs.
314
185
  function _keyOnlyCertStandIn(spkiDer) {
315
186
  var alg;
316
187
  try {
317
- // SubjectPublicKeyInfo ::= SEQUENCE { algorithm AlgorithmIdentifier, subjectPublicKey BIT STRING }
318
- // The whole structure, not just the field this function goes on to read. For an
319
- // opaque key handle the derivation check downstream is deliberately skipped, so
320
- // this is the only thing standing between a caller's bytes and a SignerInfo that
321
- // declares them: a SEQUENCE carrying an algorithm and nothing else, or a third
322
- // field, would be emitted as the signer's public key and resolve to nothing for
323
- // anyone trying to verify. The key value is not interpreted, only that there
324
- // is one, in the field the structure reserves for it.
325
188
  var node = asn1.decode(spkiDer);
326
189
  if (node.tagClass !== "universal" || node.tagNumber !== asn1.TAGS.SEQUENCE || !node.children ||
327
190
  node.children.length !== 2) {
@@ -333,44 +196,29 @@ function _keyOnlyCertStandIn(spkiDer) {
333
196
  throw _err("cms/bad-input",
334
197
  "a key-only signer's spki subjectPublicKey must be a BIT STRING (RFC 5280 sec. 4.1.2.7)");
335
198
  }
336
- asn1.read.bitString(keyNode); // read, not tag-inspected: a malformed unused-bit count is refused here
199
+ asn1.read.bitString(keyNode);
337
200
  var algNode = node.children[0];
338
201
  if (algNode.tagClass !== "universal" || algNode.tagNumber !== asn1.TAGS.SEQUENCE ||
339
202
  !algNode.children || !algNode.children.length || algNode.children.length > 2) {
340
203
  throw _err("cms/bad-input",
341
204
  "a key-only signer's spki algorithm is SEQUENCE { algorithm OID, parameters OPTIONAL } (RFC 5280 sec. 4.1.1.2)");
342
205
  }
343
- // The same shape schema-x509 surfaces: the algorithm OID plus its parameters
344
- // as the raw TLV (or null when absent); the resolver re-decodes those bytes
345
- // for an EC named curve and for the RSASSA-PSS hash pinning, so handing it a
346
- // different representation here would break exactly those two algorithms.
347
206
  alg = {
348
207
  oid: asn1.read.oid(algNode.children[0]),
349
208
  parameters: algNode.children[1] ? algNode.children[1].bytes : null,
350
209
  };
351
210
  } catch (e) {
352
- // The shape refusals above already name what is wrong; only a decode failure
353
- // needs the generic message, so a precise verdict is not overwritten by it.
354
211
  if (e && typeof e.code === "string" && e.code.indexOf("cms/") === 0) throw e;
355
212
  throw _err("cms/bad-input", "a key-only signer's spki is not a SubjectPublicKeyInfo", e);
356
213
  }
357
214
  return { subjectPublicKeyInfo: { algorithm: alg } };
358
215
  }
359
216
 
360
- // The key identifier a key-only signer's sid carries. Required: without it there
361
- // is no way for a verifier to find the key, and RFC 5272 sec. 3.2 makes the value
362
- // the one the certification request declares.
363
217
  function _keyOnlyKeyId(so) {
364
218
  if (so.keyIdentifier == null) {
365
219
  throw _err("cms/bad-input",
366
220
  "a key-only signer requires keyIdentifier -- the subjectKeyIdentifier the certification request declares (RFC 5272 sec. 3.2)");
367
221
  }
368
- // A key identifier is bytes, so the type is checked and never coerced. Buffer.from
369
- // accepts far more than it should mean here: Buffer.from(20) allocates twenty zero
370
- // octets and Buffer.from("a1b2") takes the ASCII of the text, not the two
371
- // octets a reader means by it. Either would emit a structurally valid
372
- // SignerIdentifier carrying an identifier the caller never asked for, which no
373
- // verifier can match back to the certification request (RFC 5272 sec. 3.2).
374
222
  var id = guard.bytes.view(so.keyIdentifier, CmsError, "cms/bad-input", "a key-only signer's keyIdentifier");
375
223
  if (!id.length) throw _err("cms/bad-input", "a key-only signer's keyIdentifier must not be empty");
376
224
  return id;
@@ -380,7 +228,7 @@ function _normCertDer(c) {
380
228
  if (c == null) throw _err("cms/bad-input", "each signer requires a certificate (cert)");
381
229
  if (guard.bytes.isByteSource(c)) {
382
230
  c = guard.bytes.snapshotSource(c, CmsError, "cms/bad-input", "a signer certificate");
383
- return c[0] === 0x30 ? c : _pemToDer(c.toString("latin1")); // DER as-is, else PEM
231
+ return c[0] === 0x30 ? c : _pemToDer(c.toString("latin1"));
384
232
  }
385
233
  if (typeof c === "string") return _pemToDer(c);
386
234
  throw _err("cms/bad-input", "a signer certificate must be a DER Buffer or a PEM string");
@@ -392,45 +240,22 @@ function _pemToDer(text) {
392
240
  }
393
241
 
394
242
  // pki.cms.sign -- documented by the @primitive block in cms-verify.js (the @module pki.cms home).
395
- // Documented `-> Promise`, so a fault leaves as a REJECTION (guard-async). The stream/buffer routing
396
- // classifies `content` at the door, which reads `content[Symbol.asyncIterator]` -- a caller accessor
397
- // that can throw -- so the whole dispatch runs inside the rejection boundary rather than fixedCall's
398
- // alone, which the classification precedes. The checks the impls run stay synchronous because they
399
- // read the caller's mutable content and signer list.
400
243
  function sign(content, signers, opts) {
401
244
  return guard.async.deferred(function () { return _signDispatch(content, signers, opts); });
402
245
  }
403
246
 
404
247
  function _signDispatch(content, signers, opts) {
405
- // The signer list and options are copied FIRST, before the content is classified. Classifying reads
406
- // content[Symbol.asyncIterator] -- a caller accessor that runs in-realm -- and a probe run before the
407
- // copy could mutate the still-uncopied signers/opts, or replace the Array.prototype method the copy
408
- // uses, and steer the emitted signature. With the copies taken first, the probe cannot reach them.
409
248
  return guard.bytes.fixedCall(CmsError, "cms/bad-input", [
410
249
  [signers, "the signer list"], [opts, "pki.cms.sign options"],
411
250
  ], function (copiedSigners, copiedOpts) {
412
- // A streaming content is classified by guard.bytes.asyncStreamOf, which reads Symbol.asyncIterator a
413
- // single time and returns a LAZY stream (its underlying iterator is acquired only when the digest
414
- // engine drives it, so a pre-hash rejection never opens a resource to leak). The stream, consumed
415
- // exactly once, is passed through; it CANNOT be deep-copied itself. A byte source (or any
416
- // non-iterable) yields null here and takes the buffered path.
417
251
  var stream = guard.bytes.asyncStreamOf(content);
418
252
  if (stream) return _signStream(stream, copiedSigners, copiedOpts);
419
- // Buffered: the content byte source is copied too, so the value that decides the attribute-shaped-
420
- // content refusal and the value that gets signed are the same read.
421
253
  return guard.bytes.fixedCall(CmsError, "cms/bad-input", [
422
254
  [content, "content"],
423
255
  ], function (copiedContent) { return _sign(copiedContent, copiedSigners, copiedOpts); });
424
256
  });
425
257
  }
426
258
 
427
- // Sign a streamed content (an async iterable of byte chunks) as a DETACHED SignedData. The payload
428
- // is hashed once, incrementally, under every distinct SignerInfo digest algorithm (RFC 5652
429
- // sec. 5.4), so an arbitrarily large content is never held whole and a single-use stream serves
430
- // every signer in one pass. Detached is the only conformant streamed form: an attached SignedData
431
- // embeds the content as a definite-length OCTET STRING, which needs the whole content buffered to
432
- // state its length, and signed attributes are required (a stream cannot be signed directly, and the
433
- // message-digest attribute is exactly what the streamed hash produces).
434
259
  async function _signStream(stream, signers, opts) {
435
260
  opts = guard.identifier.optionsObject(opts, _err, "cms/bad-input", "pki.cms.sign options");
436
261
  guard.identifier.assertKnownKeys(opts, KNOWN_SIGN_OPTS, _err, "cms/bad-input", "unknown opts field ");
@@ -451,32 +276,18 @@ async function _signStream(stream, signers, opts) {
451
276
  "a key-only signer must be the ONLY SignerInfo in a Full PKI Request (RFC 5272 sec. 3.2)");
452
277
  }
453
278
  if (opts.signingTime != null && opts.signingTime !== false) guard.time.assertValid(opts.signingTime, _err, "cms/bad-input", "signingTime");
454
- // Resolve every signer's context first (no stream consumed yet): this yields each SignerInfo's
455
- // digest algorithm, so the stream can be hashed once under the distinct set.
456
279
  var rcs = intrinsic.map(list, function (s) { return _resolveSignerContext(s, opts); });
457
280
  var digestNames = [], seenDigest = {};
458
281
  intrinsic.forEach(rcs, function (r) { if (!seenDigest[r.scheme.digest]) { seenDigest[r.scheme.digest] = 1; intrinsic.push(digestNames, r.scheme.digest); } });
459
282
  var wcNames = intrinsic.map(digestNames, function (n) { return DIGEST_HASH[n]; });
460
- // `await`, not `.then`: the streamed content's iterator runs during digestStream and could replace
461
- // Promise.prototype.then (or Promise.all, whose spec-internal element handling dispatches through it)
462
- // to drop SignerInfos from the emitted DER or bypass the non-empty-signer check. await and a captured
463
- // await-each aggregation dispatch through no such caller-replaceable method.
464
283
  var digests;
465
284
  try {
466
285
  digests = await subtle.digestStream(wcNames, stream);
467
286
  } catch (e) {
468
- // The engine reports malformed streamed content in its own domain; report it in this verb's via the
469
- // shared guard, rather than leaking the engine code. The digest algorithm names are this module's own,
470
- // so a webcrypto/syntax here is never an algorithm fault.
471
287
  guard.bytes.translateStreamError(e, _err, "cms/bad-input");
472
288
  }
473
289
  var byName = {};
474
290
  intrinsic.forEach(digestNames, function (n, i) { byName[n] = intrinsic.bufferFrom(digests[i]); });
475
- // Build each SignerInfo sequentially -- START it only as it is awaited -- rather than starting them
476
- // all and awaiting each: awaiting is the capture-safe combinator (no Promise.all/.then the streamed
477
- // content could replace), but starting all first would leave a later signer's rejection unobserved
478
- // if an earlier one rejects, which Node can escalate to an unhandled-rejection crash. Per-signer work
479
- // is small, so the sequential cost is negligible.
480
291
  var built = [];
481
292
  for (var _ip = 0; _ip < rcs.length; _ip++) {
482
293
  intrinsic.push(built, await _finishSignerInfo(rcs[_ip], byName[rcs[_ip].scheme.digest], null, eContentType, opts));
@@ -487,115 +298,64 @@ async function _signStream(stream, signers, opts) {
487
298
  function _sign(content, signers, opts) {
488
299
  opts = guard.identifier.optionsObject(opts, _err, "cms/bad-input", "pki.cms.sign options");
489
300
  guard.identifier.assertKnownKeys(opts, KNOWN_SIGN_OPTS, _err, "cms/bad-input", "unknown opts field ");
490
- // The arguments were copied at entry (see `sign` above), which is what makes the refusal below
491
- // hold: flipping signedAttributes from true to false after the call returns would otherwise skip
492
- // the attribute-shaped-content check while the signer signs that content directly, which is the
493
- // very signature the stripping attack needs.
494
301
  var contentBuf = _toBuf(content, "content");
495
302
  var list = Array.isArray(signers) ? _b.reqDenseArray(signers, "the signer list") : [signers];
496
303
  if (!list.length) throw _err("cms/bad-input", "pki.cms.sign requires at least one signer");
497
304
  var eContentType = opts.eContentType ? O(opts.eContentType) : OID_DATA;
498
- // RFC 5272 sec. 3.2: "If the request key is used for signing, there MUST be only
499
- // one SignerInfo in the SignedData." That clause governs a Full PKI Request, so
500
- // it binds HERE only for that content type. CMS itself is happy with several
501
- // SignerInfos, and a key-only signer's certificate can reach a verifier by other
502
- // means -- applying the CMC rule to every content type would refuse ordinary
503
- // SignedData that nothing objects to. pki.cmc.build enforces the same rule on
504
- // the message it assembles, which is where the clause is really about.
505
305
  if (eContentType === OID_PKI_DATA && list.length > 1 &&
506
306
  list.some(function (s) { return s && s.cert == null && s.spki != null; })) {
507
307
  throw _err("cms/bad-input",
508
308
  "a key-only signer must be the ONLY SignerInfo in a Full PKI Request (RFC 5272 sec. 3.2)");
509
309
  }
510
- // RFC 5652 sec. 5.3: signed attributes MUST be present (carrying a content-type attribute)
511
- // whenever the encapsulated content type is not id-data, so signedAttributes:false is only
512
- // valid for id-data content. Refusing it here keeps cms.sign from emitting a non-conformant
513
- // SignedData (e.g. a timestamp token, id-ct-TSTInfo, with no signed attributes).
514
310
  if (opts.signedAttributes === false && eContentType !== OID_DATA) {
515
311
  throw _err("cms/bad-input", "signed attributes are required when eContentType is not id-data (RFC 5652 sec. 5.3)");
516
312
  }
517
- // The signer's half of the signed-attribute stripping problem
518
- // (draft-vangeest-lamps-cms-euf-cma-signeddata, Attack Type 2). Signing attribute-shaped content
519
- // without attributes produces a signature that can afterwards be promoted into an
520
- // attributes-present message, because the signature does not commit to which mode was used: the
521
- // attacker attaches the signed bytes as the SignedAttributes and swaps in whatever content their
522
- // message-digest attribute names. Refusing to mint the ambiguous signature is the only point at
523
- // which this direction can be stopped -- by the time it is a message, the damage is done.
524
313
  if (opts.signedAttributes === false && cms.looksLikeSignedAttributes(contentBuf)) {
525
314
  throw _err("cms/ambiguous-content", "this content is itself an encoded SignedAttributes block, so signing " +
526
315
  "it WITHOUT signed attributes would produce a signature that could be re-presented as one over " +
527
316
  "attributes (RFC 5652 sec. 5.4); sign it with signed attributes instead");
528
317
  }
529
- // A supplied signing-time MUST be a valid Date (or false to omit the attribute), never a
530
- // silently-ignored non-Date or an Invalid Date that would encode a garbage Time.
531
318
  if (opts.signingTime != null && opts.signingTime !== false) guard.time.assertValid(opts.signingTime, _err, "cms/bad-input", "signingTime");
532
319
 
533
320
  return Promise.all(list.map(function (s) { return _buildSignerInfo(s, contentBuf, eContentType, opts); }))
534
321
  .then(function (built) { return _assembleSignedData(built, eContentType, opts, contentBuf); });
535
322
  }
536
323
 
537
- // Assemble the SignedData ContentInfo (RFC 5652 sec. 5.1) from the built SignerInfos: the deduped
538
- // digestAlgorithms set, the coupled CMSVersion, the EncapsulatedContentInfo (eContent omitted when
539
- // detached, the only form a streamed content takes), the deduped certificates [0], and the
540
- // signerInfos SET OF. `contentBuf` is the content bytes for the attached form, or null when detached.
541
324
  function _assembleSignedData(built, eContentType, opts, contentBuf) {
542
- // digestAlgorithms: the distinct SignerInfo digestAlgorithm AlgorithmIdentifiers, deduped. Captured
543
- // enumeration throughout: this assembly runs after a streamed content's iterator may have replaced
544
- // Array.prototype.map / forEach / Buffer.prototype.toString, and a live one could drop SignerInfos
545
- // from the emitted CMS or mis-dedup the algorithm / certificate sets.
546
325
  var seen = {}, digestAlgs = [];
547
326
  intrinsic.forEach(built, function (x) { var k = intrinsic.bufToString(x.digestAlgId, "hex"); if (!seen[k]) { seen[k] = 1; intrinsic.push(digestAlgs, x.digestAlgId); } });
548
- // CMSVersion (RFC 5652 sec. 5.1): 3 if any SignerInfo is v3 (ski) or eContentType != id-data;
549
- // otherwise 1 (v1 emits only X.509 certificates, so the v4/v5 attribute-certificate cases
550
- // do not arise).
551
327
  var v3 = intrinsic.some(built, function (x) { return x.version === 3; }) || eContentType !== OID_DATA;
552
328
  var version = v3 ? 3 : 1;
553
- // EncapsulatedContentInfo: eContentType + [0] EXPLICIT eContent (omitted when detached).
554
329
  var encapFields = [b.oid(eContentType)];
555
330
  if (!opts.detached) intrinsic.push(encapFields, b.explicit(0, b.octetString(contentBuf)));
556
331
  var encap = b.sequence(encapFields);
557
- // certificates [0] IMPLICIT SET OF (the signer certs), deduped + SET-OF-ordered, when embedded.
558
332
  var sdFields = [b.integer(BigInt(version)), b.set(digestAlgs), encap];
559
333
  if (opts.certificates !== false) {
560
- // A key-only signer contributes no certificate (certDer is null), so the
561
- // set can end up EMPTY -- and an empty certificates [0] is not the same as
562
- // an absent one, so the field is omitted entirely in that case.
563
334
  var certDers = intrinsic.sort(_dedupe(intrinsic.filter(intrinsic.map(built, function (x) { return x.certDer; }),
564
- function (d) { return d != null; })), intrinsic.compare); // X.690 sec. 11.6
565
- if (certDers.length) intrinsic.push(sdFields, b.contextConstructed(0, intrinsic.bufferConcat(certDers))); // [0] IMPLICIT SET OF
335
+ function (d) { return d != null; })), intrinsic.compare);
336
+ if (certDers.length) intrinsic.push(sdFields, b.contextConstructed(0, intrinsic.bufferConcat(certDers)));
566
337
  }
567
- intrinsic.push(sdFields, b.set(intrinsic.map(built, function (x) { return x.si; }))); // signerInfos SET OF
338
+ intrinsic.push(sdFields, b.set(intrinsic.map(built, function (x) { return x.si; })));
568
339
  var signedData = b.sequence(sdFields);
569
- var contentInfo = b.sequence([b.oid(OID_SIGNED_DATA), b.explicit(0, signedData)]); // ContentInfo
340
+ var contentInfo = b.sequence([b.oid(OID_SIGNED_DATA), b.explicit(0, signedData)]);
570
341
  return opts.pem ? pkix.pemEncode(contentInfo, "CMS", frameworkError.PemError) : contentInfo;
571
342
  }
572
343
 
573
- // Dedupe certificate DERs (two signers may share a cert, so embed it once).
574
344
  function _dedupe(ders) {
575
345
  var seen = {}, out = [];
576
346
  intrinsic.forEach(ders, function (d) { var k = intrinsic.bufToString(d, "hex"); if (!seen[k]) { seen[k] = 1; intrinsic.push(out, d); } });
577
347
  return out;
578
348
  }
579
349
 
580
- // ---- pki.cms.certsOnly (RFC 8551 sec. 3.8 / RFC 5652 sec. 5.1) --------------
581
- // A certificate-management ("certs-only") message: a degenerate SignedData that conveys
582
350
  // certificates and/or CRLs and signs nothing. Documented by the @primitive block in cms-verify.js
583
351
  // (the @module pki.cms home).
584
352
  var KNOWN_CERTS_ONLY_OPTS = { crls: 1, pem: 1 };
585
353
 
586
- // A single entity or an array of them -> a dense array (empty when the argument is nullish).
587
- // reqDenseArray snapshots the array structure and refuses a sparse hole or a nullish entry
588
- // (M15), so a caller array that mutates under iteration cannot reintroduce a hole.
589
354
  function _certsOnlyList(v, what) {
590
355
  if (v == null) return [];
591
356
  return intrinsic.isArray(v) ? _b.reqDenseArray(v, what) : [v];
592
357
  }
593
358
 
594
- // Normalize one caller-supplied certificate/CRL to validated raw DER: snapshot the byte source at
595
- // the door so a later mutation cannot swap the bytes (M15), accept a PEM block, then parse it with
596
- // `parseFn` so a non-<thing> -- including a tagged CertificateChoices / RevocationInfoChoice
597
- // alternative, whose first byte is a context tag rather than 0x30 -- is a typed cms/bad-input and is
598
- // never embedded (M9/M10/M11). `pemLabel` is the PEM armor type.
599
359
  function _normEntityDer(v, what, pemLabel, parseFn) {
600
360
  var der;
601
361
  if (guard.bytes.isByteSource(v)) {
@@ -624,19 +384,14 @@ function certsOnly(certs, opts) {
624
384
  guard.identifier.assertKnownKeys(opts, KNOWN_CERTS_ONLY_OPTS, _err, "cms/bad-input", "unknown opts field ");
625
385
  var certList = _certsOnlyList(certs, "certificates");
626
386
  var crlList = _certsOnlyList(opts.crls, "crls");
627
- // RFC 8551 sec. 3.8 conveys "certificates and/or CRLs"; a message with neither conveys nothing.
628
387
  if (!certList.length && !crlList.length) throw _err("cms/bad-input", "a certs-only message must carry at least one certificate or CRL (RFC 8551 sec. 3.8)");
629
- // Each entity validated + snapshotted at the door, then DER-sorted + deduped (X.690 sec. 11.6).
630
388
  var certDers = intrinsic.sort(_dedupe(intrinsic.map(certList, function (c) { return _normEntityDer(c, "a certificate", "CERTIFICATE", _parseX509); })), intrinsic.compare);
631
389
  var crlDers = intrinsic.sort(_dedupe(intrinsic.map(crlList, function (c) { return _normEntityDer(c, "a CRL", "X509 CRL", _parseCrl); })), intrinsic.compare);
632
- // The degenerate SignedData (RFC 5652 sec. 5.1): version 1 (all choices plain, id-data, no signer),
633
- // an empty digestAlgorithms + signerInfos, an id-data encapContentInfo with eContent ABSENT, and the
634
- // caller certificates [0] / crls [1]. The strict re-parse enforces the version<->contents coupling.
635
390
  var encap = b.sequence([b.oid(OID_DATA)]);
636
391
  var sdFields = [b.integer(1n), b.set([]), encap];
637
- if (certDers.length) intrinsic.push(sdFields, b.contextConstructed(0, intrinsic.bufferConcat(certDers))); // [0] IMPLICIT SET OF
638
- if (crlDers.length) intrinsic.push(sdFields, b.contextConstructed(1, intrinsic.bufferConcat(crlDers))); // [1] IMPLICIT SET OF
639
- intrinsic.push(sdFields, b.set([])); // signerInfos SET OF {}
392
+ if (certDers.length) intrinsic.push(sdFields, b.contextConstructed(0, intrinsic.bufferConcat(certDers)));
393
+ if (crlDers.length) intrinsic.push(sdFields, b.contextConstructed(1, intrinsic.bufferConcat(crlDers)));
394
+ intrinsic.push(sdFields, b.set([]));
640
395
  var signedData = b.sequence(sdFields);
641
396
  var contentInfo = b.sequence([b.oid(OID_SIGNED_DATA), b.explicit(0, signedData)]);
642
397
  return opts.pem ? pkix.pemEncode(contentInfo, "CMS", frameworkError.PemError) : contentInfo;
@@ -647,15 +402,7 @@ function _toBuf(v, what) {
647
402
  throw _err("cms/bad-input", what + " must be a Buffer");
648
403
  }
649
404
 
650
- // ---- pki.cms.countersign (RFC 5652 sec. 11.4) ------------------------------
651
- // A countersignature is a SignerInfo (Countersignature ::= SignerInfo) over the contents of the
652
- // countersigned SignerInfo's signature OCTET STRING, never the eContent, attached as the
653
- // id-countersignature unsigned attribute. It reuses the whole build+sign flow (resolveSignScheme /
654
- // _buildSid / _buildSignedAttrs / signOverTbs); only the preimage (the target signature octets) and
655
- // the omitted content-type are the deltas, and the orchestrator splices the [1] unsignedAttrs into
656
- // an existing SignedData while preserving the targeted SignerInfo's signed bytes BYTE-FOR-BYTE.
657
405
 
658
- // Resolve opts.signerIndex (a number, an array of numbers, or "all"; default 0) to primary indices.
659
406
  function _resolveSignerIndices(spec, n) {
660
407
  if (spec == null) { if (n < 1) throw _err("cms/bad-input", "the SignedData carries no SignerInfo to countersign"); return [0]; }
661
408
  if (spec === "all") { var all = []; for (var i = 0; i < n; i++) all.push(i); return all; }
@@ -665,18 +412,15 @@ function _resolveSignerIndices(spec, n) {
665
412
  return arr;
666
413
  }
667
414
 
668
- // Build one countersignature value (RFC 5652 sec. 11.4) over `targetSigOctets`: message-digest bound
669
- // to digest(targetSigOctets) under the countersignature's own digestAlgorithm, content-type omitted,
670
- // signed through the same per-algorithm scheme machinery as a top-level signer.
671
415
  function _buildCountersignature(targetSigOctets, countersigner, opts) {
672
416
  var so = countersigner || {};
673
417
  var certDer = _normCertDer(so.cert);
674
418
  var cert = x509.parse(certDer);
675
419
  var scheme = signScheme.resolveSignScheme(cert, so, opts.signedAttributes === false, _signE);
676
420
  var sidv = _buildSid(cert, opts.sid === "ski");
677
- var soKey = so.key; // read once, here -- the SignerIdentifier above is already fixed to `cert`
421
+ var soKey = so.key;
678
422
  return Promise.resolve().then(function () {
679
- if (opts.signedAttributes === false) return null; // sign the target signature octets directly
423
+ if (opts.signedAttributes === false) return null;
680
424
  return _digest(scheme.digest, targetSigOctets).then(function (md) {
681
425
  var pairs = [{ type: O("messageDigest"), values: [b.octetString(md)] }];
682
426
  if (opts.signingTime !== false) pairs.push({ type: O("signingTime"), values: [_timeValue(opts.signingTime)] });
@@ -687,16 +431,13 @@ function _buildCountersignature(targetSigOctets, countersigner, opts) {
687
431
  }).then(function (attrs) {
688
432
  return signScheme.signOverTbs(scheme, soKey, attrs ? attrs.setOf : targetSigOctets, _signE).then(function (sig) {
689
433
  var fields = [b.integer(BigInt(sidv.version)), sidv.sid, scheme.digestAlgId];
690
- if (attrs) fields.push(attrs.wire); // [0] IMPLICIT signedAttrs
434
+ if (attrs) fields.push(attrs.wire);
691
435
  fields.push(scheme.sigAlgId, b.octetString(sig));
692
436
  return { value: b.sequence(fields), certDer: certDer };
693
437
  });
694
438
  });
695
439
  }
696
440
 
697
- // Build the [1] IMPLICIT unsignedAttrs bytes for a SignerInfo, merging `newCsValues` into the single
698
- // id-countersignature attribute (RFC 5652 sec. 11: one instance per type, multiple values), and
699
- // keeping every other unsigned attribute and every existing countersignature value verbatim.
700
441
  function _mergeCountersig(uaNode, newCsValues) {
701
442
  var CS = O("countersignature");
702
443
  var others = [], csValues = [];
@@ -707,13 +448,10 @@ function _mergeCountersig(uaNode, newCsValues) {
707
448
  newCsValues.forEach(function (v) { csValues.push(v); });
708
449
  var csAttr = b.sequence([b.oid(CS), b.set(csValues)]);
709
450
  var setOf = b.set(others.concat([csAttr]));
710
- var wire = Buffer.from(setOf); wire[0] = 0xA1; // SET OF -> [1] IMPLICIT UnsignedAttributes
451
+ var wire = Buffer.from(setOf); wire[0] = 0xA1;
711
452
  return wire;
712
453
  }
713
454
 
714
- // Append countersignature values to a SignerInfo node, preserving version / sid / digestAlgorithm /
715
- // signedAttrs / signatureAlgorithm / signature BYTE-FOR-BYTE (the signed preimage), only adding the
716
- // [1] unsignedAttrs. Returns the new SignerInfo bytes.
717
455
  function _appendCountersigs(siNode, newCsValues) {
718
456
  var kids = siNode.children;
719
457
  var last = kids[kids.length - 1];
@@ -723,8 +461,6 @@ function _appendCountersigs(siNode, newCsValues) {
723
461
  return b.sequence(base);
724
462
  }
725
463
 
726
- // Splice countersignature values into the j-th countersignature VALUE of a SignerInfo node (nested
727
- // countersignature, RFC 5652 sec. 11.4). Returns the new SignerInfo bytes.
728
464
  function _spliceNested(siNode, j, newCsValues) {
729
465
  var kids = siNode.children;
730
466
  var last = kids[kids.length - 1];
@@ -745,8 +481,6 @@ function _spliceNested(siNode, j, newCsValues) {
745
481
  return b.sequence(base);
746
482
  }
747
483
 
748
- // The signature-value octets of a SignerInfo node: the last universal OCTET STRING, i.e. the last
749
- // child unless a [1] IMPLICIT unsignedAttrs (a prior countersignature) follows it.
750
484
  function _signatureOctets(siNode) {
751
485
  var kids = siNode.children;
752
486
  var last = kids[kids.length - 1];
@@ -754,8 +488,6 @@ function _signatureOctets(siNode) {
754
488
  return asn1.read.octetString(sigNode);
755
489
  }
756
490
 
757
- // The sec. 11.4 preimage for a target: the primary SignerInfo's signature octets, or (nested) the
758
- // j-th countersignature value's signature octets.
759
491
  function _targetPreimage(siNode, opts) {
760
492
  if (opts.countersignatureOf == null) return _signatureOctets(siNode);
761
493
  var last = siNode.children[siNode.children.length - 1];
@@ -770,11 +502,7 @@ function _targetPreimage(siNode, opts) {
770
502
  }
771
503
 
772
504
  // pki.cms.countersign -- documented by the @primitive block in cms-verify.js (the @module pki.cms home).
773
- // Documented `-> Promise`, so a fault leaves as a rejection (guard-async).
774
505
  function countersign(cmsInput, signers, opts) {
775
- // Every caller-owned argument copied at entry and released when the call settles; see the note
776
- // on the same call in x509-sign. `signerIndex` and `countersignatureOf` select which signature is
777
- // countersigned, so a late read could attach the countersignature to a different one.
778
506
  return guard.bytes.fixedCall(CmsError, "cms/bad-input", [
779
507
  [cmsInput, "the CMS message"], [signers, "the signer list"], [opts, "pki.cms.countersign options"],
780
508
  ], _countersign);
@@ -787,8 +515,6 @@ function _countersign(cmsInput, signers, opts) {
787
515
  if (!list.length) throw _err("cms/bad-input", "pki.cms.countersign requires at least one countersigner");
788
516
  if (opts.signingTime != null && opts.signingTime !== false) guard.time.assertValid(opts.signingTime, _err, "cms/bad-input", "signingTime");
789
517
  var der = pkix.coerceToDer(cmsInput, { pemLabel: null, PemError: frameworkError.PemError, ErrorClass: CmsError, prefix: "cms" });
790
- // cms.parse throws a typed cms/* error on a malformed input (mirroring verify's own parse call); a
791
- // structurally-valid but non-SignedData CMS (an EnvelopedData) parses without a signerInfos array.
792
518
  var parsed = cms.parse(der);
793
519
  if (!Array.isArray(parsed.signerInfos)) throw _err("cms/bad-input", "pki.cms.countersign input is not a CMS SignedData");
794
520
  var targets = _resolveSignerIndices(opts.signerIndex, parsed.signerInfos.length);
@@ -797,7 +523,6 @@ function _countersign(cmsInput, signers, opts) {
797
523
  var sdKids = sd.children;
798
524
  var siSet = sdKids[sdKids.length - 1];
799
525
 
800
- // Build every countersignature value (target x countersigner), then splice into the node tree.
801
526
  var jobs = [];
802
527
  targets.forEach(function (t) {
803
528
  var preimage = _targetPreimage(siSet.children[t], opts);
@@ -812,8 +537,6 @@ function _countersign(cmsInput, signers, opts) {
812
537
  return opts.countersignatureOf == null ? _appendCountersigs(siNode, byTarget[idx]) : _spliceNested(siNode, opts.countersignatureOf, byTarget[idx]);
813
538
  }));
814
539
 
815
- // Rebuild SignedData: version, digestAlgorithms (unchanged, since a countersignature digest is not a
816
- // SignedData digestAlgorithm), encapContentInfo, certificates [0]?, crls [1]?, the new signerInfos.
817
540
  var certsNode = null, crlsNode = null;
818
541
  for (var i = 3; i < sdKids.length - 1; i++) {
819
542
  if (sdKids[i].tagClass === "context" && sdKids[i].tagNumber === 0) certsNode = sdKids[i];
@@ -822,9 +545,9 @@ function _countersign(cmsInput, signers, opts) {
822
545
  var existing = [];
823
546
  if (certsNode) certsNode.children.forEach(function (c) { existing.push(c.bytes); });
824
547
  if (opts.certificates !== false) certDers.forEach(function (d) { existing.push(d); });
825
- var allCerts = _dedupe(existing).sort(Buffer.compare); // X.690 sec. 11.6
548
+ var allCerts = _dedupe(existing).sort(Buffer.compare);
826
549
 
827
- var newSdFields = [sdKids[0].bytes, sdKids[1].bytes, sdKids[2].bytes]; // version, digestAlgs, encap (raw)
550
+ var newSdFields = [sdKids[0].bytes, sdKids[1].bytes, sdKids[2].bytes];
828
551
  if (allCerts.length) newSdFields.push(b.contextConstructed(0, Buffer.concat(allCerts)));
829
552
  if (crlsNode) newSdFields.push(crlsNode.bytes);
830
553
  newSdFields.push(newSiSet);
@@ -833,27 +556,9 @@ function _countersign(cmsInput, signers, opts) {
833
556
  });
834
557
  }
835
558
 
836
- // Coverage residual: three defensive branches are unreachable through the shipped path.
837
- // * `_skiValue`'s `cert.extensions || []` fallback. x509.parse always surfaces `extensions`
838
- // as an array (empty when absent), so the `|| []` never fires.
839
- // * `_assertKeyMatchesScheme`'s `key.algorithm || {}`. A WebCrypto CryptoKey always carries
840
- // an `algorithm`, so the `|| {}` fallback never fires.
841
- // * `_assertKeyMatchesScheme`'s `!ka.hash` guard. An `imp.hash` is set only for an RSA
842
- // scheme, which requires `ka.name` to already equal the RSA name (else the earlier name
843
- // check throws); an RSA CryptoKey always carries a `hash`, so `!ka.hash` never fires.
844
- // Countersign-side residuals also unreachable through the shipped path:
845
- // * `_resolveSignerIndices`'s `n < 1` throw. A parsed SignedData always carries at least one
846
- // SignerInfo, so the default index [0] is always in range.
847
- // * `_spliceNested`'s no-countersignature / index-out-of-range / not-found throws. The same node
848
- // is validated by `_targetPreimage` first (it computes the nested preimage before the build), so
849
- // by the time `_spliceNested` re-walks it those conditions cannot hold; the checks are
850
- // belt-and-suspenders against a future caller reordering the two.
851
- // * the `crls [1]` preservation branches in `countersign`. pki.cms.sign never emits a crls field,
852
- // so a store this producer countersigns never carries one to preserve.
853
559
  module.exports = {
854
560
  sign: sign, countersign: countersign, certsOnly: certsOnly,
855
- // @internal -- the signer-descriptor field tables, for a verb that AUTHORS signer descriptors
856
- // from its own caller's options and gates them at its own door.
561
+ // @internal
857
562
  KNOWN_SIGNER_CERT_KEYS: KNOWN_SIGNER_CERT_KEYS,
858
563
  KNOWN_SIGNER_KEY_ONLY_KEYS: KNOWN_SIGNER_KEY_ONLY_KEYS,
859
564
  };