#include <Security/SecItemPriv.h>
#include <Security/SecuritydXPC.h>
#include <Security/SecFramework.h>
-#include <securityd/SecItemServer.h>
+#include "keychain/securityd/SecItemServer.h"
#include <ipc/securityd_client.h>
-#include <Security/SecureObjectSync/SOSBackupEvent.h>
+#include "keychain/SecureObjectSync/SOSBackupEvent.h"
#include <Security/SecureObjectSync/SOSCloudCircle.h>
#include <Security/SecureObjectSync/SOSViews.h>
#include <corecrypto/ccsha1.h>
#include <os/activity.h>
#include <notify.h>
-static CFDataRef data_data_to_data_error_request(enum SecXPCOperation op, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) {
+#include <sys/stat.h>
+
+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)
});
}
+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;
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;
}
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);
}
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) {
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;
}
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);
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"));
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;
}