2 * Copyright (c) 2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
23 * SecSharedCredential.c - CoreFoundation-based functions to store and retrieve shared credentials.
27 #include <Security/SecSharedCredential.h>
28 #include <Security/SecBasePriv.h>
29 #include <utilities/SecCFError.h>
30 #include <utilities/SecCFWrappers.h>
31 #include "SecItemInternal.h"
32 #include <ipc/securityd_client.h>
33 #include "SecPasswordGenerate.h"
35 /* forward declarations */
36 OSStatus
SecAddSharedWebCredentialSync(CFStringRef fqdn
, CFStringRef account
, CFStringRef password
, CFErrorRef
*error
);
37 OSStatus
SecCopySharedWebCredentialSync(CFStringRef fqdn
, CFStringRef account
, CFArrayRef
*credentials
, CFErrorRef
*error
);
40 OSStatus
SecAddSharedWebCredentialSync(CFStringRef fqdn
,
46 __block CFErrorRef
* outError
= error
;
47 __block CFMutableDictionaryRef args
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
48 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
50 CFDictionaryAddValue(args
, kSecAttrServer
, fqdn
);
53 CFDictionaryAddValue(args
, kSecAttrAccount
, account
);
56 #if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
57 CFDictionaryAddValue(args
, kSecSharedPassword
, password
);
59 CFDictionaryAddValue(args
, CFSTR("spwd"), password
);
62 status
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
63 CFTypeRef raw_result
= NULL
;
65 bool internal_spi
= false; // TODO: support this for SecurityDevTests
66 if(internal_spi
&& gSecurityd
&& gSecurityd
->sec_add_shared_web_credential
) {
67 xpc_result
= gSecurityd
->sec_add_shared_web_credential(args
, NULL
, NULL
, SecAccessGroupsGetCurrent(), &raw_result
, error
);
69 xpc_result
= cftype_ag_to_bool_cftype_error_request(sec_add_shared_web_credential_id
, args
, SecAccessGroupsGetCurrent(), &raw_result
, error
);
74 SecError(errSecInternal
, error
, CFSTR("Internal error (XPC failure)"));
78 *outError
= (error
) ? *error
: NULL
;
79 CFRetainSafe(*outError
);
81 CFReleaseNull(*error
);
83 CFReleaseNull(raw_result
);
90 void SecAddSharedWebCredential(CFStringRef fqdn
,
93 void (^completionHandler
)(CFErrorRef error
))
95 __block CFErrorRef error
= NULL
;
96 __block dispatch_queue_t dst_queue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
,0);
97 dispatch_retain(dst_queue
);
99 /* sanity check input arguments */
100 CFStringRef errStr
= NULL
;
101 if (!fqdn
|| CFGetTypeID(fqdn
) != CFStringGetTypeID() || !CFStringGetLength(fqdn
) ||
102 !account
|| CFGetTypeID(account
) != CFStringGetTypeID() || !CFStringGetLength(account
) ) {
103 errStr
= CFSTR("fqdn or account was not of type CFString, or not provided");
105 else if (password
&& CFGetTypeID(password
) != CFStringGetTypeID()) {
106 errStr
= CFSTR("non-nil password was not of type CFString");
109 SecError(errSecParam
, &error
, errStr
);
110 dispatch_async(dst_queue
, ^{
111 if (completionHandler
) {
112 completionHandler(error
);
114 CFReleaseSafe(error
);
115 dispatch_release(dst_queue
);
120 __block CFStringRef serverStr
= CFRetainSafe(fqdn
);
121 __block CFStringRef accountStr
= CFRetainSafe(account
);
122 __block CFStringRef passwordStr
= CFRetainSafe(password
);
124 dispatch_async(dst_queue
, ^{
125 OSStatus status
= SecAddSharedWebCredentialSync(serverStr
, accountStr
, passwordStr
, &error
);
126 CFReleaseSafe(serverStr
);
127 CFReleaseSafe(accountStr
);
128 CFReleaseSafe(passwordStr
);
130 if (status
&& !error
) {
131 SecError(status
, &error
, CFSTR("Error adding shared password"));
133 dispatch_async(dst_queue
, ^{
134 if (completionHandler
) {
135 completionHandler(error
);
137 CFReleaseSafe(error
);
138 dispatch_release(dst_queue
);
144 OSStatus
SecCopySharedWebCredentialSync(CFStringRef fqdn
,
146 CFArrayRef
*credentials
,
150 __block CFErrorRef
* outError
= error
;
151 __block CFMutableDictionaryRef args
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
152 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
154 CFDictionaryAddValue(args
, kSecAttrServer
, fqdn
);
157 CFDictionaryAddValue(args
, kSecAttrAccount
, account
);
159 status
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
160 CFTypeRef raw_result
= NULL
;
162 bool internal_spi
= false; // TODO: support this for SecurityDevTests
163 if(internal_spi
&& gSecurityd
&& gSecurityd
->sec_copy_shared_web_credential
) {
164 xpc_result
= gSecurityd
->sec_copy_shared_web_credential(args
, NULL
, NULL
, SecAccessGroupsGetCurrent(), &raw_result
, error
);
166 xpc_result
= cftype_ag_to_bool_cftype_error_request(sec_copy_shared_web_credential_id
, args
, SecAccessGroupsGetCurrent(), &raw_result
, error
);
170 if (NULL
== *error
) {
171 SecError(errSecInternal
, error
, CFSTR("Internal error (XPC failure)"));
175 *outError
= (error
) ? *error
: NULL
;
176 CFRetainSafe(*outError
);
178 CFReleaseNull(*error
);
181 raw_result
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
183 *credentials
= raw_result
;
191 void SecRequestSharedWebCredential(CFStringRef fqdn
,
193 void (^completionHandler
)(CFArrayRef credentials
, CFErrorRef error
))
195 __block CFArrayRef result
= NULL
;
196 __block CFErrorRef error
= NULL
;
197 __block dispatch_queue_t dst_queue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
,0);
198 dispatch_retain(dst_queue
);
200 /* sanity check input arguments, if provided */
201 CFStringRef errStr
= NULL
;
202 if (fqdn
&& (CFGetTypeID(fqdn
) != CFStringGetTypeID() || !CFStringGetLength(fqdn
))) {
203 errStr
= CFSTR("fqdn was empty or not a CFString");
205 else if (account
&& (CFGetTypeID(account
) != CFStringGetTypeID() || !CFStringGetLength(account
))) {
206 errStr
= CFSTR("account was empty or not a CFString");
209 SecError(errSecParam
, &error
, errStr
);
210 dispatch_async(dst_queue
, ^{
211 if (completionHandler
) {
212 completionHandler(result
, error
);
214 CFReleaseSafe(error
);
215 CFReleaseSafe(result
);
216 dispatch_release(dst_queue
);
221 __block CFStringRef serverStr
= CFRetainSafe(fqdn
);
222 __block CFStringRef accountStr
= CFRetainSafe(account
);
224 dispatch_async(dst_queue
, ^{
225 OSStatus status
= SecCopySharedWebCredentialSync(serverStr
, accountStr
, &result
, &error
);
226 CFReleaseSafe(serverStr
);
227 CFReleaseSafe(accountStr
);
229 if (status
&& !error
) {
230 SecError(status
, &error
, CFSTR("Error copying shared password"));
232 dispatch_async(dst_queue
, ^{
233 if (completionHandler
) {
234 completionHandler(result
, error
);
236 CFReleaseSafe(error
);
237 CFReleaseSafe(result
);
238 dispatch_release(dst_queue
);
244 CFStringRef
SecCreateSharedWebCredentialPassword(void)
247 CFStringRef password
= NULL
;
248 CFErrorRef error
= NULL
;
249 CFMutableDictionaryRef passwordRequirements
= NULL
;
251 CFStringRef allowedCharacters
= CFSTR("abcdefghkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789");
252 CFCharacterSetRef requiredCharactersLower
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("abcdefghkmnopqrstuvwxyz"));
253 CFCharacterSetRef requiredCharactersUppder
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("ABCDEFGHJKLMNPQRSTUVWXYZ"));
254 CFCharacterSetRef requiredCharactersNumbers
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("3456789"));
258 int totalLength
= (groupSize
* groupCount
);
259 CFNumberRef groupSizeRef
= CFNumberCreate(NULL
, kCFNumberIntType
, &groupSize
);
260 CFNumberRef groupCountRef
= CFNumberCreate(NULL
, kCFNumberIntType
, &groupCount
);
261 CFNumberRef totalLengthRef
= CFNumberCreate(NULL
, kCFNumberIntType
, &totalLength
);
262 CFStringRef separator
= CFSTR("-");
264 CFMutableArrayRef requiredCharacterSets
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
265 CFArrayAppendValue(requiredCharacterSets
, requiredCharactersLower
);
266 CFArrayAppendValue(requiredCharacterSets
, requiredCharactersUppder
);
267 CFArrayAppendValue(requiredCharacterSets
, requiredCharactersNumbers
);
269 passwordRequirements
= CFDictionaryCreateMutable(NULL
, 0, NULL
, NULL
);
270 CFDictionaryAddValue(passwordRequirements
, kSecPasswordAllowedCharactersKey
, allowedCharacters
);
271 CFDictionaryAddValue(passwordRequirements
, kSecPasswordRequiredCharactersKey
, requiredCharacterSets
);
272 CFDictionaryAddValue(passwordRequirements
, kSecPasswordGroupSize
, groupSizeRef
);
273 CFDictionaryAddValue(passwordRequirements
, kSecPasswordNumberOfGroups
, groupCountRef
);
274 CFDictionaryAddValue(passwordRequirements
, kSecPasswordSeparator
, separator
);
275 CFDictionaryAddValue(passwordRequirements
, kSecPasswordMaxLengthKey
, totalLengthRef
);
276 CFDictionaryAddValue(passwordRequirements
, kSecPasswordMinLengthKey
, totalLengthRef
);
277 CFDictionaryAddValue(passwordRequirements
, kSecPasswordDefaultForType
, CFSTR("false"));
278 CFRelease(requiredCharactersLower
);
279 CFRelease(requiredCharactersUppder
);
280 CFRelease(requiredCharactersNumbers
);
281 CFRelease(groupSizeRef
);
282 CFRelease(groupCountRef
);
283 CFRelease(totalLengthRef
);
285 password
= SecPasswordGenerate(kSecPasswordTypeSafari
, &error
, passwordRequirements
);
287 CFRelease(requiredCharacterSets
);
288 CFRelease(passwordRequirements
);
289 if ((error
&& error
!= errSecSuccess
) || !password
)
291 if (password
) CFRelease(password
);
292 secwarning("SecPasswordGenerate failed to generate a password for SecCreateSharedWebCredentialPassword.");