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 : * Copyright (c) 1996-2017, PostgreSQL Global Development Group
10 : *
11 : * IDENTIFICATION
12 : * src/port/pg_strong_random.c
13 : *
14 : *-------------------------------------------------------------------------
15 : */
16 :
17 : #ifndef FRONTEND
18 : #include "postgres.h"
19 : #else
20 : #include "postgres_fe.h"
21 : #endif
22 :
23 : #include <fcntl.h>
24 : #include <unistd.h>
25 : #include <sys/time.h>
26 :
27 : #ifdef USE_OPENSSL
28 : #include <openssl/rand.h>
29 : #endif
30 : #ifdef WIN32
31 : #include <wincrypt.h>
32 : #endif
33 :
34 : #ifdef WIN32
35 : /*
36 : * Cache a global crypto provider that only gets freed when the process
37 : * exits, in case we need random numbers more than once.
38 : */
39 : static HCRYPTPROV hProvider = 0;
40 : #endif
41 :
42 : #if defined(USE_DEV_URANDOM)
43 : /*
44 : * Read (random) bytes from a file.
45 : */
46 : static bool
47 338 : random_from_file(char *filename, void *buf, size_t len)
48 : {
49 : int f;
50 338 : char *p = buf;
51 : ssize_t res;
52 :
53 338 : f = open(filename, O_RDONLY, 0);
54 338 : if (f == -1)
55 0 : return false;
56 :
57 1014 : while (len)
58 : {
59 338 : res = read(f, p, len);
60 338 : if (res <= 0)
61 : {
62 0 : if (errno == EINTR)
63 0 : continue; /* interrupted by signal, just retry */
64 :
65 0 : close(f);
66 0 : return false;
67 : }
68 :
69 338 : p += res;
70 338 : len -= res;
71 : }
72 :
73 338 : close(f);
74 338 : return true;
75 : }
76 : #endif
77 :
78 : /*
79 : * pg_strong_random
80 : *
81 : * Generate requested number of random bytes. The returned bytes are
82 : * cryptographically secure, suitable for use e.g. in authentication.
83 : *
84 : * We rely on system facilities for actually generating the numbers.
85 : * We support a number of sources:
86 : *
87 : * 1. OpenSSL's RAND_bytes()
88 : * 2. Windows' CryptGenRandom() function
89 : * 3. /dev/urandom
90 : *
91 : * The configure script will choose which one to use, and set
92 : * a USE_*_RANDOM flag accordingly.
93 : *
94 : * Returns true on success, and false if none of the sources
95 : * were available. NB: It is important to check the return value!
96 : * Proceeding with key generation when no random data was available
97 : * would lead to predictable keys and security issues.
98 : */
99 : bool
100 338 : pg_strong_random(void *buf, size_t len)
101 : {
102 : /*
103 : * When built with OpenSSL, use OpenSSL's RAND_bytes function.
104 : */
105 : #if defined(USE_OPENSSL_RANDOM)
106 : if (RAND_bytes(buf, len) == 1)
107 : return true;
108 : return false;
109 :
110 : /*
111 : * Windows has CryptoAPI for strong cryptographic numbers.
112 : */
113 : #elif defined(USE_WIN32_RANDOM)
114 : if (hProvider == 0)
115 : {
116 : if (!CryptAcquireContext(&hProvider,
117 : NULL,
118 : MS_DEF_PROV,
119 : PROV_RSA_FULL,
120 : CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
121 : {
122 : /*
123 : * On failure, set back to 0 in case the value was for some reason
124 : * modified.
125 : */
126 : hProvider = 0;
127 : }
128 : }
129 : /* Re-check in case we just retrieved the provider */
130 : if (hProvider != 0)
131 : {
132 : if (CryptGenRandom(hProvider, len, buf))
133 : return true;
134 : }
135 : return false;
136 :
137 : /*
138 : * Read /dev/urandom ourselves.
139 : */
140 : #elif defined(USE_DEV_URANDOM)
141 338 : if (random_from_file("/dev/urandom", buf, len))
142 338 : return true;
143 0 : return false;
144 :
145 : #else
146 : /* The autoconf script should not have allowed this */
147 : #error no source of random numbers configured
148 : #endif
149 : }
|