1 /* This file implements the SERVER Session ID cache.
2 * NOTE: The contents of this file are NOT used by the client.
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is the Netscape security libraries.
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1994-2000
22 * the Initial Developer. All Rights Reserved.
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
39 /* $Id: sslsnce.c,v 1.42 2008/02/16 04:38:09 julien.pierre.boogz%sun.com Exp $ */
41 /* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server
44 * About record locking among different server processes:
46 * All processes that are part of the same conceptual server (serving on
47 * the same address and port) MUST share a common SSL session cache.
48 * This code makes the content of the shared cache accessible to all
49 * processes on the same "server". This code works on Unix and Win32 only.
51 * We use NSPR anonymous shared memory and move data to & from shared memory.
52 * We must do explicit locking of the records for all reads and writes.
53 * The set of Cache entries are divided up into "sets" of 128 entries.
54 * Each set is protected by a lock. There may be one or more sets protected
55 * by each lock. That is, locks to sets are 1:N.
56 * There is one lock for the entire cert cache.
57 * There is one lock for the set of wrapped sym wrap keys.
59 * The anonymous shared memory is laid out as if it were declared like this:
62 * cacheDescriptor desc;
63 * sidCacheLock sidCacheLocks[ numSIDCacheLocks];
64 * sidCacheLock keyCacheLock;
65 * sidCacheLock certCacheLock;
66 * sidCacheSet sidCacheSets[ numSIDCacheSets ];
67 * sidCacheEntry sidCacheData[ numSIDCacheEntries];
68 * certCacheEntry certCacheData[numCertCacheEntries];
69 * SSLWrappedSymWrappingKey keyCacheData[kt_kea_size][SSL_NUM_WRAP_MECHS];
70 * } cacheMemCacheData;
75 #if (defined(XP_UNIX) || defined(XP_WIN32) || defined (XP_OS2) || defined(XP_BEOS)) && !defined(_WIN32_WCE)
86 #if defined(XP_UNIX) || defined(XP_BEOS)
103 #include <sys/types.h>
105 #define SET_ERROR_CODE /* reminder */
108 #include "sslmutex.h"
111 ** Format of a cache entry in the shared memory.
113 struct sidCacheEntryStr
{
114 /* 16 */ PRIPv6Addr addr
; /* client's IP address */
115 /* 4 */ PRUint32 creationTime
;
116 /* 4 */ PRUint32 lastAccessTime
;
117 /* 4 */ PRUint32 expirationTime
;
118 /* 2 */ PRUint16 version
;
119 /* 1 */ PRUint8 valid
;
120 /* 1 */ PRUint8 sessionIDLength
;
121 /* 32 */ PRUint8 sessionID
[SSL3_SESSIONID_BYTES
];
122 /* 2 */ PRUint16 authAlgorithm
;
123 /* 2 */ PRUint16 authKeyBits
;
124 /* 2 */ PRUint16 keaType
;
125 /* 2 */ PRUint16 keaKeyBits
;
126 /* 72 - common header total */
130 /* 64 */ PRUint8 masterKey
[SSL_MAX_MASTER_KEY_BYTES
];
131 /* 32 */ PRUint8 cipherArg
[SSL_MAX_CYPHER_ARG_BYTES
];
133 /* 1 */ PRUint8 cipherType
;
134 /* 1 */ PRUint8 masterKeyLen
;
135 /* 1 */ PRUint8 keyBits
;
136 /* 1 */ PRUint8 secretKeyBits
;
137 /* 1 */ PRUint8 cipherArgLen
;
141 /* 2 */ ssl3CipherSuite cipherSuite
;
142 /* 2 */ PRUint16 compression
; /* SSL3CompressionMethod */
144 /*100 */ ssl3SidKeys keys
; /* keys and ivs, wrapped as needed. */
146 /* 4 */ PRUint32 masterWrapMech
;
147 /* 4 */ SSL3KEAType exchKeyType
;
148 /* 4 */ PRInt32 certIndex
;
150 /* force sizeof(sidCacheEntry) to be a multiple of cache line size */
152 /*120 */ PRUint8 filler
[120]; /* 72+120==196, a multiple of 16 */
156 typedef struct sidCacheEntryStr sidCacheEntry
;
158 /* The length of this struct is supposed to be a power of 2, e.g. 4KB */
159 struct certCacheEntryStr
{
160 PRUint16 certLength
; /* 2 */
161 PRUint16 sessionIDLength
; /* 2 */
162 PRUint8 sessionID
[SSL3_SESSIONID_BYTES
]; /* 32 */
163 PRUint8 cert
[SSL_MAX_CACHED_CERT_LEN
]; /* 4060 */
165 typedef struct certCacheEntryStr certCacheEntry
;
167 struct sidCacheLockStr
{
172 typedef struct sidCacheLockStr sidCacheLock
;
174 struct sidCacheSetStr
{
177 typedef struct sidCacheSetStr sidCacheSet
;
179 struct cacheDescStr
{
181 PRUint32 cacheMemSize
;
183 PRUint32 numSIDCacheLocks
;
184 PRUint32 numSIDCacheSets
;
185 PRUint32 numSIDCacheSetsPerLock
;
187 PRUint32 numSIDCacheEntries
;
188 PRUint32 sidCacheSize
;
190 PRUint32 numCertCacheEntries
;
191 PRUint32 certCacheSize
;
193 PRUint32 numKeyCacheEntries
;
194 PRUint32 keyCacheSize
;
196 PRUint32 ssl2Timeout
;
197 PRUint32 ssl3Timeout
;
199 PRUint32 numSIDCacheLocksInitialized
;
201 /* These values are volatile, and are accessed through sharedCache-> */
202 PRUint32 nextCertCacheEntry
; /* certCacheLock protects */
204 PRBool everInherited
;
206 /* The private copies of these values are pointers into shared mem */
207 /* The copies of these values in shared memory are merely offsets */
208 sidCacheLock
* sidCacheLocks
;
209 sidCacheLock
* keyCacheLock
;
210 sidCacheLock
* certCacheLock
;
211 sidCacheSet
* sidCacheSets
;
212 sidCacheEntry
* sidCacheData
;
213 certCacheEntry
* certCacheData
;
214 SSLWrappedSymWrappingKey
* keyCacheData
;
216 /* Only the private copies of these pointers are valid */
218 struct cacheDescStr
* sharedCache
; /* shared copy of this struct */
219 PRFileMap
* cacheMemMap
;
221 PRUint32 mutexTimeout
;
224 typedef struct cacheDescStr cacheDesc
;
226 static cacheDesc globalCache
;
228 static const char envVarName
[] = { SSL_ENV_VAR_NAME
};
230 static PRBool isMultiProcess
= PR_FALSE
;
233 #define DEF_SID_CACHE_ENTRIES 10000
234 #define DEF_CERT_CACHE_ENTRIES 250
235 #define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */
236 #define DEF_KEY_CACHE_ENTRIES 250
238 #define SID_CACHE_ENTRIES_PER_SET 128
239 #define SID_ALIGNMENT 16
241 #define DEF_SSL2_TIMEOUT 100 /* seconds */
242 #define MAX_SSL2_TIMEOUT 100 /* seconds */
243 #define MIN_SSL2_TIMEOUT 5 /* seconds */
245 #define DEF_SSL3_TIMEOUT 86400L /* 24 hours */
246 #define MAX_SSL3_TIMEOUT 86400L /* 24 hours */
247 #define MIN_SSL3_TIMEOUT 5 /* seconds */
249 #if defined(AIX) || defined(LINUX) || defined(VMS)
250 #define MAX_SID_CACHE_LOCKS 8 /* two FDs per lock */
252 #define MAX_SID_CACHE_LOCKS 16 /* one FD per lock */
254 #define MAX_SID_CACHE_LOCKS 256
257 #define SID_HOWMANY(val, size) (((val) + ((size) - 1)) / (size))
258 #define SID_ROUNDUP(val, size) ((size) * SID_HOWMANY((val), (size)))
262 static PRUint32 ssl_max_sid_cache_locks
= MAX_SID_CACHE_LOCKS
;
264 /* forward static function declarations */
265 static PRUint32
SIDindex(cacheDesc
*cache
, const PRIPv6Addr
*addr
, PRUint8
*s
,
267 static SECStatus
LaunchLockPoller(cacheDesc
*cache
);
268 static SECStatus
StopLockPoller(cacheDesc
*cache
);
271 struct inheritanceStr
{
272 PRUint32 cacheMemSize
;
276 typedef struct inheritanceStr inheritance
;
278 #if defined(_WIN32) || defined(XP_OS2)
280 #define DEFAULT_CACHE_DIRECTORY "\\temp"
284 #if defined(XP_UNIX) || defined(XP_BEOS)
286 #define DEFAULT_CACHE_DIRECTORY "/tmp"
288 #endif /* XP_UNIX || XP_BEOS */
291 /************************************************************************/
294 LockSidCacheLock(sidCacheLock
*lock
, PRUint32 now
)
296 SECStatus rv
= sslMutex_Lock(&lock
->mutex
);
297 if (rv
!= SECSuccess
)
301 lock
->timeStamp
= now
;
307 UnlockSidCacheLock(sidCacheLock
*lock
)
312 rv
= sslMutex_Unlock(&lock
->mutex
);
316 /* returns the value of ssl_Time on success, zero on failure. */
318 LockSet(cacheDesc
*cache
, PRUint32 set
, PRUint32 now
)
320 PRUint32 lockNum
= set
% cache
->numSIDCacheLocks
;
321 sidCacheLock
* lock
= cache
->sidCacheLocks
+ lockNum
;
323 return LockSidCacheLock(lock
, now
);
327 UnlockSet(cacheDesc
*cache
, PRUint32 set
)
329 PRUint32 lockNum
= set
% cache
->numSIDCacheLocks
;
330 sidCacheLock
* lock
= cache
->sidCacheLocks
+ lockNum
;
332 return UnlockSidCacheLock(lock
);
335 /************************************************************************/
338 /* Put a certificate in the cache. Update the cert index in the sce.
341 CacheCert(cacheDesc
* cache
, CERTCertificate
*cert
, sidCacheEntry
*sce
)
346 if ((cert
->derCert
.len
> SSL_MAX_CACHED_CERT_LEN
) ||
347 (cert
->derCert
.len
<= 0) ||
348 (cert
->derCert
.data
== NULL
)) {
349 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
353 cce
.sessionIDLength
= sce
->sessionIDLength
;
354 PORT_Memcpy(cce
.sessionID
, sce
->sessionID
, cce
.sessionIDLength
);
356 cce
.certLength
= cert
->derCert
.len
;
357 PORT_Memcpy(cce
.cert
, cert
->derCert
.data
, cce
.certLength
);
359 /* get lock on cert cache */
360 now
= LockSidCacheLock(cache
->certCacheLock
, 0);
363 /* Find where to place the next cert cache entry. */
364 cacheDesc
* sharedCache
= cache
->sharedCache
;
365 PRUint32 ndx
= sharedCache
->nextCertCacheEntry
;
367 /* write the entry */
368 cache
->certCacheData
[ndx
] = cce
;
370 /* remember where we put it. */
371 sce
->u
.ssl3
.certIndex
= ndx
;
373 /* update the "next" cache entry index */
374 sharedCache
->nextCertCacheEntry
=
375 (ndx
+ 1) % cache
->numCertCacheEntries
;
377 UnlockSidCacheLock(cache
->certCacheLock
);
384 ** Convert local SID to shared memory one
387 ConvertFromSID(sidCacheEntry
*to
, sslSessionID
*from
)
390 to
->version
= from
->version
;
391 to
->addr
= from
->addr
;
392 to
->creationTime
= from
->creationTime
;
393 to
->lastAccessTime
= from
->lastAccessTime
;
394 to
->expirationTime
= from
->expirationTime
;
395 to
->authAlgorithm
= from
->authAlgorithm
;
396 to
->authKeyBits
= from
->authKeyBits
;
397 to
->keaType
= from
->keaType
;
398 to
->keaKeyBits
= from
->keaKeyBits
;
400 if (from
->version
< SSL_LIBRARY_VERSION_3_0
) {
401 if ((from
->u
.ssl2
.masterKey
.len
> SSL_MAX_MASTER_KEY_BYTES
) ||
402 (from
->u
.ssl2
.cipherArg
.len
> SSL_MAX_CYPHER_ARG_BYTES
)) {
403 SSL_DBG(("%d: SSL: masterKeyLen=%d cipherArgLen=%d",
404 myPid
, from
->u
.ssl2
.masterKey
.len
,
405 from
->u
.ssl2
.cipherArg
.len
));
410 to
->u
.ssl2
.cipherType
= from
->u
.ssl2
.cipherType
;
411 to
->u
.ssl2
.masterKeyLen
= from
->u
.ssl2
.masterKey
.len
;
412 to
->u
.ssl2
.cipherArgLen
= from
->u
.ssl2
.cipherArg
.len
;
413 to
->u
.ssl2
.keyBits
= from
->u
.ssl2
.keyBits
;
414 to
->u
.ssl2
.secretKeyBits
= from
->u
.ssl2
.secretKeyBits
;
415 to
->sessionIDLength
= SSL2_SESSIONID_BYTES
;
416 PORT_Memcpy(to
->sessionID
, from
->u
.ssl2
.sessionID
, SSL2_SESSIONID_BYTES
);
417 PORT_Memcpy(to
->u
.ssl2
.masterKey
, from
->u
.ssl2
.masterKey
.data
,
418 from
->u
.ssl2
.masterKey
.len
);
419 PORT_Memcpy(to
->u
.ssl2
.cipherArg
, from
->u
.ssl2
.cipherArg
.data
,
420 from
->u
.ssl2
.cipherArg
.len
);
422 PORT_Memset(to
->u
.ssl2
.masterKey
+from
->u
.ssl2
.masterKey
.len
, 0,
423 sizeof(to
->u
.ssl2
.masterKey
) - from
->u
.ssl2
.masterKey
.len
);
424 PORT_Memset(to
->u
.ssl2
.cipherArg
+from
->u
.ssl2
.cipherArg
.len
, 0,
425 sizeof(to
->u
.ssl2
.cipherArg
) - from
->u
.ssl2
.cipherArg
.len
);
427 SSL_TRC(8, ("%d: SSL: ConvertSID: masterKeyLen=%d cipherArgLen=%d "
428 "time=%d addr=0x%08x%08x%08x%08x cipherType=%d", myPid
,
429 to
->u
.ssl2
.masterKeyLen
, to
->u
.ssl2
.cipherArgLen
,
430 to
->creationTime
, to
->addr
.pr_s6_addr32
[0],
431 to
->addr
.pr_s6_addr32
[1], to
->addr
.pr_s6_addr32
[2],
432 to
->addr
.pr_s6_addr32
[3], to
->u
.ssl2
.cipherType
));
434 /* This is an SSL v3 session */
436 to
->u
.ssl3
.cipherSuite
= from
->u
.ssl3
.cipherSuite
;
437 to
->u
.ssl3
.compression
= (uint16
)from
->u
.ssl3
.compression
;
438 to
->u
.ssl3
.keys
= from
->u
.ssl3
.keys
;
439 to
->u
.ssl3
.masterWrapMech
= from
->u
.ssl3
.masterWrapMech
;
440 to
->u
.ssl3
.exchKeyType
= from
->u
.ssl3
.exchKeyType
;
441 to
->sessionIDLength
= from
->u
.ssl3
.sessionIDLength
;
442 to
->u
.ssl3
.certIndex
= -1;
444 PORT_Memcpy(to
->sessionID
, from
->u
.ssl3
.sessionID
,
445 to
->sessionIDLength
);
447 SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x "
449 myPid
, to
->creationTime
, to
->addr
.pr_s6_addr32
[0],
450 to
->addr
.pr_s6_addr32
[1], to
->addr
.pr_s6_addr32
[2],
451 to
->addr
.pr_s6_addr32
[3], to
->u
.ssl3
.cipherSuite
));
456 ** Convert shared memory cache-entry to local memory based one
457 ** This is only called from ServerSessionIDLookup().
458 ** Caller must hold cache lock when calling this.
460 static sslSessionID
*
461 ConvertToSID(sidCacheEntry
*from
, certCacheEntry
*pcce
,
462 CERTCertDBHandle
* dbHandle
)
465 uint16 version
= from
->version
;
467 to
= (sslSessionID
*) PORT_ZAlloc(sizeof(sslSessionID
));
472 if (version
< SSL_LIBRARY_VERSION_3_0
) {
473 /* This is an SSL v2 session */
474 to
->u
.ssl2
.masterKey
.data
=
475 (unsigned char*) PORT_Alloc(from
->u
.ssl2
.masterKeyLen
);
476 if (!to
->u
.ssl2
.masterKey
.data
) {
479 if (from
->u
.ssl2
.cipherArgLen
) {
480 to
->u
.ssl2
.cipherArg
.data
=
481 (unsigned char*)PORT_Alloc(from
->u
.ssl2
.cipherArgLen
);
482 if (!to
->u
.ssl2
.cipherArg
.data
) {
485 PORT_Memcpy(to
->u
.ssl2
.cipherArg
.data
, from
->u
.ssl2
.cipherArg
,
486 from
->u
.ssl2
.cipherArgLen
);
489 to
->u
.ssl2
.cipherType
= from
->u
.ssl2
.cipherType
;
490 to
->u
.ssl2
.masterKey
.len
= from
->u
.ssl2
.masterKeyLen
;
491 to
->u
.ssl2
.cipherArg
.len
= from
->u
.ssl2
.cipherArgLen
;
492 to
->u
.ssl2
.keyBits
= from
->u
.ssl2
.keyBits
;
493 to
->u
.ssl2
.secretKeyBits
= from
->u
.ssl2
.secretKeyBits
;
494 /* to->sessionIDLength = SSL2_SESSIONID_BYTES; */
495 PORT_Memcpy(to
->u
.ssl2
.sessionID
, from
->sessionID
, SSL2_SESSIONID_BYTES
);
496 PORT_Memcpy(to
->u
.ssl2
.masterKey
.data
, from
->u
.ssl2
.masterKey
,
497 from
->u
.ssl2
.masterKeyLen
);
499 SSL_TRC(8, ("%d: SSL: ConvertToSID: masterKeyLen=%d cipherArgLen=%d "
500 "time=%d addr=0x%08x%08x%08x%08x cipherType=%d",
501 myPid
, to
->u
.ssl2
.masterKey
.len
,
502 to
->u
.ssl2
.cipherArg
.len
, to
->creationTime
,
503 to
->addr
.pr_s6_addr32
[0], to
->addr
.pr_s6_addr32
[1],
504 to
->addr
.pr_s6_addr32
[2], to
->addr
.pr_s6_addr32
[3],
505 to
->u
.ssl2
.cipherType
));
507 /* This is an SSL v3 session */
509 to
->u
.ssl3
.sessionIDLength
= from
->sessionIDLength
;
510 to
->u
.ssl3
.cipherSuite
= from
->u
.ssl3
.cipherSuite
;
511 to
->u
.ssl3
.compression
= (SSL3CompressionMethod
)from
->u
.ssl3
.compression
;
512 to
->u
.ssl3
.keys
= from
->u
.ssl3
.keys
;
513 to
->u
.ssl3
.masterWrapMech
= from
->u
.ssl3
.masterWrapMech
;
514 to
->u
.ssl3
.exchKeyType
= from
->u
.ssl3
.exchKeyType
;
516 PORT_Memcpy(to
->u
.ssl3
.sessionID
, from
->sessionID
, from
->sessionIDLength
);
518 /* the portions of the SID that are only restored on the client
519 * are set to invalid values on the server.
521 to
->u
.ssl3
.clientWriteKey
= NULL
;
522 to
->u
.ssl3
.serverWriteKey
= NULL
;
524 to
->urlSvrName
= NULL
;
526 to
->u
.ssl3
.masterModuleID
= (SECMODModuleID
)-1; /* invalid value */
527 to
->u
.ssl3
.masterSlotID
= (CK_SLOT_ID
)-1; /* invalid value */
528 to
->u
.ssl3
.masterWrapIndex
= 0;
529 to
->u
.ssl3
.masterWrapSeries
= 0;
530 to
->u
.ssl3
.masterValid
= PR_FALSE
;
532 to
->u
.ssl3
.clAuthModuleID
= (SECMODModuleID
)-1; /* invalid value */
533 to
->u
.ssl3
.clAuthSlotID
= (CK_SLOT_ID
)-1; /* invalid value */
534 to
->u
.ssl3
.clAuthSeries
= 0;
535 to
->u
.ssl3
.clAuthValid
= PR_FALSE
;
537 if (from
->u
.ssl3
.certIndex
!= -1 && pcce
) {
540 derCert
.len
= pcce
->certLength
;
541 derCert
.data
= pcce
->cert
;
543 to
->peerCert
= CERT_NewTempCertificate(dbHandle
, &derCert
, NULL
,
545 if (to
->peerCert
== NULL
)
550 to
->version
= from
->version
;
551 to
->creationTime
= from
->creationTime
;
552 to
->lastAccessTime
= from
->lastAccessTime
;
553 to
->expirationTime
= from
->expirationTime
;
554 to
->cached
= in_server_cache
;
555 to
->addr
= from
->addr
;
557 to
->authAlgorithm
= from
->authAlgorithm
;
558 to
->authKeyBits
= from
->authKeyBits
;
559 to
->keaType
= from
->keaType
;
560 to
->keaKeyBits
= from
->keaKeyBits
;
566 if (version
< SSL_LIBRARY_VERSION_3_0
) {
567 if (to
->u
.ssl2
.masterKey
.data
)
568 PORT_Free(to
->u
.ssl2
.masterKey
.data
);
569 if (to
->u
.ssl2
.cipherArg
.data
)
570 PORT_Free(to
->u
.ssl2
.cipherArg
.data
);
580 ** Perform some mumbo jumbo on the ip-address and the session-id value to
581 ** compute a hash value.
584 SIDindex(cacheDesc
*cache
, const PRIPv6Addr
*addr
, PRUint8
*s
, unsigned nl
)
589 memset(x
, 0, sizeof x
);
594 rv
= (addr
->pr_s6_addr32
[0] ^ addr
->pr_s6_addr32
[1] ^
595 addr
->pr_s6_addr32
[2] ^ addr
->pr_s6_addr32
[3] ^
596 x
[0] ^ x
[1] ^ x
[2] ^ x
[3] ^ x
[4] ^ x
[5] ^ x
[6] ^ x
[7])
597 % cache
->numSIDCacheSets
;
604 ** Look something up in the cache. This will invalidate old entries
605 ** in the process. Caller has locked the cache set!
606 ** Returns PR_TRUE if found a valid match. PR_FALSE otherwise.
608 static sidCacheEntry
*
609 FindSID(cacheDesc
*cache
, PRUint32 setNum
, PRUint32 now
,
610 const PRIPv6Addr
*addr
, unsigned char *sessionID
,
611 unsigned sessionIDLength
)
613 PRUint32 ndx
= cache
->sidCacheSets
[setNum
].next
;
616 sidCacheEntry
* set
= cache
->sidCacheData
+
617 (setNum
* SID_CACHE_ENTRIES_PER_SET
);
619 for (i
= SID_CACHE_ENTRIES_PER_SET
; i
> 0; --i
) {
622 ndx
= (ndx
- 1) % SID_CACHE_ENTRIES_PER_SET
;
628 if (now
> sce
->expirationTime
) {
629 /* SessionID has timed out. Invalidate the entry. */
630 SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x "
632 myPid
, sce
->addr
.pr_s6_addr32
[0],
633 sce
->addr
.pr_s6_addr32
[1], sce
->addr
.pr_s6_addr32
[2],
634 sce
->addr
.pr_s6_addr32
[3], now
,
635 sce
->expirationTime
));
641 ** Next, examine specific session-id/addr data to see if the cache
642 ** entry matches our addr+session-id value
644 if (sessionIDLength
== sce
->sessionIDLength
&&
645 !memcmp(&sce
->addr
, addr
, sizeof(PRIPv6Addr
)) &&
646 !memcmp(sce
->sessionID
, sessionID
, sessionIDLength
)) {
652 PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND
);
656 /************************************************************************/
658 /* This is the primary function for finding entries in the server's sid cache.
659 * Although it is static, this function is called via the global function
660 * pointer ssl_sid_lookup.
662 static sslSessionID
*
663 ServerSessionIDLookup(const PRIPv6Addr
*addr
,
664 unsigned char *sessionID
,
665 unsigned int sessionIDLength
,
666 CERTCertDBHandle
* dbHandle
)
668 sslSessionID
* sid
= 0;
669 sidCacheEntry
* psce
;
670 certCacheEntry
*pcce
= 0;
671 cacheDesc
* cache
= &globalCache
;
678 set
= SIDindex(cache
, addr
, sessionID
, sessionIDLength
);
679 now
= LockSet(cache
, set
, 0);
683 psce
= FindSID(cache
, set
, now
, addr
, sessionID
, sessionIDLength
);
685 if (psce
->version
>= SSL_LIBRARY_VERSION_3_0
&&
686 (cndx
= psce
->u
.ssl3
.certIndex
) != -1) {
688 PRUint32 gotLock
= LockSidCacheLock(cache
->certCacheLock
, now
);
690 pcce
= &cache
->certCacheData
[cndx
];
692 /* See if the cert's session ID matches the sce cache. */
693 if ((pcce
->sessionIDLength
== psce
->sessionIDLength
) &&
694 !PORT_Memcmp(pcce
->sessionID
, psce
->sessionID
,
695 pcce
->sessionIDLength
)) {
698 /* The cert doesen't match the SID cache entry,
699 ** so invalidate the SID cache entry.
705 UnlockSidCacheLock(cache
->certCacheLock
);
707 /* what the ??. Didn't get the cert cache lock.
708 ** Don't invalidate the SID cache entry, but don't find it.
710 PORT_Assert(!("Didn't get cert Cache Lock!"));
716 psce
->lastAccessTime
= now
;
717 sce
= *psce
; /* grab a copy while holding the lock */
720 UnlockSet(cache
, set
);
722 /* sce conains a copy of the cache entry.
723 ** Convert shared memory format to local format
725 sid
= ConvertToSID(&sce
, pcce
? &cce
: 0, dbHandle
);
731 ** Place a sid into the cache, if it isn't already there.
734 ServerSessionIDCache(sslSessionID
*sid
)
738 uint16 version
= sid
->version
;
739 cacheDesc
* cache
= &globalCache
;
741 if ((version
>= SSL_LIBRARY_VERSION_3_0
) &&
742 (sid
->u
.ssl3
.sessionIDLength
== 0)) {
746 if (sid
->cached
== never_cached
|| sid
->cached
== invalid_cache
) {
749 PORT_Assert(sid
->creationTime
!= 0);
750 if (!sid
->creationTime
)
751 sid
->lastAccessTime
= sid
->creationTime
= ssl_Time();
752 if (version
< SSL_LIBRARY_VERSION_3_0
) {
753 /* override caller's expiration time, which uses client timeout
754 * duration, not server timeout duration.
756 sid
->expirationTime
= sid
->creationTime
+ cache
->ssl2Timeout
;
757 SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
758 "cipher=%d", myPid
, sid
->cached
,
759 sid
->addr
.pr_s6_addr32
[0], sid
->addr
.pr_s6_addr32
[1],
760 sid
->addr
.pr_s6_addr32
[2], sid
->addr
.pr_s6_addr32
[3],
761 sid
->creationTime
, sid
->u
.ssl2
.cipherType
));
762 PRINT_BUF(8, (0, "sessionID:", sid
->u
.ssl2
.sessionID
,
763 SSL2_SESSIONID_BYTES
));
764 PRINT_BUF(8, (0, "masterKey:", sid
->u
.ssl2
.masterKey
.data
,
765 sid
->u
.ssl2
.masterKey
.len
));
766 PRINT_BUF(8, (0, "cipherArg:", sid
->u
.ssl2
.cipherArg
.data
,
767 sid
->u
.ssl2
.cipherArg
.len
));
770 /* override caller's expiration time, which uses client timeout
771 * duration, not server timeout duration.
773 sid
->expirationTime
= sid
->creationTime
+ cache
->ssl3Timeout
;
774 SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
775 "cipherSuite=%d", myPid
, sid
->cached
,
776 sid
->addr
.pr_s6_addr32
[0], sid
->addr
.pr_s6_addr32
[1],
777 sid
->addr
.pr_s6_addr32
[2], sid
->addr
.pr_s6_addr32
[3],
778 sid
->creationTime
, sid
->u
.ssl3
.cipherSuite
));
779 PRINT_BUF(8, (0, "sessionID:", sid
->u
.ssl3
.sessionID
,
780 sid
->u
.ssl3
.sessionIDLength
));
783 ConvertFromSID(&sce
, sid
);
785 if ((version
>= SSL_LIBRARY_VERSION_3_0
) &&
786 (sid
->peerCert
!= NULL
)) {
787 now
= CacheCert(cache
, sid
->peerCert
, &sce
);
790 set
= SIDindex(cache
, &sce
.addr
, sce
.sessionID
, sce
.sessionIDLength
);
791 now
= LockSet(cache
, set
, now
);
793 PRUint32 next
= cache
->sidCacheSets
[set
].next
;
794 PRUint32 ndx
= set
* SID_CACHE_ENTRIES_PER_SET
+ next
;
796 /* Write out new cache entry */
797 cache
->sidCacheData
[ndx
] = sce
;
799 cache
->sidCacheSets
[set
].next
=
800 (next
+ 1) % SID_CACHE_ENTRIES_PER_SET
;
802 UnlockSet(cache
, set
);
803 sid
->cached
= in_server_cache
;
809 ** Although this is static, it is called from ssl via global function pointer
810 ** ssl_sid_uncache. This invalidates the referenced cache entry.
813 ServerSessionIDUncache(sslSessionID
*sid
)
815 cacheDesc
* cache
= &globalCache
;
817 unsigned int sessionIDLength
;
826 /* Uncaching a SID should never change the error code.
827 ** So save it here and restore it before exiting.
831 if (sid
->version
< SSL_LIBRARY_VERSION_3_0
) {
832 sessionID
= sid
->u
.ssl2
.sessionID
;
833 sessionIDLength
= SSL2_SESSIONID_BYTES
;
834 SSL_TRC(8, ("%d: SSL: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
835 "cipher=%d", myPid
, sid
->cached
,
836 sid
->addr
.pr_s6_addr32
[0], sid
->addr
.pr_s6_addr32
[1],
837 sid
->addr
.pr_s6_addr32
[2], sid
->addr
.pr_s6_addr32
[3],
838 sid
->creationTime
, sid
->u
.ssl2
.cipherType
));
839 PRINT_BUF(8, (0, "sessionID:", sessionID
, sessionIDLength
));
840 PRINT_BUF(8, (0, "masterKey:", sid
->u
.ssl2
.masterKey
.data
,
841 sid
->u
.ssl2
.masterKey
.len
));
842 PRINT_BUF(8, (0, "cipherArg:", sid
->u
.ssl2
.cipherArg
.data
,
843 sid
->u
.ssl2
.cipherArg
.len
));
845 sessionID
= sid
->u
.ssl3
.sessionID
;
846 sessionIDLength
= sid
->u
.ssl3
.sessionIDLength
;
847 SSL_TRC(8, ("%d: SSL3: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
848 "cipherSuite=%d", myPid
, sid
->cached
,
849 sid
->addr
.pr_s6_addr32
[0], sid
->addr
.pr_s6_addr32
[1],
850 sid
->addr
.pr_s6_addr32
[2], sid
->addr
.pr_s6_addr32
[3],
851 sid
->creationTime
, sid
->u
.ssl3
.cipherSuite
));
852 PRINT_BUF(8, (0, "sessionID:", sessionID
, sessionIDLength
));
854 set
= SIDindex(cache
, &sid
->addr
, sessionID
, sessionIDLength
);
855 now
= LockSet(cache
, set
, 0);
857 psce
= FindSID(cache
, set
, now
, &sid
->addr
, sessionID
, sessionIDLength
);
861 UnlockSet(cache
, set
);
863 sid
->cached
= invalid_cache
;
869 #define INCL_DOSPROCESS
876 DosGetInfoBlocks(&ptib
, &ppib
);
877 return ((long)ptib
->tib_ordinal
); /* thread id */
882 CloseCache(cacheDesc
*cache
)
884 int locks_initialized
= cache
->numSIDCacheLocksInitialized
;
886 if (cache
->cacheMem
) {
887 /* If everInherited is true, this shared cache was (and may still
888 ** be) in use by multiple processes. We do not wish to destroy
889 ** the mutexes while they are still in use.
891 if (cache
->sharedCache
&&
892 PR_FALSE
== cache
->sharedCache
->everInherited
) {
893 sidCacheLock
*pLock
= cache
->sidCacheLocks
;
894 for (; locks_initialized
> 0; --locks_initialized
, ++pLock
) {
895 sslMutex_Destroy(&pLock
->mutex
);
899 PR_MemUnmap(cache
->cacheMem
, cache
->cacheMemSize
);
901 PORT_Free(cache
->cacheMem
);
903 cache
->cacheMem
= NULL
;
905 if (cache
->cacheMemMap
) {
906 PR_CloseFileMap(cache
->cacheMemMap
);
907 cache
->cacheMemMap
= NULL
;
909 memset(cache
, 0, sizeof *cache
);
913 InitCache(cacheDesc
*cache
, int maxCacheEntries
, PRUint32 ssl2_timeout
,
914 PRUint32 ssl3_timeout
, const char *directory
, PRBool shared
)
919 PRFileMap
* cacheMemMap
;
920 char * cfn
= NULL
; /* cache file name */
921 int locks_initialized
= 0;
922 int locks_to_initialize
= 0;
925 if ( (!cache
) || (maxCacheEntries
< 0) || (!directory
) ) {
926 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
930 if (cache
->cacheMem
) {
935 /* make sure loser can clean up properly */
936 cache
->shared
= shared
;
937 cache
->cacheMem
= cacheMem
= NULL
;
938 cache
->cacheMemMap
= cacheMemMap
= NULL
;
939 cache
->sharedCache
= (cacheDesc
*)0;
941 cache
->numSIDCacheLocksInitialized
= 0;
942 cache
->nextCertCacheEntry
= 0;
943 cache
->stopPolling
= PR_FALSE
;
944 cache
->everInherited
= PR_FALSE
;
945 cache
->poller
= NULL
;
946 cache
->mutexTimeout
= 0;
948 cache
->numSIDCacheEntries
= maxCacheEntries
? maxCacheEntries
949 : DEF_SID_CACHE_ENTRIES
;
950 cache
->numSIDCacheSets
=
951 SID_HOWMANY(cache
->numSIDCacheEntries
, SID_CACHE_ENTRIES_PER_SET
);
953 cache
->numSIDCacheEntries
=
954 cache
->numSIDCacheSets
* SID_CACHE_ENTRIES_PER_SET
;
956 cache
->numSIDCacheLocks
=
957 PR_MIN(cache
->numSIDCacheSets
, ssl_max_sid_cache_locks
);
959 cache
->numSIDCacheSetsPerLock
=
960 SID_HOWMANY(cache
->numSIDCacheSets
, cache
->numSIDCacheLocks
);
962 /* compute size of shared memory, and offsets of all pointers */
964 cache
->cacheMem
= (char *)ptr
;
965 ptr
+= SID_ROUNDUP(sizeof(cacheDesc
), SID_ALIGNMENT
);
967 cache
->sidCacheLocks
= (sidCacheLock
*)ptr
;
968 cache
->keyCacheLock
= cache
->sidCacheLocks
+ cache
->numSIDCacheLocks
;
969 cache
->certCacheLock
= cache
->keyCacheLock
+ 1;
970 ptr
= (ptrdiff_t)(cache
->certCacheLock
+ 1);
971 ptr
= SID_ROUNDUP(ptr
, SID_ALIGNMENT
);
973 cache
->sidCacheSets
= (sidCacheSet
*)ptr
;
974 ptr
= (ptrdiff_t)(cache
->sidCacheSets
+ cache
->numSIDCacheSets
);
975 ptr
= SID_ROUNDUP(ptr
, SID_ALIGNMENT
);
977 cache
->sidCacheData
= (sidCacheEntry
*)ptr
;
978 ptr
= (ptrdiff_t)(cache
->sidCacheData
+ cache
->numSIDCacheEntries
);
979 ptr
= SID_ROUNDUP(ptr
, SID_ALIGNMENT
);
981 cache
->certCacheData
= (certCacheEntry
*)ptr
;
982 cache
->sidCacheSize
=
983 (char *)cache
->certCacheData
- (char *)cache
->sidCacheData
;
985 /* This is really a poor way to computer this! */
986 cache
->numCertCacheEntries
= cache
->sidCacheSize
/ sizeof(certCacheEntry
);
987 if (cache
->numCertCacheEntries
< MIN_CERT_CACHE_ENTRIES
)
988 cache
->numCertCacheEntries
= MIN_CERT_CACHE_ENTRIES
;
989 ptr
= (ptrdiff_t)(cache
->certCacheData
+ cache
->numCertCacheEntries
);
990 ptr
= SID_ROUNDUP(ptr
, SID_ALIGNMENT
);
992 cache
->keyCacheData
= (SSLWrappedSymWrappingKey
*)ptr
;
993 cache
->certCacheSize
=
994 (char *)cache
->keyCacheData
- (char *)cache
->certCacheData
;
996 cache
->numKeyCacheEntries
= kt_kea_size
* SSL_NUM_WRAP_MECHS
;
997 ptr
= (ptrdiff_t)(cache
->keyCacheData
+ cache
->numKeyCacheEntries
);
998 ptr
= SID_ROUNDUP(ptr
, SID_ALIGNMENT
);
1000 cache
->cacheMemSize
= ptr
;
1002 cache
->keyCacheSize
= (char *)ptr
- (char *)cache
->keyCacheData
;
1005 if (ssl2_timeout
> MAX_SSL2_TIMEOUT
) {
1006 ssl2_timeout
= MAX_SSL2_TIMEOUT
;
1008 if (ssl2_timeout
< MIN_SSL2_TIMEOUT
) {
1009 ssl2_timeout
= MIN_SSL2_TIMEOUT
;
1011 cache
->ssl2Timeout
= ssl2_timeout
;
1013 cache
->ssl2Timeout
= DEF_SSL2_TIMEOUT
;
1017 if (ssl3_timeout
> MAX_SSL3_TIMEOUT
) {
1018 ssl3_timeout
= MAX_SSL3_TIMEOUT
;
1020 if (ssl3_timeout
< MIN_SSL3_TIMEOUT
) {
1021 ssl3_timeout
= MIN_SSL3_TIMEOUT
;
1023 cache
->ssl3Timeout
= ssl3_timeout
;
1025 cache
->ssl3Timeout
= DEF_SSL3_TIMEOUT
;
1029 /* Create file names */
1030 #if defined(XP_UNIX) || defined(XP_BEOS)
1031 /* there's some confusion here about whether PR_OpenAnonFileMap wants
1032 ** a directory name or a file name for its first argument.
1033 cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid);
1035 cfn
= PR_smprintf("%s", directory
);
1036 #elif defined(XP_WIN32)
1037 cfn
= PR_smprintf("%s/svrcache_%d_%x.ssl", directory
, myPid
,
1038 GetCurrentThreadId());
1039 #elif defined(XP_OS2)
1040 cfn
= PR_smprintf("%s/svrcache_%d_%x.ssl", directory
, myPid
,
1043 #error "Don't know how to create file name for this platform!"
1050 cacheMemMap
= PR_OpenAnonFileMap(cfn
, cache
->cacheMemSize
,
1053 PR_smprintf_free(cfn
);
1058 cacheMem
= PR_MemMap(cacheMemMap
, 0, cache
->cacheMemSize
);
1060 cacheMem
= PORT_Alloc(cache
->cacheMemSize
);
1067 /* Initialize shared memory. This may not be necessary on all platforms */
1068 memset(cacheMem
, 0, cache
->cacheMemSize
);
1070 /* Copy cache descriptor header into shared memory */
1071 memcpy(cacheMem
, cache
, sizeof *cache
);
1073 /* save private copies of these values */
1074 cache
->cacheMemMap
= cacheMemMap
;
1075 cache
->cacheMem
= cacheMem
;
1076 cache
->sharedCache
= (cacheDesc
*)cacheMem
;
1078 /* Fix pointers in our private copy of cache descriptor to point to
1079 ** spaces in shared memory
1081 ptr
= (ptrdiff_t)cache
->cacheMem
;
1082 *(ptrdiff_t *)(&cache
->sidCacheLocks
) += ptr
;
1083 *(ptrdiff_t *)(&cache
->keyCacheLock
) += ptr
;
1084 *(ptrdiff_t *)(&cache
->certCacheLock
) += ptr
;
1085 *(ptrdiff_t *)(&cache
->sidCacheSets
) += ptr
;
1086 *(ptrdiff_t *)(&cache
->sidCacheData
) += ptr
;
1087 *(ptrdiff_t *)(&cache
->certCacheData
) += ptr
;
1088 *(ptrdiff_t *)(&cache
->keyCacheData
) += ptr
;
1090 /* initialize the locks */
1091 init_time
= ssl_Time();
1092 pLock
= cache
->sidCacheLocks
;
1093 for (locks_to_initialize
= cache
->numSIDCacheLocks
+ 2;
1094 locks_initialized
< locks_to_initialize
;
1095 ++locks_initialized
, ++pLock
) {
1097 SECStatus err
= sslMutex_Init(&pLock
->mutex
, shared
);
1099 cache
->numSIDCacheLocksInitialized
= locks_initialized
;
1102 pLock
->timeStamp
= init_time
;
1105 cache
->numSIDCacheLocksInitialized
= locks_initialized
;
1115 SSL_GetMaxServerCacheLocks(void)
1117 return ssl_max_sid_cache_locks
+ 2;
1118 /* The extra two are the cert cache lock and the key cache lock. */
1122 SSL_SetMaxServerCacheLocks(PRUint32 maxLocks
)
1124 /* Minimum is 1 sid cache lock, 1 cert cache lock and 1 key cache lock.
1125 ** We'd like to test for a maximum value, but not all platforms' header
1126 ** files provide a symbol or function or other means of determining
1127 ** the maximum, other than trial and error.
1130 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
1133 ssl_max_sid_cache_locks
= maxLocks
- 2;
1134 /* The extra two are the cert cache lock and the key cache lock. */
1139 SSL_ConfigServerSessionIDCacheInstance( cacheDesc
*cache
,
1140 int maxCacheEntries
,
1141 PRUint32 ssl2_timeout
,
1142 PRUint32 ssl3_timeout
,
1143 const char * directory
, PRBool shared
)
1147 #if defined(DEBUG_nelsonb)
1148 printf("sizeof(sidCacheEntry) == %u\n", sizeof(sidCacheEntry
));
1150 PORT_Assert(sizeof(sidCacheEntry
) == 192);
1151 PORT_Assert(sizeof(certCacheEntry
) == 4096);
1153 myPid
= SSL_GETPID();
1155 directory
= DEFAULT_CACHE_DIRECTORY
;
1157 rv
= InitCache(cache
, maxCacheEntries
, ssl2_timeout
, ssl3_timeout
,
1164 ssl_sid_lookup
= ServerSessionIDLookup
;
1165 ssl_sid_cache
= ServerSessionIDCache
;
1166 ssl_sid_uncache
= ServerSessionIDUncache
;
1171 SSL_ConfigServerSessionIDCache( int maxCacheEntries
,
1172 PRUint32 ssl2_timeout
,
1173 PRUint32 ssl3_timeout
,
1174 const char * directory
)
1176 ssl_InitLocks(PR_FALSE
);
1177 return SSL_ConfigServerSessionIDCacheInstance(&globalCache
,
1178 maxCacheEntries
, ssl2_timeout
, ssl3_timeout
, directory
, PR_FALSE
);
1182 SSL_ShutdownServerSessionIDCacheInstance(cacheDesc
*cache
)
1189 SSL_ShutdownServerSessionIDCache(void)
1191 #if defined(XP_UNIX) || defined(XP_BEOS)
1192 /* Stop the thread that polls cache for expired locks on Unix */
1193 StopLockPoller(&globalCache
);
1195 SSL3_ShutdownServerCache();
1196 return SSL_ShutdownServerSessionIDCacheInstance(&globalCache
);
1199 /* Use this function, instead of SSL_ConfigServerSessionIDCache,
1200 * if the cache will be shared by multiple processes.
1203 SSL_ConfigMPServerSIDCache( int maxCacheEntries
,
1204 PRUint32 ssl2_timeout
,
1205 PRUint32 ssl3_timeout
,
1206 const char * directory
)
1210 cacheDesc
* cache
= &globalCache
;
1214 SECStatus putEnvFailed
;
1215 inheritance inherit
;
1216 char fmString
[PR_FILEMAP_STRING_BUFSIZE
];
1218 isMultiProcess
= PR_TRUE
;
1219 result
= SSL_ConfigServerSessionIDCacheInstance(cache
, maxCacheEntries
,
1220 ssl2_timeout
, ssl3_timeout
, directory
, PR_TRUE
);
1221 if (result
!= SECSuccess
)
1224 prStatus
= PR_ExportFileMapAsString(cache
->cacheMemMap
,
1225 sizeof fmString
, fmString
);
1226 if ((prStatus
!= PR_SUCCESS
) || !(fmStrLen
= strlen(fmString
))) {
1231 inherit
.cacheMemSize
= cache
->cacheMemSize
;
1232 inherit
.fmStrLen
= fmStrLen
;
1234 inhValue
= BTOA_DataToAscii((unsigned char *)&inherit
, sizeof inherit
);
1235 if (!inhValue
|| !strlen(inhValue
)) {
1239 envValue
= PR_smprintf("%s,%s", inhValue
, fmString
);
1240 if (!envValue
|| !strlen(envValue
)) {
1244 PORT_Free(inhValue
);
1246 putEnvFailed
= (SECStatus
)NSS_PutEnv(envVarName
, envValue
);
1247 PR_smprintf_free(envValue
);
1250 result
= SECFailure
;
1253 #if defined(XP_UNIX) || defined(XP_BEOS)
1254 /* Launch thread to poll cache for expired locks on Unix */
1255 LaunchLockPoller(cache
);
1261 SSL_InheritMPServerSIDCacheInstance(cacheDesc
*cache
, const char * envString
)
1263 unsigned char * decoString
= NULL
;
1264 char * fmString
= NULL
;
1265 char * myEnvString
= NULL
;
1266 unsigned int decoLen
;
1268 inheritance inherit
;
1271 sidCacheLock
* newLocks
;
1272 int locks_initialized
= 0;
1273 int locks_to_initialize
= 0;
1276 myPid
= SSL_GETPID();
1278 /* If this child was created by fork(), and not by exec() on unix,
1279 ** then isMultiProcess will already be set.
1280 ** If not, we'll set it below.
1282 if (isMultiProcess
) {
1283 if (cache
&& cache
->sharedCache
) {
1284 cache
->sharedCache
->everInherited
= PR_TRUE
;
1286 return SECSuccess
; /* already done. */
1289 ssl_InitLocks(PR_FALSE
);
1291 ssl_sid_lookup
= ServerSessionIDLookup
;
1292 ssl_sid_cache
= ServerSessionIDCache
;
1293 ssl_sid_uncache
= ServerSessionIDUncache
;
1296 envString
= getenv(envVarName
);
1302 myEnvString
= PORT_Strdup(envString
);
1305 fmString
= strchr(myEnvString
, ',');
1310 decoString
= ATOB_AsciiToData(myEnvString
, &decoLen
);
1315 if (decoLen
!= sizeof inherit
) {
1320 PORT_Memcpy(&inherit
, decoString
, sizeof inherit
);
1322 if (strlen(fmString
) != inherit
.fmStrLen
) {
1326 memset(cache
, 0, sizeof *cache
);
1327 cache
->cacheMemSize
= inherit
.cacheMemSize
;
1330 cache
->cacheMemMap
= PR_ImportFileMapFromString(fmString
);
1331 if(! cache
->cacheMemMap
) {
1334 cache
->cacheMem
= PR_MemMap(cache
->cacheMemMap
, 0, cache
->cacheMemSize
);
1335 if (! cache
->cacheMem
) {
1338 cache
->sharedCache
= (cacheDesc
*)cache
->cacheMem
;
1340 if (cache
->sharedCache
->cacheMemSize
!= cache
->cacheMemSize
) {
1345 /* We're now going to overwrite the local cache instance with the
1346 ** shared copy of the cache struct, then update several values in
1347 ** the local cache using the values for cache->cacheMemMap and
1348 ** cache->cacheMem computed just above. So, we copy cache into
1349 ** the automatic variable "my", to preserve the variables while
1350 ** cache is overwritten.
1352 my
= *cache
; /* save values computed above. */
1353 memcpy(cache
, cache
->sharedCache
, sizeof *cache
); /* overwrite */
1355 /* Fix pointers in our private copy of cache descriptor to point to
1356 ** spaces in shared memory, whose address is now in "my".
1358 ptr
= (ptrdiff_t)my
.cacheMem
;
1359 *(ptrdiff_t *)(&cache
->sidCacheLocks
) += ptr
;
1360 *(ptrdiff_t *)(&cache
->keyCacheLock
) += ptr
;
1361 *(ptrdiff_t *)(&cache
->certCacheLock
) += ptr
;
1362 *(ptrdiff_t *)(&cache
->sidCacheSets
) += ptr
;
1363 *(ptrdiff_t *)(&cache
->sidCacheData
) += ptr
;
1364 *(ptrdiff_t *)(&cache
->certCacheData
) += ptr
;
1365 *(ptrdiff_t *)(&cache
->keyCacheData
) += ptr
;
1367 cache
->cacheMemMap
= my
.cacheMemMap
;
1368 cache
->cacheMem
= my
.cacheMem
;
1369 cache
->sharedCache
= (cacheDesc
*)cache
->cacheMem
;
1372 /* On Windows NT we need to "fix" the sidCacheLocks here to support fibers
1373 ** When NT fibers are used in a multi-process server, a second level of
1374 ** locking is needed to prevent a deadlock, in case a fiber acquires the
1375 ** cross-process mutex, yields, and another fiber is later scheduled on
1376 ** the same native thread and tries to acquire the cross-process mutex.
1377 ** We do this by using a PRLock in the sslMutex. However, it is stored in
1378 ** shared memory as part of sidCacheLocks, and we don't want to overwrite
1379 ** the PRLock of the parent process. So we need to make new, private
1380 ** copies of sidCacheLocks before modifying the sslMutex with our own
1384 /* note from jpierre : this should be free'd in child processes when
1385 ** a function is added to delete the SSL session cache in the future.
1387 locks_to_initialize
= cache
->numSIDCacheLocks
+ 2;
1388 newLocks
= PORT_NewArray(sidCacheLock
, locks_to_initialize
);
1391 /* copy the old locks */
1392 memcpy(newLocks
, cache
->sidCacheLocks
,
1393 locks_to_initialize
* sizeof(sidCacheLock
));
1394 cache
->sidCacheLocks
= newLocks
;
1396 for (; locks_initialized
< locks_to_initialize
; ++locks_initialized
) {
1397 /* now, make a local PRLock in this sslMutex for this child process */
1399 err
= sslMutex_2LevelInit(&newLocks
[locks_initialized
].mutex
);
1400 if (err
!= SECSuccess
) {
1401 cache
->numSIDCacheLocksInitialized
= locks_initialized
;
1405 cache
->numSIDCacheLocksInitialized
= locks_initialized
;
1407 /* also fix the key and cert cache which use the last 2 lock entries */
1408 cache
->keyCacheLock
= cache
->sidCacheLocks
+ cache
->numSIDCacheLocks
;
1409 cache
->certCacheLock
= cache
->keyCacheLock
+ 1;
1412 PORT_Free(myEnvString
);
1413 PORT_Free(decoString
);
1415 /* mark that we have inherited this. */
1416 cache
->sharedCache
->everInherited
= PR_TRUE
;
1417 isMultiProcess
= PR_TRUE
;
1422 PORT_Free(myEnvString
);
1424 PORT_Free(decoString
);
1430 SSL_InheritMPServerSIDCache(const char * envString
)
1432 return SSL_InheritMPServerSIDCacheInstance(&globalCache
, envString
);
1435 #if defined(XP_UNIX) || defined(XP_BEOS)
1437 #define SID_LOCK_EXPIRATION_TIMEOUT 30 /* seconds */
1440 LockPoller(void * arg
)
1442 cacheDesc
* cache
= (cacheDesc
*)arg
;
1443 cacheDesc
* sharedCache
= cache
->sharedCache
;
1444 sidCacheLock
* pLock
;
1445 PRIntervalTime timeout
;
1448 int locks_polled
= 0;
1449 int locks_to_poll
= cache
->numSIDCacheLocks
+ 2;
1450 PRUint32 expiration
= cache
->mutexTimeout
;
1452 timeout
= PR_SecondsToInterval(expiration
);
1453 while(!sharedCache
->stopPolling
) {
1455 if (sharedCache
->stopPolling
)
1459 then
= now
- expiration
;
1460 for (pLock
= cache
->sidCacheLocks
, locks_polled
= 0;
1461 locks_to_poll
> locks_polled
&& !sharedCache
->stopPolling
;
1462 ++locks_polled
, ++pLock
) {
1465 if (pLock
->timeStamp
< then
&&
1466 pLock
->timeStamp
!= 0 &&
1467 (pid
= pLock
->pid
) != 0) {
1469 /* maybe we should try the lock? */
1470 int result
= kill(pid
, 0);
1471 if (result
< 0 && errno
== ESRCH
) {
1473 /* No process exists by that pid any more.
1474 ** Treat this mutex as abandoned.
1476 pLock
->timeStamp
= now
;
1478 rv
= sslMutex_Unlock(&pLock
->mutex
);
1479 if (rv
!= SECSuccess
) {
1484 } /* end of loop over locks */
1485 } /* end of entire polling loop */
1488 /* Launch thread to poll cache for expired locks */
1490 LaunchLockPoller(cacheDesc
*cache
)
1492 const char * timeoutString
;
1493 PRThread
* pollerThread
;
1495 cache
->mutexTimeout
= SID_LOCK_EXPIRATION_TIMEOUT
;
1496 timeoutString
= getenv("NSS_SSL_SERVER_CACHE_MUTEX_TIMEOUT");
1497 if (timeoutString
) {
1498 long newTime
= strtol(timeoutString
, 0, 0);
1500 return SECSuccess
; /* application doesn't want poller thread */
1502 cache
->mutexTimeout
= (PRUint32
)newTime
;
1503 /* if error (newTime < 0) ignore it and use default */
1507 PR_CreateThread(PR_USER_THREAD
, LockPoller
, cache
, PR_PRIORITY_NORMAL
,
1508 PR_GLOBAL_THREAD
, PR_JOINABLE_THREAD
, 0);
1509 if (!pollerThread
) {
1512 cache
->poller
= pollerThread
;
1516 /* Stop the thread that polls cache for expired locks */
1518 StopLockPoller(cacheDesc
*cache
)
1520 if (!cache
->poller
) {
1523 cache
->sharedCache
->stopPolling
= PR_TRUE
;
1524 if (PR_Interrupt(cache
->poller
) != PR_SUCCESS
) {
1527 if (PR_JoinThread(cache
->poller
) != PR_SUCCESS
) {
1530 cache
->poller
= NULL
;
1535 /************************************************************************
1536 * Code dealing with shared wrapped symmetric wrapping keys below *
1537 ************************************************************************/
1539 /* If now is zero, it implies that the lock is not held, and must be
1543 getSvrWrappingKey(PRInt32 symWrapMechIndex
,
1544 SSL3KEAType exchKeyType
,
1545 SSLWrappedSymWrappingKey
*wswk
,
1549 PRUint32 ndx
= (exchKeyType
* SSL_NUM_WRAP_MECHS
) + symWrapMechIndex
;
1550 SSLWrappedSymWrappingKey
* pwswk
= cache
->keyCacheData
+ ndx
;
1552 PRBool rv
= PR_FALSE
;
1554 if (!cache
->cacheMem
) { /* cache is uninitialized */
1555 PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED
);
1559 lockTime
= now
= LockSidCacheLock(cache
->keyCacheLock
, now
);
1564 if (pwswk
->exchKeyType
== exchKeyType
&&
1565 pwswk
->symWrapMechIndex
== symWrapMechIndex
&&
1566 pwswk
->wrappedSymKeyLen
!= 0) {
1571 UnlockSidCacheLock(cache
->keyCacheLock
);
1577 ssl_GetWrappingKey( PRInt32 symWrapMechIndex
,
1578 SSL3KEAType exchKeyType
,
1579 SSLWrappedSymWrappingKey
*wswk
)
1583 PORT_Assert( (unsigned)exchKeyType
< kt_kea_size
);
1584 PORT_Assert( (unsigned)symWrapMechIndex
< SSL_NUM_WRAP_MECHS
);
1585 if ((unsigned)exchKeyType
< kt_kea_size
&&
1586 (unsigned)symWrapMechIndex
< SSL_NUM_WRAP_MECHS
) {
1587 rv
= getSvrWrappingKey(symWrapMechIndex
, exchKeyType
, wswk
,
1596 /* The caller passes in the new value it wants
1597 * to set. This code tests the wrapped sym key entry in the shared memory.
1598 * If it is uninitialized, this function writes the caller's value into
1599 * the disk entry, and returns false.
1600 * Otherwise, it overwrites the caller's wswk with the value obtained from
1601 * the disk, and returns PR_TRUE.
1602 * This is all done while holding the locks/mutexes necessary to make
1603 * the operation atomic.
1606 ssl_SetWrappingKey(SSLWrappedSymWrappingKey
*wswk
)
1608 cacheDesc
* cache
= &globalCache
;
1609 PRBool rv
= PR_FALSE
;
1610 SSL3KEAType exchKeyType
= wswk
->exchKeyType
;
1611 /* type of keys used to wrap SymWrapKey*/
1612 PRInt32 symWrapMechIndex
= wswk
->symWrapMechIndex
;
1615 SSLWrappedSymWrappingKey myWswk
;
1617 if (!cache
->cacheMem
) { /* cache is uninitialized */
1618 PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED
);
1622 PORT_Assert( (unsigned)exchKeyType
< kt_kea_size
);
1623 if ((unsigned)exchKeyType
>= kt_kea_size
)
1626 PORT_Assert( (unsigned)symWrapMechIndex
< SSL_NUM_WRAP_MECHS
);
1627 if ((unsigned)symWrapMechIndex
>= SSL_NUM_WRAP_MECHS
)
1630 ndx
= (exchKeyType
* SSL_NUM_WRAP_MECHS
) + symWrapMechIndex
;
1631 PORT_Memset(&myWswk
, 0, sizeof myWswk
); /* eliminate UMRs. */
1633 now
= LockSidCacheLock(cache
->keyCacheLock
, now
);
1635 rv
= getSvrWrappingKey(wswk
->symWrapMechIndex
, wswk
->exchKeyType
,
1636 &myWswk
, cache
, now
);
1638 /* we found it on disk, copy it out to the caller. */
1639 PORT_Memcpy(wswk
, &myWswk
, sizeof *wswk
);
1641 /* Wasn't on disk, and we're still holding the lock, so write it. */
1642 cache
->keyCacheData
[ndx
] = *wswk
;
1644 UnlockSidCacheLock(cache
->keyCacheLock
);
1649 #else /* MAC version or other platform */
1651 #include "seccomon.h"
1654 #include "sslimpl.h"
1657 SSL_ConfigServerSessionIDCache( int maxCacheEntries
,
1658 PRUint32 ssl2_timeout
,
1659 PRUint32 ssl3_timeout
,
1660 const char * directory
)
1662 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigServerSessionIDCache)");
1667 SSL_ConfigMPServerSIDCache( int maxCacheEntries
,
1668 PRUint32 ssl2_timeout
,
1669 PRUint32 ssl3_timeout
,
1670 const char * directory
)
1672 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigMPServerSIDCache)");
1677 SSL_InheritMPServerSIDCache(const char * envString
)
1679 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_InheritMPServerSIDCache)");
1684 ssl_GetWrappingKey( PRInt32 symWrapMechIndex
,
1685 SSL3KEAType exchKeyType
,
1686 SSLWrappedSymWrappingKey
*wswk
)
1688 PRBool rv
= PR_FALSE
;
1689 PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)");
1693 /* This is a kind of test-and-set. The caller passes in the new value it wants
1694 * to set. This code tests the wrapped sym key entry in the shared memory.
1695 * If it is uninitialized, this function writes the caller's value into
1696 * the disk entry, and returns false.
1697 * Otherwise, it overwrites the caller's wswk with the value obtained from
1698 * the disk, and returns PR_TRUE.
1699 * This is all done while holding the locks/mutexes necessary to make
1700 * the operation atomic.
1703 ssl_SetWrappingKey(SSLWrappedSymWrappingKey
*wswk
)
1705 PRBool rv
= PR_FALSE
;
1706 PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrappingKey)");
1711 SSL_GetMaxServerCacheLocks(void)
1713 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_GetMaxServerCacheLocks)");
1718 SSL_SetMaxServerCacheLocks(PRUint32 maxLocks
)
1720 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_SetMaxServerCacheLocks)");
1724 #endif /* XP_UNIX || XP_WIN32 */