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:
parent
251d7a2ac3
commit
d6fa2406b7
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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, ¶ms);
|
||||
+}
|
||||
+
|
||||
+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, ¶ms);
|
||||
+}
|
||||
+
|
||||
+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, ¶ms);
|
||||
+ 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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
}:
|
||||
|
|
|
@ -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" } }
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue