]> git.saurik.com Git - apple/security.git/blob - keychain/ot/tests/OTLockStateNetworkingTests.m
Security-58286.70.7.tar.gz
[apple/security.git] / keychain / ot / tests / OTLockStateNetworkingTests.m
1 /*
2 * Copyright (c) 2017 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #if OCTAGON
25
26 #import <Foundation/Foundation.h>
27
28 #import <XCTest/XCTest.h>
29 #import <OCMock/OCMock.h>
30
31 #import "OTTestsBase.h"
32
33 static NSString* const testContextID = @"Foo";
34 static NSString* const testDSID = @"123456789";
35
36 static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer";
37 /* Octagon Trust BottledPeerSchema */
38 static NSString* OTCKRecordEscrowRecordID = @"escrowRecordID";
39 static NSString* OTCKRecordRecordID = @"bottledPeerRecordID";
40 static NSString* OTCKRecordSPID = @"spID";
41 static NSString* OTCKRecordEscrowSigningSPKI = @"escrowSigningSPKI";
42 static NSString* OTCKRecordPeerSigningSPKI = @"peerSigningSPKI";
43 static NSString* OTCKRecordEscrowSigningPubKey = @"escrowSigningPubKey";
44 static NSString* OTCKRecordPeerSigningPubKey = @"peerSigningPubKey";
45 static NSString* OTCKRecordSignatureFromEscrow = @"signatureUsingEscrow";
46 static NSString* OTCKRecordSignatureFromPeerKey = @"signatureUsingPeerKey";
47 static NSString* OTCKRecordBottle = @"bottle";
48
49 static NSString* OTCKRecordPeerID = @"peerID";
50
51 @interface OTLockStateNetworkingTests : OTTestsBase
52 @property (nonatomic, strong) OTBottledPeerRecord* fakeBottledPeerRecord;
53 @end
54
55 @implementation OTLockStateNetworkingTests
56
57 - (void)setUp {
58 [super setUp];
59
60 self.continueAfterFailure = NO;
61 NSError* error = nil;
62
63 OTBottledPeer *bp = [[OTBottledPeer alloc]initWithPeerID:self.egoPeerID spID:self.sosPeerID peerSigningKey:self.peerSigningKey peerEncryptionKey:self.peerEncryptionKey escrowKeys:self.escrowKeys error:&error];
64
65 XCTAssertNotNil(bp, @"plaintext should not be nil");
66 XCTAssertNil(error, @"error should be nil");
67 XCTAssertNotNil(self.escrowKeys.signingKey, @"signing public key should not be nil");
68 XCTAssertNotNil(self.escrowKeys.encryptionKey, @"encryption public key should not be nil");
69
70 OTBottledPeerSigned *bpSigned = [[OTBottledPeerSigned alloc]initWithBottledPeer:bp escrowedSigningKey:self.escrowKeys.signingKey peerSigningKey:self.peerSigningKey error:&error];
71
72 self.fakeBottledPeerRecord = [bpSigned asRecord:self.sosPeerID];
73
74 [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
75
76 }
77
78 - (void)tearDown {
79
80 [super tearDown];
81 }
82
83 //Bottle Check tests
84
85 -(void) testGrabbingBottleLocallyCheckPerfectConditions
86 {
87 [self setUpRampRecordsInCloudKitWithFeatureOn];
88 [self startCKKSSubsystem];
89
90 __block NSData* localEntropy = nil;
91 __block NSString* localBottleID = nil;
92
93 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
94
95 [self.otControl preflightBottledPeer:testContextID
96 dsid:testDSID
97 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
98 [self.spiBlockExpectation fulfill];
99 localEntropy = entropy;
100 localBottleID = bottleID;
101 XCTAssertNotNil(entropy, "entropy should not be nil");
102 XCTAssertNotNil(bottleID, "bottle id should not be nil");
103 XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil");
104 XCTAssertNil(error, "error should be nil");
105 }];
106 [self waitForExpectationsWithTimeout:1.0 handler:nil];
107
108 self.spiBlockExpectation = [self expectationWithDescription:@"launch bottled peer fired"];
109
110 NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil];
111
112 [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO];
113
114 [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
115 [self.spiBlockExpectation fulfill];
116 XCTAssertNil(error, "error should be nil");
117 }];
118
119 [self waitForExpectationsWithTimeout:1.0 handler:nil];
120
121 NSError* localError = nil;
122 XCTAssertTrue([self.context doesThisDeviceHaveABottle:&localError] == BOTTLE, @"should have a bottle");
123 XCTAssertNil(localError, "error should be nil");
124 }
125
126 -(void) testGrabbingBottleFromCloudKitCheckPerfectConditions
127 {
128 [self setUpRampRecordsInCloudKitWithFeatureOn];
129
130 CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType];
131 newRecord[OTCKRecordPeerID] = self.fakeBottledPeerRecord.peerID;
132 newRecord[OTCKRecordSPID] = @"spID";
133 newRecord[OTCKRecordEscrowSigningSPKI] = self.fakeBottledPeerRecord.escrowedSigningSPKI;
134 newRecord[OTCKRecordPeerSigningSPKI] = self.fakeBottledPeerRecord.peerSigningSPKI;
135 newRecord[OTCKRecordEscrowRecordID] = self.fakeBottledPeerRecord.escrowRecordID;
136 newRecord[OTCKRecordBottle] = self.fakeBottledPeerRecord.bottle;
137 newRecord[OTCKRecordSignatureFromEscrow] = self.fakeBottledPeerRecord.signatureUsingEscrowKey;
138 newRecord[OTCKRecordSignatureFromPeerKey] = self.fakeBottledPeerRecord.signatureUsingPeerKey;
139
140 [self.otFakeZone addToZone:newRecord];
141
142 [self startCKKSSubsystem];
143
144 NSError* localError = nil;
145 XCTAssertTrue([self.context doesThisDeviceHaveABottle:&localError] == BOTTLE, @"should have a bottle");
146 XCTAssertNil(localError, "error should be nil");
147 }
148
149 -(void) testBottleCheckWhenLocked
150 {
151 NSError* error = nil;
152 self.aksLockState = true;
153 [self.lockStateTracker recheck];
154 [self setUpRampRecordsInCloudKitWithFeatureOff];
155
156 XCTAssertTrue([self.context doesThisDeviceHaveABottle:&error] == UNCLEAR, @"bottle check should return unclear");
157
158 XCTAssertNotNil(error, "error should not be nil");
159 XCTAssertTrue(error.code == -25308, @"error should be interaction not allowed");
160 }
161
162 -(void) testBottleCheckWithNoNetwork
163 {
164 NSError* error = nil;
165 self.accountStatus = CKAccountStatusAvailable;
166 [self startCKKSSubsystem];
167
168 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
169
170 self.reachabilityFlags = 0;
171 [self.reachabilityTracker recheck];
172 XCTAssertTrue([self.context doesThisDeviceHaveABottle:&error] == UNCLEAR, @"bottle check should return unclear");
173 XCTAssertTrue(error.code == OTErrorNoNetwork, @"should have returned no network error");
174 }
175
176 -(void) testBottleCheckWhenNotSignedIn
177 {
178 NSError* error = nil;
179
180 self.accountStatus = CKAccountStatusNoAccount;
181 [self startCKKSSubsystem];
182
183 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
184
185 XCTAssertTrue([self.context doesThisDeviceHaveABottle:&error] == UNCLEAR, @"bottle check should return unclear");
186 XCTAssertTrue(error.code == OTErrorNotSignedIn, @"should have returned not signed in error");
187 }
188
189
190 //Preflight tests
191 -(void)testPreflightNotSignedIn
192 {
193 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
194
195 [self setUpRampRecordsInCloudKitWithFeatureOn];
196
197 self.accountStatus = CKAccountStatusNoAccount;
198
199 [self startCKKSSubsystem];
200
201 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
202
203 [self.otControl preflightBottledPeer:testContextID
204 dsid:testDSID
205 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
206 [self.spiBlockExpectation fulfill];
207 XCTAssertNil(entropy, "entropy should not be nil");
208 XCTAssertNil(bottleID, "bottle id should not be nil");
209 XCTAssertNil(signingPublicKey, "signing pub key should not be nil");
210 XCTAssertTrue(error.code == OTErrorNotSignedIn, @"should have returned not signed in error");
211 }];
212
213 [self waitForExpectationsWithTimeout:1.0 handler:nil];
214
215 }
216
217 -(void) testPreflightWithNoNetwork
218 {
219 self.accountStatus = CKAccountStatusAvailable;
220 [self startCKKSSubsystem];
221
222 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
223
224 self.reachabilityFlags = 0;
225 [self.reachabilityTracker recheck];
226
227 [self.otControl preflightBottledPeer:testContextID
228 dsid:testDSID
229 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
230 [self.spiBlockExpectation fulfill];
231 XCTAssertNil(entropy, "entropy should not be nil");
232 XCTAssertNil(bottleID, "bottle id should not be nil");
233 XCTAssertNil(signingPublicKey, "signing pub key should not be nil");
234 XCTAssertTrue(error.code == OTErrorNoNetwork, @"should have returned OTErrorNoNetwork in error");
235 }];
236
237 }
238
239 -(void) testPreflightWhenLocked
240 {
241 self.aksLockState = true;
242 [self.lockStateTracker recheck];
243
244 [self.otControl preflightBottledPeer:testContextID
245 dsid:testDSID
246 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
247 [self.spiBlockExpectation fulfill];
248 XCTAssertNil(entropy, "entropy should not be nil");
249 XCTAssertNil(bottleID, "bottle id should not be nil");
250 XCTAssertNil(signingPublicKey, "signing pub key should not be nil");
251 XCTAssertTrue(error.code == errSecInteractionNotAllowed, @"should have returned errSecInteractionNotAllowed in error");
252 }];
253 }
254
255 //Launch Bottle tests
256 -(void)testLaunchNotSignedIn
257 {
258 [self setUpRampRecordsInCloudKitWithFeatureOn];
259
260 self.accountStatus = CKAccountStatusNoAccount;
261
262 [self startCKKSSubsystem];
263
264 [self.enroll.accountTracker notifyCKAccountStatusChangeAndWaitForSignal];
265 [self.context.accountTracker notifyCKAccountStatusChangeAndWaitForSignal];
266
267 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
268
269 [self.otControl preflightBottledPeer:OTDefaultContext
270 dsid:@"dsid"
271 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
272 [self.spiBlockExpectation fulfill];
273 XCTAssertNil(entropy, "shouldn't return any entropy");
274 XCTAssertNil(bottleID, "shouldn't return a bottle ID");
275 XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey");
276 XCTAssertTrue(error.code == OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error");
277 }];
278 [self waitForCKModifications];
279 OCMVerifyAllWithDelay(self.mockDatabase, 8);
280 [self waitForExpectationsWithTimeout:1.0 handler:nil];
281
282 self.spiBlockExpectation = [self expectationWithDescription:@"launch SPI fired"];
283 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
284
285 NSString* localBottleID = @"random bottle id";
286 [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
287 [self.spiBlockExpectation fulfill];
288 XCTAssertTrue(error.code == OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error");
289 }];
290
291 [self waitForCKModifications];
292 OCMVerifyAllWithDelay(self.mockDatabase, 8);
293 [self waitForExpectationsWithTimeout:1.0 handler:nil];
294 }
295
296 -(void) testLaunchWithNoNetwork
297 {
298 [self setUpRampRecordsInCloudKitWithFeatureOn];
299
300 self.accountStatus = CKAccountStatusAvailable;
301 [self startCKKSSubsystem];
302
303 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
304
305 self.reachabilityFlags = 0;
306 [self.reachabilityTracker recheck];
307
308 [self startCKKSSubsystem];
309
310 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
311
312 [self.otControl preflightBottledPeer:OTDefaultContext
313 dsid:@"dsid"
314 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
315 [self.spiBlockExpectation fulfill];
316 XCTAssertNil(entropy, "shouldn't return any entropy");
317 XCTAssertNil(bottleID, "shouldn't return a bottle ID");
318 XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey");
319 XCTAssertTrue(error.code == OTErrorNoNetwork, "should return a OTErrorNoNetwork error");
320 }];
321 [self waitForCKModifications];
322 OCMVerifyAllWithDelay(self.mockDatabase, 8);
323 [self waitForExpectationsWithTimeout:1.0 handler:nil];
324
325
326 self.spiBlockExpectation = [self expectationWithDescription:@"launch SPI fired"];
327 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
328
329 NSString* localBottleID = @"random bottle id";
330 [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
331 [self.spiBlockExpectation fulfill];
332 XCTAssertTrue(error.code == OTErrorNoNetwork, "should return a OTErrorNoNetwork error");
333 }];
334
335 [self waitForCKModifications];
336 OCMVerifyAllWithDelay(self.mockDatabase, 8);
337 [self waitForExpectationsWithTimeout:1.0 handler:nil];
338 }
339
340 -(void) testLaunchWhenLocked
341 {
342 [self setUpRampRecordsInCloudKitWithFeatureOn];
343
344 self.aksLockState = true;
345 [self.lockStateTracker recheck];
346
347 [self startCKKSSubsystem];
348
349 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
350
351 [self.otControl preflightBottledPeer:OTDefaultContext
352 dsid:@"dsid"
353 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
354 [self.spiBlockExpectation fulfill];
355 XCTAssertNil(entropy, "shouldn't return any entropy");
356 XCTAssertNil(bottleID, "shouldn't return a bottle ID");
357 XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey");
358 XCTAssertTrue(error.code == errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error");
359 }];
360 [self waitForCKModifications];
361 OCMVerifyAllWithDelay(self.mockDatabase, 8);
362 [self waitForExpectationsWithTimeout:1.0 handler:nil];
363
364
365 self.spiBlockExpectation = [self expectationWithDescription:@"launch SPI fired"];
366 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
367
368 NSString* localBottleID = @"random bottle id";
369 [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
370 [self.spiBlockExpectation fulfill];
371 XCTAssertTrue(error.code == errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error");
372 }];
373
374 [self waitForCKModifications];
375 OCMVerifyAllWithDelay(self.mockDatabase, 8);
376 [self waitForExpectationsWithTimeout:1.0 handler:nil];
377 }
378
379 //Scrub tests
380 -(void)testScrubNotSignedIn
381 {
382 [self setUpRampRecordsInCloudKitWithFeatureOn];
383
384 self.accountStatus = CKAccountStatusNoAccount;
385 [self startCKKSSubsystem];
386
387 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
388
389 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer SPI fired"];
390 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
391
392 [self.otControl preflightBottledPeer:testContextID
393 dsid:testDSID
394 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
395 [self.spiBlockExpectation fulfill];
396 XCTAssertNil(entropy, "entropy should be nil");
397 XCTAssertNil(bottleID, "bottle id should be nil");
398 XCTAssertNil(signingPublicKey, "signing pub key should be nil");
399 XCTAssertTrue(error.code == OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error");
400 }];
401
402 [self waitForExpectationsWithTimeout:1.0 handler:nil];
403
404 __block NSString* localBottleID = @"random bottle id";
405 self.spiBlockExpectation = [self expectationWithDescription:@"scrub bottled peer SPI fired"];
406 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
407
408 [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
409 [self.spiBlockExpectation fulfill];
410 XCTAssertTrue(error.code == OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error");
411 }];
412
413 [self waitForCKModifications];
414 OCMVerifyAllWithDelay(self.mockDatabase, 8);
415 [self waitForExpectationsWithTimeout:1.0 handler:nil];
416
417 }
418
419 -(void) testScrubWithNoNetwork
420 {
421 [self setUpRampRecordsInCloudKitWithFeatureOn];
422
423 self.accountStatus = CKAccountStatusAvailable;
424 [self startCKKSSubsystem];
425
426 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
427
428 self.reachabilityFlags = 0;
429 [self.reachabilityTracker recheck];
430
431 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer SPI fired"];
432 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
433
434 [self.otControl preflightBottledPeer:testContextID
435 dsid:testDSID
436 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
437 [self.spiBlockExpectation fulfill];
438 XCTAssertNil(entropy, "entropy should be nil");
439 XCTAssertNil(bottleID, "bottle id should be nil");
440 XCTAssertNil(signingPublicKey, "signing pub key should be nil");
441 XCTAssertTrue(error.code == OTErrorNoNetwork, "should return a OTErrorNoNetwork error");
442 }];
443
444 [self waitForExpectationsWithTimeout:1.0 handler:nil];
445
446 __block NSString* localBottleID = @"random bottle id";
447 self.spiBlockExpectation = [self expectationWithDescription:@"scrub bottled peer SPI fired"];
448 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
449
450 [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
451 [self.spiBlockExpectation fulfill];
452 XCTAssertTrue(error.code == OTErrorNoNetwork, "should return a OTErrorNoNetwork error");
453 }];
454
455 [self waitForCKModifications];
456 OCMVerifyAllWithDelay(self.mockDatabase, 8);
457 [self waitForExpectationsWithTimeout:1.0 handler:nil];
458 }
459
460 -(void) testScrubWhenLocked
461 {
462 [self setUpRampRecordsInCloudKitWithFeatureOn];
463
464 self.aksLockState = true;
465 [self.lockStateTracker recheck];
466
467 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer SPI fired"];
468 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
469
470 [self.otControl preflightBottledPeer:testContextID
471 dsid:testDSID
472 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
473 [self.spiBlockExpectation fulfill];
474 XCTAssertNil(entropy, "entropy should be nil");
475 XCTAssertNil(bottleID, "bottle id should be nil");
476 XCTAssertNil(signingPublicKey, "signing pub key should be nil");
477 XCTAssertTrue(error.code == errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error");
478 }];
479
480 [self waitForExpectationsWithTimeout:1.0 handler:nil];
481
482 __block NSString* localBottleID = @"random bottle id";
483 self.spiBlockExpectation = [self expectationWithDescription:@"scrub bottled peer SPI fired"];
484 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
485
486 [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
487 [self.spiBlockExpectation fulfill];
488 XCTAssertTrue(error.code == errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error");
489 }];
490
491 [self waitForCKModifications];
492 OCMVerifyAllWithDelay(self.mockDatabase, 8);
493 [self waitForExpectationsWithTimeout:1.0 handler:nil];
494 }
495
496 //Restore tests
497 -(void)testRestoreNotSignedIn
498 {
499 [self setUpRampRecordsInCloudKitWithFeatureOn];
500
501 self.accountStatus = CKAccountStatusNoAccount;
502 [self startCKKSSubsystem];
503
504 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
505
506 self.spiBlockExpectation = [self expectationWithDescription:@"restore SPI fired"];
507 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
508
509 [self.otControl restore:testContextID
510 dsid:testDSID
511 secret:self.secret
512 escrowRecordID:self.sosPeerID
513 reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) {
514 [self.spiBlockExpectation fulfill];
515 XCTAssertNil(signingKeyData, "Signing key data should be nil");
516 XCTAssertNil(encryptionKeyData, "encryption key data should be nil");
517 XCTAssertTrue(error.code == OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error");
518 }];
519 [self waitForCKModifications];
520 OCMVerifyAllWithDelay(self.mockDatabase, 8);
521 [self waitForExpectationsWithTimeout:1.0 handler:nil];
522
523 }
524
525 -(void) testRestoreWithNoNetwork
526 {
527 [self setUpRampRecordsInCloudKitWithFeatureOn];
528
529 self.accountStatus = CKAccountStatusAvailable;
530 [self startCKKSSubsystem];
531
532 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
533
534 self.reachabilityFlags = 0;
535 [self.reachabilityTracker recheck];
536
537 self.spiBlockExpectation = [self expectationWithDescription:@"restore SPI fired"];
538 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
539
540 [self.otControl restore:testContextID
541 dsid:testDSID
542 secret:self.secret
543 escrowRecordID:self.sosPeerID
544 reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) {
545 [self.spiBlockExpectation fulfill];
546 XCTAssertNil(signingKeyData, "Signing key data should be nil");
547 XCTAssertNil(encryptionKeyData, "encryption key data should be nil");
548 XCTAssertTrue(error.code == OTErrorNoNetwork, "should return a OTErrorNoNetwork error");
549 }];
550 [self waitForCKModifications];
551 OCMVerifyAllWithDelay(self.mockDatabase, 8);
552 [self waitForExpectationsWithTimeout:1.0 handler:nil];
553 }
554
555 -(void) testRestoreWhenLocked
556 {
557 [self setUpRampRecordsInCloudKitWithFeatureOn];
558
559 self.aksLockState = true;
560 [self.lockStateTracker recheck];
561
562 self.spiBlockExpectation = [self expectationWithDescription:@"restore SPI fired"];
563 self.expectation = [self expectationWithDescription:@"ramp scheduler fired"];
564
565 [self.otControl restore:testContextID
566 dsid:testDSID
567 secret:self.secret
568 escrowRecordID:self.sosPeerID
569 reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) {
570 [self.spiBlockExpectation fulfill];
571 XCTAssertNil(signingKeyData, "Signing key data should be nil");
572 XCTAssertNil(encryptionKeyData, "encryption key data should be nil");
573 XCTAssertTrue(error.code == errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error");
574 }];
575 [self waitForCKModifications];
576 OCMVerifyAllWithDelay(self.mockDatabase, 8);
577 [self waitForExpectationsWithTimeout:1.0 handler:nil];
578 }
579
580 //Generic Ramp tests
581 -(void)testEnrollRampNotSignedIn
582 {
583 [self setUpRampRecordsInCloudKitWithFeatureOn];
584
585 NSError* error = nil;
586 NSInteger retryAfter = 0;
587
588 self.accountStatus = CKAccountStatusNoAccount;
589 [self startCKKSSubsystem];
590
591 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
592
593 [self.enroll checkRampState:&retryAfter qos:NSQualityOfServiceUserInitiated error:&error];
594
595 XCTAssertTrue(error.code == OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error");
596
597 }
598
599 -(void) testEnrollRampWithNoNetwork
600 {
601 [self setUpRampRecordsInCloudKitWithFeatureOn];
602
603 NSError* error = nil;
604 NSInteger retryAfter = 0;
605
606 self.accountStatus = CKAccountStatusAvailable;
607 [self startCKKSSubsystem];
608
609 [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
610
611 self.reachabilityFlags = 0;
612 [self.reachabilityTracker recheck];
613
614 [self.enroll checkRampState:&retryAfter qos:NSQualityOfServiceUserInitiated error:&error];
615
616 XCTAssertTrue(error.code == OTErrorNoNetwork, "should return a OTErrorNoNetwork error");
617 }
618
619 -(void) testEnrollRampWhenLocked
620 {
621 [self setUpRampRecordsInCloudKitWithFeatureOn];
622
623 NSError* error = nil;
624 NSInteger retryAfter = 0;
625
626 self.aksLockState = true;
627 [self.lockStateTracker recheck];
628
629 [self.enroll checkRampState:&retryAfter qos:NSQualityOfServiceUserInitiated error:&error];
630
631 XCTAssertTrue(error.code == errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error");
632 }
633
634 -(void) testTimeBetweenCFUAttempts
635 {
636 [self setUpRampRecordsInCloudKitWithFeatureOn];
637
638 NSError* error = nil;
639
640 [self.manager scheduledCloudKitRampCheck:&error];
641 XCTAssertNotNil(self.manager.lastPostedCoreFollowUp, "core followup should have been posted");
642 NSDate* firstTime = self.manager.lastPostedCoreFollowUp;
643
644 sleep(2);
645
646 [self.manager scheduledCloudKitRampCheck:&error];
647 XCTAssertNotNil(self.manager.lastPostedCoreFollowUp, "core followup should have been posted");
648 NSDate* secondTime = self.manager.lastPostedCoreFollowUp;
649
650 XCTAssertTrue([secondTime timeIntervalSinceDate:firstTime] >= 2, "time difference should be slightly more than 2 seconds");
651 }
652
653 @end
654 #endif