Err, I sent the old patch file, sorry. Real v5 coming shortly... On Thu, 13 Aug 2020 at 17:02, Elena Petrova <lenaptr@xxxxxxxxxx> wrote: > > Extend the user-space RNG interface: > 1. Add entropy input via ALG_SET_DRBG_ENTROPY setsockopt option; > 2. Add additional data input via sendmsg syscall. > > This allows DRBG to be tested with test vectors, for example for the > purpose of CAVP testing, which otherwise isn't possible. > > To prevent erroneous use of entropy input, it is hidden under > CRYPTO_USER_API_CAVP_DRBG config option and requires CAP_SYS_ADMIN to > succeed. > > Signed-off-by: Elena Petrova <lenaptr@xxxxxxxxxx> > --- > > Updates in v4: > 1) setentropy returns 0 or error code (used to return length); > 2) bigfixes suggested by Eric. > > Updates in v3: > 1) More details in commit message; > 2) config option name is now CRYPTO_USER_API_CAVP_DRBG; > 3) fixed a bug of not releasing socket locks. > > 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. > > libkcapi patch for testing: > https://github.com/Len0k/libkcapi/commit/6f095d270b982008f419078614c15caa592cb531 > > Documentation/crypto/userspace-if.rst | 17 +++- > crypto/Kconfig | 8 ++ > crypto/af_alg.c | 8 ++ > crypto/algif_rng.c | 130 ++++++++++++++++++++++++-- > include/crypto/if_alg.h | 1 + > include/uapi/linux/if_alg.h | 1 + > 6 files changed, 152 insertions(+), 13 deletions(-) > > diff --git a/Documentation/crypto/userspace-if.rst b/Documentation/crypto/userspace-if.rst > index ff86befa61e0..ef7132802c2d 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 CAVP 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_USER_API_CAVP_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..aa2b3085a431 100644 > --- a/crypto/Kconfig > +++ b/crypto/Kconfig > @@ -1896,6 +1896,14 @@ config CRYPTO_STATS > config CRYPTO_HASH_INFO > bool > > +config CRYPTO_USER_API_CAVP_DRBG > + tristate "Enable CAVP 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 CAVP 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..21e8201844bf 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,20 +54,35 @@ 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) > { > struct sock *sk = sock->sk; > struct alg_sock *ask = alg_sk(sk); > struct rng_ctx *ctx = ask->private; > - int err; > + int err = 0; > int genlen = 0; > u8 result[MAXSIZE]; > > + lock_sock(sock->sk); > if (len == 0) > - return 0; > + goto unlock; > if (len > MAXSIZE) > len = MAXSIZE; > > @@ -82,13 +98,48 @@ 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); > - if (genlen < 0) > - return genlen; > + genlen = crypto_rng_generate(ctx->drng, ctx->addtl, ctx->addtl_len, > + result, len); > + if (genlen < 0) { > + err = genlen; > + goto unlock; > + } > > err = memcpy_to_msg(msg, result, len); > memzero_explicit(result, len); > + rng_reset_addtl(ctx); > > +unlock: > + 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) { > + err = -ENOMEM; > + goto unlock; > + } > + > + err = memcpy_from_msg(ctx->addtl, msg, len); > + if (err) { > + rng_reset_addtl(ctx); > + goto unlock; > + } > + ctx->addtl_len = len; > + > +unlock: > + release_sock(sock->sk); > return err ? err : len; > } > > @@ -106,21 +157,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 +199,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 +207,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 +223,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 +234,53 @@ 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_USER_API_CAVP_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 -EACCES; > + > + if (pctx->entropy) > + return -EINVAL; > + > + if (len > MAXSIZE) > + return -EMSGSIZE; > + > + 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); > + /* > + * Since rng doesn't perform any memory management for the entropy > + * buffer, save kentropy pointer to pctx now to free it after use. > + */ > + pctx->entropy = kentropy; > + return 0; > } > +#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_USER_API_CAVP_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..9e5c8ac53c59 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); > 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.28.0.rc0.142.g3c755180ce-goog >