diff options
Diffstat (limited to 'security/nss/lib/ssl/sslsnce.c')
-rw-r--r-- | security/nss/lib/ssl/sslsnce.c | 1905 |
1 files changed, 0 insertions, 1905 deletions
diff --git a/security/nss/lib/ssl/sslsnce.c b/security/nss/lib/ssl/sslsnce.c deleted file mode 100644 index bf58c954d..000000000 --- a/security/nss/lib/ssl/sslsnce.c +++ /dev/null @@ -1,1905 +0,0 @@ -/* This file implements the SERVER Session ID cache. - * NOTE: The contents of this file are NOT used by the client. - * - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - * - * $Id$ - */ - -/* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server - * cache sids! - * - * About record locking among different server processes: - * - * All processes that are part of the same conceptual server (serving on - * the same address and port) MUST share a common SSL session cache. - * This code makes the content of the shared cache accessible to all - * processes on the same "server". This code works on Unix and Win32 only, - * and is platform specific. - * - * Unix: Multiple processes share a single (inherited) FD for a disk - * file all share one single file position. If one lseeks, the position for - * all processes is changed. Since the set of platforms we support do not - * all share portable lseek-and-read or lseek-and-write functions, a global - * lock must be used to make the lseek call and the subsequent read or write - * call be one atomic operation. It is no longer necessary for cache element - * sizes to be a power of 2, or a multiple of a sector size. - * - * For Win32, where (a) disk I/O is not atomic, and (b) we use memory-mapped - * files and move data to & from memory instead of calling read or write, - * we must do explicit locking of the records for all reads and writes. - * We have just one lock, for the entire file, using an NT semaphore. - * We avoid blocking on "local threads" since it's bad to block on a local - * thread - If NSPR offered portable semaphores, it would handle this itself. - * - * Since this file has to do lots of platform specific I/O, the system - * dependent error codes need to be mapped back into NSPR error codes. - * Since NSPR's error mapping functions are private, the code is necessarily - * duplicated in libSSL. - * - * Note, now that NSPR provides portable anonymous shared memory, for all - * platforms except Mac, the implementation below should be replaced with - * one that uses anonymous shared memory ASAP. This will eliminate most - * platform dependent code in this file, and improve performance big time. - * - * Now that NSPR offers portable cross-process locking (semaphores) on Unix - * and Win32, semaphores should be used here for all platforms. - */ -#include "seccomon.h" - -#if defined(XP_UNIX) || defined(XP_WIN32) -#ifndef NADA_VERISON - -#include "cert.h" -#include "ssl.h" -#include "sslimpl.h" -#include "sslproto.h" -#include "pk11func.h" -#include "base64.h" - -#include <stdio.h> - -#ifdef XP_UNIX - -#include <syslog.h> -#include <fcntl.h> -#include <unistd.h> -#include "unix_err.h" - -#else /* XP_WIN32 */ -#ifdef MC_HTTPD -#include <ereport.h> -#endif /* MC_HTTPD */ -#include <wtypes.h> -#include "win32err.h" -#endif /* XP_WIN32 */ -#include <sys/types.h> - -#define SET_ERROR_CODE /* reminder */ - -#include "nspr.h" -#include "nsslocks.h" - -static PRLock *cacheLock; - -/* -** The server session-id cache uses a simple flat cache. The cache is -** sized during initialization. We hash the ip-address + session-id value -** into an index into the cache and do the lookup. No buckets, nothing -** fancy. -*/ - -static PRBool isMultiProcess = PR_FALSE; - -static PRUint32 numSIDCacheEntries = 10000; -static PRUint32 sidCacheFileSize; -static PRUint32 sidCacheWrapOffset; - -static PRUint32 numCertCacheEntries = 250; -static PRUint32 certCacheFileSize; - -#define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */ - - -/* -** Format of a cache entry. -*/ -typedef struct SIDCacheEntryStr SIDCacheEntry; -struct SIDCacheEntryStr { - PRUint32 addr; - PRUint32 time; - - union { - struct { - /* This is gross. We have to have version and valid in both arms - * of the union for alignment reasons. This probably won't work - * on a 64-bit machine. XXXX - */ -/* 2 */ uint16 version; -/* 1 */ unsigned char valid; -/* 1 */ unsigned char cipherType; - -/* 16 */ unsigned char sessionID[SSL_SESSIONID_BYTES]; -/* 64 */ unsigned char masterKey[SSL_MAX_MASTER_KEY_BYTES]; -/* 32 */ unsigned char cipherArg[SSL_MAX_CYPHER_ARG_BYTES]; - -/* 1 */ unsigned char masterKeyLen; -/* 1 */ unsigned char keyBits; - -/* 1 */ unsigned char secretKeyBits; -/* 1 */ unsigned char cipherArgLen; -/*120 */} ssl2; - - struct { -/* 2 */ uint16 version; -/* 1 */ unsigned char valid; -/* 1 */ uint8 sessionIDLength; - -/* 32 */ unsigned char sessionID[SSL3_SESSIONID_BYTES]; - -/* 2 */ ssl3CipherSuite cipherSuite; -/* 2 */ uint16 compression; /* SSL3CompressionMethod */ - -/*122 */ ssl3SidKeys keys; /* keys and ivs, wrapped as needed. */ -/* 4 */ PRUint32 masterWrapMech; -/* 4 */ SSL3KEAType exchKeyType; - -/* 2 */ int16 certIndex; -/* 1 */ uint8 hasFortezza; -/* 1 */ uint8 resumable; - } ssl3; - /* We can't make this struct fit in 128 bytes - * so, force the struct size up to the next power of two. - */ - struct { - unsigned char filler[248]; /* 248 + 4 + 4 == 256 */ - } force256; - } u; -}; - - -typedef struct CertCacheEntryStr CertCacheEntry; - -/* The length of this struct is supposed to be a power of 2, e.g. 4KB */ -struct CertCacheEntryStr { - uint16 certLength; /* 2 */ - uint16 sessionIDLength; /* 2 */ - unsigned char sessionID[SSL3_SESSIONID_BYTES]; /* 32 */ - unsigned char cert[SSL_MAX_CACHED_CERT_LEN]; /* 4060 */ -}; /* total 4096 */ - - -static void IOError(int rv, char *type); -static PRUint32 Offset(PRUint32 addr, unsigned char *s, unsigned nl); -static void Invalidate(SIDCacheEntry *sce); - -/************************************************************************/ - -static const char envVarName[] = { SSL_ENV_VAR_NAME }; - -#ifdef _WIN32 - -struct winInheritanceStr { - PRUint32 numSIDCacheEntries; - PRUint32 sidCacheFileSize; - PRUint32 sidCacheWrapOffset; - PRUint32 numCertCacheEntries; - PRUint32 certCacheFileSize; - - DWORD parentProcessID; - HANDLE parentProcessHandle; - HANDLE SIDCacheFDMAP; - HANDLE certCacheFDMAP; - HANDLE svrCacheSem; -}; - -typedef struct winInheritanceStr winInheritance; - -static HANDLE svrCacheSem = INVALID_HANDLE_VALUE; - -static char * SIDCacheData = NULL; -static HANDLE SIDCacheFD = INVALID_HANDLE_VALUE; -static HANDLE SIDCacheFDMAP = INVALID_HANDLE_VALUE; - -static char * certCacheData = NULL; -static HANDLE certCacheFD = INVALID_HANDLE_VALUE; -static HANDLE certCacheFDMAP = INVALID_HANDLE_VALUE; - -static PRUint32 myPid; - -/* The presence of the TRUE element in this struct makes the semaphore - * inheritable. The NULL means use process's default security descriptor. - */ -static SECURITY_ATTRIBUTES semaphoreAttributes = - { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; - -static SECURITY_ATTRIBUTES sidCacheFDMapAttributes = - { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; - -static SECURITY_ATTRIBUTES certCacheFDMapAttributes = - { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; - -#define DEFAULT_CACHE_DIRECTORY "\\temp" - -static SECStatus -createServerCacheSemaphore(void) -{ - PR_ASSERT(svrCacheSem == INVALID_HANDLE_VALUE); - - /* inheritable, starts signalled, 1 signal max, no file name. */ - svrCacheSem = CreateSemaphore(&semaphoreAttributes, 1, 1, NULL); - if (svrCacheSem == NULL) { - svrCacheSem = INVALID_HANDLE_VALUE; - /* We could get the error code, but what could be do with it ? */ - nss_MD_win32_map_default_error(GetLastError()); - return SECFailure; - } - return SECSuccess; -} - -static SECStatus -_getServerCacheSemaphore(void) -{ - DWORD event; - DWORD lastError; - SECStatus rv; - - PR_ASSERT(svrCacheSem != INVALID_HANDLE_VALUE); - if (svrCacheSem == INVALID_HANDLE_VALUE && - SECSuccess != createServerCacheSemaphore()) { - return SECFailure; /* what else ? */ - } - event = WaitForSingleObject(svrCacheSem, INFINITE); - switch (event) { - case WAIT_OBJECT_0: - case WAIT_ABANDONED: - rv = SECSuccess; - break; - - case WAIT_TIMEOUT: - case WAIT_IO_COMPLETION: - default: /* should never happen. nothing we can do. */ - PR_ASSERT(("WaitForSingleObject returned invalid value.", 0)); - /* fall thru */ - - case WAIT_FAILED: /* failure returns this */ - rv = SECFailure; - lastError = GetLastError(); /* for debugging */ - nss_MD_win32_map_default_error(lastError); - break; - } - return rv; -} - -static void -_doGetServerCacheSemaphore(void * arg) -{ - SECStatus * rv = (SECStatus *)arg; - *rv = _getServerCacheSemaphore(); -} - -static SECStatus -getServerCacheSemaphore(void) -{ - PRThread * selectThread; - PRThread * me = PR_GetCurrentThread(); - PRThreadScope scope = PR_GetThreadScope(me); - SECStatus rv = SECFailure; - - if (scope == PR_GLOBAL_THREAD) { - rv = _getServerCacheSemaphore(); - } else { - selectThread = PR_CreateThread(PR_USER_THREAD, - _doGetServerCacheSemaphore, &rv, - PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, - PR_JOINABLE_THREAD, 0); - if (selectThread != NULL) { - /* rv will be set by _doGetServerCacheSemaphore() */ - PR_JoinThread(selectThread); - } - } - return rv; -} - -static SECStatus -releaseServerCacheSemaphore(void) -{ - BOOL success = FALSE; - - PR_ASSERT(svrCacheSem != INVALID_HANDLE_VALUE); - if (svrCacheSem != INVALID_HANDLE_VALUE) { - /* Add 1, don't want previous value. */ - success = ReleaseSemaphore(svrCacheSem, 1, NULL); - } - if (!success) { - nss_MD_win32_map_default_error(GetLastError()); - return SECFailure; - } - return SECSuccess; -} - -static void -destroyServerCacheSemaphore(void) -{ - PR_ASSERT(svrCacheSem != INVALID_HANDLE_VALUE); - if (svrCacheSem != INVALID_HANDLE_VALUE) { - CloseHandle(svrCacheSem); - /* ignore error */ - svrCacheSem = INVALID_HANDLE_VALUE; - } -} - -#define GET_SERVER_CACHE_READ_LOCK(fd, offset, size) \ - if (isMultiProcess) getServerCacheSemaphore(); - -#define GET_SERVER_CACHE_WRITE_LOCK(fd, offset, size) \ - if (isMultiProcess) getServerCacheSemaphore(); - -#define RELEASE_SERVER_CACHE_LOCK(fd, offset, size) \ - if (isMultiProcess) releaseServerCacheSemaphore(); - -#endif /* _win32 */ - -/************************************************************************/ - -#ifdef XP_UNIX -static int SIDCacheFD = -1; -static int certCacheFD = -1; - -static pid_t myPid; - -struct unixInheritanceStr { - PRUint32 numSIDCacheEntries; - PRUint32 sidCacheFileSize; - PRUint32 sidCacheWrapOffset; - PRUint32 numCertCacheEntries; - PRUint32 certCacheFileSize; - - PRInt32 SIDCacheFD; - PRInt32 certCacheFD; -}; - -typedef struct unixInheritanceStr unixInheritance; - - -#define DEFAULT_CACHE_DIRECTORY "/tmp" - -#ifdef TRACE -static void -fcntlFailed(struct flock *lock) -{ - fprintf(stderr, - "fcntl failed, errno = %d, PR_GetError = %d, lock.l_type = %d\n", - errno, PR_GetError(), lock->l_type); - fflush(stderr); -} -#define FCNTL_FAILED(lock) fcntlFailed(lock) -#else -#define FCNTL_FAILED(lock) -#endif - -/* NOTES: Because there are no atomic seek-and-read and seek-and-write -** functions that are supported on all our UNIX platforms, we need -** to prevent all simultaeous seek-and-read operations. For that reason, -** we use mutually exclusive (write) locks for read and write operations, -** and use them all at the same offset (zero). -*/ -static SECStatus -_getServerCacheLock(int fd, short type, PRUint32 offset, PRUint32 size) -{ - int result; - struct flock lock; - - memset(&lock, 0, sizeof lock); - lock.l_type = /* type */ F_WRLCK; - lock.l_whence = SEEK_SET; /* absolute file offsets. */ - lock.l_start = 0; - lock.l_len = 128; - -#ifdef TRACE - if (ssl_trace) { - fprintf(stderr, "%d: %s lock, offset %8x, size %4d\n", myPid, - (type == F_RDLCK) ? "read " : "write", offset, size); - fflush(stderr); - } -#endif - result = fcntl(fd, F_SETLKW, &lock); - if (result == -1) { - nss_MD_unix_map_default_error(errno); - FCNTL_FAILED(&lock); - return SECFailure; - } -#ifdef TRACE - if (ssl_trace) { - fprintf(stderr, "%d: got lock, offset %8x, size %4d\n", - myPid, offset, size); - fflush(stderr); - } -#endif - return SECSuccess; -} - -typedef struct sslLockArgsStr { - PRUint32 offset; - PRUint32 size; - PRErrorCode err; - SECStatus rv; - int fd; - short type; -} sslLockArgs; - -static void -_doGetServerCacheLock(void * arg) -{ - sslLockArgs * args = (sslLockArgs *)arg; - args->rv = _getServerCacheLock(args->fd, args->type, args->offset, - args->size ); - if (args->rv != SECSuccess) { - args->err = PR_GetError(); - } -} - -static SECStatus -getServerCacheLock(int fd, short type, PRUint32 offset, PRUint32 size) -{ - PRThread * selectThread; - PRThread * me = PR_GetCurrentThread(); - PRThreadScope scope = PR_GetThreadScope(me); - SECStatus rv = SECFailure; - - if (scope == PR_GLOBAL_THREAD) { - rv = _getServerCacheLock(fd, type, offset, size); - } else { - /* Ib some platforms, one thread cannot read local/automatic - ** variables from another thread's stack. So, get this space - ** from the heap, not the stack. - */ - sslLockArgs * args = PORT_New(sslLockArgs); - - if (!args) - return rv; - - args->offset = offset; - args->size = size; - args->rv = SECFailure; - args->fd = fd; - args->type = type; - selectThread = PR_CreateThread(PR_USER_THREAD, - _doGetServerCacheLock, args, - PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, - PR_JOINABLE_THREAD, 0); - if (selectThread != NULL) { - /* rv will be set by _doGetServerCacheLock() */ - PR_JoinThread(selectThread); - rv = args->rv; - if (rv != SECSuccess) { - PORT_SetError(args->err); - } - } - PORT_Free(args); - } - return rv; -} - -static SECStatus -releaseServerCacheLock(int fd, PRUint32 offset, PRUint32 size) -{ - int result; - struct flock lock; - - memset(&lock, 0, sizeof lock); - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; /* absolute file offsets. */ - lock.l_start = 0; - lock.l_len = 128; - -#ifdef TRACE - if (ssl_trace) { - fprintf(stderr, "%d: unlock, offset %8x, size %4d\n", - myPid, offset, size); - fflush(stderr); - } -#endif - result = fcntl(fd, F_SETLK, &lock); - if (result == -1) { - nss_MD_unix_map_default_error(errno); - FCNTL_FAILED(&lock); - return SECFailure; - } - return SECSuccess; -} - - -/* these defines take the arguments needed to do record locking, - * however the present implementation does only file locking. - */ - -#define GET_SERVER_CACHE_READ_LOCK( fd, offset, size) \ - if (isMultiProcess) getServerCacheLock(fd, F_RDLCK, offset, size); - -#define GET_SERVER_CACHE_WRITE_LOCK(fd, offset, size) \ - if (isMultiProcess) getServerCacheLock(fd, F_WRLCK, offset, size); - -#define RELEASE_SERVER_CACHE_LOCK( fd, offset, size) \ - if (isMultiProcess) releaseServerCacheLock(fd, offset, size); - -/* -** Zero a file out to nb bytes -*/ -static SECStatus -ZeroFile(int fd, int nb) -{ - off_t off; - int amount, rv; - char buf[16384]; - - PORT_Memset(buf, 0, sizeof(buf)); - off = lseek(fd, 0, SEEK_SET); - if (off != 0) { - if (off == -1) - nss_MD_unix_map_lseek_error(errno); - else - PORT_SetError(PR_FILE_SEEK_ERROR); - return SECFailure; - } - - while (nb > 0) { - amount = (nb > sizeof buf) ? sizeof buf : nb; - rv = write(fd, buf, amount); - if (rv <= 0) { - if (!rv) - PORT_SetError(PR_IO_ERROR); - else - nss_MD_unix_map_write_error(errno); - IOError(rv, "zero-write"); - return SECFailure; - } - nb -= rv; - } - return SECSuccess; -} - -#endif /* XP_UNIX */ - - -/************************************************************************/ - -/* -** Reconstitute a cert from the cache -** This is only called from ConvertToSID(). -** Caller must hold the cache lock before calling this. -*/ -static CERTCertificate * -GetCertFromCache(SIDCacheEntry *sce, CERTCertDBHandle *dbHandle) -{ - CERTCertificate *cert; - PRUint32 offset; - int rv; -#ifdef XP_UNIX - off_t off; -#endif - SECItem derCert; - CertCacheEntry cce; - - offset = (PRUint32)sce->u.ssl3.certIndex * sizeof(CertCacheEntry); - GET_SERVER_CACHE_READ_LOCK(certCacheFD, offset, sizeof(CertCacheEntry)); -#ifdef XP_UNIX - off = lseek(certCacheFD, offset, SEEK_SET); - rv = -1; - if (off != offset) { - if (off == -1) - nss_MD_unix_map_lseek_error(errno); - else - PORT_SetError(PR_FILE_SEEK_ERROR); - } else { - rv = read(certCacheFD, &cce, sizeof(CertCacheEntry)); - if (rv != sizeof(CertCacheEntry)) { - if (rv == -1) - nss_MD_unix_map_read_error(errno); - else - PORT_SetError(PR_IO_ERROR); - } - } -#else /* XP_WIN32 */ - /* Use memory mapped I/O and just memcpy() the data */ - CopyMemory(&cce, &certCacheData[offset], sizeof(CertCacheEntry)); - rv = sizeof cce; -#endif /* XP_WIN32 */ - RELEASE_SERVER_CACHE_LOCK(certCacheFD, offset, sizeof(CertCacheEntry)) - - if (rv != sizeof(CertCacheEntry)) { - IOError(rv, "read"); /* error set above */ - return NULL; - } - - /* See if the session ID matches with that in the sce cache. */ - if((cce.sessionIDLength != sce->u.ssl3.sessionIDLength) || - PORT_Memcmp(cce.sessionID, sce->u.ssl3.sessionID, cce.sessionIDLength)) { - /* this is a cache miss, not an error */ - PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND); - return NULL; - } - - derCert.len = cce.certLength; - derCert.data = cce.cert; - - cert = CERT_NewTempCertificate(dbHandle, &derCert, NULL, - PR_FALSE, PR_TRUE); - - return cert; -} - -/* Put a certificate in the cache. We assume that the certIndex in -** sid is valid. -*/ -static void -CacheCert(CERTCertificate *cert, SIDCacheEntry *sce) -{ - PRUint32 offset; - CertCacheEntry cce; -#ifdef XP_UNIX - off_t off; - int rv; -#endif - - offset = (PRUint32)sce->u.ssl3.certIndex * sizeof(CertCacheEntry); - if (cert->derCert.len > SSL_MAX_CACHED_CERT_LEN) - return; - - cce.sessionIDLength = sce->u.ssl3.sessionIDLength; - PORT_Memcpy(cce.sessionID, sce->u.ssl3.sessionID, cce.sessionIDLength); - - cce.certLength = cert->derCert.len; - PORT_Memcpy(cce.cert, cert->derCert.data, cce.certLength); - - GET_SERVER_CACHE_WRITE_LOCK(certCacheFD, offset, sizeof cce); -#ifdef XP_UNIX - off = lseek(certCacheFD, offset, SEEK_SET); - if (off != offset) { - if (off == -1) - nss_MD_unix_map_lseek_error(errno); - else - PORT_SetError(PR_FILE_SEEK_ERROR); - } else { - rv = write(certCacheFD, &cce, sizeof cce); - if (rv != sizeof(CertCacheEntry)) { - if (rv == -1) - nss_MD_unix_map_write_error(errno); - else - PORT_SetError(PR_IO_ERROR); - IOError(rv, "cert-write"); - Invalidate(sce); - } - } -#else /* WIN32 */ - /* Use memory mapped I/O and just memcpy() the data */ - CopyMemory(&certCacheData[offset], &cce, sizeof cce); -#endif /* XP_UNIX */ - - RELEASE_SERVER_CACHE_LOCK(certCacheFD, offset, sizeof cce); - return; -} - -/* -** Convert memory based SID to file based one -*/ -static void -ConvertFromSID(SIDCacheEntry *to, sslSessionID *from) -{ - to->u.ssl2.valid = 1; - to->u.ssl2.version = from->version; - to->addr = from->addr; - to->time = from->time; - - if (from->version < SSL_LIBRARY_VERSION_3_0) { - if ((from->u.ssl2.masterKey.len > SSL_MAX_MASTER_KEY_BYTES) || - (from->u.ssl2.cipherArg.len > SSL_MAX_CYPHER_ARG_BYTES)) { - SSL_DBG(("%d: SSL: masterKeyLen=%d cipherArgLen=%d", - myPid, from->u.ssl2.masterKey.len, - from->u.ssl2.cipherArg.len)); - to->u.ssl2.valid = 0; - return; - } - - to->u.ssl2.cipherType = from->u.ssl2.cipherType; - to->u.ssl2.masterKeyLen = from->u.ssl2.masterKey.len; - to->u.ssl2.cipherArgLen = from->u.ssl2.cipherArg.len; - to->u.ssl2.keyBits = from->u.ssl2.keyBits; - to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits; - PORT_Memcpy(to->u.ssl2.sessionID, from->u.ssl2.sessionID, - sizeof(to->u.ssl2.sessionID)); - PORT_Memcpy(to->u.ssl2.masterKey, from->u.ssl2.masterKey.data, - from->u.ssl2.masterKey.len); - PORT_Memcpy(to->u.ssl2.cipherArg, from->u.ssl2.cipherArg.data, - from->u.ssl2.cipherArg.len); -#ifdef DEBUG - PORT_Memset(to->u.ssl2.masterKey+from->u.ssl2.masterKey.len, 0, - sizeof(to->u.ssl2.masterKey) - from->u.ssl2.masterKey.len); - PORT_Memset(to->u.ssl2.cipherArg+from->u.ssl2.cipherArg.len, 0, - sizeof(to->u.ssl2.cipherArg) - from->u.ssl2.cipherArg.len); -#endif - SSL_TRC(8, ("%d: SSL: ConvertSID: masterKeyLen=%d cipherArgLen=%d " - "time=%d addr=0x%x cipherType=%d", myPid, - to->u.ssl2.masterKeyLen, to->u.ssl2.cipherArgLen, - to->time, to->addr, to->u.ssl2.cipherType)); - } else { - /* This is an SSL v3 session */ - - to->u.ssl3.sessionIDLength = from->u.ssl3.sessionIDLength; - to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite; - to->u.ssl3.compression = (uint16)from->u.ssl3.compression; - to->u.ssl3.resumable = from->u.ssl3.resumable; - to->u.ssl3.hasFortezza = from->u.ssl3.hasFortezza; - to->u.ssl3.keys = from->u.ssl3.keys; - to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech; - to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType; - - PORT_Memcpy(to->u.ssl3.sessionID, - from->u.ssl3.sessionID, - from->u.ssl3.sessionIDLength); - - SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%x cipherSuite=%d", - myPid, to->time, to->addr, to->u.ssl3.cipherSuite)); - } -} - -/* -** Convert file based cache-entry to memory based one -** This is only called from ServerSessionIDLookup(). -** Caller must hold cache lock when calling this. -*/ -static sslSessionID * -ConvertToSID(SIDCacheEntry *from, CERTCertDBHandle * dbHandle) -{ - sslSessionID *to; - uint16 version = from->u.ssl2.version; - - to = (sslSessionID*) PORT_ZAlloc(sizeof(sslSessionID)); - if (!to) { - return 0; - } - - if (version < SSL_LIBRARY_VERSION_3_0) { - /* This is an SSL v2 session */ - to->u.ssl2.masterKey.data = - (unsigned char*) PORT_Alloc(from->u.ssl2.masterKeyLen); - if (!to->u.ssl2.masterKey.data) { - goto loser; - } - if (from->u.ssl2.cipherArgLen) { - to->u.ssl2.cipherArg.data = (unsigned char*) - PORT_Alloc(from->u.ssl2.cipherArgLen); - if (!to->u.ssl2.cipherArg.data) { - goto loser; - } - PORT_Memcpy(to->u.ssl2.cipherArg.data, from->u.ssl2.cipherArg, - from->u.ssl2.cipherArgLen); - } - - to->u.ssl2.cipherType = from->u.ssl2.cipherType; - to->u.ssl2.masterKey.len = from->u.ssl2.masterKeyLen; - to->u.ssl2.cipherArg.len = from->u.ssl2.cipherArgLen; - to->u.ssl2.keyBits = from->u.ssl2.keyBits; - to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits; - PORT_Memcpy(to->u.ssl2.sessionID, from->u.ssl2.sessionID, - sizeof from->u.ssl2.sessionID); - PORT_Memcpy(to->u.ssl2.masterKey.data, from->u.ssl2.masterKey, - from->u.ssl2.masterKeyLen); - - SSL_TRC(8, ("%d: SSL: ConvertToSID: masterKeyLen=%d cipherArgLen=%d " - "time=%d addr=0x%x cipherType=%d", - myPid, to->u.ssl2.masterKey.len, - to->u.ssl2.cipherArg.len, to->time, to->addr, - to->u.ssl2.cipherType)); - } else { - /* This is an SSL v3 session */ - - to->u.ssl3.sessionIDLength = from->u.ssl3.sessionIDLength; - to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite; - to->u.ssl3.compression = (SSL3CompressionMethod)from->u.ssl3.compression; - to->u.ssl3.resumable = from->u.ssl3.resumable; - to->u.ssl3.hasFortezza = from->u.ssl3.hasFortezza; - to->u.ssl3.keys = from->u.ssl3.keys; - to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech; - to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType; - - PORT_Memcpy(to->u.ssl3.sessionID, - from->u.ssl3.sessionID, - from->u.ssl3.sessionIDLength); - - /* the portions of the SID that are only restored on the client - * are set to invalid values on the server. - */ - to->u.ssl3.clientWriteKey = NULL; - to->u.ssl3.serverWriteKey = NULL; - to->u.ssl3.tek = NULL; - to->urlSvrName = NULL; - - to->u.ssl3.masterModuleID = (SECMODModuleID)-1; /* invalid value */ - to->u.ssl3.masterSlotID = (CK_SLOT_ID)-1; /* invalid value */ - to->u.ssl3.masterWrapIndex = 0; - to->u.ssl3.masterWrapSeries = 0; - to->u.ssl3.masterValid = PR_FALSE; - - to->u.ssl3.clAuthModuleID = (SECMODModuleID)-1; /* invalid value */ - to->u.ssl3.clAuthSlotID = (CK_SLOT_ID)-1; /* invalid value */ - to->u.ssl3.clAuthSeries = 0; - to->u.ssl3.clAuthValid = PR_FALSE; - - to->u.ssl3.clientWriteSaveLen = 0; - - if (from->u.ssl3.certIndex != -1) { - to->peerCert = GetCertFromCache(from, dbHandle); - if (to->peerCert == NULL) - goto loser; - } - } - - to->version = from->u.ssl2.version; - to->time = from->time; - to->cached = in_server_cache; - to->addr = from->addr; - to->references = 1; - - return to; - - loser: - Invalidate(from); - if (to) { - if (version < SSL_LIBRARY_VERSION_3_0) { - if (to->u.ssl2.masterKey.data) - PORT_Free(to->u.ssl2.masterKey.data); - if (to->u.ssl2.cipherArg.data) - PORT_Free(to->u.ssl2.cipherArg.data); - } - PORT_Free(to); - } - return NULL; -} - - -/* Invalidate a SID cache entry. - * Called from CacheCert, ConvertToSid, and ServerSessionIDUncache. - */ -static void -Invalidate(SIDCacheEntry *sce) -{ - PRUint32 offset; -#ifdef XP_UNIX - off_t off; - int rv; -#endif - - if (sce == NULL) return; - - if (sce->u.ssl2.version < SSL_LIBRARY_VERSION_3_0) { - offset = Offset(sce->addr, sce->u.ssl2.sessionID, - sizeof sce->u.ssl2.sessionID); - } else { - offset = Offset(sce->addr, sce->u.ssl3.sessionID, - sce->u.ssl3.sessionIDLength); - } - - sce->u.ssl2.valid = 0; - SSL_TRC(7, ("%d: SSL: uncaching session-id at offset %ld", - myPid, offset)); - - GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, offset, sizeof *sce); - -#ifdef XP_UNIX - off = lseek(SIDCacheFD, offset, SEEK_SET); - if (off != offset) { - if (off == -1) - nss_MD_unix_map_lseek_error(errno); - else - PORT_SetError(PR_FILE_SEEK_ERROR); - } else { - rv = write(SIDCacheFD, sce, sizeof *sce); - if (rv != sizeof *sce) { - if (rv == -1) - nss_MD_unix_map_write_error(errno); - else - PORT_SetError(PR_IO_ERROR); - IOError(rv, "invalidate-write"); - } - } -#else /* WIN32 */ - /* Use memory mapped I/O and just memcpy() the data */ - CopyMemory(&SIDCacheData[offset], sce, sizeof *sce); -#endif /* XP_UNIX */ - - RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *sce); -} - - -static void -IOError(int rv, char *type) -{ -#ifdef XP_UNIX - syslog(LOG_ALERT, - "SSL: %s error with session-id cache, pid=%d, rv=%d, error='%m'", - type, myPid, rv); -#else /* XP_WIN32 */ -#ifdef MC_HTTPD - ereport(LOG_FAILURE, "%s error with session-id cache rv=%d\n",type, rv); -#endif /* MC_HTTPD */ -#endif /* XP_UNIX */ -} - -static void -lock_cache(void) -{ - PR_Lock(cacheLock); -} - -static void -unlock_cache(void) -{ - PR_Unlock(cacheLock); -} - -/* -** Perform some mumbo jumbo on the ip-address and the session-id value to -** compute a hash value. -*/ -static PRUint32 -Offset(PRUint32 addr, unsigned char *s, unsigned nl) -{ - PRUint32 rv; - - rv = addr ^ (((PRUint32)s[0] << 24) | ((PRUint32)s[1] << 16) - | (s[2] << 8) | s[nl-1]); - return (rv % numSIDCacheEntries) * sizeof(SIDCacheEntry); -} - - - -/* -** Look something up in the cache. This will invalidate old entries -** in the process. Caller has locked the cache! -** Returns PR_TRUE if found a valid match. PR_FALSE otherwise. -*/ -static PRBool -FindSID(PRUint32 addr, unsigned char *sessionID, - unsigned sessionIDLength, SIDCacheEntry *sce) -{ - PRUint32 offset; - PRUint32 now; - int rv; -#ifdef XP_UNIX - off_t off; -#endif - - /* Read in cache entry after hashing ip address and session-id value */ - offset = Offset(addr, sessionID, sessionIDLength); - now = ssl_Time(); - GET_SERVER_CACHE_READ_LOCK(SIDCacheFD, offset, sizeof *sce); -#ifdef XP_UNIX - off = lseek(SIDCacheFD, offset, SEEK_SET); - rv = -1; - if (off != offset) { - if (off == -1) - nss_MD_unix_map_lseek_error(errno); - else - PORT_SetError(PR_FILE_SEEK_ERROR); - } else { - rv = read(SIDCacheFD, sce, sizeof *sce); - if (rv != sizeof *sce) { - if (rv == -1) - nss_MD_unix_map_read_error(errno); - else - PORT_SetError(PR_IO_ERROR); - } - } -#else /* XP_WIN32 */ - /* Use memory mapped I/O and just memcpy() the data */ - CopyMemory(sce, &SIDCacheData[offset], sizeof *sce); - rv = sizeof *sce; -#endif /* XP_WIN32 */ - RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *sce); - - if (rv != sizeof *sce) { - IOError(rv, "server sid cache read"); - return PR_FALSE; - } - - if (!sce->u.ssl2.valid) { - /* Entry is not valid */ - PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND); - return PR_FALSE; - } - - if (((sce->u.ssl2.version < SSL_LIBRARY_VERSION_3_0) && - (now > sce->time + ssl_sid_timeout)) || - ((sce->u.ssl2.version >= SSL_LIBRARY_VERSION_3_0) && - (now > sce->time + ssl3_sid_timeout))) { - /* SessionID has timed out. Invalidate the entry. */ - SSL_TRC(7, ("%d: timed out sid entry addr=%08x now=%x time+=%x", - myPid, sce->addr, now, sce->time + ssl_sid_timeout)); - sce->u.ssl2.valid = 0; - - GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, offset, sizeof *sce); -#ifdef XP_UNIX - off = lseek(SIDCacheFD, offset, SEEK_SET); - rv = -1; - if (off != offset) { - if (off == -1) - nss_MD_unix_map_lseek_error(errno); - else - PORT_SetError(PR_IO_ERROR); - } else { - rv = write(SIDCacheFD, sce, sizeof *sce); - if (rv != sizeof *sce) { - if (rv == -1) - nss_MD_unix_map_write_error(errno); - else - PORT_SetError(PR_IO_ERROR); - IOError(rv, "timeout-write"); - } - } -#else /* WIN32 */ - /* Use memory mapped I/O and just memcpy() the data */ - CopyMemory(&SIDCacheData[offset], sce, sizeof *sce); - rv = sizeof *sce; -#endif /* XP_UNIX */ - RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *sce); - if (rv == sizeof *sce) - PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND); - return PR_FALSE; - } - - /* - ** Finally, examine specific session-id/addr data to see if the cache - ** entry matches our addr+session-id value - */ - if ((sce->addr == addr) && - (PORT_Memcmp(sce->u.ssl2.sessionID, sessionID, sessionIDLength) == 0)) { - /* Found it */ - return PR_TRUE; - } - PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND); - return PR_FALSE; -} - -/************************************************************************/ - -/* This is the primary function for finding entries in the server's sid cache. - * Although it is static, this function is called via the global function - * pointer ssl_sid_lookup. - */ -static sslSessionID * -ServerSessionIDLookup( PRUint32 addr, - unsigned char *sessionID, - unsigned int sessionIDLength, - CERTCertDBHandle * dbHandle) -{ - SIDCacheEntry sce; - sslSessionID *sid; - - sid = 0; - lock_cache(); - if (FindSID(addr, sessionID, sessionIDLength, &sce)) { - /* Found it. Convert file format to internal format */ - sid = ConvertToSID(&sce, dbHandle); - } - unlock_cache(); - return sid; -} - -/* -** Place an sid into the cache, if it isn't already there. Note that if -** some other server process has replaced a session-id cache entry that has -** the same cache index as this sid, then all is ok. Somebody has to lose -** when this condition occurs, so it might as well be this sid. -*/ -static void -ServerSessionIDCache(sslSessionID *sid) -{ - SIDCacheEntry sce; - PRUint32 offset; -#ifdef XP_UNIX - off_t off; - int rv; -#endif - uint16 version = sid->version; - - if ((version >= SSL_LIBRARY_VERSION_3_0) && - (sid->u.ssl3.sessionIDLength == 0)) { - return; - } - - if (sid->cached == never_cached || sid->cached == invalid_cache) { - lock_cache(); - - sid->time = ssl_Time(); - if (version < SSL_LIBRARY_VERSION_3_0) { - SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x time=%x " - "cipher=%d", myPid, sid->cached, sid->addr, - sid->time, sid->u.ssl2.cipherType)); - PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID, - sizeof(sid->u.ssl2.sessionID))); - PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data, - sid->u.ssl2.masterKey.len)); - PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data, - sid->u.ssl2.cipherArg.len)); - - /* Write out new cache entry */ - offset = Offset(sid->addr, sid->u.ssl2.sessionID, - sizeof(sid->u.ssl2.sessionID)); - } else { - SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x time=%x " - "cipherSuite=%d", myPid, sid->cached, sid->addr, - sid->time, sid->u.ssl3.cipherSuite)); - PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID, - sid->u.ssl3.sessionIDLength)); - - offset = Offset(sid->addr, sid->u.ssl3.sessionID, - sid->u.ssl3.sessionIDLength); - - } - - ConvertFromSID(&sce, sid); - if (version >= SSL_LIBRARY_VERSION_3_0) { - if (sid->peerCert == NULL) { - sce.u.ssl3.certIndex = -1; - } else { - sce.u.ssl3.certIndex = (int16) - ((offset / sizeof(SIDCacheEntry)) % numCertCacheEntries); - } - } - - GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, offset, sizeof sce); -#ifdef XP_UNIX - off = lseek(SIDCacheFD, offset, SEEK_SET); - if (off != offset) { - if (off == -1) - nss_MD_unix_map_lseek_error(errno); - else - PORT_SetError(PR_IO_ERROR); - } else { - rv = write(SIDCacheFD, &sce, sizeof sce); - if (rv != sizeof(sce)) { - if (rv == -1) - nss_MD_unix_map_write_error(errno); - else - PORT_SetError(PR_IO_ERROR); - IOError(rv, "update-write"); - } - } -#else /* WIN32 */ - CopyMemory(&SIDCacheData[offset], &sce, sizeof sce); -#endif /* XP_UNIX */ - RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof sce); - - if ((version >= SSL_LIBRARY_VERSION_3_0) && - (sid->peerCert != NULL)) { - CacheCert(sid->peerCert, &sce); - } - - sid->cached = in_server_cache; - unlock_cache(); - } -} - -static void -ServerSessionIDUncache(sslSessionID *sid) -{ - SIDCacheEntry sce; - int rv; - - if (sid == NULL) return; - - lock_cache(); - if (sid->version < SSL_LIBRARY_VERSION_3_0) { - SSL_TRC(8, ("%d: SSL: UncacheMT: valid=%d addr=0x%08x time=%x " - "cipher=%d", myPid, sid->cached, sid->addr, - sid->time, sid->u.ssl2.cipherType)); - PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID, - sizeof(sid->u.ssl2.sessionID))); - PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data, - sid->u.ssl2.masterKey.len)); - PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data, - sid->u.ssl2.cipherArg.len)); - rv = FindSID(sid->addr, sid->u.ssl2.sessionID, - sizeof(sid->u.ssl2.sessionID), &sce); - } else { - SSL_TRC(8, ("%d: SSL3: UncacheMT: valid=%d addr=0x%08x time=%x " - "cipherSuite=%d", myPid, sid->cached, sid->addr, - sid->time, sid->u.ssl3.cipherSuite)); - PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID, - sid->u.ssl3.sessionIDLength)); - rv = FindSID(sid->addr, sid->u.ssl3.sessionID, - sid->u.ssl3.sessionIDLength, &sce); - } - - if (rv) { - Invalidate(&sce); - } - sid->cached = invalid_cache; - unlock_cache(); -} - -static SECStatus -InitSessionIDCache(int maxCacheEntries, PRUint32 timeout, - PRUint32 ssl3_timeout, const char *directory) -{ - char *cfn; -#ifdef XP_UNIX - int rv; - if (SIDCacheFD >= 0) { - /* Already done */ - return SECSuccess; - } -#else /* WIN32 */ - if(SIDCacheFDMAP != INVALID_HANDLE_VALUE) { - /* Already done */ - return SECSuccess; - } -#endif /* XP_UNIX */ - - - if (maxCacheEntries) { - numSIDCacheEntries = maxCacheEntries; - } - sidCacheWrapOffset = numSIDCacheEntries * sizeof(SIDCacheEntry); - sidCacheFileSize = sidCacheWrapOffset + - (kt_kea_size * SSL_NUM_WRAP_MECHS * sizeof(SSLWrappedSymWrappingKey)); - - /* Create file names */ - cfn = (char*) PORT_Alloc(PORT_Strlen(directory) + 100); - if (!cfn) { - return SECFailure; - } -#ifdef XP_UNIX - sprintf(cfn, "%s/.sslsidc.%d", directory, getpid()); -#else /* XP_WIN32 */ - sprintf(cfn, "%s\\ssl.sidc.%d.%d", directory, - GetCurrentProcessId(), GetCurrentThreadId()); -#endif /* XP_WIN32 */ - - /* Create session-id cache file */ -#ifdef XP_UNIX - do { - (void) unlink(cfn); - SIDCacheFD = open(cfn, O_EXCL|O_CREAT|O_RDWR, 0600); - } while (SIDCacheFD < 0 && errno == EEXIST); - if (SIDCacheFD < 0) { - nss_MD_unix_map_open_error(errno); - IOError(SIDCacheFD, "create"); - goto loser; - } - rv = unlink(cfn); - if (rv < 0) { - nss_MD_unix_map_unlink_error(errno); - IOError(rv, "unlink"); - goto loser; - } -#else /* WIN32 */ - SIDCacheFDMAP = - CreateFileMapping(INVALID_HANDLE_VALUE, /* allocate in swap file */ - &sidCacheFDMapAttributes, /* inheritable. */ - PAGE_READWRITE, - 0, /* size, high word. */ - sidCacheFileSize, /* size, low word. */ - NULL); /* no map name in FS */ - if(! SIDCacheFDMAP) { - nss_MD_win32_map_default_error(GetLastError()); - goto loser; - } - SIDCacheData = (char *)MapViewOfFile(SIDCacheFDMAP, - FILE_MAP_ALL_ACCESS, /* R/W */ - 0, 0, /* offset */ - sidCacheFileSize); /* size */ - if (! SIDCacheData) { - nss_MD_win32_map_default_error(GetLastError()); - goto loser; - } -#endif /* XP_UNIX */ - - if (!cacheLock) - nss_InitLock(&cacheLock); - if (!cacheLock) { - SET_ERROR_CODE - goto loser; - } -#ifdef _WIN32 - if (isMultiProcess && (SECSuccess != createServerCacheSemaphore())) { - SET_ERROR_CODE - goto loser; - } -#endif - - if (timeout) { - if (timeout > 100) { - timeout = 100; - } - if (timeout < 5) { - timeout = 5; - } - ssl_sid_timeout = timeout; - } - - if (ssl3_timeout) { - if (ssl3_timeout > 86400L) { - ssl3_timeout = 86400L; - } - if (ssl3_timeout < 5) { - ssl3_timeout = 5; - } - ssl3_sid_timeout = ssl3_timeout; - } - - GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, 0, sidCacheFileSize); -#ifdef XP_UNIX - /* Initialize the files */ - if (ZeroFile(SIDCacheFD, sidCacheFileSize)) { - /* Bummer */ - close(SIDCacheFD); - SIDCacheFD = -1; - goto loser; - } -#else /* XP_WIN32 */ - ZeroMemory(SIDCacheData, sidCacheFileSize); -#endif /* XP_UNIX */ - RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, 0, sidCacheFileSize); - PORT_Free(cfn); - return SECSuccess; - - loser: -#ifdef _WIN32 - if (svrCacheSem) - destroyServerCacheSemaphore(); -#endif - if (cacheLock) { - PR_DestroyLock(cacheLock); - cacheLock = NULL; - } - PORT_Free(cfn); - return SECFailure; -} - -static SECStatus -InitCertCache(const char *directory) -{ - char *cfn; -#ifdef XP_UNIX - int rv; - if (certCacheFD >= 0) { - /* Already done */ - return SECSuccess; - } -#else /* WIN32 */ - if(certCacheFDMAP != INVALID_HANDLE_VALUE) { - /* Already done */ - return SECSuccess; - } -#endif /* XP_UNIX */ - - numCertCacheEntries = sidCacheFileSize / sizeof(CertCacheEntry); - if (numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) - numCertCacheEntries = MIN_CERT_CACHE_ENTRIES; - certCacheFileSize = numCertCacheEntries * sizeof(CertCacheEntry); - - /* Create file names */ - cfn = (char*) PORT_Alloc(PORT_Strlen(directory) + 100); - if (!cfn) { - return SECFailure; - } -#ifdef XP_UNIX - sprintf(cfn, "%s/.sslcertc.%d", directory, getpid()); -#else /* XP_WIN32 */ - sprintf(cfn, "%s\\ssl.certc.%d.%d", directory, - GetCurrentProcessId(), GetCurrentThreadId()); -#endif /* XP_WIN32 */ - - /* Create certificate cache file */ -#ifdef XP_UNIX - do { - (void) unlink(cfn); - certCacheFD = open(cfn, O_EXCL|O_CREAT|O_RDWR, 0600); - } while (certCacheFD < 0 && errno == EEXIST); - if (certCacheFD < 0) { - nss_MD_unix_map_open_error(errno); - IOError(certCacheFD, "create"); - goto loser; - } - rv = unlink(cfn); - if (rv < 0) { - nss_MD_unix_map_unlink_error(errno); - IOError(rv, "unlink"); - goto loser; - } -#else /* WIN32 */ - certCacheFDMAP = - CreateFileMapping(INVALID_HANDLE_VALUE, /* allocate in swap file */ - &certCacheFDMapAttributes, /* inheritable. */ - PAGE_READWRITE, - 0, /* size, high word. */ - certCacheFileSize, /* size, low word. */ - NULL); /* no map name in FS */ - if (! certCacheFDMAP) { - nss_MD_win32_map_default_error(GetLastError()); - goto loser; - } - certCacheData = (char *) MapViewOfFile(certCacheFDMAP, - FILE_MAP_ALL_ACCESS, /* R/W */ - 0, 0, /* offset */ - certCacheFileSize); /* size */ - if (! certCacheData) { - nss_MD_win32_map_default_error(GetLastError()); - goto loser; - } -#endif /* XP_UNIX */ - -/* GET_SERVER_CACHE_WRITE_LOCK(certCacheFD, 0, certCacheFileSize); */ -#ifdef XP_UNIX - /* Initialize the files */ - if (ZeroFile(certCacheFD, certCacheFileSize)) { - /* Bummer */ - close(certCacheFD); - certCacheFD = -1; - goto loser; - } -#else /* XP_WIN32 */ - ZeroMemory(certCacheData, certCacheFileSize); -#endif /* XP_UNIX */ -/* RELEASE_SERVER_CACHE_LOCK(certCacheFD, 0, certCacheFileSize); */ - PORT_Free(cfn); - return SECSuccess; - - loser: - PORT_Free(cfn); - return SECFailure; -} - -int -SSL_ConfigServerSessionIDCache( int maxCacheEntries, - PRUint32 timeout, - PRUint32 ssl3_timeout, - const char * directory) -{ - SECStatus rv; - - PORT_Assert(sizeof(SIDCacheEntry) == 256); - PORT_Assert(sizeof(CertCacheEntry) == 4096); - - myPid = SSL_GETPID(); - if (!directory) { - directory = DEFAULT_CACHE_DIRECTORY; - } - rv = InitSessionIDCache(maxCacheEntries, timeout, ssl3_timeout, directory); - if (rv) { - SET_ERROR_CODE - return SECFailure; - } - rv = InitCertCache(directory); - if (rv) { - SET_ERROR_CODE - return SECFailure; - } - - ssl_sid_lookup = ServerSessionIDLookup; - ssl_sid_cache = ServerSessionIDCache; - ssl_sid_uncache = ServerSessionIDUncache; - return SECSuccess; -} - -/* Use this function, instead of SSL_ConfigServerSessionIDCache, - * if the cache will be shared by multiple processes. - */ -int -SSL_ConfigMPServerSIDCache( int maxCacheEntries, - PRUint32 timeout, - PRUint32 ssl3_timeout, - const char * directory) -{ - char * envValue; - int result; - SECStatus putEnvFailed; - - isMultiProcess = PR_TRUE; - result = SSL_ConfigServerSessionIDCache(maxCacheEntries, timeout, - ssl3_timeout, directory); - if (result == SECSuccess) { -#ifdef _WIN32 - winInheritance winherit; - - winherit.numSIDCacheEntries = numSIDCacheEntries; - winherit.sidCacheFileSize = sidCacheFileSize; - winherit.sidCacheWrapOffset = sidCacheWrapOffset; - winherit.numCertCacheEntries = numCertCacheEntries; - winherit.certCacheFileSize = certCacheFileSize; - winherit.SIDCacheFDMAP = SIDCacheFDMAP; - winherit.certCacheFDMAP = certCacheFDMAP; - winherit.svrCacheSem = svrCacheSem; - winherit.parentProcessID = GetCurrentProcessId(); - winherit.parentProcessHandle = - OpenProcess(PROCESS_DUP_HANDLE, TRUE, winherit.parentProcessID); - if (winherit.parentProcessHandle == NULL) { - SET_ERROR_CODE - return SECFailure; - } - envValue = BTOA_DataToAscii((unsigned char *)&winherit, - sizeof winherit); - if (!envValue) { - SET_ERROR_CODE - return SECFailure; - } -#else - unixInheritance uinherit; - - uinherit.numSIDCacheEntries = numSIDCacheEntries; - uinherit.sidCacheFileSize = sidCacheFileSize; - uinherit.sidCacheWrapOffset = sidCacheWrapOffset; - uinherit.numCertCacheEntries = numCertCacheEntries; - uinherit.certCacheFileSize = certCacheFileSize; - uinherit.SIDCacheFD = SIDCacheFD; - uinherit.certCacheFD = certCacheFD; - - envValue = BTOA_DataToAscii((unsigned char *)&uinherit, - sizeof uinherit); - if (!envValue) { - SET_ERROR_CODE - return SECFailure; - } -#endif - } - putEnvFailed = (SECStatus)NSS_PutEnv(envVarName, envValue); - PORT_Free(envValue); - if (putEnvFailed) { - SET_ERROR_CODE - result = SECFailure; - } - return result; -} - -SECStatus -SSL_InheritMPServerSIDCache(const char * envString) -{ - unsigned char * decoString = NULL; - unsigned int decoLen; -#ifdef _WIN32 - winInheritance inherit; -#else - unixInheritance inherit; -#endif - - myPid = SSL_GETPID(); - if (isMultiProcess) - return SECSuccess; /* already done. */ - - ssl_sid_lookup = ServerSessionIDLookup; - ssl_sid_cache = ServerSessionIDCache; - ssl_sid_uncache = ServerSessionIDUncache; - - if (!envString) { - envString = getenv(envVarName); - if (!envString) { - SET_ERROR_CODE - return SECFailure; - } - } - - decoString = ATOB_AsciiToData(envString, &decoLen); - if (!decoString) { - SET_ERROR_CODE - return SECFailure; - } - if (decoLen != sizeof inherit) { - SET_ERROR_CODE - goto loser; - } - - PORT_Memcpy(&inherit, decoString, sizeof inherit); - PORT_Free(decoString); - - numSIDCacheEntries = inherit.numSIDCacheEntries; - sidCacheFileSize = inherit.sidCacheFileSize; - sidCacheWrapOffset = inherit.sidCacheWrapOffset; - numCertCacheEntries = inherit.numCertCacheEntries; - certCacheFileSize = inherit.certCacheFileSize; - -#ifdef _WIN32 - SIDCacheFDMAP = inherit.SIDCacheFDMAP; - certCacheFDMAP = inherit.certCacheFDMAP; - svrCacheSem = inherit.svrCacheSem; - -#if 0 - /* call DuplicateHandle ?? */ - inherit.parentProcessID; - inherit.parentProcessHandle; -#endif - - if(!SIDCacheFDMAP) { - SET_ERROR_CODE - goto loser; - } - SIDCacheData = (char *)MapViewOfFile(SIDCacheFDMAP, - FILE_MAP_ALL_ACCESS, /* R/W */ - 0, 0, /* offset */ - sidCacheFileSize); /* size */ - if(!SIDCacheData) { - nss_MD_win32_map_default_error(GetLastError()); - goto loser; - } - - if(!certCacheFDMAP) { - SET_ERROR_CODE - goto loser; - } - certCacheData = (char *) MapViewOfFile(certCacheFDMAP, - FILE_MAP_ALL_ACCESS, /* R/W */ - 0, 0, /* offset */ - certCacheFileSize); /* size */ - if(!certCacheData) { - nss_MD_win32_map_default_error(GetLastError()); - goto loser; - } - -#else /* must be unix */ - SIDCacheFD = inherit.SIDCacheFD; - certCacheFD = inherit.certCacheFD; - if (SIDCacheFD < 0 || certCacheFD < 0) { - SET_ERROR_CODE - goto loser; - } -#endif - - if (!cacheLock) { - nss_InitLock(&cacheLock); - if (!cacheLock) - goto loser; - } - isMultiProcess = PR_TRUE; - return SECSuccess; - -loser: - if (decoString) - PORT_Free(decoString); -#if _WIN32 - if (SIDCacheFDMAP) { - CloseHandle(SIDCacheFDMAP); - SIDCacheFDMAP = NULL; - } - if (certCacheFDMAP) { - CloseHandle(certCacheFDMAP); - certCacheFDMAP = NULL; - } -#else - if (SIDCacheFD >= 0) { - close(SIDCacheFD); - SIDCacheFD = -1; - } - if (certCacheFD >= 0) { - close(certCacheFD); - certCacheFD = -1; - } -#endif - return SECFailure; - -} - -/************************************************************************ - * Code dealing with shared wrapped symmetric wrapping keys below * - ************************************************************************/ - - -static PRBool -getWrappingKey(PRInt32 symWrapMechIndex, - SSL3KEAType exchKeyType, - SSLWrappedSymWrappingKey *wswk, - PRBool grabSharedLock) -{ - PRUint32 offset = sidCacheWrapOffset + - ((exchKeyType * SSL_NUM_WRAP_MECHS + symWrapMechIndex) * - sizeof(SSLWrappedSymWrappingKey)); - PRBool rv = PR_TRUE; -#ifdef XP_UNIX - off_t lrv; - ssize_t rrv; -#endif - - if (grabSharedLock) { - GET_SERVER_CACHE_READ_LOCK(SIDCacheFD, offset, sizeof *wswk); - } - -#ifdef XP_UNIX - lrv = lseek(SIDCacheFD, offset, SEEK_SET); - if (lrv != offset) { - if (lrv == -1) - nss_MD_unix_map_lseek_error(errno); - else - PORT_SetError(PR_IO_ERROR); - IOError(rv, "wrapping-read"); - rv = PR_FALSE; - } else { - rrv = read(SIDCacheFD, wswk, sizeof *wswk); - if (rrv != sizeof *wswk) { - if (rrv == -1) - nss_MD_unix_map_read_error(errno); - else - PORT_SetError(PR_IO_ERROR); - IOError(rv, "wrapping-read"); - rv = PR_FALSE; - } - } -#else /* XP_WIN32 */ - /* Use memory mapped I/O and just memcpy() the data */ - CopyMemory(wswk, &SIDCacheData[offset], sizeof *wswk); -#endif /* XP_WIN32 */ - if (grabSharedLock) { - RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *wswk); - } - if (rv) { - if (wswk->exchKeyType != exchKeyType || - wswk->symWrapMechIndex != symWrapMechIndex || - wswk->wrappedSymKeyLen == 0) { - memset(wswk, 0, sizeof *wswk); - rv = PR_FALSE; - } - } - return rv; -} - -PRBool -ssl_GetWrappingKey( PRInt32 symWrapMechIndex, - SSL3KEAType exchKeyType, - SSLWrappedSymWrappingKey *wswk) -{ - PRBool rv; - - lock_cache(); - - PORT_Assert( (unsigned)exchKeyType < kt_kea_size); - PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS); - if ((unsigned)exchKeyType < kt_kea_size && - (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) { - rv = getWrappingKey(symWrapMechIndex, exchKeyType, wswk, PR_TRUE); - } else { - rv = PR_FALSE; - } - unlock_cache(); - return rv; -} - -/* The caller passes in the new value it wants - * to set. This code tests the wrapped sym key entry in the file on disk. - * If it is uninitialized, this function writes the caller's value into - * the disk entry, and returns false. - * Otherwise, it overwrites the caller's wswk with the value obtained from - * the disk, and returns PR_TRUE. - * This is all done while holding the locks/semaphores necessary to make - * the operation atomic. - */ -PRBool -ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk) -{ - PRBool rv; - SSL3KEAType exchKeyType = wswk->exchKeyType; - /* type of keys used to wrap SymWrapKey*/ - PRInt32 symWrapMechIndex = wswk->symWrapMechIndex; - PRUint32 offset; - SSLWrappedSymWrappingKey myWswk; - - PORT_Assert( (unsigned)exchKeyType < kt_kea_size); - if ((unsigned)exchKeyType >= kt_kea_size) - return 0; - - PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS); - if ((unsigned)symWrapMechIndex >= SSL_NUM_WRAP_MECHS) - return 0; - - offset = sidCacheWrapOffset + - ((exchKeyType * SSL_NUM_WRAP_MECHS + symWrapMechIndex) * - sizeof(SSLWrappedSymWrappingKey)); - PORT_Memset(&myWswk, 0, sizeof myWswk); /* eliminate UMRs. */ - lock_cache(); - GET_SERVER_CACHE_WRITE_LOCK(SIDCacheFD, offset, sizeof *wswk); - - rv = getWrappingKey(wswk->symWrapMechIndex, wswk->exchKeyType, &myWswk, - PR_FALSE); - if (rv) { - /* we found it on disk, copy it out to the caller. */ - PORT_Memcpy(wswk, &myWswk, sizeof *wswk); - } else { - /* Wasn't on disk, and we're still holding the lock, so write it. */ - -#ifdef XP_UNIX - off_t lrv; - ssize_t rrv; - - lrv = lseek(SIDCacheFD, offset, SEEK_SET); - if (lrv != offset) { - if (lrv == -1) - nss_MD_unix_map_lseek_error(errno); - else - PORT_SetError(PR_IO_ERROR); - IOError(rv, "wrapping-read"); - rv = PR_FALSE; - } else { - rrv = write(SIDCacheFD, wswk, sizeof *wswk); - if (rrv != sizeof *wswk) { - if (rrv == -1) - nss_MD_unix_map_read_error(errno); - else - PORT_SetError(PR_IO_ERROR); - IOError(rv, "wrapping-read"); - rv = PR_FALSE; - } - } -#else /* XP_WIN32 */ - /* Use memory mapped I/O and just memcpy() the data */ - CopyMemory(&SIDCacheData[offset], wswk, sizeof *wswk); -#endif /* XP_WIN32 */ - } - RELEASE_SERVER_CACHE_LOCK(SIDCacheFD, offset, sizeof *wswk); - unlock_cache(); - return rv; -} - - -#endif /* NADA_VERISON */ -#else - -#include "seccomon.h" -#include "cert.h" -#include "ssl.h" -#include "sslimpl.h" - -PRBool -ssl_GetWrappingKey( PRInt32 symWrapMechIndex, - SSL3KEAType exchKeyType, - SSLWrappedSymWrappingKey *wswk) -{ - PRBool rv = PR_FALSE; - PR_ASSERT(!"SSL servers are not supported on the Mac. (ssl_GetWrappingKey)"); - return rv; -} - -/* This is a kind of test-and-set. The caller passes in the new value it wants - * to set. This code tests the wrapped sym key entry in the file on disk. - * If it is uninitialized, this function writes the caller's value into - * the disk entry, and returns false. - * Otherwise, it overwrites the caller's wswk with the value obtained from - * the disk, and returns PR_TRUE. - * This is all done while holding the locks/semaphores necessary to make - * the operation atomic. - */ -PRBool -ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk) -{ - PRBool rv = PR_FALSE; - PR_ASSERT(!"SSL servers are not supported on the Mac. (ssl_SetWrappingKey)"); - return rv; -} - -#endif /* XP_UNIX || XP_WIN32 */ |