Mbed-TLS/mbedtls

mbedtls_ecp_muladd hangs with oversized point coordinates

guidovranken opened this issue · 4 comments

Summary

mbedtls_ecp_muladd hangs with oversized point coordinates (>= curve order).

System information

Mbed TLS version (number or commit id): acc74b8
Operating system and version: Ubuntu Linux 64 bit
Configuration (if not default, please attach mbedtls_config.h):
Compiler and options (if you used a pre-built binary, please indicate how you obtained it):

export CC=clang
export CXX=clang++
git clone --depth 1 -b development_2.x https://github.com/ARMmbed/mbedtls.git
cd mbedtls/
scripts/config.pl set MBEDTLS_PLATFORM_MEMORY
scripts/config.pl set MBEDTLS_CMAC_C
scripts/config.pl set MBEDTLS_NIST_KW_C
scripts/config.pl set MBEDTLS_ARIA_C
scripts/config.pl set MBEDTLS_MD2_C
scripts/config.pl set MBEDTLS_MD4_C
mkdir build/
cd build/
cmake .. -DENABLE_PROGRAMS=0 -DENABLE_TESTING=0
make -j$(nproc)

Expected behavior

No hang

Actual behavior

Hang

Steps to reproduce

#include <mbedtls/ecp.h>

#define CF_CHECK_EQ(expr, res) if ( (expr) != (res) ) { goto end; }
#define CF_CHECK_NE(expr, res) if ( (expr) == (res) ) { goto end; }

int main(void)
{
    mbedtls_ecp_group grp;
    mbedtls_ecp_point a, b, res;
    mbedtls_mpi scalar;
    const mbedtls_ecp_curve_info* curve_info = NULL;

    mbedtls_ecp_group_init(&grp);
    mbedtls_ecp_point_init(&a);
    mbedtls_ecp_point_init(&b);
    mbedtls_mpi_init(&scalar);
    mbedtls_ecp_point_init(&res);

    /* secp256r1 */
    CF_CHECK_NE(curve_info = mbedtls_ecp_curve_info_from_tls_id(23), NULL);

    CF_CHECK_EQ(mbedtls_ecp_group_load(&grp, curve_info->grp_id), 0);

    /* Load point a */
    CF_CHECK_EQ(mbedtls_mpi_read_string(&a.X, 10, "48439561293906451759052585252797914202762949526041747995844080717082404635286"), 0);
    CF_CHECK_EQ(mbedtls_mpi_read_string(&a.Y, 10, "36134250956749795798585127919587881956611106672985015071877198253568414405109"), 0);
    CF_CHECK_EQ(mbedtls_mpi_lset(&a.Z, 1), 0);

    /* Load point b */
    CF_CHECK_EQ(mbedtls_mpi_read_string(&b.X, 10, "330527984395124299475957654016385519914202341482140609642324395022880711289249191050673258457777458014096366590617731358670"), 0);
    CF_CHECK_EQ(mbedtls_mpi_read_string(&b.Y, 10, "109665173580781193289131306340629307257455236857523409490593279367549320823692"), 0);
    CF_CHECK_EQ(mbedtls_mpi_lset(&b.Z, 1), 0);

    CF_CHECK_EQ(mbedtls_mpi_lset(&scalar, 1), 0);

    /* res = a + b */
    /* hangs */
    CF_CHECK_EQ(mbedtls_ecp_muladd(&grp, &res, &scalar, &b, &scalar, &a), 0);
end:
    mbedtls_ecp_group_free(&grp);
    mbedtls_ecp_point_free(&a);
    mbedtls_ecp_point_free(&b);
    mbedtls_mpi_free(&scalar);
    mbedtls_ecp_point_free(&res);

    return 0;
}

Additional information

This happens when the point coordinates are >= curve order, which is the case in the reproducer for the b point.

This is not necessarily a bug but the documentation does not mandate passing only valid points to mbedtls_ecp_muladd. Moreover, mbedtls_ecp_muladd does not hang when given other invalid points (not on curve, infinity). Additionally, mbedtls_ecp_mul does not hang with oversized points.

(Speaking for myself) @guidovranken I might have missed something, but directly accessing point coordinates is not supported by the public API, is it? See https://github.com/ARMmbed/mbedtls/blob/development/include/mbedtls/ecp.h#L174 I agree, though, that if the ECP module makes assumptions about the size of coordinates, those should be checked at the entry of top-level API calls (at negligible cost).

@hanno-arm It was supported (since it wasn't explicitly forbidden) in Mbed TLS 2. And it may be officially supported again in some 3.x version: we haven't settled yet on what fields we're going to add accessors for.

Actually, the public API mbedtls_ecp_point_read_string() can be used in the reproducer to circumvent direct field access.

This was fixed by #6191