]> git.saurik.com Git - apple/security.git/blob - keychain/securityd/SecItemServer+SWC.m
Security-59754.80.3.tar.gz
[apple/security.git] / keychain / securityd / SecItemServer+SWC.m
1 /*
2 * Copyright (c) 2007-2019 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 #import "SecItemServer+SWC.h"
25
26 #if TARGET_OS_IOS && !TARGET_OS_BRIDGE
27 #import <SharedWebCredentials/SharedWebCredentials.h>
28
29 #import "utilities/debugging.h"
30 #import "utilities/SecCFError.h"
31
32 // Methods in this category are here temporarily until I can add SPI in
33 // _SWCServiceSpecifier for the function below to consume.
34 @interface NSObject (Workaround61065225)
35 - (NSString *)domainHost;
36 @end
37
38 SecSWCFlags _SecAppDomainApprovalStatus(CFStringRef appID, CFStringRef fqdn, CFErrorRef *error)
39 {
40 __block SecSWCFlags flags = kSecSWCFlags_None;
41
42 @autoreleasepool {
43 secnotice("swc", "Application %@ is requesting approval for %@", appID, fqdn);
44
45 _SWCServiceSpecifier *specifier = [[_SWCServiceSpecifier alloc] initWithServiceType:_SWCServiceTypeWebCredentials
46 applicationIdentifier:(__bridge NSString *)appID
47 domain:(__bridge NSString *)fqdn];
48 NSError *err = nil;
49 NSArray<_SWCServiceDetails *> *allDetails = [_SWCServiceDetails serviceDetailsWithServiceSpecifier:specifier error:&err];
50 if (allDetails) {
51 _SWCServiceDetails *details = allDetails.firstObject;
52 if (details) {
53 switch (details.userApprovalState) {
54 case SWCServiceApprovalStateApproved:
55 flags |= kSecSWCFlag_UserApproved;
56 break;
57
58 case SWCServiceApprovalStateDenied:
59 flags |= kSecSWCFlag_UserDenied;
60 break;
61
62 default:
63 break;
64 }
65 switch (details.siteApprovalState) {
66 case SWCServiceApprovalStateApproved:
67 flags |= kSecSWCFlag_SiteApproved;
68 break;
69
70 case SWCServiceApprovalStateDenied:
71 flags |= kSecSWCFlag_SiteDenied;
72 break;
73
74 default:
75 break;
76 }
77 }
78
79 } else {
80 // An error occurred.
81 secerror("+[_SWCServiceDetails serviceDetailsWithServiceSpecifier:error:] failed with %@", err);
82 }
83 }
84
85 if (error) {
86 if (!(flags & kSecSWCFlag_SiteApproved)) {
87 SecError(errSecAuthFailed, error, CFSTR("\"%@\" failed to approve \"%@\""), fqdn, appID);
88 } else if (flags & kSecSWCFlag_UserDenied) {
89 SecError(errSecAuthFailed, error, CFSTR("User denied access to \"%@\" by \"%@\""), fqdn, appID);
90 }
91 }
92
93 return flags;
94 }
95
96 void _SecSetAppDomainApprovalStatus(CFStringRef appID, CFStringRef fqdn, CFBooleanRef approved)
97 {
98 _SWCServiceSpecifier *specifier = [[_SWCServiceSpecifier alloc] initWithServiceType:_SWCServiceTypeWebCredentials
99 applicationIdentifier:(__bridge NSString *)appID
100 domain:(__bridge NSString *)fqdn];
101 NSError *err = nil;
102 NSArray<_SWCServiceDetails *> *allDetails = [_SWCServiceDetails serviceDetailsWithServiceSpecifier:specifier error:&err];
103 if (allDetails) {
104 _SWCServiceDetails *details = allDetails.firstObject;
105 if (details) {
106 SWCServiceApprovalState state = SWCServiceApprovalStateUnspecified;
107 if (approved == kCFBooleanTrue) {
108 state = SWCServiceApprovalStateApproved;
109 } else if (approved == kCFBooleanFalse) {
110 state = SWCServiceApprovalStateDenied;
111 }
112 if (![details setUserApprovalState:state error:&err]) {
113 secerror("-[_SWCServiceDetails setUserApprovalState:error:] failed with %@", err);
114 }
115 }
116
117 } else {
118 secerror("+[_SWCServiceDetails serviceDetailsWithServiceSpecifier:error:] failed with %@", err);
119 }
120 }
121
122 CFTypeRef _SecCopyFQDNObjectFromString(CFStringRef entitlementValue)
123 {
124 CFTypeRef result = NULL;
125
126 @autoreleasepool {
127 _SWCServiceSpecifier *serviceSpecifier = [_SWCServiceSpecifier serviceSpecifiersWithEntitlementValue:@[ (__bridge NSString *)entitlementValue ] error:NULL].firstObject;
128 if (!serviceSpecifier) {
129 serviceSpecifier = [[_SWCServiceSpecifier alloc] initWithServiceType:nil applicationIdentifier:nil domain:(__bridge NSString *)entitlementValue];
130 }
131 if (serviceSpecifier) {
132 // Hiding an ObjC reference in a CFTypeRef since the caller is pure C.
133 result = CFBridgingRetain(serviceSpecifier);
134 }
135 }
136
137 return result;
138 }
139
140 CFStringRef _SecGetFQDNFromFQDNObject(CFTypeRef fqdnObject, SInt32 *outPort)
141 {
142 CFStringRef result = NULL;
143 SInt32 port = -1;
144
145 // Extracting an ObjC reference from a CFTypeRef since the caller is pure C.
146 _SWCServiceSpecifier *serviceSpecifier = (__bridge _SWCServiceSpecifier *)fqdnObject;
147 result = (__bridge CFStringRef)serviceSpecifier.domainHost;
148 if (outPort) {
149 NSNumber *portNumber = serviceSpecifier.domainPort;
150 if (portNumber) {
151 port = portNumber.unsignedShortValue;
152 }
153
154 *outPort = port;
155 }
156
157 return result;
158 }
159
160 #if !TARGET_OS_SIMULATOR
161 bool _SecEntitlementContainsDomainForService(CFArrayRef domains, CFStringRef domain, SInt32 port)
162 {
163 bool result = false;
164
165 @autoreleasepool {
166 NSArray<_SWCServiceSpecifier *> *serviceSpecifiers;
167 serviceSpecifiers = [_SWCServiceSpecifier serviceSpecifiersWithEntitlementValue:(__bridge NSArray<NSString *> *)domains
168 serviceType:_SWCServiceTypeWebCredentials
169 error:NULL];
170 for (_SWCServiceSpecifier *serviceSpecifier in serviceSpecifiers) {
171 // Check if the hostname matches.
172 NSString *specifierDomain = [serviceSpecifier domainHost];
173 if (NSOrderedSame == [specifierDomain caseInsensitiveCompare:(__bridge NSString *)domain]) {
174 result = true;
175
176 // Also check the port if specified by the caller.
177 if (result && port >= 0) {
178 NSNumber *specifierPort = serviceSpecifier.domainPort;
179 result = [specifierPort isEqualToNumber:@(port)];
180 }
181
182 if (result) {
183 break;
184 }
185 }
186 }
187 }
188
189 return result;
190 }
191 #endif /* !TARGET_OS_SIMULATOR */
192 #endif // TARGET_OS_IOS && !TARGET_OS_BRIDGE