aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl/src
diff options
context:
space:
mode:
authorIngela Anderton Andin <[email protected]>2019-05-02 11:22:39 +0200
committerIngela Anderton Andin <[email protected]>2019-05-07 09:29:21 +0200
commit28e4dd20a4e2829293b540113f7d80facc7bddc2 (patch)
tree9e27fb6dacd43a125b70bc2fa3af55aa30a4d978 /lib/ssl/src
parent627ce4fc5425688840a5db4f1085a923c6503571 (diff)
downloadotp-28e4dd20a4e2829293b540113f7d80facc7bddc2.tar.gz
otp-28e4dd20a4e2829293b540113f7d80facc7bddc2.tar.bz2
otp-28e4dd20a4e2829293b540113f7d80facc7bddc2.zip
ssl: Add cipher suite convertion functions
Diffstat (limited to 'lib/ssl/src')
-rw-r--r--lib/ssl/src/ssl.erl125
-rw-r--r--lib/ssl/src/ssl_cipher_format.erl109
2 files changed, 184 insertions, 50 deletions
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index e3bb4df1ac..fa9da25f0c 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -35,27 +35,69 @@
-include("ssl_srp.hrl").
%% Application handling
--export([start/0, start/1, stop/0, clear_pem_cache/0]).
+-export([start/0,
+ start/1,
+ stop/0,
+ clear_pem_cache/0]).
%% Socket handling
--export([connect/3, connect/2, connect/4,
- listen/2, transport_accept/1, transport_accept/2,
- handshake/1, handshake/2, handshake/3, handshake_continue/2,
- handshake_continue/3, handshake_cancel/1,
- ssl_accept/1, ssl_accept/2, ssl_accept/3,
- controlling_process/2, peername/1, peercert/1, sockname/1,
- close/1, close/2, shutdown/2, recv/2, recv/3, send/2,
- getopts/2, setopts/2, getstat/1, getstat/2
+-export([connect/3,
+ connect/2,
+ connect/4,
+ listen/2,
+ transport_accept/1,
+ transport_accept/2,
+ handshake/1,
+ handshake/2,
+ handshake/3,
+ handshake_continue/2,
+ handshake_continue/3,
+ handshake_cancel/1,
+ ssl_accept/1,
+ ssl_accept/2,
+ ssl_accept/3,
+ controlling_process/2,
+ peername/1,
+ peercert/1,
+ sockname/1,
+ close/1,
+ close/2,
+ shutdown/2,
+ recv/2,
+ recv/3,
+ send/2,
+ getopts/2,
+ setopts/2,
+ getstat/1,
+ getstat/2
]).
%% SSL/TLS protocol handling
--export([cipher_suites/0, cipher_suites/1, cipher_suites/2, filter_cipher_suites/2,
- prepend_cipher_suites/2, append_cipher_suites/2,
- eccs/0, eccs/1, versions/0, groups/0, groups/1,
- format_error/1, renegotiate/1, prf/5, negotiated_protocol/1,
- connection_information/1, connection_information/2]).
+-export([cipher_suites/0,
+ cipher_suites/1,
+ cipher_suites/2,
+ cipher_suites/3,
+ filter_cipher_suites/2,
+ prepend_cipher_suites/2,
+ append_cipher_suites/2,
+ eccs/0,
+ eccs/1,
+ versions/0,
+ groups/0,
+ groups/1,
+ format_error/1,
+ renegotiate/1,
+ prf/5,
+ negotiated_protocol/1,
+ connection_information/1,
+ connection_information/2]).
%% Misc
--export([handle_options/2, tls_version/1, new_ssl_options/3, suite_to_str/1]).
+-export([handle_options/2,
+ tls_version/1,
+ new_ssl_options/3,
+ suite_to_str/1,
+ suite_to_openssl_str/1,
+ str_to_suite/1]).
-deprecated({ssl_accept, 1, eventually}).
-deprecated({ssl_accept, 2, eventually}).
@@ -945,6 +987,29 @@ cipher_suites(Base, Version) ->
[ssl_cipher_format:suite_bin_to_map(Suite) || Suite <- supported_suites(Base, Version)].
%%--------------------------------------------------------------------
+-spec cipher_suites(Supported, Version, rfc | openssl) -> string() when
+ Supported :: default | all | anonymous,
+ Version :: protocol_version().
+
+%% Description: Returns all default and all supported cipher suites for a
+%% TLS/DTLS version
+%%--------------------------------------------------------------------
+cipher_suites(Base, Version, StringType) when Version == 'tlsv1.2';
+ Version == 'tlsv1.1';
+ Version == tlsv1;
+ Version == sslv3 ->
+ cipher_suites(Base, tls_record:protocol_version(Version), StringType);
+cipher_suites(Base, Version, StringType) when Version == 'dtlsv1.2';
+ Version == 'dtlsv1'->
+ cipher_suites(Base, dtls_record:protocol_version(Version), StringType);
+cipher_suites(Base, Version, rfc) ->
+ [ssl_cipher_format:suite_map_to_str(ssl_cipher_format:suite_bin_to_map(Suite))
+ || Suite <- supported_suites(Base, Version)];
+cipher_suites(Base, Version, openssl) ->
+ [ssl_cipher_format:suite_map_to_openssl_str(ssl_cipher_format:suite_bin_to_map(Suite))
+ || Suite <- supported_suites(Base, Version)].
+
+%%--------------------------------------------------------------------
-spec filter_cipher_suites(Suites, Filters) -> Ciphers when
Suites :: ciphers(),
Filters :: cipher_filters(),
@@ -1325,9 +1390,39 @@ tls_version({254, _} = Version) ->
suite_to_str(Cipher) ->
ssl_cipher_format:suite_map_to_str(Cipher).
+%%--------------------------------------------------------------------
+-spec suite_to_openssl_str(CipherSuite) -> string() when
+ CipherSuite :: erl_cipher_suite().
+%%
+%% Description: Return the string representation of a cipher suite.
+%%--------------------------------------------------------------------
+suite_to_openssl_str(Cipher) ->
+ ssl_cipher_format:suite_map_to_openssl_str(Cipher).
+
+%%
+%%--------------------------------------------------------------------
+-spec str_to_suite(CipherSuiteName) -> erl_cipher_suite() when
+ CipherSuiteName :: string() | {error, {not_recognized, CipherSuiteName :: string()}}.
+%%
+%% Description: Return the map representation of a cipher suite.
+%%--------------------------------------------------------------------
+str_to_suite(CipherSuiteName) ->
+ try
+ %% Note in TLS-1.3 OpenSSL conforms to RFC names
+ %% so if CipherSuiteName starts with TLS this
+ %% function will call ssl_cipher_format:suite_str_to_map
+ %% so both RFC names and legacy OpenSSL names of supported
+ %% cipher suites will be handled
+ ssl_cipher_format:suite_openssl_str_to_map(CipherSuiteName)
+ catch
+ _:_ ->
+ {error, {not_recognized, CipherSuiteName}}
+ end.
+
%%%--------------------------------------------------------------
%%% Internal functions
%%%--------------------------------------------------------------------
+
%% Possible filters out suites not supported by crypto
available_suites(default) ->
Version = tls_record:highest_protocol_version([]),
diff --git a/lib/ssl/src/ssl_cipher_format.erl b/lib/ssl/src/ssl_cipher_format.erl
index 577156a4b5..bca1022b5f 100644
--- a/lib/ssl/src/ssl_cipher_format.erl
+++ b/lib/ssl/src/ssl_cipher_format.erl
@@ -93,10 +93,16 @@ suite_str_to_map("TLS_EMPTY_RENEGOTIATION_INFO_SCSV") ->
mac => null,
prf => null};
suite_str_to_map(SuiteStr)->
- Str0 = string:trim(SuiteStr, leading, "TLS_"),
+ Str0 = string:prefix(SuiteStr, "TLS_"),
case string:split(Str0, "_WITH_") of
[Rest] ->
tls_1_3_suite_str_to_map(Rest);
+ [Prefix, Kex | Rest] when Prefix == "SPR";
+ Prefix == "PSK";
+ Prefix == "DHE";
+ Prefix == "ECDHE"
+ ->
+ pre_tls_1_3_suite_str_to_map(Prefix ++ "_" ++ Kex, Rest);
[Kex| Rest] ->
pre_tls_1_3_suite_str_to_map(Kex, Rest)
end.
@@ -108,9 +114,15 @@ suite_map_to_openssl_str(#{key_exchange := any,
suite_map_to_openssl_str(#{key_exchange := null} = Suite) ->
%% TLS_EMPTY_RENEGOTIATION_INFO_SCSV
suite_map_to_str(Suite);
+suite_map_to_openssl_str(#{key_exchange := rsa = Kex,
+ cipher := Cipher,
+ mac := Mac}) when Cipher == "des_cbc";
+ Cipher == "3des_ede_cbc" ->
+ openssl_cipher_name(Kex, string:to_upper(atom_to_list(Cipher))) ++
+ "-" ++ string:to_upper(atom_to_list(Mac));
suite_map_to_openssl_str(#{key_exchange := Kex,
- cipher := chacha20_poly1305 = Cipher,
- mac := aead}) ->
+ cipher := chacha20_poly1305 = Cipher,
+ mac := aead}) ->
openssl_suite_start(string:to_upper(atom_to_list(Kex)))
++ openssl_cipher_name(Kex, string:to_upper(atom_to_list(Cipher)));
suite_map_to_openssl_str(#{key_exchange := Kex,
@@ -130,6 +142,12 @@ suite_map_to_openssl_str(#{key_exchange := Kex,
suite_openssl_str_to_map("TLS_" ++ _ = SuiteStr) ->
suite_str_to_map(SuiteStr);
+suite_openssl_str_to_map("DES-CBC-SHA") ->
+ suite_str_to_map("TLS_RSA_WITH_DES_CBC_SHA");
+suite_openssl_str_to_map("DES-CBC3-SHA") ->
+ suite_str_to_map("TLS_RSA_WITH_3DES_EDE_CBC_SHA");
+suite_openssl_str_to_map("SRP-DSS-DES-CBC3-SHA") ->
+ suite_str_to_map("TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA");
suite_openssl_str_to_map("DHE-RSA-" ++ Rest) ->
suite_openssl_str_to_map("DHE-RSA", Rest);
suite_openssl_str_to_map("DHE-DSS-" ++ Rest) ->
@@ -164,6 +182,8 @@ suite_openssl_str_to_map("PSK-" ++ Rest) ->
suite_openssl_str_to_map("PSK", Rest);
suite_openssl_str_to_map("SRP-RSA-" ++ Rest) ->
suite_openssl_str_to_map("SRP-RSA", Rest);
+suite_openssl_str_to_map("SRP-DSS-" ++ Rest) ->
+ suite_openssl_str_to_map("SRP-DSS", Rest);
suite_openssl_str_to_map("SRP-" ++ Rest) ->
suite_openssl_str_to_map("SRP", Rest).
@@ -451,7 +471,7 @@ suite_bin_to_map(?TLS_PSK_WITH_AES_256_CBC_SHA384) ->
#{key_exchange => psk,
cipher => aes_256_cbc,
mac => sha384,
- prf => default_prf};
+ prf => sha384};
suite_bin_to_map(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256) ->
#{key_exchange => dhe_psk,
cipher => aes_128_cbc,
@@ -461,7 +481,7 @@ suite_bin_to_map(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384) ->
#{key_exchange => dhe_psk,
cipher => aes_256_cbc,
mac => sha384,
- prf => default_prf};
+ prf => sha384};
suite_bin_to_map(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256) ->
#{key_exchange => rsa_psk,
cipher => aes_128_cbc,
@@ -471,7 +491,7 @@ suite_bin_to_map(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384) ->
#{key_exchange => rsa_psk,
cipher => aes_256_cbc,
mac => sha384,
- prf => default_prf};
+ prf => sha384};
suite_bin_to_map(?TLS_PSK_WITH_NULL_SHA256) ->
#{key_exchange => psk,
cipher => null,
@@ -481,7 +501,7 @@ suite_bin_to_map(?TLS_PSK_WITH_NULL_SHA384) ->
#{key_exchange => psk,
cipher => null,
mac => sha384,
- prf => default_prf};
+ prf => sha384};
suite_bin_to_map(?TLS_DHE_PSK_WITH_NULL_SHA256) ->
#{key_exchange => dhe_psk,
cipher => null,
@@ -491,7 +511,7 @@ suite_bin_to_map(?TLS_DHE_PSK_WITH_NULL_SHA384) ->
#{key_exchange => dhe_psk,
cipher => null,
mac => sha384,
- prf => default_prf};
+ prf => sha384};
suite_bin_to_map(?TLS_RSA_PSK_WITH_NULL_SHA256) ->
#{key_exchange => rsa_psk,
cipher => null,
@@ -501,7 +521,7 @@ suite_bin_to_map(?TLS_RSA_PSK_WITH_NULL_SHA384) ->
#{key_exchange => rsa_psk,
cipher => null,
mac => sha384,
- prf => default_prf};
+ prf => sha384};
%%% ECDHE PSK Cipher Suites RFC 5489
suite_bin_to_map(?TLS_ECDHE_PSK_WITH_RC4_128_SHA) ->
#{key_exchange => ecdhe_psk,
@@ -532,7 +552,7 @@ suite_bin_to_map(?TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384) ->
#{key_exchange => ecdhe_psk,
cipher => aes_256_cbc,
mac => sha384,
- prf => default_prf};
+ prf => sha384};
suite_bin_to_map(?TLS_ECDHE_PSK_WITH_NULL_SHA256) ->
#{key_exchange => ecdhe_psk,
cipher => null,
@@ -541,7 +561,7 @@ suite_bin_to_map(?TLS_ECDHE_PSK_WITH_NULL_SHA256) ->
suite_bin_to_map(?TLS_ECDHE_PSK_WITH_NULL_SHA384) ->
#{key_exchange => ecdhe_psk,
cipher => null, mac => sha384,
- prf => default_prf};
+ prf => sha384};
%%% ECDHE_PSK with AES-GCM and AES-CCM Cipher Suites, draft-ietf-tls-ecdhe-psk-aead-05
suite_bin_to_map(?TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256) ->
#{key_exchange => ecdhe_psk,
@@ -557,12 +577,12 @@ suite_bin_to_map(?TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256) ->
#{key_exchange => ecdhe_psk,
cipher => aes_128_ccm,
mac => null,
- prf =>sha256};
+ prf => sha256};
suite_bin_to_map(?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256) ->
#{key_exchange => ecdhe_psk,
cipher => aes_128_ccm_8,
mac => null,
- prf =>sha256};
+ prf => sha256};
%%% SRP Cipher Suites RFC 5054
suite_bin_to_map(?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA) ->
#{key_exchange => srp_anon,
@@ -1704,7 +1724,7 @@ suite_map_to_bin(#{key_exchange := any,
tls_1_3_suite_str_to_map(CipherStr) ->
- {Cipher, Mac, Prf} = cipher_str_to_algs(CipherStr, ""),
+ {Cipher, Mac, Prf} = cipher_str_to_algs(any, CipherStr, ""),
#{key_exchange => any,
mac => Mac,
cipher => Cipher,
@@ -1714,37 +1734,56 @@ tls_1_3_suite_str_to_map(CipherStr) ->
pre_tls_1_3_suite_str_to_map(KexStr, Rest) ->
Kex = algo_str_to_atom(KexStr),
[CipherStr, AlgStr] = string:split(Rest, "_", trailing),
- {Cipher, Mac, Prf} = cipher_str_to_algs(CipherStr, AlgStr),
+ {Cipher, Mac, Prf} = cipher_str_to_algs(Kex, CipherStr, AlgStr),
#{key_exchange => Kex,
mac => Mac,
cipher => Cipher,
prf => Prf
}.
-cipher_str_to_algs(CipherStr, "CCM"= End) -> %% PRE TLS 1.3
+cipher_str_to_algs(_, CipherStr, "CCM"= End) -> %% PRE TLS 1.3
Cipher = algo_str_to_atom(CipherStr ++ "_" ++ End),
{Cipher, aead, sha256};
-cipher_str_to_algs(CipherStr, "8" = End) -> %% PRE TLS 1.3
+cipher_str_to_algs(_, CipherStr, "8" = End) -> %% PRE TLS 1.3
Cipher = algo_str_to_atom(CipherStr ++ "_" ++ End),
{Cipher, aead, sha256};
-cipher_str_to_algs(CipherStr, "CHACHA20_POLY1305" = End) -> %% PRE TLS 1.3
+cipher_str_to_algs(_, CipherStr, "CHACHA20_POLY1305" = End) -> %% PRE TLS 1.3
Cipher = algo_str_to_atom(CipherStr ++ "_" ++ End),
{Cipher, aead, sha256};
-cipher_str_to_algs(CipherStr0, "") -> %% TLS 1.3
+cipher_str_to_algs(_, CipherStr0, "") -> %% TLS 1.3
[CipherStr, AlgStr] = string:split(CipherStr0, "_", trailing),
Hash = algo_str_to_atom(AlgStr),
Cipher = algo_str_to_atom(CipherStr),
{Cipher, aead, Hash};
-cipher_str_to_algs(CipherStr, HashStr) -> %% PRE TLS 1.3
+cipher_str_to_algs(Kex, CipherStr, HashStr) -> %% PRE TLS 1.3
Hash = algo_str_to_atom(HashStr),
Cipher = algo_str_to_atom(CipherStr),
case is_aead_cipher(CipherStr) of
true ->
{Cipher, aead, Hash};
false ->
- {Cipher, Hash, default_prf}
+ {Cipher, Hash, default_prf(Kex, Hash)}
end.
+default_prf(_, md5) ->
+ default_prf;
+default_prf(_, sha) ->
+ default_prf;
+default_prf(ecdhe_ecdsa, sha256) ->
+ sha256;
+default_prf(ecdhe_rsa, sha256) ->
+ sha256;
+default_prf(dhe_rsa, sha256) ->
+ default_prf;
+default_prf(dhe_dss, sha256) ->
+ default_prf;
+default_prf(rsa, sha256) ->
+ default_prf;
+default_prf(rsa_psk, sha256) ->
+ default_prf;
+default_prf(_, Hash) ->
+ Hash.
+
%% PRE TLS 1.3
is_aead_cipher("CHACHA20_POLY1305") ->
true;
@@ -1762,10 +1801,13 @@ openssl_is_aead_cipher(CipherStr) ->
false
end.
+algo_str_to_atom("SRP_SHA_DSS") ->
+ srp_dss;
algo_str_to_atom(AlgoStr) ->
erlang:list_to_existing_atom(string:to_lower(AlgoStr)).
-
+openssl_cipher_name(_, "3DES_EDE_CBC" ++ _) ->
+ "DES-CBC3";
openssl_cipher_name(Kex, "AES_128_CBC" ++ _ = CipherStr) when Kex == rsa;
Kex == dhe_rsa;
Kex == ecdhe_rsa;
@@ -1828,6 +1870,10 @@ cipher_name_from_openssl("AES128-GCM") ->
"AES_128_GCM";
cipher_name_from_openssl("AES256-GCM") ->
"AES_256_GCM";
+cipher_name_from_openssl("DES-CBC") ->
+ "DES_CBC";
+cipher_name_from_openssl("DES-CBC3") ->
+ "3DES_EDE_CBC";
cipher_name_from_openssl("RC4") ->
"RC4_128";
cipher_name_from_openssl(Str) ->
@@ -1842,7 +1888,7 @@ openssl_name_concat(Str0) ->
suite_openssl_str_to_map(Kex0, Rest) ->
Kex = algo_str_to_atom(kex_name_from_openssl(Kex0)),
[CipherStr, AlgStr] = string:split(Rest, "-", trailing),
- {Cipher, Mac, Prf} = openssl_cipher_str_to_algs(CipherStr, AlgStr),
+ {Cipher, Mac, Prf} = openssl_cipher_str_to_algs(Kex, CipherStr, AlgStr),
#{key_exchange => Kex,
mac => Mac,
cipher => Cipher,
@@ -1850,31 +1896,24 @@ suite_openssl_str_to_map(Kex0, Rest) ->
}.
%% Does only need own implementation PRE TLS 1.3
-openssl_cipher_str_to_algs(CipherStr, "CCM"= End) ->
+openssl_cipher_str_to_algs(_, CipherStr, "CCM"= End) ->
Cipher = algo_str_to_atom(CipherStr ++ "_" ++ End),
{Cipher, aead, sha256};
-openssl_cipher_str_to_algs(CipherStr, "8" = End) ->
+openssl_cipher_str_to_algs(_, CipherStr, "8" = End) ->
Cipher = algo_str_to_atom(CipherStr ++ "_" ++ End),
{Cipher, aead, sha256};
-openssl_cipher_str_to_algs(CipherStr, "POLY1305" = End) ->
+openssl_cipher_str_to_algs(_, CipherStr, "POLY1305" = End) ->
Cipher = algo_str_to_atom(CipherStr ++ "_" ++ End),
{Cipher, aead, sha256};
-openssl_cipher_str_to_algs(CipherStr, HashStr) ->
+openssl_cipher_str_to_algs(Kex, CipherStr, HashStr) ->
Hash = algo_str_to_atom(HashStr),
Cipher = algo_str_to_atom(cipher_name_from_openssl(CipherStr)),
case openssl_is_aead_cipher(CipherStr) of
true ->
{Cipher, aead, Hash};
false ->
- {Cipher, Hash, openssl_prf(Hash)}
+ {Cipher, Hash, default_prf(Kex, Hash)}
end.
-openssl_prf(sha256)->
- sha256;
-openssl_prf(sha384) ->
- sha384;
-openssl_prf(_) ->
- default_prf.
-