1
2
3
4
5 package fipstest
6
7 import (
8 "crypto"
9 "crypto/internal/fips140"
10 "crypto/rand"
11 "fmt"
12 "internal/testenv"
13 "io/fs"
14 "os"
15 "regexp"
16 "slices"
17 "strings"
18 "testing"
19
20
21 "crypto/internal/cryptotest"
22 _ "crypto/internal/fips140/aes"
23 _ "crypto/internal/fips140/aes/gcm"
24 _ "crypto/internal/fips140/drbg"
25 "crypto/internal/fips140/ecdh"
26 "crypto/internal/fips140/ecdsa"
27 "crypto/internal/fips140/ed25519"
28 _ "crypto/internal/fips140/hkdf"
29 _ "crypto/internal/fips140/hmac"
30 "crypto/internal/fips140/mlkem"
31 "crypto/internal/fips140/rsa"
32 "crypto/internal/fips140/sha256"
33 _ "crypto/internal/fips140/sha3"
34 _ "crypto/internal/fips140/sha512"
35 _ "crypto/internal/fips140/tls12"
36 _ "crypto/internal/fips140/tls13"
37 )
38
39 var allCASTs = []string{
40 "AES-CBC",
41 "CTR_DRBG",
42 "CounterKDF",
43 "DetECDSA P-256 SHA2-512 sign",
44 "ECDH PCT",
45 "ECDSA P-256 SHA2-512 sign and verify",
46 "ECDSA PCT",
47 "Ed25519 sign and verify",
48 "Ed25519 sign and verify PCT",
49 "HKDF-SHA2-256",
50 "HMAC-SHA2-256",
51 "KAS-ECC-SSC P-256",
52 "ML-DSA sign and verify PCT",
53 "ML-DSA-44",
54 "ML-KEM PCT",
55 "ML-KEM PCT",
56 "ML-KEM-768",
57 "PBKDF2",
58 "RSA sign and verify PCT",
59 "RSASSA-PKCS-v1.5 2048-bit sign and verify",
60 "SHA2-256",
61 "SHA2-512",
62 "TLSv1.2-SHA2-256",
63 "TLSv1.3-SHA2-256",
64 "cSHAKE128",
65 }
66
67 func init() {
68 if fips140.Version() == "v1.0.0" {
69 allCASTs = slices.DeleteFunc(allCASTs, func(s string) bool {
70 return strings.HasPrefix(s, "ML-DSA")
71 })
72 }
73 }
74
75 func TestAllCASTs(t *testing.T) {
76 testenv.MustHaveSource(t)
77
78
79
80 cmd := testenv.Command(t, testenv.GoToolPath(t), "list", "-f", `{{.Dir}}`, "crypto/internal/fips140")
81 out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
82 if err != nil {
83 t.Fatalf("go list: %v\n%s", err, out)
84 }
85 fipsDir := strings.TrimSpace(string(out))
86 t.Logf("FIPS module directory: %s", fipsDir)
87
88
89 var foundCASTs []string
90 castRe := regexp.MustCompile(`fips140\.(CAST|PCT)\("([^"]+)"`)
91 if err := fs.WalkDir(os.DirFS(fipsDir), ".", func(path string, d fs.DirEntry, err error) error {
92 if err != nil {
93 return err
94 }
95 if d.IsDir() || !strings.HasSuffix(path, ".go") {
96 return nil
97 }
98 data, err := os.ReadFile(fipsDir + "/" + path)
99 if err != nil {
100 return err
101 }
102 for _, m := range castRe.FindAllSubmatch(data, -1) {
103 foundCASTs = append(foundCASTs, string(m[2]))
104 }
105 return nil
106 }); err != nil {
107 t.Fatalf("WalkDir: %v", err)
108 }
109
110 slices.Sort(foundCASTs)
111 if !slices.Equal(foundCASTs, allCASTs) {
112 t.Errorf("AllCASTs is out of date. Found CASTs: %#v", foundCASTs)
113 }
114 }
115
116
117 func TestConditionals(t *testing.T) {
118 moduleStatus(t)
119
120 fips140v126Conditionals()
121
122 kMLKEM, err := mlkem.GenerateKey768()
123 if err != nil {
124 t.Error(err)
125 } else {
126
127 kMLKEM.EncapsulationKey().Encapsulate()
128 }
129
130 kDH, err := ecdh.GenerateKey(ecdh.P256(), rand.Reader)
131 if err != nil {
132 t.Error(err)
133 } else {
134
135 ecdh.ECDH(ecdh.P256(), kDH, kDH.PublicKey())
136 }
137
138 kDSA, err := ecdsa.GenerateKey(ecdsa.P256(), rand.Reader)
139 if err != nil {
140 t.Error(err)
141 } else {
142
143 ecdsa.SignDeterministic(ecdsa.P256(), sha256.New, kDSA, make([]byte, 32))
144 }
145
146 k25519, err := ed25519.GenerateKey()
147 if err != nil {
148 t.Error(err)
149 } else {
150
151 ed25519.Sign(k25519, make([]byte, 32))
152 }
153
154 kRSA, err := rsa.GenerateKey(rand.Reader, 2048)
155 if err != nil {
156 t.Error(err)
157 } else {
158
159 rsa.SignPKCS1v15(kRSA, crypto.SHA256.String(), make([]byte, 32))
160 }
161 t.Log("completed successfully")
162 }
163
164 func TestCASTPasses(t *testing.T) {
165 moduleStatus(t)
166 cryptotest.MustSupportFIPS140(t)
167
168 cmd := reexecCommand(t, "fips140=debug", false, "-test.run=^TestConditionals$", "-test.v")
169 out, err := cmd.CombinedOutput()
170 t.Logf("running with GODEBUG=fips140=debug:\n%s", out)
171 if err != nil || !strings.Contains(string(out), "completed successfully") {
172 t.Errorf("TestConditionals did not complete successfully")
173 }
174
175 for _, name := range allCASTs {
176 t.Run(name, func(t *testing.T) {
177 if !strings.Contains(string(out), fmt.Sprintf("passed: %s\n", name)) {
178 t.Errorf("CAST/PCT %s success was not logged", name)
179 } else {
180 t.Logf("CAST/PCT succeeded: %s", name)
181 }
182 })
183 }
184 }
185
186 func TestCASTFailures(t *testing.T) {
187 moduleStatus(t)
188 cryptotest.MustSupportFIPS140(t)
189
190 for _, name := range allCASTs {
191 t.Run(name, func(t *testing.T) {
192
193
194 if !testing.Verbose() {
195 t.Parallel()
196 }
197 t.Logf("Testing CAST/PCT failure...")
198 godebug := fmt.Sprintf("failfipscast=%s,fips140=on", name)
199 cmd := reexecCommand(t, godebug, false, "-test.run=^TestConditionals$", "-test.v")
200 out, err := cmd.CombinedOutput()
201 t.Logf("running with GODEBUG=%s:\n%s", godebug, out)
202 if err == nil {
203 t.Fatal("test did not fail as expected")
204 }
205 if strings.Contains(string(out), "completed successfully") {
206 t.Errorf("CAST/PCT %s failure did not stop the program", name)
207 } else if !strings.Contains(string(out), "self-test failed: "+name) {
208 t.Errorf("CAST/PCT %s failure did not log the expected message", name)
209 } else {
210 t.Logf("CAST/PCT %s failed as expected and caused the program to exit", name)
211 }
212 })
213 }
214 }
215
View as plain text