2 * Copyright (c) 2015 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 * SecItemBackup.c - Client side backup interfaces and support code
29 #include <Security/SecItemBackup.h>
31 #include <Security/SecItemPriv.h>
32 #include <Security/SecuritydXPC.h>
33 #include <Security/SecFramework.h>
34 #include <securityd/SecItemServer.h>
35 #include <ipc/securityd_client.h>
36 #include <Security/SecureObjectSync/SOSBackupEvent.h>
37 #include <Security/SecureObjectSync/SOSCloudCircle.h>
38 #include <Security/SecureObjectSync/SOSViews.h>
39 #include <corecrypto/ccsha1.h>
40 #include <utilities/SecCFError.h>
41 #include <utilities/SecCFRelease.h>
42 #include <utilities/SecCFCCWrappers.h>
43 #include <utilities/array_size.h>
44 #include <utilities/der_plist.h>
45 #include <utilities/der_plist_internal.h>
46 #include <AssertMacros.h>
47 #include <os/activity.h>
50 static CFDataRef
data_data_to_data_error_request(enum SecXPCOperation op
, CFDataRef keybag
, CFDataRef passcode
, CFErrorRef
*error
) {
51 __block CFDataRef result
= NULL
;
52 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
53 return SecXPCDictionarySetDataOptional(message
, kSecXPCKeyKeybag
, keybag
, error
)
54 && SecXPCDictionarySetDataOptional(message
, kSecXPCKeyUserPassword
, passcode
, error
);
55 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
56 return (result
= SecXPCDictionaryCopyData(response
, kSecXPCKeyResult
, error
));
61 static bool data_data_data_to_error_request(enum SecXPCOperation op
, CFDataRef backup
, CFDataRef keybag
, CFDataRef passcode
, CFErrorRef
*error
) {
62 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
63 return SecXPCDictionarySetData(message
, kSecXPCKeyBackup
, backup
, error
)
64 && SecXPCDictionarySetData(message
, kSecXPCKeyKeybag
, keybag
, error
)
65 && SecXPCDictionarySetDataOptional(message
, kSecXPCKeyUserPassword
, passcode
, error
);
69 static bool dict_data_data_to_error_request(enum SecXPCOperation op
, CFDictionaryRef backup
, CFDataRef keybag
, CFDataRef passcode
, CFErrorRef
*error
) {
70 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
71 return SecXPCDictionarySetPList(message
, kSecXPCKeyBackup
, backup
, error
)
72 && SecXPCDictionarySetData(message
, kSecXPCKeyKeybag
, keybag
, error
)
73 && SecXPCDictionarySetDataOptional(message
, kSecXPCKeyUserPassword
, passcode
, error
);
77 static CFDictionaryRef
data_data_dict_to_dict_error_request(enum SecXPCOperation op
, CFDictionaryRef backup
, CFDataRef keybag
, CFDataRef passcode
, CFErrorRef
*error
) {
78 __block CFDictionaryRef dict
= NULL
;
79 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
80 return SecXPCDictionarySetPListOptional(message
, kSecXPCKeyBackup
, backup
, error
)
81 && SecXPCDictionarySetData(message
, kSecXPCKeyKeybag
, keybag
, error
)
82 && SecXPCDictionarySetDataOptional(message
, kSecXPCKeyUserPassword
, passcode
, error
);
83 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
84 return (dict
= SecXPCDictionaryCopyDictionary(response
, kSecXPCKeyResult
, error
));
89 static int string_to_fd_error_request(enum SecXPCOperation op
, CFStringRef backupName
, CFErrorRef
*error
) {
91 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
92 return SecXPCDictionarySetString(message
, kSecXPCKeyBackup
, backupName
, error
);
93 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
94 fd
= SecXPCDictionaryDupFileDescriptor(response
, kSecXPCKeyResult
, error
);
100 static bool string_data_data_to_bool_error_request(enum SecXPCOperation op
, CFStringRef backupName
, CFDataRef keybagDigest
, CFDataRef manifest
, CFErrorRef
*error
)
102 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
103 return SecXPCDictionarySetString(message
, kSecXPCKeyBackup
, backupName
, error
) &&
104 SecXPCDictionarySetDataOptional(message
, kSecXPCKeyKeybag
, keybagDigest
, error
) &&
105 SecXPCDictionarySetDataOptional(message
, kSecXPCData
, manifest
, error
);
106 }, ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
107 return xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
111 static bool string_string_data_data_data_to_bool_error_request(enum SecXPCOperation op
, CFStringRef backupName
, CFStringRef peerID
, CFDataRef keybag
, CFDataRef secret
, CFDataRef backup
, CFErrorRef
*error
)
113 return securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
114 return SecXPCDictionarySetString(message
, kSecXPCKeyBackup
, backupName
, error
) &&
115 SecXPCDictionarySetStringOptional(message
, kSecXPCKeyDigest
, peerID
, error
) &&
116 SecXPCDictionarySetData(message
, kSecXPCKeyKeybag
, keybag
, error
) &&
117 SecXPCDictionarySetData(message
, kSecXPCKeyUserPassword
, secret
, error
) &&
118 SecXPCDictionarySetData(message
, kSecXPCData
, backup
, error
);
119 }, ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
120 return xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
124 static CFArrayRef
to_array_error_request(enum SecXPCOperation op
, CFErrorRef
*error
)
126 __block CFArrayRef result
= NULL
;
127 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
129 }, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
130 return result
= SecXPCDictionaryCopyArray(response
, kSecXPCKeyResult
, error
);
137 static int SecItemBackupHandoffFD(CFStringRef backupName
, CFErrorRef
*error
) {
138 __block
int fileDesc
= -1;
139 os_activity_initiate("SecItemBackupHandoffFD", OS_ACTIVITY_FLAG_DEFAULT
, ^{
140 fileDesc
= SECURITYD_XPC(sec_item_backup_handoff_fd
, string_to_fd_error_request
, backupName
, error
);
145 CFDataRef
_SecKeychainCopyOTABackup(void) {
146 __block CFDataRef result
;
147 os_activity_initiate("_SecKeychainCopyOTABackup", OS_ACTIVITY_FLAG_DEFAULT
, ^{
148 result
= SECURITYD_XPC(sec_keychain_backup
, data_data_to_data_error_request
, NULL
, NULL
, NULL
);
153 CFDataRef
_SecKeychainCopyBackup(CFDataRef backupKeybag
, CFDataRef password
) {
154 __block CFDataRef result
;
155 os_activity_initiate("_SecKeychainCopyBackup", OS_ACTIVITY_FLAG_DEFAULT
, ^{
156 result
= SECURITYD_XPC(sec_keychain_backup
, data_data_to_data_error_request
, backupKeybag
, password
, NULL
);
161 OSStatus
_SecKeychainRestoreBackup(CFDataRef backup
, CFDataRef backupKeybag
,
162 CFDataRef password
) {
163 __block OSStatus result
;
164 os_activity_initiate("_SecKeychainRestoreBackup", OS_ACTIVITY_FLAG_DEFAULT
, ^{
165 result
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
166 return SECURITYD_XPC(sec_keychain_restore
, data_data_data_to_error_request
, backup
, backupKeybag
, password
, error
);
172 static int compareDigests(const void *l
, const void *r
) {
173 return memcmp(l
, r
, CCSHA1_OUTPUT_SIZE
);
176 CFDataRef
SecItemBackupCreateManifest(CFDictionaryRef backup
, CFErrorRef
*error
)
178 CFIndex count
= backup
? CFDictionaryGetCount(backup
) : 0;
179 CFMutableDataRef manifest
= CFDataCreateMutable(kCFAllocatorDefault
, CCSHA1_OUTPUT_SIZE
* count
);
181 CFDictionaryForEach(backup
, ^void (const void *key
, const void *value
) {
182 if (isDictionary(value
)) {
183 /* converting key back to binary blob is horrible */
184 CFDataRef sha1
= CFDictionaryGetValue(value
, kSecItemBackupHashKey
);
185 if (isData(sha1
) && CFDataGetLength(sha1
) == CCSHA1_OUTPUT_SIZE
) {
186 CFDataAppend(manifest
, sha1
);
188 CFStringRef sha1Hex
= CFDataCopyHexString(sha1
);
189 secerror("bad hash %@ in backup", sha1Hex
);
190 CFReleaseSafe(sha1Hex
);
191 // TODO: Drop this key from dictionary (outside the loop)
195 qsort(CFDataGetMutableBytePtr(manifest
), CFDataGetLength(manifest
) / CCSHA1_OUTPUT_SIZE
, CCSHA1_OUTPUT_SIZE
, compareDigests
);
201 client code in CloudServices calls SecItemBackupWithChanges in the loop of SecItemBackupWithRegisteredBackups
203 __unused
static CFDictionaryRef
SecItemBackupSyncable(CFDataRef keybag
, CFDataRef password
, CFDictionaryRef backup_in
, CFErrorRef
*error
)
205 const CFStringRef backupName
= kSOSViewKeychainV0_tomb
;
206 __block
bool complete
= false;
207 __block CFMutableDictionaryRef backup
= backup_in
? CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, backup_in
) : CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
208 CFDataRef keybagDigest
= CFDataCopySHA1Digest(keybag
, NULL
); // Used to confirm we are in sync keybag wise.
210 CFErrorRef localError
= NULL
;
211 if (!SecItemBackupWithChanges(backupName
, &localError
, ^(SecBackupEventType et
, CFTypeRef key
, CFTypeRef item
) {
212 CFStringRef hexDigest
= key
? CFDataCopyHexString(key
) : NULL
;
215 case kSecBackupEventReset
:
216 CFDictionaryRemoveAllValues(backup
);
218 case kSecBackupEventAdd
:
219 CFDictionarySetValue(backup
, hexDigest
, item
);
221 case kSecBackupEventRemove
:
222 CFDictionaryRemoveValue(backup
, hexDigest
);
224 case kSecBackupEventComplete
:
228 CFReleaseSafe(hexDigest
);
231 if (localError
&& CFEqual(CFErrorGetDomain(localError
), kSecErrnoDomain
) && CFErrorGetCode(localError
) == ENOENT
) {
232 // No journal file returned by securityd, nothing left to do, ignore error and exit.
233 CFReleaseNull(localError
);
235 CFErrorPropagate(localError
, error
);
236 CFReleaseNull(backup
);
241 CFDataRef mconfirmed
= SecItemBackupCreateManifest(backup
, error
);
243 CFReleaseNull(backup
);
246 bool ok
= SecItemBackupSetConfirmedManifest(backupName
, keybagDigest
, mconfirmed
, error
);
247 CFReleaseSafe(mconfirmed
);
249 CFReleaseNull(backup
);
253 CFReleaseSafe(keybagDigest
);
258 #if 0 // interim code to call SecItemBackupSyncable
259 OSStatus
_SecKeychainBackupSyncable(CFDataRef keybag
, CFDataRef password
, CFDictionaryRef backup_in
, CFDictionaryRef
*backup_out
)
261 __block OSStatus result
;
262 os_activity_initiate("_SecKeychainBackupSyncable", OS_ACTIVITY_FLAG_DEFAULT
, ^{
263 result
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
264 *backup_out
= SecItemBackupSyncable(keybag
, password
, backup_in
, error
);
265 return *backup_out
!= NULL
;
272 OSStatus
_SecKeychainBackupSyncable(CFDataRef keybag
, CFDataRef password
, CFDictionaryRef backup_in
, CFDictionaryRef
*backup_out
)
274 return SecOSStatusWith(^bool (CFErrorRef
*error
) {
275 *backup_out
= SECURITYD_XPC(sec_keychain_backup_syncable
, data_data_dict_to_dict_error_request
, backup_in
, keybag
, password
, error
);
276 return *backup_out
!= NULL
;
280 OSStatus
_SecKeychainRestoreSyncable(CFDataRef keybag
, CFDataRef password
, CFDictionaryRef backup_in
)
282 __block OSStatus result
;
283 os_activity_initiate("_SecKeychainRestoreSyncable", OS_ACTIVITY_FLAG_DEFAULT
, ^{
284 result
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
285 return SECURITYD_XPC(sec_keychain_restore_syncable
, dict_data_data_to_error_request
, backup_in
, keybag
, password
, error
);
293 static bool SecKeychainWithBackupFile(CFStringRef backupName
, CFErrorRef
*error
, void(^with
)(FILE *bufile
)) {
294 int fd
= SecItemBackupHandoffFD(backupName
, error
);
296 secdebug("backup", "SecItemBackupHandoffFD returned %d", fd
);
299 FILE *backup
= fdopen(fd
, "r");
302 secdebug("backup", "Receiving file for %@ failed, %d", backupName
, errno
);
303 return SecCheckErrno(!backup
, error
, CFSTR("fdopen"));
305 secdebug("backup", "Receiving file for %@ with fd %d of size %llu", backupName
, fd
, lseek(fd
, 0, SEEK_END
));
308 // Rewind file to start
309 lseek(fd
, 0, SEEK_SET
);
315 static CFArrayRef
SecItemBackupCopyNames(CFErrorRef
*error
)
317 __block CFArrayRef result
;
318 os_activity_initiate("SecItemBackupCopyNames", OS_ACTIVITY_FLAG_DEFAULT
, ^{
319 result
= SECURITYD_XPC(sec_item_backup_copy_names
, to_array_error_request
, error
);
324 bool SecItemBackupWithRegisteredBackups(CFErrorRef
*error
, void(^backup
)(CFStringRef backupName
)) {
325 CFArrayRef backupNames
= SecItemBackupCopyNames(error
);
326 if (!backupNames
) return false;
328 CFArrayForEachC(backupNames
, name
) {
331 CFRelease(backupNames
);
335 static bool SecItemBackupDoResetEventBody(const uint8_t *der
, const uint8_t *der_end
, CFErrorRef
*error
, void (^handleEvent
)(SecBackupEventType et
, CFTypeRef key
, CFTypeRef item
)) {
337 const uint8_t *sequence_body
= ccder_decode_len(&sequence_len
, der
, der_end
);
338 bool ok
= sequence_body
;
339 if (ok
&& sequence_body
+ sequence_len
!= der_end
) {
340 // Can't ever happen!
341 SecError(errSecDecode
, error
, CFSTR("trailing junk after reset"));
345 CFDataRef keybag
= NULL
;
346 if (sequence_body
!= der_end
) {
347 size_t keybag_len
= 0;
348 const uint8_t *keybag_start
= ccder_decode_tl(CCDER_OCTET_STRING
, &keybag_len
, sequence_body
, der_end
);
350 ok
= SecError(errSecDecode
, error
, CFSTR("failed to decode keybag"));
351 } else if (keybag_start
+ keybag_len
!= der_end
) {
352 ok
= SecError(errSecDecode
, error
, CFSTR("trailing junk after keybag"));
354 keybag
= CFDataCreate(kCFAllocatorDefault
, keybag_start
, keybag_len
);
357 handleEvent(kSecBackupEventReset
, keybag
, NULL
);
358 CFReleaseSafe(keybag
);
364 static bool SecItemBackupDoAddEvent(const uint8_t *der
, const uint8_t *der_end
, CFErrorRef
*error
, void (^handleEvent
)(SecBackupEventType et
, CFTypeRef key
, CFTypeRef item
)) {
365 CFDictionaryRef eventDict
= NULL
;
366 const uint8_t *der_end_of_dict
= der_decode_dictionary(kCFAllocatorDefault
, kCFPropertyListImmutable
, &eventDict
, error
, der
, der_end
);
367 if (der_end_of_dict
&& der_end_of_dict
!= der_end
) {
368 // Can't ever happen!
369 SecError(errSecDecode
, error
, CFSTR("trailing junk after add"));
370 der_end_of_dict
= NULL
;
372 if (der_end_of_dict
) {
373 CFDataRef hash
= CFDictionaryGetValue(eventDict
, kSecItemBackupHashKey
);
374 handleEvent(kSecBackupEventAdd
, hash
, eventDict
);
377 CFReleaseSafe(eventDict
);
378 return der_end_of_dict
;
381 static bool SecItemBackupDoCompleteEvent(const uint8_t *der
, const uint8_t *der_end
, CFErrorRef
*error
, void (^handleEvent
)(SecBackupEventType et
, CFTypeRef key
, CFTypeRef item
)) {
382 uint64_t event_num
= 0;
383 const uint8_t *der_end_of_num
= ccder_decode_uint64(&event_num
, der
, der_end
);
384 if (der_end_of_num
&& der_end_of_num
!= der_end
) {
385 // Can't ever happen!
386 SecError(errSecDecode
, error
, CFSTR("trailing junk after complete"));
387 der_end_of_num
= NULL
;
389 if (der_end_of_num
) {
390 handleEvent(kSecBackupEventComplete
, NULL
, NULL
);
392 return der_end_of_num
;
395 static bool SecItemBackupDoDeleteEventBody(const uint8_t *der
, const uint8_t *der_end
, CFErrorRef
*error
, void (^handleEvent
)(SecBackupEventType et
, CFTypeRef key
, CFTypeRef item
)) {
396 size_t digest_len
= 0;
397 const uint8_t *digest_start
= ccder_decode_len(&digest_len
, der
, der_end
);
398 if (digest_start
&& digest_start
+ digest_len
!= der_end
) {
399 // Can't ever happen!
400 SecError(errSecDecode
, error
, CFSTR("trailing junk after delete"));
404 CFDataRef hash
= CFDataCreate(kCFAllocatorDefault
, digest_start
, digest_len
);
405 handleEvent(kSecBackupEventRemove
, hash
, NULL
);
412 static void debugDisplayBackupEventTag(ccder_tag tag
) {
414 const char *eventDesc
;
416 case CCDER_CONSTRUCTED_SEQUENCE
: eventDesc
= "ResetEvent"; break;
417 case CCDER_CONSTRUCTED_SET
: eventDesc
= "AddEvent"; break;
418 case CCDER_INTEGER
: eventDesc
= "ResetEvent"; break;
419 case CCDER_OCTET_STRING
: eventDesc
= "DeleteEvent"; break;
420 default: eventDesc
= "UnknownEvent"; break;
422 secdebug("backup", "processing event %s (tag %08lX)", eventDesc
, tag
);
426 static bool SecItemBackupDoEvent(const uint8_t *der
, const uint8_t *der_end
, CFErrorRef
*error
, void (^handleEvent
)(SecBackupEventType et
, CFTypeRef key
, CFTypeRef item
)) {
428 const uint8_t *der_start_of_len
= ccder_decode_tag(&tag
, der
, der_end
);
429 debugDisplayBackupEventTag(tag
);
431 case CCDER_CONSTRUCTED_SEQUENCE
:
432 return SecItemBackupDoResetEventBody(der_start_of_len
, der_end
, error
, handleEvent
);
433 case CCDER_CONSTRUCTED_SET
:
434 return SecItemBackupDoAddEvent(der
, der_end
, error
, handleEvent
);
436 return SecItemBackupDoCompleteEvent(der
, der_end
, error
, handleEvent
);
437 case CCDER_OCTET_STRING
:
438 return SecItemBackupDoDeleteEventBody(der_start_of_len
, der_end
, error
, handleEvent
);
440 return SecError(errSecDecode
, error
, CFSTR("unsupported event tag: %lu"), tag
);
444 // TODO: Move to ccder and give better name.
445 static const uint8_t *ccder_decode_len_unchecked(size_t *lenp
, const uint8_t *der
, const uint8_t *der_end
) {
446 if (der
&& der
< der_end
) {
449 } else if (len
== 0x81) {
450 if (der_end
- der
< 1) goto errOut
;
452 } else if (len
== 0x82) {
453 if (der_end
- der
< 2) goto errOut
;
456 } else if (len
== 0x83) {
457 if (der_end
- der
< 3) goto errOut
;
458 len
= *(der
++) << 16;
459 len
+= *(der
++) << 8;
471 static bool SecKeychainWithBackupFileParse(FILE *backup
, CFErrorRef
*error
, void (^handleEvent
)(SecBackupEventType et
, CFTypeRef key
, CFTypeRef item
)) {
472 __block
bool ok
= true;
473 size_t buf_remaining
= 0;
474 const size_t read_ahead
= 16;
475 size_t buf_len
= read_ahead
;
476 uint8_t *buf
= malloc(buf_len
);
478 const size_t bytes_read
= fread(buf
+ buf_remaining
, 1, read_ahead
- buf_remaining
, backup
);
479 if (bytes_read
<= 0) {
481 ok
= SecCheckErrno(true, error
, CFSTR("read backup event header"));
482 else if (!buf_remaining
) {
483 // Nothing read, nothing in buffer, clean eof.
487 const size_t buf_avail
= bytes_read
+ buf_remaining
;
489 const uint8_t *der
= buf
;
490 const uint8_t *der_end
= der
+ buf_avail
;
493 der
= ccder_decode_tag(&tag
, der
, der_end
);
494 der
= ccder_decode_len_unchecked(&body_len
, der
, der_end
);
497 ok
= SecError(errSecDecode
, error
, CFSTR("failed to decode backup event header"));
501 const size_t decoded_len
= der
- buf
;
502 size_t event_len
= decoded_len
+ body_len
;
503 if (event_len
> buf_avail
) {
504 // We need to read the rest of this event, first
505 // ensure we have enough space.
506 if (buf_len
< event_len
) {
507 // TODO: Think about a max for buf_len here to prevent attacks.
508 uint8_t *new_buf
= realloc(buf
, event_len
);
510 ok
= SecError(errSecAllocate
, error
, CFSTR("realloc buf failed"));
517 // Read tail of current event.
518 const size_t tail_len
= fread(buf
+ buf_avail
, 1, event_len
- buf_avail
, backup
);
519 if (tail_len
< event_len
- buf_avail
) {
521 ok
= SecCheckErrno(true, error
, CFSTR("failed to read event body"));
523 ok
= SecError(errSecDecode
, error
, CFSTR("unexpected end of event file %zu of %zu bytes read"), tail_len
, event_len
- buf_avail
);
529 // Adjust der_end to the end of the event.
530 der_end
= buf
+ event_len
;
532 ok
&= SecItemBackupDoEvent(buf
, der_end
, error
, handleEvent
);
534 if (event_len
< buf_avail
) {
535 // Shift remaining bytes to start of buffer.
536 buf_remaining
= buf_avail
- event_len
;
537 memmove(buf
, der_end
, buf_remaining
);
546 bool SecItemBackupWithChanges(CFStringRef backupName
, CFErrorRef
*error
, void (^handleEvent
)(SecBackupEventType et
, CFTypeRef key
, CFTypeRef item
)) {
547 __block
bool ok
= true;
548 __block CFErrorRef localError
= NULL
;
549 ok
&= SecKeychainWithBackupFile(backupName
, &localError
, ^(FILE *backup
) {
550 ok
&= SecKeychainWithBackupFileParse(backup
, &localError
, handleEvent
);
552 if (!ok
) { // TODO: remove this logging
553 secdebug("backup", "SecItemBackupWithChanges failed: %@", localError
);
554 handleEvent(kSecBackupEventComplete
, NULL
, NULL
);
555 CFErrorPropagate(localError
, error
);
561 bool SecItemBackupSetConfirmedManifest(CFStringRef backupName
, CFDataRef keybagDigest
, CFDataRef manifest
, CFErrorRef
*error
) {
563 os_activity_initiate("SecItemBackupSetConfirmedManifest", OS_ACTIVITY_FLAG_DEFAULT
, ^{
564 result
= SECURITYD_XPC(sec_item_backup_set_confirmed_manifest
, string_data_data_to_bool_error_request
, backupName
, keybagDigest
, manifest
, error
);
569 void SecItemBackupRestore(CFStringRef backupName
, CFStringRef peerID
, CFDataRef keybag
, CFDataRef secret
, CFTypeRef backup
, void (^completion
)(CFErrorRef error
)) {
570 __block CFErrorRef localError
= NULL
;
571 os_activity_initiate("SecItemBackupRestore", OS_ACTIVITY_FLAG_DEFAULT
, ^{
572 SECURITYD_XPC(sec_item_backup_restore
, string_string_data_data_data_to_bool_error_request
, backupName
, peerID
, keybag
, secret
, backup
, &localError
);
574 completion(localError
);
575 CFReleaseSafe(localError
);
578 CFDictionaryRef
SecItemBackupCopyMatching(CFDataRef keybag
, CFDataRef secret
, CFDictionaryRef backup
, CFDictionaryRef query
, CFErrorRef
*error
) {
579 SecError(errSecUnimplemented
, error
, CFSTR("SecItemBackupCopyMatching unimplemented"));