+++ /dev/null
-/*
- * Copyright (c) 2004,2011,2014 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The 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.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*
- * tpOcspCache.cpp - local OCSP response cache.
- */
-
-#include "tpOcspCache.h"
-#include "tpdebugging.h"
-#include "certGroupUtils.h"
-#include <security_utilities/globalizer.h>
-#include <security_utilities/threading.h>
-#include <security_ocspd/ocspdUtils.h>
-#include <assert.h>
-
-/*
- * Set this flag nonzero to turn off this cache module. Generally used to debug
- * the ocspd disk cache.
- */
-#ifndef NDEBUG
-#define TP_OCSP_CACHE_DISABLE 0
-#else
-/* cache always enabled in production build */
-#define TP_OCSP_CACHE_DISABLE 0
-#endif
-
-#pragma mark ---- single cache entry ----
-
-/*
- * One cache entry, just a parsed OCSPResponse plus an optional URI and a
- * "latest" nextUpdate time. An entry is stale when its nextUpdate time has
- * come and gone.
- */
-class OcspCacheEntry : public OCSPResponse
-{
-public:
- OcspCacheEntry(
- const CSSM_DATA derEncoded,
- const CSSM_DATA *localResponder); // optional
- ~OcspCacheEntry();
-
- /* a trusting environment, this module...all public */
- CSSM_DATA mLocalResponder; // we new[]
-};
-
-OcspCacheEntry::OcspCacheEntry(
- const CSSM_DATA derEncoded,
- const CSSM_DATA *localResponder) // optional
- : OCSPResponse(derEncoded, TP_OCSP_CACHE_TTL)
-{
- if(localResponder) {
- mLocalResponder.Data = new uint8[localResponder->Length];
- mLocalResponder.Length = localResponder->Length;
- memmove(mLocalResponder.Data, localResponder->Data, localResponder->Length);
- }
- else {
- mLocalResponder.Data = NULL;
- mLocalResponder.Length = 0;
- }
-}
-
-OcspCacheEntry::~OcspCacheEntry()
-{
- delete[] mLocalResponder.Data;
-}
-
-#pragma mark ---- global cache object ----
-
-/*
- * The cache object; ModuleNexus provides each task with at most of of these.
- * All ops which affect the contents of the cache hold the (essentially) global
- * mCacheLock.
- */
-class OcspCache
-{
-public:
- OcspCache();
- ~OcspCache();
-
- /* The methods corresponding to this module's public interface */
- OCSPSingleResponse *lookup(
- OCSPClientCertID &certID,
- const CSSM_DATA *localResponderURI); // optional
- void addResponse(
- const CSSM_DATA &ocspResp, // we'll decode it
- const CSSM_DATA *localResponderURI); // optional
- void flush(
- OCSPClientCertID &certID);
-
-private:
- void removeEntry(unsigned dex);
- void scanForStale();
- OCSPSingleResponse *lookupPriv(
- OCSPClientCertID &certID,
- const CSSM_DATA *localResponderURI, // optional
- unsigned &rtnDex); // RETURNED on success
-
- Mutex mCacheLock;
-
- /*
- * NOTE: I am aware that most folks would just use an array<> here, but
- * gdb is so lame that it doesn't even let one examine the contents
- * of an array<> (or just about anything else in the STL). I prefer
- * debuggability over saving a few lines of trivial code.
- */
- OcspCacheEntry **mEntries; // just an array of pointers
- unsigned mNumEntries; // valid entries in mEntries
- unsigned mSizeofEntries; // mallocd space in mEntries
-};
-
-OcspCache::OcspCache()
- : mEntries(NULL), mNumEntries(0), mSizeofEntries(0)
-{
-
-}
-
-/* As of Tiger I believe that this code never runs */
-OcspCache::~OcspCache()
-{
- for(unsigned dex=0; dex<mNumEntries; dex++) {
- delete mEntries[dex];
- }
- if(mEntries) {
- free(mEntries);
- }
-}
-
-/*
- * Private routine, remove entry 'n' from cache.
- * -- caller must hold mCacheLock
- * -- if caller is traversing mEntries, they must start over because we
- * manipulate it.
- */
-void OcspCache::removeEntry(
- unsigned dex)
-{
- assert(dex <= (mNumEntries - 1));
-
- /* removed requested element and compact remaining array */
- delete mEntries[dex];
- for(unsigned i=dex; i<(mNumEntries - 1); i++) {
- mEntries[i] = mEntries[i+1];
- }
- mNumEntries--;
-}
-
-/*
- * Private routine to scan cache, deleting stale entries.
- * Caller must hold mCacheLock, and not be traversing mEntries.
- */
-void OcspCache::scanForStale()
-{
- CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
- bool foundOne;
- do {
- /* restart every time we delete a stale entry */
- foundOne = false;
- for(unsigned dex=0; dex<mNumEntries; dex++) {
- OcspCacheEntry *entry = mEntries[dex];
- if(entry->expireTime() < now) {
- tpOcspCacheDebug("OcspCache::scanForStale: deleting stale entry %p",
- entry);
- removeEntry(dex);
- foundOne = true;
- break;
- }
- }
- } while(foundOne);
-}
-
-/*
- * Private lookup routine. Caller holds mCacheLock. We return both an
- * OCSPSingleResponse and the index into mEntries at which we found it.
- */
- OCSPSingleResponse *OcspCache::lookupPriv(
- OCSPClientCertID &certID,
- const CSSM_DATA *localResponderURI, // optional
- unsigned &rtnDex) // RETURNED on success
-{
- OCSPSingleResponse *resp = NULL;
- for(unsigned dex=0; dex<mNumEntries; dex++) {
- OcspCacheEntry *entry = mEntries[dex];
- if(localResponderURI) {
- /* if caller specifies, it must match */
- if(entry->mLocalResponder.Data == NULL) {
- /* came from somewhere else, skip it */
- tpOcspCacheDebug("OcspCache::lookup: uri mismatch (1) on entry %p",
- entry);
- continue;
- }
- if(!tpCompareCssmData(localResponderURI, &entry->mLocalResponder)) {
- tpOcspCacheDebug("OcspCache::lookup: uri mismatch (2) on entry %p",
- entry);
- continue;
- }
- }
- resp = entry->singleResponseFor(certID);
- if(resp) {
- tpOcspCacheDebug("OcspCache::lookupPriv: cache HIT on entry %p", entry);
- rtnDex=dex;
- return resp;
- }
- }
- tpOcspCacheDebug("OcspCache::lookupPriv: cache MISS");
- return NULL;
-}
-
-OCSPSingleResponse *OcspCache::lookup(
- OCSPClientCertID &certID,
- const CSSM_DATA *localResponderURI) // optional
-{
- StLock<Mutex> _(mCacheLock);
-
- /* take care of stale entries right away */
- scanForStale();
-
- unsigned rtnDex;
- return lookupPriv(certID, localResponderURI, rtnDex);
-}
-
-void OcspCache::addResponse(
- const CSSM_DATA &ocspResp, // we'll decode it
- const CSSM_DATA *localResponderURI) // optional
-{
- StLock<Mutex> _(mCacheLock);
-
- OcspCacheEntry *entry = new OcspCacheEntry(ocspResp, localResponderURI);
- if(mNumEntries == mSizeofEntries) {
- if(mSizeofEntries == 0) {
- /* appending to empty array */
- mSizeofEntries = 1;
- }
- else {
- mSizeofEntries *= 2;
- }
- mEntries = (OcspCacheEntry **)realloc(mEntries,
- mSizeofEntries * sizeof(OcspCacheEntry *));
- }
- mEntries[mNumEntries++] = entry;
- tpOcspCacheDebug("OcspCache::addResponse: add entry %p", entry);
-}
-
-void OcspCache::flush(
- OCSPClientCertID &certID)
-{
- StLock<Mutex> _(mCacheLock);
-
- /* take care of all stale entries */
- scanForStale();
-
- unsigned rtnDex;
- OCSPSingleResponse *resp;
- do {
- /* execute as until we find no more entries matching */
- resp = lookupPriv(certID, NULL, rtnDex);
- if(resp) {
- assert((rtnDex >= 0) && (rtnDex < mNumEntries));
- tpOcspCacheDebug("OcspCache::flush: deleting entry %p", mEntries[rtnDex]);
- removeEntry(rtnDex);
- }
- } while(resp != NULL);
-}
-
-
-static ModuleNexus<OcspCache> tpOcspCache;
-
-#pragma mark ---- Public API ----
-/*
- * Lookup locally cached response. Caller must free the returned OCSPSingleResponse.
- */
-OCSPSingleResponse *tpOcspCacheLookup(
- OCSPClientCertID &certID,
- const CSSM_DATA *localResponderURI) // optional
-{
- return tpOcspCache().lookup(certID, localResponderURI);
-}
-
-/*
- * Add a fully verified OCSP response to cache.
- */
-void tpOcspCacheAdd(
- const CSSM_DATA &ocspResp, // we'll decode it, not keep a ref
- const CSSM_DATA *localResponderURI) // optional
-{
- #if TP_OCSP_CACHE_DISABLE
- return;
- #endif
- tpOcspCache().addResponse(ocspResp, localResponderURI);
-}
-
-/*
- * Delete any entry associated with specified certID from cache.
- */
-void tpOcspCacheFlush(
- OCSPClientCertID &certID)
-{
- tpOcspCache().flush(certID);
-}
-