From 78a9a09af9216a2dea454f561e0774e67a15c361 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Wed, 29 Nov 2017 08:39:48 +0100 Subject: Stop checking DNS name for SNI --- lib/ssl/src/ssl.erl | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'lib/ssl') diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 4007e44a83..4bff9fdf39 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -992,17 +992,21 @@ validate_option(next_protocols_advertised, Value) when is_list(Value) -> Value; validate_option(next_protocols_advertised, undefined) -> undefined; -validate_option(server_name_indication = Opt, Value) when is_list(Value) -> +validate_option(server_name_indication, Value) when is_list(Value) -> %% RFC 6066, Section 3: Currently, the only server names supported are %% DNS hostnames - case inet_parse:domain(Value) of - false -> - throw({error, {options, {{Opt, Value}}}}); - true -> - Value - end; -validate_option(server_name_indication, undefined = Value) -> + %% case inet_parse:domain(Value) of + %% false -> + %% throw({error, {options, {{Opt, Value}}}}); + %% true -> + %% Value + %% end; + %% + %% But the definition seems very diffuse, so let all strings through + %% and leave it up to public_key to decide... Value; +validate_option(server_name_indication, undefined) -> + undefined; validate_option(server_name_indication, disable) -> disable; -- cgit v1.2.3 From 457409e8a460fa115565a5450e7f4eb4a558f32c Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Wed, 29 Nov 2017 09:58:22 +0100 Subject: Read in -ssl_dist_optfile to ETS --- lib/ssl/doc/src/ssl_distribution.xml | 128 +++++++++++++++++++++++++++++------ lib/ssl/src/ssl_dist_sup.erl | 67 +++++++++++++++++- 2 files changed, 171 insertions(+), 24 deletions(-) (limited to 'lib/ssl') diff --git a/lib/ssl/doc/src/ssl_distribution.xml b/lib/ssl/doc/src/ssl_distribution.xml index 61f88e3860..7f8a08f704 100644 --- a/lib/ssl/doc/src/ssl_distribution.xml +++ b/lib/ssl/doc/src/ssl_distribution.xml @@ -4,7 +4,7 @@
- 20002016 + 20002017 Ericsson AB. All Rights Reserved. @@ -180,10 +180,96 @@ Eshell V5.0 (abort with ^G)
Specifying SSL Options -

For SSL to work, at least - a public key and a certificate must be specified for the server - side. In the following example, the PEM-files consist of two - entries, the server certificate and its private key.

+ +

+ The SSL distribution options can be written into a file + that is consulted when the node is started. This file name + is then specified with the command line argument + -ssl_dist_optfile. +

+

+ Any available SSL option can be specified in an options file, + but note that options that take a fun() has to use + the syntax fun Mod:Func/Arity since a function + body can not be compiled when consulting a file. +

+

+ Do not tamper with the socket options + list, binary, active, packet, + nodelay and deliver since they are used + by the distribution protocol handler itself. + Other raw socket options such as packet_size may + interfere severely, so beware! +

+

+ For SSL to work, at least a public key and a certificate + must be specified for the server side. + In the following example, the PEM file + "/home/me/ssl/erlserver.pem" contains both + the server certificate and its private key. +

+

+ Create a file named for example + "/home/me/ssl/ssl_test@myhost.conf": +

+ + +

+ And then start the node like this + (line breaks in the command are for readability, + and shall not be there when typed): +

+ + +

+ The options in the {server, Opts} tuple are used + when calling ssl:ssl_accept/3, and the options in the + {client, Opts} tuple are used when calling + ssl:connect/4. +

+

+ For the client, the option + {server_name_indication, atom_to_list(TargetNode)} + is added when connecting. + This makes it possible to use the client option + {verify, verify_peer}, + and the client will verify that the certificate matches + the node name you are connecting to. + This only works if the the server certificate is issued + to the name atom_to_list(TargetNode). +

+

+ For the server it is also possible to use the option + {verify, verify_peer} and the server will only accept + client connections with certificates that are trusted by + a root certificate that the server knows. + A client that presents an untrusted certificate will be rejected. + This option is preferably combined with + {fail_if_no_peer_cert, true} or a client will + still be accepted if it does not present any certificate. +

+

+ A node started in this way is fully functional, using SSL + as the distribution protocol. +

+
+ +
+ Specifying SSL Options (Legacy) + +

+ As in the previous section the PEM file + "/home/me/ssl/erlserver.pem" contains both + the server certificate and its private key. +

On the erl command line you can specify options that the SSL distribution adds when creating a socket.

@@ -226,24 +312,26 @@ Eshell V5.0 (abort with ^G) SSL options and their values. Argument -ssl_dist_opt can be repeated any number of times.

-

An example command line can now look as follows +

+ An example command line doing the same as the example + in the previous section can now look as follows (line breaks in the command are for readability, - and are not be there when typed):

- + and shall not be there when typed): +

+ -

A node started in this way is fully functional, using SSL - as the distribution protocol.

+(ssl_test@myhost)1>]]> +
- Setting up Environment to Always Use SSL + Setting up Environment to Always Use SSL (Legacy)

A convenient way to specify arguments to Erlang is to use environment variable ERL_FLAGS. All the flags needed to use the SSL distribution can be specified in that variable and are @@ -285,15 +373,11 @@ Eshell V5.0 (abort with ^G) variable.

An example command line with this option would look like this:

- + + -ssl_dist_optfile "/home/me/ssl/ssl_test@myhost.conf" + -sname ssl_test]]> +

A node started in this way will only be able to communicate with other nodes using SSL distribution over IPv6.

diff --git a/lib/ssl/src/ssl_dist_sup.erl b/lib/ssl/src/ssl_dist_sup.erl index 690b896919..e92f3d3979 100644 --- a/lib/ssl/src/ssl_dist_sup.erl +++ b/lib/ssl/src/ssl_dist_sup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2016. All Rights Reserved. +%% Copyright Ericsson AB 2011-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -30,6 +30,9 @@ %% Supervisor callback -export([init/1]). +%% Debug +-export([consult/1]). + %%%========================================================================= %%% API %%%========================================================================= @@ -37,7 +40,18 @@ -spec start_link() -> {ok, pid()} | ignore | {error, term()}. start_link() -> - supervisor:start_link({local, ?MODULE}, ?MODULE, []). + case init:get_argument(ssl_dist_optfile) of + {ok, [File]} -> + DistOpts = consult(File), + TabOpts = [set, protected, named_table], + Tab = ets:new(ssl_dist_opts, TabOpts), + true = ets:insert(Tab, DistOpts), + supervisor:start_link({local, ?MODULE}, ?MODULE, []); + {ok, BadArg} -> + error({bad_ssl_dist_optfile, BadArg}); + error -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []) + end. %%%========================================================================= %%% Supervisor callback @@ -78,3 +92,52 @@ proxy_server_child_spec() -> Modules = [ssl_tls_dist_proxy], Type = worker, {Name, StartFunc, Restart, Shutdown, Type, Modules}. + +consult(File) -> + case erl_prim_loader:get_file(File) of + {ok, Binary, _FullName} -> + Encoding = + case epp:read_encoding_from_binary(Binary) of + none -> latin1; + Enc -> Enc + end, + case unicode:characters_to_list(Binary, Encoding) of + {error, _String, Rest} -> + error( + {bad_ssl_dist_optfile, {encoding_error, Rest}}); + {incomplete, _String, Rest} -> + error( + {bad_ssl_dist_optfile, {encoding_incomplete, Rest}}); + String when is_list(String) -> + consult_string(String) + end; + error -> + error({bad_ssl_dist_optfile, File}) + end. + +consult_string(String) -> + case erl_scan:string(String) of + {error, Info, Location} -> + error({bad_ssl_dist_optfile, {scan_error, Info, Location}}); + {ok, Tokens, _EndLocation} -> + consult_tokens(Tokens) + end. + +consult_tokens(Tokens) -> + case erl_parse:parse_exprs(Tokens) of + {error, Info} -> + error({bad_ssl_dist_optfile, {parse_error, Info}}); + {ok, [Expr]} -> + consult_expr(Expr); + {ok, Other} -> + error({bad_ssl_dist_optfile, {parse_error, Other}}) + end. + +consult_expr(Expr) -> + {value, Value, Bs} = erl_eval:expr(Expr, erl_eval:new_bindings()), + case erl_eval:bindings(Bs) of + [] -> + Value; + Other -> + error({bad_ssl_dist_optfile, {bindings, Other}}) + end. -- cgit v1.2.3 From 34150ddee82a36d768ccebf46299d044ace9161d Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Wed, 29 Nov 2017 10:31:34 +0100 Subject: Use -ssl_dist_optfile options --- lib/ssl/src/ssl_tls_dist_proxy.erl | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'lib/ssl') diff --git a/lib/ssl/src/ssl_tls_dist_proxy.erl b/lib/ssl/src/ssl_tls_dist_proxy.erl index 08947f24dd..c392450e03 100644 --- a/lib/ssl/src/ssl_tls_dist_proxy.erl +++ b/lib/ssl/src/ssl_tls_dist_proxy.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2016. All Rights Reserved. +%% Copyright Ericsson AB 2011-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -369,6 +369,17 @@ loop_conn(World, Erts) -> end. get_ssl_options(Type) -> + try ets:lookup(ssl_dist_opts, Type) of + [{Type, Opts}] -> + [{erl_dist, true} | Opts]; + _ -> + get_ssl_dist_arguments(Type) + catch + error:badarg -> + get_ssl_dist_arguments(Type) + end. + +get_ssl_dist_arguments(Type) -> case init:get_argument(ssl_dist_opt) of {ok, Args} -> [{erl_dist, true} | ssl_options(Type, lists:append(Args))]; -- cgit v1.2.3 From 964d2987e754d77327d7d11918c04c028be35a5d Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Wed, 29 Nov 2017 10:52:28 +0100 Subject: Use SNI when connecting --- lib/ssl/src/inet_tls_dist.erl | 8 ++++++-- lib/ssl/src/ssl_tls_dist_proxy.erl | 17 ++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) (limited to 'lib/ssl') diff --git a/lib/ssl/src/inet_tls_dist.erl b/lib/ssl/src/inet_tls_dist.erl index 78094c474b..4c677b9c33 100644 --- a/lib/ssl/src/inet_tls_dist.erl +++ b/lib/ssl/src/inet_tls_dist.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2016. All Rights Reserved. +%% Copyright Ericsson AB 2011-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -93,7 +93,11 @@ do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) -> ?trace("port_please(~p) -> version ~p~n", [Node,Version]), dist_util:reset_timer(Timer), - case ssl_tls_dist_proxy:connect(Driver, Address, TcpPort) of + case + ssl_tls_dist_proxy:connect( + Driver, Address, TcpPort, + [{server_name_indication, atom_to_list(Node)}]) + of {ok, Socket} -> HSData = connect_hs_data(Kernel, Node, MyNode, Socket, Timer, Version, Ip, TcpPort, Address, diff --git a/lib/ssl/src/ssl_tls_dist_proxy.erl b/lib/ssl/src/ssl_tls_dist_proxy.erl index c392450e03..12a057fd22 100644 --- a/lib/ssl/src/ssl_tls_dist_proxy.erl +++ b/lib/ssl/src/ssl_tls_dist_proxy.erl @@ -20,7 +20,7 @@ -module(ssl_tls_dist_proxy). --export([listen/2, accept/2, connect/3, get_tcp_address/1]). +-export([listen/2, accept/2, connect/4, get_tcp_address/1]). -export([init/1, start_link/0, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3, ssl_options/2]). @@ -45,8 +45,9 @@ listen(Driver, Name) -> accept(Driver, Listen) -> gen_server:call(?MODULE, {accept, Driver, Listen}, infinity). -connect(Driver, Ip, Port) -> - gen_server:call(?MODULE, {connect, Driver, Ip, Port}, infinity). +connect(Driver, Ip, Port, ExtraOpts) -> + gen_server:call( + ?MODULE, {connect, Driver, Ip, Port, ExtraOpts}, infinity). do_listen(Options) -> @@ -134,9 +135,11 @@ handle_call({accept, _Driver, Listen}, {From, _}, State = #state{listen={_, Worl WorldPid = spawn_link(fun() -> accept_loop(Self, world, World, Listen) end), {reply, ErtsPid, State#state{accept_loop={ErtsPid, WorldPid}}}; -handle_call({connect, Driver, Ip, Port}, {From, _}, State) -> +handle_call({connect, Driver, Ip, Port, ExtraOpts}, {From, _}, State) -> Me = self(), - Pid = spawn_link(fun() -> setup_proxy(Driver, Ip, Port, Me) end), + Pid = + spawn_link( + fun() -> setup_proxy(Driver, Ip, Port, ExtraOpts, Me) end), receive {Pid, go_ahead, LPort} -> Res = {ok, Socket} = try_connect(LPort), @@ -270,9 +273,9 @@ try_connect(Port) -> try_connect(Port) end. -setup_proxy(Driver, Ip, Port, Parent) -> +setup_proxy(Driver, Ip, Port, ExtraOpts, Parent) -> process_flag(trap_exit, true), - Opts = connect_options(get_ssl_options(client)), + Opts = connect_options(ExtraOpts ++ get_ssl_options(client)), case ssl:connect(Ip, Port, [{active, true}, binary, {packet,?PPRE}, nodelay(), Driver:family()] ++ Opts) of {ok, World} -> -- cgit v1.2.3