diff --git a/pam-1.5.1-timestamp-openssl-hmac-authentication.patch b/pam-1.5.1-timestamp-openssl-hmac-authentication.patch new file mode 100644 index 0000000..abea760 --- /dev/null +++ b/pam-1.5.1-timestamp-openssl-hmac-authentication.patch @@ -0,0 +1,738 @@ +From b3bb13e18a74e9ece825b7de1b81db97ebb107a0 Mon Sep 17 00:00:00 2001 +From: Iker Pedrosa +Date: Thu, 25 Mar 2021 09:43:30 +0100 +Subject: [PATCH] pam_timestamp: replace hmac implementation + +sha1 is no longer recommended as a cryptographic algorithm for +authentication. Thus, the idea of this change is to replace the +implementation provided by hmacsha1 included in pam_timestamp module by +the one in the openssl library. This way, there's no need to maintain +the cryptographic algorithm implementation and it can be easily changed +with a single configuration change. + +modules/pam_timestamp/hmac_openssl_wrapper.c: implement wrapper +functions around openssl's hmac implementation. Moreover, manage the key +generation and its read and write in a file. Include an option to +configure the cryptographic algorithm in login.defs file. +modules/pam_timestamp/hmac_openssl_wrapper.h: likewise. +modules/pam_timestamp/pam_timestamp.c: replace calls to functions +provided by hmacsha1 by functions provided by openssl's wrapper. +configure.ac: include openssl dependecy if it is enabled. +modules/pam_timestamp/Makefile.am: include new files and openssl library +to compilation. +ci/install-dependencies.sh: include openssl library to dependencies. +NEWS: add new item to next release. +Make.xml.rules.in: add stringparam profiling for hmac +doc/custom-man.xsl: change import docbook to one with profiling +modules/pam_timestamp/pam_timestamp.8.xml: add conditional paragraph to +indicate the value in /etc/login.defs that holds the value for the +encryption algorithm + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1947294 +--- + Make.xml.rules.in | 2 +- + NEWS | 5 + + configure.ac | 16 + + doc/custom-man.xsl | 2 +- + modules/pam_timestamp/Makefile.am | 15 +- + modules/pam_timestamp/hmac_openssl_wrapper.c | 381 +++++++++++++++++++ + modules/pam_timestamp/hmac_openssl_wrapper.h | 57 +++ + modules/pam_timestamp/pam_timestamp.8.xml | 5 + + modules/pam_timestamp/pam_timestamp.c | 53 ++- + 10 files changed, 524 insertions(+), 13 deletions(-) + create mode 100644 modules/pam_timestamp/hmac_openssl_wrapper.c + create mode 100644 modules/pam_timestamp/hmac_openssl_wrapper.h + +diff --git a/Make.xml.rules.in b/Make.xml.rules.in +index daa1b97b..27bb510e 100644 +--- a/Make.xml.rules.in ++++ b/Make.xml.rules.in +@@ -21,6 +21,6 @@ README: README.xml + + %.8: %.8.xml + $(XMLLINT) --nonet --xinclude --postvalid --noout $< +- $(XSLTPROC) -o $(srcdir)/$@ --path $(srcdir) --xinclude @STRINGPARAM_VENDORDIR@ --nonet $(top_srcdir)/doc/custom-man.xsl $< ++ $(XSLTPROC) -o $(srcdir)/$@ --path $(srcdir) --xinclude @STRINGPARAM_VENDORDIR@ @STRINGPARAM_HMAC@ --nonet $(top_srcdir)/doc/custom-man.xsl $< + + #CLEANFILES += $(man_MANS) README +diff --git a/NEWS b/NEWS +index 2d49ec39..f4d11303 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,5 +1,10 @@ + Linux-PAM NEWS -- history of user-visible changes. + ++Release next ++* pam_timestamp: change hmac algorithm to call openssl instead of the bundled ++ sha1 implementation if selected. Add option to select the hash ++ algorithm to use with HMAC. ++ + Release 1.5.1 + * pam_unix: fixed CVE-2020-27780 - authentication bypass when a user + doesn't exist and root password is blank +diff --git a/configure.ac b/configure.ac +index bd806473..9c92d0de 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -504,6 +504,22 @@ else + fi + AC_SUBST([STRINGPARAM_VENDORDIR]) + ++AC_ARG_ENABLE([openssl], ++ AS_HELP_STRING([--enable-openssl],[use OpenSSL crypto libraries]), ++ [OPENSSL_ENABLED=$enableval], OPENSSL_ENABLED=no) ++if test "$OPENSSL_ENABLED" = "yes" ; then ++ AC_CHECK_LIB([crypto], [EVP_MAC_CTX_new], ++ [CRYPTO_LIBS="-lcrypto" ++ use_openssl=yes ++ AC_DEFINE([WITH_OPENSSL], 1, [OpenSSL provides crypto algorithm for hmac]) ++ STRINGPARAM_HMAC="--stringparam profile.condition 'openssl_hmac'"], ++ [CRYPTO_LIBS="" ++ STRINGPARAM_HMAC="--stringparam profile.condition 'no_openssl_hmac'"]) ++fi ++AC_SUBST([CRYPTO_LIBS]) ++AC_SUBST([STRINGPARAM_HMAC]) ++AM_CONDITIONAL([COND_USE_OPENSSL], [test "x$use_openssl" = "xyes"]) ++ + dnl Checks for header files. + AC_HEADER_DIRENT + AC_HEADER_STDC +diff --git a/doc/custom-man.xsl b/doc/custom-man.xsl +index 4c35e839..a3408e6c 100644 +--- a/doc/custom-man.xsl ++++ b/doc/custom-man.xsl +@@ -1,6 +1,6 @@ + + +- ++ + + + +diff --git a/modules/pam_timestamp/Makefile.am b/modules/pam_timestamp/Makefile.am +index 1faa324a..d290b85f 100644 +--- a/modules/pam_timestamp/Makefile.am ++++ b/modules/pam_timestamp/Makefile.am +@@ -18,12 +18,12 @@ TESTS = $(dist_check_SCRIPTS) $(check_PROGRAMS) + securelibdir = $(SECUREDIR) + secureconfdir = $(SCONFIGDIR) + +-noinst_HEADERS = hmacsha1.h sha1.h ++noinst_HEADERS = hmacsha1.h sha1.h hmac_openssl_wrapper.h + + AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \ + $(WARN_CFLAGS) + +-pam_timestamp_la_LDFLAGS = -no-undefined -avoid-version -module $(AM_LDFLAGS) ++pam_timestamp_la_LDFLAGS = -no-undefined -avoid-version -module $(AM_LDFLAGS) $(CRYPTO_LIBS) + pam_timestamp_la_LIBADD = $(top_builddir)/libpam/libpam.la + if HAVE_VERSIONING + pam_timestamp_la_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map +@@ -32,7 +32,12 @@ endif + securelib_LTLIBRARIES = pam_timestamp.la + sbin_PROGRAMS = pam_timestamp_check + +-pam_timestamp_la_SOURCES = pam_timestamp.c hmacsha1.c sha1.c ++pam_timestamp_la_SOURCES = pam_timestamp.c ++if COND_USE_OPENSSL ++pam_timestamp_la_SOURCES += hmac_openssl_wrapper.c ++else ++pam_timestamp_la_SOURCES += hmacsha1.c sha1.c ++endif + pam_timestamp_la_CFLAGS = $(AM_CFLAGS) + + pam_timestamp_check_SOURCES = pam_timestamp_check.c +@@ -40,7 +45,11 @@ pam_timestamp_check_CFLAGS = $(AM_CFLAGS) @EXE_CFLAGS@ + pam_timestamp_check_LDADD = $(top_builddir)/libpam/libpam.la + pam_timestamp_check_LDFLAGS = @EXE_LDFLAGS@ + ++if COND_USE_OPENSSL ++hmacfile_SOURCES = hmac_openssl_wrapper.c ++else + hmacfile_SOURCES = hmacfile.c hmacsha1.c sha1.c ++endif + hmacfile_LDADD = $(top_builddir)/libpam/libpam.la + + check_PROGRAMS = hmacfile +diff --git a/modules/pam_timestamp/hmac_openssl_wrapper.c b/modules/pam_timestamp/hmac_openssl_wrapper.c +new file mode 100644 +index 00000000..926c2fb9 +--- /dev/null ++++ b/modules/pam_timestamp/hmac_openssl_wrapper.c +@@ -0,0 +1,381 @@ ++/* Wrapper for hmac openssl implementation. ++ * ++ * Copyright (c) 2021 Red Hat, Inc. ++ * Written by Iker Pedrosa ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, and the entire permission notice in its entirety, ++ * including the disclaimer of warranties. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * ALTERNATIVELY, this product may be distributed under the terms of ++ * the GNU Public License, in which case the provisions of the GPL are ++ * required INSTEAD OF the above restrictions. (This clause is ++ * necessary due to a potential bad interaction between the GPL and ++ * the restrictions contained in a BSD-style copyright.) ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ++ * OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ */ ++ ++#include "config.h" ++ ++#ifdef WITH_OPENSSL ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "hmac_openssl_wrapper.h" ++ ++#define LOGIN_DEFS "/etc/login.defs" ++#define CRYPTO_KEY "HMAC_CRYPTO_ALGO" ++#define DEFAULT_ALGORITHM "SHA512" ++#define MAX_HMAC_LENGTH 512 ++#define MAX_KEY_LENGTH EVP_MAX_KEY_LENGTH ++ ++static char * ++get_crypto_algorithm(pam_handle_t *pamh, int debug){ ++ char *config_value = NULL; ++ ++ config_value = pam_modutil_search_key(pamh, LOGIN_DEFS, CRYPTO_KEY); ++ ++ if (config_value == NULL) { ++ config_value = strdup(DEFAULT_ALGORITHM); ++ if (debug) { ++ pam_syslog(pamh, LOG_DEBUG, ++ "Key [%s] not found, falling back to default algorithm [%s]\n", ++ CRYPTO_KEY, DEFAULT_ALGORITHM); ++ } ++ } ++ ++ return config_value; ++} ++ ++static int ++generate_key(pam_handle_t *pamh, char **key, size_t key_size) ++{ ++ int fd = 0; ++ size_t bytes_read = 0; ++ char * tmp = NULL; ++ ++ fd = open("/dev/urandom", O_RDONLY); ++ if (fd == -1) { ++ pam_syslog(pamh, LOG_ERR, "Cannot open /dev/urandom: %m"); ++ return PAM_AUTH_ERR; ++ } ++ ++ tmp = malloc(key_size); ++ if (!tmp) { ++ pam_syslog(pamh, LOG_CRIT, "Not enough memory"); ++ close(fd); ++ return PAM_AUTH_ERR; ++ } ++ ++ bytes_read = pam_modutil_read(fd, tmp, key_size); ++ close(fd); ++ ++ if (bytes_read < key_size) { ++ pam_syslog(pamh, LOG_ERR, "Short read on random device"); ++ free(tmp); ++ return PAM_AUTH_ERR; ++ } ++ ++ *key = tmp; ++ ++ return PAM_SUCCESS; ++} ++ ++static int ++read_file(pam_handle_t *pamh, int fd, char **text, size_t *text_length) ++{ ++ struct stat st; ++ size_t bytes_read = 0; ++ char *tmp = NULL; ++ ++ if (fstat(fd, &st) == -1) { ++ pam_syslog(pamh, LOG_ERR, "Unable to stat file: %m"); ++ close(fd); ++ return PAM_AUTH_ERR; ++ } ++ ++ if (st.st_size == 0) { ++ pam_syslog(pamh, LOG_ERR, "Key file size cannot be 0"); ++ close(fd); ++ return PAM_AUTH_ERR; ++ } ++ ++ tmp = malloc(st.st_size); ++ if (!tmp) { ++ pam_syslog(pamh, LOG_CRIT, "Not enough memory"); ++ close(fd); ++ return PAM_AUTH_ERR; ++ } ++ ++ bytes_read = pam_modutil_read(fd, tmp, st.st_size); ++ close(fd); ++ ++ if (bytes_read < (size_t)st.st_size) { ++ pam_syslog(pamh, LOG_ERR, "Short read on key file"); ++ memset(tmp, 0, st.st_size); ++ free(tmp); ++ return PAM_AUTH_ERR; ++ } ++ ++ *text = tmp; ++ *text_length = st.st_size; ++ ++ return PAM_SUCCESS; ++} ++ ++static int ++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; ++ ++ fd = open(file_name, ++ O_WRONLY | O_CREAT | O_TRUNC, ++ S_IRUSR | S_IWUSR); ++ if (fd == -1) { ++ pam_syslog(pamh, LOG_ERR, "Unable to open [%s]: %m", file_name); ++ memset(text, 0, text_length); ++ free(text); ++ return PAM_AUTH_ERR; ++ } ++ ++ if (fchown(fd, owner, group) == -1) { ++ pam_syslog(pamh, LOG_ERR, "Unable to change ownership [%s]: %m", file_name); ++ memset(text, 0, text_length); ++ free(text); ++ close(fd); ++ return PAM_AUTH_ERR; ++ } ++ ++ bytes_written = pam_modutil_write(fd, text, text_length); ++ close(fd); ++ ++ if (bytes_written < text_length) { ++ pam_syslog(pamh, LOG_ERR, "Short write on %s", file_name); ++ free(text); ++ return PAM_AUTH_ERR; ++ } ++ ++ return PAM_SUCCESS; ++} ++ ++static int ++key_management(pam_handle_t *pamh, const char *file_name, char **text, ++ size_t text_length, uid_t owner, gid_t group) ++{ ++ int fd = 0; ++ ++ fd = open(file_name, O_RDONLY | O_NOFOLLOW); ++ if (fd == -1) { ++ if (errno == ENOENT) { ++ if (generate_key(pamh, text, text_length)) { ++ pam_syslog(pamh, LOG_ERR, "Unable to generate key"); ++ return PAM_AUTH_ERR; ++ } ++ ++ if (write_file(pamh, file_name, *text, text_length, owner, group)) { ++ pam_syslog(pamh, LOG_ERR, "Unable to write key"); ++ return PAM_AUTH_ERR; ++ } ++ } else { ++ pam_syslog(pamh, LOG_ERR, "Unable to open %s: %m", file_name); ++ return PAM_AUTH_ERR; ++ } ++ } else { ++ if (read_file(pamh, fd, text, &text_length)) { ++ pam_syslog(pamh, LOG_ERR, "Error reading key file %s\n", file_name); ++ return PAM_AUTH_ERR; ++ } ++ } ++ ++ return PAM_SUCCESS; ++} ++ ++static int ++hmac_management(pam_handle_t *pamh, int debug, void **out, size_t *out_length, ++ char *key, size_t key_length, ++ const void *text, size_t text_length) ++{ ++ int ret = PAM_AUTH_ERR; ++ EVP_MAC *evp_mac = NULL; ++ EVP_MAC_CTX *ctx = NULL; ++ unsigned char *hmac_message = NULL; ++ size_t hmac_length; ++ char *algo = NULL; ++ OSSL_PARAM subalg_param[] = { OSSL_PARAM_END, OSSL_PARAM_END }; ++ ++ algo = get_crypto_algorithm(pamh, debug); ++ ++ subalg_param[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, ++ algo, ++ 0); ++ ++ evp_mac = EVP_MAC_fetch(NULL, "HMAC", NULL); ++ if (evp_mac == NULL) { ++ pam_syslog(pamh, LOG_ERR, "Unable to create hmac implementation"); ++ goto done; ++ } ++ ++ ctx = EVP_MAC_CTX_new(evp_mac); ++ if (ctx == NULL) { ++ pam_syslog(pamh, LOG_ERR, "Unable to create hmac context"); ++ goto done; ++ } ++ ++ ret = EVP_MAC_init(ctx, (const unsigned char *)key, key_length, subalg_param); ++ if (ret == 0) { ++ pam_syslog(pamh, LOG_ERR, "Unable to initialize hmac context"); ++ goto done; ++ } ++ ++ ret = EVP_MAC_update(ctx, (const unsigned char *)text, text_length); ++ if (ret == 0) { ++ pam_syslog(pamh, LOG_ERR, "Unable to update hmac context"); ++ goto done; ++ } ++ ++ hmac_message = (unsigned char*)malloc(sizeof(unsigned char) * MAX_HMAC_LENGTH); ++ if (!hmac_message) { ++ pam_syslog(pamh, LOG_CRIT, "Not enough memory"); ++ goto done; ++ } ++ ++ ret = EVP_MAC_final(ctx, hmac_message, &hmac_length, MAX_HMAC_LENGTH); ++ if (ret == 0) { ++ pam_syslog(pamh, LOG_ERR, "Unable to calculate hmac message"); ++ goto done; ++ } ++ ++ *out_length = hmac_length; ++ *out = malloc(*out_length); ++ if (*out == NULL) { ++ pam_syslog(pamh, LOG_CRIT, "Not enough memory"); ++ goto done; ++ } ++ ++ memcpy(*out, hmac_message, *out_length); ++ ret = PAM_SUCCESS; ++ ++done: ++ if (hmac_message != NULL) { ++ free(hmac_message); ++ } ++ if (key != NULL) { ++ memset(key, 0, key_length); ++ free(key); ++ } ++ if (ctx != NULL) { ++ EVP_MAC_CTX_free(ctx); ++ } ++ if (evp_mac != NULL) { ++ EVP_MAC_free(evp_mac); ++ } ++ free(algo); ++ ++ return ret; ++} ++ ++int ++hmac_size(pam_handle_t *pamh, int debug, size_t *hmac_length) ++{ ++ int ret = PAM_AUTH_ERR; ++ EVP_MAC *evp_mac = NULL; ++ EVP_MAC_CTX *ctx = NULL; ++ const unsigned char key[] = "ThisIsJustAKey"; ++ size_t key_length = MAX_KEY_LENGTH; ++ char *algo = NULL; ++ OSSL_PARAM subalg_param[] = { OSSL_PARAM_END, OSSL_PARAM_END }; ++ ++ algo = get_crypto_algorithm(pamh, debug); ++ ++ subalg_param[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, ++ algo, ++ 0); ++ ++ evp_mac = EVP_MAC_fetch(NULL, "HMAC", NULL); ++ if (evp_mac == NULL) { ++ pam_syslog(pamh, LOG_ERR, "Unable to create hmac implementation"); ++ goto done; ++ } ++ ++ ctx = EVP_MAC_CTX_new(evp_mac); ++ if (ctx == NULL) { ++ pam_syslog(pamh, LOG_ERR, "Unable to create hmac context"); ++ goto done; ++ } ++ ++ ret = EVP_MAC_init(ctx, key, key_length, subalg_param); ++ if (ret == 0) { ++ pam_syslog(pamh, LOG_ERR, "Unable to initialize hmac context"); ++ goto done; ++ } ++ ++ *hmac_length = EVP_MAC_CTX_get_mac_size(ctx); ++ ret = PAM_SUCCESS; ++ ++done: ++ if (ctx != NULL) { ++ EVP_MAC_CTX_free(ctx); ++ } ++ if (evp_mac != NULL) { ++ EVP_MAC_free(evp_mac); ++ } ++ free(algo); ++ ++ return ret; ++} ++ ++int ++hmac_generate(pam_handle_t *pamh, int debug, void **mac, size_t *mac_length, ++ const char *key_file, uid_t owner, gid_t group, ++ const void *text, size_t text_length) ++{ ++ char *key = NULL; ++ size_t key_length = MAX_KEY_LENGTH; ++ ++ if (key_management(pamh, key_file, &key, key_length, owner, group)) { ++ return PAM_AUTH_ERR; ++ } ++ ++ if (hmac_management(pamh, debug, mac, mac_length, key, key_length, ++ text, text_length)) { ++ return PAM_AUTH_ERR; ++ } ++ ++ return PAM_SUCCESS; ++} ++ ++#endif /* WITH_OPENSSL */ +diff --git a/modules/pam_timestamp/hmac_openssl_wrapper.h b/modules/pam_timestamp/hmac_openssl_wrapper.h +new file mode 100644 +index 00000000..cc27c811 +--- /dev/null ++++ b/modules/pam_timestamp/hmac_openssl_wrapper.h +@@ -0,0 +1,57 @@ ++/* Wrapper for hmac openssl implementation. ++ * ++ * Copyright (c) 2021 Red Hat, Inc. ++ * Written by Iker Pedrosa ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, and the entire permission notice in its entirety, ++ * including the disclaimer of warranties. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * ALTERNATIVELY, this product may be distributed under the terms of ++ * the GNU Public License, in which case the provisions of the GPL are ++ * required INSTEAD OF the above restrictions. (This clause is ++ * necessary due to a potential bad interaction between the GPL and ++ * the restrictions contained in a BSD-style copyright.) ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ++ * OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ */ ++#ifndef PAM_TIMESTAMP_HMAC_OPENSSL_WRAPPER_H ++#define PAM_TIMESTAMP_HMAC_OPENSSL_WRAPPER_H ++ ++#include "config.h" ++ ++#ifdef WITH_OPENSSL ++ ++#include ++#include ++ ++int ++hmac_size(pam_handle_t *pamh, int debug, size_t *hmac_length); ++ ++int ++hmac_generate(pam_handle_t *pamh, int debug, void **mac, size_t *mac_length, ++ const char *key_file, uid_t owner, gid_t group, ++ const void *text, size_t text_length); ++ ++#endif /* WITH_OPENSSL */ ++#endif /* PAM_TIMESTAMP_HMAC_OPENSSL_WRAPPER_H */ +diff --git a/modules/pam_timestamp/pam_timestamp.8.xml b/modules/pam_timestamp/pam_timestamp.8.xml +index e19a0bcf..83e5aea8 100644 +--- a/modules/pam_timestamp/pam_timestamp.8.xml ++++ b/modules/pam_timestamp/pam_timestamp.8.xml +@@ -50,6 +50,11 @@ for the user. When an application attempts to authenticate the user, a + pam_timestamp will treat a sufficiently recent timestamp + file as grounds for succeeding. + ++ ++ The default encryption hash is taken from the ++ HMAC_CRYPTO_ALGO variable from ++ /etc/login.defs. ++ + + + +diff --git a/modules/pam_timestamp/pam_timestamp.c b/modules/pam_timestamp/pam_timestamp.c +index 30be883c..01dd1385 100644 +--- a/modules/pam_timestamp/pam_timestamp.c ++++ b/modules/pam_timestamp/pam_timestamp.c +@@ -56,7 +56,11 @@ + #include + #include + #include ++#ifdef WITH_OPENSSL ++#include "hmac_openssl_wrapper.h" ++#else + #include "hmacsha1.h" ++#endif /* WITH_OPENSSL */ + + #include + #include +@@ -79,6 +83,9 @@ + #define BUFLEN PATH_MAX + #endif + ++#define ROOT_USER 0 ++#define ROOT_GROUP 0 ++ + /* Return PAM_SUCCESS if the given directory looks "safe". */ + static int + check_dir_perms(pam_handle_t *pamh, const char *tdir) +@@ -449,6 +456,13 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) + return PAM_AUTH_ERR; + } + ++#ifdef WITH_OPENSSL ++ if (hmac_size(pamh, debug, &maclen)) { ++ return PAM_AUTH_ERR; ++ } ++#else ++ maclen = hmac_sha1_size(); ++#endif /* WITH_OPENSSL */ + /* Check that the file is the expected size. */ + if (st.st_size == 0) { + /* Invalid, but may have been created by sudo. */ +@@ -456,7 +470,7 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) + return PAM_AUTH_ERR; + } + if (st.st_size != +- (off_t)(strlen(path) + 1 + sizeof(then) + hmac_sha1_size())) { ++ (off_t)(strlen(path) + 1 + sizeof(then) + maclen)) { + pam_syslog(pamh, LOG_NOTICE, "timestamp file `%s' " + "appears to be corrupted", path); + close(fd); +@@ -487,8 +501,17 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) + message_end = message + strlen(path) + 1 + sizeof(then); + + /* Regenerate the MAC. */ +- hmac_sha1_generate_file(pamh, &mac, &maclen, TIMESTAMPKEY, 0, 0, +- message, message_end - message); ++#ifdef WITH_OPENSSL ++ if (hmac_generate(pamh, debug, &mac, &maclen, TIMESTAMPKEY, ++ ROOT_USER, ROOT_GROUP, message, message_end - message)) { ++ close(fd); ++ free(message); ++ return PAM_AUTH_ERR; ++ } ++#else ++ hmac_sha1_generate_file(pamh, &mac, &maclen, TIMESTAMPKEY, ++ ROOT_USER, ROOT_GROUP, message, message_end - message); ++#endif /* WITH_OPENSSL */ + if ((mac == NULL) || + (memcmp(path, message, strlen(path)) != 0) || + (memcmp(mac, message_end, maclen) != 0)) { +@@ -605,8 +628,16 @@ pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, int argc, const char * + } + } + ++#ifdef WITH_OPENSSL ++ if (hmac_size(pamh, debug, &maclen)) { ++ return PAM_SESSION_ERR; ++ } ++#else ++ maclen = hmac_sha1_size(); ++#endif /* WITH_OPENSSL */ ++ + /* Generate the message. */ +- text = malloc(strlen(path) + 1 + sizeof(now) + hmac_sha1_size()); ++ text = malloc(strlen(path) + 1 + sizeof(now) + maclen); + if (text == NULL) { + pam_syslog(pamh, LOG_CRIT, "unable to allocate memory: %m"); + return PAM_SESSION_ERR; +@@ -621,15 +652,21 @@ pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, int argc, const char * + p += sizeof(now); + + /* Generate the MAC and append it to the plaintext. */ +- hmac_sha1_generate_file(pamh, &mac, &maclen, +- TIMESTAMPKEY, +- 0, 0, +- text, p - text); ++#ifdef WITH_OPENSSL ++ if (hmac_generate(pamh, debug, &mac, &maclen, TIMESTAMPKEY, ++ ROOT_USER, ROOT_GROUP, text, p - text)) { ++ free(text); ++ return PAM_SESSION_ERR; ++ } ++#else ++ hmac_sha1_generate_file(pamh, &mac, &maclen, TIMESTAMPKEY, ++ ROOT_USER, ROOT_GROUP, text, p - text); + if (mac == NULL) { + pam_syslog(pamh, LOG_ERR, "failure generating MAC: %m"); + free(text); + return PAM_SESSION_ERR; + } ++#endif /* WITH_OPENSSL */ + memmove(p, mac, maclen); + p += maclen; + free(mac); +-- +2.31.1 + diff --git a/pam.spec b/pam.spec index fc91b6f..0cecbbe 100644 --- a/pam.spec +++ b/pam.spec @@ -3,7 +3,7 @@ Summary: An extensible library which provides authentication for applications Name: pam Version: 1.5.1 -Release: 5%{?dist} +Release: 6%{?dist} # The library is BSD licensed with option to relicense as GPLv2+ # - this option is redundant as the BSD license allows that anyway. # pam_timestamp, pam_loginuid, and pam_console modules are GPLv2+. @@ -27,6 +27,7 @@ Source18: https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt Patch1: pam-1.5.0-redhat-modules.patch Patch2: pam-1.5.0-noflex.patch Patch3: pam-1.3.0-unix-nomsg.patch +Patch4: pam-1.5.1-timestamp-openssl-hmac-authentication.patch %global _pamlibdir %{_libdir} %global _moduledir %{_libdir}/security @@ -67,6 +68,8 @@ BuildRequires: libdb-devel BuildRequires: linuxdoc-tools, elinks, libxslt BuildRequires: docbook-style-xsl, docbook-dtds BuildRequires: gcc +BuildRequires: openssl-devel >= 3.0.0 +Requires: openssl >= 3.0.0 URL: http://www.linux-pam.org/ @@ -110,6 +113,7 @@ cp %{SOURCE18} . %patch1 -p1 -b .redhat-modules %patch2 -p1 -b .noflex %patch3 -p1 -b .nomsg +%patch4 -p1 -b .timestamp-openssl-hmac-authentication autoreconf -i @@ -127,7 +131,8 @@ autoreconf -i %endif --disable-static \ --disable-prelude \ - --disable-nis + --disable-nis \ + --enable-openssl make -C po update-gmo make # we do not use _smp_mflags because the build of sources in yacc/flex fails @@ -363,6 +368,9 @@ done %doc doc/sag/*.txt doc/sag/html %changelog +* Fri Jul 2 2021 Iker Pedrosa - 1.5.1-6 +- pam_timestamp: openssl hmac authentication. Resolves: #1934975 + * Mon Apr 19 2021 Iker Pedrosa - 1.5.1-5 - Disable nis support. Resolves: #1942373