Hi! > ecdh_set_secret() casts a void* pointer to a const u64* in order to > feed it into ecc_is_key_valid(). This is not generally permitted by > the C standard, and leads to actual misalignment faults on ARMv6 > cores. In some cases, these are fixed up in software, but this still > leads to performance hits that are entirely avoidable. > > So let's copy the key into the ctx buffer first, which we will do > anyway in the common case, and which guarantees correct alignment. Fair enough... but: params.key_size is validated in ecc_is_key_valid(), and that now happens _after_ memcpy. How is it guaranteed that we don't overflow the buffer during memcpy? > +++ b/crypto/ecdh.c > @@ -57,12 +57,13 @@ static int ecdh_set_secret(struct crypto > return ecc_gen_privkey(ctx->curve_id, ctx->ndigits, > ctx->private_key); > > - if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits, > - (const u64 *)params.key, params.key_size) < 0) > - return -EINVAL; > - > memcpy(ctx->private_key, params.key, params.key_size); > > + if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits, > + ctx->private_key, params.key_size) < 0) { > + memzero_explicit(ctx->private_key, params.key_size); > + return -EINVAL; > + } > return 0; Best regards, Pavel -- DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
On Thu, 31 Dec 2020 at 21:09, Pavel Machek <pavel@denx.de> wrote: > > Hi! > > > ecdh_set_secret() casts a void* pointer to a const u64* in order to > > feed it into ecc_is_key_valid(). This is not generally permitted by > > the C standard, and leads to actual misalignment faults on ARMv6 > > cores. In some cases, these are fixed up in software, but this still > > leads to performance hits that are entirely avoidable. > > > > So let's copy the key into the ctx buffer first, which we will do > > anyway in the common case, and which guarantees correct alignment. > > Fair enough... but: params.key_size is validated in > ecc_is_key_valid(), and that now happens _after_ memcpy. > > How is it guaranteed that we don't overflow the buffer during memcpy? > It is not, thanks for pointing that out. There are some redundant checks being performed, so you won't trigger it easily with fuzzing, but afaict, an intentionally crafted invalid input could indeed overflow the buffer. I'll send a fix shortly. > > +++ b/crypto/ecdh.c > > @@ -57,12 +57,13 @@ static int ecdh_set_secret(struct crypto > > return ecc_gen_privkey(ctx->curve_id, ctx->ndigits, > > ctx->private_key); > > > > - if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits, > > - (const u64 *)params.key, params.key_size) < 0) > > - return -EINVAL; > > - > > memcpy(ctx->private_key, params.key, params.key_size); > > > > + if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits, > > + ctx->private_key, params.key_size) < 0) { > > + memzero_explicit(ctx->private_key, params.key_size); > > + return -EINVAL; > > + } > > return 0; > > Best regards, > Pavel > -- > DENX Software Engineering GmbH, Managing Director: Wolfgang Denk > HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
--- a/crypto/ecdh.c +++ b/crypto/ecdh.c @@ -57,12 +57,13 @@ static int ecdh_set_secret(struct crypto return ecc_gen_privkey(ctx->curve_id, ctx->ndigits, ctx->private_key); - if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits, - (const u64 *)params.key, params.key_size) < 0) - return -EINVAL; - memcpy(ctx->private_key, params.key, params.key_size); + if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits, + ctx->private_key, params.key_size) < 0) { + memzero_explicit(ctx->private_key, params.key_size); + return -EINVAL; + } return 0; }