Potential Buffer Overrun in _asn1_tag_der()

Description of problem:

When merging libtasn1 into grub2, a potential buffer overrun issue was spotted by coverity:

*** CID 435762:  Memory - corruptions  (OVERRUN)
________________________________________________________________________________________________________
/grub-core/lib/libtasn1/lib/coding.c: 152 in _asn1_tag_der()
146     	  if (k > ASN1_MAX_TAG_SIZE - 1)
147     	    break;		/* will not encode larger tags */
148     	}
149           *ans_len = k + 1;
150           while (k--)
151     	ans[*ans_len - 1 - k] = temp[k] + 128;
>>>     CID 435762:  Memory - corruptions  (OVERRUN)
>>>     Overrunning array of 4 bytes at byte offset 4 by dereferencing pointer "ans + (*ans_len - 1)".
152           ans[*ans_len - 1] -= 128;
153         }
154     }
155     
156     /**
157      * asn1_octet_der:

Here is the code snippet:

      k = 0;
      while (tag_value != 0)
        {
          temp[k++] = tag_value & 0x7F;
          tag_value >>= 7;

          if (k > ASN1_MAX_TAG_SIZE - 1)
            break;              /* will not encode larger tags */
        }
      *ans_len = k + 1;
      while (k--)
        ans[*ans_len - 1 - k] = temp[k] + 128;

In the first while loop, k may become ASN1_MAX_TAG_SIZE, i.e.4, and trigger break. Then, in the second while loop, the iteration will be like this:

*ans_len - 1 - k: 1, k: 3
*ans_len - 1 - k: 2, k: 2
*ans_len - 1 - k: 3, k: 1
*ans_len - 1 - k: 4, k: 0

The code may access ans[4] which excesses the boundary of the array. Maybe the if statement should be k >= ASN1_MAX_TAG_SIZE - 1 to cap k below ASN1_MAX_TAG_SIZE.

The full report is available in grub-devel mailing list:

https://lists.gnu.org/archive/html/grub-devel/2024-02/txtKIuUb5lf3O.txt

Version of libtasn1 used:

4.19

Distributor of libtasn1 (e.g., Ubuntu, Fedora, RHEL)

Upstream official tarball

How reproducible:

Steps to Reproduce:

  • one
  • two
  • three

Actual results:

Expected results: