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