// 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 ( ) // 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 := fips140.Supported(); != nil { panic("fips140: " + .Error()) } if Linkinfo.Magic[0] != 0xff || string(Linkinfo.Magic[1:]) != fipsMagic || Linkinfo.Sum == zeroSum { panic("fips140: no verification checksum found") } := hmac.New(sha256.New, make([]byte, 32)) := io.Writer() /* // 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) */ .Write([]byte("go fips object v1\n")) var [8]byte for , := range Linkinfo.Sects { := uintptr(.End) - uintptr(.Start) byteorder.BEPutUint64([:], uint64()) .Write([:]) .Write(unsafe.Slice((*byte)(.Start), )) } := .Sum(nil) if [32]byte() != 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() clear([:]) .Reset() if godebug.Value("fips140") == "debug" { println("fips140: verified code+data") } Verified = true }