2 * Copyright (c) 2003-2018 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 #define CFRELEASE(cf) if (cf) { CFRelease(cf); }
28 #include <Security/SecCertificate.h>
29 #include <Security/SecCertificatePriv.h>
30 #include <Security/SecTrust.h>
31 #include <Security/SecPolicy.h>
32 #include <Security/SecPolicyPriv.h>
33 #include <utilities/fileIo.h>
39 #include "SecurityCommands.h"
41 CFStringRef
policyToConstant(const char *policy
);
42 int verify_cert(int argc
, char * const *argv
);
44 static int addCertFile(const char *fileName
, CFMutableArrayRef
*array
) {
45 SecCertificateRef certRef
= NULL
;
46 CFDataRef dataRef
= NULL
;
47 unsigned char *buf
= NULL
;
51 if (readFileSizet(fileName
, &buf
, &numBytes
)) {
56 dataRef
= CFDataCreate(NULL
, buf
, numBytes
);
57 certRef
= SecCertificateCreateWithData(NULL
, dataRef
);
59 certRef
= SecCertificateCreateWithPEM(NULL
, dataRef
);
67 *array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
70 CFArrayAppendValue(*array
, certRef
);
80 CFStringRef
policyToConstant(const char *policy
) {
84 else if (!strcmp(policy
, "basic")) {
85 return kSecPolicyAppleX509Basic
;
87 else if (!strcmp(policy
, "ssl")) {
88 return kSecPolicyAppleSSL
;
90 else if (!strcmp(policy
, "smime")) {
91 return kSecPolicyAppleSMIME
;
93 else if (!strcmp(policy
, "eap")) {
94 return kSecPolicyAppleEAP
;
96 else if (!strcmp(policy
, "IPSec")) {
97 return kSecPolicyAppleIPsec
;
99 else if (!strcmp(policy
, "appleID")) {
100 return kSecPolicyAppleIDValidation
;
102 else if (!strcmp(policy
, "codeSign")) {
103 return kSecPolicyAppleCodeSigning
;
105 else if (!strcmp(policy
, "timestamping")) {
106 return kSecPolicyAppleTimeStamping
;
108 else if (!strcmp(policy
, "revocation")) {
109 return kSecPolicyAppleRevocation
;
111 else if (!strcmp(policy
, "passbook")) {
112 /* Passbook not implemented */
120 static CFOptionFlags
revCheckOptionStringToFlags(
121 const char *revCheckOption
)
123 CFOptionFlags result
= 0;
124 if(revCheckOption
== NULL
) {
127 else if(!strcmp(revCheckOption
, "ocsp")) {
128 result
|= kSecRevocationOCSPMethod
;
130 else if(!strcmp(revCheckOption
, "crl")) {
131 result
|= kSecRevocationCRLMethod
;
133 else if(!strcmp(revCheckOption
, "require")) {
134 result
|= kSecRevocationRequirePositiveResponse
;
136 else if(!strcmp(revCheckOption
, "offline")) {
137 result
|= kSecRevocationNetworkAccessDisabled
;
139 else if(!strcmp(revCheckOption
, "online")) {
140 result
|= kSecRevocationOnlineCheck
;
145 int verify_cert(int argc
, char * const *argv
) {
150 CFMutableArrayRef certs
= NULL
;
151 CFMutableArrayRef roots
= NULL
;
152 CFMutableArrayRef policies
= NULL
;
154 CFMutableDictionaryRef dict
= NULL
;
155 CFStringRef name
= NULL
;
156 CFBooleanRef client
= kCFBooleanFalse
;
157 CFOptionFlags revOptions
= 0;
164 CFGregorianDate gregorianDate
;
165 CFDateRef dateRef
= NULL
;
167 CFStringRef policy
= NULL
;
168 SecPolicyRef policyRef
= NULL
;
169 SecPolicyRef revPolicyRef
= NULL
;
170 Boolean fetch
= true;
171 SecTrustRef trustRef
= NULL
;
172 SecTrustResultType resultType
;
175 return SHOW_USAGE_MESSAGE
;
180 while ((arg
= getopt(argc
, argv
, "Cc:r:p:d:n:LqR:")) != -1) {
183 /* Can be specified multiple times */
184 if (addCertFile(optarg
, &certs
)) {
185 fprintf(stderr
, "Cert file error\n");
191 /* Can be specified multiple times */
192 if (addCertFile(optarg
, &roots
)) {
193 fprintf(stderr
, "Root file error\n");
199 policy
= policyToConstant(optarg
);
200 if (policy
== NULL
) {
201 fprintf(stderr
, "Policy processing error\n");
207 /* Force no network fetch of certs */
212 name
= CFStringCreateWithCString(NULL
, optarg
, kCFStringEncodingUTF8
);
220 client
= kCFBooleanTrue
;
223 memset(&time
, 0, sizeof(struct tm
));
224 if (strptime(optarg
, "%Y-%m-%d-%H:%M:%S", &time
) == NULL
) {
225 if (strptime(optarg
, "%Y-%m-%d", &time
) == NULL
) {
226 fprintf(stderr
, "Date processing error\n");
231 gregorianDate
.second
= time
.tm_sec
;
232 gregorianDate
.minute
= time
.tm_min
;
233 gregorianDate
.hour
= time
.tm_hour
;
234 gregorianDate
.day
= time
.tm_mday
;
235 gregorianDate
.month
= time
.tm_mon
+ 1;
236 gregorianDate
.year
= time
.tm_year
+ 1900;
238 if (dateRef
== NULL
) {
239 dateRef
= CFDateCreate(NULL
, CFGregorianDateGetAbsoluteTime(gregorianDate
, NULL
));
243 revOptions
|= revCheckOptionStringToFlags(optarg
);
246 fprintf(stderr
, "Usage error\n");
252 if (optind
!= argc
) {
257 if (policy
== NULL
) {
258 policy
= kSecPolicyAppleX509Basic
;
263 fprintf(stderr
, "No certificates specified.\n");
267 if (CFArrayGetCount(roots
) != 1) {
268 fprintf(stderr
, "Multiple roots and no certificates not allowed.\n");
273 /* No certs and one root: verify the root */
274 certs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
275 CFArrayAppendValue(certs
, CFArrayGetValueAtIndex(roots
, 0));
278 /* Per-policy options */
279 if (!CFStringCompare(policy
, kSecPolicyAppleSSL
, 0) || !CFStringCompare(policy
, kSecPolicyAppleIPsec
, 0)) {
280 dict
= CFDictionaryCreateMutable(NULL
, 2, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
283 fprintf(stderr
, "Name not specified for IPsec or SSL policy. '-n' is a required option for these policies.");
287 CFDictionaryAddValue(dict
, kSecPolicyName
, name
);
288 CFDictionaryAddValue(dict
, kSecPolicyClient
, client
);
290 else if (!CFStringCompare(policy
, kSecPolicyAppleEAP
, 0)) {
291 dict
= CFDictionaryCreateMutable(NULL
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
293 CFDictionaryAddValue(dict
, kSecPolicyClient
, client
);
295 else if (!CFStringCompare(policy
, kSecPolicyAppleSMIME
, 0)) {
296 dict
= CFDictionaryCreateMutable(NULL
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
299 fprintf(stderr
, "Name not specified for SMIME policy. '-n' is a required option for this policy.");
303 CFDictionaryAddValue(dict
, kSecPolicyName
, name
);
306 policyRef
= SecPolicyCreateWithProperties(policy
, dict
);
308 /* create policies array */
309 policies
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
310 CFArrayAppendValue(policies
, policyRef
);
311 /* add optional SecPolicyRef for revocation, if specified */
312 if(revOptions
!= 0) {
313 revPolicyRef
= SecPolicyCreateRevocation(revOptions
);
314 CFArrayAppendValue(policies
, revPolicyRef
);
317 /* create trust reference from certs and policies */
318 ortn
= SecTrustCreateWithCertificates(certs
, policies
, &trustRef
);
320 fprintf(stderr
, "SecTrustCreateWithCertificates\n");
325 /* Roots (anchors) are optional */
327 ortn
= SecTrustSetAnchorCertificates(trustRef
, roots
);
329 fprintf(stderr
, "SecTrustSetAnchorCertificates\n");
334 if (fetch
== false) {
335 ortn
= SecTrustSetNetworkFetchAllowed(trustRef
, fetch
);
337 fprintf(stderr
, "SecTrustSetNetworkFetchAllowed\n");
343 /* Set verification time for trust object */
344 if (dateRef
!= NULL
) {
345 ortn
= SecTrustSetVerifyDate(trustRef
, dateRef
);
347 fprintf(stderr
, "SecTrustSetVerifyDate\n");
354 ortn
= SecTrustEvaluate(trustRef
, &resultType
);
356 /* Should never fail - error doesn't mean the cert verified badly */
357 fprintf(stderr
, "SecTrustEvaluate\n");
361 switch (resultType
) {
362 case kSecTrustResultUnspecified
:
363 /* Cert chain valid, no special UserTrust assignments */
364 case kSecTrustResultProceed
:
365 /* Cert chain valid AND user explicitly trusts this */
367 case kSecTrustResultDeny
:
368 /* User-configured denial */
370 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultDeny\n");
374 case kSecTrustResultInvalid
:
375 /* SecTrustEvaluate not called yet */
377 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultInvalid\n");
381 case kSecTrustResultRecoverableTrustFailure
:
382 /* Failure, can be user-overridden */
384 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultRecoverableTrustFailure\n");
388 case kSecTrustResultFatalTrustFailure
:
389 /* Complete failure */
391 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultFatalTrustFailure\n");
395 case kSecTrustResultOtherError
:
396 /* Failure unrelated to trust evaluation */
398 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultOtherError\n");
403 /* Error is not a defined SecTrustResultType */
405 fprintf(stderr
, "Cert Verify Result: %u\n", resultType
);
411 if ((ourRtn
== 0) && !quiet
) {
412 printf("...certificate verification successful.\n");
421 CFRELEASE(revPolicyRef
);
422 CFRELEASE(policyRef
);