]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecKeybagSupport.c
Security-57336.10.29.tar.gz
[apple/security.git] / OSX / sec / securityd / SecKeybagSupport.c
1 /*
2 * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * SecKeybagSupport.c - CoreFoundation-based constants and functions for
26 access to Security items (certificates, keys, identities, and
27 passwords.)
28 */
29
30 #include <securityd/SecKeybagSupport.h>
31
32 #include <securityd/SecItemServer.h>
33
34 #if USE_KEYSTORE
35 #include <IOKit/IOKitLib.h>
36 #include <libaks.h>
37 #include <libaks_acl_cf_keys.h>
38 #include <utilities/der_plist.h>
39 #include <corecrypto/ccder.h>
40 #include <ACMLib.h>
41 #if TARGET_OS_EMBEDDED
42 #include <MobileKeyBag/MobileKeyBag.h>
43 #endif
44 #endif /* USE_KEYSTORE */
45
46
47 /* g_keychain_handle is the keybag handle used for encrypting item in the keychain.
48 For testing purposes, it can be set to something other than the default, with SecItemServerSetKeychainKeybag */
49 #if USE_KEYSTORE
50 #if TARGET_OS_MAC && !TARGET_OS_EMBEDDED
51 keybag_handle_t g_keychain_keybag = session_keybag_handle;
52 #else
53 keybag_handle_t g_keychain_keybag = device_keybag_handle;
54 #endif
55 #else /* !USE_KEYSTORE */
56 keybag_handle_t g_keychain_keybag = 0; /* 0 == device_keybag_handle, constant dictated by AKS */
57 #endif /* USE_KEYSTORE */
58
59 const CFStringRef kSecKSKeyData1 = CFSTR("d1");
60 const CFStringRef kSecKSKeyData2 = CFSTR("d2");
61
62 void SecItemServerSetKeychainKeybag(int32_t keybag)
63 {
64 g_keychain_keybag=keybag;
65 }
66
67 void SecItemServerResetKeychainKeybag(void)
68 {
69 #if USE_KEYSTORE
70 #if TARGET_OS_MAC && !TARGET_OS_EMBEDDED
71 g_keychain_keybag = session_keybag_handle;
72 #else
73 g_keychain_keybag = device_keybag_handle;
74 #endif
75 #else /* !USE_KEYSTORE */
76 g_keychain_keybag = 0; /* 0 == device_keybag_handle, constant dictated by AKS */
77 #endif /* USE_KEYSTORE */
78 }
79
80 #if USE_KEYSTORE
81
82 static bool hwaes_key_available(void)
83 {
84 keybag_handle_t handle = bad_keybag_handle;
85 keybag_handle_t special_handle = bad_keybag_handle;
86 #if TARGET_OS_MAC && !TARGET_OS_EMBEDDED
87 special_handle = session_keybag_handle;
88 #elif TARGET_OS_EMBEDDED
89 special_handle = device_keybag_handle;
90 #endif
91 kern_return_t kr = aks_get_system(special_handle, &handle);
92 if (kr != kIOReturnSuccess) {
93 #if TARGET_OS_EMBEDDED
94 /* TODO: Remove this once the kext runs the daemon on demand if
95 there is no system keybag. */
96 int kb_state = MKBGetDeviceLockState(NULL);
97 asl_log(NULL, NULL, ASL_LEVEL_INFO, "AppleKeyStore lock state: %d", kb_state);
98 #endif
99 }
100 return true;
101 }
102
103 #else /* !USE_KEYSTORE */
104
105 static bool hwaes_key_available(void)
106 {
107 return false;
108 }
109
110 #endif /* USE_KEYSTORE */
111
112 /* Wrap takes a 128 - 256 bit key as input and returns output of
113 inputsize + 64 bits.
114 In bytes this means that a
115 16 byte (128 bit) key returns a 24 byte wrapped key
116 24 byte (192 bit) key returns a 32 byte wrapped key
117 32 byte (256 bit) key returns a 40 byte wrapped key */
118 bool ks_crypt(CFTypeRef operation, keybag_handle_t keybag,
119 keyclass_t keyclass, uint32_t textLength, const uint8_t *source, keyclass_t *actual_class, CFMutableDataRef dest, CFErrorRef *error) {
120 #if USE_KEYSTORE
121 kern_return_t kernResult = kIOReturnBadArgument;
122
123 int dest_len = (int)CFDataGetLength(dest);
124 if (CFEqual(operation, kAKSKeyOpEncrypt)) {
125 kernResult = aks_wrap_key(source, textLength, keyclass, keybag, CFDataGetMutableBytePtr(dest), &dest_len, actual_class);
126 } else if (CFEqual(operation, kAKSKeyOpDecrypt) || CFEqual(operation, kAKSKeyOpDelete)) {
127 kernResult = aks_unwrap_key(source, textLength, keyclass, keybag, CFDataGetMutableBytePtr(dest), &dest_len);
128 }
129
130 if (kernResult != KERN_SUCCESS) {
131 if ((kernResult == kIOReturnNotPermitted) || (kernResult == kIOReturnNotPrivileged)) {
132 /* Access to item attempted while keychain is locked. */
133 return SecError(errSecInteractionNotAllowed, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") Access to item attempted while keychain is locked."),
134 kernResult, operation, keyclass, keybag);
135 } else if (kernResult == kIOReturnError) {
136 /* Item can't be decrypted on this device, ever, so drop the item. */
137 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."),
138 kernResult, operation, keyclass, keybag);
139 } else {
140 return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32")"),
141 kernResult, operation, keyclass, keybag);
142 }
143 }
144 else
145 CFDataSetLength(dest, dest_len);
146 return true;
147 #else /* !USE_KEYSTORE */
148 uint32_t dest_len = (uint32_t)CFDataGetLength(dest);
149 if (CFEqual(operation, kAKSKeyOpEncrypt)) {
150 /* The no encryption case. */
151 if (dest_len >= textLength + 8) {
152 memcpy(CFDataGetMutableBytePtr(dest), source, textLength);
153 memset(CFDataGetMutableBytePtr(dest) + textLength, 8, 8);
154 CFDataSetLength(dest, textLength + 8);
155 *actual_class = keyclass;
156 } else
157 return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: failed to wrap item (class %"PRId32")"), keyclass);
158 } else if (CFEqual(operation, kAKSKeyOpDecrypt) || CFEqual(operation, kAKSKeyOpDelete)) {
159 if (dest_len + 8 >= textLength) {
160 memcpy(CFDataGetMutableBytePtr(dest), source, textLength - 8);
161 CFDataSetLength(dest, textLength - 8);
162 } else
163 return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: failed to unwrap item (class %"PRId32")"), keyclass);
164 }
165 return true;
166 #endif /* USE_KEYSTORE */
167 }
168
169 #if USE_KEYSTORE
170 static bool ks_access_control_needed_error(CFErrorRef *error, CFDataRef access_control_data, CFTypeRef operation) {
171 if (error == NULL)
172 return false;
173
174 if (*error && CFErrorGetCode(*error) != errSecAuthNeeded) {
175 // If we already had an error there, just leave it, no access_control specific error is needed here.
176 return false;
177 }
178
179 // Create new error instance which adds new access control data appended to existing
180 CFMutableDictionaryRef user_info;
181 if (*error) {
182 CFDictionaryRef old_user_info = CFErrorCopyUserInfo(*error);
183 user_info = CFDictionaryCreateMutableCopy(NULL, 0, old_user_info);
184 CFRelease(old_user_info);
185 CFReleaseNull(*error);
186 } else {
187 user_info = CFDictionaryCreateMutableForCFTypes(NULL);
188 }
189
190 if (access_control_data) {
191 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, errSecAuthNeeded);
192 CFMutableArrayRef acls;
193 CFArrayRef old_acls = CFDictionaryGetValue(user_info, key);
194 if (old_acls)
195 acls = CFArrayCreateMutableCopy(NULL, 0, old_acls);
196 else
197 acls = CFArrayCreateMutableForCFTypes(NULL);
198
199 CFArrayRef pair = CFArrayCreateForCFTypes(NULL, access_control_data, operation, NULL);
200 CFArrayAppendValue(acls, pair);
201 CFRelease(pair);
202
203 CFDictionarySetValue(user_info, key, acls);
204 CFRelease(key);
205 CFRelease(acls);
206
207 *error = CFErrorCreate(NULL, kSecErrorDomain, errSecAuthNeeded, user_info);
208 }
209 else
210 *error = CFErrorCreate(NULL, kSecErrorDomain, errSecAuthNeeded, NULL);
211
212 CFReleaseSafe(user_info);
213 return false;
214 }
215
216 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)
217 {
218 bool ok = false;
219 CFDataRef ed_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, ed_blob, ed_blob_len, kCFAllocatorNull);
220 CFDataRef key_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, key_blob, key_blob_len, kCFAllocatorNull);
221
222 if (ed_data && key_data) {
223 CFDictionaryRef result_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, kSecKSKeyData1, ed_data, kSecKSKeyData2, key_data, NULL);
224
225 CFDataSetLength(mergedData, 0);
226 CFDataRef der_data = CFPropertyListCreateDERData(kCFAllocatorDefault, result_dict, NULL);
227 if (der_data) {
228 CFDataAppend(mergedData, der_data);
229 CFRelease(der_data);
230 ok = CFDataGetLength(mergedData) > 0;
231 }
232 CFRelease(result_dict);
233 }
234
235 CFReleaseSafe(ed_data);
236 CFReleaseSafe(key_data);
237 return ok;
238 }
239
240 bool ks_separate_data_and_key(CFDictionaryRef blob_dict, CFDataRef *ed_data, CFDataRef *key_data)
241 {
242 bool ok = false;
243 CFDataRef tmp_ed_data = CFDictionaryGetValue(blob_dict, kSecKSKeyData1);
244 CFDataRef tmp_key_data = CFDictionaryGetValue(blob_dict, kSecKSKeyData2);
245
246 if (tmp_ed_data && tmp_key_data &&
247 CFDataGetTypeID() == CFGetTypeID(tmp_ed_data) &&
248 CFDataGetTypeID() == CFGetTypeID(tmp_key_data)) {
249 *ed_data = CFRetain(tmp_ed_data);
250 *key_data = CFRetain(tmp_key_data);
251 ok = true;
252 }
253
254 return ok;
255 }
256
257 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)
258 {
259 const char *operation_string = "";
260 if (CFEqual(operation, kAKSKeyOpDecrypt)) {
261 operation_string = "decrypt";
262 } else if (CFEqual(operation, kAKSKeyOpEncrypt)) {
263 operation_string = "encrypt";
264 } if (CFEqual(operation, kAKSKeyOpDelete)) {
265 operation_string = "delete";
266 }
267
268 if (aks_return == kAKSReturnNoPermission) {
269 /* Keychain is locked. */
270 SecError(errSecInteractionNotAllowed, error, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32", bag: %"PRId32") Access to item attempted while keychain is locked."),
271 aks_return, operation_string, keyclass, keybag);
272 } else if (aks_return == kAKSReturnPolicyError || aks_return == kAKSReturnBadPassword) {
273 if (aks_return == kAKSReturnBadPassword) {
274 ACMContextRef acm_context_ref = ACMContextCreateWithExternalForm(CFDataGetBytePtr(acm_context_data), CFDataGetLength(acm_context_data));
275 if (acm_context_ref) {
276 ACMContextRemovePassphraseCredentialsByPurposeAndScope(acm_context_ref, kACMPassphrasePurposeGeneral, kACMScopeContext);
277 ACMContextDelete(acm_context_ref, false);
278 }
279 }
280
281 /* Item needed authentication. */
282 ks_access_control_needed_error(error, access_control_data, operation);
283 } else if (aks_return == kAKSReturnError || aks_return == kAKSReturnPolicyInvalid) {
284 /* Item can't be decrypted on this device, ever, so drop the item. */
285 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."),
286 aks_return, operation_string, keyclass, keybag);
287 } else {
288 SecError(errSecNotAvailable, error, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32", bag: %"PRId32")"),
289 aks_return, operation_string, keyclass, keybag);
290 }
291
292 return false;
293 }
294
295 bool ks_encrypt_acl(keybag_handle_t keybag, keyclass_t keyclass, uint32_t textLength, const uint8_t *source,
296 CFMutableDataRef dest, CFDataRef auth_data, CFDataRef acm_context,
297 SecAccessControlRef access_control, CFErrorRef *error) {
298 void *params = NULL, *der = NULL;
299 size_t params_len = 0, der_len = 0;
300 CFDataRef access_control_data = SecAccessControlCopyData(access_control);
301 int aks_return = kAKSReturnSuccess;
302 aks_ref_key_t key_handle = NULL;
303
304 /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */
305 bool ok = false;
306 if (!acm_context || !SecAccessControlIsBound(access_control)) {
307 require_quiet(ok = ks_access_control_needed_error(error, access_control_data, SecAccessControlIsBound(access_control) ? kAKSKeyOpEncrypt : CFSTR("")), out);
308 }
309
310 aks_operation_optional_params(0, 0, CFDataGetBytePtr(auth_data), CFDataGetLength(auth_data), CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), &params, &params_len);
311 require_noerr_action_quiet(aks_return = aks_ref_key_create(keybag, keyclass, key_type_sym, params, params_len, &key_handle), out,
312 create_cferror_from_aks(aks_return, kAKSKeyOpEncrypt, keybag, keyclass, access_control_data, acm_context, error));
313 require_noerr_action_quiet(aks_return = aks_ref_key_encrypt(key_handle, params, params_len, source, textLength, &der, &der_len), out,
314 create_cferror_from_aks(aks_return, kAKSKeyOpEncrypt, keybag, keyclass, access_control_data, acm_context, error));
315 size_t key_blob_len;
316 const void *key_blob = aks_ref_key_get_blob(key_handle, &key_blob_len);
317 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."),
318 aks_return, "encrypt", keyclass, keybag));
319
320 require_action_quiet(merge_der_in_to_data(der, der_len, key_blob, key_blob_len, dest), out,
321 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."),
322 aks_return, "encrypt", keyclass, keybag));
323
324 ok = true;
325
326 out:
327 if (key_handle)
328 aks_ref_key_free(&key_handle);
329 if(params)
330 free(params);
331 if(der)
332 free(der);
333 CFReleaseSafe(access_control_data);
334 return ok;
335 }
336
337 bool ks_decrypt_acl(aks_ref_key_t ref_key, CFDataRef encrypted_data, CFMutableDataRef dest,
338 CFDataRef acm_context, CFDataRef caller_access_groups,
339 SecAccessControlRef access_control, CFErrorRef *error) {
340 void *params = NULL, *der = NULL;
341 const uint8_t *access_groups = caller_access_groups?CFDataGetBytePtr(caller_access_groups):NULL;
342 size_t params_len = 0, der_len = 0, access_groups_len = caller_access_groups?CFDataGetLength(caller_access_groups):0;
343 CFDataRef access_control_data = SecAccessControlCopyData(access_control);
344 int aks_return = kAKSReturnSuccess;
345
346 /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */
347 bool ok = false;
348 if (!acm_context) {
349 require_quiet(ok = ks_access_control_needed_error(error, NULL, NULL), out);
350 }
351
352 aks_operation_optional_params(access_groups, access_groups_len, 0, 0, CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), &params, &params_len);
353 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,
354 create_cferror_from_aks(aks_return, kAKSKeyOpDecrypt, 0, 0, access_control_data, acm_context, error));
355 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."),
356 aks_return, "decrypt"));
357
358 CFPropertyListRef decoded_data = NULL;
359 der_decode_plist(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_data, NULL, der, der + der_len);
360 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."),
361 aks_return, "decrypt"));
362 if (CFGetTypeID(decoded_data) == CFDataGetTypeID()) {
363 CFDataSetLength(dest, 0);
364 CFDataAppend(dest, decoded_data);
365 CFRelease(decoded_data);
366 }
367 else {
368 CFRelease(decoded_data);
369 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."),
370 aks_return, "decrypt"));
371 }
372
373 ok = true;
374
375 out:
376 if(params)
377 free(params);
378 if(der)
379 free(der);
380 CFReleaseSafe(access_control_data);
381 return ok;
382 }
383
384 bool ks_delete_acl(aks_ref_key_t ref_key, CFDataRef encrypted_data,
385 CFDataRef acm_context, CFDataRef caller_access_groups,
386 SecAccessControlRef access_control, CFErrorRef *error) {
387 void *params = NULL;
388 CFDataRef access_control_data = NULL;
389 int aks_return = kAKSReturnSuccess;
390 bool ok = false;
391
392 nrequire_action_quiet(CFEqual(SecAccessControlGetConstraint(access_control, kAKSKeyOpDelete), kCFBooleanTrue), out, ok = true);
393
394 /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */
395 if (!acm_context) {
396 require_quiet(ok = ks_access_control_needed_error(error, NULL, NULL), out);
397 }
398
399 access_control_data = SecAccessControlCopyData(access_control);
400 const uint8_t *access_groups = caller_access_groups?CFDataGetBytePtr(caller_access_groups):NULL;
401 size_t params_len = 0, access_groups_len = caller_access_groups?CFDataGetLength(caller_access_groups):0;
402 aks_operation_optional_params(access_groups, access_groups_len, 0, 0, CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), &params, &params_len);
403 require_noerr_action_quiet(aks_return = aks_ref_key_delete(ref_key, params, params_len), out,
404 create_cferror_from_aks(aks_return, kAKSKeyOpDelete, 0, 0, access_control_data, acm_context, error));
405
406 ok = true;
407
408 out:
409 if(params)
410 free(params);
411 CFReleaseSafe(access_control_data);
412 return ok;
413 }
414
415 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) {
416 const void* result = NULL;
417 int aks_return = kAKSReturnSuccess;
418 require_noerr_action_quiet(aks_ref_key_create_with_blob(keybag, CFDataGetBytePtr(key_data), CFDataGetLength(key_data), ref_key), out,
419 SecError(errSecNotAvailable, error, CFSTR("aks_ref_key: %x failed to '%s' item (bag: %"PRId32")"), aks_return, "create ref key with blob", keybag));
420 result = aks_ref_key_get_external_data(*ref_key, external_data_len);
421
422 out:
423 return result;
424 }
425 #endif
426
427 bool use_hwaes(void) {
428 static bool use_hwaes;
429 static dispatch_once_t check_once;
430 dispatch_once(&check_once, ^{
431 use_hwaes = hwaes_key_available();
432 if (use_hwaes) {
433 asl_log(NULL, NULL, ASL_LEVEL_INFO, "using hwaes key");
434 } else {
435 asl_log(NULL, NULL, ASL_LEVEL_ERR, "unable to access hwaes key");
436 }
437 });
438 return use_hwaes;
439 }
440
441 bool ks_open_keybag(CFDataRef keybag, CFDataRef password, keybag_handle_t *handle, CFErrorRef *error) {
442 #if USE_KEYSTORE
443 kern_return_t kernResult;
444 if (!asData(keybag, error)) return false;
445 kernResult = aks_load_bag(CFDataGetBytePtr(keybag), (int)CFDataGetLength(keybag), handle);
446 if (kernResult)
447 return SecKernError(kernResult, error, CFSTR("aks_load_bag failed: %@"), keybag);
448
449 if (password) {
450 kernResult = aks_unlock_bag(*handle, CFDataGetBytePtr(password), (int)CFDataGetLength(password));
451 if (kernResult) {
452 aks_unload_bag(*handle);
453 return SecKernError(kernResult, error, CFSTR("aks_unlock_bag failed"));
454 }
455 }
456 return true;
457 #else /* !USE_KEYSTORE */
458 *handle = KEYBAG_NONE;
459 return true;
460 #endif /* USE_KEYSTORE */
461 }
462
463 bool ks_close_keybag(keybag_handle_t keybag, CFErrorRef *error) {
464 #if USE_KEYSTORE
465 IOReturn kernResult = aks_unload_bag(keybag);
466 if (kernResult) {
467 return SecKernError(kernResult, error, CFSTR("aks_unload_bag failed"));
468 }
469 #endif /* USE_KEYSTORE */
470 return true;
471 }