Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1401)

Unified Diff: net/third_party/nss/ssl/sslnonce.c

Issue 394003: Linux: enable building with a local version of libssl. (Closed)
Patch Set: ... Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/third_party/nss/ssl/sslmutex.c ('k') | net/third_party/nss/ssl/sslproto.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/third_party/nss/ssl/sslnonce.c
diff --git a/net/third_party/nss/ssl/sslnonce.c b/net/third_party/nss/ssl/sslnonce.c
new file mode 100644
index 0000000000000000000000000000000000000000..63dc5a28507bf9a7c2194e03f52d47620010f900
--- /dev/null
+++ b/net/third_party/nss/ssl/sslnonce.c
@@ -0,0 +1,530 @@
+/*
+ * This file implements the CLIENT Session ID cache.
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/* $Id: sslnonce.c,v 1.25 2008/03/10 00:01:28 wtc%google.com Exp $ */
+
+#include "cert.h"
+#include "pk11pub.h"
+#include "secitem.h"
+#include "ssl.h"
+#include "nss.h"
+
+#include "sslimpl.h"
+#include "sslproto.h"
+#include "nssilock.h"
+#if (defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS)) && !defined(_WIN32_WCE)
+#include <time.h>
+#endif
+
+PRUint32 ssl_sid_timeout = 100;
+PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */
+
+static sslSessionID *cache = NULL;
+static PZLock * cacheLock = NULL;
+
+/* sids can be in one of 4 states:
+ *
+ * never_cached, created, but not yet put into cache.
+ * in_client_cache, in the client cache's linked list.
+ * in_server_cache, entry came from the server's cache file.
+ * invalid_cache has been removed from the cache.
+ */
+
+#define LOCK_CACHE lock_cache()
+#define UNLOCK_CACHE PZ_Unlock(cacheLock)
+
+static SECStatus
+ssl_InitClientSessionCacheLock(void)
+{
+ cacheLock = PZ_NewLock(nssILockCache);
+ return cacheLock ? SECSuccess : SECFailure;
+}
+
+static SECStatus
+ssl_FreeClientSessionCacheLock(void)
+{
+ if (cacheLock) {
+ PZ_DestroyLock(cacheLock);
+ cacheLock = NULL;
+ return SECSuccess;
+ }
+ PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+ return SECFailure;
+}
+
+static PRBool LocksInitializedEarly = PR_FALSE;
+
+static SECStatus
+FreeSessionCacheLocks()
+{
+ SECStatus rv1, rv2;
+ rv1 = ssl_FreeSymWrapKeysLock();
+ rv2 = ssl_FreeClientSessionCacheLock();
+ if ( (SECSuccess == rv1) && (SECSuccess == rv2) ) {
+ return SECSuccess;
+ }
+ return SECFailure;
+}
+
+static SECStatus
+InitSessionCacheLocks(void)
+{
+ SECStatus rv1, rv2;
+ PRErrorCode rc;
+ rv1 = ssl_InitSymWrapKeysLock();
+ rv2 = ssl_InitClientSessionCacheLock();
+ if ( (SECSuccess == rv1) && (SECSuccess == rv2) ) {
+ return SECSuccess;
+ }
+ rc = PORT_GetError();
+ FreeSessionCacheLocks();
+ PORT_SetError(rc);
+ return SECFailure;
+}
+
+/* free the session cache locks if they were initialized early */
+SECStatus
+ssl_FreeSessionCacheLocks()
+{
+ PORT_Assert(PR_TRUE == LocksInitializedEarly);
+ if (!LocksInitializedEarly) {
+ PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+ return SECFailure;
+ }
+ FreeSessionCacheLocks();
+ LocksInitializedEarly = PR_FALSE;
+ return SECSuccess;
+}
+
+static PRCallOnceType lockOnce;
+
+/* free the session cache locks if they were initialized lazily */
+static SECStatus ssl_ShutdownLocks(void* appData, void* nssData)
+{
+ PORT_Assert(PR_FALSE == LocksInitializedEarly);
+ if (LocksInitializedEarly) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ FreeSessionCacheLocks();
+ memset(&lockOnce, 0, sizeof(lockOnce));
+ return SECSuccess;
+}
+
+static PRStatus initSessionCacheLocksLazily(void)
+{
+ SECStatus rv = InitSessionCacheLocks();
+ if (SECSuccess != rv) {
+ return PR_FAILURE;
+ }
+ rv = NSS_RegisterShutdown(ssl_ShutdownLocks, NULL);
+ PORT_Assert(SECSuccess == rv);
+ if (SECSuccess != rv) {
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
+
+/* lazyInit means that the call is not happening during a 1-time
+ * initialization function, but rather during dynamic, lazy initialization
+ */
+SECStatus
+ssl_InitSessionCacheLocks(PRBool lazyInit)
+{
+ if (LocksInitializedEarly) {
+ return SECSuccess;
+ }
+
+ if (lazyInit) {
+ return (PR_SUCCESS ==
+ PR_CallOnce(&lockOnce, initSessionCacheLocksLazily)) ?
+ SECSuccess : SECFailure;
+ }
+
+ if (SECSuccess == InitSessionCacheLocks()) {
+ LocksInitializedEarly = PR_TRUE;
+ return SECSuccess;
+ }
+
+ return SECFailure;
+}
+
+static void
+lock_cache(void)
+{
+ ssl_InitSessionCacheLocks(PR_TRUE);
+ PZ_Lock(cacheLock);
+}
+
+/* BEWARE: This function gets called for both client and server SIDs !!
+ * If the unreferenced sid is not in the cache, Free sid and its contents.
+ */
+static void
+ssl_DestroySID(sslSessionID *sid)
+{
+ SSL_TRC(8, ("SSL: destroy sid: sid=0x%x cached=%d", sid, sid->cached));
+ PORT_Assert((sid->references == 0));
+
+ if (sid->cached == in_client_cache)
+ return; /* it will get taken care of next time cache is traversed. */
+
+ if (sid->version < SSL_LIBRARY_VERSION_3_0) {
+ SECITEM_ZfreeItem(&sid->u.ssl2.masterKey, PR_FALSE);
+ SECITEM_ZfreeItem(&sid->u.ssl2.cipherArg, PR_FALSE);
+ }
+ if (sid->peerID != NULL)
+ PORT_Free((void *)sid->peerID); /* CONST */
+
+ if (sid->urlSvrName != NULL)
+ PORT_Free((void *)sid->urlSvrName); /* CONST */
+
+ if ( sid->peerCert ) {
+ CERT_DestroyCertificate(sid->peerCert);
+ }
+ if ( sid->localCert ) {
+ CERT_DestroyCertificate(sid->localCert);
+ }
+ if (sid->u.ssl3.sessionTicket.ticket.data) {
+ SECITEM_FreeItem(&sid->u.ssl3.sessionTicket.ticket, PR_FALSE);
+ }
+
+ PORT_ZFree(sid, sizeof(sslSessionID));
+}
+
+/* BEWARE: This function gets called for both client and server SIDs !!
+ * Decrement reference count, and
+ * free sid if ref count is zero, and sid is not in the cache.
+ * Does NOT remove from the cache first.
+ * If the sid is still in the cache, it is left there until next time
+ * the cache list is traversed.
+ */
+static void
+ssl_FreeLockedSID(sslSessionID *sid)
+{
+ PORT_Assert(sid->references >= 1);
+ if (--sid->references == 0) {
+ ssl_DestroySID(sid);
+ }
+}
+
+/* BEWARE: This function gets called for both client and server SIDs !!
+ * Decrement reference count, and
+ * free sid if ref count is zero, and sid is not in the cache.
+ * Does NOT remove from the cache first.
+ * These locks are necessary because the sid _might_ be in the cache list.
+ */
+void
+ssl_FreeSID(sslSessionID *sid)
+{
+ LOCK_CACHE;
+ ssl_FreeLockedSID(sid);
+ UNLOCK_CACHE;
+}
+
+/************************************************************************/
+
+/*
+** Lookup sid entry in cache by Address, port, and peerID string.
+** If found, Increment reference count, and return pointer to caller.
+** If it has timed out or ref count is zero, remove from list and free it.
+*/
+
+sslSessionID *
+ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID,
+ const char * urlSvrName)
+{
+ sslSessionID **sidp;
+ sslSessionID * sid;
+ PRUint32 now;
+
+ if (!urlSvrName)
+ return NULL;
+ now = ssl_Time();
+ LOCK_CACHE;
+ sidp = &cache;
+ while ((sid = *sidp) != 0) {
+ PORT_Assert(sid->cached == in_client_cache);
+ PORT_Assert(sid->references >= 1);
+
+ SSL_TRC(8, ("SSL: Lookup1: sid=0x%x", sid));
+
+ if (sid->expirationTime < now || !sid->references) {
+ /*
+ ** This session-id timed out, or was orphaned.
+ ** Don't even care who it belongs to, blow it out of our cache.
+ */
+ SSL_TRC(7, ("SSL: lookup1, throwing sid out, age=%d refs=%d",
+ now - sid->creationTime, sid->references));
+
+ *sidp = sid->next; /* delink it from the list. */
+ sid->cached = invalid_cache; /* mark not on list. */
+ if (!sid->references)
+ ssl_DestroySID(sid);
+ else
+ ssl_FreeLockedSID(sid); /* drop ref count, free. */
+
+ } else if (!memcmp(&sid->addr, addr, sizeof(PRIPv6Addr)) && /* server IP addr matches */
+ (sid->port == port) && /* server port matches */
+ /* proxy (peerID) matches */
+ (((peerID == NULL) && (sid->peerID == NULL)) ||
+ ((peerID != NULL) && (sid->peerID != NULL) &&
+ PORT_Strcmp(sid->peerID, peerID) == 0)) &&
+ /* is cacheable */
+ (sid->version < SSL_LIBRARY_VERSION_3_0 ||
+ sid->u.ssl3.keys.resumable) &&
+ /* server hostname matches. */
+ (sid->urlSvrName != NULL) &&
+ ((0 == PORT_Strcmp(urlSvrName, sid->urlSvrName)) ||
+ ((sid->peerCert != NULL) && (SECSuccess ==
+ CERT_VerifyCertName(sid->peerCert, urlSvrName))) )
+ ) {
+ /* Hit */
+ sid->lastAccessTime = now;
+ sid->references++;
+ break;
+ } else {
+ sidp = &sid->next;
+ }
+ }
+ UNLOCK_CACHE;
+ return sid;
+}
+
+/*
+** Add an sid to the cache or return a previously cached entry to the cache.
+** Although this is static, it is called via ss->sec.cache().
+*/
+static void
+CacheSID(sslSessionID *sid)
+{
+ PRUint32 expirationPeriod;
+ SSL_TRC(8, ("SSL: Cache: sid=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x "
+ "time=%x cached=%d",
+ sid, sid->cached, sid->addr.pr_s6_addr32[0],
+ sid->addr.pr_s6_addr32[1], sid->addr.pr_s6_addr32[2],
+ sid->addr.pr_s6_addr32[3], sid->port, sid->creationTime,
+ sid->cached));
+
+ if (sid->cached == in_client_cache)
+ return;
+
+ if (!sid->urlSvrName) {
+ /* don't cache this SID because it can never be matched */
+ return;
+ }
+
+ /* XXX should be different trace for version 2 vs. version 3 */
+ if (sid->version < SSL_LIBRARY_VERSION_3_0) {
+ expirationPeriod = ssl_sid_timeout;
+ PRINT_BUF(8, (0, "sessionID:",
+ sid->u.ssl2.sessionID, sizeof(sid->u.ssl2.sessionID)));
+ PRINT_BUF(8, (0, "masterKey:",
+ sid->u.ssl2.masterKey.data, sid->u.ssl2.masterKey.len));
+ PRINT_BUF(8, (0, "cipherArg:",
+ sid->u.ssl2.cipherArg.data, sid->u.ssl2.cipherArg.len));
+ } else {
+ if (sid->u.ssl3.sessionIDLength == 0 &&
+ sid->u.ssl3.sessionTicket.ticket.data == NULL)
+ return;
+ /* Client generates the SessionID if this was a stateless resume. */
+ if (sid->u.ssl3.sessionIDLength == 0) {
+ SECStatus rv;
+ rv = PK11_GenerateRandom(sid->u.ssl3.sessionID,
+ SSL3_SESSIONID_BYTES);
+ if (rv != SECSuccess)
+ return;
+ sid->u.ssl3.sessionIDLength = SSL3_SESSIONID_BYTES;
+ }
+ expirationPeriod = ssl3_sid_timeout;
+ PRINT_BUF(8, (0, "sessionID:",
+ sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength));
+ }
+ PORT_Assert(sid->creationTime != 0 && sid->expirationTime != 0);
+ if (!sid->creationTime)
+ sid->lastAccessTime = sid->creationTime = ssl_Time();
+ if (!sid->expirationTime)
+ sid->expirationTime = sid->creationTime + expirationPeriod;
+
+ /*
+ * Put sid into the cache. Bump reference count to indicate that
+ * cache is holding a reference. Uncache will reduce the cache
+ * reference.
+ */
+ LOCK_CACHE;
+ sid->references++;
+ sid->cached = in_client_cache;
+ sid->next = cache;
+ cache = sid;
+ UNLOCK_CACHE;
+}
+
+/*
+ * If sid "zap" is in the cache,
+ * removes sid from cache, and decrements reference count.
+ * Caller must hold cache lock.
+ */
+static void
+UncacheSID(sslSessionID *zap)
+{
+ sslSessionID **sidp = &cache;
+ sslSessionID *sid;
+
+ if (zap->cached != in_client_cache) {
+ return;
+ }
+
+ SSL_TRC(8,("SSL: Uncache: zap=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x "
+ "time=%x cipher=%d",
+ zap, zap->cached, zap->addr.pr_s6_addr32[0],
+ zap->addr.pr_s6_addr32[1], zap->addr.pr_s6_addr32[2],
+ zap->addr.pr_s6_addr32[3], zap->port, zap->creationTime,
+ zap->u.ssl2.cipherType));
+ if (zap->version < SSL_LIBRARY_VERSION_3_0) {
+ PRINT_BUF(8, (0, "sessionID:",
+ zap->u.ssl2.sessionID, sizeof(zap->u.ssl2.sessionID)));
+ PRINT_BUF(8, (0, "masterKey:",
+ zap->u.ssl2.masterKey.data, zap->u.ssl2.masterKey.len));
+ PRINT_BUF(8, (0, "cipherArg:",
+ zap->u.ssl2.cipherArg.data, zap->u.ssl2.cipherArg.len));
+ }
+
+ /* See if it's in the cache, if so nuke it */
+ while ((sid = *sidp) != 0) {
+ if (sid == zap) {
+ /*
+ ** Bingo. Reduce reference count by one so that when
+ ** everyone is done with the sid we can free it up.
+ */
+ *sidp = zap->next;
+ zap->cached = invalid_cache;
+ ssl_FreeLockedSID(zap);
+ return;
+ }
+ sidp = &sid->next;
+ }
+}
+
+/* If sid "zap" is in the cache,
+ * removes sid from cache, and decrements reference count.
+ * Although this function is static, it is called externally via
+ * ss->sec.uncache().
+ */
+static void
+LockAndUncacheSID(sslSessionID *zap)
+{
+ LOCK_CACHE;
+ UncacheSID(zap);
+ UNLOCK_CACHE;
+
+}
+
+/* choose client or server cache functions for this sslsocket. */
+void
+ssl_ChooseSessionIDProcs(sslSecurityInfo *sec)
+{
+ if (sec->isServer) {
+ sec->cache = ssl_sid_cache;
+ sec->uncache = ssl_sid_uncache;
+ } else {
+ sec->cache = CacheSID;
+ sec->uncache = LockAndUncacheSID;
+ }
+}
+
+/* wipe out the entire client session cache. */
+void
+SSL_ClearSessionCache(void)
+{
+ LOCK_CACHE;
+ while(cache != NULL)
+ UncacheSID(cache);
+ UNLOCK_CACHE;
+}
+
+/* returns an unsigned int containing the number of seconds in PR_Now() */
+PRUint32
+ssl_Time(void)
+{
+ PRUint32 myTime;
+#if (defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS)) && !defined(_WIN32_WCE)
+ myTime = time(NULL); /* accurate until the year 2038. */
+#else
+ /* portable, but possibly slower */
+ PRTime now;
+ PRInt64 ll;
+
+ now = PR_Now();
+ LL_I2L(ll, 1000000L);
+ LL_DIV(now, now, ll);
+ LL_L2UI(myTime, now);
+#endif
+ return myTime;
+}
+
+SECStatus
+ssl3_SetSIDSessionTicket(sslSessionID *sid, NewSessionTicket *session_ticket)
+{
+ SECStatus rv;
+
+ /* We need to lock the cache, as this sid might already be in the cache. */
+ LOCK_CACHE;
+
+ /* A server might have sent us an empty ticket, which has the
+ * effect of clearing the previously known ticket.
+ */
+ if (sid->u.ssl3.sessionTicket.ticket.data)
+ SECITEM_FreeItem(&sid->u.ssl3.sessionTicket.ticket, PR_FALSE);
+ if (session_ticket->ticket.len > 0) {
+ rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.sessionTicket.ticket,
+ &session_ticket->ticket);
+ if (rv != SECSuccess) {
+ UNLOCK_CACHE;
+ return rv;
+ }
+ } else {
+ sid->u.ssl3.sessionTicket.ticket.data = NULL;
+ sid->u.ssl3.sessionTicket.ticket.len = 0;
+ }
+ sid->u.ssl3.sessionTicket.received_timestamp =
+ session_ticket->received_timestamp;
+ sid->u.ssl3.sessionTicket.ticket_lifetime_hint =
+ session_ticket->ticket_lifetime_hint;
+
+ UNLOCK_CACHE;
+ return SECSuccess;
+}
« no previous file with comments | « net/third_party/nss/ssl/sslmutex.c ('k') | net/third_party/nss/ssl/sslproto.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698