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
),