Revert "Merged all Chromoting Host code into remoting_core.dll (Windows)."
[chromium-blink-merge.git] / net / third_party / nss / ssl / sslsnce.c
blobe132de9a547ceb1b378cff7ae0b7462dd9d51c5a
1 /* This file implements the SERVER Session ID cache.
2 * NOTE: The contents of this file are NOT used by the client.
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 /* $Id: sslsnce.c,v 1.63 2012/06/14 19:04:59 wtc%google.com Exp $ */
9 /* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server
10 * cache sids!
12 * About record locking among different server processes:
14 * All processes that are part of the same conceptual server (serving on
15 * the same address and port) MUST share a common SSL session cache.
16 * This code makes the content of the shared cache accessible to all
17 * processes on the same "server". This code works on Unix and Win32 only.
19 * We use NSPR anonymous shared memory and move data to & from shared memory.
20 * We must do explicit locking of the records for all reads and writes.
21 * The set of Cache entries are divided up into "sets" of 128 entries.
22 * Each set is protected by a lock. There may be one or more sets protected
23 * by each lock. That is, locks to sets are 1:N.
24 * There is one lock for the entire cert cache.
25 * There is one lock for the set of wrapped sym wrap keys.
27 * The anonymous shared memory is laid out as if it were declared like this:
29 * struct {
30 * cacheDescriptor desc;
31 * sidCacheLock sidCacheLocks[ numSIDCacheLocks];
32 * sidCacheLock keyCacheLock;
33 * sidCacheLock certCacheLock;
34 * sidCacheSet sidCacheSets[ numSIDCacheSets ];
35 * sidCacheEntry sidCacheData[ numSIDCacheEntries];
36 * certCacheEntry certCacheData[numCertCacheEntries];
37 * SSLWrappedSymWrappingKey keyCacheData[kt_kea_size][SSL_NUM_WRAP_MECHS];
38 * uint8 keyNameSuffix[SESS_TICKET_KEY_VAR_NAME_LEN]
39 * encKeyCacheEntry ticketEncKey; // Wrapped in non-bypass mode
40 * encKeyCacheEntry ticketMacKey; // Wrapped in non-bypass mode
41 * PRBool ticketKeysValid;
42 * sidCacheLock srvNameCacheLock;
43 * srvNameCacheEntry srvNameData[ numSrvNameCacheEntries ];
44 * } cacheMemCacheData;
46 #include "seccomon.h"
48 #if defined(XP_UNIX) || defined(XP_WIN32) || defined (XP_OS2) || defined(XP_BEOS)
50 #include "cert.h"
51 #include "ssl.h"
52 #include "sslimpl.h"
53 #include "sslproto.h"
54 #include "pk11func.h"
55 #include "base64.h"
56 #include "keyhi.h"
57 #ifdef NO_PKCS11_BYPASS
58 #include "blapit.h"
59 #include "sechash.h"
60 #else
61 #include "blapi.h"
62 #endif
64 #include <stdio.h>
66 #if defined(XP_UNIX) || defined(XP_BEOS)
68 #include <syslog.h>
69 #include <fcntl.h>
70 #include <unistd.h>
71 #include <errno.h>
72 #include <signal.h>
73 #include "unix_err.h"
75 #else
77 #ifdef XP_WIN32
78 #include <wtypes.h>
79 #include "win32err.h"
80 #endif
82 #endif
83 #include <sys/types.h>
85 #define SET_ERROR_CODE /* reminder */
87 #include "nspr.h"
88 #include "sslmutex.h"
91 ** Format of a cache entry in the shared memory.
92 */
93 struct sidCacheEntryStr {
94 /* 16 */ PRIPv6Addr addr; /* client's IP address */
95 /* 4 */ PRUint32 creationTime;
96 /* 4 */ PRUint32 lastAccessTime;
97 /* 4 */ PRUint32 expirationTime;
98 /* 2 */ PRUint16 version;
99 /* 1 */ PRUint8 valid;
100 /* 1 */ PRUint8 sessionIDLength;
101 /* 32 */ PRUint8 sessionID[SSL3_SESSIONID_BYTES];
102 /* 2 */ PRUint16 authAlgorithm;
103 /* 2 */ PRUint16 authKeyBits;
104 /* 2 */ PRUint16 keaType;
105 /* 2 */ PRUint16 keaKeyBits;
106 /* 72 - common header total */
108 union {
109 struct {
110 /* 64 */ PRUint8 masterKey[SSL_MAX_MASTER_KEY_BYTES];
111 /* 32 */ PRUint8 cipherArg[SSL_MAX_CYPHER_ARG_BYTES];
113 /* 1 */ PRUint8 cipherType;
114 /* 1 */ PRUint8 masterKeyLen;
115 /* 1 */ PRUint8 keyBits;
116 /* 1 */ PRUint8 secretKeyBits;
117 /* 1 */ PRUint8 cipherArgLen;
118 /*101 */} ssl2;
120 struct {
121 /* 2 */ ssl3CipherSuite cipherSuite;
122 /* 2 */ PRUint16 compression; /* SSLCompressionMethod */
124 /* 52 */ ssl3SidKeys keys; /* keys, wrapped as needed. */
126 /* 4 */ PRUint32 masterWrapMech;
127 /* 4 */ SSL3KEAType exchKeyType;
128 /* 4 */ PRInt32 certIndex;
129 /* 4 */ PRInt32 srvNameIndex;
130 /* 32 */ PRUint8 srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */
131 /*104 */} ssl3;
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;
138 typedef struct sidCacheEntryStr sidCacheEntry;
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;
149 struct sidCacheLockStr {
150 PRUint32 timeStamp;
151 sslMutex mutex;
152 sslPID pid;
154 typedef struct sidCacheLockStr sidCacheLock;
156 struct sidCacheSetStr {
157 PRIntn next;
159 typedef struct sidCacheSetStr sidCacheSet;
161 struct encKeyCacheEntryStr {
162 PRUint8 bytes[512];
163 PRInt32 length;
165 typedef struct encKeyCacheEntryStr encKeyCacheEntry;
167 #define SSL_MAX_DNS_HOST_NAME 1024
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 */
176 typedef struct srvNameCacheEntryStr srvNameCacheEntry;
179 struct cacheDescStr {
181 PRUint32 cacheMemSize;
183 PRUint32 numSIDCacheLocks;
184 PRUint32 numSIDCacheSets;
185 PRUint32 numSIDCacheSetsPerLock;
187 PRUint32 numSIDCacheEntries;
188 PRUint32 sidCacheSize;
190 PRUint32 numCertCacheEntries;
191 PRUint32 certCacheSize;
193 PRUint32 numKeyCacheEntries;
194 PRUint32 keyCacheSize;
196 PRUint32 numSrvNameCacheEntries;
197 PRUint32 srvNameCacheSize;
199 PRUint32 ssl2Timeout;
200 PRUint32 ssl3Timeout;
202 PRUint32 numSIDCacheLocksInitialized;
204 /* These values are volatile, and are accessed through sharedCache-> */
205 PRUint32 nextCertCacheEntry; /* certCacheLock protects */
206 PRBool stopPolling;
207 PRBool everInherited;
209 /* The private copies of these values are pointers into shared mem */
210 /* The copies of these values in shared memory are merely offsets */
211 sidCacheLock * sidCacheLocks;
212 sidCacheLock * keyCacheLock;
213 sidCacheLock * certCacheLock;
214 sidCacheLock * srvNameCacheLock;
215 sidCacheSet * sidCacheSets;
216 sidCacheEntry * sidCacheData;
217 certCacheEntry * certCacheData;
218 SSLWrappedSymWrappingKey * keyCacheData;
219 uint8 * ticketKeyNameSuffix;
220 encKeyCacheEntry * ticketEncKey;
221 encKeyCacheEntry * ticketMacKey;
222 PRUint32 * ticketKeysValid;
223 srvNameCacheEntry * srvNameCacheData;
225 /* Only the private copies of these pointers are valid */
226 char * cacheMem;
227 struct cacheDescStr * sharedCache; /* shared copy of this struct */
228 PRFileMap * cacheMemMap;
229 PRThread * poller;
230 PRUint32 mutexTimeout;
231 PRBool shared;
233 typedef struct cacheDescStr cacheDesc;
235 static cacheDesc globalCache;
237 static const char envVarName[] = { SSL_ENV_VAR_NAME };
239 static PRBool isMultiProcess = PR_FALSE;
242 #define DEF_SID_CACHE_ENTRIES 10000
243 #define DEF_CERT_CACHE_ENTRIES 250
244 #define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */
245 #define DEF_KEY_CACHE_ENTRIES 250
246 #define DEF_NAME_CACHE_ENTRIES 1000
248 #define SID_CACHE_ENTRIES_PER_SET 128
249 #define SID_ALIGNMENT 16
251 #define DEF_SSL2_TIMEOUT 100 /* seconds */
252 #define MAX_SSL2_TIMEOUT 100 /* seconds */
253 #define MIN_SSL2_TIMEOUT 5 /* seconds */
255 #define DEF_SSL3_TIMEOUT 86400L /* 24 hours */
256 #define MAX_SSL3_TIMEOUT 86400L /* 24 hours */
257 #define MIN_SSL3_TIMEOUT 5 /* seconds */
259 #if defined(AIX) || defined(LINUX) || defined(NETBSD) || defined(OPENBSD)
260 #define MAX_SID_CACHE_LOCKS 8 /* two FDs per lock */
261 #elif defined(OSF1)
262 #define MAX_SID_CACHE_LOCKS 16 /* one FD per lock */
263 #else
264 #define MAX_SID_CACHE_LOCKS 256
265 #endif
267 #define SID_HOWMANY(val, size) (((val) + ((size) - 1)) / (size))
268 #define SID_ROUNDUP(val, size) ((size) * SID_HOWMANY((val), (size)))
271 static sslPID myPid;
272 static PRUint32 ssl_max_sid_cache_locks = MAX_SID_CACHE_LOCKS;
274 /* forward static function declarations */
275 static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s,
276 unsigned nl);
277 static SECStatus LaunchLockPoller(cacheDesc *cache);
278 static SECStatus StopLockPoller(cacheDesc *cache);
281 struct inheritanceStr {
282 PRUint32 cacheMemSize;
283 PRUint32 fmStrLen;
286 typedef struct inheritanceStr inheritance;
288 #if defined(_WIN32) || defined(XP_OS2)
290 #define DEFAULT_CACHE_DIRECTORY "\\temp"
292 #endif /* _win32 */
294 #if defined(XP_UNIX) || defined(XP_BEOS)
296 #define DEFAULT_CACHE_DIRECTORY "/tmp"
298 #endif /* XP_UNIX || XP_BEOS */
301 /************************************************************************/
303 static PRUint32
304 LockSidCacheLock(sidCacheLock *lock, PRUint32 now)
306 SECStatus rv = sslMutex_Lock(&lock->mutex);
307 if (rv != SECSuccess)
308 return 0;
309 if (!now)
310 now = ssl_Time();
311 lock->timeStamp = now;
312 lock->pid = myPid;
313 return now;
316 static SECStatus
317 UnlockSidCacheLock(sidCacheLock *lock)
319 SECStatus rv;
321 lock->pid = 0;
322 rv = sslMutex_Unlock(&lock->mutex);
323 return rv;
326 /* returns the value of ssl_Time on success, zero on failure. */
327 static PRUint32
328 LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now)
330 PRUint32 lockNum = set % cache->numSIDCacheLocks;
331 sidCacheLock * lock = cache->sidCacheLocks + lockNum;
333 return LockSidCacheLock(lock, now);
336 static SECStatus
337 UnlockSet(cacheDesc *cache, PRUint32 set)
339 PRUint32 lockNum = set % cache->numSIDCacheLocks;
340 sidCacheLock * lock = cache->sidCacheLocks + lockNum;
342 return UnlockSidCacheLock(lock);
345 /************************************************************************/
348 /* Put a certificate in the cache. Update the cert index in the sce.
350 static PRUint32
351 CacheCert(cacheDesc * cache, CERTCertificate *cert, sidCacheEntry *sce)
353 PRUint32 now;
354 certCacheEntry cce;
356 if ((cert->derCert.len > SSL_MAX_CACHED_CERT_LEN) ||
357 (cert->derCert.len <= 0) ||
358 (cert->derCert.data == NULL)) {
359 PORT_SetError(SEC_ERROR_INVALID_ARGS);
360 return 0;
363 cce.sessionIDLength = sce->sessionIDLength;
364 PORT_Memcpy(cce.sessionID, sce->sessionID, cce.sessionIDLength);
366 cce.certLength = cert->derCert.len;
367 PORT_Memcpy(cce.cert, cert->derCert.data, cce.certLength);
369 /* get lock on cert cache */
370 now = LockSidCacheLock(cache->certCacheLock, 0);
371 if (now) {
373 /* Find where to place the next cert cache entry. */
374 cacheDesc * sharedCache = cache->sharedCache;
375 PRUint32 ndx = sharedCache->nextCertCacheEntry;
377 /* write the entry */
378 cache->certCacheData[ndx] = cce;
380 /* remember where we put it. */
381 sce->u.ssl3.certIndex = ndx;
383 /* update the "next" cache entry index */
384 sharedCache->nextCertCacheEntry =
385 (ndx + 1) % cache->numCertCacheEntries;
387 UnlockSidCacheLock(cache->certCacheLock);
389 return now;
393 /* Server configuration hash tables need to account the SECITEM.type
394 * field as well. These functions accomplish that. */
395 static PLHashNumber
396 Get32BitNameHash(const SECItem *name)
398 PLHashNumber rv = SECITEM_Hash(name);
400 PRUint8 *rvc = (PRUint8 *)&rv;
401 rvc[ name->len % sizeof(rv) ] ^= name->type;
403 return rv;
406 /* Put a name in the cache. Update the cert index in the sce.
408 static PRUint32
409 CacheSrvName(cacheDesc * cache, SECItem *name, sidCacheEntry *sce)
411 PRUint32 now;
412 PRUint32 ndx;
413 srvNameCacheEntry snce;
415 if (!name || name->len <= 0 ||
416 name->len > SSL_MAX_DNS_HOST_NAME) {
417 PORT_SetError(SEC_ERROR_INVALID_ARGS);
418 return 0;
421 snce.type = name->type;
422 snce.nameLen = name->len;
423 PORT_Memcpy(snce.name, name->data, snce.nameLen);
424 #ifdef NO_PKCS11_BYPASS
425 HASH_HashBuf(HASH_AlgSHA256, snce.nameHash, name->data, name->len);
426 #else
427 SHA256_HashBuf(snce.nameHash, (unsigned char*)name->data,
428 name->len);
429 #endif
430 /* get index of the next name */
431 ndx = Get32BitNameHash(name);
432 /* get lock on cert cache */
433 now = LockSidCacheLock(cache->srvNameCacheLock, 0);
434 if (now) {
435 if (cache->numSrvNameCacheEntries > 0) {
436 /* Fit the index into array */
437 ndx %= cache->numSrvNameCacheEntries;
438 /* write the entry */
439 cache->srvNameCacheData[ndx] = snce;
440 /* remember where we put it. */
441 sce->u.ssl3.srvNameIndex = ndx;
442 /* Copy hash into sid hash */
443 PORT_Memcpy(sce->u.ssl3.srvNameHash, snce.nameHash, SHA256_LENGTH);
445 UnlockSidCacheLock(cache->srvNameCacheLock);
447 return now;
451 ** Convert local SID to shared memory one
453 static void
454 ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
456 to->valid = 1;
457 to->version = from->version;
458 to->addr = from->addr;
459 to->creationTime = from->creationTime;
460 to->lastAccessTime = from->lastAccessTime;
461 to->expirationTime = from->expirationTime;
462 to->authAlgorithm = from->authAlgorithm;
463 to->authKeyBits = from->authKeyBits;
464 to->keaType = from->keaType;
465 to->keaKeyBits = from->keaKeyBits;
467 if (from->version < SSL_LIBRARY_VERSION_3_0) {
468 if ((from->u.ssl2.masterKey.len > SSL_MAX_MASTER_KEY_BYTES) ||
469 (from->u.ssl2.cipherArg.len > SSL_MAX_CYPHER_ARG_BYTES)) {
470 SSL_DBG(("%d: SSL: masterKeyLen=%d cipherArgLen=%d",
471 myPid, from->u.ssl2.masterKey.len,
472 from->u.ssl2.cipherArg.len));
473 to->valid = 0;
474 return;
477 to->u.ssl2.cipherType = from->u.ssl2.cipherType;
478 to->u.ssl2.masterKeyLen = from->u.ssl2.masterKey.len;
479 to->u.ssl2.cipherArgLen = from->u.ssl2.cipherArg.len;
480 to->u.ssl2.keyBits = from->u.ssl2.keyBits;
481 to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
482 to->sessionIDLength = SSL2_SESSIONID_BYTES;
483 PORT_Memcpy(to->sessionID, from->u.ssl2.sessionID, SSL2_SESSIONID_BYTES);
484 PORT_Memcpy(to->u.ssl2.masterKey, from->u.ssl2.masterKey.data,
485 from->u.ssl2.masterKey.len);
486 PORT_Memcpy(to->u.ssl2.cipherArg, from->u.ssl2.cipherArg.data,
487 from->u.ssl2.cipherArg.len);
488 #ifdef DEBUG
489 PORT_Memset(to->u.ssl2.masterKey+from->u.ssl2.masterKey.len, 0,
490 sizeof(to->u.ssl2.masterKey) - from->u.ssl2.masterKey.len);
491 PORT_Memset(to->u.ssl2.cipherArg+from->u.ssl2.cipherArg.len, 0,
492 sizeof(to->u.ssl2.cipherArg) - from->u.ssl2.cipherArg.len);
493 #endif
494 SSL_TRC(8, ("%d: SSL: ConvertSID: masterKeyLen=%d cipherArgLen=%d "
495 "time=%d addr=0x%08x%08x%08x%08x cipherType=%d", myPid,
496 to->u.ssl2.masterKeyLen, to->u.ssl2.cipherArgLen,
497 to->creationTime, to->addr.pr_s6_addr32[0],
498 to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
499 to->addr.pr_s6_addr32[3], to->u.ssl2.cipherType));
500 } else {
501 /* This is an SSL v3 session */
503 to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite;
504 to->u.ssl3.compression = (uint16)from->u.ssl3.compression;
505 to->u.ssl3.keys = from->u.ssl3.keys;
506 to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech;
507 to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType;
508 to->sessionIDLength = from->u.ssl3.sessionIDLength;
509 to->u.ssl3.certIndex = -1;
510 to->u.ssl3.srvNameIndex = -1;
512 PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID,
513 to->sessionIDLength);
515 SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x "
516 "cipherSuite=%d",
517 myPid, to->creationTime, to->addr.pr_s6_addr32[0],
518 to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
519 to->addr.pr_s6_addr32[3], to->u.ssl3.cipherSuite));
524 ** Convert shared memory cache-entry to local memory based one
525 ** This is only called from ServerSessionIDLookup().
526 ** Caller must hold cache lock when calling this.
528 static sslSessionID *
529 ConvertToSID(sidCacheEntry * from,
530 certCacheEntry * pcce,
531 srvNameCacheEntry *psnce,
532 CERTCertDBHandle * dbHandle)
534 sslSessionID *to;
535 uint16 version = from->version;
537 to = PORT_ZNew(sslSessionID);
538 if (!to) {
539 return 0;
542 if (version < SSL_LIBRARY_VERSION_3_0) {
543 /* This is an SSL v2 session */
544 to->u.ssl2.masterKey.data =
545 (unsigned char*) PORT_Alloc(from->u.ssl2.masterKeyLen);
546 if (!to->u.ssl2.masterKey.data) {
547 goto loser;
549 if (from->u.ssl2.cipherArgLen) {
550 to->u.ssl2.cipherArg.data =
551 (unsigned char*)PORT_Alloc(from->u.ssl2.cipherArgLen);
552 if (!to->u.ssl2.cipherArg.data) {
553 goto loser;
555 PORT_Memcpy(to->u.ssl2.cipherArg.data, from->u.ssl2.cipherArg,
556 from->u.ssl2.cipherArgLen);
559 to->u.ssl2.cipherType = from->u.ssl2.cipherType;
560 to->u.ssl2.masterKey.len = from->u.ssl2.masterKeyLen;
561 to->u.ssl2.cipherArg.len = from->u.ssl2.cipherArgLen;
562 to->u.ssl2.keyBits = from->u.ssl2.keyBits;
563 to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
564 /* to->sessionIDLength = SSL2_SESSIONID_BYTES; */
565 PORT_Memcpy(to->u.ssl2.sessionID, from->sessionID, SSL2_SESSIONID_BYTES);
566 PORT_Memcpy(to->u.ssl2.masterKey.data, from->u.ssl2.masterKey,
567 from->u.ssl2.masterKeyLen);
569 SSL_TRC(8, ("%d: SSL: ConvertToSID: masterKeyLen=%d cipherArgLen=%d "
570 "time=%d addr=0x%08x%08x%08x%08x cipherType=%d",
571 myPid, to->u.ssl2.masterKey.len,
572 to->u.ssl2.cipherArg.len, to->creationTime,
573 to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1],
574 to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3],
575 to->u.ssl2.cipherType));
576 } else {
577 /* This is an SSL v3 session */
579 to->u.ssl3.sessionIDLength = from->sessionIDLength;
580 to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite;
581 to->u.ssl3.compression = (SSLCompressionMethod)from->u.ssl3.compression;
582 to->u.ssl3.keys = from->u.ssl3.keys;
583 to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech;
584 to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType;
585 if (from->u.ssl3.srvNameIndex != -1 && psnce) {
586 SECItem name;
587 SECStatus rv;
588 name.type = psnce->type;
589 name.len = psnce->nameLen;
590 name.data = psnce->name;
591 rv = SECITEM_CopyItem(NULL, &to->u.ssl3.srvName, &name);
592 if (rv != SECSuccess) {
593 goto loser;
597 PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength);
599 /* the portions of the SID that are only restored on the client
600 * are set to invalid values on the server.
602 to->u.ssl3.clientWriteKey = NULL;
603 to->u.ssl3.serverWriteKey = NULL;
605 to->urlSvrName = NULL;
607 to->u.ssl3.masterModuleID = (SECMODModuleID)-1; /* invalid value */
608 to->u.ssl3.masterSlotID = (CK_SLOT_ID)-1; /* invalid value */
609 to->u.ssl3.masterWrapIndex = 0;
610 to->u.ssl3.masterWrapSeries = 0;
611 to->u.ssl3.masterValid = PR_FALSE;
613 to->u.ssl3.clAuthModuleID = (SECMODModuleID)-1; /* invalid value */
614 to->u.ssl3.clAuthSlotID = (CK_SLOT_ID)-1; /* invalid value */
615 to->u.ssl3.clAuthSeries = 0;
616 to->u.ssl3.clAuthValid = PR_FALSE;
618 if (from->u.ssl3.certIndex != -1 && pcce) {
619 SECItem derCert;
621 derCert.len = pcce->certLength;
622 derCert.data = pcce->cert;
624 to->peerCert = CERT_NewTempCertificate(dbHandle, &derCert, NULL,
625 PR_FALSE, PR_TRUE);
626 if (to->peerCert == NULL)
627 goto loser;
631 to->version = from->version;
632 to->creationTime = from->creationTime;
633 to->lastAccessTime = from->lastAccessTime;
634 to->expirationTime = from->expirationTime;
635 to->cached = in_server_cache;
636 to->addr = from->addr;
637 to->references = 1;
638 to->authAlgorithm = from->authAlgorithm;
639 to->authKeyBits = from->authKeyBits;
640 to->keaType = from->keaType;
641 to->keaKeyBits = from->keaKeyBits;
643 return to;
645 loser:
646 if (to) {
647 if (version < SSL_LIBRARY_VERSION_3_0) {
648 if (to->u.ssl2.masterKey.data)
649 PORT_Free(to->u.ssl2.masterKey.data);
650 if (to->u.ssl2.cipherArg.data)
651 PORT_Free(to->u.ssl2.cipherArg.data);
652 } else {
653 SECITEM_FreeItem(&to->u.ssl3.srvName, PR_FALSE);
655 PORT_Free(to);
657 return NULL;
663 ** Perform some mumbo jumbo on the ip-address and the session-id value to
664 ** compute a hash value.
666 static PRUint32
667 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl)
669 PRUint32 rv;
670 PRUint32 x[8];
672 memset(x, 0, sizeof x);
673 if (nl > sizeof x)
674 nl = sizeof x;
675 memcpy(x, s, nl);
677 rv = (addr->pr_s6_addr32[0] ^ addr->pr_s6_addr32[1] ^
678 addr->pr_s6_addr32[2] ^ addr->pr_s6_addr32[3] ^
679 x[0] ^ x[1] ^ x[2] ^ x[3] ^ x[4] ^ x[5] ^ x[6] ^ x[7])
680 % cache->numSIDCacheSets;
681 return rv;
687 ** Look something up in the cache. This will invalidate old entries
688 ** in the process. Caller has locked the cache set!
689 ** Returns PR_TRUE if found a valid match. PR_FALSE otherwise.
691 static sidCacheEntry *
692 FindSID(cacheDesc *cache, PRUint32 setNum, PRUint32 now,
693 const PRIPv6Addr *addr, unsigned char *sessionID,
694 unsigned sessionIDLength)
696 PRUint32 ndx = cache->sidCacheSets[setNum].next;
697 int i;
699 sidCacheEntry * set = cache->sidCacheData +
700 (setNum * SID_CACHE_ENTRIES_PER_SET);
702 for (i = SID_CACHE_ENTRIES_PER_SET; i > 0; --i) {
703 sidCacheEntry * sce;
705 ndx = (ndx - 1) % SID_CACHE_ENTRIES_PER_SET;
706 sce = set + ndx;
708 if (!sce->valid)
709 continue;
711 if (now > sce->expirationTime) {
712 /* SessionID has timed out. Invalidate the entry. */
713 SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x "
714 "time+=%x",
715 myPid, sce->addr.pr_s6_addr32[0],
716 sce->addr.pr_s6_addr32[1], sce->addr.pr_s6_addr32[2],
717 sce->addr.pr_s6_addr32[3], now,
718 sce->expirationTime ));
719 sce->valid = 0;
720 continue;
724 ** Next, examine specific session-id/addr data to see if the cache
725 ** entry matches our addr+session-id value
727 if (sessionIDLength == sce->sessionIDLength &&
728 !memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) &&
729 !memcmp(sce->sessionID, sessionID, sessionIDLength)) {
730 /* Found it */
731 return sce;
735 PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
736 return NULL;
739 /************************************************************************/
741 /* This is the primary function for finding entries in the server's sid cache.
742 * Although it is static, this function is called via the global function
743 * pointer ssl_sid_lookup.
745 static sslSessionID *
746 ServerSessionIDLookup(const PRIPv6Addr *addr,
747 unsigned char *sessionID,
748 unsigned int sessionIDLength,
749 CERTCertDBHandle * dbHandle)
751 sslSessionID * sid = 0;
752 sidCacheEntry * psce;
753 certCacheEntry *pcce = 0;
754 srvNameCacheEntry *psnce = 0;
755 cacheDesc * cache = &globalCache;
756 PRUint32 now;
757 PRUint32 set;
758 PRInt32 cndx;
759 sidCacheEntry sce;
760 certCacheEntry cce;
761 srvNameCacheEntry snce;
763 set = SIDindex(cache, addr, sessionID, sessionIDLength);
764 now = LockSet(cache, set, 0);
765 if (!now)
766 return NULL;
768 psce = FindSID(cache, set, now, addr, sessionID, sessionIDLength);
769 if (psce) {
770 if (psce->version >= SSL_LIBRARY_VERSION_3_0) {
771 if ((cndx = psce->u.ssl3.certIndex) != -1) {
773 PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now);
774 if (gotLock) {
775 pcce = &cache->certCacheData[cndx];
777 /* See if the cert's session ID matches the sce cache. */
778 if ((pcce->sessionIDLength == psce->sessionIDLength) &&
779 !PORT_Memcmp(pcce->sessionID, psce->sessionID,
780 pcce->sessionIDLength)) {
781 cce = *pcce;
782 } else {
783 /* The cert doesen't match the SID cache entry,
784 ** so invalidate the SID cache entry.
786 psce->valid = 0;
787 psce = 0;
788 pcce = 0;
790 UnlockSidCacheLock(cache->certCacheLock);
791 } else {
792 /* what the ??. Didn't get the cert cache lock.
793 ** Don't invalidate the SID cache entry, but don't find it.
795 PORT_Assert(!("Didn't get cert Cache Lock!"));
796 psce = 0;
797 pcce = 0;
800 if (psce && ((cndx = psce->u.ssl3.srvNameIndex) != -1)) {
801 PRUint32 gotLock = LockSidCacheLock(cache->srvNameCacheLock,
802 now);
803 if (gotLock) {
804 psnce = &cache->srvNameCacheData[cndx];
806 if (!PORT_Memcmp(psnce->nameHash, psce->u.ssl3.srvNameHash,
807 SHA256_LENGTH)) {
808 snce = *psnce;
809 } else {
810 /* The name doesen't match the SID cache entry,
811 ** so invalidate the SID cache entry.
813 psce->valid = 0;
814 psce = 0;
815 psnce = 0;
817 UnlockSidCacheLock(cache->srvNameCacheLock);
818 } else {
819 /* what the ??. Didn't get the cert cache lock.
820 ** Don't invalidate the SID cache entry, but don't find it.
822 PORT_Assert(!("Didn't get name Cache Lock!"));
823 psce = 0;
824 psnce = 0;
829 if (psce) {
830 psce->lastAccessTime = now;
831 sce = *psce; /* grab a copy while holding the lock */
834 UnlockSet(cache, set);
835 if (psce) {
836 /* sce conains a copy of the cache entry.
837 ** Convert shared memory format to local format
839 sid = ConvertToSID(&sce, pcce ? &cce : 0, psnce ? &snce : 0, dbHandle);
841 return sid;
845 ** Place a sid into the cache, if it isn't already there.
847 static void
848 ServerSessionIDCache(sslSessionID *sid)
850 sidCacheEntry sce;
851 PRUint32 now = 0;
852 uint16 version = sid->version;
853 cacheDesc * cache = &globalCache;
855 if ((version >= SSL_LIBRARY_VERSION_3_0) &&
856 (sid->u.ssl3.sessionIDLength == 0)) {
857 return;
860 if (sid->cached == never_cached || sid->cached == invalid_cache) {
861 PRUint32 set;
863 PORT_Assert(sid->creationTime != 0);
864 if (!sid->creationTime)
865 sid->lastAccessTime = sid->creationTime = ssl_Time();
866 if (version < SSL_LIBRARY_VERSION_3_0) {
867 /* override caller's expiration time, which uses client timeout
868 * duration, not server timeout duration.
870 sid->expirationTime = sid->creationTime + cache->ssl2Timeout;
871 SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
872 "cipher=%d", myPid, sid->cached,
873 sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
874 sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
875 sid->creationTime, sid->u.ssl2.cipherType));
876 PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID,
877 SSL2_SESSIONID_BYTES));
878 PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
879 sid->u.ssl2.masterKey.len));
880 PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
881 sid->u.ssl2.cipherArg.len));
883 } else {
884 /* override caller's expiration time, which uses client timeout
885 * duration, not server timeout duration.
887 sid->expirationTime = sid->creationTime + cache->ssl3Timeout;
888 SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
889 "cipherSuite=%d", myPid, sid->cached,
890 sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
891 sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
892 sid->creationTime, sid->u.ssl3.cipherSuite));
893 PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID,
894 sid->u.ssl3.sessionIDLength));
897 ConvertFromSID(&sce, sid);
899 if (version >= SSL_LIBRARY_VERSION_3_0) {
900 SECItem *name = &sid->u.ssl3.srvName;
901 if (name->len && name->data) {
902 now = CacheSrvName(cache, name, &sce);
904 if (sid->peerCert != NULL) {
905 now = CacheCert(cache, sid->peerCert, &sce);
909 set = SIDindex(cache, &sce.addr, sce.sessionID, sce.sessionIDLength);
910 now = LockSet(cache, set, now);
911 if (now) {
912 PRUint32 next = cache->sidCacheSets[set].next;
913 PRUint32 ndx = set * SID_CACHE_ENTRIES_PER_SET + next;
915 /* Write out new cache entry */
916 cache->sidCacheData[ndx] = sce;
918 cache->sidCacheSets[set].next =
919 (next + 1) % SID_CACHE_ENTRIES_PER_SET;
921 UnlockSet(cache, set);
922 sid->cached = in_server_cache;
928 ** Although this is static, it is called from ssl via global function pointer
929 ** ssl_sid_uncache. This invalidates the referenced cache entry.
931 static void
932 ServerSessionIDUncache(sslSessionID *sid)
934 cacheDesc * cache = &globalCache;
935 PRUint8 * sessionID;
936 unsigned int sessionIDLength;
937 PRErrorCode err;
938 PRUint32 set;
939 PRUint32 now;
940 sidCacheEntry *psce;
942 if (sid == NULL)
943 return;
945 /* Uncaching a SID should never change the error code.
946 ** So save it here and restore it before exiting.
948 err = PR_GetError();
950 if (sid->version < SSL_LIBRARY_VERSION_3_0) {
951 sessionID = sid->u.ssl2.sessionID;
952 sessionIDLength = SSL2_SESSIONID_BYTES;
953 SSL_TRC(8, ("%d: SSL: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
954 "cipher=%d", myPid, sid->cached,
955 sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
956 sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
957 sid->creationTime, sid->u.ssl2.cipherType));
958 PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
959 PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
960 sid->u.ssl2.masterKey.len));
961 PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
962 sid->u.ssl2.cipherArg.len));
963 } else {
964 sessionID = sid->u.ssl3.sessionID;
965 sessionIDLength = sid->u.ssl3.sessionIDLength;
966 SSL_TRC(8, ("%d: SSL3: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
967 "cipherSuite=%d", myPid, sid->cached,
968 sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
969 sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
970 sid->creationTime, sid->u.ssl3.cipherSuite));
971 PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
973 set = SIDindex(cache, &sid->addr, sessionID, sessionIDLength);
974 now = LockSet(cache, set, 0);
975 if (now) {
976 psce = FindSID(cache, set, now, &sid->addr, sessionID, sessionIDLength);
977 if (psce) {
978 psce->valid = 0;
980 UnlockSet(cache, set);
982 sid->cached = invalid_cache;
983 PORT_SetError(err);
986 #ifdef XP_OS2
988 #define INCL_DOSPROCESS
989 #include <os2.h>
991 long gettid(void)
993 PTIB ptib;
994 PPIB ppib;
995 DosGetInfoBlocks(&ptib, &ppib);
996 return ((long)ptib->tib_ordinal); /* thread id */
998 #endif
1000 static void
1001 CloseCache(cacheDesc *cache)
1003 int locks_initialized = cache->numSIDCacheLocksInitialized;
1005 if (cache->cacheMem) {
1006 if (cache->sharedCache) {
1007 sidCacheLock *pLock = cache->sidCacheLocks;
1008 for (; locks_initialized > 0; --locks_initialized, ++pLock ) {
1009 /* If everInherited is true, this shared cache was (and may
1010 ** still be) in use by multiple processes. We do not wish to
1011 ** destroy the mutexes while they are still in use, but we do
1012 ** want to free mutex resources associated with this process.
1014 sslMutex_Destroy(&pLock->mutex,
1015 cache->sharedCache->everInherited);
1018 if (cache->shared) {
1019 PR_MemUnmap(cache->cacheMem, cache->cacheMemSize);
1020 } else {
1021 PORT_Free(cache->cacheMem);
1023 cache->cacheMem = NULL;
1025 if (cache->cacheMemMap) {
1026 PR_CloseFileMap(cache->cacheMemMap);
1027 cache->cacheMemMap = NULL;
1029 memset(cache, 0, sizeof *cache);
1032 static SECStatus
1033 InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries,
1034 int maxSrvNameCacheEntries, PRUint32 ssl2_timeout,
1035 PRUint32 ssl3_timeout, const char *directory, PRBool shared)
1037 ptrdiff_t ptr;
1038 sidCacheLock *pLock;
1039 char * cacheMem;
1040 PRFileMap * cacheMemMap;
1041 char * cfn = NULL; /* cache file name */
1042 int locks_initialized = 0;
1043 int locks_to_initialize = 0;
1044 PRUint32 init_time;
1046 if ( (!cache) || (maxCacheEntries < 0) || (!directory) ) {
1047 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1048 return SECFailure;
1051 if (cache->cacheMem) {
1052 /* Already done */
1053 return SECSuccess;
1056 /* make sure loser can clean up properly */
1057 cache->shared = shared;
1058 cache->cacheMem = cacheMem = NULL;
1059 cache->cacheMemMap = cacheMemMap = NULL;
1060 cache->sharedCache = (cacheDesc *)0;
1062 cache->numSIDCacheLocksInitialized = 0;
1063 cache->nextCertCacheEntry = 0;
1064 cache->stopPolling = PR_FALSE;
1065 cache->everInherited = PR_FALSE;
1066 cache->poller = NULL;
1067 cache->mutexTimeout = 0;
1069 cache->numSIDCacheEntries = maxCacheEntries ? maxCacheEntries
1070 : DEF_SID_CACHE_ENTRIES;
1071 cache->numSIDCacheSets =
1072 SID_HOWMANY(cache->numSIDCacheEntries, SID_CACHE_ENTRIES_PER_SET);
1074 cache->numSIDCacheEntries =
1075 cache->numSIDCacheSets * SID_CACHE_ENTRIES_PER_SET;
1077 cache->numSIDCacheLocks =
1078 PR_MIN(cache->numSIDCacheSets, ssl_max_sid_cache_locks);
1080 cache->numSIDCacheSetsPerLock =
1081 SID_HOWMANY(cache->numSIDCacheSets, cache->numSIDCacheLocks);
1083 cache->numCertCacheEntries = (maxCertCacheEntries > 0) ?
1084 maxCertCacheEntries : 0;
1085 cache->numSrvNameCacheEntries = (maxSrvNameCacheEntries >= 0) ?
1086 maxSrvNameCacheEntries : DEF_NAME_CACHE_ENTRIES;
1088 /* compute size of shared memory, and offsets of all pointers */
1089 ptr = 0;
1090 cache->cacheMem = (char *)ptr;
1091 ptr += SID_ROUNDUP(sizeof(cacheDesc), SID_ALIGNMENT);
1093 cache->sidCacheLocks = (sidCacheLock *)ptr;
1094 cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks;
1095 cache->certCacheLock = cache->keyCacheLock + 1;
1096 cache->srvNameCacheLock = cache->certCacheLock + 1;
1097 ptr = (ptrdiff_t)(cache->srvNameCacheLock + 1);
1098 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1100 cache->sidCacheSets = (sidCacheSet *)ptr;
1101 ptr = (ptrdiff_t)(cache->sidCacheSets + cache->numSIDCacheSets);
1102 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1104 cache->sidCacheData = (sidCacheEntry *)ptr;
1105 ptr = (ptrdiff_t)(cache->sidCacheData + cache->numSIDCacheEntries);
1106 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1108 cache->certCacheData = (certCacheEntry *)ptr;
1109 cache->sidCacheSize =
1110 (char *)cache->certCacheData - (char *)cache->sidCacheData;
1112 if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) {
1113 /* This is really a poor way to computer this! */
1114 cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry);
1115 if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES)
1116 cache->numCertCacheEntries = MIN_CERT_CACHE_ENTRIES;
1118 ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries);
1119 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1121 cache->keyCacheData = (SSLWrappedSymWrappingKey *)ptr;
1122 cache->certCacheSize =
1123 (char *)cache->keyCacheData - (char *)cache->certCacheData;
1125 cache->numKeyCacheEntries = kt_kea_size * SSL_NUM_WRAP_MECHS;
1126 ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries);
1127 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1129 cache->keyCacheSize = (char *)ptr - (char *)cache->keyCacheData;
1131 cache->ticketKeyNameSuffix = (uint8 *)ptr;
1132 ptr = (ptrdiff_t)(cache->ticketKeyNameSuffix +
1133 SESS_TICKET_KEY_VAR_NAME_LEN);
1134 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1136 cache->ticketEncKey = (encKeyCacheEntry *)ptr;
1137 ptr = (ptrdiff_t)(cache->ticketEncKey + 1);
1138 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1140 cache->ticketMacKey = (encKeyCacheEntry *)ptr;
1141 ptr = (ptrdiff_t)(cache->ticketMacKey + 1);
1142 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1144 cache->ticketKeysValid = (PRUint32 *)ptr;
1145 ptr = (ptrdiff_t)(cache->ticketKeysValid + 1);
1146 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1148 cache->srvNameCacheData = (srvNameCacheEntry *)ptr;
1149 cache->srvNameCacheSize =
1150 cache->numSrvNameCacheEntries * sizeof(srvNameCacheEntry);
1151 ptr = (ptrdiff_t)(cache->srvNameCacheData + cache->numSrvNameCacheEntries);
1152 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1154 cache->cacheMemSize = ptr;
1156 if (ssl2_timeout) {
1157 if (ssl2_timeout > MAX_SSL2_TIMEOUT) {
1158 ssl2_timeout = MAX_SSL2_TIMEOUT;
1160 if (ssl2_timeout < MIN_SSL2_TIMEOUT) {
1161 ssl2_timeout = MIN_SSL2_TIMEOUT;
1163 cache->ssl2Timeout = ssl2_timeout;
1164 } else {
1165 cache->ssl2Timeout = DEF_SSL2_TIMEOUT;
1168 if (ssl3_timeout) {
1169 if (ssl3_timeout > MAX_SSL3_TIMEOUT) {
1170 ssl3_timeout = MAX_SSL3_TIMEOUT;
1172 if (ssl3_timeout < MIN_SSL3_TIMEOUT) {
1173 ssl3_timeout = MIN_SSL3_TIMEOUT;
1175 cache->ssl3Timeout = ssl3_timeout;
1176 } else {
1177 cache->ssl3Timeout = DEF_SSL3_TIMEOUT;
1180 if (shared) {
1181 /* Create file names */
1182 #if defined(XP_UNIX) || defined(XP_BEOS)
1183 /* there's some confusion here about whether PR_OpenAnonFileMap wants
1184 ** a directory name or a file name for its first argument.
1185 cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid);
1187 cfn = PR_smprintf("%s", directory);
1188 #elif defined(XP_WIN32)
1189 cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid,
1190 GetCurrentThreadId());
1191 #elif defined(XP_OS2)
1192 cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid,
1193 gettid());
1194 #else
1195 #error "Don't know how to create file name for this platform!"
1196 #endif
1197 if (!cfn) {
1198 goto loser;
1201 /* Create cache */
1202 cacheMemMap = PR_OpenAnonFileMap(cfn, cache->cacheMemSize,
1203 PR_PROT_READWRITE);
1205 PR_smprintf_free(cfn);
1206 if(!cacheMemMap) {
1207 goto loser;
1210 cacheMem = PR_MemMap(cacheMemMap, 0, cache->cacheMemSize);
1211 } else {
1212 cacheMem = PORT_Alloc(cache->cacheMemSize);
1215 if (! cacheMem) {
1216 goto loser;
1219 /* Initialize shared memory. This may not be necessary on all platforms */
1220 memset(cacheMem, 0, cache->cacheMemSize);
1222 /* Copy cache descriptor header into shared memory */
1223 memcpy(cacheMem, cache, sizeof *cache);
1225 /* save private copies of these values */
1226 cache->cacheMemMap = cacheMemMap;
1227 cache->cacheMem = cacheMem;
1228 cache->sharedCache = (cacheDesc *)cacheMem;
1230 /* Fix pointers in our private copy of cache descriptor to point to
1231 ** spaces in shared memory
1233 ptr = (ptrdiff_t)cache->cacheMem;
1234 *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
1235 *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
1236 *(ptrdiff_t *)(&cache->certCacheLock) += ptr;
1237 *(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr;
1238 *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
1239 *(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
1240 *(ptrdiff_t *)(&cache->certCacheData) += ptr;
1241 *(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
1242 *(ptrdiff_t *)(&cache->ticketKeyNameSuffix) += ptr;
1243 *(ptrdiff_t *)(&cache->ticketEncKey ) += ptr;
1244 *(ptrdiff_t *)(&cache->ticketMacKey ) += ptr;
1245 *(ptrdiff_t *)(&cache->ticketKeysValid) += ptr;
1246 *(ptrdiff_t *)(&cache->srvNameCacheData) += ptr;
1248 /* initialize the locks */
1249 init_time = ssl_Time();
1250 pLock = cache->sidCacheLocks;
1251 for (locks_to_initialize = cache->numSIDCacheLocks + 3;
1252 locks_initialized < locks_to_initialize;
1253 ++locks_initialized, ++pLock ) {
1255 SECStatus err = sslMutex_Init(&pLock->mutex, shared);
1256 if (err) {
1257 cache->numSIDCacheLocksInitialized = locks_initialized;
1258 goto loser;
1260 pLock->timeStamp = init_time;
1261 pLock->pid = 0;
1263 cache->numSIDCacheLocksInitialized = locks_initialized;
1265 return SECSuccess;
1267 loser:
1268 CloseCache(cache);
1269 return SECFailure;
1272 PRUint32
1273 SSL_GetMaxServerCacheLocks(void)
1275 return ssl_max_sid_cache_locks + 2;
1276 /* The extra two are the cert cache lock and the key cache lock. */
1279 SECStatus
1280 SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
1282 /* Minimum is 1 sid cache lock, 1 cert cache lock and 1 key cache lock.
1283 ** We'd like to test for a maximum value, but not all platforms' header
1284 ** files provide a symbol or function or other means of determining
1285 ** the maximum, other than trial and error.
1287 if (maxLocks < 3) {
1288 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1289 return SECFailure;
1291 ssl_max_sid_cache_locks = maxLocks - 2;
1292 /* The extra two are the cert cache lock and the key cache lock. */
1293 return SECSuccess;
1296 static SECStatus
1297 ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache,
1298 PRUint32 ssl2_timeout,
1299 PRUint32 ssl3_timeout,
1300 const char * directory,
1301 PRBool shared,
1302 int maxCacheEntries,
1303 int maxCertCacheEntries,
1304 int maxSrvNameCacheEntries)
1306 SECStatus rv;
1308 PORT_Assert(sizeof(sidCacheEntry) == 192);
1309 PORT_Assert(sizeof(certCacheEntry) == 4096);
1310 PORT_Assert(sizeof(srvNameCacheEntry) == 1072);
1312 rv = ssl_Init();
1313 if (rv != SECSuccess) {
1314 return rv;
1317 myPid = SSL_GETPID();
1318 if (!directory) {
1319 directory = DEFAULT_CACHE_DIRECTORY;
1321 rv = InitCache(cache, maxCacheEntries, maxCertCacheEntries,
1322 maxSrvNameCacheEntries, ssl2_timeout, ssl3_timeout,
1323 directory, shared);
1324 if (rv) {
1325 SET_ERROR_CODE
1326 return SECFailure;
1329 ssl_sid_lookup = ServerSessionIDLookup;
1330 ssl_sid_cache = ServerSessionIDCache;
1331 ssl_sid_uncache = ServerSessionIDUncache;
1332 return SECSuccess;
1335 SECStatus
1336 SSL_ConfigServerSessionIDCacheInstance( cacheDesc *cache,
1337 int maxCacheEntries,
1338 PRUint32 ssl2_timeout,
1339 PRUint32 ssl3_timeout,
1340 const char * directory, PRBool shared)
1342 return ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
1343 ssl2_timeout,
1344 ssl3_timeout,
1345 directory,
1346 shared,
1347 maxCacheEntries,
1348 -1, -1);
1351 SECStatus
1352 SSL_ConfigServerSessionIDCache( int maxCacheEntries,
1353 PRUint32 ssl2_timeout,
1354 PRUint32 ssl3_timeout,
1355 const char * directory)
1357 ssl_InitSessionCacheLocks(PR_FALSE);
1358 return SSL_ConfigServerSessionIDCacheInstance(&globalCache,
1359 maxCacheEntries, ssl2_timeout, ssl3_timeout, directory, PR_FALSE);
1362 SECStatus
1363 SSL_ShutdownServerSessionIDCacheInstance(cacheDesc *cache)
1365 CloseCache(cache);
1366 return SECSuccess;
1369 SECStatus
1370 SSL_ShutdownServerSessionIDCache(void)
1372 #if defined(XP_UNIX) || defined(XP_BEOS)
1373 /* Stop the thread that polls cache for expired locks on Unix */
1374 StopLockPoller(&globalCache);
1375 #endif
1376 SSL3_ShutdownServerCache();
1377 return SSL_ShutdownServerSessionIDCacheInstance(&globalCache);
1380 /* Use this function, instead of SSL_ConfigServerSessionIDCache,
1381 * if the cache will be shared by multiple processes.
1383 static SECStatus
1384 ssl_ConfigMPServerSIDCacheWithOpt( PRUint32 ssl2_timeout,
1385 PRUint32 ssl3_timeout,
1386 const char * directory,
1387 int maxCacheEntries,
1388 int maxCertCacheEntries,
1389 int maxSrvNameCacheEntries)
1391 char * envValue;
1392 char * inhValue;
1393 cacheDesc * cache = &globalCache;
1394 PRUint32 fmStrLen;
1395 SECStatus result;
1396 PRStatus prStatus;
1397 SECStatus putEnvFailed;
1398 inheritance inherit;
1399 char fmString[PR_FILEMAP_STRING_BUFSIZE];
1401 isMultiProcess = PR_TRUE;
1402 result = ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
1403 ssl2_timeout, ssl3_timeout, directory, PR_TRUE,
1404 maxCacheEntries, maxCacheEntries, maxSrvNameCacheEntries);
1405 if (result != SECSuccess)
1406 return result;
1408 prStatus = PR_ExportFileMapAsString(cache->cacheMemMap,
1409 sizeof fmString, fmString);
1410 if ((prStatus != PR_SUCCESS) || !(fmStrLen = strlen(fmString))) {
1411 SET_ERROR_CODE
1412 return SECFailure;
1415 inherit.cacheMemSize = cache->cacheMemSize;
1416 inherit.fmStrLen = fmStrLen;
1418 inhValue = BTOA_DataToAscii((unsigned char *)&inherit, sizeof inherit);
1419 if (!inhValue || !strlen(inhValue)) {
1420 SET_ERROR_CODE
1421 return SECFailure;
1423 envValue = PR_smprintf("%s,%s", inhValue, fmString);
1424 if (!envValue || !strlen(envValue)) {
1425 SET_ERROR_CODE
1426 return SECFailure;
1428 PORT_Free(inhValue);
1430 putEnvFailed = (SECStatus)NSS_PutEnv(envVarName, envValue);
1431 PR_smprintf_free(envValue);
1432 if (putEnvFailed) {
1433 SET_ERROR_CODE
1434 result = SECFailure;
1437 #if defined(XP_UNIX) || defined(XP_BEOS)
1438 /* Launch thread to poll cache for expired locks on Unix */
1439 LaunchLockPoller(cache);
1440 #endif
1441 return result;
1444 /* Use this function, instead of SSL_ConfigServerSessionIDCache,
1445 * if the cache will be shared by multiple processes.
1447 SECStatus
1448 SSL_ConfigMPServerSIDCache( int maxCacheEntries,
1449 PRUint32 ssl2_timeout,
1450 PRUint32 ssl3_timeout,
1451 const char * directory)
1453 return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout,
1454 ssl3_timeout,
1455 directory,
1456 maxCacheEntries,
1457 -1, -1);
1460 SECStatus
1461 SSL_ConfigServerSessionIDCacheWithOpt(
1462 PRUint32 ssl2_timeout,
1463 PRUint32 ssl3_timeout,
1464 const char * directory,
1465 int maxCacheEntries,
1466 int maxCertCacheEntries,
1467 int maxSrvNameCacheEntries,
1468 PRBool enableMPCache)
1470 if (!enableMPCache) {
1471 ssl_InitSessionCacheLocks(PR_FALSE);
1472 return ssl_ConfigServerSessionIDCacheInstanceWithOpt(&globalCache,
1473 ssl2_timeout, ssl3_timeout, directory, PR_FALSE,
1474 maxCacheEntries, maxCertCacheEntries, maxSrvNameCacheEntries);
1475 } else {
1476 return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout, ssl3_timeout,
1477 directory, maxCacheEntries, maxCertCacheEntries,
1478 maxSrvNameCacheEntries);
1482 SECStatus
1483 SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
1485 unsigned char * decoString = NULL;
1486 char * fmString = NULL;
1487 char * myEnvString = NULL;
1488 unsigned int decoLen;
1489 ptrdiff_t ptr;
1490 inheritance inherit;
1491 cacheDesc my;
1492 #ifdef WINNT
1493 sidCacheLock* newLocks;
1494 int locks_initialized = 0;
1495 int locks_to_initialize = 0;
1496 #endif
1497 SECStatus status = ssl_Init();
1499 if (status != SECSuccess) {
1500 return status;
1503 myPid = SSL_GETPID();
1505 /* If this child was created by fork(), and not by exec() on unix,
1506 ** then isMultiProcess will already be set.
1507 ** If not, we'll set it below.
1509 if (isMultiProcess) {
1510 if (cache && cache->sharedCache) {
1511 cache->sharedCache->everInherited = PR_TRUE;
1513 return SECSuccess; /* already done. */
1516 ssl_InitSessionCacheLocks(PR_FALSE);
1518 ssl_sid_lookup = ServerSessionIDLookup;
1519 ssl_sid_cache = ServerSessionIDCache;
1520 ssl_sid_uncache = ServerSessionIDUncache;
1522 if (!envString) {
1523 envString = getenv(envVarName);
1524 if (!envString) {
1525 SET_ERROR_CODE
1526 return SECFailure;
1529 myEnvString = PORT_Strdup(envString);
1530 if (!myEnvString)
1531 return SECFailure;
1532 fmString = strchr(myEnvString, ',');
1533 if (!fmString)
1534 goto loser;
1535 *fmString++ = 0;
1537 decoString = ATOB_AsciiToData(myEnvString, &decoLen);
1538 if (!decoString) {
1539 SET_ERROR_CODE
1540 goto loser;
1542 if (decoLen != sizeof inherit) {
1543 SET_ERROR_CODE
1544 goto loser;
1547 PORT_Memcpy(&inherit, decoString, sizeof inherit);
1549 if (strlen(fmString) != inherit.fmStrLen ) {
1550 goto loser;
1553 memset(cache, 0, sizeof *cache);
1554 cache->cacheMemSize = inherit.cacheMemSize;
1556 /* Create cache */
1557 cache->cacheMemMap = PR_ImportFileMapFromString(fmString);
1558 if(! cache->cacheMemMap) {
1559 goto loser;
1561 cache->cacheMem = PR_MemMap(cache->cacheMemMap, 0, cache->cacheMemSize);
1562 if (! cache->cacheMem) {
1563 goto loser;
1565 cache->sharedCache = (cacheDesc *)cache->cacheMem;
1567 if (cache->sharedCache->cacheMemSize != cache->cacheMemSize) {
1568 SET_ERROR_CODE
1569 goto loser;
1572 /* We're now going to overwrite the local cache instance with the
1573 ** shared copy of the cache struct, then update several values in
1574 ** the local cache using the values for cache->cacheMemMap and
1575 ** cache->cacheMem computed just above. So, we copy cache into
1576 ** the automatic variable "my", to preserve the variables while
1577 ** cache is overwritten.
1579 my = *cache; /* save values computed above. */
1580 memcpy(cache, cache->sharedCache, sizeof *cache); /* overwrite */
1582 /* Fix pointers in our private copy of cache descriptor to point to
1583 ** spaces in shared memory, whose address is now in "my".
1585 ptr = (ptrdiff_t)my.cacheMem;
1586 *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
1587 *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
1588 *(ptrdiff_t *)(&cache->certCacheLock) += ptr;
1589 *(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr;
1590 *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
1591 *(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
1592 *(ptrdiff_t *)(&cache->certCacheData) += ptr;
1593 *(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
1594 *(ptrdiff_t *)(&cache->ticketKeyNameSuffix) += ptr;
1595 *(ptrdiff_t *)(&cache->ticketEncKey ) += ptr;
1596 *(ptrdiff_t *)(&cache->ticketMacKey ) += ptr;
1597 *(ptrdiff_t *)(&cache->ticketKeysValid) += ptr;
1598 *(ptrdiff_t *)(&cache->srvNameCacheData) += ptr;
1600 cache->cacheMemMap = my.cacheMemMap;
1601 cache->cacheMem = my.cacheMem;
1602 cache->sharedCache = (cacheDesc *)cache->cacheMem;
1604 #ifdef WINNT
1605 /* On Windows NT we need to "fix" the sidCacheLocks here to support fibers
1606 ** When NT fibers are used in a multi-process server, a second level of
1607 ** locking is needed to prevent a deadlock, in case a fiber acquires the
1608 ** cross-process mutex, yields, and another fiber is later scheduled on
1609 ** the same native thread and tries to acquire the cross-process mutex.
1610 ** We do this by using a PRLock in the sslMutex. However, it is stored in
1611 ** shared memory as part of sidCacheLocks, and we don't want to overwrite
1612 ** the PRLock of the parent process. So we need to make new, private
1613 ** copies of sidCacheLocks before modifying the sslMutex with our own
1614 ** PRLock
1617 /* note from jpierre : this should be free'd in child processes when
1618 ** a function is added to delete the SSL session cache in the future.
1620 locks_to_initialize = cache->numSIDCacheLocks + 3;
1621 newLocks = PORT_NewArray(sidCacheLock, locks_to_initialize);
1622 if (!newLocks)
1623 goto loser;
1624 /* copy the old locks */
1625 memcpy(newLocks, cache->sidCacheLocks,
1626 locks_to_initialize * sizeof(sidCacheLock));
1627 cache->sidCacheLocks = newLocks;
1628 /* fix the locks */
1629 for (; locks_initialized < locks_to_initialize; ++locks_initialized) {
1630 /* now, make a local PRLock in this sslMutex for this child process */
1631 SECStatus err;
1632 err = sslMutex_2LevelInit(&newLocks[locks_initialized].mutex);
1633 if (err != SECSuccess) {
1634 cache->numSIDCacheLocksInitialized = locks_initialized;
1635 goto loser;
1638 cache->numSIDCacheLocksInitialized = locks_initialized;
1640 /* also fix the key and cert cache which use the last 2 lock entries */
1641 cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks;
1642 cache->certCacheLock = cache->keyCacheLock + 1;
1643 cache->srvNameCacheLock = cache->certCacheLock + 1;
1644 #endif
1646 PORT_Free(myEnvString);
1647 PORT_Free(decoString);
1649 /* mark that we have inherited this. */
1650 cache->sharedCache->everInherited = PR_TRUE;
1651 isMultiProcess = PR_TRUE;
1653 return SECSuccess;
1655 loser:
1656 PORT_Free(myEnvString);
1657 if (decoString)
1658 PORT_Free(decoString);
1659 CloseCache(cache);
1660 return SECFailure;
1663 SECStatus
1664 SSL_InheritMPServerSIDCache(const char * envString)
1666 return SSL_InheritMPServerSIDCacheInstance(&globalCache, envString);
1669 #if defined(XP_UNIX) || defined(XP_BEOS)
1671 #define SID_LOCK_EXPIRATION_TIMEOUT 30 /* seconds */
1673 static void
1674 LockPoller(void * arg)
1676 cacheDesc * cache = (cacheDesc *)arg;
1677 cacheDesc * sharedCache = cache->sharedCache;
1678 sidCacheLock * pLock;
1679 PRIntervalTime timeout;
1680 PRUint32 now;
1681 PRUint32 then;
1682 int locks_polled = 0;
1683 int locks_to_poll = cache->numSIDCacheLocks + 2;
1684 PRUint32 expiration = cache->mutexTimeout;
1686 timeout = PR_SecondsToInterval(expiration);
1687 while(!sharedCache->stopPolling) {
1688 PR_Sleep(timeout);
1689 if (sharedCache->stopPolling)
1690 break;
1692 now = ssl_Time();
1693 then = now - expiration;
1694 for (pLock = cache->sidCacheLocks, locks_polled = 0;
1695 locks_to_poll > locks_polled && !sharedCache->stopPolling;
1696 ++locks_polled, ++pLock ) {
1697 pid_t pid;
1699 if (pLock->timeStamp < then &&
1700 pLock->timeStamp != 0 &&
1701 (pid = pLock->pid) != 0) {
1703 /* maybe we should try the lock? */
1704 int result = kill(pid, 0);
1705 if (result < 0 && errno == ESRCH) {
1706 SECStatus rv;
1707 /* No process exists by that pid any more.
1708 ** Treat this mutex as abandoned.
1710 pLock->timeStamp = now;
1711 pLock->pid = 0;
1712 rv = sslMutex_Unlock(&pLock->mutex);
1713 if (rv != SECSuccess) {
1714 /* Now what? */
1718 } /* end of loop over locks */
1719 } /* end of entire polling loop */
1722 /* Launch thread to poll cache for expired locks */
1723 static SECStatus
1724 LaunchLockPoller(cacheDesc *cache)
1726 const char * timeoutString;
1727 PRThread * pollerThread;
1729 cache->mutexTimeout = SID_LOCK_EXPIRATION_TIMEOUT;
1730 timeoutString = getenv("NSS_SSL_SERVER_CACHE_MUTEX_TIMEOUT");
1731 if (timeoutString) {
1732 long newTime = strtol(timeoutString, 0, 0);
1733 if (newTime == 0)
1734 return SECSuccess; /* application doesn't want poller thread */
1735 if (newTime > 0)
1736 cache->mutexTimeout = (PRUint32)newTime;
1737 /* if error (newTime < 0) ignore it and use default */
1740 pollerThread =
1741 PR_CreateThread(PR_USER_THREAD, LockPoller, cache, PR_PRIORITY_NORMAL,
1742 PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
1743 if (!pollerThread) {
1744 return SECFailure;
1746 cache->poller = pollerThread;
1747 return SECSuccess;
1750 /* Stop the thread that polls cache for expired locks */
1751 static SECStatus
1752 StopLockPoller(cacheDesc *cache)
1754 if (!cache->poller) {
1755 return SECSuccess;
1757 cache->sharedCache->stopPolling = PR_TRUE;
1758 if (PR_Interrupt(cache->poller) != PR_SUCCESS) {
1759 return SECFailure;
1761 if (PR_JoinThread(cache->poller) != PR_SUCCESS) {
1762 return SECFailure;
1764 cache->poller = NULL;
1765 return SECSuccess;
1767 #endif
1769 /************************************************************************
1770 * Code dealing with shared wrapped symmetric wrapping keys below *
1771 ************************************************************************/
1773 /* If now is zero, it implies that the lock is not held, and must be
1774 ** aquired here.
1776 static PRBool
1777 getSvrWrappingKey(PRInt32 symWrapMechIndex,
1778 SSL3KEAType exchKeyType,
1779 SSLWrappedSymWrappingKey *wswk,
1780 cacheDesc * cache,
1781 PRUint32 lockTime)
1783 PRUint32 ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
1784 SSLWrappedSymWrappingKey * pwswk = cache->keyCacheData + ndx;
1785 PRUint32 now = 0;
1786 PRBool rv = PR_FALSE;
1788 if (!cache->cacheMem) { /* cache is uninitialized */
1789 PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
1790 return rv;
1792 if (!lockTime) {
1793 lockTime = now = LockSidCacheLock(cache->keyCacheLock, now);
1794 if (!lockTime) {
1795 return rv;
1798 if (pwswk->exchKeyType == exchKeyType &&
1799 pwswk->symWrapMechIndex == symWrapMechIndex &&
1800 pwswk->wrappedSymKeyLen != 0) {
1801 *wswk = *pwswk;
1802 rv = PR_TRUE;
1804 if (now) {
1805 UnlockSidCacheLock(cache->keyCacheLock);
1807 return rv;
1810 PRBool
1811 ssl_GetWrappingKey( PRInt32 symWrapMechIndex,
1812 SSL3KEAType exchKeyType,
1813 SSLWrappedSymWrappingKey *wswk)
1815 PRBool rv;
1817 PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
1818 PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
1819 if ((unsigned)exchKeyType < kt_kea_size &&
1820 (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) {
1821 rv = getSvrWrappingKey(symWrapMechIndex, exchKeyType, wswk,
1822 &globalCache, 0);
1823 } else {
1824 rv = PR_FALSE;
1827 return rv;
1830 /* Wrap and cache a session ticket key. */
1831 static PRBool
1832 WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey,
1833 const char *keyName, encKeyCacheEntry* cacheEntry)
1835 SECItem wrappedKey = {siBuffer, NULL, 0};
1837 wrappedKey.len = SECKEY_PublicKeyStrength(svrPubKey);
1838 PORT_Assert(wrappedKey.len <= sizeof(cacheEntry->bytes));
1839 if (wrappedKey.len > sizeof(cacheEntry->bytes))
1840 return PR_FALSE;
1841 wrappedKey.data = cacheEntry->bytes;
1843 if (PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, symKey, &wrappedKey)
1844 != SECSuccess) {
1845 SSL_DBG(("%d: SSL[%s]: Unable to wrap session ticket %s.",
1846 SSL_GETPID(), "unknown", keyName));
1847 return PR_FALSE;
1849 cacheEntry->length = wrappedKey.len;
1850 return PR_TRUE;
1853 static PRBool
1854 GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey,
1855 PK11SymKey **macKey)
1857 PK11SlotInfo *slot;
1858 CK_MECHANISM_TYPE mechanismArray[2];
1859 PK11SymKey *aesKeyTmp = NULL;
1860 PK11SymKey *macKeyTmp = NULL;
1861 cacheDesc *cache = &globalCache;
1862 uint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN];
1863 uint8 *ticketKeyNameSuffix;
1865 if (!cache->cacheMem) {
1866 /* cache is not initalized. Use stack buffer */
1867 ticketKeyNameSuffix = ticketKeyNameSuffixLocal;
1868 } else {
1869 ticketKeyNameSuffix = cache->ticketKeyNameSuffix;
1872 if (PK11_GenerateRandom(ticketKeyNameSuffix,
1873 SESS_TICKET_KEY_VAR_NAME_LEN) != SECSuccess) {
1874 SSL_DBG(("%d: SSL[%s]: Unable to generate random key name bytes.",
1875 SSL_GETPID(), "unknown"));
1876 goto loser;
1879 mechanismArray[0] = CKM_AES_CBC;
1880 mechanismArray[1] = CKM_SHA256_HMAC;
1882 slot = PK11_GetBestSlotMultiple(mechanismArray, 2, pwArg);
1883 if (slot) {
1884 aesKeyTmp = PK11_KeyGen(slot, mechanismArray[0], NULL,
1885 AES_256_KEY_LENGTH, pwArg);
1886 macKeyTmp = PK11_KeyGen(slot, mechanismArray[1], NULL,
1887 SHA256_LENGTH, pwArg);
1888 PK11_FreeSlot(slot);
1891 if (aesKeyTmp == NULL || macKeyTmp == NULL) {
1892 SSL_DBG(("%d: SSL[%s]: Unable to generate session ticket keys.",
1893 SSL_GETPID(), "unknown"));
1894 goto loser;
1896 PORT_Memcpy(keyName, ticketKeyNameSuffix, SESS_TICKET_KEY_VAR_NAME_LEN);
1897 *aesKey = aesKeyTmp;
1898 *macKey = macKeyTmp;
1899 return PR_TRUE;
1901 loser:
1902 if (aesKeyTmp)
1903 PK11_FreeSymKey(aesKeyTmp);
1904 if (macKeyTmp)
1905 PK11_FreeSymKey(macKeyTmp);
1906 return PR_FALSE;
1909 static PRBool
1910 GenerateAndWrapTicketKeys(SECKEYPublicKey *svrPubKey, void *pwArg,
1911 unsigned char *keyName, PK11SymKey **aesKey,
1912 PK11SymKey **macKey)
1914 PK11SymKey *aesKeyTmp = NULL;
1915 PK11SymKey *macKeyTmp = NULL;
1916 cacheDesc *cache = &globalCache;
1918 if (!GenerateTicketKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp)) {
1919 goto loser;
1922 if (cache->cacheMem) {
1923 /* Export the keys to the shared cache in wrapped form. */
1924 if (!WrapTicketKey(svrPubKey, aesKeyTmp, "enc key", cache->ticketEncKey))
1925 goto loser;
1926 if (!WrapTicketKey(svrPubKey, macKeyTmp, "mac key", cache->ticketMacKey))
1927 goto loser;
1929 *aesKey = aesKeyTmp;
1930 *macKey = macKeyTmp;
1931 return PR_TRUE;
1933 loser:
1934 if (aesKeyTmp)
1935 PK11_FreeSymKey(aesKeyTmp);
1936 if (macKeyTmp)
1937 PK11_FreeSymKey(macKeyTmp);
1938 return PR_FALSE;
1941 static PRBool
1942 UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName,
1943 PK11SymKey **aesKey, PK11SymKey **macKey)
1945 SECItem wrappedKey = {siBuffer, NULL, 0};
1946 PK11SymKey *aesKeyTmp = NULL;
1947 PK11SymKey *macKeyTmp = NULL;
1948 cacheDesc *cache = &globalCache;
1950 wrappedKey.data = cache->ticketEncKey->bytes;
1951 wrappedKey.len = cache->ticketEncKey->length;
1952 PORT_Assert(wrappedKey.len <= sizeof(cache->ticketEncKey->bytes));
1953 aesKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
1954 CKM_AES_CBC, CKA_DECRYPT, 0);
1956 wrappedKey.data = cache->ticketMacKey->bytes;
1957 wrappedKey.len = cache->ticketMacKey->length;
1958 PORT_Assert(wrappedKey.len <= sizeof(cache->ticketMacKey->bytes));
1959 macKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
1960 CKM_SHA256_HMAC, CKA_SIGN, 0);
1962 if (aesKeyTmp == NULL || macKeyTmp == NULL) {
1963 SSL_DBG(("%d: SSL[%s]: Unable to unwrap session ticket keys.",
1964 SSL_GETPID(), "unknown"));
1965 goto loser;
1967 SSL_DBG(("%d: SSL[%s]: Successfully unwrapped session ticket keys.",
1968 SSL_GETPID(), "unknown"));
1970 PORT_Memcpy(keyName, cache->ticketKeyNameSuffix,
1971 SESS_TICKET_KEY_VAR_NAME_LEN);
1972 *aesKey = aesKeyTmp;
1973 *macKey = macKeyTmp;
1974 return PR_TRUE;
1976 loser:
1977 if (aesKeyTmp)
1978 PK11_FreeSymKey(aesKeyTmp);
1979 if (macKeyTmp)
1980 PK11_FreeSymKey(macKeyTmp);
1981 return PR_FALSE;
1984 PRBool
1985 ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey,
1986 SECKEYPublicKey *svrPubKey, void *pwArg,
1987 unsigned char *keyName, PK11SymKey **aesKey,
1988 PK11SymKey **macKey)
1990 PRUint32 now = 0;
1991 PRBool rv = PR_FALSE;
1992 PRBool keysGenerated = PR_FALSE;
1993 cacheDesc *cache = &globalCache;
1995 if (!cache->cacheMem) {
1996 /* cache is uninitialized. Generate keys and return them
1997 * without caching. */
1998 return GenerateTicketKeys(pwArg, keyName, aesKey, macKey);
2001 now = LockSidCacheLock(cache->keyCacheLock, now);
2002 if (!now)
2003 return rv;
2005 if (!*(cache->ticketKeysValid)) {
2006 /* Keys do not exist, create them. */
2007 if (!GenerateAndWrapTicketKeys(svrPubKey, pwArg, keyName,
2008 aesKey, macKey))
2009 goto loser;
2010 keysGenerated = PR_TRUE;
2011 *(cache->ticketKeysValid) = 1;
2014 rv = PR_TRUE;
2016 loser:
2017 UnlockSidCacheLock(cache->keyCacheLock);
2018 if (rv && !keysGenerated)
2019 rv = UnwrapCachedTicketKeys(svrPrivKey, keyName, aesKey, macKey);
2020 return rv;
2023 PRBool
2024 ssl_GetSessionTicketKeys(unsigned char *keyName, unsigned char *encKey,
2025 unsigned char *macKey)
2027 PRBool rv = PR_FALSE;
2028 PRUint32 now = 0;
2029 cacheDesc *cache = &globalCache;
2030 uint8 ticketMacKey[AES_256_KEY_LENGTH], ticketEncKey[SHA256_LENGTH];
2031 uint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN];
2032 uint8 *ticketMacKeyPtr, *ticketEncKeyPtr, *ticketKeyNameSuffix;
2033 PRBool cacheIsEnabled = PR_TRUE;
2035 if (!cache->cacheMem) { /* cache is uninitialized */
2036 cacheIsEnabled = PR_FALSE;
2037 ticketKeyNameSuffix = ticketKeyNameSuffixLocal;
2038 ticketEncKeyPtr = ticketEncKey;
2039 ticketMacKeyPtr = ticketMacKey;
2040 } else {
2041 /* these values have constant memory locations in the cache.
2042 * Ok to reference them without holding the lock. */
2043 ticketKeyNameSuffix = cache->ticketKeyNameSuffix;
2044 ticketEncKeyPtr = cache->ticketEncKey->bytes;
2045 ticketMacKeyPtr = cache->ticketMacKey->bytes;
2048 if (cacheIsEnabled) {
2049 /* Grab lock if initialized. */
2050 now = LockSidCacheLock(cache->keyCacheLock, now);
2051 if (!now)
2052 return rv;
2054 /* Going to regenerate keys on every call if cache was not
2055 * initialized. */
2056 if (!cacheIsEnabled || !*(cache->ticketKeysValid)) {
2057 if (PK11_GenerateRandom(ticketKeyNameSuffix,
2058 SESS_TICKET_KEY_VAR_NAME_LEN) != SECSuccess)
2059 goto loser;
2060 if (PK11_GenerateRandom(ticketEncKeyPtr,
2061 AES_256_KEY_LENGTH) != SECSuccess)
2062 goto loser;
2063 if (PK11_GenerateRandom(ticketMacKeyPtr,
2064 SHA256_LENGTH) != SECSuccess)
2065 goto loser;
2066 if (cacheIsEnabled) {
2067 *(cache->ticketKeysValid) = 1;
2071 rv = PR_TRUE;
2073 loser:
2074 if (cacheIsEnabled) {
2075 UnlockSidCacheLock(cache->keyCacheLock);
2077 if (rv) {
2078 PORT_Memcpy(keyName, ticketKeyNameSuffix,
2079 SESS_TICKET_KEY_VAR_NAME_LEN);
2080 PORT_Memcpy(encKey, ticketEncKeyPtr, AES_256_KEY_LENGTH);
2081 PORT_Memcpy(macKey, ticketMacKeyPtr, SHA256_LENGTH);
2083 return rv;
2086 /* The caller passes in the new value it wants
2087 * to set. This code tests the wrapped sym key entry in the shared memory.
2088 * If it is uninitialized, this function writes the caller's value into
2089 * the disk entry, and returns false.
2090 * Otherwise, it overwrites the caller's wswk with the value obtained from
2091 * the disk, and returns PR_TRUE.
2092 * This is all done while holding the locks/mutexes necessary to make
2093 * the operation atomic.
2095 PRBool
2096 ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
2098 cacheDesc * cache = &globalCache;
2099 PRBool rv = PR_FALSE;
2100 SSL3KEAType exchKeyType = wswk->exchKeyType;
2101 /* type of keys used to wrap SymWrapKey*/
2102 PRInt32 symWrapMechIndex = wswk->symWrapMechIndex;
2103 PRUint32 ndx;
2104 PRUint32 now = 0;
2105 SSLWrappedSymWrappingKey myWswk;
2107 if (!cache->cacheMem) { /* cache is uninitialized */
2108 PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
2109 return 0;
2112 PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
2113 if ((unsigned)exchKeyType >= kt_kea_size)
2114 return 0;
2116 PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
2117 if ((unsigned)symWrapMechIndex >= SSL_NUM_WRAP_MECHS)
2118 return 0;
2120 ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
2121 PORT_Memset(&myWswk, 0, sizeof myWswk); /* eliminate UMRs. */
2123 now = LockSidCacheLock(cache->keyCacheLock, now);
2124 if (now) {
2125 rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->exchKeyType,
2126 &myWswk, cache, now);
2127 if (rv) {
2128 /* we found it on disk, copy it out to the caller. */
2129 PORT_Memcpy(wswk, &myWswk, sizeof *wswk);
2130 } else {
2131 /* Wasn't on disk, and we're still holding the lock, so write it. */
2132 cache->keyCacheData[ndx] = *wswk;
2134 UnlockSidCacheLock(cache->keyCacheLock);
2136 return rv;
2139 #else /* MAC version or other platform */
2141 #include "seccomon.h"
2142 #include "cert.h"
2143 #include "ssl.h"
2144 #include "sslimpl.h"
2146 SECStatus
2147 SSL_ConfigServerSessionIDCache( int maxCacheEntries,
2148 PRUint32 ssl2_timeout,
2149 PRUint32 ssl3_timeout,
2150 const char * directory)
2152 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigServerSessionIDCache)");
2153 return SECFailure;
2156 SECStatus
2157 SSL_ConfigMPServerSIDCache( int maxCacheEntries,
2158 PRUint32 ssl2_timeout,
2159 PRUint32 ssl3_timeout,
2160 const char * directory)
2162 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigMPServerSIDCache)");
2163 return SECFailure;
2166 SECStatus
2167 SSL_InheritMPServerSIDCache(const char * envString)
2169 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_InheritMPServerSIDCache)");
2170 return SECFailure;
2173 PRBool
2174 ssl_GetWrappingKey( PRInt32 symWrapMechIndex,
2175 SSL3KEAType exchKeyType,
2176 SSLWrappedSymWrappingKey *wswk)
2178 PRBool rv = PR_FALSE;
2179 PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)");
2180 return rv;
2183 /* This is a kind of test-and-set. The caller passes in the new value it wants
2184 * to set. This code tests the wrapped sym key entry in the shared memory.
2185 * If it is uninitialized, this function writes the caller's value into
2186 * the disk entry, and returns false.
2187 * Otherwise, it overwrites the caller's wswk with the value obtained from
2188 * the disk, and returns PR_TRUE.
2189 * This is all done while holding the locks/mutexes necessary to make
2190 * the operation atomic.
2192 PRBool
2193 ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
2195 PRBool rv = PR_FALSE;
2196 PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrappingKey)");
2197 return rv;
2200 PRUint32
2201 SSL_GetMaxServerCacheLocks(void)
2203 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_GetMaxServerCacheLocks)");
2204 return -1;
2207 SECStatus
2208 SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
2210 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_SetMaxServerCacheLocks)");
2211 return SECFailure;
2214 #endif /* XP_UNIX || XP_WIN32 */