使用ECC算法自签Ca证书
ECC 被认为是 RSA 的继任者,新一代的非对称加密算法,加密速度快,效率更高,对服务器资源消耗低,尤其在区块链中广泛使用。这里介绍一下如何使用 ECC 算法生成 HTTPS 证书。
概览
前一篇博客 CA & OpenSSL自签名证书 讲了如何使用 OpenSSL 生成自签名证书,用的是 RSA 算法,RSA 算法是比较常见的算法,应用较早,较为普及,兼容性较好,但是 RSA 算法密钥长度较长,性能消耗较高。后来于 1985 年提出 椭圆曲线密码学,简称 ECC,并于 2004 年开始被广泛应用。 ECC 被认为是 RSA 的继任者,新一代的非对称加密算法,尤其在区块链中广泛使用。
关于 RSA 和 ECC 算法的原理这里不做介绍,我们只需要知道这是两种非对称加密算法就可以了,而 ECC 加密速度快,效率更高,对服务器资源消耗低,而且重要的是更安全,抗攻击型更强。所以这里介绍一下如何使用 ECC 替换 RSA 生成 HTTPS 证书。
想详细了解 ECC 椭圆算法的可以看文字后面的参考[1][2]。
OpenSSL ecparam 命令
OpenSSL 使用 ecparam
命令来进行 ECC 加密,我们看一下支持的参数:
-inform PEM|DER
: 输入文件格式,DER或者PEM格式。DER格式采用ASN1的DER标准格式。一般用的多的都是PEM格式,就是base64编码格式。-outform DER|PEM
: 输出文件格式,DER或者PEM格式。-in filename
: 输入的椭圆曲线密钥文件,默认为标准输入。-out filename
: 椭圆曲线密钥输出文件,默认为标准输出。-noout
: 不打印参数编码的版本信息。-text
:打印椭圆曲线密钥参数信息值。-C
:以C语言风格打印信息。-check
:检查椭圆曲线密钥参数。-name arg
:采用短名字。-list_curve
:打印所有可用的短名字。-param_enc
:指定参数编码方法,可以是named_curve
和explicit
,默认为named_curve
。-conv_form arg
:指定信息存放方式,可以是compressed
、uncompressed
或者hybrid
,默认为compressed
。-no_seed
:如果-param_enc
指定编码方式为explicit
,不采用随机数种子。-rand file(s)
:随机数产生种子。-genkey
:生成椭圆曲线密钥参数。-engine id
:指定硬件引擎。
注意:
PEM格式的EC参数用的头部和底部为:
-----BEGIN EC PARAMETERS-----
...
-----END EC PARAMETERS-----
示例
- 查看内置的椭圆曲线:
openssl ecparam -list_curves
我们可以用内置的椭圆曲线创创建 EC 参数。
- 用曲线
prime192v1
产生 EC 参数:
openssl ecparam -name prime192v1 -out ec_param.pem
- 用明确的参数来产生 EC 参数:
openssl ecparam -name prime192v1 -param_enc explicit -out ec_param.pem
- 验证给出的 EC 参数:
openssl ecparam -in ec_param.pem -check
- 创建 EC 参数和私钥文件:
openssl ecparam -genkey -name prime192v1 -out ec_key.pem
- 改变编码为
compressed
:
openssl ecparam -in ec_param.pem -conv_form compressed -out ec_out.pem
- 查看 EC 私钥:
openssl ecparam -in ec_param.pem -noout -text
使用 ECC 自建CA
使用 ECC 和使用签名使用 RAS 的基本一致,不过是把生成私钥的命令从 genrsa
换成 ecparam
了而已,完整命令如下:
#!/bin/bash
set -ex
mkdir root
# 创建 Root Key
openssl ecparam -out root/ca.key.pem -name prime256v1 -genkey
curl -o ./root/openssl.cnf https://gist.githubusercontent.com/foreverzmy/0b07d3a731d70519e35ced070118e3fe/raw/71210c2643b8997ea6e2cf333e26aa33e712a7e2/simple-root-ca.cnf
# 创建 Root Cert
openssl req -config root/openssl.cnf \
-key root/ca.key.pem \
-passin pass:123456 \
-new \
-x509 \
-days 7300 \
-sha256 \
-extensions v3_ca \
-out root/ca.cert.pem \
-subj /C=CN/ST=Shanghai/L=Shanghai/O=JediLtd/OU=JediProxy/CN=JediRootCA/emailAddress=921255465@qq.com
chmod 400 root/ca.cert.pem
# 验证证书
# openssl x509 -noout -text -in root/ca.cert.pem
# 创建 Intermediate Pair
# 创建 intermediate 文件夹存放 Intermediate Pair
mkdir intermediate
# 创建 Intermediate Key
openssl ecparam -out intermediate/intermediate.key.pem -name prime256v1 -genkey
chmod 400 intermediate/intermediate.key.pem
curl -o ./intermediate/openssl.cnf https://gist.githubusercontent.com/foreverzmy/936b1bb55adf52c5d1accc9b2216a0e3/raw/28b9f97df967d93febf09219863190aea3b36895/simple-intermediate-ca-cnf
# 创建 Intermediate Cert
openssl req -config intermediate/openssl.cnf -new -sha256 \
-key intermediate/intermediate.key.pem \
-passin pass:123456 \
-out intermediate/intermediate.csr.pem \
-subj /C=CN/ST=Shanghai/L=Shanghai/O=JediLtd/OU=JediProxy/CN=JediIntermediateCA/emailAddress=921255465@qq.com
chmod 400 intermediate/intermediate.key.pem
touch root/index.txt
echo 1000 > root/serial
# 使用 v3_intermediate_ca 扩展签名,密码为 123456
# Intermediate Pair 的有效时间一定要为 Root Pair 的子集
openssl ca -config root/openssl.cnf \
-extensions v3_intermediate_ca \
-days 3650 \
-notext \
-md sha256 \
-passin pass:123456 \
-in intermediate/intermediate.csr.pem \
-out intermediate/intermediate.cert.pem
chmod 444 intermediate/intermediate.cert.pem
# 验证 Intermediate Pair
# openssl x509 -noout -text -in intermediate/intermediate.cert.pem
# openssl verify -CAfile root/ca.cert.pem intermediate/intermediate.cert.pem
# 浏览器在验证中级证书的时候,同时也会去验证它的上一级证书是否靠谱
# 创建证书链,将 Root Cert 和 Intermediate Cert 合并到一起,可以让浏览器一并验证
cat intermediate/intermediate.cert.pem root/ca.cert.pem > intermediate/ca-chain.cert.pem
chmod 444 intermediate/ca-chain.cert.pem
# 创建服务器/客户端证书
# 创建 foreverz.cn 存放域名相关证书文件
mkdir foreverz.cn
# 生成域名私钥
openssl ecparam -out foreverz.cn/foreverz.cn.key.pem -name prime256v1 -genkey
# 创建网站证书请求
openssl req -config intermediate/openssl.cnf \
-key foreverz.cn/foreverz.cn.key.pem \
-new -sha256 \
-out foreverz.cn/foreverz.cn.req \
-subj /C=CN/ST=Shanghai/L=Shanghai/O=JediLtd/OU=JediProxy/CN=foreverz.cn/emailAddress=921255465@qq.com
# 签发网站证书
openssl x509 -req -in foreverz.cn/foreverz.cn.req \
-days 375 \
-sha256 \
-CA intermediate/intermediate.cert.pem \
-CAkey intermediate/intermediate.key.pem \
-CAcreateserial \
-out foreverz.cn/foreverz.cn.cert.pem
# 验证证书
# openssl x509 -noout -text -in foreverz.cn/foreverz.cn.cert.pem
openssl verify -CAfile intermediate/ca-chain.cert.pem foreverz.cn/foreverz.cn.cert.pem
这样就生成了一系列证书,下面是我们需要的文件:
ca.key.pem
: 根CA私钥文件,签发中级CA证书时需要。ca.cert.pem
: 根CA证书,可以安装到电脑上,用来认证中级CA。intermediate.key.pem
:中级CA私钥,签到域名证书是需要。intermediate.key.pem
:中级CA证书,可以安装到电脑上,用来认证域名证书。ca-chain.cert.pem
: CA证书链,包含根证书和中级证书,可以一次性安装两个证书。foreverz.cn.key.pem
: 网站私钥,启用 HTTPS 服务时需要foreverz.cn.cert.pem
: 网站公钥,启用 HTTPS 服务时需要
测试
下面我们启动一个 HTTPS 服务测试一下证书。由于我比较喜欢 go 语言,所以使用 go 语言的 fasthttp 框架来测试。
在 foreverz.cn
目录创建 main.go
内输入如下内容,并使用 go mod init
和 go mod tidy
安装依赖:
package main
import (
"fmt"
"github.com/valyala/fasthttp"
)
func main() {
fasthttp.ListenAndServeTLS(":6789", "foreverz.cn.cert.pem", "foreverz.cn.key.pem", requestHandler)
}
func requestHandler(ctx *fasthttp.RequestCtx) {
fmt.Printf("%s %s %s %s\n", ctx.URI().Scheme(), ctx.Method(), ctx.Host(), ctx.Path())
ctx.SetBodyString(fmt.Sprintf("hello from %s!", ctx.URI().Scheme()))
}
运行 go run main.go
启动服务。
使用 cURL 测试服务:
$ curl https://foreverz.cn:6789/123 --resolve "foreverz.cn:6789:127.0.0.1"
如果此时没有安装根证书到系统,会报错,证书不合法:
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
可以使用如下命令安装证书到系统(MacOS):
$ sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ./intermediate/ca-chain.cert.pem
此时再运行 cURL 命令,控制台显示 hello from https!
说明成功了。
PS:可以只安装中级CA证书,也可以安装证书链,只安装根CA证书不可以,会认证失败!
为了安全,在使用完成后尽量删除证书避免安全问题:
$ sudo security remove-trusted-cert -d intermediate/intermediate.cert.pem
完结,撒花🎉🎉🎉