/ OSX / utilities / der_dictionary.c
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  }