If you work with US government entities or corporations in regulated markets the subject of FIPS compliance may come up. FIPS 140-2 is a set of cryptographic standards that your application may need to adhere to.
It takes a lot to be FIPS verified or FIPS compliant (learn more), but for us the bottom line is that our app must use FIPS verified crypto libraries. This is a challenge with go, where the native crypto is not FIPS friendly.
There are no plans to change it either:
Openssl req -new -sha256 -key server.key -out server.csr openssl x509 -req -sha256 -in server.csr -signkey server.key -out server.crt -days 3650 ECDSA & RSA — FAQ Validate the elliptic curve parameters -check.
Go’s crypto is not FIPS 140 validated and I’m afraid that there is no possibility of that happening in the future either. I think Ian’s suggestion of using cgo to call out to an existing, certified library is probably your best bet. However, we would not be interested in patches to add hook points all over the Go library, so you would need to carry that work yourself.
- Aug 05, 2016 What next? Well, obviously this isn’t secure enough. I set out to familiarize myself with the Golang TLS configuration and the way these TLS certificates and keys are used. I ended up finding Creating Your Own SSL Certificate Authority (and Dumping Self Signed Certs) which was a major help. I was able to generate the keys necessary to test.
- Sep 04, 2018 Come, learn to implement mTLS using Golang and OpenSSL. Introduction TLS (Transport Layer Security) provides the necessary encryption for applications when communicating over a network. HTTPS (Hypertext Transfer Protocol Secure) is an extension of HTTP that leverages TLS for security.
- 回答 1 已采纳 First of all. I'm on thin ice here! I have a encrypted file that I get from php. I'm trying to decrypt this with golang. The php application uses a public RSA key to encrypt the key used to encrypt with aes-256-cbc.
- In an effort to do so I've already spoken with Filippo offline about upstreaming the OpenSSL port into the dev.boringcrypto branch such that both the original and the OpenSSL port continue to work (and obviously I stick around to maintain the patches and help with getting CI configured, etc).
Reimplementing crypto with cgo call outs doesn’t seem like a fun activity. Are we out of luck? Rewrite in Java? Luckily there are two options for us:
- BoringSSL based crypto.
- RedHat go toolchain.
Let’s discuss them.
BoringSSL is a fork of OpenSSL that is designed to meet Google’s needs.
Critically, it has a FIPS 140-2 verified version.
BoringSSL is used internally in google’s monorepo. Cloudflare is another prominent user.
dev.boringcrypto is a go repo branch. It is maintained alongside the mainline go (quote from its readme):
We have been working inside Google on a fork of Go that uses BoringCrypto (the core of BoringSSL) for various crypto primitives, in furtherance of some work related to FIPS 140-2. We have heard that some external users of Go would be interested in this code as well, so I intend to create a new branch dev.boringcrypto that will hold patches to make Go use BoringCrypto.
Unlike typical dev branches, we do not intend any eventual merge of this code into the master branch. Instead we intend to maintain in that branch the latest release plus BoringCrypto patches. In this sense it is a bit like dev.typealias holding go1.8+type alias patches.
This sounds good, but in an OSS fashion there are no guarantees:
To be clear, we are not making any statements or representations about the suitability of this code in relation to the FIPS 140-2 standard. Interested users will have to evaluate for themselves whether the code is useful for their own purposes.
The patches are kept up-to-date against minor version releases and master. List of branches.
Google maintains docker images with patched go toolchain, similar to
A Dockerfile that starts with FROM golang:1.8.3 can switch to FROMgoboring/golang:1.8.3b2 (see goboring/golang on Docker Hub) and shouldneed no other modifications.(…)
BoringCrypto is used for a given build only in limited circumstances:
- The build must be GOOS=linux, GOARCH=amd64.
- The build must have cgo enabled.
- The android build tag must not be specified.
- The cmd_go_bootstrap build tag must not be specified.
- The version string reported by runtime.Version does not indicate thatBoringCrypto was actually used for the build. For example, linux/386 andnon-cgo linux/amd64 binaries will report a version of go1.8.3b2 but not beusing BoringCrypto.
To check whether a given binary is using BoringCrypto, run
go tool nmon it and check that it has symbols named
The patched toolchain is a true drop-in replacement, no changes to the code are needed (maybe with an exception of filtering out unsupported ciphers, etc. but this is a configuration concern).
The foreign function interface between golang and c is not free. The library performs worse than the build-in crypto. See golang/go#21525.
In general there is about a 200ns overhead to calling intoBoringCrypto via cgo for a particular call. So for exampleaes.BenchmarkEncrypt (testing encryption of a single 16-byte block)went from 13ns to 209ns, or +1500%. That we can’t do much about excepthope that bulk operations call into cgo once instead of once per 16bytes.
Note that the benchmarks were done in 2017, so the things might’ve improved (but then vanilla tls/crypto improved as well). Also note the detailed benchmark results, not all ciphers performed as poorly as the highlight. Some where on the same level or faster. If you don’t care about every nanosecond of performance or your code is not on the critical path then this is good enough. Otherwise benchmark your usecase to see if the performance hit is acceptable.
I’ve created a simple echo server in go to show what changes are needed to switch to the
dev.boringcrypto. Check the diff between the “regular” (or “native”) crypto and the boring version: https://github.com/igor-kupczynski/fips-echo-server/compare/master...boringcrypto:
The boringssl based toolchain is basically a drop in replacement. All we need to do is:
There are some other changes in the branch, to add new option
-fipsMode, which resets the ciphersuite to a FIPS compliant one. You may want to do something else, like still allow user configured ciphers as long as they are a subset of FIPS compliant ones, etc. But these changes are UX improvements when running in FIPS mode. No “core” app changes required.
testssl reports this:
RedHat offers an alternative.
Golang Tls Client
We are excited to announce that we plan to ship go-toolset with a new feature that allows Go to bypass the standard library cryptographic routines and instead call into a FIPS 140-2 validated cryptographic library.
I think they leverage some of the
dev.boringcrypto patches internally:
This new feature builds on top of pre-existing upstream work (which instead calls into BoringSSL) …
The major differences seem to be:
- RedHat offers support contracts and FIPS mode for RHEL, so they are committed to supporting their FIPS complaint go toolchain.
- FIPS mode can be enabled at runtime.
- Older go version — 1.11 at the time of writing, they promise to upgrade to 1.12 in 2019.
dev.boringcryptois being kept up-to-date against master (but there are no guarantees it will be like that in the future).
The native go crypto is not FIPS compliant, nor it will be in a foreseeable future. Luckily, both Google and RedHat provide go toolchains backed by FIPS validated SSL libraries. We can leverage them to make our go app FIPS compliant.
Golang Openssl Smime
One of such specialized tools that can generate a TLS digital certificate and is very popular is called OpenSSL. OpenSSL can be found at: https://www.openssl.org/. OpenSSL is an open source commercial grade TLS toolkit that can be used to perform a variety of tasks; among them is to generate self-signed digital certificates. The OpenSSL organization by itself does not provide prebuilt binaries for the tool. However, there is a wiki page that lists third-party places where a binary can be downloaded for the tool. The wiki page can be found at: https://wiki.openssl.org/index.php/Binaries. Once you have the tool downloaded, here is an example of how to make use of it to generate a digital certificate in addition to its private key: