使用ECDSA算法的自签名https证书生成

在之前《自签名https证书生成 (附赠nginx配置文件)》描述了如何为网站生成https 的自签名证书了,但文中所用的非对称加密算法是传统的RSA算法,并且目前常见的自签名证书生成的文章基本都采用RSA算法。 然而作为非对称加密算法的ECDSA,其性能和安全性优于RSA算法,因此目前也被越来越多的地方用于https的证书中。 相比RSA算法的证书,相同安全强度下,ECDSA能够更少的服务器资源占用,更快的响应速度。因此,本文继上一篇文章后,再描述一下 采用ECDSA椭圆曲线算法生成自签名的ECC证书。

ECC算法与RSA算法

在 1976 年,由于对称加密算法已经不能满足需要,Diffie 和 Hellman 发表了一篇叫《密码学新动向》的文章,介绍了公匙加密的概念,由 Rivet、Shamir、Adelman 提出了 RSA 算法。RSA 就是他们三人姓氏开头字母拼在一起组成的。

随着分解大整数方法的进步及完善、计算机速度的提高以及计算机网络的发展,为了保障数据的安全,RSA 的密钥需要不断增加,但是,密钥长度的增加导致了其加解密的速度大为降低,硬件实现也变得越来越难以忍受,这对使用 RSA 的应用带来了很重的负担,因此需要一种新的算法来代替 RSA。 1985 年 N.Koblitz 和 Miller 提出将椭圆曲线用于密码算法,全称:Elliptic curve cryptography,缩写为 ECC,根据是有限域上的椭圆曲线上的点群中的离散对数问题 ECDLP。ECDLP 是比因子分解问题更难的问题,它是指数级的难度。

现在 SSL 证书普遍使用的是 RSA 算法,由于上述的 RSA 算法存在的缺点,使用 ECC 作为其公钥算法的数字证书近几年的发展也不容小觑:2008 年左右 CA 开始储备 ECC 根证书,2012 年左右 CA 开始对外公开销售 ECC 证书,2014 年 ECC 证书在国外被普遍开始使用,2015 年国内开始接受 ECC 证书。

ECC相比于RSA,有许多方面都有绝对的优势,特别是速度与性能方面。这里就不再赘述与比较了。下面开始介绍相关证书的生成。

密钥文件的生成

不同于RSA算法,ECDSA算法有一项参数是选择ECC所使用的椭圆曲线参数。可以通过以下命令查看目前openssl所支持的曲线类型。

openssl ecparam -list_curves

可以根据所列的曲线类型,选择你所需要的曲线。建议选择secp曲线或者sect的曲线,本文选择secp521r1曲线,如果考虑更好的兼容性可以选择secp384r1曲线。

openssl ecparam -genkey -name secp521r1 -out server.key

通过以上命令生成ECC椭圆算法的私钥文件server.key

创建服务器证书申请文件

openssl req -new -key server.key -out server.csr

这条命令执行后,会要求你填写一些服务器相关的信息。一般其他内容都可以随意填写,但对于https的证书而言,Common Name必须为你网站的域名。 生成的server.csr文件,是用来递交给CA让他来认证签名的。

自签名CA证书的生成

openssl x509 -req -in server.csr -signkey server.key -out ca.crt -days 3650

利用server.key生成一张有效期为10年的自签名CA证书 (没有考虑闰年平年的问题)。

为服务器签发证书

openssl x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey server.key -CAcreateserial -out server.crt

通过以上命令,采用之前生成的CA证书,对之前的服务器证书申请文件进行签名认证,生成一张有效期为10年的证书。如果你之前为CA单独生成了一个密钥, 则这里 -CAkey server.key 替换成你实际生成CA证书的密钥文件。

额外附送另一个nginx配置

考虑到这次ECC自签证书生成的文章是为了更好的安全性而写的,因此nginx的配置也换成相对安全一点的配置。

server {
    listen       443 ssl http2;
    server_name  localhost;

    ssl_certificate server.crt;        # 这里为服务器上server.crt的路径
    ssl_certificate_key server.key;    # 这里为服务器上server.key的路径
    #ssl_client_certificate ca.crt;    # 双向认证
    #ssl_verify_client on;             # 双向认证

    ssl_session_timeout 5m;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ecdh_curve X25519:P-256:P-384:P-521;
    ssl_ciphers '[ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305]:ECDHE+AES128:RSA+AES128:ECDHE+AES256:RSA+AES256:ECDHE+3DES:RSA+3DES';
    ssl_prefer_server_ciphers on;

    # ... 以下为nginx的其他配置,此处省略
}

其中ssl_ciphers选择相对较为安全的几个算法,具体部署服务器时,应根据服务器端的openssl做调整。具体可通过在服务器上执行以下命令查看所支持的算法。

openssl ciphers

最后总结

不论是ECDSA算法,还是RSA算法,在合适的场景下,正确的使用,都能起到很好的安全作用。密码学中,真正引入不安全因素的往往是人,错误的使用才是不安全的根本原因。 而对于自签名CA的网站来说,最大的安全隐患是中间人攻击。由于网站证书无法得到权威CA的认证,因此非常容易实现中间人攻击。预防这类隐患的方法是将自签名的CA加入到 受信CA中,并在链接https不授权不可信的网站证书。但这也会带来另一个问题,如果你自签的CA证书私匙泄漏了,那可能遭到更大范围的中间人攻击。因此,从通讯安全考虑, 还是使用权威授权的网站证书会比较合适,而自签证书则比较适合用于测试或其他一些可以不考虑中间人替换证书进行攻击的网络环境下使用。