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 // 0x1e, 0xa0, 0x5c, 0xa9, 0x98, 0x2e, 0x87, 0xdc, 0xf1, 0x45, 0xe8, 0x24
100 static const uint8_t gcmIV
[kIVSizeAESGCM
] = {
101 0x1e, 0xa0, 0x5c, 0xa9, 0x98, 0x2e, 0x87, 0xdc, 0xf1, 0x45, 0xe8, 0x24
105 /* Given plainText create and return a CFDataRef containing:
106 BULK_KEY = RandomKey()
107 version || keyclass|ACL || KeyStore_WRAP(keyclass, BULK_KEY) ||
108 AES(BULK_KEY, NULL_IV, plainText || padding)
110 bool ks_encrypt_data(keybag_handle_t keybag
, SecAccessControlRef access_control
, CFDataRef acm_context
,
111 CFDictionaryRef attributes
, CFDictionaryRef authenticated_attributes
, CFDataRef
*pBlob
, bool useDefaultIV
, CFErrorRef
*error
) {
112 CFMutableDataRef blob
= NULL
;
113 CFDataRef ac_data
= NULL
;
115 //check(keybag >= 0);
117 /* Precalculate output blob length. */
118 const uint32_t bulkKeySize
= 32; /* Use 256 bit AES key for bulkKey. */
119 const uint32_t maxKeyWrapOverHead
= 8 + 32;
120 uint8_t bulkKey
[bulkKeySize
];
121 CFMutableDataRef bulkKeyWrapped
= CFDataCreateMutable(NULL
, 0);
122 CFDataSetLength(bulkKeyWrapped
, bulkKeySize
+ maxKeyWrapOverHead
);
123 uint32_t key_wrapped_size
;
125 const uint8_t *iv
= NULL
;
126 const uint8_t *aad
= NULL
; // Additional Authenticated Data
127 ptrdiff_t aadLen
= 0;
130 CFDataRef auth_data
= NULL
;
133 /* If access_control specifies only protection and no ACL, use legacy blob format version 3,
134 which has better support for sync/backup. Otherwise, force new format v6 unless useDefaultIV is set. */
135 bool hasACLConstraints
= SecAccessControlGetConstraints(access_control
);
136 const uint32_t version
= (hasACLConstraints
? 6 : 3);
137 CFDataRef plainText
= NULL
;
139 CFMutableDictionaryRef attributes_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
140 if (authenticated_attributes
) {
141 CFDictionaryForEach(authenticated_attributes
, ^(const void *key
, const void *value
) {
142 CFDictionaryAddValue(attributes_dict
, key
, value
);
146 if (attributes_dict
) {
147 // Drop the accc attribute for non v6 items during encode.
148 CFDictionaryRemoveValue(attributes_dict
, kSecAttrAccessControl
);
149 plainText
= CFPropertyListCreateDERData(kCFAllocatorDefault
, attributes_dict
, error
);
150 CFRelease(attributes_dict
);
155 plainText
= CFPropertyListCreateDERData(kCFAllocatorDefault
, attributes
, error
);
158 CFMutableDictionaryRef attributes_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, attributes
);
159 if (authenticated_attributes
) {
160 CFDictionaryForEach(authenticated_attributes
, ^(const void *key
, const void *value
) {
161 CFDictionaryAddValue(attributes_dict
, key
, value
);
165 if (attributes_dict
) {
166 plainText
= CFPropertyListCreateDERData(kCFAllocatorDefault
, attributes_dict
, error
);
167 CFRelease(attributes_dict
);
172 if (!plainText
|| CFGetTypeID(plainText
) != CFDataGetTypeID()
173 || access_control
== 0) {
174 ok
= SecError(errSecParam
, error
, CFSTR("ks_encrypt_data: invalid plain text"));
178 size_t ptLen
= CFDataGetLength(plainText
);
179 size_t ctLen
= ptLen
;
181 keyclass_t actual_class
;
183 if (SecRandomCopyBytes(kSecRandomDefault
, bulkKeySize
, bulkKey
)) {
184 ok
= SecError(errSecAllocate
, error
, CFSTR("ks_encrypt_data: SecRandomCopyBytes failed"));
188 /* Extract keyclass from access control. */
189 keyclass_t keyclass
= kc_parse_keyclass(SecAccessControlGetProtection(access_control
), error
);
195 auth_data
= kc_create_auth_data(access_control
, authenticated_attributes
);
196 require_quiet(ok
= ks_encrypt_acl(keybag
, keyclass
, bulkKeySize
, bulkKey
, bulkKeyWrapped
, auth_data
, acm_context
, access_control
, error
), out
);
200 /* Encrypt bulkKey. */
201 require_quiet(ok
= ks_crypt(kAKSKeyOpEncrypt
, keybag
,
202 keyclass
, bulkKeySize
, bulkKey
,
203 &actual_class
, bulkKeyWrapped
,
207 key_wrapped_size
= (uint32_t)CFDataGetLength(bulkKeyWrapped
);
209 size_t blobLen
= sizeof(version
);
210 uint32_t prot_length
;
212 if (!hasACLConstraints
) {
213 blobLen
+= sizeof(actual_class
);
215 require_quiet(ac_data
= kc_copy_protection_data(access_control
), out
);
216 prot_length
= (uint32_t)CFDataGetLength(ac_data
);
217 blobLen
+= sizeof(prot_length
) + prot_length
;
220 blobLen
+= sizeof(key_wrapped_size
) + key_wrapped_size
+ ctLen
+ tagLen
;
221 require_quiet(blob
= CFDataCreateMutable(NULL
, blobLen
), out
);
222 CFDataSetLength(blob
, blobLen
);
223 cursor
= CFDataGetMutableBytePtr(blob
);
225 *((uint32_t *)cursor
) = useDefaultIV
? (version
| kUseDefaultIVMask
) : version
;
226 cursor
+= sizeof(version
);
228 //secerror("class: %d actual class: %d", keyclass, actual_class);
229 if (!hasACLConstraints
) {
230 *((keyclass_t
*)cursor
) = actual_class
;
231 cursor
+= sizeof(keyclass
);
233 *((uint32_t *)cursor
) = prot_length
;
234 cursor
+= sizeof(prot_length
);
236 CFDataGetBytes(ac_data
, CFRangeMake(0, prot_length
), cursor
);
237 cursor
+= prot_length
;
240 *((uint32_t *)cursor
) = key_wrapped_size
;
241 cursor
+= sizeof(key_wrapped_size
);
245 ivLen
= kIVSizeAESGCM
;
246 // AAD is (version || ac_data || key_wrapped_size)
247 aad
= CFDataGetMutableBytePtr(blob
);
248 aadLen
= cursor
- aad
;
251 memcpy(cursor
, CFDataGetBytePtr(bulkKeyWrapped
), key_wrapped_size
);
252 cursor
+= key_wrapped_size
;
254 /* Encrypt the plainText with the bulkKey. */
255 CCCryptorStatus ccerr
= CCCryptorGCM(kCCEncrypt
, kCCAlgorithmAES128
,
256 bulkKey
, bulkKeySize
,
258 aad
, aadLen
, /* auth data */
259 CFDataGetBytePtr(plainText
), ptLen
,
261 cursor
+ ctLen
, &tagLen
);
263 ok
= SecError(errSecInternal
, error
, CFSTR("ks_encrypt_data: CCCryptorGCM failed: %d"), ccerr
);
267 ok
= SecError(errSecInternal
, error
, CFSTR("ks_encrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen
);
272 memset(bulkKey
, 0, sizeof(bulkKey
));
273 CFReleaseSafe(ac_data
);
274 CFReleaseSafe(bulkKeyWrapped
);
275 CFReleaseSafe(plainText
);
283 CFReleaseSafe(auth_data
);
288 /* Given cipherText containing:
289 version || keyclass || KeyStore_WRAP(keyclass, BULK_KEY) ||
290 AES(BULK_KEY, NULL_IV, plainText || padding)
291 return the plainText. */
292 bool ks_decrypt_data(keybag_handle_t keybag
, CFTypeRef cryptoOp
, SecAccessControlRef
*paccess_control
, CFDataRef acm_context
,
293 CFDataRef blob
, const SecDbClass
*db_class
, CFArrayRef caller_access_groups
,
294 CFMutableDictionaryRef
*attributes_p
, uint32_t *version_p
, CFErrorRef
*error
) {
295 const uint32_t v0KeyWrapOverHead
= 8;
296 CFMutableDataRef bulkKey
= CFDataCreateMutable(0, 32); /* Use 256 bit AES key for bulkKey. */
297 CFDataSetLength(bulkKey
, 32); /* Use 256 bit AES key for bulkKey. */
299 SecAccessControlRef access_control
= NULL
;
302 *attributes_p
= NULL
;
306 CFMutableDataRef plainText
= NULL
;
307 CFMutableDictionaryRef attributes
= NULL
;
308 uint32_t version
= 0;
310 const uint8_t *iv
= NULL
;
311 const uint8_t *aad
= NULL
; // Additional Authenticated Data
312 ptrdiff_t aadLen
= 0;
315 CFMutableDictionaryRef authenticated_attributes
= NULL
;
316 CFDataRef caller_access_groups_data
= NULL
;
317 CFDataRef ed_data
= NULL
;
318 aks_ref_key_t ref_key
= NULL
;
322 check((keybag
>= 0) || (keybag
== session_keybag_handle
));
327 ok
= SecError(errSecParam
, error
, CFSTR("ks_decrypt_data: invalid blob"));
331 size_t blobLen
= CFDataGetLength(blob
);
332 const uint8_t *cursor
= CFDataGetBytePtr(blob
);
334 uint32_t wrapped_key_size
;
336 /* Check for underflow, ensuring we have at least one full AES block left. */
337 if (blobLen
< sizeof(version
) + sizeof(keyclass
) +
338 CFDataGetLength(bulkKey
) + v0KeyWrapOverHead
+ 16) {
339 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: Check for underflow"));
343 version
= *((uint32_t *)cursor
);
344 if (version
& kUseDefaultIVMask
) {
345 version
&= ~kUseDefaultIVMask
;
347 ivLen
= kIVSizeAESGCM
;
350 cursor
+= sizeof(version
);
352 size_t minimum_blob_len
= sizeof(version
) + 16;
353 size_t ctLen
= blobLen
- sizeof(version
);
355 bool hasProtectionData
= (version
>= 4);
357 if (hasProtectionData
) {
358 /* Deserialize SecAccessControl object from the blob. */
359 uint32_t prot_length
= *((uint32_t *)cursor
);
360 cursor
+= sizeof(prot_length
);
362 CFTypeRef protection
= kc_copy_protection_from(cursor
, cursor
+ prot_length
);
364 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid ACL"));
368 access_control
= SecAccessControlCreate(NULL
, NULL
);
369 require_quiet(access_control
, out
);
370 ok
= SecAccessControlSetProtection(access_control
, protection
, NULL
);
371 CFRelease(protection
);
373 SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid ACL"));
378 cursor
+= prot_length
;
380 minimum_blob_len
+= sizeof(prot_length
) + prot_length
;
381 ctLen
-= sizeof(prot_length
) + prot_length
;
383 /* Get numeric value of keyclass from the access_control. */
384 keyclass
= kc_parse_keyclass(SecAccessControlGetProtection(access_control
), error
);
386 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid ACL"));
390 keyclass
= *((keyclass_t
*)cursor
);
391 //secerror("class: %d keyclass: %d", keyclass, keyclass & key_class_last);
393 CFTypeRef protection
= kc_encode_keyclass(keyclass
& key_class_last
); // mask out generation
395 CFTypeRef protection
= kc_encode_keyclass(keyclass
);
397 require_action_quiet(protection
, out
, ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid keyclass detected")));
398 require_action_quiet(access_control
= SecAccessControlCreate(kCFAllocatorDefault
, error
), out
,
399 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: SecAccessControlCreate failed")));
400 require_action_quiet(SecAccessControlSetProtection(access_control
, protection
, error
), out
,
401 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: SecAccessControlSetProtection failed")));
403 cursor
+= sizeof(keyclass
);
405 minimum_blob_len
+= sizeof(keyclass
);
406 ctLen
-= sizeof(keyclass
);
412 wrapped_key_size
= (uint32_t)CFDataGetLength(bulkKey
) + v0KeyWrapOverHead
;
417 /* v2 and v3 have the same crypto, just different dictionary encodings. */
418 /* Difference between v3 and v6 is already handled above, so treat v3 as v6. */
423 minimum_blob_len
-= 16; // Remove PKCS7 padding block requirement
424 ctLen
-= tagLen
; // Remove tagLen from ctLen
427 wrapped_key_size
= *((uint32_t *)cursor
);
428 cursor
+= sizeof(wrapped_key_size
);
429 minimum_blob_len
+= sizeof(wrapped_key_size
);
430 ctLen
-= sizeof(wrapped_key_size
);
433 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid version %d"), version
);
437 /* Validate key wrap length against total length */
438 require(blobLen
- minimum_blob_len
- tagLen
>= wrapped_key_size
, out
);
439 ctLen
-= wrapped_key_size
;
440 if (version
< 2 && (ctLen
& 0xF) != 0) {
441 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: invalid version"));
446 if (hasProtectionData
) {
447 if (caller_access_groups
) {
448 caller_access_groups_data
= kc_copy_access_groups_data(caller_access_groups
, error
);
449 require_quiet(ok
= (caller_access_groups_data
!= NULL
), out
);
452 require_quiet(ok
= kc_attribs_key_encrypted_data_from_blob(keybag
, db_class
, cursor
, wrapped_key_size
, access_control
, version
,
453 &authenticated_attributes
, &ref_key
, &ed_data
, error
), out
);
454 if (CFEqual(cryptoOp
, kAKSKeyOpDecrypt
)) {
455 require_quiet(ok
= ks_decrypt_acl(ref_key
, ed_data
, bulkKey
, acm_context
, caller_access_groups_data
, access_control
, error
), out
);
456 } else if (CFEqual(cryptoOp
, kAKSKeyOpDelete
)) {
457 require_quiet(ok
= ks_delete_acl(ref_key
, ed_data
, acm_context
, caller_access_groups_data
, access_control
, error
), out
);
458 attributes
= CFRetainSafe(authenticated_attributes
);
464 /* Now unwrap the bulk key using a key in the keybag. */
465 require_quiet(ok
= ks_crypt(cryptoOp
, keybag
,
466 keyclass
, wrapped_key_size
, cursor
, NULL
, bulkKey
, error
), out
);
470 // AAD is (version || ac_data || key_wrapped_size)
471 aad
= CFDataGetBytePtr(blob
);
472 aadLen
= cursor
- aad
;
475 cursor
+= wrapped_key_size
;
477 plainText
= CFDataCreateMutable(NULL
, ctLen
);
479 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: failed to allocate data for plain text"));
482 CFDataSetLength(plainText
, ctLen
);
484 /* Decrypt the cipherText with the bulkKey. */
485 CCCryptorStatus ccerr
;
488 ccerr
= CCCryptorGCM(kCCDecrypt
, kCCAlgorithmAES128
,
489 CFDataGetBytePtr(bulkKey
), CFDataGetLength(bulkKey
),
491 aad
, aadLen
, /* auth data */
493 CFDataGetMutableBytePtr(plainText
),
496 /* TODO: Should this be errSecDecode once AppleKeyStore correctly
497 identifies uuid unwrap failures? */
498 /* errSecInteractionNotAllowed; */
499 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: CCCryptorGCM failed: %d"), ccerr
);
503 ok
= SecError(errSecInternal
, error
, CFSTR("ks_decrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen
);
507 if (memcmp(tag
, cursor
, tagLen
)) {
508 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: CCCryptorGCM computed tag not same as tag in blob"));
513 ccerr
= CCCrypt(kCCDecrypt
, kCCAlgorithmAES128
, kCCOptionPKCS7Padding
,
514 CFDataGetBytePtr(bulkKey
), CFDataGetLength(bulkKey
), NULL
, cursor
, ctLen
,
515 CFDataGetMutableBytePtr(plainText
), ctLen
, &ptLen
);
517 /* TODO: Should this be errSecDecode once AppleKeyStore correctly
518 identifies uuid unwrap failures? */
519 /* errSecInteractionNotAllowed; */
520 ok
= SecError(errSecDecode
, error
, CFSTR("ks_decrypt_data: CCCrypt failed: %d"), ccerr
);
523 CFDataSetLength(plainText
, ptLen
);
527 attributes
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
528 CFDictionaryAddValue(attributes
, CFSTR("v_Data"), plainText
);
529 } else if (version
< 3) {
530 attributes
= s3dl_item_v2_decode(plainText
, error
);
532 attributes
= s3dl_item_v3_decode(plainText
, error
);
535 require_action_quiet(attributes
, out
, { ok
= false; secerror("decode v%d failed: %@ [item: %@]", version
, error
? *error
: NULL
, plainText
); });
538 if (version
>= 4 && authenticated_attributes
!= NULL
) {
539 CFDictionaryForEach(authenticated_attributes
, ^(const void *key
, const void *value
) {
540 CFDictionaryAddValue(attributes
, key
, value
);
546 memset(CFDataGetMutableBytePtr(bulkKey
), 0, CFDataGetLength(bulkKey
));
547 CFReleaseSafe(bulkKey
);
548 CFReleaseSafe(plainText
);
550 // Always copy access control data (if present), because if we fail it may indicate why.
552 *paccess_control
= access_control
;
554 CFReleaseSafe(access_control
);
558 *attributes_p
= CFRetainSafe(attributes
);
560 *version_p
= version
;
562 CFReleaseSafe(attributes
);
564 CFReleaseSafe(authenticated_attributes
);
565 CFReleaseSafe(caller_access_groups_data
);
566 CFReleaseSafe(ed_data
);
567 if (ref_key
) aks_ref_key_free(&ref_key
);
572 static keyclass_t
kc_parse_keyclass(CFTypeRef value
, CFErrorRef
*error
) {
573 if (!isString(value
)) {
574 SecError(errSecParam
, error
, CFSTR("accessible attribute %@ not a string"), value
);
575 } else if (CFEqual(value
, kSecAttrAccessibleWhenUnlocked
)) {
577 } else if (CFEqual(value
, kSecAttrAccessibleAfterFirstUnlock
)) {
579 } else if (CFEqual(value
, kSecAttrAccessibleAlwaysPrivate
)) {
581 } else if (CFEqual(value
, kSecAttrAccessibleWhenUnlockedThisDeviceOnly
)) {
582 return key_class_aku
;
583 } else if (CFEqual(value
, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
)) {
584 return key_class_cku
;
585 } else if (CFEqual(value
, kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate
)) {
586 return key_class_dku
;
587 } else if (CFEqual(value
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
)) {
588 return key_class_akpu
;
590 SecError(errSecParam
, error
, CFSTR("accessible attribute %@ unknown"), value
);
595 static CFTypeRef
kc_encode_keyclass(keyclass_t keyclass
) {
598 return kSecAttrAccessibleWhenUnlocked
;
600 return kSecAttrAccessibleAfterFirstUnlock
;
602 return kSecAttrAccessibleAlwaysPrivate
;
604 return kSecAttrAccessibleWhenUnlockedThisDeviceOnly
;
606 return kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
;
608 return kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate
;
610 return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
;
617 static bool kc_attribs_key_encrypted_data_from_blob(keybag_handle_t keybag
, const SecDbClass
*class, const void *blob_data
, size_t blob_data_len
, SecAccessControlRef access_control
, uint32_t version
,
618 CFMutableDictionaryRef
*authenticated_attributes
, aks_ref_key_t
*ref_key
, CFDataRef
*encrypted_data
, CFErrorRef
*error
)
621 CFDictionaryRef blob_dict
= NULL
;
622 CFDataRef key_data
= NULL
;
624 aks_ref_key_t tmp_ref_key
= NULL
;
626 der_decode_plist(NULL
, kCFPropertyListImmutable
, (CFPropertyListRef
*)&blob_dict
, NULL
, blob_data
, blob_data
+ blob_data_len
);
627 require_action_quiet(blob_dict
, out
, SecError(errSecDecode
, error
, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'blob data'")));
629 if (!ks_separate_data_and_key(blob_dict
, &ed
, &key_data
)) {
630 ed
= CFDataCreate(kCFAllocatorDefault
, blob_data
, blob_data_len
);
631 key_data
= CFRetain(ed
);
633 require_action_quiet(ed
, out
, SecError(errSecDecode
, error
, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'encrypted data'")));
634 require_action_quiet(key_data
, out
, SecError(errSecDecode
, error
, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'key data'")));
636 CFMutableDictionaryRef acl
= NULL
;
637 const void *external_data
= NULL
;
638 size_t external_data_len
= 0;
639 require_quiet(external_data
= ks_ref_key_get_external_data(keybag
, key_data
, &tmp_ref_key
, &external_data_len
, error
), out
);
641 CFPropertyListRef external_data_dict
= NULL
;
642 der_decode_plist(NULL
, kCFPropertyListImmutable
, &external_data_dict
, NULL
, external_data
, external_data
+ external_data_len
);
643 require_action_quiet(external_data_dict
, out
, SecError(errSecDecode
, error
, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'encrypted data dictionary'")));
644 acl
= CFDictionaryCreateMutableCopy(NULL
, 0, external_data_dict
);
645 SecDbForEachAttrWithMask(class, attr_desc
, kSecDbInAuthenticatedDataFlag
) {
646 CFDictionaryRemoveValue(acl
, attr_desc
->name
);
647 CFTypeRef value
= CFDictionaryGetValue(external_data_dict
, attr_desc
->name
);
649 if (!*authenticated_attributes
)
650 *authenticated_attributes
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
652 CFDictionaryAddValue(*authenticated_attributes
, attr_desc
->name
, value
);
655 CFReleaseSafe(external_data_dict
);
658 /* v4 data format used wrong ACL placement, for backward compatibility we have to support both formats */
660 SecAccessControlSetConstraints(access_control
, acl
);
662 SecAccessControlSetConstraints(access_control
, CFDictionaryGetValue(acl
, kAKSKeyAcl
));
664 /* v4/v5 data format usualy does not contain kAKSKeyOpEncrypt, so add kAKSKeyOpEncrypt if is missing */
666 SecAccessConstraintRef encryptConstraint
= SecAccessControlGetConstraint(access_control
, kAKSKeyOpEncrypt
);
667 if (!encryptConstraint
)
668 SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpEncrypt
, kCFBooleanTrue
, NULL
);
675 *encrypted_data
= CFRetain(ed
);
678 *ref_key
= tmp_ref_key
;
686 aks_ref_key_free(&tmp_ref_key
);
687 CFReleaseSafe(blob_dict
);
688 CFReleaseSafe(key_data
);
694 static CFDataRef
kc_create_auth_data(SecAccessControlRef access_control
, CFDictionaryRef auth_attributes
) {
695 CFDictionaryRef constraints
= SecAccessControlGetConstraints(access_control
);
696 CFMutableDictionaryRef auth_data
= CFDictionaryCreateMutableCopy(NULL
, 0, auth_attributes
);
697 CFDictionarySetValue(auth_data
, kAKSKeyAcl
, constraints
);
698 CFDataRef encoded
= CFPropertyListCreateDERData(kCFAllocatorDefault
, auth_data
, NULL
);
699 CFReleaseSafe(auth_data
);
703 static CFDataRef
kc_copy_access_groups_data(CFArrayRef access_groups
, CFErrorRef
*error
)
705 size_t ag_size
= der_sizeof_plist(access_groups
, error
);
706 CFMutableDataRef result
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
707 CFDataSetLength(result
, ag_size
);
708 if (!der_encode_plist(access_groups
, error
, CFDataGetMutableBytePtr(result
), CFDataGetMutableBytePtr(result
) + ag_size
)) {
716 #endif /* USE_KEYSTORE */
718 static CFDataRef
kc_copy_protection_data(SecAccessControlRef access_control
)
720 CFTypeRef protection
= SecAccessControlGetProtection(access_control
);
721 size_t protection_size
= der_sizeof_plist(protection
, NULL
);
722 CFMutableDataRef result
= CFDataCreateMutable(NULL
, 0);
723 CFDataSetLength(result
, protection_size
);
724 if (!der_encode_plist(protection
, NULL
, CFDataGetMutableBytePtr(result
), CFDataGetMutableBytePtr(result
) + protection_size
)) {
732 static CFTypeRef
kc_copy_protection_from(const uint8_t *der
, const uint8_t *der_end
)
734 CFTypeRef result
= NULL
;
735 der_decode_plist(NULL
, kCFPropertyListImmutable
, &result
, NULL
, der
, der_end
);
739 /* Return a (mutable) dictionary if plist is a dictionary, return NULL and set error otherwise. Does nothing if plist is already NULL. */
740 static CF_RETURNS_RETAINED
741 CFMutableDictionaryRef
dictionaryFromPlist(CFPropertyListRef plist CF_CONSUMED
, CFErrorRef
*error
) {
742 if (plist
&& !isDictionary(plist
)) {
743 CFStringRef typeName
= CFCopyTypeIDDescription(CFGetTypeID((CFTypeRef
)plist
));
744 SecError(errSecDecode
, error
, CFSTR("plist is a %@, expecting a dictionary"), typeName
);
745 CFReleaseSafe(typeName
);
746 CFReleaseNull(plist
);
748 return (CFMutableDictionaryRef
)plist
;
751 static CF_RETURNS_RETAINED
752 CFMutableDictionaryRef
s3dl_item_v2_decode(CFDataRef plain
, CFErrorRef
*error
) {
753 CFPropertyListRef item
;
754 item
= CFPropertyListCreateWithData(0, plain
, kCFPropertyListMutableContainers
, NULL
, error
);
755 return dictionaryFromPlist(item
, error
);
758 static const uint8_t* (^s3dl_item_v3_decode_repair_date
)(CFAllocatorRef
, CFOptionFlags
, CFPropertyListRef
*, CFErrorRef
*, const uint8_t*, const uint8_t*) =
759 ^const uint8_t*(CFAllocatorRef allocator
, CFOptionFlags mutability
, CFPropertyListRef
* pl
, CFErrorRef
*error
, const uint8_t* der
, const uint8_t *der_end
) {
760 if (error
&& CFEqualSafe(CFErrorGetDomain(*error
), sSecDERErrorDomain
) && CFErrorGetCode(*error
) == kSecDERErrorUnknownEncoding
) {
761 CFAbsoluteTime date
= 0;
762 CFCalendarRef calendar
= CFCalendarCreateWithIdentifier(allocator
, kCFGregorianCalendar
);
763 CFTimeZoneRef tz
= CFTimeZoneCreateWithTimeIntervalFromGMT(allocator
, 0);
764 CFCalendarSetTimeZone(calendar
, tz
);
765 CFCalendarComposeAbsoluteTime(calendar
, &date
, "yMd", 2001, 3, 24); // random date for <rdar://problem/20458954> 15A143: can't recover keychain
767 CFReleaseSafe(calendar
);
769 *pl
= CFDateCreate(allocator
, date
);
771 CFReleaseNull(*error
);
778 static CF_RETURNS_RETAINED
779 CFMutableDictionaryRef
s3dl_item_v3_decode(CFDataRef plain
, CFErrorRef
*error
) {
780 CFPropertyListRef item
= NULL
;
781 const uint8_t *der_beg
= CFDataGetBytePtr(plain
);
782 const uint8_t *der_end
= der_beg
+ CFDataGetLength(plain
);
783 const uint8_t *der
= der_decode_plist(0, kCFPropertyListMutableContainers
, &item
, error
, der_beg
, der_end
);
784 if (!der
&& error
&& CFEqualSafe(CFErrorGetDomain(*error
), sSecDERErrorDomain
) && CFErrorGetCode(*error
) == kSecDERErrorUnknownEncoding
) {
785 CFReleaseNull(*error
);
786 der
= der_decode_plist_with_repair(0, kCFPropertyListMutableContainers
, &item
, error
, der_beg
, der_end
, s3dl_item_v3_decode_repair_date
);
788 if (der
&& der
!= der_end
) {
789 SecCFCreateError(errSecDecode
, kSecErrorDomain
, CFSTR("trailing garbage at end of decrypted item"), NULL
, error
);
792 return dictionaryFromPlist(item
, error
);
795 bool s3dl_item_from_data(CFDataRef edata
, Query
*q
, CFArrayRef accessGroups
,
796 CFMutableDictionaryRef
*item
, SecAccessControlRef
*access_control
, CFErrorRef
*error
) {
797 SecAccessControlRef ac
= NULL
;
798 CFDataRef ac_data
= NULL
;
801 /* Decrypt and decode the item and check the decoded attributes against the query. */
802 uint32_t version
= 0;
803 require_quiet((ok
= ks_decrypt_data(q
->q_keybag
, kAKSKeyOpDecrypt
, &ac
, q
->q_use_cred_handle
, edata
, q
->q_class
,
804 q
->q_caller_access_groups
, item
, &version
, error
)), out
);
809 ac_data
= SecAccessControlCopyData(ac
);
810 if (!itemInAccessGroup(*item
, accessGroups
)) {
811 secerror("items accessGroup %@ not in %@",
812 CFDictionaryGetValue(*item
, kSecAttrAccessGroup
),
814 ok
= SecError(errSecDecode
, error
, CFSTR("items accessGroup %@ not in %@"),
815 CFDictionaryGetValue(*item
, kSecAttrAccessGroup
),
817 CFReleaseNull(*item
);
820 /* AccessControl attribute does not exist in the db, so synthesize it. */
822 CFDictionarySetValue(*item
, kSecAttrAccessControl
, ac_data
);
824 /* TODO: Validate access_control attribute. */
828 *access_control
= CFRetainSafe(ac
);
830 CFReleaseSafe(ac_data
);
834 /* Infer accessibility and access group for pre-v2 (iOS4.x and earlier) items
835 being imported from a backup. */
836 static bool SecDbItemImportMigrate(SecDbItemRef item
, CFErrorRef
*error
) {
838 CFStringRef agrp
= SecDbItemGetCachedValueWithName(item
, kSecAttrAccessGroup
);
839 CFStringRef accessible
= SecDbItemGetCachedValueWithName(item
, kSecAttrAccessible
);
841 if (!isString(agrp
) || !isString(accessible
))
843 if (SecDbItemGetClass(item
) == &genp_class
&& CFEqual(accessible
, kSecAttrAccessibleAlwaysPrivate
)) {
844 CFStringRef svce
= SecDbItemGetCachedValueWithName(item
, kSecAttrService
);
845 if (!isString(svce
)) return ok
;
846 if (CFEqual(agrp
, CFSTR("apple"))) {
847 if (CFEqual(svce
, CFSTR("AirPort"))) {
848 ok
= SecDbItemSetValueWithName(item
, kSecAttrAccessible
, kSecAttrAccessibleAfterFirstUnlock
, error
);
849 } else if (CFEqual(svce
, CFSTR("com.apple.airplay.password"))) {
850 ok
= SecDbItemSetValueWithName(item
, kSecAttrAccessible
, kSecAttrAccessibleWhenUnlocked
, error
);
851 } else if (CFEqual(svce
, CFSTR("YouTube"))) {
852 ok
= (SecDbItemSetValueWithName(item
, kSecAttrAccessible
, kSecAttrAccessibleWhenUnlocked
, error
) &&
853 SecDbItemSetValueWithName(item
, kSecAttrAccessGroup
, CFSTR("com.apple.youtube.credentials"), error
));
855 CFStringRef desc
= SecDbItemGetCachedValueWithName(item
, kSecAttrDescription
);
856 if (!isString(desc
)) return ok
;
857 if (CFEqual(desc
, CFSTR("IPSec Shared Secret")) || CFEqual(desc
, CFSTR("PPP Password"))) {
858 ok
= SecDbItemSetValueWithName(item
, kSecAttrAccessible
, kSecAttrAccessibleAfterFirstUnlock
, error
);
862 } else if (SecDbItemGetClass(item
) == &inet_class
&& CFEqual(accessible
, kSecAttrAccessibleAlwaysPrivate
)) {
863 if (CFEqual(agrp
, CFSTR("PrintKitAccessGroup"))) {
864 ok
= SecDbItemSetValueWithName(item
, kSecAttrAccessible
, kSecAttrAccessibleWhenUnlocked
, error
);
865 } else if (CFEqual(agrp
, CFSTR("apple"))) {
866 CFTypeRef ptcl
= SecDbItemGetCachedValueWithName(item
, kSecAttrProtocol
);
867 bool is_proxy
= false;
868 if (isNumber(ptcl
)) {
870 CFNumberGetValue(ptcl
, kCFNumberSInt32Type
, &iptcl
);
871 is_proxy
= (iptcl
== FOUR_CHAR_CODE('htpx') ||
872 iptcl
== FOUR_CHAR_CODE('htsx') ||
873 iptcl
== FOUR_CHAR_CODE('ftpx') ||
874 iptcl
== FOUR_CHAR_CODE('rtsx') ||
875 iptcl
== FOUR_CHAR_CODE('xpth') ||
876 iptcl
== FOUR_CHAR_CODE('xsth') ||
877 iptcl
== FOUR_CHAR_CODE('xptf') ||
878 iptcl
== FOUR_CHAR_CODE('xstr'));
879 } else if (isString(ptcl
)) {
880 is_proxy
= (CFEqual(ptcl
, kSecAttrProtocolHTTPProxy
) ||
881 CFEqual(ptcl
, kSecAttrProtocolHTTPSProxy
) ||
882 CFEqual(ptcl
, kSecAttrProtocolRTSPProxy
) ||
883 CFEqual(ptcl
, kSecAttrProtocolFTPProxy
));
886 ok
= SecDbItemSetValueWithName(item
, kSecAttrAccessible
, kSecAttrAccessibleWhenUnlocked
, error
);
892 bool SecDbItemDecrypt(SecDbItemRef item
, CFDataRef edata
, CFErrorRef
*error
) {
894 CFMutableDictionaryRef dict
= NULL
;
895 SecAccessControlRef access_control
= NULL
;
896 uint32_t version
= 0;
898 require_quiet(ok
= ks_decrypt_data(SecDbItemGetKeybag(item
), item
->cryptoOp
, &access_control
, item
->credHandle
, edata
,
899 item
->class, item
->callerAccessGroups
, &dict
, &version
, error
), out
);
902 /* Old V4 style keychain backup being imported. */
903 ok
= SecDbItemSetValueWithName(item
, CFSTR("v_Data"), CFDictionaryGetValue(dict
, CFSTR("v_Data")), error
) &&
904 SecDbItemImportMigrate(item
, error
);
906 ok
= dict
&& SecDbItemSetValues(item
, dict
, error
);
909 SecAccessControlRef my_access_control
= SecDbItemCopyAccessControl(item
, error
);
910 if (!my_access_control
) {
915 /* Make sure that the protection of ACL in the dictionary (read from DB) matched what we got
916 back from decoding the data blob. */
917 if (!CFEqual(SecAccessControlGetProtection(my_access_control
), SecAccessControlGetProtection(access_control
))) {
918 ok
= SecError(errSecDecode
, error
, CFSTR("ACL protection doesn't match the one in blob (%@ : %@)"),
919 SecAccessControlGetProtection(my_access_control
),
920 SecAccessControlGetProtection(access_control
));
922 CFRelease(my_access_control
);
925 // If we got protection back from ks_decrypt_data, update the appropriate attribute even if anything else
926 // (incl. actual decryption) failed. We need to access the protection type even if we are not able to actually
928 ok
= SecDbItemSetAccessControl(item
, access_control
, NULL
) && ok
;
931 CFReleaseSafe(access_control
);
935 /* Automagically make a item syncable, based on various attributes. */
936 bool SecDbItemInferSyncable(SecDbItemRef item
, CFErrorRef
*error
)
938 CFStringRef agrp
= SecDbItemGetCachedValueWithName(item
, kSecAttrAccessGroup
);
943 if (CFEqual(agrp
, CFSTR("com.apple.cfnetwork")) && SecDbItemGetClass(item
) == &inet_class
) {
944 CFTypeRef srvr
= SecDbItemGetCachedValueWithName(item
, kSecAttrServer
);
945 CFTypeRef ptcl
= SecDbItemGetCachedValueWithName(item
, kSecAttrProtocol
);
946 CFTypeRef atyp
= SecDbItemGetCachedValueWithName(item
, kSecAttrAuthenticationType
);
948 if (isString(srvr
) && isString(ptcl
) && isString(atyp
)) {
949 /* This looks like a Mobile Safari Password, make syncable */
950 secnotice("item", "Make this item syncable: %@", item
);
951 return SecDbItemSetSyncable(item
, true, error
);
958 /* This create a SecDbItem from the item dictionnary that are exported for backups.
959 Item are stored in the backup as a dictionary containing two keys:
960 - v_Data: the encrypted data blob
961 - v_PersistentRef: a persistent Ref.
962 src_keybag is normally the backup keybag.
963 dst_keybag is normally the device keybag.
965 SecDbItemRef
SecDbItemCreateWithBackupDictionary(CFAllocatorRef allocator
, const SecDbClass
*dbclass
, CFDictionaryRef dict
, keybag_handle_t src_keybag
, keybag_handle_t dst_keybag
, CFErrorRef
*error
)
967 CFDataRef edata
= CFDictionaryGetValue(dict
, CFSTR("v_Data"));
968 SecDbItemRef item
= NULL
;
971 item
= SecDbItemCreateWithEncryptedData(kCFAllocatorDefault
, dbclass
, edata
, src_keybag
, error
);
973 if (!SecDbItemSetKeybag(item
, dst_keybag
, error
))
976 SecError(errSecDecode
, error
, CFSTR("No v_Data in backup dictionary %@"), dict
);
982 bool SecDbItemExtractRowIdFromBackupDictionary(SecDbItemRef item
, CFDictionaryRef dict
, CFErrorRef
*error
) {
983 CFDataRef ref
= CFDictionaryGetValue(dict
, CFSTR("v_PersistentRef"));
985 return SecError(errSecDecode
, error
, CFSTR("No v_PersistentRef in backup dictionary %@"), dict
);
987 CFStringRef className
;
989 if (!_SecItemParsePersistentRef(ref
, &className
, &rowid
))
990 return SecError(errSecDecode
, error
, CFSTR("v_PersistentRef %@ failed to decode"), ref
);
992 if (!CFEqual(SecDbItemGetClass(item
)->name
, className
))
993 return SecError(errSecDecode
, error
, CFSTR("v_PersistentRef has unexpected class %@"), className
);
995 return SecDbItemSetRowId(item
, rowid
, error
);
998 static CFDataRef
SecDbItemCopyDERWithMask(SecDbItemRef item
, CFOptionFlags mask
, CFErrorRef
*error
) {
999 CFDataRef der
= NULL
;
1000 CFMutableDictionaryRef dict
= SecDbItemCopyPListWithMask(item
, mask
, error
);
1002 der
= CFPropertyListCreateDERData(kCFAllocatorDefault
, dict
, error
);
1008 static CFTypeRef
SecDbItemCopyDigestWithMask(SecDbItemRef item
, CFOptionFlags mask
, CFErrorRef
*error
) {
1009 CFDataRef digest
= NULL
;
1010 CFDataRef der
= SecDbItemCopyDERWithMask(item
, mask
, error
);
1012 digest
= CFDataCopySHA1Digest(der
, error
);
1018 CFTypeRef
SecDbKeychainItemCopyPrimaryKey(SecDbItemRef item
, const SecDbAttr
*attr
, CFErrorRef
*error
) {
1019 return SecDbItemCopyDigestWithMask(item
, kSecDbPrimaryKeyFlag
, error
);
1022 CFTypeRef
SecDbKeychainItemCopySHA1(SecDbItemRef item
, const SecDbAttr
*attr
, CFErrorRef
*error
) {
1023 return SecDbItemCopyDigestWithMask(item
, kSecDbInHashFlag
, error
);
1026 CFTypeRef
SecDbKeychainItemCopyEncryptedData(SecDbItemRef item
, const SecDbAttr
*attr
, CFErrorRef
*error
) {
1027 CFDataRef edata
= NULL
;
1028 CFMutableDictionaryRef attributes
= SecDbItemCopyPListWithMask(item
, kSecDbInCryptoDataFlag
, error
);
1029 CFMutableDictionaryRef auth_attributes
= SecDbItemCopyPListWithMask(item
, kSecDbInAuthenticatedDataFlag
, error
);
1030 if (attributes
|| auth_attributes
) {
1031 SecAccessControlRef access_control
= SecDbItemCopyAccessControl(item
, error
);
1032 if (access_control
) {
1033 if (ks_encrypt_data(item
->keybag
, access_control
, item
->credHandle
, attributes
, auth_attributes
, &edata
, true, error
)) {
1034 item
->_edataState
= kSecDbItemEncrypting
;
1035 } else if (!error
|| !*error
|| CFErrorGetCode(*error
) != errSecAuthNeeded
|| !CFEqualSafe(CFErrorGetDomain(*error
), kSecErrorDomain
) ) {
1036 seccritical("ks_encrypt_data (db): failed: %@", error
? *error
: (CFErrorRef
)CFSTR(""));
1038 CFRelease(access_control
);
1040 CFReleaseSafe(attributes
);
1041 CFReleaseSafe(auth_attributes
);
1047 CFTypeRef
SecDbKeychainItemCopyCurrentDate(SecDbItemRef item
, const SecDbAttr
*attr
, CFErrorRef
*error
) {
1048 CFTypeRef value
= NULL
;
1049 switch (attr
->kind
) {
1050 case kSecDbDateAttr
:
1051 value
= CFDateCreate(kCFAllocatorDefault
, 0.0);
1053 case kSecDbCreationDateAttr
:
1054 case kSecDbModificationDateAttr
:
1055 value
= CFDateCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent());
1058 SecError(errSecInternal
, error
, CFSTR("attr %@ has no default value"), attr
->name
);
1065 SecAccessControlRef
SecDbItemCopyAccessControl(SecDbItemRef item
, CFErrorRef
*error
) {
1066 SecAccessControlRef accc
= NULL
, pdmn
= NULL
, result
= NULL
;
1067 CFTypeRef acccData
= SecDbItemGetValue(item
, SecDbClassAttrWithKind(item
->class, kSecDbAccessControlAttr
, error
), error
);
1068 CFTypeRef pdmnValue
= SecDbItemGetValue(item
, SecDbClassAttrWithKind(item
->class, kSecDbAccessAttr
, error
), error
);
1070 if (!acccData
|| !pdmnValue
)
1072 if (!CFEqual(acccData
, kCFNull
))
1073 require_quiet(accc
= SecAccessControlCreateFromData(CFGetAllocator(item
), acccData
, error
), out
);
1075 if (!CFEqual(pdmnValue
, kCFNull
)) {
1076 require_quiet(pdmn
= SecAccessControlCreate(CFGetAllocator(item
), error
), out
);
1077 require_quiet(SecAccessControlSetProtection(pdmn
, pdmnValue
, error
), out
);
1081 CFTypeRef acccProt
= SecAccessControlGetProtection(accc
);
1082 CFTypeRef pdmnProt
= SecAccessControlGetProtection(pdmn
);
1083 if (!acccProt
|| !pdmnProt
|| !CFEqual(acccProt
, pdmnProt
)) {
1084 secerror("SecDbItemCopyAccessControl accc %@ != pdmn %@, setting pdmn to accc value", acccProt
, pdmnProt
);
1085 __security_simulatecrash(CFSTR("Corrupted item on decrypt accc != pdmn"), __sec_exception_code_CorruptItem
);
1086 // Setting pdmn to accc prot value.
1087 require_quiet(SecDbItemSetValue(item
, SecDbClassAttrWithKind(item
->class, kSecDbAccessAttr
, error
), acccProt
, error
), out
);
1092 CFRetainAssign(result
, accc
);
1094 CFRetainAssign(result
, pdmn
);
1097 CFReleaseSafe(accc
);
1098 CFReleaseSafe(pdmn
);
1103 static const uint8_t* der_decode_plist_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
,
1104 CFPropertyListRef
* pl
, CFErrorRef
*error
,
1105 const uint8_t* der
, const uint8_t *der_end
,
1106 const uint8_t* (^repairBlock
)(CFAllocatorRef
, CFOptionFlags
, CFPropertyListRef
*, CFErrorRef
*,
1107 const uint8_t*, const uint8_t*))
1110 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Null DER"), NULL
, error
);
1115 if (NULL
== ccder_decode_tag(&tag
, der
, der_end
)) {
1116 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding"), NULL
, error
);
1122 return der_decode_null(allocator
, mutability
, (CFNullRef
*)pl
, error
, der
, der_end
);
1124 return der_decode_boolean(allocator
, mutability
, (CFBooleanRef
*)pl
, error
, der
, der_end
);
1125 case CCDER_OCTET_STRING
:
1126 return der_decode_data(allocator
, mutability
, (CFDataRef
*)pl
, error
, der
, der_end
);
1127 case CCDER_GENERALIZED_TIME
: {
1128 const uint8_t* der_result
= der_decode_date(allocator
, mutability
, (CFDateRef
*)pl
, error
, der
, der_end
);
1130 der_result
= repairBlock(allocator
, mutability
, pl
, error
, der
, der_end
);
1134 case CCDER_CONSTRUCTED_SEQUENCE
:
1135 return der_decode_array_with_repair(allocator
, mutability
, (CFArrayRef
*)pl
, error
, der
, der_end
, repairBlock
);
1136 case CCDER_UTF8_STRING
:
1137 return der_decode_string(allocator
, mutability
, (CFStringRef
*)pl
, error
, der
, der_end
);
1139 return der_decode_number(allocator
, mutability
, (CFNumberRef
*)pl
, error
, der
, der_end
);
1140 case CCDER_CONSTRUCTED_SET
:
1141 return der_decode_dictionary_with_repair(allocator
, mutability
, (CFDictionaryRef
*)pl
, error
, der
, der_end
, repairBlock
);
1142 case CCDER_CONSTRUCTED_CFSET
:
1143 return der_decode_set_with_repair(allocator
, mutability
, (CFSetRef
*)pl
, error
, der
, der_end
, repairBlock
);
1145 SecCFDERCreateError(kSecDERErrorUnsupportedDERType
, CFSTR("Unsupported DER Type"), NULL
, error
);
1150 static const uint8_t* der_decode_dictionary_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
,
1151 CFDictionaryRef
* dictionary
, CFErrorRef
*error
,
1152 const uint8_t* der
, const uint8_t *der_end
,
1153 const uint8_t* (^repairBlock
)(CFAllocatorRef
, CFOptionFlags
, CFPropertyListRef
*, CFErrorRef
*,
1154 const uint8_t*, const uint8_t*))
1157 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Null DER"), NULL
, error
);
1161 const uint8_t *payload_end
= 0;
1162 const uint8_t *payload
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SET
, &payload_end
, der
, der_end
);
1164 if (NULL
== payload
) {
1165 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SET"), NULL
, error
);
1170 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1173 SecCFDERCreateError(kSecDERErrorAllocationFailure
, CFSTR("Failed to create dictionary"), NULL
, error
);
1178 while (payload
!= NULL
&& payload
< payload_end
) {
1179 CFTypeRef key
= NULL
;
1180 CFTypeRef value
= NULL
;
1182 payload
= der_decode_key_value_with_repair(allocator
, mutability
, &key
, &value
, error
, payload
, payload_end
, repairBlock
);
1185 CFDictionaryAddValue(dict
, key
, value
);
1189 CFReleaseNull(value
);
1194 if (payload
== payload_end
) {
1199 CFReleaseNull(dict
);
1204 static const uint8_t* der_decode_key_value_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
,
1205 CFPropertyListRef
* key
, CFPropertyListRef
* value
, CFErrorRef
*error
,
1206 const uint8_t* der
, const uint8_t *der_end
,
1207 const uint8_t* (^repairBlock
)(CFAllocatorRef
, CFOptionFlags
, CFPropertyListRef
*, CFErrorRef
*,
1208 const uint8_t*, const uint8_t*))
1210 const uint8_t *payload_end
= 0;
1211 const uint8_t *payload
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &payload_end
, der
, der_end
);
1213 if (NULL
== payload
) {
1214 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SEQUENCE"), NULL
, error
);
1218 CFTypeRef keyObject
= NULL
;
1219 CFTypeRef valueObject
= NULL
;
1222 payload
= der_decode_plist_with_repair(allocator
, mutability
, &keyObject
, error
, payload
, payload_end
, repairBlock
);
1223 payload
= der_decode_plist_with_repair(allocator
, mutability
, &valueObject
, error
, payload
, payload_end
, repairBlock
);
1225 if (payload
!= NULL
) {
1227 *value
= valueObject
;
1229 CFReleaseNull(keyObject
);
1230 CFReleaseNull(valueObject
);
1235 static const uint8_t* der_decode_array_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
,
1236 CFArrayRef
* array
, CFErrorRef
*error
,
1237 const uint8_t* der
, const uint8_t *der_end
,
1238 const uint8_t* (^repairBlock
)(CFAllocatorRef
, CFOptionFlags
, CFPropertyListRef
*, CFErrorRef
*,
1239 const uint8_t*, const uint8_t*))
1242 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Null DER"), NULL
, error
);
1246 CFMutableArrayRef result
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
1248 const uint8_t *elements_end
;
1249 const uint8_t *current_element
= ccder_decode_sequence_tl(&elements_end
, der
, der_end
);
1251 while (current_element
!= NULL
&& current_element
< elements_end
) {
1252 CFPropertyListRef element
= NULL
;
1253 current_element
= der_decode_plist_with_repair(allocator
, mutability
, &element
, error
, current_element
, elements_end
, repairBlock
);
1254 if (current_element
) {
1255 CFArrayAppendValue(result
, element
);
1256 CFReleaseNull(element
);
1260 if (current_element
) {
1265 CFReleaseNull(result
);
1266 return current_element
;
1269 static const uint8_t* der_decode_set_with_repair(CFAllocatorRef allocator
, CFOptionFlags mutability
,
1270 CFSetRef
* set
, CFErrorRef
*error
,
1271 const uint8_t* der
, const uint8_t *der_end
,
1272 const uint8_t* (^repairBlock
)(CFAllocatorRef
, CFOptionFlags
, CFPropertyListRef
*, CFErrorRef
*,
1273 const uint8_t*, const uint8_t*))
1276 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Null DER"), NULL
, error
);
1280 const uint8_t *payload_end
= 0;
1281 const uint8_t *payload
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_CFSET
, &payload_end
, der
, der_end
);
1283 if (NULL
== payload
) {
1284 SecCFDERCreateError(kSecDERErrorUnknownEncoding
, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_CFSET"), NULL
, error
);
1288 CFMutableSetRef theSet
= (set
&& *set
) ? CFSetCreateMutableCopy(allocator
, 0, *set
)
1289 : CFSetCreateMutable(allocator
, 0, &kCFTypeSetCallBacks
);
1291 if (NULL
== theSet
) {
1292 SecCFDERCreateError(kSecDERErrorAllocationFailure
, CFSTR("Failed to create set"), NULL
, error
);
1297 while (payload
!= NULL
&& payload
< payload_end
) {
1298 CFTypeRef value
= NULL
;
1300 payload
= der_decode_plist_with_repair(allocator
, mutability
, &value
, error
, payload
, payload_end
, repairBlock
);
1303 CFSetAddValue(theSet
, value
);
1305 CFReleaseNull(value
);
1310 if (set
&& payload
== payload_end
) {
1311 CFTransferRetained(*set
, theSet
);
1314 CFReleaseNull(theSet
);