探索GmSSL+Nginx实践及原理

2023-09-19 11:27:37

前言

随着大国崛起步伐的迈进,敏感单位的数据安全问题越发受到重视,数据的加密安全传输尤为重要,对于安全问题,国家自研加密算法提供了有力的保障。

作为信创行业的国有企业,十分有必要在网络通信中使用国密算法加密通信,保障客户数据安全,做出客户放心满意的产品。

本文将介绍如何制作出支持国密算法的nginx,及相关原理。

GmSSL

介绍

  • 是由北京大学自主开发的国产商用密码开源库。
  • 实现了对国密算法、标准和安全通信协议的全面功能覆盖,支持包括移动端在内的主流操作系统和处理器。
  • 支持密码钥匙、密码卡等典型国产密码硬件。
  • 提供功能丰富的命令行工具及多种编译语言编程接口。

它在国密算法中,主要两个作用:提供库、生成证书。

版本问题

  • 根据 github 分支可以看出版本有:master(也称为 v3)、GmSSL-v2、GmSSL-v1。
  • GmSSL 起始是由 OpenSSL 开源项目变更而来,相当于 OpenSSL 的一个分支。v2 版本及以前版本提供和 OpenSSL 相同的 API,可以很好的兼容依赖 OpenSSL API的应用,比如兼容 nginx、tomcat 等。
  • 但是最新版 v3 版本,采用了新设计的架构和API,不再兼容 OpenSSL API的应用。
  • 为了体现 v3 版本的适用性,团队开源出了基于 Nginx 1.21.0 修改的 Nginx-with-GmSSLv3(部署启动后 tls 流程我是没跑通的)。
  • v3 版本还有一个重要变更:支持TLS 1.3,而 v2 版本只支持 TLS 1.2。

安装

下载代码

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

错误处理提示:

  1. 出现 .so 文件找不到的报错,这表示动态链接库找不到,这种情况要么某库未安装,去yum安装一下;要么是需要库已经装了,但是路径不在当前系统的LIB路径里,需要 export LD_LIBRARY_PATH=${库的路径}:$LD_LIBRARY_PATH
  2. 使用 /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 安装

下载代码

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 介绍

tls 是传输层安全协议,其“简单化”的握手流程如下:

  1. Client 向 Server 请求建立连接(client hello)。
  2. Server 将自己的证书发送给 Client(server hello)。
  3. Client 验证证书,然后使用证书中的公钥加密后续通信的对称密钥,将加密内容发送给 Server。
  4. Server 收到后解密获得对称密钥,且将用该对称密钥上层数据进行加解密。
  5. 自此 TLS 握手完成,接下来使用对称密钥进行通信。
    真实的 tls 握手流程会比上述复杂,主要是为了防止降级攻击、重放攻击等攻击手段。

上述握手过程中有几点需要说明:

  1. tls 中加密方式包含非对称加密、对称加密两种。
  2. tls 中使用非对称加密的主要目的,只是为了安全“护送”对称密钥。真正数据是使用对称密钥加密,使用非对称密钥太耗时了。
  3. 我们并不能使用公钥直接“护送”对称密钥,因为客户端分不清公钥是“哪家”的。万一 DNS 被劫持了,邪恶服务器顶替正常服务器,客户端收到了邪恶服务器的公钥,和邪恶服务器撩起来,就麻烦了。为了防止这种情况,需要对公钥签名,标明这个公钥是“哪家”的。
  4. 所谓签名,就是将签名所需内容:公钥、域名、所有者等信息,发给 CA 机构(公认信任的机构),CA 机构会验证信息正确性,然后将信息做个hash,再将这个 hash 值和签名所需内容放在一起,最后 CA 机构用自己的私钥对放在一起的信息进行加密,这个过程就是签名,加密后的内容就是证书。现在再想一下上述的邪恶服务器还敢顶替正常服务器,用自己的证书和客户握手吗?肯定不敢了,它自己的证书可在 CA 机构备过案了呀。
  5. 如果不是 CA 机构签发的证书,是私人签发的,客户端会有警告并提示:是否继续前往

证书介绍

格式

其实证书就两种格式:二进制、文本格式。

常见的证书后缀包括:.der、.cer、.pem、.crt、.csr、.pfx、.p12、.jks等。

der、cer,二进制格式,只保存证书,不保存私钥。pfx、p12,二进制格式,同时包含证书和私钥。pem、crt、csr 一般是文本格式。

Gmssl 生成证书指令

概述

指令及开发文档:gmssl 命令及开发文档

可以使用 Gmssl 发布私人证书,gmssl指令繁多,我们只需理解相关步骤指令含义即可,相关步骤包含:生成私钥、生成证书签名请求文件、生成证书。

生成私钥

gmssl ecparam -genkey -name sm2p256v1 -noout -out root.key

  • gmssl 官方说法ecparamgenpkey命令,都可以用来生成私钥,但实际上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=邮箱"

  • 生成 root.csr 证书签名请求文件,为什么生成root.csr,它的作用是什么:我们在签名的时候,需要提供公钥、域名、所有者等信息给 CA 机构,root.csr 就是这些信息合在一起的一个文本。所以可以知道csr文件里是含有公钥的。
  • -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

  • 使用根(CA)私钥对.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 证书配置

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错误。此时你会被这个哲学问题困扰很久,就和当初我一样,下面解释原因:

  • 正常 tls 中使用公钥可以用来验证签名和加解密。但是国密里不行,它规范要求分为验证签名的公钥加解密的公钥两种公钥,所以这里得配两个,同时国密浏览器也做了相应适配。
  • 如果是 C++ 写的“国密客户端”可能需要调用 GmSSL 提供的 API 了。

完结

感谢阅读,完结!

更多推荐

K8S架构原理

目录一、k8s概述1、什么是k8s?2、特性3、主要功能二、集群架构与组件1.Master组件(1)Kube-apiserver(2)Kube-controller-manager(3)Kube-scheduler调度算法:2.配置存储中心3.Node组件(1)Kubelet(2)Kube-Proxy(3)docker

【SpringMVC】之自定义注解

文章目录一、Java注解1.1简介1.2分类1.2.1JDK基本注解1.2.2JDK元注解1.3自定义注解二、使用自定义注解2.1案例一(获取类与方法上的注解值)2.2案例二(获取类属性上的注解属性值)2.3案例三(获取参数修饰注解对应的属性值)三、Aop自定义注解的应用一、Java注解1.1简介Java注解是附加在代

[论文阅读]Coordinate Attention for Efficient Mobile Network Design

摘要最近关于移动网络设计的研究已经证明了通道注意力(例如,theSqueeze-and-Excitationattention)对于提高模型的性能有显著的效果,但它们通常忽略了位置信息,而位置信息对于生成空间选择性注意图非常重要。在本文中,我们提出了一种新的移动网络注意力机制,将位置信息嵌入到通道注意力中,我们称之为“

【论文笔记】Baidu Apollo EM Motion Planner

文章目录AbstractI.INTRODUCTIONA.MultilaneStrategyB.Path-SpeedIterativeAlgorithmC.DecisionsandTrafficRegulationsII.EMPLANNERFRAMEWORKWITHMULTILANESTRATEGYIII.EMPLANN

nginx知识点详解:反向代理+负载均衡+动静分离+高可用集群

一、nginx基本概念1.nginx是什么,做什么事情?Nginx是一个高性能的HTTP和反向代理服务器,特点是占有内存少,并发能力强。Nginx转为性能优化而开发,能经受高负载考验。支持热部署,启动容易,运行时间长。2.反向代理正向代理:在客户端(浏览器)配置代理服务器,通过代理服务器进行互联网访问。反向代理:客户端

Python 08学习之文件操作

😀前言欢迎来到Python08学习之文件操作。在本文中,我们将介绍计算机中常见的文本文件和二进制文件,并探讨在Python中操作文件的步骤和相关函数/方法。通过学习本文,您将能够了解如何使用Python打开、读取、写入和关闭文件,以及如何按行读取文件内容。希望您能够通过本文提高您的Python文件操作能力,并且在实际

华为HCIA(二)

今天是第二天(一题一笔记)FTP(文件传输协议)使用的端口号是20和21控制层面用的是21DHCP(IP地址和子网掩码)服务器分配IP地址默认的租期是24小时Tnlnet协议(网络层)默认使用的服务器端口号是23完成链路认证后,STA要通过Association发起链路服务协商WLAN通过SSID来区分不同的网络基于M

【PickerView案例10-国旗选择界面02 Objective-C预言】

一、好了,我们继续来实现这个国旗选择界面:1.它的界面里面,是不是很简单,就一个UIPickerView,就完事儿了然后,显示的每一行内容呢,1)一个文字Label2)一个图片那大家应该有意识,它返回的应该是一个View,对吧,代理方法里面,有一个返回View的,viewForRow:viewForRowInCompo

R语言APRIORI关联规则、K-MEANS均值聚类分析中药专利复方治疗用药规律网络可视化...

全文链接:http://tecdat.cn/?p=30605应用关联规则、聚类方法等数据挖掘技术分析治疗的中药专利复方组方配伍规律(点击文末“阅读原文”获取完整代码数据)。方法检索治疗中药专利复方,排除外用中药及中西药物合用的复方。最近我们被要求撰写关于用药规律的研究报告,包括一些图形和统计输出。对入选的中药专利复方进

延长周末,获得高质量休息:工作与学习党的生活策略

🌷🍁博主猫头虎带您GotoNewWorld.✨🍁🦄博客首页——猫头虎的博客🎐🐳《面试题大全专栏》文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺🌊《IDEA开发秘籍专栏》学会IDEA常用操作,工作效率翻倍~💐🌊《100天精通Golang(基础入门篇)》学会Golang语言,畅玩云原生,走遍大

开源库源码分析:Okhttp源码分析(一)

开源库源码分析:OkHttp源码分析导言接下来就要开始分析一些常用开源库的源码了,作为最常用的网络请求库,OkHttp以其强大的功能深受Android开发者的喜爱(比如说我),还有对该库进行二次封装而成的热门库,比如说Retrofit。本文我们将从源码入手看看OkHttp是如何运作的。注意本文解析的是OkHttp3库,

热文推荐