xref: /openbmc/qemu/io/channel-tls.c (revision 64c6e744)
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         trace_qio_channel_tls_handshake_cancel(ioc);
385         g_clear_handle_id(&tioc->hs_ioc_tag, g_source_remove);
386     }
387 
388     return qio_channel_close(tioc->master, errp);
389 }
390 
391 static void qio_channel_tls_set_aio_fd_handler(QIOChannel *ioc,
392                                                AioContext *read_ctx,
393                                                IOHandler *io_read,
394                                                AioContext *write_ctx,
395                                                IOHandler *io_write,
396                                                void *opaque)
397 {
398     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
399 
400     qio_channel_set_aio_fd_handler(tioc->master, read_ctx, io_read,
401             write_ctx, io_write, opaque);
402 }
403 
404 typedef struct QIOChannelTLSSource QIOChannelTLSSource;
405 struct QIOChannelTLSSource {
406     GSource parent;
407     QIOChannelTLS *tioc;
408 };
409 
410 static gboolean
411 qio_channel_tls_source_check(GSource *source)
412 {
413     QIOChannelTLSSource *tsource = (QIOChannelTLSSource *)source;
414 
415     return qcrypto_tls_session_check_pending(tsource->tioc->session) > 0;
416 }
417 
418 static gboolean
419 qio_channel_tls_source_prepare(GSource *source, gint *timeout)
420 {
421     *timeout = -1;
422     return qio_channel_tls_source_check(source);
423 }
424 
425 static gboolean
426 qio_channel_tls_source_dispatch(GSource *source, GSourceFunc callback,
427                                 gpointer user_data)
428 {
429     return G_SOURCE_CONTINUE;
430 }
431 
432 static void
433 qio_channel_tls_source_finalize(GSource *source)
434 {
435     QIOChannelTLSSource *tsource = (QIOChannelTLSSource *)source;
436 
437     object_unref(OBJECT(tsource->tioc));
438 }
439 
440 static GSourceFuncs qio_channel_tls_source_funcs = {
441     qio_channel_tls_source_prepare,
442     qio_channel_tls_source_check,
443     qio_channel_tls_source_dispatch,
444     qio_channel_tls_source_finalize
445 };
446 
447 static void
448 qio_channel_tls_read_watch(QIOChannelTLS *tioc, GSource *source)
449 {
450     GSource *child;
451     QIOChannelTLSSource *tlssource;
452 
453     child = g_source_new(&qio_channel_tls_source_funcs,
454                           sizeof(QIOChannelTLSSource));
455     tlssource = (QIOChannelTLSSource *)child;
456 
457     tlssource->tioc = tioc;
458     object_ref(OBJECT(tioc));
459 
460     g_source_add_child_source(source, child);
461     g_source_unref(child);
462 }
463 
464 static GSource *qio_channel_tls_create_watch(QIOChannel *ioc,
465                                              GIOCondition condition)
466 {
467     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
468     GSource *source = qio_channel_create_watch(tioc->master, condition);
469 
470     if (condition & G_IO_IN) {
471         qio_channel_tls_read_watch(tioc, source);
472     }
473 
474     return source;
475 }
476 
477 QCryptoTLSSession *
478 qio_channel_tls_get_session(QIOChannelTLS *ioc)
479 {
480     return ioc->session;
481 }
482 
483 static void qio_channel_tls_class_init(ObjectClass *klass,
484                                        void *class_data G_GNUC_UNUSED)
485 {
486     QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
487 
488     ioc_klass->io_writev = qio_channel_tls_writev;
489     ioc_klass->io_readv = qio_channel_tls_readv;
490     ioc_klass->io_set_blocking = qio_channel_tls_set_blocking;
491     ioc_klass->io_set_delay = qio_channel_tls_set_delay;
492     ioc_klass->io_set_cork = qio_channel_tls_set_cork;
493     ioc_klass->io_close = qio_channel_tls_close;
494     ioc_klass->io_shutdown = qio_channel_tls_shutdown;
495     ioc_klass->io_create_watch = qio_channel_tls_create_watch;
496     ioc_klass->io_set_aio_fd_handler = qio_channel_tls_set_aio_fd_handler;
497 }
498 
499 static const TypeInfo qio_channel_tls_info = {
500     .parent = TYPE_QIO_CHANNEL,
501     .name = TYPE_QIO_CHANNEL_TLS,
502     .instance_size = sizeof(QIOChannelTLS),
503     .instance_init = qio_channel_tls_init,
504     .instance_finalize = qio_channel_tls_finalize,
505     .class_init = qio_channel_tls_class_init,
506 };
507 
508 static void qio_channel_tls_register_types(void)
509 {
510     type_register_static(&qio_channel_tls_info);
511 }
512 
513 type_init(qio_channel_tls_register_types);
514