~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/security/nss/lib/ssl/sslnonce.c

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 * This file implements the CLIENT Session ID cache.  
 
3
 *
 
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/
 
8
 * 
 
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.
 
13
 * 
 
14
 * The Original Code is the Netscape security libraries.
 
15
 * 
 
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
 
19
 * Rights Reserved.
 
20
 * 
 
21
 * Contributor(s):
 
22
 * 
 
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
 
33
 * GPL.
 
34
 *
 
35
 * $Id: sslnonce.c,v 1.12.106.1 2004/10/15 21:13:57 wchang0222%aol.com Exp $
 
36
 */
 
37
 
 
38
#include "nssrenam.h"
 
39
#include "cert.h"
 
40
#include "secitem.h"
 
41
#include "ssl.h"
 
42
 
 
43
#include "sslimpl.h"
 
44
#include "sslproto.h"
 
45
#include "nssilock.h"
 
46
#include "nsslocks.h"
 
47
#if (defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS)) && !defined(_WIN32_WCE)
 
48
#include <time.h>
 
49
#endif
 
50
 
 
51
PRUint32 ssl_sid_timeout = 100;
 
52
PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */
 
53
 
 
54
static sslSessionID *cache = NULL;
 
55
static PZLock *      cacheLock = NULL;
 
56
 
 
57
/* sids can be in one of 4 states:
 
58
 *
 
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. 
 
63
 */
 
64
 
 
65
#define LOCK_CACHE      lock_cache()
 
66
#define UNLOCK_CACHE    PZ_Unlock(cacheLock)
 
67
 
 
68
void ssl_InitClientSessionCacheLock(void)
 
69
{
 
70
    if (!cacheLock)
 
71
        nss_InitLock(&cacheLock, nssILockCache);
 
72
}
 
73
 
 
74
static void 
 
75
lock_cache(void)
 
76
{
 
77
    ssl_InitClientSessionCacheLock();
 
78
    PZ_Lock(cacheLock);
 
79
}
 
80
 
 
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.
 
83
 */
 
84
static void
 
85
ssl_DestroySID(sslSessionID *sid)
 
86
{
 
87
    SSL_TRC(8, ("SSL: destroy sid: sid=0x%x cached=%d", sid, sid->cached));
 
88
    PORT_Assert((sid->references == 0));
 
89
 
 
90
    if (sid->cached == in_client_cache)
 
91
        return; /* it will get taken care of next time cache is traversed. */
 
92
 
 
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);
 
96
    }
 
97
    if (sid->peerID != NULL)
 
98
        PORT_Free((void *)sid->peerID);         /* CONST */
 
99
 
 
100
    if (sid->urlSvrName != NULL)
 
101
        PORT_Free((void *)sid->urlSvrName);     /* CONST */
 
102
 
 
103
    if ( sid->peerCert ) {
 
104
        CERT_DestroyCertificate(sid->peerCert);
 
105
    }
 
106
    if ( sid->localCert ) {
 
107
        CERT_DestroyCertificate(sid->localCert);
 
108
    }
 
109
    
 
110
    PORT_ZFree(sid, sizeof(sslSessionID));
 
111
}
 
112
 
 
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.
 
119
 */
 
120
static void 
 
121
ssl_FreeLockedSID(sslSessionID *sid)
 
122
{
 
123
    PORT_Assert(sid->references >= 1);
 
124
    if (--sid->references == 0) {
 
125
        ssl_DestroySID(sid);
 
126
    }
 
127
}
 
128
 
 
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.
 
134
 */
 
135
void
 
136
ssl_FreeSID(sslSessionID *sid)
 
137
{
 
138
    LOCK_CACHE;
 
139
    ssl_FreeLockedSID(sid);
 
140
    UNLOCK_CACHE;
 
141
}
 
142
 
 
143
/************************************************************************/
 
144
 
 
145
/*
 
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.
 
149
*/
 
150
 
 
151
sslSessionID *
 
152
ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID, 
 
153
              const char * urlSvrName)
 
154
{
 
155
    sslSessionID **sidp;
 
156
    sslSessionID * sid;
 
157
    PRUint32       now;
 
158
 
 
159
    if (!urlSvrName)
 
160
        return NULL;
 
161
    now = ssl_Time();
 
162
    LOCK_CACHE;
 
163
    sidp = &cache;
 
164
    while ((sid = *sidp) != 0) {
 
165
        PORT_Assert(sid->cached == in_client_cache);
 
166
        PORT_Assert(sid->references >= 1);
 
167
 
 
168
        SSL_TRC(8, ("SSL: Lookup1: sid=0x%x", sid));
 
169
 
 
170
        if (sid->expirationTime < now || !sid->references) {
 
171
            /*
 
172
            ** This session-id timed out, or was orphaned.
 
173
            ** Don't even care who it belongs to, blow it out of our cache.
 
174
            */
 
175
            SSL_TRC(7, ("SSL: lookup1, throwing sid out, age=%d refs=%d",
 
176
                        now - sid->creationTime, sid->references));
 
177
 
 
178
            *sidp = sid->next;                  /* delink it from the list. */
 
179
            sid->cached = invalid_cache;        /* mark not on list. */
 
180
            if (!sid->references)
 
181
                ssl_DestroySID(sid);
 
182
            else
 
183
                ssl_FreeLockedSID(sid);         /* drop ref count, free. */
 
184
 
 
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)) &&
 
191
                   /* is cacheable */
 
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))) )
 
199
                  ) {
 
200
            /* Hit */
 
201
            sid->lastAccessTime = now;
 
202
            sid->references++;
 
203
            break;
 
204
        } else {
 
205
            sidp = &sid->next;
 
206
        }
 
207
    }
 
208
    UNLOCK_CACHE;
 
209
    return sid;
 
210
}
 
211
 
 
212
/*
 
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().
 
215
*/
 
216
static void 
 
217
CacheSID(sslSessionID *sid)
 
218
{
 
219
    PRUint32  expirationPeriod;
 
220
    SSL_TRC(8, ("SSL: Cache: sid=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x "
 
221
                "time=%x cached=%d",
 
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,
 
225
                sid->cached));
 
226
 
 
227
    if (sid->cached == in_client_cache)
 
228
        return;
 
229
 
 
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));
 
239
    } else {
 
240
        if (sid->u.ssl3.sessionIDLength == 0) 
 
241
            return;
 
242
        expirationPeriod = ssl3_sid_timeout;
 
243
        PRINT_BUF(8, (0, "sessionID:",
 
244
                      sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength));
 
245
    }
 
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;
 
251
 
 
252
    /*
 
253
     * Put sid into the cache.  Bump reference count to indicate that
 
254
     * cache is holding a reference. Uncache will reduce the cache
 
255
     * reference.
 
256
     */
 
257
    LOCK_CACHE;
 
258
    sid->references++;
 
259
    sid->cached = in_client_cache;
 
260
    sid->next   = cache;
 
261
    cache       = sid;
 
262
    UNLOCK_CACHE;
 
263
}
 
264
 
 
265
/* 
 
266
 * If sid "zap" is in the cache,
 
267
 *    removes sid from cache, and decrements reference count.
 
268
 * Caller must hold cache lock.
 
269
 */
 
270
static void
 
271
UncacheSID(sslSessionID *zap)
 
272
{
 
273
    sslSessionID **sidp = &cache;
 
274
    sslSessionID *sid;
 
275
 
 
276
    if (zap->cached != in_client_cache) {
 
277
        return;
 
278
    }
 
279
 
 
280
    SSL_TRC(8,("SSL: Uncache: zap=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x "
 
281
               "time=%x cipher=%d",
 
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));
 
293
    }
 
294
 
 
295
    /* See if it's in the cache, if so nuke it */
 
296
    while ((sid = *sidp) != 0) {
 
297
        if (sid == zap) {
 
298
            /*
 
299
            ** Bingo. Reduce reference count by one so that when
 
300
            ** everyone is done with the sid we can free it up.
 
301
            */
 
302
            *sidp = zap->next;
 
303
            zap->cached = invalid_cache;
 
304
            ssl_FreeLockedSID(zap);
 
305
            return;
 
306
        }
 
307
        sidp = &sid->next;
 
308
    }
 
309
}
 
310
 
 
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 
 
314
 *    ss->sec.uncache().
 
315
 */
 
316
static void
 
317
LockAndUncacheSID(sslSessionID *zap)
 
318
{
 
319
    LOCK_CACHE;
 
320
    UncacheSID(zap);
 
321
    UNLOCK_CACHE;
 
322
 
 
323
}
 
324
 
 
325
/* choose client or server cache functions for this sslsocket. */
 
326
void 
 
327
ssl_ChooseSessionIDProcs(sslSecurityInfo *sec)
 
328
{
 
329
    if (sec->isServer) {
 
330
        sec->cache   = ssl_sid_cache;
 
331
        sec->uncache = ssl_sid_uncache;
 
332
    } else {
 
333
        sec->cache   = CacheSID;
 
334
        sec->uncache = LockAndUncacheSID;
 
335
    }
 
336
}
 
337
 
 
338
/* wipe out the entire client session cache. */
 
339
void
 
340
SSL_ClearSessionCache(void)
 
341
{
 
342
    LOCK_CACHE;
 
343
    while(cache != NULL)
 
344
        UncacheSID(cache);
 
345
    UNLOCK_CACHE;
 
346
}
 
347
 
 
348
/* returns an unsigned int containing the number of seconds in PR_Now() */
 
349
PRUint32
 
350
ssl_Time(void)
 
351
{
 
352
    PRUint32 myTime;
 
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. */
 
355
#else
 
356
    /* portable, but possibly slower */
 
357
    PRTime now;
 
358
    PRInt64 ll;
 
359
 
 
360
    now = PR_Now();
 
361
    LL_I2L(ll, 1000000L);
 
362
    LL_DIV(now, now, ll);
 
363
    LL_L2UI(myTime, now);
 
364
#endif
 
365
    return myTime;
 
366
}
 
367