2 * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 * SOSManifest.c - Manifest object and some manipulation around it
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>
35 CFStringRef kSOSManifestErrorDomain
= CFSTR("com.apple.security.sos.manifest.error");
37 /* SOSManifest implementation. */
38 struct __OpaqueSOSManifest
{
41 CFDataRef digestVector
;
42 struct SOSDigestVector dv
;
45 CFGiblisWithCompareFor(SOSManifest
)
47 static void SOSManifestDestroy(CFTypeRef cf
) {
48 SOSManifestRef mf
= (SOSManifestRef
)cf
;
49 CFReleaseSafe(mf
->digest
);
50 CFReleaseSafe(mf
->digestVector
);
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
));
59 SOSManifestRef
SOSManifestCreateWithData(CFDataRef data
, CFErrorRef
*error
)
61 SOSManifestRef manifest
= CFTypeAllocate(SOSManifest
, struct __OpaqueSOSManifest
, kCFAllocatorDefault
);
63 SecCFCreateErrorWithFormat(kSOSManifestCreateError
, kSOSManifestErrorDomain
, NULL
, error
, NULL
, CFSTR("Failed to create manifest"));
65 manifest
->digestVector
= CFDataCreateCopy(kCFAllocatorDefault
, data
);
67 manifest
->digestVector
= CFDataCreate(kCFAllocatorDefault
, NULL
, 0);
69 assert(!manifest
|| manifest
->digestVector
!= NULL
);
73 SOSManifestRef
SOSManifestCreateWithBytes(const uint8_t *bytes
, size_t len
,
75 CFDataRef data
= CFDataCreate(kCFAllocatorDefault
, bytes
, (CFIndex
)len
);
76 SOSManifestRef manifest
= SOSManifestCreateWithData(data
, error
);
81 size_t SOSManifestGetSize(SOSManifestRef m
) {
82 return m
? (size_t)CFDataGetLength(m
->digestVector
) : 0;
85 size_t SOSManifestGetCount(SOSManifestRef m
) {
86 return m
? SOSManifestGetSize(m
) / SOSDigestSize
: 0;
89 const uint8_t *SOSManifestGetBytePtr(SOSManifestRef m
) {
90 return m
? CFDataGetBytePtr(m
->digestVector
) : NULL
;
93 CFDataRef
SOSManifestGetData(SOSManifestRef m
) {
94 return m
? m
->digestVector
: NULL
;
97 const struct SOSDigestVector
*SOSManifestGetDigestVector(SOSManifestRef manifest
) {
99 static struct SOSDigestVector nulldv
= SOSDigestVectorInit
;
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
;
108 bool SOSManifestDiff(SOSManifestRef a
, SOSManifestRef b
,
109 SOSManifestRef
*a_minus_b
, SOSManifestRef
*b_minus_a
,
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
);
125 struct SOSDigestVector dvab
= SOSDigestVectorInit
, dvba
= SOSDigestVectorInit
;
126 SOSDigestVectorDiffSorted(SOSManifestGetDigestVector(a
), SOSManifestGetDigestVector(b
), &dvab
, &dvba
);
128 *a_minus_b
= SOSManifestCreateWithDigestVector(&dvab
, error
);
133 *b_minus_a
= SOSManifestCreateWithDigestVector(&dvba
, error
);
137 SOSDigestVectorFree(&dvab
);
138 SOSDigestVectorFree(&dvba
);
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
);
150 SOSManifestRef
SOSManifestCreateWithPatch(SOSManifestRef base
,
151 SOSManifestRef removals
,
152 SOSManifestRef additions
,
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
);
162 SOSDigestVectorFree(&dvresult
);
166 // This is the set of elements in m2, but not in m1.
167 SOSManifestRef
SOSManifestCreateComplement(SOSManifestRef m1
,
170 // m2 \ emptySet => m2
171 if (SOSManifestGetCount(m1
) == 0) {
172 //secnotice("manifest", "complement = m2");
173 return m2
? CFRetainSafe(m2
) : SOSManifestCreateWithBytes(NULL
, 0, error
);
176 struct SOSDigestVector dvresult
= SOSDigestVectorInit
;
177 SOSManifestRef result
;
178 SOSDigestVectorComplementSorted(SOSManifestGetDigestVector(m1
), SOSManifestGetDigestVector(m2
), &dvresult
);
179 result
= SOSManifestCreateWithDigestVector(&dvresult
, error
);
180 SOSDigestVectorFree(&dvresult
);
184 SOSManifestRef
SOSManifestCreateIntersection(SOSManifestRef m1
,
187 struct SOSDigestVector dvresult
= SOSDigestVectorInit
;
188 SOSManifestRef result
;
189 SOSDigestVectorIntersectSorted(SOSManifestGetDigestVector(m1
), SOSManifestGetDigestVector(m2
), &dvresult
);
190 result
= SOSManifestCreateWithDigestVector(&dvresult
, error
);
191 SOSDigestVectorFree(&dvresult
);
195 SOSManifestRef
SOSManifestCreateUnion(SOSManifestRef m1
,
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
);
205 struct SOSDigestVector dvresult
= SOSDigestVectorInit
;
206 SOSManifestRef result
;
207 SOSDigestVectorUnionSorted(SOSManifestGetDigestVector(m1
), SOSManifestGetDigestVector(m2
), &dvresult
);
208 result
= SOSManifestCreateWithDigestVector(&dvresult
, error
);
209 SOSDigestVectorFree(&dvresult
);
214 void SOSManifestForEach(SOSManifestRef m
, void(^block
)(CFDataRef e
, bool *stop
)) {
216 const uint8_t *p
, *q
;
218 for (p
= SOSManifestGetBytePtr(m
), q
= p
+ SOSManifestGetSize(m
);
219 !stop
&& p
+ SOSDigestSize
<= q
; p
+= SOSDigestSize
) {
220 e
= CFDataCreateWithBytesNoCopy(0, p
, SOSDigestSize
, kCFAllocatorNull
);
228 CFDataRef
SOSManifestGetDigest(SOSManifestRef m
, CFErrorRef
*error
) {
231 m
->digest
= CFDataCreateSHA1DigestWithBytes(kCFAllocatorDefault
, SOSManifestGetSize(m
), SOSManifestGetBytePtr(m
), error
);
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]);
242 CFStringAppendFormat(desc
, NULL
, CFSTR("<[%zu]"), SOSManifestGetCount(mf
));
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]);
249 CFStringAppend(desc
, CFSTR("..."));
253 CFStringAppend(desc
, CFSTR(">"));