cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

test-io-channel-tls.c (11651B)


      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
     23
     24#include "qemu/osdep.h"
     25
     26#include "crypto-tls-x509-helpers.h"
     27#include "io/channel-tls.h"
     28#include "io/channel-socket.h"
     29#include "io-channel-helpers.h"
     30#include "crypto/init.h"
     31#include "crypto/tlscredsx509.h"
     32#include "qapi/error.h"
     33#include "qemu/module.h"
     34#include "authz/list.h"
     35#include "qom/object_interfaces.h"
     36
     37#define WORKDIR "tests/test-io-channel-tls-work/"
     38#define KEYFILE WORKDIR "key-ctx.pem"
     39
     40struct QIOChannelTLSTestData {
     41    const char *servercacrt;
     42    const char *clientcacrt;
     43    const char *servercrt;
     44    const char *clientcrt;
     45    bool expectServerFail;
     46    bool expectClientFail;
     47    const char *hostname;
     48    const char *const *wildcards;
     49};
     50
     51struct QIOChannelTLSHandshakeData {
     52    bool finished;
     53    bool failed;
     54};
     55
     56static void test_tls_handshake_done(QIOTask *task,
     57                                    gpointer opaque)
     58{
     59    struct QIOChannelTLSHandshakeData *data = opaque;
     60
     61    data->finished = true;
     62    data->failed = qio_task_propagate_error(task, NULL);
     63}
     64
     65
     66static QCryptoTLSCreds *test_tls_creds_create(QCryptoTLSCredsEndpoint endpoint,
     67                                              const char *certdir)
     68{
     69    Object *parent = object_get_objects_root();
     70    Object *creds = object_new_with_props(
     71        TYPE_QCRYPTO_TLS_CREDS_X509,
     72        parent,
     73        (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
     74         "testtlscredsserver" : "testtlscredsclient"),
     75        &error_abort,
     76        "endpoint", (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
     77                     "server" : "client"),
     78        "dir", certdir,
     79        "verify-peer", "yes",
     80        "priority", "NORMAL",
     81        /* We skip initial sanity checks here because we
     82         * want to make sure that problems are being
     83         * detected at the TLS session validation stage,
     84         * and the test-crypto-tlscreds test already
     85         * validate the sanity check code.
     86         */
     87        "sanity-check", "no",
     88        NULL
     89        );
     90
     91    return QCRYPTO_TLS_CREDS(creds);
     92}
     93
     94
     95/*
     96 * This tests validation checking of peer certificates
     97 *
     98 * This is replicating the checks that are done for an
     99 * active TLS session after handshake completes. To
    100 * simulate that we create our TLS contexts, skipping
    101 * sanity checks. When then get a socketpair, and
    102 * initiate a TLS session across them. Finally do
    103 * do actual cert validation tests
    104 */
    105static void test_io_channel_tls(const void *opaque)
    106{
    107    struct QIOChannelTLSTestData *data =
    108        (struct QIOChannelTLSTestData *)opaque;
    109    QCryptoTLSCreds *clientCreds;
    110    QCryptoTLSCreds *serverCreds;
    111    QIOChannelTLS *clientChanTLS;
    112    QIOChannelTLS *serverChanTLS;
    113    QIOChannelSocket *clientChanSock;
    114    QIOChannelSocket *serverChanSock;
    115    QAuthZList *auth;
    116    const char * const *wildcards;
    117    int channel[2];
    118    struct QIOChannelTLSHandshakeData clientHandshake = { false, false };
    119    struct QIOChannelTLSHandshakeData serverHandshake = { false, false };
    120    QIOChannelTest *test;
    121    GMainContext *mainloop;
    122
    123    /* We'll use this for our fake client-server connection */
    124    g_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, channel) == 0);
    125
    126#define CLIENT_CERT_DIR "tests/test-io-channel-tls-client/"
    127#define SERVER_CERT_DIR "tests/test-io-channel-tls-server/"
    128    mkdir(CLIENT_CERT_DIR, 0700);
    129    mkdir(SERVER_CERT_DIR, 0700);
    130
    131    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
    132    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT);
    133    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY);
    134
    135    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
    136    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
    137    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);
    138
    139    g_assert(link(data->servercacrt,
    140                  SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0);
    141    g_assert(link(data->servercrt,
    142                  SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT) == 0);
    143    g_assert(link(KEYFILE,
    144                  SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY) == 0);
    145
    146    g_assert(link(data->clientcacrt,
    147                  CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0);
    148    g_assert(link(data->clientcrt,
    149                  CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT) == 0);
    150    g_assert(link(KEYFILE,
    151                  CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY) == 0);
    152
    153    clientCreds = test_tls_creds_create(
    154        QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
    155        CLIENT_CERT_DIR);
    156    g_assert(clientCreds != NULL);
    157
    158    serverCreds = test_tls_creds_create(
    159        QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
    160        SERVER_CERT_DIR);
    161    g_assert(serverCreds != NULL);
    162
    163    auth = qauthz_list_new("channeltlsacl",
    164                           QAUTHZ_LIST_POLICY_DENY,
    165                           &error_abort);
    166    wildcards = data->wildcards;
    167    while (wildcards && *wildcards) {
    168        qauthz_list_append_rule(auth, *wildcards,
    169                                QAUTHZ_LIST_POLICY_ALLOW,
    170                                QAUTHZ_LIST_FORMAT_GLOB,
    171                                &error_abort);
    172        wildcards++;
    173    }
    174
    175    clientChanSock = qio_channel_socket_new_fd(
    176        channel[0], &error_abort);
    177    g_assert(clientChanSock != NULL);
    178    serverChanSock = qio_channel_socket_new_fd(
    179        channel[1], &error_abort);
    180    g_assert(serverChanSock != NULL);
    181
    182    /*
    183     * We have an evil loop to do the handshake in a single
    184     * thread, so we need these non-blocking to avoid deadlock
    185     * of ourselves
    186     */
    187    qio_channel_set_blocking(QIO_CHANNEL(clientChanSock), false, NULL);
    188    qio_channel_set_blocking(QIO_CHANNEL(serverChanSock), false, NULL);
    189
    190    /* Now the real part of the test, setup the sessions */
    191    clientChanTLS = qio_channel_tls_new_client(
    192        QIO_CHANNEL(clientChanSock), clientCreds,
    193        data->hostname, &error_abort);
    194    g_assert(clientChanTLS != NULL);
    195
    196    serverChanTLS = qio_channel_tls_new_server(
    197        QIO_CHANNEL(serverChanSock), serverCreds,
    198        "channeltlsacl", &error_abort);
    199    g_assert(serverChanTLS != NULL);
    200
    201    qio_channel_tls_handshake(clientChanTLS,
    202                              test_tls_handshake_done,
    203                              &clientHandshake,
    204                              NULL,
    205                              NULL);
    206    qio_channel_tls_handshake(serverChanTLS,
    207                              test_tls_handshake_done,
    208                              &serverHandshake,
    209                              NULL,
    210                              NULL);
    211
    212    /*
    213     * Finally we loop around & around doing handshake on each
    214     * session until we get an error, or the handshake completes.
    215     * This relies on the socketpair being nonblocking to avoid
    216     * deadlocking ourselves upon handshake
    217     */
    218    mainloop = g_main_context_default();
    219    do {
    220        g_main_context_iteration(mainloop, TRUE);
    221    } while (!clientHandshake.finished ||
    222             !serverHandshake.finished);
    223
    224    g_assert(clientHandshake.failed == data->expectClientFail);
    225    g_assert(serverHandshake.failed == data->expectServerFail);
    226
    227    test = qio_channel_test_new();
    228    qio_channel_test_run_threads(test, false,
    229                                 QIO_CHANNEL(clientChanTLS),
    230                                 QIO_CHANNEL(serverChanTLS));
    231    qio_channel_test_validate(test);
    232
    233    test = qio_channel_test_new();
    234    qio_channel_test_run_threads(test, true,
    235                                 QIO_CHANNEL(clientChanTLS),
    236                                 QIO_CHANNEL(serverChanTLS));
    237    qio_channel_test_validate(test);
    238
    239    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
    240    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT);
    241    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY);
    242
    243    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
    244    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
    245    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);
    246
    247    rmdir(CLIENT_CERT_DIR);
    248    rmdir(SERVER_CERT_DIR);
    249
    250    object_unparent(OBJECT(serverCreds));
    251    object_unparent(OBJECT(clientCreds));
    252
    253    object_unref(OBJECT(serverChanTLS));
    254    object_unref(OBJECT(clientChanTLS));
    255
    256    object_unref(OBJECT(serverChanSock));
    257    object_unref(OBJECT(clientChanSock));
    258
    259    object_unparent(OBJECT(auth));
    260
    261    close(channel[0]);
    262    close(channel[1]);
    263}
    264
    265
    266int main(int argc, char **argv)
    267{
    268    int ret;
    269
    270    g_assert(qcrypto_init(NULL) == 0);
    271
    272    module_call_init(MODULE_INIT_QOM);
    273    g_test_init(&argc, &argv, NULL);
    274    g_setenv("GNUTLS_FORCE_FIPS_MODE", "2", 1);
    275
    276    mkdir(WORKDIR, 0700);
    277
    278    test_tls_init(KEYFILE);
    279
    280# define TEST_CHANNEL(name, caCrt,                                      \
    281                      serverCrt, clientCrt,                             \
    282                      expectServerFail, expectClientFail,               \
    283                      hostname, wildcards)                              \
    284    struct QIOChannelTLSTestData name = {                               \
    285        caCrt, caCrt, serverCrt, clientCrt,                             \
    286        expectServerFail, expectClientFail,                             \
    287        hostname, wildcards                                             \
    288    };                                                                  \
    289    g_test_add_data_func("/qio/channel/tls/" # name,                    \
    290                         &name, test_io_channel_tls);
    291
    292    /* A perfect CA, perfect client & perfect server */
    293
    294    /* Basic:CA:critical */
    295    TLS_ROOT_REQ(cacertreq,
    296                 "UK", "qemu CA", NULL, NULL, NULL, NULL,
    297                 true, true, true,
    298                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
    299                 false, false, NULL, NULL,
    300                 0, 0);
    301    TLS_CERT_REQ(servercertreq, cacertreq,
    302                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
    303                 true, true, false,
    304                 true, true,
    305                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
    306                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
    307                 0, 0);
    308    TLS_CERT_REQ(clientcertreq, cacertreq,
    309                 "UK", "qemu", NULL, NULL, NULL, NULL,
    310                 true, true, false,
    311                 true, true,
    312                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
    313                 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
    314                 0, 0);
    315
    316    const char *const wildcards[] = {
    317        "C=UK,CN=qemu*",
    318        NULL,
    319    };
    320    TEST_CHANNEL(basic, cacertreq.filename, servercertreq.filename,
    321                 clientcertreq.filename, false, false,
    322                 "qemu.org", wildcards);
    323
    324    ret = g_test_run();
    325
    326    test_tls_discard_cert(&clientcertreq);
    327    test_tls_discard_cert(&servercertreq);
    328    test_tls_discard_cert(&cacertreq);
    329
    330    test_tls_cleanup(KEYFILE);
    331    rmdir(WORKDIR);
    332
    333    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
    334}