xref: /qemu/tests/unit/test-crypto-tlssession.c (revision 513823e7521a09ed7ad1e32e6454bac3b2cbf52d)
1 /*
2  * Copyright (C) 2015 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library.  If not, see
16  * <http://www.gnu.org/licenses/>.
17  *
18  * Author: Daniel P. Berrange <berrange@redhat.com>
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 #define WORKDIR "tests/test-crypto-tlssession-work/"
35 #define PSKFILE WORKDIR "keys.psk"
36 #define KEYFILE WORKDIR "key-ctx.pem"
37 
38 static ssize_t
39 testWrite(const char *buf, size_t len, void *opaque, Error **errp)
40 {
41     int *fd = opaque;
42     int ret;
43 
44     ret = write(*fd, buf, len);
45     if (ret < 0) {
46         if (errno == EAGAIN) {
47             return QCRYPTO_TLS_SESSION_ERR_BLOCK;
48         } else {
49             error_setg_errno(errp, errno, "unable to write");
50             return -1;
51         }
52     }
53     return ret;
54 }
55 
56 static ssize_t
57 testRead(char *buf, size_t len, void *opaque, Error **errp)
58 {
59     int *fd = opaque;
60     int ret;
61 
62     ret = read(*fd, buf, len);
63     if (ret < 0) {
64         if (errno == EAGAIN) {
65             return QCRYPTO_TLS_SESSION_ERR_BLOCK;
66         } else {
67             error_setg_errno(errp, errno, "unable to read");
68             return -1;
69         }
70     }
71     return ret;
72 }
73 
74 static QCryptoTLSCreds *test_tls_creds_psk_create(
75     QCryptoTLSCredsEndpoint endpoint,
76     const char *dir)
77 {
78     Object *parent = object_get_objects_root();
79     Object *creds = object_new_with_props(
80         TYPE_QCRYPTO_TLS_CREDS_PSK,
81         parent,
82         (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
83          "testtlscredsserver" : "testtlscredsclient"),
84         &error_abort,
85         "endpoint", (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
86                      "server" : "client"),
87         "dir", dir,
88         "priority", "NORMAL",
89         NULL
90         );
91     return QCRYPTO_TLS_CREDS(creds);
92 }
93 
94 
95 static void test_crypto_tls_session_psk(void)
96 {
97     QCryptoTLSCreds *clientCreds;
98     QCryptoTLSCreds *serverCreds;
99     QCryptoTLSSession *clientSess = NULL;
100     QCryptoTLSSession *serverSess = NULL;
101     int channel[2];
102     bool clientShake = false;
103     bool serverShake = false;
104     int ret;
105 
106     /* We'll use this for our fake client-server connection */
107     ret = qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, channel);
108     g_assert(ret == 0);
109 
110     /*
111      * We have an evil loop to do the handshake in a single
112      * thread, so we need these non-blocking to avoid deadlock
113      * of ourselves
114      */
115     qemu_socket_set_nonblock(channel[0]);
116     qemu_socket_set_nonblock(channel[1]);
117 
118     clientCreds = test_tls_creds_psk_create(
119         QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
120         WORKDIR);
121     g_assert(clientCreds != NULL);
122 
123     serverCreds = test_tls_creds_psk_create(
124         QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
125         WORKDIR);
126     g_assert(serverCreds != NULL);
127 
128     /* Now the real part of the test, setup the sessions */
129     clientSess = qcrypto_tls_session_new(
130         clientCreds, NULL, NULL,
131         QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT, &error_abort);
132     g_assert(clientSess != NULL);
133 
134     serverSess = qcrypto_tls_session_new(
135         serverCreds, NULL, NULL,
136         QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, &error_abort);
137     g_assert(serverSess != NULL);
138 
139     /* For handshake to work, we need to set the I/O callbacks
140      * to read/write over the socketpair
141      */
142     qcrypto_tls_session_set_callbacks(serverSess,
143                                       testWrite, testRead,
144                                       &channel[0]);
145     qcrypto_tls_session_set_callbacks(clientSess,
146                                       testWrite, testRead,
147                                       &channel[1]);
148 
149     /*
150      * Finally we loop around & around doing handshake on each
151      * session until we get an error, or the handshake completes.
152      * This relies on the socketpair being nonblocking to avoid
153      * deadlocking ourselves upon handshake
154      */
155     do {
156         int rv;
157         if (!serverShake) {
158             rv = qcrypto_tls_session_handshake(serverSess,
159                                                &error_abort);
160             g_assert(rv >= 0);
161             if (rv == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
162                 serverShake = true;
163             }
164         }
165         if (!clientShake) {
166             rv = qcrypto_tls_session_handshake(clientSess,
167                                                &error_abort);
168             g_assert(rv >= 0);
169             if (rv == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
170                 clientShake = true;
171             }
172         }
173     } while (!clientShake || !serverShake);
174 
175 
176     /* Finally make sure the server & client validation is successful. */
177     g_assert(qcrypto_tls_session_check_credentials(serverSess,
178                                                    &error_abort) == 0);
179     g_assert(qcrypto_tls_session_check_credentials(clientSess,
180                                                    &error_abort) == 0);
181 
182     object_unparent(OBJECT(serverCreds));
183     object_unparent(OBJECT(clientCreds));
184 
185     qcrypto_tls_session_free(serverSess);
186     qcrypto_tls_session_free(clientSess);
187 
188     close(channel[0]);
189     close(channel[1]);
190 }
191 
192 
193 struct QCryptoTLSSessionTestData {
194     const char *servercacrt;
195     const char *clientcacrt;
196     const char *servercrt;
197     const char *clientcrt;
198     bool expectServerFail;
199     bool expectClientFail;
200     const char *hostname;
201     const char *const *wildcards;
202 };
203 
204 static QCryptoTLSCreds *test_tls_creds_x509_create(
205     QCryptoTLSCredsEndpoint endpoint,
206     const char *certdir)
207 {
208     Object *parent = object_get_objects_root();
209     Object *creds = object_new_with_props(
210         TYPE_QCRYPTO_TLS_CREDS_X509,
211         parent,
212         (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
213          "testtlscredsserver" : "testtlscredsclient"),
214         &error_abort,
215         "endpoint", (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
216                      "server" : "client"),
217         "dir", certdir,
218         "verify-peer", "yes",
219         "priority", "NORMAL",
220         /* We skip initial sanity checks here because we
221          * want to make sure that problems are being
222          * detected at the TLS session validation stage,
223          * and the test-crypto-tlscreds test already
224          * validate the sanity check code.
225          */
226         "sanity-check", "no",
227         NULL
228         );
229     return QCRYPTO_TLS_CREDS(creds);
230 }
231 
232 
233 /*
234  * This tests validation checking of peer certificates
235  *
236  * This is replicating the checks that are done for an
237  * active TLS session after handshake completes. To
238  * simulate that we create our TLS contexts, skipping
239  * sanity checks. We then get a socketpair, and
240  * initiate a TLS session across them. Finally do
241  * do actual cert validation tests
242  */
243 static void test_crypto_tls_session_x509(const void *opaque)
244 {
245     struct QCryptoTLSSessionTestData *data =
246         (struct QCryptoTLSSessionTestData *)opaque;
247     QCryptoTLSCreds *clientCreds;
248     QCryptoTLSCreds *serverCreds;
249     QCryptoTLSSession *clientSess = NULL;
250     QCryptoTLSSession *serverSess = NULL;
251     QAuthZList *auth;
252     const char * const *wildcards;
253     int channel[2];
254     bool clientShake = false;
255     bool serverShake = false;
256     int ret;
257 
258     /* We'll use this for our fake client-server connection */
259     ret = qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, channel);
260     g_assert(ret == 0);
261 
262     /*
263      * We have an evil loop to do the handshake in a single
264      * thread, so we need these non-blocking to avoid deadlock
265      * of ourselves
266      */
267     qemu_socket_set_nonblock(channel[0]);
268     qemu_socket_set_nonblock(channel[1]);
269 
270 #define CLIENT_CERT_DIR "tests/test-crypto-tlssession-client/"
271 #define SERVER_CERT_DIR "tests/test-crypto-tlssession-server/"
272     g_mkdir_with_parents(CLIENT_CERT_DIR, 0700);
273     g_mkdir_with_parents(SERVER_CERT_DIR, 0700);
274 
275     unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
276     unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT);
277     unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY);
278 
279     unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
280     unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
281     unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);
282 
283     g_assert(link(data->servercacrt,
284                   SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0);
285     g_assert(link(data->servercrt,
286                   SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT) == 0);
287     g_assert(link(KEYFILE,
288                   SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY) == 0);
289 
290     g_assert(link(data->clientcacrt,
291                   CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0);
292     g_assert(link(data->clientcrt,
293                   CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT) == 0);
294     g_assert(link(KEYFILE,
295                   CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY) == 0);
296 
297     clientCreds = test_tls_creds_x509_create(
298         QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
299         CLIENT_CERT_DIR);
300     g_assert(clientCreds != NULL);
301 
302     serverCreds = test_tls_creds_x509_create(
303         QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
304         SERVER_CERT_DIR);
305     g_assert(serverCreds != NULL);
306 
307     auth = qauthz_list_new("tlssessionacl",
308                            QAUTHZ_LIST_POLICY_DENY,
309                            &error_abort);
310     wildcards = data->wildcards;
311     while (wildcards && *wildcards) {
312         qauthz_list_append_rule(auth, *wildcards,
313                                 QAUTHZ_LIST_POLICY_ALLOW,
314                                 QAUTHZ_LIST_FORMAT_GLOB,
315                                 &error_abort);
316         wildcards++;
317     }
318 
319     /* Now the real part of the test, setup the sessions */
320     clientSess = qcrypto_tls_session_new(
321         clientCreds, data->hostname, NULL,
322         QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT, &error_abort);
323     g_assert(clientSess != NULL);
324 
325     serverSess = qcrypto_tls_session_new(
326         serverCreds, NULL,
327         data->wildcards ? "tlssessionacl" : NULL,
328         QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, &error_abort);
329     g_assert(serverSess != NULL);
330 
331     /* For handshake to work, we need to set the I/O callbacks
332      * to read/write over the socketpair
333      */
334     qcrypto_tls_session_set_callbacks(serverSess,
335                                       testWrite, testRead,
336                                       &channel[0]);
337     qcrypto_tls_session_set_callbacks(clientSess,
338                                       testWrite, testRead,
339                                       &channel[1]);
340 
341     /*
342      * Finally we loop around & around doing handshake on each
343      * session until we get an error, or the handshake completes.
344      * This relies on the socketpair being nonblocking to avoid
345      * deadlocking ourselves upon handshake
346      */
347     do {
348         int rv;
349         if (!serverShake) {
350             rv = qcrypto_tls_session_handshake(serverSess,
351                                                &error_abort);
352             g_assert(rv >= 0);
353             if (rv == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
354                 serverShake = true;
355             }
356         }
357         if (!clientShake) {
358             rv = qcrypto_tls_session_handshake(clientSess,
359                                                &error_abort);
360             g_assert(rv >= 0);
361             if (rv == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
362                 clientShake = true;
363             }
364         }
365     } while (!clientShake || !serverShake);
366 
367 
368     /* Finally make sure the server validation does what
369      * we were expecting
370      */
371     if (qcrypto_tls_session_check_credentials(
372             serverSess, data->expectServerFail ? NULL : &error_abort) < 0) {
373         g_assert(data->expectServerFail);
374     } else {
375         g_assert(!data->expectServerFail);
376     }
377 
378     /*
379      * And the same for the client validation check
380      */
381     if (qcrypto_tls_session_check_credentials(
382             clientSess, data->expectClientFail ? NULL : &error_abort) < 0) {
383         g_assert(data->expectClientFail);
384     } else {
385         g_assert(!data->expectClientFail);
386     }
387 
388     unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
389     unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT);
390     unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY);
391 
392     unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
393     unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
394     unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);
395 
396     rmdir(CLIENT_CERT_DIR);
397     rmdir(SERVER_CERT_DIR);
398 
399     object_unparent(OBJECT(serverCreds));
400     object_unparent(OBJECT(clientCreds));
401     object_unparent(OBJECT(auth));
402 
403     qcrypto_tls_session_free(serverSess);
404     qcrypto_tls_session_free(clientSess);
405 
406     close(channel[0]);
407     close(channel[1]);
408 }
409 
410 
411 int main(int argc, char **argv)
412 {
413     int ret;
414 
415     module_call_init(MODULE_INIT_QOM);
416     g_test_init(&argc, &argv, NULL);
417     g_setenv("GNUTLS_FORCE_FIPS_MODE", "2", 1);
418 
419     g_mkdir_with_parents(WORKDIR, 0700);
420 
421     test_tls_init(KEYFILE);
422     test_tls_psk_init(PSKFILE);
423 
424     /* Simple initial test using Pre-Shared Keys. */
425     g_test_add_func("/qcrypto/tlssession/psk",
426                     test_crypto_tls_session_psk);
427 
428     /* More complex tests using X.509 certificates. */
429 # define TEST_SESS_REG(name, caCrt,                                     \
430                        serverCrt, clientCrt,                            \
431                        expectServerFail, expectClientFail,              \
432                        hostname, wildcards)                             \
433     struct QCryptoTLSSessionTestData name = {                           \
434         caCrt, caCrt, serverCrt, clientCrt,                             \
435         expectServerFail, expectClientFail,                             \
436         hostname, wildcards                                             \
437     };                                                                  \
438     g_test_add_data_func("/qcrypto/tlssession/" # name,                 \
439                          &name, test_crypto_tls_session_x509);          \
440 
441 
442 # define TEST_SESS_REG_EXT(name, serverCaCrt, clientCaCrt,              \
443                            serverCrt, clientCrt,                        \
444                            expectServerFail, expectClientFail,          \
445                            hostname, wildcards)                         \
446     struct QCryptoTLSSessionTestData name = {                           \
447         serverCaCrt, clientCaCrt, serverCrt, clientCrt,                 \
448         expectServerFail, expectClientFail,                             \
449         hostname, wildcards                                             \
450     };                                                                  \
451     g_test_add_data_func("/qcrypto/tlssession/" # name,                 \
452                          &name, test_crypto_tls_session_x509);          \
453 
454     /* A perfect CA, perfect client & perfect server */
455 
456     /* Basic:CA:critical */
457     TLS_ROOT_REQ(cacertreq,
458                  "UK", "qemu CA", NULL, NULL, NULL, NULL,
459                  true, true, true,
460                  true, true, GNUTLS_KEY_KEY_CERT_SIGN,
461                  false, false, NULL, NULL,
462                  0, 0);
463 
464     TLS_ROOT_REQ(altcacertreq,
465                  "UK", "qemu CA 1", NULL, NULL, NULL, NULL,
466                  true, true, true,
467                  false, false, 0,
468                  false, false, NULL, NULL,
469                  0, 0);
470 
471     TLS_CERT_REQ(servercertreq, cacertreq,
472                  "UK", "qemu.org", NULL, NULL, NULL, NULL,
473                  true, true, false,
474                  true, true,
475                  GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
476                  true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
477                  0, 0);
478     TLS_CERT_REQ(clientcertreq, cacertreq,
479                  "UK", "qemu", NULL, NULL, NULL, NULL,
480                  true, true, false,
481                  true, true,
482                  GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
483                  true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
484                  0, 0);
485 
486     TLS_CERT_REQ(clientcertaltreq, altcacertreq,
487                  "UK", "qemu", NULL, NULL, NULL, NULL,
488                  true, true, false,
489                  true, true,
490                  GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
491                  true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
492                  0, 0);
493 
494     TEST_SESS_REG(basicca, cacertreq.filename,
495                   servercertreq.filename, clientcertreq.filename,
496                   false, false, "qemu.org", NULL);
497     TEST_SESS_REG_EXT(differentca, cacertreq.filename,
498                       altcacertreq.filename, servercertreq.filename,
499                       clientcertaltreq.filename, true, true, "qemu.org", NULL);
500 
501 
502     /* When an altname is set, the CN is ignored, so it must be duplicated
503      * as an altname for it to match */
504     TLS_CERT_REQ(servercertalt1req, cacertreq,
505                  "UK", "qemu.org", "www.qemu.org", "qemu.org",
506                  "192.168.122.1", "fec0::dead:beaf",
507                  true, true, false,
508                  true, true,
509                  GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
510                  true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
511                  0, 0);
512     /* This intentionally doesn't replicate */
513     TLS_CERT_REQ(servercertalt2req, cacertreq,
514                  "UK", "qemu.org", "www.qemu.org", "wiki.qemu.org",
515                  "192.168.122.1", "fec0::dead:beaf",
516                  true, true, false,
517                  true, true,
518                  GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
519                  true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
520                  0, 0);
521 
522     TEST_SESS_REG(altname1, cacertreq.filename,
523                   servercertalt1req.filename, clientcertreq.filename,
524                   false, false, "qemu.org", NULL);
525     TEST_SESS_REG(altname2, cacertreq.filename,
526                   servercertalt1req.filename, clientcertreq.filename,
527                   false, false, "www.qemu.org", NULL);
528     TEST_SESS_REG(altname3, cacertreq.filename,
529                   servercertalt1req.filename, clientcertreq.filename,
530                   false, true, "wiki.qemu.org", NULL);
531 
532     TEST_SESS_REG(altname4, cacertreq.filename,
533                   servercertalt1req.filename, clientcertreq.filename,
534                   false, false, "192.168.122.1", NULL);
535     TEST_SESS_REG(altname5, cacertreq.filename,
536                   servercertalt1req.filename, clientcertreq.filename,
537                   false, false, "fec0::dead:beaf", NULL);
538 
539     TEST_SESS_REG(altname6, cacertreq.filename,
540                   servercertalt2req.filename, clientcertreq.filename,
541                   false, true, "qemu.org", NULL);
542     TEST_SESS_REG(altname7, cacertreq.filename,
543                   servercertalt2req.filename, clientcertreq.filename,
544                   false, false, "www.qemu.org", NULL);
545     TEST_SESS_REG(altname8, cacertreq.filename,
546                   servercertalt2req.filename, clientcertreq.filename,
547                   false, false, "wiki.qemu.org", NULL);
548 
549     const char *const wildcards1[] = {
550         "C=UK,CN=dogfood",
551         NULL,
552     };
553     const char *const wildcards2[] = {
554         "C=UK,CN=qemu",
555         NULL,
556     };
557     const char *const wildcards3[] = {
558         "C=UK,CN=dogfood",
559         "C=UK,CN=qemu",
560         NULL,
561     };
562     const char *const wildcards4[] = {
563         "C=UK,CN=qemustuff",
564         NULL,
565     };
566     const char *const wildcards5[] = {
567         "C=UK,CN=qemu*",
568         NULL,
569     };
570     const char *const wildcards6[] = {
571         "C=UK,CN=*emu*",
572         NULL,
573     };
574 
575     TEST_SESS_REG(wildcard1, cacertreq.filename,
576                   servercertreq.filename, clientcertreq.filename,
577                   true, false, "qemu.org", wildcards1);
578     TEST_SESS_REG(wildcard2, cacertreq.filename,
579                   servercertreq.filename, clientcertreq.filename,
580                   false, false, "qemu.org", wildcards2);
581     TEST_SESS_REG(wildcard3, cacertreq.filename,
582                   servercertreq.filename, clientcertreq.filename,
583                   false, false, "qemu.org", wildcards3);
584     TEST_SESS_REG(wildcard4, cacertreq.filename,
585                   servercertreq.filename, clientcertreq.filename,
586                   true, false, "qemu.org", wildcards4);
587     TEST_SESS_REG(wildcard5, cacertreq.filename,
588                   servercertreq.filename, clientcertreq.filename,
589                   false, false, "qemu.org", wildcards5);
590     TEST_SESS_REG(wildcard6, cacertreq.filename,
591                   servercertreq.filename, clientcertreq.filename,
592                   false, false, "qemu.org", wildcards6);
593 
594     TLS_ROOT_REQ(cacertrootreq,
595                  "UK", "qemu root", NULL, NULL, NULL, NULL,
596                  true, true, true,
597                  true, true, GNUTLS_KEY_KEY_CERT_SIGN,
598                  false, false, NULL, NULL,
599                  0, 0);
600     TLS_CERT_REQ(cacertlevel1areq, cacertrootreq,
601                  "UK", "qemu level 1a", NULL, NULL, NULL, NULL,
602                  true, true, true,
603                  true, true, GNUTLS_KEY_KEY_CERT_SIGN,
604                  false, false, NULL, NULL,
605                  0, 0);
606     TLS_CERT_REQ(cacertlevel1breq, cacertrootreq,
607                  "UK", "qemu level 1b", NULL, NULL, NULL, NULL,
608                  true, true, true,
609                  true, true, GNUTLS_KEY_KEY_CERT_SIGN,
610                  false, false, NULL, NULL,
611                  0, 0);
612     TLS_CERT_REQ(cacertlevel2areq, cacertlevel1areq,
613                  "UK", "qemu level 2a", NULL, NULL, NULL, NULL,
614                  true, true, true,
615                  true, true, GNUTLS_KEY_KEY_CERT_SIGN,
616                  false, false, NULL, NULL,
617                  0, 0);
618     TLS_CERT_REQ(servercertlevel3areq, cacertlevel2areq,
619                  "UK", "qemu.org", NULL, NULL, NULL, NULL,
620                  true, true, false,
621                  true, true,
622                  GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
623                  true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
624                  0, 0);
625     TLS_CERT_REQ(clientcertlevel2breq, cacertlevel1breq,
626                  "UK", "qemu client level 2b", NULL, NULL, NULL, NULL,
627                  true, true, false,
628                  true, true,
629                  GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
630                  true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
631                  0, 0);
632 
633     gnutls_x509_crt_t certchain[] = {
634         cacertrootreq.crt,
635         cacertlevel1areq.crt,
636         cacertlevel1breq.crt,
637         cacertlevel2areq.crt,
638     };
639 
640     test_tls_write_cert_chain(WORKDIR "cacertchain-sess.pem",
641                               certchain,
642                               G_N_ELEMENTS(certchain));
643 
644     TEST_SESS_REG(cachain, WORKDIR "cacertchain-sess.pem",
645                   servercertlevel3areq.filename, clientcertlevel2breq.filename,
646                   false, false, "qemu.org", NULL);
647 
648     ret = g_test_run();
649 
650     test_tls_discard_cert(&clientcertreq);
651     test_tls_discard_cert(&clientcertaltreq);
652 
653     test_tls_discard_cert(&servercertreq);
654     test_tls_discard_cert(&servercertalt1req);
655     test_tls_discard_cert(&servercertalt2req);
656 
657     test_tls_discard_cert(&cacertreq);
658     test_tls_discard_cert(&altcacertreq);
659 
660     test_tls_discard_cert(&cacertrootreq);
661     test_tls_discard_cert(&cacertlevel1areq);
662     test_tls_discard_cert(&cacertlevel1breq);
663     test_tls_discard_cert(&cacertlevel2areq);
664     test_tls_discard_cert(&servercertlevel3areq);
665     test_tls_discard_cert(&clientcertlevel2breq);
666     unlink(WORKDIR "cacertchain-sess.pem");
667 
668     test_tls_psk_cleanup(PSKFILE);
669     test_tls_cleanup(KEYFILE);
670     rmdir(WORKDIR);
671 
672     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
673 }
674