1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/ssl/sslsnce.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2212 @@ 1.4 +/* This file implements the SERVER Session ID cache. 1.5 + * NOTE: The contents of this file are NOT used by the client. 1.6 + * 1.7 + * This Source Code Form is subject to the terms of the Mozilla Public 1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.10 + 1.11 +/* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server 1.12 + * cache sids! 1.13 + * 1.14 + * About record locking among different server processes: 1.15 + * 1.16 + * All processes that are part of the same conceptual server (serving on 1.17 + * the same address and port) MUST share a common SSL session cache. 1.18 + * This code makes the content of the shared cache accessible to all 1.19 + * processes on the same "server". This code works on Unix and Win32 only. 1.20 + * 1.21 + * We use NSPR anonymous shared memory and move data to & from shared memory. 1.22 + * We must do explicit locking of the records for all reads and writes. 1.23 + * The set of Cache entries are divided up into "sets" of 128 entries. 1.24 + * Each set is protected by a lock. There may be one or more sets protected 1.25 + * by each lock. That is, locks to sets are 1:N. 1.26 + * There is one lock for the entire cert cache. 1.27 + * There is one lock for the set of wrapped sym wrap keys. 1.28 + * 1.29 + * The anonymous shared memory is laid out as if it were declared like this: 1.30 + * 1.31 + * struct { 1.32 + * cacheDescriptor desc; 1.33 + * sidCacheLock sidCacheLocks[ numSIDCacheLocks]; 1.34 + * sidCacheLock keyCacheLock; 1.35 + * sidCacheLock certCacheLock; 1.36 + * sidCacheSet sidCacheSets[ numSIDCacheSets ]; 1.37 + * sidCacheEntry sidCacheData[ numSIDCacheEntries]; 1.38 + * certCacheEntry certCacheData[numCertCacheEntries]; 1.39 + * SSLWrappedSymWrappingKey keyCacheData[kt_kea_size][SSL_NUM_WRAP_MECHS]; 1.40 + * PRUint8 keyNameSuffix[SESS_TICKET_KEY_VAR_NAME_LEN] 1.41 + * encKeyCacheEntry ticketEncKey; // Wrapped in non-bypass mode 1.42 + * encKeyCacheEntry ticketMacKey; // Wrapped in non-bypass mode 1.43 + * PRBool ticketKeysValid; 1.44 + * sidCacheLock srvNameCacheLock; 1.45 + * srvNameCacheEntry srvNameData[ numSrvNameCacheEntries ]; 1.46 + * } cacheMemCacheData; 1.47 + */ 1.48 +#include "seccomon.h" 1.49 + 1.50 +#if defined(XP_UNIX) || defined(XP_WIN32) || defined (XP_OS2) || defined(XP_BEOS) 1.51 + 1.52 +#include "cert.h" 1.53 +#include "ssl.h" 1.54 +#include "sslimpl.h" 1.55 +#include "sslproto.h" 1.56 +#include "pk11func.h" 1.57 +#include "base64.h" 1.58 +#include "keyhi.h" 1.59 +#ifdef NO_PKCS11_BYPASS 1.60 +#include "blapit.h" 1.61 +#include "sechash.h" 1.62 +#else 1.63 +#include "blapi.h" 1.64 +#endif 1.65 + 1.66 +#include <stdio.h> 1.67 + 1.68 +#if defined(XP_UNIX) || defined(XP_BEOS) 1.69 + 1.70 +#include <syslog.h> 1.71 +#include <fcntl.h> 1.72 +#include <unistd.h> 1.73 +#include <errno.h> 1.74 +#include <signal.h> 1.75 +#include "unix_err.h" 1.76 + 1.77 +#else 1.78 + 1.79 +#ifdef XP_WIN32 1.80 +#include <wtypes.h> 1.81 +#include "win32err.h" 1.82 +#endif 1.83 + 1.84 +#endif 1.85 +#include <sys/types.h> 1.86 + 1.87 +#define SET_ERROR_CODE /* reminder */ 1.88 + 1.89 +#include "nspr.h" 1.90 +#include "sslmutex.h" 1.91 + 1.92 +/* 1.93 +** Format of a cache entry in the shared memory. 1.94 +*/ 1.95 +struct sidCacheEntryStr { 1.96 +/* 16 */ PRIPv6Addr addr; /* client's IP address */ 1.97 +/* 4 */ PRUint32 creationTime; 1.98 +/* 4 */ PRUint32 lastAccessTime; 1.99 +/* 4 */ PRUint32 expirationTime; 1.100 +/* 2 */ PRUint16 version; 1.101 +/* 1 */ PRUint8 valid; 1.102 +/* 1 */ PRUint8 sessionIDLength; 1.103 +/* 32 */ PRUint8 sessionID[SSL3_SESSIONID_BYTES]; 1.104 +/* 2 */ PRUint16 authAlgorithm; 1.105 +/* 2 */ PRUint16 authKeyBits; 1.106 +/* 2 */ PRUint16 keaType; 1.107 +/* 2 */ PRUint16 keaKeyBits; 1.108 +/* 72 - common header total */ 1.109 + 1.110 + union { 1.111 + struct { 1.112 +/* 64 */ PRUint8 masterKey[SSL_MAX_MASTER_KEY_BYTES]; 1.113 +/* 32 */ PRUint8 cipherArg[SSL_MAX_CYPHER_ARG_BYTES]; 1.114 + 1.115 +/* 1 */ PRUint8 cipherType; 1.116 +/* 1 */ PRUint8 masterKeyLen; 1.117 +/* 1 */ PRUint8 keyBits; 1.118 +/* 1 */ PRUint8 secretKeyBits; 1.119 +/* 1 */ PRUint8 cipherArgLen; 1.120 +/*101 */} ssl2; 1.121 + 1.122 + struct { 1.123 +/* 2 */ ssl3CipherSuite cipherSuite; 1.124 +/* 2 */ PRUint16 compression; /* SSLCompressionMethod */ 1.125 + 1.126 +/* 52 */ ssl3SidKeys keys; /* keys, wrapped as needed. */ 1.127 + 1.128 +/* 4 */ PRUint32 masterWrapMech; 1.129 +/* 4 */ SSL3KEAType exchKeyType; 1.130 +/* 4 */ PRInt32 certIndex; 1.131 +/* 4 */ PRInt32 srvNameIndex; 1.132 +/* 32 */ PRUint8 srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */ 1.133 +/*104 */} ssl3; 1.134 +/* force sizeof(sidCacheEntry) to be a multiple of cache line size */ 1.135 + struct { 1.136 +/*120 */ PRUint8 filler[120]; /* 72+120==192, a multiple of 16 */ 1.137 + } forceSize; 1.138 + } u; 1.139 +}; 1.140 +typedef struct sidCacheEntryStr sidCacheEntry; 1.141 + 1.142 +/* The length of this struct is supposed to be a power of 2, e.g. 4KB */ 1.143 +struct certCacheEntryStr { 1.144 + PRUint16 certLength; /* 2 */ 1.145 + PRUint16 sessionIDLength; /* 2 */ 1.146 + PRUint8 sessionID[SSL3_SESSIONID_BYTES]; /* 32 */ 1.147 + PRUint8 cert[SSL_MAX_CACHED_CERT_LEN]; /* 4060 */ 1.148 +}; /* total 4096 */ 1.149 +typedef struct certCacheEntryStr certCacheEntry; 1.150 + 1.151 +struct sidCacheLockStr { 1.152 + PRUint32 timeStamp; 1.153 + sslMutex mutex; 1.154 + sslPID pid; 1.155 +}; 1.156 +typedef struct sidCacheLockStr sidCacheLock; 1.157 + 1.158 +struct sidCacheSetStr { 1.159 + PRIntn next; 1.160 +}; 1.161 +typedef struct sidCacheSetStr sidCacheSet; 1.162 + 1.163 +struct encKeyCacheEntryStr { 1.164 + PRUint8 bytes[512]; 1.165 + PRInt32 length; 1.166 +}; 1.167 +typedef struct encKeyCacheEntryStr encKeyCacheEntry; 1.168 + 1.169 +#define SSL_MAX_DNS_HOST_NAME 1024 1.170 + 1.171 +struct srvNameCacheEntryStr { 1.172 + PRUint16 type; /* 2 */ 1.173 + PRUint16 nameLen; /* 2 */ 1.174 + PRUint8 name[SSL_MAX_DNS_HOST_NAME + 12]; /* 1034 */ 1.175 + PRUint8 nameHash[SHA256_LENGTH]; /* 32 */ 1.176 + /* 1072 */ 1.177 +}; 1.178 +typedef struct srvNameCacheEntryStr srvNameCacheEntry; 1.179 + 1.180 + 1.181 +struct cacheDescStr { 1.182 + 1.183 + PRUint32 cacheMemSize; 1.184 + 1.185 + PRUint32 numSIDCacheLocks; 1.186 + PRUint32 numSIDCacheSets; 1.187 + PRUint32 numSIDCacheSetsPerLock; 1.188 + 1.189 + PRUint32 numSIDCacheEntries; 1.190 + PRUint32 sidCacheSize; 1.191 + 1.192 + PRUint32 numCertCacheEntries; 1.193 + PRUint32 certCacheSize; 1.194 + 1.195 + PRUint32 numKeyCacheEntries; 1.196 + PRUint32 keyCacheSize; 1.197 + 1.198 + PRUint32 numSrvNameCacheEntries; 1.199 + PRUint32 srvNameCacheSize; 1.200 + 1.201 + PRUint32 ssl2Timeout; 1.202 + PRUint32 ssl3Timeout; 1.203 + 1.204 + PRUint32 numSIDCacheLocksInitialized; 1.205 + 1.206 + /* These values are volatile, and are accessed through sharedCache-> */ 1.207 + PRUint32 nextCertCacheEntry; /* certCacheLock protects */ 1.208 + PRBool stopPolling; 1.209 + PRBool everInherited; 1.210 + 1.211 + /* The private copies of these values are pointers into shared mem */ 1.212 + /* The copies of these values in shared memory are merely offsets */ 1.213 + sidCacheLock * sidCacheLocks; 1.214 + sidCacheLock * keyCacheLock; 1.215 + sidCacheLock * certCacheLock; 1.216 + sidCacheLock * srvNameCacheLock; 1.217 + sidCacheSet * sidCacheSets; 1.218 + sidCacheEntry * sidCacheData; 1.219 + certCacheEntry * certCacheData; 1.220 + SSLWrappedSymWrappingKey * keyCacheData; 1.221 + PRUint8 * ticketKeyNameSuffix; 1.222 + encKeyCacheEntry * ticketEncKey; 1.223 + encKeyCacheEntry * ticketMacKey; 1.224 + PRUint32 * ticketKeysValid; 1.225 + srvNameCacheEntry * srvNameCacheData; 1.226 + 1.227 + /* Only the private copies of these pointers are valid */ 1.228 + char * cacheMem; 1.229 + struct cacheDescStr * sharedCache; /* shared copy of this struct */ 1.230 + PRFileMap * cacheMemMap; 1.231 + PRThread * poller; 1.232 + PRUint32 mutexTimeout; 1.233 + PRBool shared; 1.234 +}; 1.235 +typedef struct cacheDescStr cacheDesc; 1.236 + 1.237 +static cacheDesc globalCache; 1.238 + 1.239 +static const char envVarName[] = { SSL_ENV_VAR_NAME }; 1.240 + 1.241 +static PRBool isMultiProcess = PR_FALSE; 1.242 + 1.243 + 1.244 +#define DEF_SID_CACHE_ENTRIES 10000 1.245 +#define DEF_CERT_CACHE_ENTRIES 250 1.246 +#define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */ 1.247 +#define DEF_KEY_CACHE_ENTRIES 250 1.248 +#define DEF_NAME_CACHE_ENTRIES 1000 1.249 + 1.250 +#define SID_CACHE_ENTRIES_PER_SET 128 1.251 +#define SID_ALIGNMENT 16 1.252 + 1.253 +#define DEF_SSL2_TIMEOUT 100 /* seconds */ 1.254 +#define MAX_SSL2_TIMEOUT 100 /* seconds */ 1.255 +#define MIN_SSL2_TIMEOUT 5 /* seconds */ 1.256 + 1.257 +#define DEF_SSL3_TIMEOUT 86400L /* 24 hours */ 1.258 +#define MAX_SSL3_TIMEOUT 86400L /* 24 hours */ 1.259 +#define MIN_SSL3_TIMEOUT 5 /* seconds */ 1.260 + 1.261 +#if defined(AIX) || defined(LINUX) || defined(NETBSD) || defined(OPENBSD) 1.262 +#define MAX_SID_CACHE_LOCKS 8 /* two FDs per lock */ 1.263 +#elif defined(OSF1) 1.264 +#define MAX_SID_CACHE_LOCKS 16 /* one FD per lock */ 1.265 +#else 1.266 +#define MAX_SID_CACHE_LOCKS 256 1.267 +#endif 1.268 + 1.269 +#define SID_HOWMANY(val, size) (((val) + ((size) - 1)) / (size)) 1.270 +#define SID_ROUNDUP(val, size) ((size) * SID_HOWMANY((val), (size))) 1.271 + 1.272 + 1.273 +static sslPID myPid; 1.274 +static PRUint32 ssl_max_sid_cache_locks = MAX_SID_CACHE_LOCKS; 1.275 + 1.276 +/* forward static function declarations */ 1.277 +static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, 1.278 + unsigned nl); 1.279 +static SECStatus LaunchLockPoller(cacheDesc *cache); 1.280 +static SECStatus StopLockPoller(cacheDesc *cache); 1.281 + 1.282 + 1.283 +struct inheritanceStr { 1.284 + PRUint32 cacheMemSize; 1.285 + PRUint32 fmStrLen; 1.286 +}; 1.287 + 1.288 +typedef struct inheritanceStr inheritance; 1.289 + 1.290 +#if defined(_WIN32) || defined(XP_OS2) 1.291 + 1.292 +#define DEFAULT_CACHE_DIRECTORY "\\temp" 1.293 + 1.294 +#endif /* _win32 */ 1.295 + 1.296 +#if defined(XP_UNIX) || defined(XP_BEOS) 1.297 + 1.298 +#define DEFAULT_CACHE_DIRECTORY "/tmp" 1.299 + 1.300 +#endif /* XP_UNIX || XP_BEOS */ 1.301 + 1.302 + 1.303 +/************************************************************************/ 1.304 + 1.305 +static PRUint32 1.306 +LockSidCacheLock(sidCacheLock *lock, PRUint32 now) 1.307 +{ 1.308 + SECStatus rv = sslMutex_Lock(&lock->mutex); 1.309 + if (rv != SECSuccess) 1.310 + return 0; 1.311 + if (!now) 1.312 + now = ssl_Time(); 1.313 + lock->timeStamp = now; 1.314 + lock->pid = myPid; 1.315 + return now; 1.316 +} 1.317 + 1.318 +static SECStatus 1.319 +UnlockSidCacheLock(sidCacheLock *lock) 1.320 +{ 1.321 + SECStatus rv; 1.322 + 1.323 + lock->pid = 0; 1.324 + rv = sslMutex_Unlock(&lock->mutex); 1.325 + return rv; 1.326 +} 1.327 + 1.328 +/* returns the value of ssl_Time on success, zero on failure. */ 1.329 +static PRUint32 1.330 +LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now) 1.331 +{ 1.332 + PRUint32 lockNum = set % cache->numSIDCacheLocks; 1.333 + sidCacheLock * lock = cache->sidCacheLocks + lockNum; 1.334 + 1.335 + return LockSidCacheLock(lock, now); 1.336 +} 1.337 + 1.338 +static SECStatus 1.339 +UnlockSet(cacheDesc *cache, PRUint32 set) 1.340 +{ 1.341 + PRUint32 lockNum = set % cache->numSIDCacheLocks; 1.342 + sidCacheLock * lock = cache->sidCacheLocks + lockNum; 1.343 + 1.344 + return UnlockSidCacheLock(lock); 1.345 +} 1.346 + 1.347 +/************************************************************************/ 1.348 + 1.349 + 1.350 +/* Put a certificate in the cache. Update the cert index in the sce. 1.351 +*/ 1.352 +static PRUint32 1.353 +CacheCert(cacheDesc * cache, CERTCertificate *cert, sidCacheEntry *sce) 1.354 +{ 1.355 + PRUint32 now; 1.356 + certCacheEntry cce; 1.357 + 1.358 + if ((cert->derCert.len > SSL_MAX_CACHED_CERT_LEN) || 1.359 + (cert->derCert.len <= 0) || 1.360 + (cert->derCert.data == NULL)) { 1.361 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.362 + return 0; 1.363 + } 1.364 + 1.365 + cce.sessionIDLength = sce->sessionIDLength; 1.366 + PORT_Memcpy(cce.sessionID, sce->sessionID, cce.sessionIDLength); 1.367 + 1.368 + cce.certLength = cert->derCert.len; 1.369 + PORT_Memcpy(cce.cert, cert->derCert.data, cce.certLength); 1.370 + 1.371 + /* get lock on cert cache */ 1.372 + now = LockSidCacheLock(cache->certCacheLock, 0); 1.373 + if (now) { 1.374 + 1.375 + /* Find where to place the next cert cache entry. */ 1.376 + cacheDesc * sharedCache = cache->sharedCache; 1.377 + PRUint32 ndx = sharedCache->nextCertCacheEntry; 1.378 + 1.379 + /* write the entry */ 1.380 + cache->certCacheData[ndx] = cce; 1.381 + 1.382 + /* remember where we put it. */ 1.383 + sce->u.ssl3.certIndex = ndx; 1.384 + 1.385 + /* update the "next" cache entry index */ 1.386 + sharedCache->nextCertCacheEntry = 1.387 + (ndx + 1) % cache->numCertCacheEntries; 1.388 + 1.389 + UnlockSidCacheLock(cache->certCacheLock); 1.390 + } 1.391 + return now; 1.392 + 1.393 +} 1.394 + 1.395 +/* Server configuration hash tables need to account the SECITEM.type 1.396 + * field as well. These functions accomplish that. */ 1.397 +static PLHashNumber 1.398 +Get32BitNameHash(const SECItem *name) 1.399 +{ 1.400 + PLHashNumber rv = SECITEM_Hash(name); 1.401 + 1.402 + PRUint8 *rvc = (PRUint8 *)&rv; 1.403 + rvc[ name->len % sizeof(rv) ] ^= name->type; 1.404 + 1.405 + return rv; 1.406 +} 1.407 + 1.408 +/* Put a name in the cache. Update the cert index in the sce. 1.409 +*/ 1.410 +static PRUint32 1.411 +CacheSrvName(cacheDesc * cache, SECItem *name, sidCacheEntry *sce) 1.412 +{ 1.413 + PRUint32 now; 1.414 + PRUint32 ndx; 1.415 + srvNameCacheEntry snce; 1.416 + 1.417 + if (!name || name->len <= 0 || 1.418 + name->len > SSL_MAX_DNS_HOST_NAME) { 1.419 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.420 + return 0; 1.421 + } 1.422 + 1.423 + snce.type = name->type; 1.424 + snce.nameLen = name->len; 1.425 + PORT_Memcpy(snce.name, name->data, snce.nameLen); 1.426 +#ifdef NO_PKCS11_BYPASS 1.427 + HASH_HashBuf(HASH_AlgSHA256, snce.nameHash, name->data, name->len); 1.428 +#else 1.429 + SHA256_HashBuf(snce.nameHash, (unsigned char*)name->data, 1.430 + name->len); 1.431 +#endif 1.432 + /* get index of the next name */ 1.433 + ndx = Get32BitNameHash(name); 1.434 + /* get lock on cert cache */ 1.435 + now = LockSidCacheLock(cache->srvNameCacheLock, 0); 1.436 + if (now) { 1.437 + if (cache->numSrvNameCacheEntries > 0) { 1.438 + /* Fit the index into array */ 1.439 + ndx %= cache->numSrvNameCacheEntries; 1.440 + /* write the entry */ 1.441 + cache->srvNameCacheData[ndx] = snce; 1.442 + /* remember where we put it. */ 1.443 + sce->u.ssl3.srvNameIndex = ndx; 1.444 + /* Copy hash into sid hash */ 1.445 + PORT_Memcpy(sce->u.ssl3.srvNameHash, snce.nameHash, SHA256_LENGTH); 1.446 + } 1.447 + UnlockSidCacheLock(cache->srvNameCacheLock); 1.448 + } 1.449 + return now; 1.450 +} 1.451 + 1.452 +/* 1.453 +** Convert local SID to shared memory one 1.454 +*/ 1.455 +static void 1.456 +ConvertFromSID(sidCacheEntry *to, sslSessionID *from) 1.457 +{ 1.458 + to->valid = 1; 1.459 + to->version = from->version; 1.460 + to->addr = from->addr; 1.461 + to->creationTime = from->creationTime; 1.462 + to->lastAccessTime = from->lastAccessTime; 1.463 + to->expirationTime = from->expirationTime; 1.464 + to->authAlgorithm = from->authAlgorithm; 1.465 + to->authKeyBits = from->authKeyBits; 1.466 + to->keaType = from->keaType; 1.467 + to->keaKeyBits = from->keaKeyBits; 1.468 + 1.469 + if (from->version < SSL_LIBRARY_VERSION_3_0) { 1.470 + if ((from->u.ssl2.masterKey.len > SSL_MAX_MASTER_KEY_BYTES) || 1.471 + (from->u.ssl2.cipherArg.len > SSL_MAX_CYPHER_ARG_BYTES)) { 1.472 + SSL_DBG(("%d: SSL: masterKeyLen=%d cipherArgLen=%d", 1.473 + myPid, from->u.ssl2.masterKey.len, 1.474 + from->u.ssl2.cipherArg.len)); 1.475 + to->valid = 0; 1.476 + return; 1.477 + } 1.478 + 1.479 + to->u.ssl2.cipherType = from->u.ssl2.cipherType; 1.480 + to->u.ssl2.masterKeyLen = from->u.ssl2.masterKey.len; 1.481 + to->u.ssl2.cipherArgLen = from->u.ssl2.cipherArg.len; 1.482 + to->u.ssl2.keyBits = from->u.ssl2.keyBits; 1.483 + to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits; 1.484 + to->sessionIDLength = SSL2_SESSIONID_BYTES; 1.485 + PORT_Memcpy(to->sessionID, from->u.ssl2.sessionID, SSL2_SESSIONID_BYTES); 1.486 + PORT_Memcpy(to->u.ssl2.masterKey, from->u.ssl2.masterKey.data, 1.487 + from->u.ssl2.masterKey.len); 1.488 + PORT_Memcpy(to->u.ssl2.cipherArg, from->u.ssl2.cipherArg.data, 1.489 + from->u.ssl2.cipherArg.len); 1.490 +#ifdef DEBUG 1.491 + PORT_Memset(to->u.ssl2.masterKey+from->u.ssl2.masterKey.len, 0, 1.492 + sizeof(to->u.ssl2.masterKey) - from->u.ssl2.masterKey.len); 1.493 + PORT_Memset(to->u.ssl2.cipherArg+from->u.ssl2.cipherArg.len, 0, 1.494 + sizeof(to->u.ssl2.cipherArg) - from->u.ssl2.cipherArg.len); 1.495 +#endif 1.496 + SSL_TRC(8, ("%d: SSL: ConvertSID: masterKeyLen=%d cipherArgLen=%d " 1.497 + "time=%d addr=0x%08x%08x%08x%08x cipherType=%d", myPid, 1.498 + to->u.ssl2.masterKeyLen, to->u.ssl2.cipherArgLen, 1.499 + to->creationTime, to->addr.pr_s6_addr32[0], 1.500 + to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2], 1.501 + to->addr.pr_s6_addr32[3], to->u.ssl2.cipherType)); 1.502 + } else { 1.503 + /* This is an SSL v3 session */ 1.504 + 1.505 + to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite; 1.506 + to->u.ssl3.compression = (PRUint16)from->u.ssl3.compression; 1.507 + to->u.ssl3.keys = from->u.ssl3.keys; 1.508 + to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech; 1.509 + to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType; 1.510 + to->sessionIDLength = from->u.ssl3.sessionIDLength; 1.511 + to->u.ssl3.certIndex = -1; 1.512 + to->u.ssl3.srvNameIndex = -1; 1.513 + 1.514 + PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID, 1.515 + to->sessionIDLength); 1.516 + 1.517 + SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x " 1.518 + "cipherSuite=%d", 1.519 + myPid, to->creationTime, to->addr.pr_s6_addr32[0], 1.520 + to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2], 1.521 + to->addr.pr_s6_addr32[3], to->u.ssl3.cipherSuite)); 1.522 + } 1.523 +} 1.524 + 1.525 +/* 1.526 +** Convert shared memory cache-entry to local memory based one 1.527 +** This is only called from ServerSessionIDLookup(). 1.528 +*/ 1.529 +static sslSessionID * 1.530 +ConvertToSID(sidCacheEntry * from, 1.531 + certCacheEntry * pcce, 1.532 + srvNameCacheEntry *psnce, 1.533 + CERTCertDBHandle * dbHandle) 1.534 +{ 1.535 + sslSessionID *to; 1.536 + PRUint16 version = from->version; 1.537 + 1.538 + to = PORT_ZNew(sslSessionID); 1.539 + if (!to) { 1.540 + return 0; 1.541 + } 1.542 + 1.543 + if (version < SSL_LIBRARY_VERSION_3_0) { 1.544 + /* This is an SSL v2 session */ 1.545 + to->u.ssl2.masterKey.data = 1.546 + (unsigned char*) PORT_Alloc(from->u.ssl2.masterKeyLen); 1.547 + if (!to->u.ssl2.masterKey.data) { 1.548 + goto loser; 1.549 + } 1.550 + if (from->u.ssl2.cipherArgLen) { 1.551 + to->u.ssl2.cipherArg.data = 1.552 + (unsigned char*)PORT_Alloc(from->u.ssl2.cipherArgLen); 1.553 + if (!to->u.ssl2.cipherArg.data) { 1.554 + goto loser; 1.555 + } 1.556 + PORT_Memcpy(to->u.ssl2.cipherArg.data, from->u.ssl2.cipherArg, 1.557 + from->u.ssl2.cipherArgLen); 1.558 + } 1.559 + 1.560 + to->u.ssl2.cipherType = from->u.ssl2.cipherType; 1.561 + to->u.ssl2.masterKey.len = from->u.ssl2.masterKeyLen; 1.562 + to->u.ssl2.cipherArg.len = from->u.ssl2.cipherArgLen; 1.563 + to->u.ssl2.keyBits = from->u.ssl2.keyBits; 1.564 + to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits; 1.565 +/* to->sessionIDLength = SSL2_SESSIONID_BYTES; */ 1.566 + PORT_Memcpy(to->u.ssl2.sessionID, from->sessionID, SSL2_SESSIONID_BYTES); 1.567 + PORT_Memcpy(to->u.ssl2.masterKey.data, from->u.ssl2.masterKey, 1.568 + from->u.ssl2.masterKeyLen); 1.569 + 1.570 + SSL_TRC(8, ("%d: SSL: ConvertToSID: masterKeyLen=%d cipherArgLen=%d " 1.571 + "time=%d addr=0x%08x%08x%08x%08x cipherType=%d", 1.572 + myPid, to->u.ssl2.masterKey.len, 1.573 + to->u.ssl2.cipherArg.len, to->creationTime, 1.574 + to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1], 1.575 + to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3], 1.576 + to->u.ssl2.cipherType)); 1.577 + } else { 1.578 + /* This is an SSL v3 session */ 1.579 + 1.580 + to->u.ssl3.sessionIDLength = from->sessionIDLength; 1.581 + to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite; 1.582 + to->u.ssl3.compression = (SSLCompressionMethod)from->u.ssl3.compression; 1.583 + to->u.ssl3.keys = from->u.ssl3.keys; 1.584 + to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech; 1.585 + to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType; 1.586 + if (from->u.ssl3.srvNameIndex != -1 && psnce) { 1.587 + SECItem name; 1.588 + SECStatus rv; 1.589 + name.type = psnce->type; 1.590 + name.len = psnce->nameLen; 1.591 + name.data = psnce->name; 1.592 + rv = SECITEM_CopyItem(NULL, &to->u.ssl3.srvName, &name); 1.593 + if (rv != SECSuccess) { 1.594 + goto loser; 1.595 + } 1.596 + } 1.597 + 1.598 + PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength); 1.599 + 1.600 + /* the portions of the SID that are only restored on the client 1.601 + * are set to invalid values on the server. 1.602 + */ 1.603 + to->u.ssl3.clientWriteKey = NULL; 1.604 + to->u.ssl3.serverWriteKey = NULL; 1.605 + 1.606 + to->urlSvrName = NULL; 1.607 + 1.608 + to->u.ssl3.masterModuleID = (SECMODModuleID)-1; /* invalid value */ 1.609 + to->u.ssl3.masterSlotID = (CK_SLOT_ID)-1; /* invalid value */ 1.610 + to->u.ssl3.masterWrapIndex = 0; 1.611 + to->u.ssl3.masterWrapSeries = 0; 1.612 + to->u.ssl3.masterValid = PR_FALSE; 1.613 + 1.614 + to->u.ssl3.clAuthModuleID = (SECMODModuleID)-1; /* invalid value */ 1.615 + to->u.ssl3.clAuthSlotID = (CK_SLOT_ID)-1; /* invalid value */ 1.616 + to->u.ssl3.clAuthSeries = 0; 1.617 + to->u.ssl3.clAuthValid = PR_FALSE; 1.618 + 1.619 + if (from->u.ssl3.certIndex != -1 && pcce) { 1.620 + SECItem derCert; 1.621 + 1.622 + derCert.len = pcce->certLength; 1.623 + derCert.data = pcce->cert; 1.624 + 1.625 + to->peerCert = CERT_NewTempCertificate(dbHandle, &derCert, NULL, 1.626 + PR_FALSE, PR_TRUE); 1.627 + if (to->peerCert == NULL) 1.628 + goto loser; 1.629 + } 1.630 + } 1.631 + 1.632 + to->version = from->version; 1.633 + to->creationTime = from->creationTime; 1.634 + to->lastAccessTime = from->lastAccessTime; 1.635 + to->expirationTime = from->expirationTime; 1.636 + to->cached = in_server_cache; 1.637 + to->addr = from->addr; 1.638 + to->references = 1; 1.639 + to->authAlgorithm = from->authAlgorithm; 1.640 + to->authKeyBits = from->authKeyBits; 1.641 + to->keaType = from->keaType; 1.642 + to->keaKeyBits = from->keaKeyBits; 1.643 + 1.644 + return to; 1.645 + 1.646 + loser: 1.647 + if (to) { 1.648 + if (version < SSL_LIBRARY_VERSION_3_0) { 1.649 + if (to->u.ssl2.masterKey.data) 1.650 + PORT_Free(to->u.ssl2.masterKey.data); 1.651 + if (to->u.ssl2.cipherArg.data) 1.652 + PORT_Free(to->u.ssl2.cipherArg.data); 1.653 + } else { 1.654 + SECITEM_FreeItem(&to->u.ssl3.srvName, PR_FALSE); 1.655 + } 1.656 + PORT_Free(to); 1.657 + } 1.658 + return NULL; 1.659 +} 1.660 + 1.661 + 1.662 + 1.663 +/* 1.664 +** Perform some mumbo jumbo on the ip-address and the session-id value to 1.665 +** compute a hash value. 1.666 +*/ 1.667 +static PRUint32 1.668 +SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl) 1.669 +{ 1.670 + PRUint32 rv; 1.671 + PRUint32 x[8]; 1.672 + 1.673 + memset(x, 0, sizeof x); 1.674 + if (nl > sizeof x) 1.675 + nl = sizeof x; 1.676 + memcpy(x, s, nl); 1.677 + 1.678 + rv = (addr->pr_s6_addr32[0] ^ addr->pr_s6_addr32[1] ^ 1.679 + addr->pr_s6_addr32[2] ^ addr->pr_s6_addr32[3] ^ 1.680 + x[0] ^ x[1] ^ x[2] ^ x[3] ^ x[4] ^ x[5] ^ x[6] ^ x[7]) 1.681 + % cache->numSIDCacheSets; 1.682 + return rv; 1.683 +} 1.684 + 1.685 + 1.686 + 1.687 +/* 1.688 +** Look something up in the cache. This will invalidate old entries 1.689 +** in the process. Caller has locked the cache set! 1.690 +** Returns PR_TRUE if found a valid match. PR_FALSE otherwise. 1.691 +*/ 1.692 +static sidCacheEntry * 1.693 +FindSID(cacheDesc *cache, PRUint32 setNum, PRUint32 now, 1.694 + const PRIPv6Addr *addr, unsigned char *sessionID, 1.695 + unsigned sessionIDLength) 1.696 +{ 1.697 + PRUint32 ndx = cache->sidCacheSets[setNum].next; 1.698 + int i; 1.699 + 1.700 + sidCacheEntry * set = cache->sidCacheData + 1.701 + (setNum * SID_CACHE_ENTRIES_PER_SET); 1.702 + 1.703 + for (i = SID_CACHE_ENTRIES_PER_SET; i > 0; --i) { 1.704 + sidCacheEntry * sce; 1.705 + 1.706 + ndx = (ndx - 1) % SID_CACHE_ENTRIES_PER_SET; 1.707 + sce = set + ndx; 1.708 + 1.709 + if (!sce->valid) 1.710 + continue; 1.711 + 1.712 + if (now > sce->expirationTime) { 1.713 + /* SessionID has timed out. Invalidate the entry. */ 1.714 + SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x " 1.715 + "time+=%x", 1.716 + myPid, sce->addr.pr_s6_addr32[0], 1.717 + sce->addr.pr_s6_addr32[1], sce->addr.pr_s6_addr32[2], 1.718 + sce->addr.pr_s6_addr32[3], now, 1.719 + sce->expirationTime )); 1.720 + sce->valid = 0; 1.721 + continue; 1.722 + } 1.723 + 1.724 + /* 1.725 + ** Next, examine specific session-id/addr data to see if the cache 1.726 + ** entry matches our addr+session-id value 1.727 + */ 1.728 + if (sessionIDLength == sce->sessionIDLength && 1.729 + !memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) && 1.730 + !memcmp(sce->sessionID, sessionID, sessionIDLength)) { 1.731 + /* Found it */ 1.732 + return sce; 1.733 + } 1.734 + } 1.735 + 1.736 + PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND); 1.737 + return NULL; 1.738 +} 1.739 + 1.740 +/************************************************************************/ 1.741 + 1.742 +/* This is the primary function for finding entries in the server's sid cache. 1.743 + * Although it is static, this function is called via the global function 1.744 + * pointer ssl_sid_lookup. 1.745 + */ 1.746 +static sslSessionID * 1.747 +ServerSessionIDLookup(const PRIPv6Addr *addr, 1.748 + unsigned char *sessionID, 1.749 + unsigned int sessionIDLength, 1.750 + CERTCertDBHandle * dbHandle) 1.751 +{ 1.752 + sslSessionID * sid = 0; 1.753 + sidCacheEntry * psce; 1.754 + certCacheEntry *pcce = 0; 1.755 + srvNameCacheEntry *psnce = 0; 1.756 + cacheDesc * cache = &globalCache; 1.757 + PRUint32 now; 1.758 + PRUint32 set; 1.759 + PRInt32 cndx; 1.760 + sidCacheEntry sce; 1.761 + certCacheEntry cce; 1.762 + srvNameCacheEntry snce; 1.763 + 1.764 + set = SIDindex(cache, addr, sessionID, sessionIDLength); 1.765 + now = LockSet(cache, set, 0); 1.766 + if (!now) 1.767 + return NULL; 1.768 + 1.769 + psce = FindSID(cache, set, now, addr, sessionID, sessionIDLength); 1.770 + if (psce) { 1.771 + if (psce->version >= SSL_LIBRARY_VERSION_3_0) { 1.772 + if ((cndx = psce->u.ssl3.certIndex) != -1) { 1.773 + 1.774 + PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now); 1.775 + if (gotLock) { 1.776 + pcce = &cache->certCacheData[cndx]; 1.777 + 1.778 + /* See if the cert's session ID matches the sce cache. */ 1.779 + if ((pcce->sessionIDLength == psce->sessionIDLength) && 1.780 + !PORT_Memcmp(pcce->sessionID, psce->sessionID, 1.781 + pcce->sessionIDLength)) { 1.782 + cce = *pcce; 1.783 + } else { 1.784 + /* The cert doesen't match the SID cache entry, 1.785 + ** so invalidate the SID cache entry. 1.786 + */ 1.787 + psce->valid = 0; 1.788 + psce = 0; 1.789 + pcce = 0; 1.790 + } 1.791 + UnlockSidCacheLock(cache->certCacheLock); 1.792 + } else { 1.793 + /* what the ??. Didn't get the cert cache lock. 1.794 + ** Don't invalidate the SID cache entry, but don't find it. 1.795 + */ 1.796 + PORT_Assert(!("Didn't get cert Cache Lock!")); 1.797 + psce = 0; 1.798 + pcce = 0; 1.799 + } 1.800 + } 1.801 + if (psce && ((cndx = psce->u.ssl3.srvNameIndex) != -1)) { 1.802 + PRUint32 gotLock = LockSidCacheLock(cache->srvNameCacheLock, 1.803 + now); 1.804 + if (gotLock) { 1.805 + psnce = &cache->srvNameCacheData[cndx]; 1.806 + 1.807 + if (!PORT_Memcmp(psnce->nameHash, psce->u.ssl3.srvNameHash, 1.808 + SHA256_LENGTH)) { 1.809 + snce = *psnce; 1.810 + } else { 1.811 + /* The name doesen't match the SID cache entry, 1.812 + ** so invalidate the SID cache entry. 1.813 + */ 1.814 + psce->valid = 0; 1.815 + psce = 0; 1.816 + psnce = 0; 1.817 + } 1.818 + UnlockSidCacheLock(cache->srvNameCacheLock); 1.819 + } else { 1.820 + /* what the ??. Didn't get the cert cache lock. 1.821 + ** Don't invalidate the SID cache entry, but don't find it. 1.822 + */ 1.823 + PORT_Assert(!("Didn't get name Cache Lock!")); 1.824 + psce = 0; 1.825 + psnce = 0; 1.826 + } 1.827 + 1.828 + } 1.829 + } 1.830 + if (psce) { 1.831 + psce->lastAccessTime = now; 1.832 + sce = *psce; /* grab a copy while holding the lock */ 1.833 + } 1.834 + } 1.835 + UnlockSet(cache, set); 1.836 + if (psce) { 1.837 + /* sce conains a copy of the cache entry. 1.838 + ** Convert shared memory format to local format 1.839 + */ 1.840 + sid = ConvertToSID(&sce, pcce ? &cce : 0, psnce ? &snce : 0, dbHandle); 1.841 + } 1.842 + return sid; 1.843 +} 1.844 + 1.845 +/* 1.846 +** Place a sid into the cache, if it isn't already there. 1.847 +*/ 1.848 +static void 1.849 +ServerSessionIDCache(sslSessionID *sid) 1.850 +{ 1.851 + sidCacheEntry sce; 1.852 + PRUint32 now = 0; 1.853 + PRUint16 version = sid->version; 1.854 + cacheDesc * cache = &globalCache; 1.855 + 1.856 + if ((version >= SSL_LIBRARY_VERSION_3_0) && 1.857 + (sid->u.ssl3.sessionIDLength == 0)) { 1.858 + return; 1.859 + } 1.860 + 1.861 + if (sid->cached == never_cached || sid->cached == invalid_cache) { 1.862 + PRUint32 set; 1.863 + 1.864 + PORT_Assert(sid->creationTime != 0); 1.865 + if (!sid->creationTime) 1.866 + sid->lastAccessTime = sid->creationTime = ssl_Time(); 1.867 + if (version < SSL_LIBRARY_VERSION_3_0) { 1.868 + /* override caller's expiration time, which uses client timeout 1.869 + * duration, not server timeout duration. 1.870 + */ 1.871 + sid->expirationTime = sid->creationTime + cache->ssl2Timeout; 1.872 + SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x " 1.873 + "cipher=%d", myPid, sid->cached, 1.874 + sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], 1.875 + sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], 1.876 + sid->creationTime, sid->u.ssl2.cipherType)); 1.877 + PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID, 1.878 + SSL2_SESSIONID_BYTES)); 1.879 + PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data, 1.880 + sid->u.ssl2.masterKey.len)); 1.881 + PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data, 1.882 + sid->u.ssl2.cipherArg.len)); 1.883 + 1.884 + } else { 1.885 + /* override caller's expiration time, which uses client timeout 1.886 + * duration, not server timeout duration. 1.887 + */ 1.888 + sid->expirationTime = sid->creationTime + cache->ssl3Timeout; 1.889 + SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x " 1.890 + "cipherSuite=%d", myPid, sid->cached, 1.891 + sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], 1.892 + sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], 1.893 + sid->creationTime, sid->u.ssl3.cipherSuite)); 1.894 + PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID, 1.895 + sid->u.ssl3.sessionIDLength)); 1.896 + } 1.897 + 1.898 + ConvertFromSID(&sce, sid); 1.899 + 1.900 + if (version >= SSL_LIBRARY_VERSION_3_0) { 1.901 + SECItem *name = &sid->u.ssl3.srvName; 1.902 + if (name->len && name->data) { 1.903 + now = CacheSrvName(cache, name, &sce); 1.904 + } 1.905 + if (sid->peerCert != NULL) { 1.906 + now = CacheCert(cache, sid->peerCert, &sce); 1.907 + } 1.908 + } 1.909 + 1.910 + set = SIDindex(cache, &sce.addr, sce.sessionID, sce.sessionIDLength); 1.911 + now = LockSet(cache, set, now); 1.912 + if (now) { 1.913 + PRUint32 next = cache->sidCacheSets[set].next; 1.914 + PRUint32 ndx = set * SID_CACHE_ENTRIES_PER_SET + next; 1.915 + 1.916 + /* Write out new cache entry */ 1.917 + cache->sidCacheData[ndx] = sce; 1.918 + 1.919 + cache->sidCacheSets[set].next = 1.920 + (next + 1) % SID_CACHE_ENTRIES_PER_SET; 1.921 + 1.922 + UnlockSet(cache, set); 1.923 + sid->cached = in_server_cache; 1.924 + } 1.925 + } 1.926 +} 1.927 + 1.928 +/* 1.929 +** Although this is static, it is called from ssl via global function pointer 1.930 +** ssl_sid_uncache. This invalidates the referenced cache entry. 1.931 +*/ 1.932 +static void 1.933 +ServerSessionIDUncache(sslSessionID *sid) 1.934 +{ 1.935 + cacheDesc * cache = &globalCache; 1.936 + PRUint8 * sessionID; 1.937 + unsigned int sessionIDLength; 1.938 + PRErrorCode err; 1.939 + PRUint32 set; 1.940 + PRUint32 now; 1.941 + sidCacheEntry *psce; 1.942 + 1.943 + if (sid == NULL) 1.944 + return; 1.945 + 1.946 + /* Uncaching a SID should never change the error code. 1.947 + ** So save it here and restore it before exiting. 1.948 + */ 1.949 + err = PR_GetError(); 1.950 + 1.951 + if (sid->version < SSL_LIBRARY_VERSION_3_0) { 1.952 + sessionID = sid->u.ssl2.sessionID; 1.953 + sessionIDLength = SSL2_SESSIONID_BYTES; 1.954 + SSL_TRC(8, ("%d: SSL: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x " 1.955 + "cipher=%d", myPid, sid->cached, 1.956 + sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], 1.957 + sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], 1.958 + sid->creationTime, sid->u.ssl2.cipherType)); 1.959 + PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength)); 1.960 + PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data, 1.961 + sid->u.ssl2.masterKey.len)); 1.962 + PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data, 1.963 + sid->u.ssl2.cipherArg.len)); 1.964 + } else { 1.965 + sessionID = sid->u.ssl3.sessionID; 1.966 + sessionIDLength = sid->u.ssl3.sessionIDLength; 1.967 + SSL_TRC(8, ("%d: SSL3: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x " 1.968 + "cipherSuite=%d", myPid, sid->cached, 1.969 + sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], 1.970 + sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], 1.971 + sid->creationTime, sid->u.ssl3.cipherSuite)); 1.972 + PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength)); 1.973 + } 1.974 + set = SIDindex(cache, &sid->addr, sessionID, sessionIDLength); 1.975 + now = LockSet(cache, set, 0); 1.976 + if (now) { 1.977 + psce = FindSID(cache, set, now, &sid->addr, sessionID, sessionIDLength); 1.978 + if (psce) { 1.979 + psce->valid = 0; 1.980 + } 1.981 + UnlockSet(cache, set); 1.982 + } 1.983 + sid->cached = invalid_cache; 1.984 + PORT_SetError(err); 1.985 +} 1.986 + 1.987 +#ifdef XP_OS2 1.988 + 1.989 +#define INCL_DOSPROCESS 1.990 +#include <os2.h> 1.991 + 1.992 +long gettid(void) 1.993 +{ 1.994 + PTIB ptib; 1.995 + PPIB ppib; 1.996 + DosGetInfoBlocks(&ptib, &ppib); 1.997 + return ((long)ptib->tib_ordinal); /* thread id */ 1.998 +} 1.999 +#endif 1.1000 + 1.1001 +static void 1.1002 +CloseCache(cacheDesc *cache) 1.1003 +{ 1.1004 + int locks_initialized = cache->numSIDCacheLocksInitialized; 1.1005 + 1.1006 + if (cache->cacheMem) { 1.1007 + if (cache->sharedCache) { 1.1008 + sidCacheLock *pLock = cache->sidCacheLocks; 1.1009 + for (; locks_initialized > 0; --locks_initialized, ++pLock ) { 1.1010 + /* If everInherited is true, this shared cache was (and may 1.1011 + ** still be) in use by multiple processes. We do not wish to 1.1012 + ** destroy the mutexes while they are still in use, but we do 1.1013 + ** want to free mutex resources associated with this process. 1.1014 + */ 1.1015 + sslMutex_Destroy(&pLock->mutex, 1.1016 + cache->sharedCache->everInherited); 1.1017 + } 1.1018 + } 1.1019 + if (cache->shared) { 1.1020 + PR_MemUnmap(cache->cacheMem, cache->cacheMemSize); 1.1021 + } else { 1.1022 + PORT_Free(cache->cacheMem); 1.1023 + } 1.1024 + cache->cacheMem = NULL; 1.1025 + } 1.1026 + if (cache->cacheMemMap) { 1.1027 + PR_CloseFileMap(cache->cacheMemMap); 1.1028 + cache->cacheMemMap = NULL; 1.1029 + } 1.1030 + memset(cache, 0, sizeof *cache); 1.1031 +} 1.1032 + 1.1033 +static SECStatus 1.1034 +InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries, 1.1035 + int maxSrvNameCacheEntries, PRUint32 ssl2_timeout, 1.1036 + PRUint32 ssl3_timeout, const char *directory, PRBool shared) 1.1037 +{ 1.1038 + ptrdiff_t ptr; 1.1039 + sidCacheLock *pLock; 1.1040 + char * cacheMem; 1.1041 + PRFileMap * cacheMemMap; 1.1042 + char * cfn = NULL; /* cache file name */ 1.1043 + int locks_initialized = 0; 1.1044 + int locks_to_initialize = 0; 1.1045 + PRUint32 init_time; 1.1046 + 1.1047 + if ( (!cache) || (maxCacheEntries < 0) || (!directory) ) { 1.1048 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.1049 + return SECFailure; 1.1050 + } 1.1051 + 1.1052 + if (cache->cacheMem) { 1.1053 + /* Already done */ 1.1054 + return SECSuccess; 1.1055 + } 1.1056 + 1.1057 + /* make sure loser can clean up properly */ 1.1058 + cache->shared = shared; 1.1059 + cache->cacheMem = cacheMem = NULL; 1.1060 + cache->cacheMemMap = cacheMemMap = NULL; 1.1061 + cache->sharedCache = (cacheDesc *)0; 1.1062 + 1.1063 + cache->numSIDCacheLocksInitialized = 0; 1.1064 + cache->nextCertCacheEntry = 0; 1.1065 + cache->stopPolling = PR_FALSE; 1.1066 + cache->everInherited = PR_FALSE; 1.1067 + cache->poller = NULL; 1.1068 + cache->mutexTimeout = 0; 1.1069 + 1.1070 + cache->numSIDCacheEntries = maxCacheEntries ? maxCacheEntries 1.1071 + : DEF_SID_CACHE_ENTRIES; 1.1072 + cache->numSIDCacheSets = 1.1073 + SID_HOWMANY(cache->numSIDCacheEntries, SID_CACHE_ENTRIES_PER_SET); 1.1074 + 1.1075 + cache->numSIDCacheEntries = 1.1076 + cache->numSIDCacheSets * SID_CACHE_ENTRIES_PER_SET; 1.1077 + 1.1078 + cache->numSIDCacheLocks = 1.1079 + PR_MIN(cache->numSIDCacheSets, ssl_max_sid_cache_locks); 1.1080 + 1.1081 + cache->numSIDCacheSetsPerLock = 1.1082 + SID_HOWMANY(cache->numSIDCacheSets, cache->numSIDCacheLocks); 1.1083 + 1.1084 + cache->numCertCacheEntries = (maxCertCacheEntries > 0) ? 1.1085 + maxCertCacheEntries : 0; 1.1086 + cache->numSrvNameCacheEntries = (maxSrvNameCacheEntries >= 0) ? 1.1087 + maxSrvNameCacheEntries : DEF_NAME_CACHE_ENTRIES; 1.1088 + 1.1089 + /* compute size of shared memory, and offsets of all pointers */ 1.1090 + ptr = 0; 1.1091 + cache->cacheMem = (char *)ptr; 1.1092 + ptr += SID_ROUNDUP(sizeof(cacheDesc), SID_ALIGNMENT); 1.1093 + 1.1094 + cache->sidCacheLocks = (sidCacheLock *)ptr; 1.1095 + cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks; 1.1096 + cache->certCacheLock = cache->keyCacheLock + 1; 1.1097 + cache->srvNameCacheLock = cache->certCacheLock + 1; 1.1098 + ptr = (ptrdiff_t)(cache->srvNameCacheLock + 1); 1.1099 + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); 1.1100 + 1.1101 + cache->sidCacheSets = (sidCacheSet *)ptr; 1.1102 + ptr = (ptrdiff_t)(cache->sidCacheSets + cache->numSIDCacheSets); 1.1103 + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); 1.1104 + 1.1105 + cache->sidCacheData = (sidCacheEntry *)ptr; 1.1106 + ptr = (ptrdiff_t)(cache->sidCacheData + cache->numSIDCacheEntries); 1.1107 + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); 1.1108 + 1.1109 + cache->certCacheData = (certCacheEntry *)ptr; 1.1110 + cache->sidCacheSize = 1.1111 + (char *)cache->certCacheData - (char *)cache->sidCacheData; 1.1112 + 1.1113 + if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) { 1.1114 + /* This is really a poor way to computer this! */ 1.1115 + cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry); 1.1116 + if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) 1.1117 + cache->numCertCacheEntries = MIN_CERT_CACHE_ENTRIES; 1.1118 + } 1.1119 + ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries); 1.1120 + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); 1.1121 + 1.1122 + cache->keyCacheData = (SSLWrappedSymWrappingKey *)ptr; 1.1123 + cache->certCacheSize = 1.1124 + (char *)cache->keyCacheData - (char *)cache->certCacheData; 1.1125 + 1.1126 + cache->numKeyCacheEntries = kt_kea_size * SSL_NUM_WRAP_MECHS; 1.1127 + ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries); 1.1128 + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); 1.1129 + 1.1130 + cache->keyCacheSize = (char *)ptr - (char *)cache->keyCacheData; 1.1131 + 1.1132 + cache->ticketKeyNameSuffix = (PRUint8 *)ptr; 1.1133 + ptr = (ptrdiff_t)(cache->ticketKeyNameSuffix + 1.1134 + SESS_TICKET_KEY_VAR_NAME_LEN); 1.1135 + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); 1.1136 + 1.1137 + cache->ticketEncKey = (encKeyCacheEntry *)ptr; 1.1138 + ptr = (ptrdiff_t)(cache->ticketEncKey + 1); 1.1139 + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); 1.1140 + 1.1141 + cache->ticketMacKey = (encKeyCacheEntry *)ptr; 1.1142 + ptr = (ptrdiff_t)(cache->ticketMacKey + 1); 1.1143 + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); 1.1144 + 1.1145 + cache->ticketKeysValid = (PRUint32 *)ptr; 1.1146 + ptr = (ptrdiff_t)(cache->ticketKeysValid + 1); 1.1147 + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); 1.1148 + 1.1149 + cache->srvNameCacheData = (srvNameCacheEntry *)ptr; 1.1150 + cache->srvNameCacheSize = 1.1151 + cache->numSrvNameCacheEntries * sizeof(srvNameCacheEntry); 1.1152 + ptr = (ptrdiff_t)(cache->srvNameCacheData + cache->numSrvNameCacheEntries); 1.1153 + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); 1.1154 + 1.1155 + cache->cacheMemSize = ptr; 1.1156 + 1.1157 + if (ssl2_timeout) { 1.1158 + if (ssl2_timeout > MAX_SSL2_TIMEOUT) { 1.1159 + ssl2_timeout = MAX_SSL2_TIMEOUT; 1.1160 + } 1.1161 + if (ssl2_timeout < MIN_SSL2_TIMEOUT) { 1.1162 + ssl2_timeout = MIN_SSL2_TIMEOUT; 1.1163 + } 1.1164 + cache->ssl2Timeout = ssl2_timeout; 1.1165 + } else { 1.1166 + cache->ssl2Timeout = DEF_SSL2_TIMEOUT; 1.1167 + } 1.1168 + 1.1169 + if (ssl3_timeout) { 1.1170 + if (ssl3_timeout > MAX_SSL3_TIMEOUT) { 1.1171 + ssl3_timeout = MAX_SSL3_TIMEOUT; 1.1172 + } 1.1173 + if (ssl3_timeout < MIN_SSL3_TIMEOUT) { 1.1174 + ssl3_timeout = MIN_SSL3_TIMEOUT; 1.1175 + } 1.1176 + cache->ssl3Timeout = ssl3_timeout; 1.1177 + } else { 1.1178 + cache->ssl3Timeout = DEF_SSL3_TIMEOUT; 1.1179 + } 1.1180 + 1.1181 + if (shared) { 1.1182 + /* Create file names */ 1.1183 +#if defined(XP_UNIX) || defined(XP_BEOS) 1.1184 + /* there's some confusion here about whether PR_OpenAnonFileMap wants 1.1185 + ** a directory name or a file name for its first argument. 1.1186 + cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid); 1.1187 + */ 1.1188 + cfn = PR_smprintf("%s", directory); 1.1189 +#elif defined(XP_WIN32) 1.1190 + cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, 1.1191 + GetCurrentThreadId()); 1.1192 +#elif defined(XP_OS2) 1.1193 + cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, 1.1194 + gettid()); 1.1195 +#else 1.1196 +#error "Don't know how to create file name for this platform!" 1.1197 +#endif 1.1198 + if (!cfn) { 1.1199 + goto loser; 1.1200 + } 1.1201 + 1.1202 + /* Create cache */ 1.1203 + cacheMemMap = PR_OpenAnonFileMap(cfn, cache->cacheMemSize, 1.1204 + PR_PROT_READWRITE); 1.1205 + 1.1206 + PR_smprintf_free(cfn); 1.1207 + if(!cacheMemMap) { 1.1208 + goto loser; 1.1209 + } 1.1210 + 1.1211 + cacheMem = PR_MemMap(cacheMemMap, 0, cache->cacheMemSize); 1.1212 + } else { 1.1213 + cacheMem = PORT_Alloc(cache->cacheMemSize); 1.1214 + } 1.1215 + 1.1216 + if (! cacheMem) { 1.1217 + goto loser; 1.1218 + } 1.1219 + 1.1220 + /* Initialize shared memory. This may not be necessary on all platforms */ 1.1221 + memset(cacheMem, 0, cache->cacheMemSize); 1.1222 + 1.1223 + /* Copy cache descriptor header into shared memory */ 1.1224 + memcpy(cacheMem, cache, sizeof *cache); 1.1225 + 1.1226 + /* save private copies of these values */ 1.1227 + cache->cacheMemMap = cacheMemMap; 1.1228 + cache->cacheMem = cacheMem; 1.1229 + cache->sharedCache = (cacheDesc *)cacheMem; 1.1230 + 1.1231 + /* Fix pointers in our private copy of cache descriptor to point to 1.1232 + ** spaces in shared memory 1.1233 + */ 1.1234 + ptr = (ptrdiff_t)cache->cacheMem; 1.1235 + *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr; 1.1236 + *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr; 1.1237 + *(ptrdiff_t *)(&cache->certCacheLock) += ptr; 1.1238 + *(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr; 1.1239 + *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr; 1.1240 + *(ptrdiff_t *)(&cache->sidCacheData ) += ptr; 1.1241 + *(ptrdiff_t *)(&cache->certCacheData) += ptr; 1.1242 + *(ptrdiff_t *)(&cache->keyCacheData ) += ptr; 1.1243 + *(ptrdiff_t *)(&cache->ticketKeyNameSuffix) += ptr; 1.1244 + *(ptrdiff_t *)(&cache->ticketEncKey ) += ptr; 1.1245 + *(ptrdiff_t *)(&cache->ticketMacKey ) += ptr; 1.1246 + *(ptrdiff_t *)(&cache->ticketKeysValid) += ptr; 1.1247 + *(ptrdiff_t *)(&cache->srvNameCacheData) += ptr; 1.1248 + 1.1249 + /* initialize the locks */ 1.1250 + init_time = ssl_Time(); 1.1251 + pLock = cache->sidCacheLocks; 1.1252 + for (locks_to_initialize = cache->numSIDCacheLocks + 3; 1.1253 + locks_initialized < locks_to_initialize; 1.1254 + ++locks_initialized, ++pLock ) { 1.1255 + 1.1256 + SECStatus err = sslMutex_Init(&pLock->mutex, shared); 1.1257 + if (err) { 1.1258 + cache->numSIDCacheLocksInitialized = locks_initialized; 1.1259 + goto loser; 1.1260 + } 1.1261 + pLock->timeStamp = init_time; 1.1262 + pLock->pid = 0; 1.1263 + } 1.1264 + cache->numSIDCacheLocksInitialized = locks_initialized; 1.1265 + 1.1266 + return SECSuccess; 1.1267 + 1.1268 +loser: 1.1269 + CloseCache(cache); 1.1270 + return SECFailure; 1.1271 +} 1.1272 + 1.1273 +PRUint32 1.1274 +SSL_GetMaxServerCacheLocks(void) 1.1275 +{ 1.1276 + return ssl_max_sid_cache_locks + 2; 1.1277 + /* The extra two are the cert cache lock and the key cache lock. */ 1.1278 +} 1.1279 + 1.1280 +SECStatus 1.1281 +SSL_SetMaxServerCacheLocks(PRUint32 maxLocks) 1.1282 +{ 1.1283 + /* Minimum is 1 sid cache lock, 1 cert cache lock and 1 key cache lock. 1.1284 + ** We'd like to test for a maximum value, but not all platforms' header 1.1285 + ** files provide a symbol or function or other means of determining 1.1286 + ** the maximum, other than trial and error. 1.1287 + */ 1.1288 + if (maxLocks < 3) { 1.1289 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.1290 + return SECFailure; 1.1291 + } 1.1292 + ssl_max_sid_cache_locks = maxLocks - 2; 1.1293 + /* The extra two are the cert cache lock and the key cache lock. */ 1.1294 + return SECSuccess; 1.1295 +} 1.1296 + 1.1297 +static SECStatus 1.1298 +ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache, 1.1299 + PRUint32 ssl2_timeout, 1.1300 + PRUint32 ssl3_timeout, 1.1301 + const char * directory, 1.1302 + PRBool shared, 1.1303 + int maxCacheEntries, 1.1304 + int maxCertCacheEntries, 1.1305 + int maxSrvNameCacheEntries) 1.1306 +{ 1.1307 + SECStatus rv; 1.1308 + 1.1309 + PORT_Assert(sizeof(sidCacheEntry) == 192); 1.1310 + PORT_Assert(sizeof(certCacheEntry) == 4096); 1.1311 + PORT_Assert(sizeof(srvNameCacheEntry) == 1072); 1.1312 + 1.1313 + rv = ssl_Init(); 1.1314 + if (rv != SECSuccess) { 1.1315 + return rv; 1.1316 + } 1.1317 + 1.1318 + myPid = SSL_GETPID(); 1.1319 + if (!directory) { 1.1320 + directory = DEFAULT_CACHE_DIRECTORY; 1.1321 + } 1.1322 + rv = InitCache(cache, maxCacheEntries, maxCertCacheEntries, 1.1323 + maxSrvNameCacheEntries, ssl2_timeout, ssl3_timeout, 1.1324 + directory, shared); 1.1325 + if (rv) { 1.1326 + SET_ERROR_CODE 1.1327 + return SECFailure; 1.1328 + } 1.1329 + 1.1330 + ssl_sid_lookup = ServerSessionIDLookup; 1.1331 + ssl_sid_cache = ServerSessionIDCache; 1.1332 + ssl_sid_uncache = ServerSessionIDUncache; 1.1333 + return SECSuccess; 1.1334 +} 1.1335 + 1.1336 +SECStatus 1.1337 +SSL_ConfigServerSessionIDCacheInstance( cacheDesc *cache, 1.1338 + int maxCacheEntries, 1.1339 + PRUint32 ssl2_timeout, 1.1340 + PRUint32 ssl3_timeout, 1.1341 + const char * directory, PRBool shared) 1.1342 +{ 1.1343 + return ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache, 1.1344 + ssl2_timeout, 1.1345 + ssl3_timeout, 1.1346 + directory, 1.1347 + shared, 1.1348 + maxCacheEntries, 1.1349 + -1, -1); 1.1350 +} 1.1351 + 1.1352 +SECStatus 1.1353 +SSL_ConfigServerSessionIDCache( int maxCacheEntries, 1.1354 + PRUint32 ssl2_timeout, 1.1355 + PRUint32 ssl3_timeout, 1.1356 + const char * directory) 1.1357 +{ 1.1358 + ssl_InitSessionCacheLocks(PR_FALSE); 1.1359 + return SSL_ConfigServerSessionIDCacheInstance(&globalCache, 1.1360 + maxCacheEntries, ssl2_timeout, ssl3_timeout, directory, PR_FALSE); 1.1361 +} 1.1362 + 1.1363 +SECStatus 1.1364 +SSL_ShutdownServerSessionIDCacheInstance(cacheDesc *cache) 1.1365 +{ 1.1366 + CloseCache(cache); 1.1367 + return SECSuccess; 1.1368 +} 1.1369 + 1.1370 +SECStatus 1.1371 +SSL_ShutdownServerSessionIDCache(void) 1.1372 +{ 1.1373 +#if defined(XP_UNIX) || defined(XP_BEOS) 1.1374 + /* Stop the thread that polls cache for expired locks on Unix */ 1.1375 + StopLockPoller(&globalCache); 1.1376 +#endif 1.1377 + SSL3_ShutdownServerCache(); 1.1378 + return SSL_ShutdownServerSessionIDCacheInstance(&globalCache); 1.1379 +} 1.1380 + 1.1381 +/* Use this function, instead of SSL_ConfigServerSessionIDCache, 1.1382 + * if the cache will be shared by multiple processes. 1.1383 + */ 1.1384 +static SECStatus 1.1385 +ssl_ConfigMPServerSIDCacheWithOpt( PRUint32 ssl2_timeout, 1.1386 + PRUint32 ssl3_timeout, 1.1387 + const char * directory, 1.1388 + int maxCacheEntries, 1.1389 + int maxCertCacheEntries, 1.1390 + int maxSrvNameCacheEntries) 1.1391 +{ 1.1392 + char * envValue; 1.1393 + char * inhValue; 1.1394 + cacheDesc * cache = &globalCache; 1.1395 + PRUint32 fmStrLen; 1.1396 + SECStatus result; 1.1397 + PRStatus prStatus; 1.1398 + SECStatus putEnvFailed; 1.1399 + inheritance inherit; 1.1400 + char fmString[PR_FILEMAP_STRING_BUFSIZE]; 1.1401 + 1.1402 + isMultiProcess = PR_TRUE; 1.1403 + result = ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache, 1.1404 + ssl2_timeout, ssl3_timeout, directory, PR_TRUE, 1.1405 + maxCacheEntries, maxCacheEntries, maxSrvNameCacheEntries); 1.1406 + if (result != SECSuccess) 1.1407 + return result; 1.1408 + 1.1409 + prStatus = PR_ExportFileMapAsString(cache->cacheMemMap, 1.1410 + sizeof fmString, fmString); 1.1411 + if ((prStatus != PR_SUCCESS) || !(fmStrLen = strlen(fmString))) { 1.1412 + SET_ERROR_CODE 1.1413 + return SECFailure; 1.1414 + } 1.1415 + 1.1416 + inherit.cacheMemSize = cache->cacheMemSize; 1.1417 + inherit.fmStrLen = fmStrLen; 1.1418 + 1.1419 + inhValue = BTOA_DataToAscii((unsigned char *)&inherit, sizeof inherit); 1.1420 + if (!inhValue || !strlen(inhValue)) { 1.1421 + SET_ERROR_CODE 1.1422 + return SECFailure; 1.1423 + } 1.1424 + envValue = PR_smprintf("%s,%s", inhValue, fmString); 1.1425 + if (!envValue || !strlen(envValue)) { 1.1426 + SET_ERROR_CODE 1.1427 + return SECFailure; 1.1428 + } 1.1429 + PORT_Free(inhValue); 1.1430 + 1.1431 + putEnvFailed = (SECStatus)NSS_PutEnv(envVarName, envValue); 1.1432 + PR_smprintf_free(envValue); 1.1433 + if (putEnvFailed) { 1.1434 + SET_ERROR_CODE 1.1435 + result = SECFailure; 1.1436 + } 1.1437 + 1.1438 +#if defined(XP_UNIX) || defined(XP_BEOS) 1.1439 + /* Launch thread to poll cache for expired locks on Unix */ 1.1440 + LaunchLockPoller(cache); 1.1441 +#endif 1.1442 + return result; 1.1443 +} 1.1444 + 1.1445 +/* Use this function, instead of SSL_ConfigServerSessionIDCache, 1.1446 + * if the cache will be shared by multiple processes. 1.1447 + */ 1.1448 +SECStatus 1.1449 +SSL_ConfigMPServerSIDCache( int maxCacheEntries, 1.1450 + PRUint32 ssl2_timeout, 1.1451 + PRUint32 ssl3_timeout, 1.1452 + const char * directory) 1.1453 +{ 1.1454 + return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout, 1.1455 + ssl3_timeout, 1.1456 + directory, 1.1457 + maxCacheEntries, 1.1458 + -1, -1); 1.1459 +} 1.1460 + 1.1461 +SECStatus 1.1462 +SSL_ConfigServerSessionIDCacheWithOpt( 1.1463 + PRUint32 ssl2_timeout, 1.1464 + PRUint32 ssl3_timeout, 1.1465 + const char * directory, 1.1466 + int maxCacheEntries, 1.1467 + int maxCertCacheEntries, 1.1468 + int maxSrvNameCacheEntries, 1.1469 + PRBool enableMPCache) 1.1470 +{ 1.1471 + if (!enableMPCache) { 1.1472 + ssl_InitSessionCacheLocks(PR_FALSE); 1.1473 + return ssl_ConfigServerSessionIDCacheInstanceWithOpt(&globalCache, 1.1474 + ssl2_timeout, ssl3_timeout, directory, PR_FALSE, 1.1475 + maxCacheEntries, maxCertCacheEntries, maxSrvNameCacheEntries); 1.1476 + } else { 1.1477 + return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout, ssl3_timeout, 1.1478 + directory, maxCacheEntries, maxCertCacheEntries, 1.1479 + maxSrvNameCacheEntries); 1.1480 + } 1.1481 +} 1.1482 + 1.1483 +SECStatus 1.1484 +SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString) 1.1485 +{ 1.1486 + unsigned char * decoString = NULL; 1.1487 + char * fmString = NULL; 1.1488 + char * myEnvString = NULL; 1.1489 + unsigned int decoLen; 1.1490 + ptrdiff_t ptr; 1.1491 + inheritance inherit; 1.1492 + cacheDesc my; 1.1493 +#ifdef WINNT 1.1494 + sidCacheLock* newLocks; 1.1495 + int locks_initialized = 0; 1.1496 + int locks_to_initialize = 0; 1.1497 +#endif 1.1498 + SECStatus status = ssl_Init(); 1.1499 + 1.1500 + if (status != SECSuccess) { 1.1501 + return status; 1.1502 + } 1.1503 + 1.1504 + myPid = SSL_GETPID(); 1.1505 + 1.1506 + /* If this child was created by fork(), and not by exec() on unix, 1.1507 + ** then isMultiProcess will already be set. 1.1508 + ** If not, we'll set it below. 1.1509 + */ 1.1510 + if (isMultiProcess) { 1.1511 + if (cache && cache->sharedCache) { 1.1512 + cache->sharedCache->everInherited = PR_TRUE; 1.1513 + } 1.1514 + return SECSuccess; /* already done. */ 1.1515 + } 1.1516 + 1.1517 + ssl_InitSessionCacheLocks(PR_FALSE); 1.1518 + 1.1519 + ssl_sid_lookup = ServerSessionIDLookup; 1.1520 + ssl_sid_cache = ServerSessionIDCache; 1.1521 + ssl_sid_uncache = ServerSessionIDUncache; 1.1522 + 1.1523 + if (!envString) { 1.1524 + envString = getenv(envVarName); 1.1525 + if (!envString) { 1.1526 + SET_ERROR_CODE 1.1527 + return SECFailure; 1.1528 + } 1.1529 + } 1.1530 + myEnvString = PORT_Strdup(envString); 1.1531 + if (!myEnvString) 1.1532 + return SECFailure; 1.1533 + fmString = strchr(myEnvString, ','); 1.1534 + if (!fmString) 1.1535 + goto loser; 1.1536 + *fmString++ = 0; 1.1537 + 1.1538 + decoString = ATOB_AsciiToData(myEnvString, &decoLen); 1.1539 + if (!decoString) { 1.1540 + SET_ERROR_CODE 1.1541 + goto loser; 1.1542 + } 1.1543 + if (decoLen != sizeof inherit) { 1.1544 + SET_ERROR_CODE 1.1545 + goto loser; 1.1546 + } 1.1547 + 1.1548 + PORT_Memcpy(&inherit, decoString, sizeof inherit); 1.1549 + 1.1550 + if (strlen(fmString) != inherit.fmStrLen ) { 1.1551 + goto loser; 1.1552 + } 1.1553 + 1.1554 + memset(cache, 0, sizeof *cache); 1.1555 + cache->cacheMemSize = inherit.cacheMemSize; 1.1556 + 1.1557 + /* Create cache */ 1.1558 + cache->cacheMemMap = PR_ImportFileMapFromString(fmString); 1.1559 + if(! cache->cacheMemMap) { 1.1560 + goto loser; 1.1561 + } 1.1562 + cache->cacheMem = PR_MemMap(cache->cacheMemMap, 0, cache->cacheMemSize); 1.1563 + if (! cache->cacheMem) { 1.1564 + goto loser; 1.1565 + } 1.1566 + cache->sharedCache = (cacheDesc *)cache->cacheMem; 1.1567 + 1.1568 + if (cache->sharedCache->cacheMemSize != cache->cacheMemSize) { 1.1569 + SET_ERROR_CODE 1.1570 + goto loser; 1.1571 + } 1.1572 + 1.1573 + /* We're now going to overwrite the local cache instance with the 1.1574 + ** shared copy of the cache struct, then update several values in 1.1575 + ** the local cache using the values for cache->cacheMemMap and 1.1576 + ** cache->cacheMem computed just above. So, we copy cache into 1.1577 + ** the automatic variable "my", to preserve the variables while 1.1578 + ** cache is overwritten. 1.1579 + */ 1.1580 + my = *cache; /* save values computed above. */ 1.1581 + memcpy(cache, cache->sharedCache, sizeof *cache); /* overwrite */ 1.1582 + 1.1583 + /* Fix pointers in our private copy of cache descriptor to point to 1.1584 + ** spaces in shared memory, whose address is now in "my". 1.1585 + */ 1.1586 + ptr = (ptrdiff_t)my.cacheMem; 1.1587 + *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr; 1.1588 + *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr; 1.1589 + *(ptrdiff_t *)(&cache->certCacheLock) += ptr; 1.1590 + *(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr; 1.1591 + *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr; 1.1592 + *(ptrdiff_t *)(&cache->sidCacheData ) += ptr; 1.1593 + *(ptrdiff_t *)(&cache->certCacheData) += ptr; 1.1594 + *(ptrdiff_t *)(&cache->keyCacheData ) += ptr; 1.1595 + *(ptrdiff_t *)(&cache->ticketKeyNameSuffix) += ptr; 1.1596 + *(ptrdiff_t *)(&cache->ticketEncKey ) += ptr; 1.1597 + *(ptrdiff_t *)(&cache->ticketMacKey ) += ptr; 1.1598 + *(ptrdiff_t *)(&cache->ticketKeysValid) += ptr; 1.1599 + *(ptrdiff_t *)(&cache->srvNameCacheData) += ptr; 1.1600 + 1.1601 + cache->cacheMemMap = my.cacheMemMap; 1.1602 + cache->cacheMem = my.cacheMem; 1.1603 + cache->sharedCache = (cacheDesc *)cache->cacheMem; 1.1604 + 1.1605 +#ifdef WINNT 1.1606 + /* On Windows NT we need to "fix" the sidCacheLocks here to support fibers 1.1607 + ** When NT fibers are used in a multi-process server, a second level of 1.1608 + ** locking is needed to prevent a deadlock, in case a fiber acquires the 1.1609 + ** cross-process mutex, yields, and another fiber is later scheduled on 1.1610 + ** the same native thread and tries to acquire the cross-process mutex. 1.1611 + ** We do this by using a PRLock in the sslMutex. However, it is stored in 1.1612 + ** shared memory as part of sidCacheLocks, and we don't want to overwrite 1.1613 + ** the PRLock of the parent process. So we need to make new, private 1.1614 + ** copies of sidCacheLocks before modifying the sslMutex with our own 1.1615 + ** PRLock 1.1616 + */ 1.1617 + 1.1618 + /* note from jpierre : this should be free'd in child processes when 1.1619 + ** a function is added to delete the SSL session cache in the future. 1.1620 + */ 1.1621 + locks_to_initialize = cache->numSIDCacheLocks + 3; 1.1622 + newLocks = PORT_NewArray(sidCacheLock, locks_to_initialize); 1.1623 + if (!newLocks) 1.1624 + goto loser; 1.1625 + /* copy the old locks */ 1.1626 + memcpy(newLocks, cache->sidCacheLocks, 1.1627 + locks_to_initialize * sizeof(sidCacheLock)); 1.1628 + cache->sidCacheLocks = newLocks; 1.1629 + /* fix the locks */ 1.1630 + for (; locks_initialized < locks_to_initialize; ++locks_initialized) { 1.1631 + /* now, make a local PRLock in this sslMutex for this child process */ 1.1632 + SECStatus err; 1.1633 + err = sslMutex_2LevelInit(&newLocks[locks_initialized].mutex); 1.1634 + if (err != SECSuccess) { 1.1635 + cache->numSIDCacheLocksInitialized = locks_initialized; 1.1636 + goto loser; 1.1637 + } 1.1638 + } 1.1639 + cache->numSIDCacheLocksInitialized = locks_initialized; 1.1640 + 1.1641 + /* also fix the key and cert cache which use the last 2 lock entries */ 1.1642 + cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks; 1.1643 + cache->certCacheLock = cache->keyCacheLock + 1; 1.1644 + cache->srvNameCacheLock = cache->certCacheLock + 1; 1.1645 +#endif 1.1646 + 1.1647 + PORT_Free(myEnvString); 1.1648 + PORT_Free(decoString); 1.1649 + 1.1650 + /* mark that we have inherited this. */ 1.1651 + cache->sharedCache->everInherited = PR_TRUE; 1.1652 + isMultiProcess = PR_TRUE; 1.1653 + 1.1654 + return SECSuccess; 1.1655 + 1.1656 +loser: 1.1657 + PORT_Free(myEnvString); 1.1658 + if (decoString) 1.1659 + PORT_Free(decoString); 1.1660 + CloseCache(cache); 1.1661 + return SECFailure; 1.1662 +} 1.1663 + 1.1664 +SECStatus 1.1665 +SSL_InheritMPServerSIDCache(const char * envString) 1.1666 +{ 1.1667 + return SSL_InheritMPServerSIDCacheInstance(&globalCache, envString); 1.1668 +} 1.1669 + 1.1670 +#if defined(XP_UNIX) || defined(XP_BEOS) 1.1671 + 1.1672 +#define SID_LOCK_EXPIRATION_TIMEOUT 30 /* seconds */ 1.1673 + 1.1674 +static void 1.1675 +LockPoller(void * arg) 1.1676 +{ 1.1677 + cacheDesc * cache = (cacheDesc *)arg; 1.1678 + cacheDesc * sharedCache = cache->sharedCache; 1.1679 + sidCacheLock * pLock; 1.1680 + PRIntervalTime timeout; 1.1681 + PRUint32 now; 1.1682 + PRUint32 then; 1.1683 + int locks_polled = 0; 1.1684 + int locks_to_poll = cache->numSIDCacheLocks + 2; 1.1685 + PRUint32 expiration = cache->mutexTimeout; 1.1686 + 1.1687 + timeout = PR_SecondsToInterval(expiration); 1.1688 + while(!sharedCache->stopPolling) { 1.1689 + PR_Sleep(timeout); 1.1690 + if (sharedCache->stopPolling) 1.1691 + break; 1.1692 + 1.1693 + now = ssl_Time(); 1.1694 + then = now - expiration; 1.1695 + for (pLock = cache->sidCacheLocks, locks_polled = 0; 1.1696 + locks_to_poll > locks_polled && !sharedCache->stopPolling; 1.1697 + ++locks_polled, ++pLock ) { 1.1698 + pid_t pid; 1.1699 + 1.1700 + if (pLock->timeStamp < then && 1.1701 + pLock->timeStamp != 0 && 1.1702 + (pid = pLock->pid) != 0) { 1.1703 + 1.1704 + /* maybe we should try the lock? */ 1.1705 + int result = kill(pid, 0); 1.1706 + if (result < 0 && errno == ESRCH) { 1.1707 + SECStatus rv; 1.1708 + /* No process exists by that pid any more. 1.1709 + ** Treat this mutex as abandoned. 1.1710 + */ 1.1711 + pLock->timeStamp = now; 1.1712 + pLock->pid = 0; 1.1713 + rv = sslMutex_Unlock(&pLock->mutex); 1.1714 + if (rv != SECSuccess) { 1.1715 + /* Now what? */ 1.1716 + } 1.1717 + } 1.1718 + } 1.1719 + } /* end of loop over locks */ 1.1720 + } /* end of entire polling loop */ 1.1721 +} 1.1722 + 1.1723 +/* Launch thread to poll cache for expired locks */ 1.1724 +static SECStatus 1.1725 +LaunchLockPoller(cacheDesc *cache) 1.1726 +{ 1.1727 + const char * timeoutString; 1.1728 + PRThread * pollerThread; 1.1729 + 1.1730 + cache->mutexTimeout = SID_LOCK_EXPIRATION_TIMEOUT; 1.1731 + timeoutString = getenv("NSS_SSL_SERVER_CACHE_MUTEX_TIMEOUT"); 1.1732 + if (timeoutString) { 1.1733 + long newTime = strtol(timeoutString, 0, 0); 1.1734 + if (newTime == 0) 1.1735 + return SECSuccess; /* application doesn't want poller thread */ 1.1736 + if (newTime > 0) 1.1737 + cache->mutexTimeout = (PRUint32)newTime; 1.1738 + /* if error (newTime < 0) ignore it and use default */ 1.1739 + } 1.1740 + 1.1741 + pollerThread = 1.1742 + PR_CreateThread(PR_USER_THREAD, LockPoller, cache, PR_PRIORITY_NORMAL, 1.1743 + PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); 1.1744 + if (!pollerThread) { 1.1745 + return SECFailure; 1.1746 + } 1.1747 + cache->poller = pollerThread; 1.1748 + return SECSuccess; 1.1749 +} 1.1750 + 1.1751 +/* Stop the thread that polls cache for expired locks */ 1.1752 +static SECStatus 1.1753 +StopLockPoller(cacheDesc *cache) 1.1754 +{ 1.1755 + if (!cache->poller) { 1.1756 + return SECSuccess; 1.1757 + } 1.1758 + cache->sharedCache->stopPolling = PR_TRUE; 1.1759 + if (PR_Interrupt(cache->poller) != PR_SUCCESS) { 1.1760 + return SECFailure; 1.1761 + } 1.1762 + if (PR_JoinThread(cache->poller) != PR_SUCCESS) { 1.1763 + return SECFailure; 1.1764 + } 1.1765 + cache->poller = NULL; 1.1766 + return SECSuccess; 1.1767 +} 1.1768 +#endif 1.1769 + 1.1770 +/************************************************************************ 1.1771 + * Code dealing with shared wrapped symmetric wrapping keys below * 1.1772 + ************************************************************************/ 1.1773 + 1.1774 +/* If now is zero, it implies that the lock is not held, and must be 1.1775 +** aquired here. 1.1776 +*/ 1.1777 +static PRBool 1.1778 +getSvrWrappingKey(PRInt32 symWrapMechIndex, 1.1779 + SSL3KEAType exchKeyType, 1.1780 + SSLWrappedSymWrappingKey *wswk, 1.1781 + cacheDesc * cache, 1.1782 + PRUint32 lockTime) 1.1783 +{ 1.1784 + PRUint32 ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex; 1.1785 + SSLWrappedSymWrappingKey * pwswk = cache->keyCacheData + ndx; 1.1786 + PRUint32 now = 0; 1.1787 + PRBool rv = PR_FALSE; 1.1788 + 1.1789 + if (!cache->cacheMem) { /* cache is uninitialized */ 1.1790 + PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED); 1.1791 + return rv; 1.1792 + } 1.1793 + if (!lockTime) { 1.1794 + lockTime = now = LockSidCacheLock(cache->keyCacheLock, now); 1.1795 + if (!lockTime) { 1.1796 + return rv; 1.1797 + } 1.1798 + } 1.1799 + if (pwswk->exchKeyType == exchKeyType && 1.1800 + pwswk->symWrapMechIndex == symWrapMechIndex && 1.1801 + pwswk->wrappedSymKeyLen != 0) { 1.1802 + *wswk = *pwswk; 1.1803 + rv = PR_TRUE; 1.1804 + } 1.1805 + if (now) { 1.1806 + UnlockSidCacheLock(cache->keyCacheLock); 1.1807 + } 1.1808 + return rv; 1.1809 +} 1.1810 + 1.1811 +PRBool 1.1812 +ssl_GetWrappingKey( PRInt32 symWrapMechIndex, 1.1813 + SSL3KEAType exchKeyType, 1.1814 + SSLWrappedSymWrappingKey *wswk) 1.1815 +{ 1.1816 + PRBool rv; 1.1817 + 1.1818 + PORT_Assert( (unsigned)exchKeyType < kt_kea_size); 1.1819 + PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS); 1.1820 + if ((unsigned)exchKeyType < kt_kea_size && 1.1821 + (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) { 1.1822 + rv = getSvrWrappingKey(symWrapMechIndex, exchKeyType, wswk, 1.1823 + &globalCache, 0); 1.1824 + } else { 1.1825 + rv = PR_FALSE; 1.1826 + } 1.1827 + 1.1828 + return rv; 1.1829 +} 1.1830 + 1.1831 +/* Wrap and cache a session ticket key. */ 1.1832 +static PRBool 1.1833 +WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey, 1.1834 + const char *keyName, encKeyCacheEntry* cacheEntry) 1.1835 +{ 1.1836 + SECItem wrappedKey = {siBuffer, NULL, 0}; 1.1837 + 1.1838 + wrappedKey.len = SECKEY_PublicKeyStrength(svrPubKey); 1.1839 + PORT_Assert(wrappedKey.len <= sizeof(cacheEntry->bytes)); 1.1840 + if (wrappedKey.len > sizeof(cacheEntry->bytes)) 1.1841 + return PR_FALSE; 1.1842 + wrappedKey.data = cacheEntry->bytes; 1.1843 + 1.1844 + if (PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, symKey, &wrappedKey) 1.1845 + != SECSuccess) { 1.1846 + SSL_DBG(("%d: SSL[%s]: Unable to wrap session ticket %s.", 1.1847 + SSL_GETPID(), "unknown", keyName)); 1.1848 + return PR_FALSE; 1.1849 + } 1.1850 + cacheEntry->length = wrappedKey.len; 1.1851 + return PR_TRUE; 1.1852 +} 1.1853 + 1.1854 +static PRBool 1.1855 +GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey, 1.1856 + PK11SymKey **macKey) 1.1857 +{ 1.1858 + PK11SlotInfo *slot; 1.1859 + CK_MECHANISM_TYPE mechanismArray[2]; 1.1860 + PK11SymKey *aesKeyTmp = NULL; 1.1861 + PK11SymKey *macKeyTmp = NULL; 1.1862 + cacheDesc *cache = &globalCache; 1.1863 + PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN]; 1.1864 + PRUint8 *ticketKeyNameSuffix; 1.1865 + 1.1866 + if (!cache->cacheMem) { 1.1867 + /* cache is not initalized. Use stack buffer */ 1.1868 + ticketKeyNameSuffix = ticketKeyNameSuffixLocal; 1.1869 + } else { 1.1870 + ticketKeyNameSuffix = cache->ticketKeyNameSuffix; 1.1871 + } 1.1872 + 1.1873 + if (PK11_GenerateRandom(ticketKeyNameSuffix, 1.1874 + SESS_TICKET_KEY_VAR_NAME_LEN) != SECSuccess) { 1.1875 + SSL_DBG(("%d: SSL[%s]: Unable to generate random key name bytes.", 1.1876 + SSL_GETPID(), "unknown")); 1.1877 + goto loser; 1.1878 + } 1.1879 + 1.1880 + mechanismArray[0] = CKM_AES_CBC; 1.1881 + mechanismArray[1] = CKM_SHA256_HMAC; 1.1882 + 1.1883 + slot = PK11_GetBestSlotMultiple(mechanismArray, 2, pwArg); 1.1884 + if (slot) { 1.1885 + aesKeyTmp = PK11_KeyGen(slot, mechanismArray[0], NULL, 1.1886 + AES_256_KEY_LENGTH, pwArg); 1.1887 + macKeyTmp = PK11_KeyGen(slot, mechanismArray[1], NULL, 1.1888 + SHA256_LENGTH, pwArg); 1.1889 + PK11_FreeSlot(slot); 1.1890 + } 1.1891 + 1.1892 + if (aesKeyTmp == NULL || macKeyTmp == NULL) { 1.1893 + SSL_DBG(("%d: SSL[%s]: Unable to generate session ticket keys.", 1.1894 + SSL_GETPID(), "unknown")); 1.1895 + goto loser; 1.1896 + } 1.1897 + PORT_Memcpy(keyName, ticketKeyNameSuffix, SESS_TICKET_KEY_VAR_NAME_LEN); 1.1898 + *aesKey = aesKeyTmp; 1.1899 + *macKey = macKeyTmp; 1.1900 + return PR_TRUE; 1.1901 + 1.1902 +loser: 1.1903 + if (aesKeyTmp) 1.1904 + PK11_FreeSymKey(aesKeyTmp); 1.1905 + if (macKeyTmp) 1.1906 + PK11_FreeSymKey(macKeyTmp); 1.1907 + return PR_FALSE; 1.1908 +} 1.1909 + 1.1910 +static PRBool 1.1911 +GenerateAndWrapTicketKeys(SECKEYPublicKey *svrPubKey, void *pwArg, 1.1912 + unsigned char *keyName, PK11SymKey **aesKey, 1.1913 + PK11SymKey **macKey) 1.1914 +{ 1.1915 + PK11SymKey *aesKeyTmp = NULL; 1.1916 + PK11SymKey *macKeyTmp = NULL; 1.1917 + cacheDesc *cache = &globalCache; 1.1918 + 1.1919 + if (!GenerateTicketKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp)) { 1.1920 + goto loser; 1.1921 + } 1.1922 + 1.1923 + if (cache->cacheMem) { 1.1924 + /* Export the keys to the shared cache in wrapped form. */ 1.1925 + if (!WrapTicketKey(svrPubKey, aesKeyTmp, "enc key", cache->ticketEncKey)) 1.1926 + goto loser; 1.1927 + if (!WrapTicketKey(svrPubKey, macKeyTmp, "mac key", cache->ticketMacKey)) 1.1928 + goto loser; 1.1929 + } 1.1930 + *aesKey = aesKeyTmp; 1.1931 + *macKey = macKeyTmp; 1.1932 + return PR_TRUE; 1.1933 + 1.1934 +loser: 1.1935 + if (aesKeyTmp) 1.1936 + PK11_FreeSymKey(aesKeyTmp); 1.1937 + if (macKeyTmp) 1.1938 + PK11_FreeSymKey(macKeyTmp); 1.1939 + return PR_FALSE; 1.1940 +} 1.1941 + 1.1942 +static PRBool 1.1943 +UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName, 1.1944 + PK11SymKey **aesKey, PK11SymKey **macKey) 1.1945 +{ 1.1946 + SECItem wrappedKey = {siBuffer, NULL, 0}; 1.1947 + PK11SymKey *aesKeyTmp = NULL; 1.1948 + PK11SymKey *macKeyTmp = NULL; 1.1949 + cacheDesc *cache = &globalCache; 1.1950 + 1.1951 + wrappedKey.data = cache->ticketEncKey->bytes; 1.1952 + wrappedKey.len = cache->ticketEncKey->length; 1.1953 + PORT_Assert(wrappedKey.len <= sizeof(cache->ticketEncKey->bytes)); 1.1954 + aesKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey, 1.1955 + CKM_AES_CBC, CKA_DECRYPT, 0); 1.1956 + 1.1957 + wrappedKey.data = cache->ticketMacKey->bytes; 1.1958 + wrappedKey.len = cache->ticketMacKey->length; 1.1959 + PORT_Assert(wrappedKey.len <= sizeof(cache->ticketMacKey->bytes)); 1.1960 + macKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey, 1.1961 + CKM_SHA256_HMAC, CKA_SIGN, 0); 1.1962 + 1.1963 + if (aesKeyTmp == NULL || macKeyTmp == NULL) { 1.1964 + SSL_DBG(("%d: SSL[%s]: Unable to unwrap session ticket keys.", 1.1965 + SSL_GETPID(), "unknown")); 1.1966 + goto loser; 1.1967 + } 1.1968 + SSL_DBG(("%d: SSL[%s]: Successfully unwrapped session ticket keys.", 1.1969 + SSL_GETPID(), "unknown")); 1.1970 + 1.1971 + PORT_Memcpy(keyName, cache->ticketKeyNameSuffix, 1.1972 + SESS_TICKET_KEY_VAR_NAME_LEN); 1.1973 + *aesKey = aesKeyTmp; 1.1974 + *macKey = macKeyTmp; 1.1975 + return PR_TRUE; 1.1976 + 1.1977 +loser: 1.1978 + if (aesKeyTmp) 1.1979 + PK11_FreeSymKey(aesKeyTmp); 1.1980 + if (macKeyTmp) 1.1981 + PK11_FreeSymKey(macKeyTmp); 1.1982 + return PR_FALSE; 1.1983 +} 1.1984 + 1.1985 +PRBool 1.1986 +ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey, 1.1987 + SECKEYPublicKey *svrPubKey, void *pwArg, 1.1988 + unsigned char *keyName, PK11SymKey **aesKey, 1.1989 + PK11SymKey **macKey) 1.1990 +{ 1.1991 + PRUint32 now = 0; 1.1992 + PRBool rv = PR_FALSE; 1.1993 + PRBool keysGenerated = PR_FALSE; 1.1994 + cacheDesc *cache = &globalCache; 1.1995 + 1.1996 + if (!cache->cacheMem) { 1.1997 + /* cache is uninitialized. Generate keys and return them 1.1998 + * without caching. */ 1.1999 + return GenerateTicketKeys(pwArg, keyName, aesKey, macKey); 1.2000 + } 1.2001 + 1.2002 + now = LockSidCacheLock(cache->keyCacheLock, now); 1.2003 + if (!now) 1.2004 + return rv; 1.2005 + 1.2006 + if (!*(cache->ticketKeysValid)) { 1.2007 + /* Keys do not exist, create them. */ 1.2008 + if (!GenerateAndWrapTicketKeys(svrPubKey, pwArg, keyName, 1.2009 + aesKey, macKey)) 1.2010 + goto loser; 1.2011 + keysGenerated = PR_TRUE; 1.2012 + *(cache->ticketKeysValid) = 1; 1.2013 + } 1.2014 + 1.2015 + rv = PR_TRUE; 1.2016 + 1.2017 + loser: 1.2018 + UnlockSidCacheLock(cache->keyCacheLock); 1.2019 + if (rv && !keysGenerated) 1.2020 + rv = UnwrapCachedTicketKeys(svrPrivKey, keyName, aesKey, macKey); 1.2021 + return rv; 1.2022 +} 1.2023 + 1.2024 +PRBool 1.2025 +ssl_GetSessionTicketKeys(unsigned char *keyName, unsigned char *encKey, 1.2026 + unsigned char *macKey) 1.2027 +{ 1.2028 + PRBool rv = PR_FALSE; 1.2029 + PRUint32 now = 0; 1.2030 + cacheDesc *cache = &globalCache; 1.2031 + PRUint8 ticketMacKey[SHA256_LENGTH], ticketEncKey[AES_256_KEY_LENGTH]; 1.2032 + PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN]; 1.2033 + PRUint8 *ticketMacKeyPtr, *ticketEncKeyPtr, *ticketKeyNameSuffix; 1.2034 + PRBool cacheIsEnabled = PR_TRUE; 1.2035 + 1.2036 + if (!cache->cacheMem) { /* cache is uninitialized */ 1.2037 + cacheIsEnabled = PR_FALSE; 1.2038 + ticketKeyNameSuffix = ticketKeyNameSuffixLocal; 1.2039 + ticketEncKeyPtr = ticketEncKey; 1.2040 + ticketMacKeyPtr = ticketMacKey; 1.2041 + } else { 1.2042 + /* these values have constant memory locations in the cache. 1.2043 + * Ok to reference them without holding the lock. */ 1.2044 + ticketKeyNameSuffix = cache->ticketKeyNameSuffix; 1.2045 + ticketEncKeyPtr = cache->ticketEncKey->bytes; 1.2046 + ticketMacKeyPtr = cache->ticketMacKey->bytes; 1.2047 + } 1.2048 + 1.2049 + if (cacheIsEnabled) { 1.2050 + /* Grab lock if initialized. */ 1.2051 + now = LockSidCacheLock(cache->keyCacheLock, now); 1.2052 + if (!now) 1.2053 + return rv; 1.2054 + } 1.2055 + /* Going to regenerate keys on every call if cache was not 1.2056 + * initialized. */ 1.2057 + if (!cacheIsEnabled || !*(cache->ticketKeysValid)) { 1.2058 + if (PK11_GenerateRandom(ticketKeyNameSuffix, 1.2059 + SESS_TICKET_KEY_VAR_NAME_LEN) != SECSuccess) 1.2060 + goto loser; 1.2061 + if (PK11_GenerateRandom(ticketEncKeyPtr, 1.2062 + AES_256_KEY_LENGTH) != SECSuccess) 1.2063 + goto loser; 1.2064 + if (PK11_GenerateRandom(ticketMacKeyPtr, 1.2065 + SHA256_LENGTH) != SECSuccess) 1.2066 + goto loser; 1.2067 + if (cacheIsEnabled) { 1.2068 + *(cache->ticketKeysValid) = 1; 1.2069 + } 1.2070 + } 1.2071 + 1.2072 + rv = PR_TRUE; 1.2073 + 1.2074 + loser: 1.2075 + if (cacheIsEnabled) { 1.2076 + UnlockSidCacheLock(cache->keyCacheLock); 1.2077 + } 1.2078 + if (rv) { 1.2079 + PORT_Memcpy(keyName, ticketKeyNameSuffix, 1.2080 + SESS_TICKET_KEY_VAR_NAME_LEN); 1.2081 + PORT_Memcpy(encKey, ticketEncKeyPtr, AES_256_KEY_LENGTH); 1.2082 + PORT_Memcpy(macKey, ticketMacKeyPtr, SHA256_LENGTH); 1.2083 + } 1.2084 + return rv; 1.2085 +} 1.2086 + 1.2087 +/* The caller passes in the new value it wants 1.2088 + * to set. This code tests the wrapped sym key entry in the shared memory. 1.2089 + * If it is uninitialized, this function writes the caller's value into 1.2090 + * the disk entry, and returns false. 1.2091 + * Otherwise, it overwrites the caller's wswk with the value obtained from 1.2092 + * the disk, and returns PR_TRUE. 1.2093 + * This is all done while holding the locks/mutexes necessary to make 1.2094 + * the operation atomic. 1.2095 + */ 1.2096 +PRBool 1.2097 +ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk) 1.2098 +{ 1.2099 + cacheDesc * cache = &globalCache; 1.2100 + PRBool rv = PR_FALSE; 1.2101 + SSL3KEAType exchKeyType = wswk->exchKeyType; 1.2102 + /* type of keys used to wrap SymWrapKey*/ 1.2103 + PRInt32 symWrapMechIndex = wswk->symWrapMechIndex; 1.2104 + PRUint32 ndx; 1.2105 + PRUint32 now = 0; 1.2106 + SSLWrappedSymWrappingKey myWswk; 1.2107 + 1.2108 + if (!cache->cacheMem) { /* cache is uninitialized */ 1.2109 + PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED); 1.2110 + return 0; 1.2111 + } 1.2112 + 1.2113 + PORT_Assert( (unsigned)exchKeyType < kt_kea_size); 1.2114 + if ((unsigned)exchKeyType >= kt_kea_size) 1.2115 + return 0; 1.2116 + 1.2117 + PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS); 1.2118 + if ((unsigned)symWrapMechIndex >= SSL_NUM_WRAP_MECHS) 1.2119 + return 0; 1.2120 + 1.2121 + ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex; 1.2122 + PORT_Memset(&myWswk, 0, sizeof myWswk); /* eliminate UMRs. */ 1.2123 + 1.2124 + now = LockSidCacheLock(cache->keyCacheLock, now); 1.2125 + if (now) { 1.2126 + rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->exchKeyType, 1.2127 + &myWswk, cache, now); 1.2128 + if (rv) { 1.2129 + /* we found it on disk, copy it out to the caller. */ 1.2130 + PORT_Memcpy(wswk, &myWswk, sizeof *wswk); 1.2131 + } else { 1.2132 + /* Wasn't on disk, and we're still holding the lock, so write it. */ 1.2133 + cache->keyCacheData[ndx] = *wswk; 1.2134 + } 1.2135 + UnlockSidCacheLock(cache->keyCacheLock); 1.2136 + } 1.2137 + return rv; 1.2138 +} 1.2139 + 1.2140 +#else /* MAC version or other platform */ 1.2141 + 1.2142 +#include "seccomon.h" 1.2143 +#include "cert.h" 1.2144 +#include "ssl.h" 1.2145 +#include "sslimpl.h" 1.2146 + 1.2147 +SECStatus 1.2148 +SSL_ConfigServerSessionIDCache( int maxCacheEntries, 1.2149 + PRUint32 ssl2_timeout, 1.2150 + PRUint32 ssl3_timeout, 1.2151 + const char * directory) 1.2152 +{ 1.2153 + PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigServerSessionIDCache)"); 1.2154 + return SECFailure; 1.2155 +} 1.2156 + 1.2157 +SECStatus 1.2158 +SSL_ConfigMPServerSIDCache( int maxCacheEntries, 1.2159 + PRUint32 ssl2_timeout, 1.2160 + PRUint32 ssl3_timeout, 1.2161 + const char * directory) 1.2162 +{ 1.2163 + PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigMPServerSIDCache)"); 1.2164 + return SECFailure; 1.2165 +} 1.2166 + 1.2167 +SECStatus 1.2168 +SSL_InheritMPServerSIDCache(const char * envString) 1.2169 +{ 1.2170 + PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_InheritMPServerSIDCache)"); 1.2171 + return SECFailure; 1.2172 +} 1.2173 + 1.2174 +PRBool 1.2175 +ssl_GetWrappingKey( PRInt32 symWrapMechIndex, 1.2176 + SSL3KEAType exchKeyType, 1.2177 + SSLWrappedSymWrappingKey *wswk) 1.2178 +{ 1.2179 + PRBool rv = PR_FALSE; 1.2180 + PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)"); 1.2181 + return rv; 1.2182 +} 1.2183 + 1.2184 +/* This is a kind of test-and-set. The caller passes in the new value it wants 1.2185 + * to set. This code tests the wrapped sym key entry in the shared memory. 1.2186 + * If it is uninitialized, this function writes the caller's value into 1.2187 + * the disk entry, and returns false. 1.2188 + * Otherwise, it overwrites the caller's wswk with the value obtained from 1.2189 + * the disk, and returns PR_TRUE. 1.2190 + * This is all done while holding the locks/mutexes necessary to make 1.2191 + * the operation atomic. 1.2192 + */ 1.2193 +PRBool 1.2194 +ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk) 1.2195 +{ 1.2196 + PRBool rv = PR_FALSE; 1.2197 + PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrappingKey)"); 1.2198 + return rv; 1.2199 +} 1.2200 + 1.2201 +PRUint32 1.2202 +SSL_GetMaxServerCacheLocks(void) 1.2203 +{ 1.2204 + PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_GetMaxServerCacheLocks)"); 1.2205 + return -1; 1.2206 +} 1.2207 + 1.2208 +SECStatus 1.2209 +SSL_SetMaxServerCacheLocks(PRUint32 maxLocks) 1.2210 +{ 1.2211 + PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_SetMaxServerCacheLocks)"); 1.2212 + return SECFailure; 1.2213 +} 1.2214 + 1.2215 +#endif /* XP_UNIX || XP_WIN32 */