Mercurial > dropbear
comparison dbrandom.c @ 1698:f966834f0f9c
Use Linux getrandom() to ensure random device is initialised
Remove old code warning about random device being not ready,
/dev/random isn't used by default anyway.
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Thu, 28 May 2020 22:50:41 +0800 |
parents | 60fceff95858 |
children | 6e5037ae2c1c |
comparison
equal
deleted
inserted
replaced
1697:789466c5956b | 1698:f966834f0f9c |
---|---|
47 * It is important to ensure that counter doesn't wrap around before we | 47 * It is important to ensure that counter doesn't wrap around before we |
48 * feed in new entropy. | 48 * feed in new entropy. |
49 * | 49 * |
50 */ | 50 */ |
51 | 51 |
52 /* Pass len=0 to hash an entire file */ | 52 /* Pass wantlen=0 to hash an entire file */ |
53 static int | 53 static int |
54 process_file(hash_state *hs, const char *filename, | 54 process_file(hash_state *hs, const char *filename, |
55 unsigned int len, int prngd) | 55 unsigned int wantlen, int prngd) { |
56 { | |
57 static int already_blocked = 0; | |
58 int readfd; | 56 int readfd; |
59 unsigned int readcount; | 57 unsigned int readcount; |
60 int ret = DROPBEAR_FAILURE; | 58 int ret = DROPBEAR_FAILURE; |
61 | 59 |
60 if (prngd) { | |
62 #if DROPBEAR_USE_PRNGD | 61 #if DROPBEAR_USE_PRNGD |
63 if (prngd) | |
64 { | |
65 readfd = connect_unix(filename); | 62 readfd = connect_unix(filename); |
66 } | 63 #endif |
67 else | 64 } else { |
68 #endif | |
69 { | |
70 readfd = open(filename, O_RDONLY); | 65 readfd = open(filename, O_RDONLY); |
71 } | 66 } |
72 | 67 |
73 if (readfd < 0) { | 68 if (readfd < 0) { |
74 goto out; | 69 goto out; |
75 } | 70 } |
76 | 71 |
77 readcount = 0; | 72 readcount = 0; |
78 while (len == 0 || readcount < len) | 73 while (wantlen == 0 || readcount < wantlen) { |
79 { | |
80 int readlen, wantread; | 74 int readlen, wantread; |
81 unsigned char readbuf[4096]; | 75 unsigned char readbuf[4096]; |
82 if (!already_blocked && !prngd) | 76 if (wantlen == 0) { |
83 { | |
84 int res; | |
85 struct timeval timeout; | |
86 fd_set read_fds; | |
87 | |
88 timeout.tv_sec = 2; | |
89 timeout.tv_usec = 0; | |
90 | |
91 DROPBEAR_FD_ZERO(&read_fds); | |
92 FD_SET(readfd, &read_fds); | |
93 res = select(readfd + 1, &read_fds, NULL, NULL, &timeout); | |
94 if (res == 0) | |
95 { | |
96 dropbear_log(LOG_WARNING, "Warning: Reading the randomness source '%s' seems to have blocked.\nYou may need to find a better entropy source.", filename); | |
97 already_blocked = 1; | |
98 } | |
99 } | |
100 | |
101 if (len == 0) | |
102 { | |
103 wantread = sizeof(readbuf); | 77 wantread = sizeof(readbuf); |
104 } | 78 } else { |
105 else | 79 wantread = MIN(sizeof(readbuf), wantlen-readcount); |
106 { | |
107 wantread = MIN(sizeof(readbuf), len-readcount); | |
108 } | 80 } |
109 | 81 |
110 #if DROPBEAR_USE_PRNGD | 82 #if DROPBEAR_USE_PRNGD |
111 if (prngd) | 83 if (prngd) { |
112 { | |
113 char egdcmd[2]; | 84 char egdcmd[2]; |
114 egdcmd[0] = 0x02; /* blocking read */ | 85 egdcmd[0] = 0x02; /* blocking read */ |
115 egdcmd[1] = (unsigned char)wantread; | 86 egdcmd[1] = (unsigned char)wantread; |
116 if (write(readfd, egdcmd, 2) < 0) | 87 if (write(readfd, egdcmd, 2) < 0) { |
117 { | |
118 dropbear_exit("Can't send command to egd"); | 88 dropbear_exit("Can't send command to egd"); |
119 } | 89 } |
120 } | 90 } |
121 #endif | 91 #endif |
122 | |
123 readlen = read(readfd, readbuf, wantread); | 92 readlen = read(readfd, readbuf, wantread); |
124 if (readlen <= 0) { | 93 if (readlen <= 0) { |
125 if (readlen < 0 && errno == EINTR) { | 94 if (readlen < 0 && errno == EINTR) { |
126 continue; | 95 continue; |
127 } | 96 } |
128 if (readlen == 0 && len == 0) | 97 if (readlen == 0 && wantlen == 0) { |
129 { | |
130 /* whole file was read as requested */ | 98 /* whole file was read as requested */ |
131 break; | 99 break; |
132 } | 100 } |
133 goto out; | 101 goto out; |
134 } | 102 } |
191 counter = 0; | 159 counter = 0; |
192 donerandinit = 1; | 160 donerandinit = 1; |
193 } | 161 } |
194 #endif | 162 #endif |
195 | 163 |
164 | |
165 #ifdef HAVE_GETRANDOM | |
166 /* Reads entropy seed with getrandom(). | |
167 * May block if the kernel isn't ready. | |
168 * Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ | |
169 static int process_getrandom(hash_state *hs) { | |
170 char buf[INIT_SEED_SIZE]; | |
171 ssize_t ret; | |
172 | |
173 /* First try non-blocking so that we can warn about waiting */ | |
174 ret = getrandom(buf, sizeof(buf), GRND_NONBLOCK); | |
175 if (ret == -1) { | |
176 if (errno == ENOSYS) { | |
177 /* Old kernel */ | |
178 return DROPBEAR_FAILURE; | |
179 } | |
180 /* Other errors fall through to blocking getrandom() */ | |
181 TRACE(("first getrandom() failed: %d %s", errno, strerror(errno))) | |
182 if (errno == EAGAIN) { | |
183 dropbear_log(LOG_WARNING, "Waiting for kernel randomness to be initialised..."); | |
184 } | |
185 } | |
186 | |
187 /* Wait blocking if needed. Loop in case we get EINTR */ | |
188 while (ret != sizeof(buf)) { | |
189 ret = getrandom(buf, sizeof(buf), 0); | |
190 | |
191 if (ret == sizeof(buf)) { | |
192 /* Success */ | |
193 break; | |
194 } | |
195 if (ret == -1 && errno == EINTR) { | |
196 /* Try again. */ | |
197 continue; | |
198 } | |
199 if (ret >= 0) { | |
200 TRACE(("Short read %zd from getrandom() shouldn't happen", ret)) | |
201 /* Try again? */ | |
202 continue; | |
203 } | |
204 | |
205 /* Unexpected problem, fall back to /dev/urandom */ | |
206 TRACE(("2nd getrandom() failed: %d %s", errno, strerror(errno))) | |
207 break; | |
208 } | |
209 | |
210 if (ret == sizeof(buf)) { | |
211 /* Success, stir in the entropy */ | |
212 sha1_process(hs, (void*)buf, sizeof(buf)); | |
213 return DROPBEAR_SUCCESS; | |
214 } | |
215 | |
216 return DROPBEAR_FAILURE; | |
217 | |
218 } | |
219 #endif /* HAVE_GETRANDOM */ | |
220 | |
196 /* Initialise the prng from /dev/urandom or prngd. This function can | 221 /* Initialise the prng from /dev/urandom or prngd. This function can |
197 * be called multiple times */ | 222 * be called multiple times */ |
198 void seedrandom() { | 223 void seedrandom() { |
199 | 224 |
200 hash_state hs; | 225 hash_state hs; |
201 | 226 |
202 pid_t pid; | 227 pid_t pid; |
203 struct timeval tv; | 228 struct timeval tv; |
204 clock_t clockval; | 229 clock_t clockval; |
230 int urandom_seeded = 0; | |
205 | 231 |
206 #if DROPBEAR_FUZZ | 232 #if DROPBEAR_FUZZ |
207 if (fuzz.fuzzing) { | 233 if (fuzz.fuzzing) { |
208 return; | 234 return; |
209 } | 235 } |
213 sha1_init(&hs); | 239 sha1_init(&hs); |
214 | 240 |
215 /* existing state */ | 241 /* existing state */ |
216 sha1_process(&hs, (void*)hashpool, sizeof(hashpool)); | 242 sha1_process(&hs, (void*)hashpool, sizeof(hashpool)); |
217 | 243 |
244 #ifdef HAVE_GETRANDOM | |
245 if (process_getrandom(&hs) == DROPBEAR_SUCCESS) { | |
246 urandom_seeded = 1; | |
247 } | |
248 #endif | |
249 | |
250 if (!urandom_seeded) { | |
218 #if DROPBEAR_USE_PRNGD | 251 #if DROPBEAR_USE_PRNGD |
219 if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1) | 252 if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1) |
220 != DROPBEAR_SUCCESS) { | 253 != DROPBEAR_SUCCESS) { |
221 dropbear_exit("Failure reading random device %s", | 254 dropbear_exit("Failure reading random device %s", |
222 DROPBEAR_PRNGD_SOCKET); | 255 DROPBEAR_PRNGD_SOCKET); |
223 } | 256 urandom_seeded = 1; |
257 } | |
224 #else | 258 #else |
225 /* non-blocking random source (probably /dev/urandom) */ | 259 /* non-blocking random source (probably /dev/urandom) */ |
226 if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0) | 260 if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0) |
227 != DROPBEAR_SUCCESS) { | 261 != DROPBEAR_SUCCESS) { |
228 dropbear_exit("Failure reading random device %s", | 262 dropbear_exit("Failure reading random device %s", |
229 DROPBEAR_URANDOM_DEV); | 263 DROPBEAR_URANDOM_DEV); |
230 } | 264 urandom_seeded = 1; |
231 #endif | 265 } |
266 #endif | |
267 } /* urandom_seeded */ | |
232 | 268 |
233 /* A few other sources to fall back on. | 269 /* A few other sources to fall back on. |
234 * Add more here for other platforms */ | 270 * Add more here for other platforms */ |
235 #ifdef __linux__ | 271 #ifdef __linux__ |
236 /* Seems to be a reasonable source of entropy from timers. Possibly hard | 272 /* Seems to be a reasonable source of entropy from timers. Possibly hard |