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
);
145 require_quiet(set
, fail
); // This should be removed when SecRequirementError can squelch analyzer warnings
147 der_end
= ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
148 der_encode_data(set
->aks_bag
, error
, der
,
149 SOSPeerInfoSetEncodeToArrayDER(set
->peers
, error
, der
,
150 der_encode_dictionary(set
->wrapped_keys
, error
, der
, der_end
))));
152 require_quiet(der_end
== der
, fail
);
160 SOSBackupSliceKeyBagRef
SOSBackupSliceKeyBagCreateFromData(CFAllocatorRef allocator
, CFDataRef data
, CFErrorRef
*error
) {
161 SOSBackupSliceKeyBagRef result
= NULL
;
162 SOSBackupSliceKeyBagRef decodedBag
= NULL
;
164 const uint8_t *der
= CFDataGetBytePtr(data
);
165 const uint8_t *der_end
= der
+ CFDataGetLength(data
);
167 der
= der_decode_BackupSliceKeyBag(allocator
, &decodedBag
, error
, der
, der_end
);
169 require_quiet(SecRequirementError(der
== der_end
, error
, CFSTR("Didn't consume all data supplied")), fail
);
171 CFTransferRetained(result
, decodedBag
);
174 CFReleaseNull(decodedBag
);
179 // MARK: Construction
182 bool SOSBSKBIsGoodBackupPublic(CFDataRef publicKey
, CFErrorRef
*error
) {
185 ccec_pub_ctx_decl_cp(SOSGetBackupKeyCurveParameters(), pub_key
);
187 int cc_result
= ccec_compact_import_pub(SOSGetBackupKeyCurveParameters(), CFDataGetLength(publicKey
), CFDataGetBytePtr(publicKey
), pub_key
);
189 require_action_quiet(cc_result
== 0, exit
, SOSErrorCreate(kSOSErrorDecodeFailure
, error
, NULL
, CFSTR("Unable to decode public key: %@"), publicKey
));
198 static CFDataRef
SOSCopyECWrapped(CFDataRef publicKey
, CFDataRef secret
, CFErrorRef
*error
) {
199 CFDataRef result
= NULL
;
201 ccec_pub_ctx_decl_cp(SOSGetBackupKeyCurveParameters(), pub_key
);
203 int cc_result
= ccec_compact_import_pub(SOSGetBackupKeyCurveParameters(), CFDataGetLength(publicKey
), CFDataGetBytePtr(publicKey
), pub_key
);
205 require_action_quiet(cc_result
== 0, exit
, SOSErrorCreate(kSOSErrorDecodeFailure
, error
, NULL
, CFSTR("Unable to decode public key: %@"), publicKey
));
207 result
= SOSCopyECWrappedData(pub_key
, secret
, error
);
214 static CFDictionaryRef
SOSBackupSliceKeyBagCopyWrappedKeys(SOSBackupSliceKeyBagRef vb
, CFDataRef secret
, CFErrorRef
*error
) {
215 CFDictionaryRef result
= NULL
;
216 CFMutableDictionaryRef wrappedKeys
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
218 __block
bool success
= true;
219 CFSetForEach(vb
->peers
, ^(const void *value
) {
220 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
221 if (isSOSPeerInfo(pi
)) {
222 CFStringRef id
= SOSPeerInfoGetPeerID(pi
);
223 CFDataRef backupKey
= SOSPeerInfoCopyBackupKey(pi
);
226 CFDataRef wrappedKey
= SOSCopyECWrapped(backupKey
, secret
, error
);
228 CFDictionaryAddValue(wrappedKeys
, id
, wrappedKey
);
232 CFReleaseNull(wrappedKey
);
233 CFReleaseNull(backupKey
);
240 CFTransferRetained(result
, wrappedKeys
);
242 CFReleaseNull(wrappedKeys
);
246 static bool SOSBackupSliceKeyBagCreateBackupBag(SOSBackupSliceKeyBagRef vb
, CFErrorRef
* error
) {
247 CFReleaseNull(vb
->aks_bag
);
249 // Choose a random key.
250 PerformWithBufferAndClear(kAKSBagSecretLength
, ^(size_t size
, uint8_t *buffer
) {
251 CFDataRef secret
= NULL
;
253 require_quiet(SecError(SecRandomCopyBytes(kSecRandomDefault
, size
, buffer
), error
, CFSTR("SecRandom falied!")), fail
);
255 secret
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, buffer
, size
, kCFAllocatorNull
);
257 CFAssignRetained(vb
->wrapped_keys
, SOSBackupSliceKeyBagCopyWrappedKeys(vb
, secret
, error
));
258 CFAssignRetained(vb
->aks_bag
, SecAKSCopyBackupBagWithSecret(size
, buffer
, error
));
261 CFReleaseSafe(secret
);
264 return vb
->aks_bag
!= NULL
;
268 CFDataRef
SOSBSKBCopyEncoded(SOSBackupSliceKeyBagRef BackupSliceKeyBag
, CFErrorRef
* error
) {
269 CFDataRef result
= NULL
;
270 CFMutableDataRef encoded
= NULL
;
272 size_t encodedSize
= der_sizeof_BackupSliceKeyBag(BackupSliceKeyBag
, error
);
273 require_quiet(encodedSize
, fail
);
275 encoded
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, encodedSize
);
276 require_quiet(SecAllocationError(encoded
, error
, CFSTR("Faild to create scratch")), fail
);
278 uint8_t *encode_to
= CFDataGetMutableBytePtr(encoded
);
279 uint8_t *encode_to_end
= encode_to
+ CFDataGetLength(encoded
);
280 require_quiet(encode_to
== der_encode_BackupSliceKeyBag(BackupSliceKeyBag
, error
, encode_to
, encode_to_end
), fail
);
282 CFTransferRetained(result
, encoded
);
285 CFReleaseSafe(encoded
);
289 static CFSetRef
SOSBackupSliceKeyBagCreatePeerSet(CFAllocatorRef allocator
, CFSetRef peers
) {
290 CFMutableSetRef result
= CFSetCreateMutableForSOSPeerInfosByID(allocator
);
292 CFSetForEach(peers
, ^(const void *value
) {
293 CFSetAddValue(result
, value
);
299 SOSBackupSliceKeyBagRef
SOSBackupSliceKeyBagCreate(CFAllocatorRef allocator
, CFSetRef peers
, CFErrorRef
* error
) {
300 SOSBackupSliceKeyBagRef result
= NULL
;
301 SOSBackupSliceKeyBagRef vb
= CFTypeAllocate(SOSBackupSliceKeyBag
, struct __OpaqueSOSBackupSliceKeyBag
, allocator
);
302 require_quiet(SecAllocationError(vb
, error
, CFSTR("View bag allocation failed")), fail
);
304 require_quiet(SecRequirementError(CFSetGetCount(peers
) > 0, error
, CFSTR("Need peers")), fail
);
306 vb
->peers
= SOSBackupSliceKeyBagCreatePeerSet(allocator
, peers
);
307 vb
->wrapped_keys
= CFDictionaryCreateMutableForCFTypes(allocator
);
309 require_quiet(SOSBackupSliceKeyBagCreateBackupBag(vb
, error
), fail
);
311 CFTransferRetained(result
, vb
);
318 SOSBackupSliceKeyBagRef
SOSBackupSliceKeyBagCreateDirect(CFAllocatorRef allocator
, CFDataRef aks_bag
, CFErrorRef
*error
)
320 SOSBackupSliceKeyBagRef result
= NULL
;
321 SOSBackupSliceKeyBagRef vb
= CFTypeAllocate(SOSBackupSliceKeyBag
, struct __OpaqueSOSBackupSliceKeyBag
, allocator
);
322 require_quiet(SecAllocationError(vb
, error
, CFSTR("View bag allocation failed")), fail
);
324 require_quiet(SecRequirementError(aks_bag
, error
, CFSTR("Need aks bag")), fail
);
326 vb
->aks_bag
= CFRetainSafe(aks_bag
);
327 vb
->peers
= CFSetCreateMutableForSOSPeerInfosByID(allocator
);
328 vb
->wrapped_keys
= CFDictionaryCreateMutableForCFTypes(allocator
);
330 CFTransferRetained(result
, vb
);
341 bool SOSBSKBIsDirect(SOSBackupSliceKeyBagRef backupSliceKeyBag
)
343 return 0 == CFSetGetCount(backupSliceKeyBag
->peers
);
346 CFDataRef
SOSBSKBCopyAKSBag(SOSBackupSliceKeyBagRef backupSliceKeyBag
, CFErrorRef
* error
)
348 return CFRetainSafe(backupSliceKeyBag
->aks_bag
);
351 CFSetRef
SOSBSKBGetPeers(SOSBackupSliceKeyBagRef backupSliceKeyBag
){
352 return backupSliceKeyBag
->peers
;
355 static keybag_handle_t
SOSBSKBLoadAndUnlockBagWithSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag
,
356 size_t secretSize
, const uint8_t *secret
,
359 #if !TARGET_HAS_KEYSTORE
360 return bad_keybag_handle
;
362 keybag_handle_t result
= bad_keybag_handle
;
363 keybag_handle_t bag_handle
= bad_keybag_handle
;
365 require_quiet(SecRequirementError(backupSliceKeyBag
->aks_bag
, error
,
366 CFSTR("No aks bag to load")), exit
);
367 require_quiet(SecRequirementError(CFDataGetLength(backupSliceKeyBag
->aks_bag
) < INT_MAX
, error
,
368 CFSTR("No aks bag to load")), exit
);
369 require_quiet(SecRequirementError(secretSize
<= INT_MAX
, error
,
370 CFSTR("secret too big")), 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
);
379 aks_result
= aks_unlock_bag(bag_handle
, secret
, (int) secretSize
);
380 require_quiet(SecKernError(aks_result
, error
,
381 CFSTR("failed to unlock bag: %d"), aks_result
), exit
);
384 bag_handle
= bad_keybag_handle
;
387 if (bag_handle
!= bad_keybag_handle
) {
388 (void) aks_unload_bag(bag_handle
);
395 keybag_handle_t
SOSBSKBLoadAndUnlockWithPeerIDAndSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag
,
396 CFStringRef peerID
, CFDataRef peerSecret
,
399 __block keybag_handle_t result
= bad_keybag_handle
;
401 CFDataRef lookedUpData
= CFDictionaryGetValue(backupSliceKeyBag
->wrapped_keys
, peerID
);
402 require_quiet(SecRequirementError(lookedUpData
!= NULL
, error
, CFSTR("%@ has no wrapped key in %@"), peerID
, backupSliceKeyBag
), exit
);
404 require_quiet(SOSPerformWithDeviceBackupFullKey(SOSGetBackupKeyCurveParameters(), peerSecret
, error
, ^(ccec_full_ctx_t fullKey
) {
405 SOSPerformWithUnwrappedData(fullKey
, lookedUpData
, error
, ^(size_t size
, uint8_t *buffer
) {
406 result
= SOSBSKBLoadAndUnlockBagWithSecret(backupSliceKeyBag
, size
, buffer
, error
);
415 keybag_handle_t
SOSBSKBLoadAndUnlockWithPeerSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag
,
416 SOSPeerInfoRef peer
, CFDataRef peerSecret
,
419 return SOSBSKBLoadAndUnlockWithPeerIDAndSecret(backupSliceKeyBag
, SOSPeerInfoGetPeerID(peer
), peerSecret
, error
);
422 keybag_handle_t
SOSBSKBLoadAndUnlockWithDirectSecret(SOSBackupSliceKeyBagRef backupSliceKeyBag
,
426 keybag_handle_t result
= bad_keybag_handle
;
427 require_quiet(SecRequirementError(SOSBSKBIsDirect(backupSliceKeyBag
), error
, CFSTR("Not direct bag")), exit
);
429 result
= SOSBSKBLoadAndUnlockBagWithSecret(backupSliceKeyBag
,
430 CFDataGetLength(secret
),
431 CFDataGetBytePtr(secret
),