SSL: Handshake failed for requests made from QML.
-
Hey, I make some https requests directly from my qml views, for instance for image sources. As I have a self signed certificate server side, I need to tell qt to ignore some ssl errors. (I control both the server and the client applications, so this shouldn't be a problem really.)
I've made a QQmlNetworkAccessManagerFactory to create NAMs, where I connect to the sslErrors signal.
UltraQmlAccessManagerFactory.h
#ifndef FACKFACKTORy_H #define FACKFACKTORy_H #include <QQmlNetworkAccessManagerFactory> #include <QObject> #include <QNetworkReply> #include <QList> #include <QSslError> #include <QNetworkAccessManager> #include <QDebug> #include <QSslCertificate> class UltraQmlNetworkAccessManagerFactory : public QObject, public QQmlNetworkAccessManagerFactory { Q_OBJECT private: QNetworkAccessManager* nam; QList<QSslError> expectedSslErrors; public: explicit UltraQmlNetworkAccessManagerFactory(); ~UltraQmlNetworkAccessManagerFactory(); virtual QNetworkAccessManager* create(QObject* parent); public slots: void onIgnoreSslErrors(QNetworkReply* reply, QList<QSslError> errors); }; #endif
UltraQmlNetworkAccessManagerFactory.cpp
#include "UltraQmlNetworkAccessManagerFactory.h" UltraQmlNetworkAccessManagerFactory::UltraQmlNetworkAccessManagerFactory() { // disregard this for now... QList<QSslCertificate> cert = QSslCertificate::fromPath(":/public.crt"); QSslError self_signed_error(QSslError::SelfSignedCertificate, cert.at(0)); QSslError host_name_error(QSslError::HostNameMismatch, cert.at(0)); // QSslError untrusted_error(QSslError::CertificateUntrusted, cert.at(0)); expectedSslErrors.append(self_signed_error); // expectedSslErrors.append(host_name_error); // expectedSslErrors.append(untrusted_error); } UltraQmlNetworkAccessManagerFactory::~UltraQmlNetworkAccessManagerFactory() { delete nam; } QNetworkAccessManager* UltraQmlNetworkAccessManagerFactory::create(QObject* parent) { QNetworkAccessManager* nam = new QNetworkAccessManager(parent); QObject::connect(nam, SIGNAL(sslErrors(QNetworkReply*, QList<QSslError>)), this, SLOT(onIgnoreSslErrors(QNetworkReply*,QList<QSslError>)) ); return nam; } void UltraQmlNetworkAccessManagerFactory::onIgnoreSslErrors(QNetworkReply *reply, QList<QSslError> errors) { QNetworkRequest req = reply->request(); qDebug() << "Hello!" << endl; for (int i = 0; i < errors.size(); i++) { qDebug() << "e: " << errors.at(i) << endl; } reply->ignoreSslErrors(errors); }
There is also some glue in main.cpp that sets this factory to be used, I doubt that part is a source of errors as the qDebug prints are visible in the output.
As you can see in the .cpp file in the function/slot onIgnoreSslErrors, I try to ignore every error (as a test) that I receive, but as you can see in the output I do not get the expected results.
Output
Hello! e: "The certificate is self-signed, and untrusted" qrc:/qml/file/ImageView.qml:16:5: QML Image: SSL handshake failed
I have successfully made QNetworkRequests from c++ directly with a QSslConfiguration, specifying TLSV1_0 and a certificate. As I have a suspicion that the handshake fails because one side expects SSL and the other TLS I have also tried to set the QSslConfiguration on the QNetworkRequest object throgh reply->request(); This however, changes nothing.
Thanks for taking time to read my post.
Pelle K
-
@PelleKrogstad
I too had the same requirement. Looking further into I found out that the slot foronIgnoreSslErrors
was never called as it is required for Self Signed Certificates and which cause these SSL errors.
So actually the request needs to modified a bit which could be done by re-implementing createRequest
Thus in QNAM subclassed class:QNetworkReply *MyNam::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData) { QNetworkRequest req = request; QSslConfiguration conf = req.sslConfiguration(); conf.setProtocol(QSsl::AnyProtocol); req.setSslConfiguration(conf); QNetworkReply *reply = QNetworkAccessManager::createRequest(op, req, outgoingData); qDebug() << req.url(); return reply; }
And thus the
ignoreSSLErrors
slot was called where the errors were ignored. This worked for me. Let me know if it works for you.