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