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 60typedef uint32_t SecProtocolType; 61typedef uint32_t SecAuthenticationType; 62 63static void 64keychain_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 122static void 123keychain_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 130static 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 172static 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 195int 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 350