lemon-tls 0.4.0 → 0.4.1
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/package.json +1 -1
- package/src/tls_session.js +81 -25
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lemon-tls",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "TLS 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",
|
package/src/tls_session.js
CHANGED
|
@@ -504,20 +504,24 @@ function TLSSession(options){
|
|
|
504
504
|
// - ALPN (same as CH1)
|
|
505
505
|
// - custom extensions (QUIC transport params etc.)
|
|
506
506
|
// - same cipher_suites, session_id, random as CH1
|
|
507
|
+
// CH2 MUST match CH1 exactly except key_share/cookie (RFC 8446
|
|
508
|
+
// §4.1.2) — so mirror CH1's conditional composition: same sigalg
|
|
509
|
+
// source (CH1 wrote its final list back to the context), and the
|
|
510
|
+
// same tls13Only rules for the legacy extensions and psk modes.
|
|
511
|
+
let tls13Only2 = context.local_supported_versions.length > 0 &&
|
|
512
|
+
context.local_supported_versions.every(v => v === 0x0304);
|
|
507
513
|
let extensions = [
|
|
508
514
|
{ type: 'SUPPORTED_VERSIONS', value: context.local_supported_versions },
|
|
509
515
|
{ type: 'SUPPORTED_GROUPS', value: context.local_supported_groups },
|
|
510
516
|
{ type: 'KEY_SHARE', value: [{ group: requestedGroup, key_exchange: newKeyGroup.public_key }] },
|
|
511
|
-
{ type: 'SIGNATURE_ALGORITHMS', value:
|
|
512
|
-
// Must match CH1 exactly (RFC 8446 §4.1.2)
|
|
513
|
-
0x0804, 0x0805, 0x0806,
|
|
514
|
-
0x0403, 0x0503, 0x0603,
|
|
515
|
-
0x0807, 0x0808,
|
|
516
|
-
0x0401, 0x0501, 0x0601
|
|
517
|
-
] },
|
|
518
|
-
{ type: 'RENEGOTIATION_INFO', value: new Uint8Array(0) },
|
|
519
|
-
{ type: 'EXTENDED_MASTER_SECRET', value: null },
|
|
517
|
+
{ type: 'SIGNATURE_ALGORITHMS', value: context.local_supported_signature_algorithms },
|
|
520
518
|
];
|
|
519
|
+
if (!tls13Only2) {
|
|
520
|
+
extensions.push({ type: 'RENEGOTIATION_INFO', value: new Uint8Array(0) });
|
|
521
|
+
extensions.push({ type: 'EXTENDED_MASTER_SECRET', value: null });
|
|
522
|
+
} else {
|
|
523
|
+
extensions.push({ type: 'PSK_KEY_EXCHANGE_MODES', value: [1] });
|
|
524
|
+
}
|
|
521
525
|
|
|
522
526
|
// SNI (must be first)
|
|
523
527
|
if (context.local_sni) extensions.unshift({ type: 'SERVER_NAME', value: context.local_sni });
|
|
@@ -543,6 +547,11 @@ function TLSSession(options){
|
|
|
543
547
|
random: context.local_random,
|
|
544
548
|
session_id: context.local_session_id,
|
|
545
549
|
cookie: context.dtls_cookie,
|
|
550
|
+
// BUGFIX: `cipher_suites` (plural) is what wire.js's client_hello
|
|
551
|
+
// builder actually reads; the singular key was silently ignored and
|
|
552
|
+
// wire.js substituted its own hardcoded fallback list — the
|
|
553
|
+
// configured cipher suites never reached the wire. Both names passed.
|
|
554
|
+
cipher_suites: context.local_supported_cipher_suites,
|
|
546
555
|
cipher_suite: context.local_supported_cipher_suites,
|
|
547
556
|
extensions: extensions,
|
|
548
557
|
});
|
|
@@ -2690,9 +2699,22 @@ function TLSSession(options){
|
|
|
2690
2699
|
context.local_session_id=new Uint8Array(crypto.randomBytes(32));
|
|
2691
2700
|
}
|
|
2692
2701
|
|
|
2702
|
+
// TLS 1.3-only mode (QUIC and any client that offers no other version):
|
|
2703
|
+
// the ClientHello must not carry TLS 1.2 baggage. QUIC mandates TLS 1.3
|
|
2704
|
+
// (RFC 9001), and strict 1.3-only stacks reject hellos with legacy
|
|
2705
|
+
// artifacts. Detected from the configured versions, so plain TLS over
|
|
2706
|
+
// TCP (which offers 1.3+1.2) keeps the full compatibility behavior.
|
|
2707
|
+
let tls13Only = context.local_supported_versions.length > 0 &&
|
|
2708
|
+
context.local_supported_versions.every(v => v === 0x0304);
|
|
2709
|
+
|
|
2693
2710
|
// Support both TLS 1.3 and 1.2 (server picks the best)
|
|
2694
2711
|
if(context.local_supported_cipher_suites.length<=0){
|
|
2695
|
-
context.local_supported_cipher_suites=[
|
|
2712
|
+
context.local_supported_cipher_suites = tls13Only ? [
|
|
2713
|
+
// TLS 1.3 only — no ECDHE 1.2 suites in a QUIC hello
|
|
2714
|
+
0x1301, // TLS_AES_128_GCM_SHA256
|
|
2715
|
+
0x1302, // TLS_AES_256_GCM_SHA384
|
|
2716
|
+
0x1303, // TLS_CHACHA20_POLY1305_SHA256
|
|
2717
|
+
] : [
|
|
2696
2718
|
// TLS 1.3
|
|
2697
2719
|
0x1301, // TLS_AES_128_GCM_SHA256
|
|
2698
2720
|
0x1302, // TLS_AES_256_GCM_SHA384
|
|
@@ -2722,6 +2744,23 @@ function TLSSession(options){
|
|
|
2722
2744
|
private_key: private_key
|
|
2723
2745
|
};
|
|
2724
2746
|
|
|
2747
|
+
// Honor the configured signature algorithms; the hardcoded list is only
|
|
2748
|
+
// the default when none were set (previously the configured list was
|
|
2749
|
+
// ignored here — while the HRR CH2 hardcoded its own, so CH1 and CH2
|
|
2750
|
+
// could differ, violating RFC 8446 §4.1.2's exact-match requirement).
|
|
2751
|
+
let ch_sigalgs = (context.local_supported_signature_algorithms &&
|
|
2752
|
+
context.local_supported_signature_algorithms.length > 0)
|
|
2753
|
+
? context.local_supported_signature_algorithms
|
|
2754
|
+
: [
|
|
2755
|
+
// TLS 1.3 (PSS + ECDSA + EdDSA)
|
|
2756
|
+
0x0804, 0x0805, 0x0806,
|
|
2757
|
+
0x0403, 0x0503, 0x0603,
|
|
2758
|
+
0x0807, 0x0808,
|
|
2759
|
+
// TLS 1.2 (PKCS1)
|
|
2760
|
+
0x0401, 0x0501, 0x0601
|
|
2761
|
+
];
|
|
2762
|
+
context.local_supported_signature_algorithms = ch_sigalgs; // for CH2 reuse
|
|
2763
|
+
|
|
2725
2764
|
let extensions = [
|
|
2726
2765
|
{
|
|
2727
2766
|
type: 'SUPPORTED_VERSIONS',
|
|
@@ -2740,19 +2779,20 @@ function TLSSession(options){
|
|
|
2740
2779
|
},
|
|
2741
2780
|
{
|
|
2742
2781
|
type: 'SIGNATURE_ALGORITHMS',
|
|
2743
|
-
value:
|
|
2744
|
-
|
|
2745
|
-
0x0804, 0x0805, 0x0806,
|
|
2746
|
-
0x0403, 0x0503, 0x0603,
|
|
2747
|
-
0x0807, 0x0808,
|
|
2748
|
-
// TLS 1.2 (PKCS1)
|
|
2749
|
-
0x0401, 0x0501, 0x0601
|
|
2750
|
-
]
|
|
2751
|
-
},
|
|
2752
|
-
// TLS 1.2 compatibility
|
|
2753
|
-
{ type: 'RENEGOTIATION_INFO', value: new Uint8Array(0) },
|
|
2754
|
-
{ type: 'EXTENDED_MASTER_SECRET', value: null }
|
|
2782
|
+
value: ch_sigalgs
|
|
2783
|
+
}
|
|
2755
2784
|
];
|
|
2785
|
+
if (!tls13Only) {
|
|
2786
|
+
// TLS 1.2 compatibility — meaningless (and suspicious to strict
|
|
2787
|
+
// stacks) in a 1.3-only/QUIC hello
|
|
2788
|
+
extensions.push({ type: 'RENEGOTIATION_INFO', value: new Uint8Array(0) });
|
|
2789
|
+
extensions.push({ type: 'EXTENDED_MASTER_SECRET', value: null });
|
|
2790
|
+
} else {
|
|
2791
|
+
// psk_key_exchange_modes: every mainstream 1.3 client sends it, and a
|
|
2792
|
+
// server MUST NOT send NewSessionTicket to a client that omitted it
|
|
2793
|
+
// (RFC 8446 §4.2.9) — required for future 0-RTT/resumption anyway.
|
|
2794
|
+
extensions.push({ type: 'PSK_KEY_EXCHANGE_MODES', value: [1] });
|
|
2795
|
+
}
|
|
2756
2796
|
|
|
2757
2797
|
// Add SNI if servername was provided
|
|
2758
2798
|
if (context.local_sni) {
|
|
@@ -2822,6 +2862,11 @@ function TLSSession(options){
|
|
|
2822
2862
|
random: context.local_random,
|
|
2823
2863
|
session_id: context.local_session_id,
|
|
2824
2864
|
cookie: context.dtls_cookie,
|
|
2865
|
+
// BUGFIX: `cipher_suites` (plural) is what wire.js's client_hello
|
|
2866
|
+
// builder actually reads; the singular key was silently ignored and
|
|
2867
|
+
// wire.js substituted its own hardcoded fallback list — the
|
|
2868
|
+
// configured cipher suites never reached the wire. Both names passed.
|
|
2869
|
+
cipher_suites: context.local_supported_cipher_suites,
|
|
2825
2870
|
cipher_suite: context.local_supported_cipher_suites,
|
|
2826
2871
|
extensions: extensions
|
|
2827
2872
|
};
|
|
@@ -2877,6 +2922,11 @@ function TLSSession(options){
|
|
|
2877
2922
|
random: context.local_random,
|
|
2878
2923
|
session_id: sid,
|
|
2879
2924
|
cookie: context.dtls_cookie,
|
|
2925
|
+
// BUGFIX: `cipher_suites` (plural) is what wire.js's client_hello
|
|
2926
|
+
// builder actually reads; the singular key was silently ignored and
|
|
2927
|
+
// wire.js substituted its own hardcoded fallback list — the
|
|
2928
|
+
// configured cipher suites never reached the wire. Both names passed.
|
|
2929
|
+
cipher_suites: context.local_supported_cipher_suites,
|
|
2880
2930
|
cipher_suite: context.local_supported_cipher_suites,
|
|
2881
2931
|
extensions: extensions
|
|
2882
2932
|
};
|
|
@@ -2887,7 +2937,9 @@ function TLSSession(options){
|
|
|
2887
2937
|
// Skip for DTLS (DTLS clients/servers often don't implement RFC 5077 fully,
|
|
2888
2938
|
// and adding it caused interop issues with openssl s_server -dtls1_2).
|
|
2889
2939
|
let isDtls = context.local_supported_versions && context.local_supported_versions.some(v => (v & 0xFF00) === 0xFE00);
|
|
2890
|
-
if (!isDtls && context.sessionTickets) {
|
|
2940
|
+
if (!isDtls && !tls13Only && context.sessionTickets) {
|
|
2941
|
+
// RFC 5077 SessionTicket is a TLS 1.2 mechanism; 1.3 resumption uses
|
|
2942
|
+
// NewSessionTicket/PSK. Never advertise it in a 1.3-only/QUIC hello.
|
|
2891
2943
|
extensions.push({ type: 'SESSION_TICKET', value: new Uint8Array(0) });
|
|
2892
2944
|
}
|
|
2893
2945
|
|
|
@@ -2898,6 +2950,11 @@ function TLSSession(options){
|
|
|
2898
2950
|
random: context.local_random,
|
|
2899
2951
|
session_id: context.local_session_id,
|
|
2900
2952
|
cookie: context.dtls_cookie,
|
|
2953
|
+
// BUGFIX: `cipher_suites` (plural) is what wire.js's client_hello
|
|
2954
|
+
// builder actually reads; the singular key was silently ignored and
|
|
2955
|
+
// wire.js substituted its own hardcoded fallback list — the
|
|
2956
|
+
// configured cipher suites never reached the wire. Both names passed.
|
|
2957
|
+
cipher_suites: context.local_supported_cipher_suites,
|
|
2901
2958
|
cipher_suite: context.local_supported_cipher_suites,
|
|
2902
2959
|
extensions: extensions
|
|
2903
2960
|
};
|
|
@@ -3108,5 +3165,4 @@ function TLSSession(options){
|
|
|
3108
3165
|
return this;
|
|
3109
3166
|
}
|
|
3110
3167
|
|
|
3111
|
-
export default TLSSession;
|
|
3112
|
-
|
|
3168
|
+
export default TLSSession;
|