@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
@@ -55,23 +55,12 @@ var TAGS = asn1.TAGS;
55
55
 
56
56
  var ALGID = pkix.algorithmIdentifier(NS);
57
57
 
58
- // Registry constants -- never a dotted literal in a format module.
59
58
  var OID_SHA1 = oid.byName("sha1");
60
59
  var OID_SHA256 = oid.byName("sha256");
61
60
  var OID_SIGNING_CERTIFICATE = oid.byName("signingCertificate");
62
61
  var OID_SIGNING_CERTIFICATE_V2 = oid.byName("signingCertificateV2");
63
62
  var OID_SMIME_CAPABILITIES = oid.byName("smimeCapabilities");
64
63
 
65
- // IssuerSerial ::= SEQUENCE { issuer GeneralNames, serialNumber CertificateSerialNumber }
66
- // (RFC 5035 App A). A bare universal SEQUENCE of exactly two fields, distinct
67
- // from the RFC 5755 attribute-certificate IssuerSerial (three fields, reached
68
- // IMPLICIT-tagged), so declared per-format. `issuer` composes the shared
69
- // GeneralNames factory (every CHOICE arm validated + surfaced raw, SIZE 1..MAX)
70
- // and is surfaced unchanged here: the RFC 5035 sec. 5 directoryName narrowing applies
71
- // only to a non-attribute (public-key) certificate reference, and an ESSCertID
72
- // entry may reference an attribute certificate whose issuer is a full GeneralNames.
73
- // The first cert is known to be the signing public-key cert (RFC 5035 sec. 3), so the
74
- // directoryName rule is enforced in the SigningCertificate build and not here.
75
64
  var GENERAL_NAME_DIRECTORY = 4;
76
65
  var ISSUER_SERIAL = schema.seq([
77
66
  schema.field("issuer", pkix.generalNames(NS, { code: "smime/bad-general-names" })),
@@ -87,11 +76,6 @@ var ISSUER_SERIAL = schema.seq([
87
76
  },
88
77
  });
89
78
 
90
- // RFC 5035 sec. 5: the signing certificate (certs[0], the public-key cert that made
91
- // the signature per sec. 3) MUST identify its issuer as exactly one directoryName [4].
92
- // Additional certs[1..] may reference attribute certificates, whose issuer is a
93
- // GeneralNames -- left unconstrained (a verifier-tier profile concern). `fail`
94
- // throws the caller's code.
95
79
  function assertSignerIssuerIsDirectoryName(certs, fail) {
96
80
  if (!certs.length || !certs[0].issuerSerial) return;
97
81
  var names = certs[0].issuerSerial.issuer.names;
@@ -100,9 +84,6 @@ function assertSignerIssuerIsDirectoryName(certs, fail) {
100
84
  }
101
85
  }
102
86
 
103
- // PolicyInformation ::= SEQUENCE { policyIdentifier CertPolicyId,
104
- // policyQualifiers SEQUENCE OF PolicyQualifierInfo OPTIONAL } (RFC 5280 sec. 4.2.1.4).
105
- // Decode the policy OID (+ registry name); surface policyQualifiers raw.
106
87
  var POLICY_INFORMATION = schema.seq([
107
88
  schema.field("policyIdentifier", schema.oidLeaf()),
108
89
  schema.optional("policyQualifiers", schema.any(), { whenUniversal: [TAGS.SEQUENCE] }),
@@ -111,9 +92,6 @@ var POLICY_INFORMATION = schema.seq([
111
92
  build: function (m, ctx) {
112
93
  var qualifiers = null;
113
94
  if (m.fields.policyQualifiers.present) {
114
- // The qualifier body stays raw (per the ESS scope), but the RFC 5280
115
- // sec. 4.2.1.4 structure is validated fail-closed by the shared assertion, the
116
- // same PolicyInformation shape the certificatePolicies decoder enforces.
117
95
  var q = m.fields.policyQualifiers.node;
118
96
  pkix.assertPolicyQualifiers(q, function (msg, cause) { throw ctx.E("smime/bad-policy-information", msg, cause); });
119
97
  qualifiers = q.bytes;
@@ -125,17 +103,11 @@ var POLICY_INFORMATION = schema.seq([
125
103
  };
126
104
  },
127
105
  });
128
- // policies SEQUENCE OF PolicyInformation OPTIONAL -- order-preserving; the ASN.1
129
- // module carries no SIZE bound, so an explicitly present but empty list is legal.
130
106
  var POLICIES = schema.seqOf(POLICY_INFORMATION, {
131
107
  assert: "sequence", min: 0, code: "smime/bad-policies", what: "policies",
132
108
  build: function (m) { return m.items.map(function (it) { return it.value.result; }); },
133
109
  });
134
110
 
135
- // ESSCertID ::= SEQUENCE { certHash Hash, issuerSerial IssuerSerial OPTIONAL }
136
- // (RFC 5035 sec. 5.4.2). Hash ::= OCTET STRING; for v1 it is the SHA-1 hash of the
137
- // whole certificate with no algorithm field, so the hash algorithm is synthesized
138
- // as the implied SHA-1 to make v1 shape-compatible with v2 for a verifier.
139
111
  var ESS_CERT_ID = schema.seq([
140
112
  schema.field("certHash", schema.octetString()),
141
113
  schema.optional("issuerSerial", ISSUER_SERIAL, { whenUniversal: [TAGS.SEQUENCE] }),
@@ -150,11 +122,6 @@ var ESS_CERT_ID = schema.seq([
150
122
  },
151
123
  });
152
124
 
153
- // ESSCertIDv2 ::= SEQUENCE { hashAlgorithm AlgorithmIdentifier DEFAULT
154
- // {algorithm id-sha256}, certHash Hash, issuerSerial IssuerSerial OPTIONAL }
155
- // (RFC 5035 sec. 5.4.1 / sec. 4). The mandatory certHash OCTET STRING pivots between the
156
- // two optional SEQUENCEs, so a leading SEQUENCE is hashAlgorithm and a leading
157
- // OCTET STRING means hashAlgorithm defaulted.
158
125
  var ESS_CERT_ID_V2 = schema.seq([
159
126
  schema.optional("hashAlgorithm", ALGID, { whenUniversal: [TAGS.SEQUENCE] }),
160
127
  schema.field("certHash", schema.octetString()),
@@ -165,12 +132,6 @@ var ESS_CERT_ID_V2 = schema.seq([
165
132
  var hashAlgorithm;
166
133
  if (m.fields.hashAlgorithm.present) {
167
134
  var alg = m.fields.hashAlgorithm.value.result;
168
- // X.690 sec. 11.5: a DEFAULT value MUST be omitted in DER. The default is
169
- // {algorithm id-sha256, parameters ABSENT}; an explicit encoding byte-equal
170
- // to it is a non-canonical DEFAULT and is rejected fail-closed (the
171
- // structured-value analogue of the primitive-DEFAULT rejection the toolkit
172
- // already enforces). A present hashAlgorithm carrying a redundant NULL
173
- // parameters is not byte-equal to the params-absent default and decodes.
174
135
  if (alg.oid === OID_SHA256 && alg.parameters === null) {
175
136
  throw ctx.E("smime/non-canonical-default",
176
137
  "ESSCertIDv2 hashAlgorithm equal to the DEFAULT {algorithm id-sha256} MUST be omitted (X.690 sec. 11.5)");
@@ -187,10 +148,6 @@ var ESS_CERT_ID_V2 = schema.seq([
187
148
  },
188
149
  });
189
150
 
190
- // SigningCertificate ::= SEQUENCE { certs SEQUENCE OF ESSCertID,
191
- // policies SEQUENCE OF PolicyInformation OPTIONAL } (RFC 5035 sec. 5.4.2). certs is
192
- // order-preserving (RFC 5035 sec. 3 makes the first element the signing certificate)
193
- // and non-empty (an empty certs cannot name a signing cert).
194
151
  function signingCertificateSchema(essCertId, code, what) {
195
152
  return schema.seq([
196
153
  schema.field("certs", schema.seqOf(essCertId, { assert: "sequence", min: 1, code: "smime/bad-certs", what: "certs" })),
@@ -210,10 +167,6 @@ function signingCertificateSchema(essCertId, code, what) {
210
167
  var SIGNING_CERTIFICATE = signingCertificateSchema(ESS_CERT_ID, "smime/bad-signing-certificate", "SigningCertificate");
211
168
  var SIGNING_CERTIFICATE_V2 = signingCertificateSchema(ESS_CERT_ID_V2, "smime/bad-signing-certificate-v2", "SigningCertificateV2");
212
169
 
213
- // SMIMECapability ::= SEQUENCE { capabilityID OBJECT IDENTIFIER,
214
- // parameters ANY DEFINED BY capabilityID OPTIONAL } (RFC 8551 sec. 2.5.2). Distinct
215
- // domain from AlgorithmIdentifier though isomorphic -- surfaced as capabilityID +
216
- // raw parameters (the ANY-DEFINED-BY interpretation is a negotiation concern).
217
170
  var SMIME_CAPABILITY = schema.seq([
218
171
  schema.field("capabilityID", schema.oidLeaf()),
219
172
  schema.optional("parameters", schema.any(), { whenAny: true }),
@@ -227,8 +180,6 @@ var SMIME_CAPABILITY = schema.seq([
227
180
  };
228
181
  },
229
182
  });
230
- // SMIMECapabilities ::= SEQUENCE OF SMIMECapability, ordered by preference
231
- // (RFC 8551 sec. 2.5.2), never sorted; an empty list is legal.
232
183
  var SMIME_CAPABILITIES = schema.seqOf(SMIME_CAPABILITY, {
233
184
  assert: "sequence", min: 0, code: "smime/bad-capabilities", what: "SMIMECapabilities",
234
185
  build: function (m) { return { capabilities: m.items.map(function (it) { return it.value.result; }) }; },
@@ -334,11 +285,6 @@ function decodeAttribute(attr) {
334
285
  if (!attr || typeof attr !== "object" || typeof attr.type !== "string" || !Array.isArray(attr.values)) {
335
286
  throw new SmimeError("smime/bad-input", "decodeAttribute expects a CMS attribute { type, values }");
336
287
  }
337
- // Route on the attribute OID FIRST. The single-AttributeValue MUST (RFC 8551
338
- // sec. 2.5.2) is specific to the ESS / SMIMECapabilities attributes, so it is
339
- // enforced only inside the known-type branch; an unknown / custom attribute
340
- // recognize-and-defers with its raw values intact regardless of value count
341
- // (its own cardinality rules are not this decoder's to enforce).
342
288
  if (attr.type === OID_SIGNING_CERTIFICATE || attr.type === OID_SIGNING_CERTIFICATE_V2 || attr.type === OID_SMIME_CAPABILITIES) {
343
289
  if (attr.values.length !== 1) {
344
290
  throw new SmimeError("smime/multi-valued-attribute",
package/lib/schema-tsp.js CHANGED
@@ -49,47 +49,28 @@ var NS = pkix.makeNS("tsp", TspError, oid);
49
49
  var ALGORITHM_IDENTIFIER = pkix.algorithmIdentifier(NS);
50
50
  var EXTENSION = pkix.extension(NS);
51
51
 
52
- // TSTInfo.version is INTEGER { v1(1) }; the only legal value is 1.
53
52
  var VERSION = pkix.versionReader(NS, { "1": 1 });
54
53
 
55
- // id-ct-TSTInfo is the eContentType that identifies a timestamp token (RFC 3161
56
- // sec. 2.4.2); resolved from the registry, never a dotted literal.
57
54
  var OID_TST_INFO = oid.byName("tSTInfo");
58
55
 
59
- // The ESS certificate-identifier attributes: RFC 3161 sec. 2.4.2 requires the TSA
60
- // certificate identifier as a SigningCertificate signed attribute; RFC 5816
61
- // additionally permits SigningCertificateV2.
62
56
  var OID_SIGNING_CERT = oid.byName("signingCertificate");
63
57
  var OID_SIGNING_CERT_V2 = oid.byName("signingCertificateV2");
64
58
 
65
59
  var TAGS = asn1.TAGS;
66
60
 
67
- // PKIFailureInfo ::= BIT STRING NamedBitList (RFC 3161 sec. 2.4.2). bit 0 is the MSB of
68
- // the first content octet; a set bit outside the named set is surfaced by index.
69
61
  var FAILURE_BITS = {
70
62
  0: "badAlg", 2: "badRequest", 5: "badDataFormat", 14: "timeNotAvailable",
71
63
  15: "unacceptedPolicy", 16: "unacceptedExtension", 17: "addInfoNotAvailable", 25: "systemFailure",
72
64
  };
73
65
 
74
- // ---- shared leaves ---------------------------------------------------
75
66
 
76
- // GeneralizedTime-only leaf. RFC 3161 sec. 2.4.2 requires genTime to be GeneralizedTime,
77
- // never UTCTime; assert the tag before the (fractional-capable) codec read.
78
- // RFC 3161 genTime may carry sub-second precision (X.690 sec. 11.7 fractional profile).
79
67
  var GEN_TIME = pkix.generalizedTime(NS, { code: "tsp/bad-gentime", message: "genTime must be a GeneralizedTime (RFC 3161 sec. 2.4.2)", allowFractional: true });
80
68
 
81
- // tsa [0] EXPLICIT GeneralName (RFC 3161 sec. 2.4.2), validated and surfaced raw via the
82
- // shared pkix.generalName primitive (RFC 5280 sec. 4.2.1.6), which checks the chosen
83
- // alternative's form and content so a malformed GeneralName fails closed.
84
69
  var GENERAL_NAME_RAW = pkix.generalName(NS, { code: "tsp/bad-tsa" });
85
70
 
86
- // A PKIFreeText element MUST be a UTF8String (RFC 3161 sec. 2.4.2).
87
71
  var UTF8_TEXT = pkix.utf8Text(NS, { code: "tsp/bad-status-info", message: "PKIFreeText elements must be UTF8String" });
88
72
 
89
- // ---- MessageImprint --------------------------------------------------
90
73
 
91
- // MessageImprint ::= SEQUENCE { hashAlgorithm AlgorithmIdentifier, hashedMessage
92
- // OCTET STRING } (RFC 3161 sec. 2.4.1). hashedMessage is a digest, surfaced raw.
93
74
  var MESSAGE_IMPRINT = schema.seq([
94
75
  schema.field("hashAlgorithm", ALGORITHM_IDENTIFIER),
95
76
  schema.field("hashedMessage", schema.octetString()),
@@ -100,11 +81,7 @@ var MESSAGE_IMPRINT = schema.seq([
100
81
  },
101
82
  });
102
83
 
103
- // ---- Accuracy --------------------------------------------------------
104
84
 
105
- // Accuracy ::= SEQUENCE { seconds INTEGER OPTIONAL, millis [0] IMPLICIT INTEGER
106
- // (1..999) OPTIONAL, micros [1] IMPLICIT INTEGER (1..999) OPTIONAL } (RFC 3161
107
- // sec. 2.4.2). Every sub-field is optional; a missing one defaults to 0.
108
85
  var ACCURACY = schema.seq([
109
86
  schema.optional("seconds", schema.integerLeaf(), { whenUniversal: [TAGS.INTEGER] }),
110
87
  schema.trailing([
@@ -117,20 +94,13 @@ var ACCURACY = schema.seq([
117
94
  function sub(f) {
118
95
  if (!f.present) return 0;
119
96
  var v = f.value;
120
- // millis / micros are constrained to 1..999 (RFC 3161 sec. 2.4.2); 0 is also
121
- // excluded (and non-canonical for a positive count).
122
97
  if (v < 1n || v > 999n) throw NS.E("tsp/bad-accuracy", "Accuracy millis/micros must be in 1..999");
123
98
  return Number(v);
124
99
  }
125
- // Accuracy is the +/- deviation added to and subtracted from genTime (RFC
126
- // 3161 sec. 2.4.2), so a negative seconds inverts the time window a verifier
127
- // computes -- the same semantically-impossible class as a 0 millis/micros.
128
100
  if (m.fields.seconds.present && m.fields.seconds.value < 0n) {
129
101
  throw NS.E("tsp/bad-accuracy", "Accuracy seconds must not be negative (RFC 3161 sec. 2.4.2)");
130
102
  }
131
103
  return {
132
- // seconds is an unbounded INTEGER -- keep it lossless as a BigInt (millis /
133
- // micros are constrained to 1..999, so Number is exact for those).
134
104
  seconds: m.fields.seconds.present ? m.fields.seconds.value : 0n,
135
105
  millis: sub(m.fields.millis),
136
106
  micros: sub(m.fields.micros),
@@ -138,12 +108,7 @@ var ACCURACY = schema.seq([
138
108
  },
139
109
  });
140
110
 
141
- // ---- TSTInfo ---------------------------------------------------------
142
111
 
143
- // TSTInfo ::= SEQUENCE { version, policy, messageImprint, serialNumber, genTime,
144
- // accuracy OPTIONAL, ordering DEFAULT FALSE, nonce OPTIONAL, tsa [0] EXPLICIT
145
- // GeneralName OPTIONAL, extensions [1] IMPLICIT Extensions OPTIONAL } (RFC 3161
146
- // sec. 2.4.2). The five mandatory fields come first; the optionals are consumed by tag.
147
112
  var TST_INFO = schema.seq([
148
113
  schema.field("version", VERSION),
149
114
  schema.field("policy", schema.oidLeaf()),
@@ -160,7 +125,6 @@ var TST_INFO = schema.seq([
160
125
  ], {
161
126
  assert: "sequence", code: "tsp/bad-tst-info", what: "TSTInfo",
162
127
  build: function (m, ctx) {
163
- // ordering BOOLEAN DEFAULT FALSE -- an explicit FALSE must be omitted (DER).
164
128
  if (m.fields.ordering.present && m.fields.ordering.value === false) {
165
129
  throw NS.E("tsp/bad-ordering", "ordering is BOOLEAN DEFAULT FALSE -- an explicit FALSE must be omitted");
166
130
  }
@@ -174,11 +138,7 @@ var TST_INFO = schema.seq([
174
138
  serialNumber: m.fields.serialNumber.value,
175
139
  serialNumberHex: m.fields.serialNumber.node.content.toString("hex"),
176
140
  genTime: m.fields.genTime.value,
177
- // genTime is surfaced as a millisecond-precision Date; genTimeFraction is the
178
- // exact fractional-seconds digits (lossless for sub-millisecond precision), or
179
- // null when genTime carries no fraction.
180
141
  genTimeFraction: (function () {
181
- // /\.(\d+)Z$/ : the fractional-seconds digits before a trailing "Z" (the "." and "Z" excluded), or null.
182
142
  var s = m.fields.genTime.node.content.toString("latin1"), n = s.length;
183
143
  if (n < 3 || s.charAt(n - 1) !== "Z") return null;
184
144
  var dot = s.lastIndexOf(".");
@@ -197,10 +157,7 @@ var TST_INFO = schema.seq([
197
157
  },
198
158
  });
199
159
 
200
- // ---- PKIStatusInfo / TimeStampResp -----------------------------------
201
160
 
202
- // PKIStatusInfo ::= SEQUENCE { status PKIStatus (INTEGER), statusString PKIFreeText
203
- // OPTIONAL, failInfo PKIFailureInfo OPTIONAL } (RFC 3161 sec. 2.4.2, from RFC 4210).
204
161
  var PKI_STATUS_INFO = schema.seq([
205
162
  schema.field("status", schema.integerLeaf()),
206
163
  schema.optional("statusString", schema.seqOf(UTF8_TEXT, { assert: "sequence", min: 1, code: "tsp/bad-status-info", what: "statusString" }), { whenUniversal: [TAGS.SEQUENCE] }),
@@ -209,7 +166,6 @@ var PKI_STATUS_INFO = schema.seq([
209
166
  assert: "sequence", code: "tsp/bad-status-info", what: "PKIStatusInfo",
210
167
  build: function (m) {
211
168
  var status = m.fields.status.value;
212
- // PKIStatus ::= INTEGER { granted(0) .. revocationNotification(5) }.
213
169
  if (status < 0n || status > 5n) throw NS.E("tsp/bad-status", "PKIStatus " + status + " is outside 0..5 (RFC 3161 sec. 2.4.2)");
214
170
  var failInfo = null;
215
171
  if (m.fields.failInfo.present) {
@@ -225,18 +181,10 @@ var PKI_STATUS_INFO = schema.seq([
225
181
  },
226
182
  });
227
183
 
228
- // X.690 sec. 11.2.2 -- a BIT STRING typed with a NamedBitList (PKIFailureInfo) MUST have
229
- // all trailing 0 bits removed under DER: no trailing all-zero content octet, and the
230
- // declared unusedBits must sit exactly below the lowest set bit of the last octet (so
231
- // the encoding is minimal). The empty value encodes as 0 content octets, 0 unusedBits.
232
184
  function _assertMinimalNamedBits(unusedBits, bytes) {
233
185
  schema.assertMinimalNamedBits(unusedBits, bytes, function (m) { throw NS.E("tsp/bad-failinfo", m); });
234
186
  }
235
187
 
236
- // Decode the set NamedBitList bits to their RFC 3161 names (bit 0 = MSB of byte 0).
237
- // A set bit outside the defined set is an unsupported PKIFailureInfo value, and a client
238
- // MUST error on a failInfo it does not understand (RFC 3161 sec. 2.4.2), so reject it
239
- // instead of surfacing an opaque "bitN".
240
188
  function _namedBits(bytes) {
241
189
  var out = [];
242
190
  for (var i = 0; i < bytes.length * 8; i++) {
@@ -249,11 +197,6 @@ function _namedBits(bytes) {
249
197
  return out;
250
198
  }
251
199
 
252
- // TimeStampResp ::= SEQUENCE { status PKIStatusInfo, timeStampToken TimeStampToken
253
- // OPTIONAL } (RFC 3161 sec. 2.4.2). There is NO version field. The token is a CMS
254
- // ContentInfo, decoded via cms.parse; the status-to-token coupling is load-bearing.
255
- // The top-level reject code predates the `<prefix>/not-a-<structure>` convention
256
- // and stays frozen on the public error-code surface.
257
200
  var TIME_STAMP_RESP = schema.seq([
258
201
  schema.field("status", PKI_STATUS_INFO),
259
202
  schema.optional("timeStampToken", schema.any(), { whenUniversal: [TAGS.SEQUENCE] }),
@@ -262,17 +205,10 @@ var TIME_STAMP_RESP = schema.seq([
262
205
  build: function (m) {
263
206
  var status = m.fields.status.value.result;
264
207
  var present = m.fields.timeStampToken.present;
265
- // RFC 3161 sec. 2.4.2 -- granted / grantedWithMods carry a token; any other status
266
- // (rejection / waiting / revocation*) MUST NOT.
267
208
  var granted = status.status === 0 || status.status === 1;
268
209
  if (granted && !present) throw NS.E("tsp/missing-token", "a granted TimeStampResp must carry a timeStampToken (RFC 3161 sec. 2.4.2)");
269
210
  if (!granted && present) throw NS.E("tsp/unexpected-token", "a non-granted TimeStampResp must not carry a timeStampToken (RFC 3161 sec. 2.4.2)");
270
- // failInfo is the reason a request was rejected, so it is present only when the
271
- // status is rejection(2), never on granted(0/1) nor on waiting / revocation* (3/4/5).
272
211
  if (status.status !== 2 && status.failInfo) throw NS.E("tsp/unexpected-failinfo", "failInfo is present only when the status is rejection(2) (RFC 3161 sec. 2.4.2)");
273
- // A granted response's timeStampToken MUST be a well-formed TimeStampToken, so
274
- // decode it (composing the CMS parser) instead of surfacing arbitrary SEQUENCE
275
- // bytes as a token; a malformed token fails the response parse.
276
212
  return {
277
213
  status: status.status,
278
214
  statusString: status.statusString,
@@ -282,13 +218,7 @@ var TIME_STAMP_RESP = schema.seq([
282
218
  },
283
219
  });
284
220
 
285
- // ---- TimeStampReq ----------------------------------------------------
286
221
 
287
- // TimeStampReq ::= SEQUENCE { version INTEGER { v1(1) }, messageImprint MessageImprint,
288
- // reqPolicy TSAPolicyId OPTIONAL, nonce INTEGER OPTIONAL, certReq BOOLEAN DEFAULT FALSE,
289
- // extensions [0] IMPLICIT Extensions OPTIONAL } (RFC 3161 sec. 2.4.1). version + messageImprint
290
- // are mandatory; the three optionals are consumed by universal tag (OID / INTEGER / BOOLEAN),
291
- // then the [0] extensions. certReq DEFAULT FALSE follows the TSTInfo.ordering explicit-FALSE rule.
292
222
  var TIME_STAMP_REQ = schema.seq([
293
223
  schema.field("version", VERSION),
294
224
  schema.field("messageImprint", MESSAGE_IMPRINT),
@@ -301,7 +231,6 @@ var TIME_STAMP_REQ = schema.seq([
301
231
  ], {
302
232
  assert: "sequence", code: "tsp/bad-request", what: "TimeStampReq",
303
233
  build: function (m, ctx) {
304
- // certReq BOOLEAN DEFAULT FALSE -- an explicit FALSE must be omitted under DER.
305
234
  if (m.fields.certReq.present && m.fields.certReq.value === false) {
306
235
  throw NS.E("tsp/bad-request", "certReq is BOOLEAN DEFAULT FALSE -- an explicit FALSE must be omitted (DER)");
307
236
  }
@@ -437,23 +366,13 @@ var parse = pkix.makeParser({ pemLabel: null, PemError: PemError, ErrorClass: Ts
437
366
  * token.signerInfo.sid; // -> the TSA signer identifier
438
367
  */
439
368
  function parseToken(input) {
440
- // De-armor with TSP's label-agnostic PEM rules first (RFC 3161 has no standard
441
- // label), THEN hand DER to the CMS parser -- otherwise cms.parse would reject any
442
- // PEM block not labeled "CMS" before the TSP checks run.
443
369
  var der = pkix.coerceToDer(input, { pemLabel: null, PemError: PemError, ErrorClass: TspError, prefix: "tsp" });
444
- // Wrap the CMS decode so tsp.parse / parseToken keep their typed-TspError contract --
445
- // a malformed token surfaces tsp/bad-token, not a bare cms/* error.
446
370
  var signed;
447
371
  try { signed = cms.parse(der); }
448
372
  catch (e) {
449
373
  if (e instanceof TspError) throw e;
450
374
  throw new TspError("tsp/bad-token", "the timeStampToken did not decode as a CMS SignedData: " + ((e && e.message) || String(e)), e);
451
375
  }
452
- // cms.parse decodes every CMS content type; a TimeStampToken MUST be a
453
- // SignedData (RFC 3161 sec. 2.4.2). Gate on the dispatched content type before
454
- // any SignedData-only field access -- an AuthenticatedData / EnvelopedData
455
- // whose eContentType happens to be id-ct-TSTInfo would otherwise reach a raw
456
- // TypeError on the absent signerInfos.
457
376
  if (signed.contentTypeName !== "signedData") {
458
377
  throw new TspError("tsp/not-signed-data", "a TimeStampToken must be a CMS SignedData, got " + (signed.contentTypeName || signed.contentType));
459
378
  }
@@ -465,12 +384,6 @@ function parseToken(input) {
465
384
  if (signed.signerInfos.length !== 1) {
466
385
  throw new TspError("tsp/multi-signer", "a TimeStampToken must contain exactly one (TSA) signerInfo (RFC 3161 sec. 2.4.2)");
467
386
  }
468
- // RFC 3161 sec. 2.4.2 / RFC 5816 -- the TSA certificate identifier MUST be present
469
- // as a SigningCertificate (or SigningCertificateV2) signed attribute. Presence
470
- // is a structural token property, same altitude as the single-signer rule; the
471
- // hash-vs-certificate BINDING stays a verification-layer concern. signedAttrs
472
- // is non-null here: the CMS parse already required it for a non-id-data
473
- // eContentType (RFC 5652 sec. 5.3), and the eContentType is id-ct-TSTInfo.
474
387
  var signedAttrs = signed.signerInfos[0].signedAttrs || [];
475
388
  var hasSigningCert = false;
476
389
  for (var a = 0; a < signedAttrs.length; a++) {
@@ -485,9 +398,6 @@ function parseToken(input) {
485
398
  if (e instanceof TspError) throw e;
486
399
  throw new TspError("tsp/bad-der", "the encapsulated TSTInfo did not decode: " + ((e && e.message) || String(e)), e);
487
400
  }
488
- // Surface the RAW eContent (the exact DER a verifier hashes for the CMS
489
- // message-digest signed attribute) alongside the decoded TSTInfo -- a re-serialized
490
- // tstInfo may not byte-match, so the raw bytes are the verification feed.
491
401
  return { tstInfo: tstInfo.result, eContent: encap.eContent, signerInfo: signed.signerInfos[0], certificates: signed.certificates };
492
402
  }
493
403
 
@@ -508,9 +418,7 @@ function parseToken(input) {
508
418
  * var pemText = pki.schema.tsp.pemEncode(req, "TSP REQUEST");
509
419
  * var der = pki.schema.tsp.pemDecode(pemText);
510
420
  */
511
- // Decode a raw GeneralName TLV (the tsa field and the ESS issuerSerial issuer are surfaced raw) into
512
- // { tagClass, tagNumber, value } -- for a directoryName [4] the value is a decoded Name { rdns },
513
- // so a verifier canonically compares it (guard.name.dnEqual) rather than by raw bytes. @internal.
421
+ // @internal
514
422
  function decodeGeneralName(bytes) {
515
423
  return schema.embeddedDer(pkix.generalName(NS, { decodeValue: true, code: "tsp/bad-tsa" }), bytes, NS, { code: "tsp/bad-tsa", what: "GeneralName" });
516
424
  }
@@ -535,10 +443,6 @@ function pemDecode(text, label) { return pkix.pemDecode(text, label || null, Pem
535
443
  */
536
444
  function pemEncode(der, label) { return pkix.pemEncode(der, label, PemError); }
537
445
 
538
- // A TimeStampResp root is a SEQUENCE of 1-2 whose first child is a PKIStatusInfo (a
539
- // SEQUENCE whose own first child is an INTEGER status). Disjoint from the OID-first
540
- // CMS ContentInfo, the INTEGER-first PKCS#8 key, and the exactly-3 signed-envelope
541
- // trio, so it detects unambiguously regardless of registry order.
542
446
  function matches(root) {
543
447
  var k = pkix.rootSequenceChildren(root, 1, 2);
544
448
  if (!k) return false;
@@ -551,9 +455,9 @@ function matches(root) {
551
455
 
552
456
  module.exports = {
553
457
  parse: parse,
554
- parseResponse: parse, // TimeStampResp parsing == parse; named for symmetry with parseRequest
458
+ parseResponse: parse,
555
459
  parseRequest: parseRequest,
556
- decodeGeneralName: decodeGeneralName, // @internal -- the verifier's tsa / issuerSerial DN decode
460
+ decodeGeneralName: decodeGeneralName, // @internal
557
461
  parseTstInfo: parseTstInfo,
558
462
  parseToken: parseToken,
559
463
  pemDecode: pemDecode,
@@ -39,7 +39,6 @@ var pkix = require("./schema-pkix");
39
39
  var CertificateError = frameworkError.CertificateError;
40
40
  var PemError = frameworkError.PemError;
41
41
 
42
- // ---- PEM -------------------------------------------------------------
43
42
 
44
43
  /**
45
44
  * @primitive pki.schema.x509.pemDecode
@@ -83,22 +82,12 @@ function pemDecode(text, label) { return pkix.pemDecode(text, label === null ? n
83
82
  */
84
83
  function pemEncode(der, label) { return pkix.pemEncode(der, label, PemError); }
85
84
 
86
- // ---- helpers ---------------------------------------------------------
87
85
 
88
- // The x509 error namespace the schema engine walks under: prefix names the
89
- // error family and E constructs the typed CertificateError. The shared PKIX
90
- // sub-schemas (AlgorithmIdentifier, Name, Extension) live in lib/pkix-schema.js
91
- // as ns-parameterized factories so crl.js / cms.js reuse them while emitting
92
- // their own crl/*, cms/* codes; here they are instantiated under this NS.
93
86
  var NS = pkix.makeNS("x509", CertificateError, oid);
94
87
 
95
88
  var ALGORITHM_IDENTIFIER = pkix.algorithmIdentifier(NS);
96
89
  var NAME = pkix.name(NS);
97
90
 
98
- // Validity ::= SEQUENCE { notBefore Time, notAfter Time } -- the outer tag is
99
- // asserted (a SET-tagged body is a different ASN.1 type, not a Validity).
100
- // pkix.time enforces the RFC 5280 sec. 4.1.2.5 encoding cutover on decode: a
101
- // validity date through 2049 must be UTCTime, GeneralizedTime is 2050 onward.
102
91
  var VALIDITY = schema.seq([
103
92
  schema.field("notBefore", pkix.time(NS)),
104
93
  schema.field("notAfter", pkix.time(NS)),
@@ -107,24 +96,12 @@ var VALIDITY = schema.seq([
107
96
  build: function (m) { return { notBefore: m.fields.notBefore.value, notAfter: m.fields.notAfter.value }; },
108
97
  });
109
98
 
110
- // SubjectPublicKeyInfo -- the shared pkix.spki factory under the x509 NS.
111
99
  var SPKI = pkix.spki(NS);
112
100
 
113
101
  var EXTENSIONS = pkix.extensions(NS);
114
102
 
115
- // Version ::= INTEGER { v1(0), v2(1), v3(2) }, [0] EXPLICIT DEFAULT v1. Read as a
116
- // BigInt so an out-of-range value can't coerce to a float; reject an explicitly-
117
- // encoded v1 (DER forbids encoding the DEFAULT).
118
- // version ::= INTEGER { v1(0), v2(1), v3(2) } inside a [0] EXPLICIT DEFAULT v1 --
119
- // DER forbids encoding the default, so 0 is rejected; 1->v2, 2->v3.
120
103
  var CERTIFICATE_VERSION = pkix.versionReader(NS, { "1": 2, "2": 3 });
121
104
 
122
- // TBSCertificate ::= SEQUENCE { version [0] EXPLICIT DEFAULT v1, serialNumber
123
- // INTEGER, signature AlgorithmIdentifier, issuer Name, validity Validity,
124
- // subject Name, subjectPublicKeyInfo SubjectPublicKeyInfo, issuerUniqueID [1]
125
- // IMPLICIT OPTIONAL, subjectUniqueID [2] IMPLICIT OPTIONAL, extensions [3]
126
- // EXPLICIT OPTIONAL }. The trailing fields are at-most-once, in increasing tag
127
- // order (the engine enforces it); only extensions are surfaced.
128
105
  var CERTIFICATE_TBS = schema.seq([
129
106
  schema.optional("version", CERTIFICATE_VERSION, { tag: 0, explicit: true, emptyCode: "x509/bad-version", default: 1 }),
130
107
  schema.field("serialNumber", schema.integerLeaf()),
@@ -134,49 +111,33 @@ var CERTIFICATE_TBS = schema.seq([
134
111
  schema.field("subject", NAME),
135
112
  schema.field("subjectPublicKeyInfo", SPKI),
136
113
  schema.trailing([
137
- // RFC 5280 sec. 4.1.2.8 -- the unique identifiers are [n] IMPLICIT BIT
138
- // STRING (context PRIMITIVE, unusedBits validated), never an EXPLICIT wrap.
139
114
  { tag: 1, name: "issuerUniqueID", schema: schema.implicitBitString(1) },
140
115
  { tag: 2, name: "subjectUniqueID", schema: schema.implicitBitString(2) },
141
116
  { tag: 3, name: "extensions", schema: EXTENSIONS, explicit: true, emptyCode: "x509/bad-extensions" },
142
117
  ], { minTag: 1, maxTag: 3, unexpectedCode: "x509/bad-tbs", orderCode: "x509/bad-tbs" }),
143
118
  ], { assert: "sequence", code: "x509/bad-tbs", what: "tbsCertificate" });
144
119
 
145
- // Certificate ::= SEQUENCE { tbsCertificate, signatureAlgorithm, signatureValue
146
- // BIT STRING }. The build runs the RFC 5280 cross-field checks (sec. 4.1.1.2 sig-alg
147
- // agreement, sec. 4.1.2.4 non-empty issuer, sec. 4.1.2.9 extensions-only-in-v3) after the
148
- // structural walk, then assembles the public parse result. Raw-byte accessors
149
- // (serialNumberHex, tbsBytes, sig-alg agreement) read off the match-tree nodes.
150
- // Certificate ::= SEQUENCE { tbsCertificate, signatureAlgorithm, signatureValue }
151
- // -- the shared SIGNED envelope. The certificate-specific invariants (outer==inner
152
- // signatureAlgorithm agreement, non-empty issuer, v3-only extensions) live in the
153
- // build; the envelope owns the SEQUENCE-of-3 shape and signature extraction.
154
120
  var CERTIFICATE = pkix.signedEnvelope(NS, CERTIFICATE_TBS, {
155
121
  code: "x509/not-a-certificate", what: "Certificate",
156
122
  build: function (e, ctx) {
157
- var tbs = e.tbsMatch; // CERTIFICATE_TBS seq-match (no build)
123
+ var tbs = e.tbsMatch;
158
124
 
159
- // RFC 5280 sec. 4.1.1.2 -- outer signatureAlgorithm MUST equal tbsCertificate.signature.
160
125
  if (!e.outerSignatureAlgorithmBytes.equals(tbs.fields.signature.node.bytes)) {
161
126
  throw ctx.E("x509/bad-signature-algorithm", "signatureAlgorithm must match tbsCertificate.signature (RFC 5280 sec. 4.1.1.2)");
162
127
  }
163
128
 
164
- var version = tbs.fields.version.value; // 1 (default) | 2 | 3
129
+ var version = tbs.fields.version.value;
165
130
  var issuer = tbs.fields.issuer.value.result;
166
- // RFC 5280 sec. 4.1.2.4 -- issuer MUST be non-empty (an empty subject is permitted, sec. 4.1.2.6).
167
131
  if (!issuer.rdns.length) {
168
132
  throw ctx.E("x509/bad-issuer", "issuer must be a non-empty distinguished name");
169
133
  }
170
134
 
171
135
  var extField = tbs.fields.extensions;
172
136
  var hasExtensions = !!(extField && extField.present);
173
- // RFC 5280 sec. 4.1.2.9 -- extensions appear only in a v3 certificate.
174
137
  if (hasExtensions && version !== 3) {
175
138
  throw ctx.E("x509/bad-version", "extensions are only permitted in a v3 certificate");
176
139
  }
177
140
 
178
- // RFC 5280 sec. 4.1.2.8 -- issuerUniqueID / subjectUniqueID MUST NOT
179
- // appear when the version is 1; they require a v2 or v3 certificate.
180
141
  if ((tbs.fields.issuerUniqueID.present || tbs.fields.subjectUniqueID.present) && version < 2) {
181
142
  throw ctx.E("x509/bad-version", "issuerUniqueID/subjectUniqueID require a v2 or v3 certificate (RFC 5280 sec. 4.1.2.8)");
182
143
  }
@@ -199,7 +160,6 @@ var CERTIFICATE = pkix.signedEnvelope(NS, CERTIFICATE_TBS, {
199
160
  },
200
161
  });
201
162
 
202
- // ---- parse -----------------------------------------------------------
203
163
 
204
164
  /**
205
165
  * @primitive pki.schema.x509.parse
@@ -232,34 +192,15 @@ var CERTIFICATE = pkix.signedEnvelope(NS, CERTIFICATE_TBS, {
232
192
  * cert.validity.notAfter; // Date
233
193
  * cert.signatureAlgorithm.name; // "Ed25519" (the algorithm the issuer signed with)
234
194
  */
235
- // The parser RECORDS the bytes it read, off the returned object, so a verb that computes a verdict
236
- // can re-derive from them instead of trusting the object it was handed.
237
- //
238
- // Completeness alone cannot carry a certificate's meaning. A certificate is one signature over one
239
- // byte range, but a parsed certificate presents that range (`tbsBytes`), the signature, and every
240
- // field the range encodes as separate properties. Keep a real CA certificate's signed bytes and
241
- // signature and replace only `subjectPublicKeyInfo`, and the signature check still passes over the
242
- // original range while the substituted key is what gets used to verify the next certificate in the
243
- // chain -- a forged chain out of a genuine certificate. Emptying `extensions` is the same move
244
- // against basicConstraints, keyUsage, name constraints, and the unknown-critical rule.
245
- //
246
- // Recording the source is what makes the object safe to accept: the verdict verbs parse it again
247
- // from these bytes, so anything done to the object afterwards is discarded rather than believed.
248
195
  var parse = pkix.makeRecordingParser({ pemLabel: "CERTIFICATE", PemError: PemError, ErrorClass: CertificateError, prefix: "x509", what: "certificate", topSchema: CERTIFICATE, ns: NS }, "certificate");
249
196
 
250
- // matches(root): does the decoded DER look like a Certificate? A CSR and a CRL
251
- // share the outer SEQUENCE-of-3 envelope, so the discriminator is inside the
252
- // tbs: a certificate has a Validity -- a SEQUENCE of exactly two Time values -- at
253
- // position [serial, signature, issuer, VALIDITY] after the optional [0] version.
254
- // A CSR's certificationRequestInfo has subjectPublicKeyInfo there (no Validity),
255
- // and a CRL leads with a bare Time; neither matches. Used by the orchestrator.
256
197
  function matches(root) {
257
198
  var TAGS = asn1.TAGS;
258
199
  var tbs = pkix.signedEnvelopeTbs(root);
259
200
  if (!tbs) return false;
260
201
  var kids = tbs.children;
261
- var i = schema.isContext(kids[0], 0) ? 1 : 0; // optional [0] version
262
- var validity = kids[i + 3]; // serial(i), signature(i+1), issuer(i+2), validity(i+3)
202
+ var i = schema.isContext(kids[0], 0) ? 1 : 0;
203
+ var validity = kids[i + 3];
263
204
  return schema.isUniversal(validity, TAGS.SEQUENCE) &&
264
205
  !!validity.children && validity.children.length === 2 &&
265
206
  validity.children.every(function (t) {