Linux cryptographic layer development
 help / color / mirror / Atom feed
From: Eric Biggers <ebiggers@kernel.org>
To: linux-crypto@vger.kernel.org, Herbert Xu <herbert@gondor.apana.org.au>
Cc: "Stephan Müller" <smueller@chronox.de>,
	"Eric Biggers" <ebiggers@kernel.org>
Subject: [PATCH 07/14] crypto: drbg - Add self-test for library API
Date: Sun, 18 Oct 2026 13:46:11 -0700	[thread overview]
Message-ID: <20261018204618.104876-8-ebiggers@kernel.org> (raw)
In-Reply-To: <20261018204618.104876-1-ebiggers@kernel.org>

With the SP800-90A DRBG now being accessible through a library API, it
now needs to handle the self-test internally instead of relying on
"testmgr".  Implement it, using the existing test vectors.

Run the self-test at module_init time or on first call to
crypto_drbg_alloc(), whichever comes first, if either
CONFIG_CRYPTO_SELFTESTS is enabled or the kernel is booted with fips=1.
Also run the existing drbg_healthcheck_sanity() at the same time if
fips=1; previously that ran only at module_init time.  If fips=1 and
either test fails, the kernel panics, as required by FIPS module tests.

When fips=1, if the tests pass, "DRBG: self-tests passed" is printed to
the log.  This is for parity with testmgr.c which printed a similar
message.  If the tests fail, for now don't bother calling
fips_fail_notify() before panicking: most of the FIPS self-tests already
don't call it, and those notifications only go to one driver, so clearly
that notifier chain isn't a finished feature anyway.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 crypto/drbg-testvecs.h | 228 +++++++++++++++++++++++++++++++++++++++++
 crypto/drbg.c          | 123 +++++++++++++++++++---
 2 files changed, 338 insertions(+), 13 deletions(-)
 create mode 100644 crypto/drbg-testvecs.h

diff --git a/crypto/drbg-testvecs.h b/crypto/drbg-testvecs.h
new file mode 100644
index 0000000000000..d073257eb3d18
--- /dev/null
+++ b/crypto/drbg-testvecs.h
@@ -0,0 +1,228 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2026 Google LLC
+ */
+#ifndef _CRYPTO_DRBG_TESTVECS_H
+#define _CRYPTO_DRBG_TESTVECS_H
+
+#include <linux/types.h>
+
+struct drbg_testvec {
+	/* Instantiate */
+	const u8 *entropy;
+	size_t entropylen;
+	const u8 *pers;
+	size_t perslen;
+
+	/* Reseed (optional) */
+	const u8 *ent_reseed;
+	size_t ent_reseed_len;
+	const u8 *addtl_reseed;
+	size_t addtl_reseed_len;
+
+	/* Generate (twice) */
+	const u8 *addtla;
+	const u8 *addtlb;
+	size_t addtllen;
+
+	/* Expected output from last call to Generate */
+	const u8 *expected;
+	size_t expectedlen;
+};
+
+static const struct drbg_testvec drbg_testvecs[] = {
+	/*
+	 * Borrowed from the first applicable test vector from ACVP:
+	 * https://github.com/usnistgov/ACVP-Server/blob/v1.1.0.33/gen-val/json-files/hmacDRBG-1.0/prompt.json#L4596
+	 * https://github.com/usnistgov/ACVP-Server/blob/v1.1.0.33/gen-val/json-files/hmacDRBG-1.0/expectedResults.json#L986
+	 */
+	{
+		/* .entropy = ACVP entropyInput || nonce */
+		.entropy = "\x47\x28\x33\x05\x82\xE8\xA7\x58\x05\xBD\x07\x9E"
+			   "\xDB\x59\x87\x08\x3B\x82\x40\x70\xA1\xB7\x33\x4F"
+			   "\x0F\x53\xBE\xF6\x98\x75\xFA\x21\x00\x04\xBC\x58"
+			   "\x9B\xB1\xB3\xBC\x2A\xF6\xA4\x2A\xE1\xB3\x65\x24"
+			   "\xA8\xEE\x56\x70\x5E\x28\x06\x04\x80\xCE\xB7\x36"
+			   "\xA4\xD1\x4E\xAA\xE7\xE8\x51\x40\x7D\x30\xF7\x91"
+			   "\xF2\x9E\x98\xA7\xBB\xB3\x1D\xC6\x8A\x62\xC7\xE7"
+			   "\x1F\xE1\x0A\x52\x45\x39\x88\x92\x43\xA6\x5B\xC3"
+			   "\x9D\x60\xDE\xFE\x79\xEF\x87\x6F\xD5\x76\x51\x69"
+			   "\x7B\x4C\x3D\x08\x60\xFA\xDC\x00\x94\xEC\x0A\xC5"
+			   "\xE7\xCB\x30\x05\x9F\xCC\x07\x44\x07\x14\xF4\xF9"
+			   "\xBC\x7D\xC0\x66\x63\x5B\xD3\x2A\xA7\xF2\x1D\x75"
+			   "\x3F\x28\x5F\x4A\xEB\x63\xD7\x92\x5A\x9A\x7C\x3A"
+			   "\x56\xEA\xCB\xA9\xA0\xF9\x5B\x99\xC2\x7D\x31\xBF"
+			   "\x44\xC7\x64\x6B\x7E\x64\x60\x64\x05\x86\xF0\x6B"
+			   "\x76\xA7\x3E\x63\xAD\xB6\x76\xED\x3D\x05\x2E\xC7"
+			   "\xC7\x52\x8F\x07\x56\x23\xFC\x2F\x93\xD5\xF2\x29"
+			   "\xC6\x84\x48\xD1\x88\xB9\x3F\x84\xB2\x93\xFC\x2F"
+			   "\x00\xB1\xBC\xBE\xAC\xC4\x94\x36\xF1\x2B\xF0\xC7"
+			   "\x36\xE8\x1D\x45\x0A\xA2\xFE\x72\xD7\x3E\x15\x6A"
+			   "\x74\x23\xB2\xD1\x3C\x20\xF2\xB7\x19\xC5\xF0\x74"
+			   "\x69\x06\xD1\x92\x47\xC9\x68\xDC\xEE\xBC\xF4\x3A"
+			   "\x8B\x7C\xA4\xA4\x4A\x15\xF4\xF0\x26\x26\xC5\x7D"
+			   "\x57\xDC\x00\x59\x07\xDF\x84\x2A\x23\xA9\xC1\xAF"
+			   "\x47\x49\x88\xCC\x2F\x3B\x90\x39\xA0\x09\xAE\x3C"
+			   "\x79\xF9\x97\x9D\xEF\x13\x1D\x2B\xB6\x18\xDB\xCF"
+			   "\x95\x98\x17\x7F\xF6\x95\x44\x3A\x40\x90\x63\x16"
+			   "\x70\x38\x22\xC5\xD8\xE4\x57\xA0\x8E\x51\x6B\xED"
+			   "\x03\x18\xC6\x74\xFA\xCA\xF2\xD5\xB2\x5A\x0C\x02"
+			   "\x48\x9F\x70\x0B\x1C\x0A\xD1\xD6\x4F\x3F\x70\x3C"
+			   "\x1A\x62\x29\x63\xD0\x92\x76\x30\x7C\xB9\x54\xEC"
+			   "\xF6\x92\xA3\x11\x66\xB2\x56\xE0\x75\x3D\x27\x01",
+		.entropylen = 384,
+		.pers = "\x03\x75\x33\x7B\x6B\xE5\x14\xAF\x0E\x43\x33\xCC\xD3"
+			"\xF4\xF0\x8B\x8A\xCC\xFE\x95\xC1\x20\xB9\x56\x3D\x2C"
+			"\x34\xC7\xA1\x4C\xBC\xDC\x0A\x8D\xBE\x68\x28\x89\x2A"
+			"\x92\x10\x05\x4E\xF9\xE2\x51\xF7\x4F\xF4\x48\x76\xC9"
+			"\xCE\xA8\x6D\xC1\xDE\x5C\x05\x95\x77\x24\xB4\x5D\x3D"
+			"\x16\x1D\xCB\x43\xE5\xD3\x01\x96\xCC\x3E\x2E\xE1\x97"
+			"\xB3\x42\xC2\xAB\xEC\x56\xA9\xF9\xF2\x28\x59\x01\x4E"
+			"\xFC\x8A\xC0\x5E\x4E\x33\x30\x91\x96\x93\xBA\xFA\xE1"
+			"\x9F\x20\xC3\xC1\xD1\xC6\xC3\x2C\x59\x8F\x56\xD5\x73"
+			"\xE8\x8D\xCF\xAC\xB1\x85\x3E\xC7\x73\x21\x59\x8D\x0F"
+			"\xF4\xA4\xC4\x0C\xD2\x18\x81\x5F\x3E\x37\xC9\x9F\xD9"
+			"\xDE\x3F\x15\x6F\xAC\x1A\xEC\x5E\x28\xD5\x56\xA2\x65"
+			"\xD2\x7C\x41\xDE\x57\x8C\x60\xAB\xA5\x03\x42\xC8\x3C"
+			"\x70\xC2\xD1\x11\x62\x25\x4E\x17\x58\xBB\x08\x51\x79"
+			"\xE6\xED\xBA\x9A\xA7\x07\xD5\x0E\x89\x43\x31\x4F\x99"
+			"\xEE\xED\xF1\x36\xFA\x1E\xC0\x25\x01\xDA\x19\xC2\x7D"
+			"\x5D\x78\x74\x5C\xC0\x72\x2E\xF1\x7B\x4E\x9C\xDB\xFE"
+			"\x60\x89\x62\x71\x9C\xEA\xD3\xDF\x82\xC7\x8B\xB4\x7B"
+			"\x7B\x7F\x6A\x62\x3C\x57\x76\xA5\x67\x5F\x70\xFB\xE0"
+			"\x1B\x23\x79\x71\xB5\x7C\xEA\x76\x99",
+		.perslen = 256,
+
+		.ent_reseed = "\xE0\x5B\x69\xC5\xF9\xD4\x5A\x1F\xC1\x71\x0C"
+			      "\x37\x6F\xFE\x31\xE0\xEF\x3E\x9B\xD5\x46\x43"
+			      "\xA2\x15\xFA\x86\x75\x1C\x95\x9F\xE6\xD6\x41"
+			      "\x50\x36\x0F\x67\x68\x4A\x72\x32\x85\xB0\xCB"
+			      "\xA4\x0D\x1F\xA2\x43\xCA\x30\xF1\x42\xF8\xC4"
+			      "\x17\x6A\xD1\x2D\x43\x46\x8C\xA5\x72\x3C\xB1"
+			      "\x44\x8E\xA1\x75\xAA\x20\x30\xDD\xCD\x0B\x5A"
+			      "\x0D\xE6\x28\xCA\xBC\xA9\x3B\x11\x23\x88\x85"
+			      "\xDF\xD8\x84\x11\x89\x7A\x4F\x00\x90\x0B\xD8"
+			      "\x8A\x35\xE9\x5F\xEC\x05\x42\x15\xCA\x7E\xA3"
+			      "\xEF\xEF\xE3\xB7\xBE\x96\x8C\x36\x7D\x15\x3C"
+			      "\x7A\x78\x00\x61\xAF\x62\x45\xA7\x4B\xAE\x4A"
+			      "\xFD\xC9\xE0\x89\x53\x36\x71\x8F\x38\xC4\x00"
+			      "\x57\xD9\xE6\xC1\xEC\xBF\xF7\x4B\x3F\x55\xD6"
+			      "\x54\x15\x72\xB2\x23\x76\xD1\x4E\x8E\x7E\xFB"
+			      "\xC8\xD6\xA4\xA4\x7E\x8E\xD8\x76\xD3\xEB\x90"
+			      "\x90\xEB\xB3\x84\x26\x34\x93\x36\xCA\xA9\x12"
+			      "\xD3\x6D\x84\x07\xE1\x0E\xE7\x63\x24\x54\x90"
+			      "\x42\x8C\x6B\xE7\x21\x53\x2D\x16\xE9\x68\xA9"
+			      "\xC2\x9A\x7A\x93\x31\x5E\x35\x72\xE2\x0F\x3D"
+			      "\x55\x41\x8C\xC5\xD1\xBB\xEE\x5F\x3C\x95\x52"
+			      "\x2A\x65\x47\xB6\x84\x6A\x05\x19\xD9\xE7\x68"
+			      "\x15\xFA\x49\xD9\x9D\xFD\x47\x9F\xB9\xA6\xBB"
+			      "\xA8\xD4\x22\x6C\x8B\x59\x47\xEF\xD1\xD0\xBF"
+			      "\xBC\xE4\x53\x31\x2F\xA5\xD4\x2C\x89\xCA\xE5"
+			      "\x29\x64\xF8\x51\x2A\x02\xDE\x31\x0D\x54\x0E"
+			      "\x0E\xB8\x78\xE6\x2A\x3E\x31\xA2\xA4\xCD\x91"
+			      "\x79\xF2\x9B\x04\xA0\xDB\x78\xAC\x0D\xB5\xCA"
+			      "\x60\x4C\x08\x96\xCA\x8A\xE9\x93\x9F\x62\x38"
+			      "\xAE",
+		.ent_reseed_len = 320,
+		.addtl_reseed = "\xD5\x46\x71\x38\x46\xE0\xC1\x27\x2C\xF1\x07"
+				"\xDD\x29\x73\xD7\xF4\x5A\x3A\xE0\x99\x98\x0A"
+				"\xEB\xA5\x9E\x2E\x49\x21\x7B\x18\xC0\xD8\x3D"
+				"\xEE\x49\xF9\x52\x7C\x55\x5E\x5E\x06\xC2\x7E"
+				"\x34\x3A\xA5\xB7\x78\x21\xC1\xB8\x8B\x4E\x07"
+				"\x1F\x3F\xC4\xB4\x9B\x3F\x20\x2D\xEE\x70\x3B"
+				"\x18\xCF\x2B\x50\x15\x1B\xF3\x6C\xE7\x9F\x2A"
+				"\x2B\x69\x53\xCA\x88\x41\xA9\x07\x31\x14\x55"
+				"\xBD\x75\x49\x68\x98\x48\xCA\x46\xA5\xEC\xAA"
+				"\x9D\x8E\x6F\x40\xBA\xCA\xC8\xE9\x9F\xA4\xC5"
+				"\x94\x89\x2C\x4D\xE4\x0A\x66\xD3\xDB\x1A\xD9"
+				"\xA7\x3F\x6B\x0A\xE0\xE4\xDC\x0B\x8B\x64\xBF"
+				"\xB4\x95\xA1\xAE\x92\xA8\x7C\xE2\x4B\xED\xFD"
+				"\xFD\xE0\x54\x48\x7C\x25\xD6\xD1\x0A\xAB\x5E"
+				"\x33\x2F\x1D\xD3\x62\x47\xAB\x35\x8C\xA1\xC2"
+				"\x75\xDD\x75\xCA\x09\xE1\x38\xDE\x87\x79\x0C"
+				"\xD7\x5D\x3E\x6D\x28\x8F\x12\x98\x2C\x26\x34"
+				"\x91\x0B\x6B\xB7\x73",
+		.addtl_reseed_len = 192,
+
+		.addtla = "\xC8\xE1\x03\x59\xEA\x9F\xD3\x1F\xCC\xCB\x5A\x3E"
+			  "\x23\xDB\x47\x75\x1B\x3A\x6C\x0B\xED\xE6\xC0\xB6"
+			  "\x4B\x82\x53\x5B\x6D\xEE\x2B\x97\x0F\x59\x07\xA4"
+			  "\xFE\xE2\x26\x4F\xFF\xF7\x46\xAF\x62\xC4\x42\xE8"
+			  "\x06\xFA\x1F\xAA\x66\xF3\xA4\xCF\x85\x02\x3C\x11"
+			  "\xEF\xD2\x16\x13\x7A\xBD\x03\x66\xC3\x4D\x6F\x3A"
+			  "\xE5\xD3\xFF\x92\xB6\x45\xB8\x88\x94\x42\x2E\x84"
+			  "\x02\xA5\x54\x12\xBF\xCB\xF1\x6E\x1C\x0C\x23\xFE"
+			  "\x8A\xFD\xF5\x1A\x4C\xD6\x2A\x34\x7F\x21\x50\xBB"
+			  "\x06\x64\x9A\x77\x70\x59\x1D\x12\xD1\xA0\x10\x70"
+			  "\xD7\x4F\x3C\xEE\x82\xEF\x5B\x35\x8F\x05\xF6\x51"
+			  "\xBC\x28\xE1\xB1\x54\xFF\x25\x12\x16\x2C\x62\xFC"
+			  "\xB9\x74\x5E\x78\x41\xB2\x04\x80\x4E\xB1\x43\x2E"
+			  "\x88\x7F\x34\xA4\x33\x66\xE8\x68\x60\x54\xEB\xCE"
+			  "\xD1\x5F\xC4\xD6\x21\x5E\x22\x1A\x7E\xC5\x6D\xB7"
+			  "\x93\x8F\x9C\x77\x6E\x56\xA5\xA8\xF7\xB2\x10\x19",
+		.addtlb = "\xB8\x1E\x9E\xE2\xB3\xE4\x04\x43\x51\x7B\x96\x32"
+			  "\xAC\x95\xF2\x1E\x5E\x7A\xBF\x68\xE3\x7A\xCE\xE5"
+			  "\x2B\x3B\xB0\x34\x7F\xE1\xB5\x37\x3C\x5B\xD2\x6B"
+			  "\x17\xF6\x18\xAF\x7C\x01\xA5\x84\xFE\x07\x0B\x46"
+			  "\xCC\x96\x61\xAB\xCD\x81\x95\x8A\x8A\xB6\xD8\xCC"
+			  "\x94\x80\x45\xF6\xFF\x95\x3A\xB8\xDC\xBF\xB4\xBF"
+			  "\x26\x8C\xE9\x79\x05\x58\x9C\x03\x08\x45\xB5\xC4"
+			  "\xD8\xB4\xCD\x76\x13\xAE\x2B\xCC\xB5\x3E\x3C\x65"
+			  "\x7A\xAA\xDC\x9B\x0B\x13\x8B\x82\x5A\x39\x60\x9A"
+			  "\xF7\xA8\x38\xB5\x83\x8E\x0B\xD1\xE6\xBF\xA1\xDC"
+			  "\x30\x45\xCC\x67\x41\x0F\xF9\x86\x27\xE0\x22\x3E"
+			  "\x0D\x1F\x92\x13\x16\x9B\x84\x79\x91\xFE\xBC\xDF"
+			  "\x15\x6C\xDC\xAE\xC5\x64\x46\x9C\xE8\xEA\xBB\x9D"
+			  "\x27\xA2\x1E\xDF\xB2\xF2\x98\xB4\x88\x4E\x22\x5F"
+			  "\x3C\xD0\x35\x2C\x5C\x89\xC7\xEC\xE3\xF3\x09\x60"
+			  "\xEF\xAC\x78\xBF\x94\xAA\x8C\x30\x7F\xCF\xE4\x4B",
+		.addtllen = 192,
+
+		.expected = "\x93\xFF\x4F\x4A\xA7\xE0\xFC\x3B\xCF\xCE\x57\xCD"
+			    "\xFD\xE9\x94\x6D\x0D\x45\x7E\xA3\x98\xBB\xE6\x54"
+			    "\x36\xF9\x92\xE6\xBB\xC5\x93\x16\x69\x35\x01\xF0"
+			    "\x5A\xE2\x43\xFC\x73\x7C\xA3\x5C\x5B\x49\x72\x69"
+			    "\x6A\xC4\xB6\xD4\xB2\x48\x27\x72\xCA\xE3\xF3\xB8"
+			    "\xD6\x95\x9F\x39\xC8\xD7\x72\xAF\xC2\x7C\x75\xE5"
+			    "\xA4\xF7\x52\x4F\xDF\x80\x75\xCA\x4B\xFA\x75\x9A"
+			    "\x7A\x8D\x48\x94\x30\x1C\x82\x5E\xD6\x3F\xF1\x78"
+			    "\x84\xAA\x8D\x8B\x4F\x6A\x20\x12\xA2\x65\xC5\x02"
+			    "\x32\xA1\xE4\x6B\x86\x2F\xCF\x92\xCD\x01\x55\xF7"
+			    "\xB8\xAB\xC3\x2C\x42\xC3\xFD\x9B\x59\x2D\x47\x8E"
+			    "\xB6\x8D\xE7\x04\x2E\x67\xD9\x07\x14\xA3\xF2\x74"
+			    "\x79\x9C\xAB\xC6\xD6\x52\x3E\x91\x81\xA4\x3C\x9A"
+			    "\x3E\x10\x1E\xD0\x28\xBC\x1C\x50\xF0\xB6\xEC\x01"
+			    "\xE5\x40\x16\x08\xB5\x58\xE0\xC4\xC2\x9A\xBB\x13"
+			    "\xAB\x10\x4B\x07\x24\x09\xEB\xF9\x5E\xAA\x3E\x3A"
+			    "\x25\x34\x5B\x97\x92\xF9\x46\x8A\x8E\x5A\x06\x9C"
+			    "\x2B\x1C\x8E\x47\x19\xC3\x3B\x14\x8A\xC1\xEB\xF7"
+			    "\xB0\xA2\x05\xE0\x70\x12\x88\x21\xFF\xC0\x35\x6D"
+			    "\xE9\x08\x7E\x11\x6E\xD7\x16\x48\x24\x43\xAF\x33"
+			    "\xA3\x48\x44\x91\xC5\x32\x1D\x87\xF6\x9B\x10\x1C"
+			    "\xA4\x7A\x74\x23\xB3\xFC\xB9\x87\x08\xE6\x9A\xEF"
+			    "\xD5\x93\x82\x17\xD4\x78\xDA\x46\x34\xC2\x61\x8C"
+			    "\xB7\x53\x89\xC4\x8A\xD8\xA0\x2E\xCE\xCA\x24\x16"
+			    "\xF0\x18\x7F\xC3\x12\x3F\xD0\xB1\xEF\x37\x99\xA8"
+			    "\x04\x1F\x76\x50\x81\x08\xCD\x4D\x43\xEF\x64\xB6"
+			    "\x03\x57\xB7\x5F\xDD\xF6\xBA\x34\xE2\x88\xE7\x1F"
+			    "\x62\xA5\xA4\x05\xEB\x1A\xFE\x0B\xFE\x74\x7D\x64"
+			    "\x29\x83\xE8\x0B\x97\x7D\x94\x5B\xF9\x3C\x8E\xC8"
+			    "\x6B\xCD\xAD\x63\x32\x6E\x00\xBF\x8E\x57\xF2\x32"
+			    "\x88\x53\x17\x40\xE3\xF8\xF8\xD9\xFD\xCD\x76\x84"
+			    "\xC6\xFD\xB1\x10\x40\xED\x75\xDD\xBD\x78\x8B\x0A"
+			    "\x61\x1E\xCC\xC4\x4F\x95\xF1\x2F\x8F\x5A\xF0\x12"
+			    "\x00\xCE\x75\xB8\xE9\xAB\x63\xC0\x7A\xF6\x9A\x47"
+			    "\xD2\x3C\xB0\xAD\xAF\x03\xDF\x25\xDD\x0C\x0F\xB6"
+			    "\x29\x09\x0F\x28\x5E\xA8\x67\xBB\xC9\x78\xBE\x12"
+			    "\xD8\xD6\xD0\x98\x82\x29\xA3\x82\xFB\x8E\x1C\x79"
+			    "\x28\x52\x22\x73\x3C\x6F\xB5\x33\xFF\x40\x26\x4C"
+			    "\x30\xE4\xE0\x39\x59\x72\x65\x79\x9F\xB7\x89\x87"
+			    "\x64\xAC\x45\x11\x0D\xDD\xC0\x44\x5E\x0D\xDF\xDB"
+			    "\x91\x42\x5F\x52\x7F\xBB\x66\xEE\x32\x90\x8F\x6F"
+			    "\xF8\xB9\xFE\xEA\x42\xFB\x60\x2B\xE3\xD9\xB2\xD1"
+			    "\x74\x37\x14\xC6\xDA\x68\xE6\x09",
+		.expectedlen = 512,
+	}
+};
+
+#endif /* _CRYPTO_DRBG_TESTVECS_H */
diff --git a/crypto/drbg.c b/crypto/drbg.c
index 7d8be036e9be8..9c99b2d510e0a 100644
--- a/crypto/drbg.c
+++ b/crypto/drbg.c
@@ -93,10 +93,12 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/once.h>
 #include <linux/slab.h>
 #include <linux/string_choices.h>
 #include <linux/unaligned.h>
 #include "drbg.h"
+#include "drbg-testvecs.h"
 #include "jitterentropy-kcapi.h"
 
 /* State length in bytes */
@@ -522,7 +524,9 @@ static void drbg_kcapi_exit(struct crypto_tfm *tfm)
  * Public API
  ***************************************************************/
 
-struct drbg_state *crypto_drbg_alloc(void)
+static int drbg_selftest(void);
+
+static struct drbg_state *__crypto_drbg_alloc(void)
 {
 	struct drbg_state *drbg = kzalloc_obj(*drbg);
 
@@ -532,6 +536,15 @@ struct drbg_state *crypto_drbg_alloc(void)
 	mutex_init(&drbg->drbg_mutex);
 	return drbg;
 }
+
+struct drbg_state *crypto_drbg_alloc(void)
+{
+	int err = drbg_selftest();
+
+	if (err)
+		return ERR_PTR(err);
+	return __crypto_drbg_alloc();
+}
 EXPORT_SYMBOL_NS_GPL(crypto_drbg_alloc, "CRYPTO_INTERNAL");
 
 /* Set test entropy in the DRBG. */
@@ -635,20 +648,16 @@ EXPORT_SYMBOL_NS_GPL(crypto_drbg_free, "CRYPTO_INTERNAL");
  * Note 2: There is no sensible way of testing the reseed counter
  * enforcement, so skip it.
  */
-static inline int __init drbg_healthcheck_sanity(void)
+static void drbg_healthcheck_sanity(void)
 {
 #define OUTBUFLEN 16
 	u8 buf[OUTBUFLEN];
 	struct drbg_state *drbg = NULL;
 	int ret;
 
-	/* only perform test in FIPS mode */
-	if (!fips_enabled)
-		return 0;
-
 	drbg = kzalloc_obj(struct drbg_state);
 	if (!drbg)
-		return -ENOMEM;
+		panic("DRBG: out of memory");
 
 	guard(mutex_init)(&drbg->drbg_mutex);
 	drbg->instantiated = true;
@@ -677,8 +686,8 @@ static inline int __init drbg_healthcheck_sanity(void)
 	pr_devel("DRBG: Sanity tests for failure code paths successfully "
 		 "completed\n");
 
-	kfree(drbg);
-	return 0;
+	mutex_destroy(&drbg->drbg_mutex);
+	kfree_sensitive(drbg);
 }
 
 static struct rng_alg drbg_alg = {
@@ -694,13 +703,101 @@ static struct rng_alg drbg_alg = {
 	.base.cra_exit		= drbg_kcapi_exit,
 };
 
+DEFINE_FREE(crypto_drbg_free, struct drbg_state *, crypto_drbg_free(_T))
+
+static int drbg_selftest_one_vec(const struct drbg_testvec *test)
+{
+	struct drbg_state *drbg __free(crypto_drbg_free) = NULL;
+	unsigned char *buf __free(kfree_sensitive) = NULL;
+	int err;
+
+	buf = kzalloc(test->expectedlen, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	drbg = __crypto_drbg_alloc();
+	if (IS_ERR(drbg))
+		return PTR_ERR(drbg);
+
+	crypto_drbg_set_entropy(drbg, test->entropy, test->entropylen);
+	err = crypto_drbg_seed(drbg, test->pers, test->perslen);
+	if (err) {
+		pr_err("DRBG: Instantiation failed: %d\n", err);
+		return err;
+	}
+
+	if (test->ent_reseed_len) {
+		crypto_drbg_set_entropy(drbg, test->ent_reseed,
+					test->ent_reseed_len);
+		err = crypto_drbg_seed(drbg, test->addtl_reseed,
+				       test->addtl_reseed_len);
+		if (err) {
+			pr_err("DRBG: Reseed failed: %d\n", err);
+			return err;
+		}
+	}
+
+	err = crypto_drbg_get_bytes(drbg, buf, test->expectedlen, test->addtla,
+				    test->addtllen);
+	if (err) {
+		pr_err("DRBG: Generation failed (first): %d\n", err);
+		return err;
+	}
+
+	err = crypto_drbg_get_bytes(drbg, buf, test->expectedlen, test->addtlb,
+				    test->addtllen);
+	if (err) {
+		pr_err("DRBG: Generation failed (second): %d\n", err);
+		return err;
+	}
+
+	if (memcmp(test->expected, buf, test->expectedlen) != 0) {
+		pr_err("DRBG: Actual output doesn't match expected output\n");
+		return -ELIBBAD;
+	}
+	return 0;
+}
+
+static int drbg_selftest_err;
+
+static void drbg_selftest_once(void)
+{
+	if (!fips_enabled && !IS_ENABLED(CONFIG_CRYPTO_SELFTESTS))
+		return;
+
+	if (fips_enabled)
+		drbg_healthcheck_sanity();
+
+	for (size_t i = 0; i < ARRAY_SIZE(drbg_testvecs); i++) {
+		int err = drbg_selftest_one_vec(&drbg_testvecs[i]);
+
+		if (err) {
+			if (fips_enabled)
+				panic("DRBG self-test %zu failed: %d\n", i,
+				      err);
+			else
+				WARN(1, "DRBG self-test %zu failed: %d\n", i,
+				     err);
+			drbg_selftest_err = err;
+			break;
+		}
+	}
+	if (fips_enabled)
+		pr_info("DRBG: self-tests passed\n");
+}
+
+static int drbg_selftest(void)
+{
+	DO_ONCE_SLEEPABLE(drbg_selftest_once);
+	return drbg_selftest_err;
+}
+
 static int __init drbg_init(void)
 {
-	int ret;
+	int err = drbg_selftest();
 
-	ret = drbg_healthcheck_sanity();
-	if (ret)
-		return ret;
+	if (err)
+		return err;
 
 	/*
 	 * In FIPS mode, boost the algorithm priority to ensure that when users
-- 
2.56.0


  parent reply	other threads:[~2026-10-18 20:49 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-18 20:46 [PATCH 00/14] crypto: Remove the unnecessary crypto_rng API Eric Biggers
2026-10-18 20:46 ` [PATCH 01/14] crypto: drbg - Don't use uninitialized stack data Eric Biggers
2026-10-18 20:46 ` [PATCH 02/14] crypto: rng - Remove unnecessary inclusions of internal/rng.h Eric Biggers
2026-10-18 20:46 ` [PATCH 03/14] crypto: jitterentropy - Move health check to first use Eric Biggers
2026-10-18 20:46 ` [PATCH 04/14] crypto: jitterentropy - Add library API Eric Biggers
2026-10-18 20:46 ` [PATCH 05/14] crypto: drbg - Use jitterentropy " Eric Biggers
2026-10-18 20:46 ` [PATCH 06/14] crypto: drbg - Add " Eric Biggers
2026-10-18 20:46 ` Eric Biggers [this message]
2026-10-18 20:46 ` [PATCH 08/14] crypto: algif_rng - Use DRBG and jitterentropy library APIs Eric Biggers
2026-10-18 20:46 ` [PATCH 09/14] crypto: stdrng - Reimplement "stdrng" using direct DRBG calls Eric Biggers
2026-10-18 20:46 ` [PATCH 10/14] crypto: drbg - Remove crypto_rng support Eric Biggers
2026-10-18 20:46 ` [PATCH 11/14] crypto: jitterentropy " Eric Biggers
2026-10-18 20:46 ` [PATCH 12/14] crypto: jitterentropy - Remove the kconfig prompt Eric Biggers
2026-10-18 20:46 ` [PATCH 13/14] crypto: rng - Remove the rng algorithm type Eric Biggers
2026-10-18 20:46 ` [PATCH 14/14] crypto: stdrng - Make crypto_stdrng_get_bytes() take size_t Eric Biggers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261018204618.104876-8-ebiggers@kernel.org \
    --to=ebiggers@kernel.org \
    --cc=herbert@gondor.apana.org.au \
    --cc=linux-crypto@vger.kernel.org \
    --cc=smueller@chronox.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox