diff options
Diffstat (limited to 'lib/ssl/test')
-rw-r--r-- | lib/ssl/test/ssl_basic_SUITE.erl | 289 | ||||
-rw-r--r-- | lib/ssl/test/ssl_packet_SUITE.erl | 46 | ||||
-rw-r--r-- | lib/ssl/test/ssl_session_cache_SUITE.erl | 11 | ||||
-rw-r--r-- | lib/ssl/test/ssl_test_lib.erl | 21 | ||||
-rw-r--r-- | lib/ssl/test/ssl_to_openssl_SUITE.erl | 8 |
5 files changed, 347 insertions, 28 deletions
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index d9cb8002ed..e68a4c375d 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -36,6 +36,7 @@ -define(LONG_TIMEOUT, 600000). -define(EXPIRE, 10). -define(SLEEP, 500). +-define(RENEGOTIATION_DISABLE_TIME, 12000). %% Test server callback functions %%-------------------------------------------------------------------- @@ -256,7 +257,9 @@ all() -> %%different_ca_peer_sign, no_reuses_session_server_restart_new_cert, no_reuses_session_server_restart_new_cert_file, reuseaddr, - hibernate, connect_twice + hibernate, connect_twice, renegotiate_dos_mitigate_active, + renegotiate_dos_mitigate_passive, + tcp_error_propagation_in_active_mode, rizzo, no_rizzo_rc4 ]. groups() -> @@ -393,8 +396,8 @@ controlling_process(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - ClientMsg = "Hello server", - ServerMsg = "Hello client", + ClientMsg = "Server hello", + ServerMsg = "Client hello", Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, @@ -415,11 +418,15 @@ controlling_process(Config) when is_list(Config) -> [self(), Client, Server]), receive + {ssl, _, "S"} -> + receive_s_rizzo_duong_beast(); {ssl, _, ServerMsg} -> receive {ssl, _, ClientMsg} -> ok end; + {ssl, _, "C"} -> + receive_c_rizzo_duong_beast(); {ssl, _, ClientMsg} -> receive {ssl, _, ServerMsg} -> @@ -440,6 +447,28 @@ controlling_process_result(Socket, Pid, Msg) -> ssl:send(Socket, Msg), no_result_msg. +receive_s_rizzo_duong_beast() -> + receive + {ssl, _, "erver hello"} -> + receive + {ssl, _, "C"} -> + receive + {ssl, _, "lient hello"} -> + ok + end + end + end. +receive_c_rizzo_duong_beast() -> + receive + {ssl, _, "lient hello"} -> + receive + {ssl, _, "S"} -> + receive + {ssl, _, "erver hello"} -> + ok + end + end + end. %%-------------------------------------------------------------------- controller_dies(doc) -> ["Test that the socket is closed after controlling process dies"]; @@ -1231,6 +1260,11 @@ upgrade_result(Socket) -> %% Make sure binary is inherited from tcp socket and that we do %% not get the list default! receive + {ssl, _, <<"H">>} -> + receive + {ssl, _, <<"ello world">>} -> + ok + end; {ssl, _, <<"Hello world">>} -> ok end. @@ -1532,14 +1566,14 @@ eoptions(Config) when is_list(Config) -> {cacertfile, ""}, {dhfile,'dh.pem' }, {ciphers, [{foo, bar, sha, ignore}]}, - {reuse_session, foo}, - {reuse_sessions, 0}, + {reuse_session, foo}, + {reuse_sessions, 0}, {renegotiate_at, "10"}, - {debug, 1}, + {debug, 1}, {mode, depech}, - {packet, 8.0}, - {packet_size, "2"}, - {header, a}, + {packet, 8.0}, + {packet_size, "2"}, + {header, a}, {active, trice}, {key, 'key.pem' }], @@ -2313,8 +2347,8 @@ server_verify_client_once_passive(Config) when is_list(Config) -> {options, [{active, false} | ClientOpts]}]), ssl_test_lib:check_result(Server, ok, Client0, ok), - ssl_test_lib:close(Client0), Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, + ssl_test_lib:close(Client0), Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, @@ -2340,7 +2374,7 @@ server_verify_client_once_active(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {?MODULE, send_recv_result_active, []}}, - {options, [{active, once}, {verify, verify_peer}, + {options, [{active, true}, {verify, verify_peer}, {verify_client_once, true} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), @@ -2351,8 +2385,8 @@ server_verify_client_once_active(Config) when is_list(Config) -> {options, [{active, true} | ClientOpts]}]), ssl_test_lib:check_result(Server, ok, Client0, ok), - ssl_test_lib:close(Client0), Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, + ssl_test_lib:close(Client0), Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, @@ -2389,8 +2423,8 @@ server_verify_client_once_active_once(Config) when is_list(Config) -> {options, [{active, once} | ClientOpts]}]), ssl_test_lib:check_result(Server, ok, Client0, ok), - ssl_test_lib:close(Client0), Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, + ssl_test_lib:close(Client0), Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, @@ -2724,17 +2758,28 @@ client_no_wrap_sequence_number(Config) when is_list(Config) -> {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), + Version = ssl_record:highest_protocol_version(ssl_record:supported_protocol_versions()), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, - trigger_renegotiate, [[ErlData, N+2]]}}, + trigger_renegotiate, [[ErlData, treashold(N, Version)]]}}, {options, [{reuse_sessions, false}, {renegotiate_at, N} | ClientOpts]}]), ssl_test_lib:check_result(Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). + + %% First two clauses handles 1/n-1 splitting countermeasure Rizzo/Duong-Beast +treashold(N, {3,0}) -> + (N div 2) + 1; +treashold(N, {3,1}) -> + (N div 2) + 1; +treashold(N, _) -> + N + 1. + %%-------------------------------------------------------------------- server_no_wrap_sequence_number(doc) -> ["Test that erlang server will renegotiate session when", @@ -3647,6 +3692,166 @@ connect_twice(Config) when is_list(Config) -> ssl_test_lib:close(Client), ssl_test_lib:close(Client1). +%%-------------------------------------------------------------------- +renegotiate_dos_mitigate_active(doc) -> + ["Mitigate DOS computational attack by not allowing client to renegotiate many times in a row", + "immediately after each other"]; + +renegotiate_dos_mitigate_active(suite) -> + []; + +renegotiate_dos_mitigate_active(Config) when is_list(Config) -> + ServerOpts = ?config(server_opts, Config), + ClientOpts = ?config(client_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_recv_result_active, []}}, + {options, [ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + renegotiate_immediately, []}}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Client, ok, Server, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +renegotiate_dos_mitigate_passive(doc) -> + ["Mitigate DOS computational attack by not allowing client to renegotiate many times in a row", + "immediately after each other"]; + +renegotiate_dos_mitigate_passive(suite) -> + []; + +renegotiate_dos_mitigate_passive(Config) when is_list(Config) -> + ServerOpts = ?config(server_opts, Config), + ClientOpts = ?config(client_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_recv_result, []}}, + {options, [{active, false} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + renegotiate_immediately, []}}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Client, ok, Server, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +tcp_error_propagation_in_active_mode(doc) -> + ["Test that process recives {ssl_error, Socket, closed} when tcp error ocurres"]; +tcp_error_propagation_in_active_mode(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, no_result, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + {Client, #sslsocket{pid=Pid} = SslSocket} = ssl_test_lib:start_client([return_socket, + {node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, receive_msg, []}}, + {options, ClientOpts}]), + + {status, _, _, StatusInfo} = sys:get_status(Pid), + [_, _,_, _, Prop] = StatusInfo, + State = ssl_test_lib:state(Prop), + Socket = element(10, State), + + %% Fake tcp error + Pid ! {tcp_error, Socket, etimedout}, + + ssl_test_lib:check_result(Client, {ssl_closed, SslSocket}). +%%-------------------------------------------------------------------- + +rizzo(doc) -> ["Test that there is a 1/n-1-split for non RC4 in 'TLS < 1.1' as it is + vunrable to Rizzo/Dungon attack"]; + +rizzo(Config) when is_list(Config) -> + Ciphers = [X || X ={_,Y,_} <- ssl:cipher_suites(), Y =/= rc4_128], + run_send_recv_rizzo(Ciphers, Config, sslv3, + {?MODULE, send_recv_result_active_rizzo, []}), + run_send_recv_rizzo(Ciphers, Config, tlsv1, + {?MODULE, send_recv_result_active_rizzo, []}). + +no_rizzo_rc4(doc) -> + ["Test that there is no 1/n-1-split for RC4 as it is not vunrable to Rizzo/Dungon attack"]; + +no_rizzo_rc4(Config) when is_list(Config) -> + Ciphers = [X || X ={_,Y,_} <- ssl:cipher_suites(),Y == rc4_128], + run_send_recv_rizzo(Ciphers, Config, sslv3, + {?MODULE, send_recv_result_active_no_rizzo, []}), + run_send_recv_rizzo(Ciphers, Config, tlsv1, + {?MODULE, send_recv_result_active_no_rizzo, []}). + +run_send_recv_rizzo(Ciphers, Config, Version, Mfa) -> + Result = lists:map(fun(Cipher) -> + rizzo_test(Cipher, Config, Version, Mfa) end, + Ciphers), + case lists:flatten(Result) of + [] -> + ok; + Error -> + test_server:format("Cipher suite errors: ~p~n", [Error]), + test_server:fail(cipher_suite_failed_see_test_case_log) + end. + +rizzo_test(Cipher, Config, Version, Mfa) -> + {ClientOpts, ServerOpts} = client_server_opts(Cipher, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, Mfa}, + {options, [{active, true}, {ciphers, [Cipher]}, + {versions, [Version]} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, Mfa}, + {options, [{active, true} | ClientOpts]}]), + + Result = ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client), + case Result of + ok -> + []; + Error -> + [{Cipher, Error}] + end. + +client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == rsa orelse KeyAlgo == dhe_rsa -> + {?config(client_opts, Config), + ?config(server_opts, Config)}; +client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == dss orelse KeyAlgo == dhe_dss -> + {?config(client_dsa_opts, Config), + ?config(server_dsa_opts, Config)}. %%-------------------------------------------------------------------- %%% Internal functions @@ -3659,6 +3864,28 @@ send_recv_result(Socket) -> send_recv_result_active(Socket) -> ssl:send(Socket, "Hello world"), receive + {ssl, Socket, "H"} -> + receive + {ssl, Socket, "ello world"} -> + ok + end; + {ssl, Socket, "Hello world"} -> + ok + end. + +send_recv_result_active_rizzo(Socket) -> + ssl:send(Socket, "Hello world"), + receive + {ssl, Socket, "H"} -> + receive + {ssl, Socket, "ello world"} -> + ok + end + end. + +send_recv_result_active_no_rizzo(Socket) -> + ssl:send(Socket, "Hello world"), + receive {ssl, Socket, "Hello world"} -> ok end. @@ -3666,6 +3893,12 @@ send_recv_result_active(Socket) -> send_recv_result_active_once(Socket) -> ssl:send(Socket, "Hello world"), receive + {ssl, Socket, "H"} -> + ssl:setopts(Socket, [{active, once}]), + receive + {ssl, Socket, "ello world"} -> + ok + end; {ssl, Socket, "Hello world"} -> ok end. @@ -3690,6 +3923,25 @@ renegotiate_reuse_session(Socket, Data) -> test_server:sleep(?SLEEP), renegotiate(Socket, Data). +renegotiate_immediately(Socket) -> + receive + {ssl, Socket, "Hello world"} -> + ok; + %% Handle 1/n-1 splitting countermeasure Rizzo/Duong-Beast + {ssl, Socket, "H"} -> + receive + {ssl, Socket, "ello world"} -> + ok + end + end, + ok = ssl:renegotiate(Socket), + {error, renegotiation_rejected} = ssl:renegotiate(Socket), + test_server:sleep(?RENEGOTIATION_DISABLE_TIME +1), + ok = ssl:renegotiate(Socket), + test_server:format("Renegotiated again"), + ssl:send(Socket, "Hello world"), + ok. + new_config(PrivDir, ServerOpts0) -> CaCertFile = proplists:get_value(cacertfile, ServerOpts0), CertFile = proplists:get_value(certfile, ServerOpts0), @@ -3863,8 +4115,17 @@ erlang_ssl_receive(Socket, Data) -> {ssl, Socket, Data} -> io:format("Received ~p~n",[Data]), ok; + {ssl, Socket, Byte} when length(Byte) == 1 -> %% Handle 1/n-1 splitting countermeasure Rizzo/Duong-Beast + io:format("Received ~p~n",[Byte]), + erlang_ssl_receive(Socket, tl(Data)); Other -> test_server:fail({unexpected_message, Other}) after ?SLEEP * 3 -> test_server:fail({did_not_get, Data}) end. + +receive_msg(_) -> + receive + Msg -> + Msg + end. diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl index 9d2599b778..4b74f57a60 100644 --- a/lib/ssl/test/ssl_packet_SUITE.erl +++ b/lib/ssl/test/ssl_packet_SUITE.erl @@ -158,14 +158,24 @@ all() -> packet_asn1_decode, packet_asn1_decode_list, packet_tpkt_decode, packet_tpkt_decode_list, packet_sunrm_decode, packet_sunrm_decode_list, - header_decode_one_byte, header_decode_two_bytes, - header_decode_two_bytes_one_sent, - header_decode_two_bytes_two_sent]. + {group, header} + ]. groups() -> - []. + [{header, [], [ header_decode_one_byte, + header_decode_two_bytes, + header_decode_two_bytes_one_sent, + header_decode_two_bytes_two_sent]}]. + +init_per_group(header, Config) -> + case ssl_record:highest_protocol_version(ssl_record:supported_protocol_versions()) of + {3, N} when N < 2 -> + {skip, ""}; + _ -> + Config + end; -init_per_group(_GroupName, Config) -> +init_per_group(_, Config) -> Config. end_per_group(_GroupName, Config) -> @@ -2626,6 +2636,13 @@ active_once_raw(_, _, 0, _) -> ok; active_once_raw(Socket, Data, N, Acc) -> receive + {ssl, Socket, Byte} when length(Byte) == 1 -> + ssl:setopts(Socket, [{active, once}]), + receive + {ssl, Socket, _} -> + ssl:setopts(Socket, [{active, once}]), + active_once_raw(Socket, Data, N-1, []) + end; {ssl, Socket, Data} -> ssl:setopts(Socket, [{active, once}]), active_once_raw(Socket, Data, N-1, []); @@ -2648,7 +2665,14 @@ active_once_packet(Socket,_, 0) -> {other, Other, ssl:session_info(Socket), 0} end; active_once_packet(Socket, Data, N) -> - receive + receive + {ssl, Socket, Byte} when length(Byte) == 1 -> + ssl:setopts(Socket, [{active, once}]), + receive + {ssl, Socket, _} -> + ssl:setopts(Socket, [{active, once}]), + active_once_packet(Socket, Data, N-1) + end; {ssl, Socket, Data} -> ok end, @@ -2662,6 +2686,11 @@ active_raw(_Socket, _, 0, _) -> ok; active_raw(Socket, Data, N, Acc) -> receive + {ssl, Socket, Byte} when length(Byte) == 1 -> + receive + {ssl, Socket, _} -> + active_raw(Socket, Data, N -1) + end; {ssl, Socket, Data} -> active_raw(Socket, Data, N-1, []); {ssl, Socket, Other} -> @@ -2682,6 +2711,11 @@ active_packet(Socket, _, 0) -> end; active_packet(Socket, Data, N) -> receive + {ssl, Socket, Byte} when length(Byte) == 1 -> + receive + {ssl, Socket, _} -> + active_packet(Socket, Data, N -1) + end; {ssl, Socket, Data} -> active_packet(Socket, Data, N -1); Other -> diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl index 8cdfdec2ce..7f782233ef 100644 --- a/lib/ssl/test/ssl_session_cache_SUITE.erl +++ b/lib/ssl/test/ssl_session_cache_SUITE.erl @@ -210,7 +210,7 @@ session_cleanup(Config)when is_list(Config) -> {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), [_, _,_, _, Prop] = StatusInfo, - State = state(Prop), + State = ssl_test_lib:state(Prop), Cache = element(2, State), SessionTimer = element(6, State), @@ -238,15 +238,12 @@ session_cleanup(Config)when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). -state([{data,[{"State", State}]} | _]) -> - State; -state([_ | Rest]) -> - state(Rest). - check_timer(Timer) -> case erlang:read_timer(Timer) of false -> {status, _, _, _} = sys:get_status(whereis(ssl_manager)), + timer:sleep(?SLEEP), + {status, _, _, _} = sys:get_status(whereis(ssl_manager)), ok; Int -> test_server:sleep(Int), @@ -256,7 +253,7 @@ check_timer(Timer) -> get_delay_timer() -> {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)), [_, _,_, _, Prop] = StatusInfo, - State = state(Prop), + State = ssl_test_lib:state(Prop), case element(7, State) of undefined -> test_server:sleep(?SLEEP), diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index 46a8112a41..fa8a1826f2 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -662,6 +662,9 @@ cipher_result(Socket, Result) -> %% to properly test "cipher state" handling ssl:send(Socket, "Hello\n"), receive + {ssl, Socket, "H"} -> + ssl:send(Socket, " world\n"), + receive_rizzo_duong_beast(); {ssl, Socket, "Hello\n"} -> ssl:send(Socket, " world\n"), receive @@ -687,3 +690,21 @@ public_key(#'PrivateKeyInfo'{privateKeyAlgorithm = public_key:der_decode('DSAPrivateKey', iolist_to_binary(Key)); public_key(Key) -> Key. +receive_rizzo_duong_beast() -> + receive + {ssl, _, "ello\n"} -> + receive + {ssl, _, " "} -> + receive + {ssl, _, "world\n"} -> + ok + end + end + end. + +state([{data,[{"State", State}]} | _]) -> + State; +state([{data,[{"StateData", State}]} | _]) -> + State; +state([_ | Rest]) -> + state(Rest). diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index f37baeb9de..f04ab9af50 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -849,7 +849,9 @@ ssl3_erlang_server_erlang_client_client_cert(Config) when is_list(Config) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {?MODULE, - erlang_ssl_receive, [Data]}}, + erlang_ssl_receive, + %% Due to 1/n-1 splitting countermeasure Rizzo/Duong-Beast + [Data]}}, {options, [{verify , verify_peer} | ServerOpts]}]), @@ -858,6 +860,7 @@ ssl3_erlang_server_erlang_client_client_cert(Config) when is_list(Config) -> Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, + %% Due to 1/n-1 splitting countermeasure Rizzo/Duong-Beast {mfa, {ssl, send, [Data]}}, {options, [{versions, [sslv3]} | ClientOpts]}]), @@ -869,6 +872,7 @@ ssl3_erlang_server_erlang_client_client_cert(Config) when is_list(Config) -> process_flag(trap_exit, false), ok. + %%-------------------------------------------------------------------- tls1_erlang_client_openssl_server(doc) -> @@ -1350,6 +1354,8 @@ erlang_ssl_receive(Socket, Data) -> %% open_ssl server sometimes hangs waiting in blocking read ssl:send(Socket, "Got it"), ok; + {ssl, Socket, Byte} when length(Byte) == 1 -> + erlang_ssl_receive(Socket, tl(Data)); {Port, {data,Debug}} when is_port(Port) -> io:format("openssl ~s~n",[Debug]), erlang_ssl_receive(Socket,Data); |