All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/4] tlshd: Allow the use of post-quantum cryptography
@ 2025-09-11 21:28 Scott Mayhew
  2025-09-11 21:28 ` [PATCH v2 1/4] tlshd: deduplicate client and server config functions Scott Mayhew
                   ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: Scott Mayhew @ 2025-09-11 21:28 UTC (permalink / raw)
  To: chuck.lever; +Cc: kernel-tls-handshake

These patches allow tlshd to use post-quantum cryptography.  The first
patch does a bit of refactoring to reduce some code duplication.  The 
second fixes the priority string and allows the PQ algorithms to be
used.  The other two 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.

Changes since v1:
- Refactoring to allow the client and server code to use the same
  tlshd_config_get_* functions
- Removed a lot of "#ifdef HAVE_GNUTLS_MLDSA" statements (I'm pretty
  sure the handful that are left are necessary)
- Store both the PQ and RSA certs in the same array.  The PQ certs (if
  present) will be first, followed by the RSA certs.  Note that I didn't
  increase TLSHD_MAX_CERTS though.

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

Scott Mayhew (4):
  tlshd: deduplicate client and server config functions
  tlshd: Fix priority string to allow PQC
  tlshd: Server-side dual certificate support
  tlshd: Client-side dual certificate support

 configure.ac             |  12 ++
 src/tlshd/client.c       |  48 +++++--
 src/tlshd/config.c       | 281 +++++++++++++++++++--------------------
 src/tlshd/ktls.c         |   2 +-
 src/tlshd/server.c       |  74 ++++++++++-
 src/tlshd/tlshd.conf     |   4 +
 src/tlshd/tlshd.conf.man |  15 +++
 src/tlshd/tlshd.h        |  23 ++--
 8 files changed, 286 insertions(+), 173 deletions(-)

-- 
2.50.1


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

* [PATCH v2 1/4] tlshd: deduplicate client and server config functions
  2025-09-11 21:28 [PATCH v2 0/4] tlshd: Allow the use of post-quantum cryptography Scott Mayhew
@ 2025-09-11 21:28 ` Scott Mayhew
  2025-09-11 21:28 ` [PATCH v2 2/4] tlshd: Fix priority string to allow PQC Scott Mayhew
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 12+ messages in thread
From: Scott Mayhew @ 2025-09-11 21:28 UTC (permalink / raw)
  To: chuck.lever; +Cc: kernel-tls-handshake

The client and server variants of tlshd_config_get_* are identical
except for
1) the stanza they're looking at in the config file, and
2) whether the word "client" or "server" gets written in a log message

Add new parameter 'peer_type' to each of these functions so we can use
the same function for both the client and server code.

Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
 src/tlshd/client.c |   9 +-
 src/tlshd/config.c | 213 +++++++++------------------------------------
 src/tlshd/server.c |  11 +--
 src/tlshd/tlshd.h  |  20 ++---
 4 files changed, 62 insertions(+), 191 deletions(-)

diff --git a/src/tlshd/client.c b/src/tlshd/client.c
index 8acb0aa..c07ae29 100644
--- a/src/tlshd/client.c
+++ b/src/tlshd/client.c
@@ -48,7 +48,7 @@ static int tlshd_client_get_truststore(gnutls_certificate_credentials_t cred)
 	char *pathname;
 	int ret;
 
-	if (tlshd_config_get_client_truststore(&pathname)) {
+	if (tlshd_config_get_truststore(PEER_TYPE_CLIENT, &pathname)) {
 		ret = gnutls_certificate_set_x509_trust_file(cred, pathname,
 							     GNUTLS_X509_FMT_PEM);
 		free(pathname);
@@ -60,7 +60,7 @@ static int tlshd_client_get_truststore(gnutls_certificate_credentials_t cred)
 	}
 	tlshd_log_debug("System trust: Loaded %d certificate(s).", ret);
 
-	if (tlshd_config_get_client_crl(&pathname)) {
+	if (tlshd_config_get_crl(PEER_TYPE_CLIENT, &pathname)) {
 		ret = gnutls_certificate_set_x509_crl_file(cred, pathname,
 							   GNUTLS_X509_FMT_PEM);
 		free(pathname);
@@ -143,7 +143,8 @@ 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);
+	return tlshd_config_get_certs(PEER_TYPE_CLIENT, tlshd_certs,
+				      &tlshd_certs_len);
 }
 
 static void tlshd_x509_client_put_certs(void)
@@ -159,7 +160,7 @@ 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);
+	return tlshd_config_get_privkey(PEER_TYPE_CLIENT, &tlshd_privkey);
 }
 
 static void tlshd_x509_client_put_privkey(void)
diff --git a/src/tlshd/config.c b/src/tlshd/config.c
index 029dbcc..ff1f2a5 100644
--- a/src/tlshd/config.c
+++ b/src/tlshd/config.c
@@ -187,18 +187,22 @@ out:
 }
 
 /**
- * tlshd_config_get_client_truststore - Get truststore for ClientHello from .conf
+ * tlshd_config_get_truststore - Get truststore for {Client,Server}Hello from .conf
+ * @peer_type: IN: peer type
  * @bundle: OUT: pathname to truststore
  *
  * Return values:
  *   %false: pathname not retrieved
  *   %true: pathname retrieved successfully; caller must free @bundle using free(3)
  */
-bool tlshd_config_get_client_truststore(char **bundle)
+bool tlshd_config_get_truststore(int peer_type, char **bundle)
 {
 	gchar *pathname;
 
-	pathname = g_key_file_get_string(tlshd_configuration, "authenticate.client",
+	pathname = g_key_file_get_string(tlshd_configuration,
+					 peer_type == PEER_TYPE_CLIENT ?
+					 "authenticate.client" :
+					 "authenticate.server",
 					 "x509.truststore", NULL);
 	if (!pathname)
 		return false;
@@ -213,23 +217,29 @@ bool tlshd_config_get_client_truststore(char **bundle)
 	if (!*bundle)
 		return false;
 
-	tlshd_log_debug("Client x.509 truststore is %s", *bundle);
+	tlshd_log_debug("%s x.509 truststore is %s",
+		        peer_type == PEER_TYPE_CLIENT ? "Client" : "Server",
+			*bundle);
 	return true;
 }
 
 /**
- * tlshd_config_get_client_crl - Get CRL for ClientHello from .conf
+ * tlshd_config_get_crl - Get CRL for {Client,Server}Hello from .conf
+ * @peer_type: IN: peer type
  * @result: OUT: pathname to CRL
  *
  * Return values:
  *   %false: pathname not retrieved
  *   %true: pathname retrieved successfully; caller must free @result using free(3)
  */
-bool tlshd_config_get_client_crl(char **result)
+bool tlshd_config_get_crl(int peer_type, char **result)
 {
 	gchar *pathname;
 
-	pathname = g_key_file_get_string(tlshd_configuration, "authenticate.client",
+	pathname = g_key_file_get_string(tlshd_configuration,
+					 peer_type == PEER_TYPE_CLIENT ?
+					 "authenticate.client" :
+					 "authenticate.server",
 					 "x509.crl", NULL);
 	if (!pathname)
 		return false;
@@ -244,12 +254,15 @@ bool tlshd_config_get_client_crl(char **result)
 	if (!*result)
 		return false;
 
-	tlshd_log_debug("Client x.509 crl is %s", *result);
+	tlshd_log_debug("%s x.509 crl is %s",
+			peer_type == PEER_TYPE_CLIENT ? "Client" : "Server",
+			*result);
 	return true;
 }
 
 /**
- * tlshd_config_get_client_certs - Get certs for ClientHello from .conf
+ * tlshd_config_get_certs - Get certs for {Client,Server} Hello from .conf
+ * @peer_type: IN: peer type
  * @certs: OUT: in-memory certificates
  * @certs_len: IN: maximum number of certs to get, OUT: number of certs found
  *
@@ -257,15 +270,18 @@ bool tlshd_config_get_client_crl(char **result)
  *   %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_certs(int peer_type, gnutls_pcert_st *certs,
+			    unsigned int *certs_len)
 {
 	gnutls_datum_t data;
 	gchar *pathname;
 	int ret;
 
-	pathname = g_key_file_get_string(tlshd_configuration, "authenticate.client",
-					"x509.certificate", NULL);
+	pathname = g_key_file_get_string(tlshd_configuration,
+					 peer_type == PEER_TYPE_CLIENT ?
+					 "authenticate.client" :
+					 "authenticate.server",
+					 "x509.certificate", NULL);
 	if (!pathname)
 		return false;
 
@@ -285,181 +301,34 @@ bool tlshd_config_get_client_certs(gnutls_pcert_st *certs,
 		return false;
 	}
 
-	tlshd_log_debug("Retrieved %u x.509 client certificate(s) from %s",
-			*certs_len, pathname);
+	tlshd_log_debug("Retrieved %u x.509 %s certificate(s) from %s",
+			*certs_len,
+			peer_type == PEER_TYPE_CLIENT ? "client" : "server",
+			pathname);
 	g_free(pathname);
 	return true;
 }
 
 /**
- * tlshd_config_get_client_privkey - Get private key for ClientHello from .conf
+ * tlshd_config_get_privkey - Get private key for {Client,Server}Hello from .conf
+ * @peer_type: IN: peer type
  * @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_privkey(int peer_type, 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);
-	if (!pathname)
-		return false;
-
-	if (!tlshd_config_read_datum(pathname, &data, TLSHD_OWNER,
-				     TLSHD_PRIVKEY_MODE)) {
-		g_free(pathname);
-		return false;
-	}
-
-	ret = gnutls_privkey_init(privkey);
-	if (ret != GNUTLS_E_SUCCESS) {
-		tlshd_log_gnutls_error(ret);
-		free(data.data);
-		g_free(pathname);
-		return false;
-	}
-
-	/* Config file supports only PEM-encoded keys */
-	ret = gnutls_privkey_import_x509_raw(*privkey, &data,
-					     GNUTLS_X509_FMT_PEM, NULL, 0);
-	free(data.data);
-	if (ret != GNUTLS_E_SUCCESS) {
-		tlshd_log_gnutls_error(ret);
-		g_free(pathname);
-		return false;
-	}
-
-	tlshd_log_debug("Retrieved private key from %s", pathname);
-	g_free(pathname);
-	return true;
-}
-
-/**
- * tlshd_config_get_server_truststore - Get truststore for ServerHello from .conf
- * @bundle: OUT: pathname to truststore
- *
- * Return values:
- *   %false: pathname not retrieved
- *   %true: pathname retrieved successfully; caller must free @bundle using free(3)
- */
-bool tlshd_config_get_server_truststore(char **bundle)
-{
-	gchar *pathname;
-
-	pathname = g_key_file_get_string(tlshd_configuration, "authenticate.server",
-					 "x509.truststore", NULL);
-	if (!pathname)
-		return false;
-	if (access(pathname, F_OK)) {
-		tlshd_log_debug("tlshd cannot access \"%s\"", pathname);
-		g_free(pathname);
-		return false;
-	}
-
-	*bundle = strdup(pathname);
-	g_free(pathname);
-	if (!*bundle)
-		return false;
-
-	tlshd_log_debug("Server x.509 truststore is %s", *bundle);
-	return true;
-}
-
-/**
- * tlshd_config_get_server_crl - Get CRL for ServerHello from .conf
- * @result: OUT: pathname to CRL
- *
- * Return values:
- *   %false: pathname not retrieved
- *   %true: pathname retrieved successfully; caller must free @result using free(3)
- */
-bool tlshd_config_get_server_crl(char **result)
-{
-	gchar *pathname;
-
-	pathname = g_key_file_get_string(tlshd_configuration, "authenticate.server",
-					 "x509.crl", NULL);
-	if (!pathname)
-		return false;
-	if (access(pathname, F_OK)) {
-		tlshd_log_debug("tlshd cannot access \"%s\"", pathname);
-		g_free(pathname);
-		return false;
-	}
-
-	*result = strdup(pathname);
-	g_free(pathname);
-	if (!*result)
-		return false;
-
-	tlshd_log_debug("Server x.509 crl is %s", *result);
-	return true;
-}
-
-/**
- * tlshd_config_get_server_certs - Get certs for ServerHello from .conf
- * @certs: OUT: in-memory certificates
- * @certs_len: IN: maximum number of certs to get, OUT: number of certs found
- *
- * Return values:
- *   %true: certificate retrieved successfully
- *   %false: certificate not retrieved
- */
-bool tlshd_config_get_server_certs(gnutls_pcert_st *certs,
-				   unsigned int *certs_len)
-{
-	gnutls_datum_t data;
-	gchar *pathname;
-	int ret;
-
-	pathname = g_key_file_get_string(tlshd_configuration, "authenticate.server",
-					"x509.certificate", NULL);
-	if (!pathname)
-		return false;
-
-	if (!tlshd_config_read_datum(pathname, &data, TLSHD_OWNER,
-				     TLSHD_CERT_MODE)) {
-		g_free(pathname);
-		return false;
-	}
-
-	/* Config file supports only PEM-encoded certificates */
-	ret = gnutls_pcert_list_import_x509_raw(certs, certs_len, &data,
-						GNUTLS_X509_FMT_PEM, 0);
-	free(data.data);
-	if (ret != GNUTLS_E_SUCCESS) {
-		tlshd_log_gnutls_error(ret);
-		g_free(pathname);
-		return false;
-	}
-
-	tlshd_log_debug("Retrieved %u x.509 server certificate(s) from %s",
-			*certs_len, pathname);
-	g_free(pathname);
-	return true;
-}
-
-/**
- * tlshd_config_get_server_privkey - Get private key for ServerHello 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)
-{
-	gnutls_datum_t data;
-	gchar *pathname;
-	int ret;
-
-	pathname = g_key_file_get_string(tlshd_configuration, "authenticate.server",
-					"x509.private_key", NULL);
+	pathname = g_key_file_get_string(tlshd_configuration,
+					 peer_type == PEER_TYPE_CLIENT ?
+					 "authenticate.client" :
+					 "authenticate.server",
+					 "x509.private_key", NULL);
 	if (!pathname)
 		return false;
 
diff --git a/src/tlshd/server.c b/src/tlshd/server.c
index 44a91c4..efea387 100644
--- a/src/tlshd/server.c
+++ b/src/tlshd/server.c
@@ -52,8 +52,8 @@ static bool tlshd_x509_server_get_certs(struct tlshd_handshake_parms *parms)
 		return tlshd_keyring_get_certs(parms->x509_cert,
 					       tlshd_server_certs,
 					       &tlshd_server_certs_len);
-	return tlshd_config_get_server_certs(tlshd_server_certs,
-					     &tlshd_server_certs_len);
+	return tlshd_config_get_certs(PEER_TYPE_SERVER, tlshd_server_certs,
+				      &tlshd_server_certs_len);
 }
 
 static void tlshd_x509_server_put_certs(void)
@@ -69,7 +69,8 @@ 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);
+	return tlshd_config_get_privkey(PEER_TYPE_SERVER,
+					&tlshd_server_privkey);
 }
 
 static void tlshd_x509_server_put_privkey(void)
@@ -140,7 +141,7 @@ static int tlshd_server_get_truststore(gnutls_certificate_credentials_t cred)
 	char *pathname;
 	int ret;
 
-	if (tlshd_config_get_server_truststore(&pathname)) {
+	if (tlshd_config_get_truststore(PEER_TYPE_SERVER, &pathname)) {
 		ret = gnutls_certificate_set_x509_trust_file(cred, pathname,
 							     GNUTLS_X509_FMT_PEM);
 		free(pathname);
@@ -150,7 +151,7 @@ static int tlshd_server_get_truststore(gnutls_certificate_credentials_t cred)
 		return ret;
 	tlshd_log_debug("System trust: Loaded %d certificate(s).", ret);
 
-	if (tlshd_config_get_server_crl(&pathname)) {
+	if (tlshd_config_get_crl(PEER_TYPE_SERVER, &pathname)) {
 		ret = gnutls_certificate_set_x509_crl_file(cred, pathname,
 							   GNUTLS_X509_FMT_PEM);
 		free(pathname);
diff --git a/src/tlshd/tlshd.h b/src/tlshd/tlshd.h
index 2857804..6ba45ac 100644
--- a/src/tlshd/tlshd.h
+++ b/src/tlshd/tlshd.h
@@ -45,6 +45,11 @@ struct tlshd_handshake_parms {
 	unsigned int	session_status;
 };
 
+enum peer_type {
+	PEER_TYPE_CLIENT,
+	PEER_TYPE_SERVER,
+};
+
 /* client.c */
 extern void tlshd_tls13_clienthello_handshake(struct tlshd_handshake_parms *parms);
 extern void tlshd_quic_clienthello_handshake(struct tlshd_handshake_parms *parms);
@@ -52,16 +57,11 @@ extern void tlshd_quic_clienthello_handshake(struct tlshd_handshake_parms *parms
 /* config.c */
 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_server_truststore(char **bundle);
-bool tlshd_config_get_server_crl(char **result);
-bool tlshd_config_get_server_certs(gnutls_pcert_st *certs,
-				   unsigned int *certs_len);
-bool tlshd_config_get_server_privkey(gnutls_privkey_t *privkey);
+bool tlshd_config_get_truststore(int peer_type, char **bundle);
+bool tlshd_config_get_crl(int peer_type, char **result);
+bool tlshd_config_get_certs(int peer_type, gnutls_pcert_st *certs,
+			    unsigned int *certs_len);
+bool tlshd_config_get_privkey(int peer_type, 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] 12+ messages in thread

* [PATCH v2 2/4] tlshd: Fix priority string to allow PQC
  2025-09-11 21:28 [PATCH v2 0/4] tlshd: Allow the use of post-quantum cryptography Scott Mayhew
  2025-09-11 21:28 ` [PATCH v2 1/4] tlshd: deduplicate client and server config functions Scott Mayhew
@ 2025-09-11 21:28 ` Scott Mayhew
  2025-10-01  3:37   ` Alistair
  2025-09-11 21:28 ` [PATCH v2 3/4] tlshd: Server-side dual certificate support Scott Mayhew
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 12+ messages in thread
From: Scott Mayhew @ 2025-09-11 21:28 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 883256a..50381bf 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] 12+ messages in thread

* [PATCH v2 3/4] tlshd: Server-side dual certificate support
  2025-09-11 21:28 [PATCH v2 0/4] tlshd: Allow the use of post-quantum cryptography Scott Mayhew
  2025-09-11 21:28 ` [PATCH v2 1/4] tlshd: deduplicate client and server config functions Scott Mayhew
  2025-09-11 21:28 ` [PATCH v2 2/4] tlshd: Fix priority string to allow PQC Scott Mayhew
@ 2025-09-11 21:28 ` Scott Mayhew
  2025-09-11 21:28 ` [PATCH v2 4/4] tlshd: Client-side " Scott Mayhew
  2025-09-12 14:35 ` [PATCH v2 0/4] tlshd: Allow the use of post-quantum cryptography Chuck Lever
  4 siblings, 0 replies; 12+ messages in thread
From: Scott Mayhew @ 2025-09-11 21:28 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").

Note that we check to ensure that the PQ certificate is using a
post-quantum public-key algorithm (ML-DSA-44, ML-DSA-65, or ML-DSA-87),
and we store the algorithm value 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>
---
 configure.ac             |  12 ++++
 src/tlshd/client.c       |   6 +-
 src/tlshd/config.c       | 132 ++++++++++++++++++++++++++++++++++++---
 src/tlshd/server.c       |  65 ++++++++++++++++++-
 src/tlshd/tlshd.conf     |   2 +
 src/tlshd/tlshd.conf.man |  15 +++++
 src/tlshd/tlshd.h        |   7 ++-
 7 files changed, 225 insertions(+), 14 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/client.c b/src/tlshd/client.c
index c07ae29..257e835 100644
--- a/src/tlshd/client.c
+++ b/src/tlshd/client.c
@@ -143,8 +143,8 @@ 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_certs(PEER_TYPE_CLIENT, tlshd_certs,
-				      &tlshd_certs_len);
+	return tlshd_config_get_certs(PEER_TYPE_CLIENT, tlshd_certs, NULL,
+				      &tlshd_certs_len, NULL);
 }
 
 static void tlshd_x509_client_put_certs(void)
@@ -160,7 +160,7 @@ 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_privkey(PEER_TYPE_CLIENT, &tlshd_privkey);
+	return tlshd_config_get_privkey(PEER_TYPE_CLIENT, NULL, &tlshd_privkey);
 }
 
 static void tlshd_x509_client_put_privkey(void)
diff --git a/src/tlshd/config.c b/src/tlshd/config.c
index ff1f2a5..9a3b6b2 100644
--- a/src/tlshd/config.c
+++ b/src/tlshd/config.c
@@ -260,18 +260,66 @@ bool tlshd_config_get_crl(int peer_type, 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;
+}
+#else
+static bool tlshd_cert_check_pk_alg(__attribute__ ((unused)) gnutls_datum_t *data,
+				    __attribute__ ((unused)) gnutls_pk_algorithm_t *pkalg)
+{
+	tlshd_log_debug("%s: gnutls version does not have ML-DSA support",
+			__func__);
+	return false;
+}
+#endif /* HAVE_GNUTLS_MLDSA */
+
 /**
- * tlshd_config_get_certs - Get certs for {Client,Server} Hello from .conf
+ * __tlshd_config_get_certs - Helper for tlshd_config_get_certs()
  * @peer_type: IN: peer type
  * @certs: OUT: in-memory certificates
  * @certs_len: IN: maximum number of certs to get, OUT: number of certs found
+ * @pkgalg: IN: if non-NULL, indicates we want to retrieve the PQ cert,
+ *	 OUT: if non-NULL, store the PQ public-key alg that was used in the PQ cert
  *
  * Return values:
  *   %true: certificate retrieved successfully
  *   %false: certificate not retrieved
  */
-bool tlshd_config_get_certs(int peer_type, gnutls_pcert_st *certs,
-			    unsigned int *certs_len)
+static bool __tlshd_config_get_certs(int peer_type, gnutls_pcert_st *certs,
+				     unsigned int *certs_len,
+				     gnutls_pk_algorithm_t *pkalg)
 {
 	gnutls_datum_t data;
 	gchar *pathname;
@@ -281,7 +329,10 @@ bool tlshd_config_get_certs(int peer_type, gnutls_pcert_st *certs,
 					 peer_type == PEER_TYPE_CLIENT ?
 					 "authenticate.client" :
 					 "authenticate.server",
-					 "x509.certificate", NULL);
+					 pkalg != NULL ?
+					 "x509.pq.certificate" :
+					 "x509.certificate",
+					 NULL);
 	if (!pathname)
 		return false;
 
@@ -291,6 +342,15 @@ bool tlshd_config_get_certs(int peer_type, gnutls_pcert_st *certs,
 		return false;
 	}
 
+	if (pkalg && !tlshd_cert_check_pk_alg(&data, pkalg)) {
+		tlshd_log_debug("%s: %s not using a PQ public-key algorithm",
+				__func__, pathname);
+		free(data.data);
+		g_free(pathname);
+		*certs_len = 0;
+		return false;
+	}
+
 	/* Config file supports only PEM-encoded certificates */
 	ret = gnutls_pcert_list_import_x509_raw(certs, certs_len, &data,
 						GNUTLS_X509_FMT_PEM, 0);
@@ -310,15 +370,51 @@ bool tlshd_config_get_certs(int peer_type, gnutls_pcert_st *certs,
 }
 
 /**
- * tlshd_config_get_privkey - Get private key for {Client,Server}Hello from .conf
+ * tlshd_config_get_certs - Get certs for {Client,Server} Hello from .conf
+ * @peer_type: IN: peer type
+ * @certs: OUT: in-memory certificates
+ * @pq_certs_len: IN: maximum number of PQ certs to get, OUT: number of PQ certs found
+ * @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 PQ cert
+ *
+ * Retrieve the PQ cert(s) first, then the RSA cert(s).  Both are stored in the
+ * same list.  Note that @pq_certs_len is deducted from the available @certs_len
+ * and is also used to determine the offset to store the RSA cert(s) in the
+ * @certs array.
+ *
+ * Return values:
+ *   %true: certificate retrieved successfully
+ *   %false: certificate not retrieved
+ */
+bool tlshd_config_get_certs(int peer_type, gnutls_pcert_st *certs,
+			    unsigned int *pq_certs_len,
+			    unsigned int *certs_len,
+			    gnutls_pk_algorithm_t *pkalg)
+{
+	bool ret;
+
+	ret = __tlshd_config_get_certs(peer_type, certs, pq_certs_len, pkalg);
+
+	if (ret == true)
+		*certs_len -= *pq_certs_len;
+	else
+		*pq_certs_len = 0;
+
+	return __tlshd_config_get_certs(peer_type, certs + *pq_certs_len,
+					certs_len, NULL);
+}
+
+/**
+ * __tlshd_config_get_privkey - Helper for tlshd_config_get_privkey()
  * @peer_type: IN: peer type
  * @privkey: OUT: in-memory private key
+ * @pq: IN: if true, retrieve the PQ private key
  *
  * Return values:
  *   %true: private key retrieved successfully
  *   %false: private key not retrieved
  */
-bool tlshd_config_get_privkey(int peer_type, gnutls_privkey_t *privkey)
+static bool __tlshd_config_get_privkey(int peer_type, gnutls_privkey_t *privkey, bool pq)
 {
 	gnutls_datum_t data;
 	gchar *pathname;
@@ -328,7 +424,10 @@ bool tlshd_config_get_privkey(int peer_type, gnutls_privkey_t *privkey)
 					 peer_type == PEER_TYPE_CLIENT ?
 					 "authenticate.client" :
 					 "authenticate.server",
-					 "x509.private_key", NULL);
+					 pq == true ?
+					 "x509.pq.private_key" :
+					 "x509.private_key",
+					 NULL);
 	if (!pathname)
 		return false;
 
@@ -360,3 +459,22 @@ bool tlshd_config_get_privkey(int peer_type, gnutls_privkey_t *privkey)
 	g_free(pathname);
 	return true;
 }
+
+/**
+ * tlshd_config_get_privkey - Get private key for {Client,Server}Hello from .conf
+ * @peer_type: IN: peer type
+ * @pq_privkey: OUT: in-memory PQ private key
+ * @privkey: OUT: in-memory private key
+ *
+ * Retrieve the PQ private key first, then the RSA private key.
+ *
+ * Return values:
+ *   %true: private key retrieved successfully
+ *   %false: private key not retrieved
+ */
+bool tlshd_config_get_privkey(int peer_type, gnutls_privkey_t *pq_privkey,
+			      gnutls_privkey_t *privkey)
+{
+	__tlshd_config_get_privkey(peer_type, pq_privkey, true);
+	return __tlshd_config_get_privkey(peer_type, privkey, false);
+}
diff --git a/src/tlshd/server.c b/src/tlshd/server.c
index efea387..13b805c 100644
--- a/src/tlshd/server.c
+++ b/src/tlshd/server.c
@@ -42,9 +42,12 @@
 #include "tlshd.h"
 #include "netlink.h"
 
+static gnutls_privkey_t tlshd_server_pq_privkey;
 static gnutls_privkey_t tlshd_server_privkey;
+static unsigned int tlshd_server_pq_certs_len = TLSHD_MAX_CERTS;
 static unsigned int tlshd_server_certs_len = TLSHD_MAX_CERTS;
 static gnutls_pcert_st tlshd_server_certs[TLSHD_MAX_CERTS];
+static gnutls_pk_algorithm_t tlshd_server_pq_pkalg = GNUTLS_PK_UNKNOWN;
 
 static bool tlshd_x509_server_get_certs(struct tlshd_handshake_parms *parms)
 {
@@ -53,14 +56,16 @@ static bool tlshd_x509_server_get_certs(struct tlshd_handshake_parms *parms)
 					       tlshd_server_certs,
 					       &tlshd_server_certs_len);
 	return tlshd_config_get_certs(PEER_TYPE_SERVER, tlshd_server_certs,
-				      &tlshd_server_certs_len);
+				      &tlshd_server_pq_certs_len,
+				      &tlshd_server_certs_len,
+				      &tlshd_server_pq_pkalg);
 }
 
 static void tlshd_x509_server_put_certs(void)
 {
 	unsigned int i;
 
-	for (i = 0; i < tlshd_server_certs_len; i++)
+	for (i = 0; i < TLSHD_MAX_CERTS; i++)
 		gnutls_pcert_deinit(&tlshd_server_certs[i]);
 }
 
@@ -70,11 +75,13 @@ static bool tlshd_x509_server_get_privkey(struct tlshd_handshake_parms *parms)
 		return tlshd_keyring_get_privkey(parms->x509_privkey,
 						 &tlshd_server_privkey);
 	return tlshd_config_get_privkey(PEER_TYPE_SERVER,
+					&tlshd_server_pq_privkey,
 					&tlshd_server_privkey);
 }
 
 static void tlshd_x509_server_put_privkey(void)
 {
+	gnutls_privkey_deinit(tlshd_server_pq_privkey);
 	gnutls_privkey_deinit(tlshd_server_privkey);
 }
 
@@ -123,6 +130,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);
 
@@ -130,9 +142,58 @@ tlshd_x509_retrieve_key_cb(gnutls_session_t session,
 	if (type != GNUTLS_CRT_X509)
 		return -1;
 
+#ifdef HAVE_GNUTLS_MLDSA
+	/*
+ 	 * 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_log_debug("%s: Selecting x509.pq.certificate from conf file", __func__);
+		*pcert_length = tlshd_server_pq_certs_len;
+		*pcert = tlshd_server_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 + tlshd_server_pq_certs_len;
+		*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..575d88b 100644
--- a/src/tlshd/tlshd.conf.man
+++ b/src/tlshd/tlshd.conf.man
@@ -125,6 +125,21 @@ 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.
+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
+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 6ba45ac..664de67 100644
--- a/src/tlshd/tlshd.h
+++ b/src/tlshd/tlshd.h
@@ -60,8 +60,11 @@ void tlshd_config_shutdown(void);
 bool tlshd_config_get_truststore(int peer_type, char **bundle);
 bool tlshd_config_get_crl(int peer_type, char **result);
 bool tlshd_config_get_certs(int peer_type, gnutls_pcert_st *certs,
-			    unsigned int *certs_len);
-bool tlshd_config_get_privkey(int peer_type, gnutls_privkey_t *privkey);
+			    unsigned int *pq_certs_len,
+			    unsigned int *certs_len,
+			    gnutls_pk_algorithm_t *pkalg);
+bool tlshd_config_get_privkey(int peer_type, gnutls_privkey_t *pq_privkey,
+			      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] 12+ messages in thread

* [PATCH v2 4/4] tlshd: Client-side dual certificate support
  2025-09-11 21:28 [PATCH v2 0/4] tlshd: Allow the use of post-quantum cryptography Scott Mayhew
                   ` (2 preceding siblings ...)
  2025-09-11 21:28 ` [PATCH v2 3/4] tlshd: Server-side dual certificate support Scott Mayhew
@ 2025-09-11 21:28 ` Scott Mayhew
  2025-09-12 14:35 ` [PATCH v2 0/4] tlshd: Allow the use of post-quantum cryptography Chuck Lever
  4 siblings, 0 replies; 12+ messages in thread
From: Scott Mayhew @ 2025-09-11 21:28 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   | 45 ++++++++++++++++++++++++++++++++++++--------
 src/tlshd/tlshd.conf |  2 ++
 2 files changed, 39 insertions(+), 8 deletions(-)

diff --git a/src/tlshd/client.c b/src/tlshd/client.c
index 257e835..ad9a793 100644
--- a/src/tlshd/client.c
+++ b/src/tlshd/client.c
@@ -134,17 +134,21 @@ out_free_creds:
 	gnutls_certificate_free_credentials(xcred);
 }
 
+static gnutls_privkey_t tlshd_pq_privkey;
 static gnutls_privkey_t tlshd_privkey;
+static unsigned int tlshd_pq_certs_len = TLSHD_MAX_CERTS;
 static unsigned int tlshd_certs_len = TLSHD_MAX_CERTS;
 static gnutls_pcert_st tlshd_certs[TLSHD_MAX_CERTS];
+static gnutls_pk_algorithm_t tlshd_pq_pkalg = GNUTLS_PK_UNKNOWN;
 
 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_certs(PEER_TYPE_CLIENT, tlshd_certs, NULL,
-				      &tlshd_certs_len, NULL);
+	return tlshd_config_get_certs(PEER_TYPE_CLIENT, tlshd_certs,
+				      &tlshd_pq_certs_len, &tlshd_certs_len,
+				      &tlshd_pq_pkalg);
 }
 
 static void tlshd_x509_client_put_certs(void)
@@ -160,12 +164,14 @@ 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_privkey(PEER_TYPE_CLIENT, NULL, &tlshd_privkey);
+	return tlshd_config_get_privkey(PEER_TYPE_CLIENT, &tlshd_pq_privkey,
+					&tlshd_privkey);
 }
 
 static void tlshd_x509_client_put_privkey(void)
 {
 	gnutls_privkey_deinit(tlshd_privkey);
+	gnutls_privkey_deinit(tlshd_pq_privkey);
 }
 
 static void tlshd_x509_log_issuers(const gnutls_datum_t *req_ca_rdn, int nreqs)
@@ -206,13 +212,15 @@ 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)
 {
 	gnutls_certificate_type_t type;
+	bool use_pq_cert = false;
+	int i;
 
 	tlshd_x509_log_issuers(req_ca_rdn, nreqs);
 
@@ -220,9 +228,30 @@ tlshd_x509_retrieve_key_cb(gnutls_session_t session,
 	if (type != GNUTLS_CRT_X509)
 		return -1;
 
-	*pcert_length = tlshd_certs_len;
-	*pcert = tlshd_certs;
-	*privkey = tlshd_privkey;
+	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_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 + tlshd_pq_certs_len;
+		*privkey = tlshd_privkey;
+	}
 	return 0;
 }
 
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>
-- 
2.50.1


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

* Re: [PATCH v2 0/4] tlshd: Allow the use of post-quantum cryptography
  2025-09-11 21:28 [PATCH v2 0/4] tlshd: Allow the use of post-quantum cryptography Scott Mayhew
                   ` (3 preceding siblings ...)
  2025-09-11 21:28 ` [PATCH v2 4/4] tlshd: Client-side " Scott Mayhew
@ 2025-09-12 14:35 ` Chuck Lever
  4 siblings, 0 replies; 12+ messages in thread
From: Chuck Lever @ 2025-09-12 14:35 UTC (permalink / raw)
  To: Scott Mayhew; +Cc: kernel-tls-handshake

On 9/11/25 5:28 PM, Scott Mayhew wrote:
> These patches allow tlshd to use post-quantum cryptography.  The first
> patch does a bit of refactoring to reduce some code duplication.  The 
> second fixes the priority string and allows the PQ algorithms to be
> used.  The other two 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.
> 
> Changes since v1:
> - Refactoring to allow the client and server code to use the same
>   tlshd_config_get_* functions
> - Removed a lot of "#ifdef HAVE_GNUTLS_MLDSA" statements (I'm pretty
>   sure the handful that are left are necessary)
> - Store both the PQ and RSA certs in the same array.  The PQ certs (if
>   present) will be first, followed by the RSA certs.  Note that I didn't
>   increase TLSHD_MAX_CERTS though.
> 
> For those who prefer a web UI, these patches are also available in this
> branch:
> https://github.com/scottmayhew/ktls-utils/tree/pqc

Hi Scott, these look close enough to merge IMO. Please open a pull
request against oracle/ktls-utils.


> 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
> 
> Scott Mayhew (4):
>   tlshd: deduplicate client and server config functions
>   tlshd: Fix priority string to allow PQC
>   tlshd: Server-side dual certificate support
>   tlshd: Client-side dual certificate support
> 
>  configure.ac             |  12 ++
>  src/tlshd/client.c       |  48 +++++--
>  src/tlshd/config.c       | 281 +++++++++++++++++++--------------------
>  src/tlshd/ktls.c         |   2 +-
>  src/tlshd/server.c       |  74 ++++++++++-
>  src/tlshd/tlshd.conf     |   4 +
>  src/tlshd/tlshd.conf.man |  15 +++
>  src/tlshd/tlshd.h        |  23 ++--
>  8 files changed, 286 insertions(+), 173 deletions(-)
> 


-- 
Chuck Lever

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

* Re: [PATCH v2 2/4] tlshd: Fix priority string to allow PQC
  2025-09-11 21:28 ` [PATCH v2 2/4] tlshd: Fix priority string to allow PQC Scott Mayhew
@ 2025-10-01  3:37   ` Alistair
  2025-10-01 10:58     ` Scott Mayhew
  2025-10-01 23:35     ` [PATCH] tlshd: fix priority cache initialization Scott Mayhew
  0 siblings, 2 replies; 12+ messages in thread
From: Alistair @ 2025-10-01  3:37 UTC (permalink / raw)
  To: Scott Mayhew, Chuck Lever; +Cc: kernel-tls-handshake

On Fri, 12 Sep 2025, at 7:28 AM, 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 883256a..50381bf 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");

This change is breaking traditional handshakes for me as _gnutls_resolve_priorities() fails to resolve a priority.

I'm not sure if it's a system config issue though, is anyone else seeing this?

Alistair

> if (!pstring)
> return -ENOMEM;
>  
> -- 
> 2.50.1
> 
> 
> 

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

* Re: [PATCH v2 2/4] tlshd: Fix priority string to allow PQC
  2025-10-01  3:37   ` Alistair
@ 2025-10-01 10:58     ` Scott Mayhew
  2025-10-01 23:35     ` [PATCH] tlshd: fix priority cache initialization Scott Mayhew
  1 sibling, 0 replies; 12+ messages in thread
From: Scott Mayhew @ 2025-10-01 10:58 UTC (permalink / raw)
  To: Alistair; +Cc: Chuck Lever, kernel-tls-handshake

On Wed, 01 Oct 2025, Alistair wrote:

> On Fri, 12 Sep 2025, at 7:28 AM, 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 883256a..50381bf 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");
> 
> This change is breaking traditional handshakes for me as _gnutls_resolve_priorities() fails to resolve a priority.
> 
> I'm not sure if it's a system config issue though, is anyone else seeing this?

What output do you get when you run these commands?

gnutls-cli --priority @SYSTEM -l
gnutls-cli --list-config

-Scott
> 
> Alistair
> 
> > if (!pstring)
> > return -ENOMEM;
> >  
> > -- 
> > 2.50.1
> > 
> > 
> > 
> 


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

* [PATCH] tlshd: fix priority cache initialization
  2025-10-01  3:37   ` Alistair
  2025-10-01 10:58     ` Scott Mayhew
@ 2025-10-01 23:35     ` Scott Mayhew
  2025-10-02  0:22       ` Alistair Francis
  2025-10-02  5:28       ` Hannes Reinecke
  1 sibling, 2 replies; 12+ messages in thread
From: Scott Mayhew @ 2025-10-01 23:35 UTC (permalink / raw)
  To: alistair; +Cc: chuck.lever, kernel-tls-handshake

Commit 9253f9d added the use of the @SYSTEM keyword as the initial
keyword in the priority string used by tlshd.  Unfortunately @SYSTEM
doesn't appear to work on systems that do not have a system-wide
library configuration set up.

Instead of trying to pick an initial keyword that will work on all
systems, let's instead use gnutls_priority_init2() with the
GNUTLS_PRIORITY_INIT_DEF_APPEND flag instead.  That will *append* our
priority string to the default options.

Fixes: 9253f9d ("tlshd: Fix priority string to allow PQC")
Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---

Alistair, can you try this patch and see if it fixes your issue?

 src/tlshd/ktls.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/src/tlshd/ktls.c b/src/tlshd/ktls.c
index 50381bf..bc75313 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("@SYSTEM:-COMP-ALL");
+	pstring = strdup("-COMP-ALL");
 	if (!pstring)
 		return -ENOMEM;
 
@@ -425,7 +425,8 @@ static int tlshd_gnutls_priority_init_list(const unsigned int *ciphers,
 	}
 
 	tlshd_log_debug("x.509 priority string: %s\n", pstring);
-	ret = gnutls_priority_init(&tlshd_gnutls_priority_x509, pstring, &errpos);
+	ret = gnutls_priority_init2(&tlshd_gnutls_priority_x509, pstring, &errpos,
+				    GNUTLS_PRIORITY_INIT_DEF_APPEND);
 	if (ret != GNUTLS_E_SUCCESS) {
 		free(pstring_sha256);
 		free(pstring_sha384);
@@ -442,7 +443,8 @@ static int tlshd_gnutls_priority_init_list(const unsigned int *ciphers,
 	}
 
 	tlshd_log_debug("PSK priority string: %s\n", pstring);
-	ret = gnutls_priority_init(&tlshd_gnutls_priority_psk, pstring, &errpos);
+	ret = gnutls_priority_init2(&tlshd_gnutls_priority_psk, pstring, &errpos,
+				    GNUTLS_PRIORITY_INIT_DEF_APPEND);
 	if (ret != GNUTLS_E_SUCCESS) {
 		free(pstring_sha256);
 		free(pstring_sha384);
@@ -461,8 +463,9 @@ static int tlshd_gnutls_priority_init_list(const unsigned int *ciphers,
 	}
 
 	tlshd_log_debug("PSK SHA256 priority string: %s\n", pstring);
-	ret = gnutls_priority_init(&tlshd_gnutls_priority_psk_sha256,
-				   pstring, &errpos);
+	ret = gnutls_priority_init2(&tlshd_gnutls_priority_psk_sha256,
+				   pstring, &errpos,
+				   GNUTLS_PRIORITY_INIT_DEF_APPEND);
 	if (ret != GNUTLS_E_SUCCESS) {
 		free(pstring);
 		free(pstring_sha384);
@@ -482,8 +485,9 @@ static int tlshd_gnutls_priority_init_list(const unsigned int *ciphers,
 	}
 
 	tlshd_log_debug("PSK SHA384 priority string: %s\n", pstring);
-	ret = gnutls_priority_init(&tlshd_gnutls_priority_psk_sha384,
-				   pstring, &errpos);
+	ret = gnutls_priority_init2(&tlshd_gnutls_priority_psk_sha384,
+				   pstring, &errpos,
+				   GNUTLS_PRIORITY_INIT_DEF_APPEND);
 	if (ret != GNUTLS_E_SUCCESS) {
 		free(pstring);
 		gnutls_priority_deinit(tlshd_gnutls_priority_psk_sha256);
-- 
2.51.0


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

* Re: [PATCH] tlshd: fix priority cache initialization
  2025-10-01 23:35     ` [PATCH] tlshd: fix priority cache initialization Scott Mayhew
@ 2025-10-02  0:22       ` Alistair Francis
  2025-10-02  5:28       ` Hannes Reinecke
  1 sibling, 0 replies; 12+ messages in thread
From: Alistair Francis @ 2025-10-02  0:22 UTC (permalink / raw)
  To: Scott Mayhew; +Cc: alistair, chuck.lever, kernel-tls-handshake

On Thu, Oct 2, 2025 at 9:38 AM Scott Mayhew <smayhew@redhat.com> wrote:
>
> Commit 9253f9d added the use of the @SYSTEM keyword as the initial
> keyword in the priority string used by tlshd.  Unfortunately @SYSTEM
> doesn't appear to work on systems that do not have a system-wide
> library configuration set up.
>
> Instead of trying to pick an initial keyword that will work on all
> systems, let's instead use gnutls_priority_init2() with the
> GNUTLS_PRIORITY_INIT_DEF_APPEND flag instead.  That will *append* our
> priority string to the default options.
>
> Fixes: 9253f9d ("tlshd: Fix priority string to allow PQC")
> Signed-off-by: Scott Mayhew <smayhew@redhat.com>

Awesome! Thanks for fixing this

Tested-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

> ---
>
> Alistair, can you try this patch and see if it fixes your issue?

Yep, fixes my issue

Alistair

>
>  src/tlshd/ktls.c | 18 +++++++++++-------
>  1 file changed, 11 insertions(+), 7 deletions(-)
>
> diff --git a/src/tlshd/ktls.c b/src/tlshd/ktls.c
> index 50381bf..bc75313 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("@SYSTEM:-COMP-ALL");
> +       pstring = strdup("-COMP-ALL");
>         if (!pstring)
>                 return -ENOMEM;
>
> @@ -425,7 +425,8 @@ static int tlshd_gnutls_priority_init_list(const unsigned int *ciphers,
>         }
>
>         tlshd_log_debug("x.509 priority string: %s\n", pstring);
> -       ret = gnutls_priority_init(&tlshd_gnutls_priority_x509, pstring, &errpos);
> +       ret = gnutls_priority_init2(&tlshd_gnutls_priority_x509, pstring, &errpos,
> +                                   GNUTLS_PRIORITY_INIT_DEF_APPEND);
>         if (ret != GNUTLS_E_SUCCESS) {
>                 free(pstring_sha256);
>                 free(pstring_sha384);
> @@ -442,7 +443,8 @@ static int tlshd_gnutls_priority_init_list(const unsigned int *ciphers,
>         }
>
>         tlshd_log_debug("PSK priority string: %s\n", pstring);
> -       ret = gnutls_priority_init(&tlshd_gnutls_priority_psk, pstring, &errpos);
> +       ret = gnutls_priority_init2(&tlshd_gnutls_priority_psk, pstring, &errpos,
> +                                   GNUTLS_PRIORITY_INIT_DEF_APPEND);
>         if (ret != GNUTLS_E_SUCCESS) {
>                 free(pstring_sha256);
>                 free(pstring_sha384);
> @@ -461,8 +463,9 @@ static int tlshd_gnutls_priority_init_list(const unsigned int *ciphers,
>         }
>
>         tlshd_log_debug("PSK SHA256 priority string: %s\n", pstring);
> -       ret = gnutls_priority_init(&tlshd_gnutls_priority_psk_sha256,
> -                                  pstring, &errpos);
> +       ret = gnutls_priority_init2(&tlshd_gnutls_priority_psk_sha256,
> +                                  pstring, &errpos,
> +                                  GNUTLS_PRIORITY_INIT_DEF_APPEND);
>         if (ret != GNUTLS_E_SUCCESS) {
>                 free(pstring);
>                 free(pstring_sha384);
> @@ -482,8 +485,9 @@ static int tlshd_gnutls_priority_init_list(const unsigned int *ciphers,
>         }
>
>         tlshd_log_debug("PSK SHA384 priority string: %s\n", pstring);
> -       ret = gnutls_priority_init(&tlshd_gnutls_priority_psk_sha384,
> -                                  pstring, &errpos);
> +       ret = gnutls_priority_init2(&tlshd_gnutls_priority_psk_sha384,
> +                                  pstring, &errpos,
> +                                  GNUTLS_PRIORITY_INIT_DEF_APPEND);
>         if (ret != GNUTLS_E_SUCCESS) {
>                 free(pstring);
>                 gnutls_priority_deinit(tlshd_gnutls_priority_psk_sha256);
> --
> 2.51.0
>
>

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

* Re: [PATCH] tlshd: fix priority cache initialization
  2025-10-01 23:35     ` [PATCH] tlshd: fix priority cache initialization Scott Mayhew
  2025-10-02  0:22       ` Alistair Francis
@ 2025-10-02  5:28       ` Hannes Reinecke
  2025-10-02 18:50         ` Chuck Lever
  1 sibling, 1 reply; 12+ messages in thread
From: Hannes Reinecke @ 2025-10-02  5:28 UTC (permalink / raw)
  To: Scott Mayhew, alistair; +Cc: chuck.lever, kernel-tls-handshake

On 10/2/25 01:35, Scott Mayhew wrote:
> Commit 9253f9d added the use of the @SYSTEM keyword as the initial
> keyword in the priority string used by tlshd.  Unfortunately @SYSTEM
> doesn't appear to work on systems that do not have a system-wide
> library configuration set up.
> 
> Instead of trying to pick an initial keyword that will work on all
> systems, let's instead use gnutls_priority_init2() with the
> GNUTLS_PRIORITY_INIT_DEF_APPEND flag instead.  That will *append* our
> priority string to the default options.
> 
> Fixes: 9253f9d ("tlshd: Fix priority string to allow PQC")
> Signed-off-by: Scott Mayhew <smayhew@redhat.com>
> ---
> 
> Alistair, can you try this patch and see if it fixes your issue?
> 
>   src/tlshd/ktls.c | 18 +++++++++++-------
>   1 file changed, 11 insertions(+), 7 deletions(-)
> 
Thanks for doing this. Figuring out the init strings had been a major
pain, so I wasn't that happy with the initial patch.

Reviewed-by: Hannes Reinecke <hare@suse.de>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.de                                +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

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

* Re: [PATCH] tlshd: fix priority cache initialization
  2025-10-02  5:28       ` Hannes Reinecke
@ 2025-10-02 18:50         ` Chuck Lever
  0 siblings, 0 replies; 12+ messages in thread
From: Chuck Lever @ 2025-10-02 18:50 UTC (permalink / raw)
  To: Hannes Reinecke, Scott Mayhew, alistair; +Cc: kernel-tls-handshake

On 10/2/25 1:28 AM, Hannes Reinecke wrote:
> On 10/2/25 01:35, Scott Mayhew wrote:
>> Commit 9253f9d added the use of the @SYSTEM keyword as the initial
>> keyword in the priority string used by tlshd.  Unfortunately @SYSTEM
>> doesn't appear to work on systems that do not have a system-wide
>> library configuration set up.
>>
>> Instead of trying to pick an initial keyword that will work on all
>> systems, let's instead use gnutls_priority_init2() with the
>> GNUTLS_PRIORITY_INIT_DEF_APPEND flag instead.  That will *append* our
>> priority string to the default options.
>>
>> Fixes: 9253f9d ("tlshd: Fix priority string to allow PQC")
>> Signed-off-by: Scott Mayhew <smayhew@redhat.com>
>> ---
>>
>> Alistair, can you try this patch and see if it fixes your issue?
>>
>>   src/tlshd/ktls.c | 18 +++++++++++-------
>>   1 file changed, 11 insertions(+), 7 deletions(-)
>>
> Thanks for doing this. Figuring out the init strings had been a major
> pain, so I wasn't that happy with the initial patch.
> 
> Reviewed-by: Hannes Reinecke <hare@suse.de>

Thanks, folks. I will try to get this merged this afternoon.


-- 
Chuck Lever

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

end of thread, other threads:[~2025-10-02 18:50 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-11 21:28 [PATCH v2 0/4] tlshd: Allow the use of post-quantum cryptography Scott Mayhew
2025-09-11 21:28 ` [PATCH v2 1/4] tlshd: deduplicate client and server config functions Scott Mayhew
2025-09-11 21:28 ` [PATCH v2 2/4] tlshd: Fix priority string to allow PQC Scott Mayhew
2025-10-01  3:37   ` Alistair
2025-10-01 10:58     ` Scott Mayhew
2025-10-01 23:35     ` [PATCH] tlshd: fix priority cache initialization Scott Mayhew
2025-10-02  0:22       ` Alistair Francis
2025-10-02  5:28       ` Hannes Reinecke
2025-10-02 18:50         ` Chuck Lever
2025-09-11 21:28 ` [PATCH v2 3/4] tlshd: Server-side dual certificate support Scott Mayhew
2025-09-11 21:28 ` [PATCH v2 4/4] tlshd: Client-side " Scott Mayhew
2025-09-12 14:35 ` [PATCH v2 0/4] tlshd: Allow the use of post-quantum cryptography Chuck Lever

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.