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 ]], + [[ (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 8acb0aa..ad9a793 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); @@ -134,16 +134,21 @@ static void tlshd_tls13_client_anon_handshake(struct tlshd_handshake_parms *parm 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_client_certs(tlshd_certs, &tlshd_certs_len); + 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) @@ -159,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_client_privkey(&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) @@ -205,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); @@ -219,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/config.c b/src/tlshd/config.c index 029dbcc..9a3b6b2 100644 --- a/src/tlshd/config.c +++ b/src/tlshd/config.c @@ -187,18 +187,22 @@ static bool tlshd_config_read_datum(const char *pathname, gnutls_datum_t *data, } /** - * 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,89 +254,106 @@ 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 - * @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_client_certs(gnutls_pcert_st *certs, - unsigned int *certs_len) +#ifdef HAVE_GNUTLS_MLDSA +static bool tlshd_cert_check_pk_alg(gnutls_datum_t *data, + gnutls_pk_algorithm_t *pkalg) { - gnutls_datum_t data; - gchar *pathname; + gnutls_x509_crt_t cert; + gnutls_pk_algorithm_t pk_alg; int ret; - pathname = g_key_file_get_string(tlshd_configuration, "authenticate.client", - "x509.certificate", NULL); - if (!pathname) + ret = gnutls_x509_crt_init(&cert); + if (ret < 0) return false; - if (!tlshd_config_read_datum(pathname, &data, TLSHD_OWNER, - TLSHD_CERT_MODE)) { - g_free(pathname); + ret = gnutls_x509_crt_import(cert, data, GNUTLS_X509_FMT_PEM); + if (ret < 0) { + gnutls_x509_crt_deinit(cert); 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); + 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; } - tlshd_log_debug("Retrieved %u x.509 client certificate(s) from %s", - *certs_len, pathname); - g_free(pathname); + 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_client_privkey - Get private key for ClientHello from .conf - * @privkey: OUT: in-memory private key + * __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: private key retrieved successfully - * %false: private key not retrieved + * %true: certificate retrieved successfully + * %false: certificate not retrieved */ -bool tlshd_config_get_client_privkey(gnutls_privkey_t *privkey) +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; int ret; - pathname = g_key_file_get_string(tlshd_configuration, "authenticate.client", - "x509.private_key", NULL); + pathname = g_key_file_get_string(tlshd_configuration, + peer_type == PEER_TYPE_CLIENT ? + "authenticate.client" : + "authenticate.server", + pkalg != NULL ? + "x509.pq.certificate" : + "x509.certificate", + NULL); if (!pathname) return false; if (!tlshd_config_read_datum(pathname, &data, TLSHD_OWNER, - TLSHD_PRIVKEY_MODE)) { + TLSHD_CERT_MODE)) { g_free(pathname); return false; } - ret = gnutls_privkey_init(privkey); - if (ret != GNUTLS_E_SUCCESS) { - tlshd_log_gnutls_error(ret); + 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 keys */ - ret = gnutls_privkey_import_x509_raw(*privkey, &data, - GNUTLS_X509_FMT_PEM, NULL, 0); + /* 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); @@ -334,132 +361,73 @@ bool tlshd_config_get_client_privkey(gnutls_privkey_t *privkey) 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); + 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); - 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 + * 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_server_certs(gnutls_pcert_st *certs, - unsigned int *certs_len) +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) { - gnutls_datum_t data; - gchar *pathname; - int ret; + bool ret; - pathname = g_key_file_get_string(tlshd_configuration, "authenticate.server", - "x509.certificate", NULL); - if (!pathname) - return false; + ret = __tlshd_config_get_certs(peer_type, certs, pq_certs_len, pkalg); - if (!tlshd_config_read_datum(pathname, &data, TLSHD_OWNER, - TLSHD_CERT_MODE)) { - g_free(pathname); - return false; - } + if (ret == true) + *certs_len -= *pq_certs_len; + else + *pq_certs_len = 0; - /* 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; + return __tlshd_config_get_certs(peer_type, certs + *pq_certs_len, + certs_len, NULL); } /** - * tlshd_config_get_server_privkey - Get private key for ServerHello from .conf + * __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_server_privkey(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; 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", + pq == true ? + "x509.pq.private_key" : + "x509.private_key", + NULL); if (!pathname) return false; @@ -491,3 +459,22 @@ bool tlshd_config_get_server_privkey(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/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; diff --git a/src/tlshd/server.c b/src/tlshd/server.c index 44a91c4..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) { @@ -52,15 +55,17 @@ 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_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]); } @@ -69,11 +74,14 @@ 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_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); } @@ -122,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); @@ -129,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; } @@ -140,7 +202,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 +212,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.conf b/src/tlshd/tlshd.conf index 620bd17..1d4220e 100644 --- a/src/tlshd/tlshd.conf +++ b/src/tlshd/tlshd.conf @@ -33,9 +33,13 @@ nl=0 #x509.crl= #x509.certificate= #x509.private_key= +#x509.pq.certificate= +#x509.pq.private_key= [authenticate.server] #x509.truststore= #x509.crl= #x509.certificate= #x509.private_key= +#x509.pq.certificate= +#x509.pq.private_key= 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 2857804..664de67 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,14 @@ 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 *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,