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 <SecureObjectSync/SOSManifest.h>
30 #include <SecureObjectSync/SOSDigestVector.h>
31 #include <utilities/SecCFError.h>
32 #include <utilities/SecCFWrappers.h>
34 #include <securityd/SecDbKeychainItem.h> // for kc_copy_sha1, which needs to move to utilities
36 CFStringRef kSOSManifestErrorDomain
= CFSTR("com.apple.security.sos.manifest.error");
38 /* SOSManifest implementation. */
39 struct __OpaqueSOSManifest
{
42 CFDataRef digestVector
;
43 struct SOSDigestVector dv
;
46 CFGiblisWithCompareFor(SOSManifest
)
48 static void SOSManifestDestroy(CFTypeRef cf
) {
49 SOSManifestRef mf
= (SOSManifestRef
)cf
;
50 CFReleaseSafe(mf
->digest
);
51 CFReleaseSafe(mf
->digestVector
);
54 static 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
));
60 SOSManifestRef
SOSManifestCreateWithData(CFDataRef data
, CFErrorRef
*error
)
62 SOSManifestRef manifest
= CFTypeAllocate(SOSManifest
, struct __OpaqueSOSManifest
, kCFAllocatorDefault
);
64 SecCFCreateErrorWithFormat(kSOSManifestCreateError
, kSOSManifestErrorDomain
, NULL
, error
, NULL
, CFSTR("Failed to create manifest"));
66 manifest
->digestVector
= CFDataCreateCopy(kCFAllocatorDefault
, data
);
68 manifest
->digestVector
= CFDataCreate(kCFAllocatorDefault
, NULL
, 0);
70 assert(!manifest
|| manifest
->digestVector
!= NULL
);
74 SOSManifestRef
SOSManifestCreateWithBytes(const uint8_t *bytes
, size_t len
,
76 CFDataRef data
= CFDataCreate(kCFAllocatorDefault
, bytes
, (CFIndex
)len
);
77 SOSManifestRef manifest
= SOSManifestCreateWithData(data
, error
);
82 size_t SOSManifestGetSize(SOSManifestRef m
) {
83 return m
? (size_t)CFDataGetLength(m
->digestVector
) : 0;
86 size_t SOSManifestGetCount(SOSManifestRef m
) {
87 return m
? SOSManifestGetSize(m
) / SOSDigestSize
: 0;
90 const uint8_t *SOSManifestGetBytePtr(SOSManifestRef m
) {
91 return m
? CFDataGetBytePtr(m
->digestVector
) : NULL
;
94 CFDataRef
SOSManifestGetData(SOSManifestRef m
) {
95 return m
? m
->digestVector
: NULL
;
98 const struct SOSDigestVector
*SOSManifestGetDigestVector(SOSManifestRef manifest
) {
100 static struct SOSDigestVector nulldv
= SOSDigestVectorInit
;
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
;
109 bool SOSManifestDiff(SOSManifestRef a
, SOSManifestRef b
,
110 SOSManifestRef
*a_minus_b
, SOSManifestRef
*b_minus_a
,
113 struct SOSDigestVector dvab
= SOSDigestVectorInit
, dvba
= SOSDigestVectorInit
;
114 SOSDigestVectorDiffSorted(SOSManifestGetDigestVector(a
), SOSManifestGetDigestVector(b
), &dvab
, &dvba
);
116 *a_minus_b
= SOSManifestCreateWithDigestVector(&dvab
, error
);
121 *b_minus_a
= SOSManifestCreateWithDigestVector(&dvba
, error
);
125 SOSDigestVectorFree(&dvab
);
126 SOSDigestVectorFree(&dvba
);
131 SOSManifestRef
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
);
137 SOSManifestRef
SOSManifestCreateWithPatch(SOSManifestRef base
,
138 SOSManifestRef removals
,
139 SOSManifestRef additions
,
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
);
149 SOSDigestVectorFree(&dvresult
);
153 // This is the set of elements in m2, but not in m1.
154 SOSManifestRef
SOSManifestCreateComplement(SOSManifestRef m1
,
157 // m2 \ emptySet => m2
158 if (SOSManifestGetCount(m1
) == 0)
159 return CFRetainSafe(m2
);
161 struct SOSDigestVector dvresult
= SOSDigestVectorInit
;
162 SOSManifestRef result
;
163 SOSDigestVectorComplementSorted(SOSManifestGetDigestVector(m1
), SOSManifestGetDigestVector(m2
), &dvresult
);
164 result
= SOSManifestCreateWithDigestVector(&dvresult
, error
);
165 SOSDigestVectorFree(&dvresult
);
169 SOSManifestRef
SOSManifestCreateIntersection(SOSManifestRef m1
,
172 struct SOSDigestVector dvresult
= SOSDigestVectorInit
;
173 SOSManifestRef result
;
174 SOSDigestVectorIntersectSorted(SOSManifestGetDigestVector(m1
), SOSManifestGetDigestVector(m2
), &dvresult
);
175 result
= SOSManifestCreateWithDigestVector(&dvresult
, error
);
176 SOSDigestVectorFree(&dvresult
);
180 SOSManifestRef
SOSManifestCreateUnion(SOSManifestRef m1
,
183 struct SOSDigestVector dvresult
= SOSDigestVectorInit
;
184 SOSManifestRef result
;
185 SOSDigestVectorUnionSorted(SOSManifestGetDigestVector(m1
), SOSManifestGetDigestVector(m2
), &dvresult
);
186 result
= SOSManifestCreateWithDigestVector(&dvresult
, error
);
187 SOSDigestVectorFree(&dvresult
);
191 void SOSManifestForEach(SOSManifestRef m
, void(^block
)(CFDataRef e
, bool *stop
)) {
193 const uint8_t *p
, *q
;
195 for (p
= SOSManifestGetBytePtr(m
), q
= p
+ SOSManifestGetSize(m
);
196 !stop
&& p
+ SOSDigestSize
<= q
; p
+= SOSDigestSize
) {
197 e
= CFDataCreateWithBytesNoCopy(0, p
, SOSDigestSize
, kCFAllocatorNull
);
205 CFDataRef
SOSManifestGetDigest(SOSManifestRef m
, CFErrorRef
*error
) {
208 m
->digest
= kc_copy_sha1(SOSManifestGetSize(m
), SOSManifestGetBytePtr(m
), error
);
212 static 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]);
221 CFStringAppend(desc
, CFSTR("..."));
225 CFStringAppend(desc
, CFSTR(">"));