]> git.ipfire.org Git - thirdparty/rng-tools.git/commitdiff
drng: Move DRNG code to a separate file and make safe on non-x86
authorH. Peter Anvin <hpa@linux.intel.com>
Wed, 1 Aug 2012 21:31:35 +0000 (14:31 -0700)
committerJeff Garzik <jgarzik@redhat.com>
Thu, 2 Aug 2012 04:18:37 +0000 (00:18 -0400)
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 <hpa@linux.intel.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Makefile.am
rngd_entsource.c
rngd_entsource.h
rngd_rdrand.c [new file with mode: 0644]

index b86042e998f7afd294ca698b533749603cb70840..f8490a3a6f287e3d752588bb2390b08585db693d 100644 (file)
@@ -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
index 9a37081141c9d62b3eeebbfd2e9a27cd9d6e8be0..46b051c0268b888fb2437794c1b024725580eddf 100644 (file)
  * 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
  */
index 64d8e484baf39c0a3631196eb9c8502af0e1ef6b..79b8b86672e2933d5b7d91614dd17184488caf58 100644 (file)
 #include <unistd.h>
 #include <stdint.h>
 
-/* 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 (file)
index 0000000..d6408a0
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2012, Intel Corporation
+ * Authors: Richard B. Hill <richard.b.hill@intel.com>,
+ *          H. Peter Anvin <hpa@linux.intel.com>
+ *
+ * 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 <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <syslog.h>
+#include <string.h>
+#include <stddef.h>
+
+#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 */