2 * Copyright (c) 2010 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@
25 * keystore.c - C API for the AppleKeyStore kext
28 #include <securityd/keystore.h>
35 #include <sys/param.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>
43 #include <Security/SecInternal.h>
44 #include <TargetConditionals.h>
45 #include <AssertMacros.h>
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 */
56 #include <Kernel/IOKit/crypto/AppleKeyStoreDefs.h>
59 #include <dispatch/dispatch.h>
60 static dispatch_once_t ks_init_once
;
61 #else /* !USE_DISPATCH use pthreads instead. */
63 static pthread_once_t ks_init_once
= PTHREAD_ONCE_INIT
;
66 static io_connect_t ks_connect_handle
= MACH_PORT_NULL
;
68 static void ks_service_matching_callback(void *refcon
, io_iterator_t iterator
)
70 io_object_t obj
= IO_OBJECT_NULL
;
72 while ((obj
= IOIteratorNext(iterator
))) {
73 kern_return_t ret
= IOServiceOpen(obj
, mach_task_self(), 0,
74 (io_connect_t
*)refcon
);
76 asl_log(NULL
, NULL
, ASL_LEVEL_ERR
,
77 "IOServiceOpen() failed: %d", ret
);
83 io_connect_t
ks_connect_to_service(const char *className
)
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
;
91 if ((classToMatch
= IOServiceMatching(className
)) == NULL
) {
92 asl_log(NULL
, NULL
, ASL_LEVEL_ERR
,
93 "IOServiceMatching failed for '%s'", className
);
97 /* consumed by IOServiceGetMatchingServices, we need it if that fails. */
98 CFRetain(classToMatch
);
99 kernResult
= IOServiceGetMatchingServices(kIOMasterPortDefault
,
100 classToMatch
, &iterator
);
102 if (kernResult
== KERN_SUCCESS
) {
103 CFRelease(classToMatch
);
105 asl_log(NULL
, NULL
, ASL_LEVEL_WARNING
,
106 "IOServiceGetMatchingServices() failed %d", kernResult
);
108 notifyport
= IONotificationPortCreate(kIOMasterPortDefault
);
110 asl_log(NULL
, NULL
, ASL_LEVEL_ERR
,
111 "IONotificationPortCreate() failed");
115 kernResult
= IOServiceAddMatchingNotification(notifyport
,
116 kIOFirstMatchNotification
, classToMatch
,
117 ks_service_matching_callback
, &connect
, &iterator
);
119 asl_log(NULL
, NULL
, ASL_LEVEL_ERR
,
120 "IOServiceAddMatchingNotification() failed: %d", kernResult
);
125 /* Check whether it was already there before we registered for the
127 ks_service_matching_callback(&connect
, iterator
);
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
);
141 IONotificationPortDestroy(notifyport
);
144 IOObjectRelease(iterator
);
146 if (connect
!= IO_OBJECT_NULL
) {
147 secdebug("iokit", "obtained connection for '%s'", className
);
153 static void ks_crypto_init(void *unused
)
155 static void ks_crypto_init(void)
158 ks_connect_handle
= ks_connect_to_service(kAppleKeyStoreServiceName
);
161 io_connect_t
ks_get_connect(void)
164 dispatch_once_f(&ks_init_once
, NULL
, ks_crypto_init
);
166 pthread_once(&ks_init_once
, ks_crypto_init
);
168 return ks_connect_handle
;
171 bool ks_available(void)
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
;
183 if (!ks_connect_handle
) {
184 secdebug("ks", "AppleKeyStore.kext not found");
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
,
194 if (kernResult
!= KERN_SUCCESS
) {
195 asl_log(NULL
, NULL
, ASL_LEVEL_ERR
, "kAppleKeyStore selector(%d): %d",
196 selector
, kernResult
);
202 void ks_free(ks_object_t object
) {
203 /* TODO: this might need to be vm_deallocate in some cases. */
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
))
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
))
230 #else /* !USE_KEYSTORE */
232 bool ks_available(void)
237 #endif /* !USE_KEYSTORE */