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 35static const uint8_t* der_decode_key_value(CFAllocatorRef allocator, CFOptionFlags mutability, 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, mutability, &keyObject, error, payload, payload_end); 52 payload = der_decode_plist(allocator, mutability, &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 64const uint8_t* der_decode_dictionary(CFAllocatorRef allocator, CFOptionFlags mutability, 65 CFDictionaryRef* dictionary, CFErrorRef *error, 66 const uint8_t* der, const uint8_t *der_end) 67{ 68 if (NULL == der) 69 return NULL; 70 71 const uint8_t *payload_end = 0; 72 const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SET, &payload_end, der, der_end); 73 74 if (NULL == payload) { 75 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SET"), NULL, error); 76 return NULL; 77 } 78 79 80 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 81 82 if (NULL == dict) { 83 SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("Failed to create dictionary"), NULL, error); 84 payload = NULL; 85 goto exit; 86 } 87 88 while (payload != NULL && payload < payload_end) { 89 CFTypeRef key = NULL; 90 CFTypeRef value = NULL; 91 92 payload = der_decode_key_value(allocator, mutability, &key, &value, error, payload, payload_end); 93 94 if (payload) { 95 CFDictionaryAddValue(dict, key, value); 96 } 97 98 CFReleaseNull(key); 99 CFReleaseNull(value); 100 } 101 102 103exit: 104 if (payload == payload_end) { 105 *dictionary = dict; 106 dict = NULL; 107 } 108 109 CFReleaseNull(dict); 110 111 return payload; 112} 113 114struct size_context { 115 bool success; 116 size_t size; 117 CFErrorRef *error; 118}; 119 120static size_t der_sizeof_key_value(CFTypeRef key, CFTypeRef value, CFErrorRef *error) { 121 size_t key_size = der_sizeof_plist(key, error); 122 if (key_size == 0) { 123 return 0; 124 } 125 size_t value_size = der_sizeof_plist(value, error); 126 if (value_size == 0) { 127 return 0; 128 } 129 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, key_size + value_size); 130} 131 132static void add_key_value_size(const void *key_void, const void *value_void, void *context_void) 133{ 134 CFTypeRef key = (CFTypeRef) key_void; 135 CFTypeRef value = (CFTypeRef) value_void; 136 struct size_context *context = (struct size_context*) context_void; 137 138 if (!context->success) 139 return; 140 141 size_t kv_size = der_sizeof_key_value(key, value, context->error); 142 if (kv_size == 0) { 143 context->success = false; 144 return; 145 } 146 147 context->size += kv_size; 148} 149 150size_t der_sizeof_dictionary(CFDictionaryRef dict, CFErrorRef *error) 151{ 152 struct size_context context = { .success = true, .size = 0, .error = error }; 153 154 155 CFDictionaryApplyFunction(dict, add_key_value_size, &context); 156 157 if (!context.success) 158 return 0; 159 160 return ccder_sizeof(CCDER_CONSTRUCTED_SET, context.size); 161} 162 163static uint8_t* der_encode_key_value(CFPropertyListRef key, CFPropertyListRef value, CFErrorRef *error, 164 const uint8_t* der, uint8_t *der_end) 165{ 166 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, 167 der_encode_plist(key, error, der, 168 der_encode_plist(value, error, der, der_end))); 169} 170 171struct encode_context { 172 bool success; 173 CFErrorRef * error; 174 CFMutableArrayRef list; 175 CFAllocatorRef allocator; 176}; 177 178static void add_sequence_to_array(const void *key_void, const void *value_void, void *context_void) 179{ 180 struct encode_context *context = (struct encode_context *) context_void; 181 if (context->success) { 182 CFTypeRef key = (CFTypeRef) key_void; 183 CFTypeRef value = (CFTypeRef) value_void; 184 185 size_t der_size = der_sizeof_key_value(key, value, context->error); 186 if (der_size == 0) { 187 context-> success = false; 188 } else { 189 CFMutableDataRef encoded_kv = CFDataCreateMutable(context->allocator, der_size); 190 CFDataSetLength(encoded_kv, der_size); 191 192 uint8_t* const encode_begin = CFDataGetMutableBytePtr(encoded_kv); 193 uint8_t* encode_end = encode_begin + der_size; 194 195 encode_end = der_encode_key_value(key, value, context->error, encode_begin, encode_end); 196 197 if (encode_end != NULL) { 198 CFDataDeleteBytes(encoded_kv, CFRangeMake(0, (encode_end - encode_begin))); 199 CFArrayAppendValue(context->list, encoded_kv); 200 } else { 201 context-> success = false; 202 } 203 204 CFReleaseNull(encoded_kv); 205 } 206 } 207} 208 209static CFComparisonResult cfdata_compare_contents(const void *val1, const void *val2, void *context __unused) 210{ 211 return CFDataCompare((CFDataRef) val1, (CFDataRef) val2); 212} 213 214 215uint8_t* der_encode_dictionary(CFDictionaryRef dictionary, CFErrorRef *error, 216 const uint8_t *der, uint8_t *der_end) 217{ 218 CFMutableArrayRef elements = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 219 220 struct encode_context context = { .success = true, .error = error, .list = elements }; 221 CFDictionaryApplyFunction(dictionary, add_sequence_to_array, &context); 222 223 if (!context.success) { 224 CFReleaseNull(elements); 225 return NULL; 226 } 227 228 CFRange allOfThem = CFRangeMake(0, CFArrayGetCount(elements)); 229 230 CFArraySortValues(elements, allOfThem, cfdata_compare_contents, NULL); 231 232 uint8_t* original_der_end = der_end; 233 234 for(CFIndex position = CFArrayGetCount(elements); position > 0;) { 235 --position; 236 CFDataRef data = CFArrayGetValueAtIndex(elements, position); 237 der_end = ccder_encode_body(CFDataGetLength(data), CFDataGetBytePtr(data), der, der_end); 238 } 239 240 CFReleaseNull(elements); 241 242 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SET, original_der_end, der, der_end); 243 244} 245