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