4

I am trying to login to betfair via the betfair api using curl. I have already succeeded in doing this via the command line version of curl from a bash script but I now want to do this from my C++ code directly with libcurl. Sadly libcurl is not supported by betfair so there is no direct documentation - but if command line curl works then it should all be doable.

My libcurl is failing straight away during an attempt to login (which should get a "session token" as a response). I tell curl about my certificate and key with the lines:

curl_easy_setopt(curl, CURLOPT_SSLCERT,"client-2048.crt");
curl_easy_setopt(curl, CURLOPT_SSLKEY,"client-2048.key");

Later on I call curl_easy_perform(curl); I get a response of:

{"loginStatus":"CERT_AUTH_REQUIRED"}

According to betfair documentation this means: "Certificate required or certificate present but could not authenticate with it"

So I guess that somehow the SSL authentication failed. As an experiment I tried deliberatly putting garbage certificate and key file names (e.g. "client-2048_XXX.crt") but saw no difference in the response from betfair or any of the curl diagnostics (set up via curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace); and curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);). So I have no way of knowing for sure the libcurl has processed my cert and key files properly. Indeed I am even suspecting that perhaps it is not processing them at all - perhaps I'm missing some other option along the lines of CURLOPT_PLEASE_USE_SSL_AUTHENTICATION which is resulting in the files being ignored?

EDIT: So for the record, the full sequence looks like this (some text hidden):

curl_easy_setopt(curl, CURLOPT_URL, "https://identitysso.betfair.com/api/certlogin");
curl_easy_setopt(curl, CURLOPT_SSLCERT,"client-2048.crt");
curl_easy_setopt(curl, CURLOPT_SSLKEY,"client-2048.key");
curl_easy_setopt(curl, CURLOPT_POST, 1);

struct curl_slist *chunk = NULL;
chunk = curl_slist_append(chunk, "X-Application: _HIDDEN_");
chunk = curl_slist_append(chunk,"Content-Type: application/x-www-form-urlencoded");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);

curl_easy_setopt(curl, CURLOPT_POSTFIELDS,"username=_HIDDEN_&password=_HIDDEN_");

curl_easy_perform(curl);

EDIT: I thought that perhaps I somehow compiled my libcurl without SSL. To check this I called curl_version_info, which amongst other things gives you:

char *ssl_version;        /* human readable string */

Printing this out gave the string "WinSSL" which I assume means that SSL is included.

EDIT: FYI, I have four "client-2048" files, a .crt, .pem, .key and .csr. They all sit on the same directory as my exe file. I also print out the current working directory (as reported by _getcwd()) at run time just do double check that my exe is running from the right location.

EDIT: Here is my working login.sh (please excuse it's inelegance, I was hacking with cut and paste code and scarcely knew what I was doing). getlog.exe was a tiny utility I wrote to do some string manipulation on some JSON.

#!/bin/bash    
# uses rescript    
APP_KEY=_HIDDEN_
#SESSION_TOKEN=$2

HOST=https://api.betfair.com/exchange/betting
AUTHURL=https://identitysso.betfair.com/api/certlogin
CURL=curl    

function bflogin()
{
    echo "bflogin()"

    OUT=$($CURL -s -k --cert client-2048.crt --key client-2048.key --data "username=_HIDDEN_&password=_HIDDEN_" -H "X-Application: $APP_KEY" -H "Content-Type: application/x-www-form-urlencoded" $AUTHURL)
    echo $OUT
    SESSION_TOKEN=$(echo $OUT | getlog.exe)
    echo
    echo "Here -> "$SESSION_TOKEN
    echo $SESSION_TOKEN > st.txt
}
Mick
  • 8,284
  • 22
  • 81
  • 173
  • That looks like some kind of API response to a request, not something you would get because of SSL problems. What are you trying to do? What request are you making? To what? – Some programmer dude Mar 14 '17 at 12:32
  • I'm just trying to login. - Question edited. – Mick Mar 14 '17 at 12:32
  • cert_auth_required implies that both client certificates need to be installed and a ca cert store to validate the servers identity. – Chris Becke Mar 14 '17 at 14:07
  • @Chris Becke: A "ca cert store"? Is that a file like "client-2048.something"? pem? csr? So are you saying I need something like curl_easy_setopt(curl, CURLOPT_HERE_IS_THE_CA_STORE,"castorefilename"); ? – Mick Mar 14 '17 at 14:51
  • I've never used curl, but yes, I would imagine for client authenticated comms you need to initialize both the client cert to use and either the cert, or a cert store to authenticate the server. – Chris Becke Mar 15 '17 at 05:40
  • When you were with curl directly, was that on the same (windows?) machine? You mention bash so it sounds like a different machine. Also would be helpful if you could include the curl CLI command that actually did work – harmic Mar 21 '17 at 09:08
  • Yes, same windows machine - I had installed "winbash". – Mick Mar 21 '17 at 13:13

1 Answers1

1

Double check the paths to you crt and key files.

Also, since you haven't specified a key encoding type, PEM is the default. You can change the encoding type with the CURLOPT_SSLCERTTYPE option, or try converting your keys to PEM.

Community
  • 1
  • 1
Mark Mucha
  • 1,560
  • 2
  • 12
  • 18
  • See edit to original post... What string should I pass as my "type" in my call to curl_easy_setopt(CURL *handle, CURLOPT_SSLCERTTYPE, char *type)? – Mick Mar 16 '17 at 17:42