]> git.saurik.com Git - apple/security.git/blob - OSX/sec/ipc/server_entitlement_helpers.c
Security-59306.101.1.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 <Security/SecItem.h>
33 #include "utilities/SecCFRelease.h"
34 #include "utilities/SecCFWrappers.h"
35 #include "utilities/debugging.h"
36
37 CFStringRef SecTaskCopyStringForEntitlement(SecTaskRef task,
38 CFStringRef entitlement)
39 {
40 CFStringRef value = (CFStringRef)SecTaskCopyValueForEntitlement(task,
41 entitlement, NULL);
42 if (value && CFGetTypeID(value) != CFStringGetTypeID()) {
43 CFReleaseNull(value);
44 }
45
46 return value;
47 }
48
49 CFArrayRef SecTaskCopyArrayOfStringsForEntitlement(SecTaskRef task,
50 CFStringRef entitlement)
51 {
52 CFArrayRef value = (CFArrayRef)SecTaskCopyValueForEntitlement(task,
53 entitlement, NULL);
54 if (value) {
55 if (CFGetTypeID(value) == CFArrayGetTypeID()) {
56 CFIndex ix, count = CFArrayGetCount(value);
57 for (ix = 0; ix < count; ++ix) {
58 CFStringRef string = (CFStringRef)CFArrayGetValueAtIndex(value, ix);
59 if (CFGetTypeID(string) != CFStringGetTypeID()) {
60 CFReleaseNull(value);
61 break;
62 }
63 }
64 } else {
65 CFReleaseNull(value);
66 }
67 }
68
69 return value;
70 }
71
72 CFStringRef SecTaskCopyApplicationIdentifier(SecTaskRef task) {
73 return SecTaskCopyStringForEntitlement(task,
74 kSecEntitlementApplicationIdentifier);
75 }
76
77 #if TARGET_OS_IOS
78 CFArrayRef SecTaskCopySharedWebCredentialDomains(SecTaskRef task) {
79 return SecTaskCopyArrayOfStringsForEntitlement(task,
80 kSecEntitlementAssociatedDomains);
81 }
82 #endif
83
84 CFArrayRef SecTaskCopyAccessGroups(SecTaskRef task)
85 {
86 CFMutableArrayRef groups = NULL;
87
88 CFArrayRef keychainAccessGroups, appleSecurityApplicationGroups;
89 CFStringRef appID;
90 CFArrayRef associatedAppIDs;
91
92 keychainAccessGroups = SecTaskCopyArrayOfStringsForEntitlement(task, kSecEntitlementKeychainAccessGroups);
93 appleSecurityApplicationGroups = SecTaskCopyArrayOfStringsForEntitlement(task, kSecEntitlementAppleSecurityApplicationGroups);
94 appID = SecTaskCopyApplicationIdentifier(task);
95 // Marzipan apps (may?) have this entitlement.
96 associatedAppIDs = SecTaskCopyArrayOfStringsForEntitlement(task, kSecEntitlementAssociatedApplicationIdentifier);
97
98 groups = CFArrayCreateMutableForCFTypes(NULL);
99
100 if (keychainAccessGroups) {
101 CFArrayAppendArray(groups, keychainAccessGroups, CFRangeMake(0, CFArrayGetCount(keychainAccessGroups)));
102 }
103
104 #if TARGET_OS_OSX
105 const bool entitlementsValidated = SecTaskEntitlementsValidated(task);
106 #else
107 const bool entitlementsValidated = true;
108 #endif
109
110 if (entitlementsValidated) {
111 // If app-id or k-a-g are present but binary is not validated, just honor k-a-g.
112 // Because AMFI would not allow client to run if it would have k-a-g entitlement
113 // and not being properly signed. Assoc-app-id behaves similarly.
114 if (associatedAppIDs) {
115 CFArrayAppendAll(groups, associatedAppIDs);
116 }
117 if (appID) {
118 CFArrayAppendValue(groups, appID);
119 }
120 if (appleSecurityApplicationGroups) {
121 CFArrayAppendArray(groups, appleSecurityApplicationGroups, CFRangeMake(0, CFArrayGetCount(appleSecurityApplicationGroups)));
122 }
123 } else {
124 // Try to provide some hopefully helpful diagnostics for common failure cases.
125 if (CFArrayGetCount(groups) == 0) {
126 if (appID) {
127 secwarning("Entitlement %@=%@ is ignored because of invalid application signature or incorrect provisioning profile",
128 kSecEntitlementApplicationIdentifier, appID);
129 }
130 if (appleSecurityApplicationGroups) {
131 secwarning("Entitlement %@=%@ is ignored because of invalid application signature or incorrect provisioning profile",
132 kSecEntitlementAppleSecurityApplicationGroups, appleSecurityApplicationGroups);
133 }
134 }
135 }
136
137 /*
138 * We would like to add implicit token access group always, but we avoid doing that in case that application
139 * clearly intended to use non-smartcard functionality of keychain but messed up signing or provisioning. In this case,
140 * we want to return -34018 (errSecMissingEntitlements) to help diagnosing the issue for the app authors and adding
141 * implicit token access group would instead result in errSecItemNotFound.
142 */
143 bool entitlementsFailure = (CFArrayGetCount(groups) == 0 && appID != NULL);
144 if (!entitlementsFailure) {
145 CFArrayAppendValue(groups, kSecAttrAccessGroupToken);
146 }
147
148 CFReleaseNull(associatedAppIDs);
149 CFReleaseNull(appID);
150 CFReleaseNull(keychainAccessGroups);
151 CFReleaseNull(appleSecurityApplicationGroups);
152
153 return groups;
154 }
155
156 bool
157 SecTaskGetBooleanValueForEntitlement(SecTaskRef task, CFStringRef entitlement)
158 {
159 CFTypeRef value = SecTaskCopyValueForEntitlement(task, entitlement, NULL);
160 bool ok = false;
161
162 if (value && CFBooleanGetTypeID() == CFGetTypeID(value)) {
163 ok = CFBooleanGetValue(value);
164 }
165 CFReleaseNull(value);
166 return ok;
167 }