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
) *a_minus_b
= empty
;
116 if (b_minus_a
) *b_minus_a
= CFRetainSafe(b
? b
: empty
);
117 } else if (SOSManifestGetCount(b
) == 0) {
118 //secnotice("manifest", "diff = a");
119 SOSManifestRef empty
= SOSManifestCreateWithBytes(NULL
, 0, error
);
120 if (a_minus_b
) *a_minus_b
= CFRetainSafe(a
? a
: empty
);
121 if (b_minus_a
) *b_minus_a
= empty
;
123 struct SOSDigestVector dvab
= SOSDigestVectorInit
, dvba
= SOSDigestVectorInit
;
124 SOSDigestVectorDiffSorted(SOSManifestGetDigestVector(a
), SOSManifestGetDigestVector(b
), &dvab
, &dvba
);
126 *a_minus_b
= SOSManifestCreateWithDigestVector(&dvab
, error
);
131 *b_minus_a
= SOSManifestCreateWithDigestVector(&dvba
, error
);
135 SOSDigestVectorFree(&dvab
);
136 SOSDigestVectorFree(&dvba
);
142 SOSManifestRef
SOSManifestCreateWithDigestVector(struct SOSDigestVector
*dv
, CFErrorRef
*error
) {
143 if (!dv
) return NULL
;
144 if (dv
->unsorted
) SOSDigestVectorSort(dv
);
145 return SOSManifestCreateWithBytes((const uint8_t *)dv
->digest
, dv
->count
* SOSDigestSize
, error
);
148 SOSManifestRef
SOSManifestCreateWithPatch(SOSManifestRef base
,
149 SOSManifestRef removals
,
150 SOSManifestRef additions
,
152 struct SOSDigestVector dvresult
= SOSDigestVectorInit
;
153 SOSManifestRef result
;
154 if (SOSDigestVectorPatchSorted(SOSManifestGetDigestVector(base
), SOSManifestGetDigestVector(removals
),
155 SOSManifestGetDigestVector(additions
), &dvresult
, error
)) {
156 result
= SOSManifestCreateWithDigestVector(&dvresult
, error
);
160 SOSDigestVectorFree(&dvresult
);
164 // This is the set of elements in m2, but not in m1.
165 SOSManifestRef
SOSManifestCreateComplement(SOSManifestRef m1
,
168 // m2 \ emptySet => m2
169 if (SOSManifestGetCount(m1
) == 0) {
170 //secnotice("manifest", "complement = m2");
171 return m2
? CFRetainSafe(m2
) : SOSManifestCreateWithBytes(NULL
, 0, error
);
174 struct SOSDigestVector dvresult
= SOSDigestVectorInit
;
175 SOSManifestRef result
;
176 SOSDigestVectorComplementSorted(SOSManifestGetDigestVector(m1
), SOSManifestGetDigestVector(m2
), &dvresult
);
177 result
= SOSManifestCreateWithDigestVector(&dvresult
, error
);
178 SOSDigestVectorFree(&dvresult
);
182 SOSManifestRef
SOSManifestCreateIntersection(SOSManifestRef m1
,
185 struct SOSDigestVector dvresult
= SOSDigestVectorInit
;
186 SOSManifestRef result
;
187 SOSDigestVectorIntersectSorted(SOSManifestGetDigestVector(m1
), SOSManifestGetDigestVector(m2
), &dvresult
);
188 result
= SOSManifestCreateWithDigestVector(&dvresult
, error
);
189 SOSDigestVectorFree(&dvresult
);
193 SOSManifestRef
SOSManifestCreateUnion(SOSManifestRef m1
,
196 if (SOSManifestGetCount(m1
) == 0) {
197 //secnotice("manifest", "union = m2");
198 return m2
? CFRetainSafe(m2
) : SOSManifestCreateWithBytes(NULL
, 0, error
);
199 } else if (SOSManifestGetCount(m2
) == 0) {
200 //secnotice("manifest", "union = m1");
201 return m1
? CFRetainSafe(m1
) : SOSManifestCreateWithBytes(NULL
, 0, error
);
203 struct SOSDigestVector dvresult
= SOSDigestVectorInit
;
204 SOSManifestRef result
;
205 SOSDigestVectorUnionSorted(SOSManifestGetDigestVector(m1
), SOSManifestGetDigestVector(m2
), &dvresult
);
206 result
= SOSManifestCreateWithDigestVector(&dvresult
, error
);
207 SOSDigestVectorFree(&dvresult
);
212 void SOSManifestForEach(SOSManifestRef m
, void(^block
)(CFDataRef e
, bool *stop
)) {
214 const uint8_t *p
, *q
;
216 for (p
= SOSManifestGetBytePtr(m
), q
= p
+ SOSManifestGetSize(m
);
217 !stop
&& p
+ SOSDigestSize
<= q
; p
+= SOSDigestSize
) {
218 e
= CFDataCreateWithBytesNoCopy(0, p
, SOSDigestSize
, kCFAllocatorNull
);
226 CFDataRef
SOSManifestGetDigest(SOSManifestRef m
, CFErrorRef
*error
) {
229 m
->digest
= CFDataCreateSHA1DigestWithBytes(kCFAllocatorDefault
, SOSManifestGetSize(m
), SOSManifestGetBytePtr(m
), error
);
233 static CFStringRef
SOSManifestCopyFormatDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
234 SOSManifestRef mf
= (SOSManifestRef
)cf
;
235 CFMutableStringRef desc
= CFStringCreateMutable(0, 0);
236 if (SOSManifestGetCount(mf
) >= 8) {
237 const uint8_t *m
= CFDataGetBytePtr(SOSManifestGetDigest(mf
, NULL
));
238 CFStringAppendFormat(desc
, NULL
, CFSTR("<[%zu:%02X%02X%02X%02X]"), SOSManifestGetCount(mf
), m
[0], m
[1], m
[2], m
[3]);
240 CFStringAppendFormat(desc
, NULL
, CFSTR("<[%zu]"), SOSManifestGetCount(mf
));
242 __block
size_t maxEntries
= 8;
243 SOSManifestForEach(mf
, ^(CFDataRef e
, bool *stop
) {
244 const uint8_t *d
= CFDataGetBytePtr(e
);
245 CFStringAppendFormat(desc
, NULL
, CFSTR(" %02X%02X%02X%02X"), d
[0], d
[1], d
[2], d
[3]);
247 CFStringAppend(desc
, CFSTR("..."));
251 CFStringAppend(desc
, CFSTR(">"));