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