局域网可信SSL证书(Openssl X509 方式)
创建局域网/单机可信SSL证书(openssl X509
)
有一套完善的机制来保证证书的有效性,可靠性,这就是我们的公钥基础设施(Public Key Infrastructure, PKI)。
其中最为关键的是证书颁发机构(Certification Authority, CA),负责颁发证书、认证证书、管理已颁发证书。
CA 自己创建一个证书(公钥 + 私钥),信任这个 CA 的人使用它的证书来签名和验证自己的证书,一级一级的传递下来。
如果需要一个大家都信任的证书,就需要向一个大家都信任的 CA 申请,提交身份信息 + 密钥。
CA 确认之后,使用私钥为之签名,然后这个身份信息 + 颁发者信息(序列号) + 公钥 + 算法 + 签名 + 有效期等,合在一起就是一个证书了。
如果其他人需要确认这个证书的真假,就拿 CA 的公钥(公开的)来校验一下,通过之后就认为其有效。
PKI 的这一整套机制,全部遵循国际电信联盟制定与颁发的 X.509 标准。
几乎 IT 届所有通讯技术中使用的加密都离不开这一套(还有一套机制,就是 PGP 体系的分布式信任模型 Web of Trust)。
PEM
编码格式,就是常见的-----BEGIN XXX-----
+ base64 +-----END XXX-----
DER
编码格式,二进制PFX
参考下面说的 PKCS#12, 公钥 / 私钥 / 证书,好像是用于安全转移
通常用它来打包一个私钥及有关的 X.509 证书,或者打包信任链的全部项目。
其文件常用 .p12 后缀或 .pfx 后缀JKS
Java Key Store, 私钥 + 证书,常用Java Keytool
做合成或提取CER
/CRT
常见后缀,表示证书PKCS
The Public-Key Cryptography Standards,RSA 公司设计的公钥加密标准,目前共有 15 部分,其中:PKCS#1
RSA Cryptography Standard v2.2, RFC8017PKCS#3
Diffie–Hellman Key Agreement Standard v1.4PKCS#5
Password-based Encryption Standard v2.1, RFC8018, PBKDF2PKCS#8
Private-Key Information Syntax Standard v1.2, RFC5958PKCS#10
Certification Request Standard v1.7, RFC2986PKCS#12
Personal Information Exchange Syntax Standard v1.1 RFC7292
似乎是根据微软的 PFX 格式发展过来的,现在可以把 PFX 看做 PKCS#12 的同义词
一般的习惯:
- 公钥和私钥,用 .key 后缀
- 证书一般采用 .cer 或 .crt 做后缀
- 不管是公钥、私钥,还是证书,都有按照保存格式,使用 .pem 或 .der 后缀的
- 还有合并存储的可能,最简单的就是
cat ca.key ca.crt > ca.pem
至少 Python 的 SSL 库加载证书时,支持私钥和证书合并存储在同一个文件
什么是自签名
模拟 PKI 机制,先创建一个证书,将其作为根证书。然后使用这个根证书给其他新创建的证书做签名,形成一个证书链。
这种自己给自己背书的行为,就叫自签名,得到的签名证书就叫自签名证书。
一般,我们在 Socket 编程中,使用 TLS 的场景,似乎都不对证书做校验,只要求两边都有证书就行了。
这种情况下,自签名似乎是个脱裤子放屁的事情,直接生成 CA 证书使用就行了。
但是也有很多场景,就是应用层的互联网协议,一般需要完整的 PKI 支持,比如浏览器(HTTPS),会逐层校验证书合法性。
一、步骤
-
以一台机器作为根证书服务器(其实就是CA),负责生成根证书;
-
所有网站的证书,都用这张根证书来签发;
-
客户端导入这张根证书到自己的“受信任的根证书颁发机构”里。
二、 生成根证书
生成根证书应该有许多种:
三、生成局域网可信证书
(一)、 使用mkcert
生成CA根证书并签发对应的端证书
1、 在项目版本页选择对应系统的发布包
2、安装(以Windows系统为例)
进入mkcert
所在目录, 执行以下命令(以管理员身份):
.\mkcert-v1.4.4-windows-amd64.exe -install
输出
如果不需要CA, 使用 -uninstall 卸载。
3、 生成SSL证书
安装完毕后,依然在当前目录执行以下命令,其中ip
为服务端ip
(ip
可以同时生成多个)。在当前目录将生成两个文件,证书文件.pem
和 证书key
文件-key.pem
,这两个文件配置到服务端即可,如果需要转格式可以网上查找,一般我是配置到nginx
不需要转换。
如果是自己单机使用就已经结束了。
文件名 服务端ip
例如,我的是
.\mkcert-v1.4.4-windows-amd64.exe 192.168.x.x
4、 获取CA根证书, 以便给局域网内其它用户使用
首先取出自己的根证书。执行以下命令查看根证书位置,打开地址后能看到两个文件rootCA.pem
和 rootCA-key.pem
,将rootCA.pem
取出即可。把rootCA.pem
和 mkcert
的执行文件一起打包发送给局域网内需要的用户, 将rootCA.pem
所在目录设置进环境变量即可。
#导出CA根证书:
.\mkcert-v1.4.4-windows-amd64.exe -CAROOT
#将rootCA.pem 根证书和安装文件放到同一目录, 并制作对应脚本方便分发,目录机构示例见: https://s2.loli.net/2022/04/29/9cgp5KWltFkhuxn.png
#根证书安装脚本:
@echo off
set p=%~dp0
SETX CAROOT %p% && mkcert-v1.4.4-windows-amd64.exe -install
pause
#卸载脚本:
mkcert-v1.4.4-windows-amd64.exe -uninstall
5、分享根并安装证书
拿到分享的文件夹后,首先需要将当前文件夹放置到一个不会干扰使用者的地方(主要是别以后被机主删掉了或者移动了,毕竟我们把当前文件夹路径配置到环境变量了,要是找不到当前路径一切白搭)。
然后双击 install.bat
(二)、 使用OpenSSL生成CA根证书并签发对应的端证书(openssl X509
方式)
-
对于SSL单向认证:
服务器需要CA证书、server证书、server私钥,客户端需要CA证。
-
对于SSL双向认证:
服务器需要CA证书、server证书、server私钥,客户端需要CA证书,client证书、client私钥。
使用
openssl x509
和使用openssl ca
没有本质差别,openssl ca
使用的配置文件,文件中配置固定的index.txt和serial文件,来记录签发过的证书,确保不会重复签发。如果把当前服务器作为专门的CA签发机构,使用openssl ca
及其关联的配置文件会更好一些。如果只是命令行临时生成一下,用openssl x509
完全可以满足需求。
1、生成CA证书
1.1、 生成CA证书私钥
因为CA比较重要,它的秘钥长度可以大一点,安全性更高。另外-aes256
选项会要求输入私钥保护密码,私钥本身以密文保存。执行后当前目录下得到ROOT_CA_PRIVATEKEY.pem
文件
openssl genrsa -aes256 -out ROOT_CA_PRIVATEKEY.pem 4096
# 国密SM2证书
openssl ecparam -out ca.key -name SM2 -genkey
以上获得多文件为加密文件, 内容以密文方式存放, 如果需要解密获取裸私钥, 使用以下命令:
openssl rsa -in ROOT_CA_PRIVATEKEY.pem -out rootCA.key
生成公钥的指令为:
openssl rsa -in rootCA.key -pubout -out rootCA.pub
1.2、 使用根证书私钥创建一个自签ca根证书的申请
证数各参数含义如下:
C
-----国家(Country Name)ST
----省份(State or Province Name)L
----城市(Locality Name)O
----公司(Organization Name)OU
----部门(Organizational Unit Name)CN
----产品名(Common Name)emailAddress
----邮箱(Email Address)
# 需要手动填写资料
openssl req -new -sha256 -key ROOT_CA_PRIVATEKEY.pem -out ROOT_CA_CSR.pem
# 无交互生成
openssl req -new -sha256 -key ROOT_CA_PRIVATEKEY.pem -out ROOT_CA_CSR.pem -subj "/C=CN/ST=SC/L=ChengDu/OU=ALL/O=www.lsln.top/CN=lsln.top"
1.3、创建一个 CA 根证书的配置文件(ROOT_CA.cnf
)
很重要!! 不然苹果这样严格的设备不会识别为 CA证书, 内容如下:
# 创建 ROOT_CA.cnf 文件并写入下面内容
basicConstraints=critical,CA:TRUE
nsComment = "This Root certificate was generated by XXX"
keyUsage=critical, keyCertSign
subjectKeyIdentifier=hash
1.4、使用申请和私钥签发ca根证书
openssl x509 -req -sha256 -days 36500 -extfile ROOT_CA.cnf -in ROOT_CA_CSR.pem -signkey ROOT_CA_PRIVATEKEY.key -out ROOT_CA_CERT.crt
或者使用以下方式可以选择一步到位,不创建申请文件,直接创建根证书
# 创建root-ca并自签名
openssl req -x509 -newkey rsa:2048 -nodes -keyout ROOT_CA_PRIVATEKEY.key -out ROOT_CA_CERT.crt -days 3650 -sha256 -subj "/C=CN/ST=SC/L=ChengDu/OU=ALL/O=www.lsln.top/CN=lsln.top"
# 查看创建的证书
openssl x509 -in ROOT_CA_CERT.crt -text -noout
2.生成二级CA证书,并使用CA根证书签发
# 创建secondary-ca的证书签名请求
openssl req -new -newkey rsa:2048 -nodes -keyout secondary-ca.key -out secondary-ca.csr -subj "/C=CN/ST=SC/L=ChengDu/OU=it/O=www.lsln.top/CN=lsln.top"
# 使用root-ca签发secondary-ca的证书签名请求
openssl x509 -req -in secondary-ca.csr -CA ROOT_CA_CERT.crt -CAkey ROOT_CA_PRIVATEKEY.key -CAcreateserial -out secondary-ca.crt -days 3650 -extfile secondary-ca.cnf
# 查看创建的证书
openssl x509 -in secondary-ca.crt -text -noout
3、制作CA证书链
由于是二级CA颁发的证书,所以,服务器需要把根CA、二级CA等证书都要发送给浏览器,所以给到web服务器的证书是要一个聚合的证书
cat secondary-ca.crt ROOT_CA_CERT.crt > ca.chain.crt
4、生成SSL证书(使用二级CA证书签发)
接下来,使用 OpenSSL 创建服务器证书。
这一步原理, 首先创建私钥 和 CSR (证书签名请求), 第二步用 CA证书 为 CSR 签名生成 crt
文件。
4.1、创建证书的密钥 和 CSR 文件(证书签名请求)
这里由于不同设备支持等级不一样需要选用设备支持的加密方式.
这里使用 IP 192.168.10.1
作为演示
ECDSA (ECC 算法) P-256
openssl ecparam -out 192.168.10.1.key -name prime256v1 -genkey
openssl req -new -subj "/C=CN/ST=SC/OU=GATEWAY/O=www.lsln.top/CN=192.168.10.1" -key 192.168.10.1.key -out 192.168.10.1.csr
ECDSA (ECC 算法) P-384
openssl ecparam -out 192.168.10.1.key -name secp384r1 -genkey
openssl req -new -subj "/C=CN/ST=SC/OU=GATEWAY/O=www.lsln.top/CN=192.168.10.1" -key 192.168.10.1.key -out 192.168.10.1.csr
RSA - 嵌入式设备大多数用这个 2048-bit
, 虽然最低推荐为 3072-bit
但是有的旧设备不支持.
openssl req -newkey rsa:2048 -nodes -subj "/C=CN/ST=SC/OU=GATEWAY/O=www.lsln.top/CN=192.168.10.1" -keyout 192.168.10.1.key -out 192.168.10.1.csr
4.2、 用 CA证书 为 CSR 签名生成crt
文件
创建ssl.cnf
证书配置文件,将签发的域名或者IP地址填到 [alt_names]
里面
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1= localhost
DNS.2= localhost.loacl
DNS.3= ...
IP.1 = 192.168.10.1
IP.2 = 192.168.10.198
IP.3 = ::1
IP.4 = 127.0.0.1
IP.5 = ...
不太正规的方法, 每次签发都使用 -CAcreateserial
openssl x509 -req -CA secondary-ca.crt -CAkey secondary-ca.key -CAcreateserial -days 398 -sha256 -extfile ssl.cnf -in 192.168.10.1.csr -out 192.168.10.198.crt
正规方式, 每个证书是唯一的. 重新签发也需要使用第一次创建的序列号, 查看序列号:
openssl x509 -text -in .\192.168.10.198.crt -noout
第一次使用 -CAcreateserial
创建证书后保存证书序列号文件 192.168.10.1.srl
在此之后更新证书的时候使用相同的序列号
openssl x509 -req -CA secondary-ca.crt -CAkey secondary-ca.key -CAserial 192.168.10.1.srl -days 398 -sha256 -extfile ssl.cnf -in 192.168.10.1.csr -out 192.168.10.198.crt
4.3、 验证证书是否可信
openssl verify -CAfile ca.chain.crt 192.168.10.198.crt
#输出以下信息则证明该证书可信
192.168.10.198.crt: OK
5、生成bundle.crt
cat 192.168.10.198.crt ca.chain.crt > 192.168.10.198.bundle.crt
四、将pem
格式证书转换为JKS
1、将 .pem 格式的证书导出 .p12 格式(keytool
)的证书
openssl pkcs12 -export -in cert.pem -inkey cert.key -out keystore.p12 -passout pass:<passvalue>
示例:
#无别名, 互动输入密钥信息
openssl pkcs12 -export -in 192.168.10.198.crt -inkey 192.168.10.1.key -out 192.168.10.198.p12
# 添加别名
openssl pkcs12 -export -name <alias> -in cert.pem -inkey cert.key -out keystore.p12 -passout pass:<passvalue>
2、将证书由 .p12 格式转换成 .jks 格式:
提示:执行 openssl 命令导出 .p12 格式证书时会要求设置密钥,执行 keytool 命令时也有 3 处要写密钥,最简单的方式就是所有需要密钥的地方,都使用同一个,这样也不会搞混。
keytool -importkeystore -srckeystore keystore.p12 -srcstoretype PKCS12 -destkeystore keystore.jks \
-srcstorepass <passvalue> -deststorepass <passvalue>
示例:
keytool -importkeystore -deststorepass '<passvalue>' -destkeypass '<passvalue>' -destkeystore 192.168.10.198.jks -srckeystore 192.168.10.198.p12 -srcstoretype PKCS12 -srcstorepass '<passvalue>'