]> git.saurik.com Git - apple/security.git/blob - sec/securityd/keystore.c
Security-55163.44.tar.gz
[apple/security.git] / sec / securityd / keystore.c
1 /*
2 * Copyright (c) 2010 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 * keystore.c - C API for the AppleKeyStore kext
26 */
27
28 #include <securityd/keystore.h>
29
30 #include <errno.h>
31 #include <limits.h>
32 #include <stdint.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/param.h>
36 #include <sys/stat.h>
37 #include <CoreFoundation/CFData.h>
38 #include <CommonCrypto/CommonDigest.h>
39 #include <CommonCrypto/CommonCryptor.h>
40 #include <libkern/OSByteOrder.h>
41 #include <security_utilities/debugging.h>
42 #include <assert.h>
43 #include <Security/SecInternal.h>
44 #include <TargetConditionals.h>
45 #include <AssertMacros.h>
46 #include <asl.h>
47
48 #if TARGET_OS_EMBEDDED && !TARGET_IPHONE_SIMULATOR
49 #define USE_KEYSTORE 1
50 #define USE_DISPATCH 1 /* Shouldn't be here. */
51 #else /* No AppleKeyStore.kext on this OS. */
52 #define USE_KEYSTORE 0
53 #endif /* hardware aes */
54
55 #if USE_KEYSTORE
56 #include <Kernel/IOKit/crypto/AppleKeyStoreDefs.h>
57
58 #if USE_DISPATCH
59 #include <dispatch/dispatch.h>
60 static dispatch_once_t ks_init_once;
61 #else /* !USE_DISPATCH use pthreads instead. */
62 #include <pthread.h>
63 static pthread_once_t ks_init_once = PTHREAD_ONCE_INIT;
64 #endif
65
66 static io_connect_t ks_connect_handle = MACH_PORT_NULL;
67
68 static void ks_service_matching_callback(void *refcon, io_iterator_t iterator)
69 {
70 io_object_t obj = IO_OBJECT_NULL;
71
72 while ((obj = IOIteratorNext(iterator))) {
73 kern_return_t ret = IOServiceOpen(obj, mach_task_self(), 0,
74 (io_connect_t*)refcon);
75 if (ret) {
76 asl_log(NULL, NULL, ASL_LEVEL_ERR,
77 "IOServiceOpen() failed: %d", ret);
78 }
79 IOObjectRelease(obj);
80 }
81 }
82
83 io_connect_t ks_connect_to_service(const char *className)
84 {
85 kern_return_t kernResult;
86 io_connect_t connect = IO_OBJECT_NULL;
87 io_iterator_t iterator = IO_OBJECT_NULL;
88 IONotificationPortRef notifyport = NULL;
89 CFDictionaryRef classToMatch;
90
91 if ((classToMatch = IOServiceMatching(className)) == NULL) {
92 asl_log(NULL, NULL, ASL_LEVEL_ERR,
93 "IOServiceMatching failed for '%s'", className);
94 return connect;
95 }
96
97 /* consumed by IOServiceGetMatchingServices, we need it if that fails. */
98 CFRetain(classToMatch);
99 kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault,
100 classToMatch, &iterator);
101
102 if (kernResult == KERN_SUCCESS) {
103 CFRelease(classToMatch);
104 } else {
105 asl_log(NULL, NULL, ASL_LEVEL_WARNING,
106 "IOServiceGetMatchingServices() failed %d", kernResult);
107
108 notifyport = IONotificationPortCreate(kIOMasterPortDefault);
109 if (!notifyport) {
110 asl_log(NULL, NULL, ASL_LEVEL_ERR,
111 "IONotificationPortCreate() failed");
112 return connect;
113 }
114
115 kernResult = IOServiceAddMatchingNotification(notifyport,
116 kIOFirstMatchNotification, classToMatch,
117 ks_service_matching_callback, &connect, &iterator);
118 if (kernResult) {
119 asl_log(NULL, NULL, ASL_LEVEL_ERR,
120 "IOServiceAddMatchingNotification() failed: %d", kernResult);
121 return connect;
122 }
123 }
124
125 /* Check whether it was already there before we registered for the
126 notification. */
127 ks_service_matching_callback(&connect, iterator);
128
129 if (notifyport) {
130 /* We'll get set up to wait for it to appear */
131 if (connect == IO_OBJECT_NULL) {
132 asl_log(NULL, NULL, ASL_LEVEL_ERR,
133 "Waiting for %s to show up.", className);
134 CFStringRef mode = CFSTR("WaitForCryptoService");
135 CFRunLoopAddSource(CFRunLoopGetCurrent(),
136 IONotificationPortGetRunLoopSource(notifyport), mode);
137 CFRunLoopRunInMode(mode, 30.0, true);
138 if (connect == MACH_PORT_NULL)
139 asl_log(NULL, NULL, ASL_LEVEL_ERR, "Cannot find %s", className);
140 }
141 IONotificationPortDestroy(notifyport);
142 }
143
144 IOObjectRelease(iterator);
145
146 if (connect != IO_OBJECT_NULL) {
147 secdebug("iokit", "obtained connection for '%s'", className);
148 }
149 return connect;
150 }
151
152 #if USE_DISPATCH
153 static void ks_crypto_init(void *unused)
154 #else
155 static void ks_crypto_init(void)
156 #endif
157 {
158 ks_connect_handle = ks_connect_to_service(kAppleKeyStoreServiceName);
159 }
160
161 io_connect_t ks_get_connect(void)
162 {
163 #if USE_DISPATCH
164 dispatch_once_f(&ks_init_once, NULL, ks_crypto_init);
165 #else
166 pthread_once(&ks_init_once, ks_crypto_init);
167 #endif
168 return ks_connect_handle;
169 }
170
171 bool ks_available(void)
172 {
173 ks_get_connect();
174 return true;
175 }
176
177
178 static bool ks_crypt(uint32_t selector, uint64_t keybag,
179 uint64_t keyclass, const uint8_t *input, size_t inputLength,
180 uint8_t *buffer, size_t *keySize) {
181 kern_return_t kernResult;
182
183 if (!ks_connect_handle) {
184 secdebug("ks", "AppleKeyStore.kext not found");
185 return false;
186 }
187
188 uint64_t inputs[] = { keybag, keyclass };
189 uint32_t num_inputs = sizeof(inputs)/sizeof(*inputs);
190 kernResult = IOConnectCallMethod(ks_connect_handle, selector,
191 inputs, num_inputs, input, inputLength, NULL, NULL, buffer,
192 keySize);
193
194 if (kernResult != KERN_SUCCESS) {
195 asl_log(NULL, NULL, ASL_LEVEL_ERR, "kAppleKeyStore selector(%d): %d",
196 selector, kernResult);
197 return false;
198 }
199 return true;
200 }
201
202 void ks_free(ks_object_t object) {
203 /* TODO: this might need to be vm_deallocate in some cases. */
204 free(object._kso);
205 }
206
207 uint8_t *ks_unwrap(uint64_t keybag, uint64_t keyclass,
208 const uint8_t *wrappedKey, size_t wrappedKeySize,
209 uint8_t *buffer, size_t bufferSize, size_t *keySize) {
210 *keySize = bufferSize;
211 if (!ks_crypt(kAppleKeyStoreKeyUnwrap,
212 keybag, keyclass, wrappedKey, wrappedKeySize, buffer, keySize))
213 return NULL;
214 return buffer;
215 }
216
217
218 uint8_t *ks_wrap(uint64_t keybag, uint64_t keyclass,
219 const uint8_t *key, size_t keyByteSize,
220 uint8_t *buffer, size_t bufferSize, size_t *wrappedKeySize) {
221 *wrappedKeySize = bufferSize;
222 if (ks_crypt(kAppleKeyStoreKeyWrap,
223 keybag, keyclass, key, keyByteSize,
224 buffer, wrappedKeySize))
225 return NULL;
226 return buffer;
227 }
228
229
230 #else /* !USE_KEYSTORE */
231
232 bool ks_available(void)
233 {
234 return false;
235 }
236
237 #endif /* !USE_KEYSTORE */