@blamejs/pki 0.6.13 → 0.6.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/CHANGELOG.md +22 -1
  2. package/README.md +1 -1
  3. package/index.js +1 -1
  4. package/lib/acme.js +59 -815
  5. package/lib/asn1-der.js +7 -245
  6. package/lib/attrcert-sign.js +12 -260
  7. package/lib/attrcert-verify.js +1 -7
  8. package/lib/byte-reader.js +0 -8
  9. package/lib/byte-writer.js +0 -11
  10. package/lib/cbor-det.js +0 -54
  11. package/lib/cmc-build.js +15 -357
  12. package/lib/cmc-verify.js +6 -239
  13. package/lib/cmp-build.js +41 -317
  14. package/lib/cmp-session.js +73 -760
  15. package/lib/cmp-verify.js +32 -488
  16. package/lib/cms-compress.js +3 -32
  17. package/lib/cms-decrypt.js +29 -294
  18. package/lib/cms-encrypt.js +14 -234
  19. package/lib/cms-sign.js +29 -324
  20. package/lib/cms-verify.js +9 -500
  21. package/lib/composite-kem.js +2 -102
  22. package/lib/composite-sig.js +1 -77
  23. package/lib/constants.js +0 -249
  24. package/lib/crl-sign.js +9 -237
  25. package/lib/crl-verify.js +1 -10
  26. package/lib/crmf-sign.js +19 -198
  27. package/lib/crmf-verify.js +1 -12
  28. package/lib/csr-sign.js +3 -34
  29. package/lib/csr-verify.js +1 -12
  30. package/lib/ct.js +28 -253
  31. package/lib/edwards-point.js +10 -44
  32. package/lib/est.js +28 -764
  33. package/lib/framework-error.js +4 -182
  34. package/lib/guard-all.js +1 -58
  35. package/lib/guard-async.js +1 -36
  36. package/lib/guard-bytes.js +6 -650
  37. package/lib/guard-compress.js +5 -102
  38. package/lib/guard-crypto.js +1 -40
  39. package/lib/guard-der.js +2 -93
  40. package/lib/guard-encoding.js +2 -60
  41. package/lib/guard-header.js +1 -36
  42. package/lib/guard-identifier.js +7 -531
  43. package/lib/guard-intrinsic.js +1 -150
  44. package/lib/guard-json.js +10 -73
  45. package/lib/guard-limits.js +1 -77
  46. package/lib/guard-list.js +1 -49
  47. package/lib/guard-name.js +3 -209
  48. package/lib/guard-parsed.js +7 -335
  49. package/lib/guard-range.js +1 -71
  50. package/lib/guard-secret.js +1 -102
  51. package/lib/guard-text.js +1 -64
  52. package/lib/guard-time.js +1 -97
  53. package/lib/hpke.js +3 -105
  54. package/lib/http-digest.js +14 -142
  55. package/lib/http-retry-after.js +1 -47
  56. package/lib/http-transport.js +21 -131
  57. package/lib/inspect.js +30 -284
  58. package/lib/ip-utils.js +6 -47
  59. package/lib/jose.js +7 -142
  60. package/lib/key.js +2 -67
  61. package/lib/lint.js +9 -194
  62. package/lib/merkle.js +1 -27
  63. package/lib/mime.js +9 -82
  64. package/lib/ocsp-request-verify.js +1 -14
  65. package/lib/ocsp-verify.js +1 -82
  66. package/lib/ocsp.js +11 -169
  67. package/lib/oid.js +5 -337
  68. package/lib/path-validate.js +103 -1492
  69. package/lib/pbes2.js +2 -89
  70. package/lib/pkcs12-build.js +31 -379
  71. package/lib/pki-build.js +64 -290
  72. package/lib/rc2.js +2 -18
  73. package/lib/rfc3339.js +4 -27
  74. package/lib/scep.js +59 -233
  75. package/lib/schema-all.js +0 -122
  76. package/lib/schema-attrcert.js +4 -146
  77. package/lib/schema-c509.js +153 -802
  78. package/lib/schema-cmc.js +5 -220
  79. package/lib/schema-cmp.js +2 -223
  80. package/lib/schema-cms.js +13 -427
  81. package/lib/schema-crl.js +5 -68
  82. package/lib/schema-crmf.js +6 -167
  83. package/lib/schema-csr.js +1 -54
  84. package/lib/schema-csrattrs.js +2 -87
  85. package/lib/schema-engine.js +0 -152
  86. package/lib/schema-ocsp.js +0 -117
  87. package/lib/schema-pkcs12.js +2 -93
  88. package/lib/schema-pkcs8.js +3 -35
  89. package/lib/schema-pkix.js +24 -655
  90. package/lib/schema-smime.js +0 -54
  91. package/lib/schema-tsp.js +3 -99
  92. package/lib/schema-x509.js +4 -63
  93. package/lib/shbs.js +11 -95
  94. package/lib/sign-scheme.js +2 -97
  95. package/lib/sigstore.js +9 -169
  96. package/lib/sleep.js +2 -8
  97. package/lib/smime.js +15 -408
  98. package/lib/tls-cert-compress.js +0 -62
  99. package/lib/trust.js +19 -185
  100. package/lib/tsp-sign.js +16 -270
  101. package/lib/validator-all.js +1 -30
  102. package/lib/validator-attcert.js +2 -46
  103. package/lib/validator-cose.js +2 -153
  104. package/lib/validator-keydesc.js +1 -37
  105. package/lib/validator-sig.js +1 -46
  106. package/lib/validator-tls.js +1 -88
  107. package/lib/validator-tpm.js +19 -122
  108. package/lib/verify-seam.js +1 -24
  109. package/lib/webauthn-mds.js +3 -400
  110. package/lib/webauthn.js +12 -833
  111. package/lib/webcrypto.js +5 -485
  112. package/lib/x509-sign.js +4 -108
  113. package/package.json +1 -1
  114. package/sbom.cdx.json +6 -6
package/lib/schema-cmp.js CHANGED
@@ -54,20 +54,15 @@ var OID_CONFIRM_WAIT_TIME = oid.byName("confirmWaitTime");
54
54
  var OID_CERT_PROFILE = oid.byName("certProfile");
55
55
  var OID_PKI_ARCHIVE_OPTIONS = oid.byName("pkiArchiveOptions");
56
56
 
57
- // ---- leaves -----------------------------------------------------------
58
57
 
59
- // CMP times are GeneralizedTime only; PKIFreeText elements are UTF8String
60
- // (RFC 9810 sec. 5.1.1). Both ride the shared pkix leaf factories.
61
58
  var GENERALIZED_TIME = pkix.generalizedTime(NS, { code: "cmp/bad-time", message: "CMP times must be GeneralizedTime (RFC 9810 sec. 5.1.1)" });
62
59
  var UTF8_TEXT = pkix.utf8Text(NS, { code: "cmp/bad-freetext", message: "PKIFreeText elements must be UTF8String (RFC 9810 sec. 5.1.1)" });
63
60
 
64
- // PKIFreeText ::= SEQUENCE SIZE (1..MAX) OF UTF8String.
65
61
  var PKI_FREE_TEXT = schema.seqOf(UTF8_TEXT, {
66
62
  min: 1, code: "cmp/bad-freetext", what: "PKIFreeText",
67
63
  build: function (m) { return m.items.map(function (it) { return it.value; }); },
68
64
  });
69
65
 
70
- // PKIStatus ::= INTEGER {0..6} (sec. 5.2.3): a value whitelist, surfaced named.
71
66
  var PKI_STATUS_NAMES = ["accepted", "grantedWithMods", "rejection", "waiting",
72
67
  "revocationWarning", "revocationNotification", "keyUpdateWarning"];
73
68
  var PKI_STATUS = schema.decode(function (n, ctx) {
@@ -77,9 +72,6 @@ var PKI_STATUS = schema.decode(function (n, ctx) {
77
72
  return { code: code, name: PKI_STATUS_NAMES[code] };
78
73
  });
79
74
 
80
- // PKIFailureInfo ::= BIT STRING named bits 0..26 (sec. 5.2.3). X.690 sec. 11.2.2:
81
- // a named-bit BIT STRING drops trailing zero bits, so the final carried bit
82
- // must be 1. Bits past 26 are extensible and surface as numeric indexes.
83
75
  var FAIL_INFO_NAMES = ["badAlg", "badMessageCheck", "badRequest", "badTime", "badCertId",
84
76
  "badDataFormat", "wrongAuthority", "incorrectData", "missingTimeStamp", "badPOP",
85
77
  "certRevoked", "certConfirmed", "wrongIntegrity", "badRecipientNonce", "timeNotAvailable",
@@ -97,18 +89,10 @@ var PKI_FAILURE_INFO = schema.decode(function (n, ctx) {
97
89
  return { bits: bits, raw: bs };
98
90
  });
99
91
 
100
- // PollRep checkAfter is a delay in seconds; a negative one poisons scheduling, and
101
- // the value surfaces as an exact number or not at all.
102
92
  var CHECK_AFTER = schema.decode(function (n, ctx) {
103
93
  return guard.range.uint31(asn1.read.integer(n), ctx.E, "cmp/bad-poll-rep", "checkAfter delay in seconds (RFC 9810 sec. 5.3.22)");
104
94
  });
105
95
 
106
- // A raw certificate / CRL / publication-info element, surfaced byte-exact for
107
- // downstream parsing, but structurally a universal SEQUENCE: a CMPCertificate
108
- // is a Certificate, and CertificateList / PKIPublicationInfo are SEQUENCEs, so
109
- // a primitive (an INTEGER) or wrong-tag element is not a valid structure and
110
- // rejects, never handing arbitrary bytes to certificate processing. The
111
- // `code` names the containing structure (a shared leaf cannot know its context).
112
96
  function rawSequence(code) {
113
97
  return pkix.rawNonEmptySequence(NS, { code: code, message: "expected a non-empty universal SEQUENCE (Certificate / CertificateList / PKIPublicationInfo)" });
114
98
  }
@@ -117,12 +101,7 @@ var GENERAL_NAME = pkix.generalName(NS, { decodeValue: true });
117
101
  var ALG_ID = pkix.algorithmIdentifier(NS);
118
102
  var EXTENSIONS = pkix.extensions(NS);
119
103
 
120
- // ---- header ------------------------------------------------------------
121
104
 
122
- // InfoTypeAndValue ::= SEQUENCE { infoType OID, infoValue ANY OPTIONAL }
123
- // (sec. 5.1.1, sec. 5.3.19). Recognized id-it types with a fixed value syntax are
124
- // validated (the CMS signed-attr value-syntax posture); all others surface
125
- // raw with the registry name resolving.
126
105
  var INFO_TYPE_AND_VALUE = schema.seq([
127
106
  schema.field("infoType", schema.oidLeaf()),
128
107
  schema.optional("infoValue", schema.any(), { whenAny: true }),
@@ -131,19 +110,10 @@ var INFO_TYPE_AND_VALUE = schema.seq([
131
110
  build: function (m, ctx) {
132
111
  var t = m.fields.infoType.value;
133
112
  var valueNode = m.fields.infoValue.present ? m.fields.infoValue.value : null;
134
- // A recognized id-it type with a FIXED value syntax (RFC 9810 sec. 5.1.1) MUST
135
- // carry its infoValue -- implicitConfirm a NULL, confirmWaitTime a
136
- // GeneralizedTime, certProfile a SEQUENCE OF UTF8String. A missing value is
137
- // accepted only for the open / query id-it types (a bare OID in a genm body),
138
- // never for a type whose value syntax the RFC defines.
139
113
  if ((t === OID_IMPLICIT_CONFIRM || t === OID_CONFIRM_WAIT_TIME || t === OID_CERT_PROFILE) && valueNode === null) {
140
114
  throw ctx.E("cmp/bad-info-value", "a recognized fixed-syntax id-it (implicitConfirm / confirmWaitTime / certProfile) must carry its infoValue (RFC 9810 sec. 5.1.1)");
141
115
  }
142
116
  if (valueNode !== null) {
143
- // A recognized id-it value is validated by content, not just tag: run the
144
- // strict typed reader so a well-tagged but malformed payload (a non-empty
145
- // NULL, a GeneralizedTime carrying garbage, an invalid-UTF-8 string)
146
- // rejects and is never surfaced as valid CMP.
147
117
  if (t === OID_IMPLICIT_CONFIRM) {
148
118
  if (!(valueNode.tagClass === "universal" && valueNode.tagNumber === TAGS.NULL)) {
149
119
  throw ctx.E("cmp/bad-info-value", "an implicitConfirm value must be NULL (RFC 9810 sec. 5.1.1.1)");
@@ -182,8 +152,6 @@ var GENERAL_INFO = schema.seqOf(INFO_TYPE_AND_VALUE, {
182
152
  build: function (m) { return m.items.map(function (it) { return it.value.result; }); },
183
153
  });
184
154
 
185
- // PKIHeader ::= SEQUENCE { pvno, sender, recipient, then EXPLICIT [0]..[8]
186
- // optionals, ascending, at-most-once } (sec. 5.1.1).
187
155
  var PKI_HEADER = schema.seq([
188
156
  schema.field("pvno", pkix.versionReader(NS, { "1": 1, "2": 2, "3": 3 })),
189
157
  schema.field("sender", GENERAL_NAME),
@@ -220,9 +188,7 @@ var PKI_HEADER = schema.seq([
220
188
  },
221
189
  });
222
190
 
223
- // ---- decoded body arms ---------------------------------------------------
224
191
 
225
- // PKIStatusInfo ::= SEQUENCE { status, statusString OPTIONAL, failInfo OPTIONAL } (sec. 5.2.3).
226
192
  var PKI_STATUS_INFO = schema.seq([
227
193
  schema.field("status", PKI_STATUS),
228
194
  schema.optional("statusString", PKI_FREE_TEXT, { whenUniversal: [TAGS.SEQUENCE] }),
@@ -238,8 +204,6 @@ var PKI_STATUS_INFO = schema.seq([
238
204
  },
239
205
  });
240
206
 
241
- // ErrorMsgContent ::= SEQUENCE { pKIStatusInfo, errorCode INTEGER OPTIONAL,
242
- // errorDetails PKIFreeText OPTIONAL } (sec. 5.3.21).
243
207
  var ERROR_MSG_CONTENT = schema.seq([
244
208
  schema.field("pKIStatusInfo", PKI_STATUS_INFO),
245
209
  schema.optional("errorCode", schema.integerLeaf(), { whenUniversal: [TAGS.INTEGER] }),
@@ -255,8 +219,6 @@ var ERROR_MSG_CONTENT = schema.seq([
255
219
  },
256
220
  });
257
221
 
258
- // CertStatus ::= SEQUENCE { certHash, certReqId, statusInfo OPTIONAL,
259
- // hashAlg [0] OPTIONAL } (sec. 5.3.18). certReqId accepts the -1 sentinel.
260
222
  var CERT_STATUS = schema.seq([
261
223
  schema.field("certHash", schema.octetString()),
262
224
  schema.field("certReqId", schema.integerLeaf()),
@@ -276,23 +238,16 @@ var CERT_STATUS = schema.seq([
276
238
  },
277
239
  });
278
240
 
279
- // CertConfirmContent ::= SEQUENCE OF CertStatus, where an empty sequence is legal
280
- // (reject-all, sec. 5.3.18), so no SIZE floor.
281
241
  var CERT_CONFIRM_CONTENT = schema.seqOf(CERT_STATUS, {
282
242
  code: "cmp/bad-cert-status", what: "CertConfirmContent",
283
243
  build: function (m) { return m.items.map(function (it) { return it.value.result; }); },
284
244
  });
285
245
 
286
- // GenMsgContent / GenRepContent ::= SEQUENCE OF InfoTypeAndValue, with no SIZE
287
- // bound, empty legal (sec. 5.3.19/.20).
288
246
  var GEN_MSG_CONTENT = schema.seqOf(INFO_TYPE_AND_VALUE, {
289
247
  code: "cmp/bad-info-type-and-value", what: "GenMsgContent",
290
248
  build: function (m) { return m.items.map(function (it) { return it.value.result; }); },
291
249
  });
292
250
 
293
- // RevDetails ::= SEQUENCE { certDetails CertTemplate, crlEntryDetails
294
- // Extensions OPTIONAL } (sec. 5.3.9). The CertTemplate interior (an IMPLICIT
295
- // TAGS module) is owned by the CRMF parser and walked NS-bound there.
296
251
  var CERT_TEMPLATE_LEAF = schema.decode(function (n) { return crmf.walkCertTemplate(n); });
297
252
  var REV_DETAILS = schema.seq([
298
253
  schema.field("certDetails", CERT_TEMPLATE_LEAF),
@@ -311,7 +266,6 @@ var REV_REQ_CONTENT = schema.seqOf(REV_DETAILS, {
311
266
  build: function (m) { return m.items.map(function (it) { return it.value.result; }); },
312
267
  });
313
268
 
314
- // CertId ::= SEQUENCE { issuer GeneralName, serialNumber INTEGER } (RFC 4211).
315
269
  var CERT_ID = schema.seq([
316
270
  schema.field("issuer", GENERAL_NAME),
317
271
  schema.field("serialNumber", schema.integerLeaf()),
@@ -322,8 +276,6 @@ var CERT_ID = schema.seq([
322
276
  },
323
277
  });
324
278
 
325
- // RevRepContent ::= SEQUENCE { status SIZE(1..MAX), revCerts [0] OPTIONAL,
326
- // crls [1] OPTIONAL } (sec. 5.3.10).
327
279
  var REV_REP_CONTENT = schema.seq([
328
280
  schema.field("status", schema.seqOf(PKI_STATUS_INFO, {
329
281
  min: 1, code: "cmp/bad-rev-rep", what: "RevRep status",
@@ -350,24 +302,9 @@ var REV_REP_CONTENT = schema.seq([
350
302
  },
351
303
  });
352
304
 
353
- // EncryptedKey ::= CHOICE { encryptedValue EncryptedValue (deprecated),
354
- // envelopedData [0] EnvelopedData } (sec. 5.2.2). EncryptedKey is imported from
355
- // the RFC 4211 CRMF module, which is IMPLICIT TAGS, so `envelopedData [0]` is
356
- // an IMPLICIT context tag replacing the EnvelopedData SEQUENCE tag: the [0]
357
- // node's children are the EnvelopedData fields, with no inner wrapper. Retag it to
358
- // the universal SEQUENCE the CMS walker expects, exactly as the sibling CRMF
359
- // `encryptedKey [4] EnvelopedData` POP arm does (schema-crmf.js). The
360
- // deprecated encryptedValue arm surfaces raw and is never field-walked, so nothing
361
- // dereferences its optional interior (absent algorithm parameters crash
362
- // consumers that walk it blindly).
363
305
  var ENCRYPTED_KEY = schema.choice([
364
306
  { when: { tagClass: "universal", tagNumber: TAGS.SEQUENCE },
365
307
  schema: schema.decode(function (n, ctx) {
366
- // An RFC 4211 sec. 2 EncryptedValue REQUIRES encValue (its final BIT STRING
367
- // field), so an empty SEQUENCE has the right tag but is not any valid
368
- // EncryptedValue. Require at least one child, so no degenerate structure
369
- // surfaces as encrypted certificate/key bytes (the same
370
- // non-empty rule every raw-SEQUENCE surface in this module applies).
371
308
  if (!(n.children && n.children.length >= 1)) {
372
309
  throw ctx.E("cmp/bad-cert-response", "an EncryptedValue must be a non-empty SEQUENCE (RFC 4211 sec. 2)");
373
310
  }
@@ -376,25 +313,13 @@ var ENCRYPTED_KEY = schema.choice([
376
313
  { when: { tagClass: "context", tagNumber: 0 },
377
314
  schema: schema.decode(function (n, ctx) {
378
315
  var env;
379
- // Wrap every EnvelopedData failure -- a non-decodable retarget OR a CmsError
380
- // from the composed walker -- as the CMP domain error (with the original as
381
- // the cause), so cmp.parse never escapes with a cms/* error for a malformed
382
- // PKIMessage (the same wrapping the sibling CRMF encryptedKey POP arm does).
383
316
  try { env = cms.walkEnvelopedData(asn1.decode(asn1.sequenceTlv(n))); }
384
317
  catch (e) {
385
318
  throw ctx.E("cmp/bad-cert-response", "envelopedData [0] must be a well-formed IMPLICIT EnvelopedData (RFC 9810 sec. 5.2.2)", e);
386
319
  }
387
- // RFC 9810 sec. 5.2.2 -- a CMP EncryptedKey EnvelopedData is addressed to
388
- // exactly one recipient (the end entity for a delivered cert / key). CMS
389
- // permits RecipientInfos SET SIZE 1..MAX, so the single-recipient bound is
390
- // CMP's: more than one recipient is a malformed EncryptedKey.
391
320
  if (env.recipientInfos.length !== 1) {
392
321
  throw ctx.E("cmp/bad-cert-response", "an EncryptedKey EnvelopedData must contain exactly one RecipientInfo (RFC 9810 sec. 5.2.2)");
393
322
  }
394
- // The ciphertext is the encrypted certificate / private key here, so an
395
- // EnvelopedData with no ciphertext to decrypt, whether absent (detached, CMS
396
- // permits it) or present-but-empty, must reject (RFC 9810 sec. 5.2.2/sec. 5.3.4;
397
- // the same rule the CRMF encryptedKey POP arm enforces).
398
323
  var ct = env.encryptedContentInfo.encryptedContent;
399
324
  if (ct === null || ct.length === 0) {
400
325
  throw ctx.E("cmp/bad-cert-response", "an EncryptedKey envelopedData must carry non-empty attached ciphertext -- its encryptedContent is the certificate/key payload (RFC 9810 sec. 5.2.2)");
@@ -403,7 +328,6 @@ var ENCRYPTED_KEY = schema.choice([
403
328
  }) },
404
329
  ], { code: "cmp/bad-cert-response", what: "EncryptedKey" });
405
330
 
406
- // CertOrEncCert ::= CHOICE { certificate [0], encryptedCert [1] } (sec. 5.3.4).
407
331
  var CERT_OR_ENC_CERT = schema.choice([
408
332
  { when: { tagClass: "context", tagNumber: 0 },
409
333
  schema: schema.explicit(0, schema.decode(function (n, ctx) {
@@ -416,8 +340,6 @@ var CERT_OR_ENC_CERT = schema.choice([
416
340
  schema: schema.explicit(1, ENCRYPTED_KEY, { code: "cmp/bad-cert-response" }) },
417
341
  ], { code: "cmp/bad-cert-response", what: "CertOrEncCert" });
418
342
 
419
- // CertifiedKeyPair ::= SEQUENCE { certOrEncCert, privateKey [0] OPTIONAL,
420
- // publicationInfo [1] OPTIONAL } (sec. 5.3.4).
421
343
  var CERTIFIED_KEY_PAIR = schema.seq([
422
344
  schema.field("certOrEncCert", CERT_OR_ENC_CERT),
423
345
  schema.trailing([
@@ -436,8 +358,6 @@ var CERTIFIED_KEY_PAIR = schema.seq([
436
358
  },
437
359
  });
438
360
 
439
- // CertResponse ::= SEQUENCE { certReqId INTEGER (the -1 sentinel is legal),
440
- // status PKIStatusInfo, certifiedKeyPair OPTIONAL, rspInfo OPTIONAL } (sec. 5.3.4).
441
361
  var CERT_RESPONSE = schema.seq([
442
362
  schema.field("certReqId", schema.integerLeaf()),
443
363
  schema.field("status", PKI_STATUS_INFO),
@@ -448,21 +368,10 @@ var CERT_RESPONSE = schema.seq([
448
368
  build: function (m, ctx) {
449
369
  var status = m.fields.status.value.result;
450
370
  var certifiedKeyPair = m.fields.certifiedKeyPair.present ? m.fields.certifiedKeyPair.value.result : null;
451
- // RFC 9810 sec. 5.3.4 -- only one of the failInfo (in PKIStatusInfo) and
452
- // certifiedKeyPair fields can be present in a CertResponse: a rejection
453
- // carries no certificate. Accepting both lets a caller keying off
454
- // certifiedKeyPair process a certificate from a failed response.
455
371
  if (status.failInfo !== null && certifiedKeyPair !== null) {
456
372
  throw ctx.E("cmp/bad-cert-response",
457
373
  "a CertResponse must not carry both failInfo and certifiedKeyPair (RFC 9810 sec. 5.3.4)");
458
374
  }
459
- // A certifiedKeyPair is present only when the status grants the certificate:
460
- // accepted (0) or grantedWithMods (1). Any other status (rejection, waiting,
461
- // the revocation / keyUpdate warnings) denies or defers the request, so a
462
- // certificate under it is a malformed response even when no explicit failInfo
463
- // bit is set (a rejection is commonly signaled by status alone). Keying the
464
- // rule off failInfo presence alone would let a bare-rejection status ship a
465
- // certificate (RFC 9810 sec. 5.3.4).
466
375
  if (certifiedKeyPair !== null && status.status.code !== 0 && status.status.code !== 1) {
467
376
  throw ctx.E("cmp/bad-cert-response",
468
377
  "a CertResponse certifiedKeyPair is allowed only under a granting status (accepted or grantedWithMods) (RFC 9810 sec. 5.3.4)");
@@ -476,9 +385,6 @@ var CERT_RESPONSE = schema.seq([
476
385
  },
477
386
  });
478
387
 
479
- // CertRepMessage ::= SEQUENCE { caPubs [1] OPTIONAL, response SEQUENCE OF
480
- // CertResponse } (sec. 5.3.4), where the optional precedes the required field (the
481
- // x509-version shape). caPubs surface raw: the parser confers no trust.
482
388
  var CERT_REP_MESSAGE = schema.seq([
483
389
  schema.optional("caPubs", schema.seqOf(rawSequence("cmp/bad-cert-rep"), {
484
390
  min: 1, code: "cmp/bad-cert-rep", what: "caPubs",
@@ -498,12 +404,6 @@ var CERT_REP_MESSAGE = schema.seq([
498
404
  },
499
405
  });
500
406
 
501
- // KeyRecRepContent ::= SEQUENCE { status PKIStatusInfo, newSigCert [0]
502
- // Certificate OPTIONAL, caCerts [1] SEQUENCE OF Certificate OPTIONAL,
503
- // keyPairHist [2] SEQUENCE OF CertifiedKeyPair OPTIONAL } (sec. 5.3.8). The
504
- // keyPairHist CertifiedKeyPairs can carry the same EnvelopedData form as the
505
- // enrollment responses, so krp is decoded (not surfaced raw) and the operator sees
506
- // the status / key history and the cross-field EnvelopedData version check runs.
507
407
  var KEY_REC_REP_CONTENT = schema.seq([
508
408
  schema.field("status", PKI_STATUS_INFO),
509
409
  schema.trailing([
@@ -529,7 +429,6 @@ var KEY_REC_REP_CONTENT = schema.seq([
529
429
  },
530
430
  });
531
431
 
532
- // PollReqContent / PollRepContent (sec. 5.3.22) -- certReqId may be -1.
533
432
  var POLL_REQ_ENTRY = schema.seq([
534
433
  schema.field("certReqId", schema.integerLeaf()),
535
434
  ], {
@@ -559,16 +458,11 @@ var POLL_REP_CONTENT = schema.seqOf(POLL_REP_ENTRY, {
559
458
  build: function (m) { return m.items.map(function (it) { return it.value.result; }); },
560
459
  });
561
460
 
562
- // ---- the 27-arm body dispatch ----------------------------------------------
563
461
 
564
- // Tag -> arm name, verbatim from the PKIXCMP-2023 module (sec. 5.1.2). Every
565
- // defined arm is at minimum recognized; a subset decodes structurally.
566
462
  var BODY_ARMS = ["ir", "ip", "cr", "cp", "p10cr", "popdecc", "popdecr", "kur", "kup",
567
463
  "krr", "krp", "rr", "rp", "ccr", "ccp", "ckuann", "cann", "rann", "crlann",
568
464
  "pkiconf", "nested", "genm", "genp", "error", "certConf", "pollReq", "pollRep"];
569
- // Arms carrying RFC 4211 CertReqMessages -- walked by the CRMF parser.
570
465
  var CRMF_ARMS = { 0: true, 2: true, 7: true, 9: true, 13: true };
571
- // Arms with a structural schema here.
572
466
  var DECODED_ARMS = {
573
467
  1: CERT_REP_MESSAGE, 3: CERT_REP_MESSAGE, 8: CERT_REP_MESSAGE, 14: CERT_REP_MESSAGE,
574
468
  10: KEY_REC_REP_CONTENT,
@@ -578,12 +472,6 @@ var DECODED_ARMS = {
578
472
  25: POLL_REQ_CONTENT, 26: POLL_REP_CONTENT,
579
473
  };
580
474
 
581
- // The open-CHOICE dispatch: tag -> arm name; walk where a schema exists;
582
- // surface every other defined arm raw as { arm, tag, bytes }, where `decoded` is
583
- // absent (not null) on raw arms, so its presence discriminates decoded-empty
584
- // (pkiconf decodes to null) from recognized-undecoded. `nested` [20] is never
585
- // auto-recursed: a self-nesting tower amplifies per-level walk products, so
586
- // the operator re-feeds its bytes to parse explicitly.
587
475
  var BODY = schema.decode(function (n, ctx) {
588
476
  if (n.tagClass !== "context" || !n.children) {
589
477
  throw ctx.E("cmp/bad-body", "PKIBody must be a constructed context-tagged CHOICE arm (RFC 9810 sec. 5.1.2)");
@@ -597,26 +485,15 @@ var BODY = schema.decode(function (n, ctx) {
597
485
  var inner = n.children[0];
598
486
  var out = { arm: BODY_ARMS[n.tagNumber], tag: n.tagNumber, bytes: inner.bytes };
599
487
  if (CRMF_ARMS[n.tagNumber]) {
600
- // ccr [13] cross-certification: RFC 9810 Appendix D.6 profiles its template
601
- // with signingAlg present and version "v1 or v3" (both overriding RFC 4211
602
- // sec. 5 for this one arm). Those relaxations are allowed. The D.6 profile
603
- // also expects exactly one CertReqMsg, but sec. 5.3.11 defines a ccr as a
604
- // CertReqMessages (SIZE (1..MAX)) and App. D is OPTIONAL, so the base parser
605
- // does not enforce the single-request cardinality (an App. D.6 producer keeps
606
- // to one by its own policy, sending multiple cross-certificates in separate
607
- // messages); only the no-private-key restriction below is normative.
608
488
  var isCcr = n.tagNumber === 13;
609
489
  out.decoded = crmf.walkCertReqMessages(inner, { allowSigningAlg: isCcr, allowV1Version: isCcr });
610
490
  } else if (DECODED_ARMS[n.tagNumber]) {
611
491
  var match = schema.walk(DECODED_ARMS[n.tagNumber], inner, ctx);
612
492
  out.decoded = match.result;
613
493
  } else if (n.tagNumber === 19) {
614
- // PKIConfirmContent ::= NULL (sec. 5.3.16).
615
494
  if (!(inner.tagClass === "universal" && inner.tagNumber === TAGS.NULL)) {
616
495
  throw ctx.E("cmp/bad-pkiconf", "PKIConfirmContent must be NULL (RFC 9810 sec. 5.3.16)");
617
496
  }
618
- // A NULL is well-formed only with empty content (X.690 sec. 8.8.2); the tag check
619
- // alone would surface a non-empty NULL as a valid confirmation.
620
497
  try { asn1.read.nullValue(inner); }
621
498
  catch (e) { throw ctx.E("cmp/bad-pkiconf", "PKIConfirmContent must be an empty NULL (RFC 9810 sec. 5.3.16)", e); }
622
499
  out.decoded = null;
@@ -624,12 +501,7 @@ var BODY = schema.decode(function (n, ctx) {
624
501
  return out;
625
502
  });
626
503
 
627
- // ---- the message envelope -----------------------------------------------------
628
504
 
629
- // PKIProtection ::= BIT STRING: raw bits for the external verifier. Every
630
- // RFC 9481 MSG_SIG_ALG / MSG_MAC_ALG output is an octet string, so the BIT
631
- // STRING must be octet-aligned; with no in-tree CMP verify layer this is
632
- // enforced at parse (the posture the OCSP signature shares), fail-closed.
633
505
  var PROTECTION = schema.decode(function (n, ctx) {
634
506
  var bs;
635
507
  try { bs = asn1.read.bitString(n); }
@@ -640,13 +512,6 @@ var PROTECTION = schema.decode(function (n, ctx) {
640
512
  return { unusedBits: bs.unusedBits, bytes: bs.bytes };
641
513
  });
642
514
 
643
- // PKIMessage ::= SEQUENCE { header, body, protection [0] OPTIONAL,
644
- // extraCerts [1] OPTIONAL } (sec. 5.1). The build runs the two cross-checks that
645
- // span structures: protection presence <=> protectionAlg presence (sec. 5.1.1,
646
- // both directions), and a certConf hashAlg requires pvno cmp2021(3)
647
- // (sec. 5.3.18). headerBytes / bodyBytes are the exact wire slices protection is
648
- // computed over (as DER-SEQUENCE(headerBytes || bodyBytes)), surfaced raw and
649
- // never re-encoded.
650
515
  var PKI_MESSAGE = schema.seq([
651
516
  schema.field("header", PKI_HEADER),
652
517
  schema.field("body", BODY),
@@ -675,12 +540,6 @@ var PKI_MESSAGE = schema.seq([
675
540
  }
676
541
  }
677
542
  }
678
- // RFC 9810 sec. 5.2.2 / sec. 7: EnvelopedData is cmp2021(3) syntax, so a response
679
- // carrying it (an encryptedCert or a privateKey in the envelopedData form)
680
- // under pvno < 3 is a version mismatch, the same version gate the certConf
681
- // hashAlg rule applies. The deprecated EncryptedValue form is the pre-2021
682
- // encoding and stays legal at pvno 2. CertifiedKeyPairs arrive both in the
683
- // CertRepMessage `response` array (ip/cp/kup/ccp) and in the krp keyPairHist.
684
543
  var ckps = [];
685
544
  if (body.decoded && body.decoded.response) {
686
545
  for (var r = 0; r < body.decoded.response.length; r++) {
@@ -698,17 +557,7 @@ var PKI_MESSAGE = schema.seq([
698
557
  throw ctx.E("cmp/bad-version", "a response carrying EnvelopedData (encryptedCert or privateKey) requires CMP version cmp2021(3) (RFC 9810 sec. 5.2.2, sec. 7)");
699
558
  }
700
559
  }
701
- // RFC 9810 sec. 5.3.12 -- a cross-certification response (ccp) reuses the
702
- // CertRepMessage syntax "with the restriction that no encrypted private key
703
- // can be sent": cross-certification certifies an existing CA's public key,
704
- // so there is no key generation and CertifiedKeyPair.privateKey has no
705
- // meaning. Reject a ccp that carries one; never surface the key
706
- // material. The field stays legal in the enrollment responses (ip/cp/kup).
707
560
  if (body.arm === "ccp" && body.decoded && body.decoded.response) {
708
- // RFC 9810 Appendix D.6 profiles a one-way ccp as exactly one CertResponse (the mirror of the ccr
709
- // one-CertReqMsg profile), but sec. 5.3.12 defines a ccp as a CertRepMessage (SIZE (1..MAX)) and App. D
710
- // is OPTIONAL, so the base parser does not enforce the single-response cardinality; only the
711
- // no-private-key restriction is normative.
712
561
  for (var c = 0; c < body.decoded.response.length; c++) {
713
562
  var ckpCcp = body.decoded.response[c].certifiedKeyPair;
714
563
  if (ckpCcp && ckpCcp.privateKey !== null) {
@@ -716,25 +565,13 @@ var PKI_MESSAGE = schema.seq([
716
565
  }
717
566
  }
718
567
  }
719
- // RFC 9810 sec. 5.3.11: a cross-certification request (ccr) MUST NOT send the
720
- // private key to the responding CA (the requesting CA generates and holds
721
- // it). The private-key-carrying POP choices, encryptedKey (cmp2021) and the
722
- // deprecated thisMessage (cmp2000), are therefore forbidden in a ccr; the
723
- // MAC (dhMAC / agreeMAC) and indirect (subsequentMessage) methods carry no
724
- // key. Checked before the version gate so a ccr always gets the ccr verdict.
725
568
  if (body.arm === "ccr" && body.decoded && body.decoded.messages) {
726
569
  for (var cc = 0; cc < body.decoded.messages.length; cc++) {
727
570
  var ccrMsg = body.decoded.messages[cc];
728
- // Via the POP: the encryptedKey / thisMessage POPOPrivKey choices carry
729
- // the private key.
730
571
  var ccrPopo = ccrMsg.popo;
731
572
  if (ccrPopo && (ccrPopo.method === "encryptedKey" || ccrPopo.method === "thisMessage")) {
732
573
  throw ctx.E("cmp/bad-body", "a cross-certification request (ccr) must not send the private key -- the " + ccrPopo.method + " POP choice is forbidden (RFC 9810 sec. 5.3.11)");
733
574
  }
734
- // Via a control: a pkiArchiveOptions control with the encryptedPrivKey [0]
735
- // arm is the other private-key transport (sec. 5.2.8.3.1), likewise forbidden
736
- // in a ccr. The control value is the raw PKIArchiveOptions CHOICE; the
737
- // encryptedPrivKey arm is context tag [0].
738
575
  var controls = ccrMsg.certReq.controls;
739
576
  if (controls) {
740
577
  for (var cn = 0; cn < controls.length; cn++) {
@@ -749,21 +586,12 @@ var PKI_MESSAGE = schema.seq([
749
586
  }
750
587
  }
751
588
  }
752
- // RFC 9810 sec. 5.2.8.3 -- the agreeMAC and encryptedKey POPOPrivKey choices are
753
- // cmp2021(3) syntax; a request (ir/cr/kur/krr/ccr) whose proof-of-possession
754
- // uses either under pvno < 3 is a version mismatch, the same gate the
755
- // response EnvelopedData rule applies. The CRMF walker surfaces the chosen
756
- // POPOPrivKey method on each message's popo.
757
589
  if (body.decoded && body.decoded.messages) {
758
590
  for (var q = 0; q < body.decoded.messages.length; q++) {
759
591
  var popo = body.decoded.messages[q].popo;
760
592
  if (popo && (popo.method === "agreeMAC" || popo.method === "encryptedKey") && header.pvno !== 3) {
761
593
  throw ctx.E("cmp/bad-version", "a request POP using the agreeMAC or encryptedKey choice requires CMP version cmp2021(3) (RFC 9810 sec. 5.2.8.3)");
762
594
  }
763
- // sec. 5.2.8.3.1/sec. 7 -- the same key transport via a pkiArchiveOptions control
764
- // whose encryptedPrivKey [0] EXPLICIT wraps the envelopedData-form
765
- // EncryptedKey is cmp2021 syntax too (a ccr rejects the control outright
766
- // above; the other request arms are version-gated here).
767
595
  var archCtrls = body.decoded.messages[q].certReq.controls;
768
596
  if (archCtrls && header.pvno !== 3) {
769
597
  for (var ac = 0; ac < archCtrls.length; ac++) {
@@ -777,11 +605,6 @@ var PKI_MESSAGE = schema.seq([
777
605
  }
778
606
  }
779
607
  }
780
- // RFC 9810 sec. 5.1.1.4 -- the certProfile name count is bounded by the message
781
- // body: a p10cr carries at most one; an ir/cr/kur no more names than its
782
- // CertReqMsg count, a genm no more than its GenMsgContent InfoTypeAndValue
783
- // count (the names map positionally to the body entries). An overlong list
784
- // makes that mapping ambiguous, so reject it.
785
608
  if (header.generalInfo) {
786
609
  for (var gi = 0; gi < header.generalInfo.length; gi++) {
787
610
  if (header.generalInfo[gi].type !== OID_CERT_PROFILE) continue;
@@ -795,22 +618,12 @@ var PKI_MESSAGE = schema.seq([
795
618
  }
796
619
  }
797
620
  }
798
- // RFC 9810 sec. 5.3.13/sec. 7 -- the cAKeyUpdAnnV3 [0] RootCaKeyUpdateContent CA key
799
- // update form is cmp2021(3) syntax; a ckuann using it under pvno < 3 is a
800
- // version mismatch. ckuann surfaces raw, so inspect its top-level tag: the
801
- // deprecated cAKeyUpdAnnV2 is a universal SEQUENCE, the v3 form is [0].
802
621
  if (body.arm === "ckuann" && header.pvno !== 3) {
803
622
  var caKeyUpd = asn1.decode(body.bytes);
804
623
  if (caKeyUpd.tagClass === "context" && caKeyUpd.tagNumber === 0) {
805
624
  throw ctx.E("cmp/bad-version", "a ckuann using the cAKeyUpdAnnV3 [0] RootCaKeyUpdateContent form requires CMP version cmp2021(3) (RFC 9810 sec. 5.3.13, sec. 7)");
806
625
  }
807
626
  }
808
- // RFC 9810 sec. 5.2.8.3.2/sec. 7 -- Challenge.encryptedRand [0] EnvelopedData is
809
- // cmp2021(3) syntax (the replacement for the deprecated challenge field).
810
- // popdecc surfaces raw, so inspect the already-decoded Challenges the same
811
- // way the ckuann gate inspects its top-level tag: a Challenge carrying a
812
- // context [0] (its only context-tagged field) under pvno < 3 is a version
813
- // mismatch; a non-Challenges shape stays on the documented raw posture.
814
627
  if (body.arm === "popdecc" && header.pvno !== 3) {
815
628
  var challenges = asn1.decode(body.bytes);
816
629
  if (challenges.tagClass === "universal" && challenges.tagNumber === TAGS.SEQUENCE && challenges.children) {
@@ -835,26 +648,12 @@ var PKI_MESSAGE = schema.seq([
835
648
  },
836
649
  });
837
650
 
838
- // ---- support-message infoValue structures (RFC 9480 sec. 2.14-2.17) -----
839
- //
840
- // A genm / genp carries its payload as an ANY, so the InfoTypeAndValue leaf above
841
- // surfaces it as raw bytes. These are the strict decoders for the four values RFC 9483
842
- // sec. 4.3 defines, each a standalone parser so a malformed payload is refused with the
843
- // same caps, minimal-encoding and trailing-byte rules the message itself is held to.
844
- // The CMP module is EXPLICIT TAGS, so every context tag here wraps its value.
845
651
 
846
- // CACertsValue ::= SEQUENCE SIZE (1..MAX) OF CMPCertificate. An absent infoValue is how
847
- // "no CA certificate is available" is said (sec. 4.3.1), so an EMPTY sequence is malformed
848
- // rather than a second spelling of the same answer.
849
652
  var CA_CERTS_VALUE = schema.seqOf(rawSequence("cmp/bad-info-value"), {
850
653
  min: 1, code: "cmp/bad-info-value", what: "CACertsValue",
851
654
  build: function (m) { return m.items.map(function (it) { return it.value; }); },
852
655
  });
853
656
 
854
- // RootCaKeyUpdateContent ::= SEQUENCE { newWithNew CMPCertificate,
855
- // newWithOld [0] CMPCertificate OPTIONAL, oldWithNew [1] CMPCertificate OPTIONAL }
856
- // (RFC 9480 sec. 2.15). Both optionals are OPTIONAL in the syntax; RFC 9483 sec. 4.3.2
857
- // requires newWithOld of a response, which the caller of this decoder enforces.
858
657
  var ROOT_CA_KEY_UPDATE = schema.seq([
859
658
  schema.field("newWithNew", rawSequence("cmp/bad-info-value")),
860
659
  schema.trailing([
@@ -872,9 +671,6 @@ var ROOT_CA_KEY_UPDATE = schema.seq([
872
671
  },
873
672
  });
874
673
 
875
- // AttributeTypeAndValue ::= SEQUENCE { type OBJECT IDENTIFIER, value ANY }, the element of
876
- // the Controls that carries a CertReqTemplate keySpec (RFC 9480 sec. 2.16). The value stays
877
- // raw here: which syntax it must have depends on the type, which sec. 4.3.3 constrains.
878
674
  var ATTR_TYPE_AND_VALUE = schema.seq([
879
675
  schema.field("type", schema.oidLeaf()),
880
676
  schema.field("value", schema.any()),
@@ -886,9 +682,6 @@ var ATTR_TYPE_AND_VALUE = schema.seq([
886
682
  },
887
683
  });
888
684
 
889
- // CertReqTemplateContent ::= SEQUENCE { certTemplate CertTemplate, keySpec Controls OPTIONAL }
890
- // (RFC 9480 sec. 2.16). keySpec is untagged, so it is recognized by its universal SEQUENCE tag
891
- // following the CertTemplate, which is itself IMPLICIT [tagged] by the CRMF module.
892
685
  var CERT_REQ_TEMPLATE_VALUE = schema.seq([
893
686
  schema.field("certTemplate", CERT_TEMPLATE_LEAF),
894
687
  schema.optional("keySpec", schema.seqOf(ATTR_TYPE_AND_VALUE, {
@@ -905,7 +698,6 @@ var CERT_REQ_TEMPLATE_VALUE = schema.seq([
905
698
  },
906
699
  });
907
700
 
908
- // CRLsValue ::= SEQUENCE SIZE (1..MAX) OF CertificateList (RFC 9480 sec. 2.17).
909
701
  var CRLS_VALUE = schema.seqOf(rawSequence("cmp/bad-info-value"), {
910
702
  min: 1, code: "cmp/bad-info-value", what: "CRLsValue",
911
703
  build: function (m) { return m.items.map(function (it) { return it.value; }); },
@@ -914,18 +706,12 @@ var CRLS_VALUE = schema.seqOf(rawSequence("cmp/bad-info-value"), {
914
706
  function _valueParser(what, topSchema) {
915
707
  return pkix.makeParser({ pemLabel: "CMP", PemError: PemError, ErrorClass: CmpError, prefix: "cmp", what: what, topSchema: topSchema, ns: NS });
916
708
  }
917
- // @internal -- pki.cmp.session reads a support-message response through these.
709
+ // @internal
918
710
  var readCaCerts = _valueParser("CACertsValue", CA_CERTS_VALUE);
919
711
  var readRootCaKeyUpdate = _valueParser("RootCaKeyUpdateContent", ROOT_CA_KEY_UPDATE);
920
712
  var readCertReqTemplate = _valueParser("CertReqTemplateValue", CERT_REQ_TEMPLATE_VALUE);
921
713
  var readCrls = _valueParser("CRLsValue", CRLS_VALUE);
922
- // A CertReqTemplate keySpec states a key requirement as an AlgorithmIdentifier (RFC 9480 sec. 2.16),
923
- // which is the shared sub-schema every format already reads one with: `SEQUENCE { algorithm OID,
924
- // parameters ANY OPTIONAL }` and nothing after it. Reading it through the same definition is what
925
- // keeps a third field from passing as a well-formed one.
926
714
  var readAlgorithmIdentifier = _valueParser("AlgorithmIdentifier", ALG_ID);
927
- // A bare Name, so a caller-encoded issuer can be read back into the RDN sequence that guard-name's
928
- // canonical comparison takes. pki.cmp.session binds a returned CRL to the issuer it asked for.
929
715
  var readName = _valueParser("Name", pkix.name(NS));
930
716
 
931
717
  /**
@@ -1039,13 +825,6 @@ function pemDecode(text, label) { return pkix.pemDecode(text, label || "CMP", Pe
1039
825
  */
1040
826
  function pemEncode(der, label) { return pkix.pemEncode(der, label || "CMP", PemError); }
1041
827
 
1042
- // A PKIMessage root is a SEQUENCE of 2-4 whose first child (PKIHeader) is a
1043
- // SEQUENCE of >= 3 leading with a bare INTEGER (pvno) and whose second child
1044
- // (PKIBody) is context-class constructed [0..26]. The one overlap in the
1045
- // registry is one-directional: a 2-child PKIMessage with body ir [0] also
1046
- // satisfies the shallow ocsp-request probe, so this detector registers AHEAD
1047
- // of ocsp-request -- while every real OCSPRequest fails here (its tbsRequest
1048
- // never leads with a bare INTEGER).
1049
828
  function matches(root) {
1050
829
  var k = pkix.rootSequenceChildren(root, 2, 4);
1051
830
  if (!k) return false;
@@ -1062,7 +841,7 @@ module.exports = {
1062
841
  pemDecode: pemDecode,
1063
842
  pemEncode: pemEncode,
1064
843
  matches: matches,
1065
- // @internal -- the RFC 9483 sec. 4.3 support-message values, read strictly from a genp.
844
+ // @internal
1066
845
  readCaCerts: readCaCerts,
1067
846
  readRootCaKeyUpdate: readRootCaKeyUpdate,
1068
847
  readCertReqTemplate: readCertReqTemplate,