2 * Copyright (c) 2006,2010,2012,2014-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@
26 #include <Security/SecTrust.h>
27 #include <Security/SecKeychain.h>
28 #include <Security/SecPolicy.h>
29 #include <Security/SecPolicySearch.h>
30 #include <Security/cssmapple.h>
31 #include <Security/oidsalg.h>
36 #include "trusted_cert_ssl.h"
37 #include "trusted_cert_utils.h"
38 #include "verify_cert.h"
39 #include <utilities/SecCFRelease.h>
40 #include "security_tool.h"
43 * Read file as a cert, add to a CFArray, creating the array if necessary
45 static int addCertFile(
47 CFMutableArrayRef
*array
)
49 SecCertificateRef certRef
;
51 if(readCertFile(fileName
, &certRef
)) {
55 *array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
57 CFArrayAppendValue(*array
, certRef
);
63 verify_cert(int argc
, char * const *argv
)
69 CFMutableArrayRef certs
= NULL
;
70 CFMutableArrayRef roots
= NULL
;
71 CFMutableArrayRef keychains
= NULL
;
72 CFMutableArrayRef policies
= NULL
;
73 CFMutableDictionaryRef properties
= NULL
;
74 const CSSM_OID
*policy
= &CSSMOID_APPLE_X509_BASIC
;
75 SecKeychainRef kcRef
= NULL
;
80 bool printPem
= false;
81 bool printText
= false;
82 bool printDetails
= false;
84 SecPolicyRef policyRef
= NULL
;
85 SecPolicyRef revPolicyRef
= NULL
;
86 SecTrustRef trustRef
= NULL
;
87 SecPolicySearchRef searchRef
= NULL
;
88 CFErrorRef errorRef
= NULL
;
89 const char *emailAddrs
= NULL
;
90 const char *sslHost
= NULL
;
91 const char *name
= NULL
;
92 const char *url
= NULL
;
93 CSSM_APPLE_TP_ACTION_FLAGS actionFlags
= 0;
94 bool forceActionFlags
= false;
95 CSSM_APPLE_TP_ACTION_DATA actionData
;
96 CFDataRef cfActionData
= NULL
;
97 SecTrustResultType resultType
;
100 CFGregorianDate gregorianDate
;
101 CFDateRef dateRef
= NULL
;
102 CFOptionFlags revOptions
= 0;
105 return SHOW_USAGE_MESSAGE
;
107 /* permit network cert fetch unless explicitly turned off with '-L' */
108 actionFlags
|= CSSM_TP_ACTION_FETCH_CERT_FROM_NET
;
110 while ((arg
= getopt(argc
, argv
, "Cc:r:p:k:e:s:d:LlNnPqR:tv")) != -1) {
116 /* this can be specified multiple times */
117 if(addCertFile(optarg
, &certs
)) {
123 /* this can be specified multiple times */
124 if(addCertFile(optarg
, &roots
)) {
130 policy
= policyStringToOid(optarg
, &useTLS
);
137 ortn
= SecKeychainOpen(optarg
, &kcRef
);
139 cssmPerror("SecKeychainOpen", ortn
);
143 /* this can be specified multiple times */
144 if(keychains
== NULL
) {
145 keychains
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
147 CFArrayAppendValue(keychains
, kcRef
);
151 actionFlags
&= ~CSSM_TP_ACTION_FETCH_CERT_FROM_NET
;
152 forceActionFlags
= true;
155 actionFlags
|= CSSM_TP_ACTION_LEAF_IS_CA
;
158 /* Legacy macOS used 'n' as the "no keychain search list" flag.
159 iOS interprets it as the name option, with one argument.
161 char *o
= argv
[optind
];
162 if (o
&& o
[0] != '-') {
167 } /* intentional fall-through to "no keychains" case, if no arg */
169 /* No keychains, signalled by empty keychain array */
170 if(keychains
!= NULL
) {
171 fprintf(stderr
, "-k and -%c are mutually exclusive\n", arg
);
175 keychains
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
187 memset(&time
, 0, sizeof(struct tm
));
188 if (strptime(optarg
, "%Y-%m-%d-%H:%M:%S", &time
) == NULL
) {
189 if (strptime(optarg
, "%Y-%m-%d", &time
) == NULL
) {
190 fprintf(stderr
, "Date processing error\n");
195 gregorianDate
.second
= time
.tm_sec
;
196 gregorianDate
.minute
= time
.tm_min
;
197 gregorianDate
.hour
= time
.tm_hour
;
198 gregorianDate
.day
= time
.tm_mday
;
199 gregorianDate
.month
= time
.tm_mon
+ 1;
200 gregorianDate
.year
= time
.tm_year
+ 1900;
202 if (dateRef
== NULL
) {
203 dateRef
= CFDateCreate(NULL
, CFGregorianDateGetAbsoluteTime(gregorianDate
, NULL
));
207 revOptions
|= revCheckOptionStringToFlags(optarg
);
228 if (url
&& *url
!= '\0') {
230 ourRtn
= evaluate_ssl(url
, verbose
, &trustRef
);
240 fprintf(stderr
, "***No certs specified.\n");
244 if(CFArrayGetCount(roots
) != 1) {
245 fprintf(stderr
, "***Multiple roots and no certs not allowed.\n");
250 /* no certs and one root: verify the root */
251 certs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
252 CFArrayAppendValue(certs
, CFArrayGetValueAtIndex(roots
, 0));
253 actionFlags
|= CSSM_TP_ACTION_LEAF_IS_CA
;
256 /* cook up a SecPolicyRef */
257 properties
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
258 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
260 cssmPerror("CFDictionaryCreateMutable", errSecMemoryError
);
264 /* if a policy name was specified to match, set it in the dictionary */
265 const char *nameStr
= name
;
266 if (!nameStr
) { nameStr
= (sslHost
) ? sslHost
: ((emailAddrs
) ? emailAddrs
: NULL
); }
267 CFStringRef nameRef
= (nameStr
) ? CFStringCreateWithBytes(NULL
,
268 (const UInt8
*)nameStr
, (CFIndex
)strlen(nameStr
), kCFStringEncodingUTF8
, false) : NULL
;
270 CFDictionarySetValue(properties
, kSecPolicyName
, nameRef
);
273 CFStringRef policyID
= NULL
;
274 if (compareOids(policy
, &CSSMOID_APPLE_TP_SSL
)) {
275 policyID
= kSecPolicyAppleSSL
;
276 } else if (compareOids(policy
, &CSSMOID_APPLE_TP_EAP
)) {
277 policyID
= kSecPolicyAppleEAP
;
278 } else if (compareOids(policy
, &CSSMOID_APPLE_TP_APPLEID_SHARING
)) {
279 policyID
= kSecPolicyAppleIDValidation
;
280 } else if (compareOids(policy
, &CSSMOID_APPLE_TP_SMIME
)) {
281 policyID
= kSecPolicyAppleSMIME
;
284 policyRef
= SecPolicyCreateWithProperties(policyID
, properties
);
288 /* all other policies not handled above */
289 ortn
= SecPolicySearchCreate(CSSM_CERT_X_509v3
,
294 cssmPerror("SecPolicySearchCreate", ortn
);
298 ortn
= SecPolicySearchCopyNext(searchRef
, &policyRef
);
300 cssmPerror("SecPolicySearchCopyNext", ortn
);
306 /* create policies array */
307 policies
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
308 CFArrayAppendValue(policies
, policyRef
);
309 /* add optional SecPolicyRef for revocation, if specified */
310 if(revOptions
!= 0) {
311 revPolicyRef
= SecPolicyCreateRevocation(revOptions
);
312 CFArrayAppendValue(policies
, revPolicyRef
);
315 /* create trust reference from certs and policies */
316 ortn
= SecTrustCreateWithCertificates(certs
, policies
, &trustRef
);
318 cssmPerror("SecTrustCreateWithCertificates", ortn
);
323 /* roots (anchors) are optional */
325 ortn
= SecTrustSetAnchorCertificates(trustRef
, roots
);
327 cssmPerror("SecTrustSetAnchorCertificates", ortn
);
332 if(actionFlags
|| forceActionFlags
) {
333 memset(&actionData
, 0, sizeof(actionData
));
334 actionData
.Version
= CSSM_APPLE_TP_ACTION_VERSION
;
335 actionData
.ActionFlags
= actionFlags
;
336 cfActionData
= CFDataCreate(NULL
, (UInt8
*)&actionData
, sizeof(actionData
));
337 ortn
= SecTrustSetParameters(trustRef
, CSSM_TP_ACTION_DEFAULT
, cfActionData
);
339 cssmPerror("SecTrustSetParameters", ortn
);
345 ortn
= SecTrustSetKeychains(trustRef
, keychains
);
347 cssmPerror("SecTrustSetKeychains", ortn
);
352 if(dateRef
!= NULL
) {
353 ortn
= SecTrustSetVerifyDate(trustRef
, dateRef
);
355 cssmPerror("SecTrustSetVerifyDate", ortn
);
362 (void)SecTrustEvaluateWithError(trustRef
, &errorRef
);
364 ortn
= SecTrustGetTrustResult(trustRef
, &resultType
);
366 /* should never fail - error on this doesn't mean the cert verified badly */
367 cssmPerror("SecTrustEvaluate", ortn
);
372 case kSecTrustResultUnspecified
:
373 /* cert chain valid, no special UserTrust assignments */
374 case kSecTrustResultProceed
:
375 /* cert chain valid AND user explicitly trusts this */
377 case kSecTrustResultDeny
:
379 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultDeny\n");
386 /* See what the TP had to say about this */
387 ortn
= SecTrustGetCssmResultCode(trustRef
, &ocrtn
);
389 cssmPerror("SecTrustGetCssmResultCode", ortn
);
392 cssmPerror("Cert Verify Result", ocrtn
);
397 if((ourRtn
== 0) & !quiet
) {
398 printf("...certificate verification successful.\n");
400 if (printPem
|| printText
|| verbose
) {
401 fprintf(stdout
, "---\nCertificate chain\n");
402 printCertChain(trustRef
, printPem
, printText
);
405 printErrorDetails(trustRef
);
408 printExtendedResults(trustRef
);
411 CFArrayRef properties
= SecTrustCopyProperties(trustRef
);
413 fprintf(stderr
, "---\nCertificate chain properties\n");
414 CFShow(properties
); // output goes to stderr
417 CFRelease(properties
);
419 CFDictionaryRef result
= SecTrustCopyResult(trustRef
);
421 fprintf(stderr
, "---\nTrust evaluation results\n");
422 CFShow(result
); // output goes to stderr
426 fprintf(stdout
, "---\nTrust evaluation errors\n");
435 CFRELEASE(keychains
);
436 CFRELEASE(properties
);
438 CFRELEASE(revPolicyRef
);
440 CFRELEASE(policyRef
);
442 CFRELEASE(searchRef
);
444 CFRELEASE(cfActionData
);