Skip to content

Commit 57415dd

Browse files
committed
Add recursion limit for ASN.1 indefinite lengths
The libkrb5 ASN.1 decoder supports BER indefinite lengths. It computes the tag length using recursion; the lack of a recursion limit allows an attacker to overrun the stack and cause the process to crash. Reported by Demi Obenour. CVE-2020-28196: In MIT krb5 releases 1.11 and later, an unauthenticated attacker can cause a denial of service for any client or server to which it can send an ASN.1-encoded Kerberos message of sufficient length. ticket: 8959 (new) tags: pullup target_version: 1.18-next target_version: 1.17-next
1 parent 04c2b74 commit 57415dd

File tree

1 file changed

+9
-7
lines changed

1 file changed

+9
-7
lines changed

Diff for: src/lib/krb5/asn.1/asn1_encode.c

+9-7
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ make_tag(asn1buf *buf, const taginfo *t, size_t len)
356356
static krb5_error_code
357357
get_tag(const uint8_t *asn1, size_t len, taginfo *tag_out,
358358
const uint8_t **contents_out, size_t *clen_out,
359-
const uint8_t **remainder_out, size_t *rlen_out)
359+
const uint8_t **remainder_out, size_t *rlen_out, int recursion)
360360
{
361361
krb5_error_code ret;
362362
uint8_t o;
@@ -394,9 +394,11 @@ get_tag(const uint8_t *asn1, size_t len, taginfo *tag_out,
394394
/* Indefinite form (should not be present in DER, but we accept it). */
395395
if (tag_out->construction != CONSTRUCTED)
396396
return ASN1_MISMATCH_INDEF;
397+
if (recursion >= 32)
398+
return ASN1_OVERFLOW;
397399
p = asn1;
398400
while (!(len >= 2 && p[0] == 0 && p[1] == 0)) {
399-
ret = get_tag(p, len, &t, &c, &clen, &p, &len);
401+
ret = get_tag(p, len, &t, &c, &clen, &p, &len, recursion + 1);
400402
if (ret)
401403
return ret;
402404
}
@@ -613,7 +615,7 @@ split_der(asn1buf *buf, uint8_t *const *der, size_t len, taginfo *tag_out)
613615
const uint8_t *contents, *remainder;
614616
size_t clen, rlen;
615617

616-
ret = get_tag(*der, len, tag_out, &contents, &clen, &remainder, &rlen);
618+
ret = get_tag(*der, len, tag_out, &contents, &clen, &remainder, &rlen, 0);
617619
if (ret)
618620
return ret;
619621
if (rlen != 0)
@@ -1199,7 +1201,7 @@ decode_atype(const taginfo *t, const uint8_t *asn1, size_t len,
11991201
const uint8_t *rem;
12001202
size_t rlen;
12011203
if (!tag->implicit) {
1202-
ret = get_tag(asn1, len, &inner_tag, &asn1, &len, &rem, &rlen);
1204+
ret = get_tag(asn1, len, &inner_tag, &asn1, &len, &rem, &rlen, 0);
12031205
if (ret)
12041206
return ret;
12051207
/* Note: we don't check rlen (it should be 0). */
@@ -1420,7 +1422,7 @@ decode_sequence(const uint8_t *asn1, size_t len, const struct seq_info *seq,
14201422
for (i = 0; i < seq->n_fields; i++) {
14211423
if (len == 0)
14221424
break;
1423-
ret = get_tag(asn1, len, &t, &contents, &clen, &asn1, &len);
1425+
ret = get_tag(asn1, len, &t, &contents, &clen, &asn1, &len, 0);
14241426
if (ret)
14251427
goto error;
14261428
/*
@@ -1478,7 +1480,7 @@ decode_sequence_of(const uint8_t *asn1, size_t len,
14781480
*seq_out = NULL;
14791481
*count_out = 0;
14801482
while (len > 0) {
1481-
ret = get_tag(asn1, len, &t, &contents, &clen, &asn1, &len);
1483+
ret = get_tag(asn1, len, &t, &contents, &clen, &asn1, &len, 0);
14821484
if (ret)
14831485
goto error;
14841486
if (!check_atype_tag(elemtype, &t)) {
@@ -1584,7 +1586,7 @@ k5_asn1_full_decode(const krb5_data *code, const struct atype_info *a,
15841586

15851587
*retrep = NULL;
15861588
ret = get_tag((uint8_t *)code->data, code->length, &t, &contents,
1587-
&clen, &remainder, &rlen);
1589+
&clen, &remainder, &rlen, 0);
15881590
if (ret)
15891591
return ret;
15901592
/* rlen should be 0, but we don't check it (and due to padding in

0 commit comments

Comments
 (0)