Source file src/crypto/internal/fips140/check/check.go

     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  		panic("fips140: " + err.Error())
    61  	}
    62  
    63  	if Linkinfo.Magic[0] != 0xff || string(Linkinfo.Magic[1:]) != fipsMagic || Linkinfo.Sum == zeroSum {
    64  		panic("fips140: no verification checksum found")
    65  	}
    66  
    67  	h := hmac.New(sha256.New, make([]byte, 32))
    68  	w := io.Writer(h)
    69  
    70  	/*
    71  		// Uncomment for debugging.
    72  		// Commented (as opposed to a const bool flag)
    73  		// to avoid import "os" in default builds.
    74  		f, err := os.Create("fipscheck.o")
    75  		if err != nil {
    76  			panic(err)
    77  		}
    78  		w = io.MultiWriter(h, f)
    79  	*/
    80  
    81  	w.Write([]byte("go fips object v1\n"))
    82  
    83  	var nbuf [8]byte
    84  	for _, sect := range Linkinfo.Sects {
    85  		n := uintptr(sect.End) - uintptr(sect.Start)
    86  		byteorder.BEPutUint64(nbuf[:], uint64(n))
    87  		w.Write(nbuf[:])
    88  		w.Write(unsafe.Slice((*byte)(sect.Start), n))
    89  	}
    90  	sum := h.Sum(nil)
    91  
    92  	if [32]byte(sum) != Linkinfo.Sum {
    93  		panic("fips140: verification mismatch")
    94  	}
    95  
    96  	// "The temporary value(s) generated during the integrity test of the
    97  	// module’s software or firmware shall [05.10] be zeroised from the module
    98  	// upon completion of the integrity test"
    99  	clear(sum)
   100  	clear(nbuf[:])
   101  	h.Reset()
   102  
   103  	if godebug.Value("#fips140") == "debug" {
   104  		println("fips140: verified code+data")
   105  	}
   106  
   107  	Verified = true
   108  }
   109  

View as plain text