]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecSharedCredential.c
Security-59754.41.1.tar.gz
[apple/security.git] / OSX / sec / Security / SecSharedCredential.c
1 /*
2 * Copyright (c) 2014-2020 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 * SecSharedCredential.c - CoreFoundation-based functions to store and retrieve shared credentials.
24 *
25 */
26
27
28 #include <Security/SecSharedCredential.h>
29 #include <Security/SecBasePriv.h>
30 #include <utilities/SecCFError.h>
31 #include <utilities/SecCFWrappers.h>
32 #include "SecItemInternal.h"
33 #include <ipc/securityd_client.h>
34 #include "SecPasswordGenerate.h"
35
36 /* forward declarations */
37 OSStatus SecAddSharedWebCredentialSync(CFStringRef fqdn, CFStringRef account, CFStringRef password, CFErrorRef *error);
38 OSStatus SecCopySharedWebCredentialSync(CFStringRef fqdn, CFStringRef account, CFArrayRef *credentials, CFErrorRef *error);
39 #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
40 OSStatus SecCopySharedWebCredentialSyncUsingAuthSvcs(CFStringRef fqdn, CFStringRef account, CFArrayRef *credentials, CFErrorRef *error);
41 #endif
42
43 #if SHAREDWEBCREDENTIALS
44
45 // OSX now has SWC enabled, but cannot link SharedWebCredentials framework: rdar://59958701
46 #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
47
48 OSStatus SecAddSharedWebCredentialSync(CFStringRef fqdn,
49 CFStringRef account,
50 CFStringRef password,
51 CFErrorRef *error)
52 {
53 OSStatus status = errSecUnimplemented;
54 if (error) {
55 SecError(status, error, CFSTR("SecAddSharedWebCredentialSync not supported on this platform"));
56 }
57 return status;
58 }
59
60 #else
61
62 OSStatus SecAddSharedWebCredentialSync(CFStringRef fqdn,
63 CFStringRef account,
64 CFStringRef password,
65 CFErrorRef *error)
66 {
67 OSStatus status;
68 __block CFErrorRef* outError = error;
69 __block CFMutableDictionaryRef args = CFDictionaryCreateMutable(kCFAllocatorDefault,
70 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
71 if (fqdn) {
72 CFDictionaryAddValue(args, kSecAttrServer, fqdn);
73 }
74 if (account) {
75 CFDictionaryAddValue(args, kSecAttrAccount, account);
76 }
77 if (password) {
78 CFDictionaryAddValue(args, kSecSharedPassword, password);
79 }
80 status = SecOSStatusWith(^bool (CFErrorRef *error) {
81 CFTypeRef raw_result = NULL;
82 bool xpc_result = false;
83 bool internal_spi = false; // TODO: support this for SecurityDevTests
84 if(internal_spi && gSecurityd && gSecurityd->sec_add_shared_web_credential) {
85 xpc_result = gSecurityd->sec_add_shared_web_credential(args, NULL, NULL, NULL, SecAccessGroupsGetCurrent(), &raw_result, error);
86 } else {
87 xpc_result = cftype_client_to_bool_cftype_error_request(sec_add_shared_web_credential_id, args, SecSecurityClientGet(), &raw_result, error);
88 }
89 CFReleaseSafe(args);
90 if (!xpc_result) {
91 if (NULL == *error) {
92 SecError(errSecInternal, error, CFSTR("Internal error (XPC failure)"));
93 }
94 }
95 if (outError) {
96 *outError = (error) ? *error : NULL;
97 CFRetainSafe(*outError);
98 } else {
99 CFReleaseNull(*error);
100 }
101 CFReleaseNull(raw_result);
102 return xpc_result;
103 });
104
105 return status;
106 }
107 #endif /* !TARGET_OS_OSX || !TARGET_OS_MACCATALYST */
108 #endif /* SHAREDWEBCREDENTIALS */
109
110 void SecAddSharedWebCredential(CFStringRef fqdn,
111 CFStringRef account,
112 CFStringRef password,
113 void (^completionHandler)(CFErrorRef error))
114 {
115 __block CFErrorRef error = NULL;
116 __block dispatch_queue_t dst_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
117 #if SHAREDWEBCREDENTIALS
118
119 /* sanity check input arguments */
120 CFStringRef errStr = NULL;
121 if (!fqdn || CFGetTypeID(fqdn) != CFStringGetTypeID() || !CFStringGetLength(fqdn) ||
122 !account || CFGetTypeID(account) != CFStringGetTypeID() || !CFStringGetLength(account) ) {
123 errStr = CFSTR("fqdn or account was not of type CFString, or not provided");
124 }
125 else if (password && CFGetTypeID(password) != CFStringGetTypeID()) {
126 errStr = CFSTR("non-nil password was not of type CFString");
127 }
128 if (errStr) {
129 SecError(errSecParam, &error, CFSTR("%@"), errStr);
130 dispatch_async(dst_queue, ^{
131 if (completionHandler) {
132 completionHandler(error);
133 }
134 CFReleaseSafe(error);
135 });
136 return;
137 }
138
139 __block CFStringRef serverStr = CFRetainSafe(fqdn);
140 __block CFStringRef accountStr = CFRetainSafe(account);
141 __block CFStringRef passwordStr = CFRetainSafe(password);
142
143 dispatch_async(dst_queue, ^{
144 OSStatus status = SecAddSharedWebCredentialSync(serverStr, accountStr, passwordStr, &error);
145 CFReleaseSafe(serverStr);
146 CFReleaseSafe(accountStr);
147 CFReleaseSafe(passwordStr);
148
149 if (status && !error) {
150 SecError(status, &error, CFSTR("Error adding shared password"));
151 }
152 dispatch_async(dst_queue, ^{
153 if (completionHandler) {
154 completionHandler(error);
155 }
156 CFReleaseSafe(error);
157 });
158 });
159 #else
160 SecError(errSecParam, &error, CFSTR("SharedWebCredentials not supported on this platform"));
161 dispatch_async(dst_queue, ^{
162 if (completionHandler) {
163 completionHandler(error);
164 }
165 CFReleaseSafe(error);
166 });
167 #endif
168 }
169
170 #if SHAREDWEBCREDENTIALS
171
172 #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
173
174 OSStatus SecCopySharedWebCredentialSync(CFStringRef fqdn,
175 CFStringRef account,
176 CFArrayRef *credentials,
177 CFErrorRef *error)
178 {
179 OSStatus status = errSecUnimplemented;
180 if (error) {
181 SecError(status, error, CFSTR("SecCopySharedWebCredentialSync not supported on this platform"));
182 }
183 return status;
184 }
185
186 #else
187
188 OSStatus SecCopySharedWebCredentialSync(CFStringRef fqdn,
189 CFStringRef account,
190 CFArrayRef *credentials,
191 CFErrorRef *error)
192 {
193 OSStatus status;
194 __block CFErrorRef* outError = error;
195 __block CFMutableDictionaryRef args = CFDictionaryCreateMutable(kCFAllocatorDefault,
196 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
197 if (fqdn) {
198 CFDictionaryAddValue(args, kSecAttrServer, fqdn);
199 }
200 if (account) {
201 CFDictionaryAddValue(args, kSecAttrAccount, account);
202 }
203 status = SecOSStatusWith(^bool (CFErrorRef *error) {
204 CFTypeRef raw_result = NULL;
205 bool xpc_result = false;
206 bool internal_spi = false; // TODO: support this for SecurityDevTests
207 if(internal_spi && gSecurityd && gSecurityd->sec_copy_shared_web_credential) {
208 xpc_result = gSecurityd->sec_copy_shared_web_credential(args, NULL, NULL, NULL, SecAccessGroupsGetCurrent(), &raw_result, error);
209 } else {
210 xpc_result = cftype_client_to_bool_cftype_error_request(sec_copy_shared_web_credential_id, args, SecSecurityClientGet(), &raw_result, error);
211 }
212 CFReleaseSafe(args);
213 if (!xpc_result) {
214 if (NULL == *error) {
215 SecError(errSecInternal, error, CFSTR("Internal error (XPC failure)"));
216 }
217 }
218 if (outError) {
219 *outError = (error) ? *error : NULL;
220 CFRetainSafe(*outError);
221 } else {
222 CFReleaseNull(*error);
223 }
224 if (!raw_result) {
225 raw_result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
226 }
227 *credentials = raw_result;
228 return xpc_result;
229 });
230
231 return status;
232 }
233 #endif /* !TARGET_OS_OSX || !TARGET_OS_MACCATALYST */
234 #endif /* SHAREDWEBCREDENTIALS */
235
236 void SecRequestSharedWebCredential(CFStringRef fqdn,
237 CFStringRef account,
238 void (^completionHandler)(CFArrayRef credentials, CFErrorRef error))
239 {
240 __block CFErrorRef error = NULL;
241 __block dispatch_queue_t dst_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
242 #if SHAREDWEBCREDENTIALS
243 __block CFArrayRef result = NULL;
244
245 /* sanity check input arguments, if provided */
246 CFStringRef errStr = NULL;
247 if (fqdn && (CFGetTypeID(fqdn) != CFStringGetTypeID() || !CFStringGetLength(fqdn))) {
248 errStr = CFSTR("fqdn was empty or not a CFString");
249 }
250 else if (account && (CFGetTypeID(account) != CFStringGetTypeID() || !CFStringGetLength(account))) {
251 errStr = CFSTR("account was empty or not a CFString");
252 }
253 if (errStr) {
254 SecError(errSecParam, &error, CFSTR("%@"), errStr);
255 dispatch_async(dst_queue, ^{
256 if (completionHandler) {
257 completionHandler(result, error);
258 }
259 CFReleaseSafe(error);
260 CFReleaseSafe(result);
261 });
262 return;
263 }
264
265 __block CFStringRef serverStr = CFRetainSafe(fqdn);
266 __block CFStringRef accountStr = CFRetainSafe(account);
267
268 dispatch_async(dst_queue, ^{
269 #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
270 OSStatus status = SecCopySharedWebCredentialSyncUsingAuthSvcs(serverStr, accountStr, &result, &error);
271 #else
272 OSStatus status = SecCopySharedWebCredentialSync(serverStr, accountStr, &result, &error);
273 #endif
274 CFReleaseSafe(serverStr);
275 CFReleaseSafe(accountStr);
276
277 if (status && !error) {
278 SecError(status, &error, CFSTR("Error copying shared password"));
279 }
280 dispatch_async(dst_queue, ^{
281 if (completionHandler) {
282 completionHandler(result, error);
283 }
284 CFReleaseSafe(error);
285 CFReleaseSafe(result);
286 });
287 });
288 #else
289 SecError(errSecParam, &error, CFSTR("SharedWebCredentials not supported on this platform"));
290 dispatch_async(dst_queue, ^{
291 if (completionHandler) {
292 completionHandler(NULL, error);
293 }
294 CFReleaseSafe(error);
295 });
296 #endif /* SHAREDWEBCREDENTIALS */
297
298 }
299
300 CFStringRef SecCreateSharedWebCredentialPassword(void)
301 {
302
303 CFStringRef password = NULL;
304 CFErrorRef error = NULL;
305 CFMutableDictionaryRef passwordRequirements = NULL;
306
307 CFStringRef allowedCharacters = CFSTR("abcdefghkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789");
308 CFCharacterSetRef requiredCharactersLower = CFCharacterSetCreateWithCharactersInString(NULL, CFSTR("abcdefghkmnopqrstuvwxyz"));
309 CFCharacterSetRef requiredCharactersUppder = CFCharacterSetCreateWithCharactersInString(NULL, CFSTR("ABCDEFGHJKLMNPQRSTUVWXYZ"));
310 CFCharacterSetRef requiredCharactersNumbers = CFCharacterSetCreateWithCharactersInString(NULL, CFSTR("3456789"));
311
312 int groupSize = 3;
313 int groupCount = 4;
314 int totalLength = (groupSize * groupCount);
315 CFNumberRef groupSizeRef = CFNumberCreate(NULL, kCFNumberIntType, &groupSize);
316 CFNumberRef groupCountRef = CFNumberCreate(NULL, kCFNumberIntType, &groupCount);
317 CFNumberRef totalLengthRef = CFNumberCreate(NULL, kCFNumberIntType, &totalLength);
318 CFStringRef separator = CFSTR("-");
319
320 CFMutableArrayRef requiredCharacterSets = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
321 CFArrayAppendValue(requiredCharacterSets, requiredCharactersLower);
322 CFArrayAppendValue(requiredCharacterSets, requiredCharactersUppder);
323 CFArrayAppendValue(requiredCharacterSets, requiredCharactersNumbers);
324
325 passwordRequirements = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
326 CFDictionaryAddValue(passwordRequirements, kSecPasswordAllowedCharactersKey, allowedCharacters);
327 CFDictionaryAddValue(passwordRequirements, kSecPasswordRequiredCharactersKey, requiredCharacterSets);
328 CFDictionaryAddValue(passwordRequirements, kSecPasswordGroupSize, groupSizeRef );
329 CFDictionaryAddValue(passwordRequirements, kSecPasswordNumberOfGroups, groupCountRef);
330 CFDictionaryAddValue(passwordRequirements, kSecPasswordSeparator, separator);
331 CFDictionaryAddValue(passwordRequirements, kSecPasswordMaxLengthKey, totalLengthRef);
332 CFDictionaryAddValue(passwordRequirements, kSecPasswordMinLengthKey, totalLengthRef);
333 CFDictionaryAddValue(passwordRequirements, kSecPasswordDefaultForType, CFSTR("false"));
334 CFRelease(requiredCharactersLower);
335 CFRelease(requiredCharactersUppder);
336 CFRelease(requiredCharactersNumbers);
337 CFRelease(groupSizeRef);
338 CFRelease(groupCountRef);
339 CFRelease(totalLengthRef);
340
341 password = SecPasswordGenerate(kSecPasswordTypeSafari, &error, passwordRequirements);
342
343 CFRelease(requiredCharacterSets);
344 CFRelease(passwordRequirements);
345 if ((error && error != errSecSuccess) || !password)
346 {
347 if (password) CFRelease(password);
348 secwarning("SecPasswordGenerate failed to generate a password for SecCreateSharedWebCredentialPassword.");
349 return NULL;
350 } else {
351 return password;
352 }
353
354 }