2023年开始了,第一篇,记录最近帮朋友制作QSslSocket所需证书的过程。
使用传统的TCP连接依旧是很多工业软件的常见通信方法。但如果恰好不希望别人通过抓包等方法研究上位机和控制器模块之间的协议格式,那使用SSL连接是一种掩耳盗铃的好办法,能够抵御不是很执着的逆向行为。
SSL一般可以通过openssl实现,这样即使是嵌入式设备里也有类似的支持。在建立SSL通道时,最常见的认证方法是客户端认证服务器证书的有效性。此时,服务端需要具备自己的私钥、由根证书签名的公钥,客户端只需要安装根证书,即可验证服务器的签名。当然,你可以通过忽略各种ssl错误,在没有验证签名的情况下依然建立连接,很多嵌入式设备里也是这样干的——只要证书是一个证书,就可以连接。
正是在下面这种非专业的作坊操作下,一堆貌似可靠的工业控制SSL协议就诞生了。下文仅仅用于SSL编程实验使用,若用于流水线环境,带来的损失和本文无关。
1.使用MSYS64直接获取openssl
在msys64中,可以直接安装openssl,而且版本很新。我们选择mingw64环境,安装64位的openSSL
$ pacman -S mingw64/mingw-w64-x86_64-openssl
resolving dependencies...
looking for conflicting packages...
Packages (1) mingw-w64-x86_64-openssl-1.1.1.s-1
Total Download Size: 4.80 MiB
Total Installed Size: 69.51 MiB
Net Upgrade Size: 0.00 MiB
:: Proceed with installation? [Y/n] y
:: Retrieving packages...
mingw-w64-x86_64-openssl-1... 4.8 MiB 2.29 MiB/s 00:02 [###############################] 100%
(1/1) checking keys in keyring [###############################] 100%
(1/1) checking package integrity [###############################] 100%
(1/1) loading package files [###############################] 100%
(1/1) checking for file conflicts [###############################] 100%
(1/1) checking available disk space [###############################] 100%
:: Processing package changes...
(1/1) installing mingw-w64-x86_64-openssl [###########################################] 100%
2. 制作证书前的准备
openssl的配置默认在C:\msys64\mingw64\ssl\openssl.cnf里查看。如果是默认安装,则例子配置里默认的证书仓库位于当前文件夹相对路径的demoCA里,如下:
####################################################################
[ ca ]
default_ca = CA_default # The default ca section
####################################################################
[ CA_default ]
dir = ./demoCA # Where everything is kept
因此,我们要在准备制作证书的文件夹下,创建demoCA文件夹,并touch两个文件出来。
mkdir demoCA
touch demoCA/index.txt
echo 0100 > demoCA/serial
上面三个操作,相当于建立了一个demoCA文件夹,并生成了一个0字节的空白txt,以及一个文件serial,里面有四个字符 0100(填什么无所谓,只要是一个数字即可)
3. 生成证书
3.1 生成根证书
(1) 生成私钥
$ openssl genrsa -des3 -out ca_privkey.pem 4096
Generating RSA private key, 4096 bit long modulus (2 primes)
.................................................
e is 65537 (0x010001)
Enter pass phrase for ca_privkey.pem:【敲你的口令】
Verifying - Enter pass phrase for ca_privkey.pem:【敲你的口令】
(2)导出公钥
注意,下面的询问中,Common Name (e.g. server FQDN or YOUR name) []:一般要和url里的域名一样,或者局域网里的服务器地址一样。例子里为了方便,所有的询问都用 192.168.1.100回答了。
$ openssl req -new -x509 -key ca_privkey.pem -out ca_cert.pem -days 16384
Enter pass phrase for ca_privkey.pem:【敲你的口令】
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:192.168.1.100
Locality Name (eg, city) []:192.168.1.100
Organization Name (eg, company) [Internet Widgits Pty Ltd]:192.168.1.100
Organizational Unit Name (eg, section) []:192.168.1.100
Common Name (e.g. server FQDN or YOUR name) []:192.168.1.100
Email Address []:192.168.1.100
3.2 生成服务器证书
(1) 生成私钥
$ openssl genrsa -out svr_privkey.pem 4096
Generating RSA private key, 4096 bit long modulus (2 primes)
...........................................+
e is 65537 (0x010001)
(2)导出签名请求
要导出一个签名请求,以便后续用根证书为服务器公钥签名。注意,下面的询问中,Common Name (e.g. server FQDN or YOUR name) []:一般要和url里的域名一样,或者局域网里的服务器地址一样。例子里为了方便,所有的询问都用 192.168.1.100回答了。
$ openssl req -new -key svr_privkey.pem -out svr_cert.csr
Using configuration from C:/msys64/mingw64/ssl/openssl.cnf
Enter pass phrase for ca_privkey.pem:【敲你的口令】
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:192.168.1.100
Locality Name (eg, city) []:192.168.1.100
Organization Name (eg, company) [Internet Widgits Pty Ltd]:192.168.1.100
Organizational Unit Name (eg, section) []:192.168.1.100
Common Name (e.g. server FQDN or YOUR name) []:192.168.1.100
Email Address []:192.168.1.100
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:192.168.1.100
An optional company name []:192.168.1.100
(3)签名生成服务器公钥
openssl ca -keyfile ca_privkey.pem -outdir . -in svr_cert.csr -out svr_cert.pem -cert ca_cert.pem -days 7200
Using configuration from C:/msys64/mingw64/ssl/openssl.cnf
Enter pass phrase for ca_privkey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 256 (0x100)
Validity
Not Before: Jan 1 01:43:19 2023 GMT
Not After : Sep 18 01:43:19 2042 GMT
Subject:
countryName = AU
stateOrProvinceName = 192.168.1.100
organizationName = 192.168.1.100
organizationalUnitName = 192.168.1.100
commonName = 192.168.1.100
emailAddress = 192.168.1.100
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
65:6D:2A:0B:F6:DE:79:2E:07:38:83:F8:4C:09:83:8F:B1:49:AA:C7
X509v3 Authority Key Identifier:
keyid:B4:89:B7:A0:02:56:26:9A:A1:9F:1B:9F:F4:A6:31:33:3B:F7:8E:BA
Certificate is to be certified until Sep 18 01:43:19 2042 GMT (7200 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
4. 发布证书
把 ca_cert.pem 拷贝到客户端,并设置客户端连接时加入此根证书。
把 svr_cert.pem,svr_privkey.pem 拷贝到服务器,并设置握手时使用此证书。
具体的使用方法,参考 Qt QSslSocket的例子,或者我下一篇博文。