]> git.saurik.com Git - apple/security.git/blob - tests/SecDbBackupTests/SecDbBackupTests.m
Security-59306.101.1.tar.gz
[apple/security.git] / tests / SecDbBackupTests / SecDbBackupTests.m
1 //
2 // SecDbBackupTests.m
3 // Security
4 //
5 // Created by Wouter de Groot on 2018-12-12.
6 //
7
8 #import <XCTest/XCTest.h>
9 #import "keychain/securityd/SecDbBackupManager.h"
10
11 #if !SECDB_BACKUPS_ENABLED
12
13 @interface SecDbBackupTests : XCTestCase
14 @end
15
16 @implementation SecDbBackupTests
17 @end
18
19 #else // SECDB_BACKUPS_ENABLED
20
21 #import "keychain/securityd/SecDbBackupManager_Internal.h"
22
23 #import "CKKS.h"
24 #import <utilities/SecFileLocations.h>
25 #import "spi.h"
26 #import "SecItemServer.h"
27 #import <objc/runtime.h>
28 #include "utilities/der_plist.h"
29 #include <Security/SecItemPriv.h>
30
31 @interface SecDbBackupTests : XCTestCase
32
33 @end
34
35 SecDbBackupManager* _manager;
36 NSString* _uuidstring;
37
38 @implementation SecDbBackupTests {
39 NSString* _testHomeDirectory;
40 }
41
42 static int testCheckV12DevEnabled(void) {
43 return 1;
44 }
45
46 + (void)setUp {
47 [super setUp];
48 checkV12DevEnabled = testCheckV12DevEnabled;
49 SecCKKSDisable();
50 #if OCTAGON
51 SecCKKSTestSetDisableSOS(true);
52 #endif
53 _uuidstring = [[NSUUID UUID] UUIDString];
54 }
55
56 + (void)tearDown {
57 SetCustomHomeURL(NULL);
58 SecKeychainDbReset(NULL);
59 resetCheckV12DevEnabled();
60 }
61
62 - (void)setUp {
63 [super setUp];
64
65 NSString* testName = [self.name componentsSeparatedByString:@" "][1];
66 testName = [testName stringByReplacingOccurrencesOfString:@"]" withString:@""];
67 secnotice("secdbbackuptest", "Beginning test %@", testName);
68
69 // Make a new fake keychain
70 NSError* error;
71 _testHomeDirectory = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%@/%@/", _uuidstring, testName]];
72
73 NSLog(@"%@", _testHomeDirectory);
74
75 [[NSFileManager defaultManager] createDirectoryAtPath:_testHomeDirectory
76 withIntermediateDirectories:YES
77 attributes:nil
78 error:&error];
79 // No XCTAssert in class method
80 if (error) {
81 NSLog(@"Could not make directory at %@", _testHomeDirectory);
82 }
83
84 SetCustomHomeURLString((__bridge CFStringRef)_testHomeDirectory);
85 static dispatch_once_t onceToken;
86 dispatch_once(&onceToken, ^{
87 securityd_init(NULL);
88 });
89 SecKeychainDbReset(NULL);
90
91 // Actually load the database.
92 kc_with_dbt(true, NULL, ^bool (SecDbConnectionRef dbt) { return false; });
93
94 [SecDbBackupManager resetManager];
95 _manager = [SecDbBackupManager manager];
96 }
97
98 - (void)setFakeBagIdentity {
99 SecDbBackupBagIdentity* identity = [SecDbBackupBagIdentity new];
100 NSUUID* nsuuid = [NSUUID UUID];
101 uuid_t uuid;
102 [nsuuid getUUIDBytes:uuid];
103 identity.baguuid = [NSData dataWithBytes:uuid length:UUIDBYTESLENGTH];
104 NSMutableData* digest = [NSMutableData dataWithLength:CC_SHA512_DIGEST_LENGTH];
105 CC_SHA512(identity.baguuid.bytes, (CC_LONG)identity.baguuid.length, digest.mutableBytes);
106 identity.baghash = digest;
107 _manager.bagIdentity = identity;
108 }
109
110 - (SFAESKey*)randomAESKey {
111 return [[SFAESKey alloc] initRandomKeyWithSpecifier:[[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256] error:nil];
112 }
113
114 - (NSData*)bagIdentData {
115 NSDictionary* bagIdentDict = @{@"baguuid" : _manager.bagIdentity.baguuid, @"baghash" : _manager.bagIdentity.baghash};
116 return (__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)bagIdentDict, NULL);
117 }
118
119 #pragma mark - Tests
120
121 - (void)testAAA_MakeSureThisMakesSense {
122 XCTAssertEqual(checkV12DevEnabled(), 1, "V12 dev flag is off, no good will come of this");
123 if (!checkV12DevEnabled) {
124 abort();
125 }
126 }
127
128 - (void)testCreateBackupBagSecret {
129 NSError* error;
130 NSData* secret = [_manager createBackupBagSecret:&error];
131 XCTAssertNil(error, "Error creating backup bag secret");
132 XCTAssertNotNil(secret, "No NSData from creating backup bag secret: %@", error);
133 XCTAssertEqual(secret.length, BACKUPBAG_PASSPHRASE_LENGTH, "NSData is not %i bytes long", BACKUPBAG_PASSPHRASE_LENGTH);
134
135 // Good luck testing randomness, but let's stipulate we don't accept all-zeroes as a key
136 uint8_t buf[BACKUPBAG_PASSPHRASE_LENGTH] = {0};
137 XCTAssertNotEqual(memcmp(secret.bytes, buf, MIN(BACKUPBAG_PASSPHRASE_LENGTH, secret.length)), 0, "Secret is all zeroes");
138
139 XCTAssert([secret isMemberOfClass:objc_lookUpClass("_NSClrDat")], "Secret is not a zeroing NSData");
140 }
141
142 - (void)testCreateAndSaveBackupBag {
143 NSError* error;
144 NSData* secret = [_manager createBackupBagSecret:&error];
145 XCTAssertNil(error, "Unable to generate secret");
146 XCTAssertNotNil(secret, "Didn't get secret");
147 keybag_handle_t handle = [_manager createBackupBagWithSecret:secret error:&error];
148 XCTAssertNil(error, "Got error creating backup bag: %@", error);
149 XCTAssertNotEqual(handle, bad_keybag_handle, "Unexpected bag handle");
150 keybag_state_t keybagstate;
151 XCTAssertEqual(aks_get_lock_state(handle, &keybagstate), kAKSReturnSuccess, "Unable to check lock state of backup bag");
152 XCTAssert(keybagstate | keybag_state_locked, "Keybag unexpectedly not locked");
153 XCTAssert(keybagstate | keybag_state_been_unlocked, "Keybag unexpectedly never been unlocked (huh?)");
154
155 XCTAssert([_manager saveBackupBag:handle asDefault:YES error:&error]);
156 XCTAssertNil(error, "Error saving backup bag to keychain");
157 XCTAssertEqual(aks_unload_bag(handle), kAKSReturnSuccess, "Couldn't unload backup bag");
158 }
159
160 - (void)testCreateAndSaveBagTwice {
161 NSError* error;
162 NSData* secret = [_manager createBackupBagSecret:&error];
163 XCTAssertNil(error, "Unable to generate secret");
164 XCTAssertNotNil(secret, "Didn't get secret");
165 keybag_handle_t handle = [_manager createBackupBagWithSecret:secret error:&error];
166 XCTAssertNil(error, "Got error creating backup bag: %@", error);
167 XCTAssertNotEqual(handle, bad_keybag_handle, "Unexpected bag handle");
168
169 XCTAssert([_manager saveBackupBag:handle asDefault:YES error:&error]);
170 XCTAssertNil(error, "Error saving backup bag to keychain");
171
172 XCTAssertFalse([_manager saveBackupBag:handle asDefault:YES error:&error]);
173 XCTAssert(error, "Unexpectedly did not get error saving same bag twice");
174 XCTAssertEqual(error.code, SecDbBackupWriteFailure, "Unexpected error code for double insertion: %@", error);
175 XCTAssertEqual(aks_unload_bag(handle), kAKSReturnSuccess, "Couldn't unload backup bag");
176 }
177
178 - (void)testLoadNonExistentDefaultBackupBag {
179 NSError* error;
180 XCTAssertEqual([_manager loadBackupBag:nil error:&error], bad_keybag_handle, "Found default bag after not inserting any");
181 XCTAssertEqual(error.code, SecDbBackupNoBackupBagFound, "Didn't get an appropriate error for missing keybag: %@", error);
182 }
183
184 - (void)testLoadDefaultBackupBag {
185 NSError* error;
186 keybag_handle_t handle = bad_keybag_handle;
187 handle = [_manager createBackupBagWithSecret:[_manager createBackupBagSecret:&error] error:&error];
188 XCTAssertNotEqual(handle, bad_keybag_handle, "Didn't get a good keybag handle");
189 XCTAssertNotEqual(handle, device_keybag_handle, "Got device keybag handle (or manager is nil)");
190 XCTAssertNil(error, "Error creating backup bag");
191 [_manager saveBackupBag:handle asDefault:YES error:&error];
192 XCTAssertNil(error, "Error saving backup bag");
193
194 uuid_t uuid1 = {0};
195 XCTAssertEqual(aks_get_bag_uuid(handle, uuid1), kAKSReturnSuccess, "Couldn't get bag uuid");
196 XCTAssertEqual(aks_unload_bag(handle), kAKSReturnSuccess, "Couldn't unload backup bag");
197 handle = bad_keybag_handle;
198
199 handle = [_manager loadBackupBag:nil error:&error];
200 XCTAssertNotEqual(handle, bad_keybag_handle, "Got bad handle loading default keybag");
201 XCTAssertNil(error, "Got error loading default keybag");
202
203 uuid_t uuid2 = {0};
204 XCTAssertEqual(aks_get_bag_uuid(handle, uuid2), kAKSReturnSuccess, "Couldn't get bag uuid");
205 XCTAssertEqual(aks_unload_bag(handle), kAKSReturnSuccess, "Couldn't unload backup bag");
206 XCTAssertEqual(memcmp(uuid1, uuid2, UUIDBYTESLENGTH), 0, "UUIDs do not match after backup bag save/load");
207
208 // sanity check
209 uuid_t uuidnull = {0};
210 XCTAssertNotEqual(memcmp(uuid1, uuidnull, UUIDBYTESLENGTH), 0, "uuid1 is all zeroes");
211 XCTAssertNotEqual(memcmp(uuid2, uuidnull, UUIDBYTESLENGTH), 0, "uuid2 is all zeroes");
212
213 // TODO: signature match?
214 }
215
216 - (void)testLoadBackupBagByUUID {
217 NSError* error;
218 keybag_handle_t handle1 = bad_keybag_handle;
219 handle1 = [_manager createBackupBagWithSecret:[_manager createBackupBagSecret:&error] error:&error];
220 XCTAssertNotEqual(handle1, bad_keybag_handle, "Didn't get a good keybag handle");
221 XCTAssertNil(error, "Error creating backup bag");
222 XCTAssert([_manager saveBackupBag:handle1 asDefault:NO error:&error], "Unable to save bag 1");
223 XCTAssertNil(error, "Error saving backup bag");
224
225 keybag_handle_t handle2 = bad_keybag_handle;
226 handle2 = [_manager createBackupBagWithSecret:[_manager createBackupBagSecret:&error] error:&error];
227 XCTAssertNotEqual(handle2, bad_keybag_handle, "Didn't get a good keybag handle");
228 XCTAssertNil(error, "Error creating backup bag");
229 XCTAssert([_manager saveBackupBag:handle2 asDefault:NO error:&error], "Unable to save bag 2");
230 XCTAssertNil(error, "Error saving backup bag");
231
232 uuid_t uuid1 = {0};
233 uuid_t uuid2 = {0};
234 XCTAssertEqual(aks_get_bag_uuid(handle1, uuid1), kAKSReturnSuccess, "Couldn't get bag 1 uuid");
235 XCTAssertEqual(aks_get_bag_uuid(handle2, uuid2), kAKSReturnSuccess, "Couldn't get bag 2 uuid");
236 XCTAssertEqual(aks_unload_bag(handle1), kAKSReturnSuccess, "Couldn't unload backup bag 1");
237 XCTAssertEqual(aks_unload_bag(handle2), kAKSReturnSuccess, "Couldn't unload backup bag 2");
238 handle1 = bad_keybag_handle;
239 handle2 = bad_keybag_handle;
240
241 XCTAssertNotEqual(handle1 = [_manager loadBackupBag:[[NSUUID alloc] initWithUUIDBytes:uuid1] error:&error], bad_keybag_handle, "Didn't get handle loading bag 1 by UUID");
242 XCTAssertNotEqual(handle2 = [_manager loadBackupBag:[[NSUUID alloc] initWithUUIDBytes:uuid2] error:&error], bad_keybag_handle, "Didn't get handle loading bag 2 by UUID");
243
244 uuid_t uuid1_2 = {0};
245 uuid_t uuid2_2 = {0};
246 XCTAssertEqual(aks_get_bag_uuid(handle1, uuid1_2), kAKSReturnSuccess, "Couldn't get bag 1 uuid");
247 XCTAssertEqual(aks_get_bag_uuid(handle2, uuid2_2), kAKSReturnSuccess, "Couldn't get bag 2 uuid");
248
249 XCTAssertEqual(memcmp(uuid1, uuid1_2, UUIDBYTESLENGTH), 0, "UUIDs do not match after bag 1 save/load");
250 XCTAssertEqual(memcmp(uuid2, uuid2_2, UUIDBYTESLENGTH), 0, "UUIDs do not match after bag 2 save/load");
251
252 XCTAssertEqual(aks_unload_bag(handle1), kAKSReturnSuccess, "Couldn't unload backup bag 1");
253 XCTAssertEqual(aks_unload_bag(handle2), kAKSReturnSuccess, "Couldn't unload backup bag 2");
254 }
255
256 - (void)testCreateBackupInfrastructure
257 {
258 NSError* error;
259 XCTAssert([_manager createOrLoadBackupInfrastructure:&error], @"Couldn't create/load backup infrastructure");
260 XCTAssertNil(error, @"Error creating/loading backup infrastructure");
261
262 SFECKeyPair* ak = [_manager fetchKCSKForKeyclass:key_class_ak error:&error];
263 XCTAssertNotNil(ak);
264 XCTAssertNil(error);
265
266 SFECKeyPair* ck = [_manager fetchKCSKForKeyclass:key_class_ck error:&error];
267 XCTAssertNotNil(ck);
268 XCTAssertNil(error);
269
270 SFECKeyPair* dk = [_manager fetchKCSKForKeyclass:key_class_dk error:&error];
271 XCTAssertNotNil(dk);
272 XCTAssertNil(error);
273
274 SFECKeyPair* aku = [_manager fetchKCSKForKeyclass:key_class_aku error:&error];
275 XCTAssertNotNil(aku);
276 XCTAssertNil(error);
277
278 SFECKeyPair* cku = [_manager fetchKCSKForKeyclass:key_class_cku error:&error];
279 XCTAssertNotNil(cku);
280 XCTAssertNil(error);
281
282 SFECKeyPair* dku = [_manager fetchKCSKForKeyclass:key_class_dku error:&error];
283 XCTAssertNotNil(dku);
284 XCTAssertNil(error);
285
286 SFECKeyPair* akpu = [_manager fetchKCSKForKeyclass:key_class_akpu error:&error];
287 XCTAssertNil(akpu);
288 XCTAssertEqual(error.code, SecDbBackupNoKCSKFound);
289 }
290
291 - (void)testCreateOrLoadBackupInfrastructureFromC
292 {
293 CFErrorRef cferror = NULL;
294 XCTAssertTrue(SecDbBackupCreateOrLoadBackupInfrastructure(&cferror), @"Could create backup infrastructure from C");
295 XCTAssertFalse(cferror, @"Do not expect error creating backup infrastructure from C: %@", cferror);
296 CFReleaseNull(cferror);
297 }
298
299 // Should not run this on real AKS because don't want to lock keybag
300 - (void)disabledtestCreateOrLoadBackupInfrastructureWhileLocked
301 {
302 NSError* error;
303 XCTAssertFalse([_manager createOrLoadBackupInfrastructure:&error], @"Keychain locked, don't expect to create infrastructure");
304 XCTAssertEqual(error.code, SecDbBackupKeychainLocked, @"Expected failure creating backup infrastructure while locked");
305 }
306
307 // Should not run this on real AKS because don't want to lock keybag
308 - (void)disabledtestCreateOrLoadBackupInfrastructureWhileLockedFromC
309 {
310 CFErrorRef cferror = NULL;
311 XCTAssertFalse(SecDbBackupCreateOrLoadBackupInfrastructure(&cferror), @"Could create backup infrastructure from C");
312 XCTAssertTrue(cferror, @"Expect error creating backup infrastructure while locked from C: %@", cferror);
313 if (cferror) {
314 XCTAssertEqual(CFErrorGetCode(cferror), errSecInteractionNotAllowed, @"Expect errSecInteractionNotAllowed creating backup infrastructure while locked from C");
315 }
316 CFReleaseNull(cferror);
317 }
318
319 - (void)testOnlyOneDefaultBackupBag {
320 // Generate two backup bags, each successively claiming makeDefault
321 // Expect: the second call should fail
322 }
323
324 - (void)testLoadBackupBagFromDifferentDevice {
325 // Generate keybag on some device, manually insert it on some other device and try to load it.
326 // Expect: failure unless in recovery mode.
327 }
328
329 - (void)testLoadBackupBagWithGarbageData {
330 // manually write garbage to keychain, then call loadBackupBag
331 // Expect: ?
332 }
333
334 - (void)testCreateKCSK {
335 [self setFakeBagIdentity];
336
337 NSError* error;
338 XCTAssertNil([_manager createKCSKForKeyClass:key_class_ck withWrapper:nil error:&error], @"Shouldn't get KCSK without wrapper");
339 XCTAssertEqual(error.code, SecDbBackupInvalidArgument, @"createKSCKForKeyClass ought to be angry about not having a wrapper");
340 error = nil;
341
342 SFAESKey* key = [self randomAESKey];
343 XCTAssertNotNil(key, @"Expect key from SFAESKey");
344 SecDbBackupKeyClassSigningKey* kcsk = [_manager createKCSKForKeyClass:key_class_ak withWrapper:key error:&error];
345 XCTAssertNotNil(kcsk, @"Got a KCSK");
346 XCTAssertNil(error, @"Did not expect KCSK error: %@", error);
347
348 // Let's examine the KCSK
349
350 XCTAssertEqual(kcsk.keyClass, key_class_ak, @"key class matches");
351
352 // Verify refkey
353 aks_ref_key_t refkey = NULL;
354 XCTAssertNotNil(kcsk.aksRefKey, @"Got an AKS ref key");
355 XCTAssertEqual(aks_ref_key_create_with_blob(KEYBAG_DEVICE, kcsk.aksRefKey.bytes,
356 kcsk.aksRefKey.length, &refkey), kAKSReturnSuccess, @"Got a refkey out of kcsk blob");
357
358 // Verify aksWrappedKey
359 void* aksunwrappedbytes = NULL;
360 size_t aksunwrappedlen = 0;
361 XCTAssertEqual(aks_ref_key_decrypt(refkey, NULL, 0, kcsk.aksWrappedKey.bytes, kcsk.aksWrappedKey.length, &aksunwrappedbytes, &aksunwrappedlen), kAKSReturnSuccess, @"Successfully unwrapped KCSK private key");
362 SFECKeyPair* aksunwrapped = [_manager ECKeyPairFromDerBytes:aksunwrappedbytes length:aksunwrappedlen error:&error];
363 XCTAssertNil(error, @"No error reconstructing AKS backup key");
364 XCTAssert(aksunwrapped, @"Got key from ECKeyPairFromDerBytes");
365 aks_ref_key_free(&refkey);
366
367 // Verify backupWrappedKey
368 SFAuthenticatedEncryptionOperation* op = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:[[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256]];
369 SFAuthenticatedCiphertext* ciphertext = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFAuthenticatedCiphertext class] fromData:kcsk.backupWrappedKey error:&error];
370 XCTAssertNotNil(ciphertext, @"Reconstituted ciphertext from kcsk (%@)", error);
371 XCTAssertNil(error, @"Didn't expect error reconstituting ciphertext from kcsk: %@", error);
372
373 NSData* bagIdentData = [self bagIdentData];
374 NSData* bkunwrappedData = [op decrypt:ciphertext withKey:key additionalAuthenticatedData:bagIdentData error:&error];
375 XCTAssertNotNil(bkunwrappedData, @"backup-wrapped key decrypts");
376 SFECKeyPair* bkunwrapped = [[SFECKeyPair alloc] initWithData:bkunwrappedData specifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384] error:&error];
377 XCTAssertNotNil(bkunwrapped, @"unwrapped blob turns into an SFECKey (%@)", error);
378
379 XCTAssertEqualObjects(aksunwrapped, bkunwrapped, @"Private key same between aks and bk");
380 }
381
382 - (void)testCreateRecoverySetForRecoveryKey {
383 // Not Implemented
384 }
385
386 - (void)testCreateRecoverySetForAKS {
387 NSError* error;
388
389 [self setFakeBagIdentity];
390
391 SecDbBackupRecoverySet* set = [_manager createRecoverySetWithBagSecret:nil forType:SecDbBackupRecoveryTypeAKS error:&error];
392 XCTAssertNil(set, @"No set without secret!");
393 XCTAssertEqual(error.code, SecDbBackupInvalidArgument, @"Expected different error without secret: %@", error);
394 error = nil;
395
396 NSData* secret = [_manager createBackupBagSecret:&error];
397 set = [_manager createRecoverySetWithBagSecret:secret forType:SecDbBackupRecoveryTypeAKS error:&error];
398 XCTAssertNotNil(set, @"Got aks recoveryset from backup manager");
399 XCTAssertNil(error, @"Didn't expect error obtaining recoveryset: %@", error);
400
401 XCTAssertEqual(set.recoveryType, SecDbBackupRecoveryTypeAKS, @"Unexpected recovery type");
402 XCTAssertEqualObjects(set.bagIdentity, _manager.bagIdentity, @"Bag identity copied properly");
403 XCTAssertNotNil(set.wrappedBagSecret, @"Have bag secret in recovery set");
404 XCTAssertNotNil(set.wrappedKCSKSecret, @"Have kcsk secret in recovery set");
405 XCTAssertNotNil(set.wrappedRecoveryKey, @"Have recovery key in recovery set");
406
407 NSMutableData* recoverykeydata = [NSMutableData dataWithLength:APPLE_KEYSTORE_MAX_KEY_LEN];
408 [SecAKSObjCWrappers aksDecryptWithKeybag:KEYBAG_DEVICE keyclass:key_class_aku
409 ciphertext:set.wrappedRecoveryKey outKeyclass:nil plaintext:recoverykeydata error:&error];
410 XCTAssertNil(error, @"Able to decrypt recovery key: %@", error);
411 SFAESKey* recoverykey = [[SFAESKey alloc] initWithData:recoverykeydata specifier:[[SFAESKeySpecifier alloc]
412 initWithBitSize:SFAESKeyBitSize256] error:&error];
413 XCTAssert(recoverykey, @"Got a recovery key from blob");
414 XCTAssertNil(error, @"Didn't get error from recovery key blob: %@", error);
415
416 SFAuthenticatedEncryptionOperation* op = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:[[SFAESKeySpecifier alloc]
417 initWithBitSize:SFAESKeyBitSize256]];
418 NSData* bagsecret = [op decrypt:[NSKeyedUnarchiver unarchivedObjectOfClass:[SFAuthenticatedCiphertext class] fromData:set.wrappedBagSecret error:&error] withKey:recoverykey error:&error];
419 XCTAssert(bagsecret, @"Reconstituted bag secret");
420 XCTAssertNil(error, @"Didn't expect error reconstituting bag secret: %@", error);
421 XCTAssertEqualObjects(bagsecret, secret, @"Returned bag secret same as provided secret");
422
423 NSData* kcsksecret = [op decrypt:[NSKeyedUnarchiver unarchivedObjectOfClass:[SFAuthenticatedCiphertext class] fromData:set.wrappedKCSKSecret error:&error] withKey:recoverykey error:&error];
424 XCTAssert(kcsksecret, @"Reconstituted kcsk secret");
425 XCTAssertNil(error, @"Didn't expect error reconstituting kcsk secret: %@", error);
426 }
427
428 - (void)testWrapItemKey {
429 SFAESKey* randomKey = [self randomAESKey];
430 NSError* error;
431 SecDbBackupWrappedItemKey* itemKey = [_manager wrapItemKey:randomKey forKeyclass:key_class_akpu error:&error];
432 XCTAssertNil(itemKey, @"Do not expect result wrapping to akpu");
433 XCTAssertEqual(error.code, SecDbBackupInvalidArgument, @"Expect invalid argument error wrapping to akpu");
434
435 error = nil;
436 itemKey = [_manager wrapItemKey:randomKey forKeyclass:key_class_ak error:&error];
437 XCTAssertNil(error, @"No error wrapping item to ak");
438 XCTAssertEqualObjects(itemKey.baguuid, _manager.bagIdentity.baguuid, @"item wrapped under expected bag uuid");
439
440 // TODO: implement decryption and test it here
441 }
442
443 // Does not inspect the item because it's encrypted and no code yet built to do recovery.
444 - (void)testSecItemAddAddsBackupEncryption {
445 NSDictionary* q = @{(id)kSecClass : (id)kSecClassGenericPassword,
446 (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
447 (id)kSecAttrAccessGroup : @"com.apple.security.securityd",
448 (id)kSecUseDataProtectionKeychain : @(YES),
449 (id)kSecReturnAttributes : @(YES)
450 };
451 OSStatus status = SecItemAdd((__bridge CFDictionaryRef)q, NULL);
452 XCTAssertEqual(status, errSecSuccess, @"Regular old SecItemAdd succeeds");
453
454 __block CFErrorRef cfError = NULL;
455 __block bool ok = true;
456 __block NSData* readUUID;
457 ok &= kc_with_dbt(false, &cfError, ^bool(SecDbConnectionRef dbt) {
458 NSString* sql = @"SELECT backupUUID FROM genp WHERE agrp = 'com.apple.security.securityd'";
459 ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &cfError, ^(sqlite3_stmt *stmt) {
460 ok &= SecDbStep(dbt, stmt, &cfError, ^(bool *stop) {
461 readUUID = [[NSData alloc] initWithBytes:sqlite3_column_blob(stmt, 0) length:sqlite3_column_bytes(stmt, 0)];
462 });
463 });
464 return ok;
465 });
466
467 XCTAssert(ok, @"Talking to keychain went okay");
468 XCTAssertEqual(cfError, NULL, @"Talking to keychain didn't yield an error (%@)", cfError);
469 CFReleaseNull(cfError);
470 XCTAssert(readUUID, @"Got stuff out of the keychain");
471
472 XCTAssertEqualObjects(readUUID, _manager.bagIdentity.baguuid, @"backup UUID is good");
473 }
474
475 @end
476
477 #endif // SECDB_BACKUPS_ENABLED