aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngela Anderton Andin <[email protected]>2015-05-05 16:03:18 +0200
committerIngela Anderton Andin <[email protected]>2015-05-12 14:04:06 +0200
commitff2400d7b5b1b090e128bc537d7bdd94c6aad97e (patch)
tree43ef1c0fdb4b7f9ce35d2dd7508e43de42325788
parentdb509dd5debcd72d7f1d024d289315274f9b788b (diff)
downloadotp-ff2400d7b5b1b090e128bc537d7bdd94c6aad97e.tar.gz
otp-ff2400d7b5b1b090e128bc537d7bdd94c6aad97e.tar.bz2
otp-ff2400d7b5b1b090e128bc537d7bdd94c6aad97e.zip
ssl: Refactored and corrected sni_fun handling
Dialyzer warned about the incorrect match of Packets. Code was refactored and the problem avoided in the process. Dialyzer warned that the empty tuple is not a function as the contract said it should be. Changed the handling of the sni_fun default value to be undefined and added it to the contract.
-rw-r--r--lib/ssl/src/ssl.erl6
-rw-r--r--lib/ssl/src/ssl_internal.hrl2
-rw-r--r--lib/ssl/src/tls_connection.erl86
3 files changed, 48 insertions, 46 deletions
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 9f76612ee3..225a9be66f 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -700,7 +700,7 @@ handle_options(Opts0) ->
log_alert = handle_option(log_alert, Opts, true),
server_name_indication = handle_option(server_name_indication, Opts, undefined),
sni_hosts = handle_option(sni_hosts, Opts, []),
- sni_fun = handle_option(sni_fun, Opts, {}),
+ sni_fun = handle_option(sni_fun, Opts, undefined),
honor_cipher_order = handle_option(honor_cipher_order, Opts, false),
protocol = proplists:get_value(protocol, Opts, tls),
padding_check = proplists:get_value(padding_check, Opts, true),
@@ -933,8 +933,8 @@ validate_option(sni_hosts, [{Hostname, SSLOptions} | Tail]) when is_list(Hostnam
_ ->
throw({error, {options, {sni_hosts, RecursiveSNIOptions}}})
end;
-validate_option(sni_fun, {}) ->
- {};
+validate_option(sni_fun, undefined) ->
+ undefined;
validate_option(sni_fun, Fun) when is_function(Fun) ->
Fun;
validate_option(honor_cipher_order, Value) when is_boolean(Value) ->
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index b6b4fc44df..baeae68bc4 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -123,7 +123,7 @@
log_alert :: boolean(),
server_name_indication = undefined,
sni_hosts :: [{inet:hostname(), [tuple()]}],
- sni_fun :: function(),
+ sni_fun :: function() | undefined,
%% Should the server prefer its own cipher order over the one provided by
%% the client?
honor_cipher_order = false :: boolean(),
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index 1ee47f28b1..3304ffcddb 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -401,12 +401,13 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, Tracker}, Us
update_ssl_options_from_sni(OrigSSLOptions, SNIHostname) ->
SSLOption =
- case OrigSSLOptions#ssl_options.sni_fun of
- {} ->
- proplists:get_value(SNIHostname, OrigSSLOptions#ssl_options.sni_hosts);
- SNIFun ->
- SNIFun(SNIHostname)
- end,
+ case OrigSSLOptions#ssl_options.sni_fun of
+ undefined ->
+ proplists:get_value(SNIHostname,
+ OrigSSLOptions#ssl_options.sni_hosts);
+ SNIFun ->
+ SNIFun(SNIHostname)
+ end,
case SSLOption of
undefined ->
undefined;
@@ -442,50 +443,22 @@ next_state(Current, Next, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
%% This message should not be included in handshake
%% message hashes. Already in negotiation so it will be ignored!
?MODULE:SName(Packet, State);
- ({#client_hello{} = Packet, Raw}, {next_state, connection = SName, State}) ->
+ ({#client_hello{} = Packet, Raw}, {next_state, connection = SName, HState0}) ->
+ HState = handle_sni_extension(Packet, HState0),
Version = Packet#client_hello.client_version,
Hs0 = ssl_handshake:init_handshake_history(),
Hs1 = ssl_handshake:update_handshake_history(Hs0, Raw),
- ?MODULE:SName(Packet, State#state{tls_handshake_history=Hs1,
- renegotiation = {true, peer}});
- ({Packet, Raw}, {next_state, SName, State = #state{tls_handshake_history=Hs0}}) ->
+ ?MODULE:SName(Packet, HState#state{tls_handshake_history=Hs1,
+ renegotiation = {true, peer}});
+ ({Packet, Raw}, {next_state, SName, HState0 = #state{tls_handshake_history=Hs0}}) ->
+ HState = handle_sni_extension(Packet, HState0),
Hs1 = ssl_handshake:update_handshake_history(Hs0, Raw),
- ?MODULE:SName(Packet, State#state{tls_handshake_history=Hs1});
+ ?MODULE:SName(Packet, HState#state{tls_handshake_history=Hs1});
(_, StopState) -> StopState
end,
try
{Packets, Buf} = tls_handshake:get_tls_handshake(Version,Data,Buf0),
- State1 = case Packets of
- [{#client_hello{extensions=HelloExtensions} = ClientHello, _}] ->
- case HelloExtensions#hello_extensions.sni of
- undefined ->
- State0;
- #sni{hostname = Hostname} ->
- NewOptions = update_ssl_options_from_sni(State0#state.ssl_options, Hostname),
- case NewOptions of
- undefined ->
- State0;
- _ ->
- {ok, Ref, CertDbHandle, FileRefHandle, CacheHandle, CRLDbHandle, OwnCert, Key, DHParams} =
- ssl_config:init(NewOptions, State0#state.role),
- State0#state{
- session = State0#state.session#session{own_certificate = OwnCert},
- file_ref_db = FileRefHandle,
- cert_db_ref = Ref,
- cert_db = CertDbHandle,
- crl_db = CRLDbHandle,
- session_cache = CacheHandle,
- private_key = Key,
- diffie_hellman_params = DHParams,
- ssl_options = NewOptions,
- sni_hostname = Hostname
- }
- end
- end;
- _ ->
- State0
- end,
- State = State1#state{protocol_buffers =
+ State = State0#state{protocol_buffers =
Buffers#protocol_buffers{tls_packets = Packets,
tls_handshake_buffer = Buf}},
handle_tls_handshake(Handle, Next, State)
@@ -1027,3 +1000,32 @@ convert_options_partial_chain(Options, up) ->
list_to_tuple(Head ++ [{partial_chain, fun(_) -> unknown_ca end}] ++ Tail);
convert_options_partial_chain(Options, down) ->
list_to_tuple(proplists:delete(partial_chain, tuple_to_list(Options))).
+
+handle_sni_extension(#client_hello{extensions = HelloExtensions}, State0) ->
+ case HelloExtensions#hello_extensions.sni of
+ undefined ->
+ State0;
+ #sni{hostname = Hostname} ->
+ NewOptions = update_ssl_options_from_sni(State0#state.ssl_options, Hostname),
+ case NewOptions of
+ undefined ->
+ State0;
+ _ ->
+ {ok, Ref, CertDbHandle, FileRefHandle, CacheHandle, CRLDbHandle, OwnCert, Key, DHParams} =
+ ssl_config:init(NewOptions, State0#state.role),
+ State0#state{
+ session = State0#state.session#session{own_certificate = OwnCert},
+ file_ref_db = FileRefHandle,
+ cert_db_ref = Ref,
+ cert_db = CertDbHandle,
+ crl_db = CRLDbHandle,
+ session_cache = CacheHandle,
+ private_key = Key,
+ diffie_hellman_params = DHParams,
+ ssl_options = NewOptions,
+ sni_hostname = Hostname
+ }
+ end
+ end;
+handle_sni_extension(_, State0) ->
+ State0.