我该如何检查我的 Golang 应用程序是否使用了 BoringCrypto 而不是本地的 Golang 加密?

9

背景:我正在阅读多篇关于使我的golang应用程序符合FIPS要求(换句话说,让我的应用程序使用boringcrypto而不是本地的golang加密)的文章:

简而言之,它们都表示要运行。
# Build a binary and assert that it uses boringcrypto instead of the native golang crypto
RUN GOEXPERIMENT=boringcrypto go build . && \
    go tool nm fips-echo-server > tags.txt && \
    grep '_Cfunc__goboringcrypto_' tags.txt 1> /dev/null

然后期望得到以下输出:

  e70fa0 T _cgo_d3bdb93f8e25_Cfunc__goboringcrypto_AES_cbc_encrypt
  e70fc0 T _cgo_d3bdb93f8e25_Cfunc__goboringcrypto_AES_ctr128_encrypt
  e70ff0 T _cgo_d3bdb93f8e25_Cfunc__goboringcrypto_AES_decrypt
  e71000 T _cgo_d3bdb93f8e25_Cfunc__goboringcrypto_AES_encrypt
  e71010 T _cgo_d3bdb93f8e25_Cfunc__goboringcrypto_AES_set_decrypt_key
  e71050 T _cgo_d3bdb93f8e25_Cfunc__goboringcrypto_AES_set_encrypt_key
  e71200 T _cgo_d3bdb93f8e25_Cfunc__goboringcrypto_BN_bn2le_padded
  e71240 T _cgo_d3bdb93f8e25_Cfunc__goboringcrypto_BN_free
  e71250 T _cgo_d3bdb93f8e25_Cfunc__goboringcrypto_BN_le2bn
  e71300 T _cgo_d3bdb93f8e25_Cfunc__goboringcrypto_BN_new

这段代码将包含_goboringcrypto_(这意味着该应用程序使用boringcrypto而不是本地的golang加密),或者为空输出(这意味着该应用程序使用本地的golang加密而不是boringcrypto)。

然而,当我在添加GOEXPERIMENT=boringcrypto时,我的应用程序输出为:

➜  GOEXPERIMENT=boringcrypto CGO_ENABLED=0 go build -o ./bin/app
➜  go tool nm bin/dapp | grep -i boring | cat 
 11230a0 T crypto/internal/boring.(*PrivateKeyECDH).PublicKey
 1123060 T crypto/internal/boring.(*PublicKeyECDH).Bytes
 243fba0 D crypto/internal/boring..inittask
 243eda0 D crypto/internal/boring/bbig..inittask
 1060bc0 T crypto/internal/boring/bcache.registerCache
 24efe14 B crypto/internal/boring/fipstls.required
 1123040 T crypto/internal/boring/sig.StandardCrypto.abi0
 1219c00 T crypto/x509.boringAllowCert
 24bfae0 B runtime.boringCaches
➜  go version bin/app                                                     
bin/app: go1.20.1 X:boringcrypto

这个与 _goboringcrypto_ 没有匹配,但是有 crypto/internal/boring

当我打开 crypto/internal/boring文档 时,我可以看到:

包 boring 提供了对 BoringCrypto 实现函数的访问。检查常量 Enabled 可以找出 BoringCrypto 是否可用。如果 BoringCrypto 不可用,则此包中的所有函数都会 panic。

基于此,我有两个快速问题:

  1. 即使没有与__goboringcrypto_完全匹配,我的输出是否在语义上等价?换句话说,它是否确认我的应用程序使用了boringcrypto而不是本机的golang加密库?
  2. 我正在寻找有关FIPS合规性的其他文章,其中一些文章mention使用CGO_ENABLED=1(但我正在使用CGO_ENABLED=0)。当使用golang的1.20.1版本时,这仍然是一个要求吗?

Go 1.19及更高版本: 从Go 1.19开始,您只需添加 [BUILD_GOEXPERIMENT=boringcrypto][18] 和一些相关参数以启用将BoringCrypto集成到标准Go中。

make container \
  BUILD_GOEXPERIMENT=boringcrypto \
  BUILD_CGO_ENABLED=1 \
  BUILD_EXTRA_GO_LDFLAGS="-linkmode=external -extldflags=-static"

话虽如此,本文提到:

自从go 1.19版本以来...在构建时通过GOEXPERIMENT=boringcrypto传递给go工具。就这么简单。

并且根本没有提到CGO_ENABLED标志。

我只能在go 1.18及更早版本的部分中看到cgo的提及:

go 1.18及更早版本必须启用cgo。

更新内容:

  1. 我找到了另一篇文章,暗示即使对于golang 1.19版本,仍然需要设置CGO_ENABLED=1

  2. 前一项引用的文章指向goversion

此外,您可以使用程序 rsc.io/goversion。当使用 -crypto 标志调用时,它将报告给定二进制文件使用的加密实现。
这个 PR 很有趣,它意味着 _Cfunc__goboringcrypto_ 等同于 crypto/internal/boring/sig.BoringCrypto

enter image description here

还可以查看 goversion/version/read.go file

enter image description here enter image description here

话虽如此,我的输出显示的是 crypto/internal/boring/sig.StandardCrypto 而不是 crypto/internal/boring/sig.BoringCrypto

我的结论:

总结起来,看起来如果一个应用程序有任何一个

  • _Cfunc__goboringcrypto_
  • crypto/internal/boring/sig.BoringCrypto
在其对于go tool nm命令的输出中,它表示一个应用程序使用了boringcrypto,如果存在的话。
  • crypto/internal/boring/sig.StandardCrypto

在输出中表示应用程序使用本地的 Golang 加密。


由于对这个问题进行了许多编辑,部分回答了原始问题,因此将编辑迁移为下面的答案可能是有意义的。 - colm.anseo
请在golang-nuts邮件列表上询问有关低级编译器和stdlib内部的问题。 - Volker
1
我认为你在“更新”部分已经回答了自己的问题。也许值得将其迁移为答案?据我所知,cgo是必需的,因为boringssl是一个基于C的库。如果没有cgo,程序就无法调用它。 - Igor Kupczyński
2个回答

4

总的来说,

如果一个应用程序包含以下任何一项功能:

  • _Cfunc__goboringcrypto_

  • crypto/internal/boring/sig.BoringCrypto

go tool nm命令的输出中,它表示应用程序使用boringcrypto,如果存在的话。

  • crypto/internal/boring/sig.StandardCrypto

在其输出中,它意味着应用程序使用本机golang加密

为了具体回答2个问题,

即使没有匹配项_goboringcrypto,我的输出在语义上是否等效?换句话说,它是否确认我的应用程序使用的是boringcrypto而不是本机golang加密?

它不是,因为它包含crypto/internal/boring/sig.StandardCrypto而不是_Cfunc__goboringcrypto_ / crypto/internal/boring/sig.BoringCrypto

我正在搜索其他关于FIPS合规性的文章,其中一些提到使用CGO_ENABLED = 1(但我正在使用CGO_ENABLED = 0)。在使用1.20.1版的Golang时,这仍然是要求吗?

是的。

感谢大家的帮助!


0

正如我在PR#21-comment中提到的,goversion可以工作,但你也可以使用go tool nm

$ go tool nm main  | grep -E 'sig.FIPSOnly|sig.BoringCrypto|sig.StandardCrypto'
  52ea60 t crypto/internal/boring/sig.StandardCrypto.abi0
$ go tool nm main.fips | grep -E 'sig.FIPSOnly|sig.BoringCrypto|sig.StandardCrypto'
  532860 t crypto/internal/boring/sig.BoringCrypto.abi0
  532880 t crypto/internal/boring/sig.FIPSOnly.abi0

需要注意的一点是,只有在Linux上才能构建此程序。如果您尝试从其他操作系统进行交叉编译,则无法正常工作,除非您安装了正确的工具链和适当的环境变量,例如CCCXXLD_LIBRARY_PATH等。

谢谢,我们正在考虑使用 https://github.com/goreleaser/goreleaser-cross。 - Kostya Linou

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接