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