@samitouri / QOSamiQemu / commits / 27b127d734

crypto: fix client side anonymous TLS credentials

The previous refactoring of credential creation failed to allocate storage fo the anonymous TLS credentials on the client endpoint. Fixes: 70f9fd8dbf7233bee497055a9b7825e3729ce853 Reported-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>

Daniel P. Berrangé committed May 18, 2026 at 14:07 UTC 27b127d7348a922ef91ce607776407407f9c2a3e
2 files changed +121 -1
crypto/tlscredsanon.c
+2
@@ -73,6 +73,8 @@ qcrypto_tls_creds_anon_load(QCryptoTLSCredsAnon *creds,
73 box->dh_params);
74 }
75 } else {
76 + box = qcrypto_tls_creds_box_new_client(GNUTLS_CRD_ANON);
77 +
78 ret = gnutls_anon_allocate_client_credentials(&box->data.anonclient);
79 if (ret < 0) {
80 error_setg(errp, "Cannot allocate credentials: %s",
tests/unit/test-crypto-tlssession.c
+119 -1
@@ -24,6 +24,7 @@
24 #include "crypto-tls-psk-helpers.h"
25 #include "crypto/tlscredsx509.h"
26 #include "crypto/tlscredspsk.h"
27 +#include "crypto/tlscredsanon.h"
28 #include "crypto/tlssession.h"
29 #include "qom/object_interfaces.h"
30 #include "qapi/error.h"
@@ -190,6 +191,121 @@ static void test_crypto_tls_session_psk(void)
191 }
192
193
194 +static QCryptoTLSCreds *test_tls_creds_anon_create(
195 + QCryptoTLSCredsEndpoint endpoint)
196 +{
197 + Object *parent = object_get_objects_root();
198 + Object *creds = object_new_with_props(
199 + TYPE_QCRYPTO_TLS_CREDS_ANON,
200 + parent,
201 + (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
202 + "testtlscredsserver" : "testtlscredsclient"),
203 + &error_abort,
204 + "endpoint", (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
205 + "server" : "client"),
206 + "priority", "NORMAL",
207 + NULL
208 + );
209 + return QCRYPTO_TLS_CREDS(creds);
210 +}
211 +
212 +
213 +static void test_crypto_tls_session_anon(void)
214 +{
215 + QCryptoTLSCreds *clientCreds;
216 + QCryptoTLSCreds *serverCreds;
217 + QCryptoTLSSession *clientSess = NULL;
218 + QCryptoTLSSession *serverSess = NULL;
219 + int channel[2];
220 + bool clientShake = false;
221 + bool serverShake = false;
222 + int ret;
223 +
224 + /* We'll use this for our fake client-server connection */
225 + ret = qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, channel);
226 + g_assert(ret == 0);
227 +
228 + /*
229 + * We have an evil loop to do the handshake in a single
230 + * thread, so we need these non-blocking to avoid deadlock
231 + * of ourselves
232 + */
233 + qemu_set_blocking(channel[0], false, &error_abort);
234 + qemu_set_blocking(channel[1], false, &error_abort);
235 +
236 + clientCreds = test_tls_creds_anon_create(
237 + QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT);
238 + g_assert(clientCreds != NULL);
239 +
240 + serverCreds = test_tls_creds_anon_create(
241 + QCRYPTO_TLS_CREDS_ENDPOINT_SERVER);
242 + g_assert(serverCreds != NULL);
243 +
244 + /* Now the real part of the test, setup the sessions */
245 + clientSess = qcrypto_tls_session_new(
246 + clientCreds, NULL, NULL,
247 + QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT, &error_abort);
248 + g_assert(clientSess != NULL);
249 +
250 + serverSess = qcrypto_tls_session_new(
251 + serverCreds, NULL, NULL,
252 + QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, &error_abort);
253 + g_assert(serverSess != NULL);
254 +
255 + /* For handshake to work, we need to set the I/O callbacks
256 + * to read/write over the socketpair
257 + */
258 + qcrypto_tls_session_set_callbacks(serverSess,
259 + testWrite, testRead,
260 + &channel[0]);
261 + qcrypto_tls_session_set_callbacks(clientSess,
262 + testWrite, testRead,
263 + &channel[1]);
264 +
265 + /*
266 + * Finally we loop around & around doing handshake on each
267 + * session until we get an error, or the handshake completes.
268 + * This relies on the socketpair being nonblocking to avoid
269 + * deadlocking ourselves upon handshake
270 + */
271 + do {
272 + int rv;
273 + if (!serverShake) {
274 + rv = qcrypto_tls_session_handshake(serverSess,
275 + &error_abort);
276 + g_assert(rv >= 0);
277 + if (rv == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
278 + serverShake = true;
279 + }
280 + }
281 + if (!clientShake) {
282 + rv = qcrypto_tls_session_handshake(clientSess,
283 + &error_abort);
284 + g_assert(rv >= 0);
285 + if (rv == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
286 + clientShake = true;
287 + }
288 + }
289 + } while (!clientShake || !serverShake);
290 +
291 +
292 + /* Finally make sure the server & client validation is successful. */
293 + g_assert(qcrypto_tls_session_check_credentials(serverSess,
294 + &error_abort) == 0);
295 + g_assert(qcrypto_tls_session_check_credentials(clientSess,
296 + &error_abort) == 0);
297 +
298 + object_unparent(OBJECT(serverCreds));
299 + object_unparent(OBJECT(clientCreds));
300 +
301 + qcrypto_tls_session_free(serverSess);
302 + qcrypto_tls_session_free(clientSess);
303 +
304 + close(channel[0]);
305 + close(channel[1]);
306 +}
307 +
308 +
309 struct QCryptoTLSSessionTestData {
310 const char *servercacrt;
311 const char *clientcacrt;
@@ -421,9 +537,11 @@ int main(int argc, char **argv)
537 test_tls_init(KEYFILE);
538 test_tls_psk_init(PSKFILE);
539
424 - /* Simple initial test using Pre-Shared Keys. */
540 + /* Simple initial tests using Pre-Shared Keys & anon creds */
541 g_test_add_func("/qcrypto/tlssession/psk",
542 test_crypto_tls_session_psk);
543 + g_test_add_func("/qcrypto/tlssession/anon",
544 + test_crypto_tls_session_anon);
545
546 /* More complex tests using X.509 certificates. */
547 # define TEST_SESS_REG(name, caCrt, \