OLD | NEW |
| (Empty) |
1 /* This file implements the SERVER Session ID cache. | |
2 * NOTE: The contents of this file are NOT used by the client. | |
3 * | |
4 * This Source Code Form is subject to the terms of the Mozilla Public | |
5 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
7 | |
8 /* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server | |
9 * cache sids! | |
10 * | |
11 * About record locking among different server processes: | |
12 * | |
13 * All processes that are part of the same conceptual server (serving on | |
14 * the same address and port) MUST share a common SSL session cache. | |
15 * This code makes the content of the shared cache accessible to all | |
16 * processes on the same "server". This code works on Unix and Win32 only. | |
17 * | |
18 * We use NSPR anonymous shared memory and move data to & from shared memory. | |
19 * We must do explicit locking of the records for all reads and writes. | |
20 * The set of Cache entries are divided up into "sets" of 128 entries. | |
21 * Each set is protected by a lock. There may be one or more sets protected | |
22 * by each lock. That is, locks to sets are 1:N. | |
23 * There is one lock for the entire cert cache. | |
24 * There is one lock for the set of wrapped sym wrap keys. | |
25 * | |
26 * The anonymous shared memory is laid out as if it were declared like this: | |
27 * | |
28 * struct { | |
29 * cacheDescriptor desc; | |
30 * sidCacheLock sidCacheLocks[ numSIDCacheLocks]; | |
31 * sidCacheLock keyCacheLock; | |
32 * sidCacheLock certCacheLock; | |
33 * sidCacheSet sidCacheSets[ numSIDCacheSets ]; | |
34 * sidCacheEntry sidCacheData[ numSIDCacheEntries]; | |
35 * certCacheEntry certCacheData[numCertCacheEntries]; | |
36 * SSLWrappedSymWrappingKey keyCacheData[kt_kea_size][SSL_NUM_WRAP_MECHS]; | |
37 * PRUint8 keyNameSuffix[SESS_TICKET_KEY_VAR_NAME_LEN] | |
38 * encKeyCacheEntry ticketEncKey; // Wrapped in non-bypass mode | |
39 * encKeyCacheEntry ticketMacKey; // Wrapped in non-bypass mode | |
40 * PRBool ticketKeysValid; | |
41 * sidCacheLock srvNameCacheLock; | |
42 * srvNameCacheEntry srvNameData[ numSrvNameCacheEntries ]; | |
43 * } cacheMemCacheData; | |
44 */ | |
45 #include "seccomon.h" | |
46 | |
47 #if defined(XP_UNIX) || defined(XP_WIN32) || defined (XP_OS2) || defined(XP_BEOS
) | |
48 | |
49 #include "cert.h" | |
50 #include "ssl.h" | |
51 #include "sslimpl.h" | |
52 #include "sslproto.h" | |
53 #include "pk11func.h" | |
54 #include "base64.h" | |
55 #include "keyhi.h" | |
56 #ifdef NO_PKCS11_BYPASS | |
57 #include "blapit.h" | |
58 #include "sechash.h" | |
59 #else | |
60 #include "blapi.h" | |
61 #endif | |
62 | |
63 #include <stdio.h> | |
64 | |
65 #if defined(XP_UNIX) || defined(XP_BEOS) | |
66 | |
67 #include <syslog.h> | |
68 #include <fcntl.h> | |
69 #include <unistd.h> | |
70 #include <errno.h> | |
71 #include <signal.h> | |
72 #include "unix_err.h" | |
73 | |
74 #else | |
75 | |
76 #ifdef XP_WIN32 | |
77 #include <wtypes.h> | |
78 #include "win32err.h" | |
79 #endif | |
80 | |
81 #endif | |
82 #include <sys/types.h> | |
83 | |
84 #define SET_ERROR_CODE /* reminder */ | |
85 | |
86 #include "nspr.h" | |
87 #include "sslmutex.h" | |
88 | |
89 /* | |
90 ** Format of a cache entry in the shared memory. | |
91 */ | |
92 struct sidCacheEntryStr { | |
93 /* 16 */ PRIPv6Addr addr; /* client's IP address */ | |
94 /* 4 */ PRUint32 creationTime; | |
95 /* 4 */ PRUint32 lastAccessTime; | |
96 /* 4 */ PRUint32 expirationTime; | |
97 /* 2 */ PRUint16 version; | |
98 /* 1 */ PRUint8 valid; | |
99 /* 1 */ PRUint8 sessionIDLength; | |
100 /* 32 */ PRUint8 sessionID[SSL3_SESSIONID_BYTES]; | |
101 /* 2 */ PRUint16 authAlgorithm; | |
102 /* 2 */ PRUint16 authKeyBits; | |
103 /* 2 */ PRUint16 keaType; | |
104 /* 2 */ PRUint16 keaKeyBits; | |
105 /* 72 - common header total */ | |
106 | |
107 union { | |
108 struct { | |
109 /* 64 */ PRUint8 masterKey[SSL_MAX_MASTER_KEY_BYTES]; | |
110 /* 32 */ PRUint8 cipherArg[SSL_MAX_CYPHER_ARG_BYTES]; | |
111 | |
112 /* 1 */ PRUint8 cipherType; | |
113 /* 1 */ PRUint8 masterKeyLen; | |
114 /* 1 */ PRUint8 keyBits; | |
115 /* 1 */ PRUint8 secretKeyBits; | |
116 /* 1 */ PRUint8 cipherArgLen; | |
117 /*101 */} ssl2; | |
118 | |
119 struct { | |
120 /* 2 */ ssl3CipherSuite cipherSuite; | |
121 /* 2 */ PRUint16 compression; /* SSLCompressionMethod */ | |
122 | |
123 /* 52 */ ssl3SidKeys keys; /* keys, wrapped as needed. */ | |
124 | |
125 /* 4 */ PRUint32 masterWrapMech; | |
126 /* 4 */ SSL3KEAType exchKeyType; | |
127 /* 4 */ PRInt32 certIndex; | |
128 /* 4 */ PRInt32 srvNameIndex; | |
129 /* 32 */ PRUint8 srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */ | |
130 /*104 */} ssl3; | |
131 /* force sizeof(sidCacheEntry) to be a multiple of cache line size */ | |
132 struct { | |
133 /*120 */ PRUint8 filler[120]; /* 72+120==192, a multiple of 16 */ | |
134 } forceSize; | |
135 } u; | |
136 }; | |
137 typedef struct sidCacheEntryStr sidCacheEntry; | |
138 | |
139 /* The length of this struct is supposed to be a power of 2, e.g. 4KB */ | |
140 struct 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 */ | |
146 typedef struct certCacheEntryStr certCacheEntry; | |
147 | |
148 struct sidCacheLockStr { | |
149 PRUint32 timeStamp; | |
150 sslMutex mutex; | |
151 sslPID pid; | |
152 }; | |
153 typedef struct sidCacheLockStr sidCacheLock; | |
154 | |
155 struct sidCacheSetStr { | |
156 PRIntn next; | |
157 }; | |
158 typedef struct sidCacheSetStr sidCacheSet; | |
159 | |
160 struct encKeyCacheEntryStr { | |
161 PRUint8 bytes[512]; | |
162 PRInt32 length; | |
163 }; | |
164 typedef struct encKeyCacheEntryStr encKeyCacheEntry; | |
165 | |
166 #define SSL_MAX_DNS_HOST_NAME 1024 | |
167 | |
168 struct 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 }; | |
175 typedef struct srvNameCacheEntryStr srvNameCacheEntry; | |
176 | |
177 | |
178 struct cacheDescStr { | |
179 | |
180 PRUint32 cacheMemSize; | |
181 | |
182 PRUint32 numSIDCacheLocks; | |
183 PRUint32 numSIDCacheSets; | |
184 PRUint32 numSIDCacheSetsPerLock; | |
185 | |
186 PRUint32 numSIDCacheEntries; | |
187 PRUint32 sidCacheSize; | |
188 | |
189 PRUint32 numCertCacheEntries; | |
190 PRUint32 certCacheSize; | |
191 | |
192 PRUint32 numKeyCacheEntries; | |
193 PRUint32 keyCacheSize; | |
194 | |
195 PRUint32 numSrvNameCacheEntries; | |
196 PRUint32 srvNameCacheSize; | |
197 | |
198 PRUint32 ssl2Timeout; | |
199 PRUint32 ssl3Timeout; | |
200 | |
201 PRUint32 numSIDCacheLocksInitialized; | |
202 | |
203 /* These values are volatile, and are accessed through sharedCache-> */ | |
204 PRUint32 nextCertCacheEntry; /* certCacheLock protects */ | |
205 PRBool stopPolling; | |
206 PRBool everInherited; | |
207 | |
208 /* The private copies of these values are pointers into shared mem */ | |
209 /* The copies of these values in shared memory are merely offsets */ | |
210 sidCacheLock * sidCacheLocks; | |
211 sidCacheLock * keyCacheLock; | |
212 sidCacheLock * certCacheLock; | |
213 sidCacheLock * srvNameCacheLock; | |
214 sidCacheSet * sidCacheSets; | |
215 sidCacheEntry * sidCacheData; | |
216 certCacheEntry * certCacheData; | |
217 SSLWrappedSymWrappingKey * keyCacheData; | |
218 PRUint8 * ticketKeyNameSuffix; | |
219 encKeyCacheEntry * ticketEncKey; | |
220 encKeyCacheEntry * ticketMacKey; | |
221 PRUint32 * ticketKeysValid; | |
222 srvNameCacheEntry * srvNameCacheData; | |
223 | |
224 /* Only the private copies of these pointers are valid */ | |
225 char * cacheMem; | |
226 struct cacheDescStr * sharedCache; /* shared copy of this struct */ | |
227 PRFileMap * cacheMemMap; | |
228 PRThread * poller; | |
229 PRUint32 mutexTimeout; | |
230 PRBool shared; | |
231 }; | |
232 typedef struct cacheDescStr cacheDesc; | |
233 | |
234 static cacheDesc globalCache; | |
235 | |
236 static const char envVarName[] = { SSL_ENV_VAR_NAME }; | |
237 | |
238 static PRBool isMultiProcess = PR_FALSE; | |
239 | |
240 | |
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 | |
270 static sslPID myPid; | |
271 static PRUint32 ssl_max_sid_cache_locks = MAX_SID_CACHE_LOCKS; | |
272 | |
273 /* forward static function declarations */ | |
274 static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, | |
275 unsigned nl); | |
276 static SECStatus LaunchLockPoller(cacheDesc *cache); | |
277 static SECStatus StopLockPoller(cacheDesc *cache); | |
278 | |
279 | |
280 struct inheritanceStr { | |
281 PRUint32 cacheMemSize; | |
282 PRUint32 fmStrLen; | |
283 }; | |
284 | |
285 typedef 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 | |
302 static PRUint32 | |
303 LockSidCacheLock(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 | |
315 static SECStatus | |
316 UnlockSidCacheLock(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. */ | |
326 static PRUint32 | |
327 LockSet(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 | |
335 static SECStatus | |
336 UnlockSet(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 */ | |
349 static PRUint32 | |
350 CacheCert(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. */ | |
394 static PLHashNumber | |
395 Get32BitNameHash(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 */ | |
407 static PRUint32 | |
408 CacheSrvName(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); | |
423 #ifdef NO_PKCS11_BYPASS | |
424 HASH_HashBuf(HASH_AlgSHA256, snce.nameHash, name->data, name->len); | |
425 #else | |
426 SHA256_HashBuf(snce.nameHash, (unsigned char*)name->data, | |
427 name->len); | |
428 #endif | |
429 /* 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 */ | |
452 static void | |
453 ConvertFromSID(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; | |
503 to->u.ssl3.compression = (PRUint16)from->u.ssl3.compression; | |
504 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 */ | |
527 static sslSessionID * | |
528 ConvertToSID(sidCacheEntry * from, | |
529 certCacheEntry * pcce, | |
530 srvNameCacheEntry *psnce, | |
531 CERTCertDBHandle * dbHandle) | |
532 { | |
533 sslSessionID *to; | |
534 PRUint16 version = from->version; | |
535 | |
536 to = PORT_ZNew(sslSessionID); | |
537 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.compres
sion; | |
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 */ | |
665 static PRUint32 | |
666 SIDindex(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 */ | |
690 static sidCacheEntry * | |
691 FindSID(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 */ | |
744 static sslSessionID * | |
745 ServerSessionIDLookup(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 */ | |
846 static void | |
847 ServerSessionIDCache(sslSessionID *sid) | |
848 { | |
849 sidCacheEntry sce; | |
850 PRUint32 now = 0; | |
851 PRUint16 version = sid->version; | |
852 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 tim
e=%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 tim
e=%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 */ | |
930 static void | |
931 ServerSessionIDUncache(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 | |
990 long 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 | |
999 static void | |
1000 CloseCache(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 | |
1031 static SECStatus | |
1032 InitCache(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_C
ACHE_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 | |
1130 cache->ticketKeyNameSuffix = (PRUint8 *)ptr; | |
1131 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 | |
1266 loser: | |
1267 CloseCache(cache); | |
1268 return SECFailure; | |
1269 } | |
1270 | |
1271 PRUint32 | |
1272 SSL_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 | |
1278 SECStatus | |
1279 SSL_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 | |
1295 static SECStatus | |
1296 ssl_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 | |
1307 PORT_Assert(sizeof(sidCacheEntry) == 192); | |
1308 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 | |
1334 SECStatus | |
1335 SSL_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 | |
1350 SECStatus | |
1351 SSL_ConfigServerSessionIDCache( int maxCacheEntries, | |
1352 PRUint32 ssl2_timeout, | |
1353 PRUint32 ssl3_timeout, | |
1354 const char * directory) | |
1355 { | |
1356 ssl_InitSessionCacheLocks(); | |
1357 return SSL_ConfigServerSessionIDCacheInstance(&globalCache, | |
1358 maxCacheEntries, ssl2_timeout, ssl3_timeout, directory, PR_FALSE
); | |
1359 } | |
1360 | |
1361 SECStatus | |
1362 SSL_ShutdownServerSessionIDCacheInstance(cacheDesc *cache) | |
1363 { | |
1364 CloseCache(cache); | |
1365 return SECSuccess; | |
1366 } | |
1367 | |
1368 SECStatus | |
1369 SSL_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 */ | |
1382 static SECStatus | |
1383 ssl_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 */ | |
1446 SECStatus | |
1447 SSL_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 | |
1459 SECStatus | |
1460 SSL_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(); | |
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 | |
1481 SECStatus | |
1482 SSL_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(); | |
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 | |
1654 loser: | |
1655 PORT_Free(myEnvString); | |
1656 if (decoString) | |
1657 PORT_Free(decoString); | |
1658 CloseCache(cache); | |
1659 return SECFailure; | |
1660 } | |
1661 | |
1662 SECStatus | |
1663 SSL_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 | |
1672 static void | |
1673 LockPoller(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 */ | |
1722 static SECStatus | |
1723 LaunchLockPoller(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 */ | |
1750 static SECStatus | |
1751 StopLockPoller(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 */ | |
1775 static PRBool | |
1776 getSvrWrappingKey(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 | |
1809 PRBool | |
1810 ssl_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. */ | |
1830 static PRBool | |
1831 WrapTicketKey(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 | |
1852 static PRBool | |
1853 GenerateTicketKeys(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; | |
1861 PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN]; | |
1862 PRUint8 *ticketKeyNameSuffix; | |
1863 | |
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 | |
1900 loser: | |
1901 if (aesKeyTmp) | |
1902 PK11_FreeSymKey(aesKeyTmp); | |
1903 if (macKeyTmp) | |
1904 PK11_FreeSymKey(macKeyTmp); | |
1905 return PR_FALSE; | |
1906 } | |
1907 | |
1908 static PRBool | |
1909 GenerateAndWrapTicketKeys(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 | |
1932 loser: | |
1933 if (aesKeyTmp) | |
1934 PK11_FreeSymKey(aesKeyTmp); | |
1935 if (macKeyTmp) | |
1936 PK11_FreeSymKey(macKeyTmp); | |
1937 return PR_FALSE; | |
1938 } | |
1939 | |
1940 static PRBool | |
1941 UnwrapCachedTicketKeys(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 | |
1975 loser: | |
1976 if (aesKeyTmp) | |
1977 PK11_FreeSymKey(aesKeyTmp); | |
1978 if (macKeyTmp) | |
1979 PK11_FreeSymKey(macKeyTmp); | |
1980 return PR_FALSE; | |
1981 } | |
1982 | |
1983 PRBool | |
1984 ssl_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 | |
2022 PRBool | |
2023 ssl_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; | |
2029 PRUint8 ticketMacKey[SHA256_LENGTH], ticketEncKey[AES_256_KEY_LENGTH]; | |
2030 PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN]; | |
2031 PRUint8 *ticketMacKeyPtr, *ticketEncKeyPtr, *ticketKeyNameSuffix; | |
2032 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 */ | |
2094 PRBool | |
2095 ssl_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 | |
2145 SECStatus | |
2146 SSL_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_ConfigServe
rSessionIDCache)"); | |
2152 return SECFailure; | |
2153 } | |
2154 | |
2155 SECStatus | |
2156 SSL_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_ConfigMPSer
verSIDCache)"); | |
2162 return SECFailure; | |
2163 } | |
2164 | |
2165 SECStatus | |
2166 SSL_InheritMPServerSIDCache(const char * envString) | |
2167 { | |
2168 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_InheritMPSe
rverSIDCache)"); | |
2169 return SECFailure; | |
2170 } | |
2171 | |
2172 PRBool | |
2173 ssl_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_GetWrapping
Key)"); | |
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 */ | |
2191 PRBool | |
2192 ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk) | |
2193 { | |
2194 PRBool rv = PR_FALSE; | |
2195 PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrapping
Key)"); | |
2196 return rv; | |
2197 } | |
2198 | |
2199 PRUint32 | |
2200 SSL_GetMaxServerCacheLocks(void) | |
2201 { | |
2202 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_GetMaxServe
rCacheLocks)"); | |
2203 return -1; | |
2204 } | |
2205 | |
2206 SECStatus | |
2207 SSL_SetMaxServerCacheLocks(PRUint32 maxLocks) | |
2208 { | |
2209 PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_SetMaxServe
rCacheLocks)"); | |
2210 return SECFailure; | |
2211 } | |
2212 | |
2213 #endif /* XP_UNIX || XP_WIN32 */ | |
OLD | NEW |