ASN.1: Reject invalid extended tags in DER encoding

The extended tag case is allowed only for tag values that are 31 or
larger (i.e., the ones that would not fit in the single octet identifier
case with five bits). Extended tag format was previously accepted even
for the values 0..31 and this would enable multiple different encodings
for the same tag value. That is not allowed for DER.

Perform more strict checks to reject invalid extended tag values. This
is needed for a compliant implementation and this is especially
important for the case of verifying DER encoded signatures to prevent
potential forging attacks.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2021-03-13 16:49:07 +02:00
parent d6831a0e93
commit 3af75f23b0

View file

@ -186,18 +186,35 @@ int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
hdr->constructed = !!(hdr->identifier & (1 << 5)); hdr->constructed = !!(hdr->identifier & (1 << 5));
if ((hdr->identifier & 0x1f) == 0x1f) { if ((hdr->identifier & 0x1f) == 0x1f) {
size_t ext_len = 0;
hdr->tag = 0; hdr->tag = 0;
if (pos == end || (*pos & 0x7f) == 0) {
wpa_printf(MSG_DEBUG,
"ASN.1: Invalid extended tag (first octet has to be included with at least one nonzero bit for the tag value)");
return -1;
}
do { do {
if (pos >= end) { if (pos >= end) {
wpa_printf(MSG_DEBUG, "ASN.1: Identifier " wpa_printf(MSG_DEBUG, "ASN.1: Identifier "
"underflow"); "underflow");
return -1; return -1;
} }
ext_len++;
tmp = *pos++; tmp = *pos++;
wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: " wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: "
"0x%02x", tmp); "0x%02x", tmp);
hdr->tag = (hdr->tag << 7) | (tmp & 0x7f); hdr->tag = (hdr->tag << 7) | (tmp & 0x7f);
} while (tmp & 0x80); } while (tmp & 0x80);
wpa_printf(MSG_MSGDUMP, "ASN.1: Extended Tag: 0x%x (len=%zu)",
hdr->tag, ext_len);
if ((hdr->class != ASN1_CLASS_PRIVATE && hdr->tag < 31) ||
ext_len * 7 > sizeof(hdr->tag) * 8) {
wpa_printf(MSG_DEBUG,
"ASN.1: Invalid or unsupported (too large) extended Tag: 0x%x (len=%zu)",
hdr->tag, ext_len);
return -1;
}
} else } else
hdr->tag = hdr->identifier & 0x1f; hdr->tag = hdr->identifier & 0x1f;