Skip to content

Commit fb41d5e

Browse files
FiloSottilegopherbot
authored andcommitted
crypto/rsa: minor FIPS 186-5 compliance fixes
None of these checks actually matter, and indeed we didn't have them before, but they are required by FIPS 186-5. Fixes #69799 For #69536 Change-Id: I5e866962a1b2a31a753053e5b9ec50a3f4c87394 Reviewed-on: https://go-review.googlesource.com/c/go/+/632535 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 50a8b3a commit fb41d5e

File tree

7 files changed

+171
-44
lines changed

7 files changed

+171
-44
lines changed

src/crypto/internal/fips140/bigmod/nat.go

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,10 @@ func (x *Nat) SetOverflowingBytes(b []byte, m *Modulus) (*Nat, error) {
173173
if err := x.setBytes(b); err != nil {
174174
return nil, err
175175
}
176-
leading := _W - bitLen(x.limbs[len(x.limbs)-1])
177-
if leading < m.leading {
176+
// setBytes would have returned an error if the input overflowed the limb
177+
// size of the modulus, so now we only need to check if the most significant
178+
// limb of x has more bits than the most significant limb of the modulus.
179+
if bitLen(x.limbs[len(x.limbs)-1]) > bitLen(m.nat.limbs[len(m.nat.limbs)-1]) {
178180
return nil, errors.New("input overflows the modulus size")
179181
}
180182
x.maybeSubtractModulus(no, m)
@@ -390,6 +392,37 @@ func (x *Nat) ShiftRightVarTime(n uint) *Nat {
390392
return x
391393
}
392394

395+
// BitLenVarTime returns the actual size of x in bits.
396+
//
397+
// The actual size of x (but nothing more) leaks through timing side-channels.
398+
// Note that this is ordinarily secret, as opposed to the announced size of x.
399+
func (x *Nat) BitLenVarTime() int {
400+
// Eliminate bounds checks in the loop.
401+
size := len(x.limbs)
402+
xLimbs := x.limbs[:size]
403+
404+
for i := size - 1; i >= 0; i-- {
405+
if xLimbs[i] != 0 {
406+
return i*_W + bitLen(xLimbs[i])
407+
}
408+
}
409+
return 0
410+
}
411+
412+
// bitLen is a version of bits.Len that only leaks the bit length of n, but not
413+
// its value. bits.Len and bits.LeadingZeros use a lookup table for the
414+
// low-order bits on some architectures.
415+
func bitLen(n uint) int {
416+
len := 0
417+
// We assume, here and elsewhere, that comparison to zero is constant time
418+
// with respect to different non-zero values.
419+
for n != 0 {
420+
len++
421+
n >>= 1
422+
}
423+
return len
424+
}
425+
393426
// Modulus is used for modular arithmetic, precomputing relevant constants.
394427
//
395428
// A Modulus can leak the exact number of bits needed to store its value
@@ -399,8 +432,7 @@ type Modulus struct {
399432
//
400433
// This will be stored without any padding, and shouldn't alias with any
401434
// other natural number being used.
402-
nat *Nat
403-
leading int // number of leading zeros in the modulus
435+
nat *Nat
404436

405437
// If m is even, the following fields are not set.
406438
odd bool
@@ -501,7 +533,6 @@ func newModulus(n *Nat) (*Modulus, error) {
501533
if m.nat.IsZero() == yes || m.nat.IsOne() == yes {
502534
return nil, errors.New("modulus must be > 1")
503535
}
504-
m.leading = _W - bitLen(m.nat.limbs[len(m.nat.limbs)-1])
505536
if m.nat.IsOdd() == 1 {
506537
m.odd = true
507538
m.m0inv = minusInverseModW(m.nat.limbs[0])
@@ -510,28 +541,14 @@ func newModulus(n *Nat) (*Modulus, error) {
510541
return m, nil
511542
}
512543

513-
// bitLen is a version of bits.Len that only leaks the bit length of n, but not
514-
// its value. bits.Len and bits.LeadingZeros use a lookup table for the
515-
// low-order bits on some architectures.
516-
func bitLen(n uint) int {
517-
var len int
518-
// We assume, here and elsewhere, that comparison to zero is constant time
519-
// with respect to different non-zero values.
520-
for n != 0 {
521-
len++
522-
n >>= 1
523-
}
524-
return len
525-
}
526-
527544
// Size returns the size of m in bytes.
528545
func (m *Modulus) Size() int {
529546
return (m.BitLen() + 7) / 8
530547
}
531548

532549
// BitLen returns the size of m in bits.
533550
func (m *Modulus) BitLen() int {
534-
return len(m.nat.limbs)*_W - int(m.leading)
551+
return m.nat.BitLenVarTime()
535552
}
536553

537554
// Nat returns m as a Nat.
@@ -974,7 +991,7 @@ func (out *Nat) ExpShortVarTime(x *Nat, e uint, m *Modulus) *Nat {
974991
// chain, skipping the initial run of zeroes.
975992
xR := NewNat().set(x).montgomeryRepresentation(m)
976993
out.set(xR)
977-
for i := bits.UintSize - bitLen(e) + 1; i < bits.UintSize; i++ {
994+
for i := bits.UintSize - bits.Len(e) + 1; i < bits.UintSize; i++ {
978995
out.montgomeryMul(out, out, m)
979996
if k := (e >> (bits.UintSize - i - 1)) & 1; k != 0 {
980997
out.montgomeryMul(out, xR, m)

src/crypto/internal/fips140/rsa/keygen.go

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func GenerateKey(rand io.Reader, bits int) (*PrivateKey, error) {
2222
return nil, errors.New("rsa: key too small")
2323
}
2424
fips140.RecordApproved()
25-
if bits < 2048 || bits > 16384 {
25+
if bits < 2048 || bits > 16384 || bits%2 == 1 {
2626
fips140.RecordNonApproved()
2727
}
2828

@@ -53,28 +53,44 @@ func GenerateKey(rand io.Reader, bits int) (*PrivateKey, error) {
5353
return nil, errors.New("rsa: internal error: modulus size incorrect")
5454
}
5555

56-
φ, err := bigmod.NewModulusProduct(P.Nat().SubOne(N).Bytes(N),
57-
Q.Nat().SubOne(N).Bytes(N))
56+
φ, err := bigmod.NewModulusProduct(P.Nat().SubOne(P).Bytes(P),
57+
Q.Nat().SubOne(Q).Bytes(Q))
5858
if err != nil {
5959
return nil, err
6060
}
6161

6262
e := bigmod.NewNat().SetUint(65537)
6363
d, ok := bigmod.NewNat().InverseVarTime(e, φ)
6464
if !ok {
65+
// This checks that GCD(e, (p-1)(q-1)) = 1, which is equivalent
66+
// to checking GCD(e, p-1) = 1 and GCD(e, q-1) = 1 separately in
67+
// FIPS 186-5, Appendix A.1.3, steps 4.5 and 5.6.
6568
continue
6669
}
6770

6871
if e.ExpandFor(φ).Mul(d, φ).IsOne() == 0 {
6972
return nil, errors.New("rsa: internal error: e*d != 1 mod φ(N)")
7073
}
7174

75+
// FIPS 186-5, A.1.1(3) requires checking that d > 2^(nlen / 2).
76+
//
77+
// The probability of this check failing when d is derived from
78+
// (e, p, q) is roughly
79+
//
80+
// 2^(nlen/2) / 2^nlen = 2^(-nlen/2)
81+
//
82+
// so less than 2⁻¹²⁸ for keys larger than 256 bits.
83+
//
84+
// We still need to check to comply with FIPS 186-5, but knowing it has
85+
// negligible chance of failure we can defer the check to the end of key
86+
// generation and return an error if it fails. See [checkPrivateKey].
87+
7288
return newPrivateKey(N, 65537, d, P, Q)
7389
}
7490
}
7591

76-
// randomPrime returns a random prime number of the given bit size.
77-
// rand is ignored in FIPS mode.
92+
// randomPrime returns a random prime number of the given bit size following
93+
// the process in FIPS 186-5, Appendix A.1.3. rand is ignored in FIPS mode.
7894
func randomPrime(rand io.Reader, bits int) ([]byte, error) {
7995
if bits < 64 {
8096
return nil, errors.New("rsa: prime size must be at least 32-bit")
@@ -108,6 +124,22 @@ func randomPrime(rand io.Reader, bits int) ([]byte, error) {
108124
// Make the value odd since an even number certainly isn't prime.
109125
b[len(b)-1] |= 1
110126

127+
// We don't need to check for p >= √2 × 2^(bits-1) (steps 4.4 and 5.4)
128+
// because we set the top two bits above, so
129+
//
130+
// p > 2^(bits-1) + 2^(bits-2) = 3⁄2 × 2^(bits-1) > √2 × 2^(bits-1)
131+
//
132+
133+
// Step 5.5 requires checking that |p - q| > 2^(nlen/2 - 100).
134+
//
135+
// The probability of |p - q| ≤ k where p and q are uniformly random in
136+
// the range (a, b) is 1 - (b-a-k)^2 / (b-a)^2, so the probability of
137+
// this check failing during key generation is 2⁻⁹⁷.
138+
//
139+
// We still need to check to comply with FIPS 186-5, but knowing it has
140+
// negligible chance of failure we can defer the check to the end of key
141+
// generation and return an error if it fails. See [checkPrivateKey].
142+
111143
if isPrime(b) {
112144
return b, nil
113145
}

src/crypto/internal/fips140/rsa/pkcs1v15.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,10 @@ func VerifyPKCS1v15(pub *PublicKey, hash string, hashed []byte, sig []byte) erro
9999
}
100100

101101
func verifyPKCS1v15(pub *PublicKey, hash string, hashed []byte, sig []byte) error {
102-
if err := checkPublicKey(pub); err != nil {
102+
if fipsApproved, err := checkPublicKey(pub); err != nil {
103103
return err
104+
} else if !fipsApproved {
105+
fips140.RecordNonApproved()
104106
}
105107

106108
// RFC 8017 Section 8.2.2: If the length of the signature S is not k

src/crypto/internal/fips140/rsa/pkcs1v22.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,8 +333,10 @@ func verifyPSS(pub *PublicKey, hash fips140.Hash, digest []byte, sig []byte, sal
333333
fipsSelfTest()
334334
fips140.RecordApproved()
335335
checkApprovedHash(hash)
336-
if err := checkPublicKey(pub); err != nil {
336+
if fipsApproved, err := checkPublicKey(pub); err != nil {
337337
return err
338+
} else if !fipsApproved {
339+
fips140.RecordNonApproved()
338340
}
339341

340342
if len(sig) != pub.Size() {
@@ -384,8 +386,10 @@ func EncryptOAEP(hash, mgfHash fips140.Hash, random io.Reader, pub *PublicKey, m
384386
fipsSelfTest()
385387
fips140.RecordApproved()
386388
checkApprovedHash(hash)
387-
if err := checkPublicKey(pub); err != nil {
389+
if fipsApproved, err := checkPublicKey(pub); err != nil {
388390
return nil, err
391+
} else if !fipsApproved {
392+
fips140.RecordNonApproved()
389393
}
390394
k := pub.Size()
391395
if len(msg) > k-2*hash.Size()-2 {

src/crypto/internal/fips140/rsa/rsa.go

Lines changed: 77 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,12 @@ type PrivateKey struct {
3333
p, q *bigmod.Modulus // p × q = n
3434
// dP and dQ are used as exponents, so we store them as big-endian byte
3535
// slices to be passed to [bigmod.Nat.Exp].
36-
dP []byte // d mod (p 1)
37-
dQ []byte // d mod (q 1)
36+
dP []byte // d mod (p - 1)
37+
dQ []byte // d mod (q - 1)
3838
qInv *bigmod.Nat // qInv = q⁻¹ mod p
39+
// fipsApproved is false if this key does not comply with FIPS 186-5 or
40+
// SP 800-56B Rev. 2.
41+
fipsApproved bool
3942
}
4043

4144
func (priv *PrivateKey) PublicKey() *PublicKey {
@@ -184,20 +187,33 @@ func (priv *PrivateKey) Export() (N []byte, e int, d, P, Q, dP, dQ, qInv []byte)
184187
return
185188
}
186189

190+
// checkPrivateKey is called by the NewPrivateKey and GenerateKey functions, and
191+
// is allowed to modify priv.fipsApproved.
187192
func checkPrivateKey(priv *PrivateKey) error {
188-
if err := checkPublicKey(&priv.pub); err != nil {
193+
priv.fipsApproved = true
194+
195+
if fipsApproved, err := checkPublicKey(&priv.pub); err != nil {
189196
return err
197+
} else if !fipsApproved {
198+
priv.fipsApproved = false
190199
}
191200

192201
if priv.dP == nil {
202+
// Legacy and deprecated multi-prime keys.
203+
priv.fipsApproved = false
193204
return nil
194205
}
195206

196207
N := priv.pub.N
197208
p := priv.p
198209
q := priv.q
199210

200-
// Check that pq ≡ 1 mod N (and that pN < N and q < N).
211+
// FIPS 186-5, Section 5.1 requires "that p and q be of the same bit length."
212+
if p.BitLen() != q.BitLen() {
213+
priv.fipsApproved = false
214+
}
215+
216+
// Check that pq ≡ 1 mod N (and that p < N and q < N).
201217
pN := bigmod.NewNat().ExpandFor(N)
202218
if _, err := pN.SetBytes(p.Nat().Bytes(p), N); err != nil {
203219
return errors.New("crypto/rsa: invalid prime")
@@ -254,46 +270,89 @@ func checkPrivateKey(priv *PrivateKey) error {
254270
return errors.New("crypto/rsa: invalid CRT coefficient")
255271
}
256272

273+
// Check that |p - q| > 2^(nlen/2 - 100).
274+
//
275+
// If p and q are very close to each other, then N=pq can be trivially
276+
// factored using Fermat's factorization method. Broken RSA implementations
277+
// do generate such keys. See Hanno Böck, Fermat Factorization in the Wild,
278+
// https://eprint.iacr.org/2023/026.pdf.
279+
diff := bigmod.NewNat()
280+
if qP, err := bigmod.NewNat().SetBytes(q.Nat().Bytes(q), p); err != nil {
281+
// q > p
282+
pQ, err := bigmod.NewNat().SetBytes(p.Nat().Bytes(p), q)
283+
if err != nil {
284+
return errors.New("crypto/rsa: p == q")
285+
}
286+
// diff = 0 - p mod q = q - p
287+
diff.ExpandFor(q).Sub(pQ, q)
288+
} else {
289+
// p > q
290+
// diff = 0 - q mod p = p - q
291+
diff.ExpandFor(p).Sub(qP, p)
292+
}
293+
// A tiny bit of leakage is acceptable because it's not adaptive, an
294+
// attacker only learns the magnitude of p - q.
295+
if diff.BitLenVarTime() <= N.BitLen()/2-100 {
296+
return errors.New("crypto/rsa: |p - q| too small")
297+
}
298+
299+
// Check that d > 2^(nlen/2).
300+
//
301+
// See section 3 of https://crypto.stanford.edu/~dabo/papers/RSA-survey.pdf
302+
// for more details about attacks on small d values.
303+
//
304+
// Likewise, the leakage of the magnitude of d is not adaptive.
305+
if priv.d.BitLenVarTime() <= N.BitLen()/2 {
306+
return errors.New("crypto/rsa: d too small")
307+
}
308+
257309
return nil
258310
}
259311

260-
func checkPublicKey(pub *PublicKey) error {
312+
func checkPublicKey(pub *PublicKey) (fipsApproved bool, err error) {
313+
fipsApproved = true
261314
if pub.N == nil {
262-
return errors.New("crypto/rsa: missing public modulus")
315+
return false, errors.New("crypto/rsa: missing public modulus")
263316
}
264317
if pub.N.Nat().IsOdd() == 0 {
265-
return errors.New("crypto/rsa: public modulus is even")
318+
return false, errors.New("crypto/rsa: public modulus is even")
266319
}
320+
// FIPS 186-5, Section 5.1: "This standard specifies the use of a modulus
321+
// whose bit length is an even integer and greater than or equal to 2048
322+
// bits."
267323
if pub.N.BitLen() < 2048 || pub.N.BitLen() > 16384 {
268-
fips140.RecordNonApproved()
324+
fipsApproved = false
325+
}
326+
if pub.N.BitLen()%2 == 1 {
327+
fipsApproved = false
269328
}
270329
if pub.E < 2 {
271-
return errors.New("crypto/rsa: public exponent too small or negative")
330+
return false, errors.New("crypto/rsa: public exponent too small or negative")
272331
}
273332
// e needs to be coprime with p-1 and q-1, since it must be invertible
274333
// modulo λ(pq). Since p and q are prime, this means e needs to be odd.
275334
if pub.E&1 == 0 {
276-
return errors.New("crypto/rsa: public exponent is even")
335+
return false, errors.New("crypto/rsa: public exponent is even")
277336
}
278337
// FIPS 186-5, Section 5.5(e): "The exponent e shall be an odd, positive
279338
// integer such that 2¹⁶ < e < 2²⁵⁶."
280339
if pub.E <= 1<<16 {
281-
fips140.RecordNonApproved()
340+
fipsApproved = false
282341
}
283342
// We require pub.E to fit into a 32-bit integer so that we
284343
// do not have different behavior depending on whether
285344
// int is 32 or 64 bits. See also
286345
// https://www.imperialviolet.org/2012/03/16/rsae.html.
287346
if pub.E > 1<<31-1 {
288-
return errors.New("crypto/rsa: public exponent too large")
347+
return false, errors.New("crypto/rsa: public exponent too large")
289348
}
290-
return nil
349+
return fipsApproved, nil
291350
}
292351

293352
// Encrypt performs the RSA public key operation.
294353
func Encrypt(pub *PublicKey, plaintext []byte) ([]byte, error) {
295354
fips140.RecordNonApproved()
296-
if err := checkPublicKey(pub); err != nil {
355+
if _, err := checkPublicKey(pub); err != nil {
297356
return nil, err
298357
}
299358
return encrypt(pub, plaintext)
@@ -331,6 +390,10 @@ func DecryptWithCheck(priv *PrivateKey, ciphertext []byte) ([]byte, error) {
331390
// m^e is calculated and compared with ciphertext, in order to defend against
332391
// errors in the CRT computation.
333392
func decrypt(priv *PrivateKey, ciphertext []byte, check bool) ([]byte, error) {
393+
if !priv.fipsApproved {
394+
fips140.RecordNonApproved()
395+
}
396+
334397
var m *bigmod.Nat
335398
N, E := priv.pub.N, priv.pub.E
336399

0 commit comments

Comments
 (0)