Skip to content

Commit b299e9a

Browse files
FiloSottilegopherbot
authored andcommitted
crypto: implement fips140=only mode
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 <[email protected]> Auto-Submit: Filippo Valsorda <[email protected]> Reviewed-by: Roland Shoemaker <[email protected]> Reviewed-by: Daniel McCarney <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 07b4266 commit b299e9a

File tree

19 files changed

+271
-3
lines changed

19 files changed

+271
-3
lines changed

src/crypto/cipher/cfb.go

+7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package cipher
88

99
import (
1010
"crypto/internal/fips140/alias"
11+
"crypto/internal/fips140only"
1112
"crypto/subtle"
1213
)
1314

@@ -54,13 +55,19 @@ func (x *cfb) XORKeyStream(dst, src []byte) {
5455
// using the given [Block]. The iv must be the same length as the [Block]'s block
5556
// size.
5657
func NewCFBEncrypter(block Block, iv []byte) Stream {
58+
if fips140only.Enabled {
59+
panic("crypto/cipher: use of CFB is not allowed in FIPS 140-only mode")
60+
}
5761
return newCFB(block, iv, false)
5862
}
5963

6064
// NewCFBDecrypter returns a [Stream] which decrypts with cipher feedback mode,
6165
// using the given [Block]. The iv must be the same length as the [Block]'s block
6266
// size.
6367
func NewCFBDecrypter(block Block, iv []byte) Stream {
68+
if fips140only.Enabled {
69+
panic("crypto/cipher: use of CFB is not allowed in FIPS 140-only mode")
70+
}
6471
return newCFB(block, iv, true)
6572
}
6673

src/crypto/cipher/gcm.go

+13
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"crypto/internal/fips140/aes"
99
"crypto/internal/fips140/aes/gcm"
1010
"crypto/internal/fips140/alias"
11+
"crypto/internal/fips140only"
1112
"crypto/subtle"
1213
"errors"
1314
"internal/byteorder"
@@ -27,6 +28,9 @@ const (
2728
// An exception is when the underlying [Block] was created by aes.NewCipher
2829
// on systems with hardware support for AES. See the [crypto/aes] package documentation for details.
2930
func NewGCM(cipher Block) (AEAD, error) {
31+
if fips140only.Enabled {
32+
return nil, errors.New("crypto/cipher: use of GCM with arbitrary IVs is not allowed in FIPS 140-only mode, use NewGCMWithRandomNonce")
33+
}
3034
return newGCM(cipher, gcmStandardNonceSize, gcmTagSize)
3135
}
3236

@@ -38,6 +42,9 @@ func NewGCM(cipher Block) (AEAD, error) {
3842
// cryptosystem that uses non-standard nonce lengths. All other users should use
3943
// [NewGCM], which is faster and more resistant to misuse.
4044
func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) {
45+
if fips140only.Enabled {
46+
return nil, errors.New("crypto/cipher: use of GCM with arbitrary IVs is not allowed in FIPS 140-only mode, use NewGCMWithRandomNonce")
47+
}
4148
return newGCM(cipher, size, gcmTagSize)
4249
}
4350

@@ -50,12 +57,18 @@ func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) {
5057
// cryptosystem that uses non-standard tag lengths. All other users should use
5158
// [NewGCM], which is more resistant to misuse.
5259
func NewGCMWithTagSize(cipher Block, tagSize int) (AEAD, error) {
60+
if fips140only.Enabled {
61+
return nil, errors.New("crypto/cipher: use of GCM with arbitrary IVs is not allowed in FIPS 140-only mode, use NewGCMWithRandomNonce")
62+
}
5363
return newGCM(cipher, gcmStandardNonceSize, tagSize)
5464
}
5565

5666
func newGCM(cipher Block, nonceSize, tagSize int) (AEAD, error) {
5767
c, ok := cipher.(*aes.Block)
5868
if !ok {
69+
if fips140only.Enabled {
70+
return nil, errors.New("crypto/cipher: use of GCM with non-AES ciphers is not allowed in FIPS 140-only mode")
71+
}
5972
return newGCMFallback(cipher, nonceSize, tagSize)
6073
}
6174
// We don't return gcm.New directly, because it would always return a non-nil

src/crypto/cipher/ofb.go

+5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package cipher
88

99
import (
1010
"crypto/internal/fips140/alias"
11+
"crypto/internal/fips140only"
1112
"crypto/subtle"
1213
)
1314

@@ -22,6 +23,10 @@ type ofb struct {
2223
// in output feedback mode. The initialization vector iv's length must be equal
2324
// to b's block size.
2425
func NewOFB(b Block, iv []byte) Stream {
26+
if fips140only.Enabled {
27+
panic("crypto/cipher: use of OFB is not allowed in FIPS 140-only mode")
28+
}
29+
2530
blockSize := b.BlockSize()
2631
if len(iv) != blockSize {
2732
panic("cipher.NewOFB: IV length must equal block size")

src/crypto/des/cipher.go

+10
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ package des
77
import (
88
"crypto/cipher"
99
"crypto/internal/fips140/alias"
10+
"crypto/internal/fips140only"
11+
"errors"
1012
"internal/byteorder"
1113
"strconv"
1214
)
@@ -27,6 +29,10 @@ type desCipher struct {
2729

2830
// NewCipher creates and returns a new [cipher.Block].
2931
func NewCipher(key []byte) (cipher.Block, error) {
32+
if fips140only.Enabled {
33+
return nil, errors.New("crypto/des: use of DES is not allowed in FIPS 140-only mode")
34+
}
35+
3036
if len(key) != 8 {
3137
return nil, KeySizeError(len(key))
3238
}
@@ -71,6 +77,10 @@ type tripleDESCipher struct {
7177

7278
// NewTripleDESCipher creates and returns a new [cipher.Block].
7379
func NewTripleDESCipher(key []byte) (cipher.Block, error) {
80+
if fips140only.Enabled {
81+
return nil, errors.New("crypto/des: use of TripleDES is not allowed in FIPS 140-only mode")
82+
}
83+
7484
if len(key) != 24 {
7585
return nil, KeySizeError(len(key))
7686
}

src/crypto/dsa/dsa.go

+17
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"io"
1919
"math/big"
2020

21+
"crypto/internal/fips140only"
2122
"crypto/internal/randutil"
2223
)
2324

@@ -63,6 +64,10 @@ const numMRTests = 64
6364
// GenerateParameters puts a random, valid set of DSA parameters into params.
6465
// This function can take many seconds, even on fast machines.
6566
func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) error {
67+
if fips140only.Enabled {
68+
return errors.New("crypto/dsa: use of DSA is not allowed in FIPS 140-only mode")
69+
}
70+
6671
// This function doesn't follow FIPS 186-3 exactly in that it doesn't
6772
// use a verification seed to generate the primes. The verification
6873
// seed doesn't appear to be exported or used by other code and
@@ -157,6 +162,10 @@ GeneratePrimes:
157162
// GenerateKey generates a public&private key pair. The Parameters of the
158163
// [PrivateKey] must already be valid (see [GenerateParameters]).
159164
func GenerateKey(priv *PrivateKey, rand io.Reader) error {
165+
if fips140only.Enabled {
166+
return errors.New("crypto/dsa: use of DSA is not allowed in FIPS 140-only mode")
167+
}
168+
160169
if priv.P == nil || priv.Q == nil || priv.G == nil {
161170
return errors.New("crypto/dsa: parameters not set up before generating key")
162171
}
@@ -203,6 +212,10 @@ func fermatInverse(k, P *big.Int) *big.Int {
203212
// Be aware that calling Sign with an attacker-controlled [PrivateKey] may
204213
// require an arbitrary amount of CPU.
205214
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
215+
if fips140only.Enabled {
216+
return nil, nil, errors.New("crypto/dsa: use of DSA is not allowed in FIPS 140-only mode")
217+
}
218+
206219
randutil.MaybeReadByte(rand)
207220

208221
// 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
271284
// to the byte-length of the subgroup. This function does not perform that
272285
// truncation itself.
273286
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
287+
if fips140only.Enabled {
288+
panic("crypto/dsa: use of DSA is not allowed in FIPS 140-only mode")
289+
}
290+
274291
// FIPS 186-3, section 4.7
275292

276293
if pub.P.Sign() == 0 {

src/crypto/ecdh/x25519.go

+10
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package ecdh
77
import (
88
"bytes"
99
"crypto/internal/fips140/edwards25519/field"
10+
"crypto/internal/fips140only"
1011
"crypto/internal/randutil"
1112
"errors"
1213
"io"
@@ -34,6 +35,9 @@ func (c *x25519Curve) String() string {
3435
}
3536

3637
func (c *x25519Curve) GenerateKey(rand io.Reader) (*PrivateKey, error) {
38+
if fips140only.Enabled {
39+
return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
40+
}
3741
key := make([]byte, x25519PrivateKeySize)
3842
randutil.MaybeReadByte(rand)
3943
if _, err := io.ReadFull(rand, key); err != nil {
@@ -43,6 +47,9 @@ func (c *x25519Curve) GenerateKey(rand io.Reader) (*PrivateKey, error) {
4347
}
4448

4549
func (c *x25519Curve) NewPrivateKey(key []byte) (*PrivateKey, error) {
50+
if fips140only.Enabled {
51+
return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
52+
}
4653
if len(key) != x25519PrivateKeySize {
4754
return nil, errors.New("crypto/ecdh: invalid private key size")
4855
}
@@ -60,6 +67,9 @@ func (c *x25519Curve) NewPrivateKey(key []byte) (*PrivateKey, error) {
6067
}
6168

6269
func (c *x25519Curve) NewPublicKey(key []byte) (*PublicKey, error) {
70+
if fips140only.Enabled {
71+
return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
72+
}
6373
if len(key) != x25519PublicKeySize {
6474
return nil, errors.New("crypto/ecdh: invalid public key")
6575
}

src/crypto/ecdsa/ecdsa_legacy.go

+13
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package ecdsa
66

77
import (
88
"crypto/elliptic"
9+
"crypto/internal/fips140only"
910
"errors"
1011
"io"
1112
"math/big"
@@ -19,6 +20,10 @@ import (
1920
// deprecated custom curves.
2021

2122
func generateLegacy(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
23+
if fips140only.Enabled {
24+
return nil, errors.New("crypto/ecdsa: use of custom curves is not allowed in FIPS 140-only mode")
25+
}
26+
2227
k, err := randFieldElement(c, rand)
2328
if err != nil {
2429
return nil, err
@@ -76,6 +81,10 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
7681
}
7782

7883
func signLegacy(priv *PrivateKey, csprng io.Reader, hash []byte) (sig []byte, err error) {
84+
if fips140only.Enabled {
85+
return nil, errors.New("crypto/ecdsa: use of custom curves is not allowed in FIPS 140-only mode")
86+
}
87+
7988
c := priv.Curve
8089

8190
// 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 {
144153
}
145154

146155
func verifyLegacy(pub *PublicKey, hash []byte, sig []byte) bool {
156+
if fips140only.Enabled {
157+
panic("crypto/ecdsa: use of custom curves is not allowed in FIPS 140-only mode")
158+
}
159+
147160
rBytes, sBytes, err := parseSignature(sig)
148161
if err != nil {
149162
return false

src/crypto/ed25519/ed25519.go

+7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package ed25519
1818
import (
1919
"crypto"
2020
"crypto/internal/fips140/ed25519"
21+
"crypto/internal/fips140only"
2122
cryptorand "crypto/rand"
2223
"crypto/subtle"
2324
"errors"
@@ -103,6 +104,9 @@ func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOp
103104
case hash == crypto.SHA512: // Ed25519ph
104105
return ed25519.SignPH(k, message, context)
105106
case hash == crypto.Hash(0) && context != "": // Ed25519ctx
107+
if fips140only.Enabled {
108+
return nil, errors.New("crypto/ed25519: use of Ed25519ctx is not allowed in FIPS 140-only mode")
109+
}
106110
return ed25519.SignCtx(k, message, context)
107111
case hash == crypto.Hash(0): // Ed25519
108112
return ed25519.Sign(k, message), nil
@@ -219,6 +223,9 @@ func VerifyWithOptions(publicKey PublicKey, message, sig []byte, opts *Options)
219223
case opts.Hash == crypto.SHA512: // Ed25519ph
220224
return ed25519.VerifyPH(k, message, sig, opts.Context)
221225
case opts.Hash == crypto.Hash(0) && opts.Context != "": // Ed25519ctx
226+
if fips140only.Enabled {
227+
return errors.New("crypto/ed25519: use of Ed25519ctx is not allowed in FIPS 140-only mode")
228+
}
222229
return ed25519.VerifyCtx(k, message, sig, opts.Context)
223230
case opts.Hash == crypto.Hash(0): // Ed25519
224231
return ed25519.Verify(k, message, sig)

src/crypto/hkdf/hkdf.go

+25
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package hkdf
66

77
import (
88
"crypto/internal/fips140/hkdf"
9+
"crypto/internal/fips140only"
910
"errors"
1011
"hash"
1112
)
@@ -17,6 +18,9 @@ import (
1718
// Expand invocations and different context values. Most common scenarios,
1819
// including the generation of multiple keys, should use [Key] instead.
1920
func Extract[H hash.Hash](h func() H, secret, salt []byte) ([]byte, error) {
21+
if err := checkFIPS140Only(h, secret); err != nil {
22+
return nil, err
23+
}
2024
return hkdf.Extract(h, secret, salt), nil
2125
}
2226

@@ -28,6 +32,10 @@ func Extract[H hash.Hash](h func() H, secret, salt []byte) ([]byte, error) {
2832
// random or pseudorandom cryptographically strong key. See RFC 5869, Section
2933
// 3.3. Most common scenarios will want to use [Key] instead.
3034
func Expand[H hash.Hash](h func() H, pseudorandomKey []byte, info string, keyLength int) ([]byte, error) {
35+
if err := checkFIPS140Only(h, pseudorandomKey); err != nil {
36+
return nil, err
37+
}
38+
3139
limit := h().Size() * 255
3240
if keyLength > limit {
3341
return nil, errors.New("hkdf: requested key length too large")
@@ -40,10 +48,27 @@ func Expand[H hash.Hash](h func() H, pseudorandomKey []byte, info string, keyLen
4048
// returning a []byte of length keyLength that can be used as cryptographic key.
4149
// Salt and info can be nil.
4250
func Key[Hash hash.Hash](h func() Hash, secret, salt []byte, info string, keyLength int) ([]byte, error) {
51+
if err := checkFIPS140Only(h, secret); err != nil {
52+
return nil, err
53+
}
54+
4355
limit := h().Size() * 255
4456
if keyLength > limit {
4557
return nil, errors.New("hkdf: requested key length too large")
4658
}
4759

4860
return hkdf.Key(h, secret, salt, info, keyLength), nil
4961
}
62+
63+
func checkFIPS140Only[H hash.Hash](h func() H, key []byte) error {
64+
if !fips140only.Enabled {
65+
return nil
66+
}
67+
if len(key) < 112/8 {
68+
return errors.New("crypto/hkdf: use of keys shorter than 112 bits is not allowed in FIPS 140-only mode")
69+
}
70+
if !fips140only.ApprovedHash(h()) {
71+
return errors.New("crypto/hkdf: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
72+
}
73+
return nil
74+
}

src/crypto/hmac/hmac.go

+9
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ package hmac
2424
import (
2525
"crypto/internal/boring"
2626
"crypto/internal/fips140/hmac"
27+
"crypto/internal/fips140only"
2728
"crypto/subtle"
2829
"hash"
2930
)
@@ -42,6 +43,14 @@ func New(h func() hash.Hash, key []byte) hash.Hash {
4243
}
4344
// BoringCrypto did not recognize h, so fall through to standard Go code.
4445
}
46+
if fips140only.Enabled {
47+
if len(key) < 112/8 {
48+
panic("crypto/hmac: use of keys shorter than 112 bits is not allowed in FIPS 140-only mode")
49+
}
50+
if !fips140only.ApprovedHash(h()) {
51+
panic("crypto/hmac: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
52+
}
53+
}
4554
return hmac.New(h, key)
4655
}
4756

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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 fips140only
6+
7+
import (
8+
"crypto/internal/fips140/sha256"
9+
"crypto/internal/fips140/sha3"
10+
"crypto/internal/fips140/sha512"
11+
"hash"
12+
"internal/godebug"
13+
)
14+
15+
// Enabled reports whether FIPS 140-only mode is enabled, in which non-approved
16+
// cryptography returns an error or panics.
17+
var Enabled = godebug.New("#fips140").Value() == "only"
18+
19+
func ApprovedHash(h hash.Hash) bool {
20+
switch h.(type) {
21+
case *sha256.Digest, *sha512.Digest, *sha3.Digest:
22+
return true
23+
default:
24+
return false
25+
}
26+
}

0 commit comments

Comments
 (0)