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