]> git.saurik.com Git - apple/security.git/blob - trust/trustd/SecOCSPCache.c
Security-59306.101.1.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 if (kSecOCSPCache) {
250 cacheJob(kSecOCSPCache);
251 }
252 os_unfair_lock_unlock(&cacheLock);
253 }
254
255 static bool _SecOCSPCacheExpireWithTransaction(SecDbConnectionRef dbconn, CFAbsoluteTime now, CFErrorRef *error) {
256 //if (now > nextExpireTime)
257 {
258 return SecDbWithSQL(dbconn, expireSQL, error, ^bool(sqlite3_stmt *expire) {
259 return SecDbBindDouble(expire, 1, now, error) &&
260 SecDbStep(dbconn, expire, error, NULL);
261 });
262 // TODO: Write now + expireDelay to nextExpireTime;
263 // currently we try to expire entries on each cache write
264 }
265 }
266
267 /* Instance implementation. */
268
269 static void _SecOCSPCacheReplaceResponse(SecOCSPCacheRef this,
270 SecOCSPResponseRef oldResponse, SecOCSPResponseRef ocspResponse,
271 CFURLRef localResponderURI, CFAbsoluteTime verifyTime) {
272 secdebug("ocspcache", "adding response from %@", localResponderURI);
273 /* responses.ocspResponse */
274
275 // TODO: Update a latestProducedAt value using date in new entry, to ensure forward movement of time.
276 // Set "now" to the new producedAt we are receiving here if localTime is before this date.
277 // In addition whenever we run though here, check to see if "now" is more than past
278 // the nextCacheExpireDate and expire the cache if it is.
279 CFDataRef responseData = SecOCSPResponseGetData(ocspResponse);
280 __block CFErrorRef localError = NULL;
281 __block bool ok = true;
282 ok &= SecDbPerformWrite(this->db, &localError, ^(SecDbConnectionRef dbconn) {
283 ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) {
284 __block sqlite3_int64 responseId;
285 if (oldResponse && (responseId = SecOCSPResponseGetID(oldResponse)) >= 0) {
286 ok &= SecDbWithSQL(dbconn, deleteResponseSQL, &localError, ^bool(sqlite3_stmt *deleteResponse) {
287 ok &= SecDbBindInt64(deleteResponse, 1, responseId, &localError);
288 /* Execute the delete statement. */
289 ok &= SecDbStep(dbconn, deleteResponse, &localError, NULL);
290 return ok;
291 });
292 }
293
294 ok &= SecDbWithSQL(dbconn, insertResponseSQL, &localError, ^bool(sqlite3_stmt *insertResponse) {
295 ok &= SecDbBindBlob(insertResponse, 1,
296 CFDataGetBytePtr(responseData),
297 CFDataGetLength(responseData),
298 SQLITE_TRANSIENT, &localError);
299
300 /* responses.responderURI */
301 if (ok) {
302 CFDataRef uriData = NULL;
303 if (localResponderURI) {
304 uriData = CFURLCreateData(kCFAllocatorDefault, localResponderURI,
305 kCFStringEncodingUTF8, false);
306 }
307 if (uriData) {
308 ok = SecDbBindBlob(insertResponse, 2,
309 CFDataGetBytePtr(uriData),
310 CFDataGetLength(uriData),
311 SQLITE_TRANSIENT, &localError);
312 CFRelease(uriData);
313 }
314 }
315 /* responses.expires */
316 ok &= SecDbBindDouble(insertResponse, 3,
317 SecOCSPResponseGetExpirationTime(ocspResponse),
318 &localError);
319 /* responses.lastUsed */
320 ok &= SecDbBindDouble(insertResponse, 4,
321 verifyTime,
322 &localError);
323
324 /* Execute the insert statement. */
325 ok &= SecDbStep(dbconn, insertResponse, &localError, NULL);
326
327 responseId = sqlite3_last_insert_rowid(SecDbHandle(dbconn));
328 return ok;
329 });
330
331 /* Now add a link record for every singleResponse in the ocspResponse. */
332 ok &= SecDbWithSQL(dbconn, insertLinkSQL, &localError, ^bool(sqlite3_stmt *insertLink) {
333 SecAsn1OCSPSingleResponse **responses;
334 for (responses = ocspResponse->responseData.responses;
335 *responses; ++responses) {
336 SecAsn1OCSPSingleResponse *resp = *responses;
337 SecAsn1OCSPCertID *certId = &resp->certID;
338 SecAsn1OCSPCertStatusTag certStatus = (SecAsn1OCSPCertStatusTag)(resp->certStatus.Data[0] & SEC_ASN1_TAGNUM_MASK);
339 ok &= SecDbBindBlob(insertLink, 1,
340 certId->algId.algorithm.Data,
341 certId->algId.algorithm.Length,
342 SQLITE_TRANSIENT, &localError);
343 ok &= SecDbBindBlob(insertLink, 2,
344 certId->issuerNameHash.Data,
345 certId->issuerNameHash.Length,
346 SQLITE_TRANSIENT, &localError);
347 ok &= SecDbBindBlob(insertLink, 3,
348 certId->issuerPubKeyHash.Data,
349 certId->issuerPubKeyHash.Length,
350 SQLITE_TRANSIENT, &localError);
351 ok &= SecDbBindBlob(insertLink, 4,
352 certId->serialNumber.Data,
353 certId->serialNumber.Length,
354 SQLITE_TRANSIENT, &localError);
355 ok &= SecDbBindInt64(insertLink, 5, responseId, &localError);
356 ok &= SecDbBindInt(insertLink, 6, certStatus, &localError);
357
358 /* Execute the insert statement. */
359 ok &= SecDbStep(dbconn, insertLink, &localError, NULL);
360 ok &= SecDbReset(insertLink, &localError);
361 }
362 return ok;
363 });
364
365 // Remove expired entries here.
366 // TODO: Consider only doing this once per 24 hours or something.
367 ok &= _SecOCSPCacheExpireWithTransaction(dbconn, verifyTime, &localError);
368 if (!ok)
369 *commit = false;
370 });
371 });
372 if (!ok) {
373 secerror("_SecOCSPCacheAddResponse failed: %@", localError);
374 TrustdHealthAnalyticsLogErrorCodeForDatabase(TAOCSPCache, TAOperationWrite, TAFatalError,
375 localError ? CFErrorGetCode(localError) : errSecInternalComponent);
376 CFReleaseNull(localError);
377 }
378 CFReleaseSafe(localError);
379 }
380
381 static SecOCSPResponseRef _SecOCSPCacheCopyMatching(SecOCSPCacheRef this,
382 SecOCSPRequestRef request, CFURLRef responderURI, CFAbsoluteTime minInsertTime) {
383 const DERItem *publicKey;
384 CFDataRef issuer = NULL;
385 CFDataRef serial = NULL;
386 __block SecOCSPResponseRef response = NULL;
387 __block CFErrorRef localError = NULL;
388 __block bool ok = true;
389
390 require(publicKey = SecCertificateGetPublicKeyData(request->issuer), errOut);
391 require(issuer = SecCertificateCopyIssuerSequence(request->certificate), errOut);
392 require(serial = SecCertificateCopySerialNumberData(request->certificate, NULL), errOut);
393
394 ok &= SecDbPerformRead(this->db, &localError, ^(SecDbConnectionRef dbconn) {
395 ok &= SecDbWithSQL(dbconn, selectHashAlgorithmSQL, &localError, ^bool(sqlite3_stmt *selectHash) {
396 ok = SecDbBindBlob(selectHash, 1, CFDataGetBytePtr(serial), CFDataGetLength(serial), SQLITE_TRANSIENT, &localError);
397 ok &= SecDbStep(dbconn, selectHash, &localError, ^(bool *stopHash) {
398 SecAsn1Oid algorithm;
399 algorithm.Data = (uint8_t *)sqlite3_column_blob(selectHash, 0);
400 algorithm.Length = sqlite3_column_bytes(selectHash, 0);
401
402 /* Calculate the issuerKey and issuerName digests using the returned
403 hashAlgorithm. */
404 CFDataRef issuerNameHash = SecDigestCreate(kCFAllocatorDefault,
405 &algorithm, NULL, CFDataGetBytePtr(issuer), CFDataGetLength(issuer));
406 CFDataRef issuerPubKeyHash = SecDigestCreate(kCFAllocatorDefault,
407 &algorithm, NULL, publicKey->data, publicKey->length);
408
409 if (issuerNameHash && issuerPubKeyHash && ok) {
410 ok &= SecDbWithSQL(dbconn, selectResponseSQL, &localError, ^bool(sqlite3_stmt *selectResponse) {
411 /* Now we have the serial, algorithm, issuerNameHash and
412 issuerPubKeyHash so let's lookup the db entry. */
413 ok &= SecDbBindDouble(selectResponse, 1, minInsertTime, &localError);
414 ok &= SecDbBindBlob(selectResponse, 2, CFDataGetBytePtr(issuerNameHash),
415 CFDataGetLength(issuerNameHash), SQLITE_TRANSIENT, &localError);
416 ok &= SecDbBindBlob(selectResponse, 3, CFDataGetBytePtr(issuerPubKeyHash),
417 CFDataGetLength(issuerPubKeyHash), SQLITE_TRANSIENT, &localError);
418 ok &= SecDbBindBlob(selectResponse, 4, CFDataGetBytePtr(serial),
419 CFDataGetLength(serial), SQLITE_TRANSIENT, &localError);
420 ok &= SecDbBindBlob(selectResponse, 5, algorithm.Data,
421 algorithm.Length, SQLITE_TRANSIENT, &localError);
422 ok &= SecDbStep(dbconn, selectResponse, &localError, ^(bool *stopResponse) {
423 /* Found an entry! */
424 secdebug("ocspcache", "found cached response");
425 CFDataRef resp = CFDataCreate(kCFAllocatorDefault,
426 sqlite3_column_blob(selectResponse, 0),
427 sqlite3_column_bytes(selectResponse, 0));
428 sqlite3_int64 responseID = sqlite3_column_int64(selectResponse, 1);
429 if (resp) {
430 response = SecOCSPResponseCreateWithID(resp, responseID);
431 CFRelease(resp);
432 }
433 });
434 return ok;
435 });
436 }
437
438 CFReleaseSafe(issuerNameHash);
439 CFReleaseSafe(issuerPubKeyHash);
440 });
441 return ok;
442 });
443 });
444
445 errOut:
446 CFReleaseSafe(serial);
447 CFReleaseSafe(issuer);
448
449 if (!ok || localError) {
450 secerror("ocsp cache lookup failed: %@", localError);
451 if (response) {
452 SecOCSPResponseFinalize(response);
453 response = NULL;
454 }
455 TrustdHealthAnalyticsLogErrorCodeForDatabase(TAOCSPCache, TAOperationRead, TAFatalError,
456 localError ? CFErrorGetCode(localError) : errSecInternalComponent);
457 }
458 CFReleaseSafe(localError);
459
460 secdebug("ocspcache", "returning %s", (response ? "cached response" : "NULL"));
461
462 return response;
463 }
464
465 static bool _SecOCSPCacheFlush(SecOCSPCacheRef cache, CFErrorRef *error) {
466 __block CFErrorRef localError = NULL;
467 __block bool ok = true;
468
469 ok &= SecDbPerformWrite(cache->db, &localError, ^(SecDbConnectionRef dbconn) {
470 ok &= SecDbExec(dbconn, flushSQL, &localError);
471 });
472 if (!ok || localError) {
473 TrustdHealthAnalyticsLogErrorCodeForDatabase(TAOCSPCache, TAOperationWrite, TAFatalError,
474 localError ? CFErrorGetCode(localError) : errSecInternalComponent);
475 }
476 (void) CFErrorPropagate(localError, error);
477
478 return ok;
479 }
480
481 static bool _SecOCSPCacheDeleteContent(SecOCSPCacheRef cache, CFErrorRef *error) {
482 __block CFErrorRef localError = NULL;
483 __block bool ok = true;
484
485 ok &= SecDbPerformWrite(cache->db, &localError, ^(SecDbConnectionRef dbconn) {
486 ok &= SecDbExec(dbconn, deleteAllSQL, &localError);
487 });
488 if (!ok || localError) {
489 TrustdHealthAnalyticsLogErrorCodeForDatabase(TAOCSPCache, TAOperationWrite, TAFatalError,
490 localError ? CFErrorGetCode(localError) : errSecInternalComponent);
491 }
492 (void) CFErrorPropagate(localError, error);
493
494 return ok;
495 }
496
497
498 /* Public API */
499
500 void SecOCSPCacheReplaceResponse(SecOCSPResponseRef old_response, SecOCSPResponseRef response,
501 CFURLRef localResponderURI, CFAbsoluteTime verifyTime) {
502 SecOCSPCacheWith(^(SecOCSPCacheRef cache) {
503 _SecOCSPCacheReplaceResponse(cache, old_response, response, localResponderURI, verifyTime);
504 });
505 }
506
507 SecOCSPResponseRef SecOCSPCacheCopyMatching(SecOCSPRequestRef request,
508 CFURLRef localResponderURI /* may be NULL */) {
509 __block SecOCSPResponseRef response = NULL;
510 SecOCSPCacheWith(^(SecOCSPCacheRef cache) {
511 response = _SecOCSPCacheCopyMatching(cache, request, localResponderURI, 0.0);
512 });
513 return response;
514 }
515
516 SecOCSPResponseRef SecOCSPCacheCopyMatchingWithMinInsertTime(SecOCSPRequestRef request,
517 CFURLRef localResponderURI, CFAbsoluteTime minInsertTime) {
518 __block SecOCSPResponseRef response = NULL;
519 SecOCSPCacheWith(^(SecOCSPCacheRef cache) {
520 response = _SecOCSPCacheCopyMatching(cache, request, localResponderURI, minInsertTime);
521 });
522 return response;
523 }
524
525 bool SecOCSPCacheFlush(CFErrorRef *error) {
526 __block bool result = false;
527 SecOCSPCacheWith(^(SecOCSPCacheRef cache) {
528 result = _SecOCSPCacheFlush(cache, error);
529 });
530 return result;
531 }
532
533 bool SecOCSPCacheDeleteContent(CFErrorRef *error) {
534 __block bool result = false;
535 SecOCSPCacheWith(^(SecOCSPCacheRef cache) {
536 result = _SecOCSPCacheDeleteContent(cache, error);
537 });
538 return result;
539 }