darling-security/SecurityTool/sharedTool/show_certificates.c
2020-07-06 07:59:58 -04:00

496 lines
16 KiB
C

/*
* 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