1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-09-20 14:51:42 +02:00

gpg: Fix DoS while parsing mangled secret key packets.

* g10/parse-packet.c (parse_key): Check PKTLEN before calling mpi_read
et al.
--

Due to the missing length checks PKTLEN may turn negative.  Because
PKTLEN is an unsigned int the malloc in read_rest would try to malloc
a too large number and terminate the process with "error reading rest
of packet: Cannot allocate memory".

Reported-by: Hanno Böck.
Signed-off-by: Werner Koch <wk@gnupg.org>
(backported from 2.0 commit 0aac920f23)
This commit is contained in:
Werner Koch 2015-04-05 19:42:59 +02:00
parent f34d88364a
commit 506eb6fec6
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B

View File

@ -1747,6 +1747,12 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
byte temp[16];
size_t snlen = 0;
if (pktlen < 1)
{
rc = G10ERR_INVALID_PACKET;
goto leave;
}
if( !npkey ) {
sk->skey[0] = mpi_set_opaque( NULL,
read_rest(inp, pktlen, 0), pktlen );
@ -1755,7 +1761,9 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
}
for(i=0; i < npkey; i++ ) {
n = pktlen; sk->skey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;
n = pktlen;
sk->skey[i] = mpi_read(inp, &n, 0 );
pktlen -=n;
if( list_mode ) {
fprintf (listfp, "\tskey[%d]: ", i);
mpi_print(listfp, sk->skey[i], mpi_print_mode );
@ -1769,7 +1777,8 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
if (list_mode && npkey)
keyid_from_sk (sk, keyid);
sk->protect.algo = iobuf_get_noeof(inp); pktlen--;
sk->protect.algo = iobuf_get_noeof(inp);
pktlen--;
sk->protect.sha1chk = 0;
if( sk->protect.algo ) {
sk->is_protected = 1;
@ -1780,12 +1789,15 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
goto leave;
}
sk->protect.sha1chk = (sk->protect.algo == 254);
sk->protect.algo = iobuf_get_noeof(inp); pktlen--;
sk->protect.algo = iobuf_get_noeof(inp);
pktlen--;
/* Note that a sk->protect.algo > 110 is illegal, but
I'm not erroring on it here as otherwise there
would be no way to delete such a key. */
sk->protect.s2k.mode = iobuf_get_noeof(inp); pktlen--;
sk->protect.s2k.hash_algo = iobuf_get_noeof(inp); pktlen--;
sk->protect.s2k.mode = iobuf_get_noeof(inp);
pktlen--;
sk->protect.s2k.hash_algo = iobuf_get_noeof(inp);
pktlen--;
/* check for the special GNU extension */
if( is_v4 && sk->protect.s2k.mode == 101 ) {
for(i=0; i < 4 && pktlen; i++, pktlen-- )
@ -1940,6 +1952,11 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
/* ugly; the length is encrypted too, so we read all
* stuff up to the end of the packet into the first
* skey element */
if (pktlen < 2) /* At least two bytes for the length. */
{
rc = G10ERR_INVALID_PACKET;
goto leave;
}
sk->skey[npkey] = mpi_set_opaque(NULL,
read_rest(inp, pktlen, 0),pktlen);
pktlen = 0;
@ -1955,6 +1972,11 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
fprintf (listfp, "\tskey[%d]: [encrypted]\n", i);
}
else {
if (pktlen < 2) /* At least two bytes for the length. */
{
rc = G10ERR_INVALID_PACKET;
goto leave;
}
n = pktlen;
sk->skey[i] = mpi_read(inp, &n, 0 );
pktlen -=n;
@ -1971,7 +1993,13 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
if (rc)
goto leave;
sk->csum = read_16(inp); pktlen -= 2;
if (pktlen < 2)
{
rc = G10ERR_INVALID_PACKET;
goto leave;
}
sk->csum = read_16(inp);
pktlen -= 2;
if( list_mode ) {
fprintf (listfp, "\tchecksum: %04hx\n", sk->csum);
}
@ -1980,6 +2008,12 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
else {
PKT_public_key *pk = pkt->pkt.public_key;
if (pktlen < 1)
{
rc = G10ERR_INVALID_PACKET;
goto leave;
}
if( !npkey ) {
pk->pkey[0] = mpi_set_opaque( NULL,
read_rest(inp, pktlen, 0), pktlen );
@ -1988,7 +2022,9 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
}
for(i=0; i < npkey; i++ ) {
n = pktlen; pk->pkey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;
n = pktlen;
pk->pkey[i] = mpi_read(inp, &n, 0 );
pktlen -=n;
if( list_mode ) {
fprintf (listfp, "\tpkey[%d]: ", i);
mpi_print(listfp, pk->pkey[i], mpi_print_mode );