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 <utilities/fileIo.h>
38 CFStringRef
policyToConstant(const char *policy
);
39 int verify_cert(int argc
, char * const *argv
);
41 static int addCertFile(const char *fileName
, CFMutableArrayRef
*array
) {
42 SecCertificateRef certRef
= NULL
;
43 CFDataRef dataRef
= NULL
;
44 unsigned char *buf
= NULL
;
48 if (readFileSizet(fileName
, &buf
, &numBytes
)) {
53 dataRef
= CFDataCreate(NULL
, buf
, numBytes
);
54 certRef
= SecCertificateCreateWithData(NULL
, dataRef
);
56 certRef
= SecCertificateCreateWithPEM(NULL
, dataRef
);
64 *array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
67 CFArrayAppendValue(*array
, certRef
);
77 CFStringRef
policyToConstant(const char *policy
) {
81 else if (!strcmp(policy
, "basic")) {
82 return kSecPolicyAppleX509Basic
;
84 else if (!strcmp(policy
, "ssl")) {
85 return kSecPolicyAppleSSL
;
87 else if (!strcmp(policy
, "smime")) {
88 return kSecPolicyAppleSMIME
;
90 else if (!strcmp(policy
, "eap")) {
91 return kSecPolicyAppleEAP
;
93 else if (!strcmp(policy
, "IPSec")) {
94 return kSecPolicyAppleIPsec
;
96 else if (!strcmp(policy
, "appleID")) {
97 return kSecPolicyAppleIDValidation
;
99 else if (!strcmp(policy
, "codeSign")) {
100 return kSecPolicyAppleCodeSigning
;
102 else if (!strcmp(policy
, "timestamping")) {
103 return kSecPolicyAppleTimeStamping
;
105 else if (!strcmp(policy
, "revocation")) {
106 return kSecPolicyAppleRevocation
;
108 else if (!strcmp(policy
, "passbook")) {
109 /* Passbook not implemented */
117 int verify_cert(int argc
, char * const *argv
) {
122 CFMutableArrayRef certs
= NULL
;
123 CFMutableArrayRef roots
= NULL
;
125 CFMutableDictionaryRef dict
= NULL
;
126 CFStringRef name
= NULL
;
127 CFBooleanRef client
= kCFBooleanFalse
;
134 CFGregorianDate gregorianDate
;
135 CFDateRef dateRef
= NULL
;
137 CFStringRef policy
= NULL
;
138 SecPolicyRef policyRef
= NULL
;
139 Boolean fetch
= true;
140 SecTrustRef trustRef
= NULL
;
141 SecTrustResultType resultType
;
144 /* Return 2 triggers usage message. */
150 while ((arg
= getopt(argc
, argv
, "c:r:p:d:n:LqC")) != -1) {
153 /* Can be specified multiple times */
154 if (addCertFile(optarg
, &certs
)) {
155 fprintf(stderr
, "Cert file error\n");
161 /* Can be specified multiple times */
162 if (addCertFile(optarg
, &roots
)) {
163 fprintf(stderr
, "Root file error\n");
169 policy
= policyToConstant(optarg
);
170 if (policy
== NULL
) {
171 fprintf(stderr
, "Policy processing error\n");
177 /* Force no network fetch of certs */
182 name
= CFStringCreateWithCString(NULL
, optarg
, kCFStringEncodingUTF8
);
190 client
= kCFBooleanTrue
;
193 memset(&time
, 0, sizeof(struct tm
));
194 if (strptime(optarg
, "%Y-%m-%d-%H:%M:%S", &time
) == NULL
) {
195 if (strptime(optarg
, "%Y-%m-%d", &time
) == NULL
) {
196 fprintf(stderr
, "Date processing error\n");
202 gregorianDate
.second
= time
.tm_sec
;
203 gregorianDate
.minute
= time
.tm_min
;
204 gregorianDate
.hour
= time
.tm_hour
;
205 gregorianDate
.day
= time
.tm_mday
;
206 gregorianDate
.month
= time
.tm_mon
+ 1;
207 gregorianDate
.year
= time
.tm_year
+ 1900;
209 if (dateRef
== NULL
) {
210 dateRef
= CFDateCreate(NULL
, CFGregorianDateGetAbsoluteTime(gregorianDate
, NULL
));
214 fprintf(stderr
, "Usage error\n");
220 if (optind
!= argc
) {
225 if (policy
== NULL
) {
226 policy
= kSecPolicyAppleX509Basic
;
231 fprintf(stderr
, "No certs specified.\n");
235 if (CFArrayGetCount(roots
) != 1) {
236 fprintf(stderr
, "Multiple roots and no certs not allowed.\n");
241 /* No certs and one root: verify the root */
242 certs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
243 CFArrayAppendValue(certs
, CFArrayGetValueAtIndex(roots
, 0));
246 /* Per-policy options */
247 if (!CFStringCompare(policy
, kSecPolicyAppleSSL
, 0) || !CFStringCompare(policy
, kSecPolicyAppleIPsec
, 0)) {
248 dict
= CFDictionaryCreateMutable(NULL
, 2, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
251 fprintf(stderr
, "Name not specified for IPsec or SSL policy. '-n' is a required option for these policies.");
255 CFDictionaryAddValue(dict
, kSecPolicyName
, name
);
256 CFDictionaryAddValue(dict
, kSecPolicyClient
, client
);
258 else if (!CFStringCompare(policy
, kSecPolicyAppleEAP
, 0)) {
259 dict
= CFDictionaryCreateMutable(NULL
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
261 CFDictionaryAddValue(dict
, kSecPolicyClient
, client
);
263 else if (!CFStringCompare(policy
, kSecPolicyAppleSMIME
, 0)) {
264 dict
= CFDictionaryCreateMutable(NULL
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
267 fprintf(stderr
, "Name not specified for SMIME policy. '-n' is a required option for this policy.");
271 CFDictionaryAddValue(dict
, kSecPolicyName
, name
);
274 policyRef
= SecPolicyCreateWithProperties(policy
, dict
);
276 /* Now create a SecTrustRef and set its options */
277 ortn
= SecTrustCreateWithCertificates(certs
, policyRef
, &trustRef
);
279 fprintf(stderr
, "SecTrustCreateWithCertificates\n");
284 /* Roots (anchors) are optional */
286 ortn
= SecTrustSetAnchorCertificates(trustRef
, roots
);
288 fprintf(stderr
, "SecTrustSetAnchorCertificates\n");
293 if (fetch
== false) {
294 ortn
= SecTrustSetNetworkFetchAllowed(trustRef
, fetch
);
296 fprintf(stderr
, "SecTrustSetNetworkFetchAllowed\n");
302 /* Set verification time for trust object */
303 if (dateRef
!= NULL
) {
304 ortn
= SecTrustSetVerifyDate(trustRef
, dateRef
);
306 fprintf(stderr
, "SecTrustSetVerifyDate\n");
313 ortn
= SecTrustEvaluate(trustRef
, &resultType
);
315 /* Should never fail - error doesn't mean the cert verified badly */
316 fprintf(stderr
, "SecTrustEvaluate\n");
320 switch (resultType
) {
321 case kSecTrustResultUnspecified
:
322 /* Cert chain valid, no special UserTrust assignments */
323 case kSecTrustResultProceed
:
324 /* Cert chain valid AND user explicitly trusts this */
326 case kSecTrustResultDeny
:
327 /* User-configured denial */
329 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultDeny\n");
333 case kSecTrustResultConfirm
:
334 /* Cert chain may well have verified OK, but user has flagged
335 one of these certs as untrustable. */
337 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultConfirm\n");
341 case kSecTrustResultInvalid
:
342 /* SecTrustEvaluate not called yet */
344 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultInvalid\n");
348 case kSecTrustResultRecoverableTrustFailure
:
349 /* Failure, can be user-overridden */
351 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultRecoverableTrustFailure\n");
355 case kSecTrustResultFatalTrustFailure
:
356 /* Complete failure */
358 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultFatalTrustFailure\n");
362 case kSecTrustResultOtherError
:
363 /* Failure unrelated to trust evaluation */
365 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultOtherError\n");
370 /* Error is not a defined SecTrustResultType */
372 fprintf(stderr
, "Cert Verify Result: %u\n", resultType
);
378 if ((ourRtn
== 0) && !quiet
) {
379 printf("...certificate verification successful.\n");
387 CFRELEASE(policyRef
);