]>
Commit | Line | Data |
---|---|---|
427c49bc A |
1 | /* |
2 | * Copyright (c) 2003-2007,2009-2010 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 | * keychain_find.c | |
24 | */ | |
25 | ||
26 | #include <TargetConditionals.h> | |
27 | #if TARGET_OS_EMBEDDED | |
28 | ||
29 | #include "SecurityCommands.h" | |
30 | ||
31 | #include "security.h" | |
32 | #include "SecurityTool/print_cert.h" | |
33 | #include "SecBase64.h" | |
34 | #include <errno.h> | |
35 | #include <fcntl.h> | |
36 | #include <stdio.h> | |
37 | #include <stdlib.h> | |
38 | #include <string.h> | |
39 | #include <sys/types.h> | |
40 | #include <unistd.h> | |
41 | ||
42 | #include <SecurityTool/tool_errors.h> | |
43 | ||
44 | #include <Security/SecItem.h> | |
45 | ||
46 | #include <CoreFoundation/CFArray.h> | |
47 | #include <CoreFoundation/CFDate.h> | |
48 | #include <CoreFoundation/CFNumber.h> | |
49 | #include <CoreFoundation/CFString.h> | |
50 | ||
51 | #include <Security/SecCertificatePriv.h> | |
52 | #include <Security/SecPolicyPriv.h> | |
53 | #include <Security/SecTrustPriv.h> | |
54 | #include <Security/SecInternal.h> | |
55 | ||
56 | #include <SecurityTool/readline.h> | |
57 | ||
58 | #include <utilities/SecCFWrappers.h> | |
59 | ||
60 | typedef uint32_t SecProtocolType; | |
61 | typedef uint32_t SecAuthenticationType; | |
62 | ||
63 | static void | |
64 | keychain_query_parse_string(CFMutableDictionaryRef q, CFStringRef s) { | |
65 | bool inkey = true; | |
66 | bool escaped = false; | |
67 | CFStringRef key = NULL; | |
68 | CFMutableStringRef str = CFStringCreateMutable(0, 0); | |
69 | CFRange rng = { .location = 0, .length = CFStringGetLength(s) }; | |
70 | CFCharacterSetRef cs_key = CFCharacterSetCreateWithCharactersInString(0, CFSTR("=\\")); | |
71 | CFCharacterSetRef cs_value = CFCharacterSetCreateWithCharactersInString(0, CFSTR(",\\")); | |
72 | while (rng.length) { | |
73 | CFRange r; | |
74 | CFStringRef sub; | |
75 | bool complete = false; | |
76 | if (escaped) { | |
77 | r.location = rng.location; | |
78 | r.length = 1; | |
79 | sub = CFStringCreateWithSubstring(0, s, r); | |
80 | escaped = false; | |
81 | } else if (CFStringFindCharacterFromSet(s, inkey ? cs_key : cs_value, rng, 0, &r)) { | |
82 | if (CFStringGetCharacterAtIndex(s, r.location) == '\\') { | |
83 | escaped = true; | |
84 | } else { | |
85 | complete = true; | |
86 | } | |
87 | CFIndex next = r.location + 1; | |
88 | r.length = r.location - rng.location; | |
89 | r.location = rng.location; | |
90 | sub = CFStringCreateWithSubstring(0, s, r); | |
91 | rng.length -= next - rng.location; | |
92 | rng.location = next; | |
93 | } else { | |
94 | sub = CFStringCreateWithSubstring(0, s, rng); | |
95 | rng.location += rng.length; | |
96 | rng.length = 0; | |
97 | complete = true; | |
98 | } | |
99 | CFStringAppend(str, sub); | |
100 | CFRelease(sub); | |
101 | if (complete) { | |
102 | CFStringRef value = CFStringCreateCopy(0, str); | |
103 | CFStringReplaceAll(str, CFSTR("")); | |
104 | if (inkey) { | |
105 | key = value; | |
106 | } else { | |
107 | CFDictionarySetValue(q, key, value); | |
108 | CFReleaseNull(value); | |
109 | CFReleaseNull(key); | |
110 | } | |
111 | inkey = !inkey; | |
112 | } | |
113 | } | |
114 | if (key) { | |
115 | /* Dangeling key value is true?. */ | |
116 | CFDictionarySetValue(q, key, kCFBooleanTrue); | |
117 | CFRelease(key); | |
118 | } | |
119 | CFRelease(str); | |
120 | } | |
121 | ||
122 | static void | |
123 | keychain_query_parse_cstring(CFMutableDictionaryRef q, const char *query) { | |
124 | CFStringRef s; | |
125 | s = CFStringCreateWithCStringNoCopy(0, query, kCFStringEncodingUTF8, kCFAllocatorNull); | |
126 | keychain_query_parse_string(q, s); | |
127 | CFRelease(s); | |
128 | } | |
129 | ||
130 | static void show_cert_eval(CFArrayRef certs, bool verbose) { | |
131 | SecPolicyRef policy = SecPolicyCreateSSL(true, NULL); | |
132 | SecTrustRef trust = NULL; | |
133 | OSStatus status = SecTrustCreateWithCertificates(certs, policy, &trust); | |
134 | SecTrustResultType trustResult; | |
135 | const char *trustResults[] = { | |
136 | "invalid", | |
137 | "proceed", | |
138 | "confirm", | |
139 | "deny", | |
140 | "unspecified", | |
141 | "recoverable trust failure", | |
142 | "fatal trust failure", | |
143 | "other error", | |
144 | }; | |
145 | status = SecTrustEvaluate(trust, &trustResult); | |
146 | printf("* trust: %s *\n", trustResults[trustResult]); | |
147 | CFArrayRef properties = SecTrustCopyProperties(trust); | |
148 | print_plist(properties); | |
149 | CFReleaseNull(properties); | |
150 | CFIndex ix, count = SecTrustGetCertificateCount(trust); | |
151 | for (ix = 0; ix < count; ++ix) { | |
152 | printf("* cert %ld summary properties *\n", ix); | |
153 | properties = SecTrustCopySummaryPropertiesAtIndex(trust, ix); | |
154 | print_plist(properties); | |
155 | CFReleaseNull(properties); | |
156 | if (verbose) { | |
157 | printf("* cert %ld detail properties *\n", ix); | |
158 | properties = SecTrustCopyDetailedPropertiesAtIndex(trust, ix); | |
159 | print_plist(properties); | |
160 | CFReleaseNull(properties); | |
161 | } | |
162 | } | |
163 | ||
164 | CFDictionaryRef info = SecTrustCopyInfo(trust); | |
165 | if (info) { | |
166 | printf("* info *\n"); | |
167 | CFShow(info); | |
168 | CFReleaseNull(info); | |
169 | } | |
170 | } | |
171 | ||
172 | static size_t print_buffer_pem(FILE *stream, const char *pem_name, size_t length, | |
173 | const uint8_t *bytes) { | |
174 | size_t pem_name_len = strlen(pem_name); | |
175 | size_t b64_len = SecBase64Encode2(NULL, length, NULL, 0, | |
176 | kSecB64_F_LINE_LEN_USE_PARAM, 64, NULL); | |
177 | char *buffer = malloc(33 + 2 * pem_name_len + b64_len); | |
178 | char *p = buffer; | |
179 | p += sprintf(buffer, "-----BEGIN %s-----\n", pem_name); | |
180 | SecBase64Result result; | |
181 | p += SecBase64Encode2(bytes, length, p, b64_len,\ | |
182 | kSecB64_F_LINE_LEN_USE_PARAM, 64, &result); | |
183 | if (result) { | |
184 | free(buffer); | |
185 | return result; | |
186 | } | |
187 | p += sprintf(p, "\n-----END %s-----\n", pem_name); | |
188 | size_t res = fwrite(buffer, 1, p - buffer, stream); | |
189 | fflush(stream); | |
190 | bzero(buffer, p - buffer); | |
191 | free(buffer); | |
192 | return res; | |
193 | } | |
194 | ||
195 | int keychain_show_certificates(int argc, char * const *argv) | |
196 | { | |
197 | int ch, result = 0; | |
198 | bool output_subject = false; | |
199 | bool verbose = false; | |
200 | bool trust_eval = false; | |
201 | bool keychain_certs = false; | |
202 | bool output_pem = false; | |
203 | bool output_finger_print = false; | |
204 | CFMutableArrayRef certs = NULL; | |
205 | CFMutableDictionaryRef query = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
206 | ||
207 | while ((ch = getopt(argc, argv, "kfq:pstv")) != -1) | |
208 | { | |
209 | switch (ch) | |
210 | { | |
211 | case 'k': | |
212 | keychain_certs = true; | |
213 | break; | |
214 | case 'p': | |
215 | output_pem = true; | |
216 | break; | |
217 | case 's': | |
218 | output_subject = true; | |
219 | break; | |
220 | case 'v': | |
221 | verbose = true; | |
222 | break; | |
223 | case 't': | |
224 | trust_eval = true; | |
225 | break; | |
226 | case 'f': | |
227 | output_finger_print = true; | |
228 | break; | |
229 | case 'q': | |
230 | keychain_query_parse_cstring(query, optarg); | |
231 | keychain_certs = true; | |
232 | break; | |
233 | case '?': | |
234 | default: | |
235 | return 2; /* @@@ Return 2 triggers usage message. */ | |
236 | } | |
237 | } | |
238 | ||
239 | argc -= optind; | |
240 | argv += optind; | |
241 | ||
242 | if ((keychain_certs && argc > 0) || (!keychain_certs && argc < 1)) | |
243 | result = 2; | |
244 | ||
245 | if (trust_eval) | |
246 | certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); | |
247 | ||
248 | CFArrayRef kc_certs = NULL; | |
249 | int arg; | |
250 | if (keychain_certs) { | |
251 | for (arg = 0; arg < argc; ++arg) { | |
252 | keychain_query_parse_cstring(query, argv[arg]); | |
253 | } | |
254 | CFDictionarySetValue(query, kSecClass, kSecClassCertificate); | |
255 | CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll); | |
256 | CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue); | |
257 | CFTypeRef results; | |
258 | if (!SecItemCopyMatching(query, &results)) { | |
259 | kc_certs = results; | |
260 | argc = (int) CFArrayGetCount(kc_certs); | |
261 | } | |
262 | } | |
263 | ||
264 | for (arg = 0; arg < argc; ++arg) { | |
265 | SecCertificateRef cert = NULL; | |
266 | if (keychain_certs) { | |
267 | cert = (SecCertificateRef)CFArrayGetValueAtIndex(kc_certs, arg); | |
268 | } else { | |
269 | CFDataRef data = copyFileContents(argv[arg]); | |
270 | if (data) { | |
271 | cert = SecCertificateCreateWithData( | |
272 | kCFAllocatorDefault, data); | |
273 | if (!cert) { | |
274 | /* DER failed, try PEM. */ | |
275 | cert = SecCertificateCreateWithPEM(kCFAllocatorDefault, data); | |
276 | } | |
277 | CFRelease(data); | |
278 | } else { | |
279 | result = 1; | |
280 | } | |
281 | } | |
282 | ||
283 | if (cert) { | |
284 | if (!keychain_certs) { | |
285 | printf( | |
286 | "*******************************************************\n" | |
287 | "%s\n" | |
288 | "*******************************************************\n" | |
289 | , argv[arg]); | |
290 | } | |
291 | if (trust_eval) { | |
292 | if (keychain_certs) { | |
293 | CFArraySetValueAtIndex(certs, 0, cert); | |
294 | show_cert_eval(certs, verbose); | |
295 | } else { | |
296 | CFArrayAppendValue(certs, cert); | |
297 | } | |
298 | } else { | |
299 | if (verbose) { | |
300 | print_cert(cert, verbose); | |
301 | } else if (output_subject) { | |
302 | CFStringRef subject = SecCertificateCopySubjectString(cert); | |
303 | if (subject) { | |
304 | CFStringWriteToFileWithNewline(subject, stdout); | |
305 | CFRelease(subject); | |
306 | } | |
307 | } else if (!output_pem) { | |
308 | print_cert(cert, verbose); | |
309 | } | |
310 | } | |
311 | if (output_finger_print) { | |
312 | CFDataRef key_fingerprint = SecCertificateCopyPublicKeySHA1Digest(cert); | |
313 | if (key_fingerprint) { | |
314 | int i; | |
315 | CFIndex j = CFDataGetLength(key_fingerprint); | |
316 | const uint8_t *byte = CFDataGetBytePtr(key_fingerprint); | |
317 | ||
318 | fprintf(stdout, "Key fingerprint:"); | |
319 | for (i = 0; i < j; i++) { | |
320 | fprintf(stdout, " %02X", byte[i]); | |
321 | } | |
322 | fprintf(stdout, "\n"); | |
323 | } | |
324 | } | |
325 | if (output_pem) { | |
326 | print_buffer_pem(stdout, "CERTIFICATE", | |
327 | SecCertificateGetLength(cert), | |
328 | SecCertificateGetBytePtr(cert)); | |
329 | } | |
330 | if (!keychain_certs) { | |
331 | CFRelease(cert); | |
332 | } | |
333 | } else { | |
334 | result = 1; | |
335 | fprintf(stderr, "file %s: does not contain a valid certificate", | |
336 | argv[arg]); | |
337 | } | |
338 | } | |
339 | ||
340 | if (trust_eval && !keychain_certs) | |
341 | show_cert_eval(certs, verbose); | |
342 | ||
343 | CFReleaseSafe(kc_certs); | |
344 | CFReleaseSafe(certs); | |
345 | ||
346 | return result; | |
347 | } | |
348 | ||
349 | #endif // TARGET_OS_EMBEDDED |