]> git.saurik.com Git - apple/security.git/blob - keychain/ot/tests/OTRampingTests.m
Security-58286.70.7.tar.gz
[apple/security.git] / keychain / ot / tests / OTRampingTests.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 #import "keychain/ot/OTConstants.h"
33
34 static NSString* const testContextID = @"Foo";
35 static NSString* const testDSID = @"123456789";
36
37 static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer";
38
39 @interface OTRampingUnitTests : OTTestsBase
40
41 @end
42
43 @implementation OTRampingUnitTests
44
45 - (void)setUp {
46 [super setUp];
47 self.continueAfterFailure = NO;
48 }
49
50 - (void)tearDown {
51 [super tearDown];
52 }
53
54 -(void) testPreflightWithFeatureOnOn
55 {
56 [self setUpRampRecordsInCloudKitWithFeatureOn];
57
58 [self startCKKSSubsystem];
59
60 [self.otControl preflightBottledPeer:testContextID
61 dsid:testDSID
62 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
63 XCTAssertNotNil(entropy, "entropy should not be nil");
64 XCTAssertNotNil(bottleID, "bottle id should not be nil");
65 XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil");
66 XCTAssertNil(error, "error should be nil");
67 }];
68
69 }
70
71 -(void) testLaunchWithRampOn
72 {
73 [self setUpRampRecordsInCloudKitWithFeatureOn];
74 [self startCKKSSubsystem];
75
76 __block NSData* localEntropy = nil;
77 __block NSString* localBottleID = nil;
78
79 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
80
81 [self.otControl preflightBottledPeer:testContextID
82 dsid:testDSID
83 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
84 [self.spiBlockExpectation fulfill];
85 localEntropy = entropy;
86 localBottleID = bottleID;
87 XCTAssertNotNil(entropy, "entropy should not be nil");
88 XCTAssertNotNil(bottleID, "bottle id should not be nil");
89 XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil");
90 XCTAssertNil(error, "error should be nil");
91 }];
92 [self waitForExpectationsWithTimeout:1.0 handler:nil];
93
94 self.spiBlockExpectation = [self expectationWithDescription:@"launch bottled peer fired"];
95
96 NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil];
97
98 [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO];
99
100 [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
101 [self.spiBlockExpectation fulfill];
102 XCTAssertNil(error, "error should be nil");
103 }];
104
105 [self waitForExpectationsWithTimeout:1.0 handler:nil];
106 }
107
108 -(void) testRestoreWithRampOn
109 {
110 [self setUpRampRecordsInCloudKitWithFeatureOn];
111 [self startCKKSSubsystem];
112
113 __block NSData* localEntropy = nil;
114 __block NSString* localBottleID = nil;
115
116 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
117
118 [self.otControl preflightBottledPeer:OTDefaultContext
119 dsid:@"dsid"
120 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
121 [self.spiBlockExpectation fulfill];
122 localEntropy = entropy;
123 localBottleID = bottleID;
124 XCTAssertNotNil(entropy, "entropy should not be nil");
125 XCTAssertNotNil(bottleID, "bottle id should not be nil");
126 XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil");
127 XCTAssertNil(error, "error should be nil");
128 }];
129 [self waitForExpectationsWithTimeout:1.0 handler:nil];
130
131 __block NSData* localSigningKeyData = nil;
132 __block NSData* localEncryptionKeyData = nil;
133
134 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
135
136 [self.otControl restore:testContextID
137 dsid:testDSID
138 secret:localEntropy
139 escrowRecordID:self.sosPeerID
140 reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) {
141 [self.spiBlockExpectation fulfill];
142 localSigningKeyData = signingKeyData;
143 localEncryptionKeyData = encryptionKeyData;
144 XCTAssertNotNil(signingKeyData, "Signing key data should not be nil");
145 XCTAssertNotNil(encryptionKeyData, "encryption key data should not be nil");
146 XCTAssertNil(error, "error should not be nil");
147 }];
148 [self waitForExpectationsWithTimeout:1.0 handler:nil];
149 NSError* localError = nil;
150
151 OTIdentity *ourSelf = [self currentIdentity:&localError];
152 XCTAssertTrue([localSigningKeyData isEqualToData:[ourSelf.peerSigningKey.publicKey keyData]], @"signing keys should be equal!");
153 XCTAssertTrue([localEncryptionKeyData isEqualToData:[ourSelf.peerEncryptionKey.publicKey keyData]], @"signing keys should be equal!");
154 }
155
156 -(void) testScrubWithRampOn
157 {
158 [self setUpRampRecordsInCloudKitWithFeatureOn];
159 [self startCKKSSubsystem];
160
161 __block NSString* localBottleID = nil;
162
163 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
164
165 [self.otControl preflightBottledPeer:testContextID
166 dsid:testDSID
167 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
168 [self.spiBlockExpectation fulfill];
169 localBottleID = bottleID;
170 XCTAssertNotNil(entropy, "entropy should not be nil");
171 XCTAssertNotNil(bottleID, "bottle id should not be nil");
172 XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil");
173 XCTAssertNil(error, "error should be nil");
174 }];
175
176 [self waitForExpectationsWithTimeout:1.0 handler:nil];
177
178 self.spiBlockExpectation = [self expectationWithDescription:@"scrub scheduler fired"];
179
180 [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
181 [self.spiBlockExpectation fulfill];
182 XCTAssertNil(error, "error should be nil");
183 }];
184 [self waitForExpectationsWithTimeout:1.0 handler:nil];
185
186 NSError* localError = nil;
187 NSArray* bottles = [self.localStore readAllLocalBottledPeerRecords:&localError];
188 XCTAssertNotNil(localError, "error should not be nil");
189 XCTAssertTrue([bottles count] == 0, "should be 0 bottles");
190 }
191
192 -(void) testPreflightWithRampOff
193 {
194 [self setUpRampRecordsInCloudKitWithFeatureOff];
195
196 [self startCKKSSubsystem];
197
198 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
199
200 [self.otControl preflightBottledPeer:OTDefaultContext
201 dsid:@"dsid"
202 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
203 [self.spiBlockExpectation fulfill];
204 XCTAssertNil(entropy, "shouldn't return any entropy");
205 XCTAssertNil(bottleID, "shouldn't return a bottle ID");
206 XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey");
207 XCTAssertTrue(error.code == OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error");
208 }];
209 [self waitForCKModifications];
210 OCMVerifyAllWithDelay(self.mockDatabase, 8);
211 [self waitForExpectationsWithTimeout:1.0 handler:nil];
212 }
213
214 -(void) testPreflightWithRecordNotThere
215 {
216 [self startCKKSSubsystem];
217
218 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
219
220 [self.otControl preflightBottledPeer:OTDefaultContext
221 dsid:@"dsid"
222 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
223 [self.spiBlockExpectation fulfill];
224 XCTAssertNil(entropy, "shouldn't return any entropy");
225 XCTAssertNil(bottleID, "shouldn't return a bottle ID");
226 XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey");
227 XCTAssertNotNil(error, "should not be nil");
228 }];
229 [self waitForCKModifications];
230 OCMVerifyAllWithDelay(self.mockDatabase, 8);
231 [self waitForExpectationsWithTimeout:1.0 handler:nil];
232 }
233
234 -(void) testLaunchWithRampOff
235 {
236 [self setUpRampRecordsInCloudKitWithFeatureOff];
237
238 [self startCKKSSubsystem];
239
240 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"];
241
242 [self.otControl preflightBottledPeer:OTDefaultContext
243 dsid:@"dsid"
244 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
245 [self.spiBlockExpectation fulfill];
246 XCTAssertNil(entropy, "shouldn't return any entropy");
247 XCTAssertNil(bottleID, "shouldn't return a bottle ID");
248 XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey");
249 XCTAssertTrue(error.code == OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error");
250 }];
251 [self waitForCKModifications];
252 OCMVerifyAllWithDelay(self.mockDatabase, 8);
253 [self waitForExpectationsWithTimeout:1.0 handler:nil];
254
255
256 self.spiBlockExpectation = [self expectationWithDescription:@"launch SPI fired"];
257
258 NSString* localBottleID = @"random bottle id";
259 [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
260 [self.spiBlockExpectation fulfill];
261 XCTAssertTrue(error.code == OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error");
262 }];
263
264 [self waitForCKModifications];
265 OCMVerifyAllWithDelay(self.mockDatabase, 8);
266 [self waitForExpectationsWithTimeout:1.0 handler:nil];
267 }
268 -(void) testRestoreWithRampOff
269 {
270 [self setUpRampRecordsInCloudKitWithFeatureOff];
271 [self startCKKSSubsystem];
272
273 self.spiBlockExpectation = [self expectationWithDescription:@"restore SPI fired"];
274
275 [self.otControl restore:testContextID
276 dsid:testDSID
277 secret:self.secret
278 escrowRecordID:self.sosPeerID
279 reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) {
280 [self.spiBlockExpectation fulfill];
281 XCTAssertNil(signingKeyData, "Signing key data should be nil");
282 XCTAssertNil(encryptionKeyData, "encryption key data should be nil");
283 XCTAssertTrue(error.code == OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error");
284 }];
285 [self waitForCKModifications];
286 OCMVerifyAllWithDelay(self.mockDatabase, 8);
287 [self waitForExpectationsWithTimeout:1.0 handler:nil];
288 }
289
290 -(void) testScrubWithRampOff
291 {
292 [self setUpRampRecordsInCloudKitWithFeatureOff];
293 [self startCKKSSubsystem];
294
295 self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer SPI fired"];
296
297 [self.otControl preflightBottledPeer:testContextID
298 dsid:testDSID
299 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
300 [self.spiBlockExpectation fulfill];
301 XCTAssertNil(entropy, "entropy should be nil");
302 XCTAssertNil(bottleID, "bottle id should be nil");
303 XCTAssertNil(signingPublicKey, "signing pub key should be nil");
304 XCTAssertTrue(error.code == OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error");
305 }];
306
307 [self waitForExpectationsWithTimeout:1.0 handler:nil];
308
309 __block NSString* localBottleID = @"random bottle id";
310 self.spiBlockExpectation = [self expectationWithDescription:@"scrub bottled peer SPI fired"];
311
312 [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) {
313 [self.spiBlockExpectation fulfill];
314 XCTAssertTrue(error.code == OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error");
315 }];
316
317 [self waitForCKModifications];
318 OCMVerifyAllWithDelay(self.mockDatabase, 8);
319 [self waitForExpectationsWithTimeout:1.0 handler:nil];
320
321 [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
322 [self startCKKSSubsystem];
323
324 XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:4*NSEC_PER_SEC], @"Key state should have arrived at ready");
325 }
326
327 -(void) testRampFetchTimeout
328 {
329 [self startCKKSSubsystem];
330
331 __block NSError* localError = nil;
332
333 [self holdCloudKitFetches];
334
335 [self.otControl preflightBottledPeer:OTDefaultContext
336 dsid:@"dsid"
337 reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) {
338 localError = error;
339 XCTAssertNil(entropy, "shouldn't return any entropy");
340 XCTAssertNil(bottleID, "shouldn't return a bottle ID");
341 XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey");
342 XCTAssertTrue(error.code == OTErrorCKTimeOut, "should return a OTErrorCKTimeout error");
343 }];
344 }
345
346 -(void)testCFUWithRampOn
347 {
348 NSError* localError = nil;
349 NSInteger retryAfterInSeconds = 0;
350
351 [self setUpRampRecordsInCloudKitWithFeatureOn];
352
353 XCTAssertTrue([self.cfu checkRampState:&retryAfterInSeconds qos:NSQualityOfServiceUserInitiated error:&localError], @"should be true");
354 }
355
356 -(void)testCFUWithRampOff
357 {
358 NSError* localError = nil;
359 NSInteger retryAfterInSeconds = 0;
360 [self setUpRampRecordsInCloudKitWithFeatureOff];
361
362 XCTAssertTrue(![self.cfu checkRampState:&retryAfterInSeconds qos:NSQualityOfServiceUserInitiated error:&localError], @"should be false");
363
364 XCTAssertTrue(retryAfterInSeconds != 0, @"should be asked to retry later");
365 }
366
367 -(void)testCFUWithNonExistentRampRecord
368 {
369 NSError* localError = nil;
370 NSInteger retryAfterInSeconds = 0;
371 XCTAssertTrue(![self.cfu checkRampState:&retryAfterInSeconds qos:NSQualityOfServiceUserInitiated error:&localError], @"should be false");
372 }
373
374 @end
375
376 #endif /* OCTAGON */
377