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:
__goboringcrypto_
? In other words, does it confirm that my app uses boringcrypto instead of the native golang crypto?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:
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.
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!