Skip to content

libcurl with Secure Transport and --enable-optimize crashes when settings CURLOPT_SSLCERT to an inexistant cert #9194

Closed
@guillaumealgis

Description

@guillaumealgis

I did this

  • Compiled libcurl with Secure Transport on Darwin platform (tested on macOS and iOS).
  • Used --enable-optimize during configuration (this bellow for the full options list).
  • Tried to make a request while using a non-existent client SSL certificate (eg. curl_easy_setopt(handle, CURLOPT_SSLCERT, "thisdoesnotexistinkeychain");).

I expected the following

  • The request fails and curl_easy_perform returns an error.

What I got

  • curl_easy_perform crashes on a CFRelease call.

curl/libcurl version

curl 7.84.0 (arm-apple-darwin) libcurl/7.84.0 SecureTransport zlib/1.2.11 nghttp2/1.47.0
Release-Date: 2022-06-27
Protocols: http https mqtt 
Features: alt-svc AsynchDNS HSTS HTTP2 IPv6 Largefile libz SSL threadsafe UnixSockets

Operating system

macOS Monterey 12.4 (21F79)
Xcode 13.4.1 (13F100)

Darwin 21.5.0 Darwin Kernel Version 21.5.0: Tue Apr 26 21:08:37 PDT 2022; root:xnu-8020.121.3~4/RELEASE_ARM64_T6000 arm64

Details

libcurl ./configure options

./configure \
    --disable-dependency-tracking \
    --disable-shared \
    --enable-static \
    \
    --disable-debug \
    --disable-curldebug \
    --enable-optimize \
    --enable-warnings \
    --enable-symbol-hiding \
    \
    --disable-ares \
    \
    --enable-http \
    --disable-ftp \
    --disable-file \
    --disable-ldap \
    --disable-ldaps \
    --disable-rtsp \
    --disable-proxy \
    --disable-dict \
    --disable-telnet \
    --disable-tftp \
    --disable-pop3 \
    --disable-imap \
    --disable-smb \
    --disable-smtp \
    --disable-gopher \
    --disable-manual \
    --disable-libcurl-option \
    --enable-ipv6 \
    \
    --enable-threaded-resolver \
    --disable-sspi \
    --disable-crypto-auth \
    --disable-tls-srp \
    \
    --without-schannel \
    --with-secure-transport \
    \
    --without-libidn2 \
    \
    --host="arm-apple-darwin" --prefix="dist"

Minimal sample reproducing the issue

#include <stdlib.h>
#include <printf.h>

#include "curl-7.84.0/dist/include/curl/curl.h"

int main() {
    CURL *handle = curl_easy_init();

    if (!handle) {
        exit(1);
    }

    char errbuf[CURL_ERROR_SIZE];
    curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, errbuf);
    errbuf[0] = 0;

    curl_easy_setopt(handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);

    curl_easy_setopt(handle, CURLOPT_SSLCERTTYPE, "P12");
    curl_easy_setopt(handle, CURLOPT_SSLCERT, "thisdoesnotexistinkeychain");
    curl_easy_setopt(handle, CURLOPT_KEYPASSWD, "foobar");

    curl_easy_setopt(handle, CURLOPT_ACCEPT_ENCODING, "gzip,deflate");
    curl_easy_setopt(handle, CURLOPT_URL, "https://example.com");

    CURLcode res = curl_easy_perform(handle);

    long http_code = 0;
    curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_code);

    if (res != CURLE_OK) {
        size_t len = strlen(errbuf);
        printf("\nlibcurl: (%d) ", res);
        if(len)
            printf("%s%s", errbuf, ((errbuf[len - 1] != '\n') ? "\n" : ""));
        else
            printf("%s\n", curl_easy_strerror(res));
    } else {
        printf("OK");
    }
}
xcrun clang -g test.c -I curl-7.84.0/dist/include -L curl-7.84.0/dist/lib -lcurl -lnghttp2 -lz -framework Security -framework CoreFoundation -framework SystemConfiguration

The program will crash on :

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BREAKPOINT (code=1, subcode=0x1b925544c)
  * frame #0: 0x00000001b925544c CoreFoundation`CFRelease.cold.1 + 16
    frame #1: 0x00000001b908838c CoreFoundation`CFRelease + 268
    frame #2: 0x0000000100060574 a.out`CopyIdentityWithLabel(label="thisdoesnotexistinkeychain", out_cert_and_key=0x000000016fdfea00) at sectransp.c:1185:11
    frame #3: 0x000000010005de80 a.out`sectransp_connect_step1(data=0x0000000101808208, conn=0x000000010180ec08, sockindex=0) at sectransp.c:1890:13
    frame #4: 0x000000010005d440 a.out`sectransp_connect_common(data=0x0000000101808208, conn=0x000000010180ec08, sockindex=0, nonblocking=true, done=0x000000016fdfef15) at sectransp.c:3068:14
    frame #5: 0x000000010005d114 a.out`sectransp_connect_nonblocking(data=0x0000000101808208, conn=0x000000010180ec08, sockindex=0, done=0x000000016fdfef15) at sectransp.c:3157:10
    frame #6: 0x0000000100063a94 a.out`Curl_ssl_connect_nonblocking(data=0x0000000101808208, conn=0x000000010180ec08, isproxy=false, sockindex=0, done=0x000000016fdfef15) at vtls.c:371:12
    frame #7: 0x00000001000200d0 a.out`https_connecting(data=0x0000000101808208, done=0x000000016fdfef15) at http.c:1597:12
    frame #8: 0x000000010001ffbc a.out`Curl_http_connect(data=0x0000000101808208, done=0x000000016fdfef15) at http.c:1523:14
    frame #9: 0x000000010003e49c a.out`protocol_connect(data=0x0000000101808208, protocol_done=0x000000016fdfef15) at multi.c:1731:16
    frame #10: 0x000000010003b274 a.out`multi_runsingle(multi=0x0000000100504088, nowp=0x000000016fdfef70, data=0x0000000101808208) at multi.c:2047:16
    frame #11: 0x000000010003aa8c a.out`curl_multi_perform(multi=0x0000000100504088, running_handles=0x000000016fdfefd8) at multi.c:2640:14
    frame #12: 0x0000000100014c04 a.out`easy_transfer(multi=0x0000000100504088) at easy.c:662:15
    frame #13: 0x0000000100013b10 a.out`easy_perform(data=0x0000000101808208, events=false) at easy.c:752:42
    frame #14: 0x0000000100013970 a.out`curl_easy_perform(data=0x0000000101808208) at easy.c:771:10
    frame #15: 0x0000000100000e84 a.out`main at test.c:27:20
    frame #16: 0x00000001000e108c dyld`start + 520

Apparently curl is releasing the keys_list pointer even if nothing has been found by SecItemCopyMatching, which causes the crash. I spent a good few hours on this trying to figure out why keys_list was not NULL, but apparently my C is too rusty to solve this :(

Any help would be greatly appreciated !

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions