]> git.saurik.com Git - apple/security.git/blob - OSX/sec/ipc/server_entitlement_helpers.c
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / sec / ipc / server_entitlement_helpers.c
1 /*
2 * Copyright (c) 2017 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <pthread/pthread.h>
25
26 #include "server_entitlement_helpers.h"
27
28 #include <Security/SecTask.h>
29 #include <Security/SecTaskPriv.h>
30 #include "ipc/securityd_client.h"
31 #include <Security/SecEntitlements.h>
32 #include "sectask/SystemEntitlements.h"
33 #include <Security/SecItem.h>
34 #include "utilities/SecCFRelease.h"
35 #include "utilities/SecCFWrappers.h"
36 #include "utilities/debugging.h"
37 #include <os/feature_private.h>
38
39 CFStringRef SecTaskCopyStringForEntitlement(SecTaskRef task,
40 CFStringRef entitlement)
41 {
42 CFStringRef value = (CFStringRef)SecTaskCopyValueForEntitlement(task,
43 entitlement, NULL);
44 if (value && CFGetTypeID(value) != CFStringGetTypeID()) {
45 CFReleaseNull(value);
46 }
47
48 return value;
49 }
50
51 CFArrayRef SecTaskCopyArrayOfStringsForEntitlement(SecTaskRef task,
52 CFStringRef entitlement)
53 {
54 CFArrayRef value = (CFArrayRef)SecTaskCopyValueForEntitlement(task,
55 entitlement, NULL);
56 if (value) {
57 if (CFGetTypeID(value) == CFArrayGetTypeID()) {
58 CFIndex ix, count = CFArrayGetCount(value);
59 for (ix = 0; ix < count; ++ix) {
60 CFStringRef string = (CFStringRef)CFArrayGetValueAtIndex(value, ix);
61 if (CFGetTypeID(string) != CFStringGetTypeID()) {
62 CFReleaseNull(value);
63 break;
64 }
65 }
66 } else {
67 CFReleaseNull(value);
68 }
69 }
70
71 return value;
72 }
73
74 CFStringRef SecTaskCopyApplicationIdentifier(SecTaskRef task) {
75 // Catalyst apps may have the iOS style application identifier.
76 CFStringRef result = SecTaskCopyStringForEntitlement(task,
77 kSecEntitlementBasicApplicationIdentifier);
78 if (!result) {
79 result = SecTaskCopyStringForEntitlement(task,
80 kSecEntitlementAppleApplicationIdentifier);
81 }
82 return result;
83 }
84
85 #if TARGET_OS_IOS
86 CFArrayRef SecTaskCopySharedWebCredentialDomains(SecTaskRef task) {
87 return SecTaskCopyArrayOfStringsForEntitlement(task,
88 kSecEntitlementAssociatedDomains);
89 }
90 #endif
91
92 CFArrayRef SecTaskCopyAccessGroups(SecTaskRef task)
93 {
94 CFMutableArrayRef groups = NULL;
95
96 bool onDemandInstallable = SecTaskGetBooleanValueForEntitlement(task, kSystemEntitlementOnDemandInstallCapable);
97
98 CFArrayRef keychainAccessGroups, appleSecurityApplicationGroups;
99 CFStringRef appID;
100 CFArrayRef associatedAppIDs;
101
102 keychainAccessGroups = SecTaskCopyArrayOfStringsForEntitlement(task, kSecEntitlementKeychainAccessGroups);
103 appleSecurityApplicationGroups = SecTaskCopyArrayOfStringsForEntitlement(task, kSecEntitlementAppleSecurityApplicationGroups);
104 appID = SecTaskCopyApplicationIdentifier(task);
105 // Catalyst apps (may?) have this entitlement.
106 associatedAppIDs = SecTaskCopyArrayOfStringsForEntitlement(task, kSecEntitlementAssociatedApplicationIdentifier);
107
108 groups = CFArrayCreateMutableForCFTypes(NULL);
109
110 if (keychainAccessGroups) {
111 CFArrayAppendArray(groups, keychainAccessGroups, CFRangeMake(0, CFArrayGetCount(keychainAccessGroups)));
112 }
113
114 #if TARGET_OS_OSX
115 const bool entitlementsValidated = SecTaskEntitlementsValidated(task);
116 #else
117 const bool entitlementsValidated = true;
118 #endif
119
120 if (entitlementsValidated) {
121 // If app-id or k-a-g are present but binary is not validated, just honor k-a-g.
122 // Because AMFI would not allow client to run if it would have k-a-g entitlement
123 // and not being properly signed. Assoc-app-id behaves similarly.
124 if (associatedAppIDs) {
125 CFArrayAppendAll(groups, associatedAppIDs);
126 }
127 if (appID) {
128 CFArrayAppendValue(groups, appID);
129 }
130 if (appleSecurityApplicationGroups) {
131 if (onDemandInstallable) {
132 // This is perfectly legal for other functionality but not for keychain use
133 secnotice("entitlements", "Ignoring \"%@\" because client is API-restricted", kSecEntitlementAppleSecurityApplicationGroups);
134 } else {
135 CFArrayAppendArray(groups, appleSecurityApplicationGroups, CFRangeMake(0, CFArrayGetCount(appleSecurityApplicationGroups)));
136 }
137 }
138 } else {
139 // Try to provide some hopefully helpful diagnostics for common failure cases.
140 if (CFArrayGetCount(groups) == 0) {
141 if (appID) {
142 secwarning("Entitlement %@=%@ is ignored because of invalid application signature or incorrect provisioning profile",
143 kSecEntitlementApplicationIdentifier, appID);
144 }
145 if (appleSecurityApplicationGroups) {
146 secwarning("Entitlement %@=%@ is ignored because of invalid application signature or incorrect provisioning profile",
147 kSecEntitlementAppleSecurityApplicationGroups, appleSecurityApplicationGroups);
148 }
149 }
150 }
151
152 // Do not allow to explicitly specify com.apple.token if token support is not allowed by feature flags.
153 CFIndex index = CFArrayGetFirstIndexOfValue(groups, CFRangeMake(0, CFArrayGetCount(groups)), kSecAttrAccessGroupToken);
154 if (index != kCFNotFound) {
155 if (os_feature_enabled(CryptoTokenKit, UseTokens)) {
156 // Make sure that com.apple.token is last one. This is because it is always read-only group and therefore updating keychain
157 // operations without explicitly set kSecAttrAccessGroup attribute would always fail.
158 CFArrayRemoveValueAtIndex(groups, index);
159 CFArrayAppendValue(groups, kSecAttrAccessGroupToken);
160 } else {
161 secwarning("Keychain access group com.apple.token ignored, feature not available");
162 CFArrayRemoveValueAtIndex(groups, index);
163 }
164 }
165
166 #if TARGET_OS_OSX
167 /*
168 * We would like to add implicit token access group always, but we avoid doing that in case that application
169 * clearly intended to use non-smartcard functionality of keychain but messed up signing or provisioning. In this case,
170 * we want to return -34018 (errSecMissingEntitlements) to help diagnosing the issue for the app authors and adding
171 * implicit token access group would instead result in errSecItemNotFound.
172 */
173 bool entitlementsFailure = (CFArrayGetCount(groups) == 0 && appID != NULL);
174 if (!entitlementsFailure) {
175 bool addTokenGroup = os_feature_enabled(CryptoTokenKit, UseTokens);
176 if (addTokenGroup && !CFArrayContainsValue(groups, CFRangeMake(0, CFArrayGetCount(groups)), kSecAttrAccessGroupToken)) {
177 CFArrayAppendValue(groups, kSecAttrAccessGroupToken);
178 }
179 }
180 #endif
181
182 CFReleaseNull(associatedAppIDs);
183 CFReleaseNull(appID);
184 CFReleaseNull(keychainAccessGroups);
185 CFReleaseNull(appleSecurityApplicationGroups);
186
187 return groups;
188 }
189
190 bool
191 SecTaskGetBooleanValueForEntitlement(SecTaskRef task, CFStringRef entitlement)
192 {
193 CFTypeRef value = SecTaskCopyValueForEntitlement(task, entitlement, NULL);
194 bool ok = false;
195
196 if (value && CFBooleanGetTypeID() == CFGetTypeID(value)) {
197 ok = CFBooleanGetValue(value);
198 }
199 CFReleaseNull(value);
200 return ok;
201 }