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