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
|