Skip to content

Commit 778cc66

Browse files
committed
Add two fallback options to secure randomness generation. If getrandom() fails, we first try manually sourcing from /dev/urandom ourselves to exclude this being a simple library error. If this does not work either, we resort to using mbedtls' DRBG method.
Signed-off-by: DL6ER <[email protected]>
1 parent 99165db commit 778cc66

File tree

5 files changed

+61
-11
lines changed

5 files changed

+61
-11
lines changed

src/api/2fa.c

+1
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ int generateTOTP(struct ftl_conn *api)
267267
{
268268
// Generate random secret using the system's random number generator
269269
uint8_t random_secret[RFC6238_SECRET_LEN];
270+
log_info("A");
270271
if(!get_secure_randomness(random_secret, sizeof(random_secret)))
271272
return send_json_error(api, 500, "internal_error", "Failed to generate random secret", strerror(errno));
272273

src/api/auth.c

+1
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ static int send_api_auth_status(struct ftl_conn *api, const int user_id, const t
435435
static void generateSID(char *sid)
436436
{
437437
uint8_t raw_sid[SID_SIZE];
438+
log_info("B");
438439
if(!get_secure_randomness(raw_sid, sizeof(raw_sid)))
439440
return;
440441

src/config/password.c

+27-11
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,7 @@ static char * __attribute__((malloc)) double_sha256_password(const char *passwor
9393

9494
bool get_secure_randomness(uint8_t *buffer, const size_t length)
9595
{
96-
ssize_t result;
97-
96+
ssize_t result = -1;
9897
// First try to get randomness in non-blocking mode and print a warning when not enough entropy is available right now
9998
do {
10099
result = getrandom(buffer, length, GRND_NONBLOCK);
@@ -103,32 +102,49 @@ bool get_secure_randomness(uint8_t *buffer, const size_t length)
103102
// If not enough entropy is available right now, try again in blocking mode
104103
if (result < 0 && errno == EAGAIN)
105104
{
106-
log_warn("getrandom() failed in get_secure_randomness(): Not enough entropy available right now, retrying in blocking mode");
105+
log_warn("Not enough entropy available right now for generating secure randomness, retrying in blocking mode");
107106
// Sleep for 1 second to give the kernel some time to gather entropy
108107
sleepms(1000);
109108
}
110109
else
111110
{
112111
// If the first try was successful, return the result
113112
if (result >= 0)
114-
return true;
113+
goto random_success;
115114
}
116115
do {
117116
result = getrandom(buffer, length, 0);
118117
} while (result < 0 && errno == EINTR);
119118

120-
if (result < 0)
119+
if(result < 0)
121120
{
122-
const int err = errno;
123-
log_err("getrandom() failed in get_secure_randomness(): %s", strerror(errno));
124-
errno = err;
125-
return false;
121+
log_warn("Getting secure randomness failed (%s), trying /dev/urandom", strerror(errno));
122+
result = getrandom_fallback(buffer, length, 0);
123+
if(result < 0 || result < (ssize_t)length)
124+
{
125+
log_warn("Fallback failed, trying internal DRBG generator");
126+
result = drbg_random(buffer, length);
127+
if(result < 0)
128+
{
129+
// Warning will be printed by drbg_random()
130+
return false;
131+
}
132+
133+
log_info("Internal DRBG generator successfully used");
134+
}
135+
else
136+
log_info("Fallback to /dev/urandom successful");
126137
}
127-
else if((size_t)result != length)
138+
139+
// Check if enough bytes were generated
140+
if(result != (ssize_t)length)
128141
{
129-
log_err("getrandom() failed in get_secure_randomness(): Not enough bytes generated (%zu != %zu)", (size_t)result, length);
142+
log_err("Randomness generator failed: not enough bytes generated (%zd != %zu)", result, length);
130143
return false;
131144
}
145+
146+
random_success:
147+
log_debug(DEBUG_ANY, "Generated %zd bytes of secure randomness", result);
132148
return true;
133149
}
134150

src/webserver/x509.c

+29
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,29 @@ void destroy_entropy(void)
9898
mbedtls_ctr_drbg_free(&ctr_drbg);
9999
}
100100

101+
/**
102+
* @brief Generates random bytes using the CTR_DRBG (Counter mode Deterministic
103+
* Random Byte Generator).
104+
*
105+
* @param output Pointer to the buffer where the generated random bytes will be
106+
* stored.
107+
* @param len The number of random bytes to generate.
108+
* @return The number of bytes generated on success, or -1 on failure.
109+
*/
110+
ssize_t drbg_random(unsigned char *output, size_t len)
111+
{
112+
init_entropy();
113+
const int ret = mbedtls_ctr_drbg_random(&ctr_drbg, output, len);
114+
if(ret != 0)
115+
{
116+
log_err("mbedtls_ctr_drbg_random returned %d\n", ret);
117+
return -1;
118+
}
119+
120+
// Return number of bytes generated
121+
return len;
122+
}
123+
101124
// Generate private RSA key
102125
static int generate_private_key_rsa(mbedtls_pk_context *key,
103126
unsigned char key_buffer[])
@@ -701,4 +724,10 @@ void destroy_entropy(void)
701724
{
702725
}
703726

727+
ssize_t drbg_random(unsigned char *output, size_t len)
728+
{
729+
log_warn("FTL was not compiled with mbedtls support, fallback random number generator not available");
730+
return -1;
731+
}
732+
704733
#endif

src/webserver/x509.h

+3
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@
1717

1818
#include "enums.h"
1919
#include <stdbool.h>
20+
// ssize_t
21+
#include <unistd.h>
2022

2123
bool generate_certificate(const char* certfile, bool rsa, const char *domain);
2224
enum cert_check read_certificate(const char* certfile, const char *domain, const bool private_key);
2325

2426
bool init_entropy(void);
2527
void destroy_entropy(void);
28+
ssize_t drbg_random(unsigned char *output, size_t len);
2629

2730
#endif // X509_H

0 commit comments

Comments
 (0)