]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecDbKeychainItem.c
962fbe08c6e3ad228b6b1aa1e93b52b0b2ba9d19
[apple/security.git] / OSX / sec / securityd / SecDbKeychainItem.c
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/SecItemPriv.h>
38 #include <Security/SecItemInternal.h>
39 #include <Security/SecRandom.h>
40 #include <Security/SecAccessControl.h>
41 #include <Security/SecAccessControlPriv.h>
42 #include <utilities/der_plist.h>
43 #include <utilities/der_plist_internal.h>
44 #include <utilities/SecCFCCWrappers.h>
45
46 #if USE_KEYSTORE
47 #include <LocalAuthentication/LAPublicDefines.h>
48 #include <LocalAuthentication/LAPrivateDefines.h>
49 #include <coreauthd_spi.h>
50 #include <libaks_acl_cf_keys.h>
51 #include <securityd/spi.h>
52 #endif /* USE_KEYSTORE */
53
54 pthread_key_t CURRENT_CONNECTION_KEY;
55
56 // From SecItemServer, should be a acl-check block
57 bool itemInAccessGroup(CFDictionaryRef item, CFArrayRef accessGroups);
58
59 static keyclass_t kc_parse_keyclass(CFTypeRef value, CFErrorRef *error);
60 static CFTypeRef kc_encode_keyclass(keyclass_t keyclass);
61 static CFDataRef kc_copy_protection_data(SecAccessControlRef access_control);
62 static CFTypeRef kc_copy_protection_from(const uint8_t *der, const uint8_t *der_end);
63 static CFMutableDictionaryRef s3dl_item_v2_decode(CFDataRef plain, CFErrorRef *error);
64 static CFMutableDictionaryRef s3dl_item_v3_decode(CFDataRef plain, CFErrorRef *error);
65 #if USE_KEYSTORE
66 static CFDataRef kc_create_auth_data(SecAccessControlRef access_control, CFDictionaryRef auth_attributes);
67 static bool kc_attribs_key_encrypted_data_from_blob(keybag_handle_t keybag, const SecDbClass *class, const void *blob_data, size_t blob_data_len, SecAccessControlRef access_control, uint32_t version,
68 CFMutableDictionaryRef *authenticated_attributes, aks_ref_key_t *ref_key, CFDataRef *encrypted_data, CFErrorRef *error);
69 static CFDataRef kc_copy_access_groups_data(CFArrayRef access_groups, CFErrorRef *error);
70 #endif
71
72 static const uint8_t* der_decode_plist_with_repair(CFAllocatorRef pl, CFOptionFlags mutability, CFPropertyListRef* cf, CFErrorRef *error,
73 const uint8_t* der, const uint8_t *der_end,
74 const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error,
75 const uint8_t* der, const uint8_t *der_end));
76 static const uint8_t* der_decode_dictionary_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFDictionaryRef* dictionary, CFErrorRef *error,
77 const uint8_t* der, const uint8_t *der_end,
78 const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error,
79 const uint8_t* der, const uint8_t *der_end));
80 static const uint8_t* der_decode_key_value_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* key, CFPropertyListRef* value, CFErrorRef *error,
81 const uint8_t* der, const uint8_t *der_end,
82 const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error,
83 const uint8_t* der, const uint8_t *der_end));
84 static const uint8_t* der_decode_array_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFArrayRef* array, CFErrorRef *error,
85 const uint8_t* der, const uint8_t *der_end,
86 const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error,
87 const uint8_t* der, const uint8_t *der_end));
88 static const uint8_t* der_decode_set_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFSetRef* set, CFErrorRef *error,
89 const uint8_t* der, const uint8_t *der_end,
90 const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error,
91 const uint8_t* der, const uint8_t *der_end));
92
93 const uint32_t kUseDefaultIVMask = 1<<31;
94 const int16_t kIVSizeAESGCM = 12;
95
96 // echo "keychainblobstaticiv" | openssl dgst -sha256 | cut -c1-24 | xargs -I {} echo "0x{}" | xxd -r | xxd -p -i
97 // 0x1e, 0xa0, 0x5c, 0xa9, 0x98, 0x2e, 0x87, 0xdc, 0xf1, 0x45, 0xe8, 0x24
98
99
100 static const uint8_t gcmIV[kIVSizeAESGCM] = {
101 0x1e, 0xa0, 0x5c, 0xa9, 0x98, 0x2e, 0x87, 0xdc, 0xf1, 0x45, 0xe8, 0x24
102 };
103
104
105 /* Given plainText create and return a CFDataRef containing:
106 BULK_KEY = RandomKey()
107 version || keyclass|ACL || KeyStore_WRAP(keyclass, BULK_KEY) ||
108 AES(BULK_KEY, NULL_IV, plainText || padding)
109 */
110 bool ks_encrypt_data(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context,
111 CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, bool useDefaultIV, CFErrorRef *error) {
112 CFMutableDataRef blob = NULL;
113 CFDataRef ac_data = NULL;
114 bool ok = true;
115 //check(keybag >= 0);
116
117 /* Precalculate output blob length. */
118 const uint32_t bulkKeySize = 32; /* Use 256 bit AES key for bulkKey. */
119 const uint32_t maxKeyWrapOverHead = 8 + 32;
120 uint8_t bulkKey[bulkKeySize];
121 CFMutableDataRef bulkKeyWrapped = CFDataCreateMutable(NULL, 0);
122 CFDataSetLength(bulkKeyWrapped, bulkKeySize + maxKeyWrapOverHead);
123 uint32_t key_wrapped_size;
124 size_t ivLen = 0;
125 const uint8_t *iv = NULL;
126 const uint8_t *aad = NULL; // Additional Authenticated Data
127 ptrdiff_t aadLen = 0;
128
129 #if USE_KEYSTORE
130 CFDataRef auth_data = NULL;
131 #endif
132
133 /* If access_control specifies only protection and no ACL, use legacy blob format version 3,
134 which has better support for sync/backup. Otherwise, force new format v6 unless useDefaultIV is set. */
135 bool hasACLConstraints = SecAccessControlGetConstraints(access_control);
136 const uint32_t version = (hasACLConstraints ? 6 : 3);
137 CFDataRef plainText = NULL;
138 if (version < 4) {
139 CFMutableDictionaryRef attributes_dict = CFDictionaryCreateMutableCopy(NULL, 0, attributes);
140 if (authenticated_attributes) {
141 CFDictionaryForEach(authenticated_attributes, ^(const void *key, const void *value) {
142 CFDictionaryAddValue(attributes_dict, key, value);
143 });
144 }
145
146 if (attributes_dict) {
147 // Drop the accc attribute for non v6 items during encode.
148 CFDictionaryRemoveValue(attributes_dict, kSecAttrAccessControl);
149 plainText = CFPropertyListCreateDERData(kCFAllocatorDefault, attributes_dict, error);
150 CFRelease(attributes_dict);
151 }
152 } else {
153 #if USE_KEYSTORE
154 if (attributes) {
155 plainText = CFPropertyListCreateDERData(kCFAllocatorDefault, attributes, error);
156 }
157 #else
158 CFMutableDictionaryRef attributes_dict = CFDictionaryCreateMutableCopy(NULL, 0, attributes);
159 if (authenticated_attributes) {
160 CFDictionaryForEach(authenticated_attributes, ^(const void *key, const void *value) {
161 CFDictionaryAddValue(attributes_dict, key, value);
162 });
163 }
164
165 if (attributes_dict) {
166 plainText = CFPropertyListCreateDERData(kCFAllocatorDefault, attributes_dict, error);
167 CFRelease(attributes_dict);
168 }
169 #endif
170 }
171
172 if (!plainText || CFGetTypeID(plainText) != CFDataGetTypeID()
173 || access_control == 0) {
174 ok = SecError(errSecParam, error, CFSTR("ks_encrypt_data: invalid plain text"));
175 goto out;
176 }
177
178 size_t ptLen = CFDataGetLength(plainText);
179 size_t ctLen = ptLen;
180 size_t tagLen = 16;
181 keyclass_t actual_class;
182
183 if (SecRandomCopyBytes(kSecRandomDefault, bulkKeySize, bulkKey)) {
184 ok = SecError(errSecAllocate, error, CFSTR("ks_encrypt_data: SecRandomCopyBytes failed"));
185 goto out;
186 }
187
188 /* Extract keyclass from access control. */
189 keyclass_t keyclass = kc_parse_keyclass(SecAccessControlGetProtection(access_control), error);
190 if (!keyclass)
191 goto out;
192
193 #if USE_KEYSTORE
194 if (version >= 4) {
195 auth_data = kc_create_auth_data(access_control, authenticated_attributes);
196 require_quiet(ok = ks_encrypt_acl(keybag, keyclass, bulkKeySize, bulkKey, bulkKeyWrapped, auth_data, acm_context, access_control, error), out);
197 } else
198 #endif
199 {
200 /* Encrypt bulkKey. */
201 require_quiet(ok = ks_crypt(kAKSKeyOpEncrypt, keybag,
202 keyclass, bulkKeySize, bulkKey,
203 &actual_class, bulkKeyWrapped,
204 error), out);
205 }
206
207 key_wrapped_size = (uint32_t)CFDataGetLength(bulkKeyWrapped);
208 UInt8 *cursor;
209 size_t blobLen = sizeof(version);
210 uint32_t prot_length;
211
212 if (!hasACLConstraints) {
213 blobLen += sizeof(actual_class);
214 } else {
215 require_quiet(ac_data = kc_copy_protection_data(access_control), out);
216 prot_length = (uint32_t)CFDataGetLength(ac_data);
217 blobLen += sizeof(prot_length) + prot_length;
218 }
219
220 blobLen += sizeof(key_wrapped_size) + key_wrapped_size + ctLen + tagLen;
221 require_quiet(blob = CFDataCreateMutable(NULL, blobLen), out);
222 CFDataSetLength(blob, blobLen);
223 cursor = CFDataGetMutableBytePtr(blob);
224
225 *((uint32_t *)cursor) = useDefaultIV ? (version | kUseDefaultIVMask) : version;
226 cursor += sizeof(version);
227
228 //secerror("class: %d actual class: %d", keyclass, actual_class);
229 if (!hasACLConstraints) {
230 *((keyclass_t *)cursor) = actual_class;
231 cursor += sizeof(keyclass);
232 } else {
233 *((uint32_t *)cursor) = prot_length;
234 cursor += sizeof(prot_length);
235
236 CFDataGetBytes(ac_data, CFRangeMake(0, prot_length), cursor);
237 cursor += prot_length;
238 }
239
240 *((uint32_t *)cursor) = key_wrapped_size;
241 cursor += sizeof(key_wrapped_size);
242
243 if (useDefaultIV) {
244 iv = gcmIV;
245 ivLen = kIVSizeAESGCM;
246 // AAD is (version || ac_data || key_wrapped_size)
247 aad = CFDataGetMutableBytePtr(blob);
248 aadLen = cursor - aad;
249 }
250
251 memcpy(cursor, CFDataGetBytePtr(bulkKeyWrapped), key_wrapped_size);
252 cursor += key_wrapped_size;
253
254 /* Encrypt the plainText with the bulkKey. */
255 CCCryptorStatus ccerr = CCCryptorGCM(kCCEncrypt, kCCAlgorithmAES128,
256 bulkKey, bulkKeySize,
257 iv, ivLen, /* iv */
258 aad, aadLen, /* auth data */
259 CFDataGetBytePtr(plainText), ptLen,
260 cursor,
261 cursor + ctLen, &tagLen);
262 if (ccerr) {
263 ok = SecError(errSecInternal, error, CFSTR("ks_encrypt_data: CCCryptorGCM failed: %d"), ccerr);
264 goto out;
265 }
266 if (tagLen != 16) {
267 ok = SecError(errSecInternal, error, CFSTR("ks_encrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen);
268 goto out;
269 }
270
271 out:
272 memset(bulkKey, 0, sizeof(bulkKey));
273 CFReleaseSafe(ac_data);
274 CFReleaseSafe(bulkKeyWrapped);
275 CFReleaseSafe(plainText);
276 if (!ok) {
277 CFReleaseSafe(blob);
278 } else {
279 *pBlob = blob;
280 }
281
282 #if USE_KEYSTORE
283 CFReleaseSafe(auth_data);
284 #endif
285 return ok;
286 }
287
288 /* Given cipherText containing:
289 version || keyclass || KeyStore_WRAP(keyclass, BULK_KEY) ||
290 AES(BULK_KEY, NULL_IV, plainText || padding)
291 return the plainText. */
292 bool ks_decrypt_data(keybag_handle_t keybag, CFTypeRef cryptoOp, SecAccessControlRef *paccess_control, CFDataRef acm_context,
293 CFDataRef blob, const SecDbClass *db_class, CFArrayRef caller_access_groups,
294 CFMutableDictionaryRef *attributes_p, uint32_t *version_p, CFErrorRef *error) {
295 const uint32_t v0KeyWrapOverHead = 8;
296 CFMutableDataRef bulkKey = CFDataCreateMutable(0, 32); /* Use 256 bit AES key for bulkKey. */
297 CFDataSetLength(bulkKey, 32); /* Use 256 bit AES key for bulkKey. */
298 bool ok = true;
299 SecAccessControlRef access_control = NULL;
300
301 if (attributes_p)
302 *attributes_p = NULL;
303 if (version_p)
304 *version_p = 0;
305
306 CFMutableDataRef plainText = NULL;
307 CFMutableDictionaryRef attributes = NULL;
308 uint32_t version = 0;
309 size_t ivLen = 0;
310 const uint8_t *iv = NULL;
311 const uint8_t *aad = NULL; // Additional Authenticated Data
312 ptrdiff_t aadLen = 0;
313
314 #if USE_KEYSTORE
315 CFMutableDictionaryRef authenticated_attributes = NULL;
316 CFDataRef caller_access_groups_data = NULL;
317 CFDataRef ed_data = NULL;
318 aks_ref_key_t ref_key = NULL;
319 #if TARGET_OS_IPHONE
320 check(keybag >= 0);
321 #else
322 check((keybag >= 0) || (keybag == session_keybag_handle));
323 #endif
324 #endif
325
326 if (!blob) {
327 ok = SecError(errSecParam, error, CFSTR("ks_decrypt_data: invalid blob"));
328 goto out;
329 }
330
331 size_t blobLen = CFDataGetLength(blob);
332 const uint8_t *cursor = CFDataGetBytePtr(blob);
333 keyclass_t keyclass;
334 uint32_t wrapped_key_size;
335
336 /* Check for underflow, ensuring we have at least one full AES block left. */
337 if (blobLen < sizeof(version) + sizeof(keyclass) +
338 CFDataGetLength(bulkKey) + v0KeyWrapOverHead + 16) {
339 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow"));
340 goto out;
341 }
342
343 version = *((uint32_t *)cursor);
344 if (version & kUseDefaultIVMask) {
345 version &= ~kUseDefaultIVMask;
346 iv = gcmIV;
347 ivLen = kIVSizeAESGCM;
348 }
349
350 cursor += sizeof(version);
351
352 size_t minimum_blob_len = sizeof(version) + 16;
353 size_t ctLen = blobLen - sizeof(version);
354
355 bool hasProtectionData = (version >= 4);
356
357 if (hasProtectionData) {
358 /* Deserialize SecAccessControl object from the blob. */
359 uint32_t prot_length = *((uint32_t *)cursor);
360 cursor += sizeof(prot_length);
361
362 CFTypeRef protection = kc_copy_protection_from(cursor, cursor + prot_length);
363 if (!protection) {
364 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid ACL"));
365 goto out;
366 }
367 else {
368 access_control = SecAccessControlCreate(NULL, NULL);
369 require_quiet(access_control, out);
370 ok = SecAccessControlSetProtection(access_control, protection, NULL);
371 CFRelease(protection);
372 if (!ok) {
373 SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid ACL"));
374 goto out;
375 }
376 }
377
378 cursor += prot_length;
379
380 minimum_blob_len += sizeof(prot_length) + prot_length;
381 ctLen -= sizeof(prot_length) + prot_length;
382
383 /* Get numeric value of keyclass from the access_control. */
384 keyclass = kc_parse_keyclass(SecAccessControlGetProtection(access_control), error);
385 if (!keyclass) {
386 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid ACL"));
387 goto out;
388 }
389 } else {
390 keyclass = *((keyclass_t *)cursor);
391 //secerror("class: %d keyclass: %d", keyclass, keyclass & key_class_last);
392 #if USE_KEYSTORE
393 CFTypeRef protection = kc_encode_keyclass(keyclass & key_class_last); // mask out generation
394 #else
395 CFTypeRef protection = kc_encode_keyclass(keyclass);
396 #endif
397 require_action_quiet(protection, out, ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid keyclass detected")));
398 require_action_quiet(access_control = SecAccessControlCreate(kCFAllocatorDefault, error), out,
399 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: SecAccessControlCreate failed")));
400 require_action_quiet(SecAccessControlSetProtection(access_control, protection, error), out,
401 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: SecAccessControlSetProtection failed")));
402
403 cursor += sizeof(keyclass);
404
405 minimum_blob_len += sizeof(keyclass);
406 ctLen -= sizeof(keyclass);
407 }
408
409 size_t tagLen = 0;
410 switch (version) {
411 case 0:
412 wrapped_key_size = (uint32_t)CFDataGetLength(bulkKey) + v0KeyWrapOverHead;
413 break;
414 case 2:
415 case 3:
416 /* DROPTHROUGH */
417 /* v2 and v3 have the same crypto, just different dictionary encodings. */
418 /* Difference between v3 and v6 is already handled above, so treat v3 as v6. */
419 case 4:
420 case 5:
421 case 6:
422 tagLen = 16;
423 minimum_blob_len -= 16; // Remove PKCS7 padding block requirement
424 ctLen -= tagLen; // Remove tagLen from ctLen
425 /* DROPTHROUGH */
426 case 1:
427 wrapped_key_size = *((uint32_t *)cursor);
428 cursor += sizeof(wrapped_key_size);
429 minimum_blob_len += sizeof(wrapped_key_size);
430 ctLen -= sizeof(wrapped_key_size);
431 break;
432 default:
433 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid version %d"), version);
434 goto out;
435 }
436
437 /* Validate key wrap length against total length */
438 require(blobLen - minimum_blob_len - tagLen >= wrapped_key_size, out);
439 ctLen -= wrapped_key_size;
440 if (version < 2 && (ctLen & 0xF) != 0) {
441 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid version"));
442 goto out;
443 }
444
445 #if USE_KEYSTORE
446 if (hasProtectionData) {
447 if (caller_access_groups) {
448 caller_access_groups_data = kc_copy_access_groups_data(caller_access_groups, error);
449 require_quiet(ok = (caller_access_groups_data != NULL), out);
450 }
451
452 require_quiet(ok = kc_attribs_key_encrypted_data_from_blob(keybag, db_class, cursor, wrapped_key_size, access_control, version,
453 &authenticated_attributes, &ref_key, &ed_data, error), out);
454 if (CFEqual(cryptoOp, kAKSKeyOpDecrypt)) {
455 require_quiet(ok = ks_decrypt_acl(ref_key, ed_data, bulkKey, acm_context, caller_access_groups_data, access_control, error), out);
456 } else if (CFEqual(cryptoOp, kAKSKeyOpDelete)) {
457 require_quiet(ok = ks_delete_acl(ref_key, ed_data, acm_context, caller_access_groups_data, access_control, error), out);
458 attributes = CFRetainSafe(authenticated_attributes);
459 goto out;
460 }
461 } else
462 #endif
463 {
464 /* Now unwrap the bulk key using a key in the keybag. */
465 require_quiet(ok = ks_crypt(cryptoOp, keybag,
466 keyclass, wrapped_key_size, cursor, NULL, bulkKey, error), out);
467 }
468
469 if (iv) {
470 // AAD is (version || ac_data || key_wrapped_size)
471 aad = CFDataGetBytePtr(blob);
472 aadLen = cursor - aad;
473 }
474
475 cursor += wrapped_key_size;
476
477 plainText = CFDataCreateMutable(NULL, ctLen);
478 if (!plainText) {
479 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: failed to allocate data for plain text"));
480 goto out;
481 }
482 CFDataSetLength(plainText, ctLen);
483
484 /* Decrypt the cipherText with the bulkKey. */
485 CCCryptorStatus ccerr;
486 if (tagLen) {
487 uint8_t tag[tagLen];
488 ccerr = CCCryptorGCM(kCCDecrypt, kCCAlgorithmAES128,
489 CFDataGetBytePtr(bulkKey), CFDataGetLength(bulkKey),
490 iv, ivLen, /* iv */
491 aad, aadLen, /* auth data */
492 cursor, ctLen,
493 CFDataGetMutableBytePtr(plainText),
494 tag, &tagLen);
495 if (ccerr) {
496 /* TODO: Should this be errSecDecode once AppleKeyStore correctly
497 identifies uuid unwrap failures? */
498 /* errSecInteractionNotAllowed; */
499 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCryptorGCM failed: %d"), ccerr);
500 goto out;
501 }
502 if (tagLen != 16) {
503 ok = SecError(errSecInternal, error, CFSTR("ks_decrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen);
504 goto out;
505 }
506 cursor += ctLen;
507 if (memcmp(tag, cursor, tagLen)) {
508 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCryptorGCM computed tag not same as tag in blob"));
509 goto out;
510 }
511 } else {
512 size_t ptLen;
513 ccerr = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
514 CFDataGetBytePtr(bulkKey), CFDataGetLength(bulkKey), NULL, cursor, ctLen,
515 CFDataGetMutableBytePtr(plainText), ctLen, &ptLen);
516 if (ccerr) {
517 /* TODO: Should this be errSecDecode once AppleKeyStore correctly
518 identifies uuid unwrap failures? */
519 /* errSecInteractionNotAllowed; */
520 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCrypt failed: %d"), ccerr);
521 goto out;
522 }
523 CFDataSetLength(plainText, ptLen);
524 }
525
526 if (version < 2) {
527 attributes = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
528 CFDictionaryAddValue(attributes, CFSTR("v_Data"), plainText);
529 } else if (version < 3) {
530 attributes = s3dl_item_v2_decode(plainText, error);
531 } else {
532 attributes = s3dl_item_v3_decode(plainText, error);
533 }
534
535 require_action_quiet(attributes, out, { ok = false; secerror("decode v%d failed: %@ [item: %@]", version, error ? *error : NULL, plainText); });
536
537 #if USE_KEYSTORE
538 if (version >= 4 && authenticated_attributes != NULL) {
539 CFDictionaryForEach(authenticated_attributes, ^(const void *key, const void *value) {
540 CFDictionaryAddValue(attributes, key, value);
541 });
542 }
543 #endif
544
545 out:
546 memset(CFDataGetMutableBytePtr(bulkKey), 0, CFDataGetLength(bulkKey));
547 CFReleaseSafe(bulkKey);
548 CFReleaseSafe(plainText);
549
550 // Always copy access control data (if present), because if we fail it may indicate why.
551 if (paccess_control)
552 *paccess_control = access_control;
553 else
554 CFReleaseSafe(access_control);
555
556 if (ok) {
557 if (attributes_p)
558 *attributes_p = CFRetainSafe(attributes);
559 if (version_p)
560 *version_p = version;
561 }
562 CFReleaseSafe(attributes);
563 #if USE_KEYSTORE
564 CFReleaseSafe(authenticated_attributes);
565 CFReleaseSafe(caller_access_groups_data);
566 CFReleaseSafe(ed_data);
567 if (ref_key) aks_ref_key_free(&ref_key);
568 #endif
569 return ok;
570 }
571
572 static keyclass_t kc_parse_keyclass(CFTypeRef value, CFErrorRef *error) {
573 if (!isString(value)) {
574 SecError(errSecParam, error, CFSTR("accessible attribute %@ not a string"), value);
575 } else if (CFEqual(value, kSecAttrAccessibleWhenUnlocked)) {
576 return key_class_ak;
577 } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlock)) {
578 return key_class_ck;
579 } else if (CFEqual(value, kSecAttrAccessibleAlwaysPrivate)) {
580 return key_class_dk;
581 } else if (CFEqual(value, kSecAttrAccessibleWhenUnlockedThisDeviceOnly)) {
582 return key_class_aku;
583 } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)) {
584 return key_class_cku;
585 } else if (CFEqual(value, kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate)) {
586 return key_class_dku;
587 } else if (CFEqual(value, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)) {
588 return key_class_akpu;
589 } else {
590 SecError(errSecParam, error, CFSTR("accessible attribute %@ unknown"), value);
591 }
592 return 0;
593 }
594
595 static CFTypeRef kc_encode_keyclass(keyclass_t keyclass) {
596 switch (keyclass) {
597 case key_class_ak:
598 return kSecAttrAccessibleWhenUnlocked;
599 case key_class_ck:
600 return kSecAttrAccessibleAfterFirstUnlock;
601 case key_class_dk:
602 return kSecAttrAccessibleAlwaysPrivate;
603 case key_class_aku:
604 return kSecAttrAccessibleWhenUnlockedThisDeviceOnly;
605 case key_class_cku:
606 return kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
607 case key_class_dku:
608 return kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate;
609 case key_class_akpu:
610 return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly;
611 default:
612 return 0;
613 }
614 }
615
616 #if USE_KEYSTORE
617 static bool kc_attribs_key_encrypted_data_from_blob(keybag_handle_t keybag, const SecDbClass *class, const void *blob_data, size_t blob_data_len, SecAccessControlRef access_control, uint32_t version,
618 CFMutableDictionaryRef *authenticated_attributes, aks_ref_key_t *ref_key, CFDataRef *encrypted_data, CFErrorRef *error)
619 {
620 bool ok = false;
621 CFDictionaryRef blob_dict = NULL;
622 CFDataRef key_data = NULL;
623 CFDataRef ed = NULL;
624 aks_ref_key_t tmp_ref_key = NULL;
625
626 der_decode_plist(NULL, kCFPropertyListImmutable, (CFPropertyListRef*)&blob_dict, NULL, blob_data, blob_data + blob_data_len);
627 require_action_quiet(blob_dict, out, SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'blob data'")));
628
629 if (!ks_separate_data_and_key(blob_dict, &ed, &key_data)) {
630 ed = CFDataCreate(kCFAllocatorDefault, blob_data, blob_data_len);
631 key_data = CFRetain(ed);
632 }
633 require_action_quiet(ed, out, SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'encrypted data'")));
634 require_action_quiet(key_data, out, SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'key data'")));
635
636 CFMutableDictionaryRef acl = NULL;
637 const void *external_data = NULL;
638 size_t external_data_len = 0;
639 require_quiet(external_data = ks_ref_key_get_external_data(keybag, key_data, &tmp_ref_key, &external_data_len, error), out);
640
641 CFPropertyListRef external_data_dict = NULL;
642 der_decode_plist(NULL, kCFPropertyListImmutable, &external_data_dict, NULL, external_data, external_data + external_data_len);
643 require_action_quiet(external_data_dict, out, SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'encrypted data dictionary'")));
644 acl = CFDictionaryCreateMutableCopy(NULL, 0, external_data_dict);
645 SecDbForEachAttrWithMask(class, attr_desc, kSecDbInAuthenticatedDataFlag) {
646 CFDictionaryRemoveValue(acl, attr_desc->name);
647 CFTypeRef value = CFDictionaryGetValue(external_data_dict, attr_desc->name);
648 if (value) {
649 if (!*authenticated_attributes)
650 *authenticated_attributes = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
651
652 CFDictionaryAddValue(*authenticated_attributes, attr_desc->name, value);
653 }
654 }
655 CFReleaseSafe(external_data_dict);
656
657 if (acl) {
658 /* v4 data format used wrong ACL placement, for backward compatibility we have to support both formats */
659 if (version == 4)
660 SecAccessControlSetConstraints(access_control, acl);
661 else
662 SecAccessControlSetConstraints(access_control, CFDictionaryGetValue(acl, kAKSKeyAcl));
663
664 /* v4/v5 data format usualy does not contain kAKSKeyOpEncrypt, so add kAKSKeyOpEncrypt if is missing */
665 if (version < 6) {
666 SecAccessConstraintRef encryptConstraint = SecAccessControlGetConstraint(access_control, kAKSKeyOpEncrypt);
667 if (!encryptConstraint)
668 SecAccessControlAddConstraintForOperation(access_control, kAKSKeyOpEncrypt, kCFBooleanTrue, NULL);
669 }
670
671 CFRelease(acl);
672 }
673
674 if (encrypted_data)
675 *encrypted_data = CFRetain(ed);
676
677 if (ref_key) {
678 *ref_key = tmp_ref_key;
679 tmp_ref_key = NULL;
680 }
681
682 ok = true;
683
684 out:
685 if (tmp_ref_key)
686 aks_ref_key_free(&tmp_ref_key);
687 CFReleaseSafe(blob_dict);
688 CFReleaseSafe(key_data);
689 CFReleaseSafe(ed);
690
691 return ok;
692 }
693
694 static CFDataRef kc_create_auth_data(SecAccessControlRef access_control, CFDictionaryRef auth_attributes) {
695 CFDictionaryRef constraints = SecAccessControlGetConstraints(access_control);
696 CFMutableDictionaryRef auth_data = CFDictionaryCreateMutableCopy(NULL, 0, auth_attributes);
697 CFDictionarySetValue(auth_data, kAKSKeyAcl, constraints);
698 CFDataRef encoded = CFPropertyListCreateDERData(kCFAllocatorDefault, auth_data, NULL);
699 CFReleaseSafe(auth_data);
700 return encoded;
701 }
702
703 static CFDataRef kc_copy_access_groups_data(CFArrayRef access_groups, CFErrorRef *error)
704 {
705 size_t ag_size = der_sizeof_plist(access_groups, error);
706 CFMutableDataRef result = CFDataCreateMutable(kCFAllocatorDefault, 0);
707 CFDataSetLength(result, ag_size);
708 if (!der_encode_plist(access_groups, error, CFDataGetMutableBytePtr(result), CFDataGetMutableBytePtr(result) + ag_size)) {
709 CFRelease(result);
710 return NULL;
711 }
712 else
713 return result;
714 }
715
716 #endif /* USE_KEYSTORE */
717
718 static CFDataRef kc_copy_protection_data(SecAccessControlRef access_control)
719 {
720 CFTypeRef protection = SecAccessControlGetProtection(access_control);
721 size_t protection_size = der_sizeof_plist(protection, NULL);
722 CFMutableDataRef result = CFDataCreateMutable(NULL, 0);
723 CFDataSetLength(result, protection_size);
724 if (!der_encode_plist(protection, NULL, CFDataGetMutableBytePtr(result), CFDataGetMutableBytePtr(result) + protection_size)) {
725 CFRelease(result);
726 return NULL;
727 }
728 else
729 return result;
730 }
731
732 static CFTypeRef kc_copy_protection_from(const uint8_t *der, const uint8_t *der_end)
733 {
734 CFTypeRef result = NULL;
735 der_decode_plist(NULL, kCFPropertyListImmutable, &result, NULL, der, der_end);
736 return result;
737 }
738
739 /* Return a (mutable) dictionary if plist is a dictionary, return NULL and set error otherwise. Does nothing if plist is already NULL. */
740 static CF_RETURNS_RETAINED
741 CFMutableDictionaryRef dictionaryFromPlist(CFPropertyListRef plist CF_CONSUMED, CFErrorRef *error) {
742 if (plist && !isDictionary(plist)) {
743 CFStringRef typeName = CFCopyTypeIDDescription(CFGetTypeID((CFTypeRef)plist));
744 SecError(errSecDecode, error, CFSTR("plist is a %@, expecting a dictionary"), typeName);
745 CFReleaseSafe(typeName);
746 CFReleaseNull(plist);
747 }
748 return (CFMutableDictionaryRef)plist;
749 }
750
751 static CF_RETURNS_RETAINED
752 CFMutableDictionaryRef s3dl_item_v2_decode(CFDataRef plain, CFErrorRef *error) {
753 CFPropertyListRef item;
754 item = CFPropertyListCreateWithData(0, plain, kCFPropertyListMutableContainers, NULL, error);
755 return dictionaryFromPlist(item, error);
756 }
757
758 static const uint8_t* (^s3dl_item_v3_decode_repair_date)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*, const uint8_t*, const uint8_t*) =
759 ^const uint8_t*(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error, const uint8_t* der, const uint8_t *der_end) {
760 if (error && CFEqualSafe(CFErrorGetDomain(*error), sSecDERErrorDomain) && CFErrorGetCode(*error) == kSecDERErrorUnknownEncoding) {
761 CFAbsoluteTime date = 0;
762 CFCalendarRef calendar = CFCalendarCreateWithIdentifier(allocator, kCFGregorianCalendar);
763 CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(allocator, 0);
764 CFCalendarSetTimeZone(calendar, tz);
765 CFCalendarComposeAbsoluteTime(calendar, &date, "yMd", 2001, 3, 24); // random date for <rdar://problem/20458954> 15A143: can't recover keychain
766 CFReleaseSafe(tz);
767 CFReleaseSafe(calendar);
768
769 *pl = CFDateCreate(allocator, date);
770 if (NULL != *pl) {
771 CFReleaseNull(*error);
772 return der_end;
773 }
774 }
775 return NULL;
776 };
777
778 static CF_RETURNS_RETAINED
779 CFMutableDictionaryRef s3dl_item_v3_decode(CFDataRef plain, CFErrorRef *error) {
780 CFPropertyListRef item = NULL;
781 const uint8_t *der_beg = CFDataGetBytePtr(plain);
782 const uint8_t *der_end = der_beg + CFDataGetLength(plain);
783 const uint8_t *der = der_decode_plist(0, kCFPropertyListMutableContainers, &item, error, der_beg, der_end);
784 if (!der && error && CFEqualSafe(CFErrorGetDomain(*error), sSecDERErrorDomain) && CFErrorGetCode(*error) == kSecDERErrorUnknownEncoding) {
785 CFReleaseNull(*error);
786 der = der_decode_plist_with_repair(0, kCFPropertyListMutableContainers, &item, error, der_beg, der_end, s3dl_item_v3_decode_repair_date);
787 }
788 if (der && der != der_end) {
789 SecCFCreateError(errSecDecode, kSecErrorDomain, CFSTR("trailing garbage at end of decrypted item"), NULL, error);
790 CFReleaseNull(item);
791 }
792 return dictionaryFromPlist(item, error);
793 }
794
795 bool s3dl_item_from_data(CFDataRef edata, Query *q, CFArrayRef accessGroups,
796 CFMutableDictionaryRef *item, SecAccessControlRef *access_control, CFErrorRef *error) {
797 SecAccessControlRef ac = NULL;
798 CFDataRef ac_data = NULL;
799 bool ok = false;
800
801 /* Decrypt and decode the item and check the decoded attributes against the query. */
802 uint32_t version = 0;
803 require_quiet((ok = ks_decrypt_data(q->q_keybag, kAKSKeyOpDecrypt, &ac, q->q_use_cred_handle, edata, q->q_class,
804 q->q_caller_access_groups, item, &version, error)), out);
805 if (version < 2) {
806 goto out;
807 }
808
809 ac_data = SecAccessControlCopyData(ac);
810 if (!itemInAccessGroup(*item, accessGroups)) {
811 secerror("items accessGroup %@ not in %@",
812 CFDictionaryGetValue(*item, kSecAttrAccessGroup),
813 accessGroups);
814 ok = SecError(errSecDecode, error, CFSTR("items accessGroup %@ not in %@"),
815 CFDictionaryGetValue(*item, kSecAttrAccessGroup),
816 accessGroups);
817 CFReleaseNull(*item);
818 }
819
820 /* AccessControl attribute does not exist in the db, so synthesize it. */
821 if (version > 3)
822 CFDictionarySetValue(*item, kSecAttrAccessControl, ac_data);
823
824 /* TODO: Validate access_control attribute. */
825
826 out:
827 if (access_control)
828 *access_control = CFRetainSafe(ac);
829 CFReleaseSafe(ac);
830 CFReleaseSafe(ac_data);
831 return ok;
832 }
833
834 /* Infer accessibility and access group for pre-v2 (iOS4.x and earlier) items
835 being imported from a backup. */
836 static bool SecDbItemImportMigrate(SecDbItemRef item, CFErrorRef *error) {
837 bool ok = true;
838 CFStringRef agrp = SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup);
839 CFStringRef accessible = SecDbItemGetCachedValueWithName(item, kSecAttrAccessible);
840
841 if (!isString(agrp) || !isString(accessible))
842 return ok;
843 if (SecDbItemGetClass(item) == &genp_class && CFEqual(accessible, kSecAttrAccessibleAlwaysPrivate)) {
844 CFStringRef svce = SecDbItemGetCachedValueWithName(item, kSecAttrService);
845 if (!isString(svce)) return ok;
846 if (CFEqual(agrp, CFSTR("apple"))) {
847 if (CFEqual(svce, CFSTR("AirPort"))) {
848 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, error);
849 } else if (CFEqual(svce, CFSTR("com.apple.airplay.password"))) {
850 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error);
851 } else if (CFEqual(svce, CFSTR("YouTube"))) {
852 ok = (SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error) &&
853 SecDbItemSetValueWithName(item, kSecAttrAccessGroup, CFSTR("com.apple.youtube.credentials"), error));
854 } else {
855 CFStringRef desc = SecDbItemGetCachedValueWithName(item, kSecAttrDescription);
856 if (!isString(desc)) return ok;
857 if (CFEqual(desc, CFSTR("IPSec Shared Secret")) || CFEqual(desc, CFSTR("PPP Password"))) {
858 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, error);
859 }
860 }
861 }
862 } else if (SecDbItemGetClass(item) == &inet_class && CFEqual(accessible, kSecAttrAccessibleAlwaysPrivate)) {
863 if (CFEqual(agrp, CFSTR("PrintKitAccessGroup"))) {
864 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error);
865 } else if (CFEqual(agrp, CFSTR("apple"))) {
866 CFTypeRef ptcl = SecDbItemGetCachedValueWithName(item, kSecAttrProtocol);
867 bool is_proxy = false;
868 if (isNumber(ptcl)) {
869 SInt32 iptcl;
870 CFNumberGetValue(ptcl, kCFNumberSInt32Type, &iptcl);
871 is_proxy = (iptcl == FOUR_CHAR_CODE('htpx') ||
872 iptcl == FOUR_CHAR_CODE('htsx') ||
873 iptcl == FOUR_CHAR_CODE('ftpx') ||
874 iptcl == FOUR_CHAR_CODE('rtsx') ||
875 iptcl == FOUR_CHAR_CODE('xpth') ||
876 iptcl == FOUR_CHAR_CODE('xsth') ||
877 iptcl == FOUR_CHAR_CODE('xptf') ||
878 iptcl == FOUR_CHAR_CODE('xstr'));
879 } else if (isString(ptcl)) {
880 is_proxy = (CFEqual(ptcl, kSecAttrProtocolHTTPProxy) ||
881 CFEqual(ptcl, kSecAttrProtocolHTTPSProxy) ||
882 CFEqual(ptcl, kSecAttrProtocolRTSPProxy) ||
883 CFEqual(ptcl, kSecAttrProtocolFTPProxy));
884 }
885 if (is_proxy)
886 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error);
887 }
888 }
889 return ok;
890 }
891
892 bool SecDbItemDecrypt(SecDbItemRef item, CFDataRef edata, CFErrorRef *error) {
893 bool ok = true;
894 CFMutableDictionaryRef dict = NULL;
895 SecAccessControlRef access_control = NULL;
896 uint32_t version = 0;
897
898 require_quiet(ok = ks_decrypt_data(SecDbItemGetKeybag(item), item->cryptoOp, &access_control, item->credHandle, edata,
899 item->class, item->callerAccessGroups, &dict, &version, error), out);
900
901 if (version < 2) {
902 /* Old V4 style keychain backup being imported. */
903 ok = SecDbItemSetValueWithName(item, CFSTR("v_Data"), CFDictionaryGetValue(dict, CFSTR("v_Data")), error) &&
904 SecDbItemImportMigrate(item, error);
905 } else {
906 ok = dict && SecDbItemSetValues(item, dict, error);
907 }
908
909 SecAccessControlRef my_access_control = SecDbItemCopyAccessControl(item, error);
910 if (!my_access_control) {
911 ok = false;
912 goto out;
913 }
914
915 /* Make sure that the protection of ACL in the dictionary (read from DB) matched what we got
916 back from decoding the data blob. */
917 if (!CFEqual(SecAccessControlGetProtection(my_access_control), SecAccessControlGetProtection(access_control))) {
918 ok = SecError(errSecDecode, error, CFSTR("ACL protection doesn't match the one in blob (%@ : %@)"),
919 SecAccessControlGetProtection(my_access_control),
920 SecAccessControlGetProtection(access_control));
921 }
922 CFRelease(my_access_control);
923
924 out:
925 // If we got protection back from ks_decrypt_data, update the appropriate attribute even if anything else
926 // (incl. actual decryption) failed. We need to access the protection type even if we are not able to actually
927 // decrypt the data.
928 ok = SecDbItemSetAccessControl(item, access_control, NULL) && ok;
929
930 CFReleaseSafe(dict);
931 CFReleaseSafe(access_control);
932 return ok;
933 }
934
935 /* Automagically make a item syncable, based on various attributes. */
936 bool SecDbItemInferSyncable(SecDbItemRef item, CFErrorRef *error)
937 {
938 CFStringRef agrp = SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup);
939
940 if (!isString(agrp))
941 return true;
942
943 if (CFEqual(agrp, CFSTR("com.apple.cfnetwork")) && SecDbItemGetClass(item) == &inet_class) {
944 CFTypeRef srvr = SecDbItemGetCachedValueWithName(item, kSecAttrServer);
945 CFTypeRef ptcl = SecDbItemGetCachedValueWithName(item, kSecAttrProtocol);
946 CFTypeRef atyp = SecDbItemGetCachedValueWithName(item, kSecAttrAuthenticationType);
947
948 if (isString(srvr) && isString(ptcl) && isString(atyp)) {
949 /* This looks like a Mobile Safari Password, make syncable */
950 secnotice("item", "Make this item syncable: %@", item);
951 return SecDbItemSetSyncable(item, true, error);
952 }
953 }
954
955 return true;
956 }
957
958 /* This create a SecDbItem from the item dictionnary that are exported for backups.
959 Item are stored in the backup as a dictionary containing two keys:
960 - v_Data: the encrypted data blob
961 - v_PersistentRef: a persistent Ref.
962 src_keybag is normally the backup keybag.
963 dst_keybag is normally the device keybag.
964 */
965 SecDbItemRef SecDbItemCreateWithBackupDictionary(CFAllocatorRef allocator, const SecDbClass *dbclass, CFDictionaryRef dict, keybag_handle_t src_keybag, keybag_handle_t dst_keybag, CFErrorRef *error)
966 {
967 CFDataRef edata = CFDictionaryGetValue(dict, CFSTR("v_Data"));
968 SecDbItemRef item = NULL;
969
970 if (edata) {
971 item = SecDbItemCreateWithEncryptedData(kCFAllocatorDefault, dbclass, edata, src_keybag, error);
972 if (item)
973 if (!SecDbItemSetKeybag(item, dst_keybag, error))
974 CFReleaseNull(item);
975 } else {
976 SecError(errSecDecode, error, CFSTR("No v_Data in backup dictionary %@"), dict);
977 }
978
979 return item;
980 }
981
982 bool SecDbItemExtractRowIdFromBackupDictionary(SecDbItemRef item, CFDictionaryRef dict, CFErrorRef *error) {
983 CFDataRef ref = CFDictionaryGetValue(dict, CFSTR("v_PersistentRef"));
984 if (!ref)
985 return SecError(errSecDecode, error, CFSTR("No v_PersistentRef in backup dictionary %@"), dict);
986
987 CFStringRef className;
988 sqlite3_int64 rowid;
989 if (!_SecItemParsePersistentRef(ref, &className, &rowid))
990 return SecError(errSecDecode, error, CFSTR("v_PersistentRef %@ failed to decode"), ref);
991
992 if (!CFEqual(SecDbItemGetClass(item)->name, className))
993 return SecError(errSecDecode, error, CFSTR("v_PersistentRef has unexpected class %@"), className);
994
995 return SecDbItemSetRowId(item, rowid, error);
996 }
997
998 static CFDataRef SecDbItemCopyDERWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) {
999 CFDataRef der = NULL;
1000 CFMutableDictionaryRef dict = SecDbItemCopyPListWithMask(item, mask, error);
1001 if (dict) {
1002 der = CFPropertyListCreateDERData(kCFAllocatorDefault, dict, error);
1003 CFRelease(dict);
1004 }
1005 return der;
1006 }
1007
1008 static CFTypeRef SecDbItemCopyDigestWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) {
1009 CFDataRef digest = NULL;
1010 CFDataRef der = SecDbItemCopyDERWithMask(item, mask, error);
1011 if (der) {
1012 digest = CFDataCopySHA1Digest(der, error);
1013 CFRelease(der);
1014 }
1015 return digest;
1016 }
1017
1018 CFTypeRef SecDbKeychainItemCopyPrimaryKey(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) {
1019 return SecDbItemCopyDigestWithMask(item, kSecDbPrimaryKeyFlag, error);
1020 }
1021
1022 CFTypeRef SecDbKeychainItemCopySHA1(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) {
1023 return SecDbItemCopyDigestWithMask(item, kSecDbInHashFlag, error);
1024 }
1025
1026 CFTypeRef SecDbKeychainItemCopyEncryptedData(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) {
1027 CFDataRef edata = NULL;
1028 CFMutableDictionaryRef attributes = SecDbItemCopyPListWithMask(item, kSecDbInCryptoDataFlag, error);
1029 CFMutableDictionaryRef auth_attributes = SecDbItemCopyPListWithMask(item, kSecDbInAuthenticatedDataFlag, error);
1030 if (attributes || auth_attributes) {
1031 SecAccessControlRef access_control = SecDbItemCopyAccessControl(item, error);
1032 if (access_control) {
1033 if (ks_encrypt_data(item->keybag, access_control, item->credHandle, attributes, auth_attributes, &edata, true, error)) {
1034 item->_edataState = kSecDbItemEncrypting;
1035 } else if (!error || !*error || CFErrorGetCode(*error) != errSecAuthNeeded || !CFEqualSafe(CFErrorGetDomain(*error), kSecErrorDomain) ) {
1036 seccritical("ks_encrypt_data (db): failed: %@", error ? *error : (CFErrorRef)CFSTR(""));
1037 }
1038 CFRelease(access_control);
1039 }
1040 CFReleaseSafe(attributes);
1041 CFReleaseSafe(auth_attributes);
1042 }
1043
1044 return edata;
1045 }
1046
1047 CFTypeRef SecDbKeychainItemCopyCurrentDate(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) {
1048 CFTypeRef value = NULL;
1049 switch (attr->kind) {
1050 case kSecDbDateAttr:
1051 value = CFDateCreate(kCFAllocatorDefault, 0.0);
1052 break;
1053 case kSecDbCreationDateAttr:
1054 case kSecDbModificationDateAttr:
1055 value = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent());
1056 break;
1057 default:
1058 SecError(errSecInternal, error, CFSTR("attr %@ has no default value"), attr->name);
1059 value = NULL;
1060 }
1061
1062 return value;
1063 }
1064
1065 SecAccessControlRef SecDbItemCopyAccessControl(SecDbItemRef item, CFErrorRef *error) {
1066 SecAccessControlRef accc = NULL, pdmn = NULL, result = NULL;
1067 CFTypeRef acccData = SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessControlAttr, error), error);
1068 CFTypeRef pdmnValue = SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessAttr, error), error);
1069
1070 if (!acccData || !pdmnValue)
1071 return NULL;
1072 if (!CFEqual(acccData, kCFNull))
1073 require_quiet(accc = SecAccessControlCreateFromData(CFGetAllocator(item), acccData, error), out);
1074
1075 if (!CFEqual(pdmnValue, kCFNull)) {
1076 require_quiet(pdmn = SecAccessControlCreate(CFGetAllocator(item), error), out);
1077 require_quiet(SecAccessControlSetProtection(pdmn, pdmnValue, error), out);
1078 }
1079
1080 if (accc && pdmn) {
1081 CFTypeRef acccProt = SecAccessControlGetProtection(accc);
1082 CFTypeRef pdmnProt = SecAccessControlGetProtection(pdmn);
1083 if (!acccProt || !pdmnProt || !CFEqual(acccProt, pdmnProt)) {
1084 secerror("SecDbItemCopyAccessControl accc %@ != pdmn %@, setting pdmn to accc value", acccProt, pdmnProt);
1085 __security_simulatecrash(CFSTR("Corrupted item on decrypt accc != pdmn"), __sec_exception_code_CorruptItem);
1086 // Setting pdmn to accc prot value.
1087 require_quiet(SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessAttr, error), acccProt, error), out);
1088 }
1089 }
1090
1091 if (accc)
1092 CFRetainAssign(result, accc);
1093 else if(pdmn)
1094 CFRetainAssign(result, pdmn);
1095
1096 out:
1097 CFReleaseSafe(accc);
1098 CFReleaseSafe(pdmn);
1099
1100 return result;
1101 }
1102
1103 static const uint8_t* der_decode_plist_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability,
1104 CFPropertyListRef* pl, CFErrorRef *error,
1105 const uint8_t* der, const uint8_t *der_end,
1106 const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*,
1107 const uint8_t*, const uint8_t*))
1108 {
1109 if (NULL == der) {
1110 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Null DER"), NULL, error);
1111 return NULL;
1112 }
1113
1114 ccder_tag tag;
1115 if (NULL == ccder_decode_tag(&tag, der, der_end)) {
1116 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding"), NULL, error);
1117 return NULL;
1118 }
1119
1120 switch (tag) {
1121 case CCDER_NULL:
1122 return der_decode_null(allocator, mutability, (CFNullRef*)pl, error, der, der_end);
1123 case CCDER_BOOLEAN:
1124 return der_decode_boolean(allocator, mutability, (CFBooleanRef*)pl, error, der, der_end);
1125 case CCDER_OCTET_STRING:
1126 return der_decode_data(allocator, mutability, (CFDataRef*)pl, error, der, der_end);
1127 case CCDER_GENERALIZED_TIME: {
1128 const uint8_t* der_result = der_decode_date(allocator, mutability, (CFDateRef*)pl, error, der, der_end);
1129 if (!der_result) {
1130 der_result = repairBlock(allocator, mutability, pl, error, der, der_end);
1131 }
1132 return der_result;
1133 }
1134 case CCDER_CONSTRUCTED_SEQUENCE:
1135 return der_decode_array_with_repair(allocator, mutability, (CFArrayRef*)pl, error, der, der_end, repairBlock);
1136 case CCDER_UTF8_STRING:
1137 return der_decode_string(allocator, mutability, (CFStringRef*)pl, error, der, der_end);
1138 case CCDER_INTEGER:
1139 return der_decode_number(allocator, mutability, (CFNumberRef*)pl, error, der, der_end);
1140 case CCDER_CONSTRUCTED_SET:
1141 return der_decode_dictionary_with_repair(allocator, mutability, (CFDictionaryRef*)pl, error, der, der_end, repairBlock);
1142 case CCDER_CONSTRUCTED_CFSET:
1143 return der_decode_set_with_repair(allocator, mutability, (CFSetRef*)pl, error, der, der_end, repairBlock);
1144 default:
1145 SecCFDERCreateError(kSecDERErrorUnsupportedDERType, CFSTR("Unsupported DER Type"), NULL, error);
1146 return NULL;
1147 }
1148 }
1149
1150 static const uint8_t* der_decode_dictionary_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability,
1151 CFDictionaryRef* dictionary, CFErrorRef *error,
1152 const uint8_t* der, const uint8_t *der_end,
1153 const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*,
1154 const uint8_t*, const uint8_t*))
1155 {
1156 if (NULL == der) {
1157 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Null DER"), NULL, error);
1158 return NULL;
1159 }
1160
1161 const uint8_t *payload_end = 0;
1162 const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SET, &payload_end, der, der_end);
1163
1164 if (NULL == payload) {
1165 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SET"), NULL, error);
1166 return NULL;
1167 }
1168
1169
1170 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1171
1172 if (NULL == dict) {
1173 SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("Failed to create dictionary"), NULL, error);
1174 payload = NULL;
1175 goto exit;
1176 }
1177
1178 while (payload != NULL && payload < payload_end) {
1179 CFTypeRef key = NULL;
1180 CFTypeRef value = NULL;
1181
1182 payload = der_decode_key_value_with_repair(allocator, mutability, &key, &value, error, payload, payload_end, repairBlock);
1183
1184 if (payload) {
1185 CFDictionaryAddValue(dict, key, value);
1186 }
1187
1188 CFReleaseNull(key);
1189 CFReleaseNull(value);
1190 }
1191
1192
1193 exit:
1194 if (payload == payload_end) {
1195 *dictionary = dict;
1196 dict = NULL;
1197 }
1198
1199 CFReleaseNull(dict);
1200
1201 return payload;
1202 }
1203
1204 static const uint8_t* der_decode_key_value_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability,
1205 CFPropertyListRef* key, CFPropertyListRef* value, CFErrorRef *error,
1206 const uint8_t* der, const uint8_t *der_end,
1207 const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*,
1208 const uint8_t*, const uint8_t*))
1209 {
1210 const uint8_t *payload_end = 0;
1211 const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &payload_end, der, der_end);
1212
1213 if (NULL == payload) {
1214 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SEQUENCE"), NULL, error);
1215 return NULL;
1216 }
1217
1218 CFTypeRef keyObject = NULL;
1219 CFTypeRef valueObject = NULL;
1220
1221
1222 payload = der_decode_plist_with_repair(allocator, mutability, &keyObject, error, payload, payload_end, repairBlock);
1223 payload = der_decode_plist_with_repair(allocator, mutability, &valueObject, error, payload, payload_end, repairBlock);
1224
1225 if (payload != NULL) {
1226 *key = keyObject;
1227 *value = valueObject;
1228 } else {
1229 CFReleaseNull(keyObject);
1230 CFReleaseNull(valueObject);
1231 }
1232 return payload;
1233 }
1234
1235 static const uint8_t* der_decode_array_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability,
1236 CFArrayRef* array, CFErrorRef *error,
1237 const uint8_t* der, const uint8_t *der_end,
1238 const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*,
1239 const uint8_t*, const uint8_t*))
1240 {
1241 if (NULL == der) {
1242 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Null DER"), NULL, error);
1243 return NULL;
1244 }
1245
1246 CFMutableArrayRef result = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
1247
1248 const uint8_t *elements_end;
1249 const uint8_t *current_element = ccder_decode_sequence_tl(&elements_end, der, der_end);
1250
1251 while (current_element != NULL && current_element < elements_end) {
1252 CFPropertyListRef element = NULL;
1253 current_element = der_decode_plist_with_repair(allocator, mutability, &element, error, current_element, elements_end, repairBlock);
1254 if (current_element) {
1255 CFArrayAppendValue(result, element);
1256 CFReleaseNull(element);
1257 }
1258 }
1259
1260 if (current_element) {
1261 *array = result;
1262 result = NULL;
1263 }
1264
1265 CFReleaseNull(result);
1266 return current_element;
1267 }
1268
1269 static const uint8_t* der_decode_set_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability,
1270 CFSetRef* set, CFErrorRef *error,
1271 const uint8_t* der, const uint8_t *der_end,
1272 const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*,
1273 const uint8_t*, const uint8_t*))
1274 {
1275 if (NULL == der) {
1276 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Null DER"), NULL, error);
1277 return NULL;
1278 }
1279
1280 const uint8_t *payload_end = 0;
1281 const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_CFSET, &payload_end, der, der_end);
1282
1283 if (NULL == payload) {
1284 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_CFSET"), NULL, error);
1285 return NULL;
1286 }
1287
1288 CFMutableSetRef theSet = (set && *set) ? CFSetCreateMutableCopy(allocator, 0, *set)
1289 : CFSetCreateMutable(allocator, 0, &kCFTypeSetCallBacks);
1290
1291 if (NULL == theSet) {
1292 SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("Failed to create set"), NULL, error);
1293 payload = NULL;
1294 goto exit;
1295 }
1296
1297 while (payload != NULL && payload < payload_end) {
1298 CFTypeRef value = NULL;
1299
1300 payload = der_decode_plist_with_repair(allocator, mutability, &value, error, payload, payload_end, repairBlock);
1301
1302 if (payload) {
1303 CFSetAddValue(theSet, value);
1304 }
1305 CFReleaseNull(value);
1306 }
1307
1308
1309 exit:
1310 if (set && payload == payload_end) {
1311 CFTransferRetained(*set, theSet);
1312 }
1313
1314 CFReleaseNull(theSet);
1315
1316 return payload;
1317 }