/* * Copyright (c) 2003-2007,2009-2010,2013-2014 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ * * keychain_find.c */ #include #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR #include "SecurityCommands.h" #include "security.h" #include "SecurityTool/sharedTool/print_cert.h" #include "SecBase64.h" #include #include #include #include #include #include #include #include "SecurityTool/sharedTool/tool_errors.h" #include #include #include #include #include #include #include #include #include #include #include #include "SecurityTool/sharedTool/readline.h" #include #include "keychain_util.h" typedef uint32_t SecProtocolType; typedef uint32_t SecAuthenticationType; static void show_cert_eval(CFArrayRef certs, bool verbose) { SecPolicyRef policy = SecPolicyCreateSSL(true, NULL); SecTrustRef trust = NULL; SecTrustCreateWithCertificates(certs, policy, &trust); SecTrustResultType trustResult; const char *trustResults[] = { "invalid", "proceed", "confirm", "deny", "unspecified", "recoverable trust failure", "fatal trust failure", "other error", }; (void) SecTrustEvaluate(trust, &trustResult); printf("* trust: %s *\n", trustResults[trustResult]); CFArrayRef properties = SecTrustCopyProperties(trust); print_plist(properties); CFReleaseNull(properties); CFIndex ix, count = SecTrustGetCertificateCount(trust); for (ix = 0; ix < count; ++ix) { printf("* cert %ld summary properties *\n", ix); properties = SecTrustCopySummaryPropertiesAtIndex(trust, ix); print_plist(properties); CFReleaseNull(properties); if (verbose) { printf("* cert %ld detail properties *\n", ix); properties = SecTrustCopyDetailedPropertiesAtIndex(trust, ix); print_plist(properties); CFReleaseNull(properties); } } CFDictionaryRef info = SecTrustCopyInfo(trust); if (info) { printf("* info *\n"); CFShow(info); CFReleaseNull(info); } CFReleaseNull(policy); } static size_t print_buffer_pem(FILE *stream, const char *pem_name, size_t length, const uint8_t *bytes) { size_t pem_name_len = strlen(pem_name); size_t b64_len = SecBase64Encode2(NULL, length, NULL, 0, kSecB64_F_LINE_LEN_USE_PARAM, 64, NULL); char *buffer = malloc(33 + 2 * pem_name_len + b64_len); char *p = buffer; p += sprintf(buffer, "-----BEGIN %s-----\n", pem_name); SecBase64Result result; p += SecBase64Encode2(bytes, length, p, b64_len,\ kSecB64_F_LINE_LEN_USE_PARAM, 64, &result); if (result) { free(buffer); return result; } p += sprintf(p, "\n-----END %s-----\n", pem_name); size_t res = fwrite(buffer, 1, p - buffer, stream); fflush(stream); bzero(buffer, p - buffer); free(buffer); return res; } int keychain_show_certificates(int argc, char * const *argv) { int ch, result = 0; bool output_subject = false; bool verbose = false; bool trust_eval = false; bool keychain_certs = false; bool output_pem = false; bool output_finger_print = false; CFMutableArrayRef certs = NULL; CFMutableDictionaryRef query = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); while ((ch = getopt(argc, argv, "kfq:pstv")) != -1) { switch (ch) { case 'k': keychain_certs = true; break; case 'p': output_pem = true; break; case 's': output_subject = true; break; case 'v': verbose = true; break; case 't': trust_eval = true; break; case 'f': output_finger_print = true; break; case 'q': if (!keychain_query_parse_cstring(query, optarg)) { CFReleaseNull(query); return 1; } keychain_certs = true; break; case '?': default: return SHOW_USAGE_MESSAGE; } } argc -= optind; argv += optind; if ((keychain_certs && argc > 0) || (!keychain_certs && argc < 1)) result = 2; if (trust_eval) certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); CFArrayRef kc_certs = NULL; int arg; if (keychain_certs) { for (arg = 0; arg < argc; ++arg) { if (!keychain_query_parse_cstring(query, argv[arg])) { CFReleaseSafe(query); CFReleaseSafe(certs); return 1; } } CFDictionarySetValue(query, kSecClass, kSecClassCertificate); CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll); CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue); CFTypeRef results; if (!SecItemCopyMatching(query, &results)) { kc_certs = results; argc = (int) CFArrayGetCount(kc_certs); } } for (arg = 0; arg < argc; ++arg) { SecCertificateRef cert = NULL; if (keychain_certs) { cert = (SecCertificateRef)CFArrayGetValueAtIndex(kc_certs, arg); } else { CFDataRef data = copyFileContents(argv[arg]); if (data) { cert = SecCertificateCreateWithData( kCFAllocatorDefault, data); if (!cert) { /* DER failed, try PEM. */ cert = SecCertificateCreateWithPEM(kCFAllocatorDefault, data); } CFRelease(data); } else { result = 1; } } if (cert) { if (!keychain_certs) { printf( "*******************************************************\n" "%s\n" "*******************************************************\n" , argv[arg]); } if (trust_eval) { if (keychain_certs) { CFArraySetValueAtIndex(certs, 0, cert); show_cert_eval(certs, verbose); } else { CFArrayAppendValue(certs, cert); } } else { if (verbose) { print_cert(cert, verbose); } else if (output_subject) { CFStringRef subject = SecCertificateCopySubjectString(cert); if (subject) { CFStringWriteToFileWithNewline(subject, stdout); CFRelease(subject); } } else if (!output_pem) { print_cert(cert, verbose); } } if (output_finger_print) { CFDataRef key_fingerprint = SecCertificateCopyPublicKeySHA1Digest(cert); if (key_fingerprint) { int i; CFIndex j = CFDataGetLength(key_fingerprint); const uint8_t *byte = CFDataGetBytePtr(key_fingerprint); fprintf(stdout, "Key fingerprint:"); for (i = 0; i < j; i++) { fprintf(stdout, " %02X", byte[i]); } fprintf(stdout, "\n"); } CFReleaseSafe(key_fingerprint); } if (output_pem) { print_buffer_pem(stdout, "CERTIFICATE", SecCertificateGetLength(cert), SecCertificateGetBytePtr(cert)); } if (!keychain_certs) { CFRelease(cert); } } else { result = 1; fprintf(stderr, "file %s: does not contain a valid certificate", argv[arg]); } } if (trust_eval && !keychain_certs) show_cert_eval(certs, verbose); CFReleaseSafe(kc_certs); CFReleaseSafe(certs); return result; } static bool isSettingWithResult(CFDictionaryRef setting, SecTrustSettingsResult result) { CFNumberRef value = CFDictionaryGetValue(setting, kSecTrustSettingsResult); if (!isNumberOfType(value, kCFNumberSInt64Type)) { return false; } int64_t setting_result = 0; if (!CFNumberGetValue(value, kCFNumberSInt64Type, &setting_result) || (setting_result != result)) { return false; } return true; } static bool isUnconstrainedSettingWithResult(CFDictionaryRef setting, SecTrustSettingsResult result) { if (!isDictionary(setting) || (CFDictionaryGetCount(setting) != 1)) { return false; } return isSettingWithResult(setting, result); } static bool isDenyTrustSetting(CFArrayRef trust_settings) { if (CFArrayGetCount(trust_settings) != 1) { return false; } return isUnconstrainedSettingWithResult(CFArrayGetValueAtIndex(trust_settings, 0), kSecTrustSettingsResultDeny); } static bool isPartialSSLTrustSetting(CFArrayRef trust_settings) { if (CFArrayGetCount(trust_settings) != 2) { return false; } /* Second setting is a blanket "Trust" */ if (!isUnconstrainedSettingWithResult(CFArrayGetValueAtIndex(trust_settings, 1), kSecTrustSettingsResultTrustRoot) && !isUnconstrainedSettingWithResult(CFArrayGetValueAtIndex(trust_settings, 1), kSecTrustSettingsResultTrustAsRoot)) { return false; } /* First setting is "upspecified" for SSL policy */ CFDictionaryRef setting = CFArrayGetValueAtIndex(trust_settings, 0); if (!isDictionary(setting) || (CFDictionaryGetCount(setting) < 2)) { return false; } if (!isSettingWithResult(setting, kSecTrustSettingsResultUnspecified)) { return false; } if (!CFEqualSafe(CFDictionaryGetValue(setting, kSecTrustSettingsPolicy), kSecPolicyAppleSSL)) { return false; } return true; } int trust_store_show_certificates(int argc, char * const *argv) { int ch, result = 0; bool output_subject = false; bool verbose = false; bool trust_settings = false; bool output_pem = false; bool output_finger_print = false; bool output_keyid = false; CFArrayRef certs = NULL; while ((ch = getopt(argc, argv, "fpstvk")) != -1) { switch (ch) { case 'p': output_pem = true; break; case 's': output_subject = true; break; case 'v': verbose = true; break; case 't': trust_settings = true; break; case 'f': output_finger_print = true; break; case 'k': output_keyid = true; break; case '?': default: return SHOW_USAGE_MESSAGE; } } if(SecTrustStoreCopyAll(SecTrustStoreForDomain(kSecTrustStoreDomainUser), &certs) || !certs) { fprintf(stderr, "failed to get trust store contents for user\n"); return 1; } CFIndex ix, count = CFArrayGetCount(certs); if (count) printf("*******************************************************\n"); for (ix = 0; ix < count; ix++) { CFArrayRef certSettingsPair = NULL; CFDataRef certData = NULL; SecCertificateRef cert = NULL; certSettingsPair = CFArrayGetValueAtIndex(certs, ix); certData = (CFDataRef)CFArrayGetValueAtIndex(certSettingsPair, 0); cert = SecCertificateCreateWithData(kCFAllocatorDefault, certData); if (!cert) { fprintf(stderr, "failed to get cert at %ld\n",ix); return 1; } if (verbose) { print_cert(cert, verbose); } else if (output_subject) { CFStringRef subject = SecCertificateCopySubjectString(cert); if (subject) { CFStringWriteToFileWithNewline(subject, stdout); CFRelease(subject); } } else if (output_pem) { print_buffer_pem(stdout, "CERTIFICATE", SecCertificateGetLength(cert), SecCertificateGetBytePtr(cert)); } else { print_cert(cert, verbose); } if (output_keyid) { CFDataRef key_fingerprint = SecCertificateCopyPublicKeySHA1Digest(cert); if (key_fingerprint) { int i; CFIndex j = CFDataGetLength(key_fingerprint); const uint8_t *byte = CFDataGetBytePtr(key_fingerprint); fprintf(stdout, "Keyid:"); for (i = 0; i < j; i++) { fprintf(stdout, " %02X", byte[i]); } fprintf(stdout, "\n"); } CFReleaseSafe(key_fingerprint); } if (output_finger_print) { CFDataRef fingerprint = SecCertificateGetSHA1Digest(cert); if (fingerprint) { int i; CFIndex j = CFDataGetLength(fingerprint); const uint8_t *byte = CFDataGetBytePtr(fingerprint); fprintf(stdout, "Fingerprint:"); for (i = 0; i < j; i++) { fprintf(stdout, " %02X", byte[i]); } fprintf(stdout, "\n"); } } if (trust_settings) { CFPropertyListRef trust_settings = NULL; trust_settings = CFArrayGetValueAtIndex(certSettingsPair, 1); if (trust_settings && CFGetTypeID(trust_settings) != CFArrayGetTypeID()) { fprintf(stderr, "failed to get trust settings for cert %ld\n", ix); CFReleaseNull(cert); return 1; } /* These are some trust settings configs used by ManagedConfiguration on iOS */ if (CFArrayGetCount(trust_settings) == 0) { /* Full trust */ fprintf(stdout, "Full trust enabled\n"); } else if (isDenyTrustSetting(trust_settings)) { fprintf(stdout, "Administrator blacklisted\n"); } else if (isPartialSSLTrustSetting(trust_settings)) { fprintf(stdout, "Partial trust enabled\n"); } else { CFStringRef settings = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), trust_settings); if (settings) { char *settingsStr = CFStringToCString(settings); if (settingsStr) { fprintf(stdout, "Unknown trust settings:\n%s\n", settingsStr); free(settingsStr); } CFRelease(settings); } } } printf("*******************************************************\n"); CFReleaseNull(cert); } CFRelease(certs); return result; } #endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR