Невозможно войти с SSL-сертификатом, используя C ++, Qt и Betfair API-NG

Я нахожусь в процессе написания нового бота Betfair на C ++ с использованием Qt, но я падаю на первое препятствие с процессом входа в систему. После долгого чтения я решил использовать QNetworkAccessManager и вот что у меня сейчас есть:

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();
}

BetfairManager класс это просто фиктивный класс, который я создал, чтобы иметь слоты для QNetworkAccessManager сигналы — они просто выводят некоторую отладочную информацию на экран, чтобы увидеть, какие сигналы были выпущены.

Когда я запускаю вышеизложенное, я вижу, что QNetworkAccessManager::finished() сигнал сработал, но у меня пустой ответ — нет даже никаких заголовков HTTP.

Когда я прекращаю устанавливать сертификат, комментируя строку

request.setSslConfiguration(config);

Я получаю ответ

"{"loginStatus":"CERT_AUTH_REQUIRED"}"

что неудивительно, но показывает, что я передаю правильные параметры в своем запросе, поэтому я убежден, что проблема заключается в моем механизме передачи / создания сертификатов с классами Qt.

Я создал файл .pem в соответствии с документацией betfair (в которой говорится, что его нужно создавать, добавляя сгенерированные файлы .crt и .key), и я знаю, что они в порядке, так как у меня также есть бот Python, который отлично работает с теми же файлами ,

Я новичок в Qt и не эксперт по SSL, и у меня складывается впечатление, что мне здесь не хватает чего-то фундаментального.

В случае, если это полезно, вот мой эквивалентный код на Python, который отлично работает, используя 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)

Я разрабатываю это с Qt 5.2.1 на Ubuntu 14.04

3

Решение

Если вы хотите войти через соединение SSL с использованием сертификата клиента, вам необходимо дополнительно указать закрытый ключ клиента. Сертификат — это в основном только открытый ключ, который кто-то проверял. Доступ предоставляется, когда вы можете доказать серверу, что у вас также есть закрытый ключ к сертификату.

Вы можете сделать это, используя следующие методы:

// 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);

Когда оба ваших оригинальных файла client-2048.crt а также client-2048.key являются двоичными, вероятно, они хранятся в формате DER. В этом случае вы можете указать формат ввода, как указано выше, и вам не нужно ничего преобразовывать.

3

Другие решения


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector