]> git.saurik.com Git - apple/security.git/blob - keychain/SecureObjectSync/SOSPeerOTRTimer.m
Security-59306.140.5.tar.gz
[apple/security.git] / keychain / SecureObjectSync / SOSPeerOTRTimer.m
1 //
2 // SOSPeerOTRTimer.m
3 //
4
5 #import <Foundation/Foundation.h>
6 #include "keychain/SecureObjectSync/SOSPeer.h"
7 #include "keychain/SecureObjectSync/SOSPeerCoder.h"
8 #include "keychain/SecureObjectSync/SOSTransportMessage.h"
9 #include "keychain/SecureObjectSync/SOSAccount.h"
10 #include "keychain/SecureObjectSync/SOSCoder.h"
11 #include "keychain/SecureObjectSync/SOSEngine.h"
12 #include "keychain/SecureObjectSync/SOSDataSource.h"
13 #include "keychain/SecureObjectSync/SOSAccountTransaction.h"
14 #include "keychain/SecureObjectSync/SOSKVSKeys.h"
15 #include "keychain/SecureObjectSync/SOSPeerOTRTimer.h"
16 #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h"
17
18 #include <utilities/SecADWrapper.h>
19 #include <utilities/debugging.h>
20 #include <utilities/SecCFWrappers.h>
21
22 #include <AssertMacros.h>
23 #include "keychain/SecureObjectSync/SOSInternal.h"
24
25 //AGGD
26 NSString* const SecSOSAggdMaxRenegotiation = @"com.apple.security.sos.otrrenegotiationmaxretries";
27
28 static int maxRetryCount = 7; //max number of times to attempt restarting OTR negotiation
29
30 bool SOSPeerOTRTimerHaveReachedMaxRetryAllowance(SOSAccount* account, NSString* peerid){
31 bool reachedMax = false;
32 NSMutableDictionary* attemptsPerPeer = (__bridge NSMutableDictionary*)SOSAccountGetValue(account, kSOSAccountRenegotiationRetryCount, NULL);
33 if(!attemptsPerPeer){
34 attemptsPerPeer = [NSMutableDictionary dictionary];
35 }
36 NSNumber* attempt = [attemptsPerPeer objectForKey:peerid];
37 if(attempt && [attempt intValue] >= maxRetryCount)
38 {
39 reachedMax = true;
40 SecADAddValueForScalarKey((__bridge CFStringRef) SecSOSAggdMaxRenegotiation,1);
41 }
42 return reachedMax;
43 }
44
45 //used when evaluating whether or not securityd should start a timer for negotiation
46 bool SOSPeerOTRTimerHaveAnRTTAvailable(SOSAccount* account, NSString* peerid)
47 {
48 CFErrorRef error = NULL;
49 CFNumberRef timeout = NULL;
50 bool doesRTTExist = false;
51
52 CFMutableDictionaryRef timeouts = (CFMutableDictionaryRef)asDictionary(SOSAccountGetValue(account, kSOSAccountPeerNegotiationTimeouts, &error), NULL);
53 require_action_quiet(timeouts, exit, secnotice("otrtimer", "do not have an rtt yet"));
54
55 timeout = CFDictionaryGetValue(timeouts, (__bridge CFStringRef)peerid);
56 require_action_quiet(timeout, exit, secnotice("otrtimer", "do not have an rtt yet"));
57
58 doesRTTExist = true;
59 exit:
60 return doesRTTExist;
61 }
62
63 //call when a timer has fired, remove the current rtt entry as the existing one isn't working
64 void SOSPeerOTRTimerRemoveRTTTimeoutForPeer(SOSAccount* account, NSString* peerid)
65 {
66 CFNumberRef timeout = NULL;
67 CFErrorRef error = NULL;
68
69 CFMutableDictionaryRef timeouts = (CFMutableDictionaryRef)asDictionary(SOSAccountGetValue(account, kSOSAccountPeerNegotiationTimeouts, &error), NULL);
70 require_action_quiet(timeouts && (error == NULL), exit, secnotice("otrtimer","timeout dictionary doesn't exist"));
71
72 timeout = CFDictionaryGetValue(timeouts, (__bridge CFStringRef)peerid);
73 require_action_quiet(timeout, exit, secnotice("otrtimer","timeout for peerid: %@, doesn't exist", (__bridge CFStringRef)peerid));
74
75 CFDictionaryRemoveValue(timeouts, (__bridge CFStringRef)peerid);
76 SOSAccountSetValue(account, kSOSAccountPeerNegotiationTimeouts, timeouts, &error);
77 if(error){
78 secnotice("otrtimer","SOSAccountSetValue threw an error for key kSOSAccountPeerNegotiationTimeouts: %@", error);
79 }
80 exit:
81 CFReleaseNull(error);
82 }
83
84 void SOSPeerOTRTimerRemoveLastSentMessageTimestamp(SOSAccount* account, NSString* peerid)
85 {
86 NSMutableDictionary *peerToTimeLastSentDict = (__bridge NSMutableDictionary*)SOSAccountGetValue(account, kSOSAccountPeerLastSentTimestamp, NULL);
87
88 if(peerToTimeLastSentDict){
89 NSDate* storedDate = [peerToTimeLastSentDict objectForKey:peerid];
90 if(storedDate){
91 [peerToTimeLastSentDict removeObjectForKey:peerid];
92 SOSAccountSetValue(account, kSOSAccountPeerLastSentTimestamp, (__bridge CFMutableDictionaryRef)peerToTimeLastSentDict, NULL);
93 }
94 }
95 }
96
97 void SOSPeerOTRTimerIncreaseOTRNegotiationRetryCount(SOSAccount* account, NSString* peerid)
98 {
99 NSMutableDictionary* attemptsPerPeer = (__bridge NSMutableDictionary*)SOSAccountGetValue(account, kSOSAccountRenegotiationRetryCount, NULL);
100 if(!attemptsPerPeer){
101 attemptsPerPeer = [NSMutableDictionary dictionary];
102 }
103 NSNumber* attempt = [attemptsPerPeer objectForKey:peerid];
104 if(!attempt){
105 attempt = [[NSNumber alloc] initWithInt:1];
106 [attemptsPerPeer setObject:attempt forKey:peerid];
107 }
108 else{
109 NSNumber* newCount = [[NSNumber alloc]initWithInt:([attempt intValue]+1)];
110 [attemptsPerPeer setObject:newCount forKey:peerid];
111 secnotice("otr","OTR negotiation retry count: %d", [newCount intValue]);
112 }
113 SOSAccountSetValue(account, kSOSAccountRenegotiationRetryCount, (__bridge CFMutableDictionaryRef)attemptsPerPeer, NULL);
114 }
115
116 int SOSPeerOTRTimerTimeoutValue(SOSAccount* account, SOSPeerRef peer)
117 {
118 CFErrorRef error = NULL;
119 int timeoutIntValue = 0;
120
121 CFMutableDictionaryRef timeouts = (CFMutableDictionaryRef)asDictionary(SOSAccountGetValue(account, kSOSAccountPeerNegotiationTimeouts, &error), NULL);
122 require_action_quiet(timeouts, xit, secnotice("otrtimer","deadline value not available yet"));
123
124 CFNumberRef timeout = CFDictionaryGetValue(timeouts, SOSPeerGetID(peer));
125 require_action_quiet(timeout, xit, secnotice("otrtimer","deadline value not available yet"));
126
127 secnotice("otrtimer", "decided to wait %d before restarting negotiation", [(__bridge NSNumber*)timeout intValue]);
128 timeoutIntValue = [(__bridge NSNumber*)timeout intValue];
129
130 xit:
131 return timeoutIntValue;
132 }
133
134 void SOSPeerOTRTimerSetupAwaitingTimer(SOSAccount* account, SOSPeerRef peer, SOSEngineRef engine, SOSCoderRef coder)
135 {
136 //check which timeout value to use
137 int timeoutValue = SOSPeerOTRTimerTimeoutValue(account, peer);
138 CFStringRef peerid = CFRetainSafe(SOSPeerGetID(peer));
139
140 secnotice("otrtimer", "setting timer for peer: %@", peer);
141 __block dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
142 dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, timeoutValue * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0);
143 dispatch_source_set_event_handler(timer, ^{
144 secnotice("otrtimer","otrTimerFired fired");
145 SOSCCResetOTRNegotiation_Server(peerid);
146
147 });
148
149 dispatch_source_set_cancel_handler(timer, ^{
150 CFReleaseSafe(peerid);
151 });
152
153 dispatch_resume(timer);
154
155 SOSPeerSetOTRTimer(peer, timer);
156 }
157
158 //clear the max retry counter in the account object
159 void SOSPeerOTRTimerClearMaxRetryCount(SOSAccount* account, NSString* peerid)
160 {
161 secnotice("otrtimer", "negotiation finished! clearing max retry counter");
162 NSMutableDictionary* attemptsPerPeer = (__bridge NSMutableDictionary*)SOSAccountGetValue(account, kSOSAccountRenegotiationRetryCount, NULL);
163 if(!attemptsPerPeer){
164 attemptsPerPeer = [NSMutableDictionary dictionary];
165 }
166 [attemptsPerPeer removeObjectForKey:peerid];
167 SOSAccountSetValue(account, kSOSAccountRenegotiationRetryCount, (__bridge CFMutableDictionaryRef)attemptsPerPeer, NULL);
168 }
169