From f4901ebdeb3556897f309348ad5571abd3cb9421 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Fri, 8 Dec 2017 15:17:41 +0100 Subject: dtls: Add DTLS handling to utility functions --- lib/ssl/doc/src/ssl.xml | 53 +++++++++++++++++++++++++---------- lib/ssl/doc/src/ssl_app.xml | 13 +++++++-- lib/ssl/src/ssl.erl | 60 +++++++++++++++++++++++++++++----------- lib/ssl/src/ssl_internal.hrl | 1 + lib/ssl/test/ssl_basic_SUITE.erl | 21 +++++++++----- 5 files changed, 108 insertions(+), 40 deletions(-) (limited to 'lib/ssl') diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index ebef8bd69a..80b639155b 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -104,7 +104,7 @@ corresponding to inet:setopts/2, inet:getopts/2, inet:peername/1, inet:sockname/1, and inet:port/1. The callback gen_tcp is treated specially and calls inet - directly.

For DTLS this feature must be considered exprimental. + directly. For DTLS this feature must be considered exprimental.

CallbackModule =

atom()

@@ -140,10 +140,16 @@ sslsocket() =

opaque()

- - protocol() = + + protocol_versions() = +

ssl_tls_protocol() | dtls_protocol()

+ + ssl_tls_protocol() =

sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2'

+ dtls_protocol() = +

'dtlsv1' | 'dtlsv1.2'

+ ciphers() =

= [ciphersuite()] | string()

According to old API.

@@ -459,10 +465,10 @@ marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_valid marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_validation/3 with the selected CA as trusted anchor and the rest of the chain.

- {versions, [protocol()]} + {versions, [protocol_versions()]}

TLS protocol versions supported by started clients and servers. This option overrides the application environment option - protocol_version. If the environment option is not set, it defaults + protocol_version and dtls_protocol_version. If the environment option is not set, it defaults to all versions, except SSL-3.0, supported by the SSL application. See also ssl(6).

@@ -835,6 +841,7 @@ fun(srp, Username :: string(), UserState :: term()) -> cipher_suites() -> cipher_suites(Type) -> ciphers() + cipher_suites(Type, protocol_version()) -> ciphers() Returns a list of supported cipher suites. Type = erlang | openssl | all @@ -846,13 +853,14 @@ fun(srp, Username :: string(), UserState :: term()) -> all available cipher suites. The cipher suites not present in cipher_suites(erlang) but included in cipher_suites(all) are not used unless explicitly configured - by the user.

+ by the user. If the version option is not specified, the highest supported + TLS version will be used to determine the supported cipher suites

eccs() -> - eccs(protocol()) -> [named_curve()] + eccs(protocol_version()) -> [named_curve()] Returns a list of supported ECCs.

Returns a list of supported ECCs. eccs() @@ -860,7 +868,7 @@ fun(srp, Username :: string(), UserState :: term()) -> supported protocols and then deduplicating the output.

- + clear_pem_cache() -> ok Clears the pem cache @@ -917,7 +925,7 @@ fun(srp, Username :: string(), UserState :: term()) -> public_key:pkix_verify_hostname/2 will be performed in addition to the usual x509-path validation checks. If the check fails the error {bad_cert, hostname_check_failed} will be propagated to the path validation fun verify_fun, where it is possible to do customized - checks by using the full possibilitis of the public_key:pkix_verify_hostname/2 API. + checks by using the full possibilities of the public_key:pkix_verify_hostname/3 API. When the option server_name_indication is provided, its value (the DNS name) will be used as ReferenceID to public_key:pkix_verify_hostname/2. @@ -1335,7 +1343,8 @@ fun(srp, Username :: string(), UserState :: term()) -> Returns version information relevant for the SSL application. - versions_info() = {app_vsn, string()} | {supported | available, [protocol()] + versions_info() = {app_vsn, string()} | {supported | available, [ssl_tls_protocol()]} | + {supported_dtls | available_dtls, [dtls_protocol()]}

Returns version information relevant for the SSL @@ -1345,19 +1354,35 @@ fun(srp, Username :: string(), UserState :: term()) -> The application version of the SSL application. supported - SSL/TLS/DTLS versions supported by default. + SSL/TLS versions supported by default. Overridden by a version option on connect/[2,3,4], listen/2, and ssl_accept/[1,2,3]. - For the negotiated SSL/TLS/DTLS version, see ssl:connection_information/1 . - + + supported_dtls + DTLS versions supported by default. + Overridden by a version option on + connect/[2,3,4], + listen/2, and ssl_accept/[1,2,3]. + For the negotiated DTLS version, see ssl:connection_information/1 + . + available - All SSL/TLS/DTLS versions supported by the SSL application. + All SSL/TLS versions supported by the SSL application. TLS 1.2 requires sufficient support from the Crypto application. + + available_dtls + All DTLS versions supported by the SSL application. + DTLS 1.2 requires sufficient support from the Crypto + application. + diff --git a/lib/ssl/doc/src/ssl_app.xml b/lib/ssl/doc/src/ssl_app.xml index e79b79a434..fb395f8ffa 100644 --- a/lib/ssl/doc/src/ssl_app.xml +++ b/lib/ssl/doc/src/ssl_app.xml @@ -35,7 +35,7 @@

- The ssl application is an implementation of the SSL/TLS protocol in Erlang. + The ssl application is an implementation of the SSL/TLS/DTLS protocol in Erlang.

Supported SSL/TLS/DTLS-versions are SSL-3.0, TLS-1.0, @@ -94,13 +94,20 @@

erl -ssl protocol_version "['tlsv1.2', 'tlsv1.1']"

- protocol_version = ssl:protocol()]]> + protocol_version = ssl:ssl_tls_protocol()]]>

Protocol supported by started clients and servers. If this option is not set, it defaults to all - protocols currently supported by the SSL application. + TLS protocols currently supported by the SSL application. This option can be overridden by the version option to ssl:connect/[2,3] and ssl:listen/2.

+ dtls_protocol_version = ssl:dtls_protocol()]]> +

Protocol supported by started clients and + servers. If this option is not set, it defaults to all + DTLS protocols currently supported by the SSL application. + This option can be overridden by the version option + to ssl:connect/[2,3] and ssl:listen/2.

+ ]]>

Maximum lifetime of the session data in seconds. Defaults to 24 hours which is the maximum recommended lifetime by RFC 5246. However diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 656ed94ea5..a298012f26 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -39,7 +39,7 @@ ]). %% SSL/TLS protocol handling --export([cipher_suites/0, cipher_suites/1, eccs/0, eccs/1, versions/0, +-export([cipher_suites/0, cipher_suites/1, cipher_suites/2, eccs/0, eccs/1, versions/0, format_error/1, renegotiate/1, prf/5, negotiated_protocol/1, connection_information/1, connection_information/2]). %% Misc @@ -383,13 +383,31 @@ cipher_suites() -> %% Description: Returns all supported cipher suites. %%-------------------------------------------------------------------- cipher_suites(erlang) -> - [ssl_cipher:erl_suite_definition(Suite) || Suite <- available_suites(default)]; - + Version = tls_record:highest_protocol_version([]), + cipher_suites(erlang, Version); cipher_suites(openssl) -> - [ssl_cipher:openssl_suite_name(Suite) || Suite <- available_suites(default)]; - + Version = tls_record:highest_protocol_version([]), + cipher_suites(openssl, Version); cipher_suites(all) -> - [ssl_cipher:erl_suite_definition(Suite) || Suite <- available_suites(all)]. + Version = tls_record:highest_protocol_version([]), + cipher_suites(all, Version). + +%%-------------------------------------------------------------------- +-spec cipher_suites(erlang | openssl | all, tls_record:tls_version() | + dtls_record:dtls_version()) -> [ssl_cipher:old_erl_cipher_suite() | string()]. +%% Description: Returns all supported cipher suites. +%%-------------------------------------------------------------------- +cipher_suites(Type, Version) when Version == 'dtlsv1'; + Version == 'dtlsv1.2' -> + cipher_suites(Type, dtls_record:protocol_version(Version)); +cipher_suites(Type, Version) when is_atom(Version) -> + cipher_suites(Type, tls_record:protocol_version(Version)); +cipher_suites(erlang, Version) -> + [ssl_cipher:erl_suite_definition(Suite) || Suite <- available_suites(default, Version)]; +cipher_suites(openssl, Version) -> + [ssl_cipher:openssl_suite_name(Suite) || Suite <- available_suites(default, Version)]; +cipher_suites(all, Version) -> + [ssl_cipher:erl_suite_definition(Suite) || Suite <- available_suites(all, Version)]. %%-------------------------------------------------------------------- -spec eccs() -> tls_v1:curves(). @@ -410,6 +428,11 @@ eccs({3,0}) -> eccs({3,_}) -> Curves = tls_v1:ecc_curves(all), eccs_filter_supported(Curves); +eccs({_,_} = DTLSVersion) -> + eccs(dtls_v1:corresponding_tls_version(DTLSVersion)); +eccs(DTLSAtomVersion) when DTLSAtomVersion == 'dtlsv1'; + DTLSAtomVersion == 'dtlsv2' -> + eccs(dtls_record:protocol_version(DTLSAtomVersion)); eccs(AtomVersion) when is_atom(AtomVersion) -> eccs(tls_record:protocol_version(AtomVersion)). @@ -542,16 +565,23 @@ sockname(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}) when is_pid(Pid) %%--------------------------------------------------------------- -spec versions() -> [{ssl_app, string()} | {supported, [tls_record:tls_atom_version()]} | - {available, [tls_record:tls_atom_version()]}]. + {supported_dtls, [dtls_record:dtls_atom_version()]} | + {available, [tls_record:tls_atom_version()]} | + {available_dtls, [dtls_record:dtls_atom_version()]}]. %% %% Description: Returns a list of relevant versions. %%-------------------------------------------------------------------- versions() -> - Vsns = tls_record:supported_protocol_versions(), - SupportedVsns = [tls_record:protocol_version(Vsn) || Vsn <- Vsns], - AvailableVsns = ?ALL_AVAILABLE_VERSIONS, - %% TODO Add DTLS versions when supported - [{ssl_app, ?VSN}, {supported, SupportedVsns}, {available, AvailableVsns}]. + TLSVsns = tls_record:supported_protocol_versions(), + DTLSVsns = dtls_record:supported_protocol_versions(), + SupportedTLSVsns = [tls_record:protocol_version(Vsn) || Vsn <- TLSVsns], + SupportedDTLSVsns = [dtls_record:protocol_version(Vsn) || Vsn <- DTLSVsns], + AvailableTLSVsns = ?ALL_AVAILABLE_VERSIONS, + AvailableDTLSVsns = ?ALL_AVAILABLE_DATAGRAM_VERSIONS, + [{ssl_app, ?VSN}, {supported, SupportedTLSVsns}, + {supported_dtls, SupportedDTLSVsns}, + {available, AvailableTLSVsns}, + {available_dtls, AvailableDTLSVsns}]. %%--------------------------------------------------------------- @@ -633,12 +663,10 @@ tls_version({254, _} = Version) -> %%%-------------------------------------------------------------------- %% Possible filters out suites not supported by crypto -available_suites(default) -> - Version = tls_record:highest_protocol_version([]), +available_suites(default, Version) -> ssl_cipher:filter_suites(ssl_cipher:suites(Version)); -available_suites(all) -> - Version = tls_record:highest_protocol_version([]), +available_suites(all, Version) -> ssl_cipher:filter_suites(ssl_cipher:all_suites(Version)). do_listen(Port, #config{transport_info = {Transport, _, _, _}} = Config, tls_connection) -> diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index 9bb1cbaeb0..bbe1374fec 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -73,6 +73,7 @@ %% sslv3 is considered insecure due to lack of padding check (Poodle attack) %% Keep as interop with legacy software but do not support as default -define(ALL_AVAILABLE_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1, sslv3]). +-define(ALL_AVAILABLE_DATAGRAM_VERSIONS, ['dtlsv1.2', dtlsv1]). -define(ALL_SUPPORTED_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1]). -define(MIN_SUPPORTED_VERSIONS, ['tlsv1.1', tlsv1]). -define(ALL_DATAGRAM_SUPPORTED_VERSIONS, ['dtlsv1.2', dtlsv1]). diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 3b4ca40058..488be15242 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -3137,18 +3137,25 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) -> %%-------------------------------------------------------------------- defaults(Config) when is_list(Config)-> - [_, - {supported, Supported}, - {available, Available}] - = ssl:versions(), - true = lists:member(sslv3, Available), - false = lists:member(sslv3, Supported), + Versions = ssl:versions(), + true = lists:member(sslv3, proplists:get_value(available, Versions)), + false = lists:member(sslv3, proplists:get_value(supported, Versions)), + true = lists:member('tlsv1', proplists:get_value(available, Versions)), + true = lists:member('tlsv1', proplists:get_value(supported, Versions)), + true = lists:member('tlsv1.1', proplists:get_value(available, Versions)), + true = lists:member('tlsv1.1', proplists:get_value(supported, Versions)), + true = lists:member('tlsv1.2', proplists:get_value(available, Versions)), + true = lists:member('tlsv1.2', proplists:get_value(supported, Versions)), false = lists:member({rsa,rc4_128,sha}, ssl:cipher_suites()), true = lists:member({rsa,rc4_128,sha}, ssl:cipher_suites(all)), false = lists:member({rsa,des_cbc,sha}, ssl:cipher_suites()), true = lists:member({rsa,des_cbc,sha}, ssl:cipher_suites(all)), false = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites()), - true = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites(all)). + true = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites(all)), + true = lists:member('dtlsv1.2', proplists:get_value(available_dtls, Versions)), + true = lists:member('dtlsv1', proplists:get_value(available_dtls, Versions)), + true = lists:member('dtlsv1.2', proplists:get_value(supported_dtls, Versions)), + true = lists:member('dtlsv1', proplists:get_value(supported_dtls, Versions)). %%-------------------------------------------------------------------- reuseaddr() -> -- cgit v1.2.3