Am Donnerstag, 13. Oktober 2016, 09:53:09 CEST schrieb Gary R Hook:

Hi Gary,

> Wire up the v3 CCP as a cipher provider.
> 
> Signed-off-by: Gary R Hook <gary.h...@amd.com>
> ---
>  drivers/crypto/ccp/Makefile          |    1
>  drivers/crypto/ccp/ccp-crypto-main.c |   15 ++
>  drivers/crypto/ccp/ccp-crypto-rsa.c  |  258
> ++++++++++++++++++++++++++++++++++ drivers/crypto/ccp/ccp-crypto.h      |  
> 24 +++
>  drivers/crypto/ccp/ccp-dev-v3.c      |   38 +++++
>  drivers/crypto/ccp/ccp-ops.c         |    1
>  include/linux/ccp.h                  |   34 ++++
>  7 files changed, 370 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/crypto/ccp/ccp-crypto-rsa.c
> 
> diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile
> index 346ceb8..23f89b7 100644
> --- a/drivers/crypto/ccp/Makefile
> +++ b/drivers/crypto/ccp/Makefile
> @@ -12,4 +12,5 @@ ccp-crypto-objs := ccp-crypto-main.o \
>                  ccp-crypto-aes.o \
>                  ccp-crypto-aes-cmac.o \
>                  ccp-crypto-aes-xts.o \
> +                ccp-crypto-rsa.o \
>                  ccp-crypto-sha.o
> diff --git a/drivers/crypto/ccp/ccp-crypto-main.c
> b/drivers/crypto/ccp/ccp-crypto-main.c index e0380e5..f3c4c25 100644
> --- a/drivers/crypto/ccp/ccp-crypto-main.c
> +++ b/drivers/crypto/ccp/ccp-crypto-main.c
> @@ -33,6 +33,10 @@ static unsigned int sha_disable;
>  module_param(sha_disable, uint, 0444);
>  MODULE_PARM_DESC(sha_disable, "Disable use of SHA - any non-zero value");
> 
> +static unsigned int rsa_disable;
> +module_param(rsa_disable, uint, 0444);
> +MODULE_PARM_DESC(rsa_disable, "Disable use of RSA - any non-zero value");
> +
>  /* List heads for the supported algorithms */
>  static LIST_HEAD(hash_algs);
>  static LIST_HEAD(cipher_algs);
> @@ -343,6 +347,14 @@ static int ccp_register_algs(void)
>                       return ret;
>       }
> 
> +     if (!rsa_disable) {
> +             ret = ccp_register_rsa_algs();
> +             if (ret) {
> +                     rsa_disable = 1;
> +                     return ret;
> +             }
> +     }
> +
>       return 0;
>  }
> 
> @@ -362,6 +374,9 @@ static void ccp_unregister_algs(void)
>               list_del(&ablk_alg->entry);
>               kfree(ablk_alg);
>       }
> +
> +     if (!rsa_disable)
> +             ccp_unregister_rsa_algs();
>  }
> 
>  static int ccp_crypto_init(void)
> diff --git a/drivers/crypto/ccp/ccp-crypto-rsa.c
> b/drivers/crypto/ccp/ccp-crypto-rsa.c new file mode 100644
> index 0000000..7dab43b
> --- /dev/null
> +++ b/drivers/crypto/ccp/ccp-crypto-rsa.c
> @@ -0,0 +1,258 @@
> +/*
> + * AMD Cryptographic Coprocessor (CCP) RSA crypto API support
> + *
> + * Copyright (C) 2016 Advanced Micro Devices, Inc.
> + *
> + * Author: Gary R Hook <gary.h...@amd.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/sched.h>
> +#include <linux/mpi.h>
> +#include <linux/scatterlist.h>
> +#include <linux/crypto.h>
> +#include <crypto/algapi.h>
> +#include <crypto/internal/akcipher.h>
> +#include <crypto/akcipher.h>
> +#include <crypto/scatterwalk.h>
> +
> +#include "ccp-crypto.h"
> +
> +static inline struct akcipher_request *akcipher_request_cast(
> +     struct crypto_async_request *req)
> +{
> +     return container_of(req, struct akcipher_request, base);
> +}
> +
> +static int ccp_rsa_complete(struct crypto_async_request *async_req, int
> ret) +{
> +     struct akcipher_request *req = akcipher_request_cast(async_req);
> +     struct ccp_rsa_req_ctx *rctx = akcipher_request_ctx(req);
> +
> +     if (!ret)
> +             req->dst_len = rctx->cmd.u.rsa.d_len;
> +
> +     ret = 0;
> +
> +     return ret;
> +}
> +
> +static int ccp_rsa_maxsize(struct crypto_akcipher *tfm)
> +{
> +     return CCP_RSA_MAXMOD;
> +}
> +
> +static int ccp_rsa_crypt(struct akcipher_request *req, bool encrypt)
> +{
> +     struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
> +     struct ccp_ctx *ctx = akcipher_tfm_ctx(tfm);
> +     struct ccp_rsa_req_ctx *rctx = akcipher_request_ctx(req);
> +     int ret = 0;
> +
> +     if (!ctx->u.rsa.pkey.d && !ctx->u.rsa.pkey.e)
> +             return -EINVAL;
> +
> +     memset(&rctx->cmd, 0, sizeof(rctx->cmd));
> +     INIT_LIST_HEAD(&rctx->cmd.entry);
> +     rctx->cmd.engine = CCP_ENGINE_RSA;
> +     rctx->cmd.u.rsa.mode = encrypt ? CCP_RSA_ENCRYPT : CCP_RSA_DECRYPT;
> +
> +     rctx->cmd.u.rsa.pkey = ctx->u.rsa.pkey;
> +     rctx->cmd.u.rsa.key_size = ctx->u.rsa.key_len;
> +     rctx->cmd.u.rsa.exp = &ctx->u.rsa.e_sg;
> +     rctx->cmd.u.rsa.exp_len = ctx->u.rsa.e_len;
> +     rctx->cmd.u.rsa.mod = &ctx->u.rsa.n_sg;
> +     rctx->cmd.u.rsa.mod_len = ctx->u.rsa.n_len;
> +     if (ctx->u.rsa.pkey.d) {
> +             rctx->cmd.u.rsa.d_sg = &ctx->u.rsa.d_sg;
> +             rctx->cmd.u.rsa.d_len = ctx->u.rsa.d_len;
> +     }
> +
> +     rctx->cmd.u.rsa.src = req->src;
> +     rctx->cmd.u.rsa.src_len = req->src_len;
> +     rctx->cmd.u.rsa.dst = req->dst;
> +     rctx->cmd.u.rsa.dst_len = req->dst_len;
> +
> +     ret = ccp_crypto_enqueue_request(&req->base, &rctx->cmd);
> +
> +     return ret;
> +}
> +
> +static int ccp_rsa_encrypt(struct akcipher_request *req)
> +{
> +     return ccp_rsa_crypt(req, true);
> +}
> +
> +static int ccp_rsa_decrypt(struct akcipher_request *req)
> +{
> +     return ccp_rsa_crypt(req, false);
> +}
> +
> +static void ccp_free_mpi_key(struct ccp_rsa_key *key)
> +{
> +     mpi_free(key->d);
> +     key->d = NULL;
> +     mpi_free(key->e);
> +     key->e = NULL;
> +     mpi_free(key->n);
> +     key->n = NULL;
> +}

Could you please see whether that function can be turned into a common 
function call? crypto/rsa.c implements the same code in rsa_free_mpi_key.
> +
> +static int ccp_check_key_length(unsigned int len)
> +{
> +     /* In bits */
> +     if (len < 8 || len > 16384)
> +             return -EINVAL;
> +     return 0;
> +}
> +
> +static void ccp_rsa_free_key_bufs(struct ccp_ctx *ctx)
> +{
> +     /* Clean up old key data */
> +     kfree(ctx->u.rsa.e_buf);
> +     ctx->u.rsa.e_buf = NULL;
> +     ctx->u.rsa.e_len = 0;
> +     kfree(ctx->u.rsa.n_buf);
> +     ctx->u.rsa.n_buf = NULL;
> +     ctx->u.rsa.n_len = 0;
> +     kfree(ctx->u.rsa.d_buf);

kzfree, please.

> +     ctx->u.rsa.d_buf = NULL;
> +     ctx->u.rsa.d_len = 0;
> +}
> +
> +static int ccp_rsa_setkey(struct crypto_akcipher *tfm, const void *key,
> +                       unsigned int keylen, bool public)
> +{
> +     struct ccp_ctx *ctx = akcipher_tfm_ctx(tfm);
> +     struct rsa_key raw_key;
> +     unsigned int n_size;
> +     int ret;
> +
> +     if (!ctx)
> +             return -EINVAL;
> +
> +     ccp_rsa_free_key_bufs(ctx);
> +     memset(&raw_key, 0, sizeof(raw_key));
> +
> +     /* Code borrowed from crypto/rsa.c */
> +     if (public)
> +             ret = rsa_parse_pub_key(&raw_key, key, keylen);
> +     else
> +             ret = rsa_parse_priv_key(&raw_key, key, keylen);
> +     if (ret)
> +             goto e_ret;
> +
> +     ret = -EINVAL;
> +
> +     ctx->u.rsa.pkey.e = mpi_read_raw_data(raw_key.e, raw_key.e_sz);
> +     if (!ctx->u.rsa.pkey.e)
> +             goto e_ret;
> +     ctx->u.rsa.e_buf = mpi_get_buffer(ctx->u.rsa.pkey.e,
> +                                       &ctx->u.rsa.e_len, NULL);
> +     if (!ctx->u.rsa.e_buf)
> +             goto e_key;
> +     sg_init_one(&ctx->u.rsa.e_sg, ctx->u.rsa.e_buf, ctx->u.rsa.e_len);
> +
> +
> +     ctx->u.rsa.pkey.n = mpi_read_raw_data(raw_key.n, raw_key.n_sz);
> +     n_size = mpi_get_size(ctx->u.rsa.pkey.n);
> +     if (ccp_check_key_length(n_size << 3))
> +             goto e_key;
> +     ctx->u.rsa.key_len = n_size;
> +     ctx->u.rsa.n_buf = mpi_get_buffer(ctx->u.rsa.pkey.n,
> +                                       &ctx->u.rsa.n_len, NULL);
> +     if (!ctx->u.rsa.n_buf)
> +             goto e_nkey;
> +     sg_init_one(&ctx->u.rsa.n_sg, ctx->u.rsa.n_buf, ctx->u.rsa.n_len);
> +
> +     if (!public) {
> +             ctx->u.rsa.pkey.d = mpi_read_raw_data(raw_key.d, raw_key.d_sz);
> +             if (!ctx->u.rsa.pkey.d)
> +                     goto e_nkey;
> +             ctx->u.rsa.d_buf = mpi_get_buffer(ctx->u.rsa.pkey.d,
> +                                               &ctx->u.rsa.d_len, NULL);
> +             if (!ctx->u.rsa.d_buf)
> +                     goto e_dkey;
> +             sg_init_one(&ctx->u.rsa.d_sg, ctx->u.rsa.d_buf,
> +                         ctx->u.rsa.d_len);
> +     }
> +
> +     return 0;
> +
> +e_dkey:
> +     kfree(ctx->u.rsa.n_buf);
> +e_nkey:
> +     kfree(ctx->u.rsa.e_buf);
> +e_key:
> +     ccp_free_mpi_key(&ctx->u.rsa.pkey);
> +e_ret:
> +     return ret;
> +}
> +
> +static int ccp_rsa_setprivkey(struct crypto_akcipher *tfm, const void *key,
> +                           unsigned int keylen)
> +{
> +     return ccp_rsa_setkey(tfm, key, keylen, false);
> +}
> +
> +static int ccp_rsa_setpubkey(struct crypto_akcipher *tfm, const void *key,
> +                          unsigned int keylen)
> +{
> +     return ccp_rsa_setkey(tfm, key, keylen, true);
> +}
> +
> +static int ccp_rsa_init_tfm(struct crypto_akcipher *tfm)
> +{
> +     struct ccp_ctx *ctx = akcipher_tfm_ctx(tfm);
> +
> +     ctx->complete = ccp_rsa_complete;
> +
> +     return 0;
> +}
> +
> +static void ccp_rsa_exit_tfm(struct crypto_akcipher *tfm)
> +{
> +     struct ccp_ctx *ctx = crypto_tfm_ctx(&tfm->base);
> +
> +     ccp_rsa_free_key_bufs(ctx);
> +}
> +
> +static struct akcipher_alg rsa = {
> +     .encrypt = ccp_rsa_encrypt,
> +     .decrypt = ccp_rsa_decrypt,
> +     .sign = NULL,
> +     .verify = NULL,
> +     .set_pub_key = ccp_rsa_setpubkey,
> +     .set_priv_key = ccp_rsa_setprivkey,
> +     .max_size = ccp_rsa_maxsize,
> +     .init = ccp_rsa_init_tfm,
> +     .exit = ccp_rsa_exit_tfm,
> +     .reqsize = sizeof(struct ccp_rsa_req_ctx),
> +     .base = {
> +             .cra_name = "rsa",
> +             .cra_driver_name = "rsa-ccp",
> +             .cra_priority = 100,

Are you sure you want to leave it at 100? With this value, it will content 
with the C implementation.

> +             .cra_module = THIS_MODULE,
> +             .cra_ctxsize = sizeof(struct ccp_ctx),
> +     },
> +};
> +
> +int ccp_register_rsa_algs(void)
> +{
> +     int ret;
> +
> +     /* Register the RSA algorithm in standard mode
> +      * This works for CCP v3 and later
> +      */
> +     ret = crypto_register_akcipher(&rsa);
> +     return ret;
> +}
> +
> +void ccp_unregister_rsa_algs(void)
> +{
> +     crypto_unregister_akcipher(&rsa);
> +}
> diff --git a/drivers/crypto/ccp/ccp-crypto.h
> b/drivers/crypto/ccp/ccp-crypto.h index ae442ac..4a1d206 100644
> --- a/drivers/crypto/ccp/ccp-crypto.h
> +++ b/drivers/crypto/ccp/ccp-crypto.h
> @@ -22,6 +22,7 @@
>  #include <crypto/ctr.h>
>  #include <crypto/hash.h>
>  #include <crypto/sha.h>
> +#include <crypto/internal/rsa.h>
> 
>  #define CCP_CRA_PRIORITY     300
> 
> @@ -155,6 +156,26 @@ struct ccp_sha_ctx {
>       struct crypto_shash *hmac_tfm;
>  };
> 
> +/***** RSA related defines *****/
> +
> +struct ccp_rsa_ctx {
> +     unsigned int key_len; /* in bytes */
> +     struct ccp_rsa_key pkey;
> +     struct scatterlist e_sg;
> +     u8 *e_buf;
> +     unsigned int e_len;
> +     struct scatterlist n_sg;
> +     u8 *n_buf;
> +     unsigned int n_len;
> +     struct scatterlist d_sg;
> +     u8 *d_buf;
> +     unsigned int d_len;
> +};
> +
> +struct ccp_rsa_req_ctx {
> +     struct ccp_cmd cmd;
> +};
> +
>  struct ccp_sha_req_ctx {
>       enum ccp_sha_type type;
> 
> @@ -201,6 +222,7 @@ struct ccp_ctx {
> 
>       union {
>               struct ccp_aes_ctx aes;
> +             struct ccp_rsa_ctx rsa;
>               struct ccp_sha_ctx sha;
>       } u;
>  };
> @@ -214,5 +236,7 @@ int ccp_register_aes_algs(struct list_head *head);
>  int ccp_register_aes_cmac_algs(struct list_head *head);
>  int ccp_register_aes_xts_algs(struct list_head *head);
>  int ccp_register_sha_algs(struct list_head *head);
> +int ccp_register_rsa_algs(void);
> +void ccp_unregister_rsa_algs(void);
> 
>  #endif
> diff --git a/drivers/crypto/ccp/ccp-dev-v3.c
> b/drivers/crypto/ccp/ccp-dev-v3.c index 8d2dbac..75a0978 100644
> --- a/drivers/crypto/ccp/ccp-dev-v3.c
> +++ b/drivers/crypto/ccp/ccp-dev-v3.c
> @@ -20,6 +20,43 @@
> 
>  #include "ccp-dev.h"
> 
> +/* CCP version 3: Union to define the function field (cmd_reg1/dword0) */
> +union ccp_function {
> +     struct {
> +             u16 size:7;
> +             u16 encrypt:1;
> +             u16 mode:3;
> +             u16 type:2;
> +     } aes;
> +     struct {
> +             u16 size:7;
> +             u16 encrypt:1;
> +             u16 rsvd:5;
> +     } aes_xts;
> +     struct {
> +             u16 rsvd1:11;
> +             u16 type:2;
> +     } sha;
> +     struct {
> +             u16 size:13;
> +     } rsa;
> +     struct {
> +             u16 byteswap:2;
> +             u16 bitwise:3;
> +             u16 rsvd:8;
> +     } pt;
> +     struct  {
> +             u16 rsvd:13;
> +     } zlib;
> +     struct {
> +             u16 size:8;
> +             u16 mode:3;
> +             u16 rsvd1:1;
> +             u16 rsvd2:1;
> +     } ecc;
> +     u16 raw;
> +};
> +
>  static u32 ccp_alloc_ksb(struct ccp_cmd_queue *cmd_q, unsigned int count)
>  {
>       int start;
> @@ -88,6 +125,7 @@ static int ccp_do_cmd(struct ccp_op *op, u32 *cr,
> unsigned int cr_count) * are actually available, but reading that register
> resets it
>        * and you could lose some error information.
>        */
> +
>       cmd_q->free_slots--;
> 
>       cr0 = (cmd_q->id << REQ0_CMD_Q_SHIFT)
> diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c
> index 82cc637..826782d 100644
> --- a/drivers/crypto/ccp/ccp-ops.c
> +++ b/drivers/crypto/ccp/ccp-ops.c
> @@ -17,6 +17,7 @@
>  #include <linux/interrupt.h>
>  #include <crypto/scatterwalk.h>
>  #include <linux/ccp.h>
> +#include <linux/delay.h>
> 
>  #include "ccp-dev.h"
> 
> diff --git a/include/linux/ccp.h b/include/linux/ccp.h
> index 1a3e0b5..d634565 100644
> --- a/include/linux/ccp.h
> +++ b/include/linux/ccp.h
> @@ -19,7 +19,8 @@
>  #include <linux/list.h>
>  #include <crypto/aes.h>
>  #include <crypto/sha.h>
> -
> +#include <linux/mpi.h>
> +#include <crypto/internal/rsa.h>
> 
>  struct ccp_device;
>  struct ccp_cmd;
> @@ -293,6 +294,27 @@ struct ccp_sha_engine {
>                                * final sha cmd */
>  };
> 
> +/**
> + * ccp_rsa_type - mode of RSA operation
> + *
> + * @CCP_RSA_MODE_STD: standard mode
> + */
> +enum ccp_rsa_mode {
> +     CCP_RSA_ENCRYPT = 0,
> +     CCP_RSA_DECRYPT,
> +     CCP_RSA__LAST,
> +};
> +
> +struct ccp_rsa_key {
> +     MPI e;
> +     MPI n;
> +     MPI d;
> +};
> +
> +#define      CCP_RSA_MAXMOD  (4 * 1024 / 8)
> +#define      CCP5_RSA_MAXMOD (16 * 1024 / 8)
> +#define      CCP5_RSA_MINMOD (512 / 8)
> +
>  /***** RSA engine *****/
>  /**
>   * struct ccp_rsa_engine - CCP RSA operation
> @@ -309,16 +331,26 @@ struct ccp_sha_engine {
>   *   - key_size, exp, exp_len, mod, mod_len, src, dst, src_len
>   */
>  struct ccp_rsa_engine {
> +     enum ccp_rsa_mode mode;
>       u32 key_size;           /* In bits */
> 
> +     struct ccp_rsa_key pkey;
> +
> +/* e */
>       struct scatterlist *exp;
>       u32 exp_len;            /* In bytes */
> 
> +/* n */
>       struct scatterlist *mod;
>       u32 mod_len;            /* In bytes */
> 
> +/* d */
> +     struct scatterlist *d_sg;
> +     unsigned int d_len;
> +
>       struct scatterlist *src, *dst;
>       u32 src_len;            /* In bytes */
> +     u32 dst_len;            /* In bytes */
>  };
> 
>  /***** Passthru engine *****/
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



Ciao
Stephan
--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to