]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecTrustStatusCodes.c
Security-59306.11.20.tar.gz
[apple/security.git] / OSX / sec / Security / SecTrustStatusCodes.c
1 /*
2 * Copyright (c) 2017-2019 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 * SecTrustStatusCodes.c - map trust result details to status codes
24 *
25 */
26
27 #include <Security/Security.h>
28 #include <Security/SecTrustPriv.h>
29 #include <Security/SecPolicyPriv.h>
30 #include <Security/SecCertificatePriv.h>
31 #include <Security/SecInternal.h>
32 #include <Security/SecTrustStatusCodes.h>
33 #include <CoreFoundation/CoreFoundation.h>
34 #include <libDER/oids.h>
35
36 struct resultmap_entry_s {
37 const CFStringRef checkstr;
38 const int32_t resultcode;
39 };
40 typedef struct resultmap_entry_s resultmap_entry_t;
41
42 const resultmap_entry_t resultmap[] = {
43 #undef POLICYCHECKMACRO
44 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
45 { CFSTR(#NAME), CSSMERR },
46 #include "SecPolicyChecks.list"
47 };
48
49 static bool SecTrustDetailsHaveEKULeafErrorOnly(CFArrayRef details)
50 {
51 CFIndex ix, count = (details) ? CFArrayGetCount(details) : 0;
52 bool hasDisqualifyingError = false;
53 for (ix = 0; ix < count; ix++) {
54 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
55 if (ix == 0) { // Leaf
56 if (CFDictionaryGetCount(detail) != 1 || // One error
57 CFDictionaryGetValue(detail, kSecPolicyCheckExtendedKeyUsage) != kCFBooleanFalse) {
58 hasDisqualifyingError = true;
59 break;
60 }
61 } else {
62 if (CFDictionaryGetCount(detail) > 0) { // No errors on other certs
63 hasDisqualifyingError = true;
64 break;
65 }
66 }
67 }
68 if (hasDisqualifyingError) {
69 return false;
70 }
71 return true;
72 }
73
74 // Returns true if both of the following are true:
75 // - policy is Apple SW Update Signing
76 // - leaf certificate has the oidAppleExtendedKeyUsageCodeSigningDev EKU purpose
77 //
78 static bool SecTrustIsDevelopmentUpdateSigning(SecTrustRef trust)
79 {
80 bool result = false;
81 CFArrayRef policies = NULL; /* must release */
82 SecPolicyRef policy = NULL; /* must release */
83 SecCertificateRef cert = NULL;
84 CFArrayRef ekus = NULL; /* must release */
85 CFDataRef eku = NULL; /* must release */
86 const DERItem *oid = &oidAppleExtendedKeyUsageCodeSigningDev;
87
88 /* Apple SW Update Signing policy check */
89 if ((SecTrustCopyPolicies(trust, &policies) != errSecSuccess) ||
90 ((policy = SecPolicyCreateAppleSWUpdateSigning()) == NULL) ||
91 (!CFArrayContainsValue(policies, CFRangeMake(0, CFArrayGetCount(policies)), policy))) {
92 goto exit;
93 }
94
95 /* Apple Code Signing Dev EKU check */
96 if (((cert = SecTrustGetCertificateAtIndex(trust, 0)) == NULL) ||
97 ((ekus = SecCertificateCopyExtendedKeyUsage(cert)) == NULL) ||
98 ((eku = CFDataCreate(kCFAllocatorDefault, oid->data, oid->length)) == NULL) ||
99 (!CFArrayContainsValue(ekus, CFRangeMake(0, CFArrayGetCount(ekus)), eku))) {
100 goto exit;
101 }
102
103 result = true;
104
105 exit:
106 CFReleaseSafe(eku);
107 CFReleaseSafe(ekus);
108 CFReleaseSafe(policies);
109 CFReleaseSafe(policy);
110 return result;
111 }
112
113 //
114 // Returns a malloced array of SInt32 values, with the length in numStatusCodes,
115 // for the certificate specified by chain index in the given SecTrustRef.
116 //
117 // To match legacy behavior, the array actually allocates one element more than the
118 // value of numStatusCodes; if the certificate is revoked, the additional element
119 // at the end contains the CrlReason value.
120 //
121 // Caller must free the returned pointer.
122 //
123 SInt32 *SecTrustCopyStatusCodes(SecTrustRef trust,
124 CFIndex index, CFIndex *numStatusCodes)
125 {
126 if (!trust || !numStatusCodes) {
127 return NULL;
128 }
129 *numStatusCodes = 0;
130 CFArrayRef details = SecTrustCopyFilteredDetails(trust);
131 CFIndex chainLength = (details) ? CFArrayGetCount(details) : 0;
132 if (!(index < chainLength)) {
133 CFReleaseSafe(details);
134 return NULL;
135 }
136 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, index);
137 CFIndex ix, detailCount = CFDictionaryGetCount(detail);
138 *numStatusCodes = (unsigned int)detailCount;
139
140 // Allocate one more entry than we need; this is used to store a CrlReason
141 // at the end of the array.
142 SInt32 *statusCodes = (SInt32*)malloc((detailCount+1) * sizeof(SInt32));
143 statusCodes[*numStatusCodes] = 0;
144
145 const unsigned int resultmaplen = sizeof(resultmap) / sizeof(resultmap_entry_t);
146 const void *keys[detailCount];
147 CFDictionaryGetKeysAndValues(detail, &keys[0], NULL);
148 for (ix = 0; ix < detailCount; ix++) {
149 CFStringRef key = (CFStringRef)keys[ix];
150 SInt32 statusCode = 0;
151 for (unsigned int mapix = 0; mapix < resultmaplen; mapix++) {
152 CFStringRef str = (CFStringRef) resultmap[mapix].checkstr;
153 if (CFStringCompare(str, key, 0) == kCFCompareEqualTo) {
154 statusCode = (SInt32) resultmap[mapix].resultcode;
155 break;
156 }
157 }
158 if (statusCode == (SInt32)0x80012407) { /* CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE */
159 // To match legacy behavior, we return a more specific result code if this is a
160 // development signing certificate being evaluated for Apple SW Update Signing.
161 // [27362805,41179903]
162 if (index == 0 &&
163 SecTrustIsDevelopmentUpdateSigning(trust) &&
164 SecTrustDetailsHaveEKULeafErrorOnly(details)) {
165 statusCode = (SInt32)0x80012433; /* CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT */
166 }
167 } else if (statusCode == (SInt32)0x8001210C) { /* CSSMERR_TP_CERT_REVOKED */
168 SInt32 reason;
169 CFNumberRef number = (CFNumberRef)CFDictionaryGetValue(detail, key);
170 if (number && CFNumberGetValue(number, kCFNumberSInt32Type, &reason)) {
171 statusCodes[*numStatusCodes] = (SInt32)reason;
172 }
173 }
174 statusCodes[ix] = statusCode;
175 }
176
177 CFReleaseSafe(details);
178 return statusCodes;
179 }