LCOV - code coverage report
Current view: top level - random - rndhw.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 9 49 18.4 %
Date: 2016-11-29 14:56:30 Functions: 2 7 28.6 %

          Line data    Source code
       1             : /* rndhw.c  - Access to the external random daemon
       2             :  * Copyright (C) 2007  Free Software Foundation, Inc.
       3             :  * Copyright (C) 2012  Dmitry Kasatkin
       4             :  *
       5             :  * This file is part of Libgcrypt.
       6             :  *
       7             :  * Libgcrypt is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU Lesser General Public License as
       9             :  * published by the Free Software Foundation; either version 2.1 of
      10             :  * the License, or (at your option) any later version.
      11             :  *
      12             :  * Libgcrypt is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :  * GNU Lesser General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU Lesser General Public
      18             :  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
      19             :  */
      20             : 
      21             : #include <config.h>
      22             : #include <stdio.h>
      23             : #include <stdlib.h>
      24             : 
      25             : #include "types.h"
      26             : #include "g10lib.h"
      27             : #include "rand-internal.h"
      28             : 
      29             : #undef USE_PADLOCK
      30             : #ifdef ENABLE_PADLOCK_SUPPORT
      31             : # ifdef HAVE_GCC_ATTRIBUTE_ALIGNED
      32             : #  if (defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4) || defined(__x86_64__)
      33             : #   define USE_PADLOCK 1
      34             : #  endif
      35             : # endif
      36             : #endif /*ENABLE_PADLOCK_SUPPORT*/
      37             : 
      38             : #undef USE_DRNG
      39             : #ifdef ENABLE_DRNG_SUPPORT
      40             : # ifdef HAVE_GCC_ATTRIBUTE_ALIGNED
      41             : #  if (defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4) || defined(__x86_64__)
      42             : #   define USE_DRNG 1
      43             : #  endif
      44             : # endif
      45             : #endif /*ENABLE_RDRAND_SUPPORT*/
      46             : 
      47             : typedef void (*add_fn_t)(const void*, size_t, enum random_origins);
      48             : 
      49             : /* Keep track on whether the RNG has problems.  */
      50             : static volatile int rng_failed;
      51             : 
      52             : 
      53             : #ifdef USE_PADLOCK
      54             : static size_t
      55           0 : poll_padlock (void (*add)(const void*, size_t, enum random_origins),
      56             :               enum random_origins origin, int fast)
      57             : {
      58             :   volatile char buffer[64+8] __attribute__ ((aligned (8)));
      59             :   volatile char *p;
      60             :   unsigned int nbytes, status;
      61             : 
      62             :   /* Peter Gutmann's cryptlib tests again whether the RNG is enabled
      63             :      but we don't do so.  We would have to do this also for our AES
      64             :      implementaion and that is definitely too time consuming.  There
      65             :      would be a race condition anyway.  Thus we assume that the OS
      66             :      does not change the Padlock initialization while a user process
      67             :      is running.  */
      68           0 :   p = buffer;
      69           0 :   nbytes = 0;
      70           0 :   while (nbytes < 64)
      71             :     {
      72             : #if defined(__x86_64__) && SIZEOF_VOID_P == 8
      73           0 :       asm volatile
      74             :         ("movq %1, %%rdi\n\t"         /* Set buffer.  */
      75             :          "xorq %%rdx, %%rdx\n\t"      /* Request up to 8 bytes.  */
      76             :          ".byte 0x0f, 0xa7, 0xc0\n\t" /* XSTORE RNG. */
      77             :          : "=a" (status)
      78             :          : "g" (p)
      79             :          : "%rdx", "%rdi", "cc"
      80             :          );
      81             : #else
      82             :       asm volatile
      83             :         ("movl %1, %%edi\n\t"         /* Set buffer.  */
      84             :          "xorl %%edx, %%edx\n\t"      /* Request up to 8 bytes.  */
      85             :          ".byte 0x0f, 0xa7, 0xc0\n\t" /* XSTORE RNG. */
      86             :          : "=a" (status)
      87             :          : "g" (p)
      88             :          : "%edx", "%edi", "cc"
      89             :          );
      90             : #endif
      91           0 :       if ((status & (1<<6))         /* RNG still enabled.  */
      92           0 :           && !(status & (1<<13))    /* von Neumann corrector is enabled.  */
      93           0 :           && !(status & (1<<14))    /* String filter is disabled.  */
      94           0 :           && !(status & 0x1c00)     /* BIAS voltage at default.  */
      95           0 :           && (!(status & 0x1f) || (status & 0x1f) == 8) /* Sanity check.  */
      96             :           )
      97             :         {
      98           0 :           nbytes += (status & 0x1f);
      99           0 :           if (fast)
     100           0 :             break; /* Don't get into the loop with the fast flag set.  */
     101           0 :           p += (status & 0x1f);
     102             :         }
     103             :       else
     104             :         {
     105             :           /* If there was an error we need to break the loop and
     106             :              record that there is something wrong with the padlock
     107             :              RNG.  */
     108           0 :           rng_failed = 1;
     109           0 :           break;
     110             :         }
     111             :     }
     112             : 
     113           0 :   if (nbytes)
     114             :     {
     115           0 :       (*add) ((void*)buffer, nbytes, origin);
     116           0 :       wipememory (buffer, nbytes);
     117             :     }
     118           0 :   return nbytes;
     119             : }
     120             : #endif /*USE_PADLOCK*/
     121             : 
     122             : 
     123             : #ifdef USE_DRNG
     124             : # define RDRAND_RETRY_LOOPS     10
     125             : # define RDRAND_INT     ".byte 0x0f,0xc7,0xf0"
     126             : # if defined(__x86_64__) && SIZEOF_UNSIGNED_LONG == 8
     127             : #  define RDRAND_LONG   ".byte 0x48,0x0f,0xc7,0xf0"
     128             : # else
     129             : #  define RDRAND_LONG   RDRAND_INT
     130             : # endif
     131             : static inline int
     132           0 : rdrand_long (unsigned long *v)
     133             : {
     134             :   int ok;
     135           0 :   asm volatile ("1: " RDRAND_LONG "\n\t"
     136             :                 "jc 2f\n\t"
     137             :                 "decl %0\n\t"
     138             :                 "jnz 1b\n\t"
     139             :                 "2:"
     140             :                 : "=r" (ok), "=a" (*v)
     141             :                 : "0" (RDRAND_RETRY_LOOPS)
     142             :                 : "cc");
     143           0 :   return ok;
     144             : }
     145             : 
     146             : 
     147             : static inline int
     148           0 : rdrand_nlong (unsigned long *v, int count)
     149             : {
     150           0 :   while (count--)
     151           0 :     if (!rdrand_long(v++))
     152           0 :       return 0;
     153           0 :   return 1;
     154             : }
     155             : 
     156             : 
     157             : static size_t
     158           0 : poll_drng (add_fn_t add, enum random_origins origin, int fast)
     159             : {
     160             :   volatile char buffer[64] __attribute__ ((aligned (8)));
     161           0 :   unsigned int nbytes = sizeof (buffer);
     162             : 
     163             :   (void)fast;
     164             : 
     165           0 :   if (!rdrand_nlong ((unsigned long *)buffer, sizeof(buffer)/sizeof(long)))
     166           0 :     return 0;
     167           0 :   (*add)((void *)buffer, nbytes, origin);
     168           0 :   return nbytes;
     169             : }
     170             : #endif /*USE_DRNG*/
     171             : 
     172             : 
     173             : int
     174           0 : _gcry_rndhw_failed_p (void)
     175             : {
     176           0 :   return rng_failed;
     177             : }
     178             : 
     179             : 
     180             : /* Try to read random from a hardware RNG if a fast one is
     181             :    available.  */
     182             : void
     183       55090 : _gcry_rndhw_poll_fast (void (*add)(const void*, size_t, enum random_origins),
     184             :                        enum random_origins origin)
     185             : {
     186             :   (void)add;
     187             :   (void)origin;
     188             : 
     189             : #ifdef USE_DRNG
     190       55090 :   if ((_gcry_get_hw_features () & HWF_INTEL_RDRAND))
     191           0 :     poll_drng (add, origin, 1);
     192             : #endif
     193             : #ifdef USE_PADLOCK
     194       55090 :   if ((_gcry_get_hw_features () & HWF_PADLOCK_RNG))
     195           0 :     poll_padlock (add, origin, 1);
     196             : #endif
     197       55090 : }
     198             : 
     199             : 
     200             : /* Read 64 bytes from a hardware RNG and return the number of bytes
     201             :    actually read.  */
     202             : size_t
     203         433 : _gcry_rndhw_poll_slow (void (*add)(const void*, size_t, enum random_origins),
     204             :                        enum random_origins origin)
     205             : {
     206         433 :   size_t nbytes = 0;
     207             : 
     208             :   (void)add;
     209             :   (void)origin;
     210             : 
     211             : #ifdef USE_DRNG
     212         433 :   if ((_gcry_get_hw_features () & HWF_INTEL_RDRAND))
     213           0 :     nbytes += poll_drng (add, origin, 0);
     214             : #endif
     215             : #ifdef USE_PADLOCK
     216         433 :   if ((_gcry_get_hw_features () & HWF_PADLOCK_RNG))
     217           0 :     nbytes += poll_padlock (add, origin, 0);
     218             : #endif
     219             : 
     220         433 :   return nbytes;
     221             : }

Generated by: LCOV version 1.11