LCOV - code coverage report
Current view: top level - random - random-system.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 43 57 75.4 %
Date: 2017-03-02 16:44:37 Functions: 7 11 63.6 %

          Line data    Source code
       1             : /* random-system.c - wrapper around the system's RNG
       2             :  * Copyright (C) 2012  Free Software Foundation, Inc.
       3             :  *
       4             :  * This file is part of Libgcrypt.
       5             :  *
       6             :  * Libgcrypt is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU Lesser General Public License as
       8             :  * published by the Free Software Foundation; either version 2.1 of
       9             :  * the License, or (at your option) any later version.
      10             :  *
      11             :  * Libgcrypt is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public
      17             :  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : /*
      21             :    This RNG is merely wrapper around the system's native RNG.  For
      22             :    example on Unix systems it directly uses /dev/{u,}random.
      23             :  */
      24             : 
      25             : #include <config.h>
      26             : #include <stdio.h>
      27             : #include <stdlib.h>
      28             : #include <errno.h>
      29             : #include <sys/types.h>
      30             : #include <unistd.h>
      31             : #ifdef HAVE_GETTIMEOFDAY
      32             : #include <sys/time.h>
      33             : #endif
      34             : 
      35             : #include "g10lib.h"
      36             : #include "random.h"
      37             : #include "rand-internal.h"
      38             : 
      39             : /* This is the lock we use to serialize access to this RNG.  The extra
      40             :    integer variable is only used to check the locking state; that is,
      41             :    it is not meant to be thread-safe but merely as a failsafe feature
      42             :    to assert proper locking.  */
      43             : GPGRT_LOCK_DEFINE (system_rng_lock);
      44             : static int system_rng_is_locked;
      45             : 
      46             : 
      47             : /* --- Local prototypes ---  */
      48             : 
      49             : 
      50             : 
      51             : 
      52             : /* --- Functions  --- */
      53             : 
      54             : /* Basic initialization is required to initialize mutexes and
      55             :    do a few checks on the implementation.  */
      56             : static void
      57           8 : basic_initialization (void)
      58             : {
      59             :   static int initialized;
      60             : 
      61           8 :   if (initialized)
      62           6 :     return;
      63           2 :   initialized = 1;
      64             : 
      65           2 :   system_rng_is_locked = 0;
      66             : 
      67             :   /* Make sure that we are still using the values we traditionally
      68             :      used for the random levels.  */
      69             :   gcry_assert (GCRY_WEAK_RANDOM == 0
      70             :                && GCRY_STRONG_RANDOM == 1
      71             :                && GCRY_VERY_STRONG_RANDOM == 2);
      72             : 
      73             : }
      74             : 
      75             : 
      76             : /* Acquire the system_rng_lock.  */
      77             : static void
      78           6 : lock_rng (void)
      79             : {
      80             :   gpg_err_code_t rc;
      81             : 
      82           6 :   rc = gpgrt_lock_lock (&system_rng_lock);
      83           6 :   if (rc)
      84           0 :     log_fatal ("failed to acquire the System RNG lock: %s\n",
      85             :                gpg_strerror (rc));
      86           6 :   system_rng_is_locked = 1;
      87           6 : }
      88             : 
      89             : 
      90             : /* Release the system_rng_lock.  */
      91             : static void
      92           6 : unlock_rng (void)
      93             : {
      94             :   gpg_err_code_t rc;
      95             : 
      96           6 :   system_rng_is_locked = 0;
      97           6 :   rc = gpgrt_lock_unlock (&system_rng_lock);
      98           6 :   if (rc)
      99           0 :     log_fatal ("failed to release the System RNG lock: %s\n",
     100             :                gpg_strerror (rc));
     101           6 : }
     102             : 
     103             : 
     104             : /* Helper variables for read_cb().
     105             : 
     106             :    The _gcry_rnd*_gather_random interface does not allow to provide a
     107             :    data pointer.  Thus we need to use a global variable for
     108             :    communication.  However, the then required locking is anyway a good
     109             :    idea because it does not make sense to have several readers of (say
     110             :    /dev/random).  It is easier to serve them one after the other.  */
     111             : static unsigned char *read_cb_buffer;   /* The buffer.  */
     112             : static size_t         read_cb_size;     /* Size of the buffer.  */
     113             : static size_t         read_cb_len;      /* Used length.  */
     114             : 
     115             : 
     116             : /* Callback for _gcry_rnd*_gather_random.  */
     117             : static void
     118           6 : read_cb (const void *buffer, size_t length, enum random_origins origin)
     119             : {
     120           6 :   const unsigned char *p = buffer;
     121             : 
     122             :   (void)origin;
     123             : 
     124           6 :   gcry_assert (system_rng_is_locked);
     125           6 :   gcry_assert (read_cb_buffer);
     126             : 
     127             :   /* Note that we need to protect against gatherers returning more
     128             :      than the requested bytes (e.g. rndw32).  */
     129          36 :   while (length-- && read_cb_len < read_cb_size)
     130             :     {
     131          24 :       read_cb_buffer[read_cb_len++] = *p++;
     132             :     }
     133           6 : }
     134             : 
     135             : 
     136             : /* Fill BUFFER with LENGTH bytes of random at quality LEVEL.  The
     137             :    function either succeeds or terminates the process in case of a
     138             :    fatal error. */
     139             : static void
     140           6 : get_random (void *buffer, size_t length, int level)
     141             : {
     142             :   int rc;
     143             : 
     144           6 :   gcry_assert (buffer);
     145             : 
     146           6 :   read_cb_buffer = buffer;
     147           6 :   read_cb_size   = length;
     148           6 :   read_cb_len    = 0;
     149             : 
     150             : #if USE_RNDLINUX
     151           6 :   rc = _gcry_rndlinux_gather_random (read_cb, 0, length, level);
     152             : #elif USE_RNDUNIX
     153             :   rc = _gcry_rndunix_gather_random (read_cb, 0, length, level);
     154             : #elif USE_RNDW32
     155             :   do
     156             :     {
     157             :       rc = _gcry_rndw32_gather_random (read_cb, 0, length, level);
     158             :     }
     159             :   while (rc >= 0 && read_cb_len < read_cb_size);
     160             : #else
     161             :   rc = -1;
     162             : #endif
     163             : 
     164           6 :   if (rc < 0 || read_cb_len != read_cb_size)
     165             :     {
     166           0 :       log_fatal ("error reading random from system RNG (rc=%d)\n", rc);
     167             :     }
     168           6 : }
     169             : 
     170             : 
     171             : 
     172             : /* --- Public Functions --- */
     173             : 
     174             : /* Initialize this random subsystem.  If FULL is false, this function
     175             :    merely calls the basic initialization of the module and does not do
     176             :    anything more.  Doing this is not really required but when running
     177             :    in a threaded environment we might get a race condition
     178             :    otherwise. */
     179             : void
     180           8 : _gcry_rngsystem_initialize (int full)
     181             : {
     182           8 :   basic_initialization ();
     183           8 :   if (!full)
     184           2 :     return;
     185             :   /* Nothing more to initialize.  */
     186           6 :   return;
     187             : }
     188             : 
     189             : 
     190             : /* Try to close the FDs of the random gather module.  This is
     191             :    currently only implemented for rndlinux. */
     192             : void
     193           0 : _gcry_rngsystem_close_fds (void)
     194             : {
     195           0 :   lock_rng ();
     196             : #if USE_RNDLINUX
     197           0 :   _gcry_rndlinux_gather_random (NULL, 0, 0, 0);
     198             : #endif
     199           0 :   unlock_rng ();
     200           0 : }
     201             : 
     202             : 
     203             : /* Print some statistics about the RNG.  */
     204             : void
     205           0 : _gcry_rngsystem_dump_stats (void)
     206             : {
     207             :   /* Not yet implemented.  */
     208           0 : }
     209             : 
     210             : 
     211             : /* This function returns true if no real RNG is available or the
     212             :    quality of the RNG has been degraded for test purposes.  */
     213             : int
     214           0 : _gcry_rngsystem_is_faked (void)
     215             : {
     216           0 :   return 0;  /* Faked random is not supported.  */
     217             : }
     218             : 
     219             : 
     220             : /* Add BUFLEN bytes from BUF to the internal random pool.  QUALITY
     221             :    should be in the range of 0..100 to indicate the goodness of the
     222             :    entropy added, or -1 for goodness not known. */
     223             : gcry_error_t
     224           0 : _gcry_rngsystem_add_bytes (const void *buf, size_t buflen, int quality)
     225             : {
     226             :   (void)buf;
     227             :   (void)buflen;
     228             :   (void)quality;
     229           0 :   return 0;  /* Not implemented. */
     230             : }
     231             : 
     232             : 
     233             : /* Public function to fill the buffer with LENGTH bytes of
     234             :    cryptographically strong random bytes.  Level GCRY_WEAK_RANDOM is
     235             :    here mapped to GCRY_STRONG_RANDOM, GCRY_STRONG_RANDOM is strong
     236             :    enough for most usage, GCRY_VERY_STRONG_RANDOM is good for key
     237             :    generation stuff but may be very slow.  */
     238             : void
     239           6 : _gcry_rngsystem_randomize (void *buffer, size_t length,
     240             :                            enum gcry_random_level level)
     241             : {
     242           6 :   _gcry_rngsystem_initialize (1);  /* Auto-initialize if needed.  */
     243             : 
     244           6 :   if (level != GCRY_VERY_STRONG_RANDOM)
     245           6 :     level = GCRY_STRONG_RANDOM;
     246             : 
     247           6 :   lock_rng ();
     248           6 :   get_random (buffer, length, level);
     249           6 :   unlock_rng ();
     250           6 : }

Generated by: LCOV version 1.13