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