| OLD | NEW |
| (Empty) |
| 1 /* This file implements the SERVER Session ID cache. | |
| 2 * NOTE: The contents of this file are NOT used by the client. | |
| 3 * | |
| 4 * This Source Code Form is subject to the terms of the Mozilla Public | |
| 5 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
| 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| 7 | |
| 8 /* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server | |
| 9 * cache sids! | |
| 10 * | |
| 11 * About record locking among different server processes: | |
| 12 * | |
| 13 * All processes that are part of the same conceptual server (serving on | |
| 14 * the same address and port) MUST share a common SSL session cache. | |
| 15 * This code makes the content of the shared cache accessible to all | |
| 16 * processes on the same "server". This code works on Unix and Win32 only. | |
| 17 * | |
| 18 * We use NSPR anonymous shared memory and move data to & from shared memory. | |
| 19 * We must do explicit locking of the records for all reads and writes. | |
| 20 * The set of Cache entries are divided up into "sets" of 128 entries. | |
| 21 * Each set is protected by a lock. There may be one or more sets protected | |
| 22 * by each lock. That is, locks to sets are 1:N. | |
| 23 * There is one lock for the entire cert cache. | |
| 24 * There is one lock for the set of wrapped sym wrap keys. | |
| 25 * | |
| 26 * The anonymous shared memory is laid out as if it were declared like this: | |
| 27 * | |
| 28 * struct { | |
| 29 * cacheDescriptor desc; | |
| 30 * sidCacheLock sidCacheLocks[ numSIDCacheLocks]; | |
| 31 * sidCacheLock keyCacheLock; | |
| 32 * sidCacheLock certCacheLock; | |
| 33 * sidCacheSet sidCacheSets[ numSIDCacheSets ]; | |
| 34 * sidCacheEntry sidCacheData[ numSIDCacheEntries]; | |
| 35 * certCacheEntry certCacheData[numCertCacheEntries]; | |
| 36 * SSLWrappedSymWrappingKey keyCacheData[kt_kea_size][SSL_NUM_WRAP_MECHS]; | |
| 37 * PRUint8 keyNameSuffix[SESS_TICKET_KEY_VAR_NAME_LEN] | |
| 38 * encKeyCacheEntry ticketEncKey; // Wrapped in non-bypass mode | |
| 39 * encKeyCacheEntry ticketMacKey; // Wrapped in non-bypass mode | |
| 40 * PRBool ticketKeysValid; | |
| 41 * sidCacheLock srvNameCacheLock; | |
| 42 * srvNameCacheEntry srvNameData[ numSrvNameCacheEntries ]; | |
| 43 * } cacheMemCacheData; | |
| 44 */ | |
| 45 #include "seccomon.h" | |
| 46 | |
| 47 #if defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_OS2) || defined(XP_BEOS) | |
| 48 | |
| 49 #include "cert.h" | |
| 50 #include "ssl.h" | |
| 51 #include "sslimpl.h" | |
| 52 #include "sslproto.h" | |
| 53 #include "pk11func.h" | |
| 54 #include "base64.h" | |
| 55 #include "keyhi.h" | |
| 56 #ifdef NO_PKCS11_BYPASS | |
| 57 #include "blapit.h" | |
| 58 #include "sechash.h" | |
| 59 #else | |
| 60 #include "blapi.h" | |
| 61 #endif | |
| 62 | |
| 63 #include <stdio.h> | |
| 64 | |
| 65 #if defined(XP_UNIX) || defined(XP_BEOS) | |
| 66 | |
| 67 #include <syslog.h> | |
| 68 #include <fcntl.h> | |
| 69 #include <unistd.h> | |
| 70 #include <errno.h> | |
| 71 #include <signal.h> | |
| 72 #include "unix_err.h" | |
| 73 | |
| 74 #else | |
| 75 | |
| 76 #ifdef XP_WIN32 | |
| 77 #include <wtypes.h> | |
| 78 #include "win32err.h" | |
| 79 #endif | |
| 80 | |
| 81 #endif | |
| 82 #include <sys/types.h> | |
| 83 | |
| 84 #define SET_ERROR_CODE /* reminder */ | |
| 85 | |
| 86 #include "nspr.h" | |
| 87 #include "sslmutex.h" | |
| 88 | |
| 89 /* | |
| 90 ** Format of a cache entry in the shared memory. | |
| 91 */ | |
| 92 struct sidCacheEntryStr { | |
| 93 /* 16 */ PRIPv6Addr addr; /* client's IP address */ | |
| 94 /* 4 */ PRUint32 creationTime; | |
| 95 /* 4 */ PRUint32 lastAccessTime; | |
| 96 /* 4 */ PRUint32 expirationTime; | |
| 97 /* 2 */ PRUint16 version; | |
| 98 /* 1 */ PRUint8 valid; | |
| 99 /* 1 */ PRUint8 sessionIDLength; | |
| 100 /* 32 */ PRUint8 sessionID[SSL3_SESSIONID_BYTES]; | |
| 101 /* 2 */ PRUint16 authAlgorithm; | |
| 102 /* 2 */ PRUint16 authKeyBits; | |
| 103 /* 2 */ PRUint16 keaType; | |
| 104 /* 2 */ PRUint16 keaKeyBits; | |
| 105 /* 72 - common header total */ | |
| 106 | |
| 107 union { | |
| 108 struct { | |
| 109 /* 64 */ PRUint8 masterKey[SSL_MAX_MASTER_KEY_BYTES]; | |
| 110 /* 32 */ PRUint8 cipherArg[SSL_MAX_CYPHER_ARG_BYTES]; | |
| 111 | |
| 112 /* 1 */ PRUint8 cipherType; | |
| 113 /* 1 */ PRUint8 masterKeyLen; | |
| 114 /* 1 */ PRUint8 keyBits; | |
| 115 /* 1 */ PRUint8 secretKeyBits; | |
| 116 /* 1 */ PRUint8 cipherArgLen; | |
| 117 /*101 */} ssl2; | |
| 118 | |
| 119 struct { | |
| 120 /* 2 */ ssl3CipherSuite cipherSuite; | |
| 121 /* 2 */ PRUint16 compression; /* SSLCompressionMethod */ | |
| 122 | |
| 123 /* 54 */ ssl3SidKeys keys; /* keys, wrapped as needed. */ | |
| 124 | |
| 125 /* 4 */ PRUint32 masterWrapMech; | |
| 126 /* 4 */ SSL3KEAType exchKeyType; | |
| 127 /* 4 */ PRInt32 certIndex; | |
| 128 /* 4 */ PRInt32 srvNameIndex; | |
| 129 /* 32 */ PRUint8 srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */ | |
| 130 /*108 */} ssl3; | |
| 131 | |
| 132 /* force sizeof(sidCacheEntry) to be a multiple of cache line size */ | |
| 133 struct { | |
| 134 /*120 */ PRUint8 filler[120]; /* 72+120==192, a multiple of 16 */ | |
| 135 } forceSize; | |
| 136 } u; | |
| 137 }; | |
| 138 typedef struct sidCacheEntryStr sidCacheEntry; | |
| 139 | |
| 140 /* The length of this struct is supposed to be a power of 2, e.g. 4KB */ | |
| 141 struct certCacheEntryStr { | |
| 142 PRUint16 certLength; /* 2 */ | |
| 143 PRUint16 sessionIDLength; /* 2 */ | |
| 144 PRUint8 sessionID[SSL3_SESSIONID_BYTES]; /* 32 */ | |
| 145 PRUint8 cert[SSL_MAX_CACHED_CERT_LEN]; /* 4060 */ | |
| 146 }; /* total 4096 */ | |
| 147 typedef struct certCacheEntryStr certCacheEntry; | |
| 148 | |
| 149 struct sidCacheLockStr { | |
| 150 PRUint32 timeStamp; | |
| 151 sslMutex mutex; | |
| 152 sslPID pid; | |
| 153 }; | |
| 154 typedef struct sidCacheLockStr sidCacheLock; | |
| 155 | |
| 156 struct sidCacheSetStr { | |
| 157 PRIntn next; | |
| 158 }; | |
| 159 typedef struct sidCacheSetStr sidCacheSet; | |
| 160 | |
| 161 struct encKeyCacheEntryStr { | |
| 162 PRUint8 bytes[512]; | |
| 163 PRInt32 length; | |
| 164 }; | |
| 165 typedef struct encKeyCacheEntryStr encKeyCacheEntry; | |
| 166 | |
| 167 #define SSL_MAX_DNS_HOST_NAME 1024 | |
| 168 | |
| 169 struct srvNameCacheEntryStr { | |
| 170 PRUint16 type; /* 2 */ | |
| 171 PRUint16 nameLen; /* 2 */ | |
| 172 PRUint8 name[SSL_MAX_DNS_HOST_NAME + 12]; /* 1034 */ | |
| 173 PRUint8 nameHash[SHA256_LENGTH]; /* 32 */ | |
| 174 /* 1072 */ | |
| 175 }; | |
| 176 typedef struct srvNameCacheEntryStr srvNameCacheEntry; | |
| 177 | |
| 178 struct cacheDescStr { | |
| 179 | |
| 180 PRUint32 cacheMemSize; | |
| 181 | |
| 182 PRUint32 numSIDCacheLocks; | |
| 183 PRUint32 numSIDCacheSets; | |
| 184 PRUint32 numSIDCacheSetsPerLock; | |
| 185 | |
| 186 PRUint32 numSIDCacheEntries; | |
| 187 PRUint32 sidCacheSize; | |
| 188 | |
| 189 PRUint32 numCertCacheEntries; | |
| 190 PRUint32 certCacheSize; | |
| 191 | |
| 192 PRUint32 numKeyCacheEntries; | |
| 193 PRUint32 keyCacheSize; | |
| 194 | |
| 195 PRUint32 numSrvNameCacheEntries; | |
| 196 PRUint32 srvNameCacheSize; | |
| 197 | |
| 198 PRUint32 ssl2Timeout; | |
| 199 PRUint32 ssl3Timeout; | |
| 200 | |
| 201 PRUint32 numSIDCacheLocksInitialized; | |
| 202 | |
| 203 /* These values are volatile, and are accessed through sharedCache-> */ | |
| 204 PRUint32 nextCertCacheEntry; /* certCacheLock protects */ | |
| 205 PRBool stopPolling; | |
| 206 PRBool everInherited; | |
| 207 | |
| 208 /* The private copies of these values are pointers into shared mem */ | |
| 209 /* The copies of these values in shared memory are merely offsets */ | |
| 210 sidCacheLock *sidCacheLocks; | |
| 211 sidCacheLock *keyCacheLock; | |
| 212 sidCacheLock *certCacheLock; | |
| 213 sidCacheLock *srvNameCacheLock; | |
| 214 sidCacheSet *sidCacheSets; | |
| 215 sidCacheEntry *sidCacheData; | |
| 216 certCacheEntry *certCacheData; | |
| 217 SSLWrappedSymWrappingKey *keyCacheData; | |
| 218 PRUint8 *ticketKeyNameSuffix; | |
| 219 encKeyCacheEntry *ticketEncKey; | |
| 220 encKeyCacheEntry *ticketMacKey; | |
| 221 PRUint32 *ticketKeysValid; | |
| 222 srvNameCacheEntry *srvNameCacheData; | |
| 223 | |
| 224 /* Only the private copies of these pointers are valid */ | |
| 225 char *cacheMem; | |
| 226 struct cacheDescStr *sharedCache; /* shared copy of this struct */ | |
| 227 PRFileMap *cacheMemMap; | |
| 228 PRThread *poller; | |
| 229 PRUint32 mutexTimeout; | |
| 230 PRBool shared; | |
| 231 }; | |
| 232 typedef struct cacheDescStr cacheDesc; | |
| 233 | |
| 234 static cacheDesc globalCache; | |
| 235 | |
| 236 static const char envVarName[] = { SSL_ENV_VAR_NAME }; | |
| 237 | |
| 238 static PRBool isMultiProcess = PR_FALSE; | |
| 239 | |
| 240 #define DEF_SID_CACHE_ENTRIES 10000 | |
| 241 #define DEF_CERT_CACHE_ENTRIES 250 | |
| 242 #define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */ | |
| 243 #define DEF_KEY_CACHE_ENTRIES 250 | |
| 244 #define DEF_NAME_CACHE_ENTRIES 1000 | |
| 245 | |
| 246 #define SID_CACHE_ENTRIES_PER_SET 128 | |
| 247 #define SID_ALIGNMENT 16 | |
| 248 | |
| 249 #define DEF_SSL2_TIMEOUT 100 /* seconds */ | |
| 250 #define MAX_SSL2_TIMEOUT 100 /* seconds */ | |
| 251 #define MIN_SSL2_TIMEOUT 5 /* seconds */ | |
| 252 | |
| 253 #define DEF_SSL3_TIMEOUT 86400L /* 24 hours */ | |
| 254 #define MAX_SSL3_TIMEOUT 86400L /* 24 hours */ | |
| 255 #define MIN_SSL3_TIMEOUT 5 /* seconds */ | |
| 256 | |
| 257 #if defined(AIX) || defined(LINUX) || defined(NETBSD) || defined(OPENBSD) | |
| 258 #define MAX_SID_CACHE_LOCKS 8 /* two FDs per lock */ | |
| 259 #elif defined(OSF1) | |
| 260 #define MAX_SID_CACHE_LOCKS 16 /* one FD per lock */ | |
| 261 #else | |
| 262 #define MAX_SID_CACHE_LOCKS 256 | |
| 263 #endif | |
| 264 | |
| 265 #define SID_HOWMANY(val, size) (((val) + ((size)-1)) / (size)) | |
| 266 #define SID_ROUNDUP(val, size) ((size)*SID_HOWMANY((val), (size))) | |
| 267 | |
| 268 static sslPID myPid; | |
| 269 static PRUint32 ssl_max_sid_cache_locks = MAX_SID_CACHE_LOCKS; | |
| 270 | |
| 271 /* forward static function declarations */ | |
| 272 static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, | |
| 273 unsigned nl); | |
| 274 static SECStatus LaunchLockPoller(cacheDesc *cache); | |
| 275 static SECStatus StopLockPoller(cacheDesc *cache); | |
| 276 | |
| 277 struct inheritanceStr { | |
| 278 PRUint32 cacheMemSize; | |
| 279 PRUint32 fmStrLen; | |
| 280 }; | |
| 281 | |
| 282 typedef struct inheritanceStr inheritance; | |
| 283 | |
| 284 #if defined(_WIN32) || defined(XP_OS2) | |
| 285 | |
| 286 #define DEFAULT_CACHE_DIRECTORY "\\temp" | |
| 287 | |
| 288 #endif /* _win32 */ | |
| 289 | |
| 290 #if defined(XP_UNIX) || defined(XP_BEOS) | |
| 291 | |
| 292 #define DEFAULT_CACHE_DIRECTORY "/tmp" | |
| 293 | |
| 294 #endif /* XP_UNIX || XP_BEOS */ | |
| 295 | |
| 296 /************************************************************************/ | |
| 297 | |
| 298 static PRUint32 | |
| 299 LockSidCacheLock(sidCacheLock *lock, PRUint32 now) | |
| 300 { | |
| 301 SECStatus rv = sslMutex_Lock(&lock->mutex); | |
| 302 if (rv != SECSuccess) | |
| 303 return 0; | |
| 304 if (!now) | |
| 305 now = ssl_Time(); | |
| 306 lock->timeStamp = now; | |
| 307 lock->pid = myPid; | |
| 308 return now; | |
| 309 } | |
| 310 | |
| 311 static SECStatus | |
| 312 UnlockSidCacheLock(sidCacheLock *lock) | |
| 313 { | |
| 314 SECStatus rv; | |
| 315 | |
| 316 lock->pid = 0; | |
| 317 rv = sslMutex_Unlock(&lock->mutex); | |
| 318 return rv; | |
| 319 } | |
| 320 | |
| 321 /* returns the value of ssl_Time on success, zero on failure. */ | |
| 322 static PRUint32 | |
| 323 LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now) | |
| 324 { | |
| 325 PRUint32 lockNum = set % cache->numSIDCacheLocks; | |
| 326 sidCacheLock *lock = cache->sidCacheLocks + lockNum; | |
| 327 | |
| 328 return LockSidCacheLock(lock, now); | |
| 329 } | |
| 330 | |
| 331 static SECStatus | |
| 332 UnlockSet(cacheDesc *cache, PRUint32 set) | |
| 333 { | |
| 334 PRUint32 lockNum = set % cache->numSIDCacheLocks; | |
| 335 sidCacheLock *lock = cache->sidCacheLocks + lockNum; | |
| 336 | |
| 337 return UnlockSidCacheLock(lock); | |
| 338 } | |
| 339 | |
| 340 /************************************************************************/ | |
| 341 | |
| 342 /* Put a certificate in the cache. Update the cert index in the sce. | |
| 343 */ | |
| 344 static PRUint32 | |
| 345 CacheCert(cacheDesc *cache, CERTCertificate *cert, sidCacheEntry *sce) | |
| 346 { | |
| 347 PRUint32 now; | |
| 348 certCacheEntry cce; | |
| 349 | |
| 350 if ((cert->derCert.len > SSL_MAX_CACHED_CERT_LEN) || | |
| 351 (cert->derCert.len <= 0) || | |
| 352 (cert->derCert.data == NULL)) { | |
| 353 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 354 return 0; | |
| 355 } | |
| 356 | |
| 357 cce.sessionIDLength = sce->sessionIDLength; | |
| 358 PORT_Memcpy(cce.sessionID, sce->sessionID, cce.sessionIDLength); | |
| 359 | |
| 360 cce.certLength = cert->derCert.len; | |
| 361 PORT_Memcpy(cce.cert, cert->derCert.data, cce.certLength); | |
| 362 | |
| 363 /* get lock on cert cache */ | |
| 364 now = LockSidCacheLock(cache->certCacheLock, 0); | |
| 365 if (now) { | |
| 366 | |
| 367 /* Find where to place the next cert cache entry. */ | |
| 368 cacheDesc *sharedCache = cache->sharedCache; | |
| 369 PRUint32 ndx = sharedCache->nextCertCacheEntry; | |
| 370 | |
| 371 /* write the entry */ | |
| 372 cache->certCacheData[ndx] = cce; | |
| 373 | |
| 374 /* remember where we put it. */ | |
| 375 sce->u.ssl3.certIndex = ndx; | |
| 376 | |
| 377 /* update the "next" cache entry index */ | |
| 378 sharedCache->nextCertCacheEntry = | |
| 379 (ndx + 1) % cache->numCertCacheEntries; | |
| 380 | |
| 381 UnlockSidCacheLock(cache->certCacheLock); | |
| 382 } | |
| 383 return now; | |
| 384 } | |
| 385 | |
| 386 /* Server configuration hash tables need to account the SECITEM.type | |
| 387 * field as well. These functions accomplish that. */ | |
| 388 static PLHashNumber | |
| 389 Get32BitNameHash(const SECItem *name) | |
| 390 { | |
| 391 PLHashNumber rv = SECITEM_Hash(name); | |
| 392 | |
| 393 PRUint8 *rvc = (PRUint8 *)&rv; | |
| 394 rvc[name->len % sizeof(rv)] ^= name->type; | |
| 395 | |
| 396 return rv; | |
| 397 } | |
| 398 | |
| 399 /* Put a name in the cache. Update the cert index in the sce. | |
| 400 */ | |
| 401 static PRUint32 | |
| 402 CacheSrvName(cacheDesc *cache, SECItem *name, sidCacheEntry *sce) | |
| 403 { | |
| 404 PRUint32 now; | |
| 405 PRUint32 ndx; | |
| 406 srvNameCacheEntry snce; | |
| 407 | |
| 408 if (!name || name->len <= 0 || | |
| 409 name->len > SSL_MAX_DNS_HOST_NAME) { | |
| 410 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 411 return 0; | |
| 412 } | |
| 413 | |
| 414 snce.type = name->type; | |
| 415 snce.nameLen = name->len; | |
| 416 PORT_Memcpy(snce.name, name->data, snce.nameLen); | |
| 417 #ifdef NO_PKCS11_BYPASS | |
| 418 HASH_HashBuf(HASH_AlgSHA256, snce.nameHash, name->data, name->len); | |
| 419 #else | |
| 420 SHA256_HashBuf(snce.nameHash, (unsigned char *)name->data, | |
| 421 name->len); | |
| 422 #endif | |
| 423 /* get index of the next name */ | |
| 424 ndx = Get32BitNameHash(name); | |
| 425 /* get lock on cert cache */ | |
| 426 now = LockSidCacheLock(cache->srvNameCacheLock, 0); | |
| 427 if (now) { | |
| 428 if (cache->numSrvNameCacheEntries > 0) { | |
| 429 /* Fit the index into array */ | |
| 430 ndx %= cache->numSrvNameCacheEntries; | |
| 431 /* write the entry */ | |
| 432 cache->srvNameCacheData[ndx] = snce; | |
| 433 /* remember where we put it. */ | |
| 434 sce->u.ssl3.srvNameIndex = ndx; | |
| 435 /* Copy hash into sid hash */ | |
| 436 PORT_Memcpy(sce->u.ssl3.srvNameHash, snce.nameHash, SHA256_LENGTH); | |
| 437 } | |
| 438 UnlockSidCacheLock(cache->srvNameCacheLock); | |
| 439 } | |
| 440 return now; | |
| 441 } | |
| 442 | |
| 443 /* | |
| 444 ** Convert local SID to shared memory one | |
| 445 */ | |
| 446 static void | |
| 447 ConvertFromSID(sidCacheEntry *to, sslSessionID *from) | |
| 448 { | |
| 449 to->valid = 1; | |
| 450 to->version = from->version; | |
| 451 to->addr = from->addr; | |
| 452 to->creationTime = from->creationTime; | |
| 453 to->lastAccessTime = from->lastAccessTime; | |
| 454 to->expirationTime = from->expirationTime; | |
| 455 to->authAlgorithm = from->authAlgorithm; | |
| 456 to->authKeyBits = from->authKeyBits; | |
| 457 to->keaType = from->keaType; | |
| 458 to->keaKeyBits = from->keaKeyBits; | |
| 459 | |
| 460 if (from->version < SSL_LIBRARY_VERSION_3_0) { | |
| 461 if ((from->u.ssl2.masterKey.len > SSL_MAX_MASTER_KEY_BYTES) || | |
| 462 (from->u.ssl2.cipherArg.len > SSL_MAX_CYPHER_ARG_BYTES)) { | |
| 463 SSL_DBG(("%d: SSL: masterKeyLen=%d cipherArgLen=%d", | |
| 464 myPid, from->u.ssl2.masterKey.len, | |
| 465 from->u.ssl2.cipherArg.len)); | |
| 466 to->valid = 0; | |
| 467 return; | |
| 468 } | |
| 469 | |
| 470 to->u.ssl2.cipherType = from->u.ssl2.cipherType; | |
| 471 to->u.ssl2.masterKeyLen = from->u.ssl2.masterKey.len; | |
| 472 to->u.ssl2.cipherArgLen = from->u.ssl2.cipherArg.len; | |
| 473 to->u.ssl2.keyBits = from->u.ssl2.keyBits; | |
| 474 to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits; | |
| 475 to->sessionIDLength = SSL2_SESSIONID_BYTES; | |
| 476 PORT_Memcpy(to->sessionID, from->u.ssl2.sessionID, SSL2_SESSIONID_BYTES)
; | |
| 477 PORT_Memcpy(to->u.ssl2.masterKey, from->u.ssl2.masterKey.data, | |
| 478 from->u.ssl2.masterKey.len); | |
| 479 PORT_Memcpy(to->u.ssl2.cipherArg, from->u.ssl2.cipherArg.data, | |
| 480 from->u.ssl2.cipherArg.len); | |
| 481 #ifdef DEBUG | |
| 482 PORT_Memset(to->u.ssl2.masterKey + from->u.ssl2.masterKey.len, 0, | |
| 483 sizeof(to->u.ssl2.masterKey) - from->u.ssl2.masterKey.len); | |
| 484 PORT_Memset(to->u.ssl2.cipherArg + from->u.ssl2.cipherArg.len, 0, | |
| 485 sizeof(to->u.ssl2.cipherArg) - from->u.ssl2.cipherArg.len); | |
| 486 #endif | |
| 487 SSL_TRC(8, ("%d: SSL: ConvertSID: masterKeyLen=%d cipherArgLen=%d " | |
| 488 "time=%d addr=0x%08x%08x%08x%08x cipherType=%d", | |
| 489 myPid, | |
| 490 to->u.ssl2.masterKeyLen, to->u.ssl2.cipherArgLen, | |
| 491 to->creationTime, to->addr.pr_s6_addr32[0], | |
| 492 to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2], | |
| 493 to->addr.pr_s6_addr32[3], to->u.ssl2.cipherType)); | |
| 494 } else { | |
| 495 /* This is an SSL v3 session */ | |
| 496 | |
| 497 to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite; | |
| 498 to->u.ssl3.compression = (PRUint16)from->u.ssl3.compression; | |
| 499 to->u.ssl3.keys = from->u.ssl3.keys; | |
| 500 to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech; | |
| 501 to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType; | |
| 502 to->sessionIDLength = from->u.ssl3.sessionIDLength; | |
| 503 to->u.ssl3.certIndex = -1; | |
| 504 to->u.ssl3.srvNameIndex = -1; | |
| 505 PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID, | |
| 506 to->sessionIDLength); | |
| 507 | |
| 508 SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x " | |
| 509 "cipherSuite=%d", | |
| 510 myPid, to->creationTime, to->addr.pr_s6_addr32[0], | |
| 511 to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2], | |
| 512 to->addr.pr_s6_addr32[3], to->u.ssl3.cipherSuite)); | |
| 513 } | |
| 514 } | |
| 515 | |
| 516 /* | |
| 517 ** Convert shared memory cache-entry to local memory based one | |
| 518 ** This is only called from ServerSessionIDLookup(). | |
| 519 */ | |
| 520 static sslSessionID * | |
| 521 ConvertToSID(sidCacheEntry *from, | |
| 522 certCacheEntry *pcce, | |
| 523 srvNameCacheEntry *psnce, | |
| 524 CERTCertDBHandle *dbHandle) | |
| 525 { | |
| 526 sslSessionID *to; | |
| 527 PRUint16 version = from->version; | |
| 528 | |
| 529 to = PORT_ZNew(sslSessionID); | |
| 530 if (!to) { | |
| 531 return 0; | |
| 532 } | |
| 533 | |
| 534 if (version < SSL_LIBRARY_VERSION_3_0) { | |
| 535 /* This is an SSL v2 session */ | |
| 536 to->u.ssl2.masterKey.data = | |
| 537 (unsigned char *)PORT_Alloc(from->u.ssl2.masterKeyLen); | |
| 538 if (!to->u.ssl2.masterKey.data) { | |
| 539 goto loser; | |
| 540 } | |
| 541 if (from->u.ssl2.cipherArgLen) { | |
| 542 to->u.ssl2.cipherArg.data = | |
| 543 (unsigned char *)PORT_Alloc(from->u.ssl2.cipherArgLen); | |
| 544 if (!to->u.ssl2.cipherArg.data) { | |
| 545 goto loser; | |
| 546 } | |
| 547 PORT_Memcpy(to->u.ssl2.cipherArg.data, from->u.ssl2.cipherArg, | |
| 548 from->u.ssl2.cipherArgLen); | |
| 549 } | |
| 550 | |
| 551 to->u.ssl2.cipherType = from->u.ssl2.cipherType; | |
| 552 to->u.ssl2.masterKey.len = from->u.ssl2.masterKeyLen; | |
| 553 to->u.ssl2.cipherArg.len = from->u.ssl2.cipherArgLen; | |
| 554 to->u.ssl2.keyBits = from->u.ssl2.keyBits; | |
| 555 to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits; | |
| 556 /* to->sessionIDLength = SSL2_SESSIONID_BYTES; */ | |
| 557 PORT_Memcpy(to->u.ssl2.sessionID, from->sessionID, SSL2_SESSIONID_BYTES)
; | |
| 558 PORT_Memcpy(to->u.ssl2.masterKey.data, from->u.ssl2.masterKey, | |
| 559 from->u.ssl2.masterKeyLen); | |
| 560 | |
| 561 SSL_TRC(8, ("%d: SSL: ConvertToSID: masterKeyLen=%d cipherArgLen=%d " | |
| 562 "time=%d addr=0x%08x%08x%08x%08x cipherType=%d", | |
| 563 myPid, to->u.ssl2.masterKey.len, | |
| 564 to->u.ssl2.cipherArg.len, to->creationTime, | |
| 565 to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1], | |
| 566 to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3], | |
| 567 to->u.ssl2.cipherType)); | |
| 568 } else { | |
| 569 /* This is an SSL v3 session */ | |
| 570 | |
| 571 to->u.ssl3.sessionIDLength = from->sessionIDLength; | |
| 572 to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite; | |
| 573 to->u.ssl3.compression = (SSLCompressionMethod)from->u.ssl3.compression; | |
| 574 to->u.ssl3.keys = from->u.ssl3.keys; | |
| 575 to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech; | |
| 576 to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType; | |
| 577 if (from->u.ssl3.srvNameIndex != -1 && psnce) { | |
| 578 SECItem name; | |
| 579 SECStatus rv; | |
| 580 name.type = psnce->type; | |
| 581 name.len = psnce->nameLen; | |
| 582 name.data = psnce->name; | |
| 583 rv = SECITEM_CopyItem(NULL, &to->u.ssl3.srvName, &name); | |
| 584 if (rv != SECSuccess) { | |
| 585 goto loser; | |
| 586 } | |
| 587 } | |
| 588 | |
| 589 PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength
); | |
| 590 | |
| 591 /* the portions of the SID that are only restored on the client | |
| 592 * are set to invalid values on the server. | |
| 593 */ | |
| 594 to->u.ssl3.clientWriteKey = NULL; | |
| 595 to->u.ssl3.serverWriteKey = NULL; | |
| 596 | |
| 597 to->urlSvrName = NULL; | |
| 598 | |
| 599 to->u.ssl3.masterModuleID = (SECMODModuleID)-1; /* invalid value */ | |
| 600 to->u.ssl3.masterSlotID = (CK_SLOT_ID)-1; /* invalid value */ | |
| 601 to->u.ssl3.masterWrapIndex = 0; | |
| 602 to->u.ssl3.masterWrapSeries = 0; | |
| 603 to->u.ssl3.masterValid = PR_FALSE; | |
| 604 | |
| 605 to->u.ssl3.clAuthModuleID = (SECMODModuleID)-1; /* invalid value */ | |
| 606 to->u.ssl3.clAuthSlotID = (CK_SLOT_ID)-1; /* invalid value */ | |
| 607 to->u.ssl3.clAuthSeries = 0; | |
| 608 to->u.ssl3.clAuthValid = PR_FALSE; | |
| 609 | |
| 610 if (from->u.ssl3.certIndex != -1 && pcce) { | |
| 611 SECItem derCert; | |
| 612 | |
| 613 derCert.len = pcce->certLength; | |
| 614 derCert.data = pcce->cert; | |
| 615 | |
| 616 to->peerCert = CERT_NewTempCertificate(dbHandle, &derCert, NULL, | |
| 617 PR_FALSE, PR_TRUE); | |
| 618 if (to->peerCert == NULL) | |
| 619 goto loser; | |
| 620 } | |
| 621 } | |
| 622 | |
| 623 to->version = from->version; | |
| 624 to->creationTime = from->creationTime; | |
| 625 to->lastAccessTime = from->lastAccessTime; | |
| 626 to->expirationTime = from->expirationTime; | |
| 627 to->cached = in_server_cache; | |
| 628 to->addr = from->addr; | |
| 629 to->references = 1; | |
| 630 to->authAlgorithm = from->authAlgorithm; | |
| 631 to->authKeyBits = from->authKeyBits; | |
| 632 to->keaType = from->keaType; | |
| 633 to->keaKeyBits = from->keaKeyBits; | |
| 634 | |
| 635 return to; | |
| 636 | |
| 637 loser: | |
| 638 if (to) { | |
| 639 if (version < SSL_LIBRARY_VERSION_3_0) { | |
| 640 if (to->u.ssl2.masterKey.data) | |
| 641 PORT_Free(to->u.ssl2.masterKey.data); | |
| 642 if (to->u.ssl2.cipherArg.data) | |
| 643 PORT_Free(to->u.ssl2.cipherArg.data); | |
| 644 } else { | |
| 645 SECITEM_FreeItem(&to->u.ssl3.srvName, PR_FALSE); | |
| 646 } | |
| 647 PORT_Free(to); | |
| 648 } | |
| 649 return NULL; | |
| 650 } | |
| 651 | |
| 652 /* | |
| 653 ** Perform some mumbo jumbo on the ip-address and the session-id value to | |
| 654 ** compute a hash value. | |
| 655 */ | |
| 656 static PRUint32 | |
| 657 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl) | |
| 658 { | |
| 659 PRUint32 rv; | |
| 660 PRUint32 x[8]; | |
| 661 | |
| 662 memset(x, 0, sizeof x); | |
| 663 if (nl > sizeof x) | |
| 664 nl = sizeof x; | |
| 665 memcpy(x, s, nl); | |
| 666 | |
| 667 rv = (addr->pr_s6_addr32[0] ^ addr->pr_s6_addr32[1] ^ | |
| 668 addr->pr_s6_addr32[2] ^ addr->pr_s6_addr32[3] ^ | |
| 669 x[0] ^ x[1] ^ x[2] ^ x[3] ^ x[4] ^ x[5] ^ x[6] ^ x[7]) % | |
| 670 cache->numSIDCacheSets; | |
| 671 return rv; | |
| 672 } | |
| 673 | |
| 674 /* | |
| 675 ** Look something up in the cache. This will invalidate old entries | |
| 676 ** in the process. Caller has locked the cache set! | |
| 677 ** Returns PR_TRUE if found a valid match. PR_FALSE otherwise. | |
| 678 */ | |
| 679 static sidCacheEntry * | |
| 680 FindSID(cacheDesc *cache, PRUint32 setNum, PRUint32 now, | |
| 681 const PRIPv6Addr *addr, unsigned char *sessionID, | |
| 682 unsigned sessionIDLength) | |
| 683 { | |
| 684 PRUint32 ndx = cache->sidCacheSets[setNum].next; | |
| 685 int i; | |
| 686 | |
| 687 sidCacheEntry *set = cache->sidCacheData + | |
| 688 (setNum * SID_CACHE_ENTRIES_PER_SET); | |
| 689 | |
| 690 for (i = SID_CACHE_ENTRIES_PER_SET; i > 0; --i) { | |
| 691 sidCacheEntry *sce; | |
| 692 | |
| 693 ndx = (ndx - 1) % SID_CACHE_ENTRIES_PER_SET; | |
| 694 sce = set + ndx; | |
| 695 | |
| 696 if (!sce->valid) | |
| 697 continue; | |
| 698 | |
| 699 if (now > sce->expirationTime) { | |
| 700 /* SessionID has timed out. Invalidate the entry. */ | |
| 701 SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x " | |
| 702 "time+=%x", | |
| 703 myPid, sce->addr.pr_s6_addr32[0], | |
| 704 sce->addr.pr_s6_addr32[1], sce->addr.pr_s6_addr32[2], | |
| 705 sce->addr.pr_s6_addr32[3], now, | |
| 706 sce->expirationTime)); | |
| 707 sce->valid = 0; | |
| 708 continue; | |
| 709 } | |
| 710 | |
| 711 /* | |
| 712 ** Next, examine specific session-id/addr data to see if the cache | |
| 713 ** entry matches our addr+session-id value | |
| 714 */ | |
| 715 if (sessionIDLength == sce->sessionIDLength && | |
| 716 !memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) && | |
| 717 !memcmp(sce->sessionID, sessionID, sessionIDLength)) { | |
| 718 /* Found it */ | |
| 719 return sce; | |
| 720 } | |
| 721 } | |
| 722 | |
| 723 PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND); | |
| 724 return NULL; | |
| 725 } | |
| 726 | |
| 727 /************************************************************************/ | |
| 728 | |
| 729 /* This is the primary function for finding entries in the server's sid cache. | |
| 730 * Although it is static, this function is called via the global function | |
| 731 * pointer ssl_sid_lookup. | |
| 732 */ | |
| 733 static sslSessionID * | |
| 734 ServerSessionIDLookup(const PRIPv6Addr *addr, | |
| 735 unsigned char *sessionID, | |
| 736 unsigned int sessionIDLength, | |
| 737 CERTCertDBHandle *dbHandle) | |
| 738 { | |
| 739 sslSessionID *sid = 0; | |
| 740 sidCacheEntry *psce; | |
| 741 certCacheEntry *pcce = 0; | |
| 742 srvNameCacheEntry *psnce = 0; | |
| 743 cacheDesc *cache = &globalCache; | |
| 744 PRUint32 now; | |
| 745 PRUint32 set; | |
| 746 PRInt32 cndx; | |
| 747 sidCacheEntry sce; | |
| 748 certCacheEntry cce; | |
| 749 srvNameCacheEntry snce; | |
| 750 | |
| 751 set = SIDindex(cache, addr, sessionID, sessionIDLength); | |
| 752 now = LockSet(cache, set, 0); | |
| 753 if (!now) | |
| 754 return NULL; | |
| 755 | |
| 756 psce = FindSID(cache, set, now, addr, sessionID, sessionIDLength); | |
| 757 if (psce) { | |
| 758 if (psce->version >= SSL_LIBRARY_VERSION_3_0) { | |
| 759 if ((cndx = psce->u.ssl3.certIndex) != -1) { | |
| 760 | |
| 761 PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now); | |
| 762 if (gotLock) { | |
| 763 pcce = &cache->certCacheData[cndx]; | |
| 764 | |
| 765 /* See if the cert's session ID matches the sce cache. */ | |
| 766 if ((pcce->sessionIDLength == psce->sessionIDLength) && | |
| 767 !PORT_Memcmp(pcce->sessionID, psce->sessionID, | |
| 768 pcce->sessionIDLength)) { | |
| 769 cce = *pcce; | |
| 770 } else { | |
| 771 /* The cert doesen't match the SID cache entry, | |
| 772 ** so invalidate the SID cache entry. | |
| 773 */ | |
| 774 psce->valid = 0; | |
| 775 psce = 0; | |
| 776 pcce = 0; | |
| 777 } | |
| 778 UnlockSidCacheLock(cache->certCacheLock); | |
| 779 } else { | |
| 780 /* what the ??. Didn't get the cert cache lock. | |
| 781 ** Don't invalidate the SID cache entry, but don't find it. | |
| 782 */ | |
| 783 PORT_Assert(!("Didn't get cert Cache Lock!")); | |
| 784 psce = 0; | |
| 785 pcce = 0; | |
| 786 } | |
| 787 } | |
| 788 if (psce && ((cndx = psce->u.ssl3.srvNameIndex) != -1)) { | |
| 789 PRUint32 gotLock = LockSidCacheLock(cache->srvNameCacheLock, | |
| 790 now); | |
| 791 if (gotLock) { | |
| 792 psnce = &cache->srvNameCacheData[cndx]; | |
| 793 | |
| 794 if (!PORT_Memcmp(psnce->nameHash, psce->u.ssl3.srvNameHash, | |
| 795 SHA256_LENGTH)) { | |
| 796 snce = *psnce; | |
| 797 } else { | |
| 798 /* The name doesen't match the SID cache entry, | |
| 799 ** so invalidate the SID cache entry. | |
| 800 */ | |
| 801 psce->valid = 0; | |
| 802 psce = 0; | |
| 803 psnce = 0; | |
| 804 } | |
| 805 UnlockSidCacheLock(cache->srvNameCacheLock); | |
| 806 } else { | |
| 807 /* what the ??. Didn't get the cert cache lock. | |
| 808 ** Don't invalidate the SID cache entry, but don't find it. | |
| 809 */ | |
| 810 PORT_Assert(!("Didn't get name Cache Lock!")); | |
| 811 psce = 0; | |
| 812 psnce = 0; | |
| 813 } | |
| 814 } | |
| 815 } | |
| 816 if (psce) { | |
| 817 psce->lastAccessTime = now; | |
| 818 sce = *psce; /* grab a copy while holding the lock */ | |
| 819 } | |
| 820 } | |
| 821 UnlockSet(cache, set); | |
| 822 if (psce) { | |
| 823 /* sce conains a copy of the cache entry. | |
| 824 ** Convert shared memory format to local format | |
| 825 */ | |
| 826 sid = ConvertToSID(&sce, pcce ? &cce : 0, psnce ? &snce : 0, dbHandle); | |
| 827 } | |
| 828 return sid; | |
| 829 } | |
| 830 | |
| 831 /* | |
| 832 ** Place a sid into the cache, if it isn't already there. | |
| 833 */ | |
| 834 static void | |
| 835 ServerSessionIDCache(sslSessionID *sid) | |
| 836 { | |
| 837 sidCacheEntry sce; | |
| 838 PRUint32 now = 0; | |
| 839 PRUint16 version = sid->version; | |
| 840 cacheDesc *cache = &globalCache; | |
| 841 | |
| 842 if ((version >= SSL_LIBRARY_VERSION_3_0) && | |
| 843 (sid->u.ssl3.sessionIDLength == 0)) { | |
| 844 return; | |
| 845 } | |
| 846 | |
| 847 if (sid->cached == never_cached || sid->cached == invalid_cache) { | |
| 848 PRUint32 set; | |
| 849 | |
| 850 PORT_Assert(sid->creationTime != 0); | |
| 851 if (!sid->creationTime) | |
| 852 sid->lastAccessTime = sid->creationTime = ssl_Time(); | |
| 853 if (version < SSL_LIBRARY_VERSION_3_0) { | |
| 854 /* override caller's expiration time, which uses client timeout | |
| 855 * duration, not server timeout duration. | |
| 856 */ | |
| 857 sid->expirationTime = sid->creationTime + cache->ssl2Timeout; | |
| 858 SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x tim
e=%x " | |
| 859 "cipher=%d", | |
| 860 myPid, sid->cached, | |
| 861 sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], | |
| 862 sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], | |
| 863 sid->creationTime, sid->u.ssl2.cipherType)); | |
| 864 PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID, | |
| 865 SSL2_SESSIONID_BYTES)); | |
| 866 PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data, | |
| 867 sid->u.ssl2.masterKey.len)); | |
| 868 PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data, | |
| 869 sid->u.ssl2.cipherArg.len)); | |
| 870 } else { | |
| 871 /* override caller's expiration time, which uses client timeout | |
| 872 * duration, not server timeout duration. | |
| 873 */ | |
| 874 sid->expirationTime = sid->creationTime + cache->ssl3Timeout; | |
| 875 SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x tim
e=%x " | |
| 876 "cipherSuite=%d", | |
| 877 myPid, sid->cached, | |
| 878 sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], | |
| 879 sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], | |
| 880 sid->creationTime, sid->u.ssl3.cipherSuite)); | |
| 881 PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID, | |
| 882 sid->u.ssl3.sessionIDLength)); | |
| 883 } | |
| 884 | |
| 885 ConvertFromSID(&sce, sid); | |
| 886 | |
| 887 if (version >= SSL_LIBRARY_VERSION_3_0) { | |
| 888 SECItem *name = &sid->u.ssl3.srvName; | |
| 889 if (name->len && name->data) { | |
| 890 now = CacheSrvName(cache, name, &sce); | |
| 891 } | |
| 892 if (sid->peerCert != NULL) { | |
| 893 now = CacheCert(cache, sid->peerCert, &sce); | |
| 894 } | |
| 895 } | |
| 896 | |
| 897 set = SIDindex(cache, &sce.addr, sce.sessionID, sce.sessionIDLength); | |
| 898 now = LockSet(cache, set, now); | |
| 899 if (now) { | |
| 900 PRUint32 next = cache->sidCacheSets[set].next; | |
| 901 PRUint32 ndx = set * SID_CACHE_ENTRIES_PER_SET + next; | |
| 902 | |
| 903 /* Write out new cache entry */ | |
| 904 cache->sidCacheData[ndx] = sce; | |
| 905 | |
| 906 cache->sidCacheSets[set].next = | |
| 907 (next + 1) % SID_CACHE_ENTRIES_PER_SET; | |
| 908 | |
| 909 UnlockSet(cache, set); | |
| 910 sid->cached = in_server_cache; | |
| 911 } | |
| 912 } | |
| 913 } | |
| 914 | |
| 915 /* | |
| 916 ** Although this is static, it is called from ssl via global function pointer | |
| 917 ** ssl_sid_uncache. This invalidates the referenced cache entry. | |
| 918 */ | |
| 919 static void | |
| 920 ServerSessionIDUncache(sslSessionID *sid) | |
| 921 { | |
| 922 cacheDesc *cache = &globalCache; | |
| 923 PRUint8 *sessionID; | |
| 924 unsigned int sessionIDLength; | |
| 925 PRErrorCode err; | |
| 926 PRUint32 set; | |
| 927 PRUint32 now; | |
| 928 sidCacheEntry *psce; | |
| 929 | |
| 930 if (sid == NULL) | |
| 931 return; | |
| 932 | |
| 933 /* Uncaching a SID should never change the error code. | |
| 934 ** So save it here and restore it before exiting. | |
| 935 */ | |
| 936 err = PR_GetError(); | |
| 937 | |
| 938 if (sid->version < SSL_LIBRARY_VERSION_3_0) { | |
| 939 sessionID = sid->u.ssl2.sessionID; | |
| 940 sessionIDLength = SSL2_SESSIONID_BYTES; | |
| 941 SSL_TRC(8, ("%d: SSL: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%
x " | |
| 942 "cipher=%d", | |
| 943 myPid, sid->cached, | |
| 944 sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], | |
| 945 sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], | |
| 946 sid->creationTime, sid->u.ssl2.cipherType)); | |
| 947 PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength)); | |
| 948 PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data, | |
| 949 sid->u.ssl2.masterKey.len)); | |
| 950 PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data, | |
| 951 sid->u.ssl2.cipherArg.len)); | |
| 952 } else { | |
| 953 sessionID = sid->u.ssl3.sessionID; | |
| 954 sessionIDLength = sid->u.ssl3.sessionIDLength; | |
| 955 SSL_TRC(8, ("%d: SSL3: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=
%x " | |
| 956 "cipherSuite=%d", | |
| 957 myPid, sid->cached, | |
| 958 sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], | |
| 959 sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], | |
| 960 sid->creationTime, sid->u.ssl3.cipherSuite)); | |
| 961 PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength)); | |
| 962 } | |
| 963 set = SIDindex(cache, &sid->addr, sessionID, sessionIDLength); | |
| 964 now = LockSet(cache, set, 0); | |
| 965 if (now) { | |
| 966 psce = FindSID(cache, set, now, &sid->addr, sessionID, sessionIDLength); | |
| 967 if (psce) { | |
| 968 psce->valid = 0; | |
| 969 } | |
| 970 UnlockSet(cache, set); | |
| 971 } | |
| 972 sid->cached = invalid_cache; | |
| 973 PORT_SetError(err); | |
| 974 } | |
| 975 | |
| 976 #ifdef XP_OS2 | |
| 977 | |
| 978 #define INCL_DOSPROCESS | |
| 979 #include <os2.h> | |
| 980 | |
| 981 long | |
| 982 gettid(void) | |
| 983 { | |
| 984 PTIB ptib; | |
| 985 PPIB ppib; | |
| 986 DosGetInfoBlocks(&ptib, &ppib); | |
| 987 return ((long)ptib->tib_ordinal); /* thread id */ | |
| 988 } | |
| 989 #endif | |
| 990 | |
| 991 static void | |
| 992 CloseCache(cacheDesc *cache) | |
| 993 { | |
| 994 int locks_initialized = cache->numSIDCacheLocksInitialized; | |
| 995 | |
| 996 if (cache->cacheMem) { | |
| 997 if (cache->sharedCache) { | |
| 998 sidCacheLock *pLock = cache->sidCacheLocks; | |
| 999 for (; locks_initialized > 0; --locks_initialized, ++pLock) { | |
| 1000 /* If everInherited is true, this shared cache was (and may | |
| 1001 ** still be) in use by multiple processes. We do not wish to | |
| 1002 ** destroy the mutexes while they are still in use, but we do | |
| 1003 ** want to free mutex resources associated with this process. | |
| 1004 */ | |
| 1005 sslMutex_Destroy(&pLock->mutex, | |
| 1006 cache->sharedCache->everInherited); | |
| 1007 } | |
| 1008 } | |
| 1009 if (cache->shared) { | |
| 1010 PR_MemUnmap(cache->cacheMem, cache->cacheMemSize); | |
| 1011 } else { | |
| 1012 PORT_Free(cache->cacheMem); | |
| 1013 } | |
| 1014 cache->cacheMem = NULL; | |
| 1015 } | |
| 1016 if (cache->cacheMemMap) { | |
| 1017 PR_CloseFileMap(cache->cacheMemMap); | |
| 1018 cache->cacheMemMap = NULL; | |
| 1019 } | |
| 1020 memset(cache, 0, sizeof *cache); | |
| 1021 } | |
| 1022 | |
| 1023 static SECStatus | |
| 1024 InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries, | |
| 1025 int maxSrvNameCacheEntries, PRUint32 ssl2_timeout, | |
| 1026 PRUint32 ssl3_timeout, const char *directory, PRBool shared) | |
| 1027 { | |
| 1028 ptrdiff_t ptr; | |
| 1029 sidCacheLock *pLock; | |
| 1030 char *cacheMem; | |
| 1031 PRFileMap *cacheMemMap; | |
| 1032 char *cfn = NULL; /* cache file name */ | |
| 1033 int locks_initialized = 0; | |
| 1034 int locks_to_initialize = 0; | |
| 1035 PRUint32 init_time; | |
| 1036 | |
| 1037 if ((!cache) || (maxCacheEntries < 0) || (!directory)) { | |
| 1038 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 1039 return SECFailure; | |
| 1040 } | |
| 1041 | |
| 1042 if (cache->cacheMem) { | |
| 1043 /* Already done */ | |
| 1044 return SECSuccess; | |
| 1045 } | |
| 1046 | |
| 1047 /* make sure loser can clean up properly */ | |
| 1048 cache->shared = shared; | |
| 1049 cache->cacheMem = cacheMem = NULL; | |
| 1050 cache->cacheMemMap = cacheMemMap = NULL; | |
| 1051 cache->sharedCache = (cacheDesc *)0; | |
| 1052 | |
| 1053 cache->numSIDCacheLocksInitialized = 0; | |
| 1054 cache->nextCertCacheEntry = 0; | |
| 1055 cache->stopPolling = PR_FALSE; | |
| 1056 cache->everInherited = PR_FALSE; | |
| 1057 cache->poller = NULL; | |
| 1058 cache->mutexTimeout = 0; | |
| 1059 | |
| 1060 cache->numSIDCacheEntries = maxCacheEntries ? maxCacheEntries | |
| 1061 : DEF_SID_CACHE_ENTRIES; | |
| 1062 cache->numSIDCacheSets = | |
| 1063 SID_HOWMANY(cache->numSIDCacheEntries, SID_CACHE_ENTRIES_PER_SET); | |
| 1064 | |
| 1065 cache->numSIDCacheEntries = | |
| 1066 cache->numSIDCacheSets * SID_CACHE_ENTRIES_PER_SET; | |
| 1067 | |
| 1068 cache->numSIDCacheLocks = | |
| 1069 PR_MIN(cache->numSIDCacheSets, ssl_max_sid_cache_locks); | |
| 1070 | |
| 1071 cache->numSIDCacheSetsPerLock = | |
| 1072 SID_HOWMANY(cache->numSIDCacheSets, cache->numSIDCacheLocks); | |
| 1073 | |
| 1074 cache->numCertCacheEntries = (maxCertCacheEntries > 0) ? maxCertCacheEntries | |
| 1075 : 0; | |
| 1076 cache->numSrvNameCacheEntries = (maxSrvNameCacheEntries >= 0) ? maxSrvNameCa
cheEntries | |
| 1077 : DEF_NAME_CAC
HE_ENTRIES; | |
| 1078 | |
| 1079 /* compute size of shared memory, and offsets of all pointers */ | |
| 1080 ptr = 0; | |
| 1081 cache->cacheMem = (char *)ptr; | |
| 1082 ptr += SID_ROUNDUP(sizeof(cacheDesc), SID_ALIGNMENT); | |
| 1083 | |
| 1084 cache->sidCacheLocks = (sidCacheLock *)ptr; | |
| 1085 cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks; | |
| 1086 cache->certCacheLock = cache->keyCacheLock + 1; | |
| 1087 cache->srvNameCacheLock = cache->certCacheLock + 1; | |
| 1088 ptr = (ptrdiff_t)(cache->srvNameCacheLock + 1); | |
| 1089 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); | |
| 1090 | |
| 1091 cache->sidCacheSets = (sidCacheSet *)ptr; | |
| 1092 ptr = (ptrdiff_t)(cache->sidCacheSets + cache->numSIDCacheSets); | |
| 1093 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); | |
| 1094 | |
| 1095 cache->sidCacheData = (sidCacheEntry *)ptr; | |
| 1096 ptr = (ptrdiff_t)(cache->sidCacheData + cache->numSIDCacheEntries); | |
| 1097 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); | |
| 1098 | |
| 1099 cache->certCacheData = (certCacheEntry *)ptr; | |
| 1100 cache->sidCacheSize = | |
| 1101 (char *)cache->certCacheData - (char *)cache->sidCacheData; | |
| 1102 | |
| 1103 if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) { | |
| 1104 /* This is really a poor way to computer this! */ | |
| 1105 cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry
); | |
| 1106 if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) | |
| 1107 cache->numCertCacheEntries = MIN_CERT_CACHE_ENTRIES; | |
| 1108 } | |
| 1109 ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries); | |
| 1110 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); | |
| 1111 | |
| 1112 cache->keyCacheData = (SSLWrappedSymWrappingKey *)ptr; | |
| 1113 cache->certCacheSize = | |
| 1114 (char *)cache->keyCacheData - (char *)cache->certCacheData; | |
| 1115 | |
| 1116 cache->numKeyCacheEntries = kt_kea_size * SSL_NUM_WRAP_MECHS; | |
| 1117 ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries); | |
| 1118 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); | |
| 1119 | |
| 1120 cache->keyCacheSize = (char *)ptr - (char *)cache->keyCacheData; | |
| 1121 | |
| 1122 cache->ticketKeyNameSuffix = (PRUint8 *)ptr; | |
| 1123 ptr = (ptrdiff_t)(cache->ticketKeyNameSuffix + | |
| 1124 SESS_TICKET_KEY_VAR_NAME_LEN); | |
| 1125 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); | |
| 1126 | |
| 1127 cache->ticketEncKey = (encKeyCacheEntry *)ptr; | |
| 1128 ptr = (ptrdiff_t)(cache->ticketEncKey + 1); | |
| 1129 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); | |
| 1130 | |
| 1131 cache->ticketMacKey = (encKeyCacheEntry *)ptr; | |
| 1132 ptr = (ptrdiff_t)(cache->ticketMacKey + 1); | |
| 1133 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); | |
| 1134 | |
| 1135 cache->ticketKeysValid = (PRUint32 *)ptr; | |
| 1136 ptr = (ptrdiff_t)(cache->ticketKeysValid + 1); | |
| 1137 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); | |
| 1138 | |
| 1139 cache->srvNameCacheData = (srvNameCacheEntry *)ptr; | |
| 1140 cache->srvNameCacheSize = | |
| 1141 cache->numSrvNameCacheEntries * sizeof(srvNameCacheEntry); | |
| 1142 ptr = (ptrdiff_t)(cache->srvNameCacheData + cache->numSrvNameCacheEntries); | |
| 1143 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); | |
| 1144 | |
| 1145 cache->cacheMemSize = ptr; | |
| 1146 | |
| 1147 if (ssl2_timeout) { | |
| 1148 if (ssl2_timeout > MAX_SSL2_TIMEOUT) { | |
| 1149 ssl2_timeout = MAX_SSL2_TIMEOUT; | |
| 1150 } | |
| 1151 if (ssl2_timeout < MIN_SSL2_TIMEOUT) { | |
| 1152 ssl2_timeout = MIN_SSL2_TIMEOUT; | |
| 1153 } | |
| 1154 cache->ssl2Timeout = ssl2_timeout; | |
| 1155 } else { | |
| 1156 cache->ssl2Timeout = DEF_SSL2_TIMEOUT; | |
| 1157 } | |
| 1158 | |
| 1159 if (ssl3_timeout) { | |
| 1160 if (ssl3_timeout > MAX_SSL3_TIMEOUT) { | |
| 1161 ssl3_timeout = MAX_SSL3_TIMEOUT; | |
| 1162 } | |
| 1163 if (ssl3_timeout < MIN_SSL3_TIMEOUT) { | |
| 1164 ssl3_timeout = MIN_SSL3_TIMEOUT; | |
| 1165 } | |
| 1166 cache->ssl3Timeout = ssl3_timeout; | |
| 1167 } else { | |
| 1168 cache->ssl3Timeout = DEF_SSL3_TIMEOUT; | |
| 1169 } | |
| 1170 | |
| 1171 if (shared) { | |
| 1172 /* Create file names */ | |
| 1173 #if defined(XP_UNIX) || defined(XP_BEOS) | |
| 1174 /* there's some confusion here about whether PR_OpenAnonFileMap wants | |
| 1175 ** a directory name or a file name for its first argument. | |
| 1176 cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid); | |
| 1177 */ | |
| 1178 cfn = PR_smprintf("%s", directory); | |
| 1179 #elif defined(XP_WIN32) | |
| 1180 cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, | |
| 1181 GetCurrentThreadId()); | |
| 1182 #elif defined(XP_OS2) | |
| 1183 cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid, | |
| 1184 gettid()); | |
| 1185 #else | |
| 1186 #error "Don't know how to create file name for this platform!" | |
| 1187 #endif | |
| 1188 if (!cfn) { | |
| 1189 goto loser; | |
| 1190 } | |
| 1191 | |
| 1192 /* Create cache */ | |
| 1193 cacheMemMap = PR_OpenAnonFileMap(cfn, cache->cacheMemSize, | |
| 1194 PR_PROT_READWRITE); | |
| 1195 | |
| 1196 PR_smprintf_free(cfn); | |
| 1197 if (!cacheMemMap) { | |
| 1198 goto loser; | |
| 1199 } | |
| 1200 | |
| 1201 cacheMem = PR_MemMap(cacheMemMap, 0, cache->cacheMemSize); | |
| 1202 } else { | |
| 1203 cacheMem = PORT_Alloc(cache->cacheMemSize); | |
| 1204 } | |
| 1205 | |
| 1206 if (!cacheMem) { | |
| 1207 goto loser; | |
| 1208 } | |
| 1209 | |
| 1210 /* Initialize shared memory. This may not be necessary on all platforms */ | |
| 1211 memset(cacheMem, 0, cache->cacheMemSize); | |
| 1212 | |
| 1213 /* Copy cache descriptor header into shared memory */ | |
| 1214 memcpy(cacheMem, cache, sizeof *cache); | |
| 1215 | |
| 1216 /* save private copies of these values */ | |
| 1217 cache->cacheMemMap = cacheMemMap; | |
| 1218 cache->cacheMem = cacheMem; | |
| 1219 cache->sharedCache = (cacheDesc *)cacheMem; | |
| 1220 | |
| 1221 /* Fix pointers in our private copy of cache descriptor to point to | |
| 1222 ** spaces in shared memory | |
| 1223 */ | |
| 1224 cache->sidCacheLocks = (sidCacheLock *)(cache->cacheMem + (ptrdiff_t)cache->
sidCacheLocks); | |
| 1225 cache->keyCacheLock = (sidCacheLock *)(cache->cacheMem + (ptrdiff_t)cache->k
eyCacheLock); | |
| 1226 cache->certCacheLock = (sidCacheLock *)(cache->cacheMem + (ptrdiff_t)cache->
certCacheLock); | |
| 1227 cache->srvNameCacheLock = (sidCacheLock *)(cache->cacheMem + (ptrdiff_t)cach
e->srvNameCacheLock); | |
| 1228 cache->sidCacheSets = (sidCacheSet *)(cache->cacheMem + (ptrdiff_t)cache->si
dCacheSets); | |
| 1229 cache->sidCacheData = (sidCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache->
sidCacheData); | |
| 1230 cache->certCacheData = (certCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache
->certCacheData); | |
| 1231 cache->keyCacheData = (SSLWrappedSymWrappingKey *)(cache->cacheMem + (ptrdif
f_t)cache->keyCacheData); | |
| 1232 cache->ticketKeyNameSuffix = (PRUint8 *)(cache->cacheMem + (ptrdiff_t)cache-
>ticketKeyNameSuffix); | |
| 1233 cache->ticketEncKey = (encKeyCacheEntry *)(cache->cacheMem + (ptrdiff_t)cach
e->ticketEncKey); | |
| 1234 cache->ticketMacKey = (encKeyCacheEntry *)(cache->cacheMem + (ptrdiff_t)cach
e->ticketMacKey); | |
| 1235 cache->ticketKeysValid = (PRUint32 *)(cache->cacheMem + (ptrdiff_t)cache->ti
cketKeysValid); | |
| 1236 cache->srvNameCacheData = (srvNameCacheEntry *)(cache->cacheMem + (ptrdiff_t
)cache->srvNameCacheData); | |
| 1237 | |
| 1238 /* initialize the locks */ | |
| 1239 init_time = ssl_Time(); | |
| 1240 pLock = cache->sidCacheLocks; | |
| 1241 for (locks_to_initialize = cache->numSIDCacheLocks + 3; | |
| 1242 locks_initialized < locks_to_initialize; | |
| 1243 ++locks_initialized, ++pLock) { | |
| 1244 | |
| 1245 SECStatus err = sslMutex_Init(&pLock->mutex, shared); | |
| 1246 if (err) { | |
| 1247 cache->numSIDCacheLocksInitialized = locks_initialized; | |
| 1248 goto loser; | |
| 1249 } | |
| 1250 pLock->timeStamp = init_time; | |
| 1251 pLock->pid = 0; | |
| 1252 } | |
| 1253 cache->numSIDCacheLocksInitialized = locks_initialized; | |
| 1254 | |
| 1255 return SECSuccess; | |
| 1256 | |
| 1257 loser: | |
| 1258 CloseCache(cache); | |
| 1259 return SECFailure; | |
| 1260 } | |
| 1261 | |
| 1262 PRUint32 | |
| 1263 SSL_GetMaxServerCacheLocks(void) | |
| 1264 { | |
| 1265 return ssl_max_sid_cache_locks + 2; | |
| 1266 /* The extra two are the cert cache lock and the key cache lock. */ | |
| 1267 } | |
| 1268 | |
| 1269 SECStatus | |
| 1270 SSL_SetMaxServerCacheLocks(PRUint32 maxLocks) | |
| 1271 { | |
| 1272 /* Minimum is 1 sid cache lock, 1 cert cache lock and 1 key cache lock. | |
| 1273 ** We'd like to test for a maximum value, but not all platforms' header | |
| 1274 ** files provide a symbol or function or other means of determining | |
| 1275 ** the maximum, other than trial and error. | |
| 1276 */ | |
| 1277 if (maxLocks < 3) { | |
| 1278 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 1279 return SECFailure; | |
| 1280 } | |
| 1281 ssl_max_sid_cache_locks = maxLocks - 2; | |
| 1282 /* The extra two are the cert cache lock and the key cache lock. */ | |
| 1283 return SECSuccess; | |
| 1284 } | |
| 1285 | |
| 1286 static SECStatus | |
| 1287 ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache, | |
| 1288 PRUint32 ssl2_timeout, | |
| 1289 PRUint32 ssl3_timeout, | |
| 1290 const char *directory, | |
| 1291 PRBool shared, | |
| 1292 int maxCacheEntries, | |
| 1293 int maxCertCacheEntries, | |
| 1294 int maxSrvNameCacheEntries) | |
| 1295 { | |
| 1296 SECStatus rv; | |
| 1297 | |
| 1298 PORT_Assert(sizeof(sidCacheEntry) == 192); | |
| 1299 PORT_Assert(sizeof(certCacheEntry) == 4096); | |
| 1300 PORT_Assert(sizeof(srvNameCacheEntry) == 1072); | |
| 1301 | |
| 1302 rv = ssl_Init(); | |
| 1303 if (rv != SECSuccess) { | |
| 1304 return rv; | |
| 1305 } | |
| 1306 | |
| 1307 myPid = SSL_GETPID(); | |
| 1308 if (!directory) { | |
| 1309 directory = DEFAULT_CACHE_DIRECTORY; | |
| 1310 } | |
| 1311 rv = InitCache(cache, maxCacheEntries, maxCertCacheEntries, | |
| 1312 maxSrvNameCacheEntries, ssl2_timeout, ssl3_timeout, | |
| 1313 directory, shared); | |
| 1314 if (rv) { | |
| 1315 SET_ERROR_CODE | |
| 1316 return SECFailure; | |
| 1317 } | |
| 1318 | |
| 1319 ssl_sid_lookup = ServerSessionIDLookup; | |
| 1320 ssl_sid_cache = ServerSessionIDCache; | |
| 1321 ssl_sid_uncache = ServerSessionIDUncache; | |
| 1322 return SECSuccess; | |
| 1323 } | |
| 1324 | |
| 1325 SECStatus | |
| 1326 SSL_ConfigServerSessionIDCacheInstance(cacheDesc *cache, | |
| 1327 int maxCacheEntries, | |
| 1328 PRUint32 ssl2_timeout, | |
| 1329 PRUint32 ssl3_timeout, | |
| 1330 const char *directory, PRBool shared) | |
| 1331 { | |
| 1332 return ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache, | |
| 1333 ssl2_timeout, | |
| 1334 ssl3_timeout, | |
| 1335 directory, | |
| 1336 shared, | |
| 1337 maxCacheEntries, | |
| 1338 -1, -1); | |
| 1339 } | |
| 1340 | |
| 1341 SECStatus | |
| 1342 SSL_ConfigServerSessionIDCache(int maxCacheEntries, | |
| 1343 PRUint32 ssl2_timeout, | |
| 1344 PRUint32 ssl3_timeout, | |
| 1345 const char *directory) | |
| 1346 { | |
| 1347 ssl_InitSessionCacheLocks(); | |
| 1348 return SSL_ConfigServerSessionIDCacheInstance(&globalCache, | |
| 1349 maxCacheEntries, ssl2_timeout,
ssl3_timeout, directory, PR_FALSE); | |
| 1350 } | |
| 1351 | |
| 1352 SECStatus | |
| 1353 SSL_ShutdownServerSessionIDCacheInstance(cacheDesc *cache) | |
| 1354 { | |
| 1355 CloseCache(cache); | |
| 1356 return SECSuccess; | |
| 1357 } | |
| 1358 | |
| 1359 SECStatus | |
| 1360 SSL_ShutdownServerSessionIDCache(void) | |
| 1361 { | |
| 1362 #if defined(XP_UNIX) || defined(XP_BEOS) | |
| 1363 /* Stop the thread that polls cache for expired locks on Unix */ | |
| 1364 StopLockPoller(&globalCache); | |
| 1365 #endif | |
| 1366 SSL3_ShutdownServerCache(); | |
| 1367 return SSL_ShutdownServerSessionIDCacheInstance(&globalCache); | |
| 1368 } | |
| 1369 | |
| 1370 /* Use this function, instead of SSL_ConfigServerSessionIDCache, | |
| 1371 * if the cache will be shared by multiple processes. | |
| 1372 */ | |
| 1373 static SECStatus | |
| 1374 ssl_ConfigMPServerSIDCacheWithOpt(PRUint32 ssl2_timeout, | |
| 1375 PRUint32 ssl3_timeout, | |
| 1376 const char *directory, | |
| 1377 int maxCacheEntries, | |
| 1378 int maxCertCacheEntries, | |
| 1379 int maxSrvNameCacheEntries) | |
| 1380 { | |
| 1381 char *envValue; | |
| 1382 char *inhValue; | |
| 1383 cacheDesc *cache = &globalCache; | |
| 1384 PRUint32 fmStrLen; | |
| 1385 SECStatus result; | |
| 1386 PRStatus prStatus; | |
| 1387 SECStatus putEnvFailed; | |
| 1388 inheritance inherit; | |
| 1389 char fmString[PR_FILEMAP_STRING_BUFSIZE]; | |
| 1390 | |
| 1391 isMultiProcess = PR_TRUE; | |
| 1392 result = ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache, | |
| 1393 ssl2_timeout, ssl3_ti
meout, directory, PR_TRUE, | |
| 1394 maxCacheEntries, maxC
acheEntries, maxSrvNameCacheEntries); | |
| 1395 if (result != SECSuccess) | |
| 1396 return result; | |
| 1397 | |
| 1398 prStatus = PR_ExportFileMapAsString(cache->cacheMemMap, | |
| 1399 sizeof fmString, fmString); | |
| 1400 if ((prStatus != PR_SUCCESS) || !(fmStrLen = strlen(fmString))) { | |
| 1401 SET_ERROR_CODE | |
| 1402 return SECFailure; | |
| 1403 } | |
| 1404 | |
| 1405 inherit.cacheMemSize = cache->cacheMemSize; | |
| 1406 inherit.fmStrLen = fmStrLen; | |
| 1407 | |
| 1408 inhValue = BTOA_DataToAscii((unsigned char *)&inherit, sizeof inherit); | |
| 1409 if (!inhValue || !strlen(inhValue)) { | |
| 1410 SET_ERROR_CODE | |
| 1411 return SECFailure; | |
| 1412 } | |
| 1413 envValue = PR_smprintf("%s,%s", inhValue, fmString); | |
| 1414 if (!envValue || !strlen(envValue)) { | |
| 1415 SET_ERROR_CODE | |
| 1416 return SECFailure; | |
| 1417 } | |
| 1418 PORT_Free(inhValue); | |
| 1419 | |
| 1420 putEnvFailed = (SECStatus)NSS_PutEnv(envVarName, envValue); | |
| 1421 PR_smprintf_free(envValue); | |
| 1422 if (putEnvFailed) { | |
| 1423 SET_ERROR_CODE | |
| 1424 result = SECFailure; | |
| 1425 } | |
| 1426 | |
| 1427 #if defined(XP_UNIX) || defined(XP_BEOS) | |
| 1428 /* Launch thread to poll cache for expired locks on Unix */ | |
| 1429 LaunchLockPoller(cache); | |
| 1430 #endif | |
| 1431 return result; | |
| 1432 } | |
| 1433 | |
| 1434 /* Use this function, instead of SSL_ConfigServerSessionIDCache, | |
| 1435 * if the cache will be shared by multiple processes. | |
| 1436 */ | |
| 1437 SECStatus | |
| 1438 SSL_ConfigMPServerSIDCache(int maxCacheEntries, | |
| 1439 PRUint32 ssl2_timeout, | |
| 1440 PRUint32 ssl3_timeout, | |
| 1441 const char *directory) | |
| 1442 { | |
| 1443 return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout, | |
| 1444 ssl3_timeout, | |
| 1445 directory, | |
| 1446 maxCacheEntries, | |
| 1447 -1, -1); | |
| 1448 } | |
| 1449 | |
| 1450 SECStatus | |
| 1451 SSL_ConfigServerSessionIDCacheWithOpt( | |
| 1452 PRUint32 ssl2_timeout, | |
| 1453 PRUint32 ssl3_timeout, | |
| 1454 const char *directory, | |
| 1455 int maxCacheEntries, | |
| 1456 int maxCertCacheEntries, | |
| 1457 int maxSrvNameCacheEntries, | |
| 1458 PRBool enableMPCache) | |
| 1459 { | |
| 1460 if (!enableMPCache) { | |
| 1461 ssl_InitSessionCacheLocks(); | |
| 1462 return ssl_ConfigServerSessionIDCacheInstanceWithOpt(&globalCache, | |
| 1463 ssl2_timeout, ssl3_
timeout, directory, PR_FALSE, | |
| 1464 maxCacheEntries, ma
xCertCacheEntries, maxSrvNameCacheEntries); | |
| 1465 } else { | |
| 1466 return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout, ssl3_timeout, | |
| 1467 directory, maxCacheEntries, max
CertCacheEntries, | |
| 1468 maxSrvNameCacheEntries); | |
| 1469 } | |
| 1470 } | |
| 1471 | |
| 1472 SECStatus | |
| 1473 SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char *envString) | |
| 1474 { | |
| 1475 unsigned char *decoString = NULL; | |
| 1476 char *fmString = NULL; | |
| 1477 char *myEnvString = NULL; | |
| 1478 unsigned int decoLen; | |
| 1479 inheritance inherit; | |
| 1480 cacheDesc my; | |
| 1481 #ifdef WINNT | |
| 1482 sidCacheLock *newLocks; | |
| 1483 int locks_initialized = 0; | |
| 1484 int locks_to_initialize = 0; | |
| 1485 #endif | |
| 1486 SECStatus status = ssl_Init(); | |
| 1487 | |
| 1488 if (status != SECSuccess) { | |
| 1489 return status; | |
| 1490 } | |
| 1491 | |
| 1492 myPid = SSL_GETPID(); | |
| 1493 | |
| 1494 /* If this child was created by fork(), and not by exec() on unix, | |
| 1495 ** then isMultiProcess will already be set. | |
| 1496 ** If not, we'll set it below. | |
| 1497 */ | |
| 1498 if (isMultiProcess) { | |
| 1499 if (cache && cache->sharedCache) { | |
| 1500 cache->sharedCache->everInherited = PR_TRUE; | |
| 1501 } | |
| 1502 return SECSuccess; /* already done. */ | |
| 1503 } | |
| 1504 | |
| 1505 ssl_InitSessionCacheLocks(); | |
| 1506 | |
| 1507 ssl_sid_lookup = ServerSessionIDLookup; | |
| 1508 ssl_sid_cache = ServerSessionIDCache; | |
| 1509 ssl_sid_uncache = ServerSessionIDUncache; | |
| 1510 | |
| 1511 if (!envString) { | |
| 1512 envString = PR_GetEnvSecure(envVarName); | |
| 1513 if (!envString) { | |
| 1514 SET_ERROR_CODE | |
| 1515 return SECFailure; | |
| 1516 } | |
| 1517 } | |
| 1518 myEnvString = PORT_Strdup(envString); | |
| 1519 if (!myEnvString) | |
| 1520 return SECFailure; | |
| 1521 fmString = strchr(myEnvString, ','); | |
| 1522 if (!fmString) | |
| 1523 goto loser; | |
| 1524 *fmString++ = 0; | |
| 1525 | |
| 1526 decoString = ATOB_AsciiToData(myEnvString, &decoLen); | |
| 1527 if (!decoString) { | |
| 1528 SET_ERROR_CODE | |
| 1529 goto loser; | |
| 1530 } | |
| 1531 if (decoLen != sizeof inherit) { | |
| 1532 SET_ERROR_CODE | |
| 1533 goto loser; | |
| 1534 } | |
| 1535 | |
| 1536 PORT_Memcpy(&inherit, decoString, sizeof inherit); | |
| 1537 | |
| 1538 if (strlen(fmString) != inherit.fmStrLen) { | |
| 1539 goto loser; | |
| 1540 } | |
| 1541 | |
| 1542 memset(cache, 0, sizeof *cache); | |
| 1543 cache->cacheMemSize = inherit.cacheMemSize; | |
| 1544 | |
| 1545 /* Create cache */ | |
| 1546 cache->cacheMemMap = PR_ImportFileMapFromString(fmString); | |
| 1547 if (!cache->cacheMemMap) { | |
| 1548 goto loser; | |
| 1549 } | |
| 1550 cache->cacheMem = PR_MemMap(cache->cacheMemMap, 0, cache->cacheMemSize); | |
| 1551 if (!cache->cacheMem) { | |
| 1552 goto loser; | |
| 1553 } | |
| 1554 cache->sharedCache = (cacheDesc *)cache->cacheMem; | |
| 1555 | |
| 1556 if (cache->sharedCache->cacheMemSize != cache->cacheMemSize) { | |
| 1557 SET_ERROR_CODE | |
| 1558 goto loser; | |
| 1559 } | |
| 1560 | |
| 1561 /* We're now going to overwrite the local cache instance with the | |
| 1562 ** shared copy of the cache struct, then update several values in | |
| 1563 ** the local cache using the values for cache->cacheMemMap and | |
| 1564 ** cache->cacheMem computed just above. So, we copy cache into | |
| 1565 ** the automatic variable "my", to preserve the variables while | |
| 1566 ** cache is overwritten. | |
| 1567 */ | |
| 1568 my = *cache; /* save values computed ab
ove. */ | |
| 1569 memcpy(cache, cache->sharedCache, sizeof *cache); /* overwrite */ | |
| 1570 | |
| 1571 /* Fix pointers in our private copy of cache descriptor to point to | |
| 1572 ** spaces in shared memory, whose address is now in "my". | |
| 1573 */ | |
| 1574 cache->sidCacheLocks = (sidCacheLock *)(my.cacheMem + (ptrdiff_t)cache->sidC
acheLocks); | |
| 1575 cache->keyCacheLock = (sidCacheLock *)(my.cacheMem + (ptrdiff_t)cache->keyCa
cheLock); | |
| 1576 cache->certCacheLock = (sidCacheLock *)(my.cacheMem + (ptrdiff_t)cache->cert
CacheLock); | |
| 1577 cache->srvNameCacheLock = (sidCacheLock *)(my.cacheMem + (ptrdiff_t)cache->s
rvNameCacheLock); | |
| 1578 cache->sidCacheSets = (sidCacheSet *)(my.cacheMem + (ptrdiff_t)cache->sidCac
heSets); | |
| 1579 cache->sidCacheData = (sidCacheEntry *)(my.cacheMem + (ptrdiff_t)cache->sidC
acheData); | |
| 1580 cache->certCacheData = (certCacheEntry *)(my.cacheMem + (ptrdiff_t)cache->ce
rtCacheData); | |
| 1581 cache->keyCacheData = (SSLWrappedSymWrappingKey *)(my.cacheMem + (ptrdiff_t)
cache->keyCacheData); | |
| 1582 cache->ticketKeyNameSuffix = (PRUint8 *)(my.cacheMem + (ptrdiff_t)cache->tic
ketKeyNameSuffix); | |
| 1583 cache->ticketEncKey = (encKeyCacheEntry *)(my.cacheMem + (ptrdiff_t)cache->t
icketEncKey); | |
| 1584 cache->ticketMacKey = (encKeyCacheEntry *)(my.cacheMem + (ptrdiff_t)cache->t
icketMacKey); | |
| 1585 cache->ticketKeysValid = (PRUint32 *)(my.cacheMem + (ptrdiff_t)cache->ticket
KeysValid); | |
| 1586 cache->srvNameCacheData = (srvNameCacheEntry *)(my.cacheMem + (ptrdiff_t)cac
he->srvNameCacheData); | |
| 1587 | |
| 1588 cache->cacheMemMap = my.cacheMemMap; | |
| 1589 cache->cacheMem = my.cacheMem; | |
| 1590 cache->sharedCache = (cacheDesc *)cache->cacheMem; | |
| 1591 | |
| 1592 #ifdef WINNT | |
| 1593 /* On Windows NT we need to "fix" the sidCacheLocks here to support fibers | |
| 1594 ** When NT fibers are used in a multi-process server, a second level of | |
| 1595 ** locking is needed to prevent a deadlock, in case a fiber acquires the | |
| 1596 ** cross-process mutex, yields, and another fiber is later scheduled on | |
| 1597 ** the same native thread and tries to acquire the cross-process mutex. | |
| 1598 ** We do this by using a PRLock in the sslMutex. However, it is stored in | |
| 1599 ** shared memory as part of sidCacheLocks, and we don't want to overwrite | |
| 1600 ** the PRLock of the parent process. So we need to make new, private | |
| 1601 ** copies of sidCacheLocks before modifying the sslMutex with our own | |
| 1602 ** PRLock | |
| 1603 */ | |
| 1604 | |
| 1605 /* note from jpierre : this should be free'd in child processes when | |
| 1606 ** a function is added to delete the SSL session cache in the future. | |
| 1607 */ | |
| 1608 locks_to_initialize = cache->numSIDCacheLocks + 3; | |
| 1609 newLocks = PORT_NewArray(sidCacheLock, locks_to_initialize); | |
| 1610 if (!newLocks) | |
| 1611 goto loser; | |
| 1612 /* copy the old locks */ | |
| 1613 memcpy(newLocks, cache->sidCacheLocks, | |
| 1614 locks_to_initialize * sizeof(sidCacheLock)); | |
| 1615 cache->sidCacheLocks = newLocks; | |
| 1616 /* fix the locks */ | |
| 1617 for (; locks_initialized < locks_to_initialize; ++locks_initialized) { | |
| 1618 /* now, make a local PRLock in this sslMutex for this child process */ | |
| 1619 SECStatus err; | |
| 1620 err = sslMutex_2LevelInit(&newLocks[locks_initialized].mutex); | |
| 1621 if (err != SECSuccess) { | |
| 1622 cache->numSIDCacheLocksInitialized = locks_initialized; | |
| 1623 goto loser; | |
| 1624 } | |
| 1625 } | |
| 1626 cache->numSIDCacheLocksInitialized = locks_initialized; | |
| 1627 | |
| 1628 /* also fix the key and cert cache which use the last 2 lock entries */ | |
| 1629 cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks; | |
| 1630 cache->certCacheLock = cache->keyCacheLock + 1; | |
| 1631 cache->srvNameCacheLock = cache->certCacheLock + 1; | |
| 1632 #endif | |
| 1633 | |
| 1634 PORT_Free(myEnvString); | |
| 1635 PORT_Free(decoString); | |
| 1636 | |
| 1637 /* mark that we have inherited this. */ | |
| 1638 cache->sharedCache->everInherited = PR_TRUE; | |
| 1639 isMultiProcess = PR_TRUE; | |
| 1640 | |
| 1641 return SECSuccess; | |
| 1642 | |
| 1643 loser: | |
| 1644 PORT_Free(myEnvString); | |
| 1645 if (decoString) | |
| 1646 PORT_Free(decoString); | |
| 1647 CloseCache(cache); | |
| 1648 return SECFailure; | |
| 1649 } | |
| 1650 | |
| 1651 SECStatus | |
| 1652 SSL_InheritMPServerSIDCache(const char *envString) | |
| 1653 { | |
| 1654 return SSL_InheritMPServerSIDCacheInstance(&globalCache, envString); | |
| 1655 } | |
| 1656 | |
| 1657 #if defined(XP_UNIX) || defined(XP_BEOS) | |
| 1658 | |
| 1659 #define SID_LOCK_EXPIRATION_TIMEOUT 30 /* seconds */ | |
| 1660 | |
| 1661 static void | |
| 1662 LockPoller(void *arg) | |
| 1663 { | |
| 1664 cacheDesc *cache = (cacheDesc *)arg; | |
| 1665 cacheDesc *sharedCache = cache->sharedCache; | |
| 1666 sidCacheLock *pLock; | |
| 1667 PRIntervalTime timeout; | |
| 1668 PRUint32 now; | |
| 1669 PRUint32 then; | |
| 1670 int locks_polled = 0; | |
| 1671 int locks_to_poll = cache->numSIDCacheLocks + 2; | |
| 1672 PRUint32 expiration = cache->mutexTimeout; | |
| 1673 | |
| 1674 timeout = PR_SecondsToInterval(expiration); | |
| 1675 while (!sharedCache->stopPolling) { | |
| 1676 PR_Sleep(timeout); | |
| 1677 if (sharedCache->stopPolling) | |
| 1678 break; | |
| 1679 | |
| 1680 now = ssl_Time(); | |
| 1681 then = now - expiration; | |
| 1682 for (pLock = cache->sidCacheLocks, locks_polled = 0; | |
| 1683 locks_to_poll > locks_polled && !sharedCache->stopPolling; | |
| 1684 ++locks_polled, ++pLock) { | |
| 1685 pid_t pid; | |
| 1686 | |
| 1687 if (pLock->timeStamp < then && | |
| 1688 pLock->timeStamp != 0 && | |
| 1689 (pid = pLock->pid) != 0) { | |
| 1690 | |
| 1691 /* maybe we should try the lock? */ | |
| 1692 int result = kill(pid, 0); | |
| 1693 if (result < 0 && errno == ESRCH) { | |
| 1694 SECStatus rv; | |
| 1695 /* No process exists by that pid any more. | |
| 1696 ** Treat this mutex as abandoned. | |
| 1697 */ | |
| 1698 pLock->timeStamp = now; | |
| 1699 pLock->pid = 0; | |
| 1700 rv = sslMutex_Unlock(&pLock->mutex); | |
| 1701 if (rv != SECSuccess) { | |
| 1702 /* Now what? */ | |
| 1703 } | |
| 1704 } | |
| 1705 } | |
| 1706 } /* end of loop over locks */ | |
| 1707 } /* end of entire polling loop */ | |
| 1708 } | |
| 1709 | |
| 1710 /* Launch thread to poll cache for expired locks */ | |
| 1711 static SECStatus | |
| 1712 LaunchLockPoller(cacheDesc *cache) | |
| 1713 { | |
| 1714 const char *timeoutString; | |
| 1715 PRThread *pollerThread; | |
| 1716 | |
| 1717 cache->mutexTimeout = SID_LOCK_EXPIRATION_TIMEOUT; | |
| 1718 timeoutString = PR_GetEnvSecure("NSS_SSL_SERVER_CACHE_MUTEX_TIMEOUT"); | |
| 1719 if (timeoutString) { | |
| 1720 long newTime = strtol(timeoutString, 0, 0); | |
| 1721 if (newTime == 0) | |
| 1722 return SECSuccess; /* application doesn't want poller thread */ | |
| 1723 if (newTime > 0) | |
| 1724 cache->mutexTimeout = (PRUint32)newTime; | |
| 1725 /* if error (newTime < 0) ignore it and use default */ | |
| 1726 } | |
| 1727 | |
| 1728 pollerThread = | |
| 1729 PR_CreateThread(PR_USER_THREAD, LockPoller, cache, PR_PRIORITY_NORMAL, | |
| 1730 PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); | |
| 1731 if (!pollerThread) { | |
| 1732 return SECFailure; | |
| 1733 } | |
| 1734 cache->poller = pollerThread; | |
| 1735 return SECSuccess; | |
| 1736 } | |
| 1737 | |
| 1738 /* Stop the thread that polls cache for expired locks */ | |
| 1739 static SECStatus | |
| 1740 StopLockPoller(cacheDesc *cache) | |
| 1741 { | |
| 1742 if (!cache->poller) { | |
| 1743 return SECSuccess; | |
| 1744 } | |
| 1745 cache->sharedCache->stopPolling = PR_TRUE; | |
| 1746 if (PR_Interrupt(cache->poller) != PR_SUCCESS) { | |
| 1747 return SECFailure; | |
| 1748 } | |
| 1749 if (PR_JoinThread(cache->poller) != PR_SUCCESS) { | |
| 1750 return SECFailure; | |
| 1751 } | |
| 1752 cache->poller = NULL; | |
| 1753 return SECSuccess; | |
| 1754 } | |
| 1755 #endif | |
| 1756 | |
| 1757 /************************************************************************ | |
| 1758 * Code dealing with shared wrapped symmetric wrapping keys below * | |
| 1759 ************************************************************************/ | |
| 1760 | |
| 1761 /* If now is zero, it implies that the lock is not held, and must be | |
| 1762 ** aquired here. | |
| 1763 */ | |
| 1764 static PRBool | |
| 1765 getSvrWrappingKey(PRInt32 symWrapMechIndex, | |
| 1766 SSL3KEAType exchKeyType, | |
| 1767 SSLWrappedSymWrappingKey *wswk, | |
| 1768 cacheDesc *cache, | |
| 1769 PRUint32 lockTime) | |
| 1770 { | |
| 1771 PRUint32 ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex; | |
| 1772 SSLWrappedSymWrappingKey *pwswk = cache->keyCacheData + ndx; | |
| 1773 PRUint32 now = 0; | |
| 1774 PRBool rv = PR_FALSE; | |
| 1775 | |
| 1776 if (!cache->cacheMem) { /* cache is uninitialized */ | |
| 1777 PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED); | |
| 1778 return rv; | |
| 1779 } | |
| 1780 if (!lockTime) { | |
| 1781 lockTime = now = LockSidCacheLock(cache->keyCacheLock, now); | |
| 1782 if (!lockTime) { | |
| 1783 return rv; | |
| 1784 } | |
| 1785 } | |
| 1786 if (pwswk->exchKeyType == exchKeyType && | |
| 1787 pwswk->symWrapMechIndex == symWrapMechIndex && | |
| 1788 pwswk->wrappedSymKeyLen != 0) { | |
| 1789 *wswk = *pwswk; | |
| 1790 rv = PR_TRUE; | |
| 1791 } | |
| 1792 if (now) { | |
| 1793 UnlockSidCacheLock(cache->keyCacheLock); | |
| 1794 } | |
| 1795 return rv; | |
| 1796 } | |
| 1797 | |
| 1798 PRBool | |
| 1799 ssl_GetWrappingKey(PRInt32 symWrapMechIndex, | |
| 1800 SSL3KEAType exchKeyType, | |
| 1801 SSLWrappedSymWrappingKey *wswk) | |
| 1802 { | |
| 1803 PRBool rv; | |
| 1804 | |
| 1805 PORT_Assert((unsigned)exchKeyType < kt_kea_size); | |
| 1806 PORT_Assert((unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS); | |
| 1807 if ((unsigned)exchKeyType < kt_kea_size && | |
| 1808 (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) { | |
| 1809 rv = getSvrWrappingKey(symWrapMechIndex, exchKeyType, wswk, | |
| 1810 &globalCache, 0); | |
| 1811 } else { | |
| 1812 rv = PR_FALSE; | |
| 1813 } | |
| 1814 | |
| 1815 return rv; | |
| 1816 } | |
| 1817 | |
| 1818 /* Wrap and cache a session ticket key. */ | |
| 1819 static PRBool | |
| 1820 WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey, | |
| 1821 const char *keyName, encKeyCacheEntry *cacheEntry) | |
| 1822 { | |
| 1823 SECItem wrappedKey = { siBuffer, NULL, 0 }; | |
| 1824 | |
| 1825 wrappedKey.len = SECKEY_PublicKeyStrength(svrPubKey); | |
| 1826 PORT_Assert(wrappedKey.len <= sizeof(cacheEntry->bytes)); | |
| 1827 if (wrappedKey.len > sizeof(cacheEntry->bytes)) | |
| 1828 return PR_FALSE; | |
| 1829 wrappedKey.data = cacheEntry->bytes; | |
| 1830 | |
| 1831 if (PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, symKey, &wrappedKey) != | |
| 1832 SECSuccess) { | |
| 1833 SSL_DBG(("%d: SSL[%s]: Unable to wrap session ticket %s.", | |
| 1834 SSL_GETPID(), "unknown", keyName)); | |
| 1835 return PR_FALSE; | |
| 1836 } | |
| 1837 cacheEntry->length = wrappedKey.len; | |
| 1838 return PR_TRUE; | |
| 1839 } | |
| 1840 | |
| 1841 static PRBool | |
| 1842 GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey, | |
| 1843 PK11SymKey **macKey) | |
| 1844 { | |
| 1845 PK11SlotInfo *slot; | |
| 1846 CK_MECHANISM_TYPE mechanismArray[2]; | |
| 1847 PK11SymKey *aesKeyTmp = NULL; | |
| 1848 PK11SymKey *macKeyTmp = NULL; | |
| 1849 cacheDesc *cache = &globalCache; | |
| 1850 PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN]; | |
| 1851 PRUint8 *ticketKeyNameSuffix; | |
| 1852 | |
| 1853 if (!cache->cacheMem) { | |
| 1854 /* cache is not initalized. Use stack buffer */ | |
| 1855 ticketKeyNameSuffix = ticketKeyNameSuffixLocal; | |
| 1856 } else { | |
| 1857 ticketKeyNameSuffix = cache->ticketKeyNameSuffix; | |
| 1858 } | |
| 1859 | |
| 1860 if (PK11_GenerateRandom(ticketKeyNameSuffix, | |
| 1861 SESS_TICKET_KEY_VAR_NAME_LEN) != | |
| 1862 SECSuccess) { | |
| 1863 SSL_DBG(("%d: SSL[%s]: Unable to generate random key name bytes.", | |
| 1864 SSL_GETPID(), "unknown")); | |
| 1865 goto loser; | |
| 1866 } | |
| 1867 | |
| 1868 mechanismArray[0] = CKM_AES_CBC; | |
| 1869 mechanismArray[1] = CKM_SHA256_HMAC; | |
| 1870 | |
| 1871 slot = PK11_GetBestSlotMultiple(mechanismArray, 2, pwArg); | |
| 1872 if (slot) { | |
| 1873 aesKeyTmp = PK11_KeyGen(slot, mechanismArray[0], NULL, | |
| 1874 AES_256_KEY_LENGTH, pwArg); | |
| 1875 macKeyTmp = PK11_KeyGen(slot, mechanismArray[1], NULL, | |
| 1876 SHA256_LENGTH, pwArg); | |
| 1877 PK11_FreeSlot(slot); | |
| 1878 } | |
| 1879 | |
| 1880 if (aesKeyTmp == NULL || macKeyTmp == NULL) { | |
| 1881 SSL_DBG(("%d: SSL[%s]: Unable to generate session ticket keys.", | |
| 1882 SSL_GETPID(), "unknown")); | |
| 1883 goto loser; | |
| 1884 } | |
| 1885 PORT_Memcpy(keyName, ticketKeyNameSuffix, SESS_TICKET_KEY_VAR_NAME_LEN); | |
| 1886 *aesKey = aesKeyTmp; | |
| 1887 *macKey = macKeyTmp; | |
| 1888 return PR_TRUE; | |
| 1889 | |
| 1890 loser: | |
| 1891 if (aesKeyTmp) | |
| 1892 PK11_FreeSymKey(aesKeyTmp); | |
| 1893 if (macKeyTmp) | |
| 1894 PK11_FreeSymKey(macKeyTmp); | |
| 1895 return PR_FALSE; | |
| 1896 } | |
| 1897 | |
| 1898 static PRBool | |
| 1899 GenerateAndWrapTicketKeys(SECKEYPublicKey *svrPubKey, void *pwArg, | |
| 1900 unsigned char *keyName, PK11SymKey **aesKey, | |
| 1901 PK11SymKey **macKey) | |
| 1902 { | |
| 1903 PK11SymKey *aesKeyTmp = NULL; | |
| 1904 PK11SymKey *macKeyTmp = NULL; | |
| 1905 cacheDesc *cache = &globalCache; | |
| 1906 | |
| 1907 if (!GenerateTicketKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp)) { | |
| 1908 goto loser; | |
| 1909 } | |
| 1910 | |
| 1911 if (cache->cacheMem) { | |
| 1912 /* Export the keys to the shared cache in wrapped form. */ | |
| 1913 if (!WrapTicketKey(svrPubKey, aesKeyTmp, "enc key", cache->ticketEncKey)
) | |
| 1914 goto loser; | |
| 1915 if (!WrapTicketKey(svrPubKey, macKeyTmp, "mac key", cache->ticketMacKey)
) | |
| 1916 goto loser; | |
| 1917 } | |
| 1918 *aesKey = aesKeyTmp; | |
| 1919 *macKey = macKeyTmp; | |
| 1920 return PR_TRUE; | |
| 1921 | |
| 1922 loser: | |
| 1923 if (aesKeyTmp) | |
| 1924 PK11_FreeSymKey(aesKeyTmp); | |
| 1925 if (macKeyTmp) | |
| 1926 PK11_FreeSymKey(macKeyTmp); | |
| 1927 return PR_FALSE; | |
| 1928 } | |
| 1929 | |
| 1930 static PRBool | |
| 1931 UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName, | |
| 1932 PK11SymKey **aesKey, PK11SymKey **macKey) | |
| 1933 { | |
| 1934 SECItem wrappedKey = { siBuffer, NULL, 0 }; | |
| 1935 PK11SymKey *aesKeyTmp = NULL; | |
| 1936 PK11SymKey *macKeyTmp = NULL; | |
| 1937 cacheDesc *cache = &globalCache; | |
| 1938 | |
| 1939 wrappedKey.data = cache->ticketEncKey->bytes; | |
| 1940 wrappedKey.len = cache->ticketEncKey->length; | |
| 1941 PORT_Assert(wrappedKey.len <= sizeof(cache->ticketEncKey->bytes)); | |
| 1942 aesKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey, | |
| 1943 CKM_AES_CBC, CKA_DECRYPT, 0); | |
| 1944 | |
| 1945 wrappedKey.data = cache->ticketMacKey->bytes; | |
| 1946 wrappedKey.len = cache->ticketMacKey->length; | |
| 1947 PORT_Assert(wrappedKey.len <= sizeof(cache->ticketMacKey->bytes)); | |
| 1948 macKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey, | |
| 1949 CKM_SHA256_HMAC, CKA_SIGN, 0); | |
| 1950 | |
| 1951 if (aesKeyTmp == NULL || macKeyTmp == NULL) { | |
| 1952 SSL_DBG(("%d: SSL[%s]: Unable to unwrap session ticket keys.", | |
| 1953 SSL_GETPID(), "unknown")); | |
| 1954 goto loser; | |
| 1955 } | |
| 1956 SSL_DBG(("%d: SSL[%s]: Successfully unwrapped session ticket keys.", | |
| 1957 SSL_GETPID(), "unknown")); | |
| 1958 | |
| 1959 PORT_Memcpy(keyName, cache->ticketKeyNameSuffix, | |
| 1960 SESS_TICKET_KEY_VAR_NAME_LEN); | |
| 1961 *aesKey = aesKeyTmp; | |
| 1962 *macKey = macKeyTmp; | |
| 1963 return PR_TRUE; | |
| 1964 | |
| 1965 loser: | |
| 1966 if (aesKeyTmp) | |
| 1967 PK11_FreeSymKey(aesKeyTmp); | |
| 1968 if (macKeyTmp) | |
| 1969 PK11_FreeSymKey(macKeyTmp); | |
| 1970 return PR_FALSE; | |
| 1971 } | |
| 1972 | |
| 1973 PRBool | |
| 1974 ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey, | |
| 1975 SECKEYPublicKey *svrPubKey, void *pwArg, | |
| 1976 unsigned char *keyName, PK11SymKey **aesKey, | |
| 1977 PK11SymKey **macKey) | |
| 1978 { | |
| 1979 PRUint32 now = 0; | |
| 1980 PRBool rv = PR_FALSE; | |
| 1981 PRBool keysGenerated = PR_FALSE; | |
| 1982 cacheDesc *cache = &globalCache; | |
| 1983 | |
| 1984 if (!cache->cacheMem) { | |
| 1985 /* cache is uninitialized. Generate keys and return them | |
| 1986 * without caching. */ | |
| 1987 return GenerateTicketKeys(pwArg, keyName, aesKey, macKey); | |
| 1988 } | |
| 1989 | |
| 1990 now = LockSidCacheLock(cache->keyCacheLock, now); | |
| 1991 if (!now) | |
| 1992 return rv; | |
| 1993 | |
| 1994 if (!*(cache->ticketKeysValid)) { | |
| 1995 /* Keys do not exist, create them. */ | |
| 1996 if (!GenerateAndWrapTicketKeys(svrPubKey, pwArg, keyName, | |
| 1997 aesKey, macKey)) | |
| 1998 goto loser; | |
| 1999 keysGenerated = PR_TRUE; | |
| 2000 *(cache->ticketKeysValid) = 1; | |
| 2001 } | |
| 2002 | |
| 2003 rv = PR_TRUE; | |
| 2004 | |
| 2005 loser: | |
| 2006 UnlockSidCacheLock(cache->keyCacheLock); | |
| 2007 if (rv && !keysGenerated) | |
| 2008 rv = UnwrapCachedTicketKeys(svrPrivKey, keyName, aesKey, macKey); | |
| 2009 return rv; | |
| 2010 } | |
| 2011 | |
| 2012 PRBool | |
| 2013 ssl_GetSessionTicketKeys(unsigned char *keyName, unsigned char *encKey, | |
| 2014 unsigned char *macKey) | |
| 2015 { | |
| 2016 PRBool rv = PR_FALSE; | |
| 2017 PRUint32 now = 0; | |
| 2018 cacheDesc *cache = &globalCache; | |
| 2019 PRUint8 ticketMacKey[SHA256_LENGTH], ticketEncKey[AES_256_KEY_LENGTH]; | |
| 2020 PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN]; | |
| 2021 PRUint8 *ticketMacKeyPtr, *ticketEncKeyPtr, *ticketKeyNameSuffix; | |
| 2022 PRBool cacheIsEnabled = PR_TRUE; | |
| 2023 | |
| 2024 if (!cache->cacheMem) { /* cache is uninitialized */ | |
| 2025 cacheIsEnabled = PR_FALSE; | |
| 2026 ticketKeyNameSuffix = ticketKeyNameSuffixLocal; | |
| 2027 ticketEncKeyPtr = ticketEncKey; | |
| 2028 ticketMacKeyPtr = ticketMacKey; | |
| 2029 } else { | |
| 2030 /* these values have constant memory locations in the cache. | |
| 2031 * Ok to reference them without holding the lock. */ | |
| 2032 ticketKeyNameSuffix = cache->ticketKeyNameSuffix; | |
| 2033 ticketEncKeyPtr = cache->ticketEncKey->bytes; | |
| 2034 ticketMacKeyPtr = cache->ticketMacKey->bytes; | |
| 2035 } | |
| 2036 | |
| 2037 if (cacheIsEnabled) { | |
| 2038 /* Grab lock if initialized. */ | |
| 2039 now = LockSidCacheLock(cache->keyCacheLock, now); | |
| 2040 if (!now) | |
| 2041 return rv; | |
| 2042 } | |
| 2043 /* Going to regenerate keys on every call if cache was not | |
| 2044 * initialized. */ | |
| 2045 if (!cacheIsEnabled || !*(cache->ticketKeysValid)) { | |
| 2046 if (PK11_GenerateRandom(ticketKeyNameSuffix, | |
| 2047 SESS_TICKET_KEY_VAR_NAME_LEN) != | |
| 2048 SECSuccess) | |
| 2049 goto loser; | |
| 2050 if (PK11_GenerateRandom(ticketEncKeyPtr, | |
| 2051 AES_256_KEY_LENGTH) != SECSuccess) | |
| 2052 goto loser; | |
| 2053 if (PK11_GenerateRandom(ticketMacKeyPtr, | |
| 2054 SHA256_LENGTH) != SECSuccess) | |
| 2055 goto loser; | |
| 2056 if (cacheIsEnabled) { | |
| 2057 *(cache->ticketKeysValid) = 1; | |
| 2058 } | |
| 2059 } | |
| 2060 | |
| 2061 rv = PR_TRUE; | |
| 2062 | |
| 2063 loser: | |
| 2064 if (cacheIsEnabled) { | |
| 2065 UnlockSidCacheLock(cache->keyCacheLock); | |
| 2066 } | |
| 2067 if (rv) { | |
| 2068 PORT_Memcpy(keyName, ticketKeyNameSuffix, | |
| 2069 SESS_TICKET_KEY_VAR_NAME_LEN); | |
| 2070 PORT_Memcpy(encKey, ticketEncKeyPtr, AES_256_KEY_LENGTH); | |
| 2071 PORT_Memcpy(macKey, ticketMacKeyPtr, SHA256_LENGTH); | |
| 2072 } | |
| 2073 return rv; | |
| 2074 } | |
| 2075 | |
| 2076 /* The caller passes in the new value it wants | |
| 2077 * to set. This code tests the wrapped sym key entry in the shared memory. | |
| 2078 * If it is uninitialized, this function writes the caller's value into | |
| 2079 * the disk entry, and returns false. | |
| 2080 * Otherwise, it overwrites the caller's wswk with the value obtained from | |
| 2081 * the disk, and returns PR_TRUE. | |
| 2082 * This is all done while holding the locks/mutexes necessary to make | |
| 2083 * the operation atomic. | |
| 2084 */ | |
| 2085 PRBool | |
| 2086 ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk) | |
| 2087 { | |
| 2088 cacheDesc *cache = &globalCache; | |
| 2089 PRBool rv = PR_FALSE; | |
| 2090 SSL3KEAType exchKeyType = wswk->exchKeyType; | |
| 2091 /* type of keys used to wrap SymWrapKey*/ | |
| 2092 PRInt32 symWrapMechIndex = wswk->symWrapMechIndex; | |
| 2093 PRUint32 ndx; | |
| 2094 PRUint32 now = 0; | |
| 2095 SSLWrappedSymWrappingKey myWswk; | |
| 2096 | |
| 2097 if (!cache->cacheMem) { /* cache is uninitialized */ | |
| 2098 PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED); | |
| 2099 return 0; | |
| 2100 } | |
| 2101 | |
| 2102 PORT_Assert((unsigned)exchKeyType < kt_kea_size); | |
| 2103 if ((unsigned)exchKeyType >= kt_kea_size) | |
| 2104 return 0; | |
| 2105 | |
| 2106 PORT_Assert((unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS); | |
| 2107 if ((unsigned)symWrapMechIndex >= SSL_NUM_WRAP_MECHS) | |
| 2108 return 0; | |
| 2109 | |
| 2110 ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex; | |
| 2111 PORT_Memset(&myWswk, 0, sizeof myWswk); /* eliminate UMRs. */ | |
| 2112 | |
| 2113 now = LockSidCacheLock(cache->keyCacheLock, now); | |
| 2114 if (now) { | |
| 2115 rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->exchKeyType, | |
| 2116 &myWswk, cache, now); | |
| 2117 if (rv) { | |
| 2118 /* we found it on disk, copy it out to the caller. */ | |
| 2119 PORT_Memcpy(wswk, &myWswk, sizeof *wswk); | |
| 2120 } else { | |
| 2121 /* Wasn't on disk, and we're still holding the lock, so write it. */ | |
| 2122 cache->keyCacheData[ndx] = *wswk; | |
| 2123 } | |
| 2124 UnlockSidCacheLock(cache->keyCacheLock); | |
| 2125 } | |
| 2126 return rv; | |
| 2127 } | |
| 2128 | |
| 2129 #else /* MAC version or other platform */ | |
| 2130 | |
| 2131 #include "seccomon.h" | |
| 2132 #include "cert.h" | |
| 2133 #include "ssl.h" | |
| 2134 #include "sslimpl.h" | |
| 2135 | |
| 2136 SECStatus | |
| 2137 SSL_ConfigServerSessionIDCache(int maxCacheEntries, | |
| 2138 PRUint32 ssl2_timeout, | |
| 2139 PRUint32 ssl3_timeout, | |
| 2140 const char *directory) | |
| 2141 { | |
| 2142 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigServe
rSessionIDCache)"); | |
| 2143 return SECFailure; | |
| 2144 } | |
| 2145 | |
| 2146 SECStatus | |
| 2147 SSL_ConfigMPServerSIDCache(int maxCacheEntries, | |
| 2148 PRUint32 ssl2_timeout, | |
| 2149 PRUint32 ssl3_timeout, | |
| 2150 const char *directory) | |
| 2151 { | |
| 2152 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigMPSer
verSIDCache)"); | |
| 2153 return SECFailure; | |
| 2154 } | |
| 2155 | |
| 2156 SECStatus | |
| 2157 SSL_InheritMPServerSIDCache(const char *envString) | |
| 2158 { | |
| 2159 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_InheritMPSe
rverSIDCache)"); | |
| 2160 return SECFailure; | |
| 2161 } | |
| 2162 | |
| 2163 PRBool | |
| 2164 ssl_GetWrappingKey(PRInt32 symWrapMechIndex, | |
| 2165 SSL3KEAType exchKeyType, | |
| 2166 SSLWrappedSymWrappingKey *wswk) | |
| 2167 { | |
| 2168 PRBool rv = PR_FALSE; | |
| 2169 PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrapping
Key)"); | |
| 2170 return rv; | |
| 2171 } | |
| 2172 | |
| 2173 /* This is a kind of test-and-set. The caller passes in the new value it wants | |
| 2174 * to set. This code tests the wrapped sym key entry in the shared memory. | |
| 2175 * If it is uninitialized, this function writes the caller's value into | |
| 2176 * the disk entry, and returns false. | |
| 2177 * Otherwise, it overwrites the caller's wswk with the value obtained from | |
| 2178 * the disk, and returns PR_TRUE. | |
| 2179 * This is all done while holding the locks/mutexes necessary to make | |
| 2180 * the operation atomic. | |
| 2181 */ | |
| 2182 PRBool | |
| 2183 ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk) | |
| 2184 { | |
| 2185 PRBool rv = PR_FALSE; | |
| 2186 PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrapping
Key)"); | |
| 2187 return rv; | |
| 2188 } | |
| 2189 | |
| 2190 PRUint32 | |
| 2191 SSL_GetMaxServerCacheLocks(void) | |
| 2192 { | |
| 2193 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_GetMaxServe
rCacheLocks)"); | |
| 2194 return -1; | |
| 2195 } | |
| 2196 | |
| 2197 SECStatus | |
| 2198 SSL_SetMaxServerCacheLocks(PRUint32 maxLocks) | |
| 2199 { | |
| 2200 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_SetMaxServe
rCacheLocks)"); | |
| 2201 return SECFailure; | |
| 2202 } | |
| 2203 | |
| 2204 #endif /* XP_UNIX || XP_WIN32 */ | |
| OLD | NEW |