Skip to content
This repository was archived by the owner on Sep 2, 2021. It is now read-only.

Commit 374053e

Browse files
committed
openpgp/packet: improve handling of short MPIs for RSA values
MPIs are (supposed to be) stripped of leading zeroes. Avoid passing such short values into crypto/rsa, even if it currently happens to work. Change-Id: I5a5f4813b8358e83fcc2deeda1272d2733814542 Reviewed-on: https://go-review.googlesource.com/100844 Reviewed-by: Adam Langley <[email protected]>
1 parent b4956d3 commit 374053e

File tree

4 files changed

+65
-47
lines changed

4 files changed

+65
-47
lines changed

openpgp/packet/encrypted_key.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
7878
// padding oracle attacks.
7979
switch priv.PubKeyAlgo {
8080
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
81-
b, err = rsa.DecryptPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1.bytes)
81+
k := priv.PrivateKey.(*rsa.PrivateKey)
82+
b, err = rsa.DecryptPKCS1v15(config.Random(), k, padToKeySize(&k.PublicKey, e.encryptedMPI1.bytes))
8283
case PubKeyAlgoElGamal:
8384
c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes)
8485
c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes)

openpgp/packet/encrypted_key_test.go

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -39,39 +39,44 @@ var encryptedKeyPriv = &PrivateKey{
3939
}
4040

4141
func TestDecryptingEncryptedKey(t *testing.T) {
42-
const encryptedKeyHex = "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8"
43-
const expectedKeyHex = "d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b"
44-
45-
p, err := Read(readerFromHex(encryptedKeyHex))
46-
if err != nil {
47-
t.Errorf("error from Read: %s", err)
48-
return
49-
}
50-
ek, ok := p.(*EncryptedKey)
51-
if !ok {
52-
t.Errorf("didn't parse an EncryptedKey, got %#v", p)
53-
return
54-
}
55-
56-
if ek.KeyId != 0x2a67d68660df41c7 || ek.Algo != PubKeyAlgoRSA {
57-
t.Errorf("unexpected EncryptedKey contents: %#v", ek)
58-
return
59-
}
60-
61-
err = ek.Decrypt(encryptedKeyPriv, nil)
62-
if err != nil {
63-
t.Errorf("error from Decrypt: %s", err)
64-
return
65-
}
66-
67-
if ek.CipherFunc != CipherAES256 {
68-
t.Errorf("unexpected EncryptedKey contents: %#v", ek)
69-
return
70-
}
71-
72-
keyHex := fmt.Sprintf("%x", ek.Key)
73-
if keyHex != expectedKeyHex {
74-
t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex)
42+
for i, encryptedKeyHex := range []string{
43+
"c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8",
44+
// MPI can be shorter than the length of the key.
45+
"c18b032a67d68660df41c70103f8e520c52ae9807183c669ce26e772e482dc5d8cf60e6f59316e145be14d2e5221ee69550db1d5618a8cb002a719f1f0b9345bde21536d410ec90ba86cac37748dec7933eb7f9873873b2d61d3321d1cd44535014f6df58f7bc0c7afb5edc38e1a974428997d2f747f9a173bea9ca53079b409517d332df62d805564cffc9be6",
46+
} {
47+
const expectedKeyHex = "d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b"
48+
49+
p, err := Read(readerFromHex(encryptedKeyHex))
50+
if err != nil {
51+
t.Errorf("#%d: error from Read: %s", i, err)
52+
return
53+
}
54+
ek, ok := p.(*EncryptedKey)
55+
if !ok {
56+
t.Errorf("#%d: didn't parse an EncryptedKey, got %#v", i, p)
57+
return
58+
}
59+
60+
if ek.KeyId != 0x2a67d68660df41c7 || ek.Algo != PubKeyAlgoRSA {
61+
t.Errorf("#%d: unexpected EncryptedKey contents: %#v", i, ek)
62+
return
63+
}
64+
65+
err = ek.Decrypt(encryptedKeyPriv, nil)
66+
if err != nil {
67+
t.Errorf("#%d: error from Decrypt: %s", i, err)
68+
return
69+
}
70+
71+
if ek.CipherFunc != CipherAES256 {
72+
t.Errorf("#%d: unexpected EncryptedKey contents: %#v", i, ek)
73+
return
74+
}
75+
76+
keyHex := fmt.Sprintf("%x", ek.Key)
77+
if keyHex != expectedKeyHex {
78+
t.Errorf("#%d: bad key, got %s want %s", i, keyHex, expectedKeyHex)
79+
}
7580
}
7681
}
7782

@@ -121,7 +126,7 @@ func TestEncryptingEncryptedKey(t *testing.T) {
121126

122127
keyHex := fmt.Sprintf("%x", ek.Key)
123128
if keyHex != expectedKeyHex {
124-
t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex)
129+
t.Errorf("bad key, got %s want %s", keyHex, expectedKeyHex)
125130
}
126131
}
127132

openpgp/packet/packet.go

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ import (
1111
"crypto/aes"
1212
"crypto/cipher"
1313
"crypto/des"
14-
"golang.org/x/crypto/cast5"
15-
"golang.org/x/crypto/openpgp/errors"
14+
"crypto/rsa"
1615
"io"
1716
"math/big"
17+
18+
"golang.org/x/crypto/cast5"
19+
"golang.org/x/crypto/openpgp/errors"
1820
)
1921

2022
// readFull is the same as io.ReadFull except that reading zero bytes returns
@@ -500,19 +502,17 @@ func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err error) {
500502
numBytes := (int(bitLength) + 7) / 8
501503
mpi = make([]byte, numBytes)
502504
_, err = readFull(r, mpi)
503-
return
504-
}
505-
506-
// mpiLength returns the length of the given *big.Int when serialized as an
507-
// MPI.
508-
func mpiLength(n *big.Int) (mpiLengthInBytes int) {
509-
mpiLengthInBytes = 2 /* MPI length */
510-
mpiLengthInBytes += (n.BitLen() + 7) / 8
505+
// According to RFC 4880 3.2. we should check that the MPI has no leading
506+
// zeroes (at least when not an encrypted MPI?), but this implementation
507+
// does generate leading zeroes, so we keep accepting them.
511508
return
512509
}
513510

514511
// writeMPI serializes a big integer to w.
515512
func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err error) {
513+
// Note that we can produce leading zeroes, in violation of RFC 4880 3.2.
514+
// Implementations seem to be tolerant of them, and stripping them would
515+
// make it complex to guarantee matching re-serialization.
516516
_, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)})
517517
if err == nil {
518518
_, err = w.Write(mpiBytes)
@@ -525,6 +525,18 @@ func writeBig(w io.Writer, i *big.Int) error {
525525
return writeMPI(w, uint16(i.BitLen()), i.Bytes())
526526
}
527527

528+
// padToKeySize left-pads a MPI with zeroes to match the length of the
529+
// specified RSA public.
530+
func padToKeySize(pub *rsa.PublicKey, b []byte) []byte {
531+
k := (pub.N.BitLen() + 7) / 8
532+
if len(b) >= k {
533+
return b
534+
}
535+
bb := make([]byte, k)
536+
copy(bb[len(bb)-len(b):], b)
537+
return bb
538+
}
539+
528540
// CompressionAlgo Represents the different compression algorithms
529541
// supported by OpenPGP (except for BZIP2, which is not currently
530542
// supported). See Section 9.3 of RFC 4880.

openpgp/packet/public_key.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err erro
520520
switch pk.PubKeyAlgo {
521521
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
522522
rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey)
523-
err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes)
523+
err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.bytes))
524524
if err != nil {
525525
return errors.SignatureError("RSA verification failure")
526526
}
@@ -571,7 +571,7 @@ func (pk *PublicKey) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err
571571
switch pk.PubKeyAlgo {
572572
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
573573
rsaPublicKey := pk.PublicKey.(*rsa.PublicKey)
574-
if err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes); err != nil {
574+
if err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.bytes)); err != nil {
575575
return errors.SignatureError("RSA verification failure")
576576
}
577577
return

0 commit comments

Comments
 (0)