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 size_t bag_size
= der_sizeof_data(BackupSliceKeyBag
->aks_bag
, error
);
125 require_quiet(bag_size
, fail
);
127 size_t peers_size
= SOSPeerInfoSetGetDEREncodedArraySize(BackupSliceKeyBag
->peers
, error
);
128 require_quiet(peers_size
, fail
);
130 size_t wrapped_keys_size
= der_sizeof_dictionary(BackupSliceKeyBag
->wrapped_keys
, error
);
131 require_quiet(wrapped_keys_size
, fail
);
133 result
= ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, bag_size
+ peers_size
+ wrapped_keys_size
);
139 uint8_t* der_encode_BackupSliceKeyBag(SOSBackupSliceKeyBagRef set
, CFErrorRef
*error
,
140 const uint8_t *der
, uint8_t *der_end
) {
141 uint8_t *result
= NULL
;
142 if (der_end
== NULL
) return der_end
;
144 require_quiet(SecRequirementError(set
!= NULL
, error
, CFSTR("Null set passed to encode")), fail
);
146 der_end
= ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
147 der_encode_data(set
->aks_bag
, error
, der
,
148 SOSPeerInfoSetEncodeToArrayDER(set
->peers
, error
, der
,
149 der_encode_dictionary(set
->wrapped_keys
, error
, der
, der_end
))));
151 require_quiet(der_end
== der
, fail
);
159 SOSBackupSliceKeyBagRef
SOSBackupSliceKeyBagCreateFromData(CFAllocatorRef allocator
, CFDataRef data
, CFErrorRef
*error
) {
160 SOSBackupSliceKeyBagRef result
= NULL
;
161 SOSBackupSliceKeyBagRef decodedBag
= NULL
;
163 const uint8_t *der
= CFDataGetBytePtr(data
);
164 const uint8_t *der_end
= der
+ CFDataGetLength(data
);
166 der
= der_decode_BackupSliceKeyBag(allocator
, &decodedBag
, error
, der
, der_end
);
168 require_quiet(SecRequirementError(der
== der_end
, error
, CFSTR("Didn't consume all data supplied")), fail
);
170 CFTransferRetained(result
, decodedBag
);
173 CFReleaseNull(decodedBag
);
178 // MARK: Construction
181 bool SOSBSKBIsGoodBackupPublic(CFDataRef publicKey
, CFErrorRef
*error
) {
184 ccec_pub_ctx_decl_cp(SOSGetBackupKeyCurveParameters(), pub_key
);
186 int cc_result
= ccec_compact_import_pub(SOSGetBackupKeyCurveParameters(), CFDataGetLength(publicKey
), CFDataGetBytePtr(publicKey
), pub_key
);
188 require_action_quiet(cc_result
== 0, exit
, SOSErrorCreate(kSOSErrorDecodeFailure
, error
, NULL
, CFSTR("Unable to decode public key: %@"), publicKey
));
197 static CFDataRef
SOSCopyECWrapped(CFDataRef publicKey
, CFDataRef secret
, CFErrorRef
*error
) {
198 CFDataRef result
= NULL
;
200 ccec_pub_ctx_decl_cp(SOSGetBackupKeyCurveParameters(), pub_key
);
202 int cc_result
= ccec_compact_import_pub(SOSGetBackupKeyCurveParameters(), CFDataGetLength(publicKey
), CFDataGetBytePtr(publicKey
), pub_key
);
204 require_action_quiet(cc_result
== 0, exit
, SOSErrorCreate(kSOSErrorDecodeFailure
, error
, NULL
, CFSTR("Unable to decode public key: %@"), publicKey
));
206 result
= SOSCopyECWrappedData(pub_key
, secret
, error
);
213 static CFDictionaryRef
SOSBackupSliceKeyBagCopyWrappedKeys(SOSBackupSliceKeyBagRef vb
, CFDataRef secret
, CFErrorRef
*error
) {
214 CFDictionaryRef result
= NULL
;
215 CFMutableDictionaryRef wrappedKeys
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
217 __block
bool success
= true;
218 CFSetForEach(vb
->peers
, ^(const void *value
) {
219 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
220 if (isSOSPeerInfo(pi
)) {
221 CFStringRef id
= SOSPeerInfoGetPeerID(pi
);
222 CFDataRef backupKey
= SOSPeerInfoCopyBackupKey(pi
);
225 CFDataRef wrappedKey
= SOSCopyECWrapped(backupKey
, secret
, error
);
227 CFDictionaryAddValue(wrappedKeys
, id
, wrappedKey
);
231 CFReleaseNull(wrappedKey
);
232 CFReleaseNull(backupKey
);
239 CFTransferRetained(result
, wrappedKeys
);
241 CFReleaseNull(wrappedKeys
);
245 static bool SOSBackupSliceKeyBagCreateBackupBag(SOSBackupSliceKeyBagRef vb
, CFErrorRef
* error
) {
246 CFReleaseNull(vb
->aks_bag
);
248 // Choose a random key.
249 PerformWithBufferAndClear(kAKSBagSecretLength
, ^(size_t size
, uint8_t *buffer
) {
250 SecRandomCopyBytes(kSecRandomDefault
, size
, buffer
);
251 CFDataRef secret
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, buffer
, size
, kCFAllocatorNull
);
253 CFAssignRetained(vb
->wrapped_keys
, SOSBackupSliceKeyBagCopyWrappedKeys(vb
, secret
, error
));
254 CFAssignRetained(vb
->aks_bag
, SecAKSCopyBackupBagWithSecret(size
, buffer
, error
));
256 CFReleaseSafe(secret
);
259 return vb
->aks_bag
!= NULL
;
263 CFDataRef
SOSBSKBCopyEncoded(SOSBackupSliceKeyBagRef BackupSliceKeyBag
, CFErrorRef
* error
) {
264 CFDataRef result
= NULL
;
265 CFMutableDataRef encoded
= NULL
;
267 size_t encodedSize
= der_sizeof_BackupSliceKeyBag(BackupSliceKeyBag
, error
);
268 require_quiet(encodedSize
, fail
);
270 encoded
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, encodedSize
);
271 require_quiet(SecAllocationError(encoded
, error
, CFSTR("Faild to create scratch")), fail
);
273 uint8_t *encode_to
= CFDataGetMutableBytePtr(encoded
);
274 uint8_t *encode_to_end
= encode_to
+ CFDataGetLength(encoded
);
275 require_quiet(encode_to
== der_encode_BackupSliceKeyBag(BackupSliceKeyBag
, error
, encode_to
, encode_to_end
), fail
);
277 CFTransferRetained(result
, encoded
);
280 CFReleaseSafe(encoded
);
284 static CFSetRef
SOSBackupSliceKeyBagCreatePeerSet(CFAllocatorRef allocator
, CFSetRef peers
) {
285 CFMutableSetRef result
= CFSetCreateMutableForSOSPeerInfosByID(allocator
);
287 CFSetForEach(peers
, ^(const void *value
) {
288 CFSetAddValue(result
, value
);
294 SOSBackupSliceKeyBagRef
SOSBackupSliceKeyBagCreate(CFAllocatorRef allocator
, CFSetRef peers
, CFErrorRef
* error
) {
295 SOSBackupSliceKeyBagRef result
= NULL
;
296 SOSBackupSliceKeyBagRef vb
= CFTypeAllocate(SOSBackupSliceKeyBag
, struct __OpaqueSOSBackupSliceKeyBag
, allocator
);
297 require_quiet(SecAllocationError(vb
, error
, CFSTR("View bag allocation failed")), fail
);
299 require_quiet(SecRequirementError(CFSetGetCount(peers
) > 0, error
, CFSTR("Need peers")), fail
);
301 vb
->peers
= SOSBackupSliceKeyBagCreatePeerSet(allocator
, peers
);
302 vb
->wrapped_keys
= CFDictionaryCreateMutableForCFTypes(allocator
);
304 require_quiet(SOSBackupSliceKeyBagCreateBackupBag(vb
, error
), fail
);
306 CFTransferRetained(result
, vb
);
313 SOSBackupSliceKeyBagRef
SOSBackupSliceKeyBagCreateDirect(CFAllocatorRef allocator
, CFDataRef aks_bag
, CFErrorRef
*error
)
315 SOSBackupSliceKeyBagRef result
= NULL
;
316 SOSBackupSliceKeyBagRef vb
= CFTypeAllocate(SOSBackupSliceKeyBag
, struct __OpaqueSOSBackupSliceKeyBag
, allocator
);
317 require_quiet(SecAllocationError(vb
, error
, CFSTR("View bag allocation failed")), fail
);
319 require_quiet(SecRequirementError(aks_bag
, error
, CFSTR("Need aks bag")), fail
);
321 vb
->aks_bag
= CFRetainSafe(aks_bag
);
322 vb
->peers
= CFSetCreateMutableForSOSPeerInfosByID(allocator
);
323 vb
->wrapped_keys
= CFDictionaryCreateMutableForCFTypes(allocator
);
325 CFTransferRetained(result
, vb
);
336 bool SOSBSKBIsDirect(SOSBackupSliceKeyBagRef backupSliceKeyBag
)
338 return 0 == CFSetGetCount(backupSliceKeyBag
->peers
);
341 CFDataRef
SOSBSKBCopyAKSBag(SOSBackupSliceKeyBagRef backupSliceKeyBag
, CFErrorRef
* error
)
343 return CFRetainSafe(backupSliceKeyBag
->aks_bag
);
346 CFSetRef
SOSBSKBGetPeers(SOSBackupSliceKeyBagRef backupSliceKeyBag
){
347 return backupSliceKeyBag
->peers
;
350 static keybag_handle_t
SOSBSKBLoadAndUnlockBagWithSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag
,
351 size_t secretSize
, const uint8_t *secret
,
354 #if !TARGET_HAS_KEYSTORE
355 return bad_keybag_handle
;
357 keybag_handle_t result
= bad_keybag_handle
;
358 keybag_handle_t bag_handle
= bad_keybag_handle
;
360 require_quiet(SecRequirementError(backupSliceKeyBag
->aks_bag
, error
,
361 CFSTR("No aks bag to load")), exit
);
362 require_quiet(SecRequirementError(CFDataGetLength(backupSliceKeyBag
->aks_bag
) < INT_MAX
, error
,
363 CFSTR("No aks bag to load")), exit
);
364 require_quiet(SecRequirementError(secretSize
<= INT_MAX
, error
,
365 CFSTR("secret too big")), exit
);
367 kern_return_t aks_result
;
368 aks_result
= aks_load_bag(CFDataGetBytePtr(backupSliceKeyBag
->aks_bag
),
369 (int) CFDataGetLength(backupSliceKeyBag
->aks_bag
),
371 require_quiet(SecKernError(aks_result
, error
,
372 CFSTR("aks_load_bag failed: %d"), aks_result
), exit
);
374 aks_result
= aks_unlock_bag(bag_handle
, secret
, (int) secretSize
);
375 require_quiet(SecKernError(aks_result
, error
,
376 CFSTR("failed to unlock bag: %d"), aks_result
), exit
);
379 bag_handle
= bad_keybag_handle
;
382 if (bag_handle
!= bad_keybag_handle
) {
383 (void) aks_unload_bag(bag_handle
);
390 keybag_handle_t
SOSBSKBLoadAndUnlockWithPeerIDAndSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag
,
391 CFStringRef peerID
, CFDataRef peerSecret
,
394 __block keybag_handle_t result
= bad_keybag_handle
;
396 CFDataRef lookedUpData
= CFDictionaryGetValue(backupSliceKeyBag
->wrapped_keys
, peerID
);
397 require_quiet(SecRequirementError(lookedUpData
!= NULL
, error
, CFSTR("%@ has no wrapped key in %@"), peerID
, backupSliceKeyBag
), exit
);
399 require_quiet(SOSPerformWithDeviceBackupFullKey(SOSGetBackupKeyCurveParameters(), peerSecret
, error
, ^(ccec_full_ctx_t fullKey
) {
400 SOSPerformWithUnwrappedData(fullKey
, lookedUpData
, error
, ^(size_t size
, uint8_t *buffer
) {
401 result
= SOSBSKBLoadAndUnlockBagWithSecret(backupSliceKeyBag
, size
, buffer
, error
);
410 keybag_handle_t
SOSBSKBLoadAndUnlockWithPeerSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag
,
411 SOSPeerInfoRef peer
, CFDataRef peerSecret
,
414 return SOSBSKBLoadAndUnlockWithPeerIDAndSecret(backupSliceKeyBag
, SOSPeerInfoGetPeerID(peer
), peerSecret
, error
);
417 keybag_handle_t
SOSBSKBLoadAndUnlockWithDirectSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag
,
421 keybag_handle_t result
= bad_keybag_handle
;
422 require_quiet(SecRequirementError(SOSBSKBIsDirect(backupSliceKeyBag
), error
, CFSTR("Not direct bag")), exit
);
424 result
= SOSBSKBLoadAndUnlockBagWithSecret(backupSliceKeyBag
,
425 CFDataGetLength(secret
),
426 CFDataGetBytePtr(secret
),