aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl/src')
-rw-r--r--lib/ssl/src/Makefile3
-rw-r--r--lib/ssl/src/ssl.app.src1
-rw-r--r--lib/ssl/src/ssl.erl62
-rw-r--r--lib/ssl/src/ssl_alert.erl4
-rw-r--r--lib/ssl/src/ssl_alert.hrl2
-rw-r--r--lib/ssl/src/ssl_certificate.erl22
-rw-r--r--lib/ssl/src/ssl_certificate_db.erl2
-rw-r--r--lib/ssl/src/ssl_cipher.erl740
-rw-r--r--lib/ssl/src/ssl_cipher.hrl225
-rw-r--r--lib/ssl/src/ssl_connection.erl644
-rw-r--r--lib/ssl/src/ssl_handshake.erl554
-rw-r--r--lib/ssl/src/ssl_handshake.hrl103
-rw-r--r--lib/ssl/src/ssl_internal.hrl9
-rw-r--r--lib/ssl/src/ssl_manager.erl4
-rw-r--r--lib/ssl/src/ssl_record.erl23
-rw-r--r--lib/ssl/src/ssl_srp.hrl31
-rw-r--r--lib/ssl/src/ssl_srp_primes.erl506
-rw-r--r--lib/ssl/src/ssl_ssl3.erl10
-rw-r--r--lib/ssl/src/ssl_tls1.erl171
19 files changed, 2871 insertions, 245 deletions
diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile
index e61f415c84..3b8145089e 100644
--- a/lib/ssl/src/Makefile
+++ b/lib/ssl/src/Makefile
@@ -50,6 +50,7 @@ MODULES= \
ssl_certificate\
ssl_certificate_db\
ssl_cipher \
+ ssl_srp_primes \
ssl_connection \
ssl_connection_sup \
ssl_handshake \
@@ -65,7 +66,7 @@ MODULES= \
INTERNAL_HRL_FILES = \
ssl_alert.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_internal.hrl \
- ssl_record.hrl
+ ssl_record.hrl ssl_srp.hrl
ERL_FILES= \
$(MODULES:%=%.erl) \
diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src
index 897a097f73..5c34de905e 100644
--- a/lib/ssl/src/ssl.app.src
+++ b/lib/ssl/src/ssl.app.src
@@ -20,6 +20,7 @@
ssl_connection_sup,
ssl_connection,
ssl_cipher,
+ ssl_srp_primes,
ssl_certificate_db,
ssl_certificate,
ssl_alert
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 0ba59cede2..fb64a6652f 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -65,6 +65,9 @@
{cert, Der::binary()} | {certfile, path()} | {key, Der::binary()} |
{keyfile, path()} | {password, string()} | {cacerts, [Der::binary()]} |
{cacertfile, path()} | {dh, Der::binary()} | {dhfile, path()} |
+ {user_lookup_fun, {fun(), InitialUserState::term()}} |
+ {psk_identity, string()} |
+ {srp_identity, {string(), string()}} |
{ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} |
{reuse_session, fun()} | {hibernate_after, integer()|undefined} |
{next_protocols_advertised, list(binary())} |
@@ -351,7 +354,7 @@ negotiated_next_protocol(#sslsocket{pid = Pid}) ->
ssl_connection:negotiated_next_protocol(Pid).
-spec cipher_suites() -> [erl_cipher_suite()].
--spec cipher_suites(erlang | openssl) -> [erl_cipher_suite()] | [string()].
+-spec cipher_suites(erlang | openssl | all ) -> [erl_cipher_suite()] | [string()].
%% Description: Returns all supported cipher suites.
%%--------------------------------------------------------------------
@@ -360,12 +363,19 @@ cipher_suites() ->
cipher_suites(erlang) ->
Version = ssl_record:highest_protocol_version([]),
- [suite_definition(S) || S <- ssl_cipher:suites(Version)];
+ [suite_definition(S) || S <- cipher_suites(Version, [])];
cipher_suites(openssl) ->
Version = ssl_record:highest_protocol_version([]),
- [ssl_cipher:openssl_suite_name(S) || S <- ssl_cipher:suites(Version)].
+ [ssl_cipher:openssl_suite_name(S) || S <- cipher_suites(Version, [])];
+cipher_suites(all) ->
+ Version = ssl_record:highest_protocol_version([]),
+ Supported = ssl_cipher:suites(Version)
+ ++ ssl_cipher:anonymous_suites()
+ ++ ssl_cipher:psk_suites(Version)
+ ++ ssl_cipher:srp_suites(),
+ [suite_definition(S) || S <- Supported].
%%--------------------------------------------------------------------
-spec getopts(#sslsocket{}, [gen_tcp:option_name()]) ->
{ok, [gen_tcp:option()]} | {error, reason()}.
@@ -612,8 +622,15 @@ handle_options(Opts0, _Role) ->
CertFile = handle_option(certfile, Opts, <<>>),
+ Versions = case handle_option(versions, Opts, []) of
+ [] ->
+ ssl_record:supported_protocol_versions();
+ Vsns ->
+ [ssl_record:protocol_version(Vsn) || Vsn <- Vsns]
+ end,
+
SSLOptions = #ssl_options{
- versions = handle_option(versions, Opts, []),
+ versions = Versions,
verify = validate_option(verify, Verify),
verify_fun = VerifyFun,
fail_if_no_peer_cert = FailIfNoPeerCert,
@@ -628,6 +645,9 @@ handle_options(Opts0, _Role) ->
cacertfile = handle_option(cacertfile, Opts, CaCertDefault),
dh = handle_option(dh, Opts, undefined),
dhfile = handle_option(dhfile, Opts, undefined),
+ user_lookup_fun = handle_option(user_lookup_fun, Opts, undefined),
+ psk_identity = handle_option(psk_identity, Opts, undefined),
+ srp_identity = handle_option(srp_identity, Opts, undefined),
ciphers = handle_option(ciphers, Opts, []),
%% Server side option
reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun),
@@ -647,7 +667,8 @@ handle_options(Opts0, _Role) ->
SslOptions = [versions, verify, verify_fun,
fail_if_no_peer_cert, verify_client_once,
depth, cert, certfile, key, keyfile,
- password, cacerts, cacertfile, dh, dhfile, ciphers,
+ password, cacerts, cacertfile, dh, dhfile,
+ user_lookup_fun, psk_identity, srp_identity, ciphers,
reuse_session, reuse_sessions, ssl_imp,
cb_info, renegotiate_at, secure_renegotiate, hibernate_after,
erl_dist, next_protocols_advertised,
@@ -717,6 +738,7 @@ validate_option(key, {KeyType, Value}) when is_binary(Value),
KeyType == dsa; %% Backwards compatibility
KeyType == 'RSAPrivateKey';
KeyType == 'DSAPrivateKey';
+ KeyType == 'ECPrivateKey';
KeyType == 'PrivateKeyInfo' ->
{KeyType, Value};
@@ -749,6 +771,20 @@ validate_option(dhfile, Value) when is_binary(Value) ->
Value;
validate_option(dhfile, Value) when is_list(Value), Value =/= "" ->
list_to_binary(Value);
+validate_option(psk_identity, undefined) ->
+ undefined;
+validate_option(psk_identity, Identity)
+ when is_list(Identity), Identity =/= "", length(Identity) =< 65535 ->
+ list_to_binary(Identity);
+validate_option(user_lookup_fun, undefined) ->
+ undefined;
+validate_option(user_lookup_fun, {Fun, _} = Value) when is_function(Fun, 3) ->
+ Value;
+validate_option(srp_identity, undefined) ->
+ undefined;
+validate_option(srp_identity, {Username, Password})
+ when is_list(Username), is_list(Password), Username =/= "", length(Username) =< 255 ->
+ {list_to_binary(Username), list_to_binary(Password)};
validate_option(ciphers, Value) when is_list(Value) ->
Version = ssl_record:highest_protocol_version([]),
try cipher_suites(Version, Value)
@@ -911,18 +947,22 @@ emulated_options([], Inet,Emulated) ->
{Inet, Emulated}.
cipher_suites(Version, []) ->
- ssl_cipher:suites(Version);
+ ssl_cipher:filter_suites(ssl_cipher:suites(Version));
cipher_suites(Version, [{_,_,_,_}| _] = Ciphers0) -> %% Backwards compatibility
Ciphers = [{KeyExchange, Cipher, Hash} || {KeyExchange, Cipher, Hash, _} <- Ciphers0],
- cipher_suites(Version, Ciphers);
+ ssl_cipher:filter_suites(cipher_suites(Version, Ciphers));
cipher_suites(Version, [{_,_,_}| _] = Ciphers0) ->
Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0],
- cipher_suites(Version, Ciphers);
+ ssl_cipher:filter_suites(cipher_suites(Version, Ciphers));
cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) ->
- Supported = ssl_cipher:suites(Version) ++ ssl_cipher:anonymous_suites(),
- case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported)] of
+ Supported0 = ssl_cipher:suites(Version)
+ ++ ssl_cipher:anonymous_suites()
+ ++ ssl_cipher:psk_suites(Version)
+ ++ ssl_cipher:srp_suites(),
+ Supported1 = ssl_cipher:filter_suites(Supported0),
+ case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported1)] of
[] ->
- Supported;
+ Supported1;
Ciphers ->
Ciphers
end;
diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl
index 94e95d3cd3..1810043dfb 100644
--- a/lib/ssl/src/ssl_alert.erl
+++ b/lib/ssl/src/ssl_alert.erl
@@ -112,4 +112,6 @@ description_txt(?INTERNAL_ERROR) ->
description_txt(?USER_CANCELED) ->
"user canceled";
description_txt(?NO_RENEGOTIATION) ->
- "no renegotiation".
+ "no renegotiation";
+description_txt(?UNKNOWN_PSK_IDENTITY) ->
+ "unknown psk identity".
diff --git a/lib/ssl/src/ssl_alert.hrl b/lib/ssl/src/ssl_alert.hrl
index 92548edab7..2a8a91aefa 100644
--- a/lib/ssl/src/ssl_alert.hrl
+++ b/lib/ssl/src/ssl_alert.hrl
@@ -60,6 +60,7 @@
%% internal_error(80),
%% user_canceled(90),
%% no_renegotiation(100),
+%% unknown_psk_identity(115),
%% (255)
%% } AlertDescription;
@@ -87,6 +88,7 @@
-define(INTERNAL_ERROR, 80).
-define(USER_CANCELED, 90).
-define(NO_RENEGOTIATION, 100).
+-define(UNKNOWN_PSK_IDENTITY, 115).
-define(ALERT_REC(Level,Desc), #alert{level=Level,description=Desc,where={?FILE, ?LINE}}).
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 86f5617b54..9e1c3a09bf 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -38,7 +38,7 @@
is_valid_key_usage/2,
select_extension/2,
extensions_list/1,
- signature_type/1
+ public_key_type/1
]).
%%====================================================================
@@ -167,20 +167,16 @@ extensions_list(Extensions) ->
Extensions.
%%--------------------------------------------------------------------
--spec signature_type(term()) -> rsa | dsa .
+-spec public_key_type(term()) -> rsa | dsa | ec.
%%
-%% Description:
+%% Description:
%%--------------------------------------------------------------------
-signature_type(RSA) when RSA == ?sha1WithRSAEncryption;
- RSA == ?md5WithRSAEncryption;
- RSA == ?sha224WithRSAEncryption;
- RSA == ?sha256WithRSAEncryption;
- RSA == ?sha384WithRSAEncryption;
- RSA == ?sha512WithRSAEncryption
- ->
+public_key_type(?'rsaEncryption') ->
rsa;
-signature_type(?'id-dsa-with-sha1') ->
- dsa.
+public_key_type(?'id-dsa') ->
+ dsa;
+public_key_type(?'id-ecPublicKey') ->
+ ec.
%%--------------------------------------------------------------------
%%% Internal functions
diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl
index ff36b5ee26..cdff73336e 100644
--- a/lib/ssl/src/ssl_certificate_db.erl
+++ b/lib/ssl/src/ssl_certificate_db.erl
@@ -100,7 +100,7 @@ add_trusted_certs(_Pid, {der, DerList}, [CerDb, _,_]) ->
{ok, NewRef};
add_trusted_certs(_Pid, File, [CertsDb, RefDb, PemChache] = Db) ->
- MD5 = crypto:md5(File),
+ MD5 = crypto:hash(md5, File),
case lookup_cached_pem(Db, MD5) of
[{_Content, Ref}] ->
ref_count(Ref, RefDb, 1),
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 567690a413..898b421dff 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -34,8 +34,8 @@
-export([security_parameters/3, suite_definition/1,
decipher/5, cipher/5,
- suite/1, suites/1, anonymous_suites/0,
- openssl_suite/1, openssl_suite_name/1, filter/2,
+ suite/1, suites/1, anonymous_suites/0, psk_suites/1, srp_suites/0,
+ openssl_suite/1, openssl_suite_name/1, filter/2, filter_suites/1,
hash_algorithm/1, sign_algorithm/1]).
-compile(inline).
@@ -73,25 +73,25 @@ cipher(?NULL, CipherState, <<>>, Fragment, _Version) ->
{GenStreamCipherList, CipherState};
cipher(?RC4, CipherState, Mac, Fragment, _Version) ->
State0 = case CipherState#cipher_state.state of
- undefined -> crypto:rc4_set_key(CipherState#cipher_state.key);
+ undefined -> crypto:stream_init(rc4, CipherState#cipher_state.key);
S -> S
end,
GenStreamCipherList = [Fragment, Mac],
- {State1, T} = crypto:rc4_encrypt_with_state(State0, GenStreamCipherList),
+ {State1, T} = crypto:stream_encrypt(State0, GenStreamCipherList),
{T, CipherState#cipher_state{state = State1}};
cipher(?DES, CipherState, Mac, Fragment, Version) ->
block_cipher(fun(Key, IV, T) ->
- crypto:des_cbc_encrypt(Key, IV, T)
+ crypto:block_encrypt(des_cbc, Key, IV, T)
end, block_size(des_cbc), CipherState, Mac, Fragment, Version);
cipher(?'3DES', CipherState, Mac, Fragment, Version) ->
block_cipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) ->
- crypto:des3_cbc_encrypt(K1, K2, K3, IV, T)
+ crypto:block_encrypt(des3_cbc, [K1, K2, K3], IV, T)
end, block_size(des_cbc), CipherState, Mac, Fragment, Version);
cipher(?AES, CipherState, Mac, Fragment, Version) ->
block_cipher(fun(Key, IV, T) when byte_size(Key) =:= 16 ->
- crypto:aes_cbc_128_encrypt(Key, IV, T);
+ crypto:block_encrypt(aes_cbc128, Key, IV, T);
(Key, IV, T) when byte_size(Key) =:= 32 ->
- crypto:aes_cbc_256_encrypt(Key, IV, T)
+ crypto:block_encrypt(aes_cbc256, Key, IV, T)
end, block_size(aes_128_cbc), CipherState, Mac, Fragment, Version).
build_cipher_block(BlockSz, Mac, Fragment) ->
@@ -127,10 +127,10 @@ decipher(?NULL, _HashSz, CipherState, Fragment, _) ->
{Fragment, <<>>, CipherState};
decipher(?RC4, HashSz, CipherState, Fragment, _) ->
State0 = case CipherState#cipher_state.state of
- undefined -> crypto:rc4_set_key(CipherState#cipher_state.key);
+ undefined -> crypto:stream_init(rc4, CipherState#cipher_state.key);
S -> S
end,
- try crypto:rc4_encrypt_with_state(State0, Fragment) of
+ try crypto:stream_decrypt(State0, Fragment) of
{State, Text} ->
GSC = generic_stream_cipher_from_bin(Text, HashSz),
#generic_stream_cipher{content = Content, mac = Mac} = GSC,
@@ -147,17 +147,17 @@ decipher(?RC4, HashSz, CipherState, Fragment, _) ->
decipher(?DES, HashSz, CipherState, Fragment, Version) ->
block_decipher(fun(Key, IV, T) ->
- crypto:des_cbc_decrypt(Key, IV, T)
+ crypto:block_decrypt(des_cbc, Key, IV, T)
end, CipherState, HashSz, Fragment, Version);
decipher(?'3DES', HashSz, CipherState, Fragment, Version) ->
block_decipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) ->
- crypto:des3_cbc_decrypt(K1, K2, K3, IV, T)
+ crypto:block_decrypt(des3_cbc, [K1, K2, K3], IV, T)
end, CipherState, HashSz, Fragment, Version);
decipher(?AES, HashSz, CipherState, Fragment, Version) ->
block_decipher(fun(Key, IV, T) when byte_size(Key) =:= 16 ->
- crypto:aes_cbc_128_decrypt(Key, IV, T);
+ crypto:block_decrypt(aes_cbc128, Key, IV, T);
(Key, IV, T) when byte_size(Key) =:= 32 ->
- crypto:aes_cbc_256_decrypt(Key, IV, T)
+ crypto:block_decrypt(aes_cbc256, Key, IV, T)
end, CipherState, HashSz, Fragment, Version).
block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,
@@ -212,7 +212,61 @@ anonymous_suites() ->
?TLS_DH_anon_WITH_AES_128_CBC_SHA,
?TLS_DH_anon_WITH_AES_256_CBC_SHA,
?TLS_DH_anon_WITH_AES_128_CBC_SHA256,
- ?TLS_DH_anon_WITH_AES_256_CBC_SHA256].
+ ?TLS_DH_anon_WITH_AES_256_CBC_SHA256,
+ ?TLS_ECDH_anon_WITH_RC4_128_SHA,
+ ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_anon_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA].
+
+%%--------------------------------------------------------------------
+-spec psk_suites(tls_version() | integer()) -> [cipher_suite()].
+%%
+%% Description: Returns a list of the PSK cipher suites, only supported
+%% if explicitly set by user.
+%%--------------------------------------------------------------------
+psk_suites({3, N}) ->
+ psk_suites(N);
+
+psk_suites(N)
+ when N >= 3 ->
+ psk_suites(0) ++
+ [?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
+ ?TLS_PSK_WITH_AES_256_CBC_SHA384,
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
+ ?TLS_PSK_WITH_AES_128_CBC_SHA256];
+
+psk_suites(_) ->
+ [?TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
+ ?TLS_PSK_WITH_AES_256_CBC_SHA,
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
+ ?TLS_PSK_WITH_AES_128_CBC_SHA,
+ ?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_PSK_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DHE_PSK_WITH_RC4_128_SHA,
+ ?TLS_RSA_PSK_WITH_RC4_128_SHA,
+ ?TLS_PSK_WITH_RC4_128_SHA].
+
+%%--------------------------------------------------------------------
+-spec srp_suites() -> [cipher_suite()].
+%%
+%% Description: Returns a list of the SRP cipher suites, only supported
+%% if explicitly set by user.
+%%--------------------------------------------------------------------
+srp_suites() ->
+ [?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_WITH_AES_256_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA].
%%--------------------------------------------------------------------
-spec suite_definition(cipher_suite()) -> int_cipher_suite().
@@ -224,6 +278,11 @@ anonymous_suites() ->
%% TLS v1.1 suites
suite_definition(?TLS_NULL_WITH_NULL_NULL) ->
{null, null, null, null};
+%% RFC 5746 - Not a real cipher suite used to signal empty "renegotiation_info" extension
+%% to avoid handshake failure from old servers that do not ignore
+%% hello extension data as they should.
+suite_definition(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV) ->
+ {null, null, null, null};
%% suite_definition(?TLS_RSA_WITH_NULL_MD5) ->
%% {rsa, null, md5, default_prf};
%% suite_definition(?TLS_RSA_WITH_NULL_SHA) ->
@@ -297,7 +356,157 @@ suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA) ->
suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA256) ->
{dh_anon, aes_128_cbc, sha256, default_prf};
suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA256) ->
- {dh_anon, aes_256_cbc, sha256, default_prf}.
+ {dh_anon, aes_256_cbc, sha256, default_prf};
+
+%%% PSK Cipher Suites RFC 4279
+
+suite_definition(?TLS_PSK_WITH_RC4_128_SHA) ->
+ {psk, rc4_128, sha, default_prf};
+suite_definition(?TLS_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ {psk, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_PSK_WITH_AES_128_CBC_SHA) ->
+ {psk, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_PSK_WITH_AES_256_CBC_SHA) ->
+ {psk, aes_256_cbc, sha, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_RC4_128_SHA) ->
+ {dhe_psk, rc4_128, sha, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ {dhe_psk, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA) ->
+ {dhe_psk, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA) ->
+ {dhe_psk, aes_256_cbc, sha, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_RC4_128_SHA) ->
+ {rsa_psk, rc4_128, sha, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ {rsa_psk, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA) ->
+ {rsa_psk, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA) ->
+ {rsa_psk, aes_256_cbc, sha, default_prf};
+
+%%% TLS 1.2 PSK Cipher Suites RFC 5487
+
+suite_definition(?TLS_PSK_WITH_AES_128_CBC_SHA256) ->
+ {psk, aes_128_cbc, sha256, default_prf};
+suite_definition(?TLS_PSK_WITH_AES_256_CBC_SHA384) ->
+ {psk, aes_256_cbc, sha384, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256) ->
+ {dhe_psk, aes_128_cbc, sha256, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384) ->
+ {dhe_psk, aes_256_cbc, sha384, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256) ->
+ {rsa_psk, aes_128_cbc, sha256, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384) ->
+ {rsa_psk, aes_256_cbc, sha384, default_prf};
+
+suite_definition(?TLS_PSK_WITH_NULL_SHA256) ->
+ {psk, null, sha256, default_prf};
+suite_definition(?TLS_PSK_WITH_NULL_SHA384) ->
+ {psk, null, sha384, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA256) ->
+ {dhe_psk, null, sha256, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA384) ->
+ {dhe_psk, null, sha384, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA256) ->
+ {rsa_psk, null, sha256, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA384) ->
+ {rsa_psk, null, sha384, default_prf};
+
+%%% SRP Cipher Suites RFC 5054
+
+suite_definition(?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA) ->
+ {srp_anon, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ {srp_rsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) ->
+ {srp_dss, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_SRP_SHA_WITH_AES_128_CBC_SHA) ->
+ {srp_anon, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) ->
+ {srp_rsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) ->
+ {srp_dss, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_SRP_SHA_WITH_AES_256_CBC_SHA) ->
+ {srp_anon, aes_256_cbc, sha, default_prf};
+suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
+ {srp_rsa, aes_256_cbc, sha, default_prf};
+suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
+ {srp_dss, aes_256_cbc, sha, default_prf};
+
+%% RFC 4492 EC TLS suites
+suite_definition(?TLS_ECDH_ECDSA_WITH_NULL_SHA) ->
+ {ecdh_ecdsa, null, sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) ->
+ {ecdh_ecdsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdh_ecdsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) ->
+ {ecdh_ecdsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) ->
+ {ecdh_ecdsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDHE_ECDSA_WITH_NULL_SHA) ->
+ {ecdhe_ecdsa, null, sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) ->
+ {ecdhe_ecdsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdhe_ecdsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) ->
+ {ecdhe_ecdsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) ->
+ {ecdhe_ecdsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDH_RSA_WITH_NULL_SHA) ->
+ {ecdh_rsa, null, sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_RC4_128_SHA) ->
+ {ecdh_rsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdh_rsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) ->
+ {ecdh_rsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) ->
+ {ecdh_rsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDHE_RSA_WITH_NULL_SHA) ->
+ {ecdhe_rsa, null, sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) ->
+ {ecdhe_rsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdhe_rsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) ->
+ {ecdhe_rsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) ->
+ {ecdhe_rsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDH_anon_WITH_NULL_SHA) ->
+ {ecdh_anon, null, sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_RC4_128_SHA) ->
+ {ecdh_anon, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdh_anon, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_AES_128_CBC_SHA) ->
+ {ecdh_anon, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_AES_256_CBC_SHA) ->
+ {ecdh_anon, aes_256_cbc, sha, default_prf};
+
+%% RFC 5289 EC TLS suites
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdhe_ecdsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdhe_ecdsa, aes_256_cbc, sha384, sha384};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdh_ecdsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdh_ecdsa, aes_256_cbc, sha384, sha384};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdhe_rsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdhe_rsa, aes_256_cbc, sha384, sha384};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdh_rsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdh_rsa, aes_256_cbc, sha384, sha384}.
%%--------------------------------------------------------------------
-spec suite(erl_cipher_suite()) -> cipher_suite().
@@ -370,7 +579,157 @@ suite({dhe_rsa, aes_256_cbc, sha256}) ->
suite({dh_anon, aes_128_cbc, sha256}) ->
?TLS_DH_anon_WITH_AES_128_CBC_SHA256;
suite({dh_anon, aes_256_cbc, sha256}) ->
- ?TLS_DH_anon_WITH_AES_256_CBC_SHA256.
+ ?TLS_DH_anon_WITH_AES_256_CBC_SHA256;
+
+%%% PSK Cipher Suites RFC 4279
+
+suite({psk, rc4_128,sha}) ->
+ ?TLS_PSK_WITH_RC4_128_SHA;
+suite({psk, '3des_ede_cbc',sha}) ->
+ ?TLS_PSK_WITH_3DES_EDE_CBC_SHA;
+suite({psk, aes_128_cbc,sha}) ->
+ ?TLS_PSK_WITH_AES_128_CBC_SHA;
+suite({psk, aes_256_cbc,sha}) ->
+ ?TLS_PSK_WITH_AES_256_CBC_SHA;
+suite({dhe_psk, rc4_128,sha}) ->
+ ?TLS_DHE_PSK_WITH_RC4_128_SHA;
+suite({dhe_psk, '3des_ede_cbc',sha}) ->
+ ?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA;
+suite({dhe_psk, aes_128_cbc,sha}) ->
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA;
+suite({dhe_psk, aes_256_cbc,sha}) ->
+ ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA;
+suite({rsa_psk, rc4_128,sha}) ->
+ ?TLS_RSA_PSK_WITH_RC4_128_SHA;
+suite({rsa_psk, '3des_ede_cbc',sha}) ->
+ ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA;
+suite({rsa_psk, aes_128_cbc,sha}) ->
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA;
+suite({rsa_psk, aes_256_cbc,sha}) ->
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA;
+
+%%% TLS 1.2 PSK Cipher Suites RFC 5487
+
+suite({psk, aes_128_cbc, sha256}) ->
+ ?TLS_PSK_WITH_AES_128_CBC_SHA256;
+suite({psk, aes_256_cbc, sha384}) ->
+ ?TLS_PSK_WITH_AES_256_CBC_SHA384;
+suite({dhe_psk, aes_128_cbc, sha256}) ->
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256;
+suite({dhe_psk, aes_256_cbc, sha384}) ->
+ ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384;
+suite({rsa_psk, aes_128_cbc, sha256}) ->
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256;
+suite({rsa_psk, aes_256_cbc, sha384}) ->
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384;
+
+suite({psk, null, sha256}) ->
+ ?TLS_PSK_WITH_NULL_SHA256;
+suite({psk, null, sha384}) ->
+ ?TLS_PSK_WITH_NULL_SHA384;
+suite({dhe_psk, null, sha256}) ->
+ ?TLS_DHE_PSK_WITH_NULL_SHA256;
+suite({dhe_psk, null, sha384}) ->
+ ?TLS_DHE_PSK_WITH_NULL_SHA384;
+suite({rsa_psk, null, sha256}) ->
+ ?TLS_RSA_PSK_WITH_NULL_SHA256;
+suite({rsa_psk, null, sha384}) ->
+ ?TLS_RSA_PSK_WITH_NULL_SHA384;
+
+%%% SRP Cipher Suites RFC 5054
+
+suite({srp_anon, '3des_ede_cbc', sha}) ->
+ ?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA;
+suite({srp_rsa, '3des_ede_cbc', sha}) ->
+ ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA;
+suite({srp_dss, '3des_ede_cbc', sha}) ->
+ ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA;
+suite({srp_anon, aes_128_cbc, sha}) ->
+ ?TLS_SRP_SHA_WITH_AES_128_CBC_SHA;
+suite({srp_rsa, aes_128_cbc, sha}) ->
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
+suite({srp_dss, aes_128_cbc, sha}) ->
+ ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
+suite({srp_anon, aes_256_cbc, sha}) ->
+ ?TLS_SRP_SHA_WITH_AES_256_CBC_SHA;
+suite({srp_rsa, aes_256_cbc, sha}) ->
+ ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
+suite({srp_dss, aes_256_cbc, sha}) ->
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
+
+%%% RFC 4492 EC TLS suites
+suite({ecdh_ecdsa, null, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_NULL_SHA;
+suite({ecdh_ecdsa, rc4_128, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
+suite({ecdh_ecdsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdh_ecdsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
+suite({ecdh_ecdsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdhe_ecdsa, null, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_NULL_SHA;
+suite({ecdhe_ecdsa, rc4_128, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
+suite({ecdhe_ecdsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdhe_ecdsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
+suite({ecdhe_ecdsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdh_rsa, null, sha}) ->
+ ?TLS_ECDH_RSA_WITH_NULL_SHA;
+suite({ecdh_rsa, rc4_128, sha}) ->
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA;
+suite({ecdh_rsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdh_rsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
+suite({ecdh_rsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdhe_rsa, null, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_NULL_SHA;
+suite({ecdhe_rsa, rc4_128, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA;
+suite({ecdhe_rsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdhe_rsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
+suite({ecdhe_rsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdh_anon, null, sha}) ->
+ ?TLS_ECDH_anon_WITH_NULL_SHA;
+suite({ecdh_anon, rc4_128, sha}) ->
+ ?TLS_ECDH_anon_WITH_RC4_128_SHA;
+suite({ecdh_anon, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA;
+suite({ecdh_anon, aes_128_cbc, sha}) ->
+ ?TLS_ECDH_anon_WITH_AES_128_CBC_SHA;
+suite({ecdh_anon, aes_256_cbc, sha}) ->
+ ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA;
+
+%%% RFC 5289 EC TLS suites
+suite({ecdhe_ecdsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
+suite({ecdhe_ecdsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
+suite({ecdh_ecdsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
+suite({ecdh_ecdsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
+suite({ecdhe_rsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
+suite({ecdhe_rsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
+suite({ecdh_rsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
+suite({ecdh_rsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384.
%%--------------------------------------------------------------------
-spec openssl_suite(openssl_cipher_suite()) -> cipher_suite().
@@ -415,7 +774,78 @@ openssl_suite("RC4-MD5") ->
openssl_suite("EDH-RSA-DES-CBC-SHA") ->
?TLS_DHE_RSA_WITH_DES_CBC_SHA;
openssl_suite("DES-CBC-SHA") ->
- ?TLS_RSA_WITH_DES_CBC_SHA.
+ ?TLS_RSA_WITH_DES_CBC_SHA;
+
+%%% SRP Cipher Suites RFC 5054
+
+openssl_suite("SRP-DSS-AES-256-CBC-SHA") ->
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
+openssl_suite("SRP-RSA-AES-256-CBC-SHA") ->
+ ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
+openssl_suite("SRP-DSS-3DES-EDE-CBC-SHA") ->
+ ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("SRP-RSA-3DES-EDE-CBC-SHA") ->
+ ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("SRP-DSS-AES-128-CBC-SHA") ->
+ ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
+openssl_suite("SRP-RSA-AES-128-CBC-SHA") ->
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
+
+%% RFC 4492 EC TLS suites
+openssl_suite("ECDH-ECDSA-RC4-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
+openssl_suite("ECDH-ECDSA-DES-CBC3-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDH-ECDSA-AES128-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDH-ECDSA-AES256-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
+
+openssl_suite("ECDHE-ECDSA-RC4-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
+openssl_suite("ECDHE-ECDSA-DES-CBC3-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDHE-ECDSA-AES128-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDHE-ECDSA-AES256-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
+
+openssl_suite("ECDHE-RSA-RC4-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA;
+openssl_suite("ECDHE-RSA-DES-CBC3-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDHE-RSA-AES128-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDHE-RSA-AES256-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
+
+openssl_suite("ECDH-RSA-RC4-SHA") ->
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA;
+openssl_suite("ECDH-RSA-DES-CBC3-SHA") ->
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDH-RSA-AES128-SHA") ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDH-RSA-AES256-SHA") ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
+
+%% RFC 5289 EC TLS suites
+openssl_suite("ECDHE-ECDSA-AES128-SHA256") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDHE-ECDSA-AES256-SHA384") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
+openssl_suite("ECDH-ECDSA-AES128-SHA256") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDH-ECDSA-AES256-SHA384") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
+openssl_suite("ECDHE-RSA-AES128-SHA256") ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDHE-RSA-AES256-SHA384") ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
+openssl_suite("ECDH-RSA-AES128-SHA256") ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDH-RSA-AES256-SHA384") ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384.
+
%%--------------------------------------------------------------------
-spec openssl_suite_name(cipher_suite()) -> openssl_cipher_suite().
%%
@@ -469,6 +899,88 @@ openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256) ->
"DHE-DSS-AES256-SHA256";
openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256) ->
"DHE-RSA-AES256-SHA256";
+
+%%% PSK Cipher Suites RFC 4279
+
+openssl_suite_name(?TLS_PSK_WITH_AES_256_CBC_SHA) ->
+ "PSK-AES256-CBC-SHA";
+openssl_suite_name(?TLS_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ "PSK-3DES-EDE-CBC-SHA";
+openssl_suite_name(?TLS_PSK_WITH_AES_128_CBC_SHA) ->
+ "PSK-AES128-CBC-SHA";
+openssl_suite_name(?TLS_PSK_WITH_RC4_128_SHA) ->
+ "PSK-RC4-SHA";
+
+%%% SRP Cipher Suites RFC 5054
+
+openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ "SRP-RSA-3DES-EDE-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) ->
+ "SRP-DSS-3DES-EDE-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) ->
+ "SRP-RSA-AES-128-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) ->
+ "SRP-DSS-AES-128-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
+ "SRP-RSA-AES-256-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
+ "SRP-DSS-AES-256-CBC-SHA";
+
+%% RFC 4492 EC TLS suites
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) ->
+ "ECDH-ECDSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDH-ECDSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) ->
+ "ECDH-ECDSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) ->
+ "ECDH-ECDSA-AES256-SHA";
+
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) ->
+ "ECDHE-ECDSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDHE-ECDSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) ->
+ "ECDHE-ECDSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) ->
+ "ECDHE-ECDSA-AES256-SHA";
+
+openssl_suite_name(?TLS_ECDH_RSA_WITH_RC4_128_SHA) ->
+ "ECDH-RSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDH-RSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) ->
+ "ECDH-RSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) ->
+ "ECDH-RSA-AES256-SHA";
+
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) ->
+ "ECDHE-RSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDHE-RSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) ->
+ "ECDHE-RSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) ->
+ "ECDHE-RSA-AES256-SHA";
+
+%% RFC 5289 EC TLS suites
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDHE-ECDSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDHE-ECDSA-AES256-SHA384";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDH-ECDSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDH-ECDSA-AES256-SHA384";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDHE-RSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDHE-RSA-AES256-SHA384";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDH-RSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDH-RSA-AES256-SHA384";
+
%% No oppenssl name
openssl_suite_name(Cipher) ->
suite_definition(Cipher).
@@ -483,14 +995,87 @@ filter(undefined, Ciphers) ->
filter(DerCert, Ciphers) ->
OtpCert = public_key:pkix_decode_cert(DerCert, otp),
SigAlg = OtpCert#'OTPCertificate'.signatureAlgorithm,
- case ssl_certificate:signature_type(SigAlg#'SignatureAlgorithm'.algorithm) of
- rsa ->
- filter_rsa(OtpCert, Ciphers -- dsa_signed_suites());
- dsa ->
- Ciphers -- rsa_signed_suites()
+ PubKeyInfo = OtpCert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subjectPublicKeyInfo,
+ PubKeyAlg = PubKeyInfo#'OTPSubjectPublicKeyInfo'.algorithm,
+
+ Ciphers1 =
+ case ssl_certificate:public_key_type(PubKeyAlg#'PublicKeyAlgorithm'.algorithm) of
+ rsa ->
+ filter_keyuse(OtpCert, ((Ciphers -- dsa_signed_suites()) -- ec_keyed_suites()) -- ecdh_suites(),
+ rsa_suites(), dhe_rsa_suites() ++ ecdhe_rsa_suites());
+ dsa ->
+ (Ciphers -- rsa_keyed_suites()) -- ec_keyed_suites();
+ ec ->
+ filter_keyuse(OtpCert, (Ciphers -- rsa_keyed_suites()) -- dsa_signed_suites(),
+ [], ecdhe_ecdsa_suites())
+ end,
+ case public_key:pkix_sign_types(SigAlg#'SignatureAlgorithm'.algorithm) of
+ {_, rsa} ->
+ Ciphers1 -- ecdsa_signed_suites();
+ {_, dsa} ->
+ Ciphers1;
+ {_, ecdsa} ->
+ Ciphers1 -- rsa_signed_suites()
end.
%%--------------------------------------------------------------------
+-spec filter_suites([cipher_suite()]) -> [cipher_suite()].
+%%
+%% Description: filter suites for algorithms
+%%-------------------------------------------------------------------
+filter_suites(Suites = [{_,_,_}|_]) ->
+ Algos = crypto:supports(),
+ lists:filter(fun({KeyExchange, Cipher, Hash}) ->
+ is_acceptable_keyexchange(KeyExchange, proplists:get_value(public_keys, Algos)) andalso
+ is_acceptable_cipher(Cipher, proplists:get_value(ciphers, Algos)) andalso
+ is_acceptable_hash(Hash, proplists:get_value(hashs, Algos))
+ end, Suites);
+
+filter_suites(Suites = [{_,_,_,_}|_]) ->
+ Algos = crypto:supports(),
+ Hashs = proplists:get_value(hashs, Algos),
+ lists:filter(fun({KeyExchange, Cipher, Hash, Prf}) ->
+ is_acceptable_keyexchange(KeyExchange, proplists:get_value(public_keys, Algos)) andalso
+ is_acceptable_cipher(Cipher, proplists:get_value(ciphers, Algos)) andalso
+ is_acceptable_hash(Hash, Hashs) andalso
+ is_acceptable_prf(Prf, Hashs)
+ end, Suites);
+
+filter_suites(Suites) ->
+ Algos = crypto:supports(),
+ Hashs = proplists:get_value(hashs, Algos),
+ lists:filter(fun(Suite) ->
+ {KeyExchange, Cipher, Hash, Prf} = ssl_cipher:suite_definition(Suite),
+ is_acceptable_keyexchange(KeyExchange, proplists:get_value(public_keys, Algos)) andalso
+ is_acceptable_cipher(Cipher, proplists:get_value(ciphers, Algos)) andalso
+ is_acceptable_hash(Hash, Hashs) andalso
+ is_acceptable_prf(Prf, Hashs)
+ end, Suites).
+
+is_acceptable_keyexchange(KeyExchange, Algos)
+ when KeyExchange == ecdh_ecdsa;
+ KeyExchange == ecdhe_ecdsa;
+ KeyExchange == ecdh_rsa;
+ KeyExchange == ecdhe_rsa;
+ KeyExchange == ecdh_anon ->
+ proplists:get_bool(ecdh, Algos);
+is_acceptable_keyexchange(_, _) ->
+ true.
+
+is_acceptable_cipher(_, _) ->
+ true.
+
+is_acceptable_hash(null, _Algos) ->
+ true;
+is_acceptable_hash(Hash, Algos) ->
+ proplists:get_bool(Hash, Algos).
+
+is_acceptable_prf(default_prf, _) ->
+ true;
+is_acceptable_prf(Prf, Algos) ->
+ proplists:get_bool(Prf, Algos).
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -605,14 +1190,14 @@ hash_size(md5) ->
16;
hash_size(sha) ->
20;
+hash_size(sha224) ->
+ 28;
hash_size(sha256) ->
- 32.
-%% Currently no supported cipher suites defaults to sha384 or sha512
-%% so these clauses are not needed at the moment.
-%% hash_size(sha384) ->
-%% 48;
-%% hash_size(sha512) ->
-%% 64.
+ 32;
+hash_size(sha384) ->
+ 48;
+hash_size(sha512) ->
+ 64.
%% RFC 5246: 6.2.3.2. CBC Block Cipher
%%
@@ -702,7 +1287,14 @@ next_iv(Bin, IV) ->
NextIV.
rsa_signed_suites() ->
- dhe_rsa_suites() ++ rsa_suites().
+ dhe_rsa_suites() ++ rsa_suites() ++
+ psk_rsa_suites() ++ srp_rsa_suites() ++
+ ecdh_rsa_suites().
+
+rsa_keyed_suites() ->
+ dhe_rsa_suites() ++ rsa_suites() ++
+ psk_rsa_suites() ++ srp_rsa_suites() ++
+ ecdhe_rsa_suites().
dhe_rsa_suites() ->
[?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
@@ -712,6 +1304,19 @@ dhe_rsa_suites() ->
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
?TLS_DHE_RSA_WITH_DES_CBC_SHA].
+psk_rsa_suites() ->
+ [?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_RC4_128_SHA].
+
+srp_rsa_suites() ->
+ [?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA].
+
rsa_suites() ->
[?TLS_RSA_WITH_AES_256_CBC_SHA256,
?TLS_RSA_WITH_AES_256_CBC_SHA,
@@ -721,9 +1326,27 @@ rsa_suites() ->
?TLS_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_MD5,
?TLS_RSA_WITH_DES_CBC_SHA].
-
+
+ecdh_rsa_suites() ->
+ [?TLS_ECDH_RSA_WITH_NULL_SHA,
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA,
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384].
+
+ecdhe_rsa_suites() ->
+ [?TLS_ECDHE_RSA_WITH_NULL_SHA,
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384].
+
dsa_signed_suites() ->
- dhe_dss_suites().
+ dhe_dss_suites() ++ srp_dss_suites().
dhe_dss_suites() ->
[?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
@@ -733,24 +1356,57 @@ dhe_dss_suites() ->
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA].
-filter_rsa(OtpCert, RsaCiphers) ->
+srp_dss_suites() ->
+ [?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA].
+
+ec_keyed_suites() ->
+ ecdh_ecdsa_suites() ++ ecdhe_ecdsa_suites()
+ ++ ecdh_rsa_suites().
+
+ecdsa_signed_suites() ->
+ ecdh_ecdsa_suites() ++ ecdhe_ecdsa_suites().
+
+ecdh_suites() ->
+ ecdh_rsa_suites() ++ ecdh_ecdsa_suites().
+
+ecdh_ecdsa_suites() ->
+ [?TLS_ECDH_ECDSA_WITH_NULL_SHA,
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384].
+
+ecdhe_ecdsa_suites() ->
+ [?TLS_ECDHE_ECDSA_WITH_NULL_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384].
+
+filter_keyuse(OtpCert, Ciphers, Suites, SignSuites) ->
TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,
TBSExtensions = TBSCert#'OTPTBSCertificate'.extensions,
Extensions = ssl_certificate:extensions_list(TBSExtensions),
case ssl_certificate:select_extension(?'id-ce-keyUsage', Extensions) of
undefined ->
- RsaCiphers;
+ Ciphers;
#'Extension'{extnValue = KeyUse} ->
- Result = filter_rsa_suites(keyEncipherment,
- KeyUse, RsaCiphers, rsa_suites()),
- filter_rsa_suites(digitalSignature,
- KeyUse, Result, dhe_rsa_suites())
+ Result = filter_keyuse_suites(keyEncipherment,
+ KeyUse, Ciphers, Suites),
+ filter_keyuse_suites(digitalSignature,
+ KeyUse, Result, SignSuites)
end.
-filter_rsa_suites(Use, KeyUse, CipherSuits, RsaSuites) ->
+filter_keyuse_suites(Use, KeyUse, CipherSuits, Suites) ->
case ssl_certificate:is_valid_key_usage(KeyUse, Use) of
true ->
CipherSuits;
false ->
- CipherSuits -- RsaSuites
+ CipherSuits -- Suites
end.
diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl
index 0f439f8ed5..c7c71ee1a7 100644
--- a/lib/ssl/src/ssl_cipher.hrl
+++ b/lib/ssl/src/ssl_cipher.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,9 +28,9 @@
-type cipher() :: null |rc4_128 | idea_cbc | des40_cbc | des_cbc | '3des_ede_cbc'
| aes_128_cbc | aes_256_cbc.
--type hash() :: null | sha | md5 | sha256 | sha384 | sha512.
+-type hash() :: null | sha | md5 | ssh224 | sha256 | sha384 | sha512.
-type erl_cipher_suite() :: {key_algo(), cipher(), hash()}.
--type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash()}.
+-type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash() | default_prf}.
-type cipher_suite() :: binary().
-type cipher_enum() :: integer().
-type openssl_cipher_suite() :: string().
@@ -219,6 +219,120 @@
%% TLS_DH_anon_WITH_AES_256_CBC_SHA256 = { 0x00,0x6D };
-define(TLS_DH_anon_WITH_AES_256_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#6D)>>).
+%% RFC 4492 EC TLS suites
+
+%% ECDH_ECDSA
+
+%% TLS_ECDH_ECDSA_WITH_NULL_SHA = { 0xC0, 0x01 }
+-define(TLS_ECDH_ECDSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#01)>>).
+
+%% TLS_ECDH_ECDSA_WITH_RC4_128_SHA = { 0xC0, 0x02 }
+-define(TLS_ECDH_ECDSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#02)>>).
+
+%% TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x03 }
+-define(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#03)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x04 }
+-define(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#04)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x05 }
+-define(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#05)>>).
+
+%% ECDHE_ECDSA
+
+%% TLS_ECDHE_ECDSA_WITH_NULL_SHA = { 0xC0, 0x06 }
+-define(TLS_ECDHE_ECDSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#06)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = { 0xC0, 0x07 }
+-define(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#07)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x08 }
+-define(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#08)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x09 }
+-define(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#09)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x0A }
+-define(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0A)>>).
+
+%% ECDH_RSA
+
+%% TLS_ECDH_RSA_WITH_NULL_SHA = { 0xC0, 0x0B }
+-define(TLS_ECDH_RSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#0B)>>).
+
+%% TLS_ECDH_RSA_WITH_RC4_128_SHA = { 0xC0, 0x0C }
+-define(TLS_ECDH_RSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#0C)>>).
+
+%% TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x0D }
+-define(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0D)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x0E }
+-define(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0E)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x0F }
+-define(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0F)>>).
+
+%% ECDHE_RSA
+
+%% TLS_ECDHE_RSA_WITH_NULL_SHA = { 0xC0, 0x10 }
+-define(TLS_ECDHE_RSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#10)>>).
+
+%% TLS_ECDHE_RSA_WITH_RC4_128_SHA = { 0xC0, 0x11 }
+-define(TLS_ECDHE_RSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#11)>>).
+
+%% TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x12 }
+-define(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#12)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x13 }
+-define(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#13)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x14 }
+-define(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#14)>>).
+
+%% ECDH_anon
+
+%% TLS_ECDH_anon_WITH_NULL_SHA = { 0xC0, 0x15 }
+-define(TLS_ECDH_anon_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#15)>>).
+
+%% TLS_ECDH_anon_WITH_RC4_128_SHA = { 0xC0, 0x16 }
+-define(TLS_ECDH_anon_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#16)>>).
+
+%% TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x17 }
+-define(TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#17)>>).
+
+%% TLS_ECDH_anon_WITH_AES_128_CBC_SHA = { 0xC0, 0x18 }
+-define(TLS_ECDH_anon_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#18)>>).
+
+%% TLS_ECDH_anon_WITH_AES_256_CBC_SHA = { 0xC0, 0x19 }
+-define(TLS_ECDH_anon_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#19)>>).
+
+
+%% RFC 5289 EC TLS suites
+
+%% TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x23};
+-define(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#23)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x24};
+-define(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#24)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x25};
+-define(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#25)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x26};
+-define(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#26)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x27};
+-define(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#27)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x28};
+-define(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#28)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x29};
+-define(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#29)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x2A};
+-define(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#2A)>>).
+
%%% Kerberos Cipher Suites
%% TLS_KRB5_WITH_DES_CBC_SHA = { 0x00,0x1E };
@@ -250,4 +364,109 @@
%% hello extension data as they should.
-define(TLS_EMPTY_RENEGOTIATION_INFO_SCSV, <<?BYTE(16#00), ?BYTE(16#FF)>>).
+%%% PSK Cipher Suites RFC 4279
+
+%% TLS_PSK_WITH_RC4_128_SHA = { 0x00, 0x8A };
+-define(TLS_PSK_WITH_RC4_128_SHA, <<?BYTE(16#00), ?BYTE(16#8A)>>).
+
+%% TLS_PSK_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x8B };
+-define(TLS_PSK_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8B)>>).
+
+%% TLS_PSK_WITH_AES_128_CBC_SHA = { 0x00, 0x8C };
+-define(TLS_PSK_WITH_AES_128_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8C)>>).
+
+%% TLS_PSK_WITH_AES_256_CBC_SHA = { 0x00, 0x8D };
+-define(TLS_PSK_WITH_AES_256_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8D)>>).
+
+%% TLS_DHE_PSK_WITH_RC4_128_SHA = { 0x00, 0x8E };
+-define(TLS_DHE_PSK_WITH_RC4_128_SHA, <<?BYTE(16#00), ?BYTE(16#8E)>>).
+
+%% TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x8F };
+-define(TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8F)>>).
+
+%% TLS_DHE_PSK_WITH_AES_128_CBC_SHA = { 0x00, 0x90 };
+-define(TLS_DHE_PSK_WITH_AES_128_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#90)>>).
+
+%% TLS_DHE_PSK_WITH_AES_256_CBC_SHA = { 0x00, 0x91 };
+-define(TLS_DHE_PSK_WITH_AES_256_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#91)>>).
+
+%% TLS_RSA_PSK_WITH_RC4_128_SHA = { 0x00, 0x92 };
+-define(TLS_RSA_PSK_WITH_RC4_128_SHA, <<?BYTE(16#00), ?BYTE(16#92)>>).
+
+%% TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x93 };
+-define(TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#93)>>).
+
+%% TLS_RSA_PSK_WITH_AES_128_CBC_SHA = { 0x00, 0x94 };
+-define(TLS_RSA_PSK_WITH_AES_128_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#94)>>).
+
+%% TLS_RSA_PSK_WITH_AES_256_CBC_SHA = { 0x00, 0x95 };
+-define(TLS_RSA_PSK_WITH_AES_256_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#95)>>).
+
+%%% TLS 1.2 PSK Cipher Suites RFC 5487
+
+%% TLS_PSK_WITH_AES_128_CBC_SHA256 = {0x00,0xAE};
+-define(TLS_PSK_WITH_AES_128_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#AE)>>).
+
+%% TLS_PSK_WITH_AES_256_CBC_SHA384 = {0x00,0xAF};
+-define(TLS_PSK_WITH_AES_256_CBC_SHA384, <<?BYTE(16#00), ?BYTE(16#AF)>>).
+
+%% TLS_PSK_WITH_NULL_SHA256 = {0x00,0xB0};
+-define(TLS_PSK_WITH_NULL_SHA256, <<?BYTE(16#00), ?BYTE(16#B0)>>).
+
+%% TLS_PSK_WITH_NULL_SHA384 = {0x00,0xB1};
+-define(TLS_PSK_WITH_NULL_SHA384, <<?BYTE(16#00), ?BYTE(16#B1)>>).
+
+%% TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = {0x00,0xB2};
+-define(TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#B2)>>).
+
+%% TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = {0x00,0xB3};
+-define(TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, <<?BYTE(16#00), ?BYTE(16#B3)>>).
+
+%% TLS_DHE_PSK_WITH_NULL_SHA256 = {0x00,0xB4};
+-define(TLS_DHE_PSK_WITH_NULL_SHA256, <<?BYTE(16#00), ?BYTE(16#B4)>>).
+
+%% TLS_DHE_PSK_WITH_NULL_SHA384 = {0x00,0xB5};
+-define(TLS_DHE_PSK_WITH_NULL_SHA384, <<?BYTE(16#00), ?BYTE(16#B5)>>).
+
+%% TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 = {0x00,0xB6};
+-define(TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#B6)>>).
+
+%% TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 = {0x00,0xB7};
+-define(TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, <<?BYTE(16#00), ?BYTE(16#B7)>>).
+
+%% TLS_RSA_PSK_WITH_NULL_SHA256 = {0x00,0xB8};
+-define(TLS_RSA_PSK_WITH_NULL_SHA256, <<?BYTE(16#00), ?BYTE(16#B8)>>).
+
+%% TLS_RSA_PSK_WITH_NULL_SHA384 = {0x00,0xB9};
+-define(TLS_RSA_PSK_WITH_NULL_SHA384, <<?BYTE(16#00), ?BYTE(16#B9)>>).
+
+%%% SRP Cipher Suites RFC 5054
+
+%% TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = { 0xC0,0x1A };
+-define(TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1A)>>).
+
+%% TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0,0x1B };
+-define(TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1B)>>).
+
+%% TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = { 0xC0,0x1C };
+-define(TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1C)>>).
+
+%% TLS_SRP_SHA_WITH_AES_128_CBC_SHA = { 0xC0,0x1D };
+-define(TLS_SRP_SHA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1D)>>).
+
+%% TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = { 0xC0,0x1E };
+-define(TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1E)>>).
+
+%% TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = { 0xC0,0x1F };
+-define(TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1F)>>).
+
+%% TLS_SRP_SHA_WITH_AES_256_CBC_SHA = { 0xC0,0x20 };
+-define(TLS_SRP_SHA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#20)>>).
+
+%% TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = { 0xC0,0x21 };
+-define(TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#21)>>).
+
+%% TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = { 0xC0,0x22 };
+-define(TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#22)>>).
+
-endif. % -ifdef(ssl_cipher).
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 8f4fd88d42..de9260fd8c 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -34,6 +34,7 @@
-include("ssl_record.hrl").
-include("ssl_cipher.hrl").
-include("ssl_internal.hrl").
+-include("ssl_srp.hrl").
-include_lib("public_key/include/public_key.hrl").
%% Internal application API
@@ -73,7 +74,6 @@
session_cache, %
session_cache_cb, %
negotiated_version, % tls_version()
- supported_protocol_versions, % [atom()]
client_certificate_requested = false,
key_algorithm, % atom as defined by cipher_suite
hashsign_algorithm, % atom as defined by cipher_suite
@@ -81,6 +81,9 @@
private_key, % PKIX: #'RSAPrivateKey'{}
diffie_hellman_params, % PKIX: #'DHParameter'{} relevant for server side
diffie_hellman_keys, % {PublicKey, PrivateKey}
+ psk_identity, % binary() - server psk identity hint
+ srp_params, % #srp_user{}
+ srp_keys, % {PublicKey, PrivateKey}
premaster_secret, %
file_ref_db, % ets()
cert_db_ref, % ref()
@@ -94,7 +97,8 @@
terminated = false, %
allow_renegotiate = true,
expecting_next_protocol_negotiation = false :: boolean(),
- next_protocol = undefined :: undefined | binary()
+ next_protocol = undefined :: undefined | binary(),
+ client_ecc % {Curves, PointFmt}
}).
-define(DEFAULT_DIFFIE_HELLMAN_PARAMS,
@@ -412,11 +416,14 @@ hello(Hello = #client_hello{client_version = ClientVersion},
ssl_options = SslOpts}) ->
case ssl_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
ConnectionStates0, Cert}, Renegotiation) of
- {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise} ->
- do_server_hello(Type, ProtocolsToAdvertise, State#state{connection_states =
- ConnectionStates,
- negotiated_version = Version,
- session = Session});
+ {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise,
+ EcPointFormats, EllipticCurves} ->
+ do_server_hello(Type, ProtocolsToAdvertise,
+ EcPointFormats, EllipticCurves,
+ State#state{connection_states = ConnectionStates,
+ negotiated_version = Version,
+ session = Session,
+ client_ecc = {EllipticCurves, EcPointFormats}});
#alert{} = Alert ->
handle_own_alert(Alert, ClientVersion, hello, State)
end;
@@ -472,6 +479,13 @@ abbreviated(#finished{verify_data = Data} = Finished,
handle_own_alert(Alert, Version, abbreviated, State)
end;
+%% only allowed to send next_protocol message after change cipher spec
+%% & before finished message and it is not allowed during renegotiation
+abbreviated(#next_protocol{selected_protocol = SelectedProtocol},
+ #state{role = server, expecting_next_protocol_negotiation = true} = State0) ->
+ {Record, State} = next_record(State0#state{next_protocol = SelectedProtocol}),
+ next_state(abbreviated, abbreviated, Record, State);
+
abbreviated(timeout, State) ->
{ next_state, abbreviated, State, hibernate };
@@ -522,7 +536,11 @@ certify(#certificate{} = Cert,
certify(#server_key_exchange{} = KeyExchangeMsg,
#state{role = client, negotiated_version = Version,
key_algorithm = Alg} = State0)
- when Alg == dhe_dss; Alg == dhe_rsa; Alg == dh_anon ->
+ when Alg == dhe_dss; Alg == dhe_rsa;
+ Alg == ecdhe_rsa; Alg == ecdhe_ecdsa;
+ Alg == dh_anon; Alg == ecdh_anon;
+ Alg == psk; Alg == dhe_psk; Alg == rsa_psk;
+ Alg == srp_dss; Alg == srp_rsa; Alg == srp_anon ->
case handle_server_key(KeyExchangeMsg, State0) of
#state{} = State1 ->
{Record, State} = next_record(State1),
@@ -539,6 +557,45 @@ certify(#certificate_request{}, State0) ->
{Record, State} = next_record(State0#state{client_certificate_requested = true}),
next_state(certify, certify, Record, State);
+%% PSK and RSA_PSK might bypass the Server-Key-Exchange
+certify(#server_hello_done{},
+ #state{session = #session{master_secret = undefined},
+ negotiated_version = Version,
+ psk_identity = PSKIdentity,
+ premaster_secret = undefined,
+ role = client,
+ key_algorithm = Alg} = State0)
+ when Alg == psk ->
+ case server_psk_master_secret(PSKIdentity, State0) of
+ #state{} = State ->
+ client_certify_and_key_exchange(State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, certify, State0)
+ end;
+
+certify(#server_hello_done{},
+ #state{session = #session{master_secret = undefined},
+ ssl_options = SslOpts,
+ negotiated_version = Version,
+ psk_identity = PSKIdentity,
+ premaster_secret = undefined,
+ role = client,
+ key_algorithm = Alg} = State0)
+ when Alg == rsa_psk ->
+ case handle_psk_identity(PSKIdentity, SslOpts#ssl_options.user_lookup_fun) of
+ {ok, PSK} when is_binary(PSK) ->
+ PremasterSecret = make_premaster_secret(Version, rsa),
+ Len = byte_size(PSK),
+ RealPMS = <<?UINT16(48), PremasterSecret/binary, ?UINT16(Len), PSK/binary>>,
+ State1 = State0#state{premaster_secret = PremasterSecret},
+ State = master_from_premaster_secret(RealPMS, State1),
+ client_certify_and_key_exchange(State);
+ #alert{} = Alert ->
+ Alert;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end;
+
%% Master secret was determined with help of server-key exchange msg
certify(#server_hello_done{},
#state{session = #session{master_secret = MasterSecret} = Session,
@@ -617,9 +674,74 @@ certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS
certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPublicDhKey},
#state{negotiated_version = Version,
diffie_hellman_params = #'DHParameter'{prime = P,
+ base = G} = Params,
+ diffie_hellman_keys = {_, ServerDhPrivateKey}} = State0) ->
+ case dh_master_secret(Params, ClientPublicDhKey, ServerDhPrivateKey, State0) of
+ #state{} = State1 ->
+ {Record, State} = next_record(State1),
+ next_state(certify, cipher, Record, State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, certify, State0)
+ end;
+
+certify_client_key_exchange(#client_ec_diffie_hellman_public{dh_public = ClientPublicEcDhPoint},
+ #state{negotiated_version = Version,
+ diffie_hellman_keys = ECDHKey} = State0) ->
+ case ec_dh_master_secret(ECDHKey, #'ECPoint'{point = ClientPublicEcDhPoint}, State0) of
+ #state{} = State1 ->
+ {Record, State} = next_record(State1),
+ next_state(certify, cipher, Record, State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, certify, State0)
+ end;
+
+certify_client_key_exchange(#client_psk_identity{identity = ClientPSKIdentity},
+ #state{negotiated_version = Version} = State0) ->
+ case server_psk_master_secret(ClientPSKIdentity, State0) of
+ #state{} = State1 ->
+ {Record, State} = next_record(State1),
+ next_state(certify, cipher, Record, State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, certify, State0)
+ end;
+
+certify_client_key_exchange(#client_dhe_psk_identity{
+ identity = ClientPSKIdentity,
+ dh_public = ClientPublicDhKey},
+ #state{negotiated_version = Version,
+ diffie_hellman_params = #'DHParameter'{prime = P,
base = G},
diffie_hellman_keys = {_, ServerDhPrivateKey}} = State0) ->
- case dh_master_secret(crypto:mpint(P), crypto:mpint(G), ClientPublicDhKey, ServerDhPrivateKey, State0) of
+ case dhe_psk_master_secret(ClientPSKIdentity, P, G, ClientPublicDhKey, ServerDhPrivateKey, State0) of
+ #state{} = State1 ->
+ {Record, State} = next_record(State1),
+ next_state(certify, cipher, Record, State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, certify, State0)
+ end;
+
+certify_client_key_exchange(#client_rsa_psk_identity{
+ identity = PskIdentity,
+ exchange_keys =
+ #encrypted_premaster_secret{premaster_secret= EncPMS}},
+ #state{negotiated_version = Version,
+ private_key = Key} = State0) ->
+ PremasterSecret = ssl_handshake:decrypt_premaster_secret(EncPMS, Key),
+ case server_rsa_psk_master_secret(PskIdentity, PremasterSecret, State0) of
+ #state{} = State1 ->
+ {Record, State} = next_record(State1),
+ next_state(certify, cipher, Record, State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, certify, State0)
+ end;
+
+certify_client_key_exchange(#client_srp_public{srp_a = ClientPublicKey},
+ #state{negotiated_version = Version,
+ srp_params =
+ #srp_user{prime = Prime,
+ verifier = Verifier}
+ } = State0) ->
+ case server_srp_master_secret(Verifier, Prime, ClientPublicKey, State0) of
#state{} = State1 ->
{Record, State} = next_record(State1),
next_state(certify, cipher, Record, State);
@@ -656,11 +778,10 @@ cipher(#certificate_verify{signature = Signature, hashsign_algorithm = CertHashS
handle_own_alert(Alert, Version, cipher, State0)
end;
-% client must send a next protocol message if we are expecting it
+%% client must send a next protocol message if we are expecting it
cipher(#finished{}, #state{role = server, expecting_next_protocol_negotiation = true,
next_protocol = undefined, negotiated_version = Version} = State0) ->
- handle_own_alert(?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE), Version, cipher, State0),
- {stop, normal, State0};
+ handle_own_alert(?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE), Version, cipher, State0);
cipher(#finished{verify_data = Data} = Finished,
#state{negotiated_version = Version,
@@ -682,8 +803,8 @@ cipher(#finished{verify_data = Data} = Finished,
handle_own_alert(Alert, Version, cipher, State)
end;
-% only allowed to send next_protocol message after change cipher spec
-% & before finished message and it is not allowed during renegotiation
+%% only allowed to send next_protocol message after change cipher spec
+%% & before finished message and it is not allowed during renegotiation
cipher(#next_protocol{selected_protocol = SelectedProtocol},
#state{role = server, expecting_next_protocol_negotiation = true} = State0) ->
{Record, State} = next_record(State0#state{next_protocol = SelectedProtocol}),
@@ -1146,7 +1267,9 @@ init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHan
init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, CertFile, client) ->
try
- [OwnCert] = ssl_certificate:file_to_certificats(CertFile, PemCacheHandle),
+ %% Ignoring potential proxy-certificates see:
+ %% http://dev.globus.org/wiki/Security/ProxyFileFormat
+ [OwnCert|_] = ssl_certificate:file_to_certificats(CertFile, PemCacheHandle),
{ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, OwnCert}
catch _Error:_Reason ->
{ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, undefined}
@@ -1154,7 +1277,7 @@ init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHan
init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, CertFile, server) ->
try
- [OwnCert] = ssl_certificate:file_to_certificats(CertFile, PemCacheHandle),
+ [OwnCert|_] = ssl_certificate:file_to_certificats(CertFile, PemCacheHandle),
{ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, OwnCert}
catch
_:Reason ->
@@ -1171,6 +1294,7 @@ init_private_key(DbHandle, undefined, KeyFile, Password, _) ->
[PemEntry] = [PemEntry || PemEntry = {PKey, _ , _} <- List,
PKey =:= 'RSAPrivateKey' orelse
PKey =:= 'DSAPrivateKey' orelse
+ PKey =:= 'ECPrivateKey' orelse
PKey =:= 'PrivateKeyInfo'
],
private_key(public_key:pem_entry_decode(PemEntry, Password))
@@ -1184,6 +1308,8 @@ init_private_key(_,{rsa, PrivateKey}, _, _,_) ->
init_private_key('RSAPrivateKey', PrivateKey);
init_private_key(_,{dsa, PrivateKey},_,_,_) ->
init_private_key('DSAPrivateKey', PrivateKey);
+init_private_key(_,{ec, PrivateKey},_,_,_) ->
+ init_private_key('ECPrivateKey', PrivateKey);
init_private_key(_,{Asn1Type, PrivateKey},_,_,_) ->
private_key(init_private_key(Asn1Type, PrivateKey)).
@@ -1199,6 +1325,7 @@ private_key(#'PrivateKeyInfo'{privateKeyAlgorithm =
#'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-dsa'},
privateKey = Key}) ->
public_key:der_decode('DSAPrivateKey', iolist_to_binary(Key));
+
private_key(Key) ->
Key.
@@ -1250,7 +1377,15 @@ handle_peer_cert(PeerCert, PublicKeyInfo,
State1 = State0#state{session =
Session#session{peer_certificate = PeerCert},
public_key_info = PublicKeyInfo},
- {Record, State} = next_record(State1),
+ State2 = case PublicKeyInfo of
+ {?'id-ecPublicKey', #'ECPoint'{point = _ECPoint} = PublicKey, PublicKeyParams} ->
+ ECDHKey = public_key:generate_key(PublicKeyParams),
+ State3 = State1#state{diffie_hellman_keys = ECDHKey},
+ ec_dh_master_secret(ECDHKey, PublicKey, State3);
+
+ _ -> State1
+ end,
+ {Record, State} = next_record(State2),
next_state(certify, certify, Record, State).
certify_client(#state{client_certificate_requested = true, role = client,
@@ -1300,15 +1435,18 @@ verify_client_cert(#state{client_certificate_requested = true, role = client,
verify_client_cert(#state{client_certificate_requested = false} = State) ->
State.
-do_server_hello(Type, NextProtocolsToSend, #state{negotiated_version = Version,
- session = #session{session_id = SessId},
- connection_states = ConnectionStates0,
- renegotiation = {Renegotiation, _}}
+do_server_hello(Type, NextProtocolsToSend,
+ EcPointFormats, EllipticCurves,
+ #state{negotiated_version = Version,
+ session = #session{session_id = SessId},
+ connection_states = ConnectionStates0,
+ renegotiation = {Renegotiation, _}}
= State0) when is_atom(Type) ->
ServerHello =
ssl_handshake:server_hello(SessId, Version,
- ConnectionStates0, Renegotiation, NextProtocolsToSend),
+ ConnectionStates0, Renegotiation,
+ NextProtocolsToSend, EcPointFormats, EllipticCurves),
State = server_hello(ServerHello,
State0#state{expecting_next_protocol_negotiation =
NextProtocolsToSend =/= undefined}),
@@ -1439,7 +1577,8 @@ server_hello_done(#state{transport_cb = Transport,
State#state{connection_states = ConnectionStates,
tls_handshake_history = Handshake}.
-certify_server(#state{key_algorithm = dh_anon} = State) ->
+certify_server(#state{key_algorithm = Algo} = State)
+ when Algo == dh_anon; Algo == ecdh_anon; Algo == psk; Algo == dhe_psk; Algo == srp_anon ->
State;
certify_server(#state{transport_cb = Transport,
@@ -1466,7 +1605,7 @@ key_exchange(#state{role = server, key_algorithm = rsa} = State) ->
State;
key_exchange(#state{role = server, key_algorithm = Algo,
hashsign_algorithm = HashSignAlgo,
- diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params,
+ diffie_hellman_params = #'DHParameter'{} = Params,
private_key = PrivateKey,
connection_states = ConnectionStates0,
negotiated_version = Version,
@@ -1477,13 +1616,13 @@ key_exchange(#state{role = server, key_algorithm = Algo,
when Algo == dhe_dss;
Algo == dhe_rsa;
Algo == dh_anon ->
- Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]),
+ DHKeys = public_key:generate_key(Params),
ConnectionState =
ssl_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {dh, Keys, Params,
+ Msg = ssl_handshake:key_exchange(server, Version, {dh, DHKeys, Params,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1491,7 +1630,161 @@ key_exchange(#state{role = server, key_algorithm = Algo,
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
State#state{connection_states = ConnectionStates,
- diffie_hellman_keys = Keys,
+ diffie_hellman_keys = DHKeys,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = server, private_key = Key, key_algorithm = Algo} = State)
+ when Algo == ecdh_ecdsa; Algo == ecdh_rsa ->
+ State#state{diffie_hellman_keys = Key};
+key_exchange(#state{role = server, key_algorithm = Algo,
+ hashsign_algorithm = HashSignAlgo,
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = State)
+ when Algo == ecdhe_ecdsa; Algo == ecdhe_rsa;
+ Algo == ecdh_anon ->
+
+ ECDHKeys = public_key:generate_key(select_curve(State)),
+ ConnectionState =
+ ssl_record:pending_connection_state(ConnectionStates0, read),
+ SecParams = ConnectionState#connection_state.security_parameters,
+ #security_parameters{client_random = ClientRandom,
+ server_random = ServerRandom} = SecParams,
+ Msg = ssl_handshake:key_exchange(server, Version, {ecdh, ECDHKeys,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {BinMsg, ConnectionStates, Handshake1} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ diffie_hellman_keys = ECDHKeys,
+ tls_handshake_history = Handshake1};
+
+key_exchange(#state{role = server, key_algorithm = psk,
+ ssl_options = #ssl_options{psk_identity = undefined}} = State) ->
+ State;
+key_exchange(#state{role = server, key_algorithm = psk,
+ ssl_options = #ssl_options{psk_identity = PskIdentityHint},
+ hashsign_algorithm = HashSignAlgo,
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = State) ->
+ ConnectionState =
+ ssl_record:pending_connection_state(ConnectionStates0, read),
+ SecParams = ConnectionState#connection_state.security_parameters,
+ #security_parameters{client_random = ClientRandom,
+ server_random = ServerRandom} = SecParams,
+ Msg = ssl_handshake:key_exchange(server, Version, {psk, PskIdentityHint,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = server, key_algorithm = dhe_psk,
+ ssl_options = #ssl_options{psk_identity = PskIdentityHint},
+ hashsign_algorithm = HashSignAlgo,
+ diffie_hellman_params = #'DHParameter'{} = Params,
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = State) ->
+ DHKeys = public_key:generate_key(Params),
+ ConnectionState =
+ ssl_record:pending_connection_state(ConnectionStates0, read),
+ SecParams = ConnectionState#connection_state.security_parameters,
+ #security_parameters{client_random = ClientRandom,
+ server_random = ServerRandom} = SecParams,
+ Msg = ssl_handshake:key_exchange(server, Version, {dhe_psk, PskIdentityHint, DHKeys, Params,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ diffie_hellman_keys = DHKeys,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = server, key_algorithm = rsa_psk,
+ ssl_options = #ssl_options{psk_identity = undefined}} = State) ->
+ State;
+key_exchange(#state{role = server, key_algorithm = rsa_psk,
+ ssl_options = #ssl_options{psk_identity = PskIdentityHint},
+ hashsign_algorithm = HashSignAlgo,
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = State) ->
+ ConnectionState =
+ ssl_record:pending_connection_state(ConnectionStates0, read),
+ SecParams = ConnectionState#connection_state.security_parameters,
+ #security_parameters{client_random = ClientRandom,
+ server_random = ServerRandom} = SecParams,
+ Msg = ssl_handshake:key_exchange(server, Version, {psk, PskIdentityHint,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = server, key_algorithm = Algo,
+ ssl_options = #ssl_options{user_lookup_fun = LookupFun},
+ hashsign_algorithm = HashSignAlgo,
+ session = #session{srp_username = Username},
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = State)
+ when Algo == srp_dss;
+ Algo == srp_rsa;
+ Algo == srp_anon ->
+ SrpParams = handle_srp_identity(Username, LookupFun),
+ Keys = case generate_srp_server_keys(SrpParams, 0) of
+ Alert = #alert{} ->
+ throw(Alert);
+ Keys0 = {_,_} ->
+ Keys0
+ end,
+ ConnectionState =
+ ssl_record:pending_connection_state(ConnectionStates0, read),
+ SecParams = ConnectionState#connection_state.security_parameters,
+ #security_parameters{client_random = ClientRandom,
+ server_random = ServerRandom} = SecParams,
+ Msg = ssl_handshake:key_exchange(server, Version, {srp, Keys, SrpParams,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ srp_params = SrpParams,
+ srp_keys = Keys,
tls_handshake_history = Handshake};
key_exchange(#state{role = client,
@@ -1523,6 +1816,85 @@ key_exchange(#state{role = client,
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
State#state{connection_states = ConnectionStates,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = client,
+ connection_states = ConnectionStates0,
+ key_algorithm = Algorithm,
+ negotiated_version = Version,
+ diffie_hellman_keys = Keys,
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State)
+ when Algorithm == ecdhe_ecdsa; Algorithm == ecdhe_rsa;
+ Algorithm == ecdh_ecdsa; Algorithm == ecdh_rsa;
+ Algorithm == ecdh_anon ->
+ Msg = ssl_handshake:key_exchange(client, Version, {ecdh, Keys}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = client,
+ ssl_options = SslOpts,
+ connection_states = ConnectionStates0,
+ key_algorithm = psk,
+ negotiated_version = Version,
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State) ->
+ Msg = ssl_handshake:key_exchange(client, Version, {psk, SslOpts#ssl_options.psk_identity}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = client,
+ ssl_options = SslOpts,
+ connection_states = ConnectionStates0,
+ key_algorithm = dhe_psk,
+ negotiated_version = Version,
+ diffie_hellman_keys = {DhPubKey, _},
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State) ->
+ Msg = ssl_handshake:key_exchange(client, Version, {dhe_psk, SslOpts#ssl_options.psk_identity, DhPubKey}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = client,
+ ssl_options = SslOpts,
+ connection_states = ConnectionStates0,
+ key_algorithm = rsa_psk,
+ public_key_info = PublicKeyInfo,
+ negotiated_version = Version,
+ premaster_secret = PremasterSecret,
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State) ->
+ Msg = rsa_psk_key_exchange(Version, SslOpts#ssl_options.psk_identity, PremasterSecret, PublicKeyInfo),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = client,
+ connection_states = ConnectionStates0,
+ key_algorithm = Algorithm,
+ negotiated_version = Version,
+ srp_keys = {ClientPubKey, _},
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State)
+ when Algorithm == srp_dss;
+ Algorithm == srp_rsa;
+ Algorithm == srp_anon ->
+ Msg = ssl_handshake:key_exchange(client, Version, {srp, ClientPubKey}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
tls_handshake_history = Handshake}.
rsa_key_exchange(Version, PremasterSecret, PublicKeyInfo = {Algorithm, _, _})
@@ -1541,6 +1913,22 @@ rsa_key_exchange(Version, PremasterSecret, PublicKeyInfo = {Algorithm, _, _})
rsa_key_exchange(_, _, _) ->
throw (?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE)).
+rsa_psk_key_exchange(Version, PskIdentity, PremasterSecret, PublicKeyInfo = {Algorithm, _, _})
+ when Algorithm == ?rsaEncryption;
+ Algorithm == ?md2WithRSAEncryption;
+ Algorithm == ?md5WithRSAEncryption;
+ Algorithm == ?sha1WithRSAEncryption;
+ Algorithm == ?sha224WithRSAEncryption;
+ Algorithm == ?sha256WithRSAEncryption;
+ Algorithm == ?sha384WithRSAEncryption;
+ Algorithm == ?sha512WithRSAEncryption
+ ->
+ ssl_handshake:key_exchange(client, Version,
+ {psk_premaster_secret, PskIdentity, PremasterSecret,
+ PublicKeyInfo});
+rsa_psk_key_exchange(_, _, _, _) ->
+ throw (?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE)).
+
request_client_cert(#state{ssl_options = #ssl_options{verify = verify_peer},
connection_states = ConnectionStates0,
cert_db = CertDbHandle,
@@ -1628,7 +2016,7 @@ handle_server_key(#server_key_exchange{exchange_keys = Keys},
Params = ssl_handshake:decode_server_key(Keys, KeyAlg, Version),
HashSign = connection_hashsign(Params#server_key_params.hashsign, State),
case HashSign of
- {_, anon} ->
+ {_, SignAlgo} when SignAlgo == anon; SignAlgo == ecdh_anon ->
server_master_secret(Params#server_key_params.params, State);
_ ->
verify_server_key(Params, HashSign, State)
@@ -1659,7 +2047,28 @@ verify_server_key(#server_key_params{params = Params,
server_master_secret(#server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDhKey},
State) ->
- dh_master_secret(P, G, ServerPublicDhKey, undefined, State).
+ dh_master_secret(P, G, ServerPublicDhKey, undefined, State);
+
+server_master_secret(#server_ecdh_params{curve = ECCurve, public = ECServerPubKey},
+ State) ->
+ ECDHKeys = public_key:generate_key(ECCurve),
+ ec_dh_master_secret(ECDHKeys, #'ECPoint'{point = ECServerPubKey}, State#state{diffie_hellman_keys = ECDHKeys});
+
+server_master_secret(#server_psk_params{
+ hint = IdentityHint},
+ State) ->
+ %% store for later use
+ State#state{psk_identity = IdentityHint};
+
+server_master_secret(#server_dhe_psk_params{
+ hint = IdentityHint,
+ dh_params = #server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDhKey}},
+ State) ->
+ dhe_psk_master_secret(IdentityHint, P, G, ServerPublicDhKey, undefined, State);
+
+server_master_secret(#server_srp_params{srp_n = N, srp_g = G, srp_s = S, srp_b = B},
+ State) ->
+ client_srp_master_secret(G, N, S, B, undefined, State).
master_from_premaster_secret(PremasterSecret,
#state{session = Session,
@@ -1676,19 +2085,147 @@ master_from_premaster_secret(PremasterSecret,
Alert
end.
+dh_master_secret(#'DHParameter'{} = Params, OtherPublicDhKey, MyPrivateKey, State) ->
+ PremasterSecret =
+ public_key:compute_key(OtherPublicDhKey, MyPrivateKey, Params),
+ master_from_premaster_secret(PremasterSecret, State).
+
dh_master_secret(Prime, Base, PublicDhKey, undefined, State) ->
- PMpint = mpint_binary(Prime),
- GMpint = mpint_binary(Base),
- Keys = {_, PrivateDhKey} =
- crypto:dh_generate_key([PMpint,GMpint]),
- dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys});
+ Keys = {_, PrivateDhKey} = crypto:generate_key(dh, [Prime, Base]),
+ dh_master_secret(Prime, Base, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys});
-dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State) ->
+dh_master_secret(Prime, Base, PublicDhKey, PrivateDhKey, State) ->
PremasterSecret =
- crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey,
- [PMpint, GMpint]),
+ crypto:compute_key(dh, PublicDhKey, PrivateDhKey, [Prime, Base]),
master_from_premaster_secret(PremasterSecret, State).
+ec_dh_master_secret(ECDHKeys, ECPoint, State) ->
+ PremasterSecret =
+ public_key:compute_key(ECPoint, ECDHKeys),
+ master_from_premaster_secret(PremasterSecret, State).
+
+handle_psk_identity(_PSKIdentity, LookupFun)
+ when LookupFun == undefined ->
+ error;
+handle_psk_identity(PSKIdentity, {Fun, UserState}) ->
+ Fun(psk, PSKIdentity, UserState).
+
+server_psk_master_secret(ClientPSKIdentity,
+ #state{ssl_options = SslOpts} = State) ->
+ case handle_psk_identity(ClientPSKIdentity, SslOpts#ssl_options.user_lookup_fun) of
+ {ok, PSK} when is_binary(PSK) ->
+ Len = byte_size(PSK),
+ PremasterSecret = <<?UINT16(Len), 0:(Len*8), ?UINT16(Len), PSK/binary>>,
+ master_from_premaster_secret(PremasterSecret, State);
+ #alert{} = Alert ->
+ Alert;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end.
+
+dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, undefined, State) ->
+ Keys = {_, PrivateDhKey} =
+ crypto:generate_key(dh, [Prime, Base]),
+ dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, PrivateDhKey,
+ State#state{diffie_hellman_keys = Keys});
+
+dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, PrivateDhKey,
+ #state{ssl_options = SslOpts} = State) ->
+ case handle_psk_identity(PSKIdentity, SslOpts#ssl_options.user_lookup_fun) of
+ {ok, PSK} when is_binary(PSK) ->
+ DHSecret =
+ crypto:compute_key(dh, PublicDhKey, PrivateDhKey,
+ [Prime, Base]),
+ DHLen = erlang:byte_size(DHSecret),
+ Len = erlang:byte_size(PSK),
+ PremasterSecret = <<?UINT16(DHLen), DHSecret/binary, ?UINT16(Len), PSK/binary>>,
+ master_from_premaster_secret(PremasterSecret, State);
+ #alert{} = Alert ->
+ Alert;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end.
+
+server_rsa_psk_master_secret(PskIdentity, PremasterSecret,
+ #state{ssl_options = SslOpts} = State) ->
+ case handle_psk_identity(PskIdentity, SslOpts#ssl_options.user_lookup_fun) of
+ {ok, PSK} when is_binary(PSK) ->
+ Len = byte_size(PSK),
+ RealPMS = <<?UINT16(48), PremasterSecret/binary, ?UINT16(Len), PSK/binary>>,
+ master_from_premaster_secret(RealPMS, State);
+ #alert{} = Alert ->
+ Alert;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end.
+
+generate_srp_server_keys(_SrpParams, 10) ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+generate_srp_server_keys(SrpParams =
+ #srp_user{generator = Generator, prime = Prime,
+ verifier = Verifier}, N) ->
+ case crypto:generate_key(srp, {host, [Verifier, Generator, Prime, '6a']}) of
+ error ->
+ generate_srp_server_keys(SrpParams, N+1);
+ Keys ->
+ Keys
+ end.
+
+generate_srp_client_keys(_Generator, _Prime, 10) ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+generate_srp_client_keys(Generator, Prime, N) ->
+
+ case crypto:generate_key(srp, {user, [Generator, Prime, '6a']}) of
+ error ->
+ generate_srp_client_keys(Generator, Prime, N+1);
+ Keys ->
+ Keys
+ end.
+
+handle_srp_identity(Username, {Fun, UserState}) ->
+ case Fun(srp, Username, UserState) of
+ {ok, {SRPParams, Salt, DerivedKey}}
+ when is_atom(SRPParams), is_binary(Salt), is_binary(DerivedKey) ->
+ {Generator, Prime} = ssl_srp_primes:get_srp_params(SRPParams),
+ Verifier = crypto:mod_pow(Generator, DerivedKey, Prime),
+ #srp_user{generator = Generator, prime = Prime,
+ salt = Salt, verifier = Verifier};
+ #alert{} = Alert ->
+ throw(Alert);
+ _ ->
+ throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER))
+ end.
+
+server_srp_master_secret(Verifier, Prime, ClientPub, State = #state{srp_keys = ServerKeys}) ->
+ case crypto:compute_key(srp, ClientPub, ServerKeys, {host, [Verifier, Prime, '6a']}) of
+ error ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+ PremasterSecret ->
+ master_from_premaster_secret(PremasterSecret, State)
+ end.
+
+client_srp_master_secret(_Generator, _Prime, _Salt, _ServerPub, #alert{} = Alert, _State) ->
+ Alert;
+client_srp_master_secret(Generator, Prime, Salt, ServerPub, undefined, State) ->
+ Keys = generate_srp_client_keys(Generator, Prime, 0),
+ client_srp_master_secret(Generator, Prime, Salt, ServerPub, Keys, State#state{srp_keys = Keys});
+
+client_srp_master_secret(Generator, Prime, Salt, ServerPub, ClientKeys,
+ #state{ssl_options = SslOpts} = State) ->
+ case ssl_srp_primes:check_srp_params(Generator, Prime) of
+ ok ->
+ {Username, Password} = SslOpts#ssl_options.srp_identity,
+ DerivedKey = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, Password])]),
+ case crypto:compute_key(srp, ServerPub, ClientKeys, {user, [DerivedKey, Prime, Generator, '6a']}) of
+ error ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+ PremasterSecret ->
+ master_from_premaster_secret(PremasterSecret, State)
+ end;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end.
+
cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0} = State) ->
ConnectionStates = ssl_record:set_server_verify_data(current_both, Data, ConnectionStates0),
next_state_connection(cipher, ack_connection(State#state{session = Session,
@@ -2349,11 +2886,6 @@ make_premaster_secret({MajVer, MinVer}, rsa) ->
make_premaster_secret(_, _) ->
undefined.
-mpint_binary(Binary) ->
- Size = erlang:byte_size(Binary),
- <<?UINT32(Size), Binary/binary>>.
-
-
ack_connection(#state{renegotiation = {true, Initiater}} = State)
when Initiater == internal;
Initiater == peer ->
@@ -2488,19 +3020,34 @@ default_hashsign(_Version = {Major, Minor}, KeyExchange)
when Major == 3 andalso Minor >= 3 andalso
(KeyExchange == rsa orelse
KeyExchange == dhe_rsa orelse
- KeyExchange == dh_rsa) ->
+ KeyExchange == dh_rsa orelse
+ KeyExchange == ecdhe_rsa orelse
+ KeyExchange == srp_rsa) ->
{sha, rsa};
default_hashsign(_Version, KeyExchange)
when KeyExchange == rsa;
KeyExchange == dhe_rsa;
- KeyExchange == dh_rsa ->
+ KeyExchange == dh_rsa;
+ KeyExchange == ecdhe_rsa;
+ KeyExchange == srp_rsa ->
{md5sha, rsa};
default_hashsign(_Version, KeyExchange)
+ when KeyExchange == ecdhe_ecdsa;
+ KeyExchange == ecdh_ecdsa;
+ KeyExchange == ecdh_rsa ->
+ {sha, ecdsa};
+default_hashsign(_Version, KeyExchange)
when KeyExchange == dhe_dss;
- KeyExchange == dh_dss ->
+ KeyExchange == dh_dss;
+ KeyExchange == srp_dss ->
{sha, dsa};
default_hashsign(_Version, KeyExchange)
- when KeyExchange == dh_anon ->
+ when KeyExchange == dh_anon;
+ KeyExchange == ecdh_anon;
+ KeyExchange == psk;
+ KeyExchange == dhe_psk;
+ KeyExchange == rsa_psk;
+ KeyExchange == srp_anon ->
{null, anon}.
start_or_recv_cancel_timer(infinity, _RecvFrom) ->
@@ -2531,3 +3078,8 @@ handle_close_alert(Data, StateName, State0) ->
_ ->
ok
end.
+
+select_curve(#state{client_ecc = {[Curve|_], _}}) ->
+ {namedCurve, Curve};
+select_curve(_) ->
+ {namedCurve, ?secp256k1}.
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 1929370991..24ea86311f 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,9 +28,10 @@
-include("ssl_cipher.hrl").
-include("ssl_alert.hrl").
-include("ssl_internal.hrl").
+-include("ssl_srp.hrl").
-include_lib("public_key/include/public_key.hrl").
--export([master_secret/4, client_hello/8, server_hello/5, hello/4,
+-export([master_secret/4, client_hello/8, server_hello/7, hello/4,
hello_request/0, certify/7, certificate/4,
client_certificate_verify/6, certificate_verify/6, verify_signature/5,
certificate_request/3, key_exchange/3, server_key_exchange_hash/2,
@@ -46,6 +47,8 @@
#client_key_exchange{} | #finished{} | #certificate_verify{} |
#hello_request{} | #next_protocol{}.
+-define(NAMED_CURVE_TYPE, 3).
+
%%====================================================================
%% Internal application API
%%====================================================================
@@ -61,14 +64,12 @@ client_hello(Host, Port, ConnectionStates,
ciphers = UserSuites
} = SslOpts,
Cache, CacheCb, Renegotiation, OwnCert) ->
-
- Fun = fun(Version) ->
- ssl_record:protocol_version(Version)
- end,
- Version = ssl_record:highest_protocol_version(lists:map(Fun, Versions)),
+ Version = ssl_record:highest_protocol_version(Versions),
Pending = ssl_record:pending_connection_state(ConnectionStates, read),
SecParams = Pending#connection_state.security_parameters,
Ciphers = available_suites(UserSuites, Version),
+ SRP = srp_user(SslOpts),
+ {EcPointFormats, EllipticCurves} = default_ecc_extensions(Version),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
@@ -80,7 +81,10 @@ client_hello(Host, Port, ConnectionStates,
renegotiation_info =
renegotiation_info(client, ConnectionStates, Renegotiation),
+ srp = SRP,
hash_signs = default_hash_signs(),
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation =
encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector, Renegotiation)
}.
@@ -97,11 +101,14 @@ encode_protocols_advertised_on_server(Protocols) ->
%%--------------------------------------------------------------------
-spec server_hello(session_id(), tls_version(), #connection_states{},
- boolean(), [binary()] | undefined) -> #server_hello{}.
+ boolean(), [binary()] | undefined,
+ #ec_point_formats{} | undefined,
+ #elliptic_curves{} | undefined) -> #server_hello{}.
%%
%% Description: Creates a server hello message.
%%--------------------------------------------------------------------
-server_hello(SessionId, Version, ConnectionStates, Renegotiation, ProtocolsAdvertisedOnServer) ->
+server_hello(SessionId, Version, ConnectionStates, Renegotiation,
+ ProtocolsAdvertisedOnServer, EcPointFormats, EllipticCurves) ->
Pending = ssl_record:pending_connection_state(ConnectionStates, read),
SecParams = Pending#connection_state.security_parameters,
#server_hello{server_version = Version,
@@ -112,6 +119,8 @@ server_hello(SessionId, Version, ConnectionStates, Renegotiation, ProtocolsAdver
session_id = SessionId,
renegotiation_info =
renegotiation_info(server, ConnectionStates, Renegotiation),
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = encode_protocols_advertised_on_server(ProtocolsAdvertisedOnServer)
}.
@@ -130,7 +139,8 @@ hello_request() ->
atom(), #connection_states{}, binary()},
boolean()) ->
{tls_version(), session_id(), #connection_states{}, binary() | undefined}|
- {tls_version(), {resumed | new, #session{}}, #connection_states{}, list(binary()) | undefined} |
+ {tls_version(), {resumed | new, #session{}}, #connection_states{}, [binary()] | undefined,
+ [oid()] | undefined, [oid()] | undefined} |
#alert{}.
%%
%% Description: Handles a recieved hello message
@@ -139,10 +149,11 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version,
compression_method = Compression, random = Random,
session_id = SessionId, renegotiation_info = Info,
hash_signs = _HashSigns} = Hello,
- #ssl_options{secure_renegotiate = SecureRenegotation, next_protocol_selector = NextProtocolSelector},
+ #ssl_options{secure_renegotiate = SecureRenegotation, next_protocol_selector = NextProtocolSelector,
+ versions = SupportedVersions},
ConnectionStates0, Renegotiation) ->
%%TODO: select hash and signature algorigthm
- case ssl_record:is_acceptable_version(Version) of
+ case ssl_record:is_acceptable_version(Version, SupportedVersions) of
true ->
case handle_renegotiation_info(client, Info, ConnectionStates0,
Renegotiation, SecureRenegotation, []) of
@@ -163,42 +174,27 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version,
?ALERT_REC(?FATAL, ?PROTOCOL_VERSION)
end;
-hello(#client_hello{client_version = ClientVersion, random = Random,
- cipher_suites = CipherSuites,
- renegotiation_info = Info} = Hello,
- #ssl_options{versions = Versions,
- secure_renegotiate = SecureRenegotation} = SslOpts,
+hello(#client_hello{client_version = ClientVersion} = Hello,
+ #ssl_options{versions = Versions} = SslOpts,
{Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) ->
-%% TODO: select hash and signature algorithm
+ %% TODO: select hash and signature algorithm
Version = select_version(ClientVersion, Versions),
- case ssl_record:is_acceptable_version(Version) of
+ case ssl_record:is_acceptable_version(Version, Versions) of
true ->
- {Type, #session{cipher_suite = CipherSuite,
- compression_method = Compression} = Session}
+ %% TODO: need to take supported Curves into Account when selecting the CipherSuite....
+ %% if whe have an ECDSA cert with an unsupported curve, we need to drop ECDSA ciphers
+ {Type, #session{cipher_suite = CipherSuite} = Session1}
= select_session(Hello, Port, Session0, Version,
SslOpts, Cache, CacheCb, Cert),
case CipherSuite of
no_suite ->
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY);
_ ->
- case handle_renegotiation_info(server, Info, ConnectionStates0,
- Renegotiation, SecureRenegotation,
- CipherSuites) of
- {ok, ConnectionStates1} ->
- ConnectionStates =
- hello_pending_connection_states(server,
- Version,
- CipherSuite,
- Random,
- Compression,
- ConnectionStates1),
- case handle_next_protocol_on_server(Hello, Renegotiation, SslOpts) of
- #alert{} = Alert ->
- Alert;
- ProtocolsToAdvertise ->
- {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise}
- end;
- #alert{} = Alert ->
+ try handle_hello_extensions(Hello, Version, SslOpts, Session1, ConnectionStates0, Renegotiation) of
+ {Session, ConnectionStates, ProtocolsToAdvertise, ECPointFormats, EllipticCurves} ->
+ {Version, {Type, Session}, ConnectionStates,
+ ProtocolsToAdvertise, ECPointFormats, EllipticCurves}
+ catch throw:Alert ->
Alert
end
end;
@@ -348,9 +344,10 @@ verify_signature(_Version, Hash, _HashAlgo, Signature, {?rsaEncryption, PubKey,
_ -> false
end;
verify_signature(_Version, Hash, {HashAlgo, dsa}, Signature, {?'id-dsa', PublicKey, PublicKeyParams}) ->
+ public_key:verify({digest, Hash}, HashAlgo, Signature, {PublicKey, PublicKeyParams});
+verify_signature(_Version, Hash, {HashAlgo, ecdsa}, Signature, {?'id-ecPublicKey', PublicKey, PublicKeyParams}) ->
public_key:verify({digest, Hash}, HashAlgo, Signature, {PublicKey, PublicKeyParams}).
-
%%--------------------------------------------------------------------
-spec certificate_request(#connection_states{}, db_handle(), certdb_ref()) ->
#certificate_request{}.
@@ -375,6 +372,11 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) ->
{premaster_secret, binary(), public_key_info()} |
{dh, binary()} |
{dh, {binary(), binary()}, #'DHParameter'{}, {HashAlgo::atom(), SignAlgo::atom()},
+ binary(), binary(), private_key()} |
+ {ecdh, #'ECPrivateKey'{}} |
+ {psk, binary()} |
+ {dhe_psk, binary(), binary()} |
+ {srp, {binary(), binary()}, #srp_user{}, {HashAlgo::atom(), SignAlgo::atom()},
binary(), binary(), private_key()}) ->
#client_key_exchange{} | #server_key_exchange{}.
%%
@@ -385,20 +387,84 @@ key_exchange(client, _Version, {premaster_secret, Secret, {_, PublicKey, _}}) ->
encrypted_premaster_secret(Secret, PublicKey),
#client_key_exchange{exchange_keys = EncPremasterSecret};
-key_exchange(client, _Version, {dh, <<?UINT32(Len), PublicKey:Len/binary>>}) ->
+key_exchange(client, _Version, {dh, PublicKey}) ->
#client_key_exchange{
exchange_keys = #client_diffie_hellman_public{
dh_public = PublicKey}
};
-key_exchange(server, Version, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
- #'DHParameter'{prime = P, base = G},
- HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
- <<?UINT32(_), PBin/binary>> = crypto:mpint(P),
- <<?UINT32(_), GBin/binary>> = crypto:mpint(G),
- ServerDHParams = #server_dh_params{dh_p = PBin,
- dh_g = GBin, dh_y = PublicKey},
+key_exchange(client, _Version, {ecdh, #'ECPrivateKey'{publicKey = {0, ECPublicKey}}}) ->
+ #client_key_exchange{
+ exchange_keys = #client_ec_diffie_hellman_public{
+ dh_public = ECPublicKey}
+ };
+
+key_exchange(client, _Version, {psk, Identity}) ->
+ #client_key_exchange{
+ exchange_keys = #client_psk_identity{
+ identity = Identity}
+ };
+
+key_exchange(client, _Version, {dhe_psk, Identity, PublicKey}) ->
+ #client_key_exchange{
+ exchange_keys = #client_dhe_psk_identity{
+ identity = Identity,
+ dh_public = PublicKey}
+ };
+
+key_exchange(client, _Version, {psk_premaster_secret, PskIdentity, Secret, {_, PublicKey, _}}) ->
+ EncPremasterSecret =
+ encrypted_premaster_secret(Secret, PublicKey),
+ #client_key_exchange{
+ exchange_keys = #client_rsa_psk_identity{
+ identity = PskIdentity,
+ exchange_keys = EncPremasterSecret}};
+
+key_exchange(client, _Version, {srp, PublicKey}) ->
+ #client_key_exchange{
+ exchange_keys = #client_srp_public{
+ srp_a = PublicKey}
+ };
+
+key_exchange(server, Version, {dh, {PublicKey, _},
+ #'DHParameter'{prime = P, base = G},
+ HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
+ ServerDHParams = #server_dh_params{dh_p = int_to_bin(P),
+ dh_g = int_to_bin(G), dh_y = PublicKey},
enc_server_key_exchange(Version, ServerDHParams, HashSign,
+ ClientRandom, ServerRandom, PrivateKey);
+
+key_exchange(server, Version, {ecdh, #'ECPrivateKey'{publicKey = {0, ECPublicKey},
+ parameters = ECCurve}, HashSign, ClientRandom, ServerRandom,
+ PrivateKey}) ->
+ ServerECParams = #server_ecdh_params{curve = ECCurve, public = ECPublicKey},
+ enc_server_key_exchange(Version, ServerECParams, HashSign,
+ ClientRandom, ServerRandom, PrivateKey);
+
+key_exchange(server, Version, {psk, PskIdentityHint,
+ HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
+ ServerPSKParams = #server_psk_params{hint = PskIdentityHint},
+ enc_server_key_exchange(Version, ServerPSKParams, HashSign,
+ ClientRandom, ServerRandom, PrivateKey);
+
+key_exchange(server, Version, {dhe_psk, PskIdentityHint, {PublicKey, _},
+ #'DHParameter'{prime = P, base = G},
+ HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
+ ServerEDHPSKParams = #server_dhe_psk_params{
+ hint = PskIdentityHint,
+ dh_params = #server_dh_params{dh_p = int_to_bin(P),
+ dh_g = int_to_bin(G), dh_y = PublicKey}
+ },
+ enc_server_key_exchange(Version, ServerEDHPSKParams,
+ HashSign, ClientRandom, ServerRandom, PrivateKey);
+
+key_exchange(server, Version, {srp, {PublicKey, _},
+ #srp_user{generator = Generator, prime = Prime,
+ salt = Salt},
+ HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
+ ServerSRPParams = #server_srp_params{srp_n = Prime, srp_g = Generator,
+ srp_s = Salt, srp_b = PublicKey},
+ enc_server_key_exchange(Version, ServerSRPParams, HashSign,
ClientRandom, ServerRandom, PrivateKey).
enc_server_key_exchange(Version, Params, {HashAlgo, SignAlgo},
@@ -528,7 +594,13 @@ get_tls_handshake(Version, Data, Buffer) ->
%%--------------------------------------------------------------------
-spec decode_client_key(binary(), key_algo(), tls_version()) ->
- #encrypted_premaster_secret{} | #client_diffie_hellman_public{}.
+ #encrypted_premaster_secret{}
+ | #client_diffie_hellman_public{}
+ | #client_ec_diffie_hellman_public{}
+ | #client_psk_identity{}
+ | #client_dhe_psk_identity{}
+ | #client_rsa_psk_identity{}
+ | #client_srp_public{}.
%%
%% Description: Decode client_key data and return appropriate type
%%--------------------------------------------------------------------
@@ -595,8 +667,8 @@ decrypt_premaster_secret(Secret, RSAPrivateKey) ->
%% Description: Calculate server key exchange hash
%%--------------------------------------------------------------------
server_key_exchange_hash(md5sha, Value) ->
- MD5 = crypto:md5(Value),
- SHA = crypto:sha(Value),
+ MD5 = crypto:hash(md5, Value),
+ SHA = crypto:hash(sha, Value),
<<MD5/binary, SHA/binary>>;
server_key_exchange_hash(Hash, Value) ->
@@ -680,6 +752,11 @@ cipher_suites(Suites, false) ->
cipher_suites(Suites, true) ->
Suites.
+srp_user(#ssl_options{srp_identity = {UserName, _}}) ->
+ #srp{username = UserName};
+srp_user(_) ->
+ undefined.
+
renegotiation_info(client, _, false) ->
#renegotiation_info{renegotiated_connection = undefined};
renegotiation_info(server, ConnectionStates, false) ->
@@ -762,6 +839,38 @@ select_next_protocol(Protocols, NextProtocolSelector) ->
Protocol
end.
+default_ecc_extensions(Version) ->
+ CryptoSupport = proplists:get_value(public_keys, crypto:supports()),
+ case proplists:get_bool(ecdh, CryptoSupport) of
+ true ->
+ EcPointFormats = #ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]},
+ EllipticCurves = #elliptic_curves{elliptic_curve_list = ssl_tls1:ecc_curves(Version)},
+ {EcPointFormats, EllipticCurves};
+ _ ->
+ {undefined, undefined}
+ end.
+
+handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0) ->
+ CryptoSupport = proplists:get_value(public_keys, crypto:supports()),
+ case proplists:get_bool(ecdh, CryptoSupport) of
+ true ->
+ EcPointFormats1 = handle_ecc_point_fmt_extension(EcPointFormats0),
+ EllipticCurves1 = handle_ecc_curves_extension(Version, EllipticCurves0),
+ {EcPointFormats1, EllipticCurves1};
+ _ ->
+ {undefined, undefined}
+ end.
+
+handle_ecc_point_fmt_extension(undefined) ->
+ undefined;
+handle_ecc_point_fmt_extension(_) ->
+ #ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]}.
+
+handle_ecc_curves_extension(Version, undefined) ->
+ undefined;
+handle_ecc_curves_extension(Version, _) ->
+ #elliptic_curves{elliptic_curve_list = ssl_tls1:ecc_curves(Version)}.
+
handle_renegotiation_info(_, #renegotiation_info{renegotiated_connection = ?byte(0)},
ConnectionStates, false, _, _) ->
{ok, ssl_record:set_renegotiation_flag(true, ConnectionStates)};
@@ -869,11 +978,7 @@ hello_security_parameters(server, Version, ConnectionState, CipherSuite, Random,
}.
select_version(ClientVersion, Versions) ->
- Fun = fun(Version) ->
- ssl_record:protocol_version(Version)
- end,
- ServerVersion = ssl_record:highest_protocol_version(lists:map(Fun,
- Versions)),
+ ServerVersion = ssl_record:highest_protocol_version(Versions),
ssl_record:lowest_protocol_version(ClientVersion, ServerVersion).
select_cipher_suite([], _) ->
@@ -948,7 +1053,10 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
DecodedExtensions = dec_hello_extensions(Extensions),
RenegotiationInfo = proplists:get_value(renegotiation_info, DecodedExtensions, undefined),
+ SRP = proplists:get_value(srp, DecodedExtensions, undefined),
HashSigns = proplists:get_value(hash_signs, DecodedExtensions, undefined),
+ EllipticCurves = proplists:get_value(elliptic_curves, DecodedExtensions,
+ undefined),
NextProtocolNegotiation = proplists:get_value(next_protocol_negotiation, DecodedExtensions, undefined),
#client_hello{
@@ -958,7 +1066,9 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
cipher_suites = from_2bytes(CipherSuites),
compression_methods = Comp_methods,
renegotiation_info = RenegotiationInfo,
+ srp = SRP,
hash_signs = HashSigns,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation
};
@@ -972,7 +1082,8 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
cipher_suite = Cipher_suite,
compression_method = Comp_method,
renegotiation_info = undefined,
- hash_signs = undefined};
+ hash_signs = undefined,
+ elliptic_curves = undefined};
dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID:SID_length/binary,
@@ -984,6 +1095,8 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
undefined),
HashSigns = proplists:get_value(hash_signs, HelloExtensions,
undefined),
+ EllipticCurves = proplists:get_value(elliptic_curves, HelloExtensions,
+ undefined),
NextProtocolNegotiation = proplists:get_value(next_protocol_negotiation, HelloExtensions, undefined),
#server_hello{
@@ -994,6 +1107,7 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
compression_method = Comp_method,
renegotiation_info = RenegotiationInfo,
hash_signs = HashSigns,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation};
dec_hs(_Version, ?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>) ->
#certificate{asn1_certificates = certs_to_list(ASN1Certs)};
@@ -1036,7 +1150,28 @@ dec_client_key(<<>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
throw(?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE));
dec_client_key(<<?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>,
?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
- #client_diffie_hellman_public{dh_public = DH_Y}.
+ #client_diffie_hellman_public{dh_public = DH_Y};
+dec_client_key(<<>>, ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, _) ->
+ throw(?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE));
+dec_client_key(<<?BYTE(DH_YLen), DH_Y:DH_YLen/binary>>,
+ ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, _) ->
+ #client_ec_diffie_hellman_public{dh_public = DH_Y};
+dec_client_key(<<?UINT16(Len), Id:Len/binary>>,
+ ?KEY_EXCHANGE_PSK, _) ->
+ #client_psk_identity{identity = Id};
+dec_client_key(<<?UINT16(Len), Id:Len/binary,
+ ?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>,
+ ?KEY_EXCHANGE_DHE_PSK, _) ->
+ #client_dhe_psk_identity{identity = Id, dh_public = DH_Y};
+dec_client_key(<<?UINT16(Len), Id:Len/binary, PKEPMS/binary>>,
+ ?KEY_EXCHANGE_RSA_PSK, {3, 0}) ->
+ #client_rsa_psk_identity{identity = Id, exchange_keys = #encrypted_premaster_secret{premaster_secret = PKEPMS}};
+dec_client_key(<<?UINT16(Len), Id:Len/binary, ?UINT16(_), PKEPMS/binary>>,
+ ?KEY_EXCHANGE_RSA_PSK, _) ->
+ #client_rsa_psk_identity{identity = Id, exchange_keys = #encrypted_premaster_secret{premaster_secret = PKEPMS}};
+dec_client_key(<<?UINT16(ALen), A:ALen/binary>>,
+ ?KEY_EXCHANGE_SRP, _) ->
+ #client_srp_public{srp_a = A}.
dec_ske_params(Len, Keys, Version) ->
<<Params:Len/bytes, Signature/binary>> = Keys,
@@ -1071,6 +1206,54 @@ dec_server_key(<<?UINT16(PLen), P:PLen/binary,
params_bin = BinMsg,
hashsign = HashSign,
signature = Signature};
+%% ECParameters with named_curve
+%% TODO: explicit curve
+dec_server_key(<<?BYTE(?NAMED_CURVE), ?UINT16(CurveID),
+ ?BYTE(PointLen), ECPoint:PointLen/binary,
+ _/binary>> = KeyStruct,
+ ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, Version) ->
+ Params = #server_ecdh_params{curve = {namedCurve, ssl_tls1:enum_to_oid(CurveID)},
+ public = ECPoint},
+ {BinMsg, HashSign, Signature} = dec_ske_params(PointLen + 4, KeyStruct, Version),
+ #server_key_params{params = Params,
+ params_bin = BinMsg,
+ hashsign = HashSign,
+ signature = Signature};
+dec_server_key(<<?UINT16(Len), PskIdentityHint:Len/binary>> = KeyStruct,
+ KeyExchange, Version)
+ when KeyExchange == ?KEY_EXCHANGE_PSK; KeyExchange == ?KEY_EXCHANGE_RSA_PSK ->
+ Params = #server_psk_params{
+ hint = PskIdentityHint},
+ {BinMsg, HashSign, Signature} = dec_ske_params(Len + 2, KeyStruct, Version),
+ #server_key_params{params = Params,
+ params_bin = BinMsg,
+ hashsign = HashSign,
+ signature = Signature};
+dec_server_key(<<?UINT16(Len), IdentityHint:Len/binary,
+ ?UINT16(PLen), P:PLen/binary,
+ ?UINT16(GLen), G:GLen/binary,
+ ?UINT16(YLen), Y:YLen/binary, _/binary>> = KeyStruct,
+ ?KEY_EXCHANGE_DHE_PSK, Version) ->
+ DHParams = #server_dh_params{dh_p = P, dh_g = G, dh_y = Y},
+ Params = #server_dhe_psk_params{
+ hint = IdentityHint,
+ dh_params = DHParams},
+ {BinMsg, HashSign, Signature} = dec_ske_params(Len + PLen + GLen + YLen + 8, KeyStruct, Version),
+ #server_key_params{params = Params,
+ params_bin = BinMsg,
+ hashsign = HashSign,
+ signature = Signature};
+dec_server_key(<<?UINT16(NLen), N:NLen/binary,
+ ?UINT16(GLen), G:GLen/binary,
+ ?BYTE(SLen), S:SLen/binary,
+ ?UINT16(BLen), B:BLen/binary, _/binary>> = KeyStruct,
+ ?KEY_EXCHANGE_SRP, Version) ->
+ Params = #server_srp_params{srp_n = N, srp_g = G, srp_s = S, srp_b = B},
+ {BinMsg, HashSign, Signature} = dec_ske_params(NLen + GLen + SLen + BLen + 7, KeyStruct, Version),
+ #server_key_params{params = Params,
+ params_bin = BinMsg,
+ hashsign = HashSign,
+ signature = Signature};
dec_server_key(_, _, _) ->
throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)).
@@ -1098,6 +1281,11 @@ dec_hello_extensions(<<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), Info:Len/binar
dec_hello_extensions(Rest, [{renegotiation_info,
#renegotiation_info{renegotiated_connection = RenegotiateInfo}} | Acc]);
+dec_hello_extensions(<<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen), SRP:SRPLen/binary, Rest/binary>>, Acc)
+ when Len == SRPLen + 2 ->
+ dec_hello_extensions(Rest, [{srp,
+ #srp{username = SRP}} | Acc]);
+
dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len),
ExtData:Len/binary, Rest/binary>>, Acc) ->
SignAlgoListLen = Len - 2,
@@ -1107,6 +1295,22 @@ dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len),
dec_hello_extensions(Rest, [{hash_signs,
#hash_sign_algos{hash_sign_algos = HashSignAlgos}} | Acc]);
+dec_hello_extensions(<<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Acc) ->
+ EllipticCurveListLen = Len - 2,
+ <<?UINT16(EllipticCurveListLen), EllipticCurveList/binary>> = ExtData,
+ EllipticCurves = [ssl_tls1:enum_to_oid(X) || <<X:16>> <= EllipticCurveList],
+ dec_hello_extensions(Rest, [{elliptic_curves,
+ #elliptic_curves{elliptic_curve_list = EllipticCurves}} | Acc]);
+
+dec_hello_extensions(<<?UINT16(?EC_POINT_FORMATS_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Acc) ->
+ ECPointFormatListLen = Len - 1,
+ <<?BYTE(ECPointFormatListLen), ECPointFormatList/binary>> = ExtData,
+ ECPointFormats = binary_to_list(ECPointFormatList),
+ dec_hello_extensions(Rest, [{ec_point_formats,
+ #ec_point_formats{ec_point_format_list = ECPointFormats}} | Acc]);
+
%% Ignore data following the ClientHello (i.e.,
%% extensions) if not understood.
@@ -1155,14 +1359,19 @@ enc_hs(#client_hello{client_version = {Major, Minor},
cipher_suites = CipherSuites,
compression_methods = CompMethods,
renegotiation_info = RenegotiationInfo,
+ srp = SRP,
hash_signs = HashSigns,
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation}, _Version) ->
SIDLength = byte_size(SessionID),
BinCompMethods = list_to_binary(CompMethods),
CmLength = byte_size(BinCompMethods),
BinCipherSuites = list_to_binary(CipherSuites),
CsLength = byte_size(BinCipherSuites),
- Extensions0 = hello_extensions(RenegotiationInfo, NextProtocolNegotiation),
+ Extensions0 = hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation)
+ ++ ec_hello_extensions(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites), EcPointFormats)
+ ++ ec_hello_extensions(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites), EllipticCurves),
Extensions1 = if
Major == 3, Minor >=3 -> Extensions0 ++ hello_extensions(HashSigns);
true -> Extensions0
@@ -1177,16 +1386,21 @@ enc_hs(#client_hello{client_version = {Major, Minor},
enc_hs(#server_hello{server_version = {Major, Minor},
random = Random,
session_id = Session_ID,
- cipher_suite = Cipher_suite,
+ cipher_suite = CipherSuite,
compression_method = Comp_method,
renegotiation_info = RenegotiationInfo,
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation}, _Version) ->
SID_length = byte_size(Session_ID),
- Extensions = hello_extensions(RenegotiationInfo, NextProtocolNegotiation),
+ CipherSuites = [ssl_cipher:suite_definition(CipherSuite)],
+ Extensions = hello_extensions(RenegotiationInfo, NextProtocolNegotiation)
+ ++ ec_hello_extensions(CipherSuites, EcPointFormats)
+ ++ ec_hello_extensions(CipherSuites, EllipticCurves),
ExtensionsBin = enc_hello_extensions(Extensions),
{?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID/binary,
- Cipher_suite/binary, ?BYTE(Comp_method), ExtensionsBin/binary>>};
+ CipherSuite/binary, ?BYTE(Comp_method), ExtensionsBin/binary>>};
enc_hs(#certificate{asn1_certificates = ASN1CertList}, _Version) ->
ASN1Certs = certs_from_list(ASN1CertList),
ACLen = erlang:iolist_size(ASN1Certs),
@@ -1238,13 +1452,64 @@ enc_cke(#encrypted_premaster_secret{premaster_secret = PKEPMS}, _) ->
<<?UINT16(PKEPMSLen), PKEPMS/binary>>;
enc_cke(#client_diffie_hellman_public{dh_public = DHPublic}, _) ->
Len = byte_size(DHPublic),
- <<?UINT16(Len), DHPublic/binary>>.
+ <<?UINT16(Len), DHPublic/binary>>;
+enc_cke(#client_ec_diffie_hellman_public{dh_public = DHPublic}, _) ->
+ Len = byte_size(DHPublic),
+ <<?BYTE(Len), DHPublic/binary>>;
+enc_cke(#client_psk_identity{identity = undefined}, _) ->
+ Id = <<"psk_identity">>,
+ Len = byte_size(Id),
+ <<?UINT16(Len), Id/binary>>;
+enc_cke(#client_psk_identity{identity = Id}, _) ->
+ Len = byte_size(Id),
+ <<?UINT16(Len), Id/binary>>;
+enc_cke(Identity = #client_dhe_psk_identity{identity = undefined}, Version) ->
+ enc_cke(Identity#client_dhe_psk_identity{identity = <<"psk_identity">>}, Version);
+enc_cke(#client_dhe_psk_identity{identity = Id, dh_public = DHPublic}, _) ->
+ Len = byte_size(Id),
+ DHLen = byte_size(DHPublic),
+ <<?UINT16(Len), Id/binary, ?UINT16(DHLen), DHPublic/binary>>;
+enc_cke(Identity = #client_rsa_psk_identity{identity = undefined}, Version) ->
+ enc_cke(Identity#client_rsa_psk_identity{identity = <<"psk_identity">>}, Version);
+enc_cke(#client_rsa_psk_identity{identity = Id, exchange_keys = ExchangeKeys}, Version) ->
+ EncPMS = enc_cke(ExchangeKeys, Version),
+ Len = byte_size(Id),
+ <<?UINT16(Len), Id/binary, EncPMS/binary>>;
+enc_cke(#client_srp_public{srp_a = A}, _) ->
+ Len = byte_size(A),
+ <<?UINT16(Len), A/binary>>.
enc_server_key(#server_dh_params{dh_p = P, dh_g = G, dh_y = Y}) ->
PLen = byte_size(P),
GLen = byte_size(G),
YLen = byte_size(Y),
- <<?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>.
+ <<?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>;
+enc_server_key(#server_ecdh_params{curve = {namedCurve, ECCurve}, public = ECPubKey}) ->
+ %%TODO: support arbitrary keys
+ KLen = size(ECPubKey),
+ <<?BYTE(?NAMED_CURVE_TYPE), ?UINT16((ssl_tls1:oid_to_enum(ECCurve))),
+ ?BYTE(KLen), ECPubKey/binary>>;
+enc_server_key(#server_psk_params{hint = PskIdentityHint}) ->
+ Len = byte_size(PskIdentityHint),
+ <<?UINT16(Len), PskIdentityHint/binary>>;
+enc_server_key(Params = #server_dhe_psk_params{hint = undefined}) ->
+ enc_server_key(Params#server_dhe_psk_params{hint = <<>>});
+enc_server_key(#server_dhe_psk_params{
+ hint = PskIdentityHint,
+ dh_params = #server_dh_params{dh_p = P, dh_g = G, dh_y = Y}}) ->
+ Len = byte_size(PskIdentityHint),
+ PLen = byte_size(P),
+ GLen = byte_size(G),
+ YLen = byte_size(Y),
+ <<?UINT16(Len), PskIdentityHint/binary,
+ ?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>;
+enc_server_key(#server_srp_params{srp_n = N, srp_g = G, srp_s = S, srp_b = B}) ->
+ NLen = byte_size(N),
+ GLen = byte_size(G),
+ SLen = byte_size(S),
+ BLen = byte_size(B),
+ <<?UINT16(NLen), N/binary, ?UINT16(GLen), G/binary,
+ ?BYTE(SLen), S/binary, ?UINT16(BLen), B/binary>>.
enc_sign({_, anon}, _Sign, _Version) ->
<<>>;
@@ -1257,16 +1522,58 @@ enc_sign(_HashSign, Sign, _Version) ->
SignLen = byte_size(Sign),
<<?UINT16(SignLen), Sign/binary>>.
+
+ec_hello_extensions(CipherSuites, #elliptic_curves{} = Info) ->
+ case advertises_ec_ciphers(CipherSuites) of
+ true ->
+ [Info];
+ false ->
+ []
+ end;
+ec_hello_extensions(CipherSuites, #ec_point_formats{} = Info) ->
+ case advertises_ec_ciphers(CipherSuites) of
+ true ->
+ [Info];
+ false ->
+ []
+ end;
+ec_hello_extensions(_, undefined) ->
+ [].
+
hello_extensions(RenegotiationInfo, NextProtocolNegotiation) ->
hello_extensions(RenegotiationInfo) ++ next_protocol_extension(NextProtocolNegotiation).
+hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation) ->
+ hello_extensions(RenegotiationInfo)
+ ++ hello_extensions(SRP)
+ ++ next_protocol_extension(NextProtocolNegotiation).
+
+advertises_ec_ciphers([]) ->
+ false;
+advertises_ec_ciphers([{ecdh_ecdsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdhe_ecdsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdh_rsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdhe_rsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdh_anon, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([_| Rest]) ->
+ advertises_ec_ciphers(Rest).
+
%% Renegotiation info
hello_extensions(#renegotiation_info{renegotiated_connection = undefined}) ->
[];
hello_extensions(#renegotiation_info{} = Info) ->
[Info];
+hello_extensions(#srp{} = Info) ->
+ [Info];
hello_extensions(#hash_sign_algos{} = Info) ->
- [Info].
+ [Info];
+hello_extensions(undefined) ->
+ [].
next_protocol_extension(undefined) ->
[];
@@ -1292,7 +1599,22 @@ enc_hello_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest
InfoLen = byte_size(Info),
Len = InfoLen +1,
enc_hello_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), ?BYTE(InfoLen), Info/binary, Acc/binary>>);
-
+enc_hello_extensions([#elliptic_curves{elliptic_curve_list = EllipticCurves} | Rest], Acc) ->
+ EllipticCurveList = << <<(ssl_tls1:oid_to_enum(X)):16>> || X <- EllipticCurves>>,
+ ListLen = byte_size(EllipticCurveList),
+ Len = ListLen + 2,
+ enc_hello_extensions(Rest, <<?UINT16(?ELLIPTIC_CURVES_EXT),
+ ?UINT16(Len), ?UINT16(ListLen), EllipticCurveList/binary, Acc/binary>>);
+enc_hello_extensions([#ec_point_formats{ec_point_format_list = ECPointFormats} | Rest], Acc) ->
+ ECPointFormatList = list_to_binary(ECPointFormats),
+ ListLen = byte_size(ECPointFormatList),
+ Len = ListLen + 1,
+ enc_hello_extensions(Rest, <<?UINT16(?EC_POINT_FORMATS_EXT),
+ ?UINT16(Len), ?BYTE(ListLen), ECPointFormatList/binary, Acc/binary>>);
+enc_hello_extensions([#srp{username = UserName} | Rest], Acc) ->
+ SRPLen = byte_size(UserName),
+ Len = SRPLen + 2,
+ enc_hello_extensions(Rest, <<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen), UserName/binary, Acc/binary>>);
enc_hello_extensions([#hash_sign_algos{hash_sign_algos = HashSignAlgos} | Rest], Acc) ->
SignAlgoList = << <<(ssl_cipher:hash_algorithm(Hash)):8, (ssl_cipher:sign_algorithm(Sign)):8>> ||
{Hash, Sign} <- HashSignAlgos >>,
@@ -1327,9 +1649,15 @@ from_2bytes(<<?UINT16(N), Rest/binary>>, Acc) ->
certificate_types({KeyExchange, _, _, _})
when KeyExchange == rsa;
KeyExchange == dhe_dss;
- KeyExchange == dhe_rsa ->
+ KeyExchange == dhe_rsa;
+ KeyExchange == ecdhe_rsa ->
<<?BYTE(?RSA_SIGN), ?BYTE(?DSS_SIGN)>>;
+certificate_types({KeyExchange, _, _, _})
+ when KeyExchange == dh_ecdsa;
+ KeyExchange == dhe_ecdsa ->
+ <<?BYTE(?ECDSA_SIGN)>>;
+
certificate_types(_) ->
<<?BYTE(?RSA_SIGN)>>.
@@ -1346,9 +1674,6 @@ certificate_authorities(CertDbHandle, CertDbRef) ->
Enc = fun(#'OTPCertificate'{tbsCertificate=TBSCert}) ->
OTPSubj = TBSCert#'OTPTBSCertificate'.subject,
DNEncodedBin = public_key:pkix_encode('Name', OTPSubj, otp),
- %%Subj = public_key:pkix_transform(OTPSubj, encode),
- %% {ok, DNEncoded} = 'OTP-PUB-KEY':encode('Name', Subj),
- %% DNEncodedBin = iolist_to_binary(DNEncoded),
DNEncodedLen = byte_size(DNEncodedBin),
<<?UINT16(DNEncodedLen), DNEncodedBin/binary>>
end,
@@ -1369,7 +1694,9 @@ digitally_signed(_Version, Hash, HashAlgo, #'DSAPrivateKey'{} = Key) ->
public_key:sign({digest, Hash}, HashAlgo, Key);
digitally_signed(_Version, Hash, _HashAlgo, #'RSAPrivateKey'{} = Key) ->
public_key:encrypt_private(Hash, Key,
- [{rsa_pad, rsa_pkcs1_padding}]).
+ [{rsa_pad, rsa_pkcs1_padding}]);
+digitally_signed(_Version, Hash, HashAlgo, Key) ->
+ public_key:sign({digest, Hash}, HashAlgo, Key).
calc_master_secret({3,0}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) ->
ssl_ssl3:master_secret(PremasterSecret, ClientRandom, ServerRandom);
@@ -1402,6 +1729,19 @@ key_exchange_alg(rsa) ->
key_exchange_alg(Alg) when Alg == dhe_rsa; Alg == dhe_dss;
Alg == dh_dss; Alg == dh_rsa; Alg == dh_anon ->
?KEY_EXCHANGE_DIFFIE_HELLMAN;
+key_exchange_alg(Alg) when Alg == ecdhe_rsa; Alg == ecdh_rsa;
+ Alg == ecdhe_ecdsa; Alg == ecdh_ecdsa;
+ Alg == ecdh_anon ->
+ ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN;
+key_exchange_alg(psk) ->
+ ?KEY_EXCHANGE_PSK;
+key_exchange_alg(dhe_psk) ->
+ ?KEY_EXCHANGE_DHE_PSK;
+key_exchange_alg(rsa_psk) ->
+ ?KEY_EXCHANGE_RSA_PSK;
+key_exchange_alg(Alg)
+ when Alg == srp_rsa; Alg == srp_dss; Alg == srp_anon ->
+ ?KEY_EXCHANGE_SRP;
key_exchange_alg(_) ->
?NULL.
@@ -1417,15 +1757,71 @@ apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState) ->
-define(TLSEXT_SIGALG_RSA(MD), {MD, rsa}).
-define(TLSEXT_SIGALG_DSA(MD), {MD, dsa}).
+-define(TLSEXT_SIGALG_ECDSA(MD), {MD, ecdsa}).
--define(TLSEXT_SIGALG(MD), ?TLSEXT_SIGALG_RSA(MD)).
+-define(TLSEXT_SIGALG(MD), ?TLSEXT_SIGALG_ECDSA(MD), ?TLSEXT_SIGALG_RSA(MD)).
default_hash_signs() ->
+ HashSigns = [?TLSEXT_SIGALG(sha512),
+ ?TLSEXT_SIGALG(sha384),
+ ?TLSEXT_SIGALG(sha256),
+ ?TLSEXT_SIGALG(sha224),
+ ?TLSEXT_SIGALG(sha),
+ ?TLSEXT_SIGALG_DSA(sha),
+ ?TLSEXT_SIGALG_RSA(md5)],
+ CryptoSupport = proplists:get_value(public_keys, crypto:supports()),
+ HasECC = proplists:get_bool(ecdsa, CryptoSupport),
#hash_sign_algos{hash_sign_algos =
- [?TLSEXT_SIGALG(sha512),
- ?TLSEXT_SIGALG(sha384),
- ?TLSEXT_SIGALG(sha256),
- ?TLSEXT_SIGALG(sha224),
- ?TLSEXT_SIGALG(sha),
- ?TLSEXT_SIGALG_DSA(sha),
- ?TLSEXT_SIGALG_RSA(md5)]}.
+ lists:filter(fun({_, ecdsa}) -> HasECC;
+ (_) -> true end, HashSigns)}.
+
+handle_hello_extensions(#client_hello{random = Random,
+ cipher_suites = CipherSuites,
+ renegotiation_info = Info,
+ srp = SRP,
+ ec_point_formats = EcPointFormats0,
+ elliptic_curves = EllipticCurves0} = Hello, Version,
+ #ssl_options{secure_renegotiate = SecureRenegotation} = Opts,
+ Session0, ConnectionStates0, Renegotiation) ->
+ Session = handle_srp_extension(SRP, Session0),
+ ConnectionStates = handle_renegotiation_extension(Version, Info, Random, Session, ConnectionStates0,
+ Renegotiation, SecureRenegotation, CipherSuites),
+ ProtocolsToAdvertise = handle_next_protocol_extension(Hello, Renegotiation, Opts),
+ {EcPointFormats, EllipticCurves} = handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0),
+ %%TODO make extensions compund data structure
+ {Session, ConnectionStates, ProtocolsToAdvertise, EcPointFormats, EllipticCurves}.
+
+
+handle_renegotiation_extension(Version, Info, Random, #session{cipher_suite = CipherSuite,
+ compression_method = Compression},
+ ConnectionStates0, Renegotiation, SecureRenegotation, CipherSuites) ->
+ case handle_renegotiation_info(server, Info, ConnectionStates0,
+ Renegotiation, SecureRenegotation,
+ CipherSuites) of
+ {ok, ConnectionStates1} ->
+ hello_pending_connection_states(server,
+ Version,
+ CipherSuite,
+ Random,
+ Compression,
+ ConnectionStates1);
+ #alert{} = Alert ->
+ throw(Alert)
+ end.
+
+handle_next_protocol_extension(Hello, Renegotiation, SslOpts)->
+ case handle_next_protocol_on_server(Hello, Renegotiation, SslOpts) of
+ #alert{} = Alert ->
+ throw(Alert);
+ ProtocolsToAdvertise ->
+ ProtocolsToAdvertise
+ end.
+
+handle_srp_extension(undefined, Session) ->
+ Session;
+handle_srp_extension(#srp{username = Username}, Session) ->
+ Session#session{srp_username = Username}.
+
+int_to_bin(I) ->
+ L = (length(integer_to_list(I, 16)) + 1) div 2,
+ <<I:(L*8)>>.
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index 2414d5b666..b2387a0ee7 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,9 +28,9 @@
-include_lib("public_key/include/public_key.hrl").
--type algo_oid() :: ?'rsaEncryption' | ?'id-dsa'.
--type public_key_params() :: #'Dss-Parms'{} | term().
--type public_key_info() :: {algo_oid(), #'RSAPublicKey'{} | integer() , public_key_params()}.
+-type oid() :: tuple().
+-type public_key_params() :: #'Dss-Parms'{} | {namedCurve, oid()} | #'ECParameters'{} | term().
+-type public_key_info() :: {oid(), #'RSAPublicKey'{} | integer() | #'ECPoint'{}, public_key_params()}.
-type tls_handshake_history() :: {[binary()], [binary()]}.
-define(NO_PROTOCOL, <<>>).
@@ -48,6 +48,7 @@
compression_method,
cipher_suite,
master_secret,
+ srp_username,
is_resumable,
time_stamp
}).
@@ -99,7 +100,10 @@
cipher_suites, % cipher_suites<2..2^16-1>
compression_methods, % compression_methods<1..2^8-1>,
renegotiation_info,
+ srp, % srp username to send
hash_signs, % supported combinations of hashes/signature algos
+ ec_point_formats, % supported ec point formats
+ elliptic_curves, % supported elliptic curver
next_protocol_negotiation = undefined % [binary()]
}).
@@ -111,6 +115,8 @@
compression_method, % compression_method
renegotiation_info,
hash_signs, % supported combinations of hashes/signature algos
+ ec_point_formats, % supported ec point formats
+ elliptic_curves, % supported elliptic curver
next_protocol_negotiation = undefined % [binary()]
}).
@@ -128,6 +134,11 @@
-define(KEY_EXCHANGE_RSA, 0).
-define(KEY_EXCHANGE_DIFFIE_HELLMAN, 1).
+-define(KEY_EXCHANGE_EC_DIFFIE_HELLMAN, 6).
+-define(KEY_EXCHANGE_PSK, 2).
+-define(KEY_EXCHANGE_DHE_PSK, 3).
+-define(KEY_EXCHANGE_RSA_PSK, 4).
+-define(KEY_EXCHANGE_SRP, 5).
-record(server_rsa_params, {
rsa_modulus, %% opaque RSA_modulus<1..2^16-1>
@@ -139,7 +150,28 @@
dh_g, %% opaque DH_g<1..2^16-1>
dh_y %% opaque DH_Ys<1..2^16-1>
}).
-
+
+-record(server_ecdh_params, {
+ curve,
+ public %% opaque encoded ECpoint
+ }).
+
+-record(server_psk_params, {
+ hint
+ }).
+
+-record(server_dhe_psk_params, {
+ hint,
+ dh_params
+ }).
+
+-record(server_srp_params, {
+ srp_n, %% opaque srp_N<1..2^16-1>
+ srp_g, %% opaque srp_g<1..2^16-1>
+ srp_s, %% opaque srp_s<1..2^8-1>
+ srp_b %% opaque srp_B<1..2^16-1>
+ }).
+
-record(server_key_exchange, {
exchange_keys
}).
@@ -173,6 +205,9 @@
-define(DSS_SIGN, 2).
-define(RSA_FIXED_DH, 3).
-define(DSS_FIXED_DH, 4).
+-define(ECDSA_SIGN, 64).
+-define(RSA_FIXED_ECDH, 65).
+-define(ECDSA_FIXED_ECDH, 66).
% opaque DistinguishedName<1..2^16-1>;
@@ -209,6 +244,28 @@
dh_public
}).
+-record(client_ec_diffie_hellman_public, {
+ dh_public
+ }).
+
+-record(client_psk_identity, {
+ identity
+ }).
+
+-record(client_dhe_psk_identity, {
+ identity,
+ dh_public
+ }).
+
+-record(client_rsa_psk_identity, {
+ identity,
+ exchange_keys
+ }).
+
+-record(client_srp_public, {
+ srp_a
+ }).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Certificate verify - RFC 4346 section 7.4.8
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -235,6 +292,15 @@
}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% SRP RFC 5054 section 2.8.1.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-define(SRP_EXT, 12).
+
+-record(srp, {
+ username
+ }).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Signature Algorithms RFC 5746 section 7.4.1.4.1.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-define(SIGNATURE_ALGORITHMS_EXT, 13).
@@ -255,6 +321,33 @@
-record(next_protocol, {selected_protocol}).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% ECC Extensions RFC 4492 section 4 and 5
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(ELLIPTIC_CURVES_EXT, 10).
+-define(EC_POINT_FORMATS_EXT, 11).
+
+-record(elliptic_curves, {
+ elliptic_curve_list
+ }).
+
+-record(ec_point_formats, {
+ ec_point_format_list
+ }).
+
+-define(ECPOINT_UNCOMPRESSED, 0).
+-define(ECPOINT_ANSIX962_COMPRESSED_PRIME, 1).
+-define(ECPOINT_ANSIX962_COMPRESSED_CHAR2, 2).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% ECC RFC 4492 Handshake Messages, Section 5
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(EXPLICIT_PRIME, 1).
+-define(EXPLICIT_CHAR2, 2).
+-define(NAMED_CURVE, 3).
+
-endif. % -ifdef(ssl_handshake).
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index ed0dc34adf..14db4a6067 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -37,9 +37,9 @@
-type tls_atom_version() :: sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2'.
-type certdb_ref() :: reference().
-type db_handle() :: term().
--type key_algo() :: null | rsa | dhe_rsa | dhe_dss | dh_anon.
+-type key_algo() :: null | rsa | dhe_rsa | dhe_dss | ecdhe_ecdsa| ecdh_ecdsa | ecdh_rsa| srp_rsa| srp_dss | psk | dhe_psk | rsa_psk | dh_anon | ecdh_anon | srp_anon.
-type der_cert() :: binary().
--type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{}.
+-type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{} | #'ECPrivateKey'{}.
-type issuer() :: tuple().
-type serialnumber() :: integer().
-type cert_key() :: {reference(), integer(), issuer()}.
@@ -90,6 +90,9 @@
cacertfile, % file()
dh, % der_encoded()
dhfile, % file()
+ user_lookup_fun, % server option, fun to lookup the user
+ psk_identity, % binary
+ srp_identity, % client option {User, Password}
ciphers, %
%% Local policy for the server if it want's to reuse the session
%% or not. Defaluts to allways returning true.
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index aa9da65bb8..caea528a08 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -103,7 +103,7 @@ connection_init(Trustedcerts, Role) ->
%% Description: Cach a pem file and return its content.
%%--------------------------------------------------------------------
cache_pem_file(File, DbHandle) ->
- MD5 = crypto:md5(File),
+ MD5 = crypto:hash(md5, File),
case ssl_certificate_db:lookup_cached_pem(DbHandle, MD5) of
[{Content,_}] ->
{ok, Content};
@@ -468,7 +468,7 @@ new_id(Port, Tries, Cache, CacheCb) ->
clean_cert_db(Ref, CertDb, RefDb, PemCache, File) ->
case ssl_certificate_db:ref_count(Ref, RefDb, 0) of
0 ->
- MD5 = crypto:md5(File),
+ MD5 = crypto:hash(md5, File),
case ssl_certificate_db:lookup_cached_pem(PemCache, MD5) of
[{Content, Ref}] ->
ssl_certificate_db:insert(MD5, Content, PemCache);
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 173b9611c6..2a3356d60f 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -56,7 +56,7 @@
%% Misc.
-export([protocol_version/1, lowest_protocol_version/2,
highest_protocol_version/1, supported_protocol_versions/0,
- is_acceptable_version/1]).
+ is_acceptable_version/1, is_acceptable_version/2]).
-export([compressions/0]).
@@ -475,8 +475,10 @@ supported_protocol_versions([_|_] = Vsns) ->
%%--------------------------------------------------------------------
-spec is_acceptable_version(tls_version()) -> boolean().
+-spec is_acceptable_version(tls_version(), Supported :: [tls_version()]) -> boolean().
%%
%% Description: ssl version 2 is not acceptable security risks are too big.
+%%
%%--------------------------------------------------------------------
is_acceptable_version({N,_})
when N >= ?LOWEST_MAJOR_SUPPORTED_VERSION ->
@@ -484,6 +486,12 @@ is_acceptable_version({N,_})
is_acceptable_version(_) ->
false.
+is_acceptable_version({N,_} = Version, Versions)
+ when N >= ?LOWEST_MAJOR_SUPPORTED_VERSION ->
+ lists:member(Version, Versions);
+is_acceptable_version(_,_) ->
+ false.
+
%%--------------------------------------------------------------------
-spec compressions() -> [binary()].
%%
@@ -704,12 +712,5 @@ mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment)
Length, Fragment).
sufficient_tlsv1_2_crypto_support() ->
- Data = "Sampl",
- Data2 = "e #1",
- Key = <<0,1,2,3,16,17,18,19,32,33,34,35,48,49,50,51,4,5,6,7,20,21,22,23,36,37,38,39,
- 52,53,54,55,8,9,10,11,24,25,26,27,40,41,42,43,56,57,58,59>>,
- try
- crypto:sha256_mac(Key, lists:flatten([Data, Data2])),
- true
- catch _:_ -> false
- end.
+ CryptoSupport = crypto:supports(),
+ proplists:get_bool(sha256, proplists:get_value(hashs, CryptoSupport)).
diff --git a/lib/ssl/src/ssl_srp.hrl b/lib/ssl/src/ssl_srp.hrl
new file mode 100644
index 0000000000..ab2be33ab2
--- /dev/null
+++ b/lib/ssl/src/ssl_srp.hrl
@@ -0,0 +1,31 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Record definition for the TLS SRP protocol
+%% see RFC 5054
+%%----------------------------------------------------------------------
+
+-record(srp_user, {
+ generator :: binary(),
+ prime :: binary(),
+ salt :: binary(),
+ verifier :: binary()
+ }).
diff --git a/lib/ssl/src/ssl_srp_primes.erl b/lib/ssl/src/ssl_srp_primes.erl
new file mode 100644
index 0000000000..ca20a8d673
--- /dev/null
+++ b/lib/ssl/src/ssl_srp_primes.erl
@@ -0,0 +1,506 @@
+-module(ssl_srp_primes).
+
+-export([get_srp_params/1, check_srp_params/2]).
+
+-define(PRIME_1024, <<16#EE, 16#AF, 16#0A, 16#B9, 16#AD, 16#B3, 16#8D,
+ 16#D6, 16#9C, 16#33, 16#F8, 16#0A, 16#FA, 16#8F,
+ 16#C5, 16#E8, 16#60, 16#72, 16#61, 16#87, 16#75,
+ 16#FF, 16#3C, 16#0B, 16#9E, 16#A2, 16#31, 16#4C,
+ 16#9C, 16#25, 16#65, 16#76, 16#D6, 16#74, 16#DF,
+ 16#74, 16#96, 16#EA, 16#81, 16#D3, 16#38, 16#3B,
+ 16#48, 16#13, 16#D6, 16#92, 16#C6, 16#E0, 16#E0,
+ 16#D5, 16#D8, 16#E2, 16#50, 16#B9, 16#8B, 16#E4,
+ 16#8E, 16#49, 16#5C, 16#1D, 16#60, 16#89, 16#DA,
+ 16#D1, 16#5D, 16#C7, 16#D7, 16#B4, 16#61, 16#54,
+ 16#D6, 16#B6, 16#CE, 16#8E, 16#F4, 16#AD, 16#69,
+ 16#B1, 16#5D, 16#49, 16#82, 16#55, 16#9B, 16#29,
+ 16#7B, 16#CF, 16#18, 16#85, 16#C5, 16#29, 16#F5,
+ 16#66, 16#66, 16#0E, 16#57, 16#EC, 16#68, 16#ED,
+ 16#BC, 16#3C, 16#05, 16#72, 16#6C, 16#C0, 16#2F,
+ 16#D4, 16#CB, 16#F4, 16#97, 16#6E, 16#AA, 16#9A,
+ 16#FD, 16#51, 16#38, 16#FE, 16#83, 16#76, 16#43,
+ 16#5B, 16#9F, 16#C6, 16#1D, 16#2F, 16#C0, 16#EB,
+ 16#06, 16#E3>>).
+-define(GENERATOR_1024, <<2>>).
+
+
+-define(PRIME_1536, <<16#9D, 16#EF, 16#3C, 16#AF, 16#B9, 16#39, 16#27,
+ 16#7A, 16#B1, 16#F1, 16#2A, 16#86, 16#17, 16#A4,
+ 16#7B, 16#BB, 16#DB, 16#A5, 16#1D, 16#F4, 16#99,
+ 16#AC, 16#4C, 16#80, 16#BE, 16#EE, 16#A9, 16#61,
+ 16#4B, 16#19, 16#CC, 16#4D, 16#5F, 16#4F, 16#5F,
+ 16#55, 16#6E, 16#27, 16#CB, 16#DE, 16#51, 16#C6,
+ 16#A9, 16#4B, 16#E4, 16#60, 16#7A, 16#29, 16#15,
+ 16#58, 16#90, 16#3B, 16#A0, 16#D0, 16#F8, 16#43,
+ 16#80, 16#B6, 16#55, 16#BB, 16#9A, 16#22, 16#E8,
+ 16#DC, 16#DF, 16#02, 16#8A, 16#7C, 16#EC, 16#67,
+ 16#F0, 16#D0, 16#81, 16#34, 16#B1, 16#C8, 16#B9,
+ 16#79, 16#89, 16#14, 16#9B, 16#60, 16#9E, 16#0B,
+ 16#E3, 16#BA, 16#B6, 16#3D, 16#47, 16#54, 16#83,
+ 16#81, 16#DB, 16#C5, 16#B1, 16#FC, 16#76, 16#4E,
+ 16#3F, 16#4B, 16#53, 16#DD, 16#9D, 16#A1, 16#15,
+ 16#8B, 16#FD, 16#3E, 16#2B, 16#9C, 16#8C, 16#F5,
+ 16#6E, 16#DF, 16#01, 16#95, 16#39, 16#34, 16#96,
+ 16#27, 16#DB, 16#2F, 16#D5, 16#3D, 16#24, 16#B7,
+ 16#C4, 16#86, 16#65, 16#77, 16#2E, 16#43, 16#7D,
+ 16#6C, 16#7F, 16#8C, 16#E4, 16#42, 16#73, 16#4A,
+ 16#F7, 16#CC, 16#B7, 16#AE, 16#83, 16#7C, 16#26,
+ 16#4A, 16#E3, 16#A9, 16#BE, 16#B8, 16#7F, 16#8A,
+ 16#2F, 16#E9, 16#B8, 16#B5, 16#29, 16#2E, 16#5A,
+ 16#02, 16#1F, 16#FF, 16#5E, 16#91, 16#47, 16#9E,
+ 16#8C, 16#E7, 16#A2, 16#8C, 16#24, 16#42, 16#C6,
+ 16#F3, 16#15, 16#18, 16#0F, 16#93, 16#49, 16#9A,
+ 16#23, 16#4D, 16#CF, 16#76, 16#E3, 16#FE, 16#D1,
+ 16#35, 16#F9, 16#BB>>).
+-define(GENERATOR_1536, <<2>>).
+
+-define(PRIME_2048, <<16#AC, 16#6B, 16#DB, 16#41, 16#32, 16#4A, 16#9A,
+ 16#9B, 16#F1, 16#66, 16#DE, 16#5E, 16#13, 16#89,
+ 16#58, 16#2F, 16#AF, 16#72, 16#B6, 16#65, 16#19,
+ 16#87, 16#EE, 16#07, 16#FC, 16#31, 16#92, 16#94,
+ 16#3D, 16#B5, 16#60, 16#50, 16#A3, 16#73, 16#29,
+ 16#CB, 16#B4, 16#A0, 16#99, 16#ED, 16#81, 16#93,
+ 16#E0, 16#75, 16#77, 16#67, 16#A1, 16#3D, 16#D5,
+ 16#23, 16#12, 16#AB, 16#4B, 16#03, 16#31, 16#0D,
+ 16#CD, 16#7F, 16#48, 16#A9, 16#DA, 16#04, 16#FD,
+ 16#50, 16#E8, 16#08, 16#39, 16#69, 16#ED, 16#B7,
+ 16#67, 16#B0, 16#CF, 16#60, 16#95, 16#17, 16#9A,
+ 16#16, 16#3A, 16#B3, 16#66, 16#1A, 16#05, 16#FB,
+ 16#D5, 16#FA, 16#AA, 16#E8, 16#29, 16#18, 16#A9,
+ 16#96, 16#2F, 16#0B, 16#93, 16#B8, 16#55, 16#F9,
+ 16#79, 16#93, 16#EC, 16#97, 16#5E, 16#EA, 16#A8,
+ 16#0D, 16#74, 16#0A, 16#DB, 16#F4, 16#FF, 16#74,
+ 16#73, 16#59, 16#D0, 16#41, 16#D5, 16#C3, 16#3E,
+ 16#A7, 16#1D, 16#28, 16#1E, 16#44, 16#6B, 16#14,
+ 16#77, 16#3B, 16#CA, 16#97, 16#B4, 16#3A, 16#23,
+ 16#FB, 16#80, 16#16, 16#76, 16#BD, 16#20, 16#7A,
+ 16#43, 16#6C, 16#64, 16#81, 16#F1, 16#D2, 16#B9,
+ 16#07, 16#87, 16#17, 16#46, 16#1A, 16#5B, 16#9D,
+ 16#32, 16#E6, 16#88, 16#F8, 16#77, 16#48, 16#54,
+ 16#45, 16#23, 16#B5, 16#24, 16#B0, 16#D5, 16#7D,
+ 16#5E, 16#A7, 16#7A, 16#27, 16#75, 16#D2, 16#EC,
+ 16#FA, 16#03, 16#2C, 16#FB, 16#DB, 16#F5, 16#2F,
+ 16#B3, 16#78, 16#61, 16#60, 16#27, 16#90, 16#04,
+ 16#E5, 16#7A, 16#E6, 16#AF, 16#87, 16#4E, 16#73,
+ 16#03, 16#CE, 16#53, 16#29, 16#9C, 16#CC, 16#04,
+ 16#1C, 16#7B, 16#C3, 16#08, 16#D8, 16#2A, 16#56,
+ 16#98, 16#F3, 16#A8, 16#D0, 16#C3, 16#82, 16#71,
+ 16#AE, 16#35, 16#F8, 16#E9, 16#DB, 16#FB, 16#B6,
+ 16#94, 16#B5, 16#C8, 16#03, 16#D8, 16#9F, 16#7A,
+ 16#E4, 16#35, 16#DE, 16#23, 16#6D, 16#52, 16#5F,
+ 16#54, 16#75, 16#9B, 16#65, 16#E3, 16#72, 16#FC,
+ 16#D6, 16#8E, 16#F2, 16#0F, 16#A7, 16#11, 16#1F,
+ 16#9E, 16#4A, 16#FF, 16#73>>).
+-define(GENERATOR_2048, <<2>>).
+
+-define(PRIME_3072, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68,
+ 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80,
+ 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08,
+ 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE,
+ 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A,
+ 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF,
+ 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B,
+ 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14,
+ 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51,
+ 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62,
+ 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9,
+ 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C,
+ 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38,
+ 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE,
+ 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6,
+ 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B,
+ 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63,
+ 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C,
+ 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8,
+ 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D,
+ 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62,
+ 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E,
+ 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D,
+ 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98,
+ 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18,
+ 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E,
+ 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C,
+ 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83,
+ 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5,
+ 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE,
+ 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18,
+ 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A,
+ 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA,
+ 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A,
+ 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D,
+ 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21,
+ 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB,
+ 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A,
+ 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D,
+ 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4,
+ 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09,
+ 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A,
+ 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26,
+ 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA,
+ 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76,
+ 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52,
+ 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C,
+ 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D,
+ 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9,
+ 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74,
+ 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC,
+ 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1,
+ 16#20, 16#A9, 16#3A, 16#D2, 16#CA, 16#FF, 16#FF,
+ 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF>>).
+-define(GENERATOR_3072, <<5>>).
+
+-define(PRIME_4096, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68,
+ 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80,
+ 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08,
+ 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE,
+ 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A,
+ 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF,
+ 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B,
+ 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14,
+ 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51,
+ 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62,
+ 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9,
+ 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C,
+ 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38,
+ 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE,
+ 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6,
+ 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B,
+ 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63,
+ 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C,
+ 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8,
+ 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D,
+ 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62,
+ 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E,
+ 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D,
+ 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98,
+ 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18,
+ 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E,
+ 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C,
+ 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83,
+ 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5,
+ 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE,
+ 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18,
+ 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A,
+ 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA,
+ 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A,
+ 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D,
+ 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21,
+ 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB,
+ 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A,
+ 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D,
+ 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4,
+ 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09,
+ 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A,
+ 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26,
+ 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA,
+ 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76,
+ 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52,
+ 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C,
+ 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D,
+ 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9,
+ 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74,
+ 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC,
+ 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1,
+ 16#20, 16#A9, 16#21, 16#08, 16#01, 16#1A, 16#72,
+ 16#3C, 16#12, 16#A7, 16#87, 16#E6, 16#D7, 16#88,
+ 16#71, 16#9A, 16#10, 16#BD, 16#BA, 16#5B, 16#26,
+ 16#99, 16#C3, 16#27, 16#18, 16#6A, 16#F4, 16#E2,
+ 16#3C, 16#1A, 16#94, 16#68, 16#34, 16#B6, 16#15,
+ 16#0B, 16#DA, 16#25, 16#83, 16#E9, 16#CA, 16#2A,
+ 16#D4, 16#4C, 16#E8, 16#DB, 16#BB, 16#C2, 16#DB,
+ 16#04, 16#DE, 16#8E, 16#F9, 16#2E, 16#8E, 16#FC,
+ 16#14, 16#1F, 16#BE, 16#CA, 16#A6, 16#28, 16#7C,
+ 16#59, 16#47, 16#4E, 16#6B, 16#C0, 16#5D, 16#99,
+ 16#B2, 16#96, 16#4F, 16#A0, 16#90, 16#C3, 16#A2,
+ 16#23, 16#3B, 16#A1, 16#86, 16#51, 16#5B, 16#E7,
+ 16#ED, 16#1F, 16#61, 16#29, 16#70, 16#CE, 16#E2,
+ 16#D7, 16#AF, 16#B8, 16#1B, 16#DD, 16#76, 16#21,
+ 16#70, 16#48, 16#1C, 16#D0, 16#06, 16#91, 16#27,
+ 16#D5, 16#B0, 16#5A, 16#A9, 16#93, 16#B4, 16#EA,
+ 16#98, 16#8D, 16#8F, 16#DD, 16#C1, 16#86, 16#FF,
+ 16#B7, 16#DC, 16#90, 16#A6, 16#C0, 16#8F, 16#4D,
+ 16#F4, 16#35, 16#C9, 16#34, 16#06, 16#31, 16#99,
+ 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF>>).
+-define(GENERATOR_4096, <<5>>).
+
+-define(PRIME_6144, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68,
+ 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80,
+ 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08,
+ 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE,
+ 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A,
+ 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF,
+ 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B,
+ 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14,
+ 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51,
+ 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62,
+ 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9,
+ 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C,
+ 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38,
+ 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE,
+ 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6,
+ 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B,
+ 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63,
+ 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C,
+ 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8,
+ 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D,
+ 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62,
+ 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E,
+ 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D,
+ 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98,
+ 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18,
+ 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E,
+ 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C,
+ 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83,
+ 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5,
+ 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE,
+ 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18,
+ 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A,
+ 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA,
+ 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A,
+ 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D,
+ 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21,
+ 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB,
+ 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A,
+ 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D,
+ 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4,
+ 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09,
+ 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A,
+ 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26,
+ 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA,
+ 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76,
+ 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52,
+ 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C,
+ 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D,
+ 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9,
+ 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74,
+ 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC,
+ 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1,
+ 16#20, 16#A9, 16#21, 16#08, 16#01, 16#1A, 16#72,
+ 16#3C, 16#12, 16#A7, 16#87, 16#E6, 16#D7, 16#88,
+ 16#71, 16#9A, 16#10, 16#BD, 16#BA, 16#5B, 16#26,
+ 16#99, 16#C3, 16#27, 16#18, 16#6A, 16#F4, 16#E2,
+ 16#3C, 16#1A, 16#94, 16#68, 16#34, 16#B6, 16#15,
+ 16#0B, 16#DA, 16#25, 16#83, 16#E9, 16#CA, 16#2A,
+ 16#D4, 16#4C, 16#E8, 16#DB, 16#BB, 16#C2, 16#DB,
+ 16#04, 16#DE, 16#8E, 16#F9, 16#2E, 16#8E, 16#FC,
+ 16#14, 16#1F, 16#BE, 16#CA, 16#A6, 16#28, 16#7C,
+ 16#59, 16#47, 16#4E, 16#6B, 16#C0, 16#5D, 16#99,
+ 16#B2, 16#96, 16#4F, 16#A0, 16#90, 16#C3, 16#A2,
+ 16#23, 16#3B, 16#A1, 16#86, 16#51, 16#5B, 16#E7,
+ 16#ED, 16#1F, 16#61, 16#29, 16#70, 16#CE, 16#E2,
+ 16#D7, 16#AF, 16#B8, 16#1B, 16#DD, 16#76, 16#21,
+ 16#70, 16#48, 16#1C, 16#D0, 16#06, 16#91, 16#27,
+ 16#D5, 16#B0, 16#5A, 16#A9, 16#93, 16#B4, 16#EA,
+ 16#98, 16#8D, 16#8F, 16#DD, 16#C1, 16#86, 16#FF,
+ 16#B7, 16#DC, 16#90, 16#A6, 16#C0, 16#8F, 16#4D,
+ 16#F4, 16#35, 16#C9, 16#34, 16#02, 16#84, 16#92,
+ 16#36, 16#C3, 16#FA, 16#B4, 16#D2, 16#7C, 16#70,
+ 16#26, 16#C1, 16#D4, 16#DC, 16#B2, 16#60, 16#26,
+ 16#46, 16#DE, 16#C9, 16#75, 16#1E, 16#76, 16#3D,
+ 16#BA, 16#37, 16#BD, 16#F8, 16#FF, 16#94, 16#06,
+ 16#AD, 16#9E, 16#53, 16#0E, 16#E5, 16#DB, 16#38,
+ 16#2F, 16#41, 16#30, 16#01, 16#AE, 16#B0, 16#6A,
+ 16#53, 16#ED, 16#90, 16#27, 16#D8, 16#31, 16#17,
+ 16#97, 16#27, 16#B0, 16#86, 16#5A, 16#89, 16#18,
+ 16#DA, 16#3E, 16#DB, 16#EB, 16#CF, 16#9B, 16#14,
+ 16#ED, 16#44, 16#CE, 16#6C, 16#BA, 16#CE, 16#D4,
+ 16#BB, 16#1B, 16#DB, 16#7F, 16#14, 16#47, 16#E6,
+ 16#CC, 16#25, 16#4B, 16#33, 16#20, 16#51, 16#51,
+ 16#2B, 16#D7, 16#AF, 16#42, 16#6F, 16#B8, 16#F4,
+ 16#01, 16#37, 16#8C, 16#D2, 16#BF, 16#59, 16#83,
+ 16#CA, 16#01, 16#C6, 16#4B, 16#92, 16#EC, 16#F0,
+ 16#32, 16#EA, 16#15, 16#D1, 16#72, 16#1D, 16#03,
+ 16#F4, 16#82, 16#D7, 16#CE, 16#6E, 16#74, 16#FE,
+ 16#F6, 16#D5, 16#5E, 16#70, 16#2F, 16#46, 16#98,
+ 16#0C, 16#82, 16#B5, 16#A8, 16#40, 16#31, 16#90,
+ 16#0B, 16#1C, 16#9E, 16#59, 16#E7, 16#C9, 16#7F,
+ 16#BE, 16#C7, 16#E8, 16#F3, 16#23, 16#A9, 16#7A,
+ 16#7E, 16#36, 16#CC, 16#88, 16#BE, 16#0F, 16#1D,
+ 16#45, 16#B7, 16#FF, 16#58, 16#5A, 16#C5, 16#4B,
+ 16#D4, 16#07, 16#B2, 16#2B, 16#41, 16#54, 16#AA,
+ 16#CC, 16#8F, 16#6D, 16#7E, 16#BF, 16#48, 16#E1,
+ 16#D8, 16#14, 16#CC, 16#5E, 16#D2, 16#0F, 16#80,
+ 16#37, 16#E0, 16#A7, 16#97, 16#15, 16#EE, 16#F2,
+ 16#9B, 16#E3, 16#28, 16#06, 16#A1, 16#D5, 16#8B,
+ 16#B7, 16#C5, 16#DA, 16#76, 16#F5, 16#50, 16#AA,
+ 16#3D, 16#8A, 16#1F, 16#BF, 16#F0, 16#EB, 16#19,
+ 16#CC, 16#B1, 16#A3, 16#13, 16#D5, 16#5C, 16#DA,
+ 16#56, 16#C9, 16#EC, 16#2E, 16#F2, 16#96, 16#32,
+ 16#38, 16#7F, 16#E8, 16#D7, 16#6E, 16#3C, 16#04,
+ 16#68, 16#04, 16#3E, 16#8F, 16#66, 16#3F, 16#48,
+ 16#60, 16#EE, 16#12, 16#BF, 16#2D, 16#5B, 16#0B,
+ 16#74, 16#74, 16#D6, 16#E6, 16#94, 16#F9, 16#1E,
+ 16#6D, 16#CC, 16#40, 16#24, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#FF, 16#FF, 16#FF, 16#FF>>).
+-define(GENERATOR_6144, <<5>>).
+
+-define(PRIME_8192, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68,
+ 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80,
+ 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08,
+ 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE,
+ 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A,
+ 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF,
+ 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B,
+ 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14,
+ 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51,
+ 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62,
+ 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9,
+ 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C,
+ 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38,
+ 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE,
+ 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6,
+ 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B,
+ 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63,
+ 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C,
+ 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8,
+ 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D,
+ 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62,
+ 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E,
+ 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D,
+ 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98,
+ 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18,
+ 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E,
+ 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C,
+ 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83,
+ 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5,
+ 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE,
+ 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18,
+ 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A,
+ 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA,
+ 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A,
+ 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D,
+ 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21,
+ 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB,
+ 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A,
+ 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D,
+ 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4,
+ 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09,
+ 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A,
+ 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26,
+ 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA,
+ 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76,
+ 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52,
+ 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C,
+ 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D,
+ 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9,
+ 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74,
+ 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC,
+ 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1,
+ 16#20, 16#A9, 16#21, 16#08, 16#01, 16#1A, 16#72,
+ 16#3C, 16#12, 16#A7, 16#87, 16#E6, 16#D7, 16#88,
+ 16#71, 16#9A, 16#10, 16#BD, 16#BA, 16#5B, 16#26,
+ 16#99, 16#C3, 16#27, 16#18, 16#6A, 16#F4, 16#E2,
+ 16#3C, 16#1A, 16#94, 16#68, 16#34, 16#B6, 16#15,
+ 16#0B, 16#DA, 16#25, 16#83, 16#E9, 16#CA, 16#2A,
+ 16#D4, 16#4C, 16#E8, 16#DB, 16#BB, 16#C2, 16#DB,
+ 16#04, 16#DE, 16#8E, 16#F9, 16#2E, 16#8E, 16#FC,
+ 16#14, 16#1F, 16#BE, 16#CA, 16#A6, 16#28, 16#7C,
+ 16#59, 16#47, 16#4E, 16#6B, 16#C0, 16#5D, 16#99,
+ 16#B2, 16#96, 16#4F, 16#A0, 16#90, 16#C3, 16#A2,
+ 16#23, 16#3B, 16#A1, 16#86, 16#51, 16#5B, 16#E7,
+ 16#ED, 16#1F, 16#61, 16#29, 16#70, 16#CE, 16#E2,
+ 16#D7, 16#AF, 16#B8, 16#1B, 16#DD, 16#76, 16#21,
+ 16#70, 16#48, 16#1C, 16#D0, 16#06, 16#91, 16#27,
+ 16#D5, 16#B0, 16#5A, 16#A9, 16#93, 16#B4, 16#EA,
+ 16#98, 16#8D, 16#8F, 16#DD, 16#C1, 16#86, 16#FF,
+ 16#B7, 16#DC, 16#90, 16#A6, 16#C0, 16#8F, 16#4D,
+ 16#F4, 16#35, 16#C9, 16#34, 16#02, 16#84, 16#92,
+ 16#36, 16#C3, 16#FA, 16#B4, 16#D2, 16#7C, 16#70,
+ 16#26, 16#C1, 16#D4, 16#DC, 16#B2, 16#60, 16#26,
+ 16#46, 16#DE, 16#C9, 16#75, 16#1E, 16#76, 16#3D,
+ 16#BA, 16#37, 16#BD, 16#F8, 16#FF, 16#94, 16#06,
+ 16#AD, 16#9E, 16#53, 16#0E, 16#E5, 16#DB, 16#38,
+ 16#2F, 16#41, 16#30, 16#01, 16#AE, 16#B0, 16#6A,
+ 16#53, 16#ED, 16#90, 16#27, 16#D8, 16#31, 16#17,
+ 16#97, 16#27, 16#B0, 16#86, 16#5A, 16#89, 16#18,
+ 16#DA, 16#3E, 16#DB, 16#EB, 16#CF, 16#9B, 16#14,
+ 16#ED, 16#44, 16#CE, 16#6C, 16#BA, 16#CE, 16#D4,
+ 16#BB, 16#1B, 16#DB, 16#7F, 16#14, 16#47, 16#E6,
+ 16#CC, 16#25, 16#4B, 16#33, 16#20, 16#51, 16#51,
+ 16#2B, 16#D7, 16#AF, 16#42, 16#6F, 16#B8, 16#F4,
+ 16#01, 16#37, 16#8C, 16#D2, 16#BF, 16#59, 16#83,
+ 16#CA, 16#01, 16#C6, 16#4B, 16#92, 16#EC, 16#F0,
+ 16#32, 16#EA, 16#15, 16#D1, 16#72, 16#1D, 16#03,
+ 16#F4, 16#82, 16#D7, 16#CE, 16#6E, 16#74, 16#FE,
+ 16#F6, 16#D5, 16#5E, 16#70, 16#2F, 16#46, 16#98,
+ 16#0C, 16#82, 16#B5, 16#A8, 16#40, 16#31, 16#90,
+ 16#0B, 16#1C, 16#9E, 16#59, 16#E7, 16#C9, 16#7F,
+ 16#BE, 16#C7, 16#E8, 16#F3, 16#23, 16#A9, 16#7A,
+ 16#7E, 16#36, 16#CC, 16#88, 16#BE, 16#0F, 16#1D,
+ 16#45, 16#B7, 16#FF, 16#58, 16#5A, 16#C5, 16#4B,
+ 16#D4, 16#07, 16#B2, 16#2B, 16#41, 16#54, 16#AA,
+ 16#CC, 16#8F, 16#6D, 16#7E, 16#BF, 16#48, 16#E1,
+ 16#D8, 16#14, 16#CC, 16#5E, 16#D2, 16#0F, 16#80,
+ 16#37, 16#E0, 16#A7, 16#97, 16#15, 16#EE, 16#F2,
+ 16#9B, 16#E3, 16#28, 16#06, 16#A1, 16#D5, 16#8B,
+ 16#B7, 16#C5, 16#DA, 16#76, 16#F5, 16#50, 16#AA,
+ 16#3D, 16#8A, 16#1F, 16#BF, 16#F0, 16#EB, 16#19,
+ 16#CC, 16#B1, 16#A3, 16#13, 16#D5, 16#5C, 16#DA,
+ 16#56, 16#C9, 16#EC, 16#2E, 16#F2, 16#96, 16#32,
+ 16#38, 16#7F, 16#E8, 16#D7, 16#6E, 16#3C, 16#04,
+ 16#68, 16#04, 16#3E, 16#8F, 16#66, 16#3F, 16#48,
+ 16#60, 16#EE, 16#12, 16#BF, 16#2D, 16#5B, 16#0B,
+ 16#74, 16#74, 16#D6, 16#E6, 16#94, 16#F9, 16#1E,
+ 16#6D, 16#BE, 16#11, 16#59, 16#74, 16#A3, 16#92,
+ 16#6F, 16#12, 16#FE, 16#E5, 16#E4, 16#38, 16#77,
+ 16#7C, 16#B6, 16#A9, 16#32, 16#DF, 16#8C, 16#D8,
+ 16#BE, 16#C4, 16#D0, 16#73, 16#B9, 16#31, 16#BA,
+ 16#3B, 16#C8, 16#32, 16#B6, 16#8D, 16#9D, 16#D3,
+ 16#00, 16#74, 16#1F, 16#A7, 16#BF, 16#8A, 16#FC,
+ 16#47, 16#ED, 16#25, 16#76, 16#F6, 16#93, 16#6B,
+ 16#A4, 16#24, 16#66, 16#3A, 16#AB, 16#63, 16#9C,
+ 16#5A, 16#E4, 16#F5, 16#68, 16#34, 16#23, 16#B4,
+ 16#74, 16#2B, 16#F1, 16#C9, 16#78, 16#23, 16#8F,
+ 16#16, 16#CB, 16#E3, 16#9D, 16#65, 16#2D, 16#E3,
+ 16#FD, 16#B8, 16#BE, 16#FC, 16#84, 16#8A, 16#D9,
+ 16#22, 16#22, 16#2E, 16#04, 16#A4, 16#03, 16#7C,
+ 16#07, 16#13, 16#EB, 16#57, 16#A8, 16#1A, 16#23,
+ 16#F0, 16#C7, 16#34, 16#73, 16#FC, 16#64, 16#6C,
+ 16#EA, 16#30, 16#6B, 16#4B, 16#CB, 16#C8, 16#86,
+ 16#2F, 16#83, 16#85, 16#DD, 16#FA, 16#9D, 16#4B,
+ 16#7F, 16#A2, 16#C0, 16#87, 16#E8, 16#79, 16#68,
+ 16#33, 16#03, 16#ED, 16#5B, 16#DD, 16#3A, 16#06,
+ 16#2B, 16#3C, 16#F5, 16#B3, 16#A2, 16#78, 16#A6,
+ 16#6D, 16#2A, 16#13, 16#F8, 16#3F, 16#44, 16#F8,
+ 16#2D, 16#DF, 16#31, 16#0E, 16#E0, 16#74, 16#AB,
+ 16#6A, 16#36, 16#45, 16#97, 16#E8, 16#99, 16#A0,
+ 16#25, 16#5D, 16#C1, 16#64, 16#F3, 16#1C, 16#C5,
+ 16#08, 16#46, 16#85, 16#1D, 16#F9, 16#AB, 16#48,
+ 16#19, 16#5D, 16#ED, 16#7E, 16#A1, 16#B1, 16#D5,
+ 16#10, 16#BD, 16#7E, 16#E7, 16#4D, 16#73, 16#FA,
+ 16#F3, 16#6B, 16#C3, 16#1E, 16#CF, 16#A2, 16#68,
+ 16#35, 16#90, 16#46, 16#F4, 16#EB, 16#87, 16#9F,
+ 16#92, 16#40, 16#09, 16#43, 16#8B, 16#48, 16#1C,
+ 16#6C, 16#D7, 16#88, 16#9A, 16#00, 16#2E, 16#D5,
+ 16#EE, 16#38, 16#2B, 16#C9, 16#19, 16#0D, 16#A6,
+ 16#FC, 16#02, 16#6E, 16#47, 16#95, 16#58, 16#E4,
+ 16#47, 16#56, 16#77, 16#E9, 16#AA, 16#9E, 16#30,
+ 16#50, 16#E2, 16#76, 16#56, 16#94, 16#DF, 16#C8,
+ 16#1F, 16#56, 16#E8, 16#80, 16#B9, 16#6E, 16#71,
+ 16#60, 16#C9, 16#80, 16#DD, 16#98, 16#ED, 16#D3,
+ 16#DF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#FF>>).
+-define(GENERATOR_8192, <<19>>).
+
+get_srp_params(srp_1024) -> {?GENERATOR_1024, ?PRIME_1024};
+get_srp_params(srp_1536) -> {?GENERATOR_1536, ?PRIME_1536};
+get_srp_params(srp_2048) -> {?GENERATOR_2048, ?PRIME_2048};
+get_srp_params(srp_3072) -> {?GENERATOR_3072, ?PRIME_3072};
+get_srp_params(srp_4096) -> {?GENERATOR_4096, ?PRIME_4096};
+get_srp_params(srp_6144) -> {?GENERATOR_6144, ?PRIME_6144};
+get_srp_params(srp_8192) -> {?GENERATOR_8192, ?PRIME_8192}.
+
+check_srp_params(?GENERATOR_1024, ?PRIME_1024) -> ok;
+check_srp_params(?GENERATOR_1536, ?PRIME_1536) -> ok;
+check_srp_params(?GENERATOR_2048, ?PRIME_2048) -> ok;
+check_srp_params(?GENERATOR_3072, ?PRIME_3072) -> ok;
+check_srp_params(?GENERATOR_4096, ?PRIME_4096) -> ok;
+check_srp_params(?GENERATOR_6144, ?PRIME_6144) -> ok;
+check_srp_params(?GENERATOR_8192, ?PRIME_8192) -> ok;
+check_srp_params(_Generator, _Prime) ->
+ not_accepted.
diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl
index a11c5b8c0c..013c27ebb5 100644
--- a/lib/ssl/src/ssl_ssl3.erl
+++ b/lib/ssl/src/ssl_ssl3.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -154,9 +154,9 @@ suites() ->
%%--------------------------------------------------------------------
hash(?MD5, Data) ->
- crypto:md5(Data);
+ crypto:hash(md5, Data);
hash(?SHA, Data) ->
- crypto:sha(Data).
+ crypto:hash(sha, Data).
%%pad_1(?NULL) ->
%% "";
@@ -198,6 +198,6 @@ gen(_Secret, _All, Wanted, Len, _C, _N, Acc) when Wanted =< Len ->
Block;
gen(Secret, All, Wanted, Len, C, N, Acc) ->
Prefix = lists:duplicate(N, C),
- SHA = crypto:sha([Prefix, All]),
- MD5 = crypto:md5([Secret, SHA]),
+ SHA = crypto:hash(sha, [Prefix, All]),
+ MD5 = crypto:hash(md5, [Secret, SHA]),
gen(Secret, All, Wanted, Len + 16, C+1, N+1, [MD5 | Acc]).
diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl
index 41dc1bf0dc..8ab66d0627 100644
--- a/lib/ssl/src/ssl_tls1.erl
+++ b/lib/ssl/src/ssl_tls1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -29,7 +29,8 @@
-include("ssl_record.hrl").
-export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7,
- setup_keys/8, suites/1, prf/5]).
+ setup_keys/8, suites/1, prf/5,
+ ecc_curves/1, oid_to_enum/1, enum_to_oid/1]).
%%====================================================================
%% Internal application API
@@ -57,8 +58,8 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
%% verify_data
%% PRF(master_secret, finished_label, MD5(handshake_messages) +
%% SHA-1(handshake_messages)) [0..11];
- MD5 = crypto:md5(Handshake),
- SHA = crypto:sha(Handshake),
+ MD5 = crypto:hash(md5, Handshake),
+ SHA = crypto:hash(sha, Handshake),
prf(?MD5SHA, MasterSecret, finished_label(Role), [MD5, SHA], 12);
finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
@@ -76,8 +77,8 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
-spec certificate_verify(md5sha | sha, integer(), [binary()]) -> binary().
certificate_verify(md5sha, _Version, Handshake) ->
- MD5 = crypto:md5(Handshake),
- SHA = crypto:sha(Handshake),
+ MD5 = crypto:hash(md5, Handshake),
+ SHA = crypto:hash(sha, Handshake),
<<MD5/binary, SHA/binary>>;
certificate_verify(HashAlgo, _Version, Handshake) ->
@@ -183,24 +184,95 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
-spec suites(1|2|3) -> [cipher_suite()].
suites(Minor) when Minor == 1; Minor == 2->
+ case sufficent_ec_support() of
+ true ->
+ all_suites(Minor);
+ false ->
+ no_ec_suites(Minor)
+ end;
+
+suites(Minor) when Minor == 3 ->
+ case sufficent_ec_support() of
+ true ->
+ all_suites(3) ++ all_suites(2);
+ false ->
+ no_ec_suites(3) ++ no_ec_suites(2)
+ end.
+
+all_suites(Minor) when Minor == 1; Minor == 2->
[
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
?TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
?TLS_RSA_WITH_AES_256_CBC_SHA,
+
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
?TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
?TLS_RSA_WITH_AES_128_CBC_SHA,
- %%?TLS_RSA_WITH_IDEA_CBC_SHA,
+
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_MD5,
?TLS_DHE_RSA_WITH_DES_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA,
+
?TLS_RSA_WITH_DES_CBC_SHA
- ];
+ ];
+all_suites(3) ->
+ [
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+
+ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+ ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
+ ?TLS_RSA_WITH_AES_256_CBC_SHA256,
+
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+
+ ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
+ ?TLS_RSA_WITH_AES_128_CBC_SHA256
+ ].
-suites(Minor) when Minor == 3 ->
+no_ec_suites(Minor) when Minor == 1; Minor == 2->
+ [
+ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+ ?TLS_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ ?TLS_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_RSA_WITH_RC4_128_SHA,
+ ?TLS_RSA_WITH_RC4_128_MD5,
+ ?TLS_DHE_RSA_WITH_DES_CBC_SHA,
+ ?TLS_RSA_WITH_DES_CBC_SHA
+ ];
+no_ec_suites(3) ->
[
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
@@ -208,9 +280,7 @@ suites(Minor) when Minor == 3 ->
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
?TLS_RSA_WITH_AES_128_CBC_SHA256
- %% ?TLS_DH_anon_WITH_AES_128_CBC_SHA256,
- %% ?TLS_DH_anon_WITH_AES_256_CBC_SHA256
- ] ++ suites(2).
+ ].
%%--------------------------------------------------------------------
%%% Internal functions
@@ -218,16 +288,8 @@ suites(Minor) when Minor == 3 ->
%%%% HMAC and the Pseudorandom Functions RFC 2246 & 4346 - 5.%%%%
hmac_hash(?NULL, _, _) ->
<<>>;
-hmac_hash(?MD5, Key, Value) ->
- crypto:md5_mac(Key, Value);
-hmac_hash(?SHA, Key, Value) ->
- crypto:sha_mac(Key, Value);
-hmac_hash(?SHA256, Key, Value) ->
- crypto:sha256_mac(Key, Value);
-hmac_hash(?SHA384, Key, Value) ->
- crypto:sha384_mac(Key, Value);
-hmac_hash(?SHA512, Key, Value) ->
- crypto:sha512_mac(Key, Value).
+hmac_hash(Alg, Key, Value) ->
+ crypto:hmac(mac_algo(Alg), Key, Value).
mac_algo(?MD5) -> md5;
mac_algo(?SHA) -> sha;
@@ -303,3 +365,68 @@ finished_label(client) ->
<<"client finished">>;
finished_label(server) ->
<<"server finished">>.
+
+%% list ECC curves in prefered order
+ecc_curves(_Minor) ->
+ [?sect571r1,?sect571k1,?secp521r1,?sect409k1,?sect409r1,
+ ?secp384r1,?sect283k1,?sect283r1,?secp256k1,?secp256r1,
+ ?sect239k1,?sect233k1,?sect233r1,?secp224k1,?secp224r1,
+ ?sect193r1,?sect193r2,?secp192k1,?secp192r1,?sect163k1,
+ ?sect163r1,?sect163r2,?secp160k1,?secp160r1,?secp160r2].
+
+%% ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005)
+oid_to_enum(?sect163k1) -> 1;
+oid_to_enum(?sect163r1) -> 2;
+oid_to_enum(?sect163r2) -> 3;
+oid_to_enum(?sect193r1) -> 4;
+oid_to_enum(?sect193r2) -> 5;
+oid_to_enum(?sect233k1) -> 6;
+oid_to_enum(?sect233r1) -> 7;
+oid_to_enum(?sect239k1) -> 8;
+oid_to_enum(?sect283k1) -> 9;
+oid_to_enum(?sect283r1) -> 10;
+oid_to_enum(?sect409k1) -> 11;
+oid_to_enum(?sect409r1) -> 12;
+oid_to_enum(?sect571k1) -> 13;
+oid_to_enum(?sect571r1) -> 14;
+oid_to_enum(?secp160k1) -> 15;
+oid_to_enum(?secp160r1) -> 16;
+oid_to_enum(?secp160r2) -> 17;
+oid_to_enum(?secp192k1) -> 18;
+oid_to_enum(?secp192r1) -> 19;
+oid_to_enum(?secp224k1) -> 20;
+oid_to_enum(?secp224r1) -> 21;
+oid_to_enum(?secp256k1) -> 22;
+oid_to_enum(?secp256r1) -> 23;
+oid_to_enum(?secp384r1) -> 24;
+oid_to_enum(?secp521r1) -> 25.
+
+enum_to_oid(1) -> ?sect163k1;
+enum_to_oid(2) -> ?sect163r1;
+enum_to_oid(3) -> ?sect163r2;
+enum_to_oid(4) -> ?sect193r1;
+enum_to_oid(5) -> ?sect193r2;
+enum_to_oid(6) -> ?sect233k1;
+enum_to_oid(7) -> ?sect233r1;
+enum_to_oid(8) -> ?sect239k1;
+enum_to_oid(9) -> ?sect283k1;
+enum_to_oid(10) -> ?sect283r1;
+enum_to_oid(11) -> ?sect409k1;
+enum_to_oid(12) -> ?sect409r1;
+enum_to_oid(13) -> ?sect571k1;
+enum_to_oid(14) -> ?sect571r1;
+enum_to_oid(15) -> ?secp160k1;
+enum_to_oid(16) -> ?secp160r1;
+enum_to_oid(17) -> ?secp160r2;
+enum_to_oid(18) -> ?secp192k1;
+enum_to_oid(19) -> ?secp192r1;
+enum_to_oid(20) -> ?secp224k1;
+enum_to_oid(21) -> ?secp224r1;
+enum_to_oid(22) -> ?secp256k1;
+enum_to_oid(23) -> ?secp256r1;
+enum_to_oid(24) -> ?secp384r1;
+enum_to_oid(25) -> ?secp521r1.
+
+sufficent_ec_support() ->
+ CryptoSupport = crypto:supports(),
+ proplists:get_bool(ecdh, proplists:get_value(public_keys, CryptoSupport)).