How can I check whether my golang app uses boringcrypto instead of the native golang crypto?

huangapple go评论145阅读模式
英文:

How can I check whether my golang app uses boringcrypto instead of the native golang crypto?

问题

上下文:我正在阅读关于使我的 Golang 应用程序符合 FIPS 标准的多篇文章(换句话说,让我的应用程序使用 boringcrypto 而不是原生的 Golang 加密):

简而言之,它们都建议运行以下命令:

# 构建二进制文件并确保它使用 boringcrypto 而不是原生的 Golang 加密
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_ 匹配的次数为 0,但是有 crypto/internal/boring

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

> 包 boring 提供对 BoringCrypto 实现函数的访问。检查常量 Enabled 可以了解 BoringCrypto 是否可用。如果 BoringCrypto 不可用,此包中的函数都会引发 panic。

基于此,我有两个问题:

  1. 即使没有与 __goboringcrypto_ 匹配的内容,我的输出在语义上是否等效?换句话说,它是否确认我的应用程序使用的是 boringcrypto 而不是原生的 Golang 加密?
  2. 我正在搜索其他关于 FIPS 合规性的文章,其中一些文章提到使用 CGO_ENABLED=1(但我正在使用 CGO_ENABLED=0)。在使用 golang 的 1.20.1 版本时,这仍然是一个要求吗?

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

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

另外,这篇文章说:

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

并且根本没有提到 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

How can I check whether my golang app uses boringcrypto instead of the native golang crypto?

还请参阅 goversion/version/read.go 文件

How can I check whether my golang app uses boringcrypto instead of the native golang crypto?
How can I check whether my golang app uses boringcrypto instead of the native golang crypto?

也就是说,我的输出中有 crypto/internal/boring/sig.StandardCrypto 而不是 crypto/internal/boring/sig.BoringCrypto

我的结论

总之,如果一个应用程序的输出中包含以下任何内容:

  • _Cfunc__goboringcrypto_
  • crypto/internal/boring/sig.BoringCrypto

那么它意味着应用程序使用的是 boringcrypto;如果输出中有

  • crypto/internal/boring/sig.StandardCrypto

那么它意味着应用程序使用的是原生的 Golang 加密。

英文:

Context: I was reading multiple articles about making my golang app FIPS compliant (in other words, making my app use boringcrypto instead of the native golang crypto):

In short, they both say to run

# 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

and then expect the following output:

  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

that would contain _goboringcrypto_ (which would mean the app uses boringcrypto instead of the native golang crypto) or an empty output (which implies the app uses the native golang crypto instead of boringcrypto).

However my app's output when adding GOEXPERIMENT=boringcrypto is:

➜  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

which has 0 matches with _goboringcrypto_ but there's crypto/internal/boring instead.

When I opened crypto/internal/boring's docs I could see:

> Package boring provides access to BoringCrypto implementation functions. Check the constant Enabled to find out whether BoringCrypto is available. If BoringCrypto is not available, the functions in this package all panic.

Based on that, I've got 2 quick questions:

  1. Is my output semantically equivalent even though there's no matches for __goboringcrypto_? In other words, does it confirm that my app uses boringcrypto instead of the native golang crypto?
  2. I was searching for other articles about FIPS compliance and some of them do mention using CGO_ENABLED=1 (however I'm using CGO_ENABLED=0). Is it still a requirement when using 1.20.1 version of golang?

> Go 1.19 and higher:
> Starting with Go 1.19, you can simply add [BUILD_GOEXPERIMENT=boringcrypto][18] and some related arguments to enable integrating BoringCrypto for standard Go.

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

That said, this article says

> Since go 1.19 ... Pass GOEXPERIMENT=boringcrypto to the go tool during build time. As simple as that.

and there's no mention of CGO_ENABLED flag at all.

and I can only see the mention of cgo in the section for go 1.18 and earlier:

> go 1.18 and earlier
> The build must have cgo enabled.

Updates:

  1. I found another article that implies having CGO_ENABLED=1 is necessary still even for golang version 1.19.

  2. The article referenced in the previous item, points to goversion:

> Also, you can use the program rsc.io/goversion. It will report the crypto implementation used by a given binary when invoked with the -crypto flag.

that has this interesting PR that implies _Cfunc__goboringcrypto_ is equivalent to crypto/internal/boring/sig.BoringCrypto:

How can I check whether my golang app uses boringcrypto instead of the native golang crypto?

also see goversion/version/read.go file:

How can I check whether my golang app uses boringcrypto instead of the native golang crypto?
How can I check whether my golang app uses boringcrypto instead of the native golang crypto?

That said, my output has crypto/internal/boring/sig.StandardCrypto and not crypto/internal/boring/sig.BoringCrypto.

My conclusions:

To sum up, it looks like if an app has any of

  • _Cfunc__goboringcrypto_
  • crypto/internal/boring/sig.BoringCrypto

in its output for go tool nm command it means that an app uses boringcrypto and if there's

  • crypto/internal/boring/sig.StandardCrypto

in its output it means that an app uses native golang crypto.

答案1

得分: 3

总的来说,

如果一个应用程序的go tool nm命令的输出中包含以下任何一项:

  • _Cfunc__goboringcrypto_
  • crypto/internal/boring/sig.BoringCrypto

那么这个应用程序使用了boringcrypto。如果输出中包含以下项:

  • crypto/internal/boring/sig.StandardCrypto

那么这个应用程序使用的是本地的Go语言加密库。

具体回答两个问题:

> 即使没有匹配到__goboringcrypto_,我的输出在语义上是否等效?换句话说,这是否确认了我的应用程序使用的是boringcrypto而不是本地的Go语言加密库?

不等效,因为它包含的是crypto/internal/boring/sig.StandardCrypto,而不是_Cfunc__goboringcrypto_crypto/internal/boring/sig.BoringCrypto

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

是的

感谢大家的帮助!

英文:

Overall,

If an app has any of

  • _Cfunc__goboringcrypto_

  • crypto/internal/boring/sig.BoringCrypto

in its output for go tool nm command it means that an app uses boringcrypto and if there's

  • crypto/internal/boring/sig.StandardCrypto

in its output it means that an app uses native golang crypto.

And to answer 2 questions specifically,

> Is my output semantically equivalent even though there's no matches for _goboringcrypto? In other words, does it confirm that my app uses boringcrypto instead of the native golang crypto?

It isn't, since it contains crypto/internal/boring/sig.StandardCrypto instead of _Cfunc__goboringcrypto_ / crypto/internal/boring/sig.BoringCrypto.

> I was searching for other articles about FIPS compliance and some of them do mention using CGO_ENABLED=1 (however I'm using CGO_ENABLED=0). Is it still a requirement when using 1.20.1 version of golang?

It is.

Thanks everyone for the help!

答案2

得分: 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等),否则无法工作。

英文:

As I mentioned in PR#21-comment goversion works but you can just use 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

One thing to take into account is that you can only build this on Linux, if you try to cross-compile from another OS it won't work, unless you have the right toolchain installed and proper environment variables like CC, CXX, LD_LIBRARY_PATH, ...

huangapple
  • 本文由 发表于 2023年3月5日 03:30:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/75638176.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定