cryptotest.MustSupportFIPS140(t)
if !fips140.Enabled {
cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^TestGCMNoncesFIPSV2$", "-test.v")
- cmd = testenv.CleanCmdEnv(cmd)
- cmd.Env = append(cmd.Env, "GODEBUG=fips140=on")
+ cmd.Env = append(cmd.Environ(), "GODEBUG=fips140=on")
out, err := cmd.CombinedOutput()
- if len(out) != 0 {
- t.Logf("\n%s", out)
- }
+ t.Logf("running with GODEBUG=fips140=on:\n%s", out)
if err != nil {
t.Errorf("fips140=on subprocess failed: %v", err)
}
cryptotest.MustSupportFIPS140(t)
if !fips140.Enabled {
cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^TestGCMNoncesFIPSV1$", "-test.v")
- cmd = testenv.CleanCmdEnv(cmd)
- cmd.Env = append(cmd.Env, "GODEBUG=fips140=on")
+ cmd.Env = append(cmd.Environ(), "GODEBUG=fips140=on")
out, err := cmd.CombinedOutput()
- if len(out) != 0 {
- t.Logf("\n%s", out)
- }
+ t.Logf("running with GODEBUG=fips140=on:\n%s", out)
if err != nil {
t.Errorf("fips140=on subprocess failed: %v", err)
}
"internal/testenv"
"io"
"os"
- "os/exec"
"path/filepath"
"regexp"
"strings"
if testing.Short() {
t.Skip("test requires running 'go build'")
}
- testenv.MustHaveGoBuild(t)
dir := t.TempDir()
hello := filepath.Join(dir, "hello.go")
}
run := func(args ...string) string {
- cmd := exec.Command(args[0], args[1:]...)
+ cmd := testenv.Command(t, args[0], args[1:]...)
cmd.Dir = dir
- out, err := cmd.CombinedOutput()
+ out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
if err != nil {
t.Fatalf("%v: %v\n%s", args, err, string(out))
}
return string(out)
}
- goBin := testenv.GoToolPath(t)
- run(goBin, "build", "-o", "hello.exe", "hello.go")
+ run(testenv.GoToolPath(t), "build", "-o", "hello.exe", "hello.go")
if out := run("./hello.exe"); out != "OK\n" {
t.Error("unexpected output:", out)
}
// List all text symbols under crypto/... and make sure there are some for
// P256, but none for the other curves.
var consistent bool
- nm := run(goBin, "tool", "nm", "hello.exe")
+ nm := run(testenv.GoToolPath(t), "tool", "nm", "hello.exe")
for _, match := range regexp.MustCompile(`(?m)T (crypto/.*)$`).FindAllStringSubmatch(nm, -1) {
symbol := strings.ToLower(match[1])
if strings.Contains(symbol, "p256") {
package fips140_test
import (
+ "crypto/des"
+ "crypto/fips140"
"crypto/internal/cryptotest"
"internal/testenv"
- "path/filepath"
- "strings"
"testing"
)
+func expectAllowed(t *testing.T, why string, expected bool) {
+ t.Helper()
+ result := isAllowed()
+ if result != expected {
+ t.Fatalf("%v: expected: %v, got: %v", why, expected, result)
+ }
+}
+
+func isAllowed() bool {
+ _, err := des.NewCipher(make([]byte, 8))
+ return err == nil
+}
+
func TestWithoutEnforcement(t *testing.T) {
- testenv.MustHaveExec(t)
- testenv.MustHaveGoBuild(t)
cryptotest.MustSupportFIPS140(t)
-
- tool, _ := testenv.GoTool()
- tmpdir := t.TempDir()
- binFile := filepath.Join(tmpdir, "fips140.test")
- cmd := testenv.Command(t, tool, "test", "-c", "-o", binFile, "./testdata")
- out, err := cmd.CombinedOutput()
- if err != nil {
- t.Log(string(out))
- t.Errorf("Could not build enforcement tests")
- }
- cmd = testenv.Command(t, binFile, "-test.list", ".")
- list, err := cmd.CombinedOutput()
- if err != nil {
- t.Log(string(out))
- t.Errorf("Could not get enforcement test list")
+ if !fips140.Enforced() {
+ cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^TestWithoutEnforcement$", "-test.v")
+ cmd.Env = append(cmd.Environ(), "GODEBUG=fips140=only")
+ out, err := cmd.CombinedOutput()
+ t.Logf("running with GODEBUG=fips140=only:\n%s", out)
+ if err != nil {
+ t.Errorf("fips140=only subprocess failed: %v", err)
+ }
+ return
}
- for test := range strings.Lines(string(list)) {
- test = strings.TrimSpace(test)
- t.Run(test, func(t *testing.T) {
- cmd = testenv.Command(t, binFile, "-test.run", "^"+test+"$")
- cmd.Env = append(cmd.Env, "GODEBUG=fips140=only")
- out, err := cmd.CombinedOutput()
- if err != nil {
- t.Error(string(out))
- }
+
+ t.Run("Disabled", func(t *testing.T) {
+ expectAllowed(t, "before enforcement disabled", false)
+ fips140.WithoutEnforcement(func() {
+ expectAllowed(t, "inside WithoutEnforcement", true)
})
- }
+ // make sure that bypass doesn't live on after returning
+ expectAllowed(t, "after WithoutEnforcement", false)
+ })
+
+ t.Run("Nested", func(t *testing.T) {
+ expectAllowed(t, "before enforcement bypass", false)
+ fips140.WithoutEnforcement(func() {
+ fips140.WithoutEnforcement(func() {
+ expectAllowed(t, "inside nested WithoutEnforcement", true)
+ })
+ expectAllowed(t, "inside nested WithoutEnforcement", true)
+ })
+ expectAllowed(t, "after enforcement bypass", false)
+ })
+
+ t.Run("GoroutineInherit", func(t *testing.T) {
+ ch := make(chan bool, 2)
+ expectAllowed(t, "before enforcement bypass", false)
+ fips140.WithoutEnforcement(func() {
+ go func() {
+ ch <- isAllowed()
+ }()
+ })
+ allowed := <-ch
+ if !allowed {
+ t.Fatal("goroutine didn't inherit enforcement bypass")
+ }
+ go func() {
+ ch <- isAllowed()
+ }()
+ allowed = <-ch
+ if allowed {
+ t.Fatal("goroutine inherited bypass after WithoutEnforcement return")
+ }
+ })
}
+++ /dev/null
-// Copyright 2025 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.
-
-package fips140_test
-
-import (
- "crypto/des"
- "crypto/fips140"
- "testing"
-)
-
-func expectAllowed(t *testing.T, why string, expected bool) {
- t.Helper()
- result := isAllowed()
- if result != expected {
- t.Fatalf("%v: expected: %v, got: %v", why, expected, result)
- }
-}
-
-func isAllowed() bool {
- _, err := des.NewCipher(make([]byte, 8))
- return err == nil
-}
-
-func TestDisabled(t *testing.T) {
- expectAllowed(t, "before enforcement disabled", false)
- fips140.WithoutEnforcement(func() {
- expectAllowed(t, "inside WithoutEnforcement", true)
- })
- // make sure that bypass doesn't live on after returning
- expectAllowed(t, "after WithoutEnforcement", false)
-}
-
-func TestNested(t *testing.T) {
- expectAllowed(t, "before enforcement bypass", false)
- fips140.WithoutEnforcement(func() {
- fips140.WithoutEnforcement(func() {
- expectAllowed(t, "inside nested WithoutEnforcement", true)
- })
- expectAllowed(t, "inside nested WithoutEnforcement", true)
- })
- expectAllowed(t, "after enforcement bypass", false)
-}
-
-func TestGoroutineInherit(t *testing.T) {
- ch := make(chan bool, 2)
- expectAllowed(t, "before enforcement bypass", false)
- fips140.WithoutEnforcement(func() {
- go func() {
- ch <- isAllowed()
- }()
- })
- allowed := <-ch
- if !allowed {
- t.Fatal("goroutine didn't inherit enforcement bypass")
- }
- go func() {
- ch <- isAllowed()
- }()
- allowed = <-ch
- if allowed {
- t.Fatal("goroutine inherited bypass after WithoutEnforcement return")
- }
-}
// possible in this environment.
func FetchModule(t *testing.T, module, version string) string {
testenv.MustHaveExternalNetwork(t)
- goTool := testenv.GoToolPath(t)
// If the default GOMODCACHE doesn't exist, use a temporary directory
// instead. (For example, run.bash sets GOPATH=/nonexist-gopath.)
- out, err := testenv.Command(t, goTool, "env", "GOMODCACHE").Output()
+ out, err := testenv.CleanCmdEnv(testenv.Command(t, testenv.GoToolPath(t), "env", "GOMODCACHE")).Output()
if err != nil {
- t.Errorf("%s env GOMODCACHE: %v\n%s", goTool, err, out)
+ t.Errorf("%s env GOMODCACHE: %v\n%s", testenv.GoToolPath(t), err, out)
if ee, ok := err.(*exec.ExitError); ok {
t.Logf("%s", ee.Stderr)
}
t.Logf("fetching %s@%s\n", module, version)
- output, err := testenv.Command(t, goTool, "mod", "download", "-json", module+"@"+version).CombinedOutput()
+ output, err := testenv.Command(t, testenv.GoToolPath(t), "mod", "download", "-json", module+"@"+version).CombinedOutput()
if err != nil {
t.Fatalf("failed to download %s@%s: %s\n%s\n", module, version, err, output)
}
{{range .XTestImports -}}
{{$path}} {{.}}
{{end -}}`, "crypto/internal/fips140/...")
- bout, err := cmd.CombinedOutput()
+ bout, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
if err != nil {
t.Fatalf("go list: %v\n%s", err, bout)
}
"bytes"
"crypto/elliptic"
"crypto/internal/cryptotest"
- "crypto/internal/entropy/v1.0.0"
+ entropy "crypto/internal/entropy/v1.0.0"
"crypto/internal/fips140"
"crypto/internal/fips140/aes"
"crypto/internal/fips140/aes/gcm"
// Build the acvptool binary.
toolPath := filepath.Join(t.TempDir(), "acvptool.exe")
- goTool := testenv.GoToolPath(t)
- cmd := testenv.Command(t, goTool,
+ cmd := testenv.Command(t, testenv.GoToolPath(t),
"build",
"-o", toolPath,
"./util/fipstools/acvp/acvptool")
cmd.Dir = bsslDir
- out := &strings.Builder{}
- cmd.Stderr = out
- if err := cmd.Run(); err != nil {
- t.Fatalf("failed to build acvptool: %s\n%s", err, out.String())
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Fatalf("failed to build acvptool: %s\n%s", err, out)
}
// Similarly, fetch the ACVP data module that has vectors/expected answers.
"-module-wrappers", "go:" + os.Args[0],
"-tests", configPath,
}
- cmd = testenv.Command(t, goTool, args...)
+ cmd = testenv.Command(t, testenv.GoToolPath(t), args...)
cmd.Dir = dataDir
cmd.Env = append(os.Environ(),
"ACVP_WRAPPER=1",
"GODEBUG=fips140=on",
)
- output, err := cmd.CombinedOutput()
+ out, err := cmd.CombinedOutput()
+ t.Logf("\n%s", out)
if err != nil {
- t.Fatalf("failed to run acvp tests: %s\n%s", err, string(output))
+ t.Fatalf("failed to run acvp tests: %s", err)
}
- t.Log(string(output))
}
func TestTooFewArgs(t *testing.T) {
// Ask "go list" for the location of the crypto/internal/fips140 tree, as it
// might be the unpacked frozen tree selected with GOFIPS140.
cmd := testenv.Command(t, testenv.GoToolPath(t), "list", "-f", `{{.Dir}}`, "crypto/internal/fips140")
- out, err := cmd.CombinedOutput()
+ out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
if err != nil {
t.Fatalf("go list: %v\n%s", err, out)
}
func TestCASTPasses(t *testing.T) {
moduleStatus(t)
- testenv.MustHaveExec(t)
cryptotest.MustSupportFIPS140(t)
cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^TestConditionals$", "-test.v")
- cmd.Env = append(cmd.Env, "GODEBUG=fips140=debug")
+ cmd.Env = append(cmd.Environ(), "GODEBUG=fips140=debug")
out, err := cmd.CombinedOutput()
- t.Logf("%s", out)
+ t.Logf("running with GODEBUG=fips140=debug:\n%s", out)
if err != nil || !strings.Contains(string(out), "completed successfully") {
t.Errorf("TestConditionals did not complete successfully")
}
func TestCASTFailures(t *testing.T) {
moduleStatus(t)
- testenv.MustHaveExec(t)
cryptotest.MustSupportFIPS140(t)
for _, name := range allCASTs {
}
t.Logf("Testing CAST/PCT failure...")
cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^TestConditionals$", "-test.v")
- cmd.Env = append(cmd.Env, fmt.Sprintf("GODEBUG=failfipscast=%s,fips140=on", name))
+ GODEBUG := fmt.Sprintf("GODEBUG=failfipscast=%s,fips140=on", name)
+ cmd.Env = append(cmd.Environ(), GODEBUG)
out, err := cmd.CombinedOutput()
- t.Logf("%s", out)
+ t.Logf("running with %s:\n%s", GODEBUG, out)
if err == nil {
- t.Fatal("Test did not fail as expected")
+ t.Fatal("test did not fail as expected")
}
if strings.Contains(string(out), "completed successfully") {
t.Errorf("CAST/PCT %s failure did not stop the program", name)
func TestIntegrityCheckFailure(t *testing.T) {
moduleStatus(t)
- testenv.MustHaveExec(t)
cryptotest.MustSupportFIPS140(t)
bin, err := os.ReadFile(os.Args[0])
cmd := testenv.Command(t, binPath, "-test.v", "-test.run=^TestIntegrityCheck$")
cmd.Env = append(cmd.Environ(), "GODEBUG=fips140=on")
out, err := cmd.CombinedOutput()
- t.Logf("%s", out)
+ t.Logf("running with GODEBUG=fips140=on:\n%s", out)
if err == nil {
t.Errorf("modified binary did not fail as expected")
}
if testing.Short() {
t.Skip("skipping test in short mode")
}
- testenv.MustHaveExec(t)
+ testenv.MustHaveExec(t) // testenv.Command can't skip from a goroutine
done := make(chan struct{})
go func() {
cmd := testenv.Command(t, testenv.Executable(t), "-test.v")
cmd.Env = append(os.Environ(), "GO_GETRANDOM_DISABLED=1")
out, err := cmd.CombinedOutput()
+ t.Logf("running with GO_GETRANDOM_DISABLED=1:\n%s", out)
if err != nil {
- t.Errorf("subprocess failed: %v\n%s", err, out)
+ t.Errorf("subprocess failed: %v", err)
return
}
if testing.Short() {
t.Skip("skipping test in short mode")
}
- testenv.MustHaveExec(t)
// We run this test in a subprocess because it's expected to crash.
if os.Getenv("GO_TEST_READ_ERROR") == "1" {
return
}
- cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^TestReadError$")
+ cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^TestReadError$", "-test.v")
cmd.Env = append(os.Environ(), "GO_TEST_READ_ERROR=1")
out, err := cmd.CombinedOutput()
if err == nil {
"internal/testenv"
"log"
"os"
- "os/exec"
"strings"
"testing"
)
// such as TinyGo. See also the "crypto/...:purego" test in cmd/dist, which
// ensures the packages build correctly.
func TestPureGoTag(t *testing.T) {
- cmd := exec.Command(testenv.GoToolPath(t), "list", "-e", "crypto/...", "math/big")
- cmd.Env = append(cmd.Env, "GOOS=linux")
+ cmd := testenv.Command(t, testenv.GoToolPath(t), "list", "-e", "crypto/...", "math/big")
+ cmd = testenv.CleanCmdEnv(cmd)
+ cmd.Env = append(cmd.Environ(), "GOOS=linux", "GOFIPS140=off")
cmd.Stderr = os.Stderr
out, err := cmd.Output()
if err != nil {
}
pkgs := strings.Split(strings.TrimSpace(string(out)), "\n")
- cmd = exec.Command(testenv.GoToolPath(t), "tool", "dist", "list")
+ cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "dist", "list")
cmd.Stderr = os.Stderr
- out, err = cmd.Output()
+ out, err = testenv.CleanCmdEnv(cmd).Output()
if err != nil {
log.Fatalf("loading architecture list: %v\n%s", err, out)
}
return
}
- cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^TestReadError$")
+ cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^TestReadError$", "-test.v")
cmd.Env = append(os.Environ(), "GO_TEST_READ_ERROR=1")
out, err := cmd.CombinedOutput()
if err == nil {
}
func TestBogoSuite(t *testing.T) {
- testenv.MustHaveGoBuild(t)
if testing.Short() {
t.Skip("skipping in short mode")
}
}
cmd := testenv.Command(t, testenv.GoToolPath(t), args...)
- out := &strings.Builder{}
- cmd.Stderr = out
cmd.Dir = filepath.Join(bogoDir, "ssl/test/runner")
- err = cmd.Run()
+ out, err := cmd.CombinedOutput()
// NOTE: we don't immediately check the error, because the failure could be either because
// the runner failed for some unexpected reason, or because a test case failed, and we
// cannot easily differentiate these cases. We check if the JSON results file was written,
}
t.Logf("using fresh local bogo checkout from %q", localBogoDir)
- return
}
func generateReport(results bogoResults, outPath string) error {
"bytes"
"internal/testenv"
"os"
- "os/exec"
"path/filepath"
"testing"
)
t.Skip("skipping in short mode")
}
t.Parallel()
- goBin := testenv.GoToolPath(t)
- testenv.MustHaveGoBuild(t)
tests := []struct {
name string
t.Fatal(err)
}
os.Remove(exeFile)
- cmd := exec.Command(goBin, "build", "-o", "x.exe", "x.go")
+ cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", "x.exe", "x.go")
cmd.Dir = tmpDir
if out, err := cmd.CombinedOutput(); err != nil {
- t.Fatalf("compile: %v, %s", err, out)
+ t.Fatalf("compile: %v\n%s", err, out)
}
- cmd = exec.Command(goBin, "tool", "nm", "x.exe")
+ cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "nm", "x.exe")
cmd.Dir = tmpDir
- nm, err := cmd.CombinedOutput()
+ nm, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
if err != nil {
- t.Fatalf("nm: %v, %s", err, nm)
+ t.Fatalf("nm: %v\n%s", err, nm)
}
for _, sym := range tt.want {
if !bytes.Contains(nm, []byte(sym)) {
"export-tests",
"--out", testsJSONPath)
cmd.Dir = bettertlsDir
-
t.Log("running bettertls export-tests command")
- output, err := cmd.CombinedOutput()
- if err != nil {
- t.Fatalf(
- "failed to run bettertls export-tests: %v\nOutput: %s",
- err, output)
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Fatalf("failed to run bettertls export-tests: %v\n%s", err, out)
}
jsonData, err := os.ReadFile(testsJSONPath)
"encoding/hex"
"encoding/pem"
"fmt"
+ "internal/testenv"
"math/big"
"net"
"net/url"
}
args = append(args, leafFile.Name())
- var output bytes.Buffer
- cmd := exec.Command("openssl", args...)
- cmd.Stdout = &output
- cmd.Stderr = &output
-
- err := cmd.Run()
- return output.String(), err
+ cmd := testenv.Command(t, "openssl", args...)
+ out, err := cmd.CombinedOutput()
+ return string(out), err
}
var rfc2821Tests = []struct {
"fmt"
"internal/testenv"
"os"
- "os/exec"
"syscall"
"testing"
)
if testing.Short() {
t.Skip("skipping test in short mode")
}
- testenv.MustHaveExec(t)
test := func(t *testing.T, name string, f func(t *testing.T)) {
t.Run(name, func(t *testing.T) {
if os.Getenv("CRYPTO_X509_SETFALLBACKROOTS_TEST") != "1" {
// Execute test in a separate process with CRYPTO_X509_SETFALBACKROOTS_TEST env.
- cmd := exec.Command(os.Args[0], fmt.Sprintf("-test.run=^%v$", t.Name()))
+ cmd := testenv.Command(t, testenv.Executable(t), fmt.Sprintf("-test.run=^%v$", t.Name()), "-test.v")
cmd.Env = append(os.Environ(), "CRYPTO_X509_SETFALLBACKROOTS_TEST=1")
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWNS | syscall.CLONE_NEWUSER,
GidMappings: []syscall.SysProcIDMap{{ContainerID: 0, HostID: os.Getgid(), Size: 1}},
}
out, err := cmd.CombinedOutput()
+ if testenv.SyscallIsNotSupported(err) {
+ t.Skipf("skipping: could not start process with CLONE_NEWNS and CLONE_NEWUSER: %v", err)
+ }
+ t.Logf("running with CRYPTO_X509_SETFALLBACKROOTS_TEST=1:\n%s", out)
if err != nil {
- if testenv.SyscallIsNotSupported(err) {
- t.Skipf("skipping: could not start process with CLONE_NEWNS and CLONE_NEWUSER: %v", err)
- }
- t.Errorf("%v\n%s", err, out)
+ t.Errorf("CRYPTO_X509_SETFALLBACKROOTS_TEST=1 subprocess failed: %v", err)
}
return
}
"math/big"
"net"
"net/url"
- "os/exec"
"reflect"
"runtime"
"slices"
if testing.Short() {
t.Skip("skipping in -short mode")
}
- testenv.MustHaveGoRun(t)
-
- if out, err := exec.Command(testenv.GoToolPath(t), "run", "x509_test_import.go").CombinedOutput(); err != nil {
+ if out, err := testenv.Command(t, testenv.GoToolPath(t), "run", "x509_test_import.go").CombinedOutput(); err != nil {
t.Errorf("failed to run x509_test_import.go: %s\n%s", err, out)
}
}