1/* 2 * Copyright (c) 2006-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 * SecDbKeychainItem.c - CoreFoundation-based constants and functions for 26 access to Security items (certificates, keys, identities, and 27 passwords.) 28 */ 29 30#include <securityd/SecDbKeychainItem.h> 31 32#include <securityd/SecItemSchema.h> 33#include <CommonCrypto/CommonCryptor.h> 34#include <CommonCrypto/CommonCryptorSPI.h> 35#include <Security/SecBasePriv.h> 36#include <Security/SecItem.h> 37#include <Security/SecItemInternal.h> 38#include <Security/SecRandom.h> 39#include <Security/SecAccessControl.h> 40#include <Security/SecAccessControlPriv.h> 41#include <utilities/der_plist.h> 42 43#if USE_KEYSTORE 44#include <LocalAuthentication/LAPublicDefines.h> 45#include <LocalAuthentication/LAPrivateDefines.h> 46#include <coreauthd_spi.h> 47#include <libaks_acl_cf_keys.h> 48#include <securityd/spi.h> 49#endif /* USE_KEYSTORE */ 50 51pthread_key_t CURRENT_CONNECTION_KEY; 52 53// From SecItemServer, should be a acl-check block 54bool itemInAccessGroup(CFDictionaryRef item, CFArrayRef accessGroups); 55 56static keyclass_t kc_parse_keyclass(CFTypeRef value, CFErrorRef *error); 57static CFTypeRef kc_encode_keyclass(keyclass_t keyclass); 58static CFDataRef kc_copy_protection_data(SecAccessControlRef access_control); 59static CFTypeRef kc_copy_protection_from_data(CFDataRef data); 60static CFMutableDictionaryRef s3dl_item_v2_decode(CFDataRef plain, CFErrorRef *error); 61static CFMutableDictionaryRef s3dl_item_v3_decode(CFDataRef plain, CFErrorRef *error); 62#if USE_KEYSTORE 63static CFDataRef kc_copy_constraints_data(SecAccessControlRef access_control, CFDictionaryRef auth_attributes); 64static void kc_dict_from_auth_data(const SecDbClass *class, const uint8_t *der, const uint8_t *der_end, CFMutableDictionaryRef *authenticated_attributes, CFMutableDictionaryRef *acl); 65static CFDataRef kc_copy_access_groups_data(CFArrayRef access_groups, CFErrorRef *error); 66#endif 67 68/* Given plainText create and return a CFDataRef containing: 69 BULK_KEY = RandomKey() 70 version || keyclass|ACL || KeyStore_WRAP(keyclass, BULK_KEY) || 71 AES(BULK_KEY, NULL_IV, plainText || padding) 72 */ 73bool ks_encrypt_data(keybag_handle_t keybag, SecAccessControlRef access_control, CFTypeRef *cred_handle, 74 CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, CFErrorRef *error) { 75 CFMutableDataRef blob = NULL; 76 CFDataRef ac_data = NULL; 77 bool ok = true; 78 //check(keybag >= 0); 79 80 /* Precalculate output blob length. */ 81 const uint32_t bulkKeySize = 32; /* Use 256 bit AES key for bulkKey. */ 82 const uint32_t maxKeyWrapOverHead = 8 + 32; 83 uint8_t bulkKey[bulkKeySize]; 84 CFMutableDataRef bulkKeyWrapped = CFDataCreateMutable(NULL, 0); 85 CFDataSetLength(bulkKeyWrapped, bulkKeySize + maxKeyWrapOverHead); 86 uint32_t key_wrapped_size; 87 88#if USE_KEYSTORE 89 CFDataRef access_control_data = NULL; 90 CFDataRef constraint_data = NULL; 91 CFDataRef acm_context = NULL; 92#endif 93 94 /* If access_control specifies only protection and no ACL, use legacy blob format version 3, 95 which has better support for sync/backup. Otherwise, force new format v4. */ 96 const uint32_t version = SecAccessControlGetConstraints(access_control) ? 4 : 3; 97 CFDataRef plainText = NULL; 98 if (version < 4) { 99 CFMutableDictionaryRef attributes_dict = CFDictionaryCreateMutableCopy(NULL, 0, attributes); 100 if (authenticated_attributes) { 101 CFDictionaryForEach(authenticated_attributes, ^(const void *key, const void *value) { 102 CFDictionaryAddValue(attributes_dict, key, value); 103 }); 104 } 105 106 if (attributes_dict) { 107 // Drop the accc attribute for non v4 items during encode. 108 CFDictionaryRemoveValue(attributes_dict, kSecAttrAccessControl); 109 plainText = kc_plist_copy_der(attributes_dict, error); 110 CFRelease(attributes_dict); 111 } 112 } else { 113#if USE_KEYSTORE 114 if (attributes) { 115 plainText = kc_plist_copy_der(attributes, error); 116 } 117#else 118 CFMutableDictionaryRef attributes_dict = CFDictionaryCreateMutableCopy(NULL, 0, attributes); 119 if (authenticated_attributes) { 120 CFDictionaryForEach(authenticated_attributes, ^(const void *key, const void *value) { 121 CFDictionaryAddValue(attributes_dict, key, value); 122 }); 123 } 124 125 if (attributes_dict) { 126 plainText = kc_plist_copy_der(attributes_dict, error); 127 CFRelease(attributes_dict); 128 } 129#endif 130 } 131 132 if (!plainText || CFGetTypeID(plainText) != CFDataGetTypeID() 133 || access_control == 0) { 134 ok = SecError(errSecParam, error, CFSTR("ks_encrypt_data: invalid plain text")); 135 goto out; 136 } 137 138 size_t ptLen = CFDataGetLength(plainText); 139 size_t ctLen = ptLen; 140 size_t tagLen = 16; 141 keyclass_t actual_class; 142 143 if (SecRandomCopyBytes(kSecRandomDefault, bulkKeySize, bulkKey)) { 144 ok = SecError(errSecAllocate, error, CFSTR("ks_encrypt_data: SecRandomCopyBytes failed")); 145 goto out; 146 } 147 148 /* Extract keyclass from access control. */ 149 keyclass_t keyclass = kc_parse_keyclass(SecAccessControlGetProtection(access_control), error); 150 if (!keyclass) 151 goto out; 152 153#if USE_KEYSTORE 154 if (version >= 4) { 155 if (*cred_handle == NULL || isData(*cred_handle)) { 156 CFTypeRef auth_ref = VRCreateNewReferenceWithACMContext(*cred_handle, error); 157 if (!auth_ref) { 158 ok = false; 159 goto out; 160 } 161 CFReleaseSafe(*cred_handle); 162 *cred_handle = auth_ref; 163 } 164 165 access_control_data = SecAccessControlCopyData(access_control); 166 CFErrorRef authError = NULL; 167 ok = VRValidateACL(*cred_handle, access_control_data, &authError); 168 if (!ok) { 169 ok = SecCFCreateError(errSecParam, kSecErrorDomain, CFSTR("Invalid ACL"), authError, error); 170 CFReleaseSafe(authError); 171 goto out; 172 } 173 174 constraint_data = kc_copy_constraints_data(access_control, authenticated_attributes); 175 require_quiet(ok = ks_crypt_acl(kSecKsWrap, keybag, 176 keyclass, bulkKeySize, bulkKey, bulkKeyWrapped, constraint_data, NULL, NULL, error), out); 177 } 178 else { 179#endif 180 /* Encrypt bulkKey. */ 181 require_quiet(ok = ks_crypt(kSecKsWrap, keybag, 182 keyclass, bulkKeySize, bulkKey, 183 &actual_class, bulkKeyWrapped, 184 error), out); 185#if USE_KEYSTORE 186 } 187#endif 188 189 key_wrapped_size = (uint32_t)CFDataGetLength(bulkKeyWrapped); 190 UInt8 *cursor; 191 size_t blobLen = sizeof(version); 192 uint32_t prot_length; 193 194 if (version == 3) { 195 blobLen += sizeof(actual_class); 196 } else { 197 require_quiet(ac_data = kc_copy_protection_data(access_control), out); 198 prot_length = (uint32_t)CFDataGetLength(ac_data); 199 blobLen += sizeof(prot_length) + prot_length; 200 } 201 202 blobLen += sizeof(key_wrapped_size) + key_wrapped_size + ctLen + tagLen; 203 require_quiet(blob = CFDataCreateMutable(NULL, blobLen), out); 204 CFDataSetLength(blob, blobLen); 205 cursor = CFDataGetMutableBytePtr(blob); 206 207 *((uint32_t *)cursor) = version; 208 cursor += sizeof(version); 209 210 //secerror("class: %d actual class: %d", keyclass, actual_class); 211 if (version == 3) { 212 *((keyclass_t *)cursor) = actual_class; 213 cursor += sizeof(keyclass); 214 } else { 215 *((uint32_t *)cursor) = prot_length; 216 cursor += sizeof(prot_length); 217 218 CFDataGetBytes(ac_data, CFRangeMake(0, prot_length), cursor); 219 cursor += prot_length; 220 } 221 222 *((uint32_t *)cursor) = key_wrapped_size; 223 cursor += sizeof(key_wrapped_size); 224 225 memcpy(cursor, CFDataGetBytePtr(bulkKeyWrapped), key_wrapped_size); 226 cursor += key_wrapped_size; 227 228 /* Encrypt the plainText with the bulkKey. */ 229 CCCryptorStatus ccerr = CCCryptorGCM(kCCEncrypt, kCCAlgorithmAES128, 230 bulkKey, bulkKeySize, 231 NULL, 0, /* iv */ 232 NULL, 0, /* auth data */ 233 CFDataGetBytePtr(plainText), ptLen, 234 cursor, 235 cursor + ctLen, &tagLen); 236 if (ccerr) { 237 ok = SecError(errSecInternal, error, CFSTR("ks_encrypt_data: CCCryptorGCM failed: %d"), ccerr); 238 goto out; 239 } 240 if (tagLen != 16) { 241 ok = SecError(errSecInternal, error, CFSTR("ks_encrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen); 242 goto out; 243 } 244 245out: 246 memset(bulkKey, 0, sizeof(bulkKey)); 247 CFReleaseSafe(ac_data); 248 CFReleaseSafe(bulkKeyWrapped); 249 CFReleaseSafe(plainText); 250 if (!ok) { 251 CFReleaseSafe(blob); 252 } else { 253 *pBlob = blob; 254 } 255 256#if USE_KEYSTORE 257 CFReleaseSafe(access_control_data); 258 CFReleaseSafe(constraint_data); 259 CFReleaseSafe(acm_context); 260#endif 261 return ok; 262} 263 264/* Given cipherText containing: 265 version || keyclass || KeyStore_WRAP(keyclass, BULK_KEY) || 266 AES(BULK_KEY, NULL_IV, plainText || padding) 267 return the plainText. */ 268bool ks_decrypt_data(keybag_handle_t keybag, enum SecKsCryptoOp cryptoOp, SecAccessControlRef *paccess_control, CFTypeRef *cred_handle, 269 CFDataRef blob, const SecDbClass *db_class, CFArrayRef caller_access_groups, 270 CFMutableDictionaryRef *attributes_p, uint32_t *version_p, CFErrorRef *error) { 271 const uint32_t v0KeyWrapOverHead = 8; 272 CFMutableDataRef bulkKey = CFDataCreateMutable(0, 32); /* Use 256 bit AES key for bulkKey. */ 273 CFDataSetLength(bulkKey, 32); /* Use 256 bit AES key for bulkKey. */ 274 bool ok = true; 275 SecAccessControlRef access_control = NULL; 276 277 CFMutableDataRef plainText = NULL; 278 CFMutableDictionaryRef attributes = NULL; 279 uint32_t version = 0; 280 CFDataRef access_control_data = NULL; 281 282#if USE_KEYSTORE 283 CFDataRef acm_context = NULL; 284 CFMutableDictionaryRef authenticated_attributes = NULL; 285 CFDataRef caller_access_groups_data = NULL; 286 287#if TARGET_OS_IPHONE 288 check(keybag >= 0); 289#else 290 check((keybag >= 0) || (keybag == session_keybag_handle)); 291#endif 292#endif 293 294 if (!blob) { 295 ok = SecError(errSecParam, error, CFSTR("ks_decrypt_data: invalid blob")); 296 goto out; 297 } 298 299 size_t blobLen = CFDataGetLength(blob); 300 const uint8_t *cursor = CFDataGetBytePtr(blob); 301 keyclass_t keyclass; 302 uint32_t wrapped_key_size; 303 304 /* Check for underflow, ensuring we have at least one full AES block left. */ 305 if (blobLen < sizeof(version) + sizeof(keyclass) + 306 CFDataGetLength(bulkKey) + v0KeyWrapOverHead + 16) { 307 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow")); 308 goto out; 309 } 310 311 version = *((uint32_t *)cursor); 312 cursor += sizeof(version); 313 314 size_t minimum_blob_len = sizeof(version) + 16; 315 size_t ctLen = blobLen - sizeof(version); 316 317 if (version == 4) { 318 /* Deserialize SecAccessControl object from the blob. */ 319 uint32_t prot_length = *((uint32_t *)cursor); 320 cursor += sizeof(prot_length); 321 322 CFDataRef protection_data = CFDataCreate(kCFAllocatorDefault, cursor, prot_length); 323 CFTypeRef protection = kc_copy_protection_from_data(protection_data); 324 CFRelease(protection_data); 325 if (!protection) { 326 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid ACL")); 327 goto out; 328 } 329 else { 330 access_control = SecAccessControlCreate(NULL, NULL); 331 require_quiet(access_control, out); 332 ok = SecAccessControlSetProtection(access_control, protection, NULL); 333 CFRelease(protection); 334 if (!ok) { 335 SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid ACL")); 336 goto out; 337 } 338 } 339 340 cursor += prot_length; 341 342 minimum_blob_len += sizeof(prot_length) + prot_length; 343 ctLen -= sizeof(prot_length) + prot_length; 344 345 /* Get numeric value of keyclass from the access_control. */ 346 keyclass = kc_parse_keyclass(SecAccessControlGetProtection(access_control), error); 347 if (!keyclass) { 348 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid ACL")); 349 goto out; 350 } 351 } else { 352 keyclass = *((keyclass_t *)cursor); 353 //secerror("class: %d keyclass: %d", keyclass, keyclass & key_class_last); 354#if USE_KEYSTORE 355 CFTypeRef protection = kc_encode_keyclass(keyclass & key_class_last); // mask out generation 356#else 357 CFTypeRef protection = kc_encode_keyclass(keyclass); 358#endif 359 if (protection) { 360 access_control = SecAccessControlCreateWithFlags(kCFAllocatorDefault, protection, 0, error); 361 } 362 if (!access_control) { 363 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid keyclass detected")); 364 goto out; 365 } 366 cursor += sizeof(keyclass); 367 368 minimum_blob_len += sizeof(keyclass); 369 ctLen -= sizeof(keyclass); 370 } 371 372 size_t tagLen = 0; 373 switch (version) { 374 case 0: 375 wrapped_key_size = (uint32_t)CFDataGetLength(bulkKey) + v0KeyWrapOverHead; 376 break; 377 case 2: 378 case 3: 379 /* DROPTHROUGH */ 380 /* v2 and v3 have the same crypto, just different dictionary encodings. */ 381 /* Difference between v3 and v4 is already handled above, so treat v3 as v4. */ 382 case 4: 383 tagLen = 16; 384 minimum_blob_len -= 16; // Remove PKCS7 padding block requirement 385 ctLen -= tagLen; // Remove tagLen from ctLen 386 /* DROPTHROUGH */ 387 case 1: 388 wrapped_key_size = *((uint32_t *)cursor); 389 cursor += sizeof(wrapped_key_size); 390 minimum_blob_len += sizeof(wrapped_key_size); 391 ctLen -= sizeof(wrapped_key_size); 392 break; 393 default: 394 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid version %d"), version); 395 goto out; 396 } 397 398 /* Validate key wrap length against total length */ 399 require(blobLen - minimum_blob_len - tagLen >= wrapped_key_size, out); 400 ctLen -= wrapped_key_size; 401 if (version < 2 && (ctLen & 0xF) != 0) { 402 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid version")); 403 goto out; 404 } 405 406#if USE_KEYSTORE 407 if (version >= 4) { 408 /* Verify before we try to unwrap the key. */ 409 if (*cred_handle == NULL || isData(*cred_handle)) { 410 CFTypeRef auth_ref = VRCreateNewReferenceWithACMContext(*cred_handle, error); 411 if (!auth_ref) { 412 ok = false; 413 goto out; 414 } 415 CFReleaseSafe(*cred_handle); 416 *cred_handle = auth_ref; 417 } 418 419 CFMutableDictionaryRef acl = NULL; 420 kc_dict_from_auth_data(db_class, cursor, cursor + wrapped_key_size, &authenticated_attributes, &acl); 421 SecAccessControlSetConstraints(access_control, acl); 422 CFReleaseSafe(acl); 423 access_control_data = SecAccessControlCopyData(access_control); 424 425 static CFDictionaryRef hints = NULL; 426 static dispatch_once_t onceToken; 427 dispatch_once(&onceToken, ^{ 428 CFNumberRef noninteractiveKey = CFNumberCreateWithCFIndex(kCFAllocatorDefault, kLAOptionNotInteractive); 429 hints = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, noninteractiveKey, kCFBooleanTrue, NULL); 430 CFRelease(noninteractiveKey); 431 }); 432 433 CFErrorRef authError = NULL; 434 ok = VREvaluateACL(*cred_handle, access_control_data, (cryptoOp == kSecKsDelete)?kAKSKeyOpDelete:kAKSKeyOpDecrypt, hints, &authError); 435 if (!ok) { 436 if (CFEqual(CFErrorGetDomain(authError), CFSTR(kLAErrorDomain)) && 437 CFErrorGetCode(authError) == kLAErrorNotInteractive) { 438 /* UI is needed, but this is not really an error, just leave with no output data. */ 439 ok = true; 440 } else { 441 ok = SecCFCreateError(errSecAuthFailed, kSecErrorDomain, CFSTR("CoreAuthentication failed"), authError, error); 442 } 443 CFReleaseSafe(authError); 444 goto out; 445 } 446 447 acm_context = VRCopyACMContext(*cred_handle, error); 448 449 if (caller_access_groups) { 450 caller_access_groups_data = kc_copy_access_groups_data(caller_access_groups, error); 451 require_quiet(ok = (caller_access_groups_data != NULL), out); 452 } 453 require_quiet(ok = ks_crypt_acl(cryptoOp, keybag, 454 keyclass, wrapped_key_size, cursor, bulkKey, NULL, acm_context, caller_access_groups_data, error), out); 455 if (cryptoOp == kSecKsDelete) { 456 attributes = CFRetainSafe(authenticated_attributes); 457 goto out; 458 } 459 } 460 else { 461#endif 462 /* Now unwrap the bulk key using a key in the keybag. */ 463 require_quiet(ok = ks_crypt(kSecKsUnwrap, keybag, 464 keyclass, wrapped_key_size, cursor, NULL, bulkKey, error), out); 465#if USE_KEYSTORE 466 } 467#endif 468 469 cursor += wrapped_key_size; 470 471 plainText = CFDataCreateMutable(NULL, ctLen); 472 if (!plainText) { 473 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: failed to allocate data for plain text")); 474 goto out; 475 } 476 CFDataSetLength(plainText, ctLen); 477 478 /* Decrypt the cipherText with the bulkKey. */ 479 CCCryptorStatus ccerr; 480 if (tagLen) { 481 uint8_t tag[tagLen]; 482 ccerr = CCCryptorGCM(kCCDecrypt, kCCAlgorithmAES128, 483 CFDataGetBytePtr(bulkKey), CFDataGetLength(bulkKey), 484 NULL, 0, /* iv */ 485 NULL, 0, /* auth data */ 486 cursor, ctLen, 487 CFDataGetMutableBytePtr(plainText), 488 tag, &tagLen); 489 if (ccerr) { 490 /* TODO: Should this be errSecDecode once AppleKeyStore correctly 491 identifies uuid unwrap failures? */ 492 /* errSecInteractionNotAllowed; */ 493 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCryptorGCM failed: %d"), ccerr); 494 goto out; 495 } 496 if (tagLen != 16) { 497 ok = SecError(errSecInternal, error, CFSTR("ks_decrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen); 498 goto out; 499 } 500 cursor += ctLen; 501 if (memcmp(tag, cursor, tagLen)) { 502 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCryptorGCM computed tag not same as tag in blob")); 503 goto out; 504 } 505 } else { 506 size_t ptLen; 507 ccerr = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, 508 CFDataGetBytePtr(bulkKey), CFDataGetLength(bulkKey), NULL, cursor, ctLen, 509 CFDataGetMutableBytePtr(plainText), ctLen, &ptLen); 510 if (ccerr) { 511 /* TODO: Should this be errSecDecode once AppleKeyStore correctly 512 identifies uuid unwrap failures? */ 513 /* errSecInteractionNotAllowed; */ 514 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCrypt failed: %d"), ccerr); 515 goto out; 516 } 517 CFDataSetLength(plainText, ptLen); 518 } 519 520 if (version < 2) { 521 attributes = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 522 CFDictionaryAddValue(attributes, CFSTR("v_Data"), plainText); 523 } else if (version < 3) { 524 attributes = s3dl_item_v2_decode(plainText, error); 525 } else { 526 attributes = s3dl_item_v3_decode(plainText, error); 527 528#if USE_KEYSTORE 529 if (version >= 4 && authenticated_attributes != NULL) { 530 CFDictionaryForEach(authenticated_attributes, ^(const void *key, const void *value) { 531 CFDictionaryAddValue(attributes, key, value); 532 }); 533 } 534#endif 535 } 536 537 if (!attributes) { 538 secerror("decode v%d failed: %@ [item: %@]", version, error ? *error : NULL, plainText); 539 ok = false; 540 } 541out: 542 memset(CFDataGetMutableBytePtr(bulkKey), 0, CFDataGetLength(bulkKey)); 543 CFReleaseSafe(bulkKey); 544 CFReleaseSafe(plainText); 545 546 // Always copy access control data (if present), because if we fail it may indicate why. 547 if (paccess_control) 548 *paccess_control = access_control; 549 else 550 CFReleaseSafe(access_control); 551 552 if (ok) { 553 if (attributes_p) 554 *attributes_p = CFRetainSafe(attributes); 555 if (version_p) 556 *version_p = version; 557 } 558 CFReleaseSafe(attributes); 559 CFReleaseSafe(access_control_data); 560#if USE_KEYSTORE 561 CFReleaseSafe(acm_context); 562 CFReleaseSafe(authenticated_attributes); 563 CFReleaseSafe(caller_access_groups_data); 564#endif 565 return ok; 566} 567 568// TODO: Move to utilities - CFPropertyListCopyDERData() 569CFDataRef kc_plist_copy_der(CFPropertyListRef plist, CFErrorRef *error) { 570 size_t len = der_sizeof_plist(plist, error); 571 CFMutableDataRef encoded = CFDataCreateMutable(0, len); 572 CFDataSetLength(encoded, len); 573 uint8_t *der_end = CFDataGetMutableBytePtr(encoded); 574 const uint8_t *der = der_end; 575 der_end += len; 576 der_end = der_encode_plist(plist, error, der, der_end); 577 if (!der_end) { 578 CFReleaseNull(encoded); 579 } else { 580 assert(!der_end || der_end == der); 581 } 582 return encoded; 583} 584 585static CFDataRef kc_copy_digest(const struct ccdigest_info *di, size_t len, 586 const void *data, CFErrorRef *error) { 587 CFMutableDataRef digest = CFDataCreateMutable(0, di->output_size); 588 CFDataSetLength(digest, di->output_size); 589 ccdigest(di, len, data, CFDataGetMutableBytePtr(digest)); 590 return digest; 591} 592 593CFDataRef kc_copy_sha1(size_t len, const void *data, CFErrorRef *error) { 594 return kc_copy_digest(ccsha1_di(), len, data, error); 595} 596 597CFDataRef kc_copy_plist_sha1(CFPropertyListRef plist, CFErrorRef *error) { 598 CFDataRef der = kc_plist_copy_der(plist, error); 599 CFDataRef digest = NULL; 600 if (der) { 601 digest = kc_copy_sha1(CFDataGetLength(der), CFDataGetBytePtr(der), error); 602 CFRelease(der); 603 } 604 return digest; 605} 606 607static keyclass_t kc_parse_keyclass(CFTypeRef value, CFErrorRef *error) { 608 if (!isString(value)) { 609 SecError(errSecParam, error, CFSTR("accessible attribute %@ not a string"), value); 610 } else if (CFEqual(value, kSecAttrAccessibleWhenUnlocked)) { 611 return key_class_ak; 612 } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlock)) { 613 return key_class_ck; 614 } else if (CFEqual(value, kSecAttrAccessibleAlways)) { 615 return key_class_dk; 616 } else if (CFEqual(value, kSecAttrAccessibleWhenUnlockedThisDeviceOnly)) { 617 return key_class_aku; 618 } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)) { 619 return key_class_cku; 620 } else if (CFEqual(value, kSecAttrAccessibleAlwaysThisDeviceOnly)) { 621 return key_class_dku; 622 } else if (CFEqual(value, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)) { 623 return key_class_akpu; 624 } else { 625 SecError(errSecParam, error, CFSTR("accessible attribute %@ unknown"), value); 626 } 627 return 0; 628} 629 630static CFTypeRef kc_encode_keyclass(keyclass_t keyclass) { 631 switch (keyclass) { 632 case key_class_ak: 633 return kSecAttrAccessibleWhenUnlocked; 634 case key_class_ck: 635 return kSecAttrAccessibleAfterFirstUnlock; 636 case key_class_dk: 637 return kSecAttrAccessibleAlways; 638 case key_class_aku: 639 return kSecAttrAccessibleWhenUnlockedThisDeviceOnly; 640 case key_class_cku: 641 return kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; 642 case key_class_dku: 643 return kSecAttrAccessibleAlwaysThisDeviceOnly; 644 case key_class_akpu: 645 return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly; 646 default: 647 return 0; 648 } 649} 650 651#if USE_KEYSTORE 652static void kc_dict_from_auth_data(const SecDbClass *class, const uint8_t *der, const uint8_t *der_end, CFMutableDictionaryRef *authenticated_attributes, CFMutableDictionaryRef *acl) 653{ 654 CFPropertyListRef aks_data = NULL; 655 der = der_decode_plist(NULL, kCFPropertyListImmutable, &aks_data, NULL, der, der_end); 656 if(der == der_end) { 657 CFDictionaryRef authenticated_data = CFDictionaryGetValue(aks_data, kAKSKeyAuthData); 658 if (authenticated_data) { 659 *acl = CFDictionaryCreateMutableCopy(NULL, 0, authenticated_data); 660 SecDbForEachAttrWithMask(class, attr_desc, kSecDbInAuthenticatedDataFlag) { 661 CFDictionaryRemoveValue(*acl, attr_desc->name); 662 CFTypeRef value = CFDictionaryGetValue(authenticated_data, attr_desc->name); 663 if (value) { 664 if (!*authenticated_attributes) 665 *authenticated_attributes = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 666 667 CFDictionaryAddValue(*authenticated_attributes, attr_desc->name, value); 668 } 669 } 670 } 671 } 672 673 CFReleaseSafe(aks_data); 674} 675 676static CFDataRef kc_copy_constraints_data(SecAccessControlRef access_control, CFDictionaryRef auth_attributes) { 677 CFDictionaryRef constraints = SecAccessControlGetConstraints(access_control); 678 CFMutableDictionaryRef auth_data = CFDictionaryCreateMutableCopy(NULL, 0, constraints); 679 if (auth_attributes) { 680 CFDictionaryForEach(auth_attributes, ^(const void *key, const void *value) { 681 CFDictionaryAddValue(auth_data, key, value); 682 }); 683 } 684 685 CFDataRef encoded = kc_plist_copy_der(auth_data, NULL); 686 CFReleaseSafe(auth_data); 687 return encoded; 688} 689 690static CFDataRef kc_copy_access_groups_data(CFArrayRef access_groups, CFErrorRef *error) 691{ 692 size_t ag_size = der_sizeof_plist(access_groups, error); 693 CFMutableDataRef result = CFDataCreateMutable(kCFAllocatorDefault, 0); 694 CFDataSetLength(result, ag_size); 695 if (!der_encode_plist(access_groups, error, CFDataGetMutableBytePtr(result), CFDataGetMutableBytePtr(result) + ag_size)) { 696 CFRelease(result); 697 return NULL; 698 } 699 else 700 return result; 701} 702 703#endif /* USE_KEYSTORE */ 704 705static CFDataRef kc_copy_protection_data(SecAccessControlRef access_control) 706{ 707 CFTypeRef protection = SecAccessControlGetProtection(access_control); 708 size_t protection_size = der_sizeof_plist(protection, NULL); 709 CFMutableDataRef result = CFDataCreateMutable(NULL, 0); 710 CFDataSetLength(result, protection_size); 711 if (!der_encode_plist(protection, NULL, CFDataGetMutableBytePtr(result), CFDataGetMutableBytePtr(result) + protection_size)) { 712 CFRelease(result); 713 return NULL; 714 } 715 else 716 return result; 717} 718 719static CFTypeRef kc_copy_protection_from_data(CFDataRef data) 720{ 721 CFTypeRef result = NULL; 722 der_decode_plist(NULL, kCFPropertyListImmutable, &result, NULL, CFDataGetBytePtr(data), CFDataGetBytePtr(data) + CFDataGetLength(data)); 723 return result; 724} 725 726/* Return a (mutable) dictionary if plist is a dictionary, return NULL and set error otherwise. Does nothing if plist is already NULL. */ 727static CF_RETURNS_RETAINED 728CFMutableDictionaryRef dictionaryFromPlist(CFPropertyListRef plist CF_CONSUMED, CFErrorRef *error) { 729 if (plist && !isDictionary(plist)) { 730 CFStringRef typeName = CFCopyTypeIDDescription(CFGetTypeID((CFTypeRef)plist)); 731 SecError(errSecDecode, error, CFSTR("plist is a %@, expecting a dictionary"), typeName); 732 CFReleaseSafe(typeName); 733 CFReleaseNull(plist); 734 } 735 return (CFMutableDictionaryRef)plist; 736} 737 738static CF_RETURNS_RETAINED 739CFMutableDictionaryRef s3dl_item_v2_decode(CFDataRef plain, CFErrorRef *error) { 740 CFPropertyListRef item; 741 item = CFPropertyListCreateWithData(0, plain, kCFPropertyListMutableContainers, NULL, error); 742 return dictionaryFromPlist(item, error); 743} 744 745static CF_RETURNS_RETAINED 746CFMutableDictionaryRef s3dl_item_v3_decode(CFDataRef plain, CFErrorRef *error) { 747 CFPropertyListRef item = NULL; 748 const uint8_t *der = CFDataGetBytePtr(plain); 749 const uint8_t *der_end = der + CFDataGetLength(plain); 750 der = der_decode_plist(0, kCFPropertyListMutableContainers, &item, error, der, der_end); 751 if (der && der != der_end) { 752 SecCFCreateError(errSecDecode, kSecErrorDomain, CFSTR("trailing garbage at end of decrypted item"), NULL, error); 753 CFReleaseNull(item); 754 } 755 return dictionaryFromPlist(item, error); 756} 757 758bool s3dl_item_from_data(CFDataRef edata, Query *q, CFArrayRef accessGroups, 759 CFMutableDictionaryRef *item, SecAccessControlRef *access_control, CFErrorRef *error) { 760 SecAccessControlRef ac = NULL; 761 CFDataRef ac_data = NULL; 762 bool ok = false; 763 764 /* Decrypt and decode the item and check the decoded attributes against the query. */ 765 uint32_t version = 0; 766 require_quiet((ok = ks_decrypt_data(q->q_keybag, q->q_crypto_op, &ac, &q->q_use_cred_handle, edata, q->q_class, q->q_caller_access_groups, item, &version, error)), out); 767 if (version < 2) { 768 goto out; 769 } 770 771 ac_data = SecAccessControlCopyData(ac); 772 if (!*item) { 773 /* Item cannot be decrypted, because interactive authentication is needed. */ 774 if (!q->q_required_access_controls) { 775 ok = SecError(errSecInteractionNotAllowed, error, CFSTR("item would need ui for decrypting")); 776 goto out; 777 } 778 CFArrayAppendValue(q->q_required_access_controls, ac_data); 779 *item = NULL; 780 goto out; 781 } 782 783 if (*item && !itemInAccessGroup(*item, accessGroups)) { 784 secerror("items accessGroup %@ not in %@", 785 CFDictionaryGetValue(*item, kSecAttrAccessGroup), 786 accessGroups); 787 ok = SecError(errSecDecode, error, CFSTR("items accessGroup %@ not in %@"), 788 CFDictionaryGetValue(*item, kSecAttrAccessGroup), 789 accessGroups); 790 CFReleaseNull(*item); 791 } 792 793 /* AccessControl attribute does not exist in the db, so synthesize it. */ 794 if (*item) { 795 CFDictionarySetValue(*item, kSecAttrAccessControl, ac_data); 796 } 797 798 /* TODO: Validate access_control attribute. */ 799 800out: 801 if (access_control) 802 *access_control = CFRetainSafe(ac); 803 CFReleaseSafe(ac); 804 CFReleaseSafe(ac_data); 805 return ok; 806} 807 808/* Infer accessibility and access group for pre-v2 (iOS4.x and earlier) items 809 being imported from a backup. */ 810static bool SecDbItemImportMigrate(SecDbItemRef item, CFErrorRef *error) { 811 bool ok = true; 812 CFStringRef agrp = SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup); 813 CFStringRef accessible = SecDbItemGetCachedValueWithName(item, kSecAttrAccessible); 814 815 if (!isString(agrp) || !isString(accessible)) 816 return ok; 817 if (SecDbItemGetClass(item) == &genp_class && CFEqual(accessible, kSecAttrAccessibleAlways)) { 818 CFStringRef svce = SecDbItemGetCachedValueWithName(item, kSecAttrService); 819 if (!isString(svce)) return ok; 820 if (CFEqual(agrp, CFSTR("apple"))) { 821 if (CFEqual(svce, CFSTR("AirPort"))) { 822 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, error); 823 } else if (CFEqual(svce, CFSTR("com.apple.airplay.password"))) { 824 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error); 825 } else if (CFEqual(svce, CFSTR("YouTube"))) { 826 ok = (SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error) && 827 SecDbItemSetValueWithName(item, kSecAttrAccessGroup, CFSTR("com.apple.youtube.credentials"), error)); 828 } else { 829 CFStringRef desc = SecDbItemGetCachedValueWithName(item, kSecAttrDescription); 830 if (!isString(desc)) return ok; 831 if (CFEqual(desc, CFSTR("IPSec Shared Secret")) || CFEqual(desc, CFSTR("PPP Password"))) { 832 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, error); 833 } 834 } 835 } 836 } else if (SecDbItemGetClass(item) == &inet_class && CFEqual(accessible, kSecAttrAccessibleAlways)) { 837 if (CFEqual(agrp, CFSTR("PrintKitAccessGroup"))) { 838 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error); 839 } else if (CFEqual(agrp, CFSTR("apple"))) { 840 CFTypeRef ptcl = SecDbItemGetCachedValueWithName(item, kSecAttrProtocol); 841 bool is_proxy = false; 842 if (isNumber(ptcl)) { 843 SInt32 iptcl; 844 CFNumberGetValue(ptcl, kCFNumberSInt32Type, &iptcl); 845 is_proxy = (iptcl == FOUR_CHAR_CODE('htpx') || 846 iptcl == FOUR_CHAR_CODE('htsx') || 847 iptcl == FOUR_CHAR_CODE('ftpx') || 848 iptcl == FOUR_CHAR_CODE('rtsx') || 849 iptcl == FOUR_CHAR_CODE('xpth') || 850 iptcl == FOUR_CHAR_CODE('xsth') || 851 iptcl == FOUR_CHAR_CODE('xptf') || 852 iptcl == FOUR_CHAR_CODE('xstr')); 853 } else if (isString(ptcl)) { 854 is_proxy = (CFEqual(ptcl, kSecAttrProtocolHTTPProxy) || 855 CFEqual(ptcl, kSecAttrProtocolHTTPSProxy) || 856 CFEqual(ptcl, kSecAttrProtocolRTSPProxy) || 857 CFEqual(ptcl, kSecAttrProtocolFTPProxy)); 858 } 859 if (is_proxy) 860 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error); 861 } 862 } 863 return ok; 864} 865 866bool SecDbItemDecrypt(SecDbItemRef item, CFDataRef edata, CFDataRef *neededAuth, CFErrorRef *error) { 867 bool ok = true; 868 CFMutableDictionaryRef dict = NULL; 869 SecAccessControlRef access_control = NULL; 870 uint32_t version = 0; 871 872 if (!ks_decrypt_data(SecDbItemGetKeybag(item), item->cryptoOp, &access_control, &item->credHandle, edata, item->class, item->callerAccessGroups, &dict, &version, error)) { 873 // Copy access control data, which might indicate why decryption failed. 874 if (neededAuth) 875 *neededAuth = SecAccessControlCopyData(access_control); 876 ok = false; 877 goto out; 878 } 879 880 if (!dict) { 881 if (neededAuth) 882 *neededAuth = SecAccessControlCopyData(access_control); 883 else 884 require_quiet(ok = SecError(errSecInteractionNotAllowed, error, CFSTR("auth needed, but caller does not provide it")), out); 885 } else { 886 if (neededAuth) 887 *neededAuth = NULL; 888 if (version < 2) { 889 /* Old V4 style keychain backup being imported. */ 890 ok = SecDbItemSetValueWithName(item, CFSTR("v_Data"), CFDictionaryGetValue(dict, CFSTR("v_Data")), error) && 891 SecDbItemImportMigrate(item, error); 892 } else { 893 ok = dict && SecDbItemSetValues(item, dict, error); 894 } 895 } 896 897 SecAccessControlRef my_access_control = SecDbItemCopyAccessControl(item, error); 898 if (!my_access_control) { 899 ok = false; 900 goto out; 901 } 902 903 /* Make sure that the protection of ACL in the dictionary (read from DB) matched what we got 904 back from decoding the data blob. */ 905 if (!CFEqual(SecAccessControlGetProtection(my_access_control), SecAccessControlGetProtection(access_control))) { 906 ok = SecError(errSecDecode, error, CFSTR("ACL protection doesn't match the one in blob (%@ : %@)"), 907 SecAccessControlGetProtection(my_access_control), 908 SecAccessControlGetProtection(access_control)); 909 } 910 CFRelease(my_access_control); 911 912 // Update real protection used for decrypting in the item. 913 ok = ok && SecDbItemSetAccessControl(item, access_control, error); 914 915out: 916 CFReleaseSafe(dict); 917 CFReleaseSafe(access_control); 918 return ok; 919} 920 921/* Automagically make a item syncable, based on various attributes. */ 922bool SecDbItemInferSyncable(SecDbItemRef item, CFErrorRef *error) 923{ 924 CFStringRef agrp = SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup); 925 926 if (!isString(agrp)) 927 return true; 928 929 if (CFEqual(agrp, CFSTR("com.apple.cfnetwork")) && SecDbItemGetClass(item) == &inet_class) { 930 CFTypeRef srvr = SecDbItemGetCachedValueWithName(item, kSecAttrServer); 931 CFTypeRef ptcl = SecDbItemGetCachedValueWithName(item, kSecAttrProtocol); 932 CFTypeRef atyp = SecDbItemGetCachedValueWithName(item, kSecAttrAuthenticationType); 933 934 if (isString(srvr) && isString(ptcl) && isString(atyp)) { 935 /* This looks like a Mobile Safari Password, make syncable */ 936 secnotice("item", "Make this item syncable: %@", item); 937 return SecDbItemSetSyncable(item, true, error); 938 } 939 } 940 941 return true; 942} 943 944/* This create a SecDbItem from the item dictionnary that are exported for backups. 945 Item are stored in the backup as a dictionary containing two keys: 946 - v_Data: the encrypted data blob 947 - v_PersistentRef: a persistent Ref. 948 src_keybag is normally the backup keybag. 949 dst_keybag is normally the device keybag. 950 */ 951SecDbItemRef SecDbItemCreateWithBackupDictionary(CFAllocatorRef allocator, const SecDbClass *dbclass, CFDictionaryRef dict, keybag_handle_t src_keybag, keybag_handle_t dst_keybag, CFErrorRef *error) 952{ 953 CFDataRef edata = CFDictionaryGetValue(dict, CFSTR("v_Data")); 954 SecDbItemRef item = NULL; 955 956 if (edata) { 957 item = SecDbItemCreateWithEncryptedData(kCFAllocatorDefault, dbclass, edata, src_keybag, error); 958 if (item) 959 if (!SecDbItemSetKeybag(item, dst_keybag, error)) 960 CFReleaseNull(item); 961 } else { 962 SecError(errSecDecode, error, CFSTR("No v_Data in backup dictionary %@"), dict); 963 } 964 965 return item; 966} 967 968bool SecDbItemExtractRowIdFromBackupDictionary(SecDbItemRef item, CFDictionaryRef dict, CFErrorRef *error) { 969 CFDataRef ref = CFDictionaryGetValue(dict, CFSTR("v_PersistentRef")); 970 if (!ref) 971 return SecError(errSecDecode, error, CFSTR("No v_PersistentRef in backup dictionary %@"), dict); 972 973 CFStringRef className; 974 sqlite3_int64 rowid; 975 if (!_SecItemParsePersistentRef(ref, &className, &rowid)) 976 return SecError(errSecDecode, error, CFSTR("v_PersistentRef %@ failed to decode"), ref); 977 978 if (!CFEqual(SecDbItemGetClass(item)->name, className)) 979 return SecError(errSecDecode, error, CFSTR("v_PersistentRef has unexpected class %@"), className); 980 981 return SecDbItemSetRowId(item, rowid, error); 982} 983