一、非对称加密
1.1 非对称加密
指加密和解密使用不同密钥的加密算法,也称为公私钥加密。
1.2 非对称加密中的证书签名与验证
以上图的虚线为准,左边为签名的实现,右边为签名的验证。
- 对 Data 部分进行 Hash,结果一般称为 Digest
- 通过 CA 的私钥,也就是 ca.key ,对 Digest 进行加密
- 将加密后的结果和签名内容放在一起,变成了一个完整的证书
签名的验证
- 客户端使用相同的哈希算法,这里使用的是 SHA-256,对证书内容进行 哈希
- 客户端使用公钥对签名部分进行解密,结果就是上图中
红色值为 2
的部分 - 根据非对称加密算法的特性,
红色值 2
应该等于红色值1
- 又根据哈希算法的特性,对同样的值进行哈希,结果相同,则有
红色值1
与Hash Value H1
红色值2
==红色值1
==Hash Value H1
=>红色值2
==Hash Value H1
证书验证通过
二、创建 CA 证书
2.1 mkcert 生成证书
mkcert --install
2.2 openssl 生成 CA 证书
# 生成一个 CA 密钥
openssl genpkey -algorithm RSA -out ca.key -aes256
# 生成 ca 证书
openssl req -new -x509 -key ca.key -out ca.crt
# 生成带有过期时间的 ca 证书
openssl req -new -x509 -key ca.key -out ca.crt -days 3650
# 证书验证
openssl x509 -noout -text -in ca.crt
2.3 cfssl 生成 CA 证书
{
"CN": "My CA",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "San Francisco",
"O": "My Company",
"OU": "IT Department",
"ST": "California"
}
],
"ca": {
"expiry": "87600h"
}
}
保存为 ca-csr.json,然后使用下面命令生成 ca 证书
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
2.4 CA 证书中的信息
Certificate:
Data:
# X.509 证书版本
Version: 3 (0x2)
# 证书的序列号,由颁发机构分配
Serial Number:
b7:58:ea:fc:21:0b:0b:1f:8d:af:7d:b1:ee:ed:f5:1c
# 证书签名算法
Signature Algorithm: sha256WithRSAEncryption
# 颁发机构的信息
Issuer: O = mkcert development CA, OU = root@pve, CN = mkcert root@pve
# 证书的有效期限,包括起始时间和结束时间
Validity
Not Before: Jul 8 12:32:11 2023 GMT
Not After : Jul 8 12:32:11 2033 GMT
# 证书所代表的实体的信息
Subject: O = mkcert development CA, OU = root@pve, CN = mkcert root@pve
# 证书所包含的公钥信息,包括公钥算法、公钥和模数
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (3072 bit)
Modulus:
00:b9:62:e0:85:05:4b:ab:b8:23:02:86:4f:de:0e:
...
Exponent: 65537 (0x10001)
# X.509 证书的扩展信息,包括证书用途、基本限制和实体密钥标识符等
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
# 在后面生成的 服务端证书中会包含这个值,可以用来判断是否是由该 CA 签发的证书
X509v3 Subject Key Identifier:
61:41:20:D4:1A:22:F9:8B:A3:FE:6E:FE:C2:B8:8A:8D:26:C5:61:F3
# 证书的数字签名,由颁发机构使用其私钥签名生成,用于验证证书的完整性和真实性
Signature Algorithm: sha256WithRSAEncryption
8c:8b:81:61:b2:5a:7e:05:55:f3:e7:1a:28:df:85:3b:58:6f:
...
三、生成服务端证书
3.1 mkcert 生成服务端证书
mkcert abc.com 192.168.0.100
# ls
abc.com+1-key.pem abc.com+1.pem
3.2 openssl 生成服务端证书
# 生成服务端私钥
openssl genpkey -algorithm RSA -out server.key -aes256
# 生成 CSR
openssl req -newkey rsa:2048 -nodes -keyout server.key \
-out server.csr \
-subj "/C=US/ST=California/L=San Francisco/O=My Company/OU=IT Department/CN=example.com" \
-addext "subjectAltName = DNS:abc.com,DNS:www.abc.com,IP:192.168.0.1"
# 通过 CSR 生成服务端证书
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-out server.crt -days 3650 \
-extfile <(printf "subjectAltName=DNS:abc.com,DNS:www.abc.com,IP:192.168.0.100")
3.3 cfssl 生成服务端证书
{
"CN": "abc.com",
"hosts": [
"abc.com",
"www.abc.com",
"192.168.0.100"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "San Francisco",
"O": "My Company",
"OU": "IT Department",
"ST": "California"
}
]
}
保存为 config.json,然后使用下面命令生成
cfssl gencert -ca ca.pem -ca-key ca-key.pem -config config.json \
-profile server server-csr.json | cfssljson -bare server
3.4 证书示例与说明
Certificate:
Data:
# 证书版本号
Version: 3 (0x2)
# 证书序列号,用于唯一标识证书
Serial Number:
9e:a1:c9:65:a9:a1:6a:43:93:dc:2b:24:96:15:d7:ab
# 签名算法
Signature Algorithm: sha256WithRSAEncryption
# 证书颁发者信息,包括组织名(O)、组织单位(OU)和通用名称(CN)
# 其实就是 CA 的信息
Issuer: O = mkcert development CA, OU = root@pve, CN = mkcert root@pve
# 证书有效期,包括证书生效时间(Not Before)和证书失效时间(Not After)
Validity
Not Before: Jul 10 14:40:52 2023 GMT
Not After : Jul 10 14:40:52 2033 GMT
# 证书主体信息,包括组织名(O)和组织单位(OU)
Subject: O = mkcert development certificate, OU = root@pve
# 证书公钥信息,包括公钥算法(Public Key Algorithm)、公钥(RSA Public-Key)和指数(Exponent)
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:c9:05:0e:d7:59:02:5b:30:55:8f:df:e3:54:90:
...
Exponent: 65537 (0x10001)
# 证书扩展信息
X509v3 extensions:
# 证书密钥用途,这里是数字签名和密钥加密
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
# 证书扩展密钥用途,这里是TLS Web Server Authentication
X509v3 Extended Key Usage:
TLS Web Server Authentication
# 基本限制扩展,这里标记为非CA证书
X509v3 Basic Constraints: critical
CA:FALSE
# 颁发者密钥标识符,用于标识颁发者的公钥
# 这里对应上面 CA 中的 X509v3 Subject Key Identifier
X509v3 Authority Key Identifier:
keyid:61:41:20:D4:1A:22:F9:8B:A3:FE:6E:FE:C2:B8:8A:8D:26:C5:61:F3
# 主体备用名称,这里就是 SANs 的值
X509v3 Subject Alternative Name:
DNS:abc.com, IP Address:192.168.0.100
# 证书签名值,由颁发者使用私钥对证书信息进行签名得到
Signature Algorithm: sha256WithRSAEncryption
5c:ea:7b:5c:6b:aa:ef:03:2b:a2:9f:3a:3d:45:06:75:bc:56:
...
四、安装 CA 根证书
在 SSL 通信过程中,客户端会对服务端发送过来的证书进行验证,这个验证就需要 ca.crt
openssl verify -CAfile ca.crt server.crt
在非对称算法中,私钥用于加密,公钥用于解密
。我们使用公钥(ca.crt) 对 server.crt 进行解密,如果能解密成功,说明这个证书是通过 CA 签发的,然后再对比证书 hash 来进行验证。
4.1 Windows 安装证书
将 ca.crt 拷贝到 windows 上,然后双击进行安装。在证书存储
时选择受信任的根证书颁发机构
,安装完成后 windows 自带浏览器和一些内置的程序,就可以使用该 CA 签发的证书进行网络通信了。
如果要使用 Chrome 或 Firefox 之类的浏览器,还是需要单独对浏览器配置 受信任的根证书颁发机构
4.2 Linux 安装证书
func init() {
switch {
case binaryExists("apt"):
CertutilInstallHelp = "apt install libnss3-tools"
case binaryExists("yum"):
CertutilInstallHelp = "yum install nss-tools"
case binaryExists("zypper"):
CertutilInstallHelp = "zypper install mozilla-nss-tools"
}
if pathExists("/etc/pki/ca-trust/source/anchors/") {
SystemTrustFilename = "/etc/pki/ca-trust/source/anchors/%s.pem"
SystemTrustCommand = []string{"update-ca-trust", "extract"}
} else if pathExists("/usr/local/share/ca-certificates/") {
SystemTrustFilename = "/usr/local/share/ca-certificates/%s.crt"
SystemTrustCommand = []string{"update-ca-certificates"}
} else if pathExists("/etc/ca-certificates/trust-source/anchors/") {
SystemTrustFilename = "/etc/ca-certificates/trust-source/anchors/%s.crt"
SystemTrustCommand = []string{"trust", "extract-compat"}
} else if pathExists("/usr/share/pki/trust/anchors") {
SystemTrustFilename = "/usr/share/pki/trust/anchors/%s.pem"
SystemTrustCommand = []string{"update-ca-certificates"}
}
}
我们可以参考 mkcert 的代码,来将 ca.crt 放到对应的位置并安装到系统。