[crypto] Reject indefinite and unrepresentable length encodings An indefinite length encoding will currently be parsed as having a length of zero, and an encoded length that exceeds the range of an unsigned int will be truncated. Tighten up the parsing of lengths to explicitly reject indefinite length encodings or unrepresentable lengths. Signed-off-by: Michael Brown <mcb30@ipxe.org>
diff --git a/src/crypto/asn1.c b/src/crypto/asn1.c index f193429..09ca355 100644 --- a/src/crypto/asn1.c +++ b/src/crypto/asn1.c
@@ -175,6 +175,7 @@ static int asn1_start ( struct asn1_cursor *cursor, unsigned int type ) { unsigned int len_len; unsigned int len; + uint8_t high_byte; /* Sanity check */ if ( cursor->len < 2 /* Tag byte and first length byte */ ) { @@ -202,22 +203,29 @@ } else { len_len = 1; } - if ( cursor->len < len_len ) { - DBGC ( cursor, "ASN1 %p bad length field length %d (max " - "%zd)\n", cursor, len_len, cursor->len ); + if ( ( len_len == 0 ) || ( cursor->len < len_len ) ) { + DBGC ( cursor, "ASN1 %p bad length field length %d (min 0, " + "max %zd)\n", cursor, len_len, cursor->len ); asn1_invalidate_cursor ( cursor ); return -EINVAL_ASN1_LEN_LEN; } /* Extract the length and sanity check */ for ( len = 0 ; len_len ; len_len-- ) { + high_byte = ( len >> ( 8 * ( sizeof ( len ) - 1 ) ) ); + if ( high_byte ) { + DBGC ( cursor, "ASN1 %p unrepresentable length\n", + cursor ); + asn1_invalidate_cursor ( cursor ); + return -EINVAL_ASN1_LEN; + } len <<= 8; len |= *( ( uint8_t * ) cursor->data ); cursor->data++; cursor->len--; } - if ( cursor->len < len ) { - DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n", + if ( ( cursor->len < len ) || ( ( ( int ) len ) < 0 ) ) { + DBGC ( cursor, "ASN1 %p bad length %d (min 0, max %zd)\n", cursor, len, cursor->len ); asn1_invalidate_cursor ( cursor ); return -EINVAL_ASN1_LEN;