2 * Copyright (c) 2006,2010,2012,2014-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@
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_utils.h"
37 #include "verify_cert.h"
38 #include <utilities/SecCFRelease.h>
39 #include "security_tool.h"
42 * Read file as a cert, add to a CFArray, creating the array if necessary
44 static int addCertFile(
46 CFMutableArrayRef
*array
)
48 SecCertificateRef certRef
;
50 if(readCertFile(fileName
, &certRef
)) {
54 *array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
56 CFArrayAppendValue(*array
, certRef
);
62 verify_cert(int argc
, char * const *argv
)
68 CFMutableArrayRef certs
= NULL
;
69 CFMutableArrayRef roots
= NULL
;
70 CFMutableArrayRef keychains
= NULL
;
71 CFMutableArrayRef policies
= NULL
;
72 const CSSM_OID
*policy
= &CSSMOID_APPLE_X509_BASIC
;
73 SecKeychainRef kcRef
= NULL
;
77 SecPolicyRef policyRef
= NULL
;
78 SecPolicyRef revPolicyRef
= NULL
;
79 SecTrustRef trustRef
= NULL
;
80 SecPolicySearchRef searchRef
= NULL
;
81 const char *emailAddrs
= NULL
;
82 const char *sslHost
= NULL
;
83 const char *name
= NULL
;
84 CSSM_APPLE_TP_SSL_OPTIONS sslOpts
;
85 CSSM_APPLE_TP_SMIME_OPTIONS smimeOpts
;
86 CSSM_APPLE_TP_ACTION_FLAGS actionFlags
= 0;
87 bool forceActionFlags
= false;
88 CSSM_APPLE_TP_ACTION_DATA actionData
;
90 CFDataRef cfActionData
= NULL
;
91 SecTrustResultType resultType
;
94 CFGregorianDate gregorianDate
;
95 CFDateRef dateRef
= NULL
;
96 CFOptionFlags revOptions
= 0;
99 return SHOW_USAGE_MESSAGE
;
101 /* permit network cert fetch unless explicitly turned off with '-L' */
102 actionFlags
|= CSSM_TP_ACTION_FETCH_CERT_FROM_NET
;
104 while ((arg
= getopt(argc
, argv
, "Cc:r:p:k:e:s:d:LlNnqR:")) != -1) {
110 /* this can be specified multiple times */
111 if(addCertFile(optarg
, &certs
)) {
117 /* this can be specified multiple times */
118 if(addCertFile(optarg
, &roots
)) {
124 policy
= policyStringToOid(optarg
);
131 ortn
= SecKeychainOpen(optarg
, &kcRef
);
133 cssmPerror("SecKeychainOpen", ortn
);
137 /* this can be specified multiple times */
138 if(keychains
== NULL
) {
139 keychains
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
141 CFArrayAppendValue(keychains
, kcRef
);
145 actionFlags
&= ~CSSM_TP_ACTION_FETCH_CERT_FROM_NET
;
146 forceActionFlags
= true;
149 actionFlags
|= CSSM_TP_ACTION_LEAF_IS_CA
;
152 /* Legacy macOS used 'n' as the "no keychain search list" flag.
153 iOS interprets it as the name option, with one argument.
155 char *o
= argv
[optind
];
156 if (o
&& o
[0] != '-') {
161 } /* intentional fall-through to "no keychains" case, if no arg */
163 /* No keychains, signalled by empty keychain array */
164 if(keychains
!= NULL
) {
165 fprintf(stderr
, "-k and -%c are mutually exclusive\n", arg
);
169 keychains
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
181 memset(&time
, 0, sizeof(struct tm
));
182 if (strptime(optarg
, "%Y-%m-%d-%H:%M:%S", &time
) == NULL
) {
183 if (strptime(optarg
, "%Y-%m-%d", &time
) == NULL
) {
184 fprintf(stderr
, "Date processing error\n");
189 gregorianDate
.second
= time
.tm_sec
;
190 gregorianDate
.minute
= time
.tm_min
;
191 gregorianDate
.hour
= time
.tm_hour
;
192 gregorianDate
.day
= time
.tm_mday
;
193 gregorianDate
.month
= time
.tm_mon
+ 1;
194 gregorianDate
.year
= time
.tm_year
+ 1900;
196 if (dateRef
== NULL
) {
197 dateRef
= CFDateCreate(NULL
, CFGregorianDateGetAbsoluteTime(gregorianDate
, NULL
));
201 revOptions
|= revCheckOptionStringToFlags(optarg
);
215 fprintf(stderr
, "***No certs specified.\n");
219 if(CFArrayGetCount(roots
) != 1) {
220 fprintf(stderr
, "***Multiple roots and no certs not allowed.\n");
225 /* no certs and one root: verify the root */
226 certs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
227 CFArrayAppendValue(certs
, CFArrayGetValueAtIndex(roots
, 0));
228 actionFlags
|= CSSM_TP_ACTION_LEAF_IS_CA
;
231 /* cook up a SecPolicyRef */
232 ortn
= SecPolicySearchCreate(CSSM_CERT_X_509v3
,
237 cssmPerror("SecPolicySearchCreate", ortn
);
241 ortn
= SecPolicySearchCopyNext(searchRef
, &policyRef
);
243 cssmPerror("SecPolicySearchCopyNext", ortn
);
248 /* per-policy options */
249 if(compareOids(policy
, &CSSMOID_APPLE_TP_SSL
) || compareOids(policy
, &CSSMOID_APPLE_TP_APPLEID_SHARING
)) {
250 const char *nameStr
= (name
) ? name
: ((sslHost
) ? sslHost
: NULL
);
252 memset(&sslOpts
, 0, sizeof(sslOpts
));
253 sslOpts
.Version
= CSSM_APPLE_TP_SSL_OPTS_VERSION
;
254 sslOpts
.ServerName
= nameStr
;
255 sslOpts
.ServerNameLen
= (uint32
) strlen(nameStr
);
256 sslOpts
.Flags
= (client
) ? CSSM_APPLE_TP_SSL_CLIENT
: 0;
257 optionData
.Data
= (uint8
*)&sslOpts
;
258 optionData
.Length
= sizeof(sslOpts
);
259 ortn
= SecPolicySetValue(policyRef
, &optionData
);
261 cssmPerror("SecPolicySetValue", ortn
);
267 if(compareOids(policy
, &CSSMOID_APPLE_TP_SMIME
)) {
268 const char *nameStr
= (name
) ? name
: ((emailAddrs
) ? emailAddrs
: NULL
);
270 memset(&smimeOpts
, 0, sizeof(smimeOpts
));
271 smimeOpts
.Version
= CSSM_APPLE_TP_SMIME_OPTS_VERSION
;
272 smimeOpts
.SenderEmail
= nameStr
;
273 smimeOpts
.SenderEmailLen
= (uint32
) strlen(nameStr
);
274 optionData
.Data
= (uint8
*)&smimeOpts
;
275 optionData
.Length
= sizeof(smimeOpts
);
276 ortn
= SecPolicySetValue(policyRef
, &optionData
);
278 cssmPerror("SecPolicySetValue", ortn
);
285 /* create policies array */
286 policies
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
287 CFArrayAppendValue(policies
, policyRef
);
288 /* add optional SecPolicyRef for revocation, if specified */
289 if(revOptions
!= 0) {
290 revPolicyRef
= SecPolicyCreateRevocation(revOptions
);
291 CFArrayAppendValue(policies
, revPolicyRef
);
294 /* create trust reference from certs and policies */
295 ortn
= SecTrustCreateWithCertificates(certs
, policies
, &trustRef
);
297 cssmPerror("SecTrustCreateWithCertificates", ortn
);
302 /* roots (anchors) are optional */
304 ortn
= SecTrustSetAnchorCertificates(trustRef
, roots
);
306 cssmPerror("SecTrustSetAnchorCertificates", ortn
);
311 if(actionFlags
|| forceActionFlags
) {
312 memset(&actionData
, 0, sizeof(actionData
));
313 actionData
.Version
= CSSM_APPLE_TP_ACTION_VERSION
;
314 actionData
.ActionFlags
= actionFlags
;
315 cfActionData
= CFDataCreate(NULL
, (UInt8
*)&actionData
, sizeof(actionData
));
316 ortn
= SecTrustSetParameters(trustRef
, CSSM_TP_ACTION_DEFAULT
, cfActionData
);
318 cssmPerror("SecTrustSetParameters", ortn
);
324 ortn
= SecTrustSetKeychains(trustRef
, keychains
);
326 cssmPerror("SecTrustSetKeychains", ortn
);
331 if(dateRef
!= NULL
) {
332 ortn
= SecTrustSetVerifyDate(trustRef
, dateRef
);
334 cssmPerror("SecTrustSetVerifyDate", ortn
);
341 ortn
= SecTrustEvaluate(trustRef
, &resultType
);
343 /* should never fail - error on this doesn't mean the cert verified badly */
344 cssmPerror("SecTrustEvaluate", ortn
);
349 case kSecTrustResultUnspecified
:
350 /* cert chain valid, no special UserTrust assignments */
351 case kSecTrustResultProceed
:
352 /* cert chain valid AND user explicitly trusts this */
354 case kSecTrustResultDeny
:
356 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultDeny\n");
363 /* See what the TP had to say about this */
364 ortn
= SecTrustGetCssmResultCode(trustRef
, &ocrtn
);
366 cssmPerror("SecTrustGetCssmResultCode", ortn
);
369 cssmPerror("Cert Verify Result", ocrtn
);
375 if((ourRtn
== 0) & !quiet
) {
376 printf("...certificate verification successful.\n");
379 CFReleaseNull(dateRef
);
383 CFRELEASE(keychains
);
385 CFRELEASE(revPolicyRef
);
386 CFRELEASE(policyRef
);
388 CFRELEASE(searchRef
);
389 CFRELEASE(cfActionData
);