2 * Copyright (c) 2003-2007,2009-2010,2013-2014 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/SecTrust.h>
30 #include <Security/SecPolicy.h>
31 #include <utilities/fileIo.h>
37 CFStringRef
policyToConstant(const char *policy
);
38 int verify_cert(int argc
, char * const *argv
);
40 static int addCertFile(const char *fileName
, CFMutableArrayRef
*array
) {
41 SecCertificateRef certRef
= NULL
;
42 CFDataRef dataRef
= NULL
;
43 unsigned char *buf
= NULL
;
47 if (readFileSizet(fileName
, &buf
, &numBytes
)) {
52 dataRef
= CFDataCreate(NULL
, buf
, numBytes
);
53 certRef
= SecCertificateCreateWithData(NULL
, dataRef
);
56 *array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
59 CFArrayAppendValue(*array
, certRef
);
69 CFStringRef
policyToConstant(const char *policy
) {
73 else if (!strcmp(policy
, "basic")) {
74 return kSecPolicyAppleX509Basic
;
76 else if (!strcmp(policy
, "ssl")) {
77 return kSecPolicyAppleSSL
;
79 else if (!strcmp(policy
, "smime")) {
80 return kSecPolicyAppleSMIME
;
82 else if (!strcmp(policy
, "eap")) {
83 return kSecPolicyAppleEAP
;
85 else if (!strcmp(policy
, "IPSec")) {
86 return kSecPolicyAppleIPsec
;
88 else if (!strcmp(policy
, "appleID")) {
89 return kSecPolicyAppleIDValidation
;
91 else if (!strcmp(policy
, "codeSign")) {
92 return kSecPolicyAppleCodeSigning
;
94 else if (!strcmp(policy
, "timestamping")) {
95 return kSecPolicyAppleTimeStamping
;
97 else if (!strcmp(policy
, "revocation")) {
98 return kSecPolicyAppleRevocation
;
100 else if (!strcmp(policy
, "passbook")) {
101 /* Passbook not implemented */
109 int verify_cert(int argc
, char * const *argv
) {
114 CFMutableArrayRef certs
= NULL
;
115 CFMutableArrayRef roots
= NULL
;
117 CFMutableDictionaryRef dict
= NULL
;
118 CFStringRef name
= NULL
;
119 CFBooleanRef client
= kCFBooleanFalse
;
126 CFGregorianDate gregorianDate
;
127 CFDateRef dateRef
= NULL
;
129 CFStringRef policy
= NULL
;
130 SecPolicyRef policyRef
= NULL
;
131 Boolean fetch
= true;
132 SecTrustRef trustRef
= NULL
;
133 SecTrustResultType resultType
;
136 /* Return 2 triggers usage message. */
142 while ((arg
= getopt(argc
, argv
, "c:r:p:d:n:LqC")) != -1) {
145 /* Can be specified multiple times */
146 if (addCertFile(optarg
, &certs
)) {
147 fprintf(stderr
, "Cert file error\n");
153 /* Can be specified multiple times */
154 if (addCertFile(optarg
, &roots
)) {
155 fprintf(stderr
, "Root file error\n");
161 policy
= policyToConstant(optarg
);
162 if (policy
== NULL
) {
163 fprintf(stderr
, "Policy processing error\n");
169 /* Force no network fetch of certs */
174 name
= CFStringCreateWithCString(NULL
, optarg
, kCFStringEncodingUTF8
);
182 client
= kCFBooleanTrue
;
185 memset(&time
, 0, sizeof(struct tm
));
186 if (strptime(optarg
, "%Y-%m-%d-%H:%M:%S", &time
) == NULL
) {
187 if (strptime(optarg
, "%Y-%m-%d", &time
) == NULL
) {
188 fprintf(stderr
, "Date processing error\n");
194 gregorianDate
.second
= time
.tm_sec
;
195 gregorianDate
.minute
= time
.tm_min
;
196 gregorianDate
.hour
= time
.tm_hour
;
197 gregorianDate
.day
= time
.tm_mday
;
198 gregorianDate
.month
= time
.tm_mon
+ 1;
199 gregorianDate
.year
= time
.tm_year
+ 1900;
201 if (dateRef
== NULL
) {
202 dateRef
= CFDateCreate(NULL
, CFGregorianDateGetAbsoluteTime(gregorianDate
, NULL
));
206 fprintf(stderr
, "Usage error\n");
212 if (optind
!= argc
) {
217 if (policy
== NULL
) {
218 policy
= kSecPolicyAppleX509Basic
;
223 fprintf(stderr
, "No certs specified.\n");
227 if (CFArrayGetCount(roots
) != 1) {
228 fprintf(stderr
, "Multiple roots and no certs not allowed.\n");
233 /* No certs and one root: verify the root */
234 certs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
235 CFArrayAppendValue(certs
, CFArrayGetValueAtIndex(roots
, 0));
238 /* Per-policy options */
239 if (!CFStringCompare(policy
, kSecPolicyAppleSSL
, 0) || !CFStringCompare(policy
, kSecPolicyAppleIPsec
, 0)) {
240 dict
= CFDictionaryCreateMutable(NULL
, 2, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
243 fprintf(stderr
, "Name not specified for IPsec or SSL policy. '-n' is a required option for these policies.");
247 CFDictionaryAddValue(dict
, kSecPolicyName
, name
);
248 CFDictionaryAddValue(dict
, kSecPolicyClient
, client
);
250 else if (!CFStringCompare(policy
, kSecPolicyAppleEAP
, 0)) {
251 dict
= CFDictionaryCreateMutable(NULL
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
253 CFDictionaryAddValue(dict
, kSecPolicyClient
, client
);
255 else if (!CFStringCompare(policy
, kSecPolicyAppleSMIME
, 0)) {
256 dict
= CFDictionaryCreateMutable(NULL
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
259 fprintf(stderr
, "Name not specified for SMIME policy. '-n' is a required option for this policy.");
263 CFDictionaryAddValue(dict
, kSecPolicyName
, name
);
266 policyRef
= SecPolicyCreateWithProperties(policy
, dict
);
268 /* Now create a SecTrustRef and set its options */
269 ortn
= SecTrustCreateWithCertificates(certs
, policyRef
, &trustRef
);
271 fprintf(stderr
, "SecTrustCreateWithCertificates\n");
276 /* Roots (anchors) are optional */
278 ortn
= SecTrustSetAnchorCertificates(trustRef
, roots
);
280 fprintf(stderr
, "SecTrustSetAnchorCertificates\n");
285 if (fetch
== false) {
286 ortn
= SecTrustSetNetworkFetchAllowed(trustRef
, fetch
);
288 fprintf(stderr
, "SecTrustSetNetworkFetchAllowed\n");
294 /* Set verification time for trust object */
295 if (dateRef
!= NULL
) {
296 ortn
= SecTrustSetVerifyDate(trustRef
, dateRef
);
298 fprintf(stderr
, "SecTrustSetVerifyDate\n");
305 ortn
= SecTrustEvaluate(trustRef
, &resultType
);
307 /* Should never fail - error doesn't mean the cert verified badly */
308 fprintf(stderr
, "SecTrustEvaluate\n");
312 switch (resultType
) {
313 case kSecTrustResultUnspecified
:
314 /* Cert chain valid, no special UserTrust assignments */
315 case kSecTrustResultProceed
:
316 /* Cert chain valid AND user explicitly trusts this */
318 case kSecTrustResultDeny
:
319 /* User-configured denial */
321 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultDeny\n");
325 case kSecTrustResultConfirm
:
326 /* Cert chain may well have verified OK, but user has flagged
327 one of these certs as untrustable. */
329 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultConfirm\n");
333 case kSecTrustResultInvalid
:
334 /* SecTrustEvaluate not called yet */
336 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultInvalid\n");
340 case kSecTrustResultRecoverableTrustFailure
:
341 /* Failure, can be user-overridden */
343 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultRecoverableTrustFailure\n");
347 case kSecTrustResultFatalTrustFailure
:
348 /* Complete failure */
350 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultFatalTrustFailure\n");
354 case kSecTrustResultOtherError
:
355 /* Failure unrelated to trust evaluation */
357 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultOtherError\n");
362 /* Error is not a defined SecTrustResultType */
364 fprintf(stderr
, "Cert Verify Result: %u\n", resultType
);
370 if ((ourRtn
== 0) && !quiet
) {
371 printf("...certificate verification successful.\n");
379 CFRELEASE(policyRef
);