@amritk/nish-x86_64-linux 0.14.0 → 0.16.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.
@@ -0,0 +1,1331 @@
1
+ /**
2
+ * `nish/crypto/x509` — DER, PEM and the X.509 certificates a WebTransport or
3
+ * TLS server holds: read a P-256 private key and a certificate chain out of
4
+ * PEM, and mint the short-lived self-signed ECDSA P-256 certificate a browser
5
+ * pins by its SHA-256.
6
+ *
7
+ * import { x509MintSelfSigned, x509CertificateHash, derToPem } from "nish/crypto/x509";
8
+ *
9
+ * // Both secrets come from the kernel's CSPRNG; a predictable key or serial is the caller's bug.
10
+ * const priv: u8[] = new Array<u8>(32);
11
+ * crypto.getRandomValues(priv); // p256PublicKey(priv) === null: draw again (odds 2^-32)
12
+ * const serial: u8[] = new Array<u8>(16);
13
+ * crypto.getRandomValues(serial);
14
+ * serial[0] = serial[0] & toU8(0x7f); // positive, so it stays 16 octets
15
+ * const der: u8[] | null = x509MintSelfSigned(priv, "localhost", toI64(Date.now()), 14, serial);
16
+ * // x509CertificateHash(der) is what serverCertificateHashes names;
17
+ * // derToPem(der, "CERTIFICATE") is the file a TLS stack loads.
18
+ *
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).
23
+ *
24
+ * **DER is read strictly.** X.690 §10 leaves one encoding per value, and a
25
+ * reader that accepts a second spelling gives a certificate two identities
26
+ * while its hash — which is what a browser pins — names only one. So a length
27
+ * must be definite and minimal (no `0x80`, no long form below 128, no leading
28
+ * zero length octet), an INTEGER must be minimal in two's complement, a tag
29
+ * must fit in one octet, every element must end inside its parent, and a
30
+ * 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.
35
+ *
36
+ * **PEM is RFC 7468's strict grammar**, with standard base64 (`+` and `/`,
37
+ * padded with `=`), not `base64url`: 64 characters a line and a shorter last
38
+ * one, a `-----END` label equal to its `-----BEGIN`, no headers (so an
39
+ * RFC 1421 encrypted key is refused), and canonical base64 whose unused low
40
+ * bits are zero. Text between blocks is ignored, as RFC 7468 §5.2 allows, and
41
+ * so are blocks with another label; a line may end in CRLF.
42
+ *
43
+ * **The minted certificate** is what the WebTransport specification's
44
+ * `serverCertificateHashes` accepts (W3C WebTransport, "custom certificate
45
+ * requirements"): X.509 v3, an ECDSA P-256 key signed with ecdsa-with-SHA256,
46
+ * and a validity period of at most fourteen days — `notAfter - notBefore`,
47
+ * which is what Chromium compares, so `days` is 1 to 14. Subject and issuer
48
+ * are the same single common name, as a UTF8String. It carries **no
49
+ * extensions**: the specification requires none, a browser checking a pinned
50
+ * hash does no path building for basicConstraints or keyUsage to inform, and
51
+ * every extension would be one more field whose absence is part of the
52
+ * contract a hash pins. OpenSSL verifies it as its own trust anchor all the
53
+ * same (`tests/link/crypto_x509`'s header has the commands). The key, the
54
+ * serial and the time are parameters so the golden certificate is
55
+ * deterministic; a caller passes `Date.now()` and, for the key and the serial,
56
+ * bytes from `crypto.getRandomValues`. This module does not draw them itself,
57
+ * because a call to the operating system would stop it compiling for wasm32.
58
+ *
59
+ * **Constant time.** A private key is the one secret that passes through here:
60
+ * it is base64-decoded from PEM, lifted out of its DER, and handed to
61
+ * `nish/crypto/p256`. Base64 maps a character to its sextet and back by
62
+ * arithmetic on range masks, as `nish/crypto/base64url` does, and folds a bad
63
+ * character into one word read after the whole text, so neither a branch nor a
64
+ * table index depends on the key's bytes. PEM's framing is found by comparing
65
+ * the start of each line with the fixed `-----BEGIN ` and `-----END `, which no
66
+ * base64 character matches, so those comparisons end on a line's first byte
67
+ * whatever the key is. The DER reader branches on tags and
68
+ * lengths, which are the key's public framing, and copies its 32 octets with a
69
+ * fixed loop. Signing is `p256SignSha256`, and checking a key against the
70
+ * public key stored beside it compares public values. None of this is under
71
+ * the disassembly check; it is discipline.
72
+ *
73
+ * Private names carry the `x509` prefix because a `std/` module's private
74
+ * functions share the importing program's flat symbol namespace
75
+ * (`docs/wp26-stdlib.md` §3e).
76
+ */
77
+ import { p256PublicKey, p256SignSha256, p256VerifySha256 } from "nish/crypto/p256"
78
+ import { sha256 } from "nish/crypto/sha256"
79
+
80
+ /** The longest validity `x509MintSelfSigned` writes, in days: WebTransport's two weeks. */
81
+ export const X509_MAX_DAYS: i32 = 14
82
+
83
+ /** Longest serial number, in content octets of its INTEGER (RFC 5280 §4.1.2.2). */
84
+ export const X509_MAX_SERIAL: i32 = 20
85
+
86
+ /** The longest common name minted, in bytes (RFC 5280 Appendix A's `ub-common-name`). */
87
+ const X509_MAX_COMMON_NAME: i32 = 64
88
+
89
+ /** What a time field reads as when it is not a valid RFC 5280 time: before any year the reader accepts. */
90
+ const X509_NO_TIME: i64 = -1000000000000
91
+
92
+ const X509_MS_PER_DAY: i64 = 86400000
93
+
94
+ // DER tags (X.690 §8, and the context tags RFC 5280 gives them).
95
+ const X509_TAG_INTEGER: i32 = 0x02
96
+ const X509_TAG_BIT_STRING: i32 = 0x03
97
+ const X509_TAG_OCTET_STRING: i32 = 0x04
98
+ const X509_TAG_OID: i32 = 0x06
99
+ const X509_TAG_UTF8_STRING: i32 = 0x0c
100
+ const X509_TAG_UTC_TIME: i32 = 0x17
101
+ const X509_TAG_GENERALIZED_TIME: i32 = 0x18
102
+ const X509_TAG_SEQUENCE: i32 = 0x30
103
+ const X509_TAG_SET: i32 = 0x31
104
+
105
+ /**
106
+ * One certificate, as `x509ParseCertificate` and `x509ParseChain` read it.
107
+ * The byte fields are copies, so the certificate outlives the text it was read
108
+ * from. Times are milliseconds since 1970-01-01 UTC, as `Date.now()` counts.
109
+ */
110
+ export class X509Certificate {
111
+ /** The whole certificate, as its SHA-256 is taken. */
112
+ der: u8[]
113
+ /** The DER of `tbsCertificate`, the bytes the signature covers. */
114
+ tbs: u8[]
115
+ /** The serial number's INTEGER contents, two's complement as encoded. */
116
+ serial: u8[]
117
+ /** The issuer Name's DER, whole, to compare with another certificate's `subject`. */
118
+ issuer: u8[]
119
+ /** The subject Name's DER, whole. */
120
+ subject: u8[]
121
+ /** The subjectPublicKey BIT STRING's octets: for a P-256 key, the 65-byte uncompressed point. */
122
+ publicKey: u8[]
123
+ /** The signatureValue BIT STRING's octets: for ECDSA, the DER `SEQUENCE { r, s }`. */
124
+ signature: u8[]
125
+ /** The first instant the certificate is valid, inclusive (RFC 5280 §4.1.2.5). */
126
+ notBefore: i64 = 0
127
+ /** The last instant it is valid, inclusive. */
128
+ notAfter: i64 = 0
129
+ /** Whether the key is id-ecPublicKey on prime256v1 (RFC 5480 §2.1.1), so `publicKey` is a P-256 point. */
130
+ p256: boolean = false
131
+ /** Whether the signature algorithm is ecdsa-with-SHA256 with its parameters absent (RFC 5758 §3.2). */
132
+ ecdsaSha256: boolean = false
133
+
134
+ constructor() {
135
+ this.der = []
136
+ this.tbs = []
137
+ this.serial = []
138
+ this.issuer = []
139
+ this.subject = []
140
+ this.publicKey = []
141
+ this.signature = []
142
+ }
143
+ }
144
+
145
+ // ---------------------------------------------------------------------------
146
+ // DER, reading (X.690 §8 and §10)
147
+ // ---------------------------------------------------------------------------
148
+
149
+ /** One element's identifier octet and where its contents lie: `der[start .. end)`. */
150
+ class X509DerElement {
151
+ tag: i32
152
+ /** Where the identifier octet is, so the whole element can be copied. */
153
+ at: i32
154
+ start: i32
155
+ end: i32
156
+
157
+ constructor(tag: i32, at: i32, start: i32, end: i32) {
158
+ this.tag = tag
159
+ this.at = at
160
+ this.start = start
161
+ this.end = end
162
+ }
163
+ }
164
+
165
+ /**
166
+ * The element whose identifier octet is at `der[at]`, or `null` unless its
167
+ * header and contents lie in `der[at .. limit)` and its length is DER's: definite
168
+ * (§10.1) and minimal (§8.1.3.5 note 2 with §10.1 — long form only from 128,
169
+ * with no leading zero octet). A tag needing more than one octet is refused,
170
+ * since nothing in a certificate or a key uses one; lengths past 2^31 - 1 are
171
+ * refused before they can overflow.
172
+ */
173
+ const x509DerRead = (der: u8[], at: i32, limit: i32): X509DerElement | null => {
174
+ if (at < 0 || limit > toI32(der.length) || at > limit - 2) {
175
+ return null
176
+ }
177
+ const tag: i32 = toI32(der[at])
178
+ if ((tag & 0x1f) === 0x1f) {
179
+ return null
180
+ }
181
+ let length: i32 = toI32(der[at + 1])
182
+ let start: i32 = at + 2
183
+ if (length >= 0x80) {
184
+ const count: i32 = length & 0x7f
185
+ // 0x80 alone is BER's indefinite length, which DER forbids.
186
+ if (count < 1 || count > 4 || count > limit - start) {
187
+ return null
188
+ }
189
+ if (toI32(der[start]) === 0 || (count === 4 && toI32(der[start]) >= 0x80)) {
190
+ return null
191
+ }
192
+ length = 0
193
+ for (let k: i32 = 0; k < count; k++) {
194
+ length = (length << 8) | toI32(der[start + k])
195
+ }
196
+ if (length < 0x80) {
197
+ return null
198
+ }
199
+ start = start + count
200
+ }
201
+ if (length > limit - start) {
202
+ return null
203
+ }
204
+ return new X509DerElement(tag, at, start, start + length)
205
+ }
206
+
207
+ /** `x509DerRead`, answering `null` also when the element's tag is not `tag`. */
208
+ const x509DerExpect = (der: u8[], at: i32, limit: i32, tag: i32): X509DerElement | null => {
209
+ const e: X509DerElement | null = x509DerRead(der, at, limit)
210
+ if (e === null || e.tag !== tag) {
211
+ return null
212
+ }
213
+ return e
214
+ }
215
+
216
+ /**
217
+ * The identifier octet at `der[at]` when `at` is inside `der[.. limit)`, else
218
+ * `-1`: how an optional element is looked for.
219
+ */
220
+ const x509DerPeek = (der: u8[], at: i32, limit: i32): i32 => {
221
+ if (at < 0 || at >= limit || at >= toI32(der.length)) {
222
+ return -1
223
+ }
224
+ return toI32(der[at])
225
+ }
226
+
227
+ /** A copy of `der[from .. to)`. */
228
+ const x509DerSlice = (der: u8[], from: i32, to: i32): u8[] => {
229
+ const out: u8[] = new Array<u8>(to - from)
230
+ for (let k: i32 = 0; k < toI32(out.length); k++) {
231
+ const i: i32 = from + k
232
+ // Always true for the callers' ranges, and what lets the load drop its check.
233
+ if (i >= 0 && i < toI32(der.length)) {
234
+ out[k] = der[i]
235
+ }
236
+ }
237
+ return out
238
+ }
239
+
240
+ /** A copy of the element whole, identifier and length octets included. */
241
+ const x509DerWhole = (der: u8[], e: X509DerElement): u8[] => x509DerSlice(der, e.at, e.end)
242
+
243
+ /** Whether two byte strings are equal. Both are public here. */
244
+ const x509BytesEqual = (a: u8[], b: u8[]): boolean => {
245
+ if (toI32(b.length) !== toI32(a.length)) {
246
+ return false
247
+ }
248
+ for (let k: i32 = 0; k < toI32(a.length); k++) {
249
+ if (k < toI32(b.length) && a[k] !== b[k]) {
250
+ return false
251
+ }
252
+ }
253
+ return true
254
+ }
255
+
256
+ /** Whether `e`'s contents are exactly `expected`, as an OID is recognised by its encoding. */
257
+ const x509DerContentsAre = (der: u8[], e: X509DerElement, expected: u8[]): boolean => {
258
+ const n: i32 = toI32(expected.length)
259
+ if (e.end - e.start !== n) {
260
+ return false
261
+ }
262
+ for (let k: i32 = 0; k < n; k++) {
263
+ if (der[e.start + k] !== expected[k]) {
264
+ return false
265
+ }
266
+ }
267
+ return true
268
+ }
269
+
270
+ /**
271
+ * Whether an INTEGER's contents are DER's (X.690 §8.3.2): at least one octet,
272
+ * and the first nine bits neither all zero nor all one, which would make the
273
+ * first octet redundant.
274
+ */
275
+ const x509DerIntegerMinimal = (der: u8[], e: X509DerElement): boolean => {
276
+ const n: i32 = e.end - e.start
277
+ if (n < 1) {
278
+ return false
279
+ }
280
+ if (n === 1) {
281
+ return true
282
+ }
283
+ const b0: i32 = toI32(der[e.start])
284
+ const b1: i32 = toI32(der[e.start + 1])
285
+ return !((b0 === 0 && b1 < 0x80) || (b0 === 0xff && b1 >= 0x80))
286
+ }
287
+
288
+ /** The value of a one-octet, non-negative INTEGER such as a version, or `-1`. */
289
+ const x509DerSmallInteger = (der: u8[], e: X509DerElement): i32 => {
290
+ if (e.tag !== X509_TAG_INTEGER || e.end - e.start !== 1 || toI32(der[e.start]) >= 0x80) {
291
+ return -1
292
+ }
293
+ return toI32(der[e.start])
294
+ }
295
+
296
+ /**
297
+ * Whether `e`'s contents are a DER BIT STRING's, whatever its tag (an IMPLICIT
298
+ * one keeps the grammar): an unused-bits count of 0 to 7, none without an
299
+ * octet to hold them, and those bits zero (X.690 §8.6.2 and §11.2.1).
300
+ */
301
+ const x509DerBitStringSound = (der: u8[], e: X509DerElement): boolean => {
302
+ const n: i32 = e.end - e.start
303
+ if (n < 1) {
304
+ return false
305
+ }
306
+ const unused: i32 = toI32(der[e.start])
307
+ if (unused > 7 || (n === 1 && unused !== 0)) {
308
+ return false
309
+ }
310
+ return (toI32(der[e.end - 1]) & ((1 << unused) - 1)) === 0
311
+ }
312
+
313
+ /**
314
+ * The octets of a BIT STRING that has no unused bits, or `null`. Keys and
315
+ * signatures are whole octets, so the leading unused-bits count must be 0.
316
+ */
317
+ const x509DerBitStringOctets = (der: u8[], e: X509DerElement): u8[] | null => {
318
+ if (e.tag !== X509_TAG_BIT_STRING || !x509DerBitStringSound(der, e) || toI32(der[e.start]) !== 0) {
319
+ return null
320
+ }
321
+ return x509DerSlice(der, e.start + 1, e.end)
322
+ }
323
+
324
+ /** `count` decimal digits at `der[at ..)` as a number, or `-1` if any is not a digit. */
325
+ const x509DerDigits = (der: u8[], at: i32, count: i32): i32 => {
326
+ let value: i32 = 0
327
+ for (let k: i32 = 0; k < count; k++) {
328
+ const d: i32 = toI32(der[at + k]) - 48
329
+ if (d < 0 || d > 9) {
330
+ return -1
331
+ }
332
+ value = value * 10 + d
333
+ }
334
+ return value
335
+ }
336
+
337
+ /** Whether `year` is a leap year of the Gregorian calendar. */
338
+ const x509IsLeapYear = (year: i32): boolean => (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0
339
+
340
+ /** Days in `month` (1 to 12) of `year`. */
341
+ const x509DaysInMonth = (year: i32, month: i32): i32 => {
342
+ if (month === 2) {
343
+ return x509IsLeapYear(year) ? 29 : 28
344
+ }
345
+ return month === 4 || month === 6 || month === 9 || month === 11 ? 30 : 31
346
+ }
347
+
348
+ /**
349
+ * Days from 1970-01-01 to `year`-`month`-`day`: the days of the years between,
350
+ * counted by the leap-year rule over whole years before each, and then the
351
+ * months of the year itself. `year` is at least 1.
352
+ */
353
+ const x509DaysFromCivil = (year: i32, month: i32, day: i32): i32 => {
354
+ const y: i32 = year - 1
355
+ const before: i32 = 365 * y + y / 4 - y / 100 + y / 400
356
+ // 1969 * 365 + 492 - 19 + 4: the same count for 1970.
357
+ let days: i32 = before - 719162
358
+ for (let m: i32 = 1; m < month; m++) {
359
+ days = days + x509DaysInMonth(year, m)
360
+ }
361
+ return days + day - 1
362
+ }
363
+
364
+ /**
365
+ * A UTCTime or GeneralizedTime in the forms RFC 5280 §4.1.2.5 allows —
366
+ * `YYMMDDHHMMSSZ` and `YYYYMMDDHHMMSSZ`, in UTC, with seconds and without a
367
+ * fraction — as milliseconds since 1970, or `X509_NO_TIME`. A two-digit year
368
+ * of 50 or more is 19YY and below 50 is 20YY (§4.1.2.5.1). Both forms are
369
+ * accepted for any year from 1950, though §4.1.2.5 asks issuers to use UTCTime
370
+ * through 2049; the fields must name a real date and a time before 24:00:00.
371
+ */
372
+ const x509DerTime = (der: u8[], e: X509DerElement): i64 => {
373
+ const n: i32 = e.end - e.start
374
+ let at: i32 = e.start
375
+ let year: i32 = 0
376
+ if (e.tag === X509_TAG_UTC_TIME && n === 13) {
377
+ year = x509DerDigits(der, at, 2)
378
+ if (year >= 0) {
379
+ year = year + (year >= 50 ? 1900 : 2000)
380
+ }
381
+ at = at + 2
382
+ } else if (e.tag === X509_TAG_GENERALIZED_TIME && n === 15) {
383
+ year = x509DerDigits(der, at, 4)
384
+ at = at + 4
385
+ } else {
386
+ return X509_NO_TIME
387
+ }
388
+ const month: i32 = x509DerDigits(der, at, 2)
389
+ const day: i32 = x509DerDigits(der, at + 2, 2)
390
+ const hour: i32 = x509DerDigits(der, at + 4, 2)
391
+ const minute: i32 = x509DerDigits(der, at + 6, 2)
392
+ const second: i32 = x509DerDigits(der, at + 8, 2)
393
+ if (toI32(der[at + 10]) !== 90 || year < 1950 || month < 1 || month > 12) {
394
+ return X509_NO_TIME
395
+ }
396
+ if (day < 1 || day > x509DaysInMonth(year, month) || hour < 0 || hour > 23) {
397
+ return X509_NO_TIME
398
+ }
399
+ if (minute < 0 || minute > 59 || second < 0 || second > 59) {
400
+ return X509_NO_TIME
401
+ }
402
+ const seconds: i32 = hour * 3600 + minute * 60 + second
403
+ return toI64(x509DaysFromCivil(year, month, day)) * X509_MS_PER_DAY + toI64(seconds) * 1000
404
+ }
405
+
406
+ /**
407
+ * The OID's contents octets (X.690 §8.19): the first two arcs as one
408
+ * subidentifier `40 * a + b`, then each arc in base 128, big-endian, with the
409
+ * top bit set on every octet but its last.
410
+ */
411
+ const x509DerOidContents = (arcs: i32[]): u8[] => {
412
+ const out: u8[] = []
413
+ for (let i: i32 = 1; i < toI32(arcs.length); i++) {
414
+ const arc: i32 = i === 1 ? arcs[0] * 40 + arcs[1] : arcs[i]
415
+ let shift: i32 = 28
416
+ while (shift > 0 && arc >> shift === 0) {
417
+ shift = shift - 7
418
+ }
419
+ while (shift > 0) {
420
+ out.push(toU8(((arc >> shift) & 0x7f) | 0x80))
421
+ shift = shift - 7
422
+ }
423
+ out.push(toU8(arc & 0x7f))
424
+ }
425
+ return out
426
+ }
427
+
428
+ /** ecdsa-with-SHA256, 1.2.840.10045.4.3.2 (RFC 5758 §3.2). */
429
+ const x509OidEcdsaSha256 = (): u8[] => x509DerOidContents([1, 2, 840, 10045, 4, 3, 2])
430
+
431
+ /** id-ecPublicKey, 1.2.840.10045.2.1 (RFC 5480 §2.1.1). */
432
+ const x509OidEcPublicKey = (): u8[] => x509DerOidContents([1, 2, 840, 10045, 2, 1])
433
+
434
+ /** secp256r1, also called prime256v1 and P-256: 1.2.840.10045.3.1.7 (RFC 5480 §2.1.1.1). */
435
+ const x509OidPrime256v1 = (): u8[] => x509DerOidContents([1, 2, 840, 10045, 3, 1, 7])
436
+
437
+ /** id-at-commonName, 2.5.4.3 (RFC 5280 Appendix A). */
438
+ const x509OidCommonName = (): u8[] => x509DerOidContents([2, 5, 4, 3])
439
+
440
+ /**
441
+ * Whether `der[start .. end)` is exactly one OID element equal to `oid` and
442
+ * nothing after it.
443
+ */
444
+ const x509DerIsOnlyOid = (der: u8[], start: i32, end: i32, oid: u8[]): boolean => {
445
+ const e: X509DerElement | null = x509DerExpect(der, start, end, X509_TAG_OID)
446
+ return e !== null && e.end === end && x509DerContentsAre(der, e, oid)
447
+ }
448
+
449
+ /**
450
+ * Whether an AlgorithmIdentifier SEQUENCE is `{ oid, params }` with `params`
451
+ * the named-curve OID given, or `{ oid }` alone when `params` is empty.
452
+ */
453
+ const x509DerIsAlgorithm = (der: u8[], alg: X509DerElement, oid: u8[], params: u8[]): boolean => {
454
+ if (alg.tag !== X509_TAG_SEQUENCE) {
455
+ return false
456
+ }
457
+ const id: X509DerElement | null = x509DerExpect(der, alg.start, alg.end, X509_TAG_OID)
458
+ if (id === null || !x509DerContentsAre(der, id, oid)) {
459
+ return false
460
+ }
461
+ if (toI32(params.length) === 0) {
462
+ return id.end === alg.end
463
+ }
464
+ return x509DerIsOnlyOid(der, id.end, alg.end, params)
465
+ }
466
+
467
+ /**
468
+ * A minimal, non-negative INTEGER right-aligned into `out[off .. off + 32)`,
469
+ * or `false` when it is negative, not minimal or wider than 32 octets once a
470
+ * sign octet is set aside.
471
+ */
472
+ const x509DerUnsignedInto = (der: u8[], e: X509DerElement, out: u8[], off: i32): boolean => {
473
+ if (!x509DerIntegerMinimal(der, e) || toI32(der[e.start]) >= 0x80) {
474
+ return false
475
+ }
476
+ let start: i32 = e.start
477
+ if (toI32(der[start]) === 0 && e.end - start > 1) {
478
+ start = start + 1
479
+ }
480
+ const n: i32 = e.end - start
481
+ if (n > 32) {
482
+ return false
483
+ }
484
+ for (let k: i32 = 0; k < n; k++) {
485
+ out[off + 32 - n + k] = der[start + k]
486
+ }
487
+ return true
488
+ }
489
+
490
+ /**
491
+ * `r || s`, 32 octets each, out of an ECDSA-Sig-Value `SEQUENCE { INTEGER r,
492
+ * INTEGER s }` (RFC 5480 §2.2 by way of RFC 3279 §2.2.3), or `null` unless it
493
+ * is exactly one with both integers minimal, positive and below 2^256. This is
494
+ * the form a TLS `CertificateVerify` or an X.509 signature carries, and
495
+ * `nish/crypto/p256` takes the `r || s` it answers.
496
+ */
497
+ export const x509DerSignatureRS = (sig: u8[]): u8[] | null => {
498
+ const total: i32 = toI32(sig.length)
499
+ const seq: X509DerElement | null = x509DerExpect(sig, 0, total, X509_TAG_SEQUENCE)
500
+ if (seq === null || seq.end !== total) {
501
+ return null
502
+ }
503
+ const r: X509DerElement | null = x509DerExpect(sig, seq.start, seq.end, X509_TAG_INTEGER)
504
+ if (r === null) {
505
+ return null
506
+ }
507
+ const s: X509DerElement | null = x509DerExpect(sig, r.end, seq.end, X509_TAG_INTEGER)
508
+ if (s === null || s.end !== seq.end) {
509
+ return null
510
+ }
511
+ const out: u8[] = new Array<u8>(64)
512
+ if (!x509DerUnsignedInto(sig, r, out, 0) || !x509DerUnsignedInto(sig, s, out, 32)) {
513
+ return null
514
+ }
515
+ return out
516
+ }
517
+
518
+ // ---------------------------------------------------------------------------
519
+ // DER, writing
520
+ // ---------------------------------------------------------------------------
521
+
522
+ /** One element: `tag`, the minimal definite length of `contents` (X.690 §10.1), and `contents`. */
523
+ const x509DerTlv = (tag: i32, contents: u8[]): u8[] => {
524
+ const n: i32 = toI32(contents.length)
525
+ const out: u8[] = [toU8(tag)]
526
+ if (n < 0x80) {
527
+ out.push(toU8(n))
528
+ } else {
529
+ let count: i32 = 0
530
+ for (let v: i32 = n; v > 0; v = v >> 8) {
531
+ count = count + 1
532
+ }
533
+ out.push(toU8(0x80 | count))
534
+ for (let k: i32 = count - 1; k >= 0; k--) {
535
+ out.push(toU8((n >> (8 * k)) & 0xff))
536
+ }
537
+ }
538
+ for (let k: i32 = 0; k < toI32(contents.length); k++) {
539
+ out.push(contents[k])
540
+ }
541
+ return out
542
+ }
543
+
544
+ /** `parts` end to end. */
545
+ const x509DerConcat = (parts: u8[][]): u8[] => {
546
+ const out: u8[] = []
547
+ for (const part of parts) {
548
+ for (let k: i32 = 0; k < toI32(part.length); k++) {
549
+ out.push(part[k])
550
+ }
551
+ }
552
+ return out
553
+ }
554
+
555
+ /** A constructed element around `parts`: a SEQUENCE, a SET or an explicit context tag. */
556
+ const x509DerWrap = (tag: i32, parts: u8[][]): u8[] => x509DerTlv(tag, x509DerConcat(parts))
557
+
558
+ /**
559
+ * The INTEGER holding the non-negative big-endian `magnitude`: its leading
560
+ * zero octets dropped, and one put back when the top bit would read as a sign
561
+ * (X.690 §8.3). Zero is the single octet `00`.
562
+ */
563
+ const x509DerUnsignedInteger = (magnitude: u8[]): u8[] => {
564
+ const contents: u8[] = []
565
+ for (let k: i32 = 0; k < toI32(magnitude.length); k++) {
566
+ const octet: i32 = toI32(magnitude[k])
567
+ // The first significant octet: a sign octet in front of it if its top bit is set.
568
+ if (toI32(contents.length) === 0 && octet >= 0x80) {
569
+ contents.push(0)
570
+ }
571
+ if (toI32(contents.length) > 0 || octet !== 0) {
572
+ contents.push(toU8(octet))
573
+ }
574
+ }
575
+ if (toI32(contents.length) === 0) {
576
+ contents.push(0)
577
+ }
578
+ return x509DerTlv(X509_TAG_INTEGER, contents)
579
+ }
580
+
581
+ /** A BIT STRING of whole `octets`: the unused-bits count 0, then the octets. */
582
+ const x509DerBitString = (octets: u8[]): u8[] => {
583
+ const contents: u8[] = [0]
584
+ for (let k: i32 = 0; k < toI32(octets.length); k++) {
585
+ contents.push(octets[k])
586
+ }
587
+ return x509DerTlv(X509_TAG_BIT_STRING, contents)
588
+ }
589
+
590
+ /** `value` as `width` decimal digits, pushed onto `out`. */
591
+ const x509PushDigits = (out: u8[], value: i32, width: i32): void => {
592
+ let scale: i32 = 1
593
+ for (let k: i32 = 1; k < width; k++) {
594
+ scale = scale * 10
595
+ }
596
+ for (let k: i32 = 0; k < width; k++) {
597
+ out.push(toU8(((value / scale) % 10) + 48))
598
+ scale = scale / 10
599
+ }
600
+ }
601
+
602
+ /**
603
+ * The Time for `seconds` after 1970 (not negative, at most the last second of
604
+ * 9999), as RFC 5280 §4.1.2.5 has an issuer write it: UTCTime through 2049,
605
+ * GeneralizedTime from 2050, both in UTC with seconds.
606
+ */
607
+ const x509DerTimeAt = (seconds: i64): u8[] => {
608
+ let days: i32 = toI32(seconds / 86400)
609
+ const rest: i32 = toI32(seconds % 86400)
610
+ let year: i32 = 1970
611
+ while (days >= (x509IsLeapYear(year) ? 366 : 365)) {
612
+ days = days - (x509IsLeapYear(year) ? 366 : 365)
613
+ year = year + 1
614
+ }
615
+ let month: i32 = 1
616
+ while (days >= x509DaysInMonth(year, month)) {
617
+ days = days - x509DaysInMonth(year, month)
618
+ month = month + 1
619
+ }
620
+ const text: u8[] = []
621
+ const utc: boolean = year < 2050
622
+ x509PushDigits(text, utc ? year % 100 : year, utc ? 2 : 4)
623
+ x509PushDigits(text, month, 2)
624
+ x509PushDigits(text, days + 1, 2)
625
+ x509PushDigits(text, rest / 3600, 2)
626
+ x509PushDigits(text, (rest / 60) % 60, 2)
627
+ x509PushDigits(text, rest % 60, 2)
628
+ text.push(90)
629
+ return x509DerTlv(utc ? X509_TAG_UTC_TIME : X509_TAG_GENERALIZED_TIME, text)
630
+ }
631
+
632
+ /**
633
+ * Whether `bytes` is well-formed UTF-8 (RFC 3629 §4) with no NUL: no stray
634
+ * continuation octet, no truncated sequence, no overlong form, no surrogate and
635
+ * nothing past U+10FFFF. A string in the language is bytes and need not be
636
+ * UTF-8, and a UTF8String that is not UTF-8 is a malformed certificate; a NUL
637
+ * is refused because a name that reads differently to C is the old
638
+ * `localhost\0.example` confusion.
639
+ */
640
+ const x509IsUtf8Name = (bytes: u8[]): boolean => {
641
+ // Continuation octets still owed, and the range the next one must fall in:
642
+ // 80..BF, narrowed after E0, ED, F0 and F4 (Unicode 15 §3.9, Table 3-7).
643
+ let need: i32 = 0
644
+ let lo: i32 = 0x80
645
+ let hi: i32 = 0xbf
646
+ for (let k: i32 = 0; k < toI32(bytes.length); k++) {
647
+ const b: i32 = toI32(bytes[k])
648
+ if (need > 0) {
649
+ if (b < lo || b > hi) {
650
+ return false
651
+ }
652
+ need = need - 1
653
+ lo = 0x80
654
+ hi = 0xbf
655
+ } else if (b === 0) {
656
+ return false
657
+ } else if (b >= 0xc2 && b <= 0xdf) {
658
+ need = 1
659
+ } else if (b >= 0xe0 && b <= 0xef) {
660
+ need = 2
661
+ lo = b === 0xe0 ? 0xa0 : 0x80
662
+ hi = b === 0xed ? 0x9f : 0xbf
663
+ } else if (b >= 0xf0 && b <= 0xf4) {
664
+ need = 3
665
+ lo = b === 0xf0 ? 0x90 : 0x80
666
+ hi = b === 0xf4 ? 0x8f : 0xbf
667
+ } else if (b >= 0x80) {
668
+ return false
669
+ }
670
+ }
671
+ return need === 0
672
+ }
673
+
674
+ /** The bytes of `text`, as the language holds a string. */
675
+ const x509Bytes = (text: string): u8[] => {
676
+ const out: u8[] = []
677
+ const n: i32 = toI32(text.length)
678
+ for (let k: i32 = 0; k < n; k++) {
679
+ out.push(toU8(toI32(text.charCodeAt(k))))
680
+ }
681
+ return out
682
+ }
683
+
684
+ // ---------------------------------------------------------------------------
685
+ // PEM (RFC 7468) and standard base64 (RFC 4648 §4)
686
+ // ---------------------------------------------------------------------------
687
+
688
+ /** All ones when `lo <= c <= hi`, else zero, without a branch; `c` is a byte or a sextet. */
689
+ const x509RangeMask = (c: i32, lo: i32, hi: i32): i32 => ((lo - 1 - c) & (c - hi - 1)) >> 31
690
+
691
+ /**
692
+ * The base64 character for the sextet `v`: `'A' + v`, stepped by the gap to
693
+ * each later range it has reached — 26 lands on `a`, 52 on `0`, 62 on `+` and
694
+ * 63 on `/`.
695
+ */
696
+ const x509Base64CharOf = (v: i32): i32 =>
697
+ 65 +
698
+ v +
699
+ (x509RangeMask(v, 26, 63) & 6) -
700
+ (x509RangeMask(v, 52, 63) & 75) -
701
+ (x509RangeMask(v, 62, 63) & 15) +
702
+ (x509RangeMask(v, 63, 63) & 3)
703
+
704
+ /** The sextet the byte `c` stands for in base64, or `-1` when it is not in the alphabet. */
705
+ const x509Base64SextetOf = (c: i32): i32 => {
706
+ const upper: i32 = x509RangeMask(c, 65, 90)
707
+ const lower: i32 = x509RangeMask(c, 97, 122)
708
+ const digit: i32 = x509RangeMask(c, 48, 57)
709
+ const plus: i32 = x509RangeMask(c, 43, 43)
710
+ const slash: i32 = x509RangeMask(c, 47, 47)
711
+ const value: i32 = (upper & (c - 65)) | (lower & (c - 71)) | (digit & (c + 4)) | (plus & 62) | (slash & 63)
712
+ return value | ~(upper | lower | digit | plus | slash)
713
+ }
714
+
715
+ /** `data` in padded base64, as one line. */
716
+ const x509Base64Encode = (data: u8[]): string => {
717
+ const parts: string[] = []
718
+ let acc: i32 = 0
719
+ let bits: i32 = 0
720
+ for (let k: i32 = 0; k < toI32(data.length); k++) {
721
+ acc = ((acc << 8) | toI32(data[k])) & 0xfff
722
+ bits = bits + 8
723
+ while (bits >= 6) {
724
+ bits = bits - 6
725
+ parts.push(String.fromCharCode(x509Base64CharOf((acc >> bits) & 63)))
726
+ }
727
+ }
728
+ if (bits > 0) {
729
+ parts.push(String.fromCharCode(x509Base64CharOf((acc << (6 - bits)) & 63)))
730
+ }
731
+ // One `=` for a final group of two bytes, two for one byte.
732
+ const tail: i32 = toI32(data.length) % 3
733
+ if (tail > 0) {
734
+ parts.push(tail === 1 ? "==" : "=")
735
+ }
736
+ return parts.join("")
737
+ }
738
+
739
+ /**
740
+ * The bytes of padded base64 `text`, or `null` unless it is the one canonical
741
+ * spelling of them: a whole number of four-character groups, `=` only as the
742
+ * last one or two characters, every other character in the alphabet, and the
743
+ * bits the padding leaves over all zero (RFC 4648 §3.5). Where the padding is
744
+ * depends on the length alone; the characters themselves are read by masks and
745
+ * judged once, after the last.
746
+ */
747
+ const x509Base64Decode = (text: string): u8[] | null => {
748
+ const n: i32 = toI32(text.length)
749
+ if (n === 0 || (n & 3) !== 0) {
750
+ return null
751
+ }
752
+ let pad: i32 = 0
753
+ if (toI32(text.charCodeAt(n - 1)) === 61) {
754
+ pad = toI32(text.charCodeAt(n - 2)) === 61 ? 2 : 1
755
+ }
756
+ const chars: i32 = n - pad
757
+ const out: u8[] = new Array<u8>((n >> 2) * 3 - pad)
758
+ const outLen: i32 = toI32(out.length)
759
+ let bad: i32 = 0
760
+ let acc: i32 = 0
761
+ let bits: i32 = 0
762
+ let j: i32 = 0
763
+ for (let k: i32 = 0; k < toI32(text.length); k++) {
764
+ // The padding is past `chars`, and is not data; which positions those are
765
+ // is a fact about the length.
766
+ if (k < chars) {
767
+ const v: i32 = x509Base64SextetOf(toI32(text.charCodeAt(k)))
768
+ bad = bad | (v >> 31)
769
+ acc = ((acc << 6) | (v & 63)) & 0xfff
770
+ bits = bits + 6
771
+ if (bits >= 8) {
772
+ bits = bits - 8
773
+ // Always true — `out` was sized from the same length — and written so
774
+ // the store keeps no bounds check.
775
+ if (j >= 0 && j < outLen) {
776
+ out[j] = toU8((acc >> bits) & 0xff)
777
+ }
778
+ j = j + 1
779
+ }
780
+ }
781
+ }
782
+ bad = bad | (acc & ((1 << bits) - 1))
783
+ if (bad !== 0) {
784
+ return null
785
+ }
786
+ return out
787
+ }
788
+
789
+ /** Whether `text` starts with `prefix`. */
790
+ const x509StartsWith = (text: string, prefix: string): boolean => {
791
+ const n: i32 = toI32(prefix.length)
792
+ return toI32(text.length) >= n && text.substring(0, n) === prefix
793
+ }
794
+
795
+ /** Whether `text` ends with `suffix`. */
796
+ const x509EndsWith = (text: string, suffix: string): boolean => {
797
+ const n: i32 = toI32(text.length)
798
+ const m: i32 = toI32(suffix.length)
799
+ return n >= m && text.substring(n - m, n) === suffix
800
+ }
801
+
802
+ /**
803
+ * `der` as a PEM block (RFC 7468 §2): `-----BEGIN label-----`, the base64 of
804
+ * the DER in lines of 64 characters, and `-----END label-----`, each line
805
+ * ending in a line feed.
806
+ */
807
+ export const derToPem = (der: u8[], label: string): string => {
808
+ const body: string = x509Base64Encode(der)
809
+ const n: i32 = toI32(body.length)
810
+ const lines: string[] = [`-----BEGIN ${label}-----`]
811
+ for (let at: i32 = 0; at < n; at = at + 64) {
812
+ lines.push(body.substring(at, at + 64 < n ? at + 64 : n))
813
+ }
814
+ lines.push(`-----END ${label}-----`)
815
+ lines.push("")
816
+ return lines.join("\n")
817
+ }
818
+
819
+ /**
820
+ * The DER of every PEM block in `pem` whose label is exactly `label`, in the
821
+ * order they appear, or `null` when there is none or any block is malformed:
822
+ * an unterminated block, an END whose label is not its BEGIN's, a line longer
823
+ * than 64 characters or a short line before the last, a header line, or
824
+ * base64 that is not canonical. Blocks with other labels must be as well
825
+ * formed, and are skipped; so is text outside the blocks.
826
+ */
827
+ export const pemToDer = (pem: string, label: string): u8[][] | null => {
828
+ const out: u8[][] = []
829
+ const n: i32 = toI32(pem.length)
830
+ // The label of the block being read, or "" outside one; its body lines so far.
831
+ let inside: string = ""
832
+ let body: string[] = []
833
+ let shortSeen: boolean = false
834
+ let lineStart: i32 = 0
835
+ while (lineStart < n) {
836
+ let lineEnd: i32 = lineStart
837
+ while (lineEnd >= 0 && lineEnd < toI32(pem.length) && toI32(pem.charCodeAt(lineEnd)) !== 10) {
838
+ lineEnd = lineEnd + 1
839
+ }
840
+ const next: i32 = lineEnd + 1
841
+ if (lineEnd > lineStart && toI32(pem.charCodeAt(lineEnd - 1)) === 13) {
842
+ lineEnd = lineEnd - 1
843
+ }
844
+ const line: string = pem.slice(lineStart, lineEnd)
845
+ lineStart = next
846
+ const length: i32 = toI32(line.length)
847
+ if (inside === "") {
848
+ if (x509StartsWith(line, "-----BEGIN ") && x509EndsWith(line, "-----") && length > 16) {
849
+ inside = line.substring(11, length - 5)
850
+ body = []
851
+ shortSeen = false
852
+ } else if (x509StartsWith(line, "-----END ")) {
853
+ return null
854
+ }
855
+ } else if (x509StartsWith(line, "-----END ")) {
856
+ if (line !== `-----END ${inside}-----`) {
857
+ return null
858
+ }
859
+ // Every block is decoded, whatever its label: a malformed block beside the
860
+ // one asked for is refused, not skipped (docs/security/crypto-x509.md, X509-1).
861
+ const der: u8[] | null = x509Base64Decode(body.join(""))
862
+ if (der === null) {
863
+ return null
864
+ }
865
+ if (inside === label) {
866
+ out.push(der)
867
+ }
868
+ inside = ""
869
+ } else {
870
+ if (shortSeen || length < 1 || length > 64) {
871
+ return null
872
+ }
873
+ shortSeen = length < 64
874
+ body.push(line)
875
+ }
876
+ }
877
+ if (inside !== "" || toI32(out.length) === 0) {
878
+ return null
879
+ }
880
+ return out
881
+ }
882
+
883
+ // ---------------------------------------------------------------------------
884
+ // Private keys (RFC 5915, RFC 5208 / RFC 5958)
885
+ // ---------------------------------------------------------------------------
886
+
887
+ /**
888
+ * The 32-byte scalar of an ECPrivateKey (RFC 5915 §3) filling `der[start ..
889
+ * end)`: version 1, the key as an OCTET STRING of exactly 32 octets, the
890
+ * optional `[0]` parameters, which must name prime256v1 and are required when
891
+ * `needCurve` (a bare SEC1 key has nowhere else to say its curve), and the
892
+ * optional `[1]` public key, which must be the key's own. `null` otherwise,
893
+ * or when the scalar is 0 or not below n.
894
+ */
895
+ const x509Sec1Key = (der: u8[], start: i32, end: i32, needCurve: boolean): u8[] | null => {
896
+ const seq: X509DerElement | null = x509DerExpect(der, start, end, X509_TAG_SEQUENCE)
897
+ if (seq === null || seq.end !== end) {
898
+ return null
899
+ }
900
+ const version: X509DerElement | null = x509DerRead(der, seq.start, seq.end)
901
+ if (version === null || x509DerSmallInteger(der, version) !== 1) {
902
+ return null
903
+ }
904
+ const key: X509DerElement | null = x509DerExpect(der, version.end, seq.end, X509_TAG_OCTET_STRING)
905
+ if (key === null || key.end - key.start !== 32) {
906
+ return null
907
+ }
908
+ const priv: u8[] = x509DerSlice(der, key.start, key.end)
909
+ let at: i32 = key.end
910
+ let curve: boolean = false
911
+ let stored: u8[] | null = null
912
+ if (x509DerPeek(der, at, seq.end) === 0xa0) {
913
+ const params: X509DerElement | null = x509DerRead(der, at, seq.end)
914
+ if (params === null || !x509DerIsOnlyOid(der, params.start, params.end, x509OidPrime256v1())) {
915
+ return null
916
+ }
917
+ curve = true
918
+ at = params.end
919
+ }
920
+ if (x509DerPeek(der, at, seq.end) === 0xa1) {
921
+ const wrapper: X509DerElement | null = x509DerRead(der, at, seq.end)
922
+ if (wrapper === null) {
923
+ return null
924
+ }
925
+ const bits: X509DerElement | null = x509DerExpect(der, wrapper.start, wrapper.end, X509_TAG_BIT_STRING)
926
+ if (bits === null || bits.end !== wrapper.end) {
927
+ return null
928
+ }
929
+ stored = x509DerBitStringOctets(der, bits)
930
+ if (stored === null) {
931
+ return null
932
+ }
933
+ at = wrapper.end
934
+ }
935
+ if (at !== seq.end || (needCurve && !curve)) {
936
+ return null
937
+ }
938
+ // Refuses 0 and n and above, and gives the point to hold `stored` against.
939
+ const pub: u8[] | null = p256PublicKey(priv)
940
+ if (pub === null) {
941
+ return null
942
+ }
943
+ if (stored !== null && !x509BytesEqual(stored, pub)) {
944
+ return null
945
+ }
946
+ return priv
947
+ }
948
+
949
+ /**
950
+ * The scalar of a PKCS#8 PrivateKeyInfo (RFC 5208 §5) or OneAsymmetricKey
951
+ * (RFC 5958 §2): version 0 or 1, the algorithm id-ecPublicKey with the
952
+ * prime256v1 curve, and an ECPrivateKey inside the OCTET STRING, followed by
953
+ * the optional `[0]` attributes, which are skipped, and — in version 1 — the
954
+ * optional `[1]` public key, which must be a BIT STRING of the key's own point
955
+ * (X509-8 in docs/security/crypto-x509.md).
956
+ */
957
+ const x509Pkcs8Key = (der: u8[]): u8[] | null => {
958
+ const total: i32 = toI32(der.length)
959
+ const seq: X509DerElement | null = x509DerExpect(der, 0, total, X509_TAG_SEQUENCE)
960
+ if (seq === null || seq.end !== total) {
961
+ return null
962
+ }
963
+ const version: X509DerElement | null = x509DerRead(der, seq.start, seq.end)
964
+ if (version === null) {
965
+ return null
966
+ }
967
+ const v: i32 = x509DerSmallInteger(der, version)
968
+ if (v !== 0 && v !== 1) {
969
+ return null
970
+ }
971
+ const alg: X509DerElement | null = x509DerRead(der, version.end, seq.end)
972
+ if (alg === null || !x509DerIsAlgorithm(der, alg, x509OidEcPublicKey(), x509OidPrime256v1())) {
973
+ return null
974
+ }
975
+ const key: X509DerElement | null = x509DerExpect(der, alg.end, seq.end, X509_TAG_OCTET_STRING)
976
+ if (key === null) {
977
+ return null
978
+ }
979
+ let at: i32 = key.end
980
+ if (x509DerPeek(der, at, seq.end) === 0xa0) {
981
+ const attributes: X509DerElement | null = x509DerRead(der, at, seq.end)
982
+ if (attributes === null) {
983
+ return null
984
+ }
985
+ at = attributes.end
986
+ }
987
+ let stored: u8[] | null = null
988
+ if (v === 1 && x509DerPeek(der, at, seq.end) === 0x81) {
989
+ const outer: X509DerElement | null = x509DerRead(der, at, seq.end)
990
+ if (outer === null) {
991
+ return null
992
+ }
993
+ // `[1] IMPLICIT BIT STRING`: the 0x81 replaces the BIT STRING's own tag,
994
+ // so its contents are the unused-bits octet and then the point.
995
+ const bits: X509DerElement = new X509DerElement(X509_TAG_BIT_STRING, outer.at, outer.start, outer.end)
996
+ stored = x509DerBitStringOctets(der, bits)
997
+ if (stored === null) {
998
+ return null
999
+ }
1000
+ at = outer.end
1001
+ }
1002
+ if (at !== seq.end) {
1003
+ return null
1004
+ }
1005
+ const priv: u8[] | null = x509Sec1Key(der, key.start, key.end, false)
1006
+ if (priv === null || stored === null) {
1007
+ return priv
1008
+ }
1009
+ // The same rule as the SEC1 key's own `[1]`: the stored point is the key's.
1010
+ const pub: u8[] | null = p256PublicKey(priv)
1011
+ return pub !== null && x509BytesEqual(stored, pub) ? priv : null
1012
+ }
1013
+
1014
+ /**
1015
+ * The 32-byte P-256 private key in `pem`: one `EC PRIVATE KEY` block (SEC1,
1016
+ * RFC 5915, which must name its curve) or one `PRIVATE KEY` block (unencrypted
1017
+ * PKCS#8, RFC 5208 or RFC 5958), and not both. `null` for no such block or
1018
+ * more than one, for any curve but P-256, for a scalar of 0 or n or more, for
1019
+ * a stored public key that is not the key's own, and for anything malformed.
1020
+ * An `ENCRYPTED PRIVATE KEY` is a different label, and answers `null`.
1021
+ */
1022
+ export const x509ParseP256PrivateKey = (pem: string): u8[] | null => {
1023
+ const sec1: u8[][] | null = pemToDer(pem, "EC PRIVATE KEY")
1024
+ const pkcs8: u8[][] | null = pemToDer(pem, "PRIVATE KEY")
1025
+ if (sec1 !== null && pkcs8 === null && toI32(sec1.length) === 1) {
1026
+ const der: u8[] = sec1[0]
1027
+ return x509Sec1Key(der, 0, toI32(der.length), true)
1028
+ }
1029
+ if (pkcs8 !== null && sec1 === null && toI32(pkcs8.length) === 1) {
1030
+ return x509Pkcs8Key(pkcs8[0])
1031
+ }
1032
+ return null
1033
+ }
1034
+
1035
+ // ---------------------------------------------------------------------------
1036
+ // Certificates (RFC 5280 §4.1)
1037
+ // ---------------------------------------------------------------------------
1038
+
1039
+ /**
1040
+ * Whether a `[3]` extensions wrapper holds one non-empty SEQUENCE and nothing
1041
+ * after it (RFC 5280 §4.1's `SIZE (1..MAX)`). What an extension says is not
1042
+ * read.
1043
+ */
1044
+ const x509DerExtensionsSound = (der: u8[], e: X509DerElement): boolean => {
1045
+ const seq: X509DerElement | null = x509DerExpect(der, e.start, e.end, X509_TAG_SEQUENCE)
1046
+ return seq !== null && seq.end === e.end && seq.end > seq.start
1047
+ }
1048
+
1049
+ /**
1050
+ * `der` read as one Certificate (RFC 5280 §4.1), or `null` unless it is
1051
+ * exactly one in DER: `SEQUENCE { tbsCertificate, signatureAlgorithm,
1052
+ * signatureValue }`, where tbsCertificate holds an explicit version of v2 or
1053
+ * v3 or none (DER omits v1, the default), a minimal serial, an algorithm equal
1054
+ * to the outer one byte for byte (§4.1.1.2), issuer and subject Names, a
1055
+ * Validity of two valid times, a SubjectPublicKeyInfo whose key is whole
1056
+ * octets, then only the optional `[1]` and `[2]` unique identifiers (v2 and
1057
+ * v3) and `[3]` extensions (v3), in that order, each well formed on the
1058
+ * outside. Any algorithm and key type is read; `p256` and `ecdsaSha256` say
1059
+ * whether they are this module's.
1060
+ *
1061
+ * **A parser, not a validator.** It checks that the bytes are one certificate
1062
+ * and nothing else. It does not check the signature (`x509VerifySignature`
1063
+ * does), that `notBefore` is not after `notAfter` or that either is near any
1064
+ * clock, and it does not read extensions — basicConstraints, keyUsage,
1065
+ * subjectAltName and the critical flag RFC 5280 §4.2 obliges a verifier to
1066
+ * honour are neither checked nor exposed.
1067
+ */
1068
+ export const x509ParseCertificate = (der: u8[]): X509Certificate | null => {
1069
+ const total: i32 = toI32(der.length)
1070
+ const cert: X509DerElement | null = x509DerExpect(der, 0, total, X509_TAG_SEQUENCE)
1071
+ if (cert === null || cert.end !== total) {
1072
+ return null
1073
+ }
1074
+ const tbs: X509DerElement | null = x509DerExpect(der, cert.start, cert.end, X509_TAG_SEQUENCE)
1075
+ if (tbs === null) {
1076
+ return null
1077
+ }
1078
+ const outerAlg: X509DerElement | null = x509DerExpect(der, tbs.end, cert.end, X509_TAG_SEQUENCE)
1079
+ if (outerAlg === null) {
1080
+ return null
1081
+ }
1082
+ const sigValue: X509DerElement | null = x509DerExpect(der, outerAlg.end, cert.end, X509_TAG_BIT_STRING)
1083
+ if (sigValue === null || sigValue.end !== cert.end) {
1084
+ return null
1085
+ }
1086
+ const signature: u8[] | null = x509DerBitStringOctets(der, sigValue)
1087
+ if (signature === null) {
1088
+ return null
1089
+ }
1090
+
1091
+ let at: i32 = tbs.start
1092
+ let version: i32 = 0
1093
+ if (x509DerPeek(der, at, tbs.end) === 0xa0) {
1094
+ const explicit: X509DerElement | null = x509DerRead(der, at, tbs.end)
1095
+ if (explicit === null) {
1096
+ return null
1097
+ }
1098
+ const inner: X509DerElement | null = x509DerRead(der, explicit.start, explicit.end)
1099
+ if (inner === null || inner.end !== explicit.end) {
1100
+ return null
1101
+ }
1102
+ version = x509DerSmallInteger(der, inner)
1103
+ if (version !== 1 && version !== 2) {
1104
+ return null
1105
+ }
1106
+ at = explicit.end
1107
+ }
1108
+ const serial: X509DerElement | null = x509DerExpect(der, at, tbs.end, X509_TAG_INTEGER)
1109
+ if (serial === null || !x509DerIntegerMinimal(der, serial)) {
1110
+ return null
1111
+ }
1112
+ const alg: X509DerElement | null = x509DerExpect(der, serial.end, tbs.end, X509_TAG_SEQUENCE)
1113
+ if (alg === null || !x509BytesEqual(x509DerWhole(der, alg), x509DerWhole(der, outerAlg))) {
1114
+ return null
1115
+ }
1116
+ const issuer: X509DerElement | null = x509DerExpect(der, alg.end, tbs.end, X509_TAG_SEQUENCE)
1117
+ if (issuer === null) {
1118
+ return null
1119
+ }
1120
+ const validity: X509DerElement | null = x509DerExpect(der, issuer.end, tbs.end, X509_TAG_SEQUENCE)
1121
+ if (validity === null) {
1122
+ return null
1123
+ }
1124
+ const notBefore: X509DerElement | null = x509DerRead(der, validity.start, validity.end)
1125
+ if (notBefore === null) {
1126
+ return null
1127
+ }
1128
+ const notAfter: X509DerElement | null = x509DerRead(der, notBefore.end, validity.end)
1129
+ if (notAfter === null || notAfter.end !== validity.end) {
1130
+ return null
1131
+ }
1132
+ const subject: X509DerElement | null = x509DerExpect(der, validity.end, tbs.end, X509_TAG_SEQUENCE)
1133
+ if (subject === null) {
1134
+ return null
1135
+ }
1136
+ const spki: X509DerElement | null = x509DerExpect(der, subject.end, tbs.end, X509_TAG_SEQUENCE)
1137
+ if (spki === null) {
1138
+ return null
1139
+ }
1140
+ const keyAlg: X509DerElement | null = x509DerExpect(der, spki.start, spki.end, X509_TAG_SEQUENCE)
1141
+ if (keyAlg === null) {
1142
+ return null
1143
+ }
1144
+ const keyBits: X509DerElement | null = x509DerExpect(der, keyAlg.end, spki.end, X509_TAG_BIT_STRING)
1145
+ if (keyBits === null || keyBits.end !== spki.end) {
1146
+ return null
1147
+ }
1148
+ const publicKey: u8[] | null = x509DerBitStringOctets(der, keyBits)
1149
+ if (publicKey === null) {
1150
+ return null
1151
+ }
1152
+ at = spki.end
1153
+ // [1] issuerUniqueID and [2] subjectUniqueID are IMPLICIT BIT STRINGs (so
1154
+ // primitive, 0x81 and 0x82) from v2; [3] extensions is explicit (0xa3), v3.
1155
+ // Each is held to its outer shape; what it says is not read.
1156
+ const trailing: i32[] = [0x81, 0x82, 0xa3]
1157
+ for (let i: i32 = 0; i < 3; i++) {
1158
+ if (x509DerPeek(der, at, tbs.end) === trailing[i]) {
1159
+ const e: X509DerElement | null = x509DerRead(der, at, tbs.end)
1160
+ if (e === null || version < (i === 2 ? 2 : 1)) {
1161
+ return null
1162
+ }
1163
+ if (i === 2 ? !x509DerExtensionsSound(der, e) : !x509DerBitStringSound(der, e)) {
1164
+ return null
1165
+ }
1166
+ at = e.end
1167
+ }
1168
+ }
1169
+ if (at !== tbs.end) {
1170
+ return null
1171
+ }
1172
+
1173
+ const before: i64 = x509DerTime(der, notBefore)
1174
+ const after: i64 = x509DerTime(der, notAfter)
1175
+ if (before === X509_NO_TIME || after === X509_NO_TIME) {
1176
+ return null
1177
+ }
1178
+ const out = new X509Certificate()
1179
+ out.der = x509DerSlice(der, 0, total)
1180
+ out.tbs = x509DerWhole(der, tbs)
1181
+ out.serial = x509DerSlice(der, serial.start, serial.end)
1182
+ out.issuer = x509DerWhole(der, issuer)
1183
+ out.subject = x509DerWhole(der, subject)
1184
+ out.publicKey = publicKey
1185
+ out.p256 = x509DerIsAlgorithm(der, keyAlg, x509OidEcPublicKey(), x509OidPrime256v1())
1186
+ out.notBefore = before
1187
+ out.notAfter = after
1188
+ out.signature = signature
1189
+ out.ecdsaSha256 = x509DerIsAlgorithm(der, outerAlg, x509OidEcdsaSha256(), [])
1190
+ return out
1191
+ }
1192
+
1193
+ /**
1194
+ * Every `CERTIFICATE` block in `pem`, in the order they appear — for a
1195
+ * server's chain file, leaf first as TLS sends it — or `null` when there is
1196
+ * none, or when any block is not PEM `pemToDer` accepts or a certificate
1197
+ * `x509ParseCertificate` accepts.
1198
+ *
1199
+ * **It reads a chain; it does not validate one.** Nothing relates one
1200
+ * certificate to the next: not the order, not that each is issued by the one
1201
+ * after it (issuer against subject, or signature), not validity against a
1202
+ * clock, basicConstraints, keyUsage, name constraints or a trust anchor. RFC
1203
+ * 5280 §6's path validation is not in this module, and a chain it answers is
1204
+ * no evidence that anyone vouches for the leaf.
1205
+ */
1206
+ export const x509ParseChain = (pem: string): X509Certificate[] | null => {
1207
+ const blocks: u8[][] | null = pemToDer(pem, "CERTIFICATE")
1208
+ if (blocks === null) {
1209
+ return null
1210
+ }
1211
+ const out: X509Certificate[] = []
1212
+ for (const der of blocks) {
1213
+ const cert: X509Certificate | null = x509ParseCertificate(der)
1214
+ if (cert === null) {
1215
+ return null
1216
+ }
1217
+ out.push(cert)
1218
+ }
1219
+ return out
1220
+ }
1221
+
1222
+ /**
1223
+ * Whether `cert`'s signature is a valid ecdsa-with-SHA256 signature of its TBS
1224
+ * bytes under `issuer`'s P-256 key — a self-signed certificate passes itself
1225
+ * as both. `false` for any other algorithm or key, and for a signature that is
1226
+ * not a DER ECDSA-Sig-Value. Only the signature: that `cert.issuer` is
1227
+ * `issuer.subject` and that the times hold are fields the caller compares, and
1228
+ * whether `issuer` may issue at all (basicConstraints, keyUsage) is in
1229
+ * extensions this module does not read, so a `true` here is not path
1230
+ * validation.
1231
+ */
1232
+ export const x509VerifySignature = (cert: X509Certificate, issuer: X509Certificate): boolean => {
1233
+ if (!cert.ecdsaSha256 || !issuer.p256) {
1234
+ return false
1235
+ }
1236
+ const rs: u8[] | null = x509DerSignatureRS(cert.signature)
1237
+ if (rs === null) {
1238
+ return false
1239
+ }
1240
+ return p256VerifySha256(issuer.publicKey, cert.tbs, rs)
1241
+ }
1242
+
1243
+ /**
1244
+ * A self-signed X.509 v3 certificate, in DER, for the P-256 key `priv`: subject
1245
+ * and issuer `CN=commonName`, valid from `notBeforeMs` (milliseconds since
1246
+ * 1970, rounded down to the second) for exactly `days` days, serial number
1247
+ * `serial`, and signed with ecdsa-with-SHA256 — see the module comment for why
1248
+ * it has no extensions. `null` when `days` is below 1 or above
1249
+ * `X509_MAX_DAYS`, `notBeforeMs` is negative or the validity would end after
1250
+ * 9999, `commonName` is empty, longer than 64 bytes, not UTF-8 or holds a NUL
1251
+ * (it is written as a UTF8String), `priv` is not a P-256 private key, or
1252
+ * `serial` — big-endian, leading zeros ignored — is zero or
1253
+ * needs more than `X509_MAX_SERIAL` octets as a positive INTEGER (clear the top
1254
+ * bit of 20 random bytes, or use fewer).
1255
+ */
1256
+ export const x509MintSelfSigned = (
1257
+ priv: u8[],
1258
+ commonName: string,
1259
+ notBeforeMs: i64,
1260
+ days: i32,
1261
+ serial: u8[]
1262
+ ): u8[] | null => {
1263
+ if (days < 1 || days > X509_MAX_DAYS || notBeforeMs < 0) {
1264
+ return null
1265
+ }
1266
+ const start: i64 = notBeforeMs / 1000
1267
+ const end: i64 = start + toI64(days) * 86400
1268
+ // 9999-12-31T23:59:59Z, the last second RFC 5280's times can spell.
1269
+ if (end > 253402300799) {
1270
+ return null
1271
+ }
1272
+ const name: u8[] = x509Bytes(commonName)
1273
+ const nameLength: i32 = toI32(name.length)
1274
+ if (nameLength < 1 || nameLength > X509_MAX_COMMON_NAME || !x509IsUtf8Name(name)) {
1275
+ return null
1276
+ }
1277
+ const serialDer: u8[] = x509DerUnsignedInteger(serial)
1278
+ // Tag, length, and at most twenty content octets, of which at least one is not zero.
1279
+ let nonzero: i32 = 0
1280
+ for (let k: i32 = 0; k < toI32(serial.length); k++) {
1281
+ nonzero = nonzero | toI32(serial[k])
1282
+ }
1283
+ if (nonzero === 0 || toI32(serialDer.length) - 2 > X509_MAX_SERIAL) {
1284
+ return null
1285
+ }
1286
+ const pub: u8[] | null = p256PublicKey(priv)
1287
+ if (pub === null) {
1288
+ return null
1289
+ }
1290
+
1291
+ const algorithm: u8[] = x509DerWrap(X509_TAG_SEQUENCE, [x509DerTlv(X509_TAG_OID, x509OidEcdsaSha256())])
1292
+ const rdn: u8[] = x509DerWrap(X509_TAG_SET, [
1293
+ x509DerWrap(X509_TAG_SEQUENCE, [
1294
+ x509DerTlv(X509_TAG_OID, x509OidCommonName()),
1295
+ x509DerTlv(X509_TAG_UTF8_STRING, name),
1296
+ ]),
1297
+ ])
1298
+ const distinguished: u8[] = x509DerWrap(X509_TAG_SEQUENCE, [rdn])
1299
+ const spki: u8[] = x509DerWrap(X509_TAG_SEQUENCE, [
1300
+ x509DerWrap(X509_TAG_SEQUENCE, [
1301
+ x509DerTlv(X509_TAG_OID, x509OidEcPublicKey()),
1302
+ x509DerTlv(X509_TAG_OID, x509OidPrime256v1()),
1303
+ ]),
1304
+ x509DerBitString(pub),
1305
+ ])
1306
+ const tbs: u8[] = x509DerWrap(X509_TAG_SEQUENCE, [
1307
+ // [0] EXPLICIT Version: v3 is the INTEGER 2.
1308
+ x509DerWrap(0xa0, [x509DerTlv(X509_TAG_INTEGER, [2])]),
1309
+ serialDer,
1310
+ algorithm,
1311
+ distinguished,
1312
+ x509DerWrap(X509_TAG_SEQUENCE, [x509DerTimeAt(start), x509DerTimeAt(end)]),
1313
+ distinguished,
1314
+ spki,
1315
+ ])
1316
+ const rs: u8[] | null = p256SignSha256(priv, tbs)
1317
+ if (rs === null) {
1318
+ return null
1319
+ }
1320
+ const r: u8[] = x509DerSlice(rs, 0, 32)
1321
+ const s: u8[] = x509DerSlice(rs, 32, 64)
1322
+ const sig: u8[] = x509DerWrap(X509_TAG_SEQUENCE, [x509DerUnsignedInteger(r), x509DerUnsignedInteger(s)])
1323
+ return x509DerWrap(X509_TAG_SEQUENCE, [tbs, algorithm, x509DerBitString(sig)])
1324
+ }
1325
+
1326
+ /**
1327
+ * The SHA-256 of a certificate's DER: the value WebTransport's
1328
+ * `serverCertificateHashes` pins, and what `openssl x509 -outform DER |
1329
+ * sha256sum` prints.
1330
+ */
1331
+ export const x509CertificateHash = (der: u8[]): u8[] => sha256(der)