lemon-tls 0.7.0 → 0.9.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.
- package/README.md +253 -20
- package/index.d.ts +94 -6
- package/index.js +126 -0
- package/package.json +1 -1
- package/src/compat.js +316 -45
- package/src/crypto.js +19 -0
- package/src/dtls_session.js +62 -6
- package/src/dtls_socket.js +32 -0
- package/src/node_options.js +138 -0
- package/src/record.js +72 -5
- package/src/secure_context.js +49 -4
- package/src/session/cert_compression.js +157 -0
- package/src/session/ecdh.js +237 -10
- package/src/session/ech.js +715 -0
- package/src/session/hpke.js +414 -0
- package/src/session/message.js +39 -4
- package/src/session/signing.js +56 -3
- package/src/session/ticket.js +38 -25
- package/src/tls_session.js +2825 -195
- package/src/tls_socket.js +839 -148
- package/src/utils.js +68 -1
- package/src/wire.js +148 -9
package/index.js
CHANGED
|
@@ -21,11 +21,74 @@ import {
|
|
|
21
21
|
Server,
|
|
22
22
|
getCiphers,
|
|
23
23
|
checkServerIdentity,
|
|
24
|
+
getCACertificates,
|
|
25
|
+
setDefaultCACertificates,
|
|
24
26
|
DEFAULT_MIN_VERSION,
|
|
25
27
|
DEFAULT_MAX_VERSION,
|
|
26
28
|
DEFAULT_CIPHERS,
|
|
27
29
|
DEFAULT_ECDH_CURVE,
|
|
28
30
|
} from './src/compat.js';
|
|
31
|
+
import { parseCiphers, parseEcdhCurve, parseSigalgs, parseTlsVersion } from './src/node_options.js';
|
|
32
|
+
import { certificateObject } from './src/utils.js';
|
|
33
|
+
import { parse_cert_compression, precompress_certificate_body, supported_cert_compression } from './src/session/cert_compression.js';
|
|
34
|
+
import { build_tls_message } from './src/session/message.js';
|
|
35
|
+
import { client_session_info } from './src/session/ticket.js';
|
|
36
|
+
|
|
37
|
+
/** A saved session ('session' event's Buffer) described without its secrets:
|
|
38
|
+
* { version, servername, alpn, created, expiresAt, earlyData }, or null. */
|
|
39
|
+
function sessionInfo(blob) { return client_session_info(blob); }
|
|
40
|
+
import { SERVER_DEFAULT_GROUPS } from './src/session/ecdh.js';
|
|
41
|
+
import { default_signature_schemes } from './src/session/signing.js';
|
|
42
|
+
|
|
43
|
+
/** The signature schemes offered by default (signature_algorithms), in
|
|
44
|
+
* order, as code points: the modern ones, ML-DSA where this Node.js has it,
|
|
45
|
+
* then the legacy ones (accepted on certificates, never used in a TLS 1.3
|
|
46
|
+
* CertificateVerify). A copy. */
|
|
47
|
+
const DEFAULT_SIGNATURE_SCHEMES = Object.freeze(default_signature_schemes());
|
|
48
|
+
|
|
49
|
+
/** The key-exchange groups a server offers by default, in its preference:
|
|
50
|
+
* every post-quantum group this Node.js has (the hybrids, then ML-KEM
|
|
51
|
+
* alone), then X25519, P-256, P-384 — as code points. A copy. */
|
|
52
|
+
const DEFAULT_SERVER_GROUPS = Object.freeze(SERVER_DEFAULT_GROUPS.slice());
|
|
53
|
+
|
|
54
|
+
/** certificateCompression (RFC 8879): ['brotli', 'zlib', 'zstd'] in order,
|
|
55
|
+
* true (all this build has) or false (none) → algorithm codes; null when
|
|
56
|
+
* unset (the default). Throws on a name it does not know, so a server can
|
|
57
|
+
* check the option when it is made rather than at the first handshake. */
|
|
58
|
+
function parseCertificateCompression(value) { return parse_cert_compression(value); }
|
|
59
|
+
|
|
60
|
+
/** A server's certificate chain compressed now (RFC 8879), in the
|
|
61
|
+
* background, for each algorithm it may be sent in — `algorithms` as the
|
|
62
|
+
* certificateCompression option takes them (unset: all this build has) —
|
|
63
|
+
* so the first TLS 1.3 handshake to send it does not compress it while
|
|
64
|
+
* its client waits. `secureContext`: from createSecureContext(). Optional:
|
|
65
|
+
* without it the first handshake compresses, and caches, as before.
|
|
66
|
+
* callback() when done. */
|
|
67
|
+
function precompressCertificate(secureContext, algorithms, callback) {
|
|
68
|
+
if (typeof algorithms === 'function') { callback = algorithms; algorithms = undefined; }
|
|
69
|
+
const algs = parse_cert_compression(algorithms) || supported_cert_compression();
|
|
70
|
+
// Its chain, and those of its other key/certificate pairs (key/cert arrays).
|
|
71
|
+
const chains = secureContext ? [secureContext.certificateChain].concat((secureContext.alternates || []).map((a) => a.certificateChain)) : [];
|
|
72
|
+
let left = 1;
|
|
73
|
+
const done = () => { if (--left === 0 && callback) callback(); };
|
|
74
|
+
for (const chain of chains) {
|
|
75
|
+
if (!Array.isArray(chain) || chain.length === 0 || algs.length === 0) continue;
|
|
76
|
+
// The Certificate message's body as a TLS 1.3 server sends it: an empty
|
|
77
|
+
// request context, each entry without extensions (an OCSP response
|
|
78
|
+
// stapled to the leaf makes another body, compressed when it is sent).
|
|
79
|
+
const body = build_tls_message({ type: 'certificate', version: 0x0304, entries: chain, certificate_request_context: new Uint8Array(0) }).subarray(4);
|
|
80
|
+
left++;
|
|
81
|
+
precompress_certificate_body(body, algs, done);
|
|
82
|
+
}
|
|
83
|
+
process.nextTick(done);
|
|
84
|
+
}
|
|
85
|
+
import { generate_ech_key, prepare_ech_server } from './src/session/ech.js';
|
|
86
|
+
import { hpke_suite, setup_sender, setup_recipient, hpke_seal, hpke_open,
|
|
87
|
+
hpke_generate_key_pair, hpke_derive_key_pair } from './src/session/hpke.js';
|
|
88
|
+
import nodeTls from 'node:tls';
|
|
89
|
+
|
|
90
|
+
/** Node-compat: the shipped CA bundle, same array Node exposes. */
|
|
91
|
+
const rootCertificates = nodeTls.rootCertificates;
|
|
29
92
|
|
|
30
93
|
// DTLS
|
|
31
94
|
import DTLSSession from './src/dtls_session.js';
|
|
@@ -53,8 +116,40 @@ var crypto = {
|
|
|
53
116
|
tls12_prf,
|
|
54
117
|
tls12_exporter,
|
|
55
118
|
tls13_exporter,
|
|
119
|
+
// HPKE (RFC 9180) — what ECH encrypts with; also the base of Oblivious
|
|
120
|
+
// HTTP and MLS.
|
|
121
|
+
hpke: {
|
|
122
|
+
suite: hpke_suite,
|
|
123
|
+
setupSender: setup_sender,
|
|
124
|
+
setupRecipient: setup_recipient,
|
|
125
|
+
seal: hpke_seal,
|
|
126
|
+
open: hpke_open,
|
|
127
|
+
generateKeyPair: hpke_generate_key_pair,
|
|
128
|
+
deriveKeyPair: hpke_derive_key_pair,
|
|
129
|
+
},
|
|
56
130
|
};
|
|
57
131
|
|
|
132
|
+
/**
|
|
133
|
+
* A new Encrypted Client Hello key (RFC 9849) for a server:
|
|
134
|
+
* { config, privateKey, configList, configListBase64 }.
|
|
135
|
+
* Pass { keys: [{ config, privateKey }] } as the server's `ech` option and
|
|
136
|
+
* publish configListBase64 as `ech=` in the domain's HTTPS record.
|
|
137
|
+
*/
|
|
138
|
+
function generateEchKey(options) {
|
|
139
|
+
return generate_ech_key(options);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Check a server's `ech` option — { keys: [{ config, privateKey, retry }] }
|
|
144
|
+
* — and throw, saying what is wrong, if it would not work: a config that
|
|
145
|
+
* does not parse, a private key that is not its config's. For a server
|
|
146
|
+
* built on TLSSession directly, which would otherwise learn of it on the
|
|
147
|
+
* first connection. createServer checks by itself.
|
|
148
|
+
*/
|
|
149
|
+
function checkEchKeys(ech) {
|
|
150
|
+
prepare_ech_server(ech);
|
|
151
|
+
}
|
|
152
|
+
|
|
58
153
|
export {
|
|
59
154
|
TLSSocket,
|
|
60
155
|
TLSSession,
|
|
@@ -64,6 +159,9 @@ export {
|
|
|
64
159
|
Server,
|
|
65
160
|
getCiphers,
|
|
66
161
|
checkServerIdentity,
|
|
162
|
+
getCACertificates,
|
|
163
|
+
setDefaultCACertificates,
|
|
164
|
+
rootCertificates,
|
|
67
165
|
DEFAULT_MIN_VERSION,
|
|
68
166
|
DEFAULT_MAX_VERSION,
|
|
69
167
|
DEFAULT_CIPHERS,
|
|
@@ -71,6 +169,19 @@ export {
|
|
|
71
169
|
crypto,
|
|
72
170
|
wire,
|
|
73
171
|
record,
|
|
172
|
+
// node:tls option strings → code lists (node_options.js)
|
|
173
|
+
parseCiphers,
|
|
174
|
+
parseEcdhCurve,
|
|
175
|
+
parseSigalgs,
|
|
176
|
+
parseTlsVersion,
|
|
177
|
+
parseCertificateCompression,
|
|
178
|
+
precompressCertificate,
|
|
179
|
+
DEFAULT_SERVER_GROUPS,
|
|
180
|
+
DEFAULT_SIGNATURE_SCHEMES,
|
|
181
|
+
sessionInfo,
|
|
182
|
+
certificateObject,
|
|
183
|
+
generateEchKey,
|
|
184
|
+
checkEchKeys,
|
|
74
185
|
|
|
75
186
|
// DTLS
|
|
76
187
|
DTLSSession,
|
|
@@ -91,6 +202,9 @@ export default {
|
|
|
91
202
|
Server,
|
|
92
203
|
getCiphers,
|
|
93
204
|
checkServerIdentity,
|
|
205
|
+
getCACertificates,
|
|
206
|
+
setDefaultCACertificates,
|
|
207
|
+
rootCertificates,
|
|
94
208
|
DEFAULT_MIN_VERSION,
|
|
95
209
|
DEFAULT_MAX_VERSION,
|
|
96
210
|
DEFAULT_CIPHERS,
|
|
@@ -98,6 +212,18 @@ export default {
|
|
|
98
212
|
crypto,
|
|
99
213
|
wire,
|
|
100
214
|
record,
|
|
215
|
+
parseCiphers,
|
|
216
|
+
parseEcdhCurve,
|
|
217
|
+
parseSigalgs,
|
|
218
|
+
parseTlsVersion,
|
|
219
|
+
parseCertificateCompression,
|
|
220
|
+
precompressCertificate,
|
|
221
|
+
DEFAULT_SERVER_GROUPS,
|
|
222
|
+
DEFAULT_SIGNATURE_SCHEMES,
|
|
223
|
+
sessionInfo,
|
|
224
|
+
certificateObject,
|
|
225
|
+
generateEchKey,
|
|
226
|
+
checkEchKeys,
|
|
101
227
|
|
|
102
228
|
// DTLS
|
|
103
229
|
DTLSSession,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lemon-tls",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "TLS 1.3/1.2 DTLS 1.3/1.2 implementation for Node.js - full control over cryptographic keys, record layer, and handshake. Drop-in replacement for node:tls with advanced options impossible in OpenSSL.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|