aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl')
-rw-r--r--lib/ssl/doc/src/notes.xml36
-rw-r--r--lib/ssl/doc/src/ssl.xml4
-rw-r--r--lib/ssl/src/ssl.appup.src12
-rw-r--r--lib/ssl/src/ssl.erl75
-rw-r--r--lib/ssl/src/ssl_connection.erl2
-rw-r--r--lib/ssl/src/ssl_connection.hrl2
-rw-r--r--lib/ssl/src/ssl_handshake.erl52
-rw-r--r--lib/ssl/src/ssl_internal.hrl6
-rw-r--r--lib/ssl/src/tls_connection.erl8
-rw-r--r--lib/ssl/src/tls_handshake.erl26
-rw-r--r--lib/ssl/src/tls_v1.erl28
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl128
-rw-r--r--lib/ssl/test/ssl_dist_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_test_lib.erl20
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl48
-rw-r--r--lib/ssl/vsn.mk2
16 files changed, 353 insertions, 98 deletions
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index fb32ccec7b..0b28b1ebd4 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -25,7 +25,41 @@
<file>notes.xml</file>
</header>
<p>This document describes the changes made to the SSL application.</p>
- <section><title>SSL 5.3.2</title>
+ <section><title>SSL 5.3.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Add missing validation of the server_name_indication
+ option and test for its explicit use. It was not possible
+ to set or disable the default server_name_indication as
+ the validation of the option was missing.</p>
+ <p>
+ Own Id: OTP-11567</p>
+ </item>
+ <item>
+ <p>
+ Elliptic curve selection in server mode now properly
+ selects a curve suggested by the client, if possible, and
+ the fallback alternative is changed to a more widely
+ supported curve.</p>
+ <p>
+ Own Id: OTP-11575</p>
+ </item>
+ <item>
+ <p>
+ Bug in the TLS hello extension handling caused the server
+ to behave as it did not understand secure renegotiation.</p>
+ <p>
+ Own Id: OTP-11595</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 5.3.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 80ef419fb7..910dca3889 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -460,6 +460,10 @@ fun(srp, Username :: string(), UserState :: term()) ->
</item>
<tag>{log_alert, boolean()}</tag>
<item>If false, error reports will not be displayed.</item>
+ <tag>{honor_cipher_order, boolean()}</tag>
+ <item>If true, use the server's preference for cipher selection. If false
+ (the default), use the client's preference.
+ </item>
</taglist>
</section>
diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src
index c090b6ebfb..3a64841976 100644
--- a/lib/ssl/src/ssl.appup.src
+++ b/lib/ssl/src/ssl.appup.src
@@ -1,7 +1,11 @@
%% -*- erlang -*-
{"%VSN%",
[
- {<<"5.3\\*">>, [{restart_application, ssl}]},
+ {<<"5.3.2">>, [{load_module, ssl, soft_purge, soft_purge, []},
+ {load_module, ssl_connection, soft_purge, soft_purge, []},
+ {load_module, ssl_handshake, soft_purge, soft_purge, []},
+ {load_module, tls_connection, soft_purge, soft_purge, []}]},
+ {<<"5.3.1">>, [{restart_application, ssl}]},
{<<"5.2\\*">>, [{restart_application, ssl}]},
{<<"5.1\\*">>, [{restart_application, ssl}]},
{<<"5.0\\*">>, [{restart_application, ssl}]},
@@ -9,7 +13,11 @@
{<<"3\\.*">>, [{restart_application, ssl}]}
],
[
- {<<"5.3\\*">>, [{restart_application, ssl}]},
+ {<<"5.3.2">>, [{load_module, ssl, soft_purge, soft_purge, []},
+ {load_module, ssl_connection, soft_purge, soft_purge, []},
+ {load_module, ssl_handshake, soft_purge, soft_purge, []},
+ {load_module, tls_connection, soft_purge, soft_purge, []}]},
+ {<<"5.3.1">>, [{restart_application, ssl}]},
{<<"5.2\\*">>, [{restart_application, ssl}]},
{<<"5.1\\*">>, [{restart_application, ssl}]},
{<<"5.0\\*">>, [{restart_application, ssl}]},
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index cff842cb2f..4646468cb6 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -608,39 +608,41 @@ handle_options(Opts0, _Role) ->
end,
SSLOptions = #ssl_options{
- versions = Versions,
- verify = validate_option(verify, Verify),
- verify_fun = VerifyFun,
- fail_if_no_peer_cert = FailIfNoPeerCert,
- verify_client_once = handle_option(verify_client_once, Opts, false),
- depth = handle_option(depth, Opts, 1),
- cert = handle_option(cert, Opts, undefined),
- certfile = CertFile,
- key = handle_option(key, Opts, undefined),
- keyfile = handle_option(keyfile, Opts, CertFile),
- password = handle_option(password, Opts, ""),
- cacerts = CaCerts,
- cacertfile = handle_option(cacertfile, Opts, CaCertDefault),
- dh = handle_option(dh, Opts, undefined),
- dhfile = handle_option(dhfile, Opts, undefined),
- user_lookup_fun = handle_option(user_lookup_fun, Opts, undefined),
- psk_identity = handle_option(psk_identity, Opts, undefined),
- srp_identity = handle_option(srp_identity, Opts, undefined),
- ciphers = handle_option(ciphers, Opts, []),
- %% Server side option
- reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun),
- reuse_sessions = handle_option(reuse_sessions, Opts, true),
- secure_renegotiate = handle_option(secure_renegotiate, Opts, false),
- renegotiate_at = handle_option(renegotiate_at, Opts, ?DEFAULT_RENEGOTIATE_AT),
- hibernate_after = handle_option(hibernate_after, Opts, undefined),
- erl_dist = handle_option(erl_dist, Opts, false),
- next_protocols_advertised =
+ versions = Versions,
+ verify = validate_option(verify, Verify),
+ verify_fun = VerifyFun,
+ fail_if_no_peer_cert = FailIfNoPeerCert,
+ verify_client_once = handle_option(verify_client_once, Opts, false),
+ depth = handle_option(depth, Opts, 1),
+ cert = handle_option(cert, Opts, undefined),
+ certfile = CertFile,
+ key = handle_option(key, Opts, undefined),
+ keyfile = handle_option(keyfile, Opts, CertFile),
+ password = handle_option(password, Opts, ""),
+ cacerts = CaCerts,
+ cacertfile = handle_option(cacertfile, Opts, CaCertDefault),
+ dh = handle_option(dh, Opts, undefined),
+ dhfile = handle_option(dhfile, Opts, undefined),
+ user_lookup_fun = handle_option(user_lookup_fun, Opts, undefined),
+ psk_identity = handle_option(psk_identity, Opts, undefined),
+ srp_identity = handle_option(srp_identity, Opts, undefined),
+ ciphers = handle_option(ciphers, Opts, []),
+ %% Server side option
+ reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun),
+ reuse_sessions = handle_option(reuse_sessions, Opts, true),
+ secure_renegotiate = handle_option(secure_renegotiate, Opts, false),
+ renegotiate_at = handle_option(renegotiate_at, Opts, ?DEFAULT_RENEGOTIATE_AT),
+ hibernate_after = handle_option(hibernate_after, Opts, undefined),
+ erl_dist = handle_option(erl_dist, Opts, false),
+ next_protocols_advertised =
handle_option(next_protocols_advertised, Opts, undefined),
- next_protocol_selector =
+ next_protocol_selector =
make_next_protocol_selector(
handle_option(client_preferred_next_protocols, Opts, undefined)),
- log_alert = handle_option(log_alert, Opts, true)
- },
+ log_alert = handle_option(log_alert, Opts, true),
+ 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}),
SslOptions = [protocol, versions, verify, verify_fun,
@@ -651,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],
+ client_preferred_next_protocols, log_alert,
+ server_name_indication, honor_cipher_order],
SockOpts = lists:foldl(fun(Key, PropList) ->
proplists:delete(Key, PropList)
@@ -833,6 +836,14 @@ validate_option(next_protocols_advertised = Opt, Value) when is_list(Value) ->
validate_option(next_protocols_advertised, undefined) ->
undefined;
+validate_option(server_name_indication, Value) when is_list(Value) ->
+ Value;
+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_connection.erl b/lib/ssl/src/ssl_connection.erl
index b7c1b9e8d0..82106935cb 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -1597,7 +1597,7 @@ default_hashsign(_Version, KeyExchange)
select_curve(#state{client_ecc = {[Curve|_], _}}) ->
{namedCurve, Curve};
select_curve(_) ->
- {namedCurve, ?secp256k1}.
+ {namedCurve, ?secp256r1}.
is_anonymous(Algo) when Algo == dh_anon;
Algo == ecdh_anon;
diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl
index 27489ca325..adb2e1debe 100644
--- a/lib/ssl/src/ssl_connection.hrl
+++ b/lib/ssl/src/ssl_connection.hrl
@@ -41,7 +41,7 @@
data_tag :: atom(), % ex tcp.
close_tag :: atom(), % ex tcp_closed
error_tag :: atom(), % ex tcp_error
- host :: string() | inet:ipaddress(),
+ host :: string() | inet:ip_address(),
port :: integer(),
socket :: port(),
ssl_options :: #ssl_options{},
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index da72ffc043..7b4cf8eb06 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -56,7 +56,7 @@
%% Extensions handling
-export([client_hello_extensions/6,
- handle_client_hello_extensions/8, %% Returns server hello extensions
+ handle_client_hello_extensions/9, %% Returns server hello extensions
handle_server_hello_extensions/9, select_curve/2
]).
@@ -164,7 +164,7 @@ next_protocol(SelectedProtocol) ->
%%--------------------------------------------------------------------
-spec client_certificate_verify(undefined | der_cert(), binary(),
- tls_version(), term(), private_key(),
+ tls_version(), term(), public_key:private_key(),
tls_handshake_history()) ->
#certificate_verify{} | ignore | #alert{}.
%%
@@ -207,12 +207,12 @@ certificate_request(CipherSuite, CertDbHandle, CertDbRef, Version) ->
{premaster_secret, binary(), public_key_info()} |
{dh, binary()} |
{dh, {binary(), binary()}, #'DHParameter'{}, {HashAlgo::atom(), SignAlgo::atom()},
- binary(), binary(), private_key()} |
+ binary(), binary(), public_key:private_key()} |
{ecdh, #'ECPrivateKey'{}} |
{psk, binary()} |
{dhe_psk, binary(), binary()} |
{srp, {binary(), binary()}, #srp_user{}, {HashAlgo::atom(), SignAlgo::atom()},
- binary(), binary(), private_key()}) ->
+ binary(), binary(), public_key:private_key()}) ->
#client_key_exchange{} | #server_key_exchange{}.
%%
@@ -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,
@@ -1088,17 +1089,19 @@ certificate_authorities_from_db(CertDbHandle, CertDbRef) ->
%%-------------Extension handling --------------------------------
-handle_client_hello_extensions(RecordCB, Random,
- #hello_extensions{renegotiation_info = Info,
- srp = SRP,
- ec_point_formats = ECCFormat,
- next_protocol_negotiation = NextProtocolNegotiation}, Version,
- #ssl_options{secure_renegotiate = SecureRenegotation} = Opts,
- #session{cipher_suite = CipherSuite, compression_method = Compression} = Session0,
- ConnectionStates0, Renegotiation) ->
+handle_client_hello_extensions(RecordCB, Random, ClientCipherSuites,
+ #hello_extensions{renegotiation_info = Info,
+ srp = SRP,
+ ec_point_formats = ECCFormat,
+ next_protocol_negotiation = NextProtocolNegotiation}, Version,
+ #ssl_options{secure_renegotiate = SecureRenegotation} = Opts,
+ #session{cipher_suite = NegotiatedCipherSuite,
+ compression_method = Compression} = Session0,
+ ConnectionStates0, Renegotiation) ->
Session = handle_srp_extension(SRP, Session0),
ConnectionStates = handle_renegotiation_extension(server, RecordCB, Version, Info,
- Random, CipherSuite, Compression,
+ Random, NegotiatedCipherSuite,
+ ClientCipherSuites, Compression,
ConnectionStates0, Renegotiation, SecureRenegotation),
ProtocolsToAdvertise = handle_next_protocol_extension(NextProtocolNegotiation, Renegotiation, Opts),
@@ -1117,7 +1120,8 @@ handle_server_hello_extensions(RecordCB, Random, CipherSuite, Compression,
#ssl_options{secure_renegotiate = SecureRenegotation,
next_protocol_selector = NextProtoSelector},
ConnectionStates0, Renegotiation) ->
- ConnectionStates = handle_renegotiation_extension(client, RecordCB, Version, Info, Random, CipherSuite,
+ ConnectionStates = handle_renegotiation_extension(client, RecordCB, Version, Info, Random,
+ CipherSuite, undefined,
Compression, ConnectionStates0,
Renegotiation, SecureRenegotation),
case handle_next_protocol(NextProtocolNegotiation, NextProtoSelector, Renegotiation) of
@@ -1287,7 +1291,7 @@ select_curve(#elliptic_curves{elliptic_curve_list = ClientCurves},
select_curve(undefined, _) ->
%% Client did not send ECC extension use default curve if
%% ECC cipher is negotiated
- {namedCurve, ?secp256k1};
+ {namedCurve, ?secp256r1};
select_curve(_, []) ->
no_curve;
select_curve(Curves, [Curve| Rest]) ->
@@ -1415,15 +1419,16 @@ calc_master_secret({3,0}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom)
calc_master_secret({3,_}, PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) ->
tls_v1:master_secret(PrfAlgo, PremasterSecret, ClientRandom, ServerRandom).
-handle_renegotiation_extension(Role, RecordCB, Version, Info, Random, CipherSuite, Compression,
+handle_renegotiation_extension(Role, RecordCB, Version, Info, Random, NegotiatedCipherSuite,
+ ClientCipherSuites, Compression,
ConnectionStates0, Renegotiation, SecureRenegotation) ->
case handle_renegotiation_info(RecordCB, Role, Info, ConnectionStates0,
Renegotiation, SecureRenegotation,
- [CipherSuite]) of
+ ClientCipherSuites) of
{ok, ConnectionStates} ->
hello_pending_connection_states(RecordCB, Role,
Version,
- CipherSuite,
+ NegotiatedCipherSuite,
Random,
Compression,
ConnectionStates);
@@ -1792,6 +1797,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..102215119d 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -35,7 +35,6 @@
-type certdb_ref() :: reference().
-type db_handle() :: term().
-type der_cert() :: binary().
--type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{} | #'ECPrivateKey'{}.
-type issuer() :: tuple().
-type serialnumber() :: integer().
-type cert_key() :: {reference(), integer(), issuer()}.
@@ -114,7 +113,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
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index 8e6f80da1e..ffa04ee8ba 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -199,7 +199,9 @@ hello(start, #state{host = Host, port = Port, role = client,
next_state(hello, hello, Record, State);
hello(Hello = #client_hello{client_version = ClientVersion,
- extensions = #hello_extensions{hash_signs = HashSigns}},
+ extensions = #hello_extensions{hash_signs = HashSigns,
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves}},
State = #state{connection_states = ConnectionStates0,
port = Port, session = #session{own_certificate = Cert} = Session0,
renegotiation = {Renegotiation, _},
@@ -210,9 +212,7 @@ hello(Hello = #client_hello{client_version = ClientVersion,
case tls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
ConnectionStates0, Cert}, Renegotiation) of
{Version, {Type, Session},
- ConnectionStates,
- #hello_extensions{ec_point_formats = EcPointFormats,
- elliptic_curves = EllipticCurves} = ServerHelloExt} ->
+ ConnectionStates, ServerHelloExt} ->
ssl_connection:hello({common_client_hello, Type, ServerHelloExt, HashSign},
State#state{connection_states = ConnectionStates,
negotiated_version = Version,
diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl
index 003614b448..01abefca46 100644
--- a/lib/ssl/src/tls_handshake.erl
+++ b/lib/ssl/src/tls_handshake.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -52,9 +52,9 @@ client_hello(Host, Port, ConnectionStates,
Pending = ssl_record:pending_connection_state(ConnectionStates, read),
SecParams = Pending#connection_state.security_parameters,
CipherSuites = ssl_handshake:available_suites(UserSuites, Version),
-
- Extensions = ssl_handshake:client_hello_extensions(Host, Version, CipherSuites,
- SslOpts, ConnectionStates, Renegotiation),
+ Extensions = ssl_handshake:client_hello_extensions(Host, Version,
+ CipherSuites,
+ SslOpts, ConnectionStates, Renegotiation),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
@@ -87,8 +87,8 @@ hello(#server_hello{server_version = Version, random = Random,
ConnectionStates0, Renegotiation) ->
case tls_record:is_acceptable_version(Version, SupportedVersions) of
true ->
- handle_hello_extensions(Version, SessionId, Random, CipherSuite,
- Compression, HelloExt, SslOpt, ConnectionStates0, Renegotiation);
+ handle_server_hello_extensions(Version, SessionId, Random, CipherSuite,
+ Compression, HelloExt, SslOpt, ConnectionStates0, Renegotiation);
false ->
?ALERT_REC(?FATAL, ?PROTOCOL_VERSION)
end;
@@ -113,9 +113,9 @@ hello(#client_hello{client_version = ClientVersion,
no_suite ->
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY);
_ ->
- handle_hello_extensions(Version, Type, Random, HelloExt,
- SslOpts, Session1, ConnectionStates0,
- Renegotiation)
+ handle_client_hello_extensions(Version, Type, Random, CipherSuites, HelloExt,
+ SslOpts, Session1, ConnectionStates0,
+ Renegotiation)
end;
false ->
?ALERT_REC(?FATAL, ?PROTOCOL_VERSION)
@@ -217,8 +217,10 @@ enc_handshake(HandshakeMsg, Version) ->
ssl_handshake:encode_handshake(HandshakeMsg, Version).
-handle_hello_extensions(Version, Type, Random, HelloExt, SslOpts, Session0, ConnectionStates0, Renegotiation) ->
- try ssl_handshake:handle_client_hello_extensions(tls_record, Random, HelloExt, Version, SslOpts,
+handle_client_hello_extensions(Version, Type, Random, CipherSuites,
+ HelloExt, SslOpts, Session0, ConnectionStates0, Renegotiation) ->
+ try ssl_handshake:handle_client_hello_extensions(tls_record, Random, CipherSuites,
+ HelloExt, Version, SslOpts,
Session0, ConnectionStates0, Renegotiation) of
{Session, ConnectionStates, ServerHelloExt} ->
{Version, {Type, Session}, ConnectionStates, ServerHelloExt}
@@ -227,7 +229,7 @@ handle_hello_extensions(Version, Type, Random, HelloExt, SslOpts, Session0, Conn
end.
-handle_hello_extensions(Version, SessionId, Random, CipherSuite,
+handle_server_hello_extensions(Version, SessionId, Random, CipherSuite,
Compression, HelloExt, SslOpt, ConnectionStates0, Renegotiation) ->
case ssl_handshake:handle_server_hello_extensions(tls_record, Random, CipherSuite,
Compression, HelloExt, Version,
diff --git a/lib/ssl/src/tls_v1.erl b/lib/ssl/src/tls_v1.erl
index 2395e98642..7c7fdd64c3 100644
--- a/lib/ssl/src/tls_v1.erl
+++ b/lib/ssl/src/tls_v1.erl
@@ -368,11 +368,19 @@ finished_label(server) ->
%% list ECC curves in prefered order
ecc_curves(_Minor) ->
- [?sect571r1,?sect571k1,?secp521r1,?sect409k1,?sect409r1,
- ?secp384r1,?sect283k1,?sect283r1,?secp256k1,?secp256r1,
- ?sect239k1,?sect233k1,?sect233r1,?secp224k1,?secp224r1,
- ?sect193r1,?sect193r2,?secp192k1,?secp192r1,?sect163k1,
- ?sect163r1,?sect163r2,?secp160k1,?secp160r1,?secp160r2].
+ TLSCurves = [sect571r1,sect571k1,secp521r1,brainpoolP512r1,
+ sect409k1,sect409r1,brainpoolP384r1,secp384r1,
+ sect283k1,sect283r1,brainpoolP256r1,secp256k1,secp256r1,
+ sect239k1,sect233k1,sect233r1,secp224k1,secp224r1,
+ sect193r1,sect193r2,secp192k1,secp192r1,sect163k1,
+ sect163r1,sect163r2,secp160k1,secp160r1,secp160r2],
+ CryptoCurves = crypto:ec_curves(),
+ lists:foldr(fun(Curve, Curves) ->
+ case proplists:get_bool(Curve, CryptoCurves) of
+ true -> [pubkey_cert_records:namedCurves(Curve)|Curves];
+ false -> Curves
+ end
+ end, [], TLSCurves).
%% ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005)
oid_to_enum(?sect163k1) -> 1;
@@ -399,7 +407,10 @@ oid_to_enum(?secp224r1) -> 21;
oid_to_enum(?secp256k1) -> 22;
oid_to_enum(?secp256r1) -> 23;
oid_to_enum(?secp384r1) -> 24;
-oid_to_enum(?secp521r1) -> 25.
+oid_to_enum(?secp521r1) -> 25;
+oid_to_enum(?brainpoolP256r1) -> 26;
+oid_to_enum(?brainpoolP384r1) -> 27;
+oid_to_enum(?brainpoolP512r1) -> 28.
enum_to_oid(1) -> ?sect163k1;
enum_to_oid(2) -> ?sect163r1;
@@ -425,7 +436,10 @@ enum_to_oid(21) -> ?secp224r1;
enum_to_oid(22) -> ?secp256k1;
enum_to_oid(23) -> ?secp256r1;
enum_to_oid(24) -> ?secp384r1;
-enum_to_oid(25) -> ?secp521r1.
+enum_to_oid(25) -> ?secp521r1;
+enum_to_oid(26) -> ?brainpoolP256r1;
+enum_to_oid(27) -> ?brainpoolP384r1;
+enum_to_oid(28) -> ?brainpoolP512r1.
sufficent_ec_support() ->
CryptoSupport = crypto:supports(),
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 54029ebe6d..ddc511c652 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -110,7 +110,10 @@ options_tests() ->
empty_protocol_versions,
ipv6,
reuseaddr,
- tcp_reuseaddr].
+ tcp_reuseaddr,
+ honor_server_cipher_order,
+ honor_client_cipher_order
+].
api_tests() ->
[connection_info,
@@ -130,7 +133,8 @@ api_tests() ->
listen_socket,
ssl_accept_timeout,
ssl_recv_timeout,
- versions_option
+ versions_option,
+ server_name_indication_option
].
session_tests() ->
@@ -143,6 +147,7 @@ session_tests() ->
renegotiate_tests() ->
[client_renegotiate,
server_renegotiate,
+ client_secure_renegotiate,
client_renegotiate_reused_session,
server_renegotiate_reused_session,
client_no_wrap_sequence_number,
@@ -1978,6 +1983,37 @@ client_renegotiate(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
+client_secure_renegotiate() ->
+ [{doc,"Test ssl:renegotiate/1 on client."}].
+client_secure_renegotiate(Config) when is_list(Config) ->
+ ServerOpts = ?config(server_opts, Config),
+ ClientOpts = ?config(client_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From erlang to erlang",
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
+ {options, [{secure_renegotiate, true} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ renegotiate, [Data]}},
+ {options, [{reuse_sessions, false},
+ {secure_renegotiate, true}| ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+%%--------------------------------------------------------------------
server_renegotiate() ->
[{doc,"Test ssl:renegotiate/1 on server."}].
server_renegotiate(Config) when is_list(Config) ->
@@ -2410,6 +2446,51 @@ tcp_reuseaddr(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
+honor_server_cipher_order() ->
+ [{doc,"Test API honor server cipher order."}].
+honor_server_cipher_order(Config) when is_list(Config) ->
+ ClientCiphers = [{rsa, aes_128_cbc, sha}, {rsa, aes_256_cbc, sha}],
+ ServerCiphers = [{rsa, aes_256_cbc, sha}, {rsa, aes_128_cbc, sha}],
+honor_cipher_order(Config, true, ServerCiphers, ClientCiphers, {rsa, aes_256_cbc, sha}).
+
+honor_client_cipher_order() ->
+ [{doc,"Test API honor server cipher order."}].
+honor_client_cipher_order(Config) when is_list(Config) ->
+ ClientCiphers = [{rsa, aes_128_cbc, sha}, {rsa, aes_256_cbc, sha}],
+ ServerCiphers = [{rsa, aes_256_cbc, sha}, {rsa, aes_128_cbc, sha}],
+honor_cipher_order(Config, false, ServerCiphers, ClientCiphers, {rsa, aes_128_cbc, sha}).
+
+honor_cipher_order(Config, Honor, ServerCiphers, ClientCiphers, Expected) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, connection_info_result, []}},
+ {options, [{ciphers, ServerCiphers}, {honor_cipher_order, Honor}
+ | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, connection_info_result, []}},
+ {options, [{ciphers, ClientCiphers}, {honor_cipher_order, Honor}
+ | ClientOpts]}]),
+
+ Version =
+ tls_record:protocol_version(tls_record:highest_protocol_version([])),
+
+ ServerMsg = ClientMsg = {ok, {Version, Expected}},
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+
hibernate() ->
[{doc,"Check that an SSL connection that is started with option "
"{hibernate_after, 1000} indeed hibernates after 1000ms of "
@@ -2804,6 +2885,47 @@ versions_option(Config) when is_list(Config) ->
end,
ssl_test_lib:check_result(ErrClient, {error, {tls_alert, "protocol version"}}).
+
+
+%%--------------------------------------------------------------------
+
+server_name_indication_option() ->
+ [{doc,"Test API server_name_indication option to connect."}].
+server_name_indication_option(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options,
+ [{server_name_indication, disable} |
+ ClientOpts]}
+ ]),
+
+ ssl_test_lib:check_result(Server, ok, Client0, ok),
+ Server ! listen,
+
+ Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options,
+ [{server_name_indication, Hostname} | ClientOpts]
+ }]),
+ ssl_test_lib:check_result(Server, ok, Client1, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client0),
+ ssl_test_lib:close(Client1).
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
diff --git a/lib/ssl/test/ssl_dist_SUITE.erl b/lib/ssl/test/ssl_dist_SUITE.erl
index d3b523ca8c..1a1b2af8d4 100644
--- a/lib/ssl/test/ssl_dist_SUITE.erl
+++ b/lib/ssl/test/ssl_dist_SUITE.erl
@@ -324,7 +324,7 @@ start_ssl_node_raw(Name, Args) ->
[binary, {packet, 4}, {active, false}]),
{ok, ListenPort} = inet:port(LSock),
CmdLine = mk_node_cmdline(ListenPort, Name, Args),
- ?t:format("Attempting to start ssl node ~s: ~s~n", [Name, CmdLine]),
+ ?t:format("Attempting to start ssl node ~ts: ~ts~n", [Name, CmdLine]),
case open_port({spawn, CmdLine}, []) of
Port when is_port(Port) ->
unlink(Port),
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 74fadc0cc7..7ed9adfcd9 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -146,7 +146,7 @@ remove_close_msg(ReconnectTimes) ->
end.
start_client(Args) ->
- Result = spawn_link(?MODULE, run_client, [lists:delete(return_socket, Args)]),
+ Result = spawn_link(?MODULE, run_client_init, [lists:delete(return_socket, Args)]),
receive
{ connected, Socket } ->
case lists:member(return_socket, Args) of
@@ -155,6 +155,10 @@ start_client(Args) ->
end
end.
+run_client_init(Opts) ->
+ put(retries, 0),
+ run_client(Opts).
+
run_client(Opts) ->
Node = proplists:get_value(node, Opts),
Host = proplists:get_value(host, Opts),
@@ -189,9 +193,19 @@ run_client(Opts) ->
{gen_tcp, closed} ->
ok
end;
+ {error, econnrefused = Reason} ->
+ case get(retries) of
+ N when N < 5 ->
+ put(retries, N+1),
+ ct:sleep(?SLEEP),
+ run_client(Opts);
+ _ ->
+ ct:log("Client faild several times: connection failed: ~p ~n", [Reason]),
+ Pid ! {self(), {error, Reason}}
+ end;
{error, Reason} ->
ct:log("Client: connection failed: ~p ~n", [Reason]),
- Pid ! {self(), {error, Reason}}
+ Pid ! {self(), {error, Reason}}
end.
close(Pid) ->
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index 21f0172dba..68784a175e 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -154,22 +154,31 @@ special_init(TestCase, Config)
TestCase == erlang_client_openssl_server_nowrap_seqnum;
TestCase == erlang_server_openssl_client_nowrap_seqnum
->
- check_sane_openssl_renegotaite(Config);
+ {ok, Version} = application:get_env(ssl, protocol_version),
+ check_sane_openssl_renegotaite(Config, Version);
special_init(ssl2_erlang_server_openssl_client, Config) ->
check_sane_openssl_sslv2(Config);
special_init(TestCase, Config)
when TestCase == erlang_client_openssl_server_npn;
- TestCase == erlang_server_openssl_client_npn;
- TestCase == erlang_server_openssl_client_npn_renegotiate;
- TestCase == erlang_client_openssl_server_npn_renegotiate;
+ TestCase == erlang_server_openssl_client_npn;
TestCase == erlang_server_openssl_client_npn_only_server;
TestCase == erlang_server_openssl_client_npn_only_client;
TestCase == erlang_client_openssl_server_npn_only_client;
TestCase == erlang_client_openssl_server_npn_only_server ->
check_openssl_npn_support(Config);
+special_init(TestCase, Config)
+ when TestCase == erlang_server_openssl_client_npn_renegotiate;
+ TestCase == erlang_client_openssl_server_npn_renegotiate ->
+ {ok, Version} = application:get_env(ssl, protocol_version),
+ case check_sane_openssl_renegotaite(Config, Version) of
+ {skip, _} = Skip ->
+ Skip;
+ _ ->
+ check_openssl_npn_support(Config)
+ end;
special_init(_, Config) ->
Config.
@@ -903,8 +912,16 @@ ssl2_erlang_server_openssl_client(Config) when is_list(Config) ->
{'EXIT', OpenSslPort, _} = Exit ->
ct:log("Received: ~p ~n", [Exit]),
ok
-
end,
+ receive
+ {'EXIT', _, _} = UnkownExit ->
+ Msg = lists:flatten(io_lib:format("Received: ~p ~n", [UnkownExit])),
+ ct:log(Msg),
+ ct:comment(Msg),
+ ok
+ after 0 ->
+ ok
+ end,
ssl_test_lib:check_result(Server, {error, {tls_alert, "protocol version"}}),
process_flag(trap_exit, false).
@@ -1315,8 +1332,25 @@ check_openssl_npn_support(Config) ->
Config
end.
+check_sane_openssl_renegotaite(Config, Version) when Version == 'tlsv1.1';
+ Version == 'tlsv1.2' ->
+ case os:cmd("openssl version") of
+ "OpenSSL 1.0.1c" ++ _ ->
+ {skip, "Known renegotiation bug in OpenSSL"};
+ "OpenSSL 1.0.1b" ++ _ ->
+ {skip, "Known renegotiation bug in OpenSSL"};
+ "OpenSSL 1.0.1a" ++ _ ->
+ {skip, "Known renegotiation bug in OpenSSL"};
+ "OpenSSL 1.0.1" ++ _ ->
+ {skip, "Known renegotiation bug in OpenSSL"};
+ _ ->
+ check_sane_openssl_renegotaite(Config)
+ end;
+check_sane_openssl_renegotaite(Config, _) ->
+ check_sane_openssl_renegotaite(Config).
+
check_sane_openssl_renegotaite(Config) ->
- case os:cmd("openssl version") of
+ case os:cmd("openssl version") of
"OpenSSL 0.9.8" ++ _ ->
{skip, "Known renegotiation bug in OpenSSL"};
"OpenSSL 0.9.7" ++ _ ->
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index a2dd3f5930..a6e0efed25 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1 +1 @@
-SSL_VSN = 5.3.2
+SSL_VSN = 5.3.3