diff --git a/CMakeLists.txt b/CMakeLists.txt index c981ef75b5..c3eb9c19c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,12 +40,12 @@ cmake_policy(SET CMP0012 NEW) if(TEST_CPP) project("Mbed TLS" LANGUAGES C CXX - VERSION 3.6.3 + VERSION 3.6.4 ) else() project("Mbed TLS" LANGUAGES C - VERSION 3.6.3 + VERSION 3.6.4 ) endif() @@ -476,7 +476,7 @@ if(NOT DISABLE_PACKAGE_CONFIG_AND_INSTALL) write_basic_package_version_file( "cmake/MbedTLSConfigVersion.cmake" COMPATIBILITY SameMajorVersion - VERSION 3.6.3) + VERSION 3.6.4) install( FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/MbedTLSConfig.cmake" diff --git a/ChangeLog b/ChangeLog index 5cadd2b007..4d4bbdbe51 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,115 @@ Mbed TLS ChangeLog (Sorted per branch, date) += Mbed TLS 3.6.4 branch released 2025-06-30 + +Features + * Add the function mbedtls_ssl_export_keying_material() which allows the + client and server to extract additional shared symmetric keys from an SSL + session, according to the TLS-Exporter specification in RFC 8446 and 5705. + This requires MBEDTLS_SSL_KEYING_MATERIAL_EXPORT to be defined in + mbedtls_config.h. + +Security + * Fix a buffer overread in mbedtls_lms_import_public_key() when the input is + less than 3 bytes. Reported by Linh Le and Ngan Nguyen from Calif. + CVE-2025-49601 + * Fix a vulnerability in LMS verification through which an adversary could + get an invalid signature accepted if they could cause a hash accelerator + to fail. Found and reported by Linh Le and Ngan Nguyen from Calif. + CVE-2025-49600 + * On x86/amd64 platforms, with some compilers, when the library is + compiled with support for both AESNI and software AES and AESNI is + available in hardware, an adversary with fine control over which + threads make progress in a multithreaded program could force software + AES to be used for some time when the program starts. This could allow + the adversary to conduct timing attacks and potentially recover the + key. In particular, this attacker model may be possible against an SGX + enclave. + The same vulnerability affects GCM acceleration, which could allow + a similarly powerful adversary to craft GCM forgeries. + CVE-2025-52496 + * Fix possible use-after-free or double-free in code calling + mbedtls_x509_string_to_names(). This was caused by the function calling + mbedtls_asn1_free_named_data_list() on its head argument, while the + documentation did no suggest it did, making it likely for callers relying + on the documented behaviour to still hold pointers to memory blocks after + they were free()d, resulting in high risk of use-after-free or double-free, + with consequences ranging up to arbitrary code execution. + In particular, the two sample programs x509/cert_write and x509/cert_req + were affected (use-after-free if the san string contains more than one DN). + Code that does not call mbedtls_string_to_names() directly is not affected. + Found by Linh Le and Ngan Nguyen from Calif. + CVE-2025-47917 + * Fix a bug in mbedtls_asn1_store_named_data() where it would sometimes leave + an item in the output list in an inconsistent state with val.p == NULL but + val.len > 0. This impacts applications that call this function directly, + or indirectly via mbedtls_x509_string_to_names() or one of the + mbedtls_x509write_{crt,csr}_set_{subject,issuer}_name() functions. The + inconsistent state of the output could then cause a NULL dereference either + inside the same call to mbedtls_x509_string_to_names(), or in subsequent + users of the output structure, such as mbedtls_x509_write_names(). This + only affects applications that create (as opposed to consume) X.509 + certificates, CSRs or CRLs, or that call mbedtls_asn1_store_named_data() + directly. Found by Linh Le and Ngan Nguyen from Calif. + CVE-2025-48965 + * Fix an integer underflow that could occur when parsing malformed PEM + keys, which could be used by an attacker capable of feeding encrypted + PEM keys to a user. This could cause a crash or information disclosure. + Found and reported by Linh Le and Ngan Nguyen from Calif. + CVE-2025-52497 + * Fix a timing side channel in the implementation of PKCS#7 padding + which would allow an attacker who can request decryption of arbitrary + ciphertexts to recover the plaintext through a timing oracle attack. + Reported by Ka Lok Wu from Stony Brook University and Doria Tang from + The Chinese University of Hong Kong. + CVE-2025-49087 + +Bugfix + * Fix failures of PSA multipart or interruptible operations when the + library or the application is built with a compiler where + "union foo x = {0}" does not initialize non-default members of the + union, such as GCC 15 and some versions of Clang 18. This affected MAC + multipart operations, MAC-based key derivation operations, interruptible + signature, interruptible verification, and potentially other operations + when using third-party drivers. This also affected one-shot MAC + operations using the built-in implementation. Fixes #9814. + * On entry to PSA driver entry points that set up a multipart operation + ("xxx_setup"), the operation object is supposed to be all-bits-zero. + This was sometimes not the case when an operation object is reused, + or with compilers where "union foo x = {0}" does not initialize + non-default members of the union. The PSA core now ensures that this + guarantee is met in all cases. Fixes #9975. + * Resolved build issue with C++ projects using Mbed TLS 3.6 when compiling + with the MSVC toolset v142 and earlier. Fixes mbedtls issue #7087. + * Silence spurious -Wunterminated-string-initialization warnings introduced + by GCC 15. Fixes #9944. + * Fix a sloppy check in LMS public key import, which could lead to accepting + keys with a different LMS or LM-OTS types on some platforms. Specifically, + this could happen on platforms where enum types are smaller than 32 bits + and compiler optimization is enabled. Found and reported by Linh Le and + Ngan Nguyen from Calif. + * Fix a race condition on x86/amd64 platforms in AESNI support detection + that could lead to using software AES in some threads at the very + beginning of a multithreaded program. Reported by Solar Designer. + Fixes #9840. + * Fix mbedtls_base64_decode() on inputs that did not have the correct + number of trailing equal signs, or had 4*k+1 digits. They were accepted + as long as they had at most two trailing equal signs. They are now + rejected. Furthermore, before, on inputs with too few equal signs, the + function reported the correct size in *olen when it returned + MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL, but truncated the output to the + last multiple of 3 bytes. + * When calling mbedtls_asn1_write_raw_buffer() with NULL, 0 as the last two + arguments, undefined behaviour would be triggered, in the form of a call to + memcpy(..., NULL, 0). This was harmless in practice, but could trigger + complains from sanitizers or static analyzers. + +Changes + * The function mbedtls_x509_string_to_names() now requires its head argument + to point to NULL on entry. This makes it likely that existing risky uses of + this function (see the entry in the Security section) will be detected and + fixed. + = Mbed TLS 3.6.3 branch released 2025-03-24 Default behavior changes diff --git a/ChangeLog.d/add-tls-exporter.txt b/ChangeLog.d/add-tls-exporter.txt deleted file mode 100644 index 1aea653e09..0000000000 --- a/ChangeLog.d/add-tls-exporter.txt +++ /dev/null @@ -1,6 +0,0 @@ -Features - * Add the function mbedtls_ssl_export_keying_material() which allows the - client and server to extract additional shared symmetric keys from an SSL - session, according to the TLS-Exporter specification in RFC 8446 and 5705. - This requires MBEDTLS_SSL_KEYING_MATERIAL_EXPORT to be defined in - mbedtls_config.h. diff --git a/ChangeLog.d/move-crypto-struct-inclusion.txt b/ChangeLog.d/move-crypto-struct-inclusion.txt deleted file mode 100644 index b84e6d37d2..0000000000 --- a/ChangeLog.d/move-crypto-struct-inclusion.txt +++ /dev/null @@ -1,3 +0,0 @@ -Bugfix - * Resolved build issue with C++ projects using Mbed TLS 3.6 when compiling - with the MSVC toolset v142 and earlier. Fixes mbedtls issue #7087. diff --git a/ChangeLog.d/union-initialization.txt b/ChangeLog.d/union-initialization.txt deleted file mode 100644 index a63e1ebc00..0000000000 --- a/ChangeLog.d/union-initialization.txt +++ /dev/null @@ -1,15 +0,0 @@ -Bugfix - * Fix failures of PSA multipart or interruptible operations when the - library or the application is built with a compiler where - "union foo x = {0}" does not initialize non-default members of the - union, such as GCC 15 and some versions of Clang 18. This affected MAC - multipart operations, MAC-based key derivation operations, interruptible - signature, interruptible verification, and potentially other operations - when using third-party drivers. This also affected one-shot MAC - operations using the built-in implementation. Fixes #9814. - * On entry to PSA driver entry points that set up a multipart operation - ("xxx_setup"), the operation object is supposed to be all-bits-zero. - This was sometimes not the case when an operation object is reused, - or with compilers where "union foo x = {0}" does not initialize - non-default members of the union. The PSA core now ensures that this - guarantee is met in all cases. Fixes #9975. diff --git a/ChangeLog.d/unterminated-string-initialization.txt b/ChangeLog.d/unterminated-string-initialization.txt deleted file mode 100644 index 75a72cae6b..0000000000 --- a/ChangeLog.d/unterminated-string-initialization.txt +++ /dev/null @@ -1,3 +0,0 @@ -Bugfix - * Silence spurious -Wunterminated-string-initialization warnings introduced - by GCC 15. Fixes #9944. diff --git a/doxygen/input/doc_mainpage.h b/doxygen/input/doc_mainpage.h index f903d3f17c..200db75eea 100644 --- a/doxygen/input/doc_mainpage.h +++ b/doxygen/input/doc_mainpage.h @@ -10,7 +10,7 @@ */ /** - * @mainpage Mbed TLS v3.6.3 API Documentation + * @mainpage Mbed TLS v3.6.4 API Documentation * * This documentation describes the internal structure of Mbed TLS. It was * automatically generated from specially formatted comment blocks in diff --git a/doxygen/mbedtls.doxyfile b/doxygen/mbedtls.doxyfile index 0acead9651..2918f45075 100644 --- a/doxygen/mbedtls.doxyfile +++ b/doxygen/mbedtls.doxyfile @@ -1,4 +1,4 @@ -PROJECT_NAME = "Mbed TLS v3.6.3" +PROJECT_NAME = "Mbed TLS v3.6.4" OUTPUT_DIRECTORY = ../apidoc/ FULL_PATH_NAMES = NO OPTIMIZE_OUTPUT_FOR_C = YES diff --git a/include/mbedtls/build_info.h b/include/mbedtls/build_info.h index e70c4d7cc5..e18e823c15 100644 --- a/include/mbedtls/build_info.h +++ b/include/mbedtls/build_info.h @@ -26,16 +26,16 @@ */ #define MBEDTLS_VERSION_MAJOR 3 #define MBEDTLS_VERSION_MINOR 6 -#define MBEDTLS_VERSION_PATCH 3 +#define MBEDTLS_VERSION_PATCH 4 /** * The single version number has the following structure: * MMNNPP00 * Major version | Minor version | Patch version */ -#define MBEDTLS_VERSION_NUMBER 0x03060300 -#define MBEDTLS_VERSION_STRING "3.6.3" -#define MBEDTLS_VERSION_STRING_FULL "Mbed TLS 3.6.3" +#define MBEDTLS_VERSION_NUMBER 0x03060400 +#define MBEDTLS_VERSION_STRING "3.6.4" +#define MBEDTLS_VERSION_STRING_FULL "Mbed TLS 3.6.4" /* Macros for build-time platform detection */ diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index 453f598c74..6b104613d7 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -332,7 +332,8 @@ int mbedtls_x509_dn_gets(char *buf, size_t size, const mbedtls_x509_name *dn); * call to mbedtls_asn1_free_named_data_list(). * * \param[out] head Address in which to store the pointer to the head of the - * allocated list of mbedtls_x509_name + * allocated list of mbedtls_x509_name. Must point to NULL on + * entry. * \param[in] name The string representation of a DN to convert * * \return 0 on success, or a negative error code. diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index e2a1920850..b2c21fab35 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -300,7 +300,7 @@ endif(USE_STATIC_MBEDTLS_LIBRARY) if(USE_SHARED_MBEDTLS_LIBRARY) set(CMAKE_LIBRARY_PATH ${CMAKE_CURRENT_BINARY_DIR}) add_library(${mbedcrypto_target} SHARED ${src_crypto}) - set_target_properties(${mbedcrypto_target} PROPERTIES VERSION 3.6.3 SOVERSION 16) + set_target_properties(${mbedcrypto_target} PROPERTIES VERSION 3.6.4 SOVERSION 16) target_link_libraries(${mbedcrypto_target} PUBLIC ${libs}) if(TARGET ${everest_target}) @@ -312,11 +312,11 @@ if(USE_SHARED_MBEDTLS_LIBRARY) endif() add_library(${mbedx509_target} SHARED ${src_x509}) - set_target_properties(${mbedx509_target} PROPERTIES VERSION 3.6.3 SOVERSION 7) + set_target_properties(${mbedx509_target} PROPERTIES VERSION 3.6.4 SOVERSION 7) target_link_libraries(${mbedx509_target} PUBLIC ${libs} ${mbedcrypto_target}) add_library(${mbedtls_target} SHARED ${src_tls}) - set_target_properties(${mbedtls_target} PROPERTIES VERSION 3.6.3 SOVERSION 21) + set_target_properties(${mbedtls_target} PROPERTIES VERSION 3.6.4 SOVERSION 21) target_link_libraries(${mbedtls_target} PUBLIC ${libs} ${mbedx509_target}) endif(USE_SHARED_MBEDTLS_LIBRARY) diff --git a/library/aesni.c b/library/aesni.c index 4fc1cb918b..2857068244 100644 --- a/library/aesni.c +++ b/library/aesni.c @@ -48,8 +48,19 @@ */ int mbedtls_aesni_has_support(unsigned int what) { - static int done = 0; - static unsigned int c = 0; + /* To avoid a race condition, tell the compiler that the assignment + * `done = 1` and the assignment to `c` may not be reordered. + * https://github.com/Mbed-TLS/mbedtls/issues/9840 + * + * Note that we may also be worried about memory access reordering, + * but fortunately the x86 memory model is not too wild: stores + * from the same thread are observed consistently by other threads. + * (See example 8-1 in Sewell et al., "x86-TSO: A Rigorous and Usable + * Programmer’s Model for x86 Multiprocessors", CACM, 2010, + * https://www.cl.cam.ac.uk/~pes20/weakmemory/cacm.pdf) + */ + static volatile int done = 0; + static volatile unsigned int c = 0; if (!done) { #if MBEDTLS_AESNI_HAVE_CODE == 2 diff --git a/library/asn1write.c b/library/asn1write.c index 775a9ef530..97f9db039b 100644 --- a/library/asn1write.c +++ b/library/asn1write.c @@ -90,7 +90,9 @@ int mbedtls_asn1_write_raw_buffer(unsigned char **p, const unsigned char *start, len = size; (*p) -= len; - memcpy(*p, buf, len); + if (len != 0) { + memcpy(*p, buf, len); + } return (int) len; } @@ -412,6 +414,7 @@ mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( } else if (val_len == 0) { mbedtls_free(cur->val.p); cur->val.p = NULL; + cur->val.len = 0; } else if (cur->val.len != val_len) { /* * Enlarge existing value buffer if needed diff --git a/library/base64.c b/library/base64.c index 9677dee5b2..388fa9f388 100644 --- a/library/base64.c +++ b/library/base64.c @@ -14,6 +14,7 @@ #include "mbedtls/base64.h" #include "base64_internal.h" #include "constant_time_internal.h" +#include "mbedtls/error.h" #include @@ -183,49 +184,72 @@ int mbedtls_base64_decode(unsigned char *dst, size_t dlen, size_t *olen, n++; } - if (n == 0) { - *olen = 0; - return 0; + /* In valid base64, the number of digits (n-equals) is always of the form + * 4*k, 4*k+2 or *4k+3. Also, the number n of digits plus the number of + * equal signs at the end is always a multiple of 4. */ + if ((n - equals) % 4 == 1) { + return MBEDTLS_ERR_BASE64_INVALID_CHARACTER; + } + if (n % 4 != 0) { + return MBEDTLS_ERR_BASE64_INVALID_CHARACTER; } - /* The following expression is to calculate the following formula without - * risk of integer overflow in n: - * n = ( ( n * 6 ) + 7 ) >> 3; + /* We've determined that the input is valid, and that it contains + * exactly k blocks of digits-or-equals, with n = 4 * k, + * and equals only present at the end of the last block if at all. + * Now we can calculate the length of the output. + * + * Each block of 4 digits in the input map to 3 bytes of output. + * For the last block: + * - abcd (where abcd are digits) is a full 3-byte block; + * - abc= means 1 byte less than a full 3-byte block of output; + * - ab== means 2 bytes less than a full 3-byte block of output; + * - a==== and ==== is rejected above. */ - n = (6 * (n >> 3)) + ((6 * (n & 0x7) + 7) >> 3); - n -= equals; + *olen = (n / 4) * 3 - equals; - if (dst == NULL || dlen < n) { - *olen = n; + /* If the output buffer is too small, signal this and stop here. + * Also, as documented, stop here if `dst` is null, independently of + * `dlen`. + * + * There is an edge case when the output is empty: in this case, + * `dlen == 0` with `dst == NULL` is valid (on some platforms, + * `malloc(0)` returns `NULL`). Since the call is valid, we return + * 0 in this case. + */ + if ((*olen != 0 && dst == NULL) || dlen < *olen) { return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL; } - equals = 0; for (x = 0, p = dst; i > 0; i--, src++) { if (*src == '\r' || *src == '\n' || *src == ' ') { continue; } - - x = x << 6; if (*src == '=') { - ++equals; - } else { - x |= mbedtls_ct_base64_dec_value(*src); + /* We already know from the first loop that equal signs are + * only at the end. */ + break; } + x = x << 6; + x |= mbedtls_ct_base64_dec_value(*src); if (++accumulated_digits == 4) { accumulated_digits = 0; *p++ = MBEDTLS_BYTE_2(x); - if (equals <= 1) { - *p++ = MBEDTLS_BYTE_1(x); - } - if (equals <= 0) { - *p++ = MBEDTLS_BYTE_0(x); - } + *p++ = MBEDTLS_BYTE_1(x); + *p++ = MBEDTLS_BYTE_0(x); } } + if (accumulated_digits == 3) { + *p++ = MBEDTLS_BYTE_2(x << 6); + *p++ = MBEDTLS_BYTE_1(x << 6); + } else if (accumulated_digits == 2) { + *p++ = MBEDTLS_BYTE_2(x << 12); + } - *olen = (size_t) (p - dst); + if (*olen != (size_t) (p - dst)) { + return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + } return 0; } diff --git a/library/cipher.c b/library/cipher.c index 7f4c121492..2ae01dd84d 100644 --- a/library/cipher.c +++ b/library/cipher.c @@ -14,6 +14,7 @@ #if defined(MBEDTLS_CIPHER_C) #include "mbedtls/cipher.h" +#include "cipher_invasive.h" #include "cipher_wrap.h" #include "mbedtls/platform_util.h" #include "mbedtls/error.h" @@ -838,8 +839,14 @@ static void add_pkcs_padding(unsigned char *output, size_t output_len, } } -static int get_pkcs_padding(unsigned char *input, size_t input_len, - size_t *data_len) +/* + * Get the length of the PKCS7 padding. + * + * Note: input_len must be the block size of the cipher. + */ +MBEDTLS_STATIC_TESTABLE int mbedtls_get_pkcs_padding(unsigned char *input, + size_t input_len, + size_t *data_len) { size_t i, pad_idx; unsigned char padding_len; @@ -849,10 +856,6 @@ static int get_pkcs_padding(unsigned char *input, size_t input_len, } padding_len = input[input_len - 1]; - if (padding_len == 0 || padding_len > input_len) { - return MBEDTLS_ERR_CIPHER_INVALID_PADDING; - } - *data_len = input_len - padding_len; mbedtls_ct_condition_t bad = mbedtls_ct_uint_gt(padding_len, input_len); bad = mbedtls_ct_bool_or(bad, mbedtls_ct_uint_eq(padding_len, 0)); @@ -866,6 +869,9 @@ static int get_pkcs_padding(unsigned char *input, size_t input_len, bad = mbedtls_ct_bool_or(bad, mbedtls_ct_bool_and(in_padding, different)); } + /* If the padding is invalid, set the output length to 0 */ + *data_len = mbedtls_ct_if(bad, 0, input_len - padding_len); + return mbedtls_ct_error_if_else_0(bad, MBEDTLS_ERR_CIPHER_INVALID_PADDING); } #endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */ @@ -1144,7 +1150,7 @@ int mbedtls_cipher_set_padding_mode(mbedtls_cipher_context_t *ctx, #if defined(MBEDTLS_CIPHER_PADDING_PKCS7) case MBEDTLS_PADDING_PKCS7: ctx->add_padding = add_pkcs_padding; - ctx->get_padding = get_pkcs_padding; + ctx->get_padding = mbedtls_get_pkcs_padding; break; #endif #if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) diff --git a/library/cipher_invasive.h b/library/cipher_invasive.h new file mode 100644 index 0000000000..702f8f73e9 --- /dev/null +++ b/library/cipher_invasive.h @@ -0,0 +1,27 @@ +/** + * \file cipher_invasive.h + * + * \brief Cipher module: interfaces for invasive testing only. + * + * The interfaces in this file are intended for testing purposes only. + * They SHOULD NOT be made available in library integrations except when + * building the library for testing. + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ +#ifndef MBEDTLS_CIPHER_INVASIVE_H +#define MBEDTLS_CIPHER_INVASIVE_H + +#include "common.h" + +#if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_CIPHER_C) + +MBEDTLS_STATIC_TESTABLE int mbedtls_get_pkcs_padding(unsigned char *input, + size_t input_len, + size_t *data_len); + +#endif + +#endif /* MBEDTLS_CIPHER_INVASIVE_H */ diff --git a/library/lmots.c b/library/lmots.c index c51cb41ece..404aa80da6 100644 --- a/library/lmots.c +++ b/library/lmots.c @@ -401,8 +401,11 @@ int mbedtls_lmots_import_public_key(mbedtls_lmots_public_t *ctx, return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; } - ctx->params.type = (mbedtls_lmots_algorithm_type_t) - MBEDTLS_GET_UINT32_BE(key, MBEDTLS_LMOTS_SIG_TYPE_OFFSET); + uint32_t type = MBEDTLS_GET_UINT32_BE(key, MBEDTLS_LMOTS_SIG_TYPE_OFFSET); + if (type != (uint32_t) MBEDTLS_LMOTS_SHA256_N32_W8) { + return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; + } + ctx->params.type = (mbedtls_lmots_algorithm_type_t) type; if (key_len != MBEDTLS_LMOTS_PUBLIC_KEY_LEN(ctx->params.type)) { return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; diff --git a/library/lms.c b/library/lms.c index 7f7bec068b..41d34bfe16 100644 --- a/library/lms.c +++ b/library/lms.c @@ -101,6 +101,9 @@ static int create_merkle_leaf_value(const mbedtls_lms_parameters_t *params, size_t output_hash_len; unsigned char r_node_idx_bytes[4]; + /* Always zeroize the output buffer because it may contain data from the previous invocation */ + memset(out, 0, MBEDTLS_LMS_M_NODE_BYTES(params->type)); + op = psa_hash_operation_init(); status = psa_hash_setup(&op, PSA_ALG_SHA_256); if (status != PSA_SUCCESS) { @@ -239,25 +242,25 @@ void mbedtls_lms_public_free(mbedtls_lms_public_t *ctx) int mbedtls_lms_import_public_key(mbedtls_lms_public_t *ctx, const unsigned char *key, size_t key_size) { - mbedtls_lms_algorithm_type_t type; - mbedtls_lmots_algorithm_type_t otstype; - - type = (mbedtls_lms_algorithm_type_t) MBEDTLS_GET_UINT32_BE(key, PUBLIC_KEY_TYPE_OFFSET); - if (type != MBEDTLS_LMS_SHA256_M32_H10) { + if (key_size < 4) { return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; } - ctx->params.type = type; + + uint32_t type = MBEDTLS_GET_UINT32_BE(key, PUBLIC_KEY_TYPE_OFFSET); + if (type != (uint32_t) MBEDTLS_LMS_SHA256_M32_H10) { + return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; + } + ctx->params.type = (mbedtls_lms_algorithm_type_t) type; if (key_size != MBEDTLS_LMS_PUBLIC_KEY_LEN(ctx->params.type)) { return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; } - otstype = (mbedtls_lmots_algorithm_type_t) - MBEDTLS_GET_UINT32_BE(key, PUBLIC_KEY_OTSTYPE_OFFSET); - if (otstype != MBEDTLS_LMOTS_SHA256_N32_W8) { + uint32_t otstype = MBEDTLS_GET_UINT32_BE(key, PUBLIC_KEY_OTSTYPE_OFFSET); + if (otstype != (uint32_t) MBEDTLS_LMOTS_SHA256_N32_W8) { return MBEDTLS_ERR_LMS_BAD_INPUT_DATA; } - ctx->params.otstype = otstype; + ctx->params.otstype = (mbedtls_lmots_algorithm_type_t) otstype; memcpy(ctx->params.I_key_identifier, key + PUBLIC_KEY_I_KEY_ID_OFFSET, @@ -374,12 +377,16 @@ int mbedtls_lms_verify(const mbedtls_lms_public_t *ctx, return MBEDTLS_ERR_LMS_VERIFY_FAILED; } - create_merkle_leaf_value( + ret = create_merkle_leaf_value( &ctx->params, Kc_candidate_ots_pub_key, MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) + q_leaf_identifier, Tc_candidate_root_node); + if (ret != 0) { + return MBEDTLS_ERR_LMS_VERIFY_FAILED; + } + curr_node_id = MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) + q_leaf_identifier; @@ -398,9 +405,11 @@ int mbedtls_lms_verify(const mbedtls_lms_public_t *ctx, height * MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type); } - create_merkle_internal_value(&ctx->params, left_node, right_node, - parent_node_id, Tc_candidate_root_node); - + ret = create_merkle_internal_value(&ctx->params, left_node, right_node, + parent_node_id, Tc_candidate_root_node); + if (ret != 0) { + return MBEDTLS_ERR_LMS_VERIFY_FAILED; + } curr_node_id /= 2; } diff --git a/library/pem.c b/library/pem.c index 0207601456..119fd59e12 100644 --- a/library/pem.c +++ b/library/pem.c @@ -243,7 +243,10 @@ exit: #if defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) static int pem_check_pkcs_padding(unsigned char *input, size_t input_len, size_t *data_len) { - /* input_len > 0 is guaranteed by mbedtls_pem_read_buffer(). */ + /* input_len > 0 is not guaranteed by mbedtls_pem_read_buffer(). */ + if (input_len < 1) { + return MBEDTLS_ERR_PEM_INVALID_DATA; + } size_t pad_len = input[input_len - 1]; size_t i; diff --git a/library/x509_create.c b/library/x509_create.c index 839b5df226..420e36b81b 100644 --- a/library/x509_create.c +++ b/library/x509_create.c @@ -292,8 +292,12 @@ int mbedtls_x509_string_to_names(mbedtls_asn1_named_data **head, const char *nam unsigned char data[MBEDTLS_X509_MAX_DN_NAME_SIZE]; size_t data_len = 0; - /* Clear existing chain if present */ - mbedtls_asn1_free_named_data_list(head); + /* Ensure the output parameter is not already populated. + * (If it were, overwriting it would likely cause a memory leak.) + */ + if (*head != NULL) { + return MBEDTLS_ERR_X509_BAD_INPUT_DATA; + } while (c <= end) { if (in_attr_type && *c == '=') { diff --git a/library/x509write_crt.c b/library/x509write_crt.c index 56f23c9fab..d829ffe602 100644 --- a/library/x509write_crt.c +++ b/library/x509write_crt.c @@ -84,12 +84,14 @@ void mbedtls_x509write_crt_set_issuer_key(mbedtls_x509write_cert *ctx, int mbedtls_x509write_crt_set_subject_name(mbedtls_x509write_cert *ctx, const char *subject_name) { + mbedtls_asn1_free_named_data_list(&ctx->subject); return mbedtls_x509_string_to_names(&ctx->subject, subject_name); } int mbedtls_x509write_crt_set_issuer_name(mbedtls_x509write_cert *ctx, const char *issuer_name) { + mbedtls_asn1_free_named_data_list(&ctx->issuer); return mbedtls_x509_string_to_names(&ctx->issuer, issuer_name); } diff --git a/library/x509write_csr.c b/library/x509write_csr.c index 0d6f6bb1d3..75bd8f044e 100644 --- a/library/x509write_csr.c +++ b/library/x509write_csr.c @@ -66,6 +66,7 @@ void mbedtls_x509write_csr_set_key(mbedtls_x509write_csr *ctx, mbedtls_pk_contex int mbedtls_x509write_csr_set_subject_name(mbedtls_x509write_csr *ctx, const char *subject_name) { + mbedtls_asn1_free_named_data_list(&ctx->subject); return mbedtls_x509_string_to_names(&ctx->subject, subject_name); } diff --git a/programs/x509/cert_req.c b/programs/x509/cert_req.c index 995ee499d5..38b7af0925 100644 --- a/programs/x509/cert_req.c +++ b/programs/x509/cert_req.c @@ -150,7 +150,6 @@ int main(int argc, char *argv[]) mbedtls_ctr_drbg_context ctr_drbg; const char *pers = "csr example app"; mbedtls_x509_san_list *cur, *prev; - mbedtls_asn1_named_data *ext_san_dirname = NULL; #if defined(MBEDTLS_X509_CRT_PARSE_C) uint8_t ip[4] = { 0 }; #endif @@ -274,7 +273,15 @@ usage: cur->node.san.unstructured_name.len = sizeof(ip); } else if (strcmp(q, "DN") == 0) { cur->node.type = MBEDTLS_X509_SAN_DIRECTORY_NAME; - if ((ret = mbedtls_x509_string_to_names(&ext_san_dirname, + /* Work around an API mismatch between string_to_names() and + * mbedtls_x509_subject_alternative_name, which holds an + * actual mbedtls_x509_name while a pointer to one would be + * more convenient here. (Note mbedtls_x509_name and + * mbedtls_asn1_named_data are synonymous, again + * string_to_names() uses one while + * cur->node.san.directory_name is nominally the other.) */ + mbedtls_asn1_named_data *tmp_san_dirname = NULL; + if ((ret = mbedtls_x509_string_to_names(&tmp_san_dirname, subtype_value)) != 0) { mbedtls_strerror(ret, buf, sizeof(buf)); mbedtls_printf( @@ -283,7 +290,9 @@ usage: (unsigned int) -ret, buf); goto exit; } - cur->node.san.directory_name = *ext_san_dirname; + cur->node.san.directory_name = *tmp_san_dirname; + mbedtls_free(tmp_san_dirname); + tmp_san_dirname = NULL; } else { mbedtls_free(cur); goto usage; @@ -492,7 +501,6 @@ exit: } mbedtls_x509write_csr_free(&req); - mbedtls_asn1_free_named_data_list(&ext_san_dirname); mbedtls_pk_free(&key); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); @@ -502,12 +510,21 @@ exit: cur = opt.san_list; while (cur != NULL) { - prev = cur; - cur = cur->next; - mbedtls_free(prev); + mbedtls_x509_san_list *next = cur->next; + /* Note: mbedtls_x509_free_subject_alt_name() is not what we want here. + * It's the right thing for entries that were parsed from a certificate, + * where pointers are to the raw certificate, but here all the + * pointers were allocated while parsing from a user-provided string. */ + if (cur->node.type == MBEDTLS_X509_SAN_DIRECTORY_NAME) { + mbedtls_x509_name *dn = &cur->node.san.directory_name; + mbedtls_free(dn->oid.p); + mbedtls_free(dn->val.p); + mbedtls_asn1_free_named_data_list(&dn->next); + } + mbedtls_free(cur); + cur = next; } - mbedtls_exit(exit_code); } #endif /* MBEDTLS_X509_CSR_WRITE_C && MBEDTLS_PK_PARSE_C && MBEDTLS_FS_IO && diff --git a/programs/x509/cert_write.c b/programs/x509/cert_write.c index 6fd1dce1fc..95f08b9127 100644 --- a/programs/x509/cert_write.c +++ b/programs/x509/cert_write.c @@ -312,7 +312,6 @@ int main(int argc, char *argv[]) mbedtls_ctr_drbg_context ctr_drbg; const char *pers = "crt example app"; mbedtls_x509_san_list *cur, *prev; - mbedtls_asn1_named_data *ext_san_dirname = NULL; uint8_t ip[4] = { 0 }; /* * Set to sane values @@ -595,7 +594,15 @@ usage: cur->node.san.unstructured_name.len = sizeof(ip); } else if (strcmp(q, "DN") == 0) { cur->node.type = MBEDTLS_X509_SAN_DIRECTORY_NAME; - if ((ret = mbedtls_x509_string_to_names(&ext_san_dirname, + /* Work around an API mismatch between string_to_names() and + * mbedtls_x509_subject_alternative_name, which holds an + * actual mbedtls_x509_name while a pointer to one would be + * more convenient here. (Note mbedtls_x509_name and + * mbedtls_asn1_named_data are synonymous, again + * string_to_names() uses one while + * cur->node.san.directory_name is nominally the other.) */ + mbedtls_asn1_named_data *tmp_san_dirname = NULL; + if ((ret = mbedtls_x509_string_to_names(&tmp_san_dirname, subtype_value)) != 0) { mbedtls_strerror(ret, buf, sizeof(buf)); mbedtls_printf( @@ -604,7 +611,9 @@ usage: (unsigned int) -ret, buf); goto exit; } - cur->node.san.directory_name = *ext_san_dirname; + cur->node.san.directory_name = *tmp_san_dirname; + mbedtls_free(tmp_san_dirname); + tmp_san_dirname = NULL; } else { mbedtls_free(cur); goto usage; @@ -995,10 +1004,26 @@ usage: exit_code = MBEDTLS_EXIT_SUCCESS; exit: + cur = opt.san_list; + while (cur != NULL) { + mbedtls_x509_san_list *next = cur->next; + /* Note: mbedtls_x509_free_subject_alt_name() is not what we want here. + * It's the right thing for entries that were parsed from a certificate, + * where pointers are to the raw certificate, but here all the + * pointers were allocated while parsing from a user-provided string. */ + if (cur->node.type == MBEDTLS_X509_SAN_DIRECTORY_NAME) { + mbedtls_x509_name *dn = &cur->node.san.directory_name; + mbedtls_free(dn->oid.p); + mbedtls_free(dn->val.p); + mbedtls_asn1_free_named_data_list(&dn->next); + } + mbedtls_free(cur); + cur = next; + } + #if defined(MBEDTLS_X509_CSR_PARSE_C) mbedtls_x509_csr_free(&csr); #endif /* MBEDTLS_X509_CSR_PARSE_C */ - mbedtls_asn1_free_named_data_list(&ext_san_dirname); mbedtls_x509_crt_free(&issuer_crt); mbedtls_x509write_crt_free(&crt); mbedtls_pk_free(&loaded_subject_key); diff --git a/tests/suites/test_suite_asn1write.function b/tests/suites/test_suite_asn1write.function index f5fc025f7d..b1e66ed901 100644 --- a/tests/suites/test_suite_asn1write.function +++ b/tests/suites/test_suite_asn1write.function @@ -550,6 +550,9 @@ void store_named_data_val_found(int old_len, int new_len) } if (new_len == 0) { TEST_ASSERT(found->val.p == NULL); + /* If new_len != 0, then new_val != NULL and the length has been checked + * above by TEST_MEMORY_COMPARE(). But not here, so we need to check. */ + TEST_EQUAL(found->val.len, 0); } else if (new_len == old_len) { TEST_ASSERT(found->val.p == old_val); } else { @@ -583,8 +586,10 @@ void store_named_data_val_new(int new_len, int set_new_val) TEST_MEMORY_COMPARE(found->oid.p, found->oid.len, oid, oid_len); if (new_len == 0) { TEST_ASSERT(found->val.p == NULL); + TEST_EQUAL(found->val.len, 0); } else if (new_val == NULL) { TEST_ASSERT(found->val.p != NULL); + TEST_EQUAL(found->val.len, new_len); } else { TEST_ASSERT(found->val.p != new_val); TEST_MEMORY_COMPARE(found->val.p, found->val.len, diff --git a/tests/suites/test_suite_base64.data b/tests/suites/test_suite_base64.data index 3999e73bf9..feed172d9c 100644 --- a/tests/suites/test_suite_base64.data +++ b/tests/suites/test_suite_base64.data @@ -76,6 +76,107 @@ mbedtls_base64_decode:"zm=masd":"":MBEDTLS_ERR_BASE64_INVALID_CHARACTER Base64 decode (Space inside string) mbedtls_base64_decode:"zm masd":"":MBEDTLS_ERR_BASE64_INVALID_CHARACTER +# The next few test cases validate systematically for short inputs that +# we require the correct number of trailing equal signs. + +# 4k+1 digits is always wrong (wouldn't encode more bytes than 4k digits) +Base64 decode: 1 digit, 0 equals (bad) +mbedtls_base64_decode:"Y":"":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 1 digit, 1 equals (bad) +mbedtls_base64_decode:"Y=":"":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 1 digit, 2 equals (bad) +mbedtls_base64_decode:"Y==":"":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 1 digit, 3 equals (bad) +mbedtls_base64_decode:"Y===":"":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 2 digits, 0 equals (bad) +mbedtls_base64_decode:"Yw":"c":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 2 digits, 1 equals (bad) +mbedtls_base64_decode:"Yw=":"c":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 2 digits, 2 equals (good) +mbedtls_base64_decode:"Yw==":"c":0 + +Base64 decode: 2 digits, 3 equals (bad) +mbedtls_base64_decode:"Yw===":"c":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 3 digits, 0 equals (bad) +mbedtls_base64_decode:"Y28":"co":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 3 digits, 1 equals (good) +mbedtls_base64_decode:"Y28=":"co":0 + +Base64 decode: 3 digits, 2 equals (bad) +mbedtls_base64_decode:"Y28==":"co":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 3 digits, 3 equals (bad) +mbedtls_base64_decode:"Y28===":"co":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 4 digits, 0 equals (good) +mbedtls_base64_decode:"Y29t":"com":0 + +Base64 decode: 4 digits, 1 equals (bad) +mbedtls_base64_decode:"Y29t=":"com":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 4 digits, 2 equals (bad) +mbedtls_base64_decode:"Y29t==":"com":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 4 digits, 3 equals (bad) +mbedtls_base64_decode:"Y29t===":"com":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +# 4k+1 digits is always wrong (wouldn't encode more bytes than 4k digits) +Base64 decode: 5 digits, 0 equals (bad) +mbedtls_base64_decode:"Y29tc":"":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 5 digits, 1 equals (bad) +mbedtls_base64_decode:"Y29tc=":"":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 5 digits, 2 equals (bad) +mbedtls_base64_decode:"Y29tc==":"":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 5 digits, 3 equals (bad) +mbedtls_base64_decode:"Y29tc===":"com":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 6 digits, 0 equals (bad) +mbedtls_base64_decode:"Y29tcA":"comp":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 6 digits, 1 equals (bad) +mbedtls_base64_decode:"Y29tcA=":"comp":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 6 digits, 2 equals (good) +mbedtls_base64_decode:"Y29tcA==":"comp":0 + +Base64 decode: 6 digits, 3 equals (bad) +mbedtls_base64_decode:"Y29tcA===":"comp":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 7 digits, 0 equals (bad) +mbedtls_base64_decode:"Y29tcG8":"compo":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 7 digits, 1 equals (good) +mbedtls_base64_decode:"Y29tcG8=":"compo":0 + +Base64 decode: 7 digits, 2 equals (bad) +mbedtls_base64_decode:"Y29tcG8==":"compo":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 7 digits, 3 equals (bad) +mbedtls_base64_decode:"Y29tcG8===":"compo":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 8 digits, 0 equals (good) +mbedtls_base64_decode:"Y29tcG9z":"compos":0 + +Base64 decode: 8 digits, 1 equals (bad) +mbedtls_base64_decode:"Y29tcG9z=":"compos":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 8 digits, 2 equals (bad) +mbedtls_base64_decode:"Y29tcG9z==":"compos":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + +Base64 decode: 8 digits, 3 equals (bad) +mbedtls_base64_decode:"Y29tcG9z===":"compos":MBEDTLS_ERR_BASE64_INVALID_CHARACTER + Base64 decode "Zm9vYmFy" (no newline nor '\0' at end) base64_decode_hex_src:"5a6d3976596d4679":"foobar":0 diff --git a/tests/suites/test_suite_base64.function b/tests/suites/test_suite_base64.function index e351ad8a25..095f980f3f 100644 --- a/tests/suites/test_suite_base64.function +++ b/tests/suites/test_suite_base64.function @@ -85,20 +85,67 @@ void mbedtls_base64_encode(char *src_string, char *dst_string, /* BEGIN_CASE */ void mbedtls_base64_decode(char *src_string, char *dst_string, int result) { - unsigned char src_str[1000]; - unsigned char dst_str[1000]; + unsigned char *src = NULL; + size_t src_len = strlen(src_string); + unsigned char *dst = NULL; + size_t correct_dst_len = strlen(dst_string); + size_t dst_size = correct_dst_len; size_t len; - int res; - memset(src_str, 0x00, 1000); - memset(dst_str, 0x00, 1000); - - strncpy((char *) src_str, src_string, sizeof(src_str) - 1); - res = mbedtls_base64_decode(dst_str, sizeof(dst_str), &len, src_str, strlen((char *) src_str)); - TEST_ASSERT(res == result); - if (result == 0) { - TEST_ASSERT(strcmp((char *) dst_str, dst_string) == 0); + /* Allocate exactly the size of the input, to ensure there's no buffer + * overread in builds with ASan. (src_string has at least one extra null + * character at the end.) */ + TEST_CALLOC(src, src_len); + if (src_len != 0) { + memcpy(src, src_string, src_len); } + + /* Allocate exactly the size of the input, to ensure there's no buffer + * overflow in builds with ASan. */ + TEST_CALLOC(dst, dst_size); + + /* Test normal operation */ + TEST_EQUAL(mbedtls_base64_decode(dst, dst_size, &len, + src, src_len), + result); + if (result == 0) { + TEST_MEMORY_COMPARE(dst_string, correct_dst_len, dst, len); + } + + /* Test an output buffer that's one byte too small */ + if (result == 0 && dst_size != 0) { + mbedtls_free(dst); + dst = NULL; + TEST_CALLOC(dst, dst_size - 1); + TEST_EQUAL(mbedtls_base64_decode(dst, dst_size - 1, &len, + src, src_len), + MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL); + TEST_EQUAL(correct_dst_len, len); + } + + /* Test an empty output buffer. `mbedtls_base64_decode()` must return + * `BUFFER_TOO_SMALL` but report the correct output length. + * Skip this when dst_size==0 since that would be a valid call to + * `mbedtls_base64_decode()` which should return 0. + */ + if (result == 0 && dst_size != 0) { + TEST_EQUAL(mbedtls_base64_decode(NULL, 0, &len, + src, src_len), + MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL); + TEST_EQUAL(correct_dst_len, len); + } + + /* Test dst=NULL with dlen!=0 (explicitly documented as supported) */ + if (result == 0 && dst_size != 0) { + TEST_EQUAL(mbedtls_base64_decode(NULL, 42, &len, + src, src_len), + MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL); + TEST_EQUAL(correct_dst_len, len); + } + +exit: + mbedtls_free(src); + mbedtls_free(dst); } /* END_CASE */ diff --git a/tests/suites/test_suite_cipher.function b/tests/suites/test_suite_cipher.function index 040c35ca58..2856ae5699 100644 --- a/tests/suites/test_suite_cipher.function +++ b/tests/suites/test_suite_cipher.function @@ -6,6 +6,10 @@ #include "mbedtls/gcm.h" #endif +#include "cipher_invasive.h" + +#include "test/constant_flow.h" + #if defined(MBEDTLS_CIPHER_HAVE_SOME_AEAD_VIA_LEGACY_OR_USE_PSA) || defined(MBEDTLS_NIST_KW_C) #define MBEDTLS_CIPHER_AUTH_CRYPT #endif @@ -1260,3 +1264,20 @@ exit: mbedtls_free(key); } /* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_TEST_HOOKS */ +void get_pkcs_padding(data_t *decrypted_block, int exp_ret, int exp_len) +{ + int ret; + size_t calculated_len; + + TEST_CF_SECRET(decrypted_block->x, decrypted_block->len); + ret = mbedtls_get_pkcs_padding(decrypted_block->x, decrypted_block->len, + &calculated_len); + + TEST_EQUAL(ret, exp_ret); + if (exp_ret == 0) { + TEST_EQUAL(calculated_len, exp_len); + } +} +/* END_CASE */ diff --git a/tests/suites/test_suite_cipher.padding.data b/tests/suites/test_suite_cipher.padding.data index 0370fb3d28..85b14c1f2f 100644 --- a/tests/suites/test_suite_cipher.padding.data +++ b/tests/suites/test_suite_cipher.padding.data @@ -217,3 +217,18 @@ check_padding:MBEDTLS_PADDING_NONE:"DABBAD0001":0:5 Check no padding #3 (correct by definition) check_padding:MBEDTLS_PADDING_NONE:"":0:0 + +Constant-time PKCS7 padding, valid #1 +get_pkcs_padding:"00112233445566778899AABBCCDDEE01":0:15 + +Constant-time PKCS7 padding, valid #2 +get_pkcs_padding:"00112233445566778899AA0505050505":0:11 + +Constant-time PKCS7 padding, valid #3 +get_pkcs_padding:"10101010101010101010101010101010":0:0 + +Constant-time PKCS7 padding, invalid zero +get_pkcs_padding:"00112233445566778899AABBCCDDEE00":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +Constant-time PKCS7 padding, invalid > 16 +get_pkcs_padding:"00112233445566778899AABBCCDDEE11":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 diff --git a/tests/suites/test_suite_lms.data b/tests/suites/test_suite_lms.data index 16ebd1d217..5601cce92c 100644 --- a/tests/suites/test_suite_lms.data +++ b/tests/suites/test_suite_lms.data @@ -186,6 +186,13 @@ LMS hsslms interop test #2 # print('lms_verify_test:"{}":"{}":"{}":0'.format(message.hex(), sig.hex(), public_key.get_pubkey().hex())) lms_verify_test:"92d036bde8c45b8bb5dea2a072560b1e29fc4bb7dc4549ce90bccee8a6e962a1":"00000001000000042e758f2a0e8f301af58847b6973a15fe4856b91af88a1ff601e2f0e87bde33afbc39202a66e38931fbecd7d493cf957b37eeb57ed2e4d8f693b97adafa8241746d775cfb9471688d935e090581eb8586e7004d6b8855963d82ccb6f79df2d93dd35848556da6735def0f0c6c8fc969c1df692341f6a99626eff37d20226cef361c8802a995fa43535fe2336d8ae468c78eb6a7082e27c2c6317c034369b588e3d65a2eeac9804b427702dc49f681a841076813ed407399aa778259e7c34c750baa6d296a384e1274facaba9e2214d197628f5df7b2bf3896fedeab377b8edb775d6e8d67f1474ba3066794447f8f8e0c13552a007557a1f1c3b9bd2b41d9b446c6bcf36c828fd4c80850a31ee603065f5cc90d198df03835195b14e27da7bf727a16081fcc787f1dc7fa6da8b9ff908fb2c02d6f2a183486de0e39cd7da7fcdee0c8e96876c56ad9b0b18e4e4999e2c81a618aa4b27e050ce488dbb1e79089131afacc446cdf15b625f4e011f8d8160bb93f326bca3bb56fa41e34893d55f17d746fc142297997c5dbbba8f6b6c80678168ba455f12bac6982e5192de5462a46e14a45a01ce9e07279aa301dfd0fa9a12c6a55059b19a19d7afbe99779ea130ddeeb5ecb67d2ddb6c1c5d198e421b78091efa5aa429e1eb052760c0d8e2eb0c0ced000e93f7f265611a385f77c0cece0496eb29010f710e70a768d3713f0b7fc60c8ce372dc3234f27c7a1c2776a939ef70c7be869337b967df2223d4f20dca697e3bb6d0e53bbad153ff08d579f60c8535710f253b90e73ee9a19e1e57df66ec6c85ad1b4cea28a9d62fc5a4cf130f70b910dbc7e6f0e6b0cce1a1b5ff106b7f0b101405c0989084b2c94977116b98d15d6062a8d77d660aa813d432cf3338484308b7beed10236081f52da44eb807f9a75fd4cc1ba998ef3fc2e4791712597c786dd46431468bb4a1975a6cd854a1da23912fc99160f51df484efc9371c2d8e028d9468635cf93226f5a8834d14cead59e5d2a61dd6440d7b91c903ae8823907b75595c4828c7710036b347dcfb67f8561e835a53f569c8b3a1cd4317b2a6b2243100ee3d9468f9191acf2276d18dde9ebf2e11a48ba1fc1a15dc51091d3358d8d1f65ec7d84b97bb1669a9141f74065454f08e5ef25432b7635b8ec673ca70e4b3c25d07975a6fb725a56f28c1b5a81a6da2fe0a2c3474275926f9819a25b942462a68097e1cf6d9ae94f6b1f76b54addaeda04f9fc8db025fd6c453e1ad928f9323bf1381fce1893938828612728185d22a3d45d21ce762c066ab53a582c487d76d431e5b8f65a382142dd823d4620931e5572a4e6aee69986421afa119634bc8ea88aa6535c4d619ca0e0af94934637bc0c834e5e2a7a2853fa73835d00e13e5f26ad085ef66c8efb60097860cb199e03596a3b8f0ec78690d527bbc9363dd9702226788b1529871df74918ae2a4e02745043bd5ee8ab027826fb4cd54b0c27d99076757a1b41e2725ec02adc7926e8213796a8aa1740a2dc675437771e0364a83b0bd64c9620f6c203d92626ff29ef736eac0e13c71fd1957333ee0048000000061f7b7d6f916710efe9ed625ae689c67b3cc1cdf0d672e58c0b86b3839bbba2c243dcda2e63b26f5efa39ced6095a54625e67ab25d3df068e903eaaee894ac0f1fdeb4a2f1390f655db3608583eacfb0be4282f7bd1c42c5d748d524d7cdcd45878dea56cbc11a63bebbd74a5413ce72a931b1d4794c78c4cf16315bf2e055bb3305fe0272c8b916856cc27aa7a773ddce62afa7bb4da76c287e0ed3ed10452512de82c051f17b49c608b1a259e16a3812c0de684f2cb1ee59296c375376f146e2b0cc299ef41ed8e6fdf0557ec8d95fa026970f8d47c8347fed1e37e018413c5e813d1726ea18bc926ed02840349ab3b2adc8758a9cd57be38e9e76869762a81bb79721ca1c031c9dfdc3735fe9318064b62c2a7e8e2ec099963257b0705aac812dbc8cc3fbeea81af7c0d592c7e2ad1c21e877d4ae392b13ac1b57a8311d406":"000000060000000447cc5b29dd0cecd01c382434a6d16864d51b60cdb2a9eed2419015d8524c717ce38a865d7a37da6c84f94621ad595f5d":0 +LMS negative test (corrupt Merkle path byte) +# Corrupt one byte at index 200 in the Merkle authentication path to force internal failure. +# The test modifies a valid test's data so that the left_node parameter of create_merkle_internal_value becomes invalid. +# Since that corrupted data is not used by mbedtls_lms_verify before that invocation, +# the test targets the check of the value returned by create_merkle_internal_value. +lms_verify_test:"92d036bde8c45b8bb5dea2a072560b1e29fc4bb7dc4549ce90bccee8a6e962a1":"00000001000000042e758f2a0e8f301af58847b6973a15fe4856b91af88a1ff601e2f0e87bde33afbc39202a66e38931fbecd7d493cf957b37eeb57ed2e4d8f693b97adafa8241746d775cfb9471688d935e090581eb8586e7004d6b8855963d82ccb6f79df2d93dd35848556da6735def0f0c6c8fc969c1df692341f6a99626eff37d20226cef361c8802a995fa43535fe2336d8ae468c78eb6a7082e27c2c6317c034369b588e3d65a2eeac9804b427702dc49f681a841076813ed407399aa778259e7c34c750b556d296a384e1274facaba9e2214d197628f5df7b2bf3896fedeab377b8edb775d6e8d67f1474ba3066794447f8f8e0c13552a007557a1f1c3b9bd2b41d9b446c6bcf36c828fd4c80850a31ee603065f5cc90d198df03835195b14e27da7bf727a16081fcc787f1dc7fa6da8b9ff908fb2c02d6f2a183486de0e39cd7da7fcdee0c8e96876c56ad9b0b18e4e4999e2c81a618aa4b27e050ce488dbb1e79089131afacc446cdf15b625f4e011f8d8160bb93f326bca3bb56fa41e34893d55f17d746fc142297997c5dbbba8f6b6c80678168ba455f12bac6982e5192de5462a46e14a45a01ce9e07279aa301dfd0fa9a12c6a55059b19a19d7afbe99779ea130ddeeb5ecb67d2ddb6c1c5d198e421b78091efa5aa429e1eb052760c0d8e2eb0c0ced000e93f7f265611a385f77c0cece0496eb29010f710e70a768d3713f0b7fc60c8ce372dc3234f27c7a1c2776a939ef70c7be869337b967df2223d4f20dca697e3bb6d0e53bbad153ff08d579f60c8535710f253b90e73ee9a19e1e57df66ec6c85ad1b4cea28a9d62fc5a4cf130f70b910dbc7e6f0e6b0cce1a1b5ff106b7f0b101405c0989084b2c94977116b98d15d6062a8d77d660aa813d432cf3338484308b7beed10236081f52da44eb807f9a75fd4cc1ba998ef3fc2e4791712597c786dd46431468bb4a1975a6cd854a1da23912fc99160f51df484efc9371c2d8e028d9468635cf93226f5a8834d14cead59e5d2a61dd6440d7b91c903ae8823907b75595c4828c7710036b347dcfb67f8561e835a53f569c8b3a1cd4317b2a6b2243100ee3d9468f9191acf2276d18dde9ebf2e11a48ba1fc1a15dc51091d3358d8d1f65ec7d84b97bb1669a9141f74065454f08e5ef25432b7635b8ec673ca70e4b3c25d07975a6fb725a56f28c1b5a81a6da2fe0a2c3474275926f9819a25b942462a68097e1cf6d9ae94f6b1f76b54addaeda04f9fc8db025fd6c453e1ad928f9323bf1381fce1893938828612728185d22a3d45d21ce762c066ab53a582c487d76d431e5b8f65a382142dd823d4620931e5572a4e6aee69986421afa119634bc8ea88aa6535c4d619ca0e0af94934637bc0c834e5e2a7a2853fa73835d00e13e5f26ad085ef66c8efb60097860cb199e03596a3b8f0ec78690d527bbc9363dd9702226788b1529871df74918ae2a4e02745043bd5ee8ab027826fb4cd54b0c27d99076757a1b41e2725ec02adc7926e8213796a8aa1740a2dc675437771e0364a83b0bd64c9620f6c203d92626ff29ef736eac0e13c71fd1957333ee0048000000061f7b7d6f916710efe9ed625ae689c67b3cc1cdf0d672e58c0b86b3839bbba2c243dcda2e63b26f5efa39ced6095a54625e67ab25d3df068e903eaaee894ac0f1fdeb4a2f1390f655db3608583eacfb0be4282f7bd1c42c5d748d524d7cdcd45878dea56cbc11a63bebbd74a5413ce72a931b1d4794c78c4cf16315bf2e055bb3305fe0272c8b916856cc27aa7a773ddce62afa7bb4da76c287e0ed3ed10452512de82c051f17b49c608b1a259e16a3812c0de684f2cb1ee59296c375376f146e2b0cc299ef41ed8e6fdf0557ec8d95fa026970f8d47c8347fed1e37e018413c5e813d1726ea18bc926ed02840349ab3b2adc8758a9cd57be38e9e76869762a81bb79721ca1c031c9dfdc3735fe9318064b62c2a7e8e2ec099963257b0705aac812dbc8cc3fbeea81af7c0d592c7e2ad1c21e877d4ae392b13ac1b57a8311d406":"000000060000000447cc5b29dd0cecd01c382434a6d16864d51b60cdb2a9eed2419015d8524c717ce38a865d7a37da6c84f94621ad595f5d":MBEDTLS_ERR_LMS_VERIFY_FAILED + LMS negative test (invalid lms type) #1 # This test uses the data from hash-sigs interop test #1. This test has a valid # LMOTS type (0x4) but an invalid LMS type (0x5), and should fail. @@ -212,6 +219,12 @@ LMS negative test (invalid leaf ID) # test should fail to verify the signature. lms_verify_test:"bfff9cd687351db88a98c71fd2f9b927a0ee600130a112533b791041d30cb91665fc369a5ac7cc9a04547414ac45288081d19d4a600579c73ac4bc953de03ad6":"0000040000000004e474c96c496b231ecedcd92566ab3e1cdfac83f7e56abaae6571401e212e59bdbcc18105e0709249510d13d7ae1091558c217033316ac70a36aae764bd0f4032e369453c634b81061079d216d03d3c55976a1aabc00287b307297ae03587ba20839460daae85d26dfcef7638c10a1d8559612e5e9ced1a4205a52ca0ce88e58602e59cf9ab34adf2e958e56570573297b99f733fbbf58d2440526fd4dc15c5509e8a11405f6c08772abcf58731fbf9a73642670e3247c5f70905f0fa81f6174bf32977209923507525a170fcd260e81f04193583fbcd305ac245c80eb337ca326fd1105e73748fab8a1f0c8d8a99f011718e7aae027a34d2a85ff18769fa277810126a86b51b096a04d8e28a4fb8c5e14e50a67cb1ee88e43e5cc077902442f5d9c55ac2b8acdd76c67bc740c6083aba4e3cb404c23f1f3118337563fef6a4b01fb476810c5b5682d0aecdccd55c85a4af50e9150f7d83dcccd8e822a302e6e5a52e00505e6e65338dcfb9cfbe22594e9e18ebde36af29450c5ea31523019cf64fd6eca8c77d98c2a146dcedd51bf6c61c1f7cacbce3ab20c8606930cc42737e17f2703cf0980aef560768d1ac5585c05a60a5f94db15f5ac4d4df5cbd81430878d4e9b77346e3a6538b80b80873e3e6c37860470091979296631440adb8cc71991aba2a4dd2884764878306fe774a25512cfbf080f2829ea2903ffa748dd187c21aef918ee3436a1bd336c3d09cc1f748d7528db90a98f69078b82c4d23de7bcec092a292d2b8cac71a5c87d008f128b89a5e608a4501aef41e9f17e4056ed4767957188f780159daebf327751386980b0fca5a2d36b141acff957f46ce2381897099619475db9d3a613e7ef98b056f42b4d6eafb1d62eebbe46a7502f893fbd36ccfb12a280f45ffb93f050eb280bf0a6cd640abdea8590bffb98bdb29ee3a31daa0fa3ab35fee11dc1b7d1fcea82b0e284b2e35b34e77c3f401ed887e7fc6c97b327f76f99caca2f355afa2753a8923bfb06fb2a9df08d31c93882e34ef5a3cccc9d078855334bdf909ae418b177724c42fb1d586d212c4474932acce295236030f4379158957300fe9fdc5cc9145e3ded50cf9f5a8e19321961536c4a47fffc3eb4383fb78a5d2aeed5b45b92132b5e2a53e3b67841fa2e1bd217ee2c30812c4eb1bd4f8c85b328e23d27f12a2fad5c6b236c87f8fd1aad441416e53ebd4d45d4bf601b94eb37dc9a065218ae58e69dba1250bb20626baeda961b3ef11d217697e73f41fa3870d726a032bc4a388fb12c023822945df058e22f54e5f6377eab34297c57883515204fc189d0d4b0ad9bacb24acf7f9d55e7c6368bb8ababd7622f586ec22683306c5d88d5244219a3952adbd85c89893a441a58b532e15600cd5afdbb5b441e1670b72656c7995189bdf993154e09912db8c4ddaff0e75591720230cf99c8b71cd841dffc4372c5e0f9ff906a379d28d6884351609bf7c849ebfabfb049ae986bbb8467251dbf5ccdd05a86ff6ce1392f7ca1bd49595ad9ad805d71b389afab1865f7f69dc24662af19934f025ced212536509500c132aec000000068b991bed50319a6cb9ff040b92f1563889b3787c37145fc9737d4643f66ade33ebd85a2c29b8c64a581cff01b89d59807d6fade2d2c88872f77d0ed83d97c4b5438681d0b95feb973125e4ee70ebe11699290b831e86571e36513a71f159d48ce563f6814cc2a89851d2520c5275b34cc83614cab14c0d197166580d800ee6b9004b8fd72daac8d73c36c1623c37be93ba49a06c4efde238a3a10a05daba5d4942f7de52648af2be31f33e723b3605346282f5d5e356c5d0004eea40fe0b80abf658f6c96c56319ab53d7fefb5879e0136d1cf320973a2f47c1ee3d21554910f09d17afac4607657c4309890957a4954bf86e2a8491ba37dd88b2c3fe3c7edebd767c400bc23e40d165b27133c726b90bc26cbb2a86a6aa400c47aa7ffc538388de8490b9349afa53b814ffe2a56ff16a496e9648284193754f989f6f12aeb6e":"0000000600000004d96bb26744d99ef624e32161c36d3d6efcdd0484e2b17a6dd183125be4b1af1cda931a91a3acb1151877c174f7943fd9":MBEDTLS_ERR_LMS_VERIFY_FAILED +LMS public key import: truncated input below minimum valid size +# This test provides an input buffer that is one byte shorter than the minimum required +# size (MBEDTLS_LMS_TYPE_LEN - 1). The import operation is expected to fail gracefully, +# without attempting to read beyond the end of the buffer. +lms_import_export_test:"000000":MBEDTLS_ERR_LMS_BAD_INPUT_DATA + LMS import/export test # This test uses the key from hsslms interop test 1, imports it, exports it and # tests that it is the same. It also checks if the export correctly fail when diff --git a/tests/suites/test_suite_pem.data b/tests/suites/test_suite_pem.data index 007ba104a9..11c54b7cfc 100644 --- a/tests/suites/test_suite_pem.data +++ b/tests/suites/test_suite_pem.data @@ -49,10 +49,22 @@ PEM read (malformed PEM DES-EDE3-CBC) depends_on:MBEDTLS_MD_CAN_MD5:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC mbedtls_pem_read_buffer:"-----BEGIN EC PRIVATE KEY-----":"-----END EC PRIVATE KEY-----":"-----BEGIN EC PRIVATE KEY-----\nProc-Type\: 4,ENCRYPTED\nDEK-Info\: DES-EDE3-CBC,AA94892A169FA426\n\nMAAA\n-----END EC PRIVATE KEY-----":"pwd":MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH:"" -PEM read (malformed PEM AES-128-CBC) +PEM read (malformed PEM AES-128-CBC: 3-byte ciphertext) depends_on:MBEDTLS_MD_CAN_MD5:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC mbedtls_pem_read_buffer:"-----BEGIN EC PRIVATE KEY-----":"-----END EC PRIVATE KEY-----":"-----BEGIN EC PRIVATE KEY-----\nProc-Type\: 4,ENCRYPTED\nDEK-Info\: AES-128-CBC,AA94892A169FA426AA94892A169FA426\n\nMAAA\n-----END EC PRIVATE KEY-----":"pwd":MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH:"" +PEM read (malformed PEM AES-128-CBC: 1-byte ciphertext) +depends_on:MBEDTLS_MD_CAN_MD5:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC +mbedtls_pem_read_buffer:"-----BEGIN EC PRIVATE KEY-----":"-----END EC PRIVATE KEY-----":"-----BEGIN EC PRIVATE KEY-----\nProc-Type\: 4,ENCRYPTED\nDEK-Info\: AES-128-CBC,7BA38DE00F67851E4207216809C3BB15\n\n8Q==-----END EC PRIVATE KEY-----":"pwd":MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH:"" + +PEM read (malformed PEM AES-128-CBC: empty ciphertext) +depends_on:MBEDTLS_MD_CAN_MD5:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC +mbedtls_pem_read_buffer:"-----BEGIN EC PRIVATE KEY-----":"-----END EC PRIVATE KEY-----":"-----BEGIN EC PRIVATE KEY-----\nProc-Type\: 4,ENCRYPTED\nDEK-Info\: AES-128-CBC,7BA38DE00F67851E4207216809C3BB15\n\n-----END EC PRIVATE KEY-----":"pwd":MBEDTLS_ERR_PEM_BAD_INPUT_DATA:"" + +PEM read (malformed PEM AES-128-CBC: base64 with missing equals) +depends_on:MBEDTLS_MD_CAN_MD5:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC +mbedtls_pem_read_buffer:"-----BEGIN EC PRIVATE KEY-----":"-----END EC PRIVATE KEY-----":"-----BEGIN EC PRIVATE KEY-----\nProc-Type\: 4,ENCRYPTED\nDEK-Info\: AES-128-CBC,7BA38DE00F67851E4207216809C3BB15\n\n8Q-----END EC PRIVATE KEY-----":"pwd":MBEDTLS_ERR_PEM_INVALID_DATA + MBEDTLS_ERR_BASE64_INVALID_CHARACTER:"" + # The output sequence's length is not multiple of block size (16 bytes). This # proves that the pem_context->len value is properly updated based on the SEQUENCE # length read from the decoded ASN.1 data (i.e. extra padding, if any, is ignored). diff --git a/tests/suites/test_suite_pem.function b/tests/suites/test_suite_pem.function index 091cbd15e5..342ca52f22 100644 --- a/tests/suites/test_suite_pem.function +++ b/tests/suites/test_suite_pem.function @@ -15,16 +15,16 @@ void mbedtls_pem_write_buffer(char *start, char *end, data_t *buf, ret = mbedtls_pem_write_buffer(start, end, buf->x, buf->len, NULL, 0, &olen); - TEST_ASSERT(ret == MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL); + TEST_EQUAL(ret, MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL); check_buf = (unsigned char *) mbedtls_calloc(1, olen); TEST_ASSERT(check_buf != NULL); ret = mbedtls_pem_write_buffer(start, end, buf->x, buf->len, check_buf, olen, &olen2); - TEST_ASSERT(olen2 <= olen); - TEST_ASSERT(olen > strlen((char *) result_str)); - TEST_ASSERT(ret == 0); + TEST_LE_U(olen2, olen); + TEST_LE_U(strlen((char *) result_str) + 1, olen); + TEST_EQUAL(ret, 0); TEST_ASSERT(strncmp((char *) check_buf, (char *) result_str, olen) == 0); exit: @@ -76,15 +76,14 @@ void mbedtls_pem_read_buffer(char *header, char *footer, char *data, ret = mbedtls_pem_read_buffer(&ctx, header, footer, (unsigned char *) data, (unsigned char *) pwd, pwd_len, &use_len); - TEST_ASSERT(ret == res); + TEST_EQUAL(ret, res); if (ret != 0) { goto exit; } use_len = 0; buf = mbedtls_pem_get_buffer(&ctx, &use_len); - TEST_EQUAL(use_len, out->len); - TEST_ASSERT(memcmp(out->x, buf, out->len) == 0); + TEST_MEMORY_COMPARE(out->x, out->len, buf, use_len); exit: mbedtls_pem_free(&ctx); diff --git a/tests/suites/test_suite_version.data b/tests/suites/test_suite_version.data index bdf6fa071a..a45f3531fd 100644 --- a/tests/suites/test_suite_version.data +++ b/tests/suites/test_suite_version.data @@ -1,8 +1,8 @@ Check compile time library version -check_compiletime_version:"3.6.3" +check_compiletime_version:"3.6.4" Check runtime library version -check_runtime_version:"3.6.3" +check_runtime_version:"3.6.4" Check for MBEDTLS_VERSION_C check_feature:"MBEDTLS_VERSION_C":0 diff --git a/tests/suites/test_suite_x509write.data b/tests/suites/test_suite_x509write.data index 0cbad4bcee..56af0ce8a8 100644 --- a/tests/suites/test_suite_x509write.data +++ b/tests/suites/test_suite_x509write.data @@ -254,6 +254,27 @@ mbedtls_x509_string_to_names:"C=NL, O=Of\\CCspark, OU=PolarSSL":"C=NL, O=Of\\CCs X509 String to Names #20 (Reject empty AttributeValue) mbedtls_x509_string_to_names:"C=NL, O=, OU=PolarSSL":"":MBEDTLS_ERR_X509_INVALID_NAME:0 +# Note: the behaviour is incorrect, output from string->names->string should be +# the same as the input, rather than just the last component, see +# https://github.com/Mbed-TLS/mbedtls/issues/10189 +# Still including tests for the current incorrect behaviour because of the +# variants below where we want to ensure at least that no memory corruption +# happens (which would be a lot worse than just a functional bug). +X509 String to Names (repeated OID) +mbedtls_x509_string_to_names:"CN=ab,CN=cd,CN=ef":"CN=ef":0:0 + +# Note: when a value starts with a # sign, it's treated as the hex encoding of +# the DER encoding of the value. Here, 0400 is a zero-length OCTET STRING. +# The tag actually doesn't matter for our purposes, only the length. +X509 String to Names (repeated OID, 1st is zero-length) +mbedtls_x509_string_to_names:"CN=#0400,CN=cd,CN=ef":"CN=ef":0:0 + +X509 String to Names (repeated OID, middle is zero-length) +mbedtls_x509_string_to_names:"CN=ab,CN=#0400,CN=ef":"CN=ef":0:0 + +X509 String to Names (repeated OID, last is zero-length) +mbedtls_x509_string_to_names:"CN=ab,CN=cd,CN=#0400":"CN=#0000":0:MAY_FAIL_GET_NAME + X509 Round trip test (Escaped characters) mbedtls_x509_string_to_names:"CN=Lu\\C4\\8Di\\C4\\87, O=Offspark, OU=PolarSSL":"CN=Lu\\C4\\8Di\\C4\\87, O=Offspark, OU=PolarSSL":0:0 diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function index 81816fe63f..a22c486def 100644 --- a/tests/suites/test_suite_x509write.function +++ b/tests/suites/test_suite_x509write.function @@ -731,6 +731,11 @@ void mbedtls_x509_string_to_names(char *name, char *parsed_name, TEST_LE_S(1, ret); TEST_ASSERT(strcmp((char *) out, parsed_name) == 0); + /* Check that calling a 2nd time with the same param (now non-NULL) + * returns an error as expected. */ + ret = mbedtls_x509_string_to_names(&names, name); + TEST_EQUAL(ret, MBEDTLS_ERR_X509_BAD_INPUT_DATA); + exit: mbedtls_asn1_free_named_data_list(&names);