diff options
Diffstat (limited to 'lib/ssl/src')
-rw-r--r-- | lib/ssl/src/ssl_cipher.erl | 54 | ||||
-rw-r--r-- | lib/ssl/src/ssl_connection.erl | 14 | ||||
-rw-r--r-- | lib/ssl/src/ssl_handshake.erl | 25 | ||||
-rw-r--r-- | lib/ssl/src/ssl_record.erl | 51 |
4 files changed, 90 insertions, 54 deletions
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index daf4ef48b7..f425886ce5 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -28,10 +28,11 @@ -include("ssl_internal.hrl"). -include("ssl_record.hrl"). -include("ssl_cipher.hrl"). +-include("ssl_alert.hrl"). -include("ssl_debug.hrl"). -export([security_parameters/2, suite_definition/1, - decipher/4, cipher/4, + decipher/5, cipher/4, suite/1, suites/1, openssl_suite/1, openssl_suite_name/1]). @@ -123,7 +124,7 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0, {T, CS0#cipher_state{iv=NextIV}}. %%-------------------------------------------------------------------- -%% Function: decipher(Method, CipherState, Mac, Data) -> +%% Function: decipher(Method, CipherState, Mac, Data, Version) -> %% {Decrypted, UpdateCipherState} %% %% Method - integer() (as defined in ssl_cipher.hrl) @@ -133,9 +134,9 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0, %% Description: Decrypts the data and the mac using method, updating %% the cipher state %%------------------------------------------------------------------- -decipher(?NULL, _HashSz, CipherState, Fragment) -> +decipher(?NULL, _HashSz, CipherState, Fragment, _) -> {Fragment, <<>>, CipherState}; -decipher(?RC4, HashSz, CipherState, Fragment) -> +decipher(?RC4, HashSz, CipherState, Fragment, _) -> ?DBG_TERM(CipherState#cipher_state.key), State0 = case CipherState#cipher_state.state of undefined -> crypto:rc4_set_key(CipherState#cipher_state.key); @@ -148,43 +149,47 @@ decipher(?RC4, HashSz, CipherState, Fragment) -> GSC = generic_stream_cipher_from_bin(T, HashSz), #generic_stream_cipher{content=Content, mac=Mac} = GSC, {Content, Mac, CipherState#cipher_state{state=State1}}; -decipher(?DES, HashSz, CipherState, Fragment) -> +decipher(?DES, HashSz, CipherState, Fragment, Version) -> block_decipher(fun(Key, IV, T) -> crypto:des_cbc_decrypt(Key, IV, T) - end, CipherState, HashSz, Fragment); -%% decipher(?DES40, HashSz, CipherState, Fragment) -> + end, CipherState, HashSz, Fragment, Version); +%% decipher(?DES40, HashSz, CipherState, Fragment, Version) -> %% block_decipher(fun(Key, IV, T) -> %% crypto:des_cbc_decrypt(Key, IV, T) -%% end, CipherState, HashSz, Fragment); -decipher(?'3DES', HashSz, CipherState, Fragment) -> +%% end, CipherState, HashSz, Fragment, Version); +decipher(?'3DES', HashSz, CipherState, Fragment, Version) -> block_decipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) -> crypto:des3_cbc_decrypt(K1, K2, K3, IV, T) - end, CipherState, HashSz, Fragment); -decipher(?AES, HashSz, CipherState, Fragment) -> + end, CipherState, HashSz, Fragment, Version); +decipher(?AES, HashSz, CipherState, Fragment, Version) -> block_decipher(fun(Key, IV, T) when byte_size(Key) =:= 16 -> crypto:aes_cbc_128_decrypt(Key, IV, T); (Key, IV, T) when byte_size(Key) =:= 32 -> crypto:aes_cbc_256_decrypt(Key, IV, T) - end, CipherState, HashSz, Fragment). -%% decipher(?IDEA, HashSz, CipherState, Fragment) -> + end, CipherState, HashSz, Fragment, Version). +%% decipher(?IDEA, HashSz, CipherState, Fragment, Version) -> %% block_decipher(fun(Key, IV, T) -> %% crypto:idea_cbc_decrypt(Key, IV, T) -%% end, CipherState, HashSz, Fragment); +%% end, CipherState, HashSz, Fragment, Version); block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0, - HashSz, Fragment) -> + HashSz, Fragment, Version) -> ?DBG_HEX(Key), ?DBG_HEX(IV), ?DBG_HEX(Fragment), T = Fun(Key, IV, Fragment), ?DBG_HEX(T), GBC = generic_block_cipher_from_bin(T, HashSz), - ok = check_padding(GBC), %% TODO kolla ocks�... - Content = GBC#generic_block_cipher.content, - Mac = GBC#generic_block_cipher.mac, - CipherState1 = CipherState0#cipher_state{iv=next_iv(Fragment, IV)}, - {Content, Mac, CipherState1}. - + case is_correct_padding(GBC, Version) of + true -> + Content = GBC#generic_block_cipher.content, + Mac = GBC#generic_block_cipher.mac, + CipherState1 = CipherState0#cipher_state{iv=next_iv(Fragment, IV)}, + {Content, Mac, CipherState1}; + false -> + ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC) + end. + %%-------------------------------------------------------------------- %% Function: suites(Version) -> [Suite] %% @@ -540,9 +545,12 @@ generic_stream_cipher_from_bin(T, HashSz) -> #generic_stream_cipher{content=Content, mac=Mac}. -check_padding(_GBC) -> - ok. +is_correct_padding(_, {3, 0}) -> + true; +is_correct_padding(#generic_block_cipher{padding_length = Len, padding = Padding}, _) -> + list_to_binary(lists:duplicate(Len, Len)) == Padding. + get_padding(Length, BlockSize) -> get_padding_aux(BlockSize, Length rem BlockSize). diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 2e853c7cc8..644c2772b2 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -1137,6 +1137,8 @@ sync_send_all_state_event(FsmPid, Event, Timeout) -> exit:{timeout, _} -> {error, timeout}; exit:{normal, _} -> + {error, closed}; + exit:{shutdown, _} -> {error, closed} end. @@ -1284,7 +1286,6 @@ server_hello(ServerHello, #state{transport_cb = Transport, tls_handshake_hashes = Hashes0} = State) -> CipherSuite = ServerHello#server_hello.cipher_suite, {KeyAlgorithm, _, _} = ssl_cipher:suite_definition(CipherSuite), - %% Version = ServerHello#server_hello.server_version, TODO ska kontrolleras {BinMsg, ConnectionStates1, Hashes1} = encode_handshake(ServerHello, Version, ConnectionStates0, Hashes0), Transport:send(Socket, BinMsg), @@ -1726,6 +1727,9 @@ opposite_role(server) -> send_user(Pid, Msg) -> Pid ! Msg. +next_state(_, #alert{} = Alert, #state{negotiated_version = Version} = State) -> + handle_own_alert(Alert, Version, decipher_error, State), + {stop, normal, State}; next_state(Next, no_record, State) -> {next_state, Next, State}; @@ -1803,8 +1807,12 @@ next_record(#state{tls_cipher_texts = [], socket = Socket} = State) -> {no_record, State}; next_record(#state{tls_cipher_texts = [CT | Rest], connection_states = ConnStates0} = State) -> - {Plain, ConnStates} = ssl_record:decode_cipher_text(CT, ConnStates0), - {Plain, State#state{tls_cipher_texts = Rest, connection_states = ConnStates}}. + case ssl_record:decode_cipher_text(CT, ConnStates0) of + {Plain, ConnStates} -> + {Plain, State#state{tls_cipher_texts = Rest, connection_states = ConnStates}}; + #alert{} = Alert -> + {Alert, State} + end. next_record_if_active(State = #state{socket_options = diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 5f3dff8894..454d726f0d 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -128,16 +128,21 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version, session_id = SessionId, renegotiation_info = Info}, #ssl_options{secure_renegotiate = SecureRenegotation}, ConnectionStates0, Renegotiation) -> - - case handle_renegotiation_info(client, Info, ConnectionStates0, - Renegotiation, SecureRenegotation, []) of - {ok, ConnectionStates1} -> - ConnectionStates = - hello_pending_connection_states(client, CipherSuite, Random, - Compression, ConnectionStates1), - {Version, SessionId, ConnectionStates}; - #alert{} = Alert -> - Alert + + case ssl_record:is_acceptable_version(Version) of + true -> + case handle_renegotiation_info(client, Info, ConnectionStates0, + Renegotiation, SecureRenegotation, []) of + {ok, ConnectionStates1} -> + ConnectionStates = + hello_pending_connection_states(client, CipherSuite, Random, + Compression, ConnectionStates1), + {Version, SessionId, ConnectionStates}; + #alert{} = Alert -> + Alert + end; + false -> + ?ALERT_REC(?FATAL, ?PROTOCOL_VERSION) end; hello(#client_hello{client_version = ClientVersion, random = Random, diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl index 43f18d95a0..7c4b0ee959 100644 --- a/lib/ssl/src/ssl_record.erl +++ b/lib/ssl/src/ssl_record.erl @@ -517,13 +517,17 @@ decode_cipher_text(CipherText, ConnnectionStates0) -> #connection_state{compression_state = CompressionS0, security_parameters = SecParams} = ReadState0, CompressAlg = SecParams#security_parameters.compression_algorithm, - {Compressed, ReadState1} = decipher(CipherText, ReadState0), - {Plain, CompressionS1} = uncompress(CompressAlg, - Compressed, CompressionS0), - ConnnectionStates = ConnnectionStates0#connection_states{ - current_read = ReadState1#connection_state{ - compression_state = CompressionS1}}, - {Plain, ConnnectionStates}. + case decipher(CipherText, ReadState0) of + {Compressed, ReadState1} -> + {Plain, CompressionS1} = uncompress(CompressAlg, + Compressed, CompressionS0), + ConnnectionStates = ConnnectionStates0#connection_states{ + current_read = ReadState1#connection_state{ + compression_state = CompressionS1}}, + {Plain, ConnnectionStates}; + #alert{} = Alert -> + Alert + end. %%-------------------------------------------------------------------- %%% Internal functions @@ -647,29 +651,37 @@ encode_tls_cipher_text(Type, {MajVer, MinVer}, Fragment) -> cipher(Type, Version, Fragment, CS0) -> Length = erlang:iolist_size(Fragment), - {Hash, CS1=#connection_state{cipher_state = CipherS0, + {MacHash, CS1=#connection_state{cipher_state = CipherS0, security_parameters= #security_parameters{bulk_cipher_algorithm = BCA} }} = hash_and_bump_seqno(CS0, Type, Version, Length, Fragment), ?DBG_HEX(Fragment), - {Ciphered, CipherS1} = ssl_cipher:cipher(BCA, CipherS0, Hash, Fragment), + {Ciphered, CipherS1} = ssl_cipher:cipher(BCA, CipherS0, MacHash, Fragment), ?DBG_HEX(Ciphered), CS2 = CS1#connection_state{cipher_state=CipherS1}, {Ciphered, CS2}. decipher(TLS=#ssl_tls{type=Type, version=Version, fragment=Fragment}, CS0) -> SP = CS0#connection_state.security_parameters, - BCA = SP#security_parameters.bulk_cipher_algorithm, % eller Cipher? + BCA = SP#security_parameters.bulk_cipher_algorithm, HashSz = SP#security_parameters.hash_size, CipherS0 = CS0#connection_state.cipher_state, - {T, Mac, CipherS1} = ssl_cipher:decipher(BCA, HashSz, CipherS0, Fragment), - CS1 = CS0#connection_state{cipher_state = CipherS1}, - TLength = size(T), - {Hash, CS2} = hash_and_bump_seqno(CS1, Type, Version, TLength, Fragment), - ok = check_hash(Hash, Mac), - {TLS#ssl_tls{fragment = T}, CS2}. + case ssl_cipher:decipher(BCA, HashSz, CipherS0, Fragment, Version) of + {T, Mac, CipherS1} -> + 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 + true -> + {TLS#ssl_tls{fragment = T}, CS2}; + false -> + ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC) + end; + #alert{} = Alert -> + Alert + end. uncompress(?NULL, Data = #ssl_tls{type = _Type, version = _Version, @@ -690,8 +702,11 @@ hash_and_bump_seqno(#connection_state{sequence_number = SeqNo, Length, Fragment), {Hash, CS0#connection_state{sequence_number = SeqNo+1}}. -check_hash(_, _) -> - ok. %% TODO check this +is_correct_mac(Mac, Mac) -> + true; +is_correct_mac(_M,_H) -> + io:format("Mac ~p ~n Hash: ~p~n",[_M, _H]), + false. mac_hash({_,_}, ?NULL, _MacSecret, _SeqNo, _Type, _Length, _Fragment) -> |