Using LibCurl with SSL
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.