美文网首页Qt学习程序员
QSslSocket双向认证设置

QSslSocket双向认证设置

作者: ArcDriver | 来源:发表于2018-02-17 11:17 被阅读144次

1 证书生成

因为目标是实现双向认证,所以需要将自己的公钥和私钥以及对端的私钥加载到Qt的安全环境中。证书可借助keytoolopenssl工具生成,总结几个比较常用的生成命令如下:

# 生成jks格式密钥库
keytool -genkey -v -alias tomcat -keyalg RSA -keystore tomcat.keystore -validity 36500
# 从jks格式密钥库中导出证书(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格式密钥库转化为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密钥库中导出公钥和私钥(PEM格式)
openssl pkcs12 -clcerts -nokeys -in mykey.p12 -out cert.pem
openssl pkcs12 -nocerts -nodes -in mykey.p12 -out private.pem
# 向jks格式密钥库中导入可信任的证书
keytool -import -v -file cert.pem -keystore clients.keystore  -storepass 123456

2 QSslSocket设置

首先客户端和服务器都必须加载本地的私钥、证书和信任库。在QSslSocket中这三个设置分别对应localCertificate, privateKey和caCertificates。同时双向认证需要设置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;
}

之后在客户端连接到服务器时,设置加载好的证书和密钥:

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类的实例。
服务器端的设置类似,重载incommingConnection方法,参考实现如下:

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

注意:

  • 在客户端连接服务端时,要调用加密连接方法connectToHostEncrypted()。如果使用普通的链接connectToHost()方法,会报无效套接字的错。
  • 同理,在服务端连接客户端时,需调用加密通信方法startServerEncryption()。
  • 连接的IP要和信任库中证书所提供的IP一致,否则可能会出现IP不匹配的告警。
  • 如果ssl环境设置需要在多个地方复用,可以将设置统一加载到QSslConfiguration类的实例中,之后通过QSslSocket的setSslConfiguration方法进行加载。QSslConfiguration提供的接口与上面范例中的比较类似,这里就不赘述了。
  • 除上述直接载入证书和秘钥文件的方法外,qt5.4之后还支持直接从pkcs12格式的文件解析并载入证书,调用静态方法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();

相关文章

  • QSslSocket双向认证设置

    1 证书生成 因为目标是实现双向认证,所以需要将自己的公钥和私钥以及对端的私钥加载到Qt的安全环境中。证书可借助k...

  • iOS-HTTPS双向认证以及证书操作

    待完善 双向认证 双向认证代理处理简单的请求 NSURLSessionTaskDelegate或 NSURLSes...

  • 数据加密

    1、数据单向认证 2、数据双向认证

  • iOS HTTPS 双向认证

    iOS HTTPS 双向认证 @(iOS)[网络,HTTPS] 搞了半天,记录一下,坑很多。双向认证,就是在访问网...

  • 双向认证

    1、设置容器 docker run -it --name nginx-test2 -v /home/nginx:/...

  • window下tomcat设置双向SSL认证

    双向认证:在单向认证(客户端认证服务器端身份)的基础上,增加了服务器端对客户端的认证 1、为服务器端生成密钥库 /...

  • Qt嵌入浏览器(三)——QWebEngine与Https

    本篇简介: 本篇的小目标: 挑战通过Qt WebEngine实现与服务端的Https双向认证 双向认证,Qt We...

  • 网络

    认证 ssl/tls 1.客户端证书认证 (TLS双向认证) CA #证书认证2.bearerToken3.Se...

  • [运维] nginx 配置

    https 双向认证 部分 location 单向认证 ssl_verify_client optional; i...

  • iOS中的安全与加密

    iOS中的安全与加密 一。HTTPS双向认证 Charles是大家所熟悉的抓包工具,如果网络请求未经过双向认证,那...

网友评论

  • 423138054120:博主你好,最近碰到一个问题,也是qt证书的,可是我的认证只需要本地证书,没有密钥的,就和浏览器访问某些特殊网站需要手动选择证书的那种一样,证书是已经安装注册进电脑,只是使用时调用一下,可是我现在尝试了各种办法,都加载不了证书,偶然的一次fiddler抓包,fiddler提示把证书放到fiddler的一个目录下,结果fiddler居然可以代理请求了。然后msvc版的network模块正好可以被fiddler抓包和代理,然后现在采用的迂回方式,qt程序里发送请求但是必须开着fiddler,关了就发不了。没有办法直接程序里成功发送,试过QList<QSslCertificate>这些类似的写法。
    ArcDriver:你好,从你的描述来看应该是想实现对端接收端对发送端的认证,可以试试从对端抓包看看有没有qt提供的认证信息。
    一般来说发送端如果要提供本地认证信息,证书和密钥都是成对生成的,如果想更方便一些的话,可以试试使用p12格式的密钥库(需要qt5.4以上版本)
    423138054120:有没有办法只加载本地证书的,.cer.pem.crt文件这些。

本文标题:QSslSocket双向认证设置

本文链接:https://www.haomeiwen.com/subject/crpmtftx.html