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/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.7.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",