数字证书是现代互联网中个体间相互信任的基石。
如果没有了数字证书,那么也就没有了各式各样的电商平台以及方便的电子支付服务。
数字证书是网络安全中的一个非常重要组成部分。如果要学好网络安全,那么必须充分理解它的原理。
目前我们所提到的数字证书都是基于 ITU 制定的 X.509 标准。
本文纯属个人学习经验分享交流,内容多且较为杂乱,所以出错再所难免,仅供参考!
如果发现错误的地方,可以的话麻烦指点下,特别感谢!
有两个密钥,一个是 Key_1,另一个是 Key_2。
一段明文通过某种加密算法用 Key_1 加密之后的密文只能用 Key_2 解密,而不能还是用 Key_1 解密。
反过来,明文用 Key_2 加密之后的密文只能用 Key_1 解密,而不能还是用 Key_2 解密。
满足这种特征的加密算法称为非对称加密算法。
目前常用的非对称加密算法有 RSA、DSA 等。
将各种不定长的「数据」经过某种算法处理之后,总是能生成一段定长的数据。这段定长的数据称之为「散列值」。
这种算法如果可以满足以下特征,则可以称为摘要算法。
目前常用的摘要算法有 MD5、SHA-1、SHA-256 等。
数字签名其实就是把「散列值」经过非对称加密算法加密得到的一个「加密的散列值」。
数字签名的工作流程如下图:
数字签名一般用于身份认证和防止抵赖。
简单来说,数字证书就是一张附带了数字签名的信息表。
下图或许可以帮助对本文的理解。
假设客户端「C」想和互联网另一端的服务器「S」进行无保密通信,且客户端「C」没有部署任何服务器身份验证机制。
假冒的服务器「fake_S」冒充「S」,直接与「C」进行通信。
如果「C」打算将密码之类的敏感信息传递到「S」,那么敏感信息就会被「fake_S」截获。
这时候「fake_S」一般会向「C」报告一个错误,然后撤退。随后「C」就会与真实的服务器「S」进行通信。
这样一来,「fake_S」就获取到了敏感信息。而「C」也会有所察觉,但是一般人都会认为是网络不稳定而没有放在心上。
目前常见的欺骗方式有 DNS 欺骗等。
假冒的服务器「fake_S」可以在「C」与「S」之间架起一道桥梁,把「C」到「fake_S」的数据包转发给「S」,把「S」到「fake_S」的数据包转发给「C」。
然后,「fake_S」就可以监听「C」与「S」之间的所有通信,也可以修改数据包的内容并主动发动攻击。
这种攻击方法称为中间人攻击。而中间人攻击也十分隐蔽,一般来说「C」是无法察觉到有任何异常情况发生的。
目前常见的欺骗方式有 ARP 欺骗、DNS 欺骗等。
以 RSA 证书为例进行说明,其他算法的证书可能会有所不同。
简要流程
根证书「ca_Cert」包含的内容:ca_KeyPub + ca_Info + enc_ca_Hash。
「ca_Cert」可用于签署下一级的证书。
简要流程
服务器证书「s_Cert」包含的内容:s_KeyPub + s_Info + ca_Info + enc_s_Hash。
「s_Cert」不可用于签署下一级的证书。
在现实中,仅仅靠一个认证机构是满足不了海量证书签署需求的,因此需要构建分支认证机构。
简要流程
二级认证机构证书「ca2_Cert」包含的内容:ca2_KeyPub + ca2_Info + ca_Info + enc_ca2_Hash。
「ca2_Cert」可用于签署下一级的证书。
三级或更多级认证机构的构建流程跟这个流程差不多,这里就不再赘述了。
简要流程
服务器证书「s2_Cert」包含的内容:s2_KeyPub + s2_Info + ca2_Info + enc_s2_Hash。
「s2_Cert」不可用于签署下一级的证书。
三级或更多级认证机构证书签署流程跟这个流程差不多,也不再赘述了。
从上面可以看出,证书签署的流程是:「ca_Cert」-> 「ca2_Cert」->「s2_Cert」。它是一条完整的链条,我们把它称之为「证书链」。
现实中的证书大多数是由二级认证机构签署的。
并且,以某种方式(如 DNS)对服务器的身份进行验证之后,一般无需让服务器提供任何信息(CSR 文件)。
认证机构会提供证书、证书链以及私钥,服务器直接使用就好了。
如果服务器「S」使用的证书是由根认证机构「CA」直接签署的,那么只需要向客户端提供「s_Cert」,然后自己使用私钥 s_KeyPri 即可实现非对称加密。
如果服务器「S2」使用的证书不是由根认证机构「CA」直接签署的,则不仅需要向客户端提供「s2_Cert」,而且还要提供除根认证机构「CA」之外所有认证机构的证书(这里还要提供「ca2_Cert」),否则客户端可能会提示证书链不完整而无法通过验证。服务器自己使用私钥 s2_KeyPri 即可实现非对称加密。
简要流程
(假设根认证机构「CA」的根证书「ca_Cert」已经安装到操作系统中且被信任。下同。)
如果「ca_Cert」没有安装到系统中,那么将无法对 enc_s_Hash 进行解密,也就无法验证「s_Cert」的真实性了。下同。
简要流程
三级或更多级认证机构证书验证流程跟这个流程差不多,就是一环扣一环地验证下去。
服务器「S」的身份得到客户端「C」的认可之后,服务器「S」可以使用 s_KeyPri 对传出的数据进行加密或者对传入的数据进行解密。
反过来,客户端「C」可以使用 s_KeyPub 对传出的数据进行加密或者对传入的数据进行解密。
由于非对称加密的效率较低,所以一般使用非对称加密协商并交换一个临时的会话密钥之后,使用会话密钥进行对称加密。
现实中,一些众所周知且被信任证书认证机构的根证书都被内置到了操作系统中。
而客户端在检查服务器证书的时候,一般还会检查它的有效期以及该证书是否在认证机构的证书吊销列表中。证书吊销列表一般是在线检查的。
以下操作可在安装了 openssl 软件包的 Linux、macOS 系统上进行。
我们将自己建立一个根认证机构,然后直接用它来签署证书(即单级认证机构)。
整个证书系统默认使用 RSA4096 和 SHA512 算法。
根认证机构的有效期为 10 年,签署出来的证书有效期为 1 年。
5.1 创建工作目录并进入
执行以下命令:
mkdir ~/test_pki && cd ~/test_pki
5.2 创建证书序列号文件
执行以下命令:
echo 01 > serial
5.3 创建证书数据库文件
执行以下命令:
touch index.txt
5.4 创建 openssl 配置文件
执行以下命令:
cat << EOF >> test_pki.cnf
把以下内容直接粘贴到命令行窗口中按回车即可。
[ ca ]
default_ca = CA
[ CA ]
dir = .
database = \$dir/index.txt
new_certs_dir = \$dir
certificate = \$dir/ca_cert.pem
serial = \$dir/serial
private_key = \$dir/ca_key.pem
RANDFILE = \$dir/.rand
default_bits = 4096
default_days = 365
default_crl_days = 30
default_md = sha512
unique_subject = no
policy = policy_anything
[ policy_anything ]
countryName = supplied
stateOrProvinceName = supplied
localityName = supplied
organizationName = supplied
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
EOF
执行以下命令:
openssl req -x509 -nodes -days 3650 -newkey rsa:4096 -keyout ca_key.pem -out ca_cert.pem -new -sha512
执行结果:
(请根据提示填写相关信息)
Generating a 4096 bit RSA private key
......................................................................................................................................................................................................................++
...................................................................................................................................................................................++
writing new private key to 'ca_key.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) []: #国家码
State or Province Name (full name) []: #洲、省名
Locality Name (eg, city) []: #城市名
Organization Name (eg, company) []: #组织名
Organizational Unit Name (eg, section) []: #部门名
Common Name (eg, fully qualified host name) []: #常用名
Email Address []: #邮箱地址
执行完之后将生成根认证机构证书 ca_cert.pem 以及它的私钥 ca_key.pem。
执行以下命令:
openssl req -nodes -new -newkey rsa:4096 -keyout cert1_key.pem -out cert1_csr.pem
同样的,根据上述提示填写相关信息即可。如果出现 A challenge password []: 的话留空直接按回车就好了。
执行完之后将生成用户的证书请求文件 cert1_csr.pem 以及它的私钥 cert1_key.pem。
执行以下命令:
openssl ca -in cert1_csr.pem -out cert1_cert.pem -config test_pki.cnf
运行结果:
Using configuration from test_pki.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName :PRINTABLE:'CN'
stateOrProvinceName :ASN.1 12:'Guangdong'
localityName :ASN.1 12:'Shantou'
organizationName :ASN.1 12:'yzn_cert'
organizationalUnitName:ASN.1 12:'yzn_cert'
commonName :ASN.1 12:'yzn_cert'
emailAddress :IA5STRING:'yzn_cert'
Certificate is to be certified until Mar 19 05:12:41 2019 GMT (365 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
执行完之后将生成用户的证书文件 cert1_cert.pem。
用户使用 cert1_cert.pem 和 cert1_key.pem 即可实现身份验证以及非对称加密。
我把根证书 ca_cert.pem 导入到 macOS 的钥匙串中并设置为信任,再导入 cert1_cert.pem,查看证书的详情时可以看到以下结果:
很明显看出 yzn_cert 确实是由 yzn 这个认证机构签署的,而认证机构 yzn 已经被系统信任。信任链就是这样建立起来的。