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

Investigate ECP light #7357

Closed
wants to merge 9 commits into from
5 changes: 5 additions & 0 deletions include/mbedtls/ecp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1214,10 +1214,15 @@ int mbedtls_ecp_gen_keypair_base(mbedtls_ecp_group *grp,
* \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code
* on failure.
*/
#if defined(ECP_FULL)
int mbedtls_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);
#else
int mbedtls_ecp_alt_gen_keypair(mbedtls_ecp_group *grp, mbedtls_mpi *d,
mbedtls_ecp_point *Q);
#endif

/**
* \brief This function generates an ECP key.
Expand Down
89 changes: 87 additions & 2 deletions library/ecp.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@

#include <string.h>

#if defined(MBEDTLS_PSA_CRYPTO_C)
#include "mbedtls/psa_util.h"
#endif

#if defined(MBEDTLS_USE_PSA_CRYPTO)
#include "psa/crypto.h"
#endif

#if !defined(MBEDTLS_ECP_ALT)

#include "mbedtls/platform.h"
Expand All @@ -93,7 +101,10 @@
* Counts of point addition and doubling, and field multiplications.
* Used to test resistance of point multiplication to simple timing attacks.
*/
static unsigned long add_count, dbl_count, mul_count;
#if defined(ECP_FULL)
static unsigned long add_count, dbl_count;
#endif /* ECP_FULL */
static unsigned long mul_count;
#endif

#if defined(MBEDTLS_ECP_RESTARTABLE)
Expand Down Expand Up @@ -320,6 +331,7 @@ int mbedtls_ecp_check_budget(const mbedtls_ecp_group *grp,

#endif /* MBEDTLS_ECP_RESTARTABLE */

#if defined(ECP_FULL)
static void mpi_init_many(mbedtls_mpi *arr, size_t size)
{
while (size--) {
Expand All @@ -333,6 +345,7 @@ static void mpi_free_many(mbedtls_mpi *arr, size_t size)
mbedtls_mpi_free(arr++);
}
}
#endif /* ECP_FULL */

/*
* List of supported curves:
Expand Down Expand Up @@ -1306,7 +1319,10 @@ static int mbedtls_ecp_sw_derive_y(const mbedtls_ecp_group *grp,
mbedtls_mpi_free(&exp);
return ret;
}
#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */

#if defined(ECP_FULL)
#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
/*
* For curves in short Weierstrass form, we do all the internal operations in
* Jacobian coordinates.
Expand Down Expand Up @@ -2723,6 +2739,7 @@ int mbedtls_ecp_mul(mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
{
return mbedtls_ecp_mul_restartable(grp, R, m, P, f_rng, p_rng, NULL);
}
#endif /* ECP_FULL */

#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
/*
Expand Down Expand Up @@ -2763,6 +2780,7 @@ static int ecp_check_pubkey_sw(const mbedtls_ecp_group *grp, const mbedtls_ecp_p
}
#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */

#if defined(ECP_FULL)
#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
/*
* R = m * P with shortcuts for m == 0, m == 1 and m == -1
Expand Down Expand Up @@ -2914,6 +2932,7 @@ int mbedtls_ecp_muladd(mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
return mbedtls_ecp_muladd_restartable(grp, R, m, P, n, Q, NULL);
}
#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
#endif /* ECP_FULL */

#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED)
Expand Down Expand Up @@ -3159,6 +3178,7 @@ int mbedtls_ecp_gen_privkey(const mbedtls_ecp_group *grp,
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}

#if defined(ECP_FULL)
/*
* Generate a keypair with configurable base point
*/
Expand Down Expand Up @@ -3186,6 +3206,57 @@ int mbedtls_ecp_gen_keypair(mbedtls_ecp_group *grp,
{
return mbedtls_ecp_gen_keypair_base(grp, &grp->G, d, Q, f_rng, p_rng);
}
#else /* ECP_FULL */
int mbedtls_ecp_alt_gen_keypair(mbedtls_ecp_group *grp,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking good, but I'm not sure the implementation belongs here, as opposed to test_suite_pk.function which seems to be the only place using this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the mbedtls_ecp_alt_gen_keypair function itself is only explicitly called by test_suite_pk.function, but it is also indirectly called from mbedtls_ecp_gen_key which is instead used also elsewhere such as psa_crypto_ecp.c and test_suite_ecp.function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, thanks for the info. Regarding test_suite_ecp.function I think that's pretty simple: we'll just skip those cases. For psa_crypto_ecp.c I'll have a look right now. (I had grepped for mbedtls_ecp_gen_key() before commenting, but had completely missed the line from psa_crypto_ecp.c in the results. Should have looked more carefully.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just had a look, and the call in psa_crypto_ecp.c is guarded by MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR so it shouldn't be a problem in builds where KEY_TYPE_ECC_KEY_PAIR is accelerated, which are our target here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding test_suite_ecp.function I think that's pretty simple: we'll just skip those cases

Yes, sorry for not thinking about this, but it doesn't make much sense to test the ECP module with functions that are actually outside it. I'll fix this!

mbedtls_mpi *d, mbedtls_ecp_point *Q)
{
psa_status_t status;
psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
size_t curve_bits;
psa_ecc_family_t curve = mbedtls_ecc_group_to_psa(grp->id,
&curve_bits);
unsigned char key_buf[MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH];
size_t key_len;
int ret;

psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(curve));
psa_set_key_bits(&key_attr, curve_bits);
psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_EXPORT);

status = psa_generate_key(&key_attr, &key_id);
if (status != PSA_SUCCESS) {
return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
}

status = psa_export_key(key_id, key_buf, sizeof(key_buf), &key_len);
if (status != PSA_SUCCESS) {
psa_destroy_key(key_id);
return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
}

ret = mbedtls_mpi_read_binary(d, key_buf, key_len);
if (ret != 0) {
return ret;
}

status = psa_export_public_key(key_id, key_buf, sizeof(key_buf),
&key_len);
if (status != PSA_SUCCESS) {
psa_destroy_key(key_id);
return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
}

ret = mbedtls_ecp_point_read_binary(grp, Q, key_buf, key_len);
if (ret != 0) {
return ret;
}

psa_destroy_key(key_id);

return 0;
}
#endif /* ECP_FULL */

/*
* Generate a keypair, prettier wrapper
Expand All @@ -3198,7 +3269,13 @@ int mbedtls_ecp_gen_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key,
return ret;
}

#if defined(ECP_FULL)
return mbedtls_ecp_gen_keypair(&key->grp, &key->d, &key->Q, f_rng, p_rng);
#else
(void)f_rng;
(void)p_rng;
return mbedtls_ecp_alt_gen_keypair(&key->grp, &key->d, &key->Q);
#endif
}

#define ECP_CURVE25519_KEY_SIZE 32
Expand Down Expand Up @@ -3316,7 +3393,7 @@ int mbedtls_ecp_write_key(mbedtls_ecp_keypair *key,
return ret;
}


#if defined(ECP_FULL)
/*
* Check a public-private key pair
*/
Expand Down Expand Up @@ -3357,6 +3434,7 @@ int mbedtls_ecp_check_pub_priv(

return ret;
}
#endif /* ECP_FULL */

/*
* Export generic key-pair parameters.
Expand All @@ -3383,6 +3461,7 @@ int mbedtls_ecp_export(const mbedtls_ecp_keypair *key, mbedtls_ecp_group *grp,

#if defined(MBEDTLS_SELF_TEST)

#if defined(ECP_FULL)
/*
* PRNG for test - !!!INSECURE NEVER USE IN PRODUCTION!!!
*
Expand Down Expand Up @@ -3490,12 +3569,14 @@ static int self_test_point(int verbose,
}
return ret;
}
#endif /* ECP_FULL */

/*
* Checkup routine
*/
int mbedtls_ecp_self_test(int verbose)
{
#if defined(ECP_FULL)
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_ecp_group grp;
mbedtls_ecp_point R, P;
Expand Down Expand Up @@ -3609,6 +3690,10 @@ int mbedtls_ecp_self_test(int verbose)
}

return ret;
#else /* ECP_FULL */
(void) verbose;
return 0;
#endif /* ECP_FULL */
}

#endif /* MBEDTLS_SELF_TEST */
Expand Down
104 changes: 104 additions & 0 deletions library/pk_wrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1095,13 +1095,117 @@ static int eckey_sign_rs_wrap(void *ctx, mbedtls_md_type_t md_alg,
}
#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */

#if !defined(ECP_FULL)
/*
* Alternative function used to verify that the EC private/public key pair
* is valid using PSA functions instead of ECP ones.
* The flow is:
* - sign a hash message using the provided private key
* - verify the signature using the public key
*/
static int eckey_alt_check_pair(const void *pub, const void *prv,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng)
{
(void)f_rng;
(void)p_rng;
psa_status_t status;
psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
mbedtls_ecp_keypair *prv_ctx = (mbedtls_ecp_keypair *) prv;
mbedtls_ecp_keypair *pub_ctx = (mbedtls_ecp_keypair *) pub;
unsigned char sig[MBEDTLS_MPI_MAX_SIZE];
size_t sig_len = 0;
unsigned char hash[32];
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t curve_bits;
psa_ecc_family_t curve =
mbedtls_ecc_group_to_psa(prv_ctx->grp.id, &curve_bits);
unsigned char key_buf[MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH];
size_t key_len = PSA_BITS_TO_BYTES(curve_bits);
mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;

memset(hash, 0x2a, sizeof(hash));

psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(curve));
psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_SIGN_HASH);
// TODO: forcing SHA256 because this is included by default when building
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, this is a problem with the "sign-verify" approach I suggested, indeed. In the meantime, I had another idea, inspired by what you did for key completion: we could just serialize the public key for both prv and pub (using mbedtls_pk_write_pubkey() I think) and see if the results are identical.

(Then later when #7202 is done, that would be mbedtls_pk_write_pubkey() on prv and directly compare to the byte array in pub, then when and its private counterpart is done, that would be psa_import() + psa_export_public() on prv and compare to byte array in pub.)

Wdyt?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this idea!
However I have a question: since also for the key creation we are already importing the private key into PSA to get its public part, why can't we go that way directly also here? In theory also 7202 is a sort of middle step toward having everything on the PSA side (or at least there is a discussion on this)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's continue this discussion in #7387.

// the library (even though it's not granted that the built-in version
// is supported). Is there a more general purpose solution?
psa_set_key_algorithm(&key_attr, PSA_ALG_ECDSA(PSA_ALG_SHA_256));

ret = mbedtls_mpi_write_binary(&prv_ctx->d, key_buf, key_len);
if (ret != 0) {
return ret;
}

status = psa_import_key(&key_attr, key_buf, key_len, &key_id);
if (status != PSA_SUCCESS) {
ret = PSA_PK_TO_MBEDTLS_ERR(status);
return ret;
}

status = psa_sign_hash(key_id, PSA_ALG_ECDSA(PSA_ALG_SHA_256),
hash, sizeof(hash), sig, sizeof(sig), &sig_len);
if (status != PSA_SUCCESS) {
ret = PSA_PK_TO_MBEDTLS_ERR(status);
status = psa_destroy_key(key_id);
return (status != PSA_SUCCESS) ? PSA_PK_TO_MBEDTLS_ERR(status) : ret;
}

status = psa_destroy_key(key_id);
if (status != PSA_SUCCESS) {
return PSA_PK_TO_MBEDTLS_ERR(status);
}
psa_reset_key_attributes(&key_attr);
mbedtls_platform_zeroize(key_buf, sizeof(key_buf));

psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve));
psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_VERIFY_HASH);
psa_set_key_algorithm(&key_attr, PSA_ALG_ECDSA(PSA_ALG_SHA_256));

ret = mbedtls_ecp_point_write_binary(&pub_ctx->grp, &pub_ctx->Q,
MBEDTLS_ECP_PF_UNCOMPRESSED,
&key_len, key_buf, sizeof(key_buf));
if (ret != 0) {
return ret;
}

status = psa_import_key(&key_attr, key_buf, key_len, &key_id);
if (status != PSA_SUCCESS) {
ret = PSA_PK_TO_MBEDTLS_ERR(status);
return ret;
}

status = psa_verify_hash(key_id, PSA_ALG_ECDSA(PSA_ALG_SHA_256),
hash, sizeof(hash), sig, sig_len);
if (status != PSA_SUCCESS) {
ret = PSA_PK_TO_MBEDTLS_ERR(status);
status = psa_destroy_key(key_id);
return (status != PSA_SUCCESS) ? PSA_PK_TO_MBEDTLS_ERR(status) : ret;
}
status = psa_destroy_key(key_id);
if (status != PSA_SUCCESS) {
return PSA_PK_TO_MBEDTLS_ERR(status);
}

return 0;
}
#endif /* ECP_FULL */

static int eckey_check_pair(const void *pub, const void *prv,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng)
{
#if defined(ECP_FULL)
return mbedtls_ecp_check_pub_priv((const mbedtls_ecp_keypair *) pub,
(const mbedtls_ecp_keypair *) prv,
f_rng, p_rng);
#else /* ECP_FULL */
return eckey_alt_check_pair((const mbedtls_ecp_keypair *) pub,
(const mbedtls_ecp_keypair *) prv,
f_rng, p_rng);
#endif /* ECP_FULL */
return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
}

static void *eckey_alloc_wrap(void)
Expand Down
Loading