From 4fe38c4b8b2c8024afb60990e598ff823743fd54 Mon Sep 17 00:00:00 2001 From: Qijiang Fan Date: Tue, 30 Dec 2014 22:40:28 +0800 Subject: ssl: add SNI server support --- lib/ssl/src/tls_connection.erl | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'lib/ssl/src/tls_connection.erl') diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index 0577222980..d804d7ad37 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -398,6 +398,15 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, Tracker}, Us tracker = Tracker }. + +update_ssl_options_from_sni(OrigSSLOptions, SNIHostname) -> + case proplists:get_value(SNIHostname, OrigSSLOptions#ssl_options.sni_hosts) of + undefined -> + undefined; + SSLOption -> + ssl:handle_options(SSLOption, OrigSSLOptions) + end. + next_state(Current,_, #alert{} = Alert, #state{negotiated_version = Version} = State) -> handle_own_alert(Alert, Version, Current, State); @@ -439,7 +448,38 @@ next_state(Current, Next, #ssl_tls{type = ?HANDSHAKE, fragment = Data}, end, try {Packets, Buf} = tls_handshake:get_tls_handshake(Version,Data,Buf0), - State = State0#state{protocol_buffers = + State1 = case Packets of + [{#client_hello{extensions=HelloExtensions} = ClientHello, _}] -> + case HelloExtensions#hello_extensions.sni of + undefined -> + State0; + #sni{hostname = Hostname} -> + OrigSSLOptions = State0#state.ssl_options, + 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 = Buffers#protocol_buffers{tls_packets = Packets, tls_handshake_buffer = Buf}}, handle_tls_handshake(Handle, Next, State) -- cgit v1.2.3 From db509dd5debcd72d7f1d024d289315274f9b788b Mon Sep 17 00:00:00 2001 From: Qijiang Fan Date: Thu, 16 Apr 2015 22:25:57 +0800 Subject: ssl: add option sni_fun The newly added function sni_fun allows dynamic update of SSL options like keys and certificates depending on different SNI hostname, rather than a predefined rules of SSL options. --- lib/ssl/src/tls_connection.erl | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'lib/ssl/src/tls_connection.erl') diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index d804d7ad37..1ee47f28b1 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -400,12 +400,19 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, Tracker}, Us update_ssl_options_from_sni(OrigSSLOptions, SNIHostname) -> - case proplists:get_value(SNIHostname, OrigSSLOptions#ssl_options.sni_hosts) of - undefined -> - undefined; - SSLOption -> - ssl:handle_options(SSLOption, OrigSSLOptions) - end. + SSLOption = + case OrigSSLOptions#ssl_options.sni_fun of + {} -> + proplists:get_value(SNIHostname, OrigSSLOptions#ssl_options.sni_hosts); + SNIFun -> + SNIFun(SNIHostname) + end, + case SSLOption of + undefined -> + undefined; + _ -> + ssl:handle_options(SSLOption, OrigSSLOptions) + end. next_state(Current,_, #alert{} = Alert, #state{negotiated_version = Version} = State) -> handle_own_alert(Alert, Version, Current, State); @@ -454,7 +461,6 @@ next_state(Current, Next, #ssl_tls{type = ?HANDSHAKE, fragment = Data}, undefined -> State0; #sni{hostname = Hostname} -> - OrigSSLOptions = State0#state.ssl_options, NewOptions = update_ssl_options_from_sni(State0#state.ssl_options, Hostname), case NewOptions of undefined -> -- cgit v1.2.3 From ff2400d7b5b1b090e128bc537d7bdd94c6aad97e Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 5 May 2015 16:03:18 +0200 Subject: 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. --- lib/ssl/src/tls_connection.erl | 86 +++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 42 deletions(-) (limited to 'lib/ssl/src/tls_connection.erl') 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. -- cgit v1.2.3