2
* This file implements the CLIENT Session ID cache.
4
* The contents of this file are subject to the Mozilla Public
5
* License Version 1.1 (the "License"); you may not use this file
6
* except in compliance with the License. You may obtain a copy of
7
* the License at http://www.mozilla.org/MPL/
9
* Software distributed under the License is distributed on an "AS
10
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11
* implied. See the License for the specific language governing
12
* rights and limitations under the License.
14
* The Original Code is the Netscape security libraries.
16
* The Initial Developer of the Original Code is Netscape
17
* Communications Corporation. Portions created by Netscape are
18
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
23
* Alternatively, the contents of this file may be used under the
24
* terms of the GNU General Public License Version 2 or later (the
25
* "GPL"), in which case the provisions of the GPL are applicable
26
* instead of those above. If you wish to allow use of your
27
* version of this file only under the terms of the GPL and not to
28
* allow others to use your version of this file under the MPL,
29
* indicate your decision by deleting the provisions above and
30
* replace them with the notice and other provisions required by
31
* the GPL. If you do not delete the provisions above, a recipient
32
* may use your version of this file under either the MPL or the
35
* $Id: sslnonce.c,v 1.12.106.1 2004/10/15 21:13:57 wchang0222%aol.com Exp $
47
#if (defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS)) && !defined(_WIN32_WCE)
51
PRUint32 ssl_sid_timeout = 100;
52
PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */
54
static sslSessionID *cache = NULL;
55
static PZLock * cacheLock = NULL;
57
/* sids can be in one of 4 states:
59
* never_cached, created, but not yet put into cache.
60
* in_client_cache, in the client cache's linked list.
61
* in_server_cache, entry came from the server's cache file.
62
* invalid_cache has been removed from the cache.
65
#define LOCK_CACHE lock_cache()
66
#define UNLOCK_CACHE PZ_Unlock(cacheLock)
68
void ssl_InitClientSessionCacheLock(void)
71
nss_InitLock(&cacheLock, nssILockCache);
77
ssl_InitClientSessionCacheLock();
81
/* BEWARE: This function gets called for both client and server SIDs !!
82
* If the unreferenced sid is not in the cache, Free sid and its contents.
85
ssl_DestroySID(sslSessionID *sid)
87
SSL_TRC(8, ("SSL: destroy sid: sid=0x%x cached=%d", sid, sid->cached));
88
PORT_Assert((sid->references == 0));
90
if (sid->cached == in_client_cache)
91
return; /* it will get taken care of next time cache is traversed. */
93
if (sid->version < SSL_LIBRARY_VERSION_3_0) {
94
SECITEM_ZfreeItem(&sid->u.ssl2.masterKey, PR_FALSE);
95
SECITEM_ZfreeItem(&sid->u.ssl2.cipherArg, PR_FALSE);
97
if (sid->peerID != NULL)
98
PORT_Free((void *)sid->peerID); /* CONST */
100
if (sid->urlSvrName != NULL)
101
PORT_Free((void *)sid->urlSvrName); /* CONST */
103
if ( sid->peerCert ) {
104
CERT_DestroyCertificate(sid->peerCert);
106
if ( sid->localCert ) {
107
CERT_DestroyCertificate(sid->localCert);
110
PORT_ZFree(sid, sizeof(sslSessionID));
113
/* BEWARE: This function gets called for both client and server SIDs !!
114
* Decrement reference count, and
115
* free sid if ref count is zero, and sid is not in the cache.
116
* Does NOT remove from the cache first.
117
* If the sid is still in the cache, it is left there until next time
118
* the cache list is traversed.
121
ssl_FreeLockedSID(sslSessionID *sid)
123
PORT_Assert(sid->references >= 1);
124
if (--sid->references == 0) {
129
/* BEWARE: This function gets called for both client and server SIDs !!
130
* Decrement reference count, and
131
* free sid if ref count is zero, and sid is not in the cache.
132
* Does NOT remove from the cache first.
133
* These locks are necessary because the sid _might_ be in the cache list.
136
ssl_FreeSID(sslSessionID *sid)
139
ssl_FreeLockedSID(sid);
143
/************************************************************************/
146
** Lookup sid entry in cache by Address, port, and peerID string.
147
** If found, Increment reference count, and return pointer to caller.
148
** If it has timed out or ref count is zero, remove from list and free it.
152
ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID,
153
const char * urlSvrName)
164
while ((sid = *sidp) != 0) {
165
PORT_Assert(sid->cached == in_client_cache);
166
PORT_Assert(sid->references >= 1);
168
SSL_TRC(8, ("SSL: Lookup1: sid=0x%x", sid));
170
if (sid->expirationTime < now || !sid->references) {
172
** This session-id timed out, or was orphaned.
173
** Don't even care who it belongs to, blow it out of our cache.
175
SSL_TRC(7, ("SSL: lookup1, throwing sid out, age=%d refs=%d",
176
now - sid->creationTime, sid->references));
178
*sidp = sid->next; /* delink it from the list. */
179
sid->cached = invalid_cache; /* mark not on list. */
180
if (!sid->references)
183
ssl_FreeLockedSID(sid); /* drop ref count, free. */
185
} else if (!memcmp(&sid->addr, addr, sizeof(PRIPv6Addr)) && /* server IP addr matches */
186
(sid->port == port) && /* server port matches */
187
/* proxy (peerID) matches */
188
(((peerID == NULL) && (sid->peerID == NULL)) ||
189
((peerID != NULL) && (sid->peerID != NULL) &&
190
PORT_Strcmp(sid->peerID, peerID) == 0)) &&
192
(sid->version < SSL_LIBRARY_VERSION_3_0 ||
193
sid->u.ssl3.resumable) &&
194
/* server hostname matches. */
195
(sid->urlSvrName != NULL) &&
196
((0 == PORT_Strcmp(urlSvrName, sid->urlSvrName)) ||
197
((sid->peerCert != NULL) && (SECSuccess ==
198
CERT_VerifyCertName(sid->peerCert, urlSvrName))) )
201
sid->lastAccessTime = now;
213
** Add an sid to the cache or return a previously cached entry to the cache.
214
** Although this is static, it is called via ss->sec.cache().
217
CacheSID(sslSessionID *sid)
219
PRUint32 expirationPeriod;
220
SSL_TRC(8, ("SSL: Cache: sid=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x "
222
sid, sid->cached, sid->addr.pr_s6_addr32[0],
223
sid->addr.pr_s6_addr32[1], sid->addr.pr_s6_addr32[2],
224
sid->addr.pr_s6_addr32[3], sid->port, sid->creationTime,
227
if (sid->cached == in_client_cache)
230
/* XXX should be different trace for version 2 vs. version 3 */
231
if (sid->version < SSL_LIBRARY_VERSION_3_0) {
232
expirationPeriod = ssl_sid_timeout;
233
PRINT_BUF(8, (0, "sessionID:",
234
sid->u.ssl2.sessionID, sizeof(sid->u.ssl2.sessionID)));
235
PRINT_BUF(8, (0, "masterKey:",
236
sid->u.ssl2.masterKey.data, sid->u.ssl2.masterKey.len));
237
PRINT_BUF(8, (0, "cipherArg:",
238
sid->u.ssl2.cipherArg.data, sid->u.ssl2.cipherArg.len));
240
if (sid->u.ssl3.sessionIDLength == 0)
242
expirationPeriod = ssl3_sid_timeout;
243
PRINT_BUF(8, (0, "sessionID:",
244
sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength));
246
PORT_Assert(sid->creationTime != 0 && sid->expirationTime != 0);
247
if (!sid->creationTime)
248
sid->lastAccessTime = sid->creationTime = ssl_Time();
249
if (!sid->expirationTime)
250
sid->expirationTime = sid->creationTime + expirationPeriod;
253
* Put sid into the cache. Bump reference count to indicate that
254
* cache is holding a reference. Uncache will reduce the cache
259
sid->cached = in_client_cache;
266
* If sid "zap" is in the cache,
267
* removes sid from cache, and decrements reference count.
268
* Caller must hold cache lock.
271
UncacheSID(sslSessionID *zap)
273
sslSessionID **sidp = &cache;
276
if (zap->cached != in_client_cache) {
280
SSL_TRC(8,("SSL: Uncache: zap=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x "
282
zap, zap->cached, zap->addr.pr_s6_addr32[0],
283
zap->addr.pr_s6_addr32[1], zap->addr.pr_s6_addr32[2],
284
zap->addr.pr_s6_addr32[3], zap->port, zap->creationTime,
285
zap->u.ssl2.cipherType));
286
if (zap->version < SSL_LIBRARY_VERSION_3_0) {
287
PRINT_BUF(8, (0, "sessionID:",
288
zap->u.ssl2.sessionID, sizeof(zap->u.ssl2.sessionID)));
289
PRINT_BUF(8, (0, "masterKey:",
290
zap->u.ssl2.masterKey.data, zap->u.ssl2.masterKey.len));
291
PRINT_BUF(8, (0, "cipherArg:",
292
zap->u.ssl2.cipherArg.data, zap->u.ssl2.cipherArg.len));
295
/* See if it's in the cache, if so nuke it */
296
while ((sid = *sidp) != 0) {
299
** Bingo. Reduce reference count by one so that when
300
** everyone is done with the sid we can free it up.
303
zap->cached = invalid_cache;
304
ssl_FreeLockedSID(zap);
311
/* If sid "zap" is in the cache,
312
* removes sid from cache, and decrements reference count.
313
* Although this function is static, it is called externally via
317
LockAndUncacheSID(sslSessionID *zap)
325
/* choose client or server cache functions for this sslsocket. */
327
ssl_ChooseSessionIDProcs(sslSecurityInfo *sec)
330
sec->cache = ssl_sid_cache;
331
sec->uncache = ssl_sid_uncache;
333
sec->cache = CacheSID;
334
sec->uncache = LockAndUncacheSID;
338
/* wipe out the entire client session cache. */
340
SSL_ClearSessionCache(void)
348
/* returns an unsigned int containing the number of seconds in PR_Now() */
353
#if (defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS)) && !defined(_WIN32_WCE)
354
myTime = time(NULL); /* accurate until the year 2038. */
356
/* portable, but possibly slower */
361
LL_I2L(ll, 1000000L);
362
LL_DIV(now, now, ll);
363
LL_L2UI(myTime, now);