SOSBackupEvent.c
1 /* 2 * Copyright (c) 2015 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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 11 * file. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 /* 25 * SOSBackupEvent.c - Implementation of a secure object syncing peer 26 */ 27 28 #include "keychain/SecureObjectSync/SOSBackupEvent.h" 29 #include <corecrypto/ccsha1.h> 30 #include <utilities/SecCFError.h> 31 #include <utilities/SecCFRelease.h> 32 #include <utilities/array_size.h> 33 #include <utilities/der_plist.h> 34 #include <utilities/der_plist_internal.h> 35 #include <AssertMacros.h> 36 37 // 38 // MARK: statics 39 // 40 41 /* 42 Event ASN.1 definitions 43 44 ResetEvent := SEQUENCE { 45 keybag OCTET STRING OPTIONAL 46 } 47 48 AddEvent := SET { 49 SEQUENCE { 50 UTF8STRING :class 51 class UTF8STRING 52 } 53 SEQUENCE { 54 UTF8STRING :hash 55 hash OCTET STRING 56 } 57 SEQUENCE { 58 UTF8STRING :data 59 data OCTET STRING 60 } 61 } 62 63 DeleteEvent := OCTET STRING 64 65 CompleteEvent := INTEGER 66 67 Event := CHOICE { 68 reset ResetEvent 69 add AddEvent 70 delete DeleteEvent 71 complete CompleteEvent 72 } 73 74 */ 75 76 static size_t der_sizeof_backup_reset(CFDataRef keybag) { 77 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, 78 keybag ? ccder_sizeof_raw_octet_string(CFDataGetLength(keybag)) : 0); 79 } 80 81 static uint8_t* der_encode_backup_reset(CFDataRef keybag, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) { 82 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, 83 keybag ? ccder_encode_raw_octet_string(CFDataGetLength(keybag), CFDataGetBytePtr(keybag), der, der_end) : der_end); 84 } 85 86 static size_t der_sizeof_backup_add(CFDictionaryRef add) { 87 return der_sizeof_dictionary(add, NULL); 88 } 89 90 static uint8_t* der_encode_backup_add(CFDictionaryRef add, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) { 91 // der_dictionary tag is CCDER_CONSTRUCTED_SET 92 return der_encode_dictionary(add, error, der, der_end); 93 } 94 95 static size_t der_sizeof_backup_delete(CFDataRef deletedDigest) { 96 return ccder_sizeof_raw_octet_string(CFDataGetLength(deletedDigest)); 97 } 98 99 static uint8_t* der_encode_backup_delete(CFDataRef deletedDigest, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) { 100 return ccder_encode_raw_octet_string(CFDataGetLength(deletedDigest), CFDataGetBytePtr(deletedDigest), der, der_end); 101 } 102 103 static size_t der_sizeof_backup_complete(uint64_t event_num) { 104 return ccder_sizeof_uint64(event_num); 105 } 106 107 static uint8_t* der_encode_backup_complete(uint64_t event_num, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) { 108 return ccder_encode_uint64(event_num, der, der_end); 109 } 110 111 112 // 113 // MARK: SPI 114 // 115 116 static bool SOSBackupEventWrite(FILE *journalFile, CFErrorRef *error, 117 size_t len, 118 uint8_t *(^encode)(const uint8_t *der, uint8_t *der_end)) 119 { 120 bool ok = false; 121 CFMutableDataRef derObject = CFDataCreateMutable(kCFAllocatorDefault, len); 122 CFDataSetLength(derObject, len); 123 uint8_t *der_end = CFDataGetMutableBytePtr(derObject); 124 const uint8_t *der = der_end; 125 der_end += len; 126 127 require(der_end = encode(der, der_end), xit); 128 require_action(der == der_end, xit, SecError(-1, error, CFSTR("size mismatch der_end - der: %td"), der_end - der)); 129 130 ok = SecCheckErrno(1 != fwrite(der, len, 1, journalFile), error, CFSTR("fwrite SOSBackupEventWrite")); 131 xit: 132 CFReleaseSafe(derObject); 133 return ok; 134 } 135 136 bool SOSBackupEventWriteReset(FILE *journalFile, CFDataRef keybag, CFErrorRef *error) { 137 return SOSBackupEventWrite(journalFile, error, der_sizeof_backup_reset(keybag), ^uint8_t *(const uint8_t *der, uint8_t *der_end) { 138 return der_encode_backup_reset(keybag, error, der, der_end); 139 }); 140 } 141 142 bool SOSBackupEventWriteDelete(FILE *journalFile, CFDataRef deletedDigest, CFErrorRef *error) { 143 return SOSBackupEventWrite(journalFile, error, der_sizeof_backup_delete(deletedDigest), ^uint8_t *(const uint8_t *der, uint8_t *der_end) { 144 return der_encode_backup_delete(deletedDigest, error, der, der_end); 145 }); 146 } 147 148 bool SOSBackupEventWriteAdd(FILE *journalFile, CFDictionaryRef backup_item, CFErrorRef *error) { 149 return SOSBackupEventWrite(journalFile, error, der_sizeof_backup_add(backup_item), ^uint8_t *(const uint8_t *der, uint8_t *der_end) { 150 return der_encode_backup_add(backup_item, error, der, der_end); 151 }); 152 } 153 154 bool SOSBackupEventWriteCompleteMarker(FILE *journalFile, uint64_t eventID, CFErrorRef *error) { 155 bool ok = SOSBackupEventWrite(journalFile, error, der_sizeof_backup_complete(eventID), ^uint8_t *(const uint8_t *der, uint8_t *der_end) { 156 return der_encode_backup_complete(eventID, error, der, der_end); 157 }); 158 // TODO: Move this to right before we send a notification or something. 159 fflush(journalFile); 160 return ok; 161 }