1 // Copyright 2024 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 5 package fips140
6 7 import (
8 "bytes"
9 "crypto/internal/fips140deps/godebug"
10 "errors"
11 _ "unsafe" // for go:linkname
12 )
13 14 // fatal is [runtime.fatal], pushed via linkname.
15 //
16 //go:linkname fatal crypto/internal/fips140.fatal
17 func fatal([]byte)
18 19 // failfipscast is a GODEBUG key allowing simulation of a CAST or PCT failure,
20 // as required during FIPS 140-3 functional testing. The value is the whole name
21 // of the target CAST or PCT.
22 var failfipscast = godebug.Value("#failfipscast")
23 24 // CAST runs the named Cryptographic Algorithm Self-Test (if operated in FIPS
25 // mode) and aborts the program (stopping the module input/output and entering
26 // the "error state") if the self-test fails.
27 //
28 // CASTs are mandatory self-checks that must be performed by FIPS 140-3 modules
29 // before the algorithm is used. See Implementation Guidance 10.3.A.
30 //
31 // The name must not contain commas, colons, hashes, or equal signs.
32 //
33 // If a package p calls CAST from its init function, an import of p should also
34 // be added to crypto/internal/fips140test. If a package p calls CAST on the first
35 // use of the algorithm, an invocation of that algorithm should be added to
36 // fipstest.TestConditionals.
37 func CAST(name []byte, f func() error) {
38 if bytes.ContainsAny(name, ",#=:") {
39 var msg []byte
40 msg = append(msg, "fips: invalid self-test name: "...)
41 msg = append(msg, name...)
42 panic([]byte(msg))
43 }
44 if !Enabled {
45 return
46 }
47 48 err := f()
49 if bytes.Equal(name, failfipscast) {
50 err = errors.New("simulated CAST failure")
51 }
52 if err != nil {
53 var msg []byte
54 msg = append(msg, "FIPS 140-3 self-test failed: "...)
55 msg = append(msg, name...)
56 msg = append(msg, ": "...)
57 msg = append(msg, err.Error()...)
58 fatal(msg)
59 panic("unreachable")
60 }
61 if debug {
62 println("FIPS 140-3 self-test passed:", []byte(name))
63 }
64 }
65 66 // PCT runs the named Pairwise Consistency Test (if operated in FIPS mode) and
67 // aborts the program (stopping the module input/output and entering the "error
68 // state") if the test fails.
69 //
70 // PCTs are mandatory for every generated (but not imported) key pair, including
71 // ephemeral keys (which effectively doubles the cost of key establishment). See
72 // Implementation Guidance 10.3.A Additional Comment 1.
73 //
74 // The name must not contain commas, colons, hashes, or equal signs.
75 //
76 // If a package p calls PCT during key generation, an invocation of that
77 // function should be added to fipstest.TestConditionals.
78 func PCT(name []byte, f func() error) {
79 if bytes.ContainsAny(name, ",#=:") {
80 var msg []byte
81 msg = append(msg, "fips: invalid self-test name: "...)
82 msg = append(msg, name...)
83 panic([]byte(msg))
84 }
85 if !Enabled {
86 return
87 }
88 89 err := f()
90 if bytes.Equal(name, failfipscast) {
91 err = errors.New("simulated PCT failure")
92 }
93 if err != nil {
94 var msg []byte
95 msg = append(msg, "FIPS 140-3 self-test failed: "...)
96 msg = append(msg, name...)
97 msg = append(msg, ": "...)
98 msg = append(msg, err.Error()...)
99 fatal(msg)
100 panic("unreachable")
101 }
102 if debug {
103 println("FIPS 140-3 PCT passed:", []byte(name))
104 }
105 }
106