2 * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * SecDbKeychainItem.c - CoreFoundation-based constants and functions for
26 access to Security items (certificates, keys, identities, and
30 #include <securityd/SecDbKeychainItem.h>
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>
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 */
53 pthread_key_t CURRENT_CONNECTION_KEY
;
55 // From SecItemServer, should be a acl-check block
56 bool itemInAccessGroup(CFDictionaryRef item
, CFArrayRef accessGroups
);
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
);
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
);
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
));
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)
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
;
102 //check(keybag >= 0);
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
;
113 CFDataRef auth_data
= NULL
;
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
;
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
);
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
);
137 plainText
= CFPropertyListCreateDERData(kCFAllocatorDefault
, attributes
, error
);
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
);
147 if (attributes_dict
) {
148 plainText
= CFPropertyListCreateDERData(kCFAllocatorDefault
, attributes_dict
, error
);
149 CFRelease(attributes_dict
);
154 if (!plainText
|| CFGetTypeID(plainText
) != CFDataGetTypeID()
155 || access_control
== 0) {
156 ok
= SecError(errSecParam
, error
, CFSTR("ks_encrypt_data: invalid plain text"));
160 size_t ptLen
= CFDataGetLength(plainText
);
161 size_t ctLen
= ptLen
;
163 keyclass_t actual_class
;
165 if (SecRandomCopyBytes(kSecRandomDefault
, bulkKeySize
, bulkKey
)) {
166 ok
= SecError(errSecAllocate
, error
, CFSTR("ks_encrypt_data: SecRandomCopyBytes failed"));
170 /* Extract keyclass from access control. */
171 keyclass_t keyclass
= kc_parse_keyclass(SecAccessControlGetProtection(access_control
), error
);
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
);
182 /* Encrypt bulkKey. */
183 require_quiet(ok
= ks_crypt(kAKSKeyOpEncrypt
, keybag
,
184 keyclass
, bulkKeySize
, bulkKey
,
185 &actual_class
, bulkKeyWrapped
,
189 key_wrapped_size
= (uint32_t)CFDataGetLength(bulkKeyWrapped
);
191 size_t blobLen
= sizeof(version
);
192 uint32_t prot_length
;
195 blobLen
+= sizeof(actual_class
);
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
;
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
);
207 *((uint32_t *)cursor
) = version
;
208 cursor
+= sizeof(version
);
210 //secerror("class: %d actual class: %d", keyclass, actual_class);
212 *((keyclass_t
*)cursor
) = actual_class
;
213 cursor
+= sizeof(keyclass
);
215 *((uint32_t *)cursor
) = prot_length
;
216 cursor
+= sizeof(prot_length
);
218 CFDataGetBytes(ac_data
, CFRangeMake(0, prot_length
), cursor
);
219 cursor
+= prot_length
;
222 *((uint32_t *)cursor
) = key_wrapped_size
;
223 cursor
+= sizeof(key_wrapped_size
);
225 memcpy(cursor
, CFDataGetBytePtr(bulkKeyWrapped
), key_wrapped_size
);
226 cursor
+= key_wrapped_size
;
228 /* Encrypt the plainText with the bulkKey. */
229 CCCryptorStatus ccerr
= CCCryptorGCM(kCCEncrypt
, kCCAlgorithmAES128
,
230 bulkKey
, bulkKeySize
,
232 NULL
, 0, /* auth data */
233 CFDataGetBytePtr(plainText
), ptLen
,
235 cursor
+ ctLen
, &tagLen
);
237 ok
= SecError(errSecInternal
, error
, CFSTR("ks_encrypt_data: CCCryptorGCM failed: %d"), ccerr
);
241 ok
= SecError(errSecInternal
, error
, CFSTR("ks_encrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen
);
246 memset(bulkKey
, 0, sizeof(bulkKey
));
247 CFReleaseSafe(ac_data
);
248 CFReleaseSafe(bulkKeyWrapped
);
249 CFReleaseSafe(plainText
);
257 CFReleaseSafe(auth_data
);
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. */
273 SecAccessControlRef access_control
= NULL
;
275 CFMutableDataRef plainText
= NULL
;
276 CFMutableDictionaryRef attributes
= NULL
;
277 uint32_t version
= 0;
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
;
287 check((keybag
>= 0) || (keybag
== session_keybag_handle
));
292 ok
= SecError(errSecParam
, error
, CFSTR("ks_decrypt_data: invalid blob"));
296 size_t blobLen
= CFDataGetLength(blob
);
297 const uint8_t *cursor
= CFDataGetBytePtr(blob
);
299 uint32_t wrapped_key_size
;
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"));
308 version
= *((uint32_t *)cursor
);
309 cursor
+= sizeof(version
);
311 size_t minimum_blob_len
= sizeof(version
) + 16;
312 size_t ctLen
= blobLen
- sizeof(version
);
315 /* Deserialize SecAccessControl object from the blob. */
316 uint32_t prot_length
= *((uint32_t *)cursor
);
317 cursor
+= sizeof(prot_length
);
319 CFTypeRef protection
= kc_copy_protection_from(cursor
, cursor
+ prot_length
);
321 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid ACL"));
325 access_control
= SecAccessControlCreate(NULL
, NULL
);
326 require_quiet(access_control
, out
);
327 ok
= SecAccessControlSetProtection(access_control
, protection
, NULL
);
328 CFRelease(protection
);
330 SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid ACL"));
335 cursor
+= prot_length
;
337 minimum_blob_len
+= sizeof(prot_length
) + prot_length
;
338 ctLen
-= sizeof(prot_length
) + prot_length
;
340 /* Get numeric value of keyclass from the access_control. */
341 keyclass
= kc_parse_keyclass(SecAccessControlGetProtection(access_control
), error
);
343 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid ACL"));
347 keyclass
= *((keyclass_t
*)cursor
);
348 //secerror("class: %d keyclass: %d", keyclass, keyclass & key_class_last);
350 CFTypeRef protection
= kc_encode_keyclass(keyclass
& key_class_last
); // mask out generation
352 CFTypeRef protection
= kc_encode_keyclass(keyclass
);
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")));
360 cursor
+= sizeof(keyclass
);
362 minimum_blob_len
+= sizeof(keyclass
);
363 ctLen
-= sizeof(keyclass
);
369 wrapped_key_size
= (uint32_t)CFDataGetLength(bulkKey
) + v0KeyWrapOverHead
;
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. */
380 minimum_blob_len
-= 16; // Remove PKCS7 padding block requirement
381 ctLen
-= tagLen
; // Remove tagLen from ctLen
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
);
390 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid version %d"), version
);
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"));
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
);
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
);
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
);
426 cursor
+= wrapped_key_size
;
428 plainText
= CFDataCreateMutable(NULL
, ctLen
);
430 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: failed to allocate data for plain text"));
433 CFDataSetLength(plainText
, ctLen
);
435 /* Decrypt the cipherText with the bulkKey. */
436 CCCryptorStatus ccerr
;
439 ccerr
= CCCryptorGCM(kCCDecrypt
, kCCAlgorithmAES128
,
440 CFDataGetBytePtr(bulkKey
), CFDataGetLength(bulkKey
),
442 NULL
, 0, /* auth data */
444 CFDataGetMutableBytePtr(plainText
),
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
);
454 ok
= SecError(errSecInternal
, error
, CFSTR("ks_decrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen
);
458 if (memcmp(tag
, cursor
, tagLen
)) {
459 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: CCCryptorGCM computed tag not same as tag in blob"));
464 ccerr
= CCCrypt(kCCDecrypt
, kCCAlgorithmAES128
, kCCOptionPKCS7Padding
,
465 CFDataGetBytePtr(bulkKey
), CFDataGetLength(bulkKey
), NULL
, cursor
, ctLen
,
466 CFDataGetMutableBytePtr(plainText
), ctLen
, &ptLen
);
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
);
474 CFDataSetLength(plainText
, ptLen
);
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
);
483 attributes
= s3dl_item_v3_decode(plainText
, error
);
486 require_action_quiet(attributes
, out
, { ok
= false; secerror("decode v%d failed: %@ [item: %@]", version
, error
? *error
: NULL
, plainText
); });
489 if (version
>= 4 && authenticated_attributes
!= NULL
) {
490 CFDictionaryForEach(authenticated_attributes
, ^(const void *key
, const void *value
) {
491 CFDictionaryAddValue(attributes
, key
, value
);
497 memset(CFDataGetMutableBytePtr(bulkKey
), 0, CFDataGetLength(bulkKey
));
498 CFReleaseSafe(bulkKey
);
499 CFReleaseSafe(plainText
);
501 // Always copy access control data (if present), because if we fail it may indicate why.
503 *paccess_control
= access_control
;
505 CFReleaseSafe(access_control
);
509 *attributes_p
= CFRetainSafe(attributes
);
511 *version_p
= version
;
513 CFReleaseSafe(attributes
);
515 CFReleaseSafe(authenticated_attributes
);
516 CFReleaseSafe(caller_access_groups_data
);
517 CFReleaseSafe(ed_data
);
518 if (ref_key
) aks_ref_key_free(&ref_key
);
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
)) {
528 } else if (CFEqual(value
, kSecAttrAccessibleAfterFirstUnlock
)) {
530 } else if (CFEqual(value
, kSecAttrAccessibleAlways
)) {
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
;
541 SecError(errSecParam
, error
, CFSTR("accessible attribute %@ unknown"), value
);
546 static CFTypeRef
kc_encode_keyclass(keyclass_t keyclass
) {
549 return kSecAttrAccessibleWhenUnlocked
;
551 return kSecAttrAccessibleAfterFirstUnlock
;
553 return kSecAttrAccessibleAlways
;
555 return kSecAttrAccessibleWhenUnlockedThisDeviceOnly
;
557 return kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
;
559 return kSecAttrAccessibleAlwaysThisDeviceOnly
;
561 return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
;
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
)
572 CFDictionaryRef blob_dict
= NULL
;
573 CFDataRef key_data
= NULL
;
575 aks_ref_key_t tmp_ref_key
= NULL
;
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'")));
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
);
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'")));
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
);
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
);
600 if (!*authenticated_attributes
)
601 *authenticated_attributes
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
603 CFDictionaryAddValue(*authenticated_attributes
, attr_desc
->name
, value
);
606 CFReleaseSafe(external_data_dict
);
609 /* v4 data format used wrong ACL placement, for backward compatibility we have to support both formats */
611 SecAccessControlSetConstraints(access_control
, acl
);
613 SecAccessControlSetConstraints(access_control
, CFDictionaryGetValue(acl
, kAKSKeyAcl
));
615 /* v4/v5 data format usualy does not contain kAKSKeyOpEncrypt, so add kAKSKeyOpEncrypt if is missing */
617 SecAccessConstraintRef encryptConstraint
= SecAccessControlGetConstraint(access_control
, kAKSKeyOpEncrypt
);
618 if (!encryptConstraint
)
619 SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpEncrypt
, kCFBooleanTrue
, NULL
);
626 *encrypted_data
= CFRetain(ed
);
629 *ref_key
= tmp_ref_key
;
637 aks_ref_key_free(&tmp_ref_key
);
638 CFReleaseSafe(blob_dict
);
639 CFReleaseSafe(key_data
);
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
);
654 static CFDataRef
kc_copy_access_groups_data(CFArrayRef access_groups
, CFErrorRef
*error
)
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
)) {
667 #endif /* USE_KEYSTORE */
669 static CFDataRef
kc_copy_protection_data(SecAccessControlRef access_control
)
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
)) {
683 static CFTypeRef
kc_copy_protection_from(const uint8_t *der
, const uint8_t *der_end
)
685 CFTypeRef result
= NULL
;
686 der_decode_plist(NULL
, kCFPropertyListImmutable
, &result
, NULL
, der
, der_end
);
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
);
699 return (CFMutableDictionaryRef
)plist
;
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
);
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
718 CFReleaseSafe(calendar
);
720 *pl
= CFDateCreate(allocator
, date
);
722 CFReleaseNull(*error
);
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
);
739 if (der
&& der
!= der_end
) {
740 SecCFCreateError(errSecDecode
, kSecErrorDomain
, CFSTR("trailing garbage at end of decrypted item"), NULL
, error
);
743 return dictionaryFromPlist(item
, error
);
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
;
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
);
760 ac_data
= SecAccessControlCopyData(ac
);
761 if (!itemInAccessGroup(*item
, accessGroups
)) {
762 secerror("items accessGroup %@ not in %@",
763 CFDictionaryGetValue(*item
, kSecAttrAccessGroup
),
765 ok
= SecError(errSecDecode
, error
, CFSTR("items accessGroup %@ not in %@"),
766 CFDictionaryGetValue(*item
, kSecAttrAccessGroup
),
768 CFReleaseNull(*item
);
771 /* AccessControl attribute does not exist in the db, so synthesize it. */
773 CFDictionarySetValue(*item
, kSecAttrAccessControl
, ac_data
);
775 /* TODO: Validate access_control attribute. */
779 *access_control
= CFRetainSafe(ac
);
781 CFReleaseSafe(ac_data
);
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
) {
789 CFStringRef agrp
= SecDbItemGetCachedValueWithName(item
, kSecAttrAccessGroup
);
790 CFStringRef accessible
= SecDbItemGetCachedValueWithName(item
, kSecAttrAccessible
);
792 if (!isString(agrp
) || !isString(accessible
))
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
));
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
);
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
)) {
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
));
837 ok
= SecDbItemSetValueWithName(item
, kSecAttrAccessible
, kSecAttrAccessibleWhenUnlocked
, error
);
843 bool SecDbItemDecrypt(SecDbItemRef item
, CFDataRef edata
, CFErrorRef
*error
) {
845 CFMutableDictionaryRef dict
= NULL
;
846 SecAccessControlRef access_control
= NULL
;
847 uint32_t version
= 0;
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
);
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
);
857 ok
= dict
&& SecDbItemSetValues(item
, dict
, error
);
860 SecAccessControlRef my_access_control
= SecDbItemCopyAccessControl(item
, error
);
861 if (!my_access_control
) {
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
));
873 CFRelease(my_access_control
);
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
879 ok
= SecDbItemSetAccessControl(item
, access_control
, NULL
) && ok
;
882 CFReleaseSafe(access_control
);
886 /* Automagically make a item syncable, based on various attributes. */
887 bool SecDbItemInferSyncable(SecDbItemRef item
, CFErrorRef
*error
)
889 CFStringRef agrp
= SecDbItemGetCachedValueWithName(item
, kSecAttrAccessGroup
);
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
);
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
);
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.
916 SecDbItemRef
SecDbItemCreateWithBackupDictionary(CFAllocatorRef allocator
, const SecDbClass
*dbclass
, CFDictionaryRef dict
, keybag_handle_t src_keybag
, keybag_handle_t dst_keybag
, CFErrorRef
*error
)
918 CFDataRef edata
= CFDictionaryGetValue(dict
, CFSTR("v_Data"));
919 SecDbItemRef item
= NULL
;
922 item
= SecDbItemCreateWithEncryptedData(kCFAllocatorDefault
, dbclass
, edata
, src_keybag
, error
);
924 if (!SecDbItemSetKeybag(item
, dst_keybag
, error
))
927 SecError(errSecDecode
, error
, CFSTR("No v_Data in backup dictionary %@"), dict
);
933 bool SecDbItemExtractRowIdFromBackupDictionary(SecDbItemRef item
, CFDictionaryRef dict
, CFErrorRef
*error
) {
934 CFDataRef ref
= CFDictionaryGetValue(dict
, CFSTR("v_PersistentRef"));
936 return SecError(errSecDecode
, error
, CFSTR("No v_PersistentRef in backup dictionary %@"), dict
);
938 CFStringRef className
;
940 if (!_SecItemParsePersistentRef(ref
, &className
, &rowid
))
941 return SecError(errSecDecode
, error
, CFSTR("v_PersistentRef %@ failed to decode"), ref
);
943 if (!CFEqual(SecDbItemGetClass(item
)->name
, className
))
944 return SecError(errSecDecode
, error
, CFSTR("v_PersistentRef has unexpected class %@"), className
);
946 return SecDbItemSetRowId(item
, rowid
, error
);
949 static CFDataRef
SecDbItemCopyDERWithMask(SecDbItemRef item
, CFOptionFlags mask
, CFErrorRef
*error
) {
950 CFDataRef der
= NULL
;
951 CFMutableDictionaryRef dict
= SecDbItemCopyPListWithMask(item
, mask
, error
);
953 der
= CFPropertyListCreateDERData(kCFAllocatorDefault
, dict
, error
);
959 static CFTypeRef
SecDbItemCopyDigestWithMask(SecDbItemRef item
, CFOptionFlags mask
, CFErrorRef
*error
) {
960 CFDataRef digest
= NULL
;
961 CFDataRef der
= SecDbItemCopyDERWithMask(item
, mask
, error
);
963 digest
= CFDataCopySHA1Digest(der
, error
);
969 CFTypeRef
SecDbKeychainItemCopyPrimaryKey(SecDbItemRef item
, const SecDbAttr
*attr
, CFErrorRef
*error
) {
970 return SecDbItemCopyDigestWithMask(item
, kSecDbPrimaryKeyFlag
, error
);
973 CFTypeRef
SecDbKeychainItemCopySHA1(SecDbItemRef item
, const SecDbAttr
*attr
, CFErrorRef
*error
) {
974 return SecDbItemCopyDigestWithMask(item
, kSecDbInHashFlag
, error
);
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(""));
989 CFRelease(access_control
);
991 CFReleaseSafe(attributes
);
992 CFReleaseSafe(auth_attributes
);
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);
1004 case kSecDbCreationDateAttr
:
1005 case kSecDbModificationDateAttr
:
1006 value
= CFDateCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent());
1009 SecError(errSecInternal
, error
, CFSTR("attr %@ has no default value"), attr
->name
);
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
);
1021 if (!acccData
|| !pdmnValue
)
1023 if (!CFEqual(acccData
, kCFNull
))
1024 require_quiet(accc
= SecAccessControlCreateFromData(CFGetAllocator(item
), acccData
, error
), out
);
1026 if (!CFEqual(pdmnValue
, kCFNull
)) {
1027 require_quiet(pdmn
= SecAccessControlCreate(CFGetAllocator(item
), error
), out
);
1028 require_quiet(SecAccessControlSetProtection(pdmn
, pdmnValue
, error
), out
);
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
);
1043 CFRetainAssign(result
, accc
);
1045 CFRetainAssign(result
, pdmn
);
1048 CFReleaseSafe(accc
);
1049 CFReleaseSafe(pdmn
);
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*))
1061 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Null DER"), NULL
, error
);
1066 if (NULL
== ccder_decode_tag(&tag
, der
, der_end
)) {
1067 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding"), NULL
, error
);
1073 return der_decode_null(allocator
, mutability
, (CFNullRef
*)pl
, error
, der
, der_end
);
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
);
1081 der_result
= repairBlock(allocator
, mutability
, pl
, error
, der
, der_end
);
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
);
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
);
1096 SecCFDERCreateError(kSecDERErrorUnsupportedDERType
, CFSTR("Unsupported DER Type"), NULL
, error
);
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*))
1108 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Null DER"), NULL
, error
);
1112 const uint8_t *payload_end
= 0;
1113 const uint8_t *payload
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SET
, &payload_end
, der
, der_end
);
1115 if (NULL
== payload
) {
1116 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SET"), NULL
, error
);
1121 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1124 SecCFDERCreateError(kSecDERErrorAllocationFailure
, CFSTR("Failed to create dictionary"), NULL
, error
);
1129 while (payload
!= NULL
&& payload
< payload_end
) {
1130 CFTypeRef key
= NULL
;
1131 CFTypeRef value
= NULL
;
1133 payload
= der_decode_key_value_with_repair(allocator
, mutability
, &key
, &value
, error
, payload
, payload_end
, repairBlock
);
1136 CFDictionaryAddValue(dict
, key
, value
);
1140 CFReleaseNull(value
);
1145 if (payload
== payload_end
) {
1150 CFReleaseNull(dict
);
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*))
1161 const uint8_t *payload_end
= 0;
1162 const uint8_t *payload
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &payload_end
, der
, der_end
);
1164 if (NULL
== payload
) {
1165 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SEQUENCE"), NULL
, error
);
1169 CFTypeRef keyObject
= NULL
;
1170 CFTypeRef valueObject
= NULL
;
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
);
1176 if (payload
!= NULL
) {
1178 *value
= valueObject
;
1180 CFReleaseNull(keyObject
);
1181 CFReleaseNull(valueObject
);
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*))
1193 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Null DER"), NULL
, error
);
1197 CFMutableArrayRef result
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
1199 const uint8_t *elements_end
;
1200 const uint8_t *current_element
= ccder_decode_sequence_tl(&elements_end
, der
, der_end
);
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
);
1211 if (current_element
) {
1216 CFReleaseNull(result
);
1217 return current_element
;
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*))
1227 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Null DER"), NULL
, error
);
1231 const uint8_t *payload_end
= 0;
1232 const uint8_t *payload
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_CFSET
, &payload_end
, der
, der_end
);
1234 if (NULL
== payload
) {
1235 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_CFSET"), NULL
, error
);
1239 CFMutableSetRef theSet
= (set
&& *set
) ? CFSetCreateMutableCopy(allocator
, 0, *set
)
1240 : CFSetCreateMutable(allocator
, 0, &kCFTypeSetCallBacks
);
1242 if (NULL
== theSet
) {
1243 SecCFDERCreateError(kSecDERErrorAllocationFailure
, CFSTR("Failed to create set"), NULL
, error
);
1248 while (payload
!= NULL
&& payload
< payload_end
) {
1249 CFTypeRef value
= NULL
;
1251 payload
= der_decode_plist_with_repair(allocator
, mutability
, &value
, error
, payload
, payload_end
, repairBlock
);
1254 CFSetAddValue(theSet
, value
);
1256 CFReleaseNull(value
);
1261 if (set
&& payload
== payload_end
) {
1262 CFTransferRetained(*set
, theSet
);
1265 CFReleaseNull(theSet
);