@blamejs/pki 0.6.14 → 0.6.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/CHANGELOG.md +27 -1
  2. package/lib/acme.js +59 -815
  3. package/lib/asn1-der.js +7 -245
  4. package/lib/attrcert-sign.js +12 -260
  5. package/lib/attrcert-verify.js +1 -7
  6. package/lib/byte-reader.js +0 -8
  7. package/lib/byte-writer.js +0 -11
  8. package/lib/cbor-det.js +0 -54
  9. package/lib/cmc-build.js +15 -357
  10. package/lib/cmc-verify.js +6 -239
  11. package/lib/cmp-build.js +41 -317
  12. package/lib/cmp-session.js +73 -760
  13. package/lib/cmp-verify.js +32 -488
  14. package/lib/cms-compress.js +3 -32
  15. package/lib/cms-decrypt.js +29 -294
  16. package/lib/cms-encrypt.js +14 -234
  17. package/lib/cms-sign.js +29 -324
  18. package/lib/cms-verify.js +9 -500
  19. package/lib/composite-kem.js +2 -102
  20. package/lib/composite-sig.js +1 -77
  21. package/lib/constants.js +0 -249
  22. package/lib/crl-sign.js +9 -237
  23. package/lib/crl-verify.js +1 -10
  24. package/lib/crmf-sign.js +19 -198
  25. package/lib/crmf-verify.js +1 -12
  26. package/lib/csr-sign.js +3 -34
  27. package/lib/csr-verify.js +1 -12
  28. package/lib/ct.js +28 -253
  29. package/lib/edwards-point.js +10 -44
  30. package/lib/est.js +28 -764
  31. package/lib/framework-error.js +4 -182
  32. package/lib/guard-all.js +1 -58
  33. package/lib/guard-async.js +1 -36
  34. package/lib/guard-bytes.js +6 -650
  35. package/lib/guard-compress.js +5 -102
  36. package/lib/guard-crypto.js +1 -40
  37. package/lib/guard-der.js +2 -93
  38. package/lib/guard-encoding.js +2 -60
  39. package/lib/guard-header.js +1 -36
  40. package/lib/guard-identifier.js +7 -531
  41. package/lib/guard-intrinsic.js +1 -150
  42. package/lib/guard-json.js +10 -73
  43. package/lib/guard-limits.js +1 -77
  44. package/lib/guard-list.js +1 -49
  45. package/lib/guard-name.js +3 -209
  46. package/lib/guard-parsed.js +7 -335
  47. package/lib/guard-range.js +1 -71
  48. package/lib/guard-secret.js +1 -102
  49. package/lib/guard-text.js +1 -64
  50. package/lib/guard-time.js +1 -97
  51. package/lib/hpke.js +3 -105
  52. package/lib/http-digest.js +14 -142
  53. package/lib/http-retry-after.js +1 -47
  54. package/lib/http-transport.js +21 -131
  55. package/lib/inspect.js +30 -284
  56. package/lib/ip-utils.js +6 -47
  57. package/lib/jose.js +7 -142
  58. package/lib/key.js +2 -67
  59. package/lib/lint.js +9 -194
  60. package/lib/merkle.js +1 -27
  61. package/lib/mime.js +9 -82
  62. package/lib/ocsp-request-verify.js +1 -14
  63. package/lib/ocsp-verify.js +1 -82
  64. package/lib/ocsp.js +11 -169
  65. package/lib/oid.js +5 -337
  66. package/lib/path-validate.js +103 -1492
  67. package/lib/pbes2.js +2 -89
  68. package/lib/pkcs12-build.js +31 -379
  69. package/lib/pki-build.js +64 -290
  70. package/lib/rc2.js +2 -18
  71. package/lib/rfc3339.js +4 -27
  72. package/lib/scep.js +140 -286
  73. package/lib/schema-all.js +0 -122
  74. package/lib/schema-attrcert.js +4 -146
  75. package/lib/schema-c509.js +153 -802
  76. package/lib/schema-cmc.js +5 -220
  77. package/lib/schema-cmp.js +2 -223
  78. package/lib/schema-cms.js +13 -427
  79. package/lib/schema-crl.js +5 -68
  80. package/lib/schema-crmf.js +6 -167
  81. package/lib/schema-csr.js +1 -54
  82. package/lib/schema-csrattrs.js +2 -87
  83. package/lib/schema-engine.js +0 -152
  84. package/lib/schema-ocsp.js +0 -117
  85. package/lib/schema-pkcs12.js +2 -93
  86. package/lib/schema-pkcs8.js +3 -35
  87. package/lib/schema-pkix.js +24 -655
  88. package/lib/schema-smime.js +0 -54
  89. package/lib/schema-tsp.js +3 -99
  90. package/lib/schema-x509.js +4 -63
  91. package/lib/shbs.js +11 -95
  92. package/lib/sign-scheme.js +2 -97
  93. package/lib/sigstore.js +9 -169
  94. package/lib/sleep.js +2 -8
  95. package/lib/smime.js +15 -408
  96. package/lib/tls-cert-compress.js +0 -62
  97. package/lib/trust.js +19 -185
  98. package/lib/tsp-sign.js +16 -270
  99. package/lib/validator-all.js +1 -30
  100. package/lib/validator-attcert.js +2 -46
  101. package/lib/validator-cose.js +2 -153
  102. package/lib/validator-keydesc.js +1 -37
  103. package/lib/validator-sig.js +1 -46
  104. package/lib/validator-tls.js +1 -88
  105. package/lib/validator-tpm.js +19 -122
  106. package/lib/verify-seam.js +1 -24
  107. package/lib/webauthn-mds.js +3 -400
  108. package/lib/webauthn.js +12 -833
  109. package/lib/webcrypto.js +5 -485
  110. package/lib/x509-sign.js +4 -108
  111. package/package.json +1 -1
  112. package/sbom.cdx.json +6 -6
package/lib/schema-csr.js CHANGED
@@ -38,36 +38,15 @@ var frameworkError = require("./framework-error");
38
38
  var CsrError = frameworkError.CsrError;
39
39
  var PemError = frameworkError.PemError;
40
40
 
41
- // The csr error namespace the schema engine walks under. Shared PKIX sub-schemas
42
- // are instantiated here under csr/* so a structural fault reports a csr code.
43
41
  var NS = pkix.makeNS("csr", CsrError, oid);
44
42
 
45
43
  var NAME = pkix.name(NS);
46
44
  var SPKI = pkix.spki(NS);
47
45
 
48
- // CertificationRequestInfo version ::= INTEGER { v1(0) } (RFC 2986 sec. 4.1). A bare
49
- // mandatory INTEGER whose one legal value is 0, the inverse of the cert/CRL
50
- // readers, which reject 0 as the DER-forbidden default. Surface v1 as 1. A
51
- // cert-shaped [0] EXPLICIT wrapper at this position makes asn1.read.integer throw
52
- // asn1/* (fail-closed).
53
46
  var CSR_VERSION = pkix.versionReader(NS, { "0": 1 });
54
47
 
55
- // Attribute ::= SEQUENCE { type OID, values SET OF ANY }, the shared pkix factory
56
- // under the csr NS (values raw DER, SET SIZE(1..MAX), no uniqueness). The same
57
- // factory serves the PKCS#8 private-key attributes.
58
48
  var ATTRIBUTE = pkix.attribute(NS);
59
49
 
60
- // The two RECOGNIZED PKCS#9 request attributes get their value syntax enforced
61
- // (RFC 2985 sec. 5.4.1 challengePassword / sec. 5.4.2 extensionRequest): both
62
- // are SINGLE VALUE TRUE, extensionRequest carries one Extensions value
63
- // (RFC 5280 sec. 4.1, SIZE(1..MAX)) and challengePassword one DirectoryString
64
- // of 1..255 characters. A recognized type with a malformed, multi-valued, or
65
- // wrong-syntax value fails closed (csr/bad-attribute-value) -- a CA pipeline
66
- // reading requested extensions off csr.attributes must never receive garbage
67
- // under the extensionRequest OID. An UNRECOGNIZED attribute type stays opaque
68
- // raw DER and never fails the parse, and duplicate attribute TYPES stay legal
69
- // (RFC 2986 puts no uniqueness on the attributes SET). Registry rows keyed by
70
- // the stable dotted OID, not a switch; values are still surfaced raw.
71
50
  var EXTENSIONS = pkix.extensions(NS);
72
51
  var DIRECTORY_STRING_TAGS = [
73
52
  asn1.TAGS.UTF8_STRING, asn1.TAGS.PRINTABLE_STRING, asn1.TAGS.TELETEX_STRING,
@@ -75,10 +54,6 @@ var DIRECTORY_STRING_TAGS = [
75
54
  ];
76
55
  var RECOGNIZED_ATTRIBUTE_VALUE = {};
77
56
  RECOGNIZED_ATTRIBUTE_VALUE[oid.byName("extensionRequest")] = function (node, ctx) {
78
- // Surface the requested extensions decoded (same {oid,name,critical,value}
79
- // shape as a certificate's extensions) so a CA pipeline, and the EST
80
- // re-enroll guard, read them off the attribute instead of re-walking the
81
- // raw Extensions bytes. Returned as an enrichment merged onto the attribute.
82
57
  try { return { extensions: schema.walk(EXTENSIONS, node, ctx).result }; }
83
58
  catch (e) {
84
59
  throw ctx.E("csr/bad-attribute-value",
@@ -97,11 +72,6 @@ RECOGNIZED_ATTRIBUTE_VALUE[oid.byName("challengePassword")] = function (node, ct
97
72
  }
98
73
  };
99
74
 
100
- // CertificationRequestInfo ::= SEQUENCE { version, subject Name,
101
- // subjectPKInfo SubjectPublicKeyInfo, attributes [0] IMPLICIT SET OF Attribute }.
102
- // attributes is a REQUIRED field (a CRI omitting [0] is a missing-required-field
103
- // fault, not silently accepted) modeled as an IMPLICIT [0] SET OF with min:0 (an
104
- // empty attributes SET is legal). subject MAY be empty, so there is no non-empty-DN guard.
105
75
  var CERTIFICATION_REQUEST_INFO = schema.seq([
106
76
  schema.field("version", CSR_VERSION),
107
77
  schema.field("subject", NAME),
@@ -115,7 +85,6 @@ var CERTIFICATION_REQUEST_INFO = schema.seq([
115
85
  var checkValue = RECOGNIZED_ATTRIBUTE_VALUE[a.type];
116
86
  if (checkValue) {
117
87
  var valueItems = it.value.fields.values.value.items;
118
- // Both recognized PKCS#9 types are SINGLE VALUE TRUE (RFC 2985 sec. 5.4).
119
88
  if (valueItems.length !== 1) {
120
89
  throw ctx.E("csr/bad-attribute-value", (a.name || a.type) + " is a SINGLE VALUE attribute (RFC 2985 sec. 5.4)");
121
90
  }
@@ -126,19 +95,13 @@ var CERTIFICATION_REQUEST_INFO = schema.seq([
126
95
  });
127
96
  return {
128
97
  version: m.fields.version.value,
129
- subject: m.fields.subject.value.result, // Name is a seqOf -> field.value is the match; .result is the {rdns, dn} build
98
+ subject: m.fields.subject.value.result,
130
99
  subjectPublicKeyInfo: m.fields.subjectPKInfo.value.result,
131
100
  attributes: attributes,
132
101
  };
133
102
  },
134
103
  });
135
104
 
136
- // CertificationRequest ::= SEQUENCE { certificationRequestInfo, signatureAlgorithm,
137
- // signature BIT STRING }, the shared SIGNED envelope. It diverges from the
138
- // cert/CRL builders by omitting the outer-vs-inner signatureAlgorithm agreement
139
- // check (the CRI has no inner signature AlgorithmIdentifier) and the
140
- // non-empty-subject guard (a CSR subject MAY be empty). The omission is
141
- // structural: this build simply never references the agreement bytes.
142
105
  var CERTIFICATION_REQUEST = pkix.signedEnvelope(NS, CERTIFICATION_REQUEST_INFO, {
143
106
  code: "csr/not-a-certification-request", what: "CertificationRequest",
144
107
  build: function (e) {
@@ -185,9 +148,6 @@ var CERTIFICATION_REQUEST = pkix.signedEnvelope(NS, CERTIFICATION_REQUEST_INFO,
185
148
  * csr.subject.dn; // -> "CN=req.example"
186
149
  * csr.attributes[0].type; // -> "1.2.840.113549.1.9.14"
187
150
  */
188
- // Recording, because pki.csr.verify reaches a verdict from this result: the certificationRequestInfo
189
- // byte range, the key it proves possession of, and the subject and requested extensions that range
190
- // encodes are separate properties here, so the record is what binds them to one another.
191
151
  var parse = pkix.makeRecordingParser({ pemLabel: "CERTIFICATE REQUEST", PemError: PemError, ErrorClass: CsrError, prefix: "csr", what: "certification request", topSchema: CERTIFICATION_REQUEST, ns: NS }, "csr");
192
152
 
193
153
  /**
@@ -228,14 +188,6 @@ function pemDecode(text, label) { return pkix.pemDecode(text, label || "CERTIFIC
228
188
  */
229
189
  function pemEncode(der, label) { return pkix.pemEncode(der, label || "CERTIFICATE REQUEST", PemError); }
230
190
 
231
- // A CertificationRequest shares the outer SEQUENCE-of-3 shape with a certificate
232
- // and a CRL; a CSR is distinguished by its CertificationRequestInfo -- a SEQUENCE
233
- // of EXACTLY four children {version INTEGER, subject SEQUENCE, subjectPKInfo
234
- // SEQUENCE, attributes [0]}. The mandatory trailing context-[0] attributes
235
- // element is what a cert (whose tbs leads with [0] EXPLICIT version or an INTEGER
236
- // serial and never ends the leading run this way) and a CRL (whose tbs reaches a
237
- // bare Time at the validity position) never present, so the three detectors are
238
- // mutually exclusive.
239
191
  function matches(root) {
240
192
  var TAGS = asn1.TAGS;
241
193
  var cri = pkix.signedEnvelopeTbs(root);
@@ -253,10 +205,5 @@ module.exports = {
253
205
  pemDecode: pemDecode,
254
206
  pemEncode: pemEncode,
255
207
  matches: matches,
256
- // The top schema, exposed (not on the curated pki.schema.csr surface) so a
257
- // composer can drive the encode direction -- schema.encode(schema, v) -> a
258
- // CertificationRequest -- and prove the round-trip. The EST builder uses it
259
- // to re-encode a CSR with added attributes (the crmf certReqMessagesSchema
260
- // precedent).
261
208
  certificationRequestSchema: CERTIFICATION_REQUEST,
262
209
  };
@@ -55,37 +55,19 @@ var CsrattrsError = frameworkError.CsrattrsError;
55
55
  var NS = pkix.makeNS("csrattrs", CsrattrsError, oid);
56
56
  var T = asn1.TAGS;
57
57
 
58
- // The base Attribute is SET SIZE(1..MAX); ATTRIBUTE_KEYTYPE lowers the floor to 0
59
- // only for the ecPublicKey / rsaEncryption key-type hints, whose empty values SET
60
- // means "any key of this type" (RFC 9908 sec. 3.2). Every other attribute, and
61
- // every template inner attribute, keeps the non-empty floor, so an empty
62
- // challengePassword or unknown attribute still fails closed.
63
- // ATTRIBUTE keeps the base SET SIZE(1..MAX); ATTRIBUTE_OPTIONAL_VALUES lowers the
64
- // floor to 0. Only the recognized NON-KEY attributes that require a value
65
- // (id-ExtensionReq, the request-info template) use the strict form; a key-type
66
- // hint's empty SET means "any key of this type" (RFC 9908 sec. 3.2), and an
67
- // UNKNOWN attribute (a key type this build does not know yet, or any other OID) is
68
- // TOLERATED with an empty SET too -- RFC 8951 ignores what it does not recognize,
69
- // so an unfamiliar OID must not fail the whole response.
70
58
  var ATTRIBUTE = pkix.attribute(NS);
71
59
  var ATTRIBUTE_OPTIONAL_VALUES = pkix.attribute(NS, { minValues: 0 });
72
60
  var EXTENSIONS = pkix.extensions(NS);
73
61
  var ALGORITHM_IDENTIFIER = pkix.algorithmIdentifier(NS);
74
62
 
75
- // The RFC 9908 semantically-meaningful attribute OIDs (registry, never literals).
76
- var OID_EXTENSION_REQUEST = oid.byName("extensionRequest"); // id-ExtensionReq
63
+ var OID_EXTENSION_REQUEST = oid.byName("extensionRequest");
77
64
  var OID_EC_PUBLIC_KEY = oid.byName("ecPublicKey");
78
65
  var OID_RSA_ENCRYPTION = oid.byName("rsaEncryption");
79
66
  var OID_TEMPLATE = oid.byName("certificationRequestInfoTemplate");
80
67
  var OID_EXT_REQ_TEMPLATE = oid.byName("extensionReqTemplate");
81
68
 
82
- // The recognized non-key attributes that MUST carry a value (empty SET rejected).
83
69
  var STRICT_VALUES_OIDS = new Set([OID_EXTENSION_REQUEST, OID_TEMPLATE]);
84
70
 
85
- // The recognized public-key type OIDs -- used to FLAG a parsed attribute isKeyType
86
- // for the enroll planner (rsaEncryption / ecPublicKey are only the RFC 9908 sec. 3.2
87
- // examples; a no-parameter key like Ed25519 or an ML-DSA / SLH-DSA / ML-KEM type is
88
- // equally valid). Built by registered NAME (a typo fails at load), never literals.
89
71
  var KEY_TYPE_OIDS = new Set([
90
72
  "rsaEncryption", "ecPublicKey", "Ed25519", "Ed448", "X25519", "X448",
91
73
  "id-ml-dsa-44", "id-ml-dsa-65", "id-ml-dsa-87",
@@ -100,19 +82,13 @@ var KEY_TYPE_OIDS = new Set([
100
82
  return d;
101
83
  }));
102
84
 
103
- // ---- RFC 9908 sec. 3.4 CertificationRequestInfoTemplate ------------------
104
85
 
105
- // version MUST be v1(0). A dedicated leaf (not pkix.versionReader) so the reject
106
- // carries the template-specific code the RFC 9908 sec. 3.4 MUST names.
107
86
  var TEMPLATE_VERSION = schema.decode(function (n, ctx) {
108
87
  var v = asn1.read.integer(n);
109
88
  if (v !== 0n) throw ctx.E("csrattrs/bad-template-version", "CertificationRequestInfoTemplate version must be v1(0) (RFC 9908 sec. 3.4)");
110
89
  return 0;
111
90
  }, function () { return asn1.build.integer(0n); });
112
91
 
113
- // SingleAttributeTemplate ::= SEQUENCE { type OID, value ANY OPTIONAL }, where a
114
- // value-absent element means "the client fills this in" (RFC 9908 sec. 3.4). The
115
- // trailing OPTIONAL ANY is the algorithmIdentifier-parameters shape.
116
92
  var SINGLE_ATTR_TEMPLATE = schema.seq([
117
93
  schema.field("type", schema.oidLeaf()),
118
94
  schema.optional("value", schema.any(), { whenAny: true }),
@@ -124,29 +100,19 @@ var SINGLE_ATTR_TEMPLATE = schema.seq([
124
100
  },
125
101
  });
126
102
 
127
- // RelativeDistinguishedNameTemplate ::= SET SIZE (1..MAX) OF SingleAttributeTemplate.
128
103
  var RDN_TEMPLATE = schema.setOf(SINGLE_ATTR_TEMPLATE, {
129
104
  assert: "set", min: 1, code: "csrattrs/bad-name-template", what: "RelativeDistinguishedNameTemplate",
130
105
  build: function (m) { return m.items.map(function (it) { return it.value.result; }); },
131
106
  });
132
- // NameTemplate ::= RDNSequence (a SEQUENCE OF RDN-template SETs) -> array of RDNs,
133
- // each an array of { type, name, value } (value null = "the client fills it in").
134
107
  var NAME_TEMPLATE = schema.seqOf(RDN_TEMPLATE, {
135
108
  assert: "sequence", code: "csrattrs/bad-name-template", what: "NameTemplate",
136
109
  build: function (m) { return m.items.map(function (it) { return it.value.result; }); },
137
110
  });
138
111
 
139
- // SubjectPublicKeyInfoTemplate ::= SEQUENCE { algorithm AlgorithmIdentifier,
140
- // subjectPublicKey BIT STRING OPTIONAL }, where the key is OPTIONAL (present
141
- // only as an RSA modulus-size placeholder), so pkix.spki (key required, arity 2)
142
- // cannot be reused.
143
112
  var SPKI_TEMPLATE = schema.seq([
144
113
  schema.field("algorithm", ALGORITHM_IDENTIFIER),
145
114
  schema.optional("placeholderKey", schema.bitString(), { whenUniversal: [T.BIT_STRING] }),
146
115
  ], {
147
- // subjectPKInfo is [0] IMPLICIT (RFC 9908 sec. 3.4), so the context tag replaces
148
- // the universal SEQUENCE tag, so the node is context-[0] constructed and its
149
- // children are read directly (the pwri keyDerivationAlgorithm [0] precedent).
150
116
  assert: "implicit", implicitTag: 0, arity: { min: 1, max: 2 }, code: "csrattrs/bad-spki-template", what: "SubjectPublicKeyInfoTemplate",
151
117
  build: function (m) {
152
118
  return { algorithm: m.fields.algorithm.value.result,
@@ -154,11 +120,6 @@ var SPKI_TEMPLATE = schema.seq([
154
120
  },
155
121
  });
156
122
 
157
- // ExtensionTemplate ::= SEQUENCE { extnID OID, critical BOOLEAN DEFAULT FALSE,
158
- // extnValue OCTET STRING OPTIONAL }, where extnValue absent means "client supplies";
159
- // an explicit critical FALSE is non-DER (BOOLEAN DEFAULT FALSE). Not reusable
160
- // from pkix.extension (whose extnValue is required), so the DER-critical rule
161
- // is applied here directly.
162
123
  var EXTENSION_TEMPLATE = schema.decode(function (n, ctx) {
163
124
  if (!schema.isUniversal(n, T.SEQUENCE) || !n.children || n.children.length < 1 || n.children.length > 3) {
164
125
  throw ctx.E("csrattrs/bad-extension-template", "ExtensionTemplate must be a SEQUENCE of {extnID, critical?, extnValue?}");
@@ -176,20 +137,11 @@ var EXTENSION_TEMPLATE = schema.decode(function (n, ctx) {
176
137
  return { oid: extnID, name: ctx.oid.name(extnID) || null, critical: critical, value: value };
177
138
  });
178
139
 
179
- // ExtensionReqTemplate ::= ExtensionTemplates ::= SEQUENCE SIZE (1..MAX) OF
180
- // ExtensionTemplate (RFC 9908 sec. 3.4) -- the id-aa-extensionReqTemplate value
181
- // is a SEQUENCE OF ExtensionTemplate, not a single one.
182
140
  var EXTENSION_REQ_TEMPLATE = schema.seqOf(EXTENSION_TEMPLATE, {
183
141
  assert: "sequence", min: 1, code: "csrattrs/bad-extension-template", what: "ExtensionReqTemplate",
184
142
  build: function (m) { return m.items.map(function (it) { return it.value; }); },
185
143
  });
186
144
 
187
- // CertificationRequestInfoTemplate ::= SEQUENCE { version, subject NameTemplate
188
- // OPTIONAL, subjectPKInfo [0] IMPLICIT OPTIONAL, attributes [1] IMPLICIT
189
- // Attributes }. attributes is present (may be an empty SET). The RFC 9908
190
- // sec. 3.4 inner-attribute MUSTs (<=1 extensionReqTemplate; not both
191
- // extension-request kinds; a values SET of exactly one ExtensionTemplate) are
192
- // enforced in the build.
193
145
  var CERT_REQ_INFO_TEMPLATE = schema.seq([
194
146
  schema.field("version", TEMPLATE_VERSION),
195
147
  schema.optional("subject", NAME_TEMPLATE, { whenUniversal: [T.SEQUENCE] }),
@@ -205,16 +157,11 @@ var CERT_REQ_INFO_TEMPLATE = schema.seq([
205
157
  if (a.type === OID_EXTENSION_REQUEST) {
206
158
  hasExtReq = true;
207
159
  extReqs += 1;
208
- // A template id-ExtensionReq carries one Extensions value (RFC 9908 sec. 3.2);
209
- // decode it so a client reads the requirements off .extensions instead of
210
- // re-parsing raw bytes (the top-level extensionRequest exposes it the same way).
211
160
  if (a.values.length !== 1) throw NS.E("csrattrs/bad-template-attrs", "a template id-ExtensionReq values must be a SET of exactly one Extensions (RFC 9908 sec. 3.2)");
212
161
  extensions = schema.walk(EXTENSIONS, asn1.decode(a.values[0]), ctx).result;
213
162
  }
214
163
  if (a.type === OID_EXT_REQ_TEMPLATE) {
215
164
  extReqTemplates += 1;
216
- // The attribute's values SET holds exactly one ExtensionReqTemplate
217
- // (RFC 9908 sec. 3.4); that value is itself a SEQUENCE OF ExtensionTemplate.
218
165
  if (a.values.length !== 1) throw NS.E("csrattrs/bad-template-attrs", "an id-aa-extensionReqTemplate values must be a SET of exactly one ExtensionReqTemplate (RFC 9908 sec. 3.4)");
219
166
  extensionTemplates = extensionTemplates.concat(schema.walk(EXTENSION_REQ_TEMPLATE, asn1.decode(a.values[0]), ctx).result);
220
167
  }
@@ -233,35 +180,24 @@ var CERT_REQ_INFO_TEMPLATE = schema.seq([
233
180
  },
234
181
  });
235
182
 
236
- // ---- AttrOrOID + the semantic enrichment ---------------------------------
237
183
 
238
- // Decode the three RFC 9908-meaningful attribute types onto an already-walked
239
- // Attribute { type, name, values }. Unknown types keep only their raw values.
240
- // A recognized public-key type is flagged isKeyType so a consumer (the pki.est
241
- // enroll planner) treats every accepted key type uniformly, not just RSA/EC.
242
184
  function _enrichAttribute(item, ctx) {
243
185
  if (KEY_TYPE_OIDS.has(item.oid)) item.isKeyType = true;
244
186
  if (item.oid === OID_EXTENSION_REQUEST) {
245
187
  if (item.values.length !== 1) throw ctx.E("csrattrs/bad-extension-req", "an id-ExtensionReq attribute values must be a SET of exactly one Extensions (RFC 9908 sec. 3.2)");
246
188
  item.extensions = schema.walk(EXTENSIONS, asn1.decode(item.values[0]), ctx).result;
247
189
  } else if (item.oid === OID_EC_PUBLIC_KEY) {
248
- // A key-type hint's values SET is empty ("any curve") or a singleton naming
249
- // one curve (RFC 9908 sec. 3.2); a multi-valued SET is ambiguous, so it fails
250
- // closed instead of letting DER ordering pick the advertised constraint.
251
190
  if (item.values.length > 1) throw ctx.E("csrattrs/bad-key-type-attr", "an ecPublicKey attribute values must be empty or a SET of exactly one named-curve OBJECT IDENTIFIER (RFC 9908 sec. 3.2)");
252
191
  if (item.values.length === 1) {
253
192
  try { item.curve = asn1.read.oid(asn1.decode(item.values[0])); }
254
193
  catch (e) { throw ctx.E("csrattrs/bad-key-type-attr", "an ecPublicKey attribute value must be a named-curve OBJECT IDENTIFIER (RFC 9908 sec. 3.2)", e); }
255
194
  }
256
195
  } else if (item.oid === OID_RSA_ENCRYPTION) {
257
- // Empty ("any size") or a singleton naming one key size; reject a multi-valued SET.
258
196
  if (item.values.length > 1) throw ctx.E("csrattrs/bad-key-type-attr", "an rsaEncryption attribute values must be empty or a SET of exactly one INTEGER key size (RFC 9908 sec. 3.2)");
259
197
  if (item.values.length === 1) {
260
198
  var sz;
261
199
  try { sz = asn1.read.integer(asn1.decode(item.values[0])); }
262
200
  catch (e) { throw ctx.E("csrattrs/bad-key-type-attr", "an rsaEncryption attribute value must be an INTEGER key size (RFC 9908 sec. 3.2)", e); }
263
- // Bound before narrowing to a Number: an RSA modulus-size hint of 1..65536
264
- // bits covers every real key; a value past 2^53 would round silently.
265
201
  if (sz < 1n || sz > 65536n) throw ctx.E("csrattrs/bad-key-type-attr", "the rsaEncryption key size " + sz + " is out of range (1..65536 bits)");
266
202
  item.keySize = Number(sz);
267
203
  }
@@ -271,36 +207,25 @@ function _enrichAttribute(item, ctx) {
271
207
  }
272
208
  }
273
209
 
274
- // AttrOrOID ::= CHOICE { oid OBJECT IDENTIFIER, attribute Attribute }. The two
275
- // arms are the two universal tags; anything else is not an AttrOrOID. A decode
276
- // leaf (not schema.choice) so the enrichment + the paired write live together.
277
210
  var ATTR_OR_OID = schema.decode(function (n, ctx) {
278
211
  if (schema.isUniversal(n, T.OBJECT_IDENTIFIER) && !n.constructed) {
279
212
  var o = asn1.read.oid(n);
280
213
  return { kind: "oid", oid: o, name: ctx.oid.name(o) || null };
281
214
  }
282
215
  if (schema.isUniversal(n, T.SEQUENCE) && n.children) {
283
- // Peek the type OID to choose the values-arity rule: only a recognized non-key
284
- // attribute (id-ExtensionReq / template) requires SET SIZE(1..MAX); a key-type
285
- // hint OR an unknown OID MAY carry an empty SET (RFC 9908 sec. 3.2 / RFC 8951).
286
216
  var typeOid = (n.children.length >= 1 && schema.isUniversal(n.children[0], T.OBJECT_IDENTIFIER) && !n.children[0].constructed) ? asn1.read.oid(n.children[0]) : null;
287
217
  var attrSchema = STRICT_VALUES_OIDS.has(typeOid) ? ATTRIBUTE : ATTRIBUTE_OPTIONAL_VALUES;
288
- var a = schema.walk(attrSchema, n, ctx).result; // { type, name, values:[bytes] }
218
+ var a = schema.walk(attrSchema, n, ctx).result;
289
219
  var item = { kind: "attribute", oid: a.type, name: a.name, values: a.values };
290
220
  _enrichAttribute(item, ctx);
291
221
  return item;
292
222
  }
293
223
  throw ctx.E("csrattrs/bad-attr-or-oid", "each CsrAttrs element must be an OBJECT IDENTIFIER or an Attribute SEQUENCE (RFC 8951 sec. 3.5)");
294
224
  }, function (item) {
295
- // Paired encoder (one structure, both directions): reconstruct from the arm's
296
- // identifying fields plus raw values, since the typed enrichment is decode-only.
297
225
  if (item.kind === "oid") return asn1.build.oid(item.oid);
298
226
  return asn1.build.sequence([asn1.build.oid(item.oid), asn1.build.set(item.values)]);
299
227
  });
300
228
 
301
- // CsrAttrs ::= SEQUENCE SIZE (0..MAX) OF AttrOrOID. min:0, because an empty SEQUENCE is
302
- // a complete valid document. The cross-element MUSTs (RFC 9908 sec. 3.2 single
303
- // id-ExtensionReq; sec. 3.4 single template) are enforced in the build.
304
229
  var CSR_ATTRS = schema.seqOf(ATTR_OR_OID, {
305
230
  assert: "sequence", code: "csrattrs/not-csrattrs", what: "CsrAttrs",
306
231
  build: function (m) {
@@ -347,21 +272,13 @@ var CSR_ATTRS = schema.seqOf(ATTR_OR_OID, {
347
272
  */
348
273
  var parse = pkix.makeParser({ pemLabel: null, PemError: frameworkError.PemError, ErrorClass: CsrattrsError, prefix: "csrattrs", what: "CsrAttrs", topSchema: CSR_ATTRS, ns: NS });
349
274
 
350
- // matches(root): a CsrAttrs is a universal SEQUENCE whose children are each a
351
- // bare universal OID or an Attribute (a universal SEQUENCE of exactly 2 whose
352
- // first child is an OID and second a SET). An empty SEQUENCE (30 00) is a valid
353
- // CsrAttrs and no other registered document root accepts it. Registered BEFORE
354
- // ocsp-request (a permissive superset probe) as the strict refinement, the same
355
- // resolution tsp / crmf already use.
356
275
  function matches(root) {
357
276
  var k = pkix.rootSequenceChildren(root, 0);
358
277
  if (!k) return false;
359
278
  if (k.length === 0) return true;
360
279
  for (var i = 0; i < k.length; i++) {
361
280
  var c = k[i];
362
- // bare-OID arm: a primitive universal OBJECT IDENTIFIER.
363
281
  if (schema.isUniversal(c, T.OBJECT_IDENTIFIER) && !c.constructed) continue;
364
- // Attribute arm: a universal SEQUENCE of exactly { OID, SET }.
365
282
  if (!schema.isUniversal(c, T.SEQUENCE) || !c.children || c.children.length !== 2) return false;
366
283
  if (!schema.isUniversal(c.children[0], T.OBJECT_IDENTIFIER)) return false;
367
284
  if (!(schema.isUniversal(c.children[1], T.SET) && c.children[1].children)) return false;
@@ -372,7 +289,5 @@ function matches(root) {
372
289
  module.exports = {
373
290
  parse: parse,
374
291
  matches: matches,
375
- // The top schema, exposed (not on the curated pki.schema.csrattrs surface) so a
376
- // composer can drive the encode direction and prove the round-trip.
377
292
  csrAttrsSchema: CSR_ATTRS,
378
293
  };