]> git.saurik.com Git - apple/security.git/blob - OSX/sec/ProjectHeaders/Security/SecureObjectSync/SOSPeerInfoCollections.c
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / sec / ProjectHeaders / Security / 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 SOSPeerInfoRef SOSPeerInfoSetFindByID(CFSetRef set, CFStringRef id) {
83 return (SOSPeerInfoRef) CFSetGetValue(set, id);
84 }
85
86 //
87 // CFArray of Peer Info handling
88 //
89
90 void CFArrayOfSOSPeerInfosSortByID(CFMutableArrayRef peerInfoArray)
91 {
92 CFArraySortValues(peerInfoArray, CFRangeMake(0, CFArrayGetCount(peerInfoArray)), SOSPeerInfoCompareByID, NULL);
93 }
94
95
96 //
97 // PeerInfoArray encoding decoding
98 //
99
100 CFMutableArrayRef SOSPeerInfoArrayCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error,
101 const uint8_t** der_p, const uint8_t *der_end) {
102 CFMutableArrayRef pia = CFArrayCreateMutableForCFTypes(allocator);
103
104 const uint8_t *sequence_end;
105
106 *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
107
108 require_action(*der_p, fail, SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Peer Info Array Sequence Header"), NULL, error));
109
110 while (sequence_end != *der_p) {
111 SOSPeerInfoRef pi = SOSPeerInfoCreateFromDER(allocator, error, der_p, sequence_end);
112
113 if (pi == NULL || *der_p == NULL) {
114 SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Peer Info Array DER"), (error != NULL ? *error : NULL), error);
115 CFReleaseNull(pi);
116 goto fail;
117 }
118
119 CFArrayAppendValue(pia, pi);
120 CFReleaseSafe(pi);
121 }
122
123 if (!pia)
124 *der_p = NULL;
125 return pia;
126
127 fail:
128 CFReleaseNull(pia);
129 *der_p = NULL;
130 return NULL;
131 }
132
133 size_t SOSPeerInfoArrayGetDEREncodedSize(CFArrayRef pia, CFErrorRef *error) {
134 __block size_t array_size = 0;
135 __block bool fail = false;
136
137 CFArrayForEach(pia, ^(const void *value) {
138 if (isSOSPeerInfo(value)) {
139 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
140 size_t pi_size = SOSPeerInfoGetDEREncodedSize(pi, error);
141
142 fail = (pi_size == 0);
143 array_size += pi_size;
144 } else {
145 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Non SOSPeerInfo in array"), (error != NULL ? *error : NULL), error);
146 fail = true;
147 }
148 });
149
150 return fail ? 0 : ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, array_size);
151 }
152
153 uint8_t* SOSPeerInfoArrayEncodeToDER(CFArrayRef pia, CFErrorRef* error, const uint8_t* der, uint8_t* der_end_param) {
154
155 uint8_t* const sequence_end = der_end_param;
156 __block uint8_t* der_end = der_end_param;
157
158 CFArrayForEachReverse(pia, ^(const void *value) {
159 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
160 if (CFGetTypeID(pi) != SOSPeerInfoGetTypeID()) {
161 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Non SOSPeerInfo in array"), NULL, error);
162 der_end = NULL; // Indicate error and continue.
163 }
164 if (der_end)
165 der_end = SOSPeerInfoEncodeToDER(pi, error, der, der_end);
166 });
167
168 if (der_end == NULL)
169 return NULL;
170
171 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, sequence_end, der, der_end);
172 }
173
174
175 CFMutableSetRef SOSPeerInfoSetCreateFromArrayDER(CFAllocatorRef allocator, const CFSetCallBacks *callbacks, CFErrorRef* error,
176 const uint8_t** der_p, const uint8_t *der_end) {
177 CFMutableSetRef result = NULL;
178
179 CFArrayRef peers = SOSPeerInfoArrayCreateFromDER(allocator, error, der_p, der_end);
180
181 if (peers) {
182 result = CFSetCreateMutable(allocator, 0, callbacks);
183 CFSetSetValues(result, peers);
184 }
185
186 CFReleaseNull(peers);
187 return result;
188 }
189
190 size_t SOSPeerInfoSetGetDEREncodedArraySize(CFSetRef pia, CFErrorRef *error) {
191 __block size_t array_size = 0;
192 __block bool fail = false;
193
194 CFSetForEach(pia, ^(const void *value) {
195 if (isSOSPeerInfo(value)) {
196 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
197 size_t pi_size = SOSPeerInfoGetDEREncodedSize(pi, error);
198
199 fail = (pi_size == 0);
200 array_size += pi_size;
201 } else {
202 SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Non SOSPeerInfo in array"), (error != NULL ? *error : NULL), error);
203 fail = true;
204 }
205 });
206
207 return fail ? 0 : ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, array_size);
208 }
209
210 uint8_t* SOSPeerInfoSetEncodeToArrayDER(CFSetRef pis, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) {
211 CFMutableArrayRef pia = CFSetCopyValues(pis);
212
213 CFArrayOfSOSPeerInfosSortByID(pia);
214
215 uint8_t* result = SOSPeerInfoArrayEncodeToDER(pia, error, der, der_end);
216
217 CFReleaseNull(pia);
218
219 return result;
220 }
221
222
223
224 CFArrayRef CreateArrayOfPeerInfoWithXPCObject(xpc_object_t peerArray, CFErrorRef* error) {
225 if (!peerArray) {
226 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedNull, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("Unexpected Null Array to encode"));
227 return NULL;
228 }
229
230 if (xpc_get_type(peerArray) != XPC_TYPE_DATA) {
231 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("Array of peer info not array, got %@"), peerArray);
232 return NULL;
233 }
234
235 const uint8_t* der = xpc_data_get_bytes_ptr(peerArray);
236 const uint8_t* der_end = der + xpc_data_get_length(peerArray);
237
238 return SOSPeerInfoArrayCreateFromDER(kCFAllocatorDefault, error, &der, der_end);
239 }
240
241 xpc_object_t CreateXPCObjectWithArrayOfPeerInfo(CFArrayRef array, CFErrorRef *error) {
242 size_t data_size = SOSPeerInfoArrayGetDEREncodedSize(array, error);
243 if (data_size == 0)
244 return NULL;
245 uint8_t *data = (uint8_t *)malloc(data_size);
246 if (!data) return NULL;
247
248 xpc_object_t result = NULL;
249 if (SOSPeerInfoArrayEncodeToDER(array, error, data, data + data_size))
250 result = xpc_data_create(data, data_size);
251
252 free(data);
253 return result;
254 }