1/*
2 * Copyright (c) 2007-2010,2012-2014 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 <AssertMacros.h>
53#include <utilities/SecCFError.h>
54#include <utilities/SecCFWrappers.h>
55
56// MARK: -
57// MARK: SecCertificatePath
58/********************************************************
59 ************* SecCertificatePath object ****************
60 ********************************************************/
61struct SecCertificatePath {
62    CFRuntimeBase		_base;
63	CFIndex				count;
64
65	/* Index of next parent source to search for parents. */
66	CFIndex				nextParentSource;
67
68	/* Index of last certificate in chain who's signature has been verified.
69	   0 means nothing has been checked.  1 means the leaf has been verified
70	   against it's issuer, etc. */
71	CFIndex				lastVerifiedSigner;
72
73	/* Index of first self issued certificate in the chain.  -1 mean there is
74	   none.  0 means the leaf is self signed.  */
75	CFIndex				selfIssued;
76
77	/* True iff cert at index selfIssued does in fact self verify. */
78	bool				isSelfSigned;
79
80	/* True if the root of this path is a trusted anchor.
81	   FIXME get rid of this since it's a property of the evaluation, not a
82	   static feature of a certificate path? */
83	bool				isAnchored;
84	SecCertificateRef	certificates[];
85};
86
87CFGiblisWithHashFor(SecCertificatePath)
88
89static void SecCertificatePathDestroy(CFTypeRef cf) {
90	SecCertificatePathRef certificatePath = (SecCertificatePathRef) cf;
91	CFIndex ix;
92	for (ix = 0; ix < certificatePath->count; ++ix) {
93		CFRelease(certificatePath->certificates[ix]);
94    }
95}
96
97static Boolean SecCertificatePathCompare(CFTypeRef cf1, CFTypeRef cf2) {
98	SecCertificatePathRef cp1 = (SecCertificatePathRef) cf1;
99	SecCertificatePathRef cp2 = (SecCertificatePathRef) cf2;
100	if (cp1->count != cp2->count)
101		return false;
102	CFIndex ix;
103	for (ix = 0; ix < cp1->count; ++ix) {
104		if (!CFEqual(cp1->certificates[ix], cp2->certificates[ix]))
105			return false;
106	}
107
108	return true;
109}
110
111static CFHashCode SecCertificatePathHash(CFTypeRef cf) {
112	SecCertificatePathRef certificatePath = (SecCertificatePathRef) cf;
113	CFHashCode hashCode = 0;
114	// hashCode = 31 * SecCertificatePathGetTypeID();
115	CFIndex ix;
116	for (ix = 0; ix < certificatePath->count; ++ix) {
117		hashCode += CFHash(certificatePath->certificates[ix]);
118	}
119	return hashCode;
120}
121
122static CFStringRef SecCertificatePathCopyDescription(CFTypeRef cf) {
123	SecCertificatePathRef certificatePath = (SecCertificatePathRef) cf;
124    CFMutableStringRef desc = CFStringCreateMutable(kCFAllocatorDefault, 0);
125    CFStringRef typeStr = CFCopyTypeIDDescription(CFGetTypeID(cf));
126    CFStringAppendFormat(desc, NULL,
127        CFSTR("<%@ lvs: %" PRIdCFIndex " certs: "), typeStr,
128        certificatePath->lastVerifiedSigner);
129    CFRelease(typeStr);
130    CFIndex ix;
131	for (ix = 0; ix < certificatePath->count; ++ix) {
132        if (ix > 0) {
133            CFStringAppend(desc, CFSTR(", "));
134        }
135        CFStringRef str = CFCopyDescription(certificatePath->certificates[ix]);
136        CFStringAppend(desc, str);
137        CFRelease(str);
138	}
139    CFStringAppend(desc, CFSTR(" >"));
140
141    return desc;
142}
143
144/* Create a new certificate path from an old one. */
145SecCertificatePathRef SecCertificatePathCreate(SecCertificatePathRef path,
146	SecCertificateRef certificate) {
147    CFAllocatorRef allocator = kCFAllocatorDefault;
148	check(certificate);
149	CFIndex count;
150	CFIndex selfIssued, lastVerifiedSigner;
151	bool isSelfSigned;
152	if (path) {
153		count = path->count + 1;
154		lastVerifiedSigner = path->lastVerifiedSigner;
155		selfIssued = path->selfIssued;
156		isSelfSigned = path->isSelfSigned;
157	} else {
158		count = 1;
159		lastVerifiedSigner = 0;
160		selfIssued = -1;
161		isSelfSigned = false;
162	}
163
164    CFIndex size = sizeof(struct SecCertificatePath) +
165		count * sizeof(SecCertificateRef);
166    SecCertificatePathRef result =
167		(SecCertificatePathRef)_CFRuntimeCreateInstance(allocator,
168		SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0);
169	if (!result)
170        return NULL;
171
172	result->count = count;
173	result->nextParentSource = 0;
174	result->lastVerifiedSigner = lastVerifiedSigner;
175	result->selfIssued = selfIssued;
176	result->isSelfSigned = isSelfSigned;
177	result->isAnchored = false;
178	CFIndex ix;
179	for (ix = 0; ix < count - 1; ++ix) {
180		result->certificates[ix] = path->certificates[ix];
181		CFRetain(result->certificates[ix]);
182	}
183	result->certificates[count - 1] = certificate;
184	CFRetainSafe(certificate);
185
186    return result;
187}
188
189/* Create a new certificate path from an xpc_array of data. */
190SecCertificatePathRef SecCertificatePathCreateWithXPCArray(xpc_object_t xpc_path, CFErrorRef *error) {
191    SecCertificatePathRef result = NULL;
192    require_action_quiet(xpc_path, exit, SecError(errSecParam, error, CFSTR("xpc_path is NULL")));
193    require_action_quiet(xpc_get_type(xpc_path) == XPC_TYPE_ARRAY, exit, SecError(errSecDecode, error, CFSTR("xpc_path value is not an array")));
194    size_t count;
195    require_action_quiet(count = xpc_array_get_count(xpc_path), exit, SecError(errSecDecode, error, CFSTR("xpc_path array count == 0")));
196    size_t size = sizeof(struct SecCertificatePath) + count * sizeof(SecCertificateRef);
197    require_action_quiet(result = (SecCertificatePathRef)_CFRuntimeCreateInstance(kCFAllocatorDefault, SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0), exit, SecError(errSecDecode, error, CFSTR("_CFRuntimeCreateInstance returned NULL")));
198
199	result->count = count;
200	result->nextParentSource = 0;
201	result->lastVerifiedSigner = count;
202	result->selfIssued = -1;
203	result->isSelfSigned = false;
204	result->isAnchored = false;
205	size_t ix;
206	for (ix = 0; ix < count; ++ix) {
207        SecCertificateRef certificate = SecCertificateCreateWithXPCArrayAtIndex(xpc_path, ix, error);
208        if (certificate) {
209            result->certificates[ix] = certificate;
210        } else {
211            result->count = ix; // total allocated
212            CFReleaseNull(result);
213            break;
214        }
215	}
216
217exit:
218    return result;
219}
220
221SecCertificatePathRef SecCertificatePathCopyFromParent(
222    SecCertificatePathRef path, CFIndex skipCount) {
223    CFAllocatorRef allocator = kCFAllocatorDefault;
224	CFIndex count;
225	CFIndex selfIssued, lastVerifiedSigner;
226	bool isSelfSigned;
227
228    /* Ensure we are at least returning a path of length 1. */
229    if (skipCount < 0 || path->count < 1 + skipCount)
230        return NULL;
231
232    count = path->count - skipCount;
233    lastVerifiedSigner = path->lastVerifiedSigner > skipCount
234        ? path->lastVerifiedSigner - skipCount : 0;
235    selfIssued = path->selfIssued >= skipCount
236        ? path->selfIssued - skipCount : -1;
237    isSelfSigned = path->selfIssued >= 0 ? path->isSelfSigned : false;
238
239    CFIndex size = sizeof(struct SecCertificatePath) +
240		count * sizeof(SecCertificateRef);
241    SecCertificatePathRef result =
242		(SecCertificatePathRef)_CFRuntimeCreateInstance(allocator,
243		SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0);
244	if (!result)
245        return NULL;
246
247	result->count = count;
248	result->nextParentSource = 0;
249	result->lastVerifiedSigner = lastVerifiedSigner;
250	result->selfIssued = selfIssued;
251	result->isSelfSigned = isSelfSigned;
252	result->isAnchored = path->isAnchored;
253	CFIndex ix;
254	for (ix = 0; ix < count; ++ix) {
255		result->certificates[ix] = path->certificates[ix + skipCount];
256		CFRetain(result->certificates[ix]);
257	}
258
259    return result;
260}
261
262SecCertificatePathRef SecCertificatePathCopyAddingLeaf(SecCertificatePathRef path,
263    SecCertificateRef leaf) {
264    CFAllocatorRef allocator = kCFAllocatorDefault;
265	CFIndex count;
266	CFIndex selfIssued, lastVerifiedSigner;
267	bool isSelfSigned;
268
269    /* First make sure the new leaf is signed by path's current leaf. */
270    SecKeyRef issuerKey = SecCertificatePathCopyPublicKeyAtIndex(path, 0);
271    if (!issuerKey)
272        return NULL;
273    OSStatus status = SecCertificateIsSignedBy(leaf, issuerKey);
274    CFRelease(issuerKey);
275    if (status)
276        return NULL;
277
278    count = path->count + 1;
279    lastVerifiedSigner = path->lastVerifiedSigner + 1;
280    selfIssued = path->selfIssued;
281    isSelfSigned = path->isSelfSigned;
282
283    CFIndex size = sizeof(struct SecCertificatePath) +
284		count * sizeof(SecCertificateRef);
285    SecCertificatePathRef result =
286		(SecCertificatePathRef)_CFRuntimeCreateInstance(allocator,
287		SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0);
288	if (!result)
289        return NULL;
290
291	result->count = count;
292	result->nextParentSource = 0;
293	result->lastVerifiedSigner = lastVerifiedSigner;
294	result->selfIssued = selfIssued;
295	result->isSelfSigned = isSelfSigned;
296	result->isAnchored = path->isAnchored;
297	CFIndex ix;
298	for (ix = 1; ix < count; ++ix) {
299		result->certificates[ix] = path->certificates[ix - 1];
300		CFRetain(result->certificates[ix]);
301	}
302	result->certificates[0] = leaf;
303	CFRetain(leaf);
304
305    return result;
306}
307
308/* Create an array of CFDataRefs from a certificate path. */
309xpc_object_t SecCertificatePathCopyXPCArray(SecCertificatePathRef path, CFErrorRef *error) {
310    xpc_object_t xpc_chain = NULL;
311    size_t ix, count = path->count;
312    require_action_quiet(xpc_chain = xpc_array_create(NULL, 0), exit, SecError(errSecParam, error, CFSTR("xpc_array_create failed")));
313	for (ix = 0; ix < count; ++ix) {
314        SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(path, ix);
315        if (!SecCertificateAppendToXPCArray(cert, xpc_chain, error)) {
316            xpc_release(xpc_chain);
317            return NULL;
318        }
319    }
320
321exit:
322    return xpc_chain;
323}
324
325/* Record the fact that we found our own root cert as our parent
326   certificate. */
327void SecCertificatePathSetSelfIssued(
328	SecCertificatePathRef certificatePath) {
329	if (certificatePath->selfIssued >= 0) {
330		secdebug("trust", "%@ is already issued at %" PRIdCFIndex, certificatePath,
331			certificatePath->selfIssued);
332		return;
333	}
334    secdebug("trust", "%@ is self issued", certificatePath);
335	certificatePath->selfIssued = certificatePath->count - 1;
336}
337
338void SecCertificatePathSetIsAnchored(
339	SecCertificatePathRef certificatePath) {
340    secdebug("trust", "%@ is anchored", certificatePath);
341	certificatePath->isAnchored = true;
342}
343
344/* Return the index of the first non anchor certificate in the chain that is
345   self signed counting from the leaf up.  Return -1 if there is none. */
346CFIndex SecCertificatePathSelfSignedIndex(
347	SecCertificatePathRef certificatePath) {
348	if (certificatePath->isSelfSigned)
349		return certificatePath->selfIssued;
350	return -1;
351}
352
353Boolean SecCertificatePathIsAnchored(
354	SecCertificatePathRef certificatePath) {
355	return certificatePath->isAnchored;
356}
357
358void SecCertificatePathSetNextSourceIndex(
359	SecCertificatePathRef certificatePath, CFIndex sourceIndex) {
360	certificatePath->nextParentSource = sourceIndex;
361}
362
363CFIndex SecCertificatePathGetNextSourceIndex(
364	SecCertificatePathRef certificatePath) {
365	return certificatePath->nextParentSource;
366}
367
368CFIndex SecCertificatePathGetCount(
369	SecCertificatePathRef certificatePath) {
370	check(certificatePath);
371	return certificatePath ? certificatePath->count : 0;
372}
373
374SecCertificateRef SecCertificatePathGetCertificateAtIndex(
375	SecCertificatePathRef certificatePath, CFIndex ix) {
376	check(certificatePath);
377	check(ix >= 0 && ix < certificatePath->count);
378	return certificatePath->certificates[ix];
379}
380
381CFIndex SecCertificatePathGetIndexOfCertificate(SecCertificatePathRef path,
382    SecCertificateRef certificate) {
383    CFIndex ix, count = path->count;
384	for (ix = 0; ix < count; ++ix) {
385        if (CFEqual(path->certificates[ix], certificate))
386            return ix;
387	}
388    return kCFNotFound;
389}
390
391#if 0
392/* Return the leaf certificate for certificatePath. */
393SecCertificateRef SecCertificatePathGetLeaf(
394	SecCertificatePathRef certificatePath) {
395	return SecCertificatePathGetCertificateAtIndex(certificatePath, 0);
396}
397#endif
398
399/* Return the root certificate for certificatePath.  Note that root is just
400   the top of the path as far as it is constructed.  It may or may not be
401   trusted or self signed.  */
402SecCertificateRef SecCertificatePathGetRoot(
403	SecCertificatePathRef certificatePath) {
404	return SecCertificatePathGetCertificateAtIndex(certificatePath,
405		SecCertificatePathGetCount(certificatePath) - 1);
406}
407
408SecKeyRef SecCertificatePathCopyPublicKeyAtIndex(
409	SecCertificatePathRef certificatePath, CFIndex ix) {
410	SecCertificateRef certificate =
411        SecCertificatePathGetCertificateAtIndex(certificatePath, ix);
412	const DERAlgorithmId *algId =
413		SecCertificateGetPublicKeyAlgorithm(certificate);
414    const DERItem *params = NULL;
415    if (algId->params.length != 0) {
416        params = &algId->params;
417    } else {
418        CFIndex count = certificatePath->count;
419        for (++ix; ix < count; ++ix) {
420            certificate = certificatePath->certificates[ix];
421            const DERAlgorithmId *chain_algId =
422                SecCertificateGetPublicKeyAlgorithm(certificate);
423            if (!DEROidCompare(&algId->oid, &chain_algId->oid)) {
424                /* Algorithm oids differ, params stay NULL. */
425                break;
426            }
427            if (chain_algId->params.length != 0) {
428                params = &chain_algId->params;
429                break;
430            }
431        }
432    }
433	const DERItem *keyData = SecCertificateGetPublicKeyData(certificate);
434    SecAsn1Oid oid1 = { .Data = algId->oid.data, .Length = algId->oid.length };
435    SecAsn1Item params1 = {
436        .Data = params ? params->data : NULL,
437        .Length = params ? params->length : 0
438    };
439    SecAsn1Item keyData1 = {
440        .Data = keyData ? keyData->data : NULL,
441        .Length = keyData ? keyData->length : 0
442    };
443    return SecKeyCreatePublicFromDER(kCFAllocatorDefault, &oid1, &params1,
444        &keyData1);
445}
446
447SecPathVerifyStatus SecCertificatePathVerify(
448	SecCertificatePathRef certificatePath) {
449	check(certificatePath);
450    if (!certificatePath)
451        return kSecPathVerifyFailed;
452	for (;
453		certificatePath->lastVerifiedSigner < certificatePath->count - 1;
454		++certificatePath->lastVerifiedSigner) {
455		SecKeyRef issuerKey =
456			SecCertificatePathCopyPublicKeyAtIndex(certificatePath,
457				certificatePath->lastVerifiedSigner + 1);
458		if (!issuerKey)
459			return kSecPathVerifiesUnknown;
460		OSStatus status = SecCertificateIsSignedBy(
461			certificatePath->certificates[certificatePath->lastVerifiedSigner],
462			issuerKey);
463		CFRelease(issuerKey);
464		if (status) {
465			return kSecPathVerifyFailed;
466		}
467	}
468
469	if (certificatePath->selfIssued >= 0 && !certificatePath->isSelfSigned) {
470		SecKeyRef issuerKey =
471			SecCertificatePathCopyPublicKeyAtIndex(certificatePath,
472				certificatePath->selfIssued);
473		if (!issuerKey) {
474			certificatePath->selfIssued = -1;
475		} else {
476			OSStatus status = SecCertificateIsSignedBy(
477				certificatePath->certificates[certificatePath->selfIssued],
478				issuerKey);
479			CFRelease(issuerKey);
480			if (!status) {
481				certificatePath->isSelfSigned = true;
482			} else {
483				certificatePath->selfIssued = -1;
484			}
485		}
486	}
487
488	return kSecPathVerifySuccess;
489}
490
491/* Return a score for this certificate chain. */
492CFIndex SecCertificatePathScore(
493	SecCertificatePathRef certificatePath, CFAbsoluteTime verifyTime) {
494	CFIndex score = 0;
495	if (certificatePath->isAnchored) {
496		/* Anchored paths for the win! */
497		score += 10000;
498	}
499
500	/* Score points for each certificate in the chain. */
501	score += 10 * certificatePath->count;
502
503	if (certificatePath->isSelfSigned) {
504		/* If there is a self signed certificate at the end ofthe chain we
505		   count it as an extra certificate.  If there is one in the middle
506		   of the chain we count it for half. */
507		if (certificatePath->selfIssued == certificatePath->count - 1)
508			score += 10;
509		else
510			score += 5;
511	}
512
513	/* Paths that don't verify score terribly. */
514	if (certificatePath->lastVerifiedSigner != certificatePath->count - 1) {
515		secdebug("trust", "lvs: %" PRIdCFIndex " count: %" PRIdCFIndex,
516			certificatePath->lastVerifiedSigner, certificatePath->count);
517		score -= 100000;
518	}
519
520	/* Subtract 1 point for each not valid certificate, make sure we
521       subtract less than the amount we add per certificate, since
522       regardless of temporal validity we still prefer longer chains
523       to shorter ones.  This distinction is just to ensure that when
524       everything else is equal we prefer the chain with the most
525       certificates that are valid at the given verifyTime. */
526	CFIndex ix;
527	for (ix = 0; ix < certificatePath->count - 1; ++ix) {
528		if (!SecCertificateIsValid(certificatePath->certificates[ix],
529			verifyTime))
530			score -= 1;
531	}
532
533	return score;
534}
535