LCOV - code coverage report
Current view: top level - src/port - pg_strong_random.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 6 9 66.7 %
Date: 2019-11-15 22:06:47 Functions: 1 1 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pg_strong_random.c
       4             :  *    generate a cryptographically secure random number
       5             :  *
       6             :  * Our definition of "strong" is that it's suitable for generating random
       7             :  * salts and query cancellation keys, during authentication.
       8             :  *
       9             :  * Note: this code is run quite early in postmaster and backend startup;
      10             :  * therefore, even when built for backend, it cannot rely on backend
      11             :  * infrastructure such as elog() or palloc().
      12             :  *
      13             :  * Copyright (c) 1996-2019, PostgreSQL Global Development Group
      14             :  *
      15             :  * IDENTIFICATION
      16             :  *    src/port/pg_strong_random.c
      17             :  *
      18             :  *-------------------------------------------------------------------------
      19             :  */
      20             : 
      21             : #include "c.h"
      22             : 
      23             : #include <fcntl.h>
      24             : #include <unistd.h>
      25             : #include <sys/time.h>
      26             : 
      27             : #ifdef USE_OPENSSL
      28             : #include <openssl/rand.h>
      29             : #endif
      30             : #ifdef USE_WIN32_RANDOM
      31             : #include <wincrypt.h>
      32             : #endif
      33             : 
      34             : #ifdef USE_WIN32_RANDOM
      35             : /*
      36             :  * Cache a global crypto provider that only gets freed when the process
      37             :  * exits, in case we need random numbers more than once.
      38             :  */
      39             : static HCRYPTPROV hProvider = 0;
      40             : #endif
      41             : 
      42             : #if defined(USE_DEV_URANDOM)
      43             : /*
      44             :  * Read (random) bytes from a file.
      45             :  */
      46             : static bool
      47             : random_from_file(const char *filename, void *buf, size_t len)
      48             : {
      49             :     int         f;
      50             :     char       *p = buf;
      51             :     ssize_t     res;
      52             : 
      53             :     f = open(filename, O_RDONLY, 0);
      54             :     if (f == -1)
      55             :         return false;
      56             : 
      57             :     while (len)
      58             :     {
      59             :         res = read(f, p, len);
      60             :         if (res <= 0)
      61             :         {
      62             :             if (errno == EINTR)
      63             :                 continue;       /* interrupted by signal, just retry */
      64             : 
      65             :             close(f);
      66             :             return false;
      67             :         }
      68             : 
      69             :         p += res;
      70             :         len -= res;
      71             :     }
      72             : 
      73             :     close(f);
      74             :     return true;
      75             : }
      76             : #endif
      77             : 
      78             : /*
      79             :  * pg_strong_random
      80             :  *
      81             :  * Generate requested number of random bytes. The returned bytes are
      82             :  * cryptographically secure, suitable for use e.g. in authentication.
      83             :  *
      84             :  * We rely on system facilities for actually generating the numbers.
      85             :  * We support a number of sources:
      86             :  *
      87             :  * 1. OpenSSL's RAND_bytes()
      88             :  * 2. Windows' CryptGenRandom() function
      89             :  * 3. /dev/urandom
      90             :  *
      91             :  * The configure script will choose which one to use, and set
      92             :  * a USE_*_RANDOM flag accordingly.
      93             :  *
      94             :  * Returns true on success, and false if none of the sources
      95             :  * were available. NB: It is important to check the return value!
      96             :  * Proceeding with key generation when no random data was available
      97             :  * would lead to predictable keys and security issues.
      98             :  */
      99             : bool
     100       23654 : pg_strong_random(void *buf, size_t len)
     101             : {
     102             :     /*
     103             :      * When built with OpenSSL, use OpenSSL's RAND_bytes function.
     104             :      */
     105             : #if defined(USE_OPENSSL_RANDOM)
     106             :     int         i;
     107             : 
     108             :     /*
     109             :      * Check that OpenSSL's CSPRNG has been sufficiently seeded, and if not
     110             :      * add more seed data using RAND_poll().  With some older versions of
     111             :      * OpenSSL, it may be necessary to call RAND_poll() a number of times.
     112             :      */
     113             : #define NUM_RAND_POLL_RETRIES 8
     114             : 
     115       23654 :     for (i = 0; i < NUM_RAND_POLL_RETRIES; i++)
     116             :     {
     117       23654 :         if (RAND_status() == 1)
     118             :         {
     119             :             /* The CSPRNG is sufficiently seeded */
     120       23654 :             break;
     121             :         }
     122             : 
     123           0 :         if (RAND_poll() == 0)
     124             :         {
     125             :             /*
     126             :              * RAND_poll() failed to generate any seed data, which means that
     127             :              * RAND_bytes() will probably fail.  For now, just fall through
     128             :              * and let that happen.  XXX: maybe we could seed it some other
     129             :              * way.
     130             :              */
     131           0 :             break;
     132             :         }
     133             :     }
     134             : 
     135       23654 :     if (RAND_bytes(buf, len) == 1)
     136       23654 :         return true;
     137           0 :     return false;
     138             : 
     139             :     /*
     140             :      * Windows has CryptoAPI for strong cryptographic numbers.
     141             :      */
     142             : #elif defined(USE_WIN32_RANDOM)
     143             :     if (hProvider == 0)
     144             :     {
     145             :         if (!CryptAcquireContext(&hProvider,
     146             :                                  NULL,
     147             :                                  MS_DEF_PROV,
     148             :                                  PROV_RSA_FULL,
     149             :                                  CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
     150             :         {
     151             :             /*
     152             :              * On failure, set back to 0 in case the value was for some reason
     153             :              * modified.
     154             :              */
     155             :             hProvider = 0;
     156             :         }
     157             :     }
     158             :     /* Re-check in case we just retrieved the provider */
     159             :     if (hProvider != 0)
     160             :     {
     161             :         if (CryptGenRandom(hProvider, len, buf))
     162             :             return true;
     163             :     }
     164             :     return false;
     165             : 
     166             :     /*
     167             :      * Read /dev/urandom ourselves.
     168             :      */
     169             : #elif defined(USE_DEV_URANDOM)
     170             :     if (random_from_file("/dev/urandom", buf, len))
     171             :         return true;
     172             :     return false;
     173             : 
     174             : #else
     175             :     /* The autoconf script should not have allowed this */
     176             : #error no source of random numbers configured
     177             : #endif
     178             : }

Generated by: LCOV version 1.13