@amritk/nish-x86_64-linux 0.24.0 → 0.25.0

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 (42) hide show
  1. package/bin/nish +0 -0
  2. package/docs/AI.md +24 -4
  3. package/package.json +1 -1
  4. package/runtime/browser.mjs +4 -3
  5. package/runtime/core/host.d.ts +8 -0
  6. package/runtime/core/host.mjs +50 -2
  7. package/runtime/nish.d.ts +100 -0
  8. package/runtime/nish.h +34 -0
  9. package/runtime/nish.mjs +21 -0
  10. package/runtime/node.mjs +57 -6
  11. package/runtime/runtime-net.c +44 -3
  12. package/runtime/runtime-os.c +115 -12
  13. package/scripts/build.sh +13 -3
  14. package/std/README.md +25 -8
  15. package/std/cli-args.ts +1216 -0
  16. package/std/cli-flags.ts +585 -0
  17. package/std/cli.ts +308 -19
  18. package/std/compress/checksum.ts +132 -20
  19. package/std/compress/deflate.ts +638 -248
  20. package/std/compress/gzip.ts +20 -6
  21. package/std/crypto/LICENSE-fiat-crypto-p384 +21 -0
  22. package/std/crypto/p256.ts +63 -1
  23. package/std/crypto/p384.ts +6044 -0
  24. package/std/crypto/pki-roots.ts +322 -0
  25. package/std/crypto/pki.ts +1207 -0
  26. package/std/crypto/rsa.ts +663 -0
  27. package/std/crypto/x509.ts +1054 -58
  28. package/std/net/dns-config.ts +734 -0
  29. package/std/net/dns-message.ts +517 -0
  30. package/std/net/dns-resolver.ts +1015 -0
  31. package/std/net/dns.ts +478 -0
  32. package/std/net/http1-client.ts +1227 -0
  33. package/std/net/http1-server.ts +7 -2
  34. package/std/net/http1.ts +9 -9
  35. package/std/net/tls/client.ts +1094 -0
  36. package/std/net/tls/codec.ts +585 -3
  37. package/std/net/tls/record-client.ts +1192 -0
  38. package/std/net/tls/verify.ts +221 -0
  39. package/std/net/tls-tcp.ts +642 -11
  40. package/std/net/tls.ts +2 -2
  41. package/std/net/url.ts +559 -4
  42. package/std/yaml-write.ts +415 -0
@@ -17,9 +17,10 @@
17
17
  * // derToPem(der, "CERTIFICATE") is the file a TLS stack loads.
18
18
  *
19
19
  * Written for this module from ITU-T X.690 (DER), RFC 5280 (the certificate
20
- * profile), RFC 7468 (PEM's textual encoding), RFC 5915 and RFC 5208/5958 (the
21
- * SEC1 and PKCS#8 private-key structures), RFC 5480 (the P-256 key's
22
- * identifiers) and RFC 5758 (ecdsa-with-SHA256).
20
+ * profile and its extensions), RFC 7468 (PEM's textual encoding), RFC 5915 and
21
+ * RFC 5208/5958 (the SEC1 and PKCS#8 private-key structures), RFC 5480 (the
22
+ * elliptic-curve key identifiers), RFC 5758 (ECDSA with SHA-2), RFC 4055 (RSA
23
+ * PKCS#1 v1.5 and RSASSA-PSS identifiers) and RFC 8410 (Ed25519).
23
24
  *
24
25
  * **DER is read strictly.** X.690 §10 leaves one encoding per value, and a
25
26
  * reader that accepts a second spelling gives a certificate two identities
@@ -28,10 +29,15 @@
28
29
  * zero length octet), an INTEGER must be minimal in two's complement, a tag
29
30
  * must fit in one octet, every element must end inside its parent, and a
30
31
  * certificate must end where its outer SEQUENCE does. Anything else answers
31
- * `null`, never a panic. The reader looks at what this module uses — the
32
- * version, serial, algorithms, names as opaque bytes, validity, the subject
33
- * public key and the signature — and checks the order of what follows the key
34
- * (`[1]`, `[2]`, `[3]`) without parsing extensions; the mint writes two of its
32
+ * `null`, never a panic. The reader takes the version, serial, algorithms,
33
+ * the issuer and subject Names (their RDNs checked, their bytes kept whole),
34
+ * validity, the subject public key and the signature, checks the order of what
35
+ * follows the key (`[1]`, `[2]`, `[3]`), and decodes the extensions a path
36
+ * validator needs: subjectAltName, basicConstraints, keyUsage, extKeyUsage,
37
+ * nameConstraints and the two key identifiers. A duplicate or malformed one
38
+ * refuses the certificate, and any other critical one sets `unknownCritical`.
39
+ * It parses and does not validate: no module in `std/` does RFC 5280 §6 path
40
+ * validation yet, so applying these is the caller's. The mint writes two extensions of its
35
41
  * own (below).
36
42
  *
37
43
  * **PEM is RFC 7468's strict grammar**, with standard base64 (`+` and `/`,
@@ -106,18 +112,83 @@ export const X509_MAX_DAYS: i32 = 14
106
112
  /** Longest serial number, in content octets of its INTEGER (RFC 5280 §4.1.2.2). */
107
113
  export const X509_MAX_SERIAL: i32 = 20
108
114
 
115
+ /** `X509Certificate.sigAlg`: a signature algorithm this module does not name, or one with parameters it does not accept. */
116
+ export const X509_SIG_UNKNOWN: i32 = 0
117
+ /** ecdsa-with-SHA256, parameters absent (RFC 5758 §3.2). */
118
+ export const X509_SIG_ECDSA_SHA256: i32 = 1
119
+ /** ecdsa-with-SHA384, parameters absent (RFC 5758 §3.2). */
120
+ export const X509_SIG_ECDSA_SHA384: i32 = 2
121
+ /** sha256WithRSAEncryption, parameters NULL (RFC 4055 §5). */
122
+ export const X509_SIG_RSA_PKCS1_SHA256: i32 = 3
123
+ /** sha384WithRSAEncryption, parameters NULL. */
124
+ export const X509_SIG_RSA_PKCS1_SHA384: i32 = 4
125
+ /** sha512WithRSAEncryption, parameters NULL. */
126
+ export const X509_SIG_RSA_PKCS1_SHA512: i32 = 5
127
+ /**
128
+ * RSASSA-PSS (RFC 4055 §3.1) with a SHA-2 hash, MGF1 over that same hash and
129
+ * the trailer 1; the hash is in `pssHash` and the salt length in `pssSaltLen`.
130
+ */
131
+ export const X509_SIG_RSA_PSS: i32 = 6
132
+ /** Ed25519, parameters absent (RFC 8410 §3). */
133
+ export const X509_SIG_ED25519: i32 = 7
134
+ /** sha1WithRSAEncryption, parameters NULL: recognised so that a verifier can refuse it by name. */
135
+ export const X509_SIG_RSA_PKCS1_SHA1: i32 = 8
136
+
137
+ /** `X509Certificate.keyType`: a key algorithm this module does not name. */
138
+ export const X509_KEY_UNKNOWN: i32 = 0
139
+ /** id-ecPublicKey on secp256r1 (RFC 5480 §2.1.1): the same test as `p256`. */
140
+ export const X509_KEY_P256: i32 = 1
141
+ /** id-ecPublicKey on secp384r1 (RFC 5480 §2.1.1.1). */
142
+ export const X509_KEY_P384: i32 = 2
143
+ /** rsaEncryption with NULL parameters (RFC 3279 §2.3.1); `publicKey` is the RSAPublicKey DER. */
144
+ export const X509_KEY_RSA: i32 = 3
145
+ /** id-Ed25519 with parameters absent (RFC 8410 §3). */
146
+ export const X509_KEY_ED25519: i32 = 4
147
+
148
+ /** `X509Certificate.pssHash`: SHA-256. */
149
+ export const X509_HASH_SHA256: i32 = 1
150
+ /** SHA-384. */
151
+ export const X509_HASH_SHA384: i32 = 2
152
+ /** SHA-512. */
153
+ export const X509_HASH_SHA512: i32 = 3
154
+
155
+ /** `X509GeneralSubtree.kind`: a dNSName, in `dns`. */
156
+ export const X509_GN_DNS: i32 = 1
157
+ /** An iPAddress range, `ip` under `mask`. */
158
+ export const X509_GN_IP: i32 = 2
159
+ /** A directoryName, the Name's DER in `dirName`. */
160
+ export const X509_GN_DIR: i32 = 3
161
+ /** Any other GeneralName form: rfc822Name, URI, otherName and the rest, which this module keeps no value for. */
162
+ export const X509_GN_OTHER: i32 = 4
163
+
164
+ /** `X509Certificate.keyUsage` bits (RFC 5280 §4.2.1.3): bit 0 is digitalSignature. */
165
+ export const X509_KU_DIGITAL_SIGNATURE: i32 = 1
166
+ /** keyCertSign, bit 5. */
167
+ export const X509_KU_KEY_CERT_SIGN: i32 = 32
168
+ /** cRLSign, bit 6. */
169
+ export const X509_KU_CRL_SIGN: i32 = 64
170
+
109
171
  /** The longest common name minted, in bytes (RFC 5280 Appendix A's `ub-common-name`). */
110
172
  const X509_MAX_COMMON_NAME: i32 = 64
111
173
 
174
+ /**
175
+ * The most extensions a certificate may carry. A Web PKI certificate carries
176
+ * fewer than 20; the cap bounds the repeated-extnID search, which compares
177
+ * each extension with every one before it.
178
+ */
179
+ const X509_MAX_EXTENSIONS: i32 = 64
180
+
112
181
  /** What a time field reads as when it is not a valid RFC 5280 time: before any year the reader accepts. */
113
182
  const X509_NO_TIME: i64 = -1000000000000
114
183
 
115
184
  const X509_MS_PER_DAY: i64 = 86400000
116
185
 
117
186
  // DER tags (X.690 §8, and the context tags RFC 5280 gives them).
187
+ const X509_TAG_BOOLEAN: i32 = 0x01
118
188
  const X509_TAG_INTEGER: i32 = 0x02
119
189
  const X509_TAG_BIT_STRING: i32 = 0x03
120
190
  const X509_TAG_OCTET_STRING: i32 = 0x04
191
+ const X509_TAG_NULL: i32 = 0x05
121
192
  const X509_TAG_OID: i32 = 0x06
122
193
  const X509_TAG_UTF8_STRING: i32 = 0x0c
123
194
  const X509_TAG_UTC_TIME: i32 = 0x17
@@ -125,12 +196,38 @@ const X509_TAG_GENERALIZED_TIME: i32 = 0x18
125
196
  const X509_TAG_SEQUENCE: i32 = 0x30
126
197
  const X509_TAG_SET: i32 = 0x31
127
198
 
199
+ /**
200
+ * One subtree of a nameConstraints extension (RFC 5280 §4.2.1.10): its base
201
+ * name's form in `kind`, and the value of the forms this module reads. A
202
+ * subtree whose `minimum` or `maximum` is present keeps its base here and sets
203
+ * the certificate's `ncUnsupported`.
204
+ */
205
+ export class X509GeneralSubtree {
206
+ /** `X509_GN_DNS`, `X509_GN_IP`, `X509_GN_DIR` or `X509_GN_OTHER`. */
207
+ kind: i32 = 0
208
+ /** For a dNSName, its IA5 bytes exactly as encoded, with no case folded; `""` may be the whole tree. */
209
+ dns: string = ""
210
+ /** For an iPAddress, the address: 4 octets or 16. */
211
+ ip: u8[]
212
+ /** For an iPAddress, the mask, as long as `ip` and contiguous. */
213
+ mask: u8[]
214
+ /** For a directoryName, the Name's DER, whole. */
215
+ dirName: u8[]
216
+
217
+ constructor() {
218
+ this.ip = []
219
+ this.mask = []
220
+ this.dirName = []
221
+ }
222
+ }
223
+
128
224
  /**
129
225
  * One certificate, as `x509ParseCertificate` and `x509ParseChain` read it.
130
226
  * The byte fields are copies, so the certificate outlives the text it was read
131
227
  * from. Times are milliseconds since 1970-01-01 UTC, as `Date.now()` counts.
132
228
  */
133
229
  export class X509Certificate {
230
+ // Widest first, which leaves no padding: pointers and i64s, then i32s, then booleans.
134
231
  /** The whole certificate, as its SHA-256 is taken. */
135
232
  der: u8[]
136
233
  /** The DER of `tbsCertificate`, the bytes the signature covers. */
@@ -149,10 +246,61 @@ export class X509Certificate {
149
246
  notBefore: i64 = 0
150
247
  /** The last instant it is valid, inclusive. */
151
248
  notAfter: i64 = 0
249
+ /** subjectAltName's dNSNames, the IA5 bytes exactly as encoded, with no case folded. */
250
+ sanDns: string[]
251
+ /** subjectAltName's iPAddresses, 4 octets or 16 each. */
252
+ sanIp: u8[][]
253
+ /** nameConstraints' permittedSubtrees, in order. */
254
+ ncPermitted: X509GeneralSubtree[]
255
+ /** nameConstraints' excludedSubtrees, in order. */
256
+ ncExcluded: X509GeneralSubtree[]
257
+ /** The subjectKeyIdentifier (RFC 5280 §4.2.1.2), or `null`. */
258
+ skid: u8[] | null = null
259
+ /** The authorityKeyIdentifier's keyIdentifier (RFC 5280 §4.2.1.1), or `null`. */
260
+ akid: u8[] | null = null
261
+ /** The version as encoded: 0 for v1, 1 for v2, 2 for v3. */
262
+ version: i32 = 0
263
+ /** The signature algorithm, an `X509_SIG_` constant. */
264
+ sigAlg: i32 = 0
265
+ /** For RSASSA-PSS, the hash of the message and of MGF1, an `X509_HASH_` constant; else 0. */
266
+ pssHash: i32 = 0
267
+ /** For RSASSA-PSS, the salt length in octets; else 0. */
268
+ pssSaltLen: i32 = 0
269
+ /** The subject key's algorithm, an `X509_KEY_` constant. */
270
+ keyType: i32 = 0
271
+ /**
272
+ * How many of subjectAltName's names are another form: rfc822Name, URI,
273
+ * directoryName and the rest. Each must still be well formed: an rfc822Name
274
+ * or URI is an IA5String like a dNSName, so one with an octet of 0x80 or
275
+ * more, or a NUL, refuses the certificate rather than being counted.
276
+ */
277
+ sanOther: i32 = 0
278
+ /** basicConstraints' pathLenConstraint, or -1 when it is absent (no limit) or the extension is. */
279
+ bcPathLen: i32 = -1
280
+ /** The keyUsage bits (RFC 5280 §4.2.1.3), bit 0 digitalSignature to bit 8 decipherOnly, or -1 when absent. */
281
+ keyUsage: i32 = -1
152
282
  /** Whether the key is id-ecPublicKey on prime256v1 (RFC 5480 §2.1.1), so `publicKey` is a P-256 point. */
153
283
  p256: boolean = false
154
284
  /** Whether the signature algorithm is ecdsa-with-SHA256 with its parameters absent (RFC 5758 §3.2). */
155
285
  ecdsaSha256: boolean = false
286
+ /** Whether a subjectAltName extension is present (RFC 5280 §4.2.1.6). */
287
+ sanPresent: boolean = false
288
+ /** Whether a basicConstraints extension is present (RFC 5280 §4.2.1.9). */
289
+ bcPresent: boolean = false
290
+ /** basicConstraints' cA flag. */
291
+ bcCa: boolean = false
292
+ /** Whether an extKeyUsage extension is present (RFC 5280 §4.2.1.12). */
293
+ ekuPresent: boolean = false
294
+ /** Whether extKeyUsage names id-kp-serverAuth. */
295
+ ekuServerAuth: boolean = false
296
+ /** Whether extKeyUsage names anyExtendedKeyUsage. */
297
+ ekuAny: boolean = false
298
+ /** Whether a nameConstraints extension is present (RFC 5280 §4.2.1.10). */
299
+ ncPresent: boolean = false
300
+ /** Whether any subtree is `X509_GN_OTHER` or carries a `minimum` or `maximum`, which a validator must refuse or understand. */
301
+ ncUnsupported: boolean = false
302
+ /** Whether a critical extension is one this module does not decode: RFC 5280 §4.2 has a verifier refuse it. */
303
+ unknownCritical: boolean = false
156
304
 
157
305
  constructor() {
158
306
  this.der = []
@@ -162,6 +310,10 @@ export class X509Certificate {
162
310
  this.subject = []
163
311
  this.publicKey = []
164
312
  this.signature = []
313
+ this.sanDns = []
314
+ this.sanIp = []
315
+ this.ncPermitted = []
316
+ this.ncExcluded = []
165
317
  }
166
318
  }
167
319
 
@@ -194,12 +346,24 @@ class X509DerElement {
194
346
  * refused before they can overflow.
195
347
  */
196
348
  const x509DerRead = (der: u8[], at: i32, limit: i32): X509DerElement | null => {
197
- if (at < 0 || limit > toI32(der.length) || at > limit - 2) {
349
+ const e = new X509DerElement(0, 0, 0, 0)
350
+ if (!x509DerReadInto(der, at, limit, e)) {
198
351
  return null
199
352
  }
353
+ return e
354
+ }
355
+
356
+ /**
357
+ * `x509DerRead` into `into`, answering whether it read one: what a loop uses
358
+ * so a pass allocates nothing it leaves behind. `into` is unspecified on `false`.
359
+ */
360
+ const x509DerReadInto = (der: u8[], at: i32, limit: i32, into: X509DerElement): boolean => {
361
+ if (at < 0 || limit > toI32(der.length) || at > limit - 2) {
362
+ return false
363
+ }
200
364
  const tag: i32 = toI32(der[at])
201
365
  if ((tag & 0x1f) === 0x1f) {
202
- return null
366
+ return false
203
367
  }
204
368
  let length: i32 = toI32(der[at + 1])
205
369
  let start: i32 = at + 2
@@ -207,24 +371,28 @@ const x509DerRead = (der: u8[], at: i32, limit: i32): X509DerElement | null => {
207
371
  const count: i32 = length & 0x7f
208
372
  // 0x80 alone is BER's indefinite length, which DER forbids.
209
373
  if (count < 1 || count > 4 || count > limit - start) {
210
- return null
374
+ return false
211
375
  }
212
376
  if (toI32(der[start]) === 0 || (count === 4 && toI32(der[start]) >= 0x80)) {
213
- return null
377
+ return false
214
378
  }
215
379
  length = 0
216
380
  for (let k: i32 = 0; k < count; k++) {
217
381
  length = (length << 8) | toI32(der[start + k])
218
382
  }
219
383
  if (length < 0x80) {
220
- return null
384
+ return false
221
385
  }
222
386
  start = start + count
223
387
  }
224
388
  if (length > limit - start) {
225
- return null
389
+ return false
226
390
  }
227
- return new X509DerElement(tag, at, start, start + length)
391
+ into.tag = tag
392
+ into.at = at
393
+ into.start = start
394
+ into.end = start + length
395
+ return true
228
396
  }
229
397
 
230
398
  /** `x509DerRead`, answering `null` also when the element's tag is not `tag`. */
@@ -236,6 +404,10 @@ const x509DerExpect = (der: u8[], at: i32, limit: i32, tag: i32): X509DerElement
236
404
  return e
237
405
  }
238
406
 
407
+ /** `x509DerReadInto`, answering `false` also when the element's tag is not `tag`. */
408
+ const x509DerExpectInto = (der: u8[], at: i32, limit: i32, tag: i32, into: X509DerElement): boolean =>
409
+ x509DerReadInto(der, at, limit, into) && into.tag === tag
410
+
239
411
  /**
240
412
  * The identifier octet at `der[at]` when `at` is inside `der[.. limit)`, else
241
413
  * `-1`: how an optional element is looked for.
@@ -460,6 +632,65 @@ const x509OidPrime256v1 = (): u8[] => x509DerOidContents([1, 2, 840, 10045, 3, 1
460
632
  /** id-at-commonName, 2.5.4.3 (RFC 5280 Appendix A). */
461
633
  const x509OidCommonName = (): u8[] => x509DerOidContents([2, 5, 4, 3])
462
634
 
635
+ /** ecdsa-with-SHA384, 1.2.840.10045.4.3.3 (RFC 5758 §3.2). */
636
+ const x509OidEcdsaSha384 = (): u8[] => x509DerOidContents([1, 2, 840, 10045, 4, 3, 3])
637
+
638
+ /** secp384r1, 1.3.132.0.34 (RFC 5480 §2.1.1.1). */
639
+ const x509OidSecp384r1 = (): u8[] => x509DerOidContents([1, 3, 132, 0, 34])
640
+
641
+ /** The PKCS #1 arc 1.2.840.113549.1.1.`n` (RFC 4055 §2.1 and §5): 1 rsaEncryption, 5, 11, 12 and 13 the PKCS#1 v1.5 signatures, 8 MGF1, 10 RSASSA-PSS. */
642
+ const x509OidPkcs1 = (n: i32): u8[] => x509DerOidContents([1, 2, 840, 113549, 1, 1, n])
643
+
644
+ /** id-Ed25519, 1.3.101.112 (RFC 8410 §3). */
645
+ const x509OidEd25519 = (): u8[] => x509DerOidContents([1, 3, 101, 112])
646
+
647
+ /** The NIST hash arc 2.16.840.1.101.3.4.2.`n` (RFC 4055 §2.1): 1 SHA-256, 2 SHA-384, 3 SHA-512. */
648
+ const x509OidNistHash = (n: i32): u8[] => x509DerOidContents([2, 16, 840, 1, 101, 3, 4, 2, n])
649
+
650
+ // The extensions decoded, by their arc under 2.5.29 (RFC 5280 §4.2.1).
651
+ const X509_CE_SUBJECT_KEY_ID: i32 = 14
652
+ const X509_CE_KEY_USAGE: i32 = 15
653
+ const X509_CE_SUBJECT_ALT_NAME: i32 = 17
654
+ const X509_CE_BASIC_CONSTRAINTS: i32 = 19
655
+ const X509_CE_NAME_CONSTRAINTS: i32 = 30
656
+ const X509_CE_AUTHORITY_KEY_ID: i32 = 35
657
+ const X509_CE_EXT_KEY_USAGE: i32 = 37
658
+
659
+ /** What `x509ReadExtension` answers: an extension it does not decode, one it decoded, one that is malformed. */
660
+ const X509_EXT_UNKNOWN: i32 = 0
661
+ const X509_EXT_SOUND: i32 = 1
662
+ const X509_EXT_MALFORMED: i32 = 2
663
+
664
+ /** id-kp-serverAuth, 1.3.6.1.5.5.7.3.1 (RFC 5280 §4.2.1.12). */
665
+ const x509OidServerAuth = (): u8[] => x509DerOidContents([1, 3, 6, 1, 5, 5, 7, 3, 1])
666
+
667
+ /** anyExtendedKeyUsage, 2.5.29.37.0 (RFC 5280 §4.2.1.12). */
668
+ const x509OidAnyEku = (): u8[] => x509DerOidContents([2, 5, 29, 37, 0])
669
+
670
+ /**
671
+ * Whether an OID's contents are X.690 §8.19's: at least one octet, the last
672
+ * with its top bit clear, and no subidentifier starting with the padding
673
+ * octet `0x80` — so one OID has one spelling, and a duplicate extension cannot
674
+ * hide behind a second.
675
+ */
676
+ const x509DerOidSound = (der: u8[], e: X509DerElement): boolean => {
677
+ if (e.tag !== X509_TAG_OID || e.end <= e.start || toI32(der[e.end - 1]) >= 0x80) {
678
+ return false
679
+ }
680
+ let first: boolean = true
681
+ for (let k: i32 = e.start; k < e.end; k++) {
682
+ // Always true for an element `x509DerRead` gave, and what lets the load drop its check.
683
+ if (k >= 0 && k < toI32(der.length)) {
684
+ const b: i32 = toI32(der[k])
685
+ if (first && b === 0x80) {
686
+ return false
687
+ }
688
+ first = b < 0x80
689
+ }
690
+ }
691
+ return true
692
+ }
693
+
463
694
  /**
464
695
  * Whether `der[start .. end)` is exactly one OID element equal to `oid` and
465
696
  * nothing after it.
@@ -488,11 +719,162 @@ const x509DerIsAlgorithm = (der: u8[], alg: X509DerElement, oid: u8[], params: u
488
719
  }
489
720
 
490
721
  /**
491
- * A minimal, non-negative INTEGER right-aligned into `out[off .. off + 32)`,
492
- * or `false` when it is negative, not minimal or wider than 32 octets once a
493
- * sign octet is set aside.
722
+ * Whether an AlgorithmIdentifier SEQUENCE is `{ oid, NULL }`, the form RFC
723
+ * 4055 §5 and RFC 3279 §2.3.1 give the PKCS#1 v1.5 signatures and the RSA key.
494
724
  */
495
- const x509DerUnsignedInto = (der: u8[], e: X509DerElement, out: u8[], off: i32): boolean => {
725
+ const x509DerIsAlgorithmNull = (der: u8[], alg: X509DerElement, oid: u8[]): boolean => {
726
+ if (alg.tag !== X509_TAG_SEQUENCE) {
727
+ return false
728
+ }
729
+ const id: X509DerElement | null = x509DerExpect(der, alg.start, alg.end, X509_TAG_OID)
730
+ if (id === null || !x509DerContentsAre(der, id, oid)) {
731
+ return false
732
+ }
733
+ const params: X509DerElement | null = x509DerExpect(der, id.end, alg.end, X509_TAG_NULL)
734
+ return params !== null && params.start === params.end && params.end === alg.end
735
+ }
736
+
737
+ /**
738
+ * The `X509_HASH_` constant of a hash AlgorithmIdentifier in `der[start ..
739
+ * end)`, exactly one element: SHA-256, SHA-384 or SHA-512, with its parameters
740
+ * absent or NULL, both of which RFC 4055 §2.1 has a reader accept. 0 otherwise.
741
+ */
742
+ const x509DerHashAlgorithm = (der: u8[], start: i32, end: i32): i32 => {
743
+ const alg: X509DerElement | null = x509DerExpect(der, start, end, X509_TAG_SEQUENCE)
744
+ if (alg === null || alg.end !== end) {
745
+ return 0
746
+ }
747
+ for (let n: i32 = 1; n <= 3; n++) {
748
+ const oid: u8[] = x509OidNistHash(n)
749
+ if (x509DerIsAlgorithm(der, alg, oid, []) || x509DerIsAlgorithmNull(der, alg, oid)) {
750
+ return n
751
+ }
752
+ }
753
+ return 0
754
+ }
755
+
756
+ /** The signature algorithm `X509Certificate` reports, and for RSASSA-PSS its hash and salt length. */
757
+ class X509SigAlg {
758
+ alg: i32 = 0
759
+ hash: i32 = 0
760
+ salt: i32 = 0
761
+ }
762
+
763
+ /**
764
+ * RSASSA-PSS-params (RFC 4055 §3.1) in `der[start .. end)`, the contents of
765
+ * their SEQUENCE: `[0]` hashAlgorithm, `[1]` maskGenAlgorithm, `[2]`
766
+ * saltLength and `[3]` trailerField, each optional and in that order. Named
767
+ * only when the hash is SHA-2 (so `[0]` is present, its DEFAULT being SHA-1),
768
+ * the mask is MGF1 over that same hash, the salt length is 0 to 127 (20 when
769
+ * absent) and the trailer is 1; anything else is `X509_SIG_UNKNOWN`, which a
770
+ * verifier refuses. DER leaves a DEFAULT out (X.690 §11.5), so a salt length
771
+ * of 20 written out, or any trailerField at all (its one value, 1, being the
772
+ * DEFAULT), is unknown too.
773
+ */
774
+ const x509PssParams = (der: u8[], start: i32, end: i32): X509SigAlg => {
775
+ const out = new X509SigAlg()
776
+ const hashWrap: X509DerElement | null = x509DerExpect(der, start, end, 0xa0)
777
+ if (hashWrap === null) {
778
+ return out
779
+ }
780
+ const hash: i32 = x509DerHashAlgorithm(der, hashWrap.start, hashWrap.end)
781
+ const mgfWrap: X509DerElement | null = x509DerExpect(der, hashWrap.end, end, 0xa1)
782
+ if (hash === 0 || mgfWrap === null) {
783
+ return out
784
+ }
785
+ // MaskGenAlgorithm is `SEQUENCE { id-mgf1, HashAlgorithm }`, and the hash
786
+ // must be the message's (RFC 4055 §3.1 recommends it; RFC 8446 §4.2.3 and
787
+ // the CA/Browser Forum require it).
788
+ const mgf: X509DerElement | null = x509DerExpect(der, mgfWrap.start, mgfWrap.end, X509_TAG_SEQUENCE)
789
+ if (mgf === null || mgf.end !== mgfWrap.end) {
790
+ return out
791
+ }
792
+ const mgfId: X509DerElement | null = x509DerExpect(der, mgf.start, mgf.end, X509_TAG_OID)
793
+ if (mgfId === null || !x509DerContentsAre(der, mgfId, x509OidPkcs1(8))) {
794
+ return out
795
+ }
796
+ if (x509DerHashAlgorithm(der, mgfId.end, mgf.end) !== hash) {
797
+ return out
798
+ }
799
+ let at: i32 = mgfWrap.end
800
+ let salt: i32 = 20
801
+ if (x509DerPeek(der, at, end) === 0xa2) {
802
+ const saltWrap: X509DerElement | null = x509DerRead(der, at, end)
803
+ if (saltWrap === null) {
804
+ return out
805
+ }
806
+ const value: X509DerElement | null = x509DerRead(der, saltWrap.start, saltWrap.end)
807
+ if (value === null || value.end !== saltWrap.end) {
808
+ return out
809
+ }
810
+ salt = x509DerSmallInteger(der, value)
811
+ if (salt < 0 || salt === 20) {
812
+ return out
813
+ }
814
+ at = saltWrap.end
815
+ }
816
+ if (at !== end) {
817
+ return out
818
+ }
819
+ out.alg = X509_SIG_RSA_PSS
820
+ out.hash = hash
821
+ out.salt = salt
822
+ return out
823
+ }
824
+
825
+ /** The signature algorithm an AlgorithmIdentifier names, with the parameters RFC 5758, RFC 4055 and RFC 8410 give each. */
826
+ const x509SignatureAlgorithm = (der: u8[], alg: X509DerElement): X509SigAlg => {
827
+ const out = new X509SigAlg()
828
+ if (x509DerIsAlgorithm(der, alg, x509OidEcdsaSha256(), [])) {
829
+ out.alg = X509_SIG_ECDSA_SHA256
830
+ } else if (x509DerIsAlgorithm(der, alg, x509OidEcdsaSha384(), [])) {
831
+ out.alg = X509_SIG_ECDSA_SHA384
832
+ } else if (x509DerIsAlgorithmNull(der, alg, x509OidPkcs1(11))) {
833
+ out.alg = X509_SIG_RSA_PKCS1_SHA256
834
+ } else if (x509DerIsAlgorithmNull(der, alg, x509OidPkcs1(12))) {
835
+ out.alg = X509_SIG_RSA_PKCS1_SHA384
836
+ } else if (x509DerIsAlgorithmNull(der, alg, x509OidPkcs1(13))) {
837
+ out.alg = X509_SIG_RSA_PKCS1_SHA512
838
+ } else if (x509DerIsAlgorithmNull(der, alg, x509OidPkcs1(5))) {
839
+ out.alg = X509_SIG_RSA_PKCS1_SHA1
840
+ } else if (x509DerIsAlgorithm(der, alg, x509OidEd25519(), [])) {
841
+ out.alg = X509_SIG_ED25519
842
+ } else {
843
+ const id: X509DerElement | null = x509DerExpect(der, alg.start, alg.end, X509_TAG_OID)
844
+ if (id !== null && x509DerContentsAre(der, id, x509OidPkcs1(10))) {
845
+ // The parameters are required: RFC 4055 §3.1 gives them no absent form.
846
+ const params: X509DerElement | null = x509DerExpect(der, id.end, alg.end, X509_TAG_SEQUENCE)
847
+ if (params !== null && params.end === alg.end) {
848
+ return x509PssParams(der, params.start, params.end)
849
+ }
850
+ }
851
+ }
852
+ return out
853
+ }
854
+
855
+ /** The `X509_KEY_` constant a SubjectPublicKeyInfo's AlgorithmIdentifier names. */
856
+ const x509KeyType = (der: u8[], alg: X509DerElement): i32 => {
857
+ if (x509DerIsAlgorithm(der, alg, x509OidEcPublicKey(), x509OidPrime256v1())) {
858
+ return X509_KEY_P256
859
+ }
860
+ if (x509DerIsAlgorithm(der, alg, x509OidEcPublicKey(), x509OidSecp384r1())) {
861
+ return X509_KEY_P384
862
+ }
863
+ if (x509DerIsAlgorithmNull(der, alg, x509OidPkcs1(1))) {
864
+ return X509_KEY_RSA
865
+ }
866
+ if (x509DerIsAlgorithm(der, alg, x509OidEd25519(), [])) {
867
+ return X509_KEY_ED25519
868
+ }
869
+ return X509_KEY_UNKNOWN
870
+ }
871
+
872
+ /**
873
+ * A minimal, non-negative INTEGER right-aligned into `out[off .. off +
874
+ * width)`, or `false` when it is negative, not minimal or wider than `width`
875
+ * octets once a sign octet is set aside.
876
+ */
877
+ const x509DerUnsignedInto = (der: u8[], e: X509DerElement, out: u8[], off: i32, width: i32): boolean => {
496
878
  if (!x509DerIntegerMinimal(der, e) || toI32(der[e.start]) >= 0x80) {
497
879
  return false
498
880
  }
@@ -501,23 +883,27 @@ const x509DerUnsignedInto = (der: u8[], e: X509DerElement, out: u8[], off: i32):
501
883
  start = start + 1
502
884
  }
503
885
  const n: i32 = e.end - start
504
- if (n > 32) {
886
+ if (n > width) {
505
887
  return false
506
888
  }
507
889
  for (let k: i32 = 0; k < n; k++) {
508
- out[off + 32 - n + k] = der[start + k]
890
+ out[off + width - n + k] = der[start + k]
509
891
  }
510
892
  return true
511
893
  }
512
894
 
513
895
  /**
514
- * `r || s`, 32 octets each, out of an ECDSA-Sig-Value `SEQUENCE { INTEGER r,
515
- * INTEGER s }` (RFC 5480 §2.2 by way of RFC 3279 §2.2.3), or `null` unless it
516
- * is exactly one with both integers minimal, positive and below 2^256. This is
517
- * the form a TLS `CertificateVerify` or an X.509 signature carries, and
518
- * `nish/crypto/p256` takes the `r || s` it answers.
896
+ * `r || s`, `width` octets each, out of an ECDSA-Sig-Value `SEQUENCE { INTEGER
897
+ * r, INTEGER s }` (RFC 5480 §2.2 by way of RFC 3279 §2.2.3), or `null` unless
898
+ * it is exactly one with both integers minimal, not negative and below
899
+ * 2^(8 * width), and `width` is 32 (P-256) or 48 (P-384). This is the form a
900
+ * TLS `CertificateVerify` or an X.509 signature carries; that each value is
901
+ * below the curve's order is the curve's check.
519
902
  */
520
- export const x509DerSignatureRS = (sig: u8[]): u8[] | null => {
903
+ export const x509DerSignatureRSWidth = (sig: u8[], width: i32): u8[] | null => {
904
+ if (width !== 32 && width !== 48) {
905
+ return null
906
+ }
521
907
  const total: i32 = toI32(sig.length)
522
908
  const seq: X509DerElement | null = x509DerExpect(sig, 0, total, X509_TAG_SEQUENCE)
523
909
  if (seq === null || seq.end !== total) {
@@ -531,13 +917,19 @@ export const x509DerSignatureRS = (sig: u8[]): u8[] | null => {
531
917
  if (s === null || s.end !== seq.end) {
532
918
  return null
533
919
  }
534
- const out: u8[] = new Array<u8>(64)
535
- if (!x509DerUnsignedInto(sig, r, out, 0) || !x509DerUnsignedInto(sig, s, out, 32)) {
920
+ const out: u8[] = new Array<u8>(2 * width)
921
+ if (!x509DerUnsignedInto(sig, r, out, 0, width) || !x509DerUnsignedInto(sig, s, out, width, width)) {
536
922
  return null
537
923
  }
538
924
  return out
539
925
  }
540
926
 
927
+ /**
928
+ * `x509DerSignatureRSWidth` for P-256: `r || s`, 32 octets each, the form
929
+ * `nish/crypto/p256` takes.
930
+ */
931
+ export const x509DerSignatureRS = (sig: u8[]): u8[] | null => x509DerSignatureRSWidth(sig, 32)
932
+
541
933
  // ---------------------------------------------------------------------------
542
934
  // DER, writing
543
935
  // ---------------------------------------------------------------------------
@@ -982,13 +1374,605 @@ export const x509ParseP256PrivateKey = (pem: string): Secret<u8[]> | null => {
982
1374
  // ---------------------------------------------------------------------------
983
1375
 
984
1376
  /**
985
- * Whether a `[3]` extensions wrapper holds one non-empty SEQUENCE and nothing
986
- * after it (RFC 5280 §4.1's `SIZE (1..MAX)`). What an extension says is not
987
- * read.
1377
+ * Whether a Name in `der[e.start .. e.end)`, the contents of its SEQUENCE, is
1378
+ * RFC 5280 §4.1.2.4's `SEQUENCE OF RelativeDistinguishedName`: each RDN a
1379
+ * non-empty SET of `SEQUENCE { type OID, value }`, one element each, nothing
1380
+ * between or after. The values' string types are not read (the common name is
1381
+ * the mint's own), and DER's sorted SET OF is not checked: a validator compares
1382
+ * Names byte for byte, so an unsorted SET only fails to match.
1383
+ */
1384
+ const x509DerNameSound = (der: u8[], e: X509DerElement): boolean => {
1385
+ let at: i32 = e.start
1386
+ while (at < e.end) {
1387
+ const rdn: X509DerElement | null = x509DerExpect(der, at, e.end, X509_TAG_SET)
1388
+ if (rdn === null || rdn.end === rdn.start) {
1389
+ return false
1390
+ }
1391
+ let inner: i32 = rdn.start
1392
+ while (inner < rdn.end) {
1393
+ const pair: X509DerElement | null = x509DerExpect(der, inner, rdn.end, X509_TAG_SEQUENCE)
1394
+ if (pair === null) {
1395
+ return false
1396
+ }
1397
+ const type: X509DerElement | null = x509DerExpect(der, pair.start, pair.end, X509_TAG_OID)
1398
+ if (type === null || !x509DerOidSound(der, type)) {
1399
+ return false
1400
+ }
1401
+ const value: X509DerElement | null = x509DerRead(der, type.end, pair.end)
1402
+ if (value === null || value.end !== pair.end) {
1403
+ return false
1404
+ }
1405
+ inner = pair.end
1406
+ }
1407
+ at = rdn.end
1408
+ }
1409
+ return true
1410
+ }
1411
+
1412
+ /**
1413
+ * Whether two Names are the same: their DER, byte for byte. RFC 5280 §7.1's
1414
+ * comparison — case folded and white space collapsed after a stringprep of
1415
+ * each attribute — is not implemented (X509-12 in docs/security/crypto-x509.md),
1416
+ * so two Names spelled differently that it would match answer `false`. That
1417
+ * fails closed: a chain whose issuer and subject differ only so is not built.
1418
+ */
1419
+ export const x509NameEqual = (a: u8[], b: u8[]): boolean => x509BytesEqual(a, b)
1420
+
1421
+ /**
1422
+ * Whether the Name `base` is a prefix of the Name `name`, both whole DER as
1423
+ * `X509Certificate.issuer` and `subject` hold them: each of `base`'s RDNs is
1424
+ * `name`'s RDN at the same place, byte for byte — how a directoryName
1425
+ * constraint (RFC 5280 §4.2.1.10) is matched. An empty `base` is a prefix of
1426
+ * every Name. `false` when either is not a Name.
1427
+ */
1428
+ export const x509NameIsPrefix = (base: u8[], name: u8[]): boolean => {
1429
+ const b: X509DerElement | null = x509DerExpect(base, 0, toI32(base.length), X509_TAG_SEQUENCE)
1430
+ const n: X509DerElement | null = x509DerExpect(name, 0, toI32(name.length), X509_TAG_SEQUENCE)
1431
+ if (b === null || n === null || b.end !== toI32(base.length) || n.end !== toI32(name.length)) {
1432
+ return false
1433
+ }
1434
+ if (!x509DerNameSound(base, b) || !x509DerNameSound(name, n)) {
1435
+ return false
1436
+ }
1437
+ let atB: i32 = b.start
1438
+ let atN: i32 = n.start
1439
+ while (atB < b.end) {
1440
+ const rdnB: X509DerElement | null = x509DerRead(base, atB, b.end)
1441
+ const rdnN: X509DerElement | null = x509DerRead(name, atN, n.end)
1442
+ if (
1443
+ rdnB === null ||
1444
+ rdnN === null ||
1445
+ !x509BytesEqual(x509DerWhole(base, rdnB), x509DerWhole(name, rdnN))
1446
+ ) {
1447
+ return false
1448
+ }
1449
+ atB = rdnB.end
1450
+ atN = rdnN.end
1451
+ }
1452
+ return true
1453
+ }
1454
+
1455
+ /**
1456
+ * Whether an IA5String's contents are what a name may hold: every octet below
1457
+ * 0x80 (X.680 §41's IA5 is seven-bit), and none NUL, the old
1458
+ * `localhost\0.example` confusion a C reader would cut short.
988
1459
  */
989
- const x509DerExtensionsSound = (der: u8[], e: X509DerElement): boolean => {
1460
+ const x509DerIa5Name = (der: u8[], e: X509DerElement): boolean => {
1461
+ for (let k: i32 = e.start; k < e.end; k++) {
1462
+ // Always true for an element `x509DerRead` gave, and what lets the load drop its check.
1463
+ if (k >= 0 && k < toI32(der.length)) {
1464
+ const b: i32 = toI32(der[k])
1465
+ if (b === 0 || b >= 0x80) {
1466
+ return false
1467
+ }
1468
+ }
1469
+ }
1470
+ return true
1471
+ }
1472
+
1473
+ /** `der[e.start .. e.end)` as a string, one character per octet, as `x509Bytes` reads one back. */
1474
+ const x509DerText = (der: u8[], e: X509DerElement): string => String.fromBytes(der, e.start, e.end)
1475
+
1476
+ /**
1477
+ * The form of one GeneralName (RFC 5280 §4.2.1.6), its IMPLICIT tag checked
1478
+ * against its form — primitive for the strings, the address and the OID,
1479
+ * constructed for the rest — or -1 when it is malformed: a tag no form has, a
1480
+ * name string that is not `x509DerIa5Name`, or a directoryName that is not
1481
+ * exactly one sound Name. An iPAddress's length is the caller's to check,
1482
+ * since a subtree's is twice a name's.
1483
+ */
1484
+ const x509GeneralNameKind = (der: u8[], e: X509DerElement): i32 => {
1485
+ const tag: i32 = e.tag
1486
+ if (tag === 0x82) {
1487
+ return x509DerIa5Name(der, e) ? X509_GN_DNS : -1
1488
+ }
1489
+ if (tag === 0x87) {
1490
+ return X509_GN_IP
1491
+ }
1492
+ if (tag === 0xa4) {
1493
+ const name: X509DerElement | null = x509DerExpect(der, e.start, e.end, X509_TAG_SEQUENCE)
1494
+ return name !== null && name.end === e.end && x509DerNameSound(der, name) ? X509_GN_DIR : -1
1495
+ }
1496
+ // rfc822Name [1] and uniformResourceIdentifier [6] are IA5 strings too.
1497
+ if (tag === 0x81 || tag === 0x86) {
1498
+ return x509DerIa5Name(der, e) ? X509_GN_OTHER : -1
1499
+ }
1500
+ // otherName [0] is `type-id OID, value [0] EXPLICIT ANY`, and registeredID
1501
+ // [8] an IMPLICIT OID.
1502
+ if (tag === 0xa0) {
1503
+ const typeId: X509DerElement | null = x509DerRead(der, e.start, e.end)
1504
+ const value: X509DerElement | null = typeId === null ? null : x509DerExpect(der, typeId.end, e.end, 0xa0)
1505
+ return typeId !== null && x509DerOidSound(der, typeId) && value !== null && value.end === e.end
1506
+ ? X509_GN_OTHER
1507
+ : -1
1508
+ }
1509
+ if (tag === 0x88) {
1510
+ return x509DerOidSound(der, new X509DerElement(X509_TAG_OID, e.at, e.start, e.end)) ? X509_GN_OTHER : -1
1511
+ }
1512
+ // x400Address [3] and ediPartyName [5], whose contents are not read.
1513
+ if (tag === 0xa3 || tag === 0xa5) {
1514
+ return X509_GN_OTHER
1515
+ }
1516
+ return -1
1517
+ }
1518
+
1519
+ /**
1520
+ * subjectAltName (RFC 5280 §4.2.1.6), `SEQUENCE SIZE (1..MAX) OF
1521
+ * GeneralName`, into `out`: each dNSName and iPAddress (4 or 16 octets) kept,
1522
+ * the other forms counted. `false` when it is malformed, or holds an empty
1523
+ * dNSName, which §4.2.1.6 forbids (in a name constraint, empty is every name).
1524
+ */
1525
+ const x509ReadSubjectAltName = (der: u8[], start: i32, end: i32, out: X509Certificate): boolean => {
1526
+ const seq: X509DerElement | null = x509DerExpect(der, start, end, X509_TAG_SEQUENCE)
1527
+ if (seq === null || seq.end !== end || seq.end === seq.start) {
1528
+ return false
1529
+ }
1530
+ // Declared once and read into, so a pass leaves only what it keeps.
1531
+ const name = new X509DerElement(0, 0, 0, 0)
1532
+ let at: i32 = seq.start
1533
+ while (at < seq.end) {
1534
+ if (!x509DerReadInto(der, at, seq.end, name)) {
1535
+ return false
1536
+ }
1537
+ const kind: i32 = x509GeneralNameKind(der, name)
1538
+ const length: i32 = name.end - name.start
1539
+ if (kind === X509_GN_DNS && length > 0) {
1540
+ out.sanDns.push(x509DerText(der, name))
1541
+ } else if (kind === X509_GN_IP && (length === 4 || length === 16)) {
1542
+ out.sanIp.push(x509DerSlice(der, name.start, name.end))
1543
+ } else if (kind === X509_GN_DIR || kind === X509_GN_OTHER) {
1544
+ out.sanOther = out.sanOther + 1
1545
+ } else {
1546
+ return false
1547
+ }
1548
+ at = name.end
1549
+ }
1550
+ out.sanPresent = true
1551
+ return true
1552
+ }
1553
+
1554
+ /**
1555
+ * The value of a minimal, non-negative INTEGER below 2^31, or -1: a
1556
+ * pathLenConstraint, which RFC 5280 §4.2.1.9 makes `INTEGER (0..MAX)`.
1557
+ */
1558
+ const x509DerNonNegative = (der: u8[], e: X509DerElement): i32 => {
1559
+ const n: i32 = e.end - e.start
1560
+ if (e.tag !== X509_TAG_INTEGER || !x509DerIntegerMinimal(der, e) || toI32(der[e.start]) >= 0x80 || n > 4) {
1561
+ return -1
1562
+ }
1563
+ let value: i32 = 0
1564
+ for (let k: i32 = e.start; k < e.end; k++) {
1565
+ // Always true for an element `x509DerRead` gave, and what lets the load drop its check.
1566
+ if (k >= 0 && k < toI32(der.length)) {
1567
+ value = (value << 8) | toI32(der[k])
1568
+ }
1569
+ }
1570
+ return value
1571
+ }
1572
+
1573
+ /** Whether `e` is DER's TRUE, `01 01 ff`: a DEFAULT FALSE is left out (X.690 §11.5), so a present BOOLEAN is TRUE. */
1574
+ const x509DerIsTrue = (der: u8[], e: X509DerElement): boolean =>
1575
+ e.tag === X509_TAG_BOOLEAN && e.end - e.start === 1 && toI32(der[e.start]) === 0xff
1576
+
1577
+ /**
1578
+ * basicConstraints (RFC 5280 §4.2.1.9), `SEQUENCE { cA BOOLEAN DEFAULT FALSE,
1579
+ * pathLenConstraint INTEGER (0..MAX) OPTIONAL }`, into `out`. `false` when it
1580
+ * is malformed: a cA that is not DER's TRUE, a negative or non-minimal path
1581
+ * length, or anything after it.
1582
+ */
1583
+ const x509ReadBasicConstraints = (der: u8[], start: i32, end: i32, out: X509Certificate): boolean => {
1584
+ const seq: X509DerElement | null = x509DerExpect(der, start, end, X509_TAG_SEQUENCE)
1585
+ if (seq === null || seq.end !== end) {
1586
+ return false
1587
+ }
1588
+ let at: i32 = seq.start
1589
+ if (x509DerPeek(der, at, seq.end) === X509_TAG_BOOLEAN) {
1590
+ const ca: X509DerElement | null = x509DerRead(der, at, seq.end)
1591
+ if (ca === null || !x509DerIsTrue(der, ca)) {
1592
+ return false
1593
+ }
1594
+ out.bcCa = true
1595
+ at = ca.end
1596
+ }
1597
+ if (at < seq.end) {
1598
+ const pathLen: X509DerElement | null = x509DerRead(der, at, seq.end)
1599
+ if (pathLen === null || pathLen.end !== seq.end) {
1600
+ return false
1601
+ }
1602
+ out.bcPathLen = x509DerNonNegative(der, pathLen)
1603
+ if (out.bcPathLen < 0) {
1604
+ return false
1605
+ }
1606
+ }
1607
+ out.bcPresent = true
1608
+ return true
1609
+ }
1610
+
1611
+ /**
1612
+ * keyUsage (RFC 5280 §4.2.1.3), a BIT STRING of named bits 0 to 8, into
1613
+ * `out.keyUsage`. `false` when it is malformed: unused bits that are not
1614
+ * zero, no bit set (§4.2.1.3 requires one), a trailing zero bit DER would
1615
+ * have dropped (X.690 §11.2.2), or a bit past decipherOnly.
1616
+ */
1617
+ const x509ReadKeyUsage = (der: u8[], start: i32, end: i32, out: X509Certificate): boolean => {
1618
+ const bits: X509DerElement | null = x509DerExpect(der, start, end, X509_TAG_BIT_STRING)
1619
+ if (bits === null || bits.end !== end || !x509DerBitStringSound(der, bits)) {
1620
+ return false
1621
+ }
1622
+ // An empty BIT STRING (n = 0) needs no test of its own: its unused-bits
1623
+ // count is held to 0, so the bit check below finds no bit set.
1624
+ const n: i32 = bits.end - bits.start - 1
1625
+ if (n > 2) {
1626
+ return false
1627
+ }
1628
+ const unused: i32 = toI32(der[bits.start])
1629
+ if (((toI32(der[bits.end - 1]) >> unused) & 1) !== 1) {
1630
+ return false
1631
+ }
1632
+ let mask: i32 = 0
1633
+ for (let j: i32 = 0; j < n; j++) {
1634
+ const octet: i32 = toI32(der[bits.start + 1 + j])
1635
+ for (let b: i32 = 0; b < 8; b++) {
1636
+ if (((octet >> (7 - b)) & 1) === 1) {
1637
+ const bit: i32 = 8 * j + b
1638
+ mask = mask | (toI32(1) << bit)
1639
+ }
1640
+ }
1641
+ }
1642
+ // Past decipherOnly, bit 8.
1643
+ if (mask >= 512) {
1644
+ return false
1645
+ }
1646
+ out.keyUsage = mask
1647
+ return true
1648
+ }
1649
+
1650
+ /**
1651
+ * extKeyUsage (RFC 5280 §4.2.1.12), `SEQUENCE SIZE (1..MAX) OF KeyPurposeId`,
1652
+ * into `out`: whether it names serverAuth and anyExtendedKeyUsage. `false`
1653
+ * when it is empty or holds anything but sound OIDs.
1654
+ */
1655
+ const x509ReadExtKeyUsage = (der: u8[], start: i32, end: i32, out: X509Certificate): boolean => {
1656
+ const seq: X509DerElement | null = x509DerExpect(der, start, end, X509_TAG_SEQUENCE)
1657
+ if (seq === null || seq.end !== end || seq.end === seq.start) {
1658
+ return false
1659
+ }
1660
+ const serverAuth: u8[] = x509OidServerAuth()
1661
+ const anyEku: u8[] = x509OidAnyEku()
1662
+ let at: i32 = seq.start
1663
+ while (at < seq.end) {
1664
+ const purpose: X509DerElement | null = x509DerExpect(der, at, seq.end, X509_TAG_OID)
1665
+ if (purpose === null || !x509DerOidSound(der, purpose)) {
1666
+ return false
1667
+ }
1668
+ if (x509DerContentsAre(der, purpose, serverAuth)) {
1669
+ out.ekuServerAuth = true
1670
+ } else if (x509DerContentsAre(der, purpose, anyEku)) {
1671
+ out.ekuAny = true
1672
+ }
1673
+ at = purpose.end
1674
+ }
1675
+ out.ekuPresent = true
1676
+ return true
1677
+ }
1678
+
1679
+ /** Whether `mask` is ones and then zeros, as an iPAddress constraint's mask must be (RFC 5280 §4.2.1.10). */
1680
+ const x509MaskContiguous = (mask: u8[]): boolean => {
1681
+ let zeroSeen: boolean = false
1682
+ for (let k: i32 = 0; k < toI32(mask.length); k++) {
1683
+ const octet: i32 = toI32(mask[k])
1684
+ for (let b: i32 = 7; b >= 0; b--) {
1685
+ const one: boolean = ((octet >> b) & 1) === 1
1686
+ if (one && zeroSeen) {
1687
+ return false
1688
+ }
1689
+ zeroSeen = zeroSeen || !one
1690
+ }
1691
+ }
1692
+ return true
1693
+ }
1694
+
1695
+ /** Whether a GeneralSubtree's IMPLICIT `BaseDistance` bound is a minimal, non-negative INTEGER. */
1696
+ const x509DerBoundSound = (der: u8[], e: X509DerElement): boolean =>
1697
+ x509DerIntegerMinimal(der, e) && toI32(der[e.start]) < 0x80
1698
+
1699
+ /**
1700
+ * The GeneralSubtrees filling an IMPLICIT `[0]` or `[1]` of nameConstraints
1701
+ * (RFC 5280 §4.2.1.10), `SIZE (1..MAX) OF GeneralSubtree`, pushed onto
1702
+ * `into`. Each is `SEQUENCE { base GeneralName, minimum [0] DEFAULT 0, maximum
1703
+ * [1] OPTIONAL }`: a subtree with a minimum other than 0, or a maximum, sets
1704
+ * `out.ncUnsupported`, since §4.2.1.10 has the minimum 0 and the maximum
1705
+ * absent. `false` when it is malformed: a minimum of 0 written out (DER leaves
1706
+ * a DEFAULT out), a bound that is not a minimal non-negative INTEGER, anything
1707
+ * else after the base, or an iPAddress that is not 8 or 32 octets or whose
1708
+ * mask is not contiguous.
1709
+ */
1710
+ const x509ReadSubtrees = (
1711
+ der: u8[],
1712
+ e: X509DerElement,
1713
+ into: X509GeneralSubtree[],
1714
+ out: X509Certificate
1715
+ ): boolean => {
1716
+ if (e.end === e.start) {
1717
+ return false
1718
+ }
1719
+ // Declared once and read into, so a pass leaves only the subtree it keeps.
1720
+ const tree = new X509DerElement(0, 0, 0, 0)
1721
+ const base = new X509DerElement(0, 0, 0, 0)
1722
+ const minimum = new X509DerElement(0, 0, 0, 0)
1723
+ const maximum = new X509DerElement(0, 0, 0, 0)
1724
+ let at: i32 = e.start
1725
+ while (at < e.end) {
1726
+ if (!x509DerExpectInto(der, at, e.end, X509_TAG_SEQUENCE, tree)) {
1727
+ return false
1728
+ }
1729
+ if (!x509DerReadInto(der, tree.start, tree.end, base)) {
1730
+ return false
1731
+ }
1732
+ const subtree = new X509GeneralSubtree()
1733
+ subtree.kind = x509GeneralNameKind(der, base)
1734
+ const length: i32 = base.end - base.start
1735
+ if (subtree.kind === X509_GN_DNS) {
1736
+ subtree.dns = x509DerText(der, base)
1737
+ } else if (subtree.kind === X509_GN_IP) {
1738
+ if (length !== 8 && length !== 32) {
1739
+ return false
1740
+ }
1741
+ subtree.ip = x509DerSlice(der, base.start, base.start + length / 2)
1742
+ subtree.mask = x509DerSlice(der, base.start + length / 2, base.end)
1743
+ if (!x509MaskContiguous(subtree.mask)) {
1744
+ return false
1745
+ }
1746
+ } else if (subtree.kind === X509_GN_DIR) {
1747
+ subtree.dirName = x509DerSlice(der, base.start, base.end)
1748
+ } else if (subtree.kind === X509_GN_OTHER) {
1749
+ out.ncUnsupported = true
1750
+ } else {
1751
+ return false
1752
+ }
1753
+ let bound: i32 = base.end
1754
+ if (x509DerPeek(der, bound, tree.end) === 0x80) {
1755
+ if (
1756
+ !x509DerReadInto(der, bound, tree.end, minimum) ||
1757
+ !x509DerBoundSound(der, minimum) ||
1758
+ (minimum.end - minimum.start === 1 && toI32(der[minimum.start]) === 0)
1759
+ ) {
1760
+ return false
1761
+ }
1762
+ out.ncUnsupported = true
1763
+ bound = minimum.end
1764
+ }
1765
+ if (x509DerPeek(der, bound, tree.end) === 0x81) {
1766
+ if (!x509DerReadInto(der, bound, tree.end, maximum) || !x509DerBoundSound(der, maximum)) {
1767
+ return false
1768
+ }
1769
+ out.ncUnsupported = true
1770
+ bound = maximum.end
1771
+ }
1772
+ if (bound !== tree.end) {
1773
+ return false
1774
+ }
1775
+ into.push(subtree)
1776
+ at = tree.end
1777
+ }
1778
+ return true
1779
+ }
1780
+
1781
+ /**
1782
+ * nameConstraints (RFC 5280 §4.2.1.10), `SEQUENCE { permittedSubtrees [0]
1783
+ * OPTIONAL, excludedSubtrees [1] OPTIONAL }`, into `out`. `false` when it is
1784
+ * malformed, or empty, which §4.2.1.10 forbids.
1785
+ */
1786
+ const x509ReadNameConstraints = (der: u8[], start: i32, end: i32, out: X509Certificate): boolean => {
1787
+ const seq: X509DerElement | null = x509DerExpect(der, start, end, X509_TAG_SEQUENCE)
1788
+ if (seq === null || seq.end !== end || seq.end === seq.start) {
1789
+ return false
1790
+ }
1791
+ let at: i32 = seq.start
1792
+ if (x509DerPeek(der, at, seq.end) === 0xa0) {
1793
+ const permitted: X509DerElement | null = x509DerRead(der, at, seq.end)
1794
+ if (permitted === null || !x509ReadSubtrees(der, permitted, out.ncPermitted, out)) {
1795
+ return false
1796
+ }
1797
+ at = permitted.end
1798
+ }
1799
+ if (x509DerPeek(der, at, seq.end) === 0xa1) {
1800
+ const excluded: X509DerElement | null = x509DerRead(der, at, seq.end)
1801
+ if (excluded === null || !x509ReadSubtrees(der, excluded, out.ncExcluded, out)) {
1802
+ return false
1803
+ }
1804
+ at = excluded.end
1805
+ }
1806
+ out.ncPresent = true
1807
+ return at === seq.end
1808
+ }
1809
+
1810
+ /** subjectKeyIdentifier (RFC 5280 §4.2.1.2), one OCTET STRING, into `out.skid`; `false` when it is malformed or empty. */
1811
+ const x509ReadSubjectKeyId = (der: u8[], start: i32, end: i32, out: X509Certificate): boolean => {
1812
+ const id: X509DerElement | null = x509DerExpect(der, start, end, X509_TAG_OCTET_STRING)
1813
+ if (id === null || id.end !== end || id.end === id.start) {
1814
+ return false
1815
+ }
1816
+ out.skid = x509DerSlice(der, id.start, id.end)
1817
+ return true
1818
+ }
1819
+
1820
+ /** Whether `e`'s contents are a non-empty run of well-formed GeneralNames. */
1821
+ const x509GeneralNamesSound = (der: u8[], e: X509DerElement): boolean => {
1822
+ if (e.end === e.start) {
1823
+ return false
1824
+ }
1825
+ let at: i32 = e.start
1826
+ while (at < e.end) {
1827
+ const name: X509DerElement | null = x509DerRead(der, at, e.end)
1828
+ if (name === null || x509GeneralNameKind(der, name) === -1) {
1829
+ return false
1830
+ }
1831
+ at = name.end
1832
+ }
1833
+ return true
1834
+ }
1835
+
1836
+ /**
1837
+ * authorityKeyIdentifier (RFC 5280 §4.2.1.1), `SEQUENCE { keyIdentifier [0]
1838
+ * OPTIONAL, authorityCertIssuer [1] OPTIONAL, authorityCertSerialNumber [2]
1839
+ * OPTIONAL }`, its keyIdentifier, which may not be empty, into `out.akid`.
1840
+ * The other two are held to their order, to being both present or both
1841
+ * absent, as §4.2.1.1 has them, to a non-empty GeneralNames and a minimal
1842
+ * INTEGER, and not kept. `false` when it is malformed.
1843
+ */
1844
+ const x509ReadAuthorityKeyId = (der: u8[], start: i32, end: i32, out: X509Certificate): boolean => {
1845
+ const seq: X509DerElement | null = x509DerExpect(der, start, end, X509_TAG_SEQUENCE)
1846
+ if (seq === null || seq.end !== end) {
1847
+ return false
1848
+ }
1849
+ let at: i32 = seq.start
1850
+ if (x509DerPeek(der, at, seq.end) === 0x80) {
1851
+ const id: X509DerElement | null = x509DerRead(der, at, seq.end)
1852
+ if (id === null || id.end === id.start) {
1853
+ return false
1854
+ }
1855
+ out.akid = x509DerSlice(der, id.start, id.end)
1856
+ at = id.end
1857
+ }
1858
+ if (x509DerPeek(der, at, seq.end) === 0xa1) {
1859
+ const issuer: X509DerElement | null = x509DerRead(der, at, seq.end)
1860
+ const serial: X509DerElement | null =
1861
+ issuer === null ? null : x509DerExpect(der, issuer.end, seq.end, 0x82)
1862
+ if (
1863
+ issuer === null ||
1864
+ serial === null ||
1865
+ !x509GeneralNamesSound(der, issuer) ||
1866
+ !x509DerIntegerMinimal(der, serial)
1867
+ ) {
1868
+ return false
1869
+ }
1870
+ at = serial.end
1871
+ }
1872
+ return at === seq.end
1873
+ }
1874
+
1875
+ /**
1876
+ * One extension's value, the contents of its extnValue OCTET STRING, decoded
1877
+ * into `out` by the arc `ce` it has under 2.5.29: `X509_EXT_SOUND`, or
1878
+ * `X509_EXT_MALFORMED`. An extension this module does not decode answers
1879
+ * `X509_EXT_UNKNOWN` with `out` untouched, and `ce` is -1 for one outside the
1880
+ * arc.
1881
+ */
1882
+ const x509ReadExtension = (der: u8[], ce: i32, start: i32, end: i32, out: X509Certificate): i32 => {
1883
+ let sound: boolean = false
1884
+ if (ce === X509_CE_SUBJECT_ALT_NAME) {
1885
+ sound = x509ReadSubjectAltName(der, start, end, out)
1886
+ } else if (ce === X509_CE_BASIC_CONSTRAINTS) {
1887
+ sound = x509ReadBasicConstraints(der, start, end, out)
1888
+ } else if (ce === X509_CE_KEY_USAGE) {
1889
+ sound = x509ReadKeyUsage(der, start, end, out)
1890
+ } else if (ce === X509_CE_EXT_KEY_USAGE) {
1891
+ sound = x509ReadExtKeyUsage(der, start, end, out)
1892
+ } else if (ce === X509_CE_NAME_CONSTRAINTS) {
1893
+ sound = x509ReadNameConstraints(der, start, end, out)
1894
+ } else if (ce === X509_CE_SUBJECT_KEY_ID) {
1895
+ sound = x509ReadSubjectKeyId(der, start, end, out)
1896
+ } else if (ce === X509_CE_AUTHORITY_KEY_ID) {
1897
+ sound = x509ReadAuthorityKeyId(der, start, end, out)
1898
+ } else {
1899
+ return X509_EXT_UNKNOWN
1900
+ }
1901
+ return sound ? X509_EXT_SOUND : X509_EXT_MALFORMED
1902
+ }
1903
+
1904
+ /** The arc under 2.5.29 an extnID names, 1 to 127 (one octet), or -1 for an OID outside it. */
1905
+ const x509ExtensionArc = (der: u8[], id: X509DerElement): i32 => {
1906
+ if (id.end - id.start !== 3 || toI32(der[id.start]) !== 0x55 || toI32(der[id.start + 1]) !== 0x1d) {
1907
+ return -1
1908
+ }
1909
+ const arc: i32 = toI32(der[id.start + 2])
1910
+ return arc < 0x80 ? arc : -1
1911
+ }
1912
+
1913
+ /**
1914
+ * The `[3]` extensions wrapper read into `out` (RFC 5280 §4.1 and §4.2): one
1915
+ * non-empty SEQUENCE of `SEQUENCE { extnID OID, critical BOOLEAN DEFAULT
1916
+ * FALSE, extnValue OCTET STRING }` and nothing after it. `false` when any is
1917
+ * malformed, a critical flag is not DER's TRUE, an OID appears twice (§4.2:
1918
+ * "MUST NOT include more than one instance"), there are more than
1919
+ * `X509_MAX_EXTENSIONS`, or a decoded extension is malformed. A critical
1920
+ * extension this module does not decode sets `out.unknownCritical`; a
1921
+ * non-critical one is skipped.
1922
+ */
1923
+ const x509ReadExtensions = (der: u8[], e: X509DerElement, out: X509Certificate): boolean => {
990
1924
  const seq: X509DerElement | null = x509DerExpect(der, e.start, e.end, X509_TAG_SEQUENCE)
991
- return seq !== null && seq.end === e.end && seq.end > seq.start
1925
+ if (seq === null || seq.end !== e.end || seq.end === seq.start) {
1926
+ return false
1927
+ }
1928
+ // Every extnID so far, to find a second instance by its encoding, which
1929
+ // `x509DerOidSound` makes the only one.
1930
+ const seen: u8[][] = []
1931
+ // Declared once and read into, so a pass leaves only the extnID it keeps.
1932
+ const ext = new X509DerElement(0, 0, 0, 0)
1933
+ const id = new X509DerElement(0, 0, 0, 0)
1934
+ const flag = new X509DerElement(0, 0, 0, 0)
1935
+ const value = new X509DerElement(0, 0, 0, 0)
1936
+ let at: i32 = seq.start
1937
+ while (at < seq.end) {
1938
+ if (
1939
+ toI32(seen.length) >= X509_MAX_EXTENSIONS ||
1940
+ !x509DerExpectInto(der, at, seq.end, X509_TAG_SEQUENCE, ext)
1941
+ ) {
1942
+ return false
1943
+ }
1944
+ if (!x509DerExpectInto(der, ext.start, ext.end, X509_TAG_OID, id) || !x509DerOidSound(der, id)) {
1945
+ return false
1946
+ }
1947
+ const oid: u8[] = x509DerSlice(der, id.start, id.end)
1948
+ for (const other of seen) {
1949
+ if (x509BytesEqual(other, oid)) {
1950
+ return false
1951
+ }
1952
+ }
1953
+ seen.push(oid)
1954
+ let next: i32 = id.end
1955
+ let critical: boolean = false
1956
+ if (x509DerPeek(der, next, ext.end) === X509_TAG_BOOLEAN) {
1957
+ if (!x509DerReadInto(der, next, ext.end, flag) || !x509DerIsTrue(der, flag)) {
1958
+ return false
1959
+ }
1960
+ critical = true
1961
+ next = flag.end
1962
+ }
1963
+ if (!x509DerExpectInto(der, next, ext.end, X509_TAG_OCTET_STRING, value) || value.end !== ext.end) {
1964
+ return false
1965
+ }
1966
+ const read: i32 = x509ReadExtension(der, x509ExtensionArc(der, id), value.start, value.end, out)
1967
+ if (read === X509_EXT_MALFORMED) {
1968
+ return false
1969
+ }
1970
+ if (read === X509_EXT_UNKNOWN) {
1971
+ out.unknownCritical = out.unknownCritical || critical
1972
+ }
1973
+ at = ext.end
1974
+ }
1975
+ return true
992
1976
  }
993
1977
 
994
1978
  /**
@@ -999,16 +1983,22 @@ const x509DerExtensionsSound = (der: u8[], e: X509DerElement): boolean => {
999
1983
  * to the outer one byte for byte (§4.1.1.2), issuer and subject Names, a
1000
1984
  * Validity of two valid times, a SubjectPublicKeyInfo whose key is whole
1001
1985
  * octets, then only the optional `[1]` and `[2]` unique identifiers (v2 and
1002
- * v3) and `[3]` extensions (v3), in that order, each well formed on the
1003
- * outside. Any algorithm and key type is read; `p256` and `ecdsaSha256` say
1004
- * whether they are this module's.
1986
+ * v3) and `[3]` extensions (v3), in that order. Issuer and subject must be
1987
+ * sound Names. The signature algorithm is named in `sigAlg` (with `pssHash`
1988
+ * and `pssSaltLen` for RSA-PSS) and the key in `keyType`; `p256` and
1989
+ * `ecdsaSha256` say whether they are the ones `x509VerifySignature` checks.
1990
+ *
1991
+ * Extensions are read: subjectAltName, basicConstraints, keyUsage,
1992
+ * extKeyUsage, nameConstraints and the two key identifiers are decoded into
1993
+ * their fields, and `null` is the answer when any of them is malformed or any
1994
+ * extension appears twice. A critical extension it does not decode sets
1995
+ * `unknownCritical`, which RFC 5280 §4.2 obliges a validator to refuse.
1005
1996
  *
1006
1997
  * **A parser, not a validator.** It checks that the bytes are one certificate
1007
- * and nothing else. It does not check the signature (`x509VerifySignature`
1008
- * does), that `notBefore` is not after `notAfter` or that either is near any
1009
- * clock, and it does not read extensions — basicConstraints, keyUsage,
1010
- * subjectAltName and the critical flag RFC 5280 §4.2 obliges a verifier to
1011
- * honour are neither checked nor exposed.
1998
+ * and what its extensions say. It does not check the signature
1999
+ * (`x509VerifySignature` does), that `notBefore` is not after `notAfter` or
2000
+ * that either is near any clock, or what the extensions mean for a chain,
2001
+ * which is a path validator's to apply.
1012
2002
  */
1013
2003
  export const x509ParseCertificate = (der: u8[]): X509Certificate | null => {
1014
2004
  const total: i32 = toI32(der.length)
@@ -1059,7 +2049,7 @@ export const x509ParseCertificate = (der: u8[]): X509Certificate | null => {
1059
2049
  return null
1060
2050
  }
1061
2051
  const issuer: X509DerElement | null = x509DerExpect(der, alg.end, tbs.end, X509_TAG_SEQUENCE)
1062
- if (issuer === null) {
2052
+ if (issuer === null || !x509DerNameSound(der, issuer)) {
1063
2053
  return null
1064
2054
  }
1065
2055
  const validity: X509DerElement | null = x509DerExpect(der, issuer.end, tbs.end, X509_TAG_SEQUENCE)
@@ -1075,7 +2065,7 @@ export const x509ParseCertificate = (der: u8[]): X509Certificate | null => {
1075
2065
  return null
1076
2066
  }
1077
2067
  const subject: X509DerElement | null = x509DerExpect(der, validity.end, tbs.end, X509_TAG_SEQUENCE)
1078
- if (subject === null) {
2068
+ if (subject === null || !x509DerNameSound(der, subject)) {
1079
2069
  return null
1080
2070
  }
1081
2071
  const spki: X509DerElement | null = x509DerExpect(der, subject.end, tbs.end, X509_TAG_SEQUENCE)
@@ -1094,18 +2084,19 @@ export const x509ParseCertificate = (der: u8[]): X509Certificate | null => {
1094
2084
  if (publicKey === null) {
1095
2085
  return null
1096
2086
  }
2087
+ const out = new X509Certificate()
1097
2088
  at = spki.end
1098
2089
  // [1] issuerUniqueID and [2] subjectUniqueID are IMPLICIT BIT STRINGs (so
1099
- // primitive, 0x81 and 0x82) from v2; [3] extensions is explicit (0xa3), v3.
1100
- // Each is held to its outer shape; what it says is not read.
2090
+ // primitive, 0x81 and 0x82) from v2, held to their shape and not read; [3]
2091
+ // extensions is explicit (0xa3), v3, and read into `out`.
1101
2092
  const trailing: i32[] = [0x81, 0x82, 0xa3]
1102
- for (let i: i32 = 0; i < 3; i++) {
2093
+ const e = new X509DerElement(0, 0, 0, 0)
2094
+ for (let i: i32 = 0; i < toI32(trailing.length); i++) {
1103
2095
  if (x509DerPeek(der, at, tbs.end) === trailing[i]) {
1104
- const e: X509DerElement | null = x509DerRead(der, at, tbs.end)
1105
- if (e === null || version < (i === 2 ? 2 : 1)) {
2096
+ if (!x509DerReadInto(der, at, tbs.end, e) || version < (i === 2 ? 2 : 1)) {
1106
2097
  return null
1107
2098
  }
1108
- if (i === 2 ? !x509DerExtensionsSound(der, e) : !x509DerBitStringSound(der, e)) {
2099
+ if (i === 2 ? !x509ReadExtensions(der, e, out) : !x509DerBitStringSound(der, e)) {
1109
2100
  return null
1110
2101
  }
1111
2102
  at = e.end
@@ -1120,18 +2111,23 @@ export const x509ParseCertificate = (der: u8[]): X509Certificate | null => {
1120
2111
  if (before === X509_NO_TIME || after === X509_NO_TIME) {
1121
2112
  return null
1122
2113
  }
1123
- const out = new X509Certificate()
2114
+ const sigAlg: X509SigAlg = x509SignatureAlgorithm(der, outerAlg)
2115
+ out.version = version
2116
+ out.sigAlg = sigAlg.alg
2117
+ out.pssHash = sigAlg.hash
2118
+ out.pssSaltLen = sigAlg.salt
2119
+ out.keyType = x509KeyType(der, keyAlg)
1124
2120
  out.der = x509DerSlice(der, 0, total)
1125
2121
  out.tbs = x509DerWhole(der, tbs)
1126
2122
  out.serial = x509DerSlice(der, serial.start, serial.end)
1127
2123
  out.issuer = x509DerWhole(der, issuer)
1128
2124
  out.subject = x509DerWhole(der, subject)
1129
2125
  out.publicKey = publicKey
1130
- out.p256 = x509DerIsAlgorithm(der, keyAlg, x509OidEcPublicKey(), x509OidPrime256v1())
2126
+ out.p256 = out.keyType === X509_KEY_P256
1131
2127
  out.notBefore = before
1132
2128
  out.notAfter = after
1133
2129
  out.signature = signature
1134
- out.ecdsaSha256 = x509DerIsAlgorithm(der, outerAlg, x509OidEcdsaSha256(), [])
2130
+ out.ecdsaSha256 = out.sigAlg === X509_SIG_ECDSA_SHA256
1135
2131
  return out
1136
2132
  }
1137
2133
 
@@ -1144,9 +2140,10 @@ export const x509ParseCertificate = (der: u8[]): X509Certificate | null => {
1144
2140
  * **It reads a chain; it does not validate one.** Nothing relates one
1145
2141
  * certificate to the next: not the order, not that each is issued by the one
1146
2142
  * after it (issuer against subject, or signature), not validity against a
1147
- * clock, basicConstraints, keyUsage, name constraints or a trust anchor. RFC
1148
- * 5280 §6's path validation is not in this module, and a chain it answers is
1149
- * no evidence that anyone vouches for the leaf.
2143
+ * clock, nor what each one's basicConstraints, keyUsage and name constraints
2144
+ * allow, nor a trust anchor. Nothing here does RFC 5280 §6's path
2145
+ * validation, and a chain this answers is no evidence that anyone
2146
+ * vouches for the leaf.
1150
2147
  */
1151
2148
  export const x509ParseChain = (pem: string): X509Certificate[] | null => {
1152
2149
  const blocks: u8[][] | null = pemToDer(pem, "CERTIFICATE")
@@ -1170,9 +2167,8 @@ export const x509ParseChain = (pem: string): X509Certificate[] | null => {
1170
2167
  * as both. `false` for any other algorithm or key, and for a signature that is
1171
2168
  * not a DER ECDSA-Sig-Value. Only the signature: that `cert.issuer` is
1172
2169
  * `issuer.subject` and that the times hold are fields the caller compares, and
1173
- * whether `issuer` may issue at all (basicConstraints, keyUsage) is in
1174
- * extensions this module does not read, so a `true` here is not path
1175
- * validation.
2170
+ * whether `issuer` may issue at all (`bcCa`, `keyUsage`) is a path
2171
+ * validator's to decide, so a `true` here is not path validation.
1176
2172
  */
1177
2173
  export const x509VerifySignature = (cert: X509Certificate, issuer: X509Certificate): boolean => {
1178
2174
  if (!cert.ecdsaSha256 || !issuer.p256) {