QSslSocket雙向認證設(shè)置

1 證書生成

因為目標(biāo)是實現(xiàn)雙向認證米碰,所以需要將自己的公鑰和私鑰以及對端的私鑰加載到Qt的安全環(huán)境中。證書可借助keytoolopenssl工具生成堡掏,總結(jié)幾個比較常用的生成命令如下:

# 生成jks格式密鑰庫
keytool -genkey -v -alias tomcat -keyalg RSA -keystore tomcat.keystore -validity 36500
# 從jks格式密鑰庫中導(dǎo)出證書(DER格式)
keytool -keystore  tomcat.keystore -export -alias tomcat -file server.cer  -storepass 123456
# 生成p12格式密鑰庫
keytool -genkey -v -alias mykey -keyalg RSA -storetype PKCS12 -keystore mykey.p12 -storepass 123456
# 將jks格式密鑰庫轉(zhuǎn)化為p12格式
keytool -importkeystore -srckeystore tomcat.keystore -destkeystore tomcat.p12 -srcstoretype JKS -deststoretype PKCS12 -srcstorepass 123456 -deststorepass 123456 -srcalias tomcat -destalias tomcat -srckeypass 123456 -destkeypass 123456 -noprompt
# 從p12密鑰庫中導(dǎo)出公鑰和私鑰(PEM格式)
openssl pkcs12 -clcerts -nokeys -in mykey.p12 -out cert.pem
openssl pkcs12 -nocerts -nodes -in mykey.p12 -out private.pem
# 向jks格式密鑰庫中導(dǎo)入可信任的證書
keytool -import -v -file cert.pem -keystore clients.keystore  -storepass 123456

2 QSslSocket設(shè)置

首先客戶端和服務(wù)器都必須加載本地的私鑰应结、證書和信任庫。在QSslSocket中這三個設(shè)置分別對應(yīng)localCertificate, privateKey和caCertificates泉唁。同時雙向認證需要設(shè)置VerifyPeer和Depth = 1鹅龄。以客戶端為例,加載方法如下:

bool ClientSimulator::loadSslFiles()
{
    bool openOk = false;
    QFile certFile(QDir::currentPath() + QString("/sslCert/server.cer"));
    openOk = certFile.open(QIODevice::ReadOnly);
    m_certificate = QSslCertificate(certFile.readAll(), QSsl::Der);
    openOk &= !m_certificate.isNull();
 
    QFile keyFile(QDir::currentPath() + QString("/sslCert/ckey.pem"));
    openOk &= keyFile.open(QIODevice::ReadOnly);
    m_privateKey = QSslKey(keyFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
    openOk &= !m_privateKey.isNull();
 
    QFile peerFile(QDir::currentPath() + QString("/sslCert/cert.pem"));
    openOk &= peerFile.open(QIODevice::ReadOnly);
    QSslCertificate peerCert(peerFile.readAll(), QSsl::Pem);
    bool peerCertValid = !peerCert.isNull();
    openOk &= peerCertValid;
 
    QList<QSslCertificate> caCerts;
    caCerts << peerCert;
    m_caCertificates = caCerts;
 
    return openOk;
}

之后在客戶端連接到服務(wù)器時亭畜,設(shè)置加載好的證書和密鑰:

if(loadSslFiles())
{
    m_socket->setLocalCertificate(m_certificate);
    m_socket->setPrivateKey(m_privateKey);
    m_socket->setCaCertificates(m_caCertificates);
    m_socket->setPeerVerifyMode(QSslSocket::VerifyPeer);
    m_socket->setPeerVerifyDepth(1);
    m_socket->connectToHostEncrypted(ui->lineEditIP->text(), port);
}
else
{
    QMessageBox::warning(this, "SSL File Error", "Load SSL Files failed.");
}

這里m_socket是QSslSocket類的實例扮休。
服務(wù)器端的設(shè)置類似,重載incommingConnection方法拴鸵,參考實現(xiàn)如下:

void SslServer::incomingConnection(qintptr socketDescriptor)
{
    if(!m_client.isNull())
    {
        m_client->disconnectFromHost();
        disconnect(m_client, SIGNAL(readyRead()), this, SLOT(onRecvFromClient()));
        disconnect(m_client, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(onSslErrors(QList<QSslError>)));
        delete m_client;
    }
    m_client = new QSslSocket(this);
    m_client->setSocketDescriptor(socketDescriptor);
    if(m_sslConfig != NULL)
    {
        m_client->setLocalCertificate(m_sslConfig->certificate());
        m_client->setPrivateKey(m_sslConfig->privateKey());
        m_client->setCaCertificates(m_sslConfig->caCertificates());
    }
    m_client->setPeerVerifyMode(QSslSocket::VerifyPeer);
    m_client->setPeerVerifyDepth(1);
    connect(m_client, SIGNAL(readyRead()), this, SLOT(onRecvFromClient()));
    connect(m_client, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(onSslErrors(const QList<QSslError> &)));
    m_client->startServerEncryption();
    QTcpServer::incomingConnection(socketDescriptor);
}

注意:

  • 在客戶端連接服務(wù)端時玷坠,要調(diào)用加密連接方法connectToHostEncrypted()蜗搔。如果使用普通的鏈接connectToHost()方法,會報無效套接字的錯八堡。
  • 同理樟凄,在服務(wù)端連接客戶端時,需調(diào)用加密通信方法startServerEncryption()兄渺。
  • 連接的IP要和信任庫中證書所提供的IP一致缝龄,否則可能會出現(xiàn)IP不匹配的告警。
  • 如果ssl環(huán)境設(shè)置需要在多個地方復(fù)用溶耘,可以將設(shè)置統(tǒng)一加載到QSslConfiguration類的實例中二拐,之后通過QSslSocket的setSslConfiguration方法進行加載。QSslConfiguration提供的接口與上面范例中的比較類似凳兵,這里就不贅述了百新。
  • 除上述直接載入證書和秘鑰文件的方法外,qt5.4之后還支持直接從pkcs12格式的文件解析并載入證書庐扫,調(diào)用靜態(tài)方法QSslCertificate::importPkcs12()即可饭望,范例如下:
QFile keyFile("/certs/ks.p12");
bool openOK = keyFile.open(QIODevice::ReadWrite);

QSslKey key;
QSslCertificate certs;
QList<QSslCertificate> caCerts;

QByteArray passPhrase = QString("test123").toLatin1();
openOK = QSslCertificate::importPkcs12(&keyFile, &key, &certs, &caCerts, passPhrase);
keyFile.close();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市形庭,隨后出現(xiàn)的幾起案子铅辞,更是在濱河造成了極大的恐慌,老刑警劉巖萨醒,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件斟珊,死亡現(xiàn)場離奇詭異,居然都是意外死亡富纸,警方通過查閱死者的電腦和手機囤踩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晓褪,“玉大人堵漱,你說我怎么就攤上這事』练拢” “怎么了勤庐?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長好港。 經(jīng)常有香客問我愉镰,道長,這世上最難降的妖魔是什么钧汹? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任岛杀,我火速辦了婚禮,結(jié)果婚禮上崭孤,老公的妹妹穿的比我還像新娘类嗤。我一直安慰自己糊肠,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布遗锣。 她就那樣靜靜地躺著货裹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪精偿。 梳的紋絲不亂的頭發(fā)上弧圆,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機與錄音笔咽,去河邊找鬼搔预。 笑死,一個胖子當(dāng)著我的面吹牛叶组,可吹牛的內(nèi)容都是我干的拯田。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼甩十,長吁一口氣:“原來是場噩夢啊……” “哼船庇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起侣监,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤鸭轮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后橄霉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體窃爷,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年姓蜂,在試婚紗的時候發(fā)現(xiàn)自己被綠了按厘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡覆糟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出遮咖,到底是詐尸還是另有隱情滩字,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布御吞,位于F島的核電站麦箍,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏陶珠。R本人自食惡果不足惜挟裂,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望揍诽。 院中可真熱鬧诀蓉,春花似錦栗竖、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至沥曹,卻和暖如春份名,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背妓美。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工僵腺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人壶栋。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓辰如,卻偏偏與公主長得像,于是被迫代替她去往敵國和親委刘。 傳聞我的和親對象是個殘疾皇子丧没,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容