diff --git a/configure b/configure index 282cc52..b6b582d 100755 --- a/configure +++ b/configure @@ -934,15 +934,34 @@ if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_tomcrypt = "1" ] fi fi +if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_gnutls = "1" ]; then + test_cflags="`pkg_config --cflags gnutls`" + test_link="`pkg_config --libs gnutls`" + if test_code 'gnutls' 'gnutls/crypto.h' \ + "$test_cflags" "$test_link" ' + return gnutls_hash(NULL, NULL, 0);' + then + HASH_OBJ="hash_gnutls.o" + HASH_LINK="$test_link" + MYCPPFLAGS="$MYCPPFLAGS $test_cflags" + add_def FEAT_SECHASH + fi +fi + EXTRA_OBJECTS="$EXTRA_OBJECTS $HASH_OBJ" EXTRA_CLI_OBJECTS="$EXTRA_CLI_OBJECTS $HASH_OBJ" LIBS="$LIBS $HASH_LINK" if [ $feat_ntp = "1" ] && [ $feat_nts = "1" ] && [ $try_gnutls = "1" ]; then - test_cflags="`pkg_config --cflags gnutls`" - test_link="`pkg_config --libs gnutls`" - if test_code 'gnutls' 'gnutls/gnutls.h' \ - "$test_cflags" "$test_link" ' + if [ "$HASH_OBJ" = "hash_gnutls.o" ]; then + test_cflags="" + test_link="" + else + test_cflags="`pkg_config --cflags gnutls`" + test_link="`pkg_config --libs gnutls`" + fi + if test_code 'TLS1.3 in gnutls' 'gnutls/gnutls.h' \ + "$test_cflags" "$test_link $LIBS" ' return gnutls_init(NULL, 0) + GNUTLS_TLS1_3 + gnutls_priority_init2(NULL, "", NULL, GNUTLS_PRIORITY_INIT_DEF_APPEND) + gnutls_prf_rfc5705(NULL, 0, "", 0, "", 16, NULL);' @@ -956,7 +975,7 @@ if [ $feat_ntp = "1" ] && [ $feat_nts = "1" ] && [ $try_gnutls = "1" ]; then add_def HAVE_NETTLE_SIV_CMAC else if test_code 'SIV in gnutls' 'gnutls/crypto.h' \ - "$test_cflags" "$test_link" ' + "$test_cflags" "$test_link $LIBS" ' return gnutls_aead_cipher_init(NULL, GNUTLS_CIPHER_AES_128_SIV, NULL);' then EXTRA_OBJECTS="$EXTRA_OBJECTS siv_gnutls.o" diff --git a/hash_gnutls.c b/hash_gnutls.c new file mode 100644 index 0000000..5c77a22 --- /dev/null +++ b/hash_gnutls.c @@ -0,0 +1,137 @@ +/* + chronyd/chronyc - Programs for keeping computer clocks accurate. + + ********************************************************************** + * Copyright (C) Miroslav Lichvar 2021 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + ********************************************************************** + + ======================================================================= + + Crypto hashing using the GnuTLS library + */ + +#include "config.h" + +#include "sysincl.h" + +#include + +#include "hash.h" +#include "logging.h" + +struct hash { + const HSH_Algorithm algorithm; + const gnutls_digest_algorithm_t type; + gnutls_hash_hd_t handle; +}; + +static struct hash hashes[] = { + { HSH_MD5, GNUTLS_DIG_MD5, NULL }, + { HSH_SHA1, GNUTLS_DIG_SHA1, NULL }, + { HSH_SHA256, GNUTLS_DIG_SHA256, NULL }, + { HSH_SHA384, GNUTLS_DIG_SHA384, NULL }, + { HSH_SHA512, GNUTLS_DIG_SHA512, NULL }, + { HSH_SHA3_224, GNUTLS_DIG_SHA3_224, NULL }, + { HSH_SHA3_256, GNUTLS_DIG_SHA3_256, NULL }, + { HSH_SHA3_384, GNUTLS_DIG_SHA3_384, NULL }, + { HSH_SHA3_512, GNUTLS_DIG_SHA3_512, NULL }, + { 0, 0, NULL } +}; + +static int gnutls_initialised = 0; + +int +HSH_GetHashId(HSH_Algorithm algorithm) +{ + int id, r; + + if (!gnutls_initialised) { + r = gnutls_global_init(); + if (r < 0) + LOG_FATAL("Could not initialise %s : %s", "gnutls", gnutls_strerror(r)); + gnutls_initialised = 1; + } + + for (id = 0; hashes[id].algorithm != 0; id++) { + if (hashes[id].algorithm == algorithm) + break; + } + + if (hashes[id].algorithm == 0) + return -1; + + if (hashes[id].handle) + return id; + + r = gnutls_hash_init(&hashes[id].handle, hashes[id].type); + if (r < 0) { + DEBUG_LOG("Could not initialise %s : %s", "hash", gnutls_strerror(r)); + hashes[id].handle = NULL; + return -1; + } + + return id; +} + +int +HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len, + unsigned char *out, int out_len) +{ + unsigned char buf[MAX_HASH_LENGTH]; + gnutls_hash_hd_t handle; + int hash_len; + + if (in1_len < 0 || in2_len < 0 || out_len < 0) + return 0; + + handle = hashes[id].handle; + hash_len = gnutls_hash_get_len(hashes[id].type); + + if (out_len > hash_len) + out_len = hash_len; + + if (hash_len > sizeof (buf)) + return 0; + + if (gnutls_hash(handle, in1, in1_len) < 0 || + (in2 && gnutls_hash(handle, in2, in2_len) < 0)) { + /* Reset the state */ + gnutls_hash_output(handle, buf); + return 0; + } + + gnutls_hash_output(handle, buf); + memcpy(out, buf, out_len); + + return out_len; +} + +void +HSH_Finalise(void) +{ + int i; + + if (!gnutls_initialised) + return; + + for (i = 0; hashes[i].algorithm != 0; i++) { + if (hashes[i].handle) + gnutls_hash_deinit(hashes[i].handle, NULL); + } + + gnutls_global_deinit(); +}