/ SOSCCAuthPlugin / SOSCCAuthPlugin.m
SOSCCAuthPlugin.m
  1  //
  2  //  SOSCCAuthPlugin.m
  3  //  Security
  4  //
  5  //  Created by Christian Schmidt on 7/8/15.
  6  //  Copyright 2015 Apple, Inc. All rights reserved.
  7  //
  8  
  9  #import "SOSCCAuthPlugin.h"
 10  #import <Foundation/Foundation.h>
 11  #import <Accounts/Accounts.h>
 12  #import <Accounts/Accounts_Private.h>
 13  #import <AccountsDaemon/ACDAccountStore.h>
 14  #import <AppleAccount/ACAccount+AppleAccount.h>
 15  #import <AppleAccount/ACAccountStore+AppleAccount.h>
 16  #import <AuthKit/AuthKit.h>
 17  #import <AuthKit/AuthKit_Private.h>
 18  #import <SoftLinking/SoftLinking.h>
 19  #import <Security/SecureObjectSync/SOSCloudCircle.h>
 20  #import "utilities/SecCFRelease.h"
 21  #import "utilities/debugging.h"
 22  
 23  
 24  #if !TARGET_OS_SIMULATOR
 25  SOFT_LINK_FRAMEWORK(PrivateFrameworks, AuthKit);
 26  
 27  #pragma clang diagnostic push
 28  #pragma clang diagnostic ignored "-Wstrict-prototypes"
 29  SOFT_LINK_CLASS(AuthKit, AKAccountManager);
 30  #pragma clang diagnostic pop
 31  #endif
 32  
 33  @implementation SOSCCAuthPlugin
 34  
 35  static bool accountIsHSA2(ACAccount *account) {
 36      bool hsa2 = false;
 37  
 38  #if !TARGET_OS_SIMULATOR
 39      AKAccountManager *manager = [getAKAccountManagerClass() sharedInstance];
 40      if(manager != nil) {
 41          ACAccount *aka = [manager authKitAccountWithAltDSID:account.aa_altDSID];
 42          if (aka) {
 43              AKAppleIDSecurityLevel securityLevel = [manager securityLevelForAccount: aka];
 44              if(securityLevel == AKAppleIDSecurityLevelHSA2) {
 45                  hsa2 = true;
 46              }
 47          }
 48      }
 49  #endif
 50      secnotice("accounts", "Account %s HSA2", (hsa2) ? "is": "isn't" );
 51      return hsa2;
 52  }
 53  
 54  - (void) didReceiveAuthenticationResponseParameters: (NSDictionary *) parameters
 55  									   accountStore: (ACDAccountStore *) store
 56  											account: (ACAccount *) account
 57  										 completion: (dispatch_block_t) completion
 58  {
 59  	BOOL	do_auth = NO;
 60      NSString* accountIdentifier = account.identifier; // strong reference
 61  	secinfo("accounts", "parameters %@", parameters);
 62  	secinfo("accounts", "account %@", account);
 63  
 64  	if ([account.accountType.identifier isEqualToString:ACAccountTypeIdentifierIdentityServices]) {
 65  		ACAccount *icloud = [store aa_primaryAppleAccount];
 66  		NSString  *dsid   = [parameters[@"com.apple.private.ids"][@"service-data"][@"profile-id"] substringFromIndex:2];	// remove "D:" prefix
 67  		secinfo("accounts", "IDS account: iCloud %@ (personID %@)", icloud, icloud.aa_personID);
 68  		do_auth = icloud && icloud.aa_personID && [icloud.aa_personID isEqualToString:dsid];
 69  	} else if ([account.accountType.identifier isEqualToString:ACAccountTypeIdentifierAppleAccount]) {
 70          do_auth = [account aa_isAccountClass:AAAccountClassPrimary];
 71          secinfo("accounts", "AppleID account: primary %@", @(do_auth));
 72  	}
 73  
 74      if(do_auth && !accountIsHSA2(account)) {
 75  		NSString	*rawPassword = [account _aa_rawPassword];
 76  
 77  		if (rawPassword != NULL) {
 78              dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
 79                  CFErrorRef asyncError = NULL;
 80                  NSString *dsid = [account aa_personID];
 81                  const char *password   = [rawPassword cStringUsingEncoding:NSUTF8StringEncoding];
 82                  CFDataRef passwordData = CFDataCreate(kCFAllocatorDefault, (const uint8_t *) password, strlen(password));
 83  
 84                  if (passwordData) {
 85                      secinfo("accounts", "Performing async SOS circle credential set for account %@: %@", accountIdentifier, account.username);
 86  
 87                      if (!SOSCCSetUserCredentialsAndDSID((__bridge CFStringRef) account.username, passwordData, (__bridge CFStringRef) dsid, &asyncError)) {
 88                          secerror("Unable to set SOS circle credentials for account %@: %@", accountIdentifier, asyncError);
 89                          secinfo("accounts", "Returning from failed async call to SOSCCSetUserCredentialsAndDSID");
 90                          CFReleaseNull(asyncError);
 91                      } else {
 92                          secinfo("accounts", "Returning from successful async call to SOSCCSetUserCredentialsAndDSID");
 93                      }
 94                      CFRelease(passwordData);
 95                  } else {
 96                      secinfo("accounts", "Failed to create string for call to SOSCCSetUserCredentialsAndDSID");
 97                  }
 98              });
 99  		} else {
100              CFErrorRef    authError    = NULL;
101  			if (!SOSCCCanAuthenticate(&authError)) {
102  				secerror("Account %@ did not present a password and we could not authenticate the SOS circle: %@", accountIdentifier, authError);
103  				CFReleaseNull(authError);
104  			}
105  		}
106  	} else {
107  		secinfo("accounts", "NOT performing SOS circle credential set for account %@: %@", accountIdentifier, account.username);
108  	}
109  
110  	completion();
111  }
112  
113  @end