From 38b07caa2a1c6cd3537eadd36770afa54f067562 Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin
Date: Tue, 7 Nov 2017 18:34:34 +0100
Subject: ssl: Countermeasurements for Bleichenbacher attack
---
lib/ssl/src/dtls_connection.erl | 1 +
lib/ssl/src/ssl_connection.erl | 21 +++++++++++++++++++--
lib/ssl/src/ssl_connection.hrl | 1 +
lib/ssl/src/tls_connection.erl | 1 +
4 files changed, 22 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index ff3e69bae5..260ae8769c 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -644,6 +644,7 @@ handle_client_hello(#client_hello{client_version = ClientVersion} = Hello,
State = prepare_flight(State0#state{connection_states = ConnectionStates,
negotiated_version = Version,
+ client_hello_version = ClientVersion,
hashsign_algorithm = HashSign,
session = Session,
negotiated_protocol = Protocol}),
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index b031d3d47b..b33ce63c32 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -1367,8 +1367,25 @@ server_certify_and_key_exchange(State0, Connection) ->
request_client_cert(State2, Connection).
certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS},
- #state{private_key = Key} = State, Connection) ->
- PremasterSecret = ssl_handshake:premaster_secret(EncPMS, Key),
+ #state{private_key = Key, client_hello_version = {Major, Minor} = Version} = State, Connection) ->
+
+ %% Countermeasure for Bleichenbacher attack always provide some kind of premaster secret
+ %% and fail handshake later.RFC 5246 section 7.4.7.1.
+ PremasterSecret =
+ try ssl_handshake:premaster_secret(EncPMS, Key) of
+ Secret when erlang:byte_size(Secret) == ?NUM_OF_PREMASTERSECRET_BYTES ->
+ case Secret of
+ <> -> %% Correct
+ Secret;
+ <> -> %% Version mismatch
+ <>
+ end;
+ _ -> %% erlang:byte_size(Secret) =/= ?NUM_OF_PREMASTERSECRET_BYTES
+ make_premaster_secret(Version, rsa)
+ catch
+ #alert{description = ?DECRYPT_ERROR} ->
+ make_premaster_secret(Version, rsa)
+ end,
calculate_master_secret(PremasterSecret, State, Connection, certify, cipher);
certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPublicDhKey},
diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl
index 3e26f67de1..f9d2149170 100644
--- a/lib/ssl/src/ssl_connection.hrl
+++ b/lib/ssl/src/ssl_connection.hrl
@@ -57,6 +57,7 @@
session_cache_cb :: atom(),
crl_db :: term(),
negotiated_version :: ssl_record:ssl_version() | 'undefined',
+ client_hello_version :: ssl_record:ssl_version() | 'undefined',
client_certificate_requested = false :: boolean(),
key_algorithm :: ssl_cipher:key_algo(),
hashsign_algorithm = {undefined, undefined},
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index e3ffbea3d3..7861287a22 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -286,6 +286,7 @@ hello(internal, #client_hello{client_version = ClientVersion} = Hello,
gen_handshake(ssl_connection, hello, internal, {common_client_hello, Type, ServerHelloExt},
State#state{connection_states = ConnectionStates,
negotiated_version = Version,
+ client_hello_version = ClientVersion,
hashsign_algorithm = HashSign,
session = Session,
negotiated_protocol = Protocol})
--
cgit v1.2.3
From 90b1b43eb3be556d47cecbe766d6bff3761be31e Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin
Date: Thu, 9 Nov 2017 16:53:44 +0100
Subject: ssl: Prepare for release
---
lib/ssl/vsn.mk | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index bb77326751..cf6481d14c 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1 +1 @@
-SSL_VSN = 8.2.1
+SSL_VSN = 8.2.2
--
cgit v1.2.3
From 4147cfeb7c068cc65831d3fc249f6d4a83830a58 Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin
Date: Fri, 13 Oct 2017 13:29:05 +0200
Subject: ssl: Use ?FUNCTION_NAME
Use ?FUNCTION_NAME macro to enhance code as we will not back-port this
version of the ssl application to versions pre OTP 19.
---
lib/ssl/src/dtls_connection.erl | 82 +++++++++++++++++-----------------
lib/ssl/src/ssl_connection.erl | 98 ++++++++++++++++++++---------------------
lib/ssl/src/tls_connection.erl | 28 ++++++------
3 files changed, 104 insertions(+), 104 deletions(-)
(limited to 'lib')
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index ff3e69bae5..2c5cfb0c5e 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -273,28 +273,28 @@ init({call, From}, {start, Timeout},
{Record, State} = next_record(State3),
next_event(hello, Record, State, Actions);
init({call, _} = Type, Event, #state{role = server, transport_cb = gen_udp} = State) ->
- Result = ssl_connection:init(Type, Event,
- State#state{flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT},
- protocol_specific = #{current_cookie_secret => dtls_v1:cookie_secret(),
- previous_cookie_secret => <<>>,
- ignored_alerts => 0,
- max_ignored_alerts => 10}},
- ?MODULE),
+ Result = ssl_connection:?FUNCTION_NAME(Type, Event,
+ State#state{flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT},
+ protocol_specific = #{current_cookie_secret => dtls_v1:cookie_secret(),
+ previous_cookie_secret => <<>>,
+ ignored_alerts => 0,
+ max_ignored_alerts => 10}},
+ ?MODULE),
erlang:send_after(dtls_v1:cookie_timeout(), self(), new_cookie_secret),
Result;
-
+
init({call, _} = Type, Event, #state{role = server} = State) ->
%% I.E. DTLS over sctp
- ssl_connection:init(Type, Event, State#state{flight_state = reliable}, ?MODULE);
+ ssl_connection:?FUNCTION_NAME(Type, Event, State#state{flight_state = reliable}, ?MODULE);
init(Type, Event, State) ->
- ssl_connection:init(Type, Event, State, ?MODULE).
+ ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE).
error(enter, _, State) ->
{keep_state, State};
error({call, From}, {start, _Timeout}, {Error, State}) ->
{stop_and_reply, normal, {reply, From, {error, Error}}, State};
error({call, From}, Msg, State) ->
- handle_call(Msg, From, error, State);
+ handle_call(Msg, From, ?FUNCTION_NAME, State);
error(_, _, _) ->
{keep_state_and_data, [postpone]}.
@@ -326,7 +326,7 @@ hello(internal, #client_hello{cookie = <<>>,
State1 = prepare_flight(State0#state{negotiated_version = Version}),
{State2, Actions} = send_handshake(VerifyRequest, State1),
{Record, State} = next_record(State2),
- next_event(hello, Record, State#state{tls_handshake_history = ssl_handshake:init_handshake_history()}, Actions);
+ next_event(?FUNCTION_NAME, Record, State#state{tls_handshake_history = ssl_handshake:init_handshake_history()}, Actions);
hello(internal, #client_hello{cookie = Cookie} = Hello, #state{role = server,
transport_cb = Transport,
socket = Socket,
@@ -367,7 +367,7 @@ hello(internal, #hello_verify_request{cookie = Cookie}, #state{role = client,
Session0#session{session_id =
Hello#client_hello.session_id}},
{Record, State} = next_record(State3),
- next_event(hello, Record, State, Actions);
+ next_event(?FUNCTION_NAME, Record, State, Actions);
hello(internal, #server_hello{} = Hello,
#state{connection_states = ConnectionStates0,
negotiated_version = ReqVersion,
@@ -376,80 +376,80 @@ hello(internal, #server_hello{} = Hello,
ssl_options = SslOptions} = State) ->
case dtls_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
#alert{} = Alert ->
- handle_own_alert(Alert, ReqVersion, hello, State);
+ handle_own_alert(Alert, ReqVersion, ?FUNCTION_NAME, State);
{Version, NewId, ConnectionStates, ProtoExt, Protocol} ->
ssl_connection:handle_session(Hello,
Version, NewId, ConnectionStates, ProtoExt, Protocol, State)
end;
hello(internal, {handshake, {#client_hello{cookie = <<>>} = Handshake, _}}, State) ->
%% Initial hello should not be in handshake history
- {next_state, hello, State, [{next_event, internal, Handshake}]};
+ {next_state, ?FUNCTION_NAME, State, [{next_event, internal, Handshake}]};
hello(internal, {handshake, {#hello_verify_request{} = Handshake, _}}, State) ->
%% hello_verify should not be in handshake history
- {next_state, hello, State, [{next_event, internal, Handshake}]};
+ {next_state, ?FUNCTION_NAME, State, [{next_event, internal, Handshake}]};
hello(info, Event, State) ->
- handle_info(Event, hello, State);
+ handle_info(Event, ?FUNCTION_NAME, State);
hello(state_timeout, Event, State) ->
- handle_state_timeout(Event, hello, State);
+ handle_state_timeout(Event, ?FUNCTION_NAME, State);
hello(Type, Event, State) ->
- ssl_connection:hello(Type, Event, State, ?MODULE).
+ ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE).
abbreviated(enter, _, State0) ->
{State, Actions} = handle_flight_timer(State0),
{keep_state, State, Actions};
abbreviated(info, Event, State) ->
- handle_info(Event, abbreviated, State);
+ handle_info(Event, ?FUNCTION_NAME, State);
abbreviated(internal = Type,
#change_cipher_spec{type = <<1>>} = Event,
#state{connection_states = ConnectionStates0} = State) ->
ConnectionStates1 = dtls_record:save_current_connection_state(ConnectionStates0, read),
ConnectionStates = dtls_record:next_epoch(ConnectionStates1, read),
- ssl_connection:abbreviated(Type, Event, State#state{connection_states = ConnectionStates}, ?MODULE);
+ ssl_connection:?FUNCTION_NAME(Type, Event, State#state{connection_states = ConnectionStates}, ?MODULE);
abbreviated(internal = Type, #finished{} = Event, #state{connection_states = ConnectionStates} = State) ->
- ssl_connection:abbreviated(Type, Event,
- prepare_flight(State#state{connection_states = ConnectionStates,
- flight_state = connection}), ?MODULE);
+ ssl_connection:?FUNCTION_NAME(Type, Event,
+ prepare_flight(State#state{connection_states = ConnectionStates,
+ flight_state = connection}), ?MODULE);
abbreviated(state_timeout, Event, State) ->
- handle_state_timeout(Event, abbreviated, State);
+ handle_state_timeout(Event, ?FUNCTION_NAME, State);
abbreviated(Type, Event, State) ->
- ssl_connection:abbreviated(Type, Event, State, ?MODULE).
+ ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE).
certify(enter, _, State0) ->
{State, Actions} = handle_flight_timer(State0),
{keep_state, State, Actions};
certify(info, Event, State) ->
- handle_info(Event, certify, State);
+ handle_info(Event, ?FUNCTION_NAME, State);
certify(internal = Type, #server_hello_done{} = Event, State) ->
ssl_connection:certify(Type, Event, prepare_flight(State), ?MODULE);
certify(state_timeout, Event, State) ->
- handle_state_timeout(Event, certify, State);
+ handle_state_timeout(Event, ?FUNCTION_NAME, State);
certify(Type, Event, State) ->
- ssl_connection:certify(Type, Event, State, ?MODULE).
+ ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE).
cipher(enter, _, State0) ->
{State, Actions} = handle_flight_timer(State0),
{keep_state, State, Actions};
cipher(info, Event, State) ->
- handle_info(Event, cipher, State);
+ handle_info(Event, ?FUNCTION_NAME, State);
cipher(internal = Type, #change_cipher_spec{type = <<1>>} = Event,
#state{connection_states = ConnectionStates0} = State) ->
ConnectionStates1 = dtls_record:save_current_connection_state(ConnectionStates0, read),
ConnectionStates = dtls_record:next_epoch(ConnectionStates1, read),
- ssl_connection:cipher(Type, Event, State#state{connection_states = ConnectionStates}, ?MODULE);
+ ssl_connection:?FUNCTION_NAME(Type, Event, State#state{connection_states = ConnectionStates}, ?MODULE);
cipher(internal = Type, #finished{} = Event, #state{connection_states = ConnectionStates} = State) ->
- ssl_connection:cipher(Type, Event,
- prepare_flight(State#state{connection_states = ConnectionStates,
- flight_state = connection}),
- ?MODULE);
+ ssl_connection:?FUNCTION_NAME(Type, Event,
+ prepare_flight(State#state{connection_states = ConnectionStates,
+ flight_state = connection}),
+ ?MODULE);
cipher(state_timeout, Event, State) ->
- handle_state_timeout(Event, cipher, State);
+ handle_state_timeout(Event, ?FUNCTION_NAME, State);
cipher(Type, Event, State) ->
- ssl_connection:cipher(Type, Event, State, ?MODULE).
+ ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE).
connection(enter, _, State) ->
{keep_state, State};
connection(info, Event, State) ->
- handle_info(Event, connection, State);
+ handle_info(Event, ?FUNCTION_NAME, State);
connection(internal, #hello_request{}, #state{host = Host, port = Port,
session = #session{own_certificate = Cert} = Session0,
session_cache = Cache, session_cache_cb = CacheCb,
@@ -476,15 +476,15 @@ connection(internal, #client_hello{}, #state{role = server, allow_renegotiate =
Alert = ?ALERT_REC(?WARNING, ?NO_RENEGOTIATION),
State1 = send_alert(Alert, State0),
{Record, State} = ssl_connection:prepare_connection(State1, ?MODULE),
- next_event(connection, Record, State);
+ next_event(?FUNCTION_NAME, Record, State);
connection(Type, Event, State) ->
- ssl_connection:connection(Type, Event, State, ?MODULE).
+ ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE).
%%TODO does this make sense for DTLS ?
downgrade(enter, _, State) ->
{keep_state, State};
downgrade(Type, Event, State) ->
- ssl_connection:downgrade(Type, Event, State, ?MODULE).
+ ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE).
%%--------------------------------------------------------------------
%% Description: This function is called by a gen_fsm when it receives any
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index b031d3d47b..c6f67eb696 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -366,7 +366,7 @@ init({call, From}, {start, {Opts, EmOpts}, Timeout},
{stop_and_reply, normal, {reply, From, {error, Error}}}
end;
init({call, From}, Msg, State, Connection) ->
- handle_call(Msg, From, init, State, Connection);
+ handle_call(Msg, From, ?FUNCTION_NAME, State, Connection);
init(_Type, _Event, _State, _Connection) ->
{keep_state_and_data, [postpone]}.
@@ -377,13 +377,13 @@ init(_Type, _Event, _State, _Connection) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
hello({call, From}, Msg, State, Connection) ->
- handle_call(Msg, From, hello, State, Connection);
+ handle_call(Msg, From, ?FUNCTION_NAME, State, Connection);
hello(internal, {common_client_hello, Type, ServerHelloExt}, State, Connection) ->
do_server_hello(Type, ServerHelloExt, State, Connection);
hello(info, Msg, State, _) ->
- handle_info(Msg, hello, State);
+ handle_info(Msg, ?FUNCTION_NAME, State);
hello(Type, Msg, State, Connection) ->
- handle_common_event(Type, Msg, hello, State, Connection).
+ handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
%%--------------------------------------------------------------------
-spec abbreviated(gen_statem:event_type(),
@@ -392,7 +392,7 @@ hello(Type, Msg, State, Connection) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
abbreviated({call, From}, Msg, State, Connection) ->
- handle_call(Msg, From, abbreviated, State, Connection);
+ handle_call(Msg, From, ?FUNCTION_NAME, State, Connection);
abbreviated(internal, #finished{verify_data = Data} = Finished,
#state{role = server,
@@ -412,7 +412,7 @@ abbreviated(internal, #finished{verify_data = Data} = Finished,
expecting_finished = false}, Connection),
Connection:next_event(connection, Record, State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, abbreviated, State0)
+ handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0)
end;
abbreviated(internal, #finished{verify_data = Data} = Finished,
@@ -428,11 +428,11 @@ abbreviated(internal, #finished{verify_data = Data} = Finished,
ssl_record:set_server_verify_data(current_read, Data, ConnectionStates0),
{State1, Actions} =
finalize_handshake(State0#state{connection_states = ConnectionStates1},
- abbreviated, Connection),
+ ?FUNCTION_NAME, Connection),
{Record, State} = prepare_connection(State1#state{expecting_finished = false}, Connection),
Connection:next_event(connection, Record, State, Actions);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, abbreviated, State0)
+ handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0)
end;
%% only allowed to send next_protocol message after change cipher spec
@@ -442,7 +442,7 @@ abbreviated(internal, #next_protocol{selected_protocol = SelectedProtocol},
Connection) ->
{Record, State} =
Connection:next_record(State0#state{negotiated_protocol = SelectedProtocol}),
- Connection:next_event(abbreviated, Record,
+ Connection:next_event(?FUNCTION_NAME, Record,
State#state{expecting_next_protocol_negotiation = false});
abbreviated(internal,
#change_cipher_spec{type = <<1>>}, #state{connection_states = ConnectionStates0} =
@@ -451,11 +451,11 @@ abbreviated(internal,
ssl_record:activate_pending_connection_state(ConnectionStates0, read),
{Record, State} = Connection:next_record(State0#state{connection_states =
ConnectionStates1}),
- Connection:next_event(abbreviated, Record, State#state{expecting_finished = true});
+ Connection:next_event(?FUNCTION_NAME, Record, State#state{expecting_finished = true});
abbreviated(info, Msg, State, _) ->
- handle_info(Msg, abbreviated, State);
+ handle_info(Msg, ?FUNCTION_NAME, State);
abbreviated(Type, Msg, State, Connection) ->
- handle_common_event(Type, Msg, abbreviated, State, Connection).
+ handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
%%--------------------------------------------------------------------
-spec certify(gen_statem:event_type(),
@@ -465,16 +465,16 @@ abbreviated(Type, Msg, State, Connection) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
certify({call, From}, Msg, State, Connection) ->
- handle_call(Msg, From, certify, State, Connection);
+ handle_call(Msg, From, ?FUNCTION_NAME, State, Connection);
certify(info, Msg, State, _) ->
- handle_info(Msg, certify, State);
+ handle_info(Msg, ?FUNCTION_NAME, State);
certify(internal, #certificate{asn1_certificates = []},
#state{role = server, negotiated_version = Version,
ssl_options = #ssl_options{verify = verify_peer,
fail_if_no_peer_cert = true}} =
State, _) ->
Alert = ?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE),
- handle_own_alert(Alert, Version, certify, State);
+ handle_own_alert(Alert, Version, ?FUNCTION_NAME, State);
certify(internal, #certificate{asn1_certificates = []},
#state{role = server,
@@ -483,7 +483,7 @@ certify(internal, #certificate{asn1_certificates = []},
State0, Connection) ->
{Record, State} =
Connection:next_record(State0#state{client_certificate_requested = false}),
- Connection:next_event(certify, Record, State);
+ Connection:next_event(?FUNCTION_NAME, Record, State);
certify(internal, #certificate{},
#state{role = server,
@@ -491,7 +491,7 @@ certify(internal, #certificate{},
ssl_options = #ssl_options{verify = verify_none}} =
State, _) ->
Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE, unrequested_certificate),
- handle_own_alert(Alert, Version, certify, State);
+ handle_own_alert(Alert, Version, ?FUNCTION_NAME, State);
certify(internal, #certificate{} = Cert,
#state{negotiated_version = Version,
@@ -506,7 +506,7 @@ certify(internal, #certificate{} = Cert,
handle_peer_cert(Role, PeerCert, PublicKeyInfo,
State#state{client_certificate_requested = false}, Connection);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify, State)
+ handle_own_alert(Alert, Version, ?FUNCTION_NAME, State)
end;
certify(internal, #server_key_exchange{exchange_keys = Keys},
@@ -538,7 +538,7 @@ certify(internal, #server_key_exchange{exchange_keys = Keys},
Connection);
false ->
handle_own_alert(?ALERT_REC(?FATAL, ?DECRYPT_ERROR),
- Version, certify, State)
+ Version, ?FUNCTION_NAME, State)
end
end;
@@ -549,10 +549,10 @@ certify(internal, #certificate_request{} = CertRequest,
negotiated_version = Version} = State0, Connection) ->
case ssl_handshake:select_hashsign(CertRequest, Cert, SupportedHashSigns, ssl:tls_version(Version)) of
#alert {} = Alert ->
- handle_own_alert(Alert, Version, certify, State0);
+ handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0);
NegotiatedHashSign ->
{Record, State} = Connection:next_record(State0#state{client_certificate_requested = true}),
- Connection:next_event(certify, Record,
+ Connection:next_event(?FUNCTION_NAME, Record,
State#state{cert_hashsign_algorithm = NegotiatedHashSign})
end;
@@ -568,7 +568,7 @@ certify(internal, #server_hello_done{},
when Alg == psk ->
case ssl_handshake:premaster_secret({Alg, PSKIdentity}, PSKLookup) of
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify, State0);
+ handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0);
PremasterSecret ->
State = master_secret(PremasterSecret,
State0#state{premaster_secret = PremasterSecret}),
@@ -589,7 +589,7 @@ certify(internal, #server_hello_done{},
case ssl_handshake:premaster_secret({Alg, PSKIdentity}, PSKLookup,
RSAPremasterSecret) of
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify, State0);
+ handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0);
PremasterSecret ->
State = master_secret(PremasterSecret,
State0#state{premaster_secret = RSAPremasterSecret}),
@@ -609,7 +609,7 @@ certify(internal, #server_hello_done{},
State = State0#state{connection_states = ConnectionStates},
client_certify_and_key_exchange(State, Connection);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify, State0)
+ handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0)
end;
%% Master secret is calculated from premaster_secret
@@ -627,7 +627,7 @@ certify(internal, #server_hello_done{},
session = Session},
client_certify_and_key_exchange(State, Connection);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify, State0)
+ handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0)
end;
certify(internal = Type, #client_key_exchange{} = Msg,
@@ -636,7 +636,7 @@ certify(internal = Type, #client_key_exchange{} = Msg,
ssl_options = #ssl_options{fail_if_no_peer_cert = true}} = State,
Connection) ->
%% We expect a certificate here
- handle_common_event(Type, Msg, certify, State, Connection);
+ handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection);
certify(internal, #client_key_exchange{exchange_keys = Keys},
State = #state{key_algorithm = KeyAlg, negotiated_version = Version}, Connection) ->
@@ -645,11 +645,11 @@ certify(internal, #client_key_exchange{exchange_keys = Keys},
State, Connection)
catch
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify, State)
+ handle_own_alert(Alert, Version, ?FUNCTION_NAME, State)
end;
certify(Type, Msg, State, Connection) ->
- handle_common_event(Type, Msg, certify, State, Connection).
+ handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
%%--------------------------------------------------------------------
-spec cipher(gen_statem:event_type(),
@@ -658,10 +658,10 @@ certify(Type, Msg, State, Connection) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
cipher({call, From}, Msg, State, Connection) ->
- handle_call(Msg, From, cipher, State, Connection);
+ handle_call(Msg, From, ?FUNCTION_NAME, State, Connection);
cipher(info, Msg, State, _) ->
- handle_info(Msg, cipher, State);
+ handle_info(Msg, ?FUNCTION_NAME, State);
cipher(internal, #certificate_verify{signature = Signature,
hashsign_algorithm = CertHashSign},
@@ -680,10 +680,10 @@ cipher(internal, #certificate_verify{signature = Signature,
TLSVersion, HashSign, MasterSecret, Handshake) of
valid ->
{Record, State} = Connection:next_record(State0),
- Connection:next_event(cipher, Record,
+ Connection:next_event(?FUNCTION_NAME, Record,
State#state{cert_hashsign_algorithm = HashSign});
#alert{} = Alert ->
- handle_own_alert(Alert, Version, cipher, State0)
+ handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0)
end;
%% client must send a next protocol message if we are expecting it
@@ -691,7 +691,7 @@ cipher(internal, #finished{},
#state{role = server, expecting_next_protocol_negotiation = true,
negotiated_protocol = undefined, negotiated_version = Version} = State0,
_Connection) ->
- handle_own_alert(?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE), Version, cipher, State0);
+ handle_own_alert(?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE), Version, ?FUNCTION_NAME, State0);
cipher(internal, #finished{verify_data = Data} = Finished,
#state{negotiated_version = Version,
@@ -712,7 +712,7 @@ cipher(internal, #finished{verify_data = Data} = Finished,
cipher_role(Role, Data, Session,
State#state{expecting_finished = false}, Connection);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, cipher, State)
+ handle_own_alert(Alert, Version, ?FUNCTION_NAME, State)
end;
%% only allowed to send next_protocol message after change cipher spec
@@ -722,7 +722,7 @@ cipher(internal, #next_protocol{selected_protocol = SelectedProtocol},
expecting_finished = true} = State0, Connection) ->
{Record, State} =
Connection:next_record(State0#state{negotiated_protocol = SelectedProtocol}),
- Connection:next_event(cipher, Record,
+ Connection:next_event(?FUNCTION_NAME, Record,
State#state{expecting_next_protocol_negotiation = false});
cipher(internal, #change_cipher_spec{type = <<1>>}, #state{connection_states = ConnectionStates0} =
State0, Connection) ->
@@ -730,9 +730,9 @@ cipher(internal, #change_cipher_spec{type = <<1>>}, #state{connection_states =
ssl_record:activate_pending_connection_state(ConnectionStates0, read),
{Record, State} = Connection:next_record(State0#state{connection_states =
ConnectionStates1}),
- Connection:next_event(cipher, Record, State#state{expecting_finished = true});
+ Connection:next_event(?FUNCTION_NAME, Record, State#state{expecting_finished = true});
cipher(Type, Msg, State, Connection) ->
- handle_common_event(Type, Msg, cipher, State, Connection).
+ handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
%%--------------------------------------------------------------------
-spec connection(gen_statem:event_type(), term(),
@@ -747,7 +747,7 @@ connection({call, From}, {application_data, Data},
try
write_application_data(Data, From, State)
catch throw:Error ->
- hibernate_after(connection, State, [{reply, From, Error}])
+ hibernate_after(?FUNCTION_NAME, State, [{reply, From, Error}])
end;
connection({call, RecvFrom}, {recv, N, Timeout},
#state{protocol_cb = Connection, socket_options =
@@ -755,34 +755,34 @@ connection({call, RecvFrom}, {recv, N, Timeout},
Timer = start_or_recv_cancel_timer(Timeout, RecvFrom),
Connection:passive_receive(State0#state{bytes_to_read = N,
start_or_recv_from = RecvFrom,
- timer = Timer}, connection);
+ timer = Timer}, ?FUNCTION_NAME);
connection({call, From}, renegotiate, #state{protocol_cb = Connection} = State,
Connection) ->
Connection:renegotiate(State#state{renegotiation = {true, From}}, []);
connection({call, From}, peer_certificate,
#state{session = #session{peer_certificate = Cert}} = State, _) ->
- hibernate_after(connection, State, [{reply, From, {ok, Cert}}]);
+ hibernate_after(?FUNCTION_NAME, State, [{reply, From, {ok, Cert}}]);
connection({call, From}, {connection_information, true}, State, _) ->
Info = connection_info(State) ++ security_info(State),
- hibernate_after(connection, State, [{reply, From, {ok, Info}}]);
+ hibernate_after(?FUNCTION_NAME, State, [{reply, From, {ok, Info}}]);
connection({call, From}, {connection_information, false}, State, _) ->
Info = connection_info(State),
- hibernate_after(connection, State, [{reply, From, {ok, Info}}]);
+ hibernate_after(?FUNCTION_NAME, State, [{reply, From, {ok, Info}}]);
connection({call, From}, negotiated_protocol,
#state{negotiated_protocol = undefined} = State, _) ->
- hibernate_after(connection, State, [{reply, From, {error, protocol_not_negotiated}}]);
+ hibernate_after(?FUNCTION_NAME, State, [{reply, From, {error, protocol_not_negotiated}}]);
connection({call, From}, negotiated_protocol,
#state{negotiated_protocol = SelectedProtocol} = State, _) ->
- hibernate_after(connection, State,
+ hibernate_after(?FUNCTION_NAME, State,
[{reply, From, {ok, SelectedProtocol}}]);
connection({call, From}, Msg, State, Connection) ->
- handle_call(Msg, From, connection, State, Connection);
+ handle_call(Msg, From, ?FUNCTION_NAME, State, Connection);
connection(info, Msg, State, _) ->
- handle_info(Msg, connection, State);
+ handle_info(Msg, ?FUNCTION_NAME, State);
connection(internal, {recv, _}, State, Connection) ->
- Connection:passive_receive(State, connection);
+ Connection:passive_receive(State, ?FUNCTION_NAME);
connection(Type, Msg, State, Connection) ->
- handle_common_event(Type, Msg, connection, State, Connection).
+ handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
%%--------------------------------------------------------------------
-spec downgrade(gen_statem:event_type(), term(),
@@ -800,7 +800,7 @@ downgrade(timeout, downgrade, #state{downgrade = {_, From}} = State, _) ->
gen_statem:reply(From, {error, timeout}),
{stop, normal, State};
downgrade(Type, Event, State, Connection) ->
- handle_common_event(Type, Event, downgrade, State, Connection).
+ handle_common_event(Type, Event, ?FUNCTION_NAME, State, Connection).
%%--------------------------------------------------------------------
%% Event handling functions called by state functions to handle
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index e3ffbea3d3..ed86478008 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -241,7 +241,7 @@ init({call, From}, {start, Timeout},
{Record, State} = next_record(State1),
next_event(hello, Record, State);
init(Type, Event, State) ->
- gen_handshake(ssl_connection, init, Type, Event, State).
+ gen_handshake(ssl_connection, ?FUNCTION_NAME, Type, Event, State).
%%--------------------------------------------------------------------
-spec error(gen_statem:event_type(),
@@ -252,7 +252,7 @@ init(Type, Event, State) ->
error({call, From}, {start, _Timeout}, {Error, State}) ->
{stop_and_reply, normal, {reply, From, {error, Error}}, State};
error({call, From}, Msg, State) ->
- handle_call(Msg, From, error, State);
+ handle_call(Msg, From, ?FUNCTION_NAME, State);
error(_, _, _) ->
{keep_state_and_data, [postpone]}.
@@ -304,36 +304,36 @@ hello(internal, #server_hello{} = Hello,
Version, NewId, ConnectionStates, ProtoExt, Protocol, State)
end;
hello(info, Event, State) ->
- gen_info(Event, hello, State);
+ gen_info(Event, ?FUNCTION_NAME, State);
hello(Type, Event, State) ->
- gen_handshake(ssl_connection, hello, Type, Event, State).
+ gen_handshake(ssl_connection, ?FUNCTION_NAME, Type, Event, State).
%%--------------------------------------------------------------------
-spec abbreviated(gen_statem:event_type(), term(), #state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
abbreviated(info, Event, State) ->
- gen_info(Event, abbreviated, State);
+ gen_info(Event, ?FUNCTION_NAME, State);
abbreviated(Type, Event, State) ->
- gen_handshake(ssl_connection, abbreviated, Type, Event, State).
+ gen_handshake(ssl_connection, ?FUNCTION_NAME, Type, Event, State).
%%--------------------------------------------------------------------
-spec certify(gen_statem:event_type(), term(), #state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
certify(info, Event, State) ->
- gen_info(Event, certify, State);
+ gen_info(Event, ?FUNCTION_NAME, State);
certify(Type, Event, State) ->
- gen_handshake(ssl_connection, certify, Type, Event, State).
+ gen_handshake(ssl_connection, ?FUNCTION_NAME, Type, Event, State).
%%--------------------------------------------------------------------
-spec cipher(gen_statem:event_type(), term(), #state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
cipher(info, Event, State) ->
- gen_info(Event, cipher, State);
+ gen_info(Event, ?FUNCTION_NAME, State);
cipher(Type, Event, State) ->
- gen_handshake(ssl_connection, cipher, Type, Event, State).
+ gen_handshake(ssl_connection, ?FUNCTION_NAME, Type, Event, State).
%%--------------------------------------------------------------------
-spec connection(gen_statem:event_type(),
@@ -341,7 +341,7 @@ cipher(Type, Event, State) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
connection(info, Event, State) ->
- gen_info(Event, connection, State);
+ gen_info(Event, ?FUNCTION_NAME, State);
connection(internal, #hello_request{},
#state{role = client, host = Host, port = Port,
session = #session{own_certificate = Cert} = Session0,
@@ -373,16 +373,16 @@ connection(internal, #client_hello{},
Alert = ?ALERT_REC(?WARNING, ?NO_RENEGOTIATION),
State1 = send_alert(Alert, State0),
{Record, State} = ssl_connection:prepare_connection(State1, ?MODULE),
- next_event(connection, Record, State);
+ next_event(?FUNCTION_NAME, Record, State);
connection(Type, Event, State) ->
- ssl_connection:connection(Type, Event, State, ?MODULE).
+ ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE).
%%--------------------------------------------------------------------
-spec downgrade(gen_statem:event_type(), term(), #state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
downgrade(Type, Event, State) ->
- ssl_connection:downgrade(Type, Event, State, ?MODULE).
+ ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE).
%%--------------------------------------------------------------------
%% Event handling functions called by state functions to handle
--
cgit v1.2.3
From 48faad936ff6189daf9c0af7b39a86400057cb13 Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin
Date: Fri, 6 Oct 2017 17:15:52 +0200
Subject: public_key, ssl: Handles keys so that APIs are preserved correctly
---
lib/public_key/src/pubkey_cert.erl | 13 ++++++++++---
lib/ssl/test/x509_test.erl | 15 ++++++---------
2 files changed, 16 insertions(+), 12 deletions(-)
(limited to 'lib')
diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl
index 13833830a7..76fd0f8133 100644
--- a/lib/public_key/src/pubkey_cert.erl
+++ b/lib/public_key/src/pubkey_cert.erl
@@ -1144,7 +1144,7 @@ issuer(Contact, Role, Name) ->
subject(Contact, Role ++ Name).
subject(Contact, Name) ->
- Opts = [{email, Contact ++ "@erlang.org"},
+ Opts = [{email, Contact ++ "@example.org"},
{name, Name},
{city, "Stockholm"},
{country, "SE"},
@@ -1223,12 +1223,12 @@ cert_chain(Role, IssuerCert, IssuerKey, [PeerOpts], _, Acc) ->
Key = gen_key(proplists:get_value(key, PeerOpts, default_key_gen())),
Cert = cert(Role, public_key:pkix_decode_cert(IssuerCert, otp),
IssuerKey, Key, "admin", " Peer cert", PeerOpts, peer),
- [{Cert, Key}, {IssuerCert, IssuerKey} | Acc];
+ [{Cert, encode_key(Key)}, {IssuerCert, encode_key(IssuerKey)} | Acc];
cert_chain(Role, IssuerCert, IssuerKey, [CAOpts | Rest], N, Acc) ->
Key = gen_key(proplists:get_value(key, CAOpts, default_key_gen())),
Cert = cert(Role, public_key:pkix_decode_cert(IssuerCert, otp), IssuerKey, Key, "webadmin",
" Intermidiate CA " ++ integer_to_list(N), CAOpts, ca),
- cert_chain(Role, Cert, Key, Rest, N+1, [{IssuerCert, IssuerKey} | Acc]).
+ cert_chain(Role, Cert, Key, Rest, N+1, [{IssuerCert, encode_key(IssuerKey)} | Acc]).
cert(Role, #'OTPCertificate'{tbsCertificate = #'OTPTBSCertificate'{subject = Issuer}},
PrivKey, Key, Contact, Name, Opts, Type) ->
@@ -1311,3 +1311,10 @@ add_default_extensions(Defaults0, Exts) ->
end, Defaults0),
Exts ++ Defaults.
+encode_key(#'RSAPrivateKey'{} = Key) ->
+ {'RSAPrivateKey', public_key:der_encode('RSAPrivateKey', Key)};
+encode_key(#'ECPrivateKey'{} = Key) ->
+ {'ECPrivateKey', public_key:der_encode('ECPrivateKey', Key)};
+encode_key(#'DSAPrivateKey'{} = Key) ->
+ {'DSAPrivateKey', public_key:der_encode('DSAPrivateKey', Key)}.
+
diff --git a/lib/ssl/test/x509_test.erl b/lib/ssl/test/x509_test.erl
index 031fad1216..fea01efdaf 100644
--- a/lib/ssl/test/x509_test.erl
+++ b/lib/ssl/test/x509_test.erl
@@ -64,15 +64,12 @@ do_gen_pem_config_files(Config, CertFile, KeyFile, CAFile) ->
cert_entry(Cert) ->
{'Certificate', Cert, not_encrypted}.
-key_entry(Key = #'RSAPrivateKey'{}) ->
- Der = public_key:der_encode('RSAPrivateKey', Key),
- {'RSAPrivateKey', Der, not_encrypted};
-key_entry(Key = #'DSAPrivateKey'{}) ->
- Der = public_key:der_encode('DSAPrivateKey', Key),
- {'DSAPrivateKey', Der, not_encrypted};
-key_entry(Key = #'ECPrivateKey'{}) ->
- Der = public_key:der_encode('ECPrivateKey', Key),
- {'ECPrivateKey', Der, not_encrypted}.
+key_entry({'RSAPrivateKey', DERKey}) ->
+ {'RSAPrivateKey', DERKey, not_encrypted};
+key_entry({'DSAPrivateKey', DERKey}) ->
+ {'DSAPrivateKey', DERKey, not_encrypted};
+key_entry({'ECPrivateKey', DERKey}) ->
+ {'ECPrivateKey', DERKey, not_encrypted}.
ca_entries(CAs) ->
[{'Certificate', CACert, not_encrypted} || CACert <- CAs].
--
cgit v1.2.3
From 3da1637b5ec4f24787d473fa3031bed44958136e Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin
Date: Fri, 6 Oct 2017 17:24:16 +0200
Subject: ssl: Extend hostname check to fallback to checking IP-address
If no SNI is available and the hostname is an IP-address also check
for IP-address match. This check is not as good as a DNS hostname check
and certificates using IP-address are not recommended.
---
lib/ssl/doc/src/ssl.xml | 52 ++++++++++++++-------
lib/ssl/src/ssl.erl | 2 +-
lib/ssl/src/ssl_certificate.erl | 38 ++++++++++++---
lib/ssl/src/ssl_connection.erl | 3 +-
lib/ssl/src/ssl_handshake.erl | 18 ++++++--
lib/ssl/test/ssl_sni_SUITE.erl | 100 +++++++++++++++++++++++++++++++++++++++-
6 files changed, 182 insertions(+), 31 deletions(-)
(limited to 'lib')
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index ca2dcbb761..e80fd59a7f 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -589,22 +589,19 @@ fun(srp, Username :: string(), UserState :: term()) ->
{server_name_indication, HostName :: hostname()}
Specify the hostname to be used in TLS Server Name Indication extension.
- Is usefull when upgrading a TCP socket to a TLS socket or if the hostname can not be
- derived from the Host argument to ssl:connect/3.
- Will also cause the client to preform host name verification of the peer certificate
- public_key:pkix_verify_hostname(PeerCert, [{dns_id, HostName}])
-
during the x509-path validation. If the check fails the error {bad_cert, hostname_check_failiure} will be
- propagated to the path validation fun verify_fun
-
-
- {server_name_indication, disable}
- -
-
When starting a TLS connection without upgrade, the Server Name
- Indication extension is sent if possible that is can be derived from the Host argument
- to ssl:connect/3.
- This option can be used to disable that behavior.
- Note that this also disables the default host name verification check of the peer certificate.
+ If not specified it will default to the Host argument of connect/[3,4]
+ unless it is of type inet:ipaddress().
+
+ The HostName will also be used in the hostname verification of the peer certificate using
+ public_key:pkix_verify_hostname/2.
+
+ {server_name_indication, disable}
+ -
+
Prevents the Server Name Indication extension from being sent and
+ disables the hostname verification check
+ public_key:pkix_verify_hostname/2
+
{fallback, boolean()}
-
Send special cipher suite TLS_FALLBACK_SCSV to avoid undesired TLS version downgrade.
@@ -881,6 +878,12 @@ fun(srp, Username :: string(), UserState :: term()) ->
Upgrades a gen_tcp, or equivalent,
connected socket to an SSL socket, that is, performs the
client-side ssl handshake.
+
+ If the option verify is set to verify_peer
+ the option server_name_indication shall also be specified,
+ if it is not no Server Name Indication extension will be sent,
+ and public_key:pkix_verify_hostname/2
+ will be called with the IP-address of the connection as ReferenceID, which is proably not what you want.
@@ -897,7 +900,24 @@ fun(srp, Username :: string(), UserState :: term()) ->
SslSocket = sslsocket()
Reason = term()
- Opens an SSL connection to Host, Port.
+ Opens an SSL connection to Host, Port.
+
+ When the option verify is set to verify_peer the check
+ public_key:pkix_verify_hostname/2
+ will be performed in addition to the usual x509-path validation checks. If the check fails the error {bad_cert, hostname_check_failed} will
+ be propagated to the path validation fun verify_fun, where it is possible to do customized
+ checks by using the full possibilitis of the public_key:pkix_verify_hostname/2 API.
+
+ When the option server_name_indication is provided, its value (the DNS name) will be used as ReferenceID
+ to public_key:pkix_verify_hostname/2.
+ When no server_name_indication option is given, the Host argument will be used as
+ Server Name Indication extension. The Host argument will also be used for the
+ public_key:pkix_verify_hostname/2 check and if the Host
+ argument is an inet:ip_address() the ReferenceID used for the check will be {ip, Host} otherwise
+ dns_id will be assumed with a fallback to ip if that fails.
+ According to good practices certificates should not use IP-addresses as "server names". It would
+ be very surprising if this happen outside a closed network.
+
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 4e592c02ec..054e3b7ae3 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -1003,7 +1003,7 @@ validate_option(server_name_indication = Opt, Value) when is_list(Value) ->
validate_option(server_name_indication, undefined = Value) ->
Value;
validate_option(server_name_indication, disable) ->
- undefined;
+ disable;
validate_option(sni_hosts, []) ->
[];
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 0dd5e5c5cf..a3333d35e9 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -138,13 +138,8 @@ validate(_, {bad_cert, _} = Reason, _) ->
{fail, Reason};
validate(_, valid, UserState) ->
{valid, UserState};
-validate(Cert, valid_peer, UserState = {client, _,_, Hostname, _, _}) when Hostname =/= undefined ->
- case public_key:pkix_verify_hostname(Cert, [{dns_id, Hostname}]) of
- true ->
- {valid, UserState};
- false ->
- {fail, {bad_cert, hostname_check_failed}}
- end;
+validate(Cert, valid_peer, UserState = {client, _,_, Hostname, _, _}) when Hostname =/= disable ->
+ verify_hostname(Hostname, Cert, UserState);
validate(_, valid_peer, UserState) ->
{valid, UserState}.
@@ -337,3 +332,32 @@ new_trusteded_chain(DerCert, [_ | Rest]) ->
new_trusteded_chain(DerCert, Rest);
new_trusteded_chain(_, []) ->
unknown_ca.
+
+verify_hostname({fallback, Hostname}, Cert, UserState) when is_list(Hostname) ->
+ case public_key:pkix_verify_hostname(Cert, [{dns_id, Hostname}]) of
+ true ->
+ {valid, UserState};
+ false ->
+ case public_key:pkix_verify_hostname(Cert, [{ip, Hostname}]) of
+ true ->
+ {valid, UserState};
+ false ->
+ {fail, {bad_cert, hostname_check_failed}}
+ end
+ end;
+
+verify_hostname({fallback, Hostname}, Cert, UserState) ->
+ case public_key:pkix_verify_hostname(Cert, [{ip, Hostname}]) of
+ true ->
+ {valid, UserState};
+ false ->
+ {fail, {bad_cert, hostname_check_failed}}
+ end;
+
+verify_hostname(Hostname, Cert, UserState) ->
+ case public_key:pkix_verify_hostname(Cert, [{dns_id, Hostname}]) of
+ true ->
+ {valid, UserState};
+ false ->
+ {fail, {bad_cert, hostname_check_failed}}
+ end.
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index c6f67eb696..099b5f8ffa 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -496,12 +496,13 @@ certify(internal, #certificate{},
certify(internal, #certificate{} = Cert,
#state{negotiated_version = Version,
role = Role,
+ host = Host,
cert_db = CertDbHandle,
cert_db_ref = CertDbRef,
crl_db = CRLDbInfo,
ssl_options = Opts} = State, Connection) ->
case ssl_handshake:certify(Cert, CertDbHandle, CertDbRef,
- Opts, CRLDbInfo, Role) of
+ Opts, CRLDbInfo, Role, Host) of
{PeerCert, PublicKeyInfo} ->
handle_peer_cert(Role, PeerCert, PublicKeyInfo,
State#state{client_certificate_requested = false}, Connection);
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index b1661624b5..0ee9ee3322 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -50,7 +50,7 @@
finished/5, next_protocol/1]).
%% Handle handshake messages
--export([certify/6, client_certificate_verify/6, certificate_verify/6, verify_signature/5,
+-export([certify/7, client_certificate_verify/6, certificate_verify/6, verify_signature/5,
master_secret/4, server_key_exchange_hash/2, verify_connection/6,
init_handshake_history/0, update_handshake_history/3, verify_server_key/5
]).
@@ -389,21 +389,21 @@ verify_signature(_, Hash, {HashAlgo, _SignAlg}, Signature,
%%--------------------------------------------------------------------
-spec certify(#certificate{}, db_handle(), certdb_ref(), #ssl_options{}, term(),
- client | server) -> {der_cert(), public_key_info()} | #alert{}.
+ client | server, inet:hostname() | inet:ip_address()) -> {der_cert(), public_key_info()} | #alert{}.
%%
%% Description: Handles a certificate handshake message
%%--------------------------------------------------------------------
certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef,
- Opts, CRLDbHandle, Role) ->
+ Opts, CRLDbHandle, Role, Host) ->
+ ServerName = server_name(Opts#ssl_options.server_name_indication, Host, Role),
[PeerCert | _] = ASN1Certs,
try
{TrustedCert, CertPath} =
ssl_certificate:trusted_cert_and_path(ASN1Certs, CertDbHandle, CertDbRef,
Opts#ssl_options.partial_chain),
ValidationFunAndState = validation_fun_and_state(Opts#ssl_options.verify_fun, Role,
- CertDbHandle, CertDbRef,
- Opts#ssl_options.server_name_indication,
+ CertDbHandle, CertDbRef, ServerName,
Opts#ssl_options.crl_check, CRLDbHandle, CertPath),
case public_key:pkix_path_validation(TrustedCert,
CertPath,
@@ -1528,6 +1528,8 @@ select_shared_curve([Curve | Rest], Curves) ->
sni(undefined) ->
undefined;
+sni(disable) ->
+ undefined;
sni(Hostname) ->
#sni{hostname = Hostname}.
@@ -2353,3 +2355,9 @@ available_signature_algs(#hash_sign_algos{hash_sign_algos = ClientHashSigns}, Su
available_signature_algs(_, _, _, _) ->
undefined.
+server_name(_, _, server) ->
+ undefined; %% Not interesting to check your own name.
+server_name(undefined, Host, client) ->
+ {fallback, Host}; %% Fallback to Host argument to connect
+server_name(SNI, _, client) ->
+ SNI. %% If Server Name Indication is available
diff --git a/lib/ssl/test/ssl_sni_SUITE.erl b/lib/ssl/test/ssl_sni_SUITE.erl
index 03676cb828..e080de95f6 100644
--- a/lib/ssl/test/ssl_sni_SUITE.erl
+++ b/lib/ssl/test/ssl_sni_SUITE.erl
@@ -25,6 +25,8 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("public_key/include/public_key.hrl").
+-include_lib("kernel/include/inet.hrl").
+
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
@@ -55,7 +57,10 @@ sni_tests() ->
sni_no_match,
no_sni_header_fun,
sni_match_fun,
- sni_no_match_fun].
+ sni_no_match_fun,
+ dns_name,
+ ip_fallback,
+ no_ip_fallback].
init_per_suite(Config0) ->
catch crypto:stop(),
@@ -112,6 +117,65 @@ sni_no_match(Config) ->
sni_no_match_fun(Config) ->
run_sni_fun_handshake(Config, "c.server", undefined, "server Peer cert").
+dns_name(Config) ->
+ Hostname = "OTP.test.server",
+ #{server_config := ServerConf,
+ client_config := ClientConf} = public_key:pkix_test_data(#{server_chain =>
+ #{root => [],
+ intermediates => [[]],
+ peer => [{extensions, [#'Extension'{extnID =
+ ?'id-ce-subjectAltName',
+ extnValue = [{dNSName, Hostname}],
+ critical = false}]}]},
+ client_chain =>
+ #{root => [],
+ intermediates => [[]],
+ peer => []}}),
+ unsuccessfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], undefined, Config),
+ successfull_connect(ServerConf, [{verify, verify_peer}, {server_name_indication, Hostname} | ClientConf], undefined, Config),
+ unsuccessfull_connect(ServerConf, [{verify, verify_peer}, {server_name_indication, "foo"} | ClientConf], undefined, Config),
+ successfull_connect(ServerConf, [{verify, verify_peer}, {server_name_indication, disable} | ClientConf], undefined, Config).
+
+ip_fallback(Config) ->
+ Hostname = net_adm:localhost(),
+ {ok, #hostent{h_addr_list = [IP |_]}} = inet:gethostbyname(net_adm:localhost()),
+ IPStr = tuple_to_list(IP),
+ #{server_config := ServerConf,
+ client_config := ClientConf} = public_key:pkix_test_data(#{server_chain =>
+ #{root => [],
+ intermediates => [[]],
+ peer => [{extensions, [#'Extension'{extnID =
+ ?'id-ce-subjectAltName',
+ extnValue = [{dNSName, Hostname},
+ {iPAddress, IPStr}],
+ critical = false}]}
+ ]},
+ client_chain =>
+ #{root => [],
+ intermediates => [[]],
+ peer => []}}),
+ successfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], Hostname, Config),
+ successfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], IP, Config).
+
+no_ip_fallback(Config) ->
+ Hostname = net_adm:localhost(),
+ {ok, #hostent{h_addr_list = [IP |_]}} = inet:gethostbyname(net_adm:localhost()),
+ #{server_config := ServerConf,
+ client_config := ClientConf} = public_key:pkix_test_data(#{server_chain =>
+ #{root => [],
+ intermediates => [[]],
+ peer => [{extensions, [#'Extension'{extnID =
+ ?'id-ce-subjectAltName',
+ extnValue = [{dNSName, Hostname}],
+ critical = false}]}
+ ]},
+ client_chain =>
+ #{root => [],
+ intermediates => [[]],
+ peer => []}}),
+ successfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], Hostname, Config),
+ unsuccessfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], IP, Config).
+
%%--------------------------------------------------------------------
%% Internal Functions ------------------------------------------------
@@ -217,3 +281,37 @@ run_handshake(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) ->
ssl_test_lib:check_result(Server, ExpectedSNIHostname, Client, ExpectedCN),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+
+successfull_connect(ServerOptions, ClientOptions, Hostname0, Config) ->
+ {ClientNode, ServerNode, Hostname1} = ssl_test_lib:run_where(Config),
+ Hostname = host_name(Hostname0, Hostname1),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOptions}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname}, {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOptions}]),
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+unsuccessfull_connect(ServerOptions, ClientOptions, Hostname0, Config) ->
+ {ClientNode, ServerNode, Hostname1} = ssl_test_lib:run_where(Config),
+ Hostname = host_name(Hostname0, Hostname1),
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, ServerOptions}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options, ClientOptions}]),
+
+ ssl_test_lib:check_result(Server, {error, {tls_alert, "handshake failure"}},
+ Client, {error, {tls_alert, "handshake failure"}}).
+host_name(undefined, Hostname) ->
+ Hostname;
+host_name(Hostname, _) ->
+ Hostname.
--
cgit v1.2.3
From 138e63eb7eb2248ff3821d6dda4a64b0479b480c Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin
Date: Fri, 6 Oct 2017 17:26:43 +0200
Subject: ssl: Sessions must be registered with SNI if exists
---
lib/ssl/src/ssl_connection.erl | 8 +++++-
lib/ssl/test/ssl_sni_SUITE.erl | 62 ++++++++++++++++++++++++++++++++++++++++--
2 files changed, 67 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 099b5f8ffa..31e7738b4d 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -702,6 +702,7 @@ cipher(internal, #finished{verify_data = Data} = Finished,
expecting_finished = true,
session = #session{master_secret = MasterSecret}
= Session0,
+ ssl_options = SslOpts,
connection_states = ConnectionStates0,
tls_handshake_history = Handshake0} = State, Connection) ->
case ssl_handshake:verify_connection(ssl:tls_version(Version), Finished,
@@ -709,7 +710,7 @@ cipher(internal, #finished{verify_data = Data} = Finished,
get_current_prf(ConnectionStates0, read),
MasterSecret, Handshake0) of
verified ->
- Session = register_session(Role, Host, Port, Session0),
+ Session = register_session(Role, host_id(Role, Host, SslOpts), Port, Session0),
cipher_role(Role, Data, Session,
State#state{expecting_finished = false}, Connection);
#alert{} = Alert ->
@@ -2097,6 +2098,11 @@ register_session(server, _, Port, #session{is_resumable = new} = Session0) ->
register_session(_, _, _, Session) ->
Session. %% Already registered
+host_id(client, _Host, #ssl_options{server_name_indication = Hostname}) when is_list(Hostname) ->
+ Hostname;
+host_id(_, Host, _) ->
+ Host.
+
handle_new_session(NewId, CipherSuite, Compression,
#state{session = Session0,
protocol_cb = Connection} = State0) ->
diff --git a/lib/ssl/test/ssl_sni_SUITE.erl b/lib/ssl/test/ssl_sni_SUITE.erl
index e080de95f6..13cb567110 100644
--- a/lib/ssl/test/ssl_sni_SUITE.erl
+++ b/lib/ssl/test/ssl_sni_SUITE.erl
@@ -60,7 +60,8 @@ sni_tests() ->
sni_no_match_fun,
dns_name,
ip_fallback,
- no_ip_fallback].
+ no_ip_fallback,
+ dns_name_reuse].
init_per_suite(Config0) ->
catch crypto:stop(),
@@ -87,6 +88,13 @@ end_per_suite(_) ->
ssl:stop(),
application:stop(crypto).
+init_per_testcase(TestCase, Config) when TestCase == ip_fallback;
+ TestCase == no_ip_fallback;
+ TestCase == dns_name_reuse ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:log("Ciphers: ~p~n ", [ ssl:cipher_suites()]),
+ ct:timetrap({seconds, 20}),
+ Config;
init_per_testcase(_TestCase, Config) ->
ssl_test_lib:ct_log_supported_protocol_versions(Config),
ct:log("Ciphers: ~p~n ", [ ssl:cipher_suites()]),
@@ -176,7 +184,57 @@ no_ip_fallback(Config) ->
successfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], Hostname, Config),
unsuccessfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], IP, Config).
-
+dns_name_reuse(Config) ->
+ SNIHostname = "OTP.test.server",
+ #{server_config := ServerConf,
+ client_config := ClientConf} = public_key:pkix_test_data(#{server_chain =>
+ #{root => [],
+ intermediates => [[]],
+ peer => [{extensions, [#'Extension'{extnID =
+ ?'id-ce-subjectAltName',
+ extnValue = [{dNSName, SNIHostname}],
+ critical = false}]}]},
+ client_chain =>
+ #{root => [],
+ intermediates => [[]],
+ peer => []}}),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ unsuccessfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], undefined, Config),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, session_info_result, []}},
+ {options, ServerConf}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client0 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {from, self()}, {options, [{verify, verify_peer},
+ {server_name_indication, SNIHostname} | ClientConf]}]),
+ SessionInfo =
+ receive
+ {Server, Info} ->
+ Info
+ end,
+
+ Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
+
+ %% Make sure session is registered
+ ct:sleep(1000),
+
+ Client1 =
+ ssl_test_lib:start_client_error([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_info_result, []}},
+ {from, self()}, {options, [{verify, verify_peer} | ClientConf]}]),
+
+ ssl_test_lib:check_result(Server, {error, {tls_alert, "handshake failure"}},
+ Client1, {error, {tls_alert, "handshake failure"}}),
+ ssl_test_lib:close(Client0).
%%--------------------------------------------------------------------
%% Internal Functions ------------------------------------------------
%%--------------------------------------------------------------------
--
cgit v1.2.3
From d55f38f1d7804ffe6e9b7f7f7ee1a4d6690179ab Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin
Date: Tue, 10 Oct 2017 18:54:52 +0200
Subject: public_key: Fix dialyzer spec
---
lib/public_key/src/public_key.erl | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index cc01b61433..c1ad72b585 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -850,10 +850,10 @@ pkix_crls_validate(OtpCert, DPAndCRLs0, Options) ->
%--------------------------------------------------------------------
-spec pkix_verify_hostname(Cert :: #'OTPCertificate'{} | binary(),
- ReferenceIDs :: [{uri_id | dns_id | oid(), string()}]) -> boolean().
+ ReferenceIDs :: [{uri_id | dns_id | ip | srv_id | oid(), string()}]) -> boolean().
-spec pkix_verify_hostname(Cert :: #'OTPCertificate'{} | binary(),
- ReferenceIDs :: [{uri_id | dns_id | oid(), string()}],
+ ReferenceIDs :: [{uri_id | dns_id | ip | srv_id | oid(), string()}],
Options :: proplists:proplist()) -> boolean().
%% Description: Validates a hostname to RFC 6125
--
cgit v1.2.3
From 410d4b61d9fbd040b962c115f312f1e7080c5561 Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin
Date: Mon, 16 Oct 2017 11:17:53 +0200
Subject: ssl: Fix test cases to work on all test platforms
Use hradcoded rsa keys as this will work on all legacy platforms.
In test case dns_name_reuse only do the relevant client check in the
final test.
---
lib/ssl/test/ssl_sni_SUITE.erl | 73 ++++++++++++++++++++++--------------------
1 file changed, 38 insertions(+), 35 deletions(-)
(limited to 'lib')
diff --git a/lib/ssl/test/ssl_sni_SUITE.erl b/lib/ssl/test/ssl_sni_SUITE.erl
index 13cb567110..7e78c41444 100644
--- a/lib/ssl/test/ssl_sni_SUITE.erl
+++ b/lib/ssl/test/ssl_sni_SUITE.erl
@@ -129,75 +129,80 @@ dns_name(Config) ->
Hostname = "OTP.test.server",
#{server_config := ServerConf,
client_config := ClientConf} = public_key:pkix_test_data(#{server_chain =>
- #{root => [],
- intermediates => [[]],
+ #{root => [{key, ssl_test_lib:hardcode_rsa_key(1)}],
+ intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(2)}]],
peer => [{extensions, [#'Extension'{extnID =
?'id-ce-subjectAltName',
extnValue = [{dNSName, Hostname}],
- critical = false}]}]},
+ critical = false}]},
+ {key, ssl_test_lib:hardcode_rsa_key(3)}]},
client_chain =>
- #{root => [],
- intermediates => [[]],
- peer => []}}),
+ #{root => [{key, ssl_test_lib:hardcode_rsa_key(4)}],
+ intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(5)}]],
+ peer => [{key, ssl_test_lib:hardcode_rsa_key(6)}]}}),
unsuccessfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], undefined, Config),
successfull_connect(ServerConf, [{verify, verify_peer}, {server_name_indication, Hostname} | ClientConf], undefined, Config),
unsuccessfull_connect(ServerConf, [{verify, verify_peer}, {server_name_indication, "foo"} | ClientConf], undefined, Config),
successfull_connect(ServerConf, [{verify, verify_peer}, {server_name_indication, disable} | ClientConf], undefined, Config).
-
+
ip_fallback(Config) ->
Hostname = net_adm:localhost(),
{ok, #hostent{h_addr_list = [IP |_]}} = inet:gethostbyname(net_adm:localhost()),
IPStr = tuple_to_list(IP),
#{server_config := ServerConf,
client_config := ClientConf} = public_key:pkix_test_data(#{server_chain =>
- #{root => [],
- intermediates => [[]],
+ #{root => [{key, ssl_test_lib:hardcode_rsa_key(1)}],
+ intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(2)}]],
peer => [{extensions, [#'Extension'{extnID =
?'id-ce-subjectAltName',
extnValue = [{dNSName, Hostname},
{iPAddress, IPStr}],
- critical = false}]}
- ]},
+ critical = false}]},
+ {key, ssl_test_lib:hardcode_rsa_key(3)}]},
client_chain =>
- #{root => [],
- intermediates => [[]],
- peer => []}}),
+ #{root => [{key, ssl_test_lib:hardcode_rsa_key(4)}],
+ intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(5)}]],
+ peer => [{key, ssl_test_lib:hardcode_rsa_key(6)}]}}),
successfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], Hostname, Config),
successfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], IP, Config).
-
+
no_ip_fallback(Config) ->
Hostname = net_adm:localhost(),
{ok, #hostent{h_addr_list = [IP |_]}} = inet:gethostbyname(net_adm:localhost()),
#{server_config := ServerConf,
client_config := ClientConf} = public_key:pkix_test_data(#{server_chain =>
- #{root => [],
- intermediates => [[]],
+ #{root => [{key, ssl_test_lib:hardcode_rsa_key(1)}],
+ intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(2)}]],
peer => [{extensions, [#'Extension'{extnID =
?'id-ce-subjectAltName',
extnValue = [{dNSName, Hostname}],
- critical = false}]}
+ critical = false}]},
+ {key, ssl_test_lib:hardcode_rsa_key(3)}
]},
client_chain =>
- #{root => [],
- intermediates => [[]],
- peer => []}}),
+ #{root => [{key, ssl_test_lib:hardcode_rsa_key(4)}],
+ intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(5)}]],
+ peer => [{key, ssl_test_lib:hardcode_rsa_key(6)}]}}),
successfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], Hostname, Config),
unsuccessfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], IP, Config).
-
+
dns_name_reuse(Config) ->
SNIHostname = "OTP.test.server",
#{server_config := ServerConf,
client_config := ClientConf} = public_key:pkix_test_data(#{server_chain =>
- #{root => [],
- intermediates => [[]],
+ #{root => [{key, ssl_test_lib:hardcode_rsa_key(1)}],
+ intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(2)}]],
peer => [{extensions, [#'Extension'{extnID =
?'id-ce-subjectAltName',
extnValue = [{dNSName, SNIHostname}],
- critical = false}]}]},
+ critical = false}
+ ]},
+ {key, ssl_test_lib:hardcode_rsa_key(3)}
+ ]},
client_chain =>
- #{root => [],
- intermediates => [[]],
- peer => []}}),
+ #{root => [{key, ssl_test_lib:hardcode_rsa_key(4)}],
+ intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(5)}]],
+ peer => [{key, ssl_test_lib:hardcode_rsa_key(6)}]}}),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -215,11 +220,10 @@ dns_name_reuse(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{from, self()}, {options, [{verify, verify_peer},
{server_name_indication, SNIHostname} | ClientConf]}]),
- SessionInfo =
- receive
- {Server, Info} ->
- Info
- end,
+ receive
+ {Server, _} ->
+ ok
+ end,
Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
@@ -232,8 +236,7 @@ dns_name_reuse(Config) ->
{mfa, {ssl_test_lib, session_info_result, []}},
{from, self()}, {options, [{verify, verify_peer} | ClientConf]}]),
- ssl_test_lib:check_result(Server, {error, {tls_alert, "handshake failure"}},
- Client1, {error, {tls_alert, "handshake failure"}}),
+ ssl_test_lib:check_result(Client1, {error, {tls_alert, "handshake failure"}}),
ssl_test_lib:close(Client0).
%%--------------------------------------------------------------------
%% Internal Functions ------------------------------------------------
--
cgit v1.2.3
From 7d02ac57c576a1aa0331b25a473f085e1b04dfe0 Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 28 Sep 2017 13:19:33 +0200
Subject: public_key: Added IP4 address checks to hostname_verification tests
---
lib/public_key/test/public_key_SUITE.erl | 40 ++++++++++++++++++++++
.../pkix_verify_hostname_subjAltName_IP.pem | 13 +++++++
.../public_key_SUITE_data/verify_hostname_ip.conf | 17 +++++++++
3 files changed, 70 insertions(+)
create mode 100644 lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName_IP.pem
create mode 100644 lib/public_key/test/public_key_SUITE_data/verify_hostname_ip.conf
(limited to 'lib')
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index 374fb20375..6741a2e30c 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -47,6 +47,7 @@ all() ->
pkix_iso_rsa_oid, pkix_iso_dsa_oid, pkix_crl, general_name,
pkix_verify_hostname_cn,
pkix_verify_hostname_subjAltName,
+ pkix_verify_hostname_subjAltName_IP,
pkix_verify_hostname_options,
pkix_test_data_all_default,
pkix_test_data,
@@ -984,6 +985,45 @@ pkix_verify_hostname_options(Config) ->
[{fqdn_fun, fun(_) -> default end}]),
false = public_key:pkix_verify_hostname(Cert, [{uri_id,"some://very.wrong.domain"}]).
+%%--------------------------------------------------------------------
+%% To generate the PEM file contents:
+%%
+%% openssl req -x509 -nodes -newkey rsa:1024 -keyout /dev/null -extensions SAN -config public_key_SUITE_data/verify_hostname_ip.conf 2>/dev/null > public_key_SUITE_data/pkix_verify_hostname_subjAltName_IP.pem
+%%
+%% Subject: C=SE, CN=example.com
+%% Subject Alternative Name: DNS:1.2.3.4, IP=5.6.7.8, URI:https://10.11.12.13
+
+pkix_verify_hostname_subjAltName_IP(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ {ok,Bin} = file:read_file(filename:join(DataDir,"pkix_verify_hostname_subjAltName_IP.pem")),
+ Cert = public_key:pkix_decode_cert(element(2,hd(public_key:pem_decode(Bin))), otp),
+
+ %% Print the tests that a matchfun has to handle
+ catch public_key:pkix_verify_hostname(Cert, [{some_tag,"some.domain"},
+ {some_other_tag,[a,b,3,4]}],
+ [{match_fun,
+ fun(Ref,Pres) ->
+ ct:pal("~p:~p:~nRef : ~p~nPres: ~p",[?MODULE,?LINE,Ref,Pres]),
+ false
+ end}]),
+
+ false = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://10.11.12.14"}]),
+ true = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://10.11.12.13"}]),
+ true = public_key:pkix_verify_hostname(Cert, [{dns_id,"1.2.3.4"}]),
+ false = public_key:pkix_verify_hostname(Cert, [{dns_id,"5.6.7.8"}]),
+ true = public_key:pkix_verify_hostname(Cert, [{ip,[5,6,7,8]}],
+ [{match_fun,
+ fun({ip,IPref},{iPAddress,IPpres}) ->
+ ct:pal("~p:~p: IPref=~p, IPpres=~p",[?MODULE,?LINE,IPref,IPpres]),
+ IPref == IPpres;
+ (Ref,Pres) ->
+ ct:pal("~p:~p:~nRef : ~p~nPres: ~p",[?MODULE,?LINE,Ref,Pres]),
+ default
+ end}]).
+
+
+
+
%%--------------------------------------------------------------------
pkix_iso_rsa_oid() ->
[{doc, "Test workaround for supporting certs that use ISO oids"
diff --git a/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName_IP.pem b/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName_IP.pem
new file mode 100644
index 0000000000..e83dfdb646
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName_IP.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB7TCCAVagAwIBAgIJAJftQyvUMLESMA0GCSqGSIb3DQEBCwUAMB8xCzAJBgNV
+BAYTAlNFMRAwDgYDVQQDEwc1LjYuNy44MB4XDTE3MDkyODExMTY0MFoXDTE3MTAy
+ODExMTY0MFowHzELMAkGA1UEBhMCU0UxEDAOBgNVBAMTBzUuNi43LjgwgZ8wDQYJ
+KoZIhvcNAQEBBQADgY0AMIGJAoGBAK1jLhGZcI0D5RzcUBjXuQ1636gaIlArdM4b
+woLpJIh2Tk4pCbEv6hOX0KTl8qPs8lCMOIOvQmoZwj0Ia1B5By9xHybJ30pNIoLy
+iqOdFwjlqTjhBVR1NjmcwgIRW1f/fqQ0pQznyIo/OwieNYlCwWzIUx1ZBLlwKAfZ
+YWozJaLZAgMBAAGjMTAvMC0GA1UdEQQmMCSCBzEuMi4zLjSHBAUGBwiGE2h0dHBz
+Oi8vMTAuMTEuMTIuMTMwDQYJKoZIhvcNAQELBQADgYEADapgA5dTBSrQMTAOGI7h
+SFpaF1y9EHSnCxofugR2EJNyNyPELFBQ9etIgU8fw67D495OSfy/3X3ngNAFOuds
+OENGq0JyBrO+HsgexslKF7LGc0oFlHfuZwyO7MLNFTG9dHG393dqduwGsEAuFh09
+SvMMJh3VTEHu6P+9O8YusdI=
+-----END CERTIFICATE-----
diff --git a/lib/public_key/test/public_key_SUITE_data/verify_hostname_ip.conf b/lib/public_key/test/public_key_SUITE_data/verify_hostname_ip.conf
new file mode 100644
index 0000000000..2b905e2c4f
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/verify_hostname_ip.conf
@@ -0,0 +1,17 @@
+[req]
+prompt = no
+distinguished_name = DN
+
+[DN]
+C=SE
+CN=example.com
+CN=5.6.7.8
+
+[SAN]
+subjectAltName = @alt_names
+
+[alt_names]
+DNS = 1.2.3.4
+IP = 5.6.7.8
+URI = https://10.11.12.13
+
--
cgit v1.2.3
From 28e032d29013203bd32917ee495cc202f0bb6b4e Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 28 Sep 2017 16:46:42 +0200
Subject: public_key: verify ip (both v4 and v6)
---
lib/public_key/doc/src/public_key.xml | 14 +++++---
lib/public_key/src/public_key.erl | 37 ++++++++++++++++++++--
lib/public_key/test/public_key_SUITE.erl | 24 ++++++--------
.../pkix_verify_hostname_subjAltName_IP.pem | 22 ++++++-------
.../public_key_SUITE_data/verify_hostname_ip.conf | 3 +-
5 files changed, 67 insertions(+), 33 deletions(-)
(limited to 'lib')
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index fcf37a7a4d..3040f2db0d 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -871,12 +871,13 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
Cert = der_encoded() | #'OTPCertificate'{}
ReferenceIDs = [ RefID ]
- RefID = {IdType,string()}
- IdType = dns_id | srv_id | uri_id
+ RefID = {dns_id,string()} | {srv_id,string()} | {uri_id,string()} | {ip,inet:ip_address()|string()} | {OtherRefID,term()}}
+ OtherRefID = atom()
Opts = [ PvhOpt() ]
PvhOpt = [MatchOpt | FailCallBackOpt | FqdnExtractOpt]
- MatchOpt = {fun(RefId | FQDN::string(), PresentedID) -> boolean() | default}
- PresentedID = {dNSName,string()} | {uniformResourceIdentifier,string()}
+ MatchOpt = {match_fun, fun(RefId | FQDN::string(), PresentedID) -> boolean() | default}
+ PresentedID = {dNSName,string()} | {uniformResourceIdentifier,string() | {iPAddress,list(byte())} | {OtherPresId,term()}}
+ OtherPresID = atom()
FailCallBackOpt = {fail_callback, fun(#'OTPCertificate'{}) -> boolean()}
FqdnExtractOpt = {fqdn_fun, fun(RefID) -> FQDN::string() | default | undefined}
@@ -893,6 +894,11 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
code examples
describes this function more detailed.
+ The {OtherRefId,term()} is defined by the user and is passed to the match_fun, if defined.
+ If that term is a binary, it will be converted to a string.
+
+ The ip takes a 4-tuple or a
+
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index cc01b61433..c3f2d791a3 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -1454,13 +1454,43 @@ verify_hostname_match_default0({dns_id,R}, {dNSName,P}) ->
R==P;
verify_hostname_match_default0({uri_id,R}, {uniformResourceIdentifier,P}) ->
R==P;
-verify_hostname_match_default0({srv_id,R}, {T,P}) when T == srvName ;
- T == ?srvName_OID ->
+verify_hostname_match_default0({ip,R}, {iPAddress,P}) when length(P) == 4 ->
+ %% IPv4
+ try
+ list_to_tuple(P)
+ == if is_tuple(R), size(R)==4 -> R;
+ is_list(R) -> ok(inet:parse_ipv4strict_address(R))
+ end
+ catch
+ _:_ ->
+ false
+ end;
+
+verify_hostname_match_default0({ip,R}, {iPAddress,P}) when length(P) == 16 ->
+ %% IPv6. The length 16 is due to the certificate specification.
+ try
+ l16_to_tup(P)
+ == if is_tuple(R), size(R)==8 -> R;
+ is_list(R) -> ok(inet:parse_ipv6strict_address(R))
+ end
+ catch
+ _:_ ->
+ false
+ end;
+verify_hostname_match_default0({srv_id,R}, {srvName,P}) ->
+ R==P;
+verify_hostname_match_default0({srv_id,R}, {?srvName_OID,P}) ->
R==P;
verify_hostname_match_default0(_, _) ->
false.
+ok({ok,X}) -> X.
+l16_to_tup(L) -> list_to_tuple(l16_to_tup(L, [])).
+%%
+l16_to_tup([A,B|T], Acc) -> l16_to_tup(T, [(A bsl 8) bor B | Acc]);
+l16_to_tup([], Acc) -> lists:reverse(Acc).
+
match_wild(A, [$*|B]) -> match_wild_suffixes(A, B);
match_wild([C|A], [ C|B]) -> match_wild(A, B);
match_wild([], []) -> true;
@@ -1505,7 +1535,8 @@ to_lower_ascii(C) when $A =< C,C =< $Z -> C + ($a-$A);
to_lower_ascii(C) -> C.
to_string(S) when is_list(S) -> S;
-to_string(B) when is_binary(B) -> binary_to_list(B).
+to_string(B) when is_binary(B) -> binary_to_list(B);
+to_string(X) -> X.
format_details([]) ->
no_relevant_crls;
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index 6741a2e30c..0077c7908c 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -991,7 +991,7 @@ pkix_verify_hostname_options(Config) ->
%% openssl req -x509 -nodes -newkey rsa:1024 -keyout /dev/null -extensions SAN -config public_key_SUITE_data/verify_hostname_ip.conf 2>/dev/null > public_key_SUITE_data/pkix_verify_hostname_subjAltName_IP.pem
%%
%% Subject: C=SE, CN=example.com
-%% Subject Alternative Name: DNS:1.2.3.4, IP=5.6.7.8, URI:https://10.11.12.13
+%% Subject Alternative Name: DNS:1.2.3.4, DNS: abcd:ef::1, IP:5.6.7.8, URI:https://10.11.12.13
pkix_verify_hostname_subjAltName_IP(Config) ->
DataDir = proplists:get_value(data_dir, Config),
@@ -1000,28 +1000,24 @@ pkix_verify_hostname_subjAltName_IP(Config) ->
%% Print the tests that a matchfun has to handle
catch public_key:pkix_verify_hostname(Cert, [{some_tag,"some.domain"},
- {some_other_tag,[a,b,3,4]}],
+ {ip, {5,6,7,8}}
+ ],
[{match_fun,
fun(Ref,Pres) ->
ct:pal("~p:~p:~nRef : ~p~nPres: ~p",[?MODULE,?LINE,Ref,Pres]),
false
end}]),
- false = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://10.11.12.14"}]),
+ false = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://1.2.3.4"}]),
true = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://10.11.12.13"}]),
true = public_key:pkix_verify_hostname(Cert, [{dns_id,"1.2.3.4"}]),
+ true = public_key:pkix_verify_hostname(Cert, [{dns_id,<<"1.2.3.4">>}]),
false = public_key:pkix_verify_hostname(Cert, [{dns_id,"5.6.7.8"}]),
- true = public_key:pkix_verify_hostname(Cert, [{ip,[5,6,7,8]}],
- [{match_fun,
- fun({ip,IPref},{iPAddress,IPpres}) ->
- ct:pal("~p:~p: IPref=~p, IPpres=~p",[?MODULE,?LINE,IPref,IPpres]),
- IPref == IPpres;
- (Ref,Pres) ->
- ct:pal("~p:~p:~nRef : ~p~nPres: ~p",[?MODULE,?LINE,Ref,Pres]),
- default
- end}]).
-
-
+ true = public_key:pkix_verify_hostname(Cert, [{ip, "aBcD:ef:0::0:1"}]),
+ true = public_key:pkix_verify_hostname(Cert, [{ip, {16#abcd,16#ef,0,0,0,0,0,1}}]),
+ true = public_key:pkix_verify_hostname(Cert, [{ip, "5.6.7.8"}]),
+ true = public_key:pkix_verify_hostname(Cert, [{ip, <<"5.6.7.8">>}]),
+ true = public_key:pkix_verify_hostname(Cert, [{ip, {5,6,7,8}}]).
%%--------------------------------------------------------------------
diff --git a/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName_IP.pem b/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName_IP.pem
index e83dfdb646..f9ffb257b5 100644
--- a/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName_IP.pem
+++ b/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName_IP.pem
@@ -1,13 +1,13 @@
-----BEGIN CERTIFICATE-----
-MIIB7TCCAVagAwIBAgIJAJftQyvUMLESMA0GCSqGSIb3DQEBCwUAMB8xCzAJBgNV
-BAYTAlNFMRAwDgYDVQQDEwc1LjYuNy44MB4XDTE3MDkyODExMTY0MFoXDTE3MTAy
-ODExMTY0MFowHzELMAkGA1UEBhMCU0UxEDAOBgNVBAMTBzUuNi43LjgwgZ8wDQYJ
-KoZIhvcNAQEBBQADgY0AMIGJAoGBAK1jLhGZcI0D5RzcUBjXuQ1636gaIlArdM4b
-woLpJIh2Tk4pCbEv6hOX0KTl8qPs8lCMOIOvQmoZwj0Ia1B5By9xHybJ30pNIoLy
-iqOdFwjlqTjhBVR1NjmcwgIRW1f/fqQ0pQznyIo/OwieNYlCwWzIUx1ZBLlwKAfZ
-YWozJaLZAgMBAAGjMTAvMC0GA1UdEQQmMCSCBzEuMi4zLjSHBAUGBwiGE2h0dHBz
-Oi8vMTAuMTEuMTIuMTMwDQYJKoZIhvcNAQELBQADgYEADapgA5dTBSrQMTAOGI7h
-SFpaF1y9EHSnCxofugR2EJNyNyPELFBQ9etIgU8fw67D495OSfy/3X3ngNAFOuds
-OENGq0JyBrO+HsgexslKF7LGc0oFlHfuZwyO7MLNFTG9dHG393dqduwGsEAuFh09
-SvMMJh3VTEHu6P+9O8YusdI=
+MIIB/zCCAWigAwIBAgIJAMoSejmTjwAGMA0GCSqGSIb3DQEBCwUAMB8xCzAJBgNV
+BAYTAlNFMRAwDgYDVQQDEwc1LjYuNy44MB4XDTE3MDkyODE0MDAxNVoXDTE3MTAy
+ODE0MDAxNVowHzELMAkGA1UEBhMCU0UxEDAOBgNVBAMTBzUuNi43LjgwgZ8wDQYJ
+KoZIhvcNAQEBBQADgY0AMIGJAoGBAMUPU89KwVbTCDkyxQSz3wprMbZTLe35K6jm
+Q7oY1rJyVXjsFHwZrFqqNMScEyX40rJhczQ2Z9etEX6qYLbdb/DZeFcKo14fR583
+QMFZC+qqpLWHdvjaQN0KwD99VFeZIGpRgywG8SR+BXZjDHUkGsMrikAEJtf0Tgih
+IPyiFtiJAgMBAAGjQzBBMD8GA1UdEQQ4MDaCBzEuMi4zLjSHBAUGBwiHEKvNAO8A
+AAAAAAAAAAAAAAGGE2h0dHBzOi8vMTAuMTEuMTIuMTMwDQYJKoZIhvcNAQELBQAD
+gYEAtWVeQaRFZ0kH/pzSWMSsOCUrjbwlWRwDNbagNKoM6nCRv0QQ59fG6XrVZwR3
+c0s5arlMh3U2+bjKE+Iq9+b/lN1lGzf8iaAqBNa7KptwTSUEY3TiNG5X0zlSXKTI
+3z7AaUEtghL9ImCPj5V3tVksqWd7U0zLmeeLZnM+wGAL9Hc=
-----END CERTIFICATE-----
diff --git a/lib/public_key/test/public_key_SUITE_data/verify_hostname_ip.conf b/lib/public_key/test/public_key_SUITE_data/verify_hostname_ip.conf
index 2b905e2c4f..0a738f2586 100644
--- a/lib/public_key/test/public_key_SUITE_data/verify_hostname_ip.conf
+++ b/lib/public_key/test/public_key_SUITE_data/verify_hostname_ip.conf
@@ -12,6 +12,7 @@ subjectAltName = @alt_names
[alt_names]
DNS = 1.2.3.4
-IP = 5.6.7.8
+IP.1 = 5.6.7.8
+IP.2 = abcd:ef::1
URI = https://10.11.12.13
--
cgit v1.2.3
From 92cfb8ee136eea2ace96c3cee85f758a670b2bf7 Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Wed, 22 Nov 2017 12:23:43 +0100
Subject: Update version numbers
---
lib/public_key/vsn.mk | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk
index bb96c2237d..c01d8820f2 100644
--- a/lib/public_key/vsn.mk
+++ b/lib/public_key/vsn.mk
@@ -1 +1 @@
-PUBLIC_KEY_VSN = 1.5
+PUBLIC_KEY_VSN = 1.5.1
--
cgit v1.2.3
From 31a1cd146bf6d0caf1d3fe8005b7e6307710205d Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Wed, 22 Nov 2017 12:23:57 +0100
Subject: Update release notes
---
lib/public_key/doc/src/notes.xml | 24 +++++++++++++
lib/ssl/doc/src/notes.xml | 78 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 102 insertions(+)
(limited to 'lib')
diff --git a/lib/public_key/doc/src/notes.xml b/lib/public_key/doc/src/notes.xml
index 7a7c828760..a4c0194328 100644
--- a/lib/public_key/doc/src/notes.xml
+++ b/lib/public_key/doc/src/notes.xml
@@ -35,6 +35,30 @@
notes.xml
+Public_Key 1.5.1
+
+ Improvements and New Features
+
+ -
+
+ Hostname verification: Add handling of the general name
+ iPAddress in certificate's subject alternative
+ name extension (subjAltName).
+
+ Own Id: OTP-14653
+
+ -
+
+ Correct key handling in pkix_test_data/1 and use a
+ generic example mail address instead of an existing one.
+
+ Own Id: OTP-14766
+
+
+
+
+
+
Public_Key 1.5
Fixed Bugs and Malfunctions
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 4c6a204e63..a8450c2630 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -28,6 +28,84 @@
This document describes the changes made to the SSL application.
+SSL 8.2.2
+
+ Fixed Bugs and Malfunctions
+
+ -
+
+ TLS sessions must be registered with SNI if provided, so
+ that sessions where client hostname verification would
+ fail can not connect reusing a session created when the
+ server name verification succeeded.
+
+ Own Id: OTP-14632
+
+ -
+
An erlang TLS server configured with cipher suites
+ using rsa key exchange, may be vulnerable to an Adaptive
+ Chosen Ciphertext attack (AKA Bleichenbacher attack)
+ against RSA, which when exploited, may result in
+ plaintext recovery of encrypted messages and/or a
+ Man-in-the-middle (MiTM) attack, despite the attacker not
+ having gained access to the server’s private key
+ itself. CVE-2017-1000385
+
Exploiting this vulnerability to perform
+ plaintext recovery of encrypted messages will, in most
+ practical cases, allow an attacker to read the plaintext
+ only after the session has completed. Only TLS sessions
+ established using RSA key exchange are vulnerable to this
+ attack.
Exploiting this vulnerability to conduct
+ a MiTM attack requires the attacker to complete the
+ initial attack, which may require thousands of server
+ requests, during the handshake phase of the targeted
+ session within the window of the configured handshake
+ timeout. This attack may be conducted against any TLS
+ session using RSA signatures, but only if cipher suites
+ using RSA key exchange are also enabled on the server.
+ The limited window of opportunity, limitations in
+ bandwidth, and latency make this attack significantly
+ more difficult to execute.
RSA key exchange is
+ enabled by default although least prioritized if server
+ order is honored. For such a cipher suite to be chosen it
+ must also be supported by the client and probably the
+ only shared cipher suite.
Captured TLS sessions
+ encrypted with ephemeral cipher suites (DHE or ECDHE) are
+ not at risk for subsequent decryption due to this
+ vulnerability.
As a workaround if default cipher
+ suite configuration was used you can configure the server
+ to not use vulnerable suites with the ciphers option like
+ this:
{ciphers, [Suite || Suite <-
+ ssl:cipher_suites(), element(1,Suite) =/= rsa]}
+ that is your code will look somethingh like this:
+ ssl:listen(Port, [{ciphers, [Suite || Suite <-
+ ssl:cipher_suites(), element(1,S) =/= rsa]} | Options]).
+ Thanks to Hanno Böck, Juraj Somorovsky and
+ Craig Young for reporting this vulnerability.
+
+ Own Id: OTP-14748
+
+
+
+
+
+ Improvements and New Features
+
+ -
+
+ If no SNI is available and the hostname is an IP-address
+ also check for IP-address match. This check is not as
+ good as a DNS hostname check and certificates using
+ IP-address are not recommended.
+
+ Own Id: OTP-14655
+
+
+
+
+
+
SSL 8.2.1
Fixed Bugs and Malfunctions
--
cgit v1.2.3