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