feat(golang): detect native Go FIPS 140 mode in binaries (#5155)

Signed-off-by: Gunny Patel <zip159@gmail.com>
This commit is contained in:
Gunny Patel 2026-08-07 10:36:09 -04:00 committed by GitHub
parent f45586b457
commit 07fb23487f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 68 additions and 0 deletions

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"io" "io"
"runtime/debug" "runtime/debug"
"strings"
"github.com/kastenhq/goversion/version" "github.com/kastenhq/goversion/version"
@ -51,6 +52,7 @@ func scanFile(location file.Location, reader unionreader.UnionReader, captureSym
// we can still catalog packages, even if we can't get the crypto information // we can still catalog packages, even if we can't get the crypto information
errs = unknown.Appendf(errs, location, "unable to read golang version info: %w", err) errs = unknown.Appendf(errs, location, "unable to read golang version info: %w", err)
} }
v = append(v, getNativeFIPSSettings(bi.Settings)...)
arch := getGOARCH(bi.Settings) arch := getGOARCH(bi.Settings)
if arch == "" { if arch == "" {
arch, err = getGOARCHFromBin(r) arch, err = getGOARCHFromBin(r)
@ -101,6 +103,25 @@ func getCryptoSettingsFromVersion(v version.Version) []string {
return cryptoSettings return cryptoSettings
} }
func getNativeFIPSSettings(settings []debug.BuildSetting) []string {
var cryptoSettings []string
for _, s := range settings {
switch s.Key {
case "GOFIPS140":
if s.Value != "" {
cryptoSettings = append(cryptoSettings, "GOFIPS140="+s.Value)
}
case "DefaultGODEBUG":
for _, kv := range strings.Split(s.Value, ",") {
if setting, val, ok := strings.Cut(kv, "="); ok && setting == "fips140" {
cryptoSettings = append(cryptoSettings, "GODEBUG=fips140="+val)
}
}
}
}
return cryptoSettings
}
func getBuildInfo(r io.ReaderAt, location file.Location) (bi *debug.BuildInfo, err error) { func getBuildInfo(r io.ReaderAt, location file.Location) (bi *debug.BuildInfo, err error) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {

View File

@ -110,3 +110,50 @@ func Test_getCryptoSettingsFromVersion(t *testing.T) {
}) })
} }
} }
func Test_getNativeFIPSSettings(t *testing.T) {
for _, tt := range []struct {
name string
settings []debug.BuildSetting
result []string
}{
{
name: "not set",
settings: []debug.BuildSetting{{Key: "GOARCH", Value: "arm64"}},
result: nil,
},
{
name: "GOFIPS140=off is reported verbatim",
settings: []debug.BuildSetting{{Key: "GOFIPS140", Value: "off"}},
result: []string{"GOFIPS140=off"},
},
{
name: "pinned module version with mode on",
settings: []debug.BuildSetting{
{Key: "GOFIPS140", Value: "v1.0.0"},
{Key: "DefaultGODEBUG", Value: "fips140=on"},
},
result: []string{"GOFIPS140=v1.0.0", "GODEBUG=fips140=on"},
},
{ // GOFIPS140=latest enables FIPS mode without pinning a module version
name: "latest with mode on",
settings: []debug.BuildSetting{
{Key: "GOFIPS140", Value: "latest"},
{Key: "DefaultGODEBUG", Value: "fips140=on"},
},
result: []string{"GOFIPS140=latest", "GODEBUG=fips140=on"},
},
{ // fips140 is one entry among many in DefaultGODEBUG
name: "fips140 among other godebug defaults",
settings: []debug.BuildSetting{
{Key: "DefaultGODEBUG", Value: "asynctimerchan=1,fips140=on,tlssha1=1"},
},
result: []string{"GODEBUG=fips140=on"},
},
} {
t.Run(tt.name, func(t *testing.T) {
res := getNativeFIPSSettings(tt.settings)
assert.ElementsMatch(t, res, tt.result)
})
}
}