]> git.saurik.com Git - apple/security.git/blob - KeychainCircle/Tests/KCJoiningSessionTest.m
Security-59754.80.3.tar.gz
[apple/security.git] / KeychainCircle / Tests / KCJoiningSessionTest.m
1 //
2 // KCJoiningSessionTest.m
3 // Security
4 //
5 //
6
7 #import <XCTest/XCTest.h>
8
9 #import <Foundation/Foundation.h>
10
11 #import <KeychainCircle/KCJoiningSession.h>
12 #import <KeychainCircle/KCError.h>
13 #import <KeychainCircle/NSError+KCCreationHelpers.h>
14 #import <KeychainCircle/KCAESGCMDuplexSession.h>
15
16 #include <Security/SecBase.h>
17 #include "keychain/SecureObjectSync/SOSFullPeerInfo.h"
18 #include "keychain/SecureObjectSync/SOSPeerInfoInternal.h"
19
20
21 static SecKeyRef GenerateFullECKey_internal(int keySize, NSError** error)
22 {
23 SecKeyRef full_key = NULL;
24
25 NSDictionary* keygen_parameters = @{ (__bridge NSString*)kSecAttrKeyType:(__bridge NSString*) kSecAttrKeyTypeEC,
26 (__bridge NSString*)kSecAttrKeySizeInBits: [NSNumber numberWithInt: keySize] };
27
28
29 (void) OSStatusError(SecKeyGeneratePair((__bridge CFDictionaryRef)keygen_parameters, NULL, &full_key), error, @"Generate Key failed");
30
31 return full_key;
32 }
33
34 static SecKeyRef GenerateFullECKey(int keySize, NSError** error) {
35 return GenerateFullECKey_internal(keySize, error);
36 }
37
38
39 @interface KCJoiningRequestTestDelegate : NSObject <KCJoiningRequestSecretDelegate, KCJoiningRequestCircleDelegate>
40 @property (readwrite) NSString* sharedSecret;
41
42 @property (readonly) NSString* accountCode;
43 @property (readonly) NSData* circleJoinData;
44 @property (readwrite) SOSPeerInfoRef peerInfo;
45
46 @property (readwrite) NSString* incorrectSecret;
47 @property (readwrite) int incorrectTries;
48
49
50 + (id) requestDelegateWithSecret:(NSString*) secret;
51 - (id) init NS_UNAVAILABLE;
52 - (id) initWithSecret: (NSString*) secret
53 incorrectSecret: (NSString*) wrongSecret
54 incorrectTries: (int) retries NS_DESIGNATED_INITIALIZER;
55 - (NSString*) secret;
56 - (NSString*) verificationFailed: (bool) codeChanged;
57 - (SOSPeerInfoRef) copyPeerInfoError: (NSError**) error;
58 - (bool) processCircleJoinData: (NSData*) circleJoinData version:(PiggyBackProtocolVersion)version error: (NSError**)error ;
59 - (bool) processAccountCode: (NSString*) accountCode error: (NSError**)error;
60
61 @end
62
63 @implementation KCJoiningRequestTestDelegate
64
65 - (void)dealloc {
66 if(_peerInfo) {
67 CFRelease(_peerInfo);
68 }
69 }
70
71 + (id) requestDelegateWithSecret:(NSString*) secret {
72 return [[KCJoiningRequestTestDelegate alloc] initWithSecret:secret
73 incorrectSecret:@""
74 incorrectTries:0];
75 }
76
77 + (id) requestDelegateWithSecret:(NSString*) secret
78 incorrectSecret:(NSString*) wrongSecret
79 incorrectTries:(int) retries {
80 return [[KCJoiningRequestTestDelegate alloc] initWithSecret:secret
81 incorrectSecret:wrongSecret
82 incorrectTries:retries];
83 }
84
85
86 - (id) initWithSecret: (NSString*) secret
87 incorrectSecret: (NSString*) incorrectSecret
88 incorrectTries: (int) retries {
89 if ((self = [super init])) {
90
91 SecKeyRef signingKey = GenerateFullECKey(256, NULL);
92 SecKeyRef octagonSigningKey = GenerateFullECKey(384, NULL);
93 SecKeyRef octagonEncryptionKey = GenerateFullECKey(384, NULL);
94
95 SOSPeerInfoRef newPeerInfo = SOSPeerInfoCreate(NULL, (__bridge CFDictionaryRef) @{(__bridge NSString*)kPIUserDefinedDeviceNameKey:@"Fakey"}, NULL, signingKey, octagonSigningKey, octagonEncryptionKey, NULL);
96
97 if (newPeerInfo == NULL) {
98 return nil;
99 }
100 self.peerInfo = newPeerInfo;
101 CFRelease(newPeerInfo);
102 newPeerInfo = NULL;
103
104 self.sharedSecret = secret;
105 self.incorrectSecret = incorrectSecret;
106 self.incorrectTries = retries;
107
108 }
109 return self;
110 }
111
112 - (NSString*) nextSecret {
113 if (self.incorrectTries > 0) {
114 self.incorrectTries -= 1;
115 return self.incorrectSecret;
116 }
117 return self.sharedSecret;
118 }
119
120 - (NSString*) secret {
121 return [self nextSecret];
122 }
123
124 - (NSString*) verificationFailed: (bool) codeChanged {
125 return [self nextSecret];
126 }
127
128 - (SOSPeerInfoRef) copyPeerInfoError: (NSError**) error {
129 if(!self.peerInfo) {
130 return NULL;
131 }
132
133 return (SOSPeerInfoRef) CFRetain(self.peerInfo);
134 }
135
136 - (bool) processCircleJoinData: (NSData*) circleJoinData version:(PiggyBackProtocolVersion)version error: (NSError**)error {
137 self->_circleJoinData = circleJoinData;
138 return true;
139 }
140
141 - (bool) processAccountCode: (NSString*) accountCode error: (NSError**)error {
142 self->_accountCode = accountCode;
143 return true;
144 }
145
146 @end
147
148 @interface KCJoiningAcceptTestDelegate : NSObject <KCJoiningAcceptSecretDelegate, KCJoiningAcceptCircleDelegate>
149 @property (readonly) NSArray<NSString*>* secrets;
150 @property (readwrite) NSUInteger currentSecret;
151 @property (readwrite) int retriesLeft;
152 @property (readwrite) int retriesPerSecret;
153
154 @property (readonly) NSString* codeToUse;
155 @property (readonly) NSData* circleJoinData;
156 @property (readonly) SOSPeerInfoRef peerInfo;
157
158 + (id) acceptDelegateWithSecret: (NSString*) secret code: (NSString*) code;
159 + (id) acceptDelegateWithSecrets: (NSArray<NSString*>*) secrets retries: (int) retries code: (NSString*) code;
160 - (id) initWithSecrets: (NSArray<NSString*>*) secrets retries: (int) retries code: (NSString*) code NS_DESIGNATED_INITIALIZER;
161
162
163 - (NSString*) secret;
164 - (NSString*) accountCode;
165
166 - (KCRetryOrNot) verificationFailed: (NSError**) error;
167 - (NSData*) circleJoinDataFor: (SOSPeerInfoRef) peer
168 error: (NSError**) error;
169
170 - (id) init NS_UNAVAILABLE;
171
172 @end
173
174 @implementation KCJoiningAcceptTestDelegate
175
176 + (id) acceptDelegateWithSecrets: (NSArray<NSString*>*) secrets retries: (int) retries code: (NSString*) code {
177 return [[KCJoiningAcceptTestDelegate alloc] initWithSecrets:secrets retries:retries code:code];
178
179 }
180
181 + (id) acceptDelegateWithSecret: (NSString*) secret code: (NSString*) code {
182 return [[KCJoiningAcceptTestDelegate alloc] initWithSecret:secret code:code];
183 }
184
185 - (id) initWithSecret: (NSString*) secret code: (NSString*) code {
186 return [self initWithSecrets:@[secret] retries:3 code:code];
187 }
188
189 - (id) initWithSecrets: (NSArray<NSString*>*) secrets retries: (int) retries code: (NSString*) code {
190 if ((self = [super init])) {
191 self->_secrets = secrets;
192 self.currentSecret = 0;
193 self->_retriesPerSecret = retries;
194 self->_retriesLeft = self.retriesPerSecret;
195
196 self->_codeToUse = code;
197
198 uint8_t joinDataBuffer[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
199 self->_circleJoinData = [NSData dataWithBytes: joinDataBuffer length: sizeof(joinDataBuffer) ];
200 }
201 return self;
202 }
203
204 - (KCRetryOrNot) advanceSecret {
205 if (self.retriesLeft == 0) {
206 self.currentSecret += 1;
207 if (self.currentSecret >= [self.secrets count]) {
208 self.currentSecret = [self.secrets count] - 1;
209 }
210 self.retriesLeft = self.retriesPerSecret;
211 return kKCRetryWithNewChallenge;
212 } else {
213 self.retriesLeft -= 1;
214 return kKCRetryWithSameChallenge;
215 }
216 }
217
218 - (NSString*) secret {
219 return self.secrets[self.currentSecret];
220 }
221 - (NSString*) accountCode {
222 return self.codeToUse;
223 }
224
225 - (KCRetryOrNot) verificationFailed: (NSError**) error {
226 return [self advanceSecret];
227 }
228
229 - (NSData*) circleJoinDataFor: (SOSPeerInfoRef) peer
230 error: (NSError**) error {
231 uint8_t joinDataBuffer[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
232
233 self->_peerInfo = peer;
234 return [NSData dataWithBytes: joinDataBuffer length: sizeof(joinDataBuffer) ];
235 }
236
237 -(NSData*) circleGetInitialSyncViews:(SOSInitialSyncFlags)flags error:(NSError**) error{
238 return [NSData data];
239 }
240
241 @end
242
243
244 @interface KCJoiningSessionTest : XCTestCase
245
246 @end
247
248 @implementation KCJoiningSessionTest
249
250 - (void)setUp {
251 [super setUp];
252 // Put setup code here. This method is called before the invocation of each test method in the class.
253 }
254
255 - (void)tearDown {
256 // Put teardown code here. This method is called after the invocation of each test method in the class.
257 [super tearDown];
258 }
259
260 - (void)testJoiningSession {
261 NSError* error = nil;
262
263 NSString* secret = @"123456";
264 NSString* code = @"987654";
265
266 uint64_t dsid = 0x1234567887654321;
267
268 KCJoiningRequestTestDelegate* requestDelegate = [KCJoiningRequestTestDelegate requestDelegateWithSecret: secret];
269 KCJoiningRequestSecretSession *requestSession = [[KCJoiningRequestSecretSession alloc] initWithSecretDelegate:requestDelegate
270 dsid:dsid
271 rng:ccrng(NULL)
272 error:&error];
273
274 NSData* initialMessage = [requestSession initialMessage: &error];
275
276 XCTAssertNotNil(initialMessage, @"No initial message");
277 XCTAssertNil(error, @"Got error %@", error);
278
279 KCJoiningAcceptTestDelegate* acceptDelegate = [KCJoiningAcceptTestDelegate acceptDelegateWithSecret:secret code:code];
280 KCJoiningAcceptSession* acceptSession = [[KCJoiningAcceptSession alloc] initWithSecretDelegate:acceptDelegate
281 circleDelegate:acceptDelegate
282 dsid:dsid
283 rng:ccrng(NULL)
284 error:&error];
285
286 error = nil;
287 NSData* challenge = [acceptSession processMessage: initialMessage error: &error];
288
289 XCTAssertNotNil(challenge, @"No initial message");
290 XCTAssertNil(error, @"Got error %@", error);
291
292 error = nil;
293 NSData* response = [requestSession processMessage: challenge error: &error];
294
295 XCTAssertNotNil(response, @"No response message");
296 XCTAssertNil(error, @"Got error %@", error);
297
298 error = nil;
299 NSData* verification = [acceptSession processMessage: response error: &error];
300
301 XCTAssertNotNil(verification, @"No verification message");
302 XCTAssertNil(error, @"Got error %@", error);
303
304 error = nil;
305 NSData* doneMessage = [requestSession processMessage: verification error: &error];
306
307 XCTAssertNotNil(doneMessage, @"No response message");
308 XCTAssertNil(error, @"Got error %@", error);
309
310 XCTAssertTrue([requestSession isDone], @"SecretSession done");
311 XCTAssertFalse([acceptSession isDone], @"Unexpected accept session done");
312
313 KCAESGCMDuplexSession* aesSession = [requestSession session];
314 requestSession = nil;
315
316 KCJoiningRequestCircleSession* requestSecretSession = [KCJoiningRequestCircleSession sessionWithCircleDelegate:requestDelegate session:aesSession error:&error];
317
318 XCTAssertNotNil(requestSecretSession, @"No request secret session");
319 XCTAssertNil(error, @"Got error %@", error);
320
321 error = nil;
322 NSData* peerInfoMessage = [requestSecretSession initialMessage: &error];
323
324 XCTAssertNotNil(peerInfoMessage, @"No peerInfo message");
325 XCTAssertNil(error, @"Got error %@", error);
326
327 XCTAssertEqualObjects(requestDelegate.accountCode, acceptDelegate.codeToUse, @"Code made it");
328
329 error = nil;
330 NSData* blobMessage = [acceptSession processMessage:peerInfoMessage error: &error];
331
332 XCTAssertNotNil(blobMessage, @"No blob message");
333 XCTAssertNil(error, @"Got error %@", error);
334
335 // We have different peer_info types due to wierd linking of our tests.
336 // Compare the der representations:
337 NSData* rp_der = requestDelegate.peerInfo != nil ? (__bridge_transfer NSData*) SOSPeerInfoCopyEncodedData(requestDelegate.peerInfo, NULL, NULL) : nil;
338 NSData* ap_der = acceptDelegate.peerInfo != nil ? (__bridge_transfer NSData*) SOSPeerInfoCopyEncodedData(acceptDelegate.peerInfo, NULL, NULL) : nil;
339
340 XCTAssertEqualObjects(rp_der, ap_der, @"Peer infos match");
341
342 error = nil;
343 NSData* nothing = [requestSecretSession processMessage:blobMessage error: &error];
344
345 XCTAssertEqualObjects(requestDelegate.circleJoinData, acceptDelegate.circleJoinData);
346
347 XCTAssertNotNil(nothing, @"No initial message");
348 XCTAssertNil(error, @"Got error %@", error);
349
350 XCTAssertTrue([requestSecretSession isDone], @"requesor done");
351 XCTAssertTrue([acceptSession isDone], @"acceptor done");
352
353 }
354
355 - (void)testJoiningSessionRetry {
356 NSError* error = nil;
357
358 NSString* secret = @"123456";
359 NSString* code = @"987654";
360
361 uint64_t dsid = 0x1234567887654321;
362
363 KCJoiningRequestTestDelegate* requestDelegate = [KCJoiningRequestTestDelegate requestDelegateWithSecret: secret incorrectSecret:@"777888" incorrectTries:3];
364 KCJoiningRequestSecretSession *requestSession = [[KCJoiningRequestSecretSession alloc] initWithSecretDelegate:requestDelegate
365 dsid:dsid
366 rng:ccrng(NULL)
367 error:&error];
368
369 NSData* initialMessage = [requestSession initialMessage: &error];
370
371 XCTAssertNotNil(initialMessage, @"No initial message");
372 XCTAssertNil(error, @"Got error %@", error);
373
374 KCJoiningAcceptTestDelegate* acceptDelegate = [KCJoiningAcceptTestDelegate acceptDelegateWithSecret:secret code:code];
375 KCJoiningAcceptSession* acceptSession = [[KCJoiningAcceptSession alloc] initWithSecretDelegate:acceptDelegate
376 circleDelegate:acceptDelegate
377 dsid:dsid
378 rng:ccrng(NULL)
379 error:&error];
380
381 error = nil;
382 NSData* challenge = [acceptSession processMessage: initialMessage error: &error];
383
384 XCTAssertNotNil(challenge, @"No initial message");
385 XCTAssertNil(error, @"Got error %@", error);
386
387 NSData* response = nil;
388 NSData* verification = nil;
389
390 NSData* nextChallenge = challenge;
391 for (int tries = 0; tries < 4; ++tries) {
392 error = nil;
393 response = [requestSession processMessage: nextChallenge error: &error];
394
395 XCTAssertNotNil(response, @"No response message");
396 XCTAssertNil(error, @"Got error %@", error);
397
398 XCTAssertNotEqualObjects(requestDelegate.accountCode, acceptDelegate.codeToUse, @"Code should not make it");
399
400 error = nil;
401 verification = [acceptSession processMessage: response error: &error];
402
403 XCTAssertNotNil(verification, @"No verification message");
404 XCTAssertNil(error, @"Got error %@", error);
405
406 nextChallenge = verification;
407 }
408
409 error = nil;
410 NSData* doneMessage = [requestSession processMessage: verification error: &error];
411
412 XCTAssertNotNil(doneMessage, @"No response message");
413 XCTAssertNil(error, @"Got error %@", error);
414
415 XCTAssertTrue([requestSession isDone], @"SecretSession done");
416 XCTAssertFalse([acceptSession isDone], @"Unexpected accept session done");
417
418 KCAESGCMDuplexSession* aesSession = [requestSession session];
419 requestSession = nil;
420
421 error = nil;
422 KCJoiningRequestCircleSession* requestSecretSession = [KCJoiningRequestCircleSession sessionWithCircleDelegate:requestDelegate session:aesSession error:&error];
423
424 XCTAssertNotNil(requestSecretSession, @"No request secret session");
425 XCTAssertNil(error, @"Got error %@", error);
426
427 error = nil;
428 NSData* peerInfoMessage = [requestSecretSession initialMessage: &error];
429
430 XCTAssertNotNil(peerInfoMessage, @"No peerInfo message");
431 XCTAssertNil(error, @"Got error %@", error);
432
433 XCTAssertEqualObjects(requestDelegate.accountCode, acceptDelegate.codeToUse, @"Code made it");
434
435 error = nil;
436 NSData* blobMessage = [acceptSession processMessage:peerInfoMessage error: &error];
437
438 XCTAssertNotNil(blobMessage, @"No blob message");
439 XCTAssertNil(error, @"Got error %@", error);
440
441 // We have different peer_info types due to wierd linking of our tests.
442 // Compare the der representations:
443 NSData* rp_der = requestDelegate.peerInfo != nil ? (__bridge_transfer NSData*) SOSPeerInfoCopyEncodedData(requestDelegate.peerInfo, NULL, NULL) : nil;
444 NSData* ap_der = acceptDelegate.peerInfo != nil ? (__bridge_transfer NSData*) SOSPeerInfoCopyEncodedData(acceptDelegate.peerInfo, NULL, NULL) : nil;
445
446 XCTAssertEqualObjects(rp_der, ap_der, @"Peer infos match");
447
448 error = nil;
449 NSData* nothing = [requestSecretSession processMessage:blobMessage error: &error];
450
451 XCTAssertEqualObjects(requestDelegate.circleJoinData, acceptDelegate.circleJoinData);
452
453 XCTAssertNotNil(nothing, @"No initial message");
454 XCTAssertNil(error, @"Got error %@", error);
455
456 XCTAssertTrue([requestSecretSession isDone], @"requesor done");
457 XCTAssertTrue([acceptSession isDone], @"acceptor done");
458
459 }
460
461 - (void)testJoiningSessionCodeChange {
462 NSError* error = nil;
463
464 NSString* secret = @"123456";
465 NSString* code = @"987654";
466
467 uint64_t dsid = 0x1234567887654321;
468
469 KCJoiningRequestTestDelegate* requestDelegate = [KCJoiningRequestTestDelegate requestDelegateWithSecret: secret];
470 KCJoiningRequestSecretSession *requestSession = [[KCJoiningRequestSecretSession alloc] initWithSecretDelegate:requestDelegate
471 dsid:dsid
472 rng:ccrng(NULL)
473 error:&error];
474
475 NSData* initialMessage = [requestSession initialMessage: &error];
476
477 XCTAssertNotNil(initialMessage, @"No initial message");
478 XCTAssertNil(error, @"Got error %@", error);
479
480 KCJoiningAcceptTestDelegate* acceptDelegate = [KCJoiningAcceptTestDelegate acceptDelegateWithSecrets:@[@"222222", @"3333333", secret] retries:1 code:code];
481 KCJoiningAcceptSession* acceptSession = [[KCJoiningAcceptSession alloc] initWithSecretDelegate:acceptDelegate
482 circleDelegate:acceptDelegate
483 dsid:dsid
484 rng:ccrng(NULL)
485 error:&error];
486
487 error = nil;
488 NSData* challenge = [acceptSession processMessage: initialMessage error: &error];
489
490 XCTAssertNotNil(challenge, @"No initial message");
491 XCTAssertNil(error, @"Got error %@", error);
492
493 NSData* response = nil;
494 NSData* verification = nil;
495
496 NSData* nextChallenge = challenge;
497 for (int tries = 0; tries < 5; ++tries) {
498 error = nil;
499 response = [requestSession processMessage: nextChallenge error: &error];
500
501 XCTAssertNotNil(response, @"No response message");
502 XCTAssertNil(error, @"Got error %@", error);
503
504 XCTAssertNotEqualObjects(requestDelegate.accountCode, acceptDelegate.codeToUse, @"Code should not make it");
505
506 error = nil;
507 verification = [acceptSession processMessage: response error: &error];
508
509 XCTAssertNotNil(verification, @"No verification message");
510 XCTAssertNil(error, @"Got error %@", error);
511
512 nextChallenge = verification;
513 }
514
515 error = nil;
516 NSData* doneMessage = [requestSession processMessage: verification error: &error];
517
518 XCTAssertNotNil(doneMessage, @"No response message");
519 XCTAssertNil(error, @"Got error %@", error);
520
521 XCTAssertTrue([requestSession isDone], @"SecretSession done");
522 XCTAssertFalse([acceptSession isDone], @"Unexpected accept session done");
523
524 KCAESGCMDuplexSession* aesSession = [requestSession session];
525 requestSession = nil;
526
527 error = nil;
528 KCJoiningRequestCircleSession* requestSecretSession = [KCJoiningRequestCircleSession sessionWithCircleDelegate:requestDelegate session:aesSession error:&error];
529
530 XCTAssertNotNil(requestSecretSession, @"No request secret session");
531 XCTAssertNil(error, @"Got error %@", error);
532
533 error = nil;
534 NSData* peerInfoMessage = [requestSecretSession initialMessage: &error];
535
536 XCTAssertNotNil(peerInfoMessage, @"No peerInfo message");
537 XCTAssertNil(error, @"Got error %@", error);
538
539 XCTAssertEqualObjects(requestDelegate.accountCode, acceptDelegate.codeToUse, @"Code made it");
540
541 error = nil;
542 NSData* blobMessage = [acceptSession processMessage:peerInfoMessage error: &error];
543
544 XCTAssertNotNil(blobMessage, @"No blob message");
545 XCTAssertNil(error, @"Got error %@", error);
546
547 // We have different peer_info types due to wierd linking of our tests.
548 // Compare the der representations:
549 NSData* rp_der = requestDelegate.peerInfo != nil ? (__bridge_transfer NSData*) SOSPeerInfoCopyEncodedData(requestDelegate.peerInfo, NULL, NULL) : nil;
550 NSData* ap_der = acceptDelegate.peerInfo != nil ? (__bridge_transfer NSData*) SOSPeerInfoCopyEncodedData(acceptDelegate.peerInfo, NULL, NULL) : nil;
551
552 XCTAssertEqualObjects(rp_der, ap_der, @"Peer infos match");
553
554 error = nil;
555 NSData* nothing = [requestSecretSession processMessage:blobMessage error: &error];
556
557 XCTAssertEqualObjects(requestDelegate.circleJoinData, acceptDelegate.circleJoinData);
558
559 XCTAssertNotNil(nothing, @"No initial message");
560 XCTAssertNil(error, @"Got error %@", error);
561
562 XCTAssertTrue([requestSecretSession isDone], @"requesor done");
563 XCTAssertTrue([acceptSession isDone], @"acceptor done");
564
565 }
566
567 @end