diff --git a/syft/pkg/cataloger/golang/scan_binary.go b/syft/pkg/cataloger/golang/scan_binary.go index 84fd6d2b27d..a4841a27c67 100644 --- a/syft/pkg/cataloger/golang/scan_binary.go +++ b/syft/pkg/cataloger/golang/scan_binary.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "runtime/debug" + "strings" "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 errs = unknown.Appendf(errs, location, "unable to read golang version info: %w", err) } + v = append(v, getNativeFIPSSettings(bi.Settings)...) arch := getGOARCH(bi.Settings) if arch == "" { arch, err = getGOARCHFromBin(r) @@ -101,6 +103,25 @@ func getCryptoSettingsFromVersion(v version.Version) []string { 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) { defer func() { if r := recover(); r != nil { diff --git a/syft/pkg/cataloger/golang/scan_binary_test.go b/syft/pkg/cataloger/golang/scan_binary_test.go index 7595ae21051..1e6910e6df2 100644 --- a/syft/pkg/cataloger/golang/scan_binary_test.go +++ b/syft/pkg/cataloger/golang/scan_binary_test.go @@ -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) + }) + } +}