2 * Copyright (c) 2017-2019 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@
23 * SecTrustStatusCodes.c - map trust result details to status codes
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>
36 struct resultmap_entry_s
{
37 const CFStringRef checkstr
;
38 const int32_t resultcode
;
40 typedef struct resultmap_entry_s resultmap_entry_t
;
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"
49 static bool SecTrustDetailsHaveEKULeafErrorOnly(CFArrayRef details
)
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;
62 if (CFDictionaryGetCount(detail
) > 0) { // No errors on other certs
63 hasDisqualifyingError
= true;
68 if (hasDisqualifyingError
) {
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
78 static bool SecTrustIsDevelopmentUpdateSigning(SecTrustRef trust
)
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
;
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
))) {
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
))) {
108 CFReleaseSafe(policies
);
109 CFReleaseSafe(policy
);
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.
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.
121 // Caller must free the returned pointer.
123 SInt32
*SecTrustCopyStatusCodes(SecTrustRef trust
,
124 CFIndex index
, CFIndex
*numStatusCodes
)
126 if (!trust
|| !numStatusCodes
) {
130 CFArrayRef details
= SecTrustCopyFilteredDetails(trust
);
131 CFIndex chainLength
= (details
) ? CFArrayGetCount(details
) : 0;
132 if (!(index
< chainLength
)) {
133 CFReleaseSafe(details
);
136 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, index
);
137 CFIndex ix
, detailCount
= CFDictionaryGetCount(detail
);
138 *numStatusCodes
= (unsigned int)detailCount
;
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;
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
;
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]
163 SecTrustIsDevelopmentUpdateSigning(trust
) &&
164 SecTrustDetailsHaveEKULeafErrorOnly(details
)) {
165 statusCode
= (SInt32
)0x80012433; /* CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT */
167 } else if (statusCode
== (SInt32
)0x8001210C) { /* CSSMERR_TP_CERT_REVOKED */
169 CFNumberRef number
= (CFNumberRef
)CFDictionaryGetValue(detail
, key
);
170 if (number
&& CFNumberGetValue(number
, kCFNumberSInt32Type
, &reason
)) {
171 statusCodes
[*numStatusCodes
] = (SInt32
)reason
;
174 statusCodes
[ix
] = statusCode
;
177 CFReleaseSafe(details
);