SOSBackupSliceKeyBag.m
1 /* 2 * Copyright (c) 2015-2017 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 // Our Header 26 27 #include <Security/SecureObjectSync/SOSBackupSliceKeyBag.h> 28 29 30 // Needed headers for implementation 31 #include "AssertMacros.h" 32 #include <utilities/SecCFWrappers.h> 33 #include <utilities/SecAKSWrappers.h> 34 #include <utilities/SecBuffer.h> 35 #include <utilities/SecCFError.h> 36 #include <utilities/der_set.h> 37 #include <utilities/der_plist_internal.h> 38 #include <Security/SecRandom.h> 39 #include <Security/SecureObjectSync/SOSPeerInfo.h> 40 #include "keychain/SecureObjectSync/SOSPeerInfoCollections.h" 41 #include "keychain/SecureObjectSync/SOSInternal.h" 42 43 #include <corecrypto/ccec.h> 44 #include <corecrypto/ccsha2.h> 45 #include <corecrypto/ccrng.h> 46 47 #include <limits.h> 48 49 #include <Security/SecRecoveryKey.h> 50 #include "SOSKeyedPubKeyIdentifier.h" 51 #include "keychain/SecureObjectSync/SOSInternal.h" 52 #include "SecCFAllocator.h" 53 54 CFStringRef bskbRkbgPrefix = CFSTR("RK"); 55 56 CFDataRef SOSRKNullKey(void) { 57 static CFDataRef localNullKey = NULL; 58 static dispatch_once_t onceToken; 59 dispatch_once(&onceToken, ^{ 60 localNullKey = CFDataCreate(kCFAllocatorDefault, (const UInt8*) "nullkey", 8); 61 }); 62 return localNullKey; 63 } 64 65 // 66 // MARK: Type creation 67 // 68 69 CFGiblisFor(SOSBackupSliceKeyBag); 70 71 const int kAKSBagSecretLength = 32; 72 73 struct __OpaqueSOSBackupSliceKeyBag { 74 CFRuntimeBase _base; 75 76 CFDataRef aks_bag; 77 78 CFSetRef peers; 79 CFDictionaryRef wrapped_keys; 80 }; 81 82 static void SOSBackupSliceKeyBagDestroy(CFTypeRef aObj) { 83 SOSBackupSliceKeyBagRef vb = (SOSBackupSliceKeyBagRef) aObj; 84 85 CFReleaseNull(vb->aks_bag); 86 CFReleaseNull(vb->peers); 87 CFReleaseNull(vb->wrapped_keys); 88 } 89 90 static CFSetRef SOSBackupSliceKeyBagCopyPeerNames(SOSBackupSliceKeyBagRef bksb) { 91 CFMutableSetRef retval = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); 92 if(!retval) return NULL; 93 CFSetForEach(bksb->peers, ^(const void *value) { 94 SOSPeerInfoRef pi = (SOSPeerInfoRef) value; 95 CFSetAddValue(retval, SOSPeerInfoGetPeerName(pi)); 96 }); 97 return retval; 98 } 99 100 static CFStringRef SOSBackupSliceKeyBagCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) { 101 SOSBackupSliceKeyBagRef vb = (SOSBackupSliceKeyBagRef) aObj; 102 103 CFMutableStringRef retval = CFStringCreateMutable(kCFAllocatorDefault, 0); 104 105 CFSetRef peerIDs = SOSBackupSliceKeyBagCopyPeerNames(vb); 106 CFStringSetPerformWithDescription(peerIDs, ^(CFStringRef description) { 107 CFStringAppendFormat(retval, NULL, CFSTR("<SOSBackupSliceKeyBag@%p %ld %@"), vb, vb->peers ? CFSetGetCount(vb->peers) : 0, description); 108 }); 109 CFReleaseNull(peerIDs); 110 CFStringAppend(retval, CFSTR(">")); 111 112 return retval; 113 } 114 115 116 // 117 // MARK: Encode/Decode 118 // 119 120 const uint8_t* der_decode_BackupSliceKeyBag(CFAllocatorRef allocator, 121 SOSBackupSliceKeyBagRef* BackupSliceKeyBag, CFErrorRef *error, 122 const uint8_t* der, const uint8_t *der_end) { 123 if (der == NULL) return der; 124 125 const uint8_t *result = NULL; 126 SOSBackupSliceKeyBagRef vb = CFTypeAllocate(SOSBackupSliceKeyBag, struct __OpaqueSOSBackupSliceKeyBag, allocator); 127 require_quiet(SecAllocationError(vb, error, CFSTR("View bag allocation failed")), fail); 128 129 const uint8_t *sequence_end = NULL; 130 der = ccder_decode_sequence_tl(&sequence_end, der, der_end); 131 require_quiet(sequence_end == der_end, fail); 132 133 der = der_decode_data(kCFAllocatorDefault, &vb->aks_bag, error, der, sequence_end); 134 vb->peers = SOSPeerInfoSetCreateFromArrayDER(kCFAllocatorDefault, &kSOSPeerSetCallbacks, error, 135 &der, der_end); 136 der = der_decode_dictionary(kCFAllocatorDefault, &vb->wrapped_keys, error, der, sequence_end); 137 138 require_quiet(SecRequirementError(der == der_end, error, CFSTR("Extra space in sequence")), fail); 139 140 if (BackupSliceKeyBag) 141 CFTransferRetained(*BackupSliceKeyBag, vb); 142 143 result = der; 144 145 fail: 146 CFReleaseNull(vb); 147 return result; 148 } 149 150 size_t der_sizeof_BackupSliceKeyBag(SOSBackupSliceKeyBagRef BackupSliceKeyBag, CFErrorRef *error) { 151 size_t result = 0; 152 153 require_quiet(SecRequirementError(BackupSliceKeyBag != NULL, error, CFSTR("Null BackupSliceKeyBag")), fail); 154 require_quiet(BackupSliceKeyBag != NULL, fail); // this is redundant with what happens in SecRequirementError, but the analyzer can't understand that. 155 require_quiet(SecRequirementError(BackupSliceKeyBag->aks_bag != NULL, error, CFSTR("null aks_bag in BackupSliceKeyBag")), fail); 156 require_quiet(BackupSliceKeyBag->aks_bag != NULL, fail); // this is redundant with what happens in SecRequirementError, but the analyzer can't understand that. 157 158 size_t bag_size = der_sizeof_data(BackupSliceKeyBag->aks_bag, error); 159 require_quiet(bag_size, fail); 160 161 size_t peers_size = SOSPeerInfoSetGetDEREncodedArraySize(BackupSliceKeyBag->peers, error); 162 require_quiet(peers_size, fail); 163 164 size_t wrapped_keys_size = der_sizeof_dictionary(BackupSliceKeyBag->wrapped_keys, error); 165 require_quiet(wrapped_keys_size, fail); 166 167 result = ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, bag_size + peers_size + wrapped_keys_size); 168 169 fail: 170 return result; 171 } 172 173 uint8_t* der_encode_BackupSliceKeyBag(SOSBackupSliceKeyBagRef set, CFErrorRef *error, 174 const uint8_t *der, uint8_t *der_end) { 175 uint8_t *result = NULL; 176 if (der_end == NULL) return der_end; 177 178 require_quiet(SecRequirementError(set != NULL, error, CFSTR("Null set passed to encode")), fail); 179 require_quiet(set, fail); // Silence the NULL warning. 180 181 require_quiet(SecRequirementError(set->aks_bag != NULL, error, CFSTR("Null set passed to encode")), fail); 182 require_quiet(set->aks_bag, fail); // Silence the warning. 183 184 der_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, 185 der_encode_data(set->aks_bag, error, der, 186 SOSPeerInfoSetEncodeToArrayDER(set->peers, error, der, 187 der_encode_dictionary(set->wrapped_keys, error, der, der_end)))); 188 189 require_quiet(der_end == der, fail); 190 191 result = der_end; 192 fail: 193 return result; 194 } 195 196 197 198 SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagCreateFromData(CFAllocatorRef allocator, CFDataRef data, CFErrorRef *error) { 199 SOSBackupSliceKeyBagRef result = NULL; 200 SOSBackupSliceKeyBagRef decodedBag = NULL; 201 202 const uint8_t *der = CFDataGetBytePtr(data); 203 const uint8_t *der_end = der + CFDataGetLength(data); 204 205 der = der_decode_BackupSliceKeyBag(allocator, &decodedBag, error, der, der_end); 206 207 require_quiet(SecRequirementError(der == der_end, error, CFSTR("Didn't consume all data supplied")), fail); 208 209 CFTransferRetained(result, decodedBag); 210 211 fail: 212 CFReleaseNull(decodedBag); 213 return result; 214 } 215 216 // 217 // MARK: Construction 218 // 219 220 bool SOSBSKBIsGoodBackupPublic(CFDataRef publicKey, CFErrorRef *error) { 221 bool result = false; 222 223 ccec_pub_ctx_decl_cp(SOSGetBackupKeyCurveParameters(), pub_key); 224 225 int cc_result = ccec_compact_import_pub(SOSGetBackupKeyCurveParameters(), CFDataGetLength(publicKey), CFDataGetBytePtr(publicKey), pub_key); 226 227 require_action_quiet(cc_result == 0, exit, SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unable to decode public key: %@"), publicKey)); 228 229 result = true; 230 exit: 231 return result; 232 233 } 234 235 236 static CFDataRef SOSCopyECWrapped(CFDataRef publicKey, CFDataRef secret, CFErrorRef *error) { 237 CFDataRef result = NULL; 238 239 ccec_pub_ctx_decl_cp(SOSGetBackupKeyCurveParameters(), pub_key); 240 241 int cc_result = ccec_compact_import_pub(SOSGetBackupKeyCurveParameters(), CFDataGetLength(publicKey), CFDataGetBytePtr(publicKey), pub_key); 242 243 require_action_quiet(cc_result == 0, exit, SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unable to decode public key: %@"), publicKey)); 244 245 result = SOSCopyECWrappedData(pub_key, secret, error); 246 247 exit: 248 return result; 249 } 250 251 252 static CFDictionaryRef SOSBackupSliceKeyBagCopyWrappedKeys(SOSBackupSliceKeyBagRef vb, CFDataRef secret, CFDictionaryRef additionalKeys, CFErrorRef *error) { 253 CFDictionaryRef result = NULL; 254 CFMutableDictionaryRef wrappedKeys = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); 255 256 __block bool success = true; 257 CFSetForEach(vb->peers, ^(const void *value) { 258 SOSPeerInfoRef pi = (SOSPeerInfoRef) value; 259 if (isSOSPeerInfo(pi)) { 260 CFStringRef id = SOSPeerInfoGetPeerID(pi); 261 CFDataRef backupKey = SOSPeerInfoCopyBackupKey(pi); 262 263 if (backupKey) { 264 CFErrorRef wrapError = NULL; 265 CFDataRef wrappedKey = SOSCopyECWrapped(backupKey, secret, &wrapError); 266 if (wrappedKey) { 267 CFDictionaryAddValue(wrappedKeys, id, wrappedKey); 268 CFDataPerformWithHexString(backupKey, ^(CFStringRef backupKeyString) { 269 CFDataPerformWithHexString(wrappedKey, ^(CFStringRef wrappedKeyString) { 270 secnotice("bskb", "Add for id: %@, bk: %@, wrapped: %@", id, backupKeyString, wrappedKeyString); 271 }); 272 }); 273 } else { 274 CFDataPerformWithHexString(backupKey, ^(CFStringRef backupKeyString) { 275 secnotice("bskb", "Failed at id: %@, bk: %@ error: %@", id, backupKeyString, wrapError); 276 }); 277 CFErrorPropagate(wrapError, error); 278 success = false; 279 } 280 CFReleaseNull(wrappedKey); 281 CFReleaseNull(backupKey); 282 } else { 283 secnotice("bskb", "Skipping id %@, no backup key.", id); 284 } 285 286 } 287 }); 288 289 CFDictionaryForEach(additionalKeys, ^(const void *key, const void *value) { 290 CFStringRef prefix = asString(key, NULL); 291 CFDataRef backupKey = asData(value, NULL); 292 if (backupKey) { 293 CFDataRef wrappedKey = NULL; 294 CFErrorRef localError = NULL; 295 CFStringRef id = SOSKeyedPubKeyIdentifierCreateWithData(prefix, backupKey); 296 require_quiet(id, done); 297 298 wrappedKey = SOSCopyECWrapped(backupKey, secret, &localError); 299 require_quiet(wrappedKey, done); 300 301 CFDictionaryAddValue(wrappedKeys, id, wrappedKey); 302 303 done: 304 if (!localError) { 305 CFDataPerformWithHexString(backupKey, ^(CFStringRef backupKeyString) { 306 CFDataPerformWithHexString(wrappedKey, ^(CFStringRef wrappedKeyString) { 307 secnotice("bskb", "Add for bk: %@, wrapped: %@", backupKeyString, wrappedKeyString); 308 }); 309 }); 310 } else { 311 CFDataPerformWithHexString(backupKey, ^(CFStringRef backupKeyString) { 312 secnotice("bskb", "Failed at bk: %@ error: %@", backupKeyString, localError); 313 }); 314 CFErrorPropagate(localError, error); 315 success = false; 316 } 317 CFReleaseNull(wrappedKey); 318 CFReleaseNull(id); 319 } else { 320 secnotice("bskb", "Skipping %@, not data.", value); 321 } 322 }); 323 324 if (success) 325 CFTransferRetained(result, wrappedKeys); 326 327 CFReleaseNull(wrappedKeys); 328 return result; 329 } 330 331 static bool SOSBackupSliceKeyBagCreateBackupBag(SOSBackupSliceKeyBagRef vb, CFDictionaryRef/*CFDataRef*/ additionalKeys, CFErrorRef* error) { 332 CFReleaseNull(vb->aks_bag); 333 334 // Choose a random key. 335 PerformWithBufferAndClear(kAKSBagSecretLength, ^(size_t size, uint8_t *buffer) { 336 CFDataRef secret = NULL; 337 338 require_quiet(SecError(SecRandomCopyBytes(kSecRandomDefault, size, buffer), error, CFSTR("SecRandom falied!")), fail); 339 340 secret = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, buffer, size, kCFAllocatorNull); 341 342 CFAssignRetained(vb->wrapped_keys, SOSBackupSliceKeyBagCopyWrappedKeys(vb, secret, additionalKeys, error)); 343 CFAssignRetained(vb->aks_bag, SecAKSCopyBackupBagWithSecret(size, buffer, error)); 344 345 fail: 346 CFReleaseSafe(secret); 347 }); 348 349 return vb->aks_bag != NULL; 350 } 351 352 353 CFDataRef SOSBSKBCopyEncoded(SOSBackupSliceKeyBagRef BackupSliceKeyBag, CFErrorRef* error) { 354 CFDataRef result = NULL; 355 CFMutableDataRef encoded = NULL; 356 357 size_t encodedSize = der_sizeof_BackupSliceKeyBag(BackupSliceKeyBag, error); 358 require_quiet(encodedSize, fail); 359 360 encoded = CFDataCreateMutableWithScratch(kCFAllocatorDefault, encodedSize); 361 require_quiet(SecAllocationError(encoded, error, CFSTR("Faild to create scratch")), fail); 362 363 uint8_t *encode_to = CFDataGetMutableBytePtr(encoded); 364 uint8_t *encode_to_end = encode_to + CFDataGetLength(encoded); 365 require_quiet(encode_to == der_encode_BackupSliceKeyBag(BackupSliceKeyBag, error, encode_to, encode_to_end), fail); 366 367 CFTransferRetained(result, encoded); 368 369 fail: 370 CFReleaseSafe(encoded); 371 return result; 372 } 373 374 static CFSetRef SOSBackupSliceKeyBagCreatePeerSet(CFAllocatorRef allocator, CFSetRef peers) { 375 CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(allocator); 376 377 CFSetForEach(peers, ^(const void *value) { 378 CFSetAddValue(result, value); 379 }); 380 381 return result; 382 } 383 384 SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagCreate(CFAllocatorRef allocator, CFSetRef peers, CFErrorRef* error) { 385 CFMutableDictionaryRef additionalKeys = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); 386 387 SOSBackupSliceKeyBagRef result = SOSBackupSliceKeyBagCreateWithAdditionalKeys(allocator, peers, additionalKeys, NULL); 388 389 CFReleaseNull(additionalKeys); 390 391 return result; 392 } 393 394 SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagCreateWithAdditionalKeys(CFAllocatorRef allocator, 395 CFSetRef /*SOSPeerInfoRef*/ peers, 396 CFDictionaryRef /*CFStringRef (prefix) CFDataRef (keydata) */ additionalKeys, 397 CFErrorRef* error) { 398 SOSBackupSliceKeyBagRef result = NULL; 399 SOSBackupSliceKeyBagRef vb = CFTypeAllocate(SOSBackupSliceKeyBag, struct __OpaqueSOSBackupSliceKeyBag, allocator); 400 require_quiet(SecAllocationError(vb, error, CFSTR("View bag allocation failed")), fail); 401 402 require_quiet(SecRequirementError(CFSetGetCount(peers) > 0, error, CFSTR("Need peers")), fail); 403 404 vb->peers = SOSBackupSliceKeyBagCreatePeerSet(allocator, peers); 405 vb->wrapped_keys = CFDictionaryCreateMutableForCFTypes(allocator); 406 407 require_quiet(SOSBackupSliceKeyBagCreateBackupBag(vb, additionalKeys, error), fail); 408 409 CFTransferRetained(result, vb); 410 411 fail: 412 CFReleaseNull(vb); 413 return result; 414 } 415 416 417 SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagCreateDirect(CFAllocatorRef allocator, CFDataRef aks_bag, CFErrorRef *error) 418 { 419 SOSBackupSliceKeyBagRef result = NULL; 420 SOSBackupSliceKeyBagRef vb = CFTypeAllocate(SOSBackupSliceKeyBag, struct __OpaqueSOSBackupSliceKeyBag, allocator); 421 require_quiet(SecAllocationError(vb, error, CFSTR("View bag allocation failed")), fail); 422 423 require_quiet(SecRequirementError(aks_bag, error, CFSTR("Need aks bag")), fail); 424 425 vb->aks_bag = CFRetainSafe(aks_bag); 426 vb->peers = CFSetCreateMutableForSOSPeerInfosByID(allocator); 427 vb->wrapped_keys = CFDictionaryCreateMutableForCFTypes(allocator); 428 429 CFTransferRetained(result, vb); 430 431 fail: 432 CFReleaseNull(vb); 433 return result; 434 } 435 436 // 437 // MARK: Use 438 // 439 440 bool SOSBSKBIsDirect(SOSBackupSliceKeyBagRef backupSliceKeyBag) 441 { 442 return 0 == CFSetGetCount(backupSliceKeyBag->peers); 443 } 444 445 CFDataRef SOSBSKBCopyAKSBag(SOSBackupSliceKeyBagRef backupSliceKeyBag, CFErrorRef* error) 446 { 447 return CFRetainSafe(backupSliceKeyBag->aks_bag); 448 } 449 450 CFSetRef SOSBSKBGetPeers(SOSBackupSliceKeyBagRef backupSliceKeyBag){ 451 return backupSliceKeyBag->peers; 452 } 453 454 int SOSBSKBCountPeers(SOSBackupSliceKeyBagRef backupSliceKeyBag) { 455 return (backupSliceKeyBag->peers) ? (int) CFSetGetCount(backupSliceKeyBag->peers): 0; 456 } 457 458 bool SOSBSKBPeerIsInKeyBag(SOSBackupSliceKeyBagRef backupSliceKeyBag, SOSPeerInfoRef pi) { 459 return CFSetGetValue(backupSliceKeyBag->peers, pi) != NULL; 460 } 461 462 463 464 bool SOSBKSBKeyIsInKeyBag(SOSBackupSliceKeyBagRef backupSliceKeyBag, CFDataRef publicKey) { 465 bool result = false; 466 CFStringRef keyID = SOSCopyIDOfDataBuffer(publicKey, NULL); 467 require_quiet(keyID, done); 468 469 result = CFDictionaryContainsKey(backupSliceKeyBag->wrapped_keys, keyID); 470 471 done: 472 CFReleaseSafe(keyID); 473 return result; 474 } 475 476 bool SOSBKSBPeerBackupKeyIsInKeyBag(SOSBackupSliceKeyBagRef backupSliceKeyBag, SOSPeerInfoRef pi) { 477 bool result = false; 478 CFDataRef bskbBackupKey = NULL; 479 480 CFDataRef backupKey = SOSPeerInfoCopyBackupKey(pi); 481 SOSPeerInfoRef backupPI = asSOSPeerInfo(CFSetGetValue(backupSliceKeyBag->peers, pi)); 482 if(backupPI) { 483 bskbBackupKey = SOSPeerInfoCopyBackupKey(backupPI); 484 } 485 result = CFEqualSafe(backupKey, bskbBackupKey); 486 CFReleaseNull(bskbBackupKey); 487 CFReleaseNull(backupKey); 488 return result; 489 } 490 491 bool SOSBSKBAllPeersBackupKeysAreInKeyBag(SOSBackupSliceKeyBagRef backupSliceKeyBag, CFSetRef peers) { 492 // earlier we had to accept BSKBs listing peers without backup keys for compatibility. For that reason 493 // this routine will iterate over the peers given and only disqualify the BSKB if it doesn't include the backup key of a peer with one. 494 __block bool result = true; 495 if(backupSliceKeyBag && peers) { 496 CFSetForEach(peers, ^(const void *value) { 497 SOSPeerInfoRef pi = asSOSPeerInfo(value); 498 if(pi && SOSPeerInfoHasBackupKey(pi)) { 499 result &= SOSBKSBPeerBackupKeyIsInKeyBag(backupSliceKeyBag, pi); 500 } 501 }); 502 } 503 return result; 504 } 505 506 bool SOSBKSBPrefixedKeyIsInKeyBag(SOSBackupSliceKeyBagRef backupSliceKeyBag, CFStringRef prefix, CFDataRef publicKey) { 507 bool result = false; 508 CFStringRef kpkid = SOSKeyedPubKeyIdentifierCreateWithData(prefix, publicKey); 509 require_quiet(kpkid, done); 510 511 result = CFDictionaryContainsKey(backupSliceKeyBag->wrapped_keys, kpkid); 512 513 done: 514 CFReleaseSafe(kpkid); 515 return result; 516 517 } 518 519 520 521 bskb_keybag_handle_t SOSBSKBLoadLocked(SOSBackupSliceKeyBagRef backupSliceKeyBag, 522 CFErrorRef *error) 523 { 524 #if !TARGET_HAS_KEYSTORE 525 return bad_keybag_handle; 526 #else 527 keybag_handle_t result = bad_keybag_handle; 528 keybag_handle_t bag_handle = bad_keybag_handle; 529 530 require_quiet(SecRequirementError(backupSliceKeyBag->aks_bag, error, 531 CFSTR("No aks bag to load")), exit); 532 require_quiet(SecRequirementError(CFDataGetLength(backupSliceKeyBag->aks_bag) < INT_MAX, error, 533 CFSTR("No aks bag to load")), exit); 534 535 kern_return_t aks_result; 536 aks_result = aks_load_bag(CFDataGetBytePtr(backupSliceKeyBag->aks_bag), 537 (int) CFDataGetLength(backupSliceKeyBag->aks_bag), 538 &bag_handle); 539 require_quiet(SecKernError(aks_result, error, 540 CFSTR("aks_load_bag failed: %d"), aks_result), exit); 541 542 result = bag_handle; 543 bag_handle = bad_keybag_handle; 544 545 exit: 546 if (bag_handle != bad_keybag_handle) { 547 (void) aks_unload_bag(bag_handle); 548 } 549 550 return result; 551 #endif 552 553 } 554 555 static keybag_handle_t SOSBSKBLoadAndUnlockBagWithSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag, 556 size_t secretSize, const uint8_t *secret, 557 CFErrorRef *error) 558 { 559 #if !TARGET_HAS_KEYSTORE 560 return bad_keybag_handle; 561 #else 562 keybag_handle_t result = bad_keybag_handle; 563 keybag_handle_t bag_handle = bad_keybag_handle; 564 565 require_quiet(SecRequirementError(backupSliceKeyBag->aks_bag, error, 566 CFSTR("No aks bag to load")), exit); 567 require_quiet(SecRequirementError(CFDataGetLength(backupSliceKeyBag->aks_bag) < INT_MAX, error, 568 CFSTR("No aks bag to load")), exit); 569 require_quiet(SecRequirementError(secretSize <= INT_MAX, error, 570 CFSTR("secret too big")), exit); 571 572 kern_return_t aks_result; 573 aks_result = aks_load_bag(CFDataGetBytePtr(backupSliceKeyBag->aks_bag), 574 (int) CFDataGetLength(backupSliceKeyBag->aks_bag), 575 &bag_handle); 576 require_quiet(SecKernError(aks_result, error, 577 CFSTR("aks_load_bag failed: %d"), aks_result), exit); 578 579 aks_result = aks_unlock_bag(bag_handle, secret, (int) secretSize); 580 require_quiet(SecKernError(aks_result, error, 581 CFSTR("failed to unlock bag: %d"), aks_result), exit); 582 583 result = bag_handle; 584 bag_handle = bad_keybag_handle; 585 586 exit: 587 if (bag_handle != bad_keybag_handle) { 588 (void) aks_unload_bag(bag_handle); 589 } 590 591 return result; 592 #endif 593 } 594 595 keybag_handle_t SOSBSKBLoadAndUnlockWithPeerIDAndSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag, 596 CFStringRef peerID, CFDataRef peerSecret, 597 CFErrorRef *error) 598 { 599 __block keybag_handle_t result = bad_keybag_handle; 600 601 CFDataRef lookedUpData = CFDictionaryGetValue(backupSliceKeyBag->wrapped_keys, peerID); 602 require_quiet(SecRequirementError(lookedUpData != NULL, error, CFSTR("%@ has no wrapped key in %@"), peerID, backupSliceKeyBag), exit); 603 604 require_quiet(SOSPerformWithDeviceBackupFullKey(SOSGetBackupKeyCurveParameters(), peerSecret, error, ^(ccec_full_ctx_t fullKey) { 605 SOSPerformWithUnwrappedData(fullKey, lookedUpData, error, ^(size_t size, uint8_t *buffer) { 606 result = SOSBSKBLoadAndUnlockBagWithSecret(backupSliceKeyBag, size, buffer, error); 607 }); 608 }), exit); 609 610 exit: 611 return result; 612 } 613 614 615 keybag_handle_t SOSBSKBLoadAndUnlockWithPeerSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag, 616 SOSPeerInfoRef peer, CFDataRef peerSecret, 617 CFErrorRef *error) 618 { 619 return SOSBSKBLoadAndUnlockWithPeerIDAndSecret(backupSliceKeyBag, SOSPeerInfoGetPeerID(peer), peerSecret, error); 620 } 621 622 keybag_handle_t SOSBSKBLoadAndUnlockWithDirectSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag, 623 CFDataRef secret, 624 CFErrorRef *error) 625 { 626 keybag_handle_t result = bad_keybag_handle; 627 require_quiet(SecRequirementError(SOSBSKBIsDirect(backupSliceKeyBag), error, CFSTR("Not direct bag")), exit); 628 629 result = SOSBSKBLoadAndUnlockBagWithSecret(backupSliceKeyBag, 630 CFDataGetLength(secret), 631 CFDataGetBytePtr(secret), 632 error); 633 634 exit: 635 return result; 636 } 637 638 #include <Security/SecRecoveryKey.h> 639 640 static bool SOSPerformWithRecoveryKeyFullKey(CFDataRef wrappingSecret, CFErrorRef *error, void (^operation)(ccec_full_ctx_t fullKey, CFStringRef keyID)) { 641 bool result = false; 642 643 CFStringRef keyID = NULL; 644 NSError *nserror = NULL; 645 SecRecoveryKey *sRecKey = NULL; 646 NSData* fullKeyBytes = NULL; 647 NSData* pubKeyBytes = NULL; 648 CFStringRef restoreKeySecret = CFStringCreateWithBytes(SecCFAllocatorZeroize(), CFDataGetBytePtr(wrappingSecret), CFDataGetLength(wrappingSecret), kCFStringEncodingUTF8, false); 649 require_action_quiet(restoreKeySecret, errOut, SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unable to create key string from data."))); 650 651 sRecKey = SecRKCreateRecoveryKeyWithError((__bridge NSString *)(restoreKeySecret), &nserror); 652 if(!sRecKey) { 653 if (error) 654 *error = (CFErrorRef)CFBridgingRetain(nserror); 655 goto errOut; 656 } 657 658 require_action_quiet(sRecKey, errOut, SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unable to create recovery key from string."))); 659 660 fullKeyBytes = SecRKCopyBackupFullKey(sRecKey); 661 pubKeyBytes = SecRKCopyBackupPublicKey(sRecKey); 662 require_action_quiet(fullKeyBytes && pubKeyBytes, errOut, SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unable to get recovery key public and private keys."))); 663 keyID = SOSCopyIDOfDataBuffer(((__bridge CFDataRef) pubKeyBytes), error); 664 require_quiet(keyID, errOut); 665 { 666 size_t keysize = ccec_compact_import_priv_size(CFDataGetLength((__bridge CFDataRef)fullKeyBytes)); 667 ccec_const_cp_t cp = ccec_curve_for_length_lookup(keysize, ccec_cp_256(), ccec_cp_384(), ccec_cp_521()); 668 ccec_full_ctx_decl_cp(cp, fullKey); 669 int res = ccec_compact_import_priv(cp, CFDataGetLength((__bridge CFDataRef)fullKeyBytes), CFDataGetBytePtr((__bridge CFDataRef)fullKeyBytes), fullKey); 670 if(res == 0) { 671 operation(fullKey, keyID); 672 result = true; 673 ccec_full_ctx_clear_cp(cp, fullKey); 674 } 675 } 676 if(!result) SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("Unable to perform crypto operation from fullKeyBytes.")); 677 678 errOut: 679 CFReleaseNull(keyID); 680 CFReleaseNull(restoreKeySecret); 681 return result; 682 } 683 684 bskb_keybag_handle_t SOSBSKBLoadAndUnlockWithWrappingSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag, 685 CFDataRef wrappingSecret, 686 CFErrorRef *error) { 687 __block keybag_handle_t result = bad_keybag_handle; 688 689 CFDataRef lookedUpData = SOSBSKBCopyRecoveryKey(backupSliceKeyBag); 690 require_quiet(SecRequirementError(lookedUpData != NULL, error, CFSTR("no recovery key found in %@"), backupSliceKeyBag), errOut); 691 692 SOSPerformWithRecoveryKeyFullKey(wrappingSecret, error, ^(ccec_full_ctx_t fullKey, CFStringRef keyID) { 693 SOSPerformWithUnwrappedData(fullKey, lookedUpData, error, ^(size_t size, uint8_t *buffer) { 694 result = SOSBSKBLoadAndUnlockBagWithSecret(backupSliceKeyBag, size, buffer, error); 695 }); 696 }); 697 698 errOut: 699 CFReleaseSafe(lookedUpData); 700 return result; 701 } 702 703 // fixed for <rdar://problem/30918831> CrashTracer: secdtests at secdtests: SOSBSKBCopyAdditionalKeysWithPrefix 704 static CFDictionaryRef SOSBSKBCopyAdditionalKeysWithPrefix(CFAllocatorRef allocator, SOSBackupSliceKeyBagRef bskb, CFStringRef prefix) { 705 if(!bskb || !bskb->wrapped_keys) return NULL; 706 CFMutableDictionaryRef retval = CFDictionaryCreateMutableForCFTypes(allocator); 707 if(!retval) return NULL; 708 CFDictionaryForEach(bskb->wrapped_keys, ^(const void *key, const void *value) { 709 CFStringRef kpkid = asString(key, NULL); 710 CFDataRef keyData = asData(value, NULL); 711 if(kpkid && keyData && SOSKeyedPubKeyIdentifierIsPrefixed(kpkid)) { 712 CFStringRef idPrefix = SOSKeyedPubKeyIdentifierCopyPrefix(kpkid); 713 if(CFEqualSafe(idPrefix, prefix)) { 714 CFDictionaryAddValue(retval, kpkid, keyData); 715 } 716 CFReleaseNull(idPrefix); 717 } 718 }); 719 return retval; 720 } 721 722 static bool SOSBSKBHasPrefixedKey(SOSBackupSliceKeyBagRef bskb, CFStringRef prefix) { 723 CFDictionaryRef keyDict = SOSBSKBCopyAdditionalKeysWithPrefix(kCFAllocatorDefault, bskb, prefix); 724 bool haveKeys = keyDict && CFDictionaryGetCount(keyDict) > 0; 725 CFReleaseNull(keyDict); 726 return haveKeys; 727 } 728 729 CFDataRef SOSBSKBCopyRecoveryKey(SOSBackupSliceKeyBagRef bskb) { 730 if(!bskb) return NULL; 731 CFDictionaryRef keyDict = SOSBSKBCopyAdditionalKeysWithPrefix(kCFAllocatorDefault, bskb, bskbRkbgPrefix); 732 if(!keyDict) return NULL; 733 CFDataRef result = NULL; 734 if(CFDictionaryGetCount(keyDict) == 1) { 735 __block CFDataRef keyData = NULL; 736 CFDictionaryForEach(keyDict, ^(const void *key, const void *value) { 737 keyData = asData(value, NULL); 738 }); 739 result = CFDataCreateCopy(kCFAllocatorDefault, keyData); 740 } 741 CFReleaseNull(keyDict); 742 return result; 743 } 744 745 bool SOSBSKBHasRecoveryKey(SOSBackupSliceKeyBagRef bskb) { 746 if(!bskb) return false; 747 if(SOSBSKBHasPrefixedKey(bskb, bskbRkbgPrefix)) { 748 return true; 749 } 750 // old way for RecoveryKeys 751 int keyCount = (bskb->wrapped_keys != NULL) ? (int) CFDictionaryGetCount(bskb->wrapped_keys): 0; 752 int peerCount = SOSBSKBCountPeers(bskb); 753 return !SOSBSKBIsDirect(bskb) && ((keyCount - peerCount) > 0); 754 } 755 756 bool SOSBSKBHasThisRecoveryKey(SOSBackupSliceKeyBagRef bskb, CFDataRef backupKey) { 757 if(backupKey) { 758 CFStringRef id = SOSKeyedPubKeyIdentifierCreateWithData(bskbRkbgPrefix, backupKey); 759 bool result = (bskb && id && CFDictionaryContainsKey(bskb->wrapped_keys, id)); 760 CFReleaseNull(id); 761 return result; 762 } else { 763 // let's not judge ripping out other recovery keys 764 return true; 765 } 766 }