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@
25 #include <SecureObjectSync/SOSPeerInfoCollections.h>
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>
36 // PeerInfoSetby ID handling
41 // CFSetRetainCallback
44 static Boolean
SOSPeerInfoIDEqual(const void *value1
, const void *value2
)
46 SOSPeerInfoRef peer1
= (SOSPeerInfoRef
) value1
;
47 SOSPeerInfoRef peer2
= (SOSPeerInfoRef
) value2
;
49 return CFEqual(SOSPeerInfoGetPeerID(peer1
), SOSPeerInfoGetPeerID(peer2
));
52 static CFHashCode
SOSPeerInfoIDHash(const void *value
)
54 return CFHash(SOSPeerInfoGetPeerID((SOSPeerInfoRef
) value
));
57 bool SOSPeerInfoSetContainsIdenticalPeers(CFSetRef set1
, CFSetRef set2
){
59 __block
bool result
= true;
61 if(!CFEqualSafe(set1
, set2
))
64 CFSetForEach(set1
, ^(const void *value
) {
65 SOSPeerInfoRef peer1
= (SOSPeerInfoRef
)value
;
66 SOSPeerInfoRef peer2
= (SOSPeerInfoRef
)CFSetGetValue(set2
, peer1
);
67 result
&= CFEqualSafe(peer1
, peer2
);
71 const CFSetCallBacks kSOSPeerSetCallbacks
= {0, SecCFRetainForCollection
, SecCFReleaseForCollection
, CFCopyDescription
, SOSPeerInfoIDEqual
, SOSPeerInfoIDHash
};
73 CFMutableSetRef
CFSetCreateMutableForSOSPeerInfosByID(CFAllocatorRef allocator
)
75 return CFSetCreateMutable(allocator
, 0, &kSOSPeerSetCallbacks
);
80 // CFArray of Peer Info handling
83 void CFArrayOfSOSPeerInfosSortByID(CFMutableArrayRef peerInfoArray
)
85 CFArraySortValues(peerInfoArray
, CFRangeMake(0, CFArrayGetCount(peerInfoArray
)), SOSPeerInfoCompareByID
, NULL
);
90 // PeerInfoArray encoding decoding
93 CFMutableArrayRef
SOSPeerInfoArrayCreateFromDER(CFAllocatorRef allocator
, CFErrorRef
* error
,
94 const uint8_t** der_p
, const uint8_t *der_end
) {
95 CFMutableArrayRef pia
= CFArrayCreateMutableForCFTypes(allocator
);
97 const uint8_t *sequence_end
;
99 *der_p
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &sequence_end
, *der_p
, der_end
);
101 require_action(*der_p
, fail
, SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Peer Info Array Sequence Header"), NULL
, error
));
103 while (sequence_end
!= *der_p
) {
104 SOSPeerInfoRef pi
= SOSPeerInfoCreateFromDER(allocator
, error
, der_p
, sequence_end
);
106 if (pi
== NULL
|| *der_p
== NULL
) {
107 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Peer Info Array DER"), (error
!= NULL
? *error
: NULL
), error
);
112 CFArrayAppendValue(pia
, pi
);
126 size_t SOSPeerInfoArrayGetDEREncodedSize(CFArrayRef pia
, CFErrorRef
*error
) {
127 __block
size_t array_size
= 0;
128 __block
bool fail
= false;
130 CFArrayForEach(pia
, ^(const void *value
) {
131 if (isSOSPeerInfo(value
)) {
132 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
133 size_t pi_size
= SOSPeerInfoGetDEREncodedSize(pi
, error
);
135 fail
= (pi_size
== 0);
136 array_size
+= pi_size
;
138 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Non SOSPeerInfo in array"), (error
!= NULL
? *error
: NULL
), error
);
143 return fail
? 0 : ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, array_size
);
146 uint8_t* SOSPeerInfoArrayEncodeToDER(CFArrayRef pia
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end_param
) {
148 uint8_t* const sequence_end
= der_end_param
;
149 __block
uint8_t* der_end
= der_end_param
;
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.
158 der_end
= SOSPeerInfoEncodeToDER(pi
, error
, der
, der_end
);
164 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, sequence_end
, der
, der_end
);
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
;
172 CFArrayRef peers
= SOSPeerInfoArrayCreateFromDER(allocator
, error
, der_p
, der_end
);
175 result
= CFSetCreateMutable(allocator
, 0, callbacks
);
176 CFSetSetValues(result
, peers
);
179 CFReleaseNull(peers
);
183 size_t SOSPeerInfoSetGetDEREncodedArraySize(CFSetRef pia
, CFErrorRef
*error
) {
184 __block
size_t array_size
= 0;
185 __block
bool fail
= false;
187 CFSetForEach(pia
, ^(const void *value
) {
188 if (isSOSPeerInfo(value
)) {
189 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
190 size_t pi_size
= SOSPeerInfoGetDEREncodedSize(pi
, error
);
192 fail
= (pi_size
== 0);
193 array_size
+= pi_size
;
195 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Non SOSPeerInfo in array"), (error
!= NULL
? *error
: NULL
), error
);
200 return fail
? 0 : ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, array_size
);
203 uint8_t* SOSPeerInfoSetEncodeToArrayDER(CFSetRef pis
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end
) {
204 CFArrayRef pia
= CFSetCopyValues(pis
);
206 uint8_t* result
= SOSPeerInfoArrayEncodeToDER(pia
, error
, der
, der_end
);
215 CFArrayRef
CreateArrayOfPeerInfoWithXPCObject(xpc_object_t peerArray
, CFErrorRef
* error
) {
217 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedNull
, sSecXPCErrorDomain
, NULL
, error
, NULL
, CFSTR("Unexpected Null Array to encode"));
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
);
226 const uint8_t* der
= xpc_data_get_bytes_ptr(peerArray
);
227 const uint8_t* der_end
= der
+ xpc_data_get_length(peerArray
);
229 return SOSPeerInfoArrayCreateFromDER(kCFAllocatorDefault
, error
, &der
, der_end
);
232 xpc_object_t
CreateXPCObjectWithArrayOfPeerInfo(CFArrayRef array
, CFErrorRef
*error
) {
233 size_t data_size
= SOSPeerInfoArrayGetDEREncodedSize(array
, error
);
236 uint8_t *data
= (uint8_t *)malloc(data_size
);
237 if (!data
) return NULL
;
239 xpc_object_t result
= NULL
;
240 if (SOSPeerInfoArrayEncodeToDER(array
, error
, data
, data
+ data_size
))
241 result
= xpc_data_create(data
, data_size
);