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