PostgreSQL Source Code  git master
pg_strong_random.c
Go to the documentation of this file.
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 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  for (i = 0; i < NUM_RAND_POLL_RETRIES; i++)
116  {
117  if (RAND_status() == 1)
118  {
119  /* The CSPRNG is sufficiently seeded */
120  break;
121  }
122 
123  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  break;
132  }
133  }
134 
135  if (RAND_bytes(buf, len) == 1)
136  return true;
137  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 }
bool pg_strong_random(void *buf, size_t len)
static char * buf
Definition: pg_test_fsync.c:68
static char * filename
Definition: pg_dumpall.c:91
int i
#define close(a)
Definition: win32.h:12
#define EINTR
Definition: win32_port.h:323
#define read(a, b, c)
Definition: win32.h:13