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 check implements the FIPS 140 load-time code+data verification.
6 // Every FIPS package providing cryptographic functionality except hmac and sha256
7 // must import crypto/internal/fips140/check, so that the verification happens
8 // before initialization of package global variables.
9 // The hmac and sha256 packages are used by this package, so they cannot import it.
10 // Instead, those packages must be careful not to change global variables during init.
11 // (If necessary, we could have check call a PostCheck function in those packages
12 // after the check has completed.)
13 package check
14 15 import (
16 "crypto/internal/fips140"
17 "crypto/internal/fips140/hmac"
18 "crypto/internal/fips140/sha256"
19 "crypto/internal/fips140deps/byteorder"
20 "crypto/internal/fips140deps/godebug"
21 "io"
22 "unsafe"
23 )
24 25 // Verified is set when verification succeeded. It can be expected to always be
26 // true when [fips140.Enabled] is true, or init would have panicked.
27 var Verified bool
28 29 // Linkinfo holds the go:fipsinfo symbol prepared by the linker.
30 // See cmd/link/internal/ld/fips.go for details.
31 //
32 //go:linkname Linkinfo go:fipsinfo
33 var Linkinfo struct {
34 Magic [16]byte
35 Sum [32]byte
36 Self uintptr
37 Sects [4]struct {
38 // Note: These must be unsafe.Pointer, not uintptr,
39 // or else checkptr panics about turning uintptrs
40 // into pointers into the data segment during
41 // go test -race.
42 Start unsafe.Pointer
43 End unsafe.Pointer
44 }
45 }
46 47 // "\xff"+fipsMagic is the expected linkinfo.Magic.
48 // We avoid writing that explicitly so that the string does not appear
49 // elsewhere in normal binaries, just as a precaution.
50 const fipsMagic = " Go fipsinfo \xff\x00"
51 52 var zeroSum [32]byte
53 54 func init() {
55 if !fips140.Enabled {
56 return
57 }
58 59 if err := fips140.Supported(); err != nil {
60 var msg []byte
61 msg = append(msg, "fips140: "...)
62 msg = append(msg, err.Error()...)
63 panic(string(msg))
64 }
65 66 if Linkinfo.Magic[0] != 0xff || Linkinfo.Magic[1:] != fipsMagic || Linkinfo.Sum == zeroSum {
67 panic("fips140: no verification checksum found")
68 }
69 70 h := hmac.New(sha256.New, []byte{:32})
71 w := io.Writer(h)
72 73 /*
74 // Uncomment for debugging.
75 // Commented (as opposed to a const bool flag)
76 // to avoid import "os" in default builds.
77 f, err := os.Create("fipscheck.o")
78 if err != nil {
79 panic(err)
80 }
81 w = io.MultiWriter(h, f)
82 */
83 84 w.Write([]byte("go fips object v1\n"))
85 86 var nbuf [8]byte
87 for _, sect := range Linkinfo.Sects {
88 n := uintptr(sect.End) - uintptr(sect.Start)
89 byteorder.BEPutUint64(nbuf[:], uint64(n))
90 w.Write(nbuf[:])
91 w.Write(unsafe.Slice((*byte)(sect.Start), n))
92 }
93 sum := h.Sum(nil)
94 95 if [32]byte(sum) != Linkinfo.Sum {
96 panic("fips140: verification mismatch")
97 }
98 99 // "The temporary value(s) generated during the integrity test of the
100 // module’s software or firmware shall [05.10] be zeroised from the module
101 // upon completion of the integrity test"
102 clear(sum)
103 clear(nbuf[:])
104 h.Reset()
105 106 if godebug.Value("fips140") == "debug" {
107 println("fips140: verified code+data")
108 }
109 110 Verified = true
111 }
112