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