2 * Copyright (c) 2015 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@
27 #include <Security/SecureObjectSync/SOSBackupSliceKeyBag.h>
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 <Security/SecureObjectSync/SOSPeerInfoCollections.h>
41 #include <Security/SecureObjectSync/SOSInternal.h>
43 #include <corecrypto/ccec.h>
44 #include <corecrypto/ccsha2.h>
45 #include <corecrypto/ccrng.h>
49 #include "SecRecoveryKey.h"
50 #include "SOSKeyedPubKeyIdentifier.h"
51 #include "SOSInternal.h"
52 #include "SecADWrapper.h"
54 CFStringRef bskbRkbgPrefix
= CFSTR("RK");
57 // MARK: Type creation
60 CFGiblisFor(SOSBackupSliceKeyBag
);
62 const int kAKSBagSecretLength
= 32;
64 struct __OpaqueSOSBackupSliceKeyBag
{
70 CFDictionaryRef wrapped_keys
;
73 static void SOSBackupSliceKeyBagDestroy(CFTypeRef aObj
) {
74 SOSBackupSliceKeyBagRef vb
= (SOSBackupSliceKeyBagRef
) aObj
;
76 CFReleaseNull(vb
->aks_bag
);
77 CFReleaseNull(vb
->peers
);
78 CFReleaseNull(vb
->wrapped_keys
);
81 static CFSetRef
SOSBackupSliceKeyBagCopyPeerNames(SOSBackupSliceKeyBagRef bksb
) {
82 CFMutableSetRef retval
= CFSetCreateMutableForCFTypes(kCFAllocatorDefault
);
83 if(!retval
) return NULL
;
84 CFSetForEach(bksb
->peers
, ^(const void *value
) {
85 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
86 CFSetAddValue(retval
, SOSPeerInfoGetPeerName(pi
));
91 static CFStringRef
SOSBackupSliceKeyBagCopyFormatDescription(CFTypeRef aObj
, CFDictionaryRef formatOptions
) {
92 SOSBackupSliceKeyBagRef vb
= (SOSBackupSliceKeyBagRef
) aObj
;
94 CFMutableStringRef retval
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
96 CFSetRef peerIDs
= SOSBackupSliceKeyBagCopyPeerNames(vb
);
97 CFStringSetPerformWithDescription(peerIDs
, ^(CFStringRef description
) {
98 CFStringAppendFormat(retval
, NULL
, CFSTR("<SOSBackupSliceKeyBag@%p %ld %@"), vb
, vb
->peers
? CFSetGetCount(vb
->peers
) : 0, description
);
100 CFReleaseNull(peerIDs
);
101 CFStringAppend(retval
, CFSTR(">"));
108 // MARK: Encode/Decode
111 const uint8_t* der_decode_BackupSliceKeyBag(CFAllocatorRef allocator
,
112 SOSBackupSliceKeyBagRef
* BackupSliceKeyBag
, CFErrorRef
*error
,
113 const uint8_t* der
, const uint8_t *der_end
) {
114 if (der
== NULL
) return der
;
116 const uint8_t *result
= NULL
;
117 SOSBackupSliceKeyBagRef vb
= CFTypeAllocate(SOSBackupSliceKeyBag
, struct __OpaqueSOSBackupSliceKeyBag
, allocator
);
118 require_quiet(SecAllocationError(vb
, error
, CFSTR("View bag allocation failed")), fail
);
120 const uint8_t *sequence_end
= NULL
;
121 der
= ccder_decode_sequence_tl(&sequence_end
, der
, der_end
);
122 require_quiet(sequence_end
== der_end
, fail
);
124 der
= der_decode_data(kCFAllocatorDefault
, kCFPropertyListImmutable
, &vb
->aks_bag
, error
, der
, sequence_end
);
125 vb
->peers
= SOSPeerInfoSetCreateFromArrayDER(kCFAllocatorDefault
, &kSOSPeerSetCallbacks
, error
,
127 der
= der_decode_dictionary(kCFAllocatorDefault
, kCFPropertyListImmutable
, &vb
->wrapped_keys
, error
, der
, sequence_end
);
129 require_quiet(SecRequirementError(der
== der_end
, error
, CFSTR("Extra space in sequence")), fail
);
131 if (BackupSliceKeyBag
)
132 CFTransferRetained(*BackupSliceKeyBag
, vb
);
141 size_t der_sizeof_BackupSliceKeyBag(SOSBackupSliceKeyBagRef BackupSliceKeyBag
, CFErrorRef
*error
) {
144 require_quiet(SecRequirementError(BackupSliceKeyBag
!= NULL
, error
, CFSTR("Null BackupSliceKeyBag")), fail
);
145 require_quiet(BackupSliceKeyBag
!= NULL
, fail
); // this is redundant with what happens in SecRequirementError, but the analyzer can't understand that.
146 require_quiet(SecRequirementError(BackupSliceKeyBag
->aks_bag
!= NULL
, error
, CFSTR("null aks_bag in BackupSliceKeyBag")), fail
);
147 require_quiet(BackupSliceKeyBag
->aks_bag
!= NULL
, fail
); // this is redundant with what happens in SecRequirementError, but the analyzer can't understand that.
149 size_t bag_size
= der_sizeof_data(BackupSliceKeyBag
->aks_bag
, error
);
150 require_quiet(bag_size
, fail
);
152 size_t peers_size
= SOSPeerInfoSetGetDEREncodedArraySize(BackupSliceKeyBag
->peers
, error
);
153 require_quiet(peers_size
, fail
);
155 size_t wrapped_keys_size
= der_sizeof_dictionary(BackupSliceKeyBag
->wrapped_keys
, error
);
156 require_quiet(wrapped_keys_size
, fail
);
158 result
= ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, bag_size
+ peers_size
+ wrapped_keys_size
);
164 uint8_t* der_encode_BackupSliceKeyBag(SOSBackupSliceKeyBagRef set
, CFErrorRef
*error
,
165 const uint8_t *der
, uint8_t *der_end
) {
166 uint8_t *result
= NULL
;
167 if (der_end
== NULL
) return der_end
;
169 require_quiet(SecRequirementError(set
!= NULL
, error
, CFSTR("Null set passed to encode")), fail
);
170 require_quiet(set
, fail
); // Silence the NULL warning.
172 require_quiet(SecRequirementError(set
->aks_bag
!= NULL
, error
, CFSTR("Null set passed to encode")), fail
);
173 require_quiet(set
->aks_bag
, fail
); // Silence the warning.
175 der_end
= ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
176 der_encode_data(set
->aks_bag
, error
, der
,
177 SOSPeerInfoSetEncodeToArrayDER(set
->peers
, error
, der
,
178 der_encode_dictionary(set
->wrapped_keys
, error
, der
, der_end
))));
180 require_quiet(der_end
== der
, fail
);
189 SOSBackupSliceKeyBagRef
SOSBackupSliceKeyBagCreateFromData(CFAllocatorRef allocator
, CFDataRef data
, CFErrorRef
*error
) {
190 SOSBackupSliceKeyBagRef result
= NULL
;
191 SOSBackupSliceKeyBagRef decodedBag
= NULL
;
193 const uint8_t *der
= CFDataGetBytePtr(data
);
194 const uint8_t *der_end
= der
+ CFDataGetLength(data
);
196 der
= der_decode_BackupSliceKeyBag(allocator
, &decodedBag
, error
, der
, der_end
);
198 require_quiet(SecRequirementError(der
== der_end
, error
, CFSTR("Didn't consume all data supplied")), fail
);
200 CFTransferRetained(result
, decodedBag
);
203 CFReleaseNull(decodedBag
);
208 // MARK: Construction
211 bool SOSBSKBIsGoodBackupPublic(CFDataRef publicKey
, CFErrorRef
*error
) {
214 ccec_pub_ctx_decl_cp(SOSGetBackupKeyCurveParameters(), pub_key
);
216 int cc_result
= ccec_compact_import_pub(SOSGetBackupKeyCurveParameters(), CFDataGetLength(publicKey
), CFDataGetBytePtr(publicKey
), pub_key
);
218 require_action_quiet(cc_result
== 0, exit
, SOSErrorCreate(kSOSErrorDecodeFailure
, error
, NULL
, CFSTR("Unable to decode public key: %@"), publicKey
));
227 static CFDataRef
SOSCopyECWrapped(CFDataRef publicKey
, CFDataRef secret
, CFErrorRef
*error
) {
228 CFDataRef result
= NULL
;
230 ccec_pub_ctx_decl_cp(SOSGetBackupKeyCurveParameters(), pub_key
);
232 int cc_result
= ccec_compact_import_pub(SOSGetBackupKeyCurveParameters(), CFDataGetLength(publicKey
), CFDataGetBytePtr(publicKey
), pub_key
);
234 require_action_quiet(cc_result
== 0, exit
, SOSErrorCreate(kSOSErrorDecodeFailure
, error
, NULL
, CFSTR("Unable to decode public key: %@"), publicKey
));
236 result
= SOSCopyECWrappedData(pub_key
, secret
, error
);
243 static CFDictionaryRef
SOSBackupSliceKeyBagCopyWrappedKeys(SOSBackupSliceKeyBagRef vb
, CFDataRef secret
, CFDictionaryRef additionalKeys
, CFErrorRef
*error
) {
244 CFDictionaryRef result
= NULL
;
245 CFMutableDictionaryRef wrappedKeys
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
247 __block
bool success
= true;
248 CFSetForEach(vb
->peers
, ^(const void *value
) {
249 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
250 if (isSOSPeerInfo(pi
)) {
251 CFStringRef id
= SOSPeerInfoGetPeerID(pi
);
252 CFDataRef backupKey
= SOSPeerInfoCopyBackupKey(pi
);
255 CFErrorRef wrapError
= NULL
;
256 CFDataRef wrappedKey
= SOSCopyECWrapped(backupKey
, secret
, &wrapError
);
258 CFDictionaryAddValue(wrappedKeys
, id
, wrappedKey
);
259 CFDataPerformWithHexString(backupKey
, ^(CFStringRef backupKeyString
) {
260 CFDataPerformWithHexString(wrappedKey
, ^(CFStringRef wrappedKeyString
) {
261 secnotice("bskb", "Add for id: %@, bk: %@, wrapped: %@", id
, backupKeyString
, wrappedKeyString
);
265 CFDataPerformWithHexString(backupKey
, ^(CFStringRef backupKeyString
) {
266 secnotice("bskb", "Failed at id: %@, bk: %@ error: %@", id
, backupKeyString
, wrapError
);
268 CFErrorPropagate(wrapError
, error
);
271 CFReleaseNull(wrappedKey
);
272 CFReleaseNull(backupKey
);
274 secnotice("bskb", "Skipping id %@, no backup key.", id
);
280 CFDictionaryForEach(additionalKeys
, ^(const void *key
, const void *value
) {
281 CFStringRef prefix
= asString(key
, NULL
);
282 CFDataRef backupKey
= asData(value
, NULL
);
284 CFDataRef wrappedKey
= NULL
;
285 CFErrorRef localError
= NULL
;
286 CFStringRef id
= SOSKeyedPubKeyIdentifierCreateWithData(prefix
, backupKey
);
287 require_quiet(id
, done
);
289 wrappedKey
= SOSCopyECWrapped(backupKey
, secret
, &localError
);
290 require_quiet(wrappedKey
, done
);
292 CFDictionaryAddValue(wrappedKeys
, id
, wrappedKey
);
296 CFDataPerformWithHexString(backupKey
, ^(CFStringRef backupKeyString
) {
297 CFDataPerformWithHexString(wrappedKey
, ^(CFStringRef wrappedKeyString
) {
298 secnotice("bskb", "Add for bk: %@, wrapped: %@", backupKeyString
, wrappedKeyString
);
302 CFDataPerformWithHexString(backupKey
, ^(CFStringRef backupKeyString
) {
303 secnotice("bskb", "Failed at bk: %@ error: %@", backupKeyString
, localError
);
305 CFErrorPropagate(localError
, error
);
308 CFReleaseNull(wrappedKey
);
311 secnotice("bskb", "Skipping %@, not data.", value
);
316 CFTransferRetained(result
, wrappedKeys
);
318 CFReleaseNull(wrappedKeys
);
322 static bool SOSBackupSliceKeyBagCreateBackupBag(SOSBackupSliceKeyBagRef vb
, CFDictionaryRef
/*CFDataRef*/ additionalKeys
, CFErrorRef
* error
) {
323 CFReleaseNull(vb
->aks_bag
);
325 // Choose a random key.
326 PerformWithBufferAndClear(kAKSBagSecretLength
, ^(size_t size
, uint8_t *buffer
) {
327 CFDataRef secret
= NULL
;
329 require_quiet(SecError(SecRandomCopyBytes(kSecRandomDefault
, size
, buffer
), error
, CFSTR("SecRandom falied!")), fail
);
331 secret
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, buffer
, size
, kCFAllocatorNull
);
333 CFAssignRetained(vb
->wrapped_keys
, SOSBackupSliceKeyBagCopyWrappedKeys(vb
, secret
, additionalKeys
, error
));
334 CFAssignRetained(vb
->aks_bag
, SecAKSCopyBackupBagWithSecret(size
, buffer
, error
));
337 CFReleaseSafe(secret
);
340 return vb
->aks_bag
!= NULL
;
344 CFDataRef
SOSBSKBCopyEncoded(SOSBackupSliceKeyBagRef BackupSliceKeyBag
, CFErrorRef
* error
) {
345 CFDataRef result
= NULL
;
346 CFMutableDataRef encoded
= NULL
;
348 size_t encodedSize
= der_sizeof_BackupSliceKeyBag(BackupSliceKeyBag
, error
);
349 require_quiet(encodedSize
, fail
);
351 encoded
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, encodedSize
);
352 require_quiet(SecAllocationError(encoded
, error
, CFSTR("Faild to create scratch")), fail
);
354 uint8_t *encode_to
= CFDataGetMutableBytePtr(encoded
);
355 uint8_t *encode_to_end
= encode_to
+ CFDataGetLength(encoded
);
356 require_quiet(encode_to
== der_encode_BackupSliceKeyBag(BackupSliceKeyBag
, error
, encode_to
, encode_to_end
), fail
);
358 CFTransferRetained(result
, encoded
);
361 CFReleaseSafe(encoded
);
365 static CFSetRef
SOSBackupSliceKeyBagCreatePeerSet(CFAllocatorRef allocator
, CFSetRef peers
) {
366 CFMutableSetRef result
= CFSetCreateMutableForSOSPeerInfosByID(allocator
);
368 CFSetForEach(peers
, ^(const void *value
) {
369 CFSetAddValue(result
, value
);
375 SOSBackupSliceKeyBagRef
SOSBackupSliceKeyBagCreate(CFAllocatorRef allocator
, CFSetRef peers
, CFErrorRef
* error
) {
376 CFMutableDictionaryRef additionalKeys
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
378 SOSBackupSliceKeyBagRef result
= SOSBackupSliceKeyBagCreateWithAdditionalKeys(allocator
, peers
, additionalKeys
, NULL
);
380 CFReleaseNull(additionalKeys
);
385 SOSBackupSliceKeyBagRef
SOSBackupSliceKeyBagCreateWithAdditionalKeys(CFAllocatorRef allocator
,
386 CFSetRef
/*SOSPeerInfoRef*/ peers
,
387 CFDictionaryRef
/*CFStringRef (prefix) CFDataRef (keydata) */ additionalKeys
,
389 SOSBackupSliceKeyBagRef result
= NULL
;
390 SOSBackupSliceKeyBagRef vb
= CFTypeAllocate(SOSBackupSliceKeyBag
, struct __OpaqueSOSBackupSliceKeyBag
, allocator
);
391 require_quiet(SecAllocationError(vb
, error
, CFSTR("View bag allocation failed")), fail
);
393 require_quiet(SecRequirementError(CFSetGetCount(peers
) > 0, error
, CFSTR("Need peers")), fail
);
395 vb
->peers
= SOSBackupSliceKeyBagCreatePeerSet(allocator
, peers
);
396 vb
->wrapped_keys
= CFDictionaryCreateMutableForCFTypes(allocator
);
398 require_quiet(SOSBackupSliceKeyBagCreateBackupBag(vb
, additionalKeys
, error
), fail
);
400 CFTransferRetained(result
, vb
);
408 SOSBackupSliceKeyBagRef
SOSBackupSliceKeyBagCreateDirect(CFAllocatorRef allocator
, CFDataRef aks_bag
, CFErrorRef
*error
)
410 SOSBackupSliceKeyBagRef result
= NULL
;
411 SOSBackupSliceKeyBagRef vb
= CFTypeAllocate(SOSBackupSliceKeyBag
, struct __OpaqueSOSBackupSliceKeyBag
, allocator
);
412 require_quiet(SecAllocationError(vb
, error
, CFSTR("View bag allocation failed")), fail
);
414 require_quiet(SecRequirementError(aks_bag
, error
, CFSTR("Need aks bag")), fail
);
416 vb
->aks_bag
= CFRetainSafe(aks_bag
);
417 vb
->peers
= CFSetCreateMutableForSOSPeerInfosByID(allocator
);
418 vb
->wrapped_keys
= CFDictionaryCreateMutableForCFTypes(allocator
);
420 CFTransferRetained(result
, vb
);
431 bool SOSBSKBIsDirect(SOSBackupSliceKeyBagRef backupSliceKeyBag
)
433 return 0 == CFSetGetCount(backupSliceKeyBag
->peers
);
436 CFDataRef
SOSBSKBCopyAKSBag(SOSBackupSliceKeyBagRef backupSliceKeyBag
, CFErrorRef
* error
)
438 return CFRetainSafe(backupSliceKeyBag
->aks_bag
);
441 CFSetRef
SOSBSKBGetPeers(SOSBackupSliceKeyBagRef backupSliceKeyBag
){
442 return backupSliceKeyBag
->peers
;
445 int SOSBSKBCountPeers(SOSBackupSliceKeyBagRef backupSliceKeyBag
) {
446 return (int) CFSetGetCount(backupSliceKeyBag
->peers
);
449 bool SOSBSKBPeerIsInKeyBag(SOSBackupSliceKeyBagRef backupSliceKeyBag
, SOSPeerInfoRef pi
) {
450 return CFSetGetValue(backupSliceKeyBag
->peers
, pi
) != NULL
;
455 bool SOSBKSBKeyIsInKeyBag(SOSBackupSliceKeyBagRef backupSliceKeyBag
, CFDataRef publicKey
) {
457 CFStringRef keyID
= SOSCopyIDOfDataBuffer(publicKey
, NULL
);
458 require_quiet(keyID
, done
);
460 result
= CFDictionaryContainsKey(backupSliceKeyBag
->wrapped_keys
, keyID
);
463 CFReleaseSafe(keyID
);
467 bool SOSBKSBPrefixedKeyIsInKeyBag(SOSBackupSliceKeyBagRef backupSliceKeyBag
, CFStringRef prefix
, CFDataRef publicKey
) {
469 CFStringRef kpkid
= SOSKeyedPubKeyIdentifierCreateWithData(prefix
, publicKey
);
470 require_quiet(kpkid
, done
);
472 result
= CFDictionaryContainsKey(backupSliceKeyBag
->wrapped_keys
, kpkid
);
475 CFReleaseSafe(kpkid
);
482 bskb_keybag_handle_t
SOSBSKBLoadLocked(SOSBackupSliceKeyBagRef backupSliceKeyBag
,
485 #if !TARGET_HAS_KEYSTORE
486 return bad_keybag_handle
;
488 keybag_handle_t result
= bad_keybag_handle
;
489 keybag_handle_t bag_handle
= bad_keybag_handle
;
491 require_quiet(SecRequirementError(backupSliceKeyBag
->aks_bag
, error
,
492 CFSTR("No aks bag to load")), exit
);
493 require_quiet(SecRequirementError(CFDataGetLength(backupSliceKeyBag
->aks_bag
) < INT_MAX
, error
,
494 CFSTR("No aks bag to load")), exit
);
496 kern_return_t aks_result
;
497 aks_result
= aks_load_bag(CFDataGetBytePtr(backupSliceKeyBag
->aks_bag
),
498 (int) CFDataGetLength(backupSliceKeyBag
->aks_bag
),
500 require_quiet(SecKernError(aks_result
, error
,
501 CFSTR("aks_load_bag failed: %d"), aks_result
), exit
);
504 bag_handle
= bad_keybag_handle
;
507 if (bag_handle
!= bad_keybag_handle
) {
508 (void) aks_unload_bag(bag_handle
);
516 static keybag_handle_t
SOSBSKBLoadAndUnlockBagWithSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag
,
517 size_t secretSize
, const uint8_t *secret
,
520 #if !TARGET_HAS_KEYSTORE
521 return bad_keybag_handle
;
523 keybag_handle_t result
= bad_keybag_handle
;
524 keybag_handle_t bag_handle
= bad_keybag_handle
;
526 require_quiet(SecRequirementError(backupSliceKeyBag
->aks_bag
, error
,
527 CFSTR("No aks bag to load")), exit
);
528 require_quiet(SecRequirementError(CFDataGetLength(backupSliceKeyBag
->aks_bag
) < INT_MAX
, error
,
529 CFSTR("No aks bag to load")), exit
);
530 require_quiet(SecRequirementError(secretSize
<= INT_MAX
, error
,
531 CFSTR("secret too big")), exit
);
533 kern_return_t aks_result
;
534 aks_result
= aks_load_bag(CFDataGetBytePtr(backupSliceKeyBag
->aks_bag
),
535 (int) CFDataGetLength(backupSliceKeyBag
->aks_bag
),
537 require_quiet(SecKernError(aks_result
, error
,
538 CFSTR("aks_load_bag failed: %d"), aks_result
), exit
);
540 aks_result
= aks_unlock_bag(bag_handle
, secret
, (int) secretSize
);
541 require_quiet(SecKernError(aks_result
, error
,
542 CFSTR("failed to unlock bag: %d"), aks_result
), exit
);
545 bag_handle
= bad_keybag_handle
;
548 if (bag_handle
!= bad_keybag_handle
) {
549 (void) aks_unload_bag(bag_handle
);
556 keybag_handle_t
SOSBSKBLoadAndUnlockWithPeerIDAndSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag
,
557 CFStringRef peerID
, CFDataRef peerSecret
,
560 __block keybag_handle_t result
= bad_keybag_handle
;
562 CFDataRef lookedUpData
= CFDictionaryGetValue(backupSliceKeyBag
->wrapped_keys
, peerID
);
563 require_quiet(SecRequirementError(lookedUpData
!= NULL
, error
, CFSTR("%@ has no wrapped key in %@"), peerID
, backupSliceKeyBag
), exit
);
565 require_quiet(SOSPerformWithDeviceBackupFullKey(SOSGetBackupKeyCurveParameters(), peerSecret
, error
, ^(ccec_full_ctx_t fullKey
) {
566 SOSPerformWithUnwrappedData(fullKey
, lookedUpData
, error
, ^(size_t size
, uint8_t *buffer
) {
567 result
= SOSBSKBLoadAndUnlockBagWithSecret(backupSliceKeyBag
, size
, buffer
, error
);
576 keybag_handle_t
SOSBSKBLoadAndUnlockWithPeerSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag
,
577 SOSPeerInfoRef peer
, CFDataRef peerSecret
,
580 return SOSBSKBLoadAndUnlockWithPeerIDAndSecret(backupSliceKeyBag
, SOSPeerInfoGetPeerID(peer
), peerSecret
, error
);
583 keybag_handle_t
SOSBSKBLoadAndUnlockWithDirectSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag
,
587 keybag_handle_t result
= bad_keybag_handle
;
588 require_quiet(SecRequirementError(SOSBSKBIsDirect(backupSliceKeyBag
), error
, CFSTR("Not direct bag")), exit
);
590 result
= SOSBSKBLoadAndUnlockBagWithSecret(backupSliceKeyBag
,
591 CFDataGetLength(secret
),
592 CFDataGetBytePtr(secret
),
599 #include "SecRecoveryKey.h"
601 static bool SOSPerformWithRecoveryKeyFullKey(CFDataRef wrappingSecret
, CFErrorRef
*error
, void (^operation
)(ccec_full_ctx_t fullKey
, CFStringRef keyID
)) {
604 CFStringRef keyID
= NULL
;
605 SecRecoveryKey
*sRecKey
= NULL
;
606 CFDataRef fullKeyBytes
= NULL
;
607 CFDataRef pubKeyBytes
= NULL
;
608 CFStringRef restoreKeySecret
= CFStringCreateWithBytes(kCFAllocatorDefault
, CFDataGetBytePtr(wrappingSecret
), CFDataGetLength(wrappingSecret
), kCFStringEncodingUTF8
, false);
609 require_action_quiet(restoreKeySecret
, errOut
, SOSErrorCreate(kSOSErrorDecodeFailure
, error
, NULL
, CFSTR("Unable to create key string from data.")));
610 sRecKey
= SecRKCreateRecoveryKey(restoreKeySecret
);
611 require_action_quiet(sRecKey
, errOut
, SOSErrorCreate(kSOSErrorDecodeFailure
, error
, NULL
, CFSTR("Unable to create recovery key from string.")));
612 fullKeyBytes
= SecRKCopyBackupFullKey(sRecKey
);
613 pubKeyBytes
= SecRKCopyBackupPublicKey(sRecKey
);
614 require_action_quiet(fullKeyBytes
&& pubKeyBytes
, errOut
, SOSErrorCreate(kSOSErrorDecodeFailure
, error
, NULL
, CFSTR("Unable to create recovery key public and private keys.")));
615 keyID
= SOSCopyIDOfDataBuffer(pubKeyBytes
, error
);
616 require_quiet(keyID
, errOut
);
618 size_t keysize
= ccec_compact_import_priv_size(CFDataGetLength(fullKeyBytes
));
619 ccec_const_cp_t cp
= ccec_curve_for_length_lookup(keysize
, ccec_cp_256(), ccec_cp_384(), ccec_cp_521());
620 ccec_full_ctx_decl_cp(cp
, fullKey
);
621 int res
= ccec_compact_import_priv(cp
, CFDataGetLength(fullKeyBytes
), CFDataGetBytePtr(fullKeyBytes
), fullKey
);
623 operation(fullKey
, keyID
);
625 ccec_full_ctx_clear_cp(cp
, fullKey
);
628 if(!result
) SOSErrorCreate(kSOSErrorProcessingFailure
, error
, NULL
, CFSTR("Unable to perform crypto operation from fullKeyBytes."));
631 CFReleaseNull(keyID
);
632 CFReleaseNull(sRecKey
);
633 CFReleaseNull(fullKeyBytes
);
634 CFReleaseNull(pubKeyBytes
);
635 CFReleaseNull(restoreKeySecret
);
639 bskb_keybag_handle_t
SOSBSKBLoadAndUnlockWithWrappingSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag
,
640 CFDataRef wrappingSecret
,
642 __block keybag_handle_t result
= bad_keybag_handle
;
644 CFDataRef lookedUpData
= SOSBSKBCopyRecoveryKey(backupSliceKeyBag
);
645 require_quiet(SecRequirementError(lookedUpData
!= NULL
, error
, CFSTR("no recovery key found in %@"), backupSliceKeyBag
), errOut
);
647 SOSPerformWithRecoveryKeyFullKey(wrappingSecret
, error
, ^(ccec_full_ctx_t fullKey
, CFStringRef keyID
) {
648 SOSPerformWithUnwrappedData(fullKey
, lookedUpData
, error
, ^(size_t size
, uint8_t *buffer
) {
649 result
= SOSBSKBLoadAndUnlockBagWithSecret(backupSliceKeyBag
, size
, buffer
, error
);
654 CFReleaseSafe(lookedUpData
);
658 static CFDictionaryRef
SOSBSKBCopyAdditionalKeysWithPrefix(CFAllocatorRef allocator
, SOSBackupSliceKeyBagRef bskb
, CFStringRef prefix
) {
659 CFMutableDictionaryRef retval
= CFDictionaryCreateMutableForCFTypes(allocator
);
660 if(!retval
) return NULL
;
661 CFDictionaryForEach(bskb
->wrapped_keys
, ^(const void *key
, const void *value
) {
662 CFStringRef kpkid
= asString(key
, NULL
);
663 CFDataRef keyData
= asData(value
, NULL
);
664 if(kpkid
&& keyData
&& SOSKeyedPubKeyIdentifierIsPrefixed(kpkid
)) {
665 CFStringRef idPrefix
= SOSKeyedPubKeyIdentifierCopyPrefix(kpkid
);
666 if(CFEqualSafe(idPrefix
, prefix
)) {
667 CFDictionaryAddValue(retval
, kpkid
, keyData
);
669 CFReleaseNull(idPrefix
);
675 static bool SOSBSKBHasPrefixedKey(SOSBackupSliceKeyBagRef bskb
, CFStringRef prefix
) {
676 CFDictionaryRef keyDict
= SOSBSKBCopyAdditionalKeysWithPrefix(kCFAllocatorDefault
, bskb
, prefix
);
677 bool haveKeys
= CFDictionaryGetCount(keyDict
) > 0;
678 CFReleaseNull(keyDict
);
682 CFDataRef
SOSBSKBCopyRecoveryKey(SOSBackupSliceKeyBagRef bskb
) {
683 CFDictionaryRef keyDict
= SOSBSKBCopyAdditionalKeysWithPrefix(kCFAllocatorDefault
, bskb
, bskbRkbgPrefix
);
684 if(CFDictionaryGetCount(keyDict
) == 1) {
685 __block CFDataRef keyData
= NULL
;
686 CFDictionaryForEach(keyDict
, ^(const void *key
, const void *value
) {
687 keyData
= asData(value
, NULL
);
689 return CFDataCreateCopy(kCFAllocatorDefault
, keyData
);
691 CFReleaseNull(keyDict
);
695 bool SOSBSKBHasRecoveryKey(SOSBackupSliceKeyBagRef bskb
) {
696 if(SOSBSKBHasPrefixedKey(bskb
, bskbRkbgPrefix
)) return true;
697 // old way for RecoveryKeys
698 int keyCount
= (int) CFDictionaryGetCount(bskb
->wrapped_keys
);
699 int peerCount
= SOSBSKBCountPeers(bskb
);
700 return !SOSBSKBIsDirect(bskb
) && ((keyCount
- peerCount
) > 0);