diff options
author | Erlang/OTP <otp@erlang.org> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <otp@erlang.org> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/ssl/src/ssl_session.erl | |
download | otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2 otp-84adefa331c4159d432d22840663c38f155cd4c1.zip |
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/ssl/src/ssl_session.erl')
-rw-r--r-- | lib/ssl/src/ssl_session.erl | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl new file mode 100644 index 0000000000..bcb10daf69 --- /dev/null +++ b/lib/ssl/src/ssl_session.erl @@ -0,0 +1,172 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2007-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Handles ssl sessions +%%---------------------------------------------------------------------- + +-module(ssl_session). + +-include("ssl_handshake.hrl"). +-include("ssl_internal.hrl"). + +%% Internal application API +-export([is_new/2, id/3, id/6, valid_session/2]). + +-define(GEN_UNIQUE_ID_MAX_TRIES, 10). + +%%-------------------------------------------------------------------- +%% Function: is_new(ClientSuggestedId, ServerDecidedId) -> true | false +%% +%% ClientSuggestedId = binary() +%% ServerDecidedId = binary() +%% +%% Description: Checks if the session id decided by the server is a +%% new or resumed sesion id. +%%-------------------------------------------------------------------- +is_new(<<>>, _) -> + true; +is_new(SessionId, SessionId) -> + false; +is_new(_, _) -> + true. + +%%-------------------------------------------------------------------- +%% Function: id(ClientInfo, Cache, CacheCb) -> SessionId +%% +%% ClientInfo = {HostIP, Port, SslOpts} +%% HostIP = ipadress() +%% Port = integer() +%% CacheCb = atom() +%% SessionId = 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 + no_session -> + <<>>; + SessionId -> + SessionId + end. + +%%-------------------------------------------------------------------- +%% Function: id(Port, SuggestedSessionId, ReuseFun, CacheCb, +%% SecondLifeTime) -> SessionId +%% +%% Port = integer() +%% SuggestedSessionId = SessionId = binary() +%% ReuseFun = fun(SessionId, PeerCert, Compression, CipherSuite) -> +%% true | false +%% CacheCb = atom() +%% +%% Description: Should be called by the server side to get an id +%% for the server hello message. +%%-------------------------------------------------------------------- +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) -> + case is_resumable(SuggestedSessionId, Port, ReuseEnabled, + ReuseFun, Cache, CacheCb, SecondLifeTime) of + true -> + SuggestedSessionId; + false -> + new_id(Port, ?GEN_UNIQUE_ID_MAX_TRIES, Cache, CacheCb) + end. +%%-------------------------------------------------------------------- +%% Function: valid_session(Session, LifeTime) -> true | false +%% +%% Session = #session{} +%% LifeTime = integer() - seconds +%% +%% Description: Check that the session has not expired +%%-------------------------------------------------------------------- +valid_session(#session{time_stamp = TimeStamp}, LifeTime) -> + Now = calendar:datetime_to_gregorian_seconds({date(), time()}), + Now - TimeStamp < LifeTime. + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +select_session({HostIP, Port, SslOpts}, Cache, CacheCb) -> + Sessions = CacheCb:select_session(Cache, {HostIP, Port}), + select_session(Sessions, SslOpts). + +select_session([], _) -> + no_session; + +select_session(Sessions, #ssl_options{ciphers = Ciphers, + reuse_sessions = ReuseSession}) -> + IsResumable = + fun(Session) -> + ReuseSession andalso (Session#session.is_resumable) andalso + lists:member(Session#session.cipher_suite, Ciphers) + end, + case [Id || [Id, Session] <- Sessions, IsResumable(Session)] of + [] -> + no_session; + List -> + hd(List) + end. + +%% If we can not generate a not allready in use session ID in +%% ?GEN_UNIQUE_ID_MAX_TRIES we make the new session uncacheable The +%% value of ?GEN_UNIQUE_ID_MAX_TRIES is stolen from open SSL which +%% states : "If we can not find a session id in +%% ?GEN_UNIQUE_ID_MAX_TRIES either the RAND code is broken or someone +%% is trying to open roughly very close to 2^128 (or 2^256) SSL +%% sessions to our server" +new_id(_, 0, _, _) -> + <<>>; +new_id(Port, Tries, Cache, CacheCb) -> + Id = crypto:rand_bytes(?NUM_OF_SESSION_ID_BYTES), + case CacheCb:lookup(Cache, {Port, Id}) of + undefined -> + Now = calendar:datetime_to_gregorian_seconds({date(), time()}), + %% New sessions can not be set to resumable + %% until handshake is compleate and the + %% other session values are set. + CacheCb:update(Cache, {Port, Id}, #session{session_id = Id, + is_resumable = false, + time_stamp = Now}), + Id; + _ -> + new_id(Port, Tries - 1, Cache, CacheCb) + end. + +is_resumable(SuggestedSessionId, Port, ReuseEnabled, ReuseFun, Cache, + CacheCb, SecondLifeTime) -> + case CacheCb:lookup(Cache, {Port, SuggestedSessionId}) of + #session{cipher_suite = CipherSuite, + compression_method = Compression, + is_resumable = Is_resumable, + peer_certificate = PeerCert} = Session -> + ReuseEnabled + andalso Is_resumable + andalso valid_session(Session, SecondLifeTime) + andalso ReuseFun(SuggestedSessionId, PeerCert, + Compression, CipherSuite); + undefined -> + false + end. |