From 522bbf7053358d6c150a04a4bbf2ea539797f315 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Thu, 20 Sep 2012 14:28:47 +0200 Subject: SSL: add TLS PSK (RFC 4279 and RFC 5487) cipher suites --- lib/ssl/src/ssl.erl | 20 ++- lib/ssl/src/ssl_alert.erl | 4 +- lib/ssl/src/ssl_alert.hrl | 2 + lib/ssl/src/ssl_cipher.erl | 172 ++++++++++++++++++++++- lib/ssl/src/ssl_cipher.hrl | 76 ++++++++++ lib/ssl/src/ssl_connection.erl | 307 ++++++++++++++++++++++++++++++++++++++++- lib/ssl/src/ssl_handshake.erl | 130 ++++++++++++++++- lib/ssl/src/ssl_handshake.hrl | 28 +++- lib/ssl/src/ssl_internal.hrl | 2 + 9 files changed, 725 insertions(+), 16 deletions(-) (limited to 'lib/ssl/src') diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 0ba59cede2..c579ff1ffc 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -65,6 +65,8 @@ {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()} | {ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} | {reuse_session, fun()} | {hibernate_after, integer()|undefined} | {next_protocols_advertised, list(binary())} | @@ -628,6 +630,8 @@ 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), ciphers = handle_option(ciphers, Opts, []), %% Server side option reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun), @@ -647,7 +651,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, ciphers, reuse_session, reuse_sessions, ssl_imp, cb_info, renegotiate_at, secure_renegotiate, hibernate_after, erl_dist, next_protocols_advertised, @@ -749,6 +754,15 @@ 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(ciphers, Value) when is_list(Value) -> Version = ssl_record:highest_protocol_version([]), try cipher_suites(Version, Value) @@ -919,7 +933,9 @@ cipher_suites(Version, [{_,_,_}| _] = Ciphers0) -> Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0], cipher_suites(Version, Ciphers); cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) -> - Supported = ssl_cipher:suites(Version) ++ ssl_cipher:anonymous_suites(), + Supported = ssl_cipher:suites(Version) + ++ ssl_cipher:anonymous_suites() + ++ ssl_cipher:psk_suites(Version), case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported)] of [] -> Supported; 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_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 567690a413..f8de92efb9 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -34,7 +34,7 @@ -export([security_parameters/3, suite_definition/1, decipher/5, cipher/5, - suite/1, suites/1, anonymous_suites/0, + suite/1, suites/1, anonymous_suites/0, psk_suites/1, openssl_suite/1, openssl_suite_name/1, filter/2, hash_algorithm/1, sign_algorithm/1]). @@ -214,6 +214,39 @@ anonymous_suites() -> ?TLS_DH_anon_WITH_AES_128_CBC_SHA256, ?TLS_DH_anon_WITH_AES_256_CBC_SHA256]. +%%-------------------------------------------------------------------- +-spec psk_suites(tls_version()) -> [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 suite_definition(cipher_suite()) -> int_cipher_suite(). %% @@ -297,7 +330,62 @@ 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}. %%-------------------------------------------------------------------- -spec suite(erl_cipher_suite()) -> cipher_suite(). @@ -370,7 +458,62 @@ 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. %%-------------------------------------------------------------------- -spec openssl_suite(openssl_cipher_suite()) -> cipher_suite(). @@ -469,6 +612,18 @@ 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"; + %% No oppenssl name openssl_suite_name(Cipher) -> suite_definition(Cipher). @@ -702,7 +857,8 @@ next_iv(Bin, IV) -> NextIV. rsa_signed_suites() -> - dhe_rsa_suites() ++ rsa_suites(). + dhe_rsa_suites() ++ rsa_suites() ++ + psk_rsa_suites(). dhe_rsa_suites() -> [?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, @@ -712,6 +868,14 @@ 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]. + rsa_suites() -> [?TLS_RSA_WITH_AES_256_CBC_SHA256, ?TLS_RSA_WITH_AES_256_CBC_SHA, diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl index 0f439f8ed5..db6e36741d 100644 --- a/lib/ssl/src/ssl_cipher.hrl +++ b/lib/ssl/src/ssl_cipher.hrl @@ -250,4 +250,80 @@ %% hello extension data as they should. -define(TLS_EMPTY_RENEGOTIATION_INFO_SCSV, <>). +%%% PSK Cipher Suites RFC 4279 + +%% TLS_PSK_WITH_RC4_128_SHA = { 0x00, 0x8A }; +-define(TLS_PSK_WITH_RC4_128_SHA, <>). + +%% TLS_PSK_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x8B }; +-define(TLS_PSK_WITH_3DES_EDE_CBC_SHA, <>). + +%% TLS_PSK_WITH_AES_128_CBC_SHA = { 0x00, 0x8C }; +-define(TLS_PSK_WITH_AES_128_CBC_SHA, <>). + +%% TLS_PSK_WITH_AES_256_CBC_SHA = { 0x00, 0x8D }; +-define(TLS_PSK_WITH_AES_256_CBC_SHA, <>). + +%% TLS_DHE_PSK_WITH_RC4_128_SHA = { 0x00, 0x8E }; +-define(TLS_DHE_PSK_WITH_RC4_128_SHA, <>). + +%% TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x8F }; +-define(TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, <>). + +%% TLS_DHE_PSK_WITH_AES_128_CBC_SHA = { 0x00, 0x90 }; +-define(TLS_DHE_PSK_WITH_AES_128_CBC_SHA, <>). + +%% TLS_DHE_PSK_WITH_AES_256_CBC_SHA = { 0x00, 0x91 }; +-define(TLS_DHE_PSK_WITH_AES_256_CBC_SHA, <>). + +%% TLS_RSA_PSK_WITH_RC4_128_SHA = { 0x00, 0x92 }; +-define(TLS_RSA_PSK_WITH_RC4_128_SHA, <>). + +%% TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x93 }; +-define(TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, <>). + +%% TLS_RSA_PSK_WITH_AES_128_CBC_SHA = { 0x00, 0x94 }; +-define(TLS_RSA_PSK_WITH_AES_128_CBC_SHA, <>). + +%% TLS_RSA_PSK_WITH_AES_256_CBC_SHA = { 0x00, 0x95 }; +-define(TLS_RSA_PSK_WITH_AES_256_CBC_SHA, <>). + +%%% 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, <>). + +%% TLS_PSK_WITH_AES_256_CBC_SHA384 = {0x00,0xAF}; +-define(TLS_PSK_WITH_AES_256_CBC_SHA384, <>). + +%% TLS_PSK_WITH_NULL_SHA256 = {0x00,0xB0}; +-define(TLS_PSK_WITH_NULL_SHA256, <>). + +%% TLS_PSK_WITH_NULL_SHA384 = {0x00,0xB1}; +-define(TLS_PSK_WITH_NULL_SHA384, <>). + +%% TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = {0x00,0xB2}; +-define(TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, <>). + +%% TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = {0x00,0xB3}; +-define(TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, <>). + +%% TLS_DHE_PSK_WITH_NULL_SHA256 = {0x00,0xB4}; +-define(TLS_DHE_PSK_WITH_NULL_SHA256, <>). + +%% TLS_DHE_PSK_WITH_NULL_SHA384 = {0x00,0xB5}; +-define(TLS_DHE_PSK_WITH_NULL_SHA384, <>). + +%% TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 = {0x00,0xB6}; +-define(TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, <>). + +%% TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 = {0x00,0xB7}; +-define(TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, <>). + +%% TLS_RSA_PSK_WITH_NULL_SHA256 = {0x00,0xB8}; +-define(TLS_RSA_PSK_WITH_NULL_SHA256, <>). + +%% TLS_RSA_PSK_WITH_NULL_SHA384 = {0x00,0xB9}; +-define(TLS_RSA_PSK_WITH_NULL_SHA384, <>). + -endif. % -ifdef(ssl_cipher). diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 8f4fd88d42..7d5828c61b 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -81,6 +81,7 @@ 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 premaster_secret, % file_ref_db, % ets() cert_db_ref, % ref() @@ -522,7 +523,8 @@ 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 == dh_anon; + Alg == psk; Alg == dhe_psk; Alg == rsa_psk -> case handle_server_key(KeyExchangeMsg, State0) of #state{} = State1 -> {Record, State} = next_record(State1), @@ -539,6 +541,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 = <>, + 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, @@ -625,6 +666,46 @@ certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPubl 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 dhe_psk_master_secret(ClientPSKIdentity, crypto:mpint(P), crypto:mpint(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. %%-------------------------------------------------------------------- @@ -1439,7 +1520,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 == psk; Algo == dhe_psk -> State; certify_server(#state{transport_cb = Transport, @@ -1494,6 +1576,90 @@ key_exchange(#state{role = server, key_algorithm = Algo, diffie_hellman_keys = Keys, tls_handshake_history = Handshake}; +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'{prime = P, base = G} = Params, + private_key = PrivateKey, + connection_states = ConnectionStates0, + negotiated_version = Version, + tls_handshake_history = Handshake0, + socket = Socket, + transport_cb = Transport + } = State) -> + Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]), + 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, Keys, 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 = Keys, + 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 = client, connection_states = ConnectionStates0, key_algorithm = rsa, @@ -1522,6 +1688,51 @@ key_exchange(#state{role = client, {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}. @@ -1541,6 +1752,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, @@ -1659,7 +1886,19 @@ 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_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). master_from_premaster_secret(PremasterSecret, #state{session = Session, @@ -1689,6 +1928,63 @@ dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State) -> [PMpint, GMpint]), 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 = <>, + 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) -> + PMpint = mpint_binary(Prime), + GMpint = mpint_binary(Base), + Keys = {_, PrivateDhKey} = + crypto:dh_generate_key([PMpint,GMpint]), + dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey, + State#state{diffie_hellman_keys = Keys}); + +dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, 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:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey, + [PMpint, GMpint]), + DHLen = erlang:byte_size(DHSecret), + Len = erlang:byte_size(PSK), + PremasterSecret = <>, + 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 = <>, + master_from_premaster_secret(RealPMS, State); + #alert{} = Alert -> + Alert; + _ -> + ?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, @@ -2500,7 +2796,10 @@ default_hashsign(_Version, KeyExchange) KeyExchange == dh_dss -> {sha, dsa}; default_hashsign(_Version, KeyExchange) - when KeyExchange == dh_anon -> + when KeyExchange == dh_anon; + KeyExchange == psk; + KeyExchange == dhe_psk; + KeyExchange == rsa_psk -> {null, anon}. start_or_recv_cancel_timer(infinity, _RecvFrom) -> diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 1929370991..f878e18449 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -375,6 +375,8 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) -> {premaster_secret, binary(), public_key_info()} | {dh, binary()} | {dh, {binary(), binary()}, #'DHParameter'{}, {HashAlgo::atom(), SignAlgo::atom()}, + {psk, binary()} | + {dhe_psk, binary(), binary()}, binary(), binary(), private_key()}) -> #client_key_exchange{} | #server_key_exchange{}. %% @@ -391,6 +393,27 @@ key_exchange(client, _Version, {dh, <>}) -> dh_public = PublicKey} }; +key_exchange(client, _Version, {psk, Identity}) -> + #client_key_exchange{ + exchange_keys = #client_psk_identity{ + identity = Identity} + }; + +key_exchange(client, _Version, {dhe_psk, Identity, <>}) -> + #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(server, Version, {dh, {<>, _}, #'DHParameter'{prime = P, base = G}, HashSign, ClientRandom, ServerRandom, PrivateKey}) -> @@ -399,6 +422,25 @@ key_exchange(server, Version, {dh, {<>, _}, ServerDHParams = #server_dh_params{dh_p = PBin, dh_g = GBin, dh_y = PublicKey}, enc_server_key_exchange(Version, ServerDHParams, 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, {<>, _}, + #'DHParameter'{prime = P, base = G}, + HashSign, ClientRandom, ServerRandom, PrivateKey}) -> + <> = crypto:mpint(P), + <> = crypto:mpint(G), + ServerEDHPSKParams = #server_dhe_psk_params{ + hint = PskIdentityHint, + dh_params = #server_dh_params{dh_p = PBin, + dh_g = GBin, dh_y = PublicKey} + }, + enc_server_key_exchange(Version, ServerEDHPSKParams, HashSign, ClientRandom, ServerRandom, PrivateKey). enc_server_key_exchange(Version, Params, {HashAlgo, SignAlgo}, @@ -528,7 +570,11 @@ 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_psk_identity{} + | #client_dhe_psk_identity{} + | #client_rsa_psk_identity{}. %% %% Description: Decode client_key data and return appropriate type %%-------------------------------------------------------------------- @@ -1036,7 +1082,20 @@ dec_client_key(<<>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) -> throw(?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE)); dec_client_key(<>, ?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_PSK, _) -> + #client_psk_identity{identity = Id}; +dec_client_key(<>, + ?KEY_EXCHANGE_DHE_PSK, _) -> + #client_dhe_psk_identity{identity = Id, dh_public = DH_Y}; +dec_client_key(<>, + ?KEY_EXCHANGE_RSA_PSK, {3, 0}) -> + #client_rsa_psk_identity{identity = Id, exchange_keys = #encrypted_premaster_secret{premaster_secret = PKEPMS}}; +dec_client_key(<>, + ?KEY_EXCHANGE_RSA_PSK, _) -> + #client_rsa_psk_identity{identity = Id, exchange_keys = #encrypted_premaster_secret{premaster_secret = PKEPMS}}. dec_ske_params(Len, Keys, Version) -> <> = Keys, @@ -1071,6 +1130,30 @@ dec_server_key(<> = 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(<> = 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(_, _, _) -> throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)). @@ -1238,13 +1321,46 @@ enc_cke(#encrypted_premaster_secret{premaster_secret = PKEPMS}, _) -> <>; enc_cke(#client_diffie_hellman_public{dh_public = DHPublic}, _) -> Len = byte_size(DHPublic), - <>. + <>; +enc_cke(#client_psk_identity{identity = undefined}, _) -> + Id = <<"psk_identity">>, + Len = byte_size(Id), + <>; +enc_cke(#client_psk_identity{identity = Id}, _) -> + Len = byte_size(Id), + <>; +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), + <>; +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), + <>. 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), - <>. + <>; +enc_server_key(#server_psk_params{hint = PskIdentityHint}) -> + Len = byte_size(PskIdentityHint), + <>; +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), + <>. enc_sign({_, anon}, _Sign, _Version) -> <<>>; @@ -1402,6 +1518,12 @@ 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(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(_) -> ?NULL. diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl index 2414d5b666..e35f68409e 100644 --- a/lib/ssl/src/ssl_handshake.hrl +++ b/lib/ssl/src/ssl_handshake.hrl @@ -128,6 +128,9 @@ -define(KEY_EXCHANGE_RSA, 0). -define(KEY_EXCHANGE_DIFFIE_HELLMAN, 1). +-define(KEY_EXCHANGE_PSK, 2). +-define(KEY_EXCHANGE_DHE_PSK, 3). +-define(KEY_EXCHANGE_RSA_PSK, 4). -record(server_rsa_params, { rsa_modulus, %% opaque RSA_modulus<1..2^16-1> @@ -139,7 +142,16 @@ dh_g, %% opaque DH_g<1..2^16-1> dh_y %% opaque DH_Ys<1..2^16-1> }). - + +-record(server_psk_params, { + hint + }). + +-record(server_dhe_psk_params, { + hint, + dh_params + }). + -record(server_key_exchange, { exchange_keys }). @@ -209,6 +221,20 @@ dh_public }). +-record(client_psk_identity, { + identity + }). + +-record(client_dhe_psk_identity, { + identity, + dh_public + }). + +-record(client_rsa_psk_identity, { + identity, + exchange_keys + }). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Certificate verify - RFC 4346 section 7.4.8 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index ed0dc34adf..fc441a3f01 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -90,6 +90,8 @@ cacertfile, % file() dh, % der_encoded() dhfile, % file() + user_lookup_fun, % server option, fun to lookup the user + psk_identity, % binary ciphers, % %% Local policy for the server if it want's to reuse the session %% or not. Defaluts to allways returning true. -- cgit v1.2.1 From 31296a676698178837c01d8f09e3518f0fb93f60 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Thu, 20 Sep 2012 14:42:40 +0200 Subject: SSL: add TLS-SRP (RFC 5054) cipher suites --- lib/ssl/src/Makefile | 3 +- lib/ssl/src/ssl.app.src | 1 + lib/ssl/src/ssl.erl | 13 +- lib/ssl/src/ssl_cipher.erl | 114 +++++++++- lib/ssl/src/ssl_cipher.hrl | 29 +++ lib/ssl/src/ssl_connection.erl | 167 +++++++++++++- lib/ssl/src/ssl_handshake.erl | 100 +++++++- lib/ssl/src/ssl_handshake.hrl | 23 ++ lib/ssl/src/ssl_internal.hrl | 1 + lib/ssl/src/ssl_srp.hrl | 31 +++ lib/ssl/src/ssl_srp_primes.erl | 506 +++++++++++++++++++++++++++++++++++++++++ lib/ssl/src/ssl_srp_primes.hrl | 1 + 12 files changed, 964 insertions(+), 25 deletions(-) create mode 100644 lib/ssl/src/ssl_srp.hrl create mode 100644 lib/ssl/src/ssl_srp_primes.erl create mode 100644 lib/ssl/src/ssl_srp_primes.hrl (limited to 'lib/ssl/src') diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile index e61f415c84..d3ba76d34e 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 ssl_srp_primes.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 c579ff1ffc..dac9d53f94 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -37,6 +37,7 @@ -include("ssl_record.hrl"). -include("ssl_cipher.hrl"). -include("ssl_handshake.hrl"). +-include("ssl_srp_primes.hrl"). -include_lib("public_key/include/public_key.hrl"). @@ -67,6 +68,7 @@ {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())} | @@ -632,6 +634,7 @@ handle_options(Opts0, _Role) -> 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), @@ -652,7 +655,7 @@ handle_options(Opts0, _Role) -> fail_if_no_peer_cert, verify_client_once, depth, cert, certfile, key, keyfile, password, cacerts, cacertfile, dh, dhfile, - user_lookup_fun, psk_identity, ciphers, + 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, @@ -763,6 +766,11 @@ 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) @@ -935,7 +943,8 @@ cipher_suites(Version, [{_,_,_}| _] = Ciphers0) -> cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) -> Supported = ssl_cipher:suites(Version) ++ ssl_cipher:anonymous_suites() - ++ ssl_cipher:psk_suites(Version), + ++ ssl_cipher:psk_suites(Version) + ++ ssl_cipher:srp_suites(), case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported)] of [] -> Supported; diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index f8de92efb9..ad3f91f299 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -34,7 +34,7 @@ -export([security_parameters/3, suite_definition/1, decipher/5, cipher/5, - suite/1, suites/1, anonymous_suites/0, psk_suites/1, + suite/1, suites/1, anonymous_suites/0, psk_suites/1, srp_suites/0, openssl_suite/1, openssl_suite_name/1, filter/2, hash_algorithm/1, sign_algorithm/1]). @@ -247,6 +247,23 @@ psk_suites(_) -> ?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(). %% @@ -385,7 +402,29 @@ suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA384) -> 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}. + {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}. + %%-------------------------------------------------------------------- -spec suite(erl_cipher_suite()) -> cipher_suite(). @@ -513,7 +552,28 @@ suite({dhe_psk, null, sha384}) -> suite({rsa_psk, null, sha256}) -> ?TLS_RSA_PSK_WITH_NULL_SHA256; suite({rsa_psk, null, sha384}) -> - ?TLS_RSA_PSK_WITH_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. %%-------------------------------------------------------------------- -spec openssl_suite(openssl_cipher_suite()) -> cipher_suite(). @@ -558,7 +618,24 @@ 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. + + %%-------------------------------------------------------------------- -spec openssl_suite_name(cipher_suite()) -> openssl_cipher_suite(). %% @@ -624,6 +701,21 @@ openssl_suite_name(?TLS_PSK_WITH_AES_128_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"; + %% No oppenssl name openssl_suite_name(Cipher) -> suite_definition(Cipher). @@ -858,7 +950,7 @@ next_iv(Bin, IV) -> rsa_signed_suites() -> dhe_rsa_suites() ++ rsa_suites() ++ - psk_rsa_suites(). + psk_rsa_suites() ++ srp_rsa_suites(). dhe_rsa_suites() -> [?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, @@ -876,6 +968,11 @@ psk_rsa_suites() -> ?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, @@ -887,7 +984,7 @@ rsa_suites() -> ?TLS_RSA_WITH_DES_CBC_SHA]. dsa_signed_suites() -> - dhe_dss_suites(). + dhe_dss_suites() ++ srp_dss_suites(). dhe_dss_suites() -> [?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, @@ -897,6 +994,11 @@ dhe_dss_suites() -> ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA, ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA]. +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]. + filter_rsa(OtpCert, RsaCiphers) -> TBSCert = OtpCert#'OTPCertificate'.tbsCertificate, TBSExtensions = TBSCert#'OTPTBSCertificate'.extensions, diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl index db6e36741d..90d3704efd 100644 --- a/lib/ssl/src/ssl_cipher.hrl +++ b/lib/ssl/src/ssl_cipher.hrl @@ -326,4 +326,33 @@ %% TLS_RSA_PSK_WITH_NULL_SHA384 = {0x00,0xB9}; -define(TLS_RSA_PSK_WITH_NULL_SHA384, <>). +%%% SRP Cipher Suites RFC 5054 + +%% TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = { 0xC0,0x1A }; +-define(TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA, <>). + +%% TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0,0x1B }; +-define(TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, <>). + +%% TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = { 0xC0,0x1C }; +-define(TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, <>). + +%% TLS_SRP_SHA_WITH_AES_128_CBC_SHA = { 0xC0,0x1D }; +-define(TLS_SRP_SHA_WITH_AES_128_CBC_SHA, <>). + +%% TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = { 0xC0,0x1E }; +-define(TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, <>). + +%% TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = { 0xC0,0x1F }; +-define(TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, <>). + +%% TLS_SRP_SHA_WITH_AES_256_CBC_SHA = { 0xC0,0x20 }; +-define(TLS_SRP_SHA_WITH_AES_256_CBC_SHA, <>). + +%% TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = { 0xC0,0x21 }; +-define(TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, <>). + +%% TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = { 0xC0,0x22 }; +-define(TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, <>). + -endif. % -ifdef(ssl_cipher). diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 7d5828c61b..59f5a6a399 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -34,6 +34,8 @@ -include("ssl_record.hrl"). -include("ssl_cipher.hrl"). -include("ssl_internal.hrl"). +-include("ssl_srp.hrl"). +-include("ssl_srp_primes.hrl"). -include_lib("public_key/include/public_key.hrl"). %% Internal application API @@ -82,6 +84,8 @@ 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() @@ -524,7 +528,8 @@ 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; - Alg == psk; Alg == dhe_psk; Alg == rsa_psk -> + 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), @@ -706,6 +711,20 @@ certify_client_key_exchange(#client_rsa_psk_identity{ 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); + #alert{} = Alert -> + handle_own_alert(Alert, Version, certify, State0) end. %%-------------------------------------------------------------------- @@ -1660,6 +1679,44 @@ key_exchange(#state{role = server, key_algorithm = rsa_psk, 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, connection_states = ConnectionStates0, key_algorithm = rsa, @@ -1733,6 +1790,23 @@ key_exchange(#state{role = client, {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 = {ClntPubKey, _}, + 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, ClntPubKey}), + {BinMsg, ConnectionStates, Handshake} = + encode_handshake(Msg, Version, ConnectionStates0, Handshake0), + Transport:send(Socket, BinMsg), State#state{connection_states = ConnectionStates, tls_handshake_history = Handshake}. @@ -1898,7 +1972,11 @@ 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). + 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, @@ -1985,6 +2063,79 @@ server_rsa_psk_master_secret(PskIdentity, PremasterSecret, ?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) -> + Private = ssl:random_bytes(32), + Multiplier = crypto:srp6a_multiplier(Generator, Prime), + case crypto:srp_value_B(Multiplier, Verifier, Generator, Private, Prime) of + error -> + generate_srp_server_keys(SrpParams, N+1); + Public -> {Public, Private} + end. + +generate_srp_client_keys(_Generator, _Prime, 10) -> + ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER); +generate_srp_client_keys(Generator, Prime, N) -> + Private = ssl:random_bytes(32), + case crypto:srp_mod_exp(Generator, Private, Prime) of + error -> + generate_srp_client_keys(Generator, Prime, N+1); + Public -> {Public, Private} + end. + +handle_srp_identity(Username, {Fun, UserState}) -> + case Fun(srp, Username, UserState) of + {ok, {SRPParams, Salt, UserPassHash}} + when is_atom(SRPParams), is_binary(Salt), is_binary(UserPassHash) -> + {Generator, Prime} = ssl_srp_primes:get_srp_params(SRPParams), + Verifier = crypto:srp_mod_exp(Generator, UserPassHash, 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, ClntPub, State = #state{srp_keys = {SrvrPub, SrvrPriv}}) -> + U = crypto:srp6_value_u(ClntPub, SrvrPub, Prime), + case crypto:srp_server_secret(Verifier, SrvrPriv, U, ClntPub, Prime) of + error -> + ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER); + PremasterSecret -> + master_from_premaster_secret(PremasterSecret, State) + end. + +client_srp_master_secret(_Generator, _Prime, _Salt, _SrvrPub, #alert{} = Alert, _State) -> + Alert; +client_srp_master_secret(Generator, Prime, Salt, SrvrPub, undefined, State) -> + Keys = generate_srp_client_keys(Generator, Prime, 0), + client_srp_master_secret(Generator, Prime, Salt, SrvrPub, Keys, State#state{srp_keys = Keys}); + +client_srp_master_secret(Generator, Prime, Salt, SrvrPub, {ClntPub, ClntPriv}, + #state{ssl_options = SslOpts} = State) -> + case ssl_srp_primes:check_srp_params(Generator, Prime) of + ok -> + {Username, Password} = SslOpts#ssl_options.srp_identity, + UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), + + Multiplier = crypto:srp6a_multiplier(Generator, Prime), + U = crypto:srp6_value_u(ClntPub, SrvrPub, Prime), + case crypto:srp_client_secret(ClntPriv, U, SrvrPub, Multiplier, + Generator, UserPassHash, Prime) 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, @@ -2784,22 +2935,26 @@ 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 == srp_rsa) -> {sha, rsa}; default_hashsign(_Version, KeyExchange) when KeyExchange == rsa; KeyExchange == dhe_rsa; - KeyExchange == dh_rsa -> + KeyExchange == dh_rsa; + KeyExchange == srp_rsa -> {md5sha, rsa}; 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; KeyExchange == psk; KeyExchange == dhe_psk; - KeyExchange == rsa_psk -> + KeyExchange == rsa_psk; + KeyExchange == srp_anon -> {null, anon}. start_or_recv_cancel_timer(infinity, _RecvFrom) -> diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index f878e18449..3c4bf5e2c7 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -28,6 +28,7 @@ -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, @@ -69,6 +70,7 @@ client_hello(Host, Port, ConnectionStates, Pending = ssl_record:pending_connection_state(ConnectionStates, read), SecParams = Pending#connection_state.security_parameters, Ciphers = available_suites(UserSuites, Version), + SRP = srp_user(SslOpts), Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert), @@ -80,6 +82,7 @@ client_hello(Host, Port, ConnectionStates, renegotiation_info = renegotiation_info(client, ConnectionStates, Renegotiation), + srp = SRP, hash_signs = default_hash_signs(), next_protocol_negotiation = encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector, Renegotiation) @@ -165,7 +168,8 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version, hello(#client_hello{client_version = ClientVersion, random = Random, cipher_suites = CipherSuites, - renegotiation_info = Info} = Hello, + renegotiation_info = Info, + srp = SRP} = Hello, #ssl_options{versions = Versions, secure_renegotiate = SecureRenegotation} = SslOpts, {Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) -> @@ -174,13 +178,14 @@ hello(#client_hello{client_version = ClientVersion, random = Random, case ssl_record:is_acceptable_version(Version) of true -> {Type, #session{cipher_suite = CipherSuite, - compression_method = Compression} = Session} + compression_method = Compression} = Session1} = select_session(Hello, Port, Session0, Version, SslOpts, Cache, CacheCb, Cert), case CipherSuite of no_suite -> ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY); _ -> + Session = handle_srp_info(SRP, Session1), case handle_renegotiation_info(server, Info, ConnectionStates0, Renegotiation, SecureRenegotation, CipherSuites) of @@ -375,8 +380,10 @@ 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()} | {psk, binary()} | - {dhe_psk, binary(), binary()}, + {dhe_psk, binary(), binary()} | + {srp, {binary(), binary()}, #srp_user{}, {HashAlgo::atom(), SignAlgo::atom()}, binary(), binary(), private_key()}) -> #client_key_exchange{} | #server_key_exchange{}. %% @@ -414,6 +421,12 @@ key_exchange(client, _Version, {psk_premaster_secret, PskIdentity, Secret, {_, P 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, {<>, _}, #'DHParameter'{prime = P, base = G}, HashSign, ClientRandom, ServerRandom, PrivateKey}) -> @@ -440,7 +453,16 @@ key_exchange(server, Version, {dhe_psk, PskIdentityHint, {< + 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}, @@ -574,7 +596,8 @@ get_tls_handshake(Version, Data, Buffer) -> | #client_diffie_hellman_public{} | #client_psk_identity{} | #client_dhe_psk_identity{} - | #client_rsa_psk_identity{}. + | #client_rsa_psk_identity{} + | #client_srp_public{}. %% %% Description: Decode client_key data and return appropriate type %%-------------------------------------------------------------------- @@ -726,6 +749,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) -> @@ -808,6 +836,11 @@ select_next_protocol(Protocols, NextProtocolSelector) -> Protocol end. +handle_srp_info(undefined, Session) -> + Session; +handle_srp_info(#srp{username = Username}, Session) -> + Session#session{srp_username = Username}. + handle_renegotiation_info(_, #renegotiation_info{renegotiated_connection = ?byte(0)}, ConnectionStates, false, _, _) -> {ok, ssl_record:set_renegotiation_flag(true, ConnectionStates)}; @@ -994,6 +1027,7 @@ dec_hs(_Version, ?CLIENT_HELLO, <>, #client_rsa_psk_identity{identity = Id, exchange_keys = #encrypted_premaster_secret{premaster_secret = PKEPMS}}; dec_client_key(<>, ?KEY_EXCHANGE_RSA_PSK, _) -> - #client_rsa_psk_identity{identity = Id, exchange_keys = #encrypted_premaster_secret{premaster_secret = PKEPMS}}. + #client_rsa_psk_identity{identity = Id, exchange_keys = #encrypted_premaster_secret{premaster_secret = PKEPMS}}; +dec_client_key(<>, + ?KEY_EXCHANGE_SRP, _) -> + #client_srp_public{srp_a = A}. dec_ske_params(Len, Keys, Version) -> <> = Keys, @@ -1154,6 +1192,17 @@ dec_server_key(<> = 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)). @@ -1181,6 +1230,11 @@ dec_hello_extensions(<>, Acc) + when Len == SRPLen + 2 -> + dec_hello_extensions(Rest, [{srp, + #srp{username = SRP}} | Acc]); + dec_hello_extensions(<>, Acc) -> SignAlgoListLen = Len - 2, @@ -1238,6 +1292,7 @@ enc_hs(#client_hello{client_version = {Major, Minor}, cipher_suites = CipherSuites, compression_methods = CompMethods, renegotiation_info = RenegotiationInfo, + srp = SRP, hash_signs = HashSigns, next_protocol_negotiation = NextProtocolNegotiation}, _Version) -> SIDLength = byte_size(SessionID), @@ -1245,7 +1300,7 @@ enc_hs(#client_hello{client_version = {Major, Minor}, CmLength = byte_size(BinCompMethods), BinCipherSuites = list_to_binary(CipherSuites), CsLength = byte_size(BinCipherSuites), - Extensions0 = hello_extensions(RenegotiationInfo, NextProtocolNegotiation), + Extensions0 = hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation), Extensions1 = if Major == 3, Minor >=3 -> Extensions0 ++ hello_extensions(HashSigns); true -> Extensions0 @@ -1340,7 +1395,10 @@ enc_cke(Identity = #client_rsa_psk_identity{identity = undefined}, Version) -> enc_cke(#client_rsa_psk_identity{identity = Id, exchange_keys = ExchangeKeys}, Version) -> EncPMS = enc_cke(ExchangeKeys, Version), Len = byte_size(Id), - <>. + <>; +enc_cke(#client_srp_public{srp_a = A}, _) -> + Len = byte_size(A), + <>. enc_server_key(#server_dh_params{dh_p = P, dh_g = G, dh_y = Y}) -> PLen = byte_size(P), @@ -1360,7 +1418,14 @@ enc_server_key(#server_dhe_psk_params{ GLen = byte_size(G), YLen = byte_size(Y), <>. + ?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), + <>. enc_sign({_, anon}, _Sign, _Version) -> <<>>; @@ -1376,13 +1441,20 @@ enc_sign(_HashSign, Sign, _Version) -> 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). + %% 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) -> []; @@ -1409,6 +1481,11 @@ enc_hello_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest Len = InfoLen +1, enc_hello_extensions(Rest, <>); +enc_hello_extensions([#srp{username = UserName} | Rest], Acc) -> + SRPLen = byte_size(UserName), + Len = SRPLen + 2, + enc_hello_extensions(Rest, <>); + 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 >>, @@ -1524,6 +1601,9 @@ 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. diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl index e35f68409e..1fbb88f5f6 100644 --- a/lib/ssl/src/ssl_handshake.hrl +++ b/lib/ssl/src/ssl_handshake.hrl @@ -48,6 +48,7 @@ compression_method, cipher_suite, master_secret, + srp_username, is_resumable, time_stamp }). @@ -99,6 +100,7 @@ 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 next_protocol_negotiation = undefined % [binary()] }). @@ -131,6 +133,7 @@ -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> @@ -152,6 +155,13 @@ 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 }). @@ -235,6 +245,10 @@ exchange_keys }). +-record(client_srp_public, { + srp_a + }). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Certificate verify - RFC 4346 section 7.4.8 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -260,6 +274,15 @@ renegotiated_connection }). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% SRP RFC 5054 section 2.8.1. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-define(SRP_EXT, 12). + +-record(srp, { + username + }). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Signature Algorithms RFC 5746 section 7.4.1.4.1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index fc441a3f01..96a1c8e1ce 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -92,6 +92,7 @@ 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_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_srp_primes.hrl b/lib/ssl/src/ssl_srp_primes.hrl new file mode 100644 index 0000000000..4bd534efbf --- /dev/null +++ b/lib/ssl/src/ssl_srp_primes.hrl @@ -0,0 +1 @@ +-type srp_parameters() :: srp_1024 | srp_1536 | srp_2048 | srp_3072 | srp_4096 | srp_6144 | srp_8192. -- cgit v1.2.1 From 0e4e6cfc4e3cb0b28598ca9a9db5e6a896027435 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Fri, 12 Oct 2012 14:58:11 +0200 Subject: SSL: enable hash_size values for sha224, sha384 and sha512 Some of the PSK and SRP ciphers default to sha384, this enables hash_size for that cipher. It also adds sha512 and sha224 to be prepared for further cipher enhancements. --- lib/ssl/src/ssl_cipher.erl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'lib/ssl/src') diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index ad3f91f299..e3231effd4 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -852,14 +852,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 %% -- cgit v1.2.1 From 2da38637a507e35d4b2ea9d4aba1983ea28c2898 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Tue, 19 Feb 2013 17:31:54 +0100 Subject: SSL: replace sha256_mac() tests with crypto:algorithms() --- lib/ssl/src/ssl_record.erl | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'lib/ssl/src') diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl index 173b9611c6..5101beeac8 100644 --- a/lib/ssl/src/ssl_record.erl +++ b/lib/ssl/src/ssl_record.erl @@ -704,12 +704,4 @@ 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. + proplists:get_bool(sha256, crypto:algorithms()). -- cgit v1.2.1 From d0f06594e4c441a182fbc18a65222ae62ca44425 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Tue, 19 Feb 2013 18:06:26 +0100 Subject: SSL: filter TLS cipher suites for supported algorithms --- lib/ssl/src/ssl.erl | 17 ++++++++-------- lib/ssl/src/ssl_cipher.erl | 48 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 9 deletions(-) (limited to 'lib/ssl/src') diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index dac9d53f94..5a1c8bb731 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -364,11 +364,11 @@ 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, [])]. %%-------------------------------------------------------------------- -spec getopts(#sslsocket{}, [gen_tcp:option_name()]) -> @@ -933,21 +933,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) + Supported0 = ssl_cipher:suites(Version) ++ ssl_cipher:anonymous_suites() ++ ssl_cipher:psk_suites(Version) ++ ssl_cipher:srp_suites(), - case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported)] of + 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_cipher.erl b/lib/ssl/src/ssl_cipher.erl index e3231effd4..13f599133c 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -35,7 +35,7 @@ -export([security_parameters/3, suite_definition/1, decipher/5, cipher/5, suite/1, suites/1, anonymous_suites/0, psk_suites/1, srp_suites/0, - openssl_suite/1, openssl_suite_name/1, filter/2, + openssl_suite/1, openssl_suite_name/1, filter/2, filter_suites/1, hash_algorithm/1, sign_algorithm/1]). -compile(inline). @@ -737,6 +737,52 @@ filter(DerCert, Ciphers) -> Ciphers -- rsa_signed_suites() end. +%%-------------------------------------------------------------------- +-spec filter_suites([cipher_suite()]) -> [cipher_suite()]. +%% +%% Description: filter suites for algorithms +%%------------------------------------------------------------------- +filter_suites(Suites = [{_,_,_}|_]) -> + Algos = crypto:algorithms(), + lists:filter(fun({KeyExchange, Cipher, Hash}) -> + is_acceptable_keyexchange(KeyExchange, Algos) andalso + is_acceptable_cipher(Cipher, Algos) andalso + is_acceptable_hash(Hash, Algos) + end, Suites); + +filter_suites(Suites = [{_,_,_,_}|_]) -> + Algos = crypto:algorithms(), + lists:filter(fun({KeyExchange, Cipher, Hash, Prf}) -> + is_acceptable_keyexchange(KeyExchange, Algos) andalso + is_acceptable_cipher(Cipher, Algos) andalso + is_acceptable_hash(Hash, Algos) andalso + is_acceptable_prf(Prf, Algos) + end, Suites); + +filter_suites(Suites) -> + Algos = crypto:algorithms(), + lists:filter(fun(Suite) -> + {KeyExchange, Cipher, Hash, Prf} = ssl_cipher:suite_definition(Suite), + is_acceptable_keyexchange(KeyExchange, Algos) andalso + is_acceptable_cipher(Cipher, Algos) andalso + is_acceptable_hash(Hash, Algos) andalso + is_acceptable_prf(Prf, Algos) + end, Suites). + +is_acceptable_keyexchange(_, _) -> + true. + +is_acceptable_cipher(_, _) -> + 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 %%-------------------------------------------------------------------- -- cgit v1.2.1 From af06ccbd2ec182d10b83e772bf807d0171dd3c07 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Thu, 21 Feb 2013 15:02:36 +0100 Subject: SSL: add Elliptic Curve support for ssl app --- lib/ssl/src/ssl.erl | 1 + lib/ssl/src/ssl_certificate.erl | 26 ++- lib/ssl/src/ssl_cipher.erl | 365 +++++++++++++++++++++++++++++++++++++--- lib/ssl/src/ssl_cipher.hrl | 114 +++++++++++++ lib/ssl/src/ssl_connection.erl | 138 ++++++++++++++- lib/ssl/src/ssl_handshake.erl | 122 ++++++++++++-- lib/ssl/src/ssl_handshake.hrl | 42 +++++ lib/ssl/src/ssl_tls1.erl | 93 +++++++++- 8 files changed, 864 insertions(+), 37 deletions(-) (limited to 'lib/ssl/src') diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 5a1c8bb731..8ba58c39a3 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -725,6 +725,7 @@ validate_option(key, {KeyType, Value}) when is_binary(Value), KeyType == dsa; %% Backwards compatibility KeyType == 'RSAPrivateKey'; KeyType == 'DSAPrivateKey'; + KeyType == 'ECPrivateKey'; KeyType == 'PrivateKeyInfo' -> {KeyType, Value}; diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl index 86f5617b54..41ca81e277 100644 --- a/lib/ssl/src/ssl_certificate.erl +++ b/lib/ssl/src/ssl_certificate.erl @@ -38,7 +38,8 @@ is_valid_key_usage/2, select_extension/2, extensions_list/1, - signature_type/1 + signature_type/1, + public_key_type/1 ]). %%==================================================================== @@ -167,7 +168,7 @@ extensions_list(Extensions) -> Extensions. %%-------------------------------------------------------------------- --spec signature_type(term()) -> rsa | dsa . +-spec signature_type(term()) -> rsa | dsa | ecdsa. %% %% Description: %%-------------------------------------------------------------------- @@ -180,7 +181,26 @@ signature_type(RSA) when RSA == ?sha1WithRSAEncryption; -> rsa; signature_type(?'id-dsa-with-sha1') -> - dsa. + dsa; +signature_type(EC) when EC == ?'ecdsa-with-SHA1'; + EC == ?'ecdsa-with-SHA2'; + EC == ?'ecdsa-with-SHA224'; + EC == ?'ecdsa-with-SHA256'; + EC == ?'ecdsa-with-SHA384'; + EC == ?'ecdsa-with-SHA512' -> + ecdsa. + +%%-------------------------------------------------------------------- +-spec public_key_type(term()) -> rsa | dsa | ec. +%% +%% Description: +%%-------------------------------------------------------------------- +public_key_type(?'rsaEncryption') -> + rsa; +public_key_type(?'id-dsa') -> + dsa; +public_key_type(?'id-ecPublicKey') -> + ec. %%-------------------------------------------------------------------- %%% Internal functions diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 13f599133c..7e2277ec72 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -212,7 +212,11 @@ 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()) -> [cipher_suite()]. @@ -423,8 +427,81 @@ suite_definition(?TLS_SRP_SHA_WITH_AES_256_CBC_SHA) -> 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}. - + {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(). @@ -573,7 +650,81 @@ suite({srp_anon, 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. + ?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(). @@ -633,8 +784,62 @@ openssl_suite("SRP-RSA-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. + ?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(). @@ -716,6 +921,61 @@ openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_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). @@ -730,12 +990,25 @@ filter(undefined, Ciphers) -> filter(DerCert, Ciphers) -> OtpCert = public_key:pkix_decode_cert(DerCert, otp), SigAlg = OtpCert#'OTPCertificate'.signatureAlgorithm, + 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()) -- ecdh_suites(), + rsa_suites(), dhe_rsa_suites() ++ ecdhe_rsa_suites()); + dsa -> + (Ciphers -- rsa_signed_suites()) -- ecdsa_signed_suites(); + ec -> + filter_keyuse(OtpCert, (Ciphers -- rsa_keyed_suites()) -- dsa_signed_suites(), + [], ecdhe_ecdsa_suites()) + end, case ssl_certificate:signature_type(SigAlg#'SignatureAlgorithm'.algorithm) of - rsa -> - filter_rsa(OtpCert, Ciphers -- dsa_signed_suites()); - dsa -> - Ciphers -- rsa_signed_suites() - end. + rsa -> Ciphers1 -- ecdsa_signed_suites(); + dsa -> Ciphers1; + ecdsa -> Ciphers1 -- rsa_signed_suites() + end. %%-------------------------------------------------------------------- -spec filter_suites([cipher_suite()]) -> [cipher_suite()]. @@ -769,6 +1042,13 @@ filter_suites(Suites) -> is_acceptable_prf(Prf, Algos) 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(ec, Algos); is_acceptable_keyexchange(_, _) -> true. @@ -995,6 +1275,11 @@ next_iv(Bin, IV) -> NextIV. rsa_signed_suites() -> + dhe_rsa_suites() ++ rsa_suites() ++ + psk_rsa_suites() ++ srp_rsa_suites() ++ + ecdh_rsa_suites() ++ ecdhe_rsa_suites(). + +rsa_keyed_suites() -> dhe_rsa_suites() ++ rsa_suites() ++ psk_rsa_suites() ++ srp_rsa_suites(). @@ -1028,7 +1313,25 @@ 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() ++ srp_dss_suites(). @@ -1045,24 +1348,48 @@ srp_dss_suites() -> ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA]. -filter_rsa(OtpCert, RsaCiphers) -> +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 90d3704efd..d06fb104ba 100644 --- a/lib/ssl/src/ssl_cipher.hrl +++ b/lib/ssl/src/ssl_cipher.hrl @@ -219,6 +219,120 @@ %% TLS_DH_anon_WITH_AES_256_CBC_SHA256 = { 0x00,0x6D }; -define(TLS_DH_anon_WITH_AES_256_CBC_SHA256, <>). +%% RFC 4492 EC TLS suites + +%% ECDH_ECDSA + +%% TLS_ECDH_ECDSA_WITH_NULL_SHA = { 0xC0, 0x01 } +-define(TLS_ECDH_ECDSA_WITH_NULL_SHA, <>). + +%% TLS_ECDH_ECDSA_WITH_RC4_128_SHA = { 0xC0, 0x02 } +-define(TLS_ECDH_ECDSA_WITH_RC4_128_SHA, <>). + +%% TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x03 } +-define(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, <>). + +%% TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x04 } +-define(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, <>). + +%% TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x05 } +-define(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, <>). + +%% ECDHE_ECDSA + +%% TLS_ECDHE_ECDSA_WITH_NULL_SHA = { 0xC0, 0x06 } +-define(TLS_ECDHE_ECDSA_WITH_NULL_SHA, <>). + +%% TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = { 0xC0, 0x07 } +-define(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, <>). + +%% TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x08 } +-define(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, <>). + +%% TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x09 } +-define(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, <>). + +%% TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x0A } +-define(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, <>). + +%% ECDH_RSA + +%% TLS_ECDH_RSA_WITH_NULL_SHA = { 0xC0, 0x0B } +-define(TLS_ECDH_RSA_WITH_NULL_SHA, <>). + +%% TLS_ECDH_RSA_WITH_RC4_128_SHA = { 0xC0, 0x0C } +-define(TLS_ECDH_RSA_WITH_RC4_128_SHA, <>). + +%% TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x0D } +-define(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, <>). + +%% TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x0E } +-define(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, <>). + +%% TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x0F } +-define(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, <>). + +%% ECDHE_RSA + +%% TLS_ECDHE_RSA_WITH_NULL_SHA = { 0xC0, 0x10 } +-define(TLS_ECDHE_RSA_WITH_NULL_SHA, <>). + +%% TLS_ECDHE_RSA_WITH_RC4_128_SHA = { 0xC0, 0x11 } +-define(TLS_ECDHE_RSA_WITH_RC4_128_SHA, <>). + +%% TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x12 } +-define(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, <>). + +%% TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x13 } +-define(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, <>). + +%% TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x14 } +-define(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, <>). + +%% ECDH_anon + +%% TLS_ECDH_anon_WITH_NULL_SHA = { 0xC0, 0x15 } +-define(TLS_ECDH_anon_WITH_NULL_SHA, <>). + +%% TLS_ECDH_anon_WITH_RC4_128_SHA = { 0xC0, 0x16 } +-define(TLS_ECDH_anon_WITH_RC4_128_SHA, <>). + +%% TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x17 } +-define(TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, <>). + +%% TLS_ECDH_anon_WITH_AES_128_CBC_SHA = { 0xC0, 0x18 } +-define(TLS_ECDH_anon_WITH_AES_128_CBC_SHA, <>). + +%% TLS_ECDH_anon_WITH_AES_256_CBC_SHA = { 0xC0, 0x19 } +-define(TLS_ECDH_anon_WITH_AES_256_CBC_SHA, <>). + + +%% RFC 5289 EC TLS suites + +%% TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x23}; +-define(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, <>). + +%% TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x24}; +-define(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, <>). + +%% TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x25}; +-define(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, <>). + +%% TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x26}; +-define(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, <>). + +%% TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x27}; +-define(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, <>). + +%% TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x28}; +-define(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, <>). + +%% TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x29}; +-define(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, <>). + +%% TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x2A}; +-define(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, <>). + %%% Kerberos Cipher Suites %% TLS_KRB5_WITH_DES_CBC_SHA = { 0x00,0x1E }; diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 59f5a6a399..16232e629a 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -527,7 +527,9 @@ 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 @@ -673,6 +675,17 @@ certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPubl 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 = {'ECKey', ECDHKey}} = State0) -> + case ec_dh_master_secret(ECDHKey, 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 @@ -1271,6 +1284,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)) @@ -1284,6 +1298,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)). @@ -1299,9 +1315,29 @@ private_key(#'PrivateKeyInfo'{privateKeyAlgorithm = #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-dsa'}, privateKey = Key}) -> public_key:der_decode('DSAPrivateKey', iolist_to_binary(Key)); + +private_key(#'ECPrivateKey'{privateKey = PrivKey, + parameters = Param, + publicKey = _PubKey}) -> + ECCurve = case Param of + #'OTPECParameters'{ fieldID = FieldId, curve = PCurve, base = Base, order = Order, cofactor = CoFactor } -> + Field = {pubkey_cert_records:supportedCurvesTypes(FieldId#'OTPFieldID'.fieldType), FieldId#'OTPFieldID'.parameters}, + Curve = {list2int(PCurve#'Curve'.a), list2int(PCurve#'Curve'.b), none}, + {Field, Curve, erlang:list_to_binary(Base), Order, CoFactor}; + {namedCurve, OID} -> + pubkey_cert_records:namedCurves(OID) + end, + Key = {ECCurve, list2int(PrivKey), undefined}, + {'ECKey', crypto:term_to_ec_key(Key)}; + private_key(Key) -> Key. +list2int(L) -> + S = length(L) * 8, + <> = erlang:iolist_to_binary(L), + R. + -spec(file_error(_,_) -> no_return()). file_error(File, Throw) -> case Throw of @@ -1350,7 +1386,25 @@ 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', PublicKey}, PublicKeyParams} -> + ECCurve = case PublicKeyParams of + #'OTPECParameters'{ fieldID = FieldId, curve = PCurve, base = Base, order = Order, cofactor = CoFactor } -> + Field = {pubkey_cert_records:supportedCurvesTypes(FieldId#'OTPFieldID'.fieldType), FieldId#'OTPFieldID'.parameters}, + Curve = {list2int(PCurve#'Curve'.a), list2int(PCurve#'Curve'.b), none}, + {Field, Curve, erlang:list_to_binary(Base), Order, CoFactor}; + {namedCurve, OID} -> + pubkey_cert_records:namedCurves(OID) + end, + %% Generate Client ECDH Key + ECClntKey = crypto:ec_key_new(ECCurve), + crypto:ec_key_generate(ECClntKey), + State3 = State1#state{diffie_hellman_keys = {'ECKey', ECClntKey}}, + ec_dh_master_secret(ECClntKey, PublicKey, State3); + + _ -> State1 + end, + {Record, State} = next_record(State2), next_state(certify, certify, Record, State). certify_client(#state{client_certificate_requested = true, role = client, @@ -1540,7 +1594,7 @@ server_hello_done(#state{transport_cb = Transport, tls_handshake_history = Handshake}. certify_server(#state{key_algorithm = Algo} = State) - when Algo == dh_anon; Algo == psk; Algo == dhe_psk -> + when Algo == dh_anon; Algo == ecdh_anon; Algo == psk; Algo == dhe_psk -> State; certify_server(#state{transport_cb = Transport, @@ -1595,6 +1649,43 @@ key_exchange(#state{role = server, key_algorithm = Algo, diffie_hellman_keys = Keys, 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 -> + %%TODO: select prefered curve from extension + + %% Generate Server ECDH Key + ECDHKey = crypto:ec_key_new(secp256k1), + crypto:ec_key_generate(ECDHKey), + Keys = {'ECKey', ECDHKey}, + + 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, Keys, + 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 = Keys, + tls_handshake_history = Handshake1}; + key_exchange(#state{role = server, key_algorithm = psk, ssl_options = #ssl_options{psk_identity = undefined}} = State) -> State; @@ -1748,6 +1839,23 @@ key_exchange(#state{role = client, 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, @@ -1929,7 +2037,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) @@ -1962,6 +2070,15 @@ server_master_secret(#server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDh State) -> dh_master_secret(P, G, ServerPublicDhKey, undefined, State); +server_master_secret(#server_ecdh_params{curve = ECCurve, public = ECServerPubKey}, + State) -> + %% Generate Client ECDH Key + ECClntKey = crypto:ec_key_new(ECCurve), + crypto:ec_key_generate(ECClntKey), + State1 = State#state{diffie_hellman_keys = {'ECKey', ECClntKey}}, + + ec_dh_master_secret(ECClntKey, ECServerPubKey, State1); + server_master_secret(#server_psk_params{ hint = IdentityHint}, State) -> @@ -2006,6 +2123,11 @@ dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State) -> [PMpint, GMpint]), master_from_premaster_secret(PremasterSecret, State). +ec_dh_master_secret(ECKey, ECPoint, State) -> + PremasterSecret = + crypto:ecdh_compute_key(ECKey, ECPoint), + master_from_premaster_secret(PremasterSecret, State). + handle_psk_identity(_PSKIdentity, LookupFun) when LookupFun == undefined -> error; @@ -2936,14 +3058,21 @@ default_hashsign(_Version = {Major, Minor}, KeyExchange) (KeyExchange == rsa orelse KeyExchange == dhe_rsa orelse 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 == 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; @@ -2951,6 +3080,7 @@ default_hashsign(_Version, KeyExchange) {sha, dsa}; default_hashsign(_Version, KeyExchange) when KeyExchange == dh_anon; + KeyExchange == ecdh_anon; KeyExchange == psk; KeyExchange == dhe_psk; KeyExchange == rsa_psk; diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 3c4bf5e2c7..2758676113 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -47,6 +47,8 @@ #client_key_exchange{} | #finished{} | #certificate_verify{} | #hello_request{} | #next_protocol{}. +-define(NAMED_CURVE_TYPE, 3). + %%==================================================================== %% Internal application API %%==================================================================== @@ -84,6 +86,7 @@ client_hello(Host, Port, ConnectionStates, renegotiation_info(client, ConnectionStates, Renegotiation), srp = SRP, hash_signs = default_hash_signs(), + elliptic_curves = #elliptic_curves{elliptic_curve_list = ssl_tls1:ecc_curves(Version)}, next_protocol_negotiation = encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector, Renegotiation) }. @@ -353,9 +356,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{}. @@ -381,6 +385,8 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) -> {dh, binary()} | {dh, {binary(), binary()}, #'DHParameter'{}, {HashAlgo::atom(), SignAlgo::atom()}, binary(), binary(), private_key()} | + {ecdh, {'ECKey', any()}, {HashAlgo::atom(), SignAlgo::atom()}, + binary(), binary(), private_key()} | {psk, binary()} | {dhe_psk, binary(), binary()} | {srp, {binary(), binary()}, #srp_user{}, {HashAlgo::atom(), SignAlgo::atom()}, @@ -400,6 +406,13 @@ key_exchange(client, _Version, {dh, <>}) -> dh_public = PublicKey} }; +key_exchange(client, _Version, {ecdh, {'ECKey', ECDHKey}}) -> + {_, _, ECPublicKey} = crypto:ec_key_to_term(ECDHKey), + #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{ @@ -437,6 +450,13 @@ key_exchange(server, Version, {dh, {<>, _}, enc_server_key_exchange(Version, ServerDHParams, HashSign, ClientRandom, ServerRandom, PrivateKey); +key_exchange(server, Version, {ecdh, {'ECKey', ECKey}, HashSign, ClientRandom, ServerRandom, + PrivateKey}) -> + {ECCurve, _ECPrivKey, ECPubKey} = crypto:ec_key_to_term(ECKey), + ServerECParams = #server_ecdh_params{curve = ECCurve, public = ECPubKey}, + 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}, @@ -1029,6 +1049,8 @@ dec_hs(_Version, ?CLIENT_HELLO, <>) -> #certificate{asn1_certificates = certs_to_list(ASN1Certs)}; @@ -1118,6 +1145,11 @@ dec_client_key(<<>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) -> dec_client_key(<>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) -> #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(<>, + ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, _) -> + #client_ec_diffie_hellman_public{dh_public = DH_Y}; dec_client_key(<>, ?KEY_EXCHANGE_PSK, _) -> #client_psk_identity{identity = Id}; @@ -1168,6 +1200,19 @@ dec_server_key(<> = KeyStruct, + ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, Version) -> + Params = #server_ecdh_params{curve = ssl_tls1:ec_curve_id2nid(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(<> = KeyStruct, KeyExchange, Version) when KeyExchange == ?KEY_EXCHANGE_PSK; KeyExchange == ?KEY_EXCHANGE_RSA_PSK -> @@ -1244,6 +1289,22 @@ dec_hello_extensions(<>, Acc) -> + EllipticCurveListLen = Len - 2, + <> = ExtData, + EllipticCurves = [ssl_tls1:ec_curve_id2nid(X) || <> <= EllipticCurveList], + dec_hello_extensions(Rest, [{elliptic_curves, + #elliptic_curves{elliptic_curve_list = EllipticCurves}} | Acc]); + +dec_hello_extensions(<>, Acc) -> + ECPointFormatListLen = Len - 1, + <> = 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. @@ -1294,13 +1355,16 @@ enc_hs(#client_hello{client_version = {Major, Minor}, renegotiation_info = RenegotiationInfo, srp = SRP, hash_signs = HashSigns, + 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, SRP, NextProtocolNegotiation), + Extensions0 = hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation) + ++ hello_extensions(EllipticCurves) + ++ hello_extensions(#ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]}), Extensions1 = if Major == 3, Minor >=3 -> Extensions0 ++ hello_extensions(HashSigns); true -> Extensions0 @@ -1320,7 +1384,8 @@ enc_hs(#server_hello{server_version = {Major, Minor}, renegotiation_info = RenegotiationInfo, next_protocol_negotiation = NextProtocolNegotiation}, _Version) -> SID_length = byte_size(Session_ID), - Extensions = hello_extensions(RenegotiationInfo, NextProtocolNegotiation), + Extensions = hello_extensions(RenegotiationInfo, NextProtocolNegotiation) + ++ hello_extensions(#ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]}), ExtensionsBin = enc_hello_extensions(Extensions), {?SERVER_HELLO, < enc_cke(#client_diffie_hellman_public{dh_public = DHPublic}, _) -> Len = byte_size(DHPublic), <>; +enc_cke(#client_ec_diffie_hellman_public{dh_public = DHPublic}, _) -> + Len = byte_size(DHPublic), + <>; enc_cke(#client_psk_identity{identity = undefined}, _) -> Id = <<"psk_identity">>, Len = byte_size(Id), @@ -1405,6 +1473,11 @@ enc_server_key(#server_dh_params{dh_p = P, dh_g = G, dh_y = Y}) -> GLen = byte_size(G), YLen = byte_size(Y), <>; +enc_server_key(#server_ecdh_params{curve = ECCurve, public = ECPubKey}) -> + %%TODO: support arbitrary keys + KLen = size(ECPubKey), + <>; enc_server_key(#server_psk_params{hint = PskIdentityHint}) -> Len = byte_size(PskIdentityHint), <>; @@ -1442,13 +1515,19 @@ 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). + hello_extensions(RenegotiationInfo) + ++ hello_extensions(SRP) + ++ next_protocol_extension(NextProtocolNegotiation). %% Renegotiation info hello_extensions(#renegotiation_info{renegotiated_connection = undefined}) -> []; hello_extensions(#renegotiation_info{} = Info) -> [Info]; +hello_extensions(#elliptic_curves{} = Info) -> + [Info]; +hello_extensions(#ec_point_formats{} = Info) -> + [Info]; hello_extensions(#srp{} = Info) -> [Info]; hello_extensions(#hash_sign_algos{} = Info) -> @@ -1480,12 +1559,22 @@ enc_hello_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest InfoLen = byte_size(Info), Len = InfoLen +1, enc_hello_extensions(Rest, <>); - +enc_hello_extensions([#elliptic_curves{elliptic_curve_list = EllipticCurves} | Rest], Acc) -> + EllipticCurveList = << <<(ssl_tls1:ec_nid2curve_id(X)):16>> || X <- EllipticCurves>>, + ListLen = byte_size(EllipticCurveList), + Len = ListLen + 2, + enc_hello_extensions(Rest, <>); +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, <>); enc_hello_extensions([#srp{username = UserName} | Rest], Acc) -> SRPLen = byte_size(UserName), Len = SRPLen + 2, enc_hello_extensions(Rest, <>); - 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 >>, @@ -1520,9 +1609,15 @@ from_2bytes(<>, Acc) -> certificate_types({KeyExchange, _, _, _}) when KeyExchange == rsa; KeyExchange == dhe_dss; - KeyExchange == dhe_rsa -> + KeyExchange == dhe_rsa; + KeyExchange == ecdhe_rsa -> <>; +certificate_types({KeyExchange, _, _, _}) + when KeyExchange == dh_ecdsa; + KeyExchange == dhe_ecdsa -> + <>; + certificate_types(_) -> <>. @@ -1562,7 +1657,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, {'ECKey', _} = Key) -> + public_key:sign({digest, Hash}, HashAlgo, Key). calc_master_secret({3,0}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) -> ssl_ssl3:master_secret(PremasterSecret, ClientRandom, ServerRandom); @@ -1595,6 +1692,10 @@ 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) -> @@ -1619,8 +1720,9 @@ 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_RSA(MD), ?TLSEXT_SIGALG_ECDSA(MD)). default_hash_signs() -> #hash_sign_algos{hash_sign_algos = diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl index 1fbb88f5f6..b9b2d1f91d 100644 --- a/lib/ssl/src/ssl_handshake.hrl +++ b/lib/ssl/src/ssl_handshake.hrl @@ -102,6 +102,7 @@ renegotiation_info, srp, % srp username to send hash_signs, % supported combinations of hashes/signature algos + elliptic_curves, % supported elliptic curver next_protocol_negotiation = undefined % [binary()] }). @@ -113,6 +114,7 @@ compression_method, % compression_method renegotiation_info, hash_signs, % supported combinations of hashes/signature algos + elliptic_curves, % supported elliptic curver next_protocol_negotiation = undefined % [binary()] }). @@ -130,6 +132,7 @@ -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). @@ -146,6 +149,11 @@ dh_y %% opaque DH_Ys<1..2^16-1> }). +-record(server_ecdh_params, { + curve, + public %% opaque encoded ECpoint + }). + -record(server_psk_params, { hint }). @@ -195,6 +203,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>; @@ -231,6 +242,10 @@ dh_public }). +-record(client_ec_diffie_hellman_public, { + dh_public + }). + -record(client_psk_identity, { identity }). @@ -304,6 +319,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_tls1.erl b/lib/ssl/src/ssl_tls1.erl index 41dc1bf0dc..8a8dfca8c2 100644 --- a/lib/ssl/src/ssl_tls1.erl +++ b/lib/ssl/src/ssl_tls1.erl @@ -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, ec_nid2curve_id/1, ec_curve_id2nid/1]). %%==================================================================== %% Internal application API @@ -184,27 +185,56 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor}, 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 ]; suites(Minor) when Minor == 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 @@ -303,3 +333,64 @@ 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) +ec_nid2curve_id(sect163k1) -> 1; +ec_nid2curve_id(sect163r1) -> 2; +ec_nid2curve_id(sect163r2) -> 3; +ec_nid2curve_id(sect193r1) -> 4; +ec_nid2curve_id(sect193r2) -> 5; +ec_nid2curve_id(sect233k1) -> 6; +ec_nid2curve_id(sect233r1) -> 7; +ec_nid2curve_id(sect239k1) -> 8; +ec_nid2curve_id(sect283k1) -> 9; +ec_nid2curve_id(sect283r1) -> 10; +ec_nid2curve_id(sect409k1) -> 11; +ec_nid2curve_id(sect409r1) -> 12; +ec_nid2curve_id(sect571k1) -> 13; +ec_nid2curve_id(sect571r1) -> 14; +ec_nid2curve_id(secp160k1) -> 15; +ec_nid2curve_id(secp160r1) -> 16; +ec_nid2curve_id(secp160r2) -> 17; +ec_nid2curve_id(secp192k1) -> 18; +ec_nid2curve_id(secp192r1) -> 19; +ec_nid2curve_id(secp224k1) -> 20; +ec_nid2curve_id(secp224r1) -> 21; +ec_nid2curve_id(secp256k1) -> 22; +ec_nid2curve_id(secp256r1) -> 23; +ec_nid2curve_id(secp384r1) -> 24; +ec_nid2curve_id(secp521r1) -> 25. + +ec_curve_id2nid(1) -> sect163k1; +ec_curve_id2nid(2) -> sect163r1; +ec_curve_id2nid(3) -> sect163r2; +ec_curve_id2nid(4) -> sect193r1; +ec_curve_id2nid(5) -> sect193r2; +ec_curve_id2nid(6) -> sect233k1; +ec_curve_id2nid(7) -> sect233r1; +ec_curve_id2nid(8) -> sect239k1; +ec_curve_id2nid(9) -> sect283k1; +ec_curve_id2nid(10) -> sect283r1; +ec_curve_id2nid(11) -> sect409k1; +ec_curve_id2nid(12) -> sect409r1; +ec_curve_id2nid(13) -> sect571k1; +ec_curve_id2nid(14) -> sect571r1; +ec_curve_id2nid(15) -> secp160k1; +ec_curve_id2nid(16) -> secp160r1; +ec_curve_id2nid(17) -> secp160r2; +ec_curve_id2nid(18) -> secp192k1; +ec_curve_id2nid(19) -> secp192r1; +ec_curve_id2nid(20) -> secp224k1; +ec_curve_id2nid(21) -> secp224r1; +ec_curve_id2nid(22) -> secp256k1; +ec_curve_id2nid(23) -> secp256r1; +ec_curve_id2nid(24) -> secp384r1; +ec_curve_id2nid(25) -> secp521r1. -- cgit v1.2.1