]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoCollections.c
Security-57337.20.44.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSPeerInfoCollections.c
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 #include <Security/SecureObjectSync/SOSPeerInfoCollections.h>
26
27 #include <CoreFoundation/CoreFoundation.h>
28 #include <utilities/SecCFWrappers.h>
29 #include <utilities/SecCFError.h>
30 #include <utilities/SecXPCError.h>
31 #include <corecrypto/ccder.h>
32 #include <Security/SecureObjectSync/SOSInternal.h>
33 #include <AssertMacros.h>
34 #include <SOSPeerInfoDER.h>
35
36 //
37 // PeerInfoSetby ID handling
38 //
39
40 //
41 //
42 // CFSetRetainCallback
43 //
44
45 static CFStringRef GetIDOrString(const void *object) {
46 return isSOSPeerInfo(object) ?
47 SOSPeerInfoGetPeerID((SOSPeerInfoRef)object) :
48 (isString(object) ? (CFStringRef) object : NULL);
49 }
50
51 static Boolean SOSPeerInfoIDEqual(const void *value1, const void *value2)
52 {
53 return CFEqualSafe(GetIDOrString(value1), GetIDOrString(value2));
54 }
55
56 static CFHashCode SOSPeerInfoIDHash(const void *value)
57 {
58 return CFHash(GetIDOrString(value));
59 }
60
61 bool SOSPeerInfoSetContainsIdenticalPeers(CFSetRef set1, CFSetRef set2){
62
63 __block bool result = true;
64
65 if(!CFEqualSafe(set1, set2))
66 return false;
67
68 CFSetForEach(set1, ^(const void *value) {
69 SOSPeerInfoRef peer1 = (SOSPeerInfoRef)value;
70 SOSPeerInfoRef peer2 = (SOSPeerInfoRef)CFSetGetValue(set2, peer1);
71 result &= CFEqualSafe(peer1, peer2);
72 });
73 return result;
74 }
75 const CFSetCallBacks kSOSPeerSetCallbacks = {0, SecCFRetainForCollection, SecCFReleaseForCollection, CFCopyDescription, SOSPeerInfoIDEqual, SOSPeerInfoIDHash};
76
77 CFMutableSetRef CFSetCreateMutableForSOSPeerInfosByID(CFAllocatorRef allocator)
78 {
79 return CFSetCreateMutable(allocator, 0, &kSOSPeerSetCallbacks);
80 }
81
82 CFMutableSetRef CFSetCreateMutableForSOSPeerInfosByIDWithArray(CFAllocatorRef allocator, CFArrayRef peerInfos)
83 {
84 CFMutableSetRef newSet = CFSetCreateMutableForSOSPeerInfosByID(allocator);
85
86 CFArrayForEach(peerInfos, ^(const void *value) {
87 SOSPeerInfoRef peer = asSOSPeerInfo(value);
88 if (peer) {
89 CFSetAddValue(newSet, peer);
90 }
91 });
92
93 return newSet;
94 }
95
96 SOSPeerInfoRef SOSPeerInfoSetFindByID(CFSetRef set, CFStringRef id) {
97 return (SOSPeerInfoRef) CFSetGetValue(set, id);
98 }
99
100 //
101 // CFArray of Peer Info handling
102 //
103
104 void CFArrayOfSOSPeerInfosSortByID(CFMutableArrayRef peerInfoArray)
105 {
106 CFArraySortValues(peerInfoArray, CFRangeMake(0, CFArrayGetCount(peerInfoArray)), SOSPeerInfoCompareByID, NULL);
107 }
108
109
110 //
111 // PeerInfoArray encoding decoding
112 //
113
114 CFMutableArrayRef SOSPeerInfoArrayCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error,
115 const uint8_t** der_p, const uint8_t *der_end) {
116 CFMutableArrayRef pia = CFArrayCreateMutableForCFTypes(allocator);
117
118 const uint8_t *sequence_end;
119
120 *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
121
122 require_action(*der_p, fail, SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Peer Info Array Sequence Header"), NULL, error));
123
124 while (sequence_end != *der_p) {
125 SOSPeerInfoRef pi = SOSPeerInfoCreateFromDER(allocator, error, der_p, sequence_end);
126
127 if (pi == NULL || *der_p == NULL) {
128 SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Peer Info Array DER"), (error != NULL ? *error : NULL), error);
129 CFReleaseNull(pi);
130 goto fail;
131 }
132
133 CFArrayAppendValue(pia, pi);
134 CFReleaseSafe(pi);
135 }
136
137 if (!pia)
138 *der_p = NULL;
139 return pia;
140
141 fail:
142 CFReleaseNull(pia);
143 *der_p = NULL;
144 return NULL;
145 }
146
147 size_t SOSPeerInfoArrayGetDEREncodedSize(CFArrayRef pia, CFErrorRef *error) {
148 __block size_t array_size = 0;
149 __block bool fail = false;
150
151 CFArrayForEach(pia, ^(const void *value) {
152 if (isSOSPeerInfo(value)) {
153 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
154 size_t pi_size = SOSPeerInfoGetDEREncodedSize(pi, error);
155
156 fail = (pi_size == 0);
157 array_size += pi_size;
158 } else {
159 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Non SOSPeerInfo in array"), (error != NULL ? *error : NULL), error);
160 fail = true;
161 }
162 });
163
164 return fail ? 0 : ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, array_size);
165 }
166
167 uint8_t* SOSPeerInfoArrayEncodeToDER(CFArrayRef pia, CFErrorRef* error, const uint8_t* der, uint8_t* der_end_param) {
168
169 uint8_t* const sequence_end = der_end_param;
170 __block uint8_t* der_end = der_end_param;
171
172 CFArrayForEachReverse(pia, ^(const void *value) {
173 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
174 if (CFGetTypeID(pi) != SOSPeerInfoGetTypeID()) {
175 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Non SOSPeerInfo in array"), NULL, error);
176 der_end = NULL; // Indicate error and continue.
177 }
178 if (der_end)
179 der_end = SOSPeerInfoEncodeToDER(pi, error, der, der_end);
180 });
181
182 if (der_end == NULL)
183 return NULL;
184
185 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, sequence_end, der, der_end);
186 }
187
188
189 CFMutableSetRef SOSPeerInfoSetCreateFromArrayDER(CFAllocatorRef allocator, const CFSetCallBacks *callbacks, CFErrorRef* error,
190 const uint8_t** der_p, const uint8_t *der_end) {
191 CFMutableSetRef result = NULL;
192
193 CFArrayRef peers = SOSPeerInfoArrayCreateFromDER(allocator, error, der_p, der_end);
194
195 if (peers) {
196 result = CFSetCreateMutable(allocator, 0, callbacks);
197 CFSetSetValues(result, peers);
198 }
199
200 CFReleaseNull(peers);
201 return result;
202 }
203
204 size_t SOSPeerInfoSetGetDEREncodedArraySize(CFSetRef pia, CFErrorRef *error) {
205 __block size_t array_size = 0;
206 __block bool fail = false;
207
208 CFSetForEach(pia, ^(const void *value) {
209 if (isSOSPeerInfo(value)) {
210 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
211 size_t pi_size = SOSPeerInfoGetDEREncodedSize(pi, error);
212
213 fail = (pi_size == 0);
214 array_size += pi_size;
215 } else {
216 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Non SOSPeerInfo in array"), (error != NULL ? *error : NULL), error);
217 fail = true;
218 }
219 });
220
221 return fail ? 0 : ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, array_size);
222 }
223
224 uint8_t* SOSPeerInfoSetEncodeToArrayDER(CFSetRef pis, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) {
225 CFMutableArrayRef pia = CFSetCopyValues(pis);
226
227 CFArrayOfSOSPeerInfosSortByID(pia);
228
229 uint8_t* result = SOSPeerInfoArrayEncodeToDER(pia, error, der, der_end);
230
231 CFReleaseNull(pia);
232
233 return result;
234 }
235
236
237
238 CFArrayRef CreateArrayOfPeerInfoWithXPCObject(xpc_object_t peerArray, CFErrorRef* error) {
239 if (!peerArray) {
240 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedNull, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("Unexpected Null Array to encode"));
241 return NULL;
242 }
243
244 if (xpc_get_type(peerArray) != XPC_TYPE_DATA) {
245 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("Array of peer info not array, got %@"), peerArray);
246 return NULL;
247 }
248
249 const uint8_t* der = xpc_data_get_bytes_ptr(peerArray);
250 const uint8_t* der_end = der + xpc_data_get_length(peerArray);
251
252 return SOSPeerInfoArrayCreateFromDER(kCFAllocatorDefault, error, &der, der_end);
253 }
254
255 xpc_object_t CreateXPCObjectWithArrayOfPeerInfo(CFArrayRef array, CFErrorRef *error) {
256 size_t data_size = SOSPeerInfoArrayGetDEREncodedSize(array, error);
257 if (data_size == 0)
258 return NULL;
259 uint8_t *data = (uint8_t *)malloc(data_size);
260 if (!data) return NULL;
261
262 xpc_object_t result = NULL;
263 if (SOSPeerInfoArrayEncodeToDER(array, error, data, data + data_size))
264 result = xpc_data_create(data, data_size);
265
266 free(data);
267 return result;
268 }