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