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