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_tls_handshake(tioc,
 103                              migration_tls_incoming_handshake,
 104                              NULL,
 105                              NULL);
 106}
 107
 108
 109static void migration_tls_outgoing_handshake(Object *src,
 110                                             Error *err,
 111                                             gpointer opaque)
 112{
 113    MigrationState *s = opaque;
 114    QIOChannel *ioc = QIO_CHANNEL(src);
 115
 116    if (err) {
 117        trace_migration_tls_outgoing_handshake_error(error_get_pretty(err));
 118        s->to_dst_file = NULL;
 119        migrate_fd_error(s, err);
 120    } else {
 121        trace_migration_tls_outgoing_handshake_complete();
 122        migration_channel_connect(s, ioc, NULL);
 123    }
 124    object_unref(OBJECT(ioc));
 125}
 126
 127
 128void migration_tls_channel_connect(MigrationState *s,
 129                                   QIOChannel *ioc,
 130                                   const char *hostname,
 131                                   Error **errp)
 132{
 133    QCryptoTLSCreds *creds;
 134    QIOChannelTLS *tioc;
 135
 136    creds = migration_tls_get_creds(
 137        s, QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT, errp);
 138    if (!creds) {
 139        return;
 140    }
 141
 142    if (s->parameters.tls_hostname) {
 143        hostname = s->parameters.tls_hostname;
 144    }
 145    if (!hostname) {
 146        error_setg(errp, "No hostname available for TLS");
 147        return;
 148    }
 149
 150    tioc = qio_channel_tls_new_client(
 151        ioc, creds, hostname, errp);
 152    if (!tioc) {
 153        return;
 154    }
 155
 156    trace_migration_tls_outgoing_handshake_start(hostname);
 157    qio_channel_tls_handshake(tioc,
 158                              migration_tls_outgoing_handshake,
 159                              s,
 160                              NULL);
 161}
 162