Approx 7 minutes read

LibCurl supports URL transfer over HTTPS protocol. In this post we’ll use LibCurl to download a webpage over HTTPS protocol. To get started, make sure that you have setup your system as outlined in one of my previous posts. Note that LibCurl comes with SSL libraries included and hence you need not to install any extra packages.

Getting started

Let’s first try to download a HTTPS webpage without SSL using following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#define CURL_STATICLIB
#include <curl/curl.h>

int main(int argc, char *argv[])
{
    CURL *curl;
    CURLcode res;

    curl = curl_easy_init();
    if (curl)
    {
        curl_easy_setopt(curl, CURLOPT_URL, "https://google.com");
        /* google.com is redirected, so we tell LibCurl to follow redirection */
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);

        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);
        /* Check for errors */
        if(res != CURLE_OK)
            fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));

        /* Always cleanup */
        curl_easy_cleanup(curl);
    }

    return 0;
}

When we compile and run the above program, we get following error:

curl_easy_perform() failed: Peer certificate cannot be authenticated with given CA certificates

Well we can force LibCurl not to verify the authencity of peer’s certificate by modifying the program as below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#define CURL_STATICLIB
#include <curl/curl.h>

int main(int argc, char *argv[])
{
    CURL *curl;
    CURLcode res;

    curl = curl_easy_init();
    if (curl)
    {
        curl_easy_setopt(curl, CURLOPT_URL, "https://google.com");
        /* google.com is redirected, so we tell LibCurl to follow redirection */
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);
        /* Check for errors */
        if(res != CURLE_OK)
            fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));

        /* Always cleanup */
        curl_easy_cleanup(curl);
    }

    return 0;
}

This will resolve the error we were getting earlier but this is not secure as we are bypassing the verification of SSL certificte presented by peer.

LibCurl with SSL

Now let’s modify the code as below to enable SSL certificate verification by LibCurl:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdio.h>
#define CURL_STATICLIB
#include <curl/curl.h>

int main(int argc, char *argv[])
{
    CURL *curl;
    CURLcode res;

    curl = curl_easy_init();
    if (curl)
    {
        curl_easy_setopt(curl, CURLOPT_URL, "https://google.com");
        /* google.com is redirected, so we tell LibCurl to follow redirection */
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        /* SSL Options */
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER , 1);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST , 1);
        /* Provide CA Certs from http://curl.haxx.se/docs/caextract.html */
        curl_easy_setopt(curl, CURLOPT_CAINFO, "ca-bundle.crt");

        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);
        /* Check for errors */
        if(res != CURLE_OK)
            fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));

        /* Always cleanup */
        curl_easy_cleanup(curl);
    }

    return 0;
}

LibCurl depends on ca-bundle.crt to verify server’s certificate. CA bundle extract is provided by LibCurl itself and you can download it from here. We need to place the ca-bundle.crt in same folder as our executable. Also notice that we have enabled CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST in lines 17 and 18. When CURLOPT_SSL_VERIFYPEER is enabled, LibCurl verifes if the ceriticate presented is authentiate or not. If the verification fails to prove that the certificate is authentic, the connection fails. Authenticating the certificate is not enough to be sure about the server. We also want to ensure that the server is the server we mean to be talking to. When CURLOPT_SSL_VERIFYHOST is enabled, LibCurl checks that the host name in the certificate is valid for the host name we’re connecting to. If LibCurl fails to verify this, the connection fails.