Navigating FIPS Compliance for Go Applications: Libraries, Integration, and Security

Gil Adda
CyberArk Engineering
5 min readSep 11, 2023
Photo by Mick Haupt on Unsplash

Go (Golang) is a powerful and productive language for servers, web services, and tools, with notable projects like Docker and Kubernetes showcasing its capabilities. Despite Go’s standard cryptography library inability to meet FIPS 140–2 compliance, this post delves into the creation of FIPS 140–2-compliant applications on both Linux and Windows using Go so that you know how to best meet compliance, regardless of the operating system you are using.

Note: Readers should not use this article alone to determine the suitability of the information in relation to the FIPS 140–2 standard and compatibility of your program. CyberArk nor the author can accept responsibility for this.

Understanding FIPS Standards and Certification

First, a quick background on FIPS 140–2. The National Institute of Standards (NIST) created the Federal Information Processing Standard (140–2) with the goal of improving the security of computer and telecommunications systems in the government. The regulation sets a cryptographic-based security standard for systems and modules certified in four levels. A list of modules certified by the Cryptographic Module Validation Program (CMVP) can be found here.

Organizations such as the US government and the Department of Defense require the use of the FIPS 140–2 standard to ensure that the hardware and software they select meet specific security requirements. You can certify your program by running the CMVP certification or take the FIPS Inside approach. FIPS Inside references software that employs a FIPS-validated library such as OpenSSL, or BoringSSL to provide its cryptographic services for FIPS 140–2 readiness or compliance. In that case, you need to use a FIPS 140–2 certified library for cryptographic functionality. The list of Go libraries and how to use them will be discussed later.

FIPS 140–3 is the latest version and supersedes FIPS 140–2 for new submissions.

Utilizing FIPS 140–2 Certified Libraries in Go

In order for Go’s standard distribution cryptographic module to meet FIPS 140–2 compliance, certified external libraries are required. The table below describes several compliant integration options:

* In prior versions to 1.19, Google provided BoringCrypto support in a branch called dev.boringcrypto. In that case, you need to compile the Go compiler and tools from that branch.

** Microsoft made major modifications from version 1.21, which is described below.

Google Boring Crypto Integration

Google BoringCrypto module is a general-purpose cryptographic library that is FIPS 140–2 certified until September 21, 2026. From Go’s standard distribution version 1.19, there’s an integrated certified BoringCrypto version supporting Linux AMD64 and Arm binaries.

To compile a Go program for Linux with BoringCrypto, run the build command with an environment variable as displayed below:

GOEXPERIMENT=boringcrypto go build myprogram.go

To restrict all TLS configurations to FIPS-approved settings, import the fipsonly package anywhere in a program, as in:

import _ "crypto/tls/fipsonly"

OpenSSL

The OpenSSL FIPS library, approved by NIST, offers a C-language API for cryptographic functionalities. Versions for Windows and Linux are available, valid until September 21, 2026. This section explores integrating OpenSSL through various projects, including RedHat and Microsoft’s modified version of Go.

RedHat Modified Go with OpenSSL library

In 2019, RedHat introduced a solution for running Golang, incorporating a toolset that supports OpenSSL 1.0 and 1.1. In a 2022 update, another solution emerged, leveraging changes to BoringCrypto code within the dev.boringcrypto branch. This project now resides in the GitHub repository named “golang-fips”. It offers a modified version of the Go Language, patching cryptographic functions with bindings for OpenSSL 1.1.0, 1.1.1, and 3.x. This solution is designed for Linux OS and necessitates the use of environment variables to configure FIPS mode.

Microsoft’s Modified Go with OpenSSL library

Microsoft released a modified version of Go that can be used to build FIPS 140–2 compliant applications for both Linux and Windows. Go binaries can be downloaded here or can be built from the source.

On Linux, this modified version of Go uses OpenSSL based on golang-fips/openssl module in Go 1.21+ (go-crypto-openssl module in earlier versions). When configured correctly, OpenSSL can be executed in FIPS mode, making the OpenSSL package FIPS compliant. This project only supports multiple OpenSSL versions in Linux, namely 1.0.2, 1.1.0, 1.1.1, and 3.0.2. The OpenSSL-shared library libcrypto is loaded by your Go program at runtime.

Microsoft’s Modified Go with Windows CNG

Unlike the OpenSSL integration on Linux, on Windows, Microsoft-modified Go uses go-crypto-winnative which sets the Windows CNG library instead of the Go cryptographic standard library. Windows Crypto API Next generation is the long-term replacement for the Windows CryptoAPI. The Windows Cryptographic Primitives Library was FIPS 140–2, certified and valid until September 21, 2026. Windows 10 and Windows Server can be configured to run in a FIPS 140–2 approved mode of operation, commonly referred to as “FIPS mode”.

Up until the Microsoft-modified Go version 1.20, the modified crypto runtime defaults to the Go standard library crypto in case it cannot provide a FIPS-compliant implementation (e.g. when hashing a message using crypto/md5 hashes). It is the responsibility of the developer to verify the use of FIPS-compliant crypto primitives and workflows. However, from Go Version 1.21 there is a major update. The fallback to the Go standard crypto library is disabled by default. If a crypto backend is selected but isn’t supported, the build fails. To override it (not recommended) a new GOEXPERIMENT is defined, called allowcryptofallback.

An additional protection uses`requirefips` build tag which makes the program fail if the crypto backend FIPS mode isn’t enabled.

Another feature in version 1.21 is a new build setting for GOEXPERIMENT=systemcrypto that automatically selects the relevant FIPS-compliant backend. For Linux, it selects opensslcrypto and in Windows it sets cngcrypto. The value of GOEXPERIMENT can be set manually as well.

Runtime Checks of FIPS Mode to Match the Compilation

Since the program fails if the configuration doesn’t match the compilation, wouldn’t it be great if you could set the runtime to check whether or not it can run on FIPS mode?

Here’s how:

  • In Linux: Set the environment variable `GOFIPS=1` to enable or `GOFIPS=0` to disable or implicitly enable it by booting the Linux Kernel in FIPS mode. If the Linux Go runtime detects a FIPS preference, it configures OpenSSL during program initialization. This includes disabling FIPS mode if `GOFIPS=0`. If the configuration fails, program initialization panics.
  • In Windows: Set the environment variable `GOFIPS=1`. The runtime checks that the crypto library is set for FIPS. If not, the program will exit from version 1.21 and above. Don’t forget to set the OS to FIPS mode (instructions here).

Meeting FIPS 140–2 Compliance in Linux and Windows

Golang's latest versions by Google and Microsoft modifications have facilitated the ability to deliver FIPS-compliant programs for Windows and Linux. Using this, you’ll be able to deliver FIPS-compliant programs faster and easier than before with your Go program.

--

--

Gil Adda
CyberArk Engineering

System Architect at Cyberark. Technologies and Engineering of big things are amazing