随着大国崛起步伐的迈进,敏感单位的数据安全问题越发受到重视,数据的加密安全传输尤为重要,对于安全问题,国家自研加密算法提供了有力的保障。
作为信创行业的国有企业,十分有必要在网络通信中使用国密算法加密通信,保障客户数据安全,做出客户放心满意的产品。
本文将介绍如何制作出支持国密算法的nginx,及相关原理。
它在国密算法中,主要两个作用:提供库、生成证书。
GmSSL Github 代码下载地址
我们切换分支使用 GmSSL-v2。
git clone https://github.com/guanzhi/GmSSL.git
cd GmSSL
# 指定 gmssl 安装路径
./config --prefix=/usr/local/gmssl
# 编译安装
make && make install
# 检查安装成功否
/usr/local/gmssl/bin/gmssl version
错误处理提示:
.so
文件找不到的报错,这表示动态链接库找不到,这种情况要么某库未安装,去yum
安装一下;要么是需要库已经装了,但是路径不在当前系统的LIB
路径里,需要 export LD_LIBRARY_PATH=${库的路径}:$LD_LIBRARY_PATH
/usr/local/gmssl/bin/gmssl
命令,大概率会出现undefined symbol: xxx
的错误。这说明找到库了,但找错了,可能找到默认库路径里去了,而默认库里恰好存在同名的so
文件(比如 libcrypto.so.1.1、libssl.so.1.1 文件是 gmssl 所需的,但默认库路径也有的)。添加环境变量export LD_LIBRARY_PATH=/usr/local/gmssl/lib:$LD_LIBRARY_PATH
即可解决。nginx 下载
这里提供下载的 1.22.0 版本,你也可以选择合适的版本下载,并解压。
在刚解压的路径,vim 编辑nginx/auto/lib/openssl/conf
文件:
将文中内容:
CORE_INCS="$CORE_INCS $OPENSSL/.openssl/include"
CORE_DEPS="$CORE_DEPS $OPENSSL/.openssl/include/openssl/ssl.h"
CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libssl.a"
CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libcrypto.a"
修改为:
CORE_INCS="$CORE_INCS $OPENSSL/include"
CORE_DEPS="$CORE_DEPS $OPENSSL/include/openssl/ssl.h"
CORE_LIBS="$CORE_LIBS $OPENSSL/lib/libssl.a"
CORE_LIBS="$CORE_LIBS $OPENSSL/lib/libcrypto.a"
./configure --with-pcre \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_sub_module \
--with-http_flv_module \
--with-http_mp4_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_stub_status_module \
--with-http_auth_request_module \
--with-http_slice_module \
--with-mail \
--with-threads \
--with-file-aio \
--with-stream \
--with-mail_ssl_module \
--with-stream_ssl_module \
--with-openssl="${gmssl 安装路径}" \
--with-cc-opt="-I${gmssl 安装路径}/include" \
--with-ld-opt="-lm"
# 编译安装
make && make install
上述命令可以看出,with-openssl
是指定 openssl 安装路径的,但我们实际需要填写安装 gmssl 的路径。
tls 是传输层安全协议,其“简单化”的握手流程如下:
上述握手过程中有几点需要说明:
其实证书就两种格式:二进制、文本格式。
常见的证书后缀包括:.der、.cer、.pem、.crt、.csr、.pfx、.p12、.jks等。
der、cer,二进制格式,只保存证书,不保存私钥。pfx、p12,二进制格式,同时包含证书和私钥。pem、crt、csr 一般是文本格式。
指令及开发文档:gmssl 命令及开发文档。
可以使用 Gmssl 发布私人证书,gmssl指令繁多,我们只需理解相关步骤指令含义即可,相关步骤包含:生成私钥、生成证书签名请求文件、生成证书。
gmssl ecparam -genkey -name sm2p256v1 -noout -out root.key
ecparam
和 genpkey
命令,都可以用来生成私钥,但实际上genpkey
不可用。-name
表示选择一条椭圆曲线来生成私钥,可以通过gmssl ecparam -list_curves
查看内建了哪些椭圆曲线。-name sm2p256v1
就行,加密算法相关,不用深究。gmssl req -new -key root.key -out root.csr -subj "/C=CN/ST=BeiJing/L=BeiJing/O=公司名/CN=tom/emailAddress=邮箱"
-subj
表示主题,使用该指令就不用按照提示手动填入相关信息。/usr/local/gmssl/bin/gmssl x509 -req -days 3650 -sm3 -in root.csr -extfile openssl.cnf -extensions v3_ca -signkey root.key -out root.crt
.crt
文件加密(签名)。-extfile
指定的openssl.cnf
配置文件,其实就是 openssl 安装路径下的配置文件拷贝出来,并添加上以下配置:# 这个配置必加,否则 gmssl 会报错的。openssl 则无需。
[ v3enc_req ]
basicConstraints = CA:FALSE
keyUsage = keyAgreement, keyEncipherment, dataEncipherment
/usr/local/gmssl/bin/gmssl x509 -in server.crt -text -noout
生成脚本如下:
#!/bin/bash
# 生成CA证书
/usr/local/gmssl/bin/gmssl ecparam -genkey -name sm2p256v1 -noout -out root.key
/usr/local/gmssl/bin/gmssl req -new -key root.key -out root.csr -subj "/C=CN/ST=BeiJing/L=BeiJing/O=公司名/CN=tom/emailAddress=邮箱"
/usr/local/gmssl/bin/gmssl x509 -req -days 3650 -sm3 -in root.csr -extfile openssl.cnf -extensions v3_ca -signkey root.key -out root.crt
# Server签名证书
/usr/local/gmssl/bin/gmssl ecparam -genkey -name sm2p256v1 -noout -out server.key
/usr/local/gmssl/bin/gmssl req -new -SM3 -key server.key -out server.csr -subj "/C=CN/ST=BeiJing/L=BeiJing/O=公司名/CN=tom/emailAddress=邮箱"
/usr/local/gmssl/bin/gmssl x509 -req -SM3 -days 3650 -in server.csr -extfile openssl.cnf -extensions v3_req -CA root.crt -CAkey root.key -set_serial 1000000001 -out server.crt
# Server加密证书
/usr/local/gmssl/bin/gmssl ecparam -genkey -name sm2p256v1 -noout -out server_en.key
/usr/local/gmssl/bin/gmssl req -new -SM3 -key server_en.key -out server_en.csr -subj "/C=CN/ST=BeiJing/L=BeiJing/O=公司名/CN=tom/emailAddress=邮箱"
/usr/local/gmssl/bin/gmssl x509 -req -SM3 -days 3650 -in server_en.csr -extfile openssl.cnf -extensions v3enc_req -CA root.crt -CAkey root.key -set_serial 1000002001 -out server_en.crt
这里除了创建根(CA)密钥对,逻辑上只需再创建一个证书来使用就行,可我们脚本为什么创建了两个呢?后面再说。
在nginx.conf
里对应的“server 块”中,配置:
ssl_certificate "/usr/local/nginx/conf/tls/server.crt";
ssl_certificate_key "/usr/local/nginx/conf/tls/server.key";
ssl_certificate "/usr/local/nginx/conf/tls/server_en.crt";
ssl_certificate_key "/usr/local/nginx/conf/tls/server_en.key";
需要配置两个证书,也就是上面脚本创建两个的原因。
如果 Nginx 中只配置了单个证书,那么你抓包查看 tls 流程,就会发现:client hello
后,服务端返回一个handshake failed
错误。此时你会被这个哲学问题困扰很久,就和当初我一样,下面解释原因:
感谢阅读,完结!