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>
36 int readFile(const char *fileName
, unsigned char **bytes
, unsigned *numBytes
);
37 CFStringRef
policyToConstant(const char *policy
);
38 int verify_cert(int argc
, char * const *argv
);
40 /* Read an entire file. Copied from cuFileIo.c */
43 unsigned char **bytes
, /* malloc'd and returned */
44 unsigned *numBytes
) /* returned */
54 fd
= open(fileName
, O_RDONLY
, 0);
63 size
= (unsigned)sb
.st_size
;
70 rtn
= (int)lseek(fd
, 0, SEEK_SET
);
76 rtn
= (int)read(fd
, buf
, (size_t)size
);
77 if (rtn
!= (int)size
) {
79 printf("readFile: short read\n");
94 static int addCertFile(const char *fileName
, CFMutableArrayRef
*array
) {
95 SecCertificateRef certRef
= NULL
;
96 CFDataRef dataRef
= NULL
;
97 unsigned char *buf
= NULL
;
98 unsigned int numBytes
;
101 if (readFile(fileName
, &buf
, &numBytes
)) {
106 dataRef
= CFDataCreate(NULL
, buf
, numBytes
);
107 certRef
= SecCertificateCreateWithData(NULL
, dataRef
);
109 if (*array
== NULL
) {
110 *array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
113 CFArrayAppendValue(*array
, certRef
);
123 CFStringRef
policyToConstant(const char *policy
) {
124 if (policy
== NULL
) {
127 else if (!strcmp(policy
, "basic")) {
128 return kSecPolicyAppleX509Basic
;
130 else if (!strcmp(policy
, "ssl")) {
131 return kSecPolicyAppleSSL
;
133 else if (!strcmp(policy
, "smime")) {
134 return kSecPolicyAppleSMIME
;
136 else if (!strcmp(policy
, "eap")) {
137 return kSecPolicyAppleEAP
;
139 else if (!strcmp(policy
, "IPSec")) {
140 return kSecPolicyAppleIPsec
;
142 else if (!strcmp(policy
, "appleID")) {
143 return kSecPolicyAppleIDValidation
;
145 else if (!strcmp(policy
, "codeSign")) {
146 return kSecPolicyAppleCodeSigning
;
148 else if (!strcmp(policy
, "timestamping")) {
149 return kSecPolicyAppleTimeStamping
;
151 else if (!strcmp(policy
, "revocation")) {
152 return kSecPolicyAppleRevocation
;
154 else if (!strcmp(policy
, "passbook")) {
155 /* Passbook not implemented */
163 int verify_cert(int argc
, char * const *argv
) {
168 CFMutableArrayRef certs
= NULL
;
169 CFMutableArrayRef roots
= NULL
;
171 CFMutableDictionaryRef dict
= NULL
;
172 const char *name
= NULL
;
180 CFGregorianDate gregorianDate
;
181 CFDateRef dateRef
= NULL
;
183 CFStringRef policy
= NULL
;
184 SecPolicyRef policyRef
= NULL
;
185 Boolean fetch
= true;
186 SecTrustRef trustRef
= NULL
;
187 SecTrustResultType resultType
;
190 /* Return 2 triggers usage message. */
196 while ((arg
= getopt(argc
, argv
, "c:r:p:d:n:LqC")) != -1) {
199 /* Can be specified multiple times */
200 if (addCertFile(optarg
, &certs
)) {
201 fprintf(stderr
, "Cert file error\n");
207 /* Can be specified multiple times */
208 if (addCertFile(optarg
, &roots
)) {
209 fprintf(stderr
, "Root file error\n");
215 policy
= policyToConstant(optarg
);
216 if (policy
== NULL
) {
217 fprintf(stderr
, "Policy processing error\n");
223 /* Force no network fetch of certs */
239 memset(&time
, 0, sizeof(struct tm
));
240 if (strptime(optarg
, "%Y-%m-%d-%H:%M:%S", &time
) == NULL
) {
241 if (strptime(optarg
, "%Y-%m-%d", &time
) == NULL
) {
242 fprintf(stderr
, "Date processing error\n");
248 gregorianDate
.second
= time
.tm_sec
;
249 gregorianDate
.minute
= time
.tm_min
;
250 gregorianDate
.hour
= time
.tm_hour
;
251 gregorianDate
.day
= time
.tm_mday
;
252 gregorianDate
.month
= time
.tm_mon
+ 1;
253 gregorianDate
.year
= time
.tm_year
+ 1900;
255 if (dateRef
== NULL
) {
256 dateRef
= CFDateCreate(NULL
, CFGregorianDateGetAbsoluteTime(gregorianDate
, NULL
));
260 fprintf(stderr
, "Usage error\n");
266 if (optind
!= argc
) {
271 if (policy
== NULL
) {
272 policy
= kSecPolicyAppleX509Basic
;
277 fprintf(stderr
, "No certs specified.\n");
281 if (CFArrayGetCount(roots
) != 1) {
282 fprintf(stderr
, "Multiple roots and no certs not allowed.\n");
287 /* No certs and one root: verify the root */
288 certs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
289 CFArrayAppendValue(certs
, CFArrayGetValueAtIndex(roots
, 0));
292 /* Per-policy options */
293 if (!CFStringCompare(policy
, kSecPolicyAppleSSL
, 0) || !CFStringCompare(policy
, kSecPolicyAppleIPsec
, 0)) {
294 dict
= CFDictionaryCreateMutable(NULL
, 2, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
300 CFDictionaryAddValue(dict
, kSecPolicyName
, name
);
301 CFDictionaryAddValue(dict
, kSecPolicyClient
, &client
);
303 else if (!CFStringCompare(policy
, kSecPolicyAppleEAP
, 0)) {
304 dict
= CFDictionaryCreateMutable(NULL
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
306 CFDictionaryAddValue(dict
, kSecPolicyClient
, &client
);
308 else if (!CFStringCompare(policy
, kSecPolicyAppleSMIME
, 0)) {
309 dict
= CFDictionaryCreateMutable(NULL
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
315 CFDictionaryAddValue(dict
, kSecPolicyName
, name
);
318 policyRef
= SecPolicyCreateWithProperties(policy
, dict
);
320 /* Now create a SecTrustRef and set its options */
321 ortn
= SecTrustCreateWithCertificates(certs
, policyRef
, &trustRef
);
323 fprintf(stderr
, "SecTrustCreateWithCertificates\n");
328 /* Roots (anchors) are optional */
330 ortn
= SecTrustSetAnchorCertificates(trustRef
, roots
);
332 fprintf(stderr
, "SecTrustSetAnchorCertificates\n");
337 if (fetch
== false) {
338 ortn
= SecTrustSetNetworkFetchAllowed(trustRef
, fetch
);
340 fprintf(stderr
, "SecTrustSetNetworkFetchAllowed\n");
346 /* Set verification time for trust object */
347 if (dateRef
!= NULL
) {
348 ortn
= SecTrustSetVerifyDate(trustRef
, dateRef
);
350 fprintf(stderr
, "SecTrustSetVerifyDate\n");
357 ortn
= SecTrustEvaluate(trustRef
, &resultType
);
359 /* Should never fail - error doesn't mean the cert verified badly */
360 fprintf(stderr
, "SecTrustEvaluate\n");
364 switch (resultType
) {
365 case kSecTrustResultUnspecified
:
366 /* Cert chain valid, no special UserTrust assignments */
367 case kSecTrustResultProceed
:
368 /* Cert chain valid AND user explicitly trusts this */
370 case kSecTrustResultDeny
:
371 /* User-configured denial */
373 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultDeny\n");
377 case kSecTrustResultConfirm
:
378 /* Cert chain may well have verified OK, but user has flagged
379 one of these certs as untrustable. */
381 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultConfirm\n");
385 case kSecTrustResultInvalid
:
386 /* SecTrustEvaluate not called yet */
388 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultInvalid\n");
392 case kSecTrustResultRecoverableTrustFailure
:
393 /* Failure, can be user-overridden */
395 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultRecoverableTrustFailure\n");
399 case kSecTrustResultFatalTrustFailure
:
400 /* Complete failure */
402 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultFatalTrustFailure\n");
406 case kSecTrustResultOtherError
:
407 /* Failure unrelated to trust evaluation */
409 fprintf(stderr
, "SecTrustEvaluate result: kSecTrustResultOtherError\n");
414 /* Error is not a defined SecTrustResultType */
416 fprintf(stderr
, "Cert Verify Result: %u\n", resultType
);
422 if ((ourRtn
== 0) && !quiet
) {
423 printf("...certificate verification successful.\n");
431 CFRELEASE(policyRef
);