1/*
2 * Copyright (c) 2007-2010,2012-2014 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
59static dispatch_once_t kSecTrustStoreUserOnce;
60static SecTrustStoreRef kSecTrustStoreUser = NULL;
61
62static const char copyParentsSQL[] = "SELECT data FROM tsettings WHERE subj=?";
63static const char containsSQL[] = "SELECT tset FROM tsettings WHERE sha1=?";
64static const char insertSQL[] = "INSERT INTO tsettings(sha1,subj,tset,data)VALUES(?,?,?,?)";
65static const char updateSQL[] = "UPDATE tsettings SET tset=? WHERE sha1=?";
66static const char deleteSQL[] = "DELETE FROM tsettings WHERE sha1=?";
67static 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
75struct __SecTrustStore {
76    dispatch_queue_t queue;
77	sqlite3 *s3h;
78	sqlite3_stmt *copyParents;
79	sqlite3_stmt *contains;
80	bool readOnly;
81};
82
83static 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
123static 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
139static 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
178errOut:
179	if (ts) {
180		sqlite3_close(ts->s3h);
181        dispatch_release_safe(ts->queue);
182		free(ts);
183	}
184
185	return NULL;
186}
187
188static 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
200static 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 */
215SecTrustStoreRef 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 */
231bool _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    });
328errOutNotLocked:
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 */
336bool 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    });
354errOutNotLocked:
355	return true;
356}
357
358bool _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    });
377errOutNotLocked:
378	return removed_all;
379}
380
381CFArrayRef 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    });
421errOutNotLocked:
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*/
430bool 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    });
453errOutNotLocked:
454	return ok;
455}
456