quico 0.4.0 → 0.8.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,108 @@
1
+ // ============================================================
2
+ // The server's TLS options, as node:tls names them — read once
3
+ // ============================================================
4
+ //
5
+ // createServer takes node:tls's options and hands them to both of its TLS
6
+ // stacks: lemon-tls's TLSSocket for HTTP/1.1 and HTTP/2 (tcp_listener), and
7
+ // lemon-tls's TLSSession inside each QUIC connection (quic_server →
8
+ // quic_connection → tls_bridge). Each side reads them here, once, when it is
9
+ // created: a bad value throws from createServer, as from node:tls, and not
10
+ // from the first handshake.
11
+ //
12
+ // Several of them were accepted and dropped. tcp_listener knew requestCert,
13
+ // minVersion, maxVersion and handshakeTimeout, but createServer never passed
14
+ // them on: `createServer({ minVersion: 'TLSv1.3' })` ran TLS 1.2 all the
15
+ // same, and said nothing. ciphers, ecdhCurve and sigalgs were not read at all.
16
+ //
17
+ // requestCert, rejectUnauthorized client certificates (with `ca`) —
18
+ // rejectUnauthorized defaults to true, as
19
+ // in node:tls, and only matters with
20
+ // requestCert
21
+ // minVersion, maxVersion 'TLSv1.2' | 'TLSv1.3' (TCP; QUIC is TLS 1.3)
22
+ // handshakeTimeout ms, both
23
+ // ciphers, ecdhCurve, sigalgs OpenSSL strings (lemon-tls node_options)
24
+ // passphrase for an encrypted `key`
25
+ // sessionTimeout seconds a ticket stays good
26
+ // honorCipherOrder the cipher suite by the server's order
27
+ // (`ciphers`); default false, the
28
+ // client's — as node:tls
29
+ // certificateCompression RFC 8879: the algorithms our certificate
30
+ // may go compressed in, in order —
31
+ // ['brotli', 'zstd', 'zlib'], true (all,
32
+ // the default) or false (never)
33
+
34
+ import lemonTls from 'lemon-tls';
35
+
36
+ // RFC 8446 §4.6.1 caps a ticket's lifetime at 7 days; a value past it is
37
+ // refused, where node:tls would take it — a lifetime the client will not
38
+ // honour is a configuration mistake. 0 issues tickets that never open: no
39
+ // resumption. Unset: lemon-tls's own default (7200 s).
40
+ var MAX_TICKET_LIFETIME = 604800;
41
+ function sessionTimeout(value) {
42
+ if (value === undefined || value === null) return undefined;
43
+ if (typeof value !== 'number' || !Number.isInteger(value))
44
+ throw new TypeError('sessionTimeout must be an integer (seconds), got ' + value);
45
+ if (value < 0 || value > MAX_TICKET_LIFETIME)
46
+ throw new RangeError('sessionTimeout must be 0..' + MAX_TICKET_LIFETIME + ' seconds (RFC 8446 §4.6.1), got ' + value);
47
+ return value;
48
+ }
49
+
50
+ // The suites a QUIC connection can use: TLS 1.3's (RFC 9001 §4.2) — not
51
+ // TLS_AES_128_CCM_8_SHA256, which nothing here implements.
52
+ var TLS13_SUITES = [0x1301, 0x1302, 0x1303];
53
+
54
+ /**
55
+ * options → { requestCert, rejectUnauthorized, minVersion, maxVersion,
56
+ * handshakeTimeout, passphrase, cipherSuites, groups, sigalgs,
57
+ * sessionTimeout, certificateCompression, honorCipherOrder }
58
+ * with the lists as code points (null: the stack's default). `forQuic`:
59
+ * checked for QUIC — TLS 1.3 only, and the cipher list narrowed to its
60
+ * suites.
61
+ */
62
+ function serverTlsOptions(options, forQuic) {
63
+ options = options || {};
64
+ var minV = lemonTls.parseTlsVersion(options.minVersion, 'minVersion');
65
+ var maxV = lemonTls.parseTlsVersion(options.maxVersion, 'maxVersion');
66
+ if (minV && maxV && minV > maxV) throw new RangeError('minVersion ' + options.minVersion + ' is above maxVersion ' + options.maxVersion);
67
+ if (forQuic && maxV && maxV < 0x0304)
68
+ throw new RangeError('maxVersion ' + options.maxVersion + ' rules out HTTP/3, which is TLS 1.3 only — set http3: false, or allow TLSv1.3');
69
+ var ht = options.handshakeTimeout;
70
+ if (ht !== undefined && ht !== null && !(typeof ht === 'number' && ht > 0 && isFinite(ht)))
71
+ throw new TypeError('handshakeTimeout must be a positive number (ms), got ' + ht);
72
+ if (options.passphrase !== undefined && options.passphrase !== null && typeof options.passphrase !== 'string')
73
+ throw new TypeError('passphrase must be a string');
74
+ var suites = lemonTls.parseCiphers(options.ciphers);
75
+ if (forQuic && suites) {
76
+ suites = suites.filter(function (c) { return TLS13_SUITES.indexOf(c) >= 0; });
77
+ if (suites.length === 0) throw new Error('ciphers "' + options.ciphers + '" names no TLS 1.3 suite, and HTTP/3 needs one — set http3: false, or add one (TLS_AES_128_GCM_SHA256)');
78
+ }
79
+ return {
80
+ requestCert: !!options.requestCert,
81
+ rejectUnauthorized: options.rejectUnauthorized !== false,
82
+ minVersion: options.minVersion || undefined,
83
+ maxVersion: options.maxVersion || undefined,
84
+ handshakeTimeout: ht == null ? undefined : ht,
85
+ passphrase: options.passphrase == null ? undefined : options.passphrase,
86
+ cipherSuites: suites,
87
+ groups: lemonTls.parseEcdhCurve(options.ecdhCurve),
88
+ sigalgs: lemonTls.parseSigalgs(options.sigalgs),
89
+ sessionTimeout: sessionTimeout(options.sessionTimeout),
90
+ certificateCompression: lemonTls.parseCertificateCompression(options.certificateCompression),
91
+ honorCipherOrder: options.honorCipherOrder === true,
92
+ };
93
+ }
94
+
95
+ // The names createServer passes on to both stacks.
96
+ var TLS_OPTION_NAMES = ['requestCert', 'rejectUnauthorized', 'minVersion', 'maxVersion', 'handshakeTimeout',
97
+ 'passphrase', 'ciphers', 'ecdhCurve', 'sigalgs', 'sessionTimeout',
98
+ 'certificateCompression', 'honorCipherOrder'];
99
+ function pickTlsOptions(options) {
100
+ var out = {};
101
+ for (var i = 0; i < TLS_OPTION_NAMES.length; i++) {
102
+ var k = TLS_OPTION_NAMES[i];
103
+ if (options[k] !== undefined) out[k] = options[k];
104
+ }
105
+ return out;
106
+ }
107
+
108
+ export { serverTlsOptions, pickTlsOptions, sessionTimeout };