├── .ci └── Dockerfile ├── .github └── workflows │ ├── build-image.yml │ ├── gating.yml │ └── test-pr.yml ├── .gitmodules ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── config └── versions.json ├── patches ├── 000-fips.patch ├── 001-fix-linkage.patch └── 002-fix-std-crypto.patch └── scripts ├── configure-crypto-tests.sh ├── crypto-test.sh ├── full-initialize-repo.sh ├── setup-go-submodule.sh └── versions.go /.ci/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM fedora:35 2 | 3 | MAINTAINER Daiki Ueno 4 | 5 | RUN dnf -y update && \ 6 | dnf -y install 'dnf-command(builddep)' && \ 7 | dnf -y builddep golang && \ 8 | dnf -y install gcc-go openssl-devel && \ 9 | dnf clean all 10 | -------------------------------------------------------------------------------- /.github/workflows/build-image.yml: -------------------------------------------------------------------------------- 1 | name: Create and publish a Docker image 2 | 3 | on: 4 | workflow_dispatch 5 | 6 | env: 7 | REGISTRY: ghcr.io 8 | IMAGE_NAME: ${{ github.repository }} 9 | 10 | jobs: 11 | build: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v2 18 | 19 | - name: Log in to the Container registry 20 | uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 21 | with: 22 | registry: ${{ env.REGISTRY }} 23 | username: ${{ github.actor }} 24 | password: ${{ secrets.GITHUB_TOKEN }} 25 | 26 | - name: Extract metadata (tags, labels) for Docker 27 | id: meta 28 | uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 29 | with: 30 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} 31 | 32 | - name: Build and push Docker image 33 | uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc 34 | with: 35 | context: . 36 | file: .ci/Dockerfile 37 | push: true 38 | tags: ${{ steps.meta.outputs.tags }} 39 | labels: ${{ steps.meta.outputs.labels }} 40 | -------------------------------------------------------------------------------- /.github/workflows/gating.yml: -------------------------------------------------------------------------------- 1 | name: "Test Pull Request" 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - 'main' 7 | - 'go1.*-fips-release' 8 | - 'go1.*-openssl-fips' 9 | 10 | # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions 11 | permissions: 12 | actions: none 13 | checks: read 14 | contents: none 15 | deployments: none 16 | id-token: none 17 | issues: read 18 | discussions: read 19 | packages: none 20 | pages: none 21 | pull-requests: read 22 | repository-projects: none 23 | security-events: none 24 | statuses: none 25 | 26 | jobs: 27 | test_pr: 28 | # Look up the images for each selected compose 29 | name: "Test Pull Request" 30 | uses: golang-fips/release/.github/workflows/test-ubi-centos.yml@main 31 | with: 32 | go_fips_ref: ${{ github.event.pull_request.head.sha }} 33 | composes: "ubi8,ubi9,ubi10,c9s,c10s" 34 | -------------------------------------------------------------------------------- /.github/workflows/test-pr.yml: -------------------------------------------------------------------------------- 1 | name: "Test Go" 2 | 3 | on: 4 | issue_comment: 5 | types: [created] 6 | # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions 7 | permissions: 8 | actions: none 9 | checks: read 10 | contents: none 11 | deployments: none 12 | id-token: none 13 | issues: read 14 | discussions: read 15 | packages: none 16 | pages: none 17 | pull-requests: read 18 | repository-projects: none 19 | security-events: none 20 | statuses: none 21 | 22 | jobs: 23 | ack: 24 | name: "Check if the comment is valid" 25 | runs-on: ubuntu-latest 26 | if: | 27 | github.event.issue.pull_request 28 | && contains(github.event.comment.body, '/test') 29 | && contains(fromJson('["OWNER", "MEMBER"]'), github.event.comment.author_association) 30 | outputs: 31 | composes: ${{ steps.set-compose.outputs.composes }} 32 | steps: 33 | - name: "Set the targets" 34 | id: set-compose 35 | shell: python 36 | env: 37 | COMMENT: ${{ github.event.comment.body }} 38 | run: | 39 | import os 40 | import re 41 | import argparse 42 | 43 | class ParseCompose(argparse.Action): 44 | def __call__(self, parser, namespace, values, option_string=None): 45 | setattr(namespace, self.dest, list()) 46 | for v in values: 47 | getattr(namespace, self.dest).append(composes[v]) 48 | 49 | 50 | composes = { 51 | 'rhel7': 'registry.access.redhat.com/ubi7/go-toolset:latest', 52 | 'rhel8': 'registry.access.redhat.com/ubi8/go-toolset:latest', 53 | 'rhel9': 'registry.access.redhat.com/ubi9/go-toolset:latest' 54 | } 55 | 56 | parser = argparse.ArgumentParser(prog="ack") 57 | 58 | parser.add_argument('-o', '--os', choices=composes, nargs='+', action=ParseCompose, default=list(composes.values())) 59 | 60 | 61 | try: 62 | comment = re.search('/test (.*)', os.environ['COMMENT']).group(1) 63 | except: 64 | comment = "" 65 | 66 | options = parser.parse_intermixed_args(comment.split()) 67 | 68 | print("::set-output name=composes::{}".format(options.os)) 69 | 70 | test: 71 | name: "Test Go" 72 | runs-on: ubuntu-latest 73 | needs: ack 74 | strategy: 75 | matrix: 76 | compose: ${{fromJson(needs.ack.outputs.composes)}} 77 | container: 78 | image: ${{ matrix.compose }} 79 | steps: 80 | - name: "Print OS version" 81 | run: cat /etc/redhat-release 82 | - uses: actions/checkout@v3 83 | with: 84 | ref: "refs/pull/${{ github.event.issue.number }}/head" 85 | - name: "Build" 86 | run: | 87 | pwd 88 | ls -l 89 | pushd ./src 90 | ./make.bash -v 91 | popd 92 | shell: bash 93 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "go"] 2 | path = go 3 | url = https://github.com/golang/go.git 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | This project adopts the Go code of conduct: https://go.dev/conduct. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Go Toolchain 2 | 3 | This repository holds the source code for the fork of the Go toolchain used in the Go Toolset CentOS / RHEL packages. This fork contains modifications enabling Go to call into OpenSSL for FIPS compliance. 4 | 5 | **Disclaimer:** This repository itself is not an official Red Hat product. 6 | 7 | ## Background 8 | 9 | ### What is FIPS 140-3? 10 | 11 | FIPS 140-3 is a standard for cryptographic modules used by federal agencies to protect sensitive information. It covers design, implementation, operation, and security requirements for different levels of protection. 12 | 13 | https://csrc.nist.gov/pubs/fips/140-3/final 14 | 15 | ## Go and FIPS 16 | 17 | Before Go 1.24 there had never been an attempt to have the Go cryptographic libraries FIPS 140-3 certified. However, there was still a need for Go programs to run in environments where FIPS certification is necessary. To that end, the Go maintainers implemented a fork (maintained as a separate branch) which would link Go against the C library Boring Crypto. This branch would eventually be merged into the main branch, paving the way for their own eventual removal and the creation of the `crypto/internal/fips` module and the attempt to directly certify the Go source itself. 18 | 19 | ## Downstream Modifications 20 | 21 | This Go toolchain is based on a fork of the upstream work enabling Go to link against Boring Crypto. This fork uses OpenSSL instead of BoringSSL and adds enhancements to give operators more confidence when deploying their Go binaries in environments requiring strict compliance. 22 | 23 | ### OpenSSL 24 | 25 | The main difference between this fork and the upstream work is the FIPS validated library which is used to execute the cryptographic operations when FIPS mode is enabled. Our fork uses OpenSSL which is already FIPS validated on RHEL. 26 | 27 | ### Dynamic linkage 28 | 29 | Our OpenSSL based toolchain produces binaries that are dynamically linked by default. When a Go binary built with this toolchain including FIPS enhancements is executed it will search for a supported version of libcrypto.so (starting with OpenSSL 3, falling back to older versions) and then dlopen it if found. This means that disabling of CGO via CGO_ENABLED=0 is unsupported in FIPS mode. 30 | 31 | ### Strict FIPS mode 32 | 33 | Our downstream modifications also include a strict FIPS mode where a Go binary built with this enabled will crash when it detects it is running in a FIPS environment without being properly compiled or having loaded the appropriate OpenSSL version to call into. More details are available in later sections of this document. 34 | 35 | ## Building the Toolchain 36 | 37 | ### Clone the repository 38 | 39 | ``` 40 | $ git clone https://github.com/golang-fips/go.git && cd ./go 41 | ``` 42 | 43 | ### Build the toolchain 44 | 45 | ``` 46 | $ ./scripts/full-initialize-repo.sh && cd ./go/src && ./make.bash 47 | ``` 48 | 49 | ### Run tests 50 | 51 | ``` 52 | $ ./scripts/crypto-test.sh && cd ./go/src && ./all.bash 53 | ``` 54 | 55 | ## Compiler Usage 56 | 57 | This section details the different flags and options you have available when compiling your source code using the Go toolchain. 58 | 59 | ### Opting out of FIPS changes at compile time 60 | 61 | A user can always opt out of the downstream changes and FIPS enhancements when compiling their source code. To opt out of the downstream changes in the Go Toolset related to using OpenSSL for cryptography, you can use the following compiler tag: `-tags no_openssl`. 62 | 63 | Building your programs with this tag will completely bypass and compile out all of these changes. This means that instead of potentially calling into OpenSSL via dynamic linkage and CGO, your application will use the pure upstream standard library cryptography. 64 | 65 | For example, you would use the command like this: `go build -tags no_openssl`. 66 | 67 | ### Enabling strict FIPS mode 68 | 69 | This Go toolchain includes a strict FIPS mode. This is a startup check whose purpose is to detect build or runtime configuration issues that might prevent the application from properly using the OpenSSL backend in a FIPS environment, and it will cause the application to crash via a panic if such issues are detected. 70 | 71 | To enable this strict FIPS mode during compilation, you need to use a specific GOEXPERIMENT setting. 72 | 73 | You can enable this option by building your application using the following setting: 74 | 75 | ``` 76 | GOEXPERIMENT=strictfipsruntime 77 | ``` 78 | 79 | So, you would typically run your build command like this: `GOEXPERIMENT=strictfipsruntime go build`. 80 | 81 | ## Runtime Usage 82 | 83 | ### Forcing a specific OpenSSL version 84 | 85 | When starting your application you can choose to force a specific OpenSSL version as opposed to letting the process search for an available version at startup. By default the process will try to load the latest version of OpenSSL available on the system, starting with OpenSSL 3. In order to instead explicitly select the version you must set the environment variable `GO_OPENSSL_VERSION_OVERRIDE`. For example, to ensure that OpenSSL 3 is used you would need to start the Go binary like so: `GO_OPENSSL_VERSION_OVERRIDE=libcrypto.so.3`. 86 | 87 | **NOTE**: This option is for testing / development only and is not explicitly supported. 88 | 89 | ### Forcing FIPS mode at runtime 90 | 91 | Typically the binary will only execute in FIPS mode and call into OpenSSL if the RHEL host is in FIPS mode. If you would like to force the process to execute in FIPS mode you can set the environment variable `GOLANG_FIPS=1`. Note also that if you are using OpenSSL 3 then you will also have to set `OPENSSL_FORCE_FIPS_MODE=1` as well. 92 | 93 | ### Strict FIPS runtime protection 94 | 95 | If you have chosen to compile your binary with the additional strict FIPS runtime checks, then at startup the process will look for conditions that are incompatible with correct operation in a FIPS environment. Specifically, during initialization, the process will check if the host is in FIPS mode or FIPS mode has been specifically requested at runtime. If either of those are true, but the process was unable to successfully find a compatible OpenSSL library with the proper FIPS module (or `-tags no_openssl` was used during compilation), the process will crash via panic. This gives operators increased confidence that the binaries they are running in their FIPS environments are built correctly and are not falling back to non-FIPS validated cryptography. 96 | 97 | ## Validating a Compiled Binary 98 | 99 | Aside from the strict FIPS runtime checks, another check to ensure that your binaries are compiled correctly is via static analysis of the binary itself. The OpenShift organization has an open source payload checker to ensure OpenShift binaries are compiled correctly. This code is rather specific to OpenShift and scans container images, however the code and Go specific analysis can be beneficial. 100 | 101 | ## CentOS / OpenSSL Version Considerations 102 | 103 | Different versions of CentOS will have different versions of OpenSSL. Different versions of OpenSSL may differ with regards to accepted algorithms, etc… Please consider this during any testing or deployment. 104 | 105 | ## Migration to Upstream FIPS certified cryptography 106 | 107 | We intend to sunset our downstream OpenSSL based solution in favor of pure upstream Go cryptography once the upstream sources are FIPS certified. The maintainers of this repository are directly involved in the upstream effort for FIPS certification of the cryptographic packages in the Go standard library, and are committed to continuing this work and ensuring we deliver on our upstream first approach. 108 | 109 | ## Further Reading 110 | 111 | - https://access.redhat.com/compliance/fips 112 | - https://github.com/openshift/check-payload 113 | - https://github.com/golang-fips/go 114 | - https://developers.redhat.com/articles/2025/03/10/benefits-native-fips-support-go-124 115 | - https://developers.redhat.com/articles/2025/01/23/fips-mode-red-hat-go-toolset 116 | - https://developers.redhat.com/articles/2024/02/27/handling-fips-mode-upstream-projects-rhel 117 | - https://developers.redhat.com/articles/2023/12/14/how-improve-go-fips-test-coverage-packit 118 | - https://developers.redhat.com/articles/2022/05/31/your-go-application-fips-compliant 119 | - https://developers.redhat.com/blog/2019/06/24/go-and-fips-140-2-on-red-hat-enterprise-linux 120 | -------------------------------------------------------------------------------- /config/versions.json: -------------------------------------------------------------------------------- 1 | { 2 | "github.com/golang-fips/go": "main", 3 | "github.com/golang-fips/openssl": "61a53ab338d5f1657c6fe5d856d24528bfdd731d", 4 | "github.com/golang/go": "go1.24.4" 5 | } 6 | -------------------------------------------------------------------------------- /patches/001-fix-linkage.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go 2 | index 32e59b446a..b55f29298b 100644 3 | --- a/src/cmd/dist/build.go 4 | +++ b/src/cmd/dist/build.go 5 | @@ -1309,7 +1309,9 @@ func toolenv() []string { 6 | // we disable cgo to get static binaries for cmd/go and cmd/pprof, 7 | // so that they work on systems without the same dynamic libraries 8 | // as the original build system. 9 | - env = append(env, "CGO_ENABLED=0") 10 | + // 11 | + // Setting CGO_ENABLED to 0 prevents cmd/go and the like from linking with vendored openssl symbols. 12 | + // env = append(env, "CGO_ENABLED=0") 13 | } 14 | if isRelease || os.Getenv("GO_BUILDER_NAME") != "" { 15 | // Add -trimpath for reproducible builds of releases. 16 | -------------------------------------------------------------------------------- /patches/002-fix-std-crypto.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/crypto/internal/backend/openssl.go b/src/crypto/internal/backend/openssl.go 2 | index 3d3a9a36ee..b7a65a1f6e 100644 3 | --- a/src/crypto/internal/backend/openssl.go 4 | +++ b/src/crypto/internal/backend/openssl.go 5 | @@ -25,6 +25,21 @@ var enabled bool 6 | var knownVersions = [...]string{"3", "1.1", "11", "111", "1.0.2", "1.0.0", "10"} 7 | 8 | func init() { 9 | + // 0: FIPS opt-out: abort the process if it is enabled and can't be disabled. 10 | + // 1: FIPS required: abort the process if it is not enabled and can't be enabled. 11 | + // other values: do not override OpenSSL configured FIPS mode. 12 | + var fips string 13 | + if v, ok := syscall.Getenv("GOLANG_FIPS"); ok { 14 | + fips = v 15 | + } else if hostFIPSModeEnabled() { 16 | + // System configuration can only force FIPS mode. 17 | + fips = "1" 18 | + } 19 | + 20 | + if fips != "1" { 21 | + return 22 | + } 23 | + 24 | version, _ := syscall.Getenv("GO_OPENSSL_VERSION_OVERRIDE") 25 | if version == "" { 26 | var fallbackVersion string 27 | @@ -49,16 +64,6 @@ func init() { 28 | if err := openssl.Init(version); err != nil { 29 | panic("opensslcrypto: can't initialize OpenSSL " + version + ": " + err.Error()) 30 | } 31 | - // 0: FIPS opt-out: abort the process if it is enabled and can't be disabled. 32 | - // 1: FIPS required: abort the process if it is not enabled and can't be enabled. 33 | - // other values: do not override OpenSSL configured FIPS mode. 34 | - var fips string 35 | - if v, ok := syscall.Getenv("GOLANG_FIPS"); ok { 36 | - fips = v 37 | - } else if hostFIPSModeEnabled() { 38 | - // System configuration can only force FIPS mode. 39 | - fips = "1" 40 | - } 41 | switch fips { 42 | case "0": 43 | if openssl.FIPS() { 44 | -------------------------------------------------------------------------------- /scripts/configure-crypto-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Try PLATFORM_ID 5 | OS_ID=$(cat /etc/os-release | awk 'match($0,/PLATFORM_ID="platform:(.*)"/,a){print a[1]}') 6 | if [[ "$OS_ID" == "" ]]; then 7 | # Try REDHAT_BUGZILLA_PRODUCT 8 | OS_ID=$(cat /etc/os-release | awk 'match($0,/REDHAT_BUGZILLA_PRODUCT=\"(.*)\"/,a){print a[1]}') 9 | fi 10 | 11 | 12 | ROOT=$(realpath $(dirname $(readlink -f $0))/..) 13 | CONFIG=$ROOT/go/src/crypto/internal/backend/boringtest/config.go 14 | 15 | set_param () { 16 | local param=$1 17 | local val=$2 18 | echo "Setting $param to $val." 19 | sed -i "s/\"$param\":.*,/\"$param\": $val,/" $CONFIG 20 | } 21 | 22 | if [[ ! -f "$CONFIG" ]]; then 23 | echo "could not find $CONFIG" 24 | fi 25 | 26 | if [[ "$OS_ID" == "el9" ]]; then 27 | echo "Detected el9..." 28 | echo "Keeping current settings." 29 | elif [[ "$OS_ID" == "el8" ]]; then 30 | echo "Detected el8..." 31 | set_param "PKCSv1.5" "true" 32 | set_param "SHA1" "true" 33 | set_param "RSA4096LeafCert" "true" 34 | set_param "RSA1024LeafCert" "true" 35 | set_param "TLS13" "true" 36 | set_param "CurveP224" "true" 37 | elif [[ "$OS_ID" == "Red Hat Enterprise Linux 7" ]]; then 38 | echo "Detected el7..." 39 | set_param "PKCSv1.5" "true" 40 | set_param "SHA1" "true" 41 | set_param "RSA4096LeafCert" "false" 42 | set_param "RSA1024LeafCert" "true" 43 | set_param "TLS13" "false" 44 | set_param "CurveP224" "false" 45 | set_param "CurveP256" "false" 46 | else 47 | echo "Detected unknown os: $OS_ID ..." 48 | echo "Keeping current settings." 49 | fi 50 | -------------------------------------------------------------------------------- /scripts/crypto-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eE 4 | 5 | quiet () { 6 | 2>&1>/dev/null $@ 7 | } 8 | 9 | # Find the GOROOT. 10 | # If using a release branch, expect the GOROOT 11 | # in the go submodule directory. 12 | GOROOT=$(readlink -f $(dirname $0)/..) 13 | quiet pushd $GOROOT 14 | if 2>/dev/null cat .gitmodules | grep -q "url = https://github.com/golang/go.git"; then 15 | GOROOT=${GOROOT}/go 16 | fi 17 | quiet popd 18 | 19 | export GOCACHE=/tmp/go-cache 20 | export GO=${GOROOT}/bin/go 21 | 22 | # Test suites to run 23 | SUITES="crypto,tls,http" 24 | # Verbosity flags to pass to Go 25 | VERBOSE="" 26 | 27 | # Parse command line arguments 28 | while [[ $# -gt 0 ]]; do 29 | case $1 in 30 | --suites) 31 | SUITES=$2 32 | shift;shift 33 | ;; 34 | -v) 35 | VERBOSE="$VERBOSE -v" 36 | set -x 37 | shift 38 | ;; 39 | *) 40 | >&2 echo "unsupported option $1" 41 | exit 1 42 | ;; 43 | esac 44 | done 45 | 46 | notify_running() { 47 | local mode=$1 48 | local suite=$2 49 | echo -e "\n##### ${suite} (${mode})" 50 | } 51 | 52 | run_crypto_test_suite () { 53 | local mode=$1 54 | local tags=$2 55 | local suite="crypto-fips" 56 | notify_running ${mode} ${suite} 57 | quiet pushd ${GOROOT}/src/crypto 58 | GOLANG_FIPS=1 OPENSSL_FORCE_FIPS_MODE=1 \ 59 | $GO test $tags -count=1 $($GO list ./... | grep -v tls) $VERBOSE 60 | 61 | local suite="crypto-fips-parity-nocgo" 62 | notify_running ${mode} ${suite} 63 | GOLANG_FIPS=1 OPENSSL_FORCE_FIPS_MODE=1 \ 64 | CGO_ENABLED=0 $GO test $tags -count=1 $($GO list ./... | grep -v tls) $VERBOSE 65 | quiet popd 66 | } 67 | 68 | run_http_test_suite () { 69 | local mode=$1 70 | local tags=$2 71 | local suite="net-http-fips" 72 | notify_running ${mode} ${suite} 73 | quiet pushd ${GOROOT}/src/net/http 74 | GOLANG_FIPS=1 OPENSSL_FORCE_FIPS_MODE=1 \ 75 | $GO test $tags -count=1 $VERBOSE 76 | 77 | local suite="net-http-fips-parity-nocgo" 78 | notify_running ${mode} ${suite} 79 | quiet pushd ${GOROOT}/src/net/http 80 | GOLANG_FIPS=1 OPENSSL_FORCE_FIPS_MODE=1 \ 81 | CGO_ENABLED=0 $GO test $tags -count=1 $VERBOSE 82 | 83 | quiet popd 84 | } 85 | 86 | run_tls_test_suite () { 87 | local mode=$1 88 | local tags=$2 89 | local suite="tls-fips" 90 | notify_running ${mode} ${suite} 91 | quiet pushd ${GOROOT}/src 92 | GOLANG_FIPS=1 OPENSSL_FORCE_FIPS_MODE=1 \ 93 | $GO test $tags -count=1 crypto/tls -run "^TestBoring" $VERBOSE 94 | quiet popd 95 | } 96 | 97 | 98 | run_full_test_suite () { 99 | local mode=$1 100 | local tags=$2 101 | for suite in ${SUITES//,/ }; do 102 | if [[ "$suite" == "crypto" ]]; then 103 | run_crypto_test_suite ${mode} ${tags} 104 | elif [[ "$suite" == "tls" ]]; then 105 | run_tls_test_suite ${mode} ${tags} 106 | elif [[ "$suite" == "http" ]]; then 107 | run_http_test_suite ${mode} ${tags} 108 | fi 109 | done 110 | } 111 | 112 | # Run in default mode 113 | run_full_test_suite default "" 114 | 115 | # Run in strict fips mode 116 | export GOEXPERIMENT=strictfipsruntime 117 | run_full_test_suite strictfips "-tags=strictfipsruntime" 118 | 119 | # Run TLS Handshake tests to test ExpandHKDF 120 | notify_running "TLS Handshake", "(default)" 121 | GOLANG_FIPS=1 OPENSSL_FORCE_FIPS_MODE=1 \ 122 | $GO test -count=1 crypto/tls -run "TestTrafficKey" $VERBOSE 123 | 124 | echo ALL TESTS PASSED 125 | -------------------------------------------------------------------------------- /scripts/full-initialize-repo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script generates and applies FIPS 4 | # patches to a Go tree. 5 | 6 | echo "Host Go Version:" 7 | go version 8 | 9 | echo "Host Go Env:" 10 | go env 11 | 12 | SCRIPT_DIR=$(readlink -f $(dirname $0)) 13 | GO_DIR=${SCRIPT_DIR}/../go 14 | 15 | if [[ -d "${GO_DIR}" ]]; then 16 | 1>&2 echo "Existing go tree detected. Aborting..." 17 | exit 1 18 | fi 19 | 20 | ${SCRIPT_DIR}/setup-go-submodule.sh $@ 21 | 22 | set -ex 23 | pushd ${GO_DIR} 24 | for patch in $(ls ../patches); do 25 | git apply -v ../patches/${patch} 26 | git add -A 27 | git commit -am ${patch} 28 | done 29 | popd 30 | -------------------------------------------------------------------------------- /scripts/setup-go-submodule.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | GIT_REF=${1} 6 | SCRIPT_DIR=$(readlink -f $(dirname $0)) 7 | CONFIG_DIR=$(readlink -f $(dirname $0)/../config) 8 | 9 | if [ -z "${GIT_REF}" ]; then 10 | GIT_REF=$(go run ${SCRIPT_DIR}/versions.go ${CONFIG_DIR}/versions.json github.com/golang/go) 11 | if [ -z "${GIT_REF}" ]; then 12 | echo "You must supply a branch, tag, or commit for the Go submodule (for example release-branch.go1.19)" 13 | exit 1 14 | fi 15 | fi 16 | 17 | git submodule add --force ${GOLANG_REPO:-https://github.com/golang/go.git} 18 | git submodule update 19 | 20 | pushd go 21 | git fetch 22 | git checkout ${GIT_REF} 23 | 24 | # If we're on a branch, the cached tree might be out of sync, 25 | # so we should hard reset against origin. 26 | if [[ "$(git branch --show-current | wc -l)" == "1" ]]; then 27 | git fetch 28 | git reset origin/${GIT_REF} --hard 29 | fi 30 | 31 | popd 32 | 33 | -------------------------------------------------------------------------------- /scripts/versions.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | // Script takes two arguments, the path to version.json, 12 | // and the name of the repository. 13 | if len(os.Args) < 3 { 14 | log.Fatal("Error: requires exactly two arguments") 15 | } 16 | versionFile := os.Args[1] 17 | repository := os.Args[2] 18 | 19 | // Read the mapping of repositories to git refs. 20 | content, err := os.ReadFile(versionFile) 21 | if err != nil { 22 | log.Fatal("Could not open file: ", err) 23 | } 24 | var gitRefs map[string]string 25 | err = json.Unmarshal(content, &gitRefs) 26 | if err != nil { 27 | log.Fatal("Could not unmarshal json: ", err) 28 | } 29 | 30 | // Print the result. 31 | if gitRef, ok := gitRefs[repository]; ok { 32 | fmt.Printf("%s\n", gitRef) 33 | } else { 34 | log.Fatalf("Invalid repository: %s", gitRef) 35 | } 36 | } 37 | --------------------------------------------------------------------------------