To see relevant version information for ssl, call
To see all supported cipher suites, call
This section shows a small example of how to set up client/server connections
using the Erlang shell. The returned value of the
The minimal setup is not the most secure setup of SSL/TLS/DTLS.
To set up client/server connections:
Step 1: Start the server side:
1 server> ssl:start().
ok
Step 2: Create an TLS listen socket: (To run DTLS add the option {protocol, dtls})
2 server> {ok, ListenSocket} =
ssl:listen(9999, [{certfile, "cert.pem"}, {keyfile, "key.pem"},{reuseaddr, true}]).
{ok,{sslsocket, [...]}}
Step 3: Do a transport accept on the TLS listen socket:
3 server> {ok, TLSTransportSocket} = ssl:transport_accept(ListenSocket).
{ok,{sslsocket, [...]}}
Step 4: Start the client side:
1 client> ssl:start().
ok
To run DTLS add the option {protocol, dtls} to third argument.
2 client> {ok, Socket} = ssl:connect("localhost", 9999, [], infinity).
{ok,{sslsocket, [...]}}
Step 5: Do the TLS handshake:
4 server> {ok, Socket} = ssl:handshake(TLSTransportSocket).
ok
Step 6: Send a message over TLS:
5 server> ssl:send(Socket, "foo").
ok
Step 7: Flush the shell message queue to see that the message was sent on the server side:
3 client> flush().
Shell got {ssl,{sslsocket,[...]},"foo"}
ok
To upgrade a TCP/IP connection to an SSL connection, the client and server must agree to do so. The agreement can be accomplished by using a protocol, for example, the one used by HTTP specified in RFC 2817.
To upgrade to an SSL connection:
Step 1: Start the server side:
1 server> ssl:start().
ok
Step 2: Create a normal TCP listen socket:
2 server> {ok, ListenSocket} = gen_tcp:listen(9999, [{reuseaddr, true}]).
{ok, #Port<0.475>}
Step 3: Accept client connection:
3 server> {ok, Socket} = gen_tcp:accept(ListenSocket).
{ok, #Port<0.476>}
Step 4: Start the client side:
1 client> ssl:start().
ok
2 client> {ok, Socket} = gen_tcp:connect("localhost", 9999, [], infinity).
Step 5: Ensure
4 server> inet:setopts(Socket, [{active, false}]).
ok
Step 6: Do the TLS handshake:
5 server> {ok, TLSSocket} = ssl:handshake(Socket, [{cacertfile, "cacerts.pem"},
{certfile, "cert.pem"}, {keyfile, "key.pem"}]).
{ok,{sslsocket,[...]}}
Step 7: Upgrade to an TLS connection. The client and server
must agree upon the upgrade. The server must call
3 client>{ok, TLSSocket} = ssl:connect(Socket, [{cacertfile, "cacerts.pem"},
{certfile, "cert.pem"}, {keyfile, "key.pem"}], infinity).
{ok,{sslsocket,[...]}}
Step 8: Send a message over TLS:
4 client> ssl:send(TLSSocket, "foo").
ok
Step 9: Set
4 server> ssl:setopts(TLSSocket, [{active, true}]).
ok
Step 10: Flush the shell message queue to see that the message was sent on the client side:
5 server> flush().
Shell got {ssl,{sslsocket,[...]},"foo"}
ok
Fetch default cipher suite list for an TLS/DTLS version. Change default to all to get all possible cipher suites.
1> Default = ssl:cipher_suites(default, 'tlsv1.2').
[#{cipher => aes_256_gcm,key_exchange => ecdhe_ecdsa,
mac => aead,prf => sha384}, ....]
In OTP 20 it is desirable to remove all cipher suites that uses rsa kexchange (removed from default in 21)
2> NoRSA =
ssl:filter_cipher_suites(Default,
[{key_exchange, fun(rsa) -> false;
(_) -> true end}]).
[...]
Pick just a few suites
3> Suites =
ssl:filter_cipher_suites(Default,
[{key_exchange, fun(ecdh_ecdsa) -> true;
(_) -> false end},
{cipher, fun(aes_128_cbc) ->true;
(_) ->false end}]).
[#{cipher => aes_128_cbc,key_exchange => ecdh_ecdsa,
mac => sha256,prf => sha256},
#{cipher => aes_128_cbc,key_exchange => ecdh_ecdsa,mac => sha,
prf => default_prf}]
Make some particular suites the most preferred, or least preferred by changing prepend to append.
4>ssl:prepend_cipher_suites(Suites, Default).
[#{cipher => aes_128_cbc,key_exchange => ecdh_ecdsa,
mac => sha256,prf => sha256},
#{cipher => aes_128_cbc,key_exchange => ecdh_ecdsa,mac => sha,
prf => default_prf},
#{cipher => aes_256_cbc,key_exchange => ecdhe_ecdsa,
mac => sha384,prf => sha384}, ...]
Erlang ssl application is able to use private keys provided by OpenSSL engines using the following mechanism:
1> ssl:start().
ok
Load a crypto engine, should be done once per engine used. For example
dynamically load the engine called
2> {ok, EngineRef} =
crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, "/tmp/user/engines/MyEngine"},<<"LOAD">>],[]).
{ok,#Ref<0.2399045421.3028942852.173962>}
Create a map with the engine information and the algorithm used by the engine:
3> PrivKey =
#{algorithm => rsa,
engine => EngineRef,
key_id => "id of the private key in Engine"}.
Use the map in the ssl key option:
4> {ok, SSLSocket} =
ssl:connect("localhost", 9999,
[{cacertfile, "cacerts.pem"},
{certfile, "cert.pem"},
{key, PrivKey}], infinity).
See also