ports/184646: [PATCH] lang/erlang: tls ecc fix
ports at c0decafe.net
ports at c0decafe.net
Tue Dec 10 00:20:00 UTC 2013
>Number: 184646
>Category: ports
>Synopsis: [PATCH] lang/erlang: tls ecc fix
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-ports-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: change-request
>Submitter-Id: current-users
>Arrival-Date: Tue Dec 10 00:20:00 UTC 2013
>Closed-Date:
>Last-Modified:
>Originator: ports at c0decafe.net
>Release: FreeBSD 10.0-PRERELEASE amd64
>Organization:
>Environment:
System: FreeBSD vystrel.c0decafe.net 10.0-PRERELEASE FreeBSD 10.0-PRERELEASE #9 r259108: Mon Dec 9 03:23:52
>Description:
Discussion: http://erlang.org/pipermail/erlang-bugs/2013-October/003771.html
Patch: https://github.com/erlang/otp/commit/f13b2362c665ef2d98858a4601b1fecf31a21bb5
Port maintainer (olgeni at FreeBSD.org) is cc'd.
Generated with FreeBSD Port Tools 0.99_11 (mode: change, diff: ports)
>How-To-Repeat:
>Fix:
--- erlang-16.b.02,3.patch begins here ---
diff -ruN /usr/ports/lang/erlang/files/patch-ecc ./files/patch-ecc
--- /usr/ports/lang/erlang/files/patch-ecc 1970-01-01 02:00:00.000000000 +0200
+++ ./files/patch-ecc 2013-12-10 01:26:59.000000000 +0200
@@ -0,0 +1,313 @@
+diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
+index 6513042..e6ed0d8 100644
+--- lib/ssl/src/ssl_cipher.erl
++++ lib/ssl/src/ssl_cipher.erl
+@@ -34,7 +34,7 @@
+
+ -export([security_parameters/2, security_parameters/3, suite_definition/1,
+ decipher/5, cipher/5,
+- suite/1, suites/1, anonymous_suites/0, psk_suites/1, srp_suites/0,
++ suite/1, suites/1, ec_keyed_suites/0, anonymous_suites/0, psk_suites/1, srp_suites/0,
+ openssl_suite/1, openssl_suite_name/1, filter/2, filter_suites/1,
+ hash_algorithm/1, sign_algorithm/1, is_acceptable_hash/2]).
+
+diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
+index 29a8996..b18452a 100644
+--- lib/ssl/src/ssl_handshake.erl
++++ lib/ssl/src/ssl_handshake.erl
+@@ -49,13 +49,13 @@
+ ]).
+
+ %% Cipher suites handling
+--export([available_suites/2, available_suites/3, cipher_suites/2,
+- select_session/10]).
++-export([available_suites/2, cipher_suites/2,
++ select_session/10, supported_ecc/1]).
+
+ %% Extensions handling
+ -export([client_hello_extensions/5,
+ handle_client_hello_extensions/8, %% Returns server hello extensions
+- handle_server_hello_extensions/9
++ handle_server_hello_extensions/9, select_curve/2
+ ]).
+
+ %% MISC
+@@ -89,7 +89,7 @@ client_hello_extensions(Version, CipherSuites, SslOpts, ConnectionStates, Renego
+ {EcPointFormats, EllipticCurves} =
+ case advertises_ec_ciphers(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites)) of
+ true ->
+- ecc_extensions(tls_v1, Version);
++ client_ecc_extensions(tls_v1, Version);
+ false ->
+ {undefined, undefined}
+ end,
+@@ -861,22 +861,29 @@ available_suites(UserSuites, Version) ->
+ UserSuites
+ end.
+
+-available_suites(ServerCert, UserSuites, Version) ->
+- ssl_cipher:filter(ServerCert, available_suites(UserSuites, Version)).
++available_suites(ServerCert, UserSuites, Version, Curve) ->
++ ssl_cipher:filter(ServerCert, available_suites(UserSuites, Version))
++ -- unavailable_ecc_suites(Curve).
++
++unavailable_ecc_suites(no_curve) ->
++ ssl_cipher:ec_keyed_suites();
++unavailable_ecc_suites(_) ->
++ [].
+
+ cipher_suites(Suites, false) ->
+ [?TLS_EMPTY_RENEGOTIATION_INFO_SCSV | Suites];
+ cipher_suites(Suites, true) ->
+ Suites.
+
+-select_session(SuggestedSessionId, CipherSuites, Compressions, Port, Session, Version,
++select_session(SuggestedSessionId, CipherSuites, Compressions, Port, #session{ecc = ECCCurve} =
++ Session, Version,
+ #ssl_options{ciphers = UserSuites} = SslOpts, Cache, CacheCb, Cert) ->
+ {SessionId, Resumed} = ssl_session:server_id(Port, SuggestedSessionId,
+ SslOpts, Cert,
+ Cache, CacheCb),
+- Suites = ssl_handshake:available_suites(Cert, UserSuites, Version),
+ case Resumed of
+ undefined ->
++ Suites = available_suites(Cert, UserSuites, Version, ECCCurve),
+ CipherSuite = select_cipher_suite(CipherSuites, Suites),
+ Compression = select_compression(Compressions),
+ {new, Session#session{session_id = SessionId,
+@@ -886,6 +893,13 @@ select_session(SuggestedSessionId, CipherSuites, Compressions, Port, Session, Ve
+ {resumed, Resumed}
+ end.
+
++supported_ecc(Version) ->
++ case tls_v1:ecc_curves(Version) of
++ [] ->
++ undefined;
++ Curves ->
++ #elliptic_curves{elliptic_curve_list = Curves}
++ end.
+ %%-------------certificate handling --------------------------------
+
+ certificate_types({KeyExchange, _, _, _})
+@@ -926,9 +940,8 @@ certificate_authorities_from_db(CertDbHandle, CertDbRef) ->
+ handle_client_hello_extensions(RecordCB, Random,
+ #hello_extensions{renegotiation_info = Info,
+ srp = SRP,
+- next_protocol_negotiation = NextProtocolNegotiation,
+- ec_point_formats = EcPointFormats0,
+- elliptic_curves = EllipticCurves0}, Version,
++ 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) ->
+@@ -937,12 +950,11 @@ handle_client_hello_extensions(RecordCB, Random,
+ Random, CipherSuite, Compression,
+ ConnectionStates0, Renegotiation, SecureRenegotation),
+ ProtocolsToAdvertise = handle_next_protocol_extension(NextProtocolNegotiation, Renegotiation, Opts),
+- {EcPointFormats, EllipticCurves} = handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0),
++
+ ServerHelloExtensions = #hello_extensions{
+ renegotiation_info = renegotiation_info(RecordCB, server,
+ ConnectionStates, Renegotiation),
+- ec_point_formats = EcPointFormats,
+- elliptic_curves = EllipticCurves,
++ ec_point_formats = server_ecc_extension(Version, ECCFormat),
+ next_protocol_negotiation =
+ encode_protocols_advertised_on_server(ProtocolsToAdvertise)
+ },
+@@ -1078,7 +1090,7 @@ srp_user(#ssl_options{srp_identity = {UserName, _}}) ->
+ srp_user(_) ->
+ undefined.
+
+-ecc_extensions(Module, Version) ->
++client_ecc_extensions(Module, Version) ->
+ CryptoSupport = proplists:get_value(public_keys, crypto:supports()),
+ case proplists:get_bool(ecdh, CryptoSupport) of
+ true ->
+@@ -1089,15 +1101,13 @@ ecc_extensions(Module, Version) ->
+ {undefined, undefined}
+ end.
+
+-handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0) ->
++server_ecc_extension(_Version, EcPointFormats) ->
+ CryptoSupport = proplists:get_value(public_keys, crypto:supports()),
+ case proplists:get_bool(ecdh, CryptoSupport) of
+ true ->
+- EcPointFormats1 = handle_ecc_point_fmt_extension(EcPointFormats0),
+- EllipticCurves1 = handle_ecc_curves_extension(Version, EllipticCurves0),
+- {EcPointFormats1, EllipticCurves1};
+- _ ->
+- {undefined, undefined}
++ handle_ecc_point_fmt_extension(EcPointFormats);
++ false ->
++ undefined
+ end.
+
+ handle_ecc_point_fmt_extension(undefined) ->
+@@ -1105,11 +1115,6 @@ handle_ecc_point_fmt_extension(undefined) ->
+ handle_ecc_point_fmt_extension(_) ->
+ #ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]}.
+
+-handle_ecc_curves_extension(_Version, undefined) ->
+- undefined;
+-handle_ecc_curves_extension(Version, _) ->
+- #elliptic_curves{elliptic_curve_list = tls_v1:ecc_curves(Version)}.
+-
+ advertises_ec_ciphers([]) ->
+ false;
+ advertises_ec_ciphers([{ecdh_ecdsa, _,_,_} | _]) ->
+@@ -1124,6 +1129,22 @@ advertises_ec_ciphers([{ecdh_anon, _,_,_} | _]) ->
+ true;
+ advertises_ec_ciphers([_| Rest]) ->
+ advertises_ec_ciphers(Rest).
++select_curve(#elliptic_curves{elliptic_curve_list = ClientCurves},
++ #elliptic_curves{elliptic_curve_list = ServerCurves}) ->
++ select_curve(ClientCurves, ServerCurves);
++select_curve(undefined, _) ->
++ %% Client did not send ECC extension use default curve if
++ %% ECC cipher is negotiated
++ {namedCurve, ?secp256k1};
++select_curve(_, []) ->
++ no_curve;
++select_curve(Curves, [Curve| Rest]) ->
++ case lists:member(Curve, Curves) of
++ true ->
++ {namedCurve, Curve};
++ false ->
++ select_curve(Curves, Rest)
++ end.
+
+ %%--------------------------------------------------------------------
+ %%% Internal functions
+@@ -1648,3 +1669,4 @@ advertised_hash_signs({Major, Minor}) when Major >= 3 andalso Minor >= 3 ->
+ ({Hash, _}) -> proplists:get_bool(Hash, Hashs) end, HashSigns)};
+ advertised_hash_signs(_) ->
+ undefined.
++
+diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
+index 3a3ad8c..f25b0df 100644
+--- lib/ssl/src/ssl_handshake.hrl
++++ lib/ssl/src/ssl_handshake.hrl
+@@ -45,7 +45,8 @@
+ master_secret,
+ srp_username,
+ is_resumable,
+- time_stamp
++ time_stamp,
++ ecc
+ }).
+
+ -define(NUM_OF_SESSION_ID_BYTES, 32). % TSL 1.1 & SSL 3
+diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
+index 5618837..39595b4 100644
+--- lib/ssl/src/tls_connection.erl
++++ lib/ssl/src/tls_connection.erl
+@@ -97,8 +97,7 @@
+ terminated = false, %
+ allow_renegotiate = true,
+ expecting_next_protocol_negotiation = false :: boolean(),
+- next_protocol = undefined :: undefined | binary(),
+- client_ecc % {Curves, PointFmt}
++ next_protocol = undefined :: undefined | binary()
+ }).
+
+ -define(DEFAULT_DIFFIE_HELLMAN_PARAMS,
+@@ -405,26 +404,24 @@ hello(#server_hello{cipher_suite = CipherSuite,
+ hello(Hello = #client_hello{client_version = ClientVersion,
+ extensions = #hello_extensions{hash_signs = HashSigns}},
+ State = #state{connection_states = ConnectionStates0,
+- port = Port, session = #session{own_certificate = Cert} = Session0,
++ port = Port,
++ session = #session{own_certificate = Cert} = Session0,
+ renegotiation = {Renegotiation, _},
+ session_cache = Cache,
+ session_cache_cb = CacheCb,
+ ssl_options = SslOpts}) ->
+ HashSign = ssl_handshake:select_hashsign(HashSigns, Cert),
+ case tls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
+- ConnectionStates0, Cert}, Renegotiation) of
++ ConnectionStates0, Cert}, Renegotiation) of
+ {Version, {Type, #session{cipher_suite = CipherSuite} = Session},
+- ConnectionStates,
+- #hello_extensions{ec_point_formats = EcPointFormats,
+- elliptic_curves = EllipticCurves} = ServerHelloExt} ->
++ ConnectionStates, ServerHelloExt} ->
+ {KeyAlg, _, _, _} = ssl_cipher:suite_definition(CipherSuite),
+- NegotiatedHashSign = negotiated_hashsign(HashSign, KeyAlg, Version),
+- do_server_hello(Type, ServerHelloExt,
++ NegotiatedHashSign = negotiated_hashsign(HashSign, KeyAlg, Version),
++ do_server_hello(Type, ServerHelloExt,
+ State#state{connection_states = ConnectionStates,
+ negotiated_version = Version,
+ session = Session,
+- hashsign_algorithm = NegotiatedHashSign,
+- client_ecc = {EllipticCurves, EcPointFormats}});
++ hashsign_algorithm = NegotiatedHashSign});
+ #alert{} = Alert ->
+ handle_own_alert(Alert, ClientVersion, hello, State)
+ end;
+@@ -1647,12 +1644,13 @@ key_exchange(#state{role = server, key_algorithm = Algo,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+- transport_cb = Transport
++ transport_cb = Transport,
++ session = #session{ecc = Curve}
+ } = State)
+ when Algo == ecdhe_ecdsa; Algo == ecdhe_rsa;
+ Algo == ecdh_anon ->
+
+- ECDHKeys = public_key:generate_key(select_curve(State)),
++ ECDHKeys = public_key:generate_key(Curve),
+ ConnectionState =
+ ssl_record:pending_connection_state(ConnectionStates0, read),
+ SecParams = ConnectionState#connection_state.security_parameters,
+@@ -3086,12 +3084,7 @@ default_hashsign(_Version, KeyExchange)
+ KeyExchange == rsa_psk;
+ KeyExchange == srp_anon ->
+ {null, anon}.
+-
+-select_curve(#state{client_ecc = {[Curve|_], _}}) ->
+- {namedCurve, Curve};
+-select_curve(_) ->
+- {namedCurve, ?secp256k1}.
+-
++
+ is_anonymous(Algo) when Algo == dh_anon;
+ Algo == ecdh_anon;
+ Algo == psk;
+diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl
+index 02bfa69..ecbca83 100644
+--- lib/ssl/src/tls_handshake.erl
++++ lib/ssl/src/tls_handshake.erl
+@@ -70,7 +70,7 @@ client_hello(Host, Port, ConnectionStates,
+ }.
+
+ %%--------------------------------------------------------------------
+--spec server_hello(#session{}, tls_version(), #connection_states{},
++-spec server_hello(binary(), tls_version(), #connection_states{},
+ #hello_extensions{}) -> #server_hello{}.
+ %%
+ %% Description: Creates a server hello message.
+@@ -120,17 +120,16 @@ hello(#client_hello{client_version = ClientVersion,
+ cipher_suites = CipherSuites,
+ compression_methods = Compressions,
+ random = Random,
+- extensions = HelloExt},
++ extensions = #hello_extensions{elliptic_curves = Curves} = HelloExt},
+ #ssl_options{versions = Versions} = SslOpts,
+ {Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) ->
+ Version = ssl_handshake:select_version(tls_record, ClientVersion, Versions),
+ case tls_record:is_acceptable_version(Version, Versions) of
+ true ->
+- %% TODO: need to take supported Curves into Account when selecting the CipherSuite....
+- %% if whe have an ECDSA cert with an unsupported curve, we need to drop ECDSA ciphers
++ ECCCurve = ssl_handshake:select_curve(Curves, ssl_handshake:supported_ecc(Version)),
+ {Type, #session{cipher_suite = CipherSuite} = Session1}
+ = ssl_handshake:select_session(SugesstedId, CipherSuites, Compressions,
+- Port, Session0, Version,
++ Port, Session0#session{ecc = ECCCurve}, Version,
+ SslOpts, Cache, CacheCb, Cert),
+ case CipherSuite of
+ no_suite ->
--- erlang-16.b.02,3.patch ends here ---
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-ports-bugs
mailing list