1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include "qemu/osdep.h"
22
23#include "crypto-tls-x509-helpers.h"
24#include "crypto-tls-psk-helpers.h"
25#include "crypto/tlscredsx509.h"
26#include "crypto/tlscredspsk.h"
27#include "crypto/tlssession.h"
28#include "qom/object_interfaces.h"
29#include "qapi/error.h"
30#include "qemu/module.h"
31#include "qemu/sockets.h"
32#include "authz/list.h"
33
34#ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT
35
36#define WORKDIR "tests/test-crypto-tlssession-work/"
37#define PSKFILE WORKDIR "keys.psk"
38#define KEYFILE WORKDIR "key-ctx.pem"
39
40static ssize_t testWrite(const char *buf, size_t len, void *opaque)
41{
42 int *fd = opaque;
43
44 return write(*fd, buf, len);
45}
46
47static ssize_t testRead(char *buf, size_t len, void *opaque)
48{
49 int *fd = opaque;
50
51 return read(*fd, buf, len);
52}
53
54static QCryptoTLSCreds *test_tls_creds_psk_create(
55 QCryptoTLSCredsEndpoint endpoint,
56 const char *dir)
57{
58 Object *parent = object_get_objects_root();
59 Object *creds = object_new_with_props(
60 TYPE_QCRYPTO_TLS_CREDS_PSK,
61 parent,
62 (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
63 "testtlscredsserver" : "testtlscredsclient"),
64 &error_abort,
65 "endpoint", (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
66 "server" : "client"),
67 "dir", dir,
68 "priority", "NORMAL",
69 NULL
70 );
71 return QCRYPTO_TLS_CREDS(creds);
72}
73
74
75static void test_crypto_tls_session_psk(void)
76{
77 QCryptoTLSCreds *clientCreds;
78 QCryptoTLSCreds *serverCreds;
79 QCryptoTLSSession *clientSess = NULL;
80 QCryptoTLSSession *serverSess = NULL;
81 int channel[2];
82 bool clientShake = false;
83 bool serverShake = false;
84 int ret;
85
86
87 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, channel);
88 g_assert(ret == 0);
89
90
91
92
93
94
95 qemu_set_nonblock(channel[0]);
96 qemu_set_nonblock(channel[1]);
97
98 clientCreds = test_tls_creds_psk_create(
99 QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
100 WORKDIR);
101 g_assert(clientCreds != NULL);
102
103 serverCreds = test_tls_creds_psk_create(
104 QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
105 WORKDIR);
106 g_assert(serverCreds != NULL);
107
108
109 clientSess = qcrypto_tls_session_new(
110 clientCreds, NULL, NULL,
111 QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT, &error_abort);
112 g_assert(clientSess != NULL);
113
114 serverSess = qcrypto_tls_session_new(
115 serverCreds, NULL, NULL,
116 QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, &error_abort);
117 g_assert(serverSess != NULL);
118
119
120
121
122 qcrypto_tls_session_set_callbacks(serverSess,
123 testWrite, testRead,
124 &channel[0]);
125 qcrypto_tls_session_set_callbacks(clientSess,
126 testWrite, testRead,
127 &channel[1]);
128
129
130
131
132
133
134
135 do {
136 int rv;
137 if (!serverShake) {
138 rv = qcrypto_tls_session_handshake(serverSess,
139 &error_abort);
140 g_assert(rv >= 0);
141 if (qcrypto_tls_session_get_handshake_status(serverSess) ==
142 QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
143 serverShake = true;
144 }
145 }
146 if (!clientShake) {
147 rv = qcrypto_tls_session_handshake(clientSess,
148 &error_abort);
149 g_assert(rv >= 0);
150 if (qcrypto_tls_session_get_handshake_status(clientSess) ==
151 QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
152 clientShake = true;
153 }
154 }
155 } while (!clientShake || !serverShake);
156
157
158
159 g_assert(qcrypto_tls_session_check_credentials(serverSess,
160 &error_abort) == 0);
161 g_assert(qcrypto_tls_session_check_credentials(clientSess,
162 &error_abort) == 0);
163
164 object_unparent(OBJECT(serverCreds));
165 object_unparent(OBJECT(clientCreds));
166
167 qcrypto_tls_session_free(serverSess);
168 qcrypto_tls_session_free(clientSess);
169
170 close(channel[0]);
171 close(channel[1]);
172}
173
174
175struct QCryptoTLSSessionTestData {
176 const char *servercacrt;
177 const char *clientcacrt;
178 const char *servercrt;
179 const char *clientcrt;
180 bool expectServerFail;
181 bool expectClientFail;
182 const char *hostname;
183 const char *const *wildcards;
184};
185
186static QCryptoTLSCreds *test_tls_creds_x509_create(
187 QCryptoTLSCredsEndpoint endpoint,
188 const char *certdir)
189{
190 Object *parent = object_get_objects_root();
191 Object *creds = object_new_with_props(
192 TYPE_QCRYPTO_TLS_CREDS_X509,
193 parent,
194 (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
195 "testtlscredsserver" : "testtlscredsclient"),
196 &error_abort,
197 "endpoint", (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
198 "server" : "client"),
199 "dir", certdir,
200 "verify-peer", "yes",
201 "priority", "NORMAL",
202
203
204
205
206
207
208 "sanity-check", "no",
209 NULL
210 );
211 return QCRYPTO_TLS_CREDS(creds);
212}
213
214
215
216
217
218
219
220
221
222
223
224
225static void test_crypto_tls_session_x509(const void *opaque)
226{
227 struct QCryptoTLSSessionTestData *data =
228 (struct QCryptoTLSSessionTestData *)opaque;
229 QCryptoTLSCreds *clientCreds;
230 QCryptoTLSCreds *serverCreds;
231 QCryptoTLSSession *clientSess = NULL;
232 QCryptoTLSSession *serverSess = NULL;
233 QAuthZList *auth;
234 const char * const *wildcards;
235 int channel[2];
236 bool clientShake = false;
237 bool serverShake = false;
238 int ret;
239
240
241 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, channel);
242 g_assert(ret == 0);
243
244
245
246
247
248
249 qemu_set_nonblock(channel[0]);
250 qemu_set_nonblock(channel[1]);
251
252#define CLIENT_CERT_DIR "tests/test-crypto-tlssession-client/"
253#define SERVER_CERT_DIR "tests/test-crypto-tlssession-server/"
254 mkdir(CLIENT_CERT_DIR, 0700);
255 mkdir(SERVER_CERT_DIR, 0700);
256
257 unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
258 unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT);
259 unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY);
260
261 unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
262 unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
263 unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);
264
265 g_assert(link(data->servercacrt,
266 SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0);
267 g_assert(link(data->servercrt,
268 SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT) == 0);
269 g_assert(link(KEYFILE,
270 SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY) == 0);
271
272 g_assert(link(data->clientcacrt,
273 CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0);
274 g_assert(link(data->clientcrt,
275 CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT) == 0);
276 g_assert(link(KEYFILE,
277 CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY) == 0);
278
279 clientCreds = test_tls_creds_x509_create(
280 QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
281 CLIENT_CERT_DIR);
282 g_assert(clientCreds != NULL);
283
284 serverCreds = test_tls_creds_x509_create(
285 QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
286 SERVER_CERT_DIR);
287 g_assert(serverCreds != NULL);
288
289 auth = qauthz_list_new("tlssessionacl",
290 QAUTHZ_LIST_POLICY_DENY,
291 &error_abort);
292 wildcards = data->wildcards;
293 while (wildcards && *wildcards) {
294 qauthz_list_append_rule(auth, *wildcards,
295 QAUTHZ_LIST_POLICY_ALLOW,
296 QAUTHZ_LIST_FORMAT_GLOB,
297 &error_abort);
298 wildcards++;
299 }
300
301
302 clientSess = qcrypto_tls_session_new(
303 clientCreds, data->hostname, NULL,
304 QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT, &error_abort);
305 g_assert(clientSess != NULL);
306
307 serverSess = qcrypto_tls_session_new(
308 serverCreds, NULL,
309 data->wildcards ? "tlssessionacl" : NULL,
310 QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, &error_abort);
311 g_assert(serverSess != NULL);
312
313
314
315
316 qcrypto_tls_session_set_callbacks(serverSess,
317 testWrite, testRead,
318 &channel[0]);
319 qcrypto_tls_session_set_callbacks(clientSess,
320 testWrite, testRead,
321 &channel[1]);
322
323
324
325
326
327
328
329 do {
330 int rv;
331 if (!serverShake) {
332 rv = qcrypto_tls_session_handshake(serverSess,
333 &error_abort);
334 g_assert(rv >= 0);
335 if (qcrypto_tls_session_get_handshake_status(serverSess) ==
336 QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
337 serverShake = true;
338 }
339 }
340 if (!clientShake) {
341 rv = qcrypto_tls_session_handshake(clientSess,
342 &error_abort);
343 g_assert(rv >= 0);
344 if (qcrypto_tls_session_get_handshake_status(clientSess) ==
345 QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
346 clientShake = true;
347 }
348 }
349 } while (!clientShake || !serverShake);
350
351
352
353
354
355 if (qcrypto_tls_session_check_credentials(
356 serverSess, data->expectServerFail ? NULL : &error_abort) < 0) {
357 g_assert(data->expectServerFail);
358 } else {
359 g_assert(!data->expectServerFail);
360 }
361
362
363
364
365 if (qcrypto_tls_session_check_credentials(
366 clientSess, data->expectClientFail ? NULL : &error_abort) < 0) {
367 g_assert(data->expectClientFail);
368 } else {
369 g_assert(!data->expectClientFail);
370 }
371
372 unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
373 unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT);
374 unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY);
375
376 unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
377 unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
378 unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);
379
380 rmdir(CLIENT_CERT_DIR);
381 rmdir(SERVER_CERT_DIR);
382
383 object_unparent(OBJECT(serverCreds));
384 object_unparent(OBJECT(clientCreds));
385 object_unparent(OBJECT(auth));
386
387 qcrypto_tls_session_free(serverSess);
388 qcrypto_tls_session_free(clientSess);
389
390 close(channel[0]);
391 close(channel[1]);
392}
393
394
395int main(int argc, char **argv)
396{
397 int ret;
398
399 module_call_init(MODULE_INIT_QOM);
400 g_test_init(&argc, &argv, NULL);
401 setenv("GNUTLS_FORCE_FIPS_MODE", "2", 1);
402
403 mkdir(WORKDIR, 0700);
404
405 test_tls_init(KEYFILE);
406 test_tls_psk_init(PSKFILE);
407
408
409 g_test_add_func("/qcrypto/tlssession/psk",
410 test_crypto_tls_session_psk);
411
412
413# define TEST_SESS_REG(name, caCrt, \
414 serverCrt, clientCrt, \
415 expectServerFail, expectClientFail, \
416 hostname, wildcards) \
417 struct QCryptoTLSSessionTestData name = { \
418 caCrt, caCrt, serverCrt, clientCrt, \
419 expectServerFail, expectClientFail, \
420 hostname, wildcards \
421 }; \
422 g_test_add_data_func("/qcrypto/tlssession/" # name, \
423 &name, test_crypto_tls_session_x509); \
424
425
426# define TEST_SESS_REG_EXT(name, serverCaCrt, clientCaCrt, \
427 serverCrt, clientCrt, \
428 expectServerFail, expectClientFail, \
429 hostname, wildcards) \
430 struct QCryptoTLSSessionTestData name = { \
431 serverCaCrt, clientCaCrt, serverCrt, clientCrt, \
432 expectServerFail, expectClientFail, \
433 hostname, wildcards \
434 }; \
435 g_test_add_data_func("/qcrypto/tlssession/" # name, \
436 &name, test_crypto_tls_session_x509); \
437
438
439
440
441 TLS_ROOT_REQ(cacertreq,
442 "UK", "qemu CA", NULL, NULL, NULL, NULL,
443 true, true, true,
444 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
445 false, false, NULL, NULL,
446 0, 0);
447
448 TLS_ROOT_REQ(altcacertreq,
449 "UK", "qemu CA 1", NULL, NULL, NULL, NULL,
450 true, true, true,
451 false, false, 0,
452 false, false, NULL, NULL,
453 0, 0);
454
455 TLS_CERT_REQ(servercertreq, cacertreq,
456 "UK", "qemu.org", NULL, NULL, NULL, NULL,
457 true, true, false,
458 true, true,
459 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
460 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
461 0, 0);
462 TLS_CERT_REQ(clientcertreq, cacertreq,
463 "UK", "qemu", NULL, NULL, NULL, NULL,
464 true, true, false,
465 true, true,
466 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
467 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
468 0, 0);
469
470 TLS_CERT_REQ(clientcertaltreq, altcacertreq,
471 "UK", "qemu", NULL, NULL, NULL, NULL,
472 true, true, false,
473 true, true,
474 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
475 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
476 0, 0);
477
478 TEST_SESS_REG(basicca, cacertreq.filename,
479 servercertreq.filename, clientcertreq.filename,
480 false, false, "qemu.org", NULL);
481 TEST_SESS_REG_EXT(differentca, cacertreq.filename,
482 altcacertreq.filename, servercertreq.filename,
483 clientcertaltreq.filename, true, true, "qemu.org", NULL);
484
485
486
487
488 TLS_CERT_REQ(servercertalt1req, cacertreq,
489 "UK", "qemu.org", "www.qemu.org", "qemu.org",
490 "192.168.122.1", "fec0::dead:beaf",
491 true, true, false,
492 true, true,
493 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
494 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
495 0, 0);
496
497 TLS_CERT_REQ(servercertalt2req, cacertreq,
498 "UK", "qemu.org", "www.qemu.org", "wiki.qemu.org",
499 "192.168.122.1", "fec0::dead:beaf",
500 true, true, false,
501 true, true,
502 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
503 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
504 0, 0);
505
506 TEST_SESS_REG(altname1, cacertreq.filename,
507 servercertalt1req.filename, clientcertreq.filename,
508 false, false, "qemu.org", NULL);
509 TEST_SESS_REG(altname2, cacertreq.filename,
510 servercertalt1req.filename, clientcertreq.filename,
511 false, false, "www.qemu.org", NULL);
512 TEST_SESS_REG(altname3, cacertreq.filename,
513 servercertalt1req.filename, clientcertreq.filename,
514 false, true, "wiki.qemu.org", NULL);
515
516 TEST_SESS_REG(altname4, cacertreq.filename,
517 servercertalt2req.filename, clientcertreq.filename,
518 false, true, "qemu.org", NULL);
519 TEST_SESS_REG(altname5, cacertreq.filename,
520 servercertalt2req.filename, clientcertreq.filename,
521 false, false, "www.qemu.org", NULL);
522 TEST_SESS_REG(altname6, cacertreq.filename,
523 servercertalt2req.filename, clientcertreq.filename,
524 false, false, "wiki.qemu.org", NULL);
525
526 const char *const wildcards1[] = {
527 "C=UK,CN=dogfood",
528 NULL,
529 };
530 const char *const wildcards2[] = {
531 "C=UK,CN=qemu",
532 NULL,
533 };
534 const char *const wildcards3[] = {
535 "C=UK,CN=dogfood",
536 "C=UK,CN=qemu",
537 NULL,
538 };
539 const char *const wildcards4[] = {
540 "C=UK,CN=qemustuff",
541 NULL,
542 };
543 const char *const wildcards5[] = {
544 "C=UK,CN=qemu*",
545 NULL,
546 };
547 const char *const wildcards6[] = {
548 "C=UK,CN=*emu*",
549 NULL,
550 };
551
552 TEST_SESS_REG(wildcard1, cacertreq.filename,
553 servercertreq.filename, clientcertreq.filename,
554 true, false, "qemu.org", wildcards1);
555 TEST_SESS_REG(wildcard2, cacertreq.filename,
556 servercertreq.filename, clientcertreq.filename,
557 false, false, "qemu.org", wildcards2);
558 TEST_SESS_REG(wildcard3, cacertreq.filename,
559 servercertreq.filename, clientcertreq.filename,
560 false, false, "qemu.org", wildcards3);
561 TEST_SESS_REG(wildcard4, cacertreq.filename,
562 servercertreq.filename, clientcertreq.filename,
563 true, false, "qemu.org", wildcards4);
564 TEST_SESS_REG(wildcard5, cacertreq.filename,
565 servercertreq.filename, clientcertreq.filename,
566 false, false, "qemu.org", wildcards5);
567 TEST_SESS_REG(wildcard6, cacertreq.filename,
568 servercertreq.filename, clientcertreq.filename,
569 false, false, "qemu.org", wildcards6);
570
571 TLS_ROOT_REQ(cacertrootreq,
572 "UK", "qemu root", NULL, NULL, NULL, NULL,
573 true, true, true,
574 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
575 false, false, NULL, NULL,
576 0, 0);
577 TLS_CERT_REQ(cacertlevel1areq, cacertrootreq,
578 "UK", "qemu level 1a", NULL, NULL, NULL, NULL,
579 true, true, true,
580 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
581 false, false, NULL, NULL,
582 0, 0);
583 TLS_CERT_REQ(cacertlevel1breq, cacertrootreq,
584 "UK", "qemu level 1b", NULL, NULL, NULL, NULL,
585 true, true, true,
586 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
587 false, false, NULL, NULL,
588 0, 0);
589 TLS_CERT_REQ(cacertlevel2areq, cacertlevel1areq,
590 "UK", "qemu level 2a", NULL, NULL, NULL, NULL,
591 true, true, true,
592 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
593 false, false, NULL, NULL,
594 0, 0);
595 TLS_CERT_REQ(servercertlevel3areq, cacertlevel2areq,
596 "UK", "qemu.org", NULL, NULL, NULL, NULL,
597 true, true, false,
598 true, true,
599 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
600 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
601 0, 0);
602 TLS_CERT_REQ(clientcertlevel2breq, cacertlevel1breq,
603 "UK", "qemu client level 2b", NULL, NULL, NULL, NULL,
604 true, true, false,
605 true, true,
606 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
607 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
608 0, 0);
609
610 gnutls_x509_crt_t certchain[] = {
611 cacertrootreq.crt,
612 cacertlevel1areq.crt,
613 cacertlevel1breq.crt,
614 cacertlevel2areq.crt,
615 };
616
617 test_tls_write_cert_chain(WORKDIR "cacertchain-sess.pem",
618 certchain,
619 G_N_ELEMENTS(certchain));
620
621 TEST_SESS_REG(cachain, WORKDIR "cacertchain-sess.pem",
622 servercertlevel3areq.filename, clientcertlevel2breq.filename,
623 false, false, "qemu.org", NULL);
624
625 ret = g_test_run();
626
627 test_tls_discard_cert(&clientcertreq);
628 test_tls_discard_cert(&clientcertaltreq);
629
630 test_tls_discard_cert(&servercertreq);
631 test_tls_discard_cert(&servercertalt1req);
632 test_tls_discard_cert(&servercertalt2req);
633
634 test_tls_discard_cert(&cacertreq);
635 test_tls_discard_cert(&altcacertreq);
636
637 test_tls_discard_cert(&cacertrootreq);
638 test_tls_discard_cert(&cacertlevel1areq);
639 test_tls_discard_cert(&cacertlevel1breq);
640 test_tls_discard_cert(&cacertlevel2areq);
641 test_tls_discard_cert(&servercertlevel3areq);
642 test_tls_discard_cert(&clientcertlevel2breq);
643 unlink(WORKDIR "cacertchain-sess.pem");
644
645 test_tls_psk_cleanup(PSKFILE);
646 test_tls_cleanup(KEYFILE);
647 rmdir(WORKDIR);
648
649 return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
650}
651
652#else
653
654int
655main(void)
656{
657 return EXIT_SUCCESS;
658}
659
660#endif
661