backup: Wire up qemu full pull backup commands over QMP
[libvirt/ericb.git] / tests / virnettlssessiontest.c
blob41abbe7eaf5a050157bea8f13c2587853cabb726
1 /*
2 * Copyright (C) 2011-2012, 2014 Red Hat, Inc.
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.
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.
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/>.
19 #include <config.h>
21 #include <fcntl.h>
22 #include <sys/socket.h>
24 #include "testutils.h"
25 #include "virnettlshelpers.h"
26 #include "virutil.h"
27 #include "virerror.h"
28 #include "viralloc.h"
29 #include "virlog.h"
30 #include "virfile.h"
31 #include "vircommand.h"
32 #include "virsocketaddr.h"
34 #if !defined WIN32 && HAVE_LIBTASN1_H && LIBGNUTLS_VERSION_NUMBER >= 0x020600
36 # define VIR_FROM_THIS VIR_FROM_RPC
38 VIR_LOG_INIT("tests.nettlssessiontest");
40 # define KEYFILE "key-sess.pem"
42 struct testTLSSessionData {
43 const char *servercacrt;
44 const char *clientcacrt;
45 const char *servercrt;
46 const char *clientcrt;
47 bool expectServerFail;
48 bool expectClientFail;
49 const char *hostname;
50 const char *const* wildcards;
54 static ssize_t testWrite(const char *buf, size_t len, void *opaque)
56 int *fd = opaque;
58 return write(*fd, buf, len);
61 static ssize_t testRead(char *buf, size_t len, void *opaque)
63 int *fd = opaque;
65 return read(*fd, buf, len);
69 * This tests validation checking of peer certificates
71 * This is replicating the checks that are done for an
72 * active TLS session after handshake completes. To
73 * simulate that we create our TLS contexts, skipping
74 * sanity checks. We then get a socketpair, and
75 * initiate a TLS session across them. Finally do
76 * actual cert validation tests
78 static int testTLSSessionInit(const void *opaque)
80 struct testTLSSessionData *data = (struct testTLSSessionData *)opaque;
81 virNetTLSContextPtr clientCtxt = NULL;
82 virNetTLSContextPtr serverCtxt = NULL;
83 virNetTLSSessionPtr clientSess = NULL;
84 virNetTLSSessionPtr serverSess = NULL;
85 int ret = -1;
86 int channel[2];
87 bool clientShake = false;
88 bool serverShake = false;
91 /* We'll use this for our fake client-server connection */
92 if (socketpair(AF_UNIX, SOCK_STREAM, 0, channel) < 0)
93 abort();
96 * We have an evil loop to do the handshake in a single
97 * thread, so we need these non-blocking to avoid deadlock
98 * of ourselves
100 ignore_value(virSetNonBlock(channel[0]));
101 ignore_value(virSetNonBlock(channel[1]));
104 /* We skip initial sanity checks here because we
105 * want to make sure that problems are being
106 * detected at the TLS session validation stage
108 serverCtxt = virNetTLSContextNewServer(data->servercacrt,
109 NULL,
110 data->servercrt,
111 KEYFILE,
112 data->wildcards,
113 "NORMAL",
114 false,
115 true);
117 clientCtxt = virNetTLSContextNewClient(data->clientcacrt,
118 NULL,
119 data->clientcrt,
120 KEYFILE,
121 "NORMAL",
122 false,
123 true);
125 if (!serverCtxt) {
126 VIR_WARN("Unexpected failure loading %s against %s",
127 data->servercacrt, data->servercrt);
128 goto cleanup;
130 if (!clientCtxt) {
131 VIR_WARN("Unexpected failure loading %s against %s",
132 data->clientcacrt, data->clientcrt);
133 goto cleanup;
137 /* Now the real part of the test, setup the sessions */
138 serverSess = virNetTLSSessionNew(serverCtxt, NULL);
139 clientSess = virNetTLSSessionNew(clientCtxt, data->hostname);
141 if (!serverSess) {
142 VIR_WARN("Unexpected failure using %s against %s",
143 data->servercacrt, data->servercrt);
144 goto cleanup;
146 if (!clientSess) {
147 VIR_WARN("Unexpected failure using %s against %s",
148 data->clientcacrt, data->clientcrt);
149 goto cleanup;
152 /* For handshake to work, we need to set the I/O callbacks
153 * to read/write over the socketpair
155 virNetTLSSessionSetIOCallbacks(serverSess, testWrite, testRead, &channel[0]);
156 virNetTLSSessionSetIOCallbacks(clientSess, testWrite, testRead, &channel[1]);
159 * Finally we loop around & around doing handshake on each
160 * session until we get an error, or the handshake completes.
161 * This relies on the socketpair being nonblocking to avoid
162 * deadlocking ourselves upon handshake
164 do {
165 int rv;
166 if (!serverShake) {
167 rv = virNetTLSSessionHandshake(serverSess);
168 if (rv < 0)
169 goto cleanup;
170 if (rv == VIR_NET_TLS_HANDSHAKE_COMPLETE)
171 serverShake = true;
173 if (!clientShake) {
174 rv = virNetTLSSessionHandshake(clientSess);
175 if (rv < 0)
176 goto cleanup;
177 if (rv == VIR_NET_TLS_HANDSHAKE_COMPLETE)
178 clientShake = true;
180 } while (!clientShake || !serverShake);
183 /* Finally make sure the server validation does what
184 * we were expecting
186 if (virNetTLSContextCheckCertificate(serverCtxt,
187 serverSess) < 0) {
188 if (!data->expectServerFail) {
189 VIR_WARN("Unexpected server cert check fail");
190 goto cleanup;
191 } else {
192 VIR_DEBUG("Got expected server cert fail");
194 } else {
195 if (data->expectServerFail) {
196 VIR_WARN("Expected server cert check fail");
197 goto cleanup;
198 } else {
199 VIR_DEBUG("No unexpected server cert fail");
204 * And the same for the client validation check
206 if (virNetTLSContextCheckCertificate(clientCtxt,
207 clientSess) < 0) {
208 if (!data->expectClientFail) {
209 VIR_WARN("Unexpected client cert check fail");
210 goto cleanup;
211 } else {
212 VIR_DEBUG("Got expected client cert fail");
214 } else {
215 if (data->expectClientFail) {
216 VIR_WARN("Expected client cert check fail");
217 goto cleanup;
218 } else {
219 VIR_DEBUG("No unexpected client cert fail");
223 ret = 0;
225 cleanup:
226 virObjectUnref(serverCtxt);
227 virObjectUnref(clientCtxt);
228 virObjectUnref(serverSess);
229 virObjectUnref(clientSess);
231 VIR_FORCE_CLOSE(channel[0]);
232 VIR_FORCE_CLOSE(channel[1]);
233 return ret;
237 static int
238 mymain(void)
240 int ret = 0;
242 setenv("GNUTLS_FORCE_FIPS_MODE", "2", 1);
244 testTLSInit(KEYFILE);
246 # define DO_SESS_TEST(_caCrt, _serverCrt, _clientCrt, _expectServerFail, \
247 _expectClientFail, _hostname, _wildcards) \
248 do { \
249 static struct testTLSSessionData data; \
250 data.servercacrt = _caCrt; \
251 data.clientcacrt = _caCrt; \
252 data.servercrt = _serverCrt; \
253 data.clientcrt = _clientCrt; \
254 data.expectServerFail = _expectServerFail; \
255 data.expectClientFail = _expectClientFail; \
256 data.hostname = _hostname; \
257 data.wildcards = _wildcards; \
258 if (virTestRun("TLS Session " #_serverCrt " + " #_clientCrt, \
259 testTLSSessionInit, &data) < 0) \
260 ret = -1; \
261 } while (0)
263 # define DO_SESS_TEST_EXT(_serverCaCrt, _clientCaCrt, _serverCrt, _clientCrt, \
264 _expectServerFail, _expectClientFail, \
265 _hostname, _wildcards) \
266 do { \
267 static struct testTLSSessionData data; \
268 data.servercacrt = _serverCaCrt; \
269 data.clientcacrt = _clientCaCrt; \
270 data.servercrt = _serverCrt; \
271 data.clientcrt = _clientCrt; \
272 data.expectServerFail = _expectServerFail; \
273 data.expectClientFail = _expectClientFail; \
274 data.hostname = _hostname; \
275 data.wildcards = _wildcards; \
276 if (virTestRun("TLS Session " #_serverCrt " + " #_clientCrt, \
277 testTLSSessionInit, &data) < 0) \
278 ret = -1; \
279 } while (0)
281 # define TLS_CERT_REQ(varname, cavarname, \
282 co, cn, an1, an2, ia1, ia2, bce, bcc, bci, \
283 kue, kuc, kuv, kpe, kpc, kpo1, kpo2, so, eo) \
284 static struct testTLSCertReq varname = { \
285 NULL, #varname "-sess.pem", \
286 co, cn, an1, an2, ia1, ia2, bce, bcc, bci, \
287 kue, kuc, kuv, kpe, kpc, kpo1, kpo2, so, so \
288 }; \
289 testTLSGenerateCert(&varname, cavarname.crt)
291 # define TLS_ROOT_REQ(varname, \
292 co, cn, an1, an2, ia1, ia2, bce, bcc, bci, \
293 kue, kuc, kuv, kpe, kpc, kpo1, kpo2, so, eo) \
294 static struct testTLSCertReq varname = { \
295 NULL, #varname "-sess.pem", \
296 co, cn, an1, an2, ia1, ia2, bce, bcc, bci, \
297 kue, kuc, kuv, kpe, kpc, kpo1, kpo2, so, so \
298 }; \
299 testTLSGenerateCert(&varname, NULL)
301 /* A perfect CA, perfect client & perfect server */
303 /* Basic:CA:critical */
304 TLS_ROOT_REQ(cacertreq,
305 "UK", "libvirt CA", NULL, NULL, NULL, NULL,
306 true, true, true,
307 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
308 false, false, NULL, NULL,
309 0, 0);
311 TLS_ROOT_REQ(altcacertreq,
312 "UK", "libvirt CA 1", NULL, NULL, NULL, NULL,
313 true, true, true,
314 false, false, 0,
315 false, false, NULL, NULL,
316 0, 0);
318 TLS_CERT_REQ(servercertreq, cacertreq,
319 "UK", "libvirt.org", NULL, NULL, NULL, NULL,
320 true, true, false,
321 true, true, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
322 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
323 0, 0);
324 TLS_CERT_REQ(clientcertreq, cacertreq,
325 "UK", "libvirt", NULL, NULL, NULL, NULL,
326 true, true, false,
327 true, true, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
328 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
329 0, 0);
331 TLS_CERT_REQ(clientcertaltreq, altcacertreq,
332 "UK", "libvirt", NULL, NULL, NULL, NULL,
333 true, true, false,
334 true, true, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
335 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
336 0, 0);
338 DO_SESS_TEST(cacertreq.filename, servercertreq.filename, clientcertreq.filename,
339 false, false, "libvirt.org", NULL);
340 DO_SESS_TEST_EXT(cacertreq.filename, altcacertreq.filename, servercertreq.filename,
341 clientcertaltreq.filename, true, true, "libvirt.org", NULL);
344 /* When an altname is set, the CN is ignored, so it must be duplicated
345 * as an altname for it to match */
346 TLS_CERT_REQ(servercertalt1req, cacertreq,
347 "UK", "libvirt.org", "www.libvirt.org", "libvirt.org", "192.168.122.1", "fec0::dead:beaf",
348 true, true, false,
349 true, true, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
350 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
351 0, 0);
352 /* This intentionally doesn't replicate */
353 TLS_CERT_REQ(servercertalt2req, cacertreq,
354 "UK", "libvirt.org", "www.libvirt.org", "wiki.libvirt.org", "192.168.122.1", "fec0::dead:beaf",
355 true, true, false,
356 true, true, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
357 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
358 0, 0);
360 DO_SESS_TEST(cacertreq.filename, servercertalt1req.filename, clientcertreq.filename,
361 false, false, "libvirt.org", NULL);
362 DO_SESS_TEST(cacertreq.filename, servercertalt1req.filename, clientcertreq.filename,
363 false, false, "www.libvirt.org", NULL);
364 DO_SESS_TEST(cacertreq.filename, servercertalt1req.filename, clientcertreq.filename,
365 false, true, "wiki.libvirt.org", NULL);
367 DO_SESS_TEST(cacertreq.filename, servercertalt2req.filename, clientcertreq.filename,
368 false, true, "libvirt.org", NULL);
369 DO_SESS_TEST(cacertreq.filename, servercertalt2req.filename, clientcertreq.filename,
370 false, false, "www.libvirt.org", NULL);
371 DO_SESS_TEST(cacertreq.filename, servercertalt2req.filename, clientcertreq.filename,
372 false, false, "wiki.libvirt.org", NULL);
374 const char *const wildcards1[] = {
375 "C=UK,CN=dogfood",
376 NULL,
378 const char *const wildcards2[] = {
379 "C=UK,CN=libvirt",
380 NULL,
382 const char *const wildcards3[] = {
383 "C=UK,CN=dogfood",
384 "C=UK,CN=libvirt",
385 NULL,
387 const char *const wildcards4[] = {
388 "C=UK,CN=libvirtstuff",
389 NULL,
391 const char *const wildcards5[] = {
392 "C=UK,CN=libvirt*",
393 NULL,
395 const char *const wildcards6[] = {
396 "C=UK,CN=*virt*",
397 NULL,
400 DO_SESS_TEST(cacertreq.filename, servercertreq.filename, clientcertreq.filename,
401 true, false, "libvirt.org", wildcards1);
402 DO_SESS_TEST(cacertreq.filename, servercertreq.filename, clientcertreq.filename,
403 false, false, "libvirt.org", wildcards2);
404 DO_SESS_TEST(cacertreq.filename, servercertreq.filename, clientcertreq.filename,
405 false, false, "libvirt.org", wildcards3);
406 DO_SESS_TEST(cacertreq.filename, servercertreq.filename, clientcertreq.filename,
407 true, false, "libvirt.org", wildcards4);
408 DO_SESS_TEST(cacertreq.filename, servercertreq.filename, clientcertreq.filename,
409 false, false, "libvirt.org", wildcards5);
410 DO_SESS_TEST(cacertreq.filename, servercertreq.filename, clientcertreq.filename,
411 false, false, "libvirt.org", wildcards6);
413 TLS_ROOT_REQ(cacertrootreq,
414 "UK", "libvirt root", NULL, NULL, NULL, NULL,
415 true, true, true,
416 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
417 false, false, NULL, NULL,
418 0, 0);
419 TLS_CERT_REQ(cacertlevel1areq, cacertrootreq,
420 "UK", "libvirt level 1a", NULL, NULL, NULL, NULL,
421 true, true, true,
422 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
423 false, false, NULL, NULL,
424 0, 0);
425 TLS_CERT_REQ(cacertlevel1breq, cacertrootreq,
426 "UK", "libvirt level 1b", NULL, NULL, NULL, NULL,
427 true, true, true,
428 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
429 false, false, NULL, NULL,
430 0, 0);
431 TLS_CERT_REQ(cacertlevel2areq, cacertlevel1areq,
432 "UK", "libvirt level 2a", NULL, NULL, NULL, NULL,
433 true, true, true,
434 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
435 false, false, NULL, NULL,
436 0, 0);
437 TLS_CERT_REQ(servercertlevel3areq, cacertlevel2areq,
438 "UK", "libvirt.org", NULL, NULL, NULL, NULL,
439 true, true, false,
440 true, true, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
441 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
442 0, 0);
443 TLS_CERT_REQ(clientcertlevel2breq, cacertlevel1breq,
444 "UK", "libvirt client level 2b", NULL, NULL, NULL, NULL,
445 true, true, false,
446 true, true, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
447 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
448 0, 0);
450 gnutls_x509_crt_t certchain[] = {
451 cacertrootreq.crt,
452 cacertlevel1areq.crt,
453 cacertlevel1breq.crt,
454 cacertlevel2areq.crt,
457 testTLSWriteCertChain("cacertchain-sess.pem",
458 certchain,
459 ARRAY_CARDINALITY(certchain));
461 DO_SESS_TEST("cacertchain-sess.pem", servercertlevel3areq.filename, clientcertlevel2breq.filename,
462 false, false, "libvirt.org", NULL);
464 testTLSDiscardCert(&clientcertreq);
465 testTLSDiscardCert(&clientcertaltreq);
467 testTLSDiscardCert(&servercertreq);
468 testTLSDiscardCert(&servercertalt1req);
469 testTLSDiscardCert(&servercertalt2req);
471 testTLSDiscardCert(&cacertreq);
472 testTLSDiscardCert(&altcacertreq);
474 testTLSDiscardCert(&cacertrootreq);
475 testTLSDiscardCert(&cacertlevel1areq);
476 testTLSDiscardCert(&cacertlevel1breq);
477 testTLSDiscardCert(&cacertlevel2areq);
478 testTLSDiscardCert(&servercertlevel3areq);
479 testTLSDiscardCert(&clientcertlevel2breq);
480 unlink("cacertchain-sess.pem");
482 testTLSCleanup(KEYFILE);
484 return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
487 VIR_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/virrandommock.so")
489 #else
492 main(void)
494 return EXIT_AM_SKIP;
497 #endif