]> git.saurik.com Git - apple/security.git/blobdiff - SecureTransport/appleSession.cpp
Security-222.tar.gz
[apple/security.git] / SecureTransport / appleSession.cpp
diff --git a/SecureTransport/appleSession.cpp b/SecureTransport/appleSession.cpp
deleted file mode 100644 (file)
index e029315..0000000
+++ /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 <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
-
-#include <deque>
-#include <stdexcept>
-#include <Security/threading.h>
-#include <Security/globalizer.h>
-#include <Security/timeflow.h>
-
-/* 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<SessionCacheEntry *> 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<Mutex> _(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<Mutex> _(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<Mutex> _(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<Mutex> _(mSessionLock);
-       deletePriv(&sessionKey);
-       return noErr;
-}
-       
-/* cleanup, delete stale entries */
-bool SessionCache::cleanup()
-{
-       StLock<Mutex> _(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<SessionCache> 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;
-}