参考https://blog.csdn.net/qq_38502914/article/details/124630727
下载地址: Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions
安装到第二个选项时,选择安装到指定的/bin目录下。

下载好后将两个dll拷贝到:

然后在qt pro里导入:
LIBS += -LD:\OpenSSL-Win64\lib -llibcrypto -llibssl
INCLUDEPATH += D:\OpenSSL-Win64\include
如果在公司项目中,则需要自己将dll和libs还有include拷贝到工程里,指定生成exe路径
常见的SSL证书文件后缀扩展名说明:
①*.DER或*.CER文件: 带有这类后缀扩展名的SSL证书文件是二进制格式,只含有SSL证书信息,不包含私钥。
②*.CRT文件: 这样的证书文件可以是二进制格式,也可以是文本格式,一般均为文本格式,功能与 *.DER及*.CER证书文件相同。
③*.PEM文件: 这样的证书文件一般是文本格式,可以存放证书或私钥,或者两者都包含。 *.PEM 文件如果只包含私钥,一般用*.KEY文件代替。
④*.PFX或*.P12文件: 这样的证书文件是二进制格式,同时包含证书和私钥,且一般有密码保护。
之所以使用证书,是确保服务器地址有效性,主要是通过CA证书与服务器证书进行对比,也可以实现数据传输的加密处理,避免被劫持和篡改
*.csr文件:证书签名请求文件
*.key文件:私钥文件
*.crt文件:证书文件
生成私钥和证书
- // CN非常很重要,必须和请求url的地址保持一致
- openssl req -newkey rsa:2048 -nodes -keyout server.key -x509 -days 3650 -out server.crt -subj "/C=CN/ST=Shanghai/L=Shanghai/O=xxx/OU=xxx/CN=10.0.1.160/emailAddress=xxx@xxxx.com"
-
- req: 配置参数-x509指定使用 X.509证书签名请求管理(certificate signing request (CSR))."X.509" 是一个公钥代表that SSL and TLS adheres to for its key and certificate management.
- -nodes: 告诉OpenSSL生产证书时忽略密码环节.(因为我们需要Nginx自动读取这个文件,而不是以用户交互的形式)。
- -days 36500: 证书有效期,100年
- -newkey rsa: 2048: 同时产生一个新证书和一个新的SSL key(加密强度为RSA 2048)
- -keyout: SSL输出文件名
- -out: 证书生成文件名
-
- C : 地区,如中国为 CN,美国为 US
- CT: 省份
- L: 所在地的市/县/区
- O: 填单位/机构/企业合法的名称,比如baidu
- OU: 填部门名称
- CN: 填域名,由于我们是ip访问,所以填ip,否则填域名,我们在验证服务器证书时,会验证Common Name与http请求的url域名是否匹配,如果不匹配,ssl会返回错误。
- emailAddress: 邮件地址
-
生成了server.crt server.key
nginx开启ssl模块
由于我这里开启的,所以跳过
生成客户端证书
执行命令:
- openssl genrsa -out client.key 2048
-
- openssl req -new -key client.key -out client.csr
- Country Name (2 letter code) [AU]:CN // 如中国为 CN,美国为 US
- State or Province Name (full name) [Some-State]:Shanghai
- Locality Name (eg, city) []:Shanghai // 填您所在地的市/县/区
- Organization Name (eg, company) [Internet Widgits Pty Ltd]:puniu // 填单位/机构/企业合法的名称
- Organizational Unit Name (eg, section) []:xxxClient // 填部门名称
- Common Name (e.g. server FQDN or YOUR name) []:xxxClient // 填域名,客户端随便填
- Email Address []: email@puniu.com // 邮件地址,可以不必输入,按回车跳过
-
- A challenge password []: # 私钥保护密码,可直接回车
- An optional company name []: # 一个可选公司名称,可直接回车
-
-
- openssl x509 -req -days 3650 -in client.csr -signkey client.key -out client.crt
然后得到: client.key client.csr client.crt
配置nginx
服务器只需要服务器证书和私钥以及客户端证书即可
打开配置文件 nano /etc/nginx/nginx.conf:
修改如下所示:
- server {
- listen 8081;
- listen 443 ssl; # 监听443端口, 开启ssl(必须)
- listen [::]:8081;
- server_name 10.0.1.160; # 必须和服务器证书CN值保持一致,否则会返回ssl错误
- root /usr/share/nginx/html;
-
- ssl on;
- # 引用ssl证书(必须,如果放在nginx/conf/ssl下可以用相对路径,其他位置必须用绝对路径)
- ssl_certificate /etc/pki/CA/lisense/server.crt;
- ssl_certificate_key /etc/pki/CA/lisense/server.key;
- ssl_client_certificate /etc/pki/CA/lisense/client.crt;
- ssl_verify_client on; # 开启客户端传输
-
- # 协议优化(可选,优化https协议,增强安全性)
- ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
- ssl_ciphers HIGH:!aNULL:!MD5;
- ssl_prefer_server_ciphers on;
- ssl_session_cache shared:SSL:10m;
- ssl_session_timeout 10m;
-
-
- //...其它配置
- }
更新服务器配置
nginx -t // 查看配置,返回ok,则可以更新配置
nginx -s reload // 更新配置
注:记得开启防火墙的443端口 firewall-cmd --zone=public --add_port=443/tcp permanent
- qDebug() << "支持OpenSSL: " << QSslSocket::supportsSsl();
-
- // 客户端证书
- QFile crtFile("D:/OpenSSL-Win64/bin/client.crt");
- crtFile.open(QIODevice::ReadOnly);
- const QSslCertificate certificate(&crtFile, QSsl::Pem);
- crtFile.close();
-
- // 客户端私钥
- QFile keyFile("D:/OpenSSL-Win64/bin/client.key");
- keyFile.open(QIODevice::ReadOnly);
- const QSslKey prvateKey(&keyFile, QSsl::Rsa);
- keyFile.close();
-
- // 通过QSslConfiguration 类进行SSL连接配置
- QSslConfiguration config ;
- //设置SSL验证模式 客户端与服务器进行双向校验
- config.setPeerVerifyMode(QSslSocket::VerifyPeer);
- //使用TLS 1.2 协议版本 和服务器保持一致
- config.setProtocol(QSsl::TlsV1_2);
- config.setPrivateKey(prvateKey);
- config.setLocalCertificate(certificate);
-
- //由于是自签名的服务器端证书,我们还得将服务器端的证书叫入到CA证书数据库中,否则服务器端证书将验证失败。
- QList<QSslCertificate> caCerList;
- QFile fileServCrt("D:/OpenSSL-Win64/bin/server.crt");
- fileServCrt.open(QIODevice::ReadOnly);
- const QSslCertificate cACertificate(&fileServCrt, QSsl::Pem);
-
- //将服务证书加入到CA列表中
- caCerList << cACertificate;
- config.setCaCertificates(caCerList);
-
- //网络连接管路
- QNetworkAccessManager *manager = new QNetworkAccessManager(this);
-
- QUrl url(QUrl("https://10.0.1.160:443/static/SSD/20220621/123.txt"));
- QNetworkRequest request(url);
-
- //加入ssl配置信息
- request.setSslConfiguration(config);
- //设置rest api 数据内容为json格式
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
-
- connect(manager, &QNetworkAccessManager::finished, this, [](QNetworkReply* reply){
-
- QByteArray byteArray = reply->readAll();
-
- qDebug()<<"finished:"<<reply->error()<<byteArray.length()<<byteArray;
-
- QSslCertificate cert = reply->sslConfiguration().peerCertificate();
-
- qDebug()<<"打印服务器证书:";
-
- qDebug()<<cert.isNull();
- qDebug()<<cert.issuerDisplayName();
- qDebug()<<cert.subjectDisplayName();
- qDebug()<<cert.version();
- qDebug()<<"serialNumber"<<cert.serialNumber();
- qDebug()<<cert.issuerInfo(QSslCertificate::Organization);
- qDebug()<<"CommonName: "<<cert.issuerInfo(QSslCertificate::CommonName);
- qDebug()<<cert.issuerInfo(QSslCertificate::LocalityName);
- qDebug()<<cert.issuerInfo(QSslCertificate::OrganizationalUnitName);
- qDebug()<<cert.issuerInfo(QSslCertificate::CountryName);
- qDebug()<<cert.issuerInfo(QSslCertificate::StateOrProvinceName);
- qDebug()<<cert.issuerInfo(QSslCertificate::DistinguishedNameQualifier);
- qDebug()<<cert.issuerInfo(QSslCertificate::SerialNumber);
- qDebug()<<cert.issuerInfo(QSslCertificate::EmailAddress);
-
- qDebug()<<cert.subjectInfo(QSslCertificate::Organization);
- qDebug()<<"CommonName: "<<cert.subjectInfo(QSslCertificate::CommonName);
- qDebug()<<cert.subjectInfo(QSslCertificate::LocalityName);
- qDebug()<<cert.subjectInfo(QSslCertificate::OrganizationalUnitName);
- qDebug()<<cert.subjectInfo(QSslCertificate::CountryName);
- qDebug()<<cert.subjectInfo(QSslCertificate::StateOrProvinceName);
- qDebug()<<cert.subjectInfo(QSslCertificate::DistinguishedNameQualifier);
- qDebug()<<cert.subjectInfo(QSslCertificate::SerialNumber);
- qDebug()<<cert.subjectInfo(QSslCertificate::EmailAddress);
-
- qDebug()<<cert.effectiveDate();
- qDebug()<<cert.expiryDate();
-
- });
-
- connect(manager, &QNetworkAccessManager::sslErrors, this, [](QNetworkReply*reply,const QList<QSslError>& errors){
-
- qDebug()<<"sslErrors:"<<errors;
-
- });
-
-
- manager->get(request);
总结
如果CA证书和服务器证书不匹配,则报错:
sslErrors: ("The certificate is self-signed, and untrusted")
如果客户端证书与服务器绑定的客户端证书不匹配,则报错:
QNetworkReply::UnknownNetworkError