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