2 votes

QNetworkRequest avec certificat local ssl

Je dois échanger des données avec un serveur qui nécessite un certificat local (fichier .crt). J'essaie ceci :

loginRequest = QNetworkRequest(QUrl("https://somesite.com/login"));

QSslConfiguration sslConf = loginRequest.sslConfiguration();
QList<QSslCertificate> certs = QSslCertificate::fromPath(Preferences::certificatePath());
qDebug() << certs.first().issuerInfo(QSslCertificate::Organization); // prints name
sslConf.setLocalCertificate(certs.first());
qDebug() << "is valid " << sslConf.localCertificate().isValid(); // true
qDebug() << "is null " << sslConf.localCertificate().isNull(); // false
qDebug() << "protocol " << sslConf.protocol(); // 0
sslConf.setProtocol(QSsl::SslV3); // i also tried Qssl::AnyProtocol
qDebug() << "protocol " << sslConf.protocol(); // 0

// if i uncomment these i expect everithing to work
//QSslConfiguration::setDefaultConfiguration(sslConf);
//QSslSocket::addDefaultCaCertificate(certs.first());
//loginRequest.setSslConfiguration(sslConf);

QObject::connect(connectionManager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), this, SLOT(printSslErrors2(QNetworkReply*,QList<QSslError>)));

m_reply = connectionManager->get(loginRequest);
QObject::connect(m_reply, SIGNAL(readyRead()), this, SLOT(getCookie()));
QObject::connect(m_reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(printSslErrors(QList<QSslError>)));

Lorsque ce code s'exécute, j'ai les messages suivants dans WireShark (filter : tcp && ssl && ip.addr == my_addr) :

Client Hello
ServerHello, Certificate
Server Key Exchange, Certificate request, Server Hello Done
Alert (level: Warning, Description: no certificate), client key exchange, change cipher spec, encrypted handshake message
Alert (level: Fatal, Description: Handshake failure)

C'est attendu - le code pour appliquer le certificat est commenté, mais la chose étrange - je ne reçois aucune erreur ssl de mon QNetworkAccessManager et QNetworkReply (slots printSslErrors et printSslErrors2).

Si je décommente une de ces 3 lignes :

 //QSslConfiguration::setDefaultConfiguration(sslConf);
 //QSslSocket::addDefaultCaCertificate(certs.first());
 //loginRequest.setSslConfiguration(sslConf);

Je n'obtiens RIEN dans wireshark (quelques messages tcp SYN, ACK et FIN, mais aucun trafic http ou ssl). De plus, il n'y a toujours pas d'erreurs de QNetworkAccessManager et QNetworkReply, donc je n'ai aucune idée de ce qui ne va pas.

Existe-t-il une possibilité de faire en sorte que Qt accepte mon certificat local ou peut-être existe-t-il une librairie tierce orientée Qt pour m'aider ?

P.S. : btw - ssl et https fonctionnaient très bien il y a quelques jours, avant que le serveur ne soit modifié pour exiger des certificats côté client.

P.P.S. : le certificat est auto-signé si cela fait une différence. J'ai également essayé de l'installer (le fichier p12) dans le système et Chrome et IE7 sont capables de l'utiliser et de communiquer avec le serveur.

1voto

Matthew Points 1655

Il s'agit d'un coup d'épée dans l'eau qui part du principe que Qt peut en fait signaler une erreur mais que vous ne recevez pas le signal.

Vous connectez les signaux de votre connectionManager a this avez-vous inclus le Q_OBJECT dans l'en-tête de this ?

Examinez également la sortie lorsque vous exécutez votre application, car Qt peut signaler des problèmes de connexion des signaux/slots si c'est effectivement le cas ici.

0voto

DarkWalker Points 710

SOLUTION, première partie : J'ai en grande partie résolu ce problème (le manque de connexion), il y avait 2 raisons :

1er - le serveur apache nécessite une clé privée (pour une raison inconnue, je l'ai trouvé [ici][1]), comment ajouter une clé privée :

QFile x(Preferences::certificateKeyPath()); 
x.open(QIODevice::ReadOnly);
pKey = QSslKey(x.readAll(),QSsl::Rsa);
QSslError error1(QSslError::SelfSignedCertificate, certs.first());
QSslError error2(QSslError::CertificateUntrusted, certs.first());
QList<QSslError> expectedSslErrors;
expectedSslErrors.append(error1);
expectedSslErrors.append(error2);

2d - le certificat que j'avais n'était pas très "bon". Je ne sais pas ce que cela signifie réellement ou pourquoi cela ne fonctionnait pas, mais lorsque j'ai obtenu un nouveau certificat de l'administrateur du serveur et ajouté la clé privée, la poignée de main a réussi.

Je ne sais toujours pas comment attraper les sslErrors (par exemple pour montrer à l'utilisateur que son certificat ne fonctionne pas), mais c'est un bon début.

SOLUTION, Partie II :

J'ai résolu la dernière partie de la question (kina une solution de rechange). Il semble que QNetworkReply n'émettant pas de SslErrors est un bug (ou du moins il ne fonctionne pas tout le temps ou pour tous les sites web), je l'ai trouvé [dans Qt bug tracker][2]. Et la solution de contournement vient également de là : puisque nous ne pouvons pas obtenir les SslErrors, nous devons essayer d'obtenir quelque chose d'autre - [error][3], par exemple. Cela ne donne pas d'informations détaillées sur ce qui s'est réellement passé, mais c'est mieux que rien. Pour moi, le code d'erreur 6 - "la poignée de main SSL/TLS a échoué et le canal crypté n'a pas pu être établi. Le signal sslErrors() aurait dû être émis" est parfait (je ne me soucie de rien d'autre) :

 QObject::connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(handleSslErrors(QNetworkReply::NetworkError)));

La partie importante : si l'utilisateur a un mauvais certificat et/ou une mauvaise clé - le signal est émis. Mais il est également émis si le certificat et la clé sont corrects. Il semble que l'authentification ne soit pas encore parfaite, mais vous pouvez facilement la fermer avec

QObject::connect(m_reply, SIGNAL(sslErrors(QList<QSslError>)), 
                  this, SLOT(printSslErrors(QList<QSslError>)));

Conclusion il semble qu'ils aient corrigé un grand nombre de bogues SSL dans Qt 4.8, j'espère donc que la version sera bientôt disponible.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X