/* * Given an opaque sessionKey, alloc & retrieve associated sessionData. */ OSStatus sslGetSession ( const SSLBuffer sessionKey, SSLBuffer *sessionData) { SessionCache *cache = SessionCacheGetLockedInstance(); OSStatus serr; if (!cache) serr = errSSLSessionNotFound; else { serr = SessionCacheLookupEntry(cache, &sessionKey, sessionData); sslLogSessCacheDebug("sslGetSession(%d, %p): %ld", (int)sessionKey.length, sessionKey.data, serr); if(!serr) { cachePrint(NULL, &sessionKey, sessionData); } else { cachePrint(NULL, &sessionKey, NULL); } dumpAllCache(); } pthread_mutex_unlock(&gSessionCacheLock); return serr; }
/* cleanup, delete stale entries */ static bool SessionCacheCleanup(SessionCache *cache) { bool brtn = false; CFAbsoluteTime rightNow = CFAbsoluteTimeGetCurrent(); SessionCacheEntry **current; for (current = &(cache->head); *current;) { SessionCacheEntry *entry = *current; if(SessionCacheEntryIsStale(entry, rightNow)) { #ifndef DEBUG sslLogSessCacheDebug("...SessionCacheCleanup: deleting " "cached session (%p)", entry); cachePrint(entry, &entry->mKey, &entry->mSessionData); #endif *current = entry->next; SessionCacheEntryDelete(entry); } else { current = &((*current)->next); /* we're leaving one in the map */ brtn = true; } } return brtn; }
static OSStatus SessionCacheLookupEntry( SessionCache *cache, const SSLBuffer *sessionKey, SSLBuffer *sessionData) { SessionCacheEntry *entry = NULL; SessionCacheEntry **current; for (current = &(cache->head); *current; current = &((*current)->next)) { entry = *current; if (SessionCacheEntryMatchKey(entry, sessionKey)) break; } if (*current == NULL) return errSSLSessionNotFound; if (SessionCacheEntryIsStaleNow(entry)) { sslLogSessCacheDebug("SessionCache::lookupEntry %p: STALE " "entry, deleting; current %p, entry->next %p", entry, current, entry->next); cachePrint(entry, sessionKey, &entry->mSessionData); *current = entry->next; SessionCacheEntryDelete(entry); return errSSLSessionNotFound; } /* alloc/copy sessionData from existing entry (caller must free) */ return SSLCopyBuffer(&entry->mSessionData, sessionData); }
/* these three correspond to the C functions exported by this file */ static OSStatus SessionCacheAddEntry( SessionCache *cache, const SSLBuffer *sessionKey, const SSLBuffer *sessionData, uint32 timeToLive) /* optional time-to-live in seconds; 0 ==> default */ { SessionCacheEntry *entry = NULL; SessionCacheEntry **current; CFTimeInterval expireTime; for (current = &(cache->head); *current; current = &((*current)->next)) { entry = *current; if (SessionCacheEntryMatchKey(entry, sessionKey)) { /* cache hit - just update this entry's sessionData if necessary */ /* Note we leave expiration time and position in queue unchanged - OK? */ /* What if the entry has already expired? */ if((entry->mSessionData.length == sessionData->length) && (memcmp(entry->mSessionData.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", entry); return noErr; } else { sslLogSessCacheDebug("SessionCache::addEntry CACHE REPLACE " "entry = %p", entry); return SessionCacheEntrySetSessionData(entry, sessionData); } } } expireTime = CFAbsoluteTimeGetCurrent(); if(timeToLive) { /* caller-specified */ expireTime += (CFTimeInterval)timeToLive; } else { /* default */ expireTime += cache->mTimeToLive; } /* this allocs new copy of incoming sessionKey and sessionData */ entry = SessionCacheEntryCreate(sessionKey, sessionData, expireTime); sslLogSessCacheDebug("SessionCache::addEntry %p", entry); cachePrint(entry, sessionKey, sessionData); dumpAllCache(); /* add to head of queue for LIFO caching */ entry->next = cache->head; cache->head = entry; return noErr; }
static void dumpAllCache() { SessionCache *cache = gSessionCache; SessionCacheEntry *entry; printf("Contents of sessionCache:\n"); for(entry = cache->head; entry; entry = entry->next) { cachePrint(entry, &entry->mKey, &entry->mSessionData); } }
static OSStatus SessionCacheDeleteEntry( SessionCache *cache, const SSLBuffer *sessionKey) { SessionCacheEntry **current; for (current = &(cache->head); *current; current = &((*current)->next)) { SessionCacheEntry *entry = *current; if (SessionCacheEntryMatchKey(entry, sessionKey)) { #ifndef DEBUG sslLogSessCacheDebug("...SessionCacheDeleteEntry: deleting " "cached session (%p)", entry); cachePrint(entry, &entry->mKey, &entry->mSessionData); #endif *current = entry->next; SessionCacheEntryDelete(entry); return noErr; } } return noErr; }
static OSStatus SessionCacheLookupEntry( SessionCache *cache, const tls_buffer *sessionKey, tls_buffer *sessionData) { SessionCacheEntry *entry = NULL; SessionCacheEntry **current; for (current = &(cache->head); *current; current = &((*current)->next)) { entry = *current; if (SessionCacheEntryMatchKey(entry, sessionKey)) break; } if (*current == NULL) return -9804; //errSSLSessionNotFound; if (SessionCacheEntryIsStaleNow(entry)) { sslLogSessCacheDebug("SessionCache::lookupEntry %p: STALE " "entry, deleting; current %p, entry->next %p", entry, current, entry->next); cachePrint(entry, sessionKey, &entry->mSessionData); *current = entry->next; SessionCacheEntryDelete(entry); return -9804; //errSSLSessionNotFound; } #if 1 // "get" not "copy", see: <rdar://problem/16277298> coreTLS: session cache callbacks can lead to leaks or crashes sessionData->data = entry->mSessionData.data; sessionData->length = entry->mSessionData.length; return 0; #else /* alloc/copy sessionData from existing entry (caller must free) */ return SSLCopyBuffer(&entry->mSessionData, sessionData); #endif }