xref: /openbmc/qemu/io/channel-tls.c (revision 2e1cacfb)
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     QCryptoTLSSessionHandshakeStatus status;
166 
167     if (qcrypto_tls_session_handshake(ioc->session, &err) < 0) {
168         trace_qio_channel_tls_handshake_fail(ioc);
169         qio_task_set_error(task, err);
170         qio_task_complete(task);
171         return;
172     }
173 
174     status = qcrypto_tls_session_get_handshake_status(ioc->session);
175     if (status == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
176         trace_qio_channel_tls_handshake_complete(ioc);
177         if (qcrypto_tls_session_check_credentials(ioc->session,
178                                                   &err) < 0) {
179             trace_qio_channel_tls_credentials_deny(ioc);
180             qio_task_set_error(task, err);
181         } else {
182             trace_qio_channel_tls_credentials_allow(ioc);
183         }
184         qio_task_complete(task);
185     } else {
186         GIOCondition condition;
187         QIOChannelTLSData *data = g_new0(typeof(*data), 1);
188 
189         data->task = task;
190         data->context = context;
191 
192         if (context) {
193             g_main_context_ref(context);
194         }
195 
196         if (status == QCRYPTO_TLS_HANDSHAKE_SENDING) {
197             condition = G_IO_OUT;
198         } else {
199             condition = G_IO_IN;
200         }
201 
202         trace_qio_channel_tls_handshake_pending(ioc, status);
203         ioc->hs_ioc_tag =
204             qio_channel_add_watch_full(ioc->master,
205                                        condition,
206                                        qio_channel_tls_handshake_io,
207                                        data,
208                                        NULL,
209                                        context);
210     }
211 }
212 
213 
214 static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc,
215                                              GIOCondition condition,
216                                              gpointer user_data)
217 {
218     QIOChannelTLSData *data = user_data;
219     QIOTask *task = data->task;
220     GMainContext *context = data->context;
221     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(
222         qio_task_get_source(task));
223 
224     tioc->hs_ioc_tag = 0;
225     g_free(data);
226     qio_channel_tls_handshake_task(tioc, task, context);
227 
228     if (context) {
229         g_main_context_unref(context);
230     }
231 
232     return FALSE;
233 }
234 
235 void qio_channel_tls_handshake(QIOChannelTLS *ioc,
236                                QIOTaskFunc func,
237                                gpointer opaque,
238                                GDestroyNotify destroy,
239                                GMainContext *context)
240 {
241     QIOTask *task;
242 
243     task = qio_task_new(OBJECT(ioc),
244                         func, opaque, destroy);
245 
246     trace_qio_channel_tls_handshake_start(ioc);
247     qio_channel_tls_handshake_task(ioc, task, context);
248 }
249 
250 
251 static void qio_channel_tls_init(Object *obj G_GNUC_UNUSED)
252 {
253 }
254 
255 
256 static void qio_channel_tls_finalize(Object *obj)
257 {
258     QIOChannelTLS *ioc = QIO_CHANNEL_TLS(obj);
259 
260     object_unref(OBJECT(ioc->master));
261     qcrypto_tls_session_free(ioc->session);
262 }
263 
264 
265 static ssize_t qio_channel_tls_readv(QIOChannel *ioc,
266                                      const struct iovec *iov,
267                                      size_t niov,
268                                      int **fds,
269                                      size_t *nfds,
270                                      int flags,
271                                      Error **errp)
272 {
273     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
274     size_t i;
275     ssize_t got = 0;
276 
277     for (i = 0 ; i < niov ; i++) {
278         ssize_t ret = qcrypto_tls_session_read(
279             tioc->session,
280             iov[i].iov_base,
281             iov[i].iov_len,
282             qatomic_load_acquire(&tioc->shutdown) & QIO_CHANNEL_SHUTDOWN_READ,
283             errp);
284         if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
285             if (got) {
286                 return got;
287             } else {
288                 return QIO_CHANNEL_ERR_BLOCK;
289             }
290         } else if (ret < 0) {
291             return -1;
292         }
293         got += ret;
294         if (ret < iov[i].iov_len) {
295             break;
296         }
297     }
298     return got;
299 }
300 
301 
302 static ssize_t qio_channel_tls_writev(QIOChannel *ioc,
303                                       const struct iovec *iov,
304                                       size_t niov,
305                                       int *fds,
306                                       size_t nfds,
307                                       int flags,
308                                       Error **errp)
309 {
310     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
311     size_t i;
312     ssize_t done = 0;
313 
314     for (i = 0 ; i < niov ; i++) {
315         ssize_t ret = qcrypto_tls_session_write(tioc->session,
316                                                 iov[i].iov_base,
317                                                 iov[i].iov_len,
318                                                 errp);
319         if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
320             if (done) {
321                 return done;
322             } else {
323                 return QIO_CHANNEL_ERR_BLOCK;
324             }
325         } else if (ret < 0) {
326             return -1;
327         }
328         done += ret;
329         if (ret < iov[i].iov_len) {
330             break;
331         }
332     }
333     return done;
334 }
335 
336 static int qio_channel_tls_set_blocking(QIOChannel *ioc,
337                                         bool enabled,
338                                         Error **errp)
339 {
340     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
341 
342     return qio_channel_set_blocking(tioc->master, enabled, errp);
343 }
344 
345 static void qio_channel_tls_set_delay(QIOChannel *ioc,
346                                       bool enabled)
347 {
348     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
349 
350     qio_channel_set_delay(tioc->master, enabled);
351 }
352 
353 static void qio_channel_tls_set_cork(QIOChannel *ioc,
354                                      bool enabled)
355 {
356     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
357 
358     qio_channel_set_cork(tioc->master, enabled);
359 }
360 
361 static int qio_channel_tls_shutdown(QIOChannel *ioc,
362                                     QIOChannelShutdown how,
363                                     Error **errp)
364 {
365     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
366 
367     qatomic_or(&tioc->shutdown, how);
368 
369     return qio_channel_shutdown(tioc->master, how, errp);
370 }
371 
372 static int qio_channel_tls_close(QIOChannel *ioc,
373                                  Error **errp)
374 {
375     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
376 
377     if (tioc->hs_ioc_tag) {
378         trace_qio_channel_tls_handshake_cancel(ioc);
379         g_clear_handle_id(&tioc->hs_ioc_tag, g_source_remove);
380     }
381 
382     return qio_channel_close(tioc->master, errp);
383 }
384 
385 static void qio_channel_tls_set_aio_fd_handler(QIOChannel *ioc,
386                                                AioContext *read_ctx,
387                                                IOHandler *io_read,
388                                                AioContext *write_ctx,
389                                                IOHandler *io_write,
390                                                void *opaque)
391 {
392     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
393 
394     qio_channel_set_aio_fd_handler(tioc->master, read_ctx, io_read,
395             write_ctx, io_write, opaque);
396 }
397 
398 typedef struct QIOChannelTLSSource QIOChannelTLSSource;
399 struct QIOChannelTLSSource {
400     GSource parent;
401     QIOChannelTLS *tioc;
402 };
403 
404 static gboolean
405 qio_channel_tls_source_check(GSource *source)
406 {
407     QIOChannelTLSSource *tsource = (QIOChannelTLSSource *)source;
408 
409     return qcrypto_tls_session_check_pending(tsource->tioc->session) > 0;
410 }
411 
412 static gboolean
413 qio_channel_tls_source_prepare(GSource *source, gint *timeout)
414 {
415     *timeout = -1;
416     return qio_channel_tls_source_check(source);
417 }
418 
419 static gboolean
420 qio_channel_tls_source_dispatch(GSource *source, GSourceFunc callback,
421                                 gpointer user_data)
422 {
423     return G_SOURCE_CONTINUE;
424 }
425 
426 static void
427 qio_channel_tls_source_finalize(GSource *source)
428 {
429     QIOChannelTLSSource *tsource = (QIOChannelTLSSource *)source;
430 
431     object_unref(OBJECT(tsource->tioc));
432 }
433 
434 static GSourceFuncs qio_channel_tls_source_funcs = {
435     qio_channel_tls_source_prepare,
436     qio_channel_tls_source_check,
437     qio_channel_tls_source_dispatch,
438     qio_channel_tls_source_finalize
439 };
440 
441 static void
442 qio_channel_tls_read_watch(QIOChannelTLS *tioc, GSource *source)
443 {
444     GSource *child;
445     QIOChannelTLSSource *tlssource;
446 
447     child = g_source_new(&qio_channel_tls_source_funcs,
448                           sizeof(QIOChannelTLSSource));
449     tlssource = (QIOChannelTLSSource *)child;
450 
451     tlssource->tioc = tioc;
452     object_ref(OBJECT(tioc));
453 
454     g_source_add_child_source(source, child);
455     g_source_unref(child);
456 }
457 
458 static GSource *qio_channel_tls_create_watch(QIOChannel *ioc,
459                                              GIOCondition condition)
460 {
461     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
462     GSource *source = qio_channel_create_watch(tioc->master, condition);
463 
464     if (condition & G_IO_IN) {
465         qio_channel_tls_read_watch(tioc, source);
466     }
467 
468     return source;
469 }
470 
471 QCryptoTLSSession *
472 qio_channel_tls_get_session(QIOChannelTLS *ioc)
473 {
474     return ioc->session;
475 }
476 
477 static void qio_channel_tls_class_init(ObjectClass *klass,
478                                        void *class_data G_GNUC_UNUSED)
479 {
480     QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
481 
482     ioc_klass->io_writev = qio_channel_tls_writev;
483     ioc_klass->io_readv = qio_channel_tls_readv;
484     ioc_klass->io_set_blocking = qio_channel_tls_set_blocking;
485     ioc_klass->io_set_delay = qio_channel_tls_set_delay;
486     ioc_klass->io_set_cork = qio_channel_tls_set_cork;
487     ioc_klass->io_close = qio_channel_tls_close;
488     ioc_klass->io_shutdown = qio_channel_tls_shutdown;
489     ioc_klass->io_create_watch = qio_channel_tls_create_watch;
490     ioc_klass->io_set_aio_fd_handler = qio_channel_tls_set_aio_fd_handler;
491 }
492 
493 static const TypeInfo qio_channel_tls_info = {
494     .parent = TYPE_QIO_CHANNEL,
495     .name = TYPE_QIO_CHANNEL_TLS,
496     .instance_size = sizeof(QIOChannelTLS),
497     .instance_init = qio_channel_tls_init,
498     .instance_finalize = qio_channel_tls_finalize,
499     .class_init = qio_channel_tls_class_init,
500 };
501 
502 static void qio_channel_tls_register_types(void)
503 {
504     type_register_static(&qio_channel_tls_info);
505 }
506 
507 type_init(qio_channel_tls_register_types);
508