Skip to content

Commit

Permalink
feat: add tlsv1.3 to default cipher suites (#128)
Browse files Browse the repository at this point in the history
**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]>
  • Loading branch information
cwaldren-ld and kinyoklion authored May 20, 2024
1 parent 0b2efee commit 4074483
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 11 deletions.
28 changes: 23 additions & 5 deletions src/ldclient_config.erl
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,17 @@

-define(APPLICATION_DEFAULT_OPTIONS, undefined).

%% Enable TLS 1.3 support for erlang 23 and higher.
%% TLS 1.3 support stabilized during 22, but this implementation does not work in 22.0.
%% To use TLS 1.3 with OTP 22, custom TLS options can be used.
-if(?OTP_RELEASE >= 23).
-define(MAX_SUPPORTED_TLS_VERSION, 'tlsv1.3').
-define(SUPPORTED_TLS_VERSIONS, ['tlsv1.2', 'tlsv1.3']).
-else.
-define(MAX_SUPPORTED_TLS_VERSION, 'tlsv1.2').
-define(SUPPORTED_TLS_VERSIONS, ['tlsv1.2']).
-endif.

%%===================================================================
%% API
%%===================================================================
Expand Down Expand Up @@ -395,13 +406,15 @@ get_all() ->
{ok, Instances} = application:get_env(ldclient, instances),
Instances.

-spec tls_base_options() -> [ssl:tls_client_option()].
tls_base_options() ->
DefaultCipherSuites = ssl:cipher_suites(default, 'tlsv1.2'),
CipherSuites = ssl:filter_cipher_suites(DefaultCipherSuites, [
-spec get_suites(TlsVersion :: ssl:protocol_version()) -> ssl:ciphers().
get_suites(TlsVersion) ->
DefaultCipherSuites = ssl:cipher_suites(default, TlsVersion),
ssl:filter_cipher_suites(DefaultCipherSuites, [
{key_exchange, fun
(ecdhe_ecdsa) -> true;
(ecdhe_rsa) -> true;
%% TLS 1.3 ciphers will have 'any' as the key_exchange.
(any) -> true;
(_) -> false
end
},
Expand All @@ -410,11 +423,16 @@ tls_base_options() ->
(_) -> true
end
}
]),
]).

-spec tls_base_options() -> [ssl:tls_client_option()].
tls_base_options() ->
CipherSuites = get_suites(?MAX_SUPPORTED_TLS_VERSION),
[{verify, verify_peer},
{ciphers, CipherSuites},
{depth, 3},
%% Only include TLS versions we know we support.
{versions, ?SUPPORTED_TLS_VERSIONS},
{customize_hostname_check, [
{match_fun, public_key:pkix_verify_hostname_match_fun(https)}
]}].
Expand Down
42 changes: 36 additions & 6 deletions test-tls/ldclient_tls_options_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
check_secure_default_shotgun_stream_endpoint/1,
check_secure_default_httpc_poll_endpoint/1,
check_secure_default_httpc_events_endpoint/1,
check_secure_default_shotgun_invalid/1
check_secure_default_shotgun_invalid/1,
check_secure_default_shotgun_stream_endpoint_federal/1,
check_secure_default_httpc_poll_endpoint_federal/1,
check_secure_default_httpc_events_endpoint_federal/1
]).

%%====================================================================
Expand All @@ -38,7 +41,10 @@ all() ->
check_secure_default_shotgun_stream_endpoint,
check_secure_default_httpc_poll_endpoint,
check_secure_default_httpc_events_endpoint,
check_secure_default_shotgun_invalid
check_secure_default_shotgun_invalid,
check_secure_default_shotgun_stream_endpoint_federal,
check_secure_default_httpc_poll_endpoint_federal,
check_secure_default_httpc_events_endpoint_federal
].

init_per_suite(Config) ->
Expand All @@ -58,7 +64,7 @@ end_per_testcase(_, _Config) ->
%% Helpers
%%====================================================================

open_stream(Uri, HttpOptions) ->
open_stream(Uri, HttpOptions, SdkKeyEnv) ->
GunOpts = ldclient_http_options:gun_parse_http_options(HttpOptions),
Opts = #{gun_opts => GunOpts},
{ok, {Scheme, Host, Port, Path, Query}} = ldclient_http:uri_parse(Uri),
Expand All @@ -84,7 +90,7 @@ open_stream(Uri, HttpOptions) ->
end,
Options = #{async => true, async_mode => sse, handle_event => F},
Headers = #{
"authorization" => os:getenv("LD_SDK_KEY"),
"authorization" => os:getenv(SdkKeyEnv),
<<"user-agent">> => ldclient_config:get_user_agent()
},
case shotgun:get(Pid, Path ++ Query, Headers, Options) of
Expand All @@ -105,7 +111,14 @@ check_secure_default_shotgun_stream_endpoint(_) ->
tls_options => ldclient_config:tls_basic_options(),
connect_timeout => undefined,
custom_headers => undefined
}).
}, "LD_SDK_KEY").

check_secure_default_shotgun_stream_endpoint_federal(_) ->
{ok, _} = open_stream("https://stream.launchdarkly.us/all", #{
tls_options => ldclient_config:tls_basic_options(),
connect_timeout => undefined,
custom_headers => undefined
}, "LD_FED_SDK_KEY").

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

check_secure_default_httpc_poll_endpoint_federal(_) ->
Options = [{ssl, ldclient_config:tls_basic_options()}],
{ok, _} = httpc:request(get, {"https://sdk.launchdarkly.us/sdk/latest-all", [
{"Authorization", os:getenv("LD_FED_SDK_KEY")},
{"User-Agent", ldclient_config:get_user_agent()}
]}, Options, []).

check_secure_default_httpc_events_endpoint(_) ->
Options = [{ssl, ldclient_config:tls_basic_options()}],
{ok, _} = httpc:request(post, {"https://events.launchdarkly.com/bulk", [
Expand All @@ -124,6 +144,16 @@ check_secure_default_httpc_events_endpoint(_) ->
<<"[{\"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\":[]}}]">>
}, Options, []).

check_secure_default_httpc_events_endpoint_federal(_) ->
Options = [{ssl, ldclient_config:tls_basic_options()}],
{ok, _} = httpc:request(post, {"https://events.launchdarkly.us/bulk", [
{"Authorization", os:getenv("LD_FED_SDK_KEY")},
{"X-LaunchDarkly-Event-Schema", ldclient_config:get_event_schema()},
{"User-Agent", ldclient_config:get_user_agent()}],
"application/json",
<<"[{\"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\":[]}}]">>
}, Options, []).

check_secure_default_httpc_valid(_) ->
Options = [{ssl, ldclient_config:tls_basic_options()}],
{ok, _} = httpc:request(get, {"https://tls-v1-2.badssl.com:1012/", []}, Options, []),
Expand Down Expand Up @@ -175,4 +205,4 @@ check_secure_default_shotgun_invalid(_) ->
tls_options => ldclient_config:tls_basic_options(),
connect_timeout => undefined,
custom_headers => undefined
}).
}, "LD_SDK_KEY").
5 changes: 5 additions & 0 deletions test/ldclient_config_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ tls_basic_options(_) ->
{verify, verify_peer},
{ciphers, Ciphers},
{depth, 3},
{versions, _Versions},
{customize_hostname_check, _}] = BasicOptions,
true = (length(Ciphers) =/= 0);
false ->
Expand All @@ -152,6 +153,7 @@ tls_basic_options(_) ->
{verify, verify_peer},
{ciphers, Ciphers},
{depth, 3},
{versions, _Versions},
{customize_hostname_check, _}] = BasicOptions,
true = (length(Ciphers) =/= 0);
{_, _} ->
Expand All @@ -160,6 +162,7 @@ tls_basic_options(_) ->
{verify, verify_peer},
{ciphers, Ciphers},
{depth, 3},
{versions, _Versions},
{customize_hostname_check, _}] = BasicOptions,
true = (length(Ciphers) =/= 0)
end
Expand All @@ -171,6 +174,7 @@ tls_with_ca_certfile_options(_) ->
{verify, verify_peer},
{ciphers, Ciphers},
{depth, 3},
{versions, _Versions},
{customize_hostname_check, _}] = ldclient_config:tls_ca_certfile_options("imaginary/path/to/certfile.crt"),
true = (length(Ciphers) =/= 0).

Expand All @@ -180,6 +184,7 @@ tls_basic_linux_options(_) ->
{verify, verify_peer},
{ciphers, Ciphers},
{depth, 3},
{versions, _Versions},
{customize_hostname_check, _}] = ldclient_config:tls_basic_linux_options(),
true = (length(Ciphers) =/= 0).

Expand Down

0 comments on commit 4074483

Please sign in to comment.