Make nbtree split REDO locking match original execution.
[pgsql.git] / src / port / pg_strong_random.c
blob14e8382cd8952adbd7558667cd8266571050dd92
1 /*-------------------------------------------------------------------------
3 * pg_strong_random.c
4 * generate a cryptographically secure random number
6 * Our definition of "strong" is that it's suitable for generating random
7 * salts and query cancellation keys, during authentication.
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().
13 * Copyright (c) 1996-2020, PostgreSQL Global Development Group
15 * IDENTIFICATION
16 * src/port/pg_strong_random.c
18 *-------------------------------------------------------------------------
21 #include "c.h"
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <sys/time.h>
27 #ifdef USE_OPENSSL
28 #include <openssl/rand.h>
29 #endif
30 #ifdef USE_WIN32_RANDOM
31 #include <wincrypt.h>
32 #endif
34 #ifdef USE_WIN32_RANDOM
36 * Cache a global crypto provider that only gets freed when the process
37 * exits, in case we need random numbers more than once.
39 static HCRYPTPROV hProvider = 0;
40 #endif
42 #if defined(USE_DEV_URANDOM)
44 * Read (random) bytes from a file.
46 static bool
47 random_from_file(const char *filename, void *buf, size_t len)
49 int f;
50 char *p = buf;
51 ssize_t res;
53 f = open(filename, O_RDONLY, 0);
54 if (f == -1)
55 return false;
57 while (len)
59 res = read(f, p, len);
60 if (res <= 0)
62 if (errno == EINTR)
63 continue; /* interrupted by signal, just retry */
65 close(f);
66 return false;
69 p += res;
70 len -= res;
73 close(f);
74 return true;
76 #endif
79 * pg_strong_random
81 * Generate requested number of random bytes. The returned bytes are
82 * cryptographically secure, suitable for use e.g. in authentication.
84 * We rely on system facilities for actually generating the numbers.
85 * We support a number of sources:
87 * 1. OpenSSL's RAND_bytes()
88 * 2. Windows' CryptGenRandom() function
89 * 3. /dev/urandom
91 * The configure script will choose which one to use, and set
92 * a USE_*_RANDOM flag accordingly.
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.
99 bool
100 pg_strong_random(void *buf, size_t len)
103 * When built with OpenSSL, use OpenSSL's RAND_bytes function.
105 #if defined(USE_OPENSSL_RANDOM)
106 int i;
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. If
112 * RAND_poll() fails to generate seed data within the given amount of
113 * retries, subsequent RAND_bytes() calls will fail, but we allow that to
114 * happen to let pg_strong_random() callers handle that with appropriate
115 * error handling.
117 #define NUM_RAND_POLL_RETRIES 8
119 for (i = 0; i < NUM_RAND_POLL_RETRIES; i++)
121 if (RAND_status() == 1)
123 /* The CSPRNG is sufficiently seeded */
124 break;
127 RAND_poll();
130 if (RAND_bytes(buf, len) == 1)
131 return true;
132 return false;
135 * Windows has CryptoAPI for strong cryptographic numbers.
137 #elif defined(USE_WIN32_RANDOM)
138 if (hProvider == 0)
140 if (!CryptAcquireContext(&hProvider,
141 NULL,
142 MS_DEF_PROV,
143 PROV_RSA_FULL,
144 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
147 * On failure, set back to 0 in case the value was for some reason
148 * modified.
150 hProvider = 0;
153 /* Re-check in case we just retrieved the provider */
154 if (hProvider != 0)
156 if (CryptGenRandom(hProvider, len, buf))
157 return true;
159 return false;
162 * Read /dev/urandom ourselves.
164 #elif defined(USE_DEV_URANDOM)
165 if (random_from_file("/dev/urandom", buf, len))
166 return true;
167 return false;
169 #else
170 /* The autoconf script should not have allowed this */
171 #error no source of random numbers configured
172 #endif