/* * Copyright (c) 2001-2022, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "mbedtls/build_info.h" #include "mbedtls/ecdh.h" #include "cc_ecc_internal.h" const mbedtls_ecp_curve_info curve_25519_data = { MBEDTLS_ECP_DP_CURVE25519, 29, 255, "curve25519"}; #if defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT) /* * Generate key pair, wrapper for conventional base point */ int cc_ecp_gen_keypair( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { return( cc_ecp_gen_keypair_base( grp, &grp->G, d, Q, f_rng, p_rng ) ); } /* * Generate public key: simple wrapper around mbedtls_ecp_gen_keypair */ int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { return cc_ecp_gen_keypair( grp, d, Q, f_rng, p_rng ); } #endif /* MBEDTLS_ECDH_GEN_PUBLIC_ALT */ #if defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT) /* * Compute shared secret (SEC1 3.3.1) */ int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, const mbedtls_ecp_point *Q, const mbedtls_mpi *d, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret; mbedtls_ecp_point P; mbedtls_ecp_point_init( &P ); if ( z == NULL || Q == NULL || grp == NULL || d == NULL) { ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; goto cleanup; } /* * Make sure Q is a valid pubkey before using it */ MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) ); MBEDTLS_MPI_CHK( cc_ecp_mul( grp, &P, d, Q, f_rng, p_rng ) ); if( mbedtls_ecp_is_zero( &P ) ) { ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; goto cleanup; } MBEDTLS_MPI_CHK( mbedtls_mpi_copy( z, &P.MBEDTLS_PRIVATE(X) ) ); cleanup: mbedtls_ecp_point_free( &P ); return( ret ); } #endif /* MBEDTLS_ECDH_COMPUTE_SHARED_ALT */ /* * Write the ECParameters record corresponding to a group (RFC 4492) */ static int mbedtls_ecp_tls_write_group_edwards( const mbedtls_ecp_group *grp, size_t *olen, unsigned char *buf, size_t blen ) { const mbedtls_ecp_curve_info *curve_info = &curve_25519_data; if (grp->id != MBEDTLS_ECP_DP_CURVE25519){ return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); } /* * We are going to write 3 bytes (see below) */ *olen = 3; if( blen < *olen ) return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); /* * First byte is curve_type, always named_curve */ *buf++ = MBEDTLS_ECP_TLS_NAMED_CURVE; /* * Next two bytes are the namedcurve value */ buf[0] = curve_info->tls_id >> 8; buf[1] = curve_info->tls_id & 0xFF; return( 0 ); } /* * Setup and write the ServerKeyExhange parameters (RFC 4492) * struct { * ECParameters curve_params; * ECPoint public; * } ServerECDHParams; */ int mbedtls_ecdh_make_params_edwards( mbedtls_ecdh_context *ctx, size_t *olen, unsigned char *buf, size_t blen, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret; size_t grp_len, pt_len; if( ctx == NULL || ctx->MBEDTLS_PRIVATE(ctx).MBEDTLS_PRIVATE(mbed_ecdh).MBEDTLS_PRIVATE(grp).pbits == 0 || olen == NULL || buf == NULL || blen <= 0 || (ctx->MBEDTLS_PRIVATE(ctx).MBEDTLS_PRIVATE(mbed_ecdh).MBEDTLS_PRIVATE(grp).id != MBEDTLS_ECP_DP_CURVE25519) ){ return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); } if( ( ret = mbedtls_ecdh_gen_public( &ctx->MBEDTLS_PRIVATE(ctx).MBEDTLS_PRIVATE(mbed_ecdh).MBEDTLS_PRIVATE(grp), &ctx->MBEDTLS_PRIVATE(ctx).MBEDTLS_PRIVATE(mbed_ecdh).MBEDTLS_PRIVATE(d), &ctx->MBEDTLS_PRIVATE(ctx).MBEDTLS_PRIVATE(mbed_ecdh).MBEDTLS_PRIVATE(Q), f_rng, p_rng ) ) != 0 ) return( ret ); if( ( ret = mbedtls_ecp_tls_write_group_edwards( &ctx->MBEDTLS_PRIVATE(ctx).MBEDTLS_PRIVATE(mbed_ecdh).MBEDTLS_PRIVATE(grp), &grp_len, buf, blen ) ) != 0 ) return( ret ); buf += grp_len; blen -= grp_len; if( ( ret = mbedtls_ecp_tls_write_point( &ctx->MBEDTLS_PRIVATE(ctx).MBEDTLS_PRIVATE(mbed_ecdh).MBEDTLS_PRIVATE(grp), &ctx->MBEDTLS_PRIVATE(ctx).MBEDTLS_PRIVATE(mbed_ecdh).MBEDTLS_PRIVATE(Q), ctx->MBEDTLS_PRIVATE(point_format), &pt_len, buf, blen ) ) != 0 ) return( ret ); *olen = grp_len + pt_len; return( 0 ); } /* * Set a group from an ECParameters record (RFC 4492) */ static int mbedtls_ecp_tls_read_group_edwards( mbedtls_ecp_group *grp, const unsigned char **buf, size_t len ) { uint16_t tls_id; const mbedtls_ecp_curve_info *curve_info = &curve_25519_data; /* * We expect at least three bytes (see below) */ if( len < 3 ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); /* * First byte is curve_type; only named_curve is handled */ if( *(*buf)++ != MBEDTLS_ECP_TLS_NAMED_CURVE ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); /* * Next two bytes are the namedcurve value */ tls_id = *(*buf)++; tls_id <<= 8; tls_id |= *(*buf)++; if (curve_info->tls_id != tls_id){ return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); } return mbedtls_ecp_group_load( grp, curve_info->grp_id ); } /* * Read the ServerKeyExhange parameters (RFC 4492) * struct { * ECParameters curve_params; * ECPoint public; * } ServerECDHParams; */ int mbedtls_ecdh_read_params_edwards( mbedtls_ecdh_context *ctx, const unsigned char **buf, const unsigned char *end ) { int ret; if( ctx == NULL || buf == NULL || end == NULL){ return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); } if( ( ret = mbedtls_ecp_tls_read_group_edwards( &ctx->MBEDTLS_PRIVATE(ctx).MBEDTLS_PRIVATE(mbed_ecdh).MBEDTLS_PRIVATE(grp), buf, end - *buf ) ) != 0 ) return( ret ); if( ( ret = mbedtls_ecp_tls_read_point( &ctx->MBEDTLS_PRIVATE(ctx).MBEDTLS_PRIVATE(mbed_ecdh).MBEDTLS_PRIVATE(grp), &ctx->MBEDTLS_PRIVATE(ctx).MBEDTLS_PRIVATE(mbed_ecdh).MBEDTLS_PRIVATE(Qp), buf, end - *buf ) ) != 0 ){ return( ret ); } return( 0 ); }