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