PageRenderTime 63ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/security/nss/lib/ssl/sslsnce.c

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