crypto: crypto4xx - overhaul crypto4xx_build_pd()

This patch overhauls and fixes code related to crypto4xx_build_pd()

 * crypto4xx_build_pd() did not handle chained source scatterlist.
   This is fixed by replacing the buggy indexed-access of &src[idx]
   with sg_next() in the gather array setup loop.

 * The redundant is_hash, direction, save_iv and pd_ctl members
   in the crypto4xx_ctx struct have been removed.
    - is_hash can be derived from the crypto_async_request parameter.
    - direction is already part of the security association's
      bf.dir bitfield.
    - save_iv is unused.
    - pd_ctl always had the host_ready bit enabled anyway.
      (the hash_final case is rather pointless, since the ahash
       code has been deactivated).

 * make crypto4xx_build_pd()'s caller responsible for converting
   the IV to the LE32 format.

 * change crypto4xx_ahash_update() and crypto4xx_ahash_digest() to
   initialize a temporary destination scatterlist. This allows the
   removal of an ugly cast of req->result (which is a pointer to an
   u8-array) to a scatterlist pointer.

 * change crypto4xx_build_pd() return type to int. After all
   it returns -EINPROGRESS/-EBUSY.

 * fix crypto4xx_build_pd() thread-unsafe sa handling.

Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
Christian Lamparter
2017-10-04 01:00:11 +02:00
committed by Herbert Xu
parent 4865b122d4
commit cd4dcd6da7
3 changed files with 103 additions and 124 deletions

View File

@@ -75,27 +75,29 @@ static void set_dynamic_sa_command_1(struct dynamic_sa_ctl *sa, u32 cm,
int crypto4xx_encrypt(struct ablkcipher_request *req)
{
struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
unsigned int ivlen = crypto_ablkcipher_ivsize(
crypto_ablkcipher_reqtfm(req));
__le32 iv[ivlen];
ctx->direction = DIR_OUTBOUND;
ctx->is_hash = 0;
ctx->pd_ctl = 0x1;
if (ivlen)
crypto4xx_memcpy_to_le32(iv, req->info, ivlen);
return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
req->nbytes, req->info,
crypto_ablkcipher_ivsize(crypto_ablkcipher_reqtfm(req)));
req->nbytes, iv, ivlen, ctx->sa_out, ctx->sa_len);
}
int crypto4xx_decrypt(struct ablkcipher_request *req)
{
struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
unsigned int ivlen = crypto_ablkcipher_ivsize(
crypto_ablkcipher_reqtfm(req));
__le32 iv[ivlen];
ctx->direction = DIR_INBOUND;
ctx->is_hash = 0;
ctx->pd_ctl = 1;
if (ivlen)
crypto4xx_memcpy_to_le32(iv, req->info, ivlen);
return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
req->nbytes, req->info,
crypto_ablkcipher_ivsize(crypto_ablkcipher_reqtfm(req)));
req->nbytes, iv, ivlen, ctx->sa_in, ctx->sa_len);
}
/**
@@ -153,11 +155,6 @@ static int crypto4xx_setkey_aes(struct crypto_ablkcipher *cipher,
key, keylen);
sa->sa_contents.w = SA_AES_CONTENTS | (keylen << 2);
sa->sa_command_1.bf.key_len = keylen >> 3;
ctx->is_hash = 0;
ctx->direction = DIR_INBOUND;
memcpy(sa + get_dynamic_sa_offset_state_ptr_field(sa),
(void *)&ctx->state_record_dma_addr, 4);
ctx->offset_to_sr_ptr = get_dynamic_sa_offset_state_ptr_field(sa);
memcpy(ctx->sa_out, ctx->sa_in, ctx->sa_len * 4);
sa = ctx->sa_out;
@@ -206,7 +203,7 @@ int crypto4xx_setkey_rfc3686(struct crypto_ablkcipher *cipher,
if (rc)
return rc;
memcpy(ctx->state_record,
crypto4xx_memcpy_to_le32(ctx->state_record->save_iv,
key + keylen - CTR_RFC3686_NONCE_SIZE, CTR_RFC3686_NONCE_SIZE);
return 0;
@@ -215,27 +212,29 @@ int crypto4xx_setkey_rfc3686(struct crypto_ablkcipher *cipher,
int crypto4xx_rfc3686_encrypt(struct ablkcipher_request *req)
{
struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
__be32 iv[AES_IV_SIZE / 4] = { *(u32 *)ctx->state_record,
*(u32 *) req->info, *(u32 *) (req->info + 4), cpu_to_be32(1) };
ctx->direction = DIR_OUTBOUND;
ctx->pd_ctl = 1;
__le32 iv[AES_IV_SIZE / 4] = {
ctx->state_record->save_iv[0],
cpu_to_le32p((u32 *) req->info),
cpu_to_le32p((u32 *) (req->info + 4)),
cpu_to_le32(1) };
return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
req->nbytes, iv, AES_IV_SIZE);
req->nbytes, iv, AES_IV_SIZE,
ctx->sa_out, ctx->sa_len);
}
int crypto4xx_rfc3686_decrypt(struct ablkcipher_request *req)
{
struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
__be32 iv[AES_IV_SIZE / 4] = { *(u32 *)ctx->state_record,
*(u32 *) req->info, *(u32 *) (req->info + 4), cpu_to_be32(1) };
ctx->direction = DIR_INBOUND;
ctx->pd_ctl = 1;
__le32 iv[AES_IV_SIZE / 4] = {
ctx->state_record->save_iv[0],
cpu_to_le32p((u32 *) req->info),
cpu_to_le32p((u32 *) (req->info + 4)),
cpu_to_le32(1) };
return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
req->nbytes, iv, AES_IV_SIZE);
req->nbytes, iv, AES_IV_SIZE,
ctx->sa_out, ctx->sa_len);
}
/**
@@ -253,7 +252,6 @@ static int crypto4xx_hash_alg_init(struct crypto_tfm *tfm,
int rc;
ctx->dev = my_alg->dev;
ctx->is_hash = 1;
/* Create SA */
if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr)
@@ -284,13 +282,9 @@ static int crypto4xx_hash_alg_init(struct crypto_tfm *tfm,
SA_SEQ_MASK_OFF, SA_MC_ENABLE,
SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD,
SA_NOT_COPY_HDR);
ctx->direction = DIR_INBOUND;
/* Need to zero hash digest in SA */
memset(sa->inner_digest, 0, sizeof(sa->inner_digest));
memset(sa->outer_digest, 0, sizeof(sa->outer_digest));
sa->state_ptr = ctx->state_record_dma_addr;
ctx->offset_to_sr_ptr =
get_dynamic_sa_offset_state_ptr_field(&sa->ctrl);
return 0;
}
@@ -306,23 +300,22 @@ int crypto4xx_hash_init(struct ahash_request *req)
__crypto_ahash_cast(req->base.tfm));
sa->sa_command_0.bf.digest_len = ds >> 2;
sa->sa_command_0.bf.load_hash_state = SA_LOAD_HASH_FROM_SA;
ctx->is_hash = 1;
ctx->direction = DIR_INBOUND;
return 0;
}
int crypto4xx_hash_update(struct ahash_request *req)
{
struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
struct scatterlist dst;
unsigned int ds = crypto_ahash_digestsize(ahash);
ctx->is_hash = 1;
ctx->pd_ctl = 0x11;
ctx->direction = DIR_INBOUND;
sg_init_one(&dst, req->result, ds);
return crypto4xx_build_pd(&req->base, ctx, req->src,
(struct scatterlist *) req->result,
req->nbytes, NULL, 0);
return crypto4xx_build_pd(&req->base, ctx, req->src, &dst,
req->nbytes, NULL, 0, ctx->sa_in,
ctx->sa_len);
}
int crypto4xx_hash_final(struct ahash_request *req)
@@ -332,14 +325,16 @@ int crypto4xx_hash_final(struct ahash_request *req)
int crypto4xx_hash_digest(struct ahash_request *req)
{
struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
struct scatterlist dst;
unsigned int ds = crypto_ahash_digestsize(ahash);
ctx->pd_ctl = 0x11;
ctx->direction = DIR_INBOUND;
sg_init_one(&dst, req->result, ds);
return crypto4xx_build_pd(&req->base, ctx, req->src,
(struct scatterlist *) req->result,
req->nbytes, NULL, 0);
return crypto4xx_build_pd(&req->base, ctx, req->src, &dst,
req->nbytes, NULL, 0, ctx->sa_in,
ctx->sa_len);
}
/**