]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/Tool/verify_cert.c
Security-57337.20.44.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
32 #include <sys/stat.h>
33 #include <stdio.h>
34 #include <time.h>
35
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);
39
40 /* Read an entire file. Copied from cuFileIo.c */
41 int readFile(
42 const char *fileName,
43 unsigned char **bytes, /* malloc'd and returned */
44 unsigned *numBytes) /* returned */
45 {
46 int rtn;
47 int fd;
48 unsigned char *buf;
49 struct stat sb;
50 unsigned size;
51
52 *numBytes = 0;
53 *bytes = NULL;
54 fd = open(fileName, O_RDONLY, 0);
55 if (fd < 0) {
56 return errno;
57 }
58
59 rtn = fstat(fd, &sb);
60 if (rtn) {
61 goto errOut;
62 }
63 size = (unsigned)sb.st_size;
64 buf = malloc(size);
65 if (buf == NULL) {
66 rtn = ENOMEM;
67 goto errOut;
68 }
69
70 rtn = (int)lseek(fd, 0, SEEK_SET);
71 if (rtn < 0) {
72 free(buf);
73 goto errOut;
74 }
75
76 rtn = (int)read(fd, buf, (size_t)size);
77 if (rtn != (int)size) {
78 if (rtn >= 0) {
79 printf("readFile: short read\n");
80 }
81 free(buf);
82 rtn = EIO;
83 }
84 else {
85 rtn = 0;
86 *bytes = buf;
87 *numBytes = size;
88 }
89 errOut:
90 close(fd);
91 return rtn;
92 }
93
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;
99 int rtn = 0;
100
101 if (readFile(fileName, &buf, &numBytes)) {
102 rtn = -1;
103 goto errOut;
104 }
105
106 dataRef = CFDataCreate(NULL, buf, numBytes);
107 certRef = SecCertificateCreateWithData(NULL, dataRef);
108
109 if (*array == NULL) {
110 *array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
111 }
112
113 CFArrayAppendValue(*array, certRef);
114
115 errOut:
116 /* Cleanup */
117 free(buf);
118 CFRELEASE(dataRef);
119 CFRELEASE(certRef);
120 return rtn;
121 }
122
123 CFStringRef policyToConstant(const char *policy) {
124 if (policy == NULL) {
125 return NULL;
126 }
127 else if (!strcmp(policy, "basic")) {
128 return kSecPolicyAppleX509Basic;
129 }
130 else if (!strcmp(policy, "ssl")) {
131 return kSecPolicyAppleSSL;
132 }
133 else if (!strcmp(policy, "smime")) {
134 return kSecPolicyAppleSMIME;
135 }
136 else if (!strcmp(policy, "eap")) {
137 return kSecPolicyAppleEAP;
138 }
139 else if (!strcmp(policy, "IPSec")) {
140 return kSecPolicyAppleIPsec;
141 }
142 else if (!strcmp(policy, "appleID")) {
143 return kSecPolicyAppleIDValidation;
144 }
145 else if (!strcmp(policy, "codeSign")) {
146 return kSecPolicyAppleCodeSigning;
147 }
148 else if (!strcmp(policy, "timestamping")) {
149 return kSecPolicyAppleTimeStamping;
150 }
151 else if (!strcmp(policy, "revocation")) {
152 return kSecPolicyAppleRevocation;
153 }
154 else if (!strcmp(policy, "passbook")) {
155 /* Passbook not implemented */
156 return NULL;
157 }
158 else {
159 return NULL;
160 }
161 }
162
163 int verify_cert(int argc, char * const *argv) {
164 extern char *optarg;
165 extern int optind;
166 int arg;
167
168 CFMutableArrayRef certs = NULL;
169 CFMutableArrayRef roots = NULL;
170
171 CFMutableDictionaryRef dict = NULL;
172 const char *name = NULL;
173 bool client = false;
174
175 OSStatus ortn;
176 int ourRtn = 0;
177 bool quiet = false;
178
179 struct tm time;
180 CFGregorianDate gregorianDate;
181 CFDateRef dateRef = NULL;
182
183 CFStringRef policy = NULL;
184 SecPolicyRef policyRef = NULL;
185 Boolean fetch = true;
186 SecTrustRef trustRef = NULL;
187 SecTrustResultType resultType;
188
189 if (argc < 2) {
190 /* Return 2 triggers usage message. */
191 return 2;
192 }
193
194 optind = 1;
195
196 while ((arg = getopt(argc, argv, "c:r:p:d:n:LqC")) != -1) {
197 switch (arg) {
198 case 'c':
199 /* Can be specified multiple times */
200 if (addCertFile(optarg, &certs)) {
201 fprintf(stderr, "Cert file error\n");
202 ourRtn = 1;
203 goto errOut;
204 }
205 break;
206 case 'r':
207 /* Can be specified multiple times */
208 if (addCertFile(optarg, &roots)) {
209 fprintf(stderr, "Root file error\n");
210 ourRtn = 1;
211 goto errOut;
212 }
213 break;
214 case 'p':
215 policy = policyToConstant(optarg);
216 if (policy == NULL) {
217 fprintf(stderr, "Policy processing error\n");
218 ourRtn = 2;
219 goto errOut;
220 }
221 break;
222 case 'L':
223 /* Force no network fetch of certs */
224 fetch = false;
225 break;
226 case 'n':
227 if (name != NULL) {
228 name = optarg;
229 }
230 break;
231 case 'q':
232 quiet = true;
233 break;
234 case 'C':
235 /* Set to client */
236 client = true;
237 break;
238 case 'd':
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");
243 ourRtn = 2;
244 goto errOut;
245 }
246 }
247
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;
254
255 if (dateRef == NULL) {
256 dateRef = CFDateCreate(NULL, CFGregorianDateGetAbsoluteTime(gregorianDate, NULL));
257 }
258 break;
259 default:
260 fprintf(stderr, "Usage error\n");
261 ourRtn = 2;
262 goto errOut;
263 }
264 }
265
266 if (optind != argc) {
267 ourRtn = 2;
268 goto errOut;
269 }
270
271 if (policy == NULL) {
272 policy = kSecPolicyAppleX509Basic;
273 }
274
275 if (certs == NULL) {
276 if (roots == NULL) {
277 fprintf(stderr, "No certs specified.\n");
278 ourRtn = 2;
279 goto errOut;
280 }
281 if (CFArrayGetCount(roots) != 1) {
282 fprintf(stderr, "Multiple roots and no certs not allowed.\n");
283 ourRtn = 2;
284 goto errOut;
285 }
286
287 /* No certs and one root: verify the root */
288 certs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
289 CFArrayAppendValue(certs, CFArrayGetValueAtIndex(roots, 0));
290 }
291
292 /* Per-policy options */
293 if (!CFStringCompare(policy, kSecPolicyAppleSSL, 0) || !CFStringCompare(policy, kSecPolicyAppleIPsec, 0)) {
294 dict = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
295
296 if (name == NULL) {
297 ourRtn = 2;
298 goto errOut;
299 }
300 CFDictionaryAddValue(dict, kSecPolicyName, name);
301 CFDictionaryAddValue(dict, kSecPolicyClient, &client);
302 }
303 else if (!CFStringCompare(policy, kSecPolicyAppleEAP, 0)) {
304 dict = CFDictionaryCreateMutable(NULL, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
305
306 CFDictionaryAddValue(dict, kSecPolicyClient, &client);
307 }
308 else if (!CFStringCompare(policy, kSecPolicyAppleSMIME, 0)) {
309 dict = CFDictionaryCreateMutable(NULL, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
310
311 if (name == NULL) {
312 ourRtn = 2;
313 goto errOut;
314 }
315 CFDictionaryAddValue(dict, kSecPolicyName, name);
316 }
317
318 policyRef = SecPolicyCreateWithProperties(policy, dict);
319
320 /* Now create a SecTrustRef and set its options */
321 ortn = SecTrustCreateWithCertificates(certs, policyRef, &trustRef);
322 if (ortn) {
323 fprintf(stderr, "SecTrustCreateWithCertificates\n");
324 ourRtn = 1;
325 goto errOut;
326 }
327
328 /* Roots (anchors) are optional */
329 if (roots != NULL) {
330 ortn = SecTrustSetAnchorCertificates(trustRef, roots);
331 if (ortn) {
332 fprintf(stderr, "SecTrustSetAnchorCertificates\n");
333 ourRtn = 1;
334 goto errOut;
335 }
336 }
337 if (fetch == false) {
338 ortn = SecTrustSetNetworkFetchAllowed(trustRef, fetch);
339 if (ortn) {
340 fprintf(stderr, "SecTrustSetNetworkFetchAllowed\n");
341 ourRtn = 1;
342 goto errOut;
343 }
344 }
345
346 /* Set verification time for trust object */
347 if (dateRef != NULL) {
348 ortn = SecTrustSetVerifyDate(trustRef, dateRef);
349 if (ortn) {
350 fprintf(stderr, "SecTrustSetVerifyDate\n");
351 ourRtn = 1;
352 goto errOut;
353 }
354 }
355
356 /* Evaluate certs */
357 ortn = SecTrustEvaluate(trustRef, &resultType);
358 if (ortn) {
359 /* Should never fail - error doesn't mean the cert verified badly */
360 fprintf(stderr, "SecTrustEvaluate\n");
361 ourRtn = 1;
362 goto errOut;
363 }
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 */
369 break;
370 case kSecTrustResultDeny:
371 /* User-configured denial */
372 if (!quiet) {
373 fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultDeny\n");
374 }
375 ourRtn = 1;
376 break;
377 case kSecTrustResultConfirm:
378 /* Cert chain may well have verified OK, but user has flagged
379 one of these certs as untrustable. */
380 if (!quiet) {
381 fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultConfirm\n");
382 }
383 ourRtn = 1;
384 break;
385 case kSecTrustResultInvalid:
386 /* SecTrustEvaluate not called yet */
387 if (!quiet) {
388 fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultInvalid\n");
389 }
390 ourRtn = 1;
391 break;
392 case kSecTrustResultRecoverableTrustFailure:
393 /* Failure, can be user-overridden */
394 if (!quiet) {
395 fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultRecoverableTrustFailure\n");
396 }
397 ourRtn = 1;
398 break;
399 case kSecTrustResultFatalTrustFailure:
400 /* Complete failure */
401 if (!quiet) {
402 fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultFatalTrustFailure\n");
403 }
404 ourRtn = 1;
405 break;
406 case kSecTrustResultOtherError:
407 /* Failure unrelated to trust evaluation */
408 if (!quiet) {
409 fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultOtherError\n");
410 }
411 ourRtn = 1;
412 break;
413 default:
414 /* Error is not a defined SecTrustResultType */
415 if (!quiet) {
416 fprintf(stderr, "Cert Verify Result: %u\n", resultType);
417 }
418 ourRtn = 1;
419 break;
420 }
421
422 if ((ourRtn == 0) && !quiet) {
423 printf("...certificate verification successful.\n");
424 }
425 errOut:
426 /* Cleanup */
427 CFRELEASE(certs);
428 CFRELEASE(roots);
429 CFRELEASE(dateRef);
430 CFRELEASE(dict);
431 CFRELEASE(policyRef);
432 CFRELEASE(trustRef);
433 return ourRtn;
434 }