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