1*37da2899SCharles.Forsyth# 2*37da2899SCharles.Forsyth# SSL Session Cache 3*37da2899SCharles.Forsyth# 4*37da2899SCharles.Forsythimplement SSLsession; 5*37da2899SCharles.Forsyth 6*37da2899SCharles.Forsythinclude "sys.m"; 7*37da2899SCharles.Forsyth sys : Sys; 8*37da2899SCharles.Forsyth 9*37da2899SCharles.Forsythinclude "daytime.m"; 10*37da2899SCharles.Forsyth daytime : Daytime; 11*37da2899SCharles.Forsyth 12*37da2899SCharles.Forsythinclude "sslsession.m"; 13*37da2899SCharles.Forsyth 14*37da2899SCharles.Forsyth 15*37da2899SCharles.Forsyth# default session id timeout 16*37da2899SCharles.ForsythTIMEOUT_SECS : con 5*60; # sec 17*37da2899SCharles.Forsyth 18*37da2899SCharles.ForsythSessionCache: adt { 19*37da2899SCharles.Forsyth db : list of ref Session; 20*37da2899SCharles.Forsyth time_out : int; 21*37da2899SCharles.Forsyth}; 22*37da2899SCharles.Forsyth 23*37da2899SCharles.Forsyth# The shared session cache by all ssl contexts is available for efficiently resumming 24*37da2899SCharles.Forsyth# sessions for different run time contexts. 25*37da2899SCharles.Forsyth 26*37da2899SCharles.ForsythSession_Cache : ref SessionCache; 27*37da2899SCharles.Forsyth 28*37da2899SCharles.Forsyth 29*37da2899SCharles.Forsythinit(): string 30*37da2899SCharles.Forsyth{ 31*37da2899SCharles.Forsyth sys = load Sys Sys->PATH; 32*37da2899SCharles.Forsyth if(sys == nil) 33*37da2899SCharles.Forsyth return "sslsession: load sys module failed"; 34*37da2899SCharles.Forsyth 35*37da2899SCharles.Forsyth daytime = load Daytime Daytime->PATH; 36*37da2899SCharles.Forsyth if(daytime == nil) 37*37da2899SCharles.Forsyth return "sslsession: load Daytime module failed"; 38*37da2899SCharles.Forsyth 39*37da2899SCharles.Forsyth Session_Cache = ref SessionCache(nil, TIMEOUT_SECS); 40*37da2899SCharles.Forsyth 41*37da2899SCharles.Forsyth return ""; 42*37da2899SCharles.Forsyth} 43*37da2899SCharles.Forsyth 44*37da2899SCharles.ForsythSession.new(peer: string, time: int, ver: array of byte): ref Session 45*37da2899SCharles.Forsyth{ 46*37da2899SCharles.Forsyth s := ref Session; 47*37da2899SCharles.Forsyth 48*37da2899SCharles.Forsyth s.peer = peer; 49*37da2899SCharles.Forsyth s.connection_time = time; 50*37da2899SCharles.Forsyth s.version = array [2] of byte; 51*37da2899SCharles.Forsyth s.version[0:] = ver; 52*37da2899SCharles.Forsyth s.session_id = nil; 53*37da2899SCharles.Forsyth s.suite = nil; 54*37da2899SCharles.Forsyth s.master_secret = nil; 55*37da2899SCharles.Forsyth s.peer_certs = nil; 56*37da2899SCharles.Forsyth 57*37da2899SCharles.Forsyth return s; 58*37da2899SCharles.Forsyth} 59*37da2899SCharles.Forsyth 60*37da2899SCharles.ForsythSession.duplicate(s: self ref Session): ref Session 61*37da2899SCharles.Forsyth{ 62*37da2899SCharles.Forsyth new := ref Session; 63*37da2899SCharles.Forsyth 64*37da2899SCharles.Forsyth new.peer = s.peer; 65*37da2899SCharles.Forsyth new.connection_time = s.connection_time; 66*37da2899SCharles.Forsyth new.version = array [len s.version] of byte; 67*37da2899SCharles.Forsyth new.version[0:] = s.version; 68*37da2899SCharles.Forsyth new.session_id = array [len s.session_id] of byte; 69*37da2899SCharles.Forsyth new.session_id[0:] = s.session_id; 70*37da2899SCharles.Forsyth new.suite = array [len s.suite] of byte; 71*37da2899SCharles.Forsyth new.suite[0:] = s.suite; 72*37da2899SCharles.Forsyth new.master_secret = array [len s.master_secret] of byte; 73*37da2899SCharles.Forsyth new.master_secret[0:] = s.master_secret; 74*37da2899SCharles.Forsyth l: list of array of byte; 75*37da2899SCharles.Forsyth pcs := s.peer_certs; 76*37da2899SCharles.Forsyth while(pcs != nil) { 77*37da2899SCharles.Forsyth a := hd pcs; 78*37da2899SCharles.Forsyth b := array [len a] of byte; 79*37da2899SCharles.Forsyth b[0:] = a; 80*37da2899SCharles.Forsyth l = b :: l; 81*37da2899SCharles.Forsyth pcs = tl pcs; 82*37da2899SCharles.Forsyth } 83*37da2899SCharles.Forsyth while(l != nil) { 84*37da2899SCharles.Forsyth new.peer_certs = (hd l) :: new.peer_certs; 85*37da2899SCharles.Forsyth l = tl l; 86*37da2899SCharles.Forsyth } 87*37da2899SCharles.Forsyth return new; 88*37da2899SCharles.Forsyth} 89*37da2899SCharles.Forsyth 90*37da2899SCharles.Forsyth# Each request process should get a copy of a session. A session will be 91*37da2899SCharles.Forsyth# removed from database if it is expired. The garbage 92*37da2899SCharles.Forsyth# collector will finally remove it from memory if there are no more 93*37da2899SCharles.Forsyth# references to it. 94*37da2899SCharles.Forsyth 95*37da2899SCharles.Forsythget_session_byname(peer: string): ref Session 96*37da2899SCharles.Forsyth{ 97*37da2899SCharles.Forsyth s: ref Session; 98*37da2899SCharles.Forsyth now := daytime->now(); # not accurate but more efficient 99*37da2899SCharles.Forsyth 100*37da2899SCharles.Forsyth l := Session_Cache.db; 101*37da2899SCharles.Forsyth while(l != nil) { 102*37da2899SCharles.Forsyth if((hd l).peer == peer) { 103*37da2899SCharles.Forsyth s = hd l; 104*37da2899SCharles.Forsyth # TODO: remove expired session 105*37da2899SCharles.Forsyth if(now > s.connection_time+Session_Cache.time_out) 106*37da2899SCharles.Forsyth s = nil; 107*37da2899SCharles.Forsyth break; 108*37da2899SCharles.Forsyth } 109*37da2899SCharles.Forsyth l = tl l; 110*37da2899SCharles.Forsyth } 111*37da2899SCharles.Forsyth if(s == nil) 112*37da2899SCharles.Forsyth s = Session.new(peer, now, nil); 113*37da2899SCharles.Forsyth else 114*37da2899SCharles.Forsyth s = s.duplicate(); 115*37da2899SCharles.Forsyth 116*37da2899SCharles.Forsyth return s; 117*37da2899SCharles.Forsyth} 118*37da2899SCharles.Forsyth 119*37da2899SCharles.Forsyth# replace the old by the new one 120*37da2899SCharles.Forsythadd_session(s: ref Session) 121*37da2899SCharles.Forsyth{ 122*37da2899SCharles.Forsyth #old : ref Session; 123*37da2899SCharles.Forsyth 124*37da2899SCharles.Forsyth #ls := Session_Cache.db; 125*37da2899SCharles.Forsyth #while(ls != nil) { 126*37da2899SCharles.Forsyth # old = hd ls; 127*37da2899SCharles.Forsyth # if(s.session_id == old.session_id) { 128*37da2899SCharles.Forsyth # # old = s; 129*37da2899SCharles.Forsyth # return; 130*37da2899SCharles.Forsyth # } 131*37da2899SCharles.Forsyth #} 132*37da2899SCharles.Forsyth 133*37da2899SCharles.Forsyth # always resume the most recent 134*37da2899SCharles.Forsyth if(s != nil) 135*37da2899SCharles.Forsyth Session_Cache.db = s :: Session_Cache.db; 136*37da2899SCharles.Forsyth} 137*37da2899SCharles.Forsyth 138*37da2899SCharles.Forsythget_session_byid(session_id: array of byte): ref Session 139*37da2899SCharles.Forsyth{ 140*37da2899SCharles.Forsyth s: ref Session; 141*37da2899SCharles.Forsyth now := daytime->now(); # not accurate but more efficient 142*37da2899SCharles.Forsyth l := Session_Cache.db; 143*37da2899SCharles.Forsyth while(l != nil) { 144*37da2899SCharles.Forsyth if(bytes_cmp((hd l).session_id, session_id) == 0) { 145*37da2899SCharles.Forsyth s = hd l; 146*37da2899SCharles.Forsyth # replace expired session 147*37da2899SCharles.Forsyth if(now > s.connection_time+Session_Cache.time_out) 148*37da2899SCharles.Forsyth s = Session.new(s.peer, now, nil); 149*37da2899SCharles.Forsyth else 150*37da2899SCharles.Forsyth s = s.duplicate(); 151*37da2899SCharles.Forsyth break; 152*37da2899SCharles.Forsyth } 153*37da2899SCharles.Forsyth l = tl l; 154*37da2899SCharles.Forsyth } 155*37da2899SCharles.Forsyth return s; 156*37da2899SCharles.Forsyth} 157*37da2899SCharles.Forsyth 158*37da2899SCharles.Forsythset_timeout(t: int) 159*37da2899SCharles.Forsyth{ 160*37da2899SCharles.Forsyth Session_Cache.time_out = t; 161*37da2899SCharles.Forsyth} 162*37da2899SCharles.Forsyth 163*37da2899SCharles.Forsythbytes_cmp(a, b: array of byte): int 164*37da2899SCharles.Forsyth{ 165*37da2899SCharles.Forsyth if(len a != len b) 166*37da2899SCharles.Forsyth return -1; 167*37da2899SCharles.Forsyth 168*37da2899SCharles.Forsyth n := len a; 169*37da2899SCharles.Forsyth for(i := 0; i < n; i++) { 170*37da2899SCharles.Forsyth if(a[i] != b[i]) 171*37da2899SCharles.Forsyth return -1; 172*37da2899SCharles.Forsyth } 173*37da2899SCharles.Forsyth 174*37da2899SCharles.Forsyth return 0; 175*37da2899SCharles.Forsyth} 176*37da2899SCharles.Forsyth 177