v
Feb. 27, 2020, 4:13 a.m.

Не получается подключиться с SSL-сертификатом к API

qt, c++, openssl

Всем привет! Я пытаюсь написать бота биржи ставок Betfair, используя их API, с помощью Qt и C++. Мне нужно подключиться к их API в неинтерактивном режиме, поэтому я создал сертификат и закрытый ключ через OpenSSl (64-bit), которую я скачал отдельно от Qt. На Python у меня все работает хорошо, это означает, что сертификат и ключ созданы правильно.

  1. import requests
  2.  
  3. payload = 'username=myusername&password=mypassword'
  4. headers = {'X-Application': 'myappkey',
  5. 'Content-Type': 'application/x-www-form-urlencoded'}
  6.  
  7. response = requests.post('https://identitysso-cert.betfair.com/api/certlogin',
  8. data=payload,
  9. cert=('C:/Program Files/OpenSSL-Win64/bin/client-2048.crt',
  10. 'C:/Program Files/OpenSSL-Win64/bin/client-2048.key'),
  11. headers=headers)

Пытаюсь сделать аналогичное на C++ и Qt, но ничего не выходит.

  1. #include <QCoreApplication>
  2.  
  3. #include <QNetworkAccessManager>
  4. #include <QFile>
  5. #include <QNetworkReply>
  6. #include <QSslKey>
  7. #include <QSslConfiguration>
  8.  
  9. #include <QDebug>
  10.  
  11. QSslCertificate sslCertificate()
  12. {
  13. QFile certFile("C:/Program Files/OpenSSL-Win64/bin/client-2048.crt");
  14.  
  15. if(!certFile.exists()) {
  16. qDebug()<<"The certificate file doesn't exist";
  17. return QSslCertificate();
  18. }
  19.  
  20. if(!certFile.open(QIODevice::ReadOnly)) {
  21. qDebug()<<"Can't open certificate file";
  22. return QSslCertificate();
  23. }
  24.  
  25. QByteArray certData = certFile.readAll();
  26.  
  27. QSslCertificate sslCert(certData);
  28.  
  29. if(sslCert.isNull()) {
  30. qDebug("The certificate has no content");
  31. return QSslCertificate();
  32. }
  33.  
  34. return sslCert;
  35. }
  36.  
  37. QSslKey sslKey()
  38. {
  39. QFile keyFile("C:/Program Files/OpenSSL-Win64/bin/client-2048.key");
  40.  
  41. if(!keyFile.exists()) {
  42. qDebug()<<"The key file doesn't exist";
  43. return QSslKey();
  44. }
  45.  
  46. if(!keyFile.open(QIODevice::ReadOnly)) {
  47. qDebug()<<"Can't open key file";
  48. return QSslKey();
  49. }
  50.  
  51. QByteArray keyData = keyFile.readAll();
  52.  
  53. QSslKey sslKey(keyData, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
  54.  
  55. if(sslKey.isNull()) {
  56. qDebug("The key has no content");
  57. return QSslKey();
  58. }
  59.  
  60. return sslKey;
  61. }
  62.  
  63. int main(int argc, char *argv[])
  64. {
  65. QCoreApplication a(argc, argv);
  66.  
  67. QNetworkAccessManager manager;
  68.  
  69. QNetworkRequest request;
  70.  
  71. QByteArray payload("username=myusername&password=mypassword");
  72. QString url("https://identitysso.betfair.com/api/certlogin");
  73.  
  74. QSslConfiguration sslConfig;
  75. sslConfig.setLocalCertificate(sslCertificate());
  76. sslConfig.setPrivateKey(sslKey());
  77.  
  78. request.setSslConfiguration(sslConfig);
  79. request.setUrl(url);
  80. request.setRawHeader("X-Application", "myappkey");
  81. request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
  82.  
  83. qDebug()<<manager.post(request, payload)->readAll();
  84.  
  85. return a.exec();
  86. }

Вывод данной программы следующий:
The certificate has no content
The key has no content
""
qt.network.ssl: QSslSocket::connectToHostEncrypted: TLS initialization failed

Необходимо заметить, что я полный чайник в этом OpenSSL и слабо понимаю, что здесь происходит. Делал это по гайдам и документации Betfair API.

Много чего гуглил по данной проблеме, поэтому скажу, что возможно, у меня не так:
1. Ничего не прописано в файле .pro по OpenSSL
2. Я использую компилятор MinGW 7.3.0 32-bit, а OpenSSL, с помощью которого у меня сделан сертификат и ключ, 64-bit
3. Не добавлены какие-то либы OpenSSL в какие-то Qt-шные файлы или в файл проекта

Пожалуйста, скажите, как мне сделать так, чтобы все работало прекрасно и легко, как на Python))
Заранее благодарен!

5

Do you like it? Share on social networks!

8
Алексей Внуков
  • Feb. 27, 2020, 4:58 a.m.

TLS initialization failed - говорит что приложению не хватает библиотек OpenSSL, просто скопируйте их и положите рядом с исполняемым файлом

    v
    • Feb. 27, 2020, 5:13 a.m.
    • (edited)

    Добавил в папку проекта следующие либы, ничего не изменилось.
    Папка проекта

    Надо что-то где-то дополнительно прописывать или нет? Я просто не очень понимаю...

      положи их рядом с исполняемым файлом (.exe) в папке сборки

        Алексей Внуков
        • Feb. 27, 2020, 2:24 p.m.

        только смотри разрядность твоей сборки и разрядность библиотек, они должны совпадать, если приложение 64-х битное то и библиотеки должны быть 64-х битными и т.д.

          Положил в Build файл, результат не изменился.

            v
            • Feb. 27, 2020, 2:26 p.m.
            • (edited)

            Вот да...У меня 32-битный MinGW. Значит, мне надо делать сертификат и ключ через 32-битный OpenSSL, да?
            Ну и соответственно либы оттуда брать...

              v
              • Feb. 27, 2020, 3:53 p.m.

              Я скачал Qt-шный 32-битный OpenSSL из Maintenance Tool, сгенерировал новый сертификат и ключ, добавил 32-битные либы в сборку проекта и изменил пути сертификата и ключа на новые. Из вывода вышеуказанной программы ушли строчки:
              The certificate has no content
              The key has no content
              qt.network.ssl: QSslSocket::connectToHostEncrypted: TLS initialization failed

              Но в качестве ответа на запрос приходит по-прежнему почему-то пустая строка. Проверял новые сертификаты на Python, все работает. Может я как-то неправильно запрос отправляю или ответ считываю как-то не так?...

                v
                • Feb. 27, 2020, 8 p.m.
                • The answer was marked as a solution.

                Проблема решилась путем следующих манипуляций:
                1. Небольшое изменение url (на https://identitysso-cert.betfair.com/api/certlogin)
                2. Установки OpenSSL 32-bit (разрядность должна соответствовать разрядности компилятора)
                3. Генерации сертификата и закрытого ключа указанного выше OpenSSL
                4. Добавления libcrypto-1_1.dll и libssl-1_1.dll в папку сборки проекта

                Всем спасибо!

                P.S. Также очень важно работать с ответом запроса только после того, как получен сигнал QNetworkAccessManager::finished, иначе получится чтение ответа до момента его получения от сервера.

                  Comments

                  Only authorized users can post comments.
                  Please, Log in or Sign up
                  • Last comments
                  • AK
                    April 1, 2025, 11:41 a.m.
                    Добрый день. В данный момент работаю над проектом, где необходимо выводить звук из программы в определенное аудиоустройство (колонки, наушники, виртуальный кабель и т.д). Пишу на Qt5.12.12 поско…
                  • Evgenii Legotckoi
                    March 9, 2025, 9:02 p.m.
                    К сожалению, я этого подсказать не могу, поскольку у меня нет необходимости в обходе блокировок и т.д. Поэтому я и не задавался решением этой проблемы. Ну выглядит так, что вам действитель…
                  • VP
                    March 9, 2025, 4:14 p.m.
                    Здравствуйте! Я устанавливал Qt6 из исходников а также Qt Creator по отдельности. Все компоненты, связанные с разработкой для Android, установлены. Кроме одного... Когда пытаюсь скомпилиров…
                  • ИМ
                    Nov. 22, 2024, 9:51 p.m.
                    Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
                  • Evgenii Legotckoi
                    Oct. 31, 2024, 11:37 p.m.
                    Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup