Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / third_party / nss / ssl / sslsnce.c
blob327920080c5db9f28a093a6b1db0e4744fc3037a
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().
526 static sslSessionID *
527 ConvertToSID(sidCacheEntry * from,
528 certCacheEntry * pcce,
529 srvNameCacheEntry *psnce,
530 CERTCertDBHandle * dbHandle)
532 sslSessionID *to;
533 PRUint16 version = from->version;
535 to = PORT_ZNew(sslSessionID);
536 if (!to) {
537 return 0;
540 if (version < SSL_LIBRARY_VERSION_3_0) {
541 /* This is an SSL v2 session */
542 to->u.ssl2.masterKey.data =
543 (unsigned char*) PORT_Alloc(from->u.ssl2.masterKeyLen);
544 if (!to->u.ssl2.masterKey.data) {
545 goto loser;
547 if (from->u.ssl2.cipherArgLen) {
548 to->u.ssl2.cipherArg.data =
549 (unsigned char*)PORT_Alloc(from->u.ssl2.cipherArgLen);
550 if (!to->u.ssl2.cipherArg.data) {
551 goto loser;
553 PORT_Memcpy(to->u.ssl2.cipherArg.data, from->u.ssl2.cipherArg,
554 from->u.ssl2.cipherArgLen);
557 to->u.ssl2.cipherType = from->u.ssl2.cipherType;
558 to->u.ssl2.masterKey.len = from->u.ssl2.masterKeyLen;
559 to->u.ssl2.cipherArg.len = from->u.ssl2.cipherArgLen;
560 to->u.ssl2.keyBits = from->u.ssl2.keyBits;
561 to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
562 /* to->sessionIDLength = SSL2_SESSIONID_BYTES; */
563 PORT_Memcpy(to->u.ssl2.sessionID, from->sessionID, SSL2_SESSIONID_BYTES);
564 PORT_Memcpy(to->u.ssl2.masterKey.data, from->u.ssl2.masterKey,
565 from->u.ssl2.masterKeyLen);
567 SSL_TRC(8, ("%d: SSL: ConvertToSID: masterKeyLen=%d cipherArgLen=%d "
568 "time=%d addr=0x%08x%08x%08x%08x cipherType=%d",
569 myPid, to->u.ssl2.masterKey.len,
570 to->u.ssl2.cipherArg.len, to->creationTime,
571 to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1],
572 to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3],
573 to->u.ssl2.cipherType));
574 } else {
575 /* This is an SSL v3 session */
577 to->u.ssl3.sessionIDLength = from->sessionIDLength;
578 to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite;
579 to->u.ssl3.compression = (SSLCompressionMethod)from->u.ssl3.compression;
580 to->u.ssl3.keys = from->u.ssl3.keys;
581 to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech;
582 to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType;
583 if (from->u.ssl3.srvNameIndex != -1 && psnce) {
584 SECItem name;
585 SECStatus rv;
586 name.type = psnce->type;
587 name.len = psnce->nameLen;
588 name.data = psnce->name;
589 rv = SECITEM_CopyItem(NULL, &to->u.ssl3.srvName, &name);
590 if (rv != SECSuccess) {
591 goto loser;
595 PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength);
597 /* the portions of the SID that are only restored on the client
598 * are set to invalid values on the server.
600 to->u.ssl3.clientWriteKey = NULL;
601 to->u.ssl3.serverWriteKey = NULL;
603 to->urlSvrName = NULL;
605 to->u.ssl3.masterModuleID = (SECMODModuleID)-1; /* invalid value */
606 to->u.ssl3.masterSlotID = (CK_SLOT_ID)-1; /* invalid value */
607 to->u.ssl3.masterWrapIndex = 0;
608 to->u.ssl3.masterWrapSeries = 0;
609 to->u.ssl3.masterValid = PR_FALSE;
611 to->u.ssl3.clAuthModuleID = (SECMODModuleID)-1; /* invalid value */
612 to->u.ssl3.clAuthSlotID = (CK_SLOT_ID)-1; /* invalid value */
613 to->u.ssl3.clAuthSeries = 0;
614 to->u.ssl3.clAuthValid = PR_FALSE;
616 if (from->u.ssl3.certIndex != -1 && pcce) {
617 SECItem derCert;
619 derCert.len = pcce->certLength;
620 derCert.data = pcce->cert;
622 to->peerCert = CERT_NewTempCertificate(dbHandle, &derCert, NULL,
623 PR_FALSE, PR_TRUE);
624 if (to->peerCert == NULL)
625 goto loser;
629 to->version = from->version;
630 to->creationTime = from->creationTime;
631 to->lastAccessTime = from->lastAccessTime;
632 to->expirationTime = from->expirationTime;
633 to->cached = in_server_cache;
634 to->addr = from->addr;
635 to->references = 1;
636 to->authAlgorithm = from->authAlgorithm;
637 to->authKeyBits = from->authKeyBits;
638 to->keaType = from->keaType;
639 to->keaKeyBits = from->keaKeyBits;
641 return to;
643 loser:
644 if (to) {
645 if (version < SSL_LIBRARY_VERSION_3_0) {
646 if (to->u.ssl2.masterKey.data)
647 PORT_Free(to->u.ssl2.masterKey.data);
648 if (to->u.ssl2.cipherArg.data)
649 PORT_Free(to->u.ssl2.cipherArg.data);
650 } else {
651 SECITEM_FreeItem(&to->u.ssl3.srvName, PR_FALSE);
653 PORT_Free(to);
655 return NULL;
661 ** Perform some mumbo jumbo on the ip-address and the session-id value to
662 ** compute a hash value.
664 static PRUint32
665 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl)
667 PRUint32 rv;
668 PRUint32 x[8];
670 memset(x, 0, sizeof x);
671 if (nl > sizeof x)
672 nl = sizeof x;
673 memcpy(x, s, nl);
675 rv = (addr->pr_s6_addr32[0] ^ addr->pr_s6_addr32[1] ^
676 addr->pr_s6_addr32[2] ^ addr->pr_s6_addr32[3] ^
677 x[0] ^ x[1] ^ x[2] ^ x[3] ^ x[4] ^ x[5] ^ x[6] ^ x[7])
678 % cache->numSIDCacheSets;
679 return rv;
685 ** Look something up in the cache. This will invalidate old entries
686 ** in the process. Caller has locked the cache set!
687 ** Returns PR_TRUE if found a valid match. PR_FALSE otherwise.
689 static sidCacheEntry *
690 FindSID(cacheDesc *cache, PRUint32 setNum, PRUint32 now,
691 const PRIPv6Addr *addr, unsigned char *sessionID,
692 unsigned sessionIDLength)
694 PRUint32 ndx = cache->sidCacheSets[setNum].next;
695 int i;
697 sidCacheEntry * set = cache->sidCacheData +
698 (setNum * SID_CACHE_ENTRIES_PER_SET);
700 for (i = SID_CACHE_ENTRIES_PER_SET; i > 0; --i) {
701 sidCacheEntry * sce;
703 ndx = (ndx - 1) % SID_CACHE_ENTRIES_PER_SET;
704 sce = set + ndx;
706 if (!sce->valid)
707 continue;
709 if (now > sce->expirationTime) {
710 /* SessionID has timed out. Invalidate the entry. */
711 SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x "
712 "time+=%x",
713 myPid, sce->addr.pr_s6_addr32[0],
714 sce->addr.pr_s6_addr32[1], sce->addr.pr_s6_addr32[2],
715 sce->addr.pr_s6_addr32[3], now,
716 sce->expirationTime ));
717 sce->valid = 0;
718 continue;
722 ** Next, examine specific session-id/addr data to see if the cache
723 ** entry matches our addr+session-id value
725 if (sessionIDLength == sce->sessionIDLength &&
726 !memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) &&
727 !memcmp(sce->sessionID, sessionID, sessionIDLength)) {
728 /* Found it */
729 return sce;
733 PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
734 return NULL;
737 /************************************************************************/
739 /* This is the primary function for finding entries in the server's sid cache.
740 * Although it is static, this function is called via the global function
741 * pointer ssl_sid_lookup.
743 static sslSessionID *
744 ServerSessionIDLookup(const PRIPv6Addr *addr,
745 unsigned char *sessionID,
746 unsigned int sessionIDLength,
747 CERTCertDBHandle * dbHandle)
749 sslSessionID * sid = 0;
750 sidCacheEntry * psce;
751 certCacheEntry *pcce = 0;
752 srvNameCacheEntry *psnce = 0;
753 cacheDesc * cache = &globalCache;
754 PRUint32 now;
755 PRUint32 set;
756 PRInt32 cndx;
757 sidCacheEntry sce;
758 certCacheEntry cce;
759 srvNameCacheEntry snce;
761 set = SIDindex(cache, addr, sessionID, sessionIDLength);
762 now = LockSet(cache, set, 0);
763 if (!now)
764 return NULL;
766 psce = FindSID(cache, set, now, addr, sessionID, sessionIDLength);
767 if (psce) {
768 if (psce->version >= SSL_LIBRARY_VERSION_3_0) {
769 if ((cndx = psce->u.ssl3.certIndex) != -1) {
771 PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now);
772 if (gotLock) {
773 pcce = &cache->certCacheData[cndx];
775 /* See if the cert's session ID matches the sce cache. */
776 if ((pcce->sessionIDLength == psce->sessionIDLength) &&
777 !PORT_Memcmp(pcce->sessionID, psce->sessionID,
778 pcce->sessionIDLength)) {
779 cce = *pcce;
780 } else {
781 /* The cert doesen't match the SID cache entry,
782 ** so invalidate the SID cache entry.
784 psce->valid = 0;
785 psce = 0;
786 pcce = 0;
788 UnlockSidCacheLock(cache->certCacheLock);
789 } else {
790 /* what the ??. Didn't get the cert cache lock.
791 ** Don't invalidate the SID cache entry, but don't find it.
793 PORT_Assert(!("Didn't get cert Cache Lock!"));
794 psce = 0;
795 pcce = 0;
798 if (psce && ((cndx = psce->u.ssl3.srvNameIndex) != -1)) {
799 PRUint32 gotLock = LockSidCacheLock(cache->srvNameCacheLock,
800 now);
801 if (gotLock) {
802 psnce = &cache->srvNameCacheData[cndx];
804 if (!PORT_Memcmp(psnce->nameHash, psce->u.ssl3.srvNameHash,
805 SHA256_LENGTH)) {
806 snce = *psnce;
807 } else {
808 /* The name doesen't match the SID cache entry,
809 ** so invalidate the SID cache entry.
811 psce->valid = 0;
812 psce = 0;
813 psnce = 0;
815 UnlockSidCacheLock(cache->srvNameCacheLock);
816 } else {
817 /* what the ??. Didn't get the cert cache lock.
818 ** Don't invalidate the SID cache entry, but don't find it.
820 PORT_Assert(!("Didn't get name Cache Lock!"));
821 psce = 0;
822 psnce = 0;
827 if (psce) {
828 psce->lastAccessTime = now;
829 sce = *psce; /* grab a copy while holding the lock */
832 UnlockSet(cache, set);
833 if (psce) {
834 /* sce conains a copy of the cache entry.
835 ** Convert shared memory format to local format
837 sid = ConvertToSID(&sce, pcce ? &cce : 0, psnce ? &snce : 0, dbHandle);
839 return sid;
843 ** Place a sid into the cache, if it isn't already there.
845 static void
846 ServerSessionIDCache(sslSessionID *sid)
848 sidCacheEntry sce;
849 PRUint32 now = 0;
850 PRUint16 version = sid->version;
851 cacheDesc * cache = &globalCache;
853 if ((version >= SSL_LIBRARY_VERSION_3_0) &&
854 (sid->u.ssl3.sessionIDLength == 0)) {
855 return;
858 if (sid->cached == never_cached || sid->cached == invalid_cache) {
859 PRUint32 set;
861 PORT_Assert(sid->creationTime != 0);
862 if (!sid->creationTime)
863 sid->lastAccessTime = sid->creationTime = ssl_Time();
864 if (version < SSL_LIBRARY_VERSION_3_0) {
865 /* override caller's expiration time, which uses client timeout
866 * duration, not server timeout duration.
868 sid->expirationTime = sid->creationTime + cache->ssl2Timeout;
869 SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
870 "cipher=%d", myPid, sid->cached,
871 sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
872 sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
873 sid->creationTime, sid->u.ssl2.cipherType));
874 PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID,
875 SSL2_SESSIONID_BYTES));
876 PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
877 sid->u.ssl2.masterKey.len));
878 PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
879 sid->u.ssl2.cipherArg.len));
881 } else {
882 /* override caller's expiration time, which uses client timeout
883 * duration, not server timeout duration.
885 sid->expirationTime = sid->creationTime + cache->ssl3Timeout;
886 SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
887 "cipherSuite=%d", myPid, sid->cached,
888 sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
889 sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
890 sid->creationTime, sid->u.ssl3.cipherSuite));
891 PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID,
892 sid->u.ssl3.sessionIDLength));
895 ConvertFromSID(&sce, sid);
897 if (version >= SSL_LIBRARY_VERSION_3_0) {
898 SECItem *name = &sid->u.ssl3.srvName;
899 if (name->len && name->data) {
900 now = CacheSrvName(cache, name, &sce);
902 if (sid->peerCert != NULL) {
903 now = CacheCert(cache, sid->peerCert, &sce);
907 set = SIDindex(cache, &sce.addr, sce.sessionID, sce.sessionIDLength);
908 now = LockSet(cache, set, now);
909 if (now) {
910 PRUint32 next = cache->sidCacheSets[set].next;
911 PRUint32 ndx = set * SID_CACHE_ENTRIES_PER_SET + next;
913 /* Write out new cache entry */
914 cache->sidCacheData[ndx] = sce;
916 cache->sidCacheSets[set].next =
917 (next + 1) % SID_CACHE_ENTRIES_PER_SET;
919 UnlockSet(cache, set);
920 sid->cached = in_server_cache;
926 ** Although this is static, it is called from ssl via global function pointer
927 ** ssl_sid_uncache. This invalidates the referenced cache entry.
929 static void
930 ServerSessionIDUncache(sslSessionID *sid)
932 cacheDesc * cache = &globalCache;
933 PRUint8 * sessionID;
934 unsigned int sessionIDLength;
935 PRErrorCode err;
936 PRUint32 set;
937 PRUint32 now;
938 sidCacheEntry *psce;
940 if (sid == NULL)
941 return;
943 /* Uncaching a SID should never change the error code.
944 ** So save it here and restore it before exiting.
946 err = PR_GetError();
948 if (sid->version < SSL_LIBRARY_VERSION_3_0) {
949 sessionID = sid->u.ssl2.sessionID;
950 sessionIDLength = SSL2_SESSIONID_BYTES;
951 SSL_TRC(8, ("%d: SSL: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
952 "cipher=%d", myPid, sid->cached,
953 sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
954 sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
955 sid->creationTime, sid->u.ssl2.cipherType));
956 PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
957 PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
958 sid->u.ssl2.masterKey.len));
959 PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
960 sid->u.ssl2.cipherArg.len));
961 } else {
962 sessionID = sid->u.ssl3.sessionID;
963 sessionIDLength = sid->u.ssl3.sessionIDLength;
964 SSL_TRC(8, ("%d: SSL3: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
965 "cipherSuite=%d", myPid, sid->cached,
966 sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
967 sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
968 sid->creationTime, sid->u.ssl3.cipherSuite));
969 PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
971 set = SIDindex(cache, &sid->addr, sessionID, sessionIDLength);
972 now = LockSet(cache, set, 0);
973 if (now) {
974 psce = FindSID(cache, set, now, &sid->addr, sessionID, sessionIDLength);
975 if (psce) {
976 psce->valid = 0;
978 UnlockSet(cache, set);
980 sid->cached = invalid_cache;
981 PORT_SetError(err);
984 #ifdef XP_OS2
986 #define INCL_DOSPROCESS
987 #include <os2.h>
989 long gettid(void)
991 PTIB ptib;
992 PPIB ppib;
993 DosGetInfoBlocks(&ptib, &ppib);
994 return ((long)ptib->tib_ordinal); /* thread id */
996 #endif
998 static void
999 CloseCache(cacheDesc *cache)
1001 int locks_initialized = cache->numSIDCacheLocksInitialized;
1003 if (cache->cacheMem) {
1004 if (cache->sharedCache) {
1005 sidCacheLock *pLock = cache->sidCacheLocks;
1006 for (; locks_initialized > 0; --locks_initialized, ++pLock ) {
1007 /* If everInherited is true, this shared cache was (and may
1008 ** still be) in use by multiple processes. We do not wish to
1009 ** destroy the mutexes while they are still in use, but we do
1010 ** want to free mutex resources associated with this process.
1012 sslMutex_Destroy(&pLock->mutex,
1013 cache->sharedCache->everInherited);
1016 if (cache->shared) {
1017 PR_MemUnmap(cache->cacheMem, cache->cacheMemSize);
1018 } else {
1019 PORT_Free(cache->cacheMem);
1021 cache->cacheMem = NULL;
1023 if (cache->cacheMemMap) {
1024 PR_CloseFileMap(cache->cacheMemMap);
1025 cache->cacheMemMap = NULL;
1027 memset(cache, 0, sizeof *cache);
1030 static SECStatus
1031 InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries,
1032 int maxSrvNameCacheEntries, PRUint32 ssl2_timeout,
1033 PRUint32 ssl3_timeout, const char *directory, PRBool shared)
1035 ptrdiff_t ptr;
1036 sidCacheLock *pLock;
1037 char * cacheMem;
1038 PRFileMap * cacheMemMap;
1039 char * cfn = NULL; /* cache file name */
1040 int locks_initialized = 0;
1041 int locks_to_initialize = 0;
1042 PRUint32 init_time;
1044 if ( (!cache) || (maxCacheEntries < 0) || (!directory) ) {
1045 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1046 return SECFailure;
1049 if (cache->cacheMem) {
1050 /* Already done */
1051 return SECSuccess;
1054 /* make sure loser can clean up properly */
1055 cache->shared = shared;
1056 cache->cacheMem = cacheMem = NULL;
1057 cache->cacheMemMap = cacheMemMap = NULL;
1058 cache->sharedCache = (cacheDesc *)0;
1060 cache->numSIDCacheLocksInitialized = 0;
1061 cache->nextCertCacheEntry = 0;
1062 cache->stopPolling = PR_FALSE;
1063 cache->everInherited = PR_FALSE;
1064 cache->poller = NULL;
1065 cache->mutexTimeout = 0;
1067 cache->numSIDCacheEntries = maxCacheEntries ? maxCacheEntries
1068 : DEF_SID_CACHE_ENTRIES;
1069 cache->numSIDCacheSets =
1070 SID_HOWMANY(cache->numSIDCacheEntries, SID_CACHE_ENTRIES_PER_SET);
1072 cache->numSIDCacheEntries =
1073 cache->numSIDCacheSets * SID_CACHE_ENTRIES_PER_SET;
1075 cache->numSIDCacheLocks =
1076 PR_MIN(cache->numSIDCacheSets, ssl_max_sid_cache_locks);
1078 cache->numSIDCacheSetsPerLock =
1079 SID_HOWMANY(cache->numSIDCacheSets, cache->numSIDCacheLocks);
1081 cache->numCertCacheEntries = (maxCertCacheEntries > 0) ?
1082 maxCertCacheEntries : 0;
1083 cache->numSrvNameCacheEntries = (maxSrvNameCacheEntries >= 0) ?
1084 maxSrvNameCacheEntries : DEF_NAME_CACHE_ENTRIES;
1086 /* compute size of shared memory, and offsets of all pointers */
1087 ptr = 0;
1088 cache->cacheMem = (char *)ptr;
1089 ptr += SID_ROUNDUP(sizeof(cacheDesc), SID_ALIGNMENT);
1091 cache->sidCacheLocks = (sidCacheLock *)ptr;
1092 cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks;
1093 cache->certCacheLock = cache->keyCacheLock + 1;
1094 cache->srvNameCacheLock = cache->certCacheLock + 1;
1095 ptr = (ptrdiff_t)(cache->srvNameCacheLock + 1);
1096 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1098 cache->sidCacheSets = (sidCacheSet *)ptr;
1099 ptr = (ptrdiff_t)(cache->sidCacheSets + cache->numSIDCacheSets);
1100 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1102 cache->sidCacheData = (sidCacheEntry *)ptr;
1103 ptr = (ptrdiff_t)(cache->sidCacheData + cache->numSIDCacheEntries);
1104 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1106 cache->certCacheData = (certCacheEntry *)ptr;
1107 cache->sidCacheSize =
1108 (char *)cache->certCacheData - (char *)cache->sidCacheData;
1110 if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) {
1111 /* This is really a poor way to computer this! */
1112 cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry);
1113 if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES)
1114 cache->numCertCacheEntries = MIN_CERT_CACHE_ENTRIES;
1116 ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries);
1117 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1119 cache->keyCacheData = (SSLWrappedSymWrappingKey *)ptr;
1120 cache->certCacheSize =
1121 (char *)cache->keyCacheData - (char *)cache->certCacheData;
1123 cache->numKeyCacheEntries = kt_kea_size * SSL_NUM_WRAP_MECHS;
1124 ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries);
1125 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1127 cache->keyCacheSize = (char *)ptr - (char *)cache->keyCacheData;
1129 cache->ticketKeyNameSuffix = (PRUint8 *)ptr;
1130 ptr = (ptrdiff_t)(cache->ticketKeyNameSuffix +
1131 SESS_TICKET_KEY_VAR_NAME_LEN);
1132 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1134 cache->ticketEncKey = (encKeyCacheEntry *)ptr;
1135 ptr = (ptrdiff_t)(cache->ticketEncKey + 1);
1136 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1138 cache->ticketMacKey = (encKeyCacheEntry *)ptr;
1139 ptr = (ptrdiff_t)(cache->ticketMacKey + 1);
1140 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1142 cache->ticketKeysValid = (PRUint32 *)ptr;
1143 ptr = (ptrdiff_t)(cache->ticketKeysValid + 1);
1144 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1146 cache->srvNameCacheData = (srvNameCacheEntry *)ptr;
1147 cache->srvNameCacheSize =
1148 cache->numSrvNameCacheEntries * sizeof(srvNameCacheEntry);
1149 ptr = (ptrdiff_t)(cache->srvNameCacheData + cache->numSrvNameCacheEntries);
1150 ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
1152 cache->cacheMemSize = ptr;
1154 if (ssl2_timeout) {
1155 if (ssl2_timeout > MAX_SSL2_TIMEOUT) {
1156 ssl2_timeout = MAX_SSL2_TIMEOUT;
1158 if (ssl2_timeout < MIN_SSL2_TIMEOUT) {
1159 ssl2_timeout = MIN_SSL2_TIMEOUT;
1161 cache->ssl2Timeout = ssl2_timeout;
1162 } else {
1163 cache->ssl2Timeout = DEF_SSL2_TIMEOUT;
1166 if (ssl3_timeout) {
1167 if (ssl3_timeout > MAX_SSL3_TIMEOUT) {
1168 ssl3_timeout = MAX_SSL3_TIMEOUT;
1170 if (ssl3_timeout < MIN_SSL3_TIMEOUT) {
1171 ssl3_timeout = MIN_SSL3_TIMEOUT;
1173 cache->ssl3Timeout = ssl3_timeout;
1174 } else {
1175 cache->ssl3Timeout = DEF_SSL3_TIMEOUT;
1178 if (shared) {
1179 /* Create file names */
1180 #if defined(XP_UNIX) || defined(XP_BEOS)
1181 /* there's some confusion here about whether PR_OpenAnonFileMap wants
1182 ** a directory name or a file name for its first argument.
1183 cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid);
1185 cfn = PR_smprintf("%s", directory);
1186 #elif defined(XP_WIN32)
1187 cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid,
1188 GetCurrentThreadId());
1189 #elif defined(XP_OS2)
1190 cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid,
1191 gettid());
1192 #else
1193 #error "Don't know how to create file name for this platform!"
1194 #endif
1195 if (!cfn) {
1196 goto loser;
1199 /* Create cache */
1200 cacheMemMap = PR_OpenAnonFileMap(cfn, cache->cacheMemSize,
1201 PR_PROT_READWRITE);
1203 PR_smprintf_free(cfn);
1204 if(!cacheMemMap) {
1205 goto loser;
1208 cacheMem = PR_MemMap(cacheMemMap, 0, cache->cacheMemSize);
1209 } else {
1210 cacheMem = PORT_Alloc(cache->cacheMemSize);
1213 if (! cacheMem) {
1214 goto loser;
1217 /* Initialize shared memory. This may not be necessary on all platforms */
1218 memset(cacheMem, 0, cache->cacheMemSize);
1220 /* Copy cache descriptor header into shared memory */
1221 memcpy(cacheMem, cache, sizeof *cache);
1223 /* save private copies of these values */
1224 cache->cacheMemMap = cacheMemMap;
1225 cache->cacheMem = cacheMem;
1226 cache->sharedCache = (cacheDesc *)cacheMem;
1228 /* Fix pointers in our private copy of cache descriptor to point to
1229 ** spaces in shared memory
1231 ptr = (ptrdiff_t)cache->cacheMem;
1232 *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
1233 *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
1234 *(ptrdiff_t *)(&cache->certCacheLock) += ptr;
1235 *(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr;
1236 *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
1237 *(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
1238 *(ptrdiff_t *)(&cache->certCacheData) += ptr;
1239 *(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
1240 *(ptrdiff_t *)(&cache->ticketKeyNameSuffix) += ptr;
1241 *(ptrdiff_t *)(&cache->ticketEncKey ) += ptr;
1242 *(ptrdiff_t *)(&cache->ticketMacKey ) += ptr;
1243 *(ptrdiff_t *)(&cache->ticketKeysValid) += ptr;
1244 *(ptrdiff_t *)(&cache->srvNameCacheData) += ptr;
1246 /* initialize the locks */
1247 init_time = ssl_Time();
1248 pLock = cache->sidCacheLocks;
1249 for (locks_to_initialize = cache->numSIDCacheLocks + 3;
1250 locks_initialized < locks_to_initialize;
1251 ++locks_initialized, ++pLock ) {
1253 SECStatus err = sslMutex_Init(&pLock->mutex, shared);
1254 if (err) {
1255 cache->numSIDCacheLocksInitialized = locks_initialized;
1256 goto loser;
1258 pLock->timeStamp = init_time;
1259 pLock->pid = 0;
1261 cache->numSIDCacheLocksInitialized = locks_initialized;
1263 return SECSuccess;
1265 loser:
1266 CloseCache(cache);
1267 return SECFailure;
1270 PRUint32
1271 SSL_GetMaxServerCacheLocks(void)
1273 return ssl_max_sid_cache_locks + 2;
1274 /* The extra two are the cert cache lock and the key cache lock. */
1277 SECStatus
1278 SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
1280 /* Minimum is 1 sid cache lock, 1 cert cache lock and 1 key cache lock.
1281 ** We'd like to test for a maximum value, but not all platforms' header
1282 ** files provide a symbol or function or other means of determining
1283 ** the maximum, other than trial and error.
1285 if (maxLocks < 3) {
1286 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1287 return SECFailure;
1289 ssl_max_sid_cache_locks = maxLocks - 2;
1290 /* The extra two are the cert cache lock and the key cache lock. */
1291 return SECSuccess;
1294 static SECStatus
1295 ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache,
1296 PRUint32 ssl2_timeout,
1297 PRUint32 ssl3_timeout,
1298 const char * directory,
1299 PRBool shared,
1300 int maxCacheEntries,
1301 int maxCertCacheEntries,
1302 int maxSrvNameCacheEntries)
1304 SECStatus rv;
1306 PORT_Assert(sizeof(sidCacheEntry) == 192);
1307 PORT_Assert(sizeof(certCacheEntry) == 4096);
1308 PORT_Assert(sizeof(srvNameCacheEntry) == 1072);
1310 rv = ssl_Init();
1311 if (rv != SECSuccess) {
1312 return rv;
1315 myPid = SSL_GETPID();
1316 if (!directory) {
1317 directory = DEFAULT_CACHE_DIRECTORY;
1319 rv = InitCache(cache, maxCacheEntries, maxCertCacheEntries,
1320 maxSrvNameCacheEntries, ssl2_timeout, ssl3_timeout,
1321 directory, shared);
1322 if (rv) {
1323 SET_ERROR_CODE
1324 return SECFailure;
1327 ssl_sid_lookup = ServerSessionIDLookup;
1328 ssl_sid_cache = ServerSessionIDCache;
1329 ssl_sid_uncache = ServerSessionIDUncache;
1330 return SECSuccess;
1333 SECStatus
1334 SSL_ConfigServerSessionIDCacheInstance( cacheDesc *cache,
1335 int maxCacheEntries,
1336 PRUint32 ssl2_timeout,
1337 PRUint32 ssl3_timeout,
1338 const char * directory, PRBool shared)
1340 return ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
1341 ssl2_timeout,
1342 ssl3_timeout,
1343 directory,
1344 shared,
1345 maxCacheEntries,
1346 -1, -1);
1349 SECStatus
1350 SSL_ConfigServerSessionIDCache( int maxCacheEntries,
1351 PRUint32 ssl2_timeout,
1352 PRUint32 ssl3_timeout,
1353 const char * directory)
1355 ssl_InitSessionCacheLocks();
1356 return SSL_ConfigServerSessionIDCacheInstance(&globalCache,
1357 maxCacheEntries, ssl2_timeout, ssl3_timeout, directory, PR_FALSE);
1360 SECStatus
1361 SSL_ShutdownServerSessionIDCacheInstance(cacheDesc *cache)
1363 CloseCache(cache);
1364 return SECSuccess;
1367 SECStatus
1368 SSL_ShutdownServerSessionIDCache(void)
1370 #if defined(XP_UNIX) || defined(XP_BEOS)
1371 /* Stop the thread that polls cache for expired locks on Unix */
1372 StopLockPoller(&globalCache);
1373 #endif
1374 SSL3_ShutdownServerCache();
1375 return SSL_ShutdownServerSessionIDCacheInstance(&globalCache);
1378 /* Use this function, instead of SSL_ConfigServerSessionIDCache,
1379 * if the cache will be shared by multiple processes.
1381 static SECStatus
1382 ssl_ConfigMPServerSIDCacheWithOpt( PRUint32 ssl2_timeout,
1383 PRUint32 ssl3_timeout,
1384 const char * directory,
1385 int maxCacheEntries,
1386 int maxCertCacheEntries,
1387 int maxSrvNameCacheEntries)
1389 char * envValue;
1390 char * inhValue;
1391 cacheDesc * cache = &globalCache;
1392 PRUint32 fmStrLen;
1393 SECStatus result;
1394 PRStatus prStatus;
1395 SECStatus putEnvFailed;
1396 inheritance inherit;
1397 char fmString[PR_FILEMAP_STRING_BUFSIZE];
1399 isMultiProcess = PR_TRUE;
1400 result = ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
1401 ssl2_timeout, ssl3_timeout, directory, PR_TRUE,
1402 maxCacheEntries, maxCacheEntries, maxSrvNameCacheEntries);
1403 if (result != SECSuccess)
1404 return result;
1406 prStatus = PR_ExportFileMapAsString(cache->cacheMemMap,
1407 sizeof fmString, fmString);
1408 if ((prStatus != PR_SUCCESS) || !(fmStrLen = strlen(fmString))) {
1409 SET_ERROR_CODE
1410 return SECFailure;
1413 inherit.cacheMemSize = cache->cacheMemSize;
1414 inherit.fmStrLen = fmStrLen;
1416 inhValue = BTOA_DataToAscii((unsigned char *)&inherit, sizeof inherit);
1417 if (!inhValue || !strlen(inhValue)) {
1418 SET_ERROR_CODE
1419 return SECFailure;
1421 envValue = PR_smprintf("%s,%s", inhValue, fmString);
1422 if (!envValue || !strlen(envValue)) {
1423 SET_ERROR_CODE
1424 return SECFailure;
1426 PORT_Free(inhValue);
1428 putEnvFailed = (SECStatus)NSS_PutEnv(envVarName, envValue);
1429 PR_smprintf_free(envValue);
1430 if (putEnvFailed) {
1431 SET_ERROR_CODE
1432 result = SECFailure;
1435 #if defined(XP_UNIX) || defined(XP_BEOS)
1436 /* Launch thread to poll cache for expired locks on Unix */
1437 LaunchLockPoller(cache);
1438 #endif
1439 return result;
1442 /* Use this function, instead of SSL_ConfigServerSessionIDCache,
1443 * if the cache will be shared by multiple processes.
1445 SECStatus
1446 SSL_ConfigMPServerSIDCache( int maxCacheEntries,
1447 PRUint32 ssl2_timeout,
1448 PRUint32 ssl3_timeout,
1449 const char * directory)
1451 return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout,
1452 ssl3_timeout,
1453 directory,
1454 maxCacheEntries,
1455 -1, -1);
1458 SECStatus
1459 SSL_ConfigServerSessionIDCacheWithOpt(
1460 PRUint32 ssl2_timeout,
1461 PRUint32 ssl3_timeout,
1462 const char * directory,
1463 int maxCacheEntries,
1464 int maxCertCacheEntries,
1465 int maxSrvNameCacheEntries,
1466 PRBool enableMPCache)
1468 if (!enableMPCache) {
1469 ssl_InitSessionCacheLocks();
1470 return ssl_ConfigServerSessionIDCacheInstanceWithOpt(&globalCache,
1471 ssl2_timeout, ssl3_timeout, directory, PR_FALSE,
1472 maxCacheEntries, maxCertCacheEntries, maxSrvNameCacheEntries);
1473 } else {
1474 return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout, ssl3_timeout,
1475 directory, maxCacheEntries, maxCertCacheEntries,
1476 maxSrvNameCacheEntries);
1480 SECStatus
1481 SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
1483 unsigned char * decoString = NULL;
1484 char * fmString = NULL;
1485 char * myEnvString = NULL;
1486 unsigned int decoLen;
1487 ptrdiff_t ptr;
1488 inheritance inherit;
1489 cacheDesc my;
1490 #ifdef WINNT
1491 sidCacheLock* newLocks;
1492 int locks_initialized = 0;
1493 int locks_to_initialize = 0;
1494 #endif
1495 SECStatus status = ssl_Init();
1497 if (status != SECSuccess) {
1498 return status;
1501 myPid = SSL_GETPID();
1503 /* If this child was created by fork(), and not by exec() on unix,
1504 ** then isMultiProcess will already be set.
1505 ** If not, we'll set it below.
1507 if (isMultiProcess) {
1508 if (cache && cache->sharedCache) {
1509 cache->sharedCache->everInherited = PR_TRUE;
1511 return SECSuccess; /* already done. */
1514 ssl_InitSessionCacheLocks();
1516 ssl_sid_lookup = ServerSessionIDLookup;
1517 ssl_sid_cache = ServerSessionIDCache;
1518 ssl_sid_uncache = ServerSessionIDUncache;
1520 if (!envString) {
1521 envString = getenv(envVarName);
1522 if (!envString) {
1523 SET_ERROR_CODE
1524 return SECFailure;
1527 myEnvString = PORT_Strdup(envString);
1528 if (!myEnvString)
1529 return SECFailure;
1530 fmString = strchr(myEnvString, ',');
1531 if (!fmString)
1532 goto loser;
1533 *fmString++ = 0;
1535 decoString = ATOB_AsciiToData(myEnvString, &decoLen);
1536 if (!decoString) {
1537 SET_ERROR_CODE
1538 goto loser;
1540 if (decoLen != sizeof inherit) {
1541 SET_ERROR_CODE
1542 goto loser;
1545 PORT_Memcpy(&inherit, decoString, sizeof inherit);
1547 if (strlen(fmString) != inherit.fmStrLen ) {
1548 goto loser;
1551 memset(cache, 0, sizeof *cache);
1552 cache->cacheMemSize = inherit.cacheMemSize;
1554 /* Create cache */
1555 cache->cacheMemMap = PR_ImportFileMapFromString(fmString);
1556 if(! cache->cacheMemMap) {
1557 goto loser;
1559 cache->cacheMem = PR_MemMap(cache->cacheMemMap, 0, cache->cacheMemSize);
1560 if (! cache->cacheMem) {
1561 goto loser;
1563 cache->sharedCache = (cacheDesc *)cache->cacheMem;
1565 if (cache->sharedCache->cacheMemSize != cache->cacheMemSize) {
1566 SET_ERROR_CODE
1567 goto loser;
1570 /* We're now going to overwrite the local cache instance with the
1571 ** shared copy of the cache struct, then update several values in
1572 ** the local cache using the values for cache->cacheMemMap and
1573 ** cache->cacheMem computed just above. So, we copy cache into
1574 ** the automatic variable "my", to preserve the variables while
1575 ** cache is overwritten.
1577 my = *cache; /* save values computed above. */
1578 memcpy(cache, cache->sharedCache, sizeof *cache); /* overwrite */
1580 /* Fix pointers in our private copy of cache descriptor to point to
1581 ** spaces in shared memory, whose address is now in "my".
1583 ptr = (ptrdiff_t)my.cacheMem;
1584 *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
1585 *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
1586 *(ptrdiff_t *)(&cache->certCacheLock) += ptr;
1587 *(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr;
1588 *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
1589 *(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
1590 *(ptrdiff_t *)(&cache->certCacheData) += ptr;
1591 *(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
1592 *(ptrdiff_t *)(&cache->ticketKeyNameSuffix) += ptr;
1593 *(ptrdiff_t *)(&cache->ticketEncKey ) += ptr;
1594 *(ptrdiff_t *)(&cache->ticketMacKey ) += ptr;
1595 *(ptrdiff_t *)(&cache->ticketKeysValid) += ptr;
1596 *(ptrdiff_t *)(&cache->srvNameCacheData) += ptr;
1598 cache->cacheMemMap = my.cacheMemMap;
1599 cache->cacheMem = my.cacheMem;
1600 cache->sharedCache = (cacheDesc *)cache->cacheMem;
1602 #ifdef WINNT
1603 /* On Windows NT we need to "fix" the sidCacheLocks here to support fibers
1604 ** When NT fibers are used in a multi-process server, a second level of
1605 ** locking is needed to prevent a deadlock, in case a fiber acquires the
1606 ** cross-process mutex, yields, and another fiber is later scheduled on
1607 ** the same native thread and tries to acquire the cross-process mutex.
1608 ** We do this by using a PRLock in the sslMutex. However, it is stored in
1609 ** shared memory as part of sidCacheLocks, and we don't want to overwrite
1610 ** the PRLock of the parent process. So we need to make new, private
1611 ** copies of sidCacheLocks before modifying the sslMutex with our own
1612 ** PRLock
1615 /* note from jpierre : this should be free'd in child processes when
1616 ** a function is added to delete the SSL session cache in the future.
1618 locks_to_initialize = cache->numSIDCacheLocks + 3;
1619 newLocks = PORT_NewArray(sidCacheLock, locks_to_initialize);
1620 if (!newLocks)
1621 goto loser;
1622 /* copy the old locks */
1623 memcpy(newLocks, cache->sidCacheLocks,
1624 locks_to_initialize * sizeof(sidCacheLock));
1625 cache->sidCacheLocks = newLocks;
1626 /* fix the locks */
1627 for (; locks_initialized < locks_to_initialize; ++locks_initialized) {
1628 /* now, make a local PRLock in this sslMutex for this child process */
1629 SECStatus err;
1630 err = sslMutex_2LevelInit(&newLocks[locks_initialized].mutex);
1631 if (err != SECSuccess) {
1632 cache->numSIDCacheLocksInitialized = locks_initialized;
1633 goto loser;
1636 cache->numSIDCacheLocksInitialized = locks_initialized;
1638 /* also fix the key and cert cache which use the last 2 lock entries */
1639 cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks;
1640 cache->certCacheLock = cache->keyCacheLock + 1;
1641 cache->srvNameCacheLock = cache->certCacheLock + 1;
1642 #endif
1644 PORT_Free(myEnvString);
1645 PORT_Free(decoString);
1647 /* mark that we have inherited this. */
1648 cache->sharedCache->everInherited = PR_TRUE;
1649 isMultiProcess = PR_TRUE;
1651 return SECSuccess;
1653 loser:
1654 PORT_Free(myEnvString);
1655 if (decoString)
1656 PORT_Free(decoString);
1657 CloseCache(cache);
1658 return SECFailure;
1661 SECStatus
1662 SSL_InheritMPServerSIDCache(const char * envString)
1664 return SSL_InheritMPServerSIDCacheInstance(&globalCache, envString);
1667 #if defined(XP_UNIX) || defined(XP_BEOS)
1669 #define SID_LOCK_EXPIRATION_TIMEOUT 30 /* seconds */
1671 static void
1672 LockPoller(void * arg)
1674 cacheDesc * cache = (cacheDesc *)arg;
1675 cacheDesc * sharedCache = cache->sharedCache;
1676 sidCacheLock * pLock;
1677 PRIntervalTime timeout;
1678 PRUint32 now;
1679 PRUint32 then;
1680 int locks_polled = 0;
1681 int locks_to_poll = cache->numSIDCacheLocks + 2;
1682 PRUint32 expiration = cache->mutexTimeout;
1684 timeout = PR_SecondsToInterval(expiration);
1685 while(!sharedCache->stopPolling) {
1686 PR_Sleep(timeout);
1687 if (sharedCache->stopPolling)
1688 break;
1690 now = ssl_Time();
1691 then = now - expiration;
1692 for (pLock = cache->sidCacheLocks, locks_polled = 0;
1693 locks_to_poll > locks_polled && !sharedCache->stopPolling;
1694 ++locks_polled, ++pLock ) {
1695 pid_t pid;
1697 if (pLock->timeStamp < then &&
1698 pLock->timeStamp != 0 &&
1699 (pid = pLock->pid) != 0) {
1701 /* maybe we should try the lock? */
1702 int result = kill(pid, 0);
1703 if (result < 0 && errno == ESRCH) {
1704 SECStatus rv;
1705 /* No process exists by that pid any more.
1706 ** Treat this mutex as abandoned.
1708 pLock->timeStamp = now;
1709 pLock->pid = 0;
1710 rv = sslMutex_Unlock(&pLock->mutex);
1711 if (rv != SECSuccess) {
1712 /* Now what? */
1716 } /* end of loop over locks */
1717 } /* end of entire polling loop */
1720 /* Launch thread to poll cache for expired locks */
1721 static SECStatus
1722 LaunchLockPoller(cacheDesc *cache)
1724 const char * timeoutString;
1725 PRThread * pollerThread;
1727 cache->mutexTimeout = SID_LOCK_EXPIRATION_TIMEOUT;
1728 timeoutString = getenv("NSS_SSL_SERVER_CACHE_MUTEX_TIMEOUT");
1729 if (timeoutString) {
1730 long newTime = strtol(timeoutString, 0, 0);
1731 if (newTime == 0)
1732 return SECSuccess; /* application doesn't want poller thread */
1733 if (newTime > 0)
1734 cache->mutexTimeout = (PRUint32)newTime;
1735 /* if error (newTime < 0) ignore it and use default */
1738 pollerThread =
1739 PR_CreateThread(PR_USER_THREAD, LockPoller, cache, PR_PRIORITY_NORMAL,
1740 PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
1741 if (!pollerThread) {
1742 return SECFailure;
1744 cache->poller = pollerThread;
1745 return SECSuccess;
1748 /* Stop the thread that polls cache for expired locks */
1749 static SECStatus
1750 StopLockPoller(cacheDesc *cache)
1752 if (!cache->poller) {
1753 return SECSuccess;
1755 cache->sharedCache->stopPolling = PR_TRUE;
1756 if (PR_Interrupt(cache->poller) != PR_SUCCESS) {
1757 return SECFailure;
1759 if (PR_JoinThread(cache->poller) != PR_SUCCESS) {
1760 return SECFailure;
1762 cache->poller = NULL;
1763 return SECSuccess;
1765 #endif
1767 /************************************************************************
1768 * Code dealing with shared wrapped symmetric wrapping keys below *
1769 ************************************************************************/
1771 /* If now is zero, it implies that the lock is not held, and must be
1772 ** aquired here.
1774 static PRBool
1775 getSvrWrappingKey(PRInt32 symWrapMechIndex,
1776 SSL3KEAType exchKeyType,
1777 SSLWrappedSymWrappingKey *wswk,
1778 cacheDesc * cache,
1779 PRUint32 lockTime)
1781 PRUint32 ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
1782 SSLWrappedSymWrappingKey * pwswk = cache->keyCacheData + ndx;
1783 PRUint32 now = 0;
1784 PRBool rv = PR_FALSE;
1786 if (!cache->cacheMem) { /* cache is uninitialized */
1787 PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
1788 return rv;
1790 if (!lockTime) {
1791 lockTime = now = LockSidCacheLock(cache->keyCacheLock, now);
1792 if (!lockTime) {
1793 return rv;
1796 if (pwswk->exchKeyType == exchKeyType &&
1797 pwswk->symWrapMechIndex == symWrapMechIndex &&
1798 pwswk->wrappedSymKeyLen != 0) {
1799 *wswk = *pwswk;
1800 rv = PR_TRUE;
1802 if (now) {
1803 UnlockSidCacheLock(cache->keyCacheLock);
1805 return rv;
1808 PRBool
1809 ssl_GetWrappingKey( PRInt32 symWrapMechIndex,
1810 SSL3KEAType exchKeyType,
1811 SSLWrappedSymWrappingKey *wswk)
1813 PRBool rv;
1815 PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
1816 PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
1817 if ((unsigned)exchKeyType < kt_kea_size &&
1818 (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) {
1819 rv = getSvrWrappingKey(symWrapMechIndex, exchKeyType, wswk,
1820 &globalCache, 0);
1821 } else {
1822 rv = PR_FALSE;
1825 return rv;
1828 /* Wrap and cache a session ticket key. */
1829 static PRBool
1830 WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey,
1831 const char *keyName, encKeyCacheEntry* cacheEntry)
1833 SECItem wrappedKey = {siBuffer, NULL, 0};
1835 wrappedKey.len = SECKEY_PublicKeyStrength(svrPubKey);
1836 PORT_Assert(wrappedKey.len <= sizeof(cacheEntry->bytes));
1837 if (wrappedKey.len > sizeof(cacheEntry->bytes))
1838 return PR_FALSE;
1839 wrappedKey.data = cacheEntry->bytes;
1841 if (PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, symKey, &wrappedKey)
1842 != SECSuccess) {
1843 SSL_DBG(("%d: SSL[%s]: Unable to wrap session ticket %s.",
1844 SSL_GETPID(), "unknown", keyName));
1845 return PR_FALSE;
1847 cacheEntry->length = wrappedKey.len;
1848 return PR_TRUE;
1851 static PRBool
1852 GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey,
1853 PK11SymKey **macKey)
1855 PK11SlotInfo *slot;
1856 CK_MECHANISM_TYPE mechanismArray[2];
1857 PK11SymKey *aesKeyTmp = NULL;
1858 PK11SymKey *macKeyTmp = NULL;
1859 cacheDesc *cache = &globalCache;
1860 PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN];
1861 PRUint8 *ticketKeyNameSuffix;
1863 if (!cache->cacheMem) {
1864 /* cache is not initalized. Use stack buffer */
1865 ticketKeyNameSuffix = ticketKeyNameSuffixLocal;
1866 } else {
1867 ticketKeyNameSuffix = cache->ticketKeyNameSuffix;
1870 if (PK11_GenerateRandom(ticketKeyNameSuffix,
1871 SESS_TICKET_KEY_VAR_NAME_LEN) != SECSuccess) {
1872 SSL_DBG(("%d: SSL[%s]: Unable to generate random key name bytes.",
1873 SSL_GETPID(), "unknown"));
1874 goto loser;
1877 mechanismArray[0] = CKM_AES_CBC;
1878 mechanismArray[1] = CKM_SHA256_HMAC;
1880 slot = PK11_GetBestSlotMultiple(mechanismArray, 2, pwArg);
1881 if (slot) {
1882 aesKeyTmp = PK11_KeyGen(slot, mechanismArray[0], NULL,
1883 AES_256_KEY_LENGTH, pwArg);
1884 macKeyTmp = PK11_KeyGen(slot, mechanismArray[1], NULL,
1885 SHA256_LENGTH, pwArg);
1886 PK11_FreeSlot(slot);
1889 if (aesKeyTmp == NULL || macKeyTmp == NULL) {
1890 SSL_DBG(("%d: SSL[%s]: Unable to generate session ticket keys.",
1891 SSL_GETPID(), "unknown"));
1892 goto loser;
1894 PORT_Memcpy(keyName, ticketKeyNameSuffix, SESS_TICKET_KEY_VAR_NAME_LEN);
1895 *aesKey = aesKeyTmp;
1896 *macKey = macKeyTmp;
1897 return PR_TRUE;
1899 loser:
1900 if (aesKeyTmp)
1901 PK11_FreeSymKey(aesKeyTmp);
1902 if (macKeyTmp)
1903 PK11_FreeSymKey(macKeyTmp);
1904 return PR_FALSE;
1907 static PRBool
1908 GenerateAndWrapTicketKeys(SECKEYPublicKey *svrPubKey, void *pwArg,
1909 unsigned char *keyName, PK11SymKey **aesKey,
1910 PK11SymKey **macKey)
1912 PK11SymKey *aesKeyTmp = NULL;
1913 PK11SymKey *macKeyTmp = NULL;
1914 cacheDesc *cache = &globalCache;
1916 if (!GenerateTicketKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp)) {
1917 goto loser;
1920 if (cache->cacheMem) {
1921 /* Export the keys to the shared cache in wrapped form. */
1922 if (!WrapTicketKey(svrPubKey, aesKeyTmp, "enc key", cache->ticketEncKey))
1923 goto loser;
1924 if (!WrapTicketKey(svrPubKey, macKeyTmp, "mac key", cache->ticketMacKey))
1925 goto loser;
1927 *aesKey = aesKeyTmp;
1928 *macKey = macKeyTmp;
1929 return PR_TRUE;
1931 loser:
1932 if (aesKeyTmp)
1933 PK11_FreeSymKey(aesKeyTmp);
1934 if (macKeyTmp)
1935 PK11_FreeSymKey(macKeyTmp);
1936 return PR_FALSE;
1939 static PRBool
1940 UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName,
1941 PK11SymKey **aesKey, PK11SymKey **macKey)
1943 SECItem wrappedKey = {siBuffer, NULL, 0};
1944 PK11SymKey *aesKeyTmp = NULL;
1945 PK11SymKey *macKeyTmp = NULL;
1946 cacheDesc *cache = &globalCache;
1948 wrappedKey.data = cache->ticketEncKey->bytes;
1949 wrappedKey.len = cache->ticketEncKey->length;
1950 PORT_Assert(wrappedKey.len <= sizeof(cache->ticketEncKey->bytes));
1951 aesKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
1952 CKM_AES_CBC, CKA_DECRYPT, 0);
1954 wrappedKey.data = cache->ticketMacKey->bytes;
1955 wrappedKey.len = cache->ticketMacKey->length;
1956 PORT_Assert(wrappedKey.len <= sizeof(cache->ticketMacKey->bytes));
1957 macKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
1958 CKM_SHA256_HMAC, CKA_SIGN, 0);
1960 if (aesKeyTmp == NULL || macKeyTmp == NULL) {
1961 SSL_DBG(("%d: SSL[%s]: Unable to unwrap session ticket keys.",
1962 SSL_GETPID(), "unknown"));
1963 goto loser;
1965 SSL_DBG(("%d: SSL[%s]: Successfully unwrapped session ticket keys.",
1966 SSL_GETPID(), "unknown"));
1968 PORT_Memcpy(keyName, cache->ticketKeyNameSuffix,
1969 SESS_TICKET_KEY_VAR_NAME_LEN);
1970 *aesKey = aesKeyTmp;
1971 *macKey = macKeyTmp;
1972 return PR_TRUE;
1974 loser:
1975 if (aesKeyTmp)
1976 PK11_FreeSymKey(aesKeyTmp);
1977 if (macKeyTmp)
1978 PK11_FreeSymKey(macKeyTmp);
1979 return PR_FALSE;
1982 PRBool
1983 ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey,
1984 SECKEYPublicKey *svrPubKey, void *pwArg,
1985 unsigned char *keyName, PK11SymKey **aesKey,
1986 PK11SymKey **macKey)
1988 PRUint32 now = 0;
1989 PRBool rv = PR_FALSE;
1990 PRBool keysGenerated = PR_FALSE;
1991 cacheDesc *cache = &globalCache;
1993 if (!cache->cacheMem) {
1994 /* cache is uninitialized. Generate keys and return them
1995 * without caching. */
1996 return GenerateTicketKeys(pwArg, keyName, aesKey, macKey);
1999 now = LockSidCacheLock(cache->keyCacheLock, now);
2000 if (!now)
2001 return rv;
2003 if (!*(cache->ticketKeysValid)) {
2004 /* Keys do not exist, create them. */
2005 if (!GenerateAndWrapTicketKeys(svrPubKey, pwArg, keyName,
2006 aesKey, macKey))
2007 goto loser;
2008 keysGenerated = PR_TRUE;
2009 *(cache->ticketKeysValid) = 1;
2012 rv = PR_TRUE;
2014 loser:
2015 UnlockSidCacheLock(cache->keyCacheLock);
2016 if (rv && !keysGenerated)
2017 rv = UnwrapCachedTicketKeys(svrPrivKey, keyName, aesKey, macKey);
2018 return rv;
2021 PRBool
2022 ssl_GetSessionTicketKeys(unsigned char *keyName, unsigned char *encKey,
2023 unsigned char *macKey)
2025 PRBool rv = PR_FALSE;
2026 PRUint32 now = 0;
2027 cacheDesc *cache = &globalCache;
2028 PRUint8 ticketMacKey[SHA256_LENGTH], ticketEncKey[AES_256_KEY_LENGTH];
2029 PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN];
2030 PRUint8 *ticketMacKeyPtr, *ticketEncKeyPtr, *ticketKeyNameSuffix;
2031 PRBool cacheIsEnabled = PR_TRUE;
2033 if (!cache->cacheMem) { /* cache is uninitialized */
2034 cacheIsEnabled = PR_FALSE;
2035 ticketKeyNameSuffix = ticketKeyNameSuffixLocal;
2036 ticketEncKeyPtr = ticketEncKey;
2037 ticketMacKeyPtr = ticketMacKey;
2038 } else {
2039 /* these values have constant memory locations in the cache.
2040 * Ok to reference them without holding the lock. */
2041 ticketKeyNameSuffix = cache->ticketKeyNameSuffix;
2042 ticketEncKeyPtr = cache->ticketEncKey->bytes;
2043 ticketMacKeyPtr = cache->ticketMacKey->bytes;
2046 if (cacheIsEnabled) {
2047 /* Grab lock if initialized. */
2048 now = LockSidCacheLock(cache->keyCacheLock, now);
2049 if (!now)
2050 return rv;
2052 /* Going to regenerate keys on every call if cache was not
2053 * initialized. */
2054 if (!cacheIsEnabled || !*(cache->ticketKeysValid)) {
2055 if (PK11_GenerateRandom(ticketKeyNameSuffix,
2056 SESS_TICKET_KEY_VAR_NAME_LEN) != SECSuccess)
2057 goto loser;
2058 if (PK11_GenerateRandom(ticketEncKeyPtr,
2059 AES_256_KEY_LENGTH) != SECSuccess)
2060 goto loser;
2061 if (PK11_GenerateRandom(ticketMacKeyPtr,
2062 SHA256_LENGTH) != SECSuccess)
2063 goto loser;
2064 if (cacheIsEnabled) {
2065 *(cache->ticketKeysValid) = 1;
2069 rv = PR_TRUE;
2071 loser:
2072 if (cacheIsEnabled) {
2073 UnlockSidCacheLock(cache->keyCacheLock);
2075 if (rv) {
2076 PORT_Memcpy(keyName, ticketKeyNameSuffix,
2077 SESS_TICKET_KEY_VAR_NAME_LEN);
2078 PORT_Memcpy(encKey, ticketEncKeyPtr, AES_256_KEY_LENGTH);
2079 PORT_Memcpy(macKey, ticketMacKeyPtr, SHA256_LENGTH);
2081 return rv;
2084 /* The caller passes in the new value it wants
2085 * to set. This code tests the wrapped sym key entry in the shared memory.
2086 * If it is uninitialized, this function writes the caller's value into
2087 * the disk entry, and returns false.
2088 * Otherwise, it overwrites the caller's wswk with the value obtained from
2089 * the disk, and returns PR_TRUE.
2090 * This is all done while holding the locks/mutexes necessary to make
2091 * the operation atomic.
2093 PRBool
2094 ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
2096 cacheDesc * cache = &globalCache;
2097 PRBool rv = PR_FALSE;
2098 SSL3KEAType exchKeyType = wswk->exchKeyType;
2099 /* type of keys used to wrap SymWrapKey*/
2100 PRInt32 symWrapMechIndex = wswk->symWrapMechIndex;
2101 PRUint32 ndx;
2102 PRUint32 now = 0;
2103 SSLWrappedSymWrappingKey myWswk;
2105 if (!cache->cacheMem) { /* cache is uninitialized */
2106 PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
2107 return 0;
2110 PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
2111 if ((unsigned)exchKeyType >= kt_kea_size)
2112 return 0;
2114 PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
2115 if ((unsigned)symWrapMechIndex >= SSL_NUM_WRAP_MECHS)
2116 return 0;
2118 ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
2119 PORT_Memset(&myWswk, 0, sizeof myWswk); /* eliminate UMRs. */
2121 now = LockSidCacheLock(cache->keyCacheLock, now);
2122 if (now) {
2123 rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->exchKeyType,
2124 &myWswk, cache, now);
2125 if (rv) {
2126 /* we found it on disk, copy it out to the caller. */
2127 PORT_Memcpy(wswk, &myWswk, sizeof *wswk);
2128 } else {
2129 /* Wasn't on disk, and we're still holding the lock, so write it. */
2130 cache->keyCacheData[ndx] = *wswk;
2132 UnlockSidCacheLock(cache->keyCacheLock);
2134 return rv;
2137 #else /* MAC version or other platform */
2139 #include "seccomon.h"
2140 #include "cert.h"
2141 #include "ssl.h"
2142 #include "sslimpl.h"
2144 SECStatus
2145 SSL_ConfigServerSessionIDCache( int maxCacheEntries,
2146 PRUint32 ssl2_timeout,
2147 PRUint32 ssl3_timeout,
2148 const char * directory)
2150 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigServerSessionIDCache)");
2151 return SECFailure;
2154 SECStatus
2155 SSL_ConfigMPServerSIDCache( int maxCacheEntries,
2156 PRUint32 ssl2_timeout,
2157 PRUint32 ssl3_timeout,
2158 const char * directory)
2160 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigMPServerSIDCache)");
2161 return SECFailure;
2164 SECStatus
2165 SSL_InheritMPServerSIDCache(const char * envString)
2167 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_InheritMPServerSIDCache)");
2168 return SECFailure;
2171 PRBool
2172 ssl_GetWrappingKey( PRInt32 symWrapMechIndex,
2173 SSL3KEAType exchKeyType,
2174 SSLWrappedSymWrappingKey *wswk)
2176 PRBool rv = PR_FALSE;
2177 PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)");
2178 return rv;
2181 /* This is a kind of test-and-set. The caller passes in the new value it wants
2182 * to set. This code tests the wrapped sym key entry in the shared memory.
2183 * If it is uninitialized, this function writes the caller's value into
2184 * the disk entry, and returns false.
2185 * Otherwise, it overwrites the caller's wswk with the value obtained from
2186 * the disk, and returns PR_TRUE.
2187 * This is all done while holding the locks/mutexes necessary to make
2188 * the operation atomic.
2190 PRBool
2191 ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
2193 PRBool rv = PR_FALSE;
2194 PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrappingKey)");
2195 return rv;
2198 PRUint32
2199 SSL_GetMaxServerCacheLocks(void)
2201 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_GetMaxServerCacheLocks)");
2202 return -1;
2205 SECStatus
2206 SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
2208 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_SetMaxServerCacheLocks)");
2209 return SECFailure;
2212 #endif /* XP_UNIX || XP_WIN32 */