Age Owner TLA 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-2023, 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().
35 : *
36 : * We rely on system facilities for actually generating the numbers.
37 : * We support a number of sources:
38 : *
39 : * 1. OpenSSL's RAND_bytes()
40 : * 2. Windows' CryptGenRandom() function
41 : * 3. /dev/urandom
42 : *
43 : * Returns true on success, and false if none of the sources
44 : * were available. NB: It is important to check the return value!
45 : * Proceeding with key generation when no random data was available
46 : * would lead to predictable keys and security issues.
47 : */
48 :
49 :
50 :
51 : #ifdef USE_OPENSSL
52 :
53 : #include <openssl/rand.h>
54 :
55 : void
870 magnus 56 CBC 12835 : pg_strong_random_init(void)
57 : {
58 : /*
59 : * Make sure processes do not share OpenSSL randomness state. This is no
60 : * longer required in OpenSSL 1.1.1 and later versions, but until we drop
61 : * support for version < 1.1.1 we need to do this.
62 : */
63 12835 : RAND_poll();
64 12835 : }
65 :
66 : bool
67 26409 : pg_strong_random(void *buf, size_t len)
68 : {
69 : int i;
70 :
71 : /*
72 : * Check that OpenSSL's CSPRNG has been sufficiently seeded, and if not
73 : * add more seed data using RAND_poll(). With some older versions of
74 : * OpenSSL, it may be necessary to call RAND_poll() a number of times. If
75 : * RAND_poll() fails to generate seed data within the given amount of
76 : * retries, subsequent RAND_bytes() calls will fail, but we allow that to
77 : * happen to let pg_strong_random() callers handle that with appropriate
78 : * error handling.
79 : */
80 : #define NUM_RAND_POLL_RETRIES 8
81 :
1724 dean.a.rasheed 82 26409 : for (i = 0; i < NUM_RAND_POLL_RETRIES; i++)
83 : {
84 26409 : if (RAND_status() == 1)
85 : {
86 : /* The CSPRNG is sufficiently seeded */
87 26409 : break;
88 : }
89 :
988 noah 90 UBC 0 : RAND_poll();
91 : }
92 :
2316 heikki.linnakangas 93 CBC 26409 : if (RAND_bytes(buf, len) == 1)
94 26409 : return true;
2316 heikki.linnakangas 95 UBC 0 : return false;
96 : }
97 :
98 : #elif WIN32
99 :
100 : #include <wincrypt.h>
101 : /*
102 : * Cache a global crypto provider that only gets freed when the process
103 : * exits, in case we need random numbers more than once.
104 : */
105 : static HCRYPTPROV hProvider = 0;
106 :
107 : void
108 : pg_strong_random_init(void)
109 : {
110 : /* No initialization needed on WIN32 */
111 : }
112 :
113 : bool
114 : pg_strong_random(void *buf, size_t len)
115 : {
116 : if (hProvider == 0)
117 : {
118 : if (!CryptAcquireContext(&hProvider,
119 : NULL,
120 : MS_DEF_PROV,
121 : PROV_RSA_FULL,
122 : CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
123 : {
124 : /*
125 : * On failure, set back to 0 in case the value was for some reason
126 : * modified.
127 : */
128 : hProvider = 0;
129 : }
130 : }
131 : /* Re-check in case we just retrieved the provider */
132 : if (hProvider != 0)
133 : {
134 : if (CryptGenRandom(hProvider, len, buf))
135 : return true;
136 : }
137 : return false;
138 : }
139 :
140 : #else /* not USE_OPENSSL or WIN32 */
141 :
142 : /*
143 : * Without OpenSSL or Win32 support, just read /dev/urandom ourselves.
144 : */
145 :
146 : void
147 : pg_strong_random_init(void)
148 : {
149 : /* No initialization needed */
150 : }
151 :
152 : bool
153 : pg_strong_random(void *buf, size_t len)
154 : {
155 : int f;
156 : char *p = buf;
157 : ssize_t res;
158 :
159 : f = open("/dev/urandom", O_RDONLY, 0);
160 : if (f == -1)
161 : return false;
162 :
163 : while (len)
164 : {
165 : res = read(f, p, len);
166 : if (res <= 0)
167 : {
168 : if (errno == EINTR)
169 : continue; /* interrupted by signal, just retry */
170 :
171 : close(f);
172 : return false;
173 : }
174 :
175 : p += res;
176 : len -= res;
177 : }
178 :
179 : close(f);
180 : return true;
181 : }
182 : #endif
|