xref: /openbmc/qemu/io/channel-tls.c (revision 95f5c89e)
1 /*
2  * QEMU I/O channels TLS driver
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 "qapi/error.h"
23 #include "qemu/module.h"
24 #include "io/channel-tls.h"
25 #include "trace.h"
26 #include "qemu/atomic.h"
27 
28 
29 static ssize_t qio_channel_tls_write_handler(const char *buf,
30                                              size_t len,
31                                              void *opaque)
32 {
33     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(opaque);
34     ssize_t ret;
35 
36     ret = qio_channel_write(tioc->master, buf, len, NULL);
37     if (ret == QIO_CHANNEL_ERR_BLOCK) {
38         errno = EAGAIN;
39         return -1;
40     } else if (ret < 0) {
41         errno = EIO;
42         return -1;
43     }
44     return ret;
45 }
46 
47 static ssize_t qio_channel_tls_read_handler(char *buf,
48                                             size_t len,
49                                             void *opaque)
50 {
51     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(opaque);
52     ssize_t ret;
53 
54     ret = qio_channel_read(tioc->master, buf, len, NULL);
55     if (ret == QIO_CHANNEL_ERR_BLOCK) {
56         errno = EAGAIN;
57         return -1;
58     } else if (ret < 0) {
59         errno = EIO;
60         return -1;
61     }
62     return ret;
63 }
64 
65 
66 QIOChannelTLS *
67 qio_channel_tls_new_server(QIOChannel *master,
68                            QCryptoTLSCreds *creds,
69                            const char *aclname,
70                            Error **errp)
71 {
72     QIOChannelTLS *ioc;
73 
74     ioc = QIO_CHANNEL_TLS(object_new(TYPE_QIO_CHANNEL_TLS));
75 
76     ioc->master = master;
77     if (qio_channel_has_feature(master, QIO_CHANNEL_FEATURE_SHUTDOWN)) {
78         qio_channel_set_feature(QIO_CHANNEL(ioc), QIO_CHANNEL_FEATURE_SHUTDOWN);
79     }
80     object_ref(OBJECT(master));
81 
82     ioc->session = qcrypto_tls_session_new(
83         creds,
84         NULL,
85         aclname,
86         QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
87         errp);
88     if (!ioc->session) {
89         goto error;
90     }
91 
92     qcrypto_tls_session_set_callbacks(
93         ioc->session,
94         qio_channel_tls_write_handler,
95         qio_channel_tls_read_handler,
96         ioc);
97 
98     trace_qio_channel_tls_new_server(ioc, master, creds, aclname);
99     return ioc;
100 
101  error:
102     object_unref(OBJECT(ioc));
103     return NULL;
104 }
105 
106 QIOChannelTLS *
107 qio_channel_tls_new_client(QIOChannel *master,
108                            QCryptoTLSCreds *creds,
109                            const char *hostname,
110                            Error **errp)
111 {
112     QIOChannelTLS *tioc;
113     QIOChannel *ioc;
114 
115     tioc = QIO_CHANNEL_TLS(object_new(TYPE_QIO_CHANNEL_TLS));
116     ioc = QIO_CHANNEL(tioc);
117 
118     tioc->master = master;
119     if (qio_channel_has_feature(master, QIO_CHANNEL_FEATURE_SHUTDOWN)) {
120         qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN);
121     }
122     object_ref(OBJECT(master));
123 
124     tioc->session = qcrypto_tls_session_new(
125         creds,
126         hostname,
127         NULL,
128         QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
129         errp);
130     if (!tioc->session) {
131         goto error;
132     }
133 
134     qcrypto_tls_session_set_callbacks(
135         tioc->session,
136         qio_channel_tls_write_handler,
137         qio_channel_tls_read_handler,
138         tioc);
139 
140     trace_qio_channel_tls_new_client(tioc, master, creds, hostname);
141     return tioc;
142 
143  error:
144     object_unref(OBJECT(tioc));
145     return NULL;
146 }
147 
148 struct QIOChannelTLSData {
149     QIOTask *task;
150     GMainContext *context;
151 };
152 typedef struct QIOChannelTLSData QIOChannelTLSData;
153 
154 static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc,
155                                              GIOCondition condition,
156                                              gpointer user_data);
157 
158 static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc,
159                                            QIOTask *task,
160                                            GMainContext *context)
161 {
162     Error *err = NULL;
163     QCryptoTLSSessionHandshakeStatus status;
164 
165     if (qcrypto_tls_session_handshake(ioc->session, &err) < 0) {
166         trace_qio_channel_tls_handshake_fail(ioc);
167         qio_task_set_error(task, err);
168         qio_task_complete(task);
169         return;
170     }
171 
172     status = qcrypto_tls_session_get_handshake_status(ioc->session);
173     if (status == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
174         trace_qio_channel_tls_handshake_complete(ioc);
175         if (qcrypto_tls_session_check_credentials(ioc->session,
176                                                   &err) < 0) {
177             trace_qio_channel_tls_credentials_deny(ioc);
178             qio_task_set_error(task, err);
179         } else {
180             trace_qio_channel_tls_credentials_allow(ioc);
181         }
182         qio_task_complete(task);
183     } else {
184         GIOCondition condition;
185         QIOChannelTLSData *data = g_new0(typeof(*data), 1);
186 
187         data->task = task;
188         data->context = context;
189 
190         if (context) {
191             g_main_context_ref(context);
192         }
193 
194         if (status == QCRYPTO_TLS_HANDSHAKE_SENDING) {
195             condition = G_IO_OUT;
196         } else {
197             condition = G_IO_IN;
198         }
199 
200         trace_qio_channel_tls_handshake_pending(ioc, status);
201         ioc->hs_ioc_tag =
202             qio_channel_add_watch_full(ioc->master,
203                                        condition,
204                                        qio_channel_tls_handshake_io,
205                                        data,
206                                        NULL,
207                                        context);
208     }
209 }
210 
211 
212 static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc,
213                                              GIOCondition condition,
214                                              gpointer user_data)
215 {
216     QIOChannelTLSData *data = user_data;
217     QIOTask *task = data->task;
218     GMainContext *context = data->context;
219     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(
220         qio_task_get_source(task));
221 
222     tioc->hs_ioc_tag = 0;
223     g_free(data);
224     qio_channel_tls_handshake_task(tioc, task, context);
225 
226     if (context) {
227         g_main_context_unref(context);
228     }
229 
230     return FALSE;
231 }
232 
233 void qio_channel_tls_handshake(QIOChannelTLS *ioc,
234                                QIOTaskFunc func,
235                                gpointer opaque,
236                                GDestroyNotify destroy,
237                                GMainContext *context)
238 {
239     QIOTask *task;
240 
241     task = qio_task_new(OBJECT(ioc),
242                         func, opaque, destroy);
243 
244     trace_qio_channel_tls_handshake_start(ioc);
245     qio_channel_tls_handshake_task(ioc, task, context);
246 }
247 
248 
249 static void qio_channel_tls_init(Object *obj G_GNUC_UNUSED)
250 {
251 }
252 
253 
254 static void qio_channel_tls_finalize(Object *obj)
255 {
256     QIOChannelTLS *ioc = QIO_CHANNEL_TLS(obj);
257 
258     object_unref(OBJECT(ioc->master));
259     qcrypto_tls_session_free(ioc->session);
260 }
261 
262 
263 static ssize_t qio_channel_tls_readv(QIOChannel *ioc,
264                                      const struct iovec *iov,
265                                      size_t niov,
266                                      int **fds,
267                                      size_t *nfds,
268                                      int flags,
269                                      Error **errp)
270 {
271     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
272     size_t i;
273     ssize_t got = 0;
274 
275     for (i = 0 ; i < niov ; i++) {
276         ssize_t ret = qcrypto_tls_session_read(tioc->session,
277                                                iov[i].iov_base,
278                                                iov[i].iov_len);
279         if (ret < 0) {
280             if (errno == EAGAIN) {
281                 if (got) {
282                     return got;
283                 } else {
284                     return QIO_CHANNEL_ERR_BLOCK;
285                 }
286             } else if (errno == ECONNABORTED &&
287                        (qatomic_load_acquire(&tioc->shutdown) &
288                         QIO_CHANNEL_SHUTDOWN_READ)) {
289                 return 0;
290             }
291 
292             error_setg_errno(errp, errno,
293                              "Cannot read from TLS channel");
294             return -1;
295         }
296         got += ret;
297         if (ret < iov[i].iov_len) {
298             break;
299         }
300     }
301     return got;
302 }
303 
304 
305 static ssize_t qio_channel_tls_writev(QIOChannel *ioc,
306                                       const struct iovec *iov,
307                                       size_t niov,
308                                       int *fds,
309                                       size_t nfds,
310                                       int flags,
311                                       Error **errp)
312 {
313     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
314     size_t i;
315     ssize_t done = 0;
316 
317     for (i = 0 ; i < niov ; i++) {
318         ssize_t ret = qcrypto_tls_session_write(tioc->session,
319                                                 iov[i].iov_base,
320                                                 iov[i].iov_len);
321         if (ret <= 0) {
322             if (errno == EAGAIN) {
323                 if (done) {
324                     return done;
325                 } else {
326                     return QIO_CHANNEL_ERR_BLOCK;
327                 }
328             }
329 
330             error_setg_errno(errp, errno,
331                              "Cannot write to TLS channel");
332             return -1;
333         }
334         done += ret;
335         if (ret < iov[i].iov_len) {
336             break;
337         }
338     }
339     return done;
340 }
341 
342 static int qio_channel_tls_set_blocking(QIOChannel *ioc,
343                                         bool enabled,
344                                         Error **errp)
345 {
346     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
347 
348     return qio_channel_set_blocking(tioc->master, enabled, errp);
349 }
350 
351 static void qio_channel_tls_set_delay(QIOChannel *ioc,
352                                       bool enabled)
353 {
354     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
355 
356     qio_channel_set_delay(tioc->master, enabled);
357 }
358 
359 static void qio_channel_tls_set_cork(QIOChannel *ioc,
360                                      bool enabled)
361 {
362     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
363 
364     qio_channel_set_cork(tioc->master, enabled);
365 }
366 
367 static int qio_channel_tls_shutdown(QIOChannel *ioc,
368                                     QIOChannelShutdown how,
369                                     Error **errp)
370 {
371     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
372 
373     qatomic_or(&tioc->shutdown, how);
374 
375     return qio_channel_shutdown(tioc->master, how, errp);
376 }
377 
378 static int qio_channel_tls_close(QIOChannel *ioc,
379                                  Error **errp)
380 {
381     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
382 
383     if (tioc->hs_ioc_tag) {
384         g_clear_handle_id(&tioc->hs_ioc_tag, g_source_remove);
385     }
386 
387     return qio_channel_close(tioc->master, errp);
388 }
389 
390 static void qio_channel_tls_set_aio_fd_handler(QIOChannel *ioc,
391                                                AioContext *ctx,
392                                                IOHandler *io_read,
393                                                IOHandler *io_write,
394                                                void *opaque)
395 {
396     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
397 
398     qio_channel_set_aio_fd_handler(tioc->master, ctx, io_read, io_write, opaque);
399 }
400 
401 typedef struct QIOChannelTLSSource QIOChannelTLSSource;
402 struct QIOChannelTLSSource {
403     GSource parent;
404     QIOChannelTLS *tioc;
405 };
406 
407 static gboolean
408 qio_channel_tls_source_check(GSource *source)
409 {
410     QIOChannelTLSSource *tsource = (QIOChannelTLSSource *)source;
411 
412     return qcrypto_tls_session_check_pending(tsource->tioc->session) > 0;
413 }
414 
415 static gboolean
416 qio_channel_tls_source_prepare(GSource *source, gint *timeout)
417 {
418     *timeout = -1;
419     return qio_channel_tls_source_check(source);
420 }
421 
422 static gboolean
423 qio_channel_tls_source_dispatch(GSource *source, GSourceFunc callback,
424                                 gpointer user_data)
425 {
426     return G_SOURCE_CONTINUE;
427 }
428 
429 static void
430 qio_channel_tls_source_finalize(GSource *source)
431 {
432     QIOChannelTLSSource *tsource = (QIOChannelTLSSource *)source;
433 
434     object_unref(OBJECT(tsource->tioc));
435 }
436 
437 static GSourceFuncs qio_channel_tls_source_funcs = {
438     qio_channel_tls_source_prepare,
439     qio_channel_tls_source_check,
440     qio_channel_tls_source_dispatch,
441     qio_channel_tls_source_finalize
442 };
443 
444 static void
445 qio_channel_tls_read_watch(QIOChannelTLS *tioc, GSource *source)
446 {
447     GSource *child;
448     QIOChannelTLSSource *tlssource;
449 
450     child = g_source_new(&qio_channel_tls_source_funcs,
451                           sizeof(QIOChannelTLSSource));
452     tlssource = (QIOChannelTLSSource *)child;
453 
454     tlssource->tioc = tioc;
455     object_ref(OBJECT(tioc));
456 
457     g_source_add_child_source(source, child);
458     g_source_unref(child);
459 }
460 
461 static GSource *qio_channel_tls_create_watch(QIOChannel *ioc,
462                                              GIOCondition condition)
463 {
464     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
465     GSource *source = qio_channel_create_watch(tioc->master, condition);
466 
467     if (condition & G_IO_IN) {
468         qio_channel_tls_read_watch(tioc, source);
469     }
470 
471     return source;
472 }
473 
474 QCryptoTLSSession *
475 qio_channel_tls_get_session(QIOChannelTLS *ioc)
476 {
477     return ioc->session;
478 }
479 
480 static void qio_channel_tls_class_init(ObjectClass *klass,
481                                        void *class_data G_GNUC_UNUSED)
482 {
483     QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
484 
485     ioc_klass->io_writev = qio_channel_tls_writev;
486     ioc_klass->io_readv = qio_channel_tls_readv;
487     ioc_klass->io_set_blocking = qio_channel_tls_set_blocking;
488     ioc_klass->io_set_delay = qio_channel_tls_set_delay;
489     ioc_klass->io_set_cork = qio_channel_tls_set_cork;
490     ioc_klass->io_close = qio_channel_tls_close;
491     ioc_klass->io_shutdown = qio_channel_tls_shutdown;
492     ioc_klass->io_create_watch = qio_channel_tls_create_watch;
493     ioc_klass->io_set_aio_fd_handler = qio_channel_tls_set_aio_fd_handler;
494 }
495 
496 static const TypeInfo qio_channel_tls_info = {
497     .parent = TYPE_QIO_CHANNEL,
498     .name = TYPE_QIO_CHANNEL_TLS,
499     .instance_size = sizeof(QIOChannelTLS),
500     .instance_init = qio_channel_tls_init,
501     .instance_finalize = qio_channel_tls_finalize,
502     .class_init = qio_channel_tls_class_init,
503 };
504 
505 static void qio_channel_tls_register_types(void)
506 {
507     type_register_static(&qio_channel_tls_info);
508 }
509 
510 type_init(qio_channel_tls_register_types);
511