]> git.saurik.com Git - apple/security.git/blob - trust/trustd/SecOCSPCache.c
Security-59306.80.4.tar.gz
[apple/security.git] / trust / trustd / SecOCSPCache.c
1 /*
2 * Copyright (c) 2009-2010,2012-2017 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * SecOCSPCache.c - securityd
26 */
27
28 #include <CoreFoundation/CFUtilities.h>
29 #include <CoreFoundation/CFString.h>
30 #include "trust/trustd/SecOCSPCache.h"
31 #include "trust/trustd/SecTrustLoggingServer.h"
32 #include <utilities/debugging.h>
33 #include <Security/SecCertificateInternal.h>
34 #include <Security/SecFramework.h>
35 #include <Security/SecInternal.h>
36 #include <AssertMacros.h>
37 #include <stdlib.h>
38 #include <limits.h>
39 #include <sys/stat.h>
40 #include <asl.h>
41 #include "utilities/SecCFWrappers.h"
42 #include "utilities/SecDb.h"
43 #include "utilities/SecFileLocations.h"
44 #include "utilities/iOSforOSX.h"
45 #include <os/lock.h>
46
47 /* Note that lastUsed is actually time of insert because we don't
48 refresh lastUsed on each SELECT. */
49
50 #define deleteAllSQL CFSTR("DELETE FROM responses") /* for testing purposes */
51 #define flushSQL CFSTR("DELETE FROM ocsp WHERE certStatus!=1; " \
52 "DELETE FROM responses WHERE responseId NOT IN (SELECT responseId FROM ocsp WHERE certStatus=1)") /* Delete respones that aren't CS_Revoked */
53 #define expireSQL CFSTR("DELETE FROM responses WHERE expires<? AND responseId NOT IN (SELECT responseId FROM ocsp WHERE certStatus=1)") /* Don't expire revoked responses */
54 #define insertResponseSQL CFSTR("INSERT INTO responses " \
55 "(ocspResponse,responderURI,expires,lastUsed) VALUES (?,?,?,?)")
56 #define insertLinkSQL CFSTR("INSERT INTO ocsp (hashAlgorithm," \
57 "issuerNameHash,issuerPubKeyHash,serialNum,responseId,certStatus) VALUES (?,?,?,?,?,?)")
58 #define deleteResponseSQL CFSTR("DELETE FROM responses WHERE responseId=?")
59 #define selectHashAlgorithmSQL CFSTR("SELECT DISTINCT hashAlgorithm " \
60 "FROM ocsp WHERE serialNum=?")
61 #define selectResponseSQL CFSTR("SELECT ocspResponse,responseId FROM " \
62 "responses WHERE lastUsed>? AND responseId=(SELECT responseId FROM ocsp WHERE " \
63 "issuerNameHash=? AND issuerPubKeyHash=? AND serialNum=? AND hashAlgorithm=?)" \
64 " ORDER BY expires DESC")
65 #define hasCertStatusSQL CFSTR("SELECT issuerNameHash FROM ocsp WHERE certStatus=0 LIMIT 1")
66 #define alterOCSPTableSQL CFSTR("ALTER TABLE ocsp ADD COLUMN certStatus INTEGER NOT NULL DEFAULT 255") /* CS_NotParsed */
67
68 #define kSecOCSPCacheFileName CFSTR("ocspcache.sqlite3")
69
70
71 // MARK; -
72 // MARK: SecOCSPCacheDb
73
74 static bool SecOCSPCacheDbUpdateTables(SecDbRef db) {
75 __block bool ok = true;
76 __block CFErrorRef localError = NULL;
77
78 ok &= SecDbPerformWrite(db, &localError, ^(SecDbConnectionRef dbconn) {
79 ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) {
80 CFErrorRef readColumnError = NULL;
81 if (!SecDbWithSQL(dbconn, hasCertStatusSQL, &readColumnError, NULL) && CFErrorGetCode(readColumnError) == SQLITE_ERROR) {
82 ok &= SecDbWithSQL(dbconn, alterOCSPTableSQL, &localError, ^bool(sqlite3_stmt *stmt) {
83 ok = SecDbStep(dbconn, stmt, &localError, NULL);
84 return ok;
85 });
86 *commit = ok;
87 }
88 CFReleaseSafe(readColumnError);
89 });
90 });
91
92 if (!ok) {
93 secerror("OCSP table update failed: %@", localError);
94 CFIndex errCode = errSecInternalComponent;
95 if (localError) {
96 errCode = CFErrorGetCode(localError);
97 }
98 TrustdHealthAnalyticsLogErrorCodeForDatabase(TAOCSPCache,
99 TAOperationWrite,
100 TAFatalError, errCode);
101 }
102 CFReleaseSafe(localError);
103 return ok;
104 }
105
106 static SecDbRef SecOCSPCacheDbCreate(CFStringRef path) {
107 return SecDbCreate(path, 0600, true, true, true, true, 1,
108 ^bool (SecDbRef db, SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error) {
109 __block bool ok = true;
110
111 CFErrorRef localError = NULL;
112 if (!SecDbWithSQL(dbconn, selectHashAlgorithmSQL /* expireSQL */, &localError, NULL) && CFErrorGetCode(localError) == SQLITE_ERROR) {
113 /* SecDbWithSQL returns SQLITE_ERROR if the table we are preparing the above statement for doesn't exist. */
114 ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, error, ^(bool *commit) {
115 ok &= SecDbExec(dbconn,
116 CFSTR("CREATE TABLE ocsp("
117 "issuerNameHash BLOB NOT NULL,"
118 "issuerPubKeyHash BLOB NOT NULL,"
119 "serialNum BLOB NOT NULL,"
120 "hashAlgorithm BLOB NOT NULL,"
121 "responseId INTEGER NOT NULL,"
122 "certStatus INTEGER NOT NULL DEFAULT 255" // CS_NotParsed
123 ");"
124 "CREATE INDEX iResponseId ON ocsp(responseId);"
125 "CREATE INDEX iserialNum ON ocsp(serialNum);"
126 "CREATE INDEX iSNumDAlg ON ocsp(serialNum,hashAlgorithm);"
127 "CREATE TABLE responses("
128 "responseId INTEGER PRIMARY KEY,"
129 "ocspResponse BLOB NOT NULL,"
130 "responderURI BLOB,"
131 "expires DOUBLE NOT NULL,"
132 "lastUsed DOUBLE NOT NULL"
133 ");"
134 "CREATE INDEX iexpires ON responses(expires);"
135 "CREATE TRIGGER tocspdel BEFORE DELETE ON responses FOR EACH ROW "
136 "BEGIN "
137 "DELETE FROM ocsp WHERE responseId=OLD.responseId;"
138 " END;"), error);
139 *commit = ok;
140 });
141 }
142 CFReleaseSafe(localError);
143 if (!ok) {
144 secerror("%s failed: %@", didCreate ? "Create" : "Open", error ? *error : NULL);
145 CFIndex errCode = errSecInternalComponent;
146 if (error && *error) {
147 errCode = CFErrorGetCode(*error);
148 }
149 TrustdHealthAnalyticsLogErrorCodeForDatabase(TAOCSPCache,
150 didCreate ? TAOperationCreate : TAOperationOpen,
151 TAFatalError, errCode);
152 }
153 return ok;
154 });
155 }
156
157 // MARK; -
158 // MARK: SecOCSPCache
159
160 typedef struct __SecOCSPCache *SecOCSPCacheRef;
161 struct __SecOCSPCache {
162 SecDbRef db;
163 };
164
165 static SecOCSPCacheRef SecOCSPCacheCreate(CFStringRef db_name) {
166 SecOCSPCacheRef this;
167
168 require(this = (SecOCSPCacheRef)malloc(sizeof(struct __SecOCSPCache)), errOut);
169 require(this->db = SecOCSPCacheDbCreate(db_name), errOut);
170 require(SecOCSPCacheDbUpdateTables(this->db), errOut);
171
172 return this;
173
174 errOut:
175 if (this) {
176 CFReleaseSafe(this->db);
177 free(this);
178 }
179
180 return NULL;
181 }
182
183 CFStringRef SecOCSPCacheCopyPath(void) {
184 CFStringRef ocspRelPath = kSecOCSPCacheFileName;
185 #if TARGET_OS_IPHONE
186 CFURLRef ocspURL = SecCopyURLForFileInKeychainDirectory(ocspRelPath);
187 if (!ocspURL) {
188 ocspURL = SecCopyURLForFileInUserCacheDirectory(ocspRelPath);
189 }
190 #else
191 /* macOS caches should be in user cache dir */
192 CFURLRef ocspURL = SecCopyURLForFileInUserCacheDirectory(ocspRelPath);
193 #endif
194 CFStringRef ocspPath = NULL;
195 if (ocspURL) {
196 ocspPath = CFURLCopyFileSystemPath(ocspURL, kCFURLPOSIXPathStyle);
197 CFRelease(ocspURL);
198 }
199 return ocspPath;
200 }
201
202 static SecOCSPCacheRef kSecOCSPCache = NULL;
203 static os_unfair_lock cacheLock = OS_UNFAIR_LOCK_INIT;
204
205 void SecOCSPCacheCloseDB(void) {
206 os_unfair_lock_lock(&cacheLock);
207 if (kSecOCSPCache) {
208 // Release the DB
209 SecDbReleaseAllConnections(kSecOCSPCache->db);
210 CFReleaseSafe(kSecOCSPCache->db);
211
212 // free the cache struct
213 free(kSecOCSPCache);
214 kSecOCSPCache = NULL;
215 }
216 os_unfair_lock_unlock(&cacheLock);
217 }
218
219 void SecOCSPCacheDeleteCache(void) {
220 os_unfair_lock_lock(&cacheLock);
221 if (kSecOCSPCache) {
222 // Release the DB
223 SecDbReleaseAllConnections(kSecOCSPCache->db);
224 CFReleaseSafe(kSecOCSPCache->db);
225
226 // free the cache struct
227 free(kSecOCSPCache);
228 kSecOCSPCache = NULL;
229 }
230
231 // remove the file
232 CFStringRef path = SecOCSPCacheCopyPath();
233 CFStringPerformWithCStringAndLength(path, ^(const char *utf8Str, size_t utf8Length) {
234 remove(utf8Str);
235 });
236 CFReleaseSafe(path);
237 os_unfair_lock_unlock(&cacheLock);
238 }
239
240 static void SecOCSPCacheWith(void(^cacheJob)(SecOCSPCacheRef cache)) {
241 os_unfair_lock_lock(&cacheLock);
242 if (!kSecOCSPCache) {
243 CFStringRef dbPath = SecOCSPCacheCopyPath();
244 if (dbPath) {
245 kSecOCSPCache = SecOCSPCacheCreate(dbPath);
246 CFRelease(dbPath);
247 }
248 }
249 cacheJob(kSecOCSPCache);
250 os_unfair_lock_unlock(&cacheLock);
251 }
252
253 static bool _SecOCSPCacheExpireWithTransaction(SecDbConnectionRef dbconn, CFAbsoluteTime now, CFErrorRef *error) {
254 //if (now > nextExpireTime)
255 {
256 return SecDbWithSQL(dbconn, expireSQL, error, ^bool(sqlite3_stmt *expire) {
257 return SecDbBindDouble(expire, 1, now, error) &&
258 SecDbStep(dbconn, expire, error, NULL);
259 });
260 // TODO: Write now + expireDelay to nextExpireTime;
261 // currently we try to expire entries on each cache write
262 }
263 }
264
265 /* Instance implementation. */
266
267 static void _SecOCSPCacheReplaceResponse(SecOCSPCacheRef this,
268 SecOCSPResponseRef oldResponse, SecOCSPResponseRef ocspResponse,
269 CFURLRef localResponderURI, CFAbsoluteTime verifyTime) {
270 secdebug("ocspcache", "adding response from %@", localResponderURI);
271 /* responses.ocspResponse */
272
273 // TODO: Update a latestProducedAt value using date in new entry, to ensure forward movement of time.
274 // Set "now" to the new producedAt we are receiving here if localTime is before this date.
275 // In addition whenever we run though here, check to see if "now" is more than past
276 // the nextCacheExpireDate and expire the cache if it is.
277 CFDataRef responseData = SecOCSPResponseGetData(ocspResponse);
278 __block CFErrorRef localError = NULL;
279 __block bool ok = true;
280 ok &= SecDbPerformWrite(this->db, &localError, ^(SecDbConnectionRef dbconn) {
281 ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) {
282 __block sqlite3_int64 responseId;
283 if (oldResponse && (responseId = SecOCSPResponseGetID(oldResponse)) >= 0) {
284 ok &= SecDbWithSQL(dbconn, deleteResponseSQL, &localError, ^bool(sqlite3_stmt *deleteResponse) {
285 ok &= SecDbBindInt64(deleteResponse, 1, responseId, &localError);
286 /* Execute the delete statement. */
287 ok &= SecDbStep(dbconn, deleteResponse, &localError, NULL);
288 return ok;
289 });
290 }
291
292 ok &= SecDbWithSQL(dbconn, insertResponseSQL, &localError, ^bool(sqlite3_stmt *insertResponse) {
293 ok &= SecDbBindBlob(insertResponse, 1,
294 CFDataGetBytePtr(responseData),
295 CFDataGetLength(responseData),
296 SQLITE_TRANSIENT, &localError);
297
298 /* responses.responderURI */
299 if (ok) {
300 CFDataRef uriData = NULL;
301 if (localResponderURI) {
302 uriData = CFURLCreateData(kCFAllocatorDefault, localResponderURI,
303 kCFStringEncodingUTF8, false);
304 }
305 if (uriData) {
306 ok = SecDbBindBlob(insertResponse, 2,
307 CFDataGetBytePtr(uriData),
308 CFDataGetLength(uriData),
309 SQLITE_TRANSIENT, &localError);
310 CFRelease(uriData);
311 }
312 }
313 /* responses.expires */
314 ok &= SecDbBindDouble(insertResponse, 3,
315 SecOCSPResponseGetExpirationTime(ocspResponse),
316 &localError);
317 /* responses.lastUsed */
318 ok &= SecDbBindDouble(insertResponse, 4,
319 verifyTime,
320 &localError);
321
322 /* Execute the insert statement. */
323 ok &= SecDbStep(dbconn, insertResponse, &localError, NULL);
324
325 responseId = sqlite3_last_insert_rowid(SecDbHandle(dbconn));
326 return ok;
327 });
328
329 /* Now add a link record for every singleResponse in the ocspResponse. */
330 ok &= SecDbWithSQL(dbconn, insertLinkSQL, &localError, ^bool(sqlite3_stmt *insertLink) {
331 SecAsn1OCSPSingleResponse **responses;
332 for (responses = ocspResponse->responseData.responses;
333 *responses; ++responses) {
334 SecAsn1OCSPSingleResponse *resp = *responses;
335 SecAsn1OCSPCertID *certId = &resp->certID;
336 SecAsn1OCSPCertStatusTag certStatus = (SecAsn1OCSPCertStatusTag)(resp->certStatus.Data[0] & SEC_ASN1_TAGNUM_MASK);
337 ok &= SecDbBindBlob(insertLink, 1,
338 certId->algId.algorithm.Data,
339 certId->algId.algorithm.Length,
340 SQLITE_TRANSIENT, &localError);
341 ok &= SecDbBindBlob(insertLink, 2,
342 certId->issuerNameHash.Data,
343 certId->issuerNameHash.Length,
344 SQLITE_TRANSIENT, &localError);
345 ok &= SecDbBindBlob(insertLink, 3,
346 certId->issuerPubKeyHash.Data,
347 certId->issuerPubKeyHash.Length,
348 SQLITE_TRANSIENT, &localError);
349 ok &= SecDbBindBlob(insertLink, 4,
350 certId->serialNumber.Data,
351 certId->serialNumber.Length,
352 SQLITE_TRANSIENT, &localError);
353 ok &= SecDbBindInt64(insertLink, 5, responseId, &localError);
354 ok &= SecDbBindInt(insertLink, 6, certStatus, &localError);
355
356 /* Execute the insert statement. */
357 ok &= SecDbStep(dbconn, insertLink, &localError, NULL);
358 ok &= SecDbReset(insertLink, &localError);
359 }
360 return ok;
361 });
362
363 // Remove expired entries here.
364 // TODO: Consider only doing this once per 24 hours or something.
365 ok &= _SecOCSPCacheExpireWithTransaction(dbconn, verifyTime, &localError);
366 if (!ok)
367 *commit = false;
368 });
369 });
370 if (!ok) {
371 secerror("_SecOCSPCacheAddResponse failed: %@", localError);
372 TrustdHealthAnalyticsLogErrorCodeForDatabase(TAOCSPCache, TAOperationWrite, TAFatalError,
373 localError ? CFErrorGetCode(localError) : errSecInternalComponent);
374 CFReleaseNull(localError);
375 }
376 CFReleaseSafe(localError);
377 }
378
379 static SecOCSPResponseRef _SecOCSPCacheCopyMatching(SecOCSPCacheRef this,
380 SecOCSPRequestRef request, CFURLRef responderURI, CFAbsoluteTime minInsertTime) {
381 const DERItem *publicKey;
382 CFDataRef issuer = NULL;
383 CFDataRef serial = NULL;
384 __block SecOCSPResponseRef response = NULL;
385 __block CFErrorRef localError = NULL;
386 __block bool ok = true;
387
388 require(publicKey = SecCertificateGetPublicKeyData(request->issuer), errOut);
389 require(issuer = SecCertificateCopyIssuerSequence(request->certificate), errOut);
390 require(serial = SecCertificateCopySerialNumberData(request->certificate, NULL), errOut);
391
392 ok &= SecDbPerformRead(this->db, &localError, ^(SecDbConnectionRef dbconn) {
393 ok &= SecDbWithSQL(dbconn, selectHashAlgorithmSQL, &localError, ^bool(sqlite3_stmt *selectHash) {
394 ok = SecDbBindBlob(selectHash, 1, CFDataGetBytePtr(serial), CFDataGetLength(serial), SQLITE_TRANSIENT, &localError);
395 ok &= SecDbStep(dbconn, selectHash, &localError, ^(bool *stopHash) {
396 SecAsn1Oid algorithm;
397 algorithm.Data = (uint8_t *)sqlite3_column_blob(selectHash, 0);
398 algorithm.Length = sqlite3_column_bytes(selectHash, 0);
399
400 /* Calculate the issuerKey and issuerName digests using the returned
401 hashAlgorithm. */
402 CFDataRef issuerNameHash = SecDigestCreate(kCFAllocatorDefault,
403 &algorithm, NULL, CFDataGetBytePtr(issuer), CFDataGetLength(issuer));
404 CFDataRef issuerPubKeyHash = SecDigestCreate(kCFAllocatorDefault,
405 &algorithm, NULL, publicKey->data, publicKey->length);
406
407 if (issuerNameHash && issuerPubKeyHash && ok) {
408 ok &= SecDbWithSQL(dbconn, selectResponseSQL, &localError, ^bool(sqlite3_stmt *selectResponse) {
409 /* Now we have the serial, algorithm, issuerNameHash and
410 issuerPubKeyHash so let's lookup the db entry. */
411 ok &= SecDbBindDouble(selectResponse, 1, minInsertTime, &localError);
412 ok &= SecDbBindBlob(selectResponse, 2, CFDataGetBytePtr(issuerNameHash),
413 CFDataGetLength(issuerNameHash), SQLITE_TRANSIENT, &localError);
414 ok &= SecDbBindBlob(selectResponse, 3, CFDataGetBytePtr(issuerPubKeyHash),
415 CFDataGetLength(issuerPubKeyHash), SQLITE_TRANSIENT, &localError);
416 ok &= SecDbBindBlob(selectResponse, 4, CFDataGetBytePtr(serial),
417 CFDataGetLength(serial), SQLITE_TRANSIENT, &localError);
418 ok &= SecDbBindBlob(selectResponse, 5, algorithm.Data,
419 algorithm.Length, SQLITE_TRANSIENT, &localError);
420 ok &= SecDbStep(dbconn, selectResponse, &localError, ^(bool *stopResponse) {
421 /* Found an entry! */
422 secdebug("ocspcache", "found cached response");
423 CFDataRef resp = CFDataCreate(kCFAllocatorDefault,
424 sqlite3_column_blob(selectResponse, 0),
425 sqlite3_column_bytes(selectResponse, 0));
426 sqlite3_int64 responseID = sqlite3_column_int64(selectResponse, 1);
427 if (resp) {
428 response = SecOCSPResponseCreateWithID(resp, responseID);
429 CFRelease(resp);
430 }
431 });
432 return ok;
433 });
434 }
435
436 CFReleaseSafe(issuerNameHash);
437 CFReleaseSafe(issuerPubKeyHash);
438 });
439 return ok;
440 });
441 });
442
443 errOut:
444 CFReleaseSafe(serial);
445 CFReleaseSafe(issuer);
446
447 if (!ok || localError) {
448 secerror("ocsp cache lookup failed: %@", localError);
449 if (response) {
450 SecOCSPResponseFinalize(response);
451 response = NULL;
452 }
453 TrustdHealthAnalyticsLogErrorCodeForDatabase(TAOCSPCache, TAOperationRead, TAFatalError,
454 localError ? CFErrorGetCode(localError) : errSecInternalComponent);
455 }
456 CFReleaseSafe(localError);
457
458 secdebug("ocspcache", "returning %s", (response ? "cached response" : "NULL"));
459
460 return response;
461 }
462
463 static bool _SecOCSPCacheFlush(SecOCSPCacheRef cache, CFErrorRef *error) {
464 __block CFErrorRef localError = NULL;
465 __block bool ok = true;
466
467 ok &= SecDbPerformWrite(cache->db, &localError, ^(SecDbConnectionRef dbconn) {
468 ok &= SecDbExec(dbconn, flushSQL, &localError);
469 });
470 if (!ok || localError) {
471 TrustdHealthAnalyticsLogErrorCodeForDatabase(TAOCSPCache, TAOperationWrite, TAFatalError,
472 localError ? CFErrorGetCode(localError) : errSecInternalComponent);
473 }
474 (void) CFErrorPropagate(localError, error);
475
476 return ok;
477 }
478
479 static bool _SecOCSPCacheDeleteContent(SecOCSPCacheRef cache, CFErrorRef *error) {
480 __block CFErrorRef localError = NULL;
481 __block bool ok = true;
482
483 ok &= SecDbPerformWrite(cache->db, &localError, ^(SecDbConnectionRef dbconn) {
484 ok &= SecDbExec(dbconn, deleteAllSQL, &localError);
485 });
486 if (!ok || localError) {
487 TrustdHealthAnalyticsLogErrorCodeForDatabase(TAOCSPCache, TAOperationWrite, TAFatalError,
488 localError ? CFErrorGetCode(localError) : errSecInternalComponent);
489 }
490 (void) CFErrorPropagate(localError, error);
491
492 return ok;
493 }
494
495
496 /* Public API */
497
498 void SecOCSPCacheReplaceResponse(SecOCSPResponseRef old_response, SecOCSPResponseRef response,
499 CFURLRef localResponderURI, CFAbsoluteTime verifyTime) {
500 SecOCSPCacheWith(^(SecOCSPCacheRef cache) {
501 _SecOCSPCacheReplaceResponse(cache, old_response, response, localResponderURI, verifyTime);
502 });
503 }
504
505 SecOCSPResponseRef SecOCSPCacheCopyMatching(SecOCSPRequestRef request,
506 CFURLRef localResponderURI /* may be NULL */) {
507 __block SecOCSPResponseRef response = NULL;
508 SecOCSPCacheWith(^(SecOCSPCacheRef cache) {
509 response = _SecOCSPCacheCopyMatching(cache, request, localResponderURI, 0.0);
510 });
511 return response;
512 }
513
514 SecOCSPResponseRef SecOCSPCacheCopyMatchingWithMinInsertTime(SecOCSPRequestRef request,
515 CFURLRef localResponderURI, CFAbsoluteTime minInsertTime) {
516 __block SecOCSPResponseRef response = NULL;
517 SecOCSPCacheWith(^(SecOCSPCacheRef cache) {
518 response = _SecOCSPCacheCopyMatching(cache, request, localResponderURI, minInsertTime);
519 });
520 return response;
521 }
522
523 bool SecOCSPCacheFlush(CFErrorRef *error) {
524 __block bool result = false;
525 SecOCSPCacheWith(^(SecOCSPCacheRef cache) {
526 result = _SecOCSPCacheFlush(cache, error);
527 });
528 return result;
529 }
530
531 bool SecOCSPCacheDeleteContent(CFErrorRef *error) {
532 __block bool result = false;
533 SecOCSPCacheWith(^(SecOCSPCacheRef cache) {
534 result = _SecOCSPCacheDeleteContent(cache, error);
535 });
536 return result;
537 }