security/nss/lib/ssl/sslsnce.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/ssl/sslsnce.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2212 @@
     1.4 +/* This file implements the SERVER Session ID cache. 
     1.5 + * NOTE:  The contents of this file are NOT used by the client.
     1.6 + *
     1.7 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
    1.10 +
    1.11 +/* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server 
    1.12 + * cache sids!
    1.13 + *
    1.14 + * About record locking among different server processes:
    1.15 + *
    1.16 + * All processes that are part of the same conceptual server (serving on 
    1.17 + * the same address and port) MUST share a common SSL session cache. 
    1.18 + * This code makes the content of the shared cache accessible to all
    1.19 + * processes on the same "server".  This code works on Unix and Win32 only.
    1.20 + *
    1.21 + * We use NSPR anonymous shared memory and move data to & from shared memory.
    1.22 + * We must do explicit locking of the records for all reads and writes.
    1.23 + * The set of Cache entries are divided up into "sets" of 128 entries. 
    1.24 + * Each set is protected by a lock.  There may be one or more sets protected
    1.25 + * by each lock.  That is, locks to sets are 1:N.
    1.26 + * There is one lock for the entire cert cache.
    1.27 + * There is one lock for the set of wrapped sym wrap keys.
    1.28 + *
    1.29 + * The anonymous shared memory is laid out as if it were declared like this:
    1.30 + *
    1.31 + * struct {
    1.32 + *     cacheDescriptor          desc;
    1.33 + *     sidCacheLock             sidCacheLocks[ numSIDCacheLocks];
    1.34 + *     sidCacheLock             keyCacheLock;
    1.35 + *     sidCacheLock             certCacheLock;
    1.36 + *     sidCacheSet              sidCacheSets[ numSIDCacheSets ];
    1.37 + *     sidCacheEntry            sidCacheData[ numSIDCacheEntries];
    1.38 + *     certCacheEntry           certCacheData[numCertCacheEntries];
    1.39 + *     SSLWrappedSymWrappingKey keyCacheData[kt_kea_size][SSL_NUM_WRAP_MECHS];
    1.40 + *     PRUint8                  keyNameSuffix[SESS_TICKET_KEY_VAR_NAME_LEN]
    1.41 + *     encKeyCacheEntry         ticketEncKey; // Wrapped in non-bypass mode
    1.42 + *     encKeyCacheEntry         ticketMacKey; // Wrapped in non-bypass mode
    1.43 + *     PRBool                   ticketKeysValid;
    1.44 + *     sidCacheLock             srvNameCacheLock;
    1.45 + *     srvNameCacheEntry        srvNameData[ numSrvNameCacheEntries ];
    1.46 + * } cacheMemCacheData;
    1.47 + */
    1.48 +#include "seccomon.h"
    1.49 +
    1.50 +#if defined(XP_UNIX) || defined(XP_WIN32) || defined (XP_OS2) || defined(XP_BEOS)
    1.51 +
    1.52 +#include "cert.h"
    1.53 +#include "ssl.h"
    1.54 +#include "sslimpl.h"
    1.55 +#include "sslproto.h"
    1.56 +#include "pk11func.h"
    1.57 +#include "base64.h"
    1.58 +#include "keyhi.h"
    1.59 +#ifdef NO_PKCS11_BYPASS
    1.60 +#include "blapit.h"
    1.61 +#include "sechash.h"
    1.62 +#else
    1.63 +#include "blapi.h"
    1.64 +#endif
    1.65 +
    1.66 +#include <stdio.h>
    1.67 +
    1.68 +#if defined(XP_UNIX) || defined(XP_BEOS)
    1.69 +
    1.70 +#include <syslog.h>
    1.71 +#include <fcntl.h>
    1.72 +#include <unistd.h>
    1.73 +#include <errno.h>
    1.74 +#include <signal.h>
    1.75 +#include "unix_err.h"
    1.76 +
    1.77 +#else
    1.78 +
    1.79 +#ifdef XP_WIN32
    1.80 +#include <wtypes.h>
    1.81 +#include "win32err.h"
    1.82 +#endif
    1.83 +
    1.84 +#endif 
    1.85 +#include <sys/types.h>
    1.86 +
    1.87 +#define SET_ERROR_CODE /* reminder */
    1.88 +
    1.89 +#include "nspr.h"
    1.90 +#include "sslmutex.h"
    1.91 +
    1.92 +/*
    1.93 +** Format of a cache entry in the shared memory.
    1.94 +*/ 
    1.95 +struct sidCacheEntryStr {
    1.96 +/* 16 */    PRIPv6Addr  addr;	/* client's IP address */
    1.97 +/*  4 */    PRUint32    creationTime;
    1.98 +/*  4 */    PRUint32    lastAccessTime;	
    1.99 +/*  4 */    PRUint32    expirationTime;
   1.100 +/*  2 */    PRUint16	version;
   1.101 +/*  1 */    PRUint8	valid;
   1.102 +/*  1 */    PRUint8     sessionIDLength;
   1.103 +/* 32 */    PRUint8     sessionID[SSL3_SESSIONID_BYTES];
   1.104 +/*  2 */    PRUint16    authAlgorithm;
   1.105 +/*  2 */    PRUint16    authKeyBits;
   1.106 +/*  2 */    PRUint16    keaType;
   1.107 +/*  2 */    PRUint16    keaKeyBits;
   1.108 +/* 72  - common header total */
   1.109 +
   1.110 +    union {
   1.111 +	struct {
   1.112 +/* 64 */    PRUint8	masterKey[SSL_MAX_MASTER_KEY_BYTES];
   1.113 +/* 32 */    PRUint8	cipherArg[SSL_MAX_CYPHER_ARG_BYTES];
   1.114 +
   1.115 +/*  1 */    PRUint8	cipherType;
   1.116 +/*  1 */    PRUint8	masterKeyLen;
   1.117 +/*  1 */    PRUint8	keyBits;
   1.118 +/*  1 */    PRUint8	secretKeyBits;
   1.119 +/*  1 */    PRUint8	cipherArgLen;
   1.120 +/*101 */} ssl2;
   1.121 +
   1.122 +	struct {
   1.123 +/*  2 */    ssl3CipherSuite  cipherSuite;
   1.124 +/*  2 */    PRUint16    compression; 	/* SSLCompressionMethod */
   1.125 +
   1.126 +/* 52 */    ssl3SidKeys keys;	/* keys, wrapped as needed. */
   1.127 +
   1.128 +/*  4 */    PRUint32    masterWrapMech; 
   1.129 +/*  4 */    SSL3KEAType exchKeyType;
   1.130 +/*  4 */    PRInt32     certIndex;
   1.131 +/*  4 */    PRInt32     srvNameIndex;
   1.132 +/* 32 */    PRUint8     srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */
   1.133 +/*104 */} ssl3;
   1.134 +/* force sizeof(sidCacheEntry) to be a multiple of cache line size */
   1.135 +        struct {
   1.136 +/*120 */    PRUint8     filler[120]; /* 72+120==192, a multiple of 16 */
   1.137 +	} forceSize;
   1.138 +    } u;
   1.139 +};
   1.140 +typedef struct sidCacheEntryStr sidCacheEntry;
   1.141 +
   1.142 +/* The length of this struct is supposed to be a power of 2, e.g. 4KB */
   1.143 +struct certCacheEntryStr {
   1.144 +    PRUint16    certLength;				/*    2 */
   1.145 +    PRUint16    sessionIDLength;			/*    2 */
   1.146 +    PRUint8 	sessionID[SSL3_SESSIONID_BYTES];	/*   32 */
   1.147 +    PRUint8 	cert[SSL_MAX_CACHED_CERT_LEN];		/* 4060 */
   1.148 +};						/* total   4096 */
   1.149 +typedef struct certCacheEntryStr certCacheEntry;
   1.150 +
   1.151 +struct sidCacheLockStr {
   1.152 +    PRUint32	timeStamp;
   1.153 +    sslMutex	mutex;
   1.154 +    sslPID	pid;
   1.155 +};
   1.156 +typedef struct sidCacheLockStr sidCacheLock;
   1.157 +
   1.158 +struct sidCacheSetStr {
   1.159 +    PRIntn	next;
   1.160 +};
   1.161 +typedef struct sidCacheSetStr sidCacheSet;
   1.162 +
   1.163 +struct encKeyCacheEntryStr {
   1.164 +    PRUint8	bytes[512];
   1.165 +    PRInt32	length;
   1.166 +};
   1.167 +typedef struct encKeyCacheEntryStr encKeyCacheEntry;
   1.168 +
   1.169 +#define SSL_MAX_DNS_HOST_NAME  1024
   1.170 +
   1.171 +struct srvNameCacheEntryStr {
   1.172 +    PRUint16    type;                                   /*    2 */
   1.173 +    PRUint16    nameLen;                                /*    2 */
   1.174 +    PRUint8	name[SSL_MAX_DNS_HOST_NAME + 12];       /* 1034 */
   1.175 +    PRUint8 	nameHash[SHA256_LENGTH];                /*   32 */
   1.176 +                                                        /* 1072 */
   1.177 +};
   1.178 +typedef struct srvNameCacheEntryStr srvNameCacheEntry;
   1.179 +
   1.180 +
   1.181 +struct cacheDescStr {
   1.182 +
   1.183 +    PRUint32            cacheMemSize;
   1.184 +
   1.185 +    PRUint32		numSIDCacheLocks;
   1.186 +    PRUint32		numSIDCacheSets;
   1.187 +    PRUint32		numSIDCacheSetsPerLock;
   1.188 +
   1.189 +    PRUint32            numSIDCacheEntries; 
   1.190 +    PRUint32            sidCacheSize;
   1.191 +
   1.192 +    PRUint32            numCertCacheEntries;
   1.193 +    PRUint32            certCacheSize;
   1.194 +
   1.195 +    PRUint32            numKeyCacheEntries;
   1.196 +    PRUint32            keyCacheSize;
   1.197 +
   1.198 +    PRUint32            numSrvNameCacheEntries;
   1.199 +    PRUint32            srvNameCacheSize;
   1.200 +
   1.201 +    PRUint32		ssl2Timeout;
   1.202 +    PRUint32		ssl3Timeout;
   1.203 +
   1.204 +    PRUint32            numSIDCacheLocksInitialized;
   1.205 +
   1.206 +    /* These values are volatile, and are accessed through sharedCache-> */
   1.207 +    PRUint32		nextCertCacheEntry;	/* certCacheLock protects */
   1.208 +    PRBool      	stopPolling;
   1.209 +    PRBool		everInherited;
   1.210 +
   1.211 +    /* The private copies of these values are pointers into shared mem */
   1.212 +    /* The copies of these values in shared memory are merely offsets */
   1.213 +    sidCacheLock    *          sidCacheLocks;
   1.214 +    sidCacheLock    *          keyCacheLock;
   1.215 +    sidCacheLock    *          certCacheLock;
   1.216 +    sidCacheLock    *          srvNameCacheLock;
   1.217 +    sidCacheSet     *          sidCacheSets;
   1.218 +    sidCacheEntry   *          sidCacheData;
   1.219 +    certCacheEntry  *          certCacheData;
   1.220 +    SSLWrappedSymWrappingKey * keyCacheData;
   1.221 +    PRUint8         *          ticketKeyNameSuffix;
   1.222 +    encKeyCacheEntry         * ticketEncKey;
   1.223 +    encKeyCacheEntry         * ticketMacKey;
   1.224 +    PRUint32        *          ticketKeysValid;
   1.225 +    srvNameCacheEntry *        srvNameCacheData;
   1.226 +
   1.227 +    /* Only the private copies of these pointers are valid */
   1.228 +    char *                     cacheMem;
   1.229 +    struct cacheDescStr *      sharedCache;  /* shared copy of this struct */
   1.230 +    PRFileMap *                cacheMemMap;
   1.231 +    PRThread  *                poller;
   1.232 +    PRUint32                   mutexTimeout;
   1.233 +    PRBool                     shared;
   1.234 +};
   1.235 +typedef struct cacheDescStr cacheDesc;
   1.236 +
   1.237 +static cacheDesc globalCache;
   1.238 +
   1.239 +static const char envVarName[] = { SSL_ENV_VAR_NAME };
   1.240 +
   1.241 +static PRBool isMultiProcess  = PR_FALSE;
   1.242 +
   1.243 +
   1.244 +#define DEF_SID_CACHE_ENTRIES  10000
   1.245 +#define DEF_CERT_CACHE_ENTRIES 250
   1.246 +#define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */
   1.247 +#define DEF_KEY_CACHE_ENTRIES  250
   1.248 +#define DEF_NAME_CACHE_ENTRIES  1000
   1.249 +
   1.250 +#define SID_CACHE_ENTRIES_PER_SET  128
   1.251 +#define SID_ALIGNMENT          16
   1.252 +
   1.253 +#define DEF_SSL2_TIMEOUT	100   /* seconds */
   1.254 +#define MAX_SSL2_TIMEOUT	100   /* seconds */
   1.255 +#define MIN_SSL2_TIMEOUT	  5   /* seconds */
   1.256 +
   1.257 +#define DEF_SSL3_TIMEOUT      86400L  /* 24 hours */
   1.258 +#define MAX_SSL3_TIMEOUT      86400L  /* 24 hours */
   1.259 +#define MIN_SSL3_TIMEOUT          5   /* seconds  */
   1.260 +
   1.261 +#if defined(AIX) || defined(LINUX) || defined(NETBSD) || defined(OPENBSD)
   1.262 +#define MAX_SID_CACHE_LOCKS 8	/* two FDs per lock */
   1.263 +#elif defined(OSF1)
   1.264 +#define MAX_SID_CACHE_LOCKS 16	/* one FD per lock */
   1.265 +#else
   1.266 +#define MAX_SID_CACHE_LOCKS 256
   1.267 +#endif
   1.268 +
   1.269 +#define SID_HOWMANY(val, size) (((val) + ((size) - 1)) / (size))
   1.270 +#define SID_ROUNDUP(val, size) ((size) * SID_HOWMANY((val), (size)))
   1.271 +
   1.272 +
   1.273 +static sslPID myPid;
   1.274 +static PRUint32  ssl_max_sid_cache_locks = MAX_SID_CACHE_LOCKS;
   1.275 +
   1.276 +/* forward static function declarations */
   1.277 +static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, 
   1.278 +                         unsigned nl);
   1.279 +static SECStatus LaunchLockPoller(cacheDesc *cache);
   1.280 +static SECStatus StopLockPoller(cacheDesc *cache);
   1.281 +
   1.282 +
   1.283 +struct inheritanceStr {
   1.284 +    PRUint32 cacheMemSize;
   1.285 +    PRUint32 fmStrLen;
   1.286 +};
   1.287 +
   1.288 +typedef struct inheritanceStr inheritance;
   1.289 +
   1.290 +#if defined(_WIN32) || defined(XP_OS2)
   1.291 +
   1.292 +#define DEFAULT_CACHE_DIRECTORY "\\temp"
   1.293 +
   1.294 +#endif /* _win32 */
   1.295 +
   1.296 +#if defined(XP_UNIX) || defined(XP_BEOS)
   1.297 +
   1.298 +#define DEFAULT_CACHE_DIRECTORY "/tmp"
   1.299 +
   1.300 +#endif /* XP_UNIX || XP_BEOS */
   1.301 +
   1.302 +
   1.303 +/************************************************************************/
   1.304 +
   1.305 +static PRUint32
   1.306 +LockSidCacheLock(sidCacheLock *lock, PRUint32 now)
   1.307 +{
   1.308 +    SECStatus      rv      = sslMutex_Lock(&lock->mutex);
   1.309 +    if (rv != SECSuccess)
   1.310 +    	return 0;
   1.311 +    if (!now)
   1.312 +	now  = ssl_Time();
   1.313 +    lock->timeStamp = now;
   1.314 +    lock->pid       = myPid;
   1.315 +    return now;
   1.316 +}
   1.317 +
   1.318 +static SECStatus
   1.319 +UnlockSidCacheLock(sidCacheLock *lock)
   1.320 +{
   1.321 +    SECStatus      rv;
   1.322 +
   1.323 +    lock->pid = 0;
   1.324 +    rv        = sslMutex_Unlock(&lock->mutex);
   1.325 +    return rv;
   1.326 +}
   1.327 +
   1.328 +/* returns the value of ssl_Time on success, zero on failure. */
   1.329 +static PRUint32
   1.330 +LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now)
   1.331 +{
   1.332 +    PRUint32       lockNum = set % cache->numSIDCacheLocks;
   1.333 +    sidCacheLock * lock    = cache->sidCacheLocks + lockNum;
   1.334 +
   1.335 +    return LockSidCacheLock(lock, now);
   1.336 +}
   1.337 +
   1.338 +static SECStatus
   1.339 +UnlockSet(cacheDesc *cache, PRUint32 set)
   1.340 +{
   1.341 +    PRUint32       lockNum = set % cache->numSIDCacheLocks;
   1.342 +    sidCacheLock * lock    = cache->sidCacheLocks + lockNum;
   1.343 +
   1.344 +    return UnlockSidCacheLock(lock);
   1.345 +}
   1.346 +
   1.347 +/************************************************************************/
   1.348 +
   1.349 +
   1.350 +/* Put a certificate in the cache.  Update the cert index in the sce.
   1.351 +*/
   1.352 +static PRUint32
   1.353 +CacheCert(cacheDesc * cache, CERTCertificate *cert, sidCacheEntry *sce)
   1.354 +{
   1.355 +    PRUint32        now;
   1.356 +    certCacheEntry  cce;
   1.357 +
   1.358 +    if ((cert->derCert.len > SSL_MAX_CACHED_CERT_LEN) ||
   1.359 +        (cert->derCert.len <= 0) ||
   1.360 +	(cert->derCert.data == NULL)) {
   1.361 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1.362 +	return 0;
   1.363 +    }
   1.364 +
   1.365 +    cce.sessionIDLength = sce->sessionIDLength;
   1.366 +    PORT_Memcpy(cce.sessionID, sce->sessionID, cce.sessionIDLength);
   1.367 +
   1.368 +    cce.certLength = cert->derCert.len;
   1.369 +    PORT_Memcpy(cce.cert, cert->derCert.data, cce.certLength);
   1.370 +
   1.371 +    /* get lock on cert cache */
   1.372 +    now = LockSidCacheLock(cache->certCacheLock, 0);
   1.373 +    if (now) {
   1.374 +
   1.375 +	/* Find where to place the next cert cache entry. */
   1.376 +	cacheDesc * sharedCache = cache->sharedCache;
   1.377 +	PRUint32    ndx         = sharedCache->nextCertCacheEntry;
   1.378 +
   1.379 +	/* write the entry */
   1.380 +	cache->certCacheData[ndx] = cce;
   1.381 +
   1.382 +	/* remember where we put it. */
   1.383 +	sce->u.ssl3.certIndex = ndx;
   1.384 +
   1.385 +	/* update the "next" cache entry index */
   1.386 +	sharedCache->nextCertCacheEntry = 
   1.387 +					(ndx + 1) % cache->numCertCacheEntries;
   1.388 +
   1.389 +	UnlockSidCacheLock(cache->certCacheLock);
   1.390 +    }
   1.391 +    return now;
   1.392 +
   1.393 +}
   1.394 +
   1.395 +/* Server configuration hash tables need to account the SECITEM.type
   1.396 + * field as well. These functions accomplish that. */
   1.397 +static PLHashNumber
   1.398 +Get32BitNameHash(const SECItem *name)
   1.399 +{
   1.400 +    PLHashNumber rv = SECITEM_Hash(name);
   1.401 +    
   1.402 +    PRUint8 *rvc = (PRUint8 *)&rv;
   1.403 +    rvc[ name->len % sizeof(rv) ] ^= name->type;
   1.404 +
   1.405 +    return rv;
   1.406 +}
   1.407 +
   1.408 +/* Put a name in the cache.  Update the cert index in the sce.
   1.409 +*/
   1.410 +static PRUint32
   1.411 +CacheSrvName(cacheDesc * cache, SECItem *name, sidCacheEntry *sce)
   1.412 +{
   1.413 +    PRUint32           now;
   1.414 +    PRUint32           ndx;
   1.415 +    srvNameCacheEntry  snce;
   1.416 +
   1.417 +    if (!name || name->len <= 0 ||
   1.418 +        name->len > SSL_MAX_DNS_HOST_NAME) {
   1.419 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1.420 +	return 0;
   1.421 +    }
   1.422 +
   1.423 +    snce.type = name->type;
   1.424 +    snce.nameLen = name->len;
   1.425 +    PORT_Memcpy(snce.name, name->data, snce.nameLen);
   1.426 +#ifdef NO_PKCS11_BYPASS
   1.427 +    HASH_HashBuf(HASH_AlgSHA256, snce.nameHash, name->data, name->len);
   1.428 +#else
   1.429 +    SHA256_HashBuf(snce.nameHash, (unsigned char*)name->data,
   1.430 +                   name->len);
   1.431 +#endif
   1.432 +    /* get index of the next name */
   1.433 +    ndx = Get32BitNameHash(name);
   1.434 +    /* get lock on cert cache */
   1.435 +    now = LockSidCacheLock(cache->srvNameCacheLock, 0);
   1.436 +    if (now) {
   1.437 +        if (cache->numSrvNameCacheEntries > 0) {
   1.438 +            /* Fit the index into array */
   1.439 +            ndx %= cache->numSrvNameCacheEntries;
   1.440 +            /* write the entry */
   1.441 +            cache->srvNameCacheData[ndx] = snce;
   1.442 +            /* remember where we put it. */
   1.443 +            sce->u.ssl3.srvNameIndex = ndx;
   1.444 +            /* Copy hash into sid hash */
   1.445 +            PORT_Memcpy(sce->u.ssl3.srvNameHash, snce.nameHash, SHA256_LENGTH);
   1.446 +        }
   1.447 +	UnlockSidCacheLock(cache->srvNameCacheLock);
   1.448 +    }
   1.449 +    return now;
   1.450 +}
   1.451 +
   1.452 +/*
   1.453 +** Convert local SID to shared memory one
   1.454 +*/
   1.455 +static void 
   1.456 +ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
   1.457 +{
   1.458 +    to->valid   = 1;
   1.459 +    to->version = from->version;
   1.460 +    to->addr    = from->addr;
   1.461 +    to->creationTime    = from->creationTime;
   1.462 +    to->lastAccessTime  = from->lastAccessTime;
   1.463 +    to->expirationTime  = from->expirationTime;
   1.464 +    to->authAlgorithm	= from->authAlgorithm;
   1.465 +    to->authKeyBits	= from->authKeyBits;
   1.466 +    to->keaType		= from->keaType;
   1.467 +    to->keaKeyBits	= from->keaKeyBits;
   1.468 +
   1.469 +    if (from->version < SSL_LIBRARY_VERSION_3_0) {
   1.470 +	if ((from->u.ssl2.masterKey.len > SSL_MAX_MASTER_KEY_BYTES) ||
   1.471 +	    (from->u.ssl2.cipherArg.len > SSL_MAX_CYPHER_ARG_BYTES)) {
   1.472 +	    SSL_DBG(("%d: SSL: masterKeyLen=%d cipherArgLen=%d",
   1.473 +		     myPid, from->u.ssl2.masterKey.len,
   1.474 +		     from->u.ssl2.cipherArg.len));
   1.475 +	    to->valid = 0;
   1.476 +	    return;
   1.477 +	}
   1.478 +
   1.479 +	to->u.ssl2.cipherType    = from->u.ssl2.cipherType;
   1.480 +	to->u.ssl2.masterKeyLen  = from->u.ssl2.masterKey.len;
   1.481 +	to->u.ssl2.cipherArgLen  = from->u.ssl2.cipherArg.len;
   1.482 +	to->u.ssl2.keyBits       = from->u.ssl2.keyBits;
   1.483 +	to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
   1.484 +	to->sessionIDLength      = SSL2_SESSIONID_BYTES;
   1.485 +	PORT_Memcpy(to->sessionID, from->u.ssl2.sessionID, SSL2_SESSIONID_BYTES);
   1.486 +	PORT_Memcpy(to->u.ssl2.masterKey, from->u.ssl2.masterKey.data,
   1.487 +		  from->u.ssl2.masterKey.len);
   1.488 +	PORT_Memcpy(to->u.ssl2.cipherArg, from->u.ssl2.cipherArg.data,
   1.489 +		  from->u.ssl2.cipherArg.len);
   1.490 +#ifdef DEBUG
   1.491 +	PORT_Memset(to->u.ssl2.masterKey+from->u.ssl2.masterKey.len, 0,
   1.492 +		  sizeof(to->u.ssl2.masterKey) - from->u.ssl2.masterKey.len);
   1.493 +	PORT_Memset(to->u.ssl2.cipherArg+from->u.ssl2.cipherArg.len, 0,
   1.494 +		  sizeof(to->u.ssl2.cipherArg) - from->u.ssl2.cipherArg.len);
   1.495 +#endif
   1.496 +	SSL_TRC(8, ("%d: SSL: ConvertSID: masterKeyLen=%d cipherArgLen=%d "
   1.497 +		    "time=%d addr=0x%08x%08x%08x%08x cipherType=%d", myPid,
   1.498 +		    to->u.ssl2.masterKeyLen, to->u.ssl2.cipherArgLen,
   1.499 +		    to->creationTime, to->addr.pr_s6_addr32[0],
   1.500 +		    to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
   1.501 +		    to->addr.pr_s6_addr32[3], to->u.ssl2.cipherType));
   1.502 +    } else {
   1.503 +	/* This is an SSL v3 session */
   1.504 +
   1.505 +	to->u.ssl3.cipherSuite      = from->u.ssl3.cipherSuite;
   1.506 +	to->u.ssl3.compression      = (PRUint16)from->u.ssl3.compression;
   1.507 +	to->u.ssl3.keys             = from->u.ssl3.keys;
   1.508 +	to->u.ssl3.masterWrapMech   = from->u.ssl3.masterWrapMech;
   1.509 +	to->u.ssl3.exchKeyType      = from->u.ssl3.exchKeyType;
   1.510 +	to->sessionIDLength         = from->u.ssl3.sessionIDLength;
   1.511 +	to->u.ssl3.certIndex        = -1;
   1.512 +	to->u.ssl3.srvNameIndex     = -1;
   1.513 +
   1.514 +	PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID,
   1.515 +		    to->sessionIDLength);
   1.516 +
   1.517 +	SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x "
   1.518 +	            "cipherSuite=%d",
   1.519 +		    myPid, to->creationTime, to->addr.pr_s6_addr32[0],
   1.520 +		    to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
   1.521 +		    to->addr.pr_s6_addr32[3], to->u.ssl3.cipherSuite));
   1.522 +    }
   1.523 +}
   1.524 +
   1.525 +/*
   1.526 +** Convert shared memory cache-entry to local memory based one
   1.527 +** This is only called from ServerSessionIDLookup().
   1.528 +*/
   1.529 +static sslSessionID *
   1.530 +ConvertToSID(sidCacheEntry *    from,
   1.531 +             certCacheEntry *   pcce,
   1.532 +             srvNameCacheEntry *psnce,
   1.533 +             CERTCertDBHandle * dbHandle)
   1.534 +{
   1.535 +    sslSessionID *to;
   1.536 +    PRUint16 version = from->version;
   1.537 +
   1.538 +    to = PORT_ZNew(sslSessionID);
   1.539 +    if (!to) {
   1.540 +	return 0;
   1.541 +    }
   1.542 +
   1.543 +    if (version < SSL_LIBRARY_VERSION_3_0) {
   1.544 +	/* This is an SSL v2 session */
   1.545 +	to->u.ssl2.masterKey.data =
   1.546 +	    (unsigned char*) PORT_Alloc(from->u.ssl2.masterKeyLen);
   1.547 +	if (!to->u.ssl2.masterKey.data) {
   1.548 +	    goto loser;
   1.549 +	}
   1.550 +	if (from->u.ssl2.cipherArgLen) {
   1.551 +	    to->u.ssl2.cipherArg.data = 
   1.552 +	    	(unsigned char*)PORT_Alloc(from->u.ssl2.cipherArgLen);
   1.553 +	    if (!to->u.ssl2.cipherArg.data) {
   1.554 +		goto loser;
   1.555 +	    }
   1.556 +	    PORT_Memcpy(to->u.ssl2.cipherArg.data, from->u.ssl2.cipherArg,
   1.557 +		        from->u.ssl2.cipherArgLen);
   1.558 +	}
   1.559 +
   1.560 +	to->u.ssl2.cipherType    = from->u.ssl2.cipherType;
   1.561 +	to->u.ssl2.masterKey.len = from->u.ssl2.masterKeyLen;
   1.562 +	to->u.ssl2.cipherArg.len = from->u.ssl2.cipherArgLen;
   1.563 +	to->u.ssl2.keyBits       = from->u.ssl2.keyBits;
   1.564 +	to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
   1.565 +/*	to->sessionIDLength      = SSL2_SESSIONID_BYTES; */
   1.566 +	PORT_Memcpy(to->u.ssl2.sessionID, from->sessionID, SSL2_SESSIONID_BYTES);
   1.567 +	PORT_Memcpy(to->u.ssl2.masterKey.data, from->u.ssl2.masterKey,
   1.568 +		    from->u.ssl2.masterKeyLen);
   1.569 +
   1.570 +	SSL_TRC(8, ("%d: SSL: ConvertToSID: masterKeyLen=%d cipherArgLen=%d "
   1.571 +		    "time=%d addr=0x%08x%08x%08x%08x cipherType=%d",
   1.572 +		    myPid, to->u.ssl2.masterKey.len,
   1.573 +		    to->u.ssl2.cipherArg.len, to->creationTime,
   1.574 +		    to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1],
   1.575 +		    to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3],
   1.576 +		    to->u.ssl2.cipherType));
   1.577 +    } else {
   1.578 +	/* This is an SSL v3 session */
   1.579 +
   1.580 +	to->u.ssl3.sessionIDLength  = from->sessionIDLength;
   1.581 +	to->u.ssl3.cipherSuite      = from->u.ssl3.cipherSuite;
   1.582 +	to->u.ssl3.compression      = (SSLCompressionMethod)from->u.ssl3.compression;
   1.583 +	to->u.ssl3.keys             = from->u.ssl3.keys;
   1.584 +	to->u.ssl3.masterWrapMech   = from->u.ssl3.masterWrapMech;
   1.585 +	to->u.ssl3.exchKeyType      = from->u.ssl3.exchKeyType;
   1.586 +	if (from->u.ssl3.srvNameIndex != -1 && psnce) {
   1.587 +            SECItem name;
   1.588 +            SECStatus rv;
   1.589 +            name.type                   = psnce->type;
   1.590 +            name.len                    = psnce->nameLen;
   1.591 +            name.data                   = psnce->name;
   1.592 +            rv = SECITEM_CopyItem(NULL, &to->u.ssl3.srvName, &name);
   1.593 +            if (rv != SECSuccess) {
   1.594 +                goto loser;
   1.595 +            }
   1.596 +        }
   1.597 +
   1.598 +	PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength);
   1.599 +
   1.600 +	/* the portions of the SID that are only restored on the client
   1.601 +	 * are set to invalid values on the server.
   1.602 +	 */
   1.603 +	to->u.ssl3.clientWriteKey   = NULL;
   1.604 +	to->u.ssl3.serverWriteKey   = NULL;
   1.605 +
   1.606 +	to->urlSvrName              = NULL;
   1.607 +
   1.608 +	to->u.ssl3.masterModuleID   = (SECMODModuleID)-1; /* invalid value */
   1.609 +	to->u.ssl3.masterSlotID     = (CK_SLOT_ID)-1;     /* invalid value */
   1.610 +	to->u.ssl3.masterWrapIndex  = 0;
   1.611 +	to->u.ssl3.masterWrapSeries = 0;
   1.612 +	to->u.ssl3.masterValid      = PR_FALSE;
   1.613 +
   1.614 +	to->u.ssl3.clAuthModuleID   = (SECMODModuleID)-1; /* invalid value */
   1.615 +	to->u.ssl3.clAuthSlotID     = (CK_SLOT_ID)-1;     /* invalid value */
   1.616 +	to->u.ssl3.clAuthSeries     = 0;
   1.617 +	to->u.ssl3.clAuthValid      = PR_FALSE;
   1.618 +
   1.619 +	if (from->u.ssl3.certIndex != -1 && pcce) {
   1.620 +	    SECItem          derCert;
   1.621 +
   1.622 +	    derCert.len  = pcce->certLength;
   1.623 +	    derCert.data = pcce->cert;
   1.624 +
   1.625 +	    to->peerCert = CERT_NewTempCertificate(dbHandle, &derCert, NULL,
   1.626 +					           PR_FALSE, PR_TRUE);
   1.627 +	    if (to->peerCert == NULL)
   1.628 +		goto loser;
   1.629 +	}
   1.630 +    }
   1.631 +
   1.632 +    to->version         = from->version;
   1.633 +    to->creationTime    = from->creationTime;
   1.634 +    to->lastAccessTime  = from->lastAccessTime;
   1.635 +    to->expirationTime  = from->expirationTime;
   1.636 +    to->cached          = in_server_cache;
   1.637 +    to->addr            = from->addr;
   1.638 +    to->references      = 1;
   1.639 +    to->authAlgorithm	= from->authAlgorithm;
   1.640 +    to->authKeyBits	= from->authKeyBits;
   1.641 +    to->keaType		= from->keaType;
   1.642 +    to->keaKeyBits	= from->keaKeyBits;
   1.643 +    
   1.644 +    return to;
   1.645 +
   1.646 +  loser:
   1.647 +    if (to) {
   1.648 +	if (version < SSL_LIBRARY_VERSION_3_0) {
   1.649 +	    if (to->u.ssl2.masterKey.data)
   1.650 +		PORT_Free(to->u.ssl2.masterKey.data);
   1.651 +	    if (to->u.ssl2.cipherArg.data)
   1.652 +		PORT_Free(to->u.ssl2.cipherArg.data);
   1.653 +	} else {
   1.654 +            SECITEM_FreeItem(&to->u.ssl3.srvName, PR_FALSE);
   1.655 +        }
   1.656 +	PORT_Free(to);
   1.657 +    }
   1.658 +    return NULL;
   1.659 +}
   1.660 +
   1.661 +
   1.662 +
   1.663 +/*
   1.664 +** Perform some mumbo jumbo on the ip-address and the session-id value to
   1.665 +** compute a hash value.
   1.666 +*/
   1.667 +static PRUint32 
   1.668 +SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl)
   1.669 +{
   1.670 +    PRUint32 rv;
   1.671 +    PRUint32 x[8];
   1.672 +
   1.673 +    memset(x, 0, sizeof x);
   1.674 +    if (nl > sizeof x)
   1.675 +    	nl = sizeof x;
   1.676 +    memcpy(x, s, nl);
   1.677 +
   1.678 +    rv = (addr->pr_s6_addr32[0] ^ addr->pr_s6_addr32[1] ^
   1.679 +	  addr->pr_s6_addr32[2] ^ addr->pr_s6_addr32[3] ^
   1.680 +          x[0] ^ x[1] ^ x[2] ^ x[3] ^ x[4] ^ x[5] ^ x[6] ^ x[7])
   1.681 +	  % cache->numSIDCacheSets;
   1.682 +    return rv;
   1.683 +}
   1.684 +
   1.685 +
   1.686 +
   1.687 +/*
   1.688 +** Look something up in the cache. This will invalidate old entries
   1.689 +** in the process. Caller has locked the cache set!
   1.690 +** Returns PR_TRUE if found a valid match.  PR_FALSE otherwise.
   1.691 +*/
   1.692 +static sidCacheEntry *
   1.693 +FindSID(cacheDesc *cache, PRUint32 setNum, PRUint32 now,
   1.694 +        const PRIPv6Addr *addr, unsigned char *sessionID,
   1.695 +	unsigned sessionIDLength)
   1.696 +{
   1.697 +    PRUint32      ndx   = cache->sidCacheSets[setNum].next;
   1.698 +    int           i;
   1.699 +
   1.700 +    sidCacheEntry * set = cache->sidCacheData + 
   1.701 +    			 (setNum * SID_CACHE_ENTRIES_PER_SET);
   1.702 +
   1.703 +    for (i = SID_CACHE_ENTRIES_PER_SET; i > 0; --i) {
   1.704 +	sidCacheEntry * sce;
   1.705 +
   1.706 +	ndx  = (ndx - 1) % SID_CACHE_ENTRIES_PER_SET;
   1.707 +	sce = set + ndx;
   1.708 +
   1.709 +	if (!sce->valid)
   1.710 +	    continue;
   1.711 +
   1.712 +	if (now > sce->expirationTime) {
   1.713 +	    /* SessionID has timed out. Invalidate the entry. */
   1.714 +	    SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x "
   1.715 +			"time+=%x",
   1.716 +			myPid, sce->addr.pr_s6_addr32[0],
   1.717 +			sce->addr.pr_s6_addr32[1], sce->addr.pr_s6_addr32[2],
   1.718 +			sce->addr.pr_s6_addr32[3], now,
   1.719 +			sce->expirationTime ));
   1.720 +	    sce->valid = 0;
   1.721 +	    continue;
   1.722 +	}
   1.723 +
   1.724 +	/*
   1.725 +	** Next, examine specific session-id/addr data to see if the cache
   1.726 +	** entry matches our addr+session-id value
   1.727 +	*/
   1.728 +	if (sessionIDLength == sce->sessionIDLength      &&
   1.729 +	    !memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) &&
   1.730 +	    !memcmp(sce->sessionID, sessionID, sessionIDLength)) {
   1.731 +	    /* Found it */
   1.732 +	    return sce;
   1.733 +	}
   1.734 +    }
   1.735 +
   1.736 +    PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
   1.737 +    return NULL;
   1.738 +}
   1.739 +
   1.740 +/************************************************************************/
   1.741 +
   1.742 +/* This is the primary function for finding entries in the server's sid cache.
   1.743 + * Although it is static, this function is called via the global function 
   1.744 + * pointer ssl_sid_lookup.
   1.745 + */
   1.746 +static sslSessionID *
   1.747 +ServerSessionIDLookup(const PRIPv6Addr *addr,
   1.748 +			unsigned char *sessionID,
   1.749 +			unsigned int   sessionIDLength,
   1.750 +                        CERTCertDBHandle * dbHandle)
   1.751 +{
   1.752 +    sslSessionID *  sid      = 0;
   1.753 +    sidCacheEntry * psce;
   1.754 +    certCacheEntry *pcce     = 0;
   1.755 +    srvNameCacheEntry *psnce = 0;
   1.756 +    cacheDesc *     cache    = &globalCache;
   1.757 +    PRUint32        now;
   1.758 +    PRUint32        set;
   1.759 +    PRInt32         cndx;
   1.760 +    sidCacheEntry   sce;
   1.761 +    certCacheEntry  cce;
   1.762 +    srvNameCacheEntry snce;
   1.763 +
   1.764 +    set = SIDindex(cache, addr, sessionID, sessionIDLength);
   1.765 +    now = LockSet(cache, set, 0);
   1.766 +    if (!now)
   1.767 +    	return NULL;
   1.768 +
   1.769 +    psce = FindSID(cache, set, now, addr, sessionID, sessionIDLength);
   1.770 +    if (psce) {
   1.771 +	if (psce->version >= SSL_LIBRARY_VERSION_3_0) {
   1.772 +	    if ((cndx = psce->u.ssl3.certIndex) != -1) {
   1.773 +                
   1.774 +                PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now);
   1.775 +                if (gotLock) {
   1.776 +                    pcce = &cache->certCacheData[cndx];
   1.777 +                    
   1.778 +                    /* See if the cert's session ID matches the sce cache. */
   1.779 +                    if ((pcce->sessionIDLength == psce->sessionIDLength) &&
   1.780 +                        !PORT_Memcmp(pcce->sessionID, psce->sessionID, 
   1.781 +                                     pcce->sessionIDLength)) {
   1.782 +                        cce = *pcce;
   1.783 +                    } else {
   1.784 +                        /* The cert doesen't match the SID cache entry, 
   1.785 +                        ** so invalidate the SID cache entry. 
   1.786 +                        */
   1.787 +                        psce->valid = 0;
   1.788 +                        psce = 0;
   1.789 +                        pcce = 0;
   1.790 +                    }
   1.791 +                    UnlockSidCacheLock(cache->certCacheLock);
   1.792 +                } else {
   1.793 +                    /* what the ??.  Didn't get the cert cache lock.
   1.794 +                    ** Don't invalidate the SID cache entry, but don't find it.
   1.795 +                    */
   1.796 +                    PORT_Assert(!("Didn't get cert Cache Lock!"));
   1.797 +                    psce = 0;
   1.798 +                    pcce = 0;
   1.799 +                }
   1.800 +            }
   1.801 +            if (psce && ((cndx = psce->u.ssl3.srvNameIndex) != -1)) {
   1.802 +                PRUint32 gotLock = LockSidCacheLock(cache->srvNameCacheLock,
   1.803 +                                                    now);
   1.804 +                if (gotLock) {
   1.805 +                    psnce = &cache->srvNameCacheData[cndx];
   1.806 +                    
   1.807 +                    if (!PORT_Memcmp(psnce->nameHash, psce->u.ssl3.srvNameHash, 
   1.808 +                                     SHA256_LENGTH)) {
   1.809 +                        snce = *psnce;
   1.810 +                    } else {
   1.811 +                        /* The name doesen't match the SID cache entry, 
   1.812 +                        ** so invalidate the SID cache entry. 
   1.813 +                        */
   1.814 +                        psce->valid = 0;
   1.815 +                        psce = 0;
   1.816 +                        psnce = 0;
   1.817 +                    }
   1.818 +                    UnlockSidCacheLock(cache->srvNameCacheLock);
   1.819 +                } else {
   1.820 +                    /* what the ??.  Didn't get the cert cache lock.
   1.821 +                    ** Don't invalidate the SID cache entry, but don't find it.
   1.822 +                    */
   1.823 +                    PORT_Assert(!("Didn't get name Cache Lock!"));
   1.824 +                    psce = 0;
   1.825 +                    psnce = 0;
   1.826 +                }
   1.827 +                
   1.828 +            }
   1.829 +        }
   1.830 +	if (psce) {
   1.831 +	    psce->lastAccessTime = now;
   1.832 +	    sce = *psce;	/* grab a copy while holding the lock */
   1.833 +    	}
   1.834 +    }
   1.835 +    UnlockSet(cache, set);
   1.836 +    if (psce) {
   1.837 +	/* sce conains a copy of the cache entry.
   1.838 +	** Convert shared memory format to local format 
   1.839 +	*/
   1.840 +	sid = ConvertToSID(&sce, pcce ? &cce : 0, psnce ? &snce : 0, dbHandle);
   1.841 +    }
   1.842 +    return sid;
   1.843 +}
   1.844 +
   1.845 +/*
   1.846 +** Place a sid into the cache, if it isn't already there. 
   1.847 +*/
   1.848 +static void 
   1.849 +ServerSessionIDCache(sslSessionID *sid)
   1.850 +{
   1.851 +    sidCacheEntry sce;
   1.852 +    PRUint32      now     = 0;
   1.853 +    PRUint16      version = sid->version;
   1.854 +    cacheDesc *   cache   = &globalCache;
   1.855 +
   1.856 +    if ((version >= SSL_LIBRARY_VERSION_3_0) &&
   1.857 +	(sid->u.ssl3.sessionIDLength == 0)) {
   1.858 +	return;
   1.859 +    }
   1.860 +
   1.861 +    if (sid->cached == never_cached || sid->cached == invalid_cache) {
   1.862 +	PRUint32 set;
   1.863 +
   1.864 +	PORT_Assert(sid->creationTime != 0);
   1.865 +	if (!sid->creationTime)
   1.866 +	    sid->lastAccessTime = sid->creationTime = ssl_Time();
   1.867 +	if (version < SSL_LIBRARY_VERSION_3_0) {
   1.868 +	    /* override caller's expiration time, which uses client timeout
   1.869 +	     * duration, not server timeout duration.
   1.870 +	     */
   1.871 +	    sid->expirationTime = sid->creationTime + cache->ssl2Timeout;
   1.872 +	    SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
   1.873 +			"cipher=%d", myPid, sid->cached,
   1.874 +			sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
   1.875 +			sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
   1.876 +			sid->creationTime, sid->u.ssl2.cipherType));
   1.877 +	    PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID,
   1.878 +			  SSL2_SESSIONID_BYTES));
   1.879 +	    PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
   1.880 +			  sid->u.ssl2.masterKey.len));
   1.881 +	    PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
   1.882 +			  sid->u.ssl2.cipherArg.len));
   1.883 +
   1.884 +	} else {
   1.885 +	    /* override caller's expiration time, which uses client timeout
   1.886 +	     * duration, not server timeout duration.
   1.887 +	     */
   1.888 +	    sid->expirationTime = sid->creationTime + cache->ssl3Timeout;
   1.889 +	    SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
   1.890 +			"cipherSuite=%d", myPid, sid->cached,
   1.891 +			sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
   1.892 +			sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
   1.893 +			sid->creationTime, sid->u.ssl3.cipherSuite));
   1.894 +	    PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID,
   1.895 +			  sid->u.ssl3.sessionIDLength));
   1.896 +	}
   1.897 +
   1.898 +	ConvertFromSID(&sce, sid);
   1.899 +
   1.900 +	if (version >= SSL_LIBRARY_VERSION_3_0) {
   1.901 +            SECItem *name = &sid->u.ssl3.srvName;
   1.902 +            if (name->len && name->data) {
   1.903 +                now = CacheSrvName(cache, name, &sce);
   1.904 +            }
   1.905 +            if (sid->peerCert != NULL) {
   1.906 +                now = CacheCert(cache, sid->peerCert, &sce);
   1.907 +            }
   1.908 +	}
   1.909 +
   1.910 +	set = SIDindex(cache, &sce.addr, sce.sessionID, sce.sessionIDLength);
   1.911 +	now = LockSet(cache, set, now);
   1.912 +	if (now) {
   1.913 +	    PRUint32  next = cache->sidCacheSets[set].next;
   1.914 +	    PRUint32  ndx  = set * SID_CACHE_ENTRIES_PER_SET + next;
   1.915 +
   1.916 +	    /* Write out new cache entry */
   1.917 +	    cache->sidCacheData[ndx] = sce;
   1.918 +
   1.919 +	    cache->sidCacheSets[set].next = 
   1.920 +	    				(next + 1) % SID_CACHE_ENTRIES_PER_SET;
   1.921 +
   1.922 +	    UnlockSet(cache, set);
   1.923 +	    sid->cached = in_server_cache;
   1.924 +	}
   1.925 +    }
   1.926 +}
   1.927 +
   1.928 +/*
   1.929 +** Although this is static, it is called from ssl via global function pointer
   1.930 +**	ssl_sid_uncache.  This invalidates the referenced cache entry.
   1.931 +*/
   1.932 +static void 
   1.933 +ServerSessionIDUncache(sslSessionID *sid)
   1.934 +{
   1.935 +    cacheDesc *    cache   = &globalCache;
   1.936 +    PRUint8 *      sessionID;
   1.937 +    unsigned int   sessionIDLength;
   1.938 +    PRErrorCode    err;
   1.939 +    PRUint32       set;
   1.940 +    PRUint32       now;
   1.941 +    sidCacheEntry *psce;
   1.942 +
   1.943 +    if (sid == NULL) 
   1.944 +    	return;
   1.945 +    
   1.946 +    /* Uncaching a SID should never change the error code. 
   1.947 +    ** So save it here and restore it before exiting.
   1.948 +    */
   1.949 +    err = PR_GetError();
   1.950 +
   1.951 +    if (sid->version < SSL_LIBRARY_VERSION_3_0) {
   1.952 +	sessionID       = sid->u.ssl2.sessionID;
   1.953 +	sessionIDLength = SSL2_SESSIONID_BYTES;
   1.954 +	SSL_TRC(8, ("%d: SSL: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
   1.955 +		    "cipher=%d", myPid, sid->cached,
   1.956 +		    sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
   1.957 +		    sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
   1.958 +		    sid->creationTime, sid->u.ssl2.cipherType));
   1.959 +	PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
   1.960 +	PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
   1.961 +		      sid->u.ssl2.masterKey.len));
   1.962 +	PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
   1.963 +		      sid->u.ssl2.cipherArg.len));
   1.964 +    } else {
   1.965 +	sessionID       = sid->u.ssl3.sessionID;
   1.966 +	sessionIDLength = sid->u.ssl3.sessionIDLength;
   1.967 +	SSL_TRC(8, ("%d: SSL3: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
   1.968 +		    "cipherSuite=%d", myPid, sid->cached,
   1.969 +		    sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
   1.970 +		    sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
   1.971 +		    sid->creationTime, sid->u.ssl3.cipherSuite));
   1.972 +	PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
   1.973 +    }
   1.974 +    set = SIDindex(cache, &sid->addr, sessionID, sessionIDLength);
   1.975 +    now = LockSet(cache, set, 0);
   1.976 +    if (now) {
   1.977 +	psce = FindSID(cache, set, now, &sid->addr, sessionID, sessionIDLength);
   1.978 +	if (psce) {
   1.979 +	    psce->valid = 0;
   1.980 +	}
   1.981 +	UnlockSet(cache, set);
   1.982 +    }
   1.983 +    sid->cached = invalid_cache;
   1.984 +    PORT_SetError(err);
   1.985 +}
   1.986 +
   1.987 +#ifdef XP_OS2
   1.988 +
   1.989 +#define INCL_DOSPROCESS
   1.990 +#include <os2.h>
   1.991 +
   1.992 +long gettid(void)
   1.993 +{
   1.994 +    PTIB ptib;
   1.995 +    PPIB ppib;
   1.996 +    DosGetInfoBlocks(&ptib, &ppib);
   1.997 +    return ((long)ptib->tib_ordinal); /* thread id */
   1.998 +}
   1.999 +#endif
  1.1000 +
  1.1001 +static void
  1.1002 +CloseCache(cacheDesc *cache)
  1.1003 +{
  1.1004 +    int locks_initialized = cache->numSIDCacheLocksInitialized;
  1.1005 +
  1.1006 +    if (cache->cacheMem) {
  1.1007 +	if (cache->sharedCache) {
  1.1008 +	    sidCacheLock *pLock = cache->sidCacheLocks;
  1.1009 +	    for (; locks_initialized > 0; --locks_initialized, ++pLock ) {
  1.1010 +		/* If everInherited is true, this shared cache was (and may
  1.1011 +		** still be) in use by multiple processes.  We do not wish to
  1.1012 +		** destroy the mutexes while they are still in use, but we do
  1.1013 +		** want to free mutex resources associated with this process.
  1.1014 +		*/
  1.1015 +		sslMutex_Destroy(&pLock->mutex,
  1.1016 +				 cache->sharedCache->everInherited);
  1.1017 +	    }
  1.1018 +	}
  1.1019 +	if (cache->shared) {
  1.1020 +	    PR_MemUnmap(cache->cacheMem, cache->cacheMemSize);
  1.1021 +	} else {
  1.1022 +	    PORT_Free(cache->cacheMem);
  1.1023 +	}
  1.1024 +	cache->cacheMem = NULL;
  1.1025 +    }
  1.1026 +    if (cache->cacheMemMap) {
  1.1027 +	PR_CloseFileMap(cache->cacheMemMap);
  1.1028 +	cache->cacheMemMap = NULL;
  1.1029 +    }
  1.1030 +    memset(cache, 0, sizeof *cache);
  1.1031 +}
  1.1032 +
  1.1033 +static SECStatus
  1.1034 +InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries,
  1.1035 +          int maxSrvNameCacheEntries, PRUint32 ssl2_timeout, 
  1.1036 +          PRUint32 ssl3_timeout, const char *directory, PRBool shared)
  1.1037 +{
  1.1038 +    ptrdiff_t     ptr;
  1.1039 +    sidCacheLock *pLock;
  1.1040 +    char *        cacheMem;
  1.1041 +    PRFileMap *   cacheMemMap;
  1.1042 +    char *        cfn = NULL;	/* cache file name */
  1.1043 +    int           locks_initialized = 0;
  1.1044 +    int           locks_to_initialize = 0;
  1.1045 +    PRUint32      init_time;
  1.1046 +
  1.1047 +    if ( (!cache) || (maxCacheEntries < 0) || (!directory) ) {
  1.1048 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1049 +        return SECFailure;
  1.1050 +    }
  1.1051 +
  1.1052 +    if (cache->cacheMem) {
  1.1053 +	/* Already done */
  1.1054 +	return SECSuccess;
  1.1055 +    }
  1.1056 +
  1.1057 +    /* make sure loser can clean up properly */
  1.1058 +    cache->shared = shared;
  1.1059 +    cache->cacheMem    = cacheMem    = NULL;
  1.1060 +    cache->cacheMemMap = cacheMemMap = NULL;
  1.1061 +    cache->sharedCache = (cacheDesc *)0;
  1.1062 +
  1.1063 +    cache->numSIDCacheLocksInitialized = 0;
  1.1064 +    cache->nextCertCacheEntry = 0;
  1.1065 +    cache->stopPolling = PR_FALSE;
  1.1066 +    cache->everInherited = PR_FALSE;
  1.1067 +    cache->poller = NULL;
  1.1068 +    cache->mutexTimeout = 0;
  1.1069 +
  1.1070 +    cache->numSIDCacheEntries = maxCacheEntries ? maxCacheEntries 
  1.1071 +                                                : DEF_SID_CACHE_ENTRIES;
  1.1072 +    cache->numSIDCacheSets    = 
  1.1073 +    	SID_HOWMANY(cache->numSIDCacheEntries, SID_CACHE_ENTRIES_PER_SET);
  1.1074 +
  1.1075 +    cache->numSIDCacheEntries = 
  1.1076 +    	cache->numSIDCacheSets * SID_CACHE_ENTRIES_PER_SET;
  1.1077 +
  1.1078 +    cache->numSIDCacheLocks   = 
  1.1079 +    	PR_MIN(cache->numSIDCacheSets, ssl_max_sid_cache_locks);
  1.1080 +
  1.1081 +    cache->numSIDCacheSetsPerLock = 
  1.1082 +    	SID_HOWMANY(cache->numSIDCacheSets, cache->numSIDCacheLocks);
  1.1083 +
  1.1084 +    cache->numCertCacheEntries = (maxCertCacheEntries > 0) ?
  1.1085 +                                             maxCertCacheEntries : 0;
  1.1086 +    cache->numSrvNameCacheEntries = (maxSrvNameCacheEntries >= 0) ?
  1.1087 +                                             maxSrvNameCacheEntries : DEF_NAME_CACHE_ENTRIES;
  1.1088 +
  1.1089 +    /* compute size of shared memory, and offsets of all pointers */
  1.1090 +    ptr = 0;
  1.1091 +    cache->cacheMem     = (char *)ptr;
  1.1092 +    ptr += SID_ROUNDUP(sizeof(cacheDesc), SID_ALIGNMENT);
  1.1093 +
  1.1094 +    cache->sidCacheLocks = (sidCacheLock *)ptr;
  1.1095 +    cache->keyCacheLock  = cache->sidCacheLocks + cache->numSIDCacheLocks;
  1.1096 +    cache->certCacheLock = cache->keyCacheLock  + 1;
  1.1097 +    cache->srvNameCacheLock = cache->certCacheLock  + 1;
  1.1098 +    ptr = (ptrdiff_t)(cache->srvNameCacheLock + 1);
  1.1099 +    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
  1.1100 +
  1.1101 +    cache->sidCacheSets  = (sidCacheSet *)ptr;
  1.1102 +    ptr = (ptrdiff_t)(cache->sidCacheSets + cache->numSIDCacheSets);
  1.1103 +    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
  1.1104 +
  1.1105 +    cache->sidCacheData  = (sidCacheEntry *)ptr;
  1.1106 +    ptr = (ptrdiff_t)(cache->sidCacheData + cache->numSIDCacheEntries);
  1.1107 +    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
  1.1108 +
  1.1109 +    cache->certCacheData = (certCacheEntry *)ptr;
  1.1110 +    cache->sidCacheSize  = 
  1.1111 +    	(char *)cache->certCacheData - (char *)cache->sidCacheData;
  1.1112 +
  1.1113 +    if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) {
  1.1114 +        /* This is really a poor way to computer this! */
  1.1115 +        cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry);
  1.1116 +        if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES)
  1.1117 +    	cache->numCertCacheEntries = MIN_CERT_CACHE_ENTRIES;
  1.1118 +    }
  1.1119 +    ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries);
  1.1120 +    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
  1.1121 +
  1.1122 +    cache->keyCacheData  = (SSLWrappedSymWrappingKey *)ptr;
  1.1123 +    cache->certCacheSize = 
  1.1124 +    	(char *)cache->keyCacheData - (char *)cache->certCacheData;
  1.1125 +
  1.1126 +    cache->numKeyCacheEntries = kt_kea_size * SSL_NUM_WRAP_MECHS;
  1.1127 +    ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries);
  1.1128 +    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
  1.1129 +
  1.1130 +    cache->keyCacheSize  = (char *)ptr - (char *)cache->keyCacheData;
  1.1131 +
  1.1132 +    cache->ticketKeyNameSuffix = (PRUint8 *)ptr;
  1.1133 +    ptr = (ptrdiff_t)(cache->ticketKeyNameSuffix +
  1.1134 +	SESS_TICKET_KEY_VAR_NAME_LEN);
  1.1135 +    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
  1.1136 +
  1.1137 +    cache->ticketEncKey = (encKeyCacheEntry *)ptr;
  1.1138 +    ptr = (ptrdiff_t)(cache->ticketEncKey + 1);
  1.1139 +    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
  1.1140 +
  1.1141 +    cache->ticketMacKey = (encKeyCacheEntry *)ptr;
  1.1142 +    ptr = (ptrdiff_t)(cache->ticketMacKey + 1);
  1.1143 +    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
  1.1144 +
  1.1145 +    cache->ticketKeysValid = (PRUint32 *)ptr;
  1.1146 +    ptr = (ptrdiff_t)(cache->ticketKeysValid + 1);
  1.1147 +    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
  1.1148 +
  1.1149 +    cache->srvNameCacheData = (srvNameCacheEntry *)ptr;
  1.1150 +    cache->srvNameCacheSize =
  1.1151 +        cache->numSrvNameCacheEntries * sizeof(srvNameCacheEntry);
  1.1152 +    ptr = (ptrdiff_t)(cache->srvNameCacheData + cache->numSrvNameCacheEntries);
  1.1153 +    ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
  1.1154 +
  1.1155 +    cache->cacheMemSize = ptr;
  1.1156 +
  1.1157 +    if (ssl2_timeout) {   
  1.1158 +	if (ssl2_timeout > MAX_SSL2_TIMEOUT) {
  1.1159 +	    ssl2_timeout = MAX_SSL2_TIMEOUT;
  1.1160 +	}
  1.1161 +	if (ssl2_timeout < MIN_SSL2_TIMEOUT) {
  1.1162 +	    ssl2_timeout = MIN_SSL2_TIMEOUT;
  1.1163 +	}
  1.1164 +	cache->ssl2Timeout = ssl2_timeout;
  1.1165 +    } else {
  1.1166 +	cache->ssl2Timeout = DEF_SSL2_TIMEOUT;
  1.1167 +    }
  1.1168 +
  1.1169 +    if (ssl3_timeout) {   
  1.1170 +	if (ssl3_timeout > MAX_SSL3_TIMEOUT) {
  1.1171 +	    ssl3_timeout = MAX_SSL3_TIMEOUT;
  1.1172 +	}
  1.1173 +	if (ssl3_timeout < MIN_SSL3_TIMEOUT) {
  1.1174 +	    ssl3_timeout = MIN_SSL3_TIMEOUT;
  1.1175 +	}
  1.1176 +	cache->ssl3Timeout = ssl3_timeout;
  1.1177 +    } else {
  1.1178 +	cache->ssl3Timeout = DEF_SSL3_TIMEOUT;
  1.1179 +    }
  1.1180 +
  1.1181 +    if (shared) {
  1.1182 +	/* Create file names */
  1.1183 +#if defined(XP_UNIX) || defined(XP_BEOS)
  1.1184 +	/* there's some confusion here about whether PR_OpenAnonFileMap wants
  1.1185 +	** a directory name or a file name for its first argument.
  1.1186 +	cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid);
  1.1187 +	*/
  1.1188 +	cfn = PR_smprintf("%s", directory);
  1.1189 +#elif defined(XP_WIN32)
  1.1190 +	cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, 
  1.1191 +			    GetCurrentThreadId());
  1.1192 +#elif defined(XP_OS2)
  1.1193 +	cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, 
  1.1194 +			    gettid());
  1.1195 +#else
  1.1196 +#error "Don't know how to create file name for this platform!"
  1.1197 +#endif
  1.1198 +	if (!cfn) {
  1.1199 +	    goto loser;
  1.1200 +	}
  1.1201 +
  1.1202 +	/* Create cache */
  1.1203 +	cacheMemMap = PR_OpenAnonFileMap(cfn, cache->cacheMemSize, 
  1.1204 +					 PR_PROT_READWRITE);
  1.1205 +
  1.1206 +	PR_smprintf_free(cfn);
  1.1207 +	if(!cacheMemMap) {
  1.1208 +	    goto loser;
  1.1209 +	}
  1.1210 +
  1.1211 +        cacheMem = PR_MemMap(cacheMemMap, 0, cache->cacheMemSize);
  1.1212 +    } else {
  1.1213 +        cacheMem = PORT_Alloc(cache->cacheMemSize);
  1.1214 +    }
  1.1215 +    
  1.1216 +    if (! cacheMem) {
  1.1217 +        goto loser;
  1.1218 +    }
  1.1219 +
  1.1220 +    /* Initialize shared memory. This may not be necessary on all platforms */
  1.1221 +    memset(cacheMem, 0, cache->cacheMemSize);
  1.1222 +
  1.1223 +    /* Copy cache descriptor header into shared memory */
  1.1224 +    memcpy(cacheMem, cache, sizeof *cache);
  1.1225 +
  1.1226 +    /* save private copies of these values */
  1.1227 +    cache->cacheMemMap = cacheMemMap;
  1.1228 +    cache->cacheMem    = cacheMem;
  1.1229 +    cache->sharedCache = (cacheDesc *)cacheMem;
  1.1230 +
  1.1231 +    /* Fix pointers in our private copy of cache descriptor to point to 
  1.1232 +    ** spaces in shared memory 
  1.1233 +    */
  1.1234 +    ptr = (ptrdiff_t)cache->cacheMem;
  1.1235 +    *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
  1.1236 +    *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
  1.1237 +    *(ptrdiff_t *)(&cache->certCacheLock) += ptr;
  1.1238 +    *(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr;
  1.1239 +    *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
  1.1240 +    *(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
  1.1241 +    *(ptrdiff_t *)(&cache->certCacheData) += ptr;
  1.1242 +    *(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
  1.1243 +    *(ptrdiff_t *)(&cache->ticketKeyNameSuffix) += ptr;
  1.1244 +    *(ptrdiff_t *)(&cache->ticketEncKey ) += ptr;
  1.1245 +    *(ptrdiff_t *)(&cache->ticketMacKey ) += ptr;
  1.1246 +    *(ptrdiff_t *)(&cache->ticketKeysValid) += ptr;
  1.1247 +    *(ptrdiff_t *)(&cache->srvNameCacheData) += ptr;
  1.1248 +
  1.1249 +    /* initialize the locks */
  1.1250 +    init_time = ssl_Time();
  1.1251 +    pLock = cache->sidCacheLocks;
  1.1252 +    for (locks_to_initialize = cache->numSIDCacheLocks + 3;
  1.1253 +         locks_initialized < locks_to_initialize; 
  1.1254 +	 ++locks_initialized, ++pLock ) {
  1.1255 +
  1.1256 +	SECStatus err = sslMutex_Init(&pLock->mutex, shared);
  1.1257 +	if (err) {
  1.1258 +	    cache->numSIDCacheLocksInitialized = locks_initialized;
  1.1259 +	    goto loser;
  1.1260 +	}
  1.1261 +        pLock->timeStamp = init_time;
  1.1262 +	pLock->pid       = 0;
  1.1263 +    }
  1.1264 +    cache->numSIDCacheLocksInitialized = locks_initialized;
  1.1265 +
  1.1266 +    return SECSuccess;
  1.1267 +
  1.1268 +loser:
  1.1269 +    CloseCache(cache);
  1.1270 +    return SECFailure;
  1.1271 +}
  1.1272 +
  1.1273 +PRUint32
  1.1274 +SSL_GetMaxServerCacheLocks(void)
  1.1275 +{
  1.1276 +    return ssl_max_sid_cache_locks + 2;
  1.1277 +    /* The extra two are the cert cache lock and the key cache lock. */
  1.1278 +}
  1.1279 +
  1.1280 +SECStatus
  1.1281 +SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
  1.1282 +{
  1.1283 +    /* Minimum is 1 sid cache lock, 1 cert cache lock and 1 key cache lock.
  1.1284 +    ** We'd like to test for a maximum value, but not all platforms' header
  1.1285 +    ** files provide a symbol or function or other means of determining
  1.1286 +    ** the maximum, other than trial and error.
  1.1287 +    */
  1.1288 +    if (maxLocks < 3) {
  1.1289 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1290 +	return SECFailure;
  1.1291 +    }
  1.1292 +    ssl_max_sid_cache_locks = maxLocks - 2;
  1.1293 +    /* The extra two are the cert cache lock and the key cache lock. */
  1.1294 +    return SECSuccess;
  1.1295 +}
  1.1296 +
  1.1297 +static SECStatus
  1.1298 +ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache,
  1.1299 +                                              PRUint32 ssl2_timeout,
  1.1300 +                                              PRUint32 ssl3_timeout, 
  1.1301 +                                              const char *   directory,
  1.1302 +                                              PRBool shared,
  1.1303 +                                              int      maxCacheEntries, 
  1.1304 +                                              int      maxCertCacheEntries,
  1.1305 +                                              int      maxSrvNameCacheEntries)
  1.1306 +{
  1.1307 +    SECStatus rv;
  1.1308 +
  1.1309 +    PORT_Assert(sizeof(sidCacheEntry) == 192);
  1.1310 +    PORT_Assert(sizeof(certCacheEntry) == 4096);
  1.1311 +    PORT_Assert(sizeof(srvNameCacheEntry) == 1072);
  1.1312 +
  1.1313 +    rv = ssl_Init();
  1.1314 +    if (rv != SECSuccess) {
  1.1315 +	return rv;
  1.1316 +    }
  1.1317 +
  1.1318 +    myPid = SSL_GETPID();
  1.1319 +    if (!directory) {
  1.1320 +	directory = DEFAULT_CACHE_DIRECTORY;
  1.1321 +    }
  1.1322 +    rv = InitCache(cache, maxCacheEntries, maxCertCacheEntries,
  1.1323 +                   maxSrvNameCacheEntries, ssl2_timeout, ssl3_timeout, 
  1.1324 +                   directory, shared);
  1.1325 +    if (rv) {
  1.1326 +	SET_ERROR_CODE
  1.1327 +    	return SECFailure;
  1.1328 +    }
  1.1329 +
  1.1330 +    ssl_sid_lookup  = ServerSessionIDLookup;
  1.1331 +    ssl_sid_cache   = ServerSessionIDCache;
  1.1332 +    ssl_sid_uncache = ServerSessionIDUncache;
  1.1333 +    return SECSuccess;
  1.1334 +}
  1.1335 +
  1.1336 +SECStatus
  1.1337 +SSL_ConfigServerSessionIDCacheInstance(	cacheDesc *cache,
  1.1338 +                                int      maxCacheEntries, 
  1.1339 +                                PRUint32 ssl2_timeout,
  1.1340 +                                PRUint32 ssl3_timeout, 
  1.1341 +                                const char *   directory, PRBool shared)
  1.1342 +{
  1.1343 +    return ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
  1.1344 +                                                         ssl2_timeout,
  1.1345 +                                                         ssl3_timeout,
  1.1346 +                                                         directory,
  1.1347 +                                                         shared,
  1.1348 +                                                         maxCacheEntries, 
  1.1349 +                                                         -1, -1);
  1.1350 +}
  1.1351 +
  1.1352 +SECStatus
  1.1353 +SSL_ConfigServerSessionIDCache(	int      maxCacheEntries, 
  1.1354 +				PRUint32 ssl2_timeout,
  1.1355 +			       	PRUint32 ssl3_timeout, 
  1.1356 +			  const char *   directory)
  1.1357 +{
  1.1358 +    ssl_InitSessionCacheLocks(PR_FALSE);
  1.1359 +    return SSL_ConfigServerSessionIDCacheInstance(&globalCache, 
  1.1360 +    		maxCacheEntries, ssl2_timeout, ssl3_timeout, directory, PR_FALSE);
  1.1361 +}
  1.1362 +
  1.1363 +SECStatus
  1.1364 +SSL_ShutdownServerSessionIDCacheInstance(cacheDesc *cache)
  1.1365 +{
  1.1366 +    CloseCache(cache);
  1.1367 +    return SECSuccess;
  1.1368 +}
  1.1369 +
  1.1370 +SECStatus
  1.1371 +SSL_ShutdownServerSessionIDCache(void)
  1.1372 +{
  1.1373 +#if defined(XP_UNIX) || defined(XP_BEOS)
  1.1374 +    /* Stop the thread that polls cache for expired locks on Unix */
  1.1375 +    StopLockPoller(&globalCache);
  1.1376 +#endif
  1.1377 +    SSL3_ShutdownServerCache();
  1.1378 +    return SSL_ShutdownServerSessionIDCacheInstance(&globalCache);
  1.1379 +}
  1.1380 +
  1.1381 +/* Use this function, instead of SSL_ConfigServerSessionIDCache,
  1.1382 + * if the cache will be shared by multiple processes.
  1.1383 + */
  1.1384 +static SECStatus
  1.1385 +ssl_ConfigMPServerSIDCacheWithOpt(      PRUint32 ssl2_timeout,
  1.1386 +                                        PRUint32 ssl3_timeout, 
  1.1387 +                                        const char *   directory,
  1.1388 +                                        int maxCacheEntries,
  1.1389 +                                        int maxCertCacheEntries,
  1.1390 +                                        int maxSrvNameCacheEntries)
  1.1391 +{
  1.1392 +    char *	envValue;
  1.1393 +    char *	inhValue;
  1.1394 +    cacheDesc * cache         = &globalCache;
  1.1395 +    PRUint32    fmStrLen;
  1.1396 +    SECStatus 	result;
  1.1397 +    PRStatus 	prStatus;
  1.1398 +    SECStatus	putEnvFailed;
  1.1399 +    inheritance inherit;
  1.1400 +    char        fmString[PR_FILEMAP_STRING_BUFSIZE];
  1.1401 +
  1.1402 +    isMultiProcess = PR_TRUE;
  1.1403 +    result = ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
  1.1404 +                  ssl2_timeout, ssl3_timeout, directory, PR_TRUE,
  1.1405 +        maxCacheEntries, maxCacheEntries, maxSrvNameCacheEntries);
  1.1406 +    if (result != SECSuccess) 
  1.1407 +        return result;
  1.1408 +
  1.1409 +    prStatus = PR_ExportFileMapAsString(cache->cacheMemMap, 
  1.1410 +                                        sizeof fmString, fmString);
  1.1411 +    if ((prStatus != PR_SUCCESS) || !(fmStrLen = strlen(fmString))) {
  1.1412 +	SET_ERROR_CODE
  1.1413 +	return SECFailure;
  1.1414 +    }
  1.1415 +
  1.1416 +    inherit.cacheMemSize	= cache->cacheMemSize;
  1.1417 +    inherit.fmStrLen            = fmStrLen;
  1.1418 +
  1.1419 +    inhValue = BTOA_DataToAscii((unsigned char *)&inherit, sizeof inherit);
  1.1420 +    if (!inhValue || !strlen(inhValue)) {
  1.1421 +	SET_ERROR_CODE
  1.1422 +	return SECFailure;
  1.1423 +    }
  1.1424 +    envValue = PR_smprintf("%s,%s", inhValue, fmString);
  1.1425 +    if (!envValue || !strlen(envValue)) {
  1.1426 +	SET_ERROR_CODE
  1.1427 +	return SECFailure;
  1.1428 +    }
  1.1429 +    PORT_Free(inhValue);
  1.1430 +
  1.1431 +    putEnvFailed = (SECStatus)NSS_PutEnv(envVarName, envValue);
  1.1432 +    PR_smprintf_free(envValue);
  1.1433 +    if (putEnvFailed) {
  1.1434 +        SET_ERROR_CODE
  1.1435 +        result = SECFailure;
  1.1436 +    }
  1.1437 +
  1.1438 +#if defined(XP_UNIX) || defined(XP_BEOS)
  1.1439 +    /* Launch thread to poll cache for expired locks on Unix */
  1.1440 +    LaunchLockPoller(cache);
  1.1441 +#endif
  1.1442 +    return result;
  1.1443 +}
  1.1444 +
  1.1445 +/* Use this function, instead of SSL_ConfigServerSessionIDCache,
  1.1446 + * if the cache will be shared by multiple processes.
  1.1447 + */
  1.1448 +SECStatus
  1.1449 +SSL_ConfigMPServerSIDCache(	int      maxCacheEntries, 
  1.1450 +				PRUint32 ssl2_timeout,
  1.1451 +			       	PRUint32 ssl3_timeout, 
  1.1452 +		          const char *   directory)
  1.1453 +{
  1.1454 +    return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout,
  1.1455 +                                             ssl3_timeout,
  1.1456 +                                             directory,
  1.1457 +                                             maxCacheEntries,
  1.1458 +                                             -1, -1);
  1.1459 +}
  1.1460 +
  1.1461 +SECStatus
  1.1462 +SSL_ConfigServerSessionIDCacheWithOpt(
  1.1463 +				PRUint32 ssl2_timeout,
  1.1464 +			       	PRUint32 ssl3_timeout, 
  1.1465 +                                const char *   directory,
  1.1466 +                                int maxCacheEntries,
  1.1467 +                                int maxCertCacheEntries,
  1.1468 +                                int maxSrvNameCacheEntries,
  1.1469 +                                PRBool enableMPCache)
  1.1470 +{
  1.1471 +    if (!enableMPCache) {
  1.1472 +        ssl_InitSessionCacheLocks(PR_FALSE);
  1.1473 +        return ssl_ConfigServerSessionIDCacheInstanceWithOpt(&globalCache, 
  1.1474 +           ssl2_timeout, ssl3_timeout, directory, PR_FALSE,
  1.1475 +           maxCacheEntries, maxCertCacheEntries, maxSrvNameCacheEntries);
  1.1476 +    } else {
  1.1477 +        return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout, ssl3_timeout,
  1.1478 +                directory, maxCacheEntries, maxCertCacheEntries,
  1.1479 +                                                 maxSrvNameCacheEntries);
  1.1480 +    }
  1.1481 +}
  1.1482 +
  1.1483 +SECStatus
  1.1484 +SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
  1.1485 +{
  1.1486 +    unsigned char * decoString = NULL;
  1.1487 +    char *          fmString   = NULL;
  1.1488 +    char *          myEnvString = NULL;
  1.1489 +    unsigned int    decoLen;
  1.1490 +    ptrdiff_t       ptr;
  1.1491 +    inheritance     inherit;
  1.1492 +    cacheDesc       my;
  1.1493 +#ifdef WINNT
  1.1494 +    sidCacheLock* newLocks;
  1.1495 +    int           locks_initialized = 0;
  1.1496 +    int           locks_to_initialize = 0;
  1.1497 +#endif
  1.1498 +    SECStatus     status = ssl_Init();
  1.1499 +
  1.1500 +    if (status != SECSuccess) {
  1.1501 +	return status;
  1.1502 +    }
  1.1503 +
  1.1504 +    myPid = SSL_GETPID();
  1.1505 +
  1.1506 +    /* If this child was created by fork(), and not by exec() on unix,
  1.1507 +    ** then isMultiProcess will already be set.
  1.1508 +    ** If not, we'll set it below.
  1.1509 +    */
  1.1510 +    if (isMultiProcess) {
  1.1511 +	if (cache && cache->sharedCache) {
  1.1512 +	    cache->sharedCache->everInherited = PR_TRUE;
  1.1513 +	}
  1.1514 +    	return SECSuccess;	/* already done. */
  1.1515 +    }
  1.1516 +
  1.1517 +    ssl_InitSessionCacheLocks(PR_FALSE);
  1.1518 +
  1.1519 +    ssl_sid_lookup  = ServerSessionIDLookup;
  1.1520 +    ssl_sid_cache   = ServerSessionIDCache;
  1.1521 +    ssl_sid_uncache = ServerSessionIDUncache;
  1.1522 +
  1.1523 +    if (!envString) {
  1.1524 +    	envString  = getenv(envVarName);
  1.1525 +	if (!envString) {
  1.1526 +	    SET_ERROR_CODE
  1.1527 +	    return SECFailure;
  1.1528 +	}
  1.1529 +    }
  1.1530 +    myEnvString = PORT_Strdup(envString);
  1.1531 +    if (!myEnvString) 
  1.1532 +	return SECFailure;
  1.1533 +    fmString = strchr(myEnvString, ',');
  1.1534 +    if (!fmString) 
  1.1535 +    	goto loser;
  1.1536 +    *fmString++ = 0;
  1.1537 +
  1.1538 +    decoString = ATOB_AsciiToData(myEnvString, &decoLen);
  1.1539 +    if (!decoString) {
  1.1540 +    	SET_ERROR_CODE
  1.1541 +	goto loser;
  1.1542 +    }
  1.1543 +    if (decoLen != sizeof inherit) {
  1.1544 +    	SET_ERROR_CODE
  1.1545 +    	goto loser;
  1.1546 +    }
  1.1547 +
  1.1548 +    PORT_Memcpy(&inherit, decoString, sizeof inherit);
  1.1549 +
  1.1550 +    if (strlen(fmString)  != inherit.fmStrLen ) {
  1.1551 +    	goto loser;
  1.1552 +    }
  1.1553 +
  1.1554 +    memset(cache, 0, sizeof *cache);
  1.1555 +    cache->cacheMemSize	= inherit.cacheMemSize;
  1.1556 +
  1.1557 +    /* Create cache */
  1.1558 +    cache->cacheMemMap = PR_ImportFileMapFromString(fmString);
  1.1559 +    if(! cache->cacheMemMap) {
  1.1560 +	goto loser;
  1.1561 +    }
  1.1562 +    cache->cacheMem = PR_MemMap(cache->cacheMemMap, 0, cache->cacheMemSize);
  1.1563 +    if (! cache->cacheMem) {
  1.1564 +	goto loser;
  1.1565 +    }
  1.1566 +    cache->sharedCache   = (cacheDesc *)cache->cacheMem;
  1.1567 +
  1.1568 +    if (cache->sharedCache->cacheMemSize != cache->cacheMemSize) {
  1.1569 +	SET_ERROR_CODE
  1.1570 +    	goto loser;
  1.1571 +    }
  1.1572 +
  1.1573 +    /* We're now going to overwrite the local cache instance with the 
  1.1574 +    ** shared copy of the cache struct, then update several values in 
  1.1575 +    ** the local cache using the values for cache->cacheMemMap and 
  1.1576 +    ** cache->cacheMem computed just above.  So, we copy cache into 
  1.1577 +    ** the automatic variable "my", to preserve the variables while
  1.1578 +    ** cache is overwritten.
  1.1579 +    */
  1.1580 +    my = *cache;  /* save values computed above. */
  1.1581 +    memcpy(cache, cache->sharedCache, sizeof *cache); /* overwrite */
  1.1582 +
  1.1583 +    /* Fix pointers in our private copy of cache descriptor to point to 
  1.1584 +    ** spaces in shared memory, whose address is now in "my".
  1.1585 +    */
  1.1586 +    ptr = (ptrdiff_t)my.cacheMem;
  1.1587 +    *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
  1.1588 +    *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
  1.1589 +    *(ptrdiff_t *)(&cache->certCacheLock) += ptr;
  1.1590 +    *(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr;
  1.1591 +    *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
  1.1592 +    *(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
  1.1593 +    *(ptrdiff_t *)(&cache->certCacheData) += ptr;
  1.1594 +    *(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
  1.1595 +    *(ptrdiff_t *)(&cache->ticketKeyNameSuffix) += ptr;
  1.1596 +    *(ptrdiff_t *)(&cache->ticketEncKey ) += ptr;
  1.1597 +    *(ptrdiff_t *)(&cache->ticketMacKey ) += ptr;
  1.1598 +    *(ptrdiff_t *)(&cache->ticketKeysValid) += ptr;
  1.1599 +    *(ptrdiff_t *)(&cache->srvNameCacheData) += ptr;
  1.1600 +
  1.1601 +    cache->cacheMemMap = my.cacheMemMap;
  1.1602 +    cache->cacheMem    = my.cacheMem;
  1.1603 +    cache->sharedCache = (cacheDesc *)cache->cacheMem;
  1.1604 +
  1.1605 +#ifdef WINNT
  1.1606 +    /*  On Windows NT we need to "fix" the sidCacheLocks here to support fibers
  1.1607 +    **  When NT fibers are used in a multi-process server, a second level of
  1.1608 +    **  locking is needed to prevent a deadlock, in case a fiber acquires the
  1.1609 +    **  cross-process mutex, yields, and another fiber is later scheduled on
  1.1610 +    **  the same native thread and tries to acquire the cross-process mutex.
  1.1611 +    **  We do this by using a PRLock in the sslMutex. However, it is stored in
  1.1612 +    **  shared memory as part of sidCacheLocks, and we don't want to overwrite
  1.1613 +    **  the PRLock of the parent process. So we need to make new, private
  1.1614 +    **  copies of sidCacheLocks before modifying the sslMutex with our own
  1.1615 +    **  PRLock
  1.1616 +    */
  1.1617 +    
  1.1618 +    /* note from jpierre : this should be free'd in child processes when
  1.1619 +    ** a function is added to delete the SSL session cache in the future. 
  1.1620 +    */
  1.1621 +    locks_to_initialize = cache->numSIDCacheLocks + 3;
  1.1622 +    newLocks = PORT_NewArray(sidCacheLock, locks_to_initialize);
  1.1623 +    if (!newLocks)
  1.1624 +    	goto loser;
  1.1625 +    /* copy the old locks */
  1.1626 +    memcpy(newLocks, cache->sidCacheLocks, 
  1.1627 +           locks_to_initialize * sizeof(sidCacheLock));
  1.1628 +    cache->sidCacheLocks = newLocks;
  1.1629 +    /* fix the locks */		
  1.1630 +    for (; locks_initialized < locks_to_initialize; ++locks_initialized) {
  1.1631 +        /* now, make a local PRLock in this sslMutex for this child process */
  1.1632 +	SECStatus err;
  1.1633 +        err = sslMutex_2LevelInit(&newLocks[locks_initialized].mutex);
  1.1634 +	if (err != SECSuccess) {
  1.1635 +	    cache->numSIDCacheLocksInitialized = locks_initialized;
  1.1636 +	    goto loser;
  1.1637 +    	}
  1.1638 +    }
  1.1639 +    cache->numSIDCacheLocksInitialized = locks_initialized;
  1.1640 +
  1.1641 +    /* also fix the key and cert cache which use the last 2 lock entries */
  1.1642 +    cache->keyCacheLock  = cache->sidCacheLocks + cache->numSIDCacheLocks;
  1.1643 +    cache->certCacheLock = cache->keyCacheLock  + 1;
  1.1644 +    cache->srvNameCacheLock = cache->certCacheLock  + 1;
  1.1645 +#endif
  1.1646 +
  1.1647 +    PORT_Free(myEnvString);
  1.1648 +    PORT_Free(decoString);
  1.1649 +
  1.1650 +    /* mark that we have inherited this. */
  1.1651 +    cache->sharedCache->everInherited = PR_TRUE;
  1.1652 +    isMultiProcess = PR_TRUE;
  1.1653 +
  1.1654 +    return SECSuccess;
  1.1655 +
  1.1656 +loser:
  1.1657 +    PORT_Free(myEnvString);
  1.1658 +    if (decoString) 
  1.1659 +	PORT_Free(decoString);
  1.1660 +    CloseCache(cache);
  1.1661 +    return SECFailure;
  1.1662 +}
  1.1663 +
  1.1664 +SECStatus
  1.1665 +SSL_InheritMPServerSIDCache(const char * envString)
  1.1666 +{
  1.1667 +    return SSL_InheritMPServerSIDCacheInstance(&globalCache, envString);
  1.1668 +}
  1.1669 +
  1.1670 +#if defined(XP_UNIX) || defined(XP_BEOS)
  1.1671 +
  1.1672 +#define SID_LOCK_EXPIRATION_TIMEOUT  30 /* seconds */
  1.1673 +
  1.1674 +static void
  1.1675 +LockPoller(void * arg)
  1.1676 +{
  1.1677 +    cacheDesc *    cache         = (cacheDesc *)arg;
  1.1678 +    cacheDesc *    sharedCache   = cache->sharedCache;
  1.1679 +    sidCacheLock * pLock;
  1.1680 +    PRIntervalTime timeout;
  1.1681 +    PRUint32       now;
  1.1682 +    PRUint32       then;
  1.1683 +    int            locks_polled  = 0;
  1.1684 +    int            locks_to_poll = cache->numSIDCacheLocks + 2;
  1.1685 +    PRUint32       expiration    = cache->mutexTimeout;
  1.1686 +
  1.1687 +    timeout = PR_SecondsToInterval(expiration);
  1.1688 +    while(!sharedCache->stopPolling) {
  1.1689 +    	PR_Sleep(timeout);
  1.1690 +	if (sharedCache->stopPolling)
  1.1691 +	    break;
  1.1692 +
  1.1693 +	now   = ssl_Time();
  1.1694 +	then  = now - expiration;
  1.1695 +	for (pLock = cache->sidCacheLocks, locks_polled = 0;
  1.1696 +	     locks_to_poll > locks_polled && !sharedCache->stopPolling; 
  1.1697 +	     ++locks_polled, ++pLock ) {
  1.1698 +	    pid_t pid;
  1.1699 +
  1.1700 +	    if (pLock->timeStamp   < then && 
  1.1701 +	        pLock->timeStamp   != 0 && 
  1.1702 +		(pid = pLock->pid) != 0) {
  1.1703 +
  1.1704 +	    	/* maybe we should try the lock? */
  1.1705 +		int result = kill(pid, 0);
  1.1706 +		if (result < 0 && errno == ESRCH) {
  1.1707 +		    SECStatus rv;
  1.1708 +		    /* No process exists by that pid any more.
  1.1709 +		    ** Treat this mutex as abandoned.
  1.1710 +		    */
  1.1711 +		    pLock->timeStamp = now;
  1.1712 +		    pLock->pid       = 0;
  1.1713 +		    rv = sslMutex_Unlock(&pLock->mutex);
  1.1714 +		    if (rv != SECSuccess) {
  1.1715 +		    	/* Now what? */
  1.1716 +		    }
  1.1717 +		}
  1.1718 +	    }
  1.1719 +	} /* end of loop over locks */
  1.1720 +    } /* end of entire polling loop */
  1.1721 +}
  1.1722 +
  1.1723 +/* Launch thread to poll cache for expired locks */
  1.1724 +static SECStatus 
  1.1725 +LaunchLockPoller(cacheDesc *cache)
  1.1726 +{
  1.1727 +    const char * timeoutString;
  1.1728 +    PRThread *   pollerThread;
  1.1729 +
  1.1730 +    cache->mutexTimeout = SID_LOCK_EXPIRATION_TIMEOUT;
  1.1731 +    timeoutString       = getenv("NSS_SSL_SERVER_CACHE_MUTEX_TIMEOUT");
  1.1732 +    if (timeoutString) {
  1.1733 +	long newTime = strtol(timeoutString, 0, 0);
  1.1734 +	if (newTime == 0) 
  1.1735 +	    return SECSuccess;  /* application doesn't want poller thread */
  1.1736 +	if (newTime > 0)
  1.1737 +	    cache->mutexTimeout = (PRUint32)newTime;
  1.1738 +	/* if error (newTime < 0) ignore it and use default */
  1.1739 +    }
  1.1740 +
  1.1741 +    pollerThread = 
  1.1742 +	PR_CreateThread(PR_USER_THREAD, LockPoller, cache, PR_PRIORITY_NORMAL, 
  1.1743 +	                PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
  1.1744 +    if (!pollerThread) {
  1.1745 +    	return SECFailure;
  1.1746 +    }
  1.1747 +    cache->poller = pollerThread;
  1.1748 +    return SECSuccess;
  1.1749 +}
  1.1750 +
  1.1751 +/* Stop the thread that polls cache for expired locks */
  1.1752 +static SECStatus 
  1.1753 +StopLockPoller(cacheDesc *cache)
  1.1754 +{
  1.1755 +    if (!cache->poller) {
  1.1756 +	return SECSuccess;
  1.1757 +    }
  1.1758 +    cache->sharedCache->stopPolling = PR_TRUE;
  1.1759 +    if (PR_Interrupt(cache->poller) != PR_SUCCESS) {
  1.1760 +	return SECFailure;
  1.1761 +    }
  1.1762 +    if (PR_JoinThread(cache->poller) != PR_SUCCESS) {
  1.1763 +	return SECFailure;
  1.1764 +    }
  1.1765 +    cache->poller = NULL;
  1.1766 +    return SECSuccess;
  1.1767 +}
  1.1768 +#endif
  1.1769 +
  1.1770 +/************************************************************************
  1.1771 + *  Code dealing with shared wrapped symmetric wrapping keys below      *
  1.1772 + ************************************************************************/
  1.1773 +
  1.1774 +/* If now is zero, it implies that the lock is not held, and must be 
  1.1775 +** aquired here.  
  1.1776 +*/
  1.1777 +static PRBool
  1.1778 +getSvrWrappingKey(PRInt32                symWrapMechIndex,
  1.1779 +               SSL3KEAType               exchKeyType, 
  1.1780 +               SSLWrappedSymWrappingKey *wswk, 
  1.1781 +	       cacheDesc *               cache,
  1.1782 +	       PRUint32                  lockTime)
  1.1783 +{
  1.1784 +    PRUint32  ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
  1.1785 +    SSLWrappedSymWrappingKey * pwswk = cache->keyCacheData + ndx;
  1.1786 +    PRUint32  now = 0;
  1.1787 +    PRBool    rv  = PR_FALSE;
  1.1788 +
  1.1789 +    if (!cache->cacheMem) { /* cache is uninitialized */
  1.1790 +	PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
  1.1791 +	return rv;
  1.1792 +    }
  1.1793 +    if (!lockTime) {
  1.1794 +	lockTime = now = LockSidCacheLock(cache->keyCacheLock, now);
  1.1795 +	if (!lockTime) {
  1.1796 +	    return rv;
  1.1797 +	}
  1.1798 +    }
  1.1799 +    if (pwswk->exchKeyType      == exchKeyType && 
  1.1800 +	pwswk->symWrapMechIndex == symWrapMechIndex &&
  1.1801 +	pwswk->wrappedSymKeyLen != 0) {
  1.1802 +	*wswk = *pwswk;
  1.1803 +	rv = PR_TRUE;
  1.1804 +    }
  1.1805 +    if (now) {
  1.1806 +	UnlockSidCacheLock(cache->keyCacheLock);
  1.1807 +    }
  1.1808 +    return rv;
  1.1809 +}
  1.1810 +
  1.1811 +PRBool
  1.1812 +ssl_GetWrappingKey( PRInt32                   symWrapMechIndex,
  1.1813 +                    SSL3KEAType               exchKeyType, 
  1.1814 +		    SSLWrappedSymWrappingKey *wswk)
  1.1815 +{
  1.1816 +    PRBool rv;
  1.1817 +
  1.1818 +    PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
  1.1819 +    PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
  1.1820 +    if ((unsigned)exchKeyType < kt_kea_size &&
  1.1821 +        (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) {
  1.1822 +	rv = getSvrWrappingKey(symWrapMechIndex, exchKeyType, wswk, 
  1.1823 +	                       &globalCache, 0);
  1.1824 +    } else {
  1.1825 +    	rv = PR_FALSE;
  1.1826 +    }
  1.1827 +
  1.1828 +    return rv;
  1.1829 +}
  1.1830 +
  1.1831 +/* Wrap and cache a session ticket key. */
  1.1832 +static PRBool
  1.1833 +WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey,
  1.1834 +              const char *keyName, encKeyCacheEntry* cacheEntry)
  1.1835 +{
  1.1836 +    SECItem wrappedKey = {siBuffer, NULL, 0};
  1.1837 +
  1.1838 +    wrappedKey.len = SECKEY_PublicKeyStrength(svrPubKey);
  1.1839 +    PORT_Assert(wrappedKey.len <= sizeof(cacheEntry->bytes));
  1.1840 +    if (wrappedKey.len > sizeof(cacheEntry->bytes))
  1.1841 +	return PR_FALSE;
  1.1842 +    wrappedKey.data = cacheEntry->bytes;
  1.1843 +
  1.1844 +    if (PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, symKey, &wrappedKey)
  1.1845 +	    != SECSuccess) {
  1.1846 +	SSL_DBG(("%d: SSL[%s]: Unable to wrap session ticket %s.",
  1.1847 +		    SSL_GETPID(), "unknown", keyName));
  1.1848 +	return PR_FALSE;
  1.1849 +    }
  1.1850 +    cacheEntry->length = wrappedKey.len;
  1.1851 +    return PR_TRUE;
  1.1852 +}
  1.1853 +
  1.1854 +static PRBool
  1.1855 +GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey,
  1.1856 +                   PK11SymKey **macKey)
  1.1857 +{
  1.1858 +    PK11SlotInfo *slot;
  1.1859 +    CK_MECHANISM_TYPE mechanismArray[2];
  1.1860 +    PK11SymKey *aesKeyTmp = NULL;
  1.1861 +    PK11SymKey *macKeyTmp = NULL;
  1.1862 +    cacheDesc *cache = &globalCache;
  1.1863 +    PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN];
  1.1864 +    PRUint8 *ticketKeyNameSuffix;
  1.1865 +
  1.1866 +    if (!cache->cacheMem) {
  1.1867 +        /* cache is not initalized. Use stack buffer */
  1.1868 +        ticketKeyNameSuffix = ticketKeyNameSuffixLocal;
  1.1869 +    } else {
  1.1870 +        ticketKeyNameSuffix = cache->ticketKeyNameSuffix;
  1.1871 +    }
  1.1872 +
  1.1873 +    if (PK11_GenerateRandom(ticketKeyNameSuffix,
  1.1874 +	    SESS_TICKET_KEY_VAR_NAME_LEN) != SECSuccess) {
  1.1875 +	SSL_DBG(("%d: SSL[%s]: Unable to generate random key name bytes.",
  1.1876 +		    SSL_GETPID(), "unknown"));
  1.1877 +	goto loser;
  1.1878 +    }
  1.1879 +
  1.1880 +    mechanismArray[0] = CKM_AES_CBC;
  1.1881 +    mechanismArray[1] = CKM_SHA256_HMAC;
  1.1882 +
  1.1883 +    slot = PK11_GetBestSlotMultiple(mechanismArray, 2, pwArg);
  1.1884 +    if (slot) {
  1.1885 +	aesKeyTmp = PK11_KeyGen(slot, mechanismArray[0], NULL,
  1.1886 +                                AES_256_KEY_LENGTH, pwArg);
  1.1887 +	macKeyTmp = PK11_KeyGen(slot, mechanismArray[1], NULL,
  1.1888 +                                SHA256_LENGTH, pwArg);
  1.1889 +	PK11_FreeSlot(slot);
  1.1890 +    }
  1.1891 +
  1.1892 +    if (aesKeyTmp == NULL || macKeyTmp == NULL) {
  1.1893 +	SSL_DBG(("%d: SSL[%s]: Unable to generate session ticket keys.",
  1.1894 +		    SSL_GETPID(), "unknown"));
  1.1895 +	goto loser;
  1.1896 +    }
  1.1897 +    PORT_Memcpy(keyName, ticketKeyNameSuffix, SESS_TICKET_KEY_VAR_NAME_LEN);
  1.1898 +    *aesKey = aesKeyTmp;
  1.1899 +    *macKey = macKeyTmp;
  1.1900 +    return PR_TRUE;
  1.1901 +
  1.1902 +loser:
  1.1903 +    if (aesKeyTmp)
  1.1904 +	PK11_FreeSymKey(aesKeyTmp);
  1.1905 +    if (macKeyTmp)
  1.1906 +	PK11_FreeSymKey(macKeyTmp);
  1.1907 +    return PR_FALSE;
  1.1908 +}
  1.1909 +
  1.1910 +static PRBool
  1.1911 +GenerateAndWrapTicketKeys(SECKEYPublicKey *svrPubKey, void *pwArg,
  1.1912 +                          unsigned char *keyName, PK11SymKey **aesKey,
  1.1913 +                          PK11SymKey **macKey)
  1.1914 +{
  1.1915 +    PK11SymKey *aesKeyTmp = NULL;
  1.1916 +    PK11SymKey *macKeyTmp = NULL;
  1.1917 +    cacheDesc *cache = &globalCache;
  1.1918 +
  1.1919 +    if (!GenerateTicketKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp)) {
  1.1920 +        goto loser;
  1.1921 +    }
  1.1922 +
  1.1923 +    if (cache->cacheMem) {
  1.1924 +        /* Export the keys to the shared cache in wrapped form. */
  1.1925 +        if (!WrapTicketKey(svrPubKey, aesKeyTmp, "enc key", cache->ticketEncKey))
  1.1926 +            goto loser;
  1.1927 +        if (!WrapTicketKey(svrPubKey, macKeyTmp, "mac key", cache->ticketMacKey))
  1.1928 +            goto loser;
  1.1929 +    }
  1.1930 +    *aesKey = aesKeyTmp;
  1.1931 +    *macKey = macKeyTmp;
  1.1932 +    return PR_TRUE;
  1.1933 +
  1.1934 +loser:
  1.1935 +    if (aesKeyTmp)
  1.1936 +	PK11_FreeSymKey(aesKeyTmp);
  1.1937 +    if (macKeyTmp)
  1.1938 +	PK11_FreeSymKey(macKeyTmp);
  1.1939 +    return PR_FALSE;
  1.1940 +}
  1.1941 +
  1.1942 +static PRBool
  1.1943 +UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName,
  1.1944 +                       PK11SymKey **aesKey, PK11SymKey **macKey)
  1.1945 +{
  1.1946 +    SECItem wrappedKey = {siBuffer, NULL, 0};
  1.1947 +    PK11SymKey *aesKeyTmp = NULL;
  1.1948 +    PK11SymKey *macKeyTmp = NULL;
  1.1949 +    cacheDesc *cache = &globalCache;
  1.1950 +
  1.1951 +    wrappedKey.data = cache->ticketEncKey->bytes;
  1.1952 +    wrappedKey.len = cache->ticketEncKey->length;
  1.1953 +    PORT_Assert(wrappedKey.len <= sizeof(cache->ticketEncKey->bytes));
  1.1954 +    aesKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
  1.1955 +	CKM_AES_CBC, CKA_DECRYPT, 0);
  1.1956 +
  1.1957 +    wrappedKey.data = cache->ticketMacKey->bytes;
  1.1958 +    wrappedKey.len = cache->ticketMacKey->length;
  1.1959 +    PORT_Assert(wrappedKey.len <= sizeof(cache->ticketMacKey->bytes));
  1.1960 +    macKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
  1.1961 +	CKM_SHA256_HMAC, CKA_SIGN, 0);
  1.1962 +
  1.1963 +    if (aesKeyTmp == NULL || macKeyTmp == NULL) {
  1.1964 +	SSL_DBG(("%d: SSL[%s]: Unable to unwrap session ticket keys.",
  1.1965 +		    SSL_GETPID(), "unknown"));
  1.1966 +	goto loser;
  1.1967 +    }
  1.1968 +    SSL_DBG(("%d: SSL[%s]: Successfully unwrapped session ticket keys.",
  1.1969 +		SSL_GETPID(), "unknown"));
  1.1970 +
  1.1971 +    PORT_Memcpy(keyName, cache->ticketKeyNameSuffix,
  1.1972 +	SESS_TICKET_KEY_VAR_NAME_LEN);
  1.1973 +    *aesKey = aesKeyTmp;
  1.1974 +    *macKey = macKeyTmp;
  1.1975 +    return PR_TRUE;
  1.1976 +
  1.1977 +loser:
  1.1978 +    if (aesKeyTmp)
  1.1979 +	PK11_FreeSymKey(aesKeyTmp);
  1.1980 +    if (macKeyTmp)
  1.1981 +	PK11_FreeSymKey(macKeyTmp);
  1.1982 +    return PR_FALSE;
  1.1983 +}
  1.1984 +
  1.1985 +PRBool
  1.1986 +ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey,
  1.1987 +                               SECKEYPublicKey *svrPubKey, void *pwArg,
  1.1988 +                               unsigned char *keyName, PK11SymKey **aesKey,
  1.1989 +                               PK11SymKey **macKey)
  1.1990 +{
  1.1991 +    PRUint32 now = 0;
  1.1992 +    PRBool rv = PR_FALSE;
  1.1993 +    PRBool keysGenerated = PR_FALSE;
  1.1994 +    cacheDesc *cache = &globalCache;
  1.1995 +
  1.1996 +    if (!cache->cacheMem) {
  1.1997 +        /* cache is uninitialized. Generate keys and return them
  1.1998 +         * without caching. */
  1.1999 +        return GenerateTicketKeys(pwArg, keyName, aesKey, macKey);
  1.2000 +    }
  1.2001 +
  1.2002 +    now = LockSidCacheLock(cache->keyCacheLock, now);
  1.2003 +    if (!now)
  1.2004 +	return rv;
  1.2005 +
  1.2006 +    if (!*(cache->ticketKeysValid)) {
  1.2007 +	/* Keys do not exist, create them. */
  1.2008 +	if (!GenerateAndWrapTicketKeys(svrPubKey, pwArg, keyName,
  1.2009 +		aesKey, macKey))
  1.2010 +	    goto loser;
  1.2011 +	keysGenerated = PR_TRUE;
  1.2012 +	*(cache->ticketKeysValid) = 1;
  1.2013 +    }
  1.2014 +
  1.2015 +    rv = PR_TRUE;
  1.2016 +
  1.2017 + loser:
  1.2018 +    UnlockSidCacheLock(cache->keyCacheLock);
  1.2019 +    if (rv && !keysGenerated)
  1.2020 +	rv = UnwrapCachedTicketKeys(svrPrivKey, keyName, aesKey, macKey);
  1.2021 +    return rv;
  1.2022 +}
  1.2023 +
  1.2024 +PRBool
  1.2025 +ssl_GetSessionTicketKeys(unsigned char *keyName, unsigned char *encKey,
  1.2026 +                         unsigned char *macKey)
  1.2027 +{
  1.2028 +    PRBool rv = PR_FALSE;
  1.2029 +    PRUint32 now = 0;
  1.2030 +    cacheDesc *cache = &globalCache;
  1.2031 +    PRUint8 ticketMacKey[SHA256_LENGTH], ticketEncKey[AES_256_KEY_LENGTH];
  1.2032 +    PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN];
  1.2033 +    PRUint8 *ticketMacKeyPtr, *ticketEncKeyPtr, *ticketKeyNameSuffix;
  1.2034 +    PRBool cacheIsEnabled = PR_TRUE;
  1.2035 +
  1.2036 +    if (!cache->cacheMem) { /* cache is uninitialized */
  1.2037 +        cacheIsEnabled = PR_FALSE;
  1.2038 +        ticketKeyNameSuffix = ticketKeyNameSuffixLocal;
  1.2039 +        ticketEncKeyPtr = ticketEncKey;
  1.2040 +        ticketMacKeyPtr = ticketMacKey;
  1.2041 +    } else {
  1.2042 +        /* these values have constant memory locations in the cache.
  1.2043 +         * Ok to reference them without holding the lock. */
  1.2044 +        ticketKeyNameSuffix = cache->ticketKeyNameSuffix;
  1.2045 +        ticketEncKeyPtr = cache->ticketEncKey->bytes;
  1.2046 +        ticketMacKeyPtr = cache->ticketMacKey->bytes;
  1.2047 +    }
  1.2048 +
  1.2049 +    if (cacheIsEnabled) {
  1.2050 +        /* Grab lock if initialized. */
  1.2051 +        now = LockSidCacheLock(cache->keyCacheLock, now);
  1.2052 +        if (!now)
  1.2053 +            return rv;
  1.2054 +    }
  1.2055 +    /* Going to regenerate keys on every call if cache was not
  1.2056 +     * initialized. */
  1.2057 +    if (!cacheIsEnabled || !*(cache->ticketKeysValid)) {
  1.2058 +	if (PK11_GenerateRandom(ticketKeyNameSuffix,
  1.2059 +		SESS_TICKET_KEY_VAR_NAME_LEN) != SECSuccess)
  1.2060 +	    goto loser;
  1.2061 +	if (PK11_GenerateRandom(ticketEncKeyPtr,
  1.2062 +                                AES_256_KEY_LENGTH) != SECSuccess)
  1.2063 +	    goto loser;
  1.2064 +	if (PK11_GenerateRandom(ticketMacKeyPtr,
  1.2065 +                                SHA256_LENGTH) != SECSuccess)
  1.2066 +	    goto loser;
  1.2067 +        if (cacheIsEnabled) {
  1.2068 +            *(cache->ticketKeysValid) = 1;
  1.2069 +        }
  1.2070 +    }
  1.2071 +
  1.2072 +    rv = PR_TRUE;
  1.2073 +
  1.2074 + loser:
  1.2075 +    if (cacheIsEnabled) {
  1.2076 +        UnlockSidCacheLock(cache->keyCacheLock);
  1.2077 +    }
  1.2078 +    if (rv) {
  1.2079 +	PORT_Memcpy(keyName, ticketKeyNameSuffix,
  1.2080 +                    SESS_TICKET_KEY_VAR_NAME_LEN);
  1.2081 +	PORT_Memcpy(encKey, ticketEncKeyPtr, AES_256_KEY_LENGTH);
  1.2082 +	PORT_Memcpy(macKey, ticketMacKeyPtr, SHA256_LENGTH);
  1.2083 +    }
  1.2084 +    return rv;
  1.2085 +}
  1.2086 +
  1.2087 +/* The caller passes in the new value it wants
  1.2088 + * to set.  This code tests the wrapped sym key entry in the shared memory.
  1.2089 + * If it is uninitialized, this function writes the caller's value into 
  1.2090 + * the disk entry, and returns false.  
  1.2091 + * Otherwise, it overwrites the caller's wswk with the value obtained from 
  1.2092 + * the disk, and returns PR_TRUE.  
  1.2093 + * This is all done while holding the locks/mutexes necessary to make 
  1.2094 + * the operation atomic.
  1.2095 + */
  1.2096 +PRBool
  1.2097 +ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
  1.2098 +{
  1.2099 +    cacheDesc *   cache            = &globalCache;
  1.2100 +    PRBool        rv               = PR_FALSE;
  1.2101 +    SSL3KEAType   exchKeyType      = wswk->exchKeyType;   
  1.2102 +                                /* type of keys used to wrap SymWrapKey*/
  1.2103 +    PRInt32       symWrapMechIndex = wswk->symWrapMechIndex;
  1.2104 +    PRUint32      ndx;
  1.2105 +    PRUint32      now = 0;
  1.2106 +    SSLWrappedSymWrappingKey myWswk;
  1.2107 +
  1.2108 +    if (!cache->cacheMem) { /* cache is uninitialized */
  1.2109 +	PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
  1.2110 +	return 0;
  1.2111 +    }
  1.2112 +
  1.2113 +    PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
  1.2114 +    if ((unsigned)exchKeyType >= kt_kea_size)
  1.2115 +    	return 0;
  1.2116 +
  1.2117 +    PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
  1.2118 +    if ((unsigned)symWrapMechIndex >=  SSL_NUM_WRAP_MECHS)
  1.2119 +    	return 0;
  1.2120 +
  1.2121 +    ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
  1.2122 +    PORT_Memset(&myWswk, 0, sizeof myWswk);	/* eliminate UMRs. */
  1.2123 +
  1.2124 +    now = LockSidCacheLock(cache->keyCacheLock, now);
  1.2125 +    if (now) {
  1.2126 +	rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->exchKeyType, 
  1.2127 +	                       &myWswk, cache, now);
  1.2128 +	if (rv) {
  1.2129 +	    /* we found it on disk, copy it out to the caller. */
  1.2130 +	    PORT_Memcpy(wswk, &myWswk, sizeof *wswk);
  1.2131 +	} else {
  1.2132 +	    /* Wasn't on disk, and we're still holding the lock, so write it. */
  1.2133 +	    cache->keyCacheData[ndx] = *wswk;
  1.2134 +	}
  1.2135 +	UnlockSidCacheLock(cache->keyCacheLock);
  1.2136 +    }
  1.2137 +    return rv;
  1.2138 +}
  1.2139 +
  1.2140 +#else  /* MAC version or other platform */
  1.2141 +
  1.2142 +#include "seccomon.h"
  1.2143 +#include "cert.h"
  1.2144 +#include "ssl.h"
  1.2145 +#include "sslimpl.h"
  1.2146 +
  1.2147 +SECStatus
  1.2148 +SSL_ConfigServerSessionIDCache(	int      maxCacheEntries, 
  1.2149 +				PRUint32 ssl2_timeout,
  1.2150 +			       	PRUint32 ssl3_timeout, 
  1.2151 +			  const char *   directory)
  1.2152 +{
  1.2153 +    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigServerSessionIDCache)");    
  1.2154 +    return SECFailure;
  1.2155 +}
  1.2156 +
  1.2157 +SECStatus
  1.2158 +SSL_ConfigMPServerSIDCache(	int      maxCacheEntries, 
  1.2159 +				PRUint32 ssl2_timeout,
  1.2160 +			       	PRUint32 ssl3_timeout, 
  1.2161 +		          const char *   directory)
  1.2162 +{
  1.2163 +    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigMPServerSIDCache)");    
  1.2164 +    return SECFailure;
  1.2165 +}
  1.2166 +
  1.2167 +SECStatus
  1.2168 +SSL_InheritMPServerSIDCache(const char * envString)
  1.2169 +{
  1.2170 +    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_InheritMPServerSIDCache)");    
  1.2171 +    return SECFailure;
  1.2172 +}
  1.2173 +
  1.2174 +PRBool
  1.2175 +ssl_GetWrappingKey( PRInt32                   symWrapMechIndex,
  1.2176 +                    SSL3KEAType               exchKeyType, 
  1.2177 +		    SSLWrappedSymWrappingKey *wswk)
  1.2178 +{
  1.2179 +    PRBool rv = PR_FALSE;
  1.2180 +    PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)");    
  1.2181 +    return rv;
  1.2182 +}
  1.2183 +
  1.2184 +/* This is a kind of test-and-set.  The caller passes in the new value it wants
  1.2185 + * to set.  This code tests the wrapped sym key entry in the shared memory.
  1.2186 + * If it is uninitialized, this function writes the caller's value into 
  1.2187 + * the disk entry, and returns false.  
  1.2188 + * Otherwise, it overwrites the caller's wswk with the value obtained from 
  1.2189 + * the disk, and returns PR_TRUE.  
  1.2190 + * This is all done while holding the locks/mutexes necessary to make 
  1.2191 + * the operation atomic.
  1.2192 + */
  1.2193 +PRBool
  1.2194 +ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
  1.2195 +{
  1.2196 +    PRBool        rv = PR_FALSE;
  1.2197 +    PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrappingKey)");
  1.2198 +    return rv;
  1.2199 +}
  1.2200 +
  1.2201 +PRUint32  
  1.2202 +SSL_GetMaxServerCacheLocks(void)
  1.2203 +{
  1.2204 +    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_GetMaxServerCacheLocks)");
  1.2205 +    return -1;
  1.2206 +}
  1.2207 +
  1.2208 +SECStatus 
  1.2209 +SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
  1.2210 +{
  1.2211 +    PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_SetMaxServerCacheLocks)");
  1.2212 +    return SECFailure;
  1.2213 +}
  1.2214 +
  1.2215 +#endif /* XP_UNIX || XP_WIN32 */

mercurial