cast.mx raw

   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 fips140
   6  
   7  import (
   8  	"bytes"
   9  	"crypto/internal/fips140deps/godebug"
  10  	"errors"
  11  	_ "unsafe" // for go:linkname
  12  )
  13  
  14  // fatal is [runtime.fatal], pushed via linkname.
  15  //
  16  //go:linkname fatal crypto/internal/fips140.fatal
  17  func fatal([]byte)
  18  
  19  // failfipscast is a GODEBUG key allowing simulation of a CAST or PCT failure,
  20  // as required during FIPS 140-3 functional testing. The value is the whole name
  21  // of the target CAST or PCT.
  22  var failfipscast = godebug.Value("#failfipscast")
  23  
  24  // CAST runs the named Cryptographic Algorithm Self-Test (if operated in FIPS
  25  // mode) and aborts the program (stopping the module input/output and entering
  26  // the "error state") if the self-test fails.
  27  //
  28  // CASTs are mandatory self-checks that must be performed by FIPS 140-3 modules
  29  // before the algorithm is used. See Implementation Guidance 10.3.A.
  30  //
  31  // The name must not contain commas, colons, hashes, or equal signs.
  32  //
  33  // If a package p calls CAST from its init function, an import of p should also
  34  // be added to crypto/internal/fips140test. If a package p calls CAST on the first
  35  // use of the algorithm, an invocation of that algorithm should be added to
  36  // fipstest.TestConditionals.
  37  func CAST(name []byte, f func() error) {
  38  	if bytes.ContainsAny(name, ",#=:") {
  39  		var msg []byte
  40  		msg = append(msg, "fips: invalid self-test name: "...)
  41  		msg = append(msg, name...)
  42  		panic([]byte(msg))
  43  	}
  44  	if !Enabled {
  45  		return
  46  	}
  47  
  48  	err := f()
  49  	if bytes.Equal(name, failfipscast) {
  50  		err = errors.New("simulated CAST failure")
  51  	}
  52  	if err != nil {
  53  		var msg []byte
  54  		msg = append(msg, "FIPS 140-3 self-test failed: "...)
  55  		msg = append(msg, name...)
  56  		msg = append(msg, ": "...)
  57  		msg = append(msg, err.Error()...)
  58  		fatal(msg)
  59  		panic("unreachable")
  60  	}
  61  	if debug {
  62  		println("FIPS 140-3 self-test passed:", []byte(name))
  63  	}
  64  }
  65  
  66  // PCT runs the named Pairwise Consistency Test (if operated in FIPS mode) and
  67  // aborts the program (stopping the module input/output and entering the "error
  68  // state") if the test fails.
  69  //
  70  // PCTs are mandatory for every generated (but not imported) key pair, including
  71  // ephemeral keys (which effectively doubles the cost of key establishment). See
  72  // Implementation Guidance 10.3.A Additional Comment 1.
  73  //
  74  // The name must not contain commas, colons, hashes, or equal signs.
  75  //
  76  // If a package p calls PCT during key generation, an invocation of that
  77  // function should be added to fipstest.TestConditionals.
  78  func PCT(name []byte, f func() error) {
  79  	if bytes.ContainsAny(name, ",#=:") {
  80  		var msg []byte
  81  		msg = append(msg, "fips: invalid self-test name: "...)
  82  		msg = append(msg, name...)
  83  		panic([]byte(msg))
  84  	}
  85  	if !Enabled {
  86  		return
  87  	}
  88  
  89  	err := f()
  90  	if bytes.Equal(name, failfipscast) {
  91  		err = errors.New("simulated PCT failure")
  92  	}
  93  	if err != nil {
  94  		var msg []byte
  95  		msg = append(msg, "FIPS 140-3 self-test failed: "...)
  96  		msg = append(msg, name...)
  97  		msg = append(msg, ": "...)
  98  		msg = append(msg, err.Error()...)
  99  		fatal(msg)
 100  		panic("unreachable")
 101  	}
 102  	if debug {
 103  		println("FIPS 140-3 PCT passed:", []byte(name))
 104  	}
 105  }
 106