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 #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 
40 static 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 
47 static ssize_t testRead(char *buf, size_t len, void *opaque)
48 {
49     int *fd = opaque;
50 
51     return read(*fd, buf, len);
52 }
53 
54 static 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 
75 static 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     /* We'll use this for our fake client-server connection */
87     ret = socketpair(AF_UNIX, SOCK_STREAM, 0, channel);
88     g_assert(ret == 0);
89 
90     /*
91      * We have an evil loop to do the handshake in a single
92      * thread, so we need these non-blocking to avoid deadlock
93      * of ourselves
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     /* Now the real part of the test, setup the sessions */
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     /* For handshake to work, we need to set the I/O callbacks
120      * to read/write over the socketpair
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      * Finally we loop around & around doing handshake on each
131      * session until we get an error, or the handshake completes.
132      * This relies on the socketpair being nonblocking to avoid
133      * deadlocking ourselves upon handshake
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     /* Finally make sure the server & client validation is successful. */
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 
175 struct 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 
186 static 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         /* We skip initial sanity checks here because we
203          * want to make sure that problems are being
204          * detected at the TLS session validation stage,
205          * and the test-crypto-tlscreds test already
206          * validate the sanity check code.
207          */
208         "sanity-check", "no",
209         NULL
210         );
211     return QCRYPTO_TLS_CREDS(creds);
212 }
213 
214 
215 /*
216  * This tests validation checking of peer certificates
217  *
218  * This is replicating the checks that are done for an
219  * active TLS session after handshake completes. To
220  * simulate that we create our TLS contexts, skipping
221  * sanity checks. We then get a socketpair, and
222  * initiate a TLS session across them. Finally do
223  * do actual cert validation tests
224  */
225 static 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     /* We'll use this for our fake client-server connection */
241     ret = socketpair(AF_UNIX, SOCK_STREAM, 0, channel);
242     g_assert(ret == 0);
243 
244     /*
245      * We have an evil loop to do the handshake in a single
246      * thread, so we need these non-blocking to avoid deadlock
247      * of ourselves
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     /* Now the real part of the test, setup the sessions */
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     /* For handshake to work, we need to set the I/O callbacks
314      * to read/write over the socketpair
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      * Finally we loop around & around doing handshake on each
325      * session until we get an error, or the handshake completes.
326      * This relies on the socketpair being nonblocking to avoid
327      * deadlocking ourselves upon handshake
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     /* Finally make sure the server validation does what
353      * we were expecting
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      * And the same for the client validation check
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 
395 int 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     g_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     /* Simple initial test using Pre-Shared Keys. */
409     g_test_add_func("/qcrypto/tlssession/psk",
410                     test_crypto_tls_session_psk);
411 
412     /* More complex tests using X.509 certificates. */
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     /* A perfect CA, perfect client & perfect server */
439 
440     /* Basic:CA:critical */
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     /* When an altname is set, the CN is ignored, so it must be duplicated
487      * as an altname for it to match */
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     /* This intentionally doesn't replicate */
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 /* ! QCRYPTO_HAVE_TLS_TEST_SUPPORT */
653 
654 int
655 main(void)
656 {
657     return EXIT_SUCCESS;
658 }
659 
660 #endif /* ! QCRYPTO_HAVE_TLS_TEST_SUPPORT */
661