Back to index

lightning-sunbird  0.9+nobinonly
sslsnce.c
Go to the documentation of this file.
00001 /* This file implements the SERVER Session ID cache. 
00002  * NOTE:  The contents of this file are NOT used by the client.
00003  *
00004  * ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is the Netscape security libraries.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 /* $Id: sslsnce.c,v 1.36.2.2 2006/07/17 22:15:10 alexei.volkov.bugs%sun.com Exp $ */
00040 
00041 /* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server 
00042  * cache sids!
00043  *
00044  * About record locking among different server processes:
00045  *
00046  * All processes that are part of the same conceptual server (serving on 
00047  * the same address and port) MUST share a common SSL session cache. 
00048  * This code makes the content of the shared cache accessible to all
00049  * processes on the same "server".  This code works on Unix and Win32 only.
00050  *
00051  * We use NSPR anonymous shared memory and move data to & from shared memory.
00052  * We must do explicit locking of the records for all reads and writes.
00053  * The set of Cache entries are divided up into "sets" of 128 entries. 
00054  * Each set is protected by a lock.  There may be one or more sets protected
00055  * by each lock.  That is, locks to sets are 1:N.
00056  * There is one lock for the entire cert cache.
00057  * There is one lock for the set of wrapped sym wrap keys.
00058  *
00059  * The anonymous shared memory is laid out as if it were declared like this:
00060  *
00061  * struct {
00062  *     cacheDescriptor          desc;
00063  *     sidCacheLock             sidCacheLocks[ numSIDCacheLocks];
00064  *     sidCacheLock             keyCacheLock;
00065  *     sidCacheLock             certCacheLock;
00066  *     sidCacheSet              sidCacheSets[ numSIDCacheSets ];
00067  *     sidCacheEntry            sidCacheData[ numSIDCacheEntries];
00068  *     certCacheEntry           certCacheData[numCertCacheEntries];
00069  *     SSLWrappedSymWrappingKey keyCacheData[kt_kea_size][SSL_NUM_WRAP_MECHS];
00070  * } cacheMemCacheData;
00071  */
00072 #include "nssrenam.h"
00073 #include "seccomon.h"
00074 
00075 #if (defined(XP_UNIX) || defined(XP_WIN32) || defined (XP_OS2) || defined(XP_BEOS)) && !defined(_WIN32_WCE)
00076 
00077 #include "cert.h"
00078 #include "ssl.h"
00079 #include "sslimpl.h"
00080 #include "sslproto.h"
00081 #include "pk11func.h"
00082 #include "base64.h"
00083 
00084 #include <stdio.h>
00085 
00086 #if defined(XP_UNIX) || defined(XP_BEOS)
00087 
00088 #include <syslog.h>
00089 #include <fcntl.h>
00090 #include <unistd.h>
00091 #include <errno.h>
00092 #include <signal.h>
00093 #include "unix_err.h"
00094 
00095 #else
00096 
00097 #ifdef XP_WIN32
00098 #include <wtypes.h>
00099 #include "win32err.h"
00100 #endif
00101 
00102 #endif 
00103 #include <sys/types.h>
00104 
00105 #define SET_ERROR_CODE /* reminder */
00106 
00107 #include "nspr.h"
00108 #include "nsslocks.h"
00109 #include "sslmutex.h"
00110 
00111 #ifdef XP_OS2_VACPP
00112 #pragma pack(1)
00113 #endif
00114 
00115 /*
00116 ** Format of a cache entry in the shared memory.
00117 */ 
00118 struct sidCacheEntryStr {
00119 /* 16 */    PRIPv6Addr  addr;      /* client's IP address */
00120 /*  4 */    PRUint32    creationTime;
00121 /*  4 */    PRUint32    lastAccessTime;   
00122 /*  4 */    PRUint32    expirationTime;
00123 /*  2 */    PRUint16 version;
00124 /*  1 */    PRUint8  valid;
00125 /*  1 */    PRUint8     sessionIDLength;
00126 /* 32 */    PRUint8     sessionID[SSL3_SESSIONID_BYTES];
00127 /*  2 */    PRUint16    authAlgorithm;
00128 /*  2 */    PRUint16    authKeyBits;
00129 /*  2 */    PRUint16    keaType;
00130 /*  2 */    PRUint16    keaKeyBits;
00131 /* 72  - common header total */
00132 
00133     union {
00134        struct {
00135 /* 64 */    PRUint8  masterKey[SSL_MAX_MASTER_KEY_BYTES];
00136 /* 32 */    PRUint8  cipherArg[SSL_MAX_CYPHER_ARG_BYTES];
00137 
00138 /*  1 */    PRUint8  cipherType;
00139 /*  1 */    PRUint8  masterKeyLen;
00140 /*  1 */    PRUint8  keyBits;
00141 /*  1 */    PRUint8  secretKeyBits;
00142 /*  1 */    PRUint8  cipherArgLen;
00143 /*101 */} ssl2;
00144 
00145        struct {
00146 /*  2 */    ssl3CipherSuite  cipherSuite;
00147 /*  2 */    PRUint16    compression;      /* SSL3CompressionMethod */
00148 
00149 /*100 */    ssl3SidKeys keys;      /* keys and ivs, wrapped as needed. */
00150 
00151 /*  4 */    PRUint32    masterWrapMech; 
00152 /*  4 */    SSL3KEAType exchKeyType;
00153 /*  4 */    PRInt32     certIndex;
00154 /*116 */} ssl3;
00155 #if defined(LINUX)                      /* XXX Why only on Linux ? */
00156        struct {
00157            PRUint8     filler[144];       /* XXX why this number ? */
00158        } forceSize;
00159 #endif
00160     } u;
00161 };
00162 typedef struct sidCacheEntryStr sidCacheEntry;
00163 
00164 /* The length of this struct is supposed to be a power of 2, e.g. 4KB */
00165 struct certCacheEntryStr {
00166     PRUint16    certLength;                      /*    2 */
00167     PRUint16    sessionIDLength;                 /*    2 */
00168     PRUint8   sessionID[SSL3_SESSIONID_BYTES];   /*   32 */
00169     PRUint8   cert[SSL_MAX_CACHED_CERT_LEN];            /* 4060 */
00170 };                                        /* total   4096 */
00171 typedef struct certCacheEntryStr certCacheEntry;
00172 
00173 struct sidCacheLockStr {
00174     PRUint32  timeStamp;
00175     sslMutex  mutex;
00176     sslPID    pid;
00177 };
00178 typedef struct sidCacheLockStr sidCacheLock;
00179 
00180 struct sidCacheSetStr {
00181     PRIntn    next;
00182 };
00183 typedef struct sidCacheSetStr sidCacheSet;
00184 
00185 struct cacheDescStr {
00186 
00187     PRUint32            cacheMemSize;
00188 
00189     PRUint32         numSIDCacheLocks;
00190     PRUint32         numSIDCacheSets;
00191     PRUint32         numSIDCacheSetsPerLock;
00192 
00193     PRUint32            numSIDCacheEntries; 
00194     PRUint32            sidCacheSize;
00195 
00196     PRUint32            numCertCacheEntries;
00197     PRUint32            certCacheSize;
00198 
00199     PRUint32            numKeyCacheEntries;
00200     PRUint32            keyCacheSize;
00201 
00202     PRUint32         ssl2Timeout;
00203     PRUint32         ssl3Timeout;
00204 
00205     PRUint32            numSIDCacheLocksInitialized;
00206 
00207     /* These values are volatile, and are accessed through sharedCache-> */
00208     PRUint32         nextCertCacheEntry;  /* certCacheLock protects */
00209     PRBool           stopPolling;
00210     PRBool           everInherited;
00211 
00212     /* The private copies of these values are pointers into shared mem */
00213     /* The copies of these values in shared memory are merely offsets */
00214     sidCacheLock    *          sidCacheLocks;
00215     sidCacheLock    *          keyCacheLock;
00216     sidCacheLock    *          certCacheLock;
00217     sidCacheSet     *          sidCacheSets;
00218     sidCacheEntry   *          sidCacheData;
00219     certCacheEntry  *          certCacheData;
00220     SSLWrappedSymWrappingKey * keyCacheData;
00221 
00222     /* Only the private copies of these pointers are valid */
00223     char *                     cacheMem;
00224     struct cacheDescStr *      sharedCache;  /* shared copy of this struct */
00225     PRFileMap *                cacheMemMap;
00226     PRThread  *                poller;
00227     PRBool                     shared;
00228 };
00229 typedef struct cacheDescStr cacheDesc;
00230 
00231 static cacheDesc globalCache;
00232 
00233 static const char envVarName[] = { SSL_ENV_VAR_NAME };
00234 
00235 static PRBool isMultiProcess  = PR_FALSE;
00236 
00237 
00238 #define DEF_SID_CACHE_ENTRIES  10000
00239 #define DEF_CERT_CACHE_ENTRIES 250
00240 #define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */
00241 #define DEF_KEY_CACHE_ENTRIES  250
00242 
00243 #define SID_CACHE_ENTRIES_PER_SET  128
00244 #define SID_ALIGNMENT          16
00245 
00246 #define DEF_SSL2_TIMEOUT    100   /* seconds */
00247 #define MAX_SSL2_TIMEOUT    100   /* seconds */
00248 #define MIN_SSL2_TIMEOUT      5   /* seconds */
00249 
00250 #define DEF_SSL3_TIMEOUT      86400L  /* 24 hours */
00251 #define MAX_SSL3_TIMEOUT      86400L  /* 24 hours */
00252 #define MIN_SSL3_TIMEOUT          5   /* seconds  */
00253 
00254 #if defined(AIX) || defined(LINUX) || defined(VMS)
00255 #define MAX_SID_CACHE_LOCKS 8      /* two FDs per lock */
00256 #elif defined(OSF1)
00257 #define MAX_SID_CACHE_LOCKS 16     /* one FD per lock */
00258 #else
00259 #define MAX_SID_CACHE_LOCKS 256
00260 #endif
00261 
00262 #define SID_HOWMANY(val, size) (((val) + ((size) - 1)) / (size))
00263 #define SID_ROUNDUP(val, size) ((size) * SID_HOWMANY((val), (size)))
00264 
00265 
00266 static sslPID myPid;
00267 static PRUint32  ssl_max_sid_cache_locks = MAX_SID_CACHE_LOCKS;
00268 
00269 /* forward static function declarations */
00270 static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, 
00271                          unsigned nl);
00272 static SECStatus LaunchLockPoller(cacheDesc *cache);
00273 
00274 
00275 struct inheritanceStr {
00276     PRUint32 cacheMemSize;
00277     PRUint32 fmStrLen;
00278 };
00279 
00280 typedef struct inheritanceStr inheritance;
00281 
00282 #if defined(_WIN32) || defined(XP_OS2)
00283 
00284 #define DEFAULT_CACHE_DIRECTORY "\\temp"
00285 
00286 #endif /* _win32 */
00287 
00288 #if defined(XP_UNIX) || defined(XP_BEOS)
00289 
00290 #define DEFAULT_CACHE_DIRECTORY "/tmp"
00291 
00292 #endif /* XP_UNIX || XP_BEOS */
00293 
00294 
00295 /************************************************************************/
00296 
00297 static PRUint32
00298 LockSidCacheLock(sidCacheLock *lock, PRUint32 now)
00299 {
00300     SECStatus      rv      = sslMutex_Lock(&lock->mutex);
00301     if (rv != SECSuccess)
00302        return 0;
00303     if (!now)
00304        now  = ssl_Time();
00305     lock->timeStamp = now;
00306     lock->pid       = myPid;
00307     return now;
00308 }
00309 
00310 static SECStatus
00311 UnlockSidCacheLock(sidCacheLock *lock)
00312 {
00313     SECStatus      rv;
00314 
00315     lock->pid = 0;
00316     rv        = sslMutex_Unlock(&lock->mutex);
00317     return rv;
00318 }
00319 
00320 /* returns the value of ssl_Time on success, zero on failure. */
00321 static PRUint32
00322 LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now)
00323 {
00324     PRUint32       lockNum = set % cache->numSIDCacheLocks;
00325     sidCacheLock * lock    = cache->sidCacheLocks + lockNum;
00326 
00327     return LockSidCacheLock(lock, now);
00328 }
00329 
00330 static SECStatus
00331 UnlockSet(cacheDesc *cache, PRUint32 set)
00332 {
00333     PRUint32       lockNum = set % cache->numSIDCacheLocks;
00334     sidCacheLock * lock    = cache->sidCacheLocks + lockNum;
00335 
00336     return UnlockSidCacheLock(lock);
00337 }
00338 
00339 /************************************************************************/
00340 
00341 
00342 /* Put a certificate in the cache.  Update the cert index in the sce.
00343 */
00344 static PRUint32
00345 CacheCert(cacheDesc * cache, CERTCertificate *cert, sidCacheEntry *sce)
00346 {
00347     PRUint32        now;
00348     certCacheEntry  cce;
00349 
00350     if ((cert->derCert.len > SSL_MAX_CACHED_CERT_LEN) ||
00351         (cert->derCert.len <= 0) ||
00352        (cert->derCert.data == NULL)) {
00353        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00354        return 0;
00355     }
00356 
00357     cce.sessionIDLength = sce->sessionIDLength;
00358     PORT_Memcpy(cce.sessionID, sce->sessionID, cce.sessionIDLength);
00359 
00360     cce.certLength = cert->derCert.len;
00361     PORT_Memcpy(cce.cert, cert->derCert.data, cce.certLength);
00362 
00363     /* get lock on cert cache */
00364     now = LockSidCacheLock(cache->certCacheLock, 0);
00365     if (now) {
00366 
00367        /* Find where to place the next cert cache entry. */
00368        cacheDesc * sharedCache = cache->sharedCache;
00369        PRUint32    ndx         = sharedCache->nextCertCacheEntry;
00370 
00371        /* write the entry */
00372        cache->certCacheData[ndx] = cce;
00373 
00374        /* remember where we put it. */
00375        sce->u.ssl3.certIndex = ndx;
00376 
00377        /* update the "next" cache entry index */
00378        sharedCache->nextCertCacheEntry = 
00379                                    (ndx + 1) % cache->numCertCacheEntries;
00380 
00381        UnlockSidCacheLock(cache->certCacheLock);
00382     }
00383     return now;
00384 
00385 }
00386 
00387 /*
00388 ** Convert local SID to shared memory one
00389 */
00390 static void 
00391 ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
00392 {
00393     to->valid   = 1;
00394     to->version = from->version;
00395     to->addr    = from->addr;
00396     to->creationTime    = from->creationTime;
00397     to->lastAccessTime  = from->lastAccessTime;
00398     to->expirationTime  = from->expirationTime;
00399     to->authAlgorithm       = from->authAlgorithm;
00400     to->authKeyBits  = from->authKeyBits;
00401     to->keaType             = from->keaType;
00402     to->keaKeyBits   = from->keaKeyBits;
00403 
00404     if (from->version < SSL_LIBRARY_VERSION_3_0) {
00405        if ((from->u.ssl2.masterKey.len > SSL_MAX_MASTER_KEY_BYTES) ||
00406            (from->u.ssl2.cipherArg.len > SSL_MAX_CYPHER_ARG_BYTES)) {
00407            SSL_DBG(("%d: SSL: masterKeyLen=%d cipherArgLen=%d",
00408                    myPid, from->u.ssl2.masterKey.len,
00409                    from->u.ssl2.cipherArg.len));
00410            to->valid = 0;
00411            return;
00412        }
00413 
00414        to->u.ssl2.cipherType    = from->u.ssl2.cipherType;
00415        to->u.ssl2.masterKeyLen  = from->u.ssl2.masterKey.len;
00416        to->u.ssl2.cipherArgLen  = from->u.ssl2.cipherArg.len;
00417        to->u.ssl2.keyBits       = from->u.ssl2.keyBits;
00418        to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
00419        to->sessionIDLength      = SSL2_SESSIONID_BYTES;
00420        PORT_Memcpy(to->sessionID, from->u.ssl2.sessionID, SSL2_SESSIONID_BYTES);
00421        PORT_Memcpy(to->u.ssl2.masterKey, from->u.ssl2.masterKey.data,
00422                 from->u.ssl2.masterKey.len);
00423        PORT_Memcpy(to->u.ssl2.cipherArg, from->u.ssl2.cipherArg.data,
00424                 from->u.ssl2.cipherArg.len);
00425 #ifdef DEBUG
00426        PORT_Memset(to->u.ssl2.masterKey+from->u.ssl2.masterKey.len, 0,
00427                 sizeof(to->u.ssl2.masterKey) - from->u.ssl2.masterKey.len);
00428        PORT_Memset(to->u.ssl2.cipherArg+from->u.ssl2.cipherArg.len, 0,
00429                 sizeof(to->u.ssl2.cipherArg) - from->u.ssl2.cipherArg.len);
00430 #endif
00431        SSL_TRC(8, ("%d: SSL: ConvertSID: masterKeyLen=%d cipherArgLen=%d "
00432                   "time=%d addr=0x%08x%08x%08x%08x cipherType=%d", myPid,
00433                   to->u.ssl2.masterKeyLen, to->u.ssl2.cipherArgLen,
00434                   to->creationTime, to->addr.pr_s6_addr32[0],
00435                   to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
00436                   to->addr.pr_s6_addr32[3], to->u.ssl2.cipherType));
00437     } else {
00438        /* This is an SSL v3 session */
00439 
00440        to->u.ssl3.cipherSuite      = from->u.ssl3.cipherSuite;
00441        to->u.ssl3.compression      = (uint16)from->u.ssl3.compression;
00442        to->u.ssl3.keys             = from->u.ssl3.keys;
00443        to->u.ssl3.masterWrapMech   = from->u.ssl3.masterWrapMech;
00444        to->u.ssl3.exchKeyType      = from->u.ssl3.exchKeyType;
00445        to->sessionIDLength         = from->u.ssl3.sessionIDLength;
00446        to->u.ssl3.certIndex        = -1;
00447 
00448        PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID,
00449                   to->sessionIDLength);
00450 
00451        SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x "
00452                    "cipherSuite=%d",
00453                   myPid, to->creationTime, to->addr.pr_s6_addr32[0],
00454                   to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
00455                   to->addr.pr_s6_addr32[3], to->u.ssl3.cipherSuite));
00456     }
00457 }
00458 
00459 /*
00460 ** Convert shared memory cache-entry to local memory based one
00461 ** This is only called from ServerSessionIDLookup().
00462 ** Caller must hold cache lock when calling this.
00463 */
00464 static sslSessionID *
00465 ConvertToSID(sidCacheEntry *from, certCacheEntry *pcce, 
00466              CERTCertDBHandle * dbHandle)
00467 {
00468     sslSessionID *to;
00469     uint16 version = from->version;
00470 
00471     to = (sslSessionID*) PORT_ZAlloc(sizeof(sslSessionID));
00472     if (!to) {
00473        return 0;
00474     }
00475 
00476     if (version < SSL_LIBRARY_VERSION_3_0) {
00477        /* This is an SSL v2 session */
00478        to->u.ssl2.masterKey.data =
00479            (unsigned char*) PORT_Alloc(from->u.ssl2.masterKeyLen);
00480        if (!to->u.ssl2.masterKey.data) {
00481            goto loser;
00482        }
00483        if (from->u.ssl2.cipherArgLen) {
00484            to->u.ssl2.cipherArg.data = 
00485               (unsigned char*)PORT_Alloc(from->u.ssl2.cipherArgLen);
00486            if (!to->u.ssl2.cipherArg.data) {
00487               goto loser;
00488            }
00489            PORT_Memcpy(to->u.ssl2.cipherArg.data, from->u.ssl2.cipherArg,
00490                       from->u.ssl2.cipherArgLen);
00491        }
00492 
00493        to->u.ssl2.cipherType    = from->u.ssl2.cipherType;
00494        to->u.ssl2.masterKey.len = from->u.ssl2.masterKeyLen;
00495        to->u.ssl2.cipherArg.len = from->u.ssl2.cipherArgLen;
00496        to->u.ssl2.keyBits       = from->u.ssl2.keyBits;
00497        to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
00498 /*     to->sessionIDLength      = SSL2_SESSIONID_BYTES; */
00499        PORT_Memcpy(to->u.ssl2.sessionID, from->sessionID, SSL2_SESSIONID_BYTES);
00500        PORT_Memcpy(to->u.ssl2.masterKey.data, from->u.ssl2.masterKey,
00501                   from->u.ssl2.masterKeyLen);
00502 
00503        SSL_TRC(8, ("%d: SSL: ConvertToSID: masterKeyLen=%d cipherArgLen=%d "
00504                   "time=%d addr=0x%08x%08x%08x%08x cipherType=%d",
00505                   myPid, to->u.ssl2.masterKey.len,
00506                   to->u.ssl2.cipherArg.len, to->creationTime,
00507                   to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1],
00508                   to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3],
00509                   to->u.ssl2.cipherType));
00510     } else {
00511        /* This is an SSL v3 session */
00512 
00513        to->u.ssl3.sessionIDLength  = from->sessionIDLength;
00514        to->u.ssl3.cipherSuite      = from->u.ssl3.cipherSuite;
00515        to->u.ssl3.compression      = (SSL3CompressionMethod)from->u.ssl3.compression;
00516        to->u.ssl3.keys             = from->u.ssl3.keys;
00517        to->u.ssl3.masterWrapMech   = from->u.ssl3.masterWrapMech;
00518        to->u.ssl3.exchKeyType      = from->u.ssl3.exchKeyType;
00519 
00520        PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength);
00521 
00522        /* the portions of the SID that are only restored on the client
00523         * are set to invalid values on the server.
00524         */
00525        to->u.ssl3.clientWriteKey   = NULL;
00526        to->u.ssl3.serverWriteKey   = NULL;
00527 
00528        to->urlSvrName              = NULL;
00529 
00530        to->u.ssl3.masterModuleID   = (SECMODModuleID)-1; /* invalid value */
00531        to->u.ssl3.masterSlotID     = (CK_SLOT_ID)-1;     /* invalid value */
00532        to->u.ssl3.masterWrapIndex  = 0;
00533        to->u.ssl3.masterWrapSeries = 0;
00534        to->u.ssl3.masterValid      = PR_FALSE;
00535 
00536        to->u.ssl3.clAuthModuleID   = (SECMODModuleID)-1; /* invalid value */
00537        to->u.ssl3.clAuthSlotID     = (CK_SLOT_ID)-1;     /* invalid value */
00538        to->u.ssl3.clAuthSeries     = 0;
00539        to->u.ssl3.clAuthValid      = PR_FALSE;
00540 
00541        if (from->u.ssl3.certIndex != -1 && pcce) {
00542            SECItem          derCert;
00543 
00544            derCert.len  = pcce->certLength;
00545            derCert.data = pcce->cert;
00546 
00547            to->peerCert = CERT_NewTempCertificate(dbHandle, &derCert, NULL,
00548                                               PR_FALSE, PR_TRUE);
00549            if (to->peerCert == NULL)
00550               goto loser;
00551        }
00552     }
00553 
00554     to->version         = from->version;
00555     to->creationTime    = from->creationTime;
00556     to->lastAccessTime  = from->lastAccessTime;
00557     to->expirationTime  = from->expirationTime;
00558     to->cached          = in_server_cache;
00559     to->addr            = from->addr;
00560     to->references      = 1;
00561     to->authAlgorithm       = from->authAlgorithm;
00562     to->authKeyBits  = from->authKeyBits;
00563     to->keaType             = from->keaType;
00564     to->keaKeyBits   = from->keaKeyBits;
00565     
00566     return to;
00567 
00568   loser:
00569     if (to) {
00570        if (version < SSL_LIBRARY_VERSION_3_0) {
00571            if (to->u.ssl2.masterKey.data)
00572               PORT_Free(to->u.ssl2.masterKey.data);
00573            if (to->u.ssl2.cipherArg.data)
00574               PORT_Free(to->u.ssl2.cipherArg.data);
00575        }
00576        PORT_Free(to);
00577     }
00578     return NULL;
00579 }
00580 
00581 
00582 
00583 /*
00584 ** Perform some mumbo jumbo on the ip-address and the session-id value to
00585 ** compute a hash value.
00586 */
00587 static PRUint32 
00588 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl)
00589 {
00590     PRUint32 rv;
00591     PRUint32 x[8];
00592 
00593     memset(x, 0, sizeof x);
00594     if (nl > sizeof x)
00595        nl = sizeof x;
00596     memcpy(x, s, nl);
00597 
00598     rv = (addr->pr_s6_addr32[0] ^ addr->pr_s6_addr32[1] ^
00599          addr->pr_s6_addr32[2] ^ addr->pr_s6_addr32[3] ^
00600           x[0] ^ x[1] ^ x[2] ^ x[3] ^ x[4] ^ x[5] ^ x[6] ^ x[7])
00601          % cache->numSIDCacheSets;
00602     return rv;
00603 }
00604 
00605 
00606 
00607 /*
00608 ** Look something up in the cache. This will invalidate old entries
00609 ** in the process. Caller has locked the cache set!
00610 ** Returns PR_TRUE if found a valid match.  PR_FALSE otherwise.
00611 */
00612 static sidCacheEntry *
00613 FindSID(cacheDesc *cache, PRUint32 setNum, PRUint32 now,
00614         const PRIPv6Addr *addr, unsigned char *sessionID,
00615        unsigned sessionIDLength)
00616 {
00617     PRUint32      ndx   = cache->sidCacheSets[setNum].next;
00618     int           i;
00619 
00620     sidCacheEntry * set = cache->sidCacheData + 
00621                       (setNum * SID_CACHE_ENTRIES_PER_SET);
00622 
00623     for (i = SID_CACHE_ENTRIES_PER_SET; i > 0; --i) {
00624        sidCacheEntry * sce;
00625 
00626        ndx  = (ndx - 1) % SID_CACHE_ENTRIES_PER_SET;
00627        sce = set + ndx;
00628 
00629        if (!sce->valid)
00630            continue;
00631 
00632        if (now > sce->expirationTime) {
00633            /* SessionID has timed out. Invalidate the entry. */
00634            SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x "
00635                      "time+=%x",
00636                      myPid, sce->addr.pr_s6_addr32[0],
00637                      sce->addr.pr_s6_addr32[1], sce->addr.pr_s6_addr32[2],
00638                      sce->addr.pr_s6_addr32[3], now,
00639                      sce->expirationTime ));
00640            sce->valid = 0;
00641            continue;
00642        }
00643 
00644        /*
00645        ** Next, examine specific session-id/addr data to see if the cache
00646        ** entry matches our addr+session-id value
00647        */
00648        if (sessionIDLength == sce->sessionIDLength      &&
00649            !memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) &&
00650            !memcmp(sce->sessionID, sessionID, sessionIDLength)) {
00651            /* Found it */
00652            return sce;
00653        }
00654     }
00655 
00656     PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
00657     return NULL;
00658 }
00659 
00660 /************************************************************************/
00661 
00662 /* This is the primary function for finding entries in the server's sid cache.
00663  * Although it is static, this function is called via the global function 
00664  * pointer ssl_sid_lookup.
00665  */
00666 static sslSessionID *
00667 ServerSessionIDLookup(const PRIPv6Addr *addr,
00668                      unsigned char *sessionID,
00669                      unsigned int   sessionIDLength,
00670                         CERTCertDBHandle * dbHandle)
00671 {
00672     sslSessionID *  sid      = 0;
00673     sidCacheEntry * psce;
00674     certCacheEntry *pcce     = 0;
00675     cacheDesc *     cache    = &globalCache;
00676     PRUint32        now;
00677     PRUint32        set;
00678     PRInt32         cndx;
00679     sidCacheEntry   sce;
00680     certCacheEntry  cce;
00681 
00682     set = SIDindex(cache, addr, sessionID, sessionIDLength);
00683     now = LockSet(cache, set, 0);
00684     if (!now)
00685        return NULL;
00686 
00687     psce = FindSID(cache, set, now, addr, sessionID, sessionIDLength);
00688     if (psce) {
00689        if (psce->version >= SSL_LIBRARY_VERSION_3_0 && 
00690            (cndx = psce->u.ssl3.certIndex) != -1) {
00691 
00692            PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now);
00693            if (gotLock) {
00694               pcce = &cache->certCacheData[cndx];
00695 
00696               /* See if the cert's session ID matches the sce cache. */
00697               if ((pcce->sessionIDLength == psce->sessionIDLength) &&
00698                   !PORT_Memcmp(pcce->sessionID, psce->sessionID, 
00699                                pcce->sessionIDLength)) {
00700                   cce = *pcce;
00701               } else {
00702                   /* The cert doesen't match the SID cache entry, 
00703                   ** so invalidate the SID cache entry. 
00704                   */
00705                   psce->valid = 0;
00706                   psce = 0;
00707                   pcce = 0;
00708               }
00709               UnlockSidCacheLock(cache->certCacheLock);
00710            } else {
00711               /* what the ??.  Didn't get the cert cache lock.
00712               ** Don't invalidate the SID cache entry, but don't find it.
00713               */
00714               PORT_Assert(!("Didn't get cert Cache Lock!"));
00715               psce = 0;
00716               pcce = 0;
00717            }
00718        }
00719        if (psce) {
00720            psce->lastAccessTime = now;
00721            sce = *psce;     /* grab a copy while holding the lock */
00722        }
00723     }
00724     UnlockSet(cache, set);
00725     if (psce) {
00726        /* sce conains a copy of the cache entry.
00727        ** Convert shared memory format to local format 
00728        */
00729        sid = ConvertToSID(&sce, pcce ? &cce : 0, dbHandle);
00730     }
00731     return sid;
00732 }
00733 
00734 /*
00735 ** Place a sid into the cache, if it isn't already there. 
00736 */
00737 static void 
00738 ServerSessionIDCache(sslSessionID *sid)
00739 {
00740     sidCacheEntry sce;
00741     PRUint32      now     = 0;
00742     uint16        version = sid->version;
00743     cacheDesc *   cache   = &globalCache;
00744 
00745     if ((version >= SSL_LIBRARY_VERSION_3_0) &&
00746        (sid->u.ssl3.sessionIDLength == 0)) {
00747        return;
00748     }
00749 
00750     if (sid->cached == never_cached || sid->cached == invalid_cache) {
00751        PRUint32 set;
00752 
00753        PORT_Assert(sid->creationTime != 0);
00754        if (!sid->creationTime)
00755            sid->lastAccessTime = sid->creationTime = ssl_Time();
00756        if (version < SSL_LIBRARY_VERSION_3_0) {
00757            /* override caller's expiration time, which uses client timeout
00758             * duration, not server timeout duration.
00759             */
00760            sid->expirationTime = sid->creationTime + cache->ssl2Timeout;
00761            SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
00762                      "cipher=%d", myPid, sid->cached,
00763                      sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
00764                      sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
00765                      sid->creationTime, sid->u.ssl2.cipherType));
00766            PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID,
00767                        SSL2_SESSIONID_BYTES));
00768            PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
00769                        sid->u.ssl2.masterKey.len));
00770            PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
00771                        sid->u.ssl2.cipherArg.len));
00772 
00773        } else {
00774            /* override caller's expiration time, which uses client timeout
00775             * duration, not server timeout duration.
00776             */
00777            sid->expirationTime = sid->creationTime + cache->ssl3Timeout;
00778            SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
00779                      "cipherSuite=%d", myPid, sid->cached,
00780                      sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
00781                      sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
00782                      sid->creationTime, sid->u.ssl3.cipherSuite));
00783            PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID,
00784                        sid->u.ssl3.sessionIDLength));
00785        }
00786 
00787        ConvertFromSID(&sce, sid);
00788 
00789        if ((version >= SSL_LIBRARY_VERSION_3_0) && 
00790            (sid->peerCert != NULL)) {
00791            now = CacheCert(cache, sid->peerCert, &sce);
00792        }
00793 
00794        set = SIDindex(cache, &sce.addr, sce.sessionID, sce.sessionIDLength);
00795        now = LockSet(cache, set, now);
00796        if (now) {
00797            PRUint32  next = cache->sidCacheSets[set].next;
00798            PRUint32  ndx  = set * SID_CACHE_ENTRIES_PER_SET + next;
00799 
00800            /* Write out new cache entry */
00801            cache->sidCacheData[ndx] = sce;
00802 
00803            cache->sidCacheSets[set].next = 
00804                                    (next + 1) % SID_CACHE_ENTRIES_PER_SET;
00805 
00806            UnlockSet(cache, set);
00807            sid->cached = in_server_cache;
00808        }
00809     }
00810 }
00811 
00812 /*
00813 ** Although this is static, it is called from ssl via global function pointer
00814 **     ssl_sid_uncache.  This invalidates the referenced cache entry.
00815 */
00816 static void 
00817 ServerSessionIDUncache(sslSessionID *sid)
00818 {
00819     cacheDesc *    cache   = &globalCache;
00820     PRUint8 *      sessionID;
00821     unsigned int   sessionIDLength;
00822     PRErrorCode    err;
00823     PRUint32       set;
00824     PRUint32       now;
00825     sidCacheEntry *psce;
00826 
00827     if (sid == NULL) 
00828        return;
00829     
00830     /* Uncaching a SID should never change the error code. 
00831     ** So save it here and restore it before exiting.
00832     */
00833     err = PR_GetError();
00834 
00835     if (sid->version < SSL_LIBRARY_VERSION_3_0) {
00836        sessionID       = sid->u.ssl2.sessionID;
00837        sessionIDLength = SSL2_SESSIONID_BYTES;
00838        SSL_TRC(8, ("%d: SSL: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
00839                   "cipher=%d", myPid, sid->cached,
00840                   sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
00841                   sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
00842                   sid->creationTime, sid->u.ssl2.cipherType));
00843        PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
00844        PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
00845                     sid->u.ssl2.masterKey.len));
00846        PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
00847                     sid->u.ssl2.cipherArg.len));
00848     } else {
00849        sessionID       = sid->u.ssl3.sessionID;
00850        sessionIDLength = sid->u.ssl3.sessionIDLength;
00851        SSL_TRC(8, ("%d: SSL3: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
00852                   "cipherSuite=%d", myPid, sid->cached,
00853                   sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
00854                   sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
00855                   sid->creationTime, sid->u.ssl3.cipherSuite));
00856        PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
00857     }
00858     set = SIDindex(cache, &sid->addr, sessionID, sessionIDLength);
00859     now = LockSet(cache, set, 0);
00860     if (now) {
00861        psce = FindSID(cache, set, now, &sid->addr, sessionID, sessionIDLength);
00862        if (psce) {
00863            psce->valid = 0;
00864        }
00865        UnlockSet(cache, set);
00866     }
00867     sid->cached = invalid_cache;
00868     PORT_SetError(err);
00869 }
00870 
00871 #ifdef XP_OS2
00872 
00873 #define INCL_DOSPROCESS
00874 #include <os2.h>
00875 
00876 long gettid(void)
00877 {
00878     PTIB ptib;
00879     PPIB ppib;
00880     DosGetInfoBlocks(&ptib, &ppib);
00881     return ((long)ptib->tib_ordinal); /* thread id */
00882 }
00883 #endif
00884 
00885 static void
00886 CloseCache(cacheDesc *cache)
00887 {
00888     int locks_initialized = cache->numSIDCacheLocksInitialized;
00889 
00890     if (cache->cacheMem) {
00891        /* If everInherited is true, this shared cache was (and may still
00892        ** be) in use by multiple processes.  We do not wish to destroy
00893        ** the mutexes while they are still in use.  
00894        */
00895        if (cache->sharedCache &&
00896             PR_FALSE == cache->sharedCache->everInherited) {
00897            sidCacheLock *pLock = cache->sidCacheLocks;
00898            for (; locks_initialized > 0; --locks_initialized, ++pLock ) {
00899               sslMutex_Destroy(&pLock->mutex);
00900            }
00901        }
00902        if (cache->shared) {
00903            PR_MemUnmap(cache->cacheMem, cache->cacheMemSize);
00904        } else {
00905            PORT_Free(cache->cacheMem);
00906        }
00907        cache->cacheMem = NULL;
00908     }
00909     if (cache->cacheMemMap) {
00910        PR_CloseFileMap(cache->cacheMemMap);
00911        cache->cacheMemMap = NULL;
00912     }
00913     memset(cache, 0, sizeof *cache);
00914 }
00915 
00916 static SECStatus
00917 InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout, 
00918           PRUint32 ssl3_timeout, const char *directory, PRBool shared)
00919 {
00920     ptrdiff_t     ptr;
00921     sidCacheLock *pLock;
00922     char *        cacheMem;
00923     PRFileMap *   cacheMemMap;
00924     char *        cfn = NULL;      /* cache file name */
00925     int           locks_initialized = 0;
00926     int           locks_to_initialize = 0;
00927     PRUint32      init_time;
00928 
00929     if ( (!cache) || (maxCacheEntries < 0) || (!directory) ) {
00930         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00931         return SECFailure;
00932     }
00933 
00934     if (cache->cacheMem) {
00935        /* Already done */
00936        return SECSuccess;
00937     }
00938 
00939     /* make sure loser can clean up properly */
00940     cache->shared = shared;
00941     cache->cacheMem    = cacheMem    = NULL;
00942     cache->cacheMemMap = cacheMemMap = NULL;
00943     cache->sharedCache = (cacheDesc *)0;
00944 
00945     cache->numSIDCacheLocksInitialized = 0;
00946     cache->nextCertCacheEntry = 0;
00947     cache->stopPolling = PR_FALSE;
00948     cache->everInherited = PR_FALSE;
00949     cache->poller = NULL;
00950 
00951     cache->numSIDCacheEntries = maxCacheEntries ? maxCacheEntries 
00952                                                 : DEF_SID_CACHE_ENTRIES;
00953     cache->numSIDCacheSets    = 
00954        SID_HOWMANY(cache->numSIDCacheEntries, SID_CACHE_ENTRIES_PER_SET);
00955 
00956     cache->numSIDCacheEntries = 
00957        cache->numSIDCacheSets * SID_CACHE_ENTRIES_PER_SET;
00958 
00959     cache->numSIDCacheLocks   = 
00960        PR_MIN(cache->numSIDCacheSets, ssl_max_sid_cache_locks);
00961 
00962     cache->numSIDCacheSetsPerLock = 
00963        SID_HOWMANY(cache->numSIDCacheSets, cache->numSIDCacheLocks);
00964 
00965     /* compute size of shared memory, and offsets of all pointers */
00966     ptr = 0;
00967     cache->cacheMem     = (char *)ptr;
00968     ptr += SID_ROUNDUP(sizeof(cacheDesc), SID_ALIGNMENT);
00969 
00970     cache->sidCacheLocks = (sidCacheLock *)ptr;
00971     cache->keyCacheLock  = cache->sidCacheLocks + cache->numSIDCacheLocks;
00972     cache->certCacheLock = cache->keyCacheLock  + 1;
00973     ptr = (ptrdiff_t)(cache->certCacheLock + 1);
00974     ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
00975 
00976     cache->sidCacheSets  = (sidCacheSet *)ptr;
00977     ptr = (ptrdiff_t)(cache->sidCacheSets + cache->numSIDCacheSets);
00978     ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
00979 
00980     cache->sidCacheData  = (sidCacheEntry *)ptr;
00981     ptr = (ptrdiff_t)(cache->sidCacheData + cache->numSIDCacheEntries);
00982     ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
00983 
00984     cache->certCacheData = (certCacheEntry *)ptr;
00985     cache->sidCacheSize  = 
00986        (char *)cache->certCacheData - (char *)cache->sidCacheData;
00987 
00988     /* This is really a poor way to computer this! */
00989     cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry);
00990     if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES)
00991        cache->numCertCacheEntries = MIN_CERT_CACHE_ENTRIES;
00992     ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries);
00993     ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
00994 
00995     cache->keyCacheData  = (SSLWrappedSymWrappingKey *)ptr;
00996     cache->certCacheSize = 
00997        (char *)cache->keyCacheData - (char *)cache->certCacheData;
00998 
00999     cache->numKeyCacheEntries = kt_kea_size * SSL_NUM_WRAP_MECHS;
01000     ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries);
01001     ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
01002 
01003     cache->cacheMemSize = ptr;
01004 
01005     cache->keyCacheSize  = (char *)ptr - (char *)cache->keyCacheData;
01006 
01007     if (ssl2_timeout) {   
01008        if (ssl2_timeout > MAX_SSL2_TIMEOUT) {
01009            ssl2_timeout = MAX_SSL2_TIMEOUT;
01010        }
01011        if (ssl2_timeout < MIN_SSL2_TIMEOUT) {
01012            ssl2_timeout = MIN_SSL2_TIMEOUT;
01013        }
01014        cache->ssl2Timeout = ssl2_timeout;
01015     } else {
01016        cache->ssl2Timeout = DEF_SSL2_TIMEOUT;
01017     }
01018 
01019     if (ssl3_timeout) {   
01020        if (ssl3_timeout > MAX_SSL3_TIMEOUT) {
01021            ssl3_timeout = MAX_SSL3_TIMEOUT;
01022        }
01023        if (ssl3_timeout < MIN_SSL3_TIMEOUT) {
01024            ssl3_timeout = MIN_SSL3_TIMEOUT;
01025        }
01026        cache->ssl3Timeout = ssl3_timeout;
01027     } else {
01028        cache->ssl3Timeout = DEF_SSL3_TIMEOUT;
01029     }
01030 
01031     if (shared) {
01032        /* Create file names */
01033 #if defined(XP_UNIX) || defined(XP_BEOS)
01034        /* there's some confusion here about whether PR_OpenAnonFileMap wants
01035        ** a directory name or a file name for its first argument.
01036        cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid);
01037        */
01038        cfn = PR_smprintf("%s", directory);
01039 #elif defined(XP_WIN32)
01040        cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, 
01041                          GetCurrentThreadId());
01042 #elif defined(XP_OS2)
01043        cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, 
01044                          gettid());
01045 #else
01046 #error "Don't know how to create file name for this platform!"
01047 #endif
01048        if (!cfn) {
01049            goto loser;
01050        }
01051 
01052        /* Create cache */
01053        cacheMemMap = PR_OpenAnonFileMap(cfn, cache->cacheMemSize, 
01054                                     PR_PROT_READWRITE);
01055 
01056        PR_smprintf_free(cfn);
01057        if(!cacheMemMap) {
01058            goto loser;
01059        }
01060 
01061         cacheMem = PR_MemMap(cacheMemMap, 0, cache->cacheMemSize);
01062     } else {
01063         cacheMem = PORT_Alloc(cache->cacheMemSize);
01064     }
01065     
01066     if (! cacheMem) {
01067         goto loser;
01068     }
01069 
01070     /* Initialize shared memory. This may not be necessary on all platforms */
01071     memset(cacheMem, 0, cache->cacheMemSize);
01072 
01073     /* Copy cache descriptor header into shared memory */
01074     memcpy(cacheMem, cache, sizeof *cache);
01075 
01076     /* save private copies of these values */
01077     cache->cacheMemMap = cacheMemMap;
01078     cache->cacheMem    = cacheMem;
01079     cache->sharedCache = (cacheDesc *)cacheMem;
01080 
01081     /* Fix pointers in our private copy of cache descriptor to point to 
01082     ** spaces in shared memory 
01083     */
01084     ptr = (ptrdiff_t)cache->cacheMem;
01085     *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
01086     *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
01087     *(ptrdiff_t *)(&cache->certCacheLock) += ptr;
01088     *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
01089     *(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
01090     *(ptrdiff_t *)(&cache->certCacheData) += ptr;
01091     *(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
01092 
01093     /* initialize the locks */
01094     init_time = ssl_Time();
01095     pLock = cache->sidCacheLocks;
01096     for (locks_to_initialize = cache->numSIDCacheLocks + 2;
01097          locks_initialized < locks_to_initialize; 
01098         ++locks_initialized, ++pLock ) {
01099 
01100        SECStatus err = sslMutex_Init(&pLock->mutex, shared);
01101        if (err) {
01102            cache->numSIDCacheLocksInitialized = locks_initialized;
01103            goto loser;
01104        }
01105         pLock->timeStamp = init_time;
01106        pLock->pid       = 0;
01107     }
01108     cache->numSIDCacheLocksInitialized = locks_initialized;
01109 
01110     return SECSuccess;
01111 
01112 loser:
01113     CloseCache(cache);
01114     return SECFailure;
01115 }
01116 
01117 PRUint32
01118 SSL_GetMaxServerCacheLocks(void)
01119 {
01120     return ssl_max_sid_cache_locks + 2;
01121     /* The extra two are the cert cache lock and the key cache lock. */
01122 }
01123 
01124 SECStatus
01125 SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
01126 {
01127     /* Minimum is 1 sid cache lock, 1 cert cache lock and 1 key cache lock.
01128     ** We'd like to test for a maximum value, but not all platforms' header
01129     ** files provide a symbol or function or other means of determining
01130     ** the maximum, other than trial and error.
01131     */
01132     if (maxLocks < 3) {
01133        PORT_SetError(SEC_ERROR_INVALID_ARGS);
01134        return SECFailure;
01135     }
01136     ssl_max_sid_cache_locks = maxLocks - 2;
01137     /* The extra two are the cert cache lock and the key cache lock. */
01138     return SECSuccess;
01139 }
01140 
01141 SECStatus
01142 SSL_ConfigServerSessionIDCacheInstance(   cacheDesc *cache,
01143                                 int      maxCacheEntries, 
01144                             PRUint32 ssl2_timeout,
01145                                    PRUint32 ssl3_timeout, 
01146                        const char *   directory, PRBool shared)
01147 {
01148     SECStatus rv;
01149 
01150 #if defined(DEBUG_nelsonb)
01151     printf("sizeof(sidCacheEntry) == %u\n", sizeof(sidCacheEntry));
01152 #endif
01153 #if !(defined(SOLARIS) && defined(i386))
01154 #ifndef XP_OS2
01155     PORT_Assert(sizeof(sidCacheEntry) % 8 == 0);
01156 #endif
01157 #endif
01158     PORT_Assert(sizeof(certCacheEntry) == 4096);
01159 
01160     myPid = SSL_GETPID();
01161     if (!directory) {
01162        directory = DEFAULT_CACHE_DIRECTORY;
01163     }
01164     rv = InitCache(cache, maxCacheEntries, ssl2_timeout, ssl3_timeout, 
01165                    directory, shared);
01166     if (rv) {
01167        SET_ERROR_CODE
01168        return SECFailure;
01169     }
01170 
01171     ssl_sid_lookup  = ServerSessionIDLookup;
01172     ssl_sid_cache   = ServerSessionIDCache;
01173     ssl_sid_uncache = ServerSessionIDUncache;
01174     return SECSuccess;
01175 }
01176 
01177 SECStatus
01178 SSL_ConfigServerSessionIDCache(    int      maxCacheEntries, 
01179                             PRUint32 ssl2_timeout,
01180                                    PRUint32 ssl3_timeout, 
01181                        const char *   directory)
01182 {
01183     ssl_InitClientSessionCacheLock();
01184     ssl_InitSymWrapKeysLock();
01185     return SSL_ConfigServerSessionIDCacheInstance(&globalCache, 
01186               maxCacheEntries, ssl2_timeout, ssl3_timeout, directory, PR_FALSE);
01187 }
01188 
01189 SECStatus
01190 SSL_ShutdownServerSessionIDCacheInstance(cacheDesc *cache)
01191 {
01192     CloseCache(cache);
01193     return SECSuccess;
01194 }
01195 
01196 SECStatus
01197 SSL_ShutdownServerSessionIDCache(void)
01198 {
01199     SSL3_ShutdownServerCache();
01200     return SSL_ShutdownServerSessionIDCacheInstance(&globalCache);
01201 }
01202 
01203 /* Use this function, instead of SSL_ConfigServerSessionIDCache,
01204  * if the cache will be shared by multiple processes.
01205  */
01206 SECStatus
01207 SSL_ConfigMPServerSIDCache( int      maxCacheEntries, 
01208                             PRUint32 ssl2_timeout,
01209                                    PRUint32 ssl3_timeout, 
01210                         const char *   directory)
01211 {
01212     char *    envValue;
01213     char *    inhValue;
01214     cacheDesc * cache         = &globalCache;
01215     PRUint32    fmStrLen;
01216     SECStatus        result;
01217     PRStatus  prStatus;
01218     SECStatus putEnvFailed;
01219     inheritance inherit;
01220     char        fmString[PR_FILEMAP_STRING_BUFSIZE];
01221 
01222     isMultiProcess = PR_TRUE;
01223     result = SSL_ConfigServerSessionIDCacheInstance(cache, maxCacheEntries, 
01224                      ssl2_timeout, ssl3_timeout, directory, PR_TRUE);
01225     if (result != SECSuccess) 
01226         return result;
01227 
01228     prStatus = PR_ExportFileMapAsString(cache->cacheMemMap, 
01229                                         sizeof fmString, fmString);
01230     if ((prStatus != PR_SUCCESS) || !(fmStrLen = strlen(fmString))) {
01231        SET_ERROR_CODE
01232        return SECFailure;
01233     }
01234 
01235     inherit.cacheMemSize    = cache->cacheMemSize;
01236     inherit.fmStrLen            = fmStrLen;
01237 
01238     inhValue = BTOA_DataToAscii((unsigned char *)&inherit, sizeof inherit);
01239     if (!inhValue || !strlen(inhValue)) {
01240        SET_ERROR_CODE
01241        return SECFailure;
01242     }
01243     envValue = PR_smprintf("%s,%s", inhValue, fmString);
01244     if (!envValue || !strlen(envValue)) {
01245        SET_ERROR_CODE
01246        return SECFailure;
01247     }
01248     PORT_Free(inhValue);
01249 
01250     putEnvFailed = (SECStatus)NSS_PutEnv(envVarName, envValue);
01251     PR_smprintf_free(envValue);
01252     if (putEnvFailed) {
01253         SET_ERROR_CODE
01254         result = SECFailure;
01255     }
01256 
01257 #if defined(XP_UNIX) || defined(XP_BEOS)
01258     /* Launch thread to poll cache for expired locks on Unix */
01259     LaunchLockPoller(cache);
01260 #endif
01261     return result;
01262 }
01263 
01264 SECStatus
01265 SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
01266 {
01267     unsigned char * decoString = NULL;
01268     char *          fmString   = NULL;
01269     char *          myEnvString = NULL;
01270     unsigned int    decoLen;
01271     ptrdiff_t       ptr;
01272     inheritance     inherit;
01273     cacheDesc       my;
01274 #ifdef WINNT
01275     sidCacheLock* newLocks;
01276     int           locks_initialized = 0;
01277     int           locks_to_initialize = 0;
01278 #endif
01279 
01280     myPid = SSL_GETPID();
01281 
01282     /* If this child was created by fork(), and not by exec() on unix,
01283     ** then isMultiProcess will already be set.
01284     ** If not, we'll set it below.
01285     */
01286     if (isMultiProcess) {
01287        if (cache && cache->sharedCache) {
01288            cache->sharedCache->everInherited = PR_TRUE;
01289        }
01290        return SECSuccess;   /* already done. */
01291     }
01292 
01293     ssl_InitClientSessionCacheLock();
01294     ssl_InitSymWrapKeysLock();
01295 
01296     ssl_sid_lookup  = ServerSessionIDLookup;
01297     ssl_sid_cache   = ServerSessionIDCache;
01298     ssl_sid_uncache = ServerSessionIDUncache;
01299 
01300     if (!envString) {
01301        envString  = getenv(envVarName);
01302        if (!envString) {
01303            SET_ERROR_CODE
01304            return SECFailure;
01305        }
01306     }
01307     myEnvString = PORT_Strdup(envString);
01308     if (!myEnvString) 
01309        return SECFailure;
01310     fmString = strchr(myEnvString, ',');
01311     if (!fmString) 
01312        goto loser;
01313     *fmString++ = 0;
01314 
01315     decoString = ATOB_AsciiToData(myEnvString, &decoLen);
01316     if (!decoString) {
01317        SET_ERROR_CODE
01318        goto loser;
01319     }
01320     if (decoLen != sizeof inherit) {
01321        SET_ERROR_CODE
01322        goto loser;
01323     }
01324 
01325     PORT_Memcpy(&inherit, decoString, sizeof inherit);
01326 
01327     if (strlen(fmString)  != inherit.fmStrLen ) {
01328        goto loser;
01329     }
01330 
01331     memset(cache, 0, sizeof *cache);
01332     cache->cacheMemSize     = inherit.cacheMemSize;
01333 
01334     /* Create cache */
01335     cache->cacheMemMap = PR_ImportFileMapFromString(fmString);
01336     if(! cache->cacheMemMap) {
01337        goto loser;
01338     }
01339     cache->cacheMem = PR_MemMap(cache->cacheMemMap, 0, cache->cacheMemSize);
01340     if (! cache->cacheMem) {
01341        goto loser;
01342     }
01343     cache->sharedCache   = (cacheDesc *)cache->cacheMem;
01344 
01345     if (cache->sharedCache->cacheMemSize != cache->cacheMemSize) {
01346        SET_ERROR_CODE
01347        goto loser;
01348     }
01349 
01350     /* We're now going to overwrite the local cache instance with the 
01351     ** shared copy of the cache struct, then update several values in 
01352     ** the local cache using the values for cache->cacheMemMap and 
01353     ** cache->cacheMem computed just above.  So, we copy cache into 
01354     ** the automatic variable "my", to preserve the variables while
01355     ** cache is overwritten.
01356     */
01357     my = *cache;  /* save values computed above. */
01358     memcpy(cache, cache->sharedCache, sizeof *cache); /* overwrite */
01359 
01360     /* Fix pointers in our private copy of cache descriptor to point to 
01361     ** spaces in shared memory, whose address is now in "my".
01362     */
01363     ptr = (ptrdiff_t)my.cacheMem;
01364     *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
01365     *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
01366     *(ptrdiff_t *)(&cache->certCacheLock) += ptr;
01367     *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
01368     *(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
01369     *(ptrdiff_t *)(&cache->certCacheData) += ptr;
01370     *(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
01371 
01372     cache->cacheMemMap = my.cacheMemMap;
01373     cache->cacheMem    = my.cacheMem;
01374     cache->sharedCache = (cacheDesc *)cache->cacheMem;
01375 
01376 #ifdef WINNT
01377     /*  On Windows NT we need to "fix" the sidCacheLocks here to support fibers
01378     **  When NT fibers are used in a multi-process server, a second level of
01379     **  locking is needed to prevent a deadlock, in case a fiber acquires the
01380     **  cross-process mutex, yields, and another fiber is later scheduled on
01381     **  the same native thread and tries to acquire the cross-process mutex.
01382     **  We do this by using a PRLock in the sslMutex. However, it is stored in
01383     **  shared memory as part of sidCacheLocks, and we don't want to overwrite
01384     **  the PRLock of the parent process. So we need to make new, private
01385     **  copies of sidCacheLocks before modifying the sslMutex with our own
01386     **  PRLock
01387     */
01388     
01389     /* note from jpierre : this should be free'd in child processes when
01390     ** a function is added to delete the SSL session cache in the future. 
01391     */
01392     locks_to_initialize = cache->numSIDCacheLocks + 2;
01393     newLocks = PORT_NewArray(sidCacheLock, locks_to_initialize);
01394     if (!newLocks)
01395        goto loser;
01396     /* copy the old locks */
01397     memcpy(newLocks, cache->sidCacheLocks, 
01398            locks_to_initialize * sizeof(sidCacheLock));
01399     cache->sidCacheLocks = newLocks;
01400     /* fix the locks */            
01401     for (; locks_initialized < locks_to_initialize; ++locks_initialized) {
01402         /* now, make a local PRLock in this sslMutex for this child process */
01403        SECStatus err;
01404         err = sslMutex_2LevelInit(&newLocks[locks_initialized].mutex);
01405        if (err != SECSuccess) {
01406            cache->numSIDCacheLocksInitialized = locks_initialized;
01407            goto loser;
01408        }
01409     }
01410     cache->numSIDCacheLocksInitialized = locks_initialized;
01411 
01412     /* also fix the key and cert cache which use the last 2 lock entries */
01413     cache->keyCacheLock  = cache->sidCacheLocks + cache->numSIDCacheLocks;
01414     cache->certCacheLock = cache->keyCacheLock  + 1;
01415 #endif
01416 
01417     PORT_Free(myEnvString);
01418     PORT_Free(decoString);
01419 
01420     /* mark that we have inherited this. */
01421     cache->sharedCache->everInherited = PR_TRUE;
01422     isMultiProcess = PR_TRUE;
01423 
01424     return SECSuccess;
01425 
01426 loser:
01427     PORT_Free(myEnvString);
01428     if (decoString) 
01429        PORT_Free(decoString);
01430     CloseCache(cache);
01431     return SECFailure;
01432 }
01433 
01434 SECStatus
01435 SSL_InheritMPServerSIDCache(const char * envString)
01436 {
01437     return SSL_InheritMPServerSIDCacheInstance(&globalCache, envString);
01438 }
01439 
01440 #if defined(XP_UNIX) || defined(XP_BEOS)
01441 
01442 #define SID_LOCK_EXPIRATION_TIMEOUT  30 /* seconds */
01443 
01444 static void
01445 LockPoller(void * arg)
01446 {
01447     cacheDesc *    cache         = (cacheDesc *)arg;
01448     cacheDesc *    sharedCache   = cache->sharedCache;
01449     sidCacheLock * pLock;
01450     const char *   timeoutString;
01451     PRIntervalTime timeout;
01452     PRUint32       now;
01453     PRUint32       then;
01454     int            locks_polled  = 0;
01455     int            locks_to_poll = cache->numSIDCacheLocks + 2;
01456     PRUint32       expiration    = SID_LOCK_EXPIRATION_TIMEOUT;
01457 
01458     timeoutString = getenv("NSS_SSL_SERVER_CACHE_MUTEX_TIMEOUT");
01459     if (timeoutString) {
01460        long newTime = strtol(timeoutString, 0, 0);
01461        if (newTime == 0) 
01462            return;  /* application doesn't want this function */
01463        if (newTime > 0)
01464            expiration = (PRUint32)newTime;
01465        /* if error (newTime < 0) ignore it and use default */
01466     }
01467 
01468     timeout = PR_SecondsToInterval(expiration);
01469     while(!sharedCache->stopPolling) {
01470        PR_Sleep(timeout);
01471        if (sharedCache->stopPolling)
01472            break;
01473 
01474        now   = ssl_Time();
01475        then  = now - expiration;
01476        for (pLock = cache->sidCacheLocks, locks_polled = 0;
01477             locks_to_poll > locks_polled && !sharedCache->stopPolling; 
01478             ++locks_polled, ++pLock ) {
01479            pid_t pid;
01480 
01481            if (pLock->timeStamp   < then && 
01482                pLock->timeStamp   != 0 && 
01483               (pid = pLock->pid) != 0) {
01484 
01485               /* maybe we should try the lock? */
01486               int result = kill(pid, 0);
01487               if (result < 0 && errno == ESRCH) {
01488                   SECStatus rv;
01489                   /* No process exists by that pid any more.
01490                   ** Treat this mutex as abandoned.
01491                   */
01492                   pLock->timeStamp = now;
01493                   pLock->pid       = 0;
01494                   rv = sslMutex_Unlock(&pLock->mutex);
01495                   if (rv != SECSuccess) {
01496                      /* Now what? */
01497                   }
01498               }
01499            }
01500        } /* end of loop over locks */
01501     } /* end of entire polling loop */
01502 }
01503 
01504 /* Launch thread to poll cache for expired locks */
01505 static SECStatus 
01506 LaunchLockPoller(cacheDesc *cache)
01507 {
01508     PRThread * pollerThread;
01509 
01510     pollerThread = 
01511        PR_CreateThread(PR_USER_THREAD, LockPoller, cache, PR_PRIORITY_NORMAL, 
01512                        PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
01513     if (!pollerThread) {
01514        return SECFailure;
01515     }
01516     cache->poller = pollerThread;
01517     return SECSuccess;
01518 }
01519 #endif
01520 
01521 /************************************************************************
01522  *  Code dealing with shared wrapped symmetric wrapping keys below      *
01523  ************************************************************************/
01524 
01525 /* If now is zero, it implies that the lock is not held, and must be 
01526 ** aquired here.  
01527 */
01528 static PRBool
01529 getSvrWrappingKey(PRInt32                symWrapMechIndex,
01530                SSL3KEAType               exchKeyType, 
01531                SSLWrappedSymWrappingKey *wswk, 
01532               cacheDesc *               cache,
01533               PRUint32                  lockTime)
01534 {
01535     PRUint32  ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
01536     SSLWrappedSymWrappingKey * pwswk = cache->keyCacheData + ndx;
01537     PRUint32  now = 0;
01538     PRBool    rv  = PR_FALSE;
01539 
01540     if (!cache->cacheMem) { /* cache is uninitialized */
01541        PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
01542        return rv;
01543     }
01544     if (!lockTime) {
01545        lockTime = now = LockSidCacheLock(cache->keyCacheLock, now);
01546        if (!lockTime) {
01547            return rv;
01548        }
01549     }
01550     if (pwswk->exchKeyType      == exchKeyType && 
01551        pwswk->symWrapMechIndex == symWrapMechIndex &&
01552        pwswk->wrappedSymKeyLen != 0) {
01553        *wswk = *pwswk;
01554        rv = PR_TRUE;
01555     }
01556     if (now) {
01557        UnlockSidCacheLock(cache->keyCacheLock);
01558     }
01559     return rv;
01560 }
01561 
01562 PRBool
01563 ssl_GetWrappingKey( PRInt32                   symWrapMechIndex,
01564                     SSL3KEAType               exchKeyType, 
01565                   SSLWrappedSymWrappingKey *wswk)
01566 {
01567     PRBool rv;
01568 
01569     PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
01570     PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
01571     if ((unsigned)exchKeyType < kt_kea_size &&
01572         (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) {
01573        rv = getSvrWrappingKey(symWrapMechIndex, exchKeyType, wswk, 
01574                               &globalCache, 0);
01575     } else {
01576        rv = PR_FALSE;
01577     }
01578 
01579     return rv;
01580 }
01581 
01582 /* The caller passes in the new value it wants
01583  * to set.  This code tests the wrapped sym key entry in the shared memory.
01584  * If it is uninitialized, this function writes the caller's value into 
01585  * the disk entry, and returns false.  
01586  * Otherwise, it overwrites the caller's wswk with the value obtained from 
01587  * the disk, and returns PR_TRUE.  
01588  * This is all done while holding the locks/mutexes necessary to make 
01589  * the operation atomic.
01590  */
01591 PRBool
01592 ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
01593 {
01594     cacheDesc *   cache            = &globalCache;
01595     PRBool        rv               = PR_FALSE;
01596     SSL3KEAType   exchKeyType      = wswk->exchKeyType;   
01597                                 /* type of keys used to wrap SymWrapKey*/
01598     PRInt32       symWrapMechIndex = wswk->symWrapMechIndex;
01599     PRUint32      ndx;
01600     PRUint32      now = 0;
01601     SSLWrappedSymWrappingKey myWswk;
01602 
01603     if (!cache->cacheMem) { /* cache is uninitialized */
01604        PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
01605        return 0;
01606     }
01607 
01608     PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
01609     if ((unsigned)exchKeyType >= kt_kea_size)
01610        return 0;
01611 
01612     PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
01613     if ((unsigned)symWrapMechIndex >=  SSL_NUM_WRAP_MECHS)
01614        return 0;
01615 
01616     ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
01617     PORT_Memset(&myWswk, 0, sizeof myWswk);      /* eliminate UMRs. */
01618 
01619     now = LockSidCacheLock(cache->keyCacheLock, now);
01620     if (now) {
01621        rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->exchKeyType, 
01622                               &myWswk, cache, now);
01623        if (rv) {
01624            /* we found it on disk, copy it out to the caller. */
01625            PORT_Memcpy(wswk, &myWswk, sizeof *wswk);
01626        } else {
01627            /* Wasn't on disk, and we're still holding the lock, so write it. */
01628            cache->keyCacheData[ndx] = *wswk;
01629        }
01630        UnlockSidCacheLock(cache->keyCacheLock);
01631     }
01632     return rv;
01633 }
01634 
01635 #else  /* MAC version or other platform */
01636 
01637 #include "seccomon.h"
01638 #include "cert.h"
01639 #include "ssl.h"
01640 #include "sslimpl.h"
01641 
01642 SECStatus
01643 SSL_ConfigServerSessionIDCache(    int      maxCacheEntries, 
01644                             PRUint32 ssl2_timeout,
01645                                    PRUint32 ssl3_timeout, 
01646                        const char *   directory)
01647 {
01648     PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigServerSessionIDCache)");    
01649     return SECFailure;
01650 }
01651 
01652 SECStatus
01653 SSL_ConfigMPServerSIDCache( int      maxCacheEntries, 
01654                             PRUint32 ssl2_timeout,
01655                                    PRUint32 ssl3_timeout, 
01656                         const char *   directory)
01657 {
01658     PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigMPServerSIDCache)");    
01659     return SECFailure;
01660 }
01661 
01662 SECStatus
01663 SSL_InheritMPServerSIDCache(const char * envString)
01664 {
01665     PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_InheritMPServerSIDCache)");    
01666     return SECFailure;
01667 }
01668 
01669 PRBool
01670 ssl_GetWrappingKey( PRInt32                   symWrapMechIndex,
01671                     SSL3KEAType               exchKeyType, 
01672                   SSLWrappedSymWrappingKey *wswk)
01673 {
01674     PRBool rv = PR_FALSE;
01675     PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)");    
01676     return rv;
01677 }
01678 
01679 /* This is a kind of test-and-set.  The caller passes in the new value it wants
01680  * to set.  This code tests the wrapped sym key entry in the shared memory.
01681  * If it is uninitialized, this function writes the caller's value into 
01682  * the disk entry, and returns false.  
01683  * Otherwise, it overwrites the caller's wswk with the value obtained from 
01684  * the disk, and returns PR_TRUE.  
01685  * This is all done while holding the locks/mutexes necessary to make 
01686  * the operation atomic.
01687  */
01688 PRBool
01689 ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
01690 {
01691     PRBool        rv = PR_FALSE;
01692     PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrappingKey)");
01693     return rv;
01694 }
01695 
01696 PRUint32  
01697 SSL_GetMaxServerCacheLocks(void)
01698 {
01699     PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_GetMaxServerCacheLocks)");
01700     return -1;
01701 }
01702 
01703 SECStatus 
01704 SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
01705 {
01706     PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_SetMaxServerCacheLocks)");
01707     return SECFailure;
01708 }
01709 
01710 #endif /* XP_UNIX || XP_WIN32 */