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