1/* This file implements the SERVER Session ID cache.
2 * NOTE:  The contents of this file are NOT used by the client.
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8/* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server
9 * cache sids!
10 *
11 * About record locking among different server processes:
12 *
13 * All processes that are part of the same conceptual server (serving on
14 * the same address and port) MUST share a common SSL session cache.
15 * This code makes the content of the shared cache accessible to all
16 * processes on the same "server".  This code works on Unix and Win32 only.
17 *
18 * We use NSPR anonymous shared memory and move data to & from shared memory.
19 * We must do explicit locking of the records for all reads and writes.
20 * The set of Cache entries are divided up into "sets" of 128 entries.
21 * Each set is protected by a lock.  There may be one or more sets protected
22 * by each lock.  That is, locks to sets are 1:N.
23 * There is one lock for the entire cert cache.
24 * There is one lock for the set of wrapped sym wrap keys.
25 *
26 * The anonymous shared memory is laid out as if it were declared like this:
27 *
28 * struct {
29 *     cacheDescriptor          desc;
30 *     sidCacheLock             sidCacheLocks[ numSIDCacheLocks];
31 *     sidCacheLock             keyCacheLock;
32 *     sidCacheLock             certCacheLock;
33 *     sidCacheSet              sidCacheSets[ numSIDCacheSets ];
34 *     sidCacheEntry            sidCacheData[ numSIDCacheEntries];
35 *     certCacheEntry           certCacheData[numCertCacheEntries];
36 *     SSLWrappedSymWrappingKey keyCacheData[kt_kea_size][SSL_NUM_WRAP_MECHS];
37 *     PRUint8                  keyNameSuffix[SESS_TICKET_KEY_VAR_NAME_LEN]
38 *     encKeyCacheEntry         ticketEncKey; // Wrapped in non-bypass mode
39 *     encKeyCacheEntry         ticketMacKey; // Wrapped in non-bypass mode
40 *     PRBool                   ticketKeysValid;
41 *     sidCacheLock             srvNameCacheLock;
42 *     srvNameCacheEntry        srvNameData[ numSrvNameCacheEntries ];
43 * } cacheMemCacheData;
44 */
45#include "seccomon.h"
46
47#if defined(XP_UNIX) || defined(XP_WIN32) || defined (XP_OS2) || defined(XP_BEOS)
48
49#include "cert.h"
50#include "ssl.h"
51#include "sslimpl.h"
52#include "sslproto.h"
53#include "pk11func.h"
54#include "base64.h"
55#include "keyhi.h"
56#ifdef NO_PKCS11_BYPASS
57#include "blapit.h"
58#include "sechash.h"
59#else
60#include "blapi.h"
61#endif
62
63#include <stdio.h>
64
65#if defined(XP_UNIX) || defined(XP_BEOS)
66
67#include <syslog.h>
68#include <fcntl.h>
69#include <unistd.h>
70#include <errno.h>
71#include <signal.h>
72#include "unix_err.h"
73
74#else
75
76#ifdef XP_WIN32
77#include <wtypes.h>
78#include "win32err.h"
79#endif
80
81#endif
82#include <sys/types.h>
83
84#define SET_ERROR_CODE /* reminder */
85
86#include "nspr.h"
87#include "sslmutex.h"
88
89/*
90** Format of a cache entry in the shared memory.
91*/
92struct sidCacheEntryStr {
93/* 16 */    PRIPv6Addr  addr;	/* client's IP address */
94/*  4 */    PRUint32    creationTime;
95/*  4 */    PRUint32    lastAccessTime;
96/*  4 */    PRUint32    expirationTime;
97/*  2 */    PRUint16	version;
98/*  1 */    PRUint8	valid;
99/*  1 */    PRUint8     sessionIDLength;
100/* 32 */    PRUint8     sessionID[SSL3_SESSIONID_BYTES];
101/*  2 */    PRUint16    authAlgorithm;
102/*  2 */    PRUint16    authKeyBits;
103/*  2 */    PRUint16    keaType;
104/*  2 */    PRUint16    keaKeyBits;
105/* 72  - common header total */
106
107    union {
108	struct {
109/* 64 */    PRUint8	masterKey[SSL_MAX_MASTER_KEY_BYTES];
110/* 32 */    PRUint8	cipherArg[SSL_MAX_CYPHER_ARG_BYTES];
111
112/*  1 */    PRUint8	cipherType;
113/*  1 */    PRUint8	masterKeyLen;
114/*  1 */    PRUint8	keyBits;
115/*  1 */    PRUint8	secretKeyBits;
116/*  1 */    PRUint8	cipherArgLen;
117/*101 */} ssl2;
118
119	struct {
120/*  2 */    ssl3CipherSuite  cipherSuite;
121/*  2 */    PRUint16    compression; 	/* SSLCompressionMethod */
122
123/* 52 */    ssl3SidKeys keys;	/* keys, wrapped as needed. */
124
125/*  4 */    PRUint32    masterWrapMech;
126/*  4 */    SSL3KEAType exchKeyType;
127/*  4 */    PRInt32     certIndex;
128/*  4 */    PRInt32     srvNameIndex;
129/* 32 */    PRUint8     srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */
130/*104 */} ssl3;
131/* force sizeof(sidCacheEntry) to be a multiple of cache line size */
132        struct {
133/*120 */    PRUint8     filler[120]; /* 72+120==192, a multiple of 16 */
134	} forceSize;
135    } u;
136};
137typedef struct sidCacheEntryStr sidCacheEntry;
138
139/* The length of this struct is supposed to be a power of 2, e.g. 4KB */
140struct certCacheEntryStr {
141    PRUint16    certLength;				/*    2 */
142    PRUint16    sessionIDLength;			/*    2 */
143    PRUint8 	sessionID[SSL3_SESSIONID_BYTES];	/*   32 */
144    PRUint8 	cert[SSL_MAX_CACHED_CERT_LEN];		/* 4060 */
145};						/* total   4096 */
146typedef struct certCacheEntryStr certCacheEntry;
147
148struct sidCacheLockStr {
149    PRUint32	timeStamp;
150    sslMutex	mutex;
151    sslPID	pid;
152};
153typedef struct sidCacheLockStr sidCacheLock;
154
155struct sidCacheSetStr {
156    PRIntn	next;
157};
158typedef struct sidCacheSetStr sidCacheSet;
159
160struct encKeyCacheEntryStr {
161    PRUint8	bytes[512];
162    PRInt32	length;
163};
164typedef struct encKeyCacheEntryStr encKeyCacheEntry;
165
166#define SSL_MAX_DNS_HOST_NAME  1024
167
168struct srvNameCacheEntryStr {
169    PRUint16    type;                                   /*    2 */
170    PRUint16    nameLen;                                /*    2 */
171    PRUint8	name[SSL_MAX_DNS_HOST_NAME + 12];       /* 1034 */
172    PRUint8 	nameHash[SHA256_LENGTH];                /*   32 */
173                                                        /* 1072 */
174};
175typedef struct srvNameCacheEntryStr srvNameCacheEntry;
176
177
178struct cacheDescStr {
179
180    PRUint32            cacheMemSize;
181
182    PRUint32		numSIDCacheLocks;
183    PRUint32		numSIDCacheSets;
184    PRUint32		numSIDCacheSetsPerLock;
185
186    PRUint32            numSIDCacheEntries;
187    PRUint32            sidCacheSize;
188
189    PRUint32            numCertCacheEntries;
190    PRUint32            certCacheSize;
191
192    PRUint32            numKeyCacheEntries;
193    PRUint32            keyCacheSize;
194
195    PRUint32            numSrvNameCacheEntries;
196    PRUint32            srvNameCacheSize;
197
198    PRUint32		ssl2Timeout;
199    PRUint32		ssl3Timeout;
200
201    PRUint32            numSIDCacheLocksInitialized;
202
203    /* These values are volatile, and are accessed through sharedCache-> */
204    PRUint32		nextCertCacheEntry;	/* certCacheLock protects */
205    PRBool      	stopPolling;
206    PRBool		everInherited;
207
208    /* The private copies of these values are pointers into shared mem */
209    /* The copies of these values in shared memory are merely offsets */
210    sidCacheLock    *          sidCacheLocks;
211    sidCacheLock    *          keyCacheLock;
212    sidCacheLock    *          certCacheLock;
213    sidCacheLock    *          srvNameCacheLock;
214    sidCacheSet     *          sidCacheSets;
215    sidCacheEntry   *          sidCacheData;
216    certCacheEntry  *          certCacheData;
217    SSLWrappedSymWrappingKey * keyCacheData;
218    PRUint8         *          ticketKeyNameSuffix;
219    encKeyCacheEntry         * ticketEncKey;
220    encKeyCacheEntry         * ticketMacKey;
221    PRUint32        *          ticketKeysValid;
222    srvNameCacheEntry *        srvNameCacheData;
223
224    /* Only the private copies of these pointers are valid */
225    char *                     cacheMem;
226    struct cacheDescStr *      sharedCache;  /* shared copy of this struct */
227    PRFileMap *                cacheMemMap;
228    PRThread  *                poller;
229    PRUint32                   mutexTimeout;
230    PRBool                     shared;
231};
232typedef struct cacheDescStr cacheDesc;
233
234static cacheDesc globalCache;
235
236static const char envVarName[] = { SSL_ENV_VAR_NAME };
237
238static PRBool isMultiProcess  = PR_FALSE;
239
240
241#define DEF_SID_CACHE_ENTRIES  10000
242#define DEF_CERT_CACHE_ENTRIES 250
243#define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */
244#define DEF_KEY_CACHE_ENTRIES  250
245#define DEF_NAME_CACHE_ENTRIES  1000
246
247#define SID_CACHE_ENTRIES_PER_SET  128
248#define SID_ALIGNMENT          16
249
250#define DEF_SSL2_TIMEOUT	100   /* seconds */
251#define MAX_SSL2_TIMEOUT	100   /* seconds */
252#define MIN_SSL2_TIMEOUT	  5   /* seconds */
253
254#define DEF_SSL3_TIMEOUT      86400L  /* 24 hours */
255#define MAX_SSL3_TIMEOUT      86400L  /* 24 hours */
256#define MIN_SSL3_TIMEOUT          5   /* seconds  */
257
258#if defined(AIX) || defined(LINUX) || defined(NETBSD) || defined(OPENBSD)
259#define MAX_SID_CACHE_LOCKS 8	/* two FDs per lock */
260#elif defined(OSF1)
261#define MAX_SID_CACHE_LOCKS 16	/* one FD per lock */
262#else
263#define MAX_SID_CACHE_LOCKS 256
264#endif
265
266#define SID_HOWMANY(val, size) (((val) + ((size) - 1)) / (size))
267#define SID_ROUNDUP(val, size) ((size) * SID_HOWMANY((val), (size)))
268
269
270static sslPID myPid;
271static PRUint32  ssl_max_sid_cache_locks = MAX_SID_CACHE_LOCKS;
272
273/* forward static function declarations */
274static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s,
275                         unsigned nl);
276static SECStatus LaunchLockPoller(cacheDesc *cache);
277static SECStatus StopLockPoller(cacheDesc *cache);
278
279
280struct inheritanceStr {
281    PRUint32 cacheMemSize;
282    PRUint32 fmStrLen;
283};
284
285typedef struct inheritanceStr inheritance;
286
287#if defined(_WIN32) || defined(XP_OS2)
288
289#define DEFAULT_CACHE_DIRECTORY "\\temp"
290
291#endif /* _win32 */
292
293#if defined(XP_UNIX) || defined(XP_BEOS)
294
295#define DEFAULT_CACHE_DIRECTORY "/tmp"
296
297#endif /* XP_UNIX || XP_BEOS */
298
299
300/************************************************************************/
301
302static PRUint32
303LockSidCacheLock(sidCacheLock *lock, PRUint32 now)
304{
305    SECStatus      rv      = sslMutex_Lock(&lock->mutex);
306    if (rv != SECSuccess)
307    	return 0;
308    if (!now)
309	now  = ssl_Time();
310    lock->timeStamp = now;
311    lock->pid       = myPid;
312    return now;
313}
314
315static SECStatus
316UnlockSidCacheLock(sidCacheLock *lock)
317{
318    SECStatus      rv;
319
320    lock->pid = 0;
321    rv        = sslMutex_Unlock(&lock->mutex);
322    return rv;
323}
324
325/* returns the value of ssl_Time on success, zero on failure. */
326static PRUint32
327LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now)
328{
329    PRUint32       lockNum = set % cache->numSIDCacheLocks;
330    sidCacheLock * lock    = cache->sidCacheLocks + lockNum;
331
332    return LockSidCacheLock(lock, now);
333}
334
335static SECStatus
336UnlockSet(cacheDesc *cache, PRUint32 set)
337{
338    PRUint32       lockNum = set % cache->numSIDCacheLocks;
339    sidCacheLock * lock    = cache->sidCacheLocks + lockNum;
340
341    return UnlockSidCacheLock(lock);
342}
343
344/************************************************************************/
345
346
347/* Put a certificate in the cache.  Update the cert index in the sce.
348*/
349static PRUint32
350CacheCert(cacheDesc * cache, CERTCertificate *cert, sidCacheEntry *sce)
351{
352    PRUint32        now;
353    certCacheEntry  cce;
354
355    if ((cert->derCert.len > SSL_MAX_CACHED_CERT_LEN) ||
356        (cert->derCert.len <= 0) ||
357	(cert->derCert.data == NULL)) {
358	PORT_SetError(SEC_ERROR_INVALID_ARGS);
359	return 0;
360    }
361
362    cce.sessionIDLength = sce->sessionIDLength;
363    PORT_Memcpy(cce.sessionID, sce->sessionID, cce.sessionIDLength);
364
365    cce.certLength = cert->derCert.len;
366    PORT_Memcpy(cce.cert, cert->derCert.data, cce.certLength);
367
368    /* get lock on cert cache */
369    now = LockSidCacheLock(cache->certCacheLock, 0);
370    if (now) {
371
372	/* Find where to place the next cert cache entry. */
373	cacheDesc * sharedCache = cache->sharedCache;
374	PRUint32    ndx         = sharedCache->nextCertCacheEntry;
375
376	/* write the entry */
377	cache->certCacheData[ndx] = cce;
378
379	/* remember where we put it. */
380	sce->u.ssl3.certIndex = ndx;
381
382	/* update the "next" cache entry index */
383	sharedCache->nextCertCacheEntry =
384					(ndx + 1) % cache->numCertCacheEntries;
385
386	UnlockSidCacheLock(cache->certCacheLock);
387    }
388    return now;
389
390}
391
392/* Server configuration hash tables need to account the SECITEM.type
393 * field as well. These functions accomplish that. */
394static PLHashNumber
395Get32BitNameHash(const SECItem *name)
396{
397    PLHashNumber rv = SECITEM_Hash(name);
398
399    PRUint8 *rvc = (PRUint8 *)&rv;
400    rvc[ name->len % sizeof(rv) ] ^= name->type;
401
402    return rv;
403}
404
405/* Put a name in the cache.  Update the cert index in the sce.
406*/
407static PRUint32
408CacheSrvName(cacheDesc * cache, SECItem *name, sidCacheEntry *sce)
409{
410    PRUint32           now;
411    PRUint32           ndx;
412    srvNameCacheEntry  snce;
413
414    if (!name || name->len <= 0 ||
415        name->len > SSL_MAX_DNS_HOST_NAME) {
416	PORT_SetError(SEC_ERROR_INVALID_ARGS);
417	return 0;
418    }
419
420    snce.type = name->type;
421    snce.nameLen = name->len;
422    PORT_Memcpy(snce.name, name->data, snce.nameLen);
423#ifdef NO_PKCS11_BYPASS
424    HASH_HashBuf(HASH_AlgSHA256, snce.nameHash, name->data, name->len);
425#else
426    SHA256_HashBuf(snce.nameHash, (unsigned char*)name->data,
427                   name->len);
428#endif
429    /* get index of the next name */
430    ndx = Get32BitNameHash(name);
431    /* get lock on cert cache */
432    now = LockSidCacheLock(cache->srvNameCacheLock, 0);
433    if (now) {
434        if (cache->numSrvNameCacheEntries > 0) {
435            /* Fit the index into array */
436            ndx %= cache->numSrvNameCacheEntries;
437            /* write the entry */
438            cache->srvNameCacheData[ndx] = snce;
439            /* remember where we put it. */
440            sce->u.ssl3.srvNameIndex = ndx;
441            /* Copy hash into sid hash */
442            PORT_Memcpy(sce->u.ssl3.srvNameHash, snce.nameHash, SHA256_LENGTH);
443        }
444	UnlockSidCacheLock(cache->srvNameCacheLock);
445    }
446    return now;
447}
448
449/*
450** Convert local SID to shared memory one
451*/
452static void
453ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
454{
455    to->valid   = 1;
456    to->version = from->version;
457    to->addr    = from->addr;
458    to->creationTime    = from->creationTime;
459    to->lastAccessTime  = from->lastAccessTime;
460    to->expirationTime  = from->expirationTime;
461    to->authAlgorithm	= from->authAlgorithm;
462    to->authKeyBits	= from->authKeyBits;
463    to->keaType		= from->keaType;
464    to->keaKeyBits	= from->keaKeyBits;
465
466    if (from->version < SSL_LIBRARY_VERSION_3_0) {
467	if ((from->u.ssl2.masterKey.len > SSL_MAX_MASTER_KEY_BYTES) ||
468	    (from->u.ssl2.cipherArg.len > SSL_MAX_CYPHER_ARG_BYTES)) {
469	    SSL_DBG(("%d: SSL: masterKeyLen=%d cipherArgLen=%d",
470		     myPid, from->u.ssl2.masterKey.len,
471		     from->u.ssl2.cipherArg.len));
472	    to->valid = 0;
473	    return;
474	}
475
476	to->u.ssl2.cipherType    = from->u.ssl2.cipherType;
477	to->u.ssl2.masterKeyLen  = from->u.ssl2.masterKey.len;
478	to->u.ssl2.cipherArgLen  = from->u.ssl2.cipherArg.len;
479	to->u.ssl2.keyBits       = from->u.ssl2.keyBits;
480	to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
481	to->sessionIDLength      = SSL2_SESSIONID_BYTES;
482	PORT_Memcpy(to->sessionID, from->u.ssl2.sessionID, SSL2_SESSIONID_BYTES);
483	PORT_Memcpy(to->u.ssl2.masterKey, from->u.ssl2.masterKey.data,
484		  from->u.ssl2.masterKey.len);
485	PORT_Memcpy(to->u.ssl2.cipherArg, from->u.ssl2.cipherArg.data,
486		  from->u.ssl2.cipherArg.len);
487#ifdef DEBUG
488	PORT_Memset(to->u.ssl2.masterKey+from->u.ssl2.masterKey.len, 0,
489		  sizeof(to->u.ssl2.masterKey) - from->u.ssl2.masterKey.len);
490	PORT_Memset(to->u.ssl2.cipherArg+from->u.ssl2.cipherArg.len, 0,
491		  sizeof(to->u.ssl2.cipherArg) - from->u.ssl2.cipherArg.len);
492#endif
493	SSL_TRC(8, ("%d: SSL: ConvertSID: masterKeyLen=%d cipherArgLen=%d "
494		    "time=%d addr=0x%08x%08x%08x%08x cipherType=%d", myPid,
495		    to->u.ssl2.masterKeyLen, to->u.ssl2.cipherArgLen,
496		    to->creationTime, to->addr.pr_s6_addr32[0],
497		    to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
498		    to->addr.pr_s6_addr32[3], to->u.ssl2.cipherType));
499    } else {
500	/* This is an SSL v3 session */
501
502	to->u.ssl3.cipherSuite      = from->u.ssl3.cipherSuite;
503	to->u.ssl3.compression      = (PRUint16)from->u.ssl3.compression;
504	to->u.ssl3.keys             = from->u.ssl3.keys;
505	to->u.ssl3.masterWrapMech   = from->u.ssl3.masterWrapMech;
506	to->u.ssl3.exchKeyType      = from->u.ssl3.exchKeyType;
507	to->sessionIDLength         = from->u.ssl3.sessionIDLength;
508	to->u.ssl3.certIndex        = -1;
509	to->u.ssl3.srvNameIndex     = -1;
510
511	PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID,
512		    to->sessionIDLength);
513
514	SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x "
515	            "cipherSuite=%d",
516		    myPid, to->creationTime, to->addr.pr_s6_addr32[0],
517		    to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
518		    to->addr.pr_s6_addr32[3], to->u.ssl3.cipherSuite));
519    }
520}
521
522/*
523** Convert shared memory cache-entry to local memory based one
524** This is only called from ServerSessionIDLookup().
525** Caller must hold cache lock when calling this.
526*/
527static sslSessionID *
528ConvertToSID(sidCacheEntry *    from,
529             certCacheEntry *   pcce,
530             srvNameCacheEntry *psnce,
531             CERTCertDBHandle * dbHandle)
532{
533    sslSessionID *to;
534    PRUint16 version = from->version;
535
536    to = PORT_ZNew(sslSessionID);
537    if (!to) {
538	return 0;
539    }
540
541    if (version < SSL_LIBRARY_VERSION_3_0) {
542	/* This is an SSL v2 session */
543	to->u.ssl2.masterKey.data =
544	    (unsigned char*) PORT_Alloc(from->u.ssl2.masterKeyLen);
545	if (!to->u.ssl2.masterKey.data) {
546	    goto loser;
547	}
548	if (from->u.ssl2.cipherArgLen) {
549	    to->u.ssl2.cipherArg.data =
550	    	(unsigned char*)PORT_Alloc(from->u.ssl2.cipherArgLen);
551	    if (!to->u.ssl2.cipherArg.data) {
552		goto loser;
553	    }
554	    PORT_Memcpy(to->u.ssl2.cipherArg.data, from->u.ssl2.cipherArg,
555		        from->u.ssl2.cipherArgLen);
556	}
557
558	to->u.ssl2.cipherType    = from->u.ssl2.cipherType;
559	to->u.ssl2.masterKey.len = from->u.ssl2.masterKeyLen;
560	to->u.ssl2.cipherArg.len = from->u.ssl2.cipherArgLen;
561	to->u.ssl2.keyBits       = from->u.ssl2.keyBits;
562	to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
563/*	to->sessionIDLength      = SSL2_SESSIONID_BYTES; */
564	PORT_Memcpy(to->u.ssl2.sessionID, from->sessionID, SSL2_SESSIONID_BYTES);
565	PORT_Memcpy(to->u.ssl2.masterKey.data, from->u.ssl2.masterKey,
566		    from->u.ssl2.masterKeyLen);
567
568	SSL_TRC(8, ("%d: SSL: ConvertToSID: masterKeyLen=%d cipherArgLen=%d "
569		    "time=%d addr=0x%08x%08x%08x%08x cipherType=%d",
570		    myPid, to->u.ssl2.masterKey.len,
571		    to->u.ssl2.cipherArg.len, to->creationTime,
572		    to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1],
573		    to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3],
574		    to->u.ssl2.cipherType));
575    } else {
576	/* This is an SSL v3 session */
577
578	to->u.ssl3.sessionIDLength  = from->sessionIDLength;
579	to->u.ssl3.cipherSuite      = from->u.ssl3.cipherSuite;
580	to->u.ssl3.compression      = (SSLCompressionMethod)from->u.ssl3.compression;
581	to->u.ssl3.keys             = from->u.ssl3.keys;
582	to->u.ssl3.masterWrapMech   = from->u.ssl3.masterWrapMech;
583	to->u.ssl3.exchKeyType      = from->u.ssl3.exchKeyType;
584	if (from->u.ssl3.srvNameIndex != -1 && psnce) {
585            SECItem name;
586            SECStatus rv;
587            name.type                   = psnce->type;
588            name.len                    = psnce->nameLen;
589            name.data                   = psnce->name;
590            rv = SECITEM_CopyItem(NULL, &to->u.ssl3.srvName, &name);
591            if (rv != SECSuccess) {
592                goto loser;
593            }
594        }
595
596	PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength);
597
598	/* the portions of the SID that are only restored on the client
599	 * are set to invalid values on the server.
600	 */
601	to->u.ssl3.clientWriteKey   = NULL;
602	to->u.ssl3.serverWriteKey   = NULL;
603
604	to->urlSvrName              = NULL;
605
606	to->u.ssl3.masterModuleID   = (SECMODModuleID)-1; /* invalid value */
607	to->u.ssl3.masterSlotID     = (CK_SLOT_ID)-1;     /* invalid value */
608	to->u.ssl3.masterWrapIndex  = 0;
609	to->u.ssl3.masterWrapSeries = 0;
610	to->u.ssl3.masterValid      = PR_FALSE;
611
612	to->u.ssl3.clAuthModuleID   = (SECMODModuleID)-1; /* invalid value */
613	to->u.ssl3.clAuthSlotID     = (CK_SLOT_ID)-1;     /* invalid value */
614	to->u.ssl3.clAuthSeries     = 0;
615	to->u.ssl3.clAuthValid      = PR_FALSE;
616
617	if (from->u.ssl3.certIndex != -1 && pcce) {
618	    SECItem          derCert;
619
620	    derCert.len  = pcce->certLength;
621	    derCert.data = pcce->cert;
622
623	    to->peerCert = CERT_NewTempCertificate(dbHandle, &derCert, NULL,
624					           PR_FALSE, PR_TRUE);
625	    if (to->peerCert == NULL)
626		goto loser;
627	}
628    }
629
630    to->version         = from->version;
631    to->creationTime    = from->creationTime;
632    to->lastAccessTime  = from->lastAccessTime;
633    to->expirationTime  = from->expirationTime;
634    to->cached          = in_server_cache;
635    to->addr            = from->addr;
636    to->references      = 1;
637    to->authAlgorithm	= from->authAlgorithm;
638    to->authKeyBits	= from->authKeyBits;
639    to->keaType		= from->keaType;
640    to->keaKeyBits	= from->keaKeyBits;
641
642    return to;
643
644  loser:
645    if (to) {
646	if (version < SSL_LIBRARY_VERSION_3_0) {
647	    if (to->u.ssl2.masterKey.data)
648		PORT_Free(to->u.ssl2.masterKey.data);
649	    if (to->u.ssl2.cipherArg.data)
650		PORT_Free(to->u.ssl2.cipherArg.data);
651	} else {
652            SECITEM_FreeItem(&to->u.ssl3.srvName, PR_FALSE);
653        }
654	PORT_Free(to);
655    }
656    return NULL;
657}
658
659
660
661/*
662** Perform some mumbo jumbo on the ip-address and the session-id value to
663** compute a hash value.
664*/
665static PRUint32
666SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl)
667{
668    PRUint32 rv;
669    PRUint32 x[8];
670
671    memset(x, 0, sizeof x);
672    if (nl > sizeof x)
673    	nl = sizeof x;
674    memcpy(x, s, nl);
675
676    rv = (addr->pr_s6_addr32[0] ^ addr->pr_s6_addr32[1] ^
677	  addr->pr_s6_addr32[2] ^ addr->pr_s6_addr32[3] ^
678          x[0] ^ x[1] ^ x[2] ^ x[3] ^ x[4] ^ x[5] ^ x[6] ^ x[7])
679	  % cache->numSIDCacheSets;
680    return rv;
681}
682
683
684
685/*
686** Look something up in the cache. This will invalidate old entries
687** in the process. Caller has locked the cache set!
688** Returns PR_TRUE if found a valid match.  PR_FALSE otherwise.
689*/
690static sidCacheEntry *
691FindSID(cacheDesc *cache, PRUint32 setNum, PRUint32 now,
692        const PRIPv6Addr *addr, unsigned char *sessionID,
693	unsigned sessionIDLength)
694{
695    PRUint32      ndx   = cache->sidCacheSets[setNum].next;
696    int           i;
697
698    sidCacheEntry * set = cache->sidCacheData +
699    			 (setNum * SID_CACHE_ENTRIES_PER_SET);
700
701    for (i = SID_CACHE_ENTRIES_PER_SET; i > 0; --i) {
702	sidCacheEntry * sce;
703
704	ndx  = (ndx - 1) % SID_CACHE_ENTRIES_PER_SET;
705	sce = set + ndx;
706
707	if (!sce->valid)
708	    continue;
709
710	if (now > sce->expirationTime) {
711	    /* SessionID has timed out. Invalidate the entry. */
712	    SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x "
713			"time+=%x",
714			myPid, sce->addr.pr_s6_addr32[0],
715			sce->addr.pr_s6_addr32[1], sce->addr.pr_s6_addr32[2],
716			sce->addr.pr_s6_addr32[3], now,
717			sce->expirationTime ));
718	    sce->valid = 0;
719	    continue;
720	}
721
722	/*
723	** Next, examine specific session-id/addr data to see if the cache
724	** entry matches our addr+session-id value
725	*/
726	if (sessionIDLength == sce->sessionIDLength      &&
727	    !memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) &&
728	    !memcmp(sce->sessionID, sessionID, sessionIDLength)) {
729	    /* Found it */
730	    return sce;
731	}
732    }
733
734    PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
735    return NULL;
736}
737
738/************************************************************************/
739
740/* This is the primary function for finding entries in the server's sid cache.
741 * Although it is static, this function is called via the global function
742 * pointer ssl_sid_lookup.
743 */
744static sslSessionID *
745ServerSessionIDLookup(const PRIPv6Addr *addr,
746			unsigned char *sessionID,
747			unsigned int   sessionIDLength,
748                        CERTCertDBHandle * dbHandle)
749{
750    sslSessionID *  sid      = 0;
751    sidCacheEntry * psce;
752    certCacheEntry *pcce     = 0;
753    srvNameCacheEntry *psnce = 0;
754    cacheDesc *     cache    = &globalCache;
755    PRUint32        now;
756    PRUint32        set;
757    PRInt32         cndx;
758    sidCacheEntry   sce;
759    certCacheEntry  cce;
760    srvNameCacheEntry snce;
761
762    set = SIDindex(cache, addr, sessionID, sessionIDLength);
763    now = LockSet(cache, set, 0);
764    if (!now)
765    	return NULL;
766
767    psce = FindSID(cache, set, now, addr, sessionID, sessionIDLength);
768    if (psce) {
769	if (psce->version >= SSL_LIBRARY_VERSION_3_0) {
770	    if ((cndx = psce->u.ssl3.certIndex) != -1) {
771
772                PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now);
773                if (gotLock) {
774                    pcce = &cache->certCacheData[cndx];
775
776                    /* See if the cert's session ID matches the sce cache. */
777                    if ((pcce->sessionIDLength == psce->sessionIDLength) &&
778                        !PORT_Memcmp(pcce->sessionID, psce->sessionID,
779                                     pcce->sessionIDLength)) {
780                        cce = *pcce;
781                    } else {
782                        /* The cert doesen't match the SID cache entry,
783                        ** so invalidate the SID cache entry.
784                        */
785                        psce->valid = 0;
786                        psce = 0;
787                        pcce = 0;
788                    }
789                    UnlockSidCacheLock(cache->certCacheLock);
790                } else {
791                    /* what the ??.  Didn't get the cert cache lock.
792                    ** Don't invalidate the SID cache entry, but don't find it.
793                    */
794                    PORT_Assert(!("Didn't get cert Cache Lock!"));
795                    psce = 0;
796                    pcce = 0;
797                }
798            }
799            if (psce && ((cndx = psce->u.ssl3.srvNameIndex) != -1)) {
800                PRUint32 gotLock = LockSidCacheLock(cache->srvNameCacheLock,
801                                                    now);
802                if (gotLock) {
803                    psnce = &cache->srvNameCacheData[cndx];
804
805                    if (!PORT_Memcmp(psnce->nameHash, psce->u.ssl3.srvNameHash,
806                                     SHA256_LENGTH)) {
807                        snce = *psnce;
808                    } else {
809                        /* The name doesen't match the SID cache entry,
810                        ** so invalidate the SID cache entry.
811                        */
812                        psce->valid = 0;
813                        psce = 0;
814                        psnce = 0;
815                    }
816                    UnlockSidCacheLock(cache->srvNameCacheLock);
817                } else {
818                    /* what the ??.  Didn't get the cert cache lock.
819                    ** Don't invalidate the SID cache entry, but don't find it.
820                    */
821                    PORT_Assert(!("Didn't get name Cache Lock!"));
822                    psce = 0;
823                    psnce = 0;
824                }
825
826            }
827        }
828	if (psce) {
829	    psce->lastAccessTime = now;
830	    sce = *psce;	/* grab a copy while holding the lock */
831    	}
832    }
833    UnlockSet(cache, set);
834    if (psce) {
835	/* sce conains a copy of the cache entry.
836	** Convert shared memory format to local format
837	*/
838	sid = ConvertToSID(&sce, pcce ? &cce : 0, psnce ? &snce : 0, dbHandle);
839    }
840    return sid;
841}
842
843/*
844** Place a sid into the cache, if it isn't already there.
845*/
846static void
847ServerSessionIDCache(sslSessionID *sid)
848{
849    sidCacheEntry sce;
850    PRUint32      now     = 0;
851    PRUint16      version = sid->version;
852    cacheDesc *   cache   = &globalCache;
853
854    if ((version >= SSL_LIBRARY_VERSION_3_0) &&
855	(sid->u.ssl3.sessionIDLength == 0)) {
856	return;
857    }
858
859    if (sid->cached == never_cached || sid->cached == invalid_cache) {
860	PRUint32 set;
861
862	PORT_Assert(sid->creationTime != 0);
863	if (!sid->creationTime)
864	    sid->lastAccessTime = sid->creationTime = ssl_Time();
865	if (version < SSL_LIBRARY_VERSION_3_0) {
866	    /* override caller's expiration time, which uses client timeout
867	     * duration, not server timeout duration.
868	     */
869	    sid->expirationTime = sid->creationTime + cache->ssl2Timeout;
870	    SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
871			"cipher=%d", myPid, sid->cached,
872			sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
873			sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
874			sid->creationTime, sid->u.ssl2.cipherType));
875	    PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID,
876			  SSL2_SESSIONID_BYTES));
877	    PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
878			  sid->u.ssl2.masterKey.len));
879	    PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
880			  sid->u.ssl2.cipherArg.len));
881
882	} else {
883	    /* override caller's expiration time, which uses client timeout
884	     * duration, not server timeout duration.
885	     */
886	    sid->expirationTime = sid->creationTime + cache->ssl3Timeout;
887	    SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
888			"cipherSuite=%d", myPid, sid->cached,
889			sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
890			sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
891			sid->creationTime, sid->u.ssl3.cipherSuite));
892	    PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID,
893			  sid->u.ssl3.sessionIDLength));
894	}
895
896	ConvertFromSID(&sce, sid);
897
898	if (version >= SSL_LIBRARY_VERSION_3_0) {
899            SECItem *name = &sid->u.ssl3.srvName;
900            if (name->len && name->data) {
901                now = CacheSrvName(cache, name, &sce);
902            }
903            if (sid->peerCert != NULL) {
904                now = CacheCert(cache, sid->peerCert, &sce);
905            }
906	}
907
908	set = SIDindex(cache, &sce.addr, sce.sessionID, sce.sessionIDLength);
909	now = LockSet(cache, set, now);
910	if (now) {
911	    PRUint32  next = cache->sidCacheSets[set].next;
912	    PRUint32  ndx  = set * SID_CACHE_ENTRIES_PER_SET + next;
913
914	    /* Write out new cache entry */
915	    cache->sidCacheData[ndx] = sce;
916
917	    cache->sidCacheSets[set].next =
918	    				(next + 1) % SID_CACHE_ENTRIES_PER_SET;
919
920	    UnlockSet(cache, set);
921	    sid->cached = in_server_cache;
922	}
923    }
924}
925
926/*
927** Although this is static, it is called from ssl via global function pointer
928**	ssl_sid_uncache.  This invalidates the referenced cache entry.
929*/
930static void
931ServerSessionIDUncache(sslSessionID *sid)
932{
933    cacheDesc *    cache   = &globalCache;
934    PRUint8 *      sessionID;
935    unsigned int   sessionIDLength;
936    PRErrorCode    err;
937    PRUint32       set;
938    PRUint32       now;
939    sidCacheEntry *psce;
940
941    if (sid == NULL)
942    	return;
943
944    /* Uncaching a SID should never change the error code.
945    ** So save it here and restore it before exiting.
946    */
947    err = PR_GetError();
948
949    if (sid->version < SSL_LIBRARY_VERSION_3_0) {
950	sessionID       = sid->u.ssl2.sessionID;
951	sessionIDLength = SSL2_SESSIONID_BYTES;
952	SSL_TRC(8, ("%d: SSL: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
953		    "cipher=%d", myPid, sid->cached,
954		    sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
955		    sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
956		    sid->creationTime, sid->u.ssl2.cipherType));
957	PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
958	PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
959		      sid->u.ssl2.masterKey.len));
960	PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
961		      sid->u.ssl2.cipherArg.len));
962    } else {
963	sessionID       = sid->u.ssl3.sessionID;
964	sessionIDLength = sid->u.ssl3.sessionIDLength;
965	SSL_TRC(8, ("%d: SSL3: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
966		    "cipherSuite=%d", myPid, sid->cached,
967		    sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
968		    sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
969		    sid->creationTime, sid->u.ssl3.cipherSuite));
970	PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
971    }
972    set = SIDindex(cache, &sid->addr, sessionID, sessionIDLength);
973    now = LockSet(cache, set, 0);
974    if (now) {
975	psce = FindSID(cache, set, now, &sid->addr, sessionID, sessionIDLength);
976	if (psce) {
977	    psce->valid = 0;
978	}
979	UnlockSet(cache, set);
980    }
981    sid->cached = invalid_cache;
982    PORT_SetError(err);
983}
984
985#ifdef XP_OS2
986
987#define INCL_DOSPROCESS
988#include <os2.h>
989
990long gettid(void)
991{
992    PTIB ptib;
993    PPIB ppib;
994    DosGetInfoBlocks(&ptib, &ppib);
995    return ((long)ptib->tib_ordinal); /* thread id */
996}
997#endif
998
999static void
1000CloseCache(cacheDesc *cache)
1001{
1002    int locks_initialized = cache->numSIDCacheLocksInitialized;
1003
1004    if (cache->cacheMem) {
1005	if (cache->sharedCache) {
1006	    sidCacheLock *pLock = cache->sidCacheLocks;
1007	    for (; locks_initialized > 0; --locks_initialized, ++pLock ) {
1008		/* If everInherited is true, this shared cache was (and may
1009		** still be) in use by multiple processes.  We do not wish to
1010		** destroy the mutexes while they are still in use, but we do
1011		** want to free mutex resources associated with this process.
1012		*/
1013		sslMutex_Destroy(&pLock->mutex,
1014				 cache->sharedCache->everInherited);
1015	    }
1016	}
1017	if (cache->shared) {
1018	    PR_MemUnmap(cache->cacheMem, cache->cacheMemSize);
1019	} else {
1020	    PORT_Free(cache->cacheMem);
1021	}
1022	cache->cacheMem = NULL;
1023    }
1024    if (cache->cacheMemMap) {
1025	PR_CloseFileMap(cache->cacheMemMap);
1026	cache->cacheMemMap = NULL;
1027    }
1028    memset(cache, 0, sizeof *cache);
1029}
1030
1031static SECStatus
1032InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries,
1033          int maxSrvNameCacheEntries, PRUint32 ssl2_timeout,
1034          PRUint32 ssl3_timeout, const char *directory, PRBool shared)
1035{
1036    ptrdiff_t     ptr;
1037    sidCacheLock *pLock;
1038    char *        cacheMem;
1039    PRFileMap *   cacheMemMap;
1040    char *        cfn = NULL;	/* cache file name */
1041    int           locks_initialized = 0;
1042    int           locks_to_initialize = 0;
1043    PRUint32      init_time;
1044
1045    if ( (!cache) || (maxCacheEntries < 0) || (!directory) ) {
1046        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1047        return SECFailure;
1048    }
1049
1050    if (cache->cacheMem) {
1051	/* Already done */
1052	return SECSuccess;
1053    }
1054
1055    /* make sure loser can clean up properly */
1056    cache->shared = shared;
1057    cache->cacheMem    = cacheMem    = NULL;
1058    cache->cacheMemMap = cacheMemMap = NULL;
1059    cache->sharedCache = (cacheDesc *)0;
1060
1061    cache->numSIDCacheLocksInitialized = 0;
1062    cache->nextCertCacheEntry = 0;
1063    cache->stopPolling = PR_FALSE;
1064    cache->everInherited = PR_FALSE;
1065    cache->poller = NULL;
1066    cache->mutexTimeout = 0;
1067
1068    cache->numSIDCacheEntries = maxCacheEntries ? maxCacheEntries
1069                                                : DEF_SID_CACHE_ENTRIES;
1070    cache->numSIDCacheSets    =
1071    	SID_HOWMANY(cache->numSIDCacheEntries, SID_CACHE_ENTRIES_PER_SET);
1072
1073    cache->numSIDCacheEntries =
1074    	cache->numSIDCacheSets * SID_CACHE_ENTRIES_PER_SET;
1075
1076    cache->numSIDCacheLocks   =
1077    	PR_MIN(cache->numSIDCacheSets, ssl_max_sid_cache_locks);
1078
1079    cache->numSIDCacheSetsPerLock =
1080    	SID_HOWMANY(cache->numSIDCacheSets, cache->numSIDCacheLocks);
1081
1082    cache->numCertCacheEntries = (maxCertCacheEntries > 0) ?
1083                                             maxCertCacheEntries : 0;
1084    cache->numSrvNameCacheEntries = (maxSrvNameCacheEntries >= 0) ?
1085                                             maxSrvNameCacheEntries : DEF_NAME_CACHE_ENTRIES;
1086
1087    /* compute size of shared memory, and offsets of all pointers */
1088    ptr = 0;
1089    cache->cacheMem     = (char *)ptr;
1090    ptr += SID_ROUNDUP(sizeof(cacheDesc), SID_ALIGNMENT);
1091
1092    cache->sidCacheLocks = (sidCacheLock *)ptr;
1093    cache->keyCacheLock  = cache->sidCacheLocks + cache->numSIDCacheLocks;
1094    cache->certCacheLock = cache->keyCacheLock  + 1;
1095    cache->srvNameCacheLock = cache->certCacheLock  + 1;
1096    ptr = (ptrdiff_t)(cache->srvNameCacheLock + 1);
1097    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1098
1099    cache->sidCacheSets  = (sidCacheSet *)ptr;
1100    ptr = (ptrdiff_t)(cache->sidCacheSets + cache->numSIDCacheSets);
1101    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1102
1103    cache->sidCacheData  = (sidCacheEntry *)ptr;
1104    ptr = (ptrdiff_t)(cache->sidCacheData + cache->numSIDCacheEntries);
1105    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1106
1107    cache->certCacheData = (certCacheEntry *)ptr;
1108    cache->sidCacheSize  =
1109    	(char *)cache->certCacheData - (char *)cache->sidCacheData;
1110
1111    if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) {
1112        /* This is really a poor way to computer this! */
1113        cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry);
1114        if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES)
1115    	cache->numCertCacheEntries = MIN_CERT_CACHE_ENTRIES;
1116    }
1117    ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries);
1118    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1119
1120    cache->keyCacheData  = (SSLWrappedSymWrappingKey *)ptr;
1121    cache->certCacheSize =
1122    	(char *)cache->keyCacheData - (char *)cache->certCacheData;
1123
1124    cache->numKeyCacheEntries = kt_kea_size * SSL_NUM_WRAP_MECHS;
1125    ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries);
1126    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1127
1128    cache->keyCacheSize  = (char *)ptr - (char *)cache->keyCacheData;
1129
1130    cache->ticketKeyNameSuffix = (PRUint8 *)ptr;
1131    ptr = (ptrdiff_t)(cache->ticketKeyNameSuffix +
1132	SESS_TICKET_KEY_VAR_NAME_LEN);
1133    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1134
1135    cache->ticketEncKey = (encKeyCacheEntry *)ptr;
1136    ptr = (ptrdiff_t)(cache->ticketEncKey + 1);
1137    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1138
1139    cache->ticketMacKey = (encKeyCacheEntry *)ptr;
1140    ptr = (ptrdiff_t)(cache->ticketMacKey + 1);
1141    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1142
1143    cache->ticketKeysValid = (PRUint32 *)ptr;
1144    ptr = (ptrdiff_t)(cache->ticketKeysValid + 1);
1145    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1146
1147    cache->srvNameCacheData = (srvNameCacheEntry *)ptr;
1148    cache->srvNameCacheSize =
1149        cache->numSrvNameCacheEntries * sizeof(srvNameCacheEntry);
1150    ptr = (ptrdiff_t)(cache->srvNameCacheData + cache->numSrvNameCacheEntries);
1151    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1152
1153    cache->cacheMemSize = ptr;
1154
1155    if (ssl2_timeout) {
1156	if (ssl2_timeout > MAX_SSL2_TIMEOUT) {
1157	    ssl2_timeout = MAX_SSL2_TIMEOUT;
1158	}
1159	if (ssl2_timeout < MIN_SSL2_TIMEOUT) {
1160	    ssl2_timeout = MIN_SSL2_TIMEOUT;
1161	}
1162	cache->ssl2Timeout = ssl2_timeout;
1163    } else {
1164	cache->ssl2Timeout = DEF_SSL2_TIMEOUT;
1165    }
1166
1167    if (ssl3_timeout) {
1168	if (ssl3_timeout > MAX_SSL3_TIMEOUT) {
1169	    ssl3_timeout = MAX_SSL3_TIMEOUT;
1170	}
1171	if (ssl3_timeout < MIN_SSL3_TIMEOUT) {
1172	    ssl3_timeout = MIN_SSL3_TIMEOUT;
1173	}
1174	cache->ssl3Timeout = ssl3_timeout;
1175    } else {
1176	cache->ssl3Timeout = DEF_SSL3_TIMEOUT;
1177    }
1178
1179    if (shared) {
1180	/* Create file names */
1181#if defined(XP_UNIX) || defined(XP_BEOS)
1182	/* there's some confusion here about whether PR_OpenAnonFileMap wants
1183	** a directory name or a file name for its first argument.
1184	cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid);
1185	*/
1186	cfn = PR_smprintf("%s", directory);
1187#elif defined(XP_WIN32)
1188	cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid,
1189			    GetCurrentThreadId());
1190#elif defined(XP_OS2)
1191	cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid,
1192			    gettid());
1193#else
1194#error "Don't know how to create file name for this platform!"
1195#endif
1196	if (!cfn) {
1197	    goto loser;
1198	}
1199
1200	/* Create cache */
1201	cacheMemMap = PR_OpenAnonFileMap(cfn, cache->cacheMemSize,
1202					 PR_PROT_READWRITE);
1203
1204	PR_smprintf_free(cfn);
1205	if(!cacheMemMap) {
1206	    goto loser;
1207	}
1208
1209        cacheMem = PR_MemMap(cacheMemMap, 0, cache->cacheMemSize);
1210    } else {
1211        cacheMem = PORT_Alloc(cache->cacheMemSize);
1212    }
1213
1214    if (! cacheMem) {
1215        goto loser;
1216    }
1217
1218    /* Initialize shared memory. This may not be necessary on all platforms */
1219    memset(cacheMem, 0, cache->cacheMemSize);
1220
1221    /* Copy cache descriptor header into shared memory */
1222    memcpy(cacheMem, cache, sizeof *cache);
1223
1224    /* save private copies of these values */
1225    cache->cacheMemMap = cacheMemMap;
1226    cache->cacheMem    = cacheMem;
1227    cache->sharedCache = (cacheDesc *)cacheMem;
1228
1229    /* Fix pointers in our private copy of cache descriptor to point to
1230    ** spaces in shared memory
1231    */
1232    ptr = (ptrdiff_t)cache->cacheMem;
1233    *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
1234    *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
1235    *(ptrdiff_t *)(&cache->certCacheLock) += ptr;
1236    *(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr;
1237    *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
1238    *(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
1239    *(ptrdiff_t *)(&cache->certCacheData) += ptr;
1240    *(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
1241    *(ptrdiff_t *)(&cache->ticketKeyNameSuffix) += ptr;
1242    *(ptrdiff_t *)(&cache->ticketEncKey ) += ptr;
1243    *(ptrdiff_t *)(&cache->ticketMacKey ) += ptr;
1244    *(ptrdiff_t *)(&cache->ticketKeysValid) += ptr;
1245    *(ptrdiff_t *)(&cache->srvNameCacheData) += ptr;
1246
1247    /* initialize the locks */
1248    init_time = ssl_Time();
1249    pLock = cache->sidCacheLocks;
1250    for (locks_to_initialize = cache->numSIDCacheLocks + 3;
1251         locks_initialized < locks_to_initialize;
1252	 ++locks_initialized, ++pLock ) {
1253
1254	SECStatus err = sslMutex_Init(&pLock->mutex, shared);
1255	if (err) {
1256	    cache->numSIDCacheLocksInitialized = locks_initialized;
1257	    goto loser;
1258	}
1259        pLock->timeStamp = init_time;
1260	pLock->pid       = 0;
1261    }
1262    cache->numSIDCacheLocksInitialized = locks_initialized;
1263
1264    return SECSuccess;
1265
1266loser:
1267    CloseCache(cache);
1268    return SECFailure;
1269}
1270
1271PRUint32
1272SSL_GetMaxServerCacheLocks(void)
1273{
1274    return ssl_max_sid_cache_locks + 2;
1275    /* The extra two are the cert cache lock and the key cache lock. */
1276}
1277
1278SECStatus
1279SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
1280{
1281    /* Minimum is 1 sid cache lock, 1 cert cache lock and 1 key cache lock.
1282    ** We'd like to test for a maximum value, but not all platforms' header
1283    ** files provide a symbol or function or other means of determining
1284    ** the maximum, other than trial and error.
1285    */
1286    if (maxLocks < 3) {
1287	PORT_SetError(SEC_ERROR_INVALID_ARGS);
1288	return SECFailure;
1289    }
1290    ssl_max_sid_cache_locks = maxLocks - 2;
1291    /* The extra two are the cert cache lock and the key cache lock. */
1292    return SECSuccess;
1293}
1294
1295static SECStatus
1296ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache,
1297                                              PRUint32 ssl2_timeout,
1298                                              PRUint32 ssl3_timeout,
1299                                              const char *   directory,
1300                                              PRBool shared,
1301                                              int      maxCacheEntries,
1302                                              int      maxCertCacheEntries,
1303                                              int      maxSrvNameCacheEntries)
1304{
1305    SECStatus rv;
1306
1307    PORT_Assert(sizeof(sidCacheEntry) == 192);
1308    PORT_Assert(sizeof(certCacheEntry) == 4096);
1309    PORT_Assert(sizeof(srvNameCacheEntry) == 1072);
1310
1311    rv = ssl_Init();
1312    if (rv != SECSuccess) {
1313	return rv;
1314    }
1315
1316    myPid = SSL_GETPID();
1317    if (!directory) {
1318	directory = DEFAULT_CACHE_DIRECTORY;
1319    }
1320    rv = InitCache(cache, maxCacheEntries, maxCertCacheEntries,
1321                   maxSrvNameCacheEntries, ssl2_timeout, ssl3_timeout,
1322                   directory, shared);
1323    if (rv) {
1324	SET_ERROR_CODE
1325    	return SECFailure;
1326    }
1327
1328    ssl_sid_lookup  = ServerSessionIDLookup;
1329    ssl_sid_cache   = ServerSessionIDCache;
1330    ssl_sid_uncache = ServerSessionIDUncache;
1331    return SECSuccess;
1332}
1333
1334SECStatus
1335SSL_ConfigServerSessionIDCacheInstance(	cacheDesc *cache,
1336                                int      maxCacheEntries,
1337                                PRUint32 ssl2_timeout,
1338                                PRUint32 ssl3_timeout,
1339                                const char *   directory, PRBool shared)
1340{
1341    return ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
1342                                                         ssl2_timeout,
1343                                                         ssl3_timeout,
1344                                                         directory,
1345                                                         shared,
1346                                                         maxCacheEntries,
1347                                                         -1, -1);
1348}
1349
1350SECStatus
1351SSL_ConfigServerSessionIDCache(	int      maxCacheEntries,
1352				PRUint32 ssl2_timeout,
1353			       	PRUint32 ssl3_timeout,
1354			  const char *   directory)
1355{
1356    ssl_InitSessionCacheLocks();
1357    return SSL_ConfigServerSessionIDCacheInstance(&globalCache,
1358    		maxCacheEntries, ssl2_timeout, ssl3_timeout, directory, PR_FALSE);
1359}
1360
1361SECStatus
1362SSL_ShutdownServerSessionIDCacheInstance(cacheDesc *cache)
1363{
1364    CloseCache(cache);
1365    return SECSuccess;
1366}
1367
1368SECStatus
1369SSL_ShutdownServerSessionIDCache(void)
1370{
1371#if defined(XP_UNIX) || defined(XP_BEOS)
1372    /* Stop the thread that polls cache for expired locks on Unix */
1373    StopLockPoller(&globalCache);
1374#endif
1375    SSL3_ShutdownServerCache();
1376    return SSL_ShutdownServerSessionIDCacheInstance(&globalCache);
1377}
1378
1379/* Use this function, instead of SSL_ConfigServerSessionIDCache,
1380 * if the cache will be shared by multiple processes.
1381 */
1382static SECStatus
1383ssl_ConfigMPServerSIDCacheWithOpt(      PRUint32 ssl2_timeout,
1384                                        PRUint32 ssl3_timeout,
1385                                        const char *   directory,
1386                                        int maxCacheEntries,
1387                                        int maxCertCacheEntries,
1388                                        int maxSrvNameCacheEntries)
1389{
1390    char *	envValue;
1391    char *	inhValue;
1392    cacheDesc * cache         = &globalCache;
1393    PRUint32    fmStrLen;
1394    SECStatus 	result;
1395    PRStatus 	prStatus;
1396    SECStatus	putEnvFailed;
1397    inheritance inherit;
1398    char        fmString[PR_FILEMAP_STRING_BUFSIZE];
1399
1400    isMultiProcess = PR_TRUE;
1401    result = ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
1402                  ssl2_timeout, ssl3_timeout, directory, PR_TRUE,
1403        maxCacheEntries, maxCacheEntries, maxSrvNameCacheEntries);
1404    if (result != SECSuccess)
1405        return result;
1406
1407    prStatus = PR_ExportFileMapAsString(cache->cacheMemMap,
1408                                        sizeof fmString, fmString);
1409    if ((prStatus != PR_SUCCESS) || !(fmStrLen = strlen(fmString))) {
1410	SET_ERROR_CODE
1411	return SECFailure;
1412    }
1413
1414    inherit.cacheMemSize	= cache->cacheMemSize;
1415    inherit.fmStrLen            = fmStrLen;
1416
1417    inhValue = BTOA_DataToAscii((unsigned char *)&inherit, sizeof inherit);
1418    if (!inhValue || !strlen(inhValue)) {
1419	SET_ERROR_CODE
1420	return SECFailure;
1421    }
1422    envValue = PR_smprintf("%s,%s", inhValue, fmString);
1423    if (!envValue || !strlen(envValue)) {
1424	SET_ERROR_CODE
1425	return SECFailure;
1426    }
1427    PORT_Free(inhValue);
1428
1429    putEnvFailed = (SECStatus)NSS_PutEnv(envVarName, envValue);
1430    PR_smprintf_free(envValue);
1431    if (putEnvFailed) {
1432        SET_ERROR_CODE
1433        result = SECFailure;
1434    }
1435
1436#if defined(XP_UNIX) || defined(XP_BEOS)
1437    /* Launch thread to poll cache for expired locks on Unix */
1438    LaunchLockPoller(cache);
1439#endif
1440    return result;
1441}
1442
1443/* Use this function, instead of SSL_ConfigServerSessionIDCache,
1444 * if the cache will be shared by multiple processes.
1445 */
1446SECStatus
1447SSL_ConfigMPServerSIDCache(	int      maxCacheEntries,
1448				PRUint32 ssl2_timeout,
1449			       	PRUint32 ssl3_timeout,
1450		          const char *   directory)
1451{
1452    return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout,
1453                                             ssl3_timeout,
1454                                             directory,
1455                                             maxCacheEntries,
1456                                             -1, -1);
1457}
1458
1459SECStatus
1460SSL_ConfigServerSessionIDCacheWithOpt(
1461				PRUint32 ssl2_timeout,
1462			       	PRUint32 ssl3_timeout,
1463                                const char *   directory,
1464                                int maxCacheEntries,
1465                                int maxCertCacheEntries,
1466                                int maxSrvNameCacheEntries,
1467                                PRBool enableMPCache)
1468{
1469    if (!enableMPCache) {
1470        ssl_InitSessionCacheLocks();
1471        return ssl_ConfigServerSessionIDCacheInstanceWithOpt(&globalCache,
1472           ssl2_timeout, ssl3_timeout, directory, PR_FALSE,
1473           maxCacheEntries, maxCertCacheEntries, maxSrvNameCacheEntries);
1474    } else {
1475        return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout, ssl3_timeout,
1476                directory, maxCacheEntries, maxCertCacheEntries,
1477                                                 maxSrvNameCacheEntries);
1478    }
1479}
1480
1481SECStatus
1482SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
1483{
1484    unsigned char * decoString = NULL;
1485    char *          fmString   = NULL;
1486    char *          myEnvString = NULL;
1487    unsigned int    decoLen;
1488    ptrdiff_t       ptr;
1489    inheritance     inherit;
1490    cacheDesc       my;
1491#ifdef WINNT
1492    sidCacheLock* newLocks;
1493    int           locks_initialized = 0;
1494    int           locks_to_initialize = 0;
1495#endif
1496    SECStatus     status = ssl_Init();
1497
1498    if (status != SECSuccess) {
1499	return status;
1500    }
1501
1502    myPid = SSL_GETPID();
1503
1504    /* If this child was created by fork(), and not by exec() on unix,
1505    ** then isMultiProcess will already be set.
1506    ** If not, we'll set it below.
1507    */
1508    if (isMultiProcess) {
1509	if (cache && cache->sharedCache) {
1510	    cache->sharedCache->everInherited = PR_TRUE;
1511	}
1512    	return SECSuccess;	/* already done. */
1513    }
1514
1515    ssl_InitSessionCacheLocks();
1516
1517    ssl_sid_lookup  = ServerSessionIDLookup;
1518    ssl_sid_cache   = ServerSessionIDCache;
1519    ssl_sid_uncache = ServerSessionIDUncache;
1520
1521    if (!envString) {
1522    	envString  = getenv(envVarName);
1523	if (!envString) {
1524	    SET_ERROR_CODE
1525	    return SECFailure;
1526	}
1527    }
1528    myEnvString = PORT_Strdup(envString);
1529    if (!myEnvString)
1530	return SECFailure;
1531    fmString = strchr(myEnvString, ',');
1532    if (!fmString)
1533    	goto loser;
1534    *fmString++ = 0;
1535
1536    decoString = ATOB_AsciiToData(myEnvString, &decoLen);
1537    if (!decoString) {
1538    	SET_ERROR_CODE
1539	goto loser;
1540    }
1541    if (decoLen != sizeof inherit) {
1542    	SET_ERROR_CODE
1543    	goto loser;
1544    }
1545
1546    PORT_Memcpy(&inherit, decoString, sizeof inherit);
1547
1548    if (strlen(fmString)  != inherit.fmStrLen ) {
1549    	goto loser;
1550    }
1551
1552    memset(cache, 0, sizeof *cache);
1553    cache->cacheMemSize	= inherit.cacheMemSize;
1554
1555    /* Create cache */
1556    cache->cacheMemMap = PR_ImportFileMapFromString(fmString);
1557    if(! cache->cacheMemMap) {
1558	goto loser;
1559    }
1560    cache->cacheMem = PR_MemMap(cache->cacheMemMap, 0, cache->cacheMemSize);
1561    if (! cache->cacheMem) {
1562	goto loser;
1563    }
1564    cache->sharedCache   = (cacheDesc *)cache->cacheMem;
1565
1566    if (cache->sharedCache->cacheMemSize != cache->cacheMemSize) {
1567	SET_ERROR_CODE
1568    	goto loser;
1569    }
1570
1571    /* We're now going to overwrite the local cache instance with the
1572    ** shared copy of the cache struct, then update several values in
1573    ** the local cache using the values for cache->cacheMemMap and
1574    ** cache->cacheMem computed just above.  So, we copy cache into
1575    ** the automatic variable "my", to preserve the variables while
1576    ** cache is overwritten.
1577    */
1578    my = *cache;  /* save values computed above. */
1579    memcpy(cache, cache->sharedCache, sizeof *cache); /* overwrite */
1580
1581    /* Fix pointers in our private copy of cache descriptor to point to
1582    ** spaces in shared memory, whose address is now in "my".
1583    */
1584    ptr = (ptrdiff_t)my.cacheMem;
1585    *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
1586    *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
1587    *(ptrdiff_t *)(&cache->certCacheLock) += ptr;
1588    *(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr;
1589    *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
1590    *(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
1591    *(ptrdiff_t *)(&cache->certCacheData) += ptr;
1592    *(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
1593    *(ptrdiff_t *)(&cache->ticketKeyNameSuffix) += ptr;
1594    *(ptrdiff_t *)(&cache->ticketEncKey ) += ptr;
1595    *(ptrdiff_t *)(&cache->ticketMacKey ) += ptr;
1596    *(ptrdiff_t *)(&cache->ticketKeysValid) += ptr;
1597    *(ptrdiff_t *)(&cache->srvNameCacheData) += ptr;
1598
1599    cache->cacheMemMap = my.cacheMemMap;
1600    cache->cacheMem    = my.cacheMem;
1601    cache->sharedCache = (cacheDesc *)cache->cacheMem;
1602
1603#ifdef WINNT
1604    /*  On Windows NT we need to "fix" the sidCacheLocks here to support fibers
1605    **  When NT fibers are used in a multi-process server, a second level of
1606    **  locking is needed to prevent a deadlock, in case a fiber acquires the
1607    **  cross-process mutex, yields, and another fiber is later scheduled on
1608    **  the same native thread and tries to acquire the cross-process mutex.
1609    **  We do this by using a PRLock in the sslMutex. However, it is stored in
1610    **  shared memory as part of sidCacheLocks, and we don't want to overwrite
1611    **  the PRLock of the parent process. So we need to make new, private
1612    **  copies of sidCacheLocks before modifying the sslMutex with our own
1613    **  PRLock
1614    */
1615
1616    /* note from jpierre : this should be free'd in child processes when
1617    ** a function is added to delete the SSL session cache in the future.
1618    */
1619    locks_to_initialize = cache->numSIDCacheLocks + 3;
1620    newLocks = PORT_NewArray(sidCacheLock, locks_to_initialize);
1621    if (!newLocks)
1622    	goto loser;
1623    /* copy the old locks */
1624    memcpy(newLocks, cache->sidCacheLocks,
1625           locks_to_initialize * sizeof(sidCacheLock));
1626    cache->sidCacheLocks = newLocks;
1627    /* fix the locks */
1628    for (; locks_initialized < locks_to_initialize; ++locks_initialized) {
1629        /* now, make a local PRLock in this sslMutex for this child process */
1630	SECStatus err;
1631        err = sslMutex_2LevelInit(&newLocks[locks_initialized].mutex);
1632	if (err != SECSuccess) {
1633	    cache->numSIDCacheLocksInitialized = locks_initialized;
1634	    goto loser;
1635    	}
1636    }
1637    cache->numSIDCacheLocksInitialized = locks_initialized;
1638
1639    /* also fix the key and cert cache which use the last 2 lock entries */
1640    cache->keyCacheLock  = cache->sidCacheLocks + cache->numSIDCacheLocks;
1641    cache->certCacheLock = cache->keyCacheLock  + 1;
1642    cache->srvNameCacheLock = cache->certCacheLock  + 1;
1643#endif
1644
1645    PORT_Free(myEnvString);
1646    PORT_Free(decoString);
1647
1648    /* mark that we have inherited this. */
1649    cache->sharedCache->everInherited = PR_TRUE;
1650    isMultiProcess = PR_TRUE;
1651
1652    return SECSuccess;
1653
1654loser:
1655    PORT_Free(myEnvString);
1656    if (decoString)
1657	PORT_Free(decoString);
1658    CloseCache(cache);
1659    return SECFailure;
1660}
1661
1662SECStatus
1663SSL_InheritMPServerSIDCache(const char * envString)
1664{
1665    return SSL_InheritMPServerSIDCacheInstance(&globalCache, envString);
1666}
1667
1668#if defined(XP_UNIX) || defined(XP_BEOS)
1669
1670#define SID_LOCK_EXPIRATION_TIMEOUT  30 /* seconds */
1671
1672static void
1673LockPoller(void * arg)
1674{
1675    cacheDesc *    cache         = (cacheDesc *)arg;
1676    cacheDesc *    sharedCache   = cache->sharedCache;
1677    sidCacheLock * pLock;
1678    PRIntervalTime timeout;
1679    PRUint32       now;
1680    PRUint32       then;
1681    int            locks_polled  = 0;
1682    int            locks_to_poll = cache->numSIDCacheLocks + 2;
1683    PRUint32       expiration    = cache->mutexTimeout;
1684
1685    timeout = PR_SecondsToInterval(expiration);
1686    while(!sharedCache->stopPolling) {
1687    	PR_Sleep(timeout);
1688	if (sharedCache->stopPolling)
1689	    break;
1690
1691	now   = ssl_Time();
1692	then  = now - expiration;
1693	for (pLock = cache->sidCacheLocks, locks_polled = 0;
1694	     locks_to_poll > locks_polled && !sharedCache->stopPolling;
1695	     ++locks_polled, ++pLock ) {
1696	    pid_t pid;
1697
1698	    if (pLock->timeStamp   < then &&
1699	        pLock->timeStamp   != 0 &&
1700		(pid = pLock->pid) != 0) {
1701
1702	    	/* maybe we should try the lock? */
1703		int result = kill(pid, 0);
1704		if (result < 0 && errno == ESRCH) {
1705		    SECStatus rv;
1706		    /* No process exists by that pid any more.
1707		    ** Treat this mutex as abandoned.
1708		    */
1709		    pLock->timeStamp = now;
1710		    pLock->pid       = 0;
1711		    rv = sslMutex_Unlock(&pLock->mutex);
1712		    if (rv != SECSuccess) {
1713		    	/* Now what? */
1714		    }
1715		}
1716	    }
1717	} /* end of loop over locks */
1718    } /* end of entire polling loop */
1719}
1720
1721/* Launch thread to poll cache for expired locks */
1722static SECStatus
1723LaunchLockPoller(cacheDesc *cache)
1724{
1725    const char * timeoutString;
1726    PRThread *   pollerThread;
1727
1728    cache->mutexTimeout = SID_LOCK_EXPIRATION_TIMEOUT;
1729    timeoutString       = getenv("NSS_SSL_SERVER_CACHE_MUTEX_TIMEOUT");
1730    if (timeoutString) {
1731	long newTime = strtol(timeoutString, 0, 0);
1732	if (newTime == 0)
1733	    return SECSuccess;  /* application doesn't want poller thread */
1734	if (newTime > 0)
1735	    cache->mutexTimeout = (PRUint32)newTime;
1736	/* if error (newTime < 0) ignore it and use default */
1737    }
1738
1739    pollerThread =
1740	PR_CreateThread(PR_USER_THREAD, LockPoller, cache, PR_PRIORITY_NORMAL,
1741	                PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
1742    if (!pollerThread) {
1743    	return SECFailure;
1744    }
1745    cache->poller = pollerThread;
1746    return SECSuccess;
1747}
1748
1749/* Stop the thread that polls cache for expired locks */
1750static SECStatus
1751StopLockPoller(cacheDesc *cache)
1752{
1753    if (!cache->poller) {
1754	return SECSuccess;
1755    }
1756    cache->sharedCache->stopPolling = PR_TRUE;
1757    if (PR_Interrupt(cache->poller) != PR_SUCCESS) {
1758	return SECFailure;
1759    }
1760    if (PR_JoinThread(cache->poller) != PR_SUCCESS) {
1761	return SECFailure;
1762    }
1763    cache->poller = NULL;
1764    return SECSuccess;
1765}
1766#endif
1767
1768/************************************************************************
1769 *  Code dealing with shared wrapped symmetric wrapping keys below      *
1770 ************************************************************************/
1771
1772/* If now is zero, it implies that the lock is not held, and must be
1773** aquired here.
1774*/
1775static PRBool
1776getSvrWrappingKey(PRInt32                symWrapMechIndex,
1777               SSL3KEAType               exchKeyType,
1778               SSLWrappedSymWrappingKey *wswk,
1779	       cacheDesc *               cache,
1780	       PRUint32                  lockTime)
1781{
1782    PRUint32  ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
1783    SSLWrappedSymWrappingKey * pwswk = cache->keyCacheData + ndx;
1784    PRUint32  now = 0;
1785    PRBool    rv  = PR_FALSE;
1786
1787    if (!cache->cacheMem) { /* cache is uninitialized */
1788	PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
1789	return rv;
1790    }
1791    if (!lockTime) {
1792	lockTime = now = LockSidCacheLock(cache->keyCacheLock, now);
1793	if (!lockTime) {
1794	    return rv;
1795	}
1796    }
1797    if (pwswk->exchKeyType      == exchKeyType &&
1798	pwswk->symWrapMechIndex == symWrapMechIndex &&
1799	pwswk->wrappedSymKeyLen != 0) {
1800	*wswk = *pwswk;
1801	rv = PR_TRUE;
1802    }
1803    if (now) {
1804	UnlockSidCacheLock(cache->keyCacheLock);
1805    }
1806    return rv;
1807}
1808
1809PRBool
1810ssl_GetWrappingKey( PRInt32                   symWrapMechIndex,
1811                    SSL3KEAType               exchKeyType,
1812		    SSLWrappedSymWrappingKey *wswk)
1813{
1814    PRBool rv;
1815
1816    PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
1817    PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
1818    if ((unsigned)exchKeyType < kt_kea_size &&
1819        (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) {
1820	rv = getSvrWrappingKey(symWrapMechIndex, exchKeyType, wswk,
1821	                       &globalCache, 0);
1822    } else {
1823    	rv = PR_FALSE;
1824    }
1825
1826    return rv;
1827}
1828
1829/* Wrap and cache a session ticket key. */
1830static PRBool
1831WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey,
1832              const char *keyName, encKeyCacheEntry* cacheEntry)
1833{
1834    SECItem wrappedKey = {siBuffer, NULL, 0};
1835
1836    wrappedKey.len = SECKEY_PublicKeyStrength(svrPubKey);
1837    PORT_Assert(wrappedKey.len <= sizeof(cacheEntry->bytes));
1838    if (wrappedKey.len > sizeof(cacheEntry->bytes))
1839	return PR_FALSE;
1840    wrappedKey.data = cacheEntry->bytes;
1841
1842    if (PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, symKey, &wrappedKey)
1843	    != SECSuccess) {
1844	SSL_DBG(("%d: SSL[%s]: Unable to wrap session ticket %s.",
1845		    SSL_GETPID(), "unknown", keyName));
1846	return PR_FALSE;
1847    }
1848    cacheEntry->length = wrappedKey.len;
1849    return PR_TRUE;
1850}
1851
1852static PRBool
1853GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey,
1854                   PK11SymKey **macKey)
1855{
1856    PK11SlotInfo *slot;
1857    CK_MECHANISM_TYPE mechanismArray[2];
1858    PK11SymKey *aesKeyTmp = NULL;
1859    PK11SymKey *macKeyTmp = NULL;
1860    cacheDesc *cache = &globalCache;
1861    PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN];
1862    PRUint8 *ticketKeyNameSuffix;
1863
1864    if (!cache->cacheMem) {
1865        /* cache is not initalized. Use stack buffer */
1866        ticketKeyNameSuffix = ticketKeyNameSuffixLocal;
1867    } else {
1868        ticketKeyNameSuffix = cache->ticketKeyNameSuffix;
1869    }
1870
1871    if (PK11_GenerateRandom(ticketKeyNameSuffix,
1872	    SESS_TICKET_KEY_VAR_NAME_LEN) != SECSuccess) {
1873	SSL_DBG(("%d: SSL[%s]: Unable to generate random key name bytes.",
1874		    SSL_GETPID(), "unknown"));
1875	goto loser;
1876    }
1877
1878    mechanismArray[0] = CKM_AES_CBC;
1879    mechanismArray[1] = CKM_SHA256_HMAC;
1880
1881    slot = PK11_GetBestSlotMultiple(mechanismArray, 2, pwArg);
1882    if (slot) {
1883	aesKeyTmp = PK11_KeyGen(slot, mechanismArray[0], NULL,
1884                                AES_256_KEY_LENGTH, pwArg);
1885	macKeyTmp = PK11_KeyGen(slot, mechanismArray[1], NULL,
1886                                SHA256_LENGTH, pwArg);
1887	PK11_FreeSlot(slot);
1888    }
1889
1890    if (aesKeyTmp == NULL || macKeyTmp == NULL) {
1891	SSL_DBG(("%d: SSL[%s]: Unable to generate session ticket keys.",
1892		    SSL_GETPID(), "unknown"));
1893	goto loser;
1894    }
1895    PORT_Memcpy(keyName, ticketKeyNameSuffix, SESS_TICKET_KEY_VAR_NAME_LEN);
1896    *aesKey = aesKeyTmp;
1897    *macKey = macKeyTmp;
1898    return PR_TRUE;
1899
1900loser:
1901    if (aesKeyTmp)
1902	PK11_FreeSymKey(aesKeyTmp);
1903    if (macKeyTmp)
1904	PK11_FreeSymKey(macKeyTmp);
1905    return PR_FALSE;
1906}
1907
1908static PRBool
1909GenerateAndWrapTicketKeys(SECKEYPublicKey *svrPubKey, void *pwArg,
1910                          unsigned char *keyName, PK11SymKey **aesKey,
1911                          PK11SymKey **macKey)
1912{
1913    PK11SymKey *aesKeyTmp = NULL;
1914    PK11SymKey *macKeyTmp = NULL;
1915    cacheDesc *cache = &globalCache;
1916
1917    if (!GenerateTicketKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp)) {
1918        goto loser;
1919    }
1920
1921    if (cache->cacheMem) {
1922        /* Export the keys to the shared cache in wrapped form. */
1923        if (!WrapTicketKey(svrPubKey, aesKeyTmp, "enc key", cache->ticketEncKey))
1924            goto loser;
1925        if (!WrapTicketKey(svrPubKey, macKeyTmp, "mac key", cache->ticketMacKey))
1926            goto loser;
1927    }
1928    *aesKey = aesKeyTmp;
1929    *macKey = macKeyTmp;
1930    return PR_TRUE;
1931
1932loser:
1933    if (aesKeyTmp)
1934	PK11_FreeSymKey(aesKeyTmp);
1935    if (macKeyTmp)
1936	PK11_FreeSymKey(macKeyTmp);
1937    return PR_FALSE;
1938}
1939
1940static PRBool
1941UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName,
1942                       PK11SymKey **aesKey, PK11SymKey **macKey)
1943{
1944    SECItem wrappedKey = {siBuffer, NULL, 0};
1945    PK11SymKey *aesKeyTmp = NULL;
1946    PK11SymKey *macKeyTmp = NULL;
1947    cacheDesc *cache = &globalCache;
1948
1949    wrappedKey.data = cache->ticketEncKey->bytes;
1950    wrappedKey.len = cache->ticketEncKey->length;
1951    PORT_Assert(wrappedKey.len <= sizeof(cache->ticketEncKey->bytes));
1952    aesKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
1953	CKM_AES_CBC, CKA_DECRYPT, 0);
1954
1955    wrappedKey.data = cache->ticketMacKey->bytes;
1956    wrappedKey.len = cache->ticketMacKey->length;
1957    PORT_Assert(wrappedKey.len <= sizeof(cache->ticketMacKey->bytes));
1958    macKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
1959	CKM_SHA256_HMAC, CKA_SIGN, 0);
1960
1961    if (aesKeyTmp == NULL || macKeyTmp == NULL) {
1962	SSL_DBG(("%d: SSL[%s]: Unable to unwrap session ticket keys.",
1963		    SSL_GETPID(), "unknown"));
1964	goto loser;
1965    }
1966    SSL_DBG(("%d: SSL[%s]: Successfully unwrapped session ticket keys.",
1967		SSL_GETPID(), "unknown"));
1968
1969    PORT_Memcpy(keyName, cache->ticketKeyNameSuffix,
1970	SESS_TICKET_KEY_VAR_NAME_LEN);
1971    *aesKey = aesKeyTmp;
1972    *macKey = macKeyTmp;
1973    return PR_TRUE;
1974
1975loser:
1976    if (aesKeyTmp)
1977	PK11_FreeSymKey(aesKeyTmp);
1978    if (macKeyTmp)
1979	PK11_FreeSymKey(macKeyTmp);
1980    return PR_FALSE;
1981}
1982
1983PRBool
1984ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey,
1985                               SECKEYPublicKey *svrPubKey, void *pwArg,
1986                               unsigned char *keyName, PK11SymKey **aesKey,
1987                               PK11SymKey **macKey)
1988{
1989    PRUint32 now = 0;
1990    PRBool rv = PR_FALSE;
1991    PRBool keysGenerated = PR_FALSE;
1992    cacheDesc *cache = &globalCache;
1993
1994    if (!cache->cacheMem) {
1995        /* cache is uninitialized. Generate keys and return them
1996         * without caching. */
1997        return GenerateTicketKeys(pwArg, keyName, aesKey, macKey);
1998    }
1999
2000    now = LockSidCacheLock(cache->keyCacheLock, now);
2001    if (!now)
2002	return rv;
2003
2004    if (!*(cache->ticketKeysValid)) {
2005	/* Keys do not exist, create them. */
2006	if (!GenerateAndWrapTicketKeys(svrPubKey, pwArg, keyName,
2007		aesKey, macKey))
2008	    goto loser;
2009	keysGenerated = PR_TRUE;
2010	*(cache->ticketKeysValid) = 1;
2011    }
2012
2013    rv = PR_TRUE;
2014
2015 loser:
2016    UnlockSidCacheLock(cache->keyCacheLock);
2017    if (rv && !keysGenerated)
2018	rv = UnwrapCachedTicketKeys(svrPrivKey, keyName, aesKey, macKey);
2019    return rv;
2020}
2021
2022PRBool
2023ssl_GetSessionTicketKeys(unsigned char *keyName, unsigned char *encKey,
2024                         unsigned char *macKey)
2025{
2026    PRBool rv = PR_FALSE;
2027    PRUint32 now = 0;
2028    cacheDesc *cache = &globalCache;
2029    PRUint8 ticketMacKey[SHA256_LENGTH], ticketEncKey[AES_256_KEY_LENGTH];
2030    PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN];
2031    PRUint8 *ticketMacKeyPtr, *ticketEncKeyPtr, *ticketKeyNameSuffix;
2032    PRBool cacheIsEnabled = PR_TRUE;
2033
2034    if (!cache->cacheMem) { /* cache is uninitialized */
2035        cacheIsEnabled = PR_FALSE;
2036        ticketKeyNameSuffix = ticketKeyNameSuffixLocal;
2037        ticketEncKeyPtr = ticketEncKey;
2038        ticketMacKeyPtr = ticketMacKey;
2039    } else {
2040        /* these values have constant memory locations in the cache.
2041         * Ok to reference them without holding the lock. */
2042        ticketKeyNameSuffix = cache->ticketKeyNameSuffix;
2043        ticketEncKeyPtr = cache->ticketEncKey->bytes;
2044        ticketMacKeyPtr = cache->ticketMacKey->bytes;
2045    }
2046
2047    if (cacheIsEnabled) {
2048        /* Grab lock if initialized. */
2049        now = LockSidCacheLock(cache->keyCacheLock, now);
2050        if (!now)
2051            return rv;
2052    }
2053    /* Going to regenerate keys on every call if cache was not
2054     * initialized. */
2055    if (!cacheIsEnabled || !*(cache->ticketKeysValid)) {
2056	if (PK11_GenerateRandom(ticketKeyNameSuffix,
2057		SESS_TICKET_KEY_VAR_NAME_LEN) != SECSuccess)
2058	    goto loser;
2059	if (PK11_GenerateRandom(ticketEncKeyPtr,
2060                                AES_256_KEY_LENGTH) != SECSuccess)
2061	    goto loser;
2062	if (PK11_GenerateRandom(ticketMacKeyPtr,
2063                                SHA256_LENGTH) != SECSuccess)
2064	    goto loser;
2065        if (cacheIsEnabled) {
2066            *(cache->ticketKeysValid) = 1;
2067        }
2068    }
2069
2070    rv = PR_TRUE;
2071
2072 loser:
2073    if (cacheIsEnabled) {
2074        UnlockSidCacheLock(cache->keyCacheLock);
2075    }
2076    if (rv) {
2077	PORT_Memcpy(keyName, ticketKeyNameSuffix,
2078                    SESS_TICKET_KEY_VAR_NAME_LEN);
2079	PORT_Memcpy(encKey, ticketEncKeyPtr, AES_256_KEY_LENGTH);
2080	PORT_Memcpy(macKey, ticketMacKeyPtr, SHA256_LENGTH);
2081    }
2082    return rv;
2083}
2084
2085/* The caller passes in the new value it wants
2086 * to set.  This code tests the wrapped sym key entry in the shared memory.
2087 * If it is uninitialized, this function writes the caller's value into
2088 * the disk entry, and returns false.
2089 * Otherwise, it overwrites the caller's wswk with the value obtained from
2090 * the disk, and returns PR_TRUE.
2091 * This is all done while holding the locks/mutexes necessary to make
2092 * the operation atomic.
2093 */
2094PRBool
2095ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
2096{
2097    cacheDesc *   cache            = &globalCache;
2098    PRBool        rv               = PR_FALSE;
2099    SSL3KEAType   exchKeyType      = wswk->exchKeyType;
2100                                /* type of keys used to wrap SymWrapKey*/
2101    PRInt32       symWrapMechIndex = wswk->symWrapMechIndex;
2102    PRUint32      ndx;
2103    PRUint32      now = 0;
2104    SSLWrappedSymWrappingKey myWswk;
2105
2106    if (!cache->cacheMem) { /* cache is uninitialized */
2107	PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
2108	return 0;
2109    }
2110
2111    PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
2112    if ((unsigned)exchKeyType >= kt_kea_size)
2113    	return 0;
2114
2115    PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
2116    if ((unsigned)symWrapMechIndex >=  SSL_NUM_WRAP_MECHS)
2117    	return 0;
2118
2119    ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
2120    PORT_Memset(&myWswk, 0, sizeof myWswk);	/* eliminate UMRs. */
2121
2122    now = LockSidCacheLock(cache->keyCacheLock, now);
2123    if (now) {
2124	rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->exchKeyType,
2125	                       &myWswk, cache, now);
2126	if (rv) {
2127	    /* we found it on disk, copy it out to the caller. */
2128	    PORT_Memcpy(wswk, &myWswk, sizeof *wswk);
2129	} else {
2130	    /* Wasn't on disk, and we're still holding the lock, so write it. */
2131	    cache->keyCacheData[ndx] = *wswk;
2132	}
2133	UnlockSidCacheLock(cache->keyCacheLock);
2134    }
2135    return rv;
2136}
2137
2138#else  /* MAC version or other platform */
2139
2140#include "seccomon.h"
2141#include "cert.h"
2142#include "ssl.h"
2143#include "sslimpl.h"
2144
2145SECStatus
2146SSL_ConfigServerSessionIDCache(	int      maxCacheEntries,
2147				PRUint32 ssl2_timeout,
2148			       	PRUint32 ssl3_timeout,
2149			  const char *   directory)
2150{
2151    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigServerSessionIDCache)");
2152    return SECFailure;
2153}
2154
2155SECStatus
2156SSL_ConfigMPServerSIDCache(	int      maxCacheEntries,
2157				PRUint32 ssl2_timeout,
2158			       	PRUint32 ssl3_timeout,
2159		          const char *   directory)
2160{
2161    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigMPServerSIDCache)");
2162    return SECFailure;
2163}
2164
2165SECStatus
2166SSL_InheritMPServerSIDCache(const char * envString)
2167{
2168    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_InheritMPServerSIDCache)");
2169    return SECFailure;
2170}
2171
2172PRBool
2173ssl_GetWrappingKey( PRInt32                   symWrapMechIndex,
2174                    SSL3KEAType               exchKeyType,
2175		    SSLWrappedSymWrappingKey *wswk)
2176{
2177    PRBool rv = PR_FALSE;
2178    PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)");
2179    return rv;
2180}
2181
2182/* This is a kind of test-and-set.  The caller passes in the new value it wants
2183 * to set.  This code tests the wrapped sym key entry in the shared memory.
2184 * If it is uninitialized, this function writes the caller's value into
2185 * the disk entry, and returns false.
2186 * Otherwise, it overwrites the caller's wswk with the value obtained from
2187 * the disk, and returns PR_TRUE.
2188 * This is all done while holding the locks/mutexes necessary to make
2189 * the operation atomic.
2190 */
2191PRBool
2192ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
2193{
2194    PRBool        rv = PR_FALSE;
2195    PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrappingKey)");
2196    return rv;
2197}
2198
2199PRUint32
2200SSL_GetMaxServerCacheLocks(void)
2201{
2202    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_GetMaxServerCacheLocks)");
2203    return -1;
2204}
2205
2206SECStatus
2207SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
2208{
2209    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_SetMaxServerCacheLocks)");
2210    return SECFailure;
2211}
2212
2213#endif /* XP_UNIX || XP_WIN32 */
2214