sslsnce.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:54k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /* This file implements the SERVER Session ID cache. 
  2.  * NOTE:  The contents of this file are NOT used by the client.
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public
  5.  * License Version 1.1 (the "License"); you may not use this file
  6.  * except in compliance with the License. You may obtain a copy of
  7.  * the License at http://www.mozilla.org/MPL/
  8.  * 
  9.  * Software distributed under the License is distributed on an "AS
  10.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  11.  * implied. See the License for the specific language governing
  12.  * rights and limitations under the License.
  13.  * 
  14.  * The Original Code is the Netscape security libraries.
  15.  * 
  16.  * The Initial Developer of the Original Code is Netscape
  17.  * Communications Corporation.  Portions created by Netscape are 
  18.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  19.  * Rights Reserved.
  20.  * 
  21.  * Contributor(s):
  22.  * 
  23.  * Alternatively, the contents of this file may be used under the
  24.  * terms of the GNU General Public License Version 2 or later (the
  25.  * "GPL"), in which case the provisions of the GPL are applicable 
  26.  * instead of those above.  If you wish to allow use of your 
  27.  * version of this file only under the terms of the GPL and not to
  28.  * allow others to use your version of this file under the MPL,
  29.  * indicate your decision by deleting the provisions above and
  30.  * replace them with the notice and other provisions required by
  31.  * the GPL.  If you do not delete the provisions above, a recipient
  32.  * may use your version of this file under either the MPL or the
  33.  * GPL.
  34.  *
  35.  * $Id: sslsnce.c,v 1.4 2000/09/12 20:15:43 jgmyers%netscape.com Exp $
  36.  */
  37. /* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server 
  38.  * cache sids!
  39.  *
  40.  * About record locking among different server processes:
  41.  *
  42.  * All processes that are part of the same conceptual server (serving on 
  43.  * the same address and port) MUST share a common SSL session cache. 
  44.  * This code makes the content of the shared cache accessible to all
  45.  * processes on the same "server".  This code works on Unix and Win32 only,
  46.  * and is platform specific. 
  47.  *
  48.  * Unix: Multiple processes share a single (inherited) FD for a disk 
  49.  * file all share one single file position.  If one lseeks, the position for 
  50.  * all processes is changed.  Since the set of platforms we support do not 
  51.  * all share portable lseek-and-read or lseek-and-write functions, a global 
  52.  * lock must be used to make the lseek call and the subsequent read or write 
  53.  * call be one atomic operation.  It is no longer necessary for cache element 
  54.  * sizes to be a power of 2, or a multiple of a sector size.
  55.  *
  56.  * For Win32, where (a) disk I/O is not atomic, and (b) we use memory-mapped
  57.  * files and move data to & from memory instead of calling read or write,
  58.  * we must do explicit locking of the records for all reads and writes.
  59.  * We have just one lock, for the entire file, using an NT semaphore.
  60.  * We avoid blocking on "local threads" since it's bad to block on a local 
  61.  * thread - If NSPR offered portable semaphores, it would handle this itself.
  62.  *
  63.  * Since this file has to do lots of platform specific I/O, the system
  64.  * dependent error codes need to be mapped back into NSPR error codes.
  65.  * Since NSPR's error mapping functions are private, the code is necessarily
  66.  * duplicated in libSSL.
  67.  *
  68.  * Note, now that NSPR provides portable anonymous shared memory, for all
  69.  * platforms except Mac, the implementation below should be replaced with 
  70.  * one that uses anonymous shared memory ASAP.  This will eliminate most 
  71.  * platform dependent code in this file, and improve performance big time.
  72.  *
  73.  * Now that NSPR offers portable cross-process locking (semaphores) on Unix
  74.  * and Win32, semaphores should be used here for all platforms.
  75.  */
  76. #include "seccomon.h"
  77. #if defined(XP_UNIX) || defined(XP_WIN32)
  78. #ifndef NADA_VERISON
  79. #include "cert.h"
  80. #include "ssl.h"
  81. #include "sslimpl.h"
  82. #include "sslproto.h"
  83. #include "pk11func.h"
  84. #include "base64.h"
  85. #include <stdio.h>
  86. #ifdef XP_UNIX
  87. #include <syslog.h>
  88. #include <fcntl.h>
  89. #include <unistd.h>
  90. #include "unix_err.h"
  91. #else /* XP_WIN32 */
  92. #ifdef MC_HTTPD
  93. #include <ereport.h>
  94. #endif /* MC_HTTPD */
  95. #include <wtypes.h>
  96. #include "win32err.h"
  97. #endif /* XP_WIN32 */
  98. #include <sys/types.h>
  99. #define SET_ERROR_CODE /* reminder */
  100. #include "nspr.h"
  101. #include "nsslocks.h"
  102. static PRLock *cacheLock;
  103. /*
  104. ** The server session-id cache uses a simple flat cache. The cache is
  105. ** sized during initialization. We hash the ip-address + session-id value
  106. ** into an index into the cache and do the lookup. No buckets, nothing
  107. ** fancy.
  108. */
  109. static PRBool isMultiProcess  = PR_FALSE;
  110. static PRUint32 numSIDCacheEntries  = 10000; 
  111. static PRUint32 sidCacheFileSize;
  112. static PRUint32 sidCacheWrapOffset;
  113. static PRUint32 numCertCacheEntries = 250;
  114. static PRUint32 certCacheFileSize;
  115. #define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */
  116. /*
  117. ** Format of a cache entry.
  118. */ 
  119. typedef struct SIDCacheEntryStr SIDCacheEntry;
  120. struct SIDCacheEntryStr {
  121.     PRIPv6Addr addr;
  122.     PRUint32 time;
  123.     union {
  124. struct {
  125.     /* This is gross.  We have to have version and valid in both arms
  126.      * of the union for alignment reasons.  This probably won't work
  127.      * on a 64-bit machine. XXXX
  128.      */
  129. /*  2 */    uint16        version;
  130. /*  1 */    unsigned char valid;
  131. /*  1 */    unsigned char cipherType;
  132. /* 16 */    unsigned char sessionID[SSL_SESSIONID_BYTES];
  133. /* 64 */    unsigned char masterKey[SSL_MAX_MASTER_KEY_BYTES];
  134. /* 32 */    unsigned char cipherArg[SSL_MAX_CYPHER_ARG_BYTES];
  135. /*  1 */    unsigned char masterKeyLen;
  136. /*  1 */    unsigned char keyBits;
  137. /*  1 */    unsigned char secretKeyBits;
  138. /*  1 */    unsigned char cipherArgLen;
  139. /*120 */} ssl2;
  140. struct {
  141. /*  2 */    uint16           version;
  142. /*  1 */    unsigned char    valid;
  143. /*  1 */    uint8            sessionIDLength;
  144. /* 32 */    unsigned char    sessionID[SSL3_SESSIONID_BYTES];
  145. /*  2 */    ssl3CipherSuite  cipherSuite;
  146. /*  2 */    uint16           compression;  /* SSL3CompressionMethod */
  147. /*122 */    ssl3SidKeys      keys; /* keys and ivs, wrapped as needed. */
  148. /*  4 */    PRUint32         masterWrapMech; 
  149. /*  4 */    SSL3KEAType      exchKeyType;
  150. /*  2 */    int16            certIndex;
  151. /*  1 */    uint8            hasFortezza;
  152. /*  1 */    uint8            resumable;
  153. } ssl3;
  154. /* We can't make this struct fit in 128 bytes 
  155.  * so, force the struct size up to the next power of two.
  156.  */
  157. struct {
  158.     unsigned char filler[256 - sizeof(PRIPv6Addr) - sizeof(PRUint32)];
  159. } force256;
  160.     } u;
  161. };
  162. typedef struct CertCacheEntryStr CertCacheEntry;
  163. /* The length of this struct is supposed to be a power of 2, e.g. 4KB */
  164. struct CertCacheEntryStr {
  165.     uint16        certLength; /*    2 */
  166.     uint16        sessionIDLength; /*    2 */
  167.     unsigned char sessionID[SSL3_SESSIONID_BYTES]; /*   32 */
  168.     unsigned char cert[SSL_MAX_CACHED_CERT_LEN]; /* 4060 */
  169. }; /* total   4096 */
  170. static void IOError(int rv, char *type);
  171. static PRUint32 Offset(const PRIPv6Addr *addr, unsigned char *s, unsigned nl);
  172. static void Invalidate(SIDCacheEntry *sce);
  173. /************************************************************************/
  174. static const char envVarName[] = { SSL_ENV_VAR_NAME };
  175. #ifdef _WIN32
  176. struct winInheritanceStr {
  177.     PRUint32 numSIDCacheEntries;
  178.     PRUint32 sidCacheFileSize;
  179.     PRUint32 sidCacheWrapOffset;
  180.     PRUint32 numCertCacheEntries;
  181.     PRUint32 certCacheFileSize;
  182.     DWORD         parentProcessID;
  183.     HANDLE        parentProcessHandle;
  184.     HANDLE        SIDCacheFDMAP;
  185.     HANDLE        certCacheFDMAP;
  186.     HANDLE        svrCacheSem;
  187. };
  188. typedef struct winInheritanceStr winInheritance;
  189. static HANDLE svrCacheSem    = INVALID_HANDLE_VALUE;
  190. static char * SIDCacheData    = NULL;
  191. static HANDLE SIDCacheFD      = INVALID_HANDLE_VALUE;
  192. static HANDLE SIDCacheFDMAP   = INVALID_HANDLE_VALUE;
  193. static char * certCacheData   = NULL;
  194. static HANDLE certCacheFD     = INVALID_HANDLE_VALUE;
  195. static HANDLE certCacheFDMAP  = INVALID_HANDLE_VALUE;
  196. static PRUint32 myPid;
  197. /* The presence of the TRUE element in this struct makes the semaphore 
  198.  * inheritable. The NULL means use process's default security descriptor. 
  199.  */
  200. static SECURITY_ATTRIBUTES semaphoreAttributes = 
  201. { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
  202. static SECURITY_ATTRIBUTES sidCacheFDMapAttributes = 
  203. { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
  204. static SECURITY_ATTRIBUTES certCacheFDMapAttributes = 
  205. { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
  206. #define DEFAULT_CACHE_DIRECTORY "\temp"
  207. static SECStatus
  208. createServerCacheSemaphore(void)
  209. {
  210.     PR_ASSERT(svrCacheSem == INVALID_HANDLE_VALUE);
  211.     /* inheritable, starts signalled, 1 signal max, no file name. */
  212.     svrCacheSem = CreateSemaphore(&semaphoreAttributes, 1, 1, NULL);
  213.     if (svrCacheSem == NULL) {
  214. svrCacheSem = INVALID_HANDLE_VALUE;
  215. /* We could get the error code, but what could be do with it ? */
  216. nss_MD_win32_map_default_error(GetLastError());
  217.      return SECFailure;
  218.     }
  219.     return SECSuccess;
  220. }
  221. static SECStatus
  222. _getServerCacheSemaphore(void)
  223. {
  224.     DWORD     event;
  225.     DWORD     lastError;
  226.     SECStatus rv;
  227.     PR_ASSERT(svrCacheSem != INVALID_HANDLE_VALUE);
  228.     if (svrCacheSem == INVALID_HANDLE_VALUE &&
  229.      SECSuccess   != createServerCacheSemaphore()) {
  230. return SECFailure; /* what else ? */
  231.     }
  232.     event = WaitForSingleObject(svrCacheSem, INFINITE);
  233.     switch (event) {
  234.     case WAIT_OBJECT_0:
  235.     case WAIT_ABANDONED:
  236. rv = SECSuccess;
  237.      break;
  238.     case WAIT_TIMEOUT:
  239.     case WAIT_IO_COMPLETION:
  240.     default:  /* should never happen. nothing we can do. */
  241. PR_ASSERT(("WaitForSingleObject returned invalid value.", 0));
  242. /* fall thru */
  243.     case WAIT_FAILED: /* failure returns this */
  244. rv = SECFailure;
  245. lastError = GetLastError(); /* for debugging */
  246. nss_MD_win32_map_default_error(lastError);
  247. break;
  248.     }
  249.     return rv;
  250. }
  251. static void
  252. _doGetServerCacheSemaphore(void * arg)
  253. {
  254.     SECStatus * rv = (SECStatus *)arg;
  255.     *rv = _getServerCacheSemaphore();
  256. }
  257. static SECStatus
  258. getServerCacheSemaphore(void)
  259. {
  260.     PRThread *    selectThread;
  261.     PRThread *    me     = PR_GetCurrentThread();
  262.     PRThreadScope scope  = PR_GetThreadScope(me);
  263.     SECStatus     rv     = SECFailure;
  264.     if (scope == PR_GLOBAL_THREAD) {
  265.         rv = _getServerCacheSemaphore();
  266.     } else {
  267.         selectThread = PR_CreateThread(PR_USER_THREAD,
  268.        _doGetServerCacheSemaphore, &rv,
  269.        PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  270.        PR_JOINABLE_THREAD, 0);
  271.         if (selectThread != NULL) {
  272.     /* rv will be set by _doGetServerCacheSemaphore() */
  273.     PR_JoinThread(selectThread);
  274.         }
  275.     }
  276.     return rv;
  277. }
  278. static SECStatus
  279. releaseServerCacheSemaphore(void)
  280. {
  281.     BOOL success = FALSE;
  282.     PR_ASSERT(svrCacheSem != INVALID_HANDLE_VALUE);
  283.     if (svrCacheSem != INVALID_HANDLE_VALUE) {
  284. /* Add 1, don't want previous value. */
  285. success = ReleaseSemaphore(svrCacheSem, 1, NULL);
  286.     }
  287.     if (!success) {
  288. nss_MD_win32_map_default_error(GetLastError());
  289. return SECFailure;
  290.     }
  291.     return SECSuccess;
  292. }
  293. static void
  294. destroyServerCacheSemaphore(void)
  295. {
  296.     PR_ASSERT(svrCacheSem != INVALID_HANDLE_VALUE);
  297.     if (svrCacheSem != INVALID_HANDLE_VALUE) {
  298. CloseHandle(svrCacheSem);
  299. /* ignore error */
  300. svrCacheSem = INVALID_HANDLE_VALUE;
  301.     }
  302. }
  303. #define GET_SERVER_CACHE_READ_LOCK(fd, offset, size) 
  304.     if (isMultiProcess) getServerCacheSemaphore();
  305. #define GET_SERVER_CACHE_WRITE_LOCK(fd, offset, size) 
  306.     if (isMultiProcess) getServerCacheSemaphore();
  307. #define RELEASE_SERVER_CACHE_LOCK(fd, offset, size) 
  308.     if (isMultiProcess) releaseServerCacheSemaphore();
  309. #endif /* _win32 */
  310. /************************************************************************/
  311. #ifdef XP_UNIX
  312. static int    SIDCacheFD      = -1;
  313. static int    certCacheFD     = -1;
  314. static pid_t  myPid;
  315. struct unixInheritanceStr {
  316.     PRUint32 numSIDCacheEntries;
  317.     PRUint32 sidCacheFileSize;
  318.     PRUint32 sidCacheWrapOffset;
  319.     PRUint32 numCertCacheEntries;
  320.     PRUint32 certCacheFileSize;
  321.     PRInt32  SIDCacheFD;
  322.     PRInt32  certCacheFD;
  323. };
  324. typedef struct unixInheritanceStr unixInheritance;
  325. #define DEFAULT_CACHE_DIRECTORY "/tmp"
  326. #ifdef TRACE
  327. static void 
  328. fcntlFailed(struct flock *lock) 
  329. {
  330.     fprintf(stderr,
  331.     "fcntl failed, errno = %d, PR_GetError = %d, lock.l_type = %dn",
  332. errno, PR_GetError(), lock->l_type);
  333.     fflush(stderr);
  334. }
  335. #define FCNTL_FAILED(lock) fcntlFailed(lock)
  336. #else
  337. #define FCNTL_FAILED(lock) 
  338. #endif
  339. /* NOTES:  Because there are no atomic seek-and-read and seek-and-write
  340. ** functions that are supported on all our UNIX platforms, we need
  341. ** to prevent all simultaeous seek-and-read operations.  For that reason,
  342. ** we use mutually exclusive (write) locks for read and write operations,
  343. ** and use them all at the same offset (zero).
  344. */
  345. static SECStatus
  346. _getServerCacheLock(int fd, short type, PRUint32 offset, PRUint32 size)
  347. {
  348.     int          result;
  349.     struct flock lock;
  350.     memset(&lock, 0, sizeof lock);
  351.     lock.l_type   = /* type */ F_WRLCK;
  352.     lock.l_whence = SEEK_SET; /* absolute file offsets. */
  353.     lock.l_start  = 0;
  354.     lock.l_len    = 128;
  355. #ifdef TRACE
  356.     if (ssl_trace) {
  357. fprintf(stderr, "%d: %s lock, offset %8x, size %4dn", myPid,
  358.     (type == F_RDLCK) ? "read " : "write", offset, size);
  359. fflush(stderr);
  360.     }
  361. #endif
  362.     result = fcntl(fd, F_SETLKW, &lock);
  363.     if (result == -1) {
  364.         nss_MD_unix_map_default_error(errno);
  365. FCNTL_FAILED(&lock);
  366.      return SECFailure;
  367.     }
  368. #ifdef TRACE
  369.     if (ssl_trace) {
  370. fprintf(stderr, "%d:   got lock, offset %8x, size %4dn", 
  371.     myPid, offset, size);
  372. fflush(stderr);
  373.     }
  374. #endif
  375.     return SECSuccess;
  376. }
  377. typedef struct sslLockArgsStr {
  378.     PRUint32    offset;
  379.     PRUint32    size;
  380.     PRErrorCode err;
  381.     SECStatus   rv;
  382.     int         fd;
  383.     short       type;
  384. } sslLockArgs;
  385. static void
  386. _doGetServerCacheLock(void * arg)
  387. {
  388.     sslLockArgs * args = (sslLockArgs *)arg;
  389.     args->rv = _getServerCacheLock(args->fd, args->type, args->offset, 
  390.    args->size );
  391.     if (args->rv != SECSuccess) {
  392. args->err = PR_GetError();
  393.     }
  394. }
  395. static SECStatus
  396. getServerCacheLock(int fd, short type, PRUint32 offset, PRUint32 size)
  397. {
  398.     PRThread *    selectThread;
  399.     PRThread *    me     = PR_GetCurrentThread();
  400.     PRThreadScope scope  = PR_GetThreadScope(me);
  401.     SECStatus     rv     = SECFailure;
  402.     if (scope == PR_GLOBAL_THREAD) {
  403.         rv = _getServerCacheLock(fd, type, offset, size);
  404.     } else {
  405. /* Ib some platforms, one thread cannot read local/automatic 
  406. ** variables from another thread's stack.  So, get this space
  407. ** from the heap, not the stack.
  408. */
  409. sslLockArgs * args = PORT_New(sslLockArgs);
  410. if (!args)
  411.     return rv;
  412. args->offset = offset;
  413. args->size   = size;
  414. args->rv     = SECFailure;
  415. args->fd     = fd;
  416. args->type   = type;
  417.         selectThread = PR_CreateThread(PR_USER_THREAD,
  418.        _doGetServerCacheLock, args,
  419.        PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  420.        PR_JOINABLE_THREAD, 0);
  421.         if (selectThread != NULL) {
  422.     /* rv will be set by _doGetServerCacheLock() */
  423.     PR_JoinThread(selectThread);
  424.     rv = args->rv;
  425.     if (rv != SECSuccess) {
  426. PORT_SetError(args->err);
  427.     }
  428.         }
  429. PORT_Free(args);
  430.     }
  431.     return rv;
  432. }
  433. static SECStatus
  434. releaseServerCacheLock(int fd, PRUint32 offset, PRUint32 size)
  435. {
  436.     int          result;
  437.     struct flock lock;
  438.     memset(&lock, 0, sizeof lock);
  439.     lock.l_type   = F_UNLCK;
  440.     lock.l_whence = SEEK_SET; /* absolute file offsets. */
  441.     lock.l_start  = 0;
  442.     lock.l_len    = 128;
  443. #ifdef TRACE
  444.     if (ssl_trace) {
  445. fprintf(stderr, "%d:     unlock, offset %8x, size %4dn", 
  446.     myPid, offset, size);
  447. fflush(stderr);
  448.     }
  449. #endif
  450.     result = fcntl(fd, F_SETLK, &lock);
  451.     if (result == -1) {
  452.         nss_MD_unix_map_default_error(errno);
  453. FCNTL_FAILED(&lock);
  454.      return SECFailure;
  455.     }
  456.     return SECSuccess;
  457. }
  458. /* these defines take the arguments needed to do record locking, 
  459.  * however the present implementation does only file locking.
  460.  */
  461. #define GET_SERVER_CACHE_READ_LOCK( fd, offset, size) 
  462.     if (isMultiProcess) getServerCacheLock(fd, F_RDLCK, offset, size);
  463. #define GET_SERVER_CACHE_WRITE_LOCK(fd, offset, size) 
  464.     if (isMultiProcess) getServerCacheLock(fd, F_WRLCK, offset, size);
  465. #define RELEASE_SERVER_CACHE_LOCK(  fd, offset, size) 
  466.     if (isMultiProcess) releaseServerCacheLock(fd, offset, size);
  467. /*
  468. ** Zero a file out to nb bytes
  469. */
  470. static SECStatus 
  471. ZeroFile(int fd, int nb)
  472. {
  473.     off_t off;
  474.     int amount, rv;
  475.     char buf[16384];
  476.     PORT_Memset(buf, 0, sizeof(buf));
  477.     off = lseek(fd, 0, SEEK_SET);
  478.     if (off != 0) {
  479. if (off == -1) 
  480.     nss_MD_unix_map_lseek_error(errno);
  481.      else
  482.     PORT_SetError(PR_FILE_SEEK_ERROR);
  483.      return SECFailure;
  484.     }
  485.     while (nb > 0) {
  486. amount = (nb > sizeof buf) ? sizeof buf : nb;
  487. rv = write(fd, buf, amount);
  488. if (rv <= 0) {
  489.     if (!rv)
  490.      PORT_SetError(PR_IO_ERROR);
  491.     else
  492. nss_MD_unix_map_write_error(errno);
  493.     IOError(rv, "zero-write");
  494.     return SECFailure;
  495. }
  496. nb -= rv;
  497.     }
  498.     return SECSuccess;
  499. }
  500. #endif /* XP_UNIX */
  501. /************************************************************************/
  502. /*
  503. ** Reconstitute a cert from the cache
  504. ** This is only called from ConvertToSID().
  505. ** Caller must hold the cache lock before calling this.
  506. */
  507. static CERTCertificate *
  508. GetCertFromCache(SIDCacheEntry *sce, CERTCertDBHandle *dbHandle)
  509. {
  510.     CERTCertificate *cert;
  511.     PRUint32         offset;
  512.     int              rv;
  513. #ifdef XP_UNIX
  514.     off_t            off;
  515. #endif
  516.     SECItem          derCert;
  517.     CertCacheEntry   cce;
  518.     offset = (PRUint32)sce->u.ssl3.certIndex * sizeof(CertCacheEntry);
  519.     GET_SERVER_CACHE_READ_LOCK(certCacheFD, offset, sizeof(CertCacheEntry));
  520. #ifdef XP_UNIX
  521.     off = lseek(certCacheFD, offset, SEEK_SET);
  522.     rv = -1;
  523.     if (off != offset) {
  524. if (off == -1) 
  525.     nss_MD_unix_map_lseek_error(errno);
  526. else 
  527.     PORT_SetError(PR_FILE_SEEK_ERROR);
  528.     } else {
  529. rv = read(certCacheFD, &cce, sizeof(CertCacheEntry));
  530. if (rv != sizeof(CertCacheEntry)) {
  531.     if (rv == -1)
  532. nss_MD_unix_map_read_error(errno);
  533.     else
  534.      PORT_SetError(PR_IO_ERROR);
  535. }
  536.     }
  537. #else /* XP_WIN32 */
  538.     /* Use memory mapped I/O and just memcpy() the data */
  539.     CopyMemory(&cce, &certCacheData[offset], sizeof(CertCacheEntry));
  540.     rv = sizeof cce;
  541. #endif /* XP_WIN32 */
  542.     RELEASE_SERVER_CACHE_LOCK(certCacheFD, offset, sizeof(CertCacheEntry))
  543.     if (rv != sizeof(CertCacheEntry)) {
  544. IOError(rv, "read"); /* error set above */
  545. return NULL;
  546.     }
  547.     /* See if the session ID matches with that in the sce cache. */
  548.     if((cce.sessionIDLength != sce->u.ssl3.sessionIDLength) ||
  549.        PORT_Memcmp(cce.sessionID, sce->u.ssl3.sessionID, cce.sessionIDLength)) {
  550.         /* this is a cache miss, not an error */
  551. PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
  552. return NULL;
  553.     }
  554.     derCert.len  = cce.certLength;
  555.     derCert.data = cce.cert;
  556.     cert = CERT_NewTempCertificate(dbHandle, &derCert, NULL,
  557.    PR_FALSE, PR_TRUE);
  558.     return cert;
  559. }
  560. /* Put a certificate in the cache.  We assume that the certIndex in
  561. ** sid is valid.
  562. */
  563. static void
  564. CacheCert(CERTCertificate *cert, SIDCacheEntry *sce)
  565. {
  566.     PRUint32       offset;
  567.     CertCacheEntry cce;
  568. #ifdef XP_UNIX
  569.     off_t          off;
  570.     int            rv;
  571. #endif
  572.     offset = (PRUint32)sce->u.ssl3.certIndex * sizeof(CertCacheEntry);
  573.     if (cert->derCert.len > SSL_MAX_CACHED_CERT_LEN)
  574. return;
  575.     
  576.     cce.sessionIDLength = sce->u.ssl3.sessionIDLength;
  577.     PORT_Memcpy(cce.sessionID, sce->u.ssl3.sessionID, cce.sessionIDLength);
  578.     cce.certLength = cert->derCert.len;
  579.     PORT_Memcpy(cce.cert, cert->derCert.data, cce.certLength);
  580.     GET_SERVER_CACHE_WRITE_LOCK(certCacheFD, offset, sizeof cce);
  581. #ifdef XP_UNIX
  582.     off = lseek(certCacheFD, offset, SEEK_SET);
  583.     if (off != offset) {
  584. if (off == -1) 
  585.     nss_MD_unix_map_lseek_error(errno);
  586. else 
  587.     PORT_SetError(PR_FILE_SEEK_ERROR);
  588.     } else {
  589. rv = write(certCacheFD, &cce, sizeof cce);
  590. if (rv != sizeof(CertCacheEntry)) {
  591.     if (rv == -1)
  592. nss_MD_unix_map_write_error(errno);
  593.     else
  594.      PORT_SetError(PR_IO_ERROR);
  595.     IOError(rv, "cert-write");
  596.     Invalidate(sce);
  597. }
  598.     }
  599. #else /* WIN32 */
  600.     /* Use memory mapped I/O and just memcpy() the data */
  601.     CopyMemory(&certCacheData[offset], &cce, sizeof cce);
  602. #endif /* XP_UNIX */
  603.     RELEASE_SERVER_CACHE_LOCK(certCacheFD, offset, sizeof cce);
  604.     return;
  605. }
  606. /*
  607. ** Convert memory based SID to file based one
  608. */
  609. static void 
  610. ConvertFromSID(SIDCacheEntry *to, sslSessionID *from)
  611. {
  612.     to->u.ssl2.valid = 1;
  613.     to->u.ssl2.version = from->version;
  614.     to->addr = from->addr;
  615.     to->time = from->time;
  616.     if (from->version < SSL_LIBRARY_VERSION_3_0) {
  617. if ((from->u.ssl2.masterKey.len > SSL_MAX_MASTER_KEY_BYTES) ||
  618.     (from->u.ssl2.cipherArg.len > SSL_MAX_CYPHER_ARG_BYTES)) {
  619.     SSL_DBG(("%d: SSL: masterKeyLen=%d cipherArgLen=%d",
  620.      myPid, from->u.ssl2.masterKey.len,
  621.      from->u.ssl2.cipherArg.len));
  622.     to->u.ssl2.valid = 0;
  623.     return;
  624. }
  625. to->u.ssl2.cipherType    = from->u.ssl2.cipherType;
  626. to->u.ssl2.masterKeyLen  = from->u.ssl2.masterKey.len;
  627. to->u.ssl2.cipherArgLen  = from->u.ssl2.cipherArg.len;
  628. to->u.ssl2.keyBits       = from->u.ssl2.keyBits;
  629. to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
  630. PORT_Memcpy(to->u.ssl2.sessionID, from->u.ssl2.sessionID,
  631.   sizeof(to->u.ssl2.sessionID));
  632. PORT_Memcpy(to->u.ssl2.masterKey, from->u.ssl2.masterKey.data,
  633.   from->u.ssl2.masterKey.len);
  634. PORT_Memcpy(to->u.ssl2.cipherArg, from->u.ssl2.cipherArg.data,
  635.   from->u.ssl2.cipherArg.len);
  636. #ifdef DEBUG
  637. PORT_Memset(to->u.ssl2.masterKey+from->u.ssl2.masterKey.len, 0,
  638.   sizeof(to->u.ssl2.masterKey) - from->u.ssl2.masterKey.len);
  639. PORT_Memset(to->u.ssl2.cipherArg+from->u.ssl2.cipherArg.len, 0,
  640.   sizeof(to->u.ssl2.cipherArg) - from->u.ssl2.cipherArg.len);
  641. #endif
  642. SSL_TRC(8, ("%d: SSL: ConvertSID: masterKeyLen=%d cipherArgLen=%d "
  643.     "time=%d addr=0x%08x%08x%08x%08x cipherType=%d", myPid,
  644.     to->u.ssl2.masterKeyLen, to->u.ssl2.cipherArgLen,
  645.     to->time, to->addr.pr_s6_addr32[0], 
  646.     to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
  647.     to->addr.pr_s6_addr32[3], to->u.ssl2.cipherType));
  648.     } else {
  649. /* This is an SSL v3 session */
  650. to->u.ssl3.sessionIDLength  = from->u.ssl3.sessionIDLength;
  651. to->u.ssl3.cipherSuite      = from->u.ssl3.cipherSuite;
  652. to->u.ssl3.compression      = (uint16)from->u.ssl3.compression;
  653. to->u.ssl3.resumable        = from->u.ssl3.resumable;
  654. to->u.ssl3.hasFortezza      = from->u.ssl3.hasFortezza;
  655. to->u.ssl3.keys             = from->u.ssl3.keys;
  656. to->u.ssl3.masterWrapMech   = from->u.ssl3.masterWrapMech;
  657. to->u.ssl3.exchKeyType      = from->u.ssl3.exchKeyType;
  658. PORT_Memcpy(to->u.ssl3.sessionID, 
  659.             from->u.ssl3.sessionID,
  660.     from->u.ssl3.sessionIDLength);
  661. SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x cipherSuite=%d",
  662.     myPid, to->time, to->addr.pr_s6_addr32[0],
  663.     to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
  664.     to->addr.pr_s6_addr32[3], to->u.ssl3.cipherSuite));
  665.     }
  666. }
  667. /*
  668. ** Convert file based cache-entry to memory based one
  669. ** This is only called from ServerSessionIDLookup().
  670. ** Caller must hold cache lock when calling this.
  671. */
  672. static sslSessionID *
  673. ConvertToSID(SIDCacheEntry *from, CERTCertDBHandle * dbHandle)
  674. {
  675.     sslSessionID *to;
  676.     uint16 version = from->u.ssl2.version;
  677.     to = (sslSessionID*) PORT_ZAlloc(sizeof(sslSessionID));
  678.     if (!to) {
  679. return 0;
  680.     }
  681.     if (version < SSL_LIBRARY_VERSION_3_0) {
  682. /* This is an SSL v2 session */
  683. to->u.ssl2.masterKey.data =
  684.     (unsigned char*) PORT_Alloc(from->u.ssl2.masterKeyLen);
  685. if (!to->u.ssl2.masterKey.data) {
  686.     goto loser;
  687. }
  688. if (from->u.ssl2.cipherArgLen) {
  689.     to->u.ssl2.cipherArg.data = (unsigned char*)
  690. PORT_Alloc(from->u.ssl2.cipherArgLen);
  691.     if (!to->u.ssl2.cipherArg.data) {
  692. goto loser;
  693.     }
  694.     PORT_Memcpy(to->u.ssl2.cipherArg.data, from->u.ssl2.cipherArg,
  695.       from->u.ssl2.cipherArgLen);
  696. }
  697. to->u.ssl2.cipherType    = from->u.ssl2.cipherType;
  698. to->u.ssl2.masterKey.len = from->u.ssl2.masterKeyLen;
  699. to->u.ssl2.cipherArg.len = from->u.ssl2.cipherArgLen;
  700. to->u.ssl2.keyBits       = from->u.ssl2.keyBits;
  701. to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
  702. PORT_Memcpy(to->u.ssl2.sessionID, from->u.ssl2.sessionID,
  703.   sizeof from->u.ssl2.sessionID);
  704. PORT_Memcpy(to->u.ssl2.masterKey.data, from->u.ssl2.masterKey,
  705.   from->u.ssl2.masterKeyLen);
  706. SSL_TRC(8, ("%d: SSL: ConvertToSID: masterKeyLen=%d cipherArgLen=%d "
  707.     "time=%d addr=0x%08x%08x%08x%08x cipherType=%d",
  708.     myPid, to->u.ssl2.masterKey.len,
  709.     to->u.ssl2.cipherArg.len, to->time, 
  710.     to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1],
  711.     to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3], 
  712.     to->u.ssl2.cipherType));
  713.     } else {
  714. /* This is an SSL v3 session */
  715. to->u.ssl3.sessionIDLength  = from->u.ssl3.sessionIDLength;
  716. to->u.ssl3.cipherSuite      = from->u.ssl3.cipherSuite;
  717. to->u.ssl3.compression      = (SSL3CompressionMethod)from->u.ssl3.compression;
  718. to->u.ssl3.resumable        = from->u.ssl3.resumable;
  719. to->u.ssl3.hasFortezza      = from->u.ssl3.hasFortezza;
  720. to->u.ssl3.keys             = from->u.ssl3.keys;
  721. to->u.ssl3.masterWrapMech   = from->u.ssl3.masterWrapMech;
  722. to->u.ssl3.exchKeyType      = from->u.ssl3.exchKeyType;
  723. PORT_Memcpy(to->u.ssl3.sessionID, 
  724.             from->u.ssl3.sessionID,
  725.     from->u.ssl3.sessionIDLength);
  726. /* the portions of the SID that are only restored on the client
  727.  * are set to invalid values on the server.
  728.  */
  729. to->u.ssl3.clientWriteKey   = NULL;
  730. to->u.ssl3.serverWriteKey   = NULL;
  731. to->u.ssl3.tek              = NULL;
  732. to->urlSvrName              = NULL;
  733. to->u.ssl3.masterModuleID   = (SECMODModuleID)-1; /* invalid value */
  734. to->u.ssl3.masterSlotID     = (CK_SLOT_ID)-1;     /* invalid value */
  735. to->u.ssl3.masterWrapIndex  = 0;
  736. to->u.ssl3.masterWrapSeries = 0;
  737. to->u.ssl3.masterValid      = PR_FALSE;
  738. to->u.ssl3.clAuthModuleID   = (SECMODModuleID)-1; /* invalid value */
  739. to->u.ssl3.clAuthSlotID     = (CK_SLOT_ID)-1;     /* invalid value */
  740. to->u.ssl3.clAuthSeries     = 0;
  741. to->u.ssl3.clAuthValid      = PR_FALSE;
  742. to->u.ssl3.clientWriteSaveLen = 0;
  743. if (from->u.ssl3.certIndex != -1) {
  744.     to->peerCert = GetCertFromCache(from, dbHandle);
  745.     if (to->peerCert == NULL)
  746. goto loser;
  747. }
  748.     }
  749.     to->version    = from->u.ssl2.version;
  750.     to->time       = from->time;
  751.     to->cached     = in_server_cache;
  752.     to->addr       = from->addr;
  753.     to->references = 1;
  754.     
  755.     return to;
  756.   loser:
  757.     Invalidate(from);
  758.     if (to) {
  759. if (version < SSL_LIBRARY_VERSION_3_0) {
  760.     if (to->u.ssl2.masterKey.data)
  761. PORT_Free(to->u.ssl2.masterKey.data);
  762.     if (to->u.ssl2.cipherArg.data)
  763. PORT_Free(to->u.ssl2.cipherArg.data);
  764. }
  765. PORT_Free(to);
  766.     }
  767.     return NULL;
  768. }
  769. /* Invalidate a SID cache entry. 
  770.  * Called from CacheCert, ConvertToSid, and ServerSessionIDUncache. 
  771.  */
  772. static void 
  773. Invalidate(SIDCacheEntry *sce)
  774. {
  775.     PRUint32 offset;
  776. #ifdef XP_UNIX
  777.     off_t off;
  778.     int  rv;
  779. #endif
  780.     if (sce == NULL) return;
  781.     if (sce->u.ssl2.version < SSL_LIBRARY_VERSION_3_0) {
  782. offset = Offset(&sce->addr, sce->u.ssl2.sessionID,
  783. sizeof sce->u.ssl2.sessionID); 
  784.     } else {
  785. offset = Offset(&sce->addr, sce->u.ssl3.sessionID,
  786. sce->u.ssl3.sessionIDLength); 
  787.     }
  788.     sce->u.ssl2.valid = 0;
  789.     SSL_TRC(7, ("%d: SSL: uncaching session-id at offset %ld",
  790.     myPid, offset));
  791.     GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, offset, sizeof *sce);
  792. #ifdef XP_UNIX
  793.     off = lseek(SIDCacheFD, offset, SEEK_SET);
  794.     if (off != offset) {
  795. if (off == -1) 
  796.     nss_MD_unix_map_lseek_error(errno);
  797. else 
  798.     PORT_SetError(PR_FILE_SEEK_ERROR);
  799.     } else {
  800. rv = write(SIDCacheFD, sce, sizeof *sce);
  801. if (rv != sizeof *sce) {
  802.     if (rv == -1)
  803. nss_MD_unix_map_write_error(errno);
  804.     else
  805.      PORT_SetError(PR_IO_ERROR);
  806.     IOError(rv, "invalidate-write");
  807.      }
  808.     }
  809. #else /* WIN32 */
  810.     /* Use memory mapped I/O and just memcpy() the data */
  811.     CopyMemory(&SIDCacheData[offset], sce, sizeof *sce);
  812. #endif /* XP_UNIX */
  813.     RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *sce);
  814. }
  815. static void 
  816. IOError(int rv, char *type)
  817. {
  818. #ifdef XP_UNIX
  819.     syslog(LOG_ALERT,
  820.    "SSL: %s error with session-id cache, pid=%d, rv=%d, error='%m'",
  821.    type, myPid, rv);
  822. #else /* XP_WIN32 */
  823. #ifdef MC_HTTPD 
  824.     ereport(LOG_FAILURE, "%s error with session-id cache rv=%dn",type, rv);
  825. #endif /* MC_HTTPD */
  826. #endif /* XP_UNIX */
  827. }
  828. static void 
  829. lock_cache(void)
  830. {
  831.     PR_Lock(cacheLock);
  832. }
  833. static void 
  834. unlock_cache(void)
  835. {
  836.     PR_Unlock(cacheLock);
  837. }
  838. /*
  839. ** Perform some mumbo jumbo on the ip-address and the session-id value to
  840. ** compute a hash value.
  841. */
  842. static PRUint32 
  843. Offset(const PRIPv6Addr *addr, unsigned char *s, unsigned nl)
  844. {
  845.     PRUint32 rv;
  846.     rv = addr->pr_s6_addr32[3] ^ (((PRUint32)s[0] << 24) | ((PRUint32)s[1] << 16)
  847.  | (s[2] << 8) | s[nl-1]);
  848.     return (rv % numSIDCacheEntries) * sizeof(SIDCacheEntry);
  849. }
  850. /*
  851. ** Look something up in the cache. This will invalidate old entries
  852. ** in the process. Caller has locked the cache!
  853. ** Returns PR_TRUE if found a valid match.  PR_FALSE otherwise.
  854. */
  855. static PRBool 
  856. FindSID(const PRIPv6Addr *addr, unsigned char *sessionID,
  857. unsigned sessionIDLength, SIDCacheEntry *sce)
  858. {
  859.     PRUint32      offset;
  860.     PRUint32      now;
  861.     int           rv;
  862. #ifdef XP_UNIX
  863.     off_t         off;
  864. #endif
  865.     /* Read in cache entry after hashing ip address and session-id value */
  866.     offset = Offset(addr, sessionID, sessionIDLength); 
  867.     now = ssl_Time();
  868.     GET_SERVER_CACHE_READ_LOCK(SIDCacheFD, offset, sizeof *sce);
  869. #ifdef XP_UNIX
  870.     off = lseek(SIDCacheFD, offset, SEEK_SET);
  871.     rv = -1;
  872.     if (off != offset) {
  873. if (off == -1) 
  874.     nss_MD_unix_map_lseek_error(errno);
  875. else 
  876.     PORT_SetError(PR_FILE_SEEK_ERROR);
  877.     } else {
  878. rv = read(SIDCacheFD, sce, sizeof *sce);
  879. if (rv != sizeof *sce) {
  880.     if (rv == -1) 
  881. nss_MD_unix_map_read_error(errno);
  882.     else 
  883. PORT_SetError(PR_IO_ERROR);
  884.      }
  885.     }
  886. #else /* XP_WIN32 */
  887.     /* Use memory mapped I/O and just memcpy() the data */
  888.     CopyMemory(sce, &SIDCacheData[offset], sizeof *sce);
  889.     rv = sizeof *sce;
  890. #endif /* XP_WIN32 */
  891.     RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *sce);
  892.     if (rv != sizeof *sce) {
  893. IOError(rv, "server sid cache read");
  894. return PR_FALSE;
  895.     }
  896.     if (!sce->u.ssl2.valid) {
  897. /* Entry is not valid */
  898. PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
  899. return PR_FALSE;
  900.     }
  901.     if (((sce->u.ssl2.version < SSL_LIBRARY_VERSION_3_0) &&
  902.  (now > sce->time + ssl_sid_timeout)) ||
  903. ((sce->u.ssl2.version >= SSL_LIBRARY_VERSION_3_0) &&
  904.  (now > sce->time + ssl3_sid_timeout))) {
  905. /* SessionID has timed out. Invalidate the entry. */
  906. SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x time+=%x",
  907.     myPid, sce->addr.pr_s6_addr32[0],
  908.     sce->addr.pr_s6_addr32[1], sce->addr.pr_s6_addr32[2],
  909.     sce->addr.pr_s6_addr32[3], now, 
  910.     sce->time + ssl_sid_timeout));
  911. sce->u.ssl2.valid = 0;
  912. GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, offset, sizeof *sce);
  913. #ifdef XP_UNIX
  914. off = lseek(SIDCacheFD, offset, SEEK_SET);
  915. rv = -1;
  916. if (off != offset) {
  917.     if (off == -1) 
  918. nss_MD_unix_map_lseek_error(errno);
  919.     else
  920.      PORT_SetError(PR_IO_ERROR);
  921. } else {
  922.     rv = write(SIDCacheFD, sce, sizeof *sce);
  923.     if (rv != sizeof *sce) {
  924. if (rv == -1) 
  925.     nss_MD_unix_map_write_error(errno);
  926. else 
  927.     PORT_SetError(PR_IO_ERROR);
  928. IOError(rv, "timeout-write");
  929.     }
  930. }
  931. #else /* WIN32 */
  932. /* Use memory mapped I/O and just memcpy() the data */
  933. CopyMemory(&SIDCacheData[offset], sce, sizeof *sce);
  934. rv = sizeof *sce;
  935. #endif /* XP_UNIX */
  936. RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *sce);
  937. if (rv == sizeof *sce)
  938.     PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
  939. return PR_FALSE;
  940.     }
  941.     /*
  942.     ** Finally, examine specific session-id/addr data to see if the cache
  943.     ** entry matches our addr+session-id value
  944.     */
  945.     if (!memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) &&
  946. (PORT_Memcmp(sce->u.ssl2.sessionID, sessionID, sessionIDLength) == 0)) {
  947. /* Found it */
  948. return PR_TRUE;
  949.     }
  950.     PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
  951.     return PR_FALSE;
  952. }
  953. /************************************************************************/
  954. /* This is the primary function for finding entries in the server's sid cache.
  955.  * Although it is static, this function is called via the global function 
  956.  * pointer ssl_sid_lookup.
  957.  */
  958. static sslSessionID *
  959. ServerSessionIDLookup( const PRIPv6Addr  *addr,
  960. unsigned char *sessionID,
  961. unsigned int   sessionIDLength,
  962.                         CERTCertDBHandle * dbHandle)
  963. {
  964.     SIDCacheEntry sce;
  965.     sslSessionID *sid;
  966.     sid = 0;
  967.     lock_cache();
  968.     if (FindSID(addr, sessionID, sessionIDLength, &sce)) {
  969. /* Found it. Convert file format to internal format */
  970. sid = ConvertToSID(&sce, dbHandle);
  971.     }
  972.     unlock_cache();
  973.     return sid;
  974. }
  975. /*
  976. ** Place an sid into the cache, if it isn't already there. Note that if
  977. ** some other server process has replaced a session-id cache entry that has
  978. ** the same cache index as this sid, then all is ok. Somebody has to lose
  979. ** when this condition occurs, so it might as well be this sid.
  980. */
  981. static void 
  982. ServerSessionIDCache(sslSessionID *sid)
  983. {
  984.     SIDCacheEntry sce;
  985.     PRUint32      offset;
  986. #ifdef XP_UNIX
  987.     off_t         off;
  988.     int           rv;
  989. #endif
  990.     uint16 version = sid->version;
  991.     if ((version >= SSL_LIBRARY_VERSION_3_0) &&
  992. (sid->u.ssl3.sessionIDLength == 0)) {
  993. return;
  994.     }
  995.     if (sid->cached == never_cached || sid->cached == invalid_cache) {
  996. lock_cache();
  997. sid->time = ssl_Time();
  998. if (version < SSL_LIBRARY_VERSION_3_0) {
  999.     SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
  1000. "cipher=%d", myPid, sid->cached, 
  1001. sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
  1002. sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
  1003. sid->time, sid->u.ssl2.cipherType));
  1004.     PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID,
  1005.   sizeof(sid->u.ssl2.sessionID)));
  1006.     PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
  1007.   sid->u.ssl2.masterKey.len));
  1008.     PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
  1009.   sid->u.ssl2.cipherArg.len));
  1010.     /* Write out new cache entry */
  1011.     offset = Offset(&sid->addr, sid->u.ssl2.sessionID,
  1012.     sizeof(sid->u.ssl2.sessionID)); 
  1013. } else {
  1014.     SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
  1015. "cipherSuite=%d", myPid, sid->cached, 
  1016. sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
  1017. sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], 
  1018. sid->time, sid->u.ssl3.cipherSuite));
  1019.     PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID,
  1020.   sid->u.ssl3.sessionIDLength));
  1021.     offset = Offset(&sid->addr, sid->u.ssl3.sessionID,
  1022.     sid->u.ssl3.sessionIDLength);
  1023.     
  1024. }
  1025. ConvertFromSID(&sce, sid);
  1026. if (version >= SSL_LIBRARY_VERSION_3_0) {
  1027.     if (sid->peerCert == NULL) {
  1028. sce.u.ssl3.certIndex = -1;
  1029.     } else {
  1030. sce.u.ssl3.certIndex = (int16)
  1031.     ((offset / sizeof(SIDCacheEntry)) % numCertCacheEntries);
  1032.     }
  1033. }
  1034. GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, offset, sizeof sce);
  1035. #ifdef XP_UNIX
  1036. off = lseek(SIDCacheFD, offset, SEEK_SET);
  1037. if (off != offset) {
  1038.     if (off == -1) 
  1039. nss_MD_unix_map_lseek_error(errno);
  1040.     else
  1041.      PORT_SetError(PR_IO_ERROR);
  1042. } else {
  1043.     rv = write(SIDCacheFD, &sce, sizeof sce);
  1044.     if (rv != sizeof(sce)) {
  1045. if (rv == -1) 
  1046.     nss_MD_unix_map_write_error(errno);
  1047. else 
  1048.     PORT_SetError(PR_IO_ERROR);
  1049. IOError(rv, "update-write");
  1050.     }
  1051. }
  1052. #else /* WIN32 */
  1053. CopyMemory(&SIDCacheData[offset], &sce, sizeof sce);
  1054. #endif /* XP_UNIX */
  1055. RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof sce);
  1056. if ((version >= SSL_LIBRARY_VERSION_3_0) && 
  1057.     (sid->peerCert != NULL)) {
  1058.     CacheCert(sid->peerCert, &sce);
  1059. }
  1060. sid->cached = in_server_cache;
  1061. unlock_cache();
  1062.     }
  1063. }
  1064. static void 
  1065. ServerSessionIDUncache(sslSessionID *sid)
  1066. {
  1067.     SIDCacheEntry sce;
  1068.     PRErrorCode   err;
  1069.     int rv;
  1070.     if (sid == NULL) return;
  1071.     
  1072.     /* Uncaching a SID should never change the error code. 
  1073.     ** So save it here and restore it before exiting.
  1074.     */
  1075.     err = PR_GetError();
  1076.     lock_cache();
  1077.     if (sid->version < SSL_LIBRARY_VERSION_3_0) {
  1078. SSL_TRC(8, ("%d: SSL: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
  1079.     "cipher=%d", myPid, sid->cached, 
  1080.     sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
  1081.     sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], 
  1082.     sid->time, sid->u.ssl2.cipherType));
  1083. PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID,
  1084.       sizeof(sid->u.ssl2.sessionID)));
  1085. PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
  1086.       sid->u.ssl2.masterKey.len));
  1087. PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
  1088.       sid->u.ssl2.cipherArg.len));
  1089. rv = FindSID(&sid->addr, sid->u.ssl2.sessionID,
  1090.      sizeof(sid->u.ssl2.sessionID), &sce);
  1091.     } else {
  1092. SSL_TRC(8, ("%d: SSL3: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
  1093.     "cipherSuite=%d", myPid, sid->cached, 
  1094.     sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
  1095.     sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], 
  1096.     sid->time, sid->u.ssl3.cipherSuite));
  1097. PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID,
  1098.       sid->u.ssl3.sessionIDLength));
  1099. rv = FindSID(&sid->addr, sid->u.ssl3.sessionID,
  1100.      sid->u.ssl3.sessionIDLength, &sce);
  1101.     }
  1102.     
  1103.     if (rv) {
  1104. Invalidate(&sce);
  1105.     }
  1106.     sid->cached = invalid_cache;
  1107.     unlock_cache();
  1108.     PORT_SetError(err);
  1109. }
  1110. static SECStatus
  1111. InitSessionIDCache(int maxCacheEntries, PRUint32 timeout,
  1112.    PRUint32 ssl3_timeout, const char *directory)
  1113. {
  1114.     char *cfn;
  1115. #ifdef XP_UNIX
  1116.     int rv;
  1117.     if (SIDCacheFD >= 0) {
  1118. /* Already done */
  1119. return SECSuccess;
  1120.     }
  1121. #else /* WIN32 */
  1122. if(SIDCacheFDMAP != INVALID_HANDLE_VALUE) {
  1123. /* Already done */
  1124. return SECSuccess;
  1125. }
  1126. #endif /* XP_UNIX */
  1127.     if (maxCacheEntries) {
  1128. numSIDCacheEntries = maxCacheEntries;
  1129.     }
  1130.     sidCacheWrapOffset = numSIDCacheEntries * sizeof(SIDCacheEntry);
  1131.     sidCacheFileSize = sidCacheWrapOffset +
  1132.          (kt_kea_size * SSL_NUM_WRAP_MECHS * sizeof(SSLWrappedSymWrappingKey));
  1133.     /* Create file names */
  1134.     cfn = (char*) PORT_Alloc(PORT_Strlen(directory) + 100);
  1135.     if (!cfn) {
  1136. return SECFailure;
  1137.     }
  1138. #ifdef XP_UNIX
  1139.     sprintf(cfn, "%s/.sslsidc.%d", directory, getpid());
  1140. #else /* XP_WIN32 */
  1141. sprintf(cfn, "%s\ssl.sidc.%d.%d", directory,
  1142. GetCurrentProcessId(), GetCurrentThreadId());
  1143. #endif /* XP_WIN32 */
  1144.     /* Create session-id cache file */
  1145. #ifdef XP_UNIX
  1146.     do {
  1147. (void) unlink(cfn);
  1148. SIDCacheFD = open(cfn, O_EXCL|O_CREAT|O_RDWR, 0600);
  1149.     } while (SIDCacheFD < 0 && errno == EEXIST);
  1150.     if (SIDCacheFD < 0) {
  1151. nss_MD_unix_map_open_error(errno);
  1152. IOError(SIDCacheFD, "create");
  1153. goto loser;
  1154.     }
  1155.     rv = unlink(cfn);
  1156.     if (rv < 0) {
  1157. nss_MD_unix_map_unlink_error(errno);
  1158. IOError(rv, "unlink");
  1159. goto loser;
  1160.     }
  1161. #else  /* WIN32 */
  1162.     SIDCacheFDMAP = 
  1163.      CreateFileMapping(INVALID_HANDLE_VALUE, /* allocate in swap file */
  1164.   &sidCacheFDMapAttributes, /* inheritable. */
  1165.   PAGE_READWRITE,
  1166.   0,                    /* size, high word. */
  1167.   sidCacheFileSize,     /* size, low  word. */
  1168.   NULL); /* no map name in FS */
  1169.     if(! SIDCacheFDMAP) {
  1170. nss_MD_win32_map_default_error(GetLastError());
  1171. goto loser;
  1172.     }
  1173.     SIDCacheData = (char *)MapViewOfFile(SIDCacheFDMAP, 
  1174.                                          FILE_MAP_ALL_ACCESS,  /* R/W    */
  1175.  0, 0,  /* offset */
  1176.          sidCacheFileSize); /* size   */
  1177.     if (! SIDCacheData) {
  1178. nss_MD_win32_map_default_error(GetLastError());
  1179. goto loser;
  1180.     }
  1181. #endif /* XP_UNIX */
  1182.     if (!cacheLock)
  1183. nss_InitLock(&cacheLock);
  1184.     if (!cacheLock) {
  1185. SET_ERROR_CODE
  1186. goto loser;
  1187.     }
  1188. #ifdef _WIN32
  1189.     if (isMultiProcess  && (SECSuccess != createServerCacheSemaphore())) {
  1190. SET_ERROR_CODE
  1191. goto loser;
  1192.     }
  1193. #endif
  1194.     if (timeout) {   
  1195. if (timeout > 100) {
  1196.     timeout = 100;
  1197. }
  1198. if (timeout < 5) {
  1199.     timeout = 5;
  1200. }
  1201. ssl_sid_timeout = timeout;
  1202.     }
  1203.     if (ssl3_timeout) {   
  1204. if (ssl3_timeout > 86400L) {
  1205.     ssl3_timeout = 86400L;
  1206. }
  1207. if (ssl3_timeout < 5) {
  1208.     ssl3_timeout = 5;
  1209. }
  1210. ssl3_sid_timeout = ssl3_timeout;
  1211.     }
  1212.     GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, 0, sidCacheFileSize);
  1213. #ifdef XP_UNIX
  1214.     /* Initialize the files */
  1215.     if (ZeroFile(SIDCacheFD, sidCacheFileSize)) {
  1216. /* Bummer */
  1217. close(SIDCacheFD);
  1218. SIDCacheFD = -1;
  1219. goto loser;
  1220.     }
  1221. #else /* XP_WIN32 */
  1222.     ZeroMemory(SIDCacheData, sidCacheFileSize);
  1223. #endif /* XP_UNIX */
  1224.     RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, 0, sidCacheFileSize);
  1225.     PORT_Free(cfn);
  1226.     return SECSuccess;
  1227.   loser:
  1228. #ifdef _WIN32
  1229.     if (svrCacheSem)
  1230. destroyServerCacheSemaphore();
  1231. #endif
  1232.     if (cacheLock) {
  1233. PR_DestroyLock(cacheLock);
  1234. cacheLock = NULL;
  1235.     }
  1236.     PORT_Free(cfn);
  1237.     return SECFailure;
  1238. }
  1239. static SECStatus 
  1240. InitCertCache(const char *directory)
  1241. {
  1242.     char *cfn;
  1243. #ifdef XP_UNIX
  1244.     int rv;
  1245.     if (certCacheFD >= 0) {
  1246. /* Already done */
  1247. return SECSuccess;
  1248.     }
  1249. #else /* WIN32 */
  1250.     if(certCacheFDMAP != INVALID_HANDLE_VALUE) {
  1251. /* Already done */
  1252. return SECSuccess;
  1253.     }
  1254. #endif /* XP_UNIX */
  1255.     numCertCacheEntries = sidCacheFileSize / sizeof(CertCacheEntry);
  1256.     if (numCertCacheEntries < MIN_CERT_CACHE_ENTRIES)
  1257.      numCertCacheEntries = MIN_CERT_CACHE_ENTRIES;
  1258.     certCacheFileSize = numCertCacheEntries * sizeof(CertCacheEntry);
  1259.     /* Create file names */
  1260.     cfn = (char*) PORT_Alloc(PORT_Strlen(directory) + 100);
  1261.     if (!cfn) {
  1262. return SECFailure;
  1263.     }
  1264. #ifdef XP_UNIX
  1265.     sprintf(cfn, "%s/.sslcertc.%d", directory, getpid());
  1266. #else /* XP_WIN32 */
  1267.     sprintf(cfn, "%s\ssl.certc.%d.%d", directory,
  1268.     GetCurrentProcessId(), GetCurrentThreadId());
  1269. #endif /* XP_WIN32 */
  1270.     /* Create certificate cache file */
  1271. #ifdef XP_UNIX
  1272.     do {
  1273. (void) unlink(cfn);
  1274. certCacheFD = open(cfn, O_EXCL|O_CREAT|O_RDWR, 0600);
  1275.     } while (certCacheFD < 0 && errno == EEXIST);
  1276.     if (certCacheFD < 0) {
  1277. nss_MD_unix_map_open_error(errno);
  1278. IOError(certCacheFD, "create");
  1279. goto loser;
  1280.     }
  1281.     rv = unlink(cfn);
  1282.     if (rv < 0) {
  1283. nss_MD_unix_map_unlink_error(errno);
  1284. IOError(rv, "unlink");
  1285. goto loser;
  1286.     }
  1287. #else  /* WIN32 */
  1288.     certCacheFDMAP = 
  1289.      CreateFileMapping(INVALID_HANDLE_VALUE, /* allocate in swap file */
  1290.   &certCacheFDMapAttributes, /* inheritable. */
  1291.   PAGE_READWRITE,
  1292.   0,                /* size, high word. */
  1293.   certCacheFileSize, /* size, low word. */
  1294.   NULL);           /* no map name in FS */
  1295.     if (! certCacheFDMAP) {
  1296. nss_MD_win32_map_default_error(GetLastError());
  1297. goto loser;
  1298.     }
  1299.     certCacheData = (char *) MapViewOfFile(certCacheFDMAP, 
  1300.                                            FILE_MAP_ALL_ACCESS, /* R/W    */
  1301.    0, 0,  /* offset */
  1302.    certCacheFileSize); /* size   */
  1303.     if (! certCacheData) {
  1304. nss_MD_win32_map_default_error(GetLastError());
  1305. goto loser;
  1306.     }
  1307. #endif /* XP_UNIX */
  1308. /*  GET_SERVER_CACHE_WRITE_LOCK(certCacheFD, 0, certCacheFileSize); */
  1309. #ifdef XP_UNIX
  1310.     /* Initialize the files */
  1311.     if (ZeroFile(certCacheFD, certCacheFileSize)) {
  1312. /* Bummer */
  1313. close(certCacheFD);
  1314. certCacheFD = -1;
  1315. goto loser;
  1316.     }
  1317. #else /* XP_WIN32 */
  1318.     ZeroMemory(certCacheData, certCacheFileSize);
  1319. #endif /* XP_UNIX */
  1320. /*  RELEASE_SERVER_CACHE_LOCK(certCacheFD, 0, certCacheFileSize);   */
  1321.     PORT_Free(cfn);
  1322.     return SECSuccess;
  1323.   loser:
  1324.     PORT_Free(cfn);
  1325.     return SECFailure;
  1326. }
  1327. int
  1328. SSL_ConfigServerSessionIDCache( int      maxCacheEntries, 
  1329. PRUint32 timeout,
  1330.         PRUint32 ssl3_timeout, 
  1331.   const char *   directory)
  1332. {
  1333.     SECStatus rv;
  1334.     PORT_Assert(sizeof(SIDCacheEntry) == 256);
  1335.     PORT_Assert(sizeof(CertCacheEntry) == 4096);
  1336.     myPid = SSL_GETPID();
  1337.     if (!directory) {
  1338. directory = DEFAULT_CACHE_DIRECTORY;
  1339.     }
  1340.     rv = InitSessionIDCache(maxCacheEntries, timeout, ssl3_timeout, directory);
  1341.     if (rv) {
  1342. SET_ERROR_CODE
  1343.      return SECFailure;
  1344.     }
  1345.     rv = InitCertCache(directory);
  1346.     if (rv) {
  1347. SET_ERROR_CODE
  1348.      return SECFailure;
  1349.     }
  1350.     ssl_sid_lookup  = ServerSessionIDLookup;
  1351.     ssl_sid_cache   = ServerSessionIDCache;
  1352.     ssl_sid_uncache = ServerSessionIDUncache;
  1353.     return SECSuccess;
  1354. }
  1355. /* Use this function, instead of SSL_ConfigServerSessionIDCache,
  1356.  * if the cache will be shared by multiple processes.
  1357.  */
  1358. int
  1359. SSL_ConfigMPServerSIDCache( int      maxCacheEntries, 
  1360. PRUint32 timeout,
  1361.         PRUint32 ssl3_timeout, 
  1362.           const char *   directory)
  1363. {
  1364.     char * envValue;
  1365.     int  result;
  1366.     SECStatus putEnvFailed;
  1367.     isMultiProcess = PR_TRUE;
  1368.     result = SSL_ConfigServerSessionIDCache(maxCacheEntries, timeout, 
  1369.                                             ssl3_timeout, directory);
  1370.     if (result == SECSuccess) {
  1371. #ifdef _WIN32
  1372. winInheritance winherit;
  1373. winherit.numSIDCacheEntries = numSIDCacheEntries;
  1374. winherit.sidCacheFileSize = sidCacheFileSize;
  1375. winherit.sidCacheWrapOffset = sidCacheWrapOffset;
  1376. winherit.numCertCacheEntries = numCertCacheEntries;
  1377. winherit.certCacheFileSize = certCacheFileSize;
  1378. winherit.SIDCacheFDMAP = SIDCacheFDMAP;
  1379. winherit.certCacheFDMAP = certCacheFDMAP;
  1380. winherit.svrCacheSem = svrCacheSem;
  1381. winherit.parentProcessID = GetCurrentProcessId();
  1382. winherit.parentProcessHandle = 
  1383.     OpenProcess(PROCESS_DUP_HANDLE, TRUE, winherit.parentProcessID);
  1384.         if (winherit.parentProcessHandle == NULL) {
  1385.     SET_ERROR_CODE
  1386.     return SECFailure;
  1387. }
  1388.         envValue = BTOA_DataToAscii((unsigned char *)&winherit, 
  1389.                              sizeof winherit);
  1390.      if (!envValue) {
  1391.     SET_ERROR_CODE
  1392.     return SECFailure;
  1393. }
  1394. #else
  1395. unixInheritance uinherit;
  1396. uinherit.numSIDCacheEntries = numSIDCacheEntries;
  1397. uinherit.sidCacheFileSize = sidCacheFileSize;
  1398. uinherit.sidCacheWrapOffset = sidCacheWrapOffset;
  1399. uinherit.numCertCacheEntries = numCertCacheEntries;
  1400. uinherit.certCacheFileSize = certCacheFileSize;
  1401. uinherit.SIDCacheFD = SIDCacheFD;
  1402. uinherit.certCacheFD = certCacheFD;
  1403.         envValue = BTOA_DataToAscii((unsigned char *)&uinherit, 
  1404.                              sizeof uinherit);
  1405.      if (!envValue) {
  1406.     SET_ERROR_CODE
  1407.     return SECFailure;
  1408. }
  1409. #endif
  1410.     }
  1411.     putEnvFailed = (SECStatus)NSS_PutEnv(envVarName, envValue);
  1412.     PORT_Free(envValue);
  1413.     if (putEnvFailed) {
  1414.         SET_ERROR_CODE
  1415.         result = SECFailure;
  1416.     }
  1417.     return result;
  1418. }
  1419. SECStatus
  1420. SSL_InheritMPServerSIDCache(const char * envString)
  1421. {
  1422.     unsigned char * decoString = NULL;
  1423.     unsigned int    decoLen;
  1424. #ifdef _WIN32
  1425.     winInheritance  inherit;
  1426. #else
  1427.     unixInheritance inherit;
  1428. #endif
  1429.     myPid = SSL_GETPID();
  1430.     if (isMultiProcess)
  1431.      return SECSuccess; /* already done. */
  1432.     ssl_sid_lookup  = ServerSessionIDLookup;
  1433.     ssl_sid_cache   = ServerSessionIDCache;
  1434.     ssl_sid_uncache = ServerSessionIDUncache;
  1435.     if (!envString) {
  1436.      envString  = getenv(envVarName);
  1437. if (!envString) {
  1438.     SET_ERROR_CODE
  1439.     return SECFailure;
  1440. }
  1441.     }
  1442.     decoString = ATOB_AsciiToData(envString, &decoLen);
  1443.     if (!decoString) {
  1444.      SET_ERROR_CODE
  1445. return SECFailure;
  1446.     }
  1447.     if (decoLen != sizeof inherit) {
  1448.      SET_ERROR_CODE
  1449.      goto loser;
  1450.     }
  1451.     PORT_Memcpy(&inherit, decoString, sizeof inherit);
  1452.     PORT_Free(decoString);
  1453.     numSIDCacheEntries = inherit.numSIDCacheEntries;
  1454.     sidCacheFileSize = inherit.sidCacheFileSize;
  1455.     sidCacheWrapOffset = inherit.sidCacheWrapOffset;
  1456.     numCertCacheEntries = inherit.numCertCacheEntries;
  1457.     certCacheFileSize = inherit.certCacheFileSize;
  1458. #ifdef _WIN32
  1459.     SIDCacheFDMAP = inherit.SIDCacheFDMAP;
  1460.     certCacheFDMAP = inherit.certCacheFDMAP;
  1461.     svrCacheSem = inherit.svrCacheSem;
  1462. #if 0
  1463.     /* call DuplicateHandle ?? */
  1464.     inherit.parentProcessID;
  1465.     inherit.parentProcessHandle;
  1466. #endif
  1467.     if(!SIDCacheFDMAP) {
  1468.      SET_ERROR_CODE
  1469.      goto loser;
  1470.     }
  1471.     SIDCacheData = (char *)MapViewOfFile(SIDCacheFDMAP, 
  1472.                                          FILE_MAP_ALL_ACCESS,  /* R/W    */
  1473.  0, 0,  /* offset */
  1474.          sidCacheFileSize); /* size   */
  1475.     if(!SIDCacheData) {
  1476. nss_MD_win32_map_default_error(GetLastError());
  1477.      goto loser;
  1478.     }
  1479.     if(!certCacheFDMAP) {
  1480.      SET_ERROR_CODE
  1481.      goto loser;
  1482.     }
  1483.     certCacheData = (char *) MapViewOfFile(certCacheFDMAP, 
  1484.                                            FILE_MAP_ALL_ACCESS, /* R/W    */
  1485.    0, 0,  /* offset */
  1486.    certCacheFileSize); /* size   */
  1487.     if(!certCacheData) {
  1488. nss_MD_win32_map_default_error(GetLastError());
  1489.      goto loser;
  1490.     }
  1491. #else /* must be unix */
  1492.     SIDCacheFD = inherit.SIDCacheFD;
  1493.     certCacheFD = inherit.certCacheFD;
  1494.     if (SIDCacheFD < 0 || certCacheFD < 0) {
  1495.      SET_ERROR_CODE
  1496.      goto loser;
  1497.     }
  1498. #endif
  1499.     if (!cacheLock) {
  1500. nss_InitLock(&cacheLock);
  1501. if (!cacheLock) 
  1502.     goto loser;
  1503.     }
  1504.     isMultiProcess = PR_TRUE;
  1505.     return SECSuccess;
  1506. loser:
  1507.     if (decoString) 
  1508. PORT_Free(decoString);
  1509. #if _WIN32
  1510.     if (SIDCacheFDMAP) {
  1511. CloseHandle(SIDCacheFDMAP);
  1512. SIDCacheFDMAP = NULL;
  1513.     }
  1514.     if (certCacheFDMAP) {
  1515. CloseHandle(certCacheFDMAP);
  1516. certCacheFDMAP = NULL;
  1517.     }
  1518. #else
  1519.     if (SIDCacheFD >= 0) {
  1520. close(SIDCacheFD);
  1521. SIDCacheFD = -1;
  1522.     }
  1523.     if (certCacheFD >= 0) {
  1524. close(certCacheFD);
  1525. certCacheFD = -1;
  1526.     }
  1527. #endif
  1528.     return SECFailure;
  1529. }
  1530. /************************************************************************
  1531.  *  Code dealing with shared wrapped symmetric wrapping keys below      *
  1532.  ************************************************************************/
  1533. static PRBool
  1534. getWrappingKey(PRInt32                   symWrapMechIndex,
  1535.                SSL3KEAType               exchKeyType, 
  1536.                SSLWrappedSymWrappingKey *wswk, 
  1537.                PRBool                    grabSharedLock)
  1538. {
  1539.     PRUint32      offset = sidCacheWrapOffset + 
  1540.        ((exchKeyType * SSL_NUM_WRAP_MECHS + symWrapMechIndex) *
  1541.    sizeof(SSLWrappedSymWrappingKey));
  1542.     PRBool        rv     = PR_TRUE;
  1543. #ifdef XP_UNIX
  1544.     off_t         lrv;
  1545.     ssize_t       rrv;
  1546. #endif
  1547.     if (grabSharedLock) {
  1548. GET_SERVER_CACHE_READ_LOCK(SIDCacheFD, offset, sizeof *wswk);
  1549.     }
  1550. #ifdef XP_UNIX
  1551.     lrv = lseek(SIDCacheFD, offset, SEEK_SET);
  1552.     if (lrv != offset) {
  1553. if (lrv == -1) 
  1554.     nss_MD_unix_map_lseek_error(errno);
  1555. else
  1556.     PORT_SetError(PR_IO_ERROR);
  1557.     IOError(rv, "wrapping-read");
  1558. rv = PR_FALSE;
  1559.     } else {
  1560. rrv = read(SIDCacheFD, wswk, sizeof *wswk);
  1561. if (rrv != sizeof *wswk) {
  1562.     if (rrv == -1) 
  1563. nss_MD_unix_map_read_error(errno);
  1564.     else 
  1565. PORT_SetError(PR_IO_ERROR);
  1566.     IOError(rv, "wrapping-read");
  1567.     rv = PR_FALSE;
  1568. }
  1569.     }
  1570. #else /* XP_WIN32 */
  1571.     /* Use memory mapped I/O and just memcpy() the data */
  1572.     CopyMemory(wswk, &SIDCacheData[offset], sizeof *wswk);
  1573. #endif /* XP_WIN32 */
  1574.     if (grabSharedLock) {
  1575. RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *wswk);
  1576.     }
  1577.     if (rv) {
  1578.      if (wswk->exchKeyType      != exchKeyType || 
  1579.     wswk->symWrapMechIndex != symWrapMechIndex ||
  1580.     wswk->wrappedSymKeyLen == 0) {
  1581.     memset(wswk, 0, sizeof *wswk);
  1582.     rv = PR_FALSE;
  1583. }
  1584.     }
  1585.     return rv;
  1586. }
  1587. PRBool
  1588. ssl_GetWrappingKey( PRInt32                   symWrapMechIndex,
  1589.                     SSL3KEAType               exchKeyType, 
  1590.     SSLWrappedSymWrappingKey *wswk)
  1591. {
  1592.     PRBool rv;
  1593.     lock_cache();
  1594.     PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
  1595.     PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
  1596.     if ((unsigned)exchKeyType < kt_kea_size &&
  1597.         (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) {
  1598. rv = getWrappingKey(symWrapMechIndex, exchKeyType, wswk, PR_TRUE);
  1599.     } else {
  1600.      rv = PR_FALSE;
  1601.     }
  1602.     unlock_cache();
  1603.     return rv;
  1604. }
  1605. /* The caller passes in the new value it wants
  1606.  * to set.  This code tests the wrapped sym key entry in the file on disk.  
  1607.  * If it is uninitialized, this function writes the caller's value into 
  1608.  * the disk entry, and returns false.  
  1609.  * Otherwise, it overwrites the caller's wswk with the value obtained from 
  1610.  * the disk, and returns PR_TRUE.  
  1611.  * This is all done while holding the locks/semaphores necessary to make 
  1612.  * the operation atomic.
  1613.  */
  1614. PRBool
  1615. ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
  1616. {
  1617.     PRBool        rv;
  1618.     SSL3KEAType   exchKeyType      = wswk->exchKeyType;   
  1619.                                 /* type of keys used to wrap SymWrapKey*/
  1620.     PRInt32       symWrapMechIndex = wswk->symWrapMechIndex;
  1621.     PRUint32      offset;
  1622.     SSLWrappedSymWrappingKey myWswk;
  1623.     PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
  1624.     if ((unsigned)exchKeyType >= kt_kea_size)
  1625.      return 0;
  1626.     PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
  1627.     if ((unsigned)symWrapMechIndex >=  SSL_NUM_WRAP_MECHS)
  1628.      return 0;
  1629.     offset = sidCacheWrapOffset + 
  1630.        ((exchKeyType * SSL_NUM_WRAP_MECHS + symWrapMechIndex) *
  1631.    sizeof(SSLWrappedSymWrappingKey));
  1632.     PORT_Memset(&myWswk, 0, sizeof myWswk); /* eliminate UMRs. */
  1633.     lock_cache();
  1634.     GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, offset, sizeof *wswk);
  1635.     rv = getWrappingKey(wswk->symWrapMechIndex, wswk->exchKeyType, &myWswk, 
  1636.                         PR_FALSE);
  1637.     if (rv) {
  1638. /* we found it on disk, copy it out to the caller. */
  1639. PORT_Memcpy(wswk, &myWswk, sizeof *wswk);
  1640.     } else {
  1641. /* Wasn't on disk, and we're still holding the lock, so write it. */
  1642. #ifdef XP_UNIX
  1643. off_t         lrv;
  1644. ssize_t       rrv;
  1645. lrv = lseek(SIDCacheFD, offset, SEEK_SET);
  1646. if (lrv != offset) {
  1647.     if (lrv == -1) 
  1648. nss_MD_unix_map_lseek_error(errno);
  1649.     else
  1650. PORT_SetError(PR_IO_ERROR);
  1651.     IOError(rv, "wrapping-read");
  1652.     rv = PR_FALSE;
  1653. } else {
  1654.     rrv = write(SIDCacheFD, wswk, sizeof *wswk);
  1655.     if (rrv != sizeof *wswk) {
  1656. if (rrv == -1) 
  1657.     nss_MD_unix_map_read_error(errno);
  1658. else 
  1659.     PORT_SetError(PR_IO_ERROR);
  1660. IOError(rv, "wrapping-read");
  1661. rv = PR_FALSE;
  1662.     }
  1663. }
  1664. #else /* XP_WIN32 */
  1665. /* Use memory mapped I/O and just memcpy() the data */
  1666. CopyMemory(&SIDCacheData[offset], wswk, sizeof *wswk);
  1667. #endif /* XP_WIN32 */
  1668.     }
  1669.     RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *wswk);
  1670.     unlock_cache();
  1671.     return rv;
  1672. }
  1673. #endif /* NADA_VERISON */
  1674. #else
  1675. #include "seccomon.h"
  1676. #include "cert.h"
  1677. #include "ssl.h"
  1678. #include "sslimpl.h"
  1679. PRBool
  1680. ssl_GetWrappingKey( PRInt32                   symWrapMechIndex,
  1681.                     SSL3KEAType               exchKeyType, 
  1682.     SSLWrappedSymWrappingKey *wswk)
  1683. {
  1684.     PRBool rv = PR_FALSE;
  1685.     PR_ASSERT(!"SSL servers are not supported on the Mac. (ssl_GetWrappingKey)");    
  1686.     return rv;
  1687. }
  1688. /* This is a kind of test-and-set.  The caller passes in the new value it wants
  1689.  * to set.  This code tests the wrapped sym key entry in the file on disk.  
  1690.  * If it is uninitialized, this function writes the caller's value into 
  1691.  * the disk entry, and returns false.  
  1692.  * Otherwise, it overwrites the caller's wswk with the value obtained from 
  1693.  * the disk, and returns PR_TRUE.  
  1694.  * This is all done while holding the locks/semaphores necessary to make 
  1695.  * the operation atomic.
  1696.  */
  1697. PRBool
  1698. ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
  1699. {
  1700.     PRBool        rv = PR_FALSE;
  1701.     PR_ASSERT(!"SSL servers are not supported on the Mac. (ssl_SetWrappingKey)");
  1702.     return rv;
  1703. }
  1704. #endif /* XP_UNIX || XP_WIN32 */