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