LCOV - code coverage report
Current view: top level - src/port - pg_strong_random.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 80.0 % 10 8
Test Date: 2026-02-17 17:20:33 Functions: 100.0 % 2 2
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-2026, 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              : /*
      28              :  * pg_strong_random & pg_strong_random_init
      29              :  *
      30              :  * Generate requested number of random bytes. The returned bytes are
      31              :  * cryptographically secure, suitable for use e.g. in authentication.
      32              :  *
      33              :  * Before pg_strong_random is called in any process, the generator must first
      34              :  * be initialized by calling pg_strong_random_init().  Initialization is a no-
      35              :  * op for all supported randomness sources, it is kept to maintain backwards
      36              :  * compatibility with extensions.
      37              :  *
      38              :  * We rely on system facilities for actually generating the numbers.
      39              :  * We support a number of sources:
      40              :  *
      41              :  * 1. OpenSSL's RAND_bytes()
      42              :  * 2. Windows' CryptGenRandom() function
      43              :  * 3. /dev/urandom
      44              :  *
      45              :  * Returns true on success, and false if none of the sources
      46              :  * were available. NB: It is important to check the return value!
      47              :  * Proceeding with key generation when no random data was available
      48              :  * would lead to predictable keys and security issues.
      49              :  */
      50              : 
      51              : 
      52              : 
      53              : #ifdef USE_OPENSSL
      54              : 
      55              : #include <openssl/rand.h>
      56              : 
      57              : void
      58        23470 : pg_strong_random_init(void)
      59              : {
      60              :     /* No initialization needed */
      61        23470 : }
      62              : 
      63              : bool
      64        66034 : pg_strong_random(void *buf, size_t len)
      65              : {
      66              :     int         i;
      67              : 
      68              :     /*
      69              :      * Check that OpenSSL's CSPRNG has been sufficiently seeded, and if not
      70              :      * add more seed data using RAND_poll().  With some older versions of
      71              :      * OpenSSL, it may be necessary to call RAND_poll() a number of times.  If
      72              :      * RAND_poll() fails to generate seed data within the given amount of
      73              :      * retries, subsequent RAND_bytes() calls will fail, but we allow that to
      74              :      * happen to let pg_strong_random() callers handle that with appropriate
      75              :      * error handling.
      76              :      */
      77              : #define NUM_RAND_POLL_RETRIES 8
      78              : 
      79        66034 :     for (i = 0; i < NUM_RAND_POLL_RETRIES; i++)
      80              :     {
      81        66034 :         if (RAND_status() == 1)
      82              :         {
      83              :             /* The CSPRNG is sufficiently seeded */
      84        66034 :             break;
      85              :         }
      86              : 
      87            0 :         RAND_poll();
      88              :     }
      89              : 
      90        66034 :     if (RAND_bytes(buf, len) == 1)
      91        66034 :         return true;
      92            0 :     return false;
      93              : }
      94              : 
      95              : #elif WIN32
      96              : 
      97              : #include <wincrypt.h>
      98              : /*
      99              :  * Cache a global crypto provider that only gets freed when the process
     100              :  * exits, in case we need random numbers more than once.
     101              :  */
     102              : static HCRYPTPROV hProvider = 0;
     103              : 
     104              : void
     105              : pg_strong_random_init(void)
     106              : {
     107              :     /* No initialization needed on WIN32 */
     108              : }
     109              : 
     110              : bool
     111              : pg_strong_random(void *buf, size_t len)
     112              : {
     113              :     if (hProvider == 0)
     114              :     {
     115              :         if (!CryptAcquireContext(&hProvider,
     116              :                                  NULL,
     117              :                                  MS_DEF_PROV,
     118              :                                  PROV_RSA_FULL,
     119              :                                  CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
     120              :         {
     121              :             /*
     122              :              * On failure, set back to 0 in case the value was for some reason
     123              :              * modified.
     124              :              */
     125              :             hProvider = 0;
     126              :         }
     127              :     }
     128              :     /* Re-check in case we just retrieved the provider */
     129              :     if (hProvider != 0)
     130              :     {
     131              :         if (CryptGenRandom(hProvider, len, buf))
     132              :             return true;
     133              :     }
     134              :     return false;
     135              : }
     136              : 
     137              : #else                           /* not USE_OPENSSL or WIN32 */
     138              : 
     139              : /*
     140              :  * Without OpenSSL or Win32 support, just read /dev/urandom ourselves.
     141              :  */
     142              : 
     143              : void
     144              : pg_strong_random_init(void)
     145              : {
     146              :     /* No initialization needed */
     147              : }
     148              : 
     149              : bool
     150              : pg_strong_random(void *buf, size_t len)
     151              : {
     152              :     int         f;
     153              :     char       *p = buf;
     154              :     ssize_t     res;
     155              : 
     156              :     f = open("/dev/urandom", O_RDONLY, 0);
     157              :     if (f == -1)
     158              :         return false;
     159              : 
     160              :     while (len)
     161              :     {
     162              :         res = read(f, p, len);
     163              :         if (res <= 0)
     164              :         {
     165              :             if (errno == EINTR)
     166              :                 continue;       /* interrupted by signal, just retry */
     167              : 
     168              :             close(f);
     169              :             return false;
     170              :         }
     171              : 
     172              :         p += res;
     173              :         len -= res;
     174              :     }
     175              : 
     176              :     close(f);
     177              :     return true;
     178              : }
     179              : #endif
        

Generated by: LCOV version 2.0-1