2 * Copyright (c) 2007-2010,2012-2017 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * SecCertificatePath.c - CoreFoundation based certificate path object
28 #include "SecCertificatePath.h"
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>
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>
56 // MARK: SecCertificatePath
57 /********************************************************
58 ************* SecCertificatePath object ****************
59 ********************************************************/
60 struct SecCertificatePath
{
64 SecCertificateRef certificates
[];
67 CFGiblisWithHashFor(SecCertificatePath
)
69 static void SecCertificatePathDestroy(CFTypeRef cf
) {
70 SecCertificatePathRef certificatePath
= (SecCertificatePathRef
) cf
;
72 for (ix
= 0; ix
< certificatePath
->count
; ++ix
) {
73 CFRelease(certificatePath
->certificates
[ix
]);
77 static Boolean
SecCertificatePathCompare(CFTypeRef cf1
, CFTypeRef cf2
) {
78 SecCertificatePathRef cp1
= (SecCertificatePathRef
) cf1
;
79 SecCertificatePathRef cp2
= (SecCertificatePathRef
) cf2
;
80 if (cp1
->count
!= cp2
->count
)
83 for (ix
= 0; ix
< cp1
->count
; ++ix
) {
84 if (!CFEqual(cp1
->certificates
[ix
], cp2
->certificates
[ix
]))
91 static CFHashCode
SecCertificatePathHash(CFTypeRef cf
) {
92 SecCertificatePathRef certificatePath
= (SecCertificatePathRef
) cf
;
93 CFHashCode hashCode
= 0;
94 // hashCode = 31 * SecCertificatePathGetTypeID();
96 for (ix
= 0; ix
< certificatePath
->count
; ++ix
) {
97 hashCode
+= CFHash(certificatePath
->certificates
[ix
]);
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
);
110 for (ix
= 0; ix
< certificatePath
->count
; ++ix
) {
112 CFStringAppend(desc
, CFSTR(", "));
114 CFStringRef str
= CFCopyDescription(certificatePath
->certificates
[ix
]);
115 CFStringAppend(desc
, str
);
118 CFStringAppend(desc
, CFSTR(" >"));
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")));
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")));
134 result
->count
= count
;
137 for (ix
= 0; ix
< count
; ++ix
) {
138 SecCertificateRef certificate
= SecCertificateCreateWithXPCArrayAtIndex(xpc_path
, ix
, error
);
140 result
->certificates
[ix
] = certificate
;
142 result
->count
= ix
; // total allocated
143 CFReleaseNull(result
);
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")));
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")));
163 result
->count
= count
;
166 for (ix
= 0; ix
< count
; ++ix
) {
167 SecCertificateRef certificate
= SecCertificateCreateWithData(NULL
, CFArrayGetValueAtIndex(certificates
, ix
));
169 result
->certificates
[ix
] = certificate
;
171 result
->count
= ix
; // total allocated
172 CFReleaseNull(result
);
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
);
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
);
207 CFArrayAppendValue(outCerts
, cert
);
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")));
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")));
225 result
->count
= count
;
228 for (ix
= 0; ix
< count
; ++ix
) {
229 SecCertificateRef certificate
= (SecCertificateRef
)CFArrayGetValueAtIndex(certificates
, ix
);
231 result
->certificates
[ix
] = CFRetainSafe(certificate
);
233 result
->count
= ix
; // total allocated
234 CFReleaseNull(result
);
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
);
253 CFArrayAppendValue(serializedCerts
, certData
);
258 return serializedCerts
;
261 CFIndex
SecCertificatePathGetCount(
262 SecCertificatePathRef certificatePath
) {
263 check(certificatePath
);
264 return certificatePath
? certificatePath
->count
: 0;
267 SecCertificateRef
SecCertificatePathGetCertificateAtIndex(
268 SecCertificatePathRef certificatePath
, CFIndex ix
) {
269 check(certificatePath
&& ix
>= 0 && ix
< certificatePath
->count
);
270 return certificatePath
->certificates
[ix
];
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
))
283 SecKeyRef
SecCertificatePathCopyPublicKeyAtIndex(
284 SecCertificatePathRef certificatePath
, CFIndex ix
) {
285 SecCertificateRef certificate
=
286 SecCertificatePathGetCertificateAtIndex(certificatePath
, ix
);
288 return SecCertificateCopyPublicKey_ios(certificate
);
290 return SecCertificateCopyPublicKey(certificate
);