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