diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h index 903e118da..3eb25f909 100644 --- a/src/headers/tomcrypt_pk.h +++ b/src/headers/tomcrypt_pk.h @@ -572,6 +572,14 @@ typedef struct ltc_asn1_list_ { LTC_TMPVAR(SAI_list)[LTC_TMPVAR(SAI)].tag = (Tag); \ } while (0) +#define LTC_SET_ASN1_CUSTOM(list, index, Class, Structure, Tag, Type, Data, Size) \ + do { \ + int LTC_TMPVAR(SAC) = (index); \ + LTC_SET_ASN1(list, LTC_TMPVAR(SAC), LTC_ASN1_CUSTOM_TYPE, Data, Size); \ + LTC_SET_ASN1_IDENTIFIER(list, LTC_TMPVAR(SAC), Class, Structure, Tag); \ + list[LTC_TMPVAR(SAC)].used = (int)(Type); \ + } while (0) + #define LTC_SET_ASN1_CUSTOM_CONSTRUCTED(list, index, Class, Tag, Data) \ do { \ int LTC_TMPVAR(SACC) = (index); \ diff --git a/src/pk/asn1/der/custom_type/der_encode_custom_type.c b/src/pk/asn1/der/custom_type/der_encode_custom_type.c index 586fb316b..9b8aca077 100644 --- a/src/pk/asn1/der/custom_type/der_encode_custom_type.c +++ b/src/pk/asn1/der/custom_type/der_encode_custom_type.c @@ -24,7 +24,7 @@ int der_encode_custom_type(const ltc_asn1_list *root, unsigned char *out, unsigned long *outlen) { - int err; + int err, use_root; ltc_asn1_type type; const ltc_asn1_list *list; unsigned long size, x, y, z, i, inlen, id_len; @@ -49,8 +49,9 @@ int der_encode_custom_type(const ltc_asn1_list *root, if (der_length_asn1_identifier(root, &id_len) != CRYPT_OK) return CRYPT_INVALID_ARG; x = id_len; - - if (root->pc == LTC_ASN1_PC_PRIMITIVE) { + use_root = root->pc == LTC_ASN1_PC_PRIMITIVE || + (root->used >= LTC_ASN1_SEQUENCE && root->used <= LTC_ASN1_SETOF); + if (use_root) { list = root; inlen = 1; /* In case it's a PRIMITIVE type we encode directly to the output @@ -72,7 +73,7 @@ int der_encode_custom_type(const ltc_asn1_list *root, /* store data */ *outlen -= x; for (i = 0; i < inlen; i++) { - if (root->pc == LTC_ASN1_PC_PRIMITIVE) { + if (use_root) { type = (ltc_asn1_type)list[i].used; } else { type = list[i].type; diff --git a/src/pk/asn1/der/utf8/der_decode_utf8_string.c b/src/pk/asn1/der/utf8/der_decode_utf8_string.c index 93a5e5ed2..ee543ddb0 100644 --- a/src/pk/asn1/der/utf8/der_decode_utf8_string.c +++ b/src/pk/asn1/der/utf8/der_decode_utf8_string.c @@ -56,7 +56,8 @@ int der_decode_utf8_string(const unsigned char *in, unsigned long inlen, https://tools.ietf.org/html/rfc3629#section-3 */ - for (y = 0; x < inlen; ) { + len += x; + for (y = 0; x < len; ) { /* read first byte */ tmp = in[x++]; @@ -87,7 +88,7 @@ int der_decode_utf8_string(const unsigned char *in, unsigned long inlen, /* now update z so it equals the number of additional bytes to read */ if (z > 0) { --z; } - if (x + z > inlen) { + if (x + z > len) { return CRYPT_INVALID_PACKET; } diff --git a/tests/der_test.c b/tests/der_test.c index 70683b81a..7d5901d84 100644 --- a/tests/der_test.c +++ b/tests/der_test.c @@ -11,6 +11,8 @@ int der_test(void) #else +#include + #if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 2 #define LTC_DER_TESTS_PRINT_FLEXI #endif @@ -252,7 +254,7 @@ static void s_free(void *p) XFREE(p); } -static void s_der_tests_print_flexi(ltc_asn1_list* l, unsigned int level) +static void s_der_tests_print_flexi_i(ltc_asn1_list* l, unsigned int level) { char *buf = NULL; const char* name = NULL; @@ -435,15 +437,28 @@ static void s_der_tests_print_flexi(ltc_asn1_list* l, unsigned int level) } if (ostring) { - s_der_tests_print_flexi(ostring, level + 1); + s_der_tests_print_flexi_i(ostring, level + 1); der_free_sequence_flexi(ostring); } if (l->child) - s_der_tests_print_flexi(l->child, level + 1); + s_der_tests_print_flexi_i(l->child, level + 1); if (l->next) - s_der_tests_print_flexi(l->next, level); + s_der_tests_print_flexi_i(l->next, level); +} + +static void s_der_tests_print_flexi(ltc_asn1_list* l) +{ + fprintf(stderr, "\n\n"); + s_der_tests_print_flexi_i(l, 0); + fprintf(stderr, "\n\n"); +} + +#else +static void s_der_tests_print_flexi(ltc_asn1_list* l) +{ + LTC_UNUSED_PARAM(l); } #endif @@ -471,11 +486,7 @@ static void der_cacert_test(void) CHECK_ASN1_TYPE(decoded_list, LTC_ASN1_SEQUENCE); CHECK_ASN1_HAS_NO_DATA(decoded_list); -#ifdef LTC_DER_TESTS_PRINT_FLEXI - printf("\n\n--- test print start ---\n\n"); - s_der_tests_print_flexi(decoded_list, 0); - printf("\n\n--- test print end ---\n\n"); -#endif + s_der_tests_print_flexi(decoded_list); l = decoded_list; @@ -1169,11 +1180,7 @@ static void s_der_decode_print(const void* p, unsigned long* plen) { ltc_asn1_list *list; DO(der_decode_sequence_flexi(p, plen, &list)); -#ifdef LTC_DER_TESTS_PRINT_FLEXI - fprintf(stderr, "\n\n"); - s_der_tests_print_flexi(list, 0); - fprintf(stderr, "\n\n"); -#endif + s_der_tests_print_flexi(list); der_sequence_free(list); } @@ -1342,11 +1349,7 @@ static void der_Xcode_test(void) i = sizeof(teletex_neg_int); DO(der_decode_sequence_flexi(teletex_neg_int, &i, &list)); -#ifdef LTC_DER_TESTS_PRINT_FLEXI - fprintf(stderr, "\n\n"); - s_der_tests_print_flexi(list, 0); - fprintf(stderr, "\n\n"); -#endif + s_der_tests_print_flexi(list); if (list->child == NULL || list->child->next == NULL) exit(EXIT_FAILURE); ttex_neg_int[0] = *list->child->next; @@ -1368,11 +1371,7 @@ static int s_der_decode_sequence_flexi(const void *in, unsigned long inlen, void { ltc_asn1_list** list = ctx; if (der_decode_sequence_flexi(in, &inlen, list) == CRYPT_OK) { -#ifdef LTC_DER_TESTS_PRINT_FLEXI - fprintf(stderr, "\n\n"); - s_der_tests_print_flexi(*list, 0); - fprintf(stderr, "\n\n"); -#endif + s_der_tests_print_flexi(*list); der_sequence_free(*list); } return CRYPT_OK; @@ -1423,6 +1422,49 @@ static void s_der_regression_test(void) SHOULD_FAIL(der_decode_sequence_flexi(issue_507, &len, &l)); } +static void s_der_custom_setof(void) +{ + /* + * C.f. https://github.com/libtom/libtomcrypt/issues/622 + * +Toy ::= SEQUENCE { + hello UTF8String, + numbers [0] IMPLICIT SET OF Number } + +Number ::= INTEGER { zero(0), one(1) } + +30 0F + 0C 02 68 69 + A0 09 + 02 01 00 + 02 01 00 + 02 01 01 + + * + */ + + ltc_asn1_list setof[3]; + ltc_asn1_list seq[2]; + const unsigned long zero = 0; + const unsigned long one = 1; + const wchar_t *hello = L"hi"; + unsigned char buf[32]; + unsigned long buflen = sizeof(buf); + ltc_asn1_list *flexi; + + LTC_SET_ASN1(setof, 0, LTC_ASN1_SHORT_INTEGER, &one, 1); + LTC_SET_ASN1(setof, 1, LTC_ASN1_SHORT_INTEGER, &zero, 1); + LTC_SET_ASN1(setof, 2, LTC_ASN1_SHORT_INTEGER, &zero, 1); + + LTC_SET_ASN1(seq, 0, LTC_ASN1_UTF8_STRING, hello, wcslen(hello)); + LTC_SET_ASN1_CUSTOM(seq, 1, LTC_ASN1_CL_CONTEXT_SPECIFIC, LTC_ASN1_PC_CONSTRUCTED, 0, LTC_ASN1_SETOF, setof, 3); + DO(der_encode_sequence(seq, 2, buf, &buflen)); + + DO(der_decode_sequence_flexi(buf, &buflen, &flexi)); + s_der_tests_print_flexi(flexi); + der_free_sequence_flexi(flexi); +} + static void der_toolong_test(void) { int n, err, failed = 0; @@ -1653,6 +1695,8 @@ int der_test(void) if (ltc_mp.name == NULL) return CRYPT_NOP; + s_der_custom_setof(); + s_der_recursion_limit(); der_Xcode_test();