xref: /openbmc/qemu/io/channel-tls.c (revision 919c486c406a34823c6cef5438f1a13e2c79a7d5)
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 
qio_channel_tls_write_handler(const char * buf,size_t len,void * opaque,Error ** errp)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 
qio_channel_tls_read_handler(char * buf,size_t len,void * opaque,Error ** errp)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 *
qio_channel_tls_new_server(QIOChannel * master,QCryptoTLSCreds * creds,const char * aclname,Error ** errp)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 *
qio_channel_tls_new_client(QIOChannel * master,QCryptoTLSCreds * creds,const char * hostname,Error ** errp)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 
qio_channel_tls_handshake_task(QIOChannelTLS * ioc,QIOTask * task,GMainContext * context)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 
qio_channel_tls_handshake_io(QIOChannel * ioc,GIOCondition condition,gpointer user_data)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 
qio_channel_tls_handshake(QIOChannelTLS * ioc,QIOTaskFunc func,gpointer opaque,GDestroyNotify destroy,GMainContext * context)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 
qio_channel_tls_bye_task(QIOChannelTLS * ioc,QIOTask * task,GMainContext * context)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 
qio_channel_tls_bye_io(QIOChannel * ioc,GIOCondition condition,gpointer user_data)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 
propagate_error(QIOTask * task,gpointer opaque)321 static void propagate_error(QIOTask *task, gpointer opaque)
322 {
323     qio_task_propagate_error(task, opaque);
324 }
325 
qio_channel_tls_bye(QIOChannelTLS * ioc,Error ** errp)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 
qio_channel_tls_init(Object * obj G_GNUC_UNUSED)336 static void qio_channel_tls_init(Object *obj G_GNUC_UNUSED)
337 {
338 }
339 
340 
qio_channel_tls_finalize(Object * obj)341 static void qio_channel_tls_finalize(Object *obj)
342 {
343     QIOChannelTLS *ioc = QIO_CHANNEL_TLS(obj);
344 
345     object_unref(OBJECT(ioc->master));
346     qcrypto_tls_session_free(ioc->session);
347 }
348 
349 
qio_channel_tls_readv(QIOChannel * ioc,const struct iovec * iov,size_t niov,int ** fds,size_t * nfds,int flags,Error ** errp)350 static ssize_t qio_channel_tls_readv(QIOChannel *ioc,
351                                      const struct iovec *iov,
352                                      size_t niov,
353                                      int **fds,
354                                      size_t *nfds,
355                                      int flags,
356                                      Error **errp)
357 {
358     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
359     size_t i;
360     ssize_t got = 0;
361 
362     for (i = 0 ; i < niov ; i++) {
363         ssize_t ret = qcrypto_tls_session_read(
364             tioc->session,
365             iov[i].iov_base,
366             iov[i].iov_len,
367             flags & QIO_CHANNEL_READ_FLAG_RELAXED_EOF ||
368             qatomic_load_acquire(&tioc->shutdown) & QIO_CHANNEL_SHUTDOWN_READ,
369             errp);
370         if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
371             if (got) {
372                 return got;
373             } else {
374                 return QIO_CHANNEL_ERR_BLOCK;
375             }
376         } else if (ret < 0) {
377             return -1;
378         }
379         got += ret;
380         if (ret < iov[i].iov_len) {
381             break;
382         }
383     }
384     return got;
385 }
386 
387 
qio_channel_tls_writev(QIOChannel * ioc,const struct iovec * iov,size_t niov,int * fds,size_t nfds,int flags,Error ** errp)388 static ssize_t qio_channel_tls_writev(QIOChannel *ioc,
389                                       const struct iovec *iov,
390                                       size_t niov,
391                                       int *fds,
392                                       size_t nfds,
393                                       int flags,
394                                       Error **errp)
395 {
396     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
397     size_t i;
398     ssize_t done = 0;
399 
400     for (i = 0 ; i < niov ; i++) {
401         ssize_t ret = qcrypto_tls_session_write(tioc->session,
402                                                 iov[i].iov_base,
403                                                 iov[i].iov_len,
404                                                 errp);
405         if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
406             if (done) {
407                 return done;
408             } else {
409                 return QIO_CHANNEL_ERR_BLOCK;
410             }
411         } else if (ret < 0) {
412             return -1;
413         }
414         done += ret;
415         if (ret < iov[i].iov_len) {
416             break;
417         }
418     }
419     return done;
420 }
421 
qio_channel_tls_set_blocking(QIOChannel * ioc,bool enabled,Error ** errp)422 static int qio_channel_tls_set_blocking(QIOChannel *ioc,
423                                         bool enabled,
424                                         Error **errp)
425 {
426     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
427 
428     return qio_channel_set_blocking(tioc->master, enabled, errp);
429 }
430 
qio_channel_tls_set_delay(QIOChannel * ioc,bool enabled)431 static void qio_channel_tls_set_delay(QIOChannel *ioc,
432                                       bool enabled)
433 {
434     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
435 
436     qio_channel_set_delay(tioc->master, enabled);
437 }
438 
qio_channel_tls_set_cork(QIOChannel * ioc,bool enabled)439 static void qio_channel_tls_set_cork(QIOChannel *ioc,
440                                      bool enabled)
441 {
442     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
443 
444     qio_channel_set_cork(tioc->master, enabled);
445 }
446 
qio_channel_tls_shutdown(QIOChannel * ioc,QIOChannelShutdown how,Error ** errp)447 static int qio_channel_tls_shutdown(QIOChannel *ioc,
448                                     QIOChannelShutdown how,
449                                     Error **errp)
450 {
451     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
452 
453     qatomic_or(&tioc->shutdown, how);
454 
455     return qio_channel_shutdown(tioc->master, how, errp);
456 }
457 
qio_channel_tls_close(QIOChannel * ioc,Error ** errp)458 static int qio_channel_tls_close(QIOChannel *ioc,
459                                  Error **errp)
460 {
461     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
462 
463     if (tioc->hs_ioc_tag) {
464         trace_qio_channel_tls_handshake_cancel(ioc);
465         g_clear_handle_id(&tioc->hs_ioc_tag, g_source_remove);
466     }
467 
468     if (tioc->bye_ioc_tag) {
469         trace_qio_channel_tls_bye_cancel(ioc);
470         g_clear_handle_id(&tioc->bye_ioc_tag, g_source_remove);
471     }
472 
473     return qio_channel_close(tioc->master, errp);
474 }
475 
qio_channel_tls_set_aio_fd_handler(QIOChannel * ioc,AioContext * read_ctx,IOHandler * io_read,AioContext * write_ctx,IOHandler * io_write,void * opaque)476 static void qio_channel_tls_set_aio_fd_handler(QIOChannel *ioc,
477                                                AioContext *read_ctx,
478                                                IOHandler *io_read,
479                                                AioContext *write_ctx,
480                                                IOHandler *io_write,
481                                                void *opaque)
482 {
483     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
484 
485     qio_channel_set_aio_fd_handler(tioc->master, read_ctx, io_read,
486             write_ctx, io_write, opaque);
487 }
488 
489 typedef struct QIOChannelTLSSource QIOChannelTLSSource;
490 struct QIOChannelTLSSource {
491     GSource parent;
492     QIOChannelTLS *tioc;
493 };
494 
495 static gboolean
qio_channel_tls_source_check(GSource * source)496 qio_channel_tls_source_check(GSource *source)
497 {
498     QIOChannelTLSSource *tsource = (QIOChannelTLSSource *)source;
499 
500     return qcrypto_tls_session_check_pending(tsource->tioc->session) > 0;
501 }
502 
503 static gboolean
qio_channel_tls_source_prepare(GSource * source,gint * timeout)504 qio_channel_tls_source_prepare(GSource *source, gint *timeout)
505 {
506     *timeout = -1;
507     return qio_channel_tls_source_check(source);
508 }
509 
510 static gboolean
qio_channel_tls_source_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)511 qio_channel_tls_source_dispatch(GSource *source, GSourceFunc callback,
512                                 gpointer user_data)
513 {
514     return G_SOURCE_CONTINUE;
515 }
516 
517 static void
qio_channel_tls_source_finalize(GSource * source)518 qio_channel_tls_source_finalize(GSource *source)
519 {
520     QIOChannelTLSSource *tsource = (QIOChannelTLSSource *)source;
521 
522     object_unref(OBJECT(tsource->tioc));
523 }
524 
525 static GSourceFuncs qio_channel_tls_source_funcs = {
526     qio_channel_tls_source_prepare,
527     qio_channel_tls_source_check,
528     qio_channel_tls_source_dispatch,
529     qio_channel_tls_source_finalize
530 };
531 
532 static void
qio_channel_tls_read_watch(QIOChannelTLS * tioc,GSource * source)533 qio_channel_tls_read_watch(QIOChannelTLS *tioc, GSource *source)
534 {
535     GSource *child;
536     QIOChannelTLSSource *tlssource;
537 
538     child = g_source_new(&qio_channel_tls_source_funcs,
539                           sizeof(QIOChannelTLSSource));
540     tlssource = (QIOChannelTLSSource *)child;
541 
542     tlssource->tioc = tioc;
543     object_ref(OBJECT(tioc));
544 
545     g_source_add_child_source(source, child);
546     g_source_unref(child);
547 }
548 
qio_channel_tls_create_watch(QIOChannel * ioc,GIOCondition condition)549 static GSource *qio_channel_tls_create_watch(QIOChannel *ioc,
550                                              GIOCondition condition)
551 {
552     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
553     GSource *source = qio_channel_create_watch(tioc->master, condition);
554 
555     if (condition & G_IO_IN) {
556         qio_channel_tls_read_watch(tioc, source);
557     }
558 
559     return source;
560 }
561 
562 QCryptoTLSSession *
qio_channel_tls_get_session(QIOChannelTLS * ioc)563 qio_channel_tls_get_session(QIOChannelTLS *ioc)
564 {
565     return ioc->session;
566 }
567 
qio_channel_tls_class_init(ObjectClass * klass,const void * class_data G_GNUC_UNUSED)568 static void qio_channel_tls_class_init(ObjectClass *klass,
569                                        const void *class_data G_GNUC_UNUSED)
570 {
571     QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
572 
573     ioc_klass->io_writev = qio_channel_tls_writev;
574     ioc_klass->io_readv = qio_channel_tls_readv;
575     ioc_klass->io_set_blocking = qio_channel_tls_set_blocking;
576     ioc_klass->io_set_delay = qio_channel_tls_set_delay;
577     ioc_klass->io_set_cork = qio_channel_tls_set_cork;
578     ioc_klass->io_close = qio_channel_tls_close;
579     ioc_klass->io_shutdown = qio_channel_tls_shutdown;
580     ioc_klass->io_create_watch = qio_channel_tls_create_watch;
581     ioc_klass->io_set_aio_fd_handler = qio_channel_tls_set_aio_fd_handler;
582 }
583 
584 static const TypeInfo qio_channel_tls_info = {
585     .parent = TYPE_QIO_CHANNEL,
586     .name = TYPE_QIO_CHANNEL_TLS,
587     .instance_size = sizeof(QIOChannelTLS),
588     .instance_init = qio_channel_tls_init,
589     .instance_finalize = qio_channel_tls_finalize,
590     .class_init = qio_channel_tls_class_init,
591 };
592 
qio_channel_tls_register_types(void)593 static void qio_channel_tls_register_types(void)
594 {
595     type_register_static(&qio_channel_tls_info);
596 }
597 
598 type_init(qio_channel_tls_register_types);
599