@amritk/nish-x86_64-linux 0.16.0 → 0.18.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 (58) hide show
  1. package/INSTALL.md +43 -34
  2. package/bin/nish +0 -0
  3. package/package.json +1 -1
  4. package/runtime/nish.d.ts +117 -8
  5. package/runtime/nish.h +50 -13
  6. package/runtime/nish.mjs +71 -7
  7. package/runtime/runtime-host.c +43 -24
  8. package/runtime/runtime-net.c +57 -10
  9. package/runtime/runtime-os.c +62 -20
  10. package/runtime/runtime-simd.c +203 -0
  11. package/runtime/runtime-wasm.c +12 -0
  12. package/runtime/runtime.c +66 -18
  13. package/runtime/shim.mjs +114 -5
  14. package/scripts/build.sh +14 -12
  15. package/std/README.md +168 -36
  16. package/std/crypto/aes.ts +51 -8
  17. package/std/crypto/base64url.ts +25 -12
  18. package/std/crypto/chacha20poly1305.ts +43 -29
  19. package/std/crypto/ct.ts +6 -1
  20. package/std/crypto/hkdf.ts +364 -3
  21. package/std/crypto/hmac.ts +307 -7
  22. package/std/crypto/p256.ts +618 -34
  23. package/std/crypto/sha1.ts +147 -0
  24. package/std/crypto/sha256.ts +3 -2
  25. package/std/crypto/x25519.ts +88 -36
  26. package/std/crypto/x509.ts +130 -47
  27. package/std/json.ts +297 -41
  28. package/std/net/hpack.ts +1094 -0
  29. package/std/net/http-fields.ts +604 -0
  30. package/std/net/http1-server.ts +1389 -0
  31. package/std/net/http1.ts +1492 -0
  32. package/std/net/http2-frame.ts +745 -0
  33. package/std/net/http2-tls.ts +216 -0
  34. package/std/net/http2.ts +1433 -0
  35. package/std/net/http3-frame.ts +457 -0
  36. package/std/net/http3-server.ts +911 -0
  37. package/std/net/http3.ts +2145 -0
  38. package/std/net/qpack.ts +1163 -0
  39. package/std/net/quic-conn-ack.ts +206 -0
  40. package/std/net/quic-conn-cid.ts +425 -0
  41. package/std/net/quic-conn-params.ts +462 -0
  42. package/std/net/quic-datagram.ts +130 -0
  43. package/std/net/quic-frame.ts +1206 -0
  44. package/std/net/quic-listener.ts +929 -0
  45. package/std/net/quic-packet.ts +1698 -0
  46. package/std/net/quic-recovery.ts +849 -0
  47. package/std/net/quic-stream.ts +1609 -0
  48. package/std/net/quic.ts +3578 -0
  49. package/std/net/tls/codec.ts +1089 -0
  50. package/std/net/tls/record-server.ts +1173 -0
  51. package/std/net/tls/record.ts +621 -0
  52. package/std/net/tls/schedule.ts +429 -0
  53. package/std/net/tls-tcp.ts +414 -0
  54. package/std/net/tls.ts +1437 -0
  55. package/std/net/websocket.ts +823 -0
  56. package/std/net/webtransport.ts +1334 -0
  57. package/std/secret.ts +62 -0
  58. package/std/text.ts +77 -0
@@ -0,0 +1,1173 @@
1
+ /**
2
+ * `nish/net/tls/record-server` — a TLS 1.3 server over a byte stream: the
3
+ * record layer of `nish/net/tls/record` wrapped around `nish/net/tls`'s
4
+ * `TlsServer`, sans-IO. Bytes the client sent go in, bytes to send come out,
5
+ * and once the handshake is done application data flows both ways.
6
+ *
7
+ * const conn = new TlsRecordServer(new TlsServer(config, random, key));
8
+ * conn.receive(bytes, 0, n); // what the socket read
9
+ * if ((conn.interest() & TLS_RECORD_SIGN) !== 0) {
10
+ * conn.sign(tlsSignEcdsaP256(leaf, conn.signatureInput()));
11
+ * }
12
+ * // send conn.output[conn.outputStart .. conn.outputEnd), then conn.consume(sent)
13
+ * const got: i32 = conn.read(buf, 0, buf.length); // application data
14
+ *
15
+ * **What it adds to `TlsServer`.** Records around the handshake messages:
16
+ * ServerHello (or HelloRetryRequest) in the clear, the rest of the server's
17
+ * flight — EncryptedExtensions through Finished — in as few records as fit
18
+ * under the handshake keys once it is signed, which is one record for RFC
19
+ * 8448 §3's trace, and every key installed at the record boundary RFC 8446
20
+ * §5.1 puts it on. The middlebox-compatibility `change_cipher_spec` of §D.4:
21
+ * the server sends one right after its first handshake message when the
22
+ * client sent a session id, and drops the client's from its first ClientHello
23
+ * until its Finished. Alerts (§6) both ways: `close_notify` ends the client's
24
+ * stream, `user_canceled` is passed over, any other alert ends the
25
+ * connection, and a refusal of this module's or of `TlsServer`'s is sent as a
26
+ * fatal alert under whatever keys the server writes with. KeyUpdate (§4.6.3)
27
+ * both ways: the client's moves the read keys on and, when it asks, the
28
+ * server answers with its own; `keyUpdate` sends one, and the writer sends
29
+ * one by itself before a key has protected `TLS_KEY_UPDATE_RECORDS` records.
30
+ * More than `TLS_RECORD_IDLE_LIMIT` records in a row that carry nothing for
31
+ * the caller — KeyUpdates among them, which each cost two key derivations —
32
+ * are refused. A stream that ends without `close_notify` is truncation, but
33
+ * only once the records still waiting for the caller have been read.
34
+ *
35
+ * **Fixed buffers.** The record being read, the bytes to send and the
36
+ * application data waiting for the caller each live in an array allocated
37
+ * once, in the constructor, so a connection that has finished its handshake
38
+ * allocates nothing that outlives a record, and a slot can be handed the
39
+ * next connection with `start`. The handshake's messages are sealed straight
40
+ * out of `TlsServer`'s own buffers, and the application secrets are copied
41
+ * into arrays of this slot's, so a slot that hands its `TlsServer` the next
42
+ * connection with `restart` runs every handshake after the first without
43
+ * moving the arena, whichever suite it negotiates; a KeyUpdate's key
44
+ * install leaves nothing either (TLS-3 in `docs/security/tls.md`). When the caller leaves application data unread
45
+ * for long enough to fill its buffer, records stay in the reader and
46
+ * `interest` stops asking for reads, which is how the peer is made to wait.
47
+ *
48
+ * **Secrets.** Each traffic secret is copied out of `TlsServer` as it is
49
+ * installed and the server's copy is wiped with `secureZero`, as are the
50
+ * handshake secret once the flight is signed and the caller's ephemeral key
51
+ * once the ServerHello is written, or the handshake fails. The two application traffic secrets live
52
+ * on here, for KeyUpdate: each is overwritten in place by the next, and both
53
+ * are wiped, with both directions' keys, by `wipeKeys` when the carrier
54
+ * closes the slot and by `start`. What stays unwiped is TLS-1's and TLS-2's.
55
+ *
56
+ * Refusals are alerts, never panics. Written from RFC 8446 §4.6.3, §5, §6
57
+ * and §D.4, not ported from another implementation.
58
+ */
59
+ import {
60
+ TLS_LEVEL_APPLICATION,
61
+ TLS_LEVEL_HANDSHAKE,
62
+ TLS_LEVEL_INITIAL,
63
+ TLS_STATE_CONNECTED,
64
+ TLS_STATE_FAILED,
65
+ TLS_STATE_WAIT_CLIENT_HELLO,
66
+ TLS_STATE_WAIT_FINISHED,
67
+ TLS_STATE_WAIT_SIGNATURE,
68
+ TlsServer,
69
+ } from "nish/net/tls"
70
+ import { SHA256_SIZE } from "nish/crypto/sha256"
71
+ import { SHA384_SIZE } from "nish/crypto/sha512"
72
+ import {
73
+ TLS_ALERT_DECODE_ERROR,
74
+ TLS_ALERT_ILLEGAL_PARAMETER,
75
+ TLS_ALERT_INTERNAL_ERROR,
76
+ TLS_ALERT_UNEXPECTED_MESSAGE,
77
+ } from "nish/net/tls/codec"
78
+ import {
79
+ TLS_ALERT_CLOSE_NOTIFY,
80
+ TLS_ALERT_LEVEL_FATAL,
81
+ TLS_ALERT_LEVEL_WARNING,
82
+ TLS_ALERT_USER_CANCELED,
83
+ TLS_CONTENT_ALERT,
84
+ TLS_CONTENT_APPLICATION_DATA,
85
+ TLS_CONTENT_CHANGE_CIPHER_SPEC,
86
+ TLS_CONTENT_HANDSHAKE,
87
+ TLS_HANDSHAKE_KEY_UPDATE,
88
+ TLS_MAX_PLAINTEXT,
89
+ TLS_MAX_RECORD,
90
+ TLS_RECORD_HEADER_SIZE,
91
+ TLS_RECORD_TAG_SIZE,
92
+ TlsRecordProtection,
93
+ TlsRecordReader,
94
+ tlsRecordWindowFits,
95
+ } from "nish/net/tls/record"
96
+
97
+ // ---- States ----------------------------------------------------------------------
98
+
99
+ /** The handshake is under way. */
100
+ export const TLS_RECORD_STATE_HANDSHAKE: i32 = 0
101
+ /** The client's Finished verified: application data flows both ways. */
102
+ export const TLS_RECORD_STATE_OPEN: i32 = 1
103
+ /** The server's `close_notify` is written; it sends nothing more, and may still read. */
104
+ export const TLS_RECORD_STATE_CLOSED: i32 = 2
105
+ /** The connection ended on an alert, sent (`alert`) or received (`peerAlert`), or on a stream cut short. */
106
+ export const TLS_RECORD_STATE_FAILED: i32 = 3
107
+
108
+ // ---- What the connection wants, from `interest` -----------------------------------
109
+
110
+ /** There is room for more of the stream: read the socket. */
111
+ export const TLS_RECORD_WANT_READ: i32 = 1
112
+ /** `output` holds bytes to send: write the socket. */
113
+ export const TLS_RECORD_WANT_WRITE: i32 = 2
114
+ /** `read` has application data, or the end of the client's stream, to give. */
115
+ export const TLS_RECORD_DATA: i32 = 4
116
+ /** The server is waiting for its CertificateVerify signature: `signatureInput`, then `sign`. */
117
+ export const TLS_RECORD_SIGN: i32 = 8
118
+ /** Nothing more will happen: the connection failed or closed, and everything to send is sent. */
119
+ export const TLS_RECORD_DONE: i32 = 16
120
+
121
+ /** What `read` and `write` answer once the connection has failed: Linux's ECONNRESET, as `nish:net` spells it. */
122
+ export const TLS_RECORD_RESET: i32 = -104
123
+ /** What `write` answers once the server has closed: Linux's EPIPE, as `nish:net` spells it. */
124
+ export const TLS_RECORD_PIPE: i32 = -32
125
+ /** What `read`, `write` and `keyUpdate` answer when they have to wait: Linux's EAGAIN, as `nish:net` spells it. */
126
+ export const TLS_RECORD_AGAIN: i32 = -11
127
+ /** What `read` and `write` answer for a window outside the caller's array: Linux's EINVAL. */
128
+ export const TLS_RECORD_INVALID: i32 = -22
129
+
130
+ /** The output buffer: two of the largest records, so a record can be sealed while another is still being sent. */
131
+ const TLS_RECORD_OUTPUT_SIZE: i32 = 2 * TLS_MAX_RECORD
132
+ /** The application data buffer: two records' worth, so one is opened while the caller reads the other. */
133
+ const TLS_RECORD_PLAIN_SIZE: i32 = 2 * TLS_MAX_PLAINTEXT
134
+ /** Where a record's content is opened to before it is handed on: the most content a record carries. */
135
+ const TLS_RECORD_SCRATCH_SIZE: i32 = TLS_MAX_PLAINTEXT
136
+ /** A KeyUpdate message: type, a 24-bit length of 1, and `request_update`. */
137
+ const TLS_KEY_UPDATE_SIZE: i32 = 5
138
+ /** Where ServerHello and HelloRetryRequest hold `legacy_session_id_echo`'s length: past the header, version and random. */
139
+ const TLS_SESSION_ID_ECHO_AT: i32 = 38
140
+
141
+ /**
142
+ * How many records in a row may carry nothing for the caller — a
143
+ * `change_cipher_spec`, empty application data, a `user_canceled` warning, a
144
+ * KeyUpdate or a piece of one — before the connection is refused with
145
+ * `unexpected_message`. Each costs the server work, a KeyUpdate two key
146
+ * derivations, and none moves the connection on. Sixteen is Go's
147
+ * `maxUselessRecords`; a record of application data, or of the handshake,
148
+ * starts the count again.
149
+ */
150
+ export const TLS_RECORD_IDLE_LIMIT: i32 = 16
151
+
152
+ /**
153
+ * How many KeyUpdates one connection takes from its client before refusing
154
+ * the next with `unexpected_message`. Each costs one key install, two when
155
+ * the server answers, which leave nothing in the arena; the cap bounds the
156
+ * work a client can ask for, as `TLS_RECORD_IDLE_LIMIT` does in a row. A
157
+ * client that
158
+ * updates when RFC 8446 §5.5 asks, once per 2^24 records, reaches it after
159
+ * 2^30 records; §4.6.3 itself sets no limit, so one that updates on a clock of
160
+ * its own is cut off at the sixty-fifth, a trade-off TLS-3 records.
161
+ */
162
+ export const TLS_RECORD_MAX_KEY_UPDATES: i32 = 64
163
+
164
+ /** A typed zero for the offsets below: a bare literal is an `f64` under `--number-mode f64`. */
165
+ const TLS_RECORD_SERVER_FROM: i32 = 0
166
+
167
+ /**
168
+ * Copies a traffic secret out of `TlsServer` into `long` when it is that
169
+ * array's length and into `short` otherwise, so the server's own can be wiped
170
+ * while this one lives on, and answers the array; `none` when there is no
171
+ * secret.
172
+ */
173
+ const tlsKeepSecret = (secret: u8[] | null, short: u8[], long: u8[], none: u8[]): u8[] => {
174
+ if (secret === null) {
175
+ return none
176
+ }
177
+ const length: i32 = toI32(secret.length)
178
+ const out: u8[] = length === toI32(long.length) ? long : short
179
+ for (let k: i32 = 0; k < toI32(out.length) && k < length; k++) {
180
+ out[k] = secret[k]
181
+ }
182
+ return out
183
+ }
184
+
185
+ /**
186
+ * One TLS 1.3 server connection over a stream. Allocate one per slot, hand it
187
+ * each connection's `TlsServer` with `start`, and drive it with `receive`,
188
+ * `consume`, `read`, `write` and `sign` as `interest` says.
189
+ *
190
+ * The fields are readable: `state`, `alert` (the alert this server sent, or
191
+ * 0), `peerAlert` (the error alert the client sent, or -1), `peerClosed`
192
+ * (the client's `close_notify` arrived), `tls` (the handshake: suite, ALPN,
193
+ * server name, exporter secret), and the two protections with their
194
+ * sequence numbers. `padding` is how many zero bytes each protected record
195
+ * the server writes carries after its content type (§5.4), 0 unless the
196
+ * caller sets it.
197
+ */
198
+ export class TlsRecordServer {
199
+ tls: TlsServer
200
+ reader: TlsRecordReader
201
+ readProtection: TlsRecordProtection
202
+ writeProtection: TlsRecordProtection
203
+ /** Bytes to send are `output[outputStart .. outputEnd)`. */
204
+ output: u8[]
205
+ /** Application data the caller has not read is `plain[plainStart .. plainEnd)`. */
206
+ plain: u8[]
207
+ scratch: u8[]
208
+ /** The client's and the server's current application traffic secrets, for KeyUpdate. */
209
+ readSecret: u8[]
210
+ writeSecret: u8[]
211
+ /** The arrays those two point into, one of each hash's length, and the empty one they point at before. */
212
+ readSecret256: u8[]
213
+ readSecret384: u8[]
214
+ writeSecret256: u8[]
215
+ writeSecret384: u8[]
216
+ none: u8[]
217
+ /** A post-handshake message the client has sent part of. */
218
+ postHandshake: u8[]
219
+ state: i32 = 0
220
+ alert: i32 = 0
221
+ peerAlert: i32 = -1
222
+ padding: i32 = 0
223
+ /** The `TLS_LEVEL_*` the client's records are read at: Initial in the clear, then Handshake, then Application. */
224
+ readLevel: i32 = 0
225
+ /** The `TLS_LEVEL_*` the server's records are written at. */
226
+ writeLevel: i32 = 0
227
+ outputStart: i32 = 0
228
+ outputEnd: i32 = 0
229
+ plainStart: i32 = 0
230
+ plainEnd: i32 = 0
231
+ /** How much of `TlsServer`'s Initial-level output is already in records. */
232
+ pendingInitialAt: i32 = 0
233
+ /** How much of `TlsServer`'s Handshake-level output is already in records. */
234
+ pendingHandshakeAt: i32 = 0
235
+ /** The server's flight is signed and finished, so its Handshake-level output may be sealed. */
236
+ flightReady: boolean = false
237
+ postHandshakeLength: i32 = 0
238
+ /** Records in a row that carried nothing for the caller, against `TLS_RECORD_IDLE_LIMIT`. */
239
+ idleRecords: i32 = 0
240
+ /** KeyUpdates taken from the client, against `TLS_RECORD_MAX_KEY_UPDATES`. */
241
+ keyUpdates: i32 = 0
242
+ peerClosed: boolean = false
243
+ /** The client's TCP stream ended. Without a `close_notify` before it, that is truncation and the connection failed. */
244
+ ended: boolean = false
245
+ /** Whether the server's first handshake message has been seen, which decides the compatibility record. */
246
+ firstMessageSeen: boolean = false
247
+ /** The compatibility `change_cipher_spec` is owed, after the first handshake message (§D.4). */
248
+ ccsDue: boolean = false
249
+ /** The client's first handshake byte has arrived, which opens the window its `change_cipher_spec` may come in. */
250
+ started: boolean = false
251
+ /** The server owes a KeyUpdate before its next application data (§4.6.3). */
252
+ keyUpdateDue: boolean = false
253
+ /** The server has closed and its `close_notify` waits for room in `output`. */
254
+ closeDue: boolean = false
255
+
256
+ constructor(tls: TlsServer) {
257
+ this.tls = tls
258
+ this.reader = new TlsRecordReader()
259
+ this.readProtection = new TlsRecordProtection()
260
+ this.writeProtection = new TlsRecordProtection()
261
+ this.output = new Array<u8>(TLS_RECORD_OUTPUT_SIZE)
262
+ this.plain = new Array<u8>(TLS_RECORD_PLAIN_SIZE)
263
+ this.scratch = new Array<u8>(TLS_RECORD_SCRATCH_SIZE)
264
+ this.none = []
265
+ this.readSecret256 = new Array<u8>(SHA256_SIZE)
266
+ this.readSecret384 = new Array<u8>(SHA384_SIZE)
267
+ this.writeSecret256 = new Array<u8>(SHA256_SIZE)
268
+ this.writeSecret384 = new Array<u8>(SHA384_SIZE)
269
+ this.readSecret = this.none
270
+ this.writeSecret = this.none
271
+ this.postHandshake = new Array<u8>(TLS_KEY_UPDATE_SIZE)
272
+ this.start(tls)
273
+ }
274
+
275
+ /**
276
+ * Starts a new connection in this slot with `tls`, which should be fresh
277
+ * or just restarted (`TlsServer.restart`, which reuses its buffers):
278
+ * every buffer is emptied and the keys of the last connection are wiped;
279
+ * the buffers are reused, and nothing is allocated. A
280
+ * `tls` that has already failed — a configuration
281
+ * or randomness `TlsServer` refused — fails this connection at once, with
282
+ * its alert queued in the clear.
283
+ */
284
+ start(tls: TlsServer): void {
285
+ // The last connection's traffic keys. Its ephemeral key was wiped when it
286
+ // was used, when it failed or when its slot was closed, and is not
287
+ // touched here: the array may already hold the next connection's.
288
+ this.wipeTraffic()
289
+ this.readSecret = this.none
290
+ this.writeSecret = this.none
291
+ this.tls = tls
292
+ this.state = TLS_RECORD_STATE_HANDSHAKE
293
+ this.alert = 0
294
+ this.peerAlert = -1
295
+ this.peerClosed = false
296
+ this.ended = false
297
+ this.reader.reset()
298
+ this.readLevel = TLS_LEVEL_INITIAL
299
+ this.writeLevel = TLS_LEVEL_INITIAL
300
+ this.dropOutput()
301
+ this.plainStart = 0
302
+ this.plainEnd = 0
303
+ this.firstMessageSeen = false
304
+ this.started = false
305
+ this.postHandshakeLength = 0
306
+ this.idleRecords = 0
307
+ this.keyUpdates = 0
308
+ if (tls.state === TLS_STATE_FAILED) {
309
+ this.fail(tls.alert)
310
+ }
311
+ }
312
+
313
+ /**
314
+ * Wipes every key this connection holds: the two application traffic
315
+ * secrets it keeps for KeyUpdate, both directions' keys, and what is left
316
+ * in `TlsServer` (`wipeHandshake`). The carrier calls it when a slot is
317
+ * closed, so a free slot holds no key.
318
+ */
319
+ wipeKeys(): void {
320
+ this.wipeTraffic()
321
+ this.wipeHandshake()
322
+ }
323
+
324
+ /** Wipes the two application traffic secrets and both directions' keys. */
325
+ wipeTraffic(): void {
326
+ // The two secret fields point into these four arrays, or at nothing.
327
+ secureZero(this.readSecret256)
328
+ secureZero(this.readSecret384)
329
+ secureZero(this.writeSecret256)
330
+ secureZero(this.writeSecret384)
331
+ this.readProtection.clear()
332
+ this.writeProtection.clear()
333
+ }
334
+
335
+ /**
336
+ * Wipes every secret `TlsServer` still holds — the ephemeral key it was
337
+ * handed, the handshake, traffic and exporter secrets and the expected
338
+ * Finished — for a connection that has failed or is closed. On the way to
339
+ * an open connection each is wiped as soon as it has been used; this is
340
+ * for the ways that end early, and for the exporter secret, which a caller
341
+ * may read until the connection ends.
342
+ */
343
+ wipeHandshake(): void {
344
+ const tls: TlsServer = this.tls
345
+ secureZero(tls.ephemeralPrivate)
346
+ secureZero(tls.handshakeSecret)
347
+ secureZero(tls.clientHandshakeSecret)
348
+ secureZero(tls.serverHandshakeSecret)
349
+ secureZero(tls.clientApplicationSecret)
350
+ secureZero(tls.serverApplicationSecret)
351
+ secureZero(tls.exporterSecret)
352
+ secureZero(tls.expectedClientFinished)
353
+ }
354
+
355
+ /** How many bytes `receive` would take now: what the socket should read at most. */
356
+ space(): i32 {
357
+ return this.reader.space()
358
+ }
359
+
360
+ /**
361
+ * Takes bytes of the client's stream, `data[off .. off + len)`, and handles
362
+ * every record they complete. Answers how many it took, which is fewer than
363
+ * `len` only when its buffers are full (read `interest` before reading the
364
+ * socket again), or `TLS_RECORD_INVALID` for a window outside `data`. Once
365
+ * the connection has failed, or the client has sent `close_notify`, bytes
366
+ * are taken and dropped (§6.1).
367
+ */
368
+ receive(data: u8[], off: i32, len: i32): i32 {
369
+ if (!tlsRecordWindowFits(toI32(data.length), off, len)) {
370
+ return TLS_RECORD_INVALID
371
+ }
372
+ if (this.state === TLS_RECORD_STATE_FAILED || this.peerClosed) {
373
+ return len
374
+ }
375
+ const taken: i32 = this.reader.push(data, off, len)
376
+ this.process()
377
+ return taken
378
+ }
379
+
380
+ /**
381
+ * The client's TCP stream ended. After its `close_notify` that is the
382
+ * orderly end; before it, the stream was cut short — truncation, which an
383
+ * attacker on the path can cause — and the connection fails with nothing
384
+ * sent, since there is nobody left to read it.
385
+ */
386
+ end(): void {
387
+ this.ended = true
388
+ this.process()
389
+ }
390
+
391
+ /**
392
+ * Once the client's stream has ended and every whole record it held is
393
+ * handled, an end without `close_notify` is truncation: the connection
394
+ * fails, with nothing more sent, though what is already on `output` may
395
+ * still go out. Records still waiting for the caller to read, or for the
396
+ * signature, are handled first, so a `close_notify` among them counts.
397
+ */
398
+ checkTruncation(): void {
399
+ if (this.ended && !this.peerClosed && this.state !== TLS_RECORD_STATE_FAILED && this.reader.next() <= 0) {
400
+ this.state = TLS_RECORD_STATE_FAILED
401
+ this.dropPending()
402
+ this.wipeHandshake()
403
+ }
404
+ }
405
+
406
+ /** The socket failed under the connection: it ends with nothing more sent. */
407
+ abort(): void {
408
+ this.state = TLS_RECORD_STATE_FAILED
409
+ this.dropOutput()
410
+ }
411
+
412
+ /** Forgets everything waiting to be sent. */
413
+ dropOutput(): void {
414
+ this.outputStart = 0
415
+ this.outputEnd = 0
416
+ this.dropPending()
417
+ }
418
+
419
+ /** Forgets what is owed but not yet sealed: the handshake queues, the compatibility record, a KeyUpdate and a close. */
420
+ dropPending(): void {
421
+ this.tls.clearOutput(TLS_LEVEL_INITIAL)
422
+ this.tls.clearOutput(TLS_LEVEL_HANDSHAKE)
423
+ this.pendingInitialAt = 0
424
+ this.pendingHandshakeAt = 0
425
+ this.flightReady = false
426
+ this.ccsDue = false
427
+ this.keyUpdateDue = false
428
+ this.closeDue = false
429
+ }
430
+
431
+ /**
432
+ * Handles every whole record the reader holds, as far as the application
433
+ * data buffer has room for. While the server waits for its signature the
434
+ * records stay where they are, and `sign` comes back for them: a client has
435
+ * nothing to send then but a `change_cipher_spec`, and holding the rest
436
+ * means bytes mean the same thing however the stream was cut.
437
+ */
438
+ process(): void {
439
+ while (this.state !== TLS_RECORD_STATE_FAILED && !this.peerClosed) {
440
+ if (this.tls.state === TLS_STATE_WAIT_SIGNATURE) {
441
+ break
442
+ }
443
+ const n: i32 = this.reader.next()
444
+ if (n < 0) {
445
+ this.fail(-n)
446
+ return
447
+ }
448
+ if (n === 0) {
449
+ break
450
+ }
451
+ if (this.readLevel === TLS_LEVEL_APPLICATION && !this.plainHasRoom()) {
452
+ break
453
+ }
454
+ const alert: i32 = this.handleRecord(this.reader.buffer, this.reader.start, n)
455
+ this.reader.consume(n)
456
+ if (alert !== 0) {
457
+ this.fail(alert)
458
+ return
459
+ }
460
+ }
461
+ this.checkTruncation()
462
+ this.pump()
463
+ }
464
+
465
+ /**
466
+ * Whether a whole record's content fits beside what the caller has not
467
+ * read, moving that to the front when it would then fit and only then, so
468
+ * a caller reading a byte at a time does not move the buffer each time.
469
+ */
470
+ plainHasRoom(): boolean {
471
+ const capacity: i32 = toI32(this.plain.length)
472
+ if (capacity - (this.plainEnd - this.plainStart) < TLS_MAX_PLAINTEXT) {
473
+ return false
474
+ }
475
+ if (capacity - this.plainEnd < TLS_MAX_PLAINTEXT) {
476
+ const held: i32 = this.plainEnd - this.plainStart
477
+ for (let k: i32 = 0; k < held; k++) {
478
+ this.plain[k] = this.plain[this.plainStart + k]
479
+ }
480
+ this.plainStart = 0
481
+ this.plainEnd = held
482
+ }
483
+ return true
484
+ }
485
+
486
+ /** Counts a record that carried nothing for the caller: 0, or `unexpected_message` once there are too many in a row. */
487
+ idle(): i32 {
488
+ this.idleRecords = this.idleRecords + 1
489
+ return this.idleRecords > TLS_RECORD_IDLE_LIMIT ? TLS_ALERT_UNEXPECTED_MESSAGE : 0
490
+ }
491
+
492
+ /**
493
+ * One whole record, `buf[off .. off + n)`. A `change_cipher_spec` is
494
+ * judged on its own; anything else is opened under the read protection
495
+ * into `scratch`, and its content goes to `handleApplicationRecord` once the
496
+ * handshake is done, to the handshake before. Answers 0 or the alert.
497
+ */
498
+ handleRecord(buf: u8[], off: i32, n: i32): i32 {
499
+ if (toI32(buf[off]) === TLS_CONTENT_CHANGE_CIPHER_SPEC) {
500
+ return this.handleChangeCipherSpec(buf, off, n - TLS_RECORD_HEADER_SIZE)
501
+ }
502
+ const length: i32 = this.readProtection.open(buf, off, n, this.scratch, TLS_RECORD_SERVER_FROM)
503
+ if (length < 0) {
504
+ return -length
505
+ }
506
+ if (this.readLevel === TLS_LEVEL_APPLICATION) {
507
+ return this.handleApplicationRecord(length)
508
+ }
509
+ switch (this.readProtection.contentType) {
510
+ case TLS_CONTENT_HANDSHAKE:
511
+ return this.handleHandshake(length)
512
+ case TLS_CONTENT_ALERT:
513
+ // §5.1: an alert may not fall between the records of one handshake message.
514
+ return this.tls.inputLength > 0 ? TLS_ALERT_UNEXPECTED_MESSAGE : this.handleAlert(length)
515
+ default:
516
+ // Application data before the client's Finished, a protected
517
+ // change_cipher_spec (§5), or a type nobody defined.
518
+ return TLS_ALERT_UNEXPECTED_MESSAGE
519
+ }
520
+ }
521
+
522
+ /**
523
+ * The compatibility record (§5, §D.4): one byte of 1, in the clear, from
524
+ * the client's first ClientHello until its Finished, and not between the
525
+ * records of one handshake message. It is dropped; anything else is
526
+ * `unexpected_message`.
527
+ */
528
+ handleChangeCipherSpec(buf: u8[], off: i32, length: i32): i32 {
529
+ if (length !== 1 || toI32(buf[off + TLS_RECORD_HEADER_SIZE]) !== 1) {
530
+ return TLS_ALERT_UNEXPECTED_MESSAGE
531
+ }
532
+ if (!this.started || this.readLevel === TLS_LEVEL_APPLICATION || this.tls.inputLength > 0) {
533
+ return TLS_ALERT_UNEXPECTED_MESSAGE
534
+ }
535
+ return this.idle()
536
+ }
537
+
538
+ /**
539
+ * Handshake bytes, `scratch[0 .. length)`, for `TlsServer` at the level
540
+ * they were read at. An empty fragment is `unexpected_message` (§5.1 forbids
541
+ * sending one); `TlsServer`'s own answer otherwise.
542
+ */
543
+ handleHandshake(length: i32): i32 {
544
+ if (length === 0) {
545
+ return TLS_ALERT_UNEXPECTED_MESSAGE
546
+ }
547
+ this.started = true
548
+ this.idleRecords = 0
549
+ const alert: i32 = this.tls.receive(this.readLevel, this.scratch, TLS_RECORD_SERVER_FROM, length)
550
+ if (alert !== 0) {
551
+ return alert
552
+ }
553
+ this.advance()
554
+ return 0
555
+ }
556
+
557
+ /**
558
+ * A record under the client's application keys, its `length` bytes of
559
+ * content opened into `scratch`. Application data goes to
560
+ * the caller's buffer, which `process` made room in; an alert and a
561
+ * post-handshake message are handled here; and a post-handshake message the
562
+ * client has sent part of may not be interrupted by anything else (§5.1).
563
+ */
564
+ handleApplicationRecord(length: i32): i32 {
565
+ const type: i32 = this.readProtection.contentType
566
+ if (this.postHandshakeLength > 0 && type !== TLS_CONTENT_HANDSHAKE) {
567
+ return TLS_ALERT_UNEXPECTED_MESSAGE
568
+ }
569
+ switch (type) {
570
+ case TLS_CONTENT_APPLICATION_DATA: {
571
+ if (length === 0) {
572
+ return this.idle()
573
+ }
574
+ for (let k: i32 = 0; k < length && this.plainEnd + k < toI32(this.plain.length); k++) {
575
+ this.plain[this.plainEnd + k] = this.scratch[k]
576
+ }
577
+ this.plainEnd = this.plainEnd + length
578
+ this.idleRecords = 0
579
+ return 0
580
+ }
581
+ case TLS_CONTENT_ALERT:
582
+ return this.handleAlert(length)
583
+ case TLS_CONTENT_HANDSHAKE:
584
+ return length === 0 ? TLS_ALERT_UNEXPECTED_MESSAGE : this.handlePostHandshake(length)
585
+ default:
586
+ return TLS_ALERT_UNEXPECTED_MESSAGE
587
+ }
588
+ }
589
+
590
+ /**
591
+ * An alert, `scratch[0 .. length)` (§6): two bytes, or `decode_error`. The
592
+ * level is not read, as §6 allows. `close_notify` ends the client's
593
+ * stream, `user_canceled` is passed over, and any other description — one
594
+ * this module does not know included (§6.2) — ends the connection with
595
+ * nothing more sent.
596
+ */
597
+ handleAlert(length: i32): i32 {
598
+ if (length !== 2) {
599
+ return TLS_ALERT_DECODE_ERROR
600
+ }
601
+ const description: i32 = toI32(this.scratch[1])
602
+ if (description === TLS_ALERT_CLOSE_NOTIFY) {
603
+ this.peerClosed = true
604
+ return 0
605
+ }
606
+ if (description === TLS_ALERT_USER_CANCELED) {
607
+ return this.idle()
608
+ }
609
+ this.peerAlert = description
610
+ this.state = TLS_RECORD_STATE_FAILED
611
+ this.dropOutput()
612
+ return 0
613
+ }
614
+
615
+ /**
616
+ * Post-handshake handshake bytes, `scratch[0 .. length)`. The only message
617
+ * a client sends this server after its Finished is KeyUpdate (no
618
+ * certificate was requested, so no post-handshake authentication): another
619
+ * type is `unexpected_message`, a length other than 1 `decode_error`, a
620
+ * `request_update` other than 0 or 1 `illegal_parameter` (§4.6.3), and a
621
+ * KeyUpdate that does not end its record `unexpected_message`, since the
622
+ * keys change after it (§5.1). The message may start in an earlier record.
623
+ */
624
+ handlePostHandshake(length: i32): i32 {
625
+ const idle: i32 = this.idle()
626
+ if (idle !== 0) {
627
+ return idle
628
+ }
629
+ // The buffer never holds a whole message: the fifth byte either ends it
630
+ // or is refused, so `postHandshakeLength` stays below its length.
631
+ for (let k: i32 = 0; k < length && this.postHandshakeLength < toI32(this.postHandshake.length); k++) {
632
+ this.postHandshake[this.postHandshakeLength] = this.scratch[k]
633
+ this.postHandshakeLength = this.postHandshakeLength + 1
634
+ const held: i32 = this.postHandshakeLength
635
+ if (held === 1 && toI32(this.postHandshake[0]) !== TLS_HANDSHAKE_KEY_UPDATE) {
636
+ return TLS_ALERT_UNEXPECTED_MESSAGE
637
+ }
638
+ if (held === 4) {
639
+ const body: i32 =
640
+ (toI32(this.postHandshake[1]) << 16) |
641
+ (toI32(this.postHandshake[2]) << 8) |
642
+ toI32(this.postHandshake[3])
643
+ if (body !== 1) {
644
+ return TLS_ALERT_DECODE_ERROR
645
+ }
646
+ }
647
+ if (held === TLS_KEY_UPDATE_SIZE) {
648
+ const request: i32 = toI32(this.postHandshake[4])
649
+ if (request > 1) {
650
+ return TLS_ALERT_ILLEGAL_PARAMETER
651
+ }
652
+ if (k !== length - 1) {
653
+ return TLS_ALERT_UNEXPECTED_MESSAGE
654
+ }
655
+ this.postHandshakeLength = 0
656
+ if (this.keyUpdates >= TLS_RECORD_MAX_KEY_UPDATES) {
657
+ return TLS_ALERT_UNEXPECTED_MESSAGE
658
+ }
659
+ this.keyUpdates = this.keyUpdates + 1
660
+ return this.updateReadKeys(request === 1)
661
+ }
662
+ }
663
+ return 0
664
+ }
665
+
666
+ /**
667
+ * The client's KeyUpdate: its next records are under the next secret
668
+ * (§7.2), the old one wiped. When it asked for an update the server owes
669
+ * one of its own before its next application data, which `pump` sends.
670
+ * Answers 0, or `internal_error` when the keys do not install, which only
671
+ * a secret of the wrong length could cause.
672
+ */
673
+ updateReadKeys(requested: boolean): i32 {
674
+ if (!this.readProtection.advance(this.readSecret)) {
675
+ return TLS_ALERT_INTERNAL_ERROR
676
+ }
677
+ if (requested) {
678
+ this.keyUpdateDue = true
679
+ }
680
+ return 0
681
+ }
682
+
683
+ /**
684
+ * Picks up what `TlsServer` did with the last bytes or the signature: its
685
+ * ServerHello or HelloRetryRequest, the read keys of each level as they
686
+ * appear, the signed flight, and the end of the handshake. The secrets it
687
+ * hands over are copied or installed and then wiped in `TlsServer`, so
688
+ * that only this connection holds them.
689
+ */
690
+ advance(): void {
691
+ const tls: TlsServer = this.tls
692
+ if (tls.outputInitialLength > 0 && !this.firstMessageSeen) {
693
+ // §D.4: in compatibility mode, which a client asks for with a session
694
+ // id, the server's first handshake message is followed by a
695
+ // change_cipher_spec. The server echoes the id, so its own message says.
696
+ this.firstMessageSeen = true
697
+ this.ccsDue =
698
+ tls.outputInitialLength > TLS_SESSION_ID_ECHO_AT &&
699
+ TLS_SESSION_ID_ECHO_AT < toI32(tls.outputInitial.length) &&
700
+ toI32(tls.outputInitial[TLS_SESSION_ID_ECHO_AT]) > 0
701
+ }
702
+ if (this.readLevel === TLS_LEVEL_INITIAL) {
703
+ const handshake: u8[] | null = tls.readSecret(TLS_LEVEL_HANDSHAKE)
704
+ if (handshake !== null) {
705
+ this.readProtection.install(tls.suite, handshake)
706
+ this.readLevel = TLS_LEVEL_HANDSHAKE
707
+ }
708
+ }
709
+ if (tls.state !== TLS_STATE_WAIT_CLIENT_HELLO) {
710
+ // The ServerHello is written, so the exchange is done with the key.
711
+ secureZero(tls.ephemeralPrivate)
712
+ }
713
+ if (tls.state === TLS_STATE_WAIT_FINISHED || tls.state === TLS_STATE_CONNECTED) {
714
+ this.flightReady = true
715
+ // The flight is signed and finished: the handshake secret and the
716
+ // client's handshake secret have done their work in `TlsServer`, and
717
+ // the read keys made from the latter are installed.
718
+ secureZero(tls.handshakeSecret)
719
+ secureZero(tls.clientHandshakeSecret)
720
+ }
721
+ if (tls.state === TLS_STATE_CONNECTED && this.readLevel === TLS_LEVEL_HANDSHAKE) {
722
+ this.readSecret = tlsKeepSecret(
723
+ tls.readSecret(TLS_LEVEL_APPLICATION),
724
+ this.readSecret256,
725
+ this.readSecret384,
726
+ this.none
727
+ )
728
+ secureZero(tls.clientApplicationSecret)
729
+ // A direction whose keys did not install would read in the clear.
730
+ if (!this.readProtection.install(tls.suite, this.readSecret)) {
731
+ this.fail(TLS_ALERT_INTERNAL_ERROR)
732
+ return
733
+ }
734
+ this.readLevel = TLS_LEVEL_APPLICATION
735
+ if (this.state === TLS_RECORD_STATE_HANDSHAKE) {
736
+ this.state = TLS_RECORD_STATE_OPEN
737
+ }
738
+ }
739
+ this.pump()
740
+ }
741
+
742
+ /** Whether `need` more bytes fit in `output`, moving what is unsent to the front first. */
743
+ outputHasRoom(need: i32): boolean {
744
+ const capacity: i32 = toI32(this.output.length)
745
+ if (this.outputEnd + need > capacity && this.outputStart > 0) {
746
+ const held: i32 = this.outputEnd - this.outputStart
747
+ for (let k: i32 = 0; k < held; k++) {
748
+ this.output[k] = this.output[this.outputStart + k]
749
+ }
750
+ this.outputStart = 0
751
+ this.outputEnd = held
752
+ }
753
+ return this.outputEnd + need <= capacity
754
+ }
755
+
756
+ /**
757
+ * The most content one record may carry under the write protection as it
758
+ * stands: 2^14 bytes, less the padding each protected record carries, since
759
+ * the content, its type and the padding together may not pass 2^14 + 1
760
+ * (§5.4). Below 1 when the padding leaves no room at all.
761
+ */
762
+ maxChunk(): i32 {
763
+ return TLS_MAX_PLAINTEXT - this.writePadding()
764
+ }
765
+
766
+ /** The padding the next record carries: `padding` once records are protected, none in the clear. */
767
+ writePadding(): i32 {
768
+ return this.writeProtection.isProtected() ? this.padding : 0
769
+ }
770
+
771
+ /** The room a record of `len` content bytes takes in `output` under the write protection as it stands. */
772
+ recordRoom(len: i32): i32 {
773
+ if (!this.writeProtection.isProtected()) {
774
+ return TLS_RECORD_HEADER_SIZE + len
775
+ }
776
+ return TLS_RECORD_HEADER_SIZE + len + 1 + this.writePadding() + TLS_RECORD_TAG_SIZE
777
+ }
778
+
779
+ /**
780
+ * Seals one record of `type` from `data[off .. off + len)` onto `output`
781
+ * under the write protection, padded when it is protected. False, writing
782
+ * nothing, when it does not fit; a refusal from `seal` itself, which only a
783
+ * mistake here could cause, fails the connection.
784
+ */
785
+ sealRecord(type: i32, data: u8[], off: i32, len: i32): boolean {
786
+ if (!this.outputHasRoom(this.recordRoom(len))) {
787
+ return false
788
+ }
789
+ const n: i32 = this.writeProtection.seal(
790
+ type,
791
+ data,
792
+ off,
793
+ len,
794
+ this.writePadding(),
795
+ this.output,
796
+ this.outputEnd
797
+ )
798
+ if (n < 0) {
799
+ this.fail(-n)
800
+ return false
801
+ }
802
+ this.outputEnd = this.outputEnd + n
803
+ return true
804
+ }
805
+
806
+ /**
807
+ * Seals as much of `queue[at .. length)` as fits, in records of at most
808
+ * `maxChunk()` bytes, and answers where it stopped. A padding that leaves
809
+ * no room for content fails the connection with `internal_error`.
810
+ */
811
+ sealQueue(queue: u8[], at: i32, length: i32): i32 {
812
+ let next: i32 = at
813
+ const most: i32 = this.maxChunk()
814
+ if (most < 1 && next < length) {
815
+ this.fail(TLS_ALERT_INTERNAL_ERROR)
816
+ return next
817
+ }
818
+ while (next < length && this.state !== TLS_RECORD_STATE_FAILED) {
819
+ const left: i32 = length - next
820
+ const chunk: i32 = left < most ? left : most
821
+ if (!this.sealRecord(TLS_CONTENT_HANDSHAKE, queue, next, chunk)) {
822
+ return next
823
+ }
824
+ next = next + chunk
825
+ }
826
+ return next
827
+ }
828
+
829
+ /**
830
+ * Moves what is owed onto `output` as far as it fits, in the order the
831
+ * client must read it: the Initial-level messages in the clear, the
832
+ * compatibility record, the flight under the handshake keys, and then the
833
+ * switch to the application keys, with the server's handshake and
834
+ * application secrets wiped in `TlsServer` once they are installed here. A
835
+ * KeyUpdate owed to the client goes last.
836
+ */
837
+ pump(): void {
838
+ if (this.state === TLS_RECORD_STATE_FAILED) {
839
+ return
840
+ }
841
+ // After its close_notify the server sends nothing more (§6.1).
842
+ if (this.state === TLS_RECORD_STATE_CLOSED) {
843
+ if (this.closeDue && this.sendAlert(TLS_ALERT_LEVEL_WARNING, TLS_ALERT_CLOSE_NOTIFY)) {
844
+ this.closeDue = false
845
+ }
846
+ return
847
+ }
848
+ const tls: TlsServer = this.tls
849
+ // The handshake's messages are sealed straight out of `TlsServer`'s
850
+ // buffers, which are emptied once every byte is in a record.
851
+ if (tls.outputInitialLength > 0) {
852
+ this.pendingInitialAt = this.sealQueue(
853
+ tls.outputInitial,
854
+ this.pendingInitialAt,
855
+ tls.outputInitialLength
856
+ )
857
+ if (this.pendingInitialAt < tls.outputInitialLength) {
858
+ return
859
+ }
860
+ tls.clearOutput(TLS_LEVEL_INITIAL)
861
+ this.pendingInitialAt = 0
862
+ }
863
+ if (this.ccsDue) {
864
+ const ccs: u8[] = [toU8(1)]
865
+ const one: i32 = 1
866
+ if (!this.sealRecord(TLS_CONTENT_CHANGE_CIPHER_SPEC, ccs, TLS_RECORD_SERVER_FROM, one)) {
867
+ return
868
+ }
869
+ this.ccsDue = false
870
+ }
871
+ // Everything the server sends after its ServerHello is under the
872
+ // handshake keys (§2), an alert before the flight included, so they go
873
+ // in as soon as the ServerHello is sealed. `install` refuses only a suite
874
+ // or a secret `TlsServer` never hands over; the check keeps the flight
875
+ // from ever being sealed in the clear.
876
+ const handshake: u8[] | null = tls.writeSecret(TLS_LEVEL_HANDSHAKE)
877
+ if (this.writeLevel === TLS_LEVEL_INITIAL && handshake !== null) {
878
+ if (!this.writeProtection.install(tls.suite, handshake)) {
879
+ this.fail(TLS_ALERT_INTERNAL_ERROR)
880
+ return
881
+ }
882
+ this.writeLevel = TLS_LEVEL_HANDSHAKE
883
+ }
884
+ if (this.flightReady && tls.outputHandshakeLength > 0) {
885
+ this.pendingHandshakeAt = this.sealQueue(
886
+ tls.outputHandshake,
887
+ this.pendingHandshakeAt,
888
+ tls.outputHandshakeLength
889
+ )
890
+ if (this.pendingHandshakeAt < tls.outputHandshakeLength) {
891
+ return
892
+ }
893
+ tls.clearOutput(TLS_LEVEL_HANDSHAKE)
894
+ this.pendingHandshakeAt = 0
895
+ }
896
+ if (
897
+ this.writeLevel === TLS_LEVEL_HANDSHAKE &&
898
+ (tls.state === TLS_STATE_WAIT_FINISHED || tls.state === TLS_STATE_CONNECTED)
899
+ ) {
900
+ this.writeSecret = tlsKeepSecret(
901
+ tls.writeSecret(TLS_LEVEL_APPLICATION),
902
+ this.writeSecret256,
903
+ this.writeSecret384,
904
+ this.none
905
+ )
906
+ secureZero(tls.serverApplicationSecret)
907
+ secureZero(tls.serverHandshakeSecret)
908
+ // A direction whose keys did not install would write in the clear.
909
+ if (!this.writeProtection.install(tls.suite, this.writeSecret)) {
910
+ this.fail(TLS_ALERT_INTERNAL_ERROR)
911
+ return
912
+ }
913
+ this.writeLevel = TLS_LEVEL_APPLICATION
914
+ }
915
+ if (this.keyUpdateDue && this.writeLevel === TLS_LEVEL_APPLICATION && this.sendKeyUpdate(false)) {
916
+ this.keyUpdateDue = false
917
+ }
918
+ }
919
+
920
+ /**
921
+ * Seals a KeyUpdate under the current write keys and moves the write side
922
+ * to the next secret (§4.6.3, §7.2), the old one wiped. False, sending
923
+ * nothing, when it does not fit in `output` yet.
924
+ */
925
+ sendKeyUpdate(request: boolean): boolean {
926
+ const message: u8[] = [toU8(TLS_HANDSHAKE_KEY_UPDATE), toU8(0), toU8(0), toU8(1), toU8(request ? 1 : 0)]
927
+ if (!this.sealRecord(TLS_CONTENT_HANDSHAKE, message, TLS_RECORD_SERVER_FROM, TLS_KEY_UPDATE_SIZE)) {
928
+ return false
929
+ }
930
+ if (!this.writeProtection.advance(this.writeSecret)) {
931
+ this.fail(TLS_ALERT_INTERNAL_ERROR)
932
+ return false
933
+ }
934
+ return true
935
+ }
936
+
937
+ /**
938
+ * Sends a KeyUpdate now, asking the client to update too when
939
+ * `requestPeer` (§4.6.3). Answers 0, `TLS_RECORD_AGAIN` while the handshake
940
+ * is under way or `output` is full, `TLS_RECORD_PIPE` once the server has
941
+ * closed or the connection failed, or `TLS_RECORD_RESET` when the next keys
942
+ * do not install and the connection fails on it.
943
+ */
944
+ keyUpdate(requestPeer: boolean): i32 {
945
+ if (this.state === TLS_RECORD_STATE_FAILED || this.state === TLS_RECORD_STATE_CLOSED) {
946
+ return TLS_RECORD_PIPE
947
+ }
948
+ if (this.state !== TLS_RECORD_STATE_OPEN) {
949
+ return TLS_RECORD_AGAIN
950
+ }
951
+ this.pump()
952
+ if (this.keyUpdateDue || !this.sendKeyUpdate(requestPeer)) {
953
+ return this.state === TLS_RECORD_STATE_FAILED ? TLS_RECORD_RESET : TLS_RECORD_AGAIN
954
+ }
955
+ return 0
956
+ }
957
+
958
+ /**
959
+ * Fails the connection with `alert`, sent as a fatal alert under whatever
960
+ * the server writes with now, in the clear before its first keys. What
961
+ * was still owed is dropped: the alert is the last thing the server sends.
962
+ */
963
+ fail(alert: i32): void {
964
+ if (this.state === TLS_RECORD_STATE_FAILED) {
965
+ return
966
+ }
967
+ const closed: boolean = this.state === TLS_RECORD_STATE_CLOSED
968
+ this.dropPending()
969
+ this.wipeHandshake()
970
+ // Failed first, so a seal that refuses the alert cannot come back here.
971
+ this.state = TLS_RECORD_STATE_FAILED
972
+ this.alert = alert
973
+ // A server that has sent its close_notify sends nothing after it (§6.1).
974
+ if (!closed) {
975
+ this.sendAlert(TLS_ALERT_LEVEL_FATAL, alert)
976
+ }
977
+ }
978
+
979
+ /** Seals an alert record of `level` and `description`; false, sending nothing, when `output` has no room for it. */
980
+ sendAlert(level: i32, description: i32): boolean {
981
+ const body: u8[] = [toU8(level), toU8(description)]
982
+ const two: i32 = 2
983
+ return this.sealRecord(TLS_CONTENT_ALERT, body, TLS_RECORD_SERVER_FROM, two)
984
+ }
985
+
986
+ /**
987
+ * Lets the first `n` bytes of `output` go, once the socket has taken them,
988
+ * and seals what was waiting for the room.
989
+ */
990
+ consume(n: i32): void {
991
+ const held: i32 = this.outputEnd - this.outputStart
992
+ let take: i32 = n < held ? n : held
993
+ if (take < 0) {
994
+ take = 0
995
+ }
996
+ this.outputStart = this.outputStart + take
997
+ if (this.outputStart === this.outputEnd) {
998
+ this.outputStart = 0
999
+ this.outputEnd = 0
1000
+ }
1001
+ this.pump()
1002
+ }
1003
+
1004
+ /**
1005
+ * Application data for the client, `data[off .. off + len)`: seals as much
1006
+ * as fits, in records of at most 2^14 bytes, and answers how much that
1007
+ * was, as a socket write does. A KeyUpdate goes first when the key has
1008
+ * protected `recordLimit` records, or the client asked for one.
1009
+ * `TLS_RECORD_AGAIN` while the handshake is under way or nothing fits,
1010
+ * `TLS_RECORD_PIPE` once the server has closed or the connection failed,
1011
+ * and `TLS_RECORD_INVALID` for a window outside `data`.
1012
+ */
1013
+ write(data: u8[], off: i32, len: i32): i32 {
1014
+ if (!tlsRecordWindowFits(toI32(data.length), off, len)) {
1015
+ return TLS_RECORD_INVALID
1016
+ }
1017
+ if (this.state === TLS_RECORD_STATE_FAILED || this.state === TLS_RECORD_STATE_CLOSED) {
1018
+ return TLS_RECORD_PIPE
1019
+ }
1020
+ this.pump()
1021
+ if (
1022
+ this.state !== TLS_RECORD_STATE_OPEN ||
1023
+ this.keyUpdateDue ||
1024
+ this.writeLevel !== TLS_LEVEL_APPLICATION
1025
+ ) {
1026
+ return TLS_RECORD_AGAIN
1027
+ }
1028
+ let done: i32 = 0
1029
+ while (done < len && this.state === TLS_RECORD_STATE_OPEN) {
1030
+ if (this.writeProtection.sequence >= this.writeProtection.recordLimit && !this.sendKeyUpdate(false)) {
1031
+ break
1032
+ }
1033
+ const most: i32 = this.maxChunk()
1034
+ if (most < 1) {
1035
+ this.fail(TLS_ALERT_INTERNAL_ERROR)
1036
+ break
1037
+ }
1038
+ const left: i32 = len - done
1039
+ let chunk: i32 = left < most ? left : most
1040
+ // A record shortened to the room there is, rather than none at all.
1041
+ this.outputHasRoom(this.recordRoom(chunk))
1042
+ const room: i32 = toI32(this.output.length) - this.outputEnd - this.recordRoom(TLS_RECORD_SERVER_FROM)
1043
+ if (room < chunk) {
1044
+ chunk = room
1045
+ }
1046
+ if (chunk <= 0 || !this.sealRecord(TLS_CONTENT_APPLICATION_DATA, data, off + done, chunk)) {
1047
+ break
1048
+ }
1049
+ done = done + chunk
1050
+ }
1051
+ if (done === 0 && len > 0) {
1052
+ return this.state === TLS_RECORD_STATE_FAILED ? TLS_RECORD_RESET : TLS_RECORD_AGAIN
1053
+ }
1054
+ return done
1055
+ }
1056
+
1057
+ /**
1058
+ * Application data from the client, into `buf[off .. off + len)`: the
1059
+ * count, as a socket read answers; 0 at the end of its stream (its
1060
+ * `close_notify`) or for a `len` of 0; `TLS_RECORD_AGAIN` when nothing is
1061
+ * waiting; `TLS_RECORD_RESET` once the connection has failed; and
1062
+ * `TLS_RECORD_INVALID` for a window outside `buf`. Reading makes room, so
1063
+ * records the buffer was full for are handled before it answers.
1064
+ */
1065
+ read(buf: u8[], off: i32, len: i32): i32 {
1066
+ if (!tlsRecordWindowFits(toI32(buf.length), off, len)) {
1067
+ return TLS_RECORD_INVALID
1068
+ }
1069
+ if (len === 0) {
1070
+ return 0
1071
+ }
1072
+ const avail: i32 = this.plainEnd - this.plainStart
1073
+ if (avail > 0) {
1074
+ const n: i32 = avail < len ? avail : len
1075
+ for (let k: i32 = 0; k < n; k++) {
1076
+ buf[off + k] = this.plain[this.plainStart + k]
1077
+ }
1078
+ this.plainStart = this.plainStart + n
1079
+ if (this.plainStart === this.plainEnd) {
1080
+ this.plainStart = 0
1081
+ this.plainEnd = 0
1082
+ }
1083
+ this.process()
1084
+ return n
1085
+ }
1086
+ if (this.state === TLS_RECORD_STATE_FAILED) {
1087
+ return TLS_RECORD_RESET
1088
+ }
1089
+ return this.peerClosed ? 0 : TLS_RECORD_AGAIN
1090
+ }
1091
+
1092
+ /**
1093
+ * Closes the server's side (§6.1): a `close_notify`, after which `write`
1094
+ * answers `TLS_RECORD_PIPE` and nothing more is sent. What was still owed
1095
+ * of the handshake is dropped; application data already written stays
1096
+ * ahead of the alert, which waits for room in `output` when there is none.
1097
+ * Nothing happens once the connection has failed or closed.
1098
+ */
1099
+ close(): void {
1100
+ if (this.state === TLS_RECORD_STATE_FAILED || this.state === TLS_RECORD_STATE_CLOSED) {
1101
+ return
1102
+ }
1103
+ this.dropPending()
1104
+ this.state = TLS_RECORD_STATE_CLOSED
1105
+ this.closeDue = true
1106
+ this.pump()
1107
+ }
1108
+
1109
+ /** What the CertificateVerify signs, while `interest` says `TLS_RECORD_SIGN`; `null` otherwise. */
1110
+ signatureInput(): u8[] | null {
1111
+ if (this.state !== TLS_RECORD_STATE_HANDSHAKE) {
1112
+ return null
1113
+ }
1114
+ return this.tls.signatureInput()
1115
+ }
1116
+
1117
+ /**
1118
+ * Takes the signature over `signatureInput()` (DER for ECDSA, as
1119
+ * `tlsSignEcdsaP256` answers it) and seals the rest of the flight. Answers
1120
+ * 0, or the alert the connection failed with — `internal_error` when no
1121
+ * signature is due.
1122
+ */
1123
+ sign(signature: u8[]): i32 {
1124
+ if (this.state !== TLS_RECORD_STATE_HANDSHAKE) {
1125
+ return this.state === TLS_RECORD_STATE_FAILED ? this.alert : TLS_ALERT_INTERNAL_ERROR
1126
+ }
1127
+ const alert: i32 = this.tls.sign(signature)
1128
+ if (alert !== 0) {
1129
+ this.fail(alert)
1130
+ return alert
1131
+ }
1132
+ this.advance()
1133
+ this.process()
1134
+ return this.state === TLS_RECORD_STATE_FAILED ? this.alert : 0
1135
+ }
1136
+
1137
+ /**
1138
+ * What the connection wants next, as `TLS_RECORD_*` bits: read the socket
1139
+ * (there is room, and the stream has not ended), write it (`output` holds
1140
+ * bytes), `read` (application data, or the end of the client's stream),
1141
+ * sign, or nothing more ever (`TLS_RECORD_DONE`: failed or closed, and
1142
+ * everything is sent).
1143
+ */
1144
+ interest(): i32 {
1145
+ let bits: i32 = 0
1146
+ const sending: boolean = this.outputEnd > this.outputStart || this.closeDue
1147
+ if (sending) {
1148
+ bits = bits | TLS_RECORD_WANT_WRITE
1149
+ }
1150
+ const failed: boolean = this.state === TLS_RECORD_STATE_FAILED
1151
+ if ((failed || this.state === TLS_RECORD_STATE_CLOSED) && !sending) {
1152
+ bits = bits | TLS_RECORD_DONE
1153
+ }
1154
+ // Only a live connection reads: once the server has closed or the
1155
+ // connection failed, `TLS_RECORD_DONE` follows as soon as all is sent.
1156
+ const live: boolean = this.state === TLS_RECORD_STATE_HANDSHAKE || this.state === TLS_RECORD_STATE_OPEN
1157
+ // A whole record still held means the application data buffer is full:
1158
+ // the client waits until the caller reads.
1159
+ const blocked: boolean = this.reader.next() > 0
1160
+ if (live && !this.peerClosed && !this.ended && !blocked && this.reader.space() > 0) {
1161
+ bits = bits | TLS_RECORD_WANT_READ
1162
+ }
1163
+ // The end of the client's stream is news only while the connection is
1164
+ // live; once it is done, `TLS_RECORD_DONE` says everything.
1165
+ if (this.plainEnd > this.plainStart || (this.peerClosed && live)) {
1166
+ bits = bits | TLS_RECORD_DATA
1167
+ }
1168
+ if (this.state === TLS_RECORD_STATE_HANDSHAKE && this.tls.state === TLS_STATE_WAIT_SIGNATURE) {
1169
+ bits = bits | TLS_RECORD_SIGN
1170
+ }
1171
+ return bits
1172
+ }
1173
+ }