QNetworkRequest с локальным сертификатом ssl - PullRequest
2 голосов
/ 22 сентября 2011

Мне нужно обмениваться данными с сервером, который требует локального сертификата (файл .crt). Я пытаюсь это:

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

Когда этот код выполняется, у меня появляются следующие сообщения в WireShark (фильтр: 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)

Это ожидается - код для применения сертификата закомментирован, но странная вещь - я не получаю никаких ошибок ssl от моих QNetworkAccessManager и QNetworkReply (slots printSslErrors и printSslErrors2).

Если я раскомментирую любую из этих 3 строк:

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

Я ничего не получаю в Wireshark (мало сообщений SYN, ACK и FIN tcp, но нет трафика http или ssl). Также до сих пор нет ошибок от QNetworkAccessManager и QNetworkReply, поэтому у меня нет никакой идеи, что происходит не так.

Есть ли шанс заставить Qt принять мой локальный сертификат или, может быть, есть какая-то сторонняя библиотека, ориентированная на qt, которая может мне помочь?

P.S .: btw - ssl и https отлично работали несколько дней назад, до того, как сервер был заменен на клиентские сертификаты.

P.P.S .: сертификат самозаверяющий, если это имеет значение Также я попытался «установить» его (файл p12) в систему, и Chrome и IE7 могут использовать его и обмениваться данными с сервером.

Ответы [ 2 ]

1 голос
/ 22 сентября 2011

Выполните снимок в темноте и исходите из предположения, что Qt может фактически сообщать об ошибке, но вы не получаете сигнал.

Вы подключаете сигналы от вашего connectionManager к this Вы включили макрос Q_OBJECT в заголовок для this?

Также проверьте вывод при запуске приложения, поскольку Qt может сообщать о проблемах, связанных с сигналами / слотами, если это действительно так.

0 голосов
/ 18 декабря 2013

РЕШЕНИЕ, часть I: Я в основном решил это (отсутствие связи), было 2 причины:

1-й - серверу apache действительно требуется закрытый ключ (по неизвестной причине нашел его [здесь] [1]), как добавить закрытый ключ:

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 - сертификат, который у меня был, был не очень «хорошим». Я не знаю, что это на самом деле означает или почему он не работает, но когда я получил новый сертификат от администратора сервера и добавил закрытый ключ, рукопожатие прошло успешно.

Я до сих пор не знаю, как отлавливать sslErrors (например, чтобы показать пользователю, что его сертификат не работает), но это хорошее начало

РЕШЕНИЕ, часть II:

Решил последнюю часть вопроса (kina a woraround). Кажется, что QNetworkReply не генерирует SslErrors, является ошибкой (или, по крайней мере, она не работает постоянно или для всех веб-сайтов), обнаружил ее [в Qt bug tracker] [2]. И обходной путь также оттуда: поскольку мы не можем получить SslErrors, мы должны попытаться получить что-то еще - например, [error] [3]. Он не дает подробной информации о том, что на самом деле произошло, но лучше, чем ничего. Для меня код ошибки 6 - «рукопожатие SSL / TLS не удалось, и зашифрованный канал не может быть установлен. Сигнал sslErrors () должен был быть передан». идеально подходит (я не забочусь ни о чем другом):

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

Важная часть: если у пользователя неверный сертификат и / или ключ - выдается сигнал. Но он также выдается, если сертификат и ключ верны. Кажется, аутентификация все еще не идеальна, но вы можете легко отключить ее с помощью

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

Заключение похоже, они исправили много ошибок SSL в Qt 4.8, поэтому я надеюсь, что релиз будет в ближайшее время

...