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 <Security/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 <Security/SecureObjectSync/SOSInternal.h>
33 #include <AssertMacros.h>
34 #include <SOSPeerInfoDER.h>
37 // PeerInfoSetby ID handling
42 // CFSetRetainCallback
45 static CFStringRef
GetIDOrString(const void *object
) {
46 return isSOSPeerInfo(object
) ?
47 SOSPeerInfoGetPeerID((SOSPeerInfoRef
)object
) :
48 (isString(object
) ? (CFStringRef
) object
: NULL
);
51 static Boolean
SOSPeerInfoIDEqual(const void *value1
, const void *value2
)
53 return CFEqualSafe(GetIDOrString(value1
), GetIDOrString(value2
));
56 static CFHashCode
SOSPeerInfoIDHash(const void *value
)
58 return CFHash(GetIDOrString(value
));
61 bool SOSPeerInfoSetContainsIdenticalPeers(CFSetRef set1
, CFSetRef set2
){
63 __block
bool result
= true;
65 if(!CFEqualSafe(set1
, set2
))
68 CFSetForEach(set1
, ^(const void *value
) {
69 SOSPeerInfoRef peer1
= (SOSPeerInfoRef
)value
;
70 SOSPeerInfoRef peer2
= (SOSPeerInfoRef
)CFSetGetValue(set2
, peer1
);
71 result
&= CFEqualSafe(peer1
, peer2
);
75 const CFSetCallBacks kSOSPeerSetCallbacks
= {0, SecCFRetainForCollection
, SecCFReleaseForCollection
, CFCopyDescription
, SOSPeerInfoIDEqual
, SOSPeerInfoIDHash
};
77 CFMutableSetRef
CFSetCreateMutableForSOSPeerInfosByID(CFAllocatorRef allocator
)
79 return CFSetCreateMutable(allocator
, 0, &kSOSPeerSetCallbacks
);
82 SOSPeerInfoRef
SOSPeerInfoSetFindByID(CFSetRef set
, CFStringRef id
) {
83 return (SOSPeerInfoRef
) CFSetGetValue(set
, id
);
87 // CFArray of Peer Info handling
90 void CFArrayOfSOSPeerInfosSortByID(CFMutableArrayRef peerInfoArray
)
92 CFArraySortValues(peerInfoArray
, CFRangeMake(0, CFArrayGetCount(peerInfoArray
)), SOSPeerInfoCompareByID
, NULL
);
97 // PeerInfoArray encoding decoding
100 CFMutableArrayRef
SOSPeerInfoArrayCreateFromDER(CFAllocatorRef allocator
, CFErrorRef
* error
,
101 const uint8_t** der_p
, const uint8_t *der_end
) {
102 CFMutableArrayRef pia
= CFArrayCreateMutableForCFTypes(allocator
);
104 const uint8_t *sequence_end
;
106 *der_p
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &sequence_end
, *der_p
, der_end
);
108 require_action(*der_p
, fail
, SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Peer Info Array Sequence Header"), NULL
, error
));
110 while (sequence_end
!= *der_p
) {
111 SOSPeerInfoRef pi
= SOSPeerInfoCreateFromDER(allocator
, error
, der_p
, sequence_end
);
113 if (pi
== NULL
|| *der_p
== NULL
) {
114 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Peer Info Array DER"), (error
!= NULL
? *error
: NULL
), error
);
119 CFArrayAppendValue(pia
, pi
);
133 size_t SOSPeerInfoArrayGetDEREncodedSize(CFArrayRef pia
, CFErrorRef
*error
) {
134 __block
size_t array_size
= 0;
135 __block
bool fail
= false;
137 CFArrayForEach(pia
, ^(const void *value
) {
138 if (isSOSPeerInfo(value
)) {
139 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
140 size_t pi_size
= SOSPeerInfoGetDEREncodedSize(pi
, error
);
142 fail
= (pi_size
== 0);
143 array_size
+= pi_size
;
145 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Non SOSPeerInfo in array"), (error
!= NULL
? *error
: NULL
), error
);
150 return fail
? 0 : ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, array_size
);
153 uint8_t* SOSPeerInfoArrayEncodeToDER(CFArrayRef pia
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end_param
) {
155 uint8_t* const sequence_end
= der_end_param
;
156 __block
uint8_t* der_end
= der_end_param
;
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.
165 der_end
= SOSPeerInfoEncodeToDER(pi
, error
, der
, der_end
);
171 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, sequence_end
, der
, der_end
);
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
;
179 CFArrayRef peers
= SOSPeerInfoArrayCreateFromDER(allocator
, error
, der_p
, der_end
);
182 result
= CFSetCreateMutable(allocator
, 0, callbacks
);
183 CFSetSetValues(result
, peers
);
186 CFReleaseNull(peers
);
190 size_t SOSPeerInfoSetGetDEREncodedArraySize(CFSetRef pia
, CFErrorRef
*error
) {
191 __block
size_t array_size
= 0;
192 __block
bool fail
= false;
194 CFSetForEach(pia
, ^(const void *value
) {
195 if (isSOSPeerInfo(value
)) {
196 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
197 size_t pi_size
= SOSPeerInfoGetDEREncodedSize(pi
, error
);
199 fail
= (pi_size
== 0);
200 array_size
+= pi_size
;
202 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Non SOSPeerInfo in array"), (error
!= NULL
? *error
: NULL
), error
);
207 return fail
? 0 : ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, array_size
);
210 uint8_t* SOSPeerInfoSetEncodeToArrayDER(CFSetRef pis
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end
) {
211 CFMutableArrayRef pia
= CFSetCopyValues(pis
);
213 CFArrayOfSOSPeerInfosSortByID(pia
);
215 uint8_t* result
= SOSPeerInfoArrayEncodeToDER(pia
, error
, der
, der_end
);
224 CFArrayRef
CreateArrayOfPeerInfoWithXPCObject(xpc_object_t peerArray
, CFErrorRef
* error
) {
226 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedNull
, sSecXPCErrorDomain
, NULL
, error
, NULL
, CFSTR("Unexpected Null Array to encode"));
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
);
235 const uint8_t* der
= xpc_data_get_bytes_ptr(peerArray
);
236 const uint8_t* der_end
= der
+ xpc_data_get_length(peerArray
);
238 return SOSPeerInfoArrayCreateFromDER(kCFAllocatorDefault
, error
, &der
, der_end
);
241 xpc_object_t
CreateXPCObjectWithArrayOfPeerInfo(CFArrayRef array
, CFErrorRef
*error
) {
242 size_t data_size
= SOSPeerInfoArrayGetDEREncodedSize(array
, error
);
245 uint8_t *data
= (uint8_t *)malloc(data_size
);
246 if (!data
) return NULL
;
248 xpc_object_t result
= NULL
;
249 if (SOSPeerInfoArrayEncodeToDER(array
, error
, data
, data
+ data_size
))
250 result
= xpc_data_create(data
, data_size
);