asn1_get_object_id_der: enhance the range of decoded OIDs

The function would only successfully decode OIDs that started
with a single octet. This fixes that limitation.

Resolves: #25

Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
diff --git a/NEWS b/NEWS
index 103efbc..934f655 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,7 @@
 - asn1_decode_simple_ber: added support for constructed definite
   octet strings. This allows this function decode the whole set of
   BER encodings for OCTET STRINGs.
+- asn1_get_object_id_der: enhance the range of decoded OIDs (#25).
 
 
 * Noteworthy changes in release 4.15.0 (released 2019-11-21) [stable]
diff --git a/lib/decoding.c b/lib/decoding.c
index 5e809ff..ff04eb7 100644
--- a/lib/decoding.c
+++ b/lib/decoding.c
@@ -410,9 +410,9 @@
 			char *str, int str_size)
 {
   int len_len, len, k;
-  int leading;
+  int leading, parsed;
   char temp[LTOSTR_MAX_SIZE];
-  uint64_t val, val1;
+  uint64_t val, val1, val0;
 
   *ret_len = 0;
   if (str && str_size > 0)
@@ -426,16 +426,48 @@
   if (len <= 0 || len + len_len > der_len)
     return ASN1_DER_ERROR;
 
-  val1 = der[len_len] / 40;
-  val = der[len_len] - val1 * 40;
+  /* leading octet can never be 0x80 */
+  if (der[len_len] == 0x80)
+    return ASN1_DER_ERROR;
 
-  _asn1_str_cpy (str, str_size, _asn1_ltostr (val1, temp));
+  val0 = 0;
+
+  for (k = 0; k < len; k++)
+    {
+      if (INT_LEFT_SHIFT_OVERFLOW (val0, 7))
+	return ASN1_DER_ERROR;
+
+      val0 <<= 7;
+      val0 |= der[len_len + k] & 0x7F;
+      if (!(der[len_len + k] & 0x80))
+	break;
+    }
+  parsed = ++k;
+
+  /* val0 = (X*40) + Y, X={0,1,2}, Y<=39 when X={0,1} */
+  /* X = val, Y = val1 */
+
+  /* check if X == 0  */
+  val = 0;
+  val1 = val0;
+  if (val1 > 39)
+    {
+      val = 1;
+      val1 = val0 - 40;
+      if (val1  > 39)
+        {
+          val = 2;
+          val1 = val0 - 80;
+        }
+    }
+
+  _asn1_str_cpy (str, str_size, _asn1_ltostr (val, temp));
   _asn1_str_cat (str, str_size, ".");
-  _asn1_str_cat (str, str_size, _asn1_ltostr (val, temp));
+  _asn1_str_cat (str, str_size, _asn1_ltostr (val1, temp));
 
   val = 0;
   leading = 1;
-  for (k = 1; k < len; k++)
+  for (k = parsed; k < len; k++)
     {
       /* X.690 mandates that the leading byte must never be 0x80
        */
diff --git a/tests/object-id-decoding.c b/tests/object-id-decoding.c
index e3e9669..4c50e9c 100644
--- a/tests/object-id-decoding.c
+++ b/tests/object-id-decoding.c
@@ -33,11 +33,29 @@
 };
 
 static const struct tv tv[] = {
+  {.der_len = 5,
+   .der_str = (void *) "\x06\x03\x80\x37\x03",
+   .oid = "2.999.3",
+   .expected_error = ASN1_DER_ERROR /* leading 0x80 */
+  },
+  {.der_len = 12,
+   .der_str = (void *) "\x06\x0a\x2b\x06\x01\x80\x01\x92\x08\x09\x05\x01",
+   .oid = "1.3.6.1.4.1.2312.9.5.1",
+   .expected_error = ASN1_DER_ERROR /* leading 0x80 */
+  },
+  {.der_len = 5,
+   .der_str = (void *) "\x06\x03\x88\x37\x03",
+   .oid = "2.999.3",
+   .expected_error = ASN1_SUCCESS},
   {.der_len = 12,
    .der_str = (void *) "\x06\x0a\x2b\x06\x01\x04\x01\x92\x08\x09\x05\x01",
    .oid = "1.3.6.1.4.1.2312.9.5.1",
    .expected_error = ASN1_SUCCESS},
   {.der_len = 19,
+   .der_str = (void *) "\x06\x11\xfa\x80\x00\x00\x00\x0e\x01\x0e\xfa\x80\x00\x00\x00\x0e\x63\x6f\x6d",
+   .oid = "2.1998768.0.0.14.1.14.1998848.0.0.14.99.111.109",
+   .expected_error = ASN1_SUCCESS},
+  {.der_len = 19,
    .der_str =
    (void *)
    "\x06\x11\x2b\x06\x01\x04\x01\x92\x08\x09\x02\xaa\xda\xbe\xbe\xfa\x72\x01\x07",
@@ -62,11 +80,14 @@
       if (ret != tv[i].expected_error)
 	{
 	  fprintf (stderr,
-		   "%d: asn1_get_object_id_der iter %lu: got %d expected %d\n",
-		   __LINE__, (unsigned long) i, ret, tv[i].expected_error);
+		   "%d: asn1_get_object_id_der iter %lu: got '%s' expected %d\n",
+		   __LINE__, (unsigned long) i, asn1_strerror(ret), tv[i].expected_error);
 	  return 1;
 	}
 
+      if (tv[i].expected_error != ASN1_SUCCESS)
+        continue;
+
       if (ret_len != tv[i].der_len-1)
 	{
 	  fprintf (stderr,