This source file includes following definitions.
- LockSidCacheLock
- UnlockSidCacheLock
- LockSet
- UnlockSet
- CacheCert
- Get32BitNameHash
- CacheSrvName
- ConvertFromSID
- ConvertToSID
- SIDindex
- FindSID
- ServerSessionIDLookup
- ServerSessionIDCache
- ServerSessionIDUncache
- gettid
- CloseCache
- InitCache
- SSL_GetMaxServerCacheLocks
- SSL_SetMaxServerCacheLocks
- ssl_ConfigServerSessionIDCacheInstanceWithOpt
- SSL_ConfigServerSessionIDCacheInstance
- SSL_ConfigServerSessionIDCache
- SSL_ShutdownServerSessionIDCacheInstance
- SSL_ShutdownServerSessionIDCache
- ssl_ConfigMPServerSIDCacheWithOpt
- SSL_ConfigMPServerSIDCache
- SSL_ConfigServerSessionIDCacheWithOpt
- SSL_InheritMPServerSIDCacheInstance
- SSL_InheritMPServerSIDCache
- LockPoller
- LaunchLockPoller
- StopLockPoller
- getSvrWrappingKey
- ssl_GetWrappingKey
- WrapTicketKey
- GenerateTicketKeys
- GenerateAndWrapTicketKeys
- UnwrapCachedTicketKeys
- ssl_GetSessionTicketKeysPKCS11
- ssl_GetSessionTicketKeys
- ssl_SetWrappingKey
- SSL_ConfigServerSessionIDCache
- SSL_ConfigMPServerSIDCache
- SSL_InheritMPServerSIDCache
- ssl_GetWrappingKey
- ssl_SetWrappingKey
- SSL_GetMaxServerCacheLocks
- SSL_SetMaxServerCacheLocks
#include "seccomon.h"
#if defined(XP_UNIX) || defined(XP_WIN32) || defined (XP_OS2) || defined(XP_BEOS)
#include "cert.h"
#include "ssl.h"
#include "sslimpl.h"
#include "sslproto.h"
#include "pk11func.h"
#include "base64.h"
#include "keyhi.h"
#ifdef NO_PKCS11_BYPASS
#include "blapit.h"
#include "sechash.h"
#else
#include "blapi.h"
#endif
#include <stdio.h>
#if defined(XP_UNIX) || defined(XP_BEOS)
#include <syslog.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include "unix_err.h"
#else
#ifdef XP_WIN32
#include <wtypes.h>
#include "win32err.h"
#endif
#endif
#include <sys/types.h>
#define SET_ERROR_CODE
#include "nspr.h"
#include "sslmutex.h"
struct sidCacheEntryStr {
PRIPv6Addr addr;
PRUint32 creationTime;
PRUint32 lastAccessTime;
PRUint32 expirationTime;
PRUint16 version;
PRUint8 valid;
PRUint8 sessionIDLength;
PRUint8 sessionID[SSL3_SESSIONID_BYTES];
PRUint16 authAlgorithm;
PRUint16 authKeyBits;
PRUint16 keaType;
PRUint16 keaKeyBits;
union {
struct {
PRUint8 masterKey[SSL_MAX_MASTER_KEY_BYTES];
PRUint8 cipherArg[SSL_MAX_CYPHER_ARG_BYTES];
PRUint8 cipherType;
PRUint8 masterKeyLen;
PRUint8 keyBits;
PRUint8 secretKeyBits;
PRUint8 cipherArgLen;
} ssl2;
struct {
ssl3CipherSuite cipherSuite;
PRUint16 compression;
ssl3SidKeys keys;
PRUint32 masterWrapMech;
SSL3KEAType exchKeyType;
PRInt32 certIndex;
PRInt32 srvNameIndex;
PRUint8 srvNameHash[SHA256_LENGTH];
} ssl3;
struct {
PRUint8 filler[120];
} forceSize;
} u;
};
typedef struct sidCacheEntryStr sidCacheEntry;
struct certCacheEntryStr {
PRUint16 certLength;
PRUint16 sessionIDLength;
PRUint8 sessionID[SSL3_SESSIONID_BYTES];
PRUint8 cert[SSL_MAX_CACHED_CERT_LEN];
};
typedef struct certCacheEntryStr certCacheEntry;
struct sidCacheLockStr {
PRUint32 timeStamp;
sslMutex mutex;
sslPID pid;
};
typedef struct sidCacheLockStr sidCacheLock;
struct sidCacheSetStr {
PRIntn next;
};
typedef struct sidCacheSetStr sidCacheSet;
struct encKeyCacheEntryStr {
PRUint8 bytes[512];
PRInt32 length;
};
typedef struct encKeyCacheEntryStr encKeyCacheEntry;
#define SSL_MAX_DNS_HOST_NAME 1024
struct srvNameCacheEntryStr {
PRUint16 type;
PRUint16 nameLen;
PRUint8 name[SSL_MAX_DNS_HOST_NAME + 12];
PRUint8 nameHash[SHA256_LENGTH];
};
typedef struct srvNameCacheEntryStr srvNameCacheEntry;
struct cacheDescStr {
PRUint32 cacheMemSize;
PRUint32 numSIDCacheLocks;
PRUint32 numSIDCacheSets;
PRUint32 numSIDCacheSetsPerLock;
PRUint32 numSIDCacheEntries;
PRUint32 sidCacheSize;
PRUint32 numCertCacheEntries;
PRUint32 certCacheSize;
PRUint32 numKeyCacheEntries;
PRUint32 keyCacheSize;
PRUint32 numSrvNameCacheEntries;
PRUint32 srvNameCacheSize;
PRUint32 ssl2Timeout;
PRUint32 ssl3Timeout;
PRUint32 numSIDCacheLocksInitialized;
PRUint32 nextCertCacheEntry;
PRBool stopPolling;
PRBool everInherited;
sidCacheLock * sidCacheLocks;
sidCacheLock * keyCacheLock;
sidCacheLock * certCacheLock;
sidCacheLock * srvNameCacheLock;
sidCacheSet * sidCacheSets;
sidCacheEntry * sidCacheData;
certCacheEntry * certCacheData;
SSLWrappedSymWrappingKey * keyCacheData;
PRUint8 * ticketKeyNameSuffix;
encKeyCacheEntry * ticketEncKey;
encKeyCacheEntry * ticketMacKey;
PRUint32 * ticketKeysValid;
srvNameCacheEntry * srvNameCacheData;
char * cacheMem;
struct cacheDescStr * sharedCache;
PRFileMap * cacheMemMap;
PRThread * poller;
PRUint32 mutexTimeout;
PRBool shared;
};
typedef struct cacheDescStr cacheDesc;
static cacheDesc globalCache;
static const char envVarName[] = { SSL_ENV_VAR_NAME };
static PRBool isMultiProcess = PR_FALSE;
#define DEF_SID_CACHE_ENTRIES 10000
#define DEF_CERT_CACHE_ENTRIES 250
#define MIN_CERT_CACHE_ENTRIES 125
#define DEF_KEY_CACHE_ENTRIES 250
#define DEF_NAME_CACHE_ENTRIES 1000
#define SID_CACHE_ENTRIES_PER_SET 128
#define SID_ALIGNMENT 16
#define DEF_SSL2_TIMEOUT 100
#define MAX_SSL2_TIMEOUT 100
#define MIN_SSL2_TIMEOUT 5
#define DEF_SSL3_TIMEOUT 86400L
#define MAX_SSL3_TIMEOUT 86400L
#define MIN_SSL3_TIMEOUT 5
#if defined(AIX) || defined(LINUX) || defined(NETBSD) || defined(OPENBSD)
#define MAX_SID_CACHE_LOCKS 8
#elif defined(OSF1)
#define MAX_SID_CACHE_LOCKS 16
#else
#define MAX_SID_CACHE_LOCKS 256
#endif
#define SID_HOWMANY(val, size) (((val) + ((size) - 1)) / (size))
#define SID_ROUNDUP(val, size) ((size) * SID_HOWMANY((val), (size)))
static sslPID myPid;
static PRUint32 ssl_max_sid_cache_locks = MAX_SID_CACHE_LOCKS;
static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s,
unsigned nl);
static SECStatus LaunchLockPoller(cacheDesc *cache);
static SECStatus StopLockPoller(cacheDesc *cache);
struct inheritanceStr {
PRUint32 cacheMemSize;
PRUint32 fmStrLen;
};
typedef struct inheritanceStr inheritance;
#if defined(_WIN32) || defined(XP_OS2)
#define DEFAULT_CACHE_DIRECTORY "\\temp"
#endif
#if defined(XP_UNIX) || defined(XP_BEOS)
#define DEFAULT_CACHE_DIRECTORY "/tmp"
#endif
static PRUint32
LockSidCacheLock(sidCacheLock *lock, PRUint32 now)
{
SECStatus rv = sslMutex_Lock(&lock->mutex);
if (rv != SECSuccess)
return 0;
if (!now)
now = ssl_Time();
lock->timeStamp = now;
lock->pid = myPid;
return now;
}
static SECStatus
UnlockSidCacheLock(sidCacheLock *lock)
{
SECStatus rv;
lock->pid = 0;
rv = sslMutex_Unlock(&lock->mutex);
return rv;
}
static PRUint32
LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now)
{
PRUint32 lockNum = set % cache->numSIDCacheLocks;
sidCacheLock * lock = cache->sidCacheLocks + lockNum;
return LockSidCacheLock(lock, now);
}
static SECStatus
UnlockSet(cacheDesc *cache, PRUint32 set)
{
PRUint32 lockNum = set % cache->numSIDCacheLocks;
sidCacheLock * lock = cache->sidCacheLocks + lockNum;
return UnlockSidCacheLock(lock);
}
static PRUint32
CacheCert(cacheDesc * cache, CERTCertificate *cert, sidCacheEntry *sce)
{
PRUint32 now;
certCacheEntry cce;
if ((cert->derCert.len > SSL_MAX_CACHED_CERT_LEN) ||
(cert->derCert.len <= 0) ||
(cert->derCert.data == NULL)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return 0;
}
cce.sessionIDLength = sce->sessionIDLength;
PORT_Memcpy(cce.sessionID, sce->sessionID, cce.sessionIDLength);
cce.certLength = cert->derCert.len;
PORT_Memcpy(cce.cert, cert->derCert.data, cce.certLength);
now = LockSidCacheLock(cache->certCacheLock, 0);
if (now) {
cacheDesc * sharedCache = cache->sharedCache;
PRUint32 ndx = sharedCache->nextCertCacheEntry;
cache->certCacheData[ndx] = cce;
sce->u.ssl3.certIndex = ndx;
sharedCache->nextCertCacheEntry =
(ndx + 1) % cache->numCertCacheEntries;
UnlockSidCacheLock(cache->certCacheLock);
}
return now;
}
static PLHashNumber
Get32BitNameHash(const SECItem *name)
{
PLHashNumber rv = SECITEM_Hash(name);
PRUint8 *rvc = (PRUint8 *)&rv;
rvc[ name->len % sizeof(rv) ] ^= name->type;
return rv;
}
static PRUint32
CacheSrvName(cacheDesc * cache, SECItem *name, sidCacheEntry *sce)
{
PRUint32 now;
PRUint32 ndx;
srvNameCacheEntry snce;
if (!name || name->len <= 0 ||
name->len > SSL_MAX_DNS_HOST_NAME) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return 0;
}
snce.type = name->type;
snce.nameLen = name->len;
PORT_Memcpy(snce.name, name->data, snce.nameLen);
#ifdef NO_PKCS11_BYPASS
HASH_HashBuf(HASH_AlgSHA256, snce.nameHash, name->data, name->len);
#else
SHA256_HashBuf(snce.nameHash, (unsigned char*)name->data,
name->len);
#endif
ndx = Get32BitNameHash(name);
now = LockSidCacheLock(cache->srvNameCacheLock, 0);
if (now) {
if (cache->numSrvNameCacheEntries > 0) {
ndx %= cache->numSrvNameCacheEntries;
cache->srvNameCacheData[ndx] = snce;
sce->u.ssl3.srvNameIndex = ndx;
PORT_Memcpy(sce->u.ssl3.srvNameHash, snce.nameHash, SHA256_LENGTH);
}
UnlockSidCacheLock(cache->srvNameCacheLock);
}
return now;
}
static void
ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
{
to->valid = 1;
to->version = from->version;
to->addr = from->addr;
to->creationTime = from->creationTime;
to->lastAccessTime = from->lastAccessTime;
to->expirationTime = from->expirationTime;
to->authAlgorithm = from->authAlgorithm;
to->authKeyBits = from->authKeyBits;
to->keaType = from->keaType;
to->keaKeyBits = from->keaKeyBits;
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->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;
to->sessionIDLength = SSL2_SESSIONID_BYTES;
PORT_Memcpy(to->sessionID, from->u.ssl2.sessionID, SSL2_SESSIONID_BYTES);
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%08x%08x%08x%08x cipherType=%d", myPid,
to->u.ssl2.masterKeyLen, to->u.ssl2.cipherArgLen,
to->creationTime, to->addr.pr_s6_addr32[0],
to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
to->addr.pr_s6_addr32[3], to->u.ssl2.cipherType));
} else {
to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite;
to->u.ssl3.compression = (PRUint16)from->u.ssl3.compression;
to->u.ssl3.keys = from->u.ssl3.keys;
to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech;
to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType;
to->sessionIDLength = from->u.ssl3.sessionIDLength;
to->u.ssl3.certIndex = -1;
to->u.ssl3.srvNameIndex = -1;
PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID,
to->sessionIDLength);
SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x "
"cipherSuite=%d",
myPid, to->creationTime, to->addr.pr_s6_addr32[0],
to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
to->addr.pr_s6_addr32[3], to->u.ssl3.cipherSuite));
}
}
static sslSessionID *
ConvertToSID(sidCacheEntry * from,
certCacheEntry * pcce,
srvNameCacheEntry *psnce,
CERTCertDBHandle * dbHandle)
{
sslSessionID *to;
PRUint16 version = from->version;
to = PORT_ZNew(sslSessionID);
if (!to) {
return 0;
}
if (version < SSL_LIBRARY_VERSION_3_0) {
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->sessionID, SSL2_SESSIONID_BYTES);
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%08x%08x%08x%08x cipherType=%d",
myPid, to->u.ssl2.masterKey.len,
to->u.ssl2.cipherArg.len, to->creationTime,
to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1],
to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3],
to->u.ssl2.cipherType));
} else {
to->u.ssl3.sessionIDLength = from->sessionIDLength;
to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite;
to->u.ssl3.compression = (SSLCompressionMethod)from->u.ssl3.compression;
to->u.ssl3.keys = from->u.ssl3.keys;
to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech;
to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType;
if (from->u.ssl3.srvNameIndex != -1 && psnce) {
SECItem name;
SECStatus rv;
name.type = psnce->type;
name.len = psnce->nameLen;
name.data = psnce->name;
rv = SECITEM_CopyItem(NULL, &to->u.ssl3.srvName, &name);
if (rv != SECSuccess) {
goto loser;
}
}
PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength);
to->u.ssl3.clientWriteKey = NULL;
to->u.ssl3.serverWriteKey = NULL;
to->urlSvrName = NULL;
to->u.ssl3.masterModuleID = (SECMODModuleID)-1;
to->u.ssl3.masterSlotID = (CK_SLOT_ID)-1;
to->u.ssl3.masterWrapIndex = 0;
to->u.ssl3.masterWrapSeries = 0;
to->u.ssl3.masterValid = PR_FALSE;
to->u.ssl3.clAuthModuleID = (SECMODModuleID)-1;
to->u.ssl3.clAuthSlotID = (CK_SLOT_ID)-1;
to->u.ssl3.clAuthSeries = 0;
to->u.ssl3.clAuthValid = PR_FALSE;
if (from->u.ssl3.certIndex != -1 && pcce) {
SECItem derCert;
derCert.len = pcce->certLength;
derCert.data = pcce->cert;
to->peerCert = CERT_NewTempCertificate(dbHandle, &derCert, NULL,
PR_FALSE, PR_TRUE);
if (to->peerCert == NULL)
goto loser;
}
}
to->version = from->version;
to->creationTime = from->creationTime;
to->lastAccessTime = from->lastAccessTime;
to->expirationTime = from->expirationTime;
to->cached = in_server_cache;
to->addr = from->addr;
to->references = 1;
to->authAlgorithm = from->authAlgorithm;
to->authKeyBits = from->authKeyBits;
to->keaType = from->keaType;
to->keaKeyBits = from->keaKeyBits;
return to;
loser:
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);
} else {
SECITEM_FreeItem(&to->u.ssl3.srvName, PR_FALSE);
}
PORT_Free(to);
}
return NULL;
}
static PRUint32
SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl)
{
PRUint32 rv;
PRUint32 x[8];
memset(x, 0, sizeof x);
if (nl > sizeof x)
nl = sizeof x;
memcpy(x, s, nl);
rv = (addr->pr_s6_addr32[0] ^ addr->pr_s6_addr32[1] ^
addr->pr_s6_addr32[2] ^ addr->pr_s6_addr32[3] ^
x[0] ^ x[1] ^ x[2] ^ x[3] ^ x[4] ^ x[5] ^ x[6] ^ x[7])
% cache->numSIDCacheSets;
return rv;
}
static sidCacheEntry *
FindSID(cacheDesc *cache, PRUint32 setNum, PRUint32 now,
const PRIPv6Addr *addr, unsigned char *sessionID,
unsigned sessionIDLength)
{
PRUint32 ndx = cache->sidCacheSets[setNum].next;
int i;
sidCacheEntry * set = cache->sidCacheData +
(setNum * SID_CACHE_ENTRIES_PER_SET);
for (i = SID_CACHE_ENTRIES_PER_SET; i > 0; --i) {
sidCacheEntry * sce;
ndx = (ndx - 1) % SID_CACHE_ENTRIES_PER_SET;
sce = set + ndx;
if (!sce->valid)
continue;
if (now > sce->expirationTime) {
SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x "
"time+=%x",
myPid, sce->addr.pr_s6_addr32[0],
sce->addr.pr_s6_addr32[1], sce->addr.pr_s6_addr32[2],
sce->addr.pr_s6_addr32[3], now,
sce->expirationTime ));
sce->valid = 0;
continue;
}
if (sessionIDLength == sce->sessionIDLength &&
!memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) &&
!memcmp(sce->sessionID, sessionID, sessionIDLength)) {
return sce;
}
}
PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
return NULL;
}
static sslSessionID *
ServerSessionIDLookup(const PRIPv6Addr *addr,
unsigned char *sessionID,
unsigned int sessionIDLength,
CERTCertDBHandle * dbHandle)
{
sslSessionID * sid = 0;
sidCacheEntry * psce;
certCacheEntry *pcce = 0;
srvNameCacheEntry *psnce = 0;
cacheDesc * cache = &globalCache;
PRUint32 now;
PRUint32 set;
PRInt32 cndx;
sidCacheEntry sce;
certCacheEntry cce;
srvNameCacheEntry snce;
set = SIDindex(cache, addr, sessionID, sessionIDLength);
now = LockSet(cache, set, 0);
if (!now)
return NULL;
psce = FindSID(cache, set, now, addr, sessionID, sessionIDLength);
if (psce) {
if (psce->version >= SSL_LIBRARY_VERSION_3_0) {
if ((cndx = psce->u.ssl3.certIndex) != -1) {
PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now);
if (gotLock) {
pcce = &cache->certCacheData[cndx];
if ((pcce->sessionIDLength == psce->sessionIDLength) &&
!PORT_Memcmp(pcce->sessionID, psce->sessionID,
pcce->sessionIDLength)) {
cce = *pcce;
} else {
psce->valid = 0;
psce = 0;
pcce = 0;
}
UnlockSidCacheLock(cache->certCacheLock);
} else {
PORT_Assert(!("Didn't get cert Cache Lock!"));
psce = 0;
pcce = 0;
}
}
if (psce && ((cndx = psce->u.ssl3.srvNameIndex) != -1)) {
PRUint32 gotLock = LockSidCacheLock(cache->srvNameCacheLock,
now);
if (gotLock) {
psnce = &cache->srvNameCacheData[cndx];
if (!PORT_Memcmp(psnce->nameHash, psce->u.ssl3.srvNameHash,
SHA256_LENGTH)) {
snce = *psnce;
} else {
psce->valid = 0;
psce = 0;
psnce = 0;
}
UnlockSidCacheLock(cache->srvNameCacheLock);
} else {
PORT_Assert(!("Didn't get name Cache Lock!"));
psce = 0;
psnce = 0;
}
}
}
if (psce) {
psce->lastAccessTime = now;
sce = *psce;
}
}
UnlockSet(cache, set);
if (psce) {
sid = ConvertToSID(&sce, pcce ? &cce : 0, psnce ? &snce : 0, dbHandle);
}
return sid;
}
static void
ServerSessionIDCache(sslSessionID *sid)
{
sidCacheEntry sce;
PRUint32 now = 0;
PRUint16 version = sid->version;
cacheDesc * cache = &globalCache;
if ((version >= SSL_LIBRARY_VERSION_3_0) &&
(sid->u.ssl3.sessionIDLength == 0)) {
return;
}
if (sid->cached == never_cached || sid->cached == invalid_cache) {
PRUint32 set;
PORT_Assert(sid->creationTime != 0);
if (!sid->creationTime)
sid->lastAccessTime = sid->creationTime = ssl_Time();
if (version < SSL_LIBRARY_VERSION_3_0) {
sid->expirationTime = sid->creationTime + cache->ssl2Timeout;
SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
"cipher=%d", myPid, sid->cached,
sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
sid->creationTime, sid->u.ssl2.cipherType));
PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID,
SSL2_SESSIONID_BYTES));
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));
} else {
sid->expirationTime = sid->creationTime + cache->ssl3Timeout;
SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
"cipherSuite=%d", myPid, sid->cached,
sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
sid->creationTime, sid->u.ssl3.cipherSuite));
PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID,
sid->u.ssl3.sessionIDLength));
}
ConvertFromSID(&sce, sid);
if (version >= SSL_LIBRARY_VERSION_3_0) {
SECItem *name = &sid->u.ssl3.srvName;
if (name->len && name->data) {
now = CacheSrvName(cache, name, &sce);
}
if (sid->peerCert != NULL) {
now = CacheCert(cache, sid->peerCert, &sce);
}
}
set = SIDindex(cache, &sce.addr, sce.sessionID, sce.sessionIDLength);
now = LockSet(cache, set, now);
if (now) {
PRUint32 next = cache->sidCacheSets[set].next;
PRUint32 ndx = set * SID_CACHE_ENTRIES_PER_SET + next;
cache->sidCacheData[ndx] = sce;
cache->sidCacheSets[set].next =
(next + 1) % SID_CACHE_ENTRIES_PER_SET;
UnlockSet(cache, set);
sid->cached = in_server_cache;
}
}
}
static void
ServerSessionIDUncache(sslSessionID *sid)
{
cacheDesc * cache = &globalCache;
PRUint8 * sessionID;
unsigned int sessionIDLength;
PRErrorCode err;
PRUint32 set;
PRUint32 now;
sidCacheEntry *psce;
if (sid == NULL)
return;
err = PR_GetError();
if (sid->version < SSL_LIBRARY_VERSION_3_0) {
sessionID = sid->u.ssl2.sessionID;
sessionIDLength = SSL2_SESSIONID_BYTES;
SSL_TRC(8, ("%d: SSL: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
"cipher=%d", myPid, sid->cached,
sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
sid->creationTime, sid->u.ssl2.cipherType));
PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
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));
} else {
sessionID = sid->u.ssl3.sessionID;
sessionIDLength = sid->u.ssl3.sessionIDLength;
SSL_TRC(8, ("%d: SSL3: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
"cipherSuite=%d", myPid, sid->cached,
sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
sid->creationTime, sid->u.ssl3.cipherSuite));
PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
}
set = SIDindex(cache, &sid->addr, sessionID, sessionIDLength);
now = LockSet(cache, set, 0);
if (now) {
psce = FindSID(cache, set, now, &sid->addr, sessionID, sessionIDLength);
if (psce) {
psce->valid = 0;
}
UnlockSet(cache, set);
}
sid->cached = invalid_cache;
PORT_SetError(err);
}
#ifdef XP_OS2
#define INCL_DOSPROCESS
#include <os2.h>
long gettid(void)
{
PTIB ptib;
PPIB ppib;
DosGetInfoBlocks(&ptib, &ppib);
return ((long)ptib->tib_ordinal);
}
#endif
static void
CloseCache(cacheDesc *cache)
{
int locks_initialized = cache->numSIDCacheLocksInitialized;
if (cache->cacheMem) {
if (cache->sharedCache) {
sidCacheLock *pLock = cache->sidCacheLocks;
for (; locks_initialized > 0; --locks_initialized, ++pLock ) {
sslMutex_Destroy(&pLock->mutex,
cache->sharedCache->everInherited);
}
}
if (cache->shared) {
PR_MemUnmap(cache->cacheMem, cache->cacheMemSize);
} else {
PORT_Free(cache->cacheMem);
}
cache->cacheMem = NULL;
}
if (cache->cacheMemMap) {
PR_CloseFileMap(cache->cacheMemMap);
cache->cacheMemMap = NULL;
}
memset(cache, 0, sizeof *cache);
}
static SECStatus
InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries,
int maxSrvNameCacheEntries, PRUint32 ssl2_timeout,
PRUint32 ssl3_timeout, const char *directory, PRBool shared)
{
ptrdiff_t ptr;
sidCacheLock *pLock;
char * cacheMem;
PRFileMap * cacheMemMap;
char * cfn = NULL;
int locks_initialized = 0;
int locks_to_initialize = 0;
PRUint32 init_time;
if ( (!cache) || (maxCacheEntries < 0) || (!directory) ) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (cache->cacheMem) {
return SECSuccess;
}
cache->shared = shared;
cache->cacheMem = cacheMem = NULL;
cache->cacheMemMap = cacheMemMap = NULL;
cache->sharedCache = (cacheDesc *)0;
cache->numSIDCacheLocksInitialized = 0;
cache->nextCertCacheEntry = 0;
cache->stopPolling = PR_FALSE;
cache->everInherited = PR_FALSE;
cache->poller = NULL;
cache->mutexTimeout = 0;
cache->numSIDCacheEntries = maxCacheEntries ? maxCacheEntries
: DEF_SID_CACHE_ENTRIES;
cache->numSIDCacheSets =
SID_HOWMANY(cache->numSIDCacheEntries, SID_CACHE_ENTRIES_PER_SET);
cache->numSIDCacheEntries =
cache->numSIDCacheSets * SID_CACHE_ENTRIES_PER_SET;
cache->numSIDCacheLocks =
PR_MIN(cache->numSIDCacheSets, ssl_max_sid_cache_locks);
cache->numSIDCacheSetsPerLock =
SID_HOWMANY(cache->numSIDCacheSets, cache->numSIDCacheLocks);
cache->numCertCacheEntries = (maxCertCacheEntries > 0) ?
maxCertCacheEntries : 0;
cache->numSrvNameCacheEntries = (maxSrvNameCacheEntries >= 0) ?
maxSrvNameCacheEntries : DEF_NAME_CACHE_ENTRIES;
ptr = 0;
cache->cacheMem = (char *)ptr;
ptr += SID_ROUNDUP(sizeof(cacheDesc), SID_ALIGNMENT);
cache->sidCacheLocks = (sidCacheLock *)ptr;
cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks;
cache->certCacheLock = cache->keyCacheLock + 1;
cache->srvNameCacheLock = cache->certCacheLock + 1;
ptr = (ptrdiff_t)(cache->srvNameCacheLock + 1);
ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
cache->sidCacheSets = (sidCacheSet *)ptr;
ptr = (ptrdiff_t)(cache->sidCacheSets + cache->numSIDCacheSets);
ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
cache->sidCacheData = (sidCacheEntry *)ptr;
ptr = (ptrdiff_t)(cache->sidCacheData + cache->numSIDCacheEntries);
ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
cache->certCacheData = (certCacheEntry *)ptr;
cache->sidCacheSize =
(char *)cache->certCacheData - (char *)cache->sidCacheData;
if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) {
cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry);
if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES)
cache->numCertCacheEntries = MIN_CERT_CACHE_ENTRIES;
}
ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries);
ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
cache->keyCacheData = (SSLWrappedSymWrappingKey *)ptr;
cache->certCacheSize =
(char *)cache->keyCacheData - (char *)cache->certCacheData;
cache->numKeyCacheEntries = kt_kea_size * SSL_NUM_WRAP_MECHS;
ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries);
ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
cache->keyCacheSize = (char *)ptr - (char *)cache->keyCacheData;
cache->ticketKeyNameSuffix = (PRUint8 *)ptr;
ptr = (ptrdiff_t)(cache->ticketKeyNameSuffix +
SESS_TICKET_KEY_VAR_NAME_LEN);
ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
cache->ticketEncKey = (encKeyCacheEntry *)ptr;
ptr = (ptrdiff_t)(cache->ticketEncKey + 1);
ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
cache->ticketMacKey = (encKeyCacheEntry *)ptr;
ptr = (ptrdiff_t)(cache->ticketMacKey + 1);
ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
cache->ticketKeysValid = (PRUint32 *)ptr;
ptr = (ptrdiff_t)(cache->ticketKeysValid + 1);
ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
cache->srvNameCacheData = (srvNameCacheEntry *)ptr;
cache->srvNameCacheSize =
cache->numSrvNameCacheEntries * sizeof(srvNameCacheEntry);
ptr = (ptrdiff_t)(cache->srvNameCacheData + cache->numSrvNameCacheEntries);
ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
cache->cacheMemSize = ptr;
if (ssl2_timeout) {
if (ssl2_timeout > MAX_SSL2_TIMEOUT) {
ssl2_timeout = MAX_SSL2_TIMEOUT;
}
if (ssl2_timeout < MIN_SSL2_TIMEOUT) {
ssl2_timeout = MIN_SSL2_TIMEOUT;
}
cache->ssl2Timeout = ssl2_timeout;
} else {
cache->ssl2Timeout = DEF_SSL2_TIMEOUT;
}
if (ssl3_timeout) {
if (ssl3_timeout > MAX_SSL3_TIMEOUT) {
ssl3_timeout = MAX_SSL3_TIMEOUT;
}
if (ssl3_timeout < MIN_SSL3_TIMEOUT) {
ssl3_timeout = MIN_SSL3_TIMEOUT;
}
cache->ssl3Timeout = ssl3_timeout;
} else {
cache->ssl3Timeout = DEF_SSL3_TIMEOUT;
}
if (shared) {
#if defined(XP_UNIX) || defined(XP_BEOS)
cfn = PR_smprintf("%s", directory);
#elif defined(XP_WIN32)
cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid,
GetCurrentThreadId());
#elif defined(XP_OS2)
cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid,
gettid());
#else
#error "Don't know how to create file name for this platform!"
#endif
if (!cfn) {
goto loser;
}
cacheMemMap = PR_OpenAnonFileMap(cfn, cache->cacheMemSize,
PR_PROT_READWRITE);
PR_smprintf_free(cfn);
if(!cacheMemMap) {
goto loser;
}
cacheMem = PR_MemMap(cacheMemMap, 0, cache->cacheMemSize);
} else {
cacheMem = PORT_Alloc(cache->cacheMemSize);
}
if (! cacheMem) {
goto loser;
}
memset(cacheMem, 0, cache->cacheMemSize);
memcpy(cacheMem, cache, sizeof *cache);
cache->cacheMemMap = cacheMemMap;
cache->cacheMem = cacheMem;
cache->sharedCache = (cacheDesc *)cacheMem;
ptr = (ptrdiff_t)cache->cacheMem;
*(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
*(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
*(ptrdiff_t *)(&cache->certCacheLock) += ptr;
*(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr;
*(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
*(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
*(ptrdiff_t *)(&cache->certCacheData) += ptr;
*(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
*(ptrdiff_t *)(&cache->ticketKeyNameSuffix) += ptr;
*(ptrdiff_t *)(&cache->ticketEncKey ) += ptr;
*(ptrdiff_t *)(&cache->ticketMacKey ) += ptr;
*(ptrdiff_t *)(&cache->ticketKeysValid) += ptr;
*(ptrdiff_t *)(&cache->srvNameCacheData) += ptr;
init_time = ssl_Time();
pLock = cache->sidCacheLocks;
for (locks_to_initialize = cache->numSIDCacheLocks + 3;
locks_initialized < locks_to_initialize;
++locks_initialized, ++pLock ) {
SECStatus err = sslMutex_Init(&pLock->mutex, shared);
if (err) {
cache->numSIDCacheLocksInitialized = locks_initialized;
goto loser;
}
pLock->timeStamp = init_time;
pLock->pid = 0;
}
cache->numSIDCacheLocksInitialized = locks_initialized;
return SECSuccess;
loser:
CloseCache(cache);
return SECFailure;
}
PRUint32
SSL_GetMaxServerCacheLocks(void)
{
return ssl_max_sid_cache_locks + 2;
}
SECStatus
SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
{
if (maxLocks < 3) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
ssl_max_sid_cache_locks = maxLocks - 2;
return SECSuccess;
}
static SECStatus
ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache,
PRUint32 ssl2_timeout,
PRUint32 ssl3_timeout,
const char * directory,
PRBool shared,
int maxCacheEntries,
int maxCertCacheEntries,
int maxSrvNameCacheEntries)
{
SECStatus rv;
PORT_Assert(sizeof(sidCacheEntry) == 192);
PORT_Assert(sizeof(certCacheEntry) == 4096);
PORT_Assert(sizeof(srvNameCacheEntry) == 1072);
rv = ssl_Init();
if (rv != SECSuccess) {
return rv;
}
myPid = SSL_GETPID();
if (!directory) {
directory = DEFAULT_CACHE_DIRECTORY;
}
rv = InitCache(cache, maxCacheEntries, maxCertCacheEntries,
maxSrvNameCacheEntries, ssl2_timeout, ssl3_timeout,
directory, shared);
if (rv) {
SET_ERROR_CODE
return SECFailure;
}
ssl_sid_lookup = ServerSessionIDLookup;
ssl_sid_cache = ServerSessionIDCache;
ssl_sid_uncache = ServerSessionIDUncache;
return SECSuccess;
}
SECStatus
SSL_ConfigServerSessionIDCacheInstance( cacheDesc *cache,
int maxCacheEntries,
PRUint32 ssl2_timeout,
PRUint32 ssl3_timeout,
const char * directory, PRBool shared)
{
return ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
ssl2_timeout,
ssl3_timeout,
directory,
shared,
maxCacheEntries,
-1, -1);
}
SECStatus
SSL_ConfigServerSessionIDCache( int maxCacheEntries,
PRUint32 ssl2_timeout,
PRUint32 ssl3_timeout,
const char * directory)
{
ssl_InitSessionCacheLocks();
return SSL_ConfigServerSessionIDCacheInstance(&globalCache,
maxCacheEntries, ssl2_timeout, ssl3_timeout, directory, PR_FALSE);
}
SECStatus
SSL_ShutdownServerSessionIDCacheInstance(cacheDesc *cache)
{
CloseCache(cache);
return SECSuccess;
}
SECStatus
SSL_ShutdownServerSessionIDCache(void)
{
#if defined(XP_UNIX) || defined(XP_BEOS)
StopLockPoller(&globalCache);
#endif
SSL3_ShutdownServerCache();
return SSL_ShutdownServerSessionIDCacheInstance(&globalCache);
}
static SECStatus
ssl_ConfigMPServerSIDCacheWithOpt( PRUint32 ssl2_timeout,
PRUint32 ssl3_timeout,
const char * directory,
int maxCacheEntries,
int maxCertCacheEntries,
int maxSrvNameCacheEntries)
{
char * envValue;
char * inhValue;
cacheDesc * cache = &globalCache;
PRUint32 fmStrLen;
SECStatus result;
PRStatus prStatus;
SECStatus putEnvFailed;
inheritance inherit;
char fmString[PR_FILEMAP_STRING_BUFSIZE];
isMultiProcess = PR_TRUE;
result = ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
ssl2_timeout, ssl3_timeout, directory, PR_TRUE,
maxCacheEntries, maxCacheEntries, maxSrvNameCacheEntries);
if (result != SECSuccess)
return result;
prStatus = PR_ExportFileMapAsString(cache->cacheMemMap,
sizeof fmString, fmString);
if ((prStatus != PR_SUCCESS) || !(fmStrLen = strlen(fmString))) {
SET_ERROR_CODE
return SECFailure;
}
inherit.cacheMemSize = cache->cacheMemSize;
inherit.fmStrLen = fmStrLen;
inhValue = BTOA_DataToAscii((unsigned char *)&inherit, sizeof inherit);
if (!inhValue || !strlen(inhValue)) {
SET_ERROR_CODE
return SECFailure;
}
envValue = PR_smprintf("%s,%s", inhValue, fmString);
if (!envValue || !strlen(envValue)) {
SET_ERROR_CODE
return SECFailure;
}
PORT_Free(inhValue);
putEnvFailed = (SECStatus)NSS_PutEnv(envVarName, envValue);
PR_smprintf_free(envValue);
if (putEnvFailed) {
SET_ERROR_CODE
result = SECFailure;
}
#if defined(XP_UNIX) || defined(XP_BEOS)
LaunchLockPoller(cache);
#endif
return result;
}
SECStatus
SSL_ConfigMPServerSIDCache( int maxCacheEntries,
PRUint32 ssl2_timeout,
PRUint32 ssl3_timeout,
const char * directory)
{
return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout,
ssl3_timeout,
directory,
maxCacheEntries,
-1, -1);
}
SECStatus
SSL_ConfigServerSessionIDCacheWithOpt(
PRUint32 ssl2_timeout,
PRUint32 ssl3_timeout,
const char * directory,
int maxCacheEntries,
int maxCertCacheEntries,
int maxSrvNameCacheEntries,
PRBool enableMPCache)
{
if (!enableMPCache) {
ssl_InitSessionCacheLocks();
return ssl_ConfigServerSessionIDCacheInstanceWithOpt(&globalCache,
ssl2_timeout, ssl3_timeout, directory, PR_FALSE,
maxCacheEntries, maxCertCacheEntries, maxSrvNameCacheEntries);
} else {
return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout, ssl3_timeout,
directory, maxCacheEntries, maxCertCacheEntries,
maxSrvNameCacheEntries);
}
}
SECStatus
SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
{
unsigned char * decoString = NULL;
char * fmString = NULL;
char * myEnvString = NULL;
unsigned int decoLen;
ptrdiff_t ptr;
inheritance inherit;
cacheDesc my;
#ifdef WINNT
sidCacheLock* newLocks;
int locks_initialized = 0;
int locks_to_initialize = 0;
#endif
SECStatus status = ssl_Init();
if (status != SECSuccess) {
return status;
}
myPid = SSL_GETPID();
if (isMultiProcess) {
if (cache && cache->sharedCache) {
cache->sharedCache->everInherited = PR_TRUE;
}
return SECSuccess;
}
ssl_InitSessionCacheLocks();
ssl_sid_lookup = ServerSessionIDLookup;
ssl_sid_cache = ServerSessionIDCache;
ssl_sid_uncache = ServerSessionIDUncache;
if (!envString) {
envString = getenv(envVarName);
if (!envString) {
SET_ERROR_CODE
return SECFailure;
}
}
myEnvString = PORT_Strdup(envString);
if (!myEnvString)
return SECFailure;
fmString = strchr(myEnvString, ',');
if (!fmString)
goto loser;
*fmString++ = 0;
decoString = ATOB_AsciiToData(myEnvString, &decoLen);
if (!decoString) {
SET_ERROR_CODE
goto loser;
}
if (decoLen != sizeof inherit) {
SET_ERROR_CODE
goto loser;
}
PORT_Memcpy(&inherit, decoString, sizeof inherit);
if (strlen(fmString) != inherit.fmStrLen ) {
goto loser;
}
memset(cache, 0, sizeof *cache);
cache->cacheMemSize = inherit.cacheMemSize;
cache->cacheMemMap = PR_ImportFileMapFromString(fmString);
if(! cache->cacheMemMap) {
goto loser;
}
cache->cacheMem = PR_MemMap(cache->cacheMemMap, 0, cache->cacheMemSize);
if (! cache->cacheMem) {
goto loser;
}
cache->sharedCache = (cacheDesc *)cache->cacheMem;
if (cache->sharedCache->cacheMemSize != cache->cacheMemSize) {
SET_ERROR_CODE
goto loser;
}
my = *cache;
memcpy(cache, cache->sharedCache, sizeof *cache);
ptr = (ptrdiff_t)my.cacheMem;
*(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
*(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
*(ptrdiff_t *)(&cache->certCacheLock) += ptr;
*(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr;
*(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
*(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
*(ptrdiff_t *)(&cache->certCacheData) += ptr;
*(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
*(ptrdiff_t *)(&cache->ticketKeyNameSuffix) += ptr;
*(ptrdiff_t *)(&cache->ticketEncKey ) += ptr;
*(ptrdiff_t *)(&cache->ticketMacKey ) += ptr;
*(ptrdiff_t *)(&cache->ticketKeysValid) += ptr;
*(ptrdiff_t *)(&cache->srvNameCacheData) += ptr;
cache->cacheMemMap = my.cacheMemMap;
cache->cacheMem = my.cacheMem;
cache->sharedCache = (cacheDesc *)cache->cacheMem;
#ifdef WINNT
locks_to_initialize = cache->numSIDCacheLocks + 3;
newLocks = PORT_NewArray(sidCacheLock, locks_to_initialize);
if (!newLocks)
goto loser;
memcpy(newLocks, cache->sidCacheLocks,
locks_to_initialize * sizeof(sidCacheLock));
cache->sidCacheLocks = newLocks;
for (; locks_initialized < locks_to_initialize; ++locks_initialized) {
SECStatus err;
err = sslMutex_2LevelInit(&newLocks[locks_initialized].mutex);
if (err != SECSuccess) {
cache->numSIDCacheLocksInitialized = locks_initialized;
goto loser;
}
}
cache->numSIDCacheLocksInitialized = locks_initialized;
cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks;
cache->certCacheLock = cache->keyCacheLock + 1;
cache->srvNameCacheLock = cache->certCacheLock + 1;
#endif
PORT_Free(myEnvString);
PORT_Free(decoString);
cache->sharedCache->everInherited = PR_TRUE;
isMultiProcess = PR_TRUE;
return SECSuccess;
loser:
PORT_Free(myEnvString);
if (decoString)
PORT_Free(decoString);
CloseCache(cache);
return SECFailure;
}
SECStatus
SSL_InheritMPServerSIDCache(const char * envString)
{
return SSL_InheritMPServerSIDCacheInstance(&globalCache, envString);
}
#if defined(XP_UNIX) || defined(XP_BEOS)
#define SID_LOCK_EXPIRATION_TIMEOUT 30
static void
LockPoller(void * arg)
{
cacheDesc * cache = (cacheDesc *)arg;
cacheDesc * sharedCache = cache->sharedCache;
sidCacheLock * pLock;
PRIntervalTime timeout;
PRUint32 now;
PRUint32 then;
int locks_polled = 0;
int locks_to_poll = cache->numSIDCacheLocks + 2;
PRUint32 expiration = cache->mutexTimeout;
timeout = PR_SecondsToInterval(expiration);
while(!sharedCache->stopPolling) {
PR_Sleep(timeout);
if (sharedCache->stopPolling)
break;
now = ssl_Time();
then = now - expiration;
for (pLock = cache->sidCacheLocks, locks_polled = 0;
locks_to_poll > locks_polled && !sharedCache->stopPolling;
++locks_polled, ++pLock ) {
pid_t pid;
if (pLock->timeStamp < then &&
pLock->timeStamp != 0 &&
(pid = pLock->pid) != 0) {
int result = kill(pid, 0);
if (result < 0 && errno == ESRCH) {
SECStatus rv;
pLock->timeStamp = now;
pLock->pid = 0;
rv = sslMutex_Unlock(&pLock->mutex);
if (rv != SECSuccess) {
}
}
}
}
}
}
static SECStatus
LaunchLockPoller(cacheDesc *cache)
{
const char * timeoutString;
PRThread * pollerThread;
cache->mutexTimeout = SID_LOCK_EXPIRATION_TIMEOUT;
timeoutString = getenv("NSS_SSL_SERVER_CACHE_MUTEX_TIMEOUT");
if (timeoutString) {
long newTime = strtol(timeoutString, 0, 0);
if (newTime == 0)
return SECSuccess;
if (newTime > 0)
cache->mutexTimeout = (PRUint32)newTime;
}
pollerThread =
PR_CreateThread(PR_USER_THREAD, LockPoller, cache, PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
if (!pollerThread) {
return SECFailure;
}
cache->poller = pollerThread;
return SECSuccess;
}
static SECStatus
StopLockPoller(cacheDesc *cache)
{
if (!cache->poller) {
return SECSuccess;
}
cache->sharedCache->stopPolling = PR_TRUE;
if (PR_Interrupt(cache->poller) != PR_SUCCESS) {
return SECFailure;
}
if (PR_JoinThread(cache->poller) != PR_SUCCESS) {
return SECFailure;
}
cache->poller = NULL;
return SECSuccess;
}
#endif
static PRBool
getSvrWrappingKey(PRInt32 symWrapMechIndex,
SSL3KEAType exchKeyType,
SSLWrappedSymWrappingKey *wswk,
cacheDesc * cache,
PRUint32 lockTime)
{
PRUint32 ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
SSLWrappedSymWrappingKey * pwswk = cache->keyCacheData + ndx;
PRUint32 now = 0;
PRBool rv = PR_FALSE;
if (!cache->cacheMem) {
PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
return rv;
}
if (!lockTime) {
lockTime = now = LockSidCacheLock(cache->keyCacheLock, now);
if (!lockTime) {
return rv;
}
}
if (pwswk->exchKeyType == exchKeyType &&
pwswk->symWrapMechIndex == symWrapMechIndex &&
pwswk->wrappedSymKeyLen != 0) {
*wswk = *pwswk;
rv = PR_TRUE;
}
if (now) {
UnlockSidCacheLock(cache->keyCacheLock);
}
return rv;
}
PRBool
ssl_GetWrappingKey( PRInt32 symWrapMechIndex,
SSL3KEAType exchKeyType,
SSLWrappedSymWrappingKey *wswk)
{
PRBool rv;
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 = getSvrWrappingKey(symWrapMechIndex, exchKeyType, wswk,
&globalCache, 0);
} else {
rv = PR_FALSE;
}
return rv;
}
static PRBool
WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey,
const char *keyName, encKeyCacheEntry* cacheEntry)
{
SECItem wrappedKey = {siBuffer, NULL, 0};
wrappedKey.len = SECKEY_PublicKeyStrength(svrPubKey);
PORT_Assert(wrappedKey.len <= sizeof(cacheEntry->bytes));
if (wrappedKey.len > sizeof(cacheEntry->bytes))
return PR_FALSE;
wrappedKey.data = cacheEntry->bytes;
if (PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, symKey, &wrappedKey)
!= SECSuccess) {
SSL_DBG(("%d: SSL[%s]: Unable to wrap session ticket %s.",
SSL_GETPID(), "unknown", keyName));
return PR_FALSE;
}
cacheEntry->length = wrappedKey.len;
return PR_TRUE;
}
static PRBool
GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey,
PK11SymKey **macKey)
{
PK11SlotInfo *slot;
CK_MECHANISM_TYPE mechanismArray[2];
PK11SymKey *aesKeyTmp = NULL;
PK11SymKey *macKeyTmp = NULL;
cacheDesc *cache = &globalCache;
PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN];
PRUint8 *ticketKeyNameSuffix;
if (!cache->cacheMem) {
ticketKeyNameSuffix = ticketKeyNameSuffixLocal;
} else {
ticketKeyNameSuffix = cache->ticketKeyNameSuffix;
}
if (PK11_GenerateRandom(ticketKeyNameSuffix,
SESS_TICKET_KEY_VAR_NAME_LEN) != SECSuccess) {
SSL_DBG(("%d: SSL[%s]: Unable to generate random key name bytes.",
SSL_GETPID(), "unknown"));
goto loser;
}
mechanismArray[0] = CKM_AES_CBC;
mechanismArray[1] = CKM_SHA256_HMAC;
slot = PK11_GetBestSlotMultiple(mechanismArray, 2, pwArg);
if (slot) {
aesKeyTmp = PK11_KeyGen(slot, mechanismArray[0], NULL,
AES_256_KEY_LENGTH, pwArg);
macKeyTmp = PK11_KeyGen(slot, mechanismArray[1], NULL,
SHA256_LENGTH, pwArg);
PK11_FreeSlot(slot);
}
if (aesKeyTmp == NULL || macKeyTmp == NULL) {
SSL_DBG(("%d: SSL[%s]: Unable to generate session ticket keys.",
SSL_GETPID(), "unknown"));
goto loser;
}
PORT_Memcpy(keyName, ticketKeyNameSuffix, SESS_TICKET_KEY_VAR_NAME_LEN);
*aesKey = aesKeyTmp;
*macKey = macKeyTmp;
return PR_TRUE;
loser:
if (aesKeyTmp)
PK11_FreeSymKey(aesKeyTmp);
if (macKeyTmp)
PK11_FreeSymKey(macKeyTmp);
return PR_FALSE;
}
static PRBool
GenerateAndWrapTicketKeys(SECKEYPublicKey *svrPubKey, void *pwArg,
unsigned char *keyName, PK11SymKey **aesKey,
PK11SymKey **macKey)
{
PK11SymKey *aesKeyTmp = NULL;
PK11SymKey *macKeyTmp = NULL;
cacheDesc *cache = &globalCache;
if (!GenerateTicketKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp)) {
goto loser;
}
if (cache->cacheMem) {
if (!WrapTicketKey(svrPubKey, aesKeyTmp, "enc key", cache->ticketEncKey))
goto loser;
if (!WrapTicketKey(svrPubKey, macKeyTmp, "mac key", cache->ticketMacKey))
goto loser;
}
*aesKey = aesKeyTmp;
*macKey = macKeyTmp;
return PR_TRUE;
loser:
if (aesKeyTmp)
PK11_FreeSymKey(aesKeyTmp);
if (macKeyTmp)
PK11_FreeSymKey(macKeyTmp);
return PR_FALSE;
}
static PRBool
UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName,
PK11SymKey **aesKey, PK11SymKey **macKey)
{
SECItem wrappedKey = {siBuffer, NULL, 0};
PK11SymKey *aesKeyTmp = NULL;
PK11SymKey *macKeyTmp = NULL;
cacheDesc *cache = &globalCache;
wrappedKey.data = cache->ticketEncKey->bytes;
wrappedKey.len = cache->ticketEncKey->length;
PORT_Assert(wrappedKey.len <= sizeof(cache->ticketEncKey->bytes));
aesKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
CKM_AES_CBC, CKA_DECRYPT, 0);
wrappedKey.data = cache->ticketMacKey->bytes;
wrappedKey.len = cache->ticketMacKey->length;
PORT_Assert(wrappedKey.len <= sizeof(cache->ticketMacKey->bytes));
macKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
CKM_SHA256_HMAC, CKA_SIGN, 0);
if (aesKeyTmp == NULL || macKeyTmp == NULL) {
SSL_DBG(("%d: SSL[%s]: Unable to unwrap session ticket keys.",
SSL_GETPID(), "unknown"));
goto loser;
}
SSL_DBG(("%d: SSL[%s]: Successfully unwrapped session ticket keys.",
SSL_GETPID(), "unknown"));
PORT_Memcpy(keyName, cache->ticketKeyNameSuffix,
SESS_TICKET_KEY_VAR_NAME_LEN);
*aesKey = aesKeyTmp;
*macKey = macKeyTmp;
return PR_TRUE;
loser:
if (aesKeyTmp)
PK11_FreeSymKey(aesKeyTmp);
if (macKeyTmp)
PK11_FreeSymKey(macKeyTmp);
return PR_FALSE;
}
PRBool
ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey,
SECKEYPublicKey *svrPubKey, void *pwArg,
unsigned char *keyName, PK11SymKey **aesKey,
PK11SymKey **macKey)
{
PRUint32 now = 0;
PRBool rv = PR_FALSE;
PRBool keysGenerated = PR_FALSE;
cacheDesc *cache = &globalCache;
if (!cache->cacheMem) {
return GenerateTicketKeys(pwArg, keyName, aesKey, macKey);
}
now = LockSidCacheLock(cache->keyCacheLock, now);
if (!now)
return rv;
if (!*(cache->ticketKeysValid)) {
if (!GenerateAndWrapTicketKeys(svrPubKey, pwArg, keyName,
aesKey, macKey))
goto loser;
keysGenerated = PR_TRUE;
*(cache->ticketKeysValid) = 1;
}
rv = PR_TRUE;
loser:
UnlockSidCacheLock(cache->keyCacheLock);
if (rv && !keysGenerated)
rv = UnwrapCachedTicketKeys(svrPrivKey, keyName, aesKey, macKey);
return rv;
}
PRBool
ssl_GetSessionTicketKeys(unsigned char *keyName, unsigned char *encKey,
unsigned char *macKey)
{
PRBool rv = PR_FALSE;
PRUint32 now = 0;
cacheDesc *cache = &globalCache;
PRUint8 ticketMacKey[SHA256_LENGTH], ticketEncKey[AES_256_KEY_LENGTH];
PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN];
PRUint8 *ticketMacKeyPtr, *ticketEncKeyPtr, *ticketKeyNameSuffix;
PRBool cacheIsEnabled = PR_TRUE;
if (!cache->cacheMem) {
cacheIsEnabled = PR_FALSE;
ticketKeyNameSuffix = ticketKeyNameSuffixLocal;
ticketEncKeyPtr = ticketEncKey;
ticketMacKeyPtr = ticketMacKey;
} else {
ticketKeyNameSuffix = cache->ticketKeyNameSuffix;
ticketEncKeyPtr = cache->ticketEncKey->bytes;
ticketMacKeyPtr = cache->ticketMacKey->bytes;
}
if (cacheIsEnabled) {
now = LockSidCacheLock(cache->keyCacheLock, now);
if (!now)
return rv;
}
if (!cacheIsEnabled || !*(cache->ticketKeysValid)) {
if (PK11_GenerateRandom(ticketKeyNameSuffix,
SESS_TICKET_KEY_VAR_NAME_LEN) != SECSuccess)
goto loser;
if (PK11_GenerateRandom(ticketEncKeyPtr,
AES_256_KEY_LENGTH) != SECSuccess)
goto loser;
if (PK11_GenerateRandom(ticketMacKeyPtr,
SHA256_LENGTH) != SECSuccess)
goto loser;
if (cacheIsEnabled) {
*(cache->ticketKeysValid) = 1;
}
}
rv = PR_TRUE;
loser:
if (cacheIsEnabled) {
UnlockSidCacheLock(cache->keyCacheLock);
}
if (rv) {
PORT_Memcpy(keyName, ticketKeyNameSuffix,
SESS_TICKET_KEY_VAR_NAME_LEN);
PORT_Memcpy(encKey, ticketEncKeyPtr, AES_256_KEY_LENGTH);
PORT_Memcpy(macKey, ticketMacKeyPtr, SHA256_LENGTH);
}
return rv;
}
PRBool
ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
{
cacheDesc * cache = &globalCache;
PRBool rv = PR_FALSE;
SSL3KEAType exchKeyType = wswk->exchKeyType;
PRInt32 symWrapMechIndex = wswk->symWrapMechIndex;
PRUint32 ndx;
PRUint32 now = 0;
SSLWrappedSymWrappingKey myWswk;
if (!cache->cacheMem) {
PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
return 0;
}
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;
ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
PORT_Memset(&myWswk, 0, sizeof myWswk);
now = LockSidCacheLock(cache->keyCacheLock, now);
if (now) {
rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->exchKeyType,
&myWswk, cache, now);
if (rv) {
PORT_Memcpy(wswk, &myWswk, sizeof *wswk);
} else {
cache->keyCacheData[ndx] = *wswk;
}
UnlockSidCacheLock(cache->keyCacheLock);
}
return rv;
}
#else
#include "seccomon.h"
#include "cert.h"
#include "ssl.h"
#include "sslimpl.h"
SECStatus
SSL_ConfigServerSessionIDCache( int maxCacheEntries,
PRUint32 ssl2_timeout,
PRUint32 ssl3_timeout,
const char * directory)
{
PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigServerSessionIDCache)");
return SECFailure;
}
SECStatus
SSL_ConfigMPServerSIDCache( int maxCacheEntries,
PRUint32 ssl2_timeout,
PRUint32 ssl3_timeout,
const char * directory)
{
PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigMPServerSIDCache)");
return SECFailure;
}
SECStatus
SSL_InheritMPServerSIDCache(const char * envString)
{
PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_InheritMPServerSIDCache)");
return SECFailure;
}
PRBool
ssl_GetWrappingKey( PRInt32 symWrapMechIndex,
SSL3KEAType exchKeyType,
SSLWrappedSymWrappingKey *wswk)
{
PRBool rv = PR_FALSE;
PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)");
return rv;
}
PRBool
ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
{
PRBool rv = PR_FALSE;
PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrappingKey)");
return rv;
}
PRUint32
SSL_GetMaxServerCacheLocks(void)
{
PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_GetMaxServerCacheLocks)");
return -1;
}
SECStatus
SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
{
PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_SetMaxServerCacheLocks)");
return SECFailure;
}
#endif