Unverified Commit f8475c69 authored by Dair Grant's avatar Dair Grant Committed by Daniel Stenberg
Browse files

darwinssl: Don't import client certificates into Keychain on macOS

Closes #2085
parent 9a230ba4
Loading
Loading
Loading
Loading
+61 −12
Original line number Diff line number Diff line
@@ -1136,27 +1136,76 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
  if(CFURLCreateDataAndPropertiesFromResource(NULL, pkcs_url, &pkcs_data,
   NULL, NULL, &status)) {
    CFArrayRef items = NULL;

  /* On iOS SecPKCS12Import will never add the client certificate to the
   * Keychain.
   *
   * It gives us back a SecIdentityRef that we can use directly. */
#if CURL_BUILD_IOS
    const void *cKeys[] = {kSecImportExportPassphrase};
    const void *cValues[] = {password};
    CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues,
      password ? 1L : 0L, NULL, NULL);
    CFArrayRef items = NULL;

    /* Here we go: */
    if(options != NULL) {
      status = SecPKCS12Import(pkcs_data, options, &items);
      CFRelease(options);
    }


  /* On macOS SecPKCS12Import will always add the client certificate to
   * the Keychain.
   *
   * As this doesn't match iOS, and apps may not want to see their client
   * certificate saved in the the user's keychain, we use SecItemImport
   * with a NULL keychain to avoid importing it.
   *
   * This returns a SecCertificateRef from which we can construct a
   * SecIdentityRef.
   */
#elif CURL_BUILD_MAC_10_7
    SecItemImportExportKeyParameters keyParams;
    SecExternalFormat inputFormat = kSecFormatPKCS12;
    SecExternalItemType inputType = kSecItemTypeCertificate;

    memset(&keyParams, 0x00, sizeof(keyParams));
    keyParams.version    = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
    keyParams.passphrase = password;

    status = SecItemImport(pkcs_data, NULL, &inputFormat, &inputType,
                           0, &keyParams, NULL, &items);
#endif


    /* Extract the SecIdentityRef */
    if(status == errSecSuccess && items && CFArrayGetCount(items)) {
      CFDictionaryRef identity_and_trust = CFArrayGetValueAtIndex(items, 0L);
      const void *temp_identity = CFDictionaryGetValue(identity_and_trust,
        kSecImportItemIdentity);
      CFIndex i, count;
      count = CFArrayGetCount(items);

      for(i = 0; i < count; i++) {
        CFTypeRef item = (CFTypeRef) CFArrayGetValueAtIndex(items, i);
        CFTypeID  itemID = CFGetTypeID(item);

      /* Retain the identity; we don't care about any other data... */
      CFRetain(temp_identity);
      *out_cert_and_key = (SecIdentityRef)temp_identity;
        if(itemID == CFDictionaryGetTypeID()) {
          CFTypeRef identity = (CFTypeRef) CFDictionaryGetValue(
                                                 (CFDictionaryRef) item,
                                                 kSecImportItemIdentity);
          CFRetain(identity);
          *out_cert_and_key = (SecIdentityRef) identity;
          break;
        }
        else if(itemID == SecCertificateGetTypeID()) {
          status = SecIdentityCreateWithCertificate(NULL,
                                                 (SecCertificateRef) item,
                                                 out_cert_and_key);
          break;
        }
      }
    }

    if(items)
      CFRelease(items);
    CFRelease(options);
    CFRelease(pkcs_data);
  }
#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */