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