]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSManifest.c
Security-57336.10.29.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / 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 <Security/SecureObjectSync/SOSManifest.h>
30 #include <Security/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 = CFDataCreateWithBytesNoCopy(0, p, SOSDigestSize, kCFAllocatorNull);
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 }