Open aead opened 3 months ago
Related Issues and Documentation
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
cc @golang/security
Just use github.com/microsoft/go systemcrypto experiment with build tag to require FIPS. It produces binaries that will use openssl at runtime, with any FIPS provider available on any host OS, which all them provide (Ubuntu Pro FIPS, RHEL UBI, SuSe, Chainguard).
Unlike boringcrypto experiment, systemcrypto experiment correctly blocks unapproved usage; and prevents miss compilation by failing at build time and/or binary startup. Such that all of the above mentioned pitfalls are resolved.
Starting from trivial ones like forgetting to enable cgo (or turning it off by accident), to blocking md5, to more nuinanced caveats - like preventing silently falling back to uncertified gocrypto.
@xnox The point of issue is that the boringcrypto experiment has an "implicit" dependency on cgo which is not enforced.
Just use github.com/microsoft/go systemcrypto experiment with build tag to require FIPS.
Using an "unofficial" fork of the Go standard library is not a viable solution for everyone.
@xnox The point of issue is that the boringcrypto experiment has an "implicit" dependency on cgo which is not enforced.
Just use github.com/microsoft/go systemcrypto experiment with build tag to require FIPS.
Using an "unofficial" fork of the Go standard library is not a viable solution for everyone.
heh, and "official" fork officially said no support for boringcrypto experiment and no guarantees. Compared with support and responsiveness from multiple enterprise distributions and a tech giant that cares about FIPS on the other side.
Note that in microsoft/go fork, in addition to openssl and CNG backends the boringcrypto backend is also available, and improved upon. So even with microsoft/go you can continue to use boringcrypto if you so wish.
There is generated conflict file, that has init, that panics missbuilt binaries in boringcrypto mode. Specifically when all the conditions are not met. This resolves this issue.
That particular chunk of code can be vendored into any project, and you can self safe guard against this issue with a panic upon init, by checking the same set of tags.
@xnox you wrote:
Starting from trivial ones like forgetting to enable cgo (or turning it off by accident), to blocking md5, to more nuinanced caveats - like preventing silently falling back to uncertified gocrypto.
I've built a test app. using "github.com/microsoft/go systemcrypto experiment with build tag to require FIPS", and also added to it:
import (
"crypto/md5"
...
}
func myMD5() {
// Data to hash
data := "Hello, this is some data to hash using MD5"
// Create an MD5 hash
hash := md5.New()
hash.Write([]byte(data))
hashBytes := hash.Sum(nil)
// Convert the hash to a hexadecimal string for display
hashString := hex.EncodeToString(hashBytes)
// Print the MD5 hash
fmt.Printf("MD5 hash of '%s': %s\n", data, hashString)
}
func main() {
myMD5()
...
}
and it didn't block md5.
Here they say:
There is not yet any way to configure the crypto APIs to panic instead of falling back to standard Go crypto.
Are you sure about this? Or maybe, I'm missing something. TIA!
Discussions of third-party forks such as github.com/microsoft/go are off topic. This issue is about a safety limitation in the (not officially supported) Go+BoringCrypto mode (which is unlikely to see much investment due to #69536).
There is not yet any way to configure the crypto APIs to panic instead of falling back to standard Go crypto.
Are you sure about this? Or maybe, I'm missing something.
the blocking depends on the policy of the FIPS module at runtime, and fallbacks. For example, today you typically need openssl default library context to be loaded with openssl default & fips providers, and default query properties set to fips=yes, and the module activated and passing selftests. Then MD5 will be blocked, as per policy of the module you are using, meaning you need to use an up to date 140-3 module. It's not the toolchain that enforces policy, but the relevant runtime FIPS module. FIPS is not about what apis you call; but about whether or not a fips module is in play and what it returns.
All of the above is out of scope for this bug report - please consult with your security officer, and your FIPS policies at runtime. Or contact your FIPS module vendor (i.e. Ubuntu Pro FIPS, RHEL UBI Fips, Chainguard FIPS Images, Suse FIPS, etc).
Thanks @FiloSottile - closing this then. Hope the validation process is not too painful 🤞
To be clear I was saying that discussions of third-party forks are off topic, not the original issue about Go+BoringCrypto.
Reopening to keep track of this just in case we do decide to clean up Go+BoringCrypto (or to close once we drop it).
Go version
go version go1.22.5 linux/amd64
Output of
go env
in your module/workspace:What did you do?
The following Go program starts a simple HTTPS server on port
:4443
using a self-signed RSA certificate and writes a CPU profile tocpu.pprof
: https://go.dev/play/p/6DzPHSlU1r2Compile this program using the following
go build
commands on a linux/amd64 machine:GOEXPERIMENT=boringcrypto CGO_ENABLED=0 go build -o fips-test main.go
GOEXPERIMENT=boringcrypto CGO_ENABLED=1 go build -o fips-test main.go
What did you see happen?
Both commands produce a valid binary without any error. Inspecting both binaries with
rsc.io/goversion
results in:Looking at the
cpu.pprof
files also shows that the boringcrypto C implementation is only selected whenCGO_ENABLED=1
.Importing
crypto/tls/fipsonly
works in both cases and the Go TLS stack actually rejects TLS 1.3 connections (TLS 1.3 has to be disabled for boringcrypto). When obserbing the TLS stack behavior, it seems that the binary usesboringcrypto
whenCGO_ENABLED=0
even though it actually uses the standard library crypto implementations.What did you expect to see?
This seems like a "footgun" in the sense that people might try to build a binary that uses a FIPS 140-2 certified module to meet compliance requirements but accidentally have set
CGO_ENABLED=0
in their build environment.While it might seem obvious that
GOEXPERIMENT=boringcrypto
demandsCGO_ENABLED=1
, I was not able to find any documentation for this. Also there are blog posts not mentioning this in any way. For example: https://medium.com/cyberark-engineering/navigating-fips-compliance-for-go-applications-libraries-integration-and-security-42ac87eec40bI'm aware that building Go binaries with boringcrypto as crypto backend is not officially supported. However, requiring
CGO_ENABLED=1
does not seem to have any downside.