1817466cbSJens Wiklander /* 2817466cbSJens Wiklander * Elliptic curve Diffie-Hellman 3817466cbSJens Wiklander * 47901324dSJerome Forissier * Copyright The Mbed TLS Contributors 57901324dSJerome Forissier * SPDX-License-Identifier: Apache-2.0 6817466cbSJens Wiklander * 7817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 8817466cbSJens Wiklander * not use this file except in compliance with the License. 9817466cbSJens Wiklander * You may obtain a copy of the License at 10817466cbSJens Wiklander * 11817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 12817466cbSJens Wiklander * 13817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 14817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16817466cbSJens Wiklander * See the License for the specific language governing permissions and 17817466cbSJens Wiklander * limitations under the License. 18817466cbSJens Wiklander */ 19817466cbSJens Wiklander 20817466cbSJens Wiklander /* 21817466cbSJens Wiklander * References: 22817466cbSJens Wiklander * 23817466cbSJens Wiklander * SEC1 http://www.secg.org/index.php?action=secg,docs_secg 24817466cbSJens Wiklander * RFC 4492 25817466cbSJens Wiklander */ 26817466cbSJens Wiklander 277901324dSJerome Forissier #include "common.h" 28817466cbSJens Wiklander 29817466cbSJens Wiklander #if defined(MBEDTLS_ECDH_C) 30817466cbSJens Wiklander 31817466cbSJens Wiklander #include "mbedtls/ecdh.h" 323d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 3311fa71b9SJerome Forissier #include "mbedtls/error.h" 34817466cbSJens Wiklander 35817466cbSJens Wiklander #include <string.h> 36817466cbSJens Wiklander 373d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 383d3b0591SJens Wiklander typedef mbedtls_ecdh_context mbedtls_ecdh_context_mbed; 393d3b0591SJens Wiklander #endif 403d3b0591SJens Wiklander 415b25c76aSJerome Forissier static mbedtls_ecp_group_id mbedtls_ecdh_grp_id( 425b25c76aSJerome Forissier const mbedtls_ecdh_context *ctx) 435b25c76aSJerome Forissier { 445b25c76aSJerome Forissier #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 45*32b31808SJens Wiklander return ctx->grp.id; 465b25c76aSJerome Forissier #else 47*32b31808SJens Wiklander return ctx->grp_id; 485b25c76aSJerome Forissier #endif 495b25c76aSJerome Forissier } 505b25c76aSJerome Forissier 5111fa71b9SJerome Forissier int mbedtls_ecdh_can_do(mbedtls_ecp_group_id gid) 5211fa71b9SJerome Forissier { 5311fa71b9SJerome Forissier /* At this time, all groups support ECDH. */ 5411fa71b9SJerome Forissier (void) gid; 55*32b31808SJens Wiklander return 1; 5611fa71b9SJerome Forissier } 5711fa71b9SJerome Forissier 583d3b0591SJens Wiklander #if !defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT) 59817466cbSJens Wiklander /* 603d3b0591SJens Wiklander * Generate public key (restartable version) 613d3b0591SJens Wiklander * 623d3b0591SJens Wiklander * Note: this internal function relies on its caller preserving the value of 633d3b0591SJens Wiklander * the output parameter 'd' across continuation calls. This would not be 643d3b0591SJens Wiklander * acceptable for a public function but is OK here as we control call sites. 653d3b0591SJens Wiklander */ 663d3b0591SJens Wiklander static int ecdh_gen_public_restartable(mbedtls_ecp_group *grp, 673d3b0591SJens Wiklander mbedtls_mpi *d, mbedtls_ecp_point *Q, 683d3b0591SJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 693d3b0591SJens Wiklander void *p_rng, 703d3b0591SJens Wiklander mbedtls_ecp_restart_ctx *rs_ctx) 713d3b0591SJens Wiklander { 7211fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 733d3b0591SJens Wiklander 74*32b31808SJens Wiklander int restarting = 0; 753d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 76*32b31808SJens Wiklander restarting = (rs_ctx != NULL && rs_ctx->rsm != NULL); 773d3b0591SJens Wiklander #endif 78*32b31808SJens Wiklander /* If multiplication is in progress, we already generated a privkey */ 79*32b31808SJens Wiklander if (!restarting) { 803d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_gen_privkey(grp, d, f_rng, p_rng)); 81*32b31808SJens Wiklander } 823d3b0591SJens Wiklander 833d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_mul_restartable(grp, Q, d, &grp->G, 843d3b0591SJens Wiklander f_rng, p_rng, rs_ctx)); 853d3b0591SJens Wiklander 863d3b0591SJens Wiklander cleanup: 87*32b31808SJens Wiklander return ret; 883d3b0591SJens Wiklander } 893d3b0591SJens Wiklander 903d3b0591SJens Wiklander /* 913d3b0591SJens Wiklander * Generate public key 92817466cbSJens Wiklander */ 93817466cbSJens Wiklander int mbedtls_ecdh_gen_public(mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, 94817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 95817466cbSJens Wiklander void *p_rng) 96817466cbSJens Wiklander { 97*32b31808SJens Wiklander return ecdh_gen_public_restartable(grp, d, Q, f_rng, p_rng, NULL); 98817466cbSJens Wiklander } 993d3b0591SJens Wiklander #endif /* !MBEDTLS_ECDH_GEN_PUBLIC_ALT */ 100817466cbSJens Wiklander 1013d3b0591SJens Wiklander #if !defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT) 102817466cbSJens Wiklander /* 103817466cbSJens Wiklander * Compute shared secret (SEC1 3.3.1) 104817466cbSJens Wiklander */ 1053d3b0591SJens Wiklander static int ecdh_compute_shared_restartable(mbedtls_ecp_group *grp, 1063d3b0591SJens Wiklander mbedtls_mpi *z, 107817466cbSJens Wiklander const mbedtls_ecp_point *Q, const mbedtls_mpi *d, 108817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 1093d3b0591SJens Wiklander void *p_rng, 1103d3b0591SJens Wiklander mbedtls_ecp_restart_ctx *rs_ctx) 111817466cbSJens Wiklander { 11211fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 113817466cbSJens Wiklander mbedtls_ecp_point P; 114817466cbSJens Wiklander 115817466cbSJens Wiklander mbedtls_ecp_point_init(&P); 116817466cbSJens Wiklander 1173d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_mul_restartable(grp, &P, d, Q, 1183d3b0591SJens Wiklander f_rng, p_rng, rs_ctx)); 119817466cbSJens Wiklander 120*32b31808SJens Wiklander if (mbedtls_ecp_is_zero(&P)) { 121817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 122817466cbSJens Wiklander goto cleanup; 123817466cbSJens Wiklander } 124817466cbSJens Wiklander 125817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(z, &P.X)); 126817466cbSJens Wiklander 127817466cbSJens Wiklander cleanup: 128817466cbSJens Wiklander mbedtls_ecp_point_free(&P); 129817466cbSJens Wiklander 130*32b31808SJens Wiklander return ret; 131817466cbSJens Wiklander } 132817466cbSJens Wiklander 133817466cbSJens Wiklander /* 1343d3b0591SJens Wiklander * Compute shared secret (SEC1 3.3.1) 1353d3b0591SJens Wiklander */ 1363d3b0591SJens Wiklander int mbedtls_ecdh_compute_shared(mbedtls_ecp_group *grp, mbedtls_mpi *z, 1373d3b0591SJens Wiklander const mbedtls_ecp_point *Q, const mbedtls_mpi *d, 1383d3b0591SJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 1393d3b0591SJens Wiklander void *p_rng) 1403d3b0591SJens Wiklander { 141*32b31808SJens Wiklander return ecdh_compute_shared_restartable(grp, z, Q, d, 142*32b31808SJens Wiklander f_rng, p_rng, NULL); 1433d3b0591SJens Wiklander } 1443d3b0591SJens Wiklander #endif /* !MBEDTLS_ECDH_COMPUTE_SHARED_ALT */ 1453d3b0591SJens Wiklander 1463d3b0591SJens Wiklander static void ecdh_init_internal(mbedtls_ecdh_context_mbed *ctx) 1473d3b0591SJens Wiklander { 1483d3b0591SJens Wiklander mbedtls_ecp_group_init(&ctx->grp); 1493d3b0591SJens Wiklander mbedtls_mpi_init(&ctx->d); 1503d3b0591SJens Wiklander mbedtls_ecp_point_init(&ctx->Q); 1513d3b0591SJens Wiklander mbedtls_ecp_point_init(&ctx->Qp); 1523d3b0591SJens Wiklander mbedtls_mpi_init(&ctx->z); 1533d3b0591SJens Wiklander 1543d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 1553d3b0591SJens Wiklander mbedtls_ecp_restart_init(&ctx->rs); 1563d3b0591SJens Wiklander #endif 1573d3b0591SJens Wiklander } 1583d3b0591SJens Wiklander 1593d3b0591SJens Wiklander /* 160817466cbSJens Wiklander * Initialize context 161817466cbSJens Wiklander */ 162817466cbSJens Wiklander void mbedtls_ecdh_init(mbedtls_ecdh_context *ctx) 163817466cbSJens Wiklander { 1643d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 1653d3b0591SJens Wiklander ecdh_init_internal(ctx); 1663d3b0591SJens Wiklander mbedtls_ecp_point_init(&ctx->Vi); 1673d3b0591SJens Wiklander mbedtls_ecp_point_init(&ctx->Vf); 1683d3b0591SJens Wiklander mbedtls_mpi_init(&ctx->_d); 1693d3b0591SJens Wiklander #else 170817466cbSJens Wiklander memset(ctx, 0, sizeof(mbedtls_ecdh_context)); 1713d3b0591SJens Wiklander 1723d3b0591SJens Wiklander ctx->var = MBEDTLS_ECDH_VARIANT_NONE; 1733d3b0591SJens Wiklander #endif 1743d3b0591SJens Wiklander ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; 1753d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 1763d3b0591SJens Wiklander ctx->restart_enabled = 0; 1773d3b0591SJens Wiklander #endif 178817466cbSJens Wiklander } 179817466cbSJens Wiklander 1803d3b0591SJens Wiklander static int ecdh_setup_internal(mbedtls_ecdh_context_mbed *ctx, 1813d3b0591SJens Wiklander mbedtls_ecp_group_id grp_id) 1823d3b0591SJens Wiklander { 18311fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1843d3b0591SJens Wiklander 1853d3b0591SJens Wiklander ret = mbedtls_ecp_group_load(&ctx->grp, grp_id); 186*32b31808SJens Wiklander if (ret != 0) { 187*32b31808SJens Wiklander return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 1883d3b0591SJens Wiklander } 1893d3b0591SJens Wiklander 190*32b31808SJens Wiklander return 0; 1913d3b0591SJens Wiklander } 1923d3b0591SJens Wiklander 1933d3b0591SJens Wiklander /* 1943d3b0591SJens Wiklander * Setup context 1953d3b0591SJens Wiklander */ 1963d3b0591SJens Wiklander int mbedtls_ecdh_setup(mbedtls_ecdh_context *ctx, mbedtls_ecp_group_id grp_id) 1973d3b0591SJens Wiklander { 1983d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 199*32b31808SJens Wiklander return ecdh_setup_internal(ctx, grp_id); 2003d3b0591SJens Wiklander #else 201*32b31808SJens Wiklander switch (grp_id) { 20211fa71b9SJerome Forissier #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) 20311fa71b9SJerome Forissier case MBEDTLS_ECP_DP_CURVE25519: 20411fa71b9SJerome Forissier ctx->point_format = MBEDTLS_ECP_PF_COMPRESSED; 20511fa71b9SJerome Forissier ctx->var = MBEDTLS_ECDH_VARIANT_EVEREST; 20611fa71b9SJerome Forissier ctx->grp_id = grp_id; 207*32b31808SJens Wiklander return mbedtls_everest_setup(&ctx->ctx.everest_ecdh, grp_id); 20811fa71b9SJerome Forissier #endif 2093d3b0591SJens Wiklander default: 2103d3b0591SJens Wiklander ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; 2113d3b0591SJens Wiklander ctx->var = MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0; 2123d3b0591SJens Wiklander ctx->grp_id = grp_id; 2133d3b0591SJens Wiklander ecdh_init_internal(&ctx->ctx.mbed_ecdh); 214*32b31808SJens Wiklander return ecdh_setup_internal(&ctx->ctx.mbed_ecdh, grp_id); 2153d3b0591SJens Wiklander } 2163d3b0591SJens Wiklander #endif 2173d3b0591SJens Wiklander } 2183d3b0591SJens Wiklander 2193d3b0591SJens Wiklander static void ecdh_free_internal(mbedtls_ecdh_context_mbed *ctx) 2203d3b0591SJens Wiklander { 2213d3b0591SJens Wiklander mbedtls_ecp_group_free(&ctx->grp); 2223d3b0591SJens Wiklander mbedtls_mpi_free(&ctx->d); 2233d3b0591SJens Wiklander mbedtls_ecp_point_free(&ctx->Q); 2243d3b0591SJens Wiklander mbedtls_ecp_point_free(&ctx->Qp); 2253d3b0591SJens Wiklander mbedtls_mpi_free(&ctx->z); 2263d3b0591SJens Wiklander 2273d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 2283d3b0591SJens Wiklander mbedtls_ecp_restart_free(&ctx->rs); 2293d3b0591SJens Wiklander #endif 2303d3b0591SJens Wiklander } 2313d3b0591SJens Wiklander 2323d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 2333d3b0591SJens Wiklander /* 2343d3b0591SJens Wiklander * Enable restartable operations for context 2353d3b0591SJens Wiklander */ 2363d3b0591SJens Wiklander void mbedtls_ecdh_enable_restart(mbedtls_ecdh_context *ctx) 2373d3b0591SJens Wiklander { 2383d3b0591SJens Wiklander ctx->restart_enabled = 1; 2393d3b0591SJens Wiklander } 2403d3b0591SJens Wiklander #endif 2413d3b0591SJens Wiklander 242817466cbSJens Wiklander /* 243817466cbSJens Wiklander * Free context 244817466cbSJens Wiklander */ 245817466cbSJens Wiklander void mbedtls_ecdh_free(mbedtls_ecdh_context *ctx) 246817466cbSJens Wiklander { 247*32b31808SJens Wiklander if (ctx == NULL) { 248817466cbSJens Wiklander return; 249*32b31808SJens Wiklander } 250817466cbSJens Wiklander 2513d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 252817466cbSJens Wiklander mbedtls_ecp_point_free(&ctx->Vi); 253817466cbSJens Wiklander mbedtls_ecp_point_free(&ctx->Vf); 254817466cbSJens Wiklander mbedtls_mpi_free(&ctx->_d); 2553d3b0591SJens Wiklander ecdh_free_internal(ctx); 2563d3b0591SJens Wiklander #else 257*32b31808SJens Wiklander switch (ctx->var) { 25811fa71b9SJerome Forissier #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) 25911fa71b9SJerome Forissier case MBEDTLS_ECDH_VARIANT_EVEREST: 26011fa71b9SJerome Forissier mbedtls_everest_free(&ctx->ctx.everest_ecdh); 26111fa71b9SJerome Forissier break; 26211fa71b9SJerome Forissier #endif 2633d3b0591SJens Wiklander case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: 2643d3b0591SJens Wiklander ecdh_free_internal(&ctx->ctx.mbed_ecdh); 2653d3b0591SJens Wiklander break; 2663d3b0591SJens Wiklander default: 2673d3b0591SJens Wiklander break; 2683d3b0591SJens Wiklander } 2693d3b0591SJens Wiklander 2703d3b0591SJens Wiklander ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; 2713d3b0591SJens Wiklander ctx->var = MBEDTLS_ECDH_VARIANT_NONE; 2723d3b0591SJens Wiklander ctx->grp_id = MBEDTLS_ECP_DP_NONE; 2733d3b0591SJens Wiklander #endif 2743d3b0591SJens Wiklander } 2753d3b0591SJens Wiklander 2763d3b0591SJens Wiklander static int ecdh_make_params_internal(mbedtls_ecdh_context_mbed *ctx, 2773d3b0591SJens Wiklander size_t *olen, int point_format, 2783d3b0591SJens Wiklander unsigned char *buf, size_t blen, 2793d3b0591SJens Wiklander int (*f_rng)(void *, 2803d3b0591SJens Wiklander unsigned char *, 2813d3b0591SJens Wiklander size_t), 2823d3b0591SJens Wiklander void *p_rng, 2833d3b0591SJens Wiklander int restart_enabled) 2843d3b0591SJens Wiklander { 28511fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2863d3b0591SJens Wiklander size_t grp_len, pt_len; 2873d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 2883d3b0591SJens Wiklander mbedtls_ecp_restart_ctx *rs_ctx = NULL; 2893d3b0591SJens Wiklander #endif 2903d3b0591SJens Wiklander 291*32b31808SJens Wiklander if (ctx->grp.pbits == 0) { 292*32b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 293*32b31808SJens Wiklander } 2943d3b0591SJens Wiklander 2953d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 296*32b31808SJens Wiklander if (restart_enabled) { 2973d3b0591SJens Wiklander rs_ctx = &ctx->rs; 298*32b31808SJens Wiklander } 2993d3b0591SJens Wiklander #else 3003d3b0591SJens Wiklander (void) restart_enabled; 3013d3b0591SJens Wiklander #endif 3023d3b0591SJens Wiklander 3033d3b0591SJens Wiklander 3043d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 3053d3b0591SJens Wiklander if ((ret = ecdh_gen_public_restartable(&ctx->grp, &ctx->d, &ctx->Q, 306*32b31808SJens Wiklander f_rng, p_rng, rs_ctx)) != 0) { 307*32b31808SJens Wiklander return ret; 308*32b31808SJens Wiklander } 3093d3b0591SJens Wiklander #else 3103d3b0591SJens Wiklander if ((ret = mbedtls_ecdh_gen_public(&ctx->grp, &ctx->d, &ctx->Q, 311*32b31808SJens Wiklander f_rng, p_rng)) != 0) { 312*32b31808SJens Wiklander return ret; 313*32b31808SJens Wiklander } 3143d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */ 3153d3b0591SJens Wiklander 3163d3b0591SJens Wiklander if ((ret = mbedtls_ecp_tls_write_group(&ctx->grp, &grp_len, buf, 317*32b31808SJens Wiklander blen)) != 0) { 318*32b31808SJens Wiklander return ret; 319*32b31808SJens Wiklander } 3203d3b0591SJens Wiklander 3213d3b0591SJens Wiklander buf += grp_len; 3223d3b0591SJens Wiklander blen -= grp_len; 3233d3b0591SJens Wiklander 3243d3b0591SJens Wiklander if ((ret = mbedtls_ecp_tls_write_point(&ctx->grp, &ctx->Q, point_format, 325*32b31808SJens Wiklander &pt_len, buf, blen)) != 0) { 326*32b31808SJens Wiklander return ret; 327*32b31808SJens Wiklander } 3283d3b0591SJens Wiklander 3293d3b0591SJens Wiklander *olen = grp_len + pt_len; 330*32b31808SJens Wiklander return 0; 331817466cbSJens Wiklander } 332817466cbSJens Wiklander 333817466cbSJens Wiklander /* 33411fa71b9SJerome Forissier * Setup and write the ServerKeyExchange parameters (RFC 4492) 335817466cbSJens Wiklander * struct { 336817466cbSJens Wiklander * ECParameters curve_params; 337817466cbSJens Wiklander * ECPoint public; 338817466cbSJens Wiklander * } ServerECDHParams; 339817466cbSJens Wiklander */ 340817466cbSJens Wiklander int mbedtls_ecdh_make_params(mbedtls_ecdh_context *ctx, size_t *olen, 341817466cbSJens Wiklander unsigned char *buf, size_t blen, 342817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 343817466cbSJens Wiklander void *p_rng) 344817466cbSJens Wiklander { 3453d3b0591SJens Wiklander int restart_enabled = 0; 3463d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 3473d3b0591SJens Wiklander restart_enabled = ctx->restart_enabled; 3483d3b0591SJens Wiklander #else 3493d3b0591SJens Wiklander (void) restart_enabled; 3503d3b0591SJens Wiklander #endif 351817466cbSJens Wiklander 3523d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 353*32b31808SJens Wiklander return ecdh_make_params_internal(ctx, olen, ctx->point_format, buf, blen, 354*32b31808SJens Wiklander f_rng, p_rng, restart_enabled); 3553d3b0591SJens Wiklander #else 356*32b31808SJens Wiklander switch (ctx->var) { 35711fa71b9SJerome Forissier #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) 35811fa71b9SJerome Forissier case MBEDTLS_ECDH_VARIANT_EVEREST: 359*32b31808SJens Wiklander return mbedtls_everest_make_params(&ctx->ctx.everest_ecdh, olen, 360*32b31808SJens Wiklander buf, blen, f_rng, p_rng); 36111fa71b9SJerome Forissier #endif 3623d3b0591SJens Wiklander case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: 363*32b31808SJens Wiklander return ecdh_make_params_internal(&ctx->ctx.mbed_ecdh, olen, 3643d3b0591SJens Wiklander ctx->point_format, buf, blen, 3653d3b0591SJens Wiklander f_rng, p_rng, 366*32b31808SJens Wiklander restart_enabled); 3673d3b0591SJens Wiklander default: 3683d3b0591SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 3693d3b0591SJens Wiklander } 3703d3b0591SJens Wiklander #endif 3713d3b0591SJens Wiklander } 372817466cbSJens Wiklander 3733d3b0591SJens Wiklander static int ecdh_read_params_internal(mbedtls_ecdh_context_mbed *ctx, 3743d3b0591SJens Wiklander const unsigned char **buf, 3753d3b0591SJens Wiklander const unsigned char *end) 3763d3b0591SJens Wiklander { 377*32b31808SJens Wiklander return mbedtls_ecp_tls_read_point(&ctx->grp, &ctx->Qp, buf, 378*32b31808SJens Wiklander end - *buf); 379817466cbSJens Wiklander } 380817466cbSJens Wiklander 381817466cbSJens Wiklander /* 382039e02dfSJerome Forissier * Read the ServerKeyExchange parameters (RFC 4492) 383817466cbSJens Wiklander * struct { 384817466cbSJens Wiklander * ECParameters curve_params; 385817466cbSJens Wiklander * ECPoint public; 386817466cbSJens Wiklander * } ServerECDHParams; 387817466cbSJens Wiklander */ 388817466cbSJens Wiklander int mbedtls_ecdh_read_params(mbedtls_ecdh_context *ctx, 3893d3b0591SJens Wiklander const unsigned char **buf, 3903d3b0591SJens Wiklander const unsigned char *end) 391817466cbSJens Wiklander { 39211fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 3933d3b0591SJens Wiklander mbedtls_ecp_group_id grp_id; 3943d3b0591SJens Wiklander if ((ret = mbedtls_ecp_tls_read_group_id(&grp_id, buf, end - *buf)) 395*32b31808SJens Wiklander != 0) { 396*32b31808SJens Wiklander return ret; 397*32b31808SJens Wiklander } 398817466cbSJens Wiklander 399*32b31808SJens Wiklander if ((ret = mbedtls_ecdh_setup(ctx, grp_id)) != 0) { 400*32b31808SJens Wiklander return ret; 401*32b31808SJens Wiklander } 4023d3b0591SJens Wiklander 4033d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 404*32b31808SJens Wiklander return ecdh_read_params_internal(ctx, buf, end); 4053d3b0591SJens Wiklander #else 406*32b31808SJens Wiklander switch (ctx->var) { 40711fa71b9SJerome Forissier #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) 40811fa71b9SJerome Forissier case MBEDTLS_ECDH_VARIANT_EVEREST: 409*32b31808SJens Wiklander return mbedtls_everest_read_params(&ctx->ctx.everest_ecdh, 410*32b31808SJens Wiklander buf, end); 41111fa71b9SJerome Forissier #endif 4123d3b0591SJens Wiklander case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: 413*32b31808SJens Wiklander return ecdh_read_params_internal(&ctx->ctx.mbed_ecdh, 414*32b31808SJens Wiklander buf, end); 4153d3b0591SJens Wiklander default: 4163d3b0591SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 4173d3b0591SJens Wiklander } 4183d3b0591SJens Wiklander #endif 419817466cbSJens Wiklander } 420817466cbSJens Wiklander 4213d3b0591SJens Wiklander static int ecdh_get_params_internal(mbedtls_ecdh_context_mbed *ctx, 4223d3b0591SJens Wiklander const mbedtls_ecp_keypair *key, 423817466cbSJens Wiklander mbedtls_ecdh_side side) 424817466cbSJens Wiklander { 42511fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 426817466cbSJens Wiklander 427817466cbSJens Wiklander /* If it's not our key, just import the public part as Qp */ 428*32b31808SJens Wiklander if (side == MBEDTLS_ECDH_THEIRS) { 429*32b31808SJens Wiklander return mbedtls_ecp_copy(&ctx->Qp, &key->Q); 430*32b31808SJens Wiklander } 431817466cbSJens Wiklander 432817466cbSJens Wiklander /* Our key: import public (as Q) and private parts */ 433*32b31808SJens Wiklander if (side != MBEDTLS_ECDH_OURS) { 434*32b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 435*32b31808SJens Wiklander } 436817466cbSJens Wiklander 437817466cbSJens Wiklander if ((ret = mbedtls_ecp_copy(&ctx->Q, &key->Q)) != 0 || 438*32b31808SJens Wiklander (ret = mbedtls_mpi_copy(&ctx->d, &key->d)) != 0) { 439*32b31808SJens Wiklander return ret; 440*32b31808SJens Wiklander } 441817466cbSJens Wiklander 442*32b31808SJens Wiklander return 0; 443817466cbSJens Wiklander } 444817466cbSJens Wiklander 445817466cbSJens Wiklander /* 4463d3b0591SJens Wiklander * Get parameters from a keypair 4473d3b0591SJens Wiklander */ 4483d3b0591SJens Wiklander int mbedtls_ecdh_get_params(mbedtls_ecdh_context *ctx, 4493d3b0591SJens Wiklander const mbedtls_ecp_keypair *key, 4503d3b0591SJens Wiklander mbedtls_ecdh_side side) 4513d3b0591SJens Wiklander { 45211fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 453*32b31808SJens Wiklander if (side != MBEDTLS_ECDH_OURS && side != MBEDTLS_ECDH_THEIRS) { 454*32b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 455*32b31808SJens Wiklander } 4563d3b0591SJens Wiklander 457*32b31808SJens Wiklander if (mbedtls_ecdh_grp_id(ctx) == MBEDTLS_ECP_DP_NONE) { 4585b25c76aSJerome Forissier /* This is the first call to get_params(). Set up the context 4595b25c76aSJerome Forissier * for use with the group. */ 460*32b31808SJens Wiklander if ((ret = mbedtls_ecdh_setup(ctx, key->grp.id)) != 0) { 461*32b31808SJens Wiklander return ret; 4625b25c76aSJerome Forissier } 463*32b31808SJens Wiklander } else { 4645b25c76aSJerome Forissier /* This is not the first call to get_params(). Check that the 4655b25c76aSJerome Forissier * current key's group is the same as the context's, which was set 4665b25c76aSJerome Forissier * from the first key's group. */ 467*32b31808SJens Wiklander if (mbedtls_ecdh_grp_id(ctx) != key->grp.id) { 468*32b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 469*32b31808SJens Wiklander } 4705b25c76aSJerome Forissier } 4713d3b0591SJens Wiklander 4723d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 473*32b31808SJens Wiklander return ecdh_get_params_internal(ctx, key, side); 4743d3b0591SJens Wiklander #else 475*32b31808SJens Wiklander switch (ctx->var) { 47611fa71b9SJerome Forissier #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) 47711fa71b9SJerome Forissier case MBEDTLS_ECDH_VARIANT_EVEREST: 47811fa71b9SJerome Forissier { 47911fa71b9SJerome Forissier mbedtls_everest_ecdh_side s = side == MBEDTLS_ECDH_OURS ? 48011fa71b9SJerome Forissier MBEDTLS_EVEREST_ECDH_OURS : 48111fa71b9SJerome Forissier MBEDTLS_EVEREST_ECDH_THEIRS; 482*32b31808SJens Wiklander return mbedtls_everest_get_params(&ctx->ctx.everest_ecdh, 483*32b31808SJens Wiklander key, s); 48411fa71b9SJerome Forissier } 48511fa71b9SJerome Forissier #endif 4863d3b0591SJens Wiklander case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: 487*32b31808SJens Wiklander return ecdh_get_params_internal(&ctx->ctx.mbed_ecdh, 488*32b31808SJens Wiklander key, side); 4893d3b0591SJens Wiklander default: 4903d3b0591SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 4913d3b0591SJens Wiklander } 4923d3b0591SJens Wiklander #endif 4933d3b0591SJens Wiklander } 4943d3b0591SJens Wiklander 4953d3b0591SJens Wiklander static int ecdh_make_public_internal(mbedtls_ecdh_context_mbed *ctx, 4963d3b0591SJens Wiklander size_t *olen, int point_format, 4973d3b0591SJens Wiklander unsigned char *buf, size_t blen, 4983d3b0591SJens Wiklander int (*f_rng)(void *, 4993d3b0591SJens Wiklander unsigned char *, 5003d3b0591SJens Wiklander size_t), 5013d3b0591SJens Wiklander void *p_rng, 5023d3b0591SJens Wiklander int restart_enabled) 5033d3b0591SJens Wiklander { 50411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 5053d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 5063d3b0591SJens Wiklander mbedtls_ecp_restart_ctx *rs_ctx = NULL; 5073d3b0591SJens Wiklander #endif 5083d3b0591SJens Wiklander 509*32b31808SJens Wiklander if (ctx->grp.pbits == 0) { 510*32b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 511*32b31808SJens Wiklander } 5123d3b0591SJens Wiklander 5133d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 514*32b31808SJens Wiklander if (restart_enabled) { 5153d3b0591SJens Wiklander rs_ctx = &ctx->rs; 516*32b31808SJens Wiklander } 5173d3b0591SJens Wiklander #else 5183d3b0591SJens Wiklander (void) restart_enabled; 5193d3b0591SJens Wiklander #endif 5203d3b0591SJens Wiklander 5213d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 5223d3b0591SJens Wiklander if ((ret = ecdh_gen_public_restartable(&ctx->grp, &ctx->d, &ctx->Q, 523*32b31808SJens Wiklander f_rng, p_rng, rs_ctx)) != 0) { 524*32b31808SJens Wiklander return ret; 525*32b31808SJens Wiklander } 5263d3b0591SJens Wiklander #else 5273d3b0591SJens Wiklander if ((ret = mbedtls_ecdh_gen_public(&ctx->grp, &ctx->d, &ctx->Q, 528*32b31808SJens Wiklander f_rng, p_rng)) != 0) { 529*32b31808SJens Wiklander return ret; 530*32b31808SJens Wiklander } 5313d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */ 5323d3b0591SJens Wiklander 5333d3b0591SJens Wiklander return mbedtls_ecp_tls_write_point(&ctx->grp, &ctx->Q, point_format, olen, 5343d3b0591SJens Wiklander buf, blen); 5353d3b0591SJens Wiklander } 5363d3b0591SJens Wiklander 5373d3b0591SJens Wiklander /* 538817466cbSJens Wiklander * Setup and export the client public value 539817466cbSJens Wiklander */ 540817466cbSJens Wiklander int mbedtls_ecdh_make_public(mbedtls_ecdh_context *ctx, size_t *olen, 541817466cbSJens Wiklander unsigned char *buf, size_t blen, 542817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 543817466cbSJens Wiklander void *p_rng) 544817466cbSJens Wiklander { 5453d3b0591SJens Wiklander int restart_enabled = 0; 5463d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 5473d3b0591SJens Wiklander restart_enabled = ctx->restart_enabled; 5483d3b0591SJens Wiklander #endif 5493d3b0591SJens Wiklander 5503d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 551*32b31808SJens Wiklander return ecdh_make_public_internal(ctx, olen, ctx->point_format, buf, blen, 552*32b31808SJens Wiklander f_rng, p_rng, restart_enabled); 5533d3b0591SJens Wiklander #else 554*32b31808SJens Wiklander switch (ctx->var) { 55511fa71b9SJerome Forissier #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) 55611fa71b9SJerome Forissier case MBEDTLS_ECDH_VARIANT_EVEREST: 557*32b31808SJens Wiklander return mbedtls_everest_make_public(&ctx->ctx.everest_ecdh, olen, 558*32b31808SJens Wiklander buf, blen, f_rng, p_rng); 55911fa71b9SJerome Forissier #endif 5603d3b0591SJens Wiklander case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: 561*32b31808SJens Wiklander return ecdh_make_public_internal(&ctx->ctx.mbed_ecdh, olen, 5623d3b0591SJens Wiklander ctx->point_format, buf, blen, 5633d3b0591SJens Wiklander f_rng, p_rng, 564*32b31808SJens Wiklander restart_enabled); 5653d3b0591SJens Wiklander default: 5663d3b0591SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 5673d3b0591SJens Wiklander } 5683d3b0591SJens Wiklander #endif 5693d3b0591SJens Wiklander } 5703d3b0591SJens Wiklander 5713d3b0591SJens Wiklander static int ecdh_read_public_internal(mbedtls_ecdh_context_mbed *ctx, 5723d3b0591SJens Wiklander const unsigned char *buf, size_t blen) 5733d3b0591SJens Wiklander { 57411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 5753d3b0591SJens Wiklander const unsigned char *p = buf; 576817466cbSJens Wiklander 5773d3b0591SJens Wiklander if ((ret = mbedtls_ecp_tls_read_point(&ctx->grp, &ctx->Qp, &p, 578*32b31808SJens Wiklander blen)) != 0) { 579*32b31808SJens Wiklander return ret; 580*32b31808SJens Wiklander } 581817466cbSJens Wiklander 582*32b31808SJens Wiklander if ((size_t) (p - buf) != blen) { 583*32b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 584*32b31808SJens Wiklander } 5853d3b0591SJens Wiklander 586*32b31808SJens Wiklander return 0; 587817466cbSJens Wiklander } 588817466cbSJens Wiklander 589817466cbSJens Wiklander /* 590817466cbSJens Wiklander * Parse and import the client's public value 591817466cbSJens Wiklander */ 592817466cbSJens Wiklander int mbedtls_ecdh_read_public(mbedtls_ecdh_context *ctx, 593817466cbSJens Wiklander const unsigned char *buf, size_t blen) 594817466cbSJens Wiklander { 5953d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 596*32b31808SJens Wiklander return ecdh_read_public_internal(ctx, buf, blen); 5973d3b0591SJens Wiklander #else 598*32b31808SJens Wiklander switch (ctx->var) { 59911fa71b9SJerome Forissier #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) 60011fa71b9SJerome Forissier case MBEDTLS_ECDH_VARIANT_EVEREST: 601*32b31808SJens Wiklander return mbedtls_everest_read_public(&ctx->ctx.everest_ecdh, 602*32b31808SJens Wiklander buf, blen); 60311fa71b9SJerome Forissier #endif 6043d3b0591SJens Wiklander case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: 605*32b31808SJens Wiklander return ecdh_read_public_internal(&ctx->ctx.mbed_ecdh, 606*32b31808SJens Wiklander buf, blen); 6073d3b0591SJens Wiklander default: 6083d3b0591SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 6093d3b0591SJens Wiklander } 6103d3b0591SJens Wiklander #endif 6113d3b0591SJens Wiklander } 6123d3b0591SJens Wiklander 6133d3b0591SJens Wiklander static int ecdh_calc_secret_internal(mbedtls_ecdh_context_mbed *ctx, 6143d3b0591SJens Wiklander size_t *olen, unsigned char *buf, 6153d3b0591SJens Wiklander size_t blen, 6163d3b0591SJens Wiklander int (*f_rng)(void *, 6173d3b0591SJens Wiklander unsigned char *, 6183d3b0591SJens Wiklander size_t), 6193d3b0591SJens Wiklander void *p_rng, 6203d3b0591SJens Wiklander int restart_enabled) 6213d3b0591SJens Wiklander { 62211fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 6233d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 6243d3b0591SJens Wiklander mbedtls_ecp_restart_ctx *rs_ctx = NULL; 6253d3b0591SJens Wiklander #endif 626817466cbSJens Wiklander 627*32b31808SJens Wiklander if (ctx == NULL || ctx->grp.pbits == 0) { 628*32b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 629*32b31808SJens Wiklander } 630817466cbSJens Wiklander 6313d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 632*32b31808SJens Wiklander if (restart_enabled) { 6333d3b0591SJens Wiklander rs_ctx = &ctx->rs; 634*32b31808SJens Wiklander } 6353d3b0591SJens Wiklander #else 6363d3b0591SJens Wiklander (void) restart_enabled; 6373d3b0591SJens Wiklander #endif 6383d3b0591SJens Wiklander 6393d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 6403d3b0591SJens Wiklander if ((ret = ecdh_compute_shared_restartable(&ctx->grp, &ctx->z, &ctx->Qp, 6413d3b0591SJens Wiklander &ctx->d, f_rng, p_rng, 642*32b31808SJens Wiklander rs_ctx)) != 0) { 643*32b31808SJens Wiklander return ret; 6443d3b0591SJens Wiklander } 6453d3b0591SJens Wiklander #else 6463d3b0591SJens Wiklander if ((ret = mbedtls_ecdh_compute_shared(&ctx->grp, &ctx->z, &ctx->Qp, 647*32b31808SJens Wiklander &ctx->d, f_rng, p_rng)) != 0) { 648*32b31808SJens Wiklander return ret; 6493d3b0591SJens Wiklander } 6503d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */ 651817466cbSJens Wiklander 652*32b31808SJens Wiklander if (mbedtls_mpi_size(&ctx->z) > blen) { 653*32b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 654*32b31808SJens Wiklander } 655817466cbSJens Wiklander 6563d3b0591SJens Wiklander *olen = ctx->grp.pbits / 8 + ((ctx->grp.pbits % 8) != 0); 65711fa71b9SJerome Forissier 658*32b31808SJens Wiklander if (mbedtls_ecp_get_type(&ctx->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { 65911fa71b9SJerome Forissier return mbedtls_mpi_write_binary_le(&ctx->z, buf, *olen); 660*32b31808SJens Wiklander } 66111fa71b9SJerome Forissier 6623d3b0591SJens Wiklander return mbedtls_mpi_write_binary(&ctx->z, buf, *olen); 663817466cbSJens Wiklander } 664817466cbSJens Wiklander 665817466cbSJens Wiklander /* 666817466cbSJens Wiklander * Derive and export the shared secret 667817466cbSJens Wiklander */ 668817466cbSJens Wiklander int mbedtls_ecdh_calc_secret(mbedtls_ecdh_context *ctx, size_t *olen, 669817466cbSJens Wiklander unsigned char *buf, size_t blen, 670817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 671817466cbSJens Wiklander void *p_rng) 672817466cbSJens Wiklander { 6733d3b0591SJens Wiklander int restart_enabled = 0; 6743d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 6753d3b0591SJens Wiklander restart_enabled = ctx->restart_enabled; 6763d3b0591SJens Wiklander #endif 677817466cbSJens Wiklander 6783d3b0591SJens Wiklander #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) 679*32b31808SJens Wiklander return ecdh_calc_secret_internal(ctx, olen, buf, blen, f_rng, p_rng, 680*32b31808SJens Wiklander restart_enabled); 6813d3b0591SJens Wiklander #else 682*32b31808SJens Wiklander switch (ctx->var) { 68311fa71b9SJerome Forissier #if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) 68411fa71b9SJerome Forissier case MBEDTLS_ECDH_VARIANT_EVEREST: 685*32b31808SJens Wiklander return mbedtls_everest_calc_secret(&ctx->ctx.everest_ecdh, olen, 686*32b31808SJens Wiklander buf, blen, f_rng, p_rng); 68711fa71b9SJerome Forissier #endif 6883d3b0591SJens Wiklander case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: 689*32b31808SJens Wiklander return ecdh_calc_secret_internal(&ctx->ctx.mbed_ecdh, olen, buf, 6903d3b0591SJens Wiklander blen, f_rng, p_rng, 691*32b31808SJens Wiklander restart_enabled); 6923d3b0591SJens Wiklander default: 693*32b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 6943d3b0591SJens Wiklander } 6953d3b0591SJens Wiklander #endif 696817466cbSJens Wiklander } 697817466cbSJens Wiklander #endif /* MBEDTLS_ECDH_C */ 698