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