]> git.saurik.com Git - apple/security.git/blob - keychain/ot/OTSOSUpdatePreapprovalsOperation.m
Security-59754.80.3.tar.gz
[apple/security.git] / keychain / ot / OTSOSUpdatePreapprovalsOperation.m
1
2
3 #if OCTAGON
4
5 #import <TargetConditionals.h>
6 #import <Security/SecKey.h>
7 #import <Security/SecKeyPriv.h>
8 #import <CloudKit/CloudKit_Private.h>
9
10 #import "keychain/ot/ObjCImprovements.h"
11 #import "keychain/ot/OTSOSUpdatePreapprovalsOperation.h"
12 #import "keychain/ot/OTOperationDependencies.h"
13 #import "keychain/ot/OTCuttlefishAccountStateHolder.h"
14 #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h"
15 #import "keychain/ot/categories/OTAccountMetadataClassC+KeychainSupport.h"
16 #import "keychain/ckks/CKKSAnalytics.h"
17 #import "keychain/ckks/CloudKitCategories.h"
18
19 @interface OTSOSUpdatePreapprovalsOperation ()
20 @property OTOperationDependencies* deps;
21
22 // Since we're making callback based async calls, use this operation trick to hold off the ending of this operation
23 @property NSOperation* finishedOp;
24 @end
25
26 @implementation OTSOSUpdatePreapprovalsOperation
27 @synthesize nextState = _nextState;
28 @synthesize intendedState = _intendedState;
29
30 - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
31 intendedState:(OctagonState*)intendedState
32 sosNotPresentState:(OctagonState*)sosNotPresentState
33 errorState:(OctagonState*)errorState
34 {
35 if((self = [super init])) {
36 _deps = dependencies;
37
38 _intendedState = intendedState;
39 _sosNotPresentState = sosNotPresentState;
40 _nextState = errorState;
41 }
42 return self;
43 }
44
45 - (void)groupStart
46 {
47 WEAKIFY(self);
48
49 if(!self.deps.sosAdapter.sosEnabled) {
50 secnotice("octagon-sos", "SOS not enabled on this platform?");
51 return;
52 }
53
54 self.finishedOp = [NSBlockOperation blockOperationWithBlock:^{
55 // If we errored in some unknown way, ask to try again!
56 STRONGIFY(self);
57
58 if(self.error) {
59 // Is this a very scary error?
60 bool fatal = false;
61
62 NSTimeInterval ckDelay = CKRetryAfterSecondsForError(self.error);
63 NSTimeInterval cuttlefishDelay = [self.error cuttlefishRetryAfter];
64 NSTimeInterval delay = MAX(ckDelay, cuttlefishDelay);
65 if (delay == 0) {
66 delay = 30;
67 }
68
69 if([self.error isCuttlefishError:CuttlefishErrorResultGraphNotFullyReachable]) {
70 secnotice("octagon-sos", "SOS update preapproval error is 'result graph not reachable'; retrying is useless: %@", self.error);
71 fatal = true;
72 }
73
74 if([self.error.domain isEqualToString:TrustedPeersHelperErrorDomain] && self.error.code == TrustedPeersHelperErrorNoPreparedIdentity) {
75 secnotice("octagon-sos", "SOS update preapproval error is 'no prepared identity'; retrying immediately is useless: %@", self.error);
76 fatal = true;
77 }
78
79 if(!fatal) {
80 secnotice("octagon-sos", "SOS update preapproval error is not fatal: requesting retry in %0.2fs: %@", delay, self.error);
81 [self.deps.flagHandler handlePendingFlag:[[OctagonPendingFlag alloc] initWithFlag:OctagonFlagAttemptSOSUpdatePreapprovals
82 delayInSeconds:delay]];
83 }
84 }
85 }];
86 [self dependOnBeforeGroupFinished:self.finishedOp];
87
88 NSError* sosPreapprovalError = nil;
89 NSArray<NSData*>* publicSigningSPKIs = [OTSOSAdapterHelpers peerPublicSigningKeySPKIsForCircle:self.deps.sosAdapter error:&sosPreapprovalError];
90
91 if(!publicSigningSPKIs || sosPreapprovalError) {
92 secerror("octagon-sos: Can't fetch trusted peers; stopping preapproved key update: %@", sosPreapprovalError);
93 self.error = sosPreapprovalError;
94 self.nextState = self.sosNotPresentState;
95 [self runBeforeGroupFinished:self.finishedOp];
96 return;
97 }
98
99 secnotice("octagon-sos", "Updating SOS preapproved keys to %@", publicSigningSPKIs);
100
101 [self.deps.cuttlefishXPCWrapper setPreapprovedKeysWithContainer:self.deps.containerName
102 context:self.deps.contextID
103 preapprovedKeys:publicSigningSPKIs
104 reply:^(TrustedPeersHelperPeerState* _Nullable peerState, NSError* error) {
105 STRONGIFY(self);
106 if(error) {
107 secerror("octagon-sos: unable to update preapproved keys: %@", error);
108 self.error = error;
109 } else {
110 secnotice("octagon-sos", "Updated SOS preapproved keys");
111
112 if (peerState.memberChanges) {
113 secnotice("octagon", "Member list changed");
114 [self.deps.octagonAdapter sendTrustedPeerSetChangedUpdate];
115 }
116
117 self.nextState = self.intendedState;
118 }
119 [self runBeforeGroupFinished:self.finishedOp];
120 }];
121 }
122
123 @end
124
125 #endif // OCTAGON