SecCertificateTrace.c [plain text]
#include "SecCertificateTrace.h"
#include <TargetConditionals.h>
#include <inttypes.h>
#include "SecCFWrappers.h"
#include <sys/time.h>
#include <CoreFoundation/CoreFoundation.h>
#include "debugging.h"
#define SEC_CONST_DECL(k,v) CFTypeRef k = (CFTypeRef)(CFSTR(v));
SEC_CONST_DECL (kCertStatsPrefix, "com.apple.certstats");
SEC_CONST_DECL (kCertStatsCert, "cert");
SEC_CONST_DECL (kCertStatsPolicy, "id");
SEC_CONST_DECL (kCertStatsNotBefore, "nb");
SEC_CONST_DECL (kCertStatsNotAfter, "na");
SEC_CONST_DECL (kCertStatsSerialNumber, "sn");
SEC_CONST_DECL (kCertStatsSubjectSummary, "s");
SEC_CONST_DECL (kCertStatsIssuerSummary, "i");
static const CFStringRef kCertStatsFormat = CFSTR("%@/%@=%@/%@=%@/%@=%@/%@=%@/%@=%@/%@=%@");
static const CFStringRef kCertStatsDelimiters = CFSTR("/");
bool SetCertificateTraceValueForKey(CFStringRef key, int64_t value);
void* BeginCertificateLoggingTransaction(void);
bool AddKeyValuePairToCertificateLoggingTransaction(void* token, CFStringRef key, int64_t value);
void CloseCertificateLoggingTransaction(void* token);
CFStringRef SecCFStringCopyEncodingDelimiters(CFStringRef str, CFStringRef delimiters);
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR))
#include <asl.h>
static const char* gTopLevelKeyForCertificateTracing = "com.apple.certstats";
static const char* gMessageTracerSetPrefix = "com.apple.message.";
static const char* gMessageTracerDomainField = "com.apple.message.domain";
static void* OSX_BeginCertificateLoggingTransaction()
{
void* result = NULL;
aslmsg mAsl = NULL;
mAsl = asl_new(ASL_TYPE_MSG);
if (NULL == mAsl)
{
return result;
}
asl_set(mAsl, gMessageTracerDomainField, gTopLevelKeyForCertificateTracing);
result = (void *)mAsl;
return result;
}
static bool OSX_AddKeyValuePairToCertificateLoggingTransaction(void* token, CFStringRef key, int64_t value)
{
if (NULL == token || NULL == key)
{
return false;
}
aslmsg mAsl = (aslmsg)token;
CFStringRef real_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%@"), gMessageTracerSetPrefix, key);
if (NULL == real_key)
{
return false;
}
CFIndex key_length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(real_key), kCFStringEncodingUTF8);
key_length += 1; char key_buffer[key_length];
memset(key_buffer, 0,key_length);
if (!CFStringGetCString(real_key, key_buffer, key_length, kCFStringEncodingUTF8))
{
return false;
}
CFRelease(real_key);
CFStringRef value_str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%lld"), value);
if (NULL == value_str)
{
return false;
}
CFIndex value_str_numBytes = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value_str), kCFStringEncodingUTF8);
value_str_numBytes += 1; char value_buffer[value_str_numBytes];
memset(value_buffer, 0, value_str_numBytes);
if (!CFStringGetCString(value_str, value_buffer, value_str_numBytes, kCFStringEncodingUTF8))
{
CFRelease(value_str);
return false;
}
CFRelease(value_str);
asl_set(mAsl, key_buffer, value_buffer);
return true;
}
static void OSX_CloseCertificateLoggingTransaction(void* token)
{
if (NULL != token)
{
aslmsg mAsl = (aslmsg)token;
asl_log(NULL, mAsl, ASL_LEVEL_NOTICE, "");
asl_free(mAsl);
}
}
static bool OSX_SetCertificateTraceValueForKey(CFStringRef key, int64_t value)
{
bool result = false;
if (NULL == key)
{
return result;
}
aslmsg mAsl = NULL;
mAsl = asl_new(ASL_TYPE_MSG);
if (NULL == mAsl)
{
return result;
}
CFStringRef real_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%@"), gMessageTracerSetPrefix, key);
if (NULL == real_key)
{
return false;
}
CFIndex key_length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(real_key), kCFStringEncodingUTF8);
key_length += 1; char key_buffer[key_length];
memset(key_buffer, 0,key_length);
if (!CFStringGetCString(real_key, key_buffer, key_length, kCFStringEncodingUTF8))
{
return false;
}
CFRelease(real_key);
CFStringRef value_str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%lld"), value);
if (NULL == value_str)
{
asl_free(mAsl);
return result;
}
CFIndex value_str_numBytes = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value_str), kCFStringEncodingUTF8);
value_str_numBytes += 1; char value_buffer[value_str_numBytes];
memset(value_buffer, 0, value_str_numBytes);
if (!CFStringGetCString(value_str, value_buffer, value_str_numBytes, kCFStringEncodingUTF8))
{
asl_free(mAsl);
CFRelease(value_str);
return result;
}
CFRelease(value_str);
asl_set(mAsl, gMessageTracerDomainField, gTopLevelKeyForCertificateTracing);
asl_set(mAsl, key_buffer, value_buffer);
asl_log(NULL, mAsl, ASL_LEVEL_NOTICE, "");
asl_free(mAsl);
return true;
}
#endif
#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
static const char* gTopLevelKeyForCertificateTracing = "com.apple.certstats";
typedef void (*type_ADClientClearScalarKey)(CFStringRef key);
typedef void (*type_ADClientAddValueForScalarKey)(CFStringRef key, int64_t value);
static type_ADClientClearScalarKey gADClientClearScalarKey = NULL;
static type_ADClientAddValueForScalarKey gADClientAddValueForScalarKey = NULL;
static dispatch_once_t gADFunctionPointersSet = 0;
static CFBundleRef gAggdBundleRef = NULL;
static bool gFunctionPointersAreLoaded = false;
static bool InitializeADFunctionPointers()
{
if (gFunctionPointersAreLoaded)
{
return gFunctionPointersAreLoaded;
}
dispatch_once(&gADFunctionPointersSet,
^{
CFStringRef path_to_aggd_framework = CFSTR("/System/Library/PrivateFrameworks/AggregateDictionary.framework");
CFURLRef aggd_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path_to_aggd_framework, kCFURLPOSIXPathStyle, true);
if (NULL != aggd_url)
{
gAggdBundleRef = CFBundleCreate(kCFAllocatorDefault, aggd_url);
if (NULL != gAggdBundleRef)
{
gADClientClearScalarKey = (type_ADClientClearScalarKey)
CFBundleGetFunctionPointerForName(gAggdBundleRef, CFSTR("ADClientClearScalarKey"));
gADClientAddValueForScalarKey = (type_ADClientAddValueForScalarKey)
CFBundleGetFunctionPointerForName(gAggdBundleRef, CFSTR("ADClientAddValueForScalarKey"));
}
CFRelease(aggd_url);
}
});
gFunctionPointersAreLoaded = ((NULL != gADClientClearScalarKey) && (NULL != gADClientAddValueForScalarKey));
return gFunctionPointersAreLoaded;
}
static void Internal_ADClientClearScalarKey(CFStringRef key)
{
if (InitializeADFunctionPointers())
{
CFStringRef real_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%@"), gTopLevelKeyForCertificateTracing, key);
if (NULL == real_key)
{
return;
}
gADClientClearScalarKey(real_key);
CFRelease(real_key);
}
}
static void Internal_ADClientAddValueForScalarKey(CFStringRef key, int64_t value)
{
if (InitializeADFunctionPointers())
{
CFStringRef real_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%@"), gTopLevelKeyForCertificateTracing, key);
if (NULL == real_key)
{
return;
}
gADClientAddValueForScalarKey(real_key, value);
CFRelease(real_key);
}
}
static bool iOS_SetCertificateTraceValueForKey(CFStringRef key, int64_t value)
{
if (NULL == key)
{
return false;
}
if (0LL == value)
{
Internal_ADClientClearScalarKey(key);
}
else
{
Internal_ADClientAddValueForScalarKey(key, value);
}
return true;
}
static bool iOS_AddKeyValuePairToCertificateLoggingTransaction(void* token, CFStringRef key, int64_t value)
{
#pragma unused(token)
return iOS_SetCertificateTraceValueForKey(key, value);
}
#endif
bool SetCertificateTraceValueForKey(CFStringRef key, int64_t value)
{
#if (TARGET_IPHONE_SIMULATOR)
return false;
#endif
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
return OSX_SetCertificateTraceValueForKey(key, value);
#endif
#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
return iOS_SetCertificateTraceValueForKey(key, value);
#endif
}
void* BeginCertificateLoggingTransaction(void)
{
#if (TARGET_IPHONE_SIMULATOR)
return (void *)-1;
#endif
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
return OSX_BeginCertificateLoggingTransaction();
#endif
#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
return NULL;
#endif
}
bool AddKeyValuePairToCertificateLoggingTransaction(void* token, CFStringRef key, int64_t value)
{
#if (TARGET_IPHONE_SIMULATOR)
return false;
#endif
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
return OSX_AddKeyValuePairToCertificateLoggingTransaction(token, key, value);
#endif
#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
return iOS_AddKeyValuePairToCertificateLoggingTransaction(token, key, value);
#endif
}
void CloseCertificateLoggingTransaction(void* token)
{
#if (TARGET_IPHONE_SIMULATOR)
; #endif
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
OSX_CloseCertificateLoggingTransaction(token);
#endif
#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
; #endif
}
CFStringRef SecCFStringCopyEncodingDelimiters(CFStringRef str, CFStringRef delimiters)
{
CFMutableStringRef newStr = (str) ? CFStringCreateMutableCopy(kCFAllocatorDefault, 0, str) : NULL;
if (str && delimiters)
{
CFStringRef stringToFind = delimiters;
CFStringRef replacementString = CFSTR("_");
CFStringFindAndReplace(newStr, stringToFind, replacementString, CFRangeMake(0, CFStringGetLength(newStr)), 0);
}
return (CFStringRef) newStr;
}
bool SecCertificateTraceAddRecord(CFDictionaryRef certRecord)
{
bool result = false;
if (!certRecord)
return result;
CFStringRef policy = SecCFStringCopyEncodingDelimiters(CFDictionaryGetValue(certRecord, kCertStatsPolicy), kCertStatsDelimiters);
CFStringRef notBefore = SecCFStringCopyEncodingDelimiters(CFDictionaryGetValue(certRecord, kCertStatsNotBefore), kCertStatsDelimiters);
CFStringRef notAfter = SecCFStringCopyEncodingDelimiters(CFDictionaryGetValue(certRecord, kCertStatsNotAfter), kCertStatsDelimiters);
CFStringRef serial = SecCFStringCopyEncodingDelimiters(CFDictionaryGetValue(certRecord, kCertStatsSerialNumber), kCertStatsDelimiters);
CFStringRef subject = SecCFStringCopyEncodingDelimiters(CFDictionaryGetValue(certRecord, kCertStatsSubjectSummary), kCertStatsDelimiters);
CFStringRef issuer = SecCFStringCopyEncodingDelimiters(CFDictionaryGetValue(certRecord, kCertStatsIssuerSummary), kCertStatsDelimiters);
CFStringRef keyStr = CFStringCreateWithFormat(NULL, NULL,
kCertStatsFormat,
kCertStatsCert,
kCertStatsPolicy, policy,
kCertStatsNotBefore, notBefore,
kCertStatsNotAfter, notAfter,
kCertStatsSerialNumber, serial,
kCertStatsSubjectSummary, subject,
kCertStatsIssuerSummary, issuer
);
CFReleaseSafe(policy);
CFReleaseSafe(notBefore);
CFReleaseSafe(notAfter);
CFReleaseSafe(serial);
CFReleaseSafe(subject);
CFReleaseSafe(issuer);
result = SetCertificateTraceValueForKey(keyStr, 1);
#if DEBUG
secerror("%@.%@ (%d)", kCertStatsPrefix, keyStr, (result) ? 1 : 0);
#endif
CFReleaseSafe(keyStr);
return result;
}