crypto/internal/fips140: add Supported

Move the logic duplicated in multiple places to a central function.

Change-Id: I6a6a4656469c91dd62b0be716ec8367358f4a3e1
Reviewed-on: https://go-review.googlesource.com/c/go/+/639336
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Daniel McCarney <daniel@binaryparadox.net>
Reviewed-by: Roland Shoemaker <roland@golang.org>
This commit is contained in:
Filippo Valsorda 2024-12-27 11:13:42 +01:00 committed by Gopher Robot
parent f0a9b6df45
commit eb0c2b2f96
8 changed files with 64 additions and 45 deletions

View file

@ -1797,6 +1797,8 @@ func isEnvSet(evar string) bool {
} }
func (t *tester) fipsSupported() bool { func (t *tester) fipsSupported() bool {
// Keep this in sync with [crypto/internal/fips140.Supported].
// Use GOFIPS140 or GOEXPERIMENT=boringcrypto, but not both. // Use GOFIPS140 or GOEXPERIMENT=boringcrypto, but not both.
if strings.Contains(goexperiment, "boringcrypto") { if strings.Contains(goexperiment, "boringcrypto") {
return false return false

View file

@ -4,6 +4,6 @@
//go:build asan //go:build asan
package check package fips140
const asanEnabled = true const asanEnabled = true

View file

@ -0,0 +1,10 @@
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Keep in sync with notboring.go and crypto/internal/boring/boring.go.
//go:build boringcrypto && linux && (amd64 || arm64) && !android && !msan && cgo
package fips140
const boringEnabled = true

View file

@ -19,7 +19,6 @@ import (
"crypto/internal/fips140deps/byteorder" "crypto/internal/fips140deps/byteorder"
"crypto/internal/fips140deps/godebug" "crypto/internal/fips140deps/godebug"
"io" "io"
"runtime"
"unsafe" "unsafe"
) )
@ -27,19 +26,6 @@ import (
// true when [fips140.Enabled] is true, or init would have panicked. // true when [fips140.Enabled] is true, or init would have panicked.
var Verified bool var Verified bool
// Supported reports whether the current GOOS/GOARCH is Supported at all.
func Supported() bool {
// See cmd/internal/obj/fips.go's EnableFIPS for commentary.
switch {
case runtime.GOARCH == "wasm",
runtime.GOOS == "windows" && runtime.GOARCH == "386",
runtime.GOOS == "windows" && runtime.GOARCH == "arm",
runtime.GOOS == "aix":
return false
}
return true
}
// Linkinfo holds the go:fipsinfo symbol prepared by the linker. // Linkinfo holds the go:fipsinfo symbol prepared by the linker.
// See cmd/link/internal/ld/fips.go for details. // See cmd/link/internal/ld/fips.go for details.
// //
@ -70,19 +56,8 @@ func init() {
return return
} }
if asanEnabled { if err := fips140.Supported(); err != nil {
// ASAN disapproves of reading swaths of global memory below. panic("fips140: " + err.Error())
// One option would be to expose runtime.asanunpoison through
// crypto/internal/fips140deps and then call it to unpoison the range
// before reading it, but it is unclear whether that would then cause
// false negatives. For now, FIPS+ASAN doesn't need to work.
// If this is made to work, also re-enable the test in check_test.go
// and in cmd/dist/test.go.
panic("fips140: cannot verify in asan mode")
}
if !Supported() {
panic("fips140: unavailable on " + runtime.GOOS + "-" + runtime.GOARCH)
} }
if Linkinfo.Magic[0] != 0xff || string(Linkinfo.Magic[1:]) != fipsMagic || Linkinfo.Sum == zeroSum { if Linkinfo.Magic[0] != 0xff || string(Linkinfo.Magic[1:]) != fipsMagic || Linkinfo.Sum == zeroSum {

View file

@ -4,7 +4,11 @@
package fips140 package fips140
import "crypto/internal/fips140deps/godebug" import (
"crypto/internal/fips140deps/godebug"
"errors"
"runtime"
)
var Enabled bool var Enabled bool
@ -24,6 +28,35 @@ func init() {
} }
} }
// Supported returns an error if FIPS 140-3 mode can't be enabled.
func Supported() error {
// Keep this in sync with fipsSupported in cmd/dist/test.go.
// ASAN disapproves of reading swaths of global memory in fips140/check.
// One option would be to expose runtime.asanunpoison through
// crypto/internal/fips140deps and then call it to unpoison the range
// before reading it, but it is unclear whether that would then cause
// false negatives. For now, FIPS+ASAN doesn't need to work.
if asanEnabled {
return errors.New("FIPS 140-3 mode is incompatible with ASAN")
}
// See EnableFIPS in cmd/internal/obj/fips.go for commentary.
switch {
case runtime.GOARCH == "wasm",
runtime.GOOS == "windows" && runtime.GOARCH == "386",
runtime.GOOS == "windows" && runtime.GOARCH == "arm",
runtime.GOOS == "aix":
return errors.New("FIPS 140-3 mode is not supported on " + runtime.GOOS + "-" + runtime.GOARCH)
}
if boringEnabled {
return errors.New("FIPS 140-3 mode is incompatible with GOEXPERIMENT=boringcrypto")
}
return nil
}
func Name() string { func Name() string {
return "Go Cryptographic Module" return "Go Cryptographic Module"
} }

View file

@ -4,6 +4,6 @@
//go:build !asan //go:build !asan
package check package fips140
const asanEnabled = false const asanEnabled = false

View file

@ -0,0 +1,9 @@
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !(boringcrypto && linux && (amd64 || arm64) && !android && !msan && cgo)
package fips140
const boringEnabled = false

View file

@ -5,16 +5,14 @@
package fipstest package fipstest
import ( import (
"crypto/internal/boring" "crypto/internal/fips140"
. "crypto/internal/fips140/check" . "crypto/internal/fips140/check"
"crypto/internal/fips140/check/checktest" "crypto/internal/fips140/check/checktest"
"fmt" "fmt"
"internal/abi" "internal/abi"
"internal/asan"
"internal/godebug" "internal/godebug"
"internal/testenv" "internal/testenv"
"os" "os"
"runtime"
"testing" "testing"
"unicode" "unicode"
"unsafe" "unsafe"
@ -23,10 +21,6 @@ import (
const enableFIPSTest = true const enableFIPSTest = true
func TestFIPSCheckVerify(t *testing.T) { func TestFIPSCheckVerify(t *testing.T) {
if boring.Enabled {
t.Skip("not testing fips140 with boringcrypto enabled")
}
if Verified { if Verified {
t.Logf("verified") t.Logf("verified")
return return
@ -40,12 +34,8 @@ func TestFIPSCheckVerify(t *testing.T) {
return return
} }
if !Supported() { if err := fips140.Supported(); err != nil {
t.Skipf("skipping on %s-%s", runtime.GOOS, runtime.GOARCH) t.Skipf("skipping: %v", err)
}
if asan.Enabled {
// Verification panics with asan; don't bother.
t.Skipf("skipping with -asan")
} }
cmd := testenv.Command(t, os.Args[0], "-test.v", "-test.run=TestFIPSCheck") cmd := testenv.Command(t, os.Args[0], "-test.v", "-test.run=TestFIPSCheck")
@ -62,8 +52,8 @@ func TestFIPSCheckInfo(t *testing.T) {
return return
} }
if !Supported() { if err := fips140.Supported(); err != nil {
t.Skipf("skipping on %s-%s", runtime.GOOS, runtime.GOARCH) t.Skipf("skipping: %v", err)
} }
// Check that the checktest symbols are initialized properly. // Check that the checktest symbols are initialized properly.