der_set.c
1 /* 2 * Copyright (c) 2015 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 <stdio.h> 26 #include "der_set.h" 27 28 #include "utilities/SecCFRelease.h" 29 #include "utilities/der_plist.h" 30 #include "utilities/der_plist_internal.h" 31 #include "utilities/SecCFWrappers.h" 32 33 #include <corecrypto/ccder.h> 34 #include <CoreFoundation/CoreFoundation.h> 35 36 const uint8_t* der_decode_set(CFAllocatorRef allocator, 37 CFSetRef* set, CFErrorRef *error, 38 const uint8_t* der, const uint8_t *der_end) 39 { 40 if (NULL == der) { 41 SecCFDERCreateError(kSecDERErrorNullInput, CFSTR("null input"), NULL, error); 42 return NULL; 43 } 44 45 const uint8_t *payload_end = 0; 46 const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_CFSET, &payload_end, der, der_end); 47 48 if (NULL == payload) { 49 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_CFSET"), NULL, error); 50 return NULL; 51 } 52 53 CFMutableSetRef theSet = (set && *set) ? CFSetCreateMutableCopy(allocator, 0, *set) 54 : CFSetCreateMutable(allocator, 0, &kCFTypeSetCallBacks); 55 56 if (NULL == theSet) { 57 SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("Failed to create set"), NULL, error); 58 payload = NULL; 59 goto exit; 60 } 61 62 while (payload != NULL && payload < payload_end) { 63 CFTypeRef value = NULL; 64 65 payload = der_decode_plist(allocator, &value, error, payload, payload_end); 66 67 if (payload) { 68 CFSetAddValue(theSet, value); 69 } 70 CFReleaseNull(value); 71 } 72 73 74 exit: 75 if (payload == payload_end && set) { 76 CFTransferRetained(*set, theSet); 77 } 78 79 CFReleaseNull(theSet); 80 81 return payload; 82 } 83 84 struct size_context { 85 bool success; 86 size_t size; 87 CFErrorRef *error; 88 }; 89 90 static void add_value_size(const void *value_void, void *context_void) 91 { 92 CFTypeRef value = (CFTypeRef) value_void; 93 struct size_context *context = (struct size_context*) context_void; 94 95 if (!context->success) 96 return; 97 98 size_t kv_size = der_sizeof_plist(value, context->error); 99 if (kv_size == 0) { 100 context->success = false; 101 return; 102 } 103 104 context->size += kv_size; 105 } 106 107 size_t der_sizeof_set(CFSetRef dict, CFErrorRef *error) 108 { 109 struct size_context context = { .success = true, .size = 0, .error = error }; 110 111 CFSetApplyFunction(dict, add_value_size, &context); 112 113 if (!context.success) 114 return 0; 115 116 return ccder_sizeof(CCDER_CONSTRUCTED_CFSET, context.size); 117 } 118 119 struct encode_context { 120 bool success; 121 bool repair_contents; 122 CFErrorRef * error; 123 CFMutableArrayRef list; 124 CFAllocatorRef allocator; 125 }; 126 127 static void add_sequence_to_array(const void *value_void, void *context_void) 128 { 129 struct encode_context *context = (struct encode_context *) context_void; 130 if (context->success) { 131 size_t der_size = der_sizeof_plist(value_void, context->error); 132 if (der_size == 0) { 133 context-> success = false; 134 } else { 135 CFMutableDataRef value = CFDataCreateMutable(context->allocator, der_size); 136 CFDataSetLength(value, der_size); 137 138 uint8_t* const encode_begin = CFDataGetMutableBytePtr(value); 139 uint8_t *encode_end = encode_begin + der_size; 140 141 encode_end = der_encode_plist_repair(value_void, context->error, context->repair_contents, encode_begin, encode_end); 142 143 if (encode_end != NULL) { 144 CFDataDeleteBytes(value, CFRangeMake(0, (encode_end - encode_begin))); 145 CFArrayAppendValue(context->list, value); 146 } else { 147 context-> success = false; 148 } 149 CFReleaseNull(value); 150 } 151 } 152 } 153 154 static CFComparisonResult cfdata_compare_der_contents(const void *val1, const void *val2, void *context __unused) 155 { 156 return CFDataCompareDERData((CFDataRef) val1, (CFDataRef) val2); 157 } 158 159 160 uint8_t* der_encode_set(CFSetRef set, CFErrorRef *error, 161 const uint8_t *der, uint8_t *der_end) 162 { 163 return der_encode_set_repair(set, error, false, der, der_end); 164 } 165 166 uint8_t* der_encode_set_repair(CFSetRef set, CFErrorRef *error, 167 bool repair, const uint8_t *der, uint8_t *der_end) 168 { 169 CFMutableArrayRef elements = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 170 171 struct encode_context context = { .success = true, .error = error, .list = elements, .repair_contents = repair }; 172 CFSetApplyFunction(set, add_sequence_to_array, &context); 173 174 if (!context.success) { 175 CFReleaseNull(elements); 176 return NULL; 177 } 178 179 CFRange allOfThem = CFRangeMake(0, CFArrayGetCount(elements)); 180 181 CFArraySortValues(elements, allOfThem, cfdata_compare_der_contents, NULL); 182 183 uint8_t* original_der_end = der_end; 184 185 for(CFIndex position = CFArrayGetCount(elements); position > 0;) { 186 --position; 187 CFDataRef data = CFArrayGetValueAtIndex(elements, position); 188 der_end = ccder_encode_body(CFDataGetLength(data), CFDataGetBytePtr(data), der, der_end); 189 } 190 191 CFReleaseNull(elements); 192 193 return SecCCDEREncodeHandleResult(ccder_encode_constructed_tl(CCDER_CONSTRUCTED_CFSET, original_der_end, der, der_end), 194 error); 195 196 }