英文:
How can I check whether my golang app uses boringcrypto instead of the native golang crypto?
问题
上下文:我正在阅读关于使我的 Golang 应用程序符合 FIPS 标准的多篇文章(换句话说,让我的应用程序使用 boringcrypto 而不是原生的 Golang 加密):
- https://kupczynski.info/posts/fips-golang/
- https://developers.redhat.com/articles/2022/05/31/your-go-application-fips-compliant#
简而言之,它们都建议运行以下命令:
# 构建二进制文件并确保它使用 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。
基于此,我有两个问题:
- 即使没有与
__goboringcrypto_
匹配的内容,我的输出在语义上是否等效?换句话说,它是否确认我的应用程序使用的是 boringcrypto 而不是原生的 Golang 加密? - 我正在搜索其他关于 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。
更新:
-
我找到了另一篇文章,它暗示即使对于 golang 版本 1.19,仍然需要
CGO_ENABLED=1
。 -
前一项中引用的文章指向了
goversion
:
> 另外,您可以使用程序 rsc.io/goversion。当使用 -crypto 标志调用时,它将报告给定二进制文件使用的加密实现。
它有这个有趣的PR,暗示 _Cfunc__goboringcrypto_
等同于 crypto/internal/boring/sig.BoringCrypto
:
还请参阅 goversion/version/read.go
文件:
也就是说,我的输出中有 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):
- https://kupczynski.info/posts/fips-golang/
- https://developers.redhat.com/articles/2022/05/31/your-go-application-fips-compliant#
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:
- 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? - I was searching for other articles about FIPS compliance and some of them do mention using
CGO_ENABLED=1
(however I'm usingCGO_ENABLED=0
). Is it still a requirement when using1.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:
-
I found another article that implies having
CGO_ENABLED=1
is necessary still even for golang version 1.19. -
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
:
also see goversion/version/read.go
file:
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上构建这个项目,如果你尝试从其他操作系统进行交叉编译,除非你安装了正确的工具链和适当的环境变量(如CC
、CXX
、LD_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
, ...
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论