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(). 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 35964 : pg_strong_random_init(void) 59 : { 60 : /* No initialization needed */ 61 35964 : } 62 : 63 : bool 64 63920 : 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 63920 : for (i = 0; i < NUM_RAND_POLL_RETRIES; i++) 80 : { 81 63920 : if (RAND_status() == 1) 82 : { 83 : /* The CSPRNG is sufficiently seeded */ 84 63920 : break; 85 : } 86 : 87 0 : RAND_poll(); 88 : } 89 : 90 63920 : if (RAND_bytes(buf, len) == 1) 91 63920 : 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