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 }