Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ECP keypair utility functions #7815

Merged
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
mpg marked this conversation as resolved.
Show resolved Hide resolved
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.
mpg marked this conversation as resolved.
Show resolved Hide resolved
* 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.
mpg marked this conversation as resolved.
Show resolved Hide resolved
* 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