]> git.saurik.com Git - apple/security.git/blob - keychain/ot/tests/OTCloudStoreTests.m
Security-59306.11.20.tar.gz
[apple/security.git] / keychain / ot / tests / OTCloudStoreTests.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* OTCKRecordBottledPeerType = @"OTBottledPeer";
34 static NSString* OTCKRecordEscrowRecordID = @"escrowRecordID";
35
36 @interface OTCloudStoreUnitTests : OTTestsBase
37 @property (nonatomic, strong) OTBottledPeerRecord* fakeBottledPeerRecord;
38 @end
39
40 @implementation OTCloudStoreUnitTests
41
42
43 - (void)setUp {
44 [super setUp];
45 self.continueAfterFailure = NO;
46 self.fakeBottledPeerRecord = [[OTBottledPeerRecord alloc] init];
47 self.fakeBottledPeerRecord.bottle = [@"bottled peer data" dataUsingEncoding:NSUTF8StringEncoding];
48 self.fakeBottledPeerRecord.signatureUsingEscrowKey = [@"bottled peer escrow sig" dataUsingEncoding:NSUTF8StringEncoding];
49 self.fakeBottledPeerRecord.signatureUsingPeerKey = [@"bottled peer peer sig" dataUsingEncoding:NSUTF8StringEncoding];
50 self.fakeBottledPeerRecord.peerID = @"peer id";
51 self.fakeBottledPeerRecord.spID = @"sos peer id";
52 self.fakeBottledPeerRecord.escrowRecordID = @"escrowRecordID";
53 self.fakeBottledPeerRecord.escrowedSigningSPKI = [@"escrowedSigningSPKI" dataUsingEncoding:NSUTF8StringEncoding];
54 self.fakeBottledPeerRecord.peerSigningSPKI = [@"peerSigningSPKI" dataUsingEncoding:NSUTF8StringEncoding];
55 }
56
57 - (void)tearDown {
58 self.zones = nil;
59 self.operationQueue = nil;
60
61 [super tearDown];
62 }
63
64 - (void)testWriteSameBottledPeerTwiceToFakeRecord {
65 NSError* error = nil;
66
67 NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil];
68
69 [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES];
70 [self startCKKSSubsystem];
71 XCTAssertTrue([self.cloudStore uploadBottledPeerRecord:self.fakeBottledPeerRecord escrowRecordID:self.fakeBottledPeerRecord.escrowRecordID error:&error], @"should create bottled peer record");
72 XCTAssertNil(error, "error should be nil");
73
74 [self waitForCKModifications];
75 OCMVerifyAllWithDelay(self.mockDatabase, 8);
76 [self releaseCloudKitFetchHold];
77
78 [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES];
79
80 XCTAssertTrue([self.cloudStore uploadBottledPeerRecord:self.fakeBottledPeerRecord escrowRecordID:self.fakeBottledPeerRecord.escrowRecordID error:&error], @"should create bottled peer record");
81 XCTAssertNil(error, "error should be nil");
82
83 [self waitForCKModifications];
84 OCMVerifyAllWithDelay(self.mockDatabase, 8);
85 [self releaseCloudKitFetchHold];
86 }
87
88 - (void)testWriteBottledPeerToFakeRecord {
89 NSError* error = nil;
90
91 NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionary];
92 recordDictionary[OTCKRecordBottledPeerType] = [[NSNumber alloc] initWithInt:1];
93
94 [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES];
95 [self startCKKSSubsystem];
96
97 XCTAssertTrue([self.cloudStore uploadBottledPeerRecord:self.fakeBottledPeerRecord escrowRecordID:self.fakeBottledPeerRecord.escrowRecordID error:&error], @"should create bottled peer record");
98 XCTAssertNil(error, "error should be nil");
99
100 [self waitForCKModifications];
101 OCMVerifyAllWithDelay(self.mockDatabase, 8);
102 [self releaseCloudKitFetchHold];
103 }
104
105 - (void)testWriteMultipleBottledPeersToSAMEFakeRecord {
106 NSError* error = nil;
107
108 NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionary];
109
110 recordDictionary[OTCKRecordBottledPeerType] = [[NSNumber alloc] initWithInt:1];
111
112 [self startCKKSSubsystem];
113
114 for(int i = 0; i < 10; i++){
115 [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO];
116
117 XCTAssertTrue([self.cloudStore uploadBottledPeerRecord:self.fakeBottledPeerRecord escrowRecordID:self.fakeBottledPeerRecord.escrowRecordID error:&error], @"should create bottled peer record");
118
119 [self waitForCKModifications];
120
121 XCTAssertNil(error, "error should be nil");
122 OCMVerifyAllWithDelay(self.mockDatabase, 8);
123 [self releaseCloudKitFetchHold];
124 }
125 }
126
127 - (void)testWriteBottledPeersToDifferentFakeRecord {
128 NSError* error = nil;
129
130 NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionary];
131
132 recordDictionary[OTCKRecordBottledPeerType] = [[NSNumber alloc] initWithInt:1];
133
134 [self startCKKSSubsystem];
135
136 for(int i = 0; i < 10; i++){
137 [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES];
138 NSString *escrowID = [NSString stringWithFormat:@"bp-sospeer%d-hash", i];
139 self.fakeBottledPeerRecord.escrowRecordID = escrowID;
140 XCTAssertTrue([self.cloudStore uploadBottledPeerRecord:self.fakeBottledPeerRecord escrowRecordID:escrowID error:&error], @"should create bottled peer record");
141 [self waitForCKModifications];
142
143 XCTAssertNil(error, "error should be nil");
144 OCMVerifyAllWithDelay(self.mockDatabase, 8);
145 [self releaseCloudKitFetchHold];
146 }
147 XCTAssertTrue( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count] == 10, @"should have 1 record");
148 }
149
150
151 - (void)testReadBottledPeerRecordFromCloudKit {
152 NSError *error = nil;
153 [self startCKKSSubsystem];
154
155 CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType];
156 newRecord[OTCKRecordEscrowRecordID] = @"escrowRecordID";
157 [self.otFakeZone addToZone:newRecord];
158
159 [self.cloudStore notifyZoneChange:nil];
160
161 [self waitForCKModifications];
162
163 OCMVerifyAllWithDelay(self.mockDatabase, 8);
164 XCTAssertTrue( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count] > 0, @"should have 1 record");
165 }
166
167 -(void) testOTCloudStoreDownloadBP{
168 NSError* error = nil;
169 [self startCKKSSubsystem];
170
171 CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType];
172 newRecord[OTCKRecordEscrowRecordID] = @"escrowRecordID";
173 [self.otFakeZone addToZone:newRecord];
174
175 XCTAssertTrue([self.cloudStore downloadBottledPeerRecord:&error] == YES, @"downloading records should succeed:%@", error);
176 XCTAssertNil(error, @"error should be nil");
177
178 [self waitForCKModifications];
179
180 OCMVerifyAllWithDelay(self.mockDatabase, 8);
181
182 XCTAssertNil(error, "error should be nil");
183 XCTAssertEqual([[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count], (unsigned long)1, @"should have 1 record");
184 XCTAssertNil(error, "error should be nil");
185 }
186
187 -(void) testOTCloudStoreDownloadMultipleBP{
188 NSError* error = nil;
189 [self startCKKSSubsystem];
190
191 for(int i = 0; i < 10; i++){
192 CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType zoneID:self.otZoneID];
193 newRecord[OTCKRecordEscrowRecordID] = [NSString stringWithFormat:@"escrowRecordID%d", i];
194 [self.otFakeZone addToZone:newRecord];
195 }
196 [self waitForCKModifications];
197
198 XCTAssertTrue([self.cloudStore downloadBottledPeerRecord:&error] == YES, @"downloading records should succeed:%@", error);
199 XCTAssertNil(error, @"error should be nil");
200 [self waitForCKModifications];
201
202 OCMVerifyAllWithDelay(self.mockDatabase, 8);
203
204 XCTAssertNil(error, "error should be nil");
205 XCTAssertEqual( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count], (unsigned long)10, @"should have 1 record");
206 }
207
208 -(void) testOTCloudStoreUploadMultipleToSameRecord{
209 NSError* error = nil;
210 [self startCKKSSubsystem];
211 CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType zoneID:self.otZoneID];
212 newRecord[OTCKRecordEscrowRecordID] = @"escrowRecordID";
213 for(int i = 0; i < 10; i++){
214 [self.otFakeZone addToZone:newRecord];
215 }
216 [self waitForCKModifications];
217
218 XCTAssertTrue([self.cloudStore downloadBottledPeerRecord:&error] == YES, @"downloading records should succeed:%@", error);
219 XCTAssertNil(error, @"error should be nil");
220 [self waitForCKModifications];
221
222 OCMVerifyAllWithDelay(self.mockDatabase, 8);
223
224 XCTAssertNil(error, "error should be nil");
225 XCTAssertEqual([[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count], (unsigned long)1, @"should have 1 record");
226 }
227
228 -(void) testRemoveRecordIDs{
229
230 [self startCKKSSubsystem];
231 NSError *error = nil;
232 CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType zoneID:self.otZoneID];
233 newRecord[OTCKRecordEscrowRecordID] = @"escrowRecordID";
234 [self expectCKFetch];
235
236 [self.otFakeZone addToZone:newRecord];
237 [self waitForCKModifications];
238
239 [self.cloudStore notifyZoneChange:nil];
240 [self waitForCKModifications];
241
242 XCTAssertTrue( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count] == 1, @"should have 1 record");
243
244 [self expectCKFetch];
245 XCTAssertTrue([self.cloudStore downloadBottledPeerRecord:&error] == YES, @"downloading records should succeed:%@", error);
246 XCTAssertNil(error, @"error should be nil");
247 [self waitForCKModifications];
248 }
249
250 -(void) testFetchTimeout
251 {
252 [self startCKKSSubsystem];
253
254 NSError* error = nil;
255 CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType zoneID:self.otZoneID];
256 newRecord[OTCKRecordEscrowRecordID] = @"escrowRecordID";
257
258 [self holdCloudKitFetches];
259
260 [self.cloudStore downloadBottledPeerRecord:&error];
261
262 XCTAssertNotNil(error, "error should not be nil");
263 XCTAssertTrue([(NSString*)error.userInfo[@"NSLocalizedDescription"] isEqualToString:@"Operation(CKKSResultOperation(cloudkit-fetch-and-process-changes)) timed out waiting to start for [<CKKSResultOperation(fetch-and-process-updates-watcher): ready>]"], "expecting timed out error");
264 }
265
266 -(void) testModifyRecordsTimeout
267 {
268 NSError* error = nil;
269
270 [self expectAddedCKModifyRecords:@{OTCKRecordBottledPeerType: @1} holdFetch:NO];
271
272 [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
273 [self putSelfTLKSharesInCloudKit:self.keychainZoneID];
274 [self startCKKSSubsystem];
275
276 XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:4*NSEC_PER_SEC], @"Key state should have arrived at ready");
277
278 [self holdCloudKitModifications];
279
280 [self.cloudStore uploadBottledPeerRecord:self.fakeBottledPeerRecord
281 escrowRecordID:self.fakeBottledPeerRecord.escrowRecordID error:&error];
282
283 XCTAssertNotNil(error, "error should not be nil");
284 XCTAssertTrue([(NSString*)error.userInfo[@"NSLocalizedDescription"] isEqualToString:@"Operation(CKKSResultOperation(cloudkit-modify-changes)) timed out waiting to start for [<CKKSResultOperation(modify-records-watcher): ready>]"], "expecting timed out error");
285
286 [self expectAddedCKModifyRecords:@{OTCKRecordBottledPeerType: @1} holdFetch:NO];
287
288 [self releaseCloudKitModificationHold];
289 [self waitForCKModifications];
290 }
291
292 @end
293
294 #endif /* OCTAGON */
295