diff options
Diffstat (limited to 'modules/pam_timestamp/hmac_openssl_wrapper.c')
-rw-r--r-- | modules/pam_timestamp/hmac_openssl_wrapper.c | 69 |
1 files changed, 50 insertions, 19 deletions
diff --git a/modules/pam_timestamp/hmac_openssl_wrapper.c b/modules/pam_timestamp/hmac_openssl_wrapper.c index 2549c1db..8fa6068e 100644 --- a/modules/pam_timestamp/hmac_openssl_wrapper.c +++ b/modules/pam_timestamp/hmac_openssl_wrapper.c @@ -49,6 +49,7 @@ #include <openssl/evp.h> #include <openssl/params.h> #include <openssl/core_names.h> +#include <openssl/rand.h> #include <security/pam_ext.h> #include <security/pam_modutil.h> @@ -56,6 +57,10 @@ #include "hmac_openssl_wrapper.h" #include "pam_inline.h" +#ifdef HAVE_SYS_RANDOM_H +#include <sys/random.h> +#endif + #define LOGIN_DEFS "/etc/login.defs" #define CRYPTO_KEY "HMAC_CRYPTO_ALGO" #define DEFAULT_ALGORITHM "SHA512" @@ -81,30 +86,48 @@ get_crypto_algorithm(pam_handle_t *pamh, int debug){ } static int +PAM_NONNULL((1, 2)) generate_key(pam_handle_t *pamh, char **key, size_t key_size) { int fd = 0; - size_t bytes_read = 0; - char * tmp = NULL; + ssize_t bytes_read = 0; + char *tmp = *key = NULL; - fd = open("/dev/urandom", O_RDONLY); - if (fd == -1) { - pam_syslog(pamh, LOG_ERR, "Cannot open /dev/urandom: %m"); + tmp = calloc(1, key_size); + if (!tmp) { + pam_syslog(pamh, LOG_CRIT, "Not enough memory"); return PAM_AUTH_ERR; } - tmp = malloc(key_size); - if (!tmp) { - pam_syslog(pamh, LOG_CRIT, "Not enough memory"); - close(fd); + /* Try to get random data from OpenSSL first */ + if (RAND_priv_bytes((unsigned char *)tmp, key_size) == 1) { + *key = tmp; + return PAM_SUCCESS; + } + +#ifdef HAVE_GETRANDOM + /* Fallback to getrandom(2) if available */ + if (getrandom(tmp, key_size, 0) == (ssize_t)key_size) { + *key = tmp; + return PAM_SUCCESS; + } +#endif + + /* Fallback to /dev/urandom */ + fd = open("/dev/urandom", O_RDONLY); + if (fd == -1) { + pam_syslog(pamh, LOG_ERR, "Cannot open /dev/urandom: %m"); + pam_overwrite_n(tmp, key_size); + free(tmp); return PAM_AUTH_ERR; } bytes_read = pam_modutil_read(fd, tmp, key_size); close(fd); - if (bytes_read < key_size) { + if (bytes_read < 0 || (size_t)bytes_read < key_size) { pam_syslog(pamh, LOG_ERR, "Short read on random device"); + pam_overwrite_n(tmp, key_size); free(tmp); return PAM_AUTH_ERR; } @@ -115,10 +138,11 @@ generate_key(pam_handle_t *pamh, char **key, size_t key_size) } static int +PAM_NONNULL((1, 3, 4)) read_file(pam_handle_t *pamh, int fd, char **text, size_t *text_length) { struct stat st; - size_t bytes_read = 0; + ssize_t bytes_read = 0; char *tmp = NULL; if (fstat(fd, &st) == -1) { @@ -133,7 +157,13 @@ read_file(pam_handle_t *pamh, int fd, char **text, size_t *text_length) return PAM_AUTH_ERR; } - tmp = malloc(st.st_size); + if ((uintmax_t)st.st_size > (uintmax_t)INT_MAX) { + pam_syslog(pamh, LOG_ERR, "Key file is too large"); + close(fd); + return PAM_AUTH_ERR; + } + + tmp = calloc(1, st.st_size); if (!tmp) { pam_syslog(pamh, LOG_CRIT, "Not enough memory"); close(fd); @@ -143,7 +173,7 @@ read_file(pam_handle_t *pamh, int fd, char **text, size_t *text_length) bytes_read = pam_modutil_read(fd, tmp, st.st_size); close(fd); - if (bytes_read < (size_t)st.st_size) { + if (bytes_read < st.st_size) { pam_syslog(pamh, LOG_ERR, "Short read on key file"); pam_overwrite_n(tmp, st.st_size); free(tmp); @@ -157,11 +187,12 @@ read_file(pam_handle_t *pamh, int fd, char **text, size_t *text_length) } static int +PAM_NONNULL((1, 2, 3)) write_file(pam_handle_t *pamh, const char *file_name, char *text, size_t text_length, uid_t owner, gid_t group) { int fd = 0; - size_t bytes_written = 0; + ssize_t bytes_written = 0; fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC, @@ -184,8 +215,9 @@ write_file(pam_handle_t *pamh, const char *file_name, char *text, bytes_written = pam_modutil_write(fd, text, text_length); close(fd); - if (bytes_written < text_length) { + if (bytes_written < 0 || (size_t)bytes_written < text_length) { pam_syslog(pamh, LOG_ERR, "Short write on %s", file_name); + pam_overwrite_n(text, text_length); free(text); return PAM_AUTH_ERR; } @@ -194,6 +226,7 @@ write_file(pam_handle_t *pamh, const char *file_name, char *text, } static int +PAM_NONNULL((1, 2, 3)) key_management(pam_handle_t *pamh, const char *file_name, char **text, size_t text_length, uid_t owner, gid_t group) { @@ -268,7 +301,7 @@ hmac_management(pam_handle_t *pamh, int debug, void **out, size_t *out_length, goto done; } - hmac_message = (unsigned char*)malloc(sizeof(unsigned char) * MAX_HMAC_LENGTH); + hmac_message = malloc(sizeof(unsigned char) * MAX_HMAC_LENGTH); if (!hmac_message) { pam_syslog(pamh, LOG_CRIT, "Not enough memory"); goto done; @@ -291,9 +324,7 @@ hmac_management(pam_handle_t *pamh, int debug, void **out, size_t *out_length, ret = PAM_SUCCESS; done: - if (hmac_message != NULL) { - free(hmac_message); - } + free(hmac_message); if (key != NULL) { pam_overwrite_n(key, key_length); free(key); |