README.MD

# erltls

[![Build Status](https://travis-ci.org/silviucpp/erltls.svg?branch=master)](https://travis-ci.org/silviucpp/erltls)
![GitHub](https://img.shields.io/github/license/silviucpp/erltls)
![Hex.pm](https://img.shields.io/hexpm/v/erltls)
![Maintenance](https://img.shields.io/maintenance/yes/2019)

*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`][1] 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][4] or [BoringSSL][3]

### OpenSSL fork

The library is working with both [OpenSSL][4] or [BoringSSL][3]. 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/rebar3 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`:

```erlang
%% 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).
```

```erlang
%% 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:
    
```erlang    
{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][2]. 
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][5]   

[1]:http://erlang.org/doc/man/ssl.html
[2]:https://www.ietf.org/rfc/rfc5077.txt
[3]:https://boringssl.googlesource.com/boringssl/
[4]:https://www.openssl.org/
[5]:https://github.com/silviucpp/tls_bench