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 "keychain/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 "keychain/SecureObjectSync/SOSInternal.h"
33 #include <AssertMacros.h>
34 #include "keychain/SecureObjectSync/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 CFMutableSetRef
CFSetCreateMutableForSOSPeerInfosByIDWithArray(CFAllocatorRef allocator
, CFArrayRef peerInfos
)
84 CFMutableSetRef newSet
= CFSetCreateMutableForSOSPeerInfosByID(allocator
);
86 CFArrayForEach(peerInfos
, ^(const void *value
) {
87 SOSPeerInfoRef peer
= asSOSPeerInfo(value
);
89 CFSetAddValue(newSet
, peer
);
96 SOSPeerInfoRef
SOSPeerInfoSetFindByID(CFSetRef set
, CFStringRef id
) {
97 return (SOSPeerInfoRef
) CFSetGetValue(set
, id
);
101 // CFArray of Peer Info handling
104 void CFArrayOfSOSPeerInfosSortByID(CFMutableArrayRef peerInfoArray
)
106 CFArraySortValues(peerInfoArray
, CFRangeMake(0, CFArrayGetCount(peerInfoArray
)), SOSPeerInfoCompareByID
, NULL
);
111 // PeerInfoArray encoding decoding
114 CFMutableArrayRef
SOSPeerInfoArrayCreateFromDER(CFAllocatorRef allocator
, CFErrorRef
* error
,
115 const uint8_t** der_p
, const uint8_t *der_end
) {
116 CFMutableArrayRef pia
= CFArrayCreateMutableForCFTypes(allocator
);
118 const uint8_t *sequence_end
;
120 *der_p
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &sequence_end
, *der_p
, der_end
);
122 require_action(*der_p
, fail
, SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Peer Info Array Sequence Header"), NULL
, error
));
124 while (sequence_end
!= *der_p
) {
125 SOSPeerInfoRef pi
= SOSPeerInfoCreateFromDER(allocator
, error
, der_p
, sequence_end
);
127 if (pi
== NULL
|| *der_p
== NULL
) {
128 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Peer Info Array DER"), (error
!= NULL
? *error
: NULL
), error
);
133 CFArrayAppendValue(pia
, pi
);
147 size_t SOSPeerInfoArrayGetDEREncodedSize(CFArrayRef pia
, CFErrorRef
*error
) {
148 __block
size_t array_size
= 0;
149 __block
bool fail
= false;
151 CFArrayForEach(pia
, ^(const void *value
) {
152 if (isSOSPeerInfo(value
)) {
153 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
154 size_t pi_size
= SOSPeerInfoGetDEREncodedSize(pi
, error
);
156 fail
= (pi_size
== 0);
157 array_size
+= pi_size
;
159 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Non SOSPeerInfo in array"), (error
!= NULL
? *error
: NULL
), error
);
164 return fail
? 0 : ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, array_size
);
167 uint8_t* SOSPeerInfoArrayEncodeToDER(CFArrayRef pia
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end_param
) {
169 uint8_t* const sequence_end
= der_end_param
;
170 __block
uint8_t* der_end
= der_end_param
;
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.
179 der_end
= SOSPeerInfoEncodeToDER(pi
, error
, der
, der_end
);
185 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, sequence_end
, der
, der_end
);
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
;
193 CFArrayRef peers
= SOSPeerInfoArrayCreateFromDER(allocator
, error
, der_p
, der_end
);
196 result
= CFSetCreateMutable(allocator
, 0, callbacks
);
197 CFSetSetValues(result
, peers
);
200 CFReleaseNull(peers
);
204 size_t SOSPeerInfoSetGetDEREncodedArraySize(CFSetRef pia
, CFErrorRef
*error
) {
205 __block
size_t array_size
= 0;
206 __block
bool fail
= false;
208 CFSetForEach(pia
, ^(const void *value
) {
209 if (isSOSPeerInfo(value
)) {
210 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
211 size_t pi_size
= SOSPeerInfoGetDEREncodedSize(pi
, error
);
213 fail
= (pi_size
== 0);
214 array_size
+= pi_size
;
216 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Non SOSPeerInfo in array"), (error
!= NULL
? *error
: NULL
), error
);
221 return fail
? 0 : ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, array_size
);
224 uint8_t* SOSPeerInfoSetEncodeToArrayDER(CFSetRef pis
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end
) {
225 CFMutableArrayRef pia
= CFSetCopyValues(pis
);
227 CFArrayOfSOSPeerInfosSortByID(pia
);
229 uint8_t* result
= SOSPeerInfoArrayEncodeToDER(pia
, error
, der
, der_end
);
238 CFArrayRef
CreateArrayOfPeerInfoWithXPCObject(xpc_object_t peerArray
, CFErrorRef
* error
) {
240 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedNull
, sSecXPCErrorDomain
, NULL
, error
, NULL
, CFSTR("Unexpected Null Array to encode"));
244 if (xpc_get_type(peerArray
) != XPC_TYPE_DATA
) {
245 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType
, sSecXPCErrorDomain
, NULL
, error
, NULL
, CFSTR("Array of peer info not data"));
249 const uint8_t* der
= xpc_data_get_bytes_ptr(peerArray
);
250 const uint8_t* der_end
= der
+ xpc_data_get_length(peerArray
);
252 return SOSPeerInfoArrayCreateFromDER(kCFAllocatorDefault
, error
, &der
, der_end
);
255 xpc_object_t
CreateXPCObjectWithArrayOfPeerInfo(CFArrayRef array
, CFErrorRef
*error
) {
256 size_t data_size
= SOSPeerInfoArrayGetDEREncodedSize(array
, error
);
259 uint8_t *data
= (uint8_t *)malloc(data_size
);
260 if (!data
) return NULL
;
262 xpc_object_t result
= NULL
;
263 if (SOSPeerInfoArrayEncodeToDER(array
, error
, data
, data
+ data_size
))
264 result
= xpc_data_create(data
, data_size
);