2 * Created by Michael Brouwer on 2/14/12.
3 * Copyright 2012 Apple Inc. All Rights Reserved.
7 * SOSTransport.c - Implementation of the secure object syncing transport
10 #include <SecureObjectSync/SOSTransport.h>
11 #include <utilities/SecCFError.h>
12 #include <utilities/SecCFWrappers.h>
13 #include <dispatch/dispatch.h>
16 static CFStringRef sErrorDomain
= CFSTR("com.apple.security.sos.transport.error");
18 /* SOSDigestVector code. */
20 #define VECTOR_GROW(vector, count, capacity) \
22 if ((count) > capacity) { \
23 capacity = ((capacity) + 16) * 3 / 2; \
24 if (capacity < (count)) \
26 vector = realloc((vector), sizeof(*(vector)) * capacity); \
30 static void SOSDigestVectorEnsureCapacity(struct SOSDigestVector
*dv
, size_t count
) {
31 VECTOR_GROW(dv
->digest
, count
, dv
->capacity
);
34 void SOSDigestVectorReplaceAtIndex(struct SOSDigestVector
*dv
, size_t ix
, const uint8_t *digest
)
36 SOSDigestVectorEnsureCapacity(dv
, ix
+ 1);
37 memcpy(dv
->digest
[ix
], digest
, SOSDigestSize
);
38 dv
->is_sorted
= false;
41 static void SOSDigestVectorAppendOrdered(struct SOSDigestVector
*dv
, const uint8_t *digest
)
43 SOSDigestVectorEnsureCapacity(dv
, dv
->count
+ 1);
44 memcpy(dv
->digest
[dv
->count
++], digest
, SOSDigestSize
);
47 void SOSDigestVectorAppend(struct SOSDigestVector
*dv
, const uint8_t *digest
)
49 SOSDigestVectorAppendOrdered(dv
, digest
);
50 dv
->is_sorted
= false;
53 static int SOSDigestCompare(const void *a
, const void *b
)
55 return memcmp(a
, b
, SOSDigestSize
);
58 void SOSDigestVectorSort(struct SOSDigestVector
*dv
)
60 qsort(dv
->digest
, dv
->count
, sizeof(*dv
->digest
), SOSDigestCompare
);
64 bool SOSDigestVectorContains(struct SOSDigestVector
*dv
, const uint8_t *digest
)
66 return SOSDigestVectorIndexOf(dv
, digest
) != (size_t)-1;
69 size_t SOSDigestVectorIndexOf(struct SOSDigestVector
*dv
, const uint8_t *digest
)
72 SOSDigestVectorSort(dv
);
73 const void *pos
= bsearch(digest
, dv
->digest
, dv
->count
, sizeof(*dv
->digest
), SOSDigestCompare
);
74 return pos
? ((size_t)(pos
- (void *)dv
->digest
)) / SOSDigestSize
: ((size_t)-1);
77 void SOSDigestVectorFree(struct SOSDigestVector
*dv
)
83 dv
->is_sorted
= false;
86 void SOSDigestVectorApply(struct SOSDigestVector
*dv
,
87 void *context
, SOSDigestVectorApplyFunc func
)
90 SOSDigestVectorSort(dv
);
92 for (size_t ix
= 0; ix
< dv
->count
; ++ix
) {
93 func(context
, dv
->digest
[ix
]);
97 static void SOSDigestVectorAppendMultiple(struct SOSDigestVector
*dv
,
98 size_t count
, const uint8_t *digests
) {
100 SOSDigestVectorEnsureCapacity(dv
, dv
->count
+ count
);
101 memcpy(dv
->digest
[dv
->count
], digests
, count
* SOSDigestSize
);
106 void SOSDigestVectorDiff(struct SOSDigestVector
*dv1
, struct SOSDigestVector
*dv2
,
107 struct SOSDigestVector
*dv1_2
, struct SOSDigestVector
*dv2_1
)
109 /* dv1_2 and dv2_1 should be empty to start. */
110 assert(dv1_2
->count
== 0);
111 assert(dv2_1
->count
== 0);
114 SOSDigestVectorSort(dv1
);
116 SOSDigestVectorSort(dv2
);
118 size_t i1
= 0, i2
= 0;
119 while (i1
< dv1
->count
&& i2
< dv2
->count
) {
120 int delta
= SOSDigestCompare(dv1
->digest
[i1
], dv2
->digest
[i2
]);
123 } else if (delta
< 0) {
124 SOSDigestVectorAppendOrdered(dv1_2
, dv1
->digest
[i1
++]);
126 SOSDigestVectorAppendOrdered(dv2_1
, dv2
->digest
[i2
++]);
129 SOSDigestVectorAppendMultiple(dv1_2
, dv1
->count
- i1
, dv1
->digest
[i1
]);
130 SOSDigestVectorAppendMultiple(dv2_1
, dv2
->count
- i2
, dv2
->digest
[i2
]);
132 dv1_2
->is_sorted
= true;
133 dv2_1
->is_sorted
= true;
136 bool SOSDigestVectorPatch(struct SOSDigestVector
*base
, struct SOSDigestVector
*removals
,
137 struct SOSDigestVector
*additions
, struct SOSDigestVector
*dv
,
140 size_t base_ix
= 0, removals_ix
= 0, additions_ix
= 0;
141 if (!base
->is_sorted
)
142 SOSDigestVectorSort(base
);
143 if (!removals
->is_sorted
)
144 SOSDigestVectorSort(removals
);
145 if (!additions
->is_sorted
)
146 SOSDigestVectorSort(additions
);
148 assert(dv
->count
== 0);
149 SOSDigestVectorEnsureCapacity(dv
, base
->count
- removals
->count
+ additions
->count
);
150 dv
->is_sorted
= true;
152 while (base_ix
< base
->count
) {
153 const uint8_t *d
= base
->digest
[base_ix
];
154 if (additions_ix
< additions
->count
&& SOSDigestCompare(d
, additions
->digest
[additions_ix
]) > 0) {
155 SOSDigestVectorAppendOrdered(dv
, additions
->digest
[additions_ix
++]);
156 } else if (removals_ix
< removals
->count
&& SOSDigestCompare(d
, removals
->digest
[removals_ix
]) == 0) {
160 SOSDigestVectorAppendOrdered(dv
, base
->digest
[base_ix
++]);
164 if (removals_ix
!= removals
->count
) {
165 SecCFCreateErrorWithFormat(1, sErrorDomain
, NULL
, error
, NULL
, CFSTR("%lu extra removals left"), removals
->count
- removals_ix
);
169 while (additions_ix
< additions
->count
) {
170 if (dv
->count
> 0 && SOSDigestCompare(dv
->digest
[dv
->count
- 1], additions
->digest
[additions_ix
]) >= 0) {
171 SecCFCreateErrorWithFormat(1, sErrorDomain
, NULL
, error
, NULL
, CFSTR("unordered addition (%lu left)"), additions
->count
- additions_ix
);
174 SOSDigestVectorAppendOrdered(dv
, additions
->digest
[additions_ix
++]);
184 /* SOSManifest implementation. */
185 struct __OpaqueSOSManifest
{
188 SOSManifestRef
SOSManifestCreateWithBytes(const uint8_t *bytes
, size_t len
,
190 SOSManifestRef manifest
= (SOSManifestRef
)CFDataCreate(NULL
, bytes
, (CFIndex
)len
);
192 SecCFCreateErrorWithFormat(kSOSManifestCreateError
, sErrorDomain
, NULL
, error
, NULL
, CFSTR("Failed to create manifest"));
197 SOSManifestRef
SOSManifestCreateWithData(CFDataRef data
, CFErrorRef
*error
)
199 SOSManifestRef manifest
= NULL
;
202 manifest
= (SOSManifestRef
)CFDataCreateCopy(kCFAllocatorDefault
, data
);
204 manifest
= (SOSManifestRef
)CFDataCreate(kCFAllocatorDefault
, NULL
, 0);
207 SecCFCreateErrorWithFormat(kSOSManifestCreateError
, sErrorDomain
, NULL
, error
, NULL
, CFSTR("Failed to create manifest"));
212 void SOSManifestDispose(SOSManifestRef m
) {
216 size_t SOSManifestGetSize(SOSManifestRef m
) {
217 return (size_t)CFDataGetLength((CFDataRef
)m
);
220 size_t SOSManifestGetCount(SOSManifestRef m
) {
221 return SOSManifestGetSize(m
) / SOSDigestSize
;
224 const uint8_t *SOSManifestGetBytePtr(SOSManifestRef m
) {
225 return CFDataGetBytePtr((CFDataRef
)m
);
228 CFDataRef
SOSManifestGetData(SOSManifestRef m
) {
233 bool SOSManifestDiff(SOSManifestRef a
, SOSManifestRef b
,
234 SOSManifestRef
*a_minus_b
, SOSManifestRef
*b_minus_a
,
237 struct SOSDigestVector dva
= SOSDigestVectorInit
,
238 dvb
= SOSDigestVectorInit
,
239 dvab
= SOSDigestVectorInit
,
240 dvba
= SOSDigestVectorInit
;
241 SOSDigestVectorAppendMultiple(&dva
, SOSManifestGetCount(a
), SOSManifestGetBytePtr(a
));
242 SOSDigestVectorAppendMultiple(&dvb
, SOSManifestGetCount(b
), SOSManifestGetBytePtr(b
));
243 SOSDigestVectorDiff(&dva
, &dvb
, &dvab
, &dvba
);
244 SOSDigestVectorFree(&dva
);
245 SOSDigestVectorFree(&dvb
);
248 *a_minus_b
= SOSManifestCreateWithBytes((const uint8_t *)dvab
.digest
, dvab
.count
* SOSDigestSize
, error
);
254 *b_minus_a
= SOSManifestCreateWithBytes((const uint8_t *)dvba
.digest
, dvba
.count
* SOSDigestSize
, error
);
259 SOSDigestVectorFree(&dvab
);
260 SOSDigestVectorFree(&dvba
);
265 SOSManifestRef
SOSManifestCreateWithPatch(SOSManifestRef base
,
266 SOSManifestRef removals
,
267 SOSManifestRef additions
,
269 struct SOSDigestVector dvbase
= SOSDigestVectorInit
,
270 dvresult
= SOSDigestVectorInit
,
271 dvremovals
= SOSDigestVectorInit
,
272 dvadditions
= SOSDigestVectorInit
;
273 dvbase
.is_sorted
= dvresult
.is_sorted
= dvremovals
.is_sorted
= dvadditions
.is_sorted
= true;
274 SOSDigestVectorAppendMultiple(&dvbase
, SOSManifestGetCount(base
), SOSManifestGetBytePtr(base
));
275 SOSDigestVectorAppendMultiple(&dvremovals
, SOSManifestGetCount(removals
), SOSManifestGetBytePtr(removals
));
276 SOSDigestVectorAppendMultiple(&dvadditions
, SOSManifestGetCount(additions
), SOSManifestGetBytePtr(additions
));
277 SOSManifestRef result
;
278 if (SOSDigestVectorPatch(&dvbase
, &dvremovals
, &dvadditions
, &dvresult
, error
)) {
279 result
= SOSManifestCreateWithBytes((const uint8_t *)dvresult
.digest
, dvresult
.count
* SOSDigestSize
, error
);
283 SOSDigestVectorFree(&dvbase
);
284 SOSDigestVectorFree(&dvresult
);
285 SOSDigestVectorFree(&dvremovals
);
286 SOSDigestVectorFree(&dvadditions
);
290 void SOSManifestForEach(SOSManifestRef m
, void(^block
)(CFDataRef e
)) {
292 const uint8_t *p
, *q
;
293 for (p
= SOSManifestGetBytePtr(m
), q
= p
+ SOSManifestGetSize(m
);
294 p
+ SOSDigestSize
<= q
; p
+= SOSDigestSize
) {
295 e
= CFDataCreateWithBytesNoCopy(0, p
, SOSDigestSize
, kCFAllocatorNull
);
303 CFStringRef
SOSManifestCopyDescription(SOSManifestRef m
) {
304 CFMutableStringRef desc
= CFStringCreateMutable(0, 0);
305 CFStringAppend(desc
, CFSTR("<Manifest"));
306 SOSManifestForEach(m
, ^(CFDataRef e
) {
307 CFStringAppend(desc
, CFSTR(" "));
308 const uint8_t *d
= CFDataGetBytePtr(e
);
309 CFStringAppendFormat(desc
, 0, CFSTR("%02X%02X%02X%02X"), d
[0], d
[1], d
[2], d
[3]);
311 CFStringAppend(desc
, CFSTR(">"));
317 SOSObjectRef
SOSManifestGetObject(SOSManifestRef m
, SOSObjectID k
) {
321 void SOSManifestPutObject(SOSManifestRef m
, SOSObjectID k
, SOSObjectRef v
) {
326 SOSManifestRef
SOSManifestCreateSparse(void *get_ctx
, SOSManifestGetF get_f
) {