aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl')
-rw-r--r--lib/ssl/doc/src/ssl.xml9
-rw-r--r--lib/ssl/src/Makefile4
-rw-r--r--lib/ssl/src/dtls_connection.erl13
-rw-r--r--lib/ssl/src/dtls_listener_sup.erl (renamed from lib/ssl/src/dtls_udp_sup.erl)6
-rw-r--r--lib/ssl/src/dtls_packet_demux.erl (renamed from lib/ssl/src/dtls_udp_listener.erl)56
-rw-r--r--lib/ssl/src/dtls_socket.erl34
-rw-r--r--lib/ssl/src/inet_tls_dist.erl286
-rw-r--r--lib/ssl/src/ssl.app.src4
-rw-r--r--lib/ssl/src/ssl.erl53
-rw-r--r--lib/ssl/src/ssl_certificate.erl18
-rw-r--r--lib/ssl/src/ssl_connection_sup.erl10
-rw-r--r--lib/ssl/src/ssl_handshake.erl9
-rw-r--r--lib/ssl/src/ssl_internal.hrl5
-rw-r--r--lib/ssl/test/ssl_ECC_openssl_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl27
-rw-r--r--lib/ssl/test/ssl_certificate_verify_SUITE.erl56
-rw-r--r--lib/ssl/test/ssl_dist_bench_SUITE.erl15
-rw-r--r--lib/ssl/test/ssl_test_lib.erl12
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl28
19 files changed, 327 insertions, 320 deletions
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 029f29cdb3..825bf46459 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -89,6 +89,7 @@
[binary()]} | {client | server, [binary()], binary()}}</c></p>
<p><c>| {log_alert, boolean()}</c></p>
<p><c>| {server_name_indication, hostname() | disable}</c></p>
+ <p><c>| {customize_hostname_check, list()}</c></p>
<p><c>| {sni_hosts, [{hostname(), [ssl_option()]}]}</c></p>
<p><c>| {sni_fun, SNIfun::fun()}</c></p>
</item>
@@ -649,6 +650,14 @@ fun(srp, Username :: string(), UserState :: term()) ->
disables the hostname verification check
<seealso marker="public_key:public_key#pkix_verify_hostname-2">public_key:pkix_verify_hostname/2</seealso> </p>
</item>
+
+ <tag><c>{customize_hostname_check, Options::list()}</c></tag>
+ <item>
+ <p> Customizes the hostname verification of the peer certificate, as different protocols that use
+ TLS such as HTTP or LDAP may want to do it differently, for possible options see
+ <seealso marker="public_key:public_key#pkix_verify_hostname-3">public_key:pkix_verify_hostname/3</seealso> </p>
+ </item>
+
<tag><c>{fallback, boolean()}</c></tag>
<item>
<p> Send special cipher suite TLS_FALLBACK_SCSV to avoid undesired TLS version downgrade.
diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile
index 11b3e65912..c389aa8cfe 100644
--- a/lib/ssl/src/Makefile
+++ b/lib/ssl/src/Makefile
@@ -54,8 +54,8 @@ MODULES= \
ssl_connection_sup \
ssl_listen_tracker_sup\
dtls_connection_sup \
- dtls_udp_listener\
- dtls_udp_sup \
+ dtls_packet_demux \
+ dtls_listener_sup \
ssl_dist_sup\
ssl_dist_admin_sup\
ssl_dist_connection_sup\
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index 0fe568759d..4e3f65d9c6 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -137,9 +137,8 @@ next_record(#state{protocol_buffers =
Buffers#protocol_buffers{dtls_cipher_texts = Rest},
connection_states = ConnectionStates});
next_record(#state{role = server,
- socket = {Listener, {Client, _}},
- transport_cb = gen_udp} = State) ->
- dtls_udp_listener:active_once(Listener, Client, self()),
+ socket = {Listener, {Client, _}}} = State) ->
+ dtls_packet_demux:active_once(Listener, Client, self()),
{no_record, State};
next_record(#state{role = client,
socket = {_Server, Socket} = DTLSSocket,
@@ -448,7 +447,7 @@ init({call, From}, {start, Timeout},
},
{Record, State} = next_record(State3),
next_event(hello, Record, State, Actions);
-init({call, _} = Type, Event, #state{role = server, transport_cb = gen_udp} = State) ->
+init({call, _} = Type, Event, #state{role = server, data_tag = udp} = State) ->
Result = gen_handshake(?FUNCTION_NAME, Type, Event,
State#state{flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT},
protocol_specific = #{current_cookie_secret => dtls_v1:cookie_secret(),
@@ -922,7 +921,7 @@ handle_alerts([Alert | Alerts], {next_state, StateName, State}) ->
handle_alerts([Alert | Alerts], {next_state, StateName, State, _Actions}) ->
handle_alerts(Alerts, ssl_connection:handle_alert(Alert, StateName, State)).
-handle_own_alert(Alert, Version, StateName, #state{transport_cb = gen_udp,
+handle_own_alert(Alert, Version, StateName, #state{data_tag = udp,
role = Role,
ssl_options = Options} = State0) ->
case ignore_alert(Alert, State0) of
@@ -1013,10 +1012,10 @@ next_flight(Flight) ->
change_cipher_spec => undefined,
handshakes_after_change_cipher_spec => []}.
-handle_flight_timer(#state{transport_cb = gen_udp,
+handle_flight_timer(#state{data_tag = udp,
flight_state = {retransmit, Timeout}} = State) ->
start_retransmision_timer(Timeout, State);
-handle_flight_timer(#state{transport_cb = gen_udp,
+handle_flight_timer(#state{data_tag = udp,
flight_state = connection} = State) ->
{State, []};
handle_flight_timer(State) ->
diff --git a/lib/ssl/src/dtls_udp_sup.erl b/lib/ssl/src/dtls_listener_sup.erl
index 197882e92f..6939f1ef3b 100644
--- a/lib/ssl/src/dtls_udp_sup.erl
+++ b/lib/ssl/src/dtls_listener_sup.erl
@@ -23,7 +23,7 @@
%% Purpose: Supervisor for a procsses dispatching upd datagrams to
%% correct DTLS handler
%%----------------------------------------------------------------------
--module(dtls_udp_sup).
+-module(dtls_listener_sup).
-behaviour(supervisor).
@@ -52,10 +52,10 @@ init(_O) ->
MaxT = 3600,
Name = undefined, % As simple_one_for_one is used.
- StartFunc = {dtls_udp_listener, start_link, []},
+ StartFunc = {dtls_packet_demux, start_link, []},
Restart = temporary, % E.g. should not be restarted
Shutdown = 4000,
- Modules = [dtls_udp_listener],
+ Modules = [dtls_packet_demux],
Type = worker,
ChildSpec = {Name, StartFunc, Restart, Shutdown, Type, Modules},
diff --git a/lib/ssl/src/dtls_udp_listener.erl b/lib/ssl/src/dtls_packet_demux.erl
index 0608c6bd2b..1672626165 100644
--- a/lib/ssl/src/dtls_udp_listener.erl
+++ b/lib/ssl/src/dtls_packet_demux.erl
@@ -19,15 +19,15 @@
%%
--module(dtls_udp_listener).
+-module(dtls_packet_demux).
-behaviour(gen_server).
-include("ssl_internal.hrl").
%% API
--export([start_link/4, active_once/3, accept/2, sockname/1, close/1,
- get_all_opts/1, get_sock_opts/2, set_sock_opts/2]).
+-export([start_link/5, active_once/3, accept/2, sockname/1, close/1,
+ get_all_opts/1, get_sock_opts/2, set_sock_opts/2]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -36,6 +36,7 @@
-record(state,
{port,
listener,
+ transport,
dtls_options,
emulated_options,
dtls_msq_queues = kv_new(),
@@ -50,35 +51,36 @@
%%% API
%%%===================================================================
-start_link(Port, EmOpts, InetOptions, DTLSOptions) ->
- gen_server:start_link(?MODULE, [Port, EmOpts, InetOptions, DTLSOptions], []).
+start_link(Port, TransportInfo, EmOpts, InetOptions, DTLSOptions) ->
+ gen_server:start_link(?MODULE, [Port, TransportInfo, EmOpts, InetOptions, DTLSOptions], []).
-active_once(UDPConnection, Client, Pid) ->
- gen_server:cast(UDPConnection, {active_once, Client, Pid}).
+active_once(PacketSocket, Client, Pid) ->
+ gen_server:cast(PacketSocket, {active_once, Client, Pid}).
-accept(UDPConnection, Accepter) ->
- call(UDPConnection, {accept, Accepter}).
+accept(PacketSocket, Accepter) ->
+ call(PacketSocket, {accept, Accepter}).
-sockname(UDPConnection) ->
- call(UDPConnection, sockname).
-close(UDPConnection) ->
- call(UDPConnection, close).
-get_sock_opts(UDPConnection, SplitSockOpts) ->
- call(UDPConnection, {get_sock_opts, SplitSockOpts}).
-get_all_opts(UDPConnection) ->
- call(UDPConnection, get_all_opts).
-set_sock_opts(UDPConnection, Opts) ->
- call(UDPConnection, {set_sock_opts, Opts}).
+sockname(PacketSocket) ->
+ call(PacketSocket, sockname).
+close(PacketSocket) ->
+ call(PacketSocket, close).
+get_sock_opts(PacketSocket, SplitSockOpts) ->
+ call(PacketSocket, {get_sock_opts, SplitSockOpts}).
+get_all_opts(PacketSocket) ->
+ call(PacketSocket, get_all_opts).
+set_sock_opts(PacketSocket, Opts) ->
+ call(PacketSocket, {set_sock_opts, Opts}).
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
-init([Port, EmOpts, InetOptions, DTLSOptions]) ->
+init([Port, {TransportModule, _,_,_} = TransportInfo, EmOpts, InetOptions, DTLSOptions]) ->
try
- {ok, Socket} = gen_udp:open(Port, InetOptions),
+ {ok, Socket} = TransportModule:open(Port, InetOptions),
{ok, #state{port = Port,
first = true,
+ transport = TransportInfo,
dtls_options = DTLSOptions,
emulated_options = EmOpts,
listener = Socket,
@@ -134,20 +136,20 @@ handle_cast({active_once, Client, Pid}, State0) ->
State = handle_active_once(Client, Pid, State0),
{noreply, State}.
-handle_info({udp, Socket, IP, InPortNo, _} = Msg, #state{listener = Socket} = State0) ->
+handle_info({Transport, Socket, IP, InPortNo, _} = Msg, #state{listener = Socket, transport = {_,Transport,_,_}} = State0) ->
State = handle_datagram({IP, InPortNo}, Msg, State0),
next_datagram(Socket),
{noreply, State};
%% UDP socket does not have a connection and should not receive an econnreset
-%% This does however happens on on some windows versions. Just ignoring it
+%% This does however happens on some windows versions. Just ignoring it
%% appears to make things work as expected!
-handle_info({udp_error, Socket, econnreset = Error}, #state{listener = Socket} = State) ->
+handle_info({Error, Socket, econnreset = Error}, #state{listener = Socket, transport = {_,_,_, udp_error}} = State) ->
Report = io_lib:format("Ignore SSL UDP Listener: Socket error: ~p ~n", [Error]),
error_logger:info_report(Report),
{noreply, State};
-handle_info({udp_error, Socket, Error}, #state{listener = Socket} = State) ->
- Report = io_lib:format("SSL UDP Listener shutdown: Socket error: ~p ~n", [Error]),
+handle_info({Error, Socket, Error}, #state{listener = Socket, transport = {_,_,_, Error}} = State) ->
+ Report = io_lib:format("SSL Packet muliplxer shutdown: Socket error: ~p ~n", [Error]),
error_logger:info_report(Report),
{noreply, State#state{close=true}};
@@ -231,7 +233,7 @@ setup_new_connection(User, From, Client, Msg, #state{dtls_processes = Processes,
listener = Socket,
emulated_options = EmOpts} = State) ->
ConnArgs = [server, "localhost", Port, {self(), {Client, Socket}},
- {DTLSOpts, EmOpts, udp_listener}, User, dtls_socket:default_cb_info()],
+ {DTLSOpts, EmOpts, dtls_listener}, User, dtls_socket:default_cb_info()],
case dtls_connection_sup:start_child(ConnArgs) of
{ok, Pid} ->
erlang:monitor(process, Pid),
diff --git a/lib/ssl/src/dtls_socket.erl b/lib/ssl/src/dtls_socket.erl
index 0e4ab089dc..8dd62bc352 100644
--- a/lib/ssl/src/dtls_socket.erl
+++ b/lib/ssl/src/dtls_socket.erl
@@ -22,31 +22,31 @@
-include("ssl_internal.hrl").
-include("ssl_api.hrl").
--export([send/3, listen/3, accept/3, connect/4, socket/4, setopts/3, getopts/3, getstat/3,
+-export([send/3, listen/2, accept/3, connect/4, socket/4, setopts/3, getopts/3, getstat/3,
peername/2, sockname/2, port/2, close/2]).
-export([emulated_options/0, emulated_options/1, internal_inet_values/0, default_inet_values/0, default_cb_info/0]).
send(Transport, {{IP,Port},Socket}, Data) ->
Transport:send(Socket, IP, Port, Data).
-listen(gen_udp = Transport, Port, #config{transport_info = {Transport, _, _, _},
- ssl = SslOpts,
- emulated = EmOpts,
- inet_user = Options} = Config) ->
+listen(Port, #config{transport_info = TransportInfo,
+ ssl = SslOpts,
+ emulated = EmOpts,
+ inet_user = Options} = Config) ->
- case dtls_udp_sup:start_child([Port, emulated_socket_options(EmOpts, #socket_options{}),
+ case dtls_listener_sup:start_child([Port, TransportInfo, emulated_socket_options(EmOpts, #socket_options{}),
Options ++ internal_inet_values(), SslOpts]) of
{ok, Pid} ->
- {ok, #sslsocket{pid = {udp, Config#config{udp_handler = {Pid, Port}}}}};
+ {ok, #sslsocket{pid = {dtls, Config#config{dtls_handler = {Pid, Port}}}}};
Err = {error, _} ->
Err
end.
-accept(udp, #config{transport_info = {Transport = gen_udp,_,_,_},
+accept(dtls, #config{transport_info = {Transport,_,_,_},
connection_cb = ConnectionCb,
- udp_handler = {Listner, _}}, _Timeout) ->
- case dtls_udp_listener:accept(Listner, self()) of
+ dtls_handler = {Listner, _}}, _Timeout) ->
+ case dtls_packet_demux:accept(Listner, self()) of
{ok, Pid, Socket} ->
{ok, socket(Pid, Transport, {Listner, Socket}, ConnectionCb)};
{error, Reason} ->
@@ -69,7 +69,9 @@ connect(Address, Port, #config{transport_info = {Transport, _, _, _} = CbInfo,
end.
close(gen_udp, {_Client, _Socket}) ->
- ok.
+ ok;
+close(Transport, {_Client, Socket}) ->
+ Transport:close(Socket).
socket(Pid, gen_udp = Transport, {{_, _}, Socket}, ConnectionCb) ->
#sslsocket{pid = Pid,
@@ -79,18 +81,18 @@ socket(Pid, Transport, Socket, ConnectionCb) ->
#sslsocket{pid = Pid,
%% "The name "fd" is keept for backwards compatibility
fd = {Transport, Socket, ConnectionCb}}.
-setopts(_, #sslsocket{pid = {udp, #config{udp_handler = {ListenPid, _}}}}, Options) ->
+setopts(_, #sslsocket{pid = {dtls, #config{dtls_handler = {ListenPid, _}}}}, Options) ->
SplitOpts = tls_socket:split_options(Options),
- dtls_udp_listener:set_sock_opts(ListenPid, SplitOpts);
+ dtls_packet_demux:set_sock_opts(ListenPid, SplitOpts);
%%% Following clauses will not be called for emulated options, they are handled in the connection process
setopts(gen_udp, Socket, Options) ->
inet:setopts(Socket, Options);
setopts(Transport, Socket, Options) ->
Transport:setopts(Socket, Options).
-getopts(_, #sslsocket{pid = {udp, #config{udp_handler = {ListenPid, _}}}}, Options) ->
+getopts(_, #sslsocket{pid = {dtls, #config{dtls_handler = {ListenPid, _}}}}, Options) ->
SplitOpts = tls_socket:split_options(Options),
- dtls_udp_listener:get_sock_opts(ListenPid, SplitOpts);
+ dtls_packet_demux:get_sock_opts(ListenPid, SplitOpts);
getopts(gen_udp, #sslsocket{pid = {Socket, #config{emulated = EmOpts}}}, Options) ->
{SockOptNames, EmulatedOptNames} = tls_socket:split_options(Options),
EmulatedOpts = get_emulated_opts(EmOpts, EmulatedOptNames),
@@ -112,7 +114,7 @@ getstat(gen_udp, {_,Socket}, Options) ->
inet:getstat(Socket, Options);
getstat(Transport, Socket, Options) ->
Transport:getstat(Socket, Options).
-peername(udp, _) ->
+peername(_, undefined) ->
{error, enotconn};
peername(gen_udp, {_, {Client, _Socket}}) ->
{ok, Client};
diff --git a/lib/ssl/src/inet_tls_dist.erl b/lib/ssl/src/inet_tls_dist.erl
index a6ceff25cb..aa3d7e3f72 100644
--- a/lib/ssl/src/inet_tls_dist.erl
+++ b/lib/ssl/src/inet_tls_dist.erl
@@ -31,7 +31,7 @@
-export([nodelay/0]).
--export([verify_client/3, verify_server/3, cert_nodes/1]).
+-export([verify_client/3, cert_nodes/1]).
-export([dbg/0]). % Debug
@@ -236,12 +236,10 @@ accept_loop(Driver, Listen, Kernel) ->
end.
accept_loop(Driver, Listen, Kernel, Socket) ->
- {Opts,CertNodesFun} =
- setup_verify_client(
- Driver, Socket, get_ssl_options(server)),
+ Opts = setup_verify_client(Socket, get_ssl_options(server)),
wait_for_code_server(),
case
- ssl:ssl_accept(
+ ssl:handshake(
Socket,
trace([{active, false},{packet, 4}|Opts]),
net_kernel:connecttime())
@@ -255,7 +253,7 @@ accept_loop(Driver, Listen, Kernel, Socket) ->
{Kernel, controller, Pid} ->
ok = ssl:controlling_process(SslSocket, Pid),
trace(
- Pid ! {self(), controller, CertNodesFun});
+ Pid ! {self(), controller});
{Kernel, unsupported_protocol} ->
exit(trace(unsupported_protocol))
end,
@@ -278,48 +276,59 @@ accept_loop(Driver, Listen, Kernel, Socket) ->
%% as a configuration marker that verify_client/3 shall be used.
%%
%% Replace the State in the first occurence of
-%% {verify_fun,{fun ?MODULE:verify_client/3,State}} and remove the rest.
+%% {verify_fun,{fun ?MODULE:verify_client/3,State}}
+%% and remove the rest.
%% The inserted state is not accesible from a configuration file
%% since it is dynamic and connection dependent.
%%
-setup_verify_client(Driver, Socket, Opts) ->
- setup_verify_client(Driver, Socket, Opts, undefined, []).
+setup_verify_client(Socket, Opts) ->
+ setup_verify_client(Socket, Opts, true, []).
%%
-setup_verify_client(_Driver, _Socket, [], CertNodesFun, OptsR) ->
- {lists:reverse(OptsR),CertNodesFun};
-setup_verify_client(Driver, Socket, [Opt|Opts], CertNodesFun, OptsR) ->
+setup_verify_client(_Socket, [], _, OptsR) ->
+ lists:reverse(OptsR);
+setup_verify_client(Socket, [Opt|Opts], First, OptsR) ->
case Opt of
- {verify_fun,{Fun,NewCertNodesFun}} ->
+ {verify_fun,{Fun,_}} ->
case Fun =:= fun ?MODULE:verify_client/3 of
- true when is_function(NewCertNodesFun, 1) ->
+ true ->
if
- CertNodesFun =:= undefined ->
+ First ->
case inet:peername(Socket) of
{ok,{PeerIP,_Port}} ->
+ {ok,Allowed} = net_kernel:allowed(),
+ AllowedHosts = allowed_hosts(Allowed),
setup_verify_client(
- Driver, Socket, Opts, NewCertNodesFun,
+ Socket, Opts, false,
[{verify_fun,
- {Fun,
- {NewCertNodesFun,Driver,PeerIP}}}
+ {Fun, {AllowedHosts,PeerIP}}}
|OptsR]);
{error,Reason} ->
exit(trace({no_peername,Reason}))
end;
true ->
setup_verify_client(
- Driver, Socket, Opts, CertNodesFun, OptsR)
+ Socket, Opts, First, OptsR)
end;
- true ->
- exit(
- trace(
- {verify_client_bad_argument,CertNodesFun}));
false ->
setup_verify_client(
- Driver, Socket, Opts, CertNodesFun, [Opt|OptsR])
+ Socket, Opts, First, [Opt|OptsR])
end;
_ ->
- setup_verify_client(
- Driver, Socket, Opts, CertNodesFun, [Opt|OptsR])
+ setup_verify_client(Socket, Opts, First, [Opt|OptsR])
+ end.
+
+allowed_hosts(Allowed) ->
+ lists:usort(allowed_node_hosts(Allowed)).
+%%
+allowed_node_hosts([]) -> [];
+allowed_node_hosts([Node|Allowed]) ->
+ case dist_util:split_node(Node) of
+ {node,_,Host} ->
+ [Host|allowed_node_hosts(Allowed)];
+ {host,Host} ->
+ [Host|allowed_node_hosts(Allowed)];
+ _ ->
+ allowed_node_hosts(Allowed)
end.
%% Same as verify_peer but check cert host names for
@@ -330,48 +339,19 @@ verify_client(_, {extension,_}, S) ->
{unknown,S};
verify_client(_, valid, S) ->
{valid,S};
-verify_client(PeerCert, valid_peer, {CertNodesFun,Driver,PeerIP} = S) ->
- %%
- %% Parse out all node names from the peer's certificate
- %%
- case CertNodesFun(PeerCert) of
- undefined ->
- %% Certificate allows all nodes
+verify_client(_, valid_peer, {[],_} = S) ->
+ %% Allow all hosts
+ {valid,S};
+verify_client(PeerCert, valid_peer, {AllowedHosts,PeerIP} = S) ->
+ case
+ public_key:pkix_verify_hostname(
+ PeerCert,
+ [{ip,PeerIP}|[{dns_id,Host} || Host <- AllowedHosts]])
+ of
+ true ->
{valid,S};
- [] ->
- %% Certificate allows no nodes
- {fail,cert_missing_node_name};
- CertNodes ->
- %% Check if the IP address of one of the nodes
- %% in the peer certificate has the peer's IP address
- case filter_nodes_by_ip(CertNodes, Driver, PeerIP) of
- [] ->
- {fail,cert_no_host_with_peer_ip};
- _ ->
- {valid,S}
- end
- end.
-
-%% Filter out the nodes that has got the given IP address
-%%
-filter_nodes_by_ip(Nodes, Driver, IP) ->
- [Node ||
- Node <- Nodes,
- case dist_util:split_node(Node) of
- {node,_,Host} ->
- filter_host_by_ip(Host, Driver, IP);
- {host,Host} ->
- filter_host_by_ip(Host, Driver, IP);
- {name,_Name} ->
- true
- end].
-
-filter_host_by_ip(Host, Driver, IP) ->
- case Driver:getaddr(Host) of
- {ok,IP} ->
- true;
- _ ->
- false
+ false ->
+ {fail,cert_no_hostname_nor_ip_match}
end.
@@ -417,19 +397,18 @@ gen_accept_connection(
spawn_opt(
fun() ->
do_accept(
- Driver, Kernel, AcceptPid, DistCtrl,
- MyNode, Allowed, SetupTime)
+ Driver, AcceptPid, DistCtrl,
+ MyNode, Allowed, SetupTime, Kernel)
end,
[link, {priority, max}])).
-do_accept(Driver, Kernel, AcceptPid, DistCtrl, MyNode, Allowed, SetupTime) ->
+do_accept(
+ _Driver, AcceptPid, DistCtrl, MyNode, Allowed, SetupTime, Kernel) ->
SslSocket = ssl_connection:get_sslsocket(DistCtrl),
receive
- {AcceptPid, controller, CertNodesFun} ->
+ {AcceptPid, controller} ->
Timer = dist_util:start_timer(SetupTime),
- NewAllowed =
- allowed_nodes(
- Driver, CertNodesFun, SslSocket, Allowed),
+ NewAllowed = allowed_nodes(SslSocket, Allowed),
HSData0 = hs_data_common(SslSocket),
HSData =
HSData0#hs_data{
@@ -443,65 +422,67 @@ do_accept(Driver, Kernel, AcceptPid, DistCtrl, MyNode, Allowed, SetupTime) ->
dist_util:handshake_other_started(trace(HSData))
end.
-%% Return a list of allowed nodes according to
-%% the given Allowed list that matches the peer certificate
-%%
-allowed_nodes(_Driver, undefined, _SslSocket, Allowed) ->
- Allowed;
-allowed_nodes(Driver, CertNodesFun, SslSocket, Allowed) ->
+allowed_nodes(_SslSocket, []) ->
+ %% Allow all
+ [];
+allowed_nodes(SslSocket, Allowed) ->
case ssl:peercert(SslSocket) of
{ok,PeerCertDER} ->
case ssl:peername(SslSocket) of
{ok,{PeerIP,_Port}} ->
- PeerCert = public_key:pkix_decode_cert(PeerCertDER, otp),
- %%
- %% Parse out all node names from the peer's certificate
- %%
- case CertNodesFun(PeerCert) of
- undefined ->
- %% Certificate allows all nodes
- Allowed;
+ PeerCert =
+ public_key:pkix_decode_cert(PeerCertDER, otp),
+ case
+ allowed_nodes(
+ PeerCert, allowed_hosts(Allowed), PeerIP)
+ of
[] ->
- %% Certificate allows no nodes
- ?shutdown(cert_missing_node_name);
- CertNodes ->
- %% Filter out all nodes in the
- %% allowed list that is in peer
- %% certificate and that has got
- %% the same IP address as the peer
- allowed(
- filter_nodes_by_ip(
- CertNodes, Driver, PeerIP),
- Allowed)
+ error_logger:error_msg(
+ "** Connection attempt from "
+ "disallowed node(s) ~p ** ~n", [PeerIP]),
+ ?shutdown2(
+ PeerIP, trace({is_allowed, not_allowed}));
+ AllowedNodes ->
+ AllowedNodes
end;
Error1 ->
?shutdown2(no_peer_ip, trace(Error1))
end;
+ {error,no_peercert} ->
+ Allowed;
Error2 ->
?shutdown2(no_peer_cert, trace(Error2))
end.
-allowed(CertNodes, []) ->
- %% Empty allowed list means all allowed
- %% -> allow only certificate nodes
- CertNodes;
-allowed(CertNodes, Allowed) ->
- %% Find the intersection of the allowed list and certificate nodes
- case
- [CertNode ||
- CertNode <- CertNodes,
- dist_util:is_allowed(CertNode, Allowed)]
- of
- [] ->
- error_logger:error_msg(
- "** Connection attempt from "
- "disallowed node(s) ~p ** ~n", [CertNodes]),
- ?shutdown2(CertNodes, trace({is_allowed, not_allowed}));
- NewAllowed ->
- NewAllowed
+allowed_nodes(PeerCert, [], PeerIP) ->
+ case public_key:pkix_verify_hostname(PeerCert, [{ip,PeerIP}]) of
+ true ->
+ Host = inet:ntoa(PeerIP),
+ true = is_list(Host),
+ [Host];
+ false ->
+ []
+ end;
+allowed_nodes(PeerCert, [Node|Allowed], PeerIP) ->
+ case dist_util:split_node(Node) of
+ {node,_,Host} ->
+ allowed_nodes(PeerCert, Allowed, PeerIP, Node, Host);
+ {host,Host} ->
+ allowed_nodes(PeerCert, Allowed, PeerIP, Node, Host);
+ _ ->
+ allowed_nodes(PeerCert, Allowed, PeerIP)
+ end.
+
+allowed_nodes(PeerCert, Allowed, PeerIP, Node, Host) ->
+ case public_key:pkix_verify_hostname(PeerCert, [{dns_id,Host}]) of
+ true ->
+ [Node|allowed_nodes(PeerCert, Allowed, PeerIP)];
+ false ->
+ allowed_nodes(PeerCert, Allowed, PeerIP)
end.
+
setup(Node, Type, MyNode, LongOrShortNames, SetupTime) ->
gen_setup(inet_tcp, Node, Type, MyNode, LongOrShortNames, SetupTime).
@@ -541,15 +522,7 @@ do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
end.
do_setup_connect(Driver, Kernel, Node, Address, Ip, TcpPort, Version, Type, MyNode, Timer) ->
- Opts =
- trace(
- connect_options(
- %%
- %% Use verify_server/3 to verify that
- %% the server's certificate is for Node
- %%
- setup_verify_server(
- get_ssl_options(client), Node))),
+ Opts = trace(connect_options(get_ssl_options(client))),
dist_util:reset_timer(Timer),
case ssl:connect(
Address, TcpPort,
@@ -587,67 +560,6 @@ close(Socket) ->
gen_close(Driver, Socket) ->
trace(Driver:close(Socket)).
-%% {verify_fun,{fun ?MODULE:verify_server/3,_}} is used
-%% as a configuration marker that verify_server/3 shall be used.
-%%
-%% Replace the State in the first occurence of
-%% {verify_fun,{fun ?MODULE:verify_server/3,State}} and remove the rest.
-%% The inserted state is not accesible from a configuration file
-%% since it is dynamic and connection dependent.
-%%
-setup_verify_server(Opts, Node) ->
- setup_verify_server(Opts, Node, true).
-%%
-setup_verify_server([], _Node, _) ->
- [];
-setup_verify_server([Opt|Opts], Node, Once) ->
- case Opt of
- {verify_fun,{Fun,CertNodesFun}} ->
- case Fun =:= fun ?MODULE:verify_server/3 of
- true when not is_function(CertNodesFun, 1) ->
- ?shutdown2(
- Node,
- {verify_server_bad_argument,CertNodesFun});
- true when Once ->
- [{verify_fun,{Fun,{CertNodesFun,Node}}}
- |setup_verify_server(Opts, Node, false)];
- true ->
- setup_verify_server(Opts, Node, Once);
- false ->
- [Opt|setup_verify_server(Opts, Node, Once)]
- end;
- _ ->
- [Opt|setup_verify_server(Opts, Node, Once)]
- end.
-
-verify_server(_, {bad_cert,_} = Reason, _) ->
- {fail,Reason};
-verify_server(_, {extension,_}, S) ->
- {unknown,S};
-verify_server(_, valid, S) ->
- {valid,S};
-verify_server(PeerCert, valid_peer, {CertNodesFun,Node} = S) ->
- %%
- %% Parse out all node names from the peer's certificate
- %%
- case CertNodesFun(PeerCert) of
- undefined ->
- %% Certificate allows all nodes
- {valid,S};
- [] ->
- %% Certificate allows no nodes
- {fail,cert_missing_node_name};
- CertNodes ->
- %% Check that the node we are connecting to
- %% is in the peer certificate
- case dist_util:is_allowed(Node, CertNodes) of
- true ->
- {valid,S};
- false ->
- {fail,wrong_nodes_in_cert}
- end
- end.
-
%% ------------------------------------------------------------
%% Determine if EPMD module supports address resolving. Default
diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src
index 2aecb6836e..da281829cb 100644
--- a/lib/ssl/src/ssl.app.src
+++ b/lib/ssl/src/ssl.app.src
@@ -17,8 +17,8 @@
dtls_socket,
dtls_v1,
dtls_connection_sup,
- dtls_udp_listener,
- dtls_udp_sup,
+ dtls_packet_demux,
+ dtls_listener_sup,
%% API
ssl, %% Main API
tls, %% TLS specific
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index fb13a1ce7e..565cc9e1bc 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -234,7 +234,7 @@ handshake(#sslsocket{fd = {_, _, _, Tracker}} = Socket, SslOpts, Timeout) when
handshake(#sslsocket{pid = Pid, fd = {_, _, _}} = Socket, SslOpts, Timeout) when
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
try
- {ok, EmOpts, _} = dtls_udp_listener:get_all_opts(Pid),
+ {ok, EmOpts, _} = dtls_packet_demux:get_all_opts(Pid),
ssl_connection:handshake(Socket, {SslOpts,
tls_socket:emulated_socket_options(EmOpts, #socket_options{})}, Timeout)
catch
@@ -283,8 +283,8 @@ handshake_cancel(Socket) ->
%%--------------------------------------------------------------------
close(#sslsocket{pid = Pid}) when is_pid(Pid) ->
ssl_connection:close(Pid, {close, ?DEFAULT_TIMEOUT});
-close(#sslsocket{pid = {udp, #config{udp_handler = {Pid, _}}}}) ->
- dtls_udp_listener:close(Pid);
+close(#sslsocket{pid = {dtls, #config{dtls_handler = {Pid, _}}}}) ->
+ dtls_packet_demux:close(Pid);
close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}}}}) ->
Transport:close(ListenSocket).
@@ -311,10 +311,10 @@ close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}
%%--------------------------------------------------------------------
send(#sslsocket{pid = Pid}, Data) when is_pid(Pid) ->
ssl_connection:send(Pid, Data);
-send(#sslsocket{pid = {_, #config{transport_info={gen_udp, _, _, _}}}}, _) ->
+send(#sslsocket{pid = {_, #config{transport_info={_, udp, _, _}}}}, _) ->
{error,enotconn}; %% Emulate connection behaviour
-send(#sslsocket{pid = {udp,_}}, _) ->
- {error,enotconn};
+send(#sslsocket{pid = {dtls,_}}, _) ->
+ {error,enotconn}; %% Emulate connection behaviour
send(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport, _, _, _}}}}, Data) ->
Transport:send(ListenSocket, Data). %% {error,enotconn}
@@ -329,7 +329,7 @@ recv(Socket, Length) ->
recv(#sslsocket{pid = Pid}, Length, Timeout) when is_pid(Pid),
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
ssl_connection:recv(Pid, Length, Timeout);
-recv(#sslsocket{pid = {udp,_}}, _, _) ->
+recv(#sslsocket{pid = {dtls,_}}, _, _) ->
{error,enotconn};
recv(#sslsocket{pid = {Listen,
#config{transport_info = {Transport, _, _, _}}}}, _,_) when is_port(Listen)->
@@ -343,7 +343,7 @@ recv(#sslsocket{pid = {Listen,
%%--------------------------------------------------------------------
controlling_process(#sslsocket{pid = Pid}, NewOwner) when is_pid(Pid), is_pid(NewOwner) ->
ssl_connection:new_user(Pid, NewOwner);
-controlling_process(#sslsocket{pid = {udp, _}},
+controlling_process(#sslsocket{pid = {dtls, _}},
NewOwner) when is_pid(NewOwner) ->
ok; %% Meaningless but let it be allowed to conform with TLS
controlling_process(#sslsocket{pid = {Listen,
@@ -368,7 +368,7 @@ connection_information(#sslsocket{pid = Pid}) when is_pid(Pid) ->
end;
connection_information(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
{error, enotconn};
-connection_information(#sslsocket{pid = {udp,_}}) ->
+connection_information(#sslsocket{pid = {dtls,_}}) ->
{error,enotconn}.
%%--------------------------------------------------------------------
@@ -394,13 +394,11 @@ peername(#sslsocket{pid = Pid, fd = {Transport, Socket, _}}) when is_pid(Pid)->
dtls_socket:peername(Transport, Socket);
peername(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}) when is_pid(Pid)->
tls_socket:peername(Transport, Socket);
-peername(#sslsocket{pid = {udp = Transport, #config{udp_handler = {_Pid, _}}}}) ->
- dtls_socket:peername(Transport, undefined);
-peername(#sslsocket{pid = Pid, fd = {gen_udp= Transport, Socket, _, _}}) when is_pid(Pid) ->
- dtls_socket:peername(Transport, Socket);
+peername(#sslsocket{pid = {dtls, #config{dtls_handler = {_Pid, _}}}}) ->
+ dtls_socket:peername(dtls, undefined);
peername(#sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_,_}}}}) ->
tls_socket:peername(Transport, ListenSocket); %% Will return {error, enotconn}
-peername(#sslsocket{pid = {udp,_}}) ->
+peername(#sslsocket{pid = {dtls,_}}) ->
{error,enotconn}.
%%--------------------------------------------------------------------
@@ -415,7 +413,7 @@ peercert(#sslsocket{pid = Pid}) when is_pid(Pid) ->
Result ->
Result
end;
-peercert(#sslsocket{pid = {udp, _}}) ->
+peercert(#sslsocket{pid = {dtls, _}}) ->
{error, enotconn};
peercert(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
{error, enotconn}.
@@ -565,7 +563,7 @@ eccs_filter_supported(Curves) ->
%%--------------------------------------------------------------------
getopts(#sslsocket{pid = Pid}, OptionTags) when is_pid(Pid), is_list(OptionTags) ->
ssl_connection:get_opts(Pid, OptionTags);
-getopts(#sslsocket{pid = {udp, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, OptionTags) when is_list(OptionTags) ->
+getopts(#sslsocket{pid = {dtls, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, OptionTags) when is_list(OptionTags) ->
try dtls_socket:getopts(Transport, ListenSocket, OptionTags) of
{ok, _} = Result ->
Result;
@@ -603,7 +601,7 @@ setopts(#sslsocket{pid = Pid}, Options0) when is_pid(Pid), is_list(Options0) ->
_:_ ->
{error, {options, {not_a_proplist, Options0}}}
end;
-setopts(#sslsocket{pid = {udp, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, Options) when is_list(Options) ->
+setopts(#sslsocket{pid = {dtls, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, Options) when is_list(Options) ->
try dtls_socket:setopts(Transport, ListenSocket, Options) of
ok ->
ok;
@@ -660,7 +658,7 @@ getstat(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}, Options) when is_
shutdown(#sslsocket{pid = {Listen, #config{transport_info = {Transport,_, _, _}}}},
How) when is_port(Listen) ->
Transport:shutdown(Listen, How);
-shutdown(#sslsocket{pid = {udp,_}},_) ->
+shutdown(#sslsocket{pid = {dtls,_}},_) ->
{error, enotconn};
shutdown(#sslsocket{pid = Pid}, How) ->
ssl_connection:shutdown(Pid, How).
@@ -672,8 +670,8 @@ shutdown(#sslsocket{pid = Pid}, How) ->
%%--------------------------------------------------------------------
sockname(#sslsocket{pid = {Listen, #config{transport_info = {Transport, _, _, _}}}}) when is_port(Listen) ->
tls_socket:sockname(Transport, Listen);
-sockname(#sslsocket{pid = {udp, #config{udp_handler = {Pid, _}}}}) ->
- dtls_udp_listener:sockname(Pid);
+sockname(#sslsocket{pid = {dtls, #config{dtls_handler = {Pid, _}}}}) ->
+ dtls_packet_demux:sockname(Pid);
sockname(#sslsocket{pid = Pid, fd = {Transport, Socket, _}}) when is_pid(Pid) ->
dtls_socket:sockname(Transport, Socket);
sockname(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}) when is_pid(Pid) ->
@@ -707,7 +705,7 @@ versions() ->
%%--------------------------------------------------------------------
renegotiate(#sslsocket{pid = Pid}) when is_pid(Pid) ->
ssl_connection:renegotiation(Pid);
-renegotiate(#sslsocket{pid = {udp,_}}) ->
+renegotiate(#sslsocket{pid = {dtls,_}}) ->
{error, enotconn};
renegotiate(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
{error, enotconn}.
@@ -722,7 +720,7 @@ renegotiate(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
prf(#sslsocket{pid = Pid},
Secret, Label, Seed, WantedLength) when is_pid(Pid) ->
ssl_connection:prf(Pid, Secret, Label, Seed, WantedLength);
-prf(#sslsocket{pid = {udp,_}}, _,_,_,_) ->
+prf(#sslsocket{pid = {dtls,_}}, _,_,_,_) ->
{error, enotconn};
prf(#sslsocket{pid = {Listen,_}}, _,_,_,_) when is_port(Listen) ->
{error, enotconn}.
@@ -795,8 +793,8 @@ supported_suites(anonymous, Version) ->
do_listen(Port, #config{transport_info = {Transport, _, _, _}} = Config, tls_connection) ->
tls_socket:listen(Transport, Port, Config);
-do_listen(Port, #config{transport_info = {Transport, _, _, _}} = Config, dtls_connection) ->
- dtls_socket:listen(Transport, Port, Config).
+do_listen(Port, Config, dtls_connection) ->
+ dtls_socket:listen(Port, Config).
%% Handle extra ssl options given to ssl_accept
-spec handle_options([any()], #ssl_options{}) -> #ssl_options{}
@@ -940,7 +938,8 @@ handle_options(Opts0, Role, Host) ->
crl_check = handle_option(crl_check, Opts, false),
crl_cache = handle_option(crl_cache, Opts, {ssl_crl_cache, {internal, []}}),
max_handshake_size = handle_option(max_handshake_size, Opts, ?DEFAULT_MAX_HANDSHAKE_SIZE),
- handshake = handle_option(handshake, Opts, full)
+ handshake = handle_option(handshake, Opts, full),
+ customize_hostname_check = handle_option(customize_hostname_check, Opts, [])
},
CbInfo = proplists:get_value(cb_info, Opts, default_cb_info(Protocol)),
@@ -956,7 +955,7 @@ handle_options(Opts0, Role, Host) ->
client_preferred_next_protocols, log_alert,
server_name_indication, honor_cipher_order, padding_check, crl_check, crl_cache,
fallback, signature_algs, eccs, honor_ecc_order, beast_mitigation,
- max_handshake_size, handshake],
+ max_handshake_size, handshake, customize_hostname_check],
SockOpts = lists:foldl(fun(Key, PropList) ->
proplists:delete(Key, PropList)
end, Opts, SslOptions),
@@ -1199,6 +1198,8 @@ validate_option(handshake, hello = Value) ->
Value;
validate_option(handshake, full = Value) ->
Value;
+validate_option(customize_hostname_check, Value) when is_list(Value) ->
+ Value;
validate_option(Opt, Value) ->
throw({error, {options, {Opt, Value}}}).
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index a3333d35e9..dbd2ebf539 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -138,8 +138,8 @@ validate(_, {bad_cert, _} = Reason, _) ->
{fail, Reason};
validate(_, valid, UserState) ->
{valid, UserState};
-validate(Cert, valid_peer, UserState = {client, _,_, Hostname, _, _}) when Hostname =/= disable ->
- verify_hostname(Hostname, Cert, UserState);
+validate(Cert, valid_peer, UserState = {client, _,_, {Hostname, Customize}, _, _}) when Hostname =/= disable ->
+ verify_hostname(Hostname, Customize, Cert, UserState);
validate(_, valid_peer, UserState) ->
{valid, UserState}.
@@ -333,12 +333,12 @@ new_trusteded_chain(DerCert, [_ | Rest]) ->
new_trusteded_chain(_, []) ->
unknown_ca.
-verify_hostname({fallback, Hostname}, Cert, UserState) when is_list(Hostname) ->
- case public_key:pkix_verify_hostname(Cert, [{dns_id, Hostname}]) of
+verify_hostname({fallback, Hostname}, Customize, Cert, UserState) when is_list(Hostname) ->
+ case public_key:pkix_verify_hostname(Cert, [{dns_id, Hostname}], Customize) of
true ->
{valid, UserState};
false ->
- case public_key:pkix_verify_hostname(Cert, [{ip, Hostname}]) of
+ case public_key:pkix_verify_hostname(Cert, [{ip, Hostname}], Customize) of
true ->
{valid, UserState};
false ->
@@ -346,16 +346,16 @@ verify_hostname({fallback, Hostname}, Cert, UserState) when is_list(Hostname) ->
end
end;
-verify_hostname({fallback, Hostname}, Cert, UserState) ->
- case public_key:pkix_verify_hostname(Cert, [{ip, Hostname}]) of
+verify_hostname({fallback, Hostname}, Customize, Cert, UserState) ->
+ case public_key:pkix_verify_hostname(Cert, [{ip, Hostname}], Customize) of
true ->
{valid, UserState};
false ->
{fail, {bad_cert, hostname_check_failed}}
end;
-verify_hostname(Hostname, Cert, UserState) ->
- case public_key:pkix_verify_hostname(Cert, [{dns_id, Hostname}]) of
+verify_hostname(Hostname, Customize, Cert, UserState) ->
+ case public_key:pkix_verify_hostname(Cert, [{dns_id, Hostname}], Customize) of
true ->
{valid, UserState};
false ->
diff --git a/lib/ssl/src/ssl_connection_sup.erl b/lib/ssl/src/ssl_connection_sup.erl
index 1a1f43e683..1aa7c5844f 100644
--- a/lib/ssl/src/ssl_connection_sup.erl
+++ b/lib/ssl/src/ssl_connection_sup.erl
@@ -51,12 +51,12 @@ init([]) ->
ListenOptionsTracker = listen_options_tracker_child_spec(),
DTLSConnetionManager = dtls_connection_manager_child_spec(),
- DTLSUdpListeners = dtls_udp_listeners_spec(),
+ DTLSListeners = dtls_listeners_spec(),
{ok, {{one_for_one, 10, 3600}, [TLSConnetionManager,
ListenOptionsTracker,
DTLSConnetionManager,
- DTLSUdpListeners
+ DTLSListeners
]}}.
@@ -91,9 +91,9 @@ listen_options_tracker_child_spec() ->
Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
-dtls_udp_listeners_spec() ->
- Name = dtls_udp_listener,
- StartFunc = {dtls_udp_sup, start_link, []},
+dtls_listeners_spec() ->
+ Name = dtls_listener,
+ StartFunc = {dtls_listener_sup, start_link, []},
Restart = permanent,
Shutdown = 4000,
Modules = [],
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index ebbb633b22..71eeb00183 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -345,6 +345,7 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef,
Opts#ssl_options.partial_chain),
ValidationFunAndState = validation_fun_and_state(Opts#ssl_options.verify_fun, Role,
CertDbHandle, CertDbRef, ServerName,
+ Opts#ssl_options.customize_hostname_check,
Opts#ssl_options.crl_check, CRLDbHandle, CertPath),
case public_key:pkix_path_validation(TrustedCert,
CertPath,
@@ -1243,7 +1244,7 @@ certificate_authorities_from_db(_CertDbHandle, {extracted, CertDbData}) ->
%%-------------Handle handshake messages --------------------------------
validation_fun_and_state({Fun, UserState0}, Role, CertDbHandle, CertDbRef,
- ServerNameIndication, CRLCheck, CRLDbHandle, CertPath) ->
+ ServerNameIndication, CustomizeHostCheck, CRLCheck, CRLDbHandle, CertPath) ->
{fun(OtpCert, {extension, _} = Extension, {SslState, UserState}) ->
case ssl_certificate:validate(OtpCert,
Extension,
@@ -1260,9 +1261,9 @@ validation_fun_and_state({Fun, UserState0}, Role, CertDbHandle, CertDbRef,
(OtpCert, VerifyResult, {SslState, UserState}) ->
apply_user_fun(Fun, OtpCert, VerifyResult, UserState,
SslState, CertPath)
- end, {{Role, CertDbHandle, CertDbRef, ServerNameIndication, CRLCheck, CRLDbHandle}, UserState0}};
+ end, {{Role, CertDbHandle, CertDbRef, {ServerNameIndication, CustomizeHostCheck}, CRLCheck, CRLDbHandle}, UserState0}};
validation_fun_and_state(undefined, Role, CertDbHandle, CertDbRef,
- ServerNameIndication, CRLCheck, CRLDbHandle, CertPath) ->
+ ServerNameIndication, CustomizeHostCheck, CRLCheck, CRLDbHandle, CertPath) ->
{fun(OtpCert, {extension, _} = Extension, SslState) ->
ssl_certificate:validate(OtpCert,
Extension,
@@ -1282,7 +1283,7 @@ validation_fun_and_state(undefined, Role, CertDbHandle, CertDbRef,
ssl_certificate:validate(OtpCert,
VerifyResult,
SslState)
- end, {Role, CertDbHandle, CertDbRef, ServerNameIndication, CRLCheck, CRLDbHandle}}.
+ end, {Role, CertDbHandle, CertDbRef, {ServerNameIndication, CustomizeHostCheck}, CRLCheck, CRLDbHandle}}.
apply_user_fun(Fun, OtpCert, VerifyResult, UserState0,
{_, CertDbHandle, CertDbRef, _, CRLCheck, CRLDbHandle} = SslState, CertPath) when
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index 5df00de0e5..b736047678 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -145,7 +145,8 @@
eccs,
honor_ecc_order :: boolean(),
max_handshake_size :: integer(),
- handshake
+ handshake,
+ customize_hostname_check
}).
-record(socket_options,
@@ -160,7 +161,7 @@
-record(config, {ssl, %% SSL parameters
inet_user, %% User set inet options
emulated, %% Emulated option list or "inherit_tracker" pid
- udp_handler,
+ dtls_handler,
inet_ssl, %% inet options for internal ssl socket
transport_info, %% Callback info
connection_cb
diff --git a/lib/ssl/test/ssl_ECC_openssl_SUITE.erl b/lib/ssl/test/ssl_ECC_openssl_SUITE.erl
index 280fa94ecb..5a08b152a6 100644
--- a/lib/ssl/test/ssl_ECC_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_ECC_openssl_SUITE.erl
@@ -157,7 +157,7 @@ init_per_testcase(TestCase, Config) ->
ct:log("Ciphers: ~p~n ", [ssl:cipher_suites(default, Version)]),
end_per_testcase(TestCase, Config),
ssl:start(),
- ct:timetrap({seconds, 15}),
+ ct:timetrap({seconds, 30}),
Config.
end_per_testcase(_TestCase, Config) ->
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index d3b13050e3..162c63850f 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -686,11 +686,16 @@ hello_client_cancel(Config) when is_list(Config) ->
{host, Hostname},
{from, self()},
{options, ssl_test_lib:ssl_options([{handshake, hello}], Config)},
- {continue_options, cancel}]),
-
- ssl_test_lib:check_result(Server, {error, {tls_alert, "user canceled"}}).
-%%--------------------------------------------------------------------
+ {continue_options, cancel}]),
+ receive
+ {Server, {error, {tls_alert, "user canceled"}}} ->
+ ok;
+ {Server, {error, closed}} ->
+ ct:pal("Did not receive the ALERT"),
+ ok
+ end.
+%%--------------------------------------------------------------------
hello_server_cancel() ->
[{doc, "Test API function ssl:handshake_cancel/1 on the server side"}].
hello_server_cancel(Config) when is_list(Config) ->
@@ -2539,7 +2544,7 @@ anonymous_cipher_suites()->
[{doc,"Test the anonymous ciphersuites"}].
anonymous_cipher_suites(Config) when is_list(Config) ->
NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:anonymous_suites(NVersion),
+ Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(NVersion),
run_suites(Ciphers, Config, anonymous).
%%-------------------------------------------------------------------
psk_cipher_suites() ->
@@ -2635,7 +2640,7 @@ default_reject_anonymous(Config) when is_list(Config) ->
Version = ssl_test_lib:protocol_version(Config),
TLSVersion = ssl_test_lib:tls_version(Version),
- [CipherSuite | _] = ssl_test_lib:anonymous_suites(TLSVersion),
+ [CipherSuite | _] = ssl_test_lib:ecdh_dh_anonymous_suites(TLSVersion),
Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
{from, self()},
@@ -5046,8 +5051,14 @@ tls_downgrade_result(Socket) ->
tls_close(Socket) ->
ok = ssl_test_lib:send_recv_result(Socket),
- ok = ssl:close(Socket, 5000).
-
+ case ssl:close(Socket, 5000) of
+ ok ->
+ ok;
+ {error, closed} ->
+ ok;
+ Other ->
+ ct:fail(Other)
+ end.
%% First two clauses handles 1/n-1 splitting countermeasure Rizzo/Duong-Beast
treashold(N, {3,0}) ->
diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
index 1de4c89d7f..dca25b774b 100644
--- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl
+++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
@@ -87,7 +87,9 @@ tests() ->
extended_key_usage_verify_server,
critical_extension_verify_client,
critical_extension_verify_server,
- critical_extension_verify_none].
+ critical_extension_verify_none,
+ customize_hostname_check
+ ].
error_handling_tests()->
[client_with_cert_cipher_suites_handshake,
@@ -1145,6 +1147,58 @@ unknown_server_ca_accept_backwardscompatibility(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
+
+customize_hostname_check() ->
+ [{doc,"Test option customize_hostname_check."}].
+customize_hostname_check(Config) when is_list(Config) ->
+ Ext = [#'Extension'{extnID = ?'id-ce-subjectAltName',
+ extnValue = [{dNSName, "*.example.org"}],
+ critical = false}
+ ],
+ {ClientOpts0, ServerOpts0} = ssl_test_lib:make_rsa_cert_chains([{server_chain,
+ [[],
+ [],
+ [{extensions, Ext}]
+ ]}],
+ Config, "https_hostname_convention"),
+ ClientOpts = ssl_test_lib:ssl_options(ClientOpts0, Config),
+ ServerOpts = ssl_test_lib:ssl_options(ServerOpts0, 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, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ CustomFun = public_key:pkix_verify_hostname_match_fun(https),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options,
+ [{server_name_indication, "other.example.org"},
+ {customize_hostname_check,
+ [{match_fun, CustomFun}]} | ClientOpts]
+ }]),
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
+
+ Client1 = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}
+ ]),
+ ssl_test_lib:check_result(Client1, {error, {tls_alert, "handshake failure"}},
+ Server, {error, {tls_alert, "handshake failure"}}),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
diff --git a/lib/ssl/test/ssl_dist_bench_SUITE.erl b/lib/ssl/test/ssl_dist_bench_SUITE.erl
index f827ea12bb..3c7904cf24 100644
--- a/lib/ssl/test/ssl_dist_bench_SUITE.erl
+++ b/lib/ssl/test/ssl_dist_bench_SUITE.erl
@@ -117,19 +117,14 @@ init_per_suite(Config) ->
?MODULE_STRING ++ " ROOT CA", CertOptions),
SSLConf =
[{verify, verify_peer},
- {fail_if_no_peer_cert, true},
{versions, [TLSVersion]},
{ciphers, [TLSCipher]}],
ServerConf =
- [{verify_fun,
- {fun inet_tls_dist:verify_client/3,
- fun inet_tls_dist:cert_nodes/1}}
- | SSLConf],
- ClientConf =
- [{verify_fun,
- {fun inet_tls_dist:verify_server/3,
- fun inet_tls_dist:cert_nodes/1}}
+ [{fail_if_no_peer_cert, true},
+ {verify_fun,
+ {fun inet_tls_dist:verify_client/3,[]}}
| SSLConf],
+ ClientConf = SSLConf,
%%
write_node_conf(
NodeAConfFile, NodeA, ServerConf, ClientConf,
@@ -291,6 +286,8 @@ roundtrip(A, B, Prefix, HA, HB) ->
Rounds = 40000,
[] = ssl_apply(HA, erlang, nodes, []),
[] = ssl_apply(HB, erlang, nodes, []),
+ ok = ssl_apply(HA, net_kernel, allow, [[B]]),
+ ok = ssl_apply(HB, net_kernel, allow, [[A]]),
Time = ssl_apply(HA, fun () -> roundtrip_runner(A, B, Rounds) end),
[B] = ssl_apply(HA, erlang, nodes, []),
[A] = ssl_apply(HB, erlang, nodes, []),
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 8c27571d64..1e88ca15de 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -1264,8 +1264,16 @@ string_regex_filter(Str, Search) when is_list(Str) ->
string_regex_filter(_Str, _Search) ->
false.
-anonymous_suites(Version) ->
- ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:anonymous_suites(Version)],[]).
+ecdh_dh_anonymous_suites(Version) ->
+ ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:anonymous_suites(Version)],
+ [{key_exchange,
+ fun(dh_anon) ->
+ true;
+ (ecdh_anon) ->
+ true;
+ (_) ->
+ false
+ end}]).
psk_suites(Version) ->
ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:psk_suites(Version)], []).
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index a2e8ef8be0..4f02d8d15d 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -412,8 +412,16 @@ basic_erlang_server_openssl_client(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(Server),
Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname) ++
- ":" ++ integer_to_list(Port) ++ no_low_flag() | workaround_openssl_s_clinent()],
+ Args = case no_low_flag("-no_ssl2") of
+ [] ->
+ ["s_client", "-connect", hostname_format(Hostname) ++
+ ":" ++ integer_to_list(Port), no_low_flag("-no_ssl3")
+ | workaround_openssl_s_clinent()];
+ Flag ->
+ ["s_client", "-connect", hostname_format(Hostname) ++
+ ":" ++ integer_to_list(Port), no_low_flag("-no_ssl3"), Flag
+ | workaround_openssl_s_clinent()]
+ end,
OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
true = port_command(OpenSslPort, Data),
@@ -588,7 +596,7 @@ erlang_client_openssl_server_anon(Config) when is_list(Config) ->
ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
ClientOpts = ssl_test_lib:ssl_options(client_anon_opts, Config),
VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:anonymous_suites(VersionTuple),
+ Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple),
{ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
@@ -631,7 +639,7 @@ erlang_server_openssl_client_anon(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ssl_test_lib:ssl_options(server_anon_opts, Config),
VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:anonymous_suites(VersionTuple),
+ Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple),
{_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -665,7 +673,7 @@ erlang_server_openssl_client_anon_with_cert(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:anonymous_suites(VersionTuple),
+ Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple),
{_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -1995,10 +2003,12 @@ hostname_format(Hostname) ->
"localhost"
end.
-no_low_flag() ->
+no_low_flag("-no_ssl2" = Flag) ->
case ssl_test_lib:supports_ssl_tls_version(sslv2) of
true ->
- " -no_ssl2 -no_ssl3";
+ Flag;
false ->
- " -no_ssl3"
- end.
+ ""
+ end;
+no_low_flag(Flag) ->
+ Flag.