All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] tlshd: Allow the use of post-quantum cryptography
@ 2025-08-28 22:23 Scott Mayhew
  2025-08-28 22:23 ` [PATCH 1/5] tlshd: Fix priority string to allow PQC Scott Mayhew
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Scott Mayhew @ 2025-08-28 22:23 UTC (permalink / raw)
  To: chuck.lever; +Cc: kernel-tls-handshake

These patches allow tlshd to use post-quantum cryptography.  The first
patch fixes the priority string and allows the PQ algorithms to be used.
The remaining patches implement dual certificate support.  Dual
certificates are necessary to enable a smooth transition period,
allowing servers to work with both clients that are PQ-enabled and
clients that are not.  The server will prefer the ML-DSA certificate but
will fall back to the traditional certificate for clients that do not
support ML-DSA.

For those who prefer a web UI, these patches are also available in this
branch:
https://github.com/scottmayhew/ktls-utils/tree/pqc

To use these patches, you need a recent version of gnutls as well as
crypto-policies (if used by your distro).  These commands will help you
determine if your gnutls has the necessary stuff:

$ gnutls-cli -l | grep ML-DSA
$ gnutls-cli -l | grep MLKEM

You'll need to generate a cert using ML-DSA-44/ML-DSA-65/ML-DSA-87.  For
example, here's how I generate a self-signed cert using ML-DSA-65:

$ openssl req -new -x509 -newkey mldsa65 -days 365 \
	-keyout /etc/pki/tls/private/rhel10.smayhew.test.mldsa65.key \
	-out /etc/pki/tls/certs/rhel10.smayhew.test.mldsa65.pem \
	-subj "/CN=rhel10.smayhew.test" \
	-addext "subjectAltName=DNS:rhel10.smayhew.test,IP:192.168.124.69" \
	-noenc -quiet

Obviously if you're using openssl to generate your certs, you'll need a
recent openssl too.  Or you can use certtool if you prefer the gnutls
utilities.

You'll need to add the cert and key to the relevant sections of
tlshd.conf and you should be good to go.

If you have debug logging turned on, you should see this if you perform a
handshake with a PQ-enabled peer you should see something like this:

Aug 28 17:58:25 rhel10.smayhew.test tlshd[3291]: Session description: (TLS1.3)-(HYBRID-X25519-MLKEM768)-(ML-DSA-65)-(AES-256-GCM)

and if you perform a handshake with a non-PQ-enabled peer:

Aug 28 18:04:21 rhel10.smayhew.test tlshd[3352]: Session description: (TLS1.3)-(ECDHE-X25519)-(RSA-PSS-RSAE-SHA256)-(AES-256-GCM)


Scott Mayhew (5):
  tlshd: Fix priority string to allow PQC
  tlshd: Server-side dual certificate support
  tlshd: Make sure x509.pq.certificate is using a PQ public-key alg
  tlshd: Make sure the client supports the PQ pk alg used by the server
    cert
  tlshd: Client-side dual certificate support

 configure.ac             | 12 +++++
 src/tlshd/client.c       | 66 +++++++++++++++++++++++++--
 src/tlshd/config.c       | 97 +++++++++++++++++++++++++++++++++++-----
 src/tlshd/ktls.c         |  2 +-
 src/tlshd/server.c       | 86 +++++++++++++++++++++++++++++++++--
 src/tlshd/tlshd.conf     |  4 ++
 src/tlshd/tlshd.conf.man | 15 +++++++
 src/tlshd/tlshd.h        | 18 +++++---
 8 files changed, 276 insertions(+), 24 deletions(-)

-- 
2.50.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/5] tlshd: Fix priority string to allow PQC
  2025-08-28 22:23 [PATCH 0/5] tlshd: Allow the use of post-quantum cryptography Scott Mayhew
@ 2025-08-28 22:23 ` Scott Mayhew
  2025-08-29 16:47   ` Chuck Lever
  2025-08-28 22:23 ` [PATCH 2/5] tlshd: Server-side dual certificate support Scott Mayhew
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Scott Mayhew @ 2025-08-28 22:23 UTC (permalink / raw)
  To: chuck.lever; +Cc: kernel-tls-handshake

Specifying either of the SECURE256 or SECURE128 keywords in the priority
string results in the ML-DSA algorithms being disabled because the
post-quantum algorithms do not map nicely to the security
classifications based on "bits of security" used for traditional
algorithms [1].

Use @SYSTEM instead, which will allow PQC on systems with newer versions
of GnuTLS.  It will also allow users to disable PQC via a policy module
(on systems with the crypto-policies package).

[1] https://csrc.nist.gov/CSRC/media/Projects/Post-Quantum-Cryptography/documents/call-for-proposals-final-dec-2016.pdf#page=15

Link: https://github.com/oracle/ktls-utils/issues/113
Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
 src/tlshd/ktls.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tlshd/ktls.c b/src/tlshd/ktls.c
index 40a26a4..866a023 100644
--- a/src/tlshd/ktls.c
+++ b/src/tlshd/ktls.c
@@ -357,7 +357,7 @@ static int tlshd_gnutls_priority_init_list(const unsigned int *ciphers,
 	const char *errpos;
 	int ret, i;
 
-	pstring = strdup("SECURE256:+SECURE128:-COMP-ALL");
+	pstring = strdup("@SYSTEM:-COMP-ALL");
 	if (!pstring)
 		return -ENOMEM;
 
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/5] tlshd: Server-side dual certificate support
  2025-08-28 22:23 [PATCH 0/5] tlshd: Allow the use of post-quantum cryptography Scott Mayhew
  2025-08-28 22:23 ` [PATCH 1/5] tlshd: Fix priority string to allow PQC Scott Mayhew
@ 2025-08-28 22:23 ` Scott Mayhew
  2025-08-29 16:59   ` Chuck Lever
  2025-08-28 22:23 ` [PATCH 3/5] tlshd: Make sure x509.pq.certificate is using a PQ public-key alg Scott Mayhew
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Scott Mayhew @ 2025-08-28 22:23 UTC (permalink / raw)
  To: chuck.lever; +Cc: kernel-tls-handshake

Add two new config options, "x509.pq.certificate" and
"x509.pq.private_key" to configure tlshd to use an ML-DSA certificate.
If the cert callback determines that the client supports ML-DSA, it will
select this certificate.  Otherwise, it will fall back to the
traditional certficate (i.e. the certificate configured via
"x509.certificate" and "x509.private_key").

Link: https://github.com/oracle/ktls-utils/issues/113
Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
 configure.ac             | 12 ++++++++
 src/tlshd/config.c       | 12 +++++---
 src/tlshd/server.c       | 59 ++++++++++++++++++++++++++++++++++++++--
 src/tlshd/tlshd.conf     |  2 ++
 src/tlshd/tlshd.conf.man | 13 +++++++++
 src/tlshd/tlshd.h        |  6 ++--
 6 files changed, 96 insertions(+), 8 deletions(-)

diff --git a/configure.ac b/configure.ac
index a6d9d09..0dd23f2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -79,6 +79,18 @@ AC_CHECK_LIB([gnutls], [gnutls_get_system_config_file],
 AC_CHECK_LIB([gnutls], [gnutls_psk_allocate_client_credentials2],
              [AC_DEFINE([HAVE_GNUTLS_PSK_ALLOCATE_CREDENTIALS2], [1],
                         [Define to 1 if you have the gnutls_psk_allocate_client_credentials2 function.])])
+
+AC_MSG_CHECKING(for ML-DSA support in gnutls)
+AC_COMPILE_IFELSE(
+	[AC_LANG_PROGRAM([[ #include <gnutls/gnutls.h> ]],
+		[[ (void) GNUTLS_SIGN_MLDSA65; ]])],
+	[ have_mldsa=yes ],
+	[ have_mldsa=no ])
+AC_MSG_RESULT([$have_mldsa])
+if test "x$have_mldsa" = xyes ; then
+	AC_DEFINE([HAVE_GNUTLS_MLDSA], [1], [Define to 1 if gnutls supports ML-DSA])
+fi
+
 AC_SUBST([AM_CPPFLAGS])
 
 AC_CONFIG_FILES([Makefile src/Makefile src/tlshd/Makefile systemd/Makefile])
diff --git a/src/tlshd/config.c b/src/tlshd/config.c
index 4c54d37..20634dd 100644
--- a/src/tlshd/config.c
+++ b/src/tlshd/config.c
@@ -403,6 +403,7 @@ bool tlshd_config_get_server_crl(char **result)
 
 /**
  * tlshd_config_get_server_certs - Get certs for ServerHello from .conf
+ * @key: IN: the key field name from .conf
  * @certs: OUT: in-memory certificates
  * @certs_len: IN: maximum number of certs to get, OUT: number of certs found
  *
@@ -410,7 +411,8 @@ bool tlshd_config_get_server_crl(char **result)
  *   %true: certificate retrieved successfully
  *   %false: certificate not retrieved
  */
-bool tlshd_config_get_server_certs(gnutls_pcert_st *certs,
+bool tlshd_config_get_server_certs(const gchar *key,
+				   gnutls_pcert_st *certs,
 				   unsigned int *certs_len)
 {
 	gnutls_datum_t data;
@@ -418,7 +420,7 @@ bool tlshd_config_get_server_certs(gnutls_pcert_st *certs,
 	int ret;
 
 	pathname = g_key_file_get_string(tlshd_configuration, "authenticate.server",
-					"x509.certificate", NULL);
+					key, NULL);
 	if (!pathname)
 		return false;
 
@@ -446,20 +448,22 @@ bool tlshd_config_get_server_certs(gnutls_pcert_st *certs,
 
 /**
  * tlshd_config_get_server_privkey - Get private key for ServerHello from .conf
+ * @key: IN: the key field name from .conf
  * @privkey: OUT: in-memory private key
  *
  * Return values:
  *   %true: private key retrieved successfully
  *   %false: private key not retrieved
  */
-bool tlshd_config_get_server_privkey(gnutls_privkey_t *privkey)
+bool tlshd_config_get_server_privkey(const gchar *key,
+				     gnutls_privkey_t *privkey)
 {
 	gnutls_datum_t data;
 	gchar *pathname;
 	int ret;
 
 	pathname = g_key_file_get_string(tlshd_configuration, "authenticate.server",
-					"x509.private_key", NULL);
+					key, NULL);
 	if (!pathname)
 		return false;
 
diff --git a/src/tlshd/server.c b/src/tlshd/server.c
index 6b4535d..96b1b88 100644
--- a/src/tlshd/server.c
+++ b/src/tlshd/server.c
@@ -46,13 +46,25 @@ static gnutls_privkey_t tlshd_server_privkey;
 static unsigned int tlshd_server_certs_len = TLSHD_MAX_CERTS;
 static gnutls_pcert_st tlshd_server_certs[TLSHD_MAX_CERTS];
 
+#ifdef HAVE_GNUTLS_MLDSA
+static gnutls_privkey_t tlshd_server_pq_privkey;
+static unsigned int tlshd_server_pq_certs_len = TLSHD_MAX_CERTS;
+static gnutls_pcert_st tlshd_server_pq_certs[TLSHD_MAX_CERTS];
+#endif /* HAVE_GNUTLS_MLDSA */
+
 static bool tlshd_x509_server_get_certs(struct tlshd_handshake_parms *parms)
 {
 	if (parms->x509_cert != TLS_NO_CERT)
 		return tlshd_keyring_get_certs(parms->x509_cert,
 					       tlshd_server_certs,
 					       &tlshd_server_certs_len);
-	return tlshd_config_get_server_certs(tlshd_server_certs,
+#ifdef HAVE_GNUTLS_MLDSA
+	tlshd_config_get_server_certs("x509.pq.certificate",
+				      tlshd_server_pq_certs,
+				      &tlshd_server_pq_certs_len);
+#endif /* HAVE_GNUTLS_MLDSA */
+	return tlshd_config_get_server_certs("x509.certificate",
+					     tlshd_server_certs,
 					     &tlshd_server_certs_len);
 }
 
@@ -62,6 +74,11 @@ static void tlshd_x509_server_put_certs(void)
 
 	for (i = 0; i < tlshd_server_certs_len; i++)
 		gnutls_pcert_deinit(&tlshd_server_certs[i]);
+
+#ifdef HAVE_GNUTLS_MLDSA
+	for (i = 0; i < tlshd_server_pq_certs_len; i++)
+		gnutls_pcert_deinit(&tlshd_server_pq_certs[i]);
+#endif /* HAVE_GNUTLS_MLDSA */
 }
 
 static bool tlshd_x509_server_get_privkey(struct tlshd_handshake_parms *parms)
@@ -69,12 +86,18 @@ static bool tlshd_x509_server_get_privkey(struct tlshd_handshake_parms *parms)
 	if (parms->x509_privkey != TLS_NO_PRIVKEY)
 		return tlshd_keyring_get_privkey(parms->x509_privkey,
 						 &tlshd_server_privkey);
-	return tlshd_config_get_server_privkey(&tlshd_server_privkey);
+#ifdef HAVE_GNUTLS_MLDSA
+	tlshd_config_get_server_privkey("x509.pq.private_key", &tlshd_server_pq_privkey);
+#endif /* HAVE_GNUTLS_MLDSA */
+	return tlshd_config_get_server_privkey("x509.private_key", &tlshd_server_privkey);
 }
 
 static void tlshd_x509_server_put_privkey(void)
 {
 	gnutls_privkey_deinit(tlshd_server_privkey);
+#ifdef HAVE_GNUTLS_MLDSA
+	gnutls_privkey_deinit(tlshd_server_pq_privkey);
+#endif /* HAVE_GNUTLS_MLDSA */
 }
 
 static void tlshd_x509_log_issuers(const gnutls_datum_t *req_ca_rdn, int nreqs)
@@ -120,6 +143,11 @@ tlshd_x509_retrieve_key_cb(gnutls_session_t session,
 			   gnutls_privkey_t *privkey)
 {
 	gnutls_certificate_type_t type;
+#ifdef HAVE_GNUTLS_MLDSA
+	gnutls_sign_algorithm_t client_alg;
+	bool use_pq_cert = false;
+	int i, ret;
+#endif /* HAVE_GNUTLS_MLDSA */
 
 	tlshd_x509_log_issuers(req_ca_rdn, nreqs);
 
@@ -127,9 +155,36 @@ tlshd_x509_retrieve_key_cb(gnutls_session_t session,
 	if (type != GNUTLS_CRT_X509)
 		return -1;
 
+#ifdef HAVE_GNUTLS_MLDSA
+	for (i = 0; ; i++) {
+		ret = gnutls_sign_algorithm_get_requested(session, i, &client_alg);
+		if (ret != GNUTLS_E_SUCCESS)
+			break;
+		if (client_alg == GNUTLS_SIGN_MLDSA44
+				|| client_alg == GNUTLS_SIGN_MLDSA65
+				|| client_alg == GNUTLS_SIGN_MLDSA87) {
+			tlshd_log_debug("%s: Client supports ML-DSA", __func__);
+			use_pq_cert = true;
+			break;
+		}
+	}
+
+	if (use_pq_cert == true && tlshd_server_pq_certs_len > 0) {
+		tlshd_log_debug("%s: Selecting x509.pq.certificate from conf file", __func__);
+		*pcert_length = tlshd_server_pq_certs_len;
+		*pcert = tlshd_server_pq_certs;
+		*privkey = tlshd_server_pq_privkey;
+	} else {
+		tlshd_log_debug("%s: Selecting x509.certificate from conf file", __func__);
+		*pcert_length = tlshd_server_certs_len;
+		*pcert = tlshd_server_certs;
+		*privkey = tlshd_server_privkey;
+	}
+#else
 	*pcert_length = tlshd_server_certs_len;
 	*pcert = tlshd_server_certs;
 	*privkey = tlshd_server_privkey;
+#endif /* HAVE_GNUTLS_MLDSA */
 	return 0;
 }
 
diff --git a/src/tlshd/tlshd.conf b/src/tlshd/tlshd.conf
index 620bd17..5419146 100644
--- a/src/tlshd/tlshd.conf
+++ b/src/tlshd/tlshd.conf
@@ -39,3 +39,5 @@ nl=0
 #x509.crl= <pathname>
 #x509.certificate= <pathname>
 #x509.private_key= <pathname>
+#x509.pq.certificate= <pathname>
+#x509.pq.private_key= <pathname>
diff --git a/src/tlshd/tlshd.conf.man b/src/tlshd/tlshd.conf.man
index 914261e..ed545e4 100644
--- a/src/tlshd/tlshd.conf.man
+++ b/src/tlshd/tlshd.conf.man
@@ -125,6 +125,19 @@ a handshake request when no other certificate is available.
 .B x509.private_key
 This option specifies the pathname of a file containing
 a PEM-encoded private key associated with the above certificate.
+.TP
+.B x509.pq.certificate
+This option specifies the pathname of a file containing
+a PEM-encoded x.509 certificate that is to be presented during
+a handshake request if the peer supports post-quantum cryptography.
+If the peer does not support post-quantum cryptography, the
+certificate configured in the
+.I x509.certificate
+option will be presented instead.
+.TP
+.B x509.pq.private_key
+This option specifies the pathname of a file containing
+a PEM-encoded private key associated with the above certificate.
 .SH SEE ALSO
 .BR tlshd (8)
 .SH AUTHOR
diff --git a/src/tlshd/tlshd.h b/src/tlshd/tlshd.h
index a0dd47e..d9b68ed 100644
--- a/src/tlshd/tlshd.h
+++ b/src/tlshd/tlshd.h
@@ -59,9 +59,11 @@ bool tlshd_config_get_client_certs(gnutls_pcert_st *certs,
 bool tlshd_config_get_client_privkey(gnutls_privkey_t *privkey);
 bool tlshd_config_get_server_truststore(char **bundle);
 bool tlshd_config_get_server_crl(char **result);
-bool tlshd_config_get_server_certs(gnutls_pcert_st *certs,
+bool tlshd_config_get_server_certs(const gchar *key,
+				   gnutls_pcert_st *certs,
 				   unsigned int *certs_len);
-bool tlshd_config_get_server_privkey(gnutls_privkey_t *privkey);
+bool tlshd_config_get_server_privkey(const gchar *key,
+				     gnutls_privkey_t *privkey);
 
 /* handshake.c */
 extern void tlshd_start_tls_handshake(gnutls_session_t session,
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/5] tlshd: Make sure x509.pq.certificate is using a PQ public-key alg
  2025-08-28 22:23 [PATCH 0/5] tlshd: Allow the use of post-quantum cryptography Scott Mayhew
  2025-08-28 22:23 ` [PATCH 1/5] tlshd: Fix priority string to allow PQC Scott Mayhew
  2025-08-28 22:23 ` [PATCH 2/5] tlshd: Server-side dual certificate support Scott Mayhew
@ 2025-08-28 22:23 ` Scott Mayhew
  2025-08-28 22:23 ` [PATCH 4/5] tlshd: Make sure the client supports the PQ pk alg used by the server cert Scott Mayhew
  2025-08-28 22:23 ` [PATCH 5/5] tlshd: Client-side dual certificate support Scott Mayhew
  4 siblings, 0 replies; 11+ messages in thread
From: Scott Mayhew @ 2025-08-28 22:23 UTC (permalink / raw)
  To: chuck.lever; +Cc: kernel-tls-handshake

Ensure that the PQ certificate is using a post-quantum public-key
algorithm (ML-DSA-44, ML-DSA-65, or ML-DSA-87).

Link: https://github.com/oracle/ktls-utils/issues/113
Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
 src/tlshd/config.c       | 53 +++++++++++++++++++++++++++++++++++++++-
 src/tlshd/server.c       |  6 +++--
 src/tlshd/tlshd.conf.man |  2 ++
 src/tlshd/tlshd.h        |  3 ++-
 4 files changed, 60 insertions(+), 4 deletions(-)

diff --git a/src/tlshd/config.c b/src/tlshd/config.c
index 20634dd..6adacc0 100644
--- a/src/tlshd/config.c
+++ b/src/tlshd/config.c
@@ -401,11 +401,47 @@ bool tlshd_config_get_server_crl(char **result)
 	return true;
 }
 
+#ifdef HAVE_GNUTLS_MLDSA
+static bool tlshd_cert_check_pk_alg(gnutls_datum_t *data)
+{
+	gnutls_x509_crt_t cert;
+	gnutls_pk_algorithm_t pk_alg;
+	int ret;
+
+	ret = gnutls_x509_crt_init(&cert);
+	if (ret < 0)
+		return false;
+
+	ret = gnutls_x509_crt_import(cert, data, GNUTLS_X509_FMT_PEM);
+	if (ret < 0) {
+		gnutls_x509_crt_deinit(cert);
+		return false;
+	}
+
+	pk_alg = gnutls_x509_crt_get_pk_algorithm(cert, NULL);
+	tlshd_log_debug("%s: certificate pk algorithm %s", __func__,
+			gnutls_pk_algorithm_get_name(pk_alg));
+	switch (pk_alg) {
+	case GNUTLS_PK_MLDSA44:
+	case GNUTLS_PK_MLDSA65:
+	case GNUTLS_PK_MLDSA87:
+		break;
+	default:
+		gnutls_x509_crt_deinit(cert);
+		return false;
+	}
+
+	gnutls_x509_crt_deinit(cert);
+	return true;
+}
+#endif /* HAVE_GNUTLS_MLDSA */
+
 /**
  * tlshd_config_get_server_certs - Get certs for ServerHello from .conf
  * @key: IN: the key field name from .conf
  * @certs: OUT: in-memory certificates
  * @certs_len: IN: maximum number of certs to get, OUT: number of certs found
+ * @check_pq: IN: verify that the cert is using a PQ public-key alg
  *
  * Return values:
  *   %true: certificate retrieved successfully
@@ -413,8 +449,12 @@ bool tlshd_config_get_server_crl(char **result)
  */
 bool tlshd_config_get_server_certs(const gchar *key,
 				   gnutls_pcert_st *certs,
-				   unsigned int *certs_len)
+				   unsigned int *certs_len,
+				   bool check_pq)
 {
+#ifndef HAVE_GNUTLS_MLSDA
+	(void)check_pq;
+#endif /* HAVE_GNUTLS_MLDSA */
 	gnutls_datum_t data;
 	gchar *pathname;
 	int ret;
@@ -430,6 +470,17 @@ bool tlshd_config_get_server_certs(const gchar *key,
 		return false;
 	}
 
+#ifdef HAVE_GNUTLS_MLDSA
+	if (check_pq && !tlshd_cert_check_pk_alg(&data)) {
+		tlshd_log_debug("%s: %s certificate not using a PQ public-key algorithm",
+				__func__, key);
+		free(data.data);
+		g_free(pathname);
+		*certs_len = 0;
+		return false;
+	}
+#endif /* HAVE_GNUTLS_MLDSA */
+
 	/* Config file supports only PEM-encoded certificates */
 	ret = gnutls_pcert_list_import_x509_raw(certs, certs_len, &data,
 						GNUTLS_X509_FMT_PEM, 0);
diff --git a/src/tlshd/server.c b/src/tlshd/server.c
index 96b1b88..210a09e 100644
--- a/src/tlshd/server.c
+++ b/src/tlshd/server.c
@@ -61,11 +61,13 @@ static bool tlshd_x509_server_get_certs(struct tlshd_handshake_parms *parms)
 #ifdef HAVE_GNUTLS_MLDSA
 	tlshd_config_get_server_certs("x509.pq.certificate",
 				      tlshd_server_pq_certs,
-				      &tlshd_server_pq_certs_len);
+				      &tlshd_server_pq_certs_len,
+				      true);
 #endif /* HAVE_GNUTLS_MLDSA */
 	return tlshd_config_get_server_certs("x509.certificate",
 					     tlshd_server_certs,
-					     &tlshd_server_certs_len);
+					     &tlshd_server_certs_len,
+					     false);
 }
 
 static void tlshd_x509_server_put_certs(void)
diff --git a/src/tlshd/tlshd.conf.man b/src/tlshd/tlshd.conf.man
index ed545e4..575d88b 100644
--- a/src/tlshd/tlshd.conf.man
+++ b/src/tlshd/tlshd.conf.man
@@ -130,6 +130,8 @@ a PEM-encoded private key associated with the above certificate.
 This option specifies the pathname of a file containing
 a PEM-encoded x.509 certificate that is to be presented during
 a handshake request if the peer supports post-quantum cryptography.
+This certificate must be using a post-quantum public-key algorithm
+(ML-DSA-44, ML-DSA-65, or ML-DSA-87).
 If the peer does not support post-quantum cryptography, the
 certificate configured in the
 .I x509.certificate
diff --git a/src/tlshd/tlshd.h b/src/tlshd/tlshd.h
index d9b68ed..6bd55c7 100644
--- a/src/tlshd/tlshd.h
+++ b/src/tlshd/tlshd.h
@@ -61,7 +61,8 @@ bool tlshd_config_get_server_truststore(char **bundle);
 bool tlshd_config_get_server_crl(char **result);
 bool tlshd_config_get_server_certs(const gchar *key,
 				   gnutls_pcert_st *certs,
-				   unsigned int *certs_len);
+				   unsigned int *certs_len,
+				   bool check_pq);
 bool tlshd_config_get_server_privkey(const gchar *key,
 				     gnutls_privkey_t *privkey);
 
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 4/5] tlshd: Make sure the client supports the PQ pk alg used by the server cert
  2025-08-28 22:23 [PATCH 0/5] tlshd: Allow the use of post-quantum cryptography Scott Mayhew
                   ` (2 preceding siblings ...)
  2025-08-28 22:23 ` [PATCH 3/5] tlshd: Make sure x509.pq.certificate is using a PQ public-key alg Scott Mayhew
@ 2025-08-28 22:23 ` Scott Mayhew
  2025-08-28 22:23 ` [PATCH 5/5] tlshd: Client-side dual certificate support Scott Mayhew
  4 siblings, 0 replies; 11+ messages in thread
From: Scott Mayhew @ 2025-08-28 22:23 UTC (permalink / raw)
  To: chuck.lever; +Cc: kernel-tls-handshake

Store the public-key algorithm used by the server cert so we can later
compare it to the list of signing algorithms supported by the client in
the cert callback.

Link: https://github.com/oracle/ktls-utils/issues/113
Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
 src/tlshd/config.c | 12 +++++++-----
 src/tlshd/server.c | 49 ++++++++++++++++++++++++++++++++++------------
 src/tlshd/tlshd.h  |  2 +-
 3 files changed, 44 insertions(+), 19 deletions(-)

diff --git a/src/tlshd/config.c b/src/tlshd/config.c
index 6adacc0..735d24a 100644
--- a/src/tlshd/config.c
+++ b/src/tlshd/config.c
@@ -402,7 +402,8 @@ bool tlshd_config_get_server_crl(char **result)
 }
 
 #ifdef HAVE_GNUTLS_MLDSA
-static bool tlshd_cert_check_pk_alg(gnutls_datum_t *data)
+static bool tlshd_cert_check_pk_alg(gnutls_datum_t *data,
+				    gnutls_pk_algorithm_t *pkalg)
 {
 	gnutls_x509_crt_t cert;
 	gnutls_pk_algorithm_t pk_alg;
@@ -425,6 +426,7 @@ static bool tlshd_cert_check_pk_alg(gnutls_datum_t *data)
 	case GNUTLS_PK_MLDSA44:
 	case GNUTLS_PK_MLDSA65:
 	case GNUTLS_PK_MLDSA87:
+		*pkalg = pk_alg;
 		break;
 	default:
 		gnutls_x509_crt_deinit(cert);
@@ -441,7 +443,7 @@ static bool tlshd_cert_check_pk_alg(gnutls_datum_t *data)
  * @key: IN: the key field name from .conf
  * @certs: OUT: in-memory certificates
  * @certs_len: IN: maximum number of certs to get, OUT: number of certs found
- * @check_pq: IN: verify that the cert is using a PQ public-key alg
+ * @pkgalg: OUT: the PQ public-key alg that was used in the cert
  *
  * Return values:
  *   %true: certificate retrieved successfully
@@ -450,10 +452,10 @@ static bool tlshd_cert_check_pk_alg(gnutls_datum_t *data)
 bool tlshd_config_get_server_certs(const gchar *key,
 				   gnutls_pcert_st *certs,
 				   unsigned int *certs_len,
-				   bool check_pq)
+				   gnutls_pk_algorithm_t *pkalg)
 {
 #ifndef HAVE_GNUTLS_MLSDA
-	(void)check_pq;
+	(void)pkalg;
 #endif /* HAVE_GNUTLS_MLDSA */
 	gnutls_datum_t data;
 	gchar *pathname;
@@ -471,7 +473,7 @@ bool tlshd_config_get_server_certs(const gchar *key,
 	}
 
 #ifdef HAVE_GNUTLS_MLDSA
-	if (check_pq && !tlshd_cert_check_pk_alg(&data)) {
+	if (pkalg && !tlshd_cert_check_pk_alg(&data, pkalg)) {
 		tlshd_log_debug("%s: %s certificate not using a PQ public-key algorithm",
 				__func__, key);
 		free(data.data);
diff --git a/src/tlshd/server.c b/src/tlshd/server.c
index 210a09e..7a0ce24 100644
--- a/src/tlshd/server.c
+++ b/src/tlshd/server.c
@@ -50,6 +50,7 @@ static gnutls_pcert_st tlshd_server_certs[TLSHD_MAX_CERTS];
 static gnutls_privkey_t tlshd_server_pq_privkey;
 static unsigned int tlshd_server_pq_certs_len = TLSHD_MAX_CERTS;
 static gnutls_pcert_st tlshd_server_pq_certs[TLSHD_MAX_CERTS];
+static gnutls_pk_algorithm_t tlshd_server_pq_pkalg = GNUTLS_PK_UNKNOWN;
 #endif /* HAVE_GNUTLS_MLDSA */
 
 static bool tlshd_x509_server_get_certs(struct tlshd_handshake_parms *parms)
@@ -62,12 +63,12 @@ static bool tlshd_x509_server_get_certs(struct tlshd_handshake_parms *parms)
 	tlshd_config_get_server_certs("x509.pq.certificate",
 				      tlshd_server_pq_certs,
 				      &tlshd_server_pq_certs_len,
-				      true);
+				      &tlshd_server_pq_pkalg);
 #endif /* HAVE_GNUTLS_MLDSA */
 	return tlshd_config_get_server_certs("x509.certificate",
 					     tlshd_server_certs,
 					     &tlshd_server_certs_len,
-					     false);
+					     NULL);
 }
 
 static void tlshd_x509_server_put_certs(void)
@@ -158,20 +159,42 @@ tlshd_x509_retrieve_key_cb(gnutls_session_t session,
 		return -1;
 
 #ifdef HAVE_GNUTLS_MLDSA
-	for (i = 0; ; i++) {
-		ret = gnutls_sign_algorithm_get_requested(session, i, &client_alg);
-		if (ret != GNUTLS_E_SUCCESS)
-			break;
-		if (client_alg == GNUTLS_SIGN_MLDSA44
-				|| client_alg == GNUTLS_SIGN_MLDSA65
-				|| client_alg == GNUTLS_SIGN_MLDSA87) {
-			tlshd_log_debug("%s: Client supports ML-DSA", __func__);
-			use_pq_cert = true;
-			break;
+	/*
+ 	 * NB: Unfortunately when the callback function is invoked server-side,
+ 	 * pk_algos is NULL and pk_algos_length is 0. So we check the signature
+ 	 * algorithms the client supports and try to match one of them to the
+ 	 * public-key algorithm used by the server cert.
+ 	 */
+	if (tlshd_server_pq_pkalg != GNUTLS_PK_UNKNOWN) {
+		for (i = 0; ; i++) {
+			ret = gnutls_sign_algorithm_get_requested(session, i, &client_alg);
+			if (ret != GNUTLS_E_SUCCESS)
+				break;
+			switch (client_alg) {
+			case GNUTLS_SIGN_MLDSA44:
+				if (tlshd_server_pq_pkalg == GNUTLS_PK_MLDSA44)
+					use_pq_cert = true;
+				break;
+			case GNUTLS_SIGN_MLDSA65:
+				if (tlshd_server_pq_pkalg == GNUTLS_PK_MLDSA65)
+					use_pq_cert = true;
+				break;
+			case GNUTLS_SIGN_MLDSA87:
+				if (tlshd_server_pq_pkalg == GNUTLS_PK_MLDSA87)
+					use_pq_cert = true;
+				break;
+			default:
+				break;
+			}
+			if (use_pq_cert == true) {
+				tlshd_log_debug("%s: Client supports %s", __func__,
+						gnutls_sign_get_name(client_alg));
+				break;
+			}
 		}
 	}
 
-	if (use_pq_cert == true && tlshd_server_pq_certs_len > 0) {
+	if (use_pq_cert == true) {
 		tlshd_log_debug("%s: Selecting x509.pq.certificate from conf file", __func__);
 		*pcert_length = tlshd_server_pq_certs_len;
 		*pcert = tlshd_server_pq_certs;
diff --git a/src/tlshd/tlshd.h b/src/tlshd/tlshd.h
index 6bd55c7..ca84d8f 100644
--- a/src/tlshd/tlshd.h
+++ b/src/tlshd/tlshd.h
@@ -62,7 +62,7 @@ bool tlshd_config_get_server_crl(char **result);
 bool tlshd_config_get_server_certs(const gchar *key,
 				   gnutls_pcert_st *certs,
 				   unsigned int *certs_len,
-				   bool check_pq);
+				   gnutls_pk_algorithm_t *pkalg);
 bool tlshd_config_get_server_privkey(const gchar *key,
 				     gnutls_privkey_t *privkey);
 
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 5/5] tlshd: Client-side dual certificate support
  2025-08-28 22:23 [PATCH 0/5] tlshd: Allow the use of post-quantum cryptography Scott Mayhew
                   ` (3 preceding siblings ...)
  2025-08-28 22:23 ` [PATCH 4/5] tlshd: Make sure the client supports the PQ pk alg used by the server cert Scott Mayhew
@ 2025-08-28 22:23 ` Scott Mayhew
  4 siblings, 0 replies; 11+ messages in thread
From: Scott Mayhew @ 2025-08-28 22:23 UTC (permalink / raw)
  To: chuck.lever; +Cc: kernel-tls-handshake

Add two new config options "x509.pq.certificate" and
"x509.pq.private_key", this time to the "[authenticate.client]" stanza
of tlshd.conf.  This is for client-side handling of the server's
certificate request when the client is mounting with "xprtsec=mtls".

This commit also makes sure the client-side x509.pq.certificate is using
a post-quantum public-key algorithm, and we make sure that the server
supports that algorithm before returning that cert in the cert callback
(unlike the server-side cert callback, the pk_algos list is populated,
so this check is more straightforward than on the server-side).

Link: https://github.com/oracle/ktls-utils/issues/113
Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
 src/tlshd/client.c   |  66 +++++++++++++++++++++++++--
 src/tlshd/config.c   | 104 ++++++++++++++++++++++++++-----------------
 src/tlshd/tlshd.conf |   2 +
 src/tlshd/tlshd.h    |   9 ++--
 4 files changed, 132 insertions(+), 49 deletions(-)

diff --git a/src/tlshd/client.c b/src/tlshd/client.c
index 72cdd60..d74ea69 100644
--- a/src/tlshd/client.c
+++ b/src/tlshd/client.c
@@ -138,12 +138,24 @@ static gnutls_privkey_t tlshd_privkey;
 static unsigned int tlshd_certs_len = TLSHD_MAX_CERTS;
 static gnutls_pcert_st tlshd_certs[TLSHD_MAX_CERTS];
 
+#ifdef HAVE_GNUTLS_MLDSA
+static gnutls_privkey_t tlshd_pq_privkey;
+static unsigned int tlshd_pq_certs_len = TLSHD_MAX_CERTS;
+static gnutls_pcert_st tlshd_pq_certs[TLSHD_MAX_CERTS];
+static gnutls_pk_algorithm_t tlshd_pq_pkalg = GNUTLS_PK_UNKNOWN;
+#endif /* HAVE_GNUTLS_MLDSA */
+
 static bool tlshd_x509_client_get_certs(struct tlshd_handshake_parms *parms)
 {
 	if (parms->x509_cert != TLS_NO_CERT)
 		return tlshd_keyring_get_certs(parms->x509_cert, tlshd_certs,
 					       &tlshd_certs_len);
-	return tlshd_config_get_client_certs(tlshd_certs, &tlshd_certs_len);
+#ifdef HAVE_GNUTLS_MLDSA
+	tlshd_config_get_client_certs("x509.pq.certificate", tlshd_pq_certs,
+				      &tlshd_pq_certs_len, &tlshd_pq_pkalg);
+#endif /* HAVE_GNUTLS_MLDSA */
+	return tlshd_config_get_client_certs("x509.certificate", tlshd_certs,
+					     &tlshd_certs_len, NULL);
 }
 
 static void tlshd_x509_client_put_certs(void)
@@ -152,6 +164,11 @@ static void tlshd_x509_client_put_certs(void)
 
 	for (i = 0; i < tlshd_certs_len; i++)
 		gnutls_pcert_deinit(&tlshd_certs[i]);
+
+#ifdef HAVE_GNUTLS_MLDSA
+	for (i = 0; i < tlshd_pq_certs_len; i++)
+		gnutls_pcert_deinit(&tlshd_pq_certs[i]);
+#endif /* HAVE_GNUTLS_MLDSA */
 }
 
 static bool tlshd_x509_client_get_privkey(struct tlshd_handshake_parms *parms)
@@ -159,12 +176,18 @@ static bool tlshd_x509_client_get_privkey(struct tlshd_handshake_parms *parms)
 	if (parms->x509_privkey != TLS_NO_PRIVKEY)
 		return tlshd_keyring_get_privkey(parms->x509_privkey,
 						 &tlshd_privkey);
-	return tlshd_config_get_client_privkey(&tlshd_privkey);
+#ifdef HAVE_GNUTLS_MLDSA
+	tlshd_config_get_client_privkey("x509.pq.private_key", &tlshd_pq_privkey);
+#endif /* HAVE_GNUTLS_MLDSA */
+	return tlshd_config_get_client_privkey("x509.private_key", &tlshd_privkey);
 }
 
 static void tlshd_x509_client_put_privkey(void)
 {
 	gnutls_privkey_deinit(tlshd_privkey);
+#ifdef HAVE_GNUTLS_MLDSA
+	gnutls_privkey_deinit(tlshd_pq_privkey);
+#endif /* HAVE_GNUTLS_MLDSA */
 }
 
 static void tlshd_x509_log_issuers(const gnutls_datum_t *req_ca_rdn, int nreqs)
@@ -203,13 +226,21 @@ static void tlshd_x509_log_issuers(const gnutls_datum_t *req_ca_rdn, int nreqs)
 static int
 tlshd_x509_retrieve_key_cb(gnutls_session_t session,
 			   const gnutls_datum_t *req_ca_rdn, int nreqs,
-			   __attribute__ ((unused)) const gnutls_pk_algorithm_t *pk_algos,
-			   __attribute__ ((unused)) int pk_algos_length,
+			   const gnutls_pk_algorithm_t *pk_algos,
+			   int pk_algos_length,
 			   gnutls_pcert_st **pcert,
 			   unsigned int *pcert_length,
 			   gnutls_privkey_t *privkey)
 {
+#ifndef HAVE_GNUTLS_MLDSA
+	(void)pk_algos;
+	(void)pk_algos_length;
+#endif /* HAVE_GNUTLS_MLDSA */
 	gnutls_certificate_type_t type;
+#ifdef HAVE_GNUTLS_MLDSA
+	bool use_pq_cert = false;
+	int i;
+#endif /* HAVE_GNUTLS_MLDSA */
 
 	tlshd_x509_log_issuers(req_ca_rdn, nreqs);
 
@@ -217,9 +248,36 @@ tlshd_x509_retrieve_key_cb(gnutls_session_t session,
 	if (type != GNUTLS_CRT_X509)
 		return -1;
 
+#ifdef HAVE_GNUTLS_MLDSA
+	if (tlshd_pq_pkalg != GNUTLS_PK_UNKNOWN) {
+		for (i = 0; i < pk_algos_length; i++) {
+			if (pk_algos[i] == tlshd_pq_pkalg) {
+				use_pq_cert = true;
+				break;
+			}
+		}
+		if (use_pq_cert == true) {
+			tlshd_log_debug("%s: Server supports %s", __func__,
+					gnutls_pk_algorithm_get_name(pk_algos[i]));
+		}
+	}
+
+	if (use_pq_cert == true) {
+		tlshd_log_debug("%s: Selecting x509.pq.certificate from conf file", __func__);
+		*pcert_length = tlshd_pq_certs_len;
+		*pcert = tlshd_pq_certs;
+		*privkey = tlshd_pq_privkey;
+	} else {
+		tlshd_log_debug("%s: Selecting x509.certificate from conf file", __func__);
+		*pcert_length = tlshd_certs_len;
+		*pcert = tlshd_certs;
+		*privkey = tlshd_privkey;
+	}
+#else
 	*pcert_length = tlshd_certs_len;
 	*pcert = tlshd_certs;
 	*privkey = tlshd_privkey;
+#endif /* HAVE_GNUTLS_MLDSA */
 	return 0;
 }
 
diff --git a/src/tlshd/config.c b/src/tlshd/config.c
index 735d24a..7af345b 100644
--- a/src/tlshd/config.c
+++ b/src/tlshd/config.c
@@ -248,24 +248,68 @@ bool tlshd_config_get_client_crl(char **result)
 	return true;
 }
 
+#ifdef HAVE_GNUTLS_MLDSA
+static bool tlshd_cert_check_pk_alg(gnutls_datum_t *data,
+				    gnutls_pk_algorithm_t *pkalg)
+{
+	gnutls_x509_crt_t cert;
+	gnutls_pk_algorithm_t pk_alg;
+	int ret;
+
+	ret = gnutls_x509_crt_init(&cert);
+	if (ret < 0)
+		return false;
+
+	ret = gnutls_x509_crt_import(cert, data, GNUTLS_X509_FMT_PEM);
+	if (ret < 0) {
+		gnutls_x509_crt_deinit(cert);
+		return false;
+	}
+
+	pk_alg = gnutls_x509_crt_get_pk_algorithm(cert, NULL);
+	tlshd_log_debug("%s: certificate pk algorithm %s", __func__,
+			gnutls_pk_algorithm_get_name(pk_alg));
+	switch (pk_alg) {
+	case GNUTLS_PK_MLDSA44:
+	case GNUTLS_PK_MLDSA65:
+	case GNUTLS_PK_MLDSA87:
+		*pkalg = pk_alg;
+		break;
+	default:
+		gnutls_x509_crt_deinit(cert);
+		return false;
+	}
+
+	gnutls_x509_crt_deinit(cert);
+	return true;
+}
+#endif /* HAVE_GNUTLS_MLDSA */
+
 /**
  * tlshd_config_get_client_certs - Get certs for ClientHello from .conf
+ * @key: IN: the key field name from .conf
  * @certs: OUT: in-memory certificates
  * @certs_len: IN: maximum number of certs to get, OUT: number of certs found
+ * @pkgalg: OUT: the PQ public-key alg that was used in the cert
  *
  * Return values:
  *   %true: certificate retrieved successfully
  *   %false: certificate not retrieved
  */
-bool tlshd_config_get_client_certs(gnutls_pcert_st *certs,
-				   unsigned int *certs_len)
+bool tlshd_config_get_client_certs(const gchar *key,
+				   gnutls_pcert_st *certs,
+				   unsigned int *certs_len,
+				   gnutls_pk_algorithm_t *pkalg)
 {
+#ifndef HAVE_GNUTLS_MLSDA
+	(void)pkalg;
+#endif /* HAVE_GNUTLS_MLDSA */
 	gnutls_datum_t data;
 	gchar *pathname;
 	int ret;
 
 	pathname = g_key_file_get_string(tlshd_configuration, "authenticate.client",
-					"x509.certificate", NULL);
+					key, NULL);
 	if (!pathname)
 		return false;
 
@@ -275,6 +319,17 @@ bool tlshd_config_get_client_certs(gnutls_pcert_st *certs,
 		return false;
 	}
 
+#ifdef HAVE_GNUTLS_MLDSA
+	if (pkalg && !tlshd_cert_check_pk_alg(&data, pkalg)) {
+		tlshd_log_debug("%s: %s certificate not using a PQ public-key algorithm",
+				__func__, key);
+		free(data.data);
+		g_free(pathname);
+		*certs_len = 0;
+		return false;
+	}
+#endif /* HAVE_GNUTLS_MLDSA */
+
 	/* Config file supports only PEM-encoded certificates */
 	ret = gnutls_pcert_list_import_x509_raw(certs, certs_len, &data,
 						GNUTLS_X509_FMT_PEM, 0);
@@ -293,20 +348,22 @@ bool tlshd_config_get_client_certs(gnutls_pcert_st *certs,
 
 /**
  * tlshd_config_get_client_privkey - Get private key for ClientHello from .conf
+ * @key: IN: the key field name from .conf
  * @privkey: OUT: in-memory private key
  *
  * Return values:
  *   %true: private key retrieved successfully
  *   %false: private key not retrieved
  */
-bool tlshd_config_get_client_privkey(gnutls_privkey_t *privkey)
+bool tlshd_config_get_client_privkey(const gchar *key,
+				     gnutls_privkey_t *privkey)
 {
 	gnutls_datum_t data;
 	gchar *pathname;
 	int ret;
 
 	pathname = g_key_file_get_string(tlshd_configuration, "authenticate.client",
-					"x509.private_key", NULL);
+					key, NULL);
 	if (!pathname)
 		return false;
 
@@ -401,43 +458,6 @@ bool tlshd_config_get_server_crl(char **result)
 	return true;
 }
 
-#ifdef HAVE_GNUTLS_MLDSA
-static bool tlshd_cert_check_pk_alg(gnutls_datum_t *data,
-				    gnutls_pk_algorithm_t *pkalg)
-{
-	gnutls_x509_crt_t cert;
-	gnutls_pk_algorithm_t pk_alg;
-	int ret;
-
-	ret = gnutls_x509_crt_init(&cert);
-	if (ret < 0)
-		return false;
-
-	ret = gnutls_x509_crt_import(cert, data, GNUTLS_X509_FMT_PEM);
-	if (ret < 0) {
-		gnutls_x509_crt_deinit(cert);
-		return false;
-	}
-
-	pk_alg = gnutls_x509_crt_get_pk_algorithm(cert, NULL);
-	tlshd_log_debug("%s: certificate pk algorithm %s", __func__,
-			gnutls_pk_algorithm_get_name(pk_alg));
-	switch (pk_alg) {
-	case GNUTLS_PK_MLDSA44:
-	case GNUTLS_PK_MLDSA65:
-	case GNUTLS_PK_MLDSA87:
-		*pkalg = pk_alg;
-		break;
-	default:
-		gnutls_x509_crt_deinit(cert);
-		return false;
-	}
-
-	gnutls_x509_crt_deinit(cert);
-	return true;
-}
-#endif /* HAVE_GNUTLS_MLDSA */
-
 /**
  * tlshd_config_get_server_certs - Get certs for ServerHello from .conf
  * @key: IN: the key field name from .conf
diff --git a/src/tlshd/tlshd.conf b/src/tlshd/tlshd.conf
index 5419146..1d4220e 100644
--- a/src/tlshd/tlshd.conf
+++ b/src/tlshd/tlshd.conf
@@ -33,6 +33,8 @@ nl=0
 #x509.crl= <pathname>
 #x509.certificate= <pathname>
 #x509.private_key= <pathname>
+#x509.pq.certificate= <pathname>
+#x509.pq.private_key= <pathname>
 
 [authenticate.server]
 #x509.truststore= <pathname>
diff --git a/src/tlshd/tlshd.h b/src/tlshd/tlshd.h
index ca84d8f..a95ef70 100644
--- a/src/tlshd/tlshd.h
+++ b/src/tlshd/tlshd.h
@@ -54,9 +54,12 @@ bool tlshd_config_init(const gchar *pathname);
 void tlshd_config_shutdown(void);
 bool tlshd_config_get_client_truststore(char **bundle);
 bool tlshd_config_get_client_crl(char **result);
-bool tlshd_config_get_client_certs(gnutls_pcert_st *certs,
-				   unsigned int *certs_len);
-bool tlshd_config_get_client_privkey(gnutls_privkey_t *privkey);
+bool tlshd_config_get_client_certs(const gchar *key,
+				   gnutls_pcert_st *certs,
+				   unsigned int *certs_len,
+				   gnutls_pk_algorithm_t *pkalg);
+bool tlshd_config_get_client_privkey(const gchar *key,
+				     gnutls_privkey_t *privkey);
 bool tlshd_config_get_server_truststore(char **bundle);
 bool tlshd_config_get_server_crl(char **result);
 bool tlshd_config_get_server_certs(const gchar *key,
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/5] tlshd: Fix priority string to allow PQC
  2025-08-28 22:23 ` [PATCH 1/5] tlshd: Fix priority string to allow PQC Scott Mayhew
@ 2025-08-29 16:47   ` Chuck Lever
  0 siblings, 0 replies; 11+ messages in thread
From: Chuck Lever @ 2025-08-29 16:47 UTC (permalink / raw)
  To: Scott Mayhew, Hannes Reinecke; +Cc: kernel-tls-handshake

On 8/28/25 6:23 PM, Scott Mayhew wrote:
> Specifying either of the SECURE256 or SECURE128 keywords in the priority
> string results in the ML-DSA algorithms being disabled because the
> post-quantum algorithms do not map nicely to the security
> classifications based on "bits of security" used for traditional
> algorithms [1].
> 
> Use @SYSTEM instead, which will allow PQC on systems with newer versions
> of GnuTLS.  It will also allow users to disable PQC via a policy module
> (on systems with the crypto-policies package).
> 
> [1] https://csrc.nist.gov/CSRC/media/Projects/Post-Quantum-Cryptography/documents/call-for-proposals-final-dec-2016.pdf#page=15
> 
> Link: https://github.com/oracle/ktls-utils/issues/113
> Signed-off-by: Scott Mayhew <smayhew@redhat.com>
> ---
>  src/tlshd/ktls.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/src/tlshd/ktls.c b/src/tlshd/ktls.c
> index 40a26a4..866a023 100644
> --- a/src/tlshd/ktls.c
> +++ b/src/tlshd/ktls.c
> @@ -357,7 +357,7 @@ static int tlshd_gnutls_priority_init_list(const unsigned int *ciphers,
>  	const char *errpos;
>  	int ret, i;
>  
> -	pstring = strdup("SECURE256:+SECURE128:-COMP-ALL");
> +	pstring = strdup("@SYSTEM:-COMP-ALL");
>  	if (!pstring)
>  		return -ENOMEM;
>  

If I can get a R-b from Hannes, this can get merged right now.


-- 
Chuck Lever

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/5] tlshd: Server-side dual certificate support
  2025-08-28 22:23 ` [PATCH 2/5] tlshd: Server-side dual certificate support Scott Mayhew
@ 2025-08-29 16:59   ` Chuck Lever
  2025-09-03 13:28     ` Scott Mayhew
  0 siblings, 1 reply; 11+ messages in thread
From: Chuck Lever @ 2025-08-29 16:59 UTC (permalink / raw)
  To: Scott Mayhew; +Cc: kernel-tls-handshake

On 8/28/25 6:23 PM, Scott Mayhew wrote:
> Add two new config options, "x509.pq.certificate" and
> "x509.pq.private_key" to configure tlshd to use an ML-DSA certificate.
> If the cert callback determines that the client supports ML-DSA, it will
> select this certificate.  Otherwise, it will fall back to the
> traditional certficate (i.e. the certificate configured via
> "x509.certificate" and "x509.private_key").
> 
> Link: https://github.com/oracle/ktls-utils/issues/113
> Signed-off-by: Scott Mayhew <smayhew@redhat.com>
> ---
>  configure.ac             | 12 ++++++++
>  src/tlshd/config.c       | 12 +++++---
>  src/tlshd/server.c       | 59 ++++++++++++++++++++++++++++++++++++++--
>  src/tlshd/tlshd.conf     |  2 ++
>  src/tlshd/tlshd.conf.man | 13 +++++++++
>  src/tlshd/tlshd.h        |  6 ++--
>  6 files changed, 96 insertions(+), 8 deletions(-)
> 
> diff --git a/configure.ac b/configure.ac
> index a6d9d09..0dd23f2 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -79,6 +79,18 @@ AC_CHECK_LIB([gnutls], [gnutls_get_system_config_file],
>  AC_CHECK_LIB([gnutls], [gnutls_psk_allocate_client_credentials2],
>               [AC_DEFINE([HAVE_GNUTLS_PSK_ALLOCATE_CREDENTIALS2], [1],
>                          [Define to 1 if you have the gnutls_psk_allocate_client_credentials2 function.])])
> +
> +AC_MSG_CHECKING(for ML-DSA support in gnutls)
> +AC_COMPILE_IFELSE(
> +	[AC_LANG_PROGRAM([[ #include <gnutls/gnutls.h> ]],
> +		[[ (void) GNUTLS_SIGN_MLDSA65; ]])],
> +	[ have_mldsa=yes ],
> +	[ have_mldsa=no ])
> +AC_MSG_RESULT([$have_mldsa])
> +if test "x$have_mldsa" = xyes ; then
> +	AC_DEFINE([HAVE_GNUTLS_MLDSA], [1], [Define to 1 if gnutls supports ML-DSA])
> +fi
> +
>  AC_SUBST([AM_CPPFLAGS])
>  
>  AC_CONFIG_FILES([Makefile src/Makefile src/tlshd/Makefile systemd/Makefile])

Nice.


> diff --git a/src/tlshd/config.c b/src/tlshd/config.c
> index 4c54d37..20634dd 100644
> --- a/src/tlshd/config.c
> +++ b/src/tlshd/config.c
> @@ -403,6 +403,7 @@ bool tlshd_config_get_server_crl(char **result)
>  
>  /**
>   * tlshd_config_get_server_certs - Get certs for ServerHello from .conf
> + * @key: IN: the key field name from .conf

ETOOMANYTHINGSCALLEDKEY :-)

Can you find a less overloaded name for the new function parameter, here
and below?

But see below... perhaps the additional parameter isn't needed if all
the configured certificates and private keys can be retrieved using the
same functions.


>   * @certs: OUT: in-memory certificates
>   * @certs_len: IN: maximum number of certs to get, OUT: number of certs found
>   *
> @@ -410,7 +411,8 @@ bool tlshd_config_get_server_crl(char **result)
>   *   %true: certificate retrieved successfully
>   *   %false: certificate not retrieved
>   */
> -bool tlshd_config_get_server_certs(gnutls_pcert_st *certs,
> +bool tlshd_config_get_server_certs(const gchar *key,
> +				   gnutls_pcert_st *certs,
>  				   unsigned int *certs_len)
>  {
>  	gnutls_datum_t data;
> @@ -418,7 +420,7 @@ bool tlshd_config_get_server_certs(gnutls_pcert_st *certs,
>  	int ret;
>  
>  	pathname = g_key_file_get_string(tlshd_configuration, "authenticate.server",
> -					"x509.certificate", NULL);
> +					key, NULL);
>  	if (!pathname)
>  		return false;
>  
> @@ -446,20 +448,22 @@ bool tlshd_config_get_server_certs(gnutls_pcert_st *certs,
>  
>  /**
>   * tlshd_config_get_server_privkey - Get private key for ServerHello from .conf
> + * @key: IN: the key field name from .conf
>   * @privkey: OUT: in-memory private key
>   *
>   * Return values:
>   *   %true: private key retrieved successfully
>   *   %false: private key not retrieved
>   */
> -bool tlshd_config_get_server_privkey(gnutls_privkey_t *privkey)
> +bool tlshd_config_get_server_privkey(const gchar *key,
> +				     gnutls_privkey_t *privkey)
>  {
>  	gnutls_datum_t data;
>  	gchar *pathname;
>  	int ret;
>  
>  	pathname = g_key_file_get_string(tlshd_configuration, "authenticate.server",
> -					"x509.private_key", NULL);
> +					key, NULL);
>  	if (!pathname)
>  		return false;
>  
> diff --git a/src/tlshd/server.c b/src/tlshd/server.c
> index 6b4535d..96b1b88 100644
> --- a/src/tlshd/server.c
> +++ b/src/tlshd/server.c
> @@ -46,13 +46,25 @@ static gnutls_privkey_t tlshd_server_privkey;
>  static unsigned int tlshd_server_certs_len = TLSHD_MAX_CERTS;
>  static gnutls_pcert_st tlshd_server_certs[TLSHD_MAX_CERTS];
>  
> +#ifdef HAVE_GNUTLS_MLDSA
> +static gnutls_privkey_t tlshd_server_pq_privkey;
> +static unsigned int tlshd_server_pq_certs_len = TLSHD_MAX_CERTS;
> +static gnutls_pcert_st tlshd_server_pq_certs[TLSHD_MAX_CERTS];
> +#endif /* HAVE_GNUTLS_MLDSA */
> +

Two architectural thoughts when seeing this:

1. Generally, I'd rather see fewer "#ifdef HAVE_GNUTLS_MLDSA" throughout
   and just leave things enabled all the time where it makes sense. That
   makes for less clutter and better test coverage.

2. Does it make sense for tlshd_config_get_server_certs to retrieve both
   types of certificates in the same array? Or, more generally speaking,
   where it's sensible, try not to duplicate the logic, but combine it.

Similar comments in the client parts of the series. Overall the series
looks like a reasonable direction.


>  static bool tlshd_x509_server_get_certs(struct tlshd_handshake_parms *parms)
>  {
>  	if (parms->x509_cert != TLS_NO_CERT)
>  		return tlshd_keyring_get_certs(parms->x509_cert,
>  					       tlshd_server_certs,
>  					       &tlshd_server_certs_len);
> -	return tlshd_config_get_server_certs(tlshd_server_certs,
> +#ifdef HAVE_GNUTLS_MLDSA
> +	tlshd_config_get_server_certs("x509.pq.certificate",
> +				      tlshd_server_pq_certs,
> +				      &tlshd_server_pq_certs_len);
> +#endif /* HAVE_GNUTLS_MLDSA */
> +	return tlshd_config_get_server_certs("x509.certificate",
> +					     tlshd_server_certs,
>  					     &tlshd_server_certs_len);
>  }
>  
> @@ -62,6 +74,11 @@ static void tlshd_x509_server_put_certs(void)
>  
>  	for (i = 0; i < tlshd_server_certs_len; i++)
>  		gnutls_pcert_deinit(&tlshd_server_certs[i]);
> +
> +#ifdef HAVE_GNUTLS_MLDSA
> +	for (i = 0; i < tlshd_server_pq_certs_len; i++)
> +		gnutls_pcert_deinit(&tlshd_server_pq_certs[i]);
> +#endif /* HAVE_GNUTLS_MLDSA */
>  }
>  
>  static bool tlshd_x509_server_get_privkey(struct tlshd_handshake_parms *parms)
> @@ -69,12 +86,18 @@ static bool tlshd_x509_server_get_privkey(struct tlshd_handshake_parms *parms)
>  	if (parms->x509_privkey != TLS_NO_PRIVKEY)
>  		return tlshd_keyring_get_privkey(parms->x509_privkey,
>  						 &tlshd_server_privkey);
> -	return tlshd_config_get_server_privkey(&tlshd_server_privkey);
> +#ifdef HAVE_GNUTLS_MLDSA
> +	tlshd_config_get_server_privkey("x509.pq.private_key", &tlshd_server_pq_privkey);
> +#endif /* HAVE_GNUTLS_MLDSA */
> +	return tlshd_config_get_server_privkey("x509.private_key", &tlshd_server_privkey);
>  }
>  
>  static void tlshd_x509_server_put_privkey(void)
>  {
>  	gnutls_privkey_deinit(tlshd_server_privkey);
> +#ifdef HAVE_GNUTLS_MLDSA
> +	gnutls_privkey_deinit(tlshd_server_pq_privkey);
> +#endif /* HAVE_GNUTLS_MLDSA */
>  }
>  
>  static void tlshd_x509_log_issuers(const gnutls_datum_t *req_ca_rdn, int nreqs)
> @@ -120,6 +143,11 @@ tlshd_x509_retrieve_key_cb(gnutls_session_t session,
>  			   gnutls_privkey_t *privkey)
>  {
>  	gnutls_certificate_type_t type;
> +#ifdef HAVE_GNUTLS_MLDSA
> +	gnutls_sign_algorithm_t client_alg;
> +	bool use_pq_cert = false;
> +	int i, ret;
> +#endif /* HAVE_GNUTLS_MLDSA */
>  
>  	tlshd_x509_log_issuers(req_ca_rdn, nreqs);
>  
> @@ -127,9 +155,36 @@ tlshd_x509_retrieve_key_cb(gnutls_session_t session,
>  	if (type != GNUTLS_CRT_X509)
>  		return -1;
>  
> +#ifdef HAVE_GNUTLS_MLDSA
> +	for (i = 0; ; i++) {
> +		ret = gnutls_sign_algorithm_get_requested(session, i, &client_alg);
> +		if (ret != GNUTLS_E_SUCCESS)
> +			break;
> +		if (client_alg == GNUTLS_SIGN_MLDSA44
> +				|| client_alg == GNUTLS_SIGN_MLDSA65
> +				|| client_alg == GNUTLS_SIGN_MLDSA87) {
> +			tlshd_log_debug("%s: Client supports ML-DSA", __func__);
> +			use_pq_cert = true;
> +			break;
> +		}
> +	}
> +
> +	if (use_pq_cert == true && tlshd_server_pq_certs_len > 0) {
> +		tlshd_log_debug("%s: Selecting x509.pq.certificate from conf file", __func__);
> +		*pcert_length = tlshd_server_pq_certs_len;
> +		*pcert = tlshd_server_pq_certs;
> +		*privkey = tlshd_server_pq_privkey;
> +	} else {
> +		tlshd_log_debug("%s: Selecting x509.certificate from conf file", __func__);
> +		*pcert_length = tlshd_server_certs_len;
> +		*pcert = tlshd_server_certs;
> +		*privkey = tlshd_server_privkey;
> +	}
> +#else
>  	*pcert_length = tlshd_server_certs_len;
>  	*pcert = tlshd_server_certs;
>  	*privkey = tlshd_server_privkey;
> +#endif /* HAVE_GNUTLS_MLDSA */
>  	return 0;
>  }
>  
> diff --git a/src/tlshd/tlshd.conf b/src/tlshd/tlshd.conf
> index 620bd17..5419146 100644
> --- a/src/tlshd/tlshd.conf
> +++ b/src/tlshd/tlshd.conf
> @@ -39,3 +39,5 @@ nl=0
>  #x509.crl= <pathname>
>  #x509.certificate= <pathname>
>  #x509.private_key= <pathname>
> +#x509.pq.certificate= <pathname>
> +#x509.pq.private_key= <pathname>
> diff --git a/src/tlshd/tlshd.conf.man b/src/tlshd/tlshd.conf.man
> index 914261e..ed545e4 100644
> --- a/src/tlshd/tlshd.conf.man
> +++ b/src/tlshd/tlshd.conf.man
> @@ -125,6 +125,19 @@ a handshake request when no other certificate is available.
>  .B x509.private_key
>  This option specifies the pathname of a file containing
>  a PEM-encoded private key associated with the above certificate.
> +.TP
> +.B x509.pq.certificate
> +This option specifies the pathname of a file containing
> +a PEM-encoded x.509 certificate that is to be presented during
> +a handshake request if the peer supports post-quantum cryptography.
> +If the peer does not support post-quantum cryptography, the
> +certificate configured in the
> +.I x509.certificate
> +option will be presented instead.
> +.TP
> +.B x509.pq.private_key
> +This option specifies the pathname of a file containing
> +a PEM-encoded private key associated with the above certificate.
>  .SH SEE ALSO
>  .BR tlshd (8)
>  .SH AUTHOR
> diff --git a/src/tlshd/tlshd.h b/src/tlshd/tlshd.h
> index a0dd47e..d9b68ed 100644
> --- a/src/tlshd/tlshd.h
> +++ b/src/tlshd/tlshd.h
> @@ -59,9 +59,11 @@ bool tlshd_config_get_client_certs(gnutls_pcert_st *certs,
>  bool tlshd_config_get_client_privkey(gnutls_privkey_t *privkey);
>  bool tlshd_config_get_server_truststore(char **bundle);
>  bool tlshd_config_get_server_crl(char **result);
> -bool tlshd_config_get_server_certs(gnutls_pcert_st *certs,
> +bool tlshd_config_get_server_certs(const gchar *key,
> +				   gnutls_pcert_st *certs,
>  				   unsigned int *certs_len);
> -bool tlshd_config_get_server_privkey(gnutls_privkey_t *privkey);
> +bool tlshd_config_get_server_privkey(const gchar *key,
> +				     gnutls_privkey_t *privkey);
>  
>  /* handshake.c */
>  extern void tlshd_start_tls_handshake(gnutls_session_t session,


-- 
Chuck Lever

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/5] tlshd: Server-side dual certificate support
  2025-08-29 16:59   ` Chuck Lever
@ 2025-09-03 13:28     ` Scott Mayhew
  2025-09-03 14:17       ` Chuck Lever
  2025-09-03 15:03       ` Chuck Lever
  0 siblings, 2 replies; 11+ messages in thread
From: Scott Mayhew @ 2025-09-03 13:28 UTC (permalink / raw)
  To: Chuck Lever; +Cc: kernel-tls-handshake

On Fri, 29 Aug 2025, Chuck Lever wrote:

> On 8/28/25 6:23 PM, Scott Mayhew wrote:
> > Add two new config options, "x509.pq.certificate" and
> > "x509.pq.private_key" to configure tlshd to use an ML-DSA certificate.
> > If the cert callback determines that the client supports ML-DSA, it will
> > select this certificate.  Otherwise, it will fall back to the
> > traditional certficate (i.e. the certificate configured via
> > "x509.certificate" and "x509.private_key").
> > 
> > Link: https://github.com/oracle/ktls-utils/issues/113
> > Signed-off-by: Scott Mayhew <smayhew@redhat.com>
> > ---
> >  configure.ac             | 12 ++++++++
> >  src/tlshd/config.c       | 12 +++++---
> >  src/tlshd/server.c       | 59 ++++++++++++++++++++++++++++++++++++++--
> >  src/tlshd/tlshd.conf     |  2 ++
> >  src/tlshd/tlshd.conf.man | 13 +++++++++
> >  src/tlshd/tlshd.h        |  6 ++--
> >  6 files changed, 96 insertions(+), 8 deletions(-)
> > 
> > diff --git a/configure.ac b/configure.ac
> > index a6d9d09..0dd23f2 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -79,6 +79,18 @@ AC_CHECK_LIB([gnutls], [gnutls_get_system_config_file],
> >  AC_CHECK_LIB([gnutls], [gnutls_psk_allocate_client_credentials2],
> >               [AC_DEFINE([HAVE_GNUTLS_PSK_ALLOCATE_CREDENTIALS2], [1],
> >                          [Define to 1 if you have the gnutls_psk_allocate_client_credentials2 function.])])
> > +
> > +AC_MSG_CHECKING(for ML-DSA support in gnutls)
> > +AC_COMPILE_IFELSE(
> > +	[AC_LANG_PROGRAM([[ #include <gnutls/gnutls.h> ]],
> > +		[[ (void) GNUTLS_SIGN_MLDSA65; ]])],
> > +	[ have_mldsa=yes ],
> > +	[ have_mldsa=no ])
> > +AC_MSG_RESULT([$have_mldsa])
> > +if test "x$have_mldsa" = xyes ; then
> > +	AC_DEFINE([HAVE_GNUTLS_MLDSA], [1], [Define to 1 if gnutls supports ML-DSA])
> > +fi
> > +
> >  AC_SUBST([AM_CPPFLAGS])
> >  
> >  AC_CONFIG_FILES([Makefile src/Makefile src/tlshd/Makefile systemd/Makefile])
> 
> Nice.
> 
> 
> > diff --git a/src/tlshd/config.c b/src/tlshd/config.c
> > index 4c54d37..20634dd 100644
> > --- a/src/tlshd/config.c
> > +++ b/src/tlshd/config.c
> > @@ -403,6 +403,7 @@ bool tlshd_config_get_server_crl(char **result)
> >  
> >  /**
> >   * tlshd_config_get_server_certs - Get certs for ServerHello from .conf
> > + * @key: IN: the key field name from .conf
> 
> ETOOMANYTHINGSCALLEDKEY :-)
> 
> Can you find a less overloaded name for the new function parameter, here
> and below?

Yeah, I called it 'key' because that's what it's referred to in
https://docs.gtk.org/glib/method.KeyFile.get_string.html
I'm open to suggestions (gkey? gfile_key? option?)

> 
> But see below... perhaps the additional parameter isn't needed if all
> the configured certificates and private keys can be retrieved using the
> same functions.
> 
> 
> >   * @certs: OUT: in-memory certificates
> >   * @certs_len: IN: maximum number of certs to get, OUT: number of certs found
> >   *
> > @@ -410,7 +411,8 @@ bool tlshd_config_get_server_crl(char **result)
> >   *   %true: certificate retrieved successfully
> >   *   %false: certificate not retrieved
> >   */
> > -bool tlshd_config_get_server_certs(gnutls_pcert_st *certs,
> > +bool tlshd_config_get_server_certs(const gchar *key,
> > +				   gnutls_pcert_st *certs,
> >  				   unsigned int *certs_len)
> >  {
> >  	gnutls_datum_t data;
> > @@ -418,7 +420,7 @@ bool tlshd_config_get_server_certs(gnutls_pcert_st *certs,
> >  	int ret;
> >  
> >  	pathname = g_key_file_get_string(tlshd_configuration, "authenticate.server",
> > -					"x509.certificate", NULL);
> > +					key, NULL);
> >  	if (!pathname)
> >  		return false;
> >  
> > @@ -446,20 +448,22 @@ bool tlshd_config_get_server_certs(gnutls_pcert_st *certs,
> >  
> >  /**
> >   * tlshd_config_get_server_privkey - Get private key for ServerHello from .conf
> > + * @key: IN: the key field name from .conf
> >   * @privkey: OUT: in-memory private key
> >   *
> >   * Return values:
> >   *   %true: private key retrieved successfully
> >   *   %false: private key not retrieved
> >   */
> > -bool tlshd_config_get_server_privkey(gnutls_privkey_t *privkey)
> > +bool tlshd_config_get_server_privkey(const gchar *key,
> > +				     gnutls_privkey_t *privkey)
> >  {
> >  	gnutls_datum_t data;
> >  	gchar *pathname;
> >  	int ret;
> >  
> >  	pathname = g_key_file_get_string(tlshd_configuration, "authenticate.server",
> > -					"x509.private_key", NULL);
> > +					key, NULL);
> >  	if (!pathname)
> >  		return false;
> >  
> > diff --git a/src/tlshd/server.c b/src/tlshd/server.c
> > index 6b4535d..96b1b88 100644
> > --- a/src/tlshd/server.c
> > +++ b/src/tlshd/server.c
> > @@ -46,13 +46,25 @@ static gnutls_privkey_t tlshd_server_privkey;
> >  static unsigned int tlshd_server_certs_len = TLSHD_MAX_CERTS;
> >  static gnutls_pcert_st tlshd_server_certs[TLSHD_MAX_CERTS];
> >  
> > +#ifdef HAVE_GNUTLS_MLDSA
> > +static gnutls_privkey_t tlshd_server_pq_privkey;
> > +static unsigned int tlshd_server_pq_certs_len = TLSHD_MAX_CERTS;
> > +static gnutls_pcert_st tlshd_server_pq_certs[TLSHD_MAX_CERTS];
> > +#endif /* HAVE_GNUTLS_MLDSA */
> > +
> 
> Two architectural thoughts when seeing this:
> 
> 1. Generally, I'd rather see fewer "#ifdef HAVE_GNUTLS_MLDSA" throughout
>    and just leave things enabled all the time where it makes sense. That
>    makes for less clutter and better test coverage.

I should've sent v1 before I did any refactoring :/  There's much less
IFDEFery going on in this version.

> 
> 2. Does it make sense for tlshd_config_get_server_certs to retrieve both
>    types of certificates in the same array? Or, more generally speaking,
>    where it's sensible, try not to duplicate the logic, but combine it.

Yeah, when I did the last patch I noticed that each of the client &
server variants of the tlshd_config_get_* are pretty much identical
except for 1) which stanza/group_name of the config they're looking at
and 2) whether they have the word "client" or "server" in the log
message.

I was thinking of adding the group_name to the arg list, which would at
least allow us to use the same functions for the client and the server
side of things... or just adding a flag field to specify whether we're
looking for the configuration for client/server and
post-quantum/traditional.

I'm not sure if I could use a single list or not.  I guess I'd need to
either store the index of the PQ cert or I'd need to walk the list each
time in the cert callback each time to find it.  I thought it was
more straightforward this way.

But looking at the gnutls-serv program I'm wondering why we even need to
use a list at all.  gnutls-serv just pulls the cert and key directly into
the credentials structure (gnutls_certificate_credentials_t) using the
higher level gnutls_certificate_set_x509_key_file() API.  When you run it
with multiple certs it picks the right one, without any cert callback.  Is
there a reason tlshd needs to use the lower level functions
gnutls_pcert_list_import_x509_raw and gnutls_privkey_import_x509_raw (at
least for the server-side stuff)?  Also, why does tlshd parse the config
and set up the credentials structure every time we do a handshake instead
of just doing it once at startup and reusing it for each session?

-Scott

> 
> Similar comments in the client parts of the series. Overall the series
> looks like a reasonable direction.
> 
> 
> >  static bool tlshd_x509_server_get_certs(struct tlshd_handshake_parms *parms)
> >  {
> >  	if (parms->x509_cert != TLS_NO_CERT)
> >  		return tlshd_keyring_get_certs(parms->x509_cert,
> >  					       tlshd_server_certs,
> >  					       &tlshd_server_certs_len);
> > -	return tlshd_config_get_server_certs(tlshd_server_certs,
> > +#ifdef HAVE_GNUTLS_MLDSA
> > +	tlshd_config_get_server_certs("x509.pq.certificate",
> > +				      tlshd_server_pq_certs,
> > +				      &tlshd_server_pq_certs_len);
> > +#endif /* HAVE_GNUTLS_MLDSA */
> > +	return tlshd_config_get_server_certs("x509.certificate",
> > +					     tlshd_server_certs,
> >  					     &tlshd_server_certs_len);
> >  }
> >  
> > @@ -62,6 +74,11 @@ static void tlshd_x509_server_put_certs(void)
> >  
> >  	for (i = 0; i < tlshd_server_certs_len; i++)
> >  		gnutls_pcert_deinit(&tlshd_server_certs[i]);
> > +
> > +#ifdef HAVE_GNUTLS_MLDSA
> > +	for (i = 0; i < tlshd_server_pq_certs_len; i++)
> > +		gnutls_pcert_deinit(&tlshd_server_pq_certs[i]);
> > +#endif /* HAVE_GNUTLS_MLDSA */
> >  }
> >  
> >  static bool tlshd_x509_server_get_privkey(struct tlshd_handshake_parms *parms)
> > @@ -69,12 +86,18 @@ static bool tlshd_x509_server_get_privkey(struct tlshd_handshake_parms *parms)
> >  	if (parms->x509_privkey != TLS_NO_PRIVKEY)
> >  		return tlshd_keyring_get_privkey(parms->x509_privkey,
> >  						 &tlshd_server_privkey);
> > -	return tlshd_config_get_server_privkey(&tlshd_server_privkey);
> > +#ifdef HAVE_GNUTLS_MLDSA
> > +	tlshd_config_get_server_privkey("x509.pq.private_key", &tlshd_server_pq_privkey);
> > +#endif /* HAVE_GNUTLS_MLDSA */
> > +	return tlshd_config_get_server_privkey("x509.private_key", &tlshd_server_privkey);
> >  }
> >  
> >  static void tlshd_x509_server_put_privkey(void)
> >  {
> >  	gnutls_privkey_deinit(tlshd_server_privkey);
> > +#ifdef HAVE_GNUTLS_MLDSA
> > +	gnutls_privkey_deinit(tlshd_server_pq_privkey);
> > +#endif /* HAVE_GNUTLS_MLDSA */
> >  }
> >  
> >  static void tlshd_x509_log_issuers(const gnutls_datum_t *req_ca_rdn, int nreqs)
> > @@ -120,6 +143,11 @@ tlshd_x509_retrieve_key_cb(gnutls_session_t session,
> >  			   gnutls_privkey_t *privkey)
> >  {
> >  	gnutls_certificate_type_t type;
> > +#ifdef HAVE_GNUTLS_MLDSA
> > +	gnutls_sign_algorithm_t client_alg;
> > +	bool use_pq_cert = false;
> > +	int i, ret;
> > +#endif /* HAVE_GNUTLS_MLDSA */
> >  
> >  	tlshd_x509_log_issuers(req_ca_rdn, nreqs);
> >  
> > @@ -127,9 +155,36 @@ tlshd_x509_retrieve_key_cb(gnutls_session_t session,
> >  	if (type != GNUTLS_CRT_X509)
> >  		return -1;
> >  
> > +#ifdef HAVE_GNUTLS_MLDSA
> > +	for (i = 0; ; i++) {
> > +		ret = gnutls_sign_algorithm_get_requested(session, i, &client_alg);
> > +		if (ret != GNUTLS_E_SUCCESS)
> > +			break;
> > +		if (client_alg == GNUTLS_SIGN_MLDSA44
> > +				|| client_alg == GNUTLS_SIGN_MLDSA65
> > +				|| client_alg == GNUTLS_SIGN_MLDSA87) {
> > +			tlshd_log_debug("%s: Client supports ML-DSA", __func__);
> > +			use_pq_cert = true;
> > +			break;
> > +		}
> > +	}
> > +
> > +	if (use_pq_cert == true && tlshd_server_pq_certs_len > 0) {
> > +		tlshd_log_debug("%s: Selecting x509.pq.certificate from conf file", __func__);
> > +		*pcert_length = tlshd_server_pq_certs_len;
> > +		*pcert = tlshd_server_pq_certs;
> > +		*privkey = tlshd_server_pq_privkey;
> > +	} else {
> > +		tlshd_log_debug("%s: Selecting x509.certificate from conf file", __func__);
> > +		*pcert_length = tlshd_server_certs_len;
> > +		*pcert = tlshd_server_certs;
> > +		*privkey = tlshd_server_privkey;
> > +	}
> > +#else
> >  	*pcert_length = tlshd_server_certs_len;
> >  	*pcert = tlshd_server_certs;
> >  	*privkey = tlshd_server_privkey;
> > +#endif /* HAVE_GNUTLS_MLDSA */
> >  	return 0;
> >  }
> >  
> > diff --git a/src/tlshd/tlshd.conf b/src/tlshd/tlshd.conf
> > index 620bd17..5419146 100644
> > --- a/src/tlshd/tlshd.conf
> > +++ b/src/tlshd/tlshd.conf
> > @@ -39,3 +39,5 @@ nl=0
> >  #x509.crl= <pathname>
> >  #x509.certificate= <pathname>
> >  #x509.private_key= <pathname>
> > +#x509.pq.certificate= <pathname>
> > +#x509.pq.private_key= <pathname>
> > diff --git a/src/tlshd/tlshd.conf.man b/src/tlshd/tlshd.conf.man
> > index 914261e..ed545e4 100644
> > --- a/src/tlshd/tlshd.conf.man
> > +++ b/src/tlshd/tlshd.conf.man
> > @@ -125,6 +125,19 @@ a handshake request when no other certificate is available.
> >  .B x509.private_key
> >  This option specifies the pathname of a file containing
> >  a PEM-encoded private key associated with the above certificate.
> > +.TP
> > +.B x509.pq.certificate
> > +This option specifies the pathname of a file containing
> > +a PEM-encoded x.509 certificate that is to be presented during
> > +a handshake request if the peer supports post-quantum cryptography.
> > +If the peer does not support post-quantum cryptography, the
> > +certificate configured in the
> > +.I x509.certificate
> > +option will be presented instead.
> > +.TP
> > +.B x509.pq.private_key
> > +This option specifies the pathname of a file containing
> > +a PEM-encoded private key associated with the above certificate.
> >  .SH SEE ALSO
> >  .BR tlshd (8)
> >  .SH AUTHOR
> > diff --git a/src/tlshd/tlshd.h b/src/tlshd/tlshd.h
> > index a0dd47e..d9b68ed 100644
> > --- a/src/tlshd/tlshd.h
> > +++ b/src/tlshd/tlshd.h
> > @@ -59,9 +59,11 @@ bool tlshd_config_get_client_certs(gnutls_pcert_st *certs,
> >  bool tlshd_config_get_client_privkey(gnutls_privkey_t *privkey);
> >  bool tlshd_config_get_server_truststore(char **bundle);
> >  bool tlshd_config_get_server_crl(char **result);
> > -bool tlshd_config_get_server_certs(gnutls_pcert_st *certs,
> > +bool tlshd_config_get_server_certs(const gchar *key,
> > +				   gnutls_pcert_st *certs,
> >  				   unsigned int *certs_len);
> > -bool tlshd_config_get_server_privkey(gnutls_privkey_t *privkey);
> > +bool tlshd_config_get_server_privkey(const gchar *key,
> > +				     gnutls_privkey_t *privkey);
> >  
> >  /* handshake.c */
> >  extern void tlshd_start_tls_handshake(gnutls_session_t session,
> 
> 
> -- 
> Chuck Lever
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/5] tlshd: Server-side dual certificate support
  2025-09-03 13:28     ` Scott Mayhew
@ 2025-09-03 14:17       ` Chuck Lever
  2025-09-03 15:03       ` Chuck Lever
  1 sibling, 0 replies; 11+ messages in thread
From: Chuck Lever @ 2025-09-03 14:17 UTC (permalink / raw)
  To: Scott Mayhew; +Cc: kernel-tls-handshake

On 9/3/25 9:28 AM, Scott Mayhew wrote:
> On Fri, 29 Aug 2025, Chuck Lever wrote:
> 
>> On 8/28/25 6:23 PM, Scott Mayhew wrote:
>>> Add two new config options, "x509.pq.certificate" and
>>> "x509.pq.private_key" to configure tlshd to use an ML-DSA certificate.
>>> If the cert callback determines that the client supports ML-DSA, it will
>>> select this certificate.  Otherwise, it will fall back to the
>>> traditional certficate (i.e. the certificate configured via
>>> "x509.certificate" and "x509.private_key").
>>>
>>> Link: https://github.com/oracle/ktls-utils/issues/113
>>> Signed-off-by: Scott Mayhew <smayhew@redhat.com>
>>> ---
>>>  configure.ac             | 12 ++++++++
>>>  src/tlshd/config.c       | 12 +++++---
>>>  src/tlshd/server.c       | 59 ++++++++++++++++++++++++++++++++++++++--
>>>  src/tlshd/tlshd.conf     |  2 ++
>>>  src/tlshd/tlshd.conf.man | 13 +++++++++
>>>  src/tlshd/tlshd.h        |  6 ++--
>>>  6 files changed, 96 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/configure.ac b/configure.ac
>>> index a6d9d09..0dd23f2 100644
>>> --- a/configure.ac
>>> +++ b/configure.ac
>>> @@ -79,6 +79,18 @@ AC_CHECK_LIB([gnutls], [gnutls_get_system_config_file],
>>>  AC_CHECK_LIB([gnutls], [gnutls_psk_allocate_client_credentials2],
>>>               [AC_DEFINE([HAVE_GNUTLS_PSK_ALLOCATE_CREDENTIALS2], [1],
>>>                          [Define to 1 if you have the gnutls_psk_allocate_client_credentials2 function.])])
>>> +
>>> +AC_MSG_CHECKING(for ML-DSA support in gnutls)
>>> +AC_COMPILE_IFELSE(
>>> +	[AC_LANG_PROGRAM([[ #include <gnutls/gnutls.h> ]],
>>> +		[[ (void) GNUTLS_SIGN_MLDSA65; ]])],
>>> +	[ have_mldsa=yes ],
>>> +	[ have_mldsa=no ])
>>> +AC_MSG_RESULT([$have_mldsa])
>>> +if test "x$have_mldsa" = xyes ; then
>>> +	AC_DEFINE([HAVE_GNUTLS_MLDSA], [1], [Define to 1 if gnutls supports ML-DSA])
>>> +fi
>>> +
>>>  AC_SUBST([AM_CPPFLAGS])
>>>  
>>>  AC_CONFIG_FILES([Makefile src/Makefile src/tlshd/Makefile systemd/Makefile])
>>
>> Nice.
>>
>>
>>> diff --git a/src/tlshd/config.c b/src/tlshd/config.c
>>> index 4c54d37..20634dd 100644
>>> --- a/src/tlshd/config.c
>>> +++ b/src/tlshd/config.c
>>> @@ -403,6 +403,7 @@ bool tlshd_config_get_server_crl(char **result)
>>>  
>>>  /**
>>>   * tlshd_config_get_server_certs - Get certs for ServerHello from .conf
>>> + * @key: IN: the key field name from .conf
>>
>> ETOOMANYTHINGSCALLEDKEY :-)
>>
>> Can you find a less overloaded name for the new function parameter, here
>> and below?
> 
> Yeah, I called it 'key' because that's what it's referred to in
> https://docs.gtk.org/glib/method.KeyFile.get_string.html
> I'm open to suggestions (gkey? gfile_key? option?)
> 
>>
>> But see below... perhaps the additional parameter isn't needed if all
>> the configured certificates and private keys can be retrieved using the
>> same functions.
>>
>>
>>>   * @certs: OUT: in-memory certificates
>>>   * @certs_len: IN: maximum number of certs to get, OUT: number of certs found
>>>   *
>>> @@ -410,7 +411,8 @@ bool tlshd_config_get_server_crl(char **result)
>>>   *   %true: certificate retrieved successfully
>>>   *   %false: certificate not retrieved
>>>   */
>>> -bool tlshd_config_get_server_certs(gnutls_pcert_st *certs,
>>> +bool tlshd_config_get_server_certs(const gchar *key,
>>> +				   gnutls_pcert_st *certs,
>>>  				   unsigned int *certs_len)
>>>  {
>>>  	gnutls_datum_t data;
>>> @@ -418,7 +420,7 @@ bool tlshd_config_get_server_certs(gnutls_pcert_st *certs,
>>>  	int ret;
>>>  
>>>  	pathname = g_key_file_get_string(tlshd_configuration, "authenticate.server",
>>> -					"x509.certificate", NULL);
>>> +					key, NULL);
>>>  	if (!pathname)
>>>  		return false;
>>>  
>>> @@ -446,20 +448,22 @@ bool tlshd_config_get_server_certs(gnutls_pcert_st *certs,
>>>  
>>>  /**
>>>   * tlshd_config_get_server_privkey - Get private key for ServerHello from .conf
>>> + * @key: IN: the key field name from .conf
>>>   * @privkey: OUT: in-memory private key
>>>   *
>>>   * Return values:
>>>   *   %true: private key retrieved successfully
>>>   *   %false: private key not retrieved
>>>   */
>>> -bool tlshd_config_get_server_privkey(gnutls_privkey_t *privkey)
>>> +bool tlshd_config_get_server_privkey(const gchar *key,
>>> +				     gnutls_privkey_t *privkey)
>>>  {
>>>  	gnutls_datum_t data;
>>>  	gchar *pathname;
>>>  	int ret;
>>>  
>>>  	pathname = g_key_file_get_string(tlshd_configuration, "authenticate.server",
>>> -					"x509.private_key", NULL);
>>> +					key, NULL);
>>>  	if (!pathname)
>>>  		return false;
>>>  
>>> diff --git a/src/tlshd/server.c b/src/tlshd/server.c
>>> index 6b4535d..96b1b88 100644
>>> --- a/src/tlshd/server.c
>>> +++ b/src/tlshd/server.c
>>> @@ -46,13 +46,25 @@ static gnutls_privkey_t tlshd_server_privkey;
>>>  static unsigned int tlshd_server_certs_len = TLSHD_MAX_CERTS;
>>>  static gnutls_pcert_st tlshd_server_certs[TLSHD_MAX_CERTS];
>>>  
>>> +#ifdef HAVE_GNUTLS_MLDSA
>>> +static gnutls_privkey_t tlshd_server_pq_privkey;
>>> +static unsigned int tlshd_server_pq_certs_len = TLSHD_MAX_CERTS;
>>> +static gnutls_pcert_st tlshd_server_pq_certs[TLSHD_MAX_CERTS];
>>> +#endif /* HAVE_GNUTLS_MLDSA */
>>> +
>>
>> Two architectural thoughts when seeing this:
>>
>> 1. Generally, I'd rather see fewer "#ifdef HAVE_GNUTLS_MLDSA" throughout
>>    and just leave things enabled all the time where it makes sense. That
>>    makes for less clutter and better test coverage.
> 
> I should've sent v1 before I did any refactoring :/  There's much less
> IFDEFery going on in this version.
> 
>>
>> 2. Does it make sense for tlshd_config_get_server_certs to retrieve both
>>    types of certificates in the same array? Or, more generally speaking,
>>    where it's sensible, try not to duplicate the logic, but combine it.
> 
> Yeah, when I did the last patch I noticed that each of the client &
> server variants of the tlshd_config_get_* are pretty much identical
> except for 1) which stanza/group_name of the config they're looking at
> and 2) whether they have the word "client" or "server" in the log
> message.
> 
> I was thinking of adding the group_name to the arg list, which would at
> least allow us to use the same functions for the client and the server
> side of things... or just adding a flag field to specify whether we're
> looking for the configuration for client/server and
> post-quantum/traditional.

Careful, you might be mixing local knowlege from two subsystems. I'd
like to keep the config-related details in config.c and the x.509
related details in x509.c -- at least as much as is practical.


> I'm not sure if I could use a single list or not.  I guess I'd need to
> either store the index of the PQ cert or I'd need to walk the list each
> time in the cert callback each time to find it.  I thought it was
> more straightforward this way.
> 
> But looking at the gnutls-serv program I'm wondering why we even need to
> use a list at all.  gnutls-serv just pulls the cert and key directly into
> the credentials structure (gnutls_certificate_credentials_t) using the
> higher level gnutls_certificate_set_x509_key_file() API.  When you run it
> with multiple certs it picks the right one, without any cert callback.  Is
> there a reason tlshd needs to use the lower level functions
> gnutls_pcert_list_import_x509_raw and gnutls_privkey_import_x509_raw (at
> least for the server-side stuff)?

I don't remember, unfortunately.


> Also, why does tlshd parse the config
> and set up the credentials structure every time we do a handshake instead
> of just doing it once at startup and reusing it for each session?

Is it parsing the config, or simply walking the already-parsed
tlshd_configuration data structure?


>> Similar comments in the client parts of the series. Overall the series
>> looks like a reasonable direction.
>>
>>
>>>  static bool tlshd_x509_server_get_certs(struct tlshd_handshake_parms *parms)
>>>  {
>>>  	if (parms->x509_cert != TLS_NO_CERT)
>>>  		return tlshd_keyring_get_certs(parms->x509_cert,
>>>  					       tlshd_server_certs,
>>>  					       &tlshd_server_certs_len);
>>> -	return tlshd_config_get_server_certs(tlshd_server_certs,
>>> +#ifdef HAVE_GNUTLS_MLDSA
>>> +	tlshd_config_get_server_certs("x509.pq.certificate",
>>> +				      tlshd_server_pq_certs,
>>> +				      &tlshd_server_pq_certs_len);
>>> +#endif /* HAVE_GNUTLS_MLDSA */
>>> +	return tlshd_config_get_server_certs("x509.certificate",
>>> +					     tlshd_server_certs,
>>>  					     &tlshd_server_certs_len);
>>>  }
>>>  
>>> @@ -62,6 +74,11 @@ static void tlshd_x509_server_put_certs(void)
>>>  
>>>  	for (i = 0; i < tlshd_server_certs_len; i++)
>>>  		gnutls_pcert_deinit(&tlshd_server_certs[i]);
>>> +
>>> +#ifdef HAVE_GNUTLS_MLDSA
>>> +	for (i = 0; i < tlshd_server_pq_certs_len; i++)
>>> +		gnutls_pcert_deinit(&tlshd_server_pq_certs[i]);
>>> +#endif /* HAVE_GNUTLS_MLDSA */
>>>  }
>>>  
>>>  static bool tlshd_x509_server_get_privkey(struct tlshd_handshake_parms *parms)
>>> @@ -69,12 +86,18 @@ static bool tlshd_x509_server_get_privkey(struct tlshd_handshake_parms *parms)
>>>  	if (parms->x509_privkey != TLS_NO_PRIVKEY)
>>>  		return tlshd_keyring_get_privkey(parms->x509_privkey,
>>>  						 &tlshd_server_privkey);
>>> -	return tlshd_config_get_server_privkey(&tlshd_server_privkey);
>>> +#ifdef HAVE_GNUTLS_MLDSA
>>> +	tlshd_config_get_server_privkey("x509.pq.private_key", &tlshd_server_pq_privkey);
>>> +#endif /* HAVE_GNUTLS_MLDSA */
>>> +	return tlshd_config_get_server_privkey("x509.private_key", &tlshd_server_privkey);
>>>  }
>>>  
>>>  static void tlshd_x509_server_put_privkey(void)
>>>  {
>>>  	gnutls_privkey_deinit(tlshd_server_privkey);
>>> +#ifdef HAVE_GNUTLS_MLDSA
>>> +	gnutls_privkey_deinit(tlshd_server_pq_privkey);
>>> +#endif /* HAVE_GNUTLS_MLDSA */
>>>  }
>>>  
>>>  static void tlshd_x509_log_issuers(const gnutls_datum_t *req_ca_rdn, int nreqs)
>>> @@ -120,6 +143,11 @@ tlshd_x509_retrieve_key_cb(gnutls_session_t session,
>>>  			   gnutls_privkey_t *privkey)
>>>  {
>>>  	gnutls_certificate_type_t type;
>>> +#ifdef HAVE_GNUTLS_MLDSA
>>> +	gnutls_sign_algorithm_t client_alg;
>>> +	bool use_pq_cert = false;
>>> +	int i, ret;
>>> +#endif /* HAVE_GNUTLS_MLDSA */
>>>  
>>>  	tlshd_x509_log_issuers(req_ca_rdn, nreqs);
>>>  
>>> @@ -127,9 +155,36 @@ tlshd_x509_retrieve_key_cb(gnutls_session_t session,
>>>  	if (type != GNUTLS_CRT_X509)
>>>  		return -1;
>>>  
>>> +#ifdef HAVE_GNUTLS_MLDSA
>>> +	for (i = 0; ; i++) {
>>> +		ret = gnutls_sign_algorithm_get_requested(session, i, &client_alg);
>>> +		if (ret != GNUTLS_E_SUCCESS)
>>> +			break;
>>> +		if (client_alg == GNUTLS_SIGN_MLDSA44
>>> +				|| client_alg == GNUTLS_SIGN_MLDSA65
>>> +				|| client_alg == GNUTLS_SIGN_MLDSA87) {
>>> +			tlshd_log_debug("%s: Client supports ML-DSA", __func__);
>>> +			use_pq_cert = true;
>>> +			break;
>>> +		}
>>> +	}
>>> +
>>> +	if (use_pq_cert == true && tlshd_server_pq_certs_len > 0) {
>>> +		tlshd_log_debug("%s: Selecting x509.pq.certificate from conf file", __func__);
>>> +		*pcert_length = tlshd_server_pq_certs_len;
>>> +		*pcert = tlshd_server_pq_certs;
>>> +		*privkey = tlshd_server_pq_privkey;
>>> +	} else {
>>> +		tlshd_log_debug("%s: Selecting x509.certificate from conf file", __func__);
>>> +		*pcert_length = tlshd_server_certs_len;
>>> +		*pcert = tlshd_server_certs;
>>> +		*privkey = tlshd_server_privkey;
>>> +	}
>>> +#else
>>>  	*pcert_length = tlshd_server_certs_len;
>>>  	*pcert = tlshd_server_certs;
>>>  	*privkey = tlshd_server_privkey;
>>> +#endif /* HAVE_GNUTLS_MLDSA */
>>>  	return 0;
>>>  }
>>>  
>>> diff --git a/src/tlshd/tlshd.conf b/src/tlshd/tlshd.conf
>>> index 620bd17..5419146 100644
>>> --- a/src/tlshd/tlshd.conf
>>> +++ b/src/tlshd/tlshd.conf
>>> @@ -39,3 +39,5 @@ nl=0
>>>  #x509.crl= <pathname>
>>>  #x509.certificate= <pathname>
>>>  #x509.private_key= <pathname>
>>> +#x509.pq.certificate= <pathname>
>>> +#x509.pq.private_key= <pathname>
>>> diff --git a/src/tlshd/tlshd.conf.man b/src/tlshd/tlshd.conf.man
>>> index 914261e..ed545e4 100644
>>> --- a/src/tlshd/tlshd.conf.man
>>> +++ b/src/tlshd/tlshd.conf.man
>>> @@ -125,6 +125,19 @@ a handshake request when no other certificate is available.
>>>  .B x509.private_key
>>>  This option specifies the pathname of a file containing
>>>  a PEM-encoded private key associated with the above certificate.
>>> +.TP
>>> +.B x509.pq.certificate
>>> +This option specifies the pathname of a file containing
>>> +a PEM-encoded x.509 certificate that is to be presented during
>>> +a handshake request if the peer supports post-quantum cryptography.
>>> +If the peer does not support post-quantum cryptography, the
>>> +certificate configured in the
>>> +.I x509.certificate
>>> +option will be presented instead.
>>> +.TP
>>> +.B x509.pq.private_key
>>> +This option specifies the pathname of a file containing
>>> +a PEM-encoded private key associated with the above certificate.
>>>  .SH SEE ALSO
>>>  .BR tlshd (8)
>>>  .SH AUTHOR
>>> diff --git a/src/tlshd/tlshd.h b/src/tlshd/tlshd.h
>>> index a0dd47e..d9b68ed 100644
>>> --- a/src/tlshd/tlshd.h
>>> +++ b/src/tlshd/tlshd.h
>>> @@ -59,9 +59,11 @@ bool tlshd_config_get_client_certs(gnutls_pcert_st *certs,
>>>  bool tlshd_config_get_client_privkey(gnutls_privkey_t *privkey);
>>>  bool tlshd_config_get_server_truststore(char **bundle);
>>>  bool tlshd_config_get_server_crl(char **result);
>>> -bool tlshd_config_get_server_certs(gnutls_pcert_st *certs,
>>> +bool tlshd_config_get_server_certs(const gchar *key,
>>> +				   gnutls_pcert_st *certs,
>>>  				   unsigned int *certs_len);
>>> -bool tlshd_config_get_server_privkey(gnutls_privkey_t *privkey);
>>> +bool tlshd_config_get_server_privkey(const gchar *key,
>>> +				     gnutls_privkey_t *privkey);
>>>  
>>>  /* handshake.c */
>>>  extern void tlshd_start_tls_handshake(gnutls_session_t session,
>>
>>
>> -- 
>> Chuck Lever
>>
> 


-- 
Chuck Lever

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/5] tlshd: Server-side dual certificate support
  2025-09-03 13:28     ` Scott Mayhew
  2025-09-03 14:17       ` Chuck Lever
@ 2025-09-03 15:03       ` Chuck Lever
  1 sibling, 0 replies; 11+ messages in thread
From: Chuck Lever @ 2025-09-03 15:03 UTC (permalink / raw)
  To: Scott Mayhew; +Cc: kernel-tls-handshake

On 9/3/25 9:28 AM, Scott Mayhew wrote:
> On Fri, 29 Aug 2025, Chuck Lever wrote:
> 
>> On 8/28/25 6:23 PM, Scott Mayhew wrote:
>>> Add two new config options, "x509.pq.certificate" and
>>> "x509.pq.private_key" to configure tlshd to use an ML-DSA certificate.
>>> If the cert callback determines that the client supports ML-DSA, it will
>>> select this certificate.  Otherwise, it will fall back to the
>>> traditional certficate (i.e. the certificate configured via
>>> "x509.certificate" and "x509.private_key").
>>>
>>> Link: https://github.com/oracle/ktls-utils/issues/113
>>> Signed-off-by: Scott Mayhew <smayhew@redhat.com>
>>> ---
>>>  configure.ac             | 12 ++++++++
>>>  src/tlshd/config.c       | 12 +++++---
>>>  src/tlshd/server.c       | 59 ++++++++++++++++++++++++++++++++++++++--
>>>  src/tlshd/tlshd.conf     |  2 ++
>>>  src/tlshd/tlshd.conf.man | 13 +++++++++
>>>  src/tlshd/tlshd.h        |  6 ++--
>>>  6 files changed, 96 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/configure.ac b/configure.ac
>>> index a6d9d09..0dd23f2 100644
>>> --- a/configure.ac
>>> +++ b/configure.ac
>>> @@ -79,6 +79,18 @@ AC_CHECK_LIB([gnutls], [gnutls_get_system_config_file],
>>>  AC_CHECK_LIB([gnutls], [gnutls_psk_allocate_client_credentials2],
>>>               [AC_DEFINE([HAVE_GNUTLS_PSK_ALLOCATE_CREDENTIALS2], [1],
>>>                          [Define to 1 if you have the gnutls_psk_allocate_client_credentials2 function.])])
>>> +
>>> +AC_MSG_CHECKING(for ML-DSA support in gnutls)
>>> +AC_COMPILE_IFELSE(
>>> +	[AC_LANG_PROGRAM([[ #include <gnutls/gnutls.h> ]],
>>> +		[[ (void) GNUTLS_SIGN_MLDSA65; ]])],
>>> +	[ have_mldsa=yes ],
>>> +	[ have_mldsa=no ])
>>> +AC_MSG_RESULT([$have_mldsa])
>>> +if test "x$have_mldsa" = xyes ; then
>>> +	AC_DEFINE([HAVE_GNUTLS_MLDSA], [1], [Define to 1 if gnutls supports ML-DSA])
>>> +fi
>>> +
>>>  AC_SUBST([AM_CPPFLAGS])
>>>  
>>>  AC_CONFIG_FILES([Makefile src/Makefile src/tlshd/Makefile systemd/Makefile])
>>
>> Nice.
>>
>>
>>> diff --git a/src/tlshd/config.c b/src/tlshd/config.c
>>> index 4c54d37..20634dd 100644
>>> --- a/src/tlshd/config.c
>>> +++ b/src/tlshd/config.c
>>> @@ -403,6 +403,7 @@ bool tlshd_config_get_server_crl(char **result)
>>>  
>>>  /**
>>>   * tlshd_config_get_server_certs - Get certs for ServerHello from .conf
>>> + * @key: IN: the key field name from .conf
>>
>> ETOOMANYTHINGSCALLEDKEY :-)
>>
>> Can you find a less overloaded name for the new function parameter, here
>> and below?
> 
> Yeah, I called it 'key' because that's what it's referred to in
> https://docs.gtk.org/glib/method.KeyFile.get_string.html
> I'm open to suggestions (gkey? gfile_key? option?)

How about @cert_type ?

If you need to keep this parameter, I would make it an enumerated
integer. Keep the knowledge about the config option name internal
to config.c.


-- 
Chuck Lever

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2025-09-03 15:03 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-28 22:23 [PATCH 0/5] tlshd: Allow the use of post-quantum cryptography Scott Mayhew
2025-08-28 22:23 ` [PATCH 1/5] tlshd: Fix priority string to allow PQC Scott Mayhew
2025-08-29 16:47   ` Chuck Lever
2025-08-28 22:23 ` [PATCH 2/5] tlshd: Server-side dual certificate support Scott Mayhew
2025-08-29 16:59   ` Chuck Lever
2025-09-03 13:28     ` Scott Mayhew
2025-09-03 14:17       ` Chuck Lever
2025-09-03 15:03       ` Chuck Lever
2025-08-28 22:23 ` [PATCH 3/5] tlshd: Make sure x509.pq.certificate is using a PQ public-key alg Scott Mayhew
2025-08-28 22:23 ` [PATCH 4/5] tlshd: Make sure the client supports the PQ pk alg used by the server cert Scott Mayhew
2025-08-28 22:23 ` [PATCH 5/5] tlshd: Client-side dual certificate support Scott Mayhew

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.