1/*
2 * Copyright (c) 2003-2007,2009-2010,2013-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 * 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#include "keychain_util.h"
60
61typedef uint32_t SecProtocolType;
62typedef uint32_t SecAuthenticationType;
63
64
65static void show_cert_eval(CFArrayRef certs, bool verbose) {
66    SecPolicyRef policy = SecPolicyCreateSSL(true, NULL);
67    SecTrustRef trust = NULL;
68    SecTrustCreateWithCertificates(certs, policy, &trust);
69    SecTrustResultType trustResult;
70    const char *trustResults[] = {
71        "invalid",
72        "proceed",
73        "confirm",
74        "deny",
75        "unspecified",
76        "recoverable trust failure",
77        "fatal trust failure",
78        "other error",
79    };
80    (void) SecTrustEvaluate(trust, &trustResult);
81    printf("* trust: %s *\n", trustResults[trustResult]);
82    CFArrayRef properties = SecTrustCopyProperties(trust);
83    print_plist(properties);
84    CFReleaseNull(properties);
85    CFIndex ix, count = SecTrustGetCertificateCount(trust);
86    for (ix = 0; ix < count; ++ix) {
87        printf("* cert %ld summary properties *\n", ix);
88        properties = SecTrustCopySummaryPropertiesAtIndex(trust, ix);
89        print_plist(properties);
90        CFReleaseNull(properties);
91        if (verbose) {
92            printf("* cert %ld detail properties *\n", ix);
93            properties = SecTrustCopyDetailedPropertiesAtIndex(trust, ix);
94            print_plist(properties);
95            CFReleaseNull(properties);
96        }
97    }
98
99    CFDictionaryRef info = SecTrustCopyInfo(trust);
100    if (info) {
101        printf("* info *\n");
102        CFShow(info);
103        CFReleaseNull(info);
104    }
105}
106
107static size_t print_buffer_pem(FILE *stream, const char *pem_name, size_t length,
108                            const uint8_t *bytes) {
109    size_t pem_name_len = strlen(pem_name);
110    size_t b64_len = SecBase64Encode2(NULL, length, NULL, 0,
111                                      kSecB64_F_LINE_LEN_USE_PARAM, 64, NULL);
112    char *buffer = malloc(33 + 2 * pem_name_len + b64_len);
113    char *p = buffer;
114    p += sprintf(buffer, "-----BEGIN %s-----\n", pem_name);
115    SecBase64Result result;
116    p += SecBase64Encode2(bytes, length, p, b64_len,\
117                          kSecB64_F_LINE_LEN_USE_PARAM, 64, &result);
118    if (result) {
119        free(buffer);
120        return result;
121    }
122    p += sprintf(p, "\n-----END %s-----\n", pem_name);
123    size_t res = fwrite(buffer, 1, p - buffer, stream);
124    fflush(stream);
125    bzero(buffer, p - buffer);
126    free(buffer);
127    return res;
128}
129
130int keychain_show_certificates(int argc, char * const *argv)
131{
132	int ch, result = 0;
133	bool output_subject = false;
134	bool verbose = false;
135    bool trust_eval = false;
136    bool keychain_certs = false;
137    bool output_pem = false;
138    bool output_finger_print = false;
139    CFMutableArrayRef certs = NULL;
140    CFMutableDictionaryRef query = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
141
142	while ((ch = getopt(argc, argv, "kfq:pstv")) != -1)
143	{
144		switch  (ch)
145		{
146        case 'k':
147            keychain_certs = true;
148            break;
149        case 'p':
150            output_pem = true;
151            break;
152		case 's':
153			output_subject = true;
154			break;
155        case 'v':
156            verbose = true;
157            break;
158		case 't':
159			trust_eval = true;
160			break;
161        case 'f':
162            output_finger_print = true;
163            break;
164        case 'q':
165            if (!keychain_query_parse_cstring(query, optarg)) {
166                CFReleaseNull(query);
167                return 1;
168            }
169            keychain_certs = true;
170            break;
171        case '?':
172		default:
173			return 2; /* @@@ Return 2 triggers usage message. */
174		}
175	}
176
177	argc -= optind;
178	argv += optind;
179
180    if ((keychain_certs && argc > 0) || (!keychain_certs && argc < 1))
181        result = 2;
182
183    if (trust_eval)
184        certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
185
186    CFArrayRef kc_certs = NULL;
187    int arg;
188    if (keychain_certs) {
189        for (arg = 0; arg < argc; ++arg) {
190            if (!keychain_query_parse_cstring(query, argv[arg])) {
191                CFReleaseSafe(query);
192                CFReleaseSafe(certs);
193                return 1;
194            }
195        }
196        CFDictionarySetValue(query, kSecClass, kSecClassCertificate);
197        CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
198        CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
199        CFTypeRef results;
200        if (!SecItemCopyMatching(query, &results)) {
201            kc_certs = results;
202            argc = (int) CFArrayGetCount(kc_certs);
203        }
204    }
205
206    for (arg = 0; arg < argc; ++arg) {
207        SecCertificateRef cert = NULL;
208        if (keychain_certs) {
209            cert = (SecCertificateRef)CFArrayGetValueAtIndex(kc_certs, arg);
210        } else {
211            CFDataRef data = copyFileContents(argv[arg]);
212            if (data) {
213                cert = SecCertificateCreateWithData(
214                    kCFAllocatorDefault, data);
215                if (!cert) {
216                    /* DER failed, try PEM. */
217                    cert = SecCertificateCreateWithPEM(kCFAllocatorDefault, data);
218                }
219                CFRelease(data);
220            } else {
221                result = 1;
222            }
223        }
224
225        if (cert) {
226            if (!keychain_certs) {
227                printf(
228                       "*******************************************************\n"
229                       "%s\n"
230                       "*******************************************************\n"
231                       , argv[arg]);
232            }
233            if (trust_eval) {
234                if (keychain_certs) {
235                    CFArraySetValueAtIndex(certs, 0, cert);
236                    show_cert_eval(certs, verbose);
237                } else {
238                    CFArrayAppendValue(certs, cert);
239                }
240            } else {
241                if (verbose) {
242                    print_cert(cert, verbose);
243                } else if (output_subject) {
244                    CFStringRef subject = SecCertificateCopySubjectString(cert);
245                    if (subject) {
246                        CFStringWriteToFileWithNewline(subject, stdout);
247                        CFRelease(subject);
248                    }
249                } else if (!output_pem) {
250                    print_cert(cert, verbose);
251                }
252            }
253            if (output_finger_print) {
254                CFDataRef key_fingerprint = SecCertificateCopyPublicKeySHA1Digest(cert);
255                if (key_fingerprint) {
256                    int i;
257                    CFIndex j = CFDataGetLength(key_fingerprint);
258                    const uint8_t *byte = CFDataGetBytePtr(key_fingerprint);
259
260                    fprintf(stdout, "Key fingerprint:");
261                    for (i = 0; i < j; i++) {
262                        fprintf(stdout, " %02X", byte[i]);
263                    }
264                    fprintf(stdout, "\n");
265                }
266                CFReleaseSafe(key_fingerprint);
267            }
268            if (output_pem) {
269                print_buffer_pem(stdout, "CERTIFICATE",
270                                 SecCertificateGetLength(cert),
271                                 SecCertificateGetBytePtr(cert));
272            }
273            if (!keychain_certs) {
274                CFRelease(cert);
275            }
276        } else {
277            result = 1;
278            fprintf(stderr, "file %s: does not contain a valid certificate",
279                argv[arg]);
280        }
281    }
282
283    if (trust_eval && !keychain_certs)
284        show_cert_eval(certs, verbose);
285
286    CFReleaseSafe(kc_certs);
287    CFReleaseSafe(certs);
288
289	return result;
290}
291
292#endif // TARGET_OS_EMBEDDED
293