1 #import <XCTest/XCTest.h>
3 #import <Foundation/Foundation.h>
5 #import <KeychainCircle/KCJoiningSession.h>
6 #import <KeychainCircle/KCAccountKCCircleDelegate.h>
7 #import <KeychainCircle/KCError.h>
8 #import <KeychainCircle/KCJoiningMessages.h>
9 #import <KeychainCircle/NSError+KCCreationHelpers.h>
10 #import <KeychainCircle/KCAESGCMDuplexSession.h>
12 #include <Security/SecBase.h>
13 #include "keychain/SecureObjectSync/SOSFullPeerInfo.h"
14 #include "keychain/SecureObjectSync/SOSPeerInfoInternal.h"
16 #include <CommonCrypto/CommonRandomSPI.h>
19 static SecKeyRef GenerateFullECKey_internal(int keySize, NSError** error)
21 SecKeyRef full_key = NULL;
23 NSDictionary* keygen_parameters = @{ (__bridge NSString*)kSecAttrKeyType:(__bridge NSString*) kSecAttrKeyTypeEC,
24 (__bridge NSString*)kSecAttrKeySizeInBits: [NSNumber numberWithInt: keySize] };
27 (void) OSStatusError(SecKeyGeneratePair((__bridge CFDictionaryRef)keygen_parameters, NULL, &full_key), error, @"Generate Key failed");
32 static SecKeyRef GenerateFullECKey(int keySize, NSError** error) {
33 return GenerateFullECKey_internal(keySize, error);
36 static NSData* createTlkRequestMessage (KCAESGCMDuplexSession* aesSession) {
37 char someData[] = {1,2,3,4,5,6};
38 NSError* error = NULL;
39 NSData* rndPadding = [NSData dataWithBytes:(void*)someData length:sizeof(someData)];
40 KCJoiningMessage* tlkRequestMessage = [KCJoiningMessage messageWithType: kTLKRequest data:rndPadding error:&error];
41 return [tlkRequestMessage der];
44 @interface KCJoiningRequestTestDelegate : NSObject <KCJoiningRequestSecretDelegate, KCJoiningRequestCircleDelegate>
45 @property (readwrite) NSString* sharedSecret;
47 @property (readonly) NSString* accountCode;
48 @property (readonly) NSData* circleJoinData;
50 @property (readwrite) NSString* incorrectSecret;
51 @property (readwrite) int incorrectTries;
54 + (id) requestDelegateWithSecret:(NSString*) secret;
55 - (id) init NS_UNAVAILABLE;
56 - (id) initWithSecret: (NSString*) secret
57 incorrectSecret: (NSString*) wrongSecret
58 incorrectTries: (int) retries NS_DESIGNATED_INITIALIZER;
60 - (NSString*) verificationFailed: (bool) codeChanged;
61 - (SOSPeerInfoRef) copyPeerInfoError: (NSError**) error;
62 - (bool) processCircleJoinData: (NSData*) circleJoinData version:(PiggyBackProtocolVersion)version error: (NSError**)error ;
63 - (bool) processAccountCode: (NSString*) accountCode error: (NSError**)error;
67 @implementation KCJoiningRequestTestDelegate
69 + (id) requestDelegateWithSecret:(NSString*) secret {
70 return [[KCJoiningRequestTestDelegate alloc] initWithSecret:secret
75 + (id) requestDelegateWithSecret:(NSString*) secret
76 incorrectSecret:(NSString*) wrongSecret
77 incorrectTries:(int) retries {
78 return [[KCJoiningRequestTestDelegate alloc] initWithSecret:secret
79 incorrectSecret:wrongSecret
80 incorrectTries:retries];
84 - (id) initWithSecret: (NSString*) secret
85 incorrectSecret: (NSString*) incorrectSecret
86 incorrectTries: (int) retries {
87 if ( self = [super init] ) {
88 self.sharedSecret = secret;
89 self.incorrectSecret = incorrectSecret;
90 self.incorrectTries = retries;
95 - (NSString*) nextSecret {
96 if (self.incorrectTries > 0) {
97 self.incorrectTries -= 1;
98 return self.incorrectSecret;
100 return self.sharedSecret;
103 - (NSString*) secret {
104 return [self nextSecret];
107 - (NSString*) verificationFailed: (bool) codeChanged {
108 return [self nextSecret];
111 - (SOSPeerInfoRef) copyPeerInfoError: (NSError**) error {
115 - (bool) processCircleJoinData: (NSData*) circleJoinData version:(PiggyBackProtocolVersion)version error: (NSError**)error {
116 self->_circleJoinData = circleJoinData;
120 - (bool) processAccountCode: (NSString*) accountCode error: (NSError**)error {
121 self->_accountCode = accountCode;
127 @interface KCJoiningAcceptTestDelegate : NSObject <KCJoiningAcceptSecretDelegate, KCJoiningAcceptCircleDelegate>
128 @property (readonly) NSArray<NSString*>* secrets;
129 @property (readwrite) NSUInteger currentSecret;
130 @property (readwrite) int retriesLeft;
131 @property (readwrite) int retriesPerSecret;
133 @property (readonly) NSString* codeToUse;
134 @property (readonly) NSData* circleJoinData;
135 @property (readonly) SOSPeerInfoRef peerInfo;
137 + (id) acceptDelegateWithSecret: (NSString*) secret code: (NSString*) code;
138 + (id) acceptDelegateWithSecrets: (NSArray<NSString*>*) secrets retries: (int) retries code: (NSString*) code;
139 - (id) initWithSecrets: (NSArray<NSString*>*) secrets retries: (int) retries code: (NSString*) code NS_DESIGNATED_INITIALIZER;
141 - (NSString*) secret;
142 - (NSString*) accountCode;
144 - (KCRetryOrNot) verificationFailed: (NSError**) error;
145 - (NSData*) circleJoinDataFor: (SOSPeerInfoRef) peer
146 error: (NSError**) error;
148 - (id) init NS_UNAVAILABLE;
152 @implementation KCJoiningAcceptTestDelegate
154 + (id) acceptDelegateWithSecrets: (NSArray<NSString*>*) secrets retries: (int) retries code: (NSString*) code {
155 return [[KCJoiningAcceptTestDelegate alloc] initWithSecrets:secrets retries:retries code:code];
159 + (id) acceptDelegateWithSecret: (NSString*) secret code: (NSString*) code {
160 return [[KCJoiningAcceptTestDelegate alloc] initWithSecret:secret code:code];
163 - (id) initWithSecret: (NSString*) secret code: (NSString*) code {
164 return [self initWithSecrets:@[secret] retries:3 code:code];
167 - (id) initWithSecrets: (NSArray<NSString*>*) secrets retries: (int) retries code: (NSString*) code {
170 self->_secrets = secrets;
171 self.currentSecret = 0;
172 self->_retriesPerSecret = retries;
173 self->_retriesLeft = self.retriesPerSecret;
175 self->_codeToUse = code;
177 uint8_t joinDataBuffer[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
178 self->_circleJoinData = [NSData dataWithBytes: joinDataBuffer length: sizeof(joinDataBuffer) ];
183 - (KCRetryOrNot) advanceSecret {
184 if (self.retriesLeft == 0) {
185 self.currentSecret += 1;
186 if (self.currentSecret >= [self.secrets count]) {
187 self.currentSecret = [self.secrets count] - 1;
189 self.retriesLeft = self.retriesPerSecret;
190 return kKCRetryWithNewChallenge;
192 self.retriesLeft -= 1;
193 return kKCRetryWithSameChallenge;
197 - (NSString*) secret {
198 return self.secrets[self.currentSecret];
200 - (NSString*) accountCode {
201 return self.codeToUse;
204 - (KCRetryOrNot) verificationFailed: (NSError**) error {
205 return [self advanceSecret];
208 - (NSData*) circleJoinDataFor: (SOSPeerInfoRef) peer
209 error: (NSError**) error {
210 uint8_t joinDataBuffer[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
212 self->_peerInfo = peer;
213 return [NSData dataWithBytes: joinDataBuffer length: sizeof(joinDataBuffer) ];
216 -(NSData*) circleGetInitialSyncViews:(SOSInitialSyncFlags)flags error:(NSError**) error{
217 char testData[] = {0,1,2,3,4,5,6,7,8,9};
218 return [NSData dataWithBytes:testData length:sizeof(testData)];
219 //return [[KCJoiningAcceptAccountCircleDelegate delegate] circleGetInitialSyncViews:flags error:error]; //Need security entitlements!
224 @interface KCTLKRequestTest : XCTestCase
228 @implementation KCTLKRequestTest
232 // Put setup code here. This method is called before the invocation of each test method in the class.
236 // Put teardown code here. This method is called after the invocation of each test method in the class.
240 - (void)testTLKRequest {
241 NSError* error = nil;
243 NSString* secret = @"123456";
244 NSString* code = @"987654";
246 uint64_t dsid = 0x1234567887654321;
248 KCJoiningRequestTestDelegate* requestDelegate = [KCJoiningRequestTestDelegate requestDelegateWithSecret: secret];
249 KCJoiningRequestSecretSession *requestSession = [[KCJoiningRequestSecretSession alloc] initWithSecretDelegate:requestDelegate
251 rng:ccDRBGGetRngState()
254 NSData* initialMessage = [requestSession initialMessage: &error];
256 XCTAssertNotNil(initialMessage, @"No initial message");
257 XCTAssertNil(error, @"Got error %@", error);
259 KCJoiningAcceptTestDelegate* acceptDelegate = [KCJoiningAcceptTestDelegate acceptDelegateWithSecret:secret code:code];
260 KCJoiningAcceptSession* acceptSession = [[KCJoiningAcceptSession alloc] initWithSecretDelegate:acceptDelegate
261 circleDelegate:acceptDelegate
263 rng:ccDRBGGetRngState()
267 NSData* challenge = [acceptSession processMessage: initialMessage error: &error];
269 XCTAssertNotNil(challenge, @"No initial message");
270 XCTAssertNil(error, @"Got error %@", error);
273 NSData* response = [requestSession processMessage: challenge error: &error];
275 XCTAssertNotNil(response, @"No response message");
276 XCTAssertNil(error, @"Got error %@", error);
279 NSData* verification = [acceptSession processMessage: response error: &error];
281 XCTAssertNotNil(verification, @"No verification message");
282 XCTAssertNil(error, @"Got error %@", error);
285 NSData* doneMessage = [requestSession processMessage: verification error: &error];
287 XCTAssertNotNil(doneMessage, @"No response message");
288 XCTAssertNil(error, @"Got error %@", error);
290 XCTAssertTrue([requestSession isDone], @"SecretSession done");
291 XCTAssertFalse([acceptSession isDone], @"Unexpected accept session done");
293 KCAESGCMDuplexSession* aesSession = [requestSession session];
294 requestSession = nil;
296 KCJoiningRequestCircleSession* requestSecretSession = [KCJoiningRequestCircleSession sessionWithCircleDelegate:requestDelegate session:aesSession error:&error];
298 XCTAssertNotNil(requestSecretSession, @"No request secret session");
299 XCTAssertNil(error, @"Got error %@", error);
301 NSData* tlkRequestMessage = createTlkRequestMessage(aesSession);
302 XCTAssertNotNil(tlkRequestMessage, @"No TLKRequest message");
304 NSData* tlkMessage = [acceptSession processMessage:tlkRequestMessage error:&error];
305 XCTAssertNotNil(tlkMessage, @"No tlkData message");
306 XCTAssertNil(error, @"Got error %@", error);
308 KCJoiningMessage* receivedKCJoinMessage = [KCJoiningMessage messageWithDER:tlkMessage error:&error];
309 XCTAssertNotNil(receivedKCJoinMessage, @"No receivedKCJoinMessage message");
310 XCTAssertNil(error, @"Got error %@", error);
312 NSData* tlkDecryptedData = [aesSession decryptAndVerify:receivedKCJoinMessage.firstData error:&error];
313 XCTAssertNotNil(tlkDecryptedData, @"No tlkDecryptedData message");
314 XCTAssertNil(error, @"Got error %@", error);
316 //check for tlkc content
317 NSData* initialSync = [acceptDelegate circleGetInitialSyncViews:kSOSInitialSyncFlagTLKs error:&error];
318 XCTAssertNotNil(initialSync, @"No initialSync data");
319 XCTAssertNil(error, @"Got error %@", error);
321 XCTAssertEqualObjects(initialSync, tlkDecryptedData, @"TLK data is different.");