aboutsummaryrefslogtreecommitdiff
path: root/modules/pam_timestamp/hmac_openssl_wrapper.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/pam_timestamp/hmac_openssl_wrapper.c')
-rw-r--r--modules/pam_timestamp/hmac_openssl_wrapper.c69
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);