2 * Copyright (c) 2013-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@
29 #include <utilities/SecAKSWrappers.h>
30 #include <utilities/SecCFWrappers.h>
31 #include <utilities/SecCFError.h>
33 #if TARGET_IPHONE_SIMULATOR
34 # define change_notification "com.apple.will.never.happen"
35 #elif TARGET_OS_IPHONE
36 # include <MobileKeyBag/MobileKeyBag.h>
37 # define change_notification kMobileKeyBagLockStatusNotificationID
39 # include <AppleKeyStoreEvents.h>
40 # define change_notification kAppleKeyStoreLockStatusNotificationID
42 # error "unsupported target platform"
45 #if TARGET_OS_MAC && !TARGET_OS_EMBEDDED && TARGET_HAS_KEYSTORE
47 const keybag_handle_t keybagHandle
= session_keybag_handle
;
48 #elif TARGET_HAS_KEYSTORE // iOS, but not simulator
49 const keybag_handle_t keybagHandle
= device_keybag_handle
;
52 #if TARGET_HAS_KEYSTORE
53 const AKSAssertionType_t lockAssertType
= kAKSAssertTypeOther
;
56 CFGiblisGetSingleton(dispatch_queue_t
, GetKeybagAssertionQueue
, sUserKeyBagAssertionLockQueue
, ^{
57 *sUserKeyBagAssertionLockQueue
= dispatch_queue_create("AKS Lock Assertion Queue", NULL
);
60 #if TARGET_HAS_KEYSTORE
61 static uint32_t count
= 0;
63 const char * const kUserKeybagStateChangeNotification
= change_notification
;
65 bool SecAKSLockUserKeybag(uint64_t timeout
, CFErrorRef
*error
){
66 #if !TARGET_HAS_KEYSTORE
69 __block kern_return_t status
= kIOReturnSuccess
;
71 dispatch_sync(GetKeybagAssertionQueue(), ^{
73 secnotice("lockassertions", "Requesting lock assertion for %lld seconds", timeout
);
74 status
= aks_assert_hold(keybagHandle
, lockAssertType
, timeout
);
77 if (status
== kIOReturnSuccess
)
80 return SecKernError(status
, error
, CFSTR("Kern return error"));
81 #endif /* !TARGET_HAS_KEYSTORE */
84 bool SecAKSUnLockUserKeybag(CFErrorRef
*error
){
85 #if !TARGET_HAS_KEYSTORE
88 __block kern_return_t status
= kIOReturnSuccess
;
90 dispatch_sync(GetKeybagAssertionQueue(), ^{
91 if (count
&& (--count
== 0)) {
92 secnotice("lockassertions", "Dropping lock assertion");
93 status
= aks_assert_drop(keybagHandle
, lockAssertType
);
97 return SecKernError(status
, error
, CFSTR("Kern return error"));
98 #endif /* !TARGET_HAS_KEYSTORE */
102 bool SecAKSDoWhileUserBagLocked(CFErrorRef
*error
, dispatch_block_t action
)
104 #if !TARGET_HAS_KEYSTORE
108 // Acquire lock assertion, ref count?
111 uint64_t timeout
= 60ull;
112 if (SecAKSLockUserKeybag(timeout
, error
)) {
114 status
= SecAKSUnLockUserKeybag(error
);
117 #endif /* !TARGET_HAS_KEYSTORE */
119 CFDataRef
SecAKSCopyBackupBagWithSecret(size_t size
, uint8_t *secret
, CFErrorRef
*error
) {
120 #if !TARGET_HAS_KEYSTORE
123 CFDataRef result
= NULL
;
124 void *keybagBytes
= NULL
;
127 keybag_handle_t backupKeybagHandle
= -1;
130 require_quiet(SecRequirementError(0 <= size
&& size
<= INT_MAX
, error
, CFSTR("Invalid size: %zu"), size
), fail
);
132 ret
= aks_create_bag(secret
, (int) size
, kAppleKeyStoreAsymmetricBackupBag
, &backupKeybagHandle
);
134 require_quiet(SecKernError(ret
, error
, CFSTR("bag allocation failed: %d"), ret
), fail
);
136 ret
= aks_save_bag(backupKeybagHandle
, &keybagBytes
, &keybagSize
);
138 require_quiet(SecKernError(ret
, error
, CFSTR("save bag failed: %d"), ret
), fail
);
140 ret
= aks_unload_bag(backupKeybagHandle
);
142 if (ret
!= KERN_SUCCESS
) {
143 secerror("unload bag failed: %d", ret
);
146 result
= CFDataCreate(kCFAllocatorDefault
, keybagBytes
, keybagSize
);
148 require_quiet(SecAllocationError(result
, error
, CFSTR("Bag CFData Allocation Failed")), fail
);