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 }