diff --git a/lib/vtls/x509asn1.c b/lib/vtls/x509asn1.c
index fe4a38b8f7..0bc0a75a4b 100644
--- a/lib/vtls/x509asn1.c
+++ b/lib/vtls/x509asn1.c
@@ -178,8 +178,11 @@ static const char *getASN1Element(struct Curl_asn1Element *elem,
const char *beg, const char *end)
WARN_UNUSED_RESULT;
-static const char *getASN1Element(struct Curl_asn1Element *elem,
- const char *beg, const char *end)
+#define CURL_ASN1_MAX_RECURSIONS 16
+
+static const char *getASN1Element_(struct Curl_asn1Element *elem,
+ const char *beg, const char *end,
+ size_t lvl)
{
unsigned char b;
size_t len;
@@ -190,7 +193,8 @@ static const char *getASN1Element(struct Curl_asn1Element *elem,
Returns a pointer in source string after the parsed element, or NULL
if an error occurs. */
if(!beg || !end || beg >= end || !*beg ||
- (size_t)(end - beg) > CURL_ASN1_MAX)
+ ((size_t)(end - beg) > CURL_ASN1_MAX) ||
+ lvl >= CURL_ASN1_MAX_RECURSIONS)
return NULL;
/* Process header byte. */
@@ -216,7 +220,7 @@ static const char *getASN1Element(struct Curl_asn1Element *elem,
return NULL;
elem->beg = beg;
while(beg < end && *beg) {
- beg = getASN1Element(&lelem, beg, end);
+ beg = getASN1Element_(&lelem, beg, end, lvl + 1);
if(!beg)
return NULL;
}
@@ -243,6 +247,12 @@ static const char *getASN1Element(struct Curl_asn1Element *elem,
return elem->end;
}
+static const char *getASN1Element(struct Curl_asn1Element *elem,
+ const char *beg, const char *end)
+{
+ return getASN1Element_(elem, beg, end, 0);
+}
+
#ifdef WANT_EXTRACT_CERTINFO
/*
@@ -259,6 +269,17 @@ static const struct Curl_OID *searchOID(const char *oid)
return NULL;
}
+#ifdef UNITTESTS
+/* used by unit1657.c */
+CURLcode Curl_x509_getASN1Element(struct Curl_asn1Element *elem,
+ const char *beg, const char *end)
+{
+ if(getASN1Element(elem, beg, end))
+ return CURLE_OK;
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+}
+#endif
+
/*
* Convert an ASN.1 Boolean value into its string representation.
*
diff --git a/lib/vtls/x509asn1.h b/lib/vtls/x509asn1.h
index 5b48596c75..5de8f18e9c 100644
--- a/lib/vtls/x509asn1.h
+++ b/lib/vtls/x509asn1.h
@@ -85,6 +85,9 @@ CURLcode Curl_verifyhost(struct Curl_cfilter *cf, struct Curl_easy *data,
/* used by unit1656.c */
CURLcode Curl_x509_GTime2str(struct dynbuf *store,
const char *beg, const char *end);
+/* used by unit1657.c */
+CURLcode Curl_x509_getASN1Element(struct Curl_asn1Element *elem,
+ const char *beg, const char *end);
#endif
#endif
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 76ba64e437..1fc6c66817 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -218,7 +218,7 @@ test1620 test1621 \
\
test1630 test1631 test1632 test1633 test1634 test1635 \
\
-test1650 test1651 test1652 test1653 test1654 test1655 test1656 \
+test1650 test1651 test1652 test1653 test1654 test1655 test1656 test1657 \
test1660 test1661 test1662 test1663 test1664 \
\
test1670 test1671 \
diff --git a/tests/data/test1657 b/tests/data/test1657
new file mode 100644
index 0000000000..8e2a9c5a75
--- /dev/null
+++ b/tests/data/test1657
@@ -0,0 +1,22 @@
+
+
+
+unittest
+Curl_x509_getASN1Element
+
+
+
+#
+# Client-side
+
+
+none
+
+
+unittest
+
+
+Curl_x509_getASN1Element unit tests
+
+
+
diff --git a/tests/unit/Makefile.inc b/tests/unit/Makefile.inc
index c523189233..4b34d4dd22 100644
--- a/tests/unit/Makefile.inc
+++ b/tests/unit/Makefile.inc
@@ -38,7 +38,7 @@ UNITPROGS = unit1300 unit1302 unit1303 unit1304 unit1305 unit1307 \
unit1600 unit1601 unit1602 unit1603 unit1604 unit1605 unit1606 unit1607 \
unit1608 unit1609 unit1610 unit1611 unit1612 unit1614 unit1615 unit1616 \
unit1620 unit1621 \
- unit1650 unit1651 unit1652 unit1653 unit1654 unit1655 unit1656 \
+ unit1650 unit1651 unit1652 unit1653 unit1654 unit1655 unit1656 unit1657 \
unit1660 unit1661 unit1663 unit1664 \
unit2600 unit2601 unit2602 unit2603 unit2604 \
unit3200 \
@@ -126,6 +126,8 @@ unit1655_SOURCES = unit1655.c $(UNITFILES)
unit1656_SOURCES = unit1656.c $(UNITFILES)
+unit1657_SOURCES = unit1657.c $(UNITFILES)
+
unit1660_SOURCES = unit1660.c $(UNITFILES)
unit1661_SOURCES = unit1661.c $(UNITFILES)
diff --git a/tests/unit/unit1657.c b/tests/unit/unit1657.c
new file mode 100644
index 0000000000..bd973fdbb4
--- /dev/null
+++ b/tests/unit/unit1657.c
@@ -0,0 +1,134 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, , et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curlcheck.h"
+
+#include "vtls/x509asn1.h"
+
+static CURLcode unit_setup(void)
+{
+ return CURLE_OK;
+}
+
+static void unit_stop(void)
+{
+
+}
+
+#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
+ defined(USE_MBEDTLS)
+
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#endif
+
+struct test1657_spec {
+ CURLcode (*setbuf)(struct test1657_spec *spec, struct dynbuf *buf);
+ size_t n;
+ CURLcode exp_result;
+};
+
+static CURLcode make1657_nested(struct test1657_spec *spec, struct dynbuf *buf)
+{
+ CURLcode r;
+ size_t i;
+ unsigned char open_undef[] = { 0x32, 0x80 };
+ unsigned char close_undef[] = { 0x00, 0x00 };
+
+ for(i = 0; i < spec->n; ++i) {
+ r = Curl_dyn_addn(buf, open_undef, sizeof(open_undef));
+ if(r)
+ return r;
+ }
+ for(i = 0; i < spec->n; ++i) {
+ r = Curl_dyn_addn(buf, close_undef, sizeof(close_undef));
+ if(r)
+ return r;
+ }
+ return CURLE_OK;
+}
+
+static struct test1657_spec test1657_specs[] = {
+ { make1657_nested, 3, CURLE_OK },
+ { make1657_nested, 16, CURLE_OK },
+ { make1657_nested, 17, CURLE_BAD_FUNCTION_ARGUMENT },
+ { make1657_nested, 1024, CURLE_BAD_FUNCTION_ARGUMENT },
+};
+
+static bool do_test1657(struct test1657_spec *spec, size_t i,
+ struct dynbuf *buf)
+{
+ CURLcode result;
+ struct Curl_asn1Element elem;
+ const char *in;
+
+ memset(&elem, 0, sizeof(elem));
+ Curl_dyn_reset(buf);
+ result = spec->setbuf(spec, buf);
+ if(result) {
+ fprintf(stderr, "test %zu: error setting buf %d\n", i, result);
+ return FALSE;
+ }
+ in = Curl_dyn_ptr(buf);
+ result = Curl_x509_getASN1Element(&elem, in, in + Curl_dyn_len(buf));
+ if(result != spec->exp_result) {
+ fprintf(stderr, "test %zu: expect result %d, got %d\n",
+ i, spec->exp_result, result);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+UNITTEST_START
+{
+ size_t i;
+ bool all_ok = TRUE;
+ struct dynbuf dbuf;
+
+ Curl_dyn_init(&dbuf, 32*1024);
+
+ if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
+ fprintf(stderr, "curl_global_init() failed\n");
+ return TEST_ERR_MAJOR_BAD;
+ }
+
+ for(i = 0; i < ARRAYSIZE(test1657_specs); ++i) {
+ if(!do_test1657(&test1657_specs[i], i, &dbuf))
+ all_ok = FALSE;
+ }
+ fail_unless(all_ok, "some tests of Curl_x509_getASN1Element() fails");
+
+ Curl_dyn_free(&dbuf);
+ curl_global_cleanup();
+}
+UNITTEST_STOP
+
+#else
+
+UNITTEST_START
+{
+ puts("not tested since Curl_x509_getASN1Element() is not built-in");
+}
+UNITTEST_STOP
+
+#endif