Commit 7c9b9add authored by David Schweikert's avatar David Schweikert Committed by Daniel Stenberg
Browse files

darwinssl: fix SSL client certificate not found on MacOS Sierra

Reviewed-by: Nick Zitzmann

Closes #1105
parent 0744506c
Loading
Loading
Loading
Loading
+45 −9
Original line number Original line Diff line number Diff line
@@ -883,14 +883,18 @@ static OSStatus CopyIdentityWithLabel(char *label,
                                      SecIdentityRef *out_cert_and_key)
                                      SecIdentityRef *out_cert_and_key)
{
{
  OSStatus status = errSecItemNotFound;
  OSStatus status = errSecItemNotFound;
  CFArrayRef keys_list;
  CFIndex keys_list_count;
  CFIndex i;
  CFStringRef common_name;


#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
  /* SecItemCopyMatching() was introduced in iOS and Snow Leopard.
  /* SecItemCopyMatching() was introduced in iOS and Snow Leopard.
     kSecClassIdentity was introduced in Lion. If both exist, let's use them
     kSecClassIdentity was introduced in Lion. If both exist, let's use them
     to find the certificate. */
     to find the certificate. */
  if(SecItemCopyMatching != NULL && kSecClassIdentity != NULL) {
  if(SecItemCopyMatching != NULL && kSecClassIdentity != NULL) {
    CFTypeRef keys[4];
    CFTypeRef keys[5];
    CFTypeRef values[4];
    CFTypeRef values[5];
    CFDictionaryRef query_dict;
    CFDictionaryRef query_dict;
    CFStringRef label_cf = CFStringCreateWithCString(NULL, label,
    CFStringRef label_cf = CFStringCreateWithCString(NULL, label,
      kCFStringEncodingUTF8);
      kCFStringEncodingUTF8);
@@ -900,21 +904,53 @@ static OSStatus CopyIdentityWithLabel(char *label,
    keys[0] = kSecClass;
    keys[0] = kSecClass;
    values[1] = kCFBooleanTrue;    /* we want a reference */
    values[1] = kCFBooleanTrue;    /* we want a reference */
    keys[1] = kSecReturnRef;
    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;
    keys[2] = kSecMatchLimit;
    /* identity searches need a SecPolicyRef in order to work */
    /* identity searches need a SecPolicyRef in order to work */
    values[3] = SecPolicyCreateSSL(false, label_cf);
    values[3] = SecPolicyCreateSSL(false, NULL);
    keys[3] = kSecMatchPolicy;
    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,
    query_dict = CFDictionaryCreate(NULL, (const void **)keys,
                                   (const void **)values, 4L,
                                    (const void **)values, 5L,
                                    &kCFCopyStringDictionaryKeyCallBacks,
                                    &kCFCopyStringDictionaryKeyCallBacks,
                                    &kCFTypeDictionaryValueCallBacks);
                                    &kCFTypeDictionaryValueCallBacks);
    CFRelease(values[3]);
    CFRelease(values[3]);
    CFRelease(label_cf);


    /* Do we have a match? */
    /* 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<keys_list_count; i++) {
        OSStatus err = noErr;
        SecCertificateRef cert = NULL;
        *out_cert_and_key =
          (SecIdentityRef) CFArrayGetValueAtIndex(keys_list, i);
        err = SecIdentityCopyCertificate(*out_cert_and_key, &cert);
        if(err == noErr) {
          SecCertificateCopyCommonName(cert, &common_name);
          if(CFStringCompare(common_name, label_cf, 0) == kCFCompareEqualTo) {
            CFRelease(cert);
            CFRelease(common_name);
            status = noErr;
            break;
          }
          CFRelease(common_name);
        }
        *out_cert_and_key = NULL;
        status = 1;
        CFRelease(cert);
      }
    }

    CFRelease(query_dict);
    CFRelease(query_dict);
    CFRelease(label_cf);
  }
  }
  else {
  else {
#if CURL_SUPPORT_MAC_10_6
#if CURL_SUPPORT_MAC_10_6