/ keychain / SecureObjectSync / SOSGenCount.c
SOSGenCount.c
  1  //
  2  //  SOSGenCount.c
  3  //  sec
  4  //
  5  //  Created by Richard Murphy on 1/29/15.
  6  //
  7  //
  8  
  9  #include "SOSGenCount.h"
 10  #include <utilities/SecCFWrappers.h>
 11  #include <CoreFoundation/CFLocale.h>
 12  #include <utilities/der_plist.h>
 13  #include <utilities/der_plist_internal.h>
 14  
 15  
 16  static CFAbsoluteTime SOSGenerationCountGetDateBits(int64_t genValue) {
 17      return (uint32_t) ((((uint64_t) genValue) >> 32) << 1);
 18  }
 19  
 20  void SOSGenerationCountWithDescription(SOSGenCountRef gen, void (^operation)(CFStringRef description)) {
 21      CFStringRef description = SOSGenerationCountCopyDescription(gen);
 22  
 23      operation(description);
 24  
 25      CFReleaseSafe(description);
 26  }
 27  
 28  CFStringRef SOSGenerationCountCopyDescription(SOSGenCountRef gen) {
 29      int64_t value = SOSGetGenerationSint(gen);
 30  
 31      CFMutableStringRef gcDecsription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("["));
 32  
 33      withStringOfAbsoluteTime(SOSGenerationCountGetDateBits(value), ^(CFStringRef decription) {
 34          CFStringAppend(gcDecsription, decription);
 35      });
 36  
 37      CFStringAppendFormat(gcDecsription, NULL, CFSTR(" %u]"), (uint32_t)(value & 0xFFFFFFFF));
 38  
 39      return gcDecsription;
 40  }
 41  
 42  int64_t SOSGetGenerationSint(SOSGenCountRef gen) {
 43      int64_t value;
 44      if(!gen) return 0;
 45      CFNumberGetValue(gen, kCFNumberSInt64Type, &value);
 46      return value;
 47  }
 48  
 49  static int64_t sosGenerationSetHighBits(int64_t value, int32_t high_31)
 50  {
 51      value &= 0xFFFFFFFF; // Keep the low 32 bits.
 52      value |= ((int64_t) high_31) << 32;
 53  
 54      return value;
 55  }
 56  
 57  static SOSGenCountRef sosGenerationCreateOrIncrement(SOSGenCountRef gen) {
 58      int64_t value = 0;
 59  
 60      if(gen) {
 61          value = SOSGetGenerationSint(gen);
 62      }
 63  
 64      if((value >> 32) == 0) {
 65          uint32_t seconds = CFAbsoluteTimeGetCurrent(); // seconds
 66          value = sosGenerationSetHighBits(value, (seconds >> 1));
 67      }
 68  
 69      value++;
 70      return CFNumberCreate(NULL, kCFNumberSInt64Type, &value);
 71  }
 72  
 73  SOSGenCountRef SOSGenerationCreate() {
 74      return sosGenerationCreateOrIncrement(NULL);
 75  }
 76  
 77  
 78  // We need this for a circle gencount test
 79  SOSGenCountRef SOSGenerationCreateWithValue(int64_t value) {
 80      return CFNumberCreate(NULL, kCFNumberSInt64Type, &value);
 81  }
 82  
 83  SOSGenCountRef SOSGenerationIncrementAndCreate(SOSGenCountRef gen) {
 84      return sosGenerationCreateOrIncrement(gen);
 85  }
 86  
 87  SOSGenCountRef SOSGenerationCopy(SOSGenCountRef gen) {
 88      if(!gen) return NULL;
 89      int64_t value = SOSGetGenerationSint(gen);
 90      return CFNumberCreate(NULL, kCFNumberSInt64Type, &value);
 91  }
 92  
 93  // Is current older than proposed?
 94  bool SOSGenerationIsOlder(SOSGenCountRef older, SOSGenCountRef newer) {
 95      switch(CFNumberCompare(older, newer, NULL)) {
 96          case kCFCompareLessThan:  return true;
 97          case kCFCompareEqualTo: return false;
 98          case kCFCompareGreaterThan:  return false;
 99      }
100      return false;
101  }
102  
103  // Is current older than proposed?
104  static bool SOSGenerationIsOlderOrEqual(SOSGenCountRef older, SOSGenCountRef newer) {
105      switch(CFNumberCompare(older, newer, NULL)) {
106          case kCFCompareLessThan:  return true;
107          case kCFCompareEqualTo: return true;
108          case kCFCompareGreaterThan:  return false;
109      }
110      return false;
111  }
112  
113  
114  SOSGenCountRef SOSGenerationCreateWithBaseline(SOSGenCountRef reference) {
115      SOSGenCountRef retval = SOSGenerationCreate();
116      if(SOSGenerationIsOlderOrEqual(retval, reference)) {
117          CFReleaseNull(retval);
118          retval = SOSGenerationIncrementAndCreate(reference);
119      }
120      return retval;
121  }
122  
123  
124  SOSGenCountRef SOSGenCountCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error,
125                                          const uint8_t** der_p, const uint8_t *der_end) {
126      SOSGenCountRef retval = NULL;
127      *der_p = der_decode_number(allocator, &retval, error, *der_p, der_end);
128      if(retval == NULL)
129          retval = SOSGenerationCreate();
130      return retval;
131  }
132  
133  size_t SOSGenCountGetDEREncodedSize(SOSGenCountRef gencount, CFErrorRef *error) {
134      return der_sizeof_number(gencount, error);
135  }
136  
137  uint8_t *SOSGenCountEncodeToDER(SOSGenCountRef gencount, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) {
138      return der_encode_number(gencount, error, der, der_end);
139  }
140  
141  
142