Age Owner Branch data 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-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().
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
1241 magnus@hagander.net 56 :CBC 19834 : 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 : 19834 : RAND_poll();
64 : 19834 : }
65 : :
66 : : bool
67 : 35994 : 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 : :
2095 dean.a.rasheed@gmail 82 [ + - ]: 35994 : for (i = 0; i < NUM_RAND_POLL_RETRIES; i++)
83 : : {
84 [ + - ]: 35994 : if (RAND_status() == 1)
85 : : {
86 : : /* The CSPRNG is sufficiently seeded */
87 : 35994 : break;
88 : : }
89 : :
1359 noah@leadboat.com 90 :UBC 0 : RAND_poll();
91 : : }
92 : :
2687 heikki.linnakangas@i 93 [ + - ]:CBC 35994 : if (RAND_bytes(buf, len) == 1)
94 : 35994 : return true;
2687 heikki.linnakangas@i 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
|