| // Copyright 2024 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Package check implements the FIPS 140 load-time code+data verification. |
| // Every FIPS package providing cryptographic functionality except hmac and sha256 |
| // must import crypto/internal/fips140/check, so that the verification happens |
| // before initialization of package global variables. |
| // The hmac and sha256 packages are used by this package, so they cannot import it. |
| // Instead, those packages must be careful not to change global variables during init. |
| // (If necessary, we could have check call a PostCheck function in those packages |
| // after the check has completed.) |
| package check |
| |
| import ( |
| "crypto/internal/fips140" |
| "crypto/internal/fips140/hmac" |
| "crypto/internal/fips140/sha256" |
| "crypto/internal/fips140deps/byteorder" |
| "crypto/internal/fips140deps/godebug" |
| "io" |
| "unsafe" |
| ) |
| |
| // Verified is set when verification succeeded. It can be expected to always be |
| // true when [fips140.Enabled] is true, or init would have panicked. |
| var Verified bool |
| |
| // Linkinfo holds the go:fipsinfo symbol prepared by the linker. |
| // See cmd/link/internal/ld/fips.go for details. |
| // |
| //go:linkname Linkinfo go:fipsinfo |
| var Linkinfo struct { |
| Magic [16]byte |
| Sum [32]byte |
| Self uintptr |
| Sects [4]struct { |
| // Note: These must be unsafe.Pointer, not uintptr, |
| // or else checkptr panics about turning uintptrs |
| // into pointers into the data segment during |
| // go test -race. |
| Start unsafe.Pointer |
| End unsafe.Pointer |
| } |
| } |
| |
| // "\xff"+fipsMagic is the expected linkinfo.Magic. |
| // We avoid writing that explicitly so that the string does not appear |
| // elsewhere in normal binaries, just as a precaution. |
| const fipsMagic = " Go fipsinfo \xff\x00" |
| |
| var zeroSum [32]byte |
| |
| func init() { |
| if !fips140.Enabled { |
| return |
| } |
| |
| if err := fips140.Supported(); err != nil { |
| panic("fips140: " + err.Error()) |
| } |
| |
| if Linkinfo.Magic[0] != 0xff || string(Linkinfo.Magic[1:]) != fipsMagic || Linkinfo.Sum == zeroSum { |
| panic("fips140: no verification checksum found") |
| } |
| |
| h := hmac.New(sha256.New, make([]byte, 32)) |
| w := io.Writer(h) |
| |
| /* |
| // Uncomment for debugging. |
| // Commented (as opposed to a const bool flag) |
| // to avoid import "os" in default builds. |
| f, err := os.Create("fipscheck.o") |
| if err != nil { |
| panic(err) |
| } |
| w = io.MultiWriter(h, f) |
| */ |
| |
| w.Write([]byte("go fips object v1\n")) |
| |
| var nbuf [8]byte |
| for _, sect := range Linkinfo.Sects { |
| n := uintptr(sect.End) - uintptr(sect.Start) |
| byteorder.BEPutUint64(nbuf[:], uint64(n)) |
| w.Write(nbuf[:]) |
| w.Write(unsafe.Slice((*byte)(sect.Start), n)) |
| } |
| sum := h.Sum(nil) |
| |
| if [32]byte(sum) != Linkinfo.Sum { |
| panic("fips140: verification mismatch") |
| } |
| |
| // "The temporary value(s) generated during the integrity test of the |
| // module’s software or firmware shall [05.10] be zeroised from the module |
| // upon completion of the integrity test" |
| clear(sum) |
| clear(nbuf[:]) |
| h.Reset() |
| |
| if godebug.Value("fips140") == "debug" { |
| println("fips140: verified code+data") |
| } |
| |
| Verified = true |
| } |