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.");