aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl/test/ssl_basic_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl/test/ssl_basic_SUITE.erl')
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl316
1 files changed, 243 insertions, 73 deletions
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 8da1d947d3..228ec9e294 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -28,7 +28,6 @@
-include_lib("public_key/include/public_key.hrl").
-include("ssl_alert.hrl").
--include("ssl_int.hrl").
-include("ssl_internal.hrl").
-include("ssl_record.hrl").
@@ -37,6 +36,7 @@
-define(LONG_TIMEOUT, 600000).
-define(EXPIRE, 10).
-define(SLEEP, 500).
+-define(RENEGOTIATION_DISABLE_TIME, 12000).
%% Test server callback functions
%%--------------------------------------------------------------------
@@ -207,8 +207,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[app, alerts, connection_info, protocol_versions,
empty_protocol_versions, controlling_process,
- controller_dies, client_closes_socket, peercert,
- connect_dist, peername, sockname, socket_options,
+ controller_dies, client_closes_socket,
+ connect_dist, peername, peercert, sockname, socket_options,
invalid_inet_get_option, invalid_inet_get_option_not_list,
invalid_inet_get_option_improper_list,
invalid_inet_set_option, invalid_inet_set_option_not_list,
@@ -257,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
].
groups() ->
@@ -394,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()},
@@ -416,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} ->
@@ -441,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"];
@@ -584,50 +612,6 @@ client_closes_socket(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, {error,closed}).
%%--------------------------------------------------------------------
-
-peercert(doc) ->
- [""];
-
-peercert(suite) ->
- [];
-
-peercert(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, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, peercert_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, peercert_result, []}},
- {options, ClientOpts}]),
-
- CertFile = proplists:get_value(certfile, ServerOpts),
- [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile),
- ErlCert = public_key:pkix_decode_cert(BinCert, otp),
-
- ServerMsg = {{error, no_peercert}, {error, no_peercert}},
- ClientMsg = {{ok, BinCert}, {ok, ErlCert}},
-
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-peercert_result(Socket) ->
- Result1 = ssl:peercert(Socket),
- Result2 = ssl:peercert(Socket, [ssl]),
- {Result1, Result2}.
-
-%%--------------------------------------------------------------------
connect_dist(doc) ->
["Test a simple connect as is used by distribution"];
@@ -708,6 +692,44 @@ peername_result(S) ->
ssl:peername(S).
%%--------------------------------------------------------------------
+peercert(doc) ->
+ [""];
+peercert(suite) ->
+ [];
+peercert(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, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, peercert_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, peercert_result, []}},
+ {options, ClientOpts}]),
+
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile),
+
+ ServerMsg = {error, no_peercert},
+ ClientMsg = {ok, BinCert},
+
+ test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+peercert_result(Socket) ->
+ ssl:peercert(Socket).
+
+%%--------------------------------------------------------------------
sockname(doc) ->
["Test API function sockname/1"];
@@ -1238,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.
@@ -1528,7 +1555,6 @@ eoptions(Config) when is_list(Config) ->
end,
TestOpts = [{versions, [sslv2, sslv3]},
- {ssl_imp, cool},
{verify, 4},
{verify_fun, function},
{fail_if_no_peer_cert, 0},
@@ -1540,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' }],
@@ -2348,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),
@@ -2600,7 +2626,7 @@ client_renegotiate(Config) when is_list(Config) ->
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
{mfa, {?MODULE,
@@ -2732,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",
@@ -2792,7 +2829,7 @@ extended_key_usage_verify_peer(Config) when is_list(Config) ->
KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
[KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = public_key:pem_entry_decode(KeyEntry),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
ServerCertFile = proplists:get_value(certfile, ServerOpts),
NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"),
@@ -2854,7 +2891,7 @@ extended_key_usage_verify_none(Config) when is_list(Config) ->
KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
[KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = public_key:pem_entry_decode(KeyEntry),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
ServerCertFile = proplists:get_value(certfile, ServerOpts),
NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"),
@@ -2916,7 +2953,7 @@ no_authority_key_identifier(Config) when is_list(Config) ->
KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
[KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = public_key:pem_entry_decode(KeyEntry),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
CertFile = proplists:get_value(certfile, ServerOpts),
NewCertFile = filename:join(PrivDir, "server/new_cert.pem"),
@@ -2974,7 +3011,7 @@ invalid_signature_server(Config) when is_list(Config) ->
KeyFile = filename:join(PrivDir, "server/key.pem"),
[KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = public_key:pem_entry_decode(KeyEntry),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
ServerCertFile = proplists:get_value(certfile, ServerOpts),
NewServerCertFile = filename:join(PrivDir, "server/invalid_cert.pem"),
@@ -3014,7 +3051,7 @@ invalid_signature_client(Config) when is_list(Config) ->
KeyFile = filename:join(PrivDir, "client/key.pem"),
[KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = public_key:pem_entry_decode(KeyEntry),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
ClientCertFile = proplists:get_value(certfile, ClientOpts),
NewClientCertFile = filename:join(PrivDir, "client/invalid_cert.pem"),
@@ -3046,7 +3083,8 @@ tcp_delivery_workaround(Server, ServerMsg, Client, ClientMsg) ->
{Client, ClientMsg} ->
ok;
{Client, {error,closed}} ->
- test_server:format("client got close");
+ test_server:format("client got close"),
+ ok;
Unexpected ->
test_server:fail(Unexpected)
end;
@@ -3091,7 +3129,7 @@ cert_expired(Config) when is_list(Config) ->
KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
[KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = public_key:pem_entry_decode(KeyEntry),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
ServerCertFile = proplists:get_value(certfile, ServerOpts),
NewServerCertFile = filename:join(PrivDir, "server/expired_cert.pem"),
@@ -3366,14 +3404,14 @@ der_input_opts(Opts) ->
Keyfile = proplists:get_value(keyfile, Opts),
Dhfile = proplists:get_value(dhfile, Opts),
[{_, Cert, _}] = ssl_test_lib:pem_to_der(Certfile),
- [{_, Key, _}] = ssl_test_lib:pem_to_der(Keyfile),
+ [{Asn1Type, Key, _}] = ssl_test_lib:pem_to_der(Keyfile),
[{_, DHParams, _}] = ssl_test_lib:pem_to_der(Dhfile),
CaCerts =
lists:map(fun(Entry) ->
{_, CaCert, _} = Entry,
CaCert
end, ssl_test_lib:pem_to_der(CaCertsfile)),
- {Cert, {rsa, Key}, CaCerts, DHParams}.
+ {Cert, {Asn1Type, Key}, CaCerts, DHParams}.
%%--------------------------------------------------------------------
%% different_ca_peer_sign(doc) ->
@@ -3596,14 +3634,13 @@ hibernate(Config) ->
{from, self()},
{mfa, {?MODULE, send_recv_result_active, []}},
{options, [{hibernate_after, 1000}|ClientOpts]}]),
-
- { current_function, { _M, _F, _A } } =
+ {current_function, _} =
process_info(Pid, current_function),
timer:sleep(1100),
- { current_function, { erlang, hibernate, 3} } =
- process_info(Pid, current_function),
+ {current_function, {erlang, hibernate, 3}} =
+ process_info(Pid, current_function),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
@@ -3655,7 +3692,101 @@ 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}).
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -3667,6 +3798,11 @@ 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.
@@ -3674,6 +3810,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.
@@ -3698,6 +3840,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),
@@ -3871,8 +4032,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.