From 7c9b9add6ff5626fc8712d8f8b4e607dcbe8dbfe Mon Sep 17 00:00:00 2001 From: David Schweikert Date: Fri, 4 Nov 2016 15:18:16 +0100 Subject: darwinssl: fix SSL client certificate not found on MacOS Sierra Reviewed-by: Nick Zitzmann Closes #1105 --- lib/vtls/darwinssl.c | 54 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/lib/vtls/darwinssl.c b/lib/vtls/darwinssl.c index 73491c457..134a28211 100644 --- a/lib/vtls/darwinssl.c +++ b/lib/vtls/darwinssl.c @@ -883,14 +883,18 @@ static OSStatus CopyIdentityWithLabel(char *label, SecIdentityRef *out_cert_and_key) { OSStatus status = errSecItemNotFound; + CFArrayRef keys_list; + CFIndex keys_list_count; + CFIndex i; + CFStringRef common_name; #if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS /* SecItemCopyMatching() was introduced in iOS and Snow Leopard. kSecClassIdentity was introduced in Lion. If both exist, let's use them to find the certificate. */ if(SecItemCopyMatching != NULL && kSecClassIdentity != NULL) { - CFTypeRef keys[4]; - CFTypeRef values[4]; + CFTypeRef keys[5]; + CFTypeRef values[5]; CFDictionaryRef query_dict; CFStringRef label_cf = CFStringCreateWithCString(NULL, label, kCFStringEncodingUTF8); @@ -900,21 +904,53 @@ static OSStatus CopyIdentityWithLabel(char *label, keys[0] = kSecClass; values[1] = kCFBooleanTrue; /* we want a reference */ keys[1] = kSecReturnRef; - values[2] = kSecMatchLimitOne; /* one is enough, thanks */ + values[2] = kSecMatchLimitAll; /* kSecMatchLimitOne would be better if the + * label matching below worked correctly */ keys[2] = kSecMatchLimit; /* identity searches need a SecPolicyRef in order to work */ - values[3] = SecPolicyCreateSSL(false, label_cf); + values[3] = SecPolicyCreateSSL(false, NULL); keys[3] = kSecMatchPolicy; + /* match the name of the certificate (doesn't work in macOS 10.12.1) */ + values[4] = label_cf; + keys[4] = kSecAttrLabel; query_dict = CFDictionaryCreate(NULL, (const void **)keys, - (const void **)values, 4L, - &kCFCopyStringDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); + (const void **)values, 5L, + &kCFCopyStringDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); CFRelease(values[3]); - CFRelease(label_cf); /* Do we have a match? */ - status = SecItemCopyMatching(query_dict, (CFTypeRef *)out_cert_and_key); + status = SecItemCopyMatching(query_dict, (CFTypeRef *) &keys_list); + + /* Because kSecAttrLabel matching doesn't work with kSecClassIdentity, + * we need to find the correct identity ourselves */ + if(status == noErr) { + keys_list_count = CFArrayGetCount(keys_list); + *out_cert_and_key = NULL; + for(i=0; i