Received: by 2002:a25:7ec1:0:0:0:0:0 with SMTP id z184csp987034ybc; Sat, 23 Nov 2019 12:41:29 -0800 (PST) X-Google-Smtp-Source: APXvYqwdbrkl4Adg9K3PokqvE2mngyk1RRdEWfK+WmaUPAs4jRLM1wk8ET4u+LkU5xge3acFoUEC X-Received: by 2002:a17:906:c7d5:: with SMTP id dc21mr28928412ejb.267.1574541689176; Sat, 23 Nov 2019 12:41:29 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1574541689; cv=none; d=google.com; s=arc-20160816; b=CtWYqqm2w7Wp+FXUtAQnAMqz1rmtZNVltRryGOXKH1scTi4CT0y1uJAZ1vFPSDQhv6 SiR2L0Rn22N6y8lGvULSG9oSql4j0uh/Q7F9XNlAGfX+6ryoHpnt0U5d7YbX0KmMg5CP A6e61V4g7RBObSkY3goNMaQG2dJmkGQsj7pnMC275cd7KNAd8zXm/nexF94fcBkt4JDE qCLNd4JzKKL61CFC8rIibPVi+re+F2dvq8vlaOPJ3T6l72fv1a1+F5KOmU5KK8xUjHcr LpY1VSLbRqQ2MMsAd3hKcGJjeLvKs1V01XMhqTaWDSHdjscfnKO5DAT5xlXst9sr/3Jn vzlg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=mO7BDXg95pxXFCcFvw4eN7kQKnS1aWMttEXawinDjZc=; b=LSy+yTPIMQAlnM9mChubIffkEg1IbpC3E2fgwdlqeLNioJoNsMHe8tzmLwi19yjyy0 3ONG5eYIXCmH+YQTJloRCfycHPXobIQ71QPDVV5QPNrJgNJVri6am5iz+2oNbMM/L41U 8LlQer/W6yc3dUddNB8SbF8n//NYUXaMewe9w5CSmh8OPG2GhhYxRo2ckjadSyp92I34 37yj7t+OIbthzbKKHN0YDvnDRfDyflV7qcXJKvgOdbvPR52csLiz6vxFOAGyO6zLG4Zf 0+8Bi6+IVRaYCfCe9AxV5uvE6QkN4L1nLrWjsYKxWZoga42Ijiv65QkNLHx9hDDpkuof 0vuA== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@chronox.de header.s=strato-dkim-0002 header.b=ZGyNky31; spf=pass (google.com: best guess record for domain of linux-crypto-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-crypto-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id a7si1871756edj.84.2019.11.23.12.41.05; Sat, 23 Nov 2019 12:41:29 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-crypto-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=fail header.i=@chronox.de header.s=strato-dkim-0002 header.b=ZGyNky31; spf=pass (google.com: best guess record for domain of linux-crypto-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-crypto-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727312AbfKWUkL (ORCPT + 99 others); Sat, 23 Nov 2019 15:40:11 -0500 Received: from mo4-p03-ob.smtp.rzone.de ([85.215.255.104]:35864 "EHLO mo4-p03-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727156AbfKWUjz (ORCPT ); Sat, 23 Nov 2019 15:39:55 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1574541587; s=strato-dkim-0002; d=chronox.de; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From: X-RZG-CLASS-ID:X-RZG-AUTH:From:Subject:Sender; bh=mO7BDXg95pxXFCcFvw4eN7kQKnS1aWMttEXawinDjZc=; b=ZGyNky31C2iyqPyq8jPKha4pdh2WNbxUE77H0jEZ44FEYBEOx3MjY6hnWKFk1gKO3Q bRga2aFqeMhn/gCM0QhORKqlQZviPS67FrN4XaSc+cVx8zdyzVpNDP0ZuOIxRKGWveEm qpXQeWBLWBMOUoo9yD7XvOJEp7D+Edp04kmZxNhqIJTszetYciRC/t54KLVsc0W8A6hb wJv8mcbQwmRDEywJSnEQM6CsL80XGNM2XXDjhCSHVe1Ozrq28oHKgO2EFxuHgL4D4vMq Q3CtBucK8Pwpk4edJL4syagUELbElbU+wyWun2JoRb7QJRhutBNEsyowo+3eHNFOryPL g8hQ== X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzHHXDaJfSfWrhX" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 44.29.0 DYNA|AUTH) with ESMTPSA id N09a57vANKcX3yU (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (curve secp521r1 with 521 ECDH bits, eq. 15360 bits RSA)) (Client did not present a certificate); Sat, 23 Nov 2019 21:38:33 +0100 (CET) From: Stephan =?ISO-8859-1?Q?M=FCller?= To: Arnd Bergmann Cc: Greg Kroah-Hartman , linux-crypto@vger.kernel.org, LKML , linux-api@vger.kernel.org, "Eric W. Biederman" , "Alexander E. Patrakov" , "Ahmed S. Darwish" , "Theodore Y. Ts'o" , Willy Tarreau , Matthew Garrett , Vito Caputo , Andreas Dilger , Jan Kara , Ray Strode , William Jon McCann , zhangjs , Andy Lutomirski , Florian Weimer , Lennart Poettering , Nicolai Stange , "Peter, Matthias" , Marcelo Henrique Cerri , Roman Drahtmueller , Neil Horman , Randy Dunlap Subject: [PATCH v26 07/12] LRNG - add kernel crypto API PRNG extension Date: Sat, 23 Nov 2019 21:32:56 +0100 Message-ID: <2819520.f52rdyjaCL@positron.chronox.de> In-Reply-To: <2722222.P16TYeLAVu@positron.chronox.de> References: <6157374.ptSnyUpaCn@positron.chronox.de> <2787174.DQlWHN5GGo@positron.chronox.de> <2722222.P16TYeLAVu@positron.chronox.de> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="iso-8859-1" Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org Add runtime-pluggable support for all PRNGs that are accessible via the kernel crypto API, including hardware PRNGs. The PRNG is selected with the module parameter drng_name where the name must be one that the kernel crypto API can resolve into an RNG. This allows using of the kernel crypto API PRNG implementations that provide an interface to hardware PRNGs. Using this extension, the LRNG uses the hardware PRNGs to generate random numbers. An example is the S390 CPACF support providing such a PRNG. The hash is provided by a kernel crypto API SHASH whose digest size complies with the seedsize of the PRNG. CC: "Eric W. Biederman" CC: "Alexander E. Patrakov" CC: "Ahmed S. Darwish" CC: "Theodore Y. Ts'o" CC: Willy Tarreau CC: Matthew Garrett CC: Vito Caputo CC: Andreas Dilger CC: Jan Kara CC: Ray Strode CC: William Jon McCann CC: zhangjs CC: Andy Lutomirski CC: Florian Weimer CC: Lennart Poettering CC: Nicolai Stange Reviewed-by: Marcelo Henrique Cerri Reviewed-by: Roman Drahtmueller Tested-by: Roman Drahtm=FCller Tested-by: Marcelo Henrique Cerri Tested-by: Neil Horman Signed-off-by: Stephan Mueller =2D-- drivers/char/lrng/Kconfig | 10 + drivers/char/lrng/Makefile | 1 + drivers/char/lrng/lrng_kcapi.c | 328 +++++++++++++++++++++++++++++++++ 3 files changed, 339 insertions(+) create mode 100644 drivers/char/lrng/lrng_kcapi.c diff --git a/drivers/char/lrng/Kconfig b/drivers/char/lrng/Kconfig index dcdf4ef83da5..03e6e2ec356b 100644 =2D-- a/drivers/char/lrng/Kconfig +++ b/drivers/char/lrng/Kconfig @@ -68,6 +68,16 @@ config LRNG_DRBG Enable the SP800-90A DRBG support for the LRNG. Once the module is loaded, output from /dev/random, /dev/urandom, getrandom(2), or get_random_bytes is provided by a DRBG. + +config LRNG_KCAPI + tristate "Kernel Crypto API support for the LRNG" + select CRYPTO_RNG + help + Enable the support for generic pseudo-random number + generators offered by the kernel crypto API with the + LRNG. Once the module is loaded, output from /dev/random, + /dev/urandom, getrandom(2), or get_random_bytes is + provided by the selected kernel crypto API RNG. endif # LRNG_DRNG_SWITCH =20 endif # LRNG diff --git a/drivers/char/lrng/Makefile b/drivers/char/lrng/Makefile index e3a704b3466c..027b6ea51c20 100644 =2D-- a/drivers/char/lrng/Makefile +++ b/drivers/char/lrng/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_NUMA) +=3D lrng_numa.o obj-$(CONFIG_SYSCTL) +=3D lrng_proc.o obj-$(CONFIG_LRNG_DRNG_SWITCH) +=3D lrng_switch.o obj-$(CONFIG_LRNG_DRBG) +=3D lrng_drbg.o +obj-$(CONFIG_LRNG_KCAPI) +=3D lrng_kcapi.o diff --git a/drivers/char/lrng/lrng_kcapi.c b/drivers/char/lrng/lrng_kcapi.c new file mode 100644 index 000000000000..f887447e524d =2D-- /dev/null +++ b/drivers/char/lrng/lrng_kcapi.c @@ -0,0 +1,328 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * Backend for the LRNG providing the cryptographic primitives using the + * kernel crypto API. + * + * Copyright (C) 2018 - 2019, Stephan Mueller + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include + +static char *drng_name =3D NULL; +module_param(drng_name, charp, 0444); +MODULE_PARM_DESC(drng_name, "Kernel crypto API name of DRNG"); + +static char *pool_hash =3D "sha512"; +module_param(pool_hash, charp, 0444); +MODULE_PARM_DESC(pool_hash, + "Kernel crypto API name of hash or keyed message digest to read the ent= ropy pool"); + +static char *seed_hash =3D NULL; +module_param(seed_hash, charp, 0444); +MODULE_PARM_DESC(seed_hash, + "Kernel crypto API name of hash with output size equal to seedsize of D= RNG to bring seed string to the size required by the DRNG"); + +struct lrng_hash_info { + struct shash_desc shash; + char ctx[]; +}; + +struct lrng_drng_info { + struct crypto_rng *kcapi_rng; + struct lrng_hash_info *lrng_hash; +}; + +static struct lrng_hash_info *_lrng_kcapi_hash_alloc(const char *name) +{ + struct lrng_hash_info *lrng_hash; + struct crypto_shash *tfm; + int size; + + if (!name) { + pr_err("Hash name missing\n"); + return ERR_PTR(-EINVAL); + } + + tfm =3D crypto_alloc_shash(name, 0, 0); + if (IS_ERR(tfm)) { + pr_err("could not allocate hash %s\n", name); + return ERR_CAST(tfm); + } + + size =3D sizeof(struct lrng_hash_info) + crypto_shash_descsize(tfm); + lrng_hash =3D kmalloc(size, GFP_KERNEL); + if (!lrng_hash) { + crypto_free_shash(tfm); + return ERR_PTR(-ENOMEM); + } + + lrng_hash->shash.tfm =3D tfm; + + return lrng_hash; +} + +static inline u32 _lrng_kcapi_hash_digestsize(struct lrng_hash_info *lrng_= hash) +{ + struct shash_desc *shash =3D &lrng_hash->shash; + struct crypto_shash *tfm =3D shash->tfm; + + return crypto_shash_digestsize(tfm); +} + +static inline void _lrng_kcapi_hash_free(struct lrng_hash_info *lrng_hash) +{ + struct shash_desc *shash =3D &lrng_hash->shash; + struct crypto_shash *tfm =3D shash->tfm; + + crypto_free_shash(tfm); + kfree(lrng_hash); +} + +static void *lrng_kcapi_hash_alloc(const u8 *key, u32 keylen) +{ + struct lrng_hash_info *lrng_hash; + int ret; + + lrng_hash =3D _lrng_kcapi_hash_alloc(pool_hash); + if (IS_ERR(lrng_hash)) + return ERR_CAST(lrng_hash); + + /* If the used hash is no MAC, ignore the ENOSYS return code */ + ret =3D crypto_shash_setkey(lrng_hash->shash.tfm, key, keylen); + if (ret && ret !=3D -ENOSYS) { + pr_err("could not set the key for MAC\n"); + _lrng_kcapi_hash_free(lrng_hash); + return ERR_PTR(ret); + } + + pr_info("Hash %s allocated\n", pool_hash); + + return lrng_hash; +} + +static void lrng_kcapi_hash_dealloc(void *hash) +{ + struct lrng_hash_info *lrng_hash =3D (struct lrng_hash_info *)hash; + + _lrng_kcapi_hash_free(lrng_hash); + pr_info("Hash %s deallocated\n", pool_hash); +} + +static u32 lrng_kcapi_hash_digestsize(void *hash) +{ + struct lrng_hash_info *lrng_hash =3D (struct lrng_hash_info *)hash; + + return _lrng_kcapi_hash_digestsize(lrng_hash); +} + +static int lrng_kcapi_hash_buffer(void *hash, const u8 *inbuf, u32 inbufle= n, + u8 *digest) +{ + struct lrng_hash_info *lrng_hash =3D (struct lrng_hash_info *)hash; + struct shash_desc *shash =3D &lrng_hash->shash; + + return crypto_shash_digest(shash, inbuf, inbuflen, digest); +} + +static int lrng_kcapi_drng_seed_helper(void *drng, const u8 *inbuf, + u32 inbuflen) +{ + struct lrng_drng_info *lrng_drng_info =3D (struct lrng_drng_info *)drng; + struct crypto_rng *kcapi_rng =3D lrng_drng_info->kcapi_rng; + struct lrng_hash_info *lrng_hash =3D lrng_drng_info->lrng_hash; + + if (lrng_hash) { + struct shash_desc *shash =3D &lrng_hash->shash; + u32 digestsize =3D _lrng_kcapi_hash_digestsize(lrng_hash); + u8 digest[64] __aligned(8); + int ret; + + BUG_ON(digestsize > sizeof(digest)); + + ret =3D crypto_shash_digest(shash, inbuf, inbuflen, digest); + if (ret) + return ret; + + ret =3D crypto_rng_reset(kcapi_rng, digest, digestsize); + if (ret) + return ret; + + memzero_explicit(digest, digestsize); + + return 0; + } else { + return crypto_rng_reset(kcapi_rng, inbuf, inbuflen); + } +} + +static int lrng_kcapi_drng_generate_helper(void *drng, u8 *outbuf, + u32 outbuflen) +{ + struct lrng_drng_info *lrng_drng_info =3D (struct lrng_drng_info *)drng; + struct crypto_rng *kcapi_rng =3D lrng_drng_info->kcapi_rng; + int ret =3D crypto_rng_get_bytes(kcapi_rng, outbuf, outbuflen); + + if (ret < 0) + return ret; + + return outbuflen; +} + +static void *lrng_kcapi_drng_alloc(u32 sec_strength) +{ + struct lrng_drng_info *lrng_drng_info; + struct crypto_rng *kcapi_rng; + int seedsize; + void *ret =3D ERR_PTR(-ENOMEM); + + if (!drng_name) { + pr_err("DRNG name missing\n"); + return ERR_PTR(-EINVAL); + } + + if (!memcmp(drng_name, "drbg", 4)) { + pr_err("SP800-90A DRBG cannot be allocated using lrng_kcapi " + "backend, use lrng_drbg backend instead\n"); + return ERR_PTR(-EINVAL); + } + + if (!memcmp(drng_name, "stdrng", 6)) { + pr_err("stdrng cannot be allocated using lrng_kcapi backend, " + "it is too unspecific and potentially may allocate the " + "DRBG\n"); + return ERR_PTR(-EINVAL); + } + + lrng_drng_info =3D kmalloc(sizeof(*lrng_drng_info), GFP_KERNEL); + if (!lrng_drng_info) + return ERR_PTR(-ENOMEM); + + kcapi_rng =3D crypto_alloc_rng(drng_name, 0, 0); + if (IS_ERR(kcapi_rng)) { + pr_err("DRNG %s cannot be allocated\n", drng_name); + ret =3D ERR_CAST(kcapi_rng); + goto free; + } + lrng_drng_info->kcapi_rng =3D kcapi_rng; + + seedsize =3D crypto_rng_seedsize(kcapi_rng); + + if (sec_strength > seedsize) + pr_info("Seedsize DRNG (%u bits) lower than " + "security strength of LRNG noise source (%u bits)\n", + crypto_rng_seedsize(kcapi_rng) * 8, + sec_strength * 8); + + if (seedsize) { + struct lrng_hash_info *lrng_hash; + + if (!seed_hash) { + switch (seedsize) { + case 32: + seed_hash =3D "sha256"; + break; + case 48: + seed_hash =3D "sha384"; + break; + case 64: + seed_hash =3D "sha512"; + break; + default: + pr_err("Seed size %d cannot be processed\n", + seedsize); + goto dealloc; + break; + } + } + + lrng_hash =3D _lrng_kcapi_hash_alloc(seed_hash); + if (IS_ERR(lrng_hash)) { + ret =3D ERR_CAST(lrng_hash); + goto dealloc; + } + + if (seedsize !=3D _lrng_kcapi_hash_digestsize(lrng_hash)) { + pr_err("Seed hash output size not equal to DRNG seed " + "size\n"); + _lrng_kcapi_hash_free(lrng_hash); + ret =3D ERR_PTR(-EINVAL); + goto dealloc; + } + + lrng_drng_info->lrng_hash =3D lrng_hash; + + pr_info("Seed hash %s allocated\n", seed_hash); + } else { + lrng_drng_info->lrng_hash =3D NULL; + } + + pr_info("Kernel crypto API DRNG %s allocated\n", drng_name); + + return lrng_drng_info; + +dealloc: + crypto_free_rng(kcapi_rng); +free: + kfree(lrng_drng_info); + return ret; +} + +static void lrng_kcapi_drng_dealloc(void *drng) +{ + struct lrng_drng_info *lrng_drng_info =3D (struct lrng_drng_info *)drng; + struct crypto_rng *kcapi_rng =3D lrng_drng_info->kcapi_rng; + struct lrng_hash_info *lrng_hash =3D lrng_drng_info->lrng_hash; + + crypto_free_rng(kcapi_rng); + if (lrng_hash) { + _lrng_kcapi_hash_free(lrng_hash); + pr_info("Seed hash %s deallocated\n", seed_hash); + } + kfree(lrng_drng_info); + pr_info("DRNG %s deallocated\n", drng_name); +} + +static const char *lrng_kcapi_drng_name(void) +{ + return drng_name; +} + +static const char *lrng_kcapi_pool_hash(void) +{ + return pool_hash; +} + +const static struct lrng_crypto_cb lrng_kcapi_crypto_cb =3D { + .lrng_drng_name =3D lrng_kcapi_drng_name, + .lrng_hash_name =3D lrng_kcapi_pool_hash, + .lrng_drng_alloc =3D lrng_kcapi_drng_alloc, + .lrng_drng_dealloc =3D lrng_kcapi_drng_dealloc, + .lrng_drng_seed_helper =3D lrng_kcapi_drng_seed_helper, + .lrng_drng_generate_helper =3D lrng_kcapi_drng_generate_helper, + .lrng_drng_generate_helper_full =3D lrng_kcapi_drng_generate_helper, + .lrng_hash_alloc =3D lrng_kcapi_hash_alloc, + .lrng_hash_dealloc =3D lrng_kcapi_hash_dealloc, + .lrng_hash_digestsize =3D lrng_kcapi_hash_digestsize, + .lrng_hash_buffer =3D lrng_kcapi_hash_buffer, +}; + +static int __init lrng_kcapi_init(void) +{ + return lrng_set_drng_cb(&lrng_kcapi_crypto_cb); +} +static void __exit lrng_kcapi_exit(void) +{ + lrng_set_drng_cb(NULL); +} + +late_initcall(lrng_kcapi_init); +module_exit(lrng_kcapi_exit); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Stephan Mueller "); +MODULE_DESCRIPTION("Linux Random Number Generator - kernel crypto API DRNG= backend"); =2D-=20 2.23.0