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, \