/erltls

TLS/SSL/DTLS BoringSSL/OpenSSL-based NIF implementation of Erlang ssl module

Primary LanguageErlangMIT LicenseMIT

erltls

TLS/SSL/DTLS OpenSSL/BoringSSL-based NIF library for Erlang using the same interface as erlang ssl module.

This module contains interface functions for the SSL/TLS protocol. At this moment not all methods available in ssl module are implemented and also not all ssl_option are supported.

Implementation notes

The library is implemented in top of gen_tcp and OpenSSL API. Because SSL_* API is not thread safe in order to make sure that all calls for the same socket are not executed concurrently each socket has a gen_server to interact with native layer. This way we don't have to use any kind of locking at native level. Also read/write operations are not taking place in the gen_server process, they take place in calling process, in order to avoid gen_server to become a bottleneck for the socket.

Features not available in standard Erlang ssl

  • DTLS support (both v1 and v1.2)
  • RFC5077 for resuming sessions using ticketing
  • Can be used with both OpenSSL or BoringSSL

OpenSSL fork

The library is working with both OpenSSL or BoringSSL. Be default BoringSSL is used. To change the behavior you need to specify the USE_BORINGSSL environment variable:

USE_BORINGSSL=0 rebar compile

User guide

Add erltls as a rebar dependency to your project:

{deps, [
  {erltls, ".*", {git, "https://github.com/silviucpp/erltls.git", "master"}},
}.

Now you can use erltls module the same way you are using ssl:

%% server side

erltls:start(),
{ok, ListenSocket} = erltls:listen(9999, [
    {certfile, "test/server.pem"},
    {reuseaddr, true}
]),

{ok, Socket} = erltls:transport_accept(ListenSocket),
ok = erltls:ssl_accept(Socket),
ok = erltls:setopts(Socket, [{active, once}]),
receive AMessage -> io:format("recv:~p~n", [AMessage]) end,
ok = erltls:close(Socket),
ok = erltls:close(ListenSocket).
%% client side

erltls:start(),
{ok, Socket} = erltls:connect("localhost", 9999,  [], infinity),
ok = erltls:send(Socket, "foo"),
ok = erltls:close(Socket).

Using with Ranch

erltls can be easily used with ranch by starting a listener with ranch_erltls as the transport module:

{ok, _} = ranch:start_listener(tcp_echo, 100,
                               ranch_erltls, [{port, 5555}, {certfile, CertPath}],
                               echo_protocol, []).

Supported SSL options

Currently supported options also available in erlang ssl:

  • {verify, verify_type()}
  • {depth, integer()}
  • {fail_if_no_peer_cert, boolean()}
  • {certfile, path()}
  • {keyfile, path()}
  • {password, string()}
  • {cacertfile, path()}
  • {dhfile, path()}
  • {ciphers, ciphers()}

Options currently related to erltls only:

  • {use_session_ticket, boolean() | {boolean(), binary()}} - Enables session reuse using tickets as described in RFC5077. In case the key is not specified the tickets will be signed using a random key. In order to specify the key use the format {true, <<"key_here">>}.
  • {reuse_sessions_ttl, integer()} - The TTL of a session in seconds. In case the session is older than this TTL will not be possible to be reused. A full handshake will be negotiated.
  • {protocol, protocol()} - Specify the desired protocol. By default will negotiate highest available SSL/TLS version. Available protocols values are: sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2' | dtlsv1 | 'dtlsv1.2'

Unsupported SSL methods:

  • renegotiate/1
  • prf/5
  • negotiated_protocol/1
  • format_error/1
  • eccs/1
  • eccs/0
  • connection_information/2

SSL methods related to erltls

  • session_reused/1 - Query, whether a reused session was negotiated during the handshake (make sense if session ticketing is enabled)

Current limitations

  • working only with {packet, 0} inet option
  • Handshake process don't have a timeout implemented yet. So in connect/* or ssl_accept/* the timeout param is actually not counting the handshake process.

Benchmarks

For benchmarks between different drivers see here