X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5c19dc3ae3bd8e40a9c028b0deddd50ff337692c..HEAD:/OSX/sec/Security/SecItemBackup.c diff --git a/OSX/sec/Security/SecItemBackup.c b/OSX/sec/Security/SecItemBackup.c index e42c11d4..9581cb8b 100644 --- a/OSX/sec/Security/SecItemBackup.c +++ b/OSX/sec/Security/SecItemBackup.c @@ -31,9 +31,9 @@ #include #include #include -#include +#include "keychain/securityd/SecItemServer.h" #include -#include +#include "keychain/SecureObjectSync/SOSBackupEvent.h" #include #include #include @@ -47,18 +47,21 @@ #include #include -static CFDataRef data_data_to_data_error_request(enum SecXPCOperation op, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) { +#include + +static CFDataRef client_data_data_bool_to_data_error_request(enum SecXPCOperation op, SecurityClient *client, CFDataRef keybag, CFDataRef passcode, bool emcs, CFErrorRef *error) { __block CFDataRef result = NULL; securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { return SecXPCDictionarySetDataOptional(message, kSecXPCKeyKeybag, keybag, error) - && SecXPCDictionarySetDataOptional(message, kSecXPCKeyUserPassword, passcode, error); + && SecXPCDictionarySetDataOptional(message, kSecXPCKeyUserPassword, passcode, error) + && SecXPCDictionarySetBool(message, kSecXPCKeyEMCSBackup, emcs, NULL); }, ^bool(xpc_object_t response, CFErrorRef *error) { return (result = SecXPCDictionaryCopyData(response, kSecXPCKeyResult, error)); }); return result; } -static bool data_data_data_to_error_request(enum SecXPCOperation op, CFDataRef backup, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) { +static bool data_client_data_data_to_error_request(enum SecXPCOperation op, CFDataRef backup, SecurityClient *client, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) { return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { return SecXPCDictionarySetData(message, kSecXPCKeyBackup, backup, error) && SecXPCDictionarySetData(message, kSecXPCKeyKeybag, keybag, error) @@ -121,6 +124,17 @@ static bool string_string_data_data_data_to_bool_error_request(enum SecXPCOperat }); } +static CFStringRef string_to_string_error_request(enum SecXPCOperation op, CFStringRef viewName, CFErrorRef *error) +{ + __block CFStringRef result = NULL; + securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { + return SecXPCDictionarySetString(message, kSecXPCKeyString, viewName, error); + }, ^bool(xpc_object_t response, CFErrorRef *error) { + return result = SecXPCDictionaryCopyString(response, kSecXPCKeyResult, error); + }); + return result; +} + static CFArrayRef to_array_error_request(enum SecXPCOperation op, CFErrorRef *error) { __block CFArrayRef result = NULL; @@ -145,7 +159,7 @@ static int SecItemBackupHandoffFD(CFStringRef backupName, CFErrorRef *error) { CFDataRef _SecKeychainCopyOTABackup(void) { __block CFDataRef result; os_activity_initiate("_SecKeychainCopyOTABackup", OS_ACTIVITY_FLAG_DEFAULT, ^{ - result = SECURITYD_XPC(sec_keychain_backup, data_data_to_data_error_request, NULL, NULL, NULL); + result = SECURITYD_XPC(sec_keychain_backup, client_data_data_bool_to_data_error_request, SecSecurityClientGet(), NULL, NULL, false, NULL); }); return result; } @@ -153,22 +167,82 @@ CFDataRef _SecKeychainCopyOTABackup(void) { CFDataRef _SecKeychainCopyBackup(CFDataRef backupKeybag, CFDataRef password) { __block CFDataRef result; os_activity_initiate("_SecKeychainCopyBackup", OS_ACTIVITY_FLAG_DEFAULT, ^{ - result = SECURITYD_XPC(sec_keychain_backup, data_data_to_data_error_request, backupKeybag, password, NULL); + result = SECURITYD_XPC(sec_keychain_backup, client_data_data_bool_to_data_error_request, SecSecurityClientGet(), backupKeybag, password, false, NULL); + }); + return result; +} + +CFDataRef _SecKeychainCopyEMCSBackup(CFDataRef backupKeybag) { + __block CFDataRef result; + os_activity_initiate("_SecKeychainCopyEMCSBackup", OS_ACTIVITY_FLAG_DEFAULT, ^{ + result = SECURITYD_XPC(sec_keychain_backup, client_data_data_bool_to_data_error_request, SecSecurityClientGet(), backupKeybag, NULL, true, NULL); + }); + return result; +} + +bool _SecKeychainWriteBackupToFileDescriptor(CFDataRef backupKeybag, CFDataRef password, int fd, CFErrorRef *error) { + __block bool result = false; + os_activity_initiate("_SecKeychainWriteBackupToFile", OS_ACTIVITY_FLAG_DEFAULT, ^{ + + securityd_send_sync_and_do(sec_keychain_backup_id, error, ^bool(xpc_object_t message, CFErrorRef *error) { + return SecXPCDictionarySetDataOptional(message, kSecXPCKeyKeybag, backupKeybag, error) + && SecXPCDictionarySetDataOptional(message, kSecXPCKeyUserPassword, password, error) + && SecXPCDictionarySetFileDescriptor(message, kSecXPCKeyFileDescriptor, fd, error); + }, ^bool(xpc_object_t response, CFErrorRef *error) { + return (result = SecXPCDictionaryGetBool(response, kSecXPCKeyResult, error)); + }); + }); + return result; +} + +bool +_SecKeychainRestoreBackupFromFileDescriptor(int fd, CFDataRef backupKeybag, CFDataRef password, CFErrorRef *error) +{ + __block bool result; + os_activity_initiate("_SecKeychainRestoreBackup", OS_ACTIVITY_FLAG_DEFAULT, ^{ + securityd_send_sync_and_do(sec_keychain_restore_id, error, ^bool(xpc_object_t message, CFErrorRef *error) { + return SecXPCDictionarySetFileDescriptor(message, kSecXPCKeyFileDescriptor, fd, error) + && SecXPCDictionarySetData(message, kSecXPCKeyKeybag, backupKeybag, error) + && SecXPCDictionarySetDataOptional(message, kSecXPCKeyUserPassword, password, error); + }, ^bool(xpc_object_t response, CFErrorRef *error) { + return (result = SecXPCDictionaryGetBool(response, kSecXPCKeyResult, error)); + }); }); return result; } +/* + * Current promise is that this is low memory usage, so in the current format, ask securityd + * to resolve the item for us. + */ + +CFStringRef +_SecKeychainCopyKeybagUUIDFromFileDescriptor(int fd, CFErrorRef *error) +{ + __block CFStringRef result = NULL; + os_activity_initiate("_SecKeychainCopyKeybagUUID", OS_ACTIVITY_FLAG_DEFAULT, ^{ + securityd_send_sync_and_do(sec_keychain_backup_keybag_uuid_id, error, ^bool(xpc_object_t message, CFErrorRef *error) { + return SecXPCDictionarySetFileDescriptor(message, kSecXPCKeyFileDescriptor, fd, error); + }, ^bool(xpc_object_t response, CFErrorRef *error) { + return (result = SecXPCDictionaryCopyString(response, kSecXPCKeyResult, error)); + }); + }); + return result; +} + + OSStatus _SecKeychainRestoreBackup(CFDataRef backup, CFDataRef backupKeybag, CFDataRef password) { __block OSStatus result; os_activity_initiate("_SecKeychainRestoreBackup", OS_ACTIVITY_FLAG_DEFAULT, ^{ result = SecOSStatusWith(^bool (CFErrorRef *error) { - return SECURITYD_XPC(sec_keychain_restore, data_data_data_to_error_request, backup, backupKeybag, password, error); + return SECURITYD_XPC(sec_keychain_restore, data_client_data_data_to_error_request, backup, SecSecurityClientGet(), backupKeybag, password, error); }); }); return result; } + static int compareDigests(const void *l, const void *r) { return memcmp(l, r, CCSHA1_OUTPUT_SIZE); } @@ -197,78 +271,6 @@ CFDataRef SecItemBackupCreateManifest(CFDictionaryRef backup, CFErrorRef *error) return manifest; } -/* - client code in CloudServices calls SecItemBackupWithChanges in the loop of SecItemBackupWithRegisteredBackups - */ -__unused static CFDictionaryRef SecItemBackupSyncable(CFDataRef keybag, CFDataRef password, CFDictionaryRef backup_in, CFErrorRef *error) -{ - const CFStringRef backupName = kSOSViewKeychainV0_tomb; - __block bool complete = false; - __block CFMutableDictionaryRef backup = backup_in ? CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, backup_in) : CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFDataRef keybagDigest = CFDataCopySHA1Digest(keybag, NULL); // Used to confirm we are in sync keybag wise. - do { - CFErrorRef localError = NULL; - if (!SecItemBackupWithChanges(backupName, &localError, ^(SecBackupEventType et, CFTypeRef key, CFTypeRef item) { - CFStringRef hexDigest = key ? CFDataCopyHexString(key) : NULL; - complete = false; - switch(et) { - case kSecBackupEventReset: - CFDictionaryRemoveAllValues(backup); - break; - case kSecBackupEventAdd: - CFDictionarySetValue(backup, hexDigest, item); - break; - case kSecBackupEventRemove: - CFDictionaryRemoveValue(backup, hexDigest); - break; - case kSecBackupEventComplete: - complete = true; - break; - } - CFReleaseSafe(hexDigest); - - })) { - if (localError && CFEqual(CFErrorGetDomain(localError), kSecErrnoDomain) && CFErrorGetCode(localError) == ENOENT) { - // No journal file returned by securityd, nothing left to do, ignore error and exit. - CFReleaseNull(localError); - } else { - CFErrorPropagate(localError, error); - CFReleaseNull(backup); - } - break; - } - - CFDataRef mconfirmed = SecItemBackupCreateManifest(backup, error); - if (!mconfirmed) { - CFReleaseNull(backup); - break; - } - bool ok = SecItemBackupSetConfirmedManifest(backupName, keybagDigest, mconfirmed, error); - CFReleaseSafe(mconfirmed); - if (!ok) { - CFReleaseNull(backup); - break; - } - } while (!complete); - CFReleaseSafe(keybagDigest); - - return backup; -} - -#if 0 // interim code to call SecItemBackupSyncable -OSStatus _SecKeychainBackupSyncable(CFDataRef keybag, CFDataRef password, CFDictionaryRef backup_in, CFDictionaryRef *backup_out) -{ - __block OSStatus result; - os_activity_initiate("_SecKeychainBackupSyncable", OS_ACTIVITY_FLAG_DEFAULT, ^{ - result = SecOSStatusWith(^bool (CFErrorRef *error) { - *backup_out = SecItemBackupSyncable(keybag, password, backup_in, error); - return *backup_out != NULL; - }); - }); - return result; -} -#endif - OSStatus _SecKeychainBackupSyncable(CFDataRef keybag, CFDataRef password, CFDictionaryRef backup_in, CFDictionaryRef *backup_out) { return SecOSStatusWith(^bool (CFErrorRef *error) { @@ -296,19 +298,42 @@ static bool SecKeychainWithBackupFile(CFStringRef backupName, CFErrorRef *error, secdebug("backup", "SecItemBackupHandoffFD returned %d", fd); return false; } + + // Rewind file to start + if (lseek(fd, 0, SEEK_SET)) { + secdebug("backup", "Could not seek in fd %d for %@", fd, backupName); + return SecCheckErrno(true, error, CFSTR("lseek")); + } + FILE *backup = fdopen(fd, "r"); if (!backup) { - close(fd); secdebug("backup", "Receiving file for %@ failed, %d", backupName, errno); - return SecCheckErrno(!backup, error, CFSTR("fdopen")); + SecCheckErrno(!backup, error, CFSTR("fdopen")); + if (close(fd)) { + secdebug("backup", "Encountered error closing file %@: %d", backupName, errno); + SecCheckErrno(true, error, CFSTR("close")); + } + return false; } else { - secdebug("backup", "Receiving file for %@ with fd %d of size %llu", backupName, fd, lseek(fd, 0, SEEK_END)); + struct stat sb; + if (fstat(fd, &sb)) { + secdebug("backup", "Unable to get file metadata for %@, fd %d", backupName, fd); + SecCheckErrno(true, error, CFSTR("fstat")); + if (fclose(backup)) { + secdebug("backup", "Encountered error closing file %@: %d", backupName, errno); + SecCheckErrno(true, error, CFSTR("fclose")); + } + return false; + } + secdebug("backup", "Receiving file for %@ with fd %d of size %llu", backupName, fd, sb.st_size); } - // Rewind file to start - lseek(fd, 0, SEEK_SET); with(backup); - fclose(backup); + if (fclose(backup)) { + secdebug("backup", "Encountered error %d closing file %@ after backup handler", errno, backupName); + SecCheckErrno(true, error, CFSTR("fclose")); + // read only file and block has its own error handling for IO failure, no need to return false + } return true; } @@ -332,6 +357,25 @@ bool SecItemBackupWithRegisteredBackups(CFErrorRef *error, void(^backup)(CFStrin return true; } +static CFStringRef SecItemBackupViewAndCopyBackupPeerID(CFStringRef viewName, CFErrorRef *error) +{ + __block CFStringRef result; + os_activity_initiate("SecItemBackupViewAndCopyBackupPeerID", OS_ACTIVITY_FLAG_DEFAULT, ^{ + result = SECURITYD_XPC(sec_item_backup_ensure_copy_view, string_to_string_error_request, viewName, error); + }); + return result; +} + +bool SecItemBackupWithRegisteredViewBackup(CFStringRef viewName, CFErrorRef *error) { + CFStringRef backupName = SecItemBackupViewAndCopyBackupPeerID(viewName, error); + if(backupName == NULL) { + return false; + } + CFReleaseNull(backupName); + return true; +} + + static bool SecItemBackupDoResetEventBody(const uint8_t *der, const uint8_t *der_end, CFErrorRef *error, void (^handleEvent)(SecBackupEventType et, CFTypeRef key, CFTypeRef item)) { size_t sequence_len; const uint8_t *sequence_body = ccder_decode_len(&sequence_len, der, der_end); @@ -363,7 +407,7 @@ static bool SecItemBackupDoResetEventBody(const uint8_t *der, const uint8_t *der static bool SecItemBackupDoAddEvent(const uint8_t *der, const uint8_t *der_end, CFErrorRef *error, void (^handleEvent)(SecBackupEventType et, CFTypeRef key, CFTypeRef item)) { CFDictionaryRef eventDict = NULL; - const uint8_t *der_end_of_dict = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &eventDict, error, der, der_end); + const uint8_t *der_end_of_dict = der_decode_dictionary(kCFAllocatorDefault, &eventDict, error, der, der_end); if (der_end_of_dict && der_end_of_dict != der_end) { // Can't ever happen! SecError(errSecDecode, error, CFSTR("trailing junk after add")); @@ -575,9 +619,32 @@ void SecItemBackupRestore(CFStringRef backupName, CFStringRef peerID, CFDataRef CFReleaseSafe(localError); } -CFDictionaryRef SecItemBackupCopyMatching(CFDataRef keybag, CFDataRef secret, CFDictionaryRef backup, CFDictionaryRef query, CFErrorRef *error) { - SecError(errSecUnimplemented, error, CFSTR("SecItemBackupCopyMatching unimplemented")); - return NULL; +bool SecBackupKeybagAdd(CFDataRef passcode, CFDataRef *identifier, CFURLRef *pathinfo, CFErrorRef *error) { + __block bool result = false; + os_activity_initiate("_SecServerBackupKeybagAdd", OS_ACTIVITY_FLAG_DEFAULT, ^{ + securityd_send_sync_and_do(kSecXPCOpBackupKeybagAdd, error, ^bool(xpc_object_t message, CFErrorRef *error) { + return SecXPCDictionarySetDataOptional(message, kSecXPCKeyUserPassword, passcode, error); + }, ^bool(xpc_object_t response, CFErrorRef *error) { + result = SecXPCDictionaryCopyDataOptional(response, kSecXPCKeyBackupKeybagIdentifier, identifier, error) && + SecXPCDictionaryCopyURLOptional(response, kSecXPCKeyBackupKeybagPath, pathinfo, error) && + SecXPCDictionaryGetBool(response, kSecXPCKeyResult, error); + return result; + }); + }); + return result; +} + +bool SecBackupKeybagDelete(CFDictionaryRef query, CFErrorRef *error) { + __block bool result = false; + os_activity_initiate("_SecBackupKeybagDelete", OS_ACTIVITY_FLAG_DEFAULT, ^{ + securityd_send_sync_and_do(kSecXPCOpBackupKeybagDelete, error, ^bool(xpc_object_t message, CFErrorRef *error) { + return SecXPCDictionarySetPList(message, kSecXPCKeyQuery, query, error); + }, ^bool(xpc_object_t response, CFErrorRef *error) { + result = SecXPCDictionaryGetBool(response, kSecXPCKeyResult, error); + return result; + }); + }); + return result; }