aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl')
-rw-r--r--lib/ssl/doc/src/ssl.xml4
-rw-r--r--lib/ssl/src/ssl.erl54
-rw-r--r--lib/ssl/src/ssl_connection.erl66
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl218
-rw-r--r--lib/ssl/test/ssl_session_cache_SUITE.erl1
5 files changed, 308 insertions, 35 deletions
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 0da6bbee5b..566068beaf 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -480,7 +480,6 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
</func>
<func>
- <name>getopts(Socket) -> </name>
<name>getopts(Socket, OptionNames) ->
{ok, [socketoption()]} | {error, Reason}</name>
<fsummary>Get the value of the specified options.</fsummary>
@@ -489,8 +488,7 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<v>OptionNames = [atom()]</v>
</type>
<desc>
- <p>Get the value of the specified socket options, if no
- options are specified all options are returned.
+ <p>Get the value of the specified socket options.
</p>
</desc>
</func>
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index a5e8e7e5c2..a0aedbbbee 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -112,7 +112,7 @@ connect(Socket, SslOptions) when is_port(Socket) ->
connect(Socket, SslOptions0, Timeout) when is_port(Socket) ->
EmulatedOptions = emulated_options(),
{ok, InetValues} = inet:getopts(Socket, EmulatedOptions),
- inet:setopts(Socket, internal_inet_values()),
+ ok = inet:setopts(Socket, internal_inet_values()),
try handle_options(SslOptions0 ++ InetValues, client) of
{ok, #config{cb=CbInfo, ssl=SslOptions, emulated=EmOpts}} ->
case inet:peername(Socket) of
@@ -238,7 +238,7 @@ ssl_accept(#sslsocket{} = Socket, Timeout) ->
ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) ->
EmulatedOptions = emulated_options(),
{ok, InetValues} = inet:getopts(Socket, EmulatedOptions),
- inet:setopts(Socket, internal_inet_values()),
+ ok = inet:setopts(Socket, internal_inet_values()),
try handle_options(SslOptions ++ InetValues, server) of
{ok, #config{cb=CbInfo,ssl=SslOpts, emulated=EmOpts}} ->
{ok, Port} = inet:port(Socket),
@@ -406,25 +406,51 @@ cipher_suites(openssl) ->
%%
%% Description: Gets options
%%--------------------------------------------------------------------
-getopts(#sslsocket{fd = new_ssl, pid = Pid}, OptTags) when is_pid(Pid) ->
- ssl_connection:get_opts(Pid, OptTags);
-getopts(#sslsocket{fd = new_ssl, pid = {ListenSocket, _}}, OptTags) ->
- inet:getopts(ListenSocket, OptTags);
-getopts(#sslsocket{} = Socket, Options) ->
+getopts(#sslsocket{fd = new_ssl, pid = Pid}, OptionTags) when is_pid(Pid), is_list(OptionTags) ->
+ ssl_connection:get_opts(Pid, OptionTags);
+getopts(#sslsocket{fd = new_ssl, pid = {ListenSocket, _}}, OptionTags) when is_list(OptionTags) ->
+ try inet:getopts(ListenSocket, OptionTags) of
+ {ok, _} = Result ->
+ Result;
+ {error, InetError} ->
+ {error, {eoptions, {inet_options, OptionTags, InetError}}}
+ catch
+ _:_ ->
+ {error, {eoptions, {inet_options, OptionTags}}}
+ end;
+getopts(#sslsocket{fd = new_ssl}, OptionTags) ->
+ {error, {eoptions, {inet_options, OptionTags}}};
+getopts(#sslsocket{} = Socket, OptionTags) ->
ensure_old_ssl_started(),
- ssl_broker:getopts(Socket, Options).
+ ssl_broker:getopts(Socket, OptionTags).
%%--------------------------------------------------------------------
-spec setopts(#sslsocket{}, [proplists:property()]) -> ok | {error, reason()}.
%%
%% Description: Sets options
%%--------------------------------------------------------------------
-setopts(#sslsocket{fd = new_ssl, pid = Pid}, Opts0) when is_pid(Pid) ->
- Opts = proplists:expand([{binary, [{mode, binary}]},
- {list, [{mode, list}]}], Opts0),
- ssl_connection:set_opts(Pid, Opts);
-setopts(#sslsocket{fd = new_ssl, pid = {ListenSocket, _}}, OptTags) ->
- inet:setopts(ListenSocket, OptTags);
+setopts(#sslsocket{fd = new_ssl, pid = Pid}, Options0) when is_pid(Pid), is_list(Options0) ->
+ try proplists:expand([{binary, [{mode, binary}]},
+ {list, [{mode, list}]}], Options0) of
+ Options ->
+ ssl_connection:set_opts(Pid, Options)
+ catch
+ _:_ ->
+ {error, {eoptions, {not_a_proplist, Options0}}}
+ end;
+
+setopts(#sslsocket{fd = new_ssl, pid = {ListenSocket, _}}, Options) when is_list(Options) ->
+ try inet:setopts(ListenSocket, Options) of
+ ok ->
+ ok;
+ {error, InetError} ->
+ {error, {eoptions, {inet_options, Options, InetError}}}
+ catch
+ _:Error ->
+ {error, {eoptions, {inet_options, Options, Error}}}
+ end;
+setopts(#sslsocket{fd = new_ssl}, Options) ->
+ {error, {eoptions,{not_a_proplist, Options}}};
setopts(#sslsocket{} = Socket, Options) ->
ensure_old_ssl_started(),
ssl_broker:setopts(Socket, Options).
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 2c452837f8..5550897a06 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -859,23 +859,23 @@ handle_sync_event({set_opts, Opts0}, _From, StateName,
#state{socket_options = Opts1,
socket = Socket,
user_data_buffer = Buffer} = State0) ->
- Opts = set_socket_opts(Socket, Opts0, Opts1, []),
+ {Reply, Opts} = set_socket_opts(Socket, Opts0, Opts1, []),
State1 = State0#state{socket_options = Opts},
if
Opts#socket_options.active =:= false ->
- {reply, ok, StateName, State1, get_timeout(State1)};
+ {reply, Reply, StateName, State1, get_timeout(State1)};
Buffer =:= <<>>, Opts1#socket_options.active =:= false ->
%% Need data, set active once
{Record, State2} = next_record_if_active(State1),
case next_state(StateName, Record, State2) of
{next_state, StateName, State, Timeout} ->
- {reply, ok, StateName, State, Timeout};
+ {reply, Reply, StateName, State, Timeout};
{stop, Reason, State} ->
{stop, Reason, State}
end;
Buffer =:= <<>> ->
%% Active once already set
- {reply, ok, StateName, State1, get_timeout(State1)};
+ {reply, Reply, StateName, State1, get_timeout(State1)};
true ->
case application_data(<<>>, State1) of
Stop = {stop,_,_} ->
@@ -883,7 +883,7 @@ handle_sync_event({set_opts, Opts0}, _From, StateName,
{Record, State2} ->
case next_state(StateName, Record, State2) of
{next_state, StateName, State, Timeout} ->
- {reply, ok, StateName, State, Timeout};
+ {reply, Reply, StateName, State, Timeout};
{stop, Reason, State} ->
{stop, Reason, State}
end
@@ -2040,31 +2040,67 @@ get_socket_opts(Socket, [active | Tags], SockOpts, Acc) ->
get_socket_opts(Socket, Tags, SockOpts,
[{active, SockOpts#socket_options.active} | Acc]);
get_socket_opts(Socket, [Tag | Tags], SockOpts, Acc) ->
- case inet:getopts(Socket, [Tag]) of
+ try inet:getopts(Socket, [Tag]) of
{ok, [Opt]} ->
get_socket_opts(Socket, Tags, SockOpts, [Opt | Acc]);
{error, Error} ->
- {error, Error}
- end.
+ {error, {eoptions, {inet_option, Tag, Error}}}
+ catch
+ %% So that inet behavior does not crash our process
+ _:Error -> {error, {eoptions, {inet_option, Tag, Error}}}
+ end;
+get_socket_opts(_,Opts, _,_) ->
+ {error, {eoptions, {inet_option, Opts, function_clause}}}.
set_socket_opts(_, [], SockOpts, []) ->
- SockOpts;
+ {ok, SockOpts};
set_socket_opts(Socket, [], SockOpts, Other) ->
%% Set non emulated options
- inet:setopts(Socket, Other),
- SockOpts;
-set_socket_opts(Socket, [{mode, Mode}| Opts], SockOpts, Other) ->
+ try inet:setopts(Socket, Other) of
+ ok ->
+ {ok, SockOpts};
+ {error, InetError} ->
+ {{error, {eoptions, {inet_options, Other, InetError}}}, SockOpts}
+ catch
+ _:Error ->
+ %% So that inet behavior does not crash our process
+ {{error, {eoptions, {inet_options, Other, Error}}}, SockOpts}
+ end;
+
+set_socket_opts(Socket, [{mode, Mode}| Opts], SockOpts, Other) when Mode == list; Mode == binary ->
set_socket_opts(Socket, Opts,
SockOpts#socket_options{mode = Mode}, Other);
-set_socket_opts(Socket, [{packet, Packet}| Opts], SockOpts, Other) ->
+set_socket_opts(_, [{mode, _} = Opt| _], SockOpts, _) ->
+ {{error, {eoptions, {inet_opt, Opt}}}, SockOpts};
+set_socket_opts(Socket, [{packet, Packet}| Opts], SockOpts, Other) when Packet == raw;
+ Packet == 0;
+ Packet == 1;
+ Packet == 2;
+ Packet == 4;
+ Packet == asn1;
+ Packet == cdr;
+ Packet == sunrm;
+ Packet == fcgi;
+ Packet == tpkt;
+ Packet == line;
+ Packet == http;
+ Packet == http_bin ->
set_socket_opts(Socket, Opts,
SockOpts#socket_options{packet = Packet}, Other);
-set_socket_opts(Socket, [{header, Header}| Opts], SockOpts, Other) ->
+set_socket_opts(_, [{packet, _} = Opt| _], SockOpts, _) ->
+ {{error, {eoptions, {inet_opt, Opt}}}, SockOpts};
+set_socket_opts(Socket, [{header, Header}| Opts], SockOpts, Other) when is_integer(Header) ->
set_socket_opts(Socket, Opts,
SockOpts#socket_options{header = Header}, Other);
-set_socket_opts(Socket, [{active, Active}| Opts], SockOpts, Other) ->
+set_socket_opts(_, [{header, _} = Opt| _], SockOpts, _) ->
+ {{error,{eoptions, {inet_opt, Opt}}}, SockOpts};
+set_socket_opts(Socket, [{active, Active}| Opts], SockOpts, Other) when Active == once;
+ Active == true;
+ Active == false ->
set_socket_opts(Socket, Opts,
SockOpts#socket_options{active = Active}, Other);
+set_socket_opts(_, [{active, _} = Opt| _], SockOpts, _) ->
+ {{error, {eoptions, {inet_opt, Opt}} }, SockOpts};
set_socket_opts(Socket, [Opt | Opts], SockOpts, Other) ->
set_socket_opts(Socket, Opts, SockOpts, [Opt | Other]).
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index ecb5228a8b..d9f4a76d80 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -25,7 +25,6 @@
-compile(export_all).
-include_lib("common_test/include/ct.hrl").
--include("test_server_line.hrl").
-include_lib("public_key/include/public_key.hrl").
-include("ssl_alert.hrl").
@@ -210,6 +209,10 @@ all() ->
empty_protocol_versions, controlling_process,
controller_dies, client_closes_socket, peercert,
connect_dist, peername, 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,
+ invalid_inet_set_option_improper_list,
misc_ssl_options, versions, cipher_suites, upgrade,
upgrade_with_timeout, tcp_connect, tcp_connect_big, ipv6, ekeyfile,
ecertfile, ecacertfile, eoptions, shutdown,
@@ -810,8 +813,218 @@ socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) ->
{ok,[{nodelay,false}]} = ssl:getopts(Socket, [nodelay]),
ssl:setopts(Socket, [{nodelay, true}]),
{ok,[{nodelay, true}]} = ssl:getopts(Socket, [nodelay]),
+ {ok, All} = ssl:getopts(Socket, []),
+ test_server:format("All opts ~p~n", [All]),
ok.
+
+
+%%--------------------------------------------------------------------
+invalid_inet_get_option(doc) ->
+ ["Test handling of invalid inet options in getopts"];
+
+invalid_inet_get_option(suite) ->
+ [];
+
+invalid_inet_get_option(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, {?MODULE, get_invalid_inet_option, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+
+ test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+get_invalid_inet_option(Socket) ->
+ {error, {eoptions, {inet_option, foo, _}}} = ssl:getopts(Socket, [foo]),
+ ok.
+
+%%--------------------------------------------------------------------
+invalid_inet_get_option_not_list(doc) ->
+ ["Test handling of invalid type in getopts"];
+
+invalid_inet_get_option_not_list(suite) ->
+ [];
+
+invalid_inet_get_option_not_list(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, {?MODULE, get_invalid_inet_option_not_list, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+
+ test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+get_invalid_inet_option_not_list(Socket) ->
+ {error, {eoptions, {inet_options, some_invalid_atom_here}}}
+ = ssl:getopts(Socket, some_invalid_atom_here),
+ ok.
+
+%%--------------------------------------------------------------------
+invalid_inet_get_option_improper_list(doc) ->
+ ["Test handling of invalid type in getopts"];
+
+invalid_inet_get_option_improper_list(suite) ->
+ [];
+
+invalid_inet_get_option_improper_list(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, {?MODULE, get_invalid_inet_option_improper_list, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+
+ test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+get_invalid_inet_option_improper_list(Socket) ->
+ {error, {eoptions, {inet_option, foo,_}}} = ssl:getopts(Socket, [packet | foo]),
+ ok.
+
+%%--------------------------------------------------------------------
+invalid_inet_set_option(doc) ->
+ ["Test handling of invalid inet options in setopts"];
+
+invalid_inet_set_option(suite) ->
+ [];
+
+invalid_inet_set_option(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, {?MODULE, set_invalid_inet_option, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+
+ test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+set_invalid_inet_option(Socket) ->
+ {error, {eoptions, {inet_opt, {packet, foo}}}} = ssl:setopts(Socket, [{packet, foo}]),
+ {error, {eoptions, {inet_opt, {header, foo}}}} = ssl:setopts(Socket, [{header, foo}]),
+ {error, {eoptions, {inet_opt, {active, foo}}}} = ssl:setopts(Socket, [{active, foo}]),
+ {error, {eoptions, {inet_opt, {mode, foo}}}} = ssl:setopts(Socket, [{mode, foo}]),
+ ok.
+%%--------------------------------------------------------------------
+invalid_inet_set_option_not_list(doc) ->
+ ["Test handling of invalid type in setopts"];
+
+invalid_inet_set_option_not_list(suite) ->
+ [];
+
+invalid_inet_set_option_not_list(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, {?MODULE, set_invalid_inet_option_not_list, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+
+ test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+set_invalid_inet_option_not_list(Socket) ->
+ {error, {eoptions, {not_a_proplist, some_invalid_atom_here}}}
+ = ssl:setopts(Socket, some_invalid_atom_here),
+ ok.
+
+%%--------------------------------------------------------------------
+invalid_inet_set_option_improper_list(doc) ->
+ ["Test handling of invalid tye in setopts"];
+
+invalid_inet_set_option_improper_list(suite) ->
+ [];
+
+invalid_inet_set_option_improper_list(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, {?MODULE, set_invalid_inet_option_improper_list, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+
+ test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+set_invalid_inet_option_improper_list(Socket) ->
+ {error, {eoptions, {not_a_proplist, [{packet, 0} | {foo, 2}]}}} =
+ ssl:setopts(Socket, [{packet, 0} | {foo, 2}]),
+ ok.
+
%%--------------------------------------------------------------------
misc_ssl_options(doc) ->
["Test what happens when we give valid options"];
@@ -3338,6 +3551,7 @@ reuseaddr(Config) when is_list(Config) ->
{options, [{active, false} | ClientOpts]}]),
test_server:sleep(?SLEEP),
ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client),
Server1 =
ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
@@ -3472,7 +3686,7 @@ session_cache_process_mnesia(suite) ->
session_cache_process_mnesia(Config) when is_list(Config) ->
session_cache_process(mnesia,Config).
-session_cache_process(Type,Config) when is_list(Config) ->
+session_cache_process(_Type,Config) when is_list(Config) ->
reuse_session(Config).
init([Type]) ->
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
index 6330b349f1..f80ac3c1a9 100644
--- a/lib/ssl/test/ssl_session_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_session_cache_SUITE.erl
@@ -270,7 +270,6 @@ session_cache_process_mnesia(suite) ->
session_cache_process_mnesia(Config) when is_list(Config) ->
session_cache_process(mnesia,Config).
-
%%--------------------------------------------------------------------
%%% Session cache API callbacks
%%--------------------------------------------------------------------