security/nss/lib/ssl/sslsnce.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial