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 + -
显示快捷键?