[PATCH] tls: Don't require 'keyEncipherment' to be enabled altoghther

Peter Krempa via Devel posted 1 patch 5 months, 2 weeks ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/libvirt tags/patchew/d23a3793b9fb18bf2e31ec1ed3fb710f858fda9d.1751304305.git.pkrempa@redhat.com
src/rpc/virnettlscert.c | 28 ----------------------------
1 file changed, 28 deletions(-)
[PATCH] tls: Don't require 'keyEncipherment' to be enabled altoghther
Posted by Peter Krempa via Devel 5 months, 2 weeks ago
From: Peter Krempa <pkrempa@redhat.com>

Key encipherment is required only for RSA key exchange algorithm. With
TLS 1.3 this is not even used as RSA is used only for authentication.

Since we can't really check when it's required ahead of time drop the
check completely. GnuTLS will moan if it will not be able to use RSA
key exchange.

In commit 11867b0224a2 I tried to relax the check for some eliptic
curve algorithm that explicitly forbid it. Based on the above the proper
solution is to completely remove it.

Resolves: https://issues.redhat.com/browse/RHEL-100711
Fixes: 11867b0224a2b8dc34755ff0ace446b6842df1c1
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
---
 src/rpc/virnettlscert.c | 28 ----------------------------
 1 file changed, 28 deletions(-)

diff --git a/src/rpc/virnettlscert.c b/src/rpc/virnettlscert.c
index f197995633..7024e858f0 100644
--- a/src/rpc/virnettlscert.c
+++ b/src/rpc/virnettlscert.c
@@ -162,34 +162,6 @@ static int virNetTLSCertCheckKeyUsage(gnutls_x509_crt_t cert,
                          certFile);
             }
         }
-        if (!(usage & GNUTLS_KEY_KEY_ENCIPHERMENT)) {
-            int alg = gnutls_x509_crt_get_pk_algorithm(cert, NULL);
-
-            /* Per RFC8813 [1] which amends RFC5580 [2] ECDSA, ECDH, and ECMQV
-             * algorithms must not have 'keyEncipherment' present.
-             *
-             * [1] https://datatracker.ietf.org/doc/rfc8813/
-             * [2] https://datatracker.ietf.org/doc/rfc5480
-             */
-
-            switch (alg) {
-            case GNUTLS_PK_ECDSA:
-            case GNUTLS_PK_ECDH_X25519:
-            case GNUTLS_PK_ECDH_X448:
-                break;
-
-            default:
-                if (critical) {
-                    virReportError(VIR_ERR_SYSTEM_ERROR,
-                                   _("Certificate %1$s usage does not permit key encipherment"),
-                                   certFile);
-                    return -1;
-                } else {
-                    VIR_WARN("Certificate %s usage does not permit key encipherment",
-                             certFile);
-                }
-            }
-        }
     }

     return 0;
-- 
2.49.0
Re: [PATCH] tls: Don't require 'keyEncipherment' to be enabled altoghther
Posted by Daniel P. Berrangé via Devel 5 months, 2 weeks ago
On Mon, Jun 30, 2025 at 07:25:05PM +0200, Peter Krempa via Devel wrote:
> From: Peter Krempa <pkrempa@redhat.com>
> 
> Key encipherment is required only for RSA key exchange algorithm. With
> TLS 1.3 this is not even used as RSA is used only for authentication.
> 
> Since we can't really check when it's required ahead of time drop the
> check completely. GnuTLS will moan if it will not be able to use RSA
> key exchange.

GNUTLS only reports problems at runtime, while the libvirt code is
used at system startup. This greatly improves the debuggability of
sysadmin config screwups, so we don't really want to delegate to
GNUTLS for this.

> In commit 11867b0224a2 I tried to relax the check for some eliptic
> curve algorithm that explicitly forbid it. Based on the above the proper
> solution is to completely remove it.

We need to invert the check - instead of excluding just ECDSA, we
need to include only DSA and GHOST algorithms.


With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
Re: [PATCH] tls: Don't require 'keyEncipherment' to be enabled altoghther
Posted by Peter Krempa via Devel 5 months, 2 weeks ago
On Tue, Jul 01, 2025 at 09:49:57 +0100, Daniel P. Berrangé wrote:
> On Mon, Jun 30, 2025 at 07:25:05PM +0200, Peter Krempa via Devel wrote:
> > From: Peter Krempa <pkrempa@redhat.com>
> > 
> > Key encipherment is required only for RSA key exchange algorithm. With
> > TLS 1.3 this is not even used as RSA is used only for authentication.
> > 
> > Since we can't really check when it's required ahead of time drop the
> > check completely. GnuTLS will moan if it will not be able to use RSA
> > key exchange.
> 
> GNUTLS only reports problems at runtime, while the libvirt code is
> used at system startup. This greatly improves the debuggability of
> sysadmin config screwups, so we don't really want to delegate to
> GNUTLS for this.
> 
> > In commit 11867b0224a2 I tried to relax the check for some eliptic
> > curve algorithm that explicitly forbid it. Based on the above the proper
> > solution is to completely remove it.
> 
> We need to invert the check - instead of excluding just ECDSA, we
> need to include only DSA and GHOST algorithms.

Originally I did the same but then I read (and verified; see my
followup) that with TLS 1.3 the RSA key exchange algorithm isn't even
used so keyEncipherment capability isn't even needed.

The pre-verification doesn't really allow us checking which protocol
will be used.

If you thing it's important to stay compatible in the pre-check also
with older protocols then I can keep it but to me it didn't make too
much sense.
Re: [PATCH] tls: Don't require 'keyEncipherment' to be enabled altoghther
Posted by Daniel P. Berrangé via Devel 5 months, 2 weeks ago
On Tue, Jul 01, 2025 at 10:59:06AM +0200, Peter Krempa wrote:
> On Tue, Jul 01, 2025 at 09:49:57 +0100, Daniel P. Berrangé wrote:
> > On Mon, Jun 30, 2025 at 07:25:05PM +0200, Peter Krempa via Devel wrote:
> > > From: Peter Krempa <pkrempa@redhat.com>
> > > 
> > > Key encipherment is required only for RSA key exchange algorithm. With
> > > TLS 1.3 this is not even used as RSA is used only for authentication.
> > > 
> > > Since we can't really check when it's required ahead of time drop the
> > > check completely. GnuTLS will moan if it will not be able to use RSA
> > > key exchange.
> > 
> > GNUTLS only reports problems at runtime, while the libvirt code is
> > used at system startup. This greatly improves the debuggability of
> > sysadmin config screwups, so we don't really want to delegate to
> > GNUTLS for this.
> > 
> > > In commit 11867b0224a2 I tried to relax the check for some eliptic
> > > curve algorithm that explicitly forbid it. Based on the above the proper
> > > solution is to completely remove it.
> > 
> > We need to invert the check - instead of excluding just ECDSA, we
> > need to include only DSA and GHOST algorithms.
> 
> Originally I did the same but then I read (and verified; see my
> followup) that with TLS 1.3 the RSA key exchange algorithm isn't even
> used so keyEncipherment capability isn't even needed.

Ok, yeah, I've found that now too.

If we're removing this entirely from the impl, we should also update
the docs/kbase/tlscerts.rst.

IIRC, we need to remove the 'encryption_key' flag to stop gnutls
adding 'key encipherment' to DSA certs.

> If you thing it's important to stay compatible in the pre-check also
> with older protocols then I can keep it but to me it didn't make too
> much sense.

Yeah, TLS 1.3 is effectively the baseline for libvirt unless talking to
very old systems, as gnutls will preferentially negotiate it, we only
need care about libvirt clients.

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
Re: [PATCH] tls: Don't require 'keyEncipherment' to be enabled altoghther
Posted by Peter Krempa via Devel 5 months, 2 weeks ago
On Tue, Jul 01, 2025 at 11:38:37 +0100, Daniel P. Berrangé wrote:
> On Tue, Jul 01, 2025 at 10:59:06AM +0200, Peter Krempa wrote:
> > On Tue, Jul 01, 2025 at 09:49:57 +0100, Daniel P. Berrangé wrote:
> > > On Mon, Jun 30, 2025 at 07:25:05PM +0200, Peter Krempa via Devel wrote:
> > > > From: Peter Krempa <pkrempa@redhat.com>
> > > > 
> > > > Key encipherment is required only for RSA key exchange algorithm. With
> > > > TLS 1.3 this is not even used as RSA is used only for authentication.
> > > > 
> > > > Since we can't really check when it's required ahead of time drop the
> > > > check completely. GnuTLS will moan if it will not be able to use RSA
> > > > key exchange.
> > > 
> > > GNUTLS only reports problems at runtime, while the libvirt code is
> > > used at system startup. This greatly improves the debuggability of
> > > sysadmin config screwups, so we don't really want to delegate to
> > > GNUTLS for this.
> > > 
> > > > In commit 11867b0224a2 I tried to relax the check for some eliptic
> > > > curve algorithm that explicitly forbid it. Based on the above the proper
> > > > solution is to completely remove it.
> > > 
> > > We need to invert the check - instead of excluding just ECDSA, we
> > > need to include only DSA and GHOST algorithms.
> > 
> > Originally I did the same but then I read (and verified; see my
> > followup) that with TLS 1.3 the RSA key exchange algorithm isn't even
> > used so keyEncipherment capability isn't even needed.
> 
> Ok, yeah, I've found that now too.
> 
> If we're removing this entirely from the impl, we should also update
> the docs/kbase/tlscerts.rst.
> 
> IIRC, we need to remove the 'encryption_key' flag to stop gnutls
> adding 'key encipherment' to DSA certs.

I've found that removing the flag isn't necessary. gnutls just doesn't
use it with keys that don't support it.

I've actually used my very old script built on the examples from the
above page and just added use of one of the fancy new "post quantum"
signature algorithms and it simply worked ven with "encryption_key"
being present in the 'info' file.

> 
> > If you thing it's important to stay compatible in the pre-check also
> > with older protocols then I can keep it but to me it didn't make too
> > much sense.
> 
> Yeah, TLS 1.3 is effectively the baseline for libvirt unless talking to
> very old systems, as gnutls will preferentially negotiate it, we only
> need care about libvirt clients.

Based on this I guess we could drop it from the examples. I think that
it'd be much more beneficial to hint to better ciphers (but that'd also
effectively make it obsolete). 
Re: [PATCH] tls: Don't require 'keyEncipherment' to be enabled altoghther
Posted by Daniel P. Berrangé via Devel 5 months, 2 weeks ago
On Tue, Jul 01, 2025 at 01:13:36PM +0200, Peter Krempa wrote:
> On Tue, Jul 01, 2025 at 11:38:37 +0100, Daniel P. Berrangé wrote:
> > On Tue, Jul 01, 2025 at 10:59:06AM +0200, Peter Krempa wrote:
> > > On Tue, Jul 01, 2025 at 09:49:57 +0100, Daniel P. Berrangé wrote:
> > > > On Mon, Jun 30, 2025 at 07:25:05PM +0200, Peter Krempa via Devel wrote:
> > > > > From: Peter Krempa <pkrempa@redhat.com>
> > > > > 
> > > > > Key encipherment is required only for RSA key exchange algorithm. With
> > > > > TLS 1.3 this is not even used as RSA is used only for authentication.
> > > > > 
> > > > > Since we can't really check when it's required ahead of time drop the
> > > > > check completely. GnuTLS will moan if it will not be able to use RSA
> > > > > key exchange.
> > > > 
> > > > GNUTLS only reports problems at runtime, while the libvirt code is
> > > > used at system startup. This greatly improves the debuggability of
> > > > sysadmin config screwups, so we don't really want to delegate to
> > > > GNUTLS for this.
> > > > 
> > > > > In commit 11867b0224a2 I tried to relax the check for some eliptic
> > > > > curve algorithm that explicitly forbid it. Based on the above the proper
> > > > > solution is to completely remove it.
> > > > 
> > > > We need to invert the check - instead of excluding just ECDSA, we
> > > > need to include only DSA and GHOST algorithms.
> > > 
> > > Originally I did the same but then I read (and verified; see my
> > > followup) that with TLS 1.3 the RSA key exchange algorithm isn't even
> > > used so keyEncipherment capability isn't even needed.
> > 
> > Ok, yeah, I've found that now too.
> > 
> > If we're removing this entirely from the impl, we should also update
> > the docs/kbase/tlscerts.rst.
> > 
> > IIRC, we need to remove the 'encryption_key' flag to stop gnutls
> > adding 'key encipherment' to DSA certs.
> 
> I've found that removing the flag isn't necessary. gnutls just doesn't
> use it with keys that don't support it.
> 
> I've actually used my very old script built on the examples from the
> above page and just added use of one of the fancy new "post quantum"
> signature algorithms and it simply worked ven with "encryption_key"
> being present in the 'info' file.

Yes, gnutls simply ignores the 'encryption_key' setting in most
cases, but we should remove it from docs given that it is
redundant & potentially misleading.

> > > If you thing it's important to stay compatible in the pre-check also
> > > with older protocols then I can keep it but to me it didn't make too
> > > much sense.
> > 
> > Yeah, TLS 1.3 is effectively the baseline for libvirt unless talking to
> > very old systems, as gnutls will preferentially negotiate it, we only
> > need care about libvirt clients.
> 
> Based on this I guess we could drop it from the examples. I think that
> it'd be much more beneficial to hint to better ciphers (but that'd also
> effectively make it obsolete). 

We've generally assumed that gnutls will pick the best ciphers itself
based on crypto priority config on the host. 

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
Re: [PATCH] tls: Don't require 'keyEncipherment' to be enabled altoghther
Posted by Daniel P. Berrangé via Devel 5 months, 2 weeks ago
On Tue, Jul 01, 2025 at 11:38:37AM +0100, Daniel P. Berrangé via Devel wrote:
> On Tue, Jul 01, 2025 at 10:59:06AM +0200, Peter Krempa wrote:
> > On Tue, Jul 01, 2025 at 09:49:57 +0100, Daniel P. Berrangé wrote:
> > > On Mon, Jun 30, 2025 at 07:25:05PM +0200, Peter Krempa via Devel wrote:
> > > > From: Peter Krempa <pkrempa@redhat.com>
> > > > 
> > > > Key encipherment is required only for RSA key exchange algorithm. With
> > > > TLS 1.3 this is not even used as RSA is used only for authentication.
> > > > 
> > > > Since we can't really check when it's required ahead of time drop the
> > > > check completely. GnuTLS will moan if it will not be able to use RSA
> > > > key exchange.
> > > 
> > > GNUTLS only reports problems at runtime, while the libvirt code is
> > > used at system startup. This greatly improves the debuggability of
> > > sysadmin config screwups, so we don't really want to delegate to
> > > GNUTLS for this.
> > > 
> > > > In commit 11867b0224a2 I tried to relax the check for some eliptic
> > > > curve algorithm that explicitly forbid it. Based on the above the proper
> > > > solution is to completely remove it.
> > > 
> > > We need to invert the check - instead of excluding just ECDSA, we
> > > need to include only DSA and GHOST algorithms.
> > 
> > Originally I did the same but then I read (and verified; see my
> > followup) that with TLS 1.3 the RSA key exchange algorithm isn't even
> > used so keyEncipherment capability isn't even needed.
> 
> Ok, yeah, I've found that now too.
> 
> If we're removing this entirely from the impl, we should also update
> the docs/kbase/tlscerts.rst.
> 
> IIRC, we need to remove the 'encryption_key' flag to stop gnutls
> adding 'key encipherment' to DSA certs.

Also our test suite uses

  GNUTLS_KEY_KEY_ENCIPHERMENT

when creating test certs and so that can go.


With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
Re: [PATCH] tls: Don't require 'keyEncipherment' to be enabled altoghther
Posted by Peter Krempa via Devel 5 months, 2 weeks ago
On Mon, Jun 30, 2025 at 19:25:05 +0200, Peter Krempa wrote:
> From: Peter Krempa <pkrempa@redhat.com>
> 
> Key encipherment is required only for RSA key exchange algorithm. With
> TLS 1.3 this is not even used as RSA is used only for authentication.
> 
> Since we can't really check when it's required ahead of time drop the
> check completely. GnuTLS will moan if it will not be able to use RSA
> key exchange.
> 
> In commit 11867b0224a2 I tried to relax the check for some eliptic
> curve algorithm that explicitly forbid it. Based on the above the proper
> solution is to completely remove it.
> 
> Resolves: https://issues.redhat.com/browse/RHEL-100711
> Fixes: 11867b0224a2b8dc34755ff0ace446b6842df1c1
> Signed-off-by: Peter Krempa <pkrempa@redhat.com>
> ---

I've tested this by creating a client certificate with following info:

organization = test
cn = HOST
tls_www_server
signing_key

(thus missing 'encryption_key' field)

Attempting to use currently relased libvirt results in:

 $ virsh -c qemu+tls://speedmetal/system list
 error: failed to connect to the hypervisor
 error: Certificate /etc/pki/libvirt/clientcert.pem usage does not permit key encipherment

Whereas with patched libvirt:

 $ ./build/libvirt/gcc/tools/virsh -c qemu+tls://speedmetal/system list
  Id   Name   State
 ----------------------
  1    ha     running