Add explicit |forceOnlineSignin| to user pod status
[chromium-blink-merge.git] / net / third_party / nss / ssl / sslsnce.c
blob34e07b005118df5c515221c38e250cb60f3828aa
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/. */
8 /* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server
9 * cache sids!
11 * About record locking among different server processes:
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.
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.
26 * The anonymous shared memory is laid out as if it were declared like this:
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;
45 #include "seccomon.h"
47 #if defined(XP_UNIX) || defined(XP_WIN32) || defined (XP_OS2) || defined(XP_BEOS)
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
63 #include <stdio.h>
65 #if defined(XP_UNIX) || defined(XP_BEOS)
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"
74 #else
76 #ifdef XP_WIN32
77 #include <wtypes.h>
78 #include "win32err.h"
79 #endif
81 #endif
82 #include <sys/types.h>
84 #define SET_ERROR_CODE /* reminder */
86 #include "nspr.h"
87 #include "sslmutex.h"
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 */
107 union {
108 struct {
109 /* 64 */ PRUint8 masterKey[SSL_MAX_MASTER_KEY_BYTES];
110 /* 32 */ PRUint8 cipherArg[SSL_MAX_CYPHER_ARG_BYTES];
112 /* 1 */ PRUint8 cipherType;
113 /* 1 */ PRUint8 masterKeyLen;
114 /* 1 */ PRUint8 keyBits;
115 /* 1 */ PRUint8 secretKeyBits;
116 /* 1 */ PRUint8 cipherArgLen;
117 /*101 */} ssl2;
119 struct {
120 /* 2 */ ssl3CipherSuite cipherSuite;
121 /* 2 */ PRUint16 compression; /* SSLCompressionMethod */
123 /* 52 */ ssl3SidKeys keys; /* keys, wrapped as needed. */
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;
137 typedef struct sidCacheEntryStr sidCacheEntry;
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;
148 struct sidCacheLockStr {
149 PRUint32 timeStamp;
150 sslMutex mutex;
151 sslPID pid;
153 typedef struct sidCacheLockStr sidCacheLock;
155 struct sidCacheSetStr {
156 PRIntn next;
158 typedef struct sidCacheSetStr sidCacheSet;
160 struct encKeyCacheEntryStr {
161 PRUint8 bytes[512];
162 PRInt32 length;
164 typedef struct encKeyCacheEntryStr encKeyCacheEntry;
166 #define SSL_MAX_DNS_HOST_NAME 1024
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 */
175 typedef struct srvNameCacheEntryStr srvNameCacheEntry;
178 struct cacheDescStr {
180 PRUint32 cacheMemSize;
182 PRUint32 numSIDCacheLocks;
183 PRUint32 numSIDCacheSets;
184 PRUint32 numSIDCacheSetsPerLock;
186 PRUint32 numSIDCacheEntries;
187 PRUint32 sidCacheSize;
189 PRUint32 numCertCacheEntries;
190 PRUint32 certCacheSize;
192 PRUint32 numKeyCacheEntries;
193 PRUint32 keyCacheSize;
195 PRUint32 numSrvNameCacheEntries;
196 PRUint32 srvNameCacheSize;
198 PRUint32 ssl2Timeout;
199 PRUint32 ssl3Timeout;
201 PRUint32 numSIDCacheLocksInitialized;
203 /* These values are volatile, and are accessed through sharedCache-> */
204 PRUint32 nextCertCacheEntry; /* certCacheLock protects */
205 PRBool stopPolling;
206 PRBool everInherited;
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;
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;
232 typedef struct cacheDescStr cacheDesc;
234 static cacheDesc globalCache;
236 static const char envVarName[] = { SSL_ENV_VAR_NAME };
238 static PRBool isMultiProcess = PR_FALSE;
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
247 #define SID_CACHE_ENTRIES_PER_SET 128
248 #define SID_ALIGNMENT 16
250 #define DEF_SSL2_TIMEOUT 100 /* seconds */
251 #define MAX_SSL2_TIMEOUT 100 /* seconds */
252 #define MIN_SSL2_TIMEOUT 5 /* seconds */
254 #define DEF_SSL3_TIMEOUT 86400L /* 24 hours */
255 #define MAX_SSL3_TIMEOUT 86400L /* 24 hours */
256 #define MIN_SSL3_TIMEOUT 5 /* seconds */
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
266 #define SID_HOWMANY(val, size) (((val) + ((size) - 1)) / (size))
267 #define SID_ROUNDUP(val, size) ((size) * SID_HOWMANY((val), (size)))
270 static sslPID myPid;
271 static PRUint32 ssl_max_sid_cache_locks = MAX_SID_CACHE_LOCKS;
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);
280 struct inheritanceStr {
281 PRUint32 cacheMemSize;
282 PRUint32 fmStrLen;
285 typedef struct inheritanceStr inheritance;
287 #if defined(_WIN32) || defined(XP_OS2)
289 #define DEFAULT_CACHE_DIRECTORY "\\temp"
291 #endif /* _win32 */
293 #if defined(XP_UNIX) || defined(XP_BEOS)
295 #define DEFAULT_CACHE_DIRECTORY "/tmp"
297 #endif /* XP_UNIX || XP_BEOS */
300 /************************************************************************/
302 static PRUint32
303 LockSidCacheLock(sidCacheLock *lock, PRUint32 now)
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;
315 static SECStatus
316 UnlockSidCacheLock(sidCacheLock *lock)
318 SECStatus rv;
320 lock->pid = 0;
321 rv = sslMutex_Unlock(&lock->mutex);
322 return rv;
325 /* returns the value of ssl_Time on success, zero on failure. */
326 static PRUint32
327 LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now)
329 PRUint32 lockNum = set % cache->numSIDCacheLocks;
330 sidCacheLock * lock = cache->sidCacheLocks + lockNum;
332 return LockSidCacheLock(lock, now);
335 static SECStatus
336 UnlockSet(cacheDesc *cache, PRUint32 set)
338 PRUint32 lockNum = set % cache->numSIDCacheLocks;
339 sidCacheLock * lock = cache->sidCacheLocks + lockNum;
341 return UnlockSidCacheLock(lock);
344 /************************************************************************/
347 /* Put a certificate in the cache. Update the cert index in the sce.
349 static PRUint32
350 CacheCert(cacheDesc * cache, CERTCertificate *cert, sidCacheEntry *sce)
352 PRUint32 now;
353 certCacheEntry cce;
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;
362 cce.sessionIDLength = sce->sessionIDLength;
363 PORT_Memcpy(cce.sessionID, sce->sessionID, cce.sessionIDLength);
365 cce.certLength = cert->derCert.len;
366 PORT_Memcpy(cce.cert, cert->derCert.data, cce.certLength);
368 /* get lock on cert cache */
369 now = LockSidCacheLock(cache->certCacheLock, 0);
370 if (now) {
372 /* Find where to place the next cert cache entry. */
373 cacheDesc * sharedCache = cache->sharedCache;
374 PRUint32 ndx = sharedCache->nextCertCacheEntry;
376 /* write the entry */
377 cache->certCacheData[ndx] = cce;
379 /* remember where we put it. */
380 sce->u.ssl3.certIndex = ndx;
382 /* update the "next" cache entry index */
383 sharedCache->nextCertCacheEntry =
384 (ndx + 1) % cache->numCertCacheEntries;
386 UnlockSidCacheLock(cache->certCacheLock);
388 return now;
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)
397 PLHashNumber rv = SECITEM_Hash(name);
399 PRUint8 *rvc = (PRUint8 *)&rv;
400 rvc[ name->len % sizeof(rv) ] ^= name->type;
402 return rv;
405 /* Put a name in the cache. Update the cert index in the sce.
407 static PRUint32
408 CacheSrvName(cacheDesc * cache, SECItem *name, sidCacheEntry *sce)
410 PRUint32 now;
411 PRUint32 ndx;
412 srvNameCacheEntry snce;
414 if (!name || name->len <= 0 ||
415 name->len > SSL_MAX_DNS_HOST_NAME) {
416 PORT_SetError(SEC_ERROR_INVALID_ARGS);
417 return 0;
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);
444 UnlockSidCacheLock(cache->srvNameCacheLock);
446 return now;
450 ** Convert local SID to shared memory one
452 static void
453 ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
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;
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;
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 */
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;
511 PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID,
512 to->sessionIDLength);
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));
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.
527 static sslSessionID *
528 ConvertToSID(sidCacheEntry * from,
529 certCacheEntry * pcce,
530 srvNameCacheEntry *psnce,
531 CERTCertDBHandle * dbHandle)
533 sslSessionID *to;
534 PRUint16 version = from->version;
536 to = PORT_ZNew(sslSessionID);
537 if (!to) {
538 return 0;
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;
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;
554 PORT_Memcpy(to->u.ssl2.cipherArg.data, from->u.ssl2.cipherArg,
555 from->u.ssl2.cipherArgLen);
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);
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 */
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;
596 PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength);
598 /* the portions of the SID that are only restored on the client
599 * are set to invalid values on the server.
601 to->u.ssl3.clientWriteKey = NULL;
602 to->u.ssl3.serverWriteKey = NULL;
604 to->urlSvrName = NULL;
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;
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;
617 if (from->u.ssl3.certIndex != -1 && pcce) {
618 SECItem derCert;
620 derCert.len = pcce->certLength;
621 derCert.data = pcce->cert;
623 to->peerCert = CERT_NewTempCertificate(dbHandle, &derCert, NULL,
624 PR_FALSE, PR_TRUE);
625 if (to->peerCert == NULL)
626 goto loser;
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;
642 return to;
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);
654 PORT_Free(to);
656 return NULL;
662 ** Perform some mumbo jumbo on the ip-address and the session-id value to
663 ** compute a hash value.
665 static PRUint32
666 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl)
668 PRUint32 rv;
669 PRUint32 x[8];
671 memset(x, 0, sizeof x);
672 if (nl > sizeof x)
673 nl = sizeof x;
674 memcpy(x, s, nl);
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;
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.
690 static sidCacheEntry *
691 FindSID(cacheDesc *cache, PRUint32 setNum, PRUint32 now,
692 const PRIPv6Addr *addr, unsigned char *sessionID,
693 unsigned sessionIDLength)
695 PRUint32 ndx = cache->sidCacheSets[setNum].next;
696 int i;
698 sidCacheEntry * set = cache->sidCacheData +
699 (setNum * SID_CACHE_ENTRIES_PER_SET);
701 for (i = SID_CACHE_ENTRIES_PER_SET; i > 0; --i) {
702 sidCacheEntry * sce;
704 ndx = (ndx - 1) % SID_CACHE_ENTRIES_PER_SET;
705 sce = set + ndx;
707 if (!sce->valid)
708 continue;
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;
723 ** Next, examine specific session-id/addr data to see if the cache
724 ** entry matches our addr+session-id value
726 if (sessionIDLength == sce->sessionIDLength &&
727 !memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) &&
728 !memcmp(sce->sessionID, sessionID, sessionIDLength)) {
729 /* Found it */
730 return sce;
734 PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
735 return NULL;
738 /************************************************************************/
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.
744 static sslSessionID *
745 ServerSessionIDLookup(const PRIPv6Addr *addr,
746 unsigned char *sessionID,
747 unsigned int sessionIDLength,
748 CERTCertDBHandle * dbHandle)
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;
762 set = SIDindex(cache, addr, sessionID, sessionIDLength);
763 now = LockSet(cache, set, 0);
764 if (!now)
765 return NULL;
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) {
772 PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now);
773 if (gotLock) {
774 pcce = &cache->certCacheData[cndx];
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.
785 psce->valid = 0;
786 psce = 0;
787 pcce = 0;
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.
794 PORT_Assert(!("Didn't get cert Cache Lock!"));
795 psce = 0;
796 pcce = 0;
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];
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.
812 psce->valid = 0;
813 psce = 0;
814 psnce = 0;
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.
821 PORT_Assert(!("Didn't get name Cache Lock!"));
822 psce = 0;
823 psnce = 0;
828 if (psce) {
829 psce->lastAccessTime = now;
830 sce = *psce; /* grab a copy while holding the lock */
833 UnlockSet(cache, set);
834 if (psce) {
835 /* sce conains a copy of the cache entry.
836 ** Convert shared memory format to local format
838 sid = ConvertToSID(&sce, pcce ? &cce : 0, psnce ? &snce : 0, dbHandle);
840 return sid;
844 ** Place a sid into the cache, if it isn't already there.
846 static void
847 ServerSessionIDCache(sslSessionID *sid)
849 sidCacheEntry sce;
850 PRUint32 now = 0;
851 PRUint16 version = sid->version;
852 cacheDesc * cache = &globalCache;
854 if ((version >= SSL_LIBRARY_VERSION_3_0) &&
855 (sid->u.ssl3.sessionIDLength == 0)) {
856 return;
859 if (sid->cached == never_cached || sid->cached == invalid_cache) {
860 PRUint32 set;
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.
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));
882 } else {
883 /* override caller's expiration time, which uses client timeout
884 * duration, not server timeout duration.
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));
896 ConvertFromSID(&sce, sid);
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);
903 if (sid->peerCert != NULL) {
904 now = CacheCert(cache, sid->peerCert, &sce);
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;
914 /* Write out new cache entry */
915 cache->sidCacheData[ndx] = sce;
917 cache->sidCacheSets[set].next =
918 (next + 1) % SID_CACHE_ENTRIES_PER_SET;
920 UnlockSet(cache, set);
921 sid->cached = in_server_cache;
927 ** Although this is static, it is called from ssl via global function pointer
928 ** ssl_sid_uncache. This invalidates the referenced cache entry.
930 static void
931 ServerSessionIDUncache(sslSessionID *sid)
933 cacheDesc * cache = &globalCache;
934 PRUint8 * sessionID;
935 unsigned int sessionIDLength;
936 PRErrorCode err;
937 PRUint32 set;
938 PRUint32 now;
939 sidCacheEntry *psce;
941 if (sid == NULL)
942 return;
944 /* Uncaching a SID should never change the error code.
945 ** So save it here and restore it before exiting.
947 err = PR_GetError();
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));
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;
979 UnlockSet(cache, set);
981 sid->cached = invalid_cache;
982 PORT_SetError(err);
985 #ifdef XP_OS2
987 #define INCL_DOSPROCESS
988 #include <os2.h>
990 long gettid(void)
992 PTIB ptib;
993 PPIB ppib;
994 DosGetInfoBlocks(&ptib, &ppib);
995 return ((long)ptib->tib_ordinal); /* thread id */
997 #endif
999 static void
1000 CloseCache(cacheDesc *cache)
1002 int locks_initialized = cache->numSIDCacheLocksInitialized;
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.
1013 sslMutex_Destroy(&pLock->mutex,
1014 cache->sharedCache->everInherited);
1017 if (cache->shared) {
1018 PR_MemUnmap(cache->cacheMem, cache->cacheMemSize);
1019 } else {
1020 PORT_Free(cache->cacheMem);
1022 cache->cacheMem = NULL;
1024 if (cache->cacheMemMap) {
1025 PR_CloseFileMap(cache->cacheMemMap);
1026 cache->cacheMemMap = NULL;
1028 memset(cache, 0, sizeof *cache);
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)
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;
1045 if ( (!cache) || (maxCacheEntries < 0) || (!directory) ) {
1046 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1047 return SECFailure;
1050 if (cache->cacheMem) {
1051 /* Already done */
1052 return SECSuccess;
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;
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;
1068 cache->numSIDCacheEntries = maxCacheEntries ? maxCacheEntries
1069 : DEF_SID_CACHE_ENTRIES;
1070 cache->numSIDCacheSets =
1071 SID_HOWMANY(cache->numSIDCacheEntries, SID_CACHE_ENTRIES_PER_SET);
1073 cache->numSIDCacheEntries =
1074 cache->numSIDCacheSets * SID_CACHE_ENTRIES_PER_SET;
1076 cache->numSIDCacheLocks =
1077 PR_MIN(cache->numSIDCacheSets, ssl_max_sid_cache_locks);
1079 cache->numSIDCacheSetsPerLock =
1080 SID_HOWMANY(cache->numSIDCacheSets, cache->numSIDCacheLocks);
1082 cache->numCertCacheEntries = (maxCertCacheEntries > 0) ?
1083 maxCertCacheEntries : 0;
1084 cache->numSrvNameCacheEntries = (maxSrvNameCacheEntries >= 0) ?
1085 maxSrvNameCacheEntries : DEF_NAME_CACHE_ENTRIES;
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);
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);
1099 cache->sidCacheSets = (sidCacheSet *)ptr;
1100 ptr = (ptrdiff_t)(cache->sidCacheSets + cache->numSIDCacheSets);
1101 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1103 cache->sidCacheData = (sidCacheEntry *)ptr;
1104 ptr = (ptrdiff_t)(cache->sidCacheData + cache->numSIDCacheEntries);
1105 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1107 cache->certCacheData = (certCacheEntry *)ptr;
1108 cache->sidCacheSize =
1109 (char *)cache->certCacheData - (char *)cache->sidCacheData;
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;
1117 ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries);
1118 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1120 cache->keyCacheData = (SSLWrappedSymWrappingKey *)ptr;
1121 cache->certCacheSize =
1122 (char *)cache->keyCacheData - (char *)cache->certCacheData;
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);
1128 cache->keyCacheSize = (char *)ptr - (char *)cache->keyCacheData;
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);
1135 cache->ticketEncKey = (encKeyCacheEntry *)ptr;
1136 ptr = (ptrdiff_t)(cache->ticketEncKey + 1);
1137 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1139 cache->ticketMacKey = (encKeyCacheEntry *)ptr;
1140 ptr = (ptrdiff_t)(cache->ticketMacKey + 1);
1141 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1143 cache->ticketKeysValid = (PRUint32 *)ptr;
1144 ptr = (ptrdiff_t)(cache->ticketKeysValid + 1);
1145 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
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);
1153 cache->cacheMemSize = ptr;
1155 if (ssl2_timeout) {
1156 if (ssl2_timeout > MAX_SSL2_TIMEOUT) {
1157 ssl2_timeout = MAX_SSL2_TIMEOUT;
1159 if (ssl2_timeout < MIN_SSL2_TIMEOUT) {
1160 ssl2_timeout = MIN_SSL2_TIMEOUT;
1162 cache->ssl2Timeout = ssl2_timeout;
1163 } else {
1164 cache->ssl2Timeout = DEF_SSL2_TIMEOUT;
1167 if (ssl3_timeout) {
1168 if (ssl3_timeout > MAX_SSL3_TIMEOUT) {
1169 ssl3_timeout = MAX_SSL3_TIMEOUT;
1171 if (ssl3_timeout < MIN_SSL3_TIMEOUT) {
1172 ssl3_timeout = MIN_SSL3_TIMEOUT;
1174 cache->ssl3Timeout = ssl3_timeout;
1175 } else {
1176 cache->ssl3Timeout = DEF_SSL3_TIMEOUT;
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);
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;
1200 /* Create cache */
1201 cacheMemMap = PR_OpenAnonFileMap(cfn, cache->cacheMemSize,
1202 PR_PROT_READWRITE);
1204 PR_smprintf_free(cfn);
1205 if(!cacheMemMap) {
1206 goto loser;
1209 cacheMem = PR_MemMap(cacheMemMap, 0, cache->cacheMemSize);
1210 } else {
1211 cacheMem = PORT_Alloc(cache->cacheMemSize);
1214 if (! cacheMem) {
1215 goto loser;
1218 /* Initialize shared memory. This may not be necessary on all platforms */
1219 memset(cacheMem, 0, cache->cacheMemSize);
1221 /* Copy cache descriptor header into shared memory */
1222 memcpy(cacheMem, cache, sizeof *cache);
1224 /* save private copies of these values */
1225 cache->cacheMemMap = cacheMemMap;
1226 cache->cacheMem = cacheMem;
1227 cache->sharedCache = (cacheDesc *)cacheMem;
1229 /* Fix pointers in our private copy of cache descriptor to point to
1230 ** spaces in shared memory
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;
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 ) {
1254 SECStatus err = sslMutex_Init(&pLock->mutex, shared);
1255 if (err) {
1256 cache->numSIDCacheLocksInitialized = locks_initialized;
1257 goto loser;
1259 pLock->timeStamp = init_time;
1260 pLock->pid = 0;
1262 cache->numSIDCacheLocksInitialized = locks_initialized;
1264 return SECSuccess;
1266 loser:
1267 CloseCache(cache);
1268 return SECFailure;
1271 PRUint32
1272 SSL_GetMaxServerCacheLocks(void)
1274 return ssl_max_sid_cache_locks + 2;
1275 /* The extra two are the cert cache lock and the key cache lock. */
1278 SECStatus
1279 SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
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.
1286 if (maxLocks < 3) {
1287 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1288 return SECFailure;
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;
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)
1305 SECStatus rv;
1307 PORT_Assert(sizeof(sidCacheEntry) == 192);
1308 PORT_Assert(sizeof(certCacheEntry) == 4096);
1309 PORT_Assert(sizeof(srvNameCacheEntry) == 1072);
1311 rv = ssl_Init();
1312 if (rv != SECSuccess) {
1313 return rv;
1316 myPid = SSL_GETPID();
1317 if (!directory) {
1318 directory = DEFAULT_CACHE_DIRECTORY;
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;
1328 ssl_sid_lookup = ServerSessionIDLookup;
1329 ssl_sid_cache = ServerSessionIDCache;
1330 ssl_sid_uncache = ServerSessionIDUncache;
1331 return SECSuccess;
1334 SECStatus
1335 SSL_ConfigServerSessionIDCacheInstance( cacheDesc *cache,
1336 int maxCacheEntries,
1337 PRUint32 ssl2_timeout,
1338 PRUint32 ssl3_timeout,
1339 const char * directory, PRBool shared)
1341 return ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
1342 ssl2_timeout,
1343 ssl3_timeout,
1344 directory,
1345 shared,
1346 maxCacheEntries,
1347 -1, -1);
1350 SECStatus
1351 SSL_ConfigServerSessionIDCache( int maxCacheEntries,
1352 PRUint32 ssl2_timeout,
1353 PRUint32 ssl3_timeout,
1354 const char * directory)
1356 ssl_InitSessionCacheLocks();
1357 return SSL_ConfigServerSessionIDCacheInstance(&globalCache,
1358 maxCacheEntries, ssl2_timeout, ssl3_timeout, directory, PR_FALSE);
1361 SECStatus
1362 SSL_ShutdownServerSessionIDCacheInstance(cacheDesc *cache)
1364 CloseCache(cache);
1365 return SECSuccess;
1368 SECStatus
1369 SSL_ShutdownServerSessionIDCache(void)
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);
1379 /* Use this function, instead of SSL_ConfigServerSessionIDCache,
1380 * if the cache will be shared by multiple processes.
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)
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];
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;
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;
1414 inherit.cacheMemSize = cache->cacheMemSize;
1415 inherit.fmStrLen = fmStrLen;
1417 inhValue = BTOA_DataToAscii((unsigned char *)&inherit, sizeof inherit);
1418 if (!inhValue || !strlen(inhValue)) {
1419 SET_ERROR_CODE
1420 return SECFailure;
1422 envValue = PR_smprintf("%s,%s", inhValue, fmString);
1423 if (!envValue || !strlen(envValue)) {
1424 SET_ERROR_CODE
1425 return SECFailure;
1427 PORT_Free(inhValue);
1429 putEnvFailed = (SECStatus)NSS_PutEnv(envVarName, envValue);
1430 PR_smprintf_free(envValue);
1431 if (putEnvFailed) {
1432 SET_ERROR_CODE
1433 result = SECFailure;
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;
1443 /* Use this function, instead of SSL_ConfigServerSessionIDCache,
1444 * if the cache will be shared by multiple processes.
1446 SECStatus
1447 SSL_ConfigMPServerSIDCache( int maxCacheEntries,
1448 PRUint32 ssl2_timeout,
1449 PRUint32 ssl3_timeout,
1450 const char * directory)
1452 return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout,
1453 ssl3_timeout,
1454 directory,
1455 maxCacheEntries,
1456 -1, -1);
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)
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);
1481 SECStatus
1482 SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
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();
1498 if (status != SECSuccess) {
1499 return status;
1502 myPid = SSL_GETPID();
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.
1508 if (isMultiProcess) {
1509 if (cache && cache->sharedCache) {
1510 cache->sharedCache->everInherited = PR_TRUE;
1512 return SECSuccess; /* already done. */
1515 ssl_InitSessionCacheLocks();
1517 ssl_sid_lookup = ServerSessionIDLookup;
1518 ssl_sid_cache = ServerSessionIDCache;
1519 ssl_sid_uncache = ServerSessionIDUncache;
1521 if (!envString) {
1522 envString = getenv(envVarName);
1523 if (!envString) {
1524 SET_ERROR_CODE
1525 return SECFailure;
1528 myEnvString = PORT_Strdup(envString);
1529 if (!myEnvString)
1530 return SECFailure;
1531 fmString = strchr(myEnvString, ',');
1532 if (!fmString)
1533 goto loser;
1534 *fmString++ = 0;
1536 decoString = ATOB_AsciiToData(myEnvString, &decoLen);
1537 if (!decoString) {
1538 SET_ERROR_CODE
1539 goto loser;
1541 if (decoLen != sizeof inherit) {
1542 SET_ERROR_CODE
1543 goto loser;
1546 PORT_Memcpy(&inherit, decoString, sizeof inherit);
1548 if (strlen(fmString) != inherit.fmStrLen ) {
1549 goto loser;
1552 memset(cache, 0, sizeof *cache);
1553 cache->cacheMemSize = inherit.cacheMemSize;
1555 /* Create cache */
1556 cache->cacheMemMap = PR_ImportFileMapFromString(fmString);
1557 if(! cache->cacheMemMap) {
1558 goto loser;
1560 cache->cacheMem = PR_MemMap(cache->cacheMemMap, 0, cache->cacheMemSize);
1561 if (! cache->cacheMem) {
1562 goto loser;
1564 cache->sharedCache = (cacheDesc *)cache->cacheMem;
1566 if (cache->sharedCache->cacheMemSize != cache->cacheMemSize) {
1567 SET_ERROR_CODE
1568 goto loser;
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.
1578 my = *cache; /* save values computed above. */
1579 memcpy(cache, cache->sharedCache, sizeof *cache); /* overwrite */
1581 /* Fix pointers in our private copy of cache descriptor to point to
1582 ** spaces in shared memory, whose address is now in "my".
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;
1599 cache->cacheMemMap = my.cacheMemMap;
1600 cache->cacheMem = my.cacheMem;
1601 cache->sharedCache = (cacheDesc *)cache->cacheMem;
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
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.
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;
1637 cache->numSIDCacheLocksInitialized = locks_initialized;
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
1645 PORT_Free(myEnvString);
1646 PORT_Free(decoString);
1648 /* mark that we have inherited this. */
1649 cache->sharedCache->everInherited = PR_TRUE;
1650 isMultiProcess = PR_TRUE;
1652 return SECSuccess;
1654 loser:
1655 PORT_Free(myEnvString);
1656 if (decoString)
1657 PORT_Free(decoString);
1658 CloseCache(cache);
1659 return SECFailure;
1662 SECStatus
1663 SSL_InheritMPServerSIDCache(const char * envString)
1665 return SSL_InheritMPServerSIDCacheInstance(&globalCache, envString);
1668 #if defined(XP_UNIX) || defined(XP_BEOS)
1670 #define SID_LOCK_EXPIRATION_TIMEOUT 30 /* seconds */
1672 static void
1673 LockPoller(void * arg)
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;
1685 timeout = PR_SecondsToInterval(expiration);
1686 while(!sharedCache->stopPolling) {
1687 PR_Sleep(timeout);
1688 if (sharedCache->stopPolling)
1689 break;
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;
1698 if (pLock->timeStamp < then &&
1699 pLock->timeStamp != 0 &&
1700 (pid = pLock->pid) != 0) {
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.
1709 pLock->timeStamp = now;
1710 pLock->pid = 0;
1711 rv = sslMutex_Unlock(&pLock->mutex);
1712 if (rv != SECSuccess) {
1713 /* Now what? */
1717 } /* end of loop over locks */
1718 } /* end of entire polling loop */
1721 /* Launch thread to poll cache for expired locks */
1722 static SECStatus
1723 LaunchLockPoller(cacheDesc *cache)
1725 const char * timeoutString;
1726 PRThread * pollerThread;
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 */
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;
1745 cache->poller = pollerThread;
1746 return SECSuccess;
1749 /* Stop the thread that polls cache for expired locks */
1750 static SECStatus
1751 StopLockPoller(cacheDesc *cache)
1753 if (!cache->poller) {
1754 return SECSuccess;
1756 cache->sharedCache->stopPolling = PR_TRUE;
1757 if (PR_Interrupt(cache->poller) != PR_SUCCESS) {
1758 return SECFailure;
1760 if (PR_JoinThread(cache->poller) != PR_SUCCESS) {
1761 return SECFailure;
1763 cache->poller = NULL;
1764 return SECSuccess;
1766 #endif
1768 /************************************************************************
1769 * Code dealing with shared wrapped symmetric wrapping keys below *
1770 ************************************************************************/
1772 /* If now is zero, it implies that the lock is not held, and must be
1773 ** aquired here.
1775 static PRBool
1776 getSvrWrappingKey(PRInt32 symWrapMechIndex,
1777 SSL3KEAType exchKeyType,
1778 SSLWrappedSymWrappingKey *wswk,
1779 cacheDesc * cache,
1780 PRUint32 lockTime)
1782 PRUint32 ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
1783 SSLWrappedSymWrappingKey * pwswk = cache->keyCacheData + ndx;
1784 PRUint32 now = 0;
1785 PRBool rv = PR_FALSE;
1787 if (!cache->cacheMem) { /* cache is uninitialized */
1788 PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
1789 return rv;
1791 if (!lockTime) {
1792 lockTime = now = LockSidCacheLock(cache->keyCacheLock, now);
1793 if (!lockTime) {
1794 return rv;
1797 if (pwswk->exchKeyType == exchKeyType &&
1798 pwswk->symWrapMechIndex == symWrapMechIndex &&
1799 pwswk->wrappedSymKeyLen != 0) {
1800 *wswk = *pwswk;
1801 rv = PR_TRUE;
1803 if (now) {
1804 UnlockSidCacheLock(cache->keyCacheLock);
1806 return rv;
1809 PRBool
1810 ssl_GetWrappingKey( PRInt32 symWrapMechIndex,
1811 SSL3KEAType exchKeyType,
1812 SSLWrappedSymWrappingKey *wswk)
1814 PRBool rv;
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;
1826 return rv;
1829 /* Wrap and cache a session ticket key. */
1830 static PRBool
1831 WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey,
1832 const char *keyName, encKeyCacheEntry* cacheEntry)
1834 SECItem wrappedKey = {siBuffer, NULL, 0};
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;
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;
1848 cacheEntry->length = wrappedKey.len;
1849 return PR_TRUE;
1852 static PRBool
1853 GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey,
1854 PK11SymKey **macKey)
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;
1864 if (!cache->cacheMem) {
1865 /* cache is not initalized. Use stack buffer */
1866 ticketKeyNameSuffix = ticketKeyNameSuffixLocal;
1867 } else {
1868 ticketKeyNameSuffix = cache->ticketKeyNameSuffix;
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;
1878 mechanismArray[0] = CKM_AES_CBC;
1879 mechanismArray[1] = CKM_SHA256_HMAC;
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);
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;
1895 PORT_Memcpy(keyName, ticketKeyNameSuffix, SESS_TICKET_KEY_VAR_NAME_LEN);
1896 *aesKey = aesKeyTmp;
1897 *macKey = macKeyTmp;
1898 return PR_TRUE;
1900 loser:
1901 if (aesKeyTmp)
1902 PK11_FreeSymKey(aesKeyTmp);
1903 if (macKeyTmp)
1904 PK11_FreeSymKey(macKeyTmp);
1905 return PR_FALSE;
1908 static PRBool
1909 GenerateAndWrapTicketKeys(SECKEYPublicKey *svrPubKey, void *pwArg,
1910 unsigned char *keyName, PK11SymKey **aesKey,
1911 PK11SymKey **macKey)
1913 PK11SymKey *aesKeyTmp = NULL;
1914 PK11SymKey *macKeyTmp = NULL;
1915 cacheDesc *cache = &globalCache;
1917 if (!GenerateTicketKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp)) {
1918 goto loser;
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;
1928 *aesKey = aesKeyTmp;
1929 *macKey = macKeyTmp;
1930 return PR_TRUE;
1932 loser:
1933 if (aesKeyTmp)
1934 PK11_FreeSymKey(aesKeyTmp);
1935 if (macKeyTmp)
1936 PK11_FreeSymKey(macKeyTmp);
1937 return PR_FALSE;
1940 static PRBool
1941 UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName,
1942 PK11SymKey **aesKey, PK11SymKey **macKey)
1944 SECItem wrappedKey = {siBuffer, NULL, 0};
1945 PK11SymKey *aesKeyTmp = NULL;
1946 PK11SymKey *macKeyTmp = NULL;
1947 cacheDesc *cache = &globalCache;
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);
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);
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;
1966 SSL_DBG(("%d: SSL[%s]: Successfully unwrapped session ticket keys.",
1967 SSL_GETPID(), "unknown"));
1969 PORT_Memcpy(keyName, cache->ticketKeyNameSuffix,
1970 SESS_TICKET_KEY_VAR_NAME_LEN);
1971 *aesKey = aesKeyTmp;
1972 *macKey = macKeyTmp;
1973 return PR_TRUE;
1975 loser:
1976 if (aesKeyTmp)
1977 PK11_FreeSymKey(aesKeyTmp);
1978 if (macKeyTmp)
1979 PK11_FreeSymKey(macKeyTmp);
1980 return PR_FALSE;
1983 PRBool
1984 ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey,
1985 SECKEYPublicKey *svrPubKey, void *pwArg,
1986 unsigned char *keyName, PK11SymKey **aesKey,
1987 PK11SymKey **macKey)
1989 PRUint32 now = 0;
1990 PRBool rv = PR_FALSE;
1991 PRBool keysGenerated = PR_FALSE;
1992 cacheDesc *cache = &globalCache;
1994 if (!cache->cacheMem) {
1995 /* cache is uninitialized. Generate keys and return them
1996 * without caching. */
1997 return GenerateTicketKeys(pwArg, keyName, aesKey, macKey);
2000 now = LockSidCacheLock(cache->keyCacheLock, now);
2001 if (!now)
2002 return rv;
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;
2013 rv = PR_TRUE;
2015 loser:
2016 UnlockSidCacheLock(cache->keyCacheLock);
2017 if (rv && !keysGenerated)
2018 rv = UnwrapCachedTicketKeys(svrPrivKey, keyName, aesKey, macKey);
2019 return rv;
2022 PRBool
2023 ssl_GetSessionTicketKeys(unsigned char *keyName, unsigned char *encKey,
2024 unsigned char *macKey)
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;
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;
2047 if (cacheIsEnabled) {
2048 /* Grab lock if initialized. */
2049 now = LockSidCacheLock(cache->keyCacheLock, now);
2050 if (!now)
2051 return rv;
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;
2070 rv = PR_TRUE;
2072 loser:
2073 if (cacheIsEnabled) {
2074 UnlockSidCacheLock(cache->keyCacheLock);
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);
2082 return rv;
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.
2094 PRBool
2095 ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
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;
2106 if (!cache->cacheMem) { /* cache is uninitialized */
2107 PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
2108 return 0;
2111 PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
2112 if ((unsigned)exchKeyType >= kt_kea_size)
2113 return 0;
2115 PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
2116 if ((unsigned)symWrapMechIndex >= SSL_NUM_WRAP_MECHS)
2117 return 0;
2119 ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
2120 PORT_Memset(&myWswk, 0, sizeof myWswk); /* eliminate UMRs. */
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;
2133 UnlockSidCacheLock(cache->keyCacheLock);
2135 return rv;
2138 #else /* MAC version or other platform */
2140 #include "seccomon.h"
2141 #include "cert.h"
2142 #include "ssl.h"
2143 #include "sslimpl.h"
2145 SECStatus
2146 SSL_ConfigServerSessionIDCache( int maxCacheEntries,
2147 PRUint32 ssl2_timeout,
2148 PRUint32 ssl3_timeout,
2149 const char * directory)
2151 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigServerSessionIDCache)");
2152 return SECFailure;
2155 SECStatus
2156 SSL_ConfigMPServerSIDCache( int maxCacheEntries,
2157 PRUint32 ssl2_timeout,
2158 PRUint32 ssl3_timeout,
2159 const char * directory)
2161 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigMPServerSIDCache)");
2162 return SECFailure;
2165 SECStatus
2166 SSL_InheritMPServerSIDCache(const char * envString)
2168 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_InheritMPServerSIDCache)");
2169 return SECFailure;
2172 PRBool
2173 ssl_GetWrappingKey( PRInt32 symWrapMechIndex,
2174 SSL3KEAType exchKeyType,
2175 SSLWrappedSymWrappingKey *wswk)
2177 PRBool rv = PR_FALSE;
2178 PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)");
2179 return rv;
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.
2191 PRBool
2192 ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
2194 PRBool rv = PR_FALSE;
2195 PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrappingKey)");
2196 return rv;
2199 PRUint32
2200 SSL_GetMaxServerCacheLocks(void)
2202 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_GetMaxServerCacheLocks)");
2203 return -1;
2206 SECStatus
2207 SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
2209 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_SetMaxServerCacheLocks)");
2210 return SECFailure;
2213 #endif /* XP_UNIX || XP_WIN32 */