]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecTrustStoreServer.c
Security-57740.31.2.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
56 /* uid of the _securityd user. */
57 #define SECURTYD_UID 64
58
59 static dispatch_once_t kSecTrustStoreUserOnce;
60 static SecTrustStoreRef kSecTrustStoreUser = NULL;
61
62 static const char copyParentsSQL[] = "SELECT data FROM tsettings WHERE subj=?";
63 static const char containsSQL[] = "SELECT tset FROM tsettings WHERE sha1=?";
64 static const char insertSQL[] = "INSERT INTO tsettings(sha1,subj,tset,data)VALUES(?,?,?,?)";
65 static const char updateSQL[] = "UPDATE tsettings SET tset=? WHERE sha1=?";
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(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;
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(ts->s3h, copyParentsSQL, sizeof(copyParentsSQL),
175 &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(ts->s3h, copyParentsSQL, sizeof(copyParentsSQL),
196 &ts->copyParents, NULL);
197 }
198 require_noerr(s3e, errOut);
199 require_noerr(s3e = sqlite3_prepare(ts->s3h, containsSQL, sizeof(containsSQL),
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
220 return NULL;
221 }
222
223 static bool SecExtractFilesystemPathForKeychainFile(CFStringRef file, UInt8 *buffer, CFIndex maxBufLen)
224 {
225 bool translated = false;
226 CFURLRef fileURL = SecCopyURLForFileInKeychainDirectory(file);
227
228 if (fileURL && CFURLGetFileSystemRepresentation(fileURL, false, buffer, maxBufLen))
229 translated = true;
230 CFReleaseSafe(fileURL);
231
232 return translated;
233 }
234
235 static void SecTrustStoreInitUser(void) {
236 const char path[MAXPATHLEN];
237
238 if (SecExtractFilesystemPathForKeychainFile(kTrustStoreFileName, (UInt8*) path, (CFIndex) sizeof(path)))
239 {
240 kSecTrustStoreUser = SecTrustStoreCreate(path, true);
241 if (kSecTrustStoreUser)
242 kSecTrustStoreUser->readOnly = false;
243 }
244 }
245
246 /* AUDIT[securityd](done):
247 domainName (ok) is a caller provided string of any length (might be 0), only
248 its cf type has been checked.
249 */
250 SecTrustStoreRef SecTrustStoreForDomainName(CFStringRef domainName, CFErrorRef *error) {
251 if (CFEqual(CFSTR("user"), domainName)) {
252 dispatch_once(&kSecTrustStoreUserOnce, ^{ SecTrustStoreInitUser(); });
253 return kSecTrustStoreUser;
254 } else {
255 SecError(errSecParam, error, CFSTR("unknown domain: %@"), domainName);
256 return NULL;
257 }
258 }
259
260 /* AUDIT[securityd](done):
261 ts (ok) might be NULL.
262 certificate (ok) is a valid SecCertificateRef.
263 trustSettingsDictOrArray (checked by CFPropertyListCreateXMLData) is either
264 NULL, a dictionary or an array, but its contents have not been checked.
265 */
266 bool _SecTrustStoreSetTrustSettings(SecTrustStoreRef ts,
267 SecCertificateRef certificate,
268 CFTypeRef tsdoa, CFErrorRef *error) {
269 __block bool ok;
270 require_action_quiet(ts, errOutNotLocked, ok = SecError(errSecParam, error, CFSTR("truststore is NULL")));
271 require_action_quiet(!ts->readOnly, errOutNotLocked, ok = SecError(errSecReadOnly, error, CFSTR("truststore is readOnly")));
272 dispatch_sync(ts->queue, ^{
273 CFTypeRef trustSettingsDictOrArray = tsdoa;
274 sqlite3_stmt *insert = NULL, *update = NULL;
275 CFDataRef xmlData = NULL;
276 CFArrayRef array = NULL;
277
278 CFDataRef subject;
279 require_action_quiet(subject = SecCertificateGetNormalizedSubjectContent(certificate),
280 errOut, ok = SecError(errSecParam, error, CFSTR("get normalized subject failed")));
281 CFDataRef digest;
282 require_action_quiet(digest = SecCertificateGetSHA1Digest(certificate), errOut, ok = SecError(errSecParam, error, CFSTR("get sha1 digest failed")));
283
284 /* Do some basic checks on the trust settings passed in. */
285 if (trustSettingsDictOrArray == NULL) {
286 require_action_quiet(array = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks), errOut, ok = SecError(errSecAllocate, error, CFSTR("CFArrayCreate failed")));
287 trustSettingsDictOrArray = array;
288 }
289 else if(CFGetTypeID(trustSettingsDictOrArray) == CFDictionaryGetTypeID()) {
290 /* array-ize it */
291 array = CFArrayCreate(NULL, &trustSettingsDictOrArray, 1,
292 &kCFTypeArrayCallBacks);
293 trustSettingsDictOrArray = array;
294 }
295 else {
296 require_action_quiet(CFGetTypeID(trustSettingsDictOrArray) == CFArrayGetTypeID(), errOut, ok = SecError(errSecParam, error, CFSTR("trustSettingsDictOrArray neither dict nor array")));
297 }
298
299 require_action_quiet(xmlData = CFPropertyListCreateXMLData(kCFAllocatorDefault,
300 trustSettingsDictOrArray), errOut, ok = SecError(errSecParam, error, CFSTR("xml encode failed")));
301
302 int s3e = sqlite3_exec(ts->s3h, "BEGIN EXCLUSIVE TRANSACTION", NULL, NULL, NULL);
303 require_action_quiet(s3e == SQLITE_OK, errOut, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
304
305 /* Parameter order is sha1,subj,tset,data. */
306 require_noerr_action_quiet(sqlite3_prepare(ts->s3h, insertSQL, sizeof(insertSQL),
307 &insert, NULL), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
308 require_noerr_action_quiet(sqlite3_bind_blob_wrapper(insert, 1,
309 CFDataGetBytePtr(digest), CFDataGetLength(digest), SQLITE_STATIC),
310 errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
311 require_noerr_action_quiet(sqlite3_bind_blob_wrapper(insert, 2,
312 CFDataGetBytePtr(subject), CFDataGetLength(subject),
313 SQLITE_STATIC), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
314 require_noerr_action_quiet(sqlite3_bind_blob_wrapper(insert, 3,
315 CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData),
316 SQLITE_STATIC), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
317 require_noerr_action_quiet(sqlite3_bind_blob_wrapper(insert, 4,
318 SecCertificateGetBytePtr(certificate),
319 SecCertificateGetLength(certificate), SQLITE_STATIC), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
320 s3e = sqlite3_step(insert);
321 if (s3e == SQLITE_DONE) {
322 /* Great the insert worked. */
323 ok = true;
324 ts->containsSettings = true;
325 } else if (s3e == SQLITE_ERROR) {
326 /* Try update. */
327 require_noerr_action_quiet(s3e = sqlite3_prepare(ts->s3h, updateSQL, sizeof(updateSQL),
328 &update, NULL), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
329 require_noerr_action_quiet(s3e = sqlite3_bind_blob_wrapper(update, 1,
330 CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData),
331 SQLITE_STATIC), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
332 require_noerr_action_quiet(s3e = sqlite3_bind_blob_wrapper(update, 2,
333 CFDataGetBytePtr(digest), CFDataGetLength(digest), SQLITE_STATIC),
334 errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
335 s3e = sqlite3_step(update);
336 require_action_quiet(s3e == SQLITE_DONE, errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
337 s3e = SQLITE_OK;
338 ok = true;
339 } else {
340 require_noerr_action_quiet(s3e, errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
341 ok = true;
342 }
343
344 errOutSql:
345 if (insert)
346 s3e = sqlite3_finalize(insert);
347 if (update)
348 s3e = sqlite3_finalize(update);
349
350 if (ok && s3e == SQLITE_OK)
351 s3e = sqlite3_exec(ts->s3h, "COMMIT TRANSACTION", NULL, NULL, NULL);
352
353 if (!ok || s3e != SQLITE_OK) {
354 sqlite3_exec(ts->s3h, "ROLLBACK TRANSACTION", NULL, NULL, NULL);
355 if (ok) {
356 ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e);
357 }
358 }
359
360 errOut:
361 CFReleaseSafe(xmlData);
362 CFReleaseSafe(array);
363 });
364 errOutNotLocked:
365 return ok;
366 }
367
368 /* AUDIT[securityd](done):
369 ts (ok) might be NULL.
370 digest (ok) is a data of any length (might be 0).
371 */
372 bool SecTrustStoreRemoveCertificateWithDigest(SecTrustStoreRef ts,
373 CFDataRef digest, CFErrorRef *error) {
374 require_quiet(ts, errOutNotLocked);
375 require(!ts->readOnly, errOutNotLocked);
376 dispatch_sync(ts->queue, ^{
377 sqlite3_stmt *deleteStmt = NULL;
378 require_noerr(sqlite3_prepare(ts->s3h, deleteSQL, sizeof(deleteSQL),
379 &deleteStmt, NULL), errOut);
380 require_noerr(sqlite3_bind_blob_wrapper(deleteStmt, 1,
381 CFDataGetBytePtr(digest), CFDataGetLength(digest), SQLITE_STATIC),
382 errOut);
383 sqlite3_step(deleteStmt);
384
385 errOut:
386 if (deleteStmt) {
387 verify_noerr(sqlite3_finalize(deleteStmt));
388 }
389 });
390 errOutNotLocked:
391 return true;
392 }
393
394 bool _SecTrustStoreRemoveAll(SecTrustStoreRef ts, CFErrorRef *error)
395 {
396 __block bool removed_all = false;
397 require(ts, errOutNotLocked);
398 require(!ts->readOnly, errOutNotLocked);
399 dispatch_sync(ts->queue, ^{
400 if (SQLITE_OK == sqlite3_exec(ts->s3h, deleteAllSQL, NULL, NULL, NULL)) {
401 removed_all = true;
402 ts->containsSettings = false;
403 }
404
405 /* prepared statements become unusable after deleteAllSQL, reset them */
406 if (ts->copyParents)
407 sqlite3_finalize(ts->copyParents);
408 sqlite3_prepare(ts->s3h, copyParentsSQL, sizeof(copyParentsSQL),
409 &ts->copyParents, NULL);
410 if (ts->contains)
411 sqlite3_finalize(ts->contains);
412 sqlite3_prepare(ts->s3h, containsSQL, sizeof(containsSQL),
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 require_quiet(ts->containsSettings, errOut);
425 CFDataRef issuer;
426 require(issuer = SecCertificateGetNormalizedIssuerContent(certificate),
427 errOut);
428 /* @@@ Might have to use SQLITE_TRANSIENT */
429 require_noerr(sqlite3_bind_blob_wrapper(ts->copyParents, 1,
430 CFDataGetBytePtr(issuer), CFDataGetLength(issuer),
431 SQLITE_STATIC), errOut);
432
433 require(parents = CFArrayCreateMutable(kCFAllocatorDefault, 0,
434 &kCFTypeArrayCallBacks), errOut);
435 for (;;) {
436 int s3e = sqlite3_step(ts->copyParents);
437 if (s3e == SQLITE_ROW) {
438 SecCertificateRef cert;
439 require(cert = SecCertificateCreateWithBytes(kCFAllocatorDefault,
440 sqlite3_column_blob(ts->copyParents, 0),
441 sqlite3_column_bytes(ts->copyParents, 0)), errOut);
442 CFArrayAppendValue(parents, cert);
443 CFRelease(cert);
444 } else {
445 require(s3e == SQLITE_DONE, errOut);
446 break;
447 }
448 }
449
450 goto ok;
451 errOut:
452 if (parents) {
453 CFRelease(parents);
454 parents = NULL;
455 }
456 ok:
457 verify_noerr(sqlite3_reset(ts->copyParents));
458 verify_noerr(sqlite3_clear_bindings(ts->copyParents));
459 });
460 errOutNotLocked:
461 return parents;
462 }
463
464 static bool SecTrustStoreQueryCertificateWithDigest(SecTrustStoreRef ts,
465 CFDataRef digest, bool *contains, CFArrayRef *usageConstraints, CFErrorRef *error) {
466 if (contains)
467 *contains = false;
468 __block bool ok = true;
469 require_action_quiet(ts, errOutNotLocked, ok = SecError(errSecParam, error, CFSTR("ts is NULL")));
470 dispatch_sync(ts->queue, ^{
471 CFDataRef xmlData = NULL;
472 CFPropertyListRef trustSettings = NULL;
473 require_action_quiet(ts->containsSettings, errOut, ok = true);
474 int s3e;
475 require_noerr_action(s3e = sqlite3_bind_blob_wrapper(ts->contains, 1,
476 CFDataGetBytePtr(digest), CFDataGetLength(digest), SQLITE_STATIC),
477 errOut, ok = SecDbErrorWithStmt(s3e, ts->contains, error, CFSTR("sqlite3_bind_blob failed")));
478 s3e = sqlite3_step(ts->contains);
479 if (s3e == SQLITE_ROW) {
480 if (contains)
481 *contains = true;
482 if (usageConstraints) {
483 require_action(xmlData = CFDataCreate(NULL,
484 sqlite3_column_blob(ts->contains, 0),
485 sqlite3_column_bytes(ts->contains, 0)), errOut, ok = false);
486 require_action(trustSettings = CFPropertyListCreateWithData(NULL,
487 xmlData,
488 kCFPropertyListImmutable,
489 NULL, error), errOut, ok = false);
490 require_action(CFGetTypeID(trustSettings) == CFArrayGetTypeID(), errOut, ok = false);
491 *usageConstraints = CFRetain(trustSettings);
492 }
493 } else {
494 require_action(s3e == SQLITE_DONE, errOut, ok = SecDbErrorWithStmt(s3e, ts->contains, error, CFSTR("sqlite3_step failed")));
495 }
496
497 errOut:
498 verify_noerr(sqlite3_reset(ts->contains));
499 verify_noerr(sqlite3_clear_bindings(ts->contains));
500 CFReleaseNull(xmlData);
501 CFReleaseNull(trustSettings);
502 });
503 errOutNotLocked:
504 return ok;
505 }
506
507 bool SecTrustStoreContainsCertificateWithDigest(SecTrustStoreRef ts,
508 CFDataRef digest, bool *contains, CFErrorRef *error) {
509 return SecTrustStoreQueryCertificateWithDigest(ts, digest, contains, NULL, error);
510 }
511
512 bool _SecTrustStoreCopyUsageConstraints(SecTrustStoreRef ts,
513 CFDataRef digest, CFArrayRef *usageConstraints, CFErrorRef *error) {
514 return SecTrustStoreQueryCertificateWithDigest(ts, digest, NULL, usageConstraints, error);
515 }
516
517 bool _SecTrustStoreCopyAll(SecTrustStoreRef ts, CFArrayRef *trustStoreContents, CFErrorRef *error) {
518 __block bool ok = true;
519 __block CFMutableArrayRef CertsAndSettings = NULL;
520 require_action_quiet(ts, errOutNotLocked, ok = SecError(errSecParam, error, CFSTR("ts is NULL")));
521 require_action_quiet(trustStoreContents, errOutNotLocked, ok = SecError(errSecParam, error, CFSTR("trustStoreContents is NULL")));
522 dispatch_sync(ts->queue, ^{
523 sqlite3_stmt *copyAllStmt = NULL;
524 CFDataRef cert = NULL;
525 CFDataRef xmlData = NULL;
526 CFPropertyListRef trustSettings = NULL;
527 CFArrayRef certSettingsPair = NULL;
528 require_noerr(sqlite3_prepare(ts->s3h, copyAllSQL, sizeof(copyAllSQL),
529 &copyAllStmt, NULL), errOut);
530 require(CertsAndSettings = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks), errOut);
531
532 for(;;) {
533 int s3e = sqlite3_step(copyAllStmt);
534 if (s3e == SQLITE_ROW) {
535 require(cert = CFDataCreate(kCFAllocatorDefault,
536 sqlite3_column_blob(copyAllStmt, 0),
537 sqlite3_column_bytes(copyAllStmt, 0)), errOut);
538 require(xmlData = CFDataCreate(NULL,
539 sqlite3_column_blob(copyAllStmt, 1),
540 sqlite3_column_bytes(copyAllStmt, 1)), errOut);
541 require(trustSettings = CFPropertyListCreateWithData(NULL,
542 xmlData,
543 kCFPropertyListImmutable,
544 NULL, error), errOut);
545 const void *pair[] = { cert , trustSettings };
546 require(certSettingsPair = CFArrayCreate(NULL, pair, 2, &kCFTypeArrayCallBacks), errOut);
547 CFArrayAppendValue(CertsAndSettings, certSettingsPair);
548
549 CFReleaseNull(cert);
550 CFReleaseNull(xmlData);
551 CFReleaseNull(trustSettings);
552 CFReleaseNull(certSettingsPair);
553 } else {
554 require_action(s3e == SQLITE_DONE, errOut, ok = SecDbErrorWithStmt(s3e, copyAllStmt, error, CFSTR("sqlite3_step failed")));
555 break;
556 }
557 }
558 goto ok;
559
560 errOut:
561 CFReleaseNull(cert);
562 CFReleaseNull(xmlData);
563 CFReleaseNull(trustSettings);
564 CFReleaseNull(certSettingsPair);
565 ok:
566 if (copyAllStmt) {
567 verify_noerr(sqlite3_finalize(copyAllStmt));
568 }
569 if (CertsAndSettings) {
570 *trustStoreContents = CertsAndSettings;
571 }
572 });
573 errOutNotLocked:
574 return ok;
575 }