/ keychain / SecureObjectSync / SOSManifest.c
SOSManifest.c
  1  /*
  2   * Copyright (c) 2013-2014 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  /*
 26   * SOSManifest.c -  Manifest object and some manipulation around it
 27   */
 28  
 29  #include "keychain/SecureObjectSync/SOSManifest.h"
 30  #include "keychain/SecureObjectSync/SOSDigestVector.h"
 31  #include <utilities/SecCFError.h>
 32  #include <utilities/SecCFWrappers.h>
 33  #include <utilities/SecCFCCWrappers.h>
 34  
 35  CFStringRef kSOSManifestErrorDomain = CFSTR("com.apple.security.sos.manifest.error");
 36  
 37  /* SOSManifest implementation. */
 38  struct __OpaqueSOSManifest {
 39      CFRuntimeBase _base;
 40      CFDataRef digest;
 41      CFDataRef digestVector;
 42      struct SOSDigestVector dv;
 43  };
 44  
 45  CFGiblisWithCompareFor(SOSManifest)
 46  
 47  static void SOSManifestDestroy(CFTypeRef cf) {
 48      SOSManifestRef mf = (SOSManifestRef)cf;
 49      CFReleaseSafe(mf->digest);
 50      CFReleaseSafe(mf->digestVector);
 51  }
 52  
 53  static Boolean SOSManifestCompare(CFTypeRef cf1, CFTypeRef cf2) {
 54      SOSManifestRef mf1 = (SOSManifestRef)cf1;
 55      SOSManifestRef mf2 = (SOSManifestRef)cf2;
 56      return CFEqualSafe(SOSManifestGetDigest(mf1, NULL), SOSManifestGetDigest(mf2, NULL));
 57  }
 58  
 59  SOSManifestRef SOSManifestCreateWithData(CFDataRef data, CFErrorRef *error)
 60  {
 61      SOSManifestRef manifest = CFTypeAllocate(SOSManifest, struct __OpaqueSOSManifest, kCFAllocatorDefault);
 62      if (!manifest)
 63          SecCFCreateErrorWithFormat(kSOSManifestCreateError, kSOSManifestErrorDomain, NULL, error, NULL, CFSTR("Failed to create manifest"));
 64      else if (data)
 65          manifest->digestVector = CFDataCreateCopy(kCFAllocatorDefault, data);
 66      else
 67          manifest->digestVector = CFDataCreate(kCFAllocatorDefault, NULL, 0);
 68  
 69      assert(!manifest || manifest->digestVector != NULL);
 70      return manifest;
 71  }
 72  
 73  SOSManifestRef SOSManifestCreateWithBytes(const uint8_t *bytes, size_t len,
 74                                            CFErrorRef *error) {
 75      CFDataRef data = CFDataCreate(kCFAllocatorDefault, bytes, (CFIndex)len);
 76      SOSManifestRef manifest = SOSManifestCreateWithData(data, error);
 77      CFReleaseSafe(data);
 78      return manifest;
 79  }
 80  
 81  size_t SOSManifestGetSize(SOSManifestRef m) {
 82      return m ? (size_t)CFDataGetLength(m->digestVector) : 0;
 83  }
 84  
 85  size_t SOSManifestGetCount(SOSManifestRef m) {
 86      return m ? SOSManifestGetSize(m) / SOSDigestSize : 0;
 87  }
 88  
 89  const uint8_t *SOSManifestGetBytePtr(SOSManifestRef m) {
 90      return m ? CFDataGetBytePtr(m->digestVector) : NULL;
 91  }
 92  
 93  CFDataRef SOSManifestGetData(SOSManifestRef m) {
 94      return m ? m->digestVector : NULL;
 95  }
 96  
 97  const struct SOSDigestVector *SOSManifestGetDigestVector(SOSManifestRef manifest) {
 98      if (!manifest) {
 99          static struct SOSDigestVector nulldv = SOSDigestVectorInit;
100          return &nulldv;
101      }
102      manifest->dv.capacity = manifest->dv.count = SOSManifestGetCount(manifest);
103      manifest->dv.digest = (void *)SOSManifestGetBytePtr(manifest);
104      manifest->dv.unsorted = false;
105      return &manifest->dv;
106  }
107  
108  bool SOSManifestDiff(SOSManifestRef a, SOSManifestRef b,
109                       SOSManifestRef *a_minus_b, SOSManifestRef *b_minus_a,
110                       CFErrorRef *error) {
111      bool result = true;
112      if (SOSManifestGetCount(a) == 0) {
113          //secnotice("manifest", "diff = b");
114          SOSManifestRef empty = SOSManifestCreateWithBytes(NULL, 0, error);
115          if (a_minus_b) CFRetainAssign(*a_minus_b, empty);
116          if (b_minus_a) *b_minus_a = CFRetainSafe(b ? b : empty);
117          CFReleaseNull(empty);
118      } else if (SOSManifestGetCount(b) == 0) {
119          //secnotice("manifest", "diff = a");
120          SOSManifestRef empty = SOSManifestCreateWithBytes(NULL, 0, error);
121          if (a_minus_b) *a_minus_b = CFRetainSafe(a ? a : empty);
122          if (b_minus_a) CFRetainAssign(*b_minus_a, empty);
123          CFReleaseNull(empty);
124      } else {
125          struct SOSDigestVector dvab = SOSDigestVectorInit, dvba = SOSDigestVectorInit;
126          SOSDigestVectorDiffSorted(SOSManifestGetDigestVector(a), SOSManifestGetDigestVector(b), &dvab, &dvba);
127          if (a_minus_b) {
128              *a_minus_b = SOSManifestCreateWithDigestVector(&dvab, error);
129              if (!*a_minus_b)
130                  result = false;
131          }
132          if (b_minus_a) {
133              *b_minus_a = SOSManifestCreateWithDigestVector(&dvba, error);
134              if (!*b_minus_a)
135                  result = false;
136          }
137          SOSDigestVectorFree(&dvab);
138          SOSDigestVectorFree(&dvba);
139      }
140      return result;
141  }
142  
143  
144  SOSManifestRef SOSManifestCreateWithDigestVector(struct SOSDigestVector *dv, CFErrorRef *error) {
145      if (!dv) return NULL;
146      if (dv->unsorted) SOSDigestVectorSort(dv);
147      return SOSManifestCreateWithBytes((const uint8_t *)dv->digest, dv->count * SOSDigestSize, error);
148  }
149  
150  SOSManifestRef SOSManifestCreateWithPatch(SOSManifestRef base,
151                                            SOSManifestRef removals,
152                                            SOSManifestRef additions,
153                                            CFErrorRef *error) {
154      struct SOSDigestVector dvresult = SOSDigestVectorInit;
155      SOSManifestRef result;
156      if (SOSDigestVectorPatchSorted(SOSManifestGetDigestVector(base), SOSManifestGetDigestVector(removals),
157                               SOSManifestGetDigestVector(additions), &dvresult, error)) {
158          result = SOSManifestCreateWithDigestVector(&dvresult, error);
159      } else {
160          result = NULL;
161      }
162      SOSDigestVectorFree(&dvresult);
163      return result;
164  }
165  
166  // This is the set of elements in m2, but not in m1.
167  SOSManifestRef SOSManifestCreateComplement(SOSManifestRef m1,
168                                             SOSManifestRef m2,
169                                             CFErrorRef *error) {
170      // m2 \ emptySet => m2
171      if (SOSManifestGetCount(m1) == 0) {
172          //secnotice("manifest", "complement = m2");
173          return m2 ? CFRetainSafe(m2) : SOSManifestCreateWithBytes(NULL, 0, error);
174      }
175  
176      struct SOSDigestVector dvresult = SOSDigestVectorInit;
177      SOSManifestRef result;
178      SOSDigestVectorComplementSorted(SOSManifestGetDigestVector(m1), SOSManifestGetDigestVector(m2), &dvresult);
179      result = SOSManifestCreateWithDigestVector(&dvresult, error);
180      SOSDigestVectorFree(&dvresult);
181      return result;
182  }
183  
184  SOSManifestRef SOSManifestCreateIntersection(SOSManifestRef m1,
185                                               SOSManifestRef m2,
186                                               CFErrorRef *error) {
187      struct SOSDigestVector dvresult = SOSDigestVectorInit;
188      SOSManifestRef result;
189      SOSDigestVectorIntersectSorted(SOSManifestGetDigestVector(m1), SOSManifestGetDigestVector(m2), &dvresult);
190      result = SOSManifestCreateWithDigestVector(&dvresult, error);
191      SOSDigestVectorFree(&dvresult);
192      return result;
193  }
194  
195  SOSManifestRef SOSManifestCreateUnion(SOSManifestRef m1,
196                                        SOSManifestRef m2,
197                                        CFErrorRef *error) {
198      if (SOSManifestGetCount(m1) == 0) {
199          //secnotice("manifest", "union = m2");
200          return m2 ? CFRetainSafe(m2) : SOSManifestCreateWithBytes(NULL, 0, error);
201      } else if (SOSManifestGetCount(m2) == 0) {
202          //secnotice("manifest", "union = m1");
203          return m1 ? CFRetainSafe(m1) : SOSManifestCreateWithBytes(NULL, 0, error);
204      } else {
205          struct SOSDigestVector dvresult = SOSDigestVectorInit;
206          SOSManifestRef result;
207          SOSDigestVectorUnionSorted(SOSManifestGetDigestVector(m1), SOSManifestGetDigestVector(m2), &dvresult);
208          result = SOSManifestCreateWithDigestVector(&dvresult, error);
209          SOSDigestVectorFree(&dvresult);
210          return result;
211      }
212  }
213  
214  void SOSManifestForEach(SOSManifestRef m, void(^block)(CFDataRef e, bool *stop)) {
215      CFDataRef e;
216      const uint8_t *p, *q;
217      bool stop = false;
218      for (p = SOSManifestGetBytePtr(m), q = p + SOSManifestGetSize(m);
219           !stop && p + SOSDigestSize <= q; p += SOSDigestSize) {
220          e = CFDataCreate(kCFAllocatorDefault, p, SOSDigestSize);
221          if (e) {
222              block(e, &stop);
223              CFRelease(e);
224          }
225      }
226  }
227  
228  CFDataRef SOSManifestGetDigest(SOSManifestRef m, CFErrorRef *error) {
229      if (!m) return NULL;
230      if (!m->digest)
231          m->digest = CFDataCreateSHA1DigestWithBytes(kCFAllocatorDefault, SOSManifestGetSize(m), SOSManifestGetBytePtr(m), error);
232      return m->digest;
233  }
234  
235  static CFStringRef SOSManifestCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
236      SOSManifestRef mf = (SOSManifestRef)cf;
237      CFMutableStringRef desc = CFStringCreateMutable(0, 0);
238      if (SOSManifestGetCount(mf) >= 8) {
239          const uint8_t *m = CFDataGetBytePtr(SOSManifestGetDigest(mf, NULL));
240          CFStringAppendFormat(desc, NULL, CFSTR("<[%zu:%02X%02X%02X%02X]"), SOSManifestGetCount(mf), m[0], m[1], m[2], m[3]);
241      } else {
242          CFStringAppendFormat(desc, NULL, CFSTR("<[%zu]"), SOSManifestGetCount(mf));
243      }
244      __block size_t maxEntries = 8;
245      SOSManifestForEach(mf, ^(CFDataRef e, bool *stop) {
246          const uint8_t *d = CFDataGetBytePtr(e);
247          CFStringAppendFormat(desc, NULL, CFSTR(" %02X%02X%02X%02X"), d[0], d[1], d[2], d[3]);
248          if (!--maxEntries) {
249              CFStringAppend(desc, CFSTR("..."));
250              *stop = true;
251          }
252      });
253      CFStringAppend(desc, CFSTR(">"));
254  
255      return desc;
256  }