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