Compare commits

...

No commits in common. "c9" and "c10s" have entirely different histories.
c9 ... c10s

17 changed files with 1504 additions and 17 deletions

1
.fmf/version Normal file
View File

@ -0,0 +1 @@
1

4
.gitignore vendored
View File

@ -1 +1,3 @@
SOURCES/ktls-utils-0.11.tar.gz
/ktls-utils-0.10.tar.gz
/ktls-utils-0.11.tar.gz
/ktls-utils-1.2.1.tar.gz

View File

@ -1 +0,0 @@
9dae5134b7af7ebb14e518f9f4013a92bb44165e SOURCES/ktls-utils-0.11.tar.gz

14
changelog Normal file
View File

@ -0,0 +1,14 @@
* Thu Jan 25 2024 Fedora Release Engineering <releng@fedoraproject.org> - 0.10-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Sun Jan 21 2024 Fedora Release Engineering <releng@fedoraproject.org> - 0.10-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Sat Oct 07 2023 Steve Dickson <steved@redhat.com> - 0.10-1
- Updated to the latest upstream release: 0.10
* Thu Jul 20 2023 Fedora Release Engineering <releng@fedoraproject.org> - 0.9^20230627.g52ac9ff05a5e-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
* Tue Jun 27 2023 Jeff Layton <jlayton@kernel.org> - 0.9^20230627.g52ac9ff05a5e-1
- Initial import (fedora#2182151)

6
gating.yaml Normal file
View File

@ -0,0 +1,6 @@
--- !Policy
product_versions:
- rhel-10
decision_context: osci_compose_gate
rules:
- !PassingTestCaseRule {test_case_name: osci.brew-build.tier0.functional}

View File

@ -0,0 +1,44 @@
From b52ca7c0a9c167340950a10d8dc56be1b95f5c40 Mon Sep 17 00:00:00 2001
From: Chuck Lever <chuck.lever@oracle.com>
Date: Tue, 23 Sep 2025 19:30:16 -0400
Subject: [PATCH] tlshd: Clean up logic in tlshd_start_tls_handshake()
gnutls_handshake() is supposed to return only a GNUTLS_E value, and
the session_status field is supposed to contain only a positive
errno.
GNUTLS_E_PREMATURE_TERMINATION is -110. It turns out that on x86,
-ETIMEDOUT is also -110. Make sure the correct symbolic constants
and auditing functions are utilized.
Fixes: b010190cfed2 ("tlshd: Pass ETIMEDOUT from gnutls to kernel")
Reviewed-by: Benjamin Coddington <bcodding@redhat.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
src/tlshd/handshake.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/tlshd/handshake.c b/src/tlshd/handshake.c
index 5a28939..f688932 100644
--- a/src/tlshd/handshake.c
+++ b/src/tlshd/handshake.c
@@ -97,12 +97,12 @@ void tlshd_start_tls_handshake(gnutls_session_t session,
case GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR:
tlshd_log_cert_verification_error(session);
break;
- case -ETIMEDOUT:
- tlshd_log_gnutls_error(ret);
- parms->session_status = -ret;
+ case GNUTLS_E_PREMATURE_TERMINATION:
+ tlshd_log_error("Handshake timeout, retrying");
+ parms->session_status = ETIMEDOUT;
break;
default:
- tlshd_log_notice("tlshd_start_tls_handshake unhandled error %d, returning EACCES\n", ret);
+ tlshd_log_gnutls_error(ret);
}
return;
}
--
2.52.0

View File

@ -0,0 +1,135 @@
From facd084e43fc493ae8fbaca00cb65925ae30d0e9 Mon Sep 17 00:00:00 2001
From: Scott Mayhew <smayhew@redhat.com>
Date: Wed, 10 Sep 2025 21:00:09 -0400
Subject: [PATCH 4/4] tlshd: Client-side dual certificate support
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.51.0

View File

@ -0,0 +1,39 @@
From 9253f9df5ff986bddba38b8146ba6e650e7ebdd9 Mon Sep 17 00:00:00 2001
From: Scott Mayhew <smayhew@redhat.com>
Date: Wed, 10 Sep 2025 17:02:16 -0400
Subject: [PATCH 2/4] tlshd: Fix priority string to allow PQC
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.51.0

View File

@ -0,0 +1,57 @@
From 9e79a86b85748ba4888da49652986b09beac2459 Mon Sep 17 00:00:00 2001
From: Chuck Lever <chuck.lever@oracle.com>
Date: Thu, 5 Feb 2026 14:40:28 -0500
Subject: [PATCH] tlshd: Fix session leak on error paths in x509 server
handshake
Conflicts: src/tlshd/server.c - context difference in
tlshd_tls13_server_x509_handshake() because RHEL10 doesn't have
f11519a ("tlshd: Match ingress certificates with defined TLS session
tags")
After gnutls_init() succeeds, the error paths for gnutls_credentials_set()
and tlshd_gnutls_priority_set() failures jump to out_free_certs without
calling gnutls_deinit(session), leaking the session object.
Introduce an out_deinit_session label so all post-init error paths
properly release the session before cleaning up certificates and
credentials.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
src/tlshd/server.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/tlshd/server.c b/src/tlshd/server.c
index 4850210..3bfcca3 100644
--- a/src/tlshd/server.c
+++ b/src/tlshd/server.c
@@ -424,7 +424,7 @@ static void tlshd_tls13_server_x509_handshake(struct tlshd_handshake_parms *parm
ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
if (ret != GNUTLS_E_SUCCESS) {
tlshd_log_gnutls_error(ret);
- goto out_free_certs;
+ goto out_deinit_session;
}
gnutls_certificate_set_verify_function(xcred,
tlshd_tls13_server_x509_verify_function);
@@ -433,7 +433,7 @@ static void tlshd_tls13_server_x509_handshake(struct tlshd_handshake_parms *parm
ret = tlshd_gnutls_priority_set(session, parms, 0);
if (ret) {
tlshd_log_gnutls_error(ret);
- goto out_free_certs;
+ goto out_deinit_session;
}
tlshd_start_tls_handshake(session, parms);
@@ -373,6 +373,7 @@ static void tlshd_tls13_server_x509_hand
}
}
+out_deinit_session:
gnutls_deinit(session);
out_free_certs:
--
2.52.0

View File

@ -0,0 +1,185 @@
From a58a3600f35c16e435cdda476fe7ca0554a0a466 Mon Sep 17 00:00:00 2001
From: Scott Mayhew <smayhew@redhat.com>
Date: Thu, 5 Feb 2026 12:28:43 -0500
Subject: [PATCH] tlshd: Send fatal alert to client when there are server
config issues
Conflicts: src/tlshd/log.c - context difference because RHEL10 doesn't
have ff28f1f ("tlshd: Translate kernel-style Doxygen comments in
src/tlshd/log.c")
Currently if a client attempts an x.509 handshake and the server is
misconfigured (no certificates, no private keys, etc), the server simply
closes the connection. Prior to b010190 ("tlshd: Pass ETIMEDOUT from
gnutls to kernel"), this would result in a quick failure on the client.
Now the client keeps retrying until the mount program times out, which
takes several minutes.
A misconfigured server isn't a self-correcting problem, so send a fatal
alert to the client when this occurs so the client stops retrying
immediately. This requires some minor refactoring of
tlshd_tls13_server_x509_handshake() so that the session is initialized
before attempting to load the certs and keys (otherwise it is not
possible to send an alert). Also log an error message to help the
admin take corrective action.
Finally add some logging when an alert is received during the handshake.
Following suit with handshake completions, alerts will only be logged if
debug logging is enabled.
Signed-off-by: Scott Mayhew <smayhew@redhat.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
src/tlshd/handshake.c | 4 ++++
src/tlshd/log.c | 15 ++++++++++++
src/tlshd/server.c | 55 ++++++++++++++++++++++++-------------------
src/tlshd/tlshd.h | 1 +
4 files changed, 51 insertions(+), 24 deletions(-)
diff --git a/src/tlshd/handshake.c b/src/tlshd/handshake.c
index e78f78f..511a369 100644
--- a/src/tlshd/handshake.c
+++ b/src/tlshd/handshake.c
@@ -115,6 +115,10 @@ void tlshd_start_tls_handshake(gnutls_session_t session,
tlshd_log_error("Handshake timeout, retrying");
parms->session_status = ETIMEDOUT;
break;
+ case GNUTLS_E_WARNING_ALERT_RECEIVED:
+ case GNUTLS_E_FATAL_ALERT_RECEIVED:
+ tlshd_log_alert(session);
+ break;
default:
tlshd_log_gnutls_error(ret);
}
diff --git a/src/tlshd/log.c b/src/tlshd/log.c
index b70d4af..a890b60 100644
--- a/src/tlshd/log.c
+++ b/src/tlshd/log.c
@@ -178,6 +178,21 @@ void tlshd_log_cert_verification_error(g
}
/**
+ * @brief Report a TLS alert
+ * @param[in] session Controlling GnuTLS session
+ */
+void tlshd_log_alert(gnutls_session_t session)
+{
+ gnutls_alert_description_t alert;
+
+ if (!tlshd_debug)
+ return;
+
+ alert = gnutls_alert_get(session);
+ tlshd_log_notice("Received alert: %s", gnutls_alert_get_name(alert));
+}
+
+/**
* tlshd_log_gnutls_error - Emit "library call failed" notification
* @error: GnuTLS error code to log
*
diff --git a/src/tlshd/server.c b/src/tlshd/server.c
index 3bfcca3..8e0f192 100644
--- a/src/tlshd/server.c
+++ b/src/tlshd/server.c
@@ -397,29 +397,46 @@ static void tlshd_tls13_server_x509_handshake(struct tlshd_handshake_parms *parm
gnutls_session_t session;
int ret;
- ret = gnutls_certificate_allocate_credentials(&xcred);
+ ret = gnutls_init(&session, GNUTLS_SERVER);
if (ret != GNUTLS_E_SUCCESS) {
tlshd_log_gnutls_error(ret);
return;
}
- ret = tlshd_server_get_truststore(xcred);
- if (ret != GNUTLS_E_SUCCESS)
- goto out_free_creds;
+ gnutls_transport_set_int(session, parms->sockfd);
+ gnutls_session_set_ptr(session, parms);
- if (!tlshd_x509_server_get_certs(parms))
- goto out_free_creds;
- if (!tlshd_x509_server_get_privkey(parms))
- goto out_free_certs;
- gnutls_certificate_set_retrieve_function2(xcred,
- tlshd_x509_retrieve_key_cb);
+ ret = tlshd_gnutls_priority_set(session, parms, 0);
+ if (ret) {
+ tlshd_log_gnutls_error(ret);
+ gnutls_deinit(session);
+ return;
+ }
- ret = gnutls_init(&session, GNUTLS_SERVER);
+ ret = gnutls_certificate_allocate_credentials(&xcred);
if (ret != GNUTLS_E_SUCCESS) {
tlshd_log_gnutls_error(ret);
- goto out_free_certs;
+ gnutls_deinit(session);
+ return;
}
- gnutls_transport_set_int(session, parms->sockfd);
- gnutls_session_set_ptr(session, parms);
+ ret = tlshd_server_get_truststore(xcred);
+ if (ret != GNUTLS_E_SUCCESS) {
+ tlshd_log_error("Failed to initialize server trust store - check the configuration");
+ gnutls_alert_send(session, GNUTLS_AL_FATAL, GNUTLS_A_ACCESS_DENIED);
+ goto out_deinit_session;
+ }
+
+ if (!tlshd_x509_server_get_certs(parms)) {
+ tlshd_log_error("No usable server certificates were found - check the configuration");
+ gnutls_alert_send(session, GNUTLS_AL_FATAL, GNUTLS_A_ACCESS_DENIED);
+ goto out_deinit_session;
+ }
+ if (!tlshd_x509_server_get_privkey(parms)) {
+ tlshd_log_error("No usable private keys were found - check the configuration");
+ gnutls_alert_send(session, GNUTLS_AL_FATAL, GNUTLS_A_ACCESS_DENIED);
+ goto out_deinit_session;
+ }
+ gnutls_certificate_set_retrieve_function2(xcred,
+ tlshd_x509_retrieve_key_cb);
ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
if (ret != GNUTLS_E_SUCCESS) {
@@ -430,12 +447,6 @@ static void tlshd_tls13_server_x509_handshake(struct tlshd_handshake_parms *parm
tlshd_tls13_server_x509_verify_function);
gnutls_certificate_server_set_request(session, GNUTLS_CERT_REQUEST);
- ret = tlshd_gnutls_priority_set(session, parms, 0);
- if (ret) {
- tlshd_log_gnutls_error(ret);
- goto out_deinit_session;
- }
-
tlshd_start_tls_handshake(session, parms);
if (tlshd_debug &&
@@ -464,12 +475,8 @@ static void tlshd_tls13_server_x509_handshake(struct tlshd_handshake_parms *parm
out_deinit_session:
gnutls_deinit(session);
-
-out_free_certs:
tlshd_x509_server_put_privkey();
tlshd_x509_server_put_certs();
-
-out_free_creds:
gnutls_certificate_free_credentials(xcred);
}
diff --git a/src/tlshd/tlshd.h b/src/tlshd/tlshd.h
index 75d9a4a..d00cfdf 100644
--- a/src/tlshd/tlshd.h
+++ b/src/tlshd/tlshd.h
@@ -118,6 +118,7 @@ extern void tlshd_log_perror(const char *prefix);
extern void tlshd_log_gai_error(int error);
extern void tlshd_log_cert_verification_error(gnutls_session_t session);
+extern void tlshd_log_alert(gnutls_session_t session);
extern void tlshd_log_gnutls_error(int error);
extern void tlshd_gnutls_log_func(int level, const char *msg);
extern void tlshd_gnutls_audit_func(gnutls_session_t session, const char *msg);
--
2.52.0

View File

@ -0,0 +1,445 @@
From 14f53496509eea9cbe14eb244161b0e26699d165 Mon Sep 17 00:00:00 2001
From: Scott Mayhew <smayhew@redhat.com>
Date: Wed, 10 Sep 2025 20:45:41 -0400
Subject: [PATCH 3/4] tlshd: Server-side dual certificate support
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.51.0

View File

@ -0,0 +1,445 @@
From 6cea3a0e8a10aa893f42576059dcf5c74f092283 Mon Sep 17 00:00:00 2001
From: Scott Mayhew <smayhew@redhat.com>
Date: Wed, 10 Sep 2025 16:17:43 -0400
Subject: [PATCH 1/4] tlshd: deduplicate client and server config functions
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.51.0

View File

@ -1,9 +1,11 @@
%global forgeurl https://github.com/oracle/ktls-utils
%global baseversion 0.11
%global baseversion 1.2.1
Name: ktls-utils
Version: %{baseversion}
Release: 1%{?dist}
# Using a base release of 3 to continue the sequence from the SRPM taken
# from Fedora ELN.
Release: %{autorelease}
Summary: TLS handshake agent for kernel sockets
%forgemeta
@ -14,6 +16,17 @@ URL: %{forgeurl}
# FIXME: is this a bug in the tagging scheme or forgesource macro?
Source0: %{forgeurl}/releases/download/%{name}-%{baseversion}/%{name}-%{baseversion}.tar.gz
#
# RHEL10.2
#
Patch0: ktls-utils-1.2.1-tlshd-deduplicate-client-and-server-config-functions.patch
Patch1: ktls-utils-1.2.1-tlshd-Fix-priority-string-to-allow-PQC.patch
Patch2: ktls-utils-1.2.1-tlshd-Server-side-dual-certificate-support.patch
Patch3: ktls-utils-1.2.1-tlshd-Client-side-dual-certificate-support.patch
Patch4: ktls-utils-1.2.1-tlshd-Clean-up-logic-in-tlshd_start_tls_handshake.patch
Patch5: ktls-utils-1.2.1-tlshd-Fix-session-leak-on-error-paths-in-x509-server.patch
Patch6: ktls-utils-1.2.1-tlshd-Send-fatal-alert-to-client-when-there-are-serv.patch
BuildRequires: bash systemd-rpm-macros
BuildRequires: gcc make coreutils
BuildRequires: pkgconfig(gnutls) >= 3.3.0
@ -66,16 +79,4 @@ standard kTLS socket options.
%systemd_postun_with_restart tlshd.service
%changelog
* Mon Jun 17 2024 Steve Dickson <steved@redhat.com> 0.11-1
- Release ktls-utils 0.11 (RHEL-39442)
* Thu Feb 29 2024 Steve Dickson <steved@redhat.com> 0.10-0
- Initial package
- Upstream contributions by:
- Chuck Lever <chuck.lever@oracle.com>
- Hannes Reinecke <hare@suse.de>
- Jeff Layton <jlayton@kernel.org>
- Benjamin Coddington <bcodding@redhat.com>
- David Härdeman <david@hardeman.nu>
- Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
- Moritz "WanzenBug" Wanzenböck <moritz.wanzenboeck@linbit.com>
%autochangelog

12
plans/sanity.fmf Normal file
View File

@ -0,0 +1,12 @@
summary:
Basic sanity test for ktls-utils
discover:
how: fmf
prepare:
how: install
package:
- ktls-utils
- nfs-utils
- openssl
execute:
how: tmt

1
sources Normal file
View File

@ -0,0 +1 @@
SHA512 (ktls-utils-1.2.1.tar.gz) = 34b5565d5c816bf4dc519b41b7dba9445c6c3dffc09b0eacb56fa7345e5d6daa909a8d682448f02a42063f7a66ed8e377047852a775723fd4cb08964bb7344ca

2
tests/sanity/main.fmf Normal file
View File

@ -0,0 +1,2 @@
summary: Basic sanity test for ktls-utils
test: ./test.sh

99
tests/sanity/test.sh Executable file
View File

@ -0,0 +1,99 @@
#!/bin/bash
MYOLDHOSTNAME=$(hostnamectl hostname --static)
MYHOSTNAME=nfs.ktls-utils.test
MYIP=$(ip -o route get to 8.8.8.8 | sed -n 's/.*src \([0-9.]\+\).*/\1/p')
echo "Setup..."
hostnamectl hostname --static "$MYHOSTNAME"
cp /etc/tlshd.conf /etc/tlshd.conf.bak
openssl req -x509 -newkey rsa:4096 -subj "/CN=ktls-utils smoketest CA" -days 365 -noenc -out ca-cert.pem -keyout ca-cert.key >/dev/null 2>&1
openssl req -x509 -newkey rsa:4096 -subj "/CN=${MYHOSTNAME}" -addext "subjectAltName=DNS:${MYHOSTNAME},IP:${MYIP}" -days 365 -noenc -CA ca-cert.pem -CAkey ca-cert.key -extensions usr_cert -out ktls.pem -keyout ktls.key >/dev/null 2>&1
cp ca-cert.pem /etc/pki/tls/certs
cp ktls.pem /etc/pki/tls/certs
cp ktls.key /etc/pki/tls/private
cat <<EOF >/etc/tlshd.conf
[debug]
loglevel=0
tls=0
nl=0
[authenticate]
#keyrings= <keyring>;<keyring>;<keyring>
[authenticate.client]
x509.truststore=/etc/pki/tls/certs/ca-cert.pem
x509.certificate=/etc/pki/tls/certs/ktls.pem
x509.private_key=/etc/pki/tls/private/ktls.key
[authenticate.server]
x509.truststore=/etc/pki/tls/certs/ca-cert.pem
x509.certificate=/etc/pki/tls/certs/ktls.pem
x509.private_key=/etc/pki/tls/private/ktls.key
EOF
systemctl start tlshd
systemctl start nfs-server
mkdir /export
exportfs -o rw,insecure,no_root_squash,xprtsec=tls:mtls *:/export
# mount by hostname
echo "Try to mount $MYHOSTNAME:/export without xprtsec=tls"
mount -o v4.2 $MYHOSTNAME:/export /mnt
if [ $? -eq 0 ]; then
echo "Mounted $MYHOSTNAME:/export without xprtsec=tls!"
exit 1
fi
echo "Try to mount $MYHOSTNAME:/export with xprtsec=tls"
mount -o v4.2,xprtsec=tls $MYHOSTNAME:/export /mnt
if [ $? -ne 0 ]; then
echo "Failed to mount $MYHOSTNAME:/export with xprtsec=tls!"
exit 1
fi
if ! grep "xprtsec=tls" /proc/mounts; then
echo "Failed to find xprtsec=tls in /proc/mounts"
exit 1
fi
umount /mnt
# mount by ip address
echo "Try to mount $MYIP:/export without xprtsec=tls"
mount -o v4.2 $MYIP:/export /mnt
if [ $? -eq 0 ]; then
echo "Mounted $MYIP:/export without xprtsec=tls!"
exit 1
fi
echo "Try to mount $MYIP:/export with xprtsec=tls"
mount -o v4.2,xprtsec=tls $MYIP:/export /mnt
if [ $? -ne 0 ]; then
echo "Failed to mount $MYIP:/export with xprtsec=tls!"
exit 1
fi
if ! grep "xprtsec=tls" /proc/mounts; then
echo "Failed to find xprtsec=tls in /proc/mounts"
exit 1
fi
umount /mnt
echo "Success!"
echo "Cleanup..."
hostnamectl hostname --static "$MYOLDHOSTNAME"
exportfs -ua
systemctl stop nfs-server
rmdir /export
systemctl stop tlshd
cp /etc/tlshd.conf.bak /etc/tlshd.conf
rm -f /etc/pki/tls/certs/ca-cert.pem
rm -f /etc/pki/tls/certs/ktls.pem
rm -f /etc/pki/tls/private/ktls.key
rm -f ca-cert.pem
rm -f ca-cert.key
rm -f ktls.pem
rm -f ktls.key
exit 0