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@
26 #include <Security/SecureObjectSync/SOSBackupSliceKeyBag.h>
29 // Needed headers for implementation
30 #include "AssertMacros.h"
31 #include <utilities/SecCFWrappers.h>
32 #include <utilities/SecAKSWrappers.h>
33 #include <utilities/SecBuffer.h>
34 #include <utilities/SecCFError.h>
35 #include <utilities/der_set.h>
36 #include <utilities/der_plist_internal.h>
37 #include <Security/SecRandom.h>
38 #include <Security/SecureObjectSync/SOSPeerInfo.h>
39 #include <Security/SecureObjectSync/SOSPeerInfoCollections.h>
40 #include <Security/SecureObjectSync/SOSInternal.h>
42 #include <corecrypto/ccec.h>
43 #include <corecrypto/ccsha2.h>
44 #include <corecrypto/ccrng.h>
48 #include "SOSInternal.h"
51 // MARK: Type creation
54 CFGiblisFor(SOSBackupSliceKeyBag
);
56 const int kAKSBagSecretLength
= 32;
58 struct __OpaqueSOSBackupSliceKeyBag
{
64 CFDictionaryRef wrapped_keys
;
67 static void SOSBackupSliceKeyBagDestroy(CFTypeRef aObj
) {
68 SOSBackupSliceKeyBagRef vb
= (SOSBackupSliceKeyBagRef
) aObj
;
70 CFReleaseNull(vb
->aks_bag
);
71 CFReleaseNull(vb
->peers
);
72 CFReleaseNull(vb
->wrapped_keys
);
75 static CFStringRef
SOSBackupSliceKeyBagCopyFormatDescription(CFTypeRef aObj
, CFDictionaryRef formatOptions
) {
76 SOSBackupSliceKeyBagRef vb
= (SOSBackupSliceKeyBagRef
) aObj
;
78 CFMutableStringRef description
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
80 CFStringAppendFormat(description
, NULL
, CFSTR("<SOSBackupSliceKeyBag@%p %ld"), vb
, vb
->peers
? CFSetGetCount(vb
->peers
) : 0);
81 CFStringAppend(description
, CFSTR(">"));
88 // MARK: Encode/Decode
91 const uint8_t* der_decode_BackupSliceKeyBag(CFAllocatorRef allocator
,
92 SOSBackupSliceKeyBagRef
* BackupSliceKeyBag
, CFErrorRef
*error
,
93 const uint8_t* der
, const uint8_t *der_end
) {
94 if (der
== NULL
) return der
;
96 const uint8_t *result
= NULL
;
97 SOSBackupSliceKeyBagRef vb
= CFTypeAllocate(SOSBackupSliceKeyBag
, struct __OpaqueSOSBackupSliceKeyBag
, allocator
);
98 require_quiet(SecAllocationError(vb
, error
, CFSTR("View bag allocation failed")), fail
);
100 const uint8_t *sequence_end
= NULL
;
101 der
= ccder_decode_sequence_tl(&sequence_end
, der
, der_end
);
102 require_quiet(sequence_end
== der_end
, fail
);
104 der
= der_decode_data(kCFAllocatorDefault
, kCFPropertyListImmutable
, &vb
->aks_bag
, error
, der
, sequence_end
);
105 vb
->peers
= SOSPeerInfoSetCreateFromArrayDER(kCFAllocatorDefault
, &kSOSPeerSetCallbacks
, error
,
107 der
= der_decode_dictionary(kCFAllocatorDefault
, kCFPropertyListImmutable
, &vb
->wrapped_keys
, error
, der
, sequence_end
);
109 require_quiet(SecRequirementError(der
== der_end
, error
, CFSTR("Extra space in sequence")), fail
);
111 if (BackupSliceKeyBag
)
112 CFTransferRetained(*BackupSliceKeyBag
, vb
);
121 size_t der_sizeof_BackupSliceKeyBag(SOSBackupSliceKeyBagRef BackupSliceKeyBag
, CFErrorRef
*error
) {
124 require_quiet(SecRequirementError(BackupSliceKeyBag
!= NULL
, error
, CFSTR("Null BackupSliceKeyBag")), fail
);
125 require_quiet(SecRequirementError(BackupSliceKeyBag
->aks_bag
!= NULL
, error
, CFSTR("null aks_bag in BackupSliceKeyBag")), fail
);
127 size_t bag_size
= der_sizeof_data(BackupSliceKeyBag
->aks_bag
, error
);
128 require_quiet(bag_size
, fail
);
130 size_t peers_size
= SOSPeerInfoSetGetDEREncodedArraySize(BackupSliceKeyBag
->peers
, error
);
131 require_quiet(peers_size
, fail
);
133 size_t wrapped_keys_size
= der_sizeof_dictionary(BackupSliceKeyBag
->wrapped_keys
, error
);
134 require_quiet(wrapped_keys_size
, fail
);
136 result
= ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, bag_size
+ peers_size
+ wrapped_keys_size
);
142 uint8_t* der_encode_BackupSliceKeyBag(SOSBackupSliceKeyBagRef set
, CFErrorRef
*error
,
143 const uint8_t *der
, uint8_t *der_end
) {
144 uint8_t *result
= NULL
;
145 if (der_end
== NULL
) return der_end
;
147 require_quiet(SecRequirementError(set
!= NULL
, error
, CFSTR("Null set passed to encode")), fail
);
148 require_quiet(set
, fail
); // This should be removed when SecRequirementError can squelch analyzer warnings
150 der_end
= ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
151 der_encode_data(set
->aks_bag
, error
, der
,
152 SOSPeerInfoSetEncodeToArrayDER(set
->peers
, error
, der
,
153 der_encode_dictionary(set
->wrapped_keys
, error
, der
, der_end
))));
155 require_quiet(der_end
== der
, fail
);
163 SOSBackupSliceKeyBagRef
SOSBackupSliceKeyBagCreateFromData(CFAllocatorRef allocator
, CFDataRef data
, CFErrorRef
*error
) {
164 SOSBackupSliceKeyBagRef result
= NULL
;
165 SOSBackupSliceKeyBagRef decodedBag
= NULL
;
167 const uint8_t *der
= CFDataGetBytePtr(data
);
168 const uint8_t *der_end
= der
+ CFDataGetLength(data
);
170 der
= der_decode_BackupSliceKeyBag(allocator
, &decodedBag
, error
, der
, der_end
);
172 require_quiet(SecRequirementError(der
== der_end
, error
, CFSTR("Didn't consume all data supplied")), fail
);
174 CFTransferRetained(result
, decodedBag
);
177 CFReleaseNull(decodedBag
);
182 // MARK: Construction
185 bool SOSBSKBIsGoodBackupPublic(CFDataRef publicKey
, CFErrorRef
*error
) {
188 ccec_pub_ctx_decl_cp(SOSGetBackupKeyCurveParameters(), pub_key
);
190 int cc_result
= ccec_compact_import_pub(SOSGetBackupKeyCurveParameters(), CFDataGetLength(publicKey
), CFDataGetBytePtr(publicKey
), pub_key
);
192 require_action_quiet(cc_result
== 0, exit
, SOSErrorCreate(kSOSErrorDecodeFailure
, error
, NULL
, CFSTR("Unable to decode public key: %@"), publicKey
));
201 static CFDataRef
SOSCopyECWrapped(CFDataRef publicKey
, CFDataRef secret
, CFErrorRef
*error
) {
202 CFDataRef result
= NULL
;
204 ccec_pub_ctx_decl_cp(SOSGetBackupKeyCurveParameters(), pub_key
);
206 int cc_result
= ccec_compact_import_pub(SOSGetBackupKeyCurveParameters(), CFDataGetLength(publicKey
), CFDataGetBytePtr(publicKey
), pub_key
);
208 require_action_quiet(cc_result
== 0, exit
, SOSErrorCreate(kSOSErrorDecodeFailure
, error
, NULL
, CFSTR("Unable to decode public key: %@"), publicKey
));
210 result
= SOSCopyECWrappedData(pub_key
, secret
, error
);
217 static CFDictionaryRef
SOSBackupSliceKeyBagCopyWrappedKeys(SOSBackupSliceKeyBagRef vb
, CFDataRef secret
, CFErrorRef
*error
) {
218 CFDictionaryRef result
= NULL
;
219 CFMutableDictionaryRef wrappedKeys
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
221 __block
bool success
= true;
222 CFSetForEach(vb
->peers
, ^(const void *value
) {
223 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
224 if (isSOSPeerInfo(pi
)) {
225 CFStringRef id
= SOSPeerInfoGetPeerID(pi
);
226 CFDataRef backupKey
= SOSPeerInfoCopyBackupKey(pi
);
229 CFDataRef wrappedKey
= SOSCopyECWrapped(backupKey
, secret
, error
);
231 CFDictionaryAddValue(wrappedKeys
, id
, wrappedKey
);
235 CFReleaseNull(wrappedKey
);
236 CFReleaseNull(backupKey
);
243 CFTransferRetained(result
, wrappedKeys
);
245 CFReleaseNull(wrappedKeys
);
249 static bool SOSBackupSliceKeyBagCreateBackupBag(SOSBackupSliceKeyBagRef vb
, CFErrorRef
* error
) {
250 CFReleaseNull(vb
->aks_bag
);
252 // Choose a random key.
253 PerformWithBufferAndClear(kAKSBagSecretLength
, ^(size_t size
, uint8_t *buffer
) {
254 CFDataRef secret
= NULL
;
256 require_quiet(SecError(SecRandomCopyBytes(kSecRandomDefault
, size
, buffer
), error
, CFSTR("SecRandom falied!")), fail
);
258 secret
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, buffer
, size
, kCFAllocatorNull
);
260 CFAssignRetained(vb
->wrapped_keys
, SOSBackupSliceKeyBagCopyWrappedKeys(vb
, secret
, error
));
261 CFAssignRetained(vb
->aks_bag
, SecAKSCopyBackupBagWithSecret(size
, buffer
, error
));
264 CFReleaseSafe(secret
);
267 return vb
->aks_bag
!= NULL
;
271 CFDataRef
SOSBSKBCopyEncoded(SOSBackupSliceKeyBagRef BackupSliceKeyBag
, CFErrorRef
* error
) {
272 CFDataRef result
= NULL
;
273 CFMutableDataRef encoded
= NULL
;
275 size_t encodedSize
= der_sizeof_BackupSliceKeyBag(BackupSliceKeyBag
, error
);
276 require_quiet(encodedSize
, fail
);
278 encoded
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, encodedSize
);
279 require_quiet(SecAllocationError(encoded
, error
, CFSTR("Faild to create scratch")), fail
);
281 uint8_t *encode_to
= CFDataGetMutableBytePtr(encoded
);
282 uint8_t *encode_to_end
= encode_to
+ CFDataGetLength(encoded
);
283 require_quiet(encode_to
== der_encode_BackupSliceKeyBag(BackupSliceKeyBag
, error
, encode_to
, encode_to_end
), fail
);
285 CFTransferRetained(result
, encoded
);
288 CFReleaseSafe(encoded
);
292 static CFSetRef
SOSBackupSliceKeyBagCreatePeerSet(CFAllocatorRef allocator
, CFSetRef peers
) {
293 CFMutableSetRef result
= CFSetCreateMutableForSOSPeerInfosByID(allocator
);
295 CFSetForEach(peers
, ^(const void *value
) {
296 CFSetAddValue(result
, value
);
302 SOSBackupSliceKeyBagRef
SOSBackupSliceKeyBagCreate(CFAllocatorRef allocator
, CFSetRef peers
, CFErrorRef
* error
) {
303 SOSBackupSliceKeyBagRef result
= NULL
;
304 SOSBackupSliceKeyBagRef vb
= CFTypeAllocate(SOSBackupSliceKeyBag
, struct __OpaqueSOSBackupSliceKeyBag
, allocator
);
305 require_quiet(SecAllocationError(vb
, error
, CFSTR("View bag allocation failed")), fail
);
307 require_quiet(SecRequirementError(CFSetGetCount(peers
) > 0, error
, CFSTR("Need peers")), fail
);
309 vb
->peers
= SOSBackupSliceKeyBagCreatePeerSet(allocator
, peers
);
310 vb
->wrapped_keys
= CFDictionaryCreateMutableForCFTypes(allocator
);
312 require_quiet(SOSBackupSliceKeyBagCreateBackupBag(vb
, error
), fail
);
314 CFTransferRetained(result
, vb
);
321 SOSBackupSliceKeyBagRef
SOSBackupSliceKeyBagCreateDirect(CFAllocatorRef allocator
, CFDataRef aks_bag
, CFErrorRef
*error
)
323 SOSBackupSliceKeyBagRef result
= NULL
;
324 SOSBackupSliceKeyBagRef vb
= CFTypeAllocate(SOSBackupSliceKeyBag
, struct __OpaqueSOSBackupSliceKeyBag
, allocator
);
325 require_quiet(SecAllocationError(vb
, error
, CFSTR("View bag allocation failed")), fail
);
327 require_quiet(SecRequirementError(aks_bag
, error
, CFSTR("Need aks bag")), fail
);
329 vb
->aks_bag
= CFRetainSafe(aks_bag
);
330 vb
->peers
= CFSetCreateMutableForSOSPeerInfosByID(allocator
);
331 vb
->wrapped_keys
= CFDictionaryCreateMutableForCFTypes(allocator
);
333 CFTransferRetained(result
, vb
);
344 bool SOSBSKBIsDirect(SOSBackupSliceKeyBagRef backupSliceKeyBag
)
346 return 0 == CFSetGetCount(backupSliceKeyBag
->peers
);
349 CFDataRef
SOSBSKBCopyAKSBag(SOSBackupSliceKeyBagRef backupSliceKeyBag
, CFErrorRef
* error
)
351 return CFRetainSafe(backupSliceKeyBag
->aks_bag
);
354 CFSetRef
SOSBSKBGetPeers(SOSBackupSliceKeyBagRef backupSliceKeyBag
){
355 return backupSliceKeyBag
->peers
;
358 bskb_keybag_handle_t
SOSBSKBLoadLocked(SOSBackupSliceKeyBagRef backupSliceKeyBag
,
361 #if !TARGET_HAS_KEYSTORE
362 return bad_keybag_handle
;
364 keybag_handle_t result
= bad_keybag_handle
;
365 keybag_handle_t bag_handle
= bad_keybag_handle
;
367 require_quiet(SecRequirementError(backupSliceKeyBag
->aks_bag
, error
,
368 CFSTR("No aks bag to load")), exit
);
369 require_quiet(SecRequirementError(CFDataGetLength(backupSliceKeyBag
->aks_bag
) < INT_MAX
, error
,
370 CFSTR("No aks bag to load")), exit
);
372 kern_return_t aks_result
;
373 aks_result
= aks_load_bag(CFDataGetBytePtr(backupSliceKeyBag
->aks_bag
),
374 (int) CFDataGetLength(backupSliceKeyBag
->aks_bag
),
376 require_quiet(SecKernError(aks_result
, error
,
377 CFSTR("aks_load_bag failed: %d"), aks_result
), exit
);
380 bag_handle
= bad_keybag_handle
;
383 if (bag_handle
!= bad_keybag_handle
) {
384 (void) aks_unload_bag(bag_handle
);
392 static keybag_handle_t
SOSBSKBLoadAndUnlockBagWithSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag
,
393 size_t secretSize
, const uint8_t *secret
,
396 #if !TARGET_HAS_KEYSTORE
397 return bad_keybag_handle
;
399 keybag_handle_t result
= bad_keybag_handle
;
400 keybag_handle_t bag_handle
= bad_keybag_handle
;
402 require_quiet(SecRequirementError(backupSliceKeyBag
->aks_bag
, error
,
403 CFSTR("No aks bag to load")), exit
);
404 require_quiet(SecRequirementError(CFDataGetLength(backupSliceKeyBag
->aks_bag
) < INT_MAX
, error
,
405 CFSTR("No aks bag to load")), exit
);
406 require_quiet(SecRequirementError(secretSize
<= INT_MAX
, error
,
407 CFSTR("secret too big")), exit
);
409 kern_return_t aks_result
;
410 aks_result
= aks_load_bag(CFDataGetBytePtr(backupSliceKeyBag
->aks_bag
),
411 (int) CFDataGetLength(backupSliceKeyBag
->aks_bag
),
413 require_quiet(SecKernError(aks_result
, error
,
414 CFSTR("aks_load_bag failed: %d"), aks_result
), exit
);
416 aks_result
= aks_unlock_bag(bag_handle
, secret
, (int) secretSize
);
417 require_quiet(SecKernError(aks_result
, error
,
418 CFSTR("failed to unlock bag: %d"), aks_result
), exit
);
421 bag_handle
= bad_keybag_handle
;
424 if (bag_handle
!= bad_keybag_handle
) {
425 (void) aks_unload_bag(bag_handle
);
432 keybag_handle_t
SOSBSKBLoadAndUnlockWithPeerIDAndSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag
,
433 CFStringRef peerID
, CFDataRef peerSecret
,
436 __block keybag_handle_t result
= bad_keybag_handle
;
438 CFDataRef lookedUpData
= CFDictionaryGetValue(backupSliceKeyBag
->wrapped_keys
, peerID
);
439 require_quiet(SecRequirementError(lookedUpData
!= NULL
, error
, CFSTR("%@ has no wrapped key in %@"), peerID
, backupSliceKeyBag
), exit
);
441 require_quiet(SOSPerformWithDeviceBackupFullKey(SOSGetBackupKeyCurveParameters(), peerSecret
, error
, ^(ccec_full_ctx_t fullKey
) {
442 SOSPerformWithUnwrappedData(fullKey
, lookedUpData
, error
, ^(size_t size
, uint8_t *buffer
) {
443 result
= SOSBSKBLoadAndUnlockBagWithSecret(backupSliceKeyBag
, size
, buffer
, error
);
452 keybag_handle_t
SOSBSKBLoadAndUnlockWithPeerSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag
,
453 SOSPeerInfoRef peer
, CFDataRef peerSecret
,
456 return SOSBSKBLoadAndUnlockWithPeerIDAndSecret(backupSliceKeyBag
, SOSPeerInfoGetPeerID(peer
), peerSecret
, error
);
459 keybag_handle_t
SOSBSKBLoadAndUnlockWithDirectSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag
,
463 keybag_handle_t result
= bad_keybag_handle
;
464 require_quiet(SecRequirementError(SOSBSKBIsDirect(backupSliceKeyBag
), error
, CFSTR("Not direct bag")), exit
);
466 result
= SOSBSKBLoadAndUnlockBagWithSecret(backupSliceKeyBag
,
467 CFDataGetLength(secret
),
468 CFDataGetBytePtr(secret
),