@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
@@ -1,6 +1,6 @@
1
1
  /**
2
- * `nish/net/tls/codec` — the TLS 1.3 handshake messages a server reads and
3
- * writes (RFC 8446 §4), as bytes.
2
+ * `nish/net/tls/codec` — the TLS 1.3 handshake messages a server and a
3
+ * client read and write (RFC 8446 §4), as bytes.
4
4
  *
5
5
  * One reader and eight writers. `tlsParseClientHello` reads a ClientHello body
6
6
  * into a `TlsClientHello`, checking its structure: every length against the
@@ -25,6 +25,16 @@
25
25
  * offset — run over an empty array, it measures — and a `tlsEncode*` one
26
26
  * that answers the message in a fresh array.
27
27
  *
28
+ * The client's side is the mirror: `tlsWriteClientHello` and
29
+ * `tlsEncodeClientHello` write the hello `nish/net/tls/client` sends, and five
30
+ * readers — `tlsReadServerHello` (a HelloRetryRequest too),
31
+ * `tlsReadEncryptedExtensions`, `tlsReadCertificate`,
32
+ * `tlsReadCertificateVerify` and `tlsReadNewSessionTicket` — read the
33
+ * server's flight into a `TlsServerFlightView` made once, as windows, with
34
+ * the same checks and the same alerts in its `alert` field. A server's bytes
35
+ * are the peer's just as a client's are, so these readers never panic either
36
+ * (the `tls-server-flight` fuzz target).
37
+ *
28
38
  * The extensions read are `server_name` (RFC 6066 §3), `supported_groups`,
29
39
  * `signature_algorithms`, `supported_versions` and `key_share` (RFC 8446
30
40
  * §4.2), `application_layer_protocol_negotiation` (RFC 7301 §3.1) and
@@ -67,6 +77,8 @@ export const TLS_EXT_ALPN: i32 = 16
67
77
  export const TLS_EXT_SUPPORTED_VERSIONS: i32 = 43
68
78
  export const TLS_EXT_KEY_SHARE: i32 = 51
69
79
  export const TLS_EXT_QUIC_TRANSPORT_PARAMETERS: i32 = 57
80
+ /** `cookie` (§4.2.2): what a HelloRetryRequest may carry and the client's second ClientHello echoes. */
81
+ export const TLS_EXT_COOKIE: i32 = 44
70
82
 
71
83
  // ---- Versions, groups and signature schemes -------------------------------
72
84
 
@@ -82,6 +94,16 @@ export const TLS_X25519_SHARE_SIZE: i32 = 32
82
94
  export const TLS_SIGNATURE_ECDSA_SECP256R1_SHA256: i32 = 0x0403
83
95
  /** `rsa_pss_rsae_sha256` (§4.2.3), what RFC 8448's server signs with. */
84
96
  export const TLS_SIGNATURE_RSA_PSS_RSAE_SHA256: i32 = 0x0804
97
+ /** `ecdsa_secp384r1_sha384` (§4.2.3), offered by the client. */
98
+ export const TLS_SIGNATURE_ECDSA_SECP384R1_SHA384: i32 = 0x0503
99
+ /** `rsa_pss_rsae_sha384` (§4.2.3), offered by the client. */
100
+ export const TLS_SIGNATURE_RSA_PSS_RSAE_SHA384: i32 = 0x0805
101
+ /** `rsa_pss_rsae_sha512` (§4.2.3), offered by the client. */
102
+ export const TLS_SIGNATURE_RSA_PSS_RSAE_SHA512: i32 = 0x0806
103
+ /** secp256r1 (§4.2.7), the second group the client offers. */
104
+ export const TLS_GROUP_SECP256R1: i32 = 0x0017
105
+ /** The length of a secp256r1 key share: an uncompressed point, 0x04 then X and Y (§4.2.8.2). */
106
+ export const TLS_P256_SHARE_SIZE: i32 = 65
85
107
 
86
108
  // ---- Alert descriptions (RFC 8446 §6) --------------------------------------
87
109
 
@@ -89,6 +111,8 @@ export const TLS_SIGNATURE_RSA_PSS_RSAE_SHA256: i32 = 0x0804
89
111
  export const TLS_ALERT_UNEXPECTED_MESSAGE: i32 = 10
90
112
  /** No acceptable set of parameters: no common suite, group or signature scheme. */
91
113
  export const TLS_ALERT_HANDSHAKE_FAILURE: i32 = 40
114
+ /** The client's verdict on a server certificate it does not accept, which `TlsClient.authenticate(false)` sends by default. */
115
+ export const TLS_ALERT_BAD_CERTIFICATE: i32 = 42
92
116
  /** A field well formed but wrong: a duplicate, a bad share, a second retry without the share. */
93
117
  export const TLS_ALERT_ILLEGAL_PARAMETER: i32 = 47
94
118
  /** A message that does not parse: a length past its bytes, a vector out of its bounds, trailing bytes. */
@@ -103,6 +127,8 @@ export const TLS_ALERT_INTERNAL_ERROR: i32 = 80
103
127
  export const TLS_ALERT_MISSING_EXTENSION: i32 = 109
104
128
  /** ALPN offered no protocol the server accepts (RFC 7301 §3.2, RFC 9001 §8.1). */
105
129
  export const TLS_ALERT_NO_APPLICATION_PROTOCOL: i32 = 120
130
+ /** An extension in a server message that the client never offered (§4.2). */
131
+ export const TLS_ALERT_UNSUPPORTED_EXTENSION: i32 = 110
106
132
 
107
133
  /** `psk_ke` (§4.2.9): resumption from the PSK alone, without forward secrecy, which the server never selects. */
108
134
  export const TLS_PSK_KE: i32 = 0
@@ -821,7 +847,7 @@ export class TlsClientHello {
821
847
  }
822
848
 
823
849
  /** A copy of `data[at .. at + length)`. */
824
- const tlsCopyWindow = (data: u8[], at: i32, length: i32): u8[] => {
850
+ export const tlsCopyWindow = (data: u8[], at: i32, length: i32): u8[] => {
825
851
  const out: u8[] = new Array<u8>(length < 0 ? TLS_CODEC_FROM : length)
826
852
  for (let k: i32 = 0; k < toI32(out.length) && at + k >= 0 && at + k < toI32(data.length); k++) {
827
853
  out[k] = data[at + k]
@@ -1486,3 +1512,559 @@ export const tlsCertificateVerifyContent = (transcriptHash: u8[]): u8[] => {
1486
1512
  tlsWriteCertificateVerifyContent(out, TLS_CODEC_FROM, transcriptHash, TLS_CODEC_FROM, length)
1487
1513
  return out
1488
1514
  }
1515
+
1516
+ // ---------------------------------------------------------------------------
1517
+ // The client's half: the ClientHello it writes and the server flight it reads.
1518
+ // ---------------------------------------------------------------------------
1519
+
1520
+ /** The `signature_algorithms` the client offers (§4.2.3), in its order of preference. */
1521
+ const tlsPutClientSchemes = (out: u8[], at: i32): i32 => {
1522
+ let p: i32 = tlsPutU16(out, at, TLS_SIGNATURE_ECDSA_SECP256R1_SHA256)
1523
+ p = tlsPutU16(out, p, TLS_SIGNATURE_ECDSA_SECP384R1_SHA384)
1524
+ p = tlsPutU16(out, p, TLS_SIGNATURE_RSA_PSS_RSAE_SHA256)
1525
+ p = tlsPutU16(out, p, TLS_SIGNATURE_RSA_PSS_RSAE_SHA384)
1526
+ return tlsPutU16(out, p, TLS_SIGNATURE_RSA_PSS_RSAE_SHA512)
1527
+ }
1528
+
1529
+ /** Whether `scheme` is one the client's `signature_algorithms` offers, the only ones a server's CertificateVerify may use (§4.4.3). */
1530
+ export const tlsClientOffersScheme = (scheme: i32): boolean =>
1531
+ scheme === TLS_SIGNATURE_ECDSA_SECP256R1_SHA256 ||
1532
+ scheme === TLS_SIGNATURE_ECDSA_SECP384R1_SHA384 ||
1533
+ scheme === TLS_SIGNATURE_RSA_PSS_RSAE_SHA256 ||
1534
+ scheme === TLS_SIGNATURE_RSA_PSS_RSAE_SHA384 ||
1535
+ scheme === TLS_SIGNATURE_RSA_PSS_RSAE_SHA512
1536
+
1537
+ /**
1538
+ * Writes a ClientHello (§4.1.2) at `out[at]` and answers where it ends:
1539
+ * `random`, the `legacy_session_id` `sessionId`, the cipher suites `suites`,
1540
+ * null compression, then the extensions `server_name` (a `host_name`, left
1541
+ * out when `serverName` is empty), `supported_groups` (`groups`),
1542
+ * `signature_algorithms`, ALPN (left out when `alpn` is empty),
1543
+ * `supported_versions` (TLS 1.3 alone), a `key_share` with the one entry
1544
+ * `shareGroup`/`sharePublic`, and `cookie` when `cookie` is not empty (the
1545
+ * echo of a HelloRetryRequest's, §4.2.2).
1546
+ */
1547
+ export const tlsWriteClientHello = (
1548
+ out: u8[],
1549
+ at: i32,
1550
+ random: u8[],
1551
+ sessionId: u8[],
1552
+ suites: i32[],
1553
+ groups: i32[],
1554
+ shareGroup: i32,
1555
+ sharePublic: u8[],
1556
+ serverName: string,
1557
+ alpn: string[],
1558
+ cookie: u8[]
1559
+ ): i32 => {
1560
+ let p: i32 = tlsPutU16(out, at + 4, TLS_LEGACY_VERSION)
1561
+ p = tlsPutBytes(out, p, random)
1562
+ p = tlsPutU8(out, p, toI32(sessionId.length))
1563
+ p = tlsPutBytes(out, p, sessionId)
1564
+ const suiteList: i32 = p + 2
1565
+ p = suiteList
1566
+ for (const suite of suites) {
1567
+ p = tlsPutU16(out, p, suite)
1568
+ }
1569
+ tlsPutLength(out, suiteList, p, 2)
1570
+ p = tlsPutU8(out, tlsPutU8(out, p, 1), 0)
1571
+ const extensions: i32 = p + 2
1572
+ p = extensions
1573
+ if (toI32(serverName.length) > 0) {
1574
+ p = tlsPutU16(out, p, TLS_EXT_SERVER_NAME)
1575
+ const body: i32 = p + 2
1576
+ const list: i32 = body + 2
1577
+ const name: i32 = tlsPutU8(out, list, 0) + 2
1578
+ p = tlsPutAscii(out, name, serverName)
1579
+ tlsPutLength(out, name, p, 2)
1580
+ tlsPutLength(out, list, p, 2)
1581
+ tlsPutLength(out, body, p, 2)
1582
+ }
1583
+ p = tlsPutU16(out, p, TLS_EXT_SUPPORTED_GROUPS)
1584
+ const groupsBody: i32 = p + 2
1585
+ const groupList: i32 = groupsBody + 2
1586
+ p = groupList
1587
+ for (const group of groups) {
1588
+ p = tlsPutU16(out, p, group)
1589
+ }
1590
+ tlsPutLength(out, groupList, p, 2)
1591
+ tlsPutLength(out, groupsBody, p, 2)
1592
+ p = tlsPutU16(out, p, TLS_EXT_SIGNATURE_ALGORITHMS)
1593
+ const schemesBody: i32 = p + 2
1594
+ const schemeList: i32 = schemesBody + 2
1595
+ p = tlsPutClientSchemes(out, schemeList)
1596
+ tlsPutLength(out, schemeList, p, 2)
1597
+ tlsPutLength(out, schemesBody, p, 2)
1598
+ if (toI32(alpn.length) > 0) {
1599
+ p = tlsPutU16(out, p, TLS_EXT_ALPN)
1600
+ const body: i32 = p + 2
1601
+ const list: i32 = body + 2
1602
+ p = list
1603
+ for (const protocol of alpn) {
1604
+ const name: i32 = p + 1
1605
+ p = tlsPutAscii(out, name, protocol)
1606
+ tlsPutLength(out, name, p, 1)
1607
+ }
1608
+ tlsPutLength(out, list, p, 2)
1609
+ tlsPutLength(out, body, p, 2)
1610
+ }
1611
+ p = tlsPutU16(out, tlsPutU16(out, p, TLS_EXT_SUPPORTED_VERSIONS), 3)
1612
+ p = tlsPutU16(out, tlsPutU8(out, p, 2), TLS_VERSION_13)
1613
+ p = tlsPutU16(out, p, TLS_EXT_KEY_SHARE)
1614
+ const shareBody: i32 = p + 2
1615
+ const shareList: i32 = shareBody + 2
1616
+ const key: i32 = tlsPutU16(out, shareList, shareGroup) + 2
1617
+ p = tlsPutBytes(out, key, sharePublic)
1618
+ tlsPutLength(out, key, p, 2)
1619
+ tlsPutLength(out, shareList, p, 2)
1620
+ tlsPutLength(out, shareBody, p, 2)
1621
+ if (toI32(cookie.length) > 0) {
1622
+ p = tlsPutU16(out, p, TLS_EXT_COOKIE)
1623
+ const body: i32 = p + 2
1624
+ const value: i32 = body + 2
1625
+ p = tlsPutBytes(out, value, cookie)
1626
+ tlsPutLength(out, value, p, 2)
1627
+ tlsPutLength(out, body, p, 2)
1628
+ }
1629
+ tlsPutLength(out, extensions, p, 2)
1630
+ tlsPutHeader(out, at, TLS_HANDSHAKE_CLIENT_HELLO, p)
1631
+ return p
1632
+ }
1633
+
1634
+ /** A ClientHello (§4.1.2) in a fresh array (`tlsWriteClientHello`). */
1635
+ export const tlsEncodeClientHello = (
1636
+ random: u8[],
1637
+ sessionId: u8[],
1638
+ suites: i32[],
1639
+ groups: i32[],
1640
+ shareGroup: i32,
1641
+ sharePublic: u8[],
1642
+ serverName: string,
1643
+ alpn: string[],
1644
+ cookie: u8[]
1645
+ ): u8[] => {
1646
+ const none: u8[] = []
1647
+ const out: u8[] = new Array<u8>(
1648
+ tlsWriteClientHello(
1649
+ none,
1650
+ TLS_CODEC_FROM,
1651
+ random,
1652
+ sessionId,
1653
+ suites,
1654
+ groups,
1655
+ shareGroup,
1656
+ sharePublic,
1657
+ serverName,
1658
+ alpn,
1659
+ cookie
1660
+ )
1661
+ )
1662
+ tlsWriteClientHello(
1663
+ out,
1664
+ TLS_CODEC_FROM,
1665
+ random,
1666
+ sessionId,
1667
+ suites,
1668
+ groups,
1669
+ shareGroup,
1670
+ sharePublic,
1671
+ serverName,
1672
+ alpn,
1673
+ cookie
1674
+ )
1675
+ return out
1676
+ }
1677
+
1678
+ /**
1679
+ * One message of the server's flight as a `tlsRead*` function below read it:
1680
+ * a ServerHello or HelloRetryRequest, EncryptedExtensions, Certificate,
1681
+ * CertificateVerify or NewSessionTicket. Like `TlsClientHelloView` its fields
1682
+ * are windows into `data` and numbers, so a read allocates nothing; each read
1683
+ * forgets the last message first.
1684
+ *
1685
+ * Two verdicts, kept apart so the client can rank them. `alert` is the
1686
+ * structure's: `decode_error` for a length past its bytes, a vector out of
1687
+ * its bounds or bytes left over. `extensionAlert` is the extensions': an
1688
+ * extension sent twice, or one the client offered but this message may not
1689
+ * carry, is `illegal_parameter`; one the client never offers is
1690
+ * `unsupported_extension` (§4.2). The client reads the structure first, then
1691
+ * the version and the downgrade sentinel, then the extensions, so that a
1692
+ * TLS 1.2 ServerHello is refused for its version, not for the extensions a
1693
+ * TLS 1.2 server sends.
1694
+ */
1695
+ export class TlsServerFlightView {
1696
+ /** The buffer the windows point into: the one the last message was read from. */
1697
+ data: u8[]
1698
+ /** One bit per extension type read, for the duplicate check (§4.2). */
1699
+ extensionSeen: u32[]
1700
+ /** The reader each read runs, kept so that a read allocates none. */
1701
+ reader: TlsReader
1702
+ /** 0 when the message parsed, else `decode_error`. */
1703
+ alert: i32 = 0
1704
+ /** 0 when the extensions are ones this message may carry, else `illegal_parameter` or `unsupported_extension`. */
1705
+ extensionAlert: i32 = 0
1706
+ legacyVersion: i32 = 0
1707
+ randomAt: i32 = 0
1708
+ sessionIdAt: i32 = 0
1709
+ sessionIdLength: i32 = 0
1710
+ suite: i32 = 0
1711
+ compression: i32 = 0
1712
+ selectedVersion: i32 = 0
1713
+ /** `key_share`: a ServerHello's entry, or a HelloRetryRequest's `selected_group` with an empty share. */
1714
+ shareGroup: i32 = 0
1715
+ shareAt: i32 = 0
1716
+ shareLength: i32 = 0
1717
+ /** A HelloRetryRequest's `cookie`, which the second ClientHello echoes (§4.2.2). */
1718
+ cookieAt: i32 = 0
1719
+ cookieLength: i32 = 0
1720
+ /** EncryptedExtensions' ALPN: the one protocol the server chose (RFC 7301 §3.1). */
1721
+ alpnAt: i32 = 0
1722
+ alpnLength: i32 = 0
1723
+ /** Certificate's `certificate_request_context`, which must be empty for a server's (§4.4.2). */
1724
+ contextLength: i32 = 0
1725
+ /** Certificate's `certificate_list`, every entry in it, and how many there are. */
1726
+ certificatesAt: i32 = 0
1727
+ certificatesLength: i32 = 0
1728
+ certificateCount: i32 = 0
1729
+ /** CertificateVerify's scheme and signature (§4.4.3). */
1730
+ scheme: i32 = 0
1731
+ signatureAt: i32 = 0
1732
+ signatureLength: i32 = 0
1733
+ /** A ServerHello whose `random` is the HelloRetryRequest value (§4.1.3). */
1734
+ isRetry: boolean = false
1735
+ hasSupportedVersions: boolean = false
1736
+ hasKeyShare: boolean = false
1737
+ hasCookie: boolean = false
1738
+ hasAlpn: boolean = false
1739
+ /** EncryptedExtensions' empty `server_name`, the acknowledgement of RFC 6066 §3. */
1740
+ serverNameAcknowledged: boolean = false
1741
+
1742
+ constructor() {
1743
+ this.data = []
1744
+ this.extensionSeen = new Array<u32>(TLS_U16_BITMAP_WORDS)
1745
+ this.reader = new TlsReader(this.data, TLS_CODEC_FROM, TLS_CODEC_FROM)
1746
+ }
1747
+
1748
+ /** Forgets the last message: every window empty, every flag down, the bitmap clear. */
1749
+ clear(): void {
1750
+ this.alert = 0
1751
+ this.extensionAlert = 0
1752
+ this.isRetry = false
1753
+ this.legacyVersion = 0
1754
+ this.randomAt = 0
1755
+ this.sessionIdAt = 0
1756
+ this.sessionIdLength = 0
1757
+ this.suite = 0
1758
+ this.compression = 0
1759
+ this.hasSupportedVersions = false
1760
+ this.selectedVersion = 0
1761
+ this.hasKeyShare = false
1762
+ this.shareGroup = 0
1763
+ this.shareAt = 0
1764
+ this.shareLength = 0
1765
+ this.hasCookie = false
1766
+ this.cookieAt = 0
1767
+ this.cookieLength = 0
1768
+ this.hasAlpn = false
1769
+ this.alpnAt = 0
1770
+ this.alpnLength = 0
1771
+ this.serverNameAcknowledged = false
1772
+ this.contextLength = 0
1773
+ this.certificatesAt = 0
1774
+ this.certificatesLength = 0
1775
+ this.certificateCount = 0
1776
+ this.scheme = 0
1777
+ this.signatureAt = 0
1778
+ this.signatureLength = 0
1779
+ for (let k: i32 = 0; k < toI32(this.extensionSeen.length); k++) {
1780
+ this.extensionSeen[k] = toU32(0)
1781
+ }
1782
+ }
1783
+ }
1784
+
1785
+ /** Records `alert` as `view`'s extension verdict unless an earlier one is there. */
1786
+ const tlsFlightRefuseExtension = (view: TlsServerFlightView, alert: i32): void => {
1787
+ if (view.extensionAlert === 0) {
1788
+ view.extensionAlert = alert
1789
+ }
1790
+ }
1791
+
1792
+ /** Whether the client's hello ever offers extension `type`: what separates `illegal_parameter` from `unsupported_extension` (§4.2). */
1793
+ const tlsClientOffersExtension = (type: i32): boolean =>
1794
+ type === TLS_EXT_SERVER_NAME ||
1795
+ type === TLS_EXT_SUPPORTED_GROUPS ||
1796
+ type === TLS_EXT_SIGNATURE_ALGORITHMS ||
1797
+ type === TLS_EXT_ALPN ||
1798
+ type === TLS_EXT_SUPPORTED_VERSIONS ||
1799
+ type === TLS_EXT_KEY_SHARE ||
1800
+ type === TLS_EXT_COOKIE
1801
+
1802
+ /** Opens `view` on `data[off .. off + len)` and answers its reader, or `null` for a window outside `data` (`decode_error`). */
1803
+ const tlsFlightOpen = (view: TlsServerFlightView, data: u8[], off: i32, len: i32): TlsReader | null => {
1804
+ view.clear()
1805
+ view.data = data
1806
+ if (off < 0 || len < 0 || off > toI32(data.length) - len) {
1807
+ view.alert = TLS_ALERT_DECODE_ERROR
1808
+ return null
1809
+ }
1810
+ const r: TlsReader = view.reader
1811
+ r.data = data
1812
+ r.at = off
1813
+ r.end = off + len
1814
+ r.failed = false
1815
+ return r
1816
+ }
1817
+
1818
+ /** Closes a read: a failed reader, or bytes left before `end`, is `decode_error`. */
1819
+ const tlsFlightClose = (view: TlsServerFlightView, r: TlsReader, end: i32): void => {
1820
+ if (r.failed || r.at !== end) {
1821
+ view.alert = TLS_ALERT_DECODE_ERROR
1822
+ }
1823
+ }
1824
+
1825
+ /**
1826
+ * Reads one ServerHello or HelloRetryRequest extension body, `r.at .. end`,
1827
+ * of type `type`, and judges whether it may be there: `key_share` and
1828
+ * `supported_versions` in either, `cookie` in a HelloRetryRequest alone
1829
+ * (§4.2's table).
1830
+ */
1831
+ const tlsReadServerHelloExtension = (r: TlsReader, type: i32, end: i32, view: TlsServerFlightView): void => {
1832
+ if (type === TLS_EXT_SUPPORTED_VERSIONS) {
1833
+ view.hasSupportedVersions = true
1834
+ view.selectedVersion = tlsReadU16(r)
1835
+ } else if (type === TLS_EXT_KEY_SHARE) {
1836
+ view.hasKeyShare = true
1837
+ view.shareGroup = tlsReadU16(r)
1838
+ if (!view.isRetry) {
1839
+ const keyEnd: i32 = tlsReadVector(r, 2, 1, 65535)
1840
+ view.shareAt = r.at
1841
+ view.shareLength = keyEnd - r.at
1842
+ tlsReadSkipTo(r, keyEnd)
1843
+ }
1844
+ } else if (type === TLS_EXT_COOKIE && view.isRetry) {
1845
+ const cookieEnd: i32 = tlsReadVector(r, 2, 1, 65535)
1846
+ view.hasCookie = true
1847
+ view.cookieAt = r.at
1848
+ view.cookieLength = cookieEnd - r.at
1849
+ tlsReadSkipTo(r, cookieEnd)
1850
+ } else {
1851
+ tlsFlightRefuseExtension(
1852
+ view,
1853
+ tlsClientOffersExtension(type) ? TLS_ALERT_ILLEGAL_PARAMETER : TLS_ALERT_UNSUPPORTED_EXTENSION
1854
+ )
1855
+ tlsReadSkipTo(r, end)
1856
+ }
1857
+ if (r.at !== end) {
1858
+ r.failed = true
1859
+ }
1860
+ }
1861
+
1862
+ /** Reads one EncryptedExtensions body (§4.3.1): ALPN, an empty `server_name` and `supported_groups` may be there. */
1863
+ const tlsReadEncryptedExtension = (r: TlsReader, type: i32, end: i32, view: TlsServerFlightView): void => {
1864
+ if (type === TLS_EXT_ALPN) {
1865
+ // RFC 7301 §3.1: the server's list holds exactly one protocol.
1866
+ const listEnd: i32 = tlsReadVector(r, 2, 2, 65535)
1867
+ const nameEnd: i32 = tlsReadVector(r, 1, 1, 255)
1868
+ view.hasAlpn = true
1869
+ view.alpnAt = r.at
1870
+ view.alpnLength = nameEnd - r.at
1871
+ tlsReadSkipTo(r, nameEnd)
1872
+ if (!r.failed && nameEnd !== listEnd) {
1873
+ tlsFlightRefuseExtension(view, TLS_ALERT_ILLEGAL_PARAMETER)
1874
+ tlsReadSkipTo(r, listEnd)
1875
+ }
1876
+ } else if (type === TLS_EXT_SERVER_NAME) {
1877
+ // RFC 6066 §3: the acknowledgement's body is empty; the check below
1878
+ // refuses one with bytes in it.
1879
+ view.serverNameAcknowledged = true
1880
+ } else if (type === TLS_EXT_SUPPORTED_GROUPS) {
1881
+ // §4.2.7: the server's own preference, which the client may note and
1882
+ // this one does not; only its syntax is checked.
1883
+ tlsReadU16Vector(r, 2, 2, 65535)
1884
+ } else {
1885
+ tlsFlightRefuseExtension(
1886
+ view,
1887
+ tlsClientOffersExtension(type) ? TLS_ALERT_ILLEGAL_PARAMETER : TLS_ALERT_UNSUPPORTED_EXTENSION
1888
+ )
1889
+ tlsReadSkipTo(r, end)
1890
+ }
1891
+ if (r.at !== end) {
1892
+ r.failed = true
1893
+ }
1894
+ }
1895
+
1896
+ /** Reads an extensions block, each body by `hello`'s reader: true for a ServerHello or HelloRetryRequest, false for EncryptedExtensions. */
1897
+ const tlsReadServerExtensions = (r: TlsReader, view: TlsServerFlightView, hello: boolean): void => {
1898
+ const extensionsEnd: i32 = tlsReadVector(r, 2, 0, 65535)
1899
+ const messageEnd: i32 = tlsReadList(r, extensionsEnd)
1900
+ while (!r.failed && r.at < extensionsEnd) {
1901
+ const type: i32 = tlsReadU16(r)
1902
+ const bodyEnd: i32 = tlsReadVector(r, 2, 0, 65535)
1903
+ if (r.failed) {
1904
+ break
1905
+ }
1906
+ if (tlsMarkSeen(view.extensionSeen, type)) {
1907
+ tlsFlightRefuseExtension(view, TLS_ALERT_ILLEGAL_PARAMETER)
1908
+ }
1909
+ const outerEnd: i32 = tlsReadList(r, bodyEnd)
1910
+ if (hello) {
1911
+ tlsReadServerHelloExtension(r, type, bodyEnd, view)
1912
+ } else {
1913
+ tlsReadEncryptedExtension(r, type, bodyEnd, view)
1914
+ }
1915
+ r.end = outerEnd
1916
+ }
1917
+ r.end = messageEnd
1918
+ }
1919
+
1920
+ /** Whether the bytes at `data[at]` are the ones the hex constant `text` spells. */
1921
+ const tlsWindowIsHex = (data: u8[], at: i32, text: string): boolean => {
1922
+ const length: i32 = toI32(text.length) >> 1
1923
+ if (at < 0 || at > toI32(data.length) - length) {
1924
+ return false
1925
+ }
1926
+ for (let k: i32 = 0; k < length; k++) {
1927
+ const hi: i32 = tlsHexNibble(toI32(text.charCodeAt(2 * k)))
1928
+ const lo: i32 = tlsHexNibble(toI32(text.charCodeAt(2 * k + 1)))
1929
+ if (toI32(data[at + k]) !== ((hi << 4) | lo)) {
1930
+ return false
1931
+ }
1932
+ }
1933
+ return true
1934
+ }
1935
+
1936
+ /**
1937
+ * Reads the ServerHello body `data[off .. off + len)` — without its handshake
1938
+ * header — into `view`, which tells a HelloRetryRequest from it by its
1939
+ * `random` (§4.1.3). An absent extensions block parses: it is how a TLS 1.2
1940
+ * or older server answers, which the client refuses for its version.
1941
+ */
1942
+ export const tlsReadServerHello = (view: TlsServerFlightView, data: u8[], off: i32, len: i32): void => {
1943
+ const r: TlsReader | null = tlsFlightOpen(view, data, off, len)
1944
+ if (r === null) {
1945
+ return
1946
+ }
1947
+ view.legacyVersion = tlsReadU16(r)
1948
+ view.randomAt = r.at
1949
+ view.isRetry = tlsWindowIsHex(data, r.at, TLS_HELLO_RETRY_RANDOM) && r.end - r.at >= TLS_RANDOM_SIZE
1950
+ tlsReadSkipTo(r, r.at + TLS_RANDOM_SIZE)
1951
+ const sessionEnd: i32 = tlsReadVector(r, 1, 0, 32)
1952
+ view.sessionIdAt = r.at
1953
+ view.sessionIdLength = sessionEnd - r.at
1954
+ tlsReadSkipTo(r, sessionEnd)
1955
+ view.suite = tlsReadU16(r)
1956
+ view.compression = tlsReadU8(r)
1957
+ if (!r.failed && r.at < off + len) {
1958
+ tlsReadServerExtensions(r, view, true)
1959
+ }
1960
+ tlsFlightClose(view, r, off + len)
1961
+ }
1962
+
1963
+ /** The 8 bytes RFC 8446 §4.1.3 has a TLS 1.3 server put at the end of its random when it negotiates TLS 1.2 or below. */
1964
+ const TLS_DOWNGRADE_12: string = "444f574e47524401"
1965
+ const TLS_DOWNGRADE_11: string = "444f574e47524400"
1966
+
1967
+ /**
1968
+ * Whether the ServerHello in `view` carries a downgrade sentinel in the last
1969
+ * 8 bytes of its random (§4.1.3), which a TLS 1.3 client must refuse with
1970
+ * `illegal_parameter`.
1971
+ */
1972
+ export const tlsServerHelloDowngrade = (view: TlsServerFlightView): boolean => {
1973
+ const at: i32 = view.randomAt + TLS_RANDOM_SIZE - 8
1974
+ return tlsWindowIsHex(view.data, at, TLS_DOWNGRADE_12) || tlsWindowIsHex(view.data, at, TLS_DOWNGRADE_11)
1975
+ }
1976
+
1977
+ /** Reads an EncryptedExtensions body (§4.3.1) into `view`. */
1978
+ export const tlsReadEncryptedExtensions = (
1979
+ view: TlsServerFlightView,
1980
+ data: u8[],
1981
+ off: i32,
1982
+ len: i32
1983
+ ): void => {
1984
+ const r: TlsReader | null = tlsFlightOpen(view, data, off, len)
1985
+ if (r === null) {
1986
+ return
1987
+ }
1988
+ tlsReadServerExtensions(r, view, false)
1989
+ tlsFlightClose(view, r, off + len)
1990
+ }
1991
+
1992
+ /**
1993
+ * Reads a server's Certificate body (§4.4.2) into `view`: the request
1994
+ * context's length, which the client requires to be 0, and the list of
1995
+ * entries. An empty list is `decode_error`, as §4.4.2.4 has a client answer
1996
+ * it; an entry with extensions is `unsupported_extension`, because the
1997
+ * client offers none that a CertificateEntry may carry.
1998
+ */
1999
+ export const tlsReadCertificate = (view: TlsServerFlightView, data: u8[], off: i32, len: i32): void => {
2000
+ const r: TlsReader | null = tlsFlightOpen(view, data, off, len)
2001
+ if (r === null) {
2002
+ return
2003
+ }
2004
+ const contextEnd: i32 = tlsReadVector(r, 1, 0, 255)
2005
+ view.contextLength = contextEnd - r.at
2006
+ tlsReadSkipTo(r, contextEnd)
2007
+ const listEnd: i32 = tlsReadVector(r, 3, 1, 16777215)
2008
+ view.certificatesAt = r.at
2009
+ view.certificatesLength = listEnd - r.at
2010
+ const messageEnd: i32 = tlsReadList(r, listEnd)
2011
+ while (!r.failed && r.at < listEnd) {
2012
+ tlsReadSkipTo(r, tlsReadVector(r, 3, 1, 16777215))
2013
+ const extensionsEnd: i32 = tlsReadVector(r, 2, 0, 65535)
2014
+ if (extensionsEnd !== r.at) {
2015
+ tlsFlightRefuseExtension(view, TLS_ALERT_UNSUPPORTED_EXTENSION)
2016
+ }
2017
+ tlsReadSkipTo(r, extensionsEnd)
2018
+ view.certificateCount = view.certificateCount + 1
2019
+ }
2020
+ r.end = messageEnd
2021
+ tlsFlightClose(view, r, off + len)
2022
+ }
2023
+
2024
+ /** Reads a CertificateVerify body (§4.4.3) into `view`: the scheme and the signature. */
2025
+ export const tlsReadCertificateVerify = (view: TlsServerFlightView, data: u8[], off: i32, len: i32): void => {
2026
+ const r: TlsReader | null = tlsFlightOpen(view, data, off, len)
2027
+ if (r === null) {
2028
+ return
2029
+ }
2030
+ view.scheme = tlsReadU16(r)
2031
+ const signatureEnd: i32 = tlsReadVector(r, 2, 1, 65535)
2032
+ view.signatureAt = r.at
2033
+ view.signatureLength = signatureEnd - r.at
2034
+ tlsReadSkipTo(r, signatureEnd)
2035
+ tlsFlightClose(view, r, off + len)
2036
+ }
2037
+
2038
+ /**
2039
+ * Checks a NewSessionTicket body's structure (§4.6.1) into `view`'s `alert`:
2040
+ * the client keeps no tickets, so it reads one only to discard it, but a
2041
+ * malformed one is still `decode_error`.
2042
+ */
2043
+ export const tlsReadNewSessionTicket = (view: TlsServerFlightView, data: u8[], off: i32, len: i32): void => {
2044
+ const r: TlsReader | null = tlsFlightOpen(view, data, off, len)
2045
+ if (r === null) {
2046
+ return
2047
+ }
2048
+ tlsReadSkipTo(r, r.at + 8)
2049
+ tlsReadSkipTo(r, tlsReadVector(r, 1, 0, 255))
2050
+ tlsReadSkipTo(r, tlsReadVector(r, 2, 1, 65535))
2051
+ tlsReadSkipTo(r, tlsReadVector(r, 2, 0, 65534))
2052
+ tlsFlightClose(view, r, off + len)
2053
+ }
2054
+
2055
+ /** The DER certificates of the Certificate `tlsReadCertificate` last read into `view`, leaf first, each a fresh array. */
2056
+ export const tlsCopyCertificates = (view: TlsServerFlightView): u8[][] => {
2057
+ const chain: u8[][] = []
2058
+ const r: TlsReader = new TlsReader(
2059
+ view.data,
2060
+ view.certificatesAt,
2061
+ view.certificatesAt + view.certificatesLength
2062
+ )
2063
+ while (view.alert === 0 && !r.failed && r.at < r.end) {
2064
+ const certificateEnd: i32 = tlsReadVector(r, 3, 1, 16777215)
2065
+ chain.push(tlsCopyWindow(view.data, r.at, certificateEnd - r.at))
2066
+ tlsReadSkipTo(r, certificateEnd)
2067
+ tlsReadSkipTo(r, tlsReadVector(r, 2, 0, 65535))
2068
+ }
2069
+ return chain
2070
+ }