From cb16d84c66b6040ca668b2e23ad4e740a3f3d0af Mon Sep 17 00:00:00 2001 From: Andrew Thompson Date: Mon, 21 Oct 2013 23:19:34 -0400 Subject: Implement 'honor_cipher_order' SSL server-side option HonorCipherOrder as implemented in Apache, nginx, lighttpd, etc. This instructs the server to prefer its own cipher ordering rather than the client's and can help protect against things like BEAST while maintaining compatability with clients which only support older ciphers. This code is mostly written by Andrew Thompson, only the test case was added by Andreas Schultz. --- lib/ssl/src/ssl.erl | 8 ++++++-- lib/ssl/src/ssl_handshake.erl | 10 ++++++++-- lib/ssl/src/ssl_internal.hrl | 5 ++++- 3 files changed, 18 insertions(+), 5 deletions(-) (limited to 'lib/ssl/src') diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index a7fd9f5f81..4646468cb6 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -640,7 +640,8 @@ handle_options(Opts0, _Role) -> make_next_protocol_selector( handle_option(client_preferred_next_protocols, Opts, undefined)), log_alert = handle_option(log_alert, Opts, true), - server_name_indication = handle_option(server_name_indication, Opts, undefined) + server_name_indication = handle_option(server_name_indication, Opts, undefined), + honor_cipher_order = handle_option(honor_cipher_order, Opts, false) }, CbInfo = proplists:get_value(cb_info, Opts, {gen_tcp, tcp, tcp_closed, tcp_error}), @@ -652,7 +653,8 @@ handle_options(Opts0, _Role) -> reuse_session, reuse_sessions, ssl_imp, cb_info, renegotiate_at, secure_renegotiate, hibernate_after, erl_dist, next_protocols_advertised, - client_preferred_next_protocols, log_alert, server_name_indication], + client_preferred_next_protocols, log_alert, + server_name_indication, honor_cipher_order], SockOpts = lists:foldl(fun(Key, PropList) -> proplists:delete(Key, PropList) @@ -840,6 +842,8 @@ validate_option(server_name_indication, disable) -> disable; validate_option(server_name_indication, undefined) -> undefined; +validate_option(honor_cipher_order, Value) when is_boolean(Value) -> + Value; validate_option(Opt, Value) -> throw({error, {options, {Opt, Value}}}). diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index f5c0034f1b..62de49a349 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -1029,14 +1029,15 @@ cipher_suites(Suites, true) -> select_session(SuggestedSessionId, CipherSuites, Compressions, Port, #session{ecc = ECCCurve} = Session, Version, - #ssl_options{ciphers = UserSuites} = SslOpts, Cache, CacheCb, Cert) -> + #ssl_options{ciphers = UserSuites, honor_cipher_order = HCO} = SslOpts, + Cache, CacheCb, Cert) -> {SessionId, Resumed} = ssl_session:server_id(Port, SuggestedSessionId, SslOpts, Cert, Cache, CacheCb), case Resumed of undefined -> Suites = available_suites(Cert, UserSuites, Version, ECCCurve), - CipherSuite = select_cipher_suite(CipherSuites, Suites), + CipherSuite = select_cipher_suite(CipherSuites, Suites, HCO), Compression = select_compression(Compressions), {new, Session#session{session_id = SessionId, cipher_suite = CipherSuite, @@ -1792,6 +1793,11 @@ handle_srp_extension(#srp{username = Username}, Session) -> %%-------------Misc -------------------------------- +select_cipher_suite(CipherSuites, Suites, false) -> + select_cipher_suite(CipherSuites, Suites); +select_cipher_suite(CipherSuites, Suites, true) -> + select_cipher_suite(Suites, CipherSuites). + select_cipher_suite([], _) -> no_suite; select_cipher_suite([Suite | ClientSuites], SupportedSuites) -> diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index 0186f9fca2..5a823ec8a4 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -114,7 +114,10 @@ next_protocols_advertised = undefined, %% [binary()], next_protocol_selector = undefined, %% fun([binary()]) -> binary()) log_alert :: boolean(), - server_name_indication = undefined + server_name_indication = undefined, + %% Should the server prefer its own cipher order over the one provided by + %% the client? + honor_cipher_order = false }). -record(config, {ssl, %% SSL parameters -- cgit v1.2.3