2  * Copyright (c) 2013-2014 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@ 
  29 #include <utilities/SecAKSWrappers.h> 
  30 #include <utilities/SecCFWrappers.h> 
  31 #include <utilities/SecCFError.h> 
  33 #if TARGET_IPHONE_SIMULATOR 
  34 #  define change_notification "com.apple.will.never.happen" 
  35 #elif TARGET_OS_IPHONE 
  36 #  include <MobileKeyBag/MobileKeyBag.h> 
  37 #  define change_notification kMobileKeyBagLockStatusNotificationID 
  39 #  include <AppleKeyStoreEvents.h> 
  40 #  define change_notification kAppleKeyStoreLockStatusNotificationID 
  42 #  error "unsupported target platform" 
  45 const char * const kUserKeybagStateChangeNotification 
= change_notification
; 
  47 bool SecAKSDoWhileUserBagLocked(CFErrorRef 
*error
, dispatch_block_t action
) 
  49 #if !TARGET_HAS_KEYSTORE 
  53     // Acquire lock assertion, ref count? 
  55     __block kern_return_t status 
= kIOReturnSuccess
; 
  56     static dispatch_once_t queue_once
; 
  57     static dispatch_queue_t assertion_queue
; 
  59 #if TARGET_OS_MAC && !TARGET_OS_EMBEDDED                            // OS X 
  60     keybag_handle_t keybagHandle 
= session_keybag_handle
; 
  61 #else                                                               // iOS, but not simulator 
  62     keybag_handle_t keybagHandle 
= device_keybag_handle
; 
  64     AKSAssertionType_t lockAssertType 
= kAKSAssertTypeOther
; 
  66     dispatch_once(&queue_once
, ^{ 
  67         assertion_queue 
= dispatch_queue_create("AKS Lock Assertion Queue", NULL
); 
  70     static uint32_t count 
= 0; 
  72     dispatch_sync(assertion_queue
, ^{ 
  74             uint64_t timeout 
= 60ull; 
  75             secnotice("lockassertions", "Requesting lock assertion for %lld seconds", timeout
); 
  76             status 
= aks_assert_hold(keybagHandle
, lockAssertType
, timeout
); 
  79         if (status 
== kIOReturnSuccess
) 
  83     if (status 
== kIOReturnSuccess
) { 
  85         dispatch_sync(assertion_queue
, ^{ 
  86             if (count 
&& (--count 
== 0)) { 
  87                 secnotice("lockassertions", "Dropping lock assertion"); 
  88                 status 
= aks_assert_drop(keybagHandle
, lockAssertType
); 
  92     return SecKernError(status
, error
, CFSTR("Kern return error")); 
  93 #endif  /* !TARGET_HAS_KEYSTORE */ 
  96 CFDataRef 
SecAKSCopyBackupBagWithSecret(size_t size
, uint8_t *secret
, CFErrorRef 
*error
) { 
  97 #if !TARGET_HAS_KEYSTORE 
 100     CFDataRef result 
= NULL
; 
 101     void *keybagBytes 
= NULL
; 
 104     keybag_handle_t backupKeybagHandle 
= -1; 
 107     require_quiet(SecRequirementError(0 <= size 
&& size 
<= INT_MAX
, error
, CFSTR("Invalid size: %zu"), size
), fail
); 
 109     ret 
= aks_create_bag(secret
, (int) size
, kAppleKeyStoreAsymmetricBackupBag
, &backupKeybagHandle
); 
 111     require_quiet(SecKernError(ret
, error
, CFSTR("bag allocation failed: %d"), ret
), fail
); 
 113     ret 
= aks_save_bag(backupKeybagHandle
, &keybagBytes
, &keybagSize
); 
 115     require_quiet(SecKernError(ret
, error
, CFSTR("save bag failed: %d"), ret
), fail
); 
 117     ret 
= aks_unload_bag(backupKeybagHandle
); 
 119     if (ret 
!= KERN_SUCCESS
) { 
 120         secerror("unload bag failed: %d", ret
); 
 123     result 
= CFDataCreate(kCFAllocatorDefault
, keybagBytes
, keybagSize
); 
 125     require_quiet(SecAllocationError(result
, error
, CFSTR("Bag CFData Allocation Failed")), fail
);