gustavogenovese / curl-android-ios

Static libcurl to be used in Android and iOS apps. Build scripts included. No Android source required
641 stars 255 forks source link

CURLOPT_PINNEDPUBLICKEY does not work on iOS #57

Closed jahngordon closed 5 years ago

jahngordon commented 5 years ago

Not sure if this is a curl issue or an issue with the build, but CURLOPT_PINNEDPUBLICKEY doesn't work on iOS pre-built binaries, but works fine on Android (with OpenSSL).

I'm trying to enable pinning in our apps that use this library for both iOS and Android and the Android one works fine - correct public key it works as before we added the setting, wrong public key and it gives me an error saying I cannot connect.

Code is as follows:

      CURLcode c = curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
        fprintf(stderr, "Set Fail on Error: %s\n",
                curl_easy_strerror(c));
        c = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
        fprintf(stderr, "Set verify peer: %s\n",
                curl_easy_strerror(c));
        c = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
        fprintf(stderr, "Set verify host: %s\n",
                curl_easy_strerror(c));
        c = curl_easy_setopt(curl, CURLOPT_PINNEDPUBLICKEY,
                             "sha256//nhEOGkhMcl5uqf13KxUPoCgXYXCKA8A4E+j9JiL+UB8=");
        fprintf(stderr, "Set pinned key: %s\n",
                curl_easy_strerror(c));

The output from this on iOS is:

ENABLING PINNING Set Fail on Error: No error Set verify peer: No error Set verify host: No error Set pinned key: Error

When I look at the curl return code where I'm setting the pinned key, it's CURLE_NOT_BUILT_IN.

Digging into the curl source, I can see this section in lib/setopt.c:

  case CURLOPT_PINNEDPUBLICKEY:
    /*
     * Set pinned public key for SSL connection.
     * Specify file name of the public key in DER format.
     */
#ifdef USE_SSL
    if(Curl_ssl->supports & SSLSUPP_PINNEDPUBKEY)
      result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG],
                              va_arg(param, char *));
    else
#endif
      result = CURLE_NOT_BUILT_IN;
    break;

As far as I can tell, the enabling of the DarwinSSL backend in the prebuilt binaries build script should define USE_SSL (curl_setup.h) which leads me to the Curl_ssl->supports bit for SSLSUPP_PINNEDPUBKEY is not set. The docs for this feature (https://curl.haxx.se/libcurl/c/CURLOPT_PINNEDPUBLICKEY.html) say that support should be from 7.54.1: SecureTransport/DarwinSSL on macOS 10.7+/iOS 10+ and I'm using the 7.60 release.

I've confirmed this by pulling the curl version info that reports as follows:

screenshot 2018-11-28 at 18 04 37

My attempts to manually build here to try things have been scuppered by this error:

url.c:55:2: error: "We can't compile without socket() support!"

..but I've seen the other tickets (e.g. #19 ) where you point people to run xcode-select --install, which just says:

xcode-select: error: command line tools are already installed, use "Software Update" to install updates

I assume this difficulty in checking anything is an Xcode / Mojave issue but I see from #56 you can't upgrade until the new year.

In the meantime, any ideas where the issue for this lies?

gustavogenovese commented 5 years ago

You could try Xcode 9 and see if it builds. Sorry that's the only tip I have for you at this moment

jahngordon commented 5 years ago

Thanks - will give it a try and if I get to the bottom of it, will add to this.

jahngordon commented 5 years ago

Looks like the build issue is referred to upstream and comment https://github.com/curl/curl/issues/3189#issuecomment-434889077 recommends installing the following package:

/Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg

This seems to be added to the machine by the xcode-select --install step.

Installing this package, deleting curl/configure and re-running the build gets the iOS build running on Mojave (possibly solving #56 ).

In my case I encountered this error:

ld: warning: ignoring file /opt/local/lib/libz.dylib, file was built for x86_64 which is not the architecture being linked (armv7): /opt/local/lib/libz.dylib

It seems that I have a libz in /opt/local for something or other and the only way I could prevent attempts to link against this was by renaming libz.dylib and libz.a to libz.dylib.unused and libz.a.unused. After that, this project happily builds on Mojave... I'm now digging deeper on the pinning issue.

jahngordon commented 5 years ago

The answer is right there in my initial post... it's the supported iOS version. Curl sets or resets SSLSUPP_PINNEDPUBKEY based on the compile time version, not at runtime; this is consistent with documentation and resulting error codes.

Setting IPHONEOS_DEPLOYMENT_TARGET="10" in the build_iOS.sh script enables the support and when I run...

ENABLING PINNING
Set Fail on Error: No error
Set verify peer: No error
Set verify host: No error
Set pinned key: No error

Closing issue as this is intended and expected operation for iOS 9 which is the current spec for the prebuilt binaries.