2 * Copyright (c) 2017 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
27 #import <Foundation/Foundation.h>
28 #import <XCTest/XCTest.h>
29 #import <OCMock/OCMock.h>
31 #import "OTTestsBase.h"
33 static NSString* const testContextID = @"Foo";
34 static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer";
36 @interface UnitTestOTContext : OTTestsBase
37 @property (nonatomic, strong) OTBottledPeerRecord* fakeBottledPeerRecord;
40 @implementation UnitTestOTContext
45 self.continueAfterFailure = NO;
51 self.operationQueue = nil;
59 NSString* escrowRecordID = [self currentIdentity:&error].spID;
60 XCTAssertNil(error, @"error should be nil: %@", error);
61 XCTAssertNotNil(escrowRecordID, @"escrowRecordID should not be nil: %@", error);
63 NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil];
65 [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES];
66 [self startCKKSSubsystem];
68 OTPreflightInfo* info = nil;
69 XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info:%@", error);
70 XCTAssertNil(error, @"error should be nil: %@", error);
71 XCTAssertNotNil(info, @"preflight info should not be nil: %@", error);
72 XCTAssertNotNil(info.bottleID, @"escrowRecordID should not be nil: %@", error);
73 XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil: %@", error);
75 OTBottledPeerRecord* bprecord = [self.localStore readLocalBottledPeerRecordWithRecordID:info.bottleID error:&error];
76 XCTAssertNotNil(bprecord, @"bprecord should not be nil: %@", error);
78 XCTAssertTrue([self.context.cloudStore uploadBottledPeerRecord:bprecord escrowRecordID:escrowRecordID error:&error], @"launch should succeed");
79 XCTAssertNil(error, @"error should be nil: %@", error);
80 [self releaseCloudKitFetchHold];
83 XCTAssertEqual( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count], (unsigned long)1, @"should have 1 record");
86 -(void) testEnrollAndRestore
89 [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
91 NSString* escrowRecordID = [self currentIdentity:&error].spID;
92 XCTAssertNil(error, @"error should be nil: %@", error);
93 XCTAssertNotNil(escrowRecordID, @"escrowRecordID should not be nil: %@", error);
95 NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil];
97 [self startCKKSSubsystem];
99 OTPreflightInfo* info = nil;
100 XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info");
101 XCTAssertNil(error, @"error should be nil: %@", error);
102 XCTAssertNotNil(info, @"preflight info should not be nil: %@", error);
103 XCTAssertNotNil(info.bottleID, @"escrowRecordID should not be nil: %@", error);
104 XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil: %@", error);
106 OTBottledPeerRecord* bprecord = [self.localStore readLocalBottledPeerRecordWithRecordID:info.bottleID error:&error];
107 XCTAssertNotNil(bprecord, @"bprecord should not be nil: %@", error);
109 [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO];
110 XCTAssertTrue([self.cloudStore uploadBottledPeerRecord:bprecord escrowRecordID:bprecord.escrowRecordID error:&error], @"should create bottled peer record");
111 XCTAssertNil(error, "error should be nil");
112 [self waitForCKModifications];
114 [self releaseCloudKitFetchHold];
116 OTBottledPeerSigned* bp = [self.context restoreFromEscrowRecordID:escrowRecordID secret:self.secret error:&error];
117 [self waitForCKModifications];
119 XCTAssertTrue( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count] == 1, @"should have 1 record");
120 [self waitForCKModifications];
122 XCTAssertNil(error, @"error should be nil: %@", error);
123 XCTAssertNotNil(bp, @"signed bottled peer should not be nil: %@", error);
124 XCTAssertTrue([bp.bp.peerEncryptionKey isEqual:self.peerEncryptionKey], @"enrolled and restored peer encryption keys should match");
125 XCTAssertTrue([bp.bp.peerSigningKey isEqual:self.peerSigningKey], @"enrolled and restored peer signing keys should match");
128 -(void)testEnrollAndRestoreFromCloudKit
130 NSError* error = nil;
131 [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
133 NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil];
135 [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES];
136 [self startCKKSSubsystem];
138 OTPreflightInfo* info = nil;
139 XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info");
140 XCTAssertNil(error, @"error should be nil: %@", error);
141 XCTAssertNotNil(info, @"preflight info should not be nil: %@", error);
142 XCTAssertNotNil(info.bottleID, @"bottleID should not be nil: %@", error);
143 XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil: %@", error);
145 OTBottledPeerRecord* bprecord = [self.localStore readLocalBottledPeerRecordWithRecordID:info.bottleID error:&error];
146 XCTAssertNotNil(bprecord, @"bprecord should not be nil: %@", error);
148 XCTAssertTrue([self.context.cloudStore uploadBottledPeerRecord:bprecord escrowRecordID:info.bottleID error:&error], @"launch should succeed");
149 XCTAssertNil(error, @"error should be nil: %@", error);
151 [self waitForCKModifications];
152 OCMVerifyAllWithDelay(self.mockDatabase, 8);
153 [self releaseCloudKitFetchHold];
155 XCTAssertTrue([[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count] > 0, @"should have multiple records");
156 OTIdentity *identity = [self currentIdentity:&error];
158 XCTAssertNil(error, @"error should be nil: %@", error);
159 XCTAssertNotNil(self.escrowKeys, @"escrow keys should not be nil: %@", error);
161 NSString* recordName = [OTBottledPeerRecord constructRecordID:identity.spID escrowSigningSPKI:[self.escrowKeys.signingKey.publicKey encodeSubjectPublicKeyInfo]];
163 OTBottledPeerRecord *rec = [self.localStore readLocalBottledPeerRecordWithRecordID:recordName error:&error];
165 XCTAssertNotNil(rec.signatureUsingEscrowKey, @"signatureUsingEscrow should not be nil: %@", error);
167 XCTAssertNotNil(rec.signatureUsingPeerKey, @"signatureUsingPeerKey should not be nil: %@", error);
169 XCTAssertNotNil(rec.bottle, @"bottle should not be nil: %@", error);
172 OTBottledPeerSigned *bps = [[OTBottledPeerSigned alloc] initWithBottledPeerRecord:rec
173 escrowKeys:self.escrowKeys
175 XCTAssertNil(error, @"error should be nil: %@", error);
176 XCTAssertNotNil(bps, @"signed bottled peer should not be nil: %@", error);
177 XCTAssertTrue([bps.bp.peerEncryptionKey isEqual:self.peerEncryptionKey], @"enrolled and restored peer encryption keys should match");
178 XCTAssertTrue([bps.bp.peerSigningKey isEqual:self.peerSigningKey], @"enrolled and restored peer signing keys should match");
181 -(void) testScrubbing
183 NSError* error = nil;
185 NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil];
187 [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES];
188 [self startCKKSSubsystem];
190 OTPreflightInfo* info = nil;
191 XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info");
192 XCTAssertNil(error, @"error should be nil: %@", error);
193 XCTAssertNotNil(info, @"preflight info should not be nil: %@", error);
194 XCTAssertNotNil(info.bottleID, @"escrowRecordID should not be nil: %@", error);
195 XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil: %@", error);
197 XCTAssertTrue([self.context scrubBottledPeer:testContextID bottleID:info.bottleID error:&error], @"scrubbing bottled peer should succeed");
198 XCTAssertNil(error, @"error should be nil: %@", error);
199 NSArray* list = [self.context.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error];
200 XCTAssertTrue([list count] == 0, @"there should be 0 records in localstore");
203 -(void) testGettingListOfRecordIDS
205 NSError* error = nil;
207 NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil];
208 [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES];
209 [self startCKKSSubsystem];
211 OTPreflightInfo* info = nil;
212 XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info");
213 XCTAssertNil(error, @"error should be nil: %@", error);
214 XCTAssertNotNil(info, @"preflight info should not be nil: %@", error);
215 XCTAssertNotNil(info.bottleID, @"bottleID should not be nil: %@", error);
216 XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil: %@", error);
218 OTBottledPeerRecord* bprecord = [self.localStore readLocalBottledPeerRecordWithRecordID:info.bottleID error:&error];
219 XCTAssertNotNil(bprecord, @"bprecord should not be nil: %@", error);
221 XCTAssertTrue([self.context.cloudStore uploadBottledPeerRecord:bprecord escrowRecordID:info.bottleID error:&error], @"launch should succeed");
222 XCTAssertNil(error, @"error should be nil: %@", error);
224 [self waitForCKModifications];
225 OCMVerifyAllWithDelay(self.mockDatabase, 8);
226 [self releaseCloudKitFetchHold];
228 NSArray* list = [self.context.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error];
229 XCTAssertNotNil(list, @"list should not be nil");
230 XCTAssertTrue([list count] > 0, @"list of escrow record ids should not be empty");
233 - (nullable OTIdentity *)currentIdentity:(NSError**)error {
235 return [[OTIdentity alloc]initWithPeerID:@"ego peer id" spID:@"sos peer id" peerSigningKey:self.peerSigningKey peerEncryptionkey:self.peerEncryptionKey error:error];