Apache APISIX 玩轉 Tongsuo 國密外掛

Apache_APISIX發表於2022-12-14

本文透過解讀國密的相關內容與標準,呈現了當下國內技術環境中對於國密功能支援的現狀。並從 API 閘道器 Apache APISIX 的角度,帶來有關國密的探索與功能呈現。

作者:羅澤軒,Apache APISIX PMC

什麼是國密

顧名思義,國密就是國產化的密碼演算法。在我們日常開發過程中會接觸到各種各樣的密碼演算法,如 RSA、SHA256 等等。為了達到更高的安全等級,許多大公司和國家會制定自己的密碼演算法。國密就是這樣一組由中國國家密碼管理局制定的密碼演算法。在國際形勢越發複雜多變的今天,密碼演算法的國產化替代,在一些領域已經成為了一股勢不可擋的潮流。

國密的官方名稱為國家商用密碼,簡稱商密,拼音縮寫是 SM。這也是國密標準中 SM2/3/4/7/9 等演算法名稱的來源。國密演算法的命名方式非常簡單直接,就像“綿陽九所”、“二機部”一樣,都是“分類+序號”的組合。其中 SM1 和 SM4 是對稱演算法,對標 AES;SM2 是非對稱演算法,對標 RSA、ECDSA;SM3 是摘要演算法,對標 MD5;等等。由於本文並非涉及到國密的實現細節,所以不會講得非常細,也就科普下國密演算法的分類。

在基礎的國密演算法之上,我們可以構造一個國密的垂直生態,比如實現國密演算法的硬體、提供國密支援的密碼庫、加入國密流程的 TLS 握手協議等等。正如安全需要縱深防禦一樣,基於國密的信任鏈也需要有全軟體棧上的支援。

因此,當我們談論國密支援時,並不僅僅單獨指可以用某一種國密演算法進行加解密,而是指嵌合入國密的生態,支援某種國密的應用場景。

國密的應用場景

作為國家密碼管理局制定的密碼演算法,國密廣泛應用於電子政務(包括國家政務通、警務通等重要領域)、信創及金融業的各個應用領域。

  • 政府和金融的身份認證終端。依照現行有關規定,許多涉及政府和金融的身份認證終端(諸如 USBKey、智慧 IC 卡、銀行卡終端等)都需要提供對國密的支援。
  • 國產開源作業系統。許多主打國產替代的開源作業系統,會提供基於國密的安全加固功能。比如龍蜥作業系統 (Anolis OS) 提到自己實現了全棧國密能力;OpenEuler 也在做國密相關的一些功能,比如基於國密數字證照擴充套件了 EFI 的數字簽名。
  • 信創產品。還有許多做信創生意的廠商,圍繞國密推出符合相關標準的產品。例如支援使用國密演算法做數字簽名的 PDF 工具、支援國密接入標準的音影片軟體等等。
  • 基於國密 TLS 協議的生態。也是在日常開發中接觸得最多的。譬如各種國產 CA 廠商、支援了國密TLS的許許多多密碼庫和瀏覽器,以及國密接入的VPN和閘道器等等。

    APISIX 對國密的探索與支援

Apache APISIX 是一個動態、實時、高效能的 API 閘道器,提供負載均衡、動態上游、灰度釋出、精細化路由、限流限速、服務降級、服務熔斷、身份認證、可觀測性等數百項功能。作為一個發跡於國內環境的 API 閘道器,APISIX 自然需要考慮下如何接入國密的生態圈。

由於國密更多地用在國內環境中,尚未被 OpenSSL 等國際主流專案所完全接納。如果要使用國密的功能,就涉及到更換 APISIX 預設的 OpenSSL 庫為其他 SSL 庫。

為此,我們考察了以下的專案:

  • GMSSL:北京大學開源的專案。原版基於 OpenSSL 1.0.2 修改而來。新的 GMSSL 3.0 基本上是重新開發,跟 OpenSSL 的目錄結構差別很大。
  • gm-BoringSSL:個人開源專案,在 BoringSSL 上增加國密支援。已有兩年未改動。
  • TaSSL:北京江南天安科技有限公司開源的專案。基於 OpenSSL 1.1.1 修改而來。
  • Tongsuo:螞蟻集團開源的專案。基於 OpenSSL 3.0 修改而來,專案前身是 BabaSSL,現已 改名為銅鎖/Tongsuo
    由於 GMSSL 3.0 並不基於 OpenSSL,即使能保證 API 相容,也沒辦法確保能 100% 替換現有 OpenSSL 的行為,所以被首先排除。其次 gm-BoringSSL 疏於維護,也被排除。

在 TaSSL 和 Tongsuo 之中,我傾向於選擇 Tongsuo[1]。因為 Tongsuo 在標準上擁有更強的話語權,比如 RFC 8998(TLS 1.3 中支援 SM 套件)就是由 Tongsuo 的開發者制定的。TaSSL 則是每出一個版本,就公佈一個新的倉庫。比如前一個 版本[2],感覺不太靠譜。

對於選擇 Tongsuo,我個人存在一個顧慮,就是他目前基於 OpenSSL 3.0 的版本還沒有釋出正式的 Release 版本(第一個版本預計在 2023 年 2 月釋出)。由於 Tongsuo 當前還沒有一個固定的版本,因此社群決定先把國密相關的功能獨立出來,以外掛形式存在,有相關需求時可單獨啟用。

目前已在外掛層面實現了服務端一側國密雙證照的支援,感興趣的讀者可以在官網檢視 gm 外掛介紹文件 外掛介紹文件[3],自行完成 APISIX 的編譯和對應外掛的安裝配置工作。當然,如果想即刻預覽該外掛的使用過程,也可以直接參考下文內容。

快速參考:APISIX 國密外掛的使用 

啟用外掛

外掛要求 Apache APISIX 執行在編譯了 Tongsuo 的 APISIX-Base 上

首先需要安裝 Tongsuo (此處我們選擇編譯出 Tongsuo 的動態連結庫):

# TODO: use a fixed release once they have created one.
# See https://github.com/Tongsuo-Project/Tongsuo/issues/318
git clone https://github.com/api7/tongsuo --depth 1
pushd tongsuo
./config shared enable-ntls -g --prefix=/usr/local/tongsuo
make -j2
sudo make install_sw

其次需要構建 APISIX-Base,讓它使用 Tongsuo 作為 SSL 庫:

export OR_PREFIX=/usr/local/openresty
export openssl_prefix=/usr/local/tongsuo
export zlib_prefix=$OR_PREFIX/zlib
export pcre_prefix=$OR_PREFIX/pcre

export cc_opt="-DNGX_LUA_ABORT_AT_PANIC -I${zlib_prefix}/include -I${pcre_prefix}/include -I${openssl_prefix}/include"
export ld_opt="-L${zlib_prefix}/lib -L${pcre_prefix}/lib -L${openssl_prefix}/lib64 -Wl,-rpath,${zlib_prefix}/lib:${pcre_prefix}/lib:${openssl_prefix}/lib64"
./build-apisix-base.sh

該外掛預設是禁用狀態,你需要將其新增到配置檔案./conf/config.yaml 中才可以啟用它:

plugins:
  - ...
  - gm

由於 APISIX 的預設 cipher 中不包含國密 cipher,所以我們還需要在配置檔案 ./conf/config.yaml 中設定 cipher:

apisix:
  ...
  ssl:
    ...
    # 可按實際情況調整。錯誤的 cipher 會導致 “no shared cipher” 或 “no ciphers available” 報錯。
    ssl_ciphers: HIGH:!aNULL:!MD5

配置完成後,重新載入 APISIX,此時 APISIX 將會啟用國密相關的邏輯。

測試外掛

在測試外掛之前,需要準備好國密雙證照。Tongsuo 提供了生成 【SM2 雙證照】 的 教程[4]。

在下面的例子中,我們將用到如下的證照:

# 客戶端加密證照和金鑰
t/certs/client_enc.crt
t/certs/client_enc.key

# 客戶端簽名證照和金鑰
t/certs/client_sign.crt
t/certs/client_sign.key

# CA 和中間 CA 打包在一起的檔案,用於設定受信任的 CA
t/certs/gm_ca.crt

# 服務端加密證照和金鑰
t/certs/server_enc.crt
t/certs/server_enc.key

# 服務端簽名證照和金鑰
t/certs/server_sign.crt
t/certs/server_sign.key

此外,還需要準備 Tongsuo 命令列工具。

./config enable-ntls -static
make -j2
# 生成的命令列工具在 apps 目錄下
mv apps/openssl ..

你也可以採用非靜態編譯的方式,不過就需要根據具體環境,自己解決動態連結庫的路徑問題了。以下示例展示瞭如何在指定域名中啟用 gm 外掛。
要在指定域名中啟用 gm 外掛的功能,需要先建立對應的 SSL 物件:

#!/usr/bin/env python
# coding: utf-8

import sys
# sudo pip install requests
import requests

if len(sys.argv) <= 3:
    print("bad argument")
    sys.exit(1)
with open(sys.argv[1]) as f:
    enc_cert = f.read()
with open(sys.argv[2]) as f:
    enc_key = f.read()
with open(sys.argv[3]) as f:
    sign_cert = f.read()
with open(sys.argv[4]) as f:
    sign_key = f.read()
api_key = "edd1c9f034335f136f87ad84b625c8f1"
resp = requests.put("http://127.0.0.1:9180/apisix/admin/ssls/1", json={
    "cert": enc_cert,
    "key": enc_key,
    "certs": [sign_cert],
    "keys": [sign_key],
    "gm": True,
    "snis": ["localhost"],
}, headers={
    "X-API-KEY": api_key,
})
print(resp.status_code)
print(resp.text)

然後將上面的指令碼儲存為 ./create_gm_ssl.py,執行以下命令:

./create_gm_ssl.py t/certs/server_enc.crt  t/certs/server_enc.key t/certs/server_sign.crt t/certs/server_sign.key

輸出結果如下:

200
{"key":"\/apisix\/ssls\/1","value":{"keys":["Yn...

完成上述準備後,可以使用如下命令測試外掛是否啟用成功:

./openssl s_client -connect localhost:9443 -servername localhost -cipher ECDHE-SM2-WITH-SM4-SM3 -enable_ntls -ntls -verifyCAfile t/certs/gm_ca.crt -sign_cert t/certs/client_sign.crt -sign_key t/certs/client_sign.key -enc_cert t/certs/client_enc.crt -enc_key t/certs/client_enc.key

其中,./openssl 是上文提到的 Tongsuo 命令列工具,9443 是 APISIX 預設的 HTTPS 埠。
如果一切正常,可以看到連線已經建立了起來,並輸出如下資訊:

...
New, NTLSv1.1, Cipher is ECDHE-SM2-SM4-CBC-SM3
...

禁用外掛

如果不再使用此外掛,可將 gm 外掛從 ./conf/config.yaml 配置檔案中移除,然後重啟 APISIX 或者透過外掛熱載入的介面觸發外掛的解除安裝。

相關連結 

如果你對該功能或者外掛感興趣,歡迎在隨時在社群進行交流。

[1] https://github.com/Tongsuo-Project/Tongsuo

[2] https://github.com/jntass/TASSL-1.1.1k

[3] https://apisix.apache.org/zh/docs/apisix/next/plugins/gm/

[4] https://www.yuque.com/tsdoc/ts/sulazb

相關文章