@blamejs/pki 0.5.7 → 0.5.8

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 (104) hide show
  1. package/CHANGELOG.md +405 -386
  2. package/MIGRATING.md +43 -0
  3. package/README.md +12 -12
  4. package/lib/acme.js +31 -31
  5. package/lib/asn1-der.js +10 -10
  6. package/lib/attrcert-sign.js +19 -19
  7. package/lib/byte-reader.js +6 -6
  8. package/lib/byte-writer.js +5 -5
  9. package/lib/cbor-det.js +27 -24
  10. package/lib/cmc-build.js +97 -92
  11. package/lib/cmc-verify.js +106 -30
  12. package/lib/cmp-build.js +25 -25
  13. package/lib/cmp-session.js +70 -70
  14. package/lib/cmp-verify.js +71 -57
  15. package/lib/cms-compress.js +7 -7
  16. package/lib/cms-decrypt.js +90 -72
  17. package/lib/cms-encrypt.js +32 -32
  18. package/lib/cms-sign.js +74 -55
  19. package/lib/cms-verify.js +97 -75
  20. package/lib/composite-sig.js +13 -13
  21. package/lib/constants.js +4 -4
  22. package/lib/crl-sign.js +22 -22
  23. package/lib/crl-verify.js +7 -6
  24. package/lib/crmf-sign.js +14 -14
  25. package/lib/csr-sign.js +8 -8
  26. package/lib/ct.js +37 -37
  27. package/lib/edwards-point.js +7 -7
  28. package/lib/est.js +98 -55
  29. package/lib/framework-error.js +5 -5
  30. package/lib/guard-all.js +3 -3
  31. package/lib/guard-async.js +4 -4
  32. package/lib/guard-bytes.js +79 -79
  33. package/lib/guard-compress.js +17 -17
  34. package/lib/guard-crypto.js +1 -1
  35. package/lib/guard-encoding.js +15 -15
  36. package/lib/guard-header.js +3 -3
  37. package/lib/guard-identifier.js +16 -16
  38. package/lib/guard-json.js +15 -15
  39. package/lib/guard-limits.js +7 -7
  40. package/lib/guard-name.js +81 -16
  41. package/lib/guard-parsed.js +80 -80
  42. package/lib/guard-range.js +19 -19
  43. package/lib/guard-secret.js +11 -10
  44. package/lib/guard-text.js +6 -6
  45. package/lib/guard-time.js +10 -10
  46. package/lib/hpke.js +18 -17
  47. package/lib/http-digest.js +35 -35
  48. package/lib/http-retry-after.js +13 -13
  49. package/lib/http-transport.js +20 -19
  50. package/lib/inspect.js +53 -53
  51. package/lib/ip-utils.js +2 -2
  52. package/lib/jose.js +13 -13
  53. package/lib/key.js +16 -16
  54. package/lib/lint.js +51 -51
  55. package/lib/merkle.js +51 -36
  56. package/lib/mime.js +18 -18
  57. package/lib/ocsp-verify.js +10 -10
  58. package/lib/ocsp.js +13 -13
  59. package/lib/oid.js +29 -29
  60. package/lib/path-validate.js +114 -113
  61. package/lib/pbes2.js +16 -16
  62. package/lib/pkcs12-build.js +53 -53
  63. package/lib/pki-build.js +21 -19
  64. package/lib/rc2.js +1 -1
  65. package/lib/rfc3339.js +5 -5
  66. package/lib/schema-all.js +31 -31
  67. package/lib/schema-attrcert.js +12 -12
  68. package/lib/schema-c509.js +144 -142
  69. package/lib/schema-cmc.js +58 -58
  70. package/lib/schema-cmp.js +43 -43
  71. package/lib/schema-cms.js +45 -45
  72. package/lib/schema-crl.js +7 -7
  73. package/lib/schema-crmf.js +28 -28
  74. package/lib/schema-csr.js +12 -12
  75. package/lib/schema-csrattrs.js +16 -16
  76. package/lib/schema-engine.js +18 -18
  77. package/lib/schema-ocsp.js +15 -15
  78. package/lib/schema-pkcs12.js +20 -20
  79. package/lib/schema-pkcs8.js +2 -2
  80. package/lib/schema-pkix.js +131 -126
  81. package/lib/schema-smime.js +19 -19
  82. package/lib/schema-tsp.js +12 -12
  83. package/lib/schema-x509.js +3 -3
  84. package/lib/shbs.js +18 -18
  85. package/lib/sign-scheme.js +13 -13
  86. package/lib/sigstore.js +10 -11
  87. package/lib/sleep.js +1 -1
  88. package/lib/smime.js +308 -96
  89. package/lib/tls-cert-compress.js +18 -18
  90. package/lib/trust.js +27 -27
  91. package/lib/tsp-sign.js +17 -17
  92. package/lib/validator-all.js +1 -1
  93. package/lib/validator-attcert.js +1 -1
  94. package/lib/validator-cose.js +43 -44
  95. package/lib/validator-keydesc.js +3 -3
  96. package/lib/validator-sig.js +13 -13
  97. package/lib/validator-tls.js +11 -11
  98. package/lib/validator-tpm.js +20 -19
  99. package/lib/webauthn-mds.js +66 -66
  100. package/lib/webauthn.js +33 -33
  101. package/lib/webcrypto.js +15 -15
  102. package/lib/x509-sign.js +13 -13
  103. package/package.json +3 -2
  104. package/sbom.cdx.json +6 -6
package/lib/schema-cmc.js CHANGED
@@ -16,10 +16,10 @@
16
16
  * the CMS layer, dispatches on that content type, and decodes the message.
17
17
  *
18
18
  * Every body part carries a `BodyPartID`, and the identifier MUST be unique
19
- * across the WHOLE message rather than within one sequence; 0 is reserved as
19
+ * across the whole message, not merely within one sequence; 0 is reserved as
20
20
  * the reference to the enclosing PKIData and is never an element's own
21
- * identity. Controls are surfaced as an ordered list with their values RAW: an
22
- * unrecognized control is DATA, not a fault, because the rule that a server
21
+ * identity. Controls are surfaced as an ordered list with their values raw: an
22
+ * unrecognized control is data, not a fault, because the rule that a server
23
23
  * fails an unrecognized control binds the server, not the client reading a
24
24
  * response. The status controls (`CMCStatusInfo` v1 and `CMCStatusInfoV2`) are
25
25
  * collected in wire order -- a response may carry several verdicts, and the
@@ -31,7 +31,7 @@
31
31
  *
32
32
  * @spec RFC 5272, RFC 5273, RFC 5274, RFC 6402
33
33
  * @card
34
- * Decode RFC 5272 CMC Full PKI Requests and Responses inside CMS -- controls
34
+ * Decode RFC 5272 CMC Full PKI Requests and Responses inside CMS: controls
35
35
  * with raw values, tagged requests (PKCS#10 / CRMF / other), ordered status
36
36
  * verdicts with the RFC 6402 two-module OtherStatusInfo ambiguity resolved,
37
37
  * whole-message body-part identity, raw reqSequence bytes, fail-closed.
@@ -61,20 +61,20 @@ var OID_STATUS_INFO_V2 = O("id-cmc-statusInfoV2");
61
61
  var OID_RESPONSE_BODY = O("id-cmc-responseBody");
62
62
  var OID_RA_IDENTITY_WITNESS = O("id-cmc-raIdentityWitness");
63
63
 
64
- // BodyPartID ::= INTEGER (0..4294967295) -- RFC 5272 sec. 3.2.2.
64
+ // BodyPartID ::= INTEGER (0..4294967295), RFC 5272 sec. 3.2.2.
65
65
  var BODY_PART_MAX = 4294967295n;
66
66
 
67
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 rather
70
- // than folded into either.
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
71
  var STATUS_BY_VALUE = {
72
72
  0: "success", 2: "failed", 3: "pending", 4: "noSupport",
73
73
  5: "confirmRequired", 6: "popRequired", 7: "partial",
74
74
  };
75
75
 
76
- // CMCFailInfo ::= INTEGER { ... } -- RFC 5272 sec. 6.1.4. Values outside this set
77
- // are surfaced numerically rather than refused: sec. 6.1.4 reserves 1000..1999
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
78
  // for private extended reasons, so an unknown number is legal data.
79
79
  var FAIL_INFO_BY_VALUE = {
80
80
  0: "badAlg", 1: "badMessageCheck", 2: "badRequest", 3: "badTime", 4: "badCertId",
@@ -83,10 +83,10 @@ var FAIL_INFO_BY_VALUE = {
83
83
  13: "authDataFail",
84
84
  };
85
85
 
86
- // The CMS content types a Full PKI Request / Response may ride in -- RFC 5272
86
+ // The CMS content types a Full PKI Request / Response may ride in, per RFC 5272
87
87
  // sec. 3.2 ("encapsulated in either a SignedData or an AuthenticatedData") and
88
88
  // sec. 4.2, which says the same of the response.
89
- // The names are the OID REGISTRY's, read off `oid.name(...)` rather than the
89
+ // The names are the OID registry's, read off `oid.name(...)` and never taken from the
90
90
  // spec's prose: RFC 5652 calls the type AuthenticatedData, the registry row is
91
91
  // `authData`, and hard-coding the prose spelling would reject every conforming
92
92
  // AuthenticatedData response while looking correct.
@@ -124,12 +124,12 @@ function readBodyPartIdentity(node) {
124
124
  // ---- controls --------------------------------------------------------
125
125
 
126
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 rather than a fault.
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
131
  //
132
- // The placement rule is NOT checked here: it depends on which message the control
132
+ // The placement rule is not checked here: it depends on which message the control
133
133
  // sits in, which the enclosing walk knows and this shape does not.
134
134
  var TAGGED_ATTRIBUTE = schema.seq([
135
135
  schema.field("bodyPartID", schema.decode(readBodyPartIdentity)),
@@ -163,8 +163,8 @@ function assertControlPlacement(control, where) {
163
163
  // ---- status controls -------------------------------------------------
164
164
 
165
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 rather than "no path".
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
168
  function parseBodyPartReference(node) {
169
169
  if (node.tagClass === "universal" && node.tagNumber === TAGS.INTEGER) {
170
170
  return { bodyPartID: readBodyPartId(node), bodyPartPath: null };
@@ -189,7 +189,7 @@ function parseBodyPartReference(node) {
189
189
  *
190
190
  * universal INTEGER -> failInfo
191
191
  * context [1] -> extendedFailInfo (2008 module)
192
- * universal SEQUENCE -> disambiguate on the FIRST child's tag:
192
+ * universal SEQUENCE -> disambiguate on the first child's tag:
193
193
  * OCTET STRING -> pendInfo (PendInfo ::= SEQUENCE
194
194
  * { pendToken OCTET STRING, pendTime GeneralizedTime })
195
195
  * OBJECT IDENTIFIER -> extendedFailInfo
@@ -201,8 +201,8 @@ function parseBodyPartReference(node) {
201
201
  */
202
202
  function parseOtherStatusInfo(node, version) {
203
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
204
+ // gives the v1 otherInfo exactly two arms, `CHOICE { failInfo CMCFailInfo,
205
+ // pendInfo PendInfo }`, so accepting the third here would read a failure
206
206
  // verdict out of a v1 control that cannot legally express one, and the
207
207
  // disambiguation below would be answering a question v1 never asks.
208
208
  var extendedAllowed = version !== 1;
@@ -221,7 +221,7 @@ function parseOtherStatusInfo(node, version) {
221
221
  // unwrap. Both RFC 6402 modules are IMPLICIT: A.1 (rfc6402.txt:805) and A.2
222
222
  // (rfc6402.txt:1314) each open `DEFINITIONS IMPLICIT TAGS ::=`, and the
223
223
  // EXPLICIT-override rule does not apply here because the tagged type is a
224
- // plain SEQUENCE rather than a CHOICE or an open type. Reading this arm as
224
+ // plain SEQUENCE, not a CHOICE or an open type. Reading this arm as
225
225
  // EXPLICIT would reject every conforming 2008-module response.
226
226
  return { failInfo: null, failInfoName: null, pendInfo: null, extendedFailInfo: readExtendedFailInfo(node.children, "[1] extendedFailInfo") };
227
227
  }
@@ -230,8 +230,8 @@ function parseOtherStatusInfo(node, version) {
230
230
  if (!first) throw E("cmc/ambiguous-status-info", "an empty OtherStatusInfo SEQUENCE matches neither pendInfo nor extendedFailInfo");
231
231
  if (first.tagClass === "universal" && first.tagNumber === TAGS.OCTET_STRING) {
232
232
  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 rather than
234
- // accept either time form -- a UTCTime here is a different encoding, and
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
235
  // reading it anyway would let a two-digit year through the retry clock.
236
236
  var timeNode = node.children[1];
237
237
  if (timeNode.tagClass !== "universal" || timeNode.tagNumber !== TAGS.GENERALIZED_TIME) {
@@ -256,7 +256,7 @@ function parseOtherStatusInfo(node, version) {
256
256
  }
257
257
 
258
258
  // ExtendedFailInfo ::= SEQUENCE { failInfoOID OBJECT IDENTIFIER, failInfoValue ANY }
259
- // The OID is surfaced raw and NEVER mapped onto a CMCFailInfo: RFC 5272 sec.
259
+ // The OID is surfaced raw and never mapped onto a CMCFailInfo: RFC 5272 sec.
260
260
  // 6.1.1 makes internalCAError only a MAY for an unrecognized extended error, and
261
261
  // synthesizing it would report a reason the responder did not send.
262
262
  function readExtendedFailInfo(children, what) {
@@ -285,7 +285,7 @@ function parseStatusInfo(valueDer, version, bodyPartID) {
285
285
  var statusName = STATUS_BY_VALUE[statusNum];
286
286
  if (!statusName) {
287
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 rather than mapped.
288
+ // not a verdict in either direction, so it is refused and never mapped.
289
289
  throw E("cmc/bad-status", "unknown CMCStatus " + statusNum + " (1 is reserved; RFC 5272 sec. 6.1.3)");
290
290
  }
291
291
 
@@ -337,7 +337,7 @@ function parseStatusInfo(valueDer, version, bodyPartID) {
337
337
  // The cross-field coupling (RFC 5272 sec. 6.1.1 / 6.1.2): failInfo and
338
338
  // extendedFailInfo are "present only if cMCStatus contains the value failed",
339
339
  // and pendInfo "MUST be populated for a cMCStatus value of pending or partial".
340
- // A message whose status and detail disagree is refused rather than reconciled --
340
+ // A message whose status and detail disagree is refused, never reconciled:
341
341
  // the two halves would otherwise let a caller read a verdict neither field states.
342
342
  function _assertStatusCoherent(s) {
343
343
  var isFailed = s.status === "failed";
@@ -363,8 +363,8 @@ function _assertStatusCoherent(s) {
363
363
  // orm [2] SEQUENCE { bodyPartID, requestMessageType,
364
364
  // requestMessageValue } }
365
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
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
368
  // (and invalid) message, which is what C5 pins.
369
369
  // An IMPLICIT context-tagged constructed node re-encoded under the universal
370
370
  // SEQUENCE tag it stands in for. IMPLICIT tagging REPLACES the tag and leaves the
@@ -402,8 +402,8 @@ function parseTaggedRequest(node) {
402
402
  // bodyPartID field of the other objects", and sec. 6.5.2 repeats it
403
403
  // ("... either the bodyPartID of a TaggedCertificationRequest (PKCS #10) or
404
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
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
407
  // exempt this arm from it.
408
408
  //
409
409
  // CertReqMsg ::= SEQUENCE { certReq CertRequest, popo OPTIONAL, regInfo OPTIONAL }
@@ -445,7 +445,7 @@ function parseTaggedRequest(node) {
445
445
  // ---- body-part identity ----------------------------------------------
446
446
 
447
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
448
+ // PKIData or PKIResponse." The scope is the whole message: a checker that ran
449
449
  // per-sequence would accept a control and a request that collide, which is
450
450
  // exactly the shape B2 pins.
451
451
  function assertUniqueBodyPartIds(ids) {
@@ -463,8 +463,8 @@ function assertUniqueBodyPartIds(ids) {
463
463
  // ---- the two message bodies ------------------------------------------
464
464
 
465
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
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
468
  // fields (whole-message body-part uniqueness, control placement, the status
469
469
  // cross-checks) run in the build / the caller, which is where they can see
470
470
  // everything they need.
@@ -486,9 +486,9 @@ var REQ_SEQUENCE = schema.seqOf(schema.decode(parseTaggedRequest),
486
486
 
487
487
  // TaggedContentInfo ::= SEQUENCE { bodyPartID, contentInfo } (RFC 5272 sec.
488
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
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
492
  // "each element of a PKIData or PKIResponse". Decoding just the identifier is
493
493
  // what lets that rule cover them without this layer claiming to understand the
494
494
  // payload.
@@ -498,8 +498,8 @@ var TAGGED_CONTENT_INFO = schema.seq([
498
498
  ], {
499
499
  assert: "sequence", arity: { exact: 2 }, code: "cmc/bad-cms-sequence", what: "a TaggedContentInfo",
500
500
  build: function (m) {
501
- // The payload stays RAW -- this layer does not decode a content type it may
502
- // not know -- but it must still BE a ContentInfo: SEQUENCE { contentType
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
503
  // OBJECT IDENTIFIER, content [0] EXPLICIT ANY OPTIONAL } (RFC 5652 sec. 3).
504
504
  // Surfacing an INTEGER, or anything else that cannot be one, as a content
505
505
  // info would hand the caller a "CMS message" no CMS reader will accept, which
@@ -511,9 +511,9 @@ var TAGGED_CONTENT_INFO = schema.seq([
511
511
  throw E("cmc/bad-cms-sequence",
512
512
  "a TaggedContentInfo carries a CMS ContentInfo, which leads with its contentType OBJECT IDENTIFIER (RFC 5652 sec. 3)");
513
513
  }
514
- // READ the contentType rather than inspecting 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
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
517
  // toolkit's own CMS parser refuses them, so accepting them here would let the
518
518
  // builder sign a "CMS message" pki.schema.cms.parse will not read back. The
519
519
  // VALUE is still not interpreted: this layer only establishes that there is a
@@ -523,10 +523,10 @@ var TAGGED_CONTENT_INFO = schema.seq([
523
523
  throw E("cmc/bad-cms-sequence",
524
524
  "a TaggedContentInfo carries a CMS ContentInfo, whose contentType must be a readable OBJECT IDENTIFIER (RFC 5652 sec. 3)", e);
525
525
  }
526
- // The WHOLE envelope, not just its first field: content is `[0] EXPLICIT ANY
526
+ // The whole envelope, not just its first field: content is `[0] EXPLICIT ANY
527
527
  // DEFINED BY contentType OPTIONAL`, so at most one more element and it is that
528
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
529
+ // a ContentInfo any CMS reader will take, and stopping at the leading OID
530
530
  // would surface it as one.
531
531
  if (kids.length > 2) {
532
532
  throw E("cmc/bad-cms-sequence",
@@ -539,9 +539,9 @@ var TAGGED_CONTENT_INFO = schema.seq([
539
539
  throw E("cmc/bad-cms-sequence",
540
540
  "a CMS ContentInfo's second field is the [0] EXPLICIT content (RFC 5652 sec. 3)");
541
541
  }
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
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
545
  // builder's readback would pass a message its own CMS reader will not accept.
546
546
  if (!content.children || content.children.length !== 1) {
547
547
  throw E("cmc/bad-cms-sequence",
@@ -569,7 +569,7 @@ var OTHER_MSG = schema.seq([
569
569
  });
570
570
 
571
571
  // PKIData ::= SEQUENCE { controlSequence, reqSequence, cmsSequence,
572
- // otherMsgSequence } -- RFC 5272 sec. 3.2.1. All FOUR are mandatory though each
572
+ // otherMsgSequence }, RFC 5272 sec. 3.2.1. All four are mandatory though each
573
573
  // may be empty, so `arity: { exact: 4 }` is the rule, not a convenience.
574
574
  var PKI_DATA = schema.seq([
575
575
  schema.field("controlSequence", CONTROL_SEQUENCE),
@@ -591,7 +591,7 @@ var PKI_DATA = schema.seq([
591
591
  // The raw reqSequence TLV, tag and length included: the Identity Proof V2
592
592
  // witness is computed over exactly these bytes "encoded exactly as it
593
593
  // appears in the Full PKI Request" (RFC 5272 sec. 6.2.1), so it is taken
594
- // off the matched NODE rather than re-encoded from the decoded requests.
594
+ // off the matched node, never re-encoded from the decoded requests.
595
595
  reqSequenceBytes: m.fields.reqSequence.node.bytes,
596
596
  };
597
597
  },
@@ -621,7 +621,7 @@ var PKI_RESPONSE = schema.seq([
621
621
  });
622
622
 
623
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
624
+ // order. Absence is not an error: RFC 5272 sec. 6.1.2 says "If no status exists
625
625
  // for a Simple or Full PKI Request, then the value of success is assumed", so a
626
626
  // response with no status control is a successful one.
627
627
  function _collectStatuses(controls) {
@@ -648,9 +648,9 @@ function _finishBody(body, where) {
648
648
  return c.attrType !== OID_STATUS_INFO && c.attrType !== OID_STATUS_INFO_V2 && c.attrName === null;
649
649
  });
650
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
651
+ // PKIResponse", and four element kinds carry an identity. Enumerated here in
652
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
653
+ // rest: controls (sec. 3.2.1.1), requests (sec. 3.2.1.2, the tcr/orm
654
654
  // bodyPartID and the crm arm's certReqId), content infos (sec. 3.2.1.3) and
655
655
  // other messages (sec. 3.2.1.4).
656
656
  var ids = [];
@@ -699,10 +699,10 @@ function parsePkiData(input) {
699
699
  * @spec RFC 5272 sec. 4.2.1
700
700
  * @related pki.schema.cmc.parse, pki.schema.cmc.parsePkiData
701
701
  *
702
- * Decode a bare `PKIResponse` body. A PKIResponse has THREE sequences -- there is
703
- * no `reqSequence` -- and all three are mandatory though each may be empty. The
702
+ * Decode a bare `PKIResponse` body. A PKIResponse has three sequences (there is
703
+ * no `reqSequence`) and all three are mandatory though each may be empty. The
704
704
  * status controls are collected in wire order; a response may legitimately carry
705
- * several, and carrying NONE means success (RFC 5272 sec. 6.1.2).
705
+ * several, and carrying none means success (RFC 5272 sec. 6.1.2).
706
706
  *
707
707
  * @example
708
708
  * var b = pki.asn1.build;
@@ -730,9 +730,9 @@ function parsePkiResponse(input) {
730
730
  * is DER, a PEM `CMS` block, or an already-parsed `pki.schema.cms` object. The CMS
731
731
  * layer is peeled, the encapsulated content type selects the body
732
732
  * (`id-cct-PKIData` -> a request, `id-cct-PKIResponse` -> a response), and any
733
- * other content type is refused as not-CMC rather than guessed at.
733
+ * other content type is refused as not-CMC, never guessed at.
734
734
  *
735
- * The parsed CMS is returned on `cms` so a caller can verify the signature -- this
735
+ * The parsed CMS is returned on `cms` so a caller can verify the signature; this
736
736
  * decoder never does: reading a message and trusting it are separate steps, and
737
737
  * RFC 5272 sec. 3.2.1.3.4 makes the signature check the caller's obligation.
738
738
  *
package/lib/schema-cmp.js CHANGED
@@ -10,9 +10,9 @@
10
10
  *
11
11
  * @intro
12
12
  * Certificate Management Protocol handling per RFC 9810 (which obsoletes
13
- * RFC 4210 and RFC 9480). `parse` decodes a `PKIMessage` -- the protected
13
+ * RFC 4210 and RFC 9480). `parse` decodes a `PKIMessage`, the protected
14
14
  * transport envelope CMP enrollment, revocation, confirmation, and support
15
- * exchanges ride -- into its header (version, sender / recipient
15
+ * exchanges ride, into its header (version, sender / recipient
16
16
  * GeneralNames including the NULL-DN anonymous form, nonces, transaction
17
17
  * id, free text, general info), its body, its protection bits, and its
18
18
  * extra certificates.
@@ -29,7 +29,7 @@
29
29
  * or signature itself. DER-only, fail-closed.
30
30
  *
31
31
  * @card
32
- * Parse DER / PEM RFC 9810 CMP PKIMessages -- header, 27-arm body (requests
32
+ * Parse DER / PEM RFC 9810 CMP PKIMessages: header, 27-arm body (requests
33
33
  * via CRMF, encrypted certs via CMS, the rest structural or raw),
34
34
  * protection inputs surfaced byte-exact for external verification,
35
35
  * fail-closed.
@@ -67,7 +67,7 @@ var PKI_FREE_TEXT = schema.seqOf(UTF8_TEXT, {
67
67
  build: function (m) { return m.items.map(function (it) { return it.value; }); },
68
68
  });
69
69
 
70
- // PKIStatus ::= INTEGER {0..6} (sec. 5.2.3) -- a value whitelist, surfaced named.
70
+ // PKIStatus ::= INTEGER {0..6} (sec. 5.2.3): a value whitelist, surfaced named.
71
71
  var PKI_STATUS_NAMES = ["accepted", "grantedWithMods", "rejection", "waiting",
72
72
  "revocationWarning", "revocationNotification", "keyUpdateWarning"];
73
73
  var PKI_STATUS = schema.decode(function (n, ctx) {
@@ -97,17 +97,17 @@ var PKI_FAILURE_INFO = schema.decode(function (n, ctx) {
97
97
  return { bits: bits, raw: bs };
98
98
  });
99
99
 
100
- // PollRep checkAfter is a delay in seconds -- negative poisons scheduling, and
100
+ // PollRep checkAfter is a delay in seconds; a negative one poisons scheduling, and
101
101
  // the value surfaces as an exact number or not at all.
102
102
  var CHECK_AFTER = schema.decode(function (n, ctx) {
103
103
  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
104
  });
105
105
 
106
- // A raw certificate / CRL / publication-info element -- surfaced byte-exact for
106
+ // A raw certificate / CRL / publication-info element, surfaced byte-exact for
107
107
  // downstream parsing, but structurally a universal SEQUENCE: a CMPCertificate
108
108
  // is a Certificate, and CertificateList / PKIPublicationInfo are SEQUENCEs, so
109
109
  // a primitive (an INTEGER) or wrong-tag element is not a valid structure and
110
- // rejects rather than handing arbitrary bytes to certificate processing. The
110
+ // rejects, never handing arbitrary bytes to certificate processing. The
111
111
  // `code` names the containing structure (a shared leaf cannot know its context).
112
112
  function rawSequence(code) {
113
113
  return pkix.rawNonEmptySequence(NS, { code: code, message: "expected a non-empty universal SEQUENCE (Certificate / CertificateList / PKIPublicationInfo)" });
@@ -140,10 +140,10 @@ var INFO_TYPE_AND_VALUE = schema.seq([
140
140
  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
141
  }
142
142
  if (valueNode !== null) {
143
- // A recognized id-it value is validated by CONTENT, not just tag: run the
143
+ // A recognized id-it value is validated by content, not just tag: run the
144
144
  // strict typed reader so a well-tagged but malformed payload (a non-empty
145
145
  // NULL, a GeneralizedTime carrying garbage, an invalid-UTF-8 string)
146
- // rejects rather than being surfaced as valid CMP.
146
+ // rejects and is never surfaced as valid CMP.
147
147
  if (t === OID_IMPLICIT_CONFIRM) {
148
148
  if (!(valueNode.tagClass === "universal" && valueNode.tagNumber === TAGS.NULL)) {
149
149
  throw ctx.E("cmp/bad-info-value", "an implicitConfirm value must be NULL (RFC 9810 sec. 5.1.1.1)");
@@ -276,14 +276,14 @@ var CERT_STATUS = schema.seq([
276
276
  },
277
277
  });
278
278
 
279
- // CertConfirmContent ::= SEQUENCE OF CertStatus -- an EMPTY sequence is legal
279
+ // CertConfirmContent ::= SEQUENCE OF CertStatus, where an empty sequence is legal
280
280
  // (reject-all, sec. 5.3.18), so no SIZE floor.
281
281
  var CERT_CONFIRM_CONTENT = schema.seqOf(CERT_STATUS, {
282
282
  code: "cmp/bad-cert-status", what: "CertConfirmContent",
283
283
  build: function (m) { return m.items.map(function (it) { return it.value.result; }); },
284
284
  });
285
285
 
286
- // GenMsgContent / GenRepContent ::= SEQUENCE OF InfoTypeAndValue -- no SIZE
286
+ // GenMsgContent / GenRepContent ::= SEQUENCE OF InfoTypeAndValue, with no SIZE
287
287
  // bound, empty legal (sec. 5.3.19/.20).
288
288
  var GEN_MSG_CONTENT = schema.seqOf(INFO_TYPE_AND_VALUE, {
289
289
  code: "cmp/bad-info-type-and-value", what: "GenMsgContent",
@@ -291,7 +291,7 @@ var GEN_MSG_CONTENT = schema.seqOf(INFO_TYPE_AND_VALUE, {
291
291
  });
292
292
 
293
293
  // RevDetails ::= SEQUENCE { certDetails CertTemplate, crlEntryDetails
294
- // Extensions OPTIONAL } (sec. 5.3.9) -- the CertTemplate interior (an IMPLICIT
294
+ // Extensions OPTIONAL } (sec. 5.3.9). The CertTemplate interior (an IMPLICIT
295
295
  // TAGS module) is owned by the CRMF parser and walked NS-bound there.
296
296
  var CERT_TEMPLATE_LEAF = schema.decode(function (n) { return crmf.walkCertTemplate(n); });
297
297
  var REV_DETAILS = schema.seq([
@@ -353,20 +353,20 @@ var REV_REP_CONTENT = schema.seq([
353
353
  // EncryptedKey ::= CHOICE { encryptedValue EncryptedValue (deprecated),
354
354
  // envelopedData [0] EnvelopedData } (sec. 5.2.2). EncryptedKey is imported from
355
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, no inner wrapper. Retag it to
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
358
  // the universal SEQUENCE the CMS walker expects, exactly as the sibling CRMF
359
359
  // `encryptedKey [4] EnvelopedData` POP arm does (schema-crmf.js). The
360
- // deprecated encryptedValue arm surfaces RAW -- never field-walked, so nothing
360
+ // deprecated encryptedValue arm surfaces raw and is never field-walked, so nothing
361
361
  // dereferences its optional interior (absent algorithm parameters crash
362
362
  // consumers that walk it blindly).
363
363
  var ENCRYPTED_KEY = schema.choice([
364
364
  { when: { tagClass: "universal", tagNumber: TAGS.SEQUENCE },
365
365
  schema: schema.decode(function (n, ctx) {
366
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 rather than surface a
369
- // degenerate structure as encrypted certificate/key bytes (the same
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
370
  // non-empty rule every raw-SEQUENCE surface in this module applies).
371
371
  if (!(n.children && n.children.length >= 1)) {
372
372
  throw ctx.E("cmp/bad-cert-response", "an EncryptedValue must be a non-empty SEQUENCE (RFC 4211 sec. 2)");
@@ -391,9 +391,9 @@ var ENCRYPTED_KEY = schema.choice([
391
391
  if (env.recipientInfos.length !== 1) {
392
392
  throw ctx.E("cmp/bad-cert-response", "an EncryptedKey EnvelopedData must contain exactly one RecipientInfo (RFC 9810 sec. 5.2.2)");
393
393
  }
394
- // The ciphertext IS the encrypted certificate / private key here, so an
395
- // EnvelopedData with no ciphertext to decrypt -- absent (detached, CMS
396
- // permits it) OR present-but-empty -- must reject (RFC 9810 sec. 5.2.2/sec. 5.3.4;
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
397
  // the same rule the CRMF encryptedKey POP arm enforces).
398
398
  var ct = env.encryptedContentInfo.encryptedContent;
399
399
  if (ct === null || ct.length === 0) {
@@ -456,9 +456,9 @@ var CERT_RESPONSE = schema.seq([
456
456
  throw ctx.E("cmp/bad-cert-response",
457
457
  "a CertResponse must not carry both failInfo and certifiedKeyPair (RFC 9810 sec. 5.3.4)");
458
458
  }
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
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
462
  // certificate under it is a malformed response even when no explicit failInfo
463
463
  // bit is set (a rejection is commonly signalled by status alone). Keying the
464
464
  // rule off failInfo presence alone would let a bare-rejection status ship a
@@ -477,8 +477,8 @@ var CERT_RESPONSE = schema.seq([
477
477
  });
478
478
 
479
479
  // CertRepMessage ::= SEQUENCE { caPubs [1] OPTIONAL, response SEQUENCE OF
480
- // CertResponse } (sec. 5.3.4) -- the optional precedes the required field (the
481
- // x509-version shape). caPubs surface raw: the parser confers NO trust.
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
482
  var CERT_REP_MESSAGE = schema.seq([
483
483
  schema.optional("caPubs", schema.seqOf(rawSequence("cmp/bad-cert-rep"), {
484
484
  min: 1, code: "cmp/bad-cert-rep", what: "caPubs",
@@ -502,7 +502,7 @@ var CERT_REP_MESSAGE = schema.seq([
502
502
  // Certificate OPTIONAL, caCerts [1] SEQUENCE OF Certificate OPTIONAL,
503
503
  // keyPairHist [2] SEQUENCE OF CertifiedKeyPair OPTIONAL } (sec. 5.3.8). The
504
504
  // keyPairHist CertifiedKeyPairs can carry the same EnvelopedData form as the
505
- // enrollment responses, so krp is decoded (not surfaced raw) -- the operator sees
505
+ // enrollment responses, so krp is decoded (not surfaced raw) and the operator sees
506
506
  // the status / key history and the cross-field EnvelopedData version check runs.
507
507
  var KEY_REC_REP_CONTENT = schema.seq([
508
508
  schema.field("status", PKI_STATUS_INFO),
@@ -579,8 +579,8 @@ var DECODED_ARMS = {
579
579
  };
580
580
 
581
581
  // The open-CHOICE dispatch: tag -> arm name; walk where a schema exists;
582
- // surface every other defined arm raw as { arm, tag, bytes } -- `decoded` is
583
- // ABSENT (not null) on raw arms, so its presence discriminates decoded-empty
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
584
  // (pkiconf decodes to null) from recognized-undecoded. `nested` [20] is never
585
585
  // auto-recursed: a self-nesting tower amplifies per-level walk products, so
586
586
  // the operator re-feeds its bytes to parse explicitly.
@@ -625,7 +625,7 @@ var BODY = schema.decode(function (n, ctx) {
625
625
 
626
626
  // ---- the message envelope -----------------------------------------------------
627
627
 
628
- // PKIProtection ::= BIT STRING -- raw bits for the external verifier. Every
628
+ // PKIProtection ::= BIT STRING: raw bits for the external verifier. Every
629
629
  // RFC 9481 MSG_SIG_ALG / MSG_MAC_ALG output is an octet string, so the BIT
630
630
  // STRING must be octet-aligned; with no in-tree CMP verify layer this is
631
631
  // enforced at parse (the posture the OCSP signature shares), fail-closed.
@@ -644,7 +644,7 @@ var PROTECTION = schema.decode(function (n, ctx) {
644
644
  // span structures: protection presence <=> protectionAlg presence (sec. 5.1.1,
645
645
  // both directions), and a certConf hashAlg requires pvno cmp2021(3)
646
646
  // (sec. 5.3.18). headerBytes / bodyBytes are the exact wire slices protection is
647
- // computed over (as DER-SEQUENCE(headerBytes || bodyBytes)) -- surfaced raw,
647
+ // computed over (as DER-SEQUENCE(headerBytes || bodyBytes)), surfaced raw and
648
648
  // never re-encoded.
649
649
  var PKI_MESSAGE = schema.seq([
650
650
  schema.field("header", PKI_HEADER),
@@ -674,7 +674,7 @@ var PKI_MESSAGE = schema.seq([
674
674
  }
675
675
  }
676
676
  }
677
- // RFC 9810 sec. 5.2.2 / sec. 7 -- EnvelopedData is cmp2021(3) syntax: a response
677
+ // RFC 9810 sec. 5.2.2 / sec. 7: EnvelopedData is cmp2021(3) syntax, so a response
678
678
  // carrying it (an encryptedCert or a privateKey in the envelopedData form)
679
679
  // under pvno < 3 is a version mismatch, the same version gate the certConf
680
680
  // hashAlg rule applies. The deprecated EncryptedValue form is the pre-2021
@@ -701,10 +701,10 @@ var PKI_MESSAGE = schema.seq([
701
701
  // CertRepMessage syntax "with the restriction that no encrypted private key
702
702
  // can be sent": cross-certification certifies an existing CA's public key,
703
703
  // so there is no key generation and CertifiedKeyPair.privateKey has no
704
- // meaning. Reject a ccp that carries one rather than surface the key
705
- // material; the field stays legal in the enrollment responses (ip/cp/kup).
704
+ // meaning. Reject a ccp that carries one; never surface the key
705
+ // material. The field stays legal in the enrollment responses (ip/cp/kup).
706
706
  if (body.arm === "ccp" && body.decoded && body.decoded.response) {
707
- // RFC 9810 Appendix D.6 -- a one-way cross-certification response carries
707
+ // RFC 9810 Appendix D.6: a one-way cross-certification response carries
708
708
  // exactly one CertResponse (multiple cross-certificates go in separate
709
709
  // PKIMessages), the mirror of the ccr one-CertReqMsg rule.
710
710
  if (body.decoded.response.length !== 1) {
@@ -717,10 +717,10 @@ var PKI_MESSAGE = schema.seq([
717
717
  }
718
718
  }
719
719
  }
720
- // RFC 9810 sec. 5.3.11 -- a cross-certification request (ccr) MUST NOT send the
720
+ // RFC 9810 sec. 5.3.11: a cross-certification request (ccr) MUST NOT send the
721
721
  // private key to the responding CA (the requesting CA generates and holds
722
- // it). The private-key-carrying POP choices -- encryptedKey (cmp2021) and the
723
- // deprecated thisMessage (cmp2000) -- are therefore forbidden in a ccr; the
722
+ // it). The private-key-carrying POP choices, encryptedKey (cmp2021) and the
723
+ // deprecated thisMessage (cmp2000), are therefore forbidden in a ccr; the
724
724
  // MAC (dhMAC / agreeMAC) and indirect (subsequentMessage) methods carry no
725
725
  // key. Checked before the version gate so a ccr always gets the ccr verdict.
726
726
  if (body.arm === "ccr" && body.decoded && body.decoded.messages) {
@@ -863,22 +863,22 @@ var PKI_MESSAGE = schema.seq([
863
863
  * structurally; `pkiconf` decodes to `null`; every other defined arm --
864
864
  * `p10cr` (feed `body.bytes` to `pki.schema.csr.parse`), the
865
865
  * challenge-response and announcement arms, and `nested` (never
866
- * auto-recursed) -- surfaces raw with `decoded` absent. `certReqId` values
866
+ * auto-recursed) surfaces raw with `decoded` absent. `certReqId` values
867
867
  * are BigInt and accept the protocol's -1 sentinel.
868
868
  *
869
869
  * Protection is surfaced, not verified: `protection` carries the raw,
870
- * octet-aligned BIT STRING (unused bits are rejected at parse -- every
870
+ * octet-aligned BIT STRING (unused bits are rejected at parse, since every
871
871
  * RFC 9481 protection algorithm emits whole octets), and the MAC or
872
872
  * signature is computed over the DER of the virtual
873
- * `ProtectedPart ::= SEQUENCE { header, body }` -- reconstruct it as a DER
873
+ * `ProtectedPart ::= SEQUENCE { header, body }`, which you reconstruct as a DER
874
874
  * SEQUENCE wrapping exactly `headerBytes || bodyBytes`. `extraCerts` are
875
- * raw DER certificates and are NOT covered by protection.
875
+ * raw DER certificates and are not covered by protection.
876
876
  *
877
877
  * Throws `CmpError` when the bytes are not a well-formed PKIMessage, and
878
878
  * `Asn1Error` when the underlying DER is malformed. The request-arm interiors
879
879
  * (`ir` / `cr` / `kur` / `krr` / `ccr`, and an `rr` entry's `certDetails`) are
880
880
  * walked by the CRMF parser, so a malformed interior throws `CrmfError` with a
881
- * `crmf/*` code -- all `PkiError` subclasses.
881
+ * `crmf/*` code; all are `PkiError` subclasses.
882
882
  *
883
883
  * @example
884
884
  * var pair = await pki.key.generate("Ed25519");