]> git.saurik.com Git - apple/security.git/blob - keychain/ckks/tests/CKKSTLKSharingEncryptionTests.m
Security-59306.11.20.tar.gz
[apple/security.git] / keychain / ckks / tests / CKKSTLKSharingEncryptionTests.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 <XCTest/XCTest.h>
27 #import "keychain/ckks/CKKS.h"
28 #import "keychain/ckks/CKKSKey.h"
29 #import "keychain/ckks/CKKSTLKShareRecord.h"
30 #import "keychain/ckks/CKKSPeer.h"
31 #import "keychain/ckks/tests/CloudKitMockXCTest.h"
32
33 #import <SecurityFoundation/SFSigningOperation.h>
34 #import <SecurityFoundation/SFKey.h>
35 #import <SecurityFoundation/SFKey_Private.h>
36 #import <SecurityFoundation/SFDigestOperation.h>
37
38 @interface CloudKitKeychainTLKSharingEncryptionTests : CloudKitMockXCTest
39 @property CKKSKey* tlk;
40 @property CKKSSOSSelfPeer* localPeer;
41 @property CKKSSOSSelfPeer* remotePeer;
42 @property CKKSSOSSelfPeer* remotePeer2;
43 @end
44
45 @implementation CloudKitKeychainTLKSharingEncryptionTests
46
47 - (void)setUp {
48 // We don't really want to spin up the whole machinery for the encryption tests
49 SecCKKSDisable();
50
51 NSError* error = nil;
52 self.tlk = [CKKSKey randomKeyWrappedBySelf:[[CKRecordZoneID alloc] initWithZoneName:@"testzone" ownerName:CKCurrentUserDefaultName] error:&error];
53 XCTAssertNil(error, "Shouldn't be an error creating a new TLK");
54
55 self.localPeer = [[CKKSSOSSelfPeer alloc] initWithSOSPeerID:@"local"
56 encryptionKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]
57 signingKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]
58 viewList:self.managedViewList];
59 XCTAssertNotNil(self.localPeer, "Should be able to make a new local peer");
60
61 self.remotePeer = [[CKKSSOSSelfPeer alloc] initWithSOSPeerID:@"remote"
62 encryptionKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]
63 signingKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]
64 viewList:self.managedViewList];
65 XCTAssertNotNil(self.remotePeer, "Should be able to make a new remote peer");
66
67 self.remotePeer2 = [[CKKSSOSSelfPeer alloc] initWithSOSPeerID:@"remote"
68 encryptionKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]
69 signingKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]
70 viewList:self.managedViewList];
71 XCTAssertNotNil(self.remotePeer2, "Should be able to make a new remote peer");
72
73 [super setUp];
74 }
75
76 - (void)tearDown {
77 [super tearDown];
78 }
79
80 - (void)testKeyWrapAndUnwrap {
81 NSError* error = nil;
82 CKKSTLKShareRecord* share = [CKKSTLKShareRecord share:self.tlk
83 as:self.localPeer
84 to:self.remotePeer
85 epoch:-1
86 poisoned:0
87 error:&error];
88 XCTAssertNil(error, "Should have been no error sharing a CKKSKey");
89
90 XCTAssertEqual(self.tlk.uuid, share.tlkUUID, "TLK shares should know which key they hold");
91
92 CKKSKey* unwrappedKey = [share unwrapUsing:self.remotePeer error:&error];
93 XCTAssertNil(error, "Should have been no error unwrapping a CKKSKey");
94 XCTAssertEqualObjects(self.tlk, unwrappedKey, "CKKSKeys should be identical after wrapping/unwrapping through a TLK Share record");
95 }
96
97 - (void)testTLKShareSignAndVerify {
98 NSError* error = nil;
99 CKKSTLKShareRecord* share = [CKKSTLKShareRecord share:self.tlk
100 as:self.localPeer
101 to:self.remotePeer
102 epoch:-1
103 poisoned:0
104 error:&error];
105 XCTAssertNil(error, "Should have been no error sharing a CKKSKey");
106
107 NSData* signature = [share signRecord:self.localPeer.signingKey error:&error];
108 XCTAssertNil(error, "Should have been no error signing a CKKSTLKShare");
109 XCTAssertNotNil(signature, "Should have received a signature blob");
110
111 XCTAssertTrue([share verifySignature:signature verifyingPeer:self.localPeer error:&error], "Signature should verify using the local peer's signing key");
112 }
113
114 - (void)testTLKShareSignAndFailVerify {
115 NSError* error = nil;
116 CKKSTLKShareRecord* share = [CKKSTLKShareRecord share:self.tlk
117 as:self.localPeer
118 to:self.remotePeer
119 epoch:-1
120 poisoned:0
121 error:&error];
122 XCTAssertNil(error, "Should have been no error sharing a CKKSKey");
123
124 NSData* signature = [share signRecord:self.localPeer.signingKey error:&error];
125 XCTAssertNil(error, "Should have been no error signing a CKKSTLKShare");
126 XCTAssertNotNil(signature, "Should have received a signature blob");
127
128 CKKSTLKShareRecord* shareEpoch = [share copy];
129 XCTAssertTrue([shareEpoch verifySignature:signature verifyingPeer:self.localPeer error:&error], "Signature should verify using the local peer's signing key");
130 error = nil;
131 shareEpoch.share.epoch = 1;
132 XCTAssertFalse([shareEpoch verifySignature:signature verifyingPeer:self.localPeer error:&error], "After epoch change, signature should no longer verify");
133 XCTAssertNotNil(error, "Signature verification after epoch change should have produced an error");
134 error = nil;
135
136 CKKSTLKShareRecord* sharePoisoned = [share copy];
137 XCTAssertTrue([sharePoisoned verifySignature:signature verifyingPeer:self.localPeer error:&error], "Signature should verify using the local peer's signing key");
138 error = nil;
139 sharePoisoned.share.poisoned = 1;
140 XCTAssertFalse([sharePoisoned verifySignature:signature verifyingPeer:self.localPeer error:&error], "After poison change, signature should no longer verify");
141 XCTAssertNotNil(error, "Signature verification after poison change should have produced an error");
142 error = nil;
143
144 CKKSTLKShareRecord* shareData = [share copy];
145 XCTAssertTrue([shareData verifySignature:signature verifyingPeer:self.localPeer error:&error], "Signature should verify using the local peer's signing key");
146 error = nil;
147 shareData.share.wrappedTLK = [NSMutableData dataWithLength:shareData.wrappedTLK.length];
148 XCTAssertFalse([shareData verifySignature:signature verifyingPeer:self.localPeer error:&error], "After data change, signature should no longer verify");
149 XCTAssertNotNil(error, "Signature verification due to data change should have produced an error");
150 error = nil;
151 }
152
153 - (void)testKeyShareAndRecover {
154 NSError* error = nil;
155 CKKSTLKShareRecord* share = [CKKSTLKShareRecord share:self.tlk
156 as:self.localPeer
157 to:self.remotePeer
158 epoch:-1
159 poisoned:0
160 error:&error];
161 XCTAssertNil(error, "Should have been no error sharing a CKKSKey");
162
163 NSSet* peers = [NSSet setWithObject:self.localPeer];
164 CKKSKey* key = [share recoverTLK:self.remotePeer trustedPeers:peers error:&error];
165 XCTAssertNil(error, "Should have been no error unwrapping a CKKSKey");
166 XCTAssertEqualObjects(self.tlk, key, "CKKSKeys should be identical after wrapping/unwrapping through a TLK Share record");
167 }
168
169 - (void)testKeyShareAndFailRecovery {
170 NSError* error = nil;
171 CKKSKey* key = nil;
172 CKKSTLKShareRecord* share = [CKKSTLKShareRecord share:self.tlk
173 as:self.localPeer
174 to:self.remotePeer
175 epoch:-1
176 poisoned:0
177 error:&error];
178 XCTAssertNil(error, "Should have been no error sharing a CKKSKey");
179
180 NSSet* peers = [NSSet setWithObject:self.localPeer];
181
182 key = [share recoverTLK:self.remotePeer trustedPeers:[NSSet set] error:&error];
183 XCTAssertNil(key, "No key should have been extracted when no trusted peers exist");
184 XCTAssertNotNil(error, "Should have produced an error when failing to extract a key with no trusted peers");
185 error = nil;
186
187 key = [share recoverTLK:self.remotePeer2 trustedPeers:peers error:&error];
188 XCTAssertNil(key, "No key should have been extracted when using the wrong key");
189 XCTAssertNotNil(error, "Should have produced an error when failing to extract with the wrong key");
190 error = nil;
191
192 CKKSTLKShareRecord* shareSignature = [share copy];
193 shareSignature.share.signature = [NSMutableData dataWithLength:shareSignature.signature.length];
194 key = [shareSignature recoverTLK:self.remotePeer trustedPeers:peers error:&error];
195 XCTAssertNil(key, "No key should have been extracted when signature fails to verify");
196 XCTAssertNotNil(error, "Should have produced an error when failing to extract a key with an invalid signature");
197 error = nil;
198
199 CKKSTLKShareRecord* shareUUID = [share copy];
200 shareUUID.share.tlkUUID = [[NSUUID UUID] UUIDString];
201 key = [shareUUID recoverTLK:self.remotePeer trustedPeers:peers error:&error];
202 XCTAssertNil(key, "No key should have been extracted when uuid has changed");
203 XCTAssertNotNil(error, "Should have produced an error when failing to extract a key after uuid has changed");
204 error = nil;
205 }
206
207 - (void)testKeyShareSaveAndLoad {
208 NSError* error = nil;
209 CKKSTLKShareRecord* share = [CKKSTLKShareRecord share:self.tlk
210 as:self.localPeer
211 to:self.remotePeer
212 epoch:-1
213 poisoned:0
214 error:&error];
215 XCTAssertNil(error, "Should have been no error sharing a CKKSKey");
216
217 [share saveToDatabase:&error];
218 XCTAssertNil(error, "Shouldn't be an error saving a TLKShare record to the database");
219
220 CKKSTLKShareRecord* loadedShare = [CKKSTLKShareRecord fromDatabase:self.tlk.uuid
221 receiverPeerID:self.remotePeer.peerID
222 senderPeerID:self.localPeer.peerID
223 zoneID:self.tlk.zoneID
224 error:&error];
225 XCTAssertNil(error, "Shouldn't get an error loading the share from the db");
226 XCTAssertNotNil(loadedShare, "Should've gotten a TLK share object back from the database");
227
228 XCTAssertEqualObjects(share, loadedShare, "Re-loaded TLK share object should be equivalent to the original");
229
230 CKRecord* record = [share CKRecordWithZoneID:self.tlk.zoneID];
231 XCTAssertNotNil(record, "Should be able to turn a share into a CKRecord");
232 XCTAssertTrue([share matchesCKRecord: record], "Should be able to compare a CKRecord with a TLKShare");
233
234 CKKSTLKShareRecord* fromCKRecord = [[CKKSTLKShareRecord alloc] initWithCKRecord:record];
235 XCTAssertNotNil(fromCKRecord, "Should be able to turn a CKRecord into a TLK share");
236
237 XCTAssertEqualObjects(share, fromCKRecord, "TLK shares sent through CloudKit should be identical");
238 }
239
240 - (void)testKeyShareSignExtraFieldsInCKRecord {
241 NSError* error = nil;
242 CKKSTLKShareRecord* share = [CKKSTLKShareRecord share:self.tlk
243 as:self.localPeer
244 to:self.remotePeer
245 epoch:-1
246 poisoned:0
247 error:&error];
248 XCTAssertNil(error, "Should have been no error sharing a CKKSKey");
249
250 CKRecord* record = [share CKRecordWithZoneID:self.tlk.zoneID];
251 XCTAssertNotNil(record, "Should be able to turn a share into a CKRecord");
252 XCTAssertTrue([share matchesCKRecord: record], "Should be able to compare a CKRecord with a TLKShare");
253
254 // Add another few fields to the record
255 record[@"extra_field"] = @"asdf";
256 record[@"another_field"] = [NSNumber numberWithInt:5];
257 record[@"data"] = [@"asdfdata" dataUsingEncoding:NSUTF8StringEncoding];
258 CKKSTLKShareRecord* share2 = [share copy];
259 share2.storedCKRecord = record;
260
261 XCTAssertNotNil([share dataForSigning], "TLKShares should be able to produce some data to sign");
262 XCTAssertNotNil([share2 dataForSigning], "TLKShares should be able to produce some data to sign (that includes extra fields)");
263 XCTAssertNotEqualObjects([share dataForSigning], [share2 dataForSigning], "TLKShares should prepare to sign extra unknown data");
264
265 share2.share.signature = [share2 signRecord:self.localPeer.signingKey error:&error];
266 XCTAssertNil(error, "Shouldn't be an error signing a record with extra fields");
267 XCTAssertNotEqualObjects(share.signature, share2.signature, "Signatures should be different for different data");
268
269 XCTAssert([share2 verifySignature:share2.signature verifyingPeer:self.localPeer error:&error], "Signature with extra data should verify");
270
271 // Now, change some of the extra data and see how that works
272 CKRecord* changedDataRecord = [record copy];
273 changedDataRecord[@"extra_field"] = @"no signature here";
274 share2.storedCKRecord = changedDataRecord;
275 XCTAssertFalse([share2 verifySignature:share2.signature verifyingPeer:self.localPeer error:&error], "Signature with extra data shouldn't verify if the data changes");
276
277 CKRecord* addedDataRecord = [record copy];
278 addedDataRecord[@"anotherfieldaltogether"] = @"asdfasdf";
279 share2.storedCKRecord = addedDataRecord;
280 XCTAssertFalse([share2 verifySignature:share2.signature verifyingPeer:self.localPeer error:&error], "Signature with extra data shouldn't verify if extra data is added");
281
282 // And verify that saving to disk and reloading is successful
283 share2.storedCKRecord = record;
284 XCTAssert([share2 verifySignature:share2.signature verifyingPeer:self.localPeer error:&error], "Signature with extra data should verify");
285 [share2 saveToDatabase:&error];
286 XCTAssertNil(error, "No error saving share2 to database");
287
288 CKKSTLKShareRecord* loadedShare2 = [CKKSTLKShareRecord tryFromDatabaseFromCKRecordID:record.recordID error:&error];
289 XCTAssertNil(error, "No error loading loadedShare2 from database");
290 XCTAssertNotNil(loadedShare2, "Should have received a CKKSTLKShare from the database");
291
292 XCTAssert([loadedShare2 verifySignature:loadedShare2.signature verifyingPeer:self.localPeer error:&error], "Signature with extra data should verify after save/load");
293 }
294
295 @end
296
297 #endif // OCTAGON