Merge pull request #1381 from Mbed-TLS/mbedtls-3.6.4-mergeback
Mbedtls 3.6.4 merge-back pr
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c981ef7..c3eb9c1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -40,12 +40,12 @@
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 @@
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 5cadd2b..4d4bbdb 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 1aea653..0000000
--- 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 b84e6d3..0000000
--- 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 a63e1eb..0000000
--- 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 75a72ca..0000000
--- 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 f903d3f..200db75 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 0acead9..2918f45 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 e70c4d7..e18e823 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 453f598..6b10461 100644
--- a/include/mbedtls/x509.h
+++ b/include/mbedtls/x509.h
@@ -332,7 +332,8 @@
* 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 e2a1920..b2c21fa 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -300,7 +300,7 @@
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 @@
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 4fc1cb9..2857068 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 775a9ef..97f9db0 100644
--- a/library/asn1write.c
+++ b/library/asn1write.c
@@ -90,7 +90,9 @@
len = size;
(*p) -= len;
- memcpy(*p, buf, len);
+ if (len != 0) {
+ memcpy(*p, buf, len);
+ }
return (int) len;
}
@@ -412,6 +414,7 @@
} 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 9677dee..388fa9f 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 <stdint.h>
@@ -183,49 +184,72 @@
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 7f4c121..2ae01dd 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 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 @@
}
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 @@
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 @@
#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 0000000..702f8f7
--- /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 c51cb41..404aa80 100644
--- a/library/lmots.c
+++ b/library/lmots.c
@@ -401,8 +401,11 @@
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 7f7bec0..41d34bf 100644
--- a/library/lms.c
+++ b/library/lms.c
@@ -101,6 +101,9 @@
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 @@
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 @@
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 @@
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 0207601..119fd59 100644
--- a/library/pem.c
+++ b/library/pem.c
@@ -243,7 +243,10 @@
#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 839b5df..420e36b 100644
--- a/library/x509_create.c
+++ b/library/x509_create.c
@@ -292,8 +292,12 @@
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 56f23c9..d829ffe 100644
--- a/library/x509write_crt.c
+++ b/library/x509write_crt.c
@@ -84,12 +84,14 @@
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 0d6f6bb..75bd8f0 100644
--- a/library/x509write_csr.c
+++ b/library/x509write_csr.c
@@ -66,6 +66,7 @@
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 995ee49..38b7af0 100644
--- a/programs/x509/cert_req.c
+++ b/programs/x509/cert_req.c
@@ -150,7 +150,6 @@
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 @@
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 @@
(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 @@
}
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 @@
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 6fd1dce..95f08b9 100644
--- a/programs/x509/cert_write.c
+++ b/programs/x509/cert_write.c
@@ -312,7 +312,6 @@
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 @@
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 @@
(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 @@
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 f5fc025..b1e66ed 100644
--- a/tests/suites/test_suite_asn1write.function
+++ b/tests/suites/test_suite_asn1write.function
@@ -550,6 +550,9 @@
}
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 @@
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 3999e73..feed172 100644
--- a/tests/suites/test_suite_base64.data
+++ b/tests/suites/test_suite_base64.data
@@ -76,6 +76,107 @@
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 e351ad8..095f980 100644
--- a/tests/suites/test_suite_base64.function
+++ b/tests/suites/test_suite_base64.function
@@ -85,20 +85,67 @@
/* 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 040c35c..2856ae5 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 @@
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 0370fb3..85b14c1 100644
--- a/tests/suites/test_suite_cipher.padding.data
+++ b/tests/suites/test_suite_cipher.padding.data
@@ -217,3 +217,18 @@
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 16ebd1d..5601cce 100644
--- a/tests/suites/test_suite_lms.data
+++ b/tests/suites/test_suite_lms.data
@@ -186,6 +186,13 @@
# 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 @@
# 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 007ba10..11c54b7 100644
--- a/tests/suites/test_suite_pem.data
+++ b/tests/suites/test_suite_pem.data
@@ -49,10 +49,22 @@
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 091cbd1..342ca52 100644
--- a/tests/suites/test_suite_pem.function
+++ b/tests/suites/test_suite_pem.function
@@ -15,16 +15,16 @@
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 @@
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 bdf6fa0..a45f353 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 0cbad4b..56af0ce 100644
--- a/tests/suites/test_suite_x509write.data
+++ b/tests/suites/test_suite_x509write.data
@@ -254,6 +254,27 @@
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 81816fe..a22c486 100644
--- a/tests/suites/test_suite_x509write.function
+++ b/tests/suites/test_suite_x509write.function
@@ -731,6 +731,11 @@
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);