2 // secd-68-fullPeerInfoIntegrity.m
5 // Created by Richard Murphy on 4/30/20.
8 #import <Foundation/Foundation.h>
10 #include <Security/SecBase.h>
11 #include <Security/SecItem.h>
13 #include <CoreFoundation/CFDictionary.h>
15 #include "keychain/SecureObjectSync/SOSAccount.h"
16 #include <Security/SecureObjectSync/SOSCloudCircle.h>
17 #include "keychain/SecureObjectSync/SOSInternal.h"
18 #include "keychain/SecureObjectSync/SOSUserKeygen.h"
19 #include "keychain/SecureObjectSync/SOSTransport.h"
20 #include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h"
25 #include "secd_regressions.h"
26 #include "SOSTestDataSource.h"
28 #include "SOSRegressionUtilities.h"
29 #include <utilities/SecCFWrappers.h>
30 #include <Security/SecKeyPriv.h>
32 #include "keychain/securityd/SOSCloudCircleServer.h"
34 #include "SOSAccountTesting.h"
36 #include "SecdTestKeychainUtilities.h"
39 static NSString *makeCircle(SOSAccount* testaccount, CFMutableDictionaryRef changes) {
40 CFErrorRef error = NULL;
42 // Every time we resetToOffering should result in a new fpi
43 NSString *lastPeerID = testaccount.peerID;
44 ok(SOSAccountResetToOffering_wTxn(testaccount, &error), "Reset to offering (%@)", error);
46 is(ProcessChangesUntilNoChange(changes, testaccount, NULL), 1, "updates");
47 NSString *currentPeerID = testaccount.peerID;
48 ok(![lastPeerID isEqualToString:currentPeerID], "peerID changed on circle reset");
52 static void tests(void) {
53 CFErrorRef error = NULL;
54 CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10);
55 CFStringRef cfaccount = CFSTR("test@test.org");
57 CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
58 SOSAccount* testaccount = CreateAccountForLocalChanges(CFSTR("TestDev"), CFSTR("TestSource"));
60 // Just making an account object to mess with
61 ok(SOSAccountAssertUserCredentialsAndUpdate(testaccount, cfaccount, cfpassword, &error), "Credential setting (%@)", error);
62 is(ProcessChangesUntilNoChange(changes, testaccount, NULL), 1, "updates");
65 // make a circle then make sure fpi isn't reset just for a normal ensureFullPeerAvailable
66 NSString *lastPeerID = makeCircle(testaccount, changes);
67 ok([testaccount.trust ensureFullPeerAvailable:testaccount err:&error], "fullPeer is available");
68 NSString *currentPeerID = testaccount.peerID;
69 ok([lastPeerID isEqualToString: currentPeerID], "peerID did not alter in trip through ensureFullPeerAvailable");
72 // leaving a circle should reset the fpi
73 lastPeerID = makeCircle(testaccount, changes);
74 ok([testaccount.trust leaveCircle:testaccount err:&error], "leave the circle %@", error);
76 is(ProcessChangesUntilNoChange(changes, testaccount, NULL), 1, "updates");
77 currentPeerID = testaccount.peerID;
78 ok(![lastPeerID isEqualToString:currentPeerID], "peerID changed on leaving circle");
80 // break the fullpeerinfo by purging the private key - then fix in ensureFullPeerAvailable
81 lastPeerID = makeCircle(testaccount, changes);
82 ok(SOSFullPeerInfoPurgePersistentKey(testaccount.fullPeerInfo, &error), "purging persistent key %@", error);
83 currentPeerID = testaccount.peerID;
84 ok([lastPeerID isEqualToString:currentPeerID], "pre-ensuring peerID remains the same");
85 lastPeerID = currentPeerID;
86 ok([testaccount.trust ensureFullPeerAvailable:testaccount err:&error], "fullPeer is available");
87 currentPeerID = testaccount.peerID;
88 ok(![lastPeerID isEqualToString: currentPeerID], "peerID changed because fullPeerInfo fixed in ensureFullPeerAvailable");
89 lastPeerID = currentPeerID;
91 // If that last thing worked this peer won't be in the circle any more - changing fpi changes "me"
92 ok(SOSAccountAssertUserCredentialsAndUpdate(testaccount, cfaccount, cfpassword, &error), "Credential setting (%@)", error);
93 is(ProcessChangesUntilNoChange(changes, testaccount, NULL), 1, "updates");
95 ok(![testaccount isInCircle: &error], "No longer in circle");
97 // This join should work because the peer we left in the circle will be a ghost and there are no other peers
98 ok(SOSAccountJoinCircles_wTxn(testaccount, &error), "Apply to circle (%@)", error);
100 is(ProcessChangesUntilNoChange(changes, testaccount, NULL), 1, "updates");
101 ok([testaccount isInCircle: &error], "Is in circle");
102 currentPeerID = testaccount.peerID;
103 ok(![lastPeerID isEqualToString: currentPeerID], "peerID changed because fullPeerInfo changed during join");
105 CFReleaseNull(cfpassword);
111 int secd_68_fullPeerInfoIntegrity(int argc, char *const *argv)
115 secd_test_setup_temp_keychain(__FUNCTION__, NULL);