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