test-io-channel-tls.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /*
  2. * QEMU I/O channel TLS test
  3. *
  4. * Copyright (C) 2015 Red Hat, Inc.
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library. If not, see
  18. * <http://www.gnu.org/licenses/>.
  19. *
  20. * Author: Daniel P. Berrange <berrange@redhat.com>
  21. */
  22. #include "qemu/osdep.h"
  23. #include "crypto-tls-x509-helpers.h"
  24. #include "io/channel-tls.h"
  25. #include "io/channel-socket.h"
  26. #include "io-channel-helpers.h"
  27. #include "crypto/init.h"
  28. #include "crypto/tlscredsx509.h"
  29. #include "qapi/error.h"
  30. #include "qemu/module.h"
  31. #include "authz/list.h"
  32. #include "qom/object_interfaces.h"
  33. #ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT
  34. #define WORKDIR "tests/test-io-channel-tls-work/"
  35. #define KEYFILE WORKDIR "key-ctx.pem"
  36. struct QIOChannelTLSTestData {
  37. const char *servercacrt;
  38. const char *clientcacrt;
  39. const char *servercrt;
  40. const char *clientcrt;
  41. bool expectServerFail;
  42. bool expectClientFail;
  43. const char *hostname;
  44. const char *const *wildcards;
  45. };
  46. struct QIOChannelTLSHandshakeData {
  47. bool finished;
  48. bool failed;
  49. };
  50. static void test_tls_handshake_done(QIOTask *task,
  51. gpointer opaque)
  52. {
  53. struct QIOChannelTLSHandshakeData *data = opaque;
  54. data->finished = true;
  55. data->failed = qio_task_propagate_error(task, NULL);
  56. }
  57. static QCryptoTLSCreds *test_tls_creds_create(QCryptoTLSCredsEndpoint endpoint,
  58. const char *certdir)
  59. {
  60. Object *parent = object_get_objects_root();
  61. Object *creds = object_new_with_props(
  62. TYPE_QCRYPTO_TLS_CREDS_X509,
  63. parent,
  64. (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
  65. "testtlscredsserver" : "testtlscredsclient"),
  66. &error_abort,
  67. "endpoint", (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
  68. "server" : "client"),
  69. "dir", certdir,
  70. "verify-peer", "yes",
  71. "priority", "NORMAL",
  72. /* We skip initial sanity checks here because we
  73. * want to make sure that problems are being
  74. * detected at the TLS session validation stage,
  75. * and the test-crypto-tlscreds test already
  76. * validate the sanity check code.
  77. */
  78. "sanity-check", "no",
  79. NULL
  80. );
  81. return QCRYPTO_TLS_CREDS(creds);
  82. }
  83. /*
  84. * This tests validation checking of peer certificates
  85. *
  86. * This is replicating the checks that are done for an
  87. * active TLS session after handshake completes. To
  88. * simulate that we create our TLS contexts, skipping
  89. * sanity checks. When then get a socketpair, and
  90. * initiate a TLS session across them. Finally do
  91. * do actual cert validation tests
  92. */
  93. static void test_io_channel_tls(const void *opaque)
  94. {
  95. struct QIOChannelTLSTestData *data =
  96. (struct QIOChannelTLSTestData *)opaque;
  97. QCryptoTLSCreds *clientCreds;
  98. QCryptoTLSCreds *serverCreds;
  99. QIOChannelTLS *clientChanTLS;
  100. QIOChannelTLS *serverChanTLS;
  101. QIOChannelSocket *clientChanSock;
  102. QIOChannelSocket *serverChanSock;
  103. QAuthZList *auth;
  104. const char * const *wildcards;
  105. int channel[2];
  106. struct QIOChannelTLSHandshakeData clientHandshake = { false, false };
  107. struct QIOChannelTLSHandshakeData serverHandshake = { false, false };
  108. QIOChannelTest *test;
  109. GMainContext *mainloop;
  110. /* We'll use this for our fake client-server connection */
  111. g_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, channel) == 0);
  112. #define CLIENT_CERT_DIR "tests/test-io-channel-tls-client/"
  113. #define SERVER_CERT_DIR "tests/test-io-channel-tls-server/"
  114. mkdir(CLIENT_CERT_DIR, 0700);
  115. mkdir(SERVER_CERT_DIR, 0700);
  116. unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
  117. unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT);
  118. unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY);
  119. unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
  120. unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
  121. unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);
  122. g_assert(link(data->servercacrt,
  123. SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0);
  124. g_assert(link(data->servercrt,
  125. SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT) == 0);
  126. g_assert(link(KEYFILE,
  127. SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY) == 0);
  128. g_assert(link(data->clientcacrt,
  129. CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0);
  130. g_assert(link(data->clientcrt,
  131. CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT) == 0);
  132. g_assert(link(KEYFILE,
  133. CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY) == 0);
  134. clientCreds = test_tls_creds_create(
  135. QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
  136. CLIENT_CERT_DIR);
  137. g_assert(clientCreds != NULL);
  138. serverCreds = test_tls_creds_create(
  139. QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
  140. SERVER_CERT_DIR);
  141. g_assert(serverCreds != NULL);
  142. auth = qauthz_list_new("channeltlsacl",
  143. QAUTHZ_LIST_POLICY_DENY,
  144. &error_abort);
  145. wildcards = data->wildcards;
  146. while (wildcards && *wildcards) {
  147. qauthz_list_append_rule(auth, *wildcards,
  148. QAUTHZ_LIST_POLICY_ALLOW,
  149. QAUTHZ_LIST_FORMAT_GLOB,
  150. &error_abort);
  151. wildcards++;
  152. }
  153. clientChanSock = qio_channel_socket_new_fd(
  154. channel[0], &error_abort);
  155. g_assert(clientChanSock != NULL);
  156. serverChanSock = qio_channel_socket_new_fd(
  157. channel[1], &error_abort);
  158. g_assert(serverChanSock != NULL);
  159. /*
  160. * We have an evil loop to do the handshake in a single
  161. * thread, so we need these non-blocking to avoid deadlock
  162. * of ourselves
  163. */
  164. qio_channel_set_blocking(QIO_CHANNEL(clientChanSock), false, NULL);
  165. qio_channel_set_blocking(QIO_CHANNEL(serverChanSock), false, NULL);
  166. /* Now the real part of the test, setup the sessions */
  167. clientChanTLS = qio_channel_tls_new_client(
  168. QIO_CHANNEL(clientChanSock), clientCreds,
  169. data->hostname, &error_abort);
  170. g_assert(clientChanTLS != NULL);
  171. serverChanTLS = qio_channel_tls_new_server(
  172. QIO_CHANNEL(serverChanSock), serverCreds,
  173. "channeltlsacl", &error_abort);
  174. g_assert(serverChanTLS != NULL);
  175. qio_channel_tls_handshake(clientChanTLS,
  176. test_tls_handshake_done,
  177. &clientHandshake,
  178. NULL,
  179. NULL);
  180. qio_channel_tls_handshake(serverChanTLS,
  181. test_tls_handshake_done,
  182. &serverHandshake,
  183. NULL,
  184. NULL);
  185. /*
  186. * Finally we loop around & around doing handshake on each
  187. * session until we get an error, or the handshake completes.
  188. * This relies on the socketpair being nonblocking to avoid
  189. * deadlocking ourselves upon handshake
  190. */
  191. mainloop = g_main_context_default();
  192. do {
  193. g_main_context_iteration(mainloop, TRUE);
  194. } while (!clientHandshake.finished ||
  195. !serverHandshake.finished);
  196. g_assert(clientHandshake.failed == data->expectClientFail);
  197. g_assert(serverHandshake.failed == data->expectServerFail);
  198. test = qio_channel_test_new();
  199. qio_channel_test_run_threads(test, false,
  200. QIO_CHANNEL(clientChanTLS),
  201. QIO_CHANNEL(serverChanTLS));
  202. qio_channel_test_validate(test);
  203. test = qio_channel_test_new();
  204. qio_channel_test_run_threads(test, true,
  205. QIO_CHANNEL(clientChanTLS),
  206. QIO_CHANNEL(serverChanTLS));
  207. qio_channel_test_validate(test);
  208. unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
  209. unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT);
  210. unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY);
  211. unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
  212. unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
  213. unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);
  214. rmdir(CLIENT_CERT_DIR);
  215. rmdir(SERVER_CERT_DIR);
  216. object_unparent(OBJECT(serverCreds));
  217. object_unparent(OBJECT(clientCreds));
  218. object_unref(OBJECT(serverChanTLS));
  219. object_unref(OBJECT(clientChanTLS));
  220. object_unref(OBJECT(serverChanSock));
  221. object_unref(OBJECT(clientChanSock));
  222. object_unparent(OBJECT(auth));
  223. close(channel[0]);
  224. close(channel[1]);
  225. }
  226. int main(int argc, char **argv)
  227. {
  228. int ret;
  229. g_assert(qcrypto_init(NULL) == 0);
  230. module_call_init(MODULE_INIT_QOM);
  231. g_test_init(&argc, &argv, NULL);
  232. setenv("GNUTLS_FORCE_FIPS_MODE", "2", 1);
  233. mkdir(WORKDIR, 0700);
  234. test_tls_init(KEYFILE);
  235. # define TEST_CHANNEL(name, caCrt, \
  236. serverCrt, clientCrt, \
  237. expectServerFail, expectClientFail, \
  238. hostname, wildcards) \
  239. struct QIOChannelTLSTestData name = { \
  240. caCrt, caCrt, serverCrt, clientCrt, \
  241. expectServerFail, expectClientFail, \
  242. hostname, wildcards \
  243. }; \
  244. g_test_add_data_func("/qio/channel/tls/" # name, \
  245. &name, test_io_channel_tls);
  246. /* A perfect CA, perfect client & perfect server */
  247. /* Basic:CA:critical */
  248. TLS_ROOT_REQ(cacertreq,
  249. "UK", "qemu CA", NULL, NULL, NULL, NULL,
  250. true, true, true,
  251. true, true, GNUTLS_KEY_KEY_CERT_SIGN,
  252. false, false, NULL, NULL,
  253. 0, 0);
  254. TLS_CERT_REQ(servercertreq, cacertreq,
  255. "UK", "qemu.org", NULL, NULL, NULL, NULL,
  256. true, true, false,
  257. true, true,
  258. GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
  259. true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
  260. 0, 0);
  261. TLS_CERT_REQ(clientcertreq, cacertreq,
  262. "UK", "qemu", NULL, NULL, NULL, NULL,
  263. true, true, false,
  264. true, true,
  265. GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
  266. true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
  267. 0, 0);
  268. const char *const wildcards[] = {
  269. "C=UK,CN=qemu*",
  270. NULL,
  271. };
  272. TEST_CHANNEL(basic, cacertreq.filename, servercertreq.filename,
  273. clientcertreq.filename, false, false,
  274. "qemu.org", wildcards);
  275. ret = g_test_run();
  276. test_tls_discard_cert(&clientcertreq);
  277. test_tls_discard_cert(&servercertreq);
  278. test_tls_discard_cert(&cacertreq);
  279. test_tls_cleanup(KEYFILE);
  280. rmdir(WORKDIR);
  281. return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
  282. }
  283. #else /* ! QCRYPTO_HAVE_TLS_TEST_SUPPORT */
  284. int
  285. main(void)
  286. {
  287. return EXIT_SUCCESS;
  288. }
  289. #endif /* ! QCRYPTO_HAVE_TLS_TEST_SUPPORT */