]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecTrustStoreServer.c
Security-57337.50.23.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
69 #define kSecTrustStoreName CFSTR("TrustStore")
70 #define kSecTrustStoreDbExtension CFSTR("sqlite3")
71
72 #define kTrustStoreFileName CFSTR("TrustStore.sqlite3")
73
74
75 struct __SecTrustStore {
76 dispatch_queue_t queue;
77 sqlite3 *s3h;
78 sqlite3_stmt *copyParents;
79 sqlite3_stmt *contains;
80 bool readOnly;
81 };
82
83 static int sec_create_path(const char *path)
84 {
85 char pathbuf[PATH_MAX];
86 size_t pos, len = strlen(path);
87 if (len == 0 || len > PATH_MAX)
88 return SQLITE_CANTOPEN;
89 memcpy(pathbuf, path, len);
90 for (pos = len-1; pos > 0; --pos)
91 {
92 /* Search backwards for trailing '/'. */
93 if (pathbuf[pos] == '/')
94 {
95 pathbuf[pos] = '\0';
96 /* Attempt to create parent directories of the database. */
97 if (!mkdir(pathbuf, 0777))
98 break;
99 else
100 {
101 int err = errno;
102 if (err == EEXIST)
103 return 0;
104 if (err == ENOTDIR)
105 return SQLITE_CANTOPEN;
106 if (err == EROFS)
107 return SQLITE_READONLY;
108 if (err == EACCES)
109 return SQLITE_PERM;
110 if (err == ENOSPC || err == EDQUOT)
111 return SQLITE_FULL;
112 if (err == EIO)
113 return SQLITE_IOERR;
114
115 /* EFAULT || ELOOP | ENAMETOOLONG || something else */
116 return SQLITE_INTERNAL;
117 }
118 }
119 }
120 return SQLITE_OK;
121 }
122
123 static int sec_sqlite3_open(const char *db_name, sqlite3 **s3h,
124 bool create_path)
125 {
126 int s3e;
127 s3e = sqlite3_open(db_name, s3h);
128 if (s3e == SQLITE_CANTOPEN && create_path) {
129 /* Make sure the path to db_name exists and is writable, then
130 try again. */
131 s3e = sec_create_path(db_name);
132 if (!s3e)
133 s3e = sqlite3_open(db_name, s3h);
134 }
135
136 return s3e;
137 }
138
139 static SecTrustStoreRef SecTrustStoreCreate(const char *db_name,
140 bool create) {
141 SecTrustStoreRef ts;
142 int s3e;
143
144 require(ts = (SecTrustStoreRef)malloc(sizeof(struct __SecTrustStore)), errOut);
145 ts->queue = dispatch_queue_create("truststore", DISPATCH_QUEUE_SERIAL);
146 require_noerr(s3e = sec_sqlite3_open(db_name, &ts->s3h, create), errOut);
147
148 s3e = sqlite3_prepare(ts->s3h, copyParentsSQL, sizeof(copyParentsSQL),
149 &ts->copyParents, NULL);
150 if (create && s3e == SQLITE_ERROR) {
151 /* sqlite3_prepare returns SQLITE_ERROR if the table we are
152 compiling this statement for doesn't exist. */
153 char *errmsg = NULL;
154 s3e = sqlite3_exec(ts->s3h,
155 "CREATE TABLE tsettings("
156 "sha1 BLOB NOT NULL DEFAULT '',"
157 "subj BLOB NOT NULL DEFAULT '',"
158 "tset BLOB,"
159 "data BLOB,"
160 "PRIMARY KEY(sha1)"
161 ");"
162 "CREATE INDEX isubj ON tsettings(subj);"
163 , NULL, NULL, &errmsg);
164 if (errmsg) {
165 secwarning("CREATE TABLE cert: %s", errmsg);
166 sqlite3_free(errmsg);
167 }
168 require_noerr(s3e, errOut);
169 s3e = sqlite3_prepare(ts->s3h, copyParentsSQL, sizeof(copyParentsSQL),
170 &ts->copyParents, NULL);
171 }
172 require_noerr(s3e, errOut);
173 require_noerr(s3e = sqlite3_prepare(ts->s3h, containsSQL, sizeof(containsSQL),
174 &ts->contains, NULL), errOut);
175
176 return ts;
177
178 errOut:
179 if (ts) {
180 sqlite3_close(ts->s3h);
181 dispatch_release_safe(ts->queue);
182 free(ts);
183 }
184
185 return NULL;
186 }
187
188 static bool SecExtractFilesystemPathForKeychainFile(CFStringRef file, UInt8 *buffer, CFIndex maxBufLen)
189 {
190 bool translated = false;
191 CFURLRef fileURL = SecCopyURLForFileInKeychainDirectory(file);
192
193 if (fileURL && CFURLGetFileSystemRepresentation(fileURL, false, buffer, maxBufLen))
194 translated = true;
195 CFReleaseSafe(fileURL);
196
197 return translated;
198 }
199
200 static void SecTrustStoreInitUser(void) {
201 const char path[MAXPATHLEN];
202
203 if (SecExtractFilesystemPathForKeychainFile(kTrustStoreFileName, (UInt8*) path, (CFIndex) sizeof(path)))
204 {
205 kSecTrustStoreUser = SecTrustStoreCreate(path, true);
206 if (kSecTrustStoreUser)
207 kSecTrustStoreUser->readOnly = false;
208 }
209 }
210
211 /* AUDIT[securityd](done):
212 domainName (ok) is a caller provided string of any length (might be 0), only
213 its cf type has been checked.
214 */
215 SecTrustStoreRef SecTrustStoreForDomainName(CFStringRef domainName, CFErrorRef *error) {
216 if (CFEqual(CFSTR("user"), domainName)) {
217 dispatch_once(&kSecTrustStoreUserOnce, ^{ SecTrustStoreInitUser(); });
218 return kSecTrustStoreUser;
219 } else {
220 SecError(errSecParam, error, CFSTR("unknown domain: %@"), domainName);
221 return NULL;
222 }
223 }
224
225 /* AUDIT[securityd](done):
226 ts (ok) might be NULL.
227 certificate (ok) is a valid SecCertificateRef.
228 trustSettingsDictOrArray (checked by CFPropertyListCreateXMLData) is either
229 NULL, a dictionary or an array, but its contents have not been checked.
230 */
231 bool _SecTrustStoreSetTrustSettings(SecTrustStoreRef ts,
232 SecCertificateRef certificate,
233 CFTypeRef tsdoa, CFErrorRef *error) {
234 __block bool ok;
235 require_action_quiet(ts, errOutNotLocked, ok = SecError(errSecParam, error, CFSTR("truststore is NULL")));
236 require_action_quiet(!ts->readOnly, errOutNotLocked, ok = SecError(errSecReadOnly, error, CFSTR("truststore is readOnly")));
237 dispatch_sync(ts->queue, ^{
238 CFTypeRef trustSettingsDictOrArray = tsdoa;
239 sqlite3_stmt *insert = NULL, *update = NULL;
240 CFDataRef xmlData = NULL;
241 CFArrayRef array = NULL;
242
243 CFDataRef subject;
244 require_action_quiet(subject = SecCertificateGetNormalizedSubjectContent(certificate),
245 errOut, ok = SecError(errSecParam, error, CFSTR("get normalized subject failed")));
246 CFDataRef digest;
247 require_action_quiet(digest = SecCertificateGetSHA1Digest(certificate), errOut, ok = SecError(errSecParam, error, CFSTR("get sha1 digest failed")));
248
249 /* Do some basic checks on the trust settings passed in. */
250 if (trustSettingsDictOrArray == NULL) {
251 require_action_quiet(array = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks), errOut, ok = SecError(errSecAllocate, error, CFSTR("CFArrayCreate failed")));
252 trustSettingsDictOrArray = array;
253 }
254 else if(CFGetTypeID(trustSettingsDictOrArray) == CFDictionaryGetTypeID()) {
255 /* array-ize it */
256 array = CFArrayCreate(NULL, &trustSettingsDictOrArray, 1,
257 &kCFTypeArrayCallBacks);
258 trustSettingsDictOrArray = array;
259 }
260 else {
261 require_action_quiet(CFGetTypeID(trustSettingsDictOrArray) == CFArrayGetTypeID(), errOut, ok = SecError(errSecParam, error, CFSTR("trustSettingsDictOrArray neither dict nor array")));
262 }
263
264 require_action_quiet(xmlData = CFPropertyListCreateXMLData(kCFAllocatorDefault,
265 trustSettingsDictOrArray), errOut, ok = SecError(errSecParam, error, CFSTR("xml encode failed")));
266
267 int s3e = sqlite3_exec(ts->s3h, "BEGIN EXCLUSIVE TRANSACTION", NULL, NULL, NULL);
268 require_action_quiet(s3e == SQLITE_OK, errOut, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
269
270 /* Parameter order is sha1,subj,tset,data. */
271 require_noerr_action_quiet(sqlite3_prepare(ts->s3h, insertSQL, sizeof(insertSQL),
272 &insert, NULL), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
273 require_noerr_action_quiet(sqlite3_bind_blob_wrapper(insert, 1,
274 CFDataGetBytePtr(digest), CFDataGetLength(digest), SQLITE_STATIC),
275 errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
276 require_noerr_action_quiet(sqlite3_bind_blob_wrapper(insert, 2,
277 CFDataGetBytePtr(subject), CFDataGetLength(subject),
278 SQLITE_STATIC), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
279 require_noerr_action_quiet(sqlite3_bind_blob_wrapper(insert, 3,
280 CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData),
281 SQLITE_STATIC), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
282 require_noerr_action_quiet(sqlite3_bind_blob_wrapper(insert, 4,
283 SecCertificateGetBytePtr(certificate),
284 SecCertificateGetLength(certificate), SQLITE_STATIC), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
285 s3e = sqlite3_step(insert);
286 if (s3e == SQLITE_DONE) {
287 /* Great the insert worked. */
288 ok = true;
289 } else if (s3e == SQLITE_ERROR) {
290 /* Try update. */
291 require_noerr_action_quiet(s3e = sqlite3_prepare(ts->s3h, updateSQL, sizeof(updateSQL),
292 &update, NULL), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
293 require_noerr_action_quiet(s3e = sqlite3_bind_blob_wrapper(update, 1,
294 CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData),
295 SQLITE_STATIC), errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
296 require_noerr_action_quiet(s3e = sqlite3_bind_blob_wrapper(update, 2,
297 CFDataGetBytePtr(digest), CFDataGetLength(digest), SQLITE_STATIC),
298 errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
299 s3e = sqlite3_step(update);
300 require_action_quiet(s3e == SQLITE_DONE, errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
301 s3e = SQLITE_OK;
302 ok = true;
303 } else {
304 require_noerr_action_quiet(s3e, errOutSql, ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e));
305 ok = true;
306 }
307
308 errOutSql:
309 if (insert)
310 s3e = sqlite3_finalize(insert);
311 if (update)
312 s3e = sqlite3_finalize(update);
313
314 if (ok && s3e == SQLITE_OK)
315 s3e = sqlite3_exec(ts->s3h, "COMMIT TRANSACTION", NULL, NULL, NULL);
316
317 if (!ok || s3e != SQLITE_OK) {
318 sqlite3_exec(ts->s3h, "ROLLBACK TRANSACTION", NULL, NULL, NULL);
319 if (ok) {
320 ok = SecError(errSecInternal, error, CFSTR("sqlite3 error: %d"), s3e);
321 }
322 }
323
324 errOut:
325 CFReleaseSafe(xmlData);
326 CFReleaseSafe(array);
327 });
328 errOutNotLocked:
329 return ok;
330 }
331
332 /* AUDIT[securityd](done):
333 ts (ok) might be NULL.
334 digest (ok) is a data of any length (might be 0).
335 */
336 bool SecTrustStoreRemoveCertificateWithDigest(SecTrustStoreRef ts,
337 CFDataRef digest, CFErrorRef *error) {
338 require_quiet(ts, errOutNotLocked);
339 require(!ts->readOnly, errOutNotLocked);
340 dispatch_sync(ts->queue, ^{
341 sqlite3_stmt *deleteStmt = NULL;
342 require_noerr(sqlite3_prepare(ts->s3h, deleteSQL, sizeof(deleteSQL),
343 &deleteStmt, NULL), errOut);
344 require_noerr(sqlite3_bind_blob_wrapper(deleteStmt, 1,
345 CFDataGetBytePtr(digest), CFDataGetLength(digest), SQLITE_STATIC),
346 errOut);
347 sqlite3_step(deleteStmt);
348
349 errOut:
350 if (deleteStmt) {
351 verify_noerr(sqlite3_finalize(deleteStmt));
352 }
353 });
354 errOutNotLocked:
355 return true;
356 }
357
358 bool _SecTrustStoreRemoveAll(SecTrustStoreRef ts, CFErrorRef *error)
359 {
360 __block bool removed_all = false;
361 require(ts, errOutNotLocked);
362 require(!ts->readOnly, errOutNotLocked);
363 dispatch_sync(ts->queue, ^{
364 if (SQLITE_OK == sqlite3_exec(ts->s3h, deleteAllSQL, NULL, NULL, NULL))
365 removed_all = true;
366
367 /* prepared statements become unusable after deleteAllSQL, reset them */
368 if (ts->copyParents)
369 sqlite3_finalize(ts->copyParents);
370 sqlite3_prepare(ts->s3h, copyParentsSQL, sizeof(copyParentsSQL),
371 &ts->copyParents, NULL);
372 if (ts->contains)
373 sqlite3_finalize(ts->contains);
374 sqlite3_prepare(ts->s3h, containsSQL, sizeof(containsSQL),
375 &ts->contains, NULL);
376 });
377 errOutNotLocked:
378 return removed_all;
379 }
380
381 CFArrayRef SecTrustStoreCopyParents(SecTrustStoreRef ts,
382 SecCertificateRef certificate, CFErrorRef *error) {
383 __block CFMutableArrayRef parents = NULL;
384 require(ts, errOutNotLocked);
385 dispatch_sync(ts->queue, ^{
386 CFDataRef issuer;
387 require(issuer = SecCertificateGetNormalizedIssuerContent(certificate),
388 errOut);
389 /* @@@ Might have to use SQLITE_TRANSIENT */
390 require_noerr(sqlite3_bind_blob_wrapper(ts->copyParents, 1,
391 CFDataGetBytePtr(issuer), CFDataGetLength(issuer),
392 SQLITE_STATIC), errOut);
393
394 require(parents = CFArrayCreateMutable(kCFAllocatorDefault, 0,
395 &kCFTypeArrayCallBacks), errOut);
396 for (;;) {
397 int s3e = sqlite3_step(ts->copyParents);
398 if (s3e == SQLITE_ROW) {
399 SecCertificateRef cert;
400 require(cert = SecCertificateCreateWithBytes(kCFAllocatorDefault,
401 sqlite3_column_blob(ts->copyParents, 0),
402 sqlite3_column_bytes(ts->copyParents, 0)), errOut);
403 CFArrayAppendValue(parents, cert);
404 CFRelease(cert);
405 } else {
406 require(s3e == SQLITE_DONE, errOut);
407 break;
408 }
409 }
410
411 goto ok;
412 errOut:
413 if (parents) {
414 CFRelease(parents);
415 parents = NULL;
416 }
417 ok:
418 verify_noerr(sqlite3_reset(ts->copyParents));
419 verify_noerr(sqlite3_clear_bindings(ts->copyParents));
420 });
421 errOutNotLocked:
422 return parents;
423 }
424
425 /* AUDIT[securityd](done):
426 ts (ok) might be NULL.
427 digest (ok) is a data of any length (might be 0), only its cf type has
428 been checked.
429 */
430 bool SecTrustStoreContainsCertificateWithDigest(SecTrustStoreRef ts,
431 CFDataRef digest, bool *contains, CFErrorRef *error) {
432 if (contains)
433 *contains = false;
434 __block bool ok = true;
435 require_action_quiet(ts, errOutNotLocked, ok = SecError(errSecParam, error, CFSTR("ts is NULL")));
436 dispatch_sync(ts->queue, ^{
437 int s3e;
438 require_noerr_action(s3e = sqlite3_bind_blob_wrapper(ts->contains, 1,
439 CFDataGetBytePtr(digest), CFDataGetLength(digest), SQLITE_STATIC),
440 errOut, ok = SecDbErrorWithStmt(s3e, ts->contains, error, CFSTR("sqlite3_bind_blob failed")));
441 s3e = sqlite3_step(ts->contains);
442 if (s3e == SQLITE_ROW) {
443 if (contains)
444 *contains = true;
445 } else {
446 require_action(s3e == SQLITE_DONE, errOut, ok = SecDbErrorWithStmt(s3e, ts->contains, error, CFSTR("sqlite3_step failed")));
447 }
448
449 errOut:
450 verify_noerr(sqlite3_reset(ts->contains));
451 verify_noerr(sqlite3_clear_bindings(ts->contains));
452 });
453 errOutNotLocked:
454 return ok;
455 }