]> git.saurik.com Git - apple/security.git/blob - OSX/utilities/SecAKSWrappers.c
Security-59306.41.2.tar.gz
[apple/security.git] / OSX / utilities / SecAKSWrappers.c
1 /*
2 * Copyright (c) 2013-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 // SecAKSWrappers.c
26 // utilities
27 //
28
29 #include <utilities/SecAKSWrappers.h>
30 #include <utilities/SecCFWrappers.h>
31 #include <utilities/SecCFError.h>
32
33 #if TARGET_OS_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
38 #elif TARGET_OS_MAC
39 # include <AppleKeyStoreEvents.h>
40 # define change_notification kAppleKeyStoreLockStatusNotificationID
41 #else
42 # error "unsupported target platform"
43 #endif
44
45 #if TARGET_OS_OSX && TARGET_HAS_KEYSTORE
46 // OS X
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;
50 #endif
51
52 #if TARGET_HAS_KEYSTORE
53 const AKSAssertionType_t lockAssertType = kAKSAssertTypeOther;
54 #endif
55
56 CFGiblisGetSingleton(dispatch_queue_t, GetKeybagAssertionQueue, sUserKeyBagAssertionLockQueue, ^{
57 *sUserKeyBagAssertionLockQueue = dispatch_queue_create("AKS Lock Assertion Queue", NULL);
58 })
59
60 #if TARGET_HAS_KEYSTORE
61 static uint32_t count = 0;
62 #endif
63 const char * const kUserKeybagStateChangeNotification = change_notification;
64
65 bool SecAKSUserKeybagHoldLockAssertion(uint64_t timeout, CFErrorRef *error){
66 #if !TARGET_HAS_KEYSTORE
67 return true;
68 #else
69 __block kern_return_t status = kAKSReturnSuccess;
70
71 dispatch_sync(GetKeybagAssertionQueue(), ^{
72 if (count == 0) {
73 secnotice("lockassertions", "Requesting lock assertion for %lld seconds", timeout);
74 status = aks_assert_hold(keybagHandle, lockAssertType, timeout);
75 }
76
77 if (status == kAKSReturnSuccess)
78 ++count;
79 });
80 return SecKernError(status, error, CFSTR("Kern return error"));
81 #endif /* !TARGET_HAS_KEYSTORE */
82 }
83
84 bool SecAKSUserKeybagDropLockAssertion(CFErrorRef *error){
85 #if !TARGET_HAS_KEYSTORE
86 return true;
87 #else
88 __block kern_return_t status = kAKSReturnSuccess;
89
90 dispatch_sync(GetKeybagAssertionQueue(), ^{
91 if (count && (--count == 0)) {
92 secnotice("lockassertions", "Dropping lock assertion");
93 status = aks_assert_drop(keybagHandle, lockAssertType);
94 }
95 });
96
97 return SecKernError(status, error, CFSTR("Kern return error"));
98 #endif /* !TARGET_HAS_KEYSTORE */
99 }
100 bool SecAKSDoWithUserBagLockAssertion(CFErrorRef *error, dispatch_block_t action)
101 {
102 #if !TARGET_HAS_KEYSTORE
103 action();
104 return true;
105 #else
106 // Acquire lock assertion, ref count?
107
108 bool status = false;
109 uint64_t timeout = 60ull;
110 if (SecAKSUserKeybagHoldLockAssertion(timeout, error)) {
111 action();
112 status = SecAKSUserKeybagDropLockAssertion(error);
113 }
114 return status;
115 #endif /* !TARGET_HAS_KEYSTORE */
116 }
117
118 bool SecAKSDoWithUserBagLockAssertionSoftly(dispatch_block_t action)
119 {
120 #if !TARGET_HAS_KEYSTORE
121 action();
122 return true;
123 #else
124 uint64_t timeout = 60ull;
125 CFErrorRef localError = NULL;
126
127 bool heldAssertion = SecAKSUserKeybagHoldLockAssertion(timeout, &localError);
128 if (!heldAssertion) {
129 secnotice("secaks", "SecAKSDoWithUserBagLockAssertionSoftly: failed to get assertion proceeding bravely: %@", localError);
130 CFReleaseNull(localError);
131 }
132
133 action();
134
135 if (heldAssertion) {
136 (void)SecAKSUserKeybagDropLockAssertion(&localError);
137 CFReleaseNull(localError);
138 }
139 return true;
140 #endif /* !TARGET_HAS_KEYSTORE */
141 }
142
143
144 CFDataRef SecAKSCopyBackupBagWithSecret(size_t size, uint8_t *secret, CFErrorRef *error) {
145 #if !TARGET_HAS_KEYSTORE
146 return NULL;
147 #else
148 CFDataRef result = NULL;
149 void *keybagBytes = NULL;
150 int keybagSize = 0;
151
152 keybag_handle_t backupKeybagHandle = -1;
153 kern_return_t ret;
154
155 require_quiet(SecRequirementError(0 <= size && size <= INT_MAX, error, CFSTR("Invalid size: %zu"), size), fail);
156
157 ret = aks_create_bag(secret, (int) size, kAppleKeyStoreAsymmetricBackupBag, &backupKeybagHandle);
158
159 require_quiet(SecKernError(ret, error, CFSTR("bag allocation failed: %d"), ret), fail);
160
161 ret = aks_save_bag(backupKeybagHandle, &keybagBytes, &keybagSize);
162
163 require_quiet(SecKernError(ret, error, CFSTR("save bag failed: %d"), ret), fail);
164
165 ret = aks_unload_bag(backupKeybagHandle);
166
167 if (ret != KERN_SUCCESS) {
168 secerror("unload bag failed: %d", ret);
169 }
170
171 result = CFDataCreate(kCFAllocatorDefault, keybagBytes, keybagSize);
172
173 require_quiet(SecAllocationError(result, error, CFSTR("Bag CFData Allocation Failed")), fail);
174
175 fail:
176 if (keybagBytes)
177 free(keybagBytes);
178 return result;
179 #endif
180 }
181
182 keyclass_t SecAKSSanitizedKeyclass(keyclass_t keyclass)
183 {
184 keyclass_t sanitizedKeyclass = keyclass;
185 #if TARGET_HAS_KEYSTORE
186 if (keyclass > key_class_last) {
187 // idea is that AKS may return a keyclass value with extra bits above key_class_last from aks_wrap_key, but we only keep metadata keys for the canonical key classes
188 // so just sanitize all our inputs to the canonical values
189 sanitizedKeyclass = keyclass & key_class_last;
190 secinfo("SanitizeKeyclass", "sanitizing request for keyclass %d to keyclass %d", keyclass, sanitizedKeyclass);
191 }
192 #endif
193 return sanitizedKeyclass;
194 }