sslsnce.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 1,927 行 · 第 1/4 页

C
1,927
字号
/* 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: sslsnce.c,v 1.4 2000/09/12 20:15:43 jgmyers%netscape.com Exp $ *//* 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 {    PRIPv6Addr 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[256 - sizeof(PRIPv6Addr) - sizeof(PRUint32)];	} 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(const PRIPv6Addr *addr, unsigned char *s, unsigned nl);static void Invalidate(SIDCacheEntry *sce);/************************************************************************/static const char envVarName[] = { SSL_ENV_VAR_NAME };#ifdef _WIN32struct 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 SECStatuscreateServerCacheSemaphore(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 SECStatusgetServerCacheSemaphore(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 SECStatusreleaseServerCacheSemaphore(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 voiddestroyServerCacheSemaphore(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_UNIXstatic 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 TRACEstatic 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 SECStatusgetServerCacheLock(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.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?