@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-cmc.js CHANGED
@@ -53,7 +53,6 @@ var TAGS = asn1.TAGS;
53
53
  function E(code, message, cause) { return new CmcError(code, message, cause); }
54
54
  function O(name) { return oid.byName(name); }
55
55
 
56
- // Registry constants -- never a dotted literal in a format module.
57
56
  var OID_PKI_DATA = O("id-cct-PKIData");
58
57
  var OID_PKI_RESPONSE = O("id-cct-PKIResponse");
59
58
  var OID_STATUS_INFO = O("id-cmc-statusInfo");
@@ -61,21 +60,13 @@ var OID_STATUS_INFO_V2 = O("id-cmc-statusInfoV2");
61
60
  var OID_RESPONSE_BODY = O("id-cmc-responseBody");
62
61
  var OID_RA_IDENTITY_WITNESS = O("id-cmc-raIdentityWitness");
63
62
 
64
- // BodyPartID ::= INTEGER (0..4294967295), RFC 5272 sec. 3.2.2.
65
63
  var BODY_PART_MAX = 4294967295n;
66
64
 
67
- // CMCStatus ::= INTEGER { success(0), failed(2), pending(3), noSupport(4),
68
- // confirmRequired(5), popRequired(6), partial(7) }, RFC 5272 sec. 6.1.3.
69
- // 1 is reserved: it is neither a success nor a failure, so it is refused and
70
- // never folded into either.
71
65
  var STATUS_BY_VALUE = {
72
66
  0: "success", 2: "failed", 3: "pending", 4: "noSupport",
73
67
  5: "confirmRequired", 6: "popRequired", 7: "partial",
74
68
  };
75
69
 
76
- // CMCFailInfo ::= INTEGER { ... }, RFC 5272 sec. 6.1.4. Values outside this set
77
- // are surfaced numerically and never refused: sec. 6.1.4 reserves 1000..1999
78
- // for private extended reasons, so an unknown number is legal data.
79
70
  var FAIL_INFO_BY_VALUE = {
80
71
  0: "badAlg", 1: "badMessageCheck", 2: "badRequest", 3: "badTime", 4: "badCertId",
81
72
  5: "unsupportedExt", 6: "mustArchiveKeys", 7: "badIdentity", 8: "popRequired",
@@ -83,35 +74,18 @@ var FAIL_INFO_BY_VALUE = {
83
74
  13: "authDataFail",
84
75
  };
85
76
 
86
- // The CMS content types a Full PKI Request / Response may ride in, per RFC 5272
87
- // sec. 3.2 ("encapsulated in either a SignedData or an AuthenticatedData") and
88
- // sec. 4.2, which says the same of the response.
89
- // The names are the OID registry's, read off `oid.name(...)` and never taken from the
90
- // spec's prose: RFC 5652 calls the type AuthenticatedData, the registry row is
91
- // `authData`, and hard-coding the prose spelling would reject every conforming
92
- // AuthenticatedData response while looking correct.
93
77
  var CMC_CARRIERS = { signedData: 1, authData: 1 };
94
78
 
95
- // Control PLACEMENT -- RFC 6402 sec. 2.5 / 2.6 give two MUSTs about where a
96
- // control may appear. An OID-keyed table states them once, in the shape of the
97
- // shipped CMS attribute-placement registry, so a new placement rule is a row.
98
79
  var CONTROL_PLACEMENT = {};
99
- CONTROL_PLACEMENT[OID_RESPONSE_BODY] = "pkiResponse"; // sec. 2.6: never in a PKIData
100
- CONTROL_PLACEMENT[OID_RA_IDENTITY_WITNESS] = "pkiData"; // sec. 2.5: never in a PKIResponse
80
+ CONTROL_PLACEMENT[OID_RESPONSE_BODY] = "pkiResponse";
81
+ CONTROL_PLACEMENT[OID_RA_IDENTITY_WITNESS] = "pkiData";
101
82
 
102
- // ---- leaves ----------------------------------------------------------
103
83
 
104
- // A BodyPartID read + bounded + narrowed atomically. `guard.range.int` takes
105
- // BigInt bounds and returns a Number only when the value is inside them, so an
106
- // out-of-range identifier can never reach the caller as a silently-truncated int.
107
84
  function readBodyPartId(node, label) {
108
85
  var v = asn1.read.integer(node);
109
86
  return guard.range.int(v, 0n, BODY_PART_MAX, E, "cmc/bad-body-part-id", label || "a BodyPartID");
110
87
  }
111
88
 
112
- // The identity of an element, where 0 is reserved (RFC 5272 sec. 3.2.2: "The
113
- // bodyPartID value of 0 is reserved for use as the reference to the current
114
- // PKIData object"). A REFERENCE may be 0; an identity may not.
115
89
  function readBodyPartIdentity(node) {
116
90
  var id = readBodyPartId(node, "a body part identity");
117
91
  if (id === 0) {
@@ -121,16 +95,7 @@ function readBodyPartIdentity(node) {
121
95
  return id;
122
96
  }
123
97
 
124
- // ---- controls --------------------------------------------------------
125
98
 
126
- // TaggedAttribute ::= SEQUENCE { bodyPartID BodyPartID, attrType OBJECT
127
- // IDENTIFIER, attrValues SET OF AttributeValue }, RFC 5272 sec. 3.2.1.1.
128
- // attrValues are surfaced raw: this decoder does not know every control, and
129
- // PD7's "fail on an unrecognized control" binds the server, not a client reading
130
- // a response, so an unknown value is data to hand on, never a fault.
131
- //
132
- // The placement rule is not checked here: it depends on which message the control
133
- // sits in, which the enclosing walk knows and this shape does not.
134
99
  var TAGGED_ATTRIBUTE = schema.seq([
135
100
  schema.field("bodyPartID", schema.decode(readBodyPartIdentity)),
136
101
  schema.field("attrType", schema.oidLeaf()),
@@ -149,8 +114,6 @@ var TAGGED_ATTRIBUTE = schema.seq([
149
114
  },
150
115
  });
151
116
 
152
- // RFC 6402 sec. 2.5 / 2.6 give two MUSTs about WHERE a control may appear, and
153
- // both are one-directional. Applied against the enclosing message kind.
154
117
  function assertControlPlacement(control, where) {
155
118
  var placement = CONTROL_PLACEMENT[control.attrType];
156
119
  if (placement && placement !== where) {
@@ -160,11 +123,7 @@ function assertControlPlacement(control, where) {
160
123
  }
161
124
  }
162
125
 
163
- // ---- status controls -------------------------------------------------
164
126
 
165
- // BodyPartReference ::= CHOICE { bodyPartID BodyPartID, bodyPartPath BodyPartPath }
166
- // (an INTEGER and a SEQUENCE, so the arms are tag-disjoint). BodyPartPath is
167
- // SEQUENCE SIZE(1..MAX), so an empty one is malformed, never "no path".
168
127
  function parseBodyPartReference(node) {
169
128
  if (node.tagClass === "universal" && node.tagNumber === TAGS.INTEGER) {
170
129
  return { bodyPartID: readBodyPartId(node), bodyPartPath: null };
@@ -178,33 +137,8 @@ function parseBodyPartReference(node) {
178
137
  throw E("cmc/bad-status-info", "a BodyPartReference must be a BodyPartID INTEGER or a BodyPartPath SEQUENCE");
179
138
  }
180
139
 
181
- /**
182
- * OtherStatusInfo ::= CHOICE { failInfo CMCFailInfo, pendInfo PendInfo,
183
- * extendedFailInfo SEQUENCE { ... } }
184
- *
185
- * The load-bearing ambiguity. RFC 5272 App A and RFC 6402 App A.1 (the 1988
186
- * module) leave `extendedFailInfo` UNTAGGED, so it collides with `pendInfo` --
187
- * both are a bare SEQUENCE. RFC 6402 App A.2 (the 2008 module) tags it `[1]`.
188
- * Both encodings occur on the wire, so both are decoded:
189
- *
190
- * universal INTEGER -> failInfo
191
- * context [1] -> extendedFailInfo (2008 module)
192
- * universal SEQUENCE -> disambiguate on the first child's tag:
193
- * OCTET STRING -> pendInfo (PendInfo ::= SEQUENCE
194
- * { pendToken OCTET STRING, pendTime GeneralizedTime })
195
- * OBJECT IDENTIFIER -> extendedFailInfo
196
- * anything else -> refuse
197
- *
198
- * The final arm is the point: a shape that matches neither rule is REFUSED, not
199
- * guessed at. Guessing here would attach a failure reason, or a pending token,
200
- * that the responder never sent.
201
- */
140
+
202
141
  function parseOtherStatusInfo(node, version) {
203
- // The extendedFailInfo arm belongs to CMCStatusInfoV2 alone. RFC 5272 sec. 6.1.1
204
- // gives the v1 otherInfo exactly two arms, `CHOICE { failInfo CMCFailInfo,
205
- // pendInfo PendInfo }`, so accepting the third here would read a failure
206
- // verdict out of a v1 control that cannot legally express one, and the
207
- // disambiguation below would be answering a question v1 never asks.
208
142
  var extendedAllowed = version !== 1;
209
143
  if (node.tagClass === "universal" && node.tagNumber === TAGS.INTEGER) {
210
144
  var v = asn1.read.integer(node);
@@ -216,13 +150,6 @@ function parseOtherStatusInfo(node, version) {
216
150
  throw E("cmc/bad-status-info",
217
151
  "a v1 CMCStatusInfo otherInfo is failInfo or pendInfo only; the [1] extendedFailInfo arm is CMCStatusInfoV2's (RFC 5272 sec. 6.1.1)");
218
152
  }
219
- // IMPLICIT, so the [1] REPLACES the SEQUENCE tag and its children are the
220
- // failInfoOID / failInfoValue directly -- there is no inner SEQUENCE to
221
- // unwrap. Both RFC 6402 modules are IMPLICIT: A.1 (rfc6402.txt:805) and A.2
222
- // (rfc6402.txt:1314) each open `DEFINITIONS IMPLICIT TAGS ::=`, and the
223
- // EXPLICIT-override rule does not apply here because the tagged type is a
224
- // plain SEQUENCE, not a CHOICE or an open type. Reading this arm as
225
- // EXPLICIT would reject every conforming 2008-module response.
226
153
  return { failInfo: null, failInfoName: null, pendInfo: null, extendedFailInfo: readExtendedFailInfo(node.children, "[1] extendedFailInfo") };
227
154
  }
228
155
  if (node.tagClass === "universal" && node.tagNumber === TAGS.SEQUENCE && node.constructed) {
@@ -230,9 +157,6 @@ function parseOtherStatusInfo(node, version) {
230
157
  if (!first) throw E("cmc/ambiguous-status-info", "an empty OtherStatusInfo SEQUENCE matches neither pendInfo nor extendedFailInfo");
231
158
  if (first.tagClass === "universal" && first.tagNumber === TAGS.OCTET_STRING) {
232
159
  if (node.children.length !== 2) throw E("cmc/bad-status-info", "PendInfo must be { pendToken, pendTime }");
233
- // pendTime is a GeneralizedTime specifically, so assert the tag and do not
234
- // accept either time form: a UTCTime here is a different encoding, and
235
- // reading it anyway would let a two-digit year through the retry clock.
236
160
  var timeNode = node.children[1];
237
161
  if (timeNode.tagClass !== "universal" || timeNode.tagNumber !== TAGS.GENERALIZED_TIME) {
238
162
  throw E("cmc/bad-status-info", "PendInfo pendTime must be a GeneralizedTime (RFC 5272 sec. 6.1.1)");
@@ -255,10 +179,6 @@ function parseOtherStatusInfo(node, version) {
255
179
  throw E("cmc/bad-status-info", "OtherStatusInfo must be a CMCFailInfo INTEGER, a PendInfo SEQUENCE, or an extendedFailInfo");
256
180
  }
257
181
 
258
- // ExtendedFailInfo ::= SEQUENCE { failInfoOID OBJECT IDENTIFIER, failInfoValue ANY }
259
- // The OID is surfaced raw and never mapped onto a CMCFailInfo: RFC 5272 sec.
260
- // 6.1.1 makes internalCAError only a MAY for an unrecognized extended error, and
261
- // synthesizing it would report a reason the responder did not send.
262
182
  function readExtendedFailInfo(children, what) {
263
183
  if (!children || children.length !== 2) {
264
184
  throw E("cmc/bad-status-info", what + " must be SEQUENCE { failInfoOID, failInfoValue }");
@@ -266,12 +186,6 @@ function readExtendedFailInfo(children, what) {
266
186
  return { failInfoOID: asn1.read.oid(children[0]), failInfoValueBytes: children[1].bytes };
267
187
  }
268
188
 
269
- // CMCStatusInfoV2 ::= SEQUENCE { cMCStatus, bodyList SEQUENCE SIZE(1..MAX) OF
270
- // BodyPartReference, statusString UTF8String OPTIONAL, otherInfo OPTIONAL }
271
- // The v1 CMCStatusInfo is the same shape with a SEQUENCE OF BodyPartID bodyList
272
- // and no extendedFailInfo arm; both are decoded into one surface so a caller
273
- // reads one ordered list of verdicts (RFC 5272 sec. 6.1: a client MUST cope with
274
- // several status controls).
275
189
  function parseStatusInfo(valueDer, version, bodyPartID) {
276
190
  var root = asn1.decode(valueDer);
277
191
  if (root.tagClass !== "universal" || root.tagNumber !== TAGS.SEQUENCE || !root.constructed) {
@@ -284,8 +198,6 @@ function parseStatusInfo(valueDer, version, bodyPartID) {
284
198
  var statusNum = guard.range.int(statusValue, 0n, 0xFFFFFFFFn, E, "cmc/bad-status", "a CMCStatus");
285
199
  var statusName = STATUS_BY_VALUE[statusNum];
286
200
  if (!statusName) {
287
- // 1 is reserved and everything above 7 is unassigned. An unknown status is
288
- // not a verdict in either direction, so it is refused and never mapped.
289
201
  throw E("cmc/bad-status", "unknown CMCStatus " + statusNum + " (1 is reserved; RFC 5272 sec. 6.1.3)");
290
202
  }
291
203
 
@@ -300,17 +212,10 @@ function parseStatusInfo(valueDer, version, bodyPartID) {
300
212
  return version === 2 ? parseBodyPartReference(c) : { bodyPartID: readBodyPartId(c), bodyPartPath: null };
301
213
  });
302
214
 
303
- // The two OPTIONAL tail fields are ORDERED by the ASN.1: statusString precedes
304
- // otherInfo. Tracking only "have I seen a statusString yet" would accept them
305
- // reversed -- a second encoding of a structure DER admits exactly one encoding
306
- // of -- so the walk refuses anything once otherInfo has been consumed.
307
215
  var statusString = null, other = null, sawOther = false;
308
216
  for (var i = 2; i < kids.length; i++) {
309
217
  var k = kids[i];
310
218
  if (k.tagClass === "universal" && k.tagNumber === TAGS.UTF8_STRING && statusString === null && !sawOther) {
311
- // read.string, not a per-type reader: the codec exposes one strict text reader
312
- // for the DirectoryString family and there is no `read.utf8`. The tag is
313
- // already asserted UTF8String above, so this decodes exactly that.
314
219
  statusString = asn1.read.string(k);
315
220
  continue;
316
221
  }
@@ -334,11 +239,6 @@ function parseStatusInfo(valueDer, version, bodyPartID) {
334
239
  return out;
335
240
  }
336
241
 
337
- // The cross-field coupling (RFC 5272 sec. 6.1.1 / 6.1.2): failInfo and
338
- // extendedFailInfo are "present only if cMCStatus contains the value failed",
339
- // and pendInfo "MUST be populated for a cMCStatus value of pending or partial".
340
- // A message whose status and detail disagree is refused, never reconciled:
341
- // the two halves would otherwise let a caller read a verdict neither field states.
342
242
  function _assertStatusCoherent(s) {
343
243
  var isFailed = s.status === "failed";
344
244
  var isPending = s.status === "pending" || s.status === "partial";
@@ -356,19 +256,7 @@ function _assertStatusCoherent(s) {
356
256
  }
357
257
  }
358
258
 
359
- // ---- tagged requests -------------------------------------------------
360
-
361
- // TaggedRequest ::= CHOICE { tcr [0] TaggedCertificationRequest,
362
- // crm [1] CertReqMsg,
363
- // orm [2] SEQUENCE { bodyPartID, requestMessageType,
364
- // requestMessageValue } }
365
- // The CMC module is IMPLICIT TAGS, so each context tag REPLACES the arm's own
366
- // universal tag: the [0] node's direct children are the TaggedCertificationRequest
367
- // fields, not a nested SEQUENCE. An EXPLICIT encoding is therefore a different
368
- // (and invalid) message, which is what C5 pins.
369
- // An IMPLICIT context-tagged constructed node re-encoded under the universal
370
- // SEQUENCE tag it stands in for. IMPLICIT tagging REPLACES the tag and leaves the
371
- // content untouched, so restoring it is exactly a re-headering of the same bytes.
259
+
372
260
  function _asUniversalSequence(node) {
373
261
  var headerLen = node.header.end - node.header.start;
374
262
  return asn1.encode(0x00, true, TAGS.SEQUENCE, node.bytes.subarray(headerLen));
@@ -379,7 +267,6 @@ function parseTaggedRequest(node) {
379
267
  throw E("cmc/bad-tagged-request", "a TaggedRequest must be a context-tagged constructed CHOICE arm (RFC 5272 sec. 3.2.1.2)");
380
268
  }
381
269
  if (node.tagNumber === 0) {
382
- // TaggedCertificationRequest ::= SEQUENCE { bodyPartID, certificationRequest }
383
270
  if (node.children.length !== 2) {
384
271
  throw E("cmc/bad-tagged-request", "a tcr arm is [0] IMPLICIT { bodyPartID, certificationRequest }; the module is IMPLICIT TAGS, so an EXPLICIT wrapper is not this arm");
385
272
  }
@@ -394,23 +281,6 @@ function parseTaggedRequest(node) {
394
281
  };
395
282
  }
396
283
  if (node.tagNumber === 1) {
397
- // crm [1] IMPLICIT CertReqMsg.
398
- //
399
- // This arm still has a body part IDENTITY, and it is not a separate field:
400
- // RFC 5272 sec. 3.2.2 says "Body part identifiers are encoded in the
401
- // certReqIds field for CertReqMsg objects (in a TaggedRequest) or in the
402
- // bodyPartID field of the other objects", and sec. 6.5.2 repeats it
403
- // ("... either the bodyPartID of a TaggedCertificationRequest (PKCS #10) or
404
- // the certReqId of the CertRequest within a CertReqMsg (CRMF)"). So the
405
- // certReqId is read here and carried into the same whole-message uniqueness
406
- // check every other body part is bound by; returning null would silently
407
- // exempt this arm from it.
408
- //
409
- // CertReqMsg ::= SEQUENCE { certReq CertRequest, popo OPTIONAL, regInfo OPTIONAL }
410
- // CertRequest ::= SEQUENCE { certReqId INTEGER, certTemplate CertTemplate, ... }
411
- //
412
- // Only the identity is decoded here; the CertReqMsg's own conformance is
413
- // pki.schema.crmf's to enforce, and duplicating it would fork the rules.
414
284
  var certReq = node.children[0];
415
285
  if (!certReq || certReq.tagClass !== "universal" || certReq.tagNumber !== TAGS.SEQUENCE || !certReq.constructed) {
416
286
  throw E("cmc/bad-tagged-request", "a crm arm is [1] IMPLICIT CertReqMsg, whose first element is a CertRequest SEQUENCE");
@@ -421,9 +291,6 @@ function parseTaggedRequest(node) {
421
291
  return {
422
292
  arm: "crm", bodyPartID: readBodyPartIdentity(certReq.children[0]),
423
293
  certificationRequestBytes: null,
424
- // Re-tagged from the IMPLICIT [1] back to the universal SEQUENCE the CRMF
425
- // parser expects: handing back the context-tagged bytes would produce a
426
- // structure no CertReqMsg reader accepts.
427
294
  certReqMsgBytes: _asUniversalSequence(node),
428
295
  requestMessageType: null, requestMessageValueBytes: null,
429
296
  };
@@ -442,12 +309,7 @@ function parseTaggedRequest(node) {
442
309
  throw E("cmc/bad-tagged-request", "unknown TaggedRequest alternative [" + node.tagNumber + "] (RFC 5272 sec. 3.2.1.2)");
443
310
  }
444
311
 
445
- // ---- body-part identity ----------------------------------------------
446
312
 
447
- // RFC 5272 sec. 3.2.2: "The body part identifier MUST be unique within a single
448
- // PKIData or PKIResponse." The scope is the whole message: a checker that ran
449
- // per-sequence would accept a control and a request that collide, which is
450
- // exactly the shape B2 pins.
451
313
  function assertUniqueBodyPartIds(ids) {
452
314
  var seen = Object.create(null);
453
315
  for (var i = 0; i < ids.length; i++) {
@@ -460,21 +322,7 @@ function assertUniqueBodyPartIds(ids) {
460
322
  }
461
323
  }
462
324
 
463
- // ---- the two message bodies ------------------------------------------
464
-
465
- // The two message bodies as engine schemas. Declaring them means the engine owns
466
- // the positional reads, the field arity and the SET-OF ordering (the bug class
467
- // a hand-rolled cursor keeps reintroducing), while the rules that genuinely span
468
- // fields (whole-message body-part uniqueness, control placement, the status
469
- // cross-checks) run in the build / the caller, which is where they can see
470
- // everything they need.
471
- // A repeat's walk result is the match object `{ node, items: [{ node, value }] }`,
472
- // so each of these carries a `build` that flattens it to the plain list the
473
- // enclosing build wants. The three differ by what an item's `value` IS, which is
474
- // decided by the item schema:
475
- // - a `seq` item walks to its own MATCH, so its build output is at .value.result
476
- // - a `decode` leaf walks straight to whatever its function returned
477
- // - an `any` item walks to the node, whose .bytes is the raw TLV
325
+
478
326
  function builtList(match) { return match.items.map(function (i) { return i.value.result; }); }
479
327
  function decodedList(match) { return match.items.map(function (i) { return i.value; }); }
480
328
  function rawList(match) { return match.items.map(function (i) { return i.node.bytes; }); }
@@ -484,26 +332,12 @@ var CONTROL_SEQUENCE = schema.seqOf(TAGGED_ATTRIBUTE,
484
332
  var REQ_SEQUENCE = schema.seqOf(schema.decode(parseTaggedRequest),
485
333
  { code: "cmc/bad-tagged-request", what: "a reqSequence", build: decodedList });
486
334
 
487
- // TaggedContentInfo ::= SEQUENCE { bodyPartID, contentInfo } (RFC 5272 sec.
488
- // 3.2.1.3) and OtherMsg ::= SEQUENCE { bodyPartID, otherMsgType, otherMsgValue }
489
- // (sec. 3.2.1.4). Neither payload is interpreted here (the ContentInfo is a
490
- // CMS object the caller decodes, the OtherMsg value is by definition arbitrary),
491
- // but both carry a body part identity, and sec. 3.2.2's uniqueness rule covers
492
- // "each element of a PKIData or PKIResponse". Decoding just the identifier is
493
- // what lets that rule cover them without this layer claiming to understand the
494
- // payload.
495
335
  var TAGGED_CONTENT_INFO = schema.seq([
496
336
  schema.field("bodyPartID", schema.decode(readBodyPartIdentity)),
497
337
  schema.field("contentInfo", schema.any()),
498
338
  ], {
499
339
  assert: "sequence", arity: { exact: 2 }, code: "cmc/bad-cms-sequence", what: "a TaggedContentInfo",
500
340
  build: function (m) {
501
- // The payload stays raw, since this layer does not decode a content type it may
502
- // not know, but it must still be a ContentInfo: SEQUENCE { contentType
503
- // OBJECT IDENTIFIER, content [0] EXPLICIT ANY OPTIONAL } (RFC 5652 sec. 3).
504
- // Surfacing an INTEGER, or anything else that cannot be one, as a content
505
- // info would hand the caller a "CMS message" no CMS reader will accept, which
506
- // is not the same thing as a content type this decoder happens not to handle.
507
341
  var ci = m.fields.contentInfo.value;
508
342
  var kids = ci.children || [];
509
343
  var lead = kids[0];
@@ -511,23 +345,11 @@ var TAGGED_CONTENT_INFO = schema.seq([
511
345
  throw E("cmc/bad-cms-sequence",
512
346
  "a TaggedContentInfo carries a CMS ContentInfo, which leads with its contentType OBJECT IDENTIFIER (RFC 5652 sec. 3)");
513
347
  }
514
- // Read the contentType; do not merely inspect its tag. An OBJECT IDENTIFIER
515
- // TLV can carry content no OID reader will accept (empty, or a subidentifier
516
- // padded to a non-minimal encoding) and a tag check waves both through. The
517
- // toolkit's own CMS parser refuses them, so accepting them here would let the
518
- // builder sign a "CMS message" pki.schema.cms.parse will not read back. The
519
- // VALUE is still not interpreted: this layer only establishes that there is a
520
- // content type to interpret.
521
348
  try { asn1.read.oid(lead); }
522
349
  catch (e) {
523
350
  throw E("cmc/bad-cms-sequence",
524
351
  "a TaggedContentInfo carries a CMS ContentInfo, whose contentType must be a readable OBJECT IDENTIFIER (RFC 5652 sec. 3)", e);
525
352
  }
526
- // The whole envelope, not just its first field: content is `[0] EXPLICIT ANY
527
- // DEFINED BY contentType OPTIONAL`, so at most one more element and it is that
528
- // tag. An INTEGER sitting where the content belongs, or a third field, is not
529
- // a ContentInfo any CMS reader will take, and stopping at the leading OID
530
- // would surface it as one.
531
353
  if (kids.length > 2) {
532
354
  throw E("cmc/bad-cms-sequence",
533
355
  "a CMS ContentInfo is { contentType, [0] EXPLICIT content OPTIONAL }; this carries " +
@@ -539,10 +361,6 @@ var TAGGED_CONTENT_INFO = schema.seq([
539
361
  throw E("cmc/bad-cms-sequence",
540
362
  "a CMS ContentInfo's second field is the [0] EXPLICIT content (RFC 5652 sec. 3)");
541
363
  }
542
- // EXPLICIT wraps exactly one value (X.690 sec. 8.14). Checking the tag alone
543
- // would let an empty wrapper, or one holding several values, read as a content
544
- // info: shapes pki.schema.cms.parse refuses as cms/not-a-content-info, so the
545
- // builder's readback would pass a message its own CMS reader will not accept.
546
364
  if (!content.children || content.children.length !== 1) {
547
365
  throw E("cmc/bad-cms-sequence",
548
366
  "a ContentInfo's [0] EXPLICIT content wraps exactly one value, got " +
@@ -568,9 +386,6 @@ var OTHER_MSG = schema.seq([
568
386
  },
569
387
  });
570
388
 
571
- // PKIData ::= SEQUENCE { controlSequence, reqSequence, cmsSequence,
572
- // otherMsgSequence }, RFC 5272 sec. 3.2.1. All four are mandatory though each
573
- // may be empty, so `arity: { exact: 4 }` is the rule, not a convenience.
574
389
  var PKI_DATA = schema.seq([
575
390
  schema.field("controlSequence", CONTROL_SEQUENCE),
576
391
  schema.field("reqSequence", REQ_SEQUENCE),
@@ -588,17 +403,11 @@ var PKI_DATA = schema.seq([
588
403
  requests: m.fields.reqSequence.value.result,
589
404
  cmsSequence: m.fields.cmsSequence.value.result,
590
405
  otherMsgs: m.fields.otherMsgSequence.value.result,
591
- // The raw reqSequence TLV, tag and length included: the Identity Proof V2
592
- // witness is computed over exactly these bytes "encoded exactly as it
593
- // appears in the Full PKI Request" (RFC 5272 sec. 6.2.1), so it is taken
594
- // off the matched node, never re-encoded from the decoded requests.
595
406
  reqSequenceBytes: m.fields.reqSequence.node.bytes,
596
407
  };
597
408
  },
598
409
  });
599
410
 
600
- // PKIResponse ::= SEQUENCE { controlSequence, cmsSequence, otherMsgSequence } --
601
- // RFC 5272 sec. 4.2.1. THREE fields: there is no reqSequence in a response.
602
411
  var PKI_RESPONSE = schema.seq([
603
412
  schema.field("controlSequence", CONTROL_SEQUENCE),
604
413
  schema.field("cmsSequence", schema.seqOf(TAGGED_CONTENT_INFO,
@@ -620,10 +429,6 @@ var PKI_RESPONSE = schema.seq([
620
429
  },
621
430
  });
622
431
 
623
- // Collect the status controls out of an already-parsed control list, in wire
624
- // order. Absence is not an error: RFC 5272 sec. 6.1.2 says "If no status exists
625
- // for a Simple or Full PKI Request, then the value of success is assumed", so a
626
- // response with no status control is a successful one.
627
432
  function _collectStatuses(controls) {
628
433
  var out = [];
629
434
  for (var i = 0; i < controls.length; i++) {
@@ -638,21 +443,12 @@ function _collectStatuses(controls) {
638
443
  return out;
639
444
  }
640
445
 
641
- // The cross-cutting rules that a per-field walk cannot see: where each control is
642
- // allowed to appear, which of them are status verdicts, which are unrecognized
643
- // (surfaced, never a fault), and the whole-message body-part uniqueness.
644
446
  function _finishBody(body, where) {
645
447
  for (var i = 0; i < body.controls.length; i++) assertControlPlacement(body.controls[i], where);
646
448
  body.statuses = _collectStatuses(body.controls);
647
449
  body.unhandled = body.controls.filter(function (c) {
648
450
  return c.attrType !== OID_STATUS_INFO && c.attrType !== OID_STATUS_INFO_V2 && c.attrName === null;
649
451
  });
650
- // RFC 5272 sec. 3.2.2 scopes uniqueness to "each element of a PKIData or
651
- // PKIResponse", and four element kinds carry an identity. Enumerated here in
652
- // one place so the rule cannot hold for some of them and quietly lapse for the
653
- // rest: controls (sec. 3.2.1.1), requests (sec. 3.2.1.2, the tcr/orm
654
- // bodyPartID and the crm arm's certReqId), content infos (sec. 3.2.1.3) and
655
- // other messages (sec. 3.2.1.4).
656
452
  var ids = [];
657
453
  function collect(list) { for (var j = 0; j < list.length; j++) ids.push(list[j].bodyPartID); }
658
454
  collect(body.controls);
@@ -745,20 +541,9 @@ function parsePkiResponse(input) {
745
541
  * pki.schema.cmc.parse(der).kind; // "pkiData"
746
542
  */
747
543
  function parse(input) {
748
- // Bytes or an already-parsed CMS? Decided by a POSITIVE marker of the parsed
749
- // shape, never by "it is an object" -- a Uint8Array is an object too, so the
750
- // looser test routes perfectly good DER to the parsed branch, where it has no
751
- // content type and is refused as not-CMC while the identical Buffer parses.
752
- // encapContentInfo is the field this function goes on to read, so requiring it
753
- // is the same question the code below already asks.
754
544
  var parsedCms = (input && typeof input === "object" && !ArrayBuffer.isView(input) &&
755
545
  !guard.bytes.isByteSource(input) && input.encapContentInfo != null)
756
546
  ? input : cms.parse(input);
757
- // The CARRIER is part of the identity, not just the encapsulated content type.
758
- // RFC 5272 sec. 3.2 / 4.2 admit a SignedData or an AuthenticatedData; other CMS
759
- // types also expose an encapContentInfo (CompressedData does), and dispatching
760
- // on the inner OID alone would accept an unsigned, unauthenticated wrapper as a
761
- // Full PKI message.
762
547
  if (CMC_CARRIERS[parsedCms.contentTypeName] !== 1) {
763
548
  throw E("cmc/not-cmc",
764
549
  "a Full PKI Request / Response is carried in a CMS SignedData or AuthenticatedData, got " +