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