2  * Copyright (c) 2008-2009,2012,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@ 
  26 #include "access_utils.h" 
  27 #include "security_tool.h" 
  29 #include <Security/SecKeychainItem.h> 
  30 #include <Security/SecAccess.h> 
  31 #include <Security/SecACL.h> 
  35 // This function creates a SecAccessRef with an array of trusted applications. 
  38 create_access(const char *accessName
, Boolean allowAny
, CFArrayRef trustedApps
, SecAccessRef 
*access
) 
  41         CFArrayRef appList 
= NULL
; 
  42         CFArrayRef aclList 
= NULL
; 
  43         CFStringRef description 
= NULL
; 
  44         const char *descriptionLabel 
= (accessName
) ? accessName 
: "<unlabeled key>"; 
  45         CFStringRef promptDescription 
= NULL
; 
  46         CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector
; 
  51                 description 
= CFStringCreateWithCString(NULL
, descriptionLabel
, kCFStringEncodingUTF8
); 
  54         status 
= SecAccessCreate(description
, trustedApps
, access
); 
  57                 sec_perror("SecAccessCreate", status
); 
  62         // get the access control list for decryption operations (this controls access to an item's data) 
  63         status 
= SecAccessCopySelectedACLList(*access
, CSSM_ACL_AUTHORIZATION_DECRYPT
, &aclList
); 
  66                 sec_perror("SecAccessCopySelectedACLList", status
); 
  71         // get the first entry in the access control list 
  72         aclRef 
= (SecACLRef
)CFArrayGetValueAtIndex(aclList
, 0); 
  73         status 
= SecACLCopySimpleContents(aclRef
, &appList
, &promptDescription
, &promptSelector
); 
  76                 sec_perror("SecACLCopySimpleContents", status
); 
  81         if (allowAny
) // "allow all applications to access this item" 
  83                 // change the decryption ACL to not require the passphrase, and have a nil application list. 
  84                 promptSelector
.flags 
&= ~CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE
; 
  85                 status 
= SecACLSetSimpleContents(aclRef
, NULL
, promptDescription
, &promptSelector
); 
  87         else // "allow access by these applications" 
  89                 // modify the application list 
  90                 status 
= SecACLSetSimpleContents(aclRef
, trustedApps
, promptDescription
, &promptSelector
); 
  94                 sec_perror("SecACLSetSimpleContents", status
); 
 101                 CFRelease(description
); 
 102         if (promptDescription
) 
 103                 CFRelease(promptDescription
); 
 114 // This function merges the contents of otherAccess into access. 
 115 // Simple ACL contents are assumed, and only the standard ACL 
 116 // for decryption operations is currently processed. 
 119 merge_access(SecAccessRef access
, SecAccessRef otherAccess
) 
 122         CFArrayRef aclList
, newAclList
; 
 124         // get existing access control list for decryption operations (this controls access to an item's data) 
 125         status 
= SecAccessCopySelectedACLList(access
, CSSM_ACL_AUTHORIZATION_DECRYPT
, &aclList
); 
 129         // get desired access control list for decryption operations 
 130         status 
= SecAccessCopySelectedACLList(otherAccess
, CSSM_ACL_AUTHORIZATION_DECRYPT
, &newAclList
); 
 134                 SecACLRef aclRef
=(SecACLRef
)CFArrayGetValueAtIndex(aclList
, 0); 
 135                 SecACLRef newAclRef
=(SecACLRef
)CFArrayGetValueAtIndex(newAclList
, 0); 
 136                 CFArrayRef appList
=nil
; 
 137                 CFArrayRef newAppList
=nil
; 
 138                 CFMutableArrayRef mergedAppList 
= nil
; 
 139                 CFStringRef promptDescription
=nil
; 
 140                 CFStringRef newPromptDescription
=nil
; 
 141                 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector
; 
 142                 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR newPromptSelector
; 
 144                 status 
= SecACLCopySimpleContents(aclRef
, &appList
, &promptDescription
, &promptSelector
); 
 146                         status 
= SecACLCopySimpleContents(newAclRef
, &newAppList
, &newPromptDescription
, &newPromptSelector
); 
 150                                 mergedAppList 
= CFArrayCreateMutableCopy(NULL
, 0, appList
); 
 154                                         CFArrayAppendArray(mergedAppList
, newAppList
, CFRangeMake(0, CFArrayGetCount(newAppList
))); 
 156                                         mergedAppList 
= CFArrayCreateMutableCopy(NULL
, 0, newAppList
); 
 159                         promptSelector
.flags 
= newPromptSelector
.flags
; 
 160                         status 
= SecACLSetSimpleContents(aclRef
, mergedAppList
, newPromptDescription
, &newPromptSelector
); 
 163                 if (appList
) CFRelease(appList
); 
 164                 if (newAppList
) CFRelease(newAppList
); 
 165                 if (mergedAppList
) CFRelease(mergedAppList
); 
 166                 if (promptDescription
) CFRelease(promptDescription
); 
 167                 if (newPromptDescription
) CFRelease(newPromptDescription
); 
 169         if (aclList
) CFRelease(aclList
); 
 170         if (newAclList
) CFRelease(newAclList
); 
 177 // This function updates the access for an existing item. 
 178 // The provided access is merged with the item's existing access. 
 181 modify_access(SecKeychainItemRef itemRef
, SecAccessRef access
) 
 184         SecAccessRef curAccess 
= NULL
; 
 185         // for historical reasons, we have to modify the item's existing access reference 
 186         // (setting the item's access to a freshly created SecAccessRef instance doesn't behave as expected) 
 187         status 
= SecKeychainItemCopyAccess(itemRef
, &curAccess
); 
 189                 sec_error("SecKeychainItemCopyAccess: %s", sec_errstr(status
)); 
 191                 status 
= merge_access(curAccess
, access
); // make changes to the existing access reference 
 193                         status 
= SecKeychainItemSetAccess(itemRef
, curAccess
); // will prompt! 
 195                                 sec_error("SecKeychainItemSetAccess: %s", sec_errstr(status
)); 
 200                 CFRelease(curAccess
);