Skip to content

Commit 4074483

Browse files
feat: add tlsv1.3 to default cipher suites (#128)
**Requirements** - [ ] I have added test coverage for new or changed functionality - [ ] I have followed the repository's [pull request submission guidelines](../blob/main/CONTRIBUTING.md#submitting-pull-requests) - [ ] I have validated my changes against all supported platform versions **Related issues** #127 **Describe the solution you've provided** SDK client should be able to connect successfully to a server presenting TLSv1.2 and TLSv1.3 cipher suites. **Describe alternatives you've considered** Only support TLSv1.2 specifically. --------- Co-authored-by: Ryan Lamb <[email protected]>
1 parent 0b2efee commit 4074483

File tree

3 files changed

+64
-11
lines changed

3 files changed

+64
-11
lines changed

src/ldclient_config.erl

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,17 @@
135135

136136
-define(APPLICATION_DEFAULT_OPTIONS, undefined).
137137

138+
%% Enable TLS 1.3 support for erlang 23 and higher.
139+
%% TLS 1.3 support stabilized during 22, but this implementation does not work in 22.0.
140+
%% To use TLS 1.3 with OTP 22, custom TLS options can be used.
141+
-if(?OTP_RELEASE >= 23).
142+
-define(MAX_SUPPORTED_TLS_VERSION, 'tlsv1.3').
143+
-define(SUPPORTED_TLS_VERSIONS, ['tlsv1.2', 'tlsv1.3']).
144+
-else.
145+
-define(MAX_SUPPORTED_TLS_VERSION, 'tlsv1.2').
146+
-define(SUPPORTED_TLS_VERSIONS, ['tlsv1.2']).
147+
-endif.
148+
138149
%%===================================================================
139150
%% API
140151
%%===================================================================
@@ -395,13 +406,15 @@ get_all() ->
395406
{ok, Instances} = application:get_env(ldclient, instances),
396407
Instances.
397408

398-
-spec tls_base_options() -> [ssl:tls_client_option()].
399-
tls_base_options() ->
400-
DefaultCipherSuites = ssl:cipher_suites(default, 'tlsv1.2'),
401-
CipherSuites = ssl:filter_cipher_suites(DefaultCipherSuites, [
409+
-spec get_suites(TlsVersion :: ssl:protocol_version()) -> ssl:ciphers().
410+
get_suites(TlsVersion) ->
411+
DefaultCipherSuites = ssl:cipher_suites(default, TlsVersion),
412+
ssl:filter_cipher_suites(DefaultCipherSuites, [
402413
{key_exchange, fun
403414
(ecdhe_ecdsa) -> true;
404415
(ecdhe_rsa) -> true;
416+
%% TLS 1.3 ciphers will have 'any' as the key_exchange.
417+
(any) -> true;
405418
(_) -> false
406419
end
407420
},
@@ -410,11 +423,16 @@ tls_base_options() ->
410423
(_) -> true
411424
end
412425
}
413-
]),
426+
]).
414427

428+
-spec tls_base_options() -> [ssl:tls_client_option()].
429+
tls_base_options() ->
430+
CipherSuites = get_suites(?MAX_SUPPORTED_TLS_VERSION),
415431
[{verify, verify_peer},
416432
{ciphers, CipherSuites},
417433
{depth, 3},
434+
%% Only include TLS versions we know we support.
435+
{versions, ?SUPPORTED_TLS_VERSIONS},
418436
{customize_hostname_check, [
419437
{match_fun, public_key:pkix_verify_hostname_match_fun(https)}
420438
]}].

test-tls/ldclient_tls_options_SUITE.erl

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@
2020
check_secure_default_shotgun_stream_endpoint/1,
2121
check_secure_default_httpc_poll_endpoint/1,
2222
check_secure_default_httpc_events_endpoint/1,
23-
check_secure_default_shotgun_invalid/1
23+
check_secure_default_shotgun_invalid/1,
24+
check_secure_default_shotgun_stream_endpoint_federal/1,
25+
check_secure_default_httpc_poll_endpoint_federal/1,
26+
check_secure_default_httpc_events_endpoint_federal/1
2427
]).
2528

2629
%%====================================================================
@@ -38,7 +41,10 @@ all() ->
3841
check_secure_default_shotgun_stream_endpoint,
3942
check_secure_default_httpc_poll_endpoint,
4043
check_secure_default_httpc_events_endpoint,
41-
check_secure_default_shotgun_invalid
44+
check_secure_default_shotgun_invalid,
45+
check_secure_default_shotgun_stream_endpoint_federal,
46+
check_secure_default_httpc_poll_endpoint_federal,
47+
check_secure_default_httpc_events_endpoint_federal
4248
].
4349

4450
init_per_suite(Config) ->
@@ -58,7 +64,7 @@ end_per_testcase(_, _Config) ->
5864
%% Helpers
5965
%%====================================================================
6066

61-
open_stream(Uri, HttpOptions) ->
67+
open_stream(Uri, HttpOptions, SdkKeyEnv) ->
6268
GunOpts = ldclient_http_options:gun_parse_http_options(HttpOptions),
6369
Opts = #{gun_opts => GunOpts},
6470
{ok, {Scheme, Host, Port, Path, Query}} = ldclient_http:uri_parse(Uri),
@@ -84,7 +90,7 @@ open_stream(Uri, HttpOptions) ->
8490
end,
8591
Options = #{async => true, async_mode => sse, handle_event => F},
8692
Headers = #{
87-
"authorization" => os:getenv("LD_SDK_KEY"),
93+
"authorization" => os:getenv(SdkKeyEnv),
8894
<<"user-agent">> => ldclient_config:get_user_agent()
8995
},
9096
case shotgun:get(Pid, Path ++ Query, Headers, Options) of
@@ -105,7 +111,14 @@ check_secure_default_shotgun_stream_endpoint(_) ->
105111
tls_options => ldclient_config:tls_basic_options(),
106112
connect_timeout => undefined,
107113
custom_headers => undefined
108-
}).
114+
}, "LD_SDK_KEY").
115+
116+
check_secure_default_shotgun_stream_endpoint_federal(_) ->
117+
{ok, _} = open_stream("https://stream.launchdarkly.us/all", #{
118+
tls_options => ldclient_config:tls_basic_options(),
119+
connect_timeout => undefined,
120+
custom_headers => undefined
121+
}, "LD_FED_SDK_KEY").
109122

110123
check_secure_default_httpc_poll_endpoint(_) ->
111124
Options = [{ssl, ldclient_config:tls_basic_options()}],
@@ -114,6 +127,13 @@ check_secure_default_httpc_poll_endpoint(_) ->
114127
{"User-Agent", ldclient_config:get_user_agent()}
115128
]}, Options, []).
116129

130+
check_secure_default_httpc_poll_endpoint_federal(_) ->
131+
Options = [{ssl, ldclient_config:tls_basic_options()}],
132+
{ok, _} = httpc:request(get, {"https://sdk.launchdarkly.us/sdk/latest-all", [
133+
{"Authorization", os:getenv("LD_FED_SDK_KEY")},
134+
{"User-Agent", ldclient_config:get_user_agent()}
135+
]}, Options, []).
136+
117137
check_secure_default_httpc_events_endpoint(_) ->
118138
Options = [{ssl, ldclient_config:tls_basic_options()}],
119139
{ok, _} = httpc:request(post, {"https://events.launchdarkly.com/bulk", [
@@ -124,6 +144,16 @@ check_secure_default_httpc_events_endpoint(_) ->
124144
<<"[{\"endDate\":1634839284004,\"features\":{\"test-boolean-flag\":{\"counters\":[{\"count\":1,\"unknown\":false,\"value\":true,\"variation\":0,\"version\":1}],\"default\":\"default-value\"}},\"kind\":\"summary\",\"startDate\":1634839284004},{\"creationDate\":1634839284004,\"kind\":\"index\",\"user\":{\"firstName\":\"Tester\",\"key\":\"12345-track\",\"lastName\":\"Testerson\",\"privateAttrs\":[]}}]">>
125145
}, Options, []).
126146

147+
check_secure_default_httpc_events_endpoint_federal(_) ->
148+
Options = [{ssl, ldclient_config:tls_basic_options()}],
149+
{ok, _} = httpc:request(post, {"https://events.launchdarkly.us/bulk", [
150+
{"Authorization", os:getenv("LD_FED_SDK_KEY")},
151+
{"X-LaunchDarkly-Event-Schema", ldclient_config:get_event_schema()},
152+
{"User-Agent", ldclient_config:get_user_agent()}],
153+
"application/json",
154+
<<"[{\"endDate\":1634839284004,\"features\":{\"test-boolean-flag\":{\"counters\":[{\"count\":1,\"unknown\":false,\"value\":true,\"variation\":0,\"version\":1}],\"default\":\"default-value\"}},\"kind\":\"summary\",\"startDate\":1634839284004},{\"creationDate\":1634839284004,\"kind\":\"index\",\"user\":{\"firstName\":\"Tester\",\"key\":\"12345-track\",\"lastName\":\"Testerson\",\"privateAttrs\":[]}}]">>
155+
}, Options, []).
156+
127157
check_secure_default_httpc_valid(_) ->
128158
Options = [{ssl, ldclient_config:tls_basic_options()}],
129159
{ok, _} = httpc:request(get, {"https://tls-v1-2.badssl.com:1012/", []}, Options, []),
@@ -175,4 +205,4 @@ check_secure_default_shotgun_invalid(_) ->
175205
tls_options => ldclient_config:tls_basic_options(),
176206
connect_timeout => undefined,
177207
custom_headers => undefined
178-
}).
208+
}, "LD_SDK_KEY").

test/ldclient_config_SUITE.erl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ tls_basic_options(_) ->
141141
{verify, verify_peer},
142142
{ciphers, Ciphers},
143143
{depth, 3},
144+
{versions, _Versions},
144145
{customize_hostname_check, _}] = BasicOptions,
145146
true = (length(Ciphers) =/= 0);
146147
false ->
@@ -152,6 +153,7 @@ tls_basic_options(_) ->
152153
{verify, verify_peer},
153154
{ciphers, Ciphers},
154155
{depth, 3},
156+
{versions, _Versions},
155157
{customize_hostname_check, _}] = BasicOptions,
156158
true = (length(Ciphers) =/= 0);
157159
{_, _} ->
@@ -160,6 +162,7 @@ tls_basic_options(_) ->
160162
{verify, verify_peer},
161163
{ciphers, Ciphers},
162164
{depth, 3},
165+
{versions, _Versions},
163166
{customize_hostname_check, _}] = BasicOptions,
164167
true = (length(Ciphers) =/= 0)
165168
end
@@ -171,6 +174,7 @@ tls_with_ca_certfile_options(_) ->
171174
{verify, verify_peer},
172175
{ciphers, Ciphers},
173176
{depth, 3},
177+
{versions, _Versions},
174178
{customize_hostname_check, _}] = ldclient_config:tls_ca_certfile_options("imaginary/path/to/certfile.crt"),
175179
true = (length(Ciphers) =/= 0).
176180

@@ -180,6 +184,7 @@ tls_basic_linux_options(_) ->
180184
{verify, verify_peer},
181185
{ciphers, Ciphers},
182186
{depth, 3},
187+
{versions, _Versions},
183188
{customize_hostname_check, _}] = ldclient_config:tls_basic_linux_options(),
184189
true = (length(Ciphers) =/= 0).
185190

0 commit comments

Comments
 (0)