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