--- /dev/null
+/*
+ * 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 <TargetConditionals.h>
+#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+
+#include "SecurityCommands.h"
+
+#include "security.h"
+#include "SecurityTool/sharedTool/print_cert.h"
+#include "SecBase64.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "SecurityTool/sharedTool/tool_errors.h"
+
+#include <Security/SecItem.h>
+
+#include <CoreFoundation/CFArray.h>
+#include <CoreFoundation/CFDate.h>
+#include <CoreFoundation/CFNumber.h>
+#include <CoreFoundation/CFString.h>
+
+#include <Security/SecCertificatePriv.h>
+#include <Security/SecPolicyPriv.h>
+#include <Security/SecTrustPriv.h>
+#include <Security/SecInternal.h>
+#include <Security/SecTrustStore.h>
+#include <Security/SecTrustSettings.h>
+
+#include "SecurityTool/sharedTool/readline.h"
+
+#include <utilities/SecCFWrappers.h>
+#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