qemu/migration/tls.c
<<
>>
Prefs
   1/*
   2 * QEMU migration TLS support
   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 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 <http://www.gnu.org/licenses/>.
  18 *
  19 */
  20
  21#include "qemu/osdep.h"
  22#include "channel.h"
  23#include "migration.h"
  24#include "tls.h"
  25#include "io/channel-tls.h"
  26#include "crypto/tlscreds.h"
  27#include "qemu/error-report.h"
  28#include "qapi/error.h"
  29#include "trace.h"
  30
  31static QCryptoTLSCreds *
  32migration_tls_get_creds(MigrationState *s,
  33                        QCryptoTLSCredsEndpoint endpoint,
  34                        Error **errp)
  35{
  36    Object *creds;
  37    QCryptoTLSCreds *ret;
  38
  39    creds = object_resolve_path_component(
  40        object_get_objects_root(), s->parameters.tls_creds);
  41    if (!creds) {
  42        error_setg(errp, "No TLS credentials with id '%s'",
  43                   s->parameters.tls_creds);
  44        return NULL;
  45    }
  46    ret = (QCryptoTLSCreds *)object_dynamic_cast(
  47        creds, TYPE_QCRYPTO_TLS_CREDS);
  48    if (!ret) {
  49        error_setg(errp, "Object with id '%s' is not TLS credentials",
  50                   s->parameters.tls_creds);
  51        return NULL;
  52    }
  53    if (ret->endpoint != endpoint) {
  54        error_setg(errp,
  55                   "Expected TLS credentials for a %s endpoint",
  56                   endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT ?
  57                   "client" : "server");
  58        return NULL;
  59    }
  60
  61    object_ref(OBJECT(ret));
  62    return ret;
  63}
  64
  65
  66static void migration_tls_incoming_handshake(QIOTask *task,
  67                                             gpointer opaque)
  68{
  69    QIOChannel *ioc = QIO_CHANNEL(qio_task_get_source(task));
  70    Error *err = NULL;
  71
  72    if (qio_task_propagate_error(task, &err)) {
  73        trace_migration_tls_incoming_handshake_error(error_get_pretty(err));
  74        error_report_err(err);
  75    } else {
  76        trace_migration_tls_incoming_handshake_complete();
  77        migration_channel_process_incoming(ioc);
  78    }
  79    object_unref(OBJECT(ioc));
  80}
  81
  82void migration_tls_channel_process_incoming(MigrationState *s,
  83                                            QIOChannel *ioc,
  84                                            Error **errp)
  85{
  86    QCryptoTLSCreds *creds;
  87    QIOChannelTLS *tioc;
  88
  89    creds = migration_tls_get_creds(
  90        s, QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, errp);
  91    if (!creds) {
  92        return;
  93    }
  94
  95    tioc = qio_channel_tls_new_server(
  96        ioc, creds,
  97        s->parameters.tls_authz,
  98        errp);
  99    if (!tioc) {
 100        return;
 101    }
 102
 103    trace_migration_tls_incoming_handshake_start();
 104    qio_channel_set_name(QIO_CHANNEL(tioc), "migration-tls-incoming");
 105    qio_channel_tls_handshake(tioc,
 106                              migration_tls_incoming_handshake,
 107                              NULL,
 108                              NULL,
 109                              NULL);
 110}
 111
 112
 113static void migration_tls_outgoing_handshake(QIOTask *task,
 114                                             gpointer opaque)
 115{
 116    MigrationState *s = opaque;
 117    QIOChannel *ioc = QIO_CHANNEL(qio_task_get_source(task));
 118    Error *err = NULL;
 119
 120    if (qio_task_propagate_error(task, &err)) {
 121        trace_migration_tls_outgoing_handshake_error(error_get_pretty(err));
 122    } else {
 123        trace_migration_tls_outgoing_handshake_complete();
 124    }
 125    migration_channel_connect(s, ioc, NULL, err);
 126    object_unref(OBJECT(ioc));
 127}
 128
 129
 130void migration_tls_channel_connect(MigrationState *s,
 131                                   QIOChannel *ioc,
 132                                   const char *hostname,
 133                                   Error **errp)
 134{
 135    QCryptoTLSCreds *creds;
 136    QIOChannelTLS *tioc;
 137
 138    creds = migration_tls_get_creds(
 139        s, QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT, errp);
 140    if (!creds) {
 141        return;
 142    }
 143
 144    if (s->parameters.tls_hostname && *s->parameters.tls_hostname) {
 145        hostname = s->parameters.tls_hostname;
 146    }
 147    if (!hostname) {
 148        error_setg(errp, "No hostname available for TLS");
 149        return;
 150    }
 151
 152    tioc = qio_channel_tls_new_client(
 153        ioc, creds, hostname, errp);
 154    if (!tioc) {
 155        return;
 156    }
 157
 158    trace_migration_tls_outgoing_handshake_start(hostname);
 159    qio_channel_set_name(QIO_CHANNEL(tioc), "migration-tls-outgoing");
 160    qio_channel_tls_handshake(tioc,
 161                              migration_tls_outgoing_handshake,
 162                              s,
 163                              NULL,
 164                              NULL);
 165}
 166