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