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 * SecKeybagSupport.c - CoreFoundation-based constants and functions for
26 access to Security items (certificates, keys, identities, and
30 #include <securityd/SecKeybagSupport.h>
32 #include <securityd/SecItemServer.h>
35 #include <IOKit/IOKitLib.h>
37 #include <libaks_acl_cf_keys.h>
38 #include <utilities/der_plist.h>
39 #include <corecrypto/ccder.h>
41 #if TARGET_OS_EMBEDDED
42 #include <MobileKeyBag/MobileKeyBag.h>
44 #else /* !USE_KEYSTORE */
45 #include <utilities/SecInternalReleasePriv.h>
46 #endif /* USE_KEYSTORE */
48 #include <CommonCrypto/CommonCryptor.h>
49 #include <CommonCrypto/CommonCryptorSPI.h>
52 /* g_keychain_handle is the keybag handle used for encrypting item in the keychain.
53 For testing purposes, it can be set to something other than the default, with SecItemServerSetKeychainKeybag */
55 #if TARGET_OS_MAC && !TARGET_OS_EMBEDDED
56 keybag_handle_t g_keychain_keybag
= session_keybag_handle
;
58 keybag_handle_t g_keychain_keybag
= device_keybag_handle
;
60 #else /* !USE_KEYSTORE */
61 keybag_handle_t g_keychain_keybag
= 0; /* 0 == device_keybag_handle, constant dictated by AKS */
62 #endif /* USE_KEYSTORE */
64 const CFStringRef kSecKSKeyData1
= CFSTR("d1");
65 const CFStringRef kSecKSKeyData2
= CFSTR("d2");
67 void SecItemServerSetKeychainKeybag(int32_t keybag
)
69 g_keychain_keybag
=keybag
;
72 void SecItemServerResetKeychainKeybag(void)
75 #if TARGET_OS_MAC && !TARGET_OS_EMBEDDED
76 g_keychain_keybag
= session_keybag_handle
;
78 g_keychain_keybag
= device_keybag_handle
;
80 #else /* !USE_KEYSTORE */
81 g_keychain_keybag
= 0; /* 0 == device_keybag_handle, constant dictated by AKS */
82 #endif /* USE_KEYSTORE */
87 static bool hwaes_key_available(void)
89 keybag_handle_t handle
= bad_keybag_handle
;
90 keybag_handle_t special_handle
= bad_keybag_handle
;
92 special_handle
= session_keybag_handle
;
93 #elif TARGET_OS_EMBEDDED
94 special_handle
= device_keybag_handle
;
96 #error "supported keybag target"
99 kern_return_t kr
= aks_get_system(special_handle
, &handle
);
100 if (kr
!= kIOReturnSuccess
) {
101 #if TARGET_OS_EMBEDDED
102 /* TODO: Remove this once the kext runs the daemon on demand if
103 there is no system keybag. */
104 int kb_state
= MKBGetDeviceLockState(NULL
);
105 secinfo("aks", "AppleKeyStore lock state: %d", kb_state
);
111 #else /* !USE_KEYSTORE */
113 static bool hwaes_key_available(void)
118 #endif /* USE_KEYSTORE */
120 /* Wrap takes a 128 - 256 bit key as input and returns output of
122 In bytes this means that a
123 16 byte (128 bit) key returns a 24 byte wrapped key
124 24 byte (192 bit) key returns a 32 byte wrapped key
125 32 byte (256 bit) key returns a 40 byte wrapped key */
126 bool ks_crypt(CFTypeRef operation
, keybag_handle_t keybag
,
127 keyclass_t keyclass
, uint32_t textLength
, const uint8_t *source
, keyclass_t
*actual_class
, CFMutableDataRef dest
, CFErrorRef
*error
) {
129 kern_return_t kernResult
= kIOReturnBadArgument
;
131 int dest_len
= (int)CFDataGetLength(dest
);
132 if (CFEqual(operation
, kAKSKeyOpEncrypt
)) {
133 kernResult
= aks_wrap_key(source
, textLength
, keyclass
, keybag
, CFDataGetMutableBytePtr(dest
), &dest_len
, actual_class
);
134 } else if (CFEqual(operation
, kAKSKeyOpDecrypt
) || CFEqual(operation
, kAKSKeyOpDelete
)) {
135 kernResult
= aks_unwrap_key(source
, textLength
, keyclass
, keybag
, CFDataGetMutableBytePtr(dest
), &dest_len
);
138 if (kernResult
!= KERN_SUCCESS
) {
139 if ((kernResult
== kIOReturnNotPermitted
) || (kernResult
== kIOReturnNotPrivileged
)) {
140 const char *substatus
= "";
141 if (keyclass
== key_class_ck
|| keyclass
== key_class_cku
)
142 substatus
= " (hibernation?)";
143 /* Access to item attempted while keychain is locked. */
144 return SecError(errSecInteractionNotAllowed
, error
, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32
", bag: %"PRId32
") Access to item attempted while keychain is locked%s."),
145 kernResult
, operation
, keyclass
, keybag
, substatus
);
146 } else if (kernResult
== kIOReturnNotFound
) {
147 return SecError(errSecNotAvailable
, error
, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32
", bag: %"PRId32
") No key available for class."), kernResult
, operation
, keyclass
, keybag
);
148 } else if (kernResult
== kIOReturnError
|| kernResult
== kAKSReturnDecodeError
) {
149 /* Item can't be decrypted on this device, ever, so drop the item. */
150 return SecError(errSecDecode
, error
, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32
", bag: %"PRId32
") Item can't be decrypted on this device, ever, so drop the item."),
151 kernResult
, operation
, keyclass
, keybag
);
153 return SecError(errSecNotAvailable
, error
, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32
", bag: %"PRId32
")"),
154 kernResult
, operation
, keyclass
, keybag
);
158 CFDataSetLength(dest
, dest_len
);
160 #else /* !USE_KEYSTORE */
162 uint32_t dest_len
= (uint32_t)CFDataGetLength(dest
);
163 if (CFEqual(operation
, kAKSKeyOpEncrypt
)) {
164 /* The no encryption case. */
165 if (dest_len
>= textLength
+ 8) {
166 memcpy(CFDataGetMutableBytePtr(dest
), source
, textLength
);
167 memset(CFDataGetMutableBytePtr(dest
) + textLength
, 8, 8);
168 CFDataSetLength(dest
, textLength
+ 8);
169 *actual_class
= keyclass
;
171 return SecError(errSecNotAvailable
, error
, CFSTR("ks_crypt: failed to wrap item (class %"PRId32
")"), keyclass
);
172 } else if (CFEqual(operation
, kAKSKeyOpDecrypt
) || CFEqual(operation
, kAKSKeyOpDelete
)) {
173 if (dest_len
+ 8 >= textLength
) {
174 memcpy(CFDataGetMutableBytePtr(dest
), source
, textLength
- 8);
175 CFDataSetLength(dest
, textLength
- 8);
177 return SecError(errSecNotAvailable
, error
, CFSTR("ks_crypt: failed to unwrap item (class %"PRId32
")"), keyclass
);
180 #endif /* USE_KEYSTORE */
184 static bool ks_access_control_needed_error(CFErrorRef
*error
, CFDataRef access_control_data
, CFTypeRef operation
) {
188 if (*error
&& CFErrorGetCode(*error
) != errSecAuthNeeded
) {
189 // If we already had an error there, just leave it, no access_control specific error is needed here.
193 // Create new error instance which adds new access control data appended to existing
194 CFMutableDictionaryRef user_info
;
196 CFDictionaryRef old_user_info
= CFErrorCopyUserInfo(*error
);
197 user_info
= CFDictionaryCreateMutableCopy(NULL
, 0, old_user_info
);
198 CFRelease(old_user_info
);
199 CFReleaseNull(*error
);
201 user_info
= CFDictionaryCreateMutableForCFTypes(NULL
);
204 if (access_control_data
) {
205 CFNumberRef key
= CFNumberCreateWithCFIndex(NULL
, errSecAuthNeeded
);
206 CFMutableArrayRef acls
;
207 CFArrayRef old_acls
= CFDictionaryGetValue(user_info
, key
);
209 acls
= CFArrayCreateMutableCopy(NULL
, 0, old_acls
);
211 acls
= CFArrayCreateMutableForCFTypes(NULL
);
213 CFArrayRef pair
= CFArrayCreateForCFTypes(NULL
, access_control_data
, operation
, NULL
);
214 CFArrayAppendValue(acls
, pair
);
217 CFDictionarySetValue(user_info
, key
, acls
);
221 *error
= CFErrorCreate(NULL
, kSecErrorDomain
, errSecAuthNeeded
, user_info
);
224 *error
= CFErrorCreate(NULL
, kSecErrorDomain
, errSecAuthNeeded
, NULL
);
226 CFReleaseSafe(user_info
);
230 static bool merge_der_in_to_data(const void *ed_blob
, size_t ed_blob_len
, const void *key_blob
, size_t key_blob_len
, CFMutableDataRef mergedData
)
233 CFDataRef ed_data
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, ed_blob
, ed_blob_len
, kCFAllocatorNull
);
234 CFDataRef key_data
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, key_blob
, key_blob_len
, kCFAllocatorNull
);
236 if (ed_data
&& key_data
) {
237 CFDictionaryRef result_dict
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, kSecKSKeyData1
, ed_data
, kSecKSKeyData2
, key_data
, NULL
);
239 CFDataSetLength(mergedData
, 0);
240 CFDataRef der_data
= CFPropertyListCreateDERData(kCFAllocatorDefault
, result_dict
, NULL
);
242 CFDataAppend(mergedData
, der_data
);
244 ok
= CFDataGetLength(mergedData
) > 0;
246 CFRelease(result_dict
);
249 CFReleaseSafe(ed_data
);
250 CFReleaseSafe(key_data
);
254 bool ks_separate_data_and_key(CFDictionaryRef blob_dict
, CFDataRef
*ed_data
, CFDataRef
*key_data
)
257 CFDataRef tmp_ed_data
= CFDictionaryGetValue(blob_dict
, kSecKSKeyData1
);
258 CFDataRef tmp_key_data
= CFDictionaryGetValue(blob_dict
, kSecKSKeyData2
);
260 if (tmp_ed_data
&& tmp_key_data
&&
261 CFDataGetTypeID() == CFGetTypeID(tmp_ed_data
) &&
262 CFDataGetTypeID() == CFGetTypeID(tmp_key_data
)) {
263 *ed_data
= CFRetain(tmp_ed_data
);
264 *key_data
= CFRetain(tmp_key_data
);
271 static bool create_cferror_from_aks(int aks_return
, CFTypeRef operation
, keybag_handle_t keybag
, keyclass_t keyclass
, CFDataRef access_control_data
, CFDataRef acm_context_data
, CFErrorRef
*error
)
273 const char *operation_string
= "";
274 if (CFEqual(operation
, kAKSKeyOpDecrypt
)) {
275 operation_string
= "decrypt";
276 } else if (CFEqual(operation
, kAKSKeyOpEncrypt
)) {
277 operation_string
= "encrypt";
278 } if (CFEqual(operation
, kAKSKeyOpDelete
)) {
279 operation_string
= "delete";
282 if (aks_return
== kAKSReturnNoPermission
) {
283 /* Keychain is locked. */
284 SecError(errSecInteractionNotAllowed
, error
, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32
", bag: %"PRId32
") Access to item attempted while keychain is locked."),
285 aks_return
, operation_string
, keyclass
, keybag
);
286 } else if (aks_return
== kAKSReturnPolicyError
|| aks_return
== kAKSReturnBadPassword
) {
287 if (aks_return
== kAKSReturnBadPassword
) {
288 ACMContextRef acm_context_ref
= NULL
;
289 acm_context_ref
= ACMContextCreateWithExternalForm(CFDataGetBytePtr(acm_context_data
), CFDataGetLength(acm_context_data
));
290 if (acm_context_ref
) {
291 ACMContextRemovePassphraseCredentialsByPurposeAndScope(acm_context_ref
, kACMPassphrasePurposeGeneral
, kACMScopeContext
);
292 ACMContextDelete(acm_context_ref
, false);
296 /* Item needed authentication. */
297 ks_access_control_needed_error(error
, access_control_data
, operation
);
298 } else if (aks_return
== kAKSReturnError
|| aks_return
== kAKSReturnPolicyInvalid
|| aks_return
== kAKSReturnDecodeError
) {
299 /* Item can't be decrypted on this device, ever, so drop the item. */
300 SecError(errSecDecode
, error
, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32
", bag: %"PRId32
") Item can't be decrypted on this device, ever, so drop the item."),
301 aks_return
, operation_string
, keyclass
, keybag
);
303 } else if (aks_return
== kIOReturnNotFound
) {
304 return SecError(errSecNotAvailable
, error
, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32
", bag: %"PRId32
") No key available for class."), aks_return
, operation
, keyclass
, keybag
);
306 SecError(errSecNotAvailable
, error
, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32
", bag: %"PRId32
")"),
307 aks_return
, operation_string
, keyclass
, keybag
);
313 bool ks_encrypt_acl(keybag_handle_t keybag
, keyclass_t keyclass
, uint32_t textLength
, const uint8_t *source
,
314 CFMutableDataRef dest
, CFDataRef auth_data
, CFDataRef acm_context
,
315 SecAccessControlRef access_control
, CFErrorRef
*error
) {
316 void *params
= NULL
, *der
= NULL
;
317 size_t params_len
= 0, der_len
= 0;
318 CFDataRef access_control_data
= SecAccessControlCopyData(access_control
);
319 int aks_return
= kAKSReturnSuccess
;
320 aks_ref_key_t key_handle
= NULL
;
322 /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */
324 if (!acm_context
|| !SecAccessControlIsBound(access_control
)) {
325 require_quiet(ok
= ks_access_control_needed_error(error
, access_control_data
, SecAccessControlIsBound(access_control
) ? kAKSKeyOpEncrypt
: CFSTR("")), out
);
328 aks_operation_optional_params(0, 0, CFDataGetBytePtr(auth_data
), CFDataGetLength(auth_data
), CFDataGetBytePtr(acm_context
), (int)CFDataGetLength(acm_context
), ¶ms
, ¶ms_len
);
329 require_noerr_action_quiet(aks_return
= aks_ref_key_create(keybag
, keyclass
, key_type_sym
, params
, params_len
, &key_handle
), out
,
330 create_cferror_from_aks(aks_return
, kAKSKeyOpEncrypt
, keybag
, keyclass
, access_control_data
, acm_context
, error
));
331 require_noerr_action_quiet(aks_return
= aks_ref_key_encrypt(key_handle
, params
, params_len
, source
, textLength
, &der
, &der_len
), out
,
332 create_cferror_from_aks(aks_return
, kAKSKeyOpEncrypt
, keybag
, keyclass
, access_control_data
, acm_context
, error
));
334 const void *key_blob
= aks_ref_key_get_blob(key_handle
, &key_blob_len
);
335 require_action_quiet(key_blob
, out
, SecError(errSecDecode
, error
, CFSTR("ks_crypt_acl: %x failed to '%s' item (class %"PRId32
", bag: %"PRId32
") Item can't be encrypted due to invalid key data, so drop the item."),
336 aks_return
, "encrypt", keyclass
, keybag
));
338 require_action_quiet(merge_der_in_to_data(der
, der_len
, key_blob
, key_blob_len
, dest
), out
,
339 SecError(errSecDecode
, error
, CFSTR("ks_crypt_acl: %x failed to '%s' item (class %"PRId32
", bag: %"PRId32
") Item can't be encrypted due to merge failed, so drop the item."),
340 aks_return
, "encrypt", keyclass
, keybag
));
346 aks_ref_key_free(&key_handle
);
351 CFReleaseSafe(access_control_data
);
355 bool ks_decrypt_acl(aks_ref_key_t ref_key
, CFDataRef encrypted_data
, CFMutableDataRef dest
,
356 CFDataRef acm_context
, CFDataRef caller_access_groups
,
357 SecAccessControlRef access_control
, CFErrorRef
*error
) {
358 void *params
= NULL
, *der
= NULL
;
359 const uint8_t *access_groups
= caller_access_groups
?CFDataGetBytePtr(caller_access_groups
):NULL
;
360 size_t params_len
= 0, der_len
= 0, access_groups_len
= caller_access_groups
?CFDataGetLength(caller_access_groups
):0;
361 CFDataRef access_control_data
= SecAccessControlCopyData(access_control
);
362 int aks_return
= kAKSReturnSuccess
;
364 /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */
367 require_quiet(ok
= ks_access_control_needed_error(error
, NULL
, NULL
), out
);
370 aks_operation_optional_params(access_groups
, access_groups_len
, 0, 0, CFDataGetBytePtr(acm_context
), (int)CFDataGetLength(acm_context
), ¶ms
, ¶ms_len
);
371 require_noerr_action_quiet(aks_return
= aks_ref_key_decrypt(ref_key
, params
, params_len
, CFDataGetBytePtr(encrypted_data
), CFDataGetLength(encrypted_data
), &der
, &der_len
), out
,
372 create_cferror_from_aks(aks_return
, kAKSKeyOpDecrypt
, 0, 0, access_control_data
, acm_context
, error
));
373 require_action_quiet(der
, out
, SecError(errSecDecode
, error
, CFSTR("ks_crypt_acl: %x failed to '%s' item, Item can't be decrypted due to invalid der data, so drop the item."),
374 aks_return
, "decrypt"));
376 CFPropertyListRef decoded_data
= NULL
;
377 der_decode_plist(kCFAllocatorDefault
, kCFPropertyListImmutable
, &decoded_data
, NULL
, der
, der
+ der_len
);
378 require_action_quiet(decoded_data
, out
, SecError(errSecDecode
, error
, CFSTR("ks_crypt_acl: %x failed to '%s' item, Item can't be decrypted due to failed decode der, so drop the item."),
379 aks_return
, "decrypt"));
380 if (CFGetTypeID(decoded_data
) == CFDataGetTypeID()) {
381 CFDataSetLength(dest
, 0);
382 CFDataAppend(dest
, decoded_data
);
383 CFRelease(decoded_data
);
386 CFRelease(decoded_data
);
387 require_action_quiet(false, out
, SecError(errSecDecode
, error
, CFSTR("ks_crypt_acl: %x failed to '%s' item, Item can't be decrypted due to wrong data, so drop the item."),
388 aks_return
, "decrypt"));
398 CFReleaseSafe(access_control_data
);
402 bool ks_delete_acl(aks_ref_key_t ref_key
, CFDataRef encrypted_data
,
403 CFDataRef acm_context
, CFDataRef caller_access_groups
,
404 SecAccessControlRef access_control
, CFErrorRef
*error
) {
406 CFDataRef access_control_data
= NULL
;
407 int aks_return
= kAKSReturnSuccess
;
410 nrequire_action_quiet(CFEqual(SecAccessControlGetConstraint(access_control
, kAKSKeyOpDelete
), kCFBooleanTrue
), out
, ok
= true);
412 /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */
414 require_quiet(ok
= ks_access_control_needed_error(error
, NULL
, NULL
), out
);
417 access_control_data
= SecAccessControlCopyData(access_control
);
418 const uint8_t *access_groups
= caller_access_groups
?CFDataGetBytePtr(caller_access_groups
):NULL
;
419 size_t params_len
= 0, access_groups_len
= caller_access_groups
?CFDataGetLength(caller_access_groups
):0;
420 aks_operation_optional_params(access_groups
, access_groups_len
, 0, 0, CFDataGetBytePtr(acm_context
), (int)CFDataGetLength(acm_context
), ¶ms
, ¶ms_len
);
421 require_noerr_action_quiet(aks_return
= aks_ref_key_delete(ref_key
, params
, params_len
), out
,
422 create_cferror_from_aks(aks_return
, kAKSKeyOpDelete
, 0, 0, access_control_data
, acm_context
, error
));
429 CFReleaseSafe(access_control_data
);
433 const void* ks_ref_key_get_external_data(keybag_handle_t keybag
, CFDataRef key_data
, aks_ref_key_t
*ref_key
, size_t *external_data_len
, CFErrorRef
*error
) {
434 const void* result
= NULL
;
435 int aks_return
= kAKSReturnSuccess
;
436 require_noerr_action_quiet(aks_ref_key_create_with_blob(keybag
, CFDataGetBytePtr(key_data
), CFDataGetLength(key_data
), ref_key
), out
,
437 SecError(errSecNotAvailable
, error
, CFSTR("aks_ref_key: %x failed to '%s' item (bag: %"PRId32
")"), aks_return
, "create ref key with blob", keybag
));
438 result
= aks_ref_key_get_external_data(*ref_key
, external_data_len
);
445 bool use_hwaes(void) {
446 static bool use_hwaes
;
447 static dispatch_once_t check_once
;
448 dispatch_once(&check_once
, ^{
449 use_hwaes
= hwaes_key_available();
451 secinfo("aks", "using hwaes key");
453 secerror("unable to access hwaes key");
459 bool ks_open_keybag(CFDataRef keybag
, CFDataRef password
, keybag_handle_t
*handle
, CFErrorRef
*error
) {
461 kern_return_t kernResult
;
462 if (!asData(keybag
, error
)) return false;
463 kernResult
= aks_load_bag(CFDataGetBytePtr(keybag
), (int)CFDataGetLength(keybag
), handle
);
465 return SecKernError(kernResult
, error
, CFSTR("aks_load_bag failed: %@"), keybag
);
468 kernResult
= aks_unlock_bag(*handle
, CFDataGetBytePtr(password
), (int)CFDataGetLength(password
));
470 aks_unload_bag(*handle
);
471 return SecKernError(kernResult
, error
, CFSTR("aks_unlock_bag failed"));
475 #else /* !USE_KEYSTORE */
476 *handle
= KEYBAG_NONE
;
478 #endif /* USE_KEYSTORE */
481 bool ks_close_keybag(keybag_handle_t keybag
, CFErrorRef
*error
) {
483 IOReturn kernResult
= aks_unload_bag(keybag
);
485 return SecKernError(kernResult
, error
, CFSTR("aks_unload_bag failed"));
487 #endif /* USE_KEYSTORE */