]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecKeybagSupport.c
Security-58286.200.222.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 #else /* !USE_KEYSTORE */
45 #include <utilities/SecInternalReleasePriv.h>
46 #endif /* USE_KEYSTORE */
47
48 #include <CommonCrypto/CommonCryptor.h>
49 #include <CommonCrypto/CommonCryptorSPI.h>
50
51
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 */
54 #if USE_KEYSTORE
55 #if TARGET_OS_MAC && !TARGET_OS_EMBEDDED
56 keybag_handle_t g_keychain_keybag = session_keybag_handle;
57 #else
58 keybag_handle_t g_keychain_keybag = device_keybag_handle;
59 #endif
60 #else /* !USE_KEYSTORE */
61 keybag_handle_t g_keychain_keybag = 0; /* 0 == device_keybag_handle, constant dictated by AKS */
62 #endif /* USE_KEYSTORE */
63
64 const CFStringRef kSecKSKeyData1 = CFSTR("d1");
65 const CFStringRef kSecKSKeyData2 = CFSTR("d2");
66
67 void SecItemServerSetKeychainKeybag(int32_t keybag)
68 {
69 g_keychain_keybag=keybag;
70 }
71
72 void SecItemServerResetKeychainKeybag(void)
73 {
74 #if USE_KEYSTORE
75 #if TARGET_OS_MAC && !TARGET_OS_EMBEDDED
76 g_keychain_keybag = session_keybag_handle;
77 #else
78 g_keychain_keybag = device_keybag_handle;
79 #endif
80 #else /* !USE_KEYSTORE */
81 g_keychain_keybag = 0; /* 0 == device_keybag_handle, constant dictated by AKS */
82 #endif /* USE_KEYSTORE */
83 }
84
85 #if USE_KEYSTORE
86
87 static bool hwaes_key_available(void)
88 {
89 keybag_handle_t handle = bad_keybag_handle;
90 keybag_handle_t special_handle = bad_keybag_handle;
91 #if TARGET_OS_OSX
92 special_handle = session_keybag_handle;
93 #elif TARGET_OS_EMBEDDED
94 special_handle = device_keybag_handle;
95 #else
96 #error "supported keybag target"
97 #endif
98
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);
106 #endif
107 }
108 return true;
109 }
110
111 #else /* !USE_KEYSTORE */
112
113 static bool hwaes_key_available(void)
114 {
115 return false;
116 }
117
118 #endif /* USE_KEYSTORE */
119
120 /* Wrap takes a 128 - 256 bit key as input and returns output of
121 inputsize + 64 bits.
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) {
128 #if USE_KEYSTORE
129 kern_return_t kernResult = kIOReturnBadArgument;
130
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);
136 }
137
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);
152 } else {
153 return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32")"),
154 kernResult, operation, keyclass, keybag);
155 }
156 }
157 else
158 CFDataSetLength(dest, dest_len);
159 return true;
160 #else /* !USE_KEYSTORE */
161
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;
170 } else
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);
176 } else
177 return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: failed to unwrap item (class %"PRId32")"), keyclass);
178 }
179 return true;
180 #endif /* USE_KEYSTORE */
181 }
182
183 #if USE_KEYSTORE
184 bool ks_access_control_needed_error(CFErrorRef *error, CFDataRef access_control_data, CFTypeRef operation) {
185 if (error == NULL)
186 return false;
187
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.
190 return false;
191 }
192
193 // Create new error instance which adds new access control data appended to existing
194 CFMutableDictionaryRef user_info;
195 if (*error) {
196 CFDictionaryRef old_user_info = CFErrorCopyUserInfo(*error);
197 user_info = CFDictionaryCreateMutableCopy(NULL, 0, old_user_info);
198 CFRelease(old_user_info);
199 CFReleaseNull(*error);
200 } else {
201 user_info = CFDictionaryCreateMutableForCFTypes(NULL);
202 }
203
204 if (access_control_data) {
205 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, errSecAuthNeeded);
206 CFMutableArrayRef acls;
207 CFArrayRef old_acls = CFDictionaryGetValue(user_info, key);
208 if (old_acls)
209 acls = CFArrayCreateMutableCopy(NULL, 0, old_acls);
210 else
211 acls = CFArrayCreateMutableForCFTypes(NULL);
212
213 CFArrayRef pair = CFArrayCreateForCFTypes(NULL, access_control_data, operation, NULL);
214 CFArrayAppendValue(acls, pair);
215 CFRelease(pair);
216
217 CFDictionarySetValue(user_info, key, acls);
218 CFRelease(key);
219 CFRelease(acls);
220
221 *error = CFErrorCreate(NULL, kSecErrorDomain, errSecAuthNeeded, user_info);
222 }
223 else
224 *error = CFErrorCreate(NULL, kSecErrorDomain, errSecAuthNeeded, NULL);
225
226 CFReleaseSafe(user_info);
227 return false;
228 }
229
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)
231 {
232 bool ok = false;
233 CFDataRef ed_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, ed_blob, ed_blob_len, kCFAllocatorNull);
234 CFDataRef key_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, key_blob, key_blob_len, kCFAllocatorNull);
235
236 if (ed_data && key_data) {
237 CFDictionaryRef result_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, kSecKSKeyData1, ed_data, kSecKSKeyData2, key_data, NULL);
238
239 CFDataSetLength(mergedData, 0);
240 CFDataRef der_data = CFPropertyListCreateDERData(kCFAllocatorDefault, result_dict, NULL);
241 if (der_data) {
242 CFDataAppend(mergedData, der_data);
243 CFRelease(der_data);
244 ok = CFDataGetLength(mergedData) > 0;
245 }
246 CFRelease(result_dict);
247 }
248
249 CFReleaseSafe(ed_data);
250 CFReleaseSafe(key_data);
251 return ok;
252 }
253
254 bool ks_separate_data_and_key(CFDictionaryRef blob_dict, CFDataRef *ed_data, CFDataRef *key_data)
255 {
256 bool ok = false;
257 CFDataRef tmp_ed_data = CFDictionaryGetValue(blob_dict, kSecKSKeyData1);
258 CFDataRef tmp_key_data = CFDictionaryGetValue(blob_dict, kSecKSKeyData2);
259
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);
265 ok = true;
266 }
267
268 return ok;
269 }
270
271 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)
272 {
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";
280 }
281
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);
293 }
294 }
295
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);
302
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);
305 } else {
306 SecError(errSecNotAvailable, error, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32", bag: %"PRId32")"),
307 aks_return, operation_string, keyclass, keybag);
308 }
309
310 return false;
311 }
312
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;
321
322 /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */
323 bool ok = false;
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);
326 }
327
328 aks_operation_optional_params(0, 0, CFDataGetBytePtr(auth_data), CFDataGetLength(auth_data), CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), &params, &params_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));
333 size_t key_blob_len;
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));
337
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));
341
342 ok = true;
343
344 out:
345 if (key_handle)
346 aks_ref_key_free(&key_handle);
347 if(params)
348 free(params);
349 if(der)
350 free(der);
351 CFReleaseSafe(access_control_data);
352 return ok;
353 }
354
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;
363
364 /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */
365 bool ok = false;
366 if (!acm_context) {
367 require_quiet(ok = ks_access_control_needed_error(error, NULL, NULL), out);
368 }
369
370 aks_operation_optional_params(access_groups, access_groups_len, 0, 0, CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), &params, &params_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"));
375
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);
384 }
385 else {
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"));
389 }
390
391 ok = true;
392
393 out:
394 if(params)
395 free(params);
396 if(der)
397 free(der);
398 CFReleaseSafe(access_control_data);
399 return ok;
400 }
401
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) {
405 void *params = NULL;
406 CFDataRef access_control_data = NULL;
407 int aks_return = kAKSReturnSuccess;
408 bool ok = false;
409
410 nrequire_action_quiet(CFEqual(SecAccessControlGetConstraint(access_control, kAKSKeyOpDelete), kCFBooleanTrue), out, ok = true);
411
412 /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */
413 if (!acm_context) {
414 require_quiet(ok = ks_access_control_needed_error(error, NULL, NULL), out);
415 }
416
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), &params, &params_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));
423
424 ok = true;
425
426 out:
427 if(params)
428 free(params);
429 CFReleaseSafe(access_control_data);
430 return ok;
431 }
432
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);
439
440 out:
441 return result;
442 }
443 #endif
444
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();
450 if (use_hwaes) {
451 secinfo("aks", "using hwaes key");
452 } else {
453 secerror("unable to access hwaes key");
454 }
455 });
456 return use_hwaes;
457 }
458
459 bool ks_open_keybag(CFDataRef keybag, CFDataRef password, keybag_handle_t *handle, CFErrorRef *error) {
460 #if USE_KEYSTORE
461 kern_return_t kernResult;
462 if (!asData(keybag, error)) return false;
463 kernResult = aks_load_bag(CFDataGetBytePtr(keybag), (int)CFDataGetLength(keybag), handle);
464 if (kernResult)
465 return SecKernError(kernResult, error, CFSTR("aks_load_bag failed: %@"), keybag);
466
467 if (password) {
468 kernResult = aks_unlock_bag(*handle, CFDataGetBytePtr(password), (int)CFDataGetLength(password));
469 if (kernResult) {
470 aks_unload_bag(*handle);
471 return SecKernError(kernResult, error, CFSTR("aks_unlock_bag failed"));
472 }
473 }
474 return true;
475 #else /* !USE_KEYSTORE */
476 *handle = KEYBAG_NONE;
477 return true;
478 #endif /* USE_KEYSTORE */
479 }
480
481 bool ks_close_keybag(keybag_handle_t keybag, CFErrorRef *error) {
482 #if USE_KEYSTORE
483 IOReturn kernResult = aks_unload_bag(keybag);
484 if (kernResult) {
485 return SecKernError(kernResult, error, CFSTR("aks_unload_bag failed"));
486 }
487 #endif /* USE_KEYSTORE */
488 return true;
489 }
490