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