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