der_dictionary.c
1 /* 2 * Copyright (c) 2012-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 <stdio.h> 26 27 #include "utilities/SecCFRelease.h" 28 #include "utilities/der_plist.h" 29 #include "utilities/der_plist_internal.h" 30 #include "utilities/SecCFWrappers.h" 31 32 #include <corecrypto/ccder.h> 33 #include <CoreFoundation/CoreFoundation.h> 34 35 static const uint8_t* der_decode_key_value(CFAllocatorRef allocator, 36 CFPropertyListRef* key, CFPropertyListRef* value, CFErrorRef *error, 37 const uint8_t* der, const uint8_t *der_end) 38 { 39 const uint8_t *payload_end = 0; 40 const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &payload_end, der, der_end); 41 42 if (NULL == payload) { 43 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SEQUENCE"), NULL, error); 44 return NULL; 45 } 46 47 CFTypeRef keyObject = NULL; 48 CFTypeRef valueObject = NULL; 49 50 51 payload = der_decode_plist(allocator, &keyObject, error, payload, payload_end); 52 payload = der_decode_plist(allocator, &valueObject, error, payload, payload_end); 53 54 if (payload != NULL) { 55 *key = keyObject; 56 *value = valueObject; 57 } else { 58 CFReleaseNull(keyObject); 59 CFReleaseNull(valueObject); 60 } 61 return payload; 62 } 63 64 const uint8_t* der_decode_dictionary(CFAllocatorRef allocator, 65 CFDictionaryRef* dictionary, CFErrorRef *error, 66 const uint8_t* der, const uint8_t *der_end) 67 { 68 if (NULL == der) { 69 SecCFDERCreateError(kSecDERErrorNullInput, CFSTR("null input"), NULL, error); 70 return NULL; 71 } 72 73 const uint8_t *payload_end = 0; 74 const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SET, &payload_end, der, der_end); 75 76 if (NULL == payload) { 77 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SET"), NULL, error); 78 return NULL; 79 } 80 81 82 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 83 84 if (NULL == dict) { 85 SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("Failed to create dictionary"), NULL, error); 86 payload = NULL; 87 goto exit; 88 } 89 90 while (payload != NULL && payload < payload_end) { 91 CFTypeRef key = NULL; 92 CFTypeRef value = NULL; 93 94 payload = der_decode_key_value(allocator, &key, &value, error, payload, payload_end); 95 96 if (payload) { 97 CFDictionaryAddValue(dict, key, value); 98 } 99 100 CFReleaseNull(key); 101 CFReleaseNull(value); 102 } 103 104 105 exit: 106 if (payload == payload_end) { 107 *dictionary = dict; 108 dict = NULL; 109 } 110 111 CFReleaseNull(dict); 112 113 return payload; 114 } 115 116 struct size_context { 117 bool success; 118 size_t size; 119 CFErrorRef *error; 120 }; 121 122 static size_t der_sizeof_key_value(CFTypeRef key, CFTypeRef value, CFErrorRef *error) { 123 size_t key_size = der_sizeof_plist(key, error); 124 if (key_size == 0) { 125 SecCFDERCreateError(kSecDERErrorNullInput, CFSTR("null input"), NULL, error); 126 return 0; 127 } 128 size_t value_size = der_sizeof_plist(value, error); 129 if (value_size == 0) { 130 SecCFDERCreateError(kSecDERErrorNullInput, CFSTR("null input"), NULL, error); 131 return 0; 132 } 133 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, key_size + value_size); 134 } 135 136 static void add_key_value_size(const void *key_void, const void *value_void, void *context_void) 137 { 138 CFTypeRef key = (CFTypeRef) key_void; 139 CFTypeRef value = (CFTypeRef) value_void; 140 struct size_context *context = (struct size_context*) context_void; 141 142 if (!context->success) 143 return; 144 145 size_t kv_size = der_sizeof_key_value(key, value, context->error); 146 if (kv_size == 0) { 147 context->success = false; 148 return; 149 } 150 151 context->size += kv_size; 152 } 153 154 size_t der_sizeof_dictionary(CFDictionaryRef dict, CFErrorRef *error) 155 { 156 struct size_context context = { .success = true, .size = 0, .error = error }; 157 158 159 CFDictionaryApplyFunction(dict, add_key_value_size, &context); 160 161 if (!context.success) 162 return 0; 163 164 return ccder_sizeof(CCDER_CONSTRUCTED_SET, context.size); 165 } 166 167 static uint8_t* der_encode_key_value(CFPropertyListRef key, CFPropertyListRef value, CFErrorRef *error, 168 bool repair, 169 const uint8_t* der, uint8_t *der_end) 170 { 171 return SecCCDEREncodeHandleResult(ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, 172 der_encode_plist_repair(key, error, repair, der, 173 der_encode_plist_repair(value, error, repair, der, der_end))), 174 error); 175 } 176 177 struct encode_context { 178 bool success; 179 bool repair_contents; 180 CFErrorRef * error; 181 CFMutableArrayRef list; 182 CFAllocatorRef allocator; 183 }; 184 185 static void add_sequence_to_array(const void *key_void, const void *value_void, void *context_void) 186 { 187 struct encode_context *context = (struct encode_context *) context_void; 188 if (context->success) { 189 CFTypeRef key = (CFTypeRef) key_void; 190 CFTypeRef value = (CFTypeRef) value_void; 191 192 size_t der_size = der_sizeof_key_value(key, value, context->error); 193 if (der_size == 0) { 194 context-> success = false; 195 } else { 196 CFMutableDataRef encoded_kv = CFDataCreateMutable(context->allocator, der_size); 197 CFDataSetLength(encoded_kv, der_size); 198 199 uint8_t* const encode_begin = CFDataGetMutableBytePtr(encoded_kv); 200 uint8_t* encode_end = encode_begin + der_size; 201 202 encode_end = der_encode_key_value(key, value, context->error, context->repair_contents, encode_begin, encode_end); 203 204 if (encode_end != NULL) { 205 CFDataDeleteBytes(encoded_kv, CFRangeMake(0, (encode_end - encode_begin))); 206 CFArrayAppendValue(context->list, encoded_kv); 207 } else { 208 context-> success = false; 209 } 210 211 CFReleaseNull(encoded_kv); 212 } 213 } 214 } 215 216 static CFComparisonResult cfdata_compare_der_contents(const void *val1, const void *val2, void *context __unused) 217 { 218 return CFDataCompareDERData((CFDataRef) val1, (CFDataRef) val2); 219 } 220 221 222 uint8_t* der_encode_dictionary(CFDictionaryRef dictionary, CFErrorRef *error, 223 const uint8_t *der, uint8_t *der_end) 224 { 225 return der_encode_dictionary_repair(dictionary, error, false, der, der_end); 226 } 227 228 uint8_t* der_encode_dictionary_repair(CFDictionaryRef dictionary, CFErrorRef *error, 229 bool repair, const uint8_t *der, uint8_t *der_end) 230 { 231 CFMutableArrayRef elements = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 232 233 struct encode_context context = { .success = true, .error = error, .list = elements, .repair_contents = repair }; 234 CFDictionaryApplyFunction(dictionary, add_sequence_to_array, &context); 235 236 if (!context.success) { 237 CFReleaseNull(elements); 238 return NULL; 239 } 240 241 CFRange allOfThem = CFRangeMake(0, CFArrayGetCount(elements)); 242 243 CFArraySortValues(elements, allOfThem, cfdata_compare_der_contents, NULL); 244 245 uint8_t* original_der_end = der_end; 246 247 for(CFIndex position = CFArrayGetCount(elements); position > 0;) { 248 --position; 249 CFDataRef data = CFArrayGetValueAtIndex(elements, position); 250 der_end = ccder_encode_body(CFDataGetLength(data), CFDataGetBytePtr(data), der, der_end); 251 } 252 253 CFReleaseNull(elements); 254 255 return SecCCDEREncodeHandleResult(ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SET, original_der_end, der, der_end), 256 error); 257 258 }