Skip to content

Commit

Permalink
Merge pull request #7815 from gilles-peskine-arm/ecp-export-partial
Browse files Browse the repository at this point in the history
ECP keypair utility functions
  • Loading branch information
gilles-peskine-arm authored Jan 18, 2024
2 parents c9077cc + a10d112 commit b1f96c0
Show file tree
Hide file tree
Showing 10 changed files with 661 additions and 100 deletions.
5 changes: 5 additions & 0 deletions ChangeLog.d/ecp-keypair-utilities.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Features
* Add utility functions to manipulate mbedtls_ecp_keypair objects, filling
gaps made by making its fields private: mbedtls_ecp_set_public_key(),
mbedtls_ecp_write_public_key(), mbedtls_ecp_keypair_calc_public(),
mbedtls_ecp_keypair_get_group_id(). Fixes #5017, #5441, #8367, #8652.
111 changes: 108 additions & 3 deletions include/mbedtls/ecp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1259,9 +1259,56 @@ int mbedtls_ecp_gen_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng);

/** \brief Set the public key in a key pair object.
*
* \note This function does not check that the point actually
* belongs to the given group. Call mbedtls_ecp_check_pubkey()
* on \p Q before calling this function to check that.
*
* \note This function does not check that the public key matches
* the private key that is already in \p key, if any.
* To check the consistency of the resulting key pair object,
* call mbedtls_ecp_check_pub_priv() after setting both
* the public key and the private key.
*
* \param grp_id The ECP group identifier.
* \param key The key pair object. It must be initialized.
* If its group has already been set, it must match \p grp_id.
* If its group has not been set, it will be set to \p grp_id.
* If the public key has already been set, it is overwritten.
* \param Q The public key to copy. This must be a point on the
* curve indicated by \p grp_id.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if \p key does not
* match \p grp_id.
* \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the operation for
* the group is not implemented.
* \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure.
* \return Another negative error code on other kinds of failure.
*/
int mbedtls_ecp_set_public_key(mbedtls_ecp_group_id grp_id,
mbedtls_ecp_keypair *key,
const mbedtls_ecp_point *Q);

/**
* \brief This function reads an elliptic curve private key.
*
* \note This function does not set the public key in the
* key pair object. Without a public key, the key pair object
* cannot be used with operations that require the public key.
* Call mbedtls_ecp_keypair_calc_public() to set the public
* key from the private key. Alternatively, you can call
* mbedtls_ecp_set_public_key() to set the public key part,
* and then optionally mbedtls_ecp_check_pub_priv() to check
* that the private and public parts are consistent.
*
* \note If a public key has already been set in the key pair
* object, this function does not check that it is consistent
* with the private key. Call mbedtls_ecp_check_pub_priv()
* after setting both the public key and the private key
* to make that check.
*
* \param grp_id The ECP group identifier.
* \param key The destination key.
* \param buf The buffer containing the binary representation of the
Expand Down Expand Up @@ -1299,6 +1346,32 @@ int mbedtls_ecp_read_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key,
int mbedtls_ecp_write_key(mbedtls_ecp_keypair *key,
unsigned char *buf, size_t buflen);

/**
* \brief This function exports an elliptic curve public key.
*
* \param key The public key.
* \param format The point format. This must be either
* #MBEDTLS_ECP_PF_COMPRESSED or #MBEDTLS_ECP_PF_UNCOMPRESSED.
* (For groups without these formats, this parameter is
* ignored. But it still has to be either of the above
* values.)
* \param olen The address at which to store the length of
* the output in Bytes. This must not be \c NULL.
* \param buf The output buffer. This must be a writable buffer
* of length \p buflen Bytes.
* \param buflen The length of the output buffer \p buf in Bytes.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the output buffer
* is too small to hold the point.
* \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the point format
* or the export for the given group is not implemented.
* \return Another negative error code on other kinds of failure.
*/
int mbedtls_ecp_write_public_key(const mbedtls_ecp_keypair *key,
int format, size_t *olen,
unsigned char *buf, size_t buflen);

/**
* \brief This function checks that the keypair objects
* \p pub and \p prv have the same group and the
Expand All @@ -1323,16 +1396,48 @@ int mbedtls_ecp_check_pub_priv(
const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng);

/** \brief Calculate the public key from a private key in a key pair.
*
* \param key A keypair structure. It must have a private key set.
* If the public key is set, it will be overwritten.
* \param f_rng The RNG function. This must not be \c NULL.
* \param p_rng The RNG context to be passed to \p f_rng. This may be \c
* NULL if \p f_rng doesn't need a context.
*
* \return \c 0 on success. The key pair object can be used for
* operations that require the public key.
* \return An \c MBEDTLS_ERR_ECP_XXX or an \c MBEDTLS_ERR_MPI_XXX
* error code on calculation failure.
*/
int mbedtls_ecp_keypair_calc_public(
mbedtls_ecp_keypair *key,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng);

/** \brief Query the group that a key pair belongs to.
*
* \param key The key pair to query.
*
* \return The group ID for the group registered in the key pair
* object.
* This is \c MBEDTLS_ECP_DP_NONE if no group has been set
* in the key pair object.
*/
mbedtls_ecp_group_id mbedtls_ecp_keypair_get_group_id(
const mbedtls_ecp_keypair *key);

/**
* \brief This function exports generic key-pair parameters.
*
* Each of the output parameters can be a null pointer
* if you do not need that parameter.
*
* \param key The key pair to export from.
* \param grp Slot for exported ECP group.
* It must point to an initialized ECP group.
* It must either be null or point to an initialized ECP group.
* \param d Slot for the exported secret value.
* It must point to an initialized mpi.
* It must either be null or point to an initialized mpi.
* \param Q Slot for the exported public value.
* It must point to an initialized ECP point.
* It must either be null or point to an initialized ECP point.
*
* \return \c 0 on success,
* \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure.
Expand Down
51 changes: 48 additions & 3 deletions library/ecp.c
Original file line number Diff line number Diff line change
Expand Up @@ -3198,6 +3198,25 @@ int mbedtls_ecp_gen_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key,
}
#endif /* MBEDTLS_ECP_C */

int mbedtls_ecp_set_public_key(mbedtls_ecp_group_id grp_id,
mbedtls_ecp_keypair *key,
const mbedtls_ecp_point *Q)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;

if (key->grp.id == MBEDTLS_ECP_DP_NONE) {
/* Group not set yet */
if ((ret = mbedtls_ecp_group_load(&key->grp, grp_id)) != 0) {
return ret;
}
} else if (key->grp.id != grp_id) {
/* Group mismatch */
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
return mbedtls_ecp_copy(&key->Q, Q);
}


#define ECP_CURVE25519_KEY_SIZE 32
#define ECP_CURVE448_KEY_SIZE 56
/*
Expand Down Expand Up @@ -3314,6 +3333,18 @@ int mbedtls_ecp_write_key(mbedtls_ecp_keypair *key,
return ret;
}

/*
* Write a public key.
*/
int mbedtls_ecp_write_public_key(const mbedtls_ecp_keypair *key,
int format, size_t *olen,
unsigned char *buf, size_t buflen)
{
return mbedtls_ecp_point_write_binary(&key->grp, &key->Q,
format, olen, buf, buflen);
}


#if defined(MBEDTLS_ECP_C)
/*
* Check a public-private key pair
Expand Down Expand Up @@ -3355,8 +3386,22 @@ int mbedtls_ecp_check_pub_priv(

return ret;
}

int mbedtls_ecp_keypair_calc_public(mbedtls_ecp_keypair *key,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng)
{
return mbedtls_ecp_mul(&key->grp, &key->Q, &key->d, &key->grp.G,
f_rng, p_rng);
}
#endif /* MBEDTLS_ECP_C */

mbedtls_ecp_group_id mbedtls_ecp_keypair_get_group_id(
const mbedtls_ecp_keypair *key)
{
return key->grp.id;
}

/*
* Export generic key-pair parameters.
*/
Expand All @@ -3365,15 +3410,15 @@ int mbedtls_ecp_export(const mbedtls_ecp_keypair *key, mbedtls_ecp_group *grp,
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;

if ((ret = mbedtls_ecp_group_copy(grp, &key->grp)) != 0) {
if (grp != NULL && (ret = mbedtls_ecp_group_copy(grp, &key->grp)) != 0) {
return ret;
}

if ((ret = mbedtls_mpi_copy(d, &key->d)) != 0) {
if (d != NULL && (ret = mbedtls_mpi_copy(d, &key->d)) != 0) {
return ret;
}

if ((ret = mbedtls_ecp_copy(Q, &key->Q)) != 0) {
if (Q != NULL && (ret = mbedtls_ecp_copy(Q, &key->Q)) != 0) {
return ret;
}

Expand Down
23 changes: 13 additions & 10 deletions programs/pkey/ecdsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ static void dump_pubkey(const char *title, mbedtls_ecdsa_context *key)
unsigned char buf[300];
size_t len;

if (mbedtls_ecp_point_write_binary(&key->MBEDTLS_PRIVATE(grp), &key->MBEDTLS_PRIVATE(Q),
MBEDTLS_ECP_PF_UNCOMPRESSED, &len, buf, sizeof(buf)) != 0) {
if (mbedtls_ecp_write_public_key(key, MBEDTLS_ECP_PF_UNCOMPRESSED,
&len, buf, sizeof(buf)) != 0) {
mbedtls_printf("internal error\n");
return;
}
Expand All @@ -79,6 +79,8 @@ int main(int argc, char *argv[])
int ret = 1;
int exit_code = MBEDTLS_EXIT_FAILURE;
mbedtls_ecdsa_context ctx_sign, ctx_verify;
mbedtls_ecp_point Q;
mbedtls_ecp_point_init(&Q);
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
unsigned char message[100];
Expand Down Expand Up @@ -128,7 +130,10 @@ int main(int argc, char *argv[])
goto exit;
}

mbedtls_printf(" ok (key size: %d bits)\n", (int) ctx_sign.MBEDTLS_PRIVATE(grp).pbits);
mbedtls_ecp_group_id grp_id = mbedtls_ecp_keypair_get_group_id(&ctx_sign);
const mbedtls_ecp_curve_info *curve_info =
mbedtls_ecp_curve_info_from_grp_id(grp_id);
mbedtls_printf(" ok (key size: %d bits)\n", (int) curve_info->bit_size);

dump_pubkey(" + Public key: ", &ctx_sign);

Expand Down Expand Up @@ -174,16 +179,13 @@ int main(int argc, char *argv[])
mbedtls_printf(" . Preparing verification context...");
fflush(stdout);

if ((ret =
mbedtls_ecp_group_copy(&ctx_verify.MBEDTLS_PRIVATE(grp),
&ctx_sign.MBEDTLS_PRIVATE(grp))) != 0) {
mbedtls_printf(" failed\n ! mbedtls_ecp_group_copy returned %d\n", ret);
if ((ret = mbedtls_ecp_export(&ctx_sign, NULL, NULL, &Q)) != 0) {
mbedtls_printf(" failed\n ! mbedtls_ecp_export returned %d\n", ret);
goto exit;
}

if ((ret =
mbedtls_ecp_copy(&ctx_verify.MBEDTLS_PRIVATE(Q), &ctx_sign.MBEDTLS_PRIVATE(Q))) != 0) {
mbedtls_printf(" failed\n ! mbedtls_ecp_copy returned %d\n", ret);
if ((ret = mbedtls_ecp_set_public_key(grp_id, &ctx_verify, &Q)) != 0) {
mbedtls_printf(" failed\n ! mbedtls_ecp_set_public_key returned %d\n", ret);
goto exit;
}

Expand All @@ -208,6 +210,7 @@ int main(int argc, char *argv[])

mbedtls_ecdsa_free(&ctx_verify);
mbedtls_ecdsa_free(&ctx_sign);
mbedtls_ecp_point_free(&Q);
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);

Expand Down
Loading

0 comments on commit b1f96c0

Please sign in to comment.