]> git.saurik.com Git - apple/security.git/blob - keychain/ot/tests/OTLockStateNetworkingTests.m
Security-59306.11.20.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 [self expectAddedCKModifyRecords:@{OTCKRecordBottledPeerType: @1} holdFetch:NO];
111
112 [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
113 [self.spiBlockExpectation fulfill];
114 XCTAssertNil(error, "error should be nil");
115 }];
116
117 [self waitForExpectationsWithTimeout:1.0 handler:nil];
118
119 NSError* localError = nil;
120 XCTAssertTrue([self.context doesThisDeviceHaveABottle:&localError] == BOTTLE, @"should have a bottle");
121 XCTAssertNil(localError, "error should be nil");
122 }
123
124 -(void) testGrabbingBottleFromCloudKitCheckPerfectConditions
125 {
126 [self setUpRampRecordsInCloudKitWithFeatureOn];
127
128 CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType];
129 newRecord[OTCKRecordPeerID] = self.fakeBottledPeerRecord.peerID;
130 newRecord[OTCKRecordSPID] = @"spID";
131 newRecord[OTCKRecordEscrowSigningSPKI] = self.fakeBottledPeerRecord.escrowedSigningSPKI;
132 newRecord[OTCKRecordPeerSigningSPKI] = self.fakeBottledPeerRecord.peerSigningSPKI;
133 newRecord[OTCKRecordEscrowRecordID] = self.fakeBottledPeerRecord.escrowRecordID;
134 newRecord[OTCKRecordBottle] = self.fakeBottledPeerRecord.bottle;
135 newRecord[OTCKRecordSignatureFromEscrow] = self.fakeBottledPeerRecord.signatureUsingEscrowKey;
136 newRecord[OTCKRecordSignatureFromPeerKey] = self.fakeBottledPeerRecord.signatureUsingPeerKey;
137
138 [self.otFakeZone addToZone:newRecord];
139
140 [self startCKKSSubsystem];
141
142 NSError* localError = nil;
143 XCTAssertTrue([self.context doesThisDeviceHaveABottle:&localError] == BOTTLE, @"should have a bottle");
144 XCTAssertNil(localError, "error should be nil");
145 }
146
147 -(void) testBottleCheckWhenLocked
148 {
149 NSError* error = nil;
150 self.aksLockState = true;
151 [self.lockStateTracker recheck];
152 [self setUpRampRecordsInCloudKitWithFeatureOff];
153
154 XCTAssertTrue([self.context doesThisDeviceHaveABottle:&error] == UNCLEAR, @"bottle check should return unclear");
155
156 XCTAssertNotNil(error, "error should not be nil");
157 XCTAssertEqual(error.code, -25308, @"error should be interaction not allowed");
158 }
159
160 -(void) testBottleCheckWithNoNetwork
161 {
162 NSError* error = nil;
163 self.accountStatus = CKAccountStatusAvailable;
164 [self startCKKSSubsystem];
165
166 [self.reachabilityTracker setNetworkReachability:false];
167 XCTAssertTrue([self.context doesThisDeviceHaveABottle:&error] == UNCLEAR, @"bottle check should return unclear");
168 XCTAssertEqual(error.code, OTErrorNoNetwork, @"should have returned no network error");
169 }
170
171 -(void) testBottleCheckWhenNotSignedIn
172 {
173 NSError* error = nil;
174
175 self.accountStatus = CKAccountStatusNoAccount;
176 [self startCKKSSubsystem];
177
178 XCTAssertTrue([self.context doesThisDeviceHaveABottle:&error] == UNCLEAR, @"bottle check should return unclear");
179 XCTAssertEqual(error.code, OTErrorNotSignedIn, @"should have returned not signed in error");
180 }
181
182 //Bottle Update tests
183 -(void)testBottleUpdateNotSignedIn
184 {
185 self.spiBlockExpectation = [self expectationWithDescription:@"handle identity change spis fired"];
186
187 [self setUpRampRecordsInCloudKitWithFeatureOn];
188
189 self.accountStatus = CKAccountStatusNoAccount;
190
191 [self startCKKSSubsystem];
192
193 SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]];
194
195 SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]];
196
197 //update bottle
198 [self.otControl handleIdentityChangeForSigningKey:newSigningKey
199 ForEncryptionKey:newEncryptionKey
200 ForPeerID:self.sosPeerID
201 reply:^(BOOL result, NSError* _Nullable error){
202 [self.spiBlockExpectation fulfill];
203 XCTAssertTrue(result == NO, @"should return NO");
204 XCTAssertEqual(error.code, OTErrorNotSignedIn, @"should have returned not signed in error");
205 }];
206 [self waitForExpectationsWithTimeout:1.0 handler:nil];
207 }
208
209 -(void) testBottleUpdateWithNoNetwork
210 {
211 self.accountStatus = CKAccountStatusAvailable;
212 [self startCKKSSubsystem];
213
214 [self.reachabilityTracker setNetworkReachability:false];
215
216 SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]];
217
218 SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]];
219
220 //update bottle
221 [self.otControl handleIdentityChangeForSigningKey:newSigningKey
222 ForEncryptionKey:newEncryptionKey
223 ForPeerID:self.sosPeerID
224 reply:^(BOOL result, NSError* _Nullable error){
225 XCTAssertEqual(error.code, OTErrorNoNetwork, @"should have returned OTErrorNoNetwork in error");
226 }];
227 }
228
229 -(void) testBottleUpdateWhenLocked
230 {
231 self.aksLockState = true;
232 [self.lockStateTracker recheck];
233
234 SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]];
235
236 SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]];
237
238 //update bottle
239 [self.otControl handleIdentityChangeForSigningKey:newSigningKey
240 ForEncryptionKey:newEncryptionKey
241 ForPeerID:self.sosPeerID
242 reply:^(BOOL result, NSError* _Nullable error){
243 XCTAssertEqual(error.code, errSecInteractionNotAllowed, @"should have returned errSecInteractionNotAllowed in error");
244 }];
245 }
246
247 //Preflight tests
248 -(void)testPreflightNotSignedIn
249 {
250 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
251
252 [self setUpRampRecordsInCloudKitWithFeatureOn];
253
254 self.accountStatus = CKAccountStatusNoAccount;
255
256 [self startCKKSSubsystem];
257
258 [self.otControl preflightBottledPeer:testContextID
259 dsid:testDSID
260 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
261 [self.spiBlockExpectation fulfill];
262 XCTAssertNil(entropy, "entropy should not be nil");
263 XCTAssertNil(bottleID, "bottle id should not be nil");
264 XCTAssertNil(signingPublicKey, "signing pub key should not be nil");
265 XCTAssertEqual(error.code, OTErrorNotSignedIn, @"should have returned not signed in error");
266 }];
267
268 [self waitForExpectationsWithTimeout:1.0 handler:nil];
269
270 }
271
272 -(void) testPreflightWithNoNetwork
273 {
274 self.accountStatus = CKAccountStatusAvailable;
275 [self startCKKSSubsystem];
276
277 [self.reachabilityTracker setNetworkReachability:false];
278
279 [self.otControl preflightBottledPeer:testContextID
280 dsid:testDSID
281 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
282 [self.spiBlockExpectation fulfill];
283 XCTAssertNil(entropy, "entropy should not be nil");
284 XCTAssertNil(bottleID, "bottle id should not be nil");
285 XCTAssertNil(signingPublicKey, "signing pub key should not be nil");
286 XCTAssertEqual(error.code, OTErrorNoNetwork, @"should have returned OTErrorNoNetwork in error");
287 }];
288
289 }
290
291 -(void) testPreflightWhenLocked
292 {
293 self.aksLockState = true;
294 [self.lockStateTracker recheck];
295
296 [self.otControl preflightBottledPeer:testContextID
297 dsid:testDSID
298 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
299 [self.spiBlockExpectation fulfill];
300 XCTAssertNil(entropy, "entropy should not be nil");
301 XCTAssertNil(bottleID, "bottle id should not be nil");
302 XCTAssertNil(signingPublicKey, "signing pub key should not be nil");
303 XCTAssertEqual(error.code, errSecInteractionNotAllowed, @"should have returned errSecInteractionNotAllowed in error");
304 }];
305 }
306
307 //Launch Bottle tests
308 -(void)testLaunchNotSignedIn
309 {
310 [self setUpRampRecordsInCloudKitWithFeatureOn];
311
312 self.accountStatus = CKAccountStatusNoAccount;
313
314 [self startCKKSSubsystem];
315
316 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
317
318 [self.otControl preflightBottledPeer:OTDefaultContext
319 dsid:@"dsid"
320 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
321 [self.spiBlockExpectation fulfill];
322 XCTAssertNil(entropy, "shouldn't return any entropy");
323 XCTAssertNil(bottleID, "shouldn't return a bottle ID");
324 XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey");
325 XCTAssertEqual(error.code, OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error");
326 }];
327 OCMVerifyAllWithDelay(self.mockDatabase, 8);
328 [self waitForExpectationsWithTimeout:1.0 handler:nil];
329
330 self.spiBlockExpectation = [self expectationWithDescription:@"launch SPI fired"];
331
332 NSString* localBottleID = @"random bottle id";
333 [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
334 [self.spiBlockExpectation fulfill];
335 XCTAssertEqual(error.code, OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error");
336 }];
337
338 OCMVerifyAllWithDelay(self.mockDatabase, 8);
339 [self waitForExpectationsWithTimeout:1.0 handler:nil];
340 }
341
342 -(void) testLaunchWithNoNetwork
343 {
344 [self setUpRampRecordsInCloudKitWithFeatureOn];
345
346 self.accountStatus = CKAccountStatusAvailable;
347 [self startCKKSSubsystem];
348
349 [self.reachabilityTracker setNetworkReachability:false];
350
351 [self startCKKSSubsystem];
352
353 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
354
355 [self.otControl preflightBottledPeer:OTDefaultContext
356 dsid:@"dsid"
357 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
358 [self.spiBlockExpectation fulfill];
359 XCTAssertNil(entropy, "shouldn't return any entropy");
360 XCTAssertNil(bottleID, "shouldn't return a bottle ID");
361 XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey");
362 XCTAssertEqual(error.code, OTErrorNoNetwork, "should return a OTErrorNoNetwork error");
363 }];
364 OCMVerifyAllWithDelay(self.mockDatabase, 8);
365 [self waitForExpectationsWithTimeout:1.0 handler:nil];
366
367
368 self.spiBlockExpectation = [self expectationWithDescription:@"launch SPI fired"];
369
370 NSString* localBottleID = @"random bottle id";
371 [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
372 [self.spiBlockExpectation fulfill];
373 XCTAssertEqual(error.code, OTErrorNoNetwork, "should return a OTErrorNoNetwork error");
374 }];
375
376 OCMVerifyAllWithDelay(self.mockDatabase, 8);
377 [self waitForExpectationsWithTimeout:1.0 handler:nil];
378 }
379
380 -(void) testLaunchWhenLocked
381 {
382 [self setUpRampRecordsInCloudKitWithFeatureOn];
383
384 self.aksLockState = true;
385 [self.lockStateTracker recheck];
386
387 [self startCKKSSubsystem];
388
389 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
390
391 [self.otControl preflightBottledPeer:OTDefaultContext
392 dsid:@"dsid"
393 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
394 [self.spiBlockExpectation fulfill];
395 XCTAssertNil(entropy, "shouldn't return any entropy");
396 XCTAssertNil(bottleID, "shouldn't return a bottle ID");
397 XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey");
398 XCTAssertEqual(error.code, errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error");
399 }];
400 OCMVerifyAllWithDelay(self.mockDatabase, 8);
401 [self waitForExpectationsWithTimeout:1.0 handler:nil];
402
403
404 self.spiBlockExpectation = [self expectationWithDescription:@"launch SPI fired"];
405
406 NSString* localBottleID = @"random bottle id";
407 [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
408 [self.spiBlockExpectation fulfill];
409 XCTAssertEqual(error.code, errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error");
410 }];
411
412 OCMVerifyAllWithDelay(self.mockDatabase, 8);
413 [self waitForExpectationsWithTimeout:1.0 handler:nil];
414 }
415
416 //Scrub tests
417 -(void)testScrubNotSignedIn
418 {
419 [self setUpRampRecordsInCloudKitWithFeatureOn];
420
421 self.accountStatus = CKAccountStatusNoAccount;
422 [self startCKKSSubsystem];
423
424 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer SPI fired"];
425
426 [self.otControl preflightBottledPeer:testContextID
427 dsid:testDSID
428 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
429 [self.spiBlockExpectation fulfill];
430 XCTAssertNil(entropy, "entropy should be nil");
431 XCTAssertNil(bottleID, "bottle id should be nil");
432 XCTAssertNil(signingPublicKey, "signing pub key should be nil");
433 XCTAssertEqual(error.code, OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error");
434 }];
435
436 [self waitForExpectationsWithTimeout:1.0 handler:nil];
437
438 __block NSString* localBottleID = @"random bottle id";
439 self.spiBlockExpectation = [self expectationWithDescription:@"scrub bottled peer SPI fired"];
440
441 [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
442 [self.spiBlockExpectation fulfill];
443 XCTAssertEqual(error.code, OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error");
444 }];
445
446 OCMVerifyAllWithDelay(self.mockDatabase, 8);
447 [self waitForExpectationsWithTimeout:1.0 handler:nil];
448
449 }
450
451 -(void) testScrubWithNoNetwork
452 {
453 [self setUpRampRecordsInCloudKitWithFeatureOn];
454
455 self.accountStatus = CKAccountStatusAvailable;
456
457 [self.reachabilityTracker setNetworkReachability:false];
458
459 [self startCKKSSubsystem];
460
461 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer SPI fired"];
462
463 [self.otControl preflightBottledPeer:testContextID
464 dsid:testDSID
465 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
466 [self.spiBlockExpectation fulfill];
467 XCTAssertNil(entropy, "entropy should be nil");
468 XCTAssertNil(bottleID, "bottle id should be nil");
469 XCTAssertNil(signingPublicKey, "signing pub key should be nil");
470 XCTAssertEqual(error.code, OTErrorNoNetwork, "should return a OTErrorNoNetwork error");
471 }];
472
473 [self waitForExpectationsWithTimeout:1.0 handler:nil];
474
475 __block NSString* localBottleID = @"random bottle id";
476 self.spiBlockExpectation = [self expectationWithDescription:@"scrub bottled peer SPI fired"];
477
478 [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
479 [self.spiBlockExpectation fulfill];
480 XCTAssertEqual(error.code, OTErrorNoNetwork, "should return a OTErrorNoNetwork error");
481 }];
482
483 OCMVerifyAllWithDelay(self.mockDatabase, 8);
484 [self waitForExpectationsWithTimeout:1.0 handler:nil];
485 }
486
487 -(void) testScrubWhenLocked
488 {
489 [self setUpRampRecordsInCloudKitWithFeatureOn];
490
491 self.aksLockState = true;
492 [self.lockStateTracker recheck];
493
494 [self startCKKSSubsystem];
495
496 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer SPI fired"];
497
498 [self.otControl preflightBottledPeer:testContextID
499 dsid:testDSID
500 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
501 [self.spiBlockExpectation fulfill];
502 XCTAssertNil(entropy, "entropy should be nil");
503 XCTAssertNil(bottleID, "bottle id should be nil");
504 XCTAssertNil(signingPublicKey, "signing pub key should be nil");
505 XCTAssertEqual(error.code, errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error");
506 }];
507
508 [self waitForExpectationsWithTimeout:1.0 handler:nil];
509
510 __block NSString* localBottleID = @"random bottle id";
511 self.spiBlockExpectation = [self expectationWithDescription:@"scrub bottled peer SPI fired"];
512
513 [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
514 [self.spiBlockExpectation fulfill];
515 XCTAssertEqual(error.code, errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error");
516 }];
517
518 OCMVerifyAllWithDelay(self.mockDatabase, 8);
519 [self waitForExpectationsWithTimeout:1.0 handler:nil];
520 }
521
522 //Restore tests
523 -(void)testRestoreNotSignedIn
524 {
525 [self setUpRampRecordsInCloudKitWithFeatureOn];
526
527 self.accountStatus = CKAccountStatusNoAccount;
528
529 [self startCKKSSubsystem];
530
531 self.spiBlockExpectation = [self expectationWithDescription:@"restore SPI fired"];
532
533 [self.otControl restore:testContextID
534 dsid:testDSID
535 secret:self.secret
536 escrowRecordID:self.sosPeerID
537 reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) {
538 [self.spiBlockExpectation fulfill];
539 XCTAssertNil(signingKeyData, "Signing key data should be nil");
540 XCTAssertNil(encryptionKeyData, "encryption key data should be nil");
541 XCTAssertEqual(error.code, OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error");
542 }];
543 OCMVerifyAllWithDelay(self.mockDatabase, 8);
544 [self waitForExpectationsWithTimeout:1.0 handler:nil];
545
546 }
547
548 -(void) testRestoreWithNoNetwork
549 {
550 [self setUpRampRecordsInCloudKitWithFeatureOn];
551
552 self.accountStatus = CKAccountStatusAvailable;
553
554 [self.reachabilityTracker setNetworkReachability:false];
555
556 [self startCKKSSubsystem];
557
558 self.spiBlockExpectation = [self expectationWithDescription:@"restore SPI fired"];
559
560 [self.otControl restore:testContextID
561 dsid:testDSID
562 secret:self.secret
563 escrowRecordID:self.sosPeerID
564 reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) {
565 [self.spiBlockExpectation fulfill];
566 XCTAssertNil(signingKeyData, "Signing key data should be nil");
567 XCTAssertNil(encryptionKeyData, "encryption key data should be nil");
568 XCTAssertEqual(error.code, OTErrorNoNetwork, "should return a OTErrorNoNetwork error");
569 }];
570 OCMVerifyAllWithDelay(self.mockDatabase, 8);
571 [self waitForExpectationsWithTimeout:1.0 handler:nil];
572 }
573
574 -(void) testRestoreWhenLocked
575 {
576 [self setUpRampRecordsInCloudKitWithFeatureOn];
577
578 self.aksLockState = true;
579 [self.lockStateTracker recheck];
580
581 [self startCKKSSubsystem];
582
583 self.spiBlockExpectation = [self expectationWithDescription:@"restore SPI fired"];
584
585 [self.otControl restore:testContextID
586 dsid:testDSID
587 secret:self.secret
588 escrowRecordID:self.sosPeerID
589 reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) {
590 [self.spiBlockExpectation fulfill];
591 XCTAssertNil(signingKeyData, "Signing key data should be nil");
592 XCTAssertNil(encryptionKeyData, "encryption key data should be nil");
593 XCTAssertEqual(error.code, errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error");
594 }];
595 OCMVerifyAllWithDelay(self.mockDatabase, 8);
596 [self waitForExpectationsWithTimeout:1.0 handler:nil];
597 }
598
599 //Generic Ramp tests
600 -(void)testEnrollRampNotSignedIn
601 {
602 [self setUpRampRecordsInCloudKitWithFeatureOn];
603
604 NSError* error = nil;
605 NSInteger retryAfter = 0;
606
607 self.accountStatus = CKAccountStatusNoAccount;
608 [self startCKKSSubsystem];
609
610 [self.enroll checkRampState:&retryAfter networkBehavior:CKOperationDiscretionaryNetworkBehaviorNonDiscretionary error:&error];
611
612 XCTAssertEqual(error.code, OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error");
613
614 }
615
616 -(void) testEnrollRampWithNoNetwork
617 {
618 [self setUpRampRecordsInCloudKitWithFeatureOn];
619
620 NSError* error = nil;
621 NSInteger retryAfter = 0;
622
623 self.accountStatus = CKAccountStatusAvailable;
624 [self startCKKSSubsystem];
625
626 [self.reachabilityTracker setNetworkReachability:false];
627
628 [self.enroll checkRampState:&retryAfter networkBehavior:CKOperationDiscretionaryNetworkBehaviorNonDiscretionary error:&error];
629
630 XCTAssertEqual(error.code, OTErrorNoNetwork, "should return a OTErrorNoNetwork error");
631 }
632
633 -(void) testEnrollRampWhenLocked
634 {
635 [self setUpRampRecordsInCloudKitWithFeatureOn];
636
637 NSError* error = nil;
638 NSInteger retryAfter = 0;
639
640 self.aksLockState = true;
641 [self.lockStateTracker recheck];
642
643 [self.enroll checkRampState:&retryAfter networkBehavior:CKOperationDiscretionaryNetworkBehaviorNonDiscretionary error:&error];
644
645 XCTAssertEqual(error.code, errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error");
646 }
647
648 -(void) testTimeBetweenCFUAttempts
649 {
650 [self setUpRampRecordsInCloudKitWithFeatureOn];
651
652 NSError* error = nil;
653
654 [self startCKKSSubsystem];
655
656 [self.manager scheduledCloudKitRampCheck:&error];
657 XCTAssertNotNil(error, "Should have had an error scheduling a ramp check");
658 XCTAssertEqual(error.code, OTErrorNoBottlePeerRecords, "Error should be 'no bottled peer records'");
659 XCTAssertNotNil(self.manager.lastPostedCoreFollowUp, "core followup should have been posted");
660 NSDate* firstTime = self.manager.lastPostedCoreFollowUp;
661
662 sleep(2);
663 error = nil;
664
665 [self.manager scheduledCloudKitRampCheck:&error];
666 XCTAssertNotNil(error, "Should have had an error scheduling a ramp check");
667 XCTAssertEqual(error.code, OTErrorNoBottlePeerRecords, "Error should be 'no bottled peer records'");
668 XCTAssertNotNil(self.manager.lastPostedCoreFollowUp, "core followup should have been posted");
669 NSDate* secondTime = self.manager.lastPostedCoreFollowUp;
670
671 XCTAssertTrue([secondTime timeIntervalSinceDate:firstTime] >= 2, "time difference should be slightly more than 2 seconds");
672 }
673
674 @end
675 #endif