diff --git a/lib/vtls/x509asn1.c b/lib/vtls/x509asn1.c
index 57f5f09a91..b430c74704 100644
--- a/lib/vtls/x509asn1.c
+++ b/lib/vtls/x509asn1.c
@@ -51,41 +51,6 @@
#define CURL_ASN1_MAX ((size_t)0x40000) /* 256K */
#ifdef WANT_EXTRACT_CERTINFO
-/* ASN.1 classes. */
-/* #define CURL_ASN1_UNIVERSAL 0 */
-/* #define CURL_ASN1_APPLICATION 1 */
-/* #define CURL_ASN1_CONTEXT_SPECIFIC 2 */
-/* #define CURL_ASN1_PRIVATE 3 */
-
-/* ASN.1 types. */
-#define CURL_ASN1_BOOLEAN 1
-#define CURL_ASN1_INTEGER 2
-#define CURL_ASN1_BIT_STRING 3
-#define CURL_ASN1_OCTET_STRING 4
-#define CURL_ASN1_NULL 5
-#define CURL_ASN1_OBJECT_IDENTIFIER 6
-/* #define CURL_ASN1_OBJECT_DESCRIPTOR 7 */
-/* #define CURL_ASN1_INSTANCE_OF 8 */
-/* #define CURL_ASN1_REAL 9 */
-#define CURL_ASN1_ENUMERATED 10
-/* #define CURL_ASN1_EMBEDDED 11 */
-#define CURL_ASN1_UTF8_STRING 12
-/* #define CURL_ASN1_RELATIVE_OID 13 */
-/* #define CURL_ASN1_SEQUENCE 16 */
-/* #define CURL_ASN1_SET 17 */
-#define CURL_ASN1_NUMERIC_STRING 18
-#define CURL_ASN1_PRINTABLE_STRING 19
-#define CURL_ASN1_TELETEX_STRING 20
-/* #define CURL_ASN1_VIDEOTEX_STRING 21 */
-#define CURL_ASN1_IA5_STRING 22
-#define CURL_ASN1_UTC_TIME 23
-#define CURL_ASN1_GENERALIZED_TIME 24
-/* #define CURL_ASN1_GRAPHIC_STRING 25 */
-#define CURL_ASN1_VISIBLE_STRING 26
-/* #define CURL_ASN1_GENERAL_STRING 27 */
-#define CURL_ASN1_UNIVERSAL_STRING 28
-/* #define CURL_ASN1_CHARACTER_STRING 29 */
-#define CURL_ASN1_BMP_STRING 30
/* ASN.1 OID table entry. */
struct Curl_OID {
@@ -265,9 +230,13 @@ static const struct Curl_OID *searchOID(const char *oid)
static CURLcode bool2str(struct dynbuf *store,
const char *beg, const char *end)
{
+ uint8_t val;
if(end - beg != 1)
return CURLE_BAD_FUNCTION_ARGUMENT;
- return curlx_dyn_add(store, *beg ? "TRUE" : "FALSE");
+ val = (uint8_t)*beg;
+ if((val != 0xff) && (val != 0x00))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ return curlx_dyn_add(store, val ? "TRUE" : "FALSE");
}
/*
@@ -290,7 +259,12 @@ static CURLcode bit2str(struct dynbuf *store, const char *beg, const char *end)
{
/* Convert an ASN.1 bit string to a printable string. */
- if(++beg > end)
+ if(beg < end) {
+ uint8_t unused_bits = (uint8_t)*beg++;
+ if(unused_bits > 7)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+ else
return CURLE_BAD_FUNCTION_ARGUMENT;
return octet2str(store, beg, end);
}
@@ -302,8 +276,11 @@ static CURLcode bit2str(struct dynbuf *store, const char *beg, const char *end)
*/
static CURLcode int2str(struct dynbuf *store, const char *beg, const char *end)
{
- unsigned int val = 0;
+ uint32_t uval = 0;
+ int32_t sval = 0;
size_t n = end - beg;
+ size_t i;
+ const unsigned char *p = (const unsigned char *)beg;
if(!n)
return CURLE_BAD_FUNCTION_ARGUMENT;
@@ -311,14 +288,20 @@ static CURLcode int2str(struct dynbuf *store, const char *beg, const char *end)
if(n > 4)
return octet2str(store, beg, end);
- /* Represent integers <= 32-bit as a single value. */
- if(*beg & 0x80)
- val = ~val;
+ if(p[0] & 0x80)
+ uval = ~0U;
- do
- val = (val << 8) | *(const unsigned char *)beg++;
- while(beg < end);
- return curlx_dyn_addf(store, "%s%x", val >= 10 ? "0x" : "", val);
+ for(i = 0; i < n; i++)
+ uval = (uval << 8) | p[i];
+
+ sval = (int32_t)uval;
+
+ /* small values are easier to read as decimals */
+ if(sval > -10000 && sval < 10000)
+ return curlx_dyn_addf(store, "%d", sval);
+
+ /* represent larger values as hex */
+ return curlx_dyn_addf(store, "0x%x", uval);
}
/*
@@ -618,8 +601,6 @@ static CURLcode UTime2str(struct dynbuf *store,
tzp = "GMT";
end = tzp + 3;
}
- else
- tzp++;
tzl = end - tzp;
return curlx_dyn_addf(store, "%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s",
@@ -633,16 +614,16 @@ static CURLcode UTime2str(struct dynbuf *store,
*
* Return error
*/
-static CURLcode ASN1tostr(struct dynbuf *store,
- struct Curl_asn1Element *elem, int type)
+UNITTEST CURLcode ASN1tostr(struct dynbuf *store,
+ struct Curl_asn1Element *elem);
+UNITTEST CURLcode ASN1tostr(struct dynbuf *store,
+ struct Curl_asn1Element *elem)
{
CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
+ int type = elem->tag;
if(elem->constructed)
return result; /* No conversion of structured elements. */
- if(!type)
- type = elem->tag; /* Type not forced: use element tag as type. */
-
switch(type) {
case CURL_ASN1_BOOLEAN:
result = bool2str(store, elem->beg, elem->end);
@@ -726,7 +707,7 @@ static CURLcode encodeDN(struct dynbuf *store, struct Curl_asn1Element *dn)
goto error;
}
curlx_dyn_reset(&temp);
- result = ASN1tostr(&temp, &oid, 0);
+ result = ASN1tostr(&temp, &oid);
if(result)
goto error;
@@ -761,7 +742,7 @@ static CURLcode encodeDN(struct dynbuf *store, struct Curl_asn1Element *dn)
goto error;
/* Generate value. */
- result = ASN1tostr(store, &value, 0);
+ result = ASN1tostr(store, &value);
if(result)
goto error;
curlx_dyn_reset(&temp);
@@ -970,7 +951,7 @@ static CURLcode do_pubkey_field(struct Curl_easy *data, int certnum,
/* Generate a certificate information record for the public key. */
- result = ASN1tostr(&out, elem, 0);
+ result = ASN1tostr(&out, elem);
if(!result) {
if(data->set.ssl.certinfo)
result = ssl_push_certinfo_dyn(data, certnum, label, &out);
@@ -1158,7 +1139,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
}
/* Serial number. */
- result = ASN1tostr(&out, &cert.serialNumber, 0);
+ result = ASN1tostr(&out, &cert.serialNumber);
if(result)
goto done;
if(data->set.ssl.certinfo) {
@@ -1181,7 +1162,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
curlx_dyn_reset(&out);
/* Start Date. */
- result = ASN1tostr(&out, &cert.notBefore, 0);
+ result = ASN1tostr(&out, &cert.notBefore);
if(result)
goto done;
if(data->set.ssl.certinfo) {
@@ -1192,7 +1173,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
curlx_dyn_reset(&out);
/* Expire Date. */
- result = ASN1tostr(&out, &cert.notAfter, 0);
+ result = ASN1tostr(&out, &cert.notAfter);
if(result)
goto done;
if(data->set.ssl.certinfo) {
@@ -1223,7 +1204,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
curlx_dyn_reset(&out);
/* Signature. */
- result = ASN1tostr(&out, &cert.signature, 0);
+ result = ASN1tostr(&out, &cert.signature);
if(result)
goto done;
if(data->set.ssl.certinfo) {
diff --git a/lib/vtls/x509asn1.h b/lib/vtls/x509asn1.h
index 61ea452bcd..dda55ac77f 100644
--- a/lib/vtls/x509asn1.h
+++ b/lib/vtls/x509asn1.h
@@ -26,6 +26,7 @@
***************************************************************************/
#include "curl_setup.h"
+/* forward-declare to make it visible in all builds */
struct Curl_asn1Element;
#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || \
@@ -34,6 +35,42 @@ struct Curl_asn1Element;
#include "cfilters.h"
#include "urldata.h"
+/* ASN.1 classes. */
+/* #define CURL_ASN1_UNIVERSAL 0 */
+/* #define CURL_ASN1_APPLICATION 1 */
+/* #define CURL_ASN1_CONTEXT_SPECIFIC 2 */
+/* #define CURL_ASN1_PRIVATE 3 */
+
+/* ASN.1 types. */
+#define CURL_ASN1_BOOLEAN 1
+#define CURL_ASN1_INTEGER 2
+#define CURL_ASN1_BIT_STRING 3
+#define CURL_ASN1_OCTET_STRING 4
+#define CURL_ASN1_NULL 5
+#define CURL_ASN1_OBJECT_IDENTIFIER 6
+/* #define CURL_ASN1_OBJECT_DESCRIPTOR 7 */
+/* #define CURL_ASN1_INSTANCE_OF 8 */
+/* #define CURL_ASN1_REAL 9 */
+#define CURL_ASN1_ENUMERATED 10
+/* #define CURL_ASN1_EMBEDDED 11 */
+#define CURL_ASN1_UTF8_STRING 12
+/* #define CURL_ASN1_RELATIVE_OID 13 */
+/* #define CURL_ASN1_SEQUENCE 16 */
+/* #define CURL_ASN1_SET 17 */
+#define CURL_ASN1_NUMERIC_STRING 18
+#define CURL_ASN1_PRINTABLE_STRING 19
+#define CURL_ASN1_TELETEX_STRING 20
+/* #define CURL_ASN1_VIDEOTEX_STRING 21 */
+#define CURL_ASN1_IA5_STRING 22
+#define CURL_ASN1_UTC_TIME 23
+#define CURL_ASN1_GENERALIZED_TIME 24
+/* #define CURL_ASN1_GRAPHIC_STRING 25 */
+#define CURL_ASN1_VISIBLE_STRING 26
+/* #define CURL_ASN1_GENERAL_STRING 27 */
+#define CURL_ASN1_UNIVERSAL_STRING 28
+/* #define CURL_ASN1_CHARACTER_STRING 29 */
+#define CURL_ASN1_BMP_STRING 30
+
/*
* Types.
*/
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index ffb1d38250..d54f108631 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -222,7 +222,7 @@ test1640 test1641 test1642 test1643 \
\
test1650 test1651 test1652 test1653 test1654 test1655 test1656 test1657 \
test1658 test1659 test1660 test1661 test1662 test1663 test1664 test1665 \
-test1666 \
+test1666 test1667 \
\
test1670 test1671 \
\
diff --git a/tests/data/test1667 b/tests/data/test1667
new file mode 100644
index 0000000000..76a1daa5a9
--- /dev/null
+++ b/tests/data/test1667
@@ -0,0 +1,20 @@
+
+
+
+
+unittest
+ASN1tostr
+x509asn1
+
+
+
+# Client-side
+
+
+unittest
+
+
+ASN1tostr unit tests
+
+
+
diff --git a/tests/unit/Makefile.inc b/tests/unit/Makefile.inc
index c03658261c..91b380a037 100644
--- a/tests/unit/Makefile.inc
+++ b/tests/unit/Makefile.inc
@@ -41,7 +41,7 @@ TESTS_C = \
unit1636.c \
unit1650.c unit1651.c unit1652.c unit1653.c unit1654.c unit1655.c unit1656.c \
unit1657.c unit1658.c unit1660.c unit1661.c unit1663.c unit1664.c \
- unit1666.c \
+ unit1666.c unit1667.c \
unit1979.c unit1980.c \
unit2600.c unit2601.c unit2602.c unit2603.c unit2604.c unit2605.c \
unit3200.c unit3205.c \
diff --git a/tests/unit/unit1667.c b/tests/unit/unit1667.c
new file mode 100644
index 0000000000..070b5f75de
--- /dev/null
+++ b/tests/unit/unit1667.c
@@ -0,0 +1,339 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 "unitcheck.h"
+
+#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_MBEDTLS) || \
+ defined(USE_RUSTLS)
+
+#include "vtls/x509asn1.h"
+#include "vtls/vtls.h"
+
+struct test_1667 {
+ unsigned char tag;
+ const char *asn1;
+ const size_t size;
+ const char *out;
+ CURLcode result_exp;
+};
+
+/* the size of the object needs to deduct the null terminator */
+#define OID(x) x, sizeof(x) - 1
+
+static bool test1667(const struct test_1667 *spec, size_t i,
+ struct dynbuf *dbuf)
+{
+ CURLcode result;
+ bool ok = TRUE;
+ struct Curl_asn1Element elem;
+
+ curlx_dyn_reset(dbuf);
+
+ /* setup private struct for this invoke */
+ elem.tag = spec->tag;
+ elem.header = NULL;
+ elem.beg = spec->asn1;
+ elem.end = elem.beg + spec->size;
+ elem.eclass = 0;
+ elem.constructed = 0;
+
+ result = ASN1tostr(dbuf, &elem);
+ if(result != spec->result_exp) {
+ curl_mfprintf(stderr, "test %zu (type %u): expect result %d, got %d\n",
+ i, spec->tag, spec->result_exp, result);
+ if(!spec->result_exp) {
+ curl_mfprintf(stderr, "test %zu: expected output '%s'\n",
+ i, spec->out);
+ }
+ ok = FALSE;
+ }
+ else if(!result) {
+ /* use strlen on the pointer instead of curlx_dyn_len() because for some
+ of these type, the code explicitly adds a null terminator which is then
+ counted as buffer size. */
+ size_t actual_len = strlen(curlx_dyn_ptr(dbuf));
+ if(strlen(spec->out) != actual_len) {
+ curl_mfprintf(stderr,
+ "test %zu (type %u): "
+ "unexpected length. Got %zu, expected %zu)\n",
+ i, spec->tag, actual_len, strlen(spec->out));
+ ok = FALSE;
+ }
+ if(strcmp(spec->out, curlx_dyn_ptr(dbuf))) {
+ size_t loop;
+ const uint8_t *data = curlx_dyn_uptr(dbuf);
+ const size_t len = curlx_dyn_len(dbuf);
+ curl_mfprintf(stderr,
+ "test %zu (type %u): "
+ "expected output '%s', got '%s' (length %zu)\n",
+ i, spec->tag, spec->out, data, len);
+ for(loop = 0; loop < len; loop++)
+ curl_mfprintf(stderr, "test %zu: index %zu byte %02x\n",
+ i, loop, data[loop]);
+ ok = FALSE;
+ }
+ }
+
+ return ok;
+}
+
+static CURLcode test_unit1667(const char *arg)
+{
+ UNITTEST_BEGIN_SIMPLE
+
+ static const struct test_1667 test_specs[] = {
+ /* unsupported type > CURL_ASN1_BMP_STRING (30) */
+ { 31, "abcde", 5, "", CURLE_BAD_FUNCTION_ARGUMENT },
+ { 99, "abcde", 5, "", CURLE_BAD_FUNCTION_ARGUMENT },
+
+ /*
+ (many different) strings:
+
+ CURL_ASN1_UTF8_STRING
+ CURL_ASN1_NUMERIC_STRING
+ CURL_ASN1_PRINTABLE_STRING
+ CURL_ASN1_TELETEX_STRING
+ CURL_ASN1_IA5_STRING
+ CURL_ASN1_VISIBLE_STRING
+ CURL_ASN1_UNIVERSAL_STRING
+ CURL_ASN1_BMP_STRING
+ */
+ { CURL_ASN1_UTF8_STRING, "abcde", 5, "abcde", CURLE_OK },
+ /* a with ring, a with umlaut, o with umlaut in UTF-8 encoding */
+ { CURL_ASN1_UTF8_STRING, "\xc3\xa5\xc3\xa4\xc3\xb6", 6,
+ "\xc3\xa5\xc3\xa4\xc3\xb6", CURLE_OK },
+ { CURL_ASN1_NUMERIC_STRING, "abcde", 5, "abcde", CURLE_OK },
+ { CURL_ASN1_PRINTABLE_STRING, "abcde", 5, "abcde", CURLE_OK },
+ { CURL_ASN1_TELETEX_STRING, "abcde", 5, "abcde", CURLE_OK },
+ { CURL_ASN1_IA5_STRING, "abcde", 5, "abcde", CURLE_OK },
+ { CURL_ASN1_VISIBLE_STRING, "abcde", 5, "abcde", CURLE_OK },
+ { CURL_ASN1_UNIVERSAL_STRING, "abcde", 5, "abcde",
+ CURLE_BAD_FUNCTION_ARGUMENT },
+ { CURL_ASN1_UNIVERSAL_STRING, "abcd", 4, "abcd",
+ CURLE_WEIRD_SERVER_REPLY },
+ { CURL_ASN1_UNIVERSAL_STRING, "\x00\x00\x12\x34", 4, "\xe1\x88\xb4",
+ CURLE_OK },
+ { CURL_ASN1_BMP_STRING, "abcde", 5, "abcde", CURLE_BAD_FUNCTION_ARGUMENT },
+
+ /* Generalized Time */
+ /* GTime2str() is tested separately in unit test 1656 */
+ { CURL_ASN1_GENERALIZED_TIME, "19851106210627.3", 16,
+ "1985-11-06 21:06:27.3", CURLE_OK },
+ { CURL_ASN1_GENERALIZED_TIME, "19851106210627.3Z", 17,
+ "1985-11-06 21:06:27.3 GMT", CURLE_OK },
+ { CURL_ASN1_GENERALIZED_TIME, "19851106210627.3-0500", 21,
+ "1985-11-06 21:06:27.3 UTC-0500", CURLE_OK },
+ /* Generalized Time: Invalid month (13). Still fine! */
+ { CURL_ASN1_GENERALIZED_TIME, "20231301000000Z", 15,
+ "2023-13-01 00:00:00 GMT", CURLE_OK },
+ /* Generalized Time: Valid millisecond precision */
+ { CURL_ASN1_GENERALIZED_TIME, "20230101000000.123Z", 19,
+ "2023-01-01 00:00:00.123 GMT", CURLE_OK },
+
+ /* UTC Time */
+ { CURL_ASN1_UTC_TIME, "991231235959Z", 13, "1999-12-31 23:59:59 GMT",
+ CURLE_OK },
+ { CURL_ASN1_UTC_TIME, "991231235959+0200", 17, "1999-12-31 23:59:59 +0200",
+ CURLE_OK },
+ { CURL_ASN1_UTC_TIME, "991231235959-0200", 17, "1999-12-31 23:59:59 -0200",
+ CURLE_OK },
+ { CURL_ASN1_UTC_TIME, "991231235959+999", 16, "1999-12-31 23:59:59 +999",
+ CURLE_OK },
+ /* Leap year check (Feb 29, 2024) */
+ { CURL_ASN1_UTC_TIME, "240229120000Z", 13, "2024-02-29 12:00:00 GMT",
+ CURLE_OK },
+ /* Century roll-over (00-49 is 20xx, 50-99 is 19xx) */
+ { CURL_ASN1_UTC_TIME, "491231235959Z", 13, "2049-12-31 23:59:59 GMT",
+ CURLE_OK },
+ { CURL_ASN1_UTC_TIME, "500101000000Z", 13, "1950-01-01 00:00:00 GMT",
+ CURLE_OK },
+
+ /* Object Identifier (encodeOID() is tested in unit test 1666) */
+
+ /* 1.2.840.10040.4.1 */
+ { CURL_ASN1_OBJECT_IDENTIFIER, "\x2A\x86\x48\xCE\x38\x04\x01", 7,
+ "dsa", CURLE_OK },
+ /* 1.2.840.113549.1.1.13 */
+ { CURL_ASN1_OBJECT_IDENTIFIER, "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0D", 9,
+ "sha512WithRSAEncryption", CURLE_OK },
+ /* 1.2.840.10040.4.2 */
+ { CURL_ASN1_OBJECT_IDENTIFIER, "\x2A\x86\x48\xCE\x38\x04\x02", 7,
+ "1.2.840.10040.4.2", CURLE_OK },
+ /* 2.16.840.1.101.3.4.2.3 */
+ { CURL_ASN1_OBJECT_IDENTIFIER, "\x60\x86\x48\x01\x65\x03\x04\x02\x03", 9,
+ "sha512", CURLE_OK },
+ /* 2.999 -> (2*40) + 999 = 1079. 1079 in VLQ is 0x88 0x37 */
+ { CURL_ASN1_OBJECT_IDENTIFIER, "\x88\x37\x03", 3, "2.999.3",
+ CURLE_OK },
+ /* 1.0 (Minimum possible OID length/value)
+ (1*40) + 0 = 40 (0x28) */
+ { CURL_ASN1_OBJECT_IDENTIFIER, "\x28", 1, "1.0", CURLE_OK },
+ /* Malformed (Incomplete multi-byte SID, MSB set but no following byte) */
+ { CURL_ASN1_OBJECT_IDENTIFIER, "\x88", 1, "",
+ CURLE_BAD_FUNCTION_ARGUMENT },
+
+ /* NULL */
+ { CURL_ASN1_NULL, "", 0, "", CURLE_OK },
+ { CURL_ASN1_NULL, "a", 1, "", CURLE_OK },
+ { CURL_ASN1_NULL, "aa", 2, "", CURLE_OK },
+
+ /* Octet string */
+ { CURL_ASN1_OCTET_STRING, "\x00\x00\x00\x04\x05", 5, "00:00:00:04:05:",
+ CURLE_OK },
+ { CURL_ASN1_OCTET_STRING, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff", 14, "", CURLE_TOO_LARGE},
+
+ /* Bit string. The first byte is number of unused bits. */
+ { CURL_ASN1_BIT_STRING, "\x00\x55", 2, "55:", CURLE_OK },
+ /* Invalid number of unused bits (> 7) */
+ { CURL_ASN1_BIT_STRING, "\x08\x55", 2, "", CURLE_BAD_FUNCTION_ARGUMENT },
+ { CURL_ASN1_BIT_STRING, "\x00\xaa\x55", 3, "aa:55:", CURLE_OK },
+ { CURL_ASN1_BIT_STRING, "\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff", 15, "", CURLE_TOO_LARGE},
+ /* 3 unused bits, data 0xF0 (11110000)
+ The '0' at the end of 11110... are the unused bits. */
+ { CURL_ASN1_BIT_STRING, "\x03\xf0", 2, "f0:", CURLE_OK },
+
+ /* Integer */
+ { CURL_ASN1_INTEGER, "\x00", 1, "0", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\x01", 1, "1", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\x09", 1, "9", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\x0a", 1, "10", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\xb", 1, "11", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\x11", 1, "17", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\x7f", 1, "127", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\x80", 1, "-128", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\x81", 1, "-127", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\x82", 1, "-126", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\xff", 1, "-1", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\x27\x0f", 2, "9999", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\x27\x10", 2, "0x2710", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\x7f\x81", 2, "0x7f81", CURLE_OK },
+
+ /* sign-extended, would be -32385 in decimal */
+ { CURL_ASN1_INTEGER, "\x81\x7f", 2, "0xffff817f", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\xff\xff", 2, "-1", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\x00\x00", 2, "0", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\x01\x02\x03", 3, "0x10203", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\xff\x02\xff", 3, "0xffff02ff", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\x00\xff\x00", 3, "0xff00", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\x01\x02\x03\x04", 4, "0x1020304", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\xff\x02\x03\x04", 4, "0xff020304", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\x00\x00\x00\x04", 4, "4", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\x00\x00\x00\x04\x05", 5, "00:00:00:04:05:",
+ CURLE_OK },
+ { CURL_ASN1_INTEGER, "\xff\x00\x00\x04\x05", 5, "ff:00:00:04:05:",
+ CURLE_OK },
+ { CURL_ASN1_INTEGER, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
+ 11, "ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff", 12, "ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:", CURLE_OK },
+ { CURL_ASN1_INTEGER, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff", 14, "", CURLE_TOO_LARGE},
+ { CURL_ASN1_INTEGER, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff\xff", 15, "", CURLE_TOO_LARGE },
+ { CURL_ASN1_INTEGER, "", 0, "", CURLE_BAD_FUNCTION_ARGUMENT },
+ /* Leading zero required if the MSB of the next byte is 1 (to keep it
+ positive) */
+ { CURL_ASN1_INTEGER, "\x00\x80", 2, "128", CURLE_OK },
+
+ /* Enumerated works the same as Integer */
+ { CURL_ASN1_ENUMERATED, "\x00", 1, "0", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\x01", 1, "1", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\x09", 1, "9", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\x0a", 1, "10", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\xb", 1, "11", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\x11", 1, "17", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\x7f", 1, "127", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\x80", 1, "-128", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\xff", 1, "-1", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\x7f\x81", 2, "0x7f81", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\xff\xff", 2, "-1", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\x00\x00", 2, "0", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\x01\x02\x03", 3, "0x10203", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\xff\x02\xff", 3, "0xffff02ff", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\x00\xff\x00", 3, "0xff00", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\x01\x02\x03\x04", 4, "0x1020304", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\xff\x02\x03\x04", 4, "0xff020304", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\x00\x00\x00\x04", 4, "4", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\x00\x00\x00\x04\x05", 5, "00:00:00:04:05:",
+ CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\xff\x00\x00\x04\x05", 5, "ff:00:00:04:05:",
+ CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
+ 11, "ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff", 12, "ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:", CURLE_OK },
+ { CURL_ASN1_ENUMERATED, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff", 14, "", CURLE_TOO_LARGE},
+ { CURL_ASN1_ENUMERATED, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff\xff", 15, "", CURLE_TOO_LARGE },
+ { CURL_ASN1_ENUMERATED, "", 0, "", CURLE_BAD_FUNCTION_ARGUMENT },
+
+ /* Boolean */
+ { CURL_ASN1_BOOLEAN, "\xff", 1, "TRUE", CURLE_OK },
+ { CURL_ASN1_BOOLEAN, "\x01", 1, "", CURLE_BAD_FUNCTION_ARGUMENT },
+ { CURL_ASN1_BOOLEAN, "\x02", 1, "", CURLE_BAD_FUNCTION_ARGUMENT },
+ { CURL_ASN1_BOOLEAN, "\x00", 1, "FALSE", CURLE_OK },
+ { CURL_ASN1_BOOLEAN, "\x01\x01", 2, "", CURLE_BAD_FUNCTION_ARGUMENT },
+ { CURL_ASN1_BOOLEAN, "\x00\x01", 2, "", CURLE_BAD_FUNCTION_ARGUMENT },
+ { CURL_ASN1_BOOLEAN, "", 0, "", CURLE_BAD_FUNCTION_ARGUMENT },
+ };
+
+ size_t i;
+ struct dynbuf dbuf;
+ bool all_ok = TRUE;
+
+ if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
+ curl_mfprintf(stderr, "curl_global_init() failed\n");
+ return TEST_ERR_MAJOR_BAD;
+ }
+
+ /* the real code uses CURL_X509_STR_MAX for maximum size, but we set a
+ smaller one here so that we can test running into the limit a little
+ easier */
+ curlx_dyn_init(&dbuf, 40);
+ for(i = 0; i < CURL_ARRAYSIZE(test_specs); ++i) {
+ if(!test1667(&test_specs[i], i, &dbuf))
+ all_ok = FALSE;
+ }
+ fail_unless(all_ok, "some tests of ASN1tostr() failed");
+
+ curlx_dyn_free(&dbuf);
+ curl_global_cleanup();
+
+ UNITTEST_END_SIMPLE
+}
+
+#undef OID
+
+#else
+
+static CURLcode test_unit1667(const char *arg)
+{
+ UNITTEST_BEGIN_SIMPLE
+ puts("not tested since ASN1tostr() is not built in");
+ UNITTEST_END_SIMPLE
+}
+
+#endif