* [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* 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
* [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