From 2f2af3aa8a0366e6502751415a08413bf28ba0cb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 5 Mar 2024 09:55:47 +0100 Subject: [PATCH] lib/crypto: add legacy_gnutls_server_end_point_cb() if needed gnutls_session_channel_binding(GNUTLS_CB_TLS_SERVER_END_POINT) is only available with gnutls 3.7.2, but we still want to support older gnutls versions and that's easily doable... BUG: https://bugzilla.samba.org/show_bug.cgi?id=15621 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett --- lib/crypto/gnutls_helpers.h | 6 ++ lib/crypto/gnutls_server_end_point_cb.c | 130 ++++++++++++++++++++++++ lib/crypto/wscript | 6 +- wscript_configure_system_gnutls | 5 + 4 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 lib/crypto/gnutls_server_end_point_cb.c diff --git a/lib/crypto/gnutls_helpers.h b/lib/crypto/gnutls_helpers.h index 0362d5ee782..6699ebc0196 100644 --- a/lib/crypto/gnutls_helpers.h +++ b/lib/crypto/gnutls_helpers.h @@ -233,4 +233,10 @@ NTSTATUS samba_gnutls_sp800_108_derive_key( uint8_t *KO, size_t KO_len); +#ifndef HAVE_GNUTLS_CB_TLS_SERVER_END_POINT +int legacy_gnutls_server_end_point_cb(gnutls_session_t session, + bool is_server, + gnutls_datum_t * cb); +#endif /* HAVE_GNUTLS_CB_TLS_SERVER_END_POINT */ + #endif /* _GNUTLS_HELPERS_H */ diff --git a/lib/crypto/gnutls_server_end_point_cb.c b/lib/crypto/gnutls_server_end_point_cb.c new file mode 100644 index 00000000000..c9091974640 --- /dev/null +++ b/lib/crypto/gnutls_server_end_point_cb.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2002-2016 Free Software Foundation, Inc. + * Copyright (C) 2014-2016 Nikos Mavrogiannopoulos + * Copyright (C) 2015-2018 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + * + */ + +#include "replace.h" +#include "gnutls_helpers.h" +#include +#include + +int legacy_gnutls_server_end_point_cb(gnutls_session_t session, + bool is_server, + gnutls_datum_t * cb) +{ + /* + * copied from the logic in gnutls_session_channel_binding() + * introduced by gnutls commit (as LGPL 2.1+): + * + * commit 9ebee00c793e40e3e8c797c645577c9e025b9f1e + * Author: Ruslan N. Marchenko + * Date: Sat May 1 23:05:54 2021 +0200 + * + * Add tls-server-end-point tls channel binding implementation. + * ... + */ + const gnutls_datum_t *ders = NULL; + unsigned int num_certs = 1; + int ret; + size_t rlen; + gnutls_x509_crt_t cert; + gnutls_digest_algorithm_t algo; + + /* Only X509 certificates are supported for this binding type */ + ret = gnutls_certificate_type_get(session); + if (ret != GNUTLS_CRT_X509) { + return GNUTLS_E_UNIMPLEMENTED_FEATURE; + } + + if (is_server) { + ders = gnutls_certificate_get_ours(session); + } else { + ders = gnutls_certificate_get_peers(session, &num_certs); + } + + /* Previous check indicated we have x509 but you never know */ + if (!ders || num_certs == 0) { + return GNUTLS_E_UNIMPLEMENTED_FEATURE; + } + + ret = gnutls_x509_crt_list_import(&cert, + &num_certs, + ders, + GNUTLS_X509_FMT_DER, + 0); + /* Again, this is not supposed to happen (normally) */ + if (ret < 0 || num_certs == 0) { + return GNUTLS_E_CHANNEL_BINDING_NOT_AVAILABLE; + } + + /* Obtain signature algorithm used by certificate */ + ret = gnutls_x509_crt_get_signature_algorithm(cert); + if (ret < 0 || ret == GNUTLS_SIGN_UNKNOWN) { + gnutls_x509_crt_deinit(cert); + return GNUTLS_E_UNIMPLEMENTED_FEATURE; + } + + /* obtain hash function from signature and normalize it */ + algo = gnutls_sign_get_hash_algorithm(ret); + switch (algo) { + case GNUTLS_DIG_MD5: + case GNUTLS_DIG_SHA1: + algo = GNUTLS_DIG_SHA256; + break; + case GNUTLS_DIG_UNKNOWN: + case GNUTLS_DIG_NULL: + case GNUTLS_DIG_MD5_SHA1: + /* double hashing not supported either */ + gnutls_x509_crt_deinit(cert); + return GNUTLS_E_UNIMPLEMENTED_FEATURE; + default: + break; + } + + /* preallocate 512 bits buffer as maximum supported digest */ + rlen = 64; + cb->data = gnutls_malloc(rlen); + if (cb->data == NULL) { + gnutls_x509_crt_deinit(cert); + return GNUTLS_E_MEMORY_ERROR; + } + + ret = gnutls_x509_crt_get_fingerprint(cert, + algo, + cb->data, + &rlen); + if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { + cb->data = gnutls_realloc(cb->data, cb->size); + if (cb->data == NULL) { + gnutls_x509_crt_deinit(cert); + return GNUTLS_E_MEMORY_ERROR; + } + ret = gnutls_x509_crt_get_fingerprint(cert, + algo, + cb->data, + &rlen); + } + + cb->size = rlen; + gnutls_x509_crt_deinit(cert); + return ret; +} diff --git a/lib/crypto/wscript b/lib/crypto/wscript index 251eaae363c..7d70b62f4ae 100644 --- a/lib/crypto/wscript +++ b/lib/crypto/wscript @@ -2,6 +2,10 @@ def build(bld): + legacy_gnutls_helpers = '' + if not bld.CONFIG_SET('HAVE_GNUTLS_CB_TLS_SERVER_END_POINT'): + legacy_gnutls_helpers += ' gnutls_server_end_point_cb.c' + bld.SAMBA_SUBSYSTEM("GNUTLS_HELPERS", source=''' gnutls_error.c @@ -9,7 +13,7 @@ def build(bld): gnutls_arcfour_confounded_md5.c gnutls_weak_crypto.c gnutls_sp800_108.c - ''', + ''' + legacy_gnutls_helpers, deps="gnutls samba-errors") bld.SAMBA_SUBSYSTEM('LIBCRYPTO', diff --git a/wscript_configure_system_gnutls b/wscript_configure_system_gnutls index 1983a0cdfe9..f62de5560d6 100644 --- a/wscript_configure_system_gnutls +++ b/wscript_configure_system_gnutls @@ -34,6 +34,11 @@ conf.SET_TARGET_TYPE('gnutls', 'SYSLIB') if (gnutls_version > parse_version('3.6.14')): conf.DEFINE('ALLOW_GNUTLS_AEAD_CIPHER_ENCRYPTV2_AES_CCM', 1) +# GNUTLS_CB_TLS_SERVER_END_POINT is available with +# 3.7.2 +if (gnutls_version >= parse_version('3.7.2')): + conf.DEFINE('HAVE_GNUTLS_CB_TLS_SERVER_END_POINT', 1) + # Check if gnutls has fips mode support # gnutls_fips140_mode_enabled() is available since 3.3.0 fragment = '''