安装依赖

# nginx版本:1.25.0以上
# boringssl版本:需要go语言1.18.9以上、cmake3.12以上

yum provides */cmake
yum install gcc-c++ libunwind-devel golang cmake;
cd /midware/make
wget https://github.com/Kitware/CMake/releases/download/v3.28.0-rc3/cmake-3.28.0-rc3.tar.gz
tar xvf cmake-3.28.0-rc3.tar.gz
cd cmake-3.28.0-rc3
yum remove cmake -y
./configure --prefix=/usr/local/cmake
make && make install
ln -s /usr/local/cmake/bin/cmake /usr/bin/cmake
vim /etc/profile
export CMAKE_HOME=/usr/local/cmake
export PATH=$PATH:$CMAKE_HOME/bin
source /etc/profile
cmake -version

wget https://boringssl.googlesource.com/boringssl/+archive/refs/heads/master.tar.gz
mkdir -p /midware/make/boringssl
tar xvf master.tar.gz -C boringssl
cd boringssl && mkdir build && cd build && cmake .. && make && cd ../../





yum install gcc gcc-c++ pcre-devel openssl-devel zlib-devel cmake make libunwind-devel hg git wget

./auto/configure --user=www --group=www --prefix=/www/server/nginx --with-pcre  --add-module=/root/ngx_brotli --with-http_v2_module --with-stream --with-stream_ssl_module --with-http_ssl_module --with-http_gzip_static_module --with-http_gunzip_module --with-http_sub_module --with-http_flv_module --with-http_addition_module --with-http_realip_module --with-http_mp4_module --with-ld-opt=-Wl,-E --with-cc-opt=-Wno-error --with-ld-opt=-ljemalloc --with-http_dav_module --with-http_v3_module \
    --with-cc-opt=-I../boringssl/include \
    --with-ld-opt='-L../boringssl/build/ssl -L../boringssl/build/crypto'


./configure
    --with-debug
    --with-http_v3_module
    --with-cc-opt="-I../boringssl/include"
    --with-ld-opt="-L../boringssl/build/ssl
                   -L../boringssl/build/crypto"
http {
    log_format quic '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" "$http3"';

    access_log logs/access.log quic;

    server {
        listen 443 ssl;
        listen [::]:443 ssl;

        # 用于支持Quic或HTTP/3
        listen 443 quic reuseport;
        listen [::]:443 quic reuseport;

        # 用以支持HTTP/2
        http2 on;

        # 默认值
        http3 on;
        # 设置一个连接中并发HTTP/3请求流的最大数量
        http3_max_concurrent_streams 128;
        # 设置用于读取和写入QUIC流的缓冲区的大小
        http3_stream_buffer_size 64k;
        # 客户端连接ID的最大数量 可以存储在服务器上
        quic_active_connection_id_limit 2;
        # QUIC地址验证
        quic_retry off;
        # 0-RTT
        ssl_early_data off;
        # 通用分割卸载
        quic_gso off;

        # 设置各种令牌的主机密钥
        # quic_host_key <filename>;

        server_name r2wind.cn;

        # Quic或HTTP/3响应头,其中如果是
        add_header Alt-Svc 'h3=":443"; ma=86400';
        # add_header Alt-Svc 'quic=":443"; ma=86400, h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400, h3-30=":443"; ma=86400, h3-31=":443"; ma=86400, h3-32=":443"; ma=86400';
        # HSTS
        add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";

        location / {
            root /www/wwwroot/r2wind.cn; 
            index  index.html index.htm;
            }

        # 证书配置
        ssl_certificate /root/.acme.sh/smb.wiki/fullchain.cer; 
        ssl_certificate_key /root/.acme.sh/smb.wiki/smb.wiki.key;
        ssl_session_timeout 5m;
        # http3的SSL必须是TLSv1.3版本
        ssl_protocols TLSv1.2 TLSv1.3; 
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; 
        ssl_prefer_server_ciphers on;
    }
}





xquic_log   "pipe:rollback /home/admin/tengine/logs/tengine-xquic.log baknum=10 maxsize=1G interval=1d adjust=600" info;

http {

    ## add for xquic ####
    xquic_ssl_certificate        /etc/tengine/ssl/certificate.crt;
    xquic_ssl_certificate_key    /etc/tengine/ssl/certificate.key;
    xquic_ssl_session_ticket_key /etc/tengine/ssl/session_ticket.key;

    xquic_congestion_control bbr;
    xquic_socket_rcvbuf 5242880;
    xquic_socket_sndbuf 5242880;
    xquic_anti_amplification_limit 5;
    ## end for xquic ####

    server {
        listen 2443 xquic reuseport;
        ...
    }
}

国密配置

环境与工具准备

  • 在gmssl.com网站下载
  • 国密版wireshark(重要)
  • Tongsuo国密库(替换openssl)
  • Tengine(基于Tongsuo编译,替换nginx)
  • 国密版curl、wget

编译

准备Tengine源码包、Tongsuo源码包

# (非必要)Tongsuo编译二进制
./config no-devcryptoeng enable-ntls --prefix=/midware/tongsuo && make

# curl编译(非必要) 基于tongsuo二进制
./configure --prefix=/midware/curl --enable-warnging --enable--werror --with-openssl=/midware/tongsuo

# Tengine编译(必要) 基于tongsuo源码
./configure --prefix=/midware/tengine --add-module=modules/ngx_tongsuo_ntls \
    --with-openssl=../Tongsuo-8.3.2 \
    --with-openssl-opt='enable-ntls' \
    --with-http_ssl_module \
    --with-stream \
    --with-stream_ssl_module \
    --with-stream_sni \
    --with-http_sub_module

make && make install


    groupadd tengine
    useradd -g tengine -s /sbin/nologin tengine
    chown tengine:tengine /midware/tengine -R


    cat >/usr/lib/systemd/system/tengine.service <<EOF 
[Unit]
Description=tengine web server
Documentation=http://tengine.org/en/docs/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
User=tengine
Group=tengine
Type=forking
PIDFile=/midware/tengine/logs/nginx.pid
ExecStartPre=/usr/bin/rm -f /midware/tengine/logs/nginx.pid
ExecStartPre=/midware/tengine/sbin/nginx -t -c /midware/tengine/conf/nginx.conf
ExecStart=/midware/tengine/sbin/nginx -c /midware/tengine/conf/nginx.conf
ExecReload=/midware/tengine/sbin/nginx -s reload
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=process
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF

    systemctl daemon-reload
    systemctl start tengine

Tengine国密配置

目前需求是访问普通http端口, 再由网关或中间件做转发到国密的端口; 目前tengine实现方法是监听一个名为http端口8081, 转发到国密的对端端口7051, 信任CA证书 人行给出的加密套件是ECDHE_SM4_CBC_SM3(0xe011)、ECC_SM4_CBC_SM3(0xe013)、ECDHE_SM4_GCM_SM3(0xe051)、ECC_SM4_GCM_SM3(0xe053) Tongsuo的加密套件命名不一致, wireshark抓包显示的加密套件名称也不一致,只要后面的十六进制如(0xe051)一致即可,为ECC-SM2-SM4-CBC-SM3:ECC-SM2-SM4-GCM-SM3:ECDHE-SM2-SM4-CBC-SM3:ECDHE-SM2-SM4-GCM-SM3

# nginx.conf 配置日志格式和转发
    log_format             main '$remote_addr - $remote_user [$time_local] '
                                '"$request_method $scheme://$host$request_uri $server_protocol" '
                                '$status $upstream_status $ssl_protocol $ssl_cipher $body_bytes_sent "$http_referer" "$http_user_agent" '
                                '"$upstream_response_time $request_time" '
                                '$http_x_forwarded_for $upstream_addr $ssl_protocol';

    access_log             /midware/tengine/logs/access.log main;

    server {
        listen 8081;
        server_name localhost test.com;
        proxy_connect_timeout 10s;
        location / {
            proxy_enable_ntls on;
            proxy_ssl_ciphers "ECC-SM2-SM4-CBC-SM3:ECC-SM2-SM4-GCM-SM3:ECDHE-SM2-SM4-CBC-SM3:ECDHE-SM2-SM4-GCM-SM3";
            proxy_ssl_trusted_certificate     certs/ca.pem;
            proxy_pass https://xx.com:7051;
            # 人行的接口会返回一个指定链接,让客户端重新发起请求,这里把url替换为nginx的8081端口
            sub_filter "http://xx.com:7051" "http://localhost:8081";
            sub_filter_types *;
        }
    }

验证与测试

# 抓包测试即可
tcpdump -i any -w cert.out
# 用国密版wireshark打开cert.out
# 其中会由GMSSLv1协议的请求,再Server Hello的报文的Secure Sockets Layer的Handshake Protocol: Server Hello里面的Cipher Suite
# 如果使用了国密则会显示ECC_SM4_SM3(0xe013)等四个算法套件
# 如果需要测试国密客户端访问国密服务端,则需要使用国密版的curl或者wget等工具 类似下面请求即可,开启tlcp
/midware/curl/bin/curl -kv --capath /midware/tengine/conf/cert/ca.pem  --tlcp --ciphers "ECC-SM2-SM4-CBC-SM3:ECC-SM2-SM4-GCM-SM3:ECDHE-SM2-SM4-CBC-SM3:ECDHE-SM2-SM4-GCM-SM3:ECDHE-SM2-WITH-SM4-SM3" https://xx.com:7051/cerditreferencetest/index.html

番外:自己对外提供国密端口配置

# 需要配置签名的证书和密钥,加密的证书和密钥,国密证书分为签名和加密证书两部分
    server {
        listen 443 ssl;
        server_name 23.6.2.42;
        enable_ntls     on;

        ssl_certificate            certs/test_rsa.crt;
        ssl_certificate_key        certs/test_rsa.key;
        ssl_certificate            certs/test_ecc.crt;
        ssl_certificate_key        certs/test_ecc.key;

        ssl_sign_certificate            certs/SS.cert.pem;
        ssl_sign_certificate_key        certs/SS.key.pem;
        ssl_enc_certificate             certs/SE.cert.pem;
        ssl_enc_certificate_key         certs/SE.key.pem;

        ssl_ciphers "ECC-SM2-SM4-CBC-SM3:ECC-SM2-SM4-GCM-SM3:ECDHE-SM2-SM4-CBC-SM3:ECDHE-SM2-SM4-GCM-SM3";

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
        
        location / {
            return 200 "success";
        }
    }