2 // secd-155-otrnegotiationmonitor.m
5 // Created by Michelle Auricchio on 6/5/17.
8 #import <Foundation/Foundation.h>
9 #include <Security/SecureObjectSync/SOSAccount.h>
10 #include <Security/SecureObjectSync/SOSCloudCircle.h>
11 #include <Security/SecureObjectSync/SOSInternal.h>
12 #include <Security/SecureObjectSync/SOSUserKeygen.h>
13 #include <Security/SecureObjectSync/SOSTransport.h>
14 #include <Security/SecureObjectSync/SOSViews.h>
15 #include <Security/SecureObjectSync/SOSAccountTrustClassic+Expansion.h>
16 #include <Security/SecureObjectSync/SOSTransportMessage.h>
17 #include <Security/SecureObjectSync/SOSPeerOTRTimer.h>
19 #import "SOSAccountTesting.h"
20 #import "SOSTransportTestTransports.h"
25 #include "secd_regressions.h"
26 #include "SOSTestDataSource.h"
28 #include "SOSRegressionUtilities.h"
29 #include "SecRecoveryKey.h"
31 #include <utilities/SecCFWrappers.h>
32 #include <Security/SecKeyPriv.h>
34 #include <securityd/SOSCloudCircleServer.h>
35 #include "SecdTestKeychainUtilities.h"
36 #include "SOSAccountTesting.h"
37 #import "SOSTransportTestTransports.h"
38 #include "SOSTestDevice.h"
39 #include "SOSTestDataSource.h"
40 #include <Security/SecureObjectSync/SOSTransportMessageIDS.h>
41 #include <Security/SecureObjectSync/SOSAccountTrustClassic+Circle.h>
42 static int kTestTestCount = 114;
44 static bool SOSAccountIsThisPeerIDMe(SOSAccount* account, CFStringRef peerID) {
45 SOSAccountTrustClassic* trust = account.trust;
46 SOSPeerInfoRef mypi = trust.peerInfo;
48 CFStringRef myPeerID = SOSPeerInfoGetPeerID(mypi);
50 return myPeerID && CFEqualSafe(myPeerID, peerID);
53 __unused static void ids_test_sync(SOSAccount* alice_account, SOSAccount* bob_account){
55 CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
56 __block bool SyncingCompletedOverIDS = false;
57 __block CFErrorRef localError = NULL;
59 SOSAccountTrustClassic* aliceTrust = alice_account.trust;
60 SOSAccountTrustClassic* bobTrust = bob_account.trust;
61 SOSDataSourceRef bob_ds = SOSDataSourceFactoryCreateDataSource(bob_account.factory, CFSTR("ak"), NULL);
62 SOSEngineRef bob_engine = bob_ds ? SOSDataSourceGetSharedEngine(bob_ds, NULL) : (SOSEngineRef) NULL;
63 SOSDataSourceRef alice_ds = SOSDataSourceFactoryCreateDataSource(alice_account.factory, CFSTR("ak"), NULL);
64 SOSEngineRef alice_engine = alice_ds ? SOSDataSourceGetSharedEngine(alice_ds, NULL) : (SOSEngineRef) NULL;
66 /* new routines to test */
67 __block NSString *bobID = bob_account.peerID;
68 __block NSString *aliceID = alice_account.peerID;
71 ///////////////////////////
73 ///////////////////////////
75 SOSCircleForEachValidPeer(aliceTrust.trustedCircle, alice_account.accountKey, ^(SOSPeerInfoRef peer) {
76 if (!SOSAccountIsThisPeerIDMe(alice_account, SOSPeerInfoGetPeerID(peer))) {
77 if(SOSPeerInfoShouldUseIDSTransport(aliceTrust.peerInfo, peer) &&
78 SOSPeerInfoShouldUseIDSMessageFragmentation(aliceTrust.peerInfo, peer)){
79 secnotice("IDS Transport","Syncing with IDS capable peers using IDS!");
81 CFMutableSetRef ids = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
82 CFSetAddValue(ids, SOSPeerInfoGetPeerID(peer));
84 SyncingCompletedOverIDS = [alice_account.ids_message_transport SOSTransportMessageSyncWithPeers:alice_account.ids_message_transport p:ids err:&localError];
90 SOSEngineWithPeerID(alice_engine, (__bridge CFStringRef)bobID, NULL, ^(SOSPeerRef bob_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) {
91 ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(alice_account , bobID));
92 ok(false == SOSPeerTimerForPeerExist(bob_peer));
93 ok(false == SOSPeerOTRTimerHaveAnRTTAvailable(alice_account, bobID));
94 ok(true == SOSCoderIsCoderInAwaitingState(coder));
97 ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL);
99 SOSCircleForEachValidPeer(bobTrust.trustedCircle, bob_account.accountKey, ^(SOSPeerInfoRef peer) {
100 if (!SOSAccountIsThisPeerIDMe(bob_account, SOSPeerInfoGetPeerID(peer))) {
101 if(SOSPeerInfoShouldUseIDSTransport(bobTrust.peerInfo, peer) &&
102 SOSPeerInfoShouldUseIDSMessageFragmentation(bobTrust.peerInfo, peer)){
103 secnotice("IDS Transport","Syncing with IDS capable peers using IDS!");
105 CFMutableSetRef ids = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
106 CFSetAddValue(ids, SOSPeerInfoGetPeerID(peer));
108 SyncingCompletedOverIDS = [(SOSMessageIDSTest*)bob_account.ids_message_transport SOSTransportMessageSyncWithPeers:(SOSMessageIDSTest*)bob_account.ids_message_transport p:ids err:&localError];
114 ok(SyncingCompletedOverIDS, "synced items over IDS");
116 SOSEngineWithPeerID(bob_engine, (__bridge CFStringRef)aliceID, NULL, ^(SOSPeerRef alice_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) {
117 ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(bob_account , aliceID));
118 ok(false == SOSPeerTimerForPeerExist(alice_peer));
119 ok(false == SOSPeerOTRTimerHaveAnRTTAvailable(bob_account, aliceID));
122 ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL);
124 SOSEngineWithPeerID(alice_engine, (__bridge CFStringRef)bobID, NULL, ^(SOSPeerRef bob_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) {
125 ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(alice_account , bobID));
126 ok(false == SOSPeerTimerForPeerExist(bob_peer));
127 ok(false == SOSPeerOTRTimerHaveAnRTTAvailable(alice_account, bobID));
128 ok(true == SOSCoderIsCoderInAwaitingState(coder));
131 ///////////////////////////
132 //second sync exchange //
133 ///////////////////////////
135 SOSCircleForEachValidPeer(aliceTrust.trustedCircle, alice_account.accountKey, ^(SOSPeerInfoRef peer) {
136 if (!SOSAccountIsThisPeerIDMe(alice_account, SOSPeerInfoGetPeerID(peer))) {
137 if(SOSPeerInfoShouldUseIDSTransport(aliceTrust.peerInfo, peer) &&
138 SOSPeerInfoShouldUseIDSMessageFragmentation(aliceTrust.peerInfo, peer)){
139 secnotice("IDS Transport","Syncing with IDS capable peers using IDS!");
141 CFMutableSetRef ids = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
142 CFSetAddValue(ids, SOSPeerInfoGetPeerID(peer));
144 SyncingCompletedOverIDS = [alice_account.ids_message_transport SOSTransportMessageSyncWithPeers:alice_account.ids_message_transport p:ids err:&localError];
150 SOSEngineWithPeerID(alice_engine, (__bridge CFStringRef)bobID, NULL, ^(SOSPeerRef bob_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) {
151 ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(alice_account , bobID));
152 ok(false == SOSPeerTimerForPeerExist(bob_peer));
153 ok(false == SOSPeerOTRTimerHaveAnRTTAvailable(alice_account, bobID));
154 ok(true == SOSCoderIsCoderInAwaitingState(coder));
157 ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL);
159 SOSCircleForEachValidPeer(bobTrust.trustedCircle, bob_account.accountKey, ^(SOSPeerInfoRef peer) {
160 if (!SOSAccountIsThisPeerIDMe(bob_account, SOSPeerInfoGetPeerID(peer))) {
161 if(SOSPeerInfoShouldUseIDSTransport(bobTrust.peerInfo, peer) &&
162 SOSPeerInfoShouldUseIDSMessageFragmentation(bobTrust.peerInfo, peer)){
163 secnotice("IDS Transport","Syncing with IDS capable peers using IDS!");
165 CFMutableSetRef ids = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
166 CFSetAddValue(ids, SOSPeerInfoGetPeerID(peer));
168 SyncingCompletedOverIDS = [(SOSMessageIDSTest*)bob_account.ids_message_transport SOSTransportMessageSyncWithPeers:(SOSMessageIDSTest*)bob_account.ids_message_transport p:ids err:&localError];
174 ok(SyncingCompletedOverIDS, "synced items over IDS");
176 SOSEngineWithPeerID(bob_engine, (__bridge CFStringRef)aliceID, NULL, ^(SOSPeerRef alice_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) {
177 ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(bob_account , aliceID));
178 ok(false == SOSPeerTimerForPeerExist(alice_peer));
179 ok(false == SOSPeerOTRTimerHaveAnRTTAvailable(bob_account, aliceID));
182 ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL);
184 SOSEngineWithPeerID(alice_engine, (__bridge CFStringRef)bobID, NULL, ^(SOSPeerRef bob_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) {
185 ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(alice_account , bobID));
186 ok(false == SOSPeerTimerForPeerExist(bob_peer));
187 ok(true == SOSPeerOTRTimerHaveAnRTTAvailable(alice_account, bobID));
188 ok(false == SOSCoderIsCoderInAwaitingState(coder));
191 CFReleaseNull(changes);
195 static void tests(void)
197 CFErrorRef error = NULL;
199 CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
200 CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10);
201 CFStringRef cfaccount = CFSTR("test@test.org");
203 SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("ak"));
204 SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("ak"));
206 ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error);
208 // Bob wins writing at this point, feed the changes back to alice.
209 is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates");
211 ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error);
212 CFReleaseNull(cfpassword);
213 CFReleaseNull(error);
215 ok(NULL != alice_account, "Alice Created");
216 ok(NULL != bob_account, "Bob Created");
218 ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error);
219 CFReleaseNull(error);
221 is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates");
223 ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error);
224 CFReleaseNull(error);
226 is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates");
229 CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error);
231 ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error);
232 ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error);
233 CFReleaseNull(error);
234 CFReleaseNull(applicants);
237 is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates");
239 accounts_agree("bob&alice pair", bob_account, alice_account);
241 CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error);
242 ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error);
243 CFReleaseNull(peers);
245 SOSDataSourceRef alice_ds = SOSDataSourceFactoryCreateDataSource(alice_account.factory, CFSTR("ak"), NULL);
246 SOSEngineRef alice_engine = alice_ds ? SOSDataSourceGetSharedEngine(alice_ds, NULL) : (SOSEngineRef) NULL;
248 ok(false == SOSEngineHandleCodedMessage(alice_account, alice_engine, (__bridge CFStringRef)bob_account.peerID, NULL, NULL));
250 SOSDataSourceRef bob_ds = SOSDataSourceFactoryCreateDataSource(bob_account.factory, CFSTR("ak"), NULL);
251 SOSEngineRef bob_engine = bob_ds ? SOSDataSourceGetSharedEngine(bob_ds, NULL) : (SOSEngineRef) NULL;
253 ok(false == SOSEngineHandleCodedMessage(bob_account, bob_engine, (__bridge CFStringRef)alice_account.peerID, NULL, NULL));
255 /* new routines to test */
256 __block NSString *bobID = bob_account.peerID;
257 __block NSString *aliceID = alice_account.peerID;
259 SOSEngineWithPeerID(bob_engine, (__bridge CFStringRef)aliceID, NULL, ^(SOSPeerRef alice_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) {
260 ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(bob_account , aliceID));
261 ok(false == SOSPeerTimerForPeerExist(alice_peer));
262 ok(false == SOSPeerOTRTimerHaveAnRTTAvailable(bob_account, aliceID));
265 SOSEngineWithPeerID(alice_engine, (__bridge CFStringRef)bobID, NULL, ^(SOSPeerRef bob_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) {
266 ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(alice_account , bobID));
267 ok(false == SOSPeerTimerForPeerExist(bob_peer));
268 ok(false == SOSPeerOTRTimerHaveAnRTTAvailable(alice_account, bobID));
271 //creating test devices
274 // Optionally prefix each peer with name to make them more unique.
275 CFArrayRef deviceIDs = CFArrayCreateForCFTypes(kCFAllocatorDefault,alice_account.peerID, bob_account.peerID, NULL);
276 CFSetRef views = SOSViewsCopyTestV2Default();
277 CFMutableArrayRef peerMetas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
278 CFStringRef deviceID;
279 CFArrayForEachC(deviceIDs, deviceID) {
280 SOSPeerMetaRef peerMeta = SOSPeerMetaCreateWithComponents(deviceID, views, NULL);
281 CFArrayAppendValue(peerMetas, peerMeta);
282 CFReleaseNull(peerMeta);
285 CFReleaseNull(views);
286 CFArrayForEachC(deviceIDs, deviceID) {
287 SOSTestDeviceRef device = SOSTestDeviceCreateWithDbNamed(kCFAllocatorDefault, deviceID, deviceID);
288 SOSTestDeviceSetPeerIDs(device, peerMetas, version, NULL);
290 if([alice_account.peerID isEqual: (__bridge id)(deviceID)]){
291 alice_account.factory = device->dsf;
292 SOSTestDeviceAddGenericItem(device, CFSTR("Alice"), CFSTR("Alice-add"));
295 bob_account.factory = device->dsf;
296 SOSTestDeviceAddGenericItem(device, CFSTR("Bob"), CFSTR("Bob-add"));
299 CFReleaseNull(device);
301 CFReleaseNull(deviceIDs);
302 CFReleaseNull(peerMetas);
304 SOSUnregisterAllTransportMessages();
305 CFArrayRemoveAllValues(message_transports);
307 SOSAccountTrustClassic* aliceTrust = alice_account.trust;
308 SOSAccountTrustClassic* bobTrust = bob_account.trust;
310 alice_account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:alice_account andAccountName:CFSTR("Alice") andCircleName:SOSCircleGetName(aliceTrust.trustedCircle) err:&error ];
312 bob_account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:bob_account andAccountName:CFSTR("Bob") andCircleName:SOSCircleGetName(bobTrust.trustedCircle) err:&error];
314 ok(alice_account.ids_message_transport != NULL, "Alice Account, Created IDS Test Transport");
315 ok(bob_account.ids_message_transport != NULL, "Bob Account, Created IDS Test Transport");
317 bool result = [alice_account.trust modifyCircle:alice_account.circle_transport err:&error action:^bool(SOSCircleRef circle) {
318 CFErrorRef localError = NULL;
320 SOSFullPeerInfoUpdateTransportType(aliceTrust.fullPeerInfo, SOSTransportMessageTypeIDSV2, &localError);
321 SOSFullPeerInfoUpdateTransportPreference(aliceTrust.fullPeerInfo, kCFBooleanFalse, &localError);
322 SOSFullPeerInfoUpdateTransportFragmentationPreference(aliceTrust.fullPeerInfo, kCFBooleanTrue, &localError);
323 SOSFullPeerInfoUpdateTransportAckModelPreference(aliceTrust.fullPeerInfo, kCFBooleanTrue, &localError);
325 return SOSCircleHasPeer(circle, aliceTrust.peerInfo, NULL);
328 ok(result, "Alice account update circle with transport type");
330 is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates");
332 result = [bob_account.trust modifyCircle:bob_account.circle_transport err:&error action:^bool(SOSCircleRef circle) {
333 CFErrorRef localError = NULL;
335 SOSFullPeerInfoUpdateTransportType(bobTrust.fullPeerInfo, SOSTransportMessageTypeIDSV2, &localError);
336 SOSFullPeerInfoUpdateTransportPreference(bobTrust.fullPeerInfo, kCFBooleanFalse, &localError);
337 SOSFullPeerInfoUpdateTransportFragmentationPreference(bobTrust.fullPeerInfo, kCFBooleanTrue, &localError);
338 SOSFullPeerInfoUpdateTransportAckModelPreference(bobTrust.fullPeerInfo, kCFBooleanTrue, &localError);
340 return SOSCircleHasPeer(circle, bobTrust.peerInfo, NULL);
343 ok(result, "Bob account update circle with transport type");
344 is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates");
346 CFStringRef alice_transportType =SOSPeerInfoCopyTransportType(alice_account.peerInfo);
347 CFStringRef bob_accountTransportType = SOSPeerInfoCopyTransportType(bob_account.peerInfo);
348 ok(CFEqualSafe(alice_transportType, CFSTR("IDS2.0")), "Alice transport type not IDS");
349 ok(CFEqualSafe(bob_accountTransportType, CFSTR("IDS2.0")), "Bob transport type not IDS");
351 CFReleaseNull(alice_transportType);
352 CFReleaseNull(bob_accountTransportType);
354 SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)alice_account.ids_message_transport, CFSTR("Alice Account"));
355 ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)alice_account.ids_message_transport) != NULL, "retrieved getting account name");
356 ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(alice_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy");
358 SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)bob_account.ids_message_transport, CFSTR("Bob Account"));
359 ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)bob_account.ids_message_transport) != NULL, "retrieved getting account name");
360 ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(bob_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy");
363 ok(SOSAccountSetMyDSID_wTxn(alice_account, CFSTR("Alice"),&error), "Setting IDS device ID");
364 CFStringRef alice_dsid = SOSAccountCopyDeviceID(alice_account, &error);
365 ok(CFEqualSafe(alice_dsid, CFSTR("Alice")), "Getting IDS device ID");
366 CFReleaseNull(alice_dsid);
368 ok(SOSAccountSetMyDSID_wTxn(bob_account, CFSTR("Bob"),&error), "Setting IDS device ID");
369 CFStringRef bob_dsid = SOSAccountCopyDeviceID(bob_account, &error);
370 ok(CFEqualSafe(bob_dsid, CFSTR("Bob")), "Getting IDS device ID");
371 CFReleaseNull(bob_dsid);
372 is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates");
374 ok(SOSAccountEnsurePeerRegistration(alice_account, NULL), "ensure peer registration - alice");
376 ok(SOSAccountEnsurePeerRegistration(bob_account, NULL), "ensure peer registration - bob");
378 // ids_test_sync(alice_account, bob_account);
381 int secd_155_otr_negotiation_monitor(int argc, char *const *argv)
383 plan_tests(kTestTestCount);
385 secd_test_setup_temp_keychain(__FUNCTION__, NULL);