/ keychain / SecureObjectSync / SOSBackupEvent.c
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  }