crypto: ecdh - fix concurrency on shared secret and pubkey
ecdh_ctx contained static allocated data for the shared secret and public key. The shared secret and the public key were doomed to concurrency issues because they could be shared by multiple crypto requests. The concurrency is fixed by replacing per-tfm shared secret and public key with per-request dynamically allocated shared secret and public key. Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
parent
0876d16124
commit
952035baed
|
@ -20,8 +20,6 @@ struct ecdh_ctx {
|
||||||
unsigned int curve_id;
|
unsigned int curve_id;
|
||||||
unsigned int ndigits;
|
unsigned int ndigits;
|
||||||
u64 private_key[ECC_MAX_DIGITS];
|
u64 private_key[ECC_MAX_DIGITS];
|
||||||
u64 public_key[2 * ECC_MAX_DIGITS];
|
|
||||||
u64 shared_secret[ECC_MAX_DIGITS];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct ecdh_ctx *ecdh_get_ctx(struct crypto_kpp *tfm)
|
static inline struct ecdh_ctx *ecdh_get_ctx(struct crypto_kpp *tfm)
|
||||||
|
@ -70,41 +68,58 @@ static int ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
|
||||||
|
|
||||||
static int ecdh_compute_value(struct kpp_request *req)
|
static int ecdh_compute_value(struct kpp_request *req)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
|
||||||
struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
|
struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
|
||||||
struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
|
struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
|
||||||
size_t copied, nbytes;
|
u64 *public_key;
|
||||||
|
u64 *shared_secret = NULL;
|
||||||
void *buf;
|
void *buf;
|
||||||
|
size_t copied, nbytes, public_key_sz;
|
||||||
|
int ret = -ENOMEM;
|
||||||
|
|
||||||
nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
|
nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
|
||||||
|
/* Public part is a point thus it has both coordinates */
|
||||||
|
public_key_sz = 2 * nbytes;
|
||||||
|
|
||||||
|
public_key = kmalloc(public_key_sz, GFP_KERNEL);
|
||||||
|
if (!public_key)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
if (req->src) {
|
if (req->src) {
|
||||||
copied = sg_copy_to_buffer(req->src, 1, ctx->public_key,
|
shared_secret = kmalloc(nbytes, GFP_KERNEL);
|
||||||
2 * nbytes);
|
if (!shared_secret)
|
||||||
if (copied != 2 * nbytes)
|
goto free_pubkey;
|
||||||
return -EINVAL;
|
|
||||||
|
copied = sg_copy_to_buffer(req->src, 1, public_key,
|
||||||
|
public_key_sz);
|
||||||
|
if (copied != public_key_sz) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto free_all;
|
||||||
|
}
|
||||||
|
|
||||||
ret = crypto_ecdh_shared_secret(ctx->curve_id, ctx->ndigits,
|
ret = crypto_ecdh_shared_secret(ctx->curve_id, ctx->ndigits,
|
||||||
ctx->private_key,
|
ctx->private_key, public_key,
|
||||||
ctx->public_key,
|
shared_secret);
|
||||||
ctx->shared_secret);
|
|
||||||
|
|
||||||
buf = ctx->shared_secret;
|
buf = shared_secret;
|
||||||
} else {
|
} else {
|
||||||
ret = ecc_make_pub_key(ctx->curve_id, ctx->ndigits,
|
ret = ecc_make_pub_key(ctx->curve_id, ctx->ndigits,
|
||||||
ctx->private_key, ctx->public_key);
|
ctx->private_key, public_key);
|
||||||
buf = ctx->public_key;
|
buf = public_key;
|
||||||
/* Public part is a point thus it has both coordinates */
|
nbytes = public_key_sz;
|
||||||
nbytes *= 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
goto free_all;
|
||||||
|
|
||||||
copied = sg_copy_from_buffer(req->dst, 1, buf, nbytes);
|
copied = sg_copy_from_buffer(req->dst, 1, buf, nbytes);
|
||||||
if (copied != nbytes)
|
if (copied != nbytes)
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
|
||||||
|
/* fall through */
|
||||||
|
free_all:
|
||||||
|
kzfree(shared_secret);
|
||||||
|
free_pubkey:
|
||||||
|
kfree(public_key);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue