Failed to login with SSL certificate using C ++, Qt and Betfair API-NG

I'm in the process of writing a new Betfair bot in C ++ using Qt, but I'm falling over the first hurdle with the login process. After reading a lot, I decided to use QNetworkAccessManager

and this is what I currently have:

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    BetfairManager bet_man;
    QNetworkAccessManager *manager = new QNetworkAccessManager();
    QObject::connect(manager, SIGNAL(finished(QNetworkReply*)),
                        &bet_man,SLOT(replyFinished(QNetworkReply*)));
    QObject::connect(manager,SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
                     &bet_man,SLOT(replySSLErrors(QNetworkReply*,QList<QSslError>)));
    QObject::connect(manager,SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
                     &bet_man,SLOT(replyAuthenticationRequired(QNetworkReply*,QAuthenticator*)));
    QObject::connect(manager,SIGNAL(proxyAuthenticationRequired(const QNetworkProxy&,QAuthenticator*)),
                     &bet_man,SLOT(replyProxyAuthenticationRequired(const QNetworkProxy&,QAuthenticator*)));
    QNetworkRequest request;


    QByteArray payload("username=myusername&password=mypassword");
    QString url("https://identitysso.betfair.com/api/certlogin");
    QSslConfiguration config;
    QString pemfile("../../client-2048.pem");
    QFile file(pemfile);
    if(!file.exists()) {
       qWarning("Filename %s doesn't exists.", qPrintable(pemfile));
    }

    if(!file.open(QIODevice::ReadOnly)) {
        qWarning("Cannot open filename %s.", qPrintable(pemfile));
    }
    QByteArray data = file.readAll();

    QSslCertificate sslcert(data, QSsl::Pem);
    if(sslcert.isNull()) {
        qWarning("The certificate has no content.");
    }

    config.setLocalCertificate(sslcert);
    request.setSslConfiguration(config);
    request.setUrl(url);
    request.setRawHeader("X-Application","mykey");
    request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");

    manager->post(request,payload);

    return a.exec();
}

      

The class BetfairManager

is just a dummy class I created to have slots for signals QNetworkAccessManager

- they just dump some debug information to the screen to see what signals were emitted.

When I run the above, I see that the signal is QNetworkAccessManager::finished()

fired, but I have an empty response - not even the HTTP headers.

When I stop installing the certificate by commenting out the line

request.setSslConfiguration(config);

      

I get an answer

"{"loginStatus":"CERT_AUTH_REQUIRED"}"

      

which is unsurprising, but shows that I am passing the correct parameters in my request, so I am convinced that the problem lies in my mechanism for passing / generating certificates with the Qt classes.

I created a .pem file according to the betfair documentation (which says to create it from adding .crt and .key files) and I know they are fine as I also have a Python bot that works great the same files.

I am new to Qt, not an SSL expert, and I am under the impression that I am missing something fundamental.

In case this is helpful, this is my equivalent Python code that works fine using the package urllib2

un = "myusername";
pw = "mypassword";
app_key = 'mykey'

payload = 'username=' + un + '&password=' + pw
login_headers = {'X-Application': app_key, 'Content-Type': 'application/x-www-form-urlencoded'}
resp = requests.post('https://identitysso.betfair.com/api/certlogin', data=payload, cert=('client-2048.crt', 'client-2048.key'), headers=login_headers)

      

I am developing this using Qt 5.2.1 on Ubuntu 14.04

+3


source to share


1 answer


If you want to log in over an SSL connection using a client certificate, you must additionally specify the client's private key. A certificate is basically just a public key that someone else verifies. Access is granted when you can prove to the server that you also have the private key to the certificate.

You can do this using the following methods:



// get certData and keyData from files

QSslConfiguration config;

QSslCertificate sslcert(certData, QSsl::Der);
config.setLocalCertificate(sslcert);

QSslKey privkey(keyData, QSsl::Rsa, QSsl::Der, QSsl::PrivateKey, "myKeyPassword")
config.​setPrivateKey(privkey);

      

If both of your source file client-2048.crt

and client-2048.key

are binary, it is likely that they are stored in DER format. In this case, you can specify the input format as above and you don't need to convert anything.

+3


source







All Articles