@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/crl-verify.js CHANGED
@@ -1,22 +1,13 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  // Copyright (c) blamejs contributors
3
3
  "use strict";
4
- //
5
- // @internal -- the single CRL signature-verify seam, shared by pki.path.crlChecker and pki.crl.verify
6
- // so both route through one signature engine (algorithm-confusion + EdDSA low-order + composite
7
- // gates) and no second, weaker CRL verifier can drift. The slot, the wiring assertion and the
8
- // octet-alignment refusal are the shared seam (lib/verify-seam.js). The seam lives in this internal
9
- // module, not on path-validate's module.exports, which keeps it off the public pki.path surface: it
10
- // takes the path-internal SubjectPublicKeyInfo bytes, not a documented issuer shape. It is not
11
- // wired into index.js and is reached only by require.
4
+ // @internal
12
5
 
13
6
  var frameworkError = require("./framework-error");
14
7
  var seam = require("./verify-seam");
15
8
 
16
9
  var _seam = seam.makeSeam("crl-verify", frameworkError.CrlError, "crl/bad-input");
17
10
 
18
- // Verify a parsed CRL's signature over its raw tbsCertList bytes under the issuer
19
- // SubjectPublicKeyInfo DER.
20
11
  function verifyCrlSignature(crl, spkiBytes) {
21
12
  return _seam.verify(crl.signatureAlgorithm, crl.signatureValue, spkiBytes, crl.tbsBytes);
22
13
  }
package/lib/crmf-sign.js CHANGED
@@ -16,14 +16,6 @@
16
16
  * @spec RFC 4211
17
17
  * @card Build a CRMF CertReqMessages with a signature proof of possession.
18
18
  */
19
- //
20
- // RFC 4211 App. B / RFC 5912 sec. 10 are DEFINITIONS IMPLICIT TAGS: a CertTemplate [0]..[9] field tag
21
- // REPLACES the base universal tag (built via asn1.build.implicit, preserving the primitive/constructed
22
- // bit); the shipped parser encodes issuer [3] / subject [5] Name IMPLICITLY (the dominant CMP/EST wire
23
- // form), so the builder does too. The two EXPLICIT exceptions are the OptionalValidity notBefore [0] /
24
- // notAfter [1] Time (a genuine UTCTime/GeneralizedTime CHOICE). The signature scheme resolves from the
25
- // requested publicKey through the shared sign-scheme registry; the Name / extension / SPKI encoders and
26
- // the post-sign self-check are the shared lib/pki-build primitives, bound to the crmf namespace.
27
19
 
28
20
  var asn1 = require("./asn1-der");
29
21
  var oid = require("./oid");
@@ -34,14 +26,12 @@ var pkiBuild = require("./pki-build");
34
26
  var frameworkError = require("./framework-error");
35
27
  var guard = require("./guard-all");
36
28
  var intrinsic = require("./guard-intrinsic");
37
- // Own-key membership through an operation taken at load: it decides which proof-of-possession
38
- // alternative a request carries, and a name reached from the prototype is one the RFC never defined.
39
29
  var _hasOwn = intrinsic.hasOwn;
40
30
  var _stringify = intrinsic.stringify;
41
31
  var cms = require("./schema-cms");
42
32
  var cmsEncrypt = require("./cms-encrypt");
43
33
  var key = require("./key");
44
- require("./path-validate"); // side-effect: path-validate injects its signature engine into crmf-verify at load
34
+ require("./path-validate");
45
35
  var crmfVerify = require("./crmf-verify");
46
36
 
47
37
  var CrmfError = frameworkError.CrmfError;
@@ -58,14 +48,6 @@ var _b = pkiBuild.makeBuilder({
58
48
  });
59
49
 
60
50
  var KNOWN_SPEC_KEYS = { certReqId: 1, certTemplate: 1, controls: 1, regInfo: 1, pop: 1 };
61
- // spec.pop across all four ProofOfPossession arms: `type` picks the arm; `raVerified` and `sender`
62
- // belong to the raVerified / signature arms; the rest to POPOPrivKey (RFC 4211 sec. 4.2, 4.3).
63
- // spec.pop is a CHOICE, so the accepted key set is per ARM rather than a union of all of them. A
64
- // single flat list would accept `{ type: 'keyEncipherment', method: 'subsequentMessage', privateKey,
65
- // recipients, archive: true }`: a caller who believed they were sending the key that way gets a
66
- // message that declares a later exchange instead, with the three fields they supplied read by
67
- // nothing. `type` and `method` are what pick the arm, so they are read first and the rest is checked
68
- // against the arm the caller chose.
69
51
  var POP_KEYS_BY_ARM = {
70
52
  raVerified: { type: 1, raVerified: 1 },
71
53
  signature: { type: 1, sender: 1 },
@@ -74,8 +56,6 @@ var POP_KEYS_BY_ARM = {
74
56
  type: 1, method: 1, privateKey: 1, identifier: 1, recipients: 1, archive: 1,
75
57
  contentEncryptionAlgorithm: 1,
76
58
  },
77
- // The arms that refuse before they read anything else still need a set, so the refusal a caller
78
- // sees names the method rather than an unknown field alongside it.
79
59
  agreeMAC: { type: 1, method: 1 },
80
60
  thisMessage: { type: 1, method: 1 },
81
61
  dhMAC: { type: 1, method: 1 },
@@ -83,72 +63,50 @@ var POP_KEYS_BY_ARM = {
83
63
  var KNOWN_BATCH_KEYS = { messages: 1 };
84
64
  var KNOWN_TEMPLATE_KEYS = { version: 1, subject: 1, publicKey: 1, validity: 1, extensions: 1, issuer: 1 };
85
65
  var REVOCATION_TEMPLATE_KEYS = { version: 1, subject: 1, publicKey: 1, validity: 1, extensions: 1, issuer: 1, serialNumber: 1 };
86
- // The controls (RFC 4211 sec. 6) and regInfo (sec. 7) are disjoint AttributeTypeAndValue namespaces:
87
- // regToken/authenticator/oldCertID/protocolEncrKey are controls and utf8Pairs is regInfo, so the object
88
- // form validates each key against its own field's registry (a control name is not a valid regInfo, and
89
- // vice versa). The key name equals the registered OID name; complex values (pkiPublicationInfo, certReq)
90
- // ride the pre-encoded escape hatch. Each entry is the value encoder for that OID.
91
66
  function _ctlUtf8(v) { return b.utf8(String(v)); }
92
67
  function _ctlSpki(v) { var k = _b.reqDer(v, "protocolEncrKey (an SPKI DER)"); _b.assertValidSpki(k, "protocolEncrKey"); return b.raw(k); }
93
68
  var CONTROL_VALUE = { regToken: _ctlUtf8, authenticator: _ctlUtf8, oldCertID: function (v) { return _encodeCertId(v); }, protocolEncrKey: _ctlSpki };
94
69
  var REGINFO_VALUE = { utf8Pairs: _ctlUtf8 };
95
70
 
96
- // ---- CertTemplate + POP structural encoders (byte-exact inverses of schema-crmf.js) ----
97
71
 
98
- // OptionalValidity [4] IMPLICIT SEQUENCE { notBefore [0] EXPLICIT Time, notAfter [1] EXPLICIT Time } --
99
- // at least one present (RFC 4211 sec. 5). Time is a CHOICE so [0]/[1] are EXPLICIT.
100
72
  function _encodeOptionalValidity(validity) {
101
73
  if (!validity || typeof validity !== "object" || Buffer.isBuffer(validity)) throw _err("crmf/bad-validity", "validity must be an object { notBefore?, notAfter? }");
102
74
  var nb = validity.notBefore, na = validity.notAfter;
103
75
  if (nb == null && na == null) throw _err("crmf/bad-validity", "validity must contain notBefore or notAfter (RFC 4211 sec. 5)");
104
76
  var parts = [];
105
- // timeDer validates each instant (guard.time.assertValid throws on an Invalid Date) before the
106
- // inverted-window comparison, so getTime() below cannot be NaN.
107
77
  if (nb != null) parts.push(b.explicit(0, _b.timeDer(nb, "validity notBefore")));
108
78
  if (na != null) parts.push(b.explicit(1, _b.timeDer(na, "validity notAfter")));
109
79
  // allow:nan-date-comparison-unguarded -- both instants passed timeDer's guard.time.assertValid above.
110
80
  if (nb != null && na != null && guard.time.instantOf(nb) > guard.time.instantOf(na)) throw _err("crmf/bad-validity", "notBefore must not be after notAfter");
111
81
  return b.implicit(4, b.sequence(parts));
112
82
  }
113
- // CertTemplate ::= SEQUENCE { [0..9] all IMPLICIT OPTIONAL }. A request omits serialNumber [1] / signingAlg
114
- // [2] / issuerUID [7] / subjectUID [8] (CA-assigned or deprecated, RFC 4211 sec. 5), and the builder never
115
- // emits them. Fields are emitted in ascending tag order.
116
83
  function _encodeCertTemplate(tpl, opts) {
117
84
  if (!tpl || typeof tpl !== "object" || Buffer.isBuffer(tpl)) throw _err("crmf/bad-cert-template", "certTemplate must be an object");
118
- // A request template omits serialNumber (CA-assigned, RFC 4211 sec. 5); a revocation template (CMP rr,
119
- // RFC 9810 sec. 5.3.9) carries serialNumber [1] to name the certificate to revoke, allowed only then.
120
85
  var allowed = (opts && opts.revocation) ? REVOCATION_TEMPLATE_KEYS : KNOWN_TEMPLATE_KEYS;
121
86
  guard.identifier.assertKnownKeys(tpl, allowed, _err, "crmf/bad-input", "unknown certTemplate field ");
122
87
  var fields = [];
123
88
  if (tpl.version != null) {
124
89
  if (tpl.version !== 2) throw _err("crmf/bad-version", "certTemplate version MUST be 2 (v3) if supplied (RFC 4211 sec. 5)");
125
- fields.push(b.implicit(0, b.integer(2n))); // version [0]
90
+ fields.push(b.implicit(0, b.integer(2n)));
126
91
  }
127
- if (tpl.serialNumber != null) fields.push(b.implicit(1, _b.serialInteger(tpl.serialNumber))); // serialNumber [1] (revocation only)
128
- // issuer [3] / subject [5] are EXPLICIT: Name is a CHOICE, and X.680 sec. 31.2.7 forces a context tag on
129
- // a CHOICE to EXPLICIT even under the module's IMPLICIT TAGS default (the [3]/[5] wraps the RDNSequence
130
- // SEQUENCE, it does not replace its tag). The parser accepts both forms; this is the conformant one.
131
- if (tpl.issuer != null) fields.push(b.explicit(3, _b.encodeName(tpl.issuer))); // issuer [3] EXPLICIT
132
- if (tpl.validity != null) fields.push(_encodeOptionalValidity(tpl.validity)); // validity [4] IMPLICIT
133
- if (tpl.subject != null) fields.push(b.explicit(5, _b.encodeName(tpl.subject))); // subject [5] EXPLICIT
92
+ if (tpl.serialNumber != null) fields.push(b.implicit(1, _b.serialInteger(tpl.serialNumber)));
93
+ if (tpl.issuer != null) fields.push(b.explicit(3, _b.encodeName(tpl.issuer)));
94
+ if (tpl.validity != null) fields.push(_encodeOptionalValidity(tpl.validity));
95
+ if (tpl.subject != null) fields.push(b.explicit(5, _b.encodeName(tpl.subject)));
134
96
  var spki = null;
135
97
  if (tpl.publicKey != null) {
136
98
  spki = _b.reqDer(tpl.publicKey, "certTemplate.publicKey (the SPKI DER of the requested key)");
137
99
  _b.assertValidSpki(spki, "certTemplate.publicKey");
138
- fields.push(b.implicit(6, spki)); // publicKey [6]
100
+ fields.push(b.implicit(6, spki));
139
101
  }
140
- if (tpl.extensions != null) fields.push(b.implicit(9, _b.requestedExtensions(tpl.extensions, spki))); // extensions [9]
102
+ if (tpl.extensions != null) fields.push(b.implicit(9, _b.requestedExtensions(tpl.extensions, spki)));
141
103
  return { der: b.sequence(fields), spki: spki, complete: tpl.subject != null && tpl.publicKey != null };
142
104
  }
143
105
 
144
- // Controls / regInfo ::= SEQUENCE SIZE(1..MAX) OF AttributeTypeAndValue { type OID, value ANY }. Object
145
- // form maps recognized names to typed value encoders; any other (or a pre-encoded AttributeTypeAndValue
146
- // DER array) rides the escape hatch, shape-validated.
147
106
  function _buildAttrTypeAndValues(spec, code, label, valueMap) {
148
107
  if (Array.isArray(spec)) {
149
108
  if (!spec.length) throw _err(code, label + " must carry at least one entry");
150
109
  var seenA = {};
151
- // Density before the map, which would otherwise skip a hole into b.sequence as a native error.
152
110
  return b.sequence(pkiBuild.reqDenseArray(spec, label, _err, code).map(function (e, i) {
153
111
  var der = _b.reqDer(e, label + " [" + i + "]");
154
112
  var n;
@@ -176,9 +134,6 @@ function _buildAttrTypeAndValues(spec, code, label, valueMap) {
176
134
  if (!out.length) throw _err(code, label + " must carry at least one entry");
177
135
  return b.sequence(out);
178
136
  }
179
- // certReqId is a signed INTEGER, value UNCONSTRAINED (the RFC 9483 -1 sentinel and 0 are both legal). A
180
- // number must be a safe integer (a fractional or > 2^53 number loses precision through BigInt); a BigInt
181
- // or a decimal / 0x-hex string carries an arbitrary value.
182
137
  function _certReqId(v) {
183
138
  if (v == null) return 0n;
184
139
  if (typeof v === "bigint") return v;
@@ -186,49 +141,22 @@ function _certReqId(v) {
186
141
  if (typeof v === "string") { try { return BigInt(v); } catch (e) { throw _err("crmf/bad-input", "certReqId string must be a decimal or 0x-hex integer", e); } }
187
142
  throw _err("crmf/bad-input", "certReqId must be a BigInt, a safe integer, or a string");
188
143
  }
189
- // CertId ::= SEQUENCE { issuer GeneralName, serialNumber INTEGER } (RFC 4211 sec. 6.4, oldCertID value).
190
144
  function _encodeCertId(id) {
191
145
  if (!id || typeof id !== "object" || id.issuer == null || id.serialNumber == null) throw _err("crmf/bad-input", "oldCertID must be { issuer: GeneralName, serialNumber }");
192
146
  return b.sequence([_b.encodeGeneralName(id.issuer), _b.serialInteger(id.serialNumber)]);
193
147
  }
194
148
 
195
- // The two ProofOfPossession arms a key that cannot sign has to use: keyEncipherment [2] and
196
- // keyAgreement [3], each carrying a POPOPrivKey. Both field tags are EXPLICIT, because POPOPrivKey is
197
- // itself a CHOICE and X.680 sec. 31.2.7 forbids implicit tagging of one. The parser states and
198
- // enforces the same rule (schema-crmf.js), so an implicit emission here would disagree with the
199
- // module's own reader.
200
149
  var POPO_PRIVKEY_TAGS = { keyEncipherment: 2, keyAgreement: 3 };
201
- // SubsequentMessage ::= INTEGER { encrCert (0), challengeResp (1) } (RFC 4211 sec. 4.2).
202
150
  var SUBSEQUENT_MESSAGE = { encrCert: 0n, challengeResp: 1n };
203
- // The specification deprecates two of the five alternatives in the same breath as defining them:
204
- // thisMessage "has been deprecated in favor of encryptedKey", dhMAC "is deprecated in favor of the
205
- // agreeMAC field" (sec. 4.2), and RFC 9810 sec. 5.2.8.3 restates both as `-- deprecated`. A reader
206
- // still has to accept them, since a peer may send one; a producer choosing to emit one today is
207
- // choosing the superseded encoding, so the builder names the successor instead of emitting it.
208
151
  var DEPRECATED_POPO_METHOD = { thisMessage: "encryptedKey", dhMAC: "agreeMAC" };
209
152
 
210
- // EncKeyWithID ::= SEQUENCE { privateKey PrivateKeyInfo,
211
- // identifier CHOICE { string UTF8String, generalName GeneralName } OPTIONAL }
212
- // (RFC 4211 sec. 4.2.1). `identifier` is marked OPTIONAL in the module and then made mandatory by the
213
- // prose for this use: "This field MUST be present if the purpose is to prove possession of the private
214
- // key." The reason is stated there too. Without it an escrow agent decrypts a key without knowing
215
- // whose it is, so an attacker can wrap someone else's intercepted key in a request of their own and
216
- // then ask for it back. Building a POP is that first purpose, so the caller supplies one.
217
153
  function _encKeyWithID(privateKeyDer, identifier) {
218
154
  var idNode;
219
155
  if (typeof identifier === "string") idNode = b.utf8(identifier);
220
- else idNode = _b.encodeGeneralName(identifier); // the GeneralName alternative of the CHOICE
156
+ else idNode = _b.encodeGeneralName(identifier);
221
157
  return b.sequence([b.raw(privateKeyDer), idNode]);
222
158
  }
223
159
 
224
- // POPOPrivKey, the proof an encryption or key-agreement key gives instead of a signature (RFC 4211
225
- // sec. 4.2 / 4.3). A key that cannot sign has no POPOSigningKey available, so without these arms the
226
- // only reachable alternative is raVerified, an RA's assertion and not a proof at all. For a toolkit
227
- // whose signature story is PQC-first that gap lands exactly on ML-KEM enrollment.
228
- //
229
- // `subsequentMessage` carries no cryptography: it declares which follow-up exchange will complete the
230
- // proof, and the completion happens in the enrolling protocol (RFC 9810 sec. 5.2.8.3.2 / .3), not here.
231
- // `encryptedKey` carries the private key itself to the CA, which is why it is gated twice below.
232
160
  function _buildPopoPrivKey(pop, mode, template) {
233
161
  var outerTag = POPO_PRIVKEY_TAGS[mode];
234
162
  var method = pop && pop.method;
@@ -239,20 +167,11 @@ function _buildPopoPrivKey(pop, mode, template) {
239
167
  throw _err("crmf/bad-popo", "the " + method + " proof of possession is deprecated by RFC 4211 sec. 4.2 in favor of " +
240
168
  DEPRECATED_POPO_METHOD[method] + "; a reader still accepts it, a new message should not carry it");
241
169
  }
242
- // sec. 4.2 lists exactly three methods for an encipherment key (the private key provided, a
243
- // decrypted challenge, an encrypted certificate) and introduces the MAC alternatives only in
244
- // sec. 4.3, "for keyAgreement (only)". The parser refuses a MAC arm under keyEncipherment; the
245
- // builder refuses to produce one, so the two directions agree about the same message.
246
170
  if (method === "agreeMAC" && mode === "keyEncipherment") {
247
171
  throw _err("crmf/bad-popo", "keyEncipherment proof of possession cannot use the agreeMAC alternative -- " +
248
172
  "it is defined for keyAgreement only (RFC 4211 sec. 4.2, sec. 4.3)");
249
173
  }
250
174
  if (method === "agreeMAC") {
251
- // Conforming, and not built here. It needs the static Diffie-Hellman shared secret of RFC 2875
252
- // sec. 3, derived between the requester's private key and a CA certificate the requester already
253
- // holds, a classical key-agreement primitive this toolkit does not otherwise carry. It is
254
- // reported, not approximated: verifyPop already names an inbound agreeMAC as unverified, and an
255
- // emitted one nothing here can check would be worse than none.
256
175
  throw _err("crmf/unsupported-popo", "the agreeMAC proof of possession is not built by this toolkit: it requires " +
257
176
  "the RFC 2875 static Diffie-Hellman shared secret between the requester's key and a CA certificate it " +
258
177
  "already holds. Use 'subsequentMessage' (encrCert or challengeResp), which every key type can produce");
@@ -263,27 +182,15 @@ function _buildPopoPrivKey(pop, mode, template) {
263
182
  throw _err("crmf/bad-popo", "pop.subsequentMessage must be 'encrCert' or 'challengeResp' -- " +
264
183
  "SubsequentMessage ::= INTEGER { encrCert (0), challengeResp (1) } has no other value (RFC 4211 sec. 4.2)");
265
184
  }
266
- // subsequentMessage [1] IMPLICIT SubsequentMessage, inside the EXPLICIT [2]/[3] wrapper.
267
185
  return b.explicit(outerTag, b.implicit(1, b.integer(SUBSEQUENT_MESSAGE[which])));
268
186
  }
269
187
  if (method !== "encryptedKey") {
270
188
  throw _err("crmf/bad-popo", "unsupported POPOPrivKey method " + JSON.stringify(method) +
271
189
  " (supported: 'subsequentMessage', 'encryptedKey')");
272
190
  }
273
- // encryptedKey is legal under BOTH outer arms, and the asymmetry with agreeMAC above is the
274
- // specification's own. RFC 4211 sec. 4.3: key-agreement POP "is accomplished by one of four
275
- // different methods. The first three are identical to those presented above for key encryption
276
- // keys" -- and the first of sec. 4.2's three is "The private key can be provided to the CA/RA",
277
- // which is this alternative. Only the fourth, the MAC, is agreement-only. The parser reads
278
- // encryptedKey under both arms for the same reason, so gating it to keyEncipherment here would put
279
- // the producer and the reader back into disagreement about one message.
280
191
  return _buildEncryptedKeyPop(pop, outerTag, template);
281
192
  }
282
193
 
283
- // encryptedKey [4] EnvelopedData. RFC 9810 sec. 5.2.8.3.1: "This method SHALL only be used if archival
284
- // of the private key is desired." Nothing in a builder can confirm that intent, so it is an explicit
285
- // opt-in on the raVerified precedent: handing your private key to the CA should take a sentence that
286
- // says so, not a mistyped method name.
287
194
  function _buildEncryptedKeyPop(pop, outerTag, template) {
288
195
  if (pop.archive !== true) {
289
196
  throw _err("crmf/bad-popo", "an encryptedKey proof of possession sends the requester's private key to the CA, " +
@@ -294,11 +201,6 @@ function _buildEncryptedKeyPop(pop, outerTag, template) {
294
201
  "RFC 4211 sec. 4.2.1 makes EncKeyWithID.identifier mandatory when the purpose is proving possession, so a " +
295
202
  "decrypting agent knows whose key it holds");
296
203
  }
297
- // From here the function owns a plaintext copy of the caller's private key, so every exit clears it.
298
- // The checks below reject a malformed PKCS#8, an empty recipient list, an AEAD algorithm and a
299
- // template with no key, and each of those throws synchronously: cleanup attached only to the
300
- // promise would run on none of them, leaving the copy readable exactly on the paths a caller hits
301
- // by getting the call wrong. `wipe` tolerates the second buffer not existing yet.
302
204
  var privateKeyDer = guard.bytes.snapshot(pop.privateKey, CrmfError, "crmf/bad-input", "pop.privateKey");
303
205
  var encKeyWithIdDer = null;
304
206
  function wipe() { guard.secret.zeroizeAll([privateKeyDer, encKeyWithIdDer], CrmfError, "crmf/bad-input", "the enclosed private key"); }
@@ -308,8 +210,6 @@ function _buildEncryptedKeyPop(pop, outerTag, template) {
308
210
 
309
211
  function _encryptedKeyPopBody() {
310
212
  if (!privateKeyDer.length) throw _err("crmf/bad-input", "pop.privateKey must be the requester's PrivateKeyInfo (PKCS#8) DER");
311
- // PrivateKeyInfo.version MUST be 0 (sec. 4.2.1). These are caller bytes, so the value is read rather
312
- // than assumed; a v1 OneAsymmetricKey carries a public key the CA did not ask to be told.
313
213
  var pkiKids, pkiVersion;
314
214
  try { pkiKids = pkix.rootSequenceChildren(asn1.decode(privateKeyDer), 3); }
315
215
  catch (e) { throw _err("crmf/bad-input", "pop.privateKey must be a PrivateKeyInfo (PKCS#8) SEQUENCE", e); }
@@ -323,37 +223,19 @@ function _buildEncryptedKeyPop(pop, outerTag, template) {
323
223
  if (!intrinsic.isArray(recipients) || recipients.length === 0) {
324
224
  throw _err("crmf/bad-input", "an encryptedKey proof of possession requires pop.recipients (the CA or archive agents to envelope the key to)");
325
225
  }
326
- // The field is typed EnvelopedData, so the content-encryption algorithm has to be one that produces
327
- // one. An AEAD algorithm yields an AuthEnvelopedData (RFC 5083), a different structure this field
328
- // cannot carry and the parser will not read. It is refused by name, not emitted for a peer to
329
- // reject. CBC is the default here for that reason, not as a preference between the two.
330
226
  var cea = pop.contentEncryptionAlgorithm || "aes-256-cbc";
331
227
  if (typeof cea !== "string") throw _err("crmf/bad-input", "pop.contentEncryptionAlgorithm must be an algorithm name");
332
- var _ceaLc = intrinsic.toLowerCase(cea); // /gcm|ccm|chacha/i (ASCII algorithm name)
228
+ var _ceaLc = intrinsic.toLowerCase(cea);
333
229
  if (intrinsic.stringIndexOf(_ceaLc, "gcm") !== -1 || intrinsic.stringIndexOf(_ceaLc, "ccm") !== -1 || intrinsic.stringIndexOf(_ceaLc, "chacha") !== -1) {
334
230
  throw _err("crmf/bad-popo", "encryptedKey is typed EnvelopedData, and the AEAD algorithm " + cea +
335
231
  " produces an AuthEnvelopedData instead (RFC 5083) -- choose a CBC content-encryption algorithm");
336
232
  }
337
- // RFC 4211 sec. 4.2: encryptedKey "contains the encrypted private key MATCHING THE PUBLIC KEY for
338
- // which the certificate is to be issued". Without this the arm proves nothing it claims to: a
339
- // requester could ask for a certificate over one key while enclosing an unrelated private key, and
340
- // the CA would issue on a proof of possession of something it never certified. The signature arm
341
- // self-verifies before returning for the same reason; this is that check for this arm.
342
233
  if (template.spki == null) {
343
234
  throw _err("crmf/bad-input", "an encryptedKey proof of possession requires certTemplate.publicKey -- " +
344
235
  "the proof is that the enclosed private key is the one being certified (RFC 4211 sec. 4.2)");
345
236
  }
346
- // The second plaintext copy: the EncKeyWithID that carries the key into the message. This arm is
347
- // the one place in the toolkit that deliberately holds a caller's private key in the clear, so both
348
- // copies are cleared on every exit. The caller's own buffer stays intact, since it was copied.
349
237
  encKeyWithIdDer = _encKeyWithID(privateKeyDer, pop.identifier);
350
- // Composed, never hand-rolled: the one CMS producer emits the RecipientInfos, and the content type is
351
- // the id-ct-encKeyWithID sec. 4.2 requires -- the same OID the parser independently checks for.
352
238
  return _assertEnclosedKeyMatches(privateKeyDer, template.spki).then(function () {
353
- // The CMS producer raises its own cms/* faults for a malformed recipient or an algorithm it does
354
- // not carry. Those are this module's inputs, reached through a composition the caller cannot see,
355
- // so they are re-raised in this module's namespace with the original kept as the cause -- the
356
- // same translation the CRMF parser performs where it composes the CMS reader.
357
239
  return cmsEncrypt.encrypt(encKeyWithIdDer, recipients, { contentType: "encKeyWithID", contentEncryptionAlgorithm: cea })
358
240
  .then(null, function (e) {
359
241
  if (e instanceof CrmfError) throw e;
@@ -362,9 +244,6 @@ function _buildEncryptedKeyPop(pop, outerTag, template) {
362
244
  });
363
245
  })
364
246
  .then(function (contentInfo) {
365
- // cms.encrypt returns a ContentInfo wrapping the EnvelopedData; the field carries the bare
366
- // structure. Read back through the shipped walker rather than indexing into our own output, so a
367
- // change in what encrypt emits is a typed error here and not a malformed message on the wire.
368
247
  var inner = _bareEnvelopedData(contentInfo);
369
248
  return b.explicit(outerTag, b.implicit(4, inner));
370
249
  })
@@ -372,11 +251,6 @@ function _buildEncryptedKeyPop(pop, outerTag, template) {
372
251
  }
373
252
  }
374
253
 
375
- // Is the private key about to be enclosed the one the template asks to have certified? Derived through
376
- // the toolkit's own key engine, not a second re-implementation, so every algorithm it drives (RSA, EC,
377
- // the Edwards curves, ML-KEM, ML-DSA) answers the same way. Both values are public, so this is an
378
- // ordinary comparison and not a secret one.
379
- // nosemgrep: pki-non-constant-time-secret-compare
380
254
  function _assertEnclosedKeyMatches(privateKeyDer, templateSpki) {
381
255
  return Promise.resolve()
382
256
  .then(function () { return key.publicFromPrivate(privateKeyDer); })
@@ -395,11 +269,6 @@ function _assertEnclosedKeyMatches(privateKeyDer, templateSpki) {
395
269
  });
396
270
  }
397
271
 
398
- // The EnvelopedData SEQUENCE inside the ContentInfo cms.encrypt returns, validated on the way out.
399
- // Every fault here comes from re-reading a composition the caller never sees. The codec's decode and
400
- // the CMS walker each raise in their own namespace, so the whole body is translated, not the one call
401
- // that happens to be likeliest. `pki.crmf.build` promises a typed CrmfError, and a promise with an
402
- // exception for the paths nobody expected to take is the shape that makes it untrue exactly once.
403
272
  function _bareEnvelopedData(contentInfoDer) {
404
273
  try {
405
274
  var kids = pkix.rootSequenceChildren(asn1.decode(contentInfoDer), 2, 2);
@@ -408,7 +277,7 @@ function _bareEnvelopedData(contentInfoDer) {
408
277
  throw _err("crmf/bad-popo", "the enveloped private key is not a ContentInfo carrying one [0] EXPLICIT content");
409
278
  }
410
279
  var env = wrapper.children[0];
411
- cms.walkEnvelopedData(env); // typed cms/* on anything that is not a well-formed EnvelopedData
280
+ cms.walkEnvelopedData(env);
412
281
  return b.raw(env.bytes);
413
282
  } catch (e) {
414
283
  if (e instanceof CrmfError) throw e;
@@ -417,11 +286,6 @@ function _bareEnvelopedData(contentInfoDer) {
417
286
  }
418
287
  }
419
288
 
420
- // Check spec.pop against the arm the caller selected, never against every arm's fields at once. Every
421
- // opt-in below is a refusal a caller turns off by naming it, so a field that belongs to a different
422
- // arm must not read as one this arm accepted and ignored: the caller believes they asked for
423
- // something the message does not say. An unrecognized arm falls through with only the selector
424
- // fields allowed, so the error names the arm rather than a field beside it.
425
289
  function _assertPopArmKeys(pop, mode) {
426
290
  var arm = _hasOwn(POPO_PRIVKEY_TAGS, mode) ? pop.method : mode;
427
291
  var allowed = (typeof arm === "string" && _hasOwn(POP_KEYS_BY_ARM, arm))
@@ -433,25 +297,14 @@ function _assertPopArmKeys(pop, mode) {
433
297
  });
434
298
  }
435
299
 
436
- // ProofOfPossession. The signature arm (the default when a key is given): when the template carries both
437
- // subject and publicKey (complete), sign the CertRequest DER and omit poposkInput; otherwise build a
438
- // POPOSigningKeyInput (authInfo sender [0] GeneralName + the requested publicKey), sign its SEQUENCE, and
439
- // carry it as poposkInput [0] (RFC 4211 sec. 4.1). raVerified is emitted only on an explicit opt-in.
440
300
  function _buildProofOfPossession(pop, certReqDer, template, signingKey, opts) {
441
301
  if (pop != null && (typeof pop !== "object" || Buffer.isBuffer(pop))) throw _err("crmf/bad-input", "spec.pop must be an object (e.g. { type: 'signature' } or { type: 'raVerified', raVerified: true })");
442
- // Every opt-in below is a refusal a caller turns off by naming it, so a misspelled key must not
443
- // read as an omitted one: `archve: true` silently withholding the archival consent, or `identifer`
444
- // silently omitting the field RFC 4211 sec. 4.2.1 makes mandatory, would each be a message built
445
- // on the opposite of what the caller asked for.
446
- // The arm is resolved BEFORE its fields are checked, because `type` is not the only thing that
447
- // picks one: a spec that supplies a key and omits `type` selects the signature arm, and checking
448
- // against an unresolved arm would refuse the `pop.sender` that arm reads.
449
302
  var mode = (pop && pop.type) || (signingKey != null ? "signature" : null);
450
303
  if (pop != null) _assertPopArmKeys(pop, mode);
451
- if (mode == null) return null; // no POP requested and no key -> omit popo (an RA supplies it out of band)
304
+ if (mode == null) return null;
452
305
  if (mode === "raVerified") {
453
306
  if (!(pop && pop.raVerified === true)) throw _err("crmf/bad-popo", "raVerified must be explicitly opted into (pop: { type: 'raVerified', raVerified: true }) -- a requester does not normally assert it (RFC 4211 sec. 4)");
454
- return b.implicit(0, b.nullValue()); // raVerified [0] IMPLICIT NULL
307
+ return b.implicit(0, b.nullValue());
455
308
  }
456
309
  if (_hasOwn(POPO_PRIVKEY_TAGS, mode)) return _buildPopoPrivKey(pop, mode, template);
457
310
  if (mode !== "signature") {
@@ -463,14 +316,13 @@ function _buildProofOfPossession(pop, certReqDer, template, signingKey, opts) {
463
316
  var scheme = signScheme.resolveSignScheme(_b.certLikeFromSpki(template.spki), { combinedRsaSig: true, pss: opts.pss, digestAlgorithm: opts.digestAlgorithm }, true, _signE);
464
317
  var signedRegion, poposkInputField = null;
465
318
  if (template.complete) {
466
- signedRegion = certReqDer; // sec. 4.1: complete template -> sign the CertRequest, poposkInput omitted
319
+ signedRegion = certReqDer;
467
320
  } else {
468
- // POPOSigningKeyInput ::= SEQUENCE { authInfo CHOICE { sender [0] GeneralName, publicKeyMAC }, publicKey }.
469
321
  var sender = pop && pop.sender;
470
322
  if (sender == null) throw _err("crmf/bad-popo", "an incomplete template (missing subject or publicKey) requires pop.sender (a GeneralName) for the POPOSigningKeyInput authInfo (RFC 4211 sec. 4.1)");
471
323
  var poposkSeq = b.sequence([b.explicit(0, _b.encodeGeneralName(sender)), b.raw(template.spki)]);
472
324
  signedRegion = poposkSeq;
473
- poposkInputField = b.implicit(0, poposkSeq); // poposkInput [0] IMPLICIT POPOSigningKeyInput
325
+ poposkInputField = b.implicit(0, poposkSeq);
474
326
  }
475
327
  return signScheme.signOverTbs(scheme, signingKey, signedRegion, _signE).then(function (sig) {
476
328
  return Promise.resolve(_b.assertSignatureVerifies(signedRegion, sig, template.spki, scheme)).then(function () {
@@ -478,7 +330,7 @@ function _buildProofOfPossession(pop, certReqDer, template, signingKey, opts) {
478
330
  if (poposkInputField) popoChildren.push(poposkInputField);
479
331
  popoChildren.push(scheme.sigAlgId);
480
332
  popoChildren.push(b.bitString(sig, 0));
481
- return b.implicit(1, b.sequence(popoChildren)); // signature [1] IMPLICIT POPOSigningKey
333
+ return b.implicit(1, b.sequence(popoChildren));
482
334
  });
483
335
  }, function (e) {
484
336
  if (e instanceof CrmfError) throw e;
@@ -546,8 +398,6 @@ function _buildProofOfPossession(pop, certReqDer, template, signingKey, opts) {
546
398
  * pki.schema.crmf.parse(msg).messages[0].certReq.certTemplate.subject.dn; // "CN=device-42"
547
399
  */
548
400
  function build(spec, key, opts) {
549
- // Every caller-owned argument copied at entry and released when the call settles -- see the note
550
- // on the same call in x509-sign.
551
401
  return guard.bytes.fixedCall(CrmfError, "crmf/bad-input", [
552
402
  [spec, "the certificate-request-message spec"], [key, "the signing key"], [opts, "pki.crmf.build options"],
553
403
  ], _build);
@@ -568,7 +418,7 @@ function _buildCertReqMsg(spec, key, opts) {
568
418
  var msgChildren = [certReqDer];
569
419
  if (popoDer) msgChildren.push(popoDer);
570
420
  if (spec.regInfo != null) msgChildren.push(_buildAttrTypeAndValues(spec.regInfo, "crmf/bad-reg-info", "regInfo", REGINFO_VALUE));
571
- return b.sequence(msgChildren); // CertReqMsg
421
+ return b.sequence(msgChildren);
572
422
  });
573
423
  }
574
424
 
@@ -577,8 +427,6 @@ function _build(spec, key, opts) {
577
427
  if (!spec || typeof spec !== "object" || Buffer.isBuffer(spec)) throw _err("crmf/bad-input", "the certificate-request-message spec must be an object");
578
428
  var specs;
579
429
  if (spec.messages != null) {
580
- // Batch form: the envelope carries ONLY `messages` -- reject a stray field so a request spec written at
581
- // the wrong nesting level (e.g. certTemplate alongside messages) is not silently dropped.
582
430
  if (!Array.isArray(spec.messages)) throw _err("crmf/bad-input", "spec.messages must be an array of certificate-request-message specs");
583
431
  guard.identifier.assertKnownKeys(spec, KNOWN_BATCH_KEYS, _err, "crmf/bad-input", function (k) {
584
432
  return "unknown batch-envelope field " + JSON.stringify(k) + " -- a batch spec carries only 'messages'";
@@ -589,7 +437,7 @@ function _build(spec, key, opts) {
589
437
  }
590
438
  if (!specs.length) throw _err("crmf/bad-input", "at least one certificate request message is required (RFC 4211 sec. 3)");
591
439
  return Promise.all(specs.map(function (s) { return _buildCertReqMsg(s, key, opts); })).then(function (msgs) {
592
- var der = b.sequence(msgs); // CertReqMessages ::= SEQUENCE SIZE(1..MAX) OF CertReqMsg
440
+ var der = b.sequence(msgs);
593
441
  if (opts.pem != null) {
594
442
  if (typeof opts.pem !== "string" || !opts.pem) throw _err("crmf/bad-input", "opts.pem must be a non-empty PEM label string");
595
443
  return crmf.pemEncode(der, opts.pem);
@@ -622,8 +470,6 @@ function _coerceMessages(input) {
622
470
  return guard.parsed.acceptDerived(input, "crmf", crmf.parse, _err, "crmf/bad-input", "the certificate request messages");
623
471
  }
624
472
 
625
- // One CertReqMsg's proof of possession, reduced to a verdict. Every return names a method and
626
- // reports the requested identity, so a refusal is as informative as an acceptance.
627
473
  function _verifyOne(msg) {
628
474
  var t = msg.certReq && msg.certReq.certTemplate;
629
475
  var base = {
@@ -632,7 +478,7 @@ function _verifyOne(msg) {
632
478
  subjectBound: false,
633
479
  publicKey: (t && t.publicKey && t.publicKey.bytes) || null,
634
480
  };
635
- function settle(extra) { var v = Object.assign({}, base, extra); v.valid = v.verified === true; return Promise.resolve(v); } // `valid` is the canonical toolkit-wide alias of this message's `verified`
481
+ function settle(extra) { var v = Object.assign({}, base, extra); v.valid = v.verified === true; return Promise.resolve(v); }
636
482
 
637
483
  var popo = msg.popo;
638
484
  if (popo == null) {
@@ -640,42 +486,17 @@ function _verifyOne(msg) {
640
486
  reason: "the request carries no proof of possession" });
641
487
  }
642
488
  if (popo.type === "raVerified") {
643
- // sec. 4: an assertion by the RA that it checked possession out of band. It is not a proof and
644
- // must not read as one; a caller that trusts its RA opts in by reading `method`.
645
489
  return settle({ verified: false, method: "raVerified", cryptographicallyVerified: false,
646
490
  reason: "raVerified asserts the RA checked possession out of band -- this is not a proof and cannot be verified from the message" });
647
491
  }
648
492
  if (popo.type !== "signature") {
649
- // keyEncipherment / keyAgreement complete over a later protocol exchange (a challenge the
650
- // verifier does not hold) or need the CA's decryption key, so no verdict is available here.
651
493
  return settle({ verified: false, method: popo.type, cryptographicallyVerified: false,
652
494
  reason: "a " + popo.type + " proof of possession completes over an exchange this verifier does not hold (RFC 4211 sec. 4.2, 4.3)" });
653
495
  }
654
496
 
655
- // Which bytes the signature covers is fixed by whether poposkInput is present: the DER of
656
- // poposkInput when it is, the DER of certReq when it is not (RFC 4211 sec. 4.1, and the ASN.1
657
- // module on p.33 -- sec. 4.1's case-3 prose says "certificate template" where the field
658
- // definition and the module both say certReq).
659
- //
660
- // The three conformance rules that decide which of those is legitimate are enforced ONE layer
661
- // down, at parse: poposkInput MUST be omitted exactly when the template carries both subject and
662
- // publicKey, and poposkInput.publicKey MUST equal the template's (schema-crmf.js, the CertReqMsg
663
- // build). A message breaking either never reaches this function, and re-checking here would add
664
- // a branch no input can take while implying the parser might let one through.
665
497
  var pin = popo.poposkInput;
666
498
  var preimage = pin ? pin.signedBytes : msg.certReq.certReqBytes;
667
- // The key possession is proven for is the one inside the preimage. With poposkInput that is its
668
- // own publicKey; sec. 4.1 requires the template to carry the same value, and the parser enforces
669
- // that whenever the template has one at all. A template that omits it entirely still parses (the
670
- // equality rule has nothing to compare), so reading the template here would report null for a key
671
- // whose possession was just proven.
672
499
  var spki = pin ? pin.publicKey : base.publicKey;
673
- // Which fields the verdict may report follows from which bytes were signed. The certReq preimage
674
- // is the whole CertRequest, so the template's subject rides with it. The poposkInput preimage
675
- // covers the key and the authInfo sender and never the template, so a subject sitting in the
676
- // message alongside it is unsigned: reporting it beside `verified: true` would let a CA issue a
677
- // name the requester proved nothing about. It is withheld, and `subjectBound` says so rather than
678
- // leaving the absence to look like a request that named no subject.
679
500
  var bound = !pin;
680
501
  return crmfVerify.verifyPopSignature(popo, spki, preimage).then(function (ok) {
681
502
  return Object.assign({}, base, {
@@ -1,24 +1,13 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  // Copyright (c) blamejs contributors
3
3
  "use strict";
4
- //
5
- // @internal -- the single RFC 4211 proof-of-possession signature seam for an INBOUND CertReqMsg,
6
- // shared by pki.crmf.verifyPop and by every enrollment path that accepts one. The slot, the wiring
7
- // assertion and the octet-alignment refusal are the shared seam (lib/verify-seam.js); what is
8
- // domain-specific is the error class and which bytes the signature covers. It is not wired into
9
- // index.js and is reached only by require.
4
+ // @internal
10
5
 
11
6
  var frameworkError = require("./framework-error");
12
7
  var seam = require("./verify-seam");
13
8
 
14
9
  var _seam = seam.makeSeam("crmf-verify", frameworkError.CrmfError, "crmf/bad-input");
15
10
 
16
- // Verify one CertReqMsg's POPOSigningKey signature over `preimage` under `spkiBytes`.
17
- //
18
- // `preimage` is chosen by the caller from the two the RFC defines, because the choice is a
19
- // conformance rule about the message rather than a property of the signature: the DER of
20
- // poposkInput when that field is present, and the DER of `CertReqMsg certReq` when it is absent
21
- // (RFC 4211 sec. 4.1 and the ASN.1 module on p.33).
22
11
  function verifyPopSignature(popo, spkiBytes, preimage) {
23
12
  return _seam.verify(popo.algorithmIdentifier, popo.signature, spkiBytes, preimage);
24
13
  }