sslnonce.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:10k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /* 
  2.  * This file implements the CLIENT Session ID cache.  
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public
  5.  * License Version 1.1 (the "License"); you may not use this file
  6.  * except in compliance with the License. You may obtain a copy of
  7.  * the License at http://www.mozilla.org/MPL/
  8.  * 
  9.  * Software distributed under the License is distributed on an "AS
  10.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  11.  * implied. See the License for the specific language governing
  12.  * rights and limitations under the License.
  13.  * 
  14.  * The Original Code is the Netscape security libraries.
  15.  * 
  16.  * The Initial Developer of the Original Code is Netscape
  17.  * Communications Corporation.  Portions created by Netscape are 
  18.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  19.  * Rights Reserved.
  20.  * 
  21.  * Contributor(s):
  22.  * 
  23.  * Alternatively, the contents of this file may be used under the
  24.  * terms of the GNU General Public License Version 2 or later (the
  25.  * "GPL"), in which case the provisions of the GPL are applicable 
  26.  * instead of those above.  If you wish to allow use of your 
  27.  * version of this file only under the terms of the GPL and not to
  28.  * allow others to use your version of this file under the MPL,
  29.  * indicate your decision by deleting the provisions above and
  30.  * replace them with the notice and other provisions required by
  31.  * the GPL.  If you do not delete the provisions above, a recipient
  32.  * may use your version of this file under either the MPL or the
  33.  * GPL.
  34.  *
  35.  * $Id: sslnonce.c,v 1.4 2000/10/05 23:10:14 nelsonb%netscape.com Exp $
  36.  */
  37. #include "cert.h"
  38. #include "secitem.h"
  39. #include "ssl.h"
  40. #include "sslimpl.h"
  41. #include "sslproto.h"
  42. #include "prlock.h"
  43. #include "nsslocks.h"
  44. PRUint32 ssl_sid_timeout = 100;
  45. PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */
  46. static sslSessionID *cache;
  47. static PRLock *      cacheLock;
  48. /* sids can be in one of 4 states:
  49.  *
  50.  * never_cached,  created, but not yet put into cache. 
  51.  * in_client_cache,  in the client cache's linked list.
  52.  * in_server_cache,  entry came from the server's cache file.
  53.  * invalid_cache has been removed from the cache. 
  54.  */
  55. #define LOCK_CACHE  lock_cache()
  56. #define UNLOCK_CACHE PR_Unlock(cacheLock)
  57. static void 
  58. lock_cache(void)
  59. {
  60.     /* XXX Since the client session cache has no init function, we must
  61.      * XXX init the cacheLock on the first call.  Fix in NSS 3.0.
  62.      */
  63.     if (!cacheLock)
  64. nss_InitLock(&cacheLock);
  65.     PR_Lock(cacheLock);
  66. }
  67. /* BEWARE: This function gets called for both client and server SIDs !!
  68.  * If the unreferenced sid is not in the cache, Free sid and its contents.
  69.  */
  70. static void
  71. ssl_DestroySID(sslSessionID *sid)
  72. {
  73.     SSL_TRC(8, ("SSL: destroy sid: sid=0x%x cached=%d", sid, sid->cached));
  74.     PORT_Assert((sid->references == 0));
  75.     if (sid->cached == in_client_cache)
  76.      return; /* it will get taken care of next time cache is traversed. */
  77.     if (sid->version < SSL_LIBRARY_VERSION_3_0) {
  78. SECITEM_ZfreeItem(&sid->u.ssl2.masterKey, PR_FALSE);
  79. SECITEM_ZfreeItem(&sid->u.ssl2.cipherArg, PR_FALSE);
  80.     }
  81.     if (sid->peerID != NULL)
  82. PORT_Free((void *)sid->peerID); /* CONST */
  83.     if (sid->urlSvrName != NULL)
  84. PORT_Free((void *)sid->urlSvrName); /* CONST */
  85.     if ( sid->peerCert ) {
  86. CERT_DestroyCertificate(sid->peerCert);
  87.     }
  88.     
  89.     PORT_ZFree(sid, sizeof(sslSessionID));
  90. }
  91. /* BEWARE: This function gets called for both client and server SIDs !!
  92.  * Decrement reference count, and 
  93.  *    free sid if ref count is zero, and sid is not in the cache. 
  94.  * Does NOT remove from the cache first.  
  95.  * If the sid is still in the cache, it is left there until next time
  96.  * the cache list is traversed.
  97.  */
  98. static void 
  99. ssl_FreeLockedSID(sslSessionID *sid)
  100. {
  101.     PORT_Assert(sid->references >= 1);
  102.     if (--sid->references == 0) {
  103. ssl_DestroySID(sid);
  104.     }
  105. }
  106. /* BEWARE: This function gets called for both client and server SIDs !!
  107.  * Decrement reference count, and 
  108.  *    free sid if ref count is zero, and sid is not in the cache. 
  109.  * Does NOT remove from the cache first.  
  110.  * These locks are necessary because the sid _might_ be in the cache list.
  111.  */
  112. void
  113. ssl_FreeSID(sslSessionID *sid)
  114. {
  115.     LOCK_CACHE;
  116.     ssl_FreeLockedSID(sid);
  117.     UNLOCK_CACHE;
  118. }
  119. /************************************************************************/
  120. /*
  121. **  Lookup sid entry in cache by Address, port, and peerID string.
  122. **  If found, Increment reference count, and return pointer to caller.
  123. **  If it has timed out or ref count is zero, remove from list and free it.
  124. */
  125. sslSessionID *
  126. ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID, 
  127.               const char * urlSvrName)
  128. {
  129.     sslSessionID **sidp;
  130.     sslSessionID * sid;
  131.     PRUint32       now;
  132.     if (!urlSvrName)
  133.      return NULL;
  134.     now = ssl_Time();
  135.     LOCK_CACHE;
  136.     sidp = &cache;
  137.     while ((sid = *sidp) != 0) {
  138. PORT_Assert(sid->cached == in_client_cache);
  139. PORT_Assert(sid->references >= 1);
  140. SSL_TRC(8, ("SSL: Lookup1: sid=0x%x", sid));
  141. if (sid->time < now || !sid->references) {
  142.     /*
  143.     ** This session-id timed out, or was orphaned.
  144.     ** Don't even care who it belongs to, blow it out of our cache.
  145.     */
  146.     SSL_TRC(7, ("SSL: lookup1, throwing sid out, age=%d refs=%d",
  147. now - sid->time, sid->references));
  148.     *sidp = sid->next;  /* delink it from the list. */
  149.     sid->cached = invalid_cache; /* mark not on list. */
  150.     if (!sid->references)
  151.      ssl_DestroySID(sid);
  152.     else
  153. ssl_FreeLockedSID(sid); /* drop ref count, free. */
  154. } else if (!memcmp(&sid->addr, addr, sizeof(PRIPv6Addr)) && /* server IP addr matches */
  155.            (sid->port == port) && /* server port matches */
  156.    /* proxy (peerID) matches */
  157.    (((peerID == NULL) && (sid->peerID == NULL)) ||
  158.     ((peerID != NULL) && (sid->peerID != NULL) &&
  159.      PORT_Strcmp(sid->peerID, peerID) == 0)) &&
  160.    /* is cacheable */
  161.    (sid->version < SSL_LIBRARY_VERSION_3_0 ||
  162.     sid->u.ssl3.resumable) &&
  163.    /* server hostname matches. */
  164.            (sid->urlSvrName != NULL) &&
  165.    ((0 == PORT_Strcmp(urlSvrName, sid->urlSvrName)) ||
  166.     ((sid->peerCert != NULL) && (SECSuccess == 
  167.       CERT_VerifyCertName(sid->peerCert, urlSvrName))) )
  168.   ) {
  169.     /* Hit */
  170.     sid->references++;
  171.     break;
  172. } else {
  173.     sidp = &sid->next;
  174. }
  175.     }
  176.     UNLOCK_CACHE;
  177.     return sid;
  178. }
  179. /*
  180. ** Add an sid to the cache or return a previously cached entry to the cache.
  181. ** Although this is static, it is called via ss->sec->cache().
  182. */
  183. static void 
  184. CacheSID(sslSessionID *sid)
  185. {
  186.     PRUint32  expirationPeriod;
  187.     SSL_TRC(8, ("SSL: Cache: sid=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x "
  188. "time=%x cached=%d",
  189. sid, sid->cached, sid->addr.pr_s6_addr32[0], 
  190. sid->addr.pr_s6_addr32[1], sid->addr.pr_s6_addr32[2],
  191. sid->addr.pr_s6_addr32[3],  sid->port, sid->time,
  192. sid->cached));
  193.     if (sid->cached == in_client_cache)
  194. return;
  195.     /* XXX should be different trace for version 2 vs. version 3 */
  196.     if (sid->version < SSL_LIBRARY_VERSION_3_0) {
  197. expirationPeriod = ssl_sid_timeout;
  198. PRINT_BUF(8, (0, "sessionID:",
  199.   sid->u.ssl2.sessionID, sizeof(sid->u.ssl2.sessionID)));
  200. PRINT_BUF(8, (0, "masterKey:",
  201.   sid->u.ssl2.masterKey.data, sid->u.ssl2.masterKey.len));
  202. PRINT_BUF(8, (0, "cipherArg:",
  203.   sid->u.ssl2.cipherArg.data, sid->u.ssl2.cipherArg.len));
  204.     } else {
  205. if (sid->u.ssl3.sessionIDLength == 0) 
  206.     return;
  207. expirationPeriod = ssl3_sid_timeout;
  208. PRINT_BUF(8, (0, "sessionID:",
  209.       sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength));
  210.     }
  211.     /*
  212.      * Put sid into the cache.  Bump reference count to indicate that
  213.      * cache is holding a reference. Uncache will reduce the cache
  214.      * reference.
  215.      */
  216.     LOCK_CACHE;
  217.     sid->references++;
  218.     sid->cached = in_client_cache;
  219.     sid->next   = cache;
  220.     cache       = sid;
  221.     sid->time   = ssl_Time() + expirationPeriod;
  222.     UNLOCK_CACHE;
  223. }
  224. /* 
  225.  * If sid "zap" is in the cache,
  226.  *    removes sid from cache, and decrements reference count.
  227.  * Caller must hold cache lock.
  228.  */
  229. static void
  230. UncacheSID(sslSessionID *zap)
  231. {
  232.     sslSessionID **sidp = &cache;
  233.     sslSessionID *sid;
  234.     if (zap->cached != in_client_cache) {
  235. return;
  236.     }
  237.     SSL_TRC(8,("SSL: Uncache: zap=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x "
  238.        "time=%x cipher=%d",
  239.        zap, zap->cached, zap->addr.pr_s6_addr32[0],
  240.        zap->addr.pr_s6_addr32[1], zap->addr.pr_s6_addr32[2],
  241.        zap->addr.pr_s6_addr32[3], zap->port, zap->time,
  242.        zap->u.ssl2.cipherType));
  243.     if (zap->version < SSL_LIBRARY_VERSION_3_0) {
  244. PRINT_BUF(8, (0, "sessionID:",
  245.       zap->u.ssl2.sessionID, sizeof(zap->u.ssl2.sessionID)));
  246. PRINT_BUF(8, (0, "masterKey:",
  247.       zap->u.ssl2.masterKey.data, zap->u.ssl2.masterKey.len));
  248. PRINT_BUF(8, (0, "cipherArg:",
  249.       zap->u.ssl2.cipherArg.data, zap->u.ssl2.cipherArg.len));
  250.     }
  251.     /* See if it's in the cache, if so nuke it */
  252.     while ((sid = *sidp) != 0) {
  253. if (sid == zap) {
  254.     /*
  255.     ** Bingo. Reduce reference count by one so that when
  256.     ** everyone is done with the sid we can free it up.
  257.     */
  258.     *sidp = zap->next;
  259.     zap->cached = invalid_cache;
  260.     ssl_FreeLockedSID(zap);
  261.     return;
  262. }
  263. sidp = &sid->next;
  264.     }
  265. }
  266. /* If sid "zap" is in the cache,
  267.  *    removes sid from cache, and decrements reference count.
  268.  * Although this function is static, it is called externally via 
  269.  *    ss->sec->uncache().
  270.  */
  271. static void
  272. LockAndUncacheSID(sslSessionID *zap)
  273. {
  274.     LOCK_CACHE;
  275.     UncacheSID(zap);
  276.     UNLOCK_CACHE;
  277. }
  278. /* choose client or server cache functions for this sslsocket. */
  279. void 
  280. ssl_ChooseSessionIDProcs(sslSecurityInfo *sec)
  281. {
  282.     if (sec->isServer) {
  283. sec->cache   = ssl_sid_cache;
  284. sec->uncache = ssl_sid_uncache;
  285.     } else {
  286. sec->cache   = CacheSID;
  287. sec->uncache = LockAndUncacheSID;
  288.     }
  289. }
  290. /* wipe out the entire client session cache. */
  291. void
  292. SSL_ClearSessionCache(void)
  293. {
  294.     LOCK_CACHE;
  295.     while(cache != NULL)
  296. UncacheSID(cache);
  297.     UNLOCK_CACHE;
  298. }
  299. /* returns an unsigned int containing the number of seconds in PR_Now() */
  300. PRUint32
  301. ssl_Time(void)
  302. {
  303.     PRTime now;
  304.     PRInt64 ll;
  305.     PRUint32 time;
  306.     now = PR_Now();
  307.     LL_I2L(ll, 1000000L);
  308.     LL_DIV(now, now, ll);
  309.     LL_L2UI(time, now);
  310.     return time;
  311. }