Skip to content

GOEXPERIMENT=systemcrypto doesn't override MS_GO_NOSYSTEMCRYPTO=1 #2170

@bdhill-arista

Description

@bdhill-arista

Microsoft build of Go version

go1.26.0-1

What is your operating system and platform?

Fedora 43 on ARM64

Output of go env in your module/workspace:

AR='ar'
CC='gcc'
CGO_CFLAGS='-O2
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2
CGO_ENABLED='1'
CGO_FFLAGS='-O2
CGO_LDFLAGS='-O2
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOARCH='arm64'
GOARM64='v8.0'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/root/.cache/ms-go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/root/.config/go/env'
GOEXE=''
GOEXPERIMENT='nosystemcrypto'
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC
GOHOSTARCH='arm64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/go/src/gofipstest/go.mod'
GOMODCACHE=''
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH=''
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/root/go'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/root/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='local'
GOTOOLDIR='/root/go/pkg/tool/linux_arm64'
GOVCS=''
GOVERSION='go1.26.0'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

Tested the latest Go 1.26.0-1 release with two different configuration methods:

  1. GOEXPERIMENT=systemcrypto CGO_ENABLED=1
  2. -tags=goexperiment.systemcrypto,cgo

Reproducible with the Dockerfile below.

Dockerfile
FROM fedora:43@sha256:781b7642e8bf256e9cf75d2aa58d86f5cc695fd2df113517614e181a5eee9138

# Install cgo-related dependencies
RUN set -eux; \
    dnf -y update; \
    dnf -y install \
    ca-certificates \
    crypto-policies \
    crypto-policies-scripts \
    gcc-c++ \
    gcc \
    git \
    glibc-devel \
    openssl \
    openssl-libs \
    pkgconf \
    sudo \
    ; \
    dnf clean all

# Install toolchain
ENV PATH="/root/go/bin:${PATH}"
ENV GOROOT="/root/go"
WORKDIR /root
RUN curl -fsSL https://aka.ms/golang/release/latest/go1.26.0-1.linux-arm64.tar.gz | tar -xzf - && \
    go version

# Prepare FIPS config
RUN cat > /etc/pki/tls/openssl_fips.cnf <<EOF
.include /etc/ssl/openssl.cnf

[openssl_init]
providers = provider_sect
alg_section = algorithm_sect

[provider_sect]
fips = fips_sect

[fips_sect]
activate = 1

[algorithm_sect]
default_properties = fips=yes
EOF
# Check it works
RUN OPENSSL_CONF=/etc/pki/tls/openssl_fips.cnf openssl list -providers && openssl md5 /etc/hosts || echo "MD5 disabled as expected in FIPS mode"

# Create test files
WORKDIR /go/src/gofipstest
RUN go mod init gofipstest
COPY <<EOF ./main.go
package main

import (
   "crypto/fips140"
   "crypto/sha1"
   "fmt"
)

func main() {
   sha1.New()
   fmt.Println("   Includes fips.go =", included())
   fmt.Println("   FIPS Mode =", fips140.Enabled())
}
EOF

COPY <<EOF ./fips.go
//go:build goexperiment.opensslcrypto && cgo && linux
package main

func included() bool {
   return true
}
EOF

COPY <<EOF ./nofips.go
//go:build !goexperiment.opensslcrypto || !cgo || !linux
package main

func included() bool {
   return false
}
EOF

# Run tests
ENV MS_GO_NOSYSTEMCRYPTO=1
SHELL [ "/usr/bin/bash", "-c" ]
RUN <<EOF
set -euo pipefail
echo "go env"
go env
echo "--"

echo "TestWithTagsOnly (-tags=goexperiment.systemcrypto,cgo)"
go build -tags=goexperiment.systemcrypto,cgo -o /tmp/gofipstest ./...

echo "-- FIPS Disabled"
/tmp/gofipstest

echo "-- FIPS Enabled"
OPENSSL_CONF=/etc/pki/tls/openssl_fips.cnf GODEBUG=fips140=on /tmp/gofipstest && echo "PASSED" || echo "FAILED"

echo "--"

echo "TestWithEnvsOnly (CGO_ENABLED=1 GOEXPERIMENT=systemcrypto)"
CGO_ENABLED=1 GOEXPERIMENT=systemcrypto go build -o /tmp/gofipstest ./...

echo "-- FIPS Disabled"
/tmp/gofipstest

echo "-- FIPS Enabled"
OPENSSL_CONF=/etc/pki/tls/openssl_fips.cnf GODEBUG=fips140=on /tmp/gofipstest && echo "PASSED" || echo "FAILED"
EOF

What did you see happen?

I noticed that using GOEXPERIMENT environment variable instead of goexperiment build tag results in different FIPS runtime behavior.

  1. GOEXPERIMENT=systemcrypto doesn't set the goexperiment.opensslcrypto build tag (could be all goexperiment.* tags, idk).

  2. Binaries built with -tags=goexperiment.systemcrypto are able to run in FIPS mode, but binaries built with GOEXPERIMENT=systemcrypto CGO_ENABLED=1 panic instead.

See:

#18 0.110 TestWithTagsOnly (-tags=goexperiment.systemcrypto,cgo)
#18 4.007 -- FIPS Disabled
#18 4.010    Includes fips.go = true
#18 4.010    FIPS Mode = false
#18 4.010 -- FIPS Enabled
#18 4.016    Includes fips.go = true
#18 4.016    FIPS Mode = true
#18 4.016 PASSED
#18 4.016 --
#18 4.016 TestWithEnvsOnly (CGO_ENABLED=1 GOEXPERIMENT=systemcrypto)
#18 5.992 -- FIPS Disabled
#18 5.995    Includes fips.go = false
#18 5.995    FIPS Mode = false
#18 5.996 -- FIPS Enabled
#18 6.000 panic: FIPS mode requested (environment variable GODEBUG=fips140=on) but no supported crypto backend is enabled
#18 6.000
#18 6.000 goroutine 1 [running]:
#18 6.000 crypto/internal/backend.init.0()
#18 6.000 	/root/go/src/crypto/internal/backend/nobackend.go:19 +0xc0
#18 6.002 FAILED

What did you expect to see?

I expected them to behave the same way in both cases.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationfips

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions