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