2 * Copyright (c) 2003-2007,2009-2010,2013-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 #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 CFStringRef
policyToConstant(const char *policy
);
40 int verify_cert(int argc
, char * const *argv
);
42 static int addCertFile(const char *fileName
, CFMutableArrayRef
*array
) {
43 SecCertificateRef certRef
= NULL
;
44 CFDataRef dataRef
= NULL
;
45 unsigned char *buf
= NULL
;
49 if (readFileSizet(fileName
, &buf
, &numBytes
)) {
54 dataRef
= CFDataCreate(NULL
, buf
, numBytes
);
55 certRef
= SecCertificateCreateWithData(NULL
, dataRef
);
57 certRef
= SecCertificateCreateWithPEM(NULL
, dataRef
);
65 *array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
68 CFArrayAppendValue(*array
, certRef
);
78 CFStringRef
policyToConstant(const char *policy
) {
82 else if (!strcmp(policy
, "basic")) {
83 return kSecPolicyAppleX509Basic
;
85 else if (!strcmp(policy
, "ssl")) {
86 return kSecPolicyAppleSSL
;
88 else if (!strcmp(policy
, "smime")) {
89 return kSecPolicyAppleSMIME
;
91 else if (!strcmp(policy
, "eap")) {
92 return kSecPolicyAppleEAP
;
94 else if (!strcmp(policy
, "IPSec")) {
95 return kSecPolicyAppleIPsec
;
97 else if (!strcmp(policy
, "appleID")) {
98 return kSecPolicyAppleIDValidation
;
100 else if (!strcmp(policy
, "codeSign")) {
101 return kSecPolicyAppleCodeSigning
;
103 else if (!strcmp(policy
, "timestamping")) {
104 return kSecPolicyAppleTimeStamping
;
106 else if (!strcmp(policy
, "revocation")) {
107 return kSecPolicyAppleRevocation
;
109 else if (!strcmp(policy
, "passbook")) {
110 /* Passbook not implemented */
118 static CFOptionFlags
revCheckOptionStringToFlags(
119 const char *revCheckOption
)
121 CFOptionFlags result
= 0;
122 if(revCheckOption
== NULL
) {
125 else if(!strcmp(revCheckOption
, "ocsp")) {
126 result
|= kSecRevocationOCSPMethod
;
128 else if(!strcmp(revCheckOption
, "crl")) {
129 result
|= kSecRevocationCRLMethod
;
131 else if(!strcmp(revCheckOption
, "require")) {
132 result
|= kSecRevocationRequirePositiveResponse
;
134 else if(!strcmp(revCheckOption
, "offline")) {
135 result
|= kSecRevocationNetworkAccessDisabled
;
137 else if(!strcmp(revCheckOption
, "online")) {
138 result
|= kSecRevocationOnlineCheck
;
143 int verify_cert(int argc
, char * const *argv
) {
148 CFMutableArrayRef certs
= NULL
;
149 CFMutableArrayRef roots
= NULL
;
150 CFMutableArrayRef policies
= NULL
;
152 CFMutableDictionaryRef dict
= NULL
;
153 CFStringRef name
= NULL
;
154 CFBooleanRef client
= kCFBooleanFalse
;
155 CFOptionFlags revOptions
= 0;
162 CFGregorianDate gregorianDate
;
163 CFDateRef dateRef
= NULL
;
165 CFStringRef policy
= NULL
;
166 SecPolicyRef policyRef
= NULL
;
167 SecPolicyRef revPolicyRef
= NULL
;
168 Boolean fetch
= true;
169 SecTrustRef trustRef
= NULL
;
170 SecTrustResultType resultType
;
173 /* Return 2 triggers usage message. */
179 while ((arg
= getopt(argc
, argv
, "Cc:r:p:d:n:LqR:")) != -1) {
182 /* Can be specified multiple times */
183 if (addCertFile(optarg
, &certs
)) {
184 fprintf(stderr
, "Cert file error\n");
190 /* Can be specified multiple times */
191 if (addCertFile(optarg
, &roots
)) {
192 fprintf(stderr
, "Root file error\n");
198 policy
= policyToConstant(optarg
);
199 if (policy
== NULL
) {
200 fprintf(stderr
, "Policy processing error\n");
206 /* Force no network fetch of certs */
211 name
= CFStringCreateWithCString(NULL
, optarg
, kCFStringEncodingUTF8
);
219 client
= kCFBooleanTrue
;
222 memset(&time
, 0, sizeof(struct tm
));
223 if (strptime(optarg
, "%Y-%m-%d-%H:%M:%S", &time
) == NULL
) {
224 if (strptime(optarg
, "%Y-%m-%d", &time
) == NULL
) {
225 fprintf(stderr
, "Date processing error\n");
230 gregorianDate
.second
= time
.tm_sec
;
231 gregorianDate
.minute
= time
.tm_min
;
232 gregorianDate
.hour
= time
.tm_hour
;
233 gregorianDate
.day
= time
.tm_mday
;
234 gregorianDate
.month
= time
.tm_mon
+ 1;
235 gregorianDate
.year
= time
.tm_year
+ 1900;
237 if (dateRef
== NULL
) {
238 dateRef
= CFDateCreate(NULL
, CFGregorianDateGetAbsoluteTime(gregorianDate
, NULL
));
242 revOptions
|= revCheckOptionStringToFlags(optarg
);
245 fprintf(stderr
, "Usage error\n");
251 if (optind
!= argc
) {
256 if (policy
== NULL
) {
257 policy
= kSecPolicyAppleX509Basic
;
262 fprintf(stderr
, "No certificates specified.\n");
266 if (CFArrayGetCount(roots
) != 1) {
267 fprintf(stderr
, "Multiple roots and no certificates not allowed.\n");
272 /* No certs and one root: verify the root */
273 certs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
274 CFArrayAppendValue(certs
, CFArrayGetValueAtIndex(roots
, 0));
277 /* Per-policy options */
278 if (!CFStringCompare(policy
, kSecPolicyAppleSSL
, 0) || !CFStringCompare(policy
, kSecPolicyAppleIPsec
, 0)) {
279 dict
= CFDictionaryCreateMutable(NULL
, 2, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
282 fprintf(stderr
, "Name not specified for IPsec or SSL policy. '-n' is a required option for these policies.");
286 CFDictionaryAddValue(dict
, kSecPolicyName
, name
);
287 CFDictionaryAddValue(dict
, kSecPolicyClient
, client
);
289 else if (!CFStringCompare(policy
, kSecPolicyAppleEAP
, 0)) {
290 dict
= CFDictionaryCreateMutable(NULL
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
292 CFDictionaryAddValue(dict
, kSecPolicyClient
, client
);
294 else if (!CFStringCompare(policy
, kSecPolicyAppleSMIME
, 0)) {
295 dict
= CFDictionaryCreateMutable(NULL
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
298 fprintf(stderr
, "Name not specified for SMIME policy. '-n' is a required option for this policy.");
302 CFDictionaryAddValue(dict
, kSecPolicyName
, name
);
305 policyRef
= SecPolicyCreateWithProperties(policy
, dict
);
307 /* create policies array */
308 policies
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
309 CFArrayAppendValue(policies
, policyRef
);
310 /* add optional SecPolicyRef for revocation, if specified */
311 if(revOptions
!= 0) {
312 revPolicyRef
= SecPolicyCreateRevocation(revOptions
);
313 CFArrayAppendValue(policies
, revPolicyRef
);
316 /* create trust reference from certs and policies */
317 ortn
= SecTrustCreateWithCertificates(certs
, policies
, &trustRef
);
319 fprintf(stderr
, "SecTrustCreateWithCertificates\n");
324 /* Roots (anchors) are optional */
326 ortn
= SecTrustSetAnchorCertificates(trustRef
, roots
);
328 fprintf(stderr
, "SecTrustSetAnchorCertificates\n");
333 if (fetch
== false) {
334 ortn
= SecTrustSetNetworkFetchAllowed(trustRef
, fetch
);
336 fprintf(stderr
, "SecTrustSetNetworkFetchAllowed\n");
342 /* Set verification time for trust object */
343 if (dateRef
!= NULL
) {
344 ortn
= SecTrustSetVerifyDate(trustRef
, dateRef
);
346 fprintf(stderr
, "SecTrustSetVerifyDate\n");
353 ortn
= SecTrustEvaluate(trustRef
, &resultType
);
355 /* Should never fail - error doesn't mean the cert verified badly */
356 fprintf(stderr
, "SecTrustEvaluate\n");
360 switch (resultType
) {
361 case kSecTrustResultUnspecified
:
362 /* Cert chain valid, no special UserTrust assignments */
363 case kSecTrustResultProceed
:
364 /* Cert chain valid AND user explicitly trusts this */
366 case kSecTrustResultDeny
:
367 /* User-configured denial */
369 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultDeny\n");
373 case kSecTrustResultInvalid
:
374 /* SecTrustEvaluate not called yet */
376 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultInvalid\n");
380 case kSecTrustResultRecoverableTrustFailure
:
381 /* Failure, can be user-overridden */
383 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultRecoverableTrustFailure\n");
387 case kSecTrustResultFatalTrustFailure
:
388 /* Complete failure */
390 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultFatalTrustFailure\n");
394 case kSecTrustResultOtherError
:
395 /* Failure unrelated to trust evaluation */
397 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultOtherError\n");
402 /* Error is not a defined SecTrustResultType */
404 fprintf(stderr
, "Cert Verify Result: %u\n", resultType
);
410 if ((ourRtn
== 0) && !quiet
) {
411 printf("...certificate verification successful.\n");
420 CFRELEASE(revPolicyRef
);
421 CFRELEASE(policyRef
);