From patchwork Wed Jan 15 10:32:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 198227 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.6 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 08027C33CB6 for ; Wed, 15 Jan 2020 10:40:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id BE2632467D for ; Wed, 15 Jan 2020 10:40:08 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=chronox.de header.i=@chronox.de header.b="mnkxoy9l" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729904AbgAOKjf (ORCPT ); Wed, 15 Jan 2020 05:39:35 -0500 Received: from mo4-p04-ob.smtp.rzone.de ([85.215.255.121]:30932 "EHLO mo4-p04-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729849AbgAOKjb (ORCPT ); Wed, 15 Jan 2020 05:39:31 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1579084765; 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=ZOYKCPgIvfZRmCnEJgMTAQ5NHbca7NuUuyUIdvnjvC4=; b=mnkxoy9l6eriy6IPdmK6/DIn8gamIjcauspGko02s/OXiiW3J/z6l3DueWJJU6P4NV 05eWr+itLAD0L4rzL971F8eqAMRh8/2VVAoKuSvnnJwI75suDSdg7XmR6WjeuoNM8Nk3 p+oM6gOy7f5EXYeGm16SV/pnTvCEwTZi4zPrBHL9tHNAsONLcnzD8bvVFg5LNs2iGZzO VqH29ql2sdO/5K9e2pLoamskW5Xe/msDRFyuVNUpBr7w2xGKyE1GJTimGndMvUER/mIv WqEyMUJ4OwX7a5c6Wkjz/TTBZjDSsdNF3DuUIlmVAMw28EbvAX9lSMY+O4WEaJYbm1zM 4m8Q== X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPZJPScHivh" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 46.1.4 DYNA|AUTH) with ESMTPSA id u04585w0FAcAW0A (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Wed, 15 Jan 2020 11:38:10 +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 , Julia Lawall , Dan Carpenter Subject: [PATCH v28 03/12] LRNG - sysctls and /proc interface Date: Wed, 15 Jan 2020 11:32:31 +0100 Message-ID: <3470236.xfvW1cKDFL@positron.chronox.de> In-Reply-To: <5951792.lmNsirYsPE@positron.chronox.de> References: <6157374.ptSnyUpaCn@positron.chronox.de> <2641155.iNH938UiKq@positron.chronox.de> <5951792.lmNsirYsPE@positron.chronox.de> MIME-Version: 1.0 Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org The LRNG sysctl interface provides the same controls as the existing /dev/random implementation. These sysctls behave identically and are implemented identically. The goal is to allow a possible merge of the existing /dev/random implementation with this implementation which implies that this patch tries have a very close similarity. Yet, all sysctls are documented at [1]. In addition, it provides the file lrng_type which provides details about the LRNG: - the name of the DRNG that produces the random numbers for /dev/random, /dev/urandom, getrandom(2) - the hash used to produce random numbers from the entropy pool - the number of secondary DRNG instances - indicator whether the LRNG operates SP800-90B compliant - indicator whether a high-resolution timer is identified - only with a high-resolution timer the interrupt noise source will deliver sufficient entropy - indicator whether the LRNG has been minimally seeded (i.e. is the secondary DRNG seeded with at least 128 bits of of entropy) - indicator whether the LRNG has been fully seeded (i.e. is the secondary DRNG seeded with at least 256 bits of entropy) [1] https://www.chronox.de/lrng.html 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üller Tested-by: Marcelo Henrique Cerri Tested-by: Neil Horman Signed-off-by: Stephan Mueller --- drivers/char/lrng/Makefile | 1 + drivers/char/lrng/lrng_interfaces.c | 1 - drivers/char/lrng/lrng_internal.h | 4 + drivers/char/lrng/lrng_proc.c | 163 ++++++++++++++++++++++++++++ 4 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 drivers/char/lrng/lrng_proc.c diff --git a/drivers/char/lrng/Makefile b/drivers/char/lrng/Makefile index 0a32f22c2c1a..e69c176f0161 100644 --- a/drivers/char/lrng/Makefile +++ b/drivers/char/lrng/Makefile @@ -9,3 +9,4 @@ obj-y += lrng_pool.o lrng_aux.o \ lrng_interfaces.o \ obj-$(CONFIG_NUMA) += lrng_numa.o +obj-$(CONFIG_SYSCTL) += lrng_proc.o diff --git a/drivers/char/lrng/lrng_interfaces.c b/drivers/char/lrng/lrng_interfaces.c index d6ddc72fc9b7..8e96c3ade76e 100644 --- a/drivers/char/lrng/lrng_interfaces.c +++ b/drivers/char/lrng/lrng_interfaces.c @@ -34,7 +34,6 @@ static DECLARE_WAIT_QUEUE_HEAD(lrng_write_wait); static DECLARE_WAIT_QUEUE_HEAD(lrng_init_wait); static struct fasync_struct *fasync; -struct ctl_table random_table[]; /********************************** Helper ***********************************/ /* Is the DRNG seed level too low? */ diff --git a/drivers/char/lrng/lrng_internal.h b/drivers/char/lrng/lrng_internal.h index ecb0a7ad5e7e..f65fc6647e8a 100644 --- a/drivers/char/lrng/lrng_internal.h +++ b/drivers/char/lrng/lrng_internal.h @@ -116,7 +116,11 @@ void lrng_cc20_init_state(struct chacha20_state *state); /********************************** /proc *************************************/ +#ifdef CONFIG_SYSCTL +void lrng_pool_inc_numa_node(void); +#else static inline void lrng_pool_inc_numa_node(void) { } +#endif /****************************** LRNG interfaces *******************************/ diff --git a/drivers/char/lrng/lrng_proc.c b/drivers/char/lrng/lrng_proc.c new file mode 100644 index 000000000000..f4ee01f61925 --- /dev/null +++ b/drivers/char/lrng/lrng_proc.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * LRNG proc and sysctl interfaces + * + * Copyright (C) 2016 - 2020, Stephan Mueller + */ + +#include +#include +#include +#include +#include + +#include "lrng_internal.h" + +/* + * This function is used to return both the bootid UUID, and random + * UUID. The difference is in whether table->data is NULL; if it is, + * then a new UUID is generated and returned to the user. + * + * If the user accesses this via the proc interface, the UUID will be + * returned as an ASCII string in the standard UUID format; if via the + * sysctl system call, as 16 bytes of binary data. + */ +static int lrng_proc_do_uuid(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table fake_table; + unsigned char buf[64], tmp_uuid[16], *uuid; + + uuid = table->data; + if (!uuid) { + uuid = tmp_uuid; + generate_random_uuid(uuid); + } else { + static DEFINE_SPINLOCK(bootid_spinlock); + + spin_lock(&bootid_spinlock); + if (!uuid[8]) + generate_random_uuid(uuid); + spin_unlock(&bootid_spinlock); + } + + sprintf(buf, "%pU", uuid); + + fake_table.data = buf; + fake_table.maxlen = sizeof(buf); + + return proc_dostring(&fake_table, write, buffer, lenp, ppos); +} + +static int lrng_proc_do_entropy(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table fake_table; + int entropy_count; + + entropy_count = lrng_avail_entropy(); + + fake_table.data = &entropy_count; + fake_table.maxlen = sizeof(entropy_count); + + return proc_dointvec(&fake_table, write, buffer, lenp, ppos); +} + +static int lrng_sysctl_poolsize = LRNG_POOL_SIZE_BITS; +static int lrng_min_write_thresh; +static int lrng_max_write_thresh = LRNG_POOL_SIZE_BITS; +static char lrng_sysctl_bootid[16]; +static int lrng_drng_reseed_max_min; + +struct ctl_table random_table[] = { + { + .procname = "poolsize", + .data = &lrng_sysctl_poolsize, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = proc_dointvec, + }, + { + .procname = "entropy_avail", + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = lrng_proc_do_entropy, + }, + { + .procname = "write_wakeup_threshold", + .data = &lrng_write_wakeup_bits, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &lrng_min_write_thresh, + .extra2 = &lrng_max_write_thresh, + }, + { + .procname = "boot_id", + .data = &lrng_sysctl_bootid, + .maxlen = 16, + .mode = 0444, + .proc_handler = lrng_proc_do_uuid, + }, + { + .procname = "uuid", + .maxlen = 16, + .mode = 0444, + .proc_handler = lrng_proc_do_uuid, + }, + { + .procname = "urandom_min_reseed_secs", + .data = &lrng_drng_reseed_max_time, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + .extra1 = &lrng_drng_reseed_max_min, + }, + { } +}; + +/* Number of online DRNGs */ +static u32 numa_drngs = 1; + +void lrng_pool_inc_numa_node(void) +{ + numa_drngs++; +} + +static int lrng_proc_type_show(struct seq_file *m, void *v) +{ + struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); + unsigned long flags = 0; + unsigned char buf[300]; + + lrng_drng_lock(lrng_drng_init, &flags); + snprintf(buf, sizeof(buf), + "DRNG name: %s\n" + "Hash for reading entropy pool: %s\n" + "DRNG security strength: %d bits\n" + "number of DRNG instances: %u\n" + "SP800-90B compliance: %s\n" + "High-resolution timer: %s\n" + "LRNG minimally seeded: %s\n" + "LRNG fully seeded: %s\n", + lrng_drng_init->crypto_cb->lrng_drng_name(), + lrng_drng_init->crypto_cb->lrng_hash_name(), + LRNG_DRNG_SECURITY_STRENGTH_BITS, numa_drngs, + lrng_sp80090b_compliant() ? "true" : "false", + lrng_pool_highres_timer() ? "true" : "false", + lrng_state_min_seeded() ? "true" : "false", + lrng_state_fully_seeded() ? "true" : "false"); + lrng_drng_unlock(lrng_drng_init, &flags); + + seq_write(m, buf, strlen(buf)); + + return 0; +} + +static int __init lrng_proc_type_init(void) +{ + proc_create_single("lrng_type", 0444, NULL, &lrng_proc_type_show); + return 0; +} + +module_init(lrng_proc_type_init); From patchwork Sun Jan 19 21:14:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 198207 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=3.0 tests=DATE_IN_PAST_06_12, DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_RHS_DOB autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id DBB7EC33CA1 for ; Mon, 20 Jan 2020 07:01:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9CF7B2087E for ; Mon, 20 Jan 2020 07:01:24 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=chronox.de header.i=@chronox.de header.b="EW2WFqoo" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726999AbgATHBW (ORCPT ); Mon, 20 Jan 2020 02:01:22 -0500 Received: from mo4-p04-ob.smtp.rzone.de ([85.215.255.123]:32431 "EHLO mo4-p04-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726936AbgATHBV (ORCPT ); Mon, 20 Jan 2020 02:01:21 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1579503678; 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=QKNIQsi8ZdoYSk6W++0bm2Hui7vA8CCGEGPfHd2Fx9c=; b=EW2WFqoo56ljRfT7D9GqS0aIyySS5wa0qCDZhE8cpKAUUwkUfCswRpc9gQlxfL4Ikx ep4tSq7Sj4QHK+8YYkbTKPDoWc2nwTeyaxk+mMAFo9CeP6gTdUNUW0XHTIsr2zDn7Z9m 93FLwt036T9jZRY8lOzdxWYOIoZYv2+hLuULFSrkCI2KvMH9sZ5iInl4EGXQ2gk/fSdK 8XTjE65URDViiMNbKjL61wkHHbR2X5TR5hCV8XduA2oASe99zQ93WRKh7ZZFbm5GIN5A GxDmuNbP4Rm1KxVCuHlcNtC8v1RN2Sogy8dOG+8g0gg/s53VZrNchCvL8M5Av1Qoirin RyIw== X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPaJvSfTe7W" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 46.1.4 DYNA|AUTH) with ESMTPSA id u04585w0K6xsqZT (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Mon, 20 Jan 2020 07:59:54 +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 , Julia Lawall , Dan Carpenter Subject: [PATCH v29 04/12] LRNG - add switchable DRNG support Date: Sun, 19 Jan 2020 22:14:37 +0100 Message-ID: <2873504.ZWMft1h3jb@positron.chronox.de> In-Reply-To: <1967138.dxe05VgvIB@positron.chronox.de> References: <6157374.ptSnyUpaCn@positron.chronox.de> <5951792.lmNsirYsPE@positron.chronox.de> <1967138.dxe05VgvIB@positron.chronox.de> MIME-Version: 1.0 Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org The DRNG switch support allows replacing the DRNG mechanism of the LRNG. The switching support rests on the interface definition of include/linux/lrng.h. A new DRNG is implemented by filling in the interface defined in this header file. In addition to the DRNG, the extension also has to provide a hash implementation that is used to hash the entropy pool for random number extraction. Note: It is permissible to implement a DRNG whose operations may sleep. However, the hash function must not sleep. The switchable DRNG support allows replacing the DRNG at runtime. However, only one DRNG extension is allowed to be loaded at any given time. Before replacing it with another DRNG implementation, the possibly existing DRNG extension must be unloaded. The switchable DRNG extension activates the new DRNG during load time. It is expected, however, that such a DRNG switch would be done only once by an administrator to load the intended DRNG implementation. It is permissible to compile DRNG extensions either as kernel modules or statically. The initialization of the DRNG extension should be performed with a late_initcall to ensure the extension is available when user space starts but after all other initialization completed. The initialization is performed by registering the function call data structure with the lrng_set_drng_cb function. In order to unload the DRNG extension, lrng_set_drng_cb must be invoked with the NULL parameter. The DRNG extension should always provide a security strength that is at least as strong as LRNG_DRNG_SECURITY_STRENGTH_BITS. 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üller Tested-by: Marcelo Henrique Cerri Tested-by: Neil Horman Signed-off-by: Stephan Mueller --- drivers/char/lrng/Kconfig | 7 ++ drivers/char/lrng/Makefile | 1 + drivers/char/lrng/lrng_switch.c | 182 ++++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+) create mode 100644 drivers/char/lrng/lrng_switch.c diff --git a/drivers/char/lrng/Kconfig b/drivers/char/lrng/Kconfig index 56f13efd3592..cb701bb0b8b6 100644 --- a/drivers/char/lrng/Kconfig +++ b/drivers/char/lrng/Kconfig @@ -64,4 +64,11 @@ config LRNG_POOL_SIZE default 7 if LRNG_POOL_SIZE_65536 default 8 if LRNG_POOL_SIZE_131072 +menuconfig LRNG_DRNG_SWITCH + bool "Support DRNG runtime switching" + help + The Linux RNG per default uses a ChaCha20 DRNG that is + accessible via the external interfaces. With this configuration + option other DRNGs can be selected and loaded at runtime. + endif # LRNG diff --git a/drivers/char/lrng/Makefile b/drivers/char/lrng/Makefile index e69c176f0161..31cfe87c999e 100644 --- a/drivers/char/lrng/Makefile +++ b/drivers/char/lrng/Makefile @@ -10,3 +10,4 @@ obj-y += lrng_pool.o lrng_aux.o \ obj-$(CONFIG_NUMA) += lrng_numa.o obj-$(CONFIG_SYSCTL) += lrng_proc.o +obj-$(CONFIG_LRNG_DRNG_SWITCH) += lrng_switch.o diff --git a/drivers/char/lrng/lrng_switch.c b/drivers/char/lrng/lrng_switch.c new file mode 100644 index 000000000000..7101bda9d7aa --- /dev/null +++ b/drivers/char/lrng/lrng_switch.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * LRNG DRNG switching support + * + * Copyright (C) 2016 - 2020, Stephan Mueller + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include + +#include "lrng_internal.h" + +static int lrng_drng_switch(struct lrng_drng *drng_store, + const struct lrng_crypto_cb *cb, int node) +{ + const struct lrng_crypto_cb *old_cb; + unsigned long flags = 0; + int ret; + u8 seed[LRNG_DRNG_SECURITY_STRENGTH_BYTES]; + void *new_drng = cb->lrng_drng_alloc(LRNG_DRNG_SECURITY_STRENGTH_BYTES); + void *old_drng, *new_hash, *old_hash; + bool sl = false, reset_drng = !lrng_get_available(); + + if (IS_ERR(new_drng)) { + pr_warn("could not allocate new DRNG for NUMA node %d (%ld)\n", + node, PTR_ERR(new_drng)); + return PTR_ERR(new_drng); + } + + new_hash = cb->lrng_hash_alloc(seed, sizeof(seed)); + if (IS_ERR(new_hash)) { + pr_warn("could not allocate new LRNG pool hash (%ld)\n", + PTR_ERR(new_hash)); + cb->lrng_drng_dealloc(new_drng); + return PTR_ERR(new_hash); + } + + lrng_drng_lock(drng_store, &flags); + + /* + * Pull from existing DRNG to seed new DRNG regardless of seed status + * of old DRNG -- the entropy state for the DRNG is left unchanged which + * implies that als the new DRNG is reseeded when deemed necessary. This + * seeding of the new DRNG shall only ensure that the new DRNG has the + * same entropy as the old DRNG. + */ + ret = drng_store->crypto_cb->lrng_drng_generate_helper( + drng_store->drng, seed, sizeof(seed)); + lrng_drng_unlock(drng_store, &flags); + + if (ret < 0) { + reset_drng = true; + pr_warn("getting random data from DRNG failed for NUMA node %d (%d)\n", + node, ret); + } else { + /* seed new DRNG with data */ + ret = cb->lrng_drng_seed_helper(new_drng, seed, ret); + if (ret < 0) { + reset_drng = true; + pr_warn("seeding of new DRNG failed for NUMA node %d (%d)\n", + node, ret); + } else { + pr_debug("seeded new DRNG of NUMA node %d instance from old DRNG instance\n", + node); + } + } + + mutex_lock(&drng_store->lock); + /* + * If we switch the DRNG from the initial ChaCha20 DRNG to something + * else, there is a lock transition from spin lock to mutex (see + * lrng_drng_is_atomic and how the lock is taken in lrng_drng_lock). + * Thus, we need to take both locks during the transition phase. + */ + if (lrng_drng_is_atomic(drng_store)) { + spin_lock_irqsave(&drng_store->spin_lock, flags); + sl = true; + } + + if (reset_drng) + lrng_drng_reset(drng_store); + + old_drng = drng_store->drng; + old_cb = drng_store->crypto_cb; + drng_store->drng = new_drng; + drng_store->crypto_cb = cb; + + old_hash = drng_store->hash; + drng_store->hash = new_hash; + pr_info("Entropy pool read-hash allocated for DRNG for NUMA node %d\n", + node); + + if (sl) + spin_unlock_irqrestore(&drng_store->spin_lock, flags); + mutex_unlock(&drng_store->lock); + + /* ChaCha20 serves as atomic instance left untouched. */ + if (old_drng != &chacha20) { + old_cb->lrng_drng_dealloc(old_drng); + old_cb->lrng_hash_dealloc(old_hash); + } + + pr_info("DRNG of NUMA node %d switched\n", node); + + return 0; +} + +/* + * Switch the existing DRNG instances with new using the new crypto callbacks. + * The caller must hold the lrng_crypto_cb_update lock. + */ +static int lrng_drngs_switch(const struct lrng_crypto_cb *cb) +{ + struct lrng_drng **lrng_drng = lrng_drng_instances(); + struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); + int ret = 0; + + /* Update DRNG */ + if (lrng_drng) { + u32 node; + + for_each_online_node(node) { + if (lrng_drng[node]) + ret = lrng_drng_switch(lrng_drng[node], cb, + node); + } + } else { + ret = lrng_drng_switch(lrng_drng_init, cb, 0); + } + + if (!ret) + lrng_set_available(); + + return 0; +} + +/** + * lrng_set_drng_cb - Register new cryptographic callback functions for DRNG + * The registering implies that all old DRNG states are replaced with new + * DRNG states. + * + * @cb: Callback functions to be registered -- if NULL, use the default + * callbacks pointing to the ChaCha20 DRNG. + * + * Return: + * * 0 on success + * * < 0 on error + */ +int lrng_set_drng_cb(const struct lrng_crypto_cb *cb) +{ + struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); + int ret; + + if (!cb) + cb = &lrng_cc20_crypto_cb; + + mutex_lock(&lrng_crypto_cb_update); + + /* + * If a callback other than the default is set, allow it only to be + * set back to the default callback. This ensures that multiple + * different callbacks can be registered at the same time. If a + * callback different from the current callback and the default + * callback shall be set, the current callback must be deregistered + * (e.g. the kernel module providing it must be unloaded) and the new + * implementation can be registered. + */ + if ((cb != &lrng_cc20_crypto_cb) && + (lrng_drng_init->crypto_cb != &lrng_cc20_crypto_cb)) { + pr_warn("disallow setting new cipher callbacks, unload the old callbacks first!\n"); + ret = -EINVAL; + goto out; + } + + ret = lrng_drngs_switch(cb); + +out: + mutex_unlock(&lrng_crypto_cb_update); + return ret; +} +EXPORT_SYMBOL(lrng_set_drng_cb); From patchwork Sun Jan 19 21:15:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 198206 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=3.0 tests=DATE_IN_PAST_06_12, DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_RHS_DOB autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D1499C33CB1 for ; Mon, 20 Jan 2020 07:01:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9CB212077C for ; Mon, 20 Jan 2020 07:01:45 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=chronox.de header.i=@chronox.de header.b="Ols0BcMg" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727144AbgATHBc (ORCPT ); Mon, 20 Jan 2020 02:01:32 -0500 Received: from mo4-p04-ob.smtp.rzone.de ([81.169.146.223]:19703 "EHLO mo4-p04-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727066AbgATHBb (ORCPT ); Mon, 20 Jan 2020 02:01:31 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1579503688; 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=lQoVaKaZhQYFSzt5ljo8PmF2jf0BPLYXIAKTTbd/HUg=; b=Ols0BcMg+8jwOJ1VP+v80NKTX7u6VNUeStNLLq1/aRIODA0YdDGHVZsQ4hahTH5kAf Ov5Wvzy7sW/d7UJhLVZTEuDZh/wzExM1lrgif4zM/0JajZD4JGIw6ycFVwWihCwSVRo6 WNN7kFllARPv1RJ5qIlM5JDwim4663GV98N8mVyo1vjkM11D+DrSgH6C4n11DBOFgjdB r0To6XprdckIH3j41GZ12qJa+Up1dFrKHoISWw5IGWnfBBU1yp0Y7XfSPTYHkbAdDlpy D0Eg5I8JdR0QxiN76IjdBIj+a1pJXCXjNv06QixYBzEDwi6bry7NhY1TZX9D3+9uTbuM Wp0Q== X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPaJvSfTe7W" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 46.1.4 DYNA|AUTH) with ESMTPSA id u04585w0K6xrqZS (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Mon, 20 Jan 2020 07:59:53 +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 , Julia Lawall , Dan Carpenter Subject: [PATCH v29 05/12] crypto: DRBG - externalize DRBG functions for LRNG Date: Sun, 19 Jan 2020 22:15:16 +0100 Message-ID: <2000350.RyDQXNO8lN@positron.chronox.de> In-Reply-To: <1967138.dxe05VgvIB@positron.chronox.de> References: <6157374.ptSnyUpaCn@positron.chronox.de> <5951792.lmNsirYsPE@positron.chronox.de> <1967138.dxe05VgvIB@positron.chronox.de> MIME-Version: 1.0 Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org This patch allows several DRBG functions to be called by the LRNG kernel code paths outside the drbg.c file. 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: Roman Drahtmueller Tested-by: Roman Drahtmüller Tested-by: Marcelo Henrique Cerri Tested-by: Neil Horman Signed-off-by: Stephan Mueller --- crypto/drbg.c | 16 ++++++++++------ include/crypto/drbg.h | 7 +++++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index b6929eb5f565..5561dd0f09e1 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -113,7 +113,7 @@ * the SHA256 / AES 256 over other ciphers. Thus, the favored * DRBGs are the latest entries in this array. */ -static const struct drbg_core drbg_cores[] = { +const struct drbg_core drbg_cores[] = { #ifdef CONFIG_CRYPTO_DRBG_CTR { .flags = DRBG_CTR | DRBG_STRENGTH128, @@ -190,6 +190,7 @@ static const struct drbg_core drbg_cores[] = { }, #endif /* CONFIG_CRYPTO_DRBG_HMAC */ }; +EXPORT_SYMBOL(drbg_cores); static int drbg_uninstantiate(struct drbg_state *drbg); @@ -205,7 +206,7 @@ static int drbg_uninstantiate(struct drbg_state *drbg); * Return: normalized strength in *bytes* value or 32 as default * to counter programming errors */ -static inline unsigned short drbg_sec_strength(drbg_flag_t flags) +unsigned short drbg_sec_strength(drbg_flag_t flags) { switch (flags & DRBG_STRENGTH_MASK) { case DRBG_STRENGTH128: @@ -218,6 +219,7 @@ static inline unsigned short drbg_sec_strength(drbg_flag_t flags) return 32; } } +EXPORT_SYMBOL(drbg_sec_strength); /* * FIPS 140-2 continuous self test for the noise source @@ -1202,7 +1204,7 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, } /* Free all substructures in a DRBG state without the DRBG state structure */ -static inline void drbg_dealloc_state(struct drbg_state *drbg) +void drbg_dealloc_state(struct drbg_state *drbg) { if (!drbg) return; @@ -1223,12 +1225,13 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) drbg->fips_primed = false; } } +EXPORT_SYMBOL(drbg_dealloc_state); /* * Allocate all sub-structures for a DRBG state. * The DRBG state structure must already be allocated. */ -static inline int drbg_alloc_state(struct drbg_state *drbg) +int drbg_alloc_state(struct drbg_state *drbg) { int ret = -ENOMEM; unsigned int sb_size = 0; @@ -1307,6 +1310,7 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) drbg_dealloc_state(drbg); return ret; } +EXPORT_SYMBOL(drbg_alloc_state); /************************************************************************* * DRBG interface functions @@ -1874,8 +1878,7 @@ static int drbg_kcapi_sym_ctr(struct drbg_state *drbg, * * return: flags */ -static inline void drbg_convert_tfm_core(const char *cra_driver_name, - int *coreref, bool *pr) +void drbg_convert_tfm_core(const char *cra_driver_name, int *coreref, bool *pr) { int i = 0; size_t start = 0; @@ -1902,6 +1905,7 @@ static inline void drbg_convert_tfm_core(const char *cra_driver_name, } } } +EXPORT_SYMBOL(drbg_convert_tfm_core); static int drbg_kcapi_init(struct crypto_tfm *tfm) { diff --git a/include/crypto/drbg.h b/include/crypto/drbg.h index 8c9af21efce1..c63b20375235 100644 --- a/include/crypto/drbg.h +++ b/include/crypto/drbg.h @@ -282,4 +282,11 @@ enum drbg_prefixes { DRBG_PREFIX3 }; +extern int drbg_alloc_state(struct drbg_state *drbg); +extern void drbg_dealloc_state(struct drbg_state *drbg); +extern void drbg_convert_tfm_core(const char *cra_driver_name, int *coreref, + bool *pr); +extern const struct drbg_core drbg_cores[]; +extern unsigned short drbg_sec_strength(drbg_flag_t flags); + #endif /* _DRBG_H */ From patchwork Sun Jan 19 21:16:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 198202 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=3.0 tests=DATE_IN_PAST_06_12, DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_RHS_DOB autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 128E4C33CB8 for ; Mon, 20 Jan 2020 07:02:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id CA195207E0 for ; Mon, 20 Jan 2020 07:02:17 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=chronox.de header.i=@chronox.de header.b="E1xkvN2I" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728748AbgATHCL (ORCPT ); Mon, 20 Jan 2020 02:02:11 -0500 Received: from mo4-p04-ob.smtp.rzone.de ([85.215.255.122]:14792 "EHLO mo4-p04-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726089AbgATHCK (ORCPT ); Mon, 20 Jan 2020 02:02:10 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1579503726; 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=SL76R+x3xnCbsccg0UNdJ64H0iNg82brAV2uASaraaY=; b=E1xkvN2IfHSTRqi8Uu1zPpYWwPmDqQTcTPypQaFYd2F8Hf5tjvhHgMqJWdiNPJpRAA oILShjHQ74wDJoogfN7vjCS/9W4jaRLVbbHKYA3K8L2GcfURWq8D6BoDX0auftD88ga6 b4npKGqwzlSb2GbuXXSpzkzb8WqAVx0yc0jgORVrSDinCSznBF/yVMwPx6lM2JRwjd9z T4fWCAJlbAf0zy2/uqm0XiiK2CNpJIw6yC4qD5kj9vOxNCSozPNKBYISUMijv9UThjWV nYgD4pjjCLGh0Zews+tIshRVG40e0zboh9vhdBeL5YGw6f82ENyKhp1gXXIDyWgC5F4D J+sQ== X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPaJvSfTe7W" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 46.1.4 DYNA|AUTH) with ESMTPSA id u04585w0K6xoqZQ (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Mon, 20 Jan 2020 07:59:50 +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 , Julia Lawall , Dan Carpenter Subject: [PATCH v29 07/12] LRNG - add kernel crypto API PRNG extension Date: Sun, 19 Jan 2020 22:16:43 +0100 Message-ID: <20041252.vrp9WXmmXk@positron.chronox.de> In-Reply-To: <1967138.dxe05VgvIB@positron.chronox.de> References: <6157374.ptSnyUpaCn@positron.chronox.de> <5951792.lmNsirYsPE@positron.chronox.de> <1967138.dxe05VgvIB@positron.chronox.de> MIME-Version: 1.0 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üller Tested-by: Marcelo Henrique Cerri Tested-by: Neil Horman Signed-off-by: Stephan Mueller --- drivers/char/lrng/Kconfig | 11 ++ drivers/char/lrng/Makefile | 1 + drivers/char/lrng/lrng_kcapi.c | 321 +++++++++++++++++++++++++++++++++ 3 files changed, 333 insertions(+) create mode 100644 drivers/char/lrng/lrng_kcapi.c diff --git a/drivers/char/lrng/Kconfig b/drivers/char/lrng/Kconfig index b32442484823..7afc965a4d52 100644 --- a/drivers/char/lrng/Kconfig +++ b/drivers/char/lrng/Kconfig @@ -81,6 +81,17 @@ 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" + depends on CRYPTO + 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 endif # LRNG diff --git a/drivers/char/lrng/Makefile b/drivers/char/lrng/Makefile index 0d320fcb7b9e..94b2dfb2dfdb 100644 --- a/drivers/char/lrng/Makefile +++ b/drivers/char/lrng/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_NUMA) += lrng_numa.o obj-$(CONFIG_SYSCTL) += lrng_proc.o obj-$(CONFIG_LRNG_DRNG_SWITCH) += lrng_switch.o obj-$(CONFIG_LRNG_DRBG) += lrng_drbg.o +obj-$(CONFIG_LRNG_KCAPI) += 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..482f31627422 --- /dev/null +++ b/drivers/char/lrng/lrng_kcapi.c @@ -0,0 +1,321 @@ +// 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 - 2020, Stephan Mueller + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include + +static char *drng_name = NULL; +module_param(drng_name, charp, 0444); +MODULE_PARM_DESC(drng_name, "Kernel crypto API name of DRNG"); + +static char *pool_hash = "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 entropy pool"); + +static char *seed_hash = 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 DRNG 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 = crypto_alloc_shash(name, 0, 0); + if (IS_ERR(tfm)) { + pr_err("could not allocate hash %s\n", name); + return ERR_CAST(tfm); + } + + size = sizeof(struct lrng_hash_info) + crypto_shash_descsize(tfm); + lrng_hash = kmalloc(size, GFP_KERNEL); + if (!lrng_hash) { + crypto_free_shash(tfm); + return ERR_PTR(-ENOMEM); + } + + lrng_hash->shash.tfm = tfm; + + return lrng_hash; +} + +static inline u32 _lrng_kcapi_hash_digestsize(struct lrng_hash_info *lrng_hash) +{ + struct shash_desc *shash = &lrng_hash->shash; + struct crypto_shash *tfm = shash->tfm; + + return crypto_shash_digestsize(tfm); +} + +static inline void _lrng_kcapi_hash_free(struct lrng_hash_info *lrng_hash) +{ + struct shash_desc *shash = &lrng_hash->shash; + struct crypto_shash *tfm = 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 = _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 = crypto_shash_setkey(lrng_hash->shash.tfm, key, keylen); + if (ret && ret != -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 = (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 = (struct lrng_hash_info *)hash; + + return _lrng_kcapi_hash_digestsize(lrng_hash); +} + +static int lrng_kcapi_hash_buffer(void *hash, const u8 *inbuf, u32 inbuflen, + u8 *digest) +{ + struct lrng_hash_info *lrng_hash = (struct lrng_hash_info *)hash; + struct shash_desc *shash = &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 = (struct lrng_drng_info *)drng; + struct crypto_rng *kcapi_rng = lrng_drng_info->kcapi_rng; + struct lrng_hash_info *lrng_hash = lrng_drng_info->lrng_hash; + + if (lrng_hash) { + struct shash_desc *shash = &lrng_hash->shash; + u32 digestsize = _lrng_kcapi_hash_digestsize(lrng_hash); + u8 digest[64] __aligned(8); + int ret; + + BUG_ON(digestsize > sizeof(digest)); + + ret = crypto_shash_digest(shash, inbuf, inbuflen, digest); + if (ret) + return ret; + + ret = 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 = (struct lrng_drng_info *)drng; + struct crypto_rng *kcapi_rng = lrng_drng_info->kcapi_rng; + int ret = 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 = 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 = kmalloc(sizeof(*lrng_drng_info), GFP_KERNEL); + if (!lrng_drng_info) + return ERR_PTR(-ENOMEM); + + kcapi_rng = crypto_alloc_rng(drng_name, 0, 0); + if (IS_ERR(kcapi_rng)) { + pr_err("DRNG %s cannot be allocated\n", drng_name); + ret = ERR_CAST(kcapi_rng); + goto free; + } + lrng_drng_info->kcapi_rng = kcapi_rng; + + seedsize = 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 = "sha256"; + break; + case 48: + seed_hash = "sha384"; + break; + case 64: + seed_hash = "sha512"; + break; + default: + pr_err("Seed size %d cannot be processed\n", + seedsize); + goto dealloc; + break; + } + } + + lrng_hash = _lrng_kcapi_hash_alloc(seed_hash); + if (IS_ERR(lrng_hash)) { + ret = ERR_CAST(lrng_hash); + goto dealloc; + } + + if (seedsize != _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 = ERR_PTR(-EINVAL); + goto dealloc; + } + + lrng_drng_info->lrng_hash = lrng_hash; + + pr_info("Seed hash %s allocated\n", seed_hash); + } else { + lrng_drng_info->lrng_hash = 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 = (struct lrng_drng_info *)drng; + struct crypto_rng *kcapi_rng = lrng_drng_info->kcapi_rng; + struct lrng_hash_info *lrng_hash = 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 = { + .lrng_drng_name = lrng_kcapi_drng_name, + .lrng_hash_name = lrng_kcapi_pool_hash, + .lrng_drng_alloc = lrng_kcapi_drng_alloc, + .lrng_drng_dealloc = lrng_kcapi_drng_dealloc, + .lrng_drng_seed_helper = lrng_kcapi_drng_seed_helper, + .lrng_drng_generate_helper = lrng_kcapi_drng_generate_helper, + .lrng_hash_alloc = lrng_kcapi_hash_alloc, + .lrng_hash_dealloc = lrng_kcapi_hash_dealloc, + .lrng_hash_digestsize = lrng_kcapi_hash_digestsize, + .lrng_hash_buffer = 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"); From patchwork Sun Jan 19 21:17:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 198204 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=3.0 tests=DATE_IN_PAST_06_12, DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_RHS_DOB autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 97B0CC33CA1 for ; Mon, 20 Jan 2020 07:01:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 651112073D for ; Mon, 20 Jan 2020 07:01:59 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=chronox.de header.i=@chronox.de header.b="q5iEjTH8" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726827AbgATHBR (ORCPT ); Mon, 20 Jan 2020 02:01:17 -0500 Received: from mo4-p03-ob.smtp.rzone.de ([85.215.255.104]:15606 "EHLO mo4-p03-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726421AbgATHBQ (ORCPT ); Mon, 20 Jan 2020 02:01:16 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1579503675; 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=ft6+RGXwGoNfQPVxUIyS6aMtaPfNIigO2DmrtfxTDMo=; b=q5iEjTH8C6Ov26uOpOIr3LWTgQCb9E3oDIevGmo3OBaoAo1ekAnu4gjj/gy7Oziqqy gIFuB4MqIq1Lz0g6gQMoZVEV8KT7+Px1aholu34Kts70vi20GJIfxX3EK4yOUm0Q7omI WO/V81eS5QCMkMSI6iZjU07Lr4kwg9ULFkbFV0TrfFkAhewdMRx+y2gZ4UJytuGL5t3E /msjyFhyjyqWC71n5dDESWW+Be2Xm4pVRACvGNCZQywmH/QHBzsQcXWnxKwI/ccckK9l Z391UHBhMFGx/rSh2KygM3QWNklmEAGE2bCCrQbb4eaMADiPZmJJ77Sek9VBMyERlK3g X4tQ== X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPaJvSfTe7W" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 46.1.4 DYNA|AUTH) with ESMTPSA id u04585w0K6xnqZP (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Mon, 20 Jan 2020 07:59:49 +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 , Julia Lawall , Dan Carpenter Subject: [PATCH v29 08/12] crypto: provide access to a static Jitter RNG state Date: Sun, 19 Jan 2020 22:17:33 +0100 Message-ID: <3163301.oFKfPMb7QI@positron.chronox.de> In-Reply-To: <1967138.dxe05VgvIB@positron.chronox.de> References: <6157374.ptSnyUpaCn@positron.chronox.de> <5951792.lmNsirYsPE@positron.chronox.de> <1967138.dxe05VgvIB@positron.chronox.de> MIME-Version: 1.0 Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org To support the LRNG operation which uses the Jitter RNG separately from the kernel crypto API, at a time where potentially the regular memory management is not yet initialized, the Jitter RNG needs to provide a state whose memory is defined at compile time. As only once instance will ever be needed by the LRNG, define once static memory block which is solely to be used by the LRNG. 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: Roman Drahtmueller Tested-by: Roman Drahtmüller Tested-by: Marcelo Henrique Cerri Tested-by: Neil Horman Signed-off-by: Stephan Mueller --- crypto/jitterentropy-kcapi.c | 3 +-- crypto/jitterentropy.c | 25 ++++++++++++++++++- .../crypto/internal}/jitterentropy.h | 3 +++ 3 files changed, 28 insertions(+), 3 deletions(-) rename {crypto => include/crypto/internal}/jitterentropy.h (84%) diff --git a/crypto/jitterentropy-kcapi.c b/crypto/jitterentropy-kcapi.c index a5ce8f96790f..11b00e9f37f3 100644 --- a/crypto/jitterentropy-kcapi.c +++ b/crypto/jitterentropy-kcapi.c @@ -43,8 +43,7 @@ #include #include #include - -#include "jitterentropy.h" +#include /*************************************************************************** * Helper function diff --git a/crypto/jitterentropy.c b/crypto/jitterentropy.c index 042157f0d28b..529c9db13e64 100644 --- a/crypto/jitterentropy.c +++ b/crypto/jitterentropy.c @@ -103,7 +103,7 @@ struct rand_data { * Helper functions ***************************************************************************/ -#include "jitterentropy.h" +#include /** * Update of the loop count used for the next round of @@ -639,3 +639,26 @@ int jent_entropy_init(void) return 0; } + +struct rand_data *jent_lrng_entropy_collector(void) +{ + static unsigned char lrng_jent_mem[JENT_MEMORY_SIZE]; + static struct rand_data lrng_jent_state = { + .data = 0, + .old_data = 0, + .prev_time = 0, + .last_delta = 0, + .last_delta2 = 0, + .osr = 1, + .mem = lrng_jent_mem, + .memlocation = 0, + .memblocks = JENT_MEMORY_BLOCKSIZE, + .memblocksize = JENT_MEMORY_BLOCKS, + .memaccessloops = JENT_MEMORY_ACCESSLOOPS, + }; + + if (jent_entropy_init()) + return NULL; + + return &lrng_jent_state; +} diff --git a/crypto/jitterentropy.h b/include/crypto/internal/jitterentropy.h similarity index 84% rename from crypto/jitterentropy.h rename to include/crypto/internal/jitterentropy.h index c83fff32d130..6e07d86eac82 100644 --- a/crypto/jitterentropy.h +++ b/include/crypto/internal/jitterentropy.h @@ -15,3 +15,6 @@ extern int jent_read_entropy(struct rand_data *ec, unsigned char *data, extern struct rand_data *jent_entropy_collector_alloc(unsigned int osr, unsigned int flags); extern void jent_entropy_collector_free(struct rand_data *entropy_collector); + +/* Access to statically allocated Jitter RNG instance */ +extern struct rand_data *jent_lrng_entropy_collector(void); From patchwork Sun Jan 19 21:18:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 198203 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=3.0 tests=DATE_IN_PAST_06_12, DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_RHS_DOB autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 717D5C33CB8 for ; Mon, 20 Jan 2020 07:02:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 4974B207FD for ; Mon, 20 Jan 2020 07:02:12 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=chronox.de header.i=@chronox.de header.b="qQDnd1Pq" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726451AbgATHBP (ORCPT ); Mon, 20 Jan 2020 02:01:15 -0500 Received: from mo4-p03-ob.smtp.rzone.de ([81.169.146.174]:19741 "EHLO mo4-p03-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726417AbgATHBP (ORCPT ); Mon, 20 Jan 2020 02:01:15 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1579503671; 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=4x3dAu/lQePlKfhlvd92mlwrIjoi27oz6nruTurD6/Y=; b=qQDnd1Pqzhdc7sD36lxuLVgLef5hkKUWB/DKtLh/VXckrXemGVZ9Ppr6+6+DH6t357 q95KmU8KPg4ygRAKCa5GsG/gxEVP3l+Uo52vMafCIlhEeQWrmA7yUbEkMBXhXNSytY8X deL8I8cun2zE60QQSpXFv+/H7oeSepBA7sQuXj93F5iudNuBCAehdQm1cSuU4G9wR7iz 6Pw3SIemusCXmgM3/OpFTM+XeuxcCcjvA53/+PGY/u1lDxMB5uzb/23j4G9pE2OOASbM iUo4B0wE75fI8zyMEF+/t94aWZW0/V40xo/lqMx8hqoGFKo2eYns4ab6OhCBNy5Uzzhl ps4w== X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPaJvSfTe7W" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 46.1.4 DYNA|AUTH) with ESMTPSA id u04585w0K6xlqZO (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Mon, 20 Jan 2020 07:59:47 +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 , Julia Lawall , Dan Carpenter Subject: [PATCH v29 09/12] LRNG - add Jitter RNG fast noise source Date: Sun, 19 Jan 2020 22:18:04 +0100 Message-ID: <4639457.SCQOsVujqT@positron.chronox.de> In-Reply-To: <1967138.dxe05VgvIB@positron.chronox.de> References: <6157374.ptSnyUpaCn@positron.chronox.de> <5951792.lmNsirYsPE@positron.chronox.de> <1967138.dxe05VgvIB@positron.chronox.de> MIME-Version: 1.0 Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org The Jitter RNG fast noise source implemented as part of the kernel crypto API is queried for 256 bits of entropy at the time the seed buffer managed by the LRNG is about to be filled. 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üller Tested-by: Marcelo Henrique Cerri Tested-by: Neil Horman Signed-off-by: Stephan Mueller --- drivers/char/lrng/Kconfig | 12 +++++ drivers/char/lrng/Makefile | 1 + drivers/char/lrng/lrng_jent.c | 88 +++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 drivers/char/lrng/lrng_jent.c diff --git a/drivers/char/lrng/Kconfig b/drivers/char/lrng/Kconfig index 7afc965a4d52..4684e838f011 100644 --- a/drivers/char/lrng/Kconfig +++ b/drivers/char/lrng/Kconfig @@ -94,4 +94,16 @@ config LRNG_KCAPI provided by the selected kernel crypto API RNG. endif # LRNG_DRNG_SWITCH +config LRNG_JENT + bool "Enable Jitter RNG as LRNG Seed Source" + depends on CRYPTO + select CRYPTO_JITTERENTROPY + help + The Linux RNG may use the Jitter RNG as noise source. Enabling + this option enables the use of the Jitter RNG. Its default + entropy level is 16 bits of entropy per 256 data bits delivered + by the Jitter RNG. This entropy level can be changed at boot + time or at runtime with the lrng_base.jitterrng configuration + variable. + endif # LRNG diff --git a/drivers/char/lrng/Makefile b/drivers/char/lrng/Makefile index 94b2dfb2dfdb..4f5b6f38f0c4 100644 --- a/drivers/char/lrng/Makefile +++ b/drivers/char/lrng/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_SYSCTL) += lrng_proc.o obj-$(CONFIG_LRNG_DRNG_SWITCH) += lrng_switch.o obj-$(CONFIG_LRNG_DRBG) += lrng_drbg.o obj-$(CONFIG_LRNG_KCAPI) += lrng_kcapi.o +obj-$(CONFIG_LRNG_JENT) += lrng_jent.o diff --git a/drivers/char/lrng/lrng_jent.c b/drivers/char/lrng/lrng_jent.c new file mode 100644 index 000000000000..225505271fcb --- /dev/null +++ b/drivers/char/lrng/lrng_jent.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * LRNG Fast Noise Source: Jitter RNG + * + * Copyright (C) 2016 - 2020, Stephan Mueller + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include + +#include "lrng_internal.h" + +/* + * Estimated entropy of data is a 16th of LRNG_DRNG_SECURITY_STRENGTH_BITS. + * Albeit a full entropy assessment is provided for the noise source indicating + * that it provides high entropy rates and considering that it deactivates + * when it detects insufficient hardware, the chosen under estimation of + * entropy is considered to be acceptable to all reviewers. + */ +static u32 jitterrng = LRNG_DRNG_SECURITY_STRENGTH_BITS>>4; +module_param(jitterrng, uint, 0644); +MODULE_PARM_DESC(jitterrng, "Entropy in bits of 256 data bits from Jitter RNG noise source"); + +/** + * lrng_get_jent() - Get Jitter RNG entropy + * + * @outbuf: buffer to store entropy + * @outbuflen: length of buffer + * + * Return: + * * > 0 on success where value provides the added entropy in bits + * * 0 if no fast source was available + */ +static struct rand_data *lrng_jent_state; + +u32 lrng_get_jent(u8 *outbuf, unsigned int outbuflen) +{ + int ret; + u32 ent_bits = jitterrng; + unsigned long flags; + static DEFINE_SPINLOCK(lrng_jent_lock); + static int lrng_jent_initialized = 0; + + spin_lock_irqsave(&lrng_jent_lock, flags); + + if (!ent_bits || (lrng_jent_initialized == -1)) { + spin_unlock_irqrestore(&lrng_jent_lock, flags); + return 0; + } + + if (!lrng_jent_initialized) { + lrng_jent_state = jent_lrng_entropy_collector(); + if (!lrng_jent_state) { + jitterrng = 0; + lrng_jent_initialized = -1; + spin_unlock_irqrestore(&lrng_jent_lock, flags); + pr_info("Jitter RNG unusable on current system\n"); + return 0; + } + lrng_jent_initialized = 1; + pr_debug("Jitter RNG working on current system\n"); + } + ret = jent_read_entropy(lrng_jent_state, outbuf, outbuflen); + spin_unlock_irqrestore(&lrng_jent_lock, flags); + + if (ret) { + pr_debug("Jitter RNG failed with %d\n", ret); + return 0; + } + + /* Obtain entropy statement */ + if (outbuflen != LRNG_DRNG_SECURITY_STRENGTH_BYTES) + ent_bits = (ent_bits * outbuflen<<3) / + LRNG_DRNG_SECURITY_STRENGTH_BITS; + /* Cap entropy to buffer size in bits */ + ent_bits = min_t(u32, ent_bits, outbuflen<<3); + pr_debug("obtained %u bits of entropy from Jitter RNG noise source\n", + ent_bits); + + return ent_bits; +} + +u32 lrng_jent_entropylevel(void) +{ + return min_t(u32, jitterrng, LRNG_DRNG_SECURITY_STRENGTH_BITS); +} From patchwork Wed Jan 15 10:35:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 198226 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.6 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6745EC33CB7 for ; Wed, 15 Jan 2020 10:40:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 202DD24684 for ; Wed, 15 Jan 2020 10:40:10 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=chronox.de header.i=@chronox.de header.b="sRz79nDX" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729890AbgAOKje (ORCPT ); Wed, 15 Jan 2020 05:39:34 -0500 Received: from mo4-p03-ob.smtp.rzone.de ([81.169.146.174]:21018 "EHLO mo4-p03-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729858AbgAOKjd (ORCPT ); Wed, 15 Jan 2020 05:39:33 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1579084767; 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=UCYxsKWme4ZV2WoiD5VqK4OLlqPqJTjTZDTGoBMgiWw=; b=sRz79nDXxTDsFisAlZ92qX6l1ppP3N+IVYCMZfR6KTqg+dpYIpswbLbfE6QsHGpf+4 wuGUfFpTQRZb+W4d+RBzIV7k0QffncwPxE8p8lF4SDwcX1OSY+QAjc3MAjcY3D6P/uqD VqYUBvzJYZHdVC8myGvjL3CYoH7DVDyucDMHeFYR+evDvTM5aCHoNjPj+is9Rb8BXEE7 FtI1tO6SMyx1olzr4wQCnS1tGSUs6xy9zH9F8j+9xZFVj8vLB84wPkrk+vNdFLSVukBy aGY818WDAQfKsYt1P4+2KLK6Q2wQ0Nef37/j3XEUPykTRVRnHFpbahxo0lAj87e3rllv A8YQ== X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPZJPScHivh" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 46.1.4 DYNA|AUTH) with ESMTPSA id u04585w0FAc2W00 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Wed, 15 Jan 2020 11:38:02 +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 , Julia Lawall , Dan Carpenter Subject: [PATCH v28 10/12] LRNG - add SP800-90B compliant health tests Date: Wed, 15 Jan 2020 11:35:22 +0100 Message-ID: <3714975.c4kBKJ4xk9@positron.chronox.de> In-Reply-To: <5951792.lmNsirYsPE@positron.chronox.de> References: <6157374.ptSnyUpaCn@positron.chronox.de> <2641155.iNH938UiKq@positron.chronox.de> <5951792.lmNsirYsPE@positron.chronox.de> MIME-Version: 1.0 Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org Implement health tests for LRNG's slow noise sources as mandated by SP-800-90B The file contains the following health tests: - stuck test: The stuck test calculates the first, second and third discrete derivative of the time stamp to be processed by the LFSR. Only if all three values are non-zero, the received time delta is considered to be non-stuck. - SP800-90B Repetition Count Test (RCT): The LRNG uses an enhanced version of the RCT specified in SP800-90B section 4.4.1. Instead of counting identical back-to-back values, the input to the RCT is the counting of the stuck values during the processing of received interrupt events. The RCT is applied with alpha=2^-30 compliant to the recommendation of FIPS 140-2 IG 9.8. During the counting operation, the LRNG always calculates the RCT cut-off value of C. If that value exceeds the allowed cut-off value, the LRNG will trigger the health test failure discussed below. An error is logged to the kernel log that such RCT failure occurred. This test is only applied and enforced in FIPS mode, i.e. when the kernel compiled with CONFIG_CONFIG_FIPS is started with fips=1. - SP800-90B Adaptive Proportion Test (APT): The LRNG implements the APT as defined in SP800-90B section 4.4.2. The applied significance level again is alpha=2^-30 compliant to the recommendation of FIPS 140-2 IG 9.8. The aforementioned health tests are applied to the first 1,024 time stamps obtained from interrupt events. In case one error is identified for either the RCT, or the APT, the collected entropy is invalidated and the SP800-90B startup health test is restarted. As long as the SP800-90B startup health test is not completed, all LRNG random number output interfaces that may block will block and not generate any data. This implies that only those potentially blocking interfaces are defined to provide random numbers that are seeded with the interrupt noise source being SP800-90B compliant. All other output interfaces will not be affected by the SP800-90B startup test and thus are not considered SP800-90B compliant. At runtime, the SP800-90B APT and RCT are applied to each time stamp generated for a received interrupt. When either the APT and RCT indicates a noise source failure, the LRNG is reset to a state it has immediately after boot: - all entropy counters are set to zero - the SP800-90B startup tests are re-performed which implies that getrandom(2) would block again until new entropy was collected To summarize, the following rules apply: • SP800-90B compliant output interfaces - /dev/random - getrandom(2) system call - get_random_bytes kernel-internal interface when being triggered by the callback registered with add_random_ready_callback • SP800-90B non-compliant output interfaces - /dev/urandom - get_random_bytes kernel-internal interface called directly - randomize_page kernel-internal interface - get_random_u32 and get_random_u64 kernel-internal interfaces - get_random_u32_wait, get_random_u64_wait, get_random_int_wait, and get_random_long_wait kernel-internal interfaces If either the RCT, or the APT health test fails irrespective whether during initialization or runtime, the following actions occur: 1. The entropy of the entire entropy pool is invalidated. 2. All DRNGs are reset which imply that they are treated as being not seeded and require a reseed during next invocation. 3. The SP800-90B startup health test are initiated with all implications of the startup tests. That implies that from that point on, new events must be observed and its entropy must be inserted into the entropy pool before random numbers are calculated from the entropy pool. Further details on the SP800-90B compliance and the availability of all test tools required to perform all tests mandated by SP800-90B are provided at [1]. The entire health testing code is compile-time configurable. The patch provides a CONFIG_BROKEN configuration of the APT / RCT cutoff values which have a high likelihood to trigger the health test failure. The BROKEN APT cutoff is set to the exact mean of the expected value if the time stamps are equally distributed (512 time stamps divided by 16 possible values due to using the 4 LSB of the time stamp). The BROKEN RCT cutoff value is set to 1 which is likely to be triggered during regular operation. 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: Roman Drahtmueller Tested-by: Roman Drahtmüller Tested-by: Marcelo Henrique Cerri Tested-by: Neil Horman Signed-off-by: Stephan Mueller --- drivers/char/lrng/Kconfig | 56 +++++ drivers/char/lrng/Makefile | 1 + drivers/char/lrng/lrng_health.c | 409 ++++++++++++++++++++++++++++++++ 3 files changed, 466 insertions(+) create mode 100644 drivers/char/lrng/lrng_health.c diff --git a/drivers/char/lrng/Kconfig b/drivers/char/lrng/Kconfig index 10b7cbdb8c8e..12b6b3439853 100644 --- a/drivers/char/lrng/Kconfig +++ b/drivers/char/lrng/Kconfig @@ -103,4 +103,60 @@ config LRNG_JENT time or at runtime with the lrng_base.jitterrng configuration variable. +config LRNG_HEALTH_TESTS + bool "Enable noise source online health tests" + help + The online health tests validate the noise source at + runtime for fatal errors. These tests include SP800-90B + compliant tests which are invoked if the system is booted + with fips=1. In case of fatal errors during active + SP800-90B tests, the issue is logged and the noise + data is discarded. These tests are required for full + compliance with SP800-90B. + + If unsure, say Y. + +config LRNG_RCT_BROKEN + bool "SP800-90B RCT with dangerous low cutoff value" + depends on LRNG_HEALTH_TESTS + depends on BROKEN + default n + help + This option enables a dangerously low SP800-90B repetitive + count test (RCT) cutoff value which makes it very likely + that the RCT is triggered to raise a self test failure. + + This option is ONLY intended for developers wanting to + test the effectiveness of the SP800-90B RCT health test. + + If unsure, say N. + +config LRNG_APT_BROKEN + bool "SP800-90B APT with dangerous low cutoff value" + depends on LRNG_HEALTH_TESTS + depends on BROKEN + default n + help + This option enables a dangerously low SP800-90B adaptive + proportion test (APT) cutoff value which makes it very + likely that the RCT is triggered to raise a self test + failure. + + This option is ONLY intended for developers wanting to + test the effectiveness of the SP800-90B APT health test. + + If unsure, say N. + +# Default taken from SP800-90B sec 4.4.1 - significance level 2^-30 +config LRNG_RCT_CUTOFF + int + default 31 if !LRNG_RCT_BROKEN + default 1 if LRNG_RCT_BROKEN + +# Default taken from SP800-90B sec 4.4.2 - significance level 2^-30 +config LRNG_APT_CUTOFF + int + default 325 if !LRNG_APT_BROKEN + default 32 if LRNG_APT_BROKEN + endif # LRNG diff --git a/drivers/char/lrng/Makefile b/drivers/char/lrng/Makefile index 4f5b6f38f0c4..c3008763dd14 100644 --- a/drivers/char/lrng/Makefile +++ b/drivers/char/lrng/Makefile @@ -14,3 +14,4 @@ obj-$(CONFIG_LRNG_DRNG_SWITCH) += lrng_switch.o obj-$(CONFIG_LRNG_DRBG) += lrng_drbg.o obj-$(CONFIG_LRNG_KCAPI) += lrng_kcapi.o obj-$(CONFIG_LRNG_JENT) += lrng_jent.o +obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o diff --git a/drivers/char/lrng/lrng_health.c b/drivers/char/lrng/lrng_health.c new file mode 100644 index 000000000000..4aeca29d0b87 --- /dev/null +++ b/drivers/char/lrng/lrng_health.c @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * Linux Random Number Generator (LRNG) Health Testing + * + * Copyright (C) 2019 - 2020, Stephan Mueller + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include + +#include "lrng_internal.h" + +/* Stuck Test */ +struct lrng_stuck_test { + u32 last_time; /* Stuck test: time of previous IRQ */ + u32 last_delta; /* Stuck test: delta of previous IRQ */ + u32 last_delta2; /* Stuck test: 2. time derivation of prev IRQ */ +}; + +/* Repetition Count Test */ +struct lrng_rct { + atomic_t rct_count; /* Number of stuck values */ +}; + +/* Adaptive Proportion Test */ +struct lrng_apt { + /* Data window size */ +#define LRNG_APT_WINDOW_SIZE 512 + /* LSB of time stamp to process */ +#define LRNG_APT_LSB 16 +#define LRNG_APT_WORD_MASK (LRNG_APT_LSB - 1) + atomic_t apt_count; /* APT counter */ + atomic_t apt_base; /* APT base reference */ + + atomic_t apt_trigger; + bool apt_base_set; /* Is APT base set? */ +}; + +/* The health test code must operate lock-less */ +struct lrng_health { + struct lrng_rct rct; + struct lrng_apt apt; + + bool health_test_enabled; + + /* SP800-90B startup health tests */ +#define LRNG_SP80090B_STARTUP_SAMPLES 1024 +#define LRNG_SP80090B_STARTUP_BLOCKS ((LRNG_SP80090B_STARTUP_SAMPLES + \ + LRNG_APT_WINDOW_SIZE - 1) / \ + LRNG_APT_WINDOW_SIZE) + bool sp80090b_startup_done; + atomic_t sp80090b_startup_blocks; +}; + +static struct lrng_health lrng_health = { + .rct.rct_count = ATOMIC_INIT(0), + + .apt.apt_count = ATOMIC_INIT(0), + .apt.apt_base = ATOMIC_INIT(-1), + .apt.apt_trigger = ATOMIC_INIT(LRNG_APT_WINDOW_SIZE), + .apt.apt_base_set = false, + + .health_test_enabled = true, + + .sp80090b_startup_blocks = ATOMIC_INIT(LRNG_SP80090B_STARTUP_BLOCKS), + .sp80090b_startup_done = false, +}; + +static DEFINE_PER_CPU(struct lrng_stuck_test, lrng_stuck_test); + +static inline bool lrng_sp80090b_health_requested(void) +{ + /* Health tests are only requested in FIPS mode */ + return fips_enabled; +} + +static inline bool lrng_sp80090b_health_enabled(void) +{ + struct lrng_health *health = &lrng_health; + + return lrng_sp80090b_health_requested() && health->health_test_enabled; +} + +/*************************************************************************** + * SP800-90B Compliance + * + * If the Linux-RNG is booted into FIPS mode, the following interfaces + * provide an SP800-90B compliant noise source: + * + * * /dev/random + * * getrandom(2) + * * get_random_bytes when using it in conjunction with + * add_random_ready_callback + * + * All other interfaces, including /dev/urandom or get_random_bytes without + * the add_random_ready_callback cannot claim to use an SP800-90B compliant + * noise source. + ***************************************************************************/ + +/* + * Perform SP800-90B startup testing + */ +static inline void lrng_sp80090b_startup(struct lrng_health *health) +{ + if (!health->sp80090b_startup_done && + atomic_dec_and_test(&health->sp80090b_startup_blocks)) { + health->sp80090b_startup_done = true; + pr_info("SP800-90B startup health tests completed\n"); + lrng_init_ops(0); + + /* + * Force a reseed of DRNGs to ensure they are seeded with + * entropy that passed the SP800-90B health tests. + * As the DRNG always will reseed before generating + * random numbers, it does not need a reseed trigger. + */ + lrng_drng_force_reseed(); + } +} + +/* + * Handle failure of SP800-90B startup testing + */ +static inline void lrng_sp80090b_startup_failure(struct lrng_health *health) +{ + /* Reset of LRNG and its entropy - NOTE: we are in atomic context */ + lrng_reset(); + + /* + * Reset the SP800-90B startup test. + * + * NOTE SP800-90B section 4.3 bullet 4 does not specify what + * exactly is to be done in case of failure! Thus, we do what + * makes sense, i.e. restarting the health test and thus gating + * the output function of /dev/random and getrandom(2). + */ + atomic_set(&health->sp80090b_startup_blocks, + LRNG_SP80090B_STARTUP_BLOCKS); +} + +/* + * Handle failure of SP800-90B runtime testing + */ +static inline void lrng_sp80090b_runtime_failure(struct lrng_health *health) +{ + lrng_sp80090b_startup_failure(health); + health->sp80090b_startup_done = false; +} + +static inline void lrng_sp80090b_failure(struct lrng_health *health) +{ + if (health->sp80090b_startup_done) { + pr_err("SP800-90B runtime health test failure - invalidating " + "all existing entropy and initiate SP800-90B startup\n"); + lrng_sp80090b_runtime_failure(health); + } else { + pr_err("SP800-90B startup test failure - resetting\n"); + lrng_sp80090b_startup_failure(health); + } +} + +/* + * Is the SP800-90B startup testing complete? + * + * This function is called by the LRNG to determine whether to unblock + * a certain user interface. Therefore, only the potentially blocking + * user interfaces are considered SP800-90B compliant. + */ +bool lrng_sp80090b_startup_complete(void) +{ + struct lrng_health *health = &lrng_health; + + return (lrng_sp80090b_health_enabled()) ? health->sp80090b_startup_done: + true; +} + +bool lrng_sp80090b_compliant(void) +{ + struct lrng_health *health = &lrng_health; + + return lrng_sp80090b_health_enabled() && health->sp80090b_startup_done; +} + +/*************************************************************************** + * Adaptive Proportion Test + * + * This test complies with SP800-90B section 4.4.2. + ***************************************************************************/ + +/* + * Reset the APT counter + * + * @health [in] Reference to health state + */ +static inline void lrng_apt_reset(struct lrng_health *health, + unsigned int time_masked) +{ + struct lrng_apt *apt = &health->apt; + + pr_debug("APT value %d for base %d\n", + atomic_read(&apt->apt_count), atomic_read(&apt->apt_base)); + + /* Reset APT */ + atomic_set(&apt->apt_count, 0); + atomic_set(&apt->apt_base, time_masked); +} + +static inline void lrng_apt_restart(struct lrng_health *health) +{ + struct lrng_apt *apt = &health->apt; + + atomic_set(&apt->apt_trigger, LRNG_APT_WINDOW_SIZE); +} + +/* + * Insert a new entropy event into APT + * + * This function does is void as it does not decide about the fate of a time + * stamp. An APT failure can only happen at the same time of a stuck test + * failure. Thus, the stuck failure will already decide how the time stamp + * is handled. + * + * @health [in] Reference to health state + * @now_time [in] Time stamp to process + */ +static inline void lrng_apt_insert(struct lrng_health *health, + unsigned int now_time) +{ + struct lrng_apt *apt = &health->apt; + + if (!lrng_sp80090b_health_requested()) + return; + + now_time &= LRNG_APT_WORD_MASK; + + /* Initialization of APT */ + if (!apt->apt_base_set) { + atomic_set(&apt->apt_base, now_time); + apt->apt_base_set = true; + return; + } + + if (now_time == (unsigned int)atomic_read(&apt->apt_base)) { + u32 apt_val = (u32)atomic_inc_return_relaxed(&apt->apt_count); + + if (apt_val >= CONFIG_LRNG_APT_CUTOFF) + lrng_sp80090b_failure(health); + } + + if (atomic_dec_and_test(&apt->apt_trigger)) { + lrng_apt_restart(health); + lrng_apt_reset(health, now_time); + lrng_sp80090b_startup(health); + } +} + +/*************************************************************************** + * Repetition Count Test + * + * The LRNG uses an enhanced version of the Repetition Count Test + * (RCT) specified in SP800-90B section 4.4.1. Instead of counting identical + * back-to-back values, the input to the RCT is the counting of the stuck + * values while filling the entropy pool. + * + * The RCT is applied with an alpha of 2^-30 compliant to FIPS 140-2 IG 9.8. + * + * During the counting operation, the LRNG always calculates the RCT + * cut-off value of C. If that value exceeds the allowed cut-off value, + * the LRNG will invalidate all entropy for the entropy pool which implies + * that no data can be extracted from the entropy pool unless new entropy + * is received. + ***************************************************************************/ + +/* + * Hot code path - Insert data for Repetition Count Test + * + * @health: Reference to health information + * @stuck: Decision of stuck test + */ +static inline void lrng_rct(struct lrng_health *health, int stuck) +{ + struct lrng_rct *rct = &health->rct; + + if (!lrng_sp80090b_health_requested()) + return; + + if (stuck) { + u32 rct_count = atomic_add_return_relaxed(1, &rct->rct_count); + + pr_debug("RCT count: %u\n", rct_count); + + /* + * The cutoff value is based on the following consideration: + * alpha = 2^-30 as recommended in FIPS 140-2 IG 9.8. + * In addition, we imply an entropy value H of 1 bit as this + * is the minimum entropy required to provide full entropy. + * + * Note, rct_count (which equals to value B in the + * pseudo code of SP800-90B section 4.4.1) starts with zero. + * Hence we need to subtract one from the cutoff value as + * calculated following SP800-90B. + */ + if (rct_count >= CONFIG_LRNG_RCT_CUTOFF) { + atomic_set(&rct->rct_count, 0); + + /* + * APT must start anew as we consider all previously + * recorded data to contain no entropy. + */ + lrng_apt_restart(health); + + lrng_sp80090b_failure(health); + } + } else { + atomic_set(&rct->rct_count, 0); + } +} + +/*************************************************************************** + * Stuck Test + * + * Checking the: + * 1st derivative of the event occurrence (time delta) + * 2nd derivative of the event occurrence (delta of time deltas) + * 3rd derivative of the event occurrence (delta of delta of time deltas) + * + * All values must always be non-zero. The stuck test is only valid disabled if + * high-resolution time stamps are identified after initialization. + ***************************************************************************/ + +static inline u32 lrng_delta(u32 prev, u32 next) +{ + /* + * Note that this (unsigned) subtraction does yield the correct value + * in the wraparound-case, i.e. when next < prev. + */ + return (next - prev); +} + +/* + * Hot code path + * + * @health: Reference to health information + * @now: Event time + * @return: 0 event occurrence not stuck (good time stamp) + * != 0 event occurrence stuck (reject time stamp) + */ +static inline int lrng_irq_stuck(struct lrng_stuck_test *stuck, u32 now_time) +{ + u32 delta = lrng_delta(stuck->last_time, now_time); + u32 delta2 = lrng_delta(stuck->last_delta, delta); + u32 delta3 = lrng_delta(stuck->last_delta2, delta2); + + stuck->last_time = now_time; + stuck->last_delta = delta; + stuck->last_delta2 = delta2; + + if (!delta || !delta2 || !delta3) + return 1; + + return 0; +} + +/*************************************************************************** + * Health test interfaces + ***************************************************************************/ + +/* + * Disable all health tests + */ +void lrng_health_disable(void) +{ + struct lrng_health *health = &lrng_health; + + health->health_test_enabled = false; + + if (lrng_sp80090b_health_requested()) + pr_warn("SP800-90B compliance requested but the Linux RNG is " + "NOT SP800-90B compliant\n"); +} + +/* + * Hot code path - Perform health test on time stamp received from an event + * + * @now_time Time stap + */ +enum lrng_health_res lrng_health_test(u32 now_time) +{ + struct lrng_health *health = &lrng_health; + struct lrng_stuck_test *stuck_test = this_cpu_ptr(&lrng_stuck_test); + int stuck; + + if (!health->health_test_enabled) + return lrng_health_pass; + + lrng_apt_insert(health, now_time); + + stuck = lrng_irq_stuck(stuck_test, now_time); + lrng_rct(health, stuck); + if (stuck) { + /* SP800-90B disallows using a failing health test time stamp */ + return lrng_sp80090b_health_requested() ? + lrng_health_fail_drop : lrng_health_fail_use; + } + + return lrng_health_pass; +} From patchwork Wed Jan 15 10:36:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 198230 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.6 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8E9C4C33CB6 for ; Wed, 15 Jan 2020 10:39:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 507A9222C3 for ; Wed, 15 Jan 2020 10:39:35 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=chronox.de header.i=@chronox.de header.b="GGjIb5kk" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729880AbgAOKje (ORCPT ); Wed, 15 Jan 2020 05:39:34 -0500 Received: from mo4-p02-ob.smtp.rzone.de ([85.215.255.83]:12188 "EHLO mo4-p02-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729855AbgAOKje (ORCPT ); Wed, 15 Jan 2020 05:39:34 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1579084766; 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=PGF+aSGBgyOTOkOJuXwcr4oKXZNjFUkRg22zzKcVwbY=; b=GGjIb5kkNEO67FaUaFSM4ylqAwansVzWg5TH+V2m8KCIM2jO5GPZfuBxssIgzrd5Pi TD7JY3ypNKOOr6qdbrwQmMOf1zVD6wPeWCsnsYeEAcDE195iLKwvRH34AdEqwwWUvIKT DUZY4E4hOnU7x5jdx7VNv0a/v/yETSNR7Ha15RQ1EHaFxRuYA9AB5dWXutl3dFljMlw2 M2wqhq6NvfsCQ5crNYekqNysP6akSOY26wqPBMmfx+VJqX/l/eIn2EFLSaIHkHRh98Ch 9FGIHpF36plEHlDxW7S8CEpSkl3pilqGNZ2hDtCBrxSioVJ83z7VADX1XzefQDuQ+Q2k uTxA== X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPZJPScHivh" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 46.1.4 DYNA|AUTH) with ESMTPSA id u04585w0FAbwVzw (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Wed, 15 Jan 2020 11:37:58 +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 , Julia Lawall , Dan Carpenter Subject: [PATCH v28 12/12] LRNG - add power-on and runtime self-tests Date: Wed, 15 Jan 2020 11:36:23 +0100 Message-ID: <14680840.Vbse3Ty9G8@positron.chronox.de> In-Reply-To: <5951792.lmNsirYsPE@positron.chronox.de> References: <6157374.ptSnyUpaCn@positron.chronox.de> <2641155.iNH938UiKq@positron.chronox.de> <5951792.lmNsirYsPE@positron.chronox.de> MIME-Version: 1.0 Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org Parts of the LFSR are already covered by self-tests, including: * Self-test of SP800-90A DRBG provided by the Linux kernel crypto API. * Self-test of the PRNG provided by the Linux kernel crypto API. * Raw noise source data testing including SP800-90B compliant tests when enabling CONFIG_LRNG_HEALTH_TESTS This patch adds the self-tests for the remaining critical functions of the LRNG that are essential to maintain entropy and provide cryptographic strong random numbers. The following self-tests are implemented: * Self-test of the time array maintenance. This test verifies whether the time stamp array management to store multiple values in one integer implements a concatenation of the data. * Self-test of the LFSR operation. This test injects a monotonic increasing counter into the LFSR. After completion of the injection of the counter, 3 pool words are compared with known good values. The known good values are calculated with the newly-developed tool lfsr_testvector_generation provided as part of the LRNG test tool set at [1]. * Self-test of the Hash_DF operation ensures that this function operates compliant to the specification. The self-test performs a Hash_DF operation of a zeroized entropy pool state. The test vectors are generated using the newly-developed tool hash_df_testvector_generation provided as part of the LRNG test tool set at [1]. * Self-test of the ChaCha20 DRNG is based on the self-tests that are already present and implemented with the stand-alone user space ChaCha20 DRNG implementation available at [2]. The self-tests cover different use cases of the DRNG seeded with known seed data. The status of the LRNG self-tests is provided with the selftest_status SysFS file. If the file contains a zero, the self-tests passed. The value 0xffffffff means that the self-tests were not executed. Any other value indicates a self-test failure. The self-test may be compiled to panic the system if the self-test fails. All self-tests operate on private state data structures. This implies that none of the self-tests have any impact on the regular LRNG operations. This allows the self-tests to be repeated at runtime by writing anything into the selftest_status SysFS file. [1] https://www.chronox.de/lrng.html [2] https://www.chronox.de/chacha20.html 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 CC: Marcelo Henrique Cerri CC: Neil Horman Signed-off-by: Stephan Mueller --- drivers/char/lrng/Kconfig | 25 ++ drivers/char/lrng/Makefile | 1 + drivers/char/lrng/lrng_selftest.c | 418 ++++++++++++++++++++++++++++++ 3 files changed, 444 insertions(+) create mode 100644 drivers/char/lrng/lrng_selftest.c diff --git a/drivers/char/lrng/Kconfig b/drivers/char/lrng/Kconfig index e503a4bb7475..0c9ad9563fb7 100644 --- a/drivers/char/lrng/Kconfig +++ b/drivers/char/lrng/Kconfig @@ -175,4 +175,29 @@ config LRNG_TESTING If unsure, say N. +config LRNG_SELFTEST + bool "Enable power-on and on-demand self-tests" + help + The power-on self-tests are executed during boot time + covering the ChaCha20 DRNG, the LFSR processing and the + time stamp management of the LRNG. + + The on-demand self-tests are triggered by writing any + value into the SysFS file selftest_status. At the same + time, when reading this file, the test status is + returned. A zero indicates that all tests were executed + successfully. + + If unsure, say Y. + +if LRNG_SELFTEST + +config LRNG_SELFTEST_PANIC + bool "Panic the kernel upon self-test failure" + help + If the option is enabled, the kernel is terminated if an + LRNG power-on self-test failure is detected. + +endif # LRNG_SELFTEST + endif # LRNG diff --git a/drivers/char/lrng/Makefile b/drivers/char/lrng/Makefile index b2ce1979dc4b..92219c565f66 100644 --- a/drivers/char/lrng/Makefile +++ b/drivers/char/lrng/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_LRNG_KCAPI) += lrng_kcapi.o obj-$(CONFIG_LRNG_JENT) += lrng_jent.o obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o obj-$(CONFIG_LRNG_TESTING) += lrng_testing.o +obj-$(CONFIG_LRNG_SELFTEST) += lrng_selftest.o diff --git a/drivers/char/lrng/lrng_selftest.c b/drivers/char/lrng/lrng_selftest.c new file mode 100644 index 000000000000..da213572e1dd --- /dev/null +++ b/drivers/char/lrng/lrng_selftest.c @@ -0,0 +1,418 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * LRNG power-on and on-demand self-test + * + * Copyright (C) 2016 - 2020, Stephan Mueller + */ + +/* + * In addition to the self-tests below, the following LRNG components + * are covered with self-tests during regular operation: + * + * * power-on self-test: SP800-90A DRBG provided by the Linux kernel crypto API + * * power-on self-test: PRNG provided by the Linux kernel crypto API + * * runtime test: Raw noise source data testing including SP800-90B compliant + * tests when enabling CONFIG_LRNG_HEALTH_TESTS + * + * Additional developer tests present with LRNG code: + * * SP800-90B APT and RCT test enforcement validation when enabling + * CONFIG_LRNG_APT_BROKEN or CONFIG_LRNG_RCT_BROKEN. + * * Collection of raw entropy from the interrupt noise source when enabling + * CONFIG_LRNG_TESTING and pulling the data from the kernel with the provided + * interface. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include + +#include "lrng_chacha20.h" +#include "lrng_internal.h" +#include "lrng_lfsr.h" +#include "lrng_sw_noise.h" + +#define LRNG_SELFTEST_PASSED 0 +#define LRNG_SEFLTEST_ERROR_TIME (1 << 0) +#define LRNG_SEFLTEST_ERROR_LFSR (1 << 1) +#define LRNG_SEFLTEST_ERROR_CHACHA20 (1 << 2) +#define LRNG_SEFLTEST_ERROR_HASHDF (1 << 3) +#define LRNG_SELFTEST_NOT_EXECUTED 0xffffffff + +static u32 lrng_time_selftest[LRNG_TIME_ARRAY_SIZE]; + +static unsigned int lrng_selftest_status = LRNG_SELFTEST_NOT_EXECUTED; + +static inline void lrng_time_process_selftest_insert(u32 time) +{ + static u32 lrng_time_selftest_ptr = 0; + u32 ptr = lrng_time_selftest_ptr++ & LRNG_TIME_WORD_MASK; + + lrng_time_selftest[lrng_time_idx2array(ptr)] |= + lrng_time_slot_val(time & LRNG_TIME_SLOTSIZE_MASK, + lrng_time_idx2slot(ptr)); +} + +static unsigned int lrng_time_process_selftest(void) +{ + u32 time; + u32 idx_zero_compare = (0 << 0) | (1 << 8) | (2 << 16) | (3 << 24); + u32 idx_one_compare = (4 << 0) | (5 << 8) | (6 << 16) | (7 << 24); + u32 idx_last_compare = ((LRNG_TIME_NUM_VALUES - 4) << 0) | + ((LRNG_TIME_NUM_VALUES - 3) << 8) | + ((LRNG_TIME_NUM_VALUES - 2) << 16) | + ((LRNG_TIME_NUM_VALUES - 1) << 24); + + (void)idx_one_compare; + + for (time = 0; time < LRNG_TIME_NUM_VALUES; time++) + lrng_time_process_selftest_insert(time); + + if ((lrng_time_selftest[0] != idx_zero_compare) || +#if (LRNG_TIME_ARRAY_SIZE > 1) + (lrng_time_selftest[1] != idx_one_compare) || +#endif + (lrng_time_selftest[LRNG_TIME_ARRAY_SIZE - 1] != idx_last_compare)) + { + pr_err("LRNG time array self-test FAILED\n"); + return LRNG_SEFLTEST_ERROR_TIME; + } + + return LRNG_SELFTEST_PASSED; +} + +/* + * The test vectors are generated with the lfsr_testvector_generation tool + * provided as part of the test tool set of the LRNG. + */ +static unsigned int lrng_pool_lfsr_selftest(void) +{ + /* + * First, 67th and last entry of entropy pool. + * + * The 67th entry is picked because this one is the first to receive + * an entry. As we start with 1 to inject into the LFSR, the + * 67th entry should be equal to rol(1, 7) >> 3 considering that + * all other values of the LFSR are zero and the the twist value of 0 + * is applied. + */ + static u32 const lrng_lfsr_selftest_result[][3] = { + { 0xf56df24a, 0x00000010, 0x0e014939 }, + { 0x4b130726, 0x00000010, 0x2802f509 }, + { 0x87279152, 0x00000010, 0x00150000 }, + { 0x0b67f997, 0x00000010, 0x00150000 }, + { 0x4fea174f, 0x00000010, 0xcbf4a6ae }, + { 0x77149108, 0x00000010, 0x77bfadf2 }, + { 0x1e96037e, 0x00000010, 0x18017e79 }, + { 0xc84acef2, 0x00000010, 0x6345f7a8 }, + { 0x6a2eb6df, 0x00000010, 0x03950000 }, + }; + struct lrng_pool *lrng_pool, *lrng_pool_aligned; + u32 i, ret = LRNG_SELFTEST_PASSED; + + BUILD_BUG_ON(ARRAY_SIZE(lrng_lfsr_selftest_result) < + CONFIG_LRNG_POOL_SIZE); + + lrng_pool = kzalloc(sizeof(struct lrng_pool) + LRNG_KCAPI_ALIGN, + GFP_KERNEL); + if (!lrng_pool) + return LRNG_SEFLTEST_ERROR_LFSR; + lrng_pool_aligned = PTR_ALIGN(lrng_pool, sizeof(u32)); + + for (i = 1; i <= LRNG_POOL_SIZE; i++) + _lrng_pool_lfsr_u32(lrng_pool_aligned, i); + + if ((atomic_read_u32(&lrng_pool_aligned->pool[0]) != + lrng_lfsr_selftest_result[CONFIG_LRNG_POOL_SIZE][0]) || + (atomic_read_u32(&lrng_pool_aligned->pool[67 & + (LRNG_POOL_SIZE - 1)]) != + lrng_lfsr_selftest_result[CONFIG_LRNG_POOL_SIZE][1]) || + (atomic_read_u32(&lrng_pool_aligned->pool[LRNG_POOL_SIZE - 1]) != + lrng_lfsr_selftest_result[CONFIG_LRNG_POOL_SIZE][2])) { + pr_err("LRNG LFSR self-test FAILED\n"); + ret = LRNG_SEFLTEST_ERROR_LFSR; + } + + kfree(lrng_pool); + return ret; +} + +/* + * The test vectors are generated with the hash_df_testvector_generation tool + * provided as part of the test tool set of the LRNG. + */ +static unsigned int lrng_hash_df_selftest(void) +{ + const struct lrng_crypto_cb *crypto_cb = &lrng_cc20_crypto_cb; + + /* + * The size of 45 bytes is chosen arbitrarily. Yet, this size should + * ensure that we have at least two hash blocks plus some fraction + * of a hash block generated. + */ + static u8 const lrng_hash_df_selftest_result[][45] = { + { + 0x3b, 0xbe, 0x7a, 0xbd, 0x2b, 0x16, 0x02, 0x4c, + 0xfc, 0xd3, 0x02, 0x15, 0xf0, 0x86, 0xd4, 0xdb, + 0x49, 0xec, 0x26, 0x53, 0xd6, 0xc9, 0x6d, 0xad, + 0x24, 0xca, 0x72, 0x89, 0x2c, 0xfa, 0x48, 0x18, + 0xf7, 0x47, 0xb5, 0x2f, 0x92, 0xa2, 0x1b, 0xd9, + 0x24, 0xa7, 0x2f, 0xa2, 0x0b, + }, { + 0xd2, 0xaa, 0xf9, 0x76, 0x26, 0xc6, 0x13, 0xea, + 0xb8, 0xde, 0xe6, 0x88, 0x8f, 0xc4, 0x7a, 0x7d, + 0x9c, 0xb4, 0x1b, 0xd1, 0xd1, 0x8a, 0x40, 0xc9, + 0xaa, 0x45, 0xa6, 0xb6, 0xb5, 0x6f, 0xf6, 0xbc, + 0xbb, 0x77, 0x37, 0xbc, 0x5a, 0x2d, 0xcc, 0x84, + 0x25, 0x68, 0x5e, 0xba, 0x16, + }, { + 0x58, 0x66, 0x82, 0x88, 0x29, 0x19, 0xa4, 0xbb, + 0x33, 0x42, 0xc9, 0x72, 0x0d, 0x68, 0x6e, 0xb9, + 0xc6, 0xe0, 0x7a, 0xf9, 0x20, 0xca, 0x6d, 0x18, + 0x35, 0xec, 0xfa, 0x9e, 0xf6, 0x3a, 0xa7, 0xb6, + 0x92, 0x7a, 0xe5, 0xcd, 0xc5, 0x13, 0x9f, 0x65, + 0x6a, 0xe1, 0xe4, 0x3f, 0xb9, + }, { + 0xdd, 0xf1, 0x34, 0xca, 0x08, 0xe3, 0xce, 0x8a, + 0x26, 0x6b, 0xce, 0x99, 0x8a, 0x84, 0xd2, 0x21, + 0x98, 0x10, 0x95, 0x5f, 0x9f, 0xc3, 0xf2, 0xe4, + 0x79, 0x75, 0xb5, 0x15, 0xa7, 0xa2, 0xf1, 0xc4, + 0xdc, 0x67, 0xcb, 0x67, 0x8c, 0xb2, 0x1b, 0xd5, + 0xd6, 0x8b, 0xc2, 0x34, 0xd6, + }, { + 0xc3, 0x16, 0x9d, 0xf0, 0x78, 0x15, 0xab, 0xf2, + 0x2f, 0xc9, 0x2e, 0xe1, 0xc6, 0x5e, 0xfa, 0x03, + 0xaf, 0xd4, 0xd5, 0x47, 0x2a, 0xe8, 0x06, 0xe8, + 0x7e, 0x0a, 0x71, 0xc7, 0x0d, 0x39, 0xb1, 0xa9, + 0x5a, 0x49, 0xee, 0x8b, 0x2f, 0xcd, 0xea, 0x96, + 0xcc, 0x08, 0x71, 0xef, 0x9c, + }, { + 0x1a, 0x3d, 0x70, 0x39, 0xc2, 0x02, 0x4d, 0x3a, + 0xaa, 0x14, 0x20, 0x88, 0x96, 0x4c, 0x7c, 0xe4, + 0xaa, 0x49, 0x89, 0x30, 0x50, 0x96, 0xb6, 0xa7, + 0x55, 0x0a, 0xf8, 0xd2, 0x4e, 0x83, 0x9d, 0x1f, + 0x56, 0x49, 0x13, 0xc6, 0x46, 0x55, 0x73, 0x0d, + 0x74, 0xcd, 0x81, 0xe0, 0x65, + }, { + 0x4b, 0xf6, 0x49, 0x89, 0x2a, 0x9f, 0x67, 0xd7, + 0xb8, 0x1d, 0xbb, 0x5d, 0xf0, 0x1b, 0x60, 0xb6, + 0xb7, 0xf3, 0x86, 0x6d, 0xe0, 0x04, 0xa1, 0xbc, + 0x3b, 0xb0, 0x10, 0x91, 0xe8, 0x22, 0x67, 0x5b, + 0xe8, 0xf0, 0x4f, 0x82, 0x70, 0xc7, 0xe1, 0xc8, + 0xd8, 0xad, 0x70, 0xcf, 0xf6, + }, { + 0x60, 0x1f, 0x71, 0x07, 0x92, 0xae, 0xa0, 0x24, + 0xb6, 0xa4, 0x10, 0x70, 0x1f, 0x94, 0x51, 0x9a, + 0x5a, 0x81, 0xc4, 0x46, 0x78, 0x56, 0x71, 0xdd, + 0x45, 0x63, 0x01, 0x34, 0x87, 0x79, 0xb4, 0xd5, + 0x91, 0x79, 0xb9, 0x93, 0x11, 0x44, 0x50, 0xad, + 0x64, 0x7e, 0x5c, 0xec, 0x16, + }, { + 0x49, 0x2f, 0xa0, 0x45, 0xf8, 0xb0, 0x80, 0x88, + 0x79, 0xeb, 0xb6, 0x82, 0x1c, 0xf3, 0x67, 0xc4, + 0x88, 0x88, 0xe9, 0x75, 0x20, 0x54, 0x78, 0xc6, + 0x5c, 0x59, 0xcf, 0xd9, 0x73, 0x12, 0x17, 0xf4, + 0x30, 0x9c, 0xb7, 0x21, 0x45, 0xe2, 0xb6, 0x0c, + 0x0c, 0xeb, 0x1b, 0xdc, 0xdc, + } + }; + struct lrng_pool *lrng_pool, *lrng_pool_aligned; + u8 hash_df[sizeof(lrng_hash_df_selftest_result[0])] + __aligned(sizeof(u32)); + u32 generated; + int ret = 0; + + BUILD_BUG_ON(ARRAY_SIZE(lrng_hash_df_selftest_result) < + CONFIG_LRNG_POOL_SIZE); + + lrng_pool = kzalloc(sizeof(struct lrng_pool) + LRNG_KCAPI_ALIGN, + GFP_KERNEL); + if (!lrng_pool) + return LRNG_SEFLTEST_ERROR_HASHDF; + lrng_pool_aligned = PTR_ALIGN(lrng_pool, sizeof(u32)); + + generated = __lrng_pool_hash_df(crypto_cb, NULL, lrng_pool_aligned, + hash_df, sizeof(hash_df) << 3); + + if ((generated >> 3) != sizeof(hash_df) || + memcmp(hash_df, lrng_hash_df_selftest_result[CONFIG_LRNG_POOL_SIZE], + sizeof(hash_df))) { + pr_err("LRNG Hash DF self-test FAILED\n"); + ret = LRNG_SEFLTEST_ERROR_HASHDF; + } + + kfree(lrng_pool); + return ret; +} + +/* + * The test vectors were generated using the ChaCha20 DRNG from + * https://www.chronox.de/chacha20.html + */ +static unsigned int lrng_chacha20_drng_selftest(void) +{ + const struct lrng_crypto_cb *crypto_cb = &lrng_cc20_crypto_cb; + static u8 const seed[CHACHA_KEY_SIZE * 2] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }; + struct chacha20_block chacha20; + int ret; + u8 outbuf[CHACHA_KEY_SIZE * 2] __aligned(sizeof(u32)); + + /* + * Expected result when ChaCha20 DRNG state is zero: + * * constants are set to "expand 32-byte k" + * * remaining state is 0 + * and pulling one half ChaCha20 DRNG block. + */ + static u8 const expected_halfblock[CHACHA_KEY_SIZE] = { + 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, + 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28, + 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a, + 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7 }; + + /* + * Expected result when ChaCha20 DRNG state is zero: + * * constants are set to "expand 32-byte k" + * * remaining state is 0 + * followed by a reseed with two keyblocks + * 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + * 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + * 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + * 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + * 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + * 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + * 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + * 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f + * and pulling one ChaCha20 DRNG block. + */ + static u8 const expected_oneblock[CHACHA_KEY_SIZE * 2] = { + 0xf5, 0xb4, 0xb6, 0x5a, 0xec, 0xcd, 0x5a, 0x65, + 0x87, 0x56, 0xe3, 0x86, 0x51, 0x54, 0xfc, 0x90, + 0x56, 0xff, 0x5e, 0xae, 0x58, 0xf2, 0x01, 0x88, + 0xb1, 0x7e, 0xb8, 0x2e, 0x17, 0x9a, 0x27, 0xe6, + 0x86, 0xb3, 0xed, 0x33, 0xf7, 0xb9, 0x06, 0x05, + 0x8a, 0x2d, 0x1a, 0x93, 0xc9, 0x0b, 0x80, 0x04, + 0x03, 0xaa, 0x60, 0xaf, 0xd5, 0x36, 0x40, 0x11, + 0x67, 0x89, 0xb1, 0x66, 0xd5, 0x88, 0x62, 0x6d }; + + /* + * Expected result when ChaCha20 DRNG state is zero: + * * constants are set to "expand 32-byte k" + * * remaining state is 0 + * followed by a reseed with one key block plus one byte + * 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + * 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + * 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + * 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + * 0x20 + * and pulling less than one ChaCha20 DRNG block. + */ + static u8 const expected_block_nonalinged[CHACHA_KEY_SIZE + 1] = { + 0x3d, 0x13, 0x47, 0x1e, 0x7f, 0x7c, 0x99, 0x33, + 0xfc, 0x44, 0xa4, 0xdd, 0xf9, 0x3d, 0xe1, 0x9a, + 0xd4, 0xe8, 0x7a, 0x7d, 0x42, 0xac, 0xd1, 0xcd, + 0x10, 0x69, 0xe7, 0xbf, 0xd4, 0xfd, 0x69, 0x4b, + 0xa7 }; + + memset(&chacha20, 0, sizeof(chacha20)); + lrng_cc20_init_rfc7539(&chacha20); + + /* Generate with zero state */ + ret = crypto_cb->lrng_drng_generate_helper(&chacha20, outbuf, + sizeof(expected_halfblock)); + if (ret != sizeof(expected_halfblock)) + goto err; + if (memcmp(outbuf, expected_halfblock, sizeof(expected_halfblock))) + goto err; + + /* Clear state of DRNG */ + memset(&chacha20.key.u[0], 0, 48); + + /* Reseed with 2 key blocks */ + ret = crypto_cb->lrng_drng_seed_helper(&chacha20, seed, + sizeof(expected_oneblock)); + if (ret < 0) + goto err; + ret = crypto_cb->lrng_drng_generate_helper(&chacha20, outbuf, + sizeof(expected_oneblock)); + if (ret != sizeof(expected_oneblock)) + goto err; + if (memcmp(outbuf, expected_oneblock, sizeof(expected_oneblock))) + goto err; + + /* Clear state of DRNG */ + memset(&chacha20.key.u[0], 0, 48); + + /* Reseed with 1 key block and one byte */ + ret = crypto_cb->lrng_drng_seed_helper(&chacha20, seed, + sizeof(expected_block_nonalinged)); + if (ret < 0) + goto err; + ret = crypto_cb->lrng_drng_generate_helper(&chacha20, outbuf, + sizeof(expected_block_nonalinged)); + if (ret != sizeof(expected_block_nonalinged)) + goto err; + if (memcmp(outbuf, expected_block_nonalinged, + sizeof(expected_block_nonalinged))) + goto err; + + return LRNG_SELFTEST_PASSED; + +err: + pr_err("LRNG ChaCha20 DRNG self-test FAILED\n"); + return LRNG_SEFLTEST_ERROR_CHACHA20; +} + +static int lrng_selftest(void) +{ + unsigned int ret = lrng_time_process_selftest(); + + ret |= lrng_pool_lfsr_selftest(); + ret |= lrng_chacha20_drng_selftest(); + ret |= lrng_hash_df_selftest(); + + if (ret) { + if (IS_ENABLED(CONFIG_LRNG_SELFTEST_PANIC)) + panic("LRNG self-tests failed: %u\n", ret); + } else { + pr_info("LRNG self-tests passed\n"); + } + + lrng_selftest_status = ret; + + if (lrng_selftest_status) + return -EFAULT; + return 0; +} + +#ifdef CONFIG_SYSFS +/* Re-perform self-test when any value is written to the sysfs file. */ +static int lrng_selftest_sysfs_set(const char *val, + const struct kernel_param *kp) +{ + return lrng_selftest(); +} + +static const struct kernel_param_ops lrng_selftest_sysfs = { + .set = lrng_selftest_sysfs_set, + .get = param_get_uint, +}; +module_param_cb(selftest_status, &lrng_selftest_sysfs, &lrng_selftest_status, + 0644); +#endif /* CONFIG_SYSFS */ + +static int __init lrng_selftest_init(void) +{ + return lrng_selftest(); +} + +module_init(lrng_selftest_init);