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