0

I using Erlang Mochiweb as Http server with SSL. Mochiweb use pure Erlang SSL library.

How to configure erlang ssl to support Forward Secrecy? For more info about SSL Forward Secrecy: https://en.wikipedia.org/wiki/Forward_secrecy

dryymoon
  • 131
  • 1
  • 4
  • I am not sure if I can answer your question, but could you consider having HAproxy or nginx as a reverse proxy for your TLS sessions? – Evan P Oct 29 '14 at 15:42
  • I think about your suggestion, nginx or other is very good in common. But I want to develop pure "box" software, which can work anywhere, where can work ERLANG runtime, on unix and windows, without third-party programs, and for SSL - without proxying. – dryymoon Oct 29 '14 at 19:51
  • And with proxying i think, than i can`t authentificate users with personal SSL certificates (to improve security). – dryymoon Oct 29 '14 at 19:53
  • regarding the 2nd question maybe this is a help http://nategood.com/client-side-certificate-authentication-in-ngi regarding the 1st, have you consider Virtualization or Docker? – Evan P Oct 29 '14 at 23:08

1 Answers1

2

I'm using Erlang/OTP 17 with openssl 1.0.2a (erlang needs openssl for ciphers but not handshake or protocol, so theoretically it should supports all openssl-supported ciphers) , so its SSL module does support perfect forward secrecy by default. But it also supports some insecure protocol or ciphers like sslv3 or des, or weak ciphers like rc4 by default. SSLlabs ssltest will give you rank C for default options. You might want to disable the insecure protocol and ciphers.

And, the erlang ssl module does honor client's ciphersuite preference by default. Which will make some IEs using RSA key exchange because those versions prefers RSA key-exchange rather than ECDHE (see: https://www.ssllabs.com/ssltest/viewClient.html?name=IE&version=8-10&platform=Win%207). You will need {honor_cipher_order, true} to use server's preference. And you'll need to manually adjust the preference order of cipher-suites to fit what you need. The default order is not ranking completely by PFS.

If your have control on the client (like your own apps rather than browsers), and you really want PFS only, you can disable rsa key exchange.

A sample escript and options for erlang is: I didn't reorder the ciphersuite orders.

For mochiweb, you can add these options to your ssl_opts.

#!/usr/bin/env escript

% these ciphers will got A- on ssllabs's ssltest.
% Because as mentioned above, some version's IE prefers non-PFS key exchange.
% And got A if {honor_cipher_order, true} is set.
% No manual adjusting needed to get A, because the first ciphersuite is PFS-enabled and supported by IEs.
% So you need to adjust orders to fit whatever you needed.
secure_ciphers() -> secure_ciphers(ssl:cipher_suites()). 


% It includes insecure and weak ciphers, so it should get low rank on ssltest
pfs_ciphers() -> pfs_ciphers(ssl:cipher_suites()). 

% Rank A on ssllabs' ssltest, all modern client is using perfect forward secrecy key-exchange   
% but some client without PFS support will fail to handshake.
pfs_secure_ciphers() ->  
        sets:to_list(sets:intersection(sets:from_list(secure_ciphers()), sets:from_list(pfs_ciphers()))). 

secure_ciphers([]) -> [];
secure_ciphers([{_, rc4_128, _} | T]) -> secure_ciphers(T);
secure_ciphers([{_, des_cbc, _} | T]) -> secure_ciphers(T);
secure_ciphers([{dhe_rsa, _, _} | T]) -> secure_ciphers(T);
secure_ciphers([{_, _, md5} | T]) -> secure_ciphers(T);
secure_ciphers([H | T]) -> [H | secure_ciphers(T)].


pfs_ciphers([]) -> [];
pfs_ciphers([{dhe_dss, _, _} = H | T]) -> [H | pfs_ciphers(T)];
pfs_ciphers([{dhe_rsa, _, _} = H | T]) -> [H | pfs_ciphers(T)];
pfs_ciphers([{ecdhe_ecdsa, _, _} = H | T]) -> [H | pfs_ciphers(T)];
pfs_ciphers([{ecdhe_rsa, _, _} = H | T]) -> [H | pfs_ciphers(T)];
pfs_ciphers([_ | T]) -> pfs_ciphers(T).

accept(S) ->
        {ok, Q} = ssl:transport_accept(S),
        spawn(fun() -> accept(S) end),
        ssl:ssl_accept(Q),
        receive
                Msg ->
                        io:format("~p~n", [Msg]),
                        ssl:send(Q, <<"HTTP/1.0 200 OK\r\n\r\nHello World\r\n">>),
                        ssl:close(Q)
        end.

main(_) ->
        ssl:start(),
        {ok, P} = ssl:listen(443, [{certfile, "./aa.crt"}, {keyfile, "./aa.key"}, {ciphers, pfs_secure_ciphers()}, {versions, [tlsv1, 'tlsv1.1', 'tlsv1.2']}, {dhfile, "./dh4096.pem"}]),
        accept(P),
        receive
                stop ->
                        ok
        end.