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