]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecCertificatePath.c
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / sec / Security / 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 }