diff --git a/src/headers/tomcrypt_custom.h b/src/headers/tomcrypt_custom.h index 0fe1c933..01f77bea 100644 --- a/src/headers/tomcrypt_custom.h +++ b/src/headers/tomcrypt_custom.h @@ -505,6 +505,13 @@ #endif #endif +#if defined(LTC_DER) + #ifndef LTC_DER_MAX_RECURSION + /* Maximum recursion limit when processing nested ASN.1 types. */ + #define LTC_DER_MAX_RECURSION 30 + #endif +#endif + #if defined(LTC_MECC) || defined(LTC_MRSA) || defined(LTC_MDSA) || defined(LTC_MKAT) /* Include the MPI functionality? (required by the PK algorithms) */ #define LTC_MPI diff --git a/src/misc/crypt/crypt.c b/src/misc/crypt/crypt.c index 6705beaf..d8eaa735 100644 --- a/src/misc/crypt/crypt.c +++ b/src/misc/crypt/crypt.c @@ -428,6 +428,7 @@ const char *crypt_build_settings = #endif #if defined(LTC_DER) " DER " + " " NAME_VALUE(LTC_DER_MAX_RECURSION) " " #endif #if defined(LTC_PKCS_1) " PKCS#1 " diff --git a/src/misc/crypt/crypt_constants.c b/src/misc/crypt/crypt_constants.c index c5517695..902b7749 100644 --- a/src/misc/crypt/crypt_constants.c +++ b/src/misc/crypt/crypt_constants.c @@ -126,6 +126,7 @@ static const crypt_constant _crypt_constants[] = { #ifdef LTC_DER /* DER handling */ + {"LTC_DER", 1}, _C_STRINGIFY(LTC_ASN1_EOL), _C_STRINGIFY(LTC_ASN1_BOOLEAN), _C_STRINGIFY(LTC_ASN1_INTEGER), @@ -146,6 +147,9 @@ static const crypt_constant _crypt_constants[] = { _C_STRINGIFY(LTC_ASN1_TELETEX_STRING), _C_STRINGIFY(LTC_ASN1_GENERALIZEDTIME), _C_STRINGIFY(LTC_ASN1_CUSTOM_TYPE), + _C_STRINGIFY(LTC_DER_MAX_RECURSION), +#else + {"LTC_DER", 0}, #endif #ifdef LTC_CTR_MODE diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c b/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c index 756a6f94..a6c3cf76 100644 --- a/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c +++ b/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c @@ -43,7 +43,7 @@ static int _new_element(ltc_asn1_list **l) */ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out) { - ltc_asn1_list *l; + ltc_asn1_list *l, *t; unsigned long err, identifier, len, totlen, data_offset, id_len, len_len; void *realloc_tmp; @@ -463,6 +463,17 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc l->child->parent = l; } + t = l; + len_len = 0; + while((t != NULL) && (t->child != NULL)) { + len_len++; + t = t->child; + } + if (len_len > LTC_DER_MAX_RECURSION) { + err = CRYPT_PK_ASN1_ERROR; + goto error; + } + break; case 0x80: /* Context-specific */ diff --git a/tests/common.h b/tests/common.h index 1ba88207..f63e26b3 100644 --- a/tests/common.h +++ b/tests/common.h @@ -16,9 +16,11 @@ extern prng_state yarrow_prng; #ifdef LTC_VERBOSE #define DO(x) do { fprintf(stderr, "%s:\n", #x); run_cmd((x), __LINE__, __FILE__, #x, NULL); } while (0) #define DOX(x, str) do { fprintf(stderr, "%s - %s:\n", #x, (str)); run_cmd((x), __LINE__, __FILE__, #x, (str)); } while (0) +#define SHOULD_FAIL(x) do { fprintf(stderr, "%s:\n", #x); run_cmd((x) != CRYPT_OK ? CRYPT_OK : CRYPT_FAIL_TESTVECTOR, __LINE__, __FILE__, #x, NULL); } while (0) #else #define DO(x) do { run_cmd((x), __LINE__, __FILE__, #x, NULL); } while (0) #define DOX(x, str) do { run_cmd((x), __LINE__, __FILE__, #x, (str)); } while (0) +#define SHOULD_FAIL(x) do { run_cmd((x) != CRYPT_OK ? CRYPT_OK : CRYPT_FAIL_TESTVECTOR, __LINE__, __FILE__, #x, NULL); } while (0) #endif void run_cmd(int res, int line, const char *file, const char *cmd, const char *algorithm); diff --git a/tests/der_test.c b/tests/der_test.c index e38c9fc1..a6c34748 100644 --- a/tests/der_test.c +++ b/tests/der_test.c @@ -1580,6 +1580,25 @@ static void der_toolong_test(void) if (failed) exit(EXIT_FAILURE); } +static void _der_recursion_limit(void) +{ + int failed = 0; + unsigned int n; + unsigned long integer = 123, s; + ltc_asn1_list seqs[LTC_DER_MAX_RECURSION + 2], dummy[1], *flexi; + unsigned char buf[2048]; + LTC_SET_ASN1(dummy, 0, LTC_ASN1_SHORT_INTEGER, &integer, 1); + LTC_SET_ASN1(seqs, LTC_DER_MAX_RECURSION + 1, LTC_ASN1_SEQUENCE, dummy, 1); + for (n = 0; n < LTC_DER_MAX_RECURSION + 1; ++n) { + LTC_SET_ASN1(seqs, LTC_DER_MAX_RECURSION - n, LTC_ASN1_SEQUENCE, &seqs[LTC_DER_MAX_RECURSION - n + 1], 1); + } + s = sizeof(buf); + DO(der_encode_sequence(seqs, 1, buf, &s)); + DO(der_decode_sequence(buf, s, seqs, 1)); + SHOULD_FAIL(der_decode_sequence_flexi(buf, &s, &flexi)); + if (failed) exit(EXIT_FAILURE); +} + int der_test(void) { unsigned long x, y, z, zz, oid[2][32]; @@ -1614,6 +1633,8 @@ int der_test(void) if (ltc_mp.name == NULL) return CRYPT_NOP; + _der_recursion_limit(); + der_Xcode_test(); #if !((defined(_WIN32) || defined(_WIN32_WCE)) && !defined(__GNUC__))