EAPTLSTrustExceptionUtil.c [plain text]
#include <TargetConditionals.h>
#include <CoreFoundation/CoreFoundation.h>
#include <SystemConfiguration/SCValidation.h>
#include <Security/SecTrustPriv.h>
#include <CoreFoundation/CFPreferences.h>
#include <notify.h>
#include "EAPLog.h"
#include "symbol_scope.h"
#include "myCFUtil.h"
#include "EAPTLSUtil.h"
#include "EAPClientProperties.h"
#include "EAPSIMAKAPersistentState.h"
#define kEAPTLSTrustExceptionsID "com.apple.network.eapclient.tls.TrustExceptions"
#define kEAPTLSTrustExceptionsApplicationID CFSTR(kEAPTLSTrustExceptionsID)
STATIC void
exceptions_change_check(void)
{
STATIC int token;
STATIC bool token_valid = false;
int check = 0;
uint32_t status;
if (!token_valid) {
status = notify_register_check(kEAPTLSTrustExceptionsID, &token);
if (status != NOTIFY_STATUS_OK) {
EAPLOG_FL(LOG_NOTICE, "notify_register_check returned %d", status);
return;
}
token_valid = true;
}
status = notify_check(token, &check);
if (status != NOTIFY_STATUS_OK) {
EAPLOG_FL(LOG_NOTICE, "notify_check returned %d", status);
return;
}
if (check != 0) {
CFPreferencesSynchronize(kEAPTLSTrustExceptionsApplicationID,
kCFPreferencesCurrentUser,
kCFPreferencesAnyHost);
}
return;
}
STATIC void
exceptions_change_notify(void)
{
uint32_t status;
status = notify_post(kEAPTLSTrustExceptionsID);
if (status != NOTIFY_STATUS_OK) {
EAPLOG_FL(LOG_NOTICE, "notify_post returned %d", status);
}
return;
}
STATIC void
EAPTLSTrustExceptionsSave(CFStringRef domain, CFStringRef identifier,
CFStringRef hash_str, CFDataRef exceptions)
{
CFDictionaryRef domain_list;
CFDictionaryRef exceptions_list = NULL;
bool store_exceptions = TRUE;
exceptions_change_check();
domain_list = CFPreferencesCopyValue(domain,
kEAPTLSTrustExceptionsApplicationID,
kCFPreferencesCurrentUser,
kCFPreferencesAnyHost);
if (domain_list != NULL && isA_CFDictionary(domain_list) == NULL) {
CFRelease(domain_list);
domain_list = NULL;
}
if (domain_list != NULL) {
exceptions_list = CFDictionaryGetValue(domain_list, identifier);
exceptions_list = isA_CFDictionary(exceptions_list);
if (exceptions_list != NULL) {
CFDataRef stored_exceptions;
stored_exceptions = CFDictionaryGetValue(exceptions_list, hash_str);
if (isA_CFData(stored_exceptions) != NULL
&& CFEqual(stored_exceptions, exceptions)) {
store_exceptions = FALSE;
}
}
}
if (store_exceptions) {
if (exceptions_list == NULL) {
exceptions_list
= CFDictionaryCreate(NULL,
(const void * * )&hash_str,
(const void * *)&exceptions,
1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
else {
CFMutableDictionaryRef new_exceptions_list;
new_exceptions_list
= CFDictionaryCreateMutableCopy(NULL, 0,
exceptions_list);
CFDictionarySetValue(new_exceptions_list, hash_str, exceptions);
exceptions_list = (CFDictionaryRef)new_exceptions_list;
}
if (domain_list == NULL) {
domain_list
= CFDictionaryCreate(NULL,
(const void * *)&identifier,
(const void * *)&exceptions_list,
1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
else {
CFMutableDictionaryRef new_domain_list;
new_domain_list
= CFDictionaryCreateMutableCopy(NULL, 0,
domain_list);
CFDictionarySetValue(new_domain_list, identifier, exceptions_list);
CFRelease(domain_list);
domain_list = (CFDictionaryRef)new_domain_list;
}
CFRelease(exceptions_list);
CFPreferencesSetValue(domain, domain_list,
kEAPTLSTrustExceptionsApplicationID,
kCFPreferencesCurrentUser,
kCFPreferencesAnyHost);
CFPreferencesSynchronize(kEAPTLSTrustExceptionsApplicationID,
kCFPreferencesCurrentUser,
kCFPreferencesAnyHost);
exceptions_change_notify();
}
my_CFRelease(&domain_list);
return;
}
bool
EAPTLSSecTrustSaveExceptionsBinding(SecTrustRef trust,
CFStringRef domain, CFStringRef identifier,
CFStringRef server_hash_str)
{
CFDataRef exceptions;
exceptions = SecTrustCopyExceptions(trust);
if (exceptions == NULL) {
EAPLOG_FL(LOG_NOTICE, "failed to copy exceptions");
return (FALSE);
}
EAPTLSTrustExceptionsSave(domain, identifier, server_hash_str,
exceptions);
my_CFRelease(&exceptions);
return (TRUE);
}
CFDataRef
EAPTLSTrustExceptionsCopy(CFStringRef domain, CFStringRef identifier,
CFStringRef hash_str)
{
CFDataRef exceptions = NULL;
CFDictionaryRef domain_list;
exceptions_change_check();
domain_list = CFPreferencesCopyValue(domain,
kEAPTLSTrustExceptionsApplicationID,
kCFPreferencesCurrentUser,
kCFPreferencesAnyHost);
if (isA_CFDictionary(domain_list) != NULL) {
CFDictionaryRef exceptions_list;
exceptions_list = CFDictionaryGetValue(domain_list, identifier);
if (isA_CFDictionary(exceptions_list) != NULL) {
exceptions = isA_CFData(CFDictionaryGetValue(exceptions_list,
hash_str));
if (exceptions != NULL) {
CFRetain(exceptions);
}
}
}
my_CFRelease(&domain_list);
return (exceptions);
}
bool
EAPTLSSecTrustApplyExceptionsBinding(SecTrustRef trust, CFStringRef domain,
CFStringRef identifier,
CFStringRef server_cert_hash)
{
CFDataRef exceptions;
bool ret = false;
exceptions = EAPTLSTrustExceptionsCopy(domain, identifier,
server_cert_hash);
if (exceptions != NULL) {
if (SecTrustSetExceptions(trust, exceptions) == FALSE) {
EAPLOG_FL(LOG_NOTICE, "SecTrustSetExceptions failed");
} else {
ret = true;
}
}
my_CFRelease(&exceptions);
return ret;
}
void
EAPTLSRemoveTrustExceptionsBindings(CFStringRef domain, CFStringRef identifier)
{
CFDictionaryRef domain_list;
CFDictionaryRef exceptions_list;
#if TARGET_OS_IPHONE
if (my_CFEqual(domain, kEAPTLSTrustExceptionsDomainWirelessSSID)) {
EAPSIMAKAPersistentStateForgetSSID(identifier);
}
#endif
exceptions_change_check();
domain_list = CFPreferencesCopyValue(domain,
kEAPTLSTrustExceptionsApplicationID,
kCFPreferencesCurrentUser,
kCFPreferencesAnyHost);
if (domain_list != NULL && isA_CFDictionary(domain_list) == NULL) {
CFRelease(domain_list);
domain_list = NULL;
}
if (domain_list == NULL) {
return;
}
exceptions_list = CFDictionaryGetValue(domain_list, identifier);
if (exceptions_list != NULL) {
CFMutableDictionaryRef new_domain_list;
new_domain_list
= CFDictionaryCreateMutableCopy(NULL, 0,
domain_list);
CFDictionaryRemoveValue(new_domain_list, identifier);
CFPreferencesSetValue(domain, new_domain_list,
kEAPTLSTrustExceptionsApplicationID,
kCFPreferencesCurrentUser,
kCFPreferencesAnyHost);
CFPreferencesSynchronize(kEAPTLSTrustExceptionsApplicationID,
kCFPreferencesCurrentUser,
kCFPreferencesAnyHost);
exceptions_change_notify();
CFRelease(new_domain_list);
}
CFRelease(domain_list);
return;
}
#if TARGET_OS_IPHONE
#define PREFERENCES_USERNAME CFSTR("mobile")
#endif
CFDictionaryRef
EAPTLSCopyTrustExceptionBindings(CFStringRef domain, CFStringRef identifier)
{
CFDictionaryRef domain_list = NULL;
CFDictionaryRef exceptions_list = NULL;
CFStringRef user_name = NULL;
#if TARGET_OS_IPHONE
user_name = PREFERENCES_USERNAME;
#else
user_name = kCFPreferencesCurrentUser;
#endif
exceptions_change_check();
domain_list = CFPreferencesCopyValue(domain,
kEAPTLSTrustExceptionsApplicationID,
user_name,
kCFPreferencesAnyHost);
if (isA_CFDictionary(domain_list) != NULL) {
exceptions_list = CFDictionaryGetValue(domain_list, identifier);
if (isA_CFDictionary(exceptions_list) != NULL) {
CFRetain(exceptions_list);
}
}
my_CFRelease(&domain_list);
return (exceptions_list);
}
void
EAPTLSSetTrustExceptionBindings(CFStringRef domain, CFStringRef identifier, CFDictionaryRef exceptionList)
{
CFDictionaryRef domain_list = NULL;
CFStringRef user_name = NULL;
#if TARGET_OS_IPHONE
user_name = PREFERENCES_USERNAME;
#else
user_name = kCFPreferencesCurrentUser;
#endif
exceptions_change_check();
domain_list = CFPreferencesCopyValue(domain,
kEAPTLSTrustExceptionsApplicationID,
user_name,
kCFPreferencesAnyHost);
if (domain_list != NULL && isA_CFDictionary(domain_list) == NULL) {
my_CFRelease(&domain_list);
}
if (domain_list == NULL) {
domain_list = CFDictionaryCreate(NULL,
(const void * *)&identifier,
(const void * *)&exceptionList,
1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
else {
CFMutableDictionaryRef new_domain_list;
new_domain_list = CFDictionaryCreateMutableCopy(NULL, 0, domain_list);
CFDictionarySetValue(new_domain_list, identifier, exceptionList);
CFRelease(domain_list);
domain_list = (CFDictionaryRef)new_domain_list;
}
CFPreferencesSetValue(domain, domain_list,
kEAPTLSTrustExceptionsApplicationID,
user_name,
kCFPreferencesAnyHost);
CFPreferencesSynchronize(kEAPTLSTrustExceptionsApplicationID,
user_name,
kCFPreferencesAnyHost);
exceptions_change_notify();
my_CFRelease(&domain_list);
return;
}