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#if TARGET_OS_EMBEDDED 41#include <MobileKeyBag/MobileKeyBag.h> 42#endif 43#endif /* USE_KEYSTORE */ 44 45 46/* g_keychain_handle is the keybag handle used for encrypting item in the keychain. 47 For testing purposes, it can be set to something other than the default, with SecItemServerSetKeychainKeybag */ 48#if USE_KEYSTORE 49#if TARGET_OS_MAC && !TARGET_OS_EMBEDDED 50keybag_handle_t g_keychain_keybag = session_keybag_handle; 51#else 52keybag_handle_t g_keychain_keybag = device_keybag_handle; 53#endif 54#else /* !USE_KEYSTORE */ 55keybag_handle_t g_keychain_keybag = 0; /* 0 == device_keybag_handle, constant dictated by AKS */ 56#endif /* USE_KEYSTORE */ 57 58void SecItemServerSetKeychainKeybag(int32_t keybag) 59{ 60 g_keychain_keybag=keybag; 61} 62 63void SecItemServerResetKeychainKeybag(void) 64{ 65#if USE_KEYSTORE 66#if TARGET_OS_MAC && !TARGET_OS_EMBEDDED 67 g_keychain_keybag = session_keybag_handle; 68#else 69 g_keychain_keybag = device_keybag_handle; 70#endif 71#else /* !USE_KEYSTORE */ 72 g_keychain_keybag = 0; /* 0 == device_keybag_handle, constant dictated by AKS */ 73#endif /* USE_KEYSTORE */ 74} 75 76#if USE_KEYSTORE 77 78static bool hwaes_key_available(void) 79{ 80 keybag_handle_t handle = bad_keybag_handle; 81 keybag_handle_t special_handle = bad_keybag_handle; 82#if TARGET_OS_MAC && !TARGET_OS_EMBEDDED 83 special_handle = session_keybag_handle; 84#elif TARGET_OS_EMBEDDED 85 special_handle = device_keybag_handle; 86#endif 87 kern_return_t kr = aks_get_system(special_handle, &handle); 88 if (kr != kIOReturnSuccess) { 89#if TARGET_OS_EMBEDDED 90 /* TODO: Remove this once the kext runs the daemon on demand if 91 there is no system keybag. */ 92 int kb_state = MKBGetDeviceLockState(NULL); 93 asl_log(NULL, NULL, ASL_LEVEL_INFO, "AppleKeyStore lock state: %d", kb_state); 94#endif 95 } 96 return true; 97} 98 99#else /* !USE_KEYSTORE */ 100 101static bool hwaes_key_available(void) 102{ 103 return false; 104} 105 106#endif /* USE_KEYSTORE */ 107 108/* Wrap takes a 128 - 256 bit key as input and returns output of 109 inputsize + 64 bits. 110 In bytes this means that a 111 16 byte (128 bit) key returns a 24 byte wrapped key 112 24 byte (192 bit) key returns a 32 byte wrapped key 113 32 byte (256 bit) key returns a 40 byte wrapped key */ 114bool ks_crypt(uint32_t operation, keybag_handle_t keybag, 115 keyclass_t keyclass, uint32_t textLength, const uint8_t *source, keyclass_t *actual_class, CFMutableDataRef dest, CFErrorRef *error) { 116#if USE_KEYSTORE 117 kern_return_t kernResult = kIOReturnBadArgument; 118 119 int dest_len = (int)CFDataGetLength(dest); 120 if (operation == kSecKsWrap) { 121 kernResult = aks_wrap_key(source, textLength, keyclass, keybag, CFDataGetMutableBytePtr(dest), &dest_len, actual_class); 122 } else if (operation == kSecKsUnwrap) { 123 kernResult = aks_unwrap_key(source, textLength, keyclass, keybag, CFDataGetMutableBytePtr(dest), &dest_len); 124 } 125 126 if (kernResult != KERN_SUCCESS) { 127 if ((kernResult == kIOReturnNotPermitted) || (kernResult == kIOReturnNotPrivileged)) { 128 /* Access to item attempted while keychain is locked. */ 129 return SecError(errSecInteractionNotAllowed, error, CFSTR("ks_crypt: %x failed to %s item (class %"PRId32", bag: %"PRId32") Access to item attempted while keychain is locked."), 130 kernResult, (operation == kSecKsWrap ? "wrap" : "unwrap"), keyclass, keybag); 131 } else if (kernResult == kIOReturnError) { 132 /* Item can't be decrypted on this device, ever, so drop the item. */ 133 return SecError(errSecDecode, error, CFSTR("ks_crypt: %x failed to %s item (class %"PRId32", bag: %"PRId32") Item can't be decrypted on this device, ever, so drop the item."), 134 kernResult, (operation == kSecKsWrap ? "wrap" : "unwrap"), keyclass, keybag); 135 } else { 136 return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: %x failed to %s item (class %"PRId32", bag: %"PRId32")"), 137 kernResult, (operation == kSecKsWrap ? "wrap" : "unwrap"), keyclass, keybag); 138 } 139 } 140 else 141 CFDataSetLength(dest, dest_len); 142 return true; 143#else /* !USE_KEYSTORE */ 144 uint32_t dest_len = (uint32_t)CFDataGetLength(dest); 145 if (operation == kSecKsWrap) { 146 /* The no encryption case. */ 147 if (dest_len >= textLength + 8) { 148 memcpy(CFDataGetMutableBytePtr(dest), source, textLength); 149 memset(CFDataGetMutableBytePtr(dest) + textLength, 8, 8); 150 CFDataSetLength(dest, textLength + 8); 151 *actual_class = keyclass; 152 } else 153 return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: failed to wrap item (class %"PRId32")"), keyclass); 154 } else if (operation == kSecKsUnwrap) { 155 if (dest_len + 8 >= textLength) { 156 memcpy(CFDataGetMutableBytePtr(dest), source, textLength - 8); 157 CFDataSetLength(dest, textLength - 8); 158 } else 159 return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: failed to unwrap item (class %"PRId32")"), keyclass); 160 } 161 return true; 162#endif /* USE_KEYSTORE */ 163} 164 165#if USE_KEYSTORE 166bool ks_crypt_acl(uint32_t operation, keybag_handle_t keybag, keyclass_t keyclass, 167 uint32_t textLength, const uint8_t *source, CFMutableDataRef dest, 168 CFDataRef acl, CFDataRef acm_context, CFDataRef caller_access_groups, CFErrorRef *error) { 169 kern_return_t kernResult = kIOReturnBadArgument; 170 uint8_t *params = NULL, *der = NULL; 171 const uint8_t *access_groups = caller_access_groups?CFDataGetBytePtr(caller_access_groups):NULL; 172 size_t params_len = 0, der_len = 0, access_groups_len = caller_access_groups?CFDataGetLength(caller_access_groups):0; 173 174 if (operation == kSecKsWrap) { 175 aks_operation_optional_params(0, 0, CFDataGetBytePtr(acl), CFDataGetLength(acl), 0, 0, (void**)¶ms, ¶ms_len); 176 kernResult = aks_encrypt(keybag, keyclass, source, textLength, params, params_len, (void**)&der, &der_len); 177 } else if (operation == kSecKsUnwrap) { 178 aks_operation_optional_params(access_groups, access_groups_len, 0, 0, CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), (void**)¶ms, ¶ms_len); 179 kernResult = aks_decrypt(keybag, source, textLength, params, params_len, (void**)&der, &der_len); 180 } else if (operation == kSecKsDelete) { 181 aks_operation_optional_params(access_groups, access_groups_len, 0, 0, CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), (void**)¶ms, ¶ms_len); 182 kernResult = aks_delete(keybag, source, textLength, params, params_len); 183 } 184 185 bool result = false; 186 if (kernResult != KERN_SUCCESS) { 187 if ((kernResult == kIOReturnNotPermitted) || (kernResult == kIOReturnNotPrivileged)) { 188 /* Access to item attempted while keychain is locked. */ 189 result = SecError(errSecInteractionNotAllowed, error, CFSTR("ks_crypt_acl: %x failed to %s item (class %"PRId32", bag: %"PRId32") Access to item attempted while keychain is locked."), 190 kernResult, (operation == kSecKsWrap ? "wrap" : "unwrap"), keyclass, keybag); 191 } else if (kernResult == kIOReturnError) { 192 /* Item can't be decrypted on this device, ever, so drop the item. */ 193 result = SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to %s item (class %"PRId32", bag: %"PRId32") Item can't be decrypted on this device, ever, so drop the item."), 194 kernResult, (operation == kSecKsWrap ? "wrap" : "unwrap"), keyclass, keybag); 195 } else { 196 result = SecError(errSecNotAvailable, error, CFSTR("ks_crypt_acl: %x failed to %s item (class %"PRId32", bag: %"PRId32")"), 197 kernResult, (operation == kSecKsWrap ? "wrap" : "unwrap"), keyclass, keybag); 198 } 199 } 200 else { 201 if (operation != kSecKsDelete) { 202 const uint8_t *value = der; 203 if (operation == kSecKsUnwrap) { 204 ccder_tag der_tag; 205 size_t der_tag_len; 206 value = ccder_decode_tag(&der_tag, der, der + der_len); 207 value = ccder_decode_len(&der_tag_len, value, der + der_len); 208 209 require_action(der_tag == CCDER_OCTET_STRING, out, 210 SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to %s item (class %"PRId32", bag: %"PRId32") Item can't be decrypted due to invalid der tag, so drop the item."), 211 kernResult, (operation == kSecKsWrap ? "wrap" : "unwrap"), keyclass, keybag)); 212 require_action(der_tag_len == (size_t)((der + der_len) - value), out, 213 SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to %s item (class %"PRId32", bag: %"PRId32") Item can't be decrypted due to invalid der tag length, so drop the item."), 214 kernResult, (operation == kSecKsWrap ? "wrap" : "unwrap"), keyclass, keybag)); 215 } 216 217 if(CFDataGetLength(dest) != (der + der_len) - value) 218 CFDataSetLength(dest, (der + der_len) - value); 219 220 memcpy(CFDataGetMutableBytePtr(dest), value, CFDataGetLength(dest)); 221 } 222 result = true; 223 } 224 225out: 226 if(params) 227 free(params); 228 if(der) 229 free(der); 230 return result; 231} 232#endif 233 234bool use_hwaes(void) { 235 static bool use_hwaes; 236 static dispatch_once_t check_once; 237 dispatch_once(&check_once, ^{ 238 use_hwaes = hwaes_key_available(); 239 if (use_hwaes) { 240 asl_log(NULL, NULL, ASL_LEVEL_INFO, "using hwaes key"); 241 } else { 242 asl_log(NULL, NULL, ASL_LEVEL_ERR, "unable to access hwaes key"); 243 } 244 }); 245 return use_hwaes; 246} 247 248bool ks_open_keybag(CFDataRef keybag, CFDataRef password, keybag_handle_t *handle, CFErrorRef *error) { 249#if USE_KEYSTORE 250 kern_return_t kernResult; 251 kernResult = aks_load_bag(CFDataGetBytePtr(keybag), (int)CFDataGetLength(keybag), handle); 252 if (kernResult) 253 return SecKernError(kernResult, error, CFSTR("aks_load_bag failed: %@"), keybag); 254 255 if (password) { 256 kernResult = aks_unlock_bag(*handle, CFDataGetBytePtr(password), (int)CFDataGetLength(password)); 257 if (kernResult) { 258 aks_unload_bag(*handle); 259 return SecKernError(kernResult, error, CFSTR("aks_unlock_bag failed")); 260 } 261 } 262 return true; 263#else /* !USE_KEYSTORE */ 264 *handle = KEYBAG_NONE; 265 return true; 266#endif /* USE_KEYSTORE */ 267} 268 269bool ks_close_keybag(keybag_handle_t keybag, CFErrorRef *error) { 270#if USE_KEYSTORE 271 IOReturn kernResult = aks_unload_bag(keybag); 272 if (kernResult) { 273 return SecKernError(kernResult, error, CFSTR("aks_unload_bag failed")); 274 } 275#endif /* USE_KEYSTORE */ 276 return true; 277} 278