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