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