diff options
author | Ingela Anderton Andin <[email protected]> | 2013-06-18 12:30:38 +0200 |
---|---|---|
committer | Ingela Anderton Andin <[email protected]> | 2013-09-10 09:37:29 +0200 |
commit | b9a31f24053c84d9a7ffa4281bc11f47b3be5905 (patch) | |
tree | e0698a95d56b1fd6070d916033cd07f098d3b5ed | |
parent | fb6ac178ac437fcc04f1675df75b0583c1d24ad7 (diff) | |
download | otp-b9a31f24053c84d9a7ffa4281bc11f47b3be5905.tar.gz otp-b9a31f24053c84d9a7ffa4281bc11f47b3be5905.tar.bz2 otp-b9a31f24053c84d9a7ffa4281bc11f47b3be5905.zip |
ssl: DTLS record handling
Also refactor so that TLS and DTLS can have common functions when possible.
-rw-r--r-- | lib/ssl/src/Makefile | 7 | ||||
-rw-r--r-- | lib/ssl/src/dtls_record.erl | 51 | ||||
-rw-r--r-- | lib/ssl/src/dtls_record.hrl | 10 | ||||
-rw-r--r-- | lib/ssl/src/dtls_v1.erl | 2 | ||||
-rw-r--r-- | lib/ssl/src/ssl.app.src | 8 | ||||
-rw-r--r-- | lib/ssl/src/ssl_cipher.erl | 4 | ||||
-rw-r--r-- | lib/ssl/src/ssl_handshake.erl | 12 | ||||
-rw-r--r-- | lib/ssl/src/ssl_record.erl | 89 | ||||
-rw-r--r-- | lib/ssl/src/ssl_record.hrl | 7 | ||||
-rw-r--r-- | lib/ssl/src/ssl_v2.erl (renamed from lib/ssl/src/ssl_ssl2.erl) | 16 | ||||
-rw-r--r-- | lib/ssl/src/ssl_v3.erl (renamed from lib/ssl/src/ssl_ssl3.erl) | 28 | ||||
-rw-r--r-- | lib/ssl/src/tls_handshake.erl | 19 | ||||
-rw-r--r-- | lib/ssl/src/tls_record.erl | 31 | ||||
-rw-r--r-- | lib/ssl/src/tls_record.hrl | 7 | ||||
-rw-r--r-- | lib/ssl/src/tls_v1.erl (renamed from lib/ssl/src/ssl_tls1.erl) | 42 |
15 files changed, 193 insertions, 140 deletions
diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile index a467b3f608..a5af451244 100644 --- a/lib/ssl/src/Makefile +++ b/lib/ssl/src/Makefile @@ -65,9 +65,10 @@ MODULES= \ ssl_socket \ tls_record \ dtls_record \ - ssl_ssl2 \ - ssl_ssl3 \ - ssl_tls1 \ + ssl_record \ + ssl_v2 \ + ssl_v3 \ + tls_v1 \ ssl_tls_dist_proxy INTERNAL_HRL_FILES = \ diff --git a/lib/ssl/src/dtls_record.erl b/lib/ssl/src/dtls_record.erl index 98c60f599c..daadae0725 100644 --- a/lib/ssl/src/dtls_record.erl +++ b/lib/ssl/src/dtls_record.erl @@ -30,7 +30,7 @@ %% Misc. -export([protocol_version/1, lowest_protocol_version/2, highest_protocol_version/1, supported_protocol_versions/0, - is_acceptable_version/2]). + is_acceptable_version/2, cipher/4, decipher/2]). %%-------------------------------------------------------------------- -spec init_connection_state_seq(tls_version(), #connection_states{}) -> @@ -71,25 +71,18 @@ current_connection_state_epoch(#connection_states{current_write = Current}, %% Description: Returns the instance of the connection_state record %% that is defined by the Epoch. %%-------------------------------------------------------------------- -connection_state_by_epoch(#connection_states{previous_read = CS}, Epoch, read) - when CS#connection_state.epoch == Epoch -> - CS; connection_state_by_epoch(#connection_states{current_read = CS}, Epoch, read) when CS#connection_state.epoch == Epoch -> CS; connection_state_by_epoch(#connection_states{pending_read = CS}, Epoch, read) when CS#connection_state.epoch == Epoch -> CS; -connection_state_by_epoch(#connection_states{previous_write = CS}, Epoch, write) - when CS#connection_state.epoch == Epoch -> - CS; connection_state_by_epoch(#connection_states{current_write = CS}, Epoch, write) when CS#connection_state.epoch == Epoch -> CS; connection_state_by_epoch(#connection_states{pending_write = CS}, Epoch, write) when CS#connection_state.epoch == Epoch -> CS. - %%-------------------------------------------------------------------- -spec set_connection_state_by_epoch(#connection_states{}, #connection_state{}, read | write) -> ok. @@ -98,12 +91,6 @@ connection_state_by_epoch(#connection_states{pending_write = CS}, Epoch, write) %% that is defined by the Epoch. %%-------------------------------------------------------------------- set_connection_state_by_epoch(ConnectionStates0 = - #connection_states{previous_read = CS}, - NewCS = #connection_state{epoch = Epoch}, read) - when CS#connection_state.epoch == Epoch -> - ConnectionStates0#connection_states{previous_read = NewCS}; - -set_connection_state_by_epoch(ConnectionStates0 = #connection_states{current_read = CS}, NewCS = #connection_state{epoch = Epoch}, read) when CS#connection_state.epoch == Epoch -> @@ -116,12 +103,6 @@ set_connection_state_by_epoch(ConnectionStates0 = ConnectionStates0#connection_states{pending_read = NewCS}; set_connection_state_by_epoch(ConnectionStates0 = - #connection_states{previous_write = CS}, - NewCS = #connection_state{epoch = Epoch}, write) - when CS#connection_state.epoch == Epoch -> - ConnectionStates0#connection_states{previous_write = NewCS}; - -set_connection_state_by_epoch(ConnectionStates0 = #connection_states{current_write = CS}, NewCS = #connection_state{epoch = Epoch}, write) when CS#connection_state.epoch == Epoch -> @@ -133,7 +114,6 @@ set_connection_state_by_epoch(ConnectionStates0 = when CS#connection_state.epoch == Epoch -> ConnectionStates0#connection_states{pending_write = NewCS}. - %%-------------------------------------------------------------------- -spec protocol_version(tls_atom_version() | tls_version()) -> tls_version() | tls_atom_version(). @@ -283,20 +263,21 @@ supported_connection_protocol_versions([]) -> is_acceptable_version(Version, Versions) -> lists:member(Version, Versions). -%%-------------------------------------------------------------------- --spec clear_previous_epoch(#connection_states{}) -> - #connection_states{}. -%% -%% Description: Advance to min_read_epoch to the current read epoch. -%%-------------------------------------------------------------------- -clear_previous_epoch(States = - #connection_states{current_read = Current}) -> - States#connection_states{min_read_epoch = Current#connection_state.epoch}. - +cipher(Type, Version, Fragment, CS0) -> + Length = erlang:iolist_size(Fragment), + {MacHash, CS1=#connection_state{cipher_state = CipherS0, + security_parameters= + #security_parameters{bulk_cipher_algorithm = + BCA} + }} = + hash_and_bump_seqno(CS0, Type, Version, Length, Fragment), + {Ciphered, CipherS1} = ssl_cipher:cipher(BCA, CipherS0, MacHash, Fragment, Version), + CS2 = CS1#connection_state{cipher_state=CipherS1}, + {Ciphered, CS2}. decipher(TLS=#ssl_tls{type=Type, version=Version={254, _}, - epoch = Epoch, sequence = SeqNo, + epoch = Epoch, record_seq = SeqNo, fragment=Fragment}, CS0) -> SP = CS0#connection_state.security_parameters, BCA = SP#security_parameters.bulk_cipher_algorithm, @@ -307,7 +288,7 @@ decipher(TLS=#ssl_tls{type=Type, version=Version={254, _}, CS1 = CS0#connection_state{cipher_state = CipherS1}, TLength = size(T), MacHash = hash_with_seqno(CS1, Type, Version, Epoch, SeqNo, TLength, T), - case is_correct_mac(Mac, MacHash) of + case ssl_record:is_correct_mac(Mac, MacHash) of true -> {TLS#ssl_tls{fragment = T}, CS1}; false -> @@ -338,3 +319,7 @@ hash_and_bump_seqno(#connection_state{epoch = Epoch, MacSecret, (Epoch bsl 48) + SeqNo, Type, Length, Fragment), {Hash, CS0#connection_state{sequence_number = SeqNo+1}}. + +mac_hash(Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) -> + dtls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version, + Length, Fragment). diff --git a/lib/ssl/src/dtls_record.hrl b/lib/ssl/src/dtls_record.hrl index c50550cc28..b72c14c2d7 100644 --- a/lib/ssl/src/dtls_record.hrl +++ b/lib/ssl/src/dtls_record.hrl @@ -30,16 +30,6 @@ -define(INITIAL_BYTES, 5). --record(connection_states, { - min_read_epoch, - previous_read, - current_read, - pending_read, - previous_write, - current_write, - pending_write - }). - %% Used to handle tls_plain_text, tls_compressed and tls_cipher_text -record(ssl_tls, { diff --git a/lib/ssl/src/dtls_v1.erl b/lib/ssl/src/dtls_v1.erl index 930998b460..a9fcf575af 100644 --- a/lib/ssl/src/dtls_v1.erl +++ b/lib/ssl/src/dtls_v1.erl @@ -25,7 +25,7 @@ -spec suites(Minor:: 253|255) -> [cipher_suite()]. suites(Minor) -> - tls_v1:suites(corresponding_minor_tls_version(Minor)); + tls_v1:suites(corresponding_minor_tls_version(Minor)). mac_hash(Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) -> tls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version, diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src index 0a2ae92e9d..677f5fdd07 100644 --- a/lib/ssl/src/ssl.app.src +++ b/lib/ssl/src/ssl.app.src @@ -20,14 +20,14 @@ inet_tls_dist, ssl_tls_dist_proxy, ssl_dist_sup, - ssl_tls1, - ssl_ssl3, - ssl_ssl2, + tls_v1, + ssl_v3, + ssl_v2, ssl_session, ssl_session_cache_api, ssl_session_cache, ssl_socket, - %%ssl_record, + ssl_record, ssl_manager, ssl_handshake, ssl_connection_sup, diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 09aad8e414..d958b74e9f 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -195,9 +195,9 @@ block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0, %% Description: Returns a list of supported cipher suites. %%-------------------------------------------------------------------- suites({3, 0}) -> - ssl_ssl3:suites(); + ssl_v3:suites(); suites({3, N}) -> - ssl_tls1:suites(N). + tls_v1:suites(N). %%-------------------------------------------------------------------- -spec anonymous_suites() -> [cipher_suite()]. diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 0f5d5def48..5084c46571 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -575,6 +575,7 @@ encode_hello_extensions([#renegotiation_info{renegotiated_connection = Info} | R encode_hello_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), ?BYTE(InfoLen), Info/binary, Acc/binary>>); encode_hello_extensions([#elliptic_curves{elliptic_curve_list = EllipticCurves} | Rest], Acc) -> + EllipticCurveList = << <<(tls_v1:oid_to_enum(X)):16>> || X <- EllipticCurves>>, ListLen = byte_size(EllipticCurveList), Len = ListLen + 2, @@ -752,7 +753,7 @@ dec_server_key(<<?BYTE(?NAMED_CURVE), ?UINT16(CurveID), ?BYTE(PointLen), ECPoint:PointLen/binary, _/binary>> = KeyStruct, ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, Version) -> - Params = #server_ecdh_params{curve = {namedCurve, ssl_tls1:enum_to_oid(CurveID)}, + Params = #server_ecdh_params{curve = {namedCurve, tls_v1:enum_to_oid(CurveID)}, public = ECPoint}, {BinMsg, HashSign, Signature} = dec_server_key_params(PointLen + 4, KeyStruct, Version), #server_key_params{params = Params, @@ -1445,10 +1446,11 @@ dec_hello_extensions(<<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len), EllipticCurveListLen = Len - 2, <<?UINT16(EllipticCurveListLen), EllipticCurveList/binary>> = ExtData, EllipticCurves = [tls_v1:enum_to_oid(X) || <<X:16>> <= EllipticCurveList], - dec_hello_extensions(Rest, Acc#hello_extensions{elliptic_curves = - #elliptic_curves{elliptic_curve_list = - EllipticCurves}}); -dec_hello_extensions(<<?UINT16(?EC_POINT_FORMATS_EXT), ?UINT16(Len), ?BYTE(_), + + dec_hello_extensions(Rest, [{elliptic_curves, + #elliptic_curves{elliptic_curve_list = EllipticCurves}} | Acc]); + +dec_hello_extensions(<<?UINT16(?EC_POINT_FORMATS_EXT), ?UINT16(Len), ExtData:Len/binary, Rest/binary>>, Acc) -> %%ECPointFormatListLen = Len - 1, <<?BYTE(_), ECPointFormatList/binary>> = ExtData, diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl new file mode 100644 index 0000000000..ac56e3ab29 --- /dev/null +++ b/lib/ssl/src/ssl_record.erl @@ -0,0 +1,89 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2013-2013. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% 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% + +-module(ssl_record). + +-include("ssl_internal.hrl"). +-include("ssl_record.hrl"). + +-export([empty_connection_state/1, activate_pending_connection_state/2, is_correct_mac/2]). + +empty_connection_state(ConnectionEnd) -> + SecParams = empty_security_params(ConnectionEnd), + #connection_state{security_parameters = SecParams}. + +empty_security_params(ConnectionEnd = ?CLIENT) -> + #security_parameters{connection_end = ConnectionEnd, + client_random = random()}; +empty_security_params(ConnectionEnd = ?SERVER) -> + #security_parameters{connection_end = ConnectionEnd, + server_random = random()}. +random() -> + Secs_since_1970 = calendar:datetime_to_gregorian_seconds( + calendar:universal_time()) - 62167219200, + Random_28_bytes = crypto:rand_bytes(28), + <<?UINT32(Secs_since_1970), Random_28_bytes/binary>>. + +%%-------------------------------------------------------------------- +-spec activate_pending_connection_state(#connection_states{}, read | write) -> + #connection_states{}. +%% +%% Description: Creates a new instance of the connection_states record +%% where the pending state of <Type> has been activated. +%%-------------------------------------------------------------------- +activate_pending_connection_state(States = + #connection_states{current_read = Current, + pending_read = Pending}, + read) -> + %% Next epoch is a noop for SSL/TLS only uesed by DTLS + NewCurrent = Pending#connection_state{epoch = connection_state_next_epoch(Current), + sequence_number = 0}, + SecParams = Pending#connection_state.security_parameters, + ConnectionEnd = SecParams#security_parameters.connection_end, + EmptyPending = empty_connection_state(ConnectionEnd), + SecureRenegotation = NewCurrent#connection_state.secure_renegotiation, + NewPending = EmptyPending#connection_state{secure_renegotiation = SecureRenegotation}, + States#connection_states{current_read = NewCurrent, + pending_read = NewPending + }; + +activate_pending_connection_state(States = + #connection_states{current_write = Current, + pending_write = Pending}, + write) -> + %% Next epoch is a noop for SSL/TLS only uesed by DTLS + NewCurrent = Pending#connection_state{epoch = connection_state_next_epoch(Current), + sequence_number = 0}, + SecParams = Pending#connection_state.security_parameters, + ConnectionEnd = SecParams#security_parameters.connection_end, + EmptyPending = empty_connection_state(ConnectionEnd), + SecureRenegotation = NewCurrent#connection_state.secure_renegotiation, + NewPending = EmptyPending#connection_state{secure_renegotiation = SecureRenegotation}, + States#connection_states{current_write = NewCurrent, + pending_write = NewPending + }. + +connection_state_next_epoch(#connection_state{epoch = undefined}) -> + undefined; +connection_state_next_epoch(State) -> + State#connection_state.epoch + 1. + +is_correct_mac(Mac, Mac) -> + true; +is_correct_mac(_M,_H) -> + false. diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl index 8a6a211553..34893ce699 100644 --- a/lib/ssl/src/ssl_record.hrl +++ b/lib/ssl/src/ssl_record.hrl @@ -42,6 +42,13 @@ server_verify_data }). +-record(connection_states, { + current_read, + pending_read, + current_write, + pending_write + }). + -record(security_parameters, { cipher_suite, connection_end, diff --git a/lib/ssl/src/ssl_ssl2.erl b/lib/ssl/src/ssl_v2.erl index a9ab6a2678..07876366f1 100644 --- a/lib/ssl/src/ssl_ssl2.erl +++ b/lib/ssl/src/ssl_v2.erl @@ -1,30 +1,30 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2007-2013. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% 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: Handles sslv2 hello as clients supporting sslv2 and higher +%% Purpose: Handles sslv2 hello as clients supporting sslv2 and higher %% will send an sslv2 hello. %%---------------------------------------------------------------------- --module(ssl_ssl2). - +-module(ssl_v2). + -export([client_random/2]). client_random(ChallengeData, 32) -> diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_v3.erl index 013c27ebb5..d477b3df81 100644 --- a/lib/ssl/src/ssl_ssl3.erl +++ b/lib/ssl/src/ssl_v3.erl @@ -22,14 +22,14 @@ %% Purpose: Handles sslv3 encryption. %%---------------------------------------------------------------------- --module(ssl_ssl3). +-module(ssl_v3). -include("ssl_cipher.hrl"). -include("ssl_internal.hrl"). -include("ssl_record.hrl"). % MD5 and SHA -export([master_secret/3, finished/3, certificate_verify/3, - mac_hash/6, setup_keys/7, + mac_hash/6, setup_keys/7, suites/0]). -compile(inline). @@ -40,7 +40,7 @@ -spec master_secret(binary(), binary(), binary()) -> binary(). master_secret(PremasterSecret, ClientRandom, ServerRandom) -> - %% draft-ietf-tls-ssl-version3-00 - 6.2.2 + %% draft-ietf-tls-ssl-version3-00 - 6.2.2 %% key_block = %% MD5(master_secret + SHA(`A' + master_secret + %% ServerHello.random + @@ -62,7 +62,7 @@ finished(Role, MasterSecret, Handshake) -> %% opaque md5_hash[16]; %% opaque sha_hash[20]; %% } Finished; - %% + %% %% md5_hash MD5(master_secret + pad2 + %% MD5(handshake_messages + Sender + %% master_secret + pad1)); @@ -95,23 +95,23 @@ certificate_verify(sha, MasterSecret, Handshake) -> handshake_hash(?SHA, MasterSecret, undefined, Handshake). --spec mac_hash(integer(), binary(), integer(), integer(), integer(), binary()) -> binary(). +-spec mac_hash(integer(), binary(), integer(), integer(), integer(), binary()) -> binary(). mac_hash(Method, Mac_write_secret, Seq_num, Type, Length, Fragment) -> - %% draft-ietf-tls-ssl-version3-00 - 5.2.3.1 + %% draft-ietf-tls-ssl-version3-00 - 5.2.3.1 %% hash(MAC_write_secret + pad_2 + %% hash(MAC_write_secret + pad_1 + seq_num + %% SSLCompressed.type + SSLCompressed.length + %% SSLCompressed.fragment)); - Mac = mac_hash(Method, Mac_write_secret, - [<<?UINT64(Seq_num), ?BYTE(Type), + Mac = mac_hash(Method, Mac_write_secret, + [<<?UINT64(Seq_num), ?BYTE(Type), ?UINT16(Length)>>, Fragment]), Mac. --spec setup_keys(binary(), binary(), binary(), - integer(), integer(), term(), integer()) -> - {binary(), binary(), binary(), - binary(), binary(), binary()}. +-spec setup_keys(binary(), binary(), binary(), + integer(), integer(), term(), integer()) -> + {binary(), binary(), binary(), + binary(), binary(), binary()}. setup_keys(MasterSecret, ServerRandom, ClientRandom, HS, KML, _EKML, IVS) -> KeyBlock = generate_keyblock(MasterSecret, ServerRandom, ClientRandom, @@ -133,7 +133,7 @@ setup_keys(MasterSecret, ServerRandom, ClientRandom, HS, KML, _EKML, IVS) -> -spec suites() -> [cipher_suite()]. suites() -> - [ + [ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA, ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA, ?TLS_RSA_WITH_AES_256_CBC_SHA, @@ -143,7 +143,7 @@ suites() -> ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA, ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA, ?TLS_RSA_WITH_AES_128_CBC_SHA, - %%?TLS_RSA_WITH_IDEA_CBC_SHA, + %%?TLS_RSA_WITH_IDEA_CBC_SHA, ?TLS_RSA_WITH_RC4_128_SHA, ?TLS_RSA_WITH_RC4_128_MD5, ?TLS_RSA_WITH_DES_CBC_SHA diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl index 066590afb1..fef1464c64 100644 --- a/lib/ssl/src/tls_handshake.erl +++ b/lib/ssl/src/tls_handshake.erl @@ -33,7 +33,7 @@ -include_lib("public_key/include/public_key.hrl"). -export([client_hello/8, server_hello/4, hello/4, - get_tls_handshake/3, encode_handshake/2, + get_tls_handshake/3, encode_handshake/2, decode_handshake/3, init_handshake_history/0, update_handshake_history/2]). %%==================================================================== @@ -197,17 +197,22 @@ update_handshake_history(Handshake, % special-case SSL2 client hello update_handshake_history({Handshake0, _Prev}, Data) -> {[Data|Handshake0], Handshake0}. -%%-------------------------------------------------------------------- -%%% Internal functions -%%-------------------------------------------------------------------- + get_tls_handshake_aux(Version, <<?BYTE(Type), ?UINT24(Length), Body:Length/binary,Rest/binary>>, Acc) -> Raw = <<?BYTE(Type), ?UINT24(Length), Body/binary>>, - H = decode_handshake(Version, Type, Body), - get_tls_handshake_aux(Version, Rest, [{H,Raw} | Acc]); + Handshake = decode_handshake(Version, Type, Body), + get_tls_handshake_aux(Version, Rest, [{Handshake,Raw} | Acc]); get_tls_handshake_aux(_Version, Data, Acc) -> {lists:reverse(Acc), Data}. +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- + +decode_handshake(_, ?HELLO_REQUEST, <<>>) -> + #hello_request{}; + %% Client hello v2. %% The server must be able to receive such messages, from clients that %% are willing to use ssl v3 or higher, but have ssl v2 compatibility. @@ -217,7 +222,7 @@ decode_handshake(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), CipherSuites:CSLength/binary, ChallengeData:CDLength/binary>>) -> #client_hello{client_version = {Major, Minor}, - random = ssl_ssl2:client_random(ChallengeData, CDLength), + random = ssl_v2:client_random(ChallengeData, CDLength), session_id = 0, cipher_suites = ssl_handshake:decode_suites('3_bytes', CipherSuites), compression_methods = [?NULL], diff --git a/lib/ssl/src/tls_record.erl b/lib/ssl/src/tls_record.erl index 1409a04763..9ab512f334 100644 --- a/lib/ssl/src/tls_record.erl +++ b/lib/ssl/src/tls_record.erl @@ -77,7 +77,7 @@ init_connection_states(Role) -> ConnectionEnd = record_protocol_role(Role), Current = initial_connection_state(ConnectionEnd), - Pending = empty_connection_state(ConnectionEnd), + Pending = ssl_record:empty_connection_state(ConnectionEnd), #connection_states{current_read = Current, pending_read = Pending, current_write = Current, @@ -265,7 +265,7 @@ activate_pending_connection_state(States = NewCurrent = Pending#connection_state{sequence_number = 0}, SecParams = Pending#connection_state.security_parameters, ConnectionEnd = SecParams#security_parameters.connection_end, - EmptyPending = empty_connection_state(ConnectionEnd), + EmptyPending = ssl_record:empty_connection_state(ConnectionEnd), SecureRenegotation = NewCurrent#connection_state.secure_renegotiation, NewPending = EmptyPending#connection_state{secure_renegotiation = SecureRenegotation}, States#connection_states{current_read = NewCurrent, @@ -278,7 +278,7 @@ activate_pending_connection_state(States = NewCurrent = Pending#connection_state{sequence_number = 0}, SecParams = Pending#connection_state.security_parameters, ConnectionEnd = SecParams#security_parameters.connection_end, - EmptyPending = empty_connection_state(ConnectionEnd), + EmptyPending = ssl_record:empty_connection_state(ConnectionEnd), SecureRenegotation = NewCurrent#connection_state.secure_renegotiation, NewPending = EmptyPending#connection_state{secure_renegotiation = SecureRenegotation}, States#connection_states{current_write = NewCurrent, @@ -591,21 +591,6 @@ initial_security_params(ConnectionEnd) -> ssl_cipher:security_parameters(highest_protocol_version(), ?TLS_NULL_WITH_NULL_NULL, SecParams). -empty_connection_state(ConnectionEnd) -> - SecParams = empty_security_params(ConnectionEnd), - #connection_state{security_parameters = SecParams}. - -empty_security_params(ConnectionEnd = ?CLIENT) -> - #security_parameters{connection_end = ConnectionEnd, - client_random = random()}; -empty_security_params(ConnectionEnd = ?SERVER) -> - #security_parameters{connection_end = ConnectionEnd, - server_random = random()}. -random() -> - Secs_since_1970 = calendar:datetime_to_gregorian_seconds( - calendar:universal_time()) - 62167219200, - Random_28_bytes = crypto:rand_bytes(28), - <<?UINT32(Secs_since_1970), Random_28_bytes/binary>>. record_protocol_role(client) -> ?CLIENT; @@ -667,7 +652,7 @@ decipher(TLS=#ssl_tls{type=Type, version=Version, fragment=Fragment}, CS0) -> CS1 = CS0#connection_state{cipher_state = CipherS1}, TLength = size(T), {MacHash, CS2} = hash_and_bump_seqno(CS1, Type, Version, TLength, T), - case is_correct_mac(Mac, MacHash) of + case ssl_record:is_correct_mac(Mac, MacHash) of true -> {TLS#ssl_tls{fragment = T}, CS2}; false -> @@ -696,19 +681,15 @@ hash_and_bump_seqno(#connection_state{sequence_number = SeqNo, Length, Fragment), {Hash, CS0#connection_state{sequence_number = SeqNo+1}}. -is_correct_mac(Mac, Mac) -> - true; -is_correct_mac(_M,_H) -> - false. mac_hash({_,_}, ?NULL, _MacSecret, _SeqNo, _Type, _Length, _Fragment) -> <<>>; mac_hash({3, 0}, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) -> - ssl_ssl3:mac_hash(MacAlg, MacSecret, SeqNo, Type, Length, Fragment); + ssl_v3:mac_hash(MacAlg, MacSecret, SeqNo, Type, Length, Fragment); mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) when N =:= 1; N =:= 2; N =:= 3 -> - ssl_tls1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version, + tls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version, Length, Fragment). sufficient_tlsv1_2_crypto_support() -> diff --git a/lib/ssl/src/tls_record.hrl b/lib/ssl/src/tls_record.hrl index 0e3552bafa..0be1e35458 100644 --- a/lib/ssl/src/tls_record.hrl +++ b/lib/ssl/src/tls_record.hrl @@ -27,13 +27,6 @@ -define(tls_record, true). -include("ssl_record.hrl"). %% Common TLS and DTLS records and Constantes --record(connection_states, { - current_read, - pending_read, - current_write, - pending_write - }). - %% Used to handle tls_plain_text, tls_compressed and tls_cipher_text -record(ssl_tls, { diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/tls_v1.erl index 8ab66d0627..2395e98642 100644 --- a/lib/ssl/src/ssl_tls1.erl +++ b/lib/ssl/src/tls_v1.erl @@ -22,7 +22,7 @@ %% Purpose: Handles tls1 encryption. %%---------------------------------------------------------------------- --module(ssl_tls1). +-module(tls_v1). -include("ssl_cipher.hrl"). -include("ssl_internal.hrl"). @@ -86,7 +86,7 @@ certificate_verify(HashAlgo, _Version, Handshake) -> -spec setup_keys(integer(), integer(), binary(), binary(), binary(), integer(), integer(), integer()) -> {binary(), binary(), binary(), - binary(), binary(), binary()}. + binary(), binary(), binary()}. setup_keys(Version, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize, KeyMatLen, IVSize) @@ -106,7 +106,7 @@ setup_keys(Version, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize WantedLength = 2 * (HashSize + KeyMatLen + IVSize), KeyBlock = prf(?MD5SHA, MasterSecret, "key expansion", [ServerRandom, ClientRandom], WantedLength), - <<ClientWriteMacSecret:HashSize/binary, + <<ClientWriteMacSecret:HashSize/binary, ServerWriteMacSecret:HashSize/binary, ClientWriteKey:KeyMatLen/binary, ServerWriteKey:KeyMatLen/binary, ClientIV:IVSize/binary, ServerIV:IVSize/binary>> = KeyBlock, @@ -167,22 +167,22 @@ setup_keys(Version, PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize, ServerWriteKey, ClientIV, ServerIV}. -spec mac_hash(integer(), binary(), integer(), integer(), tls_version(), - integer(), binary()) -> binary(). + integer(), binary()) -> binary(). -mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor}, +mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor}, Length, Fragment) -> %% RFC 2246 & 4346 - 6.2.3.1. %% HMAC_hash(MAC_write_secret, seq_num + TLSCompressed.type + %% TLSCompressed.version + TLSCompressed.length + %% TLSCompressed.fragment)); - Mac = hmac_hash(Method, Mac_write_secret, - [<<?UINT64(Seq_num), ?BYTE(Type), - ?BYTE(Major), ?BYTE(Minor), ?UINT16(Length)>>, + Mac = hmac_hash(Method, Mac_write_secret, + [<<?UINT64(Seq_num), ?BYTE(Type), + ?BYTE(Major), ?BYTE(Minor), ?UINT16(Length)>>, Fragment]), Mac. -spec suites(1|2|3) -> [cipher_suite()]. - + suites(Minor) when Minor == 1; Minor == 2-> case sufficent_ec_support() of true -> @@ -199,8 +199,8 @@ suites(Minor) when Minor == 3 -> no_ec_suites(3) ++ no_ec_suites(2) end. -all_suites(Minor) when Minor == 1; Minor == 2-> - [ +all_suites(Minor) when Minor == 1; Minor == 2-> + [ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA, @@ -224,7 +224,7 @@ all_suites(Minor) when Minor == 1; Minor == 2-> ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, ?TLS_RSA_WITH_AES_128_CBC_SHA, - + ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, ?TLS_ECDHE_RSA_WITH_RC4_128_SHA, ?TLS_RSA_WITH_RC4_128_SHA, @@ -232,32 +232,32 @@ all_suites(Minor) when Minor == 1; Minor == 2-> ?TLS_DHE_RSA_WITH_DES_CBC_SHA, ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA, ?TLS_ECDH_RSA_WITH_RC4_128_SHA, - + ?TLS_RSA_WITH_DES_CBC_SHA ]; -all_suites(3) -> +all_suites(3) -> [ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, - + ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, ?TLS_RSA_WITH_AES_256_CBC_SHA256, - + ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, - + ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, ?TLS_RSA_WITH_AES_128_CBC_SHA256 ]. -no_ec_suites(Minor) when Minor == 1; Minor == 2-> - [ +no_ec_suites(Minor) when Minor == 1; Minor == 2-> + [ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA, ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA, ?TLS_RSA_WITH_AES_256_CBC_SHA, @@ -272,7 +272,7 @@ no_ec_suites(Minor) when Minor == 1; Minor == 2-> ?TLS_DHE_RSA_WITH_DES_CBC_SHA, ?TLS_RSA_WITH_DES_CBC_SHA ]; -no_ec_suites(3) -> +no_ec_suites(3) -> [ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, @@ -323,7 +323,7 @@ p_hash(Secret, Seed, WantedLength, Method, N, Acc) -> %% ... Where A(0) = seed %% A(i) = HMAC_hash(secret, A(i-1)) -%% a(0, _Secret, Seed, _Method) -> +%% a(0, _Secret, Seed, _Method) -> %% Seed. %% a(N, Secret, Seed, Method) -> %% hmac_hash(Method, Secret, a(N-1, Secret, Seed, Method)). |