2011-09-21 165 views
2

我需要與需要本地證書(.crt文件)的服務器交換數據。 我試試這個:QNetworkRequest與SSL本地證書

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) 

這是預期 - 應用證書的代碼被註釋掉了,但奇怪的是 - 我沒有從我的QNetworkAccessManager和QNetworkReply(插槽printSslErrors和printSslErrors2)獲得任何ssl錯誤。

如果我取消這些3行:

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

我得到Wireshark的NOTHING(幾SYN,ACK和FIN TCP消息,但沒有HTTP或SSL流量)。 QNetworkAccessManager和QNetworkReply仍然沒有錯誤,所以我沒有idia出了什麼問題。

是否有任何機會讓Qt接受我的本地證書或者可能是有一些3d方面的QT導向的lib來幫助我?

P.S .: btw - ssl和https在前幾天工作得很好,在服務器更改爲需要客戶端證書之前。

P.P.S .:證書是自簽名的,如果它有任何區別。另外我試圖將它(p12文件)「安裝」到系統中,並且Chrome和IE7都能夠使用它並與服務器進行通信。

回答

0

解決方案,第一部分: 我主要是解決了這個(缺少連接),有2理由:

月1日 - Apache服務器的實際需要私有密鑰(對於一些未知的原因,發現[如何添加私鑰:如何添加私鑰:

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(例如顯示用戶,他的證書是不工作),但它是一個良好的開端

解決方案,第二部分:

解決了最後這個問題的一部分(基納瓦拉)。看來QNetworkReply沒有發佈SslErrors是一個錯誤(或者至少它不能一直工作或者對所有網站都不起作用),發現它[在Qt bug追蹤器中] [2]。還有解決方法:我們不能得到SslErrors,我們必須嘗試並獲得其他的 - 例如[error] [3]。它沒有提供關於實際發生的事情的詳細信息,但總比沒有更好。對於我來說,錯誤代碼爲6 - 「SSL/TLS握手失敗,無法建立加密通道,sslErrors()信號應該已經發出。」是完美的(我不在乎其他的事):

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

的重要組成部分:如果用戶有錯誤的證書和/或密鑰 - 的信號emited。但是如果證書和密鑰是正確的,它也是有效的。看起來auth可能還是不完美,但是你可以很容易地關閉它,但是你可以很容易地關閉它。

結論似乎他們的Qt 4.8已經修復了許多SSL錯誤的,所以我希望發行會很快

1

在黑暗中完成拍攝,並假設Qt實際上可能會報告錯誤,但您沒有收到信號。

您正在將信號從您的connectionManager連接到this您是否在this的標題中包含了Q_OBJECT宏?

當你運行你的應用程序時也檢查輸出,因爲Qt可能會報告連接信號/插槽的問題,如果這確實是這樣的話。

+0

1.這是一個QMainWindow的,它從登錄按鈕信號(這一個開始登錄序列),所以我不明白爲什麼其他信號可能會被忽略2.信號/插槽沒有錯誤。 Tbh我知道的唯一錯誤(在應用程序輸出窗口中報告)是關於信號並且插槽不存在或者參數錯誤 – DarkWalker

+0

如果您將其他信號傳入QMainWindow類,這很好。在遇到問題時,檢查Q_OBJECT宏是我做的第一件事。希望你追蹤真正的問題。 – Matthew