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