X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/ed6778a32ecff23bc2dfb6ca452badd0c68774a0..563f4f96f568bcdc0a04a82f89cafe3bebbe43f1:/SecureTransport/appleSession.cpp diff --git a/SecureTransport/appleSession.cpp b/SecureTransport/appleSession.cpp deleted file mode 100644 index e0293155..00000000 --- a/SecureTransport/appleSession.cpp +++ /dev/null @@ -1,500 +0,0 @@ -/* - * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. - * - * The contents of this file constitute Original Code as defined in and are - * subject to the Apple Public Source License Version 1.2 (the 'License'). - * You may not use this file except in compliance with the License. Please obtain - * a copy of the License at http://www.apple.com/publicsource and read it before - * using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS - * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT - * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the - * specific language governing rights and limitations under the License. - */ - - -/* - File: appleSession.cpp - - Contains: Session storage module, Apple CDSA version. - - Written by: Doug Mitchell - - Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved. - -*/ - -/* - * The current implementation stores sessions in a deque<>, a member of a - * SessionCache object for which we keep a ModuleNexus-ized instance. It is - * expected that at a given time, only a small number of sessions will be - * cached, so the random insertion access provided by a map<> is unnecessary. - * New entries are placed in the head of the queue, assuming a LIFO usage - * tendency. - * - * Entries in this cache have a time to live of SESSION_CACHE_TTL, currently - * ten minutes. Entries are tested for being stale upon lookup; also, the global - * sslCleanupSession() tests all entries in the cache, deleting entries which - * are stale. This function is currently called whenever an SSLContext is deleted. - * The current design does not provide any asynchronous timed callouts to perform - * further cache cleanup; it was decided that the thread overhead of this would - * outweight the benefits (again assuming a small number of entries in the - * cache). - * - * When a session is added via sslAddSession, and a cache entry already - * exists for the specifed key (sessionID), the sessionData for the existing - * cache entry is updated with the new sessionData. The entry's expiration - * time is unchanged (thus a given session entry can only be used for a finite - * time no mattter how often it is re-used), - */ - -#include "ssl.h" -#include "sslMemory.h" -#include "sslDebug.h" -#include "appleSession.h" - -#include - -#include -#include -#include -#include -#include - -/* time-to-live in cache, in seconds */ -#define QUICK_CACHE_TEST 0 -#if QUICK_CACHE_TEST -#define SESSION_CACHE_TTL ((int)5) -#else -#define SESSION_CACHE_TTL ((int)(10 * 60)) -#endif /* QUICK_CACHE_TEST */ - -#define CACHE_PRINT 0 -#if CACHE_PRINT -#define DUMP_ALL_CACHE 0 - -static void cachePrint( - const SSLBuffer *key, - const SSLBuffer *data) -{ - unsigned char *kd = key->data; - if(data != NULL) { - unsigned char *dd = data->data; - printf(" key: %02X%02X%02X%02X%02X%02X%02X%02X" - " data: %02X%02X%02X%02X... (len %d)\n", - kd[0],kd[1],kd[2],kd[3], kd[4],kd[5],kd[6],kd[7], - dd[0],dd[1],dd[2],dd[3], (unsigned)data->length); - } - else { - /* just print key */ - printf(" key: %02X%02X%02X%02X%02X%02X%02X%02X\n", - kd[0],kd[1],kd[2],kd[3], kd[4],kd[5],kd[6],kd[7]); - } -} -#else /* !CACHE_PRINT */ -#define cachePrint(k, d) -#define DUMP_ALL_CACHE 0 -#endif /* CACHE_PRINT */ - -#if DUMP_ALL_CACHE -static void dumpAllCache(); -#else -#define dumpAllCache() -#endif - -/* - * One entry (value) in SessionCache. - */ -class SessionCacheEntry { -public: - /* - * This constructor, the only one, allocs copies of the key and value - * SSLBuffers. - */ - SessionCacheEntry( - const SSLBuffer &key, - const SSLBuffer &sessionData, - const Time::Absolute &expirationTime); - ~SessionCacheEntry(); - - /* basic lookup/match function */ - bool matchKey(const SSLBuffer &key) const; - - /* has this expired? */ - bool isStale(); // calculates "now" - bool isStale(const Time::Absolute &now); // when you know it - - /* key/data accessors */ - SSLBuffer &key() { return mKey; } - SSLBuffer &sessionData() { return mSessionData; } - - /* replace existing mSessionData */ - OSStatus sessionData(const SSLBuffer &data); - -private: - SSLBuffer mKey; - SSLBuffer mSessionData; - - /* this entry to be removed from session map at this time */ - Time::Absolute mExpiration; -}; - -/* - * Note: the caller passes in the expiration time solely to accomodate the - * instantiation of a single const Time::Interval for use in calculating - * TTL. This const, SessionCache.mTimeToLive, is in the singleton gSession Cache. - */ -SessionCacheEntry::SessionCacheEntry( - const SSLBuffer &key, - const SSLBuffer &sessionData, - const Time::Absolute &expirationTime) - : mExpiration(expirationTime) -{ - OSStatus serr; - - serr = SSLCopyBuffer(key, mKey); - if(serr) { - throw runtime_error("memory error"); - } - serr = SSLCopyBuffer(sessionData, mSessionData); - if(serr) { - throw runtime_error("memory error"); - } - sslLogSessCacheDebug("SessionCacheEntry(buf,buf) this %p", this); - mExpiration += Time::Interval(SESSION_CACHE_TTL); -} - -SessionCacheEntry::~SessionCacheEntry() -{ - sslLogSessCacheDebug("~SessionCacheEntry() this %p", this); - SSLFreeBuffer(mKey, NULL); // no SSLContext - SSLFreeBuffer(mSessionData, NULL); -} - -/* basic lookup/match function */ -bool SessionCacheEntry::matchKey(const SSLBuffer &key) const -{ - if(key.length != mKey.length) { - return false; - } - if((key.data == NULL) || (mKey.data == NULL)) { - return false; - } - return (memcmp(key.data, mKey.data, mKey.length) == 0); -} - -/* has this expired? */ -bool SessionCacheEntry::isStale() -{ - return isStale(Time::now()); -} - -bool SessionCacheEntry::isStale(const Time::Absolute &now) -{ - if(now > mExpiration) { - return true; - } - else { - return false; - } -} - -/* replace existing mSessionData */ -OSStatus SessionCacheEntry::sessionData( - const SSLBuffer &data) -{ - SSLFreeBuffer(mSessionData, NULL); - return SSLCopyBuffer(data, mSessionData); -} - -/* Types for the actual deque and its iterator */ -typedef std::deque SessionCacheType; -typedef SessionCacheType::iterator SessionCacheIter; - -/* - * Global map and associated state. We maintain a singleton of this. - */ -class SessionCache -{ -public: - SessionCache() - : mTimeToLive(SESSION_CACHE_TTL) {} - ~SessionCache(); - - /* these correspond to the C functions exported by this file */ - OSStatus addEntry( - const SSLBuffer sessionKey, - const SSLBuffer sessionData); - OSStatus lookupEntry( - const SSLBuffer sessionKey, - SSLBuffer *sessionData); - OSStatus deleteEntry( - const SSLBuffer sessionKey); - - /* cleanup, delete stale entries */ - bool cleanup(); - SessionCacheType &sessMap() { return mSessionCache; } - -private: - SessionCacheIter lookupPriv( - const SSLBuffer *sessionKey); - void deletePriv( - const SSLBuffer *sessionKey); - SessionCacheIter deletePriv( - SessionCacheIter iter); - SessionCacheType mSessionCache; - Mutex mSessionLock; - const Time::Interval mTimeToLive; -}; - -SessionCache::~SessionCache() -{ - /* free all entries */ - StLock _(mSessionLock); - for(SessionCacheIter iter = mSessionCache.begin(); iter != mSessionCache.end(); ) { - iter = deletePriv(iter); - } -} - -/* these three correspond to the C functions exported by this file */ -OSStatus SessionCache::addEntry( - const SSLBuffer sessionKey, - const SSLBuffer sessionData) -{ - StLock _(mSessionLock); - - SessionCacheIter existIter = lookupPriv(&sessionKey); - if(existIter != mSessionCache.end()) { - /* cache hit - just update this entry's sessionData if necessary */ - /* Note we leave expiration time and position in deque unchanged - OK? */ - SessionCacheEntry *existEntry = *existIter; - SSLBuffer &existBuf = existEntry->sessionData(); - if((existBuf.length == sessionData.length) && - (memcmp(existBuf.data, sessionData.data, sessionData.length) == 0)) { - /* - * These usually match, and a memcmp is a lot cheaper than - * a malloc and a free, hence this quick optimization..... - */ - sslLogSessCacheDebug("SessionCache::addEntry CACHE HIT " - "entry = %p", existEntry); - return noErr; - } - else { - sslLogSessCacheDebug("SessionCache::addEntry CACHE REPLACE " - "entry = %p", existEntry); - return existEntry->sessionData(sessionData); - } - } - - /* this allocs new copy of incoming sessionKey and sessionData */ - SessionCacheEntry *entry = new SessionCacheEntry(sessionKey, - sessionData, - Time::now() + mTimeToLive); - - sslLogSessCacheDebug("SessionCache::addEntry %p", entry); - cachePrint(&sessionKey, &sessionData); - dumpAllCache(); - - /* add to head of queue for LIFO caching */ - mSessionCache.push_front(entry); - assert(lookupPriv(&sessionKey) != mSessionCache.end()); - return noErr; -} - -OSStatus SessionCache::lookupEntry( - const SSLBuffer sessionKey, - SSLBuffer *sessionData) -{ - StLock _(mSessionLock); - - SessionCacheIter existIter = lookupPriv(&sessionKey); - if(existIter == mSessionCache.end()) { - return errSSLSessionNotFound; - } - SessionCacheEntry *entry = *existIter; - if(entry->isStale()) { - sslLogSessCacheDebug("SessionCache::lookupEntry %p: STALE " - "entry, deleting", entry); - cachePrint(&sessionKey, &entry->sessionData()); - deletePriv(existIter); - return errSSLSessionNotFound; - } - /* alloc/copy sessionData from existing entry (caller must free) */ - return SSLCopyBuffer(entry->sessionData(), *sessionData); -} - -OSStatus SessionCache::deleteEntry( - const SSLBuffer sessionKey) -{ - StLock _(mSessionLock); - deletePriv(&sessionKey); - return noErr; -} - -/* cleanup, delete stale entries */ -bool SessionCache::cleanup() -{ - StLock _(mSessionLock); - bool brtn = false; - Time::Absolute rightNow = Time::now(); - SessionCacheIter iter; - - for(iter = mSessionCache.begin(); iter != mSessionCache.end(); ) { - SessionCacheEntry *entry = *iter; - if(entry->isStale(rightNow)) { - #ifndef DEBUG - sslLogSessCacheDebug("...SessionCache::cleanup: deleting " - "cached session (%p)", entry); - cachePrint(&entry->key(), &entry->sessionData()); - #endif - iter = deletePriv(iter); - } - else { - iter++; - /* we're leaving one in the map */ - brtn = true; - } - } - return brtn; -} - -/* private methods, mSessionLock held on entry and exit */ -SessionCacheIter SessionCache::lookupPriv( - const SSLBuffer *sessionKey) -{ - SessionCacheIter it; - - for(it = mSessionCache.begin(); it != mSessionCache.end(); it++) { - SessionCacheEntry *entry = *it; - if(entry->matchKey(*sessionKey)) { - return it; - } - } - /* returning map.end() */ - return it; -} - -void SessionCache::deletePriv( - const SSLBuffer *sessionKey) -{ - SessionCacheIter iter = lookupPriv(sessionKey); - if(iter != mSessionCache.end()) { - /* - * delete from map - * free underlying SSLBuffer.data pointers - * destruct the stored map entry - */ - #if CACHE_PRINT - SessionCacheEntry *entry = *iter; - sslLogSessCacheDebug("SessionCache::deletePriv %p", entry); - cachePrint(sessionKey, &entry->sessionData()); - dumpAllCache(); - #endif - deletePriv(iter); - } - assert(lookupPriv(sessionKey) == mSessionCache.end()); -} - -/* common erase, given a SessionCacheIter; returns next iter */ -SessionCacheIter SessionCache::deletePriv( - SessionCacheIter iter) -{ - assert(iter != mSessionCache.end()); - SessionCacheEntry *entry = *iter; - SessionCacheIter nextIter = mSessionCache.erase(iter); - delete entry; - return nextIter; -} - -/* the single global thing */ -static ModuleNexus gSessionCache; - -#if DUMP_ALL_CACHE -static void dumpAllCache() -{ - SessionCacheIter it; - SessionCacheType &smap = gSessionCache().sessMap(); - - printf("Contents of sessionCache:\n"); - for(it = smap.begin(); it != smap.end(); it++) { - SessionCacheEntry *entry = *it; - cachePrint(&entry->key(), &entry->sessionData()); - } -} -#endif /* DUMP_ALL_CACHE */ - -/* - * Store opaque sessionData, associated with opaque sessionKey. - */ -OSStatus sslAddSession ( - const SSLBuffer sessionKey, - const SSLBuffer sessionData) -{ - OSStatus serr; - try { - serr = gSessionCache().addEntry(sessionKey, sessionData); - } - catch(...) { - serr = unimpErr; - } - dumpAllCache(); - return serr; -} - -/* - * Given an opaque sessionKey, alloc & retrieve associated sessionData. - */ -OSStatus sslGetSession ( - const SSLBuffer sessionKey, - SSLBuffer *sessionData) -{ - OSStatus serr; - try { - serr = gSessionCache().lookupEntry(sessionKey, sessionData); - } - catch(...) { - serr = errSSLSessionNotFound; - } - sslLogSessCacheDebug("sslGetSession(%d, %p): %ld", - (int)sessionKey.length, sessionKey.data, - serr); - if(serr == noErr) { - cachePrint(&sessionKey, sessionData); - } - else { - cachePrint(&sessionKey, NULL); - } - dumpAllCache(); - return serr; -} - -OSStatus sslDeleteSession ( - const SSLBuffer sessionKey) -{ - OSStatus serr; - try { - serr = gSessionCache().deleteEntry(sessionKey); - } - catch(...) { - serr = errSSLSessionNotFound; - } - return serr; -} - -/* cleanup up session cache, deleting stale entries. */ -OSStatus sslCleanupSession () -{ - OSStatus serr = noErr; - bool moreToGo = false; - try { - moreToGo = gSessionCache().cleanup(); - } - catch(...) { - serr = errSSLSessionNotFound; - } - /* Possible TBD: if moreToGo, schedule a timed callback to this function */ - return serr; -}