]> git.saurik.com Git - apple/security.git/blob - SecurityTool/verify_cert.c
Security-57740.51.3.tar.gz
[apple/security.git] / SecurityTool / verify_cert.c
1 /*
2 * Copyright (c) 2006,2010,2012,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 #include <Security/SecTrust.h>
27 #include <Security/SecKeychain.h>
28 #include <Security/SecPolicy.h>
29 #include <Security/SecPolicySearch.h>
30 #include <Security/cssmapple.h>
31 #include <Security/oidsalg.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <time.h>
36 #include "trusted_cert_utils.h"
37 #include "verify_cert.h"
38
39 /*
40 * Read file as a cert, add to a CFArray, creating the array if necessary
41 */
42 static int addCertFile(
43 const char *fileName,
44 CFMutableArrayRef *array)
45 {
46 SecCertificateRef certRef;
47
48 if(readCertFile(fileName, &certRef)) {
49 return -1;
50 }
51 if(*array == NULL) {
52 *array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
53 }
54 CFArrayAppendValue(*array, certRef);
55 CFRelease(certRef);
56 return 0;
57 }
58
59 int
60 verify_cert(int argc, char * const *argv)
61 {
62 extern char *optarg;
63 extern int optind;
64 OSStatus ortn;
65 int arg;
66 CFMutableArrayRef certs = NULL;
67 CFMutableArrayRef roots = NULL;
68 CFMutableArrayRef keychains = NULL;
69 const CSSM_OID *policy = &CSSMOID_APPLE_X509_BASIC;
70 SecKeychainRef kcRef = NULL;
71 int ourRtn = 0;
72 bool quiet = false;
73 SecPolicyRef policyRef = NULL;
74 SecTrustRef trustRef = NULL;
75 SecPolicySearchRef searchRef = NULL;
76 const char *emailAddrs = NULL;
77 const char *sslHost = NULL;
78 CSSM_APPLE_TP_SSL_OPTIONS sslOpts;
79 CSSM_APPLE_TP_SMIME_OPTIONS smimeOpts;
80 CSSM_APPLE_TP_ACTION_FLAGS actionFlags = 0;
81 bool forceActionFlags = false;
82 CSSM_APPLE_TP_ACTION_DATA actionData;
83 CSSM_DATA optionData;
84 CFDataRef cfActionData = NULL;
85 SecTrustResultType resultType;
86 OSStatus ocrtn;
87 struct tm time;
88 CFGregorianDate gregorianDate;
89 CFDateRef dateRef = NULL;
90
91 if(argc < 2) {
92 return 2; /* @@@ Return 2 triggers usage message. */
93 }
94 /* permit network cert fetch unless explicitly turned off with '-L' */
95 actionFlags |= CSSM_TP_ACTION_FETCH_CERT_FROM_NET;
96 optind = 1;
97 while ((arg = getopt(argc, argv, "c:r:p:k:e:s:d:Llnq")) != -1) {
98 switch (arg) {
99 case 'c':
100 /* this can be specified multiple times */
101 if(addCertFile(optarg, &certs)) {
102 ourRtn = 1;
103 goto errOut;
104 }
105 break;
106 case 'r':
107 /* this can be specified multiple times */
108 if(addCertFile(optarg, &roots)) {
109 ourRtn = 1;
110 goto errOut;
111 }
112 break;
113 case 'p':
114 policy = policyStringToOid(optarg);
115 if(policy == NULL) {
116 ourRtn = 2;
117 goto errOut;
118 }
119 break;
120 case 'k':
121 ortn = SecKeychainOpen(optarg, &kcRef);
122 if(ortn) {
123 cssmPerror("SecKeychainOpen", ortn);
124 ourRtn = 1;
125 goto errOut;
126 }
127 /* this can be specified multiple times */
128 if(keychains == NULL) {
129 keychains = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
130 }
131 CFArrayAppendValue(keychains, kcRef);
132 CFRelease(kcRef);
133 break;
134 case 'L':
135 actionFlags &= ~CSSM_TP_ACTION_FETCH_CERT_FROM_NET;
136 forceActionFlags = true;
137 break;
138 case 'l':
139 actionFlags |= CSSM_TP_ACTION_LEAF_IS_CA;
140 break;
141 case 'n':
142 /* No keychains, signalled by empty keychain array */
143 if(keychains != NULL) {
144 fprintf(stderr, "-k and -n are mutually exclusive\n");
145 ourRtn = 2;
146 goto errOut;
147 }
148 keychains = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
149 break;
150 case 'e':
151 emailAddrs = optarg;
152 break;
153 case 's':
154 sslHost = optarg;
155 break;
156 case 'q':
157 quiet = true;
158 break;
159 case 'd':
160 memset(&time, 0, sizeof(struct tm));
161 if (strptime(optarg, "%Y-%m-%d-%H:%M:%S", &time) == NULL) {
162 if (strptime(optarg, "%Y-%m-%d", &time) == NULL) {
163 fprintf(stderr, "Date processing error\n");
164 ourRtn = 2;
165 goto errOut;
166 }
167 }
168
169 gregorianDate.second = time.tm_sec;
170 gregorianDate.minute = time.tm_min;
171 gregorianDate.hour = time.tm_hour;
172 gregorianDate.day = time.tm_mday;
173 gregorianDate.month = time.tm_mon + 1;
174 gregorianDate.year = time.tm_year + 1900;
175
176 if (dateRef == NULL) {
177 dateRef = CFDateCreate(NULL, CFGregorianDateGetAbsoluteTime(gregorianDate, NULL));
178 }
179 break;
180 default:
181 ourRtn = 2;
182 goto errOut;
183 }
184 }
185 if(optind != argc) {
186 ourRtn = 2;
187 goto errOut;
188 }
189
190 if(certs == NULL) {
191 if(roots == NULL) {
192 fprintf(stderr, "***No certs specified.\n");
193 ourRtn = 2;
194 goto errOut;
195 }
196 if(CFArrayGetCount(roots) != 1) {
197 fprintf(stderr, "***Multiple roots and no certs not allowed.\n");
198 ourRtn = 2;
199 goto errOut;
200 }
201
202 /* no certs and one root: verify the root */
203 certs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
204 CFArrayAppendValue(certs, CFArrayGetValueAtIndex(roots, 0));
205 actionFlags |= CSSM_TP_ACTION_LEAF_IS_CA;
206 }
207
208 /* cook up a SecPolicyRef */
209 ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
210 policy,
211 NULL, // policy opts
212 &searchRef);
213 if(ortn) {
214 cssmPerror("SecPolicySearchCreate", ortn);
215 ourRtn = 1;
216 goto errOut;
217 }
218 ortn = SecPolicySearchCopyNext(searchRef, &policyRef);
219 if(ortn) {
220 cssmPerror("SecPolicySearchCopyNext", ortn);
221 ourRtn = 1;
222 goto errOut;
223 }
224
225 /* per-policy options */
226 if(compareOids(policy, &CSSMOID_APPLE_TP_SSL) || compareOids(policy, &CSSMOID_APPLE_TP_APPLEID_SHARING)) {
227 if(sslHost != NULL) {
228 memset(&sslOpts, 0, sizeof(sslOpts));
229 sslOpts.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION;
230 sslOpts.ServerName = sslHost;
231 sslOpts.ServerNameLen = (uint32) strlen(sslHost);
232 optionData.Data = (uint8 *)&sslOpts;
233 optionData.Length = sizeof(sslOpts);
234 ortn = SecPolicySetValue(policyRef, &optionData);
235 if(ortn) {
236 cssmPerror("SecPolicySetValue", ortn);
237 ourRtn = 1;
238 goto errOut;
239 }
240 }
241 }
242 if(compareOids(policy, &CSSMOID_APPLE_TP_SMIME)) {
243 if(emailAddrs != NULL) {
244 memset(&smimeOpts, 0, sizeof(smimeOpts));
245 smimeOpts.Version = CSSM_APPLE_TP_SMIME_OPTS_VERSION;
246 smimeOpts.SenderEmail = emailAddrs;
247 smimeOpts.SenderEmailLen = (uint32) strlen(emailAddrs);
248 optionData.Data = (uint8 *)&smimeOpts;
249 optionData.Length = sizeof(smimeOpts);
250 ortn = SecPolicySetValue(policyRef, &optionData);
251 if(ortn) {
252 cssmPerror("SecPolicySetValue", ortn);
253 ourRtn = 1;
254 goto errOut;
255 }
256 }
257 }
258
259 /* Now create a SecTrustRef and set its options */
260 ortn = SecTrustCreateWithCertificates(certs, policyRef, &trustRef);
261 if(ortn) {
262 cssmPerror("SecTrustCreateWithCertificates", ortn);
263 ourRtn = 1;
264 goto errOut;
265 }
266
267 /* roots (anchors) are optional */
268 if(roots != NULL) {
269 ortn = SecTrustSetAnchorCertificates(trustRef, roots);
270 if(ortn) {
271 cssmPerror("SecTrustSetAnchorCertificates", ortn);
272 ourRtn = 1;
273 goto errOut;
274 }
275 }
276 if(actionFlags || forceActionFlags) {
277 memset(&actionData, 0, sizeof(actionData));
278 actionData.Version = CSSM_APPLE_TP_ACTION_VERSION;
279 actionData.ActionFlags = actionFlags;
280 cfActionData = CFDataCreate(NULL, (UInt8 *)&actionData, sizeof(actionData));
281 ortn = SecTrustSetParameters(trustRef, CSSM_TP_ACTION_DEFAULT, cfActionData);
282 if(ortn) {
283 cssmPerror("SecTrustSetParameters", ortn);
284 ourRtn = 1;
285 goto errOut;
286 }
287 }
288 if(keychains) {
289 ortn = SecTrustSetKeychains(trustRef, keychains);
290 if(ortn) {
291 cssmPerror("SecTrustSetKeychains", ortn);
292 ourRtn = 1;
293 goto errOut;
294 }
295 }
296 if(dateRef != NULL) {
297 ortn = SecTrustSetVerifyDate(trustRef, dateRef);
298 if(ortn) {
299 cssmPerror("SecTrustSetVerifyDate", ortn);
300 ourRtn = 1;
301 goto errOut;
302 }
303 }
304
305 /* GO */
306 ortn = SecTrustEvaluate(trustRef, &resultType);
307 if(ortn) {
308 /* should never fail - error on this doesn't mean the cert verified badly */
309 cssmPerror("SecTrustEvaluate", ortn);
310 ourRtn = 1;
311 goto errOut;
312 }
313 switch(resultType) {
314 case kSecTrustResultUnspecified:
315 /* cert chain valid, no special UserTrust assignments */
316 case kSecTrustResultProceed:
317 /* cert chain valid AND user explicitly trusts this */
318 break;
319 case kSecTrustResultDeny:
320 if(!quiet) {
321 fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultDeny\n");
322 }
323 ourRtn = 1;
324 break;
325 case kSecTrustResultConfirm:
326 /*
327 * Cert chain may well have verified OK, but user has flagged
328 * one of these certs as untrustable.
329 */
330 if(!quiet) {
331 fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultConfirm\n");
332 }
333 ourRtn = 1;
334 break;
335 default:
336 ourRtn = 1;
337 if(!quiet) {
338 /* See what the TP had to say about this */
339 ortn = SecTrustGetCssmResultCode(trustRef, &ocrtn);
340 if(ortn) {
341 cssmPerror("SecTrustGetCssmResultCode", ortn);
342 }
343 else {
344 cssmPerror("Cert Verify Result", ocrtn);
345 }
346 }
347 break;
348 }
349
350 if((ourRtn == 0) & !quiet) {
351 printf("...certificate verification successful.\n");
352 }
353 errOut:
354 /* cleanup */
355 CFRELEASE(certs);
356 CFRELEASE(roots);
357 CFRELEASE(keychains);
358 CFRELEASE(policyRef);
359 CFRELEASE(trustRef);
360 CFRELEASE(searchRef);
361 CFRELEASE(cfActionData);
362 return ourRtn;
363 }