@@ -43,83 +43,117 @@ const SSL_OP_NO_ENCRYPT_THEN_MAC = 1 << 19;
43
43
44
44
// All settings are designed to exactly match Firefox v103, since that's a good baseline
45
45
// that seems to be widely accepted and is easy to emulate from Node.js.
46
- export const getUpstreamTlsOptions = ( { strictHttpsChecks, serverName } : {
47
- strictHttpsChecks : boolean ,
48
- serverName ?: string
49
- } ) : tls . ConnectionOptions => ( {
50
- servername : serverName && ! isIP ( serverName )
51
- ? serverName
52
- : undefined , // Can't send IPs in SNI
53
- ecdhCurve : [
54
- 'X25519' ,
55
- 'prime256v1' , // N.B. Equivalent to secp256r1
56
- 'secp384r1' ,
57
- 'secp521r1' ,
58
- ...( NEW_CURVES_SUPPORTED
59
- ? [ // Only available with OpenSSL v3+:
60
- 'ffdhe2048' ,
61
- 'ffdhe3072'
62
- ] : [ ]
63
- )
64
- ] . join ( ':' ) ,
65
- sigalgs : [
66
- 'ecdsa_secp256r1_sha256' ,
67
- 'ecdsa_secp384r1_sha384' ,
68
- 'ecdsa_secp521r1_sha512' ,
69
- 'rsa_pss_rsae_sha256' ,
70
- 'rsa_pss_rsae_sha384' ,
71
- 'rsa_pss_rsae_sha512' ,
72
- 'rsa_pkcs1_sha256' ,
73
- 'rsa_pkcs1_sha384' ,
74
- 'rsa_pkcs1_sha512' ,
75
- 'ECDSA+SHA1' ,
76
- 'rsa_pkcs1_sha1'
77
- ] . join ( ':' ) ,
78
- ciphers : [
79
- 'TLS_AES_128_GCM_SHA256' ,
80
- 'TLS_CHACHA20_POLY1305_SHA256' ,
81
- 'TLS_AES_256_GCM_SHA384' ,
82
- 'ECDHE-ECDSA-AES128-GCM-SHA256' ,
83
- 'ECDHE-RSA-AES128-GCM-SHA256' ,
84
- 'ECDHE-ECDSA-CHACHA20-POLY1305' ,
85
- 'ECDHE-RSA-CHACHA20-POLY1305' ,
86
- 'ECDHE-ECDSA-AES256-GCM-SHA384' ,
87
- 'ECDHE-RSA-AES256-GCM-SHA384' ,
88
- 'ECDHE-ECDSA-AES256-SHA' ,
89
- 'ECDHE-ECDSA-AES128-SHA' ,
90
- 'ECDHE-RSA-AES128-SHA' ,
91
- 'ECDHE-RSA-AES256-SHA' ,
92
- 'AES128-GCM-SHA256' ,
93
- 'AES256-GCM-SHA384' ,
94
- 'AES128-SHA' ,
95
- 'AES256-SHA' ,
96
-
97
- // This magic cipher is the very obtuse way that OpenSSL downgrades the overall
98
- // security level to allow various legacy settings, protocols & ciphers:
99
- ...( ! strictHttpsChecks
100
- ? [ '@SECLEVEL=0' ]
101
- : [ ]
102
- )
103
- ] . join ( ':' ) ,
104
- secureOptions : strictHttpsChecks
105
- ? SSL_OP_TLSEXT_PADDING | SSL_OP_NO_ENCRYPT_THEN_MAC
106
- : SSL_OP_TLSEXT_PADDING | SSL_OP_NO_ENCRYPT_THEN_MAC | SSL_OP_LEGACY_SERVER_CONNECT ,
107
- ...( {
108
- // Valid, but not included in Node.js TLS module types:
109
- requestOSCP : true
110
- } as any ) ,
111
-
112
- // Trust intermediate certificates from the trusted CA list too. Without this, trusted CAs
113
- // are only used when they are self-signed root certificates. Seems to cause issues in Node v20
114
- // in HTTP/2 tests, so disabled below the supported v22 version.
115
- allowPartialTrustChain : semver . satisfies ( process . version , '>=22.9.0' ) ,
116
-
117
- // Allow TLSv1, if !strict:
118
- minVersion : strictHttpsChecks ? tls . DEFAULT_MIN_VERSION : 'TLSv1' ,
119
-
120
- // Skip certificate validation entirely, if not strict:
121
- rejectUnauthorized : strictHttpsChecks ,
122
- } ) ;
46
+ export function getUpstreamTlsOptions ( {
47
+ hostname,
48
+ port,
49
+
50
+ ignoreHostHttpsErrors,
51
+ clientCertificateHostMap,
52
+ trustedCAs
53
+ } : {
54
+ // The effective hostname & port we're connecting to - note that this isn't exactly
55
+ // the same as the destination (e.g. if you tunnel to an IP but set a hostname via SNI
56
+ // then this is the hostname, not the IP).
57
+ hostname : string ,
58
+ port : number ,
59
+
60
+ // The general config that's relevant to this request:
61
+ ignoreHostHttpsErrors : string [ ] | boolean ,
62
+ clientCertificateHostMap : { [ host : string ] : { pfx : Buffer , passphrase ?: string } } ,
63
+ trustedCAs : Array < string > | undefined
64
+ } ) : tls . ConnectionOptions {
65
+ const strictHttpsChecks = shouldUseStrictHttps ( hostname , port , ignoreHostHttpsErrors ) ;
66
+
67
+ const hostWithPort = `${ hostname } :${ port } ` ;
68
+ const clientCert = clientCertificateHostMap [ hostWithPort ] ||
69
+ clientCertificateHostMap [ hostname ] ||
70
+ { } ;
71
+
72
+ return {
73
+ servername : hostname && ! isIP ( hostname )
74
+ ? hostname
75
+ : undefined , // Can't send IPs in SNI
76
+
77
+ // We precisely control the various TLS parameters here to limit TLS fingerprinting issues:
78
+ ecdhCurve : [
79
+ 'X25519' ,
80
+ 'prime256v1' , // N.B. Equivalent to secp256r1
81
+ 'secp384r1' ,
82
+ 'secp521r1' ,
83
+ ...( NEW_CURVES_SUPPORTED
84
+ ? [ // Only available with OpenSSL v3+:
85
+ 'ffdhe2048' ,
86
+ 'ffdhe3072'
87
+ ] : [ ]
88
+ )
89
+ ] . join ( ':' ) ,
90
+ sigalgs : [
91
+ 'ecdsa_secp256r1_sha256' ,
92
+ 'ecdsa_secp384r1_sha384' ,
93
+ 'ecdsa_secp521r1_sha512' ,
94
+ 'rsa_pss_rsae_sha256' ,
95
+ 'rsa_pss_rsae_sha384' ,
96
+ 'rsa_pss_rsae_sha512' ,
97
+ 'rsa_pkcs1_sha256' ,
98
+ 'rsa_pkcs1_sha384' ,
99
+ 'rsa_pkcs1_sha512' ,
100
+ 'ECDSA+SHA1' ,
101
+ 'rsa_pkcs1_sha1'
102
+ ] . join ( ':' ) ,
103
+ ciphers : [
104
+ 'TLS_AES_128_GCM_SHA256' ,
105
+ 'TLS_CHACHA20_POLY1305_SHA256' ,
106
+ 'TLS_AES_256_GCM_SHA384' ,
107
+ 'ECDHE-ECDSA-AES128-GCM-SHA256' ,
108
+ 'ECDHE-RSA-AES128-GCM-SHA256' ,
109
+ 'ECDHE-ECDSA-CHACHA20-POLY1305' ,
110
+ 'ECDHE-RSA-CHACHA20-POLY1305' ,
111
+ 'ECDHE-ECDSA-AES256-GCM-SHA384' ,
112
+ 'ECDHE-RSA-AES256-GCM-SHA384' ,
113
+ 'ECDHE-ECDSA-AES256-SHA' ,
114
+ 'ECDHE-ECDSA-AES128-SHA' ,
115
+ 'ECDHE-RSA-AES128-SHA' ,
116
+ 'ECDHE-RSA-AES256-SHA' ,
117
+ 'AES128-GCM-SHA256' ,
118
+ 'AES256-GCM-SHA384' ,
119
+ 'AES128-SHA' ,
120
+ 'AES256-SHA' ,
121
+
122
+ // This magic cipher is the very obtuse way that OpenSSL downgrades the overall
123
+ // security level to allow various legacy settings, protocols & ciphers:
124
+ ...( ! strictHttpsChecks
125
+ ? [ '@SECLEVEL=0' ]
126
+ : [ ]
127
+ )
128
+ ] . join ( ':' ) ,
129
+ secureOptions : strictHttpsChecks
130
+ ? SSL_OP_TLSEXT_PADDING | SSL_OP_NO_ENCRYPT_THEN_MAC
131
+ : SSL_OP_TLSEXT_PADDING | SSL_OP_NO_ENCRYPT_THEN_MAC | SSL_OP_LEGACY_SERVER_CONNECT ,
132
+ ...( {
133
+ // Valid, but not included in Node.js TLS module types:
134
+ requestOSCP : true
135
+ } as any ) ,
136
+
137
+ // Trust intermediate certificates from the trusted CA list too. Without this, trusted CAs
138
+ // are only used when they are self-signed root certificates. Seems to cause issues in Node v20
139
+ // in HTTP/2 tests, so disabled below the supported v22 version.
140
+ allowPartialTrustChain : semver . satisfies ( process . version , '>=22.9.0' ) ,
141
+
142
+ // Allow TLSv1, if !strict:
143
+ minVersion : strictHttpsChecks ? tls . DEFAULT_MIN_VERSION : 'TLSv1' ,
144
+
145
+ // Skip certificate validation entirely, if not strict:
146
+ rejectUnauthorized : strictHttpsChecks ,
147
+
148
+ // Override the set of trusted CAs, if configured to do so:
149
+ ...( trustedCAs ? {
150
+ ca : trustedCAs
151
+ } : { } ) ,
152
+
153
+ // Use a client cert, if one matches for this hostname+port:
154
+ ...clientCert
155
+ }
156
+ }
123
157
124
158
export async function getTrustedCAs (
125
159
trustedCAs : Array < CADefinition > | undefined ,
@@ -478,7 +512,7 @@ export function getResponseContentLengthAfterModification(
478
512
479
513
// Function to check if we should skip https errors for the current hostname and port,
480
514
// based on the given config
481
- export function shouldUseStrictHttps (
515
+ function shouldUseStrictHttps (
482
516
hostname : string ,
483
517
port : number ,
484
518
ignoreHostHttpsErrors : string [ ] | boolean
0 commit comments