Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(692)

Side by Side Diff: net/third_party/nss/ssl/sslsnce.c

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

Powered by Google App Engine
This is Rietveld 408576698