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 56 30188 : 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 30188 : RAND_poll(); 64 30188 : } 65 : 66 : bool 67 58908 : 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 : 82 58908 : for (i = 0; i < NUM_RAND_POLL_RETRIES; i++) 83 : { 84 58908 : if (RAND_status() == 1) 85 : { 86 : /* The CSPRNG is sufficiently seeded */ 87 58908 : break; 88 : } 89 : 90 0 : RAND_poll(); 91 : } 92 : 93 58908 : if (RAND_bytes(buf, len) == 1) 94 58908 : return true; 95 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