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 44static 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 52static CFHashCode SOSPeerInfoIDHash(const void *value) 53{ 54 return CFHash(SOSPeerInfoGetPeerID((SOSPeerInfoRef) value)); 55} 56 57bool 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} 71const CFSetCallBacks kSOSPeerSetCallbacks = {0, SecCFRetainForCollection, SecCFReleaseForCollection, CFCopyDescription, SOSPeerInfoIDEqual, SOSPeerInfoIDHash}; 72 73CFMutableSetRef CFSetCreateMutableForSOSPeerInfosByID(CFAllocatorRef allocator) 74{ 75 return CFSetCreateMutable(allocator, 0, &kSOSPeerSetCallbacks); 76} 77 78 79// 80// CFArray of Peer Info handling 81// 82 83void CFArrayOfSOSPeerInfosSortByID(CFMutableArrayRef peerInfoArray) 84{ 85 CFArraySortValues(peerInfoArray, CFRangeMake(0, CFArrayGetCount(peerInfoArray)), SOSPeerInfoCompareByID, NULL); 86} 87 88 89// 90// PeerInfoArray encoding decoding 91// 92 93CFMutableArrayRef 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 120fail: 121 CFReleaseNull(pia); 122 *der_p = NULL; 123 return NULL; 124} 125 126size_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 146uint8_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 168CFMutableSetRef 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 183size_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 203uint8_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 215CFArrayRef 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 232xpc_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} 246