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