/ OSX / sec / Security / SecCertificatePath.c
SecCertificatePath.c
  1  /*
  2   * Copyright (c) 2007-2010,2012-2017 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   * SecCertificatePath.c - CoreFoundation based certificate path object
 26   */
 27  
 28  #include "SecCertificatePath.h"
 29  
 30  #include <Security/SecTrust.h>
 31  #include <Security/SecTrustStore.h>
 32  #include <Security/SecItem.h>
 33  #include <Security/SecCertificateInternal.h>
 34  #include <Security/SecFramework.h>
 35  #include <utilities/SecIOFormat.h>
 36  #include <CoreFoundation/CFRuntime.h>
 37  #include <CoreFoundation/CFSet.h>
 38  #include <CoreFoundation/CFString.h>
 39  #include <CoreFoundation/CFNumber.h>
 40  #include <CoreFoundation/CFArray.h>
 41  #include <CoreFoundation/CFPropertyList.h>
 42  #include <AssertMacros.h>
 43  #include <stdbool.h>
 44  #include <string.h>
 45  #include <stdlib.h>
 46  #include <pthread.h>
 47  #include <Security/SecBase.h>
 48  #include "SecRSAKey.h"
 49  #include <libDER/oids.h>
 50  #include <utilities/debugging.h>
 51  #include <Security/SecInternal.h>
 52  #include <utilities/SecCFError.h>
 53  #include <utilities/SecCFWrappers.h>
 54  
 55  // MARK: -
 56  // MARK: SecCertificatePath
 57  /********************************************************
 58   ************* SecCertificatePath object ****************
 59   ********************************************************/
 60  struct SecCertificatePath {
 61      CFRuntimeBase		_base;
 62  	CFIndex				count;
 63  
 64  	SecCertificateRef	certificates[];
 65  };
 66  
 67  CFGiblisWithHashFor(SecCertificatePath)
 68  
 69  static void SecCertificatePathDestroy(CFTypeRef cf) {
 70  	SecCertificatePathRef certificatePath = (SecCertificatePathRef) cf;
 71  	CFIndex ix;
 72  	for (ix = 0; ix < certificatePath->count; ++ix) {
 73  		CFRelease(certificatePath->certificates[ix]);
 74      }
 75  }
 76  
 77  static Boolean SecCertificatePathCompare(CFTypeRef cf1, CFTypeRef cf2) {
 78  	SecCertificatePathRef cp1 = (SecCertificatePathRef) cf1;
 79  	SecCertificatePathRef cp2 = (SecCertificatePathRef) cf2;
 80  	if (cp1->count != cp2->count)
 81  		return false;
 82  	CFIndex ix;
 83  	for (ix = 0; ix < cp1->count; ++ix) {
 84  		if (!CFEqual(cp1->certificates[ix], cp2->certificates[ix]))
 85  			return false;
 86  	}
 87  
 88  	return true;
 89  }
 90  
 91  static CFHashCode SecCertificatePathHash(CFTypeRef cf) {
 92  	SecCertificatePathRef certificatePath = (SecCertificatePathRef) cf;
 93  	CFHashCode hashCode = 0;
 94  	// hashCode = 31 * SecCertificatePathGetTypeID();
 95  	CFIndex ix;
 96  	for (ix = 0; ix < certificatePath->count; ++ix) {
 97  		hashCode += CFHash(certificatePath->certificates[ix]);
 98  	}
 99  	return hashCode;
100  }
101  
102  static CFStringRef SecCertificatePathCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
103  	SecCertificatePathRef certificatePath = (SecCertificatePathRef) cf;
104      CFMutableStringRef desc = CFStringCreateMutable(kCFAllocatorDefault, 0);
105      CFStringRef typeStr = CFCopyTypeIDDescription(CFGetTypeID(cf));
106      CFStringAppendFormat(desc, NULL,
107          CFSTR("<%@ certs: "), typeStr);
108      CFRelease(typeStr);
109      CFIndex ix;
110  	for (ix = 0; ix < certificatePath->count; ++ix) {
111          if (ix > 0) {
112              CFStringAppend(desc, CFSTR(", "));
113          }
114          CFStringRef str = CFCopyDescription(certificatePath->certificates[ix]);
115          CFStringAppend(desc, str);
116          CFRelease(str);
117  	}
118      CFStringAppend(desc, CFSTR(" >"));
119  
120      return desc;
121  }
122  
123  
124  /* Create a new certificate path from an xpc_array of data. */
125  SecCertificatePathRef SecCertificatePathCreateWithXPCArray(xpc_object_t xpc_path, CFErrorRef *error) {
126      SecCertificatePathRef result = NULL;
127      require_action_quiet(xpc_path, exit, SecError(errSecParam, error, CFSTR("xpc_path is NULL")));
128      require_action_quiet(xpc_get_type(xpc_path) == XPC_TYPE_ARRAY, exit, SecError(errSecDecode, error, CFSTR("xpc_path value is not an array")));
129      size_t count;
130      require_action_quiet(count = xpc_array_get_count(xpc_path), exit, SecError(errSecDecode, error, CFSTR("xpc_path array count == 0")));
131      size_t size = sizeof(struct SecCertificatePath) + count * sizeof(SecCertificateRef);
132      require_action_quiet(result = (SecCertificatePathRef)_CFRuntimeCreateInstance(kCFAllocatorDefault, SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0), exit, SecError(errSecDecode, error, CFSTR("_CFRuntimeCreateInstance returned NULL")));
133  
134      result->count = count;
135  
136  	size_t ix;
137  	for (ix = 0; ix < count; ++ix) {
138          SecCertificateRef certificate = SecCertificateCreateWithXPCArrayAtIndex(xpc_path, ix, error);
139          if (certificate) {
140              result->certificates[ix] = certificate;
141          } else {
142              result->count = ix; // total allocated
143              CFReleaseNull(result);
144              break;
145          }
146  	}
147  
148  exit:
149      return result;
150  }
151  
152  SecCertificatePathRef SecCertificatePathCreateDeserialized(CFArrayRef certificates, CFErrorRef *error) {
153      SecCertificatePathRef result = NULL;
154      require_action_quiet(isArray(certificates), exit,
155                           SecError(errSecParam, error, CFSTR("certificates is not an array")));
156      size_t count = 0;
157      require_action_quiet(count = CFArrayGetCount(certificates), exit,
158                           SecError(errSecDecode, error, CFSTR("certificates array count == 0")));
159      size_t size = sizeof(struct SecCertificatePath) + count * sizeof(SecCertificateRef);
160      require_action_quiet(result = (SecCertificatePathRef)_CFRuntimeCreateInstance(kCFAllocatorDefault, SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0), exit,
161                           SecError(errSecDecode, error, CFSTR("_CFRuntimeCreateInstance returned NULL")));
162  
163      result->count = count;
164  
165      size_t ix;
166      for (ix = 0; ix < count; ++ix) {
167          SecCertificateRef certificate = SecCertificateCreateWithData(NULL, CFArrayGetValueAtIndex(certificates, ix));
168          if (certificate) {
169              result->certificates[ix] = certificate;
170          } else {
171              result->count = ix; // total allocated
172              CFReleaseNull(result);
173              break;
174          }
175      }
176  
177  exit:
178      return result;
179  }
180  
181  /* Create an array of CFDataRefs from a certificate path. */
182  xpc_object_t SecCertificatePathCopyXPCArray(SecCertificatePathRef path, CFErrorRef *error) {
183      xpc_object_t xpc_chain = NULL;
184      size_t ix, count = path->count;
185      require_action_quiet(xpc_chain = xpc_array_create(NULL, 0), exit, SecError(errSecParam, error, CFSTR("xpc_array_create failed")));
186  	for (ix = 0; ix < count; ++ix) {
187          SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(path, ix);
188          if (!SecCertificateAppendToXPCArray(cert, xpc_chain, error)) {
189              xpc_release(xpc_chain);
190              return NULL;
191          }
192      }
193  
194  exit:
195      return xpc_chain;
196  }
197  
198  /* Create an array of SecCertificateRefs from a certificate path. */
199  CFArrayRef SecCertificatePathCopyCertificates(SecCertificatePathRef path, CFErrorRef *error) {
200      CFMutableArrayRef outCerts = NULL;
201      size_t ix, count = path->count;
202      require_action_quiet(outCerts = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks), exit,
203                           SecError(errSecParam, error, CFSTR("CFArray failed to create")));
204      for (ix = 0; ix < count; ++ix) {
205          SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(path, ix);
206          if (cert) {
207              CFArrayAppendValue(outCerts, cert);
208          }
209     }
210  exit:
211      return outCerts;
212  }
213  
214  SecCertificatePathRef SecCertificatePathCreateWithCertificates(CFArrayRef certificates, CFErrorRef *error) {
215      SecCertificatePathRef result = NULL;
216      require_action_quiet(isArray(certificates), exit,
217                           SecError(errSecParam, error, CFSTR("certificates is not an array")));
218      size_t count = 0;
219      require_action_quiet(count = CFArrayGetCount(certificates), exit,
220                           SecError(errSecDecode, error, CFSTR("certificates array count == 0")));
221      size_t size = sizeof(struct SecCertificatePath) + count * sizeof(SecCertificateRef);
222      require_action_quiet(result = (SecCertificatePathRef)_CFRuntimeCreateInstance(kCFAllocatorDefault, SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0), exit,
223                           SecError(errSecDecode, error, CFSTR("_CFRuntimeCreateInstance returned NULL")));
224  
225      result->count = count;
226  
227      size_t ix;
228      for (ix = 0; ix < count; ++ix) {
229          SecCertificateRef certificate = (SecCertificateRef)CFArrayGetValueAtIndex(certificates, ix);
230          if (certificate) {
231              result->certificates[ix] = CFRetainSafe(certificate);
232          } else {
233              result->count = ix; // total allocated
234              CFReleaseNull(result);
235              break;
236          }
237      }
238  
239  exit:
240      return result;
241  }
242  
243  CFArrayRef SecCertificatePathCreateSerialized(SecCertificatePathRef path, CFErrorRef *error) {
244      CFMutableArrayRef serializedCerts = NULL;
245      require_quiet(path, exit);
246      size_t ix, count = path->count;
247      require_action_quiet(serializedCerts = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks), exit,
248                           SecError(errSecParam, error, CFSTR("CFArray failed to create")));
249      for (ix = 0; ix < count; ++ix) {
250          SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(path, ix);
251          CFDataRef certData = SecCertificateCopyData(cert);
252          if (certData) {
253              CFArrayAppendValue(serializedCerts, certData);
254              CFRelease(certData);
255          }
256      }
257  exit:
258      return serializedCerts;
259  }
260  
261  CFIndex SecCertificatePathGetCount(
262  	SecCertificatePathRef certificatePath) {
263  	check(certificatePath);
264  	return certificatePath ? certificatePath->count : 0;
265  }
266  
267  SecCertificateRef SecCertificatePathGetCertificateAtIndex(
268  	SecCertificatePathRef certificatePath, CFIndex ix) {
269  	check(certificatePath && ix >= 0 && ix < certificatePath->count);
270  	return certificatePath->certificates[ix];
271  }
272  
273  CFIndex SecCertificatePathGetIndexOfCertificate(SecCertificatePathRef path,
274      SecCertificateRef certificate) {
275      CFIndex ix, count = path->count;
276  	for (ix = 0; ix < count; ++ix) {
277          if (CFEqual(path->certificates[ix], certificate))
278              return ix;
279  	}
280      return kCFNotFound;
281  }
282  
283  SecKeyRef SecCertificatePathCopyPublicKeyAtIndex(
284  	SecCertificatePathRef certificatePath, CFIndex ix) {
285  	SecCertificateRef certificate =
286          SecCertificatePathGetCertificateAtIndex(certificatePath, ix);
287  #if TARGET_OS_OSX
288      return SecCertificateCopyPublicKey_ios(certificate);
289  #else
290      return SecCertificateCopyPublicKey(certificate);
291  #endif
292  }