xref: /openbsd-src/regress/lib/libcrypto/asn1/asn1complex.c (revision 7bb1a6cf33c70622e249876e749b4a7ea7b98384)
1*7bb1a6cfStb /* $OpenBSD: asn1complex.c,v 1.4 2022/09/05 21:06:31 tb Exp $ */
29e833530Sjsing /*
39e833530Sjsing  * Copyright (c) 2017, 2021 Joel Sing <jsing@openbsd.org>
49e833530Sjsing  *
59e833530Sjsing  * Permission to use, copy, modify, and distribute this software for any
69e833530Sjsing  * purpose with or without fee is hereby granted, provided that the above
79e833530Sjsing  * copyright notice and this permission notice appear in all copies.
89e833530Sjsing  *
99e833530Sjsing  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
109e833530Sjsing  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
119e833530Sjsing  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
129e833530Sjsing  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
139e833530Sjsing  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
149e833530Sjsing  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
159e833530Sjsing  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
169e833530Sjsing  */
179e833530Sjsing 
189e833530Sjsing #include <openssl/asn1.h>
1974884328Sjsing #include <openssl/asn1t.h>
209e833530Sjsing #include <openssl/err.h>
219e833530Sjsing 
229e833530Sjsing #include <err.h>
239e833530Sjsing #include <stdio.h>
249e833530Sjsing #include <string.h>
259e833530Sjsing 
269e833530Sjsing static void
hexdump(const unsigned char * buf,size_t len)279e833530Sjsing hexdump(const unsigned char *buf, size_t len)
289e833530Sjsing {
299e833530Sjsing 	size_t i;
309e833530Sjsing 
319e833530Sjsing 	for (i = 1; i <= len; i++)
329e833530Sjsing 		fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n");
339e833530Sjsing 
349e833530Sjsing 	fprintf(stderr, "\n");
359e833530Sjsing }
369e833530Sjsing 
379e833530Sjsing static int
asn1_compare_bytes(const char * label,const unsigned char * d1,int len1,const unsigned char * d2,int len2)389e833530Sjsing asn1_compare_bytes(const char *label, const unsigned char *d1, int len1,
399e833530Sjsing     const unsigned char *d2, int len2)
409e833530Sjsing {
419e833530Sjsing 	if (len1 != len2) {
429e833530Sjsing 		fprintf(stderr, "FAIL: %s - byte lengths differ "
43*7bb1a6cfStb 		    "(%d != %d)\n", label, len1, len2);
449e833530Sjsing 		return 0;
459e833530Sjsing 	}
469e833530Sjsing 	if (memcmp(d1, d2, len1) != 0) {
479e833530Sjsing 		fprintf(stderr, "FAIL: %s - bytes differ\n", label);
489e833530Sjsing 		fprintf(stderr, "Got:\n");
499e833530Sjsing 		hexdump(d1, len1);
509e833530Sjsing 		fprintf(stderr, "Want:\n");
519e833530Sjsing 		hexdump(d2, len2);
529e833530Sjsing 		return 0;
539e833530Sjsing 	}
549e833530Sjsing 	return 1;
559e833530Sjsing }
569e833530Sjsing 
579e833530Sjsing /* Constructed octet string with length 12. */
589e833530Sjsing const uint8_t asn1_constructed_basic_ber[] = {
599e833530Sjsing 	0x24, 0x0c,
609e833530Sjsing 	0x04, 0x01, 0x01,
619e833530Sjsing 	0x04, 0x02, 0x01, 0x02,
629e833530Sjsing 	0x04, 0x03, 0x01, 0x02, 0x03
639e833530Sjsing };
649e833530Sjsing const uint8_t asn1_constructed_basic_content[] = {
659e833530Sjsing 	0x01, 0x01, 0x02, 0x01, 0x02, 0x03,
669e833530Sjsing };
679e833530Sjsing 
689e833530Sjsing /* Nested constructed octet string. */
699e833530Sjsing const uint8_t asn1_constructed_nested_ber[] = {
709e833530Sjsing 	0x24, 0x1a,
719e833530Sjsing 	0x04, 0x01, 0x01,
729e833530Sjsing 	0x24, 0x15,
739e833530Sjsing 	0x04, 0x02, 0x02, 0x03,
749e833530Sjsing 	0x24, 0x0f,
759e833530Sjsing 	0x24, 0x0d,
769e833530Sjsing 	0x04, 0x03, 0x04, 0x05, 0x06,
779e833530Sjsing 	0x24, 0x06,
789e833530Sjsing 	0x24, 0x04,
799e833530Sjsing 	0x04, 0x02, 0x07, 0x08,
809e833530Sjsing };
819e833530Sjsing const uint8_t asn1_constructed_nested_content[] = {
829e833530Sjsing 	0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
839e833530Sjsing };
849e833530Sjsing 
859e833530Sjsing /* Deeply nested constructed octet string. */
869e833530Sjsing const uint8_t asn1_constructed_deep_nested_ber[] = {
879e833530Sjsing 	0x24, 0x1b,
889e833530Sjsing 	0x04, 0x01, 0x01,
899e833530Sjsing 	0x24, 0x16,
909e833530Sjsing 	0x04, 0x02, 0x02, 0x03,
919e833530Sjsing 	0x24, 0x10,
929e833530Sjsing 	0x24, 0x0e,
939e833530Sjsing 	0x04, 0x03, 0x04, 0x05, 0x06,
949e833530Sjsing 	0x24, 0x07,
959e833530Sjsing 	0x24, 0x05,
969e833530Sjsing 	0x24, 0x03,
979e833530Sjsing 	0x04, 0x01, 0x07,
989e833530Sjsing };
999e833530Sjsing 
1009e833530Sjsing /* Constructed octet string with indefinite length. */
1019e833530Sjsing const uint8_t asn1_constructed_indefinite_ber[] = {
1029e833530Sjsing 	0x24, 0x80,
1039e833530Sjsing 	0x04, 0x01, 0x01,
1049e833530Sjsing 	0x04, 0x02, 0x01, 0x02,
1059e833530Sjsing 	0x04, 0x03, 0x01, 0x02, 0x03,
1069e833530Sjsing 	0x00, 0x00,
1079e833530Sjsing };
1089e833530Sjsing const uint8_t asn1_constructed_indefinite_content[] = {
1099e833530Sjsing 	0x01, 0x01, 0x02, 0x01, 0x02, 0x03,
1109e833530Sjsing };
1119e833530Sjsing 
1129e833530Sjsing struct asn1_constructed_test {
1139e833530Sjsing 	const char *name;
1149e833530Sjsing 	const uint8_t *asn1;
1159e833530Sjsing 	size_t asn1_len;
1169e833530Sjsing 	const uint8_t *want;
1179e833530Sjsing 	size_t want_len;
1189e833530Sjsing 	int want_error;
1199e833530Sjsing 	int valid;
1209e833530Sjsing };
1219e833530Sjsing 
1229e833530Sjsing const struct asn1_constructed_test asn1_constructed_tests[] = {
1239e833530Sjsing 	{
1249e833530Sjsing 		.name = "basic constructed",
1259e833530Sjsing 		.asn1 = asn1_constructed_basic_ber,
1269e833530Sjsing 		.asn1_len = sizeof(asn1_constructed_basic_ber),
1279e833530Sjsing 		.want = asn1_constructed_basic_content,
1289e833530Sjsing 		.want_len = sizeof(asn1_constructed_basic_content),
1299e833530Sjsing 		.valid = 1,
1309e833530Sjsing 	},
1319e833530Sjsing 	{
1329e833530Sjsing 		.name = "nested constructed",
1339e833530Sjsing 		.asn1 = asn1_constructed_nested_ber,
1349e833530Sjsing 		.asn1_len = sizeof(asn1_constructed_nested_ber),
1359e833530Sjsing 		.want = asn1_constructed_nested_content,
1369e833530Sjsing 		.want_len = sizeof(asn1_constructed_nested_content),
1379e833530Sjsing 		.valid = 1,
1389e833530Sjsing 	},
1399e833530Sjsing 	{
1409e833530Sjsing 		.name = "deep nested constructed",
1419e833530Sjsing 		.asn1 = asn1_constructed_deep_nested_ber,
1429e833530Sjsing 		.asn1_len = sizeof(asn1_constructed_deep_nested_ber),
1439e833530Sjsing 		.want_error = ASN1_R_NESTED_ASN1_STRING,
1449e833530Sjsing 		.valid = 0,
1459e833530Sjsing 	},
1469e833530Sjsing 	{
1479e833530Sjsing 		.name = "indefinite length constructed",
1489e833530Sjsing 		.asn1 = asn1_constructed_indefinite_ber,
1499e833530Sjsing 		.asn1_len = sizeof(asn1_constructed_indefinite_ber),
1509e833530Sjsing 		.want = asn1_constructed_indefinite_content,
1519e833530Sjsing 		.want_len = sizeof(asn1_constructed_indefinite_content),
1529e833530Sjsing 		.valid = 1,
1539e833530Sjsing 	},
1549e833530Sjsing };
1559e833530Sjsing 
1569e833530Sjsing #define N_CONSTRUCTED_TESTS \
1579e833530Sjsing     (sizeof(asn1_constructed_tests) / sizeof(*asn1_constructed_tests))
1589e833530Sjsing 
1599e833530Sjsing static int
do_asn1_constructed_test(const struct asn1_constructed_test * act)1609e833530Sjsing do_asn1_constructed_test(const struct asn1_constructed_test *act)
1619e833530Sjsing {
1629e833530Sjsing 	ASN1_OCTET_STRING *aos = NULL;
1639e833530Sjsing 	const uint8_t *p;
1649e833530Sjsing 	long err;
1659e833530Sjsing 	int failed = 1;
1669e833530Sjsing 
167fb228d6dSjsing 	ERR_clear_error();
168fb228d6dSjsing 
1699e833530Sjsing 	p = act->asn1;
1709e833530Sjsing 	aos = d2i_ASN1_OCTET_STRING(NULL, &p, act->asn1_len);
1719e833530Sjsing 	if (!act->valid) {
1729e833530Sjsing 		if (aos != NULL) {
1739e833530Sjsing 			fprintf(stderr, "FAIL: invalid ASN.1 decoded\n");
1749e833530Sjsing 			goto failed;
1759e833530Sjsing 		}
1769e833530Sjsing 		if (act->want_error != 0) {
1779e833530Sjsing 			err = ERR_peek_error();
1789e833530Sjsing 			if (ERR_GET_REASON(err) != act->want_error) {
1799e833530Sjsing 				fprintf(stderr, "FAIL: got error reason %d,"
1809e833530Sjsing 				    "want %d", ERR_GET_REASON(err),
1819e833530Sjsing 				    act->want_error);
1829e833530Sjsing 				goto failed;
1839e833530Sjsing 			}
1849e833530Sjsing 		}
1859e833530Sjsing 		goto done;
1869e833530Sjsing 	}
1879e833530Sjsing 	if (aos == NULL) {
1889e833530Sjsing 		fprintf(stderr, "FAIL: failed to decode ASN.1 constructed "
1899e833530Sjsing 		    "octet string\n");
1909e833530Sjsing 		ERR_print_errors_fp(stderr);
1919e833530Sjsing 		goto failed;
1929e833530Sjsing 	}
1939e833530Sjsing 	if (!asn1_compare_bytes(act->name, ASN1_STRING_data(aos),
1949e833530Sjsing 	    ASN1_STRING_length(aos), act->want, act->want_len))
1959e833530Sjsing 		goto failed;
1969e833530Sjsing 
1979e833530Sjsing  done:
1989e833530Sjsing 	failed = 0;
1999e833530Sjsing 
2009e833530Sjsing  failed:
2019e833530Sjsing 	ASN1_OCTET_STRING_free(aos);
2029e833530Sjsing 
2039e833530Sjsing 	return failed;
2049e833530Sjsing }
2059e833530Sjsing 
2069e833530Sjsing static int
do_asn1_constructed_tests(void)2079e833530Sjsing do_asn1_constructed_tests(void)
2089e833530Sjsing {
2099e833530Sjsing 	const struct asn1_constructed_test *act;
2109e833530Sjsing 	int failed = 0;
2119e833530Sjsing 	size_t i;
2129e833530Sjsing 
2139e833530Sjsing 	for (i = 0; i < N_CONSTRUCTED_TESTS; i++) {
2149e833530Sjsing 		act = &asn1_constructed_tests[i];
2159e833530Sjsing 		failed |= do_asn1_constructed_test(act);
2169e833530Sjsing 	}
2179e833530Sjsing 
2189e833530Sjsing 	return failed;
2199e833530Sjsing }
2209e833530Sjsing 
22174884328Sjsing /* Sequence with length. */
22274884328Sjsing const uint8_t asn1_sequence_ber[] = {
22374884328Sjsing 	0x30, 0x16,
22474884328Sjsing 	0x04, 0x01, 0x01,
22574884328Sjsing 	0x04, 0x02, 0x01, 0x02,
22674884328Sjsing 	0x04, 0x03, 0x01, 0x02, 0x03,
22774884328Sjsing 	0x30, 0x80, 0x04, 0x01, 0x01, 0x00, 0x00,
22874884328Sjsing 	0x04, 0x01, 0x01,
22974884328Sjsing 
23074884328Sjsing 	0x04, 0x01, 0x01, /* Trailing data. */
23174884328Sjsing };
23274884328Sjsing 
23374884328Sjsing const uint8_t asn1_sequence_content[] = {
23474884328Sjsing 	0x30, 0x16, 0x04, 0x01, 0x01, 0x04, 0x02, 0x01,
23574884328Sjsing 	0x02, 0x04, 0x03, 0x01, 0x02, 0x03, 0x30, 0x80,
23674884328Sjsing 	0x04, 0x01, 0x01, 0x00, 0x00, 0x04, 0x01, 0x01,
23774884328Sjsing };
23874884328Sjsing 
23974884328Sjsing /* Sequence with indefinite length. */
24074884328Sjsing const uint8_t asn1_sequence_indefinite_ber[] = {
24174884328Sjsing 	0x30, 0x80,
24274884328Sjsing 	0x04, 0x01, 0x01,
24374884328Sjsing 	0x04, 0x02, 0x01, 0x02,
24474884328Sjsing 	0x04, 0x03, 0x01, 0x02, 0x03,
24574884328Sjsing 	0x30, 0x80, 0x04, 0x01, 0x01, 0x00, 0x00,
24674884328Sjsing 	0x04, 0x01, 0x01,
24774884328Sjsing 	0x00, 0x00,
24874884328Sjsing 
24974884328Sjsing 	0x04, 0x01, 0x01, /* Trailing data. */
25074884328Sjsing };
25174884328Sjsing 
25274884328Sjsing const uint8_t asn1_sequence_indefinite_content[] = {
25374884328Sjsing 	0x30, 0x80, 0x04, 0x01, 0x01, 0x04, 0x02, 0x01,
25474884328Sjsing 	0x02, 0x04, 0x03, 0x01, 0x02, 0x03, 0x30, 0x80,
25574884328Sjsing 	0x04, 0x01, 0x01, 0x00, 0x00, 0x04, 0x01, 0x01,
25674884328Sjsing 	0x00, 0x00,
25774884328Sjsing };
25874884328Sjsing 
25974884328Sjsing static int
do_asn1_sequence_string_tests(void)26074884328Sjsing do_asn1_sequence_string_tests(void)
26174884328Sjsing {
26274884328Sjsing 	ASN1_STRING *astr = NULL;
26374884328Sjsing 	const uint8_t *p;
26474884328Sjsing 	long len;
26574884328Sjsing 	int failed = 1;
26674884328Sjsing 
26774884328Sjsing 	ERR_clear_error();
26874884328Sjsing 
26974884328Sjsing 	/*
27074884328Sjsing 	 * Test decoding of sequence with length and indefinite length into
27174884328Sjsing 	 * a string - in this case the ASN.1 is not decoded and is stored
27274884328Sjsing 	 * directly as the content for the string.
27374884328Sjsing 	 */
27474884328Sjsing 	if ((astr = ASN1_STRING_new()) == NULL) {
27574884328Sjsing 		fprintf(stderr, "FAIL: ASN1_STRING_new() returned NULL\n");
27674884328Sjsing 		goto failed;
27774884328Sjsing 	}
27874884328Sjsing 
27974884328Sjsing 	p = asn1_sequence_ber;
28074884328Sjsing 	len = sizeof(asn1_sequence_ber);
28174884328Sjsing 	if (ASN1_item_d2i((ASN1_VALUE **)&astr, &p, len,
28274884328Sjsing 	    &ASN1_SEQUENCE_it) == NULL) {
28374884328Sjsing 		fprintf(stderr, "FAIL: failed to decode ASN1_SEQUENCE\n");
28474884328Sjsing 		ERR_print_errors_fp(stderr);
28574884328Sjsing 		goto failed;
28674884328Sjsing 	}
28774884328Sjsing 
28874884328Sjsing 	if (!asn1_compare_bytes("sequence", ASN1_STRING_data(astr),
28974884328Sjsing 	    ASN1_STRING_length(astr), asn1_sequence_content,
29074884328Sjsing 	    sizeof(asn1_sequence_content)))
29174884328Sjsing 		goto failed;
29274884328Sjsing 
29374884328Sjsing 	p = asn1_sequence_indefinite_ber;
29474884328Sjsing 	len = sizeof(asn1_sequence_indefinite_ber);
29574884328Sjsing 	if (ASN1_item_d2i((ASN1_VALUE **)&astr, &p, len,
29674884328Sjsing 	    &ASN1_SEQUENCE_it) == NULL) {
29774884328Sjsing 		fprintf(stderr, "FAIL: failed to decode ASN1_SEQUENCE\n");
29874884328Sjsing 		ERR_print_errors_fp(stderr);
29974884328Sjsing 		goto failed;
30074884328Sjsing 	}
30174884328Sjsing 
30274884328Sjsing 	if (!asn1_compare_bytes("sequence indefinite", ASN1_STRING_data(astr),
30374884328Sjsing 	    ASN1_STRING_length(astr), asn1_sequence_indefinite_content,
30474884328Sjsing 	    sizeof(asn1_sequence_indefinite_content)))
30574884328Sjsing 		goto failed;
30674884328Sjsing 
30774884328Sjsing 	failed = 0;
30874884328Sjsing 
30974884328Sjsing  failed:
31074884328Sjsing 	ASN1_STRING_free(astr);
31174884328Sjsing 
31274884328Sjsing 	return failed;
31374884328Sjsing }
31474884328Sjsing 
3159e833530Sjsing int
main(int argc,char ** argv)3169e833530Sjsing main(int argc, char **argv)
3179e833530Sjsing {
3189e833530Sjsing 	int failed = 0;
3199e833530Sjsing 
3209e833530Sjsing 	failed |= do_asn1_constructed_tests();
32174884328Sjsing 	failed |= do_asn1_sequence_string_tests();
3229e833530Sjsing 
3239e833530Sjsing 	return (failed);
3249e833530Sjsing }
325