From 49a355c272336a2018e56a636a9ae51cd3a8b514 Mon Sep 17 00:00:00 2001 From: Praneeth Sarode Date: Fri, 21 Mar 2025 00:08:17 +0530 Subject: [PATCH] curve25519: Use mbedTLS curve25519 for ECDH, if available Signed-off-by: Praneeth Sarode Reviewed-by: Jakub Jelen --- ConfigureChecks.cmake | 14 ++ config.h.cmake | 3 + src/curve25519.c | 225 +++++++++++++++++++++++++ tests/external_override/CMakeLists.txt | 8 +- 4 files changed, 249 insertions(+), 1 deletion(-) diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index 8765dc6e..07bb829c 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -236,6 +236,20 @@ if (MBEDTLS_FOUND) set(CMAKE_REQUIRED_INCLUDES "${MBEDTLS_INCLUDE_DIR}/mbedtls") check_include_file(chacha20.h HAVE_MBEDTLS_CHACHA20_H) check_include_file(poly1305.h HAVE_MBEDTLS_POLY1305_H) + + + set(CMAKE_REQUIRED_INCLUDES "${MBEDTLS_INCLUDE_DIR}") + check_c_source_compiles(" + #include + int main() { + #if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + return 0; + #else + #error \"X25519 not supported\" + #endif + } + " HAVE_MBEDTLS_CURVE25519) + if (WITH_BLOWFISH_CIPHER) check_include_file(blowfish.h HAVE_BLOWFISH) endif() diff --git a/config.h.cmake b/config.h.cmake index b61ce1db..dac315eb 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -87,6 +87,9 @@ /* Define to 1 if you have elliptic curve cryptography in openssl */ #cmakedefine HAVE_OPENSSL_ECC 1 +/* Define to 1 if mbedTLS supports curve25519 */ +#cmakedefine HAVE_MBEDTLS_CURVE25519 1 + /* Define to 1 if you have elliptic curve cryptography in gcrypt */ #cmakedefine HAVE_GCRYPT_ECC 1 diff --git a/src/curve25519.c b/src/curve25519.c index f1c7589d..7708aa0b 100644 --- a/src/curve25519.c +++ b/src/curve25519.c @@ -41,6 +41,10 @@ #ifdef HAVE_LIBCRYPTO #include +#elif defined(HAVE_MBEDTLS_CURVE25519) +#include "mbedcrypto-compat.h" +#include +#include #endif static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply); @@ -108,6 +112,102 @@ int ssh_curve25519_init(ssh_session session) session->next_crypto->curve25519_privkey = pkey; pkey = NULL; + +#elif defined(HAVE_MBEDTLS_CURVE25519) + mbedtls_ecdh_context ecdh_ctx; + mbedtls_ctr_drbg_context *ctr_drbg = NULL; + ssh_curve25519_pubkey *pubkey_loc = NULL; + char error_buf[128]; + int ret = SSH_ERROR; + + ctr_drbg = ssh_get_mbedtls_ctr_drbg_context(); + + mbedtls_ecdh_init(&ecdh_ctx); + rc = mbedtls_ecdh_setup(&ecdh_ctx, MBEDTLS_ECP_DP_CURVE25519); + if (rc != 0) { + mbedtls_strerror(rc, error_buf, sizeof(error_buf)); + SSH_LOG(SSH_LOG_TRACE, "Failed to setup X25519 context: %s", error_buf); + goto error; + } + +#if MBEDTLS_VERSION_MAJOR > 2 + rc = mbedtls_ecdh_gen_public(&ecdh_ctx.MBEDTLS_PRIVATE(ctx) + .MBEDTLS_PRIVATE(mbed_ecdh) + .MBEDTLS_PRIVATE(grp), + &ecdh_ctx.MBEDTLS_PRIVATE(ctx) + .MBEDTLS_PRIVATE(mbed_ecdh) + .MBEDTLS_PRIVATE(d), + &ecdh_ctx.MBEDTLS_PRIVATE(ctx) + .MBEDTLS_PRIVATE(mbed_ecdh) + .MBEDTLS_PRIVATE(Q), + mbedtls_ctr_drbg_random, + ctr_drbg); +#else + rc = mbedtls_ecdh_gen_public(&ecdh_ctx.grp, + &ecdh_ctx.d, + &ecdh_ctx.Q, + mbedtls_ctr_drbg_random, + ctr_drbg); +#endif + if (rc != 0) { + mbedtls_strerror(rc, error_buf, sizeof(error_buf)); + SSH_LOG(SSH_LOG_TRACE, + "Failed to generate X25519 keypair: %s", + error_buf); + goto error; + } + + if (session->server) { + pubkey_loc = &session->next_crypto->curve25519_server_pubkey; + } else { + pubkey_loc = &session->next_crypto->curve25519_client_pubkey; + } + +#if MBEDTLS_VERSION_MAJOR > 2 + rc = mbedtls_mpi_write_binary_le(&ecdh_ctx.MBEDTLS_PRIVATE(ctx) + .MBEDTLS_PRIVATE(mbed_ecdh) + .MBEDTLS_PRIVATE(d), + session->next_crypto->curve25519_privkey, + CURVE25519_PRIVKEY_SIZE); +#else + rc = mbedtls_mpi_write_binary_le(&ecdh_ctx.d, + session->next_crypto->curve25519_privkey, + CURVE25519_PRIVKEY_SIZE); +#endif + if (rc != 0) { + mbedtls_strerror(rc, error_buf, sizeof(error_buf)); + SSH_LOG(SSH_LOG_TRACE, + "Failed to write X25519 private key: %s", + error_buf); + goto error; + } + +#if MBEDTLS_VERSION_MAJOR > 2 + rc = mbedtls_mpi_write_binary_le(&ecdh_ctx.MBEDTLS_PRIVATE(ctx) + .MBEDTLS_PRIVATE(mbed_ecdh) + .MBEDTLS_PRIVATE(Q) + .MBEDTLS_PRIVATE(X), + *pubkey_loc, + CURVE25519_PUBKEY_SIZE); +#else + rc = mbedtls_mpi_write_binary_le(&ecdh_ctx.Q.X, + *pubkey_loc, + CURVE25519_PUBKEY_SIZE); +#endif + if (rc != 0) { + mbedtls_strerror(rc, error_buf, sizeof(error_buf)); + SSH_LOG(SSH_LOG_TRACE, + "Failed to write X25519 public key: %s", + error_buf); + goto error; + } + + ret = SSH_OK; + +error: + mbedtls_ecdh_free(&ecdh_ctx); + return ret; + #else rc = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1); @@ -234,6 +334,131 @@ out: if (ret == SSH_ERROR) { return ret; } +#elif defined(HAVE_MBEDTLS_CURVE25519) + mbedtls_ecdh_context ecdh_ctx; + mbedtls_ctr_drbg_context *ctr_drbg = NULL; + ssh_curve25519_pubkey *peer_pubkey_loc = NULL; + char error_buf[128]; + int rc, ret = SSH_ERROR; + + ctr_drbg = ssh_get_mbedtls_ctr_drbg_context(); + + mbedtls_ecdh_init(&ecdh_ctx); + rc = mbedtls_ecdh_setup(&ecdh_ctx, MBEDTLS_ECP_DP_CURVE25519); + if (rc != 0) { + mbedtls_strerror(rc, error_buf, sizeof(error_buf)); + SSH_LOG(SSH_LOG_TRACE, "Failed to setup X25519 context: %s", error_buf); + goto error; + } + +#if MBEDTLS_VERSION_MAJOR > 2 + rc = mbedtls_mpi_read_binary_le(&ecdh_ctx.MBEDTLS_PRIVATE(ctx) + .MBEDTLS_PRIVATE(mbed_ecdh) + .MBEDTLS_PRIVATE(d), + session->next_crypto->curve25519_privkey, + CURVE25519_PRIVKEY_SIZE); +#else + rc = mbedtls_mpi_read_binary_le(&ecdh_ctx.d, + session->next_crypto->curve25519_privkey, + CURVE25519_PRIVKEY_SIZE); +#endif + if (rc != 0) { + mbedtls_strerror(rc, error_buf, sizeof(error_buf)); + SSH_LOG(SSH_LOG_TRACE, "Failed to read private key: %s", error_buf); + goto error; + } + + if (session->server) { + peer_pubkey_loc = &session->next_crypto->curve25519_client_pubkey; + } else { + peer_pubkey_loc = &session->next_crypto->curve25519_server_pubkey; + } + +#if MBEDTLS_VERSION_MAJOR > 2 + rc = mbedtls_mpi_read_binary_le(&ecdh_ctx.MBEDTLS_PRIVATE(ctx) + .MBEDTLS_PRIVATE(mbed_ecdh) + .MBEDTLS_PRIVATE(Qp) + .MBEDTLS_PRIVATE(X), + *peer_pubkey_loc, + CURVE25519_PUBKEY_SIZE); +#else + rc = mbedtls_mpi_read_binary_le(&ecdh_ctx.Qp.X, + *peer_pubkey_loc, + CURVE25519_PUBKEY_SIZE); +#endif + if (rc != 0) { + mbedtls_strerror(rc, error_buf, sizeof(error_buf)); + SSH_LOG(SSH_LOG_TRACE, "Failed to read peer public key: %s", error_buf); + goto error; + } + +#if MBEDTLS_VERSION_MAJOR > 2 + rc = mbedtls_mpi_lset(&ecdh_ctx.MBEDTLS_PRIVATE(ctx) + .MBEDTLS_PRIVATE(mbed_ecdh) + .MBEDTLS_PRIVATE(Qp) + .MBEDTLS_PRIVATE(Z), + 1); +#else + rc = mbedtls_mpi_lset(&ecdh_ctx.Qp.Z, 1); +#endif + if (rc != 0) { + mbedtls_strerror(rc, error_buf, sizeof(error_buf)); + SSH_LOG(SSH_LOG_TRACE, "Failed to set Z coordinate: %s", error_buf); + goto error; + } + +#if MBEDTLS_VERSION_MAJOR > 2 + rc = mbedtls_ecdh_compute_shared(&ecdh_ctx.MBEDTLS_PRIVATE(ctx) + .MBEDTLS_PRIVATE(mbed_ecdh) + .MBEDTLS_PRIVATE(grp), + &ecdh_ctx.MBEDTLS_PRIVATE(ctx) + .MBEDTLS_PRIVATE(mbed_ecdh) + .MBEDTLS_PRIVATE(z), + &ecdh_ctx.MBEDTLS_PRIVATE(ctx) + .MBEDTLS_PRIVATE(mbed_ecdh) + .MBEDTLS_PRIVATE(Qp), + &ecdh_ctx.MBEDTLS_PRIVATE(ctx) + .MBEDTLS_PRIVATE(mbed_ecdh) + .MBEDTLS_PRIVATE(d), + mbedtls_ctr_drbg_random, + ctr_drbg); +#else + rc = mbedtls_ecdh_compute_shared(&ecdh_ctx.grp, + &ecdh_ctx.z, + &ecdh_ctx.Qp, + &ecdh_ctx.d, + mbedtls_ctr_drbg_random, + ctr_drbg); +#endif + if (rc != 0) { + mbedtls_strerror(rc, error_buf, sizeof(error_buf)); + SSH_LOG(SSH_LOG_TRACE, + "Failed to compute shared secret: %s", + error_buf); + goto error; + } + +#if MBEDTLS_VERSION_MAJOR > 2 + rc = mbedtls_mpi_write_binary_le(&ecdh_ctx.MBEDTLS_PRIVATE(ctx) + .MBEDTLS_PRIVATE(mbed_ecdh) + .MBEDTLS_PRIVATE(z), + k, + CURVE25519_PUBKEY_SIZE); +#else + rc = mbedtls_mpi_write_binary_le(&ecdh_ctx.z, k, CURVE25519_PUBKEY_SIZE); +#endif + if (rc != 0) { + mbedtls_strerror(rc, error_buf, sizeof(error_buf)); + SSH_LOG(SSH_LOG_TRACE, "Failed to write shared secret: %s", error_buf); + goto error; + } + + ret = SSH_OK; + +error: + mbedtls_ecdh_free(&ecdh_ctx); + return ret; + #else if (session->server) { crypto_scalarmult(k, session->next_crypto->curve25519_privkey, diff --git a/tests/external_override/CMakeLists.txt b/tests/external_override/CMakeLists.txt index 8047cd4f..cf8cd800 100644 --- a/tests/external_override/CMakeLists.txt +++ b/tests/external_override/CMakeLists.txt @@ -98,8 +98,14 @@ if (WITH_MBEDTLS) else () list(APPEND OVERRIDE_RESULTS "-DSHOULD_CALL_INTERNAL_CHACHAPOLY=1") endif () + + if(HAVE_MBEDTLS_CURVE25519) + list(APPEND OVERRIDE_RESULTS "-DSHOULD_CALL_INTERNAL_CURVE25519=0") + else () + list(APPEND OVERRIDE_RESULTS "-DSHOULD_CALL_INTERNAL_CURVE25519=1") + endif() + list(APPEND OVERRIDE_RESULTS "-DSHOULD_CALL_INTERNAL_ED25519=1") - list(APPEND OVERRIDE_RESULTS "-DSHOULD_CALL_INTERNAL_CURVE25519=1") list(APPEND OVERRIDE_RESULTS "-DSHOULD_CALL_INTERNAL_SNTRUP761=1") elseif (WITH_GCRYPT) if (HAVE_GCRYPT_CHACHA_POLY)