]> git.saurik.com Git - apple/security.git/blobdiff - sec/securityd/SecOCSPCache.c
Security-57031.1.35.tar.gz
[apple/security.git] / sec / securityd / SecOCSPCache.c
diff --git a/sec/securityd/SecOCSPCache.c b/sec/securityd/SecOCSPCache.c
deleted file mode 100644 (file)
index 1ae99db..0000000
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * Copyright (c) 2009-2010 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@
- */
-
-/*
- *  SecOCSPCache.c - securityd
- */
-
-#include <CoreFoundation/CFUtilities.h>
-#include <CoreFoundation/CFString.h>
-#include <securityd/SecOCSPCache.h>
-#include <utilities/debugging.h>
-#include <Security/SecCertificateInternal.h>
-#include <Security/SecFramework.h>
-#include <Security/SecInternal.h>
-#include <AssertMacros.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <sys/stat.h>
-#include <asl.h>
-#include "utilities/SecDb.h"
-#include "utilities/SecFileLocations.h"
-#include "utilities/iOSforOSX.h"
-
-#define expireSQL  CFSTR("DELETE FROM responses WHERE expires<?")
-#define beginTxnSQL  CFSTR("BEGIN EXCLUSIVE TRANSACTION")
-#define endTxnSQL  CFSTR("COMMIT TRANSACTION")
-#define insertResponseSQL  CFSTR("INSERT INTO responses " \
-    "(ocspResponse,responderURI,expires,lastUsed) VALUES (?,?,?,?)")
-#define insertLinkSQL  CFSTR("INSERT INTO ocsp (hashAlgorithm," \
-    "issuerNameHash,issuerPubKeyHash,serialNum,responseId) VALUES (?,?,?,?,?)")
-#define selectHashAlgorithmSQL  CFSTR("SELECT DISTINCT hashAlgorithm " \
-    "FROM ocsp WHERE serialNum=?")
-#define selectResponseSQL  CFSTR("SELECT ocspResponse,responseId FROM " \
-    "responses WHERE responseId=(SELECT responseId FROM ocsp WHERE " \
-    "issuerNameHash=? AND issuerPubKeyHash=? AND serialNum=? AND hashAlgorithm=?)" \
-    " ORDER BY expires DESC")
-
-
-#define kSecOCSPCacheFileName CFSTR("ocspcache.sqlite3")
-
-
-// MARK; -
-// MARK: SecOCSPCacheDb
-
-static SecDbRef SecOCSPCacheDbCreate(CFStringRef path) {
-    return SecDbCreate(path, ^bool (SecDbConnectionRef dbconn, bool didCreate, CFErrorRef *error) {
-        __block bool ok;
-        ok = (SecDbExec(dbconn, CFSTR("PRAGMA auto_vacuum = FULL"), error) &&
-              SecDbExec(dbconn, CFSTR("PRAGMA journal_mode = WAL"), error));
-        CFErrorRef localError = NULL;
-        if (ok && !SecDbWithSQL(dbconn, selectHashAlgorithmSQL /* expireSQL */, &localError, NULL) && CFErrorGetCode(localError) == SQLITE_ERROR) {
-            /* SecDbWithSQL returns SQLITE_ERROR if the table we are preparing the above statement for doesn't exist. */
-            ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, error, ^(bool *commit) {
-                ok = SecDbExec(dbconn,
-                    CFSTR("CREATE TABLE ocsp("
-                          "issuerNameHash BLOB NOT NULL,"
-                          "issuerPubKeyHash BLOB NOT NULL,"
-                          "serialNum BLOB NOT NULL,"
-                          "hashAlgorithm BLOB NOT NULL,"
-                          "responseId INTEGER NOT NULL"
-                          ");"
-                          "CREATE INDEX iResponseId ON ocsp(responseId);"
-                          "CREATE INDEX iserialNum ON ocsp(serialNum);"
-                          "CREATE INDEX iSNumDAlg ON ocsp(serialNum,hashAlgorithm);"
-                          "CREATE TABLE responses("
-                          "responseId INTEGER PRIMARY KEY,"
-                          "ocspResponse BLOB NOT NULL,"
-                          "responderURI BLOB,"
-                          "expires DOUBLE NOT NULL,"
-                          "lastUsed DOUBLE NOT NULL"
-                          ");"
-                          "CREATE INDEX iexpires ON responses(expires);"
-                          "CREATE TRIGGER tocspdel BEFORE DELETE ON responses FOR EACH ROW "
-                          "BEGIN "
-                          "DELETE FROM ocsp WHERE responseId=OLD.responseId;"
-                          " END;"), error);
-                *commit = ok;
-            });
-        }
-        CFReleaseSafe(localError);
-        if (!ok)
-            secerror("%s failed: %@", didCreate ? "Create" : "Open", error ? *error : NULL);
-        return ok;
-    });
-}
-
-// MARK; -
-// MARK: SecOCSPCache
-
-typedef struct __SecOCSPCache *SecOCSPCacheRef;
-struct __SecOCSPCache {
-       SecDbRef db;
-};
-
-static dispatch_once_t kSecOCSPCacheOnce;
-static SecOCSPCacheRef kSecOCSPCache = NULL;
-
-static SecOCSPCacheRef SecOCSPCacheCreate(CFStringRef db_name) {
-       SecOCSPCacheRef this;
-
-       require(this = (SecOCSPCacheRef)malloc(sizeof(struct __SecOCSPCache)), errOut);
-    require(this->db = SecOCSPCacheDbCreate(db_name), errOut);
-
-       return this;
-
-errOut:
-       if (this) {
-        CFReleaseSafe(this->db);
-               free(this);
-       }
-
-       return NULL;
-}
-
-static CFStringRef SecOCSPCacheCopyPath(void) {
-    CFStringRef ocspRelPath = kSecOCSPCacheFileName;
-    CFURLRef ocspURL = SecCopyURLForFileInKeychainDirectory(ocspRelPath);
-    CFStringRef ocspPath = NULL;
-    if (ocspURL) {
-        ocspPath = CFURLCopyFileSystemPath(ocspURL, kCFURLPOSIXPathStyle);
-        CFRelease(ocspURL);
-    }
-    return ocspPath;
-}
-
-static void SecOCSPCacheWith(void(^cacheJob)(SecOCSPCacheRef cache)) {
-    dispatch_once(&kSecOCSPCacheOnce, ^{
-        CFStringRef dbPath = SecOCSPCacheCopyPath();
-        if (dbPath) {
-            kSecOCSPCache = SecOCSPCacheCreate(dbPath);
-            CFRelease(dbPath);
-        }
-    });
-    // Do pre job run work here (cancel idle timers etc.)
-    cacheJob(kSecOCSPCache);
-    // Do post job run work here (gc timer, etc.)
-}
-
-/* Instance implemenation. */
-
-static void _SecOCSPCacheAddResponse(SecOCSPCacheRef this,
-    SecOCSPResponseRef ocspResponse, CFURLRef localResponderURI) {
-    secdebug("ocspcache", "adding response from %@", localResponderURI);
-    /* responses.ocspResponse */
-    CFDataRef responseData = SecOCSPResponseGetData(ocspResponse);
-    __block CFErrorRef localError = NULL;
-    __block bool ok = true;
-    ok &= SecDbPerformWrite(this->db, &localError, ^(SecDbConnectionRef dbconn) {
-        ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) {
-            __block sqlite3_int64 responseId;
-            ok = SecDbWithSQL(dbconn, insertResponseSQL, &localError, ^bool(sqlite3_stmt *insertResponse) {
-                if (ok)
-                    ok = SecDbBindBlob(insertResponse, 1,
-                                       CFDataGetBytePtr(responseData),
-                                       CFDataGetLength(responseData),
-                                       SQLITE_TRANSIENT, &localError);
-
-                /* responses.responderURI */
-                if (ok) {
-                    CFDataRef uriData = NULL;
-                    if (localResponderURI) {
-                        uriData = CFURLCreateData(kCFAllocatorDefault, localResponderURI,
-                                                  kCFStringEncodingUTF8, false);
-                    }
-                    if (uriData) {
-                        ok = SecDbBindBlob(insertResponse, 2,
-                                           CFDataGetBytePtr(uriData),
-                                           CFDataGetLength(uriData),
-                                           SQLITE_TRANSIENT, &localError);
-                        CFRelease(uriData);
-                    } else {
-                        // Since we use SecDbClearBindings this shouldn't be needed.
-                        //ok = SecDbBindNull(insertResponse, 2, &localError);
-                    }
-                }
-                /* responses.expires */
-                if (ok)
-                    ok = SecDbBindDouble(insertResponse, 3,
-                                         SecOCSPResponseGetExpirationTime(ocspResponse),
-                                         &localError);
-                /* responses.lastUsed */
-                if (ok)
-                    ok = SecDbBindDouble(insertResponse, 4,
-                                         SecOCSPResponseVerifyTime(ocspResponse),
-                                         &localError);
-
-                /* Execute the insert statement. */
-                if (ok)
-                    ok = SecDbStep(dbconn, insertResponse, &localError, NULL);
-
-                responseId = sqlite3_last_insert_rowid(SecDbHandle(dbconn));
-                return ok;
-            });
-
-            /* Now add a link record for every singleResponse in the ocspResponse. */
-            if (ok) ok = SecDbWithSQL(dbconn, insertLinkSQL, &localError, ^bool(sqlite3_stmt *insertLink) {
-                SecAsn1OCSPSingleResponse **responses;
-                for (responses = ocspResponse->responseData.responses;
-                     *responses; ++responses) {
-                    SecAsn1OCSPSingleResponse *resp = *responses;
-                    SecAsn1OCSPCertID *certId = &resp->certID;
-                    if (ok) ok = SecDbBindBlob(insertLink, 1,
-                                               certId->algId.algorithm.Data,
-                                               certId->algId.algorithm.Length,
-                                               SQLITE_TRANSIENT, &localError);
-                    if (ok) ok = SecDbBindBlob(insertLink, 2,
-                                               certId->issuerNameHash.Data,
-                                               certId->issuerNameHash.Length,
-                                               SQLITE_TRANSIENT, &localError);
-                    if (ok) ok = SecDbBindBlob(insertLink, 3,
-                                               certId->issuerPubKeyHash.Data,
-                                               certId->issuerPubKeyHash.Length,
-                                               SQLITE_TRANSIENT, &localError);
-                    if (ok) ok = SecDbBindBlob(insertLink, 4,
-                                               certId->serialNumber.Data,
-                                               certId->serialNumber.Length,
-                                               SQLITE_TRANSIENT, &localError);
-                    if (ok) ok = SecDbBindInt64(insertLink, 5, responseId, &localError);
-
-                    /* Execute the insert statement. */
-                    if (ok) ok = SecDbStep(dbconn, insertLink, &localError, NULL);
-                    if (ok) ok = SecDbReset(insertLink, &localError);
-                }
-                return ok;
-            });
-            if (!ok)
-                *commit = false;
-        });
-    });
-    if (!ok) {
-        secerror("_SecOCSPCacheAddResponse failed: %@", localError);
-    }
-    CFReleaseSafe(localError);
-}
-
-static SecOCSPResponseRef _SecOCSPCacheCopyMatching(SecOCSPCacheRef this,
-    SecOCSPRequestRef request, CFURLRef responderURI) {
-    const DERItem *publicKey;
-    CFDataRef issuer = NULL;
-    CFDataRef serial = NULL;
-    __block SecOCSPResponseRef response = NULL;
-    __block CFErrorRef localError = NULL;
-    __block bool ok = true;
-
-    require(publicKey = SecCertificateGetPublicKeyData(request->issuer), errOut);
-    require(issuer = SecCertificateCopyIssuerSequence(request->certificate), errOut);
-    require(serial = SecCertificateCopySerialNumber(request->certificate), errOut);
-
-    ok &= SecDbPerformRead(this->db, &localError, ^(SecDbConnectionRef dbconn) {
-        ok &= SecDbWithSQL(dbconn, selectHashAlgorithmSQL, &localError, ^bool(sqlite3_stmt *selectHash) {
-            ok = SecDbBindBlob(selectHash, 1, CFDataGetBytePtr(serial), CFDataGetLength(serial), SQLITE_TRANSIENT, &localError);
-            ok &= SecDbStep(dbconn, selectHash, &localError, ^(bool *stopHash) {
-                SecAsn1Oid algorithm;
-                algorithm.Data = (uint8_t *)sqlite3_column_blob(selectHash, 0);
-                algorithm.Length = sqlite3_column_bytes(selectHash, 0);
-
-                /* Calcluate the issuerKey and issuerName digests using the returned
-                 hashAlgorithm. */
-                CFDataRef issuerNameHash = SecDigestCreate(kCFAllocatorDefault,
-                                                           &algorithm, NULL, CFDataGetBytePtr(issuer), CFDataGetLength(issuer));
-                CFDataRef issuerPubKeyHash = SecDigestCreate(kCFAllocatorDefault,
-                                                             &algorithm, NULL, publicKey->data, publicKey->length);
-
-                if (issuerNameHash && issuerPubKeyHash && ok) ok &= SecDbWithSQL(dbconn, selectResponseSQL, &localError, ^bool(sqlite3_stmt *selectResponse) {
-                    /* Now we have the serial, algorithm, issuerNameHash and
-                     issuerPubKeyHash so let's lookup the db entry. */
-                    if (ok) ok = SecDbBindBlob(selectResponse, 1, CFDataGetBytePtr(issuerNameHash),
-                                               CFDataGetLength(issuerNameHash), SQLITE_TRANSIENT, &localError);
-                    if (ok) ok = SecDbBindBlob(selectResponse, 2, CFDataGetBytePtr(issuerPubKeyHash),
-                                               CFDataGetLength(issuerPubKeyHash), SQLITE_TRANSIENT, &localError);
-                    if (ok) ok = SecDbBindBlob(selectResponse, 3, CFDataGetBytePtr(serial),
-                                               CFDataGetLength(serial), SQLITE_TRANSIENT, &localError);
-                    if (ok) ok = SecDbBindBlob(selectResponse, 4, algorithm.Data,
-                                               algorithm.Length, SQLITE_TRANSIENT, &localError);
-                    if (ok) ok &= SecDbStep(dbconn, selectResponse, &localError, ^(bool *stopResponse) {
-                        /* Found an entry! */
-                        secdebug("ocspcache", "found cached response");
-                        CFDataRef resp = CFDataCreate(kCFAllocatorDefault,
-                                                      sqlite3_column_blob(selectResponse, 0),
-                                                      sqlite3_column_bytes(selectResponse, 0));
-                        if (resp) {
-                            response = SecOCSPResponseCreate(resp, NULL_TIME);
-                            CFRelease(resp);
-                        }
-                        if (response) {
-                            //sqlite3_int64 responseId = sqlite3_column_int64(this->selectResponse, 1);
-                            /* @@@ Update the lastUsed field in the db. */
-                        }
-                    });
-                    return ok;
-                });
-
-                CFReleaseSafe(issuerNameHash);
-                CFReleaseSafe(issuerPubKeyHash);
-            });
-            return ok;
-        });
-    });
-
-errOut:
-    CFReleaseSafe(serial);
-    CFReleaseSafe(issuer);
-
-    if (!ok) {
-        secerror("ocsp cache lookup failed: %@", localError);
-        if (response) {
-            SecOCSPResponseFinalize(response);
-            response = NULL;
-        }
-    }
-    CFReleaseSafe(localError);
-
-    secdebug("ocspcache", "returning %s", (response ? "cached response" : "NULL"));
-
-    return response;
-}
-
-static void _SecOCSPCacheGC(SecOCSPCacheRef this) {
-    secdebug("ocspcache", "expiring stale responses");
-
-    __block CFErrorRef localError = NULL;
-    __block bool ok = true;
-    ok &= SecDbPerformWrite(this->db, &localError, ^(SecDbConnectionRef dbconn) {
-        ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) {
-            ok &= SecDbWithSQL(dbconn, expireSQL, &localError, ^bool(sqlite3_stmt *expire) {
-                return SecDbBindDouble(expire, 1, CFAbsoluteTimeGetCurrent(), &localError) &&
-                    SecDbStep(dbconn, expire, &localError, NULL);
-            });
-            *commit = ok;
-        });
-    });
-
-    if (!ok) {
-        secerror("ocsp cache expire failed: %@", localError);
-    }
-    CFReleaseSafe(localError);
-}
-
-static void _SecOCSPCacheFlush(SecOCSPCacheRef this) {
-    secdebug("ocspcache", "flushing pending changes");
-    // NOOP since we use WAL now and commit right away.
-}
-
-/* Public API */
-
-void SecOCSPCacheAddResponse(SecOCSPResponseRef response,
-    CFURLRef localResponderURI) {
-    SecOCSPCacheWith(^(SecOCSPCacheRef cache) {
-        _SecOCSPCacheAddResponse(cache, response, localResponderURI);
-    });
-}
-
-SecOCSPResponseRef SecOCSPCacheCopyMatching(SecOCSPRequestRef request,
-    CFURLRef localResponderURI /* may be NULL */) {
-    __block SecOCSPResponseRef response = NULL;
-    SecOCSPCacheWith(^(SecOCSPCacheRef cache) {
-        response = _SecOCSPCacheCopyMatching(cache, request, localResponderURI);
-    });
-    return response;
-}
-
-/* This should be called on a normal non emergency exit. This function
-   effectively does a SecOCSPCacheFlush.
-   Currently this is called from our atexit handeler.
-   This function expires any records that are stale and commits.
-
-   Idea for future cache management policies:
-   Expire old cache entires from database if:
-    - The time to do so has arrived based on the nextExpire date in the
-      policy table.
-    - If the size of the database exceeds the limit set in the maxSize field
-      in the policy table, vacuum the db.  If the database is still too
-      big, expire records on a LRU basis.
- */
-void SecOCSPCacheGC(void) {
-    if (kSecOCSPCache)
-        _SecOCSPCacheGC(kSecOCSPCache);
-}
-
-/* Call this periodically or perhaps when we are exiting due to low memory. */
-void SecOCSPCacheFlush(void) {
-    if (kSecOCSPCache)
-        _SecOCSPCacheFlush(kSecOCSPCache);
-}