]> git.saurik.com Git - apple/security.git/blob - keychain/ot/OTAuthKitAdapter.m
Security-59306.41.2.tar.gz
[apple/security.git] / keychain / ot / OTAuthKitAdapter.m
1 #if OCTAGON
2
3 #import "OTAuthKitAdapter.h"
4
5 #import "utilities/SecCFError.h"
6 #import "keychain/categories/NSError+UsefulConstructors.h"
7
8 #import <AppleAccount/AppleAccount.h>
9 #import <AppleAccount/AppleAccount_Private.h>
10 #import <AuthKit/AuthKit.h>
11 #import <AuthKit/AuthKit_Private.h>
12 #import <AuthKit/AKDeviceListDeltaMessagePayload.h>
13 #import <Foundation/NSDistributedNotificationCenter.h>
14 #import "keychain/ckks/CKKSListenerCollection.h"
15
16 #import <AppleAccount/ACAccount+AppleAccount.h>
17
18 @interface OTAuthKitActualAdapter ()
19 @property CKKSListenerCollection<OTAuthKitAdapterNotifier>* notifiers;
20 @end
21
22 @implementation OTAuthKitActualAdapter
23
24 - (NSString* _Nullable)primaryiCloudAccountAltDSID
25 {
26 ACAccountStore *store = [[ACAccountStore alloc] init];
27 ACAccount* primaryAccount = [store aa_primaryAppleAccount];
28 if(!primaryAccount) {
29 return nil;
30 }
31
32 return [primaryAccount aa_altDSID];
33 }
34
35 - (BOOL)accountIsHSA2ByAltDSID:(NSString*)altDSID
36 {
37 bool hsa2 = false;
38
39 AKAccountManager *manager = [AKAccountManager sharedInstance];
40 ACAccount *authKitAccount = [manager authKitAccountWithAltDSID:altDSID];
41 AKAppleIDSecurityLevel securityLevel = [manager securityLevelForAccount:authKitAccount];
42 if(securityLevel == AKAppleIDSecurityLevelHSA2) {
43 hsa2 = true;
44 }
45 secnotice("security-authkit", "Security level for altDSID %@ is %lu", altDSID, (unsigned long)securityLevel);
46 return hsa2;
47 }
48
49 - (NSString* _Nullable)machineID:(NSError**)error
50 {
51 AKAnisetteProvisioningController* anisetteController = [[AKAnisetteProvisioningController alloc] init];
52 NSError* localError = nil;
53 AKAnisetteData* anisetteData = [anisetteController anisetteDataWithError:&localError];
54 if(!anisetteData) {
55 secnotice("authkit", "Unable to fetch data: %@", localError);
56 if(error) {
57 *error = localError;
58 }
59 return nil;
60 }
61
62 NSString* machineID = anisetteData.machineID;
63 if(!machineID) {
64 secnotice("authkit", "Anisette data does not have machineID");
65 if(error) {
66 // TODO: this is a terrible error
67 *error = [NSError errorWithDomain:(__bridge NSString *)kSecErrorDomain
68 code:errSecParam
69 description:@"Anisette data does not have machineID"];
70 }
71 return nil;
72 }
73
74 secnotice("authkit", "fetched current machine ID as: %@", machineID);
75
76 return machineID;
77 }
78
79 - (void)fetchCurrentDeviceList:(void (^)(NSSet<NSString*>* _Nullable machineIDs, NSError* _Nullable error))complete
80 {
81 ACAccountStore *store = [[ACAccountStore alloc] init];
82 ACAccount* primaryAccount = [store aa_primaryAppleAccount];
83 if(primaryAccount == nil) {
84 secnotice("authkit", "can't get account");
85 complete(nil, [NSError errorWithDomain:(__bridge NSString *)kSecErrorDomain
86 code:errSecParam
87 description:@"no primary account"]);
88 return;
89 }
90
91 AKDeviceListRequestContext* context = [[AKDeviceListRequestContext alloc] init];
92 if (context == nil) {
93 complete(nil, [NSError errorWithDomain:(__bridge NSString *)kSecErrorDomain
94 code:errSecParam
95 description:@"can't get AKDeviceListRequestContextClass"]);
96 return;
97 }
98 context.altDSID = primaryAccount.aa_altDSID;
99
100 AKAppleIDAuthenticationController *authController = [[AKAppleIDAuthenticationController alloc] init];
101 if(authController == nil) {
102 complete(nil, [NSError errorWithDomain:(__bridge NSString *)kSecErrorDomain
103 code:errSecParam
104 description:@"can't get authController"]);
105 return;
106 }
107
108 [authController fetchDeviceListWithContext:context completion:^(NSArray<AKRemoteDevice *> *deviceList, NSError *error) {
109 if (deviceList) {
110 NSMutableSet *mids = [[NSMutableSet alloc] init];
111
112 for (AKRemoteDevice *device in deviceList) {
113 [mids addObject:device.machineId];
114 }
115
116 secnotice("authkit", "Current machine ID list: %@", mids);
117 complete(mids, error);
118 } else {
119 secnotice("authkit", "received no device list: %@", error);
120 complete(nil, error);
121 }
122 }];
123 }
124
125 - (void)registerNotification:(id<OTAuthKitAdapterNotifier>)newNotifier
126 {
127 if (self.notifiers == nil) {
128 self.notifiers = [[CKKSListenerCollection<OTAuthKitAdapterNotifier> alloc] initWithName:@"otauthkitadapter-notifiers"];
129 [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyAKDeviceList:) name:AKDeviceListChangedNotification object:nil];
130 }
131 [self.notifiers registerListener:newNotifier];
132 }
133
134 - (void)notifyAKDeviceList:(NSNotification* _Nullable)notification
135 {
136 AKDeviceListDeltaMessagePayload *payload = nil;
137 NSDictionary *userInfo = nil;
138 if (notification != nil) {
139 userInfo = [notification userInfo];
140 if (userInfo != nil) {
141 payload = [[AKDeviceListDeltaMessagePayload alloc] initWithResponseBody:userInfo];
142 }
143 }
144
145 secnotice("authkit", "received notifyAKDeviceList: %@, read payload: %@",
146 notification.userInfo,
147 // Logging the payload logs an address, so clean it up here.
148 payload ? @"YES" : @"NO");
149
150 [self.notifiers iterateListeners:^(id<OTAuthKitAdapterNotifier> listener) {
151 NSString* altDSID = payload.altDSID;
152 NSArray<NSString*>* machineIDs = payload.machineIDs;
153
154 if (altDSID == nil || machineIDs == nil || machineIDs.count == 0) {
155 secnotice("authkit", "partial push or no machine IDs in list; treating as incomplete");
156 [listener incompleteNotificationOfMachineIDListChange];
157 return;
158 }
159 switch (payload.operation) {
160 case AKDeviceListDeltaOperationAdd:
161 [listener machinesAdded:machineIDs altDSID:altDSID];
162 return;
163 break;
164 case AKDeviceListDeltaOperationRemove:
165 [listener machinesRemoved:machineIDs altDSID:altDSID];
166 return;
167 break;
168 case AKDeviceListDeltaOperationUnknown:
169 default:
170 break;
171 }
172 [listener incompleteNotificationOfMachineIDListChange];
173 }];
174 }
175
176 @end
177
178 #endif // OCTAGON