1
2
3
4
5 package fipstest
6
7 import (
8 "bytes"
9 "crypto/internal/fips140"
10 . "crypto/internal/fips140/check"
11 "crypto/internal/fips140/check/checktest"
12 "fmt"
13 "internal/abi"
14 "internal/godebug"
15 "internal/testenv"
16 "os"
17 "path/filepath"
18 "runtime"
19 "testing"
20 "unicode"
21 "unsafe"
22 )
23
24 func TestIntegrityCheck(t *testing.T) {
25 if Verified {
26 t.Logf("verified")
27 return
28 }
29
30 if godebug.New("fips140").Value() == "on" {
31 t.Fatalf("GODEBUG=fips140=on but verification did not run")
32 }
33
34 if err := fips140.Supported(); err != nil {
35 t.Skipf("skipping: %v", err)
36 }
37
38 cmd := testenv.Command(t, testenv.Executable(t), "-test.v", "-test.run=^TestIntegrityCheck$")
39 cmd.Env = append(cmd.Environ(), "GODEBUG=fips140=on")
40 out, err := cmd.CombinedOutput()
41 if err != nil {
42 t.Fatalf("GODEBUG=fips140=on %v failed: %v\n%s", cmd.Args, err, out)
43 }
44 t.Logf("exec'ed GODEBUG=fips140=on and succeeded:\n%s", out)
45 }
46
47 func TestIntegrityCheckFailure(t *testing.T) {
48 moduleStatus(t)
49 testenv.MustHaveExec(t)
50 if err := fips140.Supported(); err != nil {
51 t.Skipf("skipping: %v", err)
52 }
53
54 bin, err := os.ReadFile(os.Args[0])
55 if err != nil {
56 t.Fatal(err)
57 }
58
59
60 bin = bytes.ReplaceAll(bin, Linkinfo.Sum[:], bytes.Repeat([]byte("X"), len(Linkinfo.Sum)))
61
62 binPath := filepath.Join(t.TempDir(), "fips140test.exe")
63 if err := os.WriteFile(binPath, bin, 0o755); err != nil {
64 t.Fatal(err)
65 }
66
67 if runtime.GOOS == "darwin" {
68
69 cmd := testenv.Command(t, "codesign", "-s", "-", "-f", binPath)
70 out, err := cmd.CombinedOutput()
71 if err != nil {
72 t.Fatalf("codesign failed: %v\n%s", err, out)
73 }
74 }
75
76 t.Logf("running modified binary...")
77 cmd := testenv.Command(t, binPath, "-test.v", "-test.run=^TestIntegrityCheck$")
78 cmd.Env = append(cmd.Environ(), "GODEBUG=fips140=on")
79 out, err := cmd.CombinedOutput()
80 t.Logf("%s", out)
81 if err == nil {
82 t.Errorf("modified binary did not fail as expected")
83 }
84 if !bytes.Contains(out, []byte("fips140: verification mismatch")) {
85 t.Errorf("modified binary did not fail with expected message")
86 }
87 if bytes.Contains(out, []byte("verified")) {
88 t.Errorf("modified binary did not exit")
89 }
90 }
91
92 func TestIntegrityCheckInfo(t *testing.T) {
93 if err := fips140.Supported(); err != nil {
94 t.Skipf("skipping: %v", err)
95 }
96
97
98 if checktest.NOPTRDATA != 1 {
99 t.Errorf("checktest.NOPTRDATA = %d, want 1", checktest.NOPTRDATA)
100 }
101 if checktest.RODATA != 2 {
102 t.Errorf("checktest.RODATA = %d, want 2", checktest.RODATA)
103 }
104 if checktest.DATA.P != &checktest.NOPTRDATA {
105 t.Errorf("checktest.DATA.P = %p, want &checktest.NOPTRDATA (%p)", checktest.DATA.P, &checktest.NOPTRDATA)
106 }
107 if checktest.DATA.X != 3 {
108 t.Errorf("checktest.DATA.X = %d, want 3", checktest.DATA.X)
109 }
110 if checktest.NOPTRBSS != 0 {
111 t.Errorf("checktest.NOPTRBSS = %d, want 0", checktest.NOPTRBSS)
112 }
113 if checktest.BSS != nil {
114 t.Errorf("checktest.BSS = %p, want nil", checktest.BSS)
115 }
116 if p := checktest.PtrStaticData(); p != nil && *p != 10 {
117 t.Errorf("*checktest.PtrStaticData() = %d, want 10", *p)
118 }
119
120
121 sect := func(i int, name string, p unsafe.Pointer) {
122 s := Linkinfo.Sects[i]
123 if !(uintptr(s.Start) <= uintptr(p) && uintptr(p) < uintptr(s.End)) {
124 t.Errorf("checktest.%s (%#x) not in section #%d (%#x..%#x)", name, p, i, s.Start, s.End)
125 }
126 }
127 sect(0, "TEXT", unsafe.Pointer(abi.FuncPCABIInternal(checktest.TEXT)))
128 if p := checktest.PtrStaticText(); p != nil {
129 sect(0, "StaticText", p)
130 }
131 sect(1, "RODATA", unsafe.Pointer(&checktest.RODATA))
132 sect(2, "NOPTRDATA", unsafe.Pointer(&checktest.NOPTRDATA))
133 if p := checktest.PtrStaticData(); p != nil {
134 sect(2, "StaticData", unsafe.Pointer(p))
135 }
136 sect(3, "DATA", unsafe.Pointer(&checktest.DATA))
137
138
139 no := func(name string, p unsafe.Pointer, ix ...int) {
140 for _, i := range ix {
141 s := Linkinfo.Sects[i]
142 if uintptr(s.Start) <= uintptr(p) && uintptr(p) < uintptr(s.End) {
143 t.Errorf("%s (%#x) unexpectedly in section #%d (%#x..%#x)", name, p, i, s.Start, s.End)
144 }
145 }
146 }
147
148
149 no("checktest.TEXT", unsafe.Pointer(abi.FuncPCABIInternal(checktest.TEXT)), 1, 2, 3)
150 no("checktest.RODATA", unsafe.Pointer(&checktest.RODATA), 0, 2, 3)
151 no("checktest.NOPTRDATA", unsafe.Pointer(&checktest.NOPTRDATA), 0, 1, 3)
152 no("checktest.DATA", unsafe.Pointer(&checktest.DATA), 0, 1, 2)
153
154
155 no("fmt.Printf", unsafe.Pointer(abi.FuncPCABIInternal(fmt.Printf)), 0, 1, 2, 3)
156 no("unicode.Categories", unsafe.Pointer(&unicode.Categories), 0, 1, 2, 3)
157 no("unicode.ASCII_Hex_Digit", unsafe.Pointer(&unicode.ASCII_Hex_Digit), 0, 1, 2, 3)
158
159
160
161 n := uintptr(0)
162 for _, s := range Linkinfo.Sects {
163 n += uintptr(s.End) - uintptr(s.Start)
164 }
165 if n < 16*1024 {
166 t.Fatalf("fips sections not big enough: %d, want at least 16 kB", n)
167 }
168 }
169
View as plain text