162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * AMD Cryptographic Coprocessor (CCP) RSA crypto API support 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2017 Advanced Micro Devices, Inc. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Gary R Hook <gary.hook@amd.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/sched.h> 1262306a36Sopenharmony_ci#include <linux/scatterlist.h> 1362306a36Sopenharmony_ci#include <linux/crypto.h> 1462306a36Sopenharmony_ci#include <crypto/algapi.h> 1562306a36Sopenharmony_ci#include <crypto/internal/rsa.h> 1662306a36Sopenharmony_ci#include <crypto/internal/akcipher.h> 1762306a36Sopenharmony_ci#include <crypto/akcipher.h> 1862306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "ccp-crypto.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic inline struct akcipher_request *akcipher_request_cast( 2362306a36Sopenharmony_ci struct crypto_async_request *req) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci return container_of(req, struct akcipher_request, base); 2662306a36Sopenharmony_ci} 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic inline int ccp_copy_and_save_keypart(u8 **kpbuf, unsigned int *kplen, 2962306a36Sopenharmony_ci const u8 *buf, size_t sz) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci int nskip; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci for (nskip = 0; nskip < sz; nskip++) 3462306a36Sopenharmony_ci if (buf[nskip]) 3562306a36Sopenharmony_ci break; 3662306a36Sopenharmony_ci *kplen = sz - nskip; 3762306a36Sopenharmony_ci *kpbuf = kmemdup(buf + nskip, *kplen, GFP_KERNEL); 3862306a36Sopenharmony_ci if (!*kpbuf) 3962306a36Sopenharmony_ci return -ENOMEM; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci return 0; 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic int ccp_rsa_complete(struct crypto_async_request *async_req, int ret) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci struct akcipher_request *req = akcipher_request_cast(async_req); 4762306a36Sopenharmony_ci struct ccp_rsa_req_ctx *rctx = akcipher_request_ctx_dma(req); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (ret) 5062306a36Sopenharmony_ci return ret; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci req->dst_len = rctx->cmd.u.rsa.key_size >> 3; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci return 0; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic unsigned int ccp_rsa_maxsize(struct crypto_akcipher *tfm) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci struct ccp_ctx *ctx = akcipher_tfm_ctx_dma(tfm); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return ctx->u.rsa.n_len; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int ccp_rsa_crypt(struct akcipher_request *req, bool encrypt) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); 6762306a36Sopenharmony_ci struct ccp_ctx *ctx = akcipher_tfm_ctx_dma(tfm); 6862306a36Sopenharmony_ci struct ccp_rsa_req_ctx *rctx = akcipher_request_ctx_dma(req); 6962306a36Sopenharmony_ci int ret = 0; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci memset(&rctx->cmd, 0, sizeof(rctx->cmd)); 7262306a36Sopenharmony_ci INIT_LIST_HEAD(&rctx->cmd.entry); 7362306a36Sopenharmony_ci rctx->cmd.engine = CCP_ENGINE_RSA; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci rctx->cmd.u.rsa.key_size = ctx->u.rsa.key_len; /* in bits */ 7662306a36Sopenharmony_ci if (encrypt) { 7762306a36Sopenharmony_ci rctx->cmd.u.rsa.exp = &ctx->u.rsa.e_sg; 7862306a36Sopenharmony_ci rctx->cmd.u.rsa.exp_len = ctx->u.rsa.e_len; 7962306a36Sopenharmony_ci } else { 8062306a36Sopenharmony_ci rctx->cmd.u.rsa.exp = &ctx->u.rsa.d_sg; 8162306a36Sopenharmony_ci rctx->cmd.u.rsa.exp_len = ctx->u.rsa.d_len; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci rctx->cmd.u.rsa.mod = &ctx->u.rsa.n_sg; 8462306a36Sopenharmony_ci rctx->cmd.u.rsa.mod_len = ctx->u.rsa.n_len; 8562306a36Sopenharmony_ci rctx->cmd.u.rsa.src = req->src; 8662306a36Sopenharmony_ci rctx->cmd.u.rsa.src_len = req->src_len; 8762306a36Sopenharmony_ci rctx->cmd.u.rsa.dst = req->dst; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci ret = ccp_crypto_enqueue_request(&req->base, &rctx->cmd); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci return ret; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic int ccp_rsa_encrypt(struct akcipher_request *req) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci return ccp_rsa_crypt(req, true); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic int ccp_rsa_decrypt(struct akcipher_request *req) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci return ccp_rsa_crypt(req, false); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic int ccp_check_key_length(unsigned int len) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci /* In bits */ 10762306a36Sopenharmony_ci if (len < 8 || len > 4096) 10862306a36Sopenharmony_ci return -EINVAL; 10962306a36Sopenharmony_ci return 0; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic void ccp_rsa_free_key_bufs(struct ccp_ctx *ctx) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci /* Clean up old key data */ 11562306a36Sopenharmony_ci kfree_sensitive(ctx->u.rsa.e_buf); 11662306a36Sopenharmony_ci ctx->u.rsa.e_buf = NULL; 11762306a36Sopenharmony_ci ctx->u.rsa.e_len = 0; 11862306a36Sopenharmony_ci kfree_sensitive(ctx->u.rsa.n_buf); 11962306a36Sopenharmony_ci ctx->u.rsa.n_buf = NULL; 12062306a36Sopenharmony_ci ctx->u.rsa.n_len = 0; 12162306a36Sopenharmony_ci kfree_sensitive(ctx->u.rsa.d_buf); 12262306a36Sopenharmony_ci ctx->u.rsa.d_buf = NULL; 12362306a36Sopenharmony_ci ctx->u.rsa.d_len = 0; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic int ccp_rsa_setkey(struct crypto_akcipher *tfm, const void *key, 12762306a36Sopenharmony_ci unsigned int keylen, bool private) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci struct ccp_ctx *ctx = akcipher_tfm_ctx_dma(tfm); 13062306a36Sopenharmony_ci struct rsa_key raw_key; 13162306a36Sopenharmony_ci int ret; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci ccp_rsa_free_key_bufs(ctx); 13462306a36Sopenharmony_ci memset(&raw_key, 0, sizeof(raw_key)); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* Code borrowed from crypto/rsa.c */ 13762306a36Sopenharmony_ci if (private) 13862306a36Sopenharmony_ci ret = rsa_parse_priv_key(&raw_key, key, keylen); 13962306a36Sopenharmony_ci else 14062306a36Sopenharmony_ci ret = rsa_parse_pub_key(&raw_key, key, keylen); 14162306a36Sopenharmony_ci if (ret) 14262306a36Sopenharmony_ci goto n_key; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci ret = ccp_copy_and_save_keypart(&ctx->u.rsa.n_buf, &ctx->u.rsa.n_len, 14562306a36Sopenharmony_ci raw_key.n, raw_key.n_sz); 14662306a36Sopenharmony_ci if (ret) 14762306a36Sopenharmony_ci goto key_err; 14862306a36Sopenharmony_ci sg_init_one(&ctx->u.rsa.n_sg, ctx->u.rsa.n_buf, ctx->u.rsa.n_len); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci ctx->u.rsa.key_len = ctx->u.rsa.n_len << 3; /* convert to bits */ 15162306a36Sopenharmony_ci if (ccp_check_key_length(ctx->u.rsa.key_len)) { 15262306a36Sopenharmony_ci ret = -EINVAL; 15362306a36Sopenharmony_ci goto key_err; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci ret = ccp_copy_and_save_keypart(&ctx->u.rsa.e_buf, &ctx->u.rsa.e_len, 15762306a36Sopenharmony_ci raw_key.e, raw_key.e_sz); 15862306a36Sopenharmony_ci if (ret) 15962306a36Sopenharmony_ci goto key_err; 16062306a36Sopenharmony_ci sg_init_one(&ctx->u.rsa.e_sg, ctx->u.rsa.e_buf, ctx->u.rsa.e_len); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (private) { 16362306a36Sopenharmony_ci ret = ccp_copy_and_save_keypart(&ctx->u.rsa.d_buf, 16462306a36Sopenharmony_ci &ctx->u.rsa.d_len, 16562306a36Sopenharmony_ci raw_key.d, raw_key.d_sz); 16662306a36Sopenharmony_ci if (ret) 16762306a36Sopenharmony_ci goto key_err; 16862306a36Sopenharmony_ci sg_init_one(&ctx->u.rsa.d_sg, 16962306a36Sopenharmony_ci ctx->u.rsa.d_buf, ctx->u.rsa.d_len); 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci return 0; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cikey_err: 17562306a36Sopenharmony_ci ccp_rsa_free_key_bufs(ctx); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cin_key: 17862306a36Sopenharmony_ci return ret; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic int ccp_rsa_setprivkey(struct crypto_akcipher *tfm, const void *key, 18262306a36Sopenharmony_ci unsigned int keylen) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci return ccp_rsa_setkey(tfm, key, keylen, true); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic int ccp_rsa_setpubkey(struct crypto_akcipher *tfm, const void *key, 18862306a36Sopenharmony_ci unsigned int keylen) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci return ccp_rsa_setkey(tfm, key, keylen, false); 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic int ccp_rsa_init_tfm(struct crypto_akcipher *tfm) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci struct ccp_ctx *ctx = akcipher_tfm_ctx_dma(tfm); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci akcipher_set_reqsize_dma(tfm, sizeof(struct ccp_rsa_req_ctx)); 19862306a36Sopenharmony_ci ctx->complete = ccp_rsa_complete; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci return 0; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic void ccp_rsa_exit_tfm(struct crypto_akcipher *tfm) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci struct ccp_ctx *ctx = akcipher_tfm_ctx_dma(tfm); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci ccp_rsa_free_key_bufs(ctx); 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic struct akcipher_alg ccp_rsa_defaults = { 21162306a36Sopenharmony_ci .encrypt = ccp_rsa_encrypt, 21262306a36Sopenharmony_ci .decrypt = ccp_rsa_decrypt, 21362306a36Sopenharmony_ci .set_pub_key = ccp_rsa_setpubkey, 21462306a36Sopenharmony_ci .set_priv_key = ccp_rsa_setprivkey, 21562306a36Sopenharmony_ci .max_size = ccp_rsa_maxsize, 21662306a36Sopenharmony_ci .init = ccp_rsa_init_tfm, 21762306a36Sopenharmony_ci .exit = ccp_rsa_exit_tfm, 21862306a36Sopenharmony_ci .base = { 21962306a36Sopenharmony_ci .cra_name = "rsa", 22062306a36Sopenharmony_ci .cra_driver_name = "rsa-ccp", 22162306a36Sopenharmony_ci .cra_priority = CCP_CRA_PRIORITY, 22262306a36Sopenharmony_ci .cra_module = THIS_MODULE, 22362306a36Sopenharmony_ci .cra_ctxsize = 2 * sizeof(struct ccp_ctx) + CRYPTO_DMA_PADDING, 22462306a36Sopenharmony_ci }, 22562306a36Sopenharmony_ci}; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistruct ccp_rsa_def { 22862306a36Sopenharmony_ci unsigned int version; 22962306a36Sopenharmony_ci const char *name; 23062306a36Sopenharmony_ci const char *driver_name; 23162306a36Sopenharmony_ci unsigned int reqsize; 23262306a36Sopenharmony_ci struct akcipher_alg *alg_defaults; 23362306a36Sopenharmony_ci}; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic struct ccp_rsa_def rsa_algs[] = { 23662306a36Sopenharmony_ci { 23762306a36Sopenharmony_ci .version = CCP_VERSION(3, 0), 23862306a36Sopenharmony_ci .name = "rsa", 23962306a36Sopenharmony_ci .driver_name = "rsa-ccp", 24062306a36Sopenharmony_ci .reqsize = sizeof(struct ccp_rsa_req_ctx), 24162306a36Sopenharmony_ci .alg_defaults = &ccp_rsa_defaults, 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci}; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic int ccp_register_rsa_alg(struct list_head *head, 24662306a36Sopenharmony_ci const struct ccp_rsa_def *def) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci struct ccp_crypto_akcipher_alg *ccp_alg; 24962306a36Sopenharmony_ci struct akcipher_alg *alg; 25062306a36Sopenharmony_ci int ret; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci ccp_alg = kzalloc(sizeof(*ccp_alg), GFP_KERNEL); 25362306a36Sopenharmony_ci if (!ccp_alg) 25462306a36Sopenharmony_ci return -ENOMEM; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci INIT_LIST_HEAD(&ccp_alg->entry); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci alg = &ccp_alg->alg; 25962306a36Sopenharmony_ci *alg = *def->alg_defaults; 26062306a36Sopenharmony_ci snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name); 26162306a36Sopenharmony_ci snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", 26262306a36Sopenharmony_ci def->driver_name); 26362306a36Sopenharmony_ci ret = crypto_register_akcipher(alg); 26462306a36Sopenharmony_ci if (ret) { 26562306a36Sopenharmony_ci pr_err("%s akcipher algorithm registration error (%d)\n", 26662306a36Sopenharmony_ci alg->base.cra_name, ret); 26762306a36Sopenharmony_ci kfree(ccp_alg); 26862306a36Sopenharmony_ci return ret; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci list_add(&ccp_alg->entry, head); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci return 0; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ciint ccp_register_rsa_algs(struct list_head *head) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci int i, ret; 27962306a36Sopenharmony_ci unsigned int ccpversion = ccp_version(); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* Register the RSA algorithm in standard mode 28262306a36Sopenharmony_ci * This works for CCP v3 and later 28362306a36Sopenharmony_ci */ 28462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rsa_algs); i++) { 28562306a36Sopenharmony_ci if (rsa_algs[i].version > ccpversion) 28662306a36Sopenharmony_ci continue; 28762306a36Sopenharmony_ci ret = ccp_register_rsa_alg(head, &rsa_algs[i]); 28862306a36Sopenharmony_ci if (ret) 28962306a36Sopenharmony_ci return ret; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return 0; 29362306a36Sopenharmony_ci} 294