PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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-2024, 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
57void
59{
60 /* No initialization needed */
61}
62
63bool
64pg_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 for (i = 0; i < NUM_RAND_POLL_RETRIES; i++)
80 {
81 if (RAND_status() == 1)
82 {
83 /* The CSPRNG is sufficiently seeded */
84 break;
85 }
86
87 RAND_poll();
88 }
89
90 if (RAND_bytes(buf, len) == 1)
91 return true;
92 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 */
102static HCRYPTPROV hProvider = 0;
103
104void
106{
107 /* No initialization needed on WIN32 */
108}
109
110bool
111pg_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
143void
145{
146 /* No initialization needed */
147}
148
149bool
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
#define close(a)
Definition: win32.h:12
#define read(a, b, c)
Definition: win32.h:13
int i
Definition: isn.c:72
const void size_t len
bool pg_strong_random(void *buf, size_t len)
void pg_strong_random_init(void)
static char * buf
Definition: pg_test_fsync.c:72
#define EINTR
Definition: win32_port.h:374