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/SecItemPriv.h>
38 #include <Security/SecItemInternal.h>
39 #include <Security/SecRandom.h>
40 #include <Security/SecAccessControl.h>
41 #include <Security/SecAccessControlPriv.h>
42 #include <utilities/der_plist.h>
43 #include <utilities/der_plist_internal.h>
44 #include <utilities/SecCFCCWrappers.h>
47 #include <LocalAuthentication/LAPublicDefines.h>
48 #include <LocalAuthentication/LAPrivateDefines.h>
49 #include <coreauthd_spi.h>
50 #include <libaks_acl_cf_keys.h>
51 #include <securityd/spi.h>
52 #endif /* USE_KEYSTORE */
54 pthread_key_t CURRENT_CONNECTION_KEY
;
56 // From SecItemServer, should be a acl-check block
57 bool itemInAccessGroup(CFDictionaryRef item
, CFArrayRef accessGroups
);
59 static keyclass_t
kc_parse_keyclass(CFTypeRef value
, CFErrorRef
*error
);
60 static CFTypeRef
kc_encode_keyclass(keyclass_t keyclass
);
61 static CFDataRef
kc_copy_protection_data(SecAccessControlRef access_control
);
62 static CFTypeRef
kc_copy_protection_from(const uint8_t *der
, const uint8_t *der_end
);
63 static CFMutableDictionaryRef
s3dl_item_v2_decode(CFDataRef plain
, CFErrorRef
*error
);
64 static CFMutableDictionaryRef
s3dl_item_v3_decode(CFDataRef plain
, CFErrorRef
*error
);
66 static CFDataRef
kc_create_auth_data(SecAccessControlRef access_control
, CFDictionaryRef auth_attributes
);
67 static bool kc_attribs_key_encrypted_data_from_blob(keybag_handle_t keybag
, const SecDbClass
*class, const void *blob_data
, size_t blob_data_len
, SecAccessControlRef access_control
, uint32_t version
,
68 CFMutableDictionaryRef
*authenticated_attributes
, aks_ref_key_t
*ref_key
, CFDataRef
*encrypted_data
, CFErrorRef
*error
);
69 static CFDataRef
kc_copy_access_groups_data(CFArrayRef access_groups
, CFErrorRef
*error
);
72 static const uint8_t* der_decode_plist_with_repair(CFAllocatorRef pl
, CFOptionFlags mutability
, CFPropertyListRef
* cf
, CFErrorRef
*error
,
73 const uint8_t* der
, const uint8_t *der_end
,
74 const uint8_t* (^repairBlock
)(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFPropertyListRef
* pl
, CFErrorRef
*error
,
75 const uint8_t* der
, const uint8_t *der_end
));
76 static const uint8_t* der_decode_dictionary_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFDictionaryRef
* dictionary
, CFErrorRef
*error
,
77 const uint8_t* der
, const uint8_t *der_end
,
78 const uint8_t* (^repairBlock
)(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFPropertyListRef
* pl
, CFErrorRef
*error
,
79 const uint8_t* der
, const uint8_t *der_end
));
80 static const uint8_t* der_decode_key_value_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFPropertyListRef
* key
, CFPropertyListRef
* value
, CFErrorRef
*error
,
81 const uint8_t* der
, const uint8_t *der_end
,
82 const uint8_t* (^repairBlock
)(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFPropertyListRef
* pl
, CFErrorRef
*error
,
83 const uint8_t* der
, const uint8_t *der_end
));
84 static const uint8_t* der_decode_array_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFArrayRef
* array
, CFErrorRef
*error
,
85 const uint8_t* der
, const uint8_t *der_end
,
86 const uint8_t* (^repairBlock
)(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFPropertyListRef
* pl
, CFErrorRef
*error
,
87 const uint8_t* der
, const uint8_t *der_end
));
88 static const uint8_t* der_decode_set_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFSetRef
* set
, CFErrorRef
*error
,
89 const uint8_t* der
, const uint8_t *der_end
,
90 const uint8_t* (^repairBlock
)(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFPropertyListRef
* pl
, CFErrorRef
*error
,
91 const uint8_t* der
, const uint8_t *der_end
));
93 const uint32_t kUseDefaultIVMask
= 1<<31;
94 const int16_t kIVSizeAESGCM
= 12;
96 // echo "keychainblobstaticiv" | openssl dgst -sha256 | cut -c1-24 | xargs -I {} echo "0x{}" | xxd -r | xxd -p -i
97 static const uint8_t gcmIV
[kIVSizeAESGCM
] = {
98 0x1e, 0xa0, 0x5c, 0xa9, 0x98, 0x2e, 0x87, 0xdc, 0xf1, 0x45, 0xe8, 0x24
101 /* Given plainText create and return a CFDataRef containing:
102 BULK_KEY = RandomKey()
103 version || keyclass|ACL || KeyStore_WRAP(keyclass, BULK_KEY) ||
104 AES(BULK_KEY, NULL_IV, plainText || padding)
106 bool ks_encrypt_data(keybag_handle_t keybag
, SecAccessControlRef access_control
, CFDataRef acm_context
,
107 CFDictionaryRef attributes
, CFDictionaryRef authenticated_attributes
, CFDataRef
*pBlob
, bool useDefaultIV
, CFErrorRef
*error
) {
108 CFMutableDataRef blob
= NULL
;
109 CFDataRef ac_data
= NULL
;
111 //check(keybag >= 0);
113 /* Precalculate output blob length. */
114 const uint32_t bulkKeySize
= 32; /* Use 256 bit AES key for bulkKey. */
115 const uint32_t maxKeyWrapOverHead
= 8 + 32;
116 uint8_t bulkKey
[bulkKeySize
];
117 CFMutableDataRef bulkKeyWrapped
= CFDataCreateMutable(NULL
, 0);
118 CFDataSetLength(bulkKeyWrapped
, bulkKeySize
+ maxKeyWrapOverHead
);
119 uint32_t key_wrapped_size
;
121 const uint8_t *iv
= NULL
;
122 const uint8_t *aad
= NULL
; // Additional Authenticated Data
123 ptrdiff_t aadLen
= 0;
126 CFDataRef auth_data
= NULL
;
129 /* If access_control specifies only protection and no ACL, use legacy blob format version 3,
130 which has better support for sync/backup. Otherwise, force new format v6 unless useDefaultIV is set. */
131 bool hasACLConstraints
= SecAccessControlGetConstraints(access_control
);
132 const uint32_t version
= (hasACLConstraints
? 6 : 3);
133 CFDataRef plainText
= NULL
;
135 CFMutableDictionaryRef attributes_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
136 if (authenticated_attributes
) {
137 CFDictionaryForEach(authenticated_attributes
, ^(const void *key
, const void *value
) {
138 CFDictionaryAddValue(attributes_dict
, key
, value
);
142 if (attributes_dict
) {
143 // Drop the accc attribute for non v6 items during encode.
144 CFDictionaryRemoveValue(attributes_dict
, kSecAttrAccessControl
);
145 plainText
= CFPropertyListCreateDERData(kCFAllocatorDefault
, attributes_dict
, error
);
146 CFRelease(attributes_dict
);
151 plainText
= CFPropertyListCreateDERData(kCFAllocatorDefault
, attributes
, error
);
154 CFMutableDictionaryRef attributes_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
155 if (authenticated_attributes
) {
156 CFDictionaryForEach(authenticated_attributes
, ^(const void *key
, const void *value
) {
157 CFDictionaryAddValue(attributes_dict
, key
, value
);
161 if (attributes_dict
) {
162 plainText
= CFPropertyListCreateDERData(kCFAllocatorDefault
, attributes_dict
, error
);
163 CFRelease(attributes_dict
);
168 if (!plainText
|| CFGetTypeID(plainText
) != CFDataGetTypeID()
169 || access_control
== 0) {
170 ok
= SecError(errSecParam
, error
, CFSTR("ks_encrypt_data: invalid plain text"));
174 size_t ptLen
= CFDataGetLength(plainText
);
175 size_t ctLen
= ptLen
;
177 keyclass_t actual_class
;
179 if (SecRandomCopyBytes(kSecRandomDefault
, bulkKeySize
, bulkKey
)) {
180 ok
= SecError(errSecAllocate
, error
, CFSTR("ks_encrypt_data: SecRandomCopyBytes failed"));
184 /* Extract keyclass from access control. */
185 keyclass_t keyclass
= kc_parse_keyclass(SecAccessControlGetProtection(access_control
), error
);
191 auth_data
= kc_create_auth_data(access_control
, authenticated_attributes
);
192 require_quiet(ok
= ks_encrypt_acl(keybag
, keyclass
, bulkKeySize
, bulkKey
, bulkKeyWrapped
, auth_data
, acm_context
, access_control
, error
), out
);
196 /* Encrypt bulkKey. */
197 require_quiet(ok
= ks_crypt(kAKSKeyOpEncrypt
, keybag
,
198 keyclass
, bulkKeySize
, bulkKey
,
199 &actual_class
, bulkKeyWrapped
,
203 key_wrapped_size
= (uint32_t)CFDataGetLength(bulkKeyWrapped
);
205 size_t blobLen
= sizeof(version
);
206 uint32_t prot_length
;
208 if (!hasACLConstraints
) {
209 blobLen
+= sizeof(actual_class
);
211 require_quiet(ac_data
= kc_copy_protection_data(access_control
), out
);
212 prot_length
= (uint32_t)CFDataGetLength(ac_data
);
213 blobLen
+= sizeof(prot_length
) + prot_length
;
216 blobLen
+= sizeof(key_wrapped_size
) + key_wrapped_size
+ ctLen
+ tagLen
;
217 require_quiet(blob
= CFDataCreateMutable(NULL
, blobLen
), out
);
218 CFDataSetLength(blob
, blobLen
);
219 cursor
= CFDataGetMutableBytePtr(blob
);
221 *((uint32_t *)cursor
) = useDefaultIV
? (version
| kUseDefaultIVMask
) : version
;
222 cursor
+= sizeof(version
);
224 //secerror("class: %d actual class: %d", keyclass, actual_class);
225 if (!hasACLConstraints
) {
226 *((keyclass_t
*)cursor
) = actual_class
;
227 cursor
+= sizeof(keyclass
);
229 *((uint32_t *)cursor
) = prot_length
;
230 cursor
+= sizeof(prot_length
);
232 CFDataGetBytes(ac_data
, CFRangeMake(0, prot_length
), cursor
);
233 cursor
+= prot_length
;
236 *((uint32_t *)cursor
) = key_wrapped_size
;
237 cursor
+= sizeof(key_wrapped_size
);
241 ivLen
= kIVSizeAESGCM
;
242 // AAD is (version || ac_data || key_wrapped_size)
243 aad
= CFDataGetMutableBytePtr(blob
);
244 aadLen
= cursor
- aad
;
247 memcpy(cursor
, CFDataGetBytePtr(bulkKeyWrapped
), key_wrapped_size
);
248 cursor
+= key_wrapped_size
;
250 /* Encrypt the plainText with the bulkKey. */
251 CCCryptorStatus ccerr
= CCCryptorGCM(kCCEncrypt
, kCCAlgorithmAES128
,
252 bulkKey
, bulkKeySize
,
254 aad
, aadLen
, /* auth data */
255 CFDataGetBytePtr(plainText
), ptLen
,
257 cursor
+ ctLen
, &tagLen
);
259 ok
= SecError(errSecInternal
, error
, CFSTR("ks_encrypt_data: CCCryptorGCM failed: %d"), ccerr
);
263 ok
= SecError(errSecInternal
, error
, CFSTR("ks_encrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen
);
268 memset(bulkKey
, 0, sizeof(bulkKey
));
269 CFReleaseSafe(ac_data
);
270 CFReleaseSafe(bulkKeyWrapped
);
271 CFReleaseSafe(plainText
);
279 CFReleaseSafe(auth_data
);
284 /* Given cipherText containing:
285 version || keyclass || KeyStore_WRAP(keyclass, BULK_KEY) ||
286 AES(BULK_KEY, NULL_IV, plainText || padding)
287 return the plainText. */
288 bool ks_decrypt_data(keybag_handle_t keybag
, CFTypeRef cryptoOp
, SecAccessControlRef
*paccess_control
, CFDataRef acm_context
,
289 CFDataRef blob
, const SecDbClass
*db_class
, CFArrayRef caller_access_groups
,
290 CFMutableDictionaryRef
*attributes_p
, uint32_t *version_p
, CFErrorRef
*error
) {
291 const uint32_t v0KeyWrapOverHead
= 8;
292 CFMutableDataRef bulkKey
= CFDataCreateMutable(0, 32); /* Use 256 bit AES key for bulkKey. */
293 CFDataSetLength(bulkKey
, 32); /* Use 256 bit AES key for bulkKey. */
295 SecAccessControlRef access_control
= NULL
;
298 *attributes_p
= NULL
;
302 CFMutableDataRef plainText
= NULL
;
303 CFMutableDictionaryRef attributes
= NULL
;
304 uint32_t version
= 0;
306 const uint8_t *iv
= NULL
;
307 const uint8_t *aad
= NULL
; // Additional Authenticated Data
308 ptrdiff_t aadLen
= 0;
311 CFMutableDictionaryRef authenticated_attributes
= NULL
;
312 CFDataRef caller_access_groups_data
= NULL
;
313 CFDataRef ed_data
= NULL
;
314 aks_ref_key_t ref_key
= NULL
;
318 check((keybag
>= 0) || (keybag
== session_keybag_handle
));
323 ok
= SecError(errSecParam
, error
, CFSTR("ks_decrypt_data: invalid blob"));
327 size_t blobLen
= CFDataGetLength(blob
);
328 const uint8_t *cursor
= CFDataGetBytePtr(blob
);
331 if (blobLen
< sizeof(version
)) {
332 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: Check for underflow (length)"));
336 version
= *((uint32_t *)cursor
);
337 if (version
& kUseDefaultIVMask
) {
338 version
&= ~kUseDefaultIVMask
;
340 ivLen
= kIVSizeAESGCM
;
343 cursor
+= sizeof(version
);
344 blobLen
-= sizeof(version
);
346 bool hasProtectionData
= (version
>= 4);
348 if (hasProtectionData
) {
349 /* Deserialize SecAccessControl object from the blob. */
350 uint32_t prot_length
;
356 if (blobLen
< sizeof(prot_length
)) {
357 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: Check for underflow (prot_length)"));
361 prot_length
= *((uint32_t *)cursor
);
362 cursor
+= sizeof(prot_length
);
363 blobLen
-= sizeof(prot_length
);
369 if (blobLen
< prot_length
) {
370 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: Check for underflow (prot)"));
374 CFTypeRef protection
= kc_copy_protection_from(cursor
, cursor
+ prot_length
);
376 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid ACL"));
379 access_control
= SecAccessControlCreate(NULL
, NULL
);
380 require_quiet(access_control
, out
);
381 ok
= SecAccessControlSetProtection(access_control
, protection
, NULL
);
382 CFRelease(protection
);
384 SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid ACL"));
389 cursor
+= prot_length
;
390 blobLen
-= prot_length
;
393 * Get numeric value of keyclass from the access_control.
395 keyclass
= kc_parse_keyclass(SecAccessControlGetProtection(access_control
), error
);
397 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid ACL"));
401 if (blobLen
< sizeof(keyclass
)) {
402 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: Check for underflow (keyclass)"));
406 keyclass
= *((keyclass_t
*)cursor
);
409 CFTypeRef protection
= kc_encode_keyclass(keyclass
& key_class_last
); // mask out generation
411 CFTypeRef protection
= kc_encode_keyclass(keyclass
);
413 require_action_quiet(protection
, out
, ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid keyclass detected")));
414 require_action_quiet(access_control
= SecAccessControlCreate(kCFAllocatorDefault
, error
), out
,
415 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: SecAccessControlCreate failed")));
416 require_action_quiet(SecAccessControlSetProtection(access_control
, protection
, error
), out
,
417 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: SecAccessControlSetProtection failed")));
419 cursor
+= sizeof(keyclass
);
420 blobLen
-= sizeof(keyclass
);
424 uint32_t wrapped_key_size
= 0;
428 wrapped_key_size
= (uint32_t)CFDataGetLength(bulkKey
) + v0KeyWrapOverHead
;
433 /* v2 and v3 have the same crypto, just different dictionary encodings. */
434 /* Difference between v3 and v6 is already handled above, so treat v3 as v6. */
441 if (blobLen
< sizeof(wrapped_key_size
)) {
442 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: Check for underflow (wrapped_key_size)"));
445 wrapped_key_size
= *((uint32_t *)cursor
);
447 cursor
+= sizeof(wrapped_key_size
);
448 blobLen
-= sizeof(wrapped_key_size
);
452 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid version %d"), version
);
456 if (blobLen
< tagLen
+ wrapped_key_size
) {
457 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: Check for underflow (wrapped_key/taglen)"));
461 size_t ctLen
= blobLen
- tagLen
- wrapped_key_size
;
464 * Pre-version 2 have some additial constraints since it use AES in CBC mode
467 if (ctLen
< kCCBlockSizeAES128
) {
468 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: Check for underflow (CBC check)"));
471 if ((ctLen
& 0xF) != 0) {
472 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid length on CBC data"));
478 if (hasProtectionData
) {
479 if (caller_access_groups
) {
480 caller_access_groups_data
= kc_copy_access_groups_data(caller_access_groups
, error
);
481 require_quiet(ok
= (caller_access_groups_data
!= NULL
), out
);
484 require_quiet(ok
= kc_attribs_key_encrypted_data_from_blob(keybag
, db_class
, cursor
, wrapped_key_size
, access_control
, version
,
485 &authenticated_attributes
, &ref_key
, &ed_data
, error
), out
);
486 if (CFEqual(cryptoOp
, kAKSKeyOpDecrypt
)) {
487 require_quiet(ok
= ks_decrypt_acl(ref_key
, ed_data
, bulkKey
, acm_context
, caller_access_groups_data
, access_control
, error
), out
);
488 } else if (CFEqual(cryptoOp
, kAKSKeyOpDelete
)) {
489 require_quiet(ok
= ks_delete_acl(ref_key
, ed_data
, acm_context
, caller_access_groups_data
, access_control
, error
), out
);
490 attributes
= CFRetainSafe(authenticated_attributes
);
493 ok
= SecError(errSecInternal
, error
, CFSTR("ks_decrypt_data: invalid operation"));
499 /* Now unwrap the bulk key using a key in the keybag. */
500 require_quiet(ok
= ks_crypt(cryptoOp
, keybag
,
501 keyclass
, wrapped_key_size
, cursor
, NULL
, bulkKey
, error
), out
);
505 // AAD is (version || ... [|| key_wrapped_size ])
506 aad
= CFDataGetBytePtr(blob
);
507 aadLen
= cursor
- aad
;
510 cursor
+= wrapped_key_size
;
512 plainText
= CFDataCreateMutable(NULL
, ctLen
);
514 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: failed to allocate data for plain text"));
517 CFDataSetLength(plainText
, ctLen
);
519 /* Decrypt the cipherText with the bulkKey. */
520 CCCryptorStatus ccerr
;
523 ccerr
= CCCryptorGCM(kCCDecrypt
, kCCAlgorithmAES128
,
524 CFDataGetBytePtr(bulkKey
), CFDataGetLength(bulkKey
),
526 aad
, aadLen
, /* auth data */
528 CFDataGetMutableBytePtr(plainText
),
531 /* TODO: Should this be errSecDecode once AppleKeyStore correctly
532 identifies uuid unwrap failures? */
533 /* errSecInteractionNotAllowed; */
534 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: CCCryptorGCM failed: %d"), ccerr
);
538 ok
= SecError(errSecInternal
, error
, CFSTR("ks_decrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen
);
542 if (timingsafe_bcmp(tag
, cursor
, tagLen
)) {
543 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: CCCryptorGCM computed tag not same as tag in blob"));
548 ccerr
= CCCrypt(kCCDecrypt
, kCCAlgorithmAES128
, kCCOptionPKCS7Padding
,
549 CFDataGetBytePtr(bulkKey
), CFDataGetLength(bulkKey
), NULL
, cursor
, ctLen
,
550 CFDataGetMutableBytePtr(plainText
), ctLen
, &ptLen
);
552 /* TODO: Should this be errSecDecode once AppleKeyStore correctly
553 identifies uuid unwrap failures? */
554 /* errSecInteractionNotAllowed; */
555 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: CCCrypt failed: %d"), ccerr
);
558 CFDataSetLength(plainText
, ptLen
);
562 attributes
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
563 CFDictionaryAddValue(attributes
, CFSTR("v_Data"), plainText
);
564 } else if (version
< 3) {
565 attributes
= s3dl_item_v2_decode(plainText
, error
);
567 attributes
= s3dl_item_v3_decode(plainText
, error
);
570 require_action_quiet(attributes
, out
, { ok
= false; secerror("decode v%d failed: %@ [item: %@]", version
, error
? *error
: NULL
, plainText
); });
573 if (version
>= 4 && authenticated_attributes
!= NULL
) {
574 CFDictionaryForEach(authenticated_attributes
, ^(const void *key
, const void *value
) {
575 CFDictionaryAddValue(attributes
, key
, value
);
581 memset(CFDataGetMutableBytePtr(bulkKey
), 0, CFDataGetLength(bulkKey
));
582 CFReleaseSafe(bulkKey
);
583 CFReleaseSafe(plainText
);
585 // Always copy access control data (if present), because if we fail it may indicate why.
587 *paccess_control
= access_control
;
589 CFReleaseSafe(access_control
);
593 *attributes_p
= CFRetainSafe(attributes
);
595 *version_p
= version
;
597 CFReleaseSafe(attributes
);
599 CFReleaseSafe(authenticated_attributes
);
600 CFReleaseSafe(caller_access_groups_data
);
601 CFReleaseSafe(ed_data
);
602 if (ref_key
) aks_ref_key_free(&ref_key
);
607 static keyclass_t
kc_parse_keyclass(CFTypeRef value
, CFErrorRef
*error
) {
608 if (!isString(value
)) {
609 SecError(errSecParam
, error
, CFSTR("accessible attribute %@ not a string"), value
);
610 } else if (CFEqual(value
, kSecAttrAccessibleWhenUnlocked
)) {
612 } else if (CFEqual(value
, kSecAttrAccessibleAfterFirstUnlock
)) {
614 } else if (CFEqual(value
, kSecAttrAccessibleAlwaysPrivate
)) {
616 } else if (CFEqual(value
, kSecAttrAccessibleWhenUnlockedThisDeviceOnly
)) {
617 return key_class_aku
;
618 } else if (CFEqual(value
, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
)) {
619 return key_class_cku
;
620 } else if (CFEqual(value
, kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate
)) {
621 return key_class_dku
;
622 } else if (CFEqual(value
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
)) {
623 return key_class_akpu
;
625 SecError(errSecParam
, error
, CFSTR("accessible attribute %@ unknown"), value
);
630 static CFTypeRef
kc_encode_keyclass(keyclass_t keyclass
) {
633 return kSecAttrAccessibleWhenUnlocked
;
635 return kSecAttrAccessibleAfterFirstUnlock
;
637 return kSecAttrAccessibleAlwaysPrivate
;
639 return kSecAttrAccessibleWhenUnlockedThisDeviceOnly
;
641 return kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
;
643 return kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate
;
645 return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
;
652 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
,
653 CFMutableDictionaryRef
*authenticated_attributes
, aks_ref_key_t
*ref_key
, CFDataRef
*encrypted_data
, CFErrorRef
*error
)
655 CFMutableDictionaryRef acl
= NULL
;
656 CFDictionaryRef blob_dict
= NULL
;
657 aks_ref_key_t tmp_ref_key
= NULL
;
658 CFDataRef key_data
= NULL
;
662 der_decode_plist(NULL
, kCFPropertyListImmutable
, (CFPropertyListRef
*)&blob_dict
, NULL
, blob_data
, blob_data
+ blob_data_len
);
663 require_action_quiet(blob_dict
, out
, SecError(errSecDecode
, error
, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'blob data'")));
665 if (!ks_separate_data_and_key(blob_dict
, &ed
, &key_data
)) {
666 ed
= CFDataCreate(kCFAllocatorDefault
, blob_data
, blob_data_len
);
667 key_data
= CFRetain(ed
);
669 require_action_quiet(ed
, out
, SecError(errSecDecode
, error
, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'encrypted data'")));
670 require_action_quiet(key_data
, out
, SecError(errSecDecode
, error
, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'key data'")));
672 const void *external_data
= NULL
;
673 size_t external_data_len
= 0;
674 require_quiet(external_data
= ks_ref_key_get_external_data(keybag
, key_data
, &tmp_ref_key
, &external_data_len
, error
), out
);
676 CFPropertyListRef external_data_dict
= NULL
;
677 der_decode_plist(NULL
, kCFPropertyListImmutable
, &external_data_dict
, NULL
, external_data
, external_data
+ external_data_len
);
678 require_action_quiet(external_data_dict
, out
, SecError(errSecDecode
, error
, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'encrypted data dictionary'")));
679 acl
= CFDictionaryCreateMutableCopy(NULL
, 0, external_data_dict
);
680 SecDbForEachAttrWithMask(class, attr_desc
, kSecDbInAuthenticatedDataFlag
) {
681 CFDictionaryRemoveValue(acl
, attr_desc
->name
);
682 CFTypeRef value
= CFDictionaryGetValue(external_data_dict
, attr_desc
->name
);
684 if (!*authenticated_attributes
)
685 *authenticated_attributes
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
687 CFDictionaryAddValue(*authenticated_attributes
, attr_desc
->name
, value
);
690 CFReleaseSafe(external_data_dict
);
693 /* v4 data format used wrong ACL placement, for backward compatibility we have to support both formats */
695 SecAccessControlSetConstraints(access_control
, acl
);
697 CFDictionaryRef constraints
= CFDictionaryGetValue(acl
, kAKSKeyAcl
);
698 require_action_quiet(isDictionary(constraints
), out
,
699 SecError(errSecDecode
, error
, CFSTR("kc_attribs_key_encrypted_data_from_blob: acl missing")));
700 SecAccessControlSetConstraints(access_control
, constraints
);
703 /* v4/v5 data format usualy does not contain kAKSKeyOpEncrypt, so add kAKSKeyOpEncrypt if is missing */
705 SecAccessConstraintRef encryptConstraint
= SecAccessControlGetConstraint(access_control
, kAKSKeyOpEncrypt
);
706 if (!encryptConstraint
)
707 SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpEncrypt
, kCFBooleanTrue
, NULL
);
713 *encrypted_data
= CFRetain(ed
);
716 *ref_key
= tmp_ref_key
;
724 aks_ref_key_free(&tmp_ref_key
);
725 CFReleaseSafe(blob_dict
);
726 CFReleaseSafe(key_data
);
734 static CFDataRef
kc_create_auth_data(SecAccessControlRef access_control
, CFDictionaryRef auth_attributes
) {
735 CFDictionaryRef constraints
= SecAccessControlGetConstraints(access_control
);
736 CFMutableDictionaryRef auth_data
= CFDictionaryCreateMutableCopy(NULL
, 0, auth_attributes
);
737 CFDictionarySetValue(auth_data
, kAKSKeyAcl
, constraints
);
738 CFDataRef encoded
= CFPropertyListCreateDERData(kCFAllocatorDefault
, auth_data
, NULL
);
739 CFReleaseSafe(auth_data
);
743 static CFDataRef
kc_copy_access_groups_data(CFArrayRef access_groups
, CFErrorRef
*error
)
745 size_t ag_size
= der_sizeof_plist(access_groups
, error
);
746 CFMutableDataRef result
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
747 CFDataSetLength(result
, ag_size
);
748 if (!der_encode_plist(access_groups
, error
, CFDataGetMutableBytePtr(result
), CFDataGetMutableBytePtr(result
) + ag_size
)) {
756 #endif /* USE_KEYSTORE */
758 static CFDataRef
kc_copy_protection_data(SecAccessControlRef access_control
)
760 CFTypeRef protection
= SecAccessControlGetProtection(access_control
);
761 size_t protection_size
= der_sizeof_plist(protection
, NULL
);
762 CFMutableDataRef result
= CFDataCreateMutable(NULL
, 0);
763 CFDataSetLength(result
, protection_size
);
764 if (!der_encode_plist(protection
, NULL
, CFDataGetMutableBytePtr(result
), CFDataGetMutableBytePtr(result
) + protection_size
)) {
772 static CFTypeRef
kc_copy_protection_from(const uint8_t *der
, const uint8_t *der_end
)
774 CFTypeRef result
= NULL
;
775 der_decode_plist(NULL
, kCFPropertyListImmutable
, &result
, NULL
, der
, der_end
);
779 /* Return a (mutable) dictionary if plist is a dictionary, return NULL and set error otherwise. Does nothing if plist is already NULL. */
780 static CF_RETURNS_RETAINED
781 CFMutableDictionaryRef
dictionaryFromPlist(CFPropertyListRef plist CF_CONSUMED
, CFErrorRef
*error
) {
782 if (plist
&& !isDictionary(plist
)) {
783 CFStringRef typeName
= CFCopyTypeIDDescription(CFGetTypeID((CFTypeRef
)plist
));
784 SecError(errSecDecode
, error
, CFSTR("plist is a %@, expecting a dictionary"), typeName
);
785 CFReleaseSafe(typeName
);
786 CFReleaseNull(plist
);
788 return (CFMutableDictionaryRef
)plist
;
791 static CF_RETURNS_RETAINED
792 CFMutableDictionaryRef
s3dl_item_v2_decode(CFDataRef plain
, CFErrorRef
*error
) {
793 CFPropertyListRef item
;
794 item
= CFPropertyListCreateWithData(0, plain
, kCFPropertyListMutableContainers
, NULL
, error
);
795 return dictionaryFromPlist(item
, error
);
798 static const uint8_t* (^s3dl_item_v3_decode_repair_date
)(CFAllocatorRef
, CFOptionFlags
, CFPropertyListRef
*, CFErrorRef
*, const uint8_t*, const uint8_t*) =
799 ^const uint8_t*(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFPropertyListRef
* pl
, CFErrorRef
*error
, const uint8_t* der
, const uint8_t *der_end
) {
800 if (error
&& CFEqualSafe(CFErrorGetDomain(*error
), sSecDERErrorDomain
) && CFErrorGetCode(*error
) == kSecDERErrorUnknownEncoding
) {
801 CFAbsoluteTime date
= 0;
802 CFCalendarRef calendar
= CFCalendarCreateWithIdentifier(allocator
, kCFGregorianCalendar
);
803 CFTimeZoneRef tz
= CFTimeZoneCreateWithTimeIntervalFromGMT(allocator
, 0);
804 CFCalendarSetTimeZone(calendar
, tz
);
805 CFCalendarComposeAbsoluteTime(calendar
, &date
, "yMd", 2001, 3, 24); // random date for <rdar://problem/20458954> 15A143: can't recover keychain
807 CFReleaseSafe(calendar
);
809 *pl
= CFDateCreate(allocator
, date
);
811 CFReleaseNull(*error
);
818 static CF_RETURNS_RETAINED
819 CFMutableDictionaryRef
s3dl_item_v3_decode(CFDataRef plain
, CFErrorRef
*error
) {
820 CFPropertyListRef item
= NULL
;
821 const uint8_t *der_beg
= CFDataGetBytePtr(plain
);
822 const uint8_t *der_end
= der_beg
+ CFDataGetLength(plain
);
823 const uint8_t *der
= der_decode_plist(0, kCFPropertyListMutableContainers
, &item
, error
, der_beg
, der_end
);
824 if (!der
&& error
&& CFEqualSafe(CFErrorGetDomain(*error
), sSecDERErrorDomain
) && CFErrorGetCode(*error
) == kSecDERErrorUnknownEncoding
) {
825 CFReleaseNull(*error
);
826 der
= der_decode_plist_with_repair(0, kCFPropertyListMutableContainers
, &item
, error
, der_beg
, der_end
, s3dl_item_v3_decode_repair_date
);
828 if (der
&& der
!= der_end
) {
829 SecCFCreateError(errSecDecode
, kSecErrorDomain
, CFSTR("trailing garbage at end of decrypted item"), NULL
, error
);
832 return dictionaryFromPlist(item
, error
);
835 bool s3dl_item_from_data(CFDataRef edata
, Query
*q
, CFArrayRef accessGroups
,
836 CFMutableDictionaryRef
*item
, SecAccessControlRef
*access_control
, CFErrorRef
*error
) {
837 SecAccessControlRef ac
= NULL
;
838 CFDataRef ac_data
= NULL
;
841 /* Decrypt and decode the item and check the decoded attributes against the query. */
842 uint32_t version
= 0;
843 require_quiet((ok
= ks_decrypt_data(q
->q_keybag
, kAKSKeyOpDecrypt
, &ac
, q
->q_use_cred_handle
, edata
, q
->q_class
,
844 q
->q_caller_access_groups
, item
, &version
, error
)), out
);
849 ac_data
= SecAccessControlCopyData(ac
);
850 if (!itemInAccessGroup(*item
, accessGroups
)) {
851 secerror("items accessGroup %@ not in %@",
852 CFDictionaryGetValue(*item
, kSecAttrAccessGroup
),
854 ok
= SecError(errSecDecode
, error
, CFSTR("items accessGroup %@ not in %@"),
855 CFDictionaryGetValue(*item
, kSecAttrAccessGroup
),
857 CFReleaseNull(*item
);
860 /* AccessControl attribute does not exist in the db, so synthesize it. */
862 CFDictionarySetValue(*item
, kSecAttrAccessControl
, ac_data
);
864 /* TODO: Validate access_control attribute. */
868 *access_control
= CFRetainSafe(ac
);
870 CFReleaseSafe(ac_data
);
874 /* Infer accessibility and access group for pre-v2 (iOS4.x and earlier) items
875 being imported from a backup. */
876 static bool SecDbItemImportMigrate(SecDbItemRef item
, CFErrorRef
*error
) {
878 CFStringRef agrp
= SecDbItemGetCachedValueWithName(item
, kSecAttrAccessGroup
);
879 CFStringRef accessible
= SecDbItemGetCachedValueWithName(item
, kSecAttrAccessible
);
881 if (!isString(agrp
) || !isString(accessible
))
883 if (SecDbItemGetClass(item
) == &genp_class
&& CFEqual(accessible
, kSecAttrAccessibleAlwaysPrivate
)) {
884 CFStringRef svce
= SecDbItemGetCachedValueWithName(item
, kSecAttrService
);
885 if (!isString(svce
)) return ok
;
886 if (CFEqual(agrp
, CFSTR("apple"))) {
887 if (CFEqual(svce
, CFSTR("AirPort"))) {
888 ok
= SecDbItemSetValueWithName(item
, kSecAttrAccessible
, kSecAttrAccessibleAfterFirstUnlock
, error
);
889 } else if (CFEqual(svce
, CFSTR("com.apple.airplay.password"))) {
890 ok
= SecDbItemSetValueWithName(item
, kSecAttrAccessible
, kSecAttrAccessibleWhenUnlocked
, error
);
891 } else if (CFEqual(svce
, CFSTR("YouTube"))) {
892 ok
= (SecDbItemSetValueWithName(item
, kSecAttrAccessible
, kSecAttrAccessibleWhenUnlocked
, error
) &&
893 SecDbItemSetValueWithName(item
, kSecAttrAccessGroup
, CFSTR("com.apple.youtube.credentials"), error
));
895 CFStringRef desc
= SecDbItemGetCachedValueWithName(item
, kSecAttrDescription
);
896 if (!isString(desc
)) return ok
;
897 if (CFEqual(desc
, CFSTR("IPSec Shared Secret")) || CFEqual(desc
, CFSTR("PPP Password"))) {
898 ok
= SecDbItemSetValueWithName(item
, kSecAttrAccessible
, kSecAttrAccessibleAfterFirstUnlock
, error
);
902 } else if (SecDbItemGetClass(item
) == &inet_class
&& CFEqual(accessible
, kSecAttrAccessibleAlwaysPrivate
)) {
903 if (CFEqual(agrp
, CFSTR("PrintKitAccessGroup"))) {
904 ok
= SecDbItemSetValueWithName(item
, kSecAttrAccessible
, kSecAttrAccessibleWhenUnlocked
, error
);
905 } else if (CFEqual(agrp
, CFSTR("apple"))) {
906 CFTypeRef ptcl
= SecDbItemGetCachedValueWithName(item
, kSecAttrProtocol
);
907 bool is_proxy
= false;
908 if (isNumber(ptcl
)) {
910 CFNumberGetValue(ptcl
, kCFNumberSInt32Type
, &iptcl
);
911 is_proxy
= (iptcl
== FOUR_CHAR_CODE('htpx') ||
912 iptcl
== FOUR_CHAR_CODE('htsx') ||
913 iptcl
== FOUR_CHAR_CODE('ftpx') ||
914 iptcl
== FOUR_CHAR_CODE('rtsx') ||
915 iptcl
== FOUR_CHAR_CODE('xpth') ||
916 iptcl
== FOUR_CHAR_CODE('xsth') ||
917 iptcl
== FOUR_CHAR_CODE('xptf') ||
918 iptcl
== FOUR_CHAR_CODE('xstr'));
919 } else if (isString(ptcl
)) {
920 is_proxy
= (CFEqual(ptcl
, kSecAttrProtocolHTTPProxy
) ||
921 CFEqual(ptcl
, kSecAttrProtocolHTTPSProxy
) ||
922 CFEqual(ptcl
, kSecAttrProtocolRTSPProxy
) ||
923 CFEqual(ptcl
, kSecAttrProtocolFTPProxy
));
926 ok
= SecDbItemSetValueWithName(item
, kSecAttrAccessible
, kSecAttrAccessibleWhenUnlocked
, error
);
932 bool SecDbItemDecrypt(SecDbItemRef item
, CFDataRef edata
, CFErrorRef
*error
) {
934 CFMutableDictionaryRef dict
= NULL
;
935 SecAccessControlRef access_control
= NULL
;
936 uint32_t version
= 0;
938 require_quiet(ok
= ks_decrypt_data(SecDbItemGetKeybag(item
), item
->cryptoOp
, &access_control
, item
->credHandle
, edata
,
939 item
->class, item
->callerAccessGroups
, &dict
, &version
, error
), out
);
942 /* Old V4 style keychain backup being imported. */
943 ok
= SecDbItemSetValueWithName(item
, CFSTR("v_Data"), CFDictionaryGetValue(dict
, CFSTR("v_Data")), error
) &&
944 SecDbItemImportMigrate(item
, error
);
946 ok
= dict
&& SecDbItemSetValues(item
, dict
, error
);
949 SecAccessControlRef my_access_control
= SecDbItemCopyAccessControl(item
, error
);
950 if (!my_access_control
) {
955 /* Make sure that the protection of ACL in the dictionary (read from DB) matched what we got
956 back from decoding the data blob. */
957 if (!CFEqual(SecAccessControlGetProtection(my_access_control
), SecAccessControlGetProtection(access_control
))) {
958 ok
= SecError(errSecDecode
, error
, CFSTR("ACL protection doesn't match the one in blob (%@ : %@)"),
959 SecAccessControlGetProtection(my_access_control
),
960 SecAccessControlGetProtection(access_control
));
962 CFRelease(my_access_control
);
965 // If we got protection back from ks_decrypt_data, update the appropriate attribute even if anything else
966 // (incl. actual decryption) failed. We need to access the protection type even if we are not able to actually
968 ok
= SecDbItemSetAccessControl(item
, access_control
, NULL
) && ok
;
971 CFReleaseSafe(access_control
);
975 /* Automagically make a item syncable, based on various attributes. */
976 bool SecDbItemInferSyncable(SecDbItemRef item
, CFErrorRef
*error
)
978 CFStringRef agrp
= SecDbItemGetCachedValueWithName(item
, kSecAttrAccessGroup
);
983 if (CFEqual(agrp
, CFSTR("com.apple.cfnetwork")) && SecDbItemGetClass(item
) == &inet_class
) {
984 CFTypeRef srvr
= SecDbItemGetCachedValueWithName(item
, kSecAttrServer
);
985 CFTypeRef ptcl
= SecDbItemGetCachedValueWithName(item
, kSecAttrProtocol
);
986 CFTypeRef atyp
= SecDbItemGetCachedValueWithName(item
, kSecAttrAuthenticationType
);
988 if (isString(srvr
) && isString(ptcl
) && isString(atyp
)) {
989 /* This looks like a Mobile Safari Password, make syncable */
990 secnotice("item", "Make this item syncable: %@", item
);
991 return SecDbItemSetSyncable(item
, true, error
);
998 /* This create a SecDbItem from the item dictionnary that are exported for backups.
999 Item are stored in the backup as a dictionary containing two keys:
1000 - v_Data: the encrypted data blob
1001 - v_PersistentRef: a persistent Ref.
1002 src_keybag is normally the backup keybag.
1003 dst_keybag is normally the device keybag.
1005 SecDbItemRef
SecDbItemCreateWithBackupDictionary(CFAllocatorRef allocator
, const SecDbClass
*dbclass
, CFDictionaryRef dict
, keybag_handle_t src_keybag
, keybag_handle_t dst_keybag
, CFErrorRef
*error
)
1007 CFDataRef edata
= CFDictionaryGetValue(dict
, CFSTR("v_Data"));
1008 SecDbItemRef item
= NULL
;
1011 item
= SecDbItemCreateWithEncryptedData(kCFAllocatorDefault
, dbclass
, edata
, src_keybag
, error
);
1013 if (!SecDbItemSetKeybag(item
, dst_keybag
, error
))
1014 CFReleaseNull(item
);
1016 SecError(errSecDecode
, error
, CFSTR("No v_Data in backup dictionary %@"), dict
);
1022 bool SecDbItemExtractRowIdFromBackupDictionary(SecDbItemRef item
, CFDictionaryRef dict
, CFErrorRef
*error
) {
1023 CFDataRef ref
= CFDictionaryGetValue(dict
, CFSTR("v_PersistentRef"));
1025 return SecError(errSecDecode
, error
, CFSTR("No v_PersistentRef in backup dictionary %@"), dict
);
1027 CFStringRef className
;
1028 sqlite3_int64 rowid
;
1029 if (!_SecItemParsePersistentRef(ref
, &className
, &rowid
))
1030 return SecError(errSecDecode
, error
, CFSTR("v_PersistentRef %@ failed to decode"), ref
);
1032 if (!CFEqual(SecDbItemGetClass(item
)->name
, className
))
1033 return SecError(errSecDecode
, error
, CFSTR("v_PersistentRef has unexpected class %@"), className
);
1035 return SecDbItemSetRowId(item
, rowid
, error
);
1038 static CFDataRef
SecDbItemCopyDERWithMask(SecDbItemRef item
, CFOptionFlags mask
, CFErrorRef
*error
) {
1039 CFDataRef der
= NULL
;
1040 CFMutableDictionaryRef dict
= SecDbItemCopyPListWithMask(item
, mask
, error
);
1042 der
= CFPropertyListCreateDERData(kCFAllocatorDefault
, dict
, error
);
1048 static CFTypeRef
SecDbItemCopyDigestWithMask(SecDbItemRef item
, CFOptionFlags mask
, CFErrorRef
*error
) {
1049 CFDataRef digest
= NULL
;
1050 CFDataRef der
= SecDbItemCopyDERWithMask(item
, mask
, error
);
1052 digest
= CFDataCopySHA1Digest(der
, error
);
1058 CFTypeRef
SecDbKeychainItemCopyPrimaryKey(SecDbItemRef item
, const SecDbAttr
*attr
, CFErrorRef
*error
) {
1059 return SecDbItemCopyDigestWithMask(item
, kSecDbPrimaryKeyFlag
, error
);
1062 CFTypeRef
SecDbKeychainItemCopySHA1(SecDbItemRef item
, const SecDbAttr
*attr
, CFErrorRef
*error
) {
1063 return SecDbItemCopyDigestWithMask(item
, kSecDbInHashFlag
, error
);
1066 CFTypeRef
SecDbKeychainItemCopyEncryptedData(SecDbItemRef item
, const SecDbAttr
*attr
, CFErrorRef
*error
) {
1067 CFDataRef edata
= NULL
;
1068 CFMutableDictionaryRef attributes
= SecDbItemCopyPListWithMask(item
, kSecDbInCryptoDataFlag
, error
);
1069 CFMutableDictionaryRef auth_attributes
= SecDbItemCopyPListWithMask(item
, kSecDbInAuthenticatedDataFlag
, error
);
1070 if (attributes
|| auth_attributes
) {
1071 SecAccessControlRef access_control
= SecDbItemCopyAccessControl(item
, error
);
1072 if (access_control
) {
1073 if (ks_encrypt_data(item
->keybag
, access_control
, item
->credHandle
, attributes
, auth_attributes
, &edata
, true, error
)) {
1074 item
->_edataState
= kSecDbItemEncrypting
;
1075 } else if (!error
|| !*error
|| CFErrorGetCode(*error
) != errSecAuthNeeded
|| !CFEqualSafe(CFErrorGetDomain(*error
), kSecErrorDomain
) ) {
1076 seccritical("ks_encrypt_data (db): failed: %@", error
? *error
: (CFErrorRef
)CFSTR(""));
1078 CFRelease(access_control
);
1080 CFReleaseSafe(attributes
);
1081 CFReleaseSafe(auth_attributes
);
1087 CFTypeRef
SecDbKeychainItemCopyCurrentDate(SecDbItemRef item
, const SecDbAttr
*attr
, CFErrorRef
*error
) {
1088 CFTypeRef value
= NULL
;
1089 switch (attr
->kind
) {
1090 case kSecDbDateAttr
:
1091 value
= CFDateCreate(kCFAllocatorDefault
, 0.0);
1093 case kSecDbCreationDateAttr
:
1094 case kSecDbModificationDateAttr
:
1095 value
= CFDateCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent());
1098 SecError(errSecInternal
, error
, CFSTR("attr %@ has no default value"), attr
->name
);
1105 SecAccessControlRef
SecDbItemCopyAccessControl(SecDbItemRef item
, CFErrorRef
*error
) {
1106 SecAccessControlRef accc
= NULL
, pdmn
= NULL
, result
= NULL
;
1107 CFTypeRef acccData
= SecDbItemGetValue(item
, SecDbClassAttrWithKind(item
->class, kSecDbAccessControlAttr
, error
), error
);
1108 CFTypeRef pdmnValue
= SecDbItemGetValue(item
, SecDbClassAttrWithKind(item
->class, kSecDbAccessAttr
, error
), error
);
1110 if (!acccData
|| !pdmnValue
)
1112 if (!CFEqual(acccData
, kCFNull
))
1113 require_quiet(accc
= SecAccessControlCreateFromData(CFGetAllocator(item
), acccData
, error
), out
);
1115 if (!CFEqual(pdmnValue
, kCFNull
)) {
1116 require_quiet(pdmn
= SecAccessControlCreate(CFGetAllocator(item
), error
), out
);
1117 require_quiet(SecAccessControlSetProtection(pdmn
, pdmnValue
, error
), out
);
1121 CFTypeRef acccProt
= SecAccessControlGetProtection(accc
);
1122 CFTypeRef pdmnProt
= SecAccessControlGetProtection(pdmn
);
1123 if (!acccProt
|| !pdmnProt
|| !CFEqual(acccProt
, pdmnProt
)) {
1124 secerror("SecDbItemCopyAccessControl accc %@ != pdmn %@, setting pdmn to accc value", acccProt
, pdmnProt
);
1125 __security_simulatecrash(CFSTR("Corrupted item on decrypt accc != pdmn"), __sec_exception_code_CorruptItem
);
1126 // Setting pdmn to accc prot value.
1127 require_quiet(SecDbItemSetValue(item
, SecDbClassAttrWithKind(item
->class, kSecDbAccessAttr
, error
), acccProt
, error
), out
);
1132 CFRetainAssign(result
, accc
);
1134 CFRetainAssign(result
, pdmn
);
1137 CFReleaseSafe(accc
);
1138 CFReleaseSafe(pdmn
);
1143 static const uint8_t* der_decode_plist_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
,
1144 CFPropertyListRef
* pl
, CFErrorRef
*error
,
1145 const uint8_t* der
, const uint8_t *der_end
,
1146 const uint8_t* (^repairBlock
)(CFAllocatorRef
, CFOptionFlags
, CFPropertyListRef
*, CFErrorRef
*,
1147 const uint8_t*, const uint8_t*))
1150 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Null DER"), NULL
, error
);
1155 if (NULL
== ccder_decode_tag(&tag
, der
, der_end
)) {
1156 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding"), NULL
, error
);
1162 return der_decode_null(allocator
, mutability
, (CFNullRef
*)pl
, error
, der
, der_end
);
1164 return der_decode_boolean(allocator
, mutability
, (CFBooleanRef
*)pl
, error
, der
, der_end
);
1165 case CCDER_OCTET_STRING
:
1166 return der_decode_data(allocator
, mutability
, (CFDataRef
*)pl
, error
, der
, der_end
);
1167 case CCDER_GENERALIZED_TIME
: {
1168 const uint8_t* der_result
= der_decode_date(allocator
, mutability
, (CFDateRef
*)pl
, error
, der
, der_end
);
1170 der_result
= repairBlock(allocator
, mutability
, pl
, error
, der
, der_end
);
1174 case CCDER_CONSTRUCTED_SEQUENCE
:
1175 return der_decode_array_with_repair(allocator
, mutability
, (CFArrayRef
*)pl
, error
, der
, der_end
, repairBlock
);
1176 case CCDER_UTF8_STRING
:
1177 return der_decode_string(allocator
, mutability
, (CFStringRef
*)pl
, error
, der
, der_end
);
1179 return der_decode_number(allocator
, mutability
, (CFNumberRef
*)pl
, error
, der
, der_end
);
1180 case CCDER_CONSTRUCTED_SET
:
1181 return der_decode_dictionary_with_repair(allocator
, mutability
, (CFDictionaryRef
*)pl
, error
, der
, der_end
, repairBlock
);
1182 case CCDER_CONSTRUCTED_CFSET
:
1183 return der_decode_set_with_repair(allocator
, mutability
, (CFSetRef
*)pl
, error
, der
, der_end
, repairBlock
);
1185 SecCFDERCreateError(kSecDERErrorUnsupportedDERType
, CFSTR("Unsupported DER Type"), NULL
, error
);
1190 static const uint8_t* der_decode_dictionary_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
,
1191 CFDictionaryRef
* dictionary
, CFErrorRef
*error
,
1192 const uint8_t* der
, const uint8_t *der_end
,
1193 const uint8_t* (^repairBlock
)(CFAllocatorRef
, CFOptionFlags
, CFPropertyListRef
*, CFErrorRef
*,
1194 const uint8_t*, const uint8_t*))
1197 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Null DER"), NULL
, error
);
1201 const uint8_t *payload_end
= 0;
1202 const uint8_t *payload
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SET
, &payload_end
, der
, der_end
);
1204 if (NULL
== payload
) {
1205 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SET"), NULL
, error
);
1210 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1213 SecCFDERCreateError(kSecDERErrorAllocationFailure
, CFSTR("Failed to create dictionary"), NULL
, error
);
1218 while (payload
!= NULL
&& payload
< payload_end
) {
1219 CFTypeRef key
= NULL
;
1220 CFTypeRef value
= NULL
;
1222 payload
= der_decode_key_value_with_repair(allocator
, mutability
, &key
, &value
, error
, payload
, payload_end
, repairBlock
);
1225 CFDictionaryAddValue(dict
, key
, value
);
1229 CFReleaseNull(value
);
1234 if (payload
== payload_end
) {
1239 CFReleaseNull(dict
);
1244 static const uint8_t* der_decode_key_value_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
,
1245 CFPropertyListRef
* key
, CFPropertyListRef
* value
, CFErrorRef
*error
,
1246 const uint8_t* der
, const uint8_t *der_end
,
1247 const uint8_t* (^repairBlock
)(CFAllocatorRef
, CFOptionFlags
, CFPropertyListRef
*, CFErrorRef
*,
1248 const uint8_t*, const uint8_t*))
1250 const uint8_t *payload_end
= 0;
1251 const uint8_t *payload
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &payload_end
, der
, der_end
);
1253 if (NULL
== payload
) {
1254 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SEQUENCE"), NULL
, error
);
1258 CFTypeRef keyObject
= NULL
;
1259 CFTypeRef valueObject
= NULL
;
1262 payload
= der_decode_plist_with_repair(allocator
, mutability
, &keyObject
, error
, payload
, payload_end
, repairBlock
);
1263 payload
= der_decode_plist_with_repair(allocator
, mutability
, &valueObject
, error
, payload
, payload_end
, repairBlock
);
1265 if (payload
!= NULL
) {
1267 *value
= valueObject
;
1269 CFReleaseNull(keyObject
);
1270 CFReleaseNull(valueObject
);
1275 static const uint8_t* der_decode_array_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
,
1276 CFArrayRef
* array
, CFErrorRef
*error
,
1277 const uint8_t* der
, const uint8_t *der_end
,
1278 const uint8_t* (^repairBlock
)(CFAllocatorRef
, CFOptionFlags
, CFPropertyListRef
*, CFErrorRef
*,
1279 const uint8_t*, const uint8_t*))
1282 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Null DER"), NULL
, error
);
1286 CFMutableArrayRef result
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
1288 const uint8_t *elements_end
;
1289 const uint8_t *current_element
= ccder_decode_sequence_tl(&elements_end
, der
, der_end
);
1291 while (current_element
!= NULL
&& current_element
< elements_end
) {
1292 CFPropertyListRef element
= NULL
;
1293 current_element
= der_decode_plist_with_repair(allocator
, mutability
, &element
, error
, current_element
, elements_end
, repairBlock
);
1294 if (current_element
) {
1295 CFArrayAppendValue(result
, element
);
1296 CFReleaseNull(element
);
1300 if (current_element
) {
1305 CFReleaseNull(result
);
1306 return current_element
;
1309 static const uint8_t* der_decode_set_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
,
1310 CFSetRef
* set
, CFErrorRef
*error
,
1311 const uint8_t* der
, const uint8_t *der_end
,
1312 const uint8_t* (^repairBlock
)(CFAllocatorRef
, CFOptionFlags
, CFPropertyListRef
*, CFErrorRef
*,
1313 const uint8_t*, const uint8_t*))
1316 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Null DER"), NULL
, error
);
1320 const uint8_t *payload_end
= 0;
1321 const uint8_t *payload
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_CFSET
, &payload_end
, der
, der_end
);
1323 if (NULL
== payload
) {
1324 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_CFSET"), NULL
, error
);
1328 CFMutableSetRef theSet
= (set
&& *set
) ? CFSetCreateMutableCopy(allocator
, 0, *set
)
1329 : CFSetCreateMutable(allocator
, 0, &kCFTypeSetCallBacks
);
1331 if (NULL
== theSet
) {
1332 SecCFDERCreateError(kSecDERErrorAllocationFailure
, CFSTR("Failed to create set"), NULL
, error
);
1337 while (payload
!= NULL
&& payload
< payload_end
) {
1338 CFTypeRef value
= NULL
;
1340 payload
= der_decode_plist_with_repair(allocator
, mutability
, &value
, error
, payload
, payload_end
, repairBlock
);
1343 CFSetAddValue(theSet
, value
);
1345 CFReleaseNull(value
);
1350 if (set
&& payload
== payload_end
) {
1351 CFTransferRetained(*set
, theSet
);
1354 CFReleaseNull(theSet
);