]> git.saurik.com Git - apple/security.git/blob - keychain/SecureObjectSync/SOSAuthKitHelpers.m
Security-59754.41.1.tar.gz
[apple/security.git] / keychain / SecureObjectSync / SOSAuthKitHelpers.m
1 //
2 // SOSAuthKitHelpers.m
3 // Security
4 //
5 //
6
7 #import <Foundation/Foundation.h>
8 #import "SOSAuthKitHelpers.h"
9 #import <utilities/debugging.h>
10 #import "keychain/SecureObjectSync/SOSAccount.h"
11 #import "keychain/SecureObjectSync/SOSAccountPriv.h"
12 #import "keychain/SecureObjectSync/SOSFullPeerInfo.h"
13 #import "keychain/SecureObjectSync/SOSPeerInfoV2.h"
14 #import "keychain/SecureObjectSync/SOSPeerInfoPriv.h"
15
16 #if !TARGET_OS_BRIDGE && !TARGET_OS_SIMULATOR && __OBJC2__
17 #import <AppleAccount/AppleAccount_Private.h>
18 #import <AuthKit/AuthKit.h>
19 #import <AuthKit/AuthKit_Private.h>
20 #import <SoftLinking/SoftLinking.h>
21
22 #define SUPPORT_MID 1
23
24 SOFT_LINK_FRAMEWORK(PrivateFrameworks, AuthKit);
25 SOFT_LINK_FRAMEWORK(Frameworks, Accounts);
26
27 #pragma clang diagnostic push
28 #pragma clang diagnostic ignored "-Wstrict-prototypes"
29 SOFT_LINK_CLASS(AuthKit, AKAccountManager);
30 SOFT_LINK_CLASS(AuthKit, AKAnisetteProvisioningController);
31 SOFT_LINK_CLASS(AuthKit, AKAppleIDAuthenticationController);
32 SOFT_LINK_CLASS(AuthKit, AKDeviceListRequestContext);
33 SOFT_LINK_CLASS(Accounts, ACAccountStore);
34 SOFT_LINK_CONSTANT(AuthKit, AKServiceNameiCloud, const NSString *);
35 #pragma clang diagnostic pop
36
37 static void *accountsFramework = NULL;
38 static void *appleAccountFramework = NULL;
39
40 static void
41 initAccountsFramework(void) {
42 static dispatch_once_t onceToken;
43 dispatch_once(&onceToken, ^{
44 accountsFramework = dlopen("/System/Library/Frameworks/Accounts.framework/Accounts", RTLD_LAZY);
45 appleAccountFramework = dlopen("/System/Library/PrivateFrameworks/AppleAccount.framework/AppleAccount", RTLD_LAZY);
46 });
47 }
48
49 @implementation SOSAuthKitHelpers
50
51 @class SOSAuthKitHelpers;
52
53 + (NSString *) machineID {
54 NSError *error = nil;
55 NSString *retval = nil;
56 secnotice("sosauthkit", "Entering machineID");
57
58 AKAnisetteProvisioningController *anisetteController = [getAKAnisetteProvisioningControllerClass() new];
59 if(anisetteController) {
60 AKAnisetteData *anisetteData = [anisetteController anisetteDataWithError:&error];
61 if (anisetteData) {
62 retval = [anisetteData.machineID copy];
63 if(retval) {
64 secnotice("sosauthkit", "machineID is %@", retval);
65 } else {
66 secnotice("sosauthkit", "Failed to get machineID");
67 }
68 } else {
69 secnotice("sosauthkit", "can't get mID: %@", error);
70 }
71 } else {
72 secnotice("sosauthkit", "can't get controller");
73 }
74 return retval;
75 }
76
77 static ACAccount *GetPrimaryAccount(void) {
78 ACAccount *primaryAccount;
79
80 initAccountsFramework();
81
82 ACAccountStore *store = [getACAccountStoreClass() new];
83
84 if(!store) {
85 secnotice("sosauthkit", "can't get store");
86 return nil;
87 }
88
89 primaryAccount = [store aa_primaryAppleAccount];
90
91 return primaryAccount;
92 }
93
94
95 + (void)activeMIDs:(void(^_Nonnull)(NSSet <SOSTrustedDeviceAttributes *> *activeMIDs, NSError *error))complete {
96 ACAccount *primaryAccount;
97 AKDeviceListRequestContext *context;
98
99 primaryAccount = GetPrimaryAccount();
100
101 if(!primaryAccount) {
102 secnotice("sosauthkit", "can't get account");
103 complete(NULL, [NSError errorWithDomain:(__bridge NSString *)kSecErrorDomain code:errSecParam userInfo:@{NSLocalizedDescriptionKey : @"no primary account"}]);
104 return;
105 }
106
107 context = [getAKDeviceListRequestContextClass() new];
108 if (context == NULL) {
109 complete(NULL, [NSError errorWithDomain:(__bridge NSString *)kSecErrorDomain code:errSecParam userInfo:@{NSLocalizedDescriptionKey : @"can't get AKDeviceListRequestContextClass"}]);
110 return;
111 }
112 context.altDSID = primaryAccount.aa_altDSID;
113 context.services = @[ getAKServiceNameiCloud() ];
114
115 // -[AKAppleIDAuthenticationController fetchDeviceListWithContext:error:] is not exposed, use a semaphore
116 AKAppleIDAuthenticationController *authController = [getAKAppleIDAuthenticationControllerClass() new];
117 if(!authController) {
118 complete(NULL, [NSError errorWithDomain:(__bridge NSString *)kSecErrorDomain code:errSecParam userInfo:@{NSLocalizedDescriptionKey : @"can't get authController"}]);
119 return;
120 }
121
122 [authController fetchDeviceListWithContext:context completion:^(NSArray<AKRemoteDevice *> *deviceList, NSError *error) {
123 NSMutableSet *mids = [NSMutableSet new];
124 for(AKRemoteDevice *akdev in deviceList) {
125 SOSTrustedDeviceAttributes *newdev = [SOSTrustedDeviceAttributes new];
126 newdev.machineID = akdev.machineId;
127 newdev.serialNumber = akdev.serialNumber;
128 [mids addObject:newdev];
129 }
130 if([mids count] == 0) {
131 secnotice("sosauthkit", "found no devices in account");
132 mids = nil;
133 }
134 complete(mids, error);
135 }];
136 }
137
138 + (bool) peerinfoHasMID: (SOSAccount *) account {
139 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(account.fullPeerInfo);
140 if(!pi) return true; // if there's no PI then just say "we don't need one"
141 return SOSPeerInfoV2DictionaryHasString(pi, sMachineIDKey);
142 }
143
144
145
146 + (bool) updateMIDInPeerInfo: (SOSAccount *) account {
147 NSString *mid = [SOSAuthKitHelpers machineID];
148 if(!mid) return true;
149 CFErrorRef error = NULL;
150 SOSAccountSetValue(account, sMachineIDKey, (__bridge CFStringRef)mid, &error);
151 bool peerUpdated = SOSAccountUpdatePeerInfoAndPush(account, CFSTR("Add Machine ID"), &error, ^bool(SOSPeerInfoRef pi, CFErrorRef *error) {
152 if(SOSPeerInfoV2DictionaryHasString(pi, sMachineIDKey)) {
153 return false;
154 }
155 secnotice("sosauthkit", "Setting PeerInfo MID to %@", mid);
156 SOSPeerInfoV2DictionarySetValue(pi, sMachineIDKey, (__bridge CFStringRef)mid);
157 return true;
158 });
159 if(!peerUpdated) {
160 secnotice("sosauthkit", "Failed to record MID in PeerInfo: %@", error);
161 }
162 CFReleaseNull(error);
163 return peerUpdated;
164 }
165
166
167 + (bool) accountIsHSA2 {
168 bool hsa2 = false;
169
170 ACAccount *primaryAccount = GetPrimaryAccount();
171 AKAccountManager *manager = [getAKAccountManagerClass() new];
172
173 if(manager && primaryAccount) {
174 ACAccount *account = [manager authKitAccountWithAltDSID:[manager altDSIDForAccount:primaryAccount]];
175 AKAppleIDSecurityLevel securityLevel = [manager securityLevelForAccount:account];
176 if(securityLevel == AKAppleIDSecurityLevelHSA2) {
177 hsa2 = true;
178 } else {
179 secnotice("sosauthkit", "Security level is %lu", (unsigned long)securityLevel);
180 }
181 secnotice("sosauthkit", "Account %s HSA2", (hsa2) ? "is": "isn't" );
182 } else {
183 secnotice("sosauthkit", "Failed to get manager");
184 }
185 return hsa2;
186 }
187
188
189 -(id) initWithActiveMIDS: (NSSet <SOSTrustedDeviceAttributes *> *) theMidList
190 {
191 if ((self = [super init])) {
192 NSMutableSet *MmachineIDs = [[NSMutableSet alloc] init];
193 NSMutableSet *MserialNumbers = [[NSMutableSet alloc] init];
194 _machineIDs = [[NSSet alloc] init];
195 _serialNumbers = [[NSSet alloc] init];
196
197 if(!theMidList) return nil;
198 _midList = theMidList;
199
200 for(SOSTrustedDeviceAttributes *dev in _midList) {
201 if(dev.machineID) {
202 [MmachineIDs addObject:dev.machineID];
203 }
204 if(dev.serialNumber) {
205 [MserialNumbers addObject:dev.serialNumber];
206 }
207
208 }
209 _machineIDs = MmachineIDs;
210 _serialNumbers = MserialNumbers;
211 }
212 return self;
213 }
214
215 // if the ID passed in is null, the peer doesn't have one, we'll say true - we can't tell from the list
216 - (bool) midIsValidInList: (NSString *) machineId {
217 return (machineId) ? [_machineIDs containsObject:machineId]: true;
218 }
219
220 - (bool) serialIsValidInList: (NSString *) serialNumber {
221 return (serialNumber) ? [_serialNumbers containsObject:serialNumber]: true;
222 }
223
224 - (bool) isUseful {
225 return [ _machineIDs count ] > 0;
226 }
227
228 #else
229
230
231 @implementation SOSAuthKitHelpers
232
233 @class SOSAuthKitHelpers;
234
235 + (NSString *) machineID {
236 return nil;
237 }
238
239 + (void)activeMIDs:(void(^_Nonnull)(NSSet<SOSTrustedDeviceAttributes*> *activeMIDs, NSError *error))complete {
240 complete(nil, nil);
241 }
242
243 + (bool) updateMIDInPeerInfo: (SOSAccount *) account {
244 return true;
245 }
246
247 + (bool) peerinfoHasMID: (SOSAccount *) account {
248 return true;
249 }
250
251 + (bool) accountIsHSA2 {
252 return false;
253 }
254
255 - (id _Nullable) initWithActiveMIDS: (NSSet *_Nullable) theMidList {
256 return nil;
257 }
258
259 - (bool) midIsValidInList: (NSString *_Nullable) machineId {
260 return true;
261 }
262
263 - (bool) serialIsValidInList: (NSString *_Nullable) serialNumber {
264 return true;
265 }
266
267 - (bool) isUseful {
268 return false;
269 }
270
271 #endif
272
273 @end
274