Skip to content

Commit f5a89df

Browse files
FiloSottilegopherbot
authored andcommitted
crypto: fix fips140=only detection of SHA-3
Both fips140only and the service indicator checks in crypto/internal/fips140/... expect to type assert to crypto/internal/fips140/{sha256,sha512,sha3}.Digest. However, crypto/sha3 returns a wrapper concrete type around sha3.Digest. Add a new fips140hash.Unwrap function to turn the wrapper into the underlying sha3.Digest, and use it consistently before calling into fips140only or the FIPS 140-3 module. In crypto/rsa, also made the fips140only checks apply consistently after the Go+BoringCrypto shims, so we can instantiate the hash, and avoid having to wrap the New function. Note that fips140=only is incompatible with Go+BoringCrypto. Fixes #70879 Change-Id: I6a6a4656ec55c3e13f6cbfadb9cf89c0f9183bdc Reviewed-on: https://go-review.googlesource.com/c/go/+/640855 Auto-Submit: Filippo Valsorda <[email protected]> Reviewed-by: Roland Shoemaker <[email protected]> Reviewed-by: Russ Cox <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 4225c6c commit f5a89df

File tree

8 files changed

+139
-73
lines changed

8 files changed

+139
-73
lines changed

src/crypto/ecdsa/ecdsa.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"crypto/internal/boring"
2424
"crypto/internal/boring/bbig"
2525
"crypto/internal/fips140/ecdsa"
26+
"crypto/internal/fips140hash"
2627
"crypto/internal/fips140only"
2728
"crypto/internal/randutil"
2829
"crypto/sha512"
@@ -281,10 +282,11 @@ func signFIPSDeterministic[P ecdsa.Point[P]](c *ecdsa.Curve[P], hashFunc crypto.
281282
if err != nil {
282283
return nil, err
283284
}
284-
if fips140only.Enabled && !fips140only.ApprovedHash(hashFunc.New()) {
285+
h := fips140hash.UnwrapNew(hashFunc.New)
286+
if fips140only.Enabled && !fips140only.ApprovedHash(h()) {
285287
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")
286288
}
287-
sig, err := ecdsa.SignDeterministic(c, hashFunc.New, k, hash)
289+
sig, err := ecdsa.SignDeterministic(c, h, k, hash)
288290
if err != nil {
289291
return nil, err
290292
}

src/crypto/hkdf/hkdf.go

+13-9
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ package hkdf
1212

1313
import (
1414
"crypto/internal/fips140/hkdf"
15+
"crypto/internal/fips140hash"
1516
"crypto/internal/fips140only"
1617
"errors"
1718
"hash"
@@ -24,10 +25,11 @@ import (
2425
// Expand invocations and different context values. Most common scenarios,
2526
// including the generation of multiple keys, should use [Key] instead.
2627
func Extract[H hash.Hash](h func() H, secret, salt []byte) ([]byte, error) {
27-
if err := checkFIPS140Only(h, secret); err != nil {
28+
fh := fips140hash.UnwrapNew(h)
29+
if err := checkFIPS140Only(fh, secret); err != nil {
2830
return nil, err
2931
}
30-
return hkdf.Extract(h, secret, salt), nil
32+
return hkdf.Extract(fh, secret, salt), nil
3133
}
3234

3335
// Expand derives a key from the given hash, key, and optional context info,
@@ -38,35 +40,37 @@ func Extract[H hash.Hash](h func() H, secret, salt []byte) ([]byte, error) {
3840
// random or pseudorandom cryptographically strong key. See RFC 5869, Section
3941
// 3.3. Most common scenarios will want to use [Key] instead.
4042
func Expand[H hash.Hash](h func() H, pseudorandomKey []byte, info string, keyLength int) ([]byte, error) {
41-
if err := checkFIPS140Only(h, pseudorandomKey); err != nil {
43+
fh := fips140hash.UnwrapNew(h)
44+
if err := checkFIPS140Only(fh, pseudorandomKey); err != nil {
4245
return nil, err
4346
}
4447

45-
limit := h().Size() * 255
48+
limit := fh().Size() * 255
4649
if keyLength > limit {
4750
return nil, errors.New("hkdf: requested key length too large")
4851
}
4952

50-
return hkdf.Expand(h, pseudorandomKey, info, keyLength), nil
53+
return hkdf.Expand(fh, pseudorandomKey, info, keyLength), nil
5154
}
5255

5356
// Key derives a key from the given hash, secret, salt and context info,
5457
// returning a []byte of length keyLength that can be used as cryptographic key.
5558
// Salt and info can be nil.
5659
func Key[Hash hash.Hash](h func() Hash, secret, salt []byte, info string, keyLength int) ([]byte, error) {
57-
if err := checkFIPS140Only(h, secret); err != nil {
60+
fh := fips140hash.UnwrapNew(h)
61+
if err := checkFIPS140Only(fh, secret); err != nil {
5862
return nil, err
5963
}
6064

61-
limit := h().Size() * 255
65+
limit := fh().Size() * 255
6266
if keyLength > limit {
6367
return nil, errors.New("hkdf: requested key length too large")
6468
}
6569

66-
return hkdf.Key(h, secret, salt, info, keyLength), nil
70+
return hkdf.Key(fh, secret, salt, info, keyLength), nil
6771
}
6872

69-
func checkFIPS140Only[H hash.Hash](h func() H, key []byte) error {
73+
func checkFIPS140Only[Hash hash.Hash](h func() Hash, key []byte) error {
7074
if !fips140only.Enabled {
7175
return nil
7276
}

src/crypto/hmac/hmac.go

+2
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/fips140hash"
2728
"crypto/internal/fips140only"
2829
"crypto/subtle"
2930
"hash"
@@ -43,6 +44,7 @@ func New(h func() hash.Hash, key []byte) hash.Hash {
4344
}
4445
// BoringCrypto did not recognize h, so fall through to standard Go code.
4546
}
47+
h = fips140hash.UnwrapNew(h)
4648
if fips140only.Enabled {
4749
if len(key) < 112/8 {
4850
panic("crypto/hmac: use of keys shorter than 112 bits is not allowed in FIPS 140-only mode")
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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 fips140hash
6+
7+
import (
8+
fsha3 "crypto/internal/fips140/sha3"
9+
"crypto/sha3"
10+
"hash"
11+
_ "unsafe"
12+
)
13+
14+
//go:linkname sha3Unwrap
15+
func sha3Unwrap(*sha3.SHA3) *fsha3.Digest
16+
17+
// Unwrap returns h, or a crypto/internal/fips140 inner implementation of h.
18+
//
19+
// The return value can be type asserted to one of
20+
// [crypto/internal/fips140/sha256.Digest],
21+
// [crypto/internal/fips140/sha512.Digest], or
22+
// [crypto/internal/fips140/sha3.Digest] if it is a FIPS 140-3 approved hash.
23+
func Unwrap(h hash.Hash) hash.Hash {
24+
if sha3, ok := h.(*sha3.SHA3); ok {
25+
return sha3Unwrap(sha3)
26+
}
27+
return h
28+
}
29+
30+
// UnwrapNew returns a function that calls newHash and applies [Unwrap] to the
31+
// return value.
32+
func UnwrapNew[Hash hash.Hash](newHash func() Hash) func() hash.Hash {
33+
return func() hash.Hash { return Unwrap(newHash()) }
34+
}

src/crypto/pbkdf2/pbkdf2.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ package pbkdf2
1212

1313
import (
1414
"crypto/internal/fips140/pbkdf2"
15+
"crypto/internal/fips140hash"
1516
"crypto/internal/fips140only"
1617
"errors"
1718
"hash"
@@ -34,16 +35,17 @@ import (
3435
// Using a higher iteration count will increase the cost of an exhaustive
3536
// search but will also make derivation proportionally slower.
3637
func Key[Hash hash.Hash](h func() Hash, password string, salt []byte, iter, keyLength int) ([]byte, error) {
38+
fh := fips140hash.UnwrapNew(h)
3739
if fips140only.Enabled {
3840
if keyLength < 112/8 {
3941
return nil, errors.New("crypto/pbkdf2: use of keys shorter than 112 bits is not allowed in FIPS 140-only mode")
4042
}
4143
if len(salt) < 128/8 {
4244
return nil, errors.New("crypto/pbkdf2: use of salts shorter than 128 bits is not allowed in FIPS 140-only mode")
4345
}
44-
if !fips140only.ApprovedHash(h()) {
46+
if !fips140only.ApprovedHash(fh()) {
4547
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")
4648
}
4749
}
48-
return pbkdf2.Key(h, password, salt, iter, keyLength)
50+
return pbkdf2.Key(fh, password, salt, iter, keyLength)
4951
}

0 commit comments

Comments
 (0)