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,