From 101309bc070667a39794bf13714d43f950b9bade Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 1 Aug 2012 14:31:35 -0700 Subject: [PATCH] drng: Move DRNG code to a separate file and make safe on non-x86 Move all the DRNG code to a separate file, and make sure it is properly stubbed out on non-x86. Furthermore, fix the CPUID bits we check for; in particular we need AES-ni for the whitening code. Signed-off-by: H. Peter Anvin Signed-off-by: Jeff Garzik --- Makefile.am | 3 +- rngd_entsource.c | 133 ------------------------------- rngd_entsource.h | 15 ---- rngd_rdrand.c | 198 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 200 insertions(+), 149 deletions(-) create mode 100644 rngd_rdrand.c diff --git a/Makefile.am b/Makefile.am index b86042e..f8490a3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -10,7 +10,8 @@ man_MANS = rngd.8 rngtest.1 noinst_LIBRARIES = librngd.a rngd_SOURCES = rngd.h rngd.c rngd_entsource.h rngd_entsource.c \ - rngd_linux.h rngd_linux.c util.c rdrand_asm.S + rngd_linux.h rngd_linux.c util.c \ + rngd_rdrand.c rdrand_asm.S rngd_LDADD = librngd.a rngtest_SOURCES = exits.h stats.h stats.c rngtest.c diff --git a/rngd_entsource.c b/rngd_entsource.c index 9a37081..46b051c 100644 --- a/rngd_entsource.c +++ b/rngd_entsource.c @@ -47,49 +47,6 @@ * it is 14 bytes.*/ #define TPM_GET_RNG_OVERHEAD 14 -/* Checking eflags to confirm cpuid instruction available */ -/* Only necessary for 32 bit processors */ -#if defined (__i386__) -int x86_has_eflag(uint32_t flag) -{ - uint32_t f0, f1; - asm("pushfl ; " - "pushfl ; " - "popl %0 ; " - "movl %0,%1 ; " - "xorl %2,%1 ; " - "pushl %1 ; " - "popfl ; " - "pushfl ; " - "popl %1 ; " - "popfl" - : "=&r" (f0), "=&r" (f1) - : "ri" (flag)); - return !!((f0^f1) & flag); -} -#endif - -/* Calling cpuid instruction to verify rdrand capability */ -static void cpuid(unsigned int leaf, unsigned int subleaf, struct cpuid *out) -{ -#ifdef __i386__ - /* %ebx is a forbidden register if we compile with -fPIC or -fPIE */ - asm volatile("movl %%ebx,%0 ; cpuid ; xchgl %%ebx,%0" - : "=r" (out->ebx), - "=a" (out->eax), - "=c" (out->ecx), - "=d" (out->edx) - : "a" (leaf), "c" (subleaf)); -#else - asm volatile("cpuid" - : "=b" (out->ebx), - "=a" (out->eax), - "=c" (out->ecx), - "=d" (out->edx) - : "a" (leaf), "c" (subleaf)); -#endif -} - /* Read data from the entropy source */ int xread(void *buf, size_t size, struct rng *ent_src) { @@ -113,59 +70,6 @@ int xread(void *buf, size_t size, struct rng *ent_src) return 0; } -/* Initialization vector and msg sizes for standard AES usage */ -#define IV_SIZE (16*1) -#define MSG_SIZE (16*7) -#define CHUNK_SIZE (16*8) - -/* Read data from the drng - * in chunks of 128 bytes for AES scrambling */ -int xread_drng(void *buf, size_t size, struct rng *ent_src) -{ - size_t psize = size; - size_t off = 0; - ssize_t r = 0; - int rdrand_round_count = size / 128; - - static unsigned char iv_buf[IV_SIZE] __attribute__((aligned(128))); - static unsigned char m_buf[MSG_SIZE] __attribute__((aligned(128))); - static unsigned char tmp[CHUNK_SIZE] __attribute__((aligned(128))); - static unsigned char fwd[CHUNK_SIZE] __attribute__((aligned(128))); - int i; - - while (size > 0 && size <= psize) { - for (i = 0; i < rdrand_round_count && size <= psize; i++) { - if (!x86_rdrand_nlong(iv_buf, sizeof(iv_buf)/sizeof(long))) { - r = -1; - break; - } - if (!x86_rdrand_nlong(m_buf, sizeof(m_buf)/sizeof(long))) { - r = -1; - break; - } - memcpy(tmp, iv_buf, IV_SIZE); - memcpy(tmp+IV_SIZE, m_buf, MSG_SIZE); - - x86_aes_mangle(tmp, fwd); - r = (sizeof(tmp) > size)? size : sizeof(tmp); - - if (r <= 0) - break; - memcpy(buf+off, tmp, r); - off += r; - size -= r; - } - if (r <= 0) - break; - } - - if (size > 0 && size < psize) { - message(LOG_DAEMON|LOG_ERR, "read error\n"); - return -1; - } - return 0; -} - /* tpm rng read call to kernel has 13 bytes of overhead * the logic to process this involves reading to a temporary_buf * and copying the no generated to buf */ @@ -282,43 +186,6 @@ int init_entropy_source(struct rng *ent_src) return 0; } -/* - * Confirm RDRAND capabilities for drng entropy source - */ -int init_drng_entropy_source(struct rng *ent_src) -{ -#if defined (__x86_64__) || defined(__i386__) - struct cpuid info; - int got_intel_cpu = 0; - -#if defined (__i386__) - uint32_t flag = 0x200000; - - if(!x86_has_eflag(flag)) return 1; //check 32 bit processor for cpuid -#endif - - cpuid(0,0, &info); - if(memcmp((char *)(&info.ebx), "Genu", 4) == 0 && - memcmp((char *)(&info.edx), "ineI", 4) == 0 && - memcmp((char *)(&info.ecx), "ntel", 4) == 0) { - got_intel_cpu = 1; - } - if(got_intel_cpu == 0) return 1; - - cpuid(1,0,&info); - if ((info.ecx & 0x40000000)!=0x40000000) return 1; - - src_list_add(ent_src); - /* Bootstrap FIPS tests */ - ent_src->fipsctx = malloc(sizeof(fips_ctx_t)); - fips_init(ent_src->fipsctx, 0); - return 0; -#else - //No intel processor, no drng - return 1; -#endif -} - /* * Open tpm entropy source, and initialize it */ diff --git a/rngd_entsource.h b/rngd_entsource.h index 64d8e48..79b8b86 100644 --- a/rngd_entsource.h +++ b/rngd_entsource.h @@ -26,25 +26,10 @@ #include #include -/* Struct for CPUID return values */ -struct cpuid { - uint32_t eax, ecx, edx, ebx; -}; - /* Logic and contexts */ extern fips_ctx_t fipsctx; /* Context for the FIPS tests */ extern fips_ctx_t tpm_fipsctx; /* Context for the tpm FIPS tests */ -/* Inline assembly to check eflags */ -/* Only necessary on 32 bit processor */ -#if defined (__i386__) -int x86_has_eflag(uint32_t flag); -#endif - -/* Inline assembly for CPUID call for RDRAND */ -extern int x86_rdrand_nlong(void *ptr, size_t count); /* RDRAND-access logic */ -extern void x86_aes_mangle(void *data, void *state); /* Conditioning RDRAND for seed-grade entropy */ - /* * Initialize entropy source and entropy conditioning * diff --git a/rngd_rdrand.c b/rngd_rdrand.c new file mode 100644 index 0000000..d6408a0 --- /dev/null +++ b/rngd_rdrand.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2012, Intel Corporation + * Authors: Richard B. Hill , + * H. Peter Anvin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#define _GNU_SOURCE + +#ifndef HAVE_CONFIG_H +#error Invalid or missing autoconf build environment +#endif + +#include "rng-tools-config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rngd.h" +#include "fips.h" +#include "exits.h" +#include "rngd_entsource.h" + +#if defined(__i386__) || defined(__x86_64__) + +/* Initialization vector and msg sizes for standard AES usage */ +#define IV_SIZE (16*1) +#define MSG_SIZE (16*7) +#define CHUNK_SIZE (16*8) + +/* Struct for CPUID return values */ +struct cpuid { + uint32_t eax, ecx, edx, ebx; +}; + +/* Get data from RDRAND */ +extern int x86_rdrand_nlong(void *ptr, size_t count); +/* Conditioning RDRAND for seed-grade entropy */ +extern void x86_aes_mangle(void *data, void *state); + +/* Checking eflags to confirm cpuid instruction available */ +/* Only necessary for 32 bit processors */ +#if defined (__i386__) +static int x86_has_eflag(uint32_t flag) +{ + uint32_t f0, f1; + asm("pushfl ; " + "pushfl ; " + "popl %0 ; " + "movl %0,%1 ; " + "xorl %2,%1 ; " + "pushl %1 ; " + "popfl ; " + "pushfl ; " + "popl %1 ; " + "popfl" + : "=&r" (f0), "=&r" (f1) + : "ri" (flag)); + return !!((f0^f1) & flag); +} +#endif + +/* Calling cpuid instruction to verify rdrand capability */ +static void cpuid(unsigned int leaf, unsigned int subleaf, struct cpuid *out) +{ +#ifdef __i386__ + /* %ebx is a forbidden register if we compile with -fPIC or -fPIE */ + asm volatile("movl %%ebx,%0 ; cpuid ; xchgl %%ebx,%0" + : "=r" (out->ebx), + "=a" (out->eax), + "=c" (out->ecx), + "=d" (out->edx) + : "a" (leaf), "c" (subleaf)); +#else + asm volatile("cpuid" + : "=b" (out->ebx), + "=a" (out->eax), + "=c" (out->ecx), + "=d" (out->edx) + : "a" (leaf), "c" (subleaf)); +#endif +} + +/* Read data from the drng + * in chunks of 128 bytes for AES scrambling */ +int xread_drng(void *buf, size_t size, struct rng *ent_src) +{ + size_t psize = size; + size_t off = 0; + ssize_t r = 0; + int rdrand_round_count = size / 128; + + static unsigned char iv_buf[IV_SIZE] __attribute__((aligned(128))); + static unsigned char m_buf[MSG_SIZE] __attribute__((aligned(128))); + static unsigned char tmp[CHUNK_SIZE] __attribute__((aligned(128))); + static unsigned char fwd[CHUNK_SIZE] __attribute__((aligned(128))); + int i; + + while (size > 0 && size <= psize) { + for (i = 0; i < rdrand_round_count && size <= psize; i++) { + if (!x86_rdrand_nlong(iv_buf, sizeof(iv_buf)/sizeof(long))) { + r = -1; + break; + } + if (!x86_rdrand_nlong(m_buf, sizeof(m_buf)/sizeof(long))) { + r = -1; + break; + } + memcpy(tmp, iv_buf, IV_SIZE); + memcpy(tmp+IV_SIZE, m_buf, MSG_SIZE); + + x86_aes_mangle(tmp, fwd); + r = (sizeof(tmp) > size)? size : sizeof(tmp); + + if (r <= 0) + break; + memcpy(buf+off, tmp, r); + off += r; + size -= r; + } + if (r <= 0) + break; + } + + if (size > 0 && size < psize) { + message(LOG_DAEMON|LOG_ERR, "read error\n"); + return -1; + } + return 0; +} + +/* + * Confirm RDRAND capabilities for drng entropy source + */ +int init_drng_entropy_source(struct rng *ent_src) +{ + struct cpuid info; + /* We need RDRAND and AESni */ + const uint32_t need_features_ecx1 = (1 << 30) | (1 << 25); + +#if defined(__i386__) + if (!x86_has_eflag(1 << 21)) + return 1; /* No CPUID instruction */ +#endif + + cpuid(0, 0, &info); + if (info.eax < 1) + return 1; + cpuid(1, 0, &info); + if ((info.ecx & need_features_ecx1) != need_features_ecx1) + return 1; + + src_list_add(ent_src); + /* Bootstrap FIPS tests */ + ent_src->fipsctx = malloc(sizeof(fips_ctx_t)); + fips_init(ent_src->fipsctx, 0); + return 0; +} + +#else /* Not i386 or x86-64 */ + +int init_drng_entropy_source(struct rng *ent_src) +{ + (void)ent_src; + return 1; +} + +int xread_drng(void *buf, size_t size, struct rng *ent_src) +{ + (void)buf; + (void)size; + (void)ent_src; + + return -1; +} + +#endif /* Not i386 or x86-64 */ -- 2.39.2