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