diff options
Diffstat (limited to 'lib/ssl/src')
| -rw-r--r-- | lib/ssl/src/ssl.appup.src | 2 | ||||
| -rw-r--r-- | lib/ssl/src/ssl_certificate_db.erl | 56 | ||||
| -rw-r--r-- | lib/ssl/src/ssl_connection.erl | 42 | ||||
| -rw-r--r-- | lib/ssl/src/ssl_handshake.erl | 10 | ||||
| -rw-r--r-- | lib/ssl/src/ssl_handshake.hrl | 1 | ||||
| -rw-r--r-- | lib/ssl/src/ssl_manager.erl | 89 | ||||
| -rw-r--r-- | lib/ssl/src/ssl_session.erl | 30 | ||||
| -rw-r--r-- | lib/ssl/src/ssl_ssl3.erl | 5 | ||||
| -rw-r--r-- | lib/ssl/src/ssl_tls1.erl | 5 | 
9 files changed, 161 insertions, 79 deletions
| diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src index 51c5289bd2..a9c07ec87c 100644 --- a/lib/ssl/src/ssl.appup.src +++ b/lib/ssl/src/ssl.appup.src @@ -1,10 +1,12 @@  %% -*- erlang -*-  {"%VSN%",   [ +  {"4.1.1", [{restart_application, ssl}]},    {"4.1", [{restart_application, ssl}]},    {"4.0.1", [{restart_application, ssl}]}   ],    [ +  {"4.1.1", [{restart_application, ssl}]},    {"4.1", [{restart_application, ssl}]},    {"4.0.1", [{restart_application, ssl}]}   ]}. diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl index 2a5a7f3394..f34459de37 100644 --- a/lib/ssl/src/ssl_certificate_db.erl +++ b/lib/ssl/src/ssl_certificate_db.erl @@ -27,7 +27,9 @@  -export([create/0, remove/1, add_trusted_certs/3,   	 remove_trusted_certs/2, lookup_trusted_cert/3, issuer_candidate/1, -	 lookup_cached_certs/1, cache_pem_file/3]). +	 lookup_cached_certs/1, cache_pem_file/4, uncache_pem_file/2, lookup/2]). + +-type time()      :: {non_neg_integer(), non_neg_integer(), non_neg_integer()}.  %%====================================================================  %% Internal application API @@ -98,17 +100,35 @@ add_trusted_certs(Pid, File, [CertsDb, FileToRefDb, PidToFileDb]) ->      insert(Pid, File, PidToFileDb),      {ok, Ref}.  %%-------------------------------------------------------------------- --spec cache_pem_file(pid(), string(), certdb_ref()) -> term(). +-spec cache_pem_file(pid(), string(), time(), certdb_ref()) -> term().  %%  %% Description: Cache file as binary in DB  %%-------------------------------------------------------------------- -cache_pem_file(Pid, File, [CertsDb, _FileToRefDb, PidToFileDb]) -> +cache_pem_file(Pid, File, Time, [CertsDb, _FileToRefDb, PidToFileDb]) ->      {ok, PemBin} = file:read_file(File),       Content = public_key:pem_decode(PemBin), -    insert({file, File}, Content, CertsDb), +    insert({file, File}, {Time, Content}, CertsDb),      insert(Pid, File, PidToFileDb),      {ok, Content}. +%-------------------------------------------------------------------- +-spec uncache_pem_file(string(), certdb_ref()) -> no_return(). +%% +%% Description: If a cached file is no longer valid (changed on disk) +%% we must terminate the connections using the old file content, and +%% when those processes are finish the cache will be cleaned. It is +%% a rare but possible case a new ssl client/server is started with +%% a filename with the same name as previously started client/server +%% but with different content. +%% -------------------------------------------------------------------- +uncache_pem_file(File, [_CertsDb, _FileToRefDb, PidToFileDb]) -> +    [Pids] = select(PidToFileDb, [{{'$1', File},[],['$$']}]), +    lists:foreach(fun(Pid) -> +			  exit(Pid, shutdown) +		  end, Pids). + + +  %%--------------------------------------------------------------------  -spec remove_trusted_certs(pid(), certdb_ref()) -> term(). @@ -174,6 +194,22 @@ issuer_candidate(PrevCandidateKey) ->      end.  %%-------------------------------------------------------------------- +-spec lookup(term(), term()) -> term() | undefined. +%% +%% Description: Looks up an element in a certificat <Db>. +%%-------------------------------------------------------------------- +lookup(Key, Db) -> +    case ets:lookup(Db, Key) of +	[] -> +	    undefined; +	Contents  -> +	    Pick = fun({_, Data}) -> Data; +		      ({_,_,Data}) -> Data +		   end, +	    [Pick(Data) || Data <- Contents] +    end. + +%%--------------------------------------------------------------------  %%% Internal functions  %%--------------------------------------------------------------------  certificate_db_name() -> @@ -191,16 +227,8 @@ ref_count(Key, Db,N) ->  delete(Key, Db) ->      _ = ets:delete(Db, Key). -lookup(Key, Db) -> -    case ets:lookup(Db, Key) of -	[] -> -	    undefined; -	Contents  -> -	    Pick = fun({_, Data}) -> Data; -		      ({_,_,Data}) -> Data -		   end, -	    [Pick(Data) || Data <- Contents] -    end. +select(Db, MatchSpec)-> +    ets:select(Db, MatchSpec).  remove_certs(Ref, CertsDb) ->      ets:match_delete(CertsDb, {{Ref, '_', '_'}, '_'}). diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 6c9ac65b64..675e5e44bd 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -70,7 +70,7 @@  	  %% {{md5_hash, sha_hash}, {prev_md5, prev_sha}} (binary())            tls_handshake_hashes, % see above             tls_cipher_texts,     % list() received but not deciphered yet -          own_cert,             % binary()   +          own_cert,             % binary() | undefined            session,              % #session{} from ssl_handshake.hrl  	  session_cache,        %   	  session_cache_cb,     % @@ -90,7 +90,8 @@  	  log_alert,           % boolean()   	  renegotiation,        % {boolean(), From | internal | peer}  	  recv_during_renegotiation,  %boolean()  -	  send_queue           % queue() +	  send_queue,           % queue() +	  terminated = false   %  	 }).  -define(DEFAULT_DIFFIE_HELLMAN_PARAMS,  @@ -304,8 +305,10 @@ init([Role, Host, Port, Socket, {SSLOpts0, _} = Options,      try ssl_init(SSLOpts0, Role) of  	{ok, Ref, CacheRef, OwnCert, Key, DHParams} ->	    +	    Session = State0#state.session,  	    State = State0#state{tls_handshake_hashes = Hashes0,  				 own_cert = OwnCert, +				 session = Session#session{own_certificate = OwnCert},  				 cert_db_ref = Ref,  				 session_cache = CacheRef,  				 private_key = Key, @@ -331,6 +334,7 @@ init([Role, Host, Port, Socket, {SSLOpts0, _} = Options,  %%--------------------------------------------------------------------  hello(start, #state{host = Host, port = Port, role = client,  		    ssl_options = SslOpts,  +		    own_cert = Cert,  		    transport_cb = Transport, socket = Socket,  		    connection_states = ConnectionStates,  		    renegotiation = {Renegotiation, _}} @@ -338,7 +342,7 @@ hello(start, #state{host = Host, port = Port, role = client,      Hello = ssl_handshake:client_hello(Host, Port,   				       ConnectionStates,  -				       SslOpts, Renegotiation), +				       SslOpts, Renegotiation, Cert),      Version = Hello#client_hello.client_version,      Hashes0 = ssl_handshake:init_hashes(), @@ -678,6 +682,7 @@ cipher(Msg, State) ->  %%--------------------------------------------------------------------  connection(#hello_request{}, #state{host = Host, port = Port,  				    socket = Socket, +				    own_cert = Cert,  				    ssl_options = SslOpts,  				    negotiated_version = Version,  				    transport_cb = Transport, @@ -686,7 +691,7 @@ connection(#hello_request{}, #state{host = Host, port = Port,  				    tls_handshake_hashes = Hashes0} = State0) ->      Hello = ssl_handshake:client_hello(Host, Port, ConnectionStates0, -				       SslOpts, Renegotiation), +				       SslOpts, Renegotiation, Cert),      {BinMsg, ConnectionStates1, Hashes1} =          encode_handshake(Hello, Version, ConnectionStates0, Hashes0), @@ -777,8 +782,12 @@ handle_sync_event(start, _, connection, State) ->  handle_sync_event(start, From, StateName, State) ->      {next_state, StateName, State#state{from = From}}; -handle_sync_event(close, _, _StateName, State) -> -    {stop, normal, ok, State}; +handle_sync_event(close, _, StateName, State) -> +    %% Run terminate before returning +    %% so that the reuseaddr inet-option will work +    %% as intended. +    (catch terminate(user_close, StateName, State)), +    {stop, normal, ok, State#state{terminated = true}};  handle_sync_event({shutdown, How0}, _, StateName,  		  #state{transport_cb = Transport, @@ -966,6 +975,11 @@ handle_info(Msg, StateName, State) ->  %% necessary cleaning up. When it returns, the gen_fsm terminates with  %% Reason. The return value is ignored.  %%-------------------------------------------------------------------- +terminate(_, _, #state{terminated = true}) -> +    %% Happens when user closes the connection using ssl:close/1 +    %% we want to guarantee that Transport:close has been called +    %% when ssl:close/1 returns. +    ok;  terminate(Reason, connection, #state{negotiated_version = Version,  				      connection_states = ConnectionStates,  				      transport_cb = Transport, @@ -975,14 +989,14 @@ terminate(Reason, connection, #state{negotiated_version = Version,      notify_renegotiater(Renegotiate),      BinAlert = terminate_alert(Reason, Version, ConnectionStates),      Transport:send(Socket, BinAlert), -    workaround_transport_delivery_problems(Socket, Transport), +    workaround_transport_delivery_problems(Socket, Transport, Reason),      Transport:close(Socket); -terminate(_Reason, _StateName, #state{transport_cb = Transport,  +terminate(Reason, _StateName, #state{transport_cb = Transport,  				      socket = Socket, send_queue = SendQueue,  				      renegotiation = Renegotiate}) ->      notify_senders(SendQueue),      notify_renegotiater(Renegotiate), -    workaround_transport_delivery_problems(Socket, Transport), +    workaround_transport_delivery_problems(Socket, Transport, Reason),      Transport:close(Socket).  %%-------------------------------------------------------------------- @@ -2185,7 +2199,8 @@ notify_renegotiater({true, From}) when not is_atom(From)  ->  notify_renegotiater(_) ->      ok. -terminate_alert(Reason, Version, ConnectionStates) when Reason == normal; Reason == shutdown -> +terminate_alert(Reason, Version, ConnectionStates) when Reason == normal; Reason == shutdown; +							Reason == user_close ->      {BinAlert, _} = encode_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),  				 Version, ConnectionStates),      BinAlert; @@ -2194,10 +2209,13 @@ terminate_alert(_, Version, ConnectionStates) ->  				 Version, ConnectionStates),      BinAlert. -workaround_transport_delivery_problems(Socket, Transport) -> +workaround_transport_delivery_problems(_,_, user_close) -> +    ok; +workaround_transport_delivery_problems(Socket, Transport, _) ->      %% Standard trick to try to make sure all      %% data sent to to tcp port is really sent -    %% before tcp port is closed. +    %% before tcp port is closed so that the peer will +    %% get a correct error message.      inet:setopts(Socket, [{active, false}]),      Transport:shutdown(Socket, write),      Transport:recv(Socket, 0). diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index c7a1c4965d..125c28b373 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -30,7 +30,7 @@  -include("ssl_internal.hrl").  -include_lib("public_key/include/public_key.hrl"). --export([master_secret/4, client_hello/5, server_hello/4, hello/4, +-export([master_secret/4, client_hello/6, server_hello/4, hello/4,  	 hello_request/0, certify/6, certificate/3,  	 client_certificate_verify/5, certificate_verify/5,  	 certificate_request/2, key_exchange/2, server_key_exchange_hash/2, @@ -49,13 +49,13 @@  %%====================================================================  %%--------------------------------------------------------------------  -spec client_hello(host(), port_num(), #connection_states{}, -		   #ssl_options{}, boolean()) -> #client_hello{}. +		   #ssl_options{}, boolean(), der_cert()) -> #client_hello{}.  %%  %% Description: Creates a client hello message.  %%--------------------------------------------------------------------  client_hello(Host, Port, ConnectionStates, #ssl_options{versions = Versions,  							ciphers = UserSuites}  -	     = SslOpts, Renegotiation) -> +	     = SslOpts, Renegotiation, OwnCert) ->      Fun = fun(Version) ->  		  ssl_record:protocol_version(Version) @@ -65,7 +65,7 @@ client_hello(Host, Port, ConnectionStates, #ssl_options{versions = Versions,      SecParams = Pending#connection_state.security_parameters,      Ciphers = available_suites(UserSuites, Version), -    Id = ssl_manager:client_session_id(Host, Port, SslOpts), +    Id = ssl_manager:client_session_id(Host, Port, SslOpts, OwnCert),      #client_hello{session_id = Id,   		  client_version = Version, @@ -571,7 +571,7 @@ select_session(Hello, Port, Session, Version,  	       #ssl_options{ciphers = UserSuites} = SslOpts, Cache, CacheCb, Cert) ->      SuggestedSessionId = Hello#client_hello.session_id,      SessionId = ssl_manager:server_session_id(Port, SuggestedSessionId,  -					      SslOpts), +					      SslOpts, Cert),      Suites = available_suites(Cert, UserSuites, Version),       case ssl_session:is_new(SuggestedSessionId, SessionId) of diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl index 68a7802ef2..8ae4d2332e 100644 --- a/lib/ssl/src/ssl_handshake.hrl +++ b/lib/ssl/src/ssl_handshake.hrl @@ -36,6 +36,7 @@  -record(session, {  	  session_id,  	  peer_certificate, +	  own_certificate,  	  compression_method,  	  cipher_suite,  	  master_secret, diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl index 3b02d96562..f845b1ecc0 100644 --- a/lib/ssl/src/ssl_manager.erl +++ b/lib/ssl/src/ssl_manager.erl @@ -29,8 +29,8 @@  %% Internal application API  -export([start_link/1,   	 connection_init/2, cache_pem_file/1, -	 lookup_trusted_cert/3, issuer_candidate/1, client_session_id/3,  -	 server_session_id/3, +	 lookup_trusted_cert/3, issuer_candidate/1, client_session_id/4, +	 server_session_id/4,  	 register_session/2, register_session/3, invalidate_session/2,  	 invalidate_session/3]). @@ -43,6 +43,7 @@  -include("ssl_handshake.hrl").  -include("ssl_internal.hrl"). +-include_lib("kernel/include/file.hrl").  -record(state, {  	  session_cache, @@ -76,16 +77,17 @@ start_link(Opts) ->  connection_init(Trustedcerts, Role) ->      call({connection_init, Trustedcerts, Role}).  %%-------------------------------------------------------------------- --spec cache_pem_file(string()) -> {ok, term()}.	 +-spec cache_pem_file(string()) -> {ok, term()} | {error, reason()}.  %%		     -%% Description: Cach a pem file and  +%% Description: Cach a pem file and return its content.  %%-------------------------------------------------------------------- -cache_pem_file(File) ->    -    case ssl_certificate_db:lookup_cached_certs(File) of -	[{_,Content}] -> -	    {ok, Content}; -	[] -> -	    call({cache_pem, File}) +cache_pem_file(File) -> +    try file:read_file_info(File) of +	{ok, #file_info{mtime = LastWrite}} -> +	    cache_pem_file(File, LastWrite) +    catch +	_:Reason -> +	    {error, Reason}      end.  %%--------------------------------------------------------------------  -spec lookup_trusted_cert(reference(), serialnumber(), issuer()) ->  @@ -106,20 +108,21 @@ lookup_trusted_cert(Ref, SerialNumber, Issuer) ->  issuer_candidate(PrevCandidateKey) ->      ssl_certificate_db:issuer_candidate(PrevCandidateKey).  %%-------------------------------------------------------------------- --spec client_session_id(host(), port_num(), #ssl_options{}) -> session_id(). +-spec client_session_id(host(), port_num(), #ssl_options{}, +			der_cert() | undefined) -> session_id().  %%  %% Description: Select a session id for the client.  %%-------------------------------------------------------------------- -client_session_id(Host, Port, SslOpts) -> -    call({client_session_id, Host, Port, SslOpts}). +client_session_id(Host, Port, SslOpts, OwnCert) -> +    call({client_session_id, Host, Port, SslOpts, OwnCert}).  %%-------------------------------------------------------------------- --spec server_session_id(host(), port_num(), #ssl_options{}) -> session_id(). +-spec server_session_id(host(), port_num(), #ssl_options{}, der_cert()) -> session_id().  %%  %% Description: Select a session id for the server.  %%-------------------------------------------------------------------- -server_session_id(Port, SuggestedSessionId, SslOpts) -> -    call({server_session_id, Port, SuggestedSessionId, SslOpts}). +server_session_id(Port, SuggestedSessionId, SslOpts, OwnCert) -> +    call({server_session_id, Port, SuggestedSessionId, SslOpts, OwnCert}).  %%--------------------------------------------------------------------  -spec register_session(port_num(), #session{}) -> ok. @@ -201,28 +204,35 @@ handle_call({{connection_init, Trustedcerts, _Role}, Pid}, _From,  	end,      {reply, Result, State}; -handle_call({{client_session_id, Host, Port, SslOpts}, _}, _,  +handle_call({{client_session_id, Host, Port, SslOpts, OwnCert}, _}, _,  	    #state{session_cache = Cache,  		  session_cache_cb = CacheCb} = State) -> -    Id = ssl_session:id({Host, Port, SslOpts}, Cache, CacheCb), +    Id = ssl_session:id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),      {reply, Id, State}; -handle_call({{server_session_id, Port, SuggestedSessionId, SslOpts}, _}, +handle_call({{server_session_id, Port, SuggestedSessionId, SslOpts, OwnCert}, _},  	    _, #state{session_cache_cb = CacheCb,  		      session_cache = Cache,  		      session_lifetime = LifeTime} = State) ->      Id = ssl_session:id(Port, SuggestedSessionId, SslOpts, -			Cache, CacheCb, LifeTime), +			Cache, CacheCb, LifeTime, OwnCert),      {reply, Id, State}; -handle_call({{cache_pem, File},Pid}, _, State = #state{certificate_db = Db}) -> -    try ssl_certificate_db:cache_pem_file(Pid,File,Db) of +handle_call({{cache_pem, File, LastWrite}, Pid}, _,  +	    #state{certificate_db = Db} = State) -> +    try ssl_certificate_db:cache_pem_file(Pid, File, LastWrite, Db) of  	Result ->  	    {reply, Result, State}      catch   	_:Reason ->  	    {reply, {error, Reason}, State} -    end. +    end; +handle_call({{recache_pem, File, LastWrite}, Pid}, From, +	    #state{certificate_db = Db} = State) -> +    ssl_certificate_db:uncache_pem_file(File, Db), +    cast({recache_pem, File, LastWrite, Pid, From}), +    {noreply, State}. +  %%--------------------------------------------------------------------  -spec  handle_cast(msg(), #state{}) -> {noreply, #state{}}.  %% Possible return values not used now.   @@ -259,7 +269,21 @@ handle_cast({invalidate_session, Port, #session{session_id = ID}},  	    #state{session_cache = Cache,  		   session_cache_cb = CacheCb} = State) ->      CacheCb:delete(Cache, {Port, ID}), -    {noreply, State}. +    {noreply, State}; + +handle_cast({recache_pem, File, LastWrite, Pid, From}, +	    #state{certificate_db = [_, FileToRefDb, _]} = State0) -> +    case ssl_certificate_db:lookup(File, FileToRefDb) of +	undefined -> +	    {reply, Msg, State} = handle_call({{cache_pem, File, LastWrite}, Pid}, From, State0), +	    gen_server:reply(From, Msg), +	    {noreply, State}; +	_ -> %% Send message to self letting cleanup messages be handled +	     %% first so that no reference to the old version of file +             %% exists when we cache the new one. +	    cast({recache_pem, File, LastWrite, Pid, From}), +	    {noreply, State0} +    end.  %%--------------------------------------------------------------------  -spec handle_info(msg(), #state{}) -> {noreply, #state{}}. @@ -286,12 +310,14 @@ handle_info({'EXIT', _, _}, State) ->  handle_info({'DOWN', _Ref, _Type, _Pid, ecacertfile}, State) ->      {noreply, State}; +handle_info({'DOWN', _Ref, _Type, Pid, shutdown}, State) -> +    handle_info({remove_trusted_certs, Pid}, State);  handle_info({'DOWN', _Ref, _Type, Pid, _Reason}, State) ->      erlang:send_after(?CERTIFICATE_CACHE_CLEANUP, self(),   		      {remove_trusted_certs, Pid}),      {noreply, State};  handle_info({remove_trusted_certs, Pid},  -	    State = #state{certificate_db = Db}) -> +	    #state{certificate_db = Db} = State) ->      ssl_certificate_db:remove_trusted_certs(Pid, Db),      {noreply, State}; @@ -362,3 +388,16 @@ session_validation({{{Host, Port}, _}, Session}, LifeTime) ->  session_validation({{Port, _}, Session}, LifeTime) ->      validate_session(Port, Session, LifeTime),      LifeTime. + +cache_pem_file(File, LastWrite) -> +    case ssl_certificate_db:lookup_cached_certs(File) of +	[{_, {Mtime, Content}}] -> +	    case LastWrite of +		Mtime -> +		    {ok, Content}; +		_ -> +		    call({recache_pem, File, LastWrite}) +	    end; +	[] -> +	    call({cache_pem, File, LastWrite}) +    end. diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl index 25e7445180..dc4b7a711c 100644 --- a/lib/ssl/src/ssl_session.erl +++ b/lib/ssl/src/ssl_session.erl @@ -28,7 +28,7 @@  -include("ssl_internal.hrl").  %% Internal application API --export([is_new/2, id/3, id/6, valid_session/2]). +-export([is_new/2, id/4, id/7, valid_session/2]).  -define(GEN_UNIQUE_ID_MAX_TRIES, 10). @@ -48,13 +48,14 @@ is_new(_ClientSuggestion, _ServerDecision) ->      true.  %%-------------------------------------------------------------------- --spec id({host(), port_num(), #ssl_options{}}, cache_ref(), atom()) -> binary(). +-spec id({host(), port_num(), #ssl_options{}}, cache_ref(), atom(), +	 undefined | binary()) -> binary().  %%  %% Description: Should be called by the client side to get an id   %%              for the client hello message.  %%-------------------------------------------------------------------- -id(ClientInfo, Cache, CacheCb) -> -    case select_session(ClientInfo, Cache, CacheCb) of +id(ClientInfo, Cache, CacheCb, OwnCert) -> +    case select_session(ClientInfo, Cache, CacheCb, OwnCert) of  	no_session ->  	    <<>>;  	SessionId -> @@ -63,19 +64,19 @@ id(ClientInfo, Cache, CacheCb) ->  %%--------------------------------------------------------------------  -spec id(port_num(), binary(), #ssl_options{}, cache_ref(),  -	 atom(), seconds()) -> binary(). +	 atom(), seconds(), binary()) -> binary().  %%  %% Description: Should be called by the server side to get an id   %%              for the server hello message.  %%-------------------------------------------------------------------- -id(Port, <<>>, _, Cache, CacheCb, _) -> +id(Port, <<>>, _, Cache, CacheCb, _, _) ->      new_id(Port, ?GEN_UNIQUE_ID_MAX_TRIES, Cache, CacheCb);  id(Port, SuggestedSessionId, #ssl_options{reuse_sessions = ReuseEnabled,  					  reuse_session = ReuseFun},  -   Cache, CacheCb, SecondLifeTime) -> +   Cache, CacheCb, SecondLifeTime, OwnCert) ->      case is_resumable(SuggestedSessionId, Port, ReuseEnabled,  -		      ReuseFun, Cache, CacheCb, SecondLifeTime) of +		      ReuseFun, Cache, CacheCb, SecondLifeTime, OwnCert) of  	true ->  	    SuggestedSessionId;  	false -> @@ -93,19 +94,20 @@ valid_session(#session{time_stamp = TimeStamp}, LifeTime) ->  %%--------------------------------------------------------------------  %%% Internal functions  %%-------------------------------------------------------------------- -select_session({HostIP, Port, SslOpts}, Cache, CacheCb) ->     +select_session({HostIP, Port, SslOpts}, Cache, CacheCb, OwnCert) ->      Sessions = CacheCb:select_session(Cache, {HostIP, Port}), -    select_session(Sessions, SslOpts). +    select_session(Sessions, SslOpts, OwnCert). -select_session([], _) -> +select_session([], _, _) ->      no_session;  select_session(Sessions, #ssl_options{ciphers = Ciphers, -				      reuse_sessions = ReuseSession}) -> +				      reuse_sessions = ReuseSession}, OwnCert) ->      IsResumable =    	fun(Session) ->    		ReuseSession andalso (Session#session.is_resumable) andalso     		    lists:member(Session#session.cipher_suite, Ciphers) +		    andalso (OwnCert == Session#session.own_certificate)   	end,      case [Id || [Id, Session] <- Sessions, IsResumable(Session)] of   	[] -> @@ -140,14 +142,16 @@ new_id(Port, Tries, Cache, CacheCb) ->      end.  is_resumable(SuggestedSessionId, Port, ReuseEnabled, ReuseFun, Cache,  -	     CacheCb, SecondLifeTime) -> +	     CacheCb, SecondLifeTime, OwnCert) ->      case CacheCb:lookup(Cache, {Port, SuggestedSessionId}) of  	#session{cipher_suite = CipherSuite, +		 own_certificate = SessionOwnCert,  		 compression_method = Compression,  		 is_resumable = Is_resumable,  		 peer_certificate = PeerCert} = Session ->  	    ReuseEnabled   		andalso Is_resumable   +		andalso (OwnCert == SessionOwnCert)  		andalso valid_session(Session, SecondLifeTime)   		andalso ReuseFun(SuggestedSessionId, PeerCert,   				 Compression, CipherSuite); diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl index c49f9f1e6d..f2926b2d2f 100644 --- a/lib/ssl/src/ssl_ssl3.erl +++ b/lib/ssl/src/ssl_ssl3.erl @@ -102,11 +102,6 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, Length, Fragment) ->      %%      hash(MAC_write_secret + pad_1 + seq_num +      %%           SSLCompressed.type + SSLCompressed.length +      %%           SSLCompressed.fragment)); -    case Method of -        ?NULL -> ok; -        _ -> -            ok -    end,      Mac = mac_hash(Method, Mac_write_secret,   		   [<<?UINT64(Seq_num), ?BYTE(Type),   		     ?UINT16(Length)>>, Fragment]), diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl index 3784483e9c..5f9850c386 100644 --- a/lib/ssl/src/ssl_tls1.erl +++ b/lib/ssl/src/ssl_tls1.erl @@ -128,11 +128,6 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},      %% HMAC_hash(MAC_write_secret, seq_num + TLSCompressed.type +      %%              TLSCompressed.version + TLSCompressed.length +      %%              TLSCompressed.fragment)); -    case Method of -        ?NULL -> ok; -        _ -> -            ok -    end,      Mac = hmac_hash(Method, Mac_write_secret,   		    [<<?UINT64(Seq_num), ?BYTE(Type),   		      ?BYTE(Major), ?BYTE(Minor), ?UINT16(Length)>>,  | 
