mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
crypto/fips140: add WithoutEnforcement
WithoutEnforcement lets programs running under GODEBUG=fips140=only selectively opt out of strict enforcement. This is especially helpful for non-critical uses of cryptography routines like SHA-1 for content addressable storage backends (E.g. git). Fixes #74630 Change-Id: Iabba1f5eb63498db98047aca45e09c5dccf2fbdf Reviewed-on: https://go-review.googlesource.com/c/go/+/723720 Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: Filippo Valsorda <filippo@golang.org> Auto-Submit: Filippo Valsorda <filippo@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Roland Shoemaker <roland@golang.org>
This commit is contained in:
parent
e2cae9ecdf
commit
86bbea0cfa
32 changed files with 252 additions and 61 deletions
2
api/next/74630.txt
Normal file
2
api/next/74630.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
pkg crypto/fips140, func Enforced() bool #74630
|
||||||
|
pkg crypto/fips140, func WithoutEnforcement(func()) #74630
|
||||||
2
doc/next/6-stdlib/99-minor/crypto/fips140/74630.md
Normal file
2
doc/next/6-stdlib/99-minor/crypto/fips140/74630.md
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
The new [WithoutEnforcement] and [Enforced] functions now allow running
|
||||||
|
in `GODEBUG=fips140=only` mode while selectively disabling the strict FIPS 140-3 checks.
|
||||||
|
|
@ -54,7 +54,7 @@ func NewCBCEncrypter(b Block, iv []byte) BlockMode {
|
||||||
if b, ok := b.(*aes.Block); ok {
|
if b, ok := b.(*aes.Block); ok {
|
||||||
return aes.NewCBCEncrypter(b, [16]byte(iv))
|
return aes.NewCBCEncrypter(b, [16]byte(iv))
|
||||||
}
|
}
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
panic("crypto/cipher: use of CBC with non-AES ciphers is not allowed in FIPS 140-only mode")
|
panic("crypto/cipher: use of CBC with non-AES ciphers is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
if cbc, ok := b.(cbcEncAble); ok {
|
if cbc, ok := b.(cbcEncAble); ok {
|
||||||
|
|
@ -133,7 +133,7 @@ func NewCBCDecrypter(b Block, iv []byte) BlockMode {
|
||||||
if b, ok := b.(*aes.Block); ok {
|
if b, ok := b.(*aes.Block); ok {
|
||||||
return aes.NewCBCDecrypter(b, [16]byte(iv))
|
return aes.NewCBCDecrypter(b, [16]byte(iv))
|
||||||
}
|
}
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
panic("crypto/cipher: use of CBC with non-AES ciphers is not allowed in FIPS 140-only mode")
|
panic("crypto/cipher: use of CBC with non-AES ciphers is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
if cbc, ok := b.(cbcDecAble); ok {
|
if cbc, ok := b.(cbcDecAble); ok {
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ func (x *cfb) XORKeyStream(dst, src []byte) {
|
||||||
// CFB is also unoptimized and not validated as part of the FIPS 140-3 module.
|
// CFB is also unoptimized and not validated as part of the FIPS 140-3 module.
|
||||||
// If an unauthenticated [Stream] mode is required, use [NewCTR] instead.
|
// If an unauthenticated [Stream] mode is required, use [NewCTR] instead.
|
||||||
func NewCFBEncrypter(block Block, iv []byte) Stream {
|
func NewCFBEncrypter(block Block, iv []byte) Stream {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
panic("crypto/cipher: use of CFB is not allowed in FIPS 140-only mode")
|
panic("crypto/cipher: use of CFB is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
return newCFB(block, iv, false)
|
return newCFB(block, iv, false)
|
||||||
|
|
@ -77,7 +77,7 @@ func NewCFBEncrypter(block Block, iv []byte) Stream {
|
||||||
// CFB is also unoptimized and not validated as part of the FIPS 140-3 module.
|
// CFB is also unoptimized and not validated as part of the FIPS 140-3 module.
|
||||||
// If an unauthenticated [Stream] mode is required, use [NewCTR] instead.
|
// If an unauthenticated [Stream] mode is required, use [NewCTR] instead.
|
||||||
func NewCFBDecrypter(block Block, iv []byte) Stream {
|
func NewCFBDecrypter(block Block, iv []byte) Stream {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
panic("crypto/cipher: use of CFB is not allowed in FIPS 140-only mode")
|
panic("crypto/cipher: use of CFB is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
return newCFB(block, iv, true)
|
return newCFB(block, iv, true)
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ func NewCTR(block Block, iv []byte) Stream {
|
||||||
if block, ok := block.(*aes.Block); ok {
|
if block, ok := block.(*aes.Block); ok {
|
||||||
return aesCtrWrapper{aes.NewCTR(block, iv)}
|
return aesCtrWrapper{aes.NewCTR(block, iv)}
|
||||||
}
|
}
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
panic("crypto/cipher: use of CTR with non-AES ciphers is not allowed in FIPS 140-only mode")
|
panic("crypto/cipher: use of CTR with non-AES ciphers is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
if ctr, ok := block.(ctrAble); ok {
|
if ctr, ok := block.(ctrAble); ok {
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ const (
|
||||||
// An exception is when the underlying [Block] was created by aes.NewCipher
|
// An exception is when the underlying [Block] was created by aes.NewCipher
|
||||||
// on systems with hardware support for AES. See the [crypto/aes] package documentation for details.
|
// on systems with hardware support for AES. See the [crypto/aes] package documentation for details.
|
||||||
func NewGCM(cipher Block) (AEAD, error) {
|
func NewGCM(cipher Block) (AEAD, error) {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return nil, errors.New("crypto/cipher: use of GCM with arbitrary IVs is not allowed in FIPS 140-only mode, use NewGCMWithRandomNonce")
|
return nil, errors.New("crypto/cipher: use of GCM with arbitrary IVs is not allowed in FIPS 140-only mode, use NewGCMWithRandomNonce")
|
||||||
}
|
}
|
||||||
return newGCM(cipher, gcmStandardNonceSize, gcmTagSize)
|
return newGCM(cipher, gcmStandardNonceSize, gcmTagSize)
|
||||||
|
|
@ -42,7 +42,7 @@ func NewGCM(cipher Block) (AEAD, error) {
|
||||||
// cryptosystem that uses non-standard nonce lengths. All other users should use
|
// cryptosystem that uses non-standard nonce lengths. All other users should use
|
||||||
// [NewGCM], which is faster and more resistant to misuse.
|
// [NewGCM], which is faster and more resistant to misuse.
|
||||||
func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) {
|
func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return nil, errors.New("crypto/cipher: use of GCM with arbitrary IVs is not allowed in FIPS 140-only mode, use NewGCMWithRandomNonce")
|
return nil, errors.New("crypto/cipher: use of GCM with arbitrary IVs is not allowed in FIPS 140-only mode, use NewGCMWithRandomNonce")
|
||||||
}
|
}
|
||||||
return newGCM(cipher, size, gcmTagSize)
|
return newGCM(cipher, size, gcmTagSize)
|
||||||
|
|
@ -57,7 +57,7 @@ func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) {
|
||||||
// cryptosystem that uses non-standard tag lengths. All other users should use
|
// cryptosystem that uses non-standard tag lengths. All other users should use
|
||||||
// [NewGCM], which is more resistant to misuse.
|
// [NewGCM], which is more resistant to misuse.
|
||||||
func NewGCMWithTagSize(cipher Block, tagSize int) (AEAD, error) {
|
func NewGCMWithTagSize(cipher Block, tagSize int) (AEAD, error) {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return nil, errors.New("crypto/cipher: use of GCM with arbitrary IVs is not allowed in FIPS 140-only mode, use NewGCMWithRandomNonce")
|
return nil, errors.New("crypto/cipher: use of GCM with arbitrary IVs is not allowed in FIPS 140-only mode, use NewGCMWithRandomNonce")
|
||||||
}
|
}
|
||||||
return newGCM(cipher, gcmStandardNonceSize, tagSize)
|
return newGCM(cipher, gcmStandardNonceSize, tagSize)
|
||||||
|
|
@ -66,7 +66,7 @@ func NewGCMWithTagSize(cipher Block, tagSize int) (AEAD, error) {
|
||||||
func newGCM(cipher Block, nonceSize, tagSize int) (AEAD, error) {
|
func newGCM(cipher Block, nonceSize, tagSize int) (AEAD, error) {
|
||||||
c, ok := cipher.(*aes.Block)
|
c, ok := cipher.(*aes.Block)
|
||||||
if !ok {
|
if !ok {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return nil, errors.New("crypto/cipher: use of GCM with non-AES ciphers is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/cipher: use of GCM with non-AES ciphers is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
return newGCMFallback(cipher, nonceSize, tagSize)
|
return newGCMFallback(cipher, nonceSize, tagSize)
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ type ofb struct {
|
||||||
// OFB is also unoptimized and not validated as part of the FIPS 140-3 module.
|
// OFB is also unoptimized and not validated as part of the FIPS 140-3 module.
|
||||||
// If an unauthenticated [Stream] mode is required, use [NewCTR] instead.
|
// If an unauthenticated [Stream] mode is required, use [NewCTR] instead.
|
||||||
func NewOFB(b Block, iv []byte) Stream {
|
func NewOFB(b Block, iv []byte) Stream {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
panic("crypto/cipher: use of OFB is not allowed in FIPS 140-only mode")
|
panic("crypto/cipher: use of OFB is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ type desCipher struct {
|
||||||
|
|
||||||
// NewCipher creates and returns a new [cipher.Block].
|
// NewCipher creates and returns a new [cipher.Block].
|
||||||
func NewCipher(key []byte) (cipher.Block, error) {
|
func NewCipher(key []byte) (cipher.Block, error) {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return nil, errors.New("crypto/des: use of DES is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/des: use of DES is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,7 +77,7 @@ type tripleDESCipher struct {
|
||||||
|
|
||||||
// NewTripleDESCipher creates and returns a new [cipher.Block].
|
// NewTripleDESCipher creates and returns a new [cipher.Block].
|
||||||
func NewTripleDESCipher(key []byte) (cipher.Block, error) {
|
func NewTripleDESCipher(key []byte) (cipher.Block, error) {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return nil, errors.New("crypto/des: use of TripleDES is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/des: use of TripleDES is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ const numMRTests = 64
|
||||||
// GenerateParameters puts a random, valid set of DSA parameters into params.
|
// GenerateParameters puts a random, valid set of DSA parameters into params.
|
||||||
// This function can take many seconds, even on fast machines.
|
// This function can take many seconds, even on fast machines.
|
||||||
func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) error {
|
func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) error {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return errors.New("crypto/dsa: use of DSA is not allowed in FIPS 140-only mode")
|
return errors.New("crypto/dsa: use of DSA is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -162,7 +162,7 @@ GeneratePrimes:
|
||||||
// GenerateKey generates a public&private key pair. The Parameters of the
|
// GenerateKey generates a public&private key pair. The Parameters of the
|
||||||
// [PrivateKey] must already be valid (see [GenerateParameters]).
|
// [PrivateKey] must already be valid (see [GenerateParameters]).
|
||||||
func GenerateKey(priv *PrivateKey, rand io.Reader) error {
|
func GenerateKey(priv *PrivateKey, rand io.Reader) error {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return errors.New("crypto/dsa: use of DSA is not allowed in FIPS 140-only mode")
|
return errors.New("crypto/dsa: use of DSA is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,7 +212,7 @@ func fermatInverse(k, P *big.Int) *big.Int {
|
||||||
// Be aware that calling Sign with an attacker-controlled [PrivateKey] may
|
// Be aware that calling Sign with an attacker-controlled [PrivateKey] may
|
||||||
// require an arbitrary amount of CPU.
|
// require an arbitrary amount of CPU.
|
||||||
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
|
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return nil, nil, errors.New("crypto/dsa: use of DSA is not allowed in FIPS 140-only mode")
|
return nil, nil, errors.New("crypto/dsa: use of DSA is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -284,7 +284,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
|
||||||
// to the byte-length of the subgroup. This function does not perform that
|
// to the byte-length of the subgroup. This function does not perform that
|
||||||
// truncation itself.
|
// truncation itself.
|
||||||
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
|
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
panic("crypto/dsa: use of DSA is not allowed in FIPS 140-only mode")
|
panic("crypto/dsa: use of DSA is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ func (c *nistCurve) GenerateKey(rand io.Reader) (*PrivateKey, error) {
|
||||||
return k, nil
|
return k, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) {
|
if fips140only.Enforced() && !fips140only.ApprovedRandomReader(rand) {
|
||||||
return nil, errors.New("crypto/ecdh: only crypto/rand.Reader is allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/ecdh: only crypto/rand.Reader is allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ func (c *x25519Curve) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *x25519Curve) GenerateKey(rand io.Reader) (*PrivateKey, error) {
|
func (c *x25519Curve) GenerateKey(rand io.Reader) (*PrivateKey, error) {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
key := make([]byte, x25519PrivateKeySize)
|
key := make([]byte, x25519PrivateKeySize)
|
||||||
|
|
@ -47,7 +47,7 @@ func (c *x25519Curve) GenerateKey(rand io.Reader) (*PrivateKey, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *x25519Curve) NewPrivateKey(key []byte) (*PrivateKey, error) {
|
func (c *x25519Curve) NewPrivateKey(key []byte) (*PrivateKey, error) {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
if len(key) != x25519PrivateKeySize {
|
if len(key) != x25519PrivateKeySize {
|
||||||
|
|
@ -67,7 +67,7 @@ func (c *x25519Curve) NewPrivateKey(key []byte) (*PrivateKey, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *x25519Curve) NewPublicKey(key []byte) (*PublicKey, error) {
|
func (c *x25519Curve) NewPublicKey(key []byte) (*PublicKey, error) {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
if len(key) != x25519PublicKeySize {
|
if len(key) != x25519PublicKeySize {
|
||||||
|
|
|
||||||
|
|
@ -358,7 +358,7 @@ func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateFIPS[P ecdsa.Point[P]](curve elliptic.Curve, c *ecdsa.Curve[P], rand io.Reader) (*PrivateKey, error) {
|
func generateFIPS[P ecdsa.Point[P]](curve elliptic.Curve, c *ecdsa.Curve[P], rand io.Reader) (*PrivateKey, error) {
|
||||||
if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) {
|
if fips140only.Enforced() && !fips140only.ApprovedRandomReader(rand) {
|
||||||
return nil, errors.New("crypto/ecdsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/ecdsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
privateKey, err := ecdsa.GenerateKey(c, rand)
|
privateKey, err := ecdsa.GenerateKey(c, rand)
|
||||||
|
|
@ -403,7 +403,7 @@ func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func signFIPS[P ecdsa.Point[P]](c *ecdsa.Curve[P], priv *PrivateKey, rand io.Reader, hash []byte) ([]byte, error) {
|
func signFIPS[P ecdsa.Point[P]](c *ecdsa.Curve[P], priv *PrivateKey, rand io.Reader, hash []byte) ([]byte, error) {
|
||||||
if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) {
|
if fips140only.Enforced() && !fips140only.ApprovedRandomReader(rand) {
|
||||||
return nil, errors.New("crypto/ecdsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/ecdsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
k, err := privateKeyToFIPS(c, priv)
|
k, err := privateKeyToFIPS(c, priv)
|
||||||
|
|
@ -448,7 +448,7 @@ func signFIPSDeterministic[P ecdsa.Point[P]](c *ecdsa.Curve[P], hashFunc crypto.
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
h := fips140hash.UnwrapNew(hashFunc.New)
|
h := fips140hash.UnwrapNew(hashFunc.New)
|
||||||
if fips140only.Enabled && !fips140only.ApprovedHash(h()) {
|
if fips140only.Enforced() && !fips140only.ApprovedHash(h()) {
|
||||||
return nil, errors.New("crypto/ecdsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/ecdsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
sig, err := ecdsa.SignDeterministic(c, h, k, hash)
|
sig, err := ecdsa.SignDeterministic(c, h, k, hash)
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import (
|
||||||
// deprecated custom curves.
|
// deprecated custom curves.
|
||||||
|
|
||||||
func generateLegacy(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
|
func generateLegacy(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return nil, errors.New("crypto/ecdsa: use of custom curves is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/ecdsa: use of custom curves is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,7 +81,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
|
||||||
}
|
}
|
||||||
|
|
||||||
func signLegacy(priv *PrivateKey, csprng io.Reader, hash []byte) (sig []byte, err error) {
|
func signLegacy(priv *PrivateKey, csprng io.Reader, hash []byte) (sig []byte, err error) {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return nil, errors.New("crypto/ecdsa: use of custom curves is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/ecdsa: use of custom curves is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,7 +153,7 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyLegacy(pub *PublicKey, hash []byte, sig []byte) bool {
|
func verifyLegacy(pub *PublicKey, hash []byte, sig []byte) bool {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
panic("crypto/ecdsa: use of custom curves is not allowed in FIPS 140-only mode")
|
panic("crypto/ecdsa: use of custom curves is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOp
|
||||||
case hash == crypto.SHA512: // Ed25519ph
|
case hash == crypto.SHA512: // Ed25519ph
|
||||||
return ed25519.SignPH(k, message, context)
|
return ed25519.SignPH(k, message, context)
|
||||||
case hash == crypto.Hash(0) && context != "": // Ed25519ctx
|
case hash == crypto.Hash(0) && context != "": // Ed25519ctx
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return nil, errors.New("crypto/ed25519: use of Ed25519ctx is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/ed25519: use of Ed25519ctx is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
return ed25519.SignCtx(k, message, context)
|
return ed25519.SignCtx(k, message, context)
|
||||||
|
|
@ -230,7 +230,7 @@ func VerifyWithOptions(publicKey PublicKey, message, sig []byte, opts *Options)
|
||||||
case opts.Hash == crypto.SHA512: // Ed25519ph
|
case opts.Hash == crypto.SHA512: // Ed25519ph
|
||||||
return ed25519.VerifyPH(k, message, sig, opts.Context)
|
return ed25519.VerifyPH(k, message, sig, opts.Context)
|
||||||
case opts.Hash == crypto.Hash(0) && opts.Context != "": // Ed25519ctx
|
case opts.Hash == crypto.Hash(0) && opts.Context != "": // Ed25519ctx
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return errors.New("crypto/ed25519: use of Ed25519ctx is not allowed in FIPS 140-only mode")
|
return errors.New("crypto/ed25519: use of Ed25519ctx is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
return ed25519.VerifyCtx(k, message, sig, opts.Context)
|
return ed25519.VerifyCtx(k, message, sig, opts.Context)
|
||||||
|
|
|
||||||
47
src/crypto/fips140/enforcement.go
Normal file
47
src/crypto/fips140/enforcement.go
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
// Copyright 2025 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 fips140
|
||||||
|
|
||||||
|
import (
|
||||||
|
"internal/godebug"
|
||||||
|
_ "unsafe" // for linkname
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithoutEnforcement disables strict FIPS 140-3 enforcement while executing f.
|
||||||
|
// Calling WithoutEnforcement without strict enforcement enabled
|
||||||
|
// (GODEBUG=fips140=only is not set or already inside of a call to
|
||||||
|
// WithoutEnforcement) is a no-op.
|
||||||
|
//
|
||||||
|
// WithoutEnforcement is inherited by any goroutines spawned while executing f.
|
||||||
|
//
|
||||||
|
// As this disables enforcement, it should be applied carefully to tightly
|
||||||
|
// scoped functions.
|
||||||
|
func WithoutEnforcement(f func()) {
|
||||||
|
if !Enabled() || !Enforced() {
|
||||||
|
f()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setBypass()
|
||||||
|
defer unsetBypass()
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
|
||||||
|
var enabled = godebug.New("fips140").Value() == "only"
|
||||||
|
|
||||||
|
// Enforced indicates if strict FIPS 140-3 enforcement is enabled. Strict
|
||||||
|
// enforcement is enabled when a program is run with GODEBUG=fips140=only and
|
||||||
|
// enforcement has not been disabled by a call to [WithoutEnforcement].
|
||||||
|
func Enforced() bool {
|
||||||
|
return enabled && !isBypassed()
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname setBypass
|
||||||
|
func setBypass()
|
||||||
|
|
||||||
|
//go:linkname isBypassed
|
||||||
|
func isBypassed() bool
|
||||||
|
|
||||||
|
//go:linkname unsetBypass
|
||||||
|
func unsetBypass()
|
||||||
46
src/crypto/fips140/enforcement_test.go
Normal file
46
src/crypto/fips140/enforcement_test.go
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright 2025 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 fips140_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/internal/cryptotest"
|
||||||
|
"internal/testenv"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWithoutEnforcement(t *testing.T) {
|
||||||
|
testenv.MustHaveExec(t)
|
||||||
|
testenv.MustHaveGoBuild(t)
|
||||||
|
cryptotest.MustSupportFIPS140(t)
|
||||||
|
|
||||||
|
tool, _ := testenv.GoTool()
|
||||||
|
tmpdir := t.TempDir()
|
||||||
|
binFile := filepath.Join(tmpdir, "fips140.test")
|
||||||
|
cmd := testenv.Command(t, tool, "test", "-c", "-o", binFile, "./testdata")
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Log(string(out))
|
||||||
|
t.Errorf("Could not build enforcement tests")
|
||||||
|
}
|
||||||
|
cmd = testenv.Command(t, binFile, "-test.list", ".")
|
||||||
|
list, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Log(string(out))
|
||||||
|
t.Errorf("Could not get enforcement test list")
|
||||||
|
}
|
||||||
|
for test := range strings.Lines(string(list)) {
|
||||||
|
test = strings.TrimSpace(test)
|
||||||
|
t.Run(test, func(t *testing.T) {
|
||||||
|
cmd = testenv.Command(t, binFile, "-test.run", "^"+test+"$")
|
||||||
|
cmd.Env = append(cmd.Env, "GODEBUG=fips140=only")
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(string(out))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
65
src/crypto/fips140/testdata/enforcement_test.go
vendored
Normal file
65
src/crypto/fips140/testdata/enforcement_test.go
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
// Copyright 2025 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 fips140_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/des"
|
||||||
|
"crypto/fips140"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func expectAllowed(t *testing.T, why string, expected bool) {
|
||||||
|
t.Helper()
|
||||||
|
result := isAllowed()
|
||||||
|
if result != expected {
|
||||||
|
t.Fatalf("%v: expected: %v, got: %v", why, expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isAllowed() bool {
|
||||||
|
_, err := des.NewCipher(make([]byte, 8))
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDisabled(t *testing.T) {
|
||||||
|
expectAllowed(t, "before enforcement disabled", false)
|
||||||
|
fips140.WithoutEnforcement(func() {
|
||||||
|
expectAllowed(t, "inside WithoutEnforcement", true)
|
||||||
|
})
|
||||||
|
// make sure that bypass doesn't live on after returning
|
||||||
|
expectAllowed(t, "after WithoutEnforcement", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNested(t *testing.T) {
|
||||||
|
expectAllowed(t, "before enforcement bypass", false)
|
||||||
|
fips140.WithoutEnforcement(func() {
|
||||||
|
fips140.WithoutEnforcement(func() {
|
||||||
|
expectAllowed(t, "inside nested WithoutEnforcement", true)
|
||||||
|
})
|
||||||
|
expectAllowed(t, "inside nested WithoutEnforcement", true)
|
||||||
|
})
|
||||||
|
expectAllowed(t, "after enforcement bypass", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGoroutineInherit(t *testing.T) {
|
||||||
|
ch := make(chan bool, 2)
|
||||||
|
expectAllowed(t, "before enforcement bypass", false)
|
||||||
|
fips140.WithoutEnforcement(func() {
|
||||||
|
go func() {
|
||||||
|
ch <- isAllowed()
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
allowed := <-ch
|
||||||
|
if !allowed {
|
||||||
|
t.Fatal("goroutine didn't inherit enforcement bypass")
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
ch <- isAllowed()
|
||||||
|
}()
|
||||||
|
allowed = <-ch
|
||||||
|
if allowed {
|
||||||
|
t.Fatal("goroutine inherited bypass after WithoutEnforcement return")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -71,7 +71,7 @@ func Key[Hash hash.Hash](h func() Hash, secret, salt []byte, info string, keyLen
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkFIPS140Only[Hash hash.Hash](h func() Hash, key []byte) error {
|
func checkFIPS140Only[Hash hash.Hash](h func() Hash, key []byte) error {
|
||||||
if !fips140only.Enabled {
|
if !fips140only.Enforced() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if len(key) < 112/8 {
|
if len(key) < 112/8 {
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ func New(h func() hash.Hash, key []byte) hash.Hash {
|
||||||
// BoringCrypto did not recognize h, so fall through to standard Go code.
|
// BoringCrypto did not recognize h, so fall through to standard Go code.
|
||||||
}
|
}
|
||||||
h = fips140hash.UnwrapNew(h)
|
h = fips140hash.UnwrapNew(h)
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
if len(key) < 112/8 {
|
if len(key) < 112/8 {
|
||||||
panic("crypto/hmac: use of keys shorter than 112 bits is not allowed in FIPS 140-only mode")
|
panic("crypto/hmac: use of keys shorter than 112 bits is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,18 +5,20 @@
|
||||||
package fips140only
|
package fips140only
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/fips140"
|
||||||
"crypto/internal/fips140/drbg"
|
"crypto/internal/fips140/drbg"
|
||||||
"crypto/internal/fips140/sha256"
|
"crypto/internal/fips140/sha256"
|
||||||
"crypto/internal/fips140/sha3"
|
"crypto/internal/fips140/sha3"
|
||||||
"crypto/internal/fips140/sha512"
|
"crypto/internal/fips140/sha512"
|
||||||
"hash"
|
"hash"
|
||||||
"internal/godebug"
|
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Enabled reports whether FIPS 140-only mode is enabled, in which non-approved
|
// Enforced reports whether FIPS 140-only mode is enabled and enforced, in which non-approved
|
||||||
// cryptography returns an error or panics.
|
// cryptography returns an error or panics.
|
||||||
var Enabled = godebug.New("fips140").Value() == "only"
|
func Enforced() bool {
|
||||||
|
return fips140.Enforced()
|
||||||
|
}
|
||||||
|
|
||||||
func ApprovedHash(h hash.Hash) bool {
|
func ApprovedHash(h hash.Hash) bool {
|
||||||
switch h.(type) {
|
switch h.(type) {
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ func (d *digest) Size() int { return Size }
|
||||||
func (d *digest) BlockSize() int { return BlockSize }
|
func (d *digest) BlockSize() int { return BlockSize }
|
||||||
|
|
||||||
func (d *digest) Write(p []byte) (nn int, err error) {
|
func (d *digest) Write(p []byte) (nn int, err error) {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return 0, errors.New("crypto/md5: use of MD5 is not allowed in FIPS 140-only mode")
|
return 0, errors.New("crypto/md5: use of MD5 is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
// Note that we currently call block or blockGeneric
|
// Note that we currently call block or blockGeneric
|
||||||
|
|
@ -173,7 +173,7 @@ func (d *digest) Sum(in []byte) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *digest) checkSum() [Size]byte {
|
func (d *digest) checkSum() [Size]byte {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
panic("crypto/md5: use of MD5 is not allowed in FIPS 140-only mode")
|
panic("crypto/md5: use of MD5 is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ import (
|
||||||
// Setting keyLength to a value outside of this range will result in an error.
|
// Setting keyLength to a value outside of this range will result in an error.
|
||||||
func Key[Hash hash.Hash](h func() Hash, password string, salt []byte, iter, keyLength int) ([]byte, error) {
|
func Key[Hash hash.Hash](h func() Hash, password string, salt []byte, iter, keyLength int) ([]byte, error) {
|
||||||
fh := fips140hash.UnwrapNew(h)
|
fh := fips140hash.UnwrapNew(h)
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
if keyLength < 112/8 {
|
if keyLength < 112/8 {
|
||||||
return nil, errors.New("crypto/pbkdf2: use of keys shorter than 112 bits is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/pbkdf2: use of keys shorter than 112 bits is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import (
|
||||||
// Prime returns a number of the given bit length that is prime with high probability.
|
// Prime returns a number of the given bit length that is prime with high probability.
|
||||||
// Prime will return error for any error returned by rand.Read or if bits < 2.
|
// Prime will return error for any error returned by rand.Read or if bits < 2.
|
||||||
func Prime(rand io.Reader, bits int) (*big.Int, error) {
|
func Prime(rand io.Reader, bits int) (*big.Int, error) {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return nil, errors.New("crypto/rand: use of Prime is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/rand: use of Prime is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
if bits < 2 {
|
if bits < 2 {
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ func (k KeySizeError) Error() string {
|
||||||
// NewCipher creates and returns a new [Cipher]. The key argument should be the
|
// NewCipher creates and returns a new [Cipher]. The key argument should be the
|
||||||
// RC4 key, at least 1 byte and at most 256 bytes.
|
// RC4 key, at least 1 byte and at most 256 bytes.
|
||||||
func NewCipher(key []byte) (*Cipher, error) {
|
func NewCipher(key []byte) (*Cipher, error) {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return nil, errors.New("crypto/rc4: use of RC4 is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/rc4: use of RC4 is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
k := len(key)
|
k := len(key)
|
||||||
|
|
|
||||||
|
|
@ -84,10 +84,10 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte,
|
||||||
if err := checkFIPS140OnlyPrivateKey(priv); err != nil {
|
if err := checkFIPS140OnlyPrivateKey(priv); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if fips140only.Enabled && !fips140only.ApprovedHash(h) {
|
if fips140only.Enforced() && !fips140only.ApprovedHash(h) {
|
||||||
return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) {
|
if fips140only.Enforced() && !fips140only.ApprovedRandomReader(rand) {
|
||||||
return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,7 +97,7 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte,
|
||||||
}
|
}
|
||||||
|
|
||||||
saltLength := opts.saltLength()
|
saltLength := opts.saltLength()
|
||||||
if fips140only.Enabled && saltLength > h.Size() {
|
if fips140only.Enforced() && saltLength > h.Size() {
|
||||||
return nil, errors.New("crypto/rsa: use of PSS salt longer than the hash is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/rsa: use of PSS salt longer than the hash is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
switch saltLength {
|
switch saltLength {
|
||||||
|
|
@ -149,7 +149,7 @@ func VerifyPSS(pub *PublicKey, hash crypto.Hash, digest []byte, sig []byte, opts
|
||||||
if err := checkFIPS140OnlyPublicKey(pub); err != nil {
|
if err := checkFIPS140OnlyPublicKey(pub); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if fips140only.Enabled && !fips140only.ApprovedHash(h) {
|
if fips140only.Enforced() && !fips140only.ApprovedHash(h) {
|
||||||
return errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
|
return errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,7 +159,7 @@ func VerifyPSS(pub *PublicKey, hash crypto.Hash, digest []byte, sig []byte, opts
|
||||||
}
|
}
|
||||||
|
|
||||||
saltLength := opts.saltLength()
|
saltLength := opts.saltLength()
|
||||||
if fips140only.Enabled && saltLength > h.Size() {
|
if fips140only.Enforced() && saltLength > h.Size() {
|
||||||
return errors.New("crypto/rsa: use of PSS salt longer than the hash is not allowed in FIPS 140-only mode")
|
return errors.New("crypto/rsa: use of PSS salt longer than the hash is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
switch saltLength {
|
switch saltLength {
|
||||||
|
|
@ -234,10 +234,10 @@ func encryptOAEP(hash hash.Hash, mgfHash hash.Hash, random io.Reader, pub *Publi
|
||||||
if err := checkFIPS140OnlyPublicKey(pub); err != nil {
|
if err := checkFIPS140OnlyPublicKey(pub); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if fips140only.Enabled && !fips140only.ApprovedHash(hash) {
|
if fips140only.Enforced() && !fips140only.ApprovedHash(hash) {
|
||||||
return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
if fips140only.Enabled && !fips140only.ApprovedRandomReader(random) {
|
if fips140only.Enforced() && !fips140only.ApprovedRandomReader(random) {
|
||||||
return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -291,7 +291,7 @@ func decryptOAEP(hash, mgfHash hash.Hash, priv *PrivateKey, ciphertext []byte, l
|
||||||
if err := checkFIPS140OnlyPrivateKey(priv); err != nil {
|
if err := checkFIPS140OnlyPrivateKey(priv); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
if !fips140only.ApprovedHash(hash) || !fips140only.ApprovedHash(mgfHash) {
|
if !fips140only.ApprovedHash(hash) || !fips140only.ApprovedHash(mgfHash) {
|
||||||
return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
@ -341,7 +341,7 @@ func SignPKCS1v15(random io.Reader, priv *PrivateKey, hash crypto.Hash, hashed [
|
||||||
if err := checkFIPS140OnlyPrivateKey(priv); err != nil {
|
if err := checkFIPS140OnlyPrivateKey(priv); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if fips140only.Enabled && !fips140only.ApprovedHash(fips140hash.Unwrap(hash.New())) {
|
if fips140only.Enforced() && !fips140only.ApprovedHash(fips140hash.Unwrap(hash.New())) {
|
||||||
return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -387,7 +387,7 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte)
|
||||||
if err := checkFIPS140OnlyPublicKey(pub); err != nil {
|
if err := checkFIPS140OnlyPublicKey(pub); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if fips140only.Enabled && !fips140only.ApprovedHash(fips140hash.Unwrap(hash.New())) {
|
if fips140only.Enforced() && !fips140only.ApprovedHash(fips140hash.Unwrap(hash.New())) {
|
||||||
return errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
|
return errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -415,7 +415,7 @@ func fipsError2[T any](x T, err error) (T, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkFIPS140OnlyPublicKey(pub *PublicKey) error {
|
func checkFIPS140OnlyPublicKey(pub *PublicKey) error {
|
||||||
if !fips140only.Enabled {
|
if !fips140only.Enforced() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if pub.N == nil {
|
if pub.N == nil {
|
||||||
|
|
@ -437,7 +437,7 @@ func checkFIPS140OnlyPublicKey(pub *PublicKey) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkFIPS140OnlyPrivateKey(priv *PrivateKey) error {
|
func checkFIPS140OnlyPrivateKey(priv *PrivateKey) error {
|
||||||
if !fips140only.Enabled {
|
if !fips140only.Enforced() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err := checkFIPS140OnlyPublicKey(&priv.PublicKey); err != nil {
|
if err := checkFIPS140OnlyPublicKey(&priv.PublicKey); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ type PKCS1v15DecryptOptions struct {
|
||||||
//
|
//
|
||||||
// [draft-irtf-cfrg-rsa-guidance-05]: https://www.ietf.org/archive/id/draft-irtf-cfrg-rsa-guidance-05.html#name-rationale
|
// [draft-irtf-cfrg-rsa-guidance-05]: https://www.ietf.org/archive/id/draft-irtf-cfrg-rsa-guidance-05.html#name-rationale
|
||||||
func EncryptPKCS1v15(random io.Reader, pub *PublicKey, msg []byte) ([]byte, error) {
|
func EncryptPKCS1v15(random io.Reader, pub *PublicKey, msg []byte) ([]byte, error) {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return nil, errors.New("crypto/rsa: use of PKCS#1 v1.5 encryption is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/rsa: use of PKCS#1 v1.5 encryption is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,7 +212,7 @@ func DecryptPKCS1v15SessionKey(random io.Reader, priv *PrivateKey, ciphertext []
|
||||||
// access patterns. If the plaintext was valid then index contains the index of
|
// access patterns. If the plaintext was valid then index contains the index of
|
||||||
// the original message in em, to allow constant time padding removal.
|
// the original message in em, to allow constant time padding removal.
|
||||||
func decryptPKCS1v15(priv *PrivateKey, ciphertext []byte) (valid int, em []byte, index int, err error) {
|
func decryptPKCS1v15(priv *PrivateKey, ciphertext []byte) (valid int, em []byte, index int, err error) {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return 0, nil, 0, errors.New("crypto/rsa: use of PKCS#1 v1.5 encryption is not allowed in FIPS 140-only mode")
|
return 0, nil, 0, errors.New("crypto/rsa: use of PKCS#1 v1.5 encryption is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -350,13 +350,13 @@ func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) {
|
||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if fips140only.Enabled && bits < 2048 {
|
if fips140only.Enforced() && bits < 2048 {
|
||||||
return nil, errors.New("crypto/rsa: use of keys smaller than 2048 bits is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/rsa: use of keys smaller than 2048 bits is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
if fips140only.Enabled && bits%2 == 1 {
|
if fips140only.Enforced() && bits%2 == 1 {
|
||||||
return nil, errors.New("crypto/rsa: use of keys with odd size is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/rsa: use of keys with odd size is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
if fips140only.Enabled && !fips140only.ApprovedRandomReader(random) {
|
if fips140only.Enforced() && !fips140only.ApprovedRandomReader(random) {
|
||||||
return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -424,7 +424,7 @@ func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (*PrivateKey
|
||||||
if nprimes == 2 {
|
if nprimes == 2 {
|
||||||
return GenerateKey(random, bits)
|
return GenerateKey(random, bits)
|
||||||
}
|
}
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return nil, errors.New("crypto/rsa: multi-prime RSA is not allowed in FIPS 140-only mode")
|
return nil, errors.New("crypto/rsa: multi-prime RSA is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ func (d *digest) Size() int { return Size }
|
||||||
func (d *digest) BlockSize() int { return BlockSize }
|
func (d *digest) BlockSize() int { return BlockSize }
|
||||||
|
|
||||||
func (d *digest) Write(p []byte) (nn int, err error) {
|
func (d *digest) Write(p []byte) (nn int, err error) {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
return 0, errors.New("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode")
|
return 0, errors.New("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
boring.Unreachable()
|
boring.Unreachable()
|
||||||
|
|
@ -161,7 +161,7 @@ func (d *digest) Sum(in []byte) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *digest) checkSum() [Size]byte {
|
func (d *digest) checkSum() [Size]byte {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
panic("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode")
|
panic("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,7 +205,7 @@ func (d *digest) ConstantTimeSum(in []byte) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *digest) constSum() [Size]byte {
|
func (d *digest) constSum() [Size]byte {
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
panic("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode")
|
panic("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -274,7 +274,7 @@ func Sum(data []byte) [Size]byte {
|
||||||
if boring.Enabled {
|
if boring.Enabled {
|
||||||
return boring.SHA1(data)
|
return boring.SHA1(data)
|
||||||
}
|
}
|
||||||
if fips140only.Enabled {
|
if fips140only.Enforced() {
|
||||||
panic("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode")
|
panic("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode")
|
||||||
}
|
}
|
||||||
var d digest
|
var d digest
|
||||||
|
|
|
||||||
|
|
@ -537,7 +537,7 @@ var depsRules = `
|
||||||
< crypto/internal/fips140/edwards25519
|
< crypto/internal/fips140/edwards25519
|
||||||
< crypto/internal/fips140/ed25519
|
< crypto/internal/fips140/ed25519
|
||||||
< crypto/internal/fips140/rsa
|
< crypto/internal/fips140/rsa
|
||||||
< FIPS < crypto/fips140;
|
< crypto/fips140 < FIPS;
|
||||||
|
|
||||||
crypto !< FIPS;
|
crypto !< FIPS;
|
||||||
|
|
||||||
|
|
|
||||||
22
src/runtime/fipsbypass.go
Normal file
22
src/runtime/fipsbypass.go
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
// Copyright 2025 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 runtime
|
||||||
|
|
||||||
|
import _ "unsafe"
|
||||||
|
|
||||||
|
//go:linkname fips140_setBypass crypto/fips140.setBypass
|
||||||
|
func fips140_setBypass() {
|
||||||
|
getg().fipsOnlyBypass = true
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname fips140_unsetBypass crypto/fips140.unsetBypass
|
||||||
|
func fips140_unsetBypass() {
|
||||||
|
getg().fipsOnlyBypass = false
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname fips140_isBypassed crypto/fips140.isBypassed
|
||||||
|
func fips140_isBypassed() bool {
|
||||||
|
return getg().fipsOnlyBypass
|
||||||
|
}
|
||||||
|
|
@ -4481,6 +4481,7 @@ func gdestroy(gp *g) {
|
||||||
gp.labels = nil
|
gp.labels = nil
|
||||||
gp.timer = nil
|
gp.timer = nil
|
||||||
gp.bubble = nil
|
gp.bubble = nil
|
||||||
|
gp.fipsOnlyBypass = false
|
||||||
|
|
||||||
if gcBlackenEnabled != 0 && gp.gcAssistBytes > 0 {
|
if gcBlackenEnabled != 0 && gp.gcAssistBytes > 0 {
|
||||||
// Flush assist credit to the global pool. This gives
|
// Flush assist credit to the global pool. This gives
|
||||||
|
|
@ -5325,6 +5326,9 @@ func newproc1(fn *funcval, callergp *g, callerpc uintptr, parked bool, waitreaso
|
||||||
traceRelease(trace)
|
traceRelease(trace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fips140 bubble
|
||||||
|
newg.fipsOnlyBypass = callergp.fipsOnlyBypass
|
||||||
|
|
||||||
// Set up race context.
|
// Set up race context.
|
||||||
if raceenabled {
|
if raceenabled {
|
||||||
newg.racectx = racegostart(callerpc)
|
newg.racectx = racegostart(callerpc)
|
||||||
|
|
|
||||||
|
|
@ -545,6 +545,7 @@ type g struct {
|
||||||
runnableTime int64 // the amount of time spent runnable, cleared when running, only used when tracking
|
runnableTime int64 // the amount of time spent runnable, cleared when running, only used when tracking
|
||||||
lockedm muintptr
|
lockedm muintptr
|
||||||
fipsIndicator uint8
|
fipsIndicator uint8
|
||||||
|
fipsOnlyBypass bool
|
||||||
syncSafePoint bool // set if g is stopped at a synchronous safe point.
|
syncSafePoint bool // set if g is stopped at a synchronous safe point.
|
||||||
runningCleanups atomic.Bool
|
runningCleanups atomic.Bool
|
||||||
sig uint32
|
sig uint32
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue