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