linux: Adding support for ACVP Build

- ACVP_BUILD param to prpare kernel for the conduction of CAVP
- Added jitterentropy implementation of SHA3-256

Change-Id: I99de0bc844ae5e8225f19e2f1cbf4e581997afc1
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/c/photon/+/21317
Tested-by: Keerthana K <keerthanak@vmware.com>
Reviewed-by: Keerthana K <keerthanak@vmware.com>
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/c/photon/+/22520
Tested-by: Ajay Kaher <akaher@vmware.com>
This commit is contained in:
Srish Srinivasan 2023-07-19 19:45:38 +00:00 committed by Ajay Kaher
parent 251d7a2ac3
commit d6fa2406b7
17 changed files with 2354 additions and 1 deletions

View File

@ -0,0 +1,245 @@
From a3ffd1cbd87f218c44e91c85ede157dd6374a9b0 Mon Sep 17 00:00:00 2001
From: Vikash Bansal <bvikas@vmware.com>
Date: Mon, 25 Jan 2021 10:53:06 +0530
Subject: [PATCH 1/7] crypto: AF_ALG -- add sign/verify API
Add the flags for handling signature generation and signature
verification.
The af_alg helper code as well as the algif_skcipher and algif_aead code
must be changed from a boolean indicating the cipher operation to an
integer because there are now 4 different cipher operations that are
defined. Yet, the algif_aead and algif_skcipher code still only allows
encryption and decryption cipher operations.
Signed-off-by: Stephan Mueller <smueller@chronox.de>
Signed-off-by: Tadeusz Struk <tadeusz.struk@intel.com>
---
crypto/af_alg.c | 10 +++++-----
crypto/algif_aead.c | 30 ++++++++++++++++++++----------
crypto/algif_skcipher.c | 24 +++++++++++++++++-------
include/crypto/if_alg.h | 4 ++--
include/uapi/linux/if_alg.h | 2 ++
5 files changed, 46 insertions(+), 24 deletions(-)
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index 9acb9d2c4..df0852ca4 100755
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -836,7 +836,7 @@ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size,
struct af_alg_tsgl *sgl;
struct af_alg_control con = {};
long copied = 0;
- bool enc = false;
+ int op = 0;
bool init = false;
int err = 0;
@@ -847,11 +847,11 @@ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size,
init = true;
switch (con.op) {
+ case ALG_OP_VERIFY:
+ case ALG_OP_SIGN:
case ALG_OP_ENCRYPT:
- enc = true;
- break;
case ALG_OP_DECRYPT:
- enc = false;
+ op = con.op;
break;
default:
return -EINVAL;
@@ -875,7 +875,7 @@ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size,
ctx->init = true;
if (init) {
- ctx->enc = enc;
+ ctx->op = op;
if (con.iv)
memcpy(ctx->iv, con.iv->iv, ivsize);
diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c
index 42493b4d8..5078d75dc 100755
--- a/crypto/algif_aead.c
+++ b/crypto/algif_aead.c
@@ -55,7 +55,7 @@ static inline bool aead_sufficient_data(struct sock *sk)
* The minimum amount of memory needed for an AEAD cipher is
* the AAD and in case of decryption the tag.
*/
- return ctx->used >= ctx->aead_assoclen + (ctx->enc ? 0 : as);
+ return ctx->used >= ctx->aead_assoclen + (ctx->op ? 0 : as);
}
static int aead_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
@@ -71,6 +71,19 @@ static int aead_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
return af_alg_sendmsg(sock, msg, size, ivsize);
}
+static inline int aead_cipher_op(struct af_alg_ctx *ctx,
+ struct af_alg_async_req *areq)
+{
+ switch (ctx->op) {
+ case ALG_OP_ENCRYPT:
+ return crypto_aead_encrypt(&areq->cra_u.aead_req);
+ case ALG_OP_DECRYPT:
+ return crypto_aead_decrypt(&areq->cra_u.aead_req);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static int crypto_aead_copy_sgl(struct crypto_sync_skcipher *null_tfm,
struct scatterlist *src,
struct scatterlist *dst, unsigned int len)
@@ -138,7 +151,7 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
* buffer provides the tag which is consumed resulting in only the
* plaintext without a buffer for the tag returned to the caller.
*/
- if (ctx->enc)
+ if (ctx->op)
outlen = used + as;
else
outlen = used - as;
@@ -212,7 +225,7 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
/* Use the RX SGL as source (and destination) for crypto op. */
rsgl_src = areq->first_rsgl.sgl.sg;
- if (ctx->enc) {
+ if (ctx->op == ALG_OP_ENCRYPT) {
/*
* Encryption operation - The in-place cipher operation is
* achieved by the following operation:
@@ -228,7 +241,7 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
if (err)
goto free;
af_alg_pull_tsgl(sk, processed, NULL, 0);
- } else {
+ } else if (ctx->op == ALG_OP_DECRYPT) {
/*
* Decryption operation - To achieve an in-place cipher
* operation, the following SGL structure is used:
@@ -293,8 +306,7 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
aead_request_set_callback(&areq->cra_u.aead_req,
CRYPTO_TFM_REQ_MAY_SLEEP,
af_alg_async_cb, areq);
- err = ctx->enc ? crypto_aead_encrypt(&areq->cra_u.aead_req) :
- crypto_aead_decrypt(&areq->cra_u.aead_req);
+ err = aead_cipher_op(ctx, areq);
/* AIO operation in progress */
if (err == -EINPROGRESS)
@@ -307,10 +319,7 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
CRYPTO_TFM_REQ_MAY_SLEEP |
CRYPTO_TFM_REQ_MAY_BACKLOG,
crypto_req_done, &ctx->wait);
- err = crypto_wait_req(ctx->enc ?
- crypto_aead_encrypt(&areq->cra_u.aead_req) :
- crypto_aead_decrypt(&areq->cra_u.aead_req),
- &ctx->wait);
+ err = crypto_wait_req(aead_cipher_op(ctx, areq), &ctx->wait);
}
@@ -555,6 +564,7 @@ static int aead_accept_parent_nokey(void *private, struct sock *sk)
INIT_LIST_HEAD(&ctx->tsgl_list);
ctx->len = len;
+ ctx->op = 0;
crypto_init_wait(&ctx->wait);
ask->private = ctx;
diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
index ee8890ee8..eed627782 100755
--- a/crypto/algif_skcipher.c
+++ b/crypto/algif_skcipher.c
@@ -47,6 +47,19 @@ static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg,
return af_alg_sendmsg(sock, msg, size, ivsize);
}
+static inline int skcipher_cipher_op(struct af_alg_ctx *ctx,
+ struct af_alg_async_req *areq)
+{
+ switch (ctx->op) {
+ case ALG_OP_ENCRYPT:
+ return crypto_skcipher_encrypt(&areq->cra_u.skcipher_req);
+ case ALG_OP_DECRYPT:
+ return crypto_skcipher_decrypt(&areq->cra_u.skcipher_req);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
size_t ignored, int flags)
{
@@ -118,9 +131,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
skcipher_request_set_callback(&areq->cra_u.skcipher_req,
CRYPTO_TFM_REQ_MAY_SLEEP,
af_alg_async_cb, areq);
- err = ctx->enc ?
- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) :
- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req);
+ err = skcipher_cipher_op(ctx, areq);
/* AIO operation in progress */
if (err == -EINPROGRESS)
@@ -133,10 +144,8 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
CRYPTO_TFM_REQ_MAY_SLEEP |
CRYPTO_TFM_REQ_MAY_BACKLOG,
crypto_req_done, &ctx->wait);
- err = crypto_wait_req(ctx->enc ?
- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) :
- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req),
- &ctx->wait);
+ err = crypto_wait_req(skcipher_cipher_op(ctx, areq),
+ &ctx->wait);
}
@@ -341,6 +350,7 @@ static int skcipher_accept_parent_nokey(void *private, struct sock *sk)
INIT_LIST_HEAD(&ctx->tsgl_list);
ctx->len = len;
+ ctx->op = 0;
crypto_init_wait(&ctx->wait);
ask->private = ctx;
diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
index a5db86670..a93cd67d1 100755
--- a/include/crypto/if_alg.h
+++ b/include/crypto/if_alg.h
@@ -134,7 +134,7 @@ struct af_alg_async_req {
* @more: More data to be expected from user space?
* @merge: Shall new data from user space be merged into existing
* SG?
- * @enc: Cryptographic operation to be performed when
+ * @op: Cryptographic operation to be performed when
* recvmsg is invoked.
* @init: True if metadata has been sent.
* @len: Length of memory allocated for this data structure.
@@ -152,7 +152,7 @@ struct af_alg_ctx {
bool more;
bool merge;
- bool enc;
+ int op;
bool init;
unsigned int len;
diff --git a/include/uapi/linux/if_alg.h b/include/uapi/linux/if_alg.h
index dc52a11ba..a6395ea01 100755
--- a/include/uapi/linux/if_alg.h
+++ b/include/uapi/linux/if_alg.h
@@ -56,5 +56,7 @@ struct af_alg_iv {
/* Operations */
#define ALG_OP_DECRYPT 0
#define ALG_OP_ENCRYPT 1
+#define ALG_OP_SIGN 2
+#define ALG_OP_VERIFY 3
#endif /* _LINUX_IF_ALG_H */
--
2.17.1

View File

@ -0,0 +1,94 @@
From b24c7668ab324554dc7fd9211fa27795d9a1cd9a Mon Sep 17 00:00:00 2001
From: Vikash Bansal <bvikas@vmware.com>
Date: Mon, 25 Jan 2021 10:59:15 +0530
Subject: [PATCH 2/7] crypto: AF_ALG -- add setpubkey setsockopt call
For supporting asymmetric ciphers, user space must be able to set the
public key. The patch adds a new setsockopt call for setting the public
key.
Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
crypto/af_alg.c | 18 +++++++++++++-----
include/crypto/if_alg.h | 1 +
include/uapi/linux/if_alg.h | 1 +
3 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index df0852ca4..c00271337 100755
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -202,13 +202,17 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
return err;
}
-static int alg_setkey(struct sock *sk, sockptr_t ukey, unsigned int keylen)
+static int alg_setkey(struct sock *sk, sockptr_t ukey, unsigned int keylen,
+ int (*setkey)(void *private, const u8 *key,
+ unsigned int keylen))
{
struct alg_sock *ask = alg_sk(sk);
- const struct af_alg_type *type = ask->type;
u8 *key;
int err;
+ if (!setkey)
+ return -ENOPROTOOPT;
+
key = sock_kmalloc(sk, keylen, GFP_KERNEL);
if (!key)
return -ENOMEM;
@@ -217,7 +221,7 @@ static int alg_setkey(struct sock *sk, sockptr_t ukey, unsigned int keylen)
if (copy_from_sockptr(key, ukey, keylen))
goto out;
- err = type->setkey(ask->private, key, keylen);
+ err = setkey(ask->private, key, keylen);
out:
sock_kzfree_s(sk, key, keylen);
@@ -247,10 +251,14 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,
case ALG_SET_KEY:
if (sock->state == SS_CONNECTED)
goto unlock;
- if (!type->setkey)
+
+ err = alg_setkey(sk, optval, optlen, type->setkey);
+ break;
+ case ALG_SET_PUBKEY:
+ if (sock->state == SS_CONNECTED)
goto unlock;
- err = alg_setkey(sk, optval, optlen);
+ err = alg_setkey(sk, optval, optlen, type->setpubkey);
break;
case ALG_SET_AEAD_AUTHSIZE:
if (sock->state == SS_CONNECTED)
diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
index a93cd67d1..dcacc1021 100755
--- a/include/crypto/if_alg.h
+++ b/include/crypto/if_alg.h
@@ -46,6 +46,7 @@ struct af_alg_type {
void *(*bind)(const char *name, u32 type, u32 mask);
void (*release)(void *private);
int (*setkey)(void *private, const u8 *key, unsigned int keylen);
+ int (*setpubkey)(void *private, const u8 *key, unsigned int keylen);
int (*setentropy)(void *private, sockptr_t entropy, unsigned int len);
int (*accept)(void *private, struct sock *sk);
int (*accept_nokey)(void *private, struct sock *sk);
diff --git a/include/uapi/linux/if_alg.h b/include/uapi/linux/if_alg.h
index a6395ea01..6f3340410 100755
--- a/include/uapi/linux/if_alg.h
+++ b/include/uapi/linux/if_alg.h
@@ -52,6 +52,7 @@ struct af_alg_iv {
#define ALG_SET_AEAD_ASSOCLEN 4
#define ALG_SET_AEAD_AUTHSIZE 5
#define ALG_SET_DRBG_ENTROPY 6
+#define ALG_SET_PUBKEY 7
/* Operations */
#define ALG_OP_DECRYPT 0
--
2.17.1

View File

@ -0,0 +1,557 @@
From 4114f2c60065e417380bceb36d39a52cc53b40e1 Mon Sep 17 00:00:00 2001
From: Vikash Bansal <bvikas@vmware.com>
Date: Tue, 23 Mar 2021 13:13:00 +0530
Subject: [PATCH 3/7] crypto: AF_ALG -- add asymmetric cipher
This patch adds the user space interface for asymmetric ciphers. The
interface allows the use of sendmsg as well as vmsplice to provide data.
The akcipher interface implementation uses the common AF_ALG interface
code regarding TX and RX SGL handling.
Signed-off-by: Stephan Mueller <smueller@chronox.de>
Signed-off-by: Vikash Bansal <bvikas@vmware.com>
Signed-off-by: Srish Srinivasan <ssrish@vmware.com>
---
crypto/Kconfig | 9 +
crypto/Makefile | 1 +
crypto/algif_akcipher.c | 473 ++++++++++++++++++++++++++++++++++++++++
include/crypto/if_alg.h | 2 +
4 files changed, 485 insertions(+)
create mode 100644 crypto/algif_akcipher.c
diff --git a/crypto/Kconfig b/crypto/Kconfig
index b338b5cf6..aeecdbd0d 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -1403,6 +1403,15 @@ config CRYPTO_STATS
endmenu
+config CRYPTO_USER_API_AKCIPHER
+ tristate "User-space interface for asymmetric key cipher algorithms"
+ depends on NET
+ select CRYPTO_AKCIPHER2
+ select CRYPTO_USER_API
+ help
+ This option enables the user-space interface for asymmetric
+ key cipher algorithms.
+
config CRYPTO_HASH_INFO
bool
diff --git a/crypto/Makefile b/crypto/Makefile
index 7289ccb84..f68acf932 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -166,6 +166,7 @@ obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o
obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o
obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o
+obj-$(CONFIG_CRYPTO_USER_API_AKCIPHER) += algif_akcipher.o
obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o
obj-$(CONFIG_CRYPTO_OFB) += ofb.o
obj-$(CONFIG_CRYPTO_ESSIV) += essiv.o
diff --git a/crypto/algif_akcipher.c b/crypto/algif_akcipher.c
new file mode 100644
index 000000000..8ed305ecc
--- /dev/null
+++ b/crypto/algif_akcipher.c
@@ -0,0 +1,473 @@
+/*
+ * algif_akcipher: User-space interface for asymmetric cipher algorithms
+ *
+ * Copyright (C) 2018 - 2020, Stephan Mueller <smueller@chronox.de>
+ *
+ * This file provides the user-space API for asymmetric ciphers.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * The following concept of the memory management is used:
+ *
+ * The kernel maintains two SGLs, the TX SGL and the RX SGL. The TX SGL is
+ * filled by user space with the data submitted via sendpage/sendmsg. Filling
+ * up the TX SGL does not cause a crypto operation -- the data will only be
+ * tracked by the kernel. Upon receipt of one recvmsg call, the caller must
+ * provide a buffer which is tracked with the RX SGL.
+ *
+ * During the processing of the recvmsg operation, the cipher request is
+ * allocated and prepared. As part of the recvmsg operation, the processed
+ * TX buffers are extracted from the TX SGL into a separate SGL.
+ *
+ * After the completion of the crypto operation, the RX SGL and the cipher
+ * request is released. The extracted TX SGL parts are released together with
+ * the RX SGL release.
+ */
+
+#include <crypto/akcipher.h>
+#include <crypto/if_alg.h>
+#include <crypto/scatterwalk.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/net.h>
+#include <net/sock.h>
+
+struct akcipher_tfm {
+ struct crypto_akcipher *akcipher;
+ bool has_key;
+};
+
+static int akcipher_sendmsg(struct socket *sock, struct msghdr *msg,
+ size_t size)
+{
+ return af_alg_sendmsg(sock, msg, size, 0);
+}
+
+static inline int akcipher_cipher_op(struct af_alg_ctx *ctx,
+ struct af_alg_async_req *areq)
+{
+ switch (ctx->op) {
+ case ALG_OP_ENCRYPT:
+ return crypto_akcipher_encrypt(&areq->cra_u.akcipher_req);
+ case ALG_OP_DECRYPT:
+ return crypto_akcipher_decrypt(&areq->cra_u.akcipher_req);
+ case ALG_OP_SIGN:
+ return crypto_akcipher_sign(&areq->cra_u.akcipher_req);
+ case ALG_OP_VERIFY:
+ areq->cra_u.akcipher_req.dst = NULL;
+ areq->cra_u.akcipher_req.src_len = areq->cra_u.akcipher_req.src_len - areq->cra_u.akcipher_req.dst_len;
+ return crypto_akcipher_verify(&areq->cra_u.akcipher_req);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int _akcipher_recvmsg(struct socket *sock, struct msghdr *msg,
+ size_t ignored, int flags)
+{
+ struct sock *sk = sock->sk;
+ struct alg_sock *ask = alg_sk(sk);
+ struct sock *psk = ask->parent;
+ struct alg_sock *pask = alg_sk(psk);
+ struct af_alg_ctx *ctx = ask->private;
+ struct akcipher_tfm *akc = pask->private;
+ struct crypto_akcipher *tfm = akc->akcipher;
+ struct af_alg_async_req *areq;
+ size_t len;
+ size_t used;
+ int err;
+ int maxsize;
+
+ if (!ctx->used) {
+ err = af_alg_wait_for_data(sk, flags, 0);
+ if (err)
+ return err;
+ }
+
+ maxsize = crypto_akcipher_maxsize(tfm);
+ if (maxsize < 0)
+ return maxsize;
+
+ /* Allocate cipher request for current operation. */
+ areq = af_alg_alloc_areq(sk, sizeof(struct af_alg_async_req) +
+ crypto_akcipher_reqsize(tfm));
+ if (IS_ERR(areq))
+ return PTR_ERR(areq);
+
+ /* convert iovecs of output buffers into RX SGL */
+ err = af_alg_get_rsgl(sk, msg, flags, areq, -1 , &len);
+ if (err)
+ goto free;
+
+ /* ensure output buffer is sufficiently large */
+ if (ctx->op != ALG_OP_VERIFY && len < maxsize) {
+ err = -EMSGSIZE;
+ goto free;
+ }
+
+ /*
+ * Create a per request TX SGL for this request which tracks the
+ * SG entries from the global TX SGL.
+ */
+ used = ctx->used;
+ areq->tsgl_entries = af_alg_count_tsgl(sk, used, 0);
+ if (!areq->tsgl_entries)
+ areq->tsgl_entries = 1;
+ areq->tsgl = sock_kmalloc(sk, sizeof(*areq->tsgl) * areq->tsgl_entries,
+ GFP_KERNEL);
+ if (!areq->tsgl) {
+ err = -ENOMEM;
+ goto free;
+ }
+ sg_init_table(areq->tsgl, areq->tsgl_entries);
+ af_alg_pull_tsgl(sk, used, areq->tsgl, 0);
+
+ /* Initialize the crypto operation */
+ akcipher_request_set_tfm(&areq->cra_u.akcipher_req, tfm);
+ akcipher_request_set_crypt(&areq->cra_u.akcipher_req, areq->tsgl,
+ areq->first_rsgl.sgl.sg, used, len);
+
+ if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) {
+ /* AIO operation */
+ sock_hold(sk);
+ areq->iocb = msg->msg_iocb;
+
+ /* Remember output size that will be generated. */
+ areq->outlen = areq->cra_u.akcipher_req.dst_len ?
+ areq->cra_u.akcipher_req.dst_len : len;
+
+ akcipher_request_set_callback(&areq->cra_u.akcipher_req,
+ CRYPTO_TFM_REQ_MAY_SLEEP,
+ af_alg_async_cb, areq);
+ err = akcipher_cipher_op(ctx, areq);
+
+ /* AIO operation in progress */
+ if (err == -EINPROGRESS || err == -EBUSY)
+ return -EIOCBQUEUED;
+
+ sock_put(sk);
+ } else {
+ /* Synchronous operation */
+ akcipher_request_set_callback(&areq->cra_u.akcipher_req,
+ CRYPTO_TFM_REQ_MAY_SLEEP |
+ CRYPTO_TFM_REQ_MAY_BACKLOG,
+ crypto_req_done,
+ &ctx->wait);
+ err = crypto_wait_req(akcipher_cipher_op(ctx, areq),
+ &ctx->wait);
+ }
+
+free:
+ af_alg_free_resources(areq);
+
+ return err ? err : areq->cra_u.akcipher_req.dst_len;
+}
+
+static int akcipher_recvmsg(struct socket *sock, struct msghdr *msg,
+ size_t ignored, int flags)
+{
+ struct sock *sk = sock->sk;
+ struct alg_sock *ask = alg_sk(sk);
+ struct sock *psk = ask->parent;
+ struct alg_sock *pask = alg_sk(psk);
+ struct akcipher_tfm *akc = pask->private;
+ struct crypto_akcipher *tfm = akc->akcipher;
+ int ret = 0;
+ int err;
+
+ lock_sock(sk);
+
+ while (msg_data_left(msg)) {
+ err = _akcipher_recvmsg(sock, msg, ignored, flags);
+
+ /*
+ * This error covers -EIOCBQUEUED which implies that we can
+ * only handle one AIO request. If the caller wants to have
+ * multiple AIO requests in parallel, he must make multiple
+ * separate AIO calls.
+ */
+ if (err <= 0) {
+ if (err == -EIOCBQUEUED || err == -EBADMSG || !ret)
+ ret = err;
+ goto out;
+ }
+
+ ret += err;
+
+ /*
+ * The caller must provide crypto_akcipher_maxsize per request.
+ * If he provides more, we conclude that multiple akcipher
+ * operations are requested.
+ */
+ iov_iter_advance(&msg->msg_iter,
+ crypto_akcipher_maxsize(tfm) - err);
+ }
+
+out:
+ af_alg_wmem_wakeup(sk);
+ release_sock(sk);
+ return ret;
+}
+
+static struct proto_ops algif_akcipher_ops = {
+ .family = PF_ALG,
+
+ .connect = sock_no_connect,
+ .socketpair = sock_no_socketpair,
+ .getname = sock_no_getname,
+ .ioctl = sock_no_ioctl,
+ .listen = sock_no_listen,
+ .shutdown = sock_no_shutdown,
+ .getsockopt = sock_getsockopt,
+ .mmap = sock_no_mmap,
+ .bind = sock_no_bind,
+ .accept = sock_no_accept,
+ .setsockopt = sock_setsockopt,
+
+ .release = af_alg_release,
+ .sendmsg = akcipher_sendmsg,
+ .sendpage = af_alg_sendpage,
+ .recvmsg = akcipher_recvmsg,
+ .poll = af_alg_poll,
+};
+
+static int akcipher_check_key(struct socket *sock)
+{
+ struct sock *psk;
+ struct alg_sock *pask;
+ struct akcipher_tfm *tfm;
+ struct sock *sk = sock->sk;
+ struct alg_sock *ask = alg_sk(sk);
+ int err = 0;
+
+ lock_sock(sk);
+ if (!atomic_read(&ask->nokey_refcnt))
+ goto unlock_child;
+
+ psk = ask->parent;
+ pask = alg_sk(ask->parent);
+ tfm = pask->private;
+
+ lock_sock_nested(psk, SINGLE_DEPTH_NESTING);
+ if (!tfm->has_key) {
+ err = -ENOKEY;
+ goto unlock;
+ }
+ atomic_dec(&pask->nokey_refcnt);
+ atomic_set(&ask->nokey_refcnt, 0);
+
+ err = 0;
+
+unlock:
+ release_sock(psk);
+unlock_child:
+ release_sock(sk);
+
+ return err;
+}
+
+static int akcipher_sendmsg_nokey(struct socket *sock, struct msghdr *msg,
+ size_t size)
+{
+ int err;
+
+ err = akcipher_check_key(sock);
+ if (err)
+ return err;
+
+ return akcipher_sendmsg(sock, msg, size);
+}
+
+static ssize_t akcipher_sendpage_nokey(struct socket *sock, struct page *page,
+ int offset, size_t size, int flags)
+{
+ int err;
+
+ err = akcipher_check_key(sock);
+ if (err)
+ return err;
+
+ return af_alg_sendpage(sock, page, offset, size, flags);
+}
+
+static int akcipher_recvmsg_nokey(struct socket *sock, struct msghdr *msg,
+ size_t ignored, int flags)
+{
+ int err;
+
+ err = akcipher_check_key(sock);
+ if (err)
+ return err;
+
+ return akcipher_recvmsg(sock, msg, ignored, flags);
+}
+
+static struct proto_ops algif_akcipher_ops_nokey = {
+ .family = PF_ALG,
+
+ .connect = sock_no_connect,
+ .socketpair = sock_no_socketpair,
+ .getname = sock_no_getname,
+ .ioctl = sock_no_ioctl,
+ .listen = sock_no_listen,
+ .shutdown = sock_no_shutdown,
+ .getsockopt = sock_getsockopt,
+ .mmap = sock_no_mmap,
+ .bind = sock_no_bind,
+ .accept = sock_no_accept,
+ .setsockopt = sock_setsockopt,
+
+ .release = af_alg_release,
+ .sendmsg = akcipher_sendmsg_nokey,
+ .sendpage = akcipher_sendpage_nokey,
+ .recvmsg = akcipher_recvmsg_nokey,
+ .poll = af_alg_poll,
+};
+
+static void *akcipher_bind(const char *name, u32 type, u32 mask)
+{
+ struct akcipher_tfm *tfm;
+ struct crypto_akcipher *akcipher;
+
+ tfm = kmalloc(sizeof(*tfm), GFP_KERNEL);
+ if (!tfm)
+ return ERR_PTR(-ENOMEM);
+
+ akcipher = crypto_alloc_akcipher(name, type, mask);
+ if (IS_ERR(akcipher)) {
+ kfree(tfm);
+ return ERR_CAST(akcipher);
+ }
+
+ tfm->akcipher = akcipher;
+ tfm->has_key = false;
+
+ return tfm;
+}
+
+static void akcipher_release(void *private)
+{
+ struct akcipher_tfm *tfm = private;
+ struct crypto_akcipher *akcipher = tfm->akcipher;
+
+ crypto_free_akcipher(akcipher);
+ kfree(tfm);
+}
+
+static int akcipher_setprivkey(void *private, const u8 *key,
+ unsigned int keylen)
+{
+ struct akcipher_tfm *tfm = private;
+ struct crypto_akcipher *akcipher = tfm->akcipher;
+ int err;
+
+ err = crypto_akcipher_set_priv_key(akcipher, key, keylen);
+ tfm->has_key = !err;
+
+ /* Return the maximum size of the akcipher operation. */
+ if (!err)
+ err = crypto_akcipher_maxsize(akcipher);
+
+ return err;
+}
+
+static int akcipher_setpubkey(void *private, const u8 *key, unsigned int keylen)
+{
+ struct akcipher_tfm *tfm = private;
+ struct crypto_akcipher *akcipher = tfm->akcipher;
+ int err;
+
+ err = crypto_akcipher_set_pub_key(akcipher, key, keylen);
+ tfm->has_key = !err;
+
+ /* Return the maximum size of the akcipher operation. */
+ if (!err)
+ err = crypto_akcipher_maxsize(akcipher);
+
+ return err;
+}
+
+static void akcipher_sock_destruct(struct sock *sk)
+{
+ struct alg_sock *ask = alg_sk(sk);
+ struct af_alg_ctx *ctx = ask->private;
+
+ af_alg_pull_tsgl(sk, ctx->used, NULL, 0);
+ sock_kfree_s(sk, ctx, ctx->len);
+ af_alg_release_parent(sk);
+}
+
+static int akcipher_accept_parent_nokey(void *private, struct sock *sk)
+{
+ struct af_alg_ctx *ctx;
+ struct alg_sock *ask = alg_sk(sk);
+ unsigned int len = sizeof(*ctx);
+
+ ctx = sock_kmalloc(sk, len, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&ctx->tsgl_list);
+ ctx->len = len;
+ ctx->used = 0;
+ atomic_set(&ctx->rcvused, 0);
+ ctx->more = 0;
+ ctx->merge = 0;
+ ctx->op = 0;
+ crypto_init_wait(&ctx->wait);
+
+ ask->private = ctx;
+
+ sk->sk_destruct = akcipher_sock_destruct;
+
+ return 0;
+}
+
+static int akcipher_accept_parent(void *private, struct sock *sk)
+{
+ struct akcipher_tfm *tfm = private;
+
+ if (!tfm->has_key)
+ return -ENOKEY;
+
+ return akcipher_accept_parent_nokey(private, sk);
+}
+
+static const struct af_alg_type algif_type_akcipher = {
+ .bind = akcipher_bind,
+ .release = akcipher_release,
+ .setkey = akcipher_setprivkey,
+ .setpubkey = akcipher_setpubkey,
+ .setauthsize = NULL,
+ .accept = akcipher_accept_parent,
+ .accept_nokey = akcipher_accept_parent_nokey,
+ .ops = &algif_akcipher_ops,
+ .ops_nokey = &algif_akcipher_ops_nokey,
+ .name = "akcipher",
+ .owner = THIS_MODULE
+};
+
+static int __init algif_akcipher_init(void)
+{
+ printk("This build is only for ACVP test (not a production build)\n");
+ return af_alg_register_type(&algif_type_akcipher);
+}
+
+static void __exit algif_akcipher_exit(void)
+{
+ int err = af_alg_unregister_type(&algif_type_akcipher);
+
+ BUG_ON(err);
+}
+
+module_init(algif_akcipher_init);
+module_exit(algif_akcipher_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
+MODULE_DESCRIPTION("Asymmetric kernel crypto API user space interface");
diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
index dcacc1021..c4ff208b6 100644
--- a/include/crypto/if_alg.h
+++ b/include/crypto/if_alg.h
@@ -18,6 +18,7 @@
#include <crypto/aead.h>
#include <crypto/skcipher.h>
+#include <crypto/akcipher.h>
#define ALG_MAX_PAGES 16
@@ -111,6 +112,7 @@ struct af_alg_async_req {
union {
struct aead_request aead_req;
struct skcipher_request skcipher_req;
+ struct akcipher_request akcipher_req;
} cra_u;
/* req ctx trails this struct */
--
2.17.1

View File

@ -0,0 +1,29 @@
From 153a39ad5f1a67709869331821602f8e3c579746 Mon Sep 17 00:00:00 2001
From: Vikash Bansal <bvikas@vmware.com>
Date: Mon, 25 Jan 2021 11:02:35 +0530
Subject: [PATCH 4/7] crypto: AF_ALG -- add DH keygen / ssgen API
Add the flags for handling DH key generation and DH shared
secret generation.
Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
include/uapi/linux/if_alg.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/uapi/linux/if_alg.h b/include/uapi/linux/if_alg.h
index 6f3340410..b3d296fba 100755
--- a/include/uapi/linux/if_alg.h
+++ b/include/uapi/linux/if_alg.h
@@ -59,5 +59,7 @@ struct af_alg_iv {
#define ALG_OP_ENCRYPT 1
#define ALG_OP_SIGN 2
#define ALG_OP_VERIFY 3
+#define ALG_OP_KEYGEN 4
+#define ALG_OP_SSGEN 5
#endif /* _LINUX_IF_ALG_H */
--
2.17.1

View File

@ -0,0 +1,74 @@
From e03916c6171575028537f09ab6d938189baf6308 Mon Sep 17 00:00:00 2001
From: Vikash Bansal <bvikas@vmware.com>
Date: Mon, 25 Jan 2021 11:06:25 +0530
Subject: [PATCH 5/7] crypto: AF_ALG -- add DH param / ECDH curve setsockopt
call
For supporting DH ciphers, user space must be able to set the
DH parameters. The patch adds a new setsockopt call for setting
these parameters.
Similarly, the ECDH curve information can be set by user space via the
newly added setsockopt call.
Signed-off-by: Stephan Mueller <smueller@chronox.de>
Signed-off-by: Vikash Bansal <bvikas@vmware.com>
---
crypto/af_alg.c | 12 ++++++++++++
include/crypto/if_alg.h | 2 ++
include/uapi/linux/if_alg.h | 2 ++
3 files changed, 16 insertions(+)
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index c00271337..b854c72da 100755
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -260,6 +260,18 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,
err = alg_setkey(sk, optval, optlen, type->setpubkey);
break;
+ case ALG_SET_DH_PARAMETERS:
+ if (sock->state == SS_CONNECTED)
+ goto unlock;
+
+ err = alg_setkey(sk, optval, optlen, type->dhparams);
+ break;
+ case ALG_SET_ECDH_CURVE:
+ if (sock->state == SS_CONNECTED)
+ goto unlock;
+
+ err = alg_setkey(sk, optval, optlen, type->ecdhcurve);
+ break;
case ALG_SET_AEAD_AUTHSIZE:
if (sock->state == SS_CONNECTED)
goto unlock;
diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
index c4ff208b6..1412672e1 100755
--- a/include/crypto/if_alg.h
+++ b/include/crypto/if_alg.h
@@ -48,6 +48,8 @@ struct af_alg_type {
void (*release)(void *private);
int (*setkey)(void *private, const u8 *key, unsigned int keylen);
int (*setpubkey)(void *private, const u8 *key, unsigned int keylen);
+ int (*dhparams)(void *private, const u8 *param, unsigned int paramlen);
+ int (*ecdhcurve)(void *private, const u8 *param, unsigned int paramlen);
int (*setentropy)(void *private, sockptr_t entropy, unsigned int len);
int (*accept)(void *private, struct sock *sk);
int (*accept_nokey)(void *private, struct sock *sk);
diff --git a/include/uapi/linux/if_alg.h b/include/uapi/linux/if_alg.h
index b3d296fba..c5fe777a8 100755
--- a/include/uapi/linux/if_alg.h
+++ b/include/uapi/linux/if_alg.h
@@ -53,6 +53,8 @@ struct af_alg_iv {
#define ALG_SET_AEAD_AUTHSIZE 5
#define ALG_SET_DRBG_ENTROPY 6
#define ALG_SET_PUBKEY 7
+#define ALG_SET_DH_PARAMETERS 8
+#define ALG_SET_ECDH_CURVE 9
/* Operations */
#define ALG_OP_DECRYPT 0
--
2.17.1

View File

@ -0,0 +1,60 @@
From 5fac0b8dcb3770c25b27fb5454cfb01e00fdefc3 Mon Sep 17 00:00:00 2001
From: Vikash Bansal <bvikas@vmware.com>
Date: Mon, 25 Jan 2021 11:08:19 +0530
Subject: [PATCH 6/7] crypto: AF_ALG - eliminate code duplication
The handling function for setsockopt contains duplicated code which is
cleaned up with this patch. This patch does not change the functionality.
Signed-off-by: Stephan Mueller <smueller@chronox.de>
Signed-off-by: Vikash Bansal <bvikas@vmware.com>
---
crypto/af_alg.c | 17 +++--------------
1 file changed, 3 insertions(+), 14 deletions(-)
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index b854c72da..4178ebac8 100755
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -247,34 +247,23 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,
if (level != SOL_ALG || !type)
goto unlock;
+ if (sock->state == SS_CONNECTED)
+ goto unlock;
+
switch (optname) {
case ALG_SET_KEY:
- if (sock->state == SS_CONNECTED)
- goto unlock;
-
err = alg_setkey(sk, optval, optlen, type->setkey);
break;
case ALG_SET_PUBKEY:
- if (sock->state == SS_CONNECTED)
- goto unlock;
-
err = alg_setkey(sk, optval, optlen, type->setpubkey);
break;
case ALG_SET_DH_PARAMETERS:
- if (sock->state == SS_CONNECTED)
- goto unlock;
-
err = alg_setkey(sk, optval, optlen, type->dhparams);
break;
case ALG_SET_ECDH_CURVE:
- if (sock->state == SS_CONNECTED)
- goto unlock;
-
err = alg_setkey(sk, optval, optlen, type->ecdhcurve);
break;
case ALG_SET_AEAD_AUTHSIZE:
- if (sock->state == SS_CONNECTED)
- goto unlock;
if (!type->setauthsize)
goto unlock;
err = type->setauthsize(ask->private, optlen);
--
2.17.1

View File

@ -0,0 +1,708 @@
From 136fe0719b504d2f1016570307c3c2c563700738 Mon Sep 17 00:00:00 2001
From: Vikash Bansal <bvikas@vmware.com>
Date: Tue, 23 Mar 2021 13:19:28 +0530
Subject: [PATCH] crypto: AF_ALG - add KPP support
The patch externalizes the KPP kernel crypto API to user space. This
allows user space to make use of Diffie-Hellman and EC Diffie-Hellman
operations.
The following operations are supported:
* DH parameters formatted in PKCS#3 with ALG_SET_DH_PARAMETERS
setsockopt. The call returns the buffer length user space must
allocate for the shared secret / public key operation.
* ECDH curve selection via ALG_SET_ECDH_CURVE setsockopt. The call
returns the buffer length user space must allocate for the shared
secret / public key operation.
* The private key can be set with the ALG_SET_KEY setsockopt. It is
permissible to provide a NULL key. In this case, the kernel uses the
tries to generate a private key of appropriate size and sets the key
with the TFM. The idea is that the caller can obtain the public key
from the private key, exchange it with the peer, inject the peer's
public key into the kernel and derive the shared secret. This way,
the private key does not leave the kernel realm. The call returns the
buffer length user space must allocate for the shared secret / public
key operation.
* The public key is obtained from the private key via the recvmsg
operation. For this operation, no data sent to the kernel via sendmsg
or sendpage is required.
* The shared secret is obtained by providing the peer's public key via
sendmsg / sendpage and reading the shared secret via recvmsg.
Added support for LKCM 5.0:
* Removed the use of curve_id as it is no longer present in the ecdh structure
Signed-off-by: Stephan Mueller <smueller@chronox.de>
Signed-off-by: Vikash Bansal <bvikas@vmware.com>
Signed-off-by: Srish Srinivasan <ssrish@vmware.com>
---
crypto/Kconfig | 10 +
crypto/Makefile | 1 +
crypto/af_alg.c | 2 +
crypto/algif_kpp.c | 582 ++++++++++++++++++++++++++++++++++++++++
include/crypto/if_alg.h | 2 +
5 files changed, 597 insertions(+)
create mode 100644 crypto/algif_kpp.c
diff --git a/crypto/Kconfig b/crypto/Kconfig
index c2aa90b98..13556bd15 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -1412,6 +1412,16 @@ config CRYPTO_USER_API_AKCIPHER
This option enables the user-space interface for asymmetric
key cipher algorithms.
+config CRYPTO_USER_API_KPP
+ tristate "User-space interface for key protocol primitives algorithms"
+ depends on NET
+ select CRYPTO_KPP2
+ select CRYPTO_USER_API
+ help
+ This option enables the user-spaces interface for key protocol
+ primitives algorithms. This covers Diffie-Hellman and EC
+ Diffie-Hellman.
+
config CRYPTO_HASH_INFO
bool
diff --git a/crypto/Makefile b/crypto/Makefile
index 4a06f5659..3ea05f3b9 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -164,6 +164,7 @@ obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o
obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o
obj-$(CONFIG_CRYPTO_USER_API_AKCIPHER) += algif_akcipher.o
+obj-$(CONFIG_CRYPTO_USER_API_KPP) += algif_kpp.o
obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o
obj-$(CONFIG_CRYPTO_OFB) += ofb.o
obj-$(CONFIG_CRYPTO_ESSIV) += essiv.o
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index 4178ebac8..e6ef93a28 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -857,6 +857,8 @@ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size,
case ALG_OP_SIGN:
case ALG_OP_ENCRYPT:
case ALG_OP_DECRYPT:
+ case ALG_OP_KEYGEN:
+ case ALG_OP_SSGEN:
op = con.op;
break;
default:
diff --git a/crypto/algif_kpp.c b/crypto/algif_kpp.c
new file mode 100644
index 000000000..d30136020
--- /dev/null
+++ b/crypto/algif_kpp.c
@@ -0,0 +1,582 @@
+/*
+ * algif_kpp: User-space interface for key protocol primitives algorithms
+ *
+ * Copyright (C) 2018 - 2020, Stephan Mueller <smueller@chronox.de>
+ *
+ * This file provides the user-space API for key protocol primitives.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * The following concept of the memory management is used:
+ *
+ * The kernel maintains two SGLs, the TX SGL and the RX SGL. The TX SGL is
+ * filled by user space with the data submitted via sendpage/sendmsg. Filling
+ * up the TX SGL does not cause a crypto operation -- the data will only be
+ * tracked by the kernel. Upon receipt of one recvmsg call, the caller must
+ * provide a buffer which is tracked with the RX SGL.
+ *
+ * During the processing of the recvmsg operation, the cipher request is
+ * allocated and prepared. As part of the recvmsg operation, the processed
+ * TX buffers are extracted from the TX SGL into a separate SGL.
+ *
+ * After the completion of the crypto operation, the RX SGL and the cipher
+ * request is released. The extracted TX SGL parts are released together with
+ * the RX SGL release.
+ */
+
+#include <crypto/dh.h>
+#include <crypto/ecdh.h>
+#include <crypto/kpp.h>
+#include <crypto/rng.h>
+#include <crypto/if_alg.h>
+#include <crypto/scatterwalk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/net.h>
+#include <net/sock.h>
+
+struct kpp_tfm {
+ struct crypto_kpp *kpp;
+ bool has_key;
+
+#define KPP_NO_PARAMS 0
+#define KPP_DH_PARAMS 1
+#define KPP_ECDH_PARAMS 2
+ int has_params; /* Type of KPP mechanism */
+};
+
+static int kpp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
+{
+ return af_alg_sendmsg(sock, msg, size, 0);
+}
+
+static inline int kpp_cipher_op(struct af_alg_ctx *ctx,
+ struct af_alg_async_req *areq)
+{
+ switch (ctx->op) {
+ case ALG_OP_KEYGEN:
+ return crypto_kpp_generate_public_key(&areq->cra_u.kpp_req);
+ case ALG_OP_SSGEN:
+ return crypto_kpp_compute_shared_secret(&areq->cra_u.kpp_req);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int _kpp_recvmsg(struct socket *sock, struct msghdr *msg,
+ size_t ignored, int flags)
+{
+ struct sock *sk = sock->sk;
+ struct alg_sock *ask = alg_sk(sk);
+ struct sock *psk = ask->parent;
+ struct alg_sock *pask = alg_sk(psk);
+ struct af_alg_ctx *ctx = ask->private;
+ struct kpp_tfm *kpp = pask->private;
+ struct crypto_kpp *tfm = kpp->kpp;
+ struct af_alg_async_req *areq;
+ size_t len;
+ size_t used = 0;
+ int err;
+ int maxsize;
+
+ if (!ctx->used) {
+ err = af_alg_wait_for_data(sk, flags, 0);
+ if (err)
+ return err;
+ }
+
+ maxsize = crypto_kpp_maxsize(tfm);
+ if (maxsize < 0)
+ return maxsize;
+
+ /* Allocate cipher request for current operation. */
+ areq = af_alg_alloc_areq(sk, sizeof(struct af_alg_async_req) +
+ crypto_kpp_reqsize(tfm));
+ if (IS_ERR(areq))
+ return PTR_ERR(areq);
+
+ /* convert iovecs of output buffers into RX SGL */
+ err = af_alg_get_rsgl(sk, msg, flags, areq, maxsize, &len);
+ if (err)
+ goto free;
+
+ /* ensure output buffer is sufficiently large */
+ if (len < maxsize) {
+ err = -EMSGSIZE;
+ goto free;
+ }
+
+ /*
+ * Create a per request TX SGL for this request which tracks the
+ * SG entries from the global TX SGL.
+ */
+ if (ctx->op == ALG_OP_SSGEN) {
+ used = ctx->used;
+
+ areq->tsgl_entries = af_alg_count_tsgl(sk, used, 0);
+ if (!areq->tsgl_entries)
+ areq->tsgl_entries = 1;
+ areq->tsgl = sock_kmalloc(
+ sk, sizeof(*areq->tsgl) * areq->tsgl_entries,
+ GFP_KERNEL);
+ if (!areq->tsgl) {
+ err = -ENOMEM;
+ goto free;
+ }
+ sg_init_table(areq->tsgl, areq->tsgl_entries);
+ af_alg_pull_tsgl(sk, used, areq->tsgl, 0);
+ }
+
+ /* Initialize the crypto operation */
+ kpp_request_set_input(&areq->cra_u.kpp_req, areq->tsgl, used);
+ kpp_request_set_output(&areq->cra_u.kpp_req, areq->first_rsgl.sgl.sg,
+ len);
+ kpp_request_set_tfm(&areq->cra_u.kpp_req, tfm);
+
+ if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) {
+ /* AIO operation */
+ sock_hold(sk);
+ areq->iocb = msg->msg_iocb;
+
+ /* Remember output size that will be generated. */
+ areq->outlen = len;
+
+ kpp_request_set_callback(&areq->cra_u.kpp_req,
+ CRYPTO_TFM_REQ_MAY_SLEEP,
+ af_alg_async_cb, areq);
+ err = kpp_cipher_op(ctx, areq);
+
+ /* AIO operation in progress */
+ if (err == -EINPROGRESS || err == -EBUSY)
+ return -EIOCBQUEUED;
+
+ sock_put(sk);
+ } else {
+ /* Synchronous operation */
+ kpp_request_set_callback(&areq->cra_u.kpp_req,
+ CRYPTO_TFM_REQ_MAY_SLEEP |
+ CRYPTO_TFM_REQ_MAY_BACKLOG,
+ crypto_req_done,
+ &ctx->wait);
+ err = crypto_wait_req(kpp_cipher_op(ctx, areq), &ctx->wait);
+ }
+
+free:
+ af_alg_free_resources(areq);
+
+ return err ? err : len;
+}
+
+static int kpp_recvmsg(struct socket *sock, struct msghdr *msg,
+ size_t ignored, int flags)
+{
+ struct sock *sk = sock->sk;
+ struct alg_sock *ask = alg_sk(sk);
+ struct sock *psk = ask->parent;
+ struct alg_sock *pask = alg_sk(psk);
+ struct kpp_tfm *kpp = pask->private;
+ struct crypto_kpp *tfm = kpp->kpp;
+ int ret = 0;
+ int err;
+
+ lock_sock(sk);
+
+ while (msg_data_left(msg)) {
+ err = _kpp_recvmsg(sock, msg, ignored, flags);
+
+ /*
+ * This error covers -EIOCBQUEUED which implies that we can
+ * only handle one AIO request. If the caller wants to have
+ * multiple AIO requests in parallel, he must make multiple
+ * separate AIO calls.
+ */
+ if (err <= 0) {
+ if (err == -EIOCBQUEUED || err == -EBADMSG || !ret)
+ ret = err;
+ goto out;
+ }
+
+ ret += err;
+
+ /*
+ * The caller must provide crypto_kpp_maxsize per request.
+ * If he provides more, we conclude that multiple kpp
+ * operations are requested.
+ */
+ iov_iter_advance(&msg->msg_iter,
+ crypto_kpp_maxsize(tfm) - err);
+ }
+
+out:
+
+ af_alg_wmem_wakeup(sk);
+ release_sock(sk);
+ return ret;
+}
+
+static struct proto_ops algif_kpp_ops = {
+ .family = PF_ALG,
+
+ .connect = sock_no_connect,
+ .socketpair = sock_no_socketpair,
+ .getname = sock_no_getname,
+ .ioctl = sock_no_ioctl,
+ .listen = sock_no_listen,
+ .shutdown = sock_no_shutdown,
+ .getsockopt = sock_getsockopt,
+ .mmap = sock_no_mmap,
+ .bind = sock_no_bind,
+ .accept = sock_no_accept,
+ .setsockopt = sock_setsockopt,
+
+ .release = af_alg_release,
+ .sendmsg = kpp_sendmsg,
+ .sendpage = af_alg_sendpage,
+ .recvmsg = kpp_recvmsg,
+ .poll = af_alg_poll,
+};
+
+static int kpp_check_key(struct socket *sock)
+{
+ struct sock *psk;
+ struct alg_sock *pask;
+ struct kpp_tfm *tfm;
+ struct sock *sk = sock->sk;
+ struct alg_sock *ask = alg_sk(sk);
+ int err = 0;
+
+ lock_sock(sk);
+ if (!atomic_read(&ask->nokey_refcnt))
+ goto unlock_child;
+
+ psk = ask->parent;
+ pask = alg_sk(ask->parent);
+ tfm = pask->private;
+
+ lock_sock_nested(psk, SINGLE_DEPTH_NESTING);
+ if (!tfm->has_key || (tfm->has_params == KPP_NO_PARAMS)) {
+ err = -ENOKEY;
+ goto unlock;
+ }
+
+ atomic_dec(&pask->nokey_refcnt);
+ atomic_set(&ask->nokey_refcnt, 0);
+
+ err = 0;
+
+unlock:
+ release_sock(psk);
+unlock_child:
+ release_sock(sk);
+
+ return err;
+}
+
+static int kpp_sendmsg_nokey(struct socket *sock, struct msghdr *msg,
+ size_t size)
+{
+ int err;
+
+ err = kpp_check_key(sock);
+ if (err)
+ return err;
+
+ return kpp_sendmsg(sock, msg, size);
+}
+
+static ssize_t kpp_sendpage_nokey(struct socket *sock, struct page *page,
+ int offset, size_t size, int flags)
+{
+ int err;
+
+ err = kpp_check_key(sock);
+ if (err)
+ return err;
+
+ return af_alg_sendpage(sock, page, offset, size, flags);
+}
+
+static int kpp_recvmsg_nokey(struct socket *sock, struct msghdr *msg,
+ size_t ignored, int flags)
+{
+ int err;
+
+ err = kpp_check_key(sock);
+ if (err)
+ return err;
+
+ return kpp_recvmsg(sock, msg, ignored, flags);
+}
+
+static struct proto_ops algif_kpp_ops_nokey = {
+ .family = PF_ALG,
+
+ .connect = sock_no_connect,
+ .socketpair = sock_no_socketpair,
+ .getname = sock_no_getname,
+ .ioctl = sock_no_ioctl,
+ .listen = sock_no_listen,
+ .shutdown = sock_no_shutdown,
+ .getsockopt = sock_getsockopt,
+ .mmap = sock_no_mmap,
+ .bind = sock_no_bind,
+ .accept = sock_no_accept,
+ .setsockopt = sock_setsockopt,
+
+ .release = af_alg_release,
+ .sendmsg = kpp_sendmsg_nokey,
+ .sendpage = kpp_sendpage_nokey,
+ .recvmsg = kpp_recvmsg_nokey,
+ .poll = af_alg_poll,
+};
+
+static void *kpp_bind(const char *name, u32 type, u32 mask)
+{
+ struct kpp_tfm *tfm;
+ struct crypto_kpp *kpp;
+
+ tfm = kmalloc(sizeof(*tfm), GFP_KERNEL);
+ if (!tfm)
+ return ERR_PTR(-ENOMEM);
+
+ kpp = crypto_alloc_kpp(name, type, mask);
+ if (IS_ERR(kpp)) {
+ kfree(tfm);
+ return ERR_CAST(kpp);
+ }
+
+ tfm->kpp = kpp;
+ tfm->has_key = false;
+ tfm->has_params = KPP_NO_PARAMS;
+
+ return tfm;
+}
+
+static void kpp_release(void *private)
+{
+ struct kpp_tfm *tfm = private;
+ struct crypto_kpp *kpp = tfm->kpp;
+
+ crypto_free_kpp(kpp);
+ kfree(tfm);
+}
+
+static int kpp_dh_set_secret(struct crypto_kpp *tfm, struct dh *params)
+{
+ char *packed_key = NULL;
+ unsigned int packed_key_len;
+ int ret;
+
+ packed_key_len = crypto_dh_key_len(params);
+ packed_key = kmalloc(packed_key_len, GFP_KERNEL);
+ if (!packed_key)
+ return -ENOMEM;
+
+ ret = crypto_dh_encode_key(packed_key, packed_key_len, params);
+ if (ret)
+ goto out;
+
+ ret = crypto_kpp_set_secret(tfm, packed_key, packed_key_len);
+
+out:
+ kfree(packed_key);
+ return ret;
+}
+
+static int kpp_dh_set_privkey(struct crypto_kpp *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct dh params = {
+ .key = key,
+ .key_size = keylen,
+ .p = NULL,
+ .p_size = 0,
+ .g = NULL,
+ .g_size = 0,
+ };
+
+ return kpp_dh_set_secret(tfm, &params);
+}
+
+static int kpp_ecdh_set_secret(struct crypto_kpp *tfm, struct ecdh *params)
+{
+ char *packed_key = NULL;
+ unsigned int packed_key_len;
+ int ret;
+
+ packed_key_len = crypto_ecdh_key_len(params);
+ packed_key = kmalloc(packed_key_len, GFP_KERNEL);
+ if (!packed_key)
+ return -ENOMEM;
+
+ ret = crypto_ecdh_encode_key(packed_key, packed_key_len, params);
+ if (ret)
+ goto out;
+
+ ret = crypto_kpp_set_secret(tfm, packed_key, packed_key_len);
+
+out:
+ kfree(packed_key);
+ return ret;
+}
+
+static int kpp_ecdh_set_privkey(struct crypto_kpp *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct ecdh params = {
+ .key = key,
+ .key_size = keylen,
+ };
+
+ return kpp_ecdh_set_secret(tfm, &params);
+}
+
+static int kpp_setprivkey(void *private, const u8 *key, unsigned int keylen)
+{
+ struct kpp_tfm *kpp = private;
+ struct crypto_kpp *tfm = kpp->kpp;
+ int err;
+
+ if (kpp->has_params == KPP_NO_PARAMS)
+ return -ENOKEY;
+
+ /* The DH code cannot generate private keys. ECDH can do that */
+ if ((!key || !keylen) && (kpp->has_params == KPP_DH_PARAMS)) {
+ kpp->has_key = false;
+ return -EOPNOTSUPP;
+ }
+
+ switch (kpp->has_params) {
+ case KPP_DH_PARAMS:
+ err = kpp_dh_set_privkey(tfm, key, keylen);
+ break;
+ case KPP_ECDH_PARAMS:
+ err = kpp_ecdh_set_privkey(tfm, key, keylen);
+ break;
+ default:
+ err = -EFAULT;
+ }
+
+ kpp->has_key = !err;
+
+ /* Return the maximum size of the kpp operation. */
+ if (!err)
+ err = crypto_kpp_maxsize(tfm);
+
+ return err;
+}
+
+static int kpp_ecdh_setcurve(void *private, const u8 *curveid,
+ unsigned int curveidlen)
+{
+ struct kpp_tfm *kpp = private;
+ struct crypto_kpp *tfm = kpp->kpp;
+ int err;
+ struct ecdh params = {
+ .key = NULL,
+ .key_size = 0,
+ };
+
+ /* If parameters were already set, disallow setting them again. */
+ if (kpp->has_params != KPP_NO_PARAMS)
+ return -EINVAL;
+
+ if (curveidlen != sizeof(unsigned long))
+ return -EINVAL;
+
+ err = kpp_ecdh_set_secret(tfm, &params);
+ if (!err) {
+ kpp->has_params = KPP_ECDH_PARAMS;
+ /* Return the maximum size of the kpp operation. */
+ err = crypto_kpp_maxsize(tfm);
+ } else
+ kpp->has_params = KPP_NO_PARAMS;
+
+ return err;
+}
+
+static void kpp_sock_destruct(struct sock *sk)
+{
+ struct alg_sock *ask = alg_sk(sk);
+ struct af_alg_ctx *ctx = ask->private;
+
+ af_alg_pull_tsgl(sk, ctx->used, NULL, 0);
+ sock_kfree_s(sk, ctx, ctx->len);
+ af_alg_release_parent(sk);
+}
+
+static int kpp_accept_parent_nokey(void *private, struct sock *sk)
+{
+ struct af_alg_ctx *ctx;
+ struct alg_sock *ask = alg_sk(sk);
+ unsigned int len = sizeof(*ctx);
+
+ ctx = sock_kmalloc(sk, len, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&ctx->tsgl_list);
+ ctx->len = len;
+ ctx->used = 0;
+ atomic_set(&ctx->rcvused, 0);
+ ctx->more = 0;
+ ctx->merge = 0;
+ ctx->op = 0;
+ crypto_init_wait(&ctx->wait);
+
+ ask->private = ctx;
+
+ sk->sk_destruct = kpp_sock_destruct;
+
+ return 0;
+}
+
+static int kpp_accept_parent(void *private, struct sock *sk)
+{
+ struct kpp_tfm *tfm = private;
+
+ if (!tfm->has_key || (tfm->has_params == KPP_NO_PARAMS))
+ return -ENOKEY;
+
+ return kpp_accept_parent_nokey(private, sk);
+}
+
+static const struct af_alg_type algif_type_kpp = {
+ .bind = kpp_bind,
+ .release = kpp_release,
+ .setkey = kpp_setprivkey,
+ .setpubkey = NULL,
+ .dhparams = NULL,
+ .ecdhcurve = kpp_ecdh_setcurve,
+ .setauthsize = NULL,
+ .accept = kpp_accept_parent,
+ .accept_nokey = kpp_accept_parent_nokey,
+ .ops = &algif_kpp_ops,
+ .ops_nokey = &algif_kpp_ops_nokey,
+ .name = "kpp",
+ .owner = THIS_MODULE
+};
+
+static int __init algif_kpp_init(void)
+{
+ return af_alg_register_type(&algif_type_kpp);
+}
+
+static void __exit algif_kpp_exit(void)
+{
+ int err = af_alg_unregister_type(&algif_type_kpp);
+
+ BUG_ON(err);
+}
+
+module_init(algif_kpp_init);
+module_exit(algif_kpp_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
+MODULE_DESCRIPTION("Key protocol primitives kernel crypto API user space interface");
diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
index 1412672e1..85a67f635 100644
--- a/include/crypto/if_alg.h
+++ b/include/crypto/if_alg.h
@@ -19,6 +19,7 @@
#include <crypto/aead.h>
#include <crypto/skcipher.h>
#include <crypto/akcipher.h>
+#include <crypto/kpp.h>
#define ALG_MAX_PAGES 16
@@ -115,6 +116,7 @@ struct af_alg_async_req {
struct aead_request aead_req;
struct skcipher_request skcipher_req;
struct akcipher_request akcipher_req;
+ struct kpp_request kpp_req;
} cra_u;
/* req ctx trails this struct */
--
2.17.1

View File

@ -0,0 +1,333 @@
From ea71c92640a871da306d555b588f42c8e5a90743 Mon Sep 17 00:00:00 2001
From: srinidhira0 <srinidhir@vmware.com>
Date: Tue, 8 Feb 2022 11:10:27 +0000
Subject: [PATCH] crypto: AF_ALG - add ECC support
The patch externalizes the ECC crypto API to user space. ECC domain does not
require cipher handler (such as ECDH for KPP) as ECC routines can be called
directly and there is no ECC cipher algo.
The following operations are supported:
* Key generation. Return values are private key, public key in form of X and
Y coordinates.
* Key verification. It takes X and Y coordinates of a public key as an input
and performs validation.
Since we need only 2 operations from ECC: to verify key and to generate
key, simply sendmsg/recvmsg API for this domain will be sufficient.
Enabling CONFIG_CRYPTO_USER_API_ECC is not recommended for production, but
it will not harm if enabled, as it does not expose used by kernel keys to
user space.
Added support for LKCM 5.0:
* In LKCM 4.0 (kernel v5.10.x), nist_p256 was the only fips supported curve.
* In kernel v6.1.x, there are two fips supported curves - nist_p256 and nist_p384
* Tweaked ecc_sendmsg and ecc_recvmsg to accomodate both these curves while performing
keyVer and keyGen respectively.
Signed-off-by: Alexey Makhalov <amakhalov@vmware.com>
Signed-off-by: srinidhira0 <srinidhir@vmware.com>
Signed-off-by: Srish Srinivasan <ssrish@vmware.com>
---
crypto/Kconfig | 8 ++
crypto/Makefile | 1 +
crypto/algif_ecc.c | 253 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 262 insertions(+)
create mode 100644 crypto/algif_ecc.c
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 573d692f1..31fab9344 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -1422,6 +1422,14 @@ config CRYPTO_USER_API_KPP
primitives algorithms. This covers Diffie-Hellman and EC
Diffie-Hellman.
+config CRYPTO_USER_API_ECC
+ tristate "User-space interface for ECC primitives algorithms"
+ depends on NET
+ select CRYPTO_USER_API
+ help
+ This option enables the user-spaces interface for ECC
+ primitives algorithms that are used in EC Diffie-Hellman.
+
config CRYPTO_HASH_INFO
bool
diff --git a/crypto/Makefile b/crypto/Makefile
index 0a5cb6e22..f52797a08 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -161,6 +161,7 @@ obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o
obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o
obj-$(CONFIG_CRYPTO_USER_API_AKCIPHER) += algif_akcipher.o
obj-$(CONFIG_CRYPTO_USER_API_KPP) += algif_kpp.o
+obj-$(CONFIG_CRYPTO_USER_API_ECC) += algif_ecc.o
obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o
obj-$(CONFIG_CRYPTO_OFB) += ofb.o
obj-$(CONFIG_CRYPTO_ESSIV) += essiv.o
diff --git a/crypto/algif_ecc.c b/crypto/algif_ecc.c
new file mode 100644
index 000000000..865b479f5
--- /dev/null
+++ b/crypto/algif_ecc.c
@@ -0,0 +1,253 @@
+/*
+ * algif_ecc: User-space interface for ECC routines
+ *
+ * Copyright (C) 2022, VMware Inc.
+ * Author: Alexey Makhalov <amakhalov@vmware.com>
+ *
+ * This file provides the user-space API for ECC routins for keyGen and keyVer
+ * ACVP testing.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * The following concept of the memory management is used:
+ *
+ * The kernel maintains two SGLs, the TX SGL and the RX SGL. The TX SGL is
+ * filled by user space with the data submitted via sendpage/sendmsg. Filling
+ * up the TX SGL does not cause a crypto operation -- the data will only be
+ * tracked by the kernel. Upon receipt of one recvmsg call, the caller must
+ * provide a buffer which is tracked with the RX SGL.
+ *
+ * During the processing of the recvmsg operation, the cipher request is
+ * allocated and prepared. As part of the recvmsg operation, the processed
+ * TX buffers are extracted from the TX SGL into a separate SGL.
+ *
+ * After the completion of the crypto operation, the RX SGL and the cipher
+ * request is released. The extracted TX SGL parts are released together with
+ * the RX SGL release.
+ */
+
+#include <crypto/if_alg.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/net.h>
+#include <net/sock.h>
+#include <crypto/internal/ecc.h>
+#include "ecc_curve_defs.h"
+
+/*
+ * Sendmsg to ecc socket is used only to verify public key curve point.
+ * There are 2 input iov segments, one for x coordinate and another for y.
+ * On success, it returns number of bytes that were verified.
+ * Negative return value means failure. -EINVAL value get returned if
+ * key verification failed.
+ */
+
+static int ecc_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
+{
+ const struct iovec *iov;
+ int ret;
+ /* FIPS supported curves: nist_p256 and nist_p384 */
+ const struct ecc_curve *curve = &nist_p256;
+ u8 x_buf[48] = {0}, y_buf[48] = {0}, hash_buf[64] = {0};
+ int curve_id = 2;
+
+ if (!iter_is_iovec(&msg->msg_iter))
+ return -ENOTSUPP;
+
+ if(msg->msg_iter.nr_segs == 3) {
+
+ iov = msg->msg_iter.iov;
+ struct ecc_point pk;
+
+ if(iov[2].iov_len == 384)
+ curve = &nist_p384;
+
+ if (iov[0].iov_len != curve->g.ndigits * sizeof(u64) ||
+ iov[1].iov_len != curve->g.ndigits * sizeof(u64))
+ return -EINVAL;
+
+ ret = copy_from_user(x_buf, iov[0].iov_base, iov[0].iov_len);
+ if (ret) {
+ pr_err("\n Error in copying X from iov_base %p %d\n",
+ iov[0].iov_base, ret);
+ return -ENOMEM;
+ }
+ ret = copy_from_user(y_buf, iov[1].iov_base, iov[1].iov_len);
+ if (ret) {
+ pr_err("\n Error in copying Y from iov_base %p %d\n",
+ iov[1].iov_base, ret);
+ return -ENOMEM;
+ }
+
+ pk.ndigits = curve->g.ndigits;
+ pk.x = kmalloc(pk.ndigits * sizeof(u64), GFP_KERNEL);
+ if (!pk.x)
+ return -ENOMEM;
+
+ pk.y = kmalloc(pk.ndigits * sizeof(u64), GFP_KERNEL);
+ if (!pk.y) {
+ kfree(pk.x);
+ return -ENOMEM;
+ }
+
+ ecc_swap_digits((u64 *)x_buf, pk.x, pk.ndigits);
+ ecc_swap_digits((u64 *)y_buf, pk.y, pk.ndigits);
+
+ ret = ecc_is_pubkey_valid_full(curve, &pk);
+
+
+ kfree(pk.x);
+ kfree(pk.y);
+ return ret;
+ }
+ else
+ return -EINVAL;
+}
+
+/*
+ * Recvmsg from ecc socket is used only to generate private/public key pair
+ * There are 3 output iov segments, one for private key and other two for x
+ * and y coordinates of the public key. Concatenation of bytes from these
+ * coordinates gives a public key.
+ * On success, it returns number of bytes that were provided.
+ * Negative return value means failure.
+ */
+static int ecc_recvmsg(struct socket *sock, struct msghdr *msg,
+ size_t ignored, int flags)
+{
+ const struct iovec *iov;
+ u64 pubkey[12];
+ int ret;
+ /* FIPS supported curves: nist_p256 and nist_p384 */
+ struct ecc_curve *curve = &nist_p256;
+ u8 d_buf[48] = {0};
+ int curve_id = 2;
+
+ if (!iter_is_iovec(&msg->msg_iter))
+ return -ENOTSUPP;
+
+ if (msg->msg_iter.nr_segs != 4)
+ return -EINVAL;
+
+ iov = msg->msg_iter.iov;
+
+ if(iov[3].iov_len == 384){
+ curve = &nist_p384;
+ curve_id = 3;
+ }
+
+ if (iov[0].iov_len != curve->g.ndigits * sizeof(u64) ||
+ iov[1].iov_len != curve->g.ndigits * sizeof(u64) ||
+ iov[2].iov_len != curve->g.ndigits * sizeof(u64))
+ return -EINVAL;
+
+ ret = ecc_gen_privkey(curve_id, curve->g.ndigits, (u64 *)d_buf);
+ if (ret < 0)
+ return ret;
+
+ ret = ecc_make_pub_key(curve_id, curve->g.ndigits, (u64 *)d_buf, pubkey);
+ if (ret < 0)
+ return ret;
+
+ ret = copy_to_user(iov[0].iov_base, d_buf, iov[0].iov_len);
+ if (ret) {
+ pr_err("\n Error in copying from iov_base %p %d\n",
+ iov[0].iov_base, ret);
+ return -ENOMEM;
+ }
+ ret = copy_to_user(iov[1].iov_base, pubkey,
+ curve->g.ndigits * sizeof(u64));
+ if (ret) {
+ pr_err("\n Err in copying to user %d\n", ret);
+ return -ENOMEM;
+ }
+ ret = copy_to_user(iov[2].iov_base, &pubkey[curve->g.ndigits],
+ curve->g.ndigits * sizeof(u64));
+ if (ret) {
+ pr_err("\n Err in copying to user %d\n", ret);
+ return -ENOMEM;
+ }
+
+ return msg->msg_iter.count;
+}
+
+static struct proto_ops algif_ecc_ops = {
+ .family = PF_ALG,
+
+ .connect = sock_no_connect,
+ .socketpair = sock_no_socketpair,
+ .getname = sock_no_getname,
+ .ioctl = sock_no_ioctl,
+ .listen = sock_no_listen,
+ .shutdown = sock_no_shutdown,
+ .getsockopt = sock_getsockopt,
+ .mmap = sock_no_mmap,
+ .bind = sock_no_bind,
+ .accept = sock_no_accept,
+ .setsockopt = sock_setsockopt,
+
+ .release = af_alg_release,
+ .sendmsg = ecc_sendmsg,
+ .sendpage = af_alg_sendpage,
+ .recvmsg = ecc_recvmsg,
+ .poll = af_alg_poll,
+};
+
+static void *ecc_bind(const char *name, u32 type, u32 mask)
+{
+ return 0;
+}
+
+static void ecc_release(void *private)
+{
+}
+
+static void ecc_sock_destruct(struct sock *sk)
+{
+}
+
+static int ecc_accept_parent(void *private, struct sock *sk)
+{
+ sk->sk_destruct = ecc_sock_destruct;
+ return 0;
+}
+
+static const struct af_alg_type algif_type_ecc = {
+ .bind = ecc_bind,
+ .release = ecc_release,
+ .setkey = NULL,
+ .setpubkey = NULL,
+ .dhparams = NULL,
+ .ecdhcurve = NULL,
+ .setauthsize = NULL,
+ .accept = ecc_accept_parent,
+ .accept_nokey = NULL,
+ .ops = &algif_ecc_ops,
+ .ops_nokey = NULL,
+ .name = "ecc",
+ .owner = THIS_MODULE
+};
+
+static int __init algif_ecc_init(void)
+{
+ return af_alg_register_type(&algif_type_ecc);
+}
+
+static void __exit algif_ecc_exit(void)
+{
+ int err = af_alg_unregister_type(&algif_type_ecc);
+
+ BUG_ON(err);
+}
+
+module_init(algif_ecc_init);
+module_exit(algif_ecc_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexey Makhalov <amakhalov@vmware.com>");
+MODULE_DESCRIPTION("ECC primitives kernel crypto API user space interface");
--
2.35.6

View File

@ -0,0 +1,29 @@
From 9a10c8668c56f4da65ad5a3386fff303ea700514 Mon Sep 17 00:00:00 2001
From: srinidhira0 <srinidhir@vmware.com>
Date: Tue, 8 Feb 2022 12:30:38 +0000
Subject: [PATCH] kernels:net: Export sock_getsockopt
- Export the symbol sock_getsockopt.
Signed-off-by: srinidhira0 <srinidhir@vmware.com>
Signed-off-by: Srish Srinivasan <ssrish@vmware.com>
---
net/core/sock.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net/core/sock.c b/net/core/sock.c
index 30407b2dd..3379779be 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1949,6 +1949,7 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
return -EFAULT;
return 0;
}
+EXPORT_SYMBOL(sock_getsockopt);
int sock_getsockopt(struct socket *sock, int level, int optname,
char __user *optval, int __user *optlen)
--
2.17.1

View File

@ -0,0 +1,58 @@
From a3503190e5f761ec5313685a74318e0dc7c5cbf0 Mon Sep 17 00:00:00 2001
From: Vikash Bansal <bvikas@vmware.com>
Date: Thu, 28 Jan 2021 08:13:00 +0530
Subject: [PATCH] drbg: Fixed issue
Fixed issue with MaxSize and Setting Entropy
---
crypto/af_alg.c | 7 +++++--
crypto/algif_rng.c | 5 ++++-
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index e6ef93a28..6475030d6 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -238,8 +238,11 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,
int err = -EBUSY;
lock_sock(sk);
- if (atomic_read(&ask->refcnt) != atomic_read(&ask->nokey_refcnt))
- goto unlock;
+
+ if(strcmp(ask->type->name, "rng")) {
+ if (atomic_read(&ask->refcnt) != atomic_read(&ask->nokey_refcnt))
+ goto unlock;
+ }
type = ask->type;
diff --git a/crypto/algif_rng.c b/crypto/algif_rng.c
index 407408c43..1a84f23fe 100644
--- a/crypto/algif_rng.c
+++ b/crypto/algif_rng.c
@@ -51,7 +51,7 @@ MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
MODULE_DESCRIPTION("User-space interface for random number generators");
struct rng_ctx {
-#define MAXSIZE 128
+#define MAXSIZE 256
unsigned int len;
struct crypto_rng *drng;
u8 *addtl;
@@ -293,8 +293,11 @@ static int __maybe_unused rng_setentropy(void *private, sockptr_t entropy,
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
+#if 0
+#Entropy can be set multiple times if pr=true
if (pctx->entropy)
return -EINVAL;
+#endif
if (len > MAXSIZE)
return -EMSGSIZE;
--
2.17.1

View File

@ -0,0 +1,97 @@
From fe09ae9b7169583f3ace090bff0237c2aa5880c7 Mon Sep 17 00:00:00 2001
From: Srish Srinivasan <ssrish@vmware.com>
Date: Thu, 28 Sep 2023 07:52:42 +0000
Subject: [PATCH] Added jitterentropy implementation of SHA3-256
---
crypto/jitterentropy-kcapi.c | 45 ++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/crypto/jitterentropy-kcapi.c b/crypto/jitterentropy-kcapi.c
index 8b98d2e29..891b92d1d 100644
--- a/crypto/jitterentropy-kcapi.c
+++ b/crypto/jitterentropy-kcapi.c
@@ -43,9 +43,11 @@
#include <linux/slab.h>
#include <linux/time.h>
#include <crypto/internal/rng.h>
+#include <crypto/internal/hash.h>
#include "jitterentropy-3.4.1/jitterentropy.h"
#include "jitterentropy-3.4.1/jitterentropy-timer.h"
+#include "jitterentropy-3.4.1/jitterentropy-sha3.h"
/***************************************************************************
* Helper function
@@ -147,6 +149,30 @@ static int jent_kcapi_reset(struct crypto_rng *tfm,
return 0;
}
+int sha3_256_init_wrapper(struct shash_desc *desc)
+{
+ struct sha_ctx *sctx = shash_desc_ctx(desc);
+ sha3_256_init(sctx);
+ return 0;
+}
+EXPORT_SYMBOL(sha3_256_init_wrapper);
+
+int sha3_update_wrapper(struct shash_desc *desc, const u8 *data, unsigned int len)
+{
+ struct sha_ctx *sctx = shash_desc_ctx(desc);
+ sha3_update(sctx, data, len);
+ return 0;
+}
+EXPORT_SYMBOL(sha3_update_wrapper);
+
+int sha3_final_wrapper(struct shash_desc *desc, u8 *out)
+{
+ struct sha_ctx *sctx = shash_desc_ctx(desc);
+ sha3_final(sctx, out);
+ return 0;
+}
+EXPORT_SYMBOL(sha3_final_wrapper);
+
static struct rng_alg jent_alg = {
.generate = jent_kcapi_random,
.seed = jent_kcapi_reset,
@@ -163,6 +189,18 @@ static struct rng_alg jent_alg = {
}
};
+static struct shash_alg algs[] = { {
+ .digestsize = SHA3_256_SIZE_DIGEST,
+ .init = sha3_256_init_wrapper,
+ .update = sha3_update_wrapper,
+ .final = sha3_final_wrapper,
+ .descsize = sizeof(struct sha_ctx),
+ .base.cra_name = "jitter-sha3-256",
+ .base.cra_driver_name = "jitter-sha3-256-generic",
+ .base.cra_blocksize = SHA3_256_SIZE_BLOCK,
+ .base.cra_module = THIS_MODULE,
+} };
+
static int __init jent_mod_init(void)
{
int ret = 0;
@@ -176,12 +214,19 @@ static int __init jent_mod_init(void)
pr_info("jitterentropy: Initialization failed with host not compliant with requirements: %d\n", ret);
return -EFAULT;
}
+ ret = crypto_register_shashes(algs, ARRAY_SIZE(algs));
+ if (ret) {
+ pr_info("jitterentropy: jitter-sha3-256 registration failed with err: %d\n", ret);
+ return -EFAULT;
+ }
+
return crypto_register_rng(&jent_alg);
}
static void __exit jent_mod_exit(void)
{
crypto_unregister_rng(&jent_alg);
+ crypto_unregister_shashes(algs, ARRAY_SIZE(algs));
}
/* Must be initialized before tcrypt */
--
2.39.0

View File

@ -14,6 +14,10 @@
%endif
%endif
%if 0%{?acvp_build}
%global fips 1
%endif
%ifarch aarch64
%define arch arm64
%define archdir arm64
@ -23,7 +27,7 @@
Summary: Kernel
Name: linux
Version: 6.1.56
Release: 3%{?kat_build:.kat}%{?dist}
Release: 4%{?acvp_build:.acvp}%{?kat_build:.kat}%{?dist}
License: GPLv2
URL: http://www.kernel.org/
Group: System Environment/Kernel
@ -217,6 +221,22 @@ Patch511: 0003-FIPS-broken-kattest.patch
%endif
%endif
%if 0%{?acvp_build:1}
#ACVP test harness patches.
#Need to be applied on top of FIPS canister usage patch to avoid HUNK failure
Patch512: 0001-crypto-AF_ALG-add-sign-verify-API.patch
Patch513: 0002-crypto-AF_ALG-add-setpubkey-setsockopt-call.patch
Patch514: 0003-crypto-AF_ALG-add-asymmetric-cipher.patch
Patch515: 0004-crypto-AF_ALG-add-DH-keygen-ssgen-API.patch
Patch516: 0005-crypto-AF_ALG-add-DH-param-ECDH-curve-setsockopt.patch
Patch517: 0006-crypto-AF_ALG-eliminate-code-duplication.patch
Patch518: 0007-crypto-AF_ALG-add-KPP-support.patch
Patch519: 0008-crypto-AF_ALG-add-ECC-support.patch
Patch520: 0009-kernels-net-Export-sock_getsockopt.patch
Patch521: 0010-DRBG-Fix-issues-with-DRBG.patch
Patch522: 0011-Added-jitterentropy-implementation-of-SHA3-256.patch
%endif
%ifarch x86_64
# SEV on VMware: [600..609]
Patch600: 0079-x86-sev-es-Disable-BIOS-ACPI-RSDP-probing-if-SEV-ES-.patch
@ -405,6 +425,12 @@ manipulation of eBPF programs and maps.
%autopatch -p1 -m511 -M511
%endif
%if 0%{?acvp_build:1}
#ACVP test harness patches.
#Need to be applied on top of FIPS canister usage patch to avoid HUNK failure
%autopatch -p1 -m512 -M522
%endif
%ifarch x86_64
# SEV on VMware
%autopatch -p1 -m600 -M609
@ -442,6 +468,27 @@ cp %{SOURCE35} crypto/jitterentropy-%{jent_major_version}/
make %{?_smp_mflags} mrproper
cp %{SOURCE1} .config
%if 0%{?acvp_build:1}
#ACVP test harness changes in kernel configs.
sed -i 's/# CONFIG_CRYPTO_USER is not set/CONFIG_CRYPTO_USER=y/' .config
sed -i 's/# CONFIG_CRYPTO_DH is not set/CONFIG_CRYPTO_DH=y/' .config
sed -i 's/CONFIG_CRYPTO_USER_API=m/CONFIG_CRYPTO_USER_API=y/' .config
sed -i 's/CONFIG_CRYPTO_USER_API_HASH=m/CONFIG_CRYPTO_USER_API_HASH=y/' .config
sed -i 's/CONFIG_CRYPTO_USER_API_SKCIPHER=m/CONFIG_CRYPTO_USER_API_SKCIPHER=y/' .config
sed -i 's/CONFIG_CRYPTO_USER_API_RNG=m/CONFIG_CRYPTO_USER_API_RNG=y/' .config
sed -i 's/# CONFIG_CRYPTO_USER_API_RNG_CAVP is not set/CONFIG_CRYPTO_USER_API_RNG_CAVP=y/' .config
sed -i 's/# CONFIG_CRYPTO_USER_API_AEAD is not set/CONFIG_CRYPTO_USER_API_AEAD=y/' .config
sed -i '/CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE/ a # CONFIG_CRYPTO_STATS is not set' .config
sed -i '/CONFIG_CRYPTO_STATS/ a CONFIG_CRYPTO_USER_API_AKCIPHER=y' .config
sed -i '/CONFIG_CRYPTO_USER_API_AKCIPHER/ a CONFIG_CRYPTO_USER_API_KPP=y' .config
sed -i '/CONFIG_CRYPTO_USER_API_KPP=y/ a CONFIG_CRYPTO_USER_API_ECC=y' .config
sed -i '/CONFIG_CRYPTO_DH=y/ a # CONFIG_CRYPTO_DH_RFC7919_GROUPS is not set' .config
sed -i '/# end of Userspace interface/ { N; d; }' .config
sed -i '/# CONFIG_CRYPTO_STATS is not set/ a # end of Userspace interface' .config
sed -i '/# end of Userspace interface/{G;}' .config
%endif
cp %{SOURCE20} photon_sb2020.pem
%if 0%{?fips}
cp ../fips-canister-%{fips_canister_version}/fips_canister.o \
@ -746,6 +793,9 @@ ln -sf linux-%{uname_r}.cfg /boot/photon.cfg
%{_datadir}/bash-completion/completions/bpftool
%changelog
* Wed Nov 29 2023 Srish Srinivasan <ssrish@vmware.com> 6.1.56-4
- Adding support for ACVP build
- Added jitterentropy implementation of SHA3-256
* Wed Nov 29 2023 Srish Srinivasan <ssrish@vmware.com> 6.1.56-3
- Add missing self-test vector for ecdh-nist-p384 with genkey
* Wed Nov 29 2023 Srinidhi Rao <srinidhir@vmware.com> 6.1.56-2

5
build.py Executable file → Normal file
View File

@ -1481,6 +1481,9 @@ def initialize_constants():
constants.setCanisterBuild(
configdict["photon-build-param"].get("canister-build", False)
)
constants.setAcvpBuild(
configdict["photon-build-param"].get("acvp-build", False)
)
Build_Config.setConfFile(configdict["additional-path"]["conf-file"])
Build_Config.setPkgToBeCopiedConfFile(
configdict.get("additional-path", {}).get("pkg-to-be-copied-conf-file")
@ -1569,6 +1572,7 @@ def process_env_build_params(ph_build_param):
"PHOTON_DOCKER_IMAGE": "photon-docker-image",
"KAT_BUILD": "kat-build",
"CANISTER_BUILD": "canister-build",
"ACVP_BUILD": "acvp-build",
"BUILDDEPS": "publish-build-dependencies",
"PH_DOCKER_IMAGE_URL": "ph-docker-img-url",
"BUILD_SRC_RPM": "build-src-rpm",
@ -1602,6 +1606,7 @@ def process_env_build_params(ph_build_param):
"BUILDDEPS",
"SCHEDULER_SERVER",
"CANISTER_BUILD",
"ACVP_BUILD",
"BUILD_EXTRA_PKGS",
"RESUME_BUILD",
}:

View File

@ -63,6 +63,10 @@ Build config file is a json format with possible parameters:
Default value: null
Example: { "photon-build-param": { "kat-build" : null } }
"acvp-build":
Default value: null
Example: { "photon-build-param": { "acvp-build" : null } }
"pkg-build-options":
Default value: "pkg_build_options.json"
Example: { "photon-build-param": { "pkg-build-options" : "pkg_build_options.json" } }

View File

@ -76,6 +76,7 @@ class BuilderClient:
constants.setPackageWeightsPath(constant_dict["packageWeightsPath"])
constants.setKatBuild(constant_dict["katBuild"])
constants.setCanisterBuild(constant_dict["canisterBuild"])
constants.setAcvpBuild(constant_dict['acvpBuild'])
constants.extrasourcesURLs = constant_dict["extrasourcesURLs"]
constants.userDefinedMacros = constant_dict["userDefinedMacros"]
constants.tmpDirPath = constant_dict["tmpDirPath"]

View File

@ -114,6 +114,7 @@ def getConstants():
constant_dict["userDefinedMacros"] = constants.userDefinedMacros
constant_dict["katBuild"] = constants.katBuild
constant_dict["canisterBuild"] = constants.canisterBuild
constant_dict['acvpBuild'] = constants.acvpBuild
constant_dict["tmpDirPath"] = constants.tmpDirPath
constant_dict["buildArch"] = constants.buildArch
constant_dict["currentArch"] = constants.currentArch

View File

@ -35,6 +35,7 @@ class constants(object):
releaseVersion = None
katBuild = False
canisterBuild = False
acvpBuild = False
testForceRPMS = []
tmpDirPath = "/dev/shm"
buildOptions = {}
@ -491,6 +492,10 @@ class constants(object):
def setCanisterBuild(canisterBuild):
constants.canisterBuild = canisterBuild
@staticmethod
def setAcvpBuild(acvpBuild):
constants.acvpBuild = acvpBuild
@staticmethod
def setCompressionMacro(compressionMacro):
constants.addMacro("_source_payload", compressionMacro)
@ -526,6 +531,9 @@ class constants(object):
if constants.canisterBuild:
constants.addMacro("canister_build", "1")
if constants.acvpBuild:
constants.addMacro("acvp_build", "1")
@staticmethod
def setTestForceRPMS(listsPackages):
constants.testForceRPMS = listsPackages