diff options
Diffstat (limited to 'appl/lib/crypt/sslsession.b')
| -rw-r--r-- | appl/lib/crypt/sslsession.b | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/appl/lib/crypt/sslsession.b b/appl/lib/crypt/sslsession.b new file mode 100644 index 00000000..cce8399e --- /dev/null +++ b/appl/lib/crypt/sslsession.b @@ -0,0 +1,176 @@ +# +# SSL Session Cache +# +implement SSLsession; + +include "sys.m"; + sys : Sys; + +include "daytime.m"; + daytime : Daytime; + +include "sslsession.m"; + + +# default session id timeout +TIMEOUT_SECS : con 5*60; # sec + +SessionCache: adt { + db : list of ref Session; + time_out : int; +}; + +# The shared session cache by all ssl contexts is available for efficiently resumming +# sessions for different run time contexts. + +Session_Cache : ref SessionCache; + + +init(): string +{ + sys = load Sys Sys->PATH; + if(sys == nil) + return "sslsession: load sys module failed"; + + daytime = load Daytime Daytime->PATH; + if(daytime == nil) + return "sslsession: load Daytime module failed"; + + Session_Cache = ref SessionCache(nil, TIMEOUT_SECS); + + return ""; +} + +Session.new(peer: string, time: int, ver: array of byte): ref Session +{ + s := ref Session; + + s.peer = peer; + s.connection_time = time; + s.version = array [2] of byte; + s.version[0:] = ver; + s.session_id = nil; + s.suite = nil; + s.master_secret = nil; + s.peer_certs = nil; + + return s; +} + +Session.duplicate(s: self ref Session): ref Session +{ + new := ref Session; + + new.peer = s.peer; + new.connection_time = s.connection_time; + new.version = array [len s.version] of byte; + new.version[0:] = s.version; + new.session_id = array [len s.session_id] of byte; + new.session_id[0:] = s.session_id; + new.suite = array [len s.suite] of byte; + new.suite[0:] = s.suite; + new.master_secret = array [len s.master_secret] of byte; + new.master_secret[0:] = s.master_secret; + l: list of array of byte; + pcs := s.peer_certs; + while(pcs != nil) { + a := hd pcs; + b := array [len a] of byte; + b[0:] = a; + l = b :: l; + pcs = tl pcs; + } + while(l != nil) { + new.peer_certs = (hd l) :: new.peer_certs; + l = tl l; + } + return new; +} + +# Each request process should get a copy of a session. A session will be +# removed from database if it is expired. The garbage +# collector will finally remove it from memory if there are no more +# references to it. + +get_session_byname(peer: string): ref Session +{ + s: ref Session; + now := daytime->now(); # not accurate but more efficient + + l := Session_Cache.db; + while(l != nil) { + if((hd l).peer == peer) { + s = hd l; + # TODO: remove expired session + if(now > s.connection_time+Session_Cache.time_out) + s = nil; + break; + } + l = tl l; + } + if(s == nil) + s = Session.new(peer, now, nil); + else + s = s.duplicate(); + + return s; +} + +# replace the old by the new one +add_session(s: ref Session) +{ + #old : ref Session; + + #ls := Session_Cache.db; + #while(ls != nil) { + # old = hd ls; + # if(s.session_id == old.session_id) { + # # old = s; + # return; + # } + #} + + # always resume the most recent + if(s != nil) + Session_Cache.db = s :: Session_Cache.db; +} + +get_session_byid(session_id: array of byte): ref Session +{ + s: ref Session; + now := daytime->now(); # not accurate but more efficient + l := Session_Cache.db; + while(l != nil) { + if(bytes_cmp((hd l).session_id, session_id) == 0) { + s = hd l; + # replace expired session + if(now > s.connection_time+Session_Cache.time_out) + s = Session.new(s.peer, now, nil); + else + s = s.duplicate(); + break; + } + l = tl l; + } + return s; +} + +set_timeout(t: int) +{ + Session_Cache.time_out = t; +} + +bytes_cmp(a, b: array of byte): int +{ + if(len a != len b) + return -1; + + n := len a; + for(i := 0; i < n; i++) { + if(a[i] != b[i]) + return -1; + } + + return 0; +} + |
