diff options
Diffstat (limited to 'lib/ssl')
| -rw-r--r-- | lib/ssl/src/dtls_connection.erl | 9 | ||||
| -rw-r--r-- | lib/ssl/src/dtls_handshake.erl | 404 | ||||
| -rw-r--r-- | lib/ssl/src/dtls_handshake.hrl | 4 | ||||
| -rw-r--r-- | lib/ssl/src/dtls_record.erl | 23 | 
4 files changed, 240 insertions, 200 deletions
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl index 823bed14fd..57f8dd86d3 100644 --- a/lib/ssl/src/dtls_connection.erl +++ b/lib/ssl/src/dtls_connection.erl @@ -341,8 +341,10 @@ code_change(_OldVsn, StateName, State, _Extra) ->  %%% Internal functions  %%--------------------------------------------------------------------  encode_handshake(Handshake, Version, ConnectionStates0, Hist0) -> -    {Handshake, FragmentedHandshake} = dtls_handshake:encode_handshake(Handshake, Version), -    Hist = ssl_handshake:update_handshake_history(Hist0, Handshake), +    Seq = sequence(ConnectionStates0), +    {EncHandshake, FragmentedHandshake} = dtls_handshake:encode_handshake(Handshake, Version, +								      Seq), +    Hist = ssl_handshake:update_handshake_history(Hist0, EncHandshake),      {Encoded, ConnectionStates} =          dtls_record:encode_handshake(FragmentedHandshake,   				     Version, ConnectionStates0), @@ -526,3 +528,6 @@ get_timeout(_) -> %% Place holder  next_state_connection(_, State) -> %% Place holder      {next_state, connection, State, get_timeout(State)}. +sequence(_) ->  +    %%TODO real imp +    1. diff --git a/lib/ssl/src/dtls_handshake.erl b/lib/ssl/src/dtls_handshake.erl index 2ab5598dea..31d525b295 100644 --- a/lib/ssl/src/dtls_handshake.erl +++ b/lib/ssl/src/dtls_handshake.erl @@ -20,11 +20,15 @@  -include("dtls_handshake.hrl").  -include("dtls_record.hrl").  -include("ssl_internal.hrl"). +-include("ssl_alert.hrl").  -export([client_hello/8, client_hello/9, hello/4,  	 get_dtls_handshake/2, -	 dtls_handshake_new_flight/1, dtls_handshake_new_epoch/1, -	 encode_handshake/2]). +	 %%dtls_handshake_new_flight/1, dtls_handshake_new_epoch/1, +	 encode_handshake/3]). + +-type dtls_handshake() :: #client_hello{} | #hello_verify_request{} |  +			  ssl_handshake:ssl_handshake().  %%====================================================================  %% Internal application API @@ -32,7 +36,7 @@  %%--------------------------------------------------------------------  -spec client_hello(host(), inet:port_number(), #connection_states{},  		   #ssl_options{}, integer(), atom(), boolean(), der_cert()) -> -			  #client_hello{}  | {retransmit, term()}. +			  #client_hello{}.  %%  %% Description: Creates a client hello message.  %%-------------------------------------------------------------------- @@ -45,21 +49,21 @@ client_hello(Host, Port, ConnectionStates, SslOpts,  %%--------------------------------------------------------------------  -spec client_hello(host(), inet:port_number(), term(), #connection_states{},  		   #ssl_options{}, integer(), atom(), boolean(), der_cert()) -> -			  #client_hello{} | {retransmit, term()}. +			  #client_hello{}.  %%  %% Description: Creates a client hello message.  %%--------------------------------------------------------------------  client_hello(Host, Port, Cookie, ConnectionStates, -	     #ssl_options{versions = _Versions, +	     #ssl_options{versions = Versions,  			  ciphers = UserSuites  			 } = SslOpts,  	     Cache, CacheCb, Renegotiation, OwnCert) -> -    Version =  [{254, 253}], %%dtls_record:highest_protocol_version(Versions), +    Version =  dtls_record:highest_protocol_version(Versions),      Pending = ssl_record:pending_connection_state(ConnectionStates, read),      SecParams = Pending#connection_state.security_parameters,      CipherSuites = ssl_handshake:available_suites(UserSuites, Version), -    Extensions = ssl_handshake:client_hello_extensions(Host, Version, CipherSuites, +    Extensions = ssl_handshake:client_hello_extensions(Host, dtls_v1:corresponding_tls_version(Version), CipherSuites,  						SslOpts, ConnectionStates, Renegotiation),      Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert), @@ -73,85 +77,113 @@ client_hello(Host, Port, Cookie, ConnectionStates,  		  extensions = Extensions  		 }. -hello(Address, Port, -      #ssl_tls{epoch = _Epoch, sequence_number = _Seq, -	       version = Version} = Record) -> -    case get_dtls_handshake(Record, -				dtls_handshake_new_flight(undefined)) of -	{[Hello | _], _} -> -	    hello(Address, Port, Version, Hello); -	{retransmit, HandshakeState} -> -	    {retransmit, HandshakeState} -    end. -					      -hello(Address, Port, Version, Hello) -> -    #client_hello{client_version = {Major, Minor}, -		  random = Random, -		  session_id = SessionId, -		  cipher_suites = CipherSuites, -		  compression_methods = CompressionMethods} = Hello, -    CookieData = [address_to_bin(Address, Port), -		  <<?BYTE(Major), ?BYTE(Minor)>>, -		  Random, SessionId, CipherSuites, CompressionMethods], -    Cookie = crypto:hmac(sha, <<"secret">>, CookieData), - -    case Hello of -	#client_hello{cookie = Cookie} -> -	    accept; -	_ -> -	    %% generate HelloVerifyRequest -	    HelloVerifyRequest = enc_hs(#hello_verify_request{protocol_version = Version, -									  cookie = Cookie}, -						    Version, 0, 1400), -	    {reply, HelloVerifyRequest} -    end. +hello(#server_hello{server_version = Version, random = Random, +		    cipher_suite = CipherSuite, +		    compression_method = Compression, +		    session_id = SessionId, extensions = HelloExt}, +      #ssl_options{versions = SupportedVersions} = SslOpt, +      ConnectionStates0, Renegotiation) -> +    case dtls_record:is_acceptable_version(Version, SupportedVersions) of +	true -> +	    handle_server_hello_extensions(Version, SessionId, Random, CipherSuite, +					   Compression, HelloExt, SslOpt, ConnectionStates0, Renegotiation); +	false -> +	    ?ALERT_REC(?FATAL, ?PROTOCOL_VERSION) +    end; -%%-------------------------------------------------------------------- -enc_hs(Package, Version, MsgSeq, Mss) -> -    {MsgType, Bin} = encode_handshake(Package, Version), +hello(#client_hello{client_version = ClientVersion}, _Options, {_,_,_,_,ConnectionStates,_}, _Renegotiation) ->       +    %% Return correct typ to make dialyzer happy until we have time to make the real imp. +    {ClientVersion, {new, #session{}}, ConnectionStates, #hello_extensions{}}. + +%% hello(Address, Port, +%%       #ssl_tls{epoch = _Epoch, sequence_number = _Seq, +%% 	       version = Version} = Record) -> +%%     case get_dtls_handshake(Record, +%% 				dtls_handshake_new_flight(undefined)) of +%% 	{[Hello | _], _} -> +%% 	    hello(Address, Port, Version, Hello); +%% 	{retransmit, HandshakeState} -> +%% 	    {retransmit, HandshakeState} +%%     end. +					      +%% hello(Address, Port, Version, Hello) -> +%%     #client_hello{client_version = {Major, Minor}, +%% 		  random = Random, +%% 		  session_id = SessionId, +%% 		  cipher_suites = CipherSuites, +%% 		  compression_methods = CompressionMethods} = Hello, +%%     CookieData = [address_to_bin(Address, Port), +%% 		  <<?BYTE(Major), ?BYTE(Minor)>>, +%% 		  Random, SessionId, CipherSuites, CompressionMethods], +%%     Cookie = crypto:hmac(sha, <<"secret">>, CookieData), + +%%     case Hello of +%% 	#client_hello{cookie = Cookie} -> +%% 	    accept; +%% 	_ -> +%% 	    %% generate HelloVerifyRequest +%% 	    HelloVerifyRequest = enc_hs(#hello_verify_request{protocol_version = Version, +%% 									  cookie = Cookie}, +%% 						    Version, 0, 1400), +%% 	    {reply, HelloVerifyRequest} +%%     end. + +%% %%-------------------------------------------------------------------- +encode_handshake(Handshake, Version, MsgSeq) -> +    {MsgType, Bin} = enc_handshake(Handshake, Version),      Len = byte_size(Bin), -    Handshake = [MsgType, ?uint24(Len), ?uint16(MsgSeq), ?uint24(0), ?uint24(Len), Bin], -    FragmentedHandshake = dtls_fragment(Mss, MsgType, Len, MsgSeq, Bin, 0, []), -    {Handshake, FragmentedHandshake}. +    EncHandshake = [MsgType, ?uint24(Len), ?uint16(MsgSeq), ?uint24(0), ?uint24(Len), Bin], +    FragmentedHandshake = dtls_fragment(erlang:iolist_size(EncHandshake), MsgType, Len, MsgSeq, Bin, 0, []), +    {EncHandshake, FragmentedHandshake}. -%-------------------------------------------------------------------- +%%--------------------------------------------------------------------  -spec get_dtls_handshake(#ssl_tls{}, #dtls_hs_state{} | binary()) -> -     {[dtls_handshake()], #dtls_hs_state{}} | {retransmit, #dtls_hs_state{}}. -% -% Description: Given a DTLS state and new data from ssl_record, collects -% and returns it as a list of handshake messages, also returns a new -% DTLS state -%-------------------------------------------------------------------- -% get_dtls_handshake(Record, <<>>) -> -%     get_dtls_handshake_aux(Record, dtls_hs_state_init()); +				{[dtls_handshake()], #dtls_hs_state{}} | {retransmit, #dtls_hs_state{}}. +%% +%% Description: Given a DTLS state and new data from ssl_record, collects +%% and returns it as a list of handshake messages, also returns a new +%% DTLS state +%%-------------------------------------------------------------------- +get_dtls_handshake(Record, <<>>) -> +    get_dtls_handshake_aux(Record, #dtls_hs_state{}); %% Init handshake state!?  get_dtls_handshake(Record, HsState) ->      get_dtls_handshake_aux(Record, HsState). -%-------------------------------------------------------------------- --spec dtls_handshake_new_epoch(#dtls_hs_state{}) -> #dtls_hs_state{}. -% -% Description: Reset the DTLS decoder state for a new Epoch -%-------------------------------------------------------------------- -% dtls_handshake_new_epoch(<<>>) -> -%     dtls_hs_state_init(); -dtls_handshake_new_epoch(HsState) -> -    HsState#dtls_hs_state{highest_record_seq = 0, -			  starting_read_seq = HsState#dtls_hs_state.current_read_seq, -			  fragments = gb_trees:empty(), completed = []}. - -%-------------------------------------------------------------------- --spec dtls_handshake_new_flight(integer() | undefined) -> #dtls_hs_state{}. -% -% Description: Init the DTLS decoder state for a new Flight -dtls_handshake_new_flight(ExpectedReadReq) -> -    #dtls_hs_state{current_read_seq = ExpectedReadReq, -		   highest_record_seq = 0, -		   starting_read_seq = 0, -		   fragments = gb_trees:empty(), completed = []}. +%% %%-------------------------------------------------------------------- +%% -spec dtls_handshake_new_epoch(#dtls_hs_state{}) -> #dtls_hs_state{}. +%% %% +%% %% Description: Reset the DTLS decoder state for a new Epoch +%% %%-------------------------------------------------------------------- +%% dtls_handshake_new_epoch(<<>>) -> +%%     dtls_hs_state_init(); +%% dtls_handshake_new_epoch(HsState) -> +%%     HsState#dtls_hs_state{highest_record_seq = 0, +%%   			  starting_read_seq = HsState#dtls_hs_state.current_read_seq, +%%   			  fragments = gb_trees:empty(), completed = []}. + +%% %-------------------------------------------------------------------- +%% -spec dtls_handshake_new_flight(integer() | undefined) -> #dtls_hs_state{}. +%% % +%% % Description: Init the DTLS decoder state for a new Flight +%% dtls_handshake_new_flight(ExpectedReadReq) -> +%%     #dtls_hs_state{current_read_seq = ExpectedReadReq, +%% 		   highest_record_seq = 0, +%% 		   starting_read_seq = 0, +%% 		   fragments = gb_trees:empty(), completed = []}.  %%--------------------------------------------------------------------  %%% Internal functions  %%-------------------------------------------------------------------- +handle_server_hello_extensions(Version, SessionId, Random, CipherSuite, +			       Compression, HelloExt, SslOpt, ConnectionStates0, Renegotiation) -> +    case ssl_handshake:handle_server_hello_extensions(dtls_record, Random, CipherSuite, +						      Compression, HelloExt, Version, +						      SslOpt, ConnectionStates0, Renegotiation) of +	#alert{} = Alert -> +	    Alert; +	{ConnectionStates, Protocol} -> +	    {Version, SessionId, ConnectionStates, Protocol} +    end.  dtls_fragment(Mss, MsgType, Len, MsgSeq, Bin, Offset, Acc)    when byte_size(Bin) + 12 < Mss -> @@ -165,77 +197,77 @@ dtls_fragment(Mss, MsgType, Len, MsgSeq, Bin, Offset, Acc) ->      dtls_fragment(Mss, MsgType, Len, MsgSeq, Rest, Offset + FragmentLen, [BinMsg|Acc]).  get_dtls_handshake_aux(#ssl_tls{version = Version, -				sequence_number = SeqNo, -				fragment = Data}, HsState) -> + 				sequence_number = SeqNo, + 				fragment = Data}, HsState) ->      get_dtls_handshake_aux(Version, SeqNo, Data, HsState).  get_dtls_handshake_aux(Version, SeqNo, -		       <<?BYTE(Type), ?UINT24(Length), -			 ?UINT16(MessageSeq), -			 ?UINT24(FragmentOffset), ?UINT24(FragmentLength), -			 Body:FragmentLength/binary, Rest/binary>>, -		       HsState0) -> + 		       <<?BYTE(Type), ?UINT24(Length), + 			 ?UINT16(MessageSeq), + 			 ?UINT24(FragmentOffset), ?UINT24(FragmentLength), + 			 Body:FragmentLength/binary, Rest/binary>>, + 		       HsState0) ->      case reassemble_dtls_fragment(SeqNo, Type, Length, MessageSeq, -				 FragmentOffset, FragmentLength, -				 Body, HsState0) of -	{retransmit, HsState1} -> -	    case Rest of -		<<>> -> -		    {retransmit, HsState1}; -		_ -> -		    get_dtls_handshake_aux(Version, SeqNo, Rest, HsState1) -	    end; -	{HsState1, HighestSeqNo, MsgBody} -> -	    HsState2 = dec_dtls_fragment(Version, HighestSeqNo, Type, Length, MessageSeq, MsgBody, HsState1), -	    HsState3 = process_dtls_fragments(Version, HsState2), -	    get_dtls_handshake_aux(Version, SeqNo, Rest, HsState3); -	HsState2 -> -	    HsState3 = process_dtls_fragments(Version, HsState2), -	    get_dtls_handshake_aux(Version, SeqNo, Rest, HsState3) -    end; +				  FragmentOffset, FragmentLength, +				  Body, HsState0) of + 	{retransmit, HsState1} -> + 	    case Rest of + 		<<>> -> + 		    {retransmit, HsState1}; + 		_ -> + 		    get_dtls_handshake_aux(Version, SeqNo, Rest, HsState1) + 	    end; + 	{HsState1, HighestSeqNo, MsgBody} -> + 	    HsState2 = dec_dtls_fragment(Version, HighestSeqNo, Type, Length, MessageSeq, MsgBody, HsState1), + 	    HsState3 = process_dtls_fragments(Version, HsState2), + 	    get_dtls_handshake_aux(Version, SeqNo, Rest, HsState3); + 	HsState2 -> + 	    HsState3 = process_dtls_fragments(Version, HsState2), + 	    get_dtls_handshake_aux(Version, SeqNo, Rest, HsState3) +     end;  get_dtls_handshake_aux(_Version, _SeqNo, <<>>, HsState) -> -    {lists:reverse(HsState#dtls_hs_state.completed), -     HsState#dtls_hs_state{completed = []}}. +     {lists:reverse(HsState#dtls_hs_state.completed), +      HsState#dtls_hs_state{completed = []}}.  dec_dtls_fragment(Version, SeqNo, Type, Length, MessageSeq, MsgBody, -		  HsState = #dtls_hs_state{highest_record_seq = HighestSeqNo, completed = Acc}) -> + 		  HsState = #dtls_hs_state{highest_record_seq = HighestSeqNo, completed = Acc}) ->      Raw = <<?BYTE(Type), ?UINT24(Length), ?UINT16(MessageSeq), ?UINT24(0), ?UINT24(Length), MsgBody/binary>>,      H = decode_handshake(Version, Type, MsgBody),      HsState#dtls_hs_state{completed = [{H,Raw}|Acc], highest_record_seq = erlang:max(HighestSeqNo, SeqNo)}.  process_dtls_fragments(Version, -		       HsState0 = #dtls_hs_state{current_read_seq = CurrentReadSeq, -						 fragments = Fragments0}) -> + 		       HsState0 = #dtls_hs_state{current_read_seq = CurrentReadSeq, + 						 fragments = Fragments0}) ->      case gb_trees:is_empty(Fragments0) of -	true -> -	    HsState0; -	_ -> -	    case gb_trees:smallest(Fragments0) of -		{CurrentReadSeq, {SeqNo, Type, Length, CurrentReadSeq, {Length, [{0, Length}], MsgBody}}} -> -		    HsState1 = dtls_hs_state_process_seq(HsState0), -		    HsState2 = dec_dtls_fragment(Version, SeqNo, Type, Length, CurrentReadSeq, MsgBody, HsState1), -		    process_dtls_fragments(Version, HsState2); -		_ -> -		    HsState0 -	    end -    end. + 	true -> + 	    HsState0; + 	_ -> + 	    case gb_trees:smallest(Fragments0) of + 		{CurrentReadSeq, {SeqNo, Type, Length, CurrentReadSeq, {Length, [{0, Length}], MsgBody}}} -> + 		    HsState1 = dtls_hs_state_process_seq(HsState0), + 		    HsState2 = dec_dtls_fragment(Version, SeqNo, Type, Length, CurrentReadSeq, MsgBody, HsState1), + 		    process_dtls_fragments(Version, HsState2); + 		_ -> + 		    HsState0 + 	    end +     end.  dtls_hs_state_process_seq(HsState0 = #dtls_hs_state{current_read_seq = CurrentReadSeq, -						    fragments = Fragments0}) -> + 						    fragments = Fragments0}) ->      Fragments1 = gb_trees:delete_any(CurrentReadSeq, Fragments0),      HsState0#dtls_hs_state{current_read_seq = CurrentReadSeq + 1, -			   fragments = Fragments1}. + 			   fragments = Fragments1}.  dtls_hs_state_add_fragment(MessageSeq, Fragment, HsState0 = #dtls_hs_state{fragments = Fragments0}) ->      Fragments1 = gb_trees:enter(MessageSeq, Fragment, Fragments0),      HsState0#dtls_hs_state{fragments = Fragments1}.  reassemble_dtls_fragment(SeqNo, Type, Length, MessageSeq, 0, Length, -			 Body, HsState0 = #dtls_hs_state{current_read_seq = undefined}) + 			 Body, HsState0 = #dtls_hs_state{current_read_seq = undefined})    when Type == ?CLIENT_HELLO;         Type == ?SERVER_HELLO; -       Type == ?HELLO_VERIFY_REQUEST -> +        Type == ?HELLO_VERIFY_REQUEST ->      %% First message, should be client hello      %% return the current message and set the next expected Sequence      %% @@ -251,8 +283,8 @@ reassemble_dtls_fragment(_SeqNo, _Type, Length, _MessageSeq, _, Length,      HsState;  reassemble_dtls_fragment(SeqNo, _Type, Length, MessageSeq, 0, Length, -			 Body, HsState0 = -			     #dtls_hs_state{starting_read_seq = StartingReadSeq}) + 			 Body, HsState0 = + 			     #dtls_hs_state{starting_read_seq = StartingReadSeq})    when MessageSeq < StartingReadSeq ->      %% this has to be the start of a new flight, let it through      %% @@ -263,69 +295,69 @@ reassemble_dtls_fragment(SeqNo, _Type, Length, MessageSeq, 0, Length,      {HsState, SeqNo, Body};  reassemble_dtls_fragment(_SeqNo, _Type, Length, MessageSeq, 0, Length, -			 _Body, HsState = -			     #dtls_hs_state{current_read_seq = CurrentReadSeq}) + 			 _Body, HsState = + 			     #dtls_hs_state{current_read_seq = CurrentReadSeq})    when MessageSeq < CurrentReadSeq ->      {retransmit, HsState};  reassemble_dtls_fragment(_SeqNo, _Type, Length, MessageSeq, 0, Length, -			 _Body, HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq}) + 			 _Body, HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq})    when MessageSeq < CurrentReadSeq ->      HsState;  reassemble_dtls_fragment(SeqNo, _Type, Length, MessageSeq, 0, Length, -			 Body, HsState0 = #dtls_hs_state{current_read_seq = MessageSeq}) -> + 			 Body, HsState0 = #dtls_hs_state{current_read_seq = MessageSeq}) ->      %% Message fully contained and it's the current seq      HsState1 = dtls_hs_state_process_seq(HsState0),      {HsState1, SeqNo, Body};  reassemble_dtls_fragment(SeqNo, Type, Length, MessageSeq, 0, Length, -			 Body, HsState) -> + 			 Body, HsState) ->      %% Message fully contained and it's the NOT the current seq -> buffer      Fragment = {SeqNo, Type, Length, MessageSeq, -		dtls_fragment_init(Length, 0, Length, Body)}, + 		dtls_fragment_init(Length, 0, Length, Body)},      dtls_hs_state_add_fragment(MessageSeq, Fragment, HsState);  reassemble_dtls_fragment(_SeqNo, _Type, Length, MessageSeq, FragmentOffset, FragmentLength, -			 _Body, -			 HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq}) + 			 _Body, + 			 HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq})    when FragmentOffset + FragmentLength == Length andalso MessageSeq == (CurrentReadSeq - 1) ->      {retransmit, HsState};  reassemble_dtls_fragment(_SeqNo, _Type, _Length, MessageSeq, _FragmentOffset, _FragmentLength, -			 _Body, -			 HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq}) + 			 _Body, + 			 HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq})    when MessageSeq < CurrentReadSeq ->      HsState;  reassemble_dtls_fragment(SeqNo, Type, Length, MessageSeq, -			 FragmentOffset, FragmentLength, -			 Body, -			 HsState = #dtls_hs_state{fragments = Fragments0}) -> + 			 FragmentOffset, FragmentLength, + 			 Body, + 			 HsState = #dtls_hs_state{fragments = Fragments0}) ->      case gb_trees:lookup(MessageSeq, Fragments0) of -	{value, Fragment} -> -	    dtls_fragment_reassemble(SeqNo, Type, Length, MessageSeq, -				     FragmentOffset, FragmentLength, -				     Body, Fragment, HsState); -	none -> -	    dtls_fragment_start(SeqNo, Type, Length, MessageSeq, -				FragmentOffset, FragmentLength, -				Body, HsState) + 	{value, Fragment} -> + 	    dtls_fragment_reassemble(SeqNo, Type, Length, MessageSeq, + 				     FragmentOffset, FragmentLength, + 				     Body, Fragment, HsState); + 	none -> + 	    dtls_fragment_start(SeqNo, Type, Length, MessageSeq, + 				FragmentOffset, FragmentLength, + 				Body, HsState)      end.  dtls_fragment_start(SeqNo, Type, Length, MessageSeq, -				FragmentOffset, FragmentLength, -				Body, HsState = #dtls_hs_state{fragments = Fragments0}) -> +		    FragmentOffset, FragmentLength, +		    Body, HsState = #dtls_hs_state{fragments = Fragments0}) ->      Fragment = {SeqNo, Type, Length, MessageSeq, -		dtls_fragment_init(Length, FragmentOffset, FragmentLength, Body)}, -    Fragments1 = gb_trees:insert(MessageSeq, Fragment, Fragments0), + 		dtls_fragment_init(Length, FragmentOffset, FragmentLength, Body)}, +     Fragments1 = gb_trees:insert(MessageSeq, Fragment, Fragments0),      HsState#dtls_hs_state{fragments = Fragments1}.  dtls_fragment_reassemble(SeqNo, Type, Length, MessageSeq,  			 FragmentOffset, FragmentLength, -			 Body, -			 {LastSeqNo, Type, Length, MessageSeq, FragBuffer0}, -			 HsState = #dtls_hs_state{fragments = Fragments0}) -> + 			 Body, + 			 {LastSeqNo, Type, Length, MessageSeq, FragBuffer0}, + 			 HsState = #dtls_hs_state{fragments = Fragments0}) ->      FragBuffer1 = dtls_fragment_add(FragBuffer0, FragmentOffset, FragmentLength, Body),      Fragment = {erlang:max(SeqNo, LastSeqNo), Type, Length, MessageSeq, FragBuffer1},      Fragments1 = gb_trees:enter(MessageSeq, Fragment, Fragments0), @@ -334,8 +366,8 @@ dtls_fragment_reassemble(SeqNo, Type, Length, MessageSeq,  %% Type, Length or Seq mismatch, drop everything...  %% Note: the RFC is not clear on how to handle this...  dtls_fragment_reassemble(_SeqNo, _Type, _Length, MessageSeq, -			 _FragmentOffset, _FragmentLength, _Body, _Fragment, -			 HsState = #dtls_hs_state{fragments = Fragments0}) -> + 			 _FragmentOffset, _FragmentLength, _Body, _Fragment, + 			 HsState = #dtls_hs_state{fragments = Fragments0}) ->      Fragments1 = gb_trees:delete_any(MessageSeq, Fragments0),      HsState#dtls_hs_state{fragments = Fragments1}. @@ -366,7 +398,7 @@ merge_fragment_list(Rest = [{HStart, _HEnd}|_], Frag = {_FStart, FEnd}, Acc)      lists:reverse(Acc) ++ [Frag|Rest];  merge_fragment_list([{HStart, HEnd}|Rest], _Frag = {FStart, FEnd}, Acc) -  when +   when        FStart =< HEnd orelse FEnd >= HStart ->      Start = erlang:min(HStart, FStart),      End = erlang:max(HEnd, FEnd), @@ -376,20 +408,20 @@ merge_fragment_list([{HStart, HEnd}|Rest], _Frag = {FStart, FEnd}, Acc)  add_fragment(List, {FragmentOffset, FragmentLength}) ->      merge_fragment_list(List, {FragmentOffset, FragmentOffset + FragmentLength}, []). -encode_handshake(#hello_verify_request{protocol_version = {Major, Minor}, -				       cookie = Cookie}, _Version) -> -    CookieLength = byte_size(Cookie), +enc_handshake(#hello_verify_request{protocol_version = {Major, Minor}, + 				       cookie = Cookie}, _Version) -> +     CookieLength = byte_size(Cookie),      {?HELLO_VERIFY_REQUEST, <<?BYTE(Major), ?BYTE(Minor), -			      ?BYTE(CookieLength), -			      Cookie/binary>>}; - -encode_handshake(#client_hello{client_version = {Major, Minor}, -		     random = Random, -		     session_id = SessionID, -		     cookie = Cookie, -		     cipher_suites = CipherSuites, -		     compression_methods = CompMethods, -		     extensions = HelloExtensions}, Version) -> + 			      ?BYTE(CookieLength), + 			      Cookie/binary>>}; + +enc_handshake(#client_hello{client_version = {Major, Minor}, +			       random = Random, +			       session_id = SessionID, +			       cookie = Cookie, +			       cipher_suites = CipherSuites, +			       compression_methods = CompMethods, +			       extensions = HelloExtensions}, Version) ->      SIDLength = byte_size(SessionID),      BinCookie = enc_client_hello_cookie(Version, Cookie),      BinCompMethods = list_to_binary(CompMethods), @@ -397,13 +429,13 @@ encode_handshake(#client_hello{client_version = {Major, Minor},      BinCipherSuites = list_to_binary(CipherSuites),      CsLength = byte_size(BinCipherSuites),      ExtensionsBin = ssl_handshake:encode_hello_extensions(HelloExtensions), - +          {?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, -		      ?BYTE(SIDLength), SessionID/binary, -		      BinCookie/binary, -				?UINT16(CsLength), BinCipherSuites/binary, -		      ?BYTE(CmLength), BinCompMethods/binary, ExtensionsBin/binary>>}; -encode_handshake(HandshakeMsg, Version) -> + 		      ?BYTE(SIDLength), SessionID/binary, + 		      BinCookie/binary, +		      ?UINT16(CsLength), BinCipherSuites/binary, + 		      ?BYTE(CmLength), BinCompMethods/binary, ExtensionsBin/binary>>}; +enc_handshake(HandshakeMsg, Version) ->      ssl_handshake:encode_handshake(HandshakeMsg, Version).  enc_client_hello_cookie(_, <<>>) -> @@ -413,26 +445,26 @@ enc_client_hello_cookie(_, Cookie) ->      <<?BYTE(CookieLength), Cookie/binary>>.  decode_handshake(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, -		       ?BYTE(SID_length), Session_ID:SID_length/binary, -		       ?BYTE(Cookie_length), Cookie:Cookie_length/binary, -		       ?UINT16(Cs_length), CipherSuites:Cs_length/binary, -		       ?BYTE(Cm_length), Comp_methods:Cm_length/binary, -		       Extensions/binary>>) -> - +					    ?BYTE(SID_length), Session_ID:SID_length/binary, +					    ?BYTE(Cookie_length), Cookie:Cookie_length/binary, +					    ?UINT16(Cs_length), CipherSuites:Cs_length/binary, +					    ?BYTE(Cm_length), Comp_methods:Cm_length/binary, +					    Extensions/binary>>) -> +          DecodedExtensions = ssl_handshake:decode_hello_extensions(Extensions), - +          #client_hello{         client_version = {Major,Minor},         random = Random, -       session_id = Session_ID, +        session_id = Session_ID,         cookie = Cookie,         cipher_suites = ssl_handshake:decode_suites('2_bytes', CipherSuites),         compression_methods = Comp_methods,         extensions = DecodedExtensions -      }; +       };  decode_handshake(_Version, ?HELLO_VERIFY_REQUEST, <<?BYTE(Major), ?BYTE(Minor), -					  ?BYTE(CookieLength), Cookie:CookieLength/binary>>) -> +						    ?BYTE(CookieLength), Cookie:CookieLength/binary>>) ->      #hello_verify_request{         protocol_version = {Major,Minor}, @@ -440,7 +472,7 @@ decode_handshake(_Version, ?HELLO_VERIFY_REQUEST, <<?BYTE(Major), ?BYTE(Minor),  decode_handshake(Version, Tag, Msg) ->      ssl_handshake:decode_handshake(Version, Tag, Msg). -address_to_bin({A,B,C,D}, Port) -> -    <<0:80,16#ffff:16,A,B,C,D,Port:16>>; -address_to_bin({A,B,C,D,E,F,G,H}, Port) -> -    <<A:16,B:16,C:16,D:16,E:16,F:16,G:16,H:16,Port:16>>. +%% address_to_bin({A,B,C,D}, Port) -> +%%     <<0:80,16#ffff:16,A,B,C,D,Port:16>>; +%% address_to_bin({A,B,C,D,E,F,G,H}, Port) -> +%%     <<A:16,B:16,C:16,D:16,E:16,F:16,G:16,H:16,Port:16>>. diff --git a/lib/ssl/src/dtls_handshake.hrl b/lib/ssl/src/dtls_handshake.hrl index 5bdf45f627..3b57575b6d 100644 --- a/lib/ssl/src/dtls_handshake.hrl +++ b/lib/ssl/src/dtls_handshake.hrl @@ -1,7 +1,7 @@  %%  %% %CopyrightBegin%  %% -%% Copyright Ericsson AB 2013-2013. All Rights Reserved. +%% Copyright Ericsson AB 2013-2014. 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 @@ -53,6 +53,4 @@  	 completed  	}). --type dtls_handshake() :: #client_hello{} | #hello_verify_request{} | ssl_handshake(). -  -endif. % -ifdef(dtls_handshake). diff --git a/lib/ssl/src/dtls_record.erl b/lib/ssl/src/dtls_record.erl index 531e2612a5..a7bbb6bc40 100644 --- a/lib/ssl/src/dtls_record.erl +++ b/lib/ssl/src/dtls_record.erl @@ -46,6 +46,11 @@  -export([init_connection_state_seq/2, current_connection_state_epoch/2,  	 set_connection_state_by_epoch/3, connection_state_by_epoch/3]). +-export_type([dtls_version/0, dtls_atom_version/0]). + +-type dtls_version()       :: ssl_record:ssl_version(). +-type dtls_atom_version()  :: dtlsv1 | 'dtlsv1.2'. +  -compile(inline).  %%==================================================================== @@ -155,7 +160,7 @@ decode_cipher_text(#ssl_tls{type = Type, version = Version,  	    ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)      end.  %%-------------------------------------------------------------------- --spec encode_handshake(iolist(), tls_version(), #connection_states{}) -> +-spec encode_handshake(iolist(), dtls_version(), #connection_states{}) ->  			      {iolist(), #connection_states{}}.  %%  %% Description: Encodes a handshake message to send on the ssl-socket. @@ -164,7 +169,7 @@ encode_handshake(Frag, Version, ConnectionStates) ->      encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates).  %%-------------------------------------------------------------------- --spec encode_change_cipher_spec(tls_version(), #connection_states{}) -> +-spec encode_change_cipher_spec(dtls_version(), #connection_states{}) ->  				       {iolist(), #connection_states{}}.  %%  %% Description: Encodes a change_cipher_spec-message to send on the ssl socket. @@ -173,8 +178,8 @@ encode_change_cipher_spec(Version, ConnectionStates) ->      encode_plain_text(?CHANGE_CIPHER_SPEC, Version, <<1:8>>, ConnectionStates).  %%-------------------------------------------------------------------- --spec protocol_version(tls_atom_version() | tls_version()) -> -			      tls_version() | tls_atom_version(). +-spec protocol_version(dtls_atom_version() | dtls_version()) -> +			      dtls_version() | dtls_atom_version().  %%  %% Description: Creates a protocol version record from a version atom  %% or vice versa. @@ -188,7 +193,7 @@ protocol_version({254, 253}) ->  protocol_version({254, 255}) ->      dtlsv1.  %%-------------------------------------------------------------------- --spec lowest_protocol_version(tls_version(), tls_version()) -> tls_version(). +-spec lowest_protocol_version(dtls_version(), dtls_version()) -> dtls_version().  %%  %% Description: Lowes protocol version of two given versions  %%-------------------------------------------------------------------- @@ -201,7 +206,7 @@ lowest_protocol_version(Version = {M,_}, {N, _}) when M > N ->  lowest_protocol_version(_,Version) ->      Version.  %%-------------------------------------------------------------------- --spec highest_protocol_version([tls_version()]) -> tls_version(). +-spec highest_protocol_version([dtls_version()]) -> dtls_version().  %%  %% Description: Highest protocol version present in a list  %%-------------------------------------------------------------------- @@ -221,7 +226,7 @@ highest_protocol_version(_, [Version | Rest]) ->  %%-------------------------------------------------------------------- --spec supported_protocol_versions() -> [tls_version()]. +-spec supported_protocol_versions() -> [dtls_version()].  %%  %% Description: Protocol versions supported  %%-------------------------------------------------------------------- @@ -252,7 +257,7 @@ supported_connection_protocol_versions([]) ->      ?ALL_DATAGRAM_SUPPORTED_VERSIONS.  %%-------------------------------------------------------------------- --spec is_acceptable_version(tls_version(), Supported :: [tls_version()]) -> boolean(). +-spec is_acceptable_version(dtls_version(), Supported :: [dtls_version()]) -> boolean().  %%  %% Description: ssl version 2 is not acceptable security risks are too big.  %% @@ -262,7 +267,7 @@ is_acceptable_version(Version, Versions) ->  %%-------------------------------------------------------------------- --spec init_connection_state_seq(tls_version(), #connection_states{}) -> +-spec init_connection_state_seq(dtls_version(), #connection_states{}) ->  				       #connection_state{}.  %%  %% Description: Copy the read sequence number to the write sequence number  | 
