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>
53 #endif /* USE_KEYSTORE */
55 pthread_key_t CURRENT_CONNECTION_KEY
;
57 // From SecItemServer, should be a acl-check block
58 bool itemInAccessGroup(CFDictionaryRef item
, CFArrayRef accessGroups
);
60 static keyclass_t
kc_parse_keyclass(CFTypeRef value
, CFErrorRef
*error
);
61 static CFTypeRef
kc_encode_keyclass(keyclass_t keyclass
);
62 static CFDataRef
kc_copy_protection_data(SecAccessControlRef access_control
);
63 static CFTypeRef
kc_copy_protection_from(const uint8_t *der
, const uint8_t *der_end
);
64 static CF_RETURNS_RETAINED CFMutableDictionaryRef
s3dl_item_v2_decode(CFDataRef plain
, CFErrorRef
*error
);
65 static CF_RETURNS_RETAINED CFMutableDictionaryRef
s3dl_item_v3_decode(CFDataRef plain
, CFErrorRef
*error
);
67 static CFDataRef
kc_create_auth_data(SecAccessControlRef access_control
, CFDictionaryRef auth_attributes
);
68 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
,
69 CFMutableDictionaryRef
*authenticated_attributes
, aks_ref_key_t
*ref_key
, CFDataRef
*encrypted_data
, CFErrorRef
*error
);
70 static CFDataRef
kc_copy_access_groups_data(CFArrayRef access_groups
, CFErrorRef
*error
);
73 static const uint8_t* der_decode_plist_with_repair(CFAllocatorRef pl
, CFOptionFlags mutability
, CFPropertyListRef
* cf
, CFErrorRef
*error
,
74 const uint8_t* der
, const uint8_t *der_end
,
75 const uint8_t* (^repairBlock
)(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFPropertyListRef
* pl
, CFErrorRef
*error
,
76 const uint8_t* der
, const uint8_t *der_end
));
77 static const uint8_t* der_decode_dictionary_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFDictionaryRef
* dictionary
, CFErrorRef
*error
,
78 const uint8_t* der
, const uint8_t *der_end
,
79 const uint8_t* (^repairBlock
)(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFPropertyListRef
* pl
, CFErrorRef
*error
,
80 const uint8_t* der
, const uint8_t *der_end
));
81 static const uint8_t* der_decode_key_value_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFPropertyListRef
* key
, CFPropertyListRef
* value
, CFErrorRef
*error
,
82 const uint8_t* der
, const uint8_t *der_end
,
83 const uint8_t* (^repairBlock
)(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFPropertyListRef
* pl
, CFErrorRef
*error
,
84 const uint8_t* der
, const uint8_t *der_end
));
85 static const uint8_t* der_decode_array_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFArrayRef
* array
, CFErrorRef
*error
,
86 const uint8_t* der
, const uint8_t *der_end
,
87 const uint8_t* (^repairBlock
)(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFPropertyListRef
* pl
, CFErrorRef
*error
,
88 const uint8_t* der
, const uint8_t *der_end
));
89 static const uint8_t* der_decode_set_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFSetRef
* set
, CFErrorRef
*error
,
90 const uint8_t* der
, const uint8_t *der_end
,
91 const uint8_t* (^repairBlock
)(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFPropertyListRef
* pl
, CFErrorRef
*error
,
92 const uint8_t* der
, const uint8_t *der_end
));
94 const uint32_t kUseDefaultIVMask
= 1<<31;
95 const int16_t kIVSizeAESGCM
= 12;
97 // echo "keychainblobstaticiv" | openssl dgst -sha256 | cut -c1-24 | xargs -I {} echo "0x{}" | xxd -r | xxd -p -i
98 static const uint8_t gcmIV
[kIVSizeAESGCM
] = {
99 0x1e, 0xa0, 0x5c, 0xa9, 0x98, 0x2e, 0x87, 0xdc, 0xf1, 0x45, 0xe8, 0x24
102 /* Given plainText create and return a CFDataRef containing:
103 BULK_KEY = RandomKey()
104 version || keyclass|ACL || KeyStore_WRAP(keyclass, BULK_KEY) ||
105 AES(BULK_KEY, NULL_IV, plainText || padding)
107 bool ks_encrypt_data(keybag_handle_t keybag
, SecAccessControlRef access_control
, CFDataRef acm_context
,
108 CFDictionaryRef attributes
, CFDictionaryRef authenticated_attributes
, CFDataRef
*pBlob
, bool useDefaultIV
, CFErrorRef
*error
) {
109 CFMutableDataRef blob
= NULL
;
110 CFDataRef ac_data
= NULL
;
112 //check(keybag >= 0);
114 /* Precalculate output blob length. */
115 const uint32_t bulkKeySize
= 32; /* Use 256 bit AES key for bulkKey. */
116 const uint32_t maxKeyWrapOverHead
= 8 + 32;
117 uint8_t bulkKey
[bulkKeySize
];
118 CFMutableDataRef bulkKeyWrapped
= CFDataCreateMutable(NULL
, 0);
119 CFDataSetLength(bulkKeyWrapped
, bulkKeySize
+ maxKeyWrapOverHead
);
120 uint32_t key_wrapped_size
;
122 const uint8_t *iv
= NULL
;
123 const uint8_t *aad
= NULL
; // Additional Authenticated Data
124 ptrdiff_t aadLen
= 0;
127 CFDataRef auth_data
= NULL
;
130 /* If access_control specifies only protection and no ACL, use legacy blob format version 3,
131 which has better support for sync/backup. Otherwise, force new format v6 unless useDefaultIV is set. */
132 bool hasACLConstraints
= SecAccessControlGetConstraints(access_control
);
133 const uint32_t version
= (hasACLConstraints
? 6 : 3);
134 CFDataRef plainText
= NULL
;
136 CFMutableDictionaryRef attributes_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
137 if (authenticated_attributes
) {
138 CFDictionaryForEach(authenticated_attributes
, ^(const void *key
, const void *value
) {
139 CFDictionaryAddValue(attributes_dict
, key
, value
);
143 if (attributes_dict
) {
144 // Drop the accc attribute for non v6 items during encode.
145 CFDictionaryRemoveValue(attributes_dict
, kSecAttrAccessControl
);
146 plainText
= CFPropertyListCreateDERData(kCFAllocatorDefault
, attributes_dict
, error
);
147 CFRelease(attributes_dict
);
152 plainText
= CFPropertyListCreateDERData(kCFAllocatorDefault
, attributes
, error
);
155 CFMutableDictionaryRef attributes_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
156 if (authenticated_attributes
) {
157 CFDictionaryForEach(authenticated_attributes
, ^(const void *key
, const void *value
) {
158 CFDictionaryAddValue(attributes_dict
, key
, value
);
162 if (attributes_dict
) {
163 plainText
= CFPropertyListCreateDERData(kCFAllocatorDefault
, attributes_dict
, error
);
164 CFRelease(attributes_dict
);
169 if (!plainText
|| CFGetTypeID(plainText
) != CFDataGetTypeID()
170 || access_control
== 0) {
171 ok
= SecError(errSecParam
, error
, CFSTR("ks_encrypt_data: invalid plain text"));
175 size_t ptLen
= CFDataGetLength(plainText
);
176 size_t ctLen
= ptLen
;
178 keyclass_t actual_class
= 0;
180 if (SecRandomCopyBytes(kSecRandomDefault
, bulkKeySize
, bulkKey
)) {
181 ok
= SecError(errSecAllocate
, error
, CFSTR("ks_encrypt_data: SecRandomCopyBytes failed"));
185 /* Extract keyclass from access control. */
186 keyclass_t keyclass
= kc_parse_keyclass(SecAccessControlGetProtection(access_control
), error
);
192 auth_data
= kc_create_auth_data(access_control
, authenticated_attributes
);
193 require_quiet(ok
= ks_encrypt_acl(keybag
, keyclass
, bulkKeySize
, bulkKey
, bulkKeyWrapped
, auth_data
, acm_context
, access_control
, error
), out
);
197 /* Encrypt bulkKey. */
198 require_quiet(ok
= ks_crypt(kAKSKeyOpEncrypt
, keybag
,
199 keyclass
, bulkKeySize
, bulkKey
,
200 &actual_class
, bulkKeyWrapped
,
204 key_wrapped_size
= (uint32_t)CFDataGetLength(bulkKeyWrapped
);
206 size_t blobLen
= sizeof(version
);
207 uint32_t prot_length
= 0;
209 if (!hasACLConstraints
) {
210 blobLen
+= sizeof(actual_class
);
212 require_quiet(ac_data
= kc_copy_protection_data(access_control
), out
);
213 prot_length
= (uint32_t)CFDataGetLength(ac_data
);
214 blobLen
+= sizeof(prot_length
) + prot_length
;
217 blobLen
+= sizeof(key_wrapped_size
) + key_wrapped_size
+ ctLen
+ tagLen
;
218 require_quiet(blob
= CFDataCreateMutable(NULL
, blobLen
), out
);
219 CFDataSetLength(blob
, blobLen
);
220 cursor
= CFDataGetMutableBytePtr(blob
);
222 *((uint32_t *)cursor
) = useDefaultIV
? (version
| kUseDefaultIVMask
) : version
;
223 cursor
+= sizeof(version
);
225 //secerror("class: %d actual class: %d", keyclass, actual_class);
226 if (!hasACLConstraints
) {
227 *((keyclass_t
*)cursor
) = actual_class
;
228 cursor
+= sizeof(keyclass
);
230 *((uint32_t *)cursor
) = prot_length
;
231 cursor
+= sizeof(prot_length
);
233 CFDataGetBytes(ac_data
, CFRangeMake(0, prot_length
), cursor
);
234 cursor
+= prot_length
;
237 *((uint32_t *)cursor
) = key_wrapped_size
;
238 cursor
+= sizeof(key_wrapped_size
);
242 ivLen
= kIVSizeAESGCM
;
243 // AAD is (version || ac_data || key_wrapped_size)
244 aad
= CFDataGetMutableBytePtr(blob
);
245 aadLen
= cursor
- aad
;
248 memcpy(cursor
, CFDataGetBytePtr(bulkKeyWrapped
), key_wrapped_size
);
249 cursor
+= key_wrapped_size
;
251 /* Encrypt the plainText with the bulkKey. */
252 CCCryptorStatus ccerr
= CCCryptorGCM(kCCEncrypt
, kCCAlgorithmAES128
,
253 bulkKey
, bulkKeySize
,
255 aad
, aadLen
, /* auth data */
256 CFDataGetBytePtr(plainText
), ptLen
,
258 cursor
+ ctLen
, &tagLen
);
260 ok
= SecError(errSecInternal
, error
, CFSTR("ks_encrypt_data: CCCryptorGCM failed: %d"), ccerr
);
264 ok
= SecError(errSecInternal
, error
, CFSTR("ks_encrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen
);
269 memset(bulkKey
, 0, sizeof(bulkKey
));
270 CFReleaseSafe(ac_data
);
271 CFReleaseSafe(bulkKeyWrapped
);
272 CFReleaseSafe(plainText
);
280 CFReleaseSafe(auth_data
);
285 /* Given cipherText containing:
286 version || keyclass || KeyStore_WRAP(keyclass, BULK_KEY) ||
287 AES(BULK_KEY, NULL_IV, plainText || padding)
288 return the plainText. */
289 bool ks_decrypt_data(keybag_handle_t keybag
, CFTypeRef cryptoOp
, SecAccessControlRef
*paccess_control
, CFDataRef acm_context
,
290 CFDataRef blob
, const SecDbClass
*db_class
, CFArrayRef caller_access_groups
,
291 CFMutableDictionaryRef
*attributes_p
, uint32_t *version_p
, CFErrorRef
*error
) {
292 const uint32_t v0KeyWrapOverHead
= 8;
293 CFMutableDataRef bulkKey
= CFDataCreateMutable(0, 32); /* Use 256 bit AES key for bulkKey. */
294 CFDataSetLength(bulkKey
, 32); /* Use 256 bit AES key for bulkKey. */
296 SecAccessControlRef access_control
= NULL
;
299 *attributes_p
= NULL
;
303 CFMutableDataRef plainText
= NULL
;
304 CFMutableDictionaryRef attributes
= NULL
;
305 uint32_t version
= 0;
307 const uint8_t *iv
= NULL
;
308 const uint8_t *aad
= NULL
; // Additional Authenticated Data
309 ptrdiff_t aadLen
= 0;
312 CFMutableDictionaryRef authenticated_attributes
= NULL
;
313 CFDataRef caller_access_groups_data
= NULL
;
314 CFDataRef ed_data
= NULL
;
315 aks_ref_key_t ref_key
= NULL
;
319 check((keybag
>= 0) || (keybag
== session_keybag_handle
));
324 ok
= SecError(errSecParam
, error
, CFSTR("ks_decrypt_data: invalid blob"));
328 size_t blobLen
= CFDataGetLength(blob
);
329 const uint8_t *cursor
= CFDataGetBytePtr(blob
);
332 if (blobLen
< sizeof(version
)) {
333 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: Check for underflow (length)"));
337 version
= *((uint32_t *)cursor
);
338 if (version
& kUseDefaultIVMask
) {
339 version
&= ~kUseDefaultIVMask
;
341 ivLen
= kIVSizeAESGCM
;
344 cursor
+= sizeof(version
);
345 blobLen
-= sizeof(version
);
347 bool hasProtectionData
= (version
>= 4);
349 if (hasProtectionData
) {
350 /* Deserialize SecAccessControl object from the blob. */
351 uint32_t prot_length
;
357 if (blobLen
< sizeof(prot_length
)) {
358 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: Check for underflow (prot_length)"));
362 prot_length
= *((uint32_t *)cursor
);
363 cursor
+= sizeof(prot_length
);
364 blobLen
-= sizeof(prot_length
);
370 if (blobLen
< prot_length
) {
371 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: Check for underflow (prot)"));
375 CFTypeRef protection
= kc_copy_protection_from(cursor
, cursor
+ prot_length
);
377 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid ACL"));
380 access_control
= SecAccessControlCreate(NULL
, NULL
);
381 require_quiet(access_control
, out
);
382 ok
= SecAccessControlSetProtection(access_control
, protection
, NULL
);
383 CFRelease(protection
);
385 SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid ACL"));
390 cursor
+= prot_length
;
391 blobLen
-= prot_length
;
394 * Get numeric value of keyclass from the access_control.
396 keyclass
= kc_parse_keyclass(SecAccessControlGetProtection(access_control
), error
);
398 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid ACL"));
402 if (blobLen
< sizeof(keyclass
)) {
403 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: Check for underflow (keyclass)"));
407 keyclass
= *((keyclass_t
*)cursor
);
410 CFTypeRef protection
= kc_encode_keyclass(keyclass
& key_class_last
); // mask out generation
412 CFTypeRef protection
= kc_encode_keyclass(keyclass
);
414 require_action_quiet(protection
, out
, ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid keyclass detected")));
415 require_action_quiet(access_control
= SecAccessControlCreate(kCFAllocatorDefault
, error
), out
,
416 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: SecAccessControlCreate failed")));
417 require_action_quiet(SecAccessControlSetProtection(access_control
, protection
, error
), out
,
418 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: SecAccessControlSetProtection failed")));
420 cursor
+= sizeof(keyclass
);
421 blobLen
-= sizeof(keyclass
);
425 uint32_t wrapped_key_size
= 0;
429 wrapped_key_size
= (uint32_t)CFDataGetLength(bulkKey
) + v0KeyWrapOverHead
;
434 /* v2 and v3 have the same crypto, just different dictionary encodings. */
435 /* Difference between v3 and v6 is already handled above, so treat v3 as v6. */
442 if (blobLen
< sizeof(wrapped_key_size
)) {
443 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: Check for underflow (wrapped_key_size)"));
446 wrapped_key_size
= *((uint32_t *)cursor
);
448 cursor
+= sizeof(wrapped_key_size
);
449 blobLen
-= sizeof(wrapped_key_size
);
453 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid version %d"), version
);
457 if (blobLen
< tagLen
+ wrapped_key_size
) {
458 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: Check for underflow (wrapped_key/taglen)"));
462 size_t ctLen
= blobLen
- tagLen
- wrapped_key_size
;
465 * Pre-version 2 have some additial constraints since it use AES in CBC mode
468 if (ctLen
< kCCBlockSizeAES128
) {
469 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: Check for underflow (CBC check)"));
472 if ((ctLen
& 0xF) != 0) {
473 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid length on CBC data"));
479 if (hasProtectionData
) {
480 if (caller_access_groups
) {
481 caller_access_groups_data
= kc_copy_access_groups_data(caller_access_groups
, error
);
482 require_quiet(ok
= (caller_access_groups_data
!= NULL
), out
);
485 require_quiet(ok
= kc_attribs_key_encrypted_data_from_blob(keybag
, db_class
, cursor
, wrapped_key_size
, access_control
, version
,
486 &authenticated_attributes
, &ref_key
, &ed_data
, error
), out
);
487 if (CFEqual(cryptoOp
, kAKSKeyOpDecrypt
)) {
488 require_quiet(ok
= ks_decrypt_acl(ref_key
, ed_data
, bulkKey
, acm_context
, caller_access_groups_data
, access_control
, error
), out
);
489 } else if (CFEqual(cryptoOp
, kAKSKeyOpDelete
)) {
490 require_quiet(ok
= ks_delete_acl(ref_key
, ed_data
, acm_context
, caller_access_groups_data
, access_control
, error
), out
);
491 attributes
= CFRetainSafe(authenticated_attributes
);
494 ok
= SecError(errSecInternal
, error
, CFSTR("ks_decrypt_data: invalid operation"));
500 /* Now unwrap the bulk key using a key in the keybag. */
501 require_quiet(ok
= ks_crypt(cryptoOp
, keybag
,
502 keyclass
, wrapped_key_size
, cursor
, NULL
, bulkKey
, error
), out
);
506 // AAD is (version || ... [|| key_wrapped_size ])
507 aad
= CFDataGetBytePtr(blob
);
508 aadLen
= cursor
- aad
;
511 cursor
+= wrapped_key_size
;
513 plainText
= CFDataCreateMutable(NULL
, ctLen
);
515 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: failed to allocate data for plain text"));
518 CFDataSetLength(plainText
, ctLen
);
520 /* Decrypt the cipherText with the bulkKey. */
521 CCCryptorStatus ccerr
;
524 ccerr
= CCCryptorGCM(kCCDecrypt
, kCCAlgorithmAES128
,
525 CFDataGetBytePtr(bulkKey
), CFDataGetLength(bulkKey
),
527 aad
, aadLen
, /* auth data */
529 CFDataGetMutableBytePtr(plainText
),
532 /* TODO: Should this be errSecDecode once AppleKeyStore correctly
533 identifies uuid unwrap failures? */
534 /* errSecInteractionNotAllowed; */
535 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: CCCryptorGCM failed: %d"), ccerr
);
539 ok
= SecError(errSecInternal
, error
, CFSTR("ks_decrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen
);
543 if (timingsafe_bcmp(tag
, cursor
, tagLen
)) {
544 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: CCCryptorGCM computed tag not same as tag in blob"));
549 ccerr
= CCCrypt(kCCDecrypt
, kCCAlgorithmAES128
, kCCOptionPKCS7Padding
,
550 CFDataGetBytePtr(bulkKey
), CFDataGetLength(bulkKey
), NULL
, cursor
, ctLen
,
551 CFDataGetMutableBytePtr(plainText
), ctLen
, &ptLen
);
553 /* TODO: Should this be errSecDecode once AppleKeyStore correctly
554 identifies uuid unwrap failures? */
555 /* errSecInteractionNotAllowed; */
556 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: CCCrypt failed: %d"), ccerr
);
559 CFDataSetLength(plainText
, ptLen
);
563 attributes
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
564 CFDictionaryAddValue(attributes
, CFSTR("v_Data"), plainText
);
565 } else if (version
< 3) {
566 attributes
= s3dl_item_v2_decode(plainText
, error
);
568 attributes
= s3dl_item_v3_decode(plainText
, error
);
571 require_action_quiet(attributes
, out
, { ok
= false; secerror("decode v%d failed: %@", version
, error
? *error
: NULL
); });
574 if (version
>= 4 && authenticated_attributes
!= NULL
) {
575 CFDictionaryForEach(authenticated_attributes
, ^(const void *key
, const void *value
) {
576 CFDictionaryAddValue(attributes
, key
, value
);
582 memset(CFDataGetMutableBytePtr(bulkKey
), 0, CFDataGetLength(bulkKey
));
583 CFReleaseNull(bulkKey
);
584 CFReleaseNull(plainText
);
586 // Always copy access control data (if present), because if we fail it may indicate why.
588 *paccess_control
= access_control
;
590 CFReleaseNull(access_control
);
594 CFRetainAssign(*attributes_p
, attributes
);
596 *version_p
= version
;
598 CFReleaseNull(attributes
);
600 CFReleaseNull(authenticated_attributes
);
601 CFReleaseNull(caller_access_groups_data
);
602 CFReleaseNull(ed_data
);
603 if (ref_key
) aks_ref_key_free(&ref_key
);
608 static keyclass_t
kc_parse_keyclass(CFTypeRef value
, CFErrorRef
*error
) {
609 if (!isString(value
)) {
610 SecError(errSecParam
, error
, CFSTR("accessible attribute %@ not a string"), value
);
611 } else if (CFEqual(value
, kSecAttrAccessibleWhenUnlocked
)) {
613 } else if (CFEqual(value
, kSecAttrAccessibleAfterFirstUnlock
)) {
615 } else if (CFEqual(value
, kSecAttrAccessibleAlwaysPrivate
)) {
617 } else if (CFEqual(value
, kSecAttrAccessibleWhenUnlockedThisDeviceOnly
)) {
618 return key_class_aku
;
619 } else if (CFEqual(value
, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
)) {
620 return key_class_cku
;
621 } else if (CFEqual(value
, kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate
)) {
622 return key_class_dku
;
623 } else if (CFEqual(value
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
)) {
624 return key_class_akpu
;
626 SecError(errSecParam
, error
, CFSTR("accessible attribute %@ unknown"), value
);
631 static CFTypeRef
kc_encode_keyclass(keyclass_t keyclass
) {
634 return kSecAttrAccessibleWhenUnlocked
;
636 return kSecAttrAccessibleAfterFirstUnlock
;
638 return kSecAttrAccessibleAlwaysPrivate
;
640 return kSecAttrAccessibleWhenUnlockedThisDeviceOnly
;
642 return kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
;
644 return kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate
;
646 return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
;
653 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
,
654 CFMutableDictionaryRef
*authenticated_attributes
, aks_ref_key_t
*ref_key
, CFDataRef
*encrypted_data
, CFErrorRef
*error
)
656 CFMutableDictionaryRef acl
= NULL
;
657 CFDictionaryRef blob_dict
= NULL
;
658 aks_ref_key_t tmp_ref_key
= NULL
;
659 CFDataRef key_data
= NULL
;
663 der_decode_plist(NULL
, kCFPropertyListImmutable
, (CFPropertyListRef
*)&blob_dict
, NULL
, blob_data
, blob_data
+ blob_data_len
);
664 require_action_quiet(blob_dict
, out
, SecError(errSecDecode
, error
, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'blob data'")));
666 if (!ks_separate_data_and_key(blob_dict
, &ed
, &key_data
)) {
667 ed
= CFDataCreate(kCFAllocatorDefault
, blob_data
, blob_data_len
);
668 key_data
= CFRetain(ed
);
670 require_action_quiet(ed
, out
, SecError(errSecDecode
, error
, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'encrypted data'")));
671 require_action_quiet(key_data
, out
, SecError(errSecDecode
, error
, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'key data'")));
673 const void *external_data
= NULL
;
674 size_t external_data_len
= 0;
675 require_quiet(external_data
= ks_ref_key_get_external_data(keybag
, key_data
, &tmp_ref_key
, &external_data_len
, error
), out
);
677 CFPropertyListRef external_data_dict
= NULL
;
678 der_decode_plist(NULL
, kCFPropertyListImmutable
, &external_data_dict
, NULL
, external_data
, external_data
+ external_data_len
);
679 require_action_quiet(external_data_dict
, out
, SecError(errSecDecode
, error
, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'encrypted data dictionary'")));
680 acl
= CFDictionaryCreateMutableCopy(NULL
, 0, external_data_dict
);
681 SecDbForEachAttrWithMask(class, attr_desc
, kSecDbInAuthenticatedDataFlag
) {
682 CFDictionaryRemoveValue(acl
, attr_desc
->name
);
683 CFTypeRef value
= CFDictionaryGetValue(external_data_dict
, attr_desc
->name
);
685 if (!*authenticated_attributes
)
686 *authenticated_attributes
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
688 CFDictionaryAddValue(*authenticated_attributes
, attr_desc
->name
, value
);
691 CFReleaseSafe(external_data_dict
);
694 /* v4 data format used wrong ACL placement, for backward compatibility we have to support both formats */
696 SecAccessControlSetConstraints(access_control
, acl
);
698 CFDictionaryRef constraints
= CFDictionaryGetValue(acl
, kAKSKeyAcl
);
699 require_action_quiet(isDictionary(constraints
), out
,
700 SecError(errSecDecode
, error
, CFSTR("kc_attribs_key_encrypted_data_from_blob: acl missing")));
701 SecAccessControlSetConstraints(access_control
, constraints
);
704 /* v4/v5 data format usualy does not contain kAKSKeyOpEncrypt, so add kAKSKeyOpEncrypt if is missing */
706 SecAccessConstraintRef encryptConstraint
= SecAccessControlGetConstraint(access_control
, kAKSKeyOpEncrypt
);
707 if (!encryptConstraint
)
708 SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpEncrypt
, kCFBooleanTrue
, NULL
);
714 *encrypted_data
= CFRetain(ed
);
717 *ref_key
= tmp_ref_key
;
725 aks_ref_key_free(&tmp_ref_key
);
726 CFReleaseSafe(blob_dict
);
727 CFReleaseSafe(key_data
);
735 static CFDataRef
kc_create_auth_data(SecAccessControlRef access_control
, CFDictionaryRef auth_attributes
) {
736 CFDictionaryRef constraints
= SecAccessControlGetConstraints(access_control
);
737 CFMutableDictionaryRef auth_data
= CFDictionaryCreateMutableCopy(NULL
, 0, auth_attributes
);
738 CFDictionarySetValue(auth_data
, kAKSKeyAcl
, constraints
);
739 CFDataRef encoded
= CFPropertyListCreateDERData(kCFAllocatorDefault
, auth_data
, NULL
);
740 CFReleaseSafe(auth_data
);
744 static CFDataRef
kc_copy_access_groups_data(CFArrayRef access_groups
, CFErrorRef
*error
)
746 size_t ag_size
= der_sizeof_plist(access_groups
, error
);
747 CFMutableDataRef result
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
748 CFDataSetLength(result
, ag_size
);
749 if (!der_encode_plist(access_groups
, error
, CFDataGetMutableBytePtr(result
), CFDataGetMutableBytePtr(result
) + ag_size
)) {
757 #endif /* USE_KEYSTORE */
759 static CFDataRef
kc_copy_protection_data(SecAccessControlRef access_control
)
761 CFTypeRef protection
= SecAccessControlGetProtection(access_control
);
762 size_t protection_size
= der_sizeof_plist(protection
, NULL
);
763 CFMutableDataRef result
= CFDataCreateMutable(NULL
, 0);
764 CFDataSetLength(result
, protection_size
);
765 if (!der_encode_plist(protection
, NULL
, CFDataGetMutableBytePtr(result
), CFDataGetMutableBytePtr(result
) + protection_size
)) {
773 static CFTypeRef
kc_copy_protection_from(const uint8_t *der
, const uint8_t *der_end
)
775 CFTypeRef result
= NULL
;
776 der_decode_plist(NULL
, kCFPropertyListImmutable
, &result
, NULL
, der
, der_end
);
780 /* Return a (mutable) dictionary if plist is a dictionary, return NULL and set error otherwise. Does nothing if plist is already NULL. */
781 static CF_RETURNS_RETAINED
782 CFMutableDictionaryRef
dictionaryFromPlist(CFPropertyListRef plist CF_CONSUMED
, CFErrorRef
*error
) {
783 if (plist
&& !isDictionary(plist
)) {
784 CFStringRef typeName
= CFCopyTypeIDDescription(CFGetTypeID((CFTypeRef
)plist
));
785 SecError(errSecDecode
, error
, CFSTR("plist is a %@, expecting a dictionary"), typeName
);
786 CFReleaseSafe(typeName
);
787 CFReleaseNull(plist
);
789 return (CFMutableDictionaryRef
)plist
;
792 static CF_RETURNS_RETAINED
793 CFMutableDictionaryRef
s3dl_item_v2_decode(CFDataRef plain
, CFErrorRef
*error
) {
794 CFPropertyListRef item
;
795 item
= CFPropertyListCreateWithData(0, plain
, kCFPropertyListMutableContainers
, NULL
, error
);
796 return dictionaryFromPlist(item
, error
);
799 static const uint8_t* (^s3dl_item_v3_decode_repair_date
)(CFAllocatorRef
, CFOptionFlags
, CFPropertyListRef
*, CFErrorRef
*, const uint8_t*, const uint8_t*) =
800 ^const uint8_t*(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFPropertyListRef
* pl
, CFErrorRef
*error
, const uint8_t* der
, const uint8_t *der_end
) {
801 if (error
&& CFEqualSafe(CFErrorGetDomain(*error
), sSecDERErrorDomain
) && CFErrorGetCode(*error
) == kSecDERErrorUnknownEncoding
) {
802 CFAbsoluteTime date
= 0;
803 CFCalendarRef calendar
= CFCalendarCreateWithIdentifier(allocator
, kCFGregorianCalendar
);
804 CFTimeZoneRef tz
= CFTimeZoneCreateWithTimeIntervalFromGMT(allocator
, 0);
805 CFCalendarSetTimeZone(calendar
, tz
);
806 CFCalendarComposeAbsoluteTime(calendar
, &date
, "yMd", 2001, 3, 24); // random date for <rdar://problem/20458954> 15A143: can't recover keychain
808 CFReleaseSafe(calendar
);
810 *pl
= CFDateCreate(allocator
, date
);
812 CFReleaseNull(*error
);
819 static CF_RETURNS_RETAINED
820 CFMutableDictionaryRef
s3dl_item_v3_decode(CFDataRef plain
, CFErrorRef
*error
) {
821 CFPropertyListRef item
= NULL
;
822 const uint8_t *der_beg
= CFDataGetBytePtr(plain
);
823 const uint8_t *der_end
= der_beg
+ CFDataGetLength(plain
);
824 const uint8_t *der
= der_decode_plist(0, kCFPropertyListMutableContainers
, &item
, error
, der_beg
, der_end
);
825 if (!der
&& error
&& CFEqualSafe(CFErrorGetDomain(*error
), sSecDERErrorDomain
) && CFErrorGetCode(*error
) == kSecDERErrorUnknownEncoding
) {
826 CFReleaseNull(*error
);
827 der
= der_decode_plist_with_repair(0, kCFPropertyListMutableContainers
, &item
, error
, der_beg
, der_end
, s3dl_item_v3_decode_repair_date
);
829 if (der
&& der
!= der_end
) {
830 SecCFCreateError(errSecDecode
, kSecErrorDomain
, CFSTR("trailing garbage at end of decrypted item"), NULL
, error
);
833 return dictionaryFromPlist(item
, error
);
836 bool s3dl_item_from_data(CFDataRef edata
, Query
*q
, CFArrayRef accessGroups
,
837 CFMutableDictionaryRef
*item
, SecAccessControlRef
*access_control
, CFErrorRef
*error
) {
838 SecAccessControlRef ac
= NULL
;
839 CFDataRef ac_data
= NULL
;
842 /* Decrypt and decode the item and check the decoded attributes against the query. */
843 uint32_t version
= 0;
844 require_quiet((ok
= ks_decrypt_data(q
->q_keybag
, kAKSKeyOpDecrypt
, &ac
, q
->q_use_cred_handle
, edata
, q
->q_class
,
845 q
->q_caller_access_groups
, item
, &version
, error
)), out
);
850 ac_data
= SecAccessControlCopyData(ac
);
851 if (!itemInAccessGroup(*item
, accessGroups
)) {
852 secerror("items accessGroup %@ not in %@",
853 CFDictionaryGetValue(*item
, kSecAttrAccessGroup
),
855 ok
= SecError(errSecDecode
, error
, CFSTR("items accessGroup %@ not in %@"),
856 CFDictionaryGetValue(*item
, kSecAttrAccessGroup
),
858 CFReleaseNull(*item
);
861 /* AccessControl attribute does not exist in the db, so synthesize it. */
863 CFDictionarySetValue(*item
, kSecAttrAccessControl
, ac_data
);
865 /* TODO: Validate access_control attribute. */
869 *access_control
= CFRetainSafe(ac
);
871 CFReleaseSafe(ac_data
);
875 /* Infer accessibility and access group for pre-v2 (iOS4.x and earlier) items
876 being imported from a backup. */
877 static bool SecDbItemImportMigrate(SecDbItemRef item
, CFErrorRef
*error
) {
879 CFStringRef agrp
= SecDbItemGetCachedValueWithName(item
, kSecAttrAccessGroup
);
880 CFStringRef accessible
= SecDbItemGetCachedValueWithName(item
, kSecAttrAccessible
);
882 if (!isString(agrp
) || !isString(accessible
))
884 if (SecDbItemGetClass(item
) == genp_class() && CFEqual(accessible
, kSecAttrAccessibleAlwaysPrivate
)) {
885 CFStringRef svce
= SecDbItemGetCachedValueWithName(item
, kSecAttrService
);
886 if (!isString(svce
)) return ok
;
887 if (CFEqual(agrp
, CFSTR("apple"))) {
888 if (CFEqual(svce
, CFSTR("AirPort"))) {
889 ok
= SecDbItemSetValueWithName(item
, kSecAttrAccessible
, kSecAttrAccessibleAfterFirstUnlock
, error
);
890 } else if (CFEqual(svce
, CFSTR("com.apple.airplay.password"))) {
891 ok
= SecDbItemSetValueWithName(item
, kSecAttrAccessible
, kSecAttrAccessibleWhenUnlocked
, error
);
892 } else if (CFEqual(svce
, CFSTR("YouTube"))) {
893 ok
= (SecDbItemSetValueWithName(item
, kSecAttrAccessible
, kSecAttrAccessibleWhenUnlocked
, error
) &&
894 SecDbItemSetValueWithName(item
, kSecAttrAccessGroup
, CFSTR("com.apple.youtube.credentials"), error
));
896 CFStringRef desc
= SecDbItemGetCachedValueWithName(item
, kSecAttrDescription
);
897 if (!isString(desc
)) return ok
;
898 if (CFEqual(desc
, CFSTR("IPSec Shared Secret")) || CFEqual(desc
, CFSTR("PPP Password"))) {
899 ok
= SecDbItemSetValueWithName(item
, kSecAttrAccessible
, kSecAttrAccessibleAfterFirstUnlock
, error
);
903 } else if (SecDbItemGetClass(item
) == inet_class() && CFEqual(accessible
, kSecAttrAccessibleAlwaysPrivate
)) {
904 if (CFEqual(agrp
, CFSTR("PrintKitAccessGroup"))) {
905 ok
= SecDbItemSetValueWithName(item
, kSecAttrAccessible
, kSecAttrAccessibleWhenUnlocked
, error
);
906 } else if (CFEqual(agrp
, CFSTR("apple"))) {
907 CFTypeRef ptcl
= SecDbItemGetCachedValueWithName(item
, kSecAttrProtocol
);
908 bool is_proxy
= false;
909 if (isNumber(ptcl
)) {
911 CFNumberGetValue(ptcl
, kCFNumberSInt32Type
, &iptcl
);
912 is_proxy
= (iptcl
== FOUR_CHAR_CODE('htpx') ||
913 iptcl
== FOUR_CHAR_CODE('htsx') ||
914 iptcl
== FOUR_CHAR_CODE('ftpx') ||
915 iptcl
== FOUR_CHAR_CODE('rtsx') ||
916 iptcl
== FOUR_CHAR_CODE('xpth') ||
917 iptcl
== FOUR_CHAR_CODE('xsth') ||
918 iptcl
== FOUR_CHAR_CODE('xptf') ||
919 iptcl
== FOUR_CHAR_CODE('xstr'));
920 } else if (isString(ptcl
)) {
921 is_proxy
= (CFEqual(ptcl
, kSecAttrProtocolHTTPProxy
) ||
922 CFEqual(ptcl
, kSecAttrProtocolHTTPSProxy
) ||
923 CFEqual(ptcl
, kSecAttrProtocolRTSPProxy
) ||
924 CFEqual(ptcl
, kSecAttrProtocolFTPProxy
));
927 ok
= SecDbItemSetValueWithName(item
, kSecAttrAccessible
, kSecAttrAccessibleWhenUnlocked
, error
);
933 bool SecDbItemDecrypt(SecDbItemRef item
, CFDataRef edata
, CFErrorRef
*error
) {
935 CFMutableDictionaryRef dict
= NULL
;
936 SecAccessControlRef access_control
= NULL
;
937 uint32_t version
= 0;
939 require_quiet(ok
= ks_decrypt_data(SecDbItemGetKeybag(item
), item
->cryptoOp
, &access_control
, item
->credHandle
, edata
,
940 item
->class, item
->callerAccessGroups
, &dict
, &version
, error
), out
);
943 /* Old V4 style keychain backup being imported. */
944 ok
= SecDbItemSetValueWithName(item
, CFSTR("v_Data"), CFDictionaryGetValue(dict
, CFSTR("v_Data")), error
) &&
945 SecDbItemImportMigrate(item
, error
);
947 ok
= dict
&& SecDbItemSetValues(item
, dict
, error
);
950 SecAccessControlRef my_access_control
= SecDbItemCopyAccessControl(item
, error
);
951 if (!my_access_control
) {
956 /* Make sure that the protection of ACL in the dictionary (read from DB) matched what we got
957 back from decoding the data blob. */
958 if (!CFEqual(SecAccessControlGetProtection(my_access_control
), SecAccessControlGetProtection(access_control
))) {
959 ok
= SecError(errSecDecode
, error
, CFSTR("ACL protection doesn't match the one in blob (%@ : %@)"),
960 SecAccessControlGetProtection(my_access_control
),
961 SecAccessControlGetProtection(access_control
));
963 CFRelease(my_access_control
);
966 // If we got protection back from ks_decrypt_data, update the appropriate attribute even if anything else
967 // (incl. actual decryption) failed. We need to access the protection type even if we are not able to actually
969 ok
= SecDbItemSetAccessControl(item
, access_control
, NULL
) && ok
;
972 CFReleaseSafe(access_control
);
976 /* Automagically make a item syncable, based on various attributes. */
977 bool SecDbItemInferSyncable(SecDbItemRef item
, CFErrorRef
*error
)
979 CFStringRef agrp
= SecDbItemGetCachedValueWithName(item
, kSecAttrAccessGroup
);
984 if (CFEqual(agrp
, CFSTR("com.apple.cfnetwork")) && SecDbItemGetClass(item
) == inet_class()) {
985 CFTypeRef srvr
= SecDbItemGetCachedValueWithName(item
, kSecAttrServer
);
986 CFTypeRef ptcl
= SecDbItemGetCachedValueWithName(item
, kSecAttrProtocol
);
987 CFTypeRef atyp
= SecDbItemGetCachedValueWithName(item
, kSecAttrAuthenticationType
);
989 if (isString(srvr
) && isString(ptcl
) && isString(atyp
)) {
990 /* This looks like a Mobile Safari Password, make syncable */
991 secnotice("item", "Make this item syncable: %@", item
);
992 return SecDbItemSetSyncable(item
, true, error
);
999 /* This create a SecDbItem from the item dictionnary that are exported for backups.
1000 Item are stored in the backup as a dictionary containing two keys:
1001 - v_Data: the encrypted data blob
1002 - v_PersistentRef: a persistent Ref.
1003 src_keybag is normally the backup keybag.
1004 dst_keybag is normally the device keybag.
1006 SecDbItemRef
SecDbItemCreateWithBackupDictionary(CFAllocatorRef allocator
, const SecDbClass
*dbclass
, CFDictionaryRef dict
, keybag_handle_t src_keybag
, keybag_handle_t dst_keybag
, CFErrorRef
*error
)
1008 CFDataRef edata
= CFDictionaryGetValue(dict
, CFSTR("v_Data"));
1009 SecDbItemRef item
= NULL
;
1012 item
= SecDbItemCreateWithEncryptedData(kCFAllocatorDefault
, dbclass
, edata
, src_keybag
, error
);
1014 if (!SecDbItemSetKeybag(item
, dst_keybag
, error
))
1015 CFReleaseNull(item
);
1017 SecError(errSecDecode
, error
, CFSTR("No v_Data in backup dictionary %@"), dict
);
1023 bool SecDbItemExtractRowIdFromBackupDictionary(SecDbItemRef item
, CFDictionaryRef dict
, CFErrorRef
*error
) {
1024 CFDataRef ref
= CFDictionaryGetValue(dict
, CFSTR("v_PersistentRef"));
1026 return SecError(errSecDecode
, error
, CFSTR("No v_PersistentRef in backup dictionary %@"), dict
);
1028 CFStringRef className
;
1029 sqlite3_int64 rowid
;
1030 if (!_SecItemParsePersistentRef(ref
, &className
, &rowid
, NULL
))
1031 return SecError(errSecDecode
, error
, CFSTR("v_PersistentRef %@ failed to decode"), ref
);
1033 if (!CFEqual(SecDbItemGetClass(item
)->name
, className
))
1034 return SecError(errSecDecode
, error
, CFSTR("v_PersistentRef has unexpected class %@"), className
);
1036 return SecDbItemSetRowId(item
, rowid
, error
);
1039 static CFDataRef
SecDbItemCopyDERWithMask(SecDbItemRef item
, CFOptionFlags mask
, CFErrorRef
*error
) {
1040 CFDataRef der
= NULL
;
1041 CFMutableDictionaryRef dict
= SecDbItemCopyPListWithMask(item
, mask
, error
);
1043 der
= CFPropertyListCreateDERData(kCFAllocatorDefault
, dict
, error
);
1049 static CFTypeRef
SecDbItemCopyDigestWithMask(SecDbItemRef item
, CFOptionFlags mask
, CFErrorRef
*error
) {
1050 CFDataRef digest
= NULL
;
1051 CFDataRef der
= SecDbItemCopyDERWithMask(item
, mask
, error
);
1053 digest
= CFDataCopySHA1Digest(der
, error
);
1059 static CFTypeRef
SecDbItemCopySHA256DigestWithMask(SecDbItemRef item
, CFOptionFlags mask
, CFErrorRef
*error
) {
1060 CFDataRef digest
= NULL
;
1061 CFDataRef der
= SecDbItemCopyDERWithMask(item
, mask
, error
);
1063 digest
= CFDataCopySHA256Digest(der
, error
);
1069 CFTypeRef
SecDbKeychainItemCopyPrimaryKey(SecDbItemRef item
, const SecDbAttr
*attr
, CFErrorRef
*error
) {
1070 return SecDbItemCopyDigestWithMask(item
, kSecDbPrimaryKeyFlag
, error
);
1073 CFTypeRef
SecDbKeychainItemCopySHA256PrimaryKey(SecDbItemRef item
, CFErrorRef
*error
) {
1074 return SecDbItemCopySHA256DigestWithMask(item
, kSecDbPrimaryKeyFlag
, error
);
1077 CFTypeRef
SecDbKeychainItemCopySHA1(SecDbItemRef item
, const SecDbAttr
*attr
, CFErrorRef
*error
) {
1078 return SecDbItemCopyDigestWithMask(item
, kSecDbInHashFlag
, error
);
1081 CFTypeRef
SecDbKeychainItemCopyEncryptedData(SecDbItemRef item
, const SecDbAttr
*attr
, CFErrorRef
*error
) {
1082 CFDataRef edata
= NULL
;
1083 CFMutableDictionaryRef attributes
= SecDbItemCopyPListWithMask(item
, kSecDbInCryptoDataFlag
, error
);
1084 CFMutableDictionaryRef auth_attributes
= SecDbItemCopyPListWithMask(item
, kSecDbInAuthenticatedDataFlag
, error
);
1085 if (attributes
|| auth_attributes
) {
1086 SecAccessControlRef access_control
= SecDbItemCopyAccessControl(item
, error
);
1087 if (access_control
) {
1088 if (ks_encrypt_data(item
->keybag
, access_control
, item
->credHandle
, attributes
, auth_attributes
, &edata
, true, error
)) {
1089 item
->_edataState
= kSecDbItemEncrypting
;
1090 } else if (!error
|| !*error
|| CFErrorGetCode(*error
) != errSecAuthNeeded
|| !CFEqualSafe(CFErrorGetDomain(*error
), kSecErrorDomain
) ) {
1091 seccritical("ks_encrypt_data (db): failed: %@", error
? *error
: (CFErrorRef
)CFSTR(""));
1093 CFRelease(access_control
);
1095 CFReleaseSafe(attributes
);
1096 CFReleaseSafe(auth_attributes
);
1102 CFTypeRef
SecDbKeychainItemCopyCurrentDate(SecDbItemRef item
, const SecDbAttr
*attr
, CFErrorRef
*error
) {
1103 CFTypeRef value
= NULL
;
1104 switch (attr
->kind
) {
1105 case kSecDbDateAttr
:
1106 value
= CFDateCreate(kCFAllocatorDefault
, 0.0);
1108 case kSecDbCreationDateAttr
:
1109 case kSecDbModificationDateAttr
:
1110 value
= CFDateCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent());
1113 SecError(errSecInternal
, error
, CFSTR("attr %@ has no default value"), attr
->name
);
1120 SecAccessControlRef
SecDbItemCopyAccessControl(SecDbItemRef item
, CFErrorRef
*error
) {
1121 SecAccessControlRef accc
= NULL
, pdmn
= NULL
, result
= NULL
;
1122 CFTypeRef acccData
= SecDbItemGetValue(item
, SecDbClassAttrWithKind(item
->class, kSecDbAccessControlAttr
, error
), error
);
1123 CFTypeRef pdmnValue
= SecDbItemGetValue(item
, SecDbClassAttrWithKind(item
->class, kSecDbAccessAttr
, error
), error
);
1125 if (!acccData
|| !pdmnValue
)
1127 if (!CFEqual(acccData
, kCFNull
))
1128 require_quiet(accc
= SecAccessControlCreateFromData(CFGetAllocator(item
), acccData
, error
), out
);
1130 if (!CFEqual(pdmnValue
, kCFNull
)) {
1131 require_quiet(pdmn
= SecAccessControlCreate(CFGetAllocator(item
), error
), out
);
1132 require_quiet(SecAccessControlSetProtection(pdmn
, pdmnValue
, error
), out
);
1136 CFTypeRef acccProt
= SecAccessControlGetProtection(accc
);
1137 CFTypeRef pdmnProt
= SecAccessControlGetProtection(pdmn
);
1138 if (!acccProt
|| !pdmnProt
|| !CFEqual(acccProt
, pdmnProt
)) {
1139 secerror("SecDbItemCopyAccessControl accc %@ != pdmn %@, setting pdmn to accc value", acccProt
, pdmnProt
);
1140 __security_simulatecrash(CFSTR("Corrupted item on decrypt accc != pdmn"), __sec_exception_code_CorruptItem
);
1141 // Setting pdmn to accc prot value.
1142 require_quiet(SecDbItemSetValue(item
, SecDbClassAttrWithKind(item
->class, kSecDbAccessAttr
, error
), acccProt
, error
), out
);
1147 CFRetainAssign(result
, accc
);
1149 CFRetainAssign(result
, pdmn
);
1152 CFReleaseSafe(accc
);
1153 CFReleaseSafe(pdmn
);
1158 static const uint8_t* der_decode_plist_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
,
1159 CFPropertyListRef
* pl
, CFErrorRef
*error
,
1160 const uint8_t* der
, const uint8_t *der_end
,
1161 const uint8_t* (^repairBlock
)(CFAllocatorRef
, CFOptionFlags
, CFPropertyListRef
*, CFErrorRef
*,
1162 const uint8_t*, const uint8_t*))
1165 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Null DER"), NULL
, error
);
1170 if (NULL
== ccder_decode_tag(&tag
, der
, der_end
)) {
1171 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding"), NULL
, error
);
1177 return der_decode_null(allocator
, mutability
, (CFNullRef
*)pl
, error
, der
, der_end
);
1179 return der_decode_boolean(allocator
, mutability
, (CFBooleanRef
*)pl
, error
, der
, der_end
);
1180 case CCDER_OCTET_STRING
:
1181 return der_decode_data(allocator
, mutability
, (CFDataRef
*)pl
, error
, der
, der_end
);
1182 case CCDER_GENERALIZED_TIME
: {
1183 const uint8_t* der_result
= der_decode_date(allocator
, mutability
, (CFDateRef
*)pl
, error
, der
, der_end
);
1185 der_result
= repairBlock(allocator
, mutability
, pl
, error
, der
, der_end
);
1189 case CCDER_CONSTRUCTED_SEQUENCE
:
1190 return der_decode_array_with_repair(allocator
, mutability
, (CFArrayRef
*)pl
, error
, der
, der_end
, repairBlock
);
1191 case CCDER_UTF8_STRING
:
1192 return der_decode_string(allocator
, mutability
, (CFStringRef
*)pl
, error
, der
, der_end
);
1194 return der_decode_number(allocator
, mutability
, (CFNumberRef
*)pl
, error
, der
, der_end
);
1195 case CCDER_CONSTRUCTED_SET
:
1196 return der_decode_dictionary_with_repair(allocator
, mutability
, (CFDictionaryRef
*)pl
, error
, der
, der_end
, repairBlock
);
1197 case CCDER_CONSTRUCTED_CFSET
:
1198 return der_decode_set_with_repair(allocator
, mutability
, (CFSetRef
*)pl
, error
, der
, der_end
, repairBlock
);
1200 SecCFDERCreateError(kSecDERErrorUnsupportedDERType
, CFSTR("Unsupported DER Type"), NULL
, error
);
1205 static const uint8_t* der_decode_dictionary_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
,
1206 CFDictionaryRef
* dictionary
, CFErrorRef
*error
,
1207 const uint8_t* der
, const uint8_t *der_end
,
1208 const uint8_t* (^repairBlock
)(CFAllocatorRef
, CFOptionFlags
, CFPropertyListRef
*, CFErrorRef
*,
1209 const uint8_t*, const uint8_t*))
1212 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Null DER"), NULL
, error
);
1216 const uint8_t *payload_end
= 0;
1217 const uint8_t *payload
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SET
, &payload_end
, der
, der_end
);
1219 if (NULL
== payload
) {
1220 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SET"), NULL
, error
);
1225 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1228 SecCFDERCreateError(kSecDERErrorAllocationFailure
, CFSTR("Failed to create dictionary"), NULL
, error
);
1233 while (payload
!= NULL
&& payload
< payload_end
) {
1234 CFTypeRef key
= NULL
;
1235 CFTypeRef value
= NULL
;
1237 payload
= der_decode_key_value_with_repair(allocator
, mutability
, &key
, &value
, error
, payload
, payload_end
, repairBlock
);
1240 CFDictionaryAddValue(dict
, key
, value
);
1244 CFReleaseNull(value
);
1249 if (payload
== payload_end
) {
1254 CFReleaseNull(dict
);
1259 static const uint8_t* der_decode_key_value_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
,
1260 CFPropertyListRef
* key
, CFPropertyListRef
* value
, CFErrorRef
*error
,
1261 const uint8_t* der
, const uint8_t *der_end
,
1262 const uint8_t* (^repairBlock
)(CFAllocatorRef
, CFOptionFlags
, CFPropertyListRef
*, CFErrorRef
*,
1263 const uint8_t*, const uint8_t*))
1265 const uint8_t *payload_end
= 0;
1266 const uint8_t *payload
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &payload_end
, der
, der_end
);
1268 if (NULL
== payload
) {
1269 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SEQUENCE"), NULL
, error
);
1273 CFTypeRef keyObject
= NULL
;
1274 CFTypeRef valueObject
= NULL
;
1277 payload
= der_decode_plist_with_repair(allocator
, mutability
, &keyObject
, error
, payload
, payload_end
, repairBlock
);
1278 payload
= der_decode_plist_with_repair(allocator
, mutability
, &valueObject
, error
, payload
, payload_end
, repairBlock
);
1280 if (payload
!= NULL
) {
1282 *value
= valueObject
;
1284 CFReleaseNull(keyObject
);
1285 CFReleaseNull(valueObject
);
1290 static const uint8_t* der_decode_array_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
,
1291 CFArrayRef
* array
, CFErrorRef
*error
,
1292 const uint8_t* der
, const uint8_t *der_end
,
1293 const uint8_t* (^repairBlock
)(CFAllocatorRef
, CFOptionFlags
, CFPropertyListRef
*, CFErrorRef
*,
1294 const uint8_t*, const uint8_t*))
1297 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Null DER"), NULL
, error
);
1301 CFMutableArrayRef result
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
1303 const uint8_t *elements_end
;
1304 const uint8_t *current_element
= ccder_decode_sequence_tl(&elements_end
, der
, der_end
);
1306 while (current_element
!= NULL
&& current_element
< elements_end
) {
1307 CFPropertyListRef element
= NULL
;
1308 current_element
= der_decode_plist_with_repair(allocator
, mutability
, &element
, error
, current_element
, elements_end
, repairBlock
);
1309 if (current_element
) {
1310 CFArrayAppendValue(result
, element
);
1311 CFReleaseNull(element
);
1315 if (current_element
) {
1320 CFReleaseNull(result
);
1321 return current_element
;
1324 static const uint8_t* der_decode_set_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
,
1325 CFSetRef
* set
, CFErrorRef
*error
,
1326 const uint8_t* der
, const uint8_t *der_end
,
1327 const uint8_t* (^repairBlock
)(CFAllocatorRef
, CFOptionFlags
, CFPropertyListRef
*, CFErrorRef
*,
1328 const uint8_t*, const uint8_t*))
1331 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Null DER"), NULL
, error
);
1335 const uint8_t *payload_end
= 0;
1336 const uint8_t *payload
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_CFSET
, &payload_end
, der
, der_end
);
1338 if (NULL
== payload
) {
1339 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_CFSET"), NULL
, error
);
1343 CFMutableSetRef theSet
= (set
&& *set
) ? CFSetCreateMutableCopy(allocator
, 0, *set
)
1344 : CFSetCreateMutable(allocator
, 0, &kCFTypeSetCallBacks
);
1346 if (NULL
== theSet
) {
1347 SecCFDERCreateError(kSecDERErrorAllocationFailure
, CFSTR("Failed to create set"), NULL
, error
);
1352 while (payload
!= NULL
&& payload
< payload_end
) {
1353 CFTypeRef value
= NULL
;
1355 payload
= der_decode_plist_with_repair(allocator
, mutability
, &value
, error
, payload
, payload_end
, repairBlock
);
1358 CFSetAddValue(theSet
, value
);
1360 CFReleaseNull(value
);
1365 if (set
&& payload
== payload_end
) {
1366 CFTransferRetained(*set
, theSet
);
1369 CFReleaseNull(theSet
);