]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecTrustStoreServer.c
Security-58286.200.222.tar.gz
[apple/security.git] / OSX / sec / securityd / SecTrustStoreServer.c
1 /*
2 * Copyright (c) 2007-2010,2012-2015 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 * SecTrustStoreServer.c - CertificateSource API to a system root certificate store
26 */
27 #include "SecTrustStoreServer.h"
28
29 #include <Security/SecCertificateInternal.h>
30 #include <Security/SecFramework.h>
31 #include <errno.h>
32 #include <limits.h>
33 #include <dispatch/dispatch.h>
34 #include <sqlite3.h>
35 #include <stdint.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/param.h>
39 #include <sys/stat.h>
40 #include <unistd.h>
41 #include <CoreFoundation/CFData.h>
42 #include <CoreFoundation/CFPropertyList.h>
43 #include <CoreFoundation/CFURL.h>
44 #include <AssertMacros.h>
45 #include <utilities/debugging.h>
46 #include "SecBasePriv.h"
47 #include <Security/SecInternal.h>
48 #include <ipc/securityd_client.h>
49 #include <securityd/SecTrustStoreServer.h>
50 #include "utilities/sqlutils.h"
51 #include "utilities/SecDb.h"
52 #include <utilities/SecCFError.h>
53 #include "utilities/SecFileLocations.h"
54 #include <utilities/SecDispatchRelease.h>
55 #include <securityd/SecTrustLoggingServer.h>
56
57 /* uid of the _securityd user. */
58 #define SECURTYD_UID 64
59
60 static dispatch_once_t kSecTrustStoreUserOnce;
61 static SecTrustStoreRef kSecTrustStoreUser = NULL;
62
63 static const char copyParentsSQL[] = "SELECT data FROM tsettings WHERE subj=?";
64 static const char containsSQL[] = "SELECT tset FROM tsettings WHERE sha1=?";
65 static const char insertSQL[] = "INSERT OR REPLACE INTO tsettings(sha1,subj,tset,data)VALUES(?,?,?,?)";
66 static const char deleteSQL[] = "DELETE FROM tsettings WHERE sha1=?";
67 static const char deleteAllSQL[] = "BEGIN EXCLUSIVE TRANSACTION; DELETE from tsettings; COMMIT TRANSACTION; VACUUM;";
68 static const char copyAllSQL[] = "SELECT data,tset FROM tsettings ORDER BY sha1";
69 static const char countAllSQL[] = "SELECT COUNT(*) FROM tsettings";
70
71 #define kSecTrustStoreName CFSTR("TrustStore")
72 #define kSecTrustStoreDbExtension CFSTR("sqlite3")
73
74 #define kTrustStoreFileName CFSTR("TrustStore.sqlite3")
75
76
77 struct __SecTrustStore {
78 dispatch_queue_t queue;
79 sqlite3 *s3h;
80 sqlite3_stmt *copyParents;
81 sqlite3_stmt *contains;
82 bool readOnly;
83 bool containsSettings; // For optimization of high-use calls.
84 };
85
86 static int sec_create_path(const char *path)
87 {
88 char pathbuf[PATH_MAX];
89 size_t pos, len = strlen(path);
90 if (len == 0 || len > PATH_MAX)
91 return SQLITE_CANTOPEN;
92 memcpy(pathbuf, path, len);
93 for (pos = len-1; pos > 0; --pos)
94 {
95 /* Search backwards for trailing '/'. */
96 if (pathbuf[pos] == '/')
97 {
98 pathbuf[pos] = '\0';
99 /* Attempt to create parent directories of the database. */
100 if (!mkdir(pathbuf, 0777))
101 break;
102 else
103 {
104 int err = errno;
105 if (err == EEXIST)
106 return 0;
107 if (err == ENOTDIR)
108 return SQLITE_CANTOPEN;
109 if (err == EROFS)
110 return SQLITE_READONLY;
111 if (err == EACCES)
112 return SQLITE_PERM;
113 if (err == ENOSPC || err == EDQUOT)
114 return SQLITE_FULL;
115 if (err == EIO)
116 return SQLITE_IOERR;
117
118 /* EFAULT || ELOOP | ENAMETOOLONG || something else */
119 return SQLITE_INTERNAL;
120 }
121 }
122 }
123 return SQLITE_OK;
124 }
125
126 static int sec_sqlite3_open(const char *db_name, sqlite3 **s3h,
127 bool create_path)
128 {
129 int s3e;
130 s3e = sqlite3_open(db_name, s3h);
131 if (s3e == SQLITE_CANTOPEN && create_path) {
132 /* Make sure the path to db_name exists and is writable, then
133 try again. */
134 s3e = sec_create_path(db_name);
135 if (!s3e)
136 s3e = sqlite3_open(db_name, s3h);
137 }
138
139 return s3e;
140 }
141
142 static int64_t SecTrustStoreCountAll(SecTrustStoreRef ts) {
143 __block int64_t result = -1;
144 require_quiet(ts, errOutNotLocked);
145 dispatch_sync(ts->queue, ^{
146 sqlite3_stmt *countAllStmt = NULL;
147 int s3e = sqlite3_prepare_v2(ts->s3h, countAllSQL, sizeof(countAllSQL),
148 &countAllStmt, NULL);
149 if (s3e == SQLITE_OK) {
150 s3e = sqlite3_step(countAllStmt);
151 if (s3e == SQLITE_ROW) {
152 result = sqlite3_column_int64(countAllStmt, 0);
153 }
154 }
155
156 if (countAllStmt) {
157 verify_noerr(sqlite3_finalize(countAllStmt));
158 }
159 });
160
161 errOutNotLocked:
162 return result;
163 }
164
165 static SecTrustStoreRef SecTrustStoreCreate(const char *db_name,
166 bool create) {
167 SecTrustStoreRef ts;
168 int s3e = SQLITE_OK;
169
170 require(ts = (SecTrustStoreRef)malloc(sizeof(struct __SecTrustStore)), errOut);
171 ts->queue = dispatch_queue_create("truststore", DISPATCH_QUEUE_SERIAL);
172 require_noerr(s3e = sec_sqlite3_open(db_name, &ts->s3h, create), errOut);
173
174 s3e = sqlite3_prepare_v3(ts->s3h, copyParentsSQL, sizeof(copyParentsSQL),
175 SQLITE_PREPARE_PERSISTENT, &ts->copyParents, NULL);
176 if (create && s3e == SQLITE_ERROR) {
177 /* sqlite3_prepare returns SQLITE_ERROR if the table we are
178 compiling this statement for doesn't exist. */
179 char *errmsg = NULL;
180 s3e = sqlite3_exec(ts->s3h,
181 "CREATE TABLE tsettings("
182 "sha1 BLOB NOT NULL DEFAULT '',"
183 "subj BLOB NOT NULL DEFAULT '',"
184 "tset BLOB,"
185 "data BLOB,"
186 "PRIMARY KEY(sha1)"
187 ");"
188 "CREATE INDEX isubj ON tsettings(subj);"
189 , NULL, NULL, &errmsg);
190 if (errmsg) {
191 secwarning("CREATE TABLE cert: %s", errmsg);
192 sqlite3_free(errmsg);
193 }
194 require_noerr(s3e, errOut);
195 s3e = sqlite3_prepare_v3(ts->s3h, copyParentsSQL, sizeof(copyParentsSQL),
196 SQLITE_PREPARE_PERSISTENT, &ts->copyParents, NULL);
197 }
198 require_noerr(s3e, errOut);
199 require_noerr(s3e = sqlite3_prepare_v3(ts->s3h, containsSQL, sizeof(containsSQL), SQLITE_PREPARE_PERSISTENT,
200 &ts->contains, NULL), errOut);
201
202 if (SecTrustStoreCountAll(ts) == 0) {
203 ts->containsSettings = false;
204 } else {
205 /* In the error case where SecTrustStoreCountAll returns a negative result,
206 * we'll pretend there are contents in the trust store so that we still do
207 * DB operations */
208 ts->containsSettings = true;
209 }
210
211 return ts;
212
213 errOut:
214 if (ts) {
215 sqlite3_close(ts->s3h);
216 dispatch_release_safe(ts->queue);
217 free(ts);
218 }
219 secerror("Failed to create trust store database: %d", s3e);
220 TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationCreate, TAFatalError, s3e);
221
222 return NULL;
223 }
224
225 static bool SecExtractFilesystemPathForKeychainFile(CFStringRef file, UInt8 *buffer, CFIndex maxBufLen)
226 {
227 bool translated = false;
228 CFURLRef fileURL = SecCopyURLForFileInKeychainDirectory(file);
229
230 if (fileURL && CFURLGetFileSystemRepresentation(fileURL, false, buffer, maxBufLen))
231 translated = true;
232 CFReleaseSafe(fileURL);
233
234 return translated;
235 }
236
237 static void SecTrustStoreInitUser(void) {
238 const char path[MAXPATHLEN];
239
240 if (SecExtractFilesystemPathForKeychainFile(kTrustStoreFileName, (UInt8*) path, (CFIndex) sizeof(path)))
241 {
242 kSecTrustStoreUser = SecTrustStoreCreate(path, true);
243 if (kSecTrustStoreUser)
244 kSecTrustStoreUser->readOnly = false;
245 }
246 }
247
248 /* AUDIT[securityd](done):
249 domainName (ok) is a caller provided string of any length (might be 0), only
250 its cf type has been checked.
251 */
252 SecTrustStoreRef SecTrustStoreForDomainName(CFStringRef domainName, CFErrorRef *error) {
253 if (CFEqual(CFSTR("user"), domainName)) {
254 dispatch_once(&kSecTrustStoreUserOnce, ^{ SecTrustStoreInitUser(); });
255 return kSecTrustStoreUser;
256 } else {
257 SecError(errSecParam, error, CFSTR("unknown domain: %@"), domainName);
258 return NULL;
259 }
260 }
261
262 /* AUDIT[securityd](done):
263 ts (ok) might be NULL.
264 certificate (ok) is a valid SecCertificateRef.
265 trustSettingsDictOrArray (checked by CFPropertyListCreateXMLData) is either
266 NULL, a dictionary or an array, but its contents have not been checked.
267 */
268 bool _SecTrustStoreSetTrustSettings(SecTrustStoreRef ts,
269 SecCertificateRef certificate,
270 CFTypeRef tsdoa, CFErrorRef *error) {
271 __block bool ok;
272 require_action_quiet(ts, errOutNotLocked, ok = SecError(errSecParam, error, CFSTR("truststore is NULL")));
273 require_action_quiet(!ts->readOnly, errOutNotLocked, ok = SecError(errSecReadOnly, error, CFSTR("truststore is readOnly")));
274 dispatch_sync(ts->queue, ^{
275 CFTypeRef trustSettingsDictOrArray = tsdoa;
276 sqlite3_stmt *insert = NULL;
277 CFDataRef xmlData = NULL;
278 CFArrayRef array = NULL;
279
280 CFDataRef subject;
281 require_action_quiet(subject = SecCertificateGetNormalizedSubjectContent(certificate),
282 errOut, ok = SecError(errSecParam, error, CFSTR("get normalized subject failed")));
283 CFDataRef digest;
284 require_action_quiet(digest = SecCertificateGetSHA1Digest(certificate), errOut, ok = SecError(errSecParam, error, CFSTR("get sha1 digest failed")));
285
286 /* Do some basic checks on the trust settings passed in. */
287 if (trustSettingsDictOrArray == NULL) {
288 require_action_quiet(array = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks), errOut, ok = SecError(errSecAllocate, error, CFSTR("CFArrayCreate failed")));
289 trustSettingsDictOrArray = array;
290 }
291 else if(CFGetTypeID(trustSettingsDictOrArray) == CFDictionaryGetTypeID()) {
292 /* array-ize it */
293 array = CFArrayCreate(NULL, &trustSettingsDictOrArray, 1,
294 &kCFTypeArrayCallBacks);
295 trustSettingsDictOrArray = array;
296 }
297 else {
298 require_action_quiet(CFGetTypeID(trustSettingsDictOrArray) == CFArrayGetTypeID(), errOut, ok = SecError(errSecParam, error, CFSTR("trustSettingsDictOrArray neither dict nor array")));
299 }
300
301 require_action_quiet(xmlData = CFPropertyListCreateXMLData(kCFAllocatorDefault,
302 trustSettingsDictOrArray), errOut, ok = SecError(errSecParam, error, CFSTR("xml encode failed")));
303
304 int s3e = sqlite3_exec(ts->s3h, "BEGIN EXCLUSIVE TRANSACTION", NULL, NULL, NULL);
305 require_action_quiet(s3e == SQLITE_OK, errOut, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
306
307 /* Parameter order is sha1,subj,tset,data. */
308 require_noerr_action_quiet(s3e = sqlite3_prepare_v2(ts->s3h, insertSQL, sizeof(insertSQL),
309 &insert, NULL), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
310 require_noerr_action_quiet(s3e = sqlite3_bind_blob_wrapper(insert, 1,
311 CFDataGetBytePtr(digest), CFDataGetLength(digest), SQLITE_STATIC),
312 errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
313 require_noerr_action_quiet(s3e = sqlite3_bind_blob_wrapper(insert, 2,
314 CFDataGetBytePtr(subject), CFDataGetLength(subject),
315 SQLITE_STATIC), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
316 require_noerr_action_quiet(s3e = sqlite3_bind_blob_wrapper(insert, 3,
317 CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData),
318 SQLITE_STATIC), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
319 require_noerr_action_quiet(s3e = sqlite3_bind_blob_wrapper(insert, 4,
320 SecCertificateGetBytePtr(certificate),
321 SecCertificateGetLength(certificate), SQLITE_STATIC), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
322 s3e = sqlite3_step(insert);
323 if (s3e == SQLITE_DONE) {
324 /* Great the insert worked. */
325 ok = true;
326 ts->containsSettings = true;
327 } else {
328 require_noerr_action_quiet(s3e, errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
329 ok = true;
330 }
331
332 errOutSql:
333 if (insert) {
334 s3e = sqlite3_finalize(insert);
335 }
336
337 if (ok && s3e == SQLITE_OK) {
338 s3e = sqlite3_exec(ts->s3h, "COMMIT TRANSACTION", NULL, NULL, NULL);
339 }
340
341 if (!ok || s3e != SQLITE_OK) {
342 secerror("Failed to update trust store: (%d) %@", s3e, error ? *error : NULL);
343 TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationWrite, TAFatalError, s3e);
344 sqlite3_exec(ts->s3h, "ROLLBACK TRANSACTION", NULL, NULL, NULL);
345 if (ok) {
346 ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e);
347 }
348 }
349
350 errOut:
351 CFReleaseSafe(xmlData);
352 CFReleaseSafe(array);
353 });
354 errOutNotLocked:
355 return ok;
356 }
357
358 /* AUDIT[securityd](done):
359 ts (ok) might be NULL.
360 digest (ok) is a data of any length (might be 0).
361 */
362 bool SecTrustStoreRemoveCertificateWithDigest(SecTrustStoreRef ts,
363 CFDataRef digest, CFErrorRef *error) {
364 require_quiet(ts, errOutNotLocked);
365 require(!ts->readOnly, errOutNotLocked);
366 dispatch_sync(ts->queue, ^{
367 int s3e = SQLITE_OK;
368 sqlite3_stmt *deleteStmt = NULL;
369
370 require_noerr(s3e = sqlite3_prepare_v2(ts->s3h, deleteSQL, sizeof(deleteSQL),
371 &deleteStmt, NULL), errOut);
372 require_noerr(s3e = sqlite3_bind_blob_wrapper(deleteStmt, 1,
373 CFDataGetBytePtr(digest), CFDataGetLength(digest), SQLITE_STATIC),
374 errOut);
375 s3e = sqlite3_step(deleteStmt);
376
377 errOut:
378 if (deleteStmt) {
379 verify_noerr(sqlite3_finalize(deleteStmt));
380 }
381 if (s3e != SQLITE_OK && s3e != SQLITE_DONE) {
382 secerror("Removal of certificate from trust store failed: %d", s3e);
383 TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationWrite, TAFatalError, s3e);
384 }
385 });
386 errOutNotLocked:
387 return true;
388 }
389
390 bool _SecTrustStoreRemoveAll(SecTrustStoreRef ts, CFErrorRef *error)
391 {
392 __block bool removed_all = false;
393 require(ts, errOutNotLocked);
394 require(!ts->readOnly, errOutNotLocked);
395 dispatch_sync(ts->queue, ^{
396 int s3e =sqlite3_exec(ts->s3h, deleteAllSQL, NULL, NULL, NULL);
397 if (s3e == SQLITE_OK) {
398 removed_all = true;
399 ts->containsSettings = false;
400 } else {
401 secerror("Clearing of trust store failed: %d", s3e);
402 TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationWrite, TAFatalError, s3e);
403 }
404
405 /* prepared statements become unusable after deleteAllSQL, reset them */
406 if (ts->copyParents)
407 sqlite3_finalize(ts->copyParents);
408 sqlite3_prepare_v3(ts->s3h, copyParentsSQL, sizeof(copyParentsSQL), SQLITE_PREPARE_PERSISTENT,
409 &ts->copyParents, NULL);
410 if (ts->contains)
411 sqlite3_finalize(ts->contains);
412 sqlite3_prepare_v3(ts->s3h, containsSQL, sizeof(containsSQL), SQLITE_PREPARE_PERSISTENT,
413 &ts->contains, NULL);
414 });
415 errOutNotLocked:
416 return removed_all;
417 }
418
419 CFArrayRef SecTrustStoreCopyParents(SecTrustStoreRef ts,
420 SecCertificateRef certificate, CFErrorRef *error) {
421 __block CFMutableArrayRef parents = NULL;
422 require(ts, errOutNotLocked);
423 dispatch_sync(ts->queue, ^{
424 int s3e = SQLITE_OK;
425 require_quiet(ts->containsSettings, ok);
426 CFDataRef issuer;
427 require(issuer = SecCertificateGetNormalizedIssuerContent(certificate),
428 errOut);
429 /* @@@ Might have to use SQLITE_TRANSIENT */
430 require_noerr(s3e = sqlite3_bind_blob_wrapper(ts->copyParents, 1,
431 CFDataGetBytePtr(issuer), CFDataGetLength(issuer),
432 SQLITE_STATIC), errOut);
433
434 require(parents = CFArrayCreateMutable(kCFAllocatorDefault, 0,
435 &kCFTypeArrayCallBacks), errOut);
436 for (;;) {
437 s3e = sqlite3_step(ts->copyParents);
438 if (s3e == SQLITE_ROW) {
439 SecCertificateRef cert;
440 require(cert = SecCertificateCreateWithBytes(kCFAllocatorDefault,
441 sqlite3_column_blob(ts->copyParents, 0),
442 sqlite3_column_bytes(ts->copyParents, 0)), errOut);
443 CFArrayAppendValue(parents, cert);
444 CFRelease(cert);
445 } else {
446 require(s3e == SQLITE_DONE || s3e == SQLITE_OK, errOut);
447 break;
448 }
449 }
450
451 goto ok;
452 errOut:
453 secerror("Failed to read parents from trust store: %d", s3e);
454 TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationRead, TAFatalError, s3e);
455 if (parents) {
456 CFRelease(parents);
457 parents = NULL;
458 }
459 ok:
460 verify_noerr(sqlite3_reset(ts->copyParents));
461 verify_noerr(sqlite3_clear_bindings(ts->copyParents));
462 });
463 errOutNotLocked:
464 return parents;
465 }
466
467 static bool SecTrustStoreQueryCertificateWithDigest(SecTrustStoreRef ts,
468 CFDataRef digest, bool *contains, CFArrayRef *usageConstraints, CFErrorRef *error) {
469 if (contains)
470 *contains = false;
471 __block bool ok = true;
472 require_action_quiet(ts, errOutNotLocked, ok = SecError(errSecParam, error, CFSTR("ts is NULL")));
473 dispatch_sync(ts->queue, ^{
474 CFDataRef xmlData = NULL;
475 CFPropertyListRef trustSettings = NULL;
476 int s3e = SQLITE_OK;
477 require_action_quiet(ts->containsSettings, errOut, ok = true);
478 require_noerr_action(s3e = sqlite3_bind_blob_wrapper(ts->contains, 1,
479 CFDataGetBytePtr(digest), CFDataGetLength(digest), SQLITE_STATIC),
480 errOut, ok = SecDbErrorWithStmt(s3e, ts->contains, error, CFSTR("sqlite3_bind_blob failed")));
481 s3e = sqlite3_step(ts->contains);
482 if (s3e == SQLITE_ROW) {
483 if (contains)
484 *contains = true;
485 if (usageConstraints) {
486 require_action(xmlData = CFDataCreate(NULL,
487 sqlite3_column_blob(ts->contains, 0),
488 sqlite3_column_bytes(ts->contains, 0)), errOut, ok = false);
489 require_action(trustSettings = CFPropertyListCreateWithData(NULL,
490 xmlData,
491 kCFPropertyListImmutable,
492 NULL, error), errOut, ok = false);
493 require_action(CFGetTypeID(trustSettings) == CFArrayGetTypeID(), errOut, ok = false);
494 *usageConstraints = CFRetain(trustSettings);
495 }
496 } else {
497 require_action(s3e == SQLITE_DONE || s3e == SQLITE_OK, errOut,
498 ok = SecDbErrorWithStmt(s3e, ts->contains, error, CFSTR("sqlite3_step failed")));
499 }
500
501 errOut:
502 if (!ok) {
503 secerror("Failed to query for cert in trust store: %d", s3e);
504 TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationRead, TAFatalError, s3e);
505 }
506 verify_noerr(sqlite3_reset(ts->contains));
507 verify_noerr(sqlite3_clear_bindings(ts->contains));
508 CFReleaseNull(xmlData);
509 CFReleaseNull(trustSettings);
510 });
511 errOutNotLocked:
512 return ok;
513 }
514
515 bool SecTrustStoreContainsCertificateWithDigest(SecTrustStoreRef ts,
516 CFDataRef digest, bool *contains, CFErrorRef *error) {
517 return SecTrustStoreQueryCertificateWithDigest(ts, digest, contains, NULL, error);
518 }
519
520 bool _SecTrustStoreCopyUsageConstraints(SecTrustStoreRef ts,
521 CFDataRef digest, CFArrayRef *usageConstraints, CFErrorRef *error) {
522 return SecTrustStoreQueryCertificateWithDigest(ts, digest, NULL, usageConstraints, error);
523 }
524
525 bool _SecTrustStoreCopyAll(SecTrustStoreRef ts, CFArrayRef *trustStoreContents, CFErrorRef *error) {
526 __block bool ok = true;
527 __block CFMutableArrayRef CertsAndSettings = NULL;
528 require_action_quiet(ts, errOutNotLocked, ok = SecError(errSecParam, error, CFSTR("ts is NULL")));
529 require_action_quiet(trustStoreContents, errOutNotLocked, ok = SecError(errSecParam, error, CFSTR("trustStoreContents is NULL")));
530 dispatch_sync(ts->queue, ^{
531 sqlite3_stmt *copyAllStmt = NULL;
532 CFDataRef cert = NULL;
533 CFDataRef xmlData = NULL;
534 CFPropertyListRef trustSettings = NULL;
535 CFArrayRef certSettingsPair = NULL;
536 int s3e = SQLITE_OK;
537 require_noerr(s3e = sqlite3_prepare_v2(ts->s3h, copyAllSQL, sizeof(copyAllSQL),
538 &copyAllStmt, NULL), errOut);
539 require(CertsAndSettings = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks), errOut);
540 for(;;) {
541 s3e = sqlite3_step(copyAllStmt);
542 if (s3e == SQLITE_ROW) {
543 require(cert = CFDataCreate(kCFAllocatorDefault,
544 sqlite3_column_blob(copyAllStmt, 0),
545 sqlite3_column_bytes(copyAllStmt, 0)), errOut);
546 require(xmlData = CFDataCreate(NULL,
547 sqlite3_column_blob(copyAllStmt, 1),
548 sqlite3_column_bytes(copyAllStmt, 1)), errOut);
549 require(trustSettings = CFPropertyListCreateWithData(NULL,
550 xmlData,
551 kCFPropertyListImmutable,
552 NULL, error), errOut);
553 const void *pair[] = { cert , trustSettings };
554 require(certSettingsPair = CFArrayCreate(NULL, pair, 2, &kCFTypeArrayCallBacks), errOut);
555 CFArrayAppendValue(CertsAndSettings, certSettingsPair);
556
557 CFReleaseNull(cert);
558 CFReleaseNull(xmlData);
559 CFReleaseNull(trustSettings);
560 CFReleaseNull(certSettingsPair);
561 } else {
562 require_action(s3e == SQLITE_DONE || s3e == SQLITE_OK, errOut, ok = SecDbErrorWithStmt(s3e, copyAllStmt, error, CFSTR("sqlite3_step failed")));
563 break;
564 }
565 }
566 goto ok;
567
568 errOut:
569 secerror("Failed to query for all certs in trust store: %d", s3e);
570 TrustdHealthAnalyticsLogErrorCodeForDatabase(TATrustStore, TAOperationRead, TAFatalError, s3e);
571 CFReleaseNull(cert);
572 CFReleaseNull(xmlData);
573 CFReleaseNull(trustSettings);
574 CFReleaseNull(certSettingsPair);
575 ok:
576 if (copyAllStmt) {
577 verify_noerr(sqlite3_finalize(copyAllStmt));
578 }
579 if (CertsAndSettings) {
580 *trustStoreContents = CertsAndSettings;
581 }
582 });
583 errOutNotLocked:
584 return ok;
585 }