_asn1_object_id_der: expanded to handle all OIDs that can be decoded
In addition to making a more precise OID encoding, we add
a unit test.
Signed-off-by: Nikos Mavrogiannopoulos <nmav@gnutls.org>
diff --git a/.gitignore b/.gitignore
index fc0f113..28ab335 100644
--- a/.gitignore
+++ b/.gitignore
@@ -202,3 +202,4 @@
tests/*.trs
windows/libtasn1-*-win??.zip
windows/tmp
+tests/object-id-encoding
diff --git a/lib/coding.c b/lib/coding.c
index 90d6203..08aca3d 100644
--- a/lib/coding.c
+++ b/lib/coding.c
@@ -33,6 +33,10 @@
#include "minmax.h"
#include <structure.h>
+/* for unit testing */
+extern ASN1_API int
+_asn1_object_id_der (const char *str, unsigned char *der, int *der_len);
+
#define MAX_TAG_LEN 16
/******************************************************/
@@ -320,8 +324,30 @@
}
*/
+static
+void encode_val(uint64_t val, unsigned char *der, int max_len, int *der_len)
+{
+ int first, k;
+ unsigned char bit7;
+
+ first = 0;
+ for (k = sizeof(val); k >= 0; k--)
+ {
+ bit7 = (val >> (k * 7)) & 0x7F;
+ if (bit7 || first || !k)
+ {
+ if (k)
+ bit7 |= 0x80;
+ if (max_len > (*der_len))
+ der[*der_len] = bit7;
+ (*der_len)++;
+ first = 1;
+ }
+ }
+}
+
/******************************************************/
-/* Function : _asn1_objectid_der */
+/* Function : _asn1_object_id_der */
/* Description: creates the DER coding for an */
/* OBJECT IDENTIFIER type (length included). */
/* Parameters: */
@@ -335,16 +361,16 @@
/* ASN1_SUCCESS if succesful */
/* or an error value. */
/******************************************************/
-static int
-_asn1_objectid_der (unsigned char *str, unsigned char *der, int *der_len)
+int
+_asn1_object_id_der (const char *str, unsigned char *der, int *der_len)
{
- int len_len, counter, k, first, max_len;
+ int len_len, counter, max_len;
char *temp, *n_end, *n_start;
- unsigned char bit7;
uint64_t val, val1 = 0;
int str_len = _asn1_strlen (str);
max_len = *der_len;
+ *der_len = 0;
if (der == NULL && max_len > 0)
return ASN1_VALUE_NOT_VALID;
@@ -366,30 +392,30 @@
counter++;
if (counter == 1)
- val1 = val;
+ {
+ val1 = val;
+ }
else if (counter == 2)
{
- if (max_len > 0)
- der[0] = 40 * val1 + val;
- *der_len = 1;
+ uint64_t val0;
+
+ if (val1 > 2)
+ {
+ free(temp);
+ return ASN1_VALUE_NOT_VALID;
+ }
+ else if ((val1 == 0 || val1 == 1) && val > 39)
+ {
+ free(temp);
+ return ASN1_VALUE_NOT_VALID;
+ }
+
+ val0 = 40 * val1 + val;
+ encode_val(val0, der, max_len, der_len);
}
else
{
- first = 0;
- for (k = sizeof(val); k >= 0; k--)
- {
- bit7 = (val >> (k * 7)) & 0x7F;
- if (bit7 || first || !k)
- {
- if (k)
- bit7 |= 0x80;
- if (max_len > (*der_len))
- der[*der_len] = bit7;
- (*der_len)++;
- first = 1;
- }
- }
-
+ encode_val(val, der, max_len, der_len);
}
n_start = n_end + 1;
}
@@ -1142,7 +1168,7 @@
goto error;
}
len2 = max_len;
- err = _asn1_objectid_der (p->value, der + counter, &len2);
+ err = _asn1_object_id_der ((char*)p->value, der + counter, &len2);
if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
goto error;
diff --git a/lib/libtasn1.map b/lib/libtasn1.map
index 007925c..3ce75d6 100644
--- a/lib/libtasn1.map
+++ b/lib/libtasn1.map
@@ -61,3 +61,8 @@
local:
*;
};
+
+LIBTASN1_4_15_1 {
+ global:
+ _asn1_object_id_der;
+} LIBTASN1_0_3;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index c73a442..f850df7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -61,7 +61,7 @@
Test_errors Test_simple Test_overflow Test_strings Test_choice \
Test_encdec copynode coding-decoding2 strict-der Test_choice_ocsp \
ocsp-basic-response octet-string coding-long-oid object-id-decoding \
- spc_pe_image_data setof CVE-2018-1000654 reproducers
+ spc_pe_image_data setof CVE-2018-1000654 reproducers object-id-encoding
TESTS = Test_parser Test_tree Test_encoding Test_indefinite \
Test_errors Test_simple Test_overflow crlf threadsafety \
@@ -69,7 +69,7 @@
strict-der Test_choice_ocsp decoding decoding-invalid-x509 \
ocsp-basic-response octet-string coding-long-oid object-id-decoding \
spc_pe_image_data decoding-invalid-pkcs7 coding setof \
- CVE-2018-1000654 parser.sh reproducers
+ CVE-2018-1000654 parser.sh reproducers object-id-encoding
CVE-2018-1000654-1_asn1_tab.h: $(srcdir)/CVE-2018-1000654-1.asn
$(top_builddir)/src/asn1Parser$(EXEEXT) $^ -o $@
diff --git a/tests/object-id-decoding.c b/tests/object-id-decoding.c
index 4c50e9c..7052b4f 100644
--- a/tests/object-id-decoding.c
+++ b/tests/object-id-decoding.c
@@ -27,36 +27,44 @@
struct tv
{
int der_len;
- const unsigned char *der_str;
+ const unsigned char *der;
const char *oid;
int expected_error;
};
static const struct tv tv[] = {
{.der_len = 5,
- .der_str = (void *) "\x06\x03\x80\x37\x03",
+ .der = (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",
+ .der = (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 = 6,
+ .der = (void *) "\x06\x04\x01\x02\x03\x04",
+ .oid = "0.1.2.3.4",
+ .expected_error = ASN1_SUCCESS},
{.der_len = 5,
- .der_str = (void *) "\x06\x03\x88\x37\x03",
+ .der = (void *) "\x06\x03\x51\x02\x03",
+ .oid = "2.1.2.3",
+ .expected_error = ASN1_SUCCESS},
+ {.der_len = 5,
+ .der = (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",
+ .der = (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",
+ .der = (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 =
+ .der =
(void *)
"\x06\x11\x2b\x06\x01\x04\x01\x92\x08\x09\x02\xaa\xda\xbe\xbe\xfa\x72\x01\x07",
.oid = "1.3.6.1.4.1.2312.9.2.1467399257458.1.7",
@@ -74,7 +82,7 @@
{
/* decode */
ret =
- asn1_get_object_id_der (tv[i].der_str+1,
+ asn1_get_object_id_der (tv[i].der+1,
tv[i].der_len-1, &ret_len, str,
sizeof (str));
if (ret != tv[i].expected_error)
diff --git a/tests/object-id-encoding.c b/tests/object-id-encoding.c
new file mode 100644
index 0000000..7c39448
--- /dev/null
+++ b/tests/object-id-encoding.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2019 Nikos Mavrogiannopoulos
+ *
+ * This file is part of LIBTASN1.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "libtasn1.h"
+
+extern ASN1_API int
+_asn1_object_id_der (const char *str, unsigned char *der, int *der_len);
+
+
+struct tv
+{
+ int der_len;
+ const unsigned char *der;
+ const char *oid;
+ int expected_error;
+};
+
+static const struct tv tv[] = {
+ {.der_len = 0,
+ .der = (void *) "",
+ .oid = "5.999.3",
+ .expected_error = ASN1_VALUE_NOT_VALID /* cannot start with 5 */
+ },
+ {.der_len = 0,
+ .der = (void *) "",
+ .oid = "0.48.9",
+ .expected_error = ASN1_VALUE_NOT_VALID /* second field cannot be 48 */
+ },
+ {.der_len = 0,
+ .der = (void *) "",
+ .oid = "1.40.9",
+ .expected_error = ASN1_VALUE_NOT_VALID /* second field cannot be 40 */
+ },
+ {.der_len = 4,
+ .der = (void *) "\x06\x02\x4f\x63",
+ .oid = "1.39.99",
+ .expected_error = ASN1_SUCCESS,
+ },
+ {.der_len = 6,
+ .der = (void *) "\x06\x04\x01\x02\x03\x04",
+ .oid = "0.1.2.3.4",
+ .expected_error = ASN1_SUCCESS},
+ {.der_len = 5,
+ .der = (void *) "\x06\x03\x51\x02\x03",
+ .oid = "2.1.2.3",
+ .expected_error = ASN1_SUCCESS},
+ {.der_len = 5,
+ .der = (void *) "\x06\x03\x88\x37\x03",
+ .oid = "2.999.3",
+ .expected_error = ASN1_SUCCESS},
+ {.der_len = 12,
+ .der = (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 = (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 =
+ (void *)
+ "\x06\x11\x2b\x06\x01\x04\x01\x92\x08\x09\x02\xaa\xda\xbe\xbe\xfa\x72\x01\x07",
+ .oid = "1.3.6.1.4.1.2312.9.2.1467399257458.1.7",
+ .expected_error = ASN1_SUCCESS},
+};
+
+int
+main (int argc, char *argv[])
+{
+ unsigned char der[128];
+ int ret, der_len, i, j, exp_der_len;
+ const unsigned char *exp_der;
+
+ for (i = 0; i < (int)(sizeof (tv) / sizeof (tv[0])); i++)
+ {
+ der_len = sizeof(der);
+ ret = _asn1_object_id_der(tv[i].oid, der, &der_len);
+ if (ret != ASN1_SUCCESS)
+ {
+ if (ret == tv[i].expected_error)
+ continue;
+ fprintf (stderr,
+ "%d: iter %lu, encoding of OID failed: %s\n",
+ __LINE__, (unsigned long) i, asn1_strerror(ret));
+ return 1;
+ }
+ else if (ret != tv[i].expected_error)
+ {
+ fprintf (stderr,
+ "%d: iter %lu, encoding of OID %s succeeded when expecting failure\n",
+ __LINE__, (unsigned long) i, tv[i].oid);
+ return 1;
+ }
+
+ /* the internal function does not insert the tag */
+ exp_der = tv[i].der + 1;
+ exp_der_len = tv[i].der_len - 1;
+ if (der_len != exp_der_len || memcmp(der, exp_der, der_len-1) != 0)
+ {
+ fprintf (stderr,
+ "%d: iter %lu, re-encoding of OID %s resulted to different string (%d vs %d bytes)\n",
+ __LINE__, (unsigned long) i, tv[i].oid, der_len, exp_der_len);
+ fprintf(stderr, "\nGot:\t\t");
+ for (j=0;j<der_len;j++)
+ fprintf(stderr, "%.2x", der[j]);
+
+ fprintf(stderr, "\nExpected:\t");
+ for (j=0;j<exp_der_len;j++)
+ fprintf(stderr, "%.2x", exp_der[j]);
+ fprintf(stderr, "\n");
+
+ return 1;
+ }
+ }
+
+ return 0;
+}