[libvirt] [PATCHv2] build: avoid -lgcrypt with newer gnutls

https://bugzilla.redhat.com/show_bug.cgi?id=951637 Newer gnutls uses nettle, rather than gcrypt, which is a lot nicer regarding initialization. Yet we were unconditionally initializing gcrypt even when gnutls wouldn't be using it, and having two crypto libraries linked into libvirt.so is pointless. Assume that the switch to gnutls 3.0 is a reliable witness, when pkg-config is present; otherwise be pessimistic and use gcrypt. * configure.ac (WITH_GNUTLS): Probe whether to add -lgcrypt, and define a witness WITH_GNUTLS_GCRYPT. * src/libvirt.c (virTLSMutexInit, virTLSMutexDestroy) (virTLSMutexLock, virTLSMutexUnlock, virTLSThreadImpl) (virGlobalInit): Honor the witness. * libvirt.spec.in (BuildRequires): Make gcrypt usage conditional, no longer needed in Fedora 19. Signed-off-by: Eric Blake <eblake@redhat.com> --- v2: use second pkg-config invocation rather than ldd to determine whether gnutls uses gcrypt configure.ac | 27 +++++++++++++++++++-------- libvirt.spec.in | 2 ++ src/libvirt.c | 10 ++++++---- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/configure.ac b/configure.ac index cc9942a..eb56b63 100644 --- a/configure.ac +++ b/configure.ac @@ -1076,12 +1076,19 @@ if test "x$with_gnutls" != "xno"; then LIBS="$LIBS $GNUTLS_LIBS" GNUTLS_FOUND=no + GNUTLS_GCRYPT=no if test -x "$PKG_CONFIG" ; then + dnl double probe, since we know that gnutls 3.0 switched to nettle instead of + dnl gcrypt PKG_CHECK_MODULES(GNUTLS, gnutls >= $GNUTLS_REQUIRED, - [GNUTLS_FOUND=yes], [GNUTLS_FOUND=no]) + [GNUTLS_FOUND=yes + PKG_CHECK_MODULES([GNUTLS], [gnutls >= 3.0], [], [GNUTLS_GCRYPT=yes])], + [GNUTLS_FOUND=no]) fi if test "$GNUTLS_FOUND" = "no"; then + dnl pkg-config couldn't help us, assume gcrypt is necessary fail=0 + GNUTLS_GCRYPT=yes AC_CHECK_HEADER([gnutls/gnutls.h], [], [fail=1]) AC_CHECK_LIB([gnutls], [gnutls_handshake],[], [fail=1], [-lgcrypt]) @@ -1098,13 +1105,17 @@ if test "x$with_gnutls" != "xno"; then AC_MSG_ERROR([You must install the GnuTLS library in order to compile and run libvirt]) fi else - dnl Not all versions of gnutls include -lgcrypt, and so we add - dnl it explicitly for the calls to gcry_control/check_version - GNUTLS_LIBS="$GNUTLS_LIBS -lgcrypt" - - dnl We're not using gcrypt deprecated features so define - dnl GCRYPT_NO_DEPRECATED to avoid deprecated warnings - GNUTLS_CFLAGS="$GNUTLS_CFLAGS -DGCRYPT_NO_DEPRECATED" + dnl If gnutls linked against -lgcrypt, then we must initialize gcrypt + dnl prior to using gnutls. Newer versions of gnutls use -lnettle, in + dnl which case we don't want to drag in gcrypt ourselves. + if test "$GNUTLS_GCRYPT" = yes; then + GNUTLS_LIBS="$GNUTLS_LIBS -lgcrypt" + dnl We're not using gcrypt deprecated features so define + dnl GCRYPT_NO_DEPRECATED to avoid deprecated warnings + GNUTLS_CFLAGS="$GNUTLS_CFLAGS -DGCRYPT_NO_DEPRECATED" + AC_DEFINE_UNQUOTED([WITH_GNUTLS_GCRYPT], 1, + [set to 1 if it is known or assumed that GNUTLS uses gcrypt]) + fi dnl gnutls 3.x moved some declarations to a new header AC_CHECK_HEADERS([gnutls/crypto.h], [], [], [[ diff --git a/libvirt.spec.in b/libvirt.spec.in index e0e0004..4320281 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -422,7 +422,9 @@ BuildRequires: readline-devel BuildRequires: ncurses-devel BuildRequires: gettext BuildRequires: libtasn1-devel +%if (0%{?rhel} && 0%{?rhel} < 7) || (0%{?fedora} && 0%{?fedora} < 19) BuildRequires: libgcrypt-devel +%endif BuildRequires: gnutls-devel BuildRequires: libattr-devel %if %{with_libvirtd} diff --git a/src/libvirt.c b/src/libvirt.c index 8157488..66e8248 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -55,7 +55,9 @@ #include "intprops.h" #include "virconf.h" #if WITH_GNUTLS -# include <gcrypt.h> +# if WITH_GNUTLS_GCRYPT +# include <gcrypt.h> +# endif # include "rpc/virnettlscontext.h" #endif #include "vircommand.h" @@ -270,7 +272,7 @@ winsock_init(void) #endif -#ifdef WITH_GNUTLS +#ifdef WITH_GNUTLS_GCRYPT static int virTLSMutexInit(void **priv) { virMutexPtr lock = NULL; @@ -323,7 +325,7 @@ static struct gcry_thread_cbs virTLSThreadImpl = { virTLSMutexUnlock, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; -#endif +#endif /* WITH_GNUTLS_GCRYPT */ /* Helper macros to implement VIR_DOMAIN_DEBUG using just C99. This * assumes you pass fewer than 15 arguments to VIR_DOMAIN_DEBUG, but @@ -407,7 +409,7 @@ virGlobalInit(void) virErrorInitialize() < 0) goto error; -#ifdef WITH_GNUTLS +#ifdef WITH_GNUTLS_GCRYPT /* * This sequence of API calls it copied exactly from * gnutls 2.12.23 source lib/gcrypt/init.c, with -- 1.8.3.1

On Fri, Jul 26, 2013 at 5:04 PM, Eric Blake <eblake@redhat.com> wrote:
https://bugzilla.redhat.com/show_bug.cgi?id=951637
Newer gnutls uses nettle, rather than gcrypt, which is a lot nicer regarding initialization. Yet we were unconditionally initializing gcrypt even when gnutls wouldn't be using it, and having two crypto libraries linked into libvirt.so is pointless.
Assume that the switch to gnutls 3.0 is a reliable witness, when pkg-config is present; otherwise be pessimistic and use gcrypt.
* configure.ac (WITH_GNUTLS): Probe whether to add -lgcrypt, and define a witness WITH_GNUTLS_GCRYPT. * src/libvirt.c (virTLSMutexInit, virTLSMutexDestroy) (virTLSMutexLock, virTLSMutexUnlock, virTLSThreadImpl) (virGlobalInit): Honor the witness. * libvirt.spec.in (BuildRequires): Make gcrypt usage conditional, no longer needed in Fedora 19.
Signed-off-by: Eric Blake <eblake@redhat.com> ---
v2: use second pkg-config invocation rather than ldd to determine whether gnutls uses gcrypt
configure.ac | 27 +++++++++++++++++++-------- libvirt.spec.in | 2 ++ src/libvirt.c | 10 ++++++---- 3 files changed, 27 insertions(+), 12 deletions(-)
diff --git a/configure.ac b/configure.ac index cc9942a..eb56b63 100644 --- a/configure.ac +++ b/configure.ac @@ -1076,12 +1076,19 @@ if test "x$with_gnutls" != "xno"; then LIBS="$LIBS $GNUTLS_LIBS"
GNUTLS_FOUND=no + GNUTLS_GCRYPT=no if test -x "$PKG_CONFIG" ; then + dnl double probe, since we know that gnutls 3.0 switched to nettle instead of + dnl gcrypt PKG_CHECK_MODULES(GNUTLS, gnutls >= $GNUTLS_REQUIRED, - [GNUTLS_FOUND=yes], [GNUTLS_FOUND=no]) + [GNUTLS_FOUND=yes + PKG_CHECK_MODULES([GNUTLS], [gnutls >= 3.0], [], [GNUTLS_GCRYPT=yes])], + [GNUTLS_FOUND=no]) fi if test "$GNUTLS_FOUND" = "no"; then + dnl pkg-config couldn't help us, assume gcrypt is necessary fail=0 + GNUTLS_GCRYPT=yes AC_CHECK_HEADER([gnutls/gnutls.h], [], [fail=1]) AC_CHECK_LIB([gnutls], [gnutls_handshake],[], [fail=1], [-lgcrypt])
@@ -1098,13 +1105,17 @@ if test "x$with_gnutls" != "xno"; then AC_MSG_ERROR([You must install the GnuTLS library in order to compile and run libvirt]) fi else - dnl Not all versions of gnutls include -lgcrypt, and so we add - dnl it explicitly for the calls to gcry_control/check_version - GNUTLS_LIBS="$GNUTLS_LIBS -lgcrypt" - - dnl We're not using gcrypt deprecated features so define - dnl GCRYPT_NO_DEPRECATED to avoid deprecated warnings - GNUTLS_CFLAGS="$GNUTLS_CFLAGS -DGCRYPT_NO_DEPRECATED" + dnl If gnutls linked against -lgcrypt, then we must initialize gcrypt + dnl prior to using gnutls. Newer versions of gnutls use -lnettle, in + dnl which case we don't want to drag in gcrypt ourselves. + if test "$GNUTLS_GCRYPT" = yes; then + GNUTLS_LIBS="$GNUTLS_LIBS -lgcrypt" + dnl We're not using gcrypt deprecated features so define + dnl GCRYPT_NO_DEPRECATED to avoid deprecated warnings + GNUTLS_CFLAGS="$GNUTLS_CFLAGS -DGCRYPT_NO_DEPRECATED" + AC_DEFINE_UNQUOTED([WITH_GNUTLS_GCRYPT], 1, + [set to 1 if it is known or assumed that GNUTLS uses gcrypt]) + fi
dnl gnutls 3.x moved some declarations to a new header AC_CHECK_HEADERS([gnutls/crypto.h], [], [], [[ diff --git a/libvirt.spec.in b/libvirt.spec.in index e0e0004..4320281 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -422,7 +422,9 @@ BuildRequires: readline-devel BuildRequires: ncurses-devel BuildRequires: gettext BuildRequires: libtasn1-devel +%if (0%{?rhel} && 0%{?rhel} < 7) || (0%{?fedora} && 0%{?fedora} < 19) BuildRequires: libgcrypt-devel +%endif BuildRequires: gnutls-devel BuildRequires: libattr-devel %if %{with_libvirtd} diff --git a/src/libvirt.c b/src/libvirt.c index 8157488..66e8248 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -55,7 +55,9 @@ #include "intprops.h" #include "virconf.h" #if WITH_GNUTLS -# include <gcrypt.h> +# if WITH_GNUTLS_GCRYPT +# include <gcrypt.h> +# endif # include "rpc/virnettlscontext.h" #endif #include "vircommand.h" @@ -270,7 +272,7 @@ winsock_init(void) #endif
-#ifdef WITH_GNUTLS +#ifdef WITH_GNUTLS_GCRYPT static int virTLSMutexInit(void **priv) { virMutexPtr lock = NULL; @@ -323,7 +325,7 @@ static struct gcry_thread_cbs virTLSThreadImpl = { virTLSMutexUnlock, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; -#endif +#endif /* WITH_GNUTLS_GCRYPT */
/* Helper macros to implement VIR_DOMAIN_DEBUG using just C99. This * assumes you pass fewer than 15 arguments to VIR_DOMAIN_DEBUG, but @@ -407,7 +409,7 @@ virGlobalInit(void) virErrorInitialize() < 0) goto error;
-#ifdef WITH_GNUTLS +#ifdef WITH_GNUTLS_GCRYPT /* * This sequence of API calls it copied exactly from * gnutls 2.12.23 source lib/gcrypt/init.c, with -- 1.8.3.1
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Hate to throw a monkey wrench in the plan, but GnuTLS 3.0 isn't the nettle cut over. On my stable Gentoo box with GnuTLS 2.12.23, its using nettle as seen by ldd. ldd /usr/lib64/libgnutls.so.26 linux-vdso.so.1 (0x00007fffad3ff000) libnettle.so.4 => /usr/lib64/libnettle.so.4 (0x00007f60fa4f4000) libgmp.so.10 => /usr/lib64/libgmp.so.10 (0x00007f60fa284000) libhogweed.so.2 => /usr/lib64/libhogweed.so.2 (0x00007f60fa054000) libz.so.1 => /lib64/libz.so.1 (0x00007f60f9e3e000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f60f9c21000) libtasn1.so.3 => /usr/lib64/libtasn1.so.3 (0x00007f60f9a0f000) libc.so.6 => /lib64/libc.so.6 (0x00007f60f9661000) /lib64/ld-linux-x86-64.so.2 (0x00007f60fa9ec000) It appears it was an optional cutover and I guess Gentoo made the plunge. Another idea, that you might hate would be to use pkg-config directly and pass --static so we can get the private libraries. I'm not running Fedora 19 yet so the best I can do is give you Fedora 18 as a comp, but that works out great since its using 2.12.23 as well. stable Gentoo: Name: GnuTLS Description: Transport Security Layer implementation for the GNU system URL: http://www.gnu.org/software/gnutls/ Version: 2.12.23 Libs: -L${libdir} -lgnutls Libs.private: -L/usr/lib64 -lnettle -lgmp -lhogweed Requires.private: libtasn1 , zlib Cflags: -I${includedir} $ pkg-config --libs --static gnutls -lgnutls -ltasn1 -lz -lnettle -lgmp -lhogweed Fedora 18: Name: GnuTLS Description: Transport Security Layer implementation for the GNU system URL: http://www.gnu.org/software/gnutls/ Version: 2.12.23 Libs: -L${libdir} -lgnutls Libs.private: -L/usr/lib64 -lgcrypt -L/usr/lib64 -lgpg-error Requires.private: libtasn1 , zlib, p11-kit-1 Cflags: -I${includedir} $ pkg-config --libs --static gnutls -lgnutls -lgcrypt -lgpg-error -ltasn1 -lz -lp11-kit With GnuTLS 3.2 I get the following: pkg-config --libs --static gnutls -lgnutls -lhogweed -lnettle -lz -lgmp Maybe that helps? -- Doug Goldstein

On 07/26/2013 07:22 PM, Doug Goldstein wrote:
It appears it was an optional cutover and I guess Gentoo made the plunge. Another idea, that you might hate would be to use pkg-config directly and pass --static so we can get the private libraries. I'm not running Fedora 19 yet so the best I can do is give you Fedora 18 as a comp, but that works out great since its using 2.12.23 as well.
stable Gentoo:
Name: GnuTLS Description: Transport Security Layer implementation for the GNU system URL: http://www.gnu.org/software/gnutls/ Version: 2.12.23 Libs: -L${libdir} -lgnutls Libs.private: -L/usr/lib64 -lnettle -lgmp -lhogweed Requires.private: libtasn1 , zlib Cflags: -I${includedir}
$ pkg-config --libs --static gnutls -lgnutls -ltasn1 -lz -lnettle -lgmp -lhogweed
Fedora 18:
Name: GnuTLS Description: Transport Security Layer implementation for the GNU system URL: http://www.gnu.org/software/gnutls/ Version: 2.12.23 Libs: -L${libdir} -lgnutls Libs.private: -L/usr/lib64 -lgcrypt -L/usr/lib64 -lgpg-error Requires.private: libtasn1 , zlib, p11-kit-1 Cflags: -I${includedir}
$ pkg-config --libs --static gnutls -lgnutls -lgcrypt -lgpg-error -ltasn1 -lz -lp11-kit
With GnuTLS 3.2 I get the following:
pkg-config --libs --static gnutls -lgnutls -lhogweed -lnettle -lz -lgmp
Maybe that helps?
Unfortunately, no: Fedora 19: $ pkg-config --libs --static gnutls -lgnutls -lnettle -lhogweed -lgmp -lpthread -ltasn1 -lp11-kit -lz Correct - nettle instead of gcrypt. RHEL 6.4: $ pkg-config --libs --static gnutls -lgnutls -ltasn1 Ouch - no mention of gcrypt, even though this version still used gcrypt. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On Fri, Jul 26, 2013 at 10:37 PM, Eric Blake <eblake@redhat.com> wrote:
On 07/26/2013 07:22 PM, Doug Goldstein wrote:
It appears it was an optional cutover and I guess Gentoo made the plunge. Another idea, that you might hate would be to use pkg-config directly and pass --static so we can get the private libraries. I'm not running Fedora 19 yet so the best I can do is give you Fedora 18 as a comp, but that works out great since its using 2.12.23 as well.
stable Gentoo:
Name: GnuTLS Description: Transport Security Layer implementation for the GNU system URL: http://www.gnu.org/software/gnutls/ Version: 2.12.23 Libs: -L${libdir} -lgnutls Libs.private: -L/usr/lib64 -lnettle -lgmp -lhogweed Requires.private: libtasn1 , zlib Cflags: -I${includedir}
$ pkg-config --libs --static gnutls -lgnutls -ltasn1 -lz -lnettle -lgmp -lhogweed
Fedora 18:
Name: GnuTLS Description: Transport Security Layer implementation for the GNU system URL: http://www.gnu.org/software/gnutls/ Version: 2.12.23 Libs: -L${libdir} -lgnutls Libs.private: -L/usr/lib64 -lgcrypt -L/usr/lib64 -lgpg-error Requires.private: libtasn1 , zlib, p11-kit-1 Cflags: -I${includedir}
$ pkg-config --libs --static gnutls -lgnutls -lgcrypt -lgpg-error -ltasn1 -lz -lp11-kit
With GnuTLS 3.2 I get the following:
pkg-config --libs --static gnutls -lgnutls -lhogweed -lnettle -lz -lgmp
Maybe that helps?
Unfortunately, no:
Fedora 19: $ pkg-config --libs --static gnutls -lgnutls -lnettle -lhogweed -lgmp -lpthread -ltasn1 -lp11-kit -lz
Correct - nettle instead of gcrypt.
RHEL 6.4: $ pkg-config --libs --static gnutls -lgnutls -ltasn1
Ouch - no mention of gcrypt, even though this version still used gcrypt.
Well that's not really to problematic. RHEL 6.4 uses gnutls 2.8.x which didn't have any concept of nettle at that point. nettle wasn't introduced as a supported backend until 2.12 [1]. So let's rework the patch to assume libgcrypt before gnutls 2.12 and then starting with 2.12 we double probe for nettle or libgcrypt. [1] http://lists.gnu.org/archive/html/gnutls-devel/2011-03/msg00034.html -- Doug Goldstein

On Sat, Jul 27, 2013 at 3:09 PM, Doug Goldstein <cardoe@gentoo.org> wrote:
On Fri, Jul 26, 2013 at 10:37 PM, Eric Blake <eblake@redhat.com> wrote:
On 07/26/2013 07:22 PM, Doug Goldstein wrote:
It appears it was an optional cutover and I guess Gentoo made the plunge. Another idea, that you might hate would be to use pkg-config directly and pass --static so we can get the private libraries. I'm not running Fedora 19 yet so the best I can do is give you Fedora 18 as a comp, but that works out great since its using 2.12.23 as well.
stable Gentoo:
Name: GnuTLS Description: Transport Security Layer implementation for the GNU system URL: http://www.gnu.org/software/gnutls/ Version: 2.12.23 Libs: -L${libdir} -lgnutls Libs.private: -L/usr/lib64 -lnettle -lgmp -lhogweed Requires.private: libtasn1 , zlib Cflags: -I${includedir}
$ pkg-config --libs --static gnutls -lgnutls -ltasn1 -lz -lnettle -lgmp -lhogweed
Fedora 18:
Name: GnuTLS Description: Transport Security Layer implementation for the GNU system URL: http://www.gnu.org/software/gnutls/ Version: 2.12.23 Libs: -L${libdir} -lgnutls Libs.private: -L/usr/lib64 -lgcrypt -L/usr/lib64 -lgpg-error Requires.private: libtasn1 , zlib, p11-kit-1 Cflags: -I${includedir}
$ pkg-config --libs --static gnutls -lgnutls -lgcrypt -lgpg-error -ltasn1 -lz -lp11-kit
With GnuTLS 3.2 I get the following:
pkg-config --libs --static gnutls -lgnutls -lhogweed -lnettle -lz -lgmp
Maybe that helps?
Unfortunately, no:
Fedora 19: $ pkg-config --libs --static gnutls -lgnutls -lnettle -lhogweed -lgmp -lpthread -ltasn1 -lp11-kit -lz
Correct - nettle instead of gcrypt.
RHEL 6.4: $ pkg-config --libs --static gnutls -lgnutls -ltasn1
Ouch - no mention of gcrypt, even though this version still used gcrypt.
Well that's not really to problematic. RHEL 6.4 uses gnutls 2.8.x which didn't have any concept of nettle at that point. nettle wasn't introduced as a supported backend until 2.12 [1]. So let's rework the patch to assume libgcrypt before gnutls 2.12 and then starting with 2.12 we double probe for nettle or libgcrypt.
[1] http://lists.gnu.org/archive/html/gnutls-devel/2011-03/msg00034.html -- Doug Goldstein
What about squashing something like this into your patch? I know its a bit ugly but I'm hoping your autoconf knowledge can clean it up a little bit. diff --git a/configure.ac b/configure.ac index eb56b63..c8ddd5b 100644 --- a/configure.ac +++ b/configure.ac @@ -1082,7 +1082,7 @@ if test "x$with_gnutls" != "xno"; then dnl gcrypt PKG_CHECK_MODULES(GNUTLS, gnutls >= $GNUTLS_REQUIRED, [GNUTLS_FOUND=yes - PKG_CHECK_MODULES([GNUTLS], [gnutls >= 3.0], [], [GNUTLS_GCRYPT=yes])], + PKG_CHECK_MODULES([GNUTLS], [gnutls >= 2.12], [], [GNUTLS_GCRYPT=yes])], [GNUTLS_FOUND=no]) fi if test "$GNUTLS_FOUND" = "no"; then @@ -1105,6 +1105,16 @@ if test "x$with_gnutls" != "xno"; then AC_MSG_ERROR([You must install the GnuTLS library in order to compile and run libvirt]) fi else + dnl Unfortunately we need to detect if the user has gnutls built against + dnl gcrypt or nettle for gnutls 2.12 and newer but there isn't a pretty + dnl way to do it. + if test "$GNUTLS_GCRYPT" = no; then + pkg_config_save="$PKG_CONFIG" + PKG_CONFIG="$PKG_CONFIG --static" + PKG_CHECK_MODULES([GNUTLS_CRYPTO], [gnutls >= 2.12]) + PKG_CONFIG="$pkg_config_save" + echo "$GNUTLS_CRYPTO_LIBS" | grep -q "lgcrypt" && GNUTLS_GCRYPT=yes + fi dnl If gnutls linked against -lgcrypt, then we must initialize gcrypt dnl prior to using gnutls. Newer versions of gnutls use -lnettle, in dnl which case we don't want to drag in gcrypt ourselves. I get the following output from ./configure for gnutls on the platforms below: Gentoo: -lgnutls Fedora 18: -I/usr/include/p11-kit-1 -DGCRYPT_NO_DEPRECATED -lgnutls -lgcrypt Unfortunately I can't test RHEL6 right now but will later. -- Doug Goldstein

On Fri, Jul 26, 2013 at 08:22:29PM -0500, Doug Goldstein wrote:
On Fri, Jul 26, 2013 at 5:04 PM, Eric Blake <eblake@redhat.com> wrote:
https://bugzilla.redhat.com/show_bug.cgi?id=951637
Newer gnutls uses nettle, rather than gcrypt, which is a lot nicer regarding initialization. Yet we were unconditionally initializing gcrypt even when gnutls wouldn't be using it, and having two crypto libraries linked into libvirt.so is pointless.
Assume that the switch to gnutls 3.0 is a reliable witness, when pkg-config is present; otherwise be pessimistic and use gcrypt.
* configure.ac (WITH_GNUTLS): Probe whether to add -lgcrypt, and define a witness WITH_GNUTLS_GCRYPT. * src/libvirt.c (virTLSMutexInit, virTLSMutexDestroy) (virTLSMutexLock, virTLSMutexUnlock, virTLSThreadImpl) (virGlobalInit): Honor the witness. * libvirt.spec.in (BuildRequires): Make gcrypt usage conditional, no longer needed in Fedora 19.
Signed-off-by: Eric Blake <eblake@redhat.com> ---
v2: use second pkg-config invocation rather than ldd to determine whether gnutls uses gcrypt
configure.ac | 27 +++++++++++++++++++-------- libvirt.spec.in | 2 ++ src/libvirt.c | 10 ++++++---- 3 files changed, 27 insertions(+), 12 deletions(-)
diff --git a/configure.ac b/configure.ac index cc9942a..eb56b63 100644 --- a/configure.ac +++ b/configure.ac @@ -1076,12 +1076,19 @@ if test "x$with_gnutls" != "xno"; then LIBS="$LIBS $GNUTLS_LIBS"
GNUTLS_FOUND=no + GNUTLS_GCRYPT=no if test -x "$PKG_CONFIG" ; then + dnl double probe, since we know that gnutls 3.0 switched to nettle instead of + dnl gcrypt PKG_CHECK_MODULES(GNUTLS, gnutls >= $GNUTLS_REQUIRED, - [GNUTLS_FOUND=yes], [GNUTLS_FOUND=no]) + [GNUTLS_FOUND=yes + PKG_CHECK_MODULES([GNUTLS], [gnutls >= 3.0], [], [GNUTLS_GCRYPT=yes])], + [GNUTLS_FOUND=no]) fi if test "$GNUTLS_FOUND" = "no"; then + dnl pkg-config couldn't help us, assume gcrypt is necessary fail=0 + GNUTLS_GCRYPT=yes AC_CHECK_HEADER([gnutls/gnutls.h], [], [fail=1]) AC_CHECK_LIB([gnutls], [gnutls_handshake],[], [fail=1], [-lgcrypt])
@@ -1098,13 +1105,17 @@ if test "x$with_gnutls" != "xno"; then AC_MSG_ERROR([You must install the GnuTLS library in order to compile and run libvirt]) fi else - dnl Not all versions of gnutls include -lgcrypt, and so we add - dnl it explicitly for the calls to gcry_control/check_version - GNUTLS_LIBS="$GNUTLS_LIBS -lgcrypt" - - dnl We're not using gcrypt deprecated features so define - dnl GCRYPT_NO_DEPRECATED to avoid deprecated warnings - GNUTLS_CFLAGS="$GNUTLS_CFLAGS -DGCRYPT_NO_DEPRECATED" + dnl If gnutls linked against -lgcrypt, then we must initialize gcrypt + dnl prior to using gnutls. Newer versions of gnutls use -lnettle, in + dnl which case we don't want to drag in gcrypt ourselves. + if test "$GNUTLS_GCRYPT" = yes; then + GNUTLS_LIBS="$GNUTLS_LIBS -lgcrypt" + dnl We're not using gcrypt deprecated features so define + dnl GCRYPT_NO_DEPRECATED to avoid deprecated warnings + GNUTLS_CFLAGS="$GNUTLS_CFLAGS -DGCRYPT_NO_DEPRECATED" + AC_DEFINE_UNQUOTED([WITH_GNUTLS_GCRYPT], 1, + [set to 1 if it is known or assumed that GNUTLS uses gcrypt]) + fi
dnl gnutls 3.x moved some declarations to a new header AC_CHECK_HEADERS([gnutls/crypto.h], [], [], [[ diff --git a/libvirt.spec.in b/libvirt.spec.in index e0e0004..4320281 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -422,7 +422,9 @@ BuildRequires: readline-devel BuildRequires: ncurses-devel BuildRequires: gettext BuildRequires: libtasn1-devel +%if (0%{?rhel} && 0%{?rhel} < 7) || (0%{?fedora} && 0%{?fedora} < 19) BuildRequires: libgcrypt-devel +%endif BuildRequires: gnutls-devel BuildRequires: libattr-devel %if %{with_libvirtd} diff --git a/src/libvirt.c b/src/libvirt.c index 8157488..66e8248 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -55,7 +55,9 @@ #include "intprops.h" #include "virconf.h" #if WITH_GNUTLS -# include <gcrypt.h> +# if WITH_GNUTLS_GCRYPT +# include <gcrypt.h> +# endif # include "rpc/virnettlscontext.h" #endif #include "vircommand.h" @@ -270,7 +272,7 @@ winsock_init(void) #endif
-#ifdef WITH_GNUTLS +#ifdef WITH_GNUTLS_GCRYPT static int virTLSMutexInit(void **priv) { virMutexPtr lock = NULL; @@ -323,7 +325,7 @@ static struct gcry_thread_cbs virTLSThreadImpl = { virTLSMutexUnlock, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; -#endif +#endif /* WITH_GNUTLS_GCRYPT */
/* Helper macros to implement VIR_DOMAIN_DEBUG using just C99. This * assumes you pass fewer than 15 arguments to VIR_DOMAIN_DEBUG, but @@ -407,7 +409,7 @@ virGlobalInit(void) virErrorInitialize() < 0) goto error;
-#ifdef WITH_GNUTLS +#ifdef WITH_GNUTLS_GCRYPT /* * This sequence of API calls it copied exactly from * gnutls 2.12.23 source lib/gcrypt/init.c, with -- 1.8.3.1
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Hate to throw a monkey wrench in the plan, but GnuTLS 3.0 isn't the nettle cut over. On my stable Gentoo box with GnuTLS 2.12.23, its using nettle as seen by ldd.
ldd /usr/lib64/libgnutls.so.26 linux-vdso.so.1 (0x00007fffad3ff000) libnettle.so.4 => /usr/lib64/libnettle.so.4 (0x00007f60fa4f4000) libgmp.so.10 => /usr/lib64/libgmp.so.10 (0x00007f60fa284000) libhogweed.so.2 => /usr/lib64/libhogweed.so.2 (0x00007f60fa054000) libz.so.1 => /lib64/libz.so.1 (0x00007f60f9e3e000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f60f9c21000) libtasn1.so.3 => /usr/lib64/libtasn1.so.3 (0x00007f60f9a0f000) libc.so.6 => /lib64/libc.so.6 (0x00007f60f9661000) /lib64/ld-linux-x86-64.so.2 (0x00007f60fa9ec000)
It appears it was an optional cutover and I guess Gentoo made the plunge. Another idea, that you might hate would be to use pkg-config directly and pass --static so we can get the private libraries. I'm not running Fedora 19 yet so the best I can do is give you Fedora 18 as a comp, but that works out great since its using 2.12.23 as well.
Hmm, so Eric's patch is mostly just an optimization, to avoid uneccessarily linking to libgcrypt. If we link to libgcrypt when gnutls is using nettle nothing bad really happens. We just unecessarily initialize gcrypt. Conversely, if we do not link to libgcrypt, when gnutls is using libgcrypt, then we are missing important initialization code, which *is* bad. IOW, doing the check against version 3.0.0 or later does not cause any problems, since we know that libgcrypt can never be used with that version. If we do a check against 2.12 though, we could miss out linkage against libgcrypt depending on how the distro built their packages. So unless we can come up with an easy & reliable way to detect use of nettle with 2.x versions, I'm inclined to just stick our heads in the sand and pretend that no 2.x version ever used nettle. Worst case we link to and initialize gcrypt, which is not a bad problem. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 07/29/2013 04:25 AM, Daniel P. Berrange wrote:
On Fri, Jul 26, 2013 at 08:22:29PM -0500, Doug Goldstein wrote:
On Fri, Jul 26, 2013 at 5:04 PM, Eric Blake <eblake@redhat.com> wrote:
https://bugzilla.redhat.com/show_bug.cgi?id=951637
Newer gnutls uses nettle, rather than gcrypt, which is a lot nicer regarding initialization. Yet we were unconditionally initializing gcrypt even when gnutls wouldn't be using it, and having two crypto libraries linked into libvirt.so is pointless.
Assume that the switch to gnutls 3.0 is a reliable witness, when pkg-config is present; otherwise be pessimistic and use gcrypt.
Hate to throw a monkey wrench in the plan, but GnuTLS 3.0 isn't the nettle cut over. On my stable Gentoo box with GnuTLS 2.12.23, its using nettle as seen by ldd.
It appears it was an optional cutover and I guess Gentoo made the plunge. Another idea, that you might hate would be to use pkg-config directly and pass --static so we can get the private libraries. I'm not running Fedora 19 yet so the best I can do is give you Fedora 18 as a comp, but that works out great since its using 2.12.23 as well.
Hmm, so Eric's patch is mostly just an optimization, to avoid uneccessarily linking to libgcrypt. If we link to libgcrypt when gnutls is using nettle nothing bad really happens. We just unecessarily initialize gcrypt.
So, should I try for a v3 that treats: < 2.12 - gcrypt only
= 3.0 - nettle only <= 2.12 && < 3.0 - assume gcrypt unless 'pkg-config --static' proves the use of nettle instead of gcrypt
or do we just stick with v2? Also, is this still worth getting in before 1.1.1, or since (as Dan pointed out) this is just an optimization and not a correctness issue, should we wait until after the release so we aren't rushing things?
Conversely, if we do not link to libgcrypt, when gnutls is using libgcrypt, then we are missing important initialization code, which *is* bad.
IOW, doing the check against version 3.0.0 or later does not cause any problems, since we know that libgcrypt can never be used with that version.
If we do a check against 2.12 though, we could miss out linkage against libgcrypt depending on how the distro built their packages.
So unless we can come up with an easy & reliable way to detect use of nettle with 2.x versions, I'm inclined to just stick our heads in the sand and pretend that no 2.x version ever used nettle. Worst case we link to and initialize gcrypt, which is not a bad problem.
Versions less than 2.12 (such as RHEL 6) don't matter - and so far, 'pkg-config --static' appears to be reliable on all 2.12 builds whether or not they made the switch. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
participants (3)
-
Daniel P. Berrange
-
Doug Goldstein
-
Eric Blake