]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/Tool/verify_cert.c
Security-57740.31.2.tar.gz
[apple/security.git] / OSX / sec / Security / Tool / verify_cert.c
1 /*
2 * Copyright (c) 2003-2007,2009-2010,2013-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 *
23 * verify-cert.c
24 */
25
26 #define CFRELEASE(cf) if (cf) { CFRelease(cf); }
27
28 #include <Security/SecCertificate.h>
29 #include <Security/SecTrust.h>
30 #include <Security/SecPolicy.h>
31 #include <utilities/fileIo.h>
32
33 #include <sys/stat.h>
34 #include <stdio.h>
35 #include <time.h>
36
37 CFStringRef policyToConstant(const char *policy);
38 int verify_cert(int argc, char * const *argv);
39
40 static int addCertFile(const char *fileName, CFMutableArrayRef *array) {
41 SecCertificateRef certRef = NULL;
42 CFDataRef dataRef = NULL;
43 unsigned char *buf = NULL;
44 size_t numBytes;
45 int rtn = 0;
46
47 if (readFileSizet(fileName, &buf, &numBytes)) {
48 rtn = -1;
49 goto errOut;
50 }
51
52 dataRef = CFDataCreate(NULL, buf, numBytes);
53 certRef = SecCertificateCreateWithData(NULL, dataRef);
54
55 if (*array == NULL) {
56 *array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
57 }
58
59 CFArrayAppendValue(*array, certRef);
60
61 errOut:
62 /* Cleanup */
63 free(buf);
64 CFRELEASE(dataRef);
65 CFRELEASE(certRef);
66 return rtn;
67 }
68
69 CFStringRef policyToConstant(const char *policy) {
70 if (policy == NULL) {
71 return NULL;
72 }
73 else if (!strcmp(policy, "basic")) {
74 return kSecPolicyAppleX509Basic;
75 }
76 else if (!strcmp(policy, "ssl")) {
77 return kSecPolicyAppleSSL;
78 }
79 else if (!strcmp(policy, "smime")) {
80 return kSecPolicyAppleSMIME;
81 }
82 else if (!strcmp(policy, "eap")) {
83 return kSecPolicyAppleEAP;
84 }
85 else if (!strcmp(policy, "IPSec")) {
86 return kSecPolicyAppleIPsec;
87 }
88 else if (!strcmp(policy, "appleID")) {
89 return kSecPolicyAppleIDValidation;
90 }
91 else if (!strcmp(policy, "codeSign")) {
92 return kSecPolicyAppleCodeSigning;
93 }
94 else if (!strcmp(policy, "timestamping")) {
95 return kSecPolicyAppleTimeStamping;
96 }
97 else if (!strcmp(policy, "revocation")) {
98 return kSecPolicyAppleRevocation;
99 }
100 else if (!strcmp(policy, "passbook")) {
101 /* Passbook not implemented */
102 return NULL;
103 }
104 else {
105 return NULL;
106 }
107 }
108
109 int verify_cert(int argc, char * const *argv) {
110 extern char *optarg;
111 extern int optind;
112 int arg;
113
114 CFMutableArrayRef certs = NULL;
115 CFMutableArrayRef roots = NULL;
116
117 CFMutableDictionaryRef dict = NULL;
118 CFStringRef name = NULL;
119 CFBooleanRef client = kCFBooleanFalse;
120
121 OSStatus ortn;
122 int ourRtn = 0;
123 bool quiet = false;
124
125 struct tm time;
126 CFGregorianDate gregorianDate;
127 CFDateRef dateRef = NULL;
128
129 CFStringRef policy = NULL;
130 SecPolicyRef policyRef = NULL;
131 Boolean fetch = true;
132 SecTrustRef trustRef = NULL;
133 SecTrustResultType resultType;
134
135 if (argc < 2) {
136 /* Return 2 triggers usage message. */
137 return 2;
138 }
139
140 optind = 1;
141
142 while ((arg = getopt(argc, argv, "c:r:p:d:n:LqC")) != -1) {
143 switch (arg) {
144 case 'c':
145 /* Can be specified multiple times */
146 if (addCertFile(optarg, &certs)) {
147 fprintf(stderr, "Cert file error\n");
148 ourRtn = 1;
149 goto errOut;
150 }
151 break;
152 case 'r':
153 /* Can be specified multiple times */
154 if (addCertFile(optarg, &roots)) {
155 fprintf(stderr, "Root file error\n");
156 ourRtn = 1;
157 goto errOut;
158 }
159 break;
160 case 'p':
161 policy = policyToConstant(optarg);
162 if (policy == NULL) {
163 fprintf(stderr, "Policy processing error\n");
164 ourRtn = 2;
165 goto errOut;
166 }
167 break;
168 case 'L':
169 /* Force no network fetch of certs */
170 fetch = false;
171 break;
172 case 'n':
173 if (name == NULL) {
174 name = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8);
175 }
176 break;
177 case 'q':
178 quiet = true;
179 break;
180 case 'C':
181 /* Set to client */
182 client = kCFBooleanTrue;
183 break;
184 case 'd':
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");
189 ourRtn = 2;
190 goto errOut;
191 }
192 }
193
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;
200
201 if (dateRef == NULL) {
202 dateRef = CFDateCreate(NULL, CFGregorianDateGetAbsoluteTime(gregorianDate, NULL));
203 }
204 break;
205 default:
206 fprintf(stderr, "Usage error\n");
207 ourRtn = 2;
208 goto errOut;
209 }
210 }
211
212 if (optind != argc) {
213 ourRtn = 2;
214 goto errOut;
215 }
216
217 if (policy == NULL) {
218 policy = kSecPolicyAppleX509Basic;
219 }
220
221 if (certs == NULL) {
222 if (roots == NULL) {
223 fprintf(stderr, "No certs specified.\n");
224 ourRtn = 2;
225 goto errOut;
226 }
227 if (CFArrayGetCount(roots) != 1) {
228 fprintf(stderr, "Multiple roots and no certs not allowed.\n");
229 ourRtn = 2;
230 goto errOut;
231 }
232
233 /* No certs and one root: verify the root */
234 certs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
235 CFArrayAppendValue(certs, CFArrayGetValueAtIndex(roots, 0));
236 }
237
238 /* Per-policy options */
239 if (!CFStringCompare(policy, kSecPolicyAppleSSL, 0) || !CFStringCompare(policy, kSecPolicyAppleIPsec, 0)) {
240 dict = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
241
242 if (name == NULL) {
243 fprintf(stderr, "Name not specified for IPsec or SSL policy. '-n' is a required option for these policies.");
244 ourRtn = 2;
245 goto errOut;
246 }
247 CFDictionaryAddValue(dict, kSecPolicyName, name);
248 CFDictionaryAddValue(dict, kSecPolicyClient, client);
249 }
250 else if (!CFStringCompare(policy, kSecPolicyAppleEAP, 0)) {
251 dict = CFDictionaryCreateMutable(NULL, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
252
253 CFDictionaryAddValue(dict, kSecPolicyClient, client);
254 }
255 else if (!CFStringCompare(policy, kSecPolicyAppleSMIME, 0)) {
256 dict = CFDictionaryCreateMutable(NULL, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
257
258 if (name == NULL) {
259 fprintf(stderr, "Name not specified for SMIME policy. '-n' is a required option for this policy.");
260 ourRtn = 2;
261 goto errOut;
262 }
263 CFDictionaryAddValue(dict, kSecPolicyName, name);
264 }
265
266 policyRef = SecPolicyCreateWithProperties(policy, dict);
267
268 /* Now create a SecTrustRef and set its options */
269 ortn = SecTrustCreateWithCertificates(certs, policyRef, &trustRef);
270 if (ortn) {
271 fprintf(stderr, "SecTrustCreateWithCertificates\n");
272 ourRtn = 1;
273 goto errOut;
274 }
275
276 /* Roots (anchors) are optional */
277 if (roots != NULL) {
278 ortn = SecTrustSetAnchorCertificates(trustRef, roots);
279 if (ortn) {
280 fprintf(stderr, "SecTrustSetAnchorCertificates\n");
281 ourRtn = 1;
282 goto errOut;
283 }
284 }
285 if (fetch == false) {
286 ortn = SecTrustSetNetworkFetchAllowed(trustRef, fetch);
287 if (ortn) {
288 fprintf(stderr, "SecTrustSetNetworkFetchAllowed\n");
289 ourRtn = 1;
290 goto errOut;
291 }
292 }
293
294 /* Set verification time for trust object */
295 if (dateRef != NULL) {
296 ortn = SecTrustSetVerifyDate(trustRef, dateRef);
297 if (ortn) {
298 fprintf(stderr, "SecTrustSetVerifyDate\n");
299 ourRtn = 1;
300 goto errOut;
301 }
302 }
303
304 /* Evaluate certs */
305 ortn = SecTrustEvaluate(trustRef, &resultType);
306 if (ortn) {
307 /* Should never fail - error doesn't mean the cert verified badly */
308 fprintf(stderr, "SecTrustEvaluate\n");
309 ourRtn = 1;
310 goto errOut;
311 }
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 */
317 break;
318 case kSecTrustResultDeny:
319 /* User-configured denial */
320 if (!quiet) {
321 fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultDeny\n");
322 }
323 ourRtn = 1;
324 break;
325 case kSecTrustResultConfirm:
326 /* Cert chain may well have verified OK, but user has flagged
327 one of these certs as untrustable. */
328 if (!quiet) {
329 fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultConfirm\n");
330 }
331 ourRtn = 1;
332 break;
333 case kSecTrustResultInvalid:
334 /* SecTrustEvaluate not called yet */
335 if (!quiet) {
336 fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultInvalid\n");
337 }
338 ourRtn = 1;
339 break;
340 case kSecTrustResultRecoverableTrustFailure:
341 /* Failure, can be user-overridden */
342 if (!quiet) {
343 fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultRecoverableTrustFailure\n");
344 }
345 ourRtn = 1;
346 break;
347 case kSecTrustResultFatalTrustFailure:
348 /* Complete failure */
349 if (!quiet) {
350 fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultFatalTrustFailure\n");
351 }
352 ourRtn = 1;
353 break;
354 case kSecTrustResultOtherError:
355 /* Failure unrelated to trust evaluation */
356 if (!quiet) {
357 fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultOtherError\n");
358 }
359 ourRtn = 1;
360 break;
361 default:
362 /* Error is not a defined SecTrustResultType */
363 if (!quiet) {
364 fprintf(stderr, "Cert Verify Result: %u\n", resultType);
365 }
366 ourRtn = 1;
367 break;
368 }
369
370 if ((ourRtn == 0) && !quiet) {
371 printf("...certificate verification successful.\n");
372 }
373 errOut:
374 /* Cleanup */
375 CFRELEASE(certs);
376 CFRELEASE(roots);
377 CFRELEASE(dateRef);
378 CFRELEASE(dict);
379 CFRELEASE(policyRef);
380 CFRELEASE(trustRef);
381 CFRELEASE(name);
382 return ourRtn;
383 }