From: Elena Petrova <lenaptr@google.com>
To: linux-crypto@vger.kernel.org
Cc: "Elena Petrova" <lenaptr@google.com>,
"Eric Biggers" <ebiggers@kernel.org>,
"Stephan Müller" <smueller@chronox.de>,
"Ard Biesheuvel" <ardb@kernel.org>
Subject: [PATCH v2] crypto: af_alg - add extra parameters for DRBG interface
Date: Thu, 16 Jul 2020 17:40:28 +0100 [thread overview]
Message-ID: <20200716164028.1805047-1-lenaptr@google.com> (raw)
In-Reply-To: <CABvBcwY44BPa+TaDwxWaEogpg3Kdkq8o9cR5gSqNGF-o6d3jrw@mail.gmail.com>
Extending the userspace RNG interface:
1. adding ALG_SET_DRBG_ENTROPY setsockopt option for entropy input;
2. using sendmsg syscall for specifying the additional data.
Signed-off-by: Elena Petrova <lenaptr@google.com>
---
libkcapi patch for testing:
https://github.com/Len0k/libkcapi/commit/6f095d270b982008f419078614c15caa592cb531
Updates in v2:
1) Adding CONFIG_CRYPTO_CAVS_DRBG around setentropy.
2) Requiring CAP_SYS_ADMIN for entropy reset.
3) Locking for send and recv.
4) Length checks added for send and setentropy; send and setentropy now return
number of bytes accepted.
5) Minor code style corrections.
Documentation/crypto/userspace-if.rst | 17 +++-
crypto/Kconfig | 8 ++
crypto/af_alg.c | 8 ++
crypto/algif_rng.c | 112 ++++++++++++++++++++++++--
include/crypto/if_alg.h | 3 +-
include/uapi/linux/if_alg.h | 1 +
6 files changed, 139 insertions(+), 10 deletions(-)
diff --git a/Documentation/crypto/userspace-if.rst b/Documentation/crypto/userspace-if.rst
index ff86befa61e0..c3695d2c7e0b 100644
--- a/Documentation/crypto/userspace-if.rst
+++ b/Documentation/crypto/userspace-if.rst
@@ -296,15 +296,23 @@ follows:
struct sockaddr_alg sa = {
.salg_family = AF_ALG,
- .salg_type = "rng", /* this selects the symmetric cipher */
- .salg_name = "drbg_nopr_sha256" /* this is the cipher name */
+ .salg_type = "rng", /* this selects the random number generator */
+ .salg_name = "drbg_nopr_sha256" /* this is the RNG name */
};
Depending on the RNG type, the RNG must be seeded. The seed is provided
using the setsockopt interface to set the key. For example, the
ansi_cprng requires a seed. The DRBGs do not require a seed, but may be
-seeded.
+seeded. The seed is also known as a *Personalization String* in DRBG800-90A
+standard.
+
+For the purpose of CAVS testing, the concatenation of *Entropy* and *Nonce*
+can be provided to the RNG via ALG_SET_DRBG_ENTROPY setsockopt interface. This
+requires a kernel built with CONFIG_CRYPTO_CAVS_DRBG, and CAP_SYS_ADMIN
+permission.
+
+*Additional Data* can be provided using the send()/sendmsg() system calls.
Using the read()/recvmsg() system calls, random numbers can be obtained.
The kernel generates at most 128 bytes in one call. If user space
@@ -377,6 +385,9 @@ mentioned optname:
provided ciphertext is assumed to contain an authentication tag of
the given size (see section about AEAD memory layout below).
+- ALG_SET_DRBG_ENTROPY -- Setting the entropy of the random number generator.
+ This option is applicable to RNG cipher type only.
+
User space API example
----------------------
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 091c0a0bbf26..8484617596d1 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -1896,6 +1896,14 @@ config CRYPTO_STATS
config CRYPTO_HASH_INFO
bool
+config CRYPTO_CAVS_DRBG
+ tristate "Enable CAVS testing of DRBG"
+ depends on CRYPTO_USER_API_RNG && CRYPTO_DRBG
+ help
+ This option enables the resetting of DRBG entropy via the user-space
+ interface. This should only be enabled for CAVS testing. You should say
+ no unless you know what this is.
+
source "lib/crypto/Kconfig"
source "drivers/crypto/Kconfig"
source "crypto/asymmetric_keys/Kconfig"
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index b1cd3535c525..27d6248ca447 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -260,6 +260,14 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,
if (!type->setauthsize)
goto unlock;
err = type->setauthsize(ask->private, optlen);
+ break;
+ case ALG_SET_DRBG_ENTROPY:
+ if (sock->state == SS_CONNECTED)
+ goto unlock;
+ if (!type->setentropy)
+ goto unlock;
+
+ err = type->setentropy(ask->private, optval, optlen);
}
unlock:
diff --git a/crypto/algif_rng.c b/crypto/algif_rng.c
index 087c0ad09d38..8a3b0eb45a85 100644
--- a/crypto/algif_rng.c
+++ b/crypto/algif_rng.c
@@ -38,6 +38,7 @@
* DAMAGE.
*/
+#include <linux/capability.h>
#include <linux/module.h>
#include <crypto/rng.h>
#include <linux/random.h>
@@ -53,8 +54,22 @@ struct rng_ctx {
#define MAXSIZE 128
unsigned int len;
struct crypto_rng *drng;
+ u8 *addtl;
+ size_t addtl_len;
};
+struct rng_parent_ctx {
+ struct crypto_rng *drng;
+ u8 *entropy;
+};
+
+static void rng_reset_addtl(struct rng_ctx *ctx)
+{
+ kzfree(ctx->addtl);
+ ctx->addtl = NULL;
+ ctx->addtl_len = 0;
+}
+
static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
int flags)
{
@@ -65,6 +80,7 @@ static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
int genlen = 0;
u8 result[MAXSIZE];
+ lock_sock(sock->sk);
if (len == 0)
return 0;
if (len > MAXSIZE)
@@ -82,16 +98,45 @@ static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
* seeding as they automatically seed. The X9.31 DRNG will return
* an error if it was not seeded properly.
*/
- genlen = crypto_rng_get_bytes(ctx->drng, result, len);
+ genlen = crypto_rng_generate(ctx->drng, ctx->addtl, ctx->addtl_len,
+ result, len);
if (genlen < 0)
return genlen;
err = memcpy_to_msg(msg, result, len);
memzero_explicit(result, len);
+ rng_reset_addtl(ctx);
+ release_sock(sock->sk);
return err ? err : len;
}
+static int rng_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
+{
+ int err;
+ struct alg_sock *ask = alg_sk(sock->sk);
+ struct rng_ctx *ctx = ask->private;
+
+ lock_sock(sock->sk);
+ if (len > MAXSIZE)
+ len = MAXSIZE;
+
+ rng_reset_addtl(ctx);
+ ctx->addtl = kmalloc(len, GFP_KERNEL);
+ if (!ctx->addtl)
+ return -ENOMEM;
+
+ err = memcpy_from_msg(ctx->addtl, msg, len);
+ if (err) {
+ rng_reset_addtl(ctx);
+ return err;
+ }
+ ctx->addtl_len = len;
+ release_sock(sock->sk);
+
+ return len;
+}
+
static struct proto_ops algif_rng_ops = {
.family = PF_ALG,
@@ -106,21 +151,41 @@ static struct proto_ops algif_rng_ops = {
.bind = sock_no_bind,
.accept = sock_no_accept,
.setsockopt = sock_no_setsockopt,
- .sendmsg = sock_no_sendmsg,
.sendpage = sock_no_sendpage,
.release = af_alg_release,
.recvmsg = rng_recvmsg,
+ .sendmsg = rng_sendmsg,
};
static void *rng_bind(const char *name, u32 type, u32 mask)
{
- return crypto_alloc_rng(name, type, mask);
+ struct rng_parent_ctx *pctx;
+ struct crypto_rng *rng;
+
+ pctx = kzalloc(sizeof(*pctx), GFP_KERNEL);
+ if (!pctx)
+ return ERR_PTR(-ENOMEM);
+
+ rng = crypto_alloc_rng(name, type, mask);
+ if (IS_ERR(rng)) {
+ kfree(pctx);
+ return ERR_CAST(rng);
+ }
+
+ pctx->drng = rng;
+ return pctx;
}
static void rng_release(void *private)
{
- crypto_free_rng(private);
+ struct rng_parent_ctx *pctx = private;
+
+ if (unlikely(!pctx))
+ return;
+ crypto_free_rng(pctx->drng);
+ kzfree(pctx->entropy);
+ kzfree(pctx);
}
static void rng_sock_destruct(struct sock *sk)
@@ -128,6 +193,7 @@ static void rng_sock_destruct(struct sock *sk)
struct alg_sock *ask = alg_sk(sk);
struct rng_ctx *ctx = ask->private;
+ rng_reset_addtl(ctx);
sock_kfree_s(sk, ctx, ctx->len);
af_alg_release_parent(sk);
}
@@ -135,6 +201,7 @@ static void rng_sock_destruct(struct sock *sk)
static int rng_accept_parent(void *private, struct sock *sk)
{
struct rng_ctx *ctx;
+ struct rng_parent_ctx *pctx = private;
struct alg_sock *ask = alg_sk(sk);
unsigned int len = sizeof(*ctx);
@@ -150,7 +217,9 @@ static int rng_accept_parent(void *private, struct sock *sk)
* state of the RNG.
*/
- ctx->drng = private;
+ ctx->drng = pctx->drng;
+ ctx->addtl = NULL;
+ ctx->addtl_len = 0;
ask->private = ctx;
sk->sk_destruct = rng_sock_destruct;
@@ -159,18 +228,49 @@ static int rng_accept_parent(void *private, struct sock *sk)
static int rng_setkey(void *private, const u8 *seed, unsigned int seedlen)
{
+ struct rng_parent_ctx *pctx = private;
/*
* Check whether seedlen is of sufficient size is done in RNG
* implementations.
*/
- return crypto_rng_reset(private, seed, seedlen);
+ return crypto_rng_reset(pctx->drng, seed, seedlen);
+}
+
+#ifdef CONFIG_CRYPTO_CAVS_DRBG
+static int rng_setentropy(void *private, const u8 *entropy, unsigned int len)
+{
+ struct rng_parent_ctx *pctx = private;
+ u8 *kentropy = NULL;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (pctx->entropy)
+ return -EINVAL;
+
+ if (len > MAXSIZE)
+ len = MAXSIZE;
+
+ if (len) {
+ kentropy = memdup_user(entropy, len);
+ if (IS_ERR(kentropy))
+ return PTR_ERR(kentropy);
+ }
+
+ crypto_rng_alg(pctx->drng)->set_ent(pctx->drng, kentropy, len);
+ pctx->entropy = kentropy;
+ return len;
}
+#endif
static const struct af_alg_type algif_type_rng = {
.bind = rng_bind,
.release = rng_release,
.accept = rng_accept_parent,
.setkey = rng_setkey,
+#ifdef CONFIG_CRYPTO_CAVS_DRBG
+ .setentropy = rng_setentropy,
+#endif
.ops = &algif_rng_ops,
.name = "rng",
.owner = THIS_MODULE
diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
index 56527c85d122..312fdb3469cf 100644
--- 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 (*setentropy)(void *private, const u8 *entropy, unsigned int len);
int (*accept)(void *private, struct sock *sk);
int (*accept_nokey)(void *private, struct sock *sk);
int (*setauthsize)(void *private, unsigned int authsize);
@@ -123,7 +124,7 @@ struct af_alg_async_req {
* @tsgl_list: Link to TX SGL
* @iv: IV for cipher operation
* @aead_assoclen: Length of AAD for AEAD cipher operations
- * @completion: Work queue for synchronous operation
+ * @wait: Wait on completion of async crypto ops
* @used: TX bytes sent to kernel. This variable is used to
* ensure that user space cannot cause the kernel
* to allocate too much memory in sendmsg operation.
diff --git a/include/uapi/linux/if_alg.h b/include/uapi/linux/if_alg.h
index bc2bcdec377b..60b7c2efd921 100644
--- a/include/uapi/linux/if_alg.h
+++ b/include/uapi/linux/if_alg.h
@@ -35,6 +35,7 @@ struct af_alg_iv {
#define ALG_SET_OP 3
#define ALG_SET_AEAD_ASSOCLEN 4
#define ALG_SET_AEAD_AUTHSIZE 5
+#define ALG_SET_DRBG_ENTROPY 6
/* Operations */
#define ALG_OP_DECRYPT 0
--
2.27.0.389.gc38d7665816-goog
next prev parent reply other threads:[~2020-07-16 16:40 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-07-13 16:48 [PATCH 0/1] crypto: af_alg - add extra parameters for DRBG interface Elena Petrova
2020-07-13 16:48 ` [PATCH 1/1] " Elena Petrova
2020-07-13 17:10 ` Eric Biggers
2020-07-16 14:23 ` Elena Petrova
2020-07-16 16:40 ` Elena Petrova [this message]
2020-07-20 17:35 ` [PATCH v2] " Stephan Mueller
2020-07-21 12:55 ` Elena Petrova
2020-07-21 13:18 ` Stephan Mueller
2020-07-28 16:16 ` Elena Petrova
2020-07-20 17:42 ` Stephan Müller
2020-07-22 15:59 ` Eric Biggers
2020-07-28 15:51 ` [PATCH v3] " Elena Petrova
2020-07-28 17:36 ` Eric Biggers
2020-07-29 15:45 ` [PATCH v4] " Elena Petrova
2020-07-29 19:26 ` Stephan Müller
2020-07-31 7:23 ` Herbert Xu
2020-08-03 14:48 ` Elena Petrova
2020-08-03 15:10 ` Stephan Mueller
2020-08-03 15:30 ` Elena Petrova
2020-08-04 2:18 ` Herbert Xu
2020-07-13 17:25 ` [PATCH 1/1] " Eric Biggers
2020-07-31 7:26 ` Herbert Xu
2020-08-13 16:00 ` Elena Petrova
2020-08-13 16:01 ` [PATCH v4] " Elena Petrova
2020-08-13 16:04 ` Elena Petrova
2020-08-13 16:08 ` [PATCH v5] " Elena Petrova
2020-08-13 19:32 ` Eric Biggers
2020-08-21 4:24 ` Herbert Xu
2020-09-08 17:04 ` [PATCH v6] " Elena Petrova
2020-09-09 4:35 ` Eric Biggers
2020-09-09 18:29 ` [PATCH v7] " Elena Petrova
2020-09-09 21:00 ` Eric Biggers
2020-09-16 11:07 ` [PATCH v8] " Elena Petrova
2020-09-18 6:43 ` Herbert Xu
2020-09-18 15:42 ` [PATCH v9] " Elena Petrova
2020-09-25 8:16 ` Herbert Xu
2020-09-08 17:23 ` [PATCH v5] " Elena Petrova
2020-09-08 17:18 ` Elena Petrova
2020-07-14 5:17 ` [PATCH 0/1] " Stephan Mueller
2020-07-14 15:23 ` Elena Petrova
2020-07-14 15:34 ` Stephan Mueller
2020-07-16 14:41 ` Elena Petrova
2020-07-16 14:49 ` Stephan Mueller
2020-07-16 14:59 ` Stephan Mueller
2020-07-16 14:59 ` Stephan Mueller
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200716164028.1805047-1-lenaptr@google.com \
--to=lenaptr@google.com \
--cc=ardb@kernel.org \
--cc=ebiggers@kernel.org \
--cc=linux-crypto@vger.kernel.org \
--cc=smueller@chronox.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.