[erlang-questions] SSL hostname verification

Raimo Niskanen raimo+erlang-questions@REDACTED
Thu Jan 25 10:40:30 CET 2018


On Tue, Jan 23, 2018 at 06:04:53PM +0100, San Gillis wrote:
> > So you need to have a module implementing the function that you want to
> > use as a fun.
> >
> 
> I tried this, and I start my remote shell using
> `erl -remsh nodename@REDACTED -pa ./ebin -setcookie cookie -name node@REDACTED
> -ssl_dist_optfile ./sslopts.conf -proto_dist inet_tls`
> where ./ebin contains the module beam.
> 
> In this case the shell process just terminates without giving me any error
> messages.
> 
> 
> This is a limitation for  distribution over TLS as unamed funs can not be
> > handled in files.
> >
> 
> When I put some `io:format` statements in my unnamed function they did get
> printed to console, so it seems this does work?
> 
> Regards,
> San

Well, I'll be darned, but that acually seems to work!

The file parsing results in an erl_eval internal fun with the parsed
abstract form in its environment, so when that fun is called it is
interpreted by erl_eval.  Interpretation is _much_ slower then execution,
but I do not know when that would be a real problem...

Here is an example that works, I ripped out pieces from after running
the test suite ssl_dist_bench_SUITE:setup/1:

To start one node:
    erl -run application start crypto -run application start public_key
        -eval 'net_kernel:verbose(1)'
        -sname ssl_dist_bench_SUITE_node_a
        -proto_dist inet_tls
        -ssl_dist_optfile ~/tmp/ssl_dist_bench_SUITE_node_a@REDACTED

To start the other node:
    erl -run application start crypto -run application start public_key
        -eval 'net_kernel:verbose(1)'
        -sname ssl_dist_bench_SUITE_node_b
        -proto_dist inet_tls
        -ssl_dist_optfile ~/tmp/ssl_dist_bench_SUITE_node_b@REDACTED

My host's short name is elxd1243rl3.
The "-eval 'net_kernel:verbose(1)' increases verbosity for testing.
The applications 'crypto' and 'public_key' has to be started, either from
the command line like this, or from a dedicated boot script.  See:

    http://erlang.org/doc/apps/ssl/ssl_distribution.html Section 4.1


The test framework generates the .conf files containing certificates for
the short node names so these nodes actually pass hostname verification.
In these .conf files I have added an inline verify_fun in the client
section.

Excerpt from ~/tmp/ssl_dist_bench_SUITE_node_b@REDACTED:

[{server,
  [{fail_if_no_peer_cert,true},
   {verify,verify_peer},
   {versions,['tlsv1.2']},
   {ciphers,[{ecdhe_ecdsa,aes_128_cbc,sha256,sha256}]},
   {cert,<<48,130,2,237,48,130,2,72,160,3,2,1,2,2,1,4,48,16,6,7,42,134,
           ...,235,67,74,159,21,16,15>>},
   {key,{'ECPrivateKey',<<48,129,220,2,1,1,4,66,1,177,250,81,233,146,
                          ...,60,213,172>>}},
   {cacerts,[<<48,130,2,213,48,130,2,48,160,3,2,1,2,2,1,2,48,16,6,7,42,
               ...,141,240,231,115,166,243>>,
             <<48,130,2,213,48,130,2,48,160,3,2,1,2,2,1,2,48,16,6,7,
               ...,237,32,9,141,240,231,115,166,243>>]}]},

 {client,
  [{verify,verify_peer},
   {verify_fun,
    {fun (_, Event, UserState) ->
         io:format("~p.~n", [Event]),
         case Event of
             {bad_cert, hostname_check_failed} ->
                  %%% Preform own check ...
                 {valid, UserState};
             {extension, _} ->
                 {unknown, UserState};
             valid ->
                 {valid, UserState};
             valid_peer ->
                 {valid, UserState}
         end
     end, []}},
   {versions,['tlsv1.2']},
   {ciphers,[{ecdhe_ecdsa,aes_128_cbc,sha256,sha256}]},
   {cert,<<48,130,2,237,48,130,2,72,160,3,2,1,2,2,1,4,48,16,6,7,42,134,
           ...,235,67,74,159,21,16,15>>},
   {key,{'ECPrivateKey',<<48,129,220,2,1,1,4,66,1,177,250,81,233,146,
                          ...,60,213,172>>}},
   {cacerts,[<<48,130,2,213,48,130,2,48,160,3,2,1,2,2,1,2,48,16,6,7,42,
               ...,141,240,231,115,166,243>>,
             <<48,130,2,213,48,130,2,48,160,3,2,1,2,2,1,2,48,16,6,
               ...,206,74,237,32,9,141,240,231,115,166,243>>]}
  ]
 }].


This is node a that gets connected to, I am sorry I connected from node b
to node a, that is not according to telco tradition :-(

erl -run application start crypto -run application start public_key
    -eval 'net_kernel:verbose(1)' -sname ssl_dist_bench_SUITE_node_a
    -proto_dist inet_tls
    -ssl_dist_optfile ~/tmp/ssl_dist_bench_SUITE_node_a@REDACTED 
Erlang/OTP 21 [DEVELOPMENT] [erts-9.2] [source-8e66754] [64-bit] [smp:8:8]
    [ds:8:8:10] [async-threads:10] [hipe]

Eshell V9.2  (abort with ^G)
(ssl_dist_bench_SUITE_node_a@REDACTED)1> 

=ERROR REPORT==== 25-Jan-2018::09:53:37 ===
Net kernel got ping


And this is node b that connects:

erl -run application start crypto -run application start public_key
    -eval 'net_kernel:verbose(1)' -sname ssl_dist_bench_SUITE_node_b
    -proto_dist inet_tls
    -ssl_dist_optfile ~/tmp/ssl_dist_bench_SUITE_node_b@REDACTED
Erlang/OTP 21 [DEVELOPMENT] [erts-9.2] [source-8e66754] [64-bit] [smp:8:8]
    [ds:8:8:10] [async-threads:10] [hipe]

Eshell V9.2  (abort with ^G)
(ssl_dist_bench_SUITE_node_b@REDACTED)1>
    {net_kernel,ssl_dist_bench_SUITE_node_a@REDACTED} ! ping.
ping

=INFO REPORT==== 25-Jan-2018::09:53:37 ===
{net_kernel,{auto_connect,ssl_dist_bench_SUITE_node_a@REDACTED,1,
                          #Ref<0.1220262086.1603141640.225564>}}
{extension,
 {'Extension',{2,5,29,17},false,
  [{dNSName,"ssl_dist_bench_SUITE_node_a@REDACTED"}]}}.

valid_peer.

(ssl_dist_bench_SUITE_node_b@REDACTED)2>


So we got two printouts from the verify_fun on node b, one for the
subject altnames extension, and one from the succesful validation.

I hope this information was useful.
-- 

/ Raimo Niskanen, Erlang/OTP, Ericsson AB



More information about the erlang-questions mailing list