diff options
author | Andreas Schultz <[email protected]> | 2012-04-08 02:39:18 +0200 |
---|---|---|
committer | Ingela Anderton Andin <[email protected]> | 2012-08-22 14:00:44 +0200 |
commit | d848984efd05314abf2de8da6ddd4ee651f0da35 (patch) | |
tree | c56ce48d75c8c8ba74c99af46a59182575202d88 /lib/ssl/src | |
parent | 7c9639c785bb6b3047788b6b27ddbafb8f5b0b08 (diff) | |
download | otp-d848984efd05314abf2de8da6ddd4ee651f0da35.tar.gz otp-d848984efd05314abf2de8da6ddd4ee651f0da35.tar.bz2 otp-d848984efd05314abf2de8da6ddd4ee651f0da35.zip |
ssl: make PRF function selectable
TLS 1.2 allows to negotiate the used PRF,
additional the default PRF uses a different
hash. This change make the PRF selectable
and hardwires the PRF for TLS < 1.2
Diffstat (limited to 'lib/ssl/src')
-rw-r--r-- | lib/ssl/src/ssl.erl | 14 | ||||
-rw-r--r-- | lib/ssl/src/ssl_cipher.erl | 78 | ||||
-rw-r--r-- | lib/ssl/src/ssl_cipher.hrl | 5 | ||||
-rw-r--r-- | lib/ssl/src/ssl_connection.erl | 28 | ||||
-rw-r--r-- | lib/ssl/src/ssl_handshake.erl | 51 | ||||
-rw-r--r-- | lib/ssl/src/ssl_record.hrl | 7 | ||||
-rw-r--r-- | lib/ssl/src/ssl_ssl3.erl | 21 | ||||
-rw-r--r-- | lib/ssl/src/ssl_tls1.erl | 38 |
8 files changed, 159 insertions, 83 deletions
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 5e3ced144a..d645d89a68 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -25,7 +25,8 @@ -export([start/0, start/1, stop/0, transport_accept/1, transport_accept/2, ssl_accept/1, ssl_accept/2, ssl_accept/3, - cipher_suites/0, cipher_suites/1, close/1, shutdown/2, + cipher_suites/0, cipher_suites/1, suite_definition/1, + close/1, shutdown/2, connect/3, connect/2, connect/4, connection_info/1, controlling_process/2, listen/2, pid/1, peername/1, peercert/1, recv/2, recv/3, send/2, getopts/2, setopts/2, sockname/1, @@ -304,6 +305,15 @@ peercert(#sslsocket{pid = Pid}) -> end. %%-------------------------------------------------------------------- +-spec suite_definition(cipher_suite()) -> erl_cipher_suite(). +%% +%% Description: Return erlang cipher suite definition. +%%-------------------------------------------------------------------- +suite_definition(S) -> + {KeyExchange, Cipher, Hash, _} = ssl_cipher:suite_definition(S), + {KeyExchange, Cipher, Hash}. + +%%-------------------------------------------------------------------- -spec cipher_suites() -> [erl_cipher_suite()]. -spec cipher_suites(erlang | openssl) -> [erl_cipher_suite()] | [string()]. @@ -314,7 +324,7 @@ cipher_suites() -> cipher_suites(erlang) -> Version = ssl_record:highest_protocol_version([]), - [ssl_cipher:suite_definition(S) || S <- ssl_cipher:suites(Version)]; + [suite_definition(S) || S <- ssl_cipher:suites(Version)]; cipher_suites(openssl) -> Version = ssl_record:highest_protocol_version([]), diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 1b67260388..8fc3929b97 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% 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 @@ -46,7 +46,7 @@ %% cipher values has been updated according to <CipherSuite> %%------------------------------------------------------------------- security_parameters(CipherSuite, SecParams) -> - { _, Cipher, Hash} = suite_definition(CipherSuite), + { _, Cipher, Hash, PrfHash} = suite_definition(CipherSuite), SecParams#security_parameters{ cipher_suite = CipherSuite, bulk_cipher_algorithm = bulk_cipher_algorithm(Cipher), @@ -56,6 +56,7 @@ security_parameters(CipherSuite, SecParams) -> key_material_length = key_material(Cipher), iv_size = iv_size(Cipher), mac_algorithm = mac_algorithm(Hash), + prf_algorithm = prf_algorithm(PrfHash), hash_size = hash_size(Hash)}. %%-------------------------------------------------------------------- @@ -218,7 +219,7 @@ anonymous_suites() -> ?TLS_DH_anon_WITH_AES_256_CBC_SHA]. %%-------------------------------------------------------------------- --spec suite_definition(cipher_suite()) -> erl_cipher_suite(). +-spec suite_definition(cipher_suite()) -> int_cipher_suite(). %% %% Description: Return erlang cipher suite definition. %% Note: Currently not supported suites are commented away. @@ -226,56 +227,56 @@ anonymous_suites() -> %%------------------------------------------------------------------- %% TLS v1.1 suites suite_definition(?TLS_NULL_WITH_NULL_NULL) -> - {null, null, null}; + {null, null, null, null}; %% suite_definition(?TLS_RSA_WITH_NULL_MD5) -> -%% {rsa, null, md5}; +%% {rsa, null, md5, default_prf}; %% suite_definition(?TLS_RSA_WITH_NULL_SHA) -> -%% {rsa, null, sha}; +%% {rsa, null, sha, default_prf}; suite_definition(?TLS_RSA_WITH_RC4_128_MD5) -> - {rsa, rc4_128, md5}; + {rsa, rc4_128, md5, default_prf}; suite_definition(?TLS_RSA_WITH_RC4_128_SHA) -> - {rsa, rc4_128, sha}; + {rsa, rc4_128, sha, default_prf}; %% suite_definition(?TLS_RSA_WITH_IDEA_CBC_SHA) -> -%% {rsa, idea_cbc, sha}; +%% {rsa, idea_cbc, sha, default_prf}; suite_definition(?TLS_RSA_WITH_DES_CBC_SHA) -> - {rsa, des_cbc, sha}; + {rsa, des_cbc, sha, default_prf}; suite_definition(?TLS_RSA_WITH_3DES_EDE_CBC_SHA) -> - {rsa, '3des_ede_cbc', sha}; + {rsa, '3des_ede_cbc', sha, default_prf}; suite_definition(?TLS_DHE_DSS_WITH_DES_CBC_SHA) -> - {dhe_dss, des_cbc, sha}; + {dhe_dss, des_cbc, sha, default_prf}; suite_definition(?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA) -> - {dhe_dss, '3des_ede_cbc', sha}; + {dhe_dss, '3des_ede_cbc', sha, default_prf}; suite_definition(?TLS_DHE_RSA_WITH_DES_CBC_SHA) -> - {dhe_rsa, des_cbc, sha}; + {dhe_rsa, des_cbc, sha, default_prf}; suite_definition(?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) -> - {dhe_rsa, '3des_ede_cbc', sha}; + {dhe_rsa, '3des_ede_cbc', sha, default_prf}; %%% TSL V1.1 AES suites suite_definition(?TLS_RSA_WITH_AES_128_CBC_SHA) -> - {rsa, aes_128_cbc, sha}; + {rsa, aes_128_cbc, sha, default_prf}; suite_definition(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA) -> - {dhe_dss, aes_128_cbc, sha}; + {dhe_dss, aes_128_cbc, sha, default_prf}; suite_definition(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA) -> - {dhe_rsa, aes_128_cbc, sha}; + {dhe_rsa, aes_128_cbc, sha, default_prf}; suite_definition(?TLS_RSA_WITH_AES_256_CBC_SHA) -> - {rsa, aes_256_cbc, sha}; + {rsa, aes_256_cbc, sha, default_prf}; suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) -> - {dhe_dss, aes_256_cbc, sha}; + {dhe_dss, aes_256_cbc, sha, default_prf}; suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) -> - {dhe_rsa, aes_256_cbc, sha}; + {dhe_rsa, aes_256_cbc, sha, default_prf}; %%% DH-ANON deprecated by TLS spec and not available %%% by default, but good for testing purposes. suite_definition(?TLS_DH_anon_WITH_RC4_128_MD5) -> - {dh_anon, rc4_128, md5}; + {dh_anon, rc4_128, md5, default_prf}; suite_definition(?TLS_DH_anon_WITH_DES_CBC_SHA) -> - {dh_anon, des_cbc, sha}; + {dh_anon, des_cbc, sha, default_prf}; suite_definition(?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA) -> - {dh_anon, '3des_ede_cbc', sha}; + {dh_anon, '3des_ede_cbc', sha, default_prf}; suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA) -> - {dh_anon, aes_128_cbc, sha}; + {dh_anon, aes_128_cbc, sha, default_prf}; suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA) -> - {dh_anon, aes_256_cbc, sha}. + {dh_anon, aes_256_cbc, sha, default_prf}. %%-------------------------------------------------------------------- -spec suite(erl_cipher_suite()) -> cipher_suite(). @@ -510,14 +511,35 @@ mac_algorithm(null) -> mac_algorithm(md5) -> ?MD5; mac_algorithm(sha) -> - ?SHA. + ?SHA; +mac_algorithm(sha256) -> + ?SHA256; +mac_algorithm(sha384) -> + ?SHA384. + +prf_algorithm(default_prf) -> + ?SHA256; +prf_algorithm(null) -> + ?NULL; +prf_algorithm(md5) -> + ?MD5; +prf_algorithm(sha) -> + ?SHA; +prf_algorithm(sha256) -> + ?SHA256; +prf_algorithm(sha384) -> + ?SHA384. hash_size(null) -> 0; hash_size(md5) -> 16; hash_size(sha) -> - 20. + 20; +hash_size(sha256) -> + 32; +hash_size(sha384) -> + 48. %% RFC 5246: 6.2.3.2. CBC Block Cipher %% diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl index 8bd68cc190..6509b977b6 100644 --- a/lib/ssl/src/ssl_cipher.hrl +++ b/lib/ssl/src/ssl_cipher.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% 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 @@ -28,8 +28,9 @@ -type cipher() :: null |rc4_128 | idea_cbc | des40_cbc | des_cbc | '3des_ede_cbc' | aes_128_cbc | aes_256_cbc. --type hash() :: null | sha | md5. +-type hash() :: null | sha | md5 | sha256 | sha384 | sha512. -type erl_cipher_suite() :: {key_algo(), cipher(), hash()}. +-type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash()}. -type cipher_suite() :: binary(). -type cipher_enum() :: integer(). -type openssl_cipher_suite() :: string(). diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 4552941297..002565bc79 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -374,7 +374,7 @@ hello(#server_hello{cipher_suite = CipherSuite, ssl_options = SslOptions} = State0) -> case ssl_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of {Version, NewId, ConnectionStates} -> - {KeyAlgorithm, _, _} = + {KeyAlgorithm, _, _, _} = ssl_cipher:suite_definition(CipherSuite), PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm), @@ -435,8 +435,9 @@ abbreviated(#finished{verify_data = Data} = Finished, session = #session{master_secret = MasterSecret}, connection_states = ConnectionStates0} = State) -> -%%CHECKME +%%CHECKME: the connection state prf logic is pure guess work! case ssl_handshake:verify_connection(Version, Finished, client, + get_current_connection_state_prf(ConnectionStates0, read), MasterSecret, Handshake) of verified -> ConnectionStates = ssl_record:set_client_verify_data(current_both, Data, ConnectionStates0), @@ -452,7 +453,9 @@ abbreviated(#finished{verify_data = Data} = Finished, session = #session{master_secret = MasterSecret}, negotiated_version = Version, connection_states = ConnectionStates0} = State) -> +%%CHECKME: the connection state prf logic is pure guess work! case ssl_handshake:verify_connection(Version, Finished, server, + get_pending_connection_state_prf(ConnectionStates0, write), MasterSecret, Handshake0) of verified -> ConnectionStates1 = ssl_record:set_server_verify_data(current_read, Data, ConnectionStates0), @@ -661,9 +664,12 @@ cipher(#finished{verify_data = Data} = Finished, role = Role, session = #session{master_secret = MasterSecret} = Session0, + connection_states = ConnectionStates0, tls_handshake_history = Handshake0} = State) -> +%%CHECKME: the connection state prf logic is pure guess work! case ssl_handshake:verify_connection(Version, Finished, opposite_role(Role), + get_current_connection_state_prf(ConnectionStates0, read), MasterSecret, Handshake0) of verified -> Session = register_session(Role, Host, Port, Session0), @@ -909,14 +915,14 @@ handle_sync_event(info, _, StateName, session = #session{cipher_suite = Suite}} = State) -> AtomVersion = ssl_record:protocol_version(Version), - {reply, {ok, {AtomVersion, ssl_cipher:suite_definition(Suite)}}, + {reply, {ok, {AtomVersion, ssl:suite_definition(Suite)}}, StateName, State, get_timeout(State)}; handle_sync_event(session_info, _, StateName, #state{session = #session{session_id = Id, cipher_suite = Suite}} = State) -> {reply, [{session_id, Id}, - {cipher_suite, ssl_cipher:suite_definition(Suite)}], + {cipher_suite, ssl:suite_definition(Suite)}], StateName, State, get_timeout(State)}; handle_sync_event(peer_certificate, _, StateName, @@ -1381,7 +1387,7 @@ server_hello(ServerHello, #state{transport_cb = Transport, connection_states = ConnectionStates0, tls_handshake_history = Handshake0} = State) -> CipherSuite = ServerHello#server_hello.cipher_suite, - {KeyAlgorithm, _, _} = ssl_cipher:suite_definition(CipherSuite), + {KeyAlgorithm, _, _, _} = ssl_cipher:suite_definition(CipherSuite), {BinMsg, ConnectionStates1, Handshake1} = encode_handshake(ServerHello, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinMsg), @@ -1541,7 +1547,10 @@ finished(#state{role = Role, socket = Socket, negotiated_version = Version, connection_states = ConnectionStates0, tls_handshake_history = Handshake0}, StateName) -> MasterSecret = Session#session.master_secret, - Finished = ssl_handshake:finished(Version, Role, MasterSecret, Handshake0), +%%CHECKME: the connection state prf logic is pure guess work! + Finished = ssl_handshake:finished(Version, Role, + get_current_connection_state_prf(ConnectionStates0, write), + MasterSecret, Handshake0), ConnectionStates1 = save_verify_data(Role, Finished, ConnectionStates0, StateName), {BinFinished, ConnectionStates, Handshake} = encode_handshake(Finished, Version, ConnectionStates1, Handshake0), @@ -2398,3 +2407,10 @@ handle_trusted_certs_db(#state{cert_db_ref = Ref, _ -> ok end. + +get_current_connection_state_prf(CStates, Direction) -> + CS = ssl_record:current_connection_state(CStates, Direction), + CS#connection_state.security_parameters#security_parameters.prf_algorithm. +get_pending_connection_state_prf(CStates, Direction) -> + CS = ssl_record:pending_connection_state(CStates, Direction), + CS#connection_state.security_parameters#security_parameters.prf_algorithm. diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index c7d5ca6903..1759c920cc 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -34,7 +34,7 @@ hello_request/0, certify/7, certificate/4, client_certificate_verify/5, certificate_verify/5, certificate_request/3, key_exchange/3, server_key_exchange_hash/2, - finished/4, verify_connection/5, get_tls_handshake/3, + finished/5, verify_connection/6, get_tls_handshake/3, decode_client_key/3, server_hello_done/0, encode_handshake/2, init_handshake_history/0, update_handshake_history/2, decrypt_premaster_secret/2, prf/5]). @@ -401,10 +401,11 @@ master_secret(Version, PremasterSecret, ConnectionStates, Role) -> ConnectionState = ssl_record:pending_connection_state(ConnectionStates, read), SecParams = ConnectionState#connection_state.security_parameters, - #security_parameters{client_random = ClientRandom, + #security_parameters{prf_algorithm = PrfAlgo, + client_random = ClientRandom, server_random = ServerRandom} = SecParams, try master_secret(Version, - calc_master_secret(Version,PremasterSecret, + calc_master_secret(Version,PrfAlgo,PremasterSecret, ClientRandom, ServerRandom), SecParams, ConnectionStates, Role) catch @@ -416,26 +417,26 @@ master_secret(Version, PremasterSecret, ConnectionStates, Role) -> end. %%-------------------------------------------------------------------- --spec finished(tls_version(), client | server, binary(), tls_handshake_history()) -> +-spec finished(tls_version(), client | server, integer(), binary(), tls_handshake_history()) -> #finished{}. %% %% Description: Creates a handshake finished message %%------------------------------------------------------------------- -finished(Version, Role, MasterSecret, {Handshake, _}) -> % use the current hashes +finished(Version, Role, PrfAlgo, MasterSecret, {Handshake, _}) -> % use the current handshake #finished{verify_data = - calc_finished(Version, Role, MasterSecret, Handshake)}. + calc_finished(Version, Role, PrfAlgo, MasterSecret, Handshake)}. %%-------------------------------------------------------------------- --spec verify_connection(tls_version(), #finished{}, client | server, binary(), +-spec verify_connection(tls_version(), #finished{}, client | server, integer(), binary(), tls_handshake_history()) -> verified | #alert{}. %% %% Description: Checks the ssl handshake finished message to verify %% the connection. %%------------------------------------------------------------------- verify_connection(Version, #finished{verify_data = Data}, - Role, MasterSecret, {_, Handshake}) -> + Role, PrfAlgo, MasterSecret, {_, Handshake}) -> %% use the previous hashes - case calc_finished(Version, Role, MasterSecret, Handshake) of + case calc_finished(Version, Role, PrfAlgo, MasterSecret, Handshake) of Data -> verified; _ -> @@ -782,13 +783,14 @@ master_secret(Version, MasterSecret, #security_parameters{ client_random = ClientRandom, server_random = ServerRandom, hash_size = HashSize, + prf_algorithm = PrfAlgo, key_material_length = KML, expanded_key_material_length = EKML, iv_size = IVS}, ConnectionStates, Role) -> {ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey, ServerWriteKey, ClientIV, ServerIV} = - setup_keys(Version, MasterSecret, ServerRandom, + setup_keys(Version, PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize, KML, EKML, IVS), ConnStates1 = ssl_record:set_master_secret(MasterSecret, ConnectionStates), @@ -1117,34 +1119,35 @@ digitally_signed(Hash, #'RSAPrivateKey'{} = Key) -> digitally_signed(Hash, #'DSAPrivateKey'{} = Key) -> public_key:sign(Hash, none, Key). -calc_master_secret({3,0}, PremasterSecret, ClientRandom, ServerRandom) -> +calc_master_secret({3,0}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) -> ssl_ssl3:master_secret(PremasterSecret, ClientRandom, ServerRandom); -calc_master_secret({3,N},PremasterSecret, ClientRandom, ServerRandom) +calc_master_secret({3,N}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) when N == 1; N == 2 -> - ssl_tls1:master_secret(PremasterSecret, ClientRandom, ServerRandom). + ssl_tls1:master_secret(?MD5SHA, PremasterSecret, ClientRandom, ServerRandom). -setup_keys({3,0}, MasterSecret, +setup_keys({3,0}, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize, KML, EKML, IVS) -> ssl_ssl3:setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize, KML, EKML, IVS); -setup_keys({3,1}, MasterSecret, - ServerRandom, ClientRandom, HashSize, KML, _EKML, IVS) -> - ssl_tls1:setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize, +setup_keys({3,N}, _PrfAlgo, MasterSecret, + ServerRandom, ClientRandom, HashSize, KML, _EKML, IVS) + when N == 1; N == 2 -> + ssl_tls1:setup_keys(N, ?MD5SHA, MasterSecret, ServerRandom, ClientRandom, HashSize, KML, IVS). -calc_finished({3, 0}, Role, MasterSecret, Handshake) -> +calc_finished({3, 0}, Role, _PrfAlgo, MasterSecret, Handshake) -> ssl_ssl3:finished(Role, MasterSecret, lists:reverse(Handshake)); -calc_finished({3, N}, Role, MasterSecret, Handshake) +calc_finished({3, N}, Role, _PrfAlgo, MasterSecret, Handshake) when N == 1; N == 2 -> - ssl_tls1:finished(Role, MasterSecret, lists:reverse(Handshake)). + ssl_tls1:finished(Role, N, ?MD5SHA, MasterSecret, lists:reverse(Handshake)). -calc_certificate_verify({3, 0}, MasterSecret, Algorithm, Handshake) -> - ssl_ssl3:certificate_verify(Algorithm, MasterSecret, lists:reverse(Handshake)); -calc_certificate_verify({3, N}, _, Algorithm, Handshake) +calc_certificate_verify({3, 0}, HashAlgo, MasterSecret, Handshake) -> + ssl_ssl3:certificate_verify(HashAlgo, MasterSecret, lists:reverse(Handshake)); +calc_certificate_verify({3, N}, HashAlgo, _MasterSecret, Handshake) when N == 1; N == 2 -> - ssl_tls1:certificate_verify(Algorithm, lists:reverse(Handshake)). + ssl_tls1:certificate_verify(HashAlgo, N, lists:reverse(Handshake)). key_exchange_alg(rsa) -> ?KEY_EXCHANGE_RSA; diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl index 3d22fa6acb..cb1008c2be 100644 --- a/lib/ssl/src/ssl_record.hrl +++ b/lib/ssl/src/ssl_record.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% 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 @@ -47,6 +47,7 @@ key_material_length, % unit 8 expanded_key_material_length, % unit 8 mac_algorithm, % unit 8 + prf_algorithm, % unit 8 hash_size, % unit 8 compression_algorithm, % unit 8 master_secret, % opaque 48 @@ -101,6 +102,10 @@ %-define(NULL, 0). %% Already defined by ssl_internal.hrl -define(MD5, 1). -define(SHA, 2). +-define(MD5SHA, 3). +-define(SHA256, 4). +-define(SHA384, 5). +-define(SHA512, 6). %% CompressionMethod % -define(NULL, 0). %% Already defined by ssl_internal.hrl diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl index 2b4ae1539f..11bc663e77 100644 --- a/lib/ssl/src/ssl_ssl3.erl +++ b/lib/ssl/src/ssl_ssl3.erl @@ -156,14 +156,22 @@ suites() -> hash(?MD5, Data) -> crypto:md5(Data); hash(?SHA, Data) -> - crypto:sha(Data). + crypto:sha(Data); +hash(?SHA256, Data) -> + crypto:sha256(Data); +hash(?SHA384, Data) -> + crypto:sha384(Data). %%pad_1(?NULL) -> %% ""; pad_1(?MD5) -> <<"666666666666666666666666666666666666666666666666">>; pad_1(?SHA) -> - <<"6666666666666666666666666666666666666666">>. + <<"6666666666666666666666666666666666666666">>; +pad_1(?SHA256) -> + <<"66666666666666666666666666666666">>; +pad_1(?SHA384) -> + <<"666666666666666666666666666666666666666666666666">>. %%pad_2(?NULL) -> %% ""; @@ -172,7 +180,14 @@ pad_2(?MD5) -> "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\">>; pad_2(?SHA) -> <<"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" - "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\">>. + "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\">>; +pad_2(?SHA256) -> + <<"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" + "\\\\\\\\\\\\\\\\\\\\\\\\">>; +pad_2(?SHA384) -> + <<"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" + "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" + "\\\\\\\\\\\\\\\\">>. mac_hash(?NULL, _Secret, _Data) -> <<>>; diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl index d64a8f815d..dc3d9774c2 100644 --- a/lib/ssl/src/ssl_tls1.erl +++ b/lib/ssl/src/ssl_tls1.erl @@ -28,25 +28,27 @@ -include("ssl_internal.hrl"). -include("ssl_record.hrl"). --export([master_secret/3, finished/3, certificate_verify/2, mac_hash/7, - setup_keys/6, suites/0, prf/4]). +-export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7, + setup_keys/8, suites/0, prf/5]). %%==================================================================== %% Internal application API %%==================================================================== --spec master_secret(binary(), binary(), binary()) -> binary(). +-spec master_secret(integer(), binary(), binary(), binary()) -> binary(). -master_secret(PreMasterSecret, ClientRandom, ServerRandom) -> - %% RFC 2246 & 4346 - 8.1 %% master_secret = PRF(pre_master_secret, - %% "master secret", ClientHello.random + - %% ServerHello.random)[0..47]; - prf(PreMasterSecret, <<"master secret">>, +master_secret(PrfAlgo, PreMasterSecret, ClientRandom, ServerRandom) -> + %% RFC 2246 & 4346 && RFC 5246 - 8.1 %% master_secret = PRF(pre_master_secret, + %% "master secret", ClientHello.random + + %% ServerHello.random)[0..47]; + + prf(PrfAlgo, PreMasterSecret, <<"master secret">>, [ClientRandom, ServerRandom], 48). --spec finished(client | server, binary(), [binary()]) -> binary(). +-spec finished(client | server, integer(), integer(), binary(), [binary()]) -> binary(). -finished(Role, MasterSecret, Handshake) -> +finished(Role, Version, PrfAlgo, MasterSecret, Handshake) + when Version == 1; Version == 2; PrfAlgo == ?MD5SHA -> %% RFC 2246 & 4346 - 7.4.9. Finished %% struct { %% opaque verify_data[12]; @@ -57,7 +59,7 @@ finished(Role, MasterSecret, Handshake) -> %% SHA-1(handshake_messages)) [0..11]; MD5 = crypto:md5(Handshake), SHA = crypto:sha(Handshake), - prf(MasterSecret, finished_label(Role), [MD5, SHA], 12). + prf(?MD5SHA, MasterSecret, finished_label(Role), [MD5, SHA], 12); -spec certificate_verify(OID::tuple(), [binary()]) -> binary(). @@ -69,12 +71,13 @@ certificate_verify(?'rsaEncryption', Handshake) -> certificate_verify(?'id-dsa', Handshake) -> crypto:sha(Handshake). --spec setup_keys(binary(), binary(), binary(), integer(), +-spec setup_keys(integer(), integer(), binary(), binary(), binary(), integer(), integer(), integer()) -> {binary(), binary(), binary(), binary(), binary(), binary()}. -setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize, - KeyMatLen, IVSize) -> +setup_keys(Version, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize, + KeyMatLen, IVSize) + when Version == 1 -> %% RFC 2246 - 6.3. Key calculation %% key_block = PRF(SecurityParameters.master_secret, %% "key expansion", @@ -88,7 +91,7 @@ setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize, %% client_write_IV[SecurityParameters.IV_size] %% server_write_IV[SecurityParameters.IV_size] WantedLength = 2 * (HashSize + KeyMatLen + IVSize), - KeyBlock = prf(MasterSecret, "key expansion", + KeyBlock = prf(?MD5SHA, MasterSecret, "key expansion", [ServerRandom, ClientRandom], WantedLength), <<ClientWriteMacSecret:HashSize/binary, ServerWriteMacSecret:HashSize/binary, @@ -182,7 +185,7 @@ p_hash(_Secret, _Seed, WantedLength, _Method, _N, [Last | Acc]) when WantedLength =< 0 -> Keep = byte_size(Last) + WantedLength, <<B:Keep/binary, _/binary>> = Last, - lists:reverse(Acc, [B]); + list_to_binary(lists:reverse(Acc, [B])); p_hash(Secret, Seed, WantedLength, Method, N, Acc) -> N1 = N+1, Bin = hmac_hash(Method, Secret, [a(N1, Secret, Seed, Method), Seed]), @@ -214,7 +217,8 @@ split_secret(BinSecret) -> <<_:Div/binary, Secret2:EvenLength/binary>> = BinSecret, {Secret1, Secret2}. -prf(Secret, Label, Seed, WantedLength) -> +prf(MAC, Secret, Label, Seed, WantedLength) + when MAC == ?MD5SHA -> %% PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR %% P_SHA-1(S2, label + seed); {S1, S2} = split_secret(Secret), |