]> Cypherpunks repositories - gostls13.git/commitdiff
crypto: implement fips140=only mode
authorFilippo Valsorda <filippo@golang.org>
Fri, 22 Nov 2024 03:21:12 +0000 (04:21 +0100)
committerGopher Robot <gobot@golang.org>
Fri, 22 Nov 2024 03:48:06 +0000 (03:48 +0000)
Running the test suite in this mode is definitely not an option. Testing
this will probably look like a very long test that tries all functions.
Filed #70514 to track the tests.

For #70123

Change-Id: I6f67de83da37dd1e94e620b7f4f4f6aabe040c41
Reviewed-on: https://go-review.googlesource.com/c/go/+/631018
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Daniel McCarney <daniel@binaryparadox.net>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

19 files changed:
src/crypto/cipher/cfb.go
src/crypto/cipher/gcm.go
src/crypto/cipher/ofb.go
src/crypto/des/cipher.go
src/crypto/dsa/dsa.go
src/crypto/ecdh/x25519.go
src/crypto/ecdsa/ecdsa_legacy.go
src/crypto/ed25519/ed25519.go
src/crypto/hkdf/hkdf.go
src/crypto/hmac/hmac.go
src/crypto/internal/fips140only/fips140only.go [new file with mode: 0644]
src/crypto/md5/md5.go
src/crypto/pbkdf2/pbkdf2.go
src/crypto/rand/util.go
src/crypto/rc4/rc4.go
src/crypto/rsa/fips.go
src/crypto/rsa/pkcs1v15.go
src/crypto/sha1/sha1.go
src/go/build/deps_test.go

index eccb1afa7d4383e5215d1f9a659b47ec78ea69a7..b9f9efa574679fafbe751ad81f0e7aeb7cc67fee 100644 (file)
@@ -8,6 +8,7 @@ package cipher
 
 import (
        "crypto/internal/fips140/alias"
+       "crypto/internal/fips140only"
        "crypto/subtle"
 )
 
@@ -54,6 +55,9 @@ func (x *cfb) XORKeyStream(dst, src []byte) {
 // using the given [Block]. The iv must be the same length as the [Block]'s block
 // size.
 func NewCFBEncrypter(block Block, iv []byte) Stream {
+       if fips140only.Enabled {
+               panic("crypto/cipher: use of CFB is not allowed in FIPS 140-only mode")
+       }
        return newCFB(block, iv, false)
 }
 
@@ -61,6 +65,9 @@ func NewCFBEncrypter(block Block, iv []byte) Stream {
 // using the given [Block]. The iv must be the same length as the [Block]'s block
 // size.
 func NewCFBDecrypter(block Block, iv []byte) Stream {
+       if fips140only.Enabled {
+               panic("crypto/cipher: use of CFB is not allowed in FIPS 140-only mode")
+       }
        return newCFB(block, iv, true)
 }
 
index ca600081116fd2de6e158136510cdc0a87e5aaad..5580f96d55a0fb7e5766992e7fcce77d8afda696 100644 (file)
@@ -8,6 +8,7 @@ import (
        "crypto/internal/fips140/aes"
        "crypto/internal/fips140/aes/gcm"
        "crypto/internal/fips140/alias"
+       "crypto/internal/fips140only"
        "crypto/subtle"
        "errors"
        "internal/byteorder"
@@ -27,6 +28,9 @@ const (
 // 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.
 func NewGCM(cipher Block) (AEAD, error) {
+       if fips140only.Enabled {
+               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)
 }
 
@@ -38,6 +42,9 @@ func NewGCM(cipher Block) (AEAD, error) {
 // cryptosystem that uses non-standard nonce lengths. All other users should use
 // [NewGCM], which is faster and more resistant to misuse.
 func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) {
+       if fips140only.Enabled {
+               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)
 }
 
@@ -50,12 +57,18 @@ func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) {
 // cryptosystem that uses non-standard tag lengths. All other users should use
 // [NewGCM], which is more resistant to misuse.
 func NewGCMWithTagSize(cipher Block, tagSize int) (AEAD, error) {
+       if fips140only.Enabled {
+               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)
 }
 
 func newGCM(cipher Block, nonceSize, tagSize int) (AEAD, error) {
        c, ok := cipher.(*aes.Block)
        if !ok {
+               if fips140only.Enabled {
+                       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)
        }
        // We don't return gcm.New directly, because it would always return a non-nil
index 549dc9196291512c75d84420c16e8507cd976345..abdc0225c01663763500c21ae22d232f250b6762 100644 (file)
@@ -8,6 +8,7 @@ package cipher
 
 import (
        "crypto/internal/fips140/alias"
+       "crypto/internal/fips140only"
        "crypto/subtle"
 )
 
@@ -22,6 +23,10 @@ type ofb struct {
 // in output feedback mode. The initialization vector iv's length must be equal
 // to b's block size.
 func NewOFB(b Block, iv []byte) Stream {
+       if fips140only.Enabled {
+               panic("crypto/cipher: use of OFB is not allowed in FIPS 140-only mode")
+       }
+
        blockSize := b.BlockSize()
        if len(iv) != blockSize {
                panic("cipher.NewOFB: IV length must equal block size")
index 5663d16fb2157eed967c2f566f0e9c43b6e2345d..21303b384cf7577b38f6bf9cc1e862024deae884 100644 (file)
@@ -7,6 +7,8 @@ package des
 import (
        "crypto/cipher"
        "crypto/internal/fips140/alias"
+       "crypto/internal/fips140only"
+       "errors"
        "internal/byteorder"
        "strconv"
 )
@@ -27,6 +29,10 @@ type desCipher struct {
 
 // NewCipher creates and returns a new [cipher.Block].
 func NewCipher(key []byte) (cipher.Block, error) {
+       if fips140only.Enabled {
+               return nil, errors.New("crypto/des: use of DES is not allowed in FIPS 140-only mode")
+       }
+
        if len(key) != 8 {
                return nil, KeySizeError(len(key))
        }
@@ -71,6 +77,10 @@ type tripleDESCipher struct {
 
 // NewTripleDESCipher creates and returns a new [cipher.Block].
 func NewTripleDESCipher(key []byte) (cipher.Block, error) {
+       if fips140only.Enabled {
+               return nil, errors.New("crypto/des: use of TripleDES is not allowed in FIPS 140-only mode")
+       }
+
        if len(key) != 24 {
                return nil, KeySizeError(len(key))
        }
index 4524bd492feba03ff43370941a01aad1136d6b1c..000becc82dfb793a3310d2df4bb132b723b0f274 100644 (file)
@@ -18,6 +18,7 @@ import (
        "io"
        "math/big"
 
+       "crypto/internal/fips140only"
        "crypto/internal/randutil"
 )
 
@@ -63,6 +64,10 @@ const numMRTests = 64
 // GenerateParameters puts a random, valid set of DSA parameters into params.
 // This function can take many seconds, even on fast machines.
 func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) error {
+       if fips140only.Enabled {
+               return errors.New("crypto/dsa: use of DSA is not allowed in FIPS 140-only mode")
+       }
+
        // This function doesn't follow FIPS 186-3 exactly in that it doesn't
        // use a verification seed to generate the primes. The verification
        // seed doesn't appear to be exported or used by other code and
@@ -157,6 +162,10 @@ GeneratePrimes:
 // GenerateKey generates a public&private key pair. The Parameters of the
 // [PrivateKey] must already be valid (see [GenerateParameters]).
 func GenerateKey(priv *PrivateKey, rand io.Reader) error {
+       if fips140only.Enabled {
+               return errors.New("crypto/dsa: use of DSA is not allowed in FIPS 140-only mode")
+       }
+
        if priv.P == nil || priv.Q == nil || priv.G == nil {
                return errors.New("crypto/dsa: parameters not set up before generating key")
        }
@@ -203,6 +212,10 @@ func fermatInverse(k, P *big.Int) *big.Int {
 // Be aware that calling Sign with an attacker-controlled [PrivateKey] may
 // require an arbitrary amount of CPU.
 func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
+       if fips140only.Enabled {
+               return nil, nil, errors.New("crypto/dsa: use of DSA is not allowed in FIPS 140-only mode")
+       }
+
        randutil.MaybeReadByte(rand)
 
        // FIPS 186-3, section 4.6
@@ -271,6 +284,10 @@ 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
 // truncation itself.
 func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
+       if fips140only.Enabled {
+               panic("crypto/dsa: use of DSA is not allowed in FIPS 140-only mode")
+       }
+
        // FIPS 186-3, section 4.7
 
        if pub.P.Sign() == 0 {
index 73c1120bf306cc3ba9b207f7b92b7e8bf70a8bc1..81dca5d3a423e056df1ef6712e5115fcd5905c5c 100644 (file)
@@ -7,6 +7,7 @@ package ecdh
 import (
        "bytes"
        "crypto/internal/fips140/edwards25519/field"
+       "crypto/internal/fips140only"
        "crypto/internal/randutil"
        "errors"
        "io"
@@ -34,6 +35,9 @@ func (c *x25519Curve) String() string {
 }
 
 func (c *x25519Curve) GenerateKey(rand io.Reader) (*PrivateKey, error) {
+       if fips140only.Enabled {
+               return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
+       }
        key := make([]byte, x25519PrivateKeySize)
        randutil.MaybeReadByte(rand)
        if _, err := io.ReadFull(rand, key); err != nil {
@@ -43,6 +47,9 @@ func (c *x25519Curve) GenerateKey(rand io.Reader) (*PrivateKey, error) {
 }
 
 func (c *x25519Curve) NewPrivateKey(key []byte) (*PrivateKey, error) {
+       if fips140only.Enabled {
+               return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
+       }
        if len(key) != x25519PrivateKeySize {
                return nil, errors.New("crypto/ecdh: invalid private key size")
        }
@@ -60,6 +67,9 @@ func (c *x25519Curve) NewPrivateKey(key []byte) (*PrivateKey, error) {
 }
 
 func (c *x25519Curve) NewPublicKey(key []byte) (*PublicKey, error) {
+       if fips140only.Enabled {
+               return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
+       }
        if len(key) != x25519PublicKeySize {
                return nil, errors.New("crypto/ecdh: invalid public key")
        }
index a6590a5de36f076642c04a6ac48c9ae247ad1371..74f27b74885e0dff3c7f773965959f60df7ba417 100644 (file)
@@ -6,6 +6,7 @@ package ecdsa
 
 import (
        "crypto/elliptic"
+       "crypto/internal/fips140only"
        "errors"
        "io"
        "math/big"
@@ -19,6 +20,10 @@ import (
 // deprecated custom curves.
 
 func generateLegacy(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
+       if fips140only.Enabled {
+               return nil, errors.New("crypto/ecdsa: use of custom curves is not allowed in FIPS 140-only mode")
+       }
+
        k, err := randFieldElement(c, rand)
        if err != nil {
                return nil, err
@@ -76,6 +81,10 @@ 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) {
+       if fips140only.Enabled {
+               return nil, errors.New("crypto/ecdsa: use of custom curves is not allowed in FIPS 140-only mode")
+       }
+
        c := priv.Curve
 
        // A cheap version of hedged signatures, for the deprecated path.
@@ -144,6 +153,10 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
 }
 
 func verifyLegacy(pub *PublicKey, hash []byte, sig []byte) bool {
+       if fips140only.Enabled {
+               panic("crypto/ecdsa: use of custom curves is not allowed in FIPS 140-only mode")
+       }
+
        rBytes, sBytes, err := parseSignature(sig)
        if err != nil {
                return false
index 6480463b4ae7a61f88581e9f6cea54eed4722729..c1f8ff784e4a5cf04ae43909138ea76d20657aa2 100644 (file)
@@ -18,6 +18,7 @@ package ed25519
 import (
        "crypto"
        "crypto/internal/fips140/ed25519"
+       "crypto/internal/fips140only"
        cryptorand "crypto/rand"
        "crypto/subtle"
        "errors"
@@ -103,6 +104,9 @@ func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOp
        case hash == crypto.SHA512: // Ed25519ph
                return ed25519.SignPH(k, message, context)
        case hash == crypto.Hash(0) && context != "": // Ed25519ctx
+               if fips140only.Enabled {
+                       return nil, errors.New("crypto/ed25519: use of Ed25519ctx is not allowed in FIPS 140-only mode")
+               }
                return ed25519.SignCtx(k, message, context)
        case hash == crypto.Hash(0): // Ed25519
                return ed25519.Sign(k, message), nil
@@ -219,6 +223,9 @@ func VerifyWithOptions(publicKey PublicKey, message, sig []byte, opts *Options)
        case opts.Hash == crypto.SHA512: // Ed25519ph
                return ed25519.VerifyPH(k, message, sig, opts.Context)
        case opts.Hash == crypto.Hash(0) && opts.Context != "": // Ed25519ctx
+               if fips140only.Enabled {
+                       return errors.New("crypto/ed25519: use of Ed25519ctx is not allowed in FIPS 140-only mode")
+               }
                return ed25519.VerifyCtx(k, message, sig, opts.Context)
        case opts.Hash == crypto.Hash(0): // Ed25519
                return ed25519.Verify(k, message, sig)
index e33e0acef2f9e4048f33f14a6b59df2ef9324a9e..f4f441af0423525738dd8f510b05d4242273ef22 100644 (file)
@@ -6,6 +6,7 @@ package hkdf
 
 import (
        "crypto/internal/fips140/hkdf"
+       "crypto/internal/fips140only"
        "errors"
        "hash"
 )
@@ -17,6 +18,9 @@ import (
 // Expand invocations and different context values. Most common scenarios,
 // including the generation of multiple keys, should use [Key] instead.
 func Extract[H hash.Hash](h func() H, secret, salt []byte) ([]byte, error) {
+       if err := checkFIPS140Only(h, secret); err != nil {
+               return nil, err
+       }
        return hkdf.Extract(h, secret, salt), nil
 }
 
@@ -28,6 +32,10 @@ func Extract[H hash.Hash](h func() H, secret, salt []byte) ([]byte, error) {
 // random or pseudorandom cryptographically strong key. See RFC 5869, Section
 // 3.3. Most common scenarios will want to use [Key] instead.
 func Expand[H hash.Hash](h func() H, pseudorandomKey []byte, info string, keyLength int) ([]byte, error) {
+       if err := checkFIPS140Only(h, pseudorandomKey); err != nil {
+               return nil, err
+       }
+
        limit := h().Size() * 255
        if keyLength > limit {
                return nil, errors.New("hkdf: requested key length too large")
@@ -40,6 +48,10 @@ func Expand[H hash.Hash](h func() H, pseudorandomKey []byte, info string, keyLen
 // returning a []byte of length keyLength that can be used as cryptographic key.
 // Salt and info can be nil.
 func Key[Hash hash.Hash](h func() Hash, secret, salt []byte, info string, keyLength int) ([]byte, error) {
+       if err := checkFIPS140Only(h, secret); err != nil {
+               return nil, err
+       }
+
        limit := h().Size() * 255
        if keyLength > limit {
                return nil, errors.New("hkdf: requested key length too large")
@@ -47,3 +59,16 @@ func Key[Hash hash.Hash](h func() Hash, secret, salt []byte, info string, keyLen
 
        return hkdf.Key(h, secret, salt, info, keyLength), nil
 }
+
+func checkFIPS140Only[H hash.Hash](h func() H, key []byte) error {
+       if !fips140only.Enabled {
+               return nil
+       }
+       if len(key) < 112/8 {
+               return errors.New("crypto/hkdf: use of keys shorter than 112 bits is not allowed in FIPS 140-only mode")
+       }
+       if !fips140only.ApprovedHash(h()) {
+               return errors.New("crypto/hkdf: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
+       }
+       return nil
+}
index 3b777665cbdf8ad20a46201fea30b910b5a5e806..72f5a4abea9d359fd7ee66efd7e59acc43e493b3 100644 (file)
@@ -24,6 +24,7 @@ package hmac
 import (
        "crypto/internal/boring"
        "crypto/internal/fips140/hmac"
+       "crypto/internal/fips140only"
        "crypto/subtle"
        "hash"
 )
@@ -42,6 +43,14 @@ func New(h func() hash.Hash, key []byte) hash.Hash {
                }
                // BoringCrypto did not recognize h, so fall through to standard Go code.
        }
+       if fips140only.Enabled {
+               if len(key) < 112/8 {
+                       panic("crypto/hmac: use of keys shorter than 112 bits is not allowed in FIPS 140-only mode")
+               }
+               if !fips140only.ApprovedHash(h()) {
+                       panic("crypto/hmac: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
+               }
+       }
        return hmac.New(h, key)
 }
 
diff --git a/src/crypto/internal/fips140only/fips140only.go b/src/crypto/internal/fips140only/fips140only.go
new file mode 100644 (file)
index 0000000..6ad97be
--- /dev/null
@@ -0,0 +1,26 @@
+// 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 fips140only
+
+import (
+       "crypto/internal/fips140/sha256"
+       "crypto/internal/fips140/sha3"
+       "crypto/internal/fips140/sha512"
+       "hash"
+       "internal/godebug"
+)
+
+// Enabled reports whether FIPS 140-only mode is enabled, in which non-approved
+// cryptography returns an error or panics.
+var Enabled = godebug.New("#fips140").Value() == "only"
+
+func ApprovedHash(h hash.Hash) bool {
+       switch h.(type) {
+       case *sha256.Digest, *sha512.Digest, *sha3.Digest:
+               return true
+       default:
+               return false
+       }
+}
index c49de91314fb50764db11fcd68bde3fa146ee236..75e1fc7404724a8ce233ea496e48e6142a1a57e2 100644 (file)
@@ -12,6 +12,7 @@ package md5
 
 import (
        "crypto"
+       "crypto/internal/fips140only"
        "errors"
        "hash"
        "internal/byteorder"
@@ -103,6 +104,9 @@ func consumeUint32(b []byte) ([]byte, uint32) {
 // [encoding.BinaryUnmarshaler] to marshal and unmarshal the internal
 // state of the hash.
 func New() hash.Hash {
+       if fips140only.Enabled {
+               panic("crypto/md5: use of MD5 is not allowed in FIPS 140-only mode")
+       }
        d := new(digest)
        d.Reset()
        return d
@@ -180,6 +184,9 @@ func (d *digest) checkSum() [Size]byte {
 
 // Sum returns the MD5 checksum of the data.
 func Sum(data []byte) [Size]byte {
+       if fips140only.Enabled {
+               panic("crypto/md5: use of MD5 is not allowed in FIPS 140-only mode")
+       }
        var d digest
        d.Reset()
        d.Write(data)
index e6fef68b298cd812abb3890708ebd7b6a6e3bb85..0fdd9e822d40a501d749f43e87f23c772c0587b7 100644 (file)
@@ -20,6 +20,8 @@ package pbkdf2
 
 import (
        "crypto/internal/fips140/pbkdf2"
+       "crypto/internal/fips140only"
+       "errors"
        "hash"
 )
 
@@ -40,5 +42,16 @@ import (
 // Using a higher iteration count will increase the cost of an exhaustive
 // search but will also make derivation proportionally slower.
 func Key[Hash hash.Hash](h func() Hash, password string, salt []byte, iter, keyLength int) ([]byte, error) {
+       if fips140only.Enabled {
+               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")
+               }
+               if len(salt) < 128/8 {
+                       return nil, errors.New("crypto/pbkdf2: use of salts shorter than 128 bits is not allowed in FIPS 140-only mode")
+               }
+               if !fips140only.ApprovedHash(h()) {
+                       return nil, errors.New("crypto/pbkdf2: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
+               }
+       }
        return pbkdf2.Key(h, password, salt, iter, keyLength)
 }
index bb1f6f6fa3574487297c81937b07091fc7abce2c..10c2284a9b5fc430282eae659afd150fcf80e69f 100644 (file)
@@ -5,6 +5,7 @@
 package rand
 
 import (
+       "crypto/internal/fips140only"
        "crypto/internal/randutil"
        "errors"
        "io"
@@ -14,6 +15,9 @@ import (
 // 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.
 func Prime(rand io.Reader, bits int) (*big.Int, error) {
+       if fips140only.Enabled {
+               return nil, errors.New("crypto/rand: use of Prime is not allowed in FIPS 140-only mode")
+       }
        if bits < 2 {
                return nil, errors.New("crypto/rand: prime size must be at least 2-bit")
        }
index 19e6b8a047dcad33b573272e2d414547a6bda7d0..90943a0935befbf1841d4ca01ccd192db35d9676 100644 (file)
@@ -11,6 +11,8 @@ package rc4
 
 import (
        "crypto/internal/fips140/alias"
+       "crypto/internal/fips140only"
+       "errors"
        "strconv"
 )
 
@@ -29,6 +31,9 @@ func (k KeySizeError) Error() string {
 // NewCipher creates and returns a new [Cipher]. The key argument should be the
 // RC4 key, at least 1 byte and at most 256 bytes.
 func NewCipher(key []byte) (*Cipher, error) {
+       if fips140only.Enabled {
+               return nil, errors.New("crypto/rc4: use of RC4 is not allowed in FIPS 140-only mode")
+       }
        k := len(key)
        if k < 1 || k > 256 {
                return nil, KeySizeError(k)
index 581bcf194e7653d7b0890e3bdbb8cd025a211097..eac4c44066db5d94d07b96b6a44547406a9c1fb4 100644 (file)
@@ -8,6 +8,7 @@ import (
        "crypto"
        "crypto/internal/boring"
        "crypto/internal/fips140/rsa"
+       "crypto/internal/fips140only"
        "errors"
        "hash"
        "io"
@@ -60,6 +61,12 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte,
        if err := checkPublicKeySize(&priv.PublicKey); err != nil {
                return nil, err
        }
+       if err := checkFIPS140OnlyPrivateKey(priv); err != nil {
+               return nil, err
+       }
+       if fips140only.Enabled && !fips140only.ApprovedHash(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")
+       }
 
        if opts != nil && opts.Hash != 0 {
                hash = opts.Hash
@@ -81,6 +88,9 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte,
        h := hash.New()
 
        saltLength := opts.saltLength()
+       if fips140only.Enabled && saltLength > hash.Size() {
+               return nil, errors.New("crypto/rsa: use of PSS salt longer than the hash is not allowed in FIPS 140-only mode")
+       }
        switch saltLength {
        case PSSSaltLengthAuto:
                saltLength, err = rsa.PSSMaxSaltLength(k.PublicKey(), h)
@@ -113,6 +123,12 @@ func VerifyPSS(pub *PublicKey, hash crypto.Hash, digest []byte, sig []byte, opts
        if err := checkPublicKeySize(pub); err != nil {
                return err
        }
+       if err := checkFIPS140OnlyPublicKey(pub); err != nil {
+               return err
+       }
+       if fips140only.Enabled && !fips140only.ApprovedHash(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")
+       }
 
        if boring.Enabled {
                bkey, err := boringPublicKey(pub)
@@ -131,6 +147,9 @@ func VerifyPSS(pub *PublicKey, hash crypto.Hash, digest []byte, sig []byte, opts
        }
 
        saltLength := opts.saltLength()
+       if fips140only.Enabled && saltLength > hash.Size() {
+               return errors.New("crypto/rsa: use of PSS salt longer than the hash is not allowed in FIPS 140-only mode")
+       }
        switch saltLength {
        case PSSSaltLengthAuto:
                return fipsError(rsa.VerifyPSS(k, hash.New(), digest, sig))
@@ -163,6 +182,12 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l
        if err := checkPublicKeySize(pub); err != nil {
                return nil, err
        }
+       if err := checkFIPS140OnlyPublicKey(pub); err != nil {
+               return nil, err
+       }
+       if fips140only.Enabled && !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")
+       }
 
        defer hash.Reset()
 
@@ -206,6 +231,14 @@ func decryptOAEP(hash, mgfHash hash.Hash, priv *PrivateKey, ciphertext []byte, l
        if err := checkPublicKeySize(&priv.PublicKey); err != nil {
                return nil, err
        }
+       if err := checkFIPS140OnlyPrivateKey(priv); err != nil {
+               return nil, err
+       }
+       if fips140only.Enabled {
+               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")
+               }
+       }
 
        if boring.Enabled {
                k := priv.Size()
@@ -248,6 +281,12 @@ func SignPKCS1v15(random io.Reader, priv *PrivateKey, hash crypto.Hash, hashed [
        if err := checkPublicKeySize(&priv.PublicKey); err != nil {
                return nil, err
        }
+       if err := checkFIPS140OnlyPrivateKey(priv); err != nil {
+               return nil, err
+       }
+       if fips140only.Enabled && !fips140only.ApprovedHash(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")
+       }
 
        if boring.Enabled {
                bkey, err := boringPrivateKey(priv)
@@ -283,6 +322,12 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte)
        if err := checkPublicKeySize(pub); err != nil {
                return err
        }
+       if err := checkFIPS140OnlyPublicKey(pub); err != nil {
+               return err
+       }
+       if fips140only.Enabled && !fips140only.ApprovedHash(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")
+       }
 
        if boring.Enabled {
                bkey, err := boringPublicKey(pub)
@@ -324,3 +369,38 @@ func fipsError(err error) error {
 func fipsError2[T any](x T, err error) (T, error) {
        return x, fipsError(err)
 }
+
+func checkFIPS140OnlyPublicKey(pub *PublicKey) error {
+       if !fips140only.Enabled {
+               return nil
+       }
+       if pub.N == nil {
+               return errors.New("crypto/rsa: public key missing N")
+       }
+       if pub.N.BitLen() < 2048 {
+               return errors.New("crypto/rsa: use of keys smaller than 2048 bits is not allowed in FIPS 140-only mode")
+       }
+       if pub.N.BitLen() > 16384 {
+               return errors.New("crypto/rsa: use of keys larger than 16384 bits is not allowed in FIPS 140-only mode")
+       }
+       if pub.E <= 1<<16 {
+               return errors.New("crypto/rsa: use of public exponent <= 2¹⁶ is not allowed in FIPS 140-only mode")
+       }
+       if pub.E&1 == 0 {
+               return errors.New("crypto/rsa: use of even public exponent is not allowed in FIPS 140-only mode")
+       }
+       return nil
+}
+
+func checkFIPS140OnlyPrivateKey(priv *PrivateKey) error {
+       if !fips140only.Enabled {
+               return nil
+       }
+       if err := checkFIPS140OnlyPublicKey(&priv.PublicKey); err != nil {
+               return err
+       }
+       if len(priv.Primes) > 2 {
+               return errors.New("crypto/rsa: use of multi-prime keys is not allowed in FIPS 140-only mode")
+       }
+       return nil
+}
index 819b447f1eef45fe16614c8ec06c528c2e62ec06..f1e4ef48a4fd1cb3ccd6cf430539e23d975a2219 100644 (file)
@@ -7,8 +7,10 @@ package rsa
 import (
        "crypto/internal/boring"
        "crypto/internal/fips140/rsa"
+       "crypto/internal/fips140only"
        "crypto/internal/randutil"
        "crypto/subtle"
+       "errors"
        "io"
 )
 
@@ -38,6 +40,10 @@ type PKCS1v15DecryptOptions struct {
 // WARNING: use of this function to encrypt plaintexts other than
 // session keys is dangerous. Use RSA OAEP in new protocols.
 func EncryptPKCS1v15(random io.Reader, pub *PublicKey, msg []byte) ([]byte, error) {
+       if fips140only.Enabled {
+               return nil, errors.New("crypto/rsa: use of PKCS#1 v1.5 encryption is not allowed in FIPS 140-only mode")
+       }
+
        if err := checkPublicKeySize(pub); err != nil {
                return nil, err
        }
@@ -187,6 +193,10 @@ func DecryptPKCS1v15SessionKey(random io.Reader, priv *PrivateKey, ciphertext []
 // access patterns. If the plaintext was valid then index contains the index of
 // 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) {
+       if fips140only.Enabled {
+               return 0, nil, 0, errors.New("crypto/rsa: use of PKCS#1 v1.5 encryption is not allowed in FIPS 140-only mode")
+       }
+
        k := priv.Size()
        if k < 11 {
                err = ErrDecryption
index c3972bea6320c34556c1b6fa101f0d8b4e55d7a0..b799f0d2fb154886877c800214abd5b3e06ebfd8 100644 (file)
@@ -11,6 +11,7 @@ package sha1
 import (
        "crypto"
        "crypto/internal/boring"
+       "crypto/internal/fips140only"
        "errors"
        "hash"
        "internal/byteorder"
@@ -102,7 +103,7 @@ func (d *digest) Reset() {
        d.len = 0
 }
 
-// New512_224 returns a new [hash.Hash] computing the SHA1 checksum. The Hash
+// New returns a new [hash.Hash] computing the SHA1 checksum. The Hash
 // also implements [encoding.BinaryMarshaler], [encoding.BinaryAppender] and
 // [encoding.BinaryUnmarshaler] to marshal and unmarshal the internal
 // state of the hash.
@@ -110,6 +111,9 @@ func New() hash.Hash {
        if boring.Enabled {
                return boring.NewSHA1()
        }
+       if fips140only.Enabled {
+               panic("crypto/sha1: use of weak SHA-1 is not allowed in FIPS 140-only mode")
+       }
        d := new(digest)
        d.Reset()
        return d
@@ -257,6 +261,9 @@ func Sum(data []byte) [Size]byte {
        if boring.Enabled {
                return boring.SHA1(data)
        }
+       if fips140only.Enabled {
+               panic("crypto/sha1: use of weak SHA-1 is not allowed in FIPS 140-only mode")
+       }
        var d digest
        d.Reset()
        d.Write(data)
index 4eb7b5f078a2dc3ccaf814a623df33581fd11fd8..90b1eed00ed01d3ff91ec8d8f94fb62715fc96de 100644 (file)
@@ -491,14 +491,14 @@ var depsRules = `
 
        FIPS, sync/atomic < crypto/tls/internal/fips140tls;
 
-       FIPS, internal/godebug < crypto/fips140;
+       FIPS, internal/godebug, hash < crypto/fips140, crypto/internal/fips140only;
 
        NONE < crypto/internal/boring/sig, crypto/internal/boring/syso;
        sync/atomic < crypto/internal/boring/bcache, crypto/internal/boring/fips140tls;
        crypto/internal/boring/sig, crypto/tls/internal/fips140tls < crypto/tls/fipsonly;
 
        # CRYPTO is core crypto algorithms - no cgo, fmt, net.
-       FIPS,
+       FIPS, crypto/internal/fips140only,
        crypto/internal/boring/sig,
        crypto/internal/boring/syso,
        golang.org/x/sys/cpu,