SecKeybagSupport.c
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 "keychain/securityd/SecKeybagSupport.h" 31 #include <TargetConditionals.h> 32 33 #include "keychain/securityd/SecItemServer.h" 34 35 #if USE_KEYSTORE 36 #include <IOKit/IOKitLib.h> 37 #include <libaks_acl_cf_keys.h> 38 #include <utilities/der_plist.h> 39 #include <corecrypto/ccder.h> 40 #include <ACMLib.h> 41 #else /* !USE_KEYSTORE */ 42 #include <utilities/SecInternalReleasePriv.h> 43 #endif /* USE_KEYSTORE */ 44 45 #include <CommonCrypto/CommonCryptor.h> 46 #include <CommonCrypto/CommonCryptorSPI.h> 47 48 #include "OSX/utilities/SecAKSWrappers.h" 49 50 /* g_keychain_handle is the keybag handle used for encrypting item in the keychain. 51 For testing purposes, it can be set to something other than the default, with SecItemServerSetKeychainKeybag */ 52 #if USE_KEYSTORE 53 #if TARGET_OS_OSX 54 keybag_handle_t g_keychain_keybag = session_keybag_handle; 55 #else 56 keybag_handle_t g_keychain_keybag = device_keybag_handle; 57 #endif 58 #else /* !USE_KEYSTORE */ 59 keybag_handle_t g_keychain_keybag = 0; /* 0 == device_keybag_handle, constant dictated by AKS */ 60 #endif /* USE_KEYSTORE */ 61 62 const CFStringRef kSecKSKeyData1 = CFSTR("d1"); 63 const CFStringRef kSecKSKeyData2 = CFSTR("d2"); 64 65 void SecItemServerSetKeychainKeybag(int32_t keybag) 66 { 67 g_keychain_keybag=keybag; 68 } 69 70 void SecItemServerResetKeychainKeybag(void) 71 { 72 #if USE_KEYSTORE 73 #if TARGET_OS_OSX 74 g_keychain_keybag = session_keybag_handle; 75 #else 76 g_keychain_keybag = device_keybag_handle; 77 #endif 78 #else /* !USE_KEYSTORE */ 79 g_keychain_keybag = 0; /* 0 == device_keybag_handle, constant dictated by AKS */ 80 #endif /* USE_KEYSTORE */ 81 } 82 83 /* Wrap takes a 128 - 256 bit key as input and returns output of 84 inputsize + 64 bits. 85 In bytes this means that a 86 16 byte (128 bit) key returns a 24 byte wrapped key 87 24 byte (192 bit) key returns a 32 byte wrapped key 88 32 byte (256 bit) key returns a 40 byte wrapped key */ 89 bool ks_crypt(CFTypeRef operation, keybag_handle_t keybag, 90 keyclass_t keyclass, uint32_t textLength, const uint8_t *source, keyclass_t *actual_class, CFMutableDataRef dest, CFErrorRef *error) { 91 #if USE_KEYSTORE 92 kern_return_t kernResult = kAKSReturnBadArgument; 93 94 int dest_len = (int)CFDataGetLength(dest); 95 if (CFEqual(operation, kAKSKeyOpEncrypt)) { 96 kernResult = aks_wrap_key(source, textLength, keyclass, keybag, CFDataGetMutableBytePtr(dest), &dest_len, actual_class); 97 } else if (CFEqual(operation, kAKSKeyOpDecrypt) || CFEqual(operation, kAKSKeyOpDelete)) { 98 kernResult = aks_unwrap_key(source, textLength, keyclass, keybag, CFDataGetMutableBytePtr(dest), &dest_len); 99 } 100 101 if (kernResult != KERN_SUCCESS) { 102 if ((kernResult == kAKSReturnNoPermission) || (kernResult == kAKSReturnNotPrivileged)) { 103 const char *substatus = ""; 104 if (keyclass == key_class_ck || keyclass == key_class_cku) 105 substatus = " (hibernation?)"; 106 /* Access to item attempted while keychain is locked. */ 107 return SecError(errSecInteractionNotAllowed, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") Access to item attempted while keychain is locked%s."), 108 kernResult, operation, keyclass, keybag, substatus); 109 } else if (kernResult == kAKSReturnNotFound) { 110 return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") No key available for class."), kernResult, operation, keyclass, keybag); 111 } else if (kernResult == kAKSReturnError || kernResult == kAKSReturnDecodeError) { 112 /* Item can't be decrypted on this device, ever, so drop the item. */ 113 return SecError(errSecDecode, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") Item can't be decrypted on this device, ever, so drop the item."), 114 kernResult, operation, keyclass, keybag); 115 } else { 116 return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32")"), 117 kernResult, operation, keyclass, keybag); 118 } 119 } 120 else 121 CFDataSetLength(dest, dest_len); 122 return true; 123 #else /* !USE_KEYSTORE */ 124 125 uint32_t dest_len = (uint32_t)CFDataGetLength(dest); 126 if (CFEqual(operation, kAKSKeyOpEncrypt)) { 127 /* The no encryption case. */ 128 if (dest_len >= textLength + 8) { 129 memcpy(CFDataGetMutableBytePtr(dest), source, textLength); 130 memset(CFDataGetMutableBytePtr(dest) + textLength, 8, 8); 131 CFDataSetLength(dest, textLength + 8); 132 *actual_class = keyclass; 133 } else 134 return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: failed to wrap item (class %"PRId32")"), keyclass); 135 } else if (CFEqual(operation, kAKSKeyOpDecrypt) || CFEqual(operation, kAKSKeyOpDelete)) { 136 if (dest_len + 8 >= textLength) { 137 memcpy(CFDataGetMutableBytePtr(dest), source, textLength - 8); 138 CFDataSetLength(dest, textLength - 8); 139 } else 140 return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: failed to unwrap item (class %"PRId32")"), keyclass); 141 } 142 return true; 143 #endif /* USE_KEYSTORE */ 144 } 145 146 #if USE_KEYSTORE 147 bool ks_access_control_needed_error(CFErrorRef *error, CFDataRef access_control_data, CFTypeRef operation) { 148 if (error == NULL) 149 return false; 150 151 if (*error && CFErrorGetCode(*error) != errSecAuthNeeded) { 152 // If we already had an error there, just leave it, no access_control specific error is needed here. 153 return false; 154 } 155 156 // Create new error instance which adds new access control data appended to existing 157 CFMutableDictionaryRef user_info; 158 if (*error) { 159 CFDictionaryRef old_user_info = CFErrorCopyUserInfo(*error); 160 user_info = CFDictionaryCreateMutableCopy(NULL, 0, old_user_info); 161 CFRelease(old_user_info); 162 CFReleaseNull(*error); 163 } else { 164 user_info = CFDictionaryCreateMutableForCFTypes(NULL); 165 } 166 167 if (access_control_data) { 168 CFNumberRef key = CFNumberCreateWithCFIndex(NULL, errSecAuthNeeded); 169 CFMutableArrayRef acls; 170 CFArrayRef old_acls = CFDictionaryGetValue(user_info, key); 171 if (old_acls) 172 acls = CFArrayCreateMutableCopy(NULL, 0, old_acls); 173 else 174 acls = CFArrayCreateMutableForCFTypes(NULL); 175 176 CFArrayRef pair = CFArrayCreateForCFTypes(NULL, access_control_data, operation, NULL); 177 CFArrayAppendValue(acls, pair); 178 CFRelease(pair); 179 180 CFDictionarySetValue(user_info, key, acls); 181 CFRelease(key); 182 CFRelease(acls); 183 184 *error = CFErrorCreate(NULL, kSecErrorDomain, errSecAuthNeeded, user_info); 185 } 186 else 187 *error = CFErrorCreate(NULL, kSecErrorDomain, errSecAuthNeeded, NULL); 188 189 CFReleaseSafe(user_info); 190 return false; 191 } 192 193 static bool merge_der_in_to_data(const void *ed_blob, size_t ed_blob_len, const void *key_blob, size_t key_blob_len, CFMutableDataRef mergedData) 194 { 195 bool ok = false; 196 CFDataRef ed_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, ed_blob, ed_blob_len, kCFAllocatorNull); 197 CFDataRef key_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, key_blob, key_blob_len, kCFAllocatorNull); 198 199 if (ed_data && key_data) { 200 CFDictionaryRef result_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, kSecKSKeyData1, ed_data, kSecKSKeyData2, key_data, NULL); 201 202 CFDataSetLength(mergedData, 0); 203 CFDataRef der_data = CFPropertyListCreateDERData(kCFAllocatorDefault, result_dict, NULL); 204 if (der_data) { 205 CFDataAppend(mergedData, der_data); 206 CFRelease(der_data); 207 ok = CFDataGetLength(mergedData) > 0; 208 } 209 CFRelease(result_dict); 210 } 211 212 CFReleaseSafe(ed_data); 213 CFReleaseSafe(key_data); 214 return ok; 215 } 216 217 bool ks_separate_data_and_key(CFDictionaryRef blob_dict, CFDataRef *ed_data, CFDataRef *key_data) 218 { 219 bool ok = false; 220 CFDataRef tmp_ed_data = CFDictionaryGetValue(blob_dict, kSecKSKeyData1); 221 CFDataRef tmp_key_data = CFDictionaryGetValue(blob_dict, kSecKSKeyData2); 222 223 if (tmp_ed_data && tmp_key_data && 224 CFDataGetTypeID() == CFGetTypeID(tmp_ed_data) && 225 CFDataGetTypeID() == CFGetTypeID(tmp_key_data)) { 226 *ed_data = CFRetain(tmp_ed_data); 227 *key_data = CFRetain(tmp_key_data); 228 ok = true; 229 } 230 231 return ok; 232 } 233 234 bool create_cferror_from_aks(int aks_return, CFTypeRef operation, keybag_handle_t keybag, keyclass_t keyclass, CFDataRef access_control_data, CFDataRef acm_context_data, CFErrorRef *error) 235 { 236 const char *operation_string = ""; 237 if (CFEqual(operation, kAKSKeyOpDecrypt)) { 238 operation_string = "decrypt"; 239 } else if (CFEqual(operation, kAKSKeyOpEncrypt)) { 240 operation_string = "encrypt"; 241 } if (CFEqual(operation, kAKSKeyOpDelete)) { 242 operation_string = "delete"; 243 } 244 245 if (aks_return == kAKSReturnNoPermission) { 246 /* Keychain is locked. */ 247 SecError(errSecInteractionNotAllowed, error, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32", bag: %"PRId32") Access to item attempted while keychain is locked."), 248 aks_return, operation_string, keyclass, keybag); 249 } else if (aks_return == kAKSReturnPolicyError || aks_return == kAKSReturnBadPassword) { 250 if (aks_return == kAKSReturnBadPassword) { 251 ACMContextRef acm_context_ref = NULL; 252 acm_context_ref = ACMContextCreateWithExternalForm(CFDataGetBytePtr(acm_context_data), CFDataGetLength(acm_context_data)); 253 if (acm_context_ref) { 254 ACMContextRemovePassphraseCredentialsByPurposeAndScope(acm_context_ref, kACMPassphrasePurposeGeneral, kACMScopeContext); 255 ACMContextDelete(acm_context_ref, false); 256 } 257 } 258 259 /* Item needed authentication. */ 260 ks_access_control_needed_error(error, access_control_data, operation); 261 } else if (aks_return == kAKSReturnError || aks_return == kAKSReturnPolicyInvalid || aks_return == kAKSReturnDecodeError) { 262 /* Item can't be decrypted on this device, ever, so drop the item. */ 263 SecError(errSecDecode, error, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32", bag: %"PRId32") Item can't be decrypted on this device, ever, so drop the item."), 264 aks_return, operation_string, keyclass, keybag); 265 266 } else if (aks_return == kAKSReturnNotFound) { 267 return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") No key available for class."), aks_return, operation, keyclass, keybag); 268 } else { 269 SecError(errSecNotAvailable, error, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32", bag: %"PRId32")"), 270 aks_return, operation_string, keyclass, keybag); 271 } 272 273 return false; 274 } 275 276 bool ks_encrypt_acl(keybag_handle_t keybag, keyclass_t keyclass, uint32_t textLength, const uint8_t *source, 277 CFMutableDataRef dest, CFDataRef auth_data, CFDataRef acm_context, 278 SecAccessControlRef access_control, CFErrorRef *error) { 279 void *params = NULL, *der = NULL; 280 size_t params_len = 0, der_len = 0; 281 CFDataRef access_control_data = SecAccessControlCopyData(access_control); 282 int aks_return = kAKSReturnSuccess; 283 aks_ref_key_t key_handle = NULL; 284 285 /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */ 286 bool ok = false; 287 if (!acm_context || !SecAccessControlIsBound(access_control)) { 288 require_quiet(ok = ks_access_control_needed_error(error, access_control_data, SecAccessControlIsBound(access_control) ? kAKSKeyOpEncrypt : CFSTR("")), out); 289 } 290 291 aks_operation_optional_params(0, 0, CFDataGetBytePtr(auth_data), CFDataGetLength(auth_data), CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), ¶ms, ¶ms_len); 292 require_noerr_action_quiet(aks_return = aks_ref_key_create(keybag, keyclass, key_type_sym, params, params_len, &key_handle), out, 293 create_cferror_from_aks(aks_return, kAKSKeyOpEncrypt, keybag, keyclass, access_control_data, acm_context, error)); 294 require_noerr_action_quiet(aks_return = aks_ref_key_encrypt(key_handle, params, params_len, source, textLength, &der, &der_len), out, 295 create_cferror_from_aks(aks_return, kAKSKeyOpEncrypt, keybag, keyclass, access_control_data, acm_context, error)); 296 size_t key_blob_len; 297 const void *key_blob = aks_ref_key_get_blob(key_handle, &key_blob_len); 298 require_action_quiet(key_blob, out, SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item (class %"PRId32", bag: %"PRId32") Item can't be encrypted due to invalid key data, so drop the item."), 299 aks_return, "encrypt", keyclass, keybag)); 300 301 require_action_quiet(merge_der_in_to_data(der, der_len, key_blob, key_blob_len, dest), out, 302 SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item (class %"PRId32", bag: %"PRId32") Item can't be encrypted due to merge failed, so drop the item."), 303 aks_return, "encrypt", keyclass, keybag)); 304 305 ok = true; 306 307 out: 308 if (key_handle) 309 aks_ref_key_free(&key_handle); 310 if(params) 311 free(params); 312 if(der) 313 free(der); 314 CFReleaseSafe(access_control_data); 315 return ok; 316 } 317 318 bool ks_decrypt_acl(aks_ref_key_t ref_key, CFDataRef encrypted_data, CFMutableDataRef dest, 319 CFDataRef acm_context, CFDataRef caller_access_groups, 320 SecAccessControlRef access_control, CFErrorRef *error) { 321 void *params = NULL, *der = NULL; 322 const uint8_t *access_groups = caller_access_groups?CFDataGetBytePtr(caller_access_groups):NULL; 323 size_t params_len = 0, der_len = 0, access_groups_len = caller_access_groups?CFDataGetLength(caller_access_groups):0; 324 CFDataRef access_control_data = SecAccessControlCopyData(access_control); 325 int aks_return = kAKSReturnSuccess; 326 327 /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */ 328 bool ok = false; 329 if (!acm_context) { 330 require_quiet(ok = ks_access_control_needed_error(error, NULL, NULL), out); 331 } 332 333 aks_operation_optional_params(access_groups, access_groups_len, 0, 0, CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), ¶ms, ¶ms_len); 334 require_noerr_action_quiet(aks_return = aks_ref_key_decrypt(ref_key, params, params_len, CFDataGetBytePtr(encrypted_data), CFDataGetLength(encrypted_data), &der, &der_len), out, 335 create_cferror_from_aks(aks_return, kAKSKeyOpDecrypt, 0, 0, access_control_data, acm_context, error)); 336 require_action_quiet(der, out, SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item, Item can't be decrypted due to invalid der data, so drop the item."), 337 aks_return, "decrypt")); 338 339 CFPropertyListRef decoded_data = NULL; 340 der_decode_plist(kCFAllocatorDefault, &decoded_data, NULL, der, der + der_len); 341 require_action_quiet(decoded_data, out, SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item, Item can't be decrypted due to failed decode der, so drop the item."), 342 aks_return, "decrypt")); 343 if (CFGetTypeID(decoded_data) == CFDataGetTypeID()) { 344 CFDataSetLength(dest, 0); 345 CFDataAppend(dest, decoded_data); 346 CFRelease(decoded_data); 347 } 348 else { 349 CFRelease(decoded_data); 350 require_action_quiet(false, out, SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item, Item can't be decrypted due to wrong data, so drop the item."), 351 aks_return, "decrypt")); 352 } 353 354 ok = true; 355 356 out: 357 if(params) 358 free(params); 359 if(der) 360 free(der); 361 CFReleaseSafe(access_control_data); 362 return ok; 363 } 364 365 bool ks_delete_acl(aks_ref_key_t ref_key, CFDataRef encrypted_data, 366 CFDataRef acm_context, CFDataRef caller_access_groups, 367 SecAccessControlRef access_control, CFErrorRef *error) { 368 void *params = NULL; 369 CFDataRef access_control_data = NULL; 370 int aks_return = kAKSReturnSuccess; 371 bool ok = false; 372 373 nrequire_action_quiet(CFEqualSafe(SecAccessControlGetConstraint(access_control, kAKSKeyOpDelete), kCFBooleanTrue), out, ok = true); 374 375 /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */ 376 if (!acm_context) { 377 require_quiet(ok = ks_access_control_needed_error(error, NULL, NULL), out); 378 } 379 380 access_control_data = SecAccessControlCopyData(access_control); 381 const uint8_t *access_groups = caller_access_groups?CFDataGetBytePtr(caller_access_groups):NULL; 382 size_t params_len = 0, access_groups_len = caller_access_groups?CFDataGetLength(caller_access_groups):0; 383 aks_operation_optional_params(access_groups, access_groups_len, 0, 0, CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), ¶ms, ¶ms_len); 384 require_noerr_action_quiet(aks_return = aks_ref_key_delete(ref_key, params, params_len), out, 385 create_cferror_from_aks(aks_return, kAKSKeyOpDelete, 0, 0, access_control_data, acm_context, error)); 386 387 ok = true; 388 389 out: 390 if(params) 391 free(params); 392 CFReleaseSafe(access_control_data); 393 return ok; 394 } 395 396 const void* ks_ref_key_get_external_data(keybag_handle_t keybag, CFDataRef key_data, aks_ref_key_t *ref_key, size_t *external_data_len, CFErrorRef *error) { 397 int aks_return = aks_ref_key_create_with_blob(keybag, CFDataGetBytePtr(key_data), CFDataGetLength(key_data), ref_key); 398 if (aks_return == kAKSReturnBadArgument) { 399 SecError(errSecDecode, error, CFSTR("aks_ref_key: failed to create ref key with blob because bad data (bag: %"PRId32")"), keybag); 400 return NULL; 401 // As of this writing the only other error code is kAKSReturnInternalError but we don't want to rely on that 402 } else if (aks_return != kAKSReturnSuccess) { 403 SecError(errSecDecode, error, CFSTR("aks_ref_key: failed to create ref key with blob: %x (bag: %"PRId32")"), aks_return, keybag); 404 return NULL; 405 } 406 return aks_ref_key_get_external_data(*ref_key, external_data_len); 407 } 408 #endif 409 410 bool use_hwaes(void) { 411 #if !TARGET_OS_BRIDGE 412 static bool use_hwaes; 413 static dispatch_once_t check_once; 414 dispatch_once(&check_once, ^{ 415 use_hwaes = hwaes_key_available(); 416 if (use_hwaes) { 417 secinfo("aks", "using hwaes key"); 418 } else { 419 secerror("unable to access hwaes key"); 420 } 421 }); 422 return use_hwaes; 423 #else 424 return false; 425 #endif // TARGET_OS_BRIDGE 426 } 427 428 bool ks_open_keybag(CFDataRef keybag, CFDataRef password, keybag_handle_t *handle, CFErrorRef *error) { 429 #if USE_KEYSTORE 430 kern_return_t kernResult; 431 if (!asData(keybag, error)) return false; 432 kernResult = aks_load_bag(CFDataGetBytePtr(keybag), (int)CFDataGetLength(keybag), handle); 433 if (kernResult) 434 return SecKernError(kernResult, error, CFSTR("aks_load_bag failed: %@"), keybag); 435 436 if (password) { 437 kernResult = aks_unlock_bag(*handle, CFDataGetBytePtr(password), (int)CFDataGetLength(password)); 438 if (kernResult) { 439 aks_unload_bag(*handle); 440 return SecKernError(kernResult, error, CFSTR("aks_unlock_bag failed")); 441 } 442 } 443 return true; 444 #else /* !USE_KEYSTORE */ 445 *handle = KEYBAG_NONE; 446 return true; 447 #endif /* USE_KEYSTORE */ 448 } 449 450 bool ks_close_keybag(keybag_handle_t keybag, CFErrorRef *error) { 451 #if USE_KEYSTORE 452 IOReturn kernResult = aks_unload_bag(keybag); 453 if (kernResult) { 454 return SecKernError(kernResult, error, CFSTR("aks_unload_bag failed")); 455 } 456 #endif /* USE_KEYSTORE */ 457 return true; 458 } 459