diff --git a/src/api/2fa.c b/src/api/2fa.c index 164f70007..b23165f65 100644 --- a/src/api/2fa.c +++ b/src/api/2fa.c @@ -13,8 +13,6 @@ #include "webserver/json_macros.h" #include "log.h" #include "config/config.h" -// getrandom() -#include "daemon.h" // generate_password() #include "config/password.h" @@ -269,10 +267,8 @@ int generateTOTP(struct ftl_conn *api) { // Generate random secret using the system's random number generator uint8_t random_secret[RFC6238_SECRET_LEN]; - if(getrandom(random_secret, sizeof(random_secret), 0) < (ssize_t)sizeof(random_secret)) - { + if(!get_secure_randomness(random_secret, sizeof(random_secret))) return send_json_error(api, 500, "internal_error", "Failed to generate random secret", strerror(errno)); - } // Encode base32 secret const size_t base32_len = sizeof(random_secret)*8/5+1; diff --git a/src/api/auth.c b/src/api/auth.c index 285f9d7d0..62165439f 100644 --- a/src/api/auth.c +++ b/src/api/auth.c @@ -435,11 +435,9 @@ static int send_api_auth_status(struct ftl_conn *api, const int user_id, const t static void generateSID(char *sid) { uint8_t raw_sid[SID_SIZE]; - if(getrandom(raw_sid, sizeof(raw_sid), 0) < 0) - { - log_err("getrandom() failed in generateSID(): %s", strerror(errno)); + if(!get_secure_randomness(raw_sid, sizeof(raw_sid))) return; - } + base64_encode_raw(NETTLE_SIGN sid, SID_BITSIZE/8, raw_sid); sid[SID_SIZE-1] = '\0'; } diff --git a/src/config/password.c b/src/config/password.c index b85b87cb0..14b99c127 100644 --- a/src/config/password.c +++ b/src/config/password.c @@ -91,6 +91,47 @@ static char * __attribute__((malloc)) double_sha256_password(const char *passwor return strdup(response); } +bool get_secure_randomness(uint8_t *buffer, const size_t length) +{ + ssize_t result; + + // First try to get randomness in non-blocking mode and print a warning when not enough entropy is available right now + do { + result = getrandom(buffer, length, GRND_NONBLOCK); + } while (result < 0 && errno == EINTR); + + // If not enough entropy is available right now, try again in blocking mode + if (result < 0 && errno == EAGAIN) + { + log_warn("getrandom() failed in get_secure_randomness(): Not enough entropy available right now, retrying in blocking mode"); + // Sleep for 1 second to give the kernel some time to gather entropy + sleepms(1000); + } + else + { + // If the first try was successful, return the result + if (result >= 0) + return true; + } + do { + result = getrandom(buffer, length, 0); + } while (result < 0 && errno == EINTR); + + if (result < 0) + { + const int err = errno; + log_err("getrandom() failed in get_secure_randomness(): %s", strerror(errno)); + errno = err; + return false; + } + else if((size_t)result != length) + { + log_err("getrandom() failed in get_secure_randomness(): Not enough bytes generated (%zu != %zu)", (size_t)result, length); + return false; + } + return true; +} + static char * __attribute__((malloc)) base64_encode(const uint8_t *data, const size_t length) { // Base64 encoding requires 4 bytes for every 3 bytes of input, plus @@ -328,11 +369,8 @@ char * __attribute__((malloc)) create_password(const char *password) // Generate a 128 bit random salt // genrandom() returns cryptographically secure random data uint8_t salt[SALT_LEN] = { 0 }; - if(getrandom(salt, sizeof(salt), 0) < 0) - { - log_err("getrandom() failed in create_password(): %s", strerror(errno)); + if(!get_secure_randomness(salt, sizeof(salt))) return NULL; - } // Generate balloon PHC-encoded password hash return balloon_password(password, salt, true); @@ -527,11 +565,8 @@ int run_performance_test(void) // Generate a 128 bit random salt // genrandom() returns cryptographically secure random data uint8_t salt[SALT_LEN] = { 0 }; - if(getrandom(salt, sizeof(salt), 0) < 0) - { - printf("Could not generate random salt!: %s\n", strerror(errno)); + if(!get_secure_randomness(salt, sizeof(salt))) return EXIT_FAILURE; - } printf("Running time-performance test:\n"); size_t t_t_cost = 16; @@ -675,11 +710,8 @@ bool generate_password(char **password, char **pwhash) // Generate a 256 bit random password // genrandom() returns cryptographically secure random data uint8_t password_raw[APPPW_LEN] = { 0 }; - if(getrandom(password_raw, sizeof(password_raw), 0) < 0) - { - log_err("getrandom() failed in generate_password(): %s", strerror(errno)); + if(!get_secure_randomness(password_raw, sizeof(password_raw))) return false; - } // Encode password as base64 *password = base64_encode(password_raw, sizeof(password_raw)); @@ -698,11 +730,8 @@ bool generate_password(char **password, char **pwhash) // Generate a 128 bit random salt uint8_t salt[SALT_LEN] = { 0 }; - if(getrandom(salt, sizeof(salt), 0) < 0) - { - log_err("getrandom() failed in generate_password(): %s", strerror(errno)); + if(!get_secure_randomness(salt, sizeof(salt))) return false; - } // Generate balloon PHC-encoded password hash *pwhash = balloon_password(*password, salt, true); diff --git a/src/config/password.h b/src/config/password.h index fd6fd3320..aeacb40c5 100644 --- a/src/config/password.h +++ b/src/config/password.h @@ -16,6 +16,7 @@ void sha256_raw_to_hex(uint8_t *data, char *buffer); char *create_password(const char *password) __attribute__((malloc)); +bool get_secure_randomness(uint8_t *buffer, const size_t length); enum password_result verify_login(const char *password); enum password_result verify_password(const char *password, const char *pwhash, const bool rate_limiting); int run_performance_test(void);