show_certificates.c [plain text]
#include <TargetConditionals.h>
#if TARGET_OS_EMBEDDED
#include "SecurityCommands.h"
#include "security.h"
#include "SecurityTool/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/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 <SecurityTool/readline.h>
#include <utilities/SecCFWrappers.h>
typedef uint32_t SecProtocolType;
typedef uint32_t SecAuthenticationType;
static void
keychain_query_parse_string(CFMutableDictionaryRef q, CFStringRef s) {
bool inkey = true;
bool escaped = false;
CFStringRef key = NULL;
CFMutableStringRef str = CFStringCreateMutable(0, 0);
CFRange rng = { .location = 0, .length = CFStringGetLength(s) };
CFCharacterSetRef cs_key = CFCharacterSetCreateWithCharactersInString(0, CFSTR("=\\"));
CFCharacterSetRef cs_value = CFCharacterSetCreateWithCharactersInString(0, CFSTR(",\\"));
while (rng.length) {
CFRange r;
CFStringRef sub;
bool complete = false;
if (escaped) {
r.location = rng.location;
r.length = 1;
sub = CFStringCreateWithSubstring(0, s, r);
escaped = false;
} else if (CFStringFindCharacterFromSet(s, inkey ? cs_key : cs_value, rng, 0, &r)) {
if (CFStringGetCharacterAtIndex(s, r.location) == '\\') {
escaped = true;
} else {
complete = true;
}
CFIndex next = r.location + 1;
r.length = r.location - rng.location;
r.location = rng.location;
sub = CFStringCreateWithSubstring(0, s, r);
rng.length -= next - rng.location;
rng.location = next;
} else {
sub = CFStringCreateWithSubstring(0, s, rng);
rng.location += rng.length;
rng.length = 0;
complete = true;
}
CFStringAppend(str, sub);
CFRelease(sub);
if (complete) {
CFStringRef value = CFStringCreateCopy(0, str);
CFStringReplaceAll(str, CFSTR(""));
if (inkey) {
key = value;
} else {
CFDictionarySetValue(q, key, value);
CFReleaseNull(value);
CFReleaseNull(key);
}
inkey = !inkey;
}
}
if (key) {
CFDictionarySetValue(q, key, kCFBooleanTrue);
CFRelease(key);
}
CFRelease(str);
}
static void
keychain_query_parse_cstring(CFMutableDictionaryRef q, const char *query) {
CFStringRef s;
s = CFStringCreateWithCStringNoCopy(0, query, kCFStringEncodingUTF8, kCFAllocatorNull);
keychain_query_parse_string(q, s);
CFRelease(s);
}
static void show_cert_eval(CFArrayRef certs, bool verbose) {
SecPolicyRef policy = SecPolicyCreateSSL(true, NULL);
SecTrustRef trust = NULL;
OSStatus status = SecTrustCreateWithCertificates(certs, policy, &trust);
SecTrustResultType trustResult;
const char *trustResults[] = {
"invalid",
"proceed",
"confirm",
"deny",
"unspecified",
"recoverable trust failure",
"fatal trust failure",
"other error",
};
status = 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);
}
}
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':
keychain_query_parse_cstring(query, optarg);
keychain_certs = true;
break;
case '?':
default:
return 2;
}
}
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) {
keychain_query_parse_cstring(query, argv[arg]);
}
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) {
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");
}
}
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;
}
#endif // TARGET_OS_EMBEDDED