xref: /openbmc/qemu/io/channel-tls.c (revision 9726687f2fdfe7ae4a3014d78c2b2f639f75e303)
1ed8ee42cSDaniel P. Berrange /*
2ed8ee42cSDaniel P. Berrange  * QEMU I/O channels TLS driver
3ed8ee42cSDaniel P. Berrange  *
4ed8ee42cSDaniel P. Berrange  * Copyright (c) 2015 Red Hat, Inc.
5ed8ee42cSDaniel P. Berrange  *
6ed8ee42cSDaniel P. Berrange  * This library is free software; you can redistribute it and/or
7ed8ee42cSDaniel P. Berrange  * modify it under the terms of the GNU Lesser General Public
8ed8ee42cSDaniel P. Berrange  * License as published by the Free Software Foundation; either
9c8198bd5SChetan Pant  * version 2.1 of the License, or (at your option) any later version.
10ed8ee42cSDaniel P. Berrange  *
11ed8ee42cSDaniel P. Berrange  * This library is distributed in the hope that it will be useful,
12ed8ee42cSDaniel P. Berrange  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13ed8ee42cSDaniel P. Berrange  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14ed8ee42cSDaniel P. Berrange  * Lesser General Public License for more details.
15ed8ee42cSDaniel P. Berrange  *
16ed8ee42cSDaniel P. Berrange  * You should have received a copy of the GNU Lesser General Public
17ed8ee42cSDaniel P. Berrange  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18ed8ee42cSDaniel P. Berrange  *
19ed8ee42cSDaniel P. Berrange  */
20ed8ee42cSDaniel P. Berrange 
21cae9fc56SPeter Maydell #include "qemu/osdep.h"
22da34e65cSMarkus Armbruster #include "qapi/error.h"
230b8fa32fSMarkus Armbruster #include "qemu/module.h"
24ed8ee42cSDaniel P. Berrange #include "io/channel-tls.h"
25ed8ee42cSDaniel P. Berrange #include "trace.h"
26e4d2bfb1SLukas Straub #include "qemu/atomic.h"
27ed8ee42cSDaniel P. Berrange 
28ed8ee42cSDaniel P. Berrange 
qio_channel_tls_write_handler(const char * buf,size_t len,void * opaque,Error ** errp)29ed8ee42cSDaniel P. Berrange static ssize_t qio_channel_tls_write_handler(const char *buf,
30ed8ee42cSDaniel P. Berrange                                              size_t len,
31*97f7bf11SDaniel P. Berrangé                                              void *opaque,
32*97f7bf11SDaniel P. Berrangé                                              Error **errp)
33ed8ee42cSDaniel P. Berrange {
34ed8ee42cSDaniel P. Berrange     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(opaque);
35ed8ee42cSDaniel P. Berrange     ssize_t ret;
36ed8ee42cSDaniel P. Berrange 
37*97f7bf11SDaniel P. Berrangé     ret = qio_channel_write(tioc->master, buf, len, errp);
38ed8ee42cSDaniel P. Berrange     if (ret == QIO_CHANNEL_ERR_BLOCK) {
39*97f7bf11SDaniel P. Berrangé         return QCRYPTO_TLS_SESSION_ERR_BLOCK;
40ed8ee42cSDaniel P. Berrange     } else if (ret < 0) {
41ed8ee42cSDaniel P. Berrange         return -1;
42ed8ee42cSDaniel P. Berrange     }
43ed8ee42cSDaniel P. Berrange     return ret;
44ed8ee42cSDaniel P. Berrange }
45ed8ee42cSDaniel P. Berrange 
qio_channel_tls_read_handler(char * buf,size_t len,void * opaque,Error ** errp)46ed8ee42cSDaniel P. Berrange static ssize_t qio_channel_tls_read_handler(char *buf,
47ed8ee42cSDaniel P. Berrange                                             size_t len,
48*97f7bf11SDaniel P. Berrangé                                             void *opaque,
49*97f7bf11SDaniel P. Berrangé                                             Error **errp)
50ed8ee42cSDaniel P. Berrange {
51ed8ee42cSDaniel P. Berrange     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(opaque);
52ed8ee42cSDaniel P. Berrange     ssize_t ret;
53ed8ee42cSDaniel P. Berrange 
54*97f7bf11SDaniel P. Berrangé     ret = qio_channel_read(tioc->master, buf, len, errp);
55ed8ee42cSDaniel P. Berrange     if (ret == QIO_CHANNEL_ERR_BLOCK) {
56*97f7bf11SDaniel P. Berrangé         return QCRYPTO_TLS_SESSION_ERR_BLOCK;
57ed8ee42cSDaniel P. Berrange     } else if (ret < 0) {
58ed8ee42cSDaniel P. Berrange         return -1;
59ed8ee42cSDaniel P. Berrange     }
60ed8ee42cSDaniel P. Berrange     return ret;
61ed8ee42cSDaniel P. Berrange }
62ed8ee42cSDaniel P. Berrange 
63ed8ee42cSDaniel P. Berrange 
64ed8ee42cSDaniel P. Berrange QIOChannelTLS *
qio_channel_tls_new_server(QIOChannel * master,QCryptoTLSCreds * creds,const char * aclname,Error ** errp)65ed8ee42cSDaniel P. Berrange qio_channel_tls_new_server(QIOChannel *master,
66ed8ee42cSDaniel P. Berrange                            QCryptoTLSCreds *creds,
67ed8ee42cSDaniel P. Berrange                            const char *aclname,
68ed8ee42cSDaniel P. Berrange                            Error **errp)
69ed8ee42cSDaniel P. Berrange {
70199e84deSEric Blake     QIOChannelTLS *tioc;
71199e84deSEric Blake     QIOChannel *ioc;
72ed8ee42cSDaniel P. Berrange 
73199e84deSEric Blake     tioc = QIO_CHANNEL_TLS(object_new(TYPE_QIO_CHANNEL_TLS));
74199e84deSEric Blake     ioc = QIO_CHANNEL(tioc);
75ed8ee42cSDaniel P. Berrange 
76199e84deSEric Blake     tioc->master = master;
77199e84deSEric Blake     ioc->follow_coroutine_ctx = master->follow_coroutine_ctx;
7886d063faSPeter Xu     if (qio_channel_has_feature(master, QIO_CHANNEL_FEATURE_SHUTDOWN)) {
79199e84deSEric Blake         qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN);
8086d063faSPeter Xu     }
81ed8ee42cSDaniel P. Berrange     object_ref(OBJECT(master));
82ed8ee42cSDaniel P. Berrange 
83199e84deSEric Blake     tioc->session = qcrypto_tls_session_new(
84ed8ee42cSDaniel P. Berrange         creds,
85ed8ee42cSDaniel P. Berrange         NULL,
86ed8ee42cSDaniel P. Berrange         aclname,
87ed8ee42cSDaniel P. Berrange         QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
88ed8ee42cSDaniel P. Berrange         errp);
89199e84deSEric Blake     if (!tioc->session) {
90ed8ee42cSDaniel P. Berrange         goto error;
91ed8ee42cSDaniel P. Berrange     }
92ed8ee42cSDaniel P. Berrange 
93ed8ee42cSDaniel P. Berrange     qcrypto_tls_session_set_callbacks(
94199e84deSEric Blake         tioc->session,
95ed8ee42cSDaniel P. Berrange         qio_channel_tls_write_handler,
96ed8ee42cSDaniel P. Berrange         qio_channel_tls_read_handler,
97199e84deSEric Blake         tioc);
98ed8ee42cSDaniel P. Berrange 
99199e84deSEric Blake     trace_qio_channel_tls_new_server(tioc, master, creds, aclname);
100199e84deSEric Blake     return tioc;
101ed8ee42cSDaniel P. Berrange 
102ed8ee42cSDaniel P. Berrange  error:
103199e84deSEric Blake     object_unref(OBJECT(tioc));
104ed8ee42cSDaniel P. Berrange     return NULL;
105ed8ee42cSDaniel P. Berrange }
106ed8ee42cSDaniel P. Berrange 
107ed8ee42cSDaniel P. Berrange QIOChannelTLS *
qio_channel_tls_new_client(QIOChannel * master,QCryptoTLSCreds * creds,const char * hostname,Error ** errp)108ed8ee42cSDaniel P. Berrange qio_channel_tls_new_client(QIOChannel *master,
109ed8ee42cSDaniel P. Berrange                            QCryptoTLSCreds *creds,
110ed8ee42cSDaniel P. Berrange                            const char *hostname,
111ed8ee42cSDaniel P. Berrange                            Error **errp)
112ed8ee42cSDaniel P. Berrange {
113ed8ee42cSDaniel P. Berrange     QIOChannelTLS *tioc;
114ed8ee42cSDaniel P. Berrange     QIOChannel *ioc;
115ed8ee42cSDaniel P. Berrange 
116ed8ee42cSDaniel P. Berrange     tioc = QIO_CHANNEL_TLS(object_new(TYPE_QIO_CHANNEL_TLS));
117ed8ee42cSDaniel P. Berrange     ioc = QIO_CHANNEL(tioc);
118ed8ee42cSDaniel P. Berrange 
119ed8ee42cSDaniel P. Berrange     tioc->master = master;
120199e84deSEric Blake     ioc->follow_coroutine_ctx = master->follow_coroutine_ctx;
121e413ae0cSFelipe Franciosi     if (qio_channel_has_feature(master, QIO_CHANNEL_FEATURE_SHUTDOWN)) {
122d8d3c7ccSFelipe Franciosi         qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN);
123ed8ee42cSDaniel P. Berrange     }
124ed8ee42cSDaniel P. Berrange     object_ref(OBJECT(master));
125ed8ee42cSDaniel P. Berrange 
126ed8ee42cSDaniel P. Berrange     tioc->session = qcrypto_tls_session_new(
127ed8ee42cSDaniel P. Berrange         creds,
128ed8ee42cSDaniel P. Berrange         hostname,
129ed8ee42cSDaniel P. Berrange         NULL,
130ed8ee42cSDaniel P. Berrange         QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
131ed8ee42cSDaniel P. Berrange         errp);
132ed8ee42cSDaniel P. Berrange     if (!tioc->session) {
133ed8ee42cSDaniel P. Berrange         goto error;
134ed8ee42cSDaniel P. Berrange     }
135ed8ee42cSDaniel P. Berrange 
136ed8ee42cSDaniel P. Berrange     qcrypto_tls_session_set_callbacks(
137ed8ee42cSDaniel P. Berrange         tioc->session,
138ed8ee42cSDaniel P. Berrange         qio_channel_tls_write_handler,
139ed8ee42cSDaniel P. Berrange         qio_channel_tls_read_handler,
140ed8ee42cSDaniel P. Berrange         tioc);
141ed8ee42cSDaniel P. Berrange 
142ed8ee42cSDaniel P. Berrange     trace_qio_channel_tls_new_client(tioc, master, creds, hostname);
143ed8ee42cSDaniel P. Berrange     return tioc;
144ed8ee42cSDaniel P. Berrange 
145ed8ee42cSDaniel P. Berrange  error:
146ed8ee42cSDaniel P. Berrange     object_unref(OBJECT(tioc));
147ed8ee42cSDaniel P. Berrange     return NULL;
148ed8ee42cSDaniel P. Berrange }
149ed8ee42cSDaniel P. Berrange 
1501939ccdaSPeter Xu struct QIOChannelTLSData {
1511939ccdaSPeter Xu     QIOTask *task;
1521939ccdaSPeter Xu     GMainContext *context;
1531939ccdaSPeter Xu };
1541939ccdaSPeter Xu typedef struct QIOChannelTLSData QIOChannelTLSData;
155ed8ee42cSDaniel P. Berrange 
156ed8ee42cSDaniel P. Berrange static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc,
157ed8ee42cSDaniel P. Berrange                                              GIOCondition condition,
158ed8ee42cSDaniel P. Berrange                                              gpointer user_data);
159ed8ee42cSDaniel P. Berrange 
qio_channel_tls_handshake_task(QIOChannelTLS * ioc,QIOTask * task,GMainContext * context)160ed8ee42cSDaniel P. Berrange static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc,
1611939ccdaSPeter Xu                                            QIOTask *task,
1621939ccdaSPeter Xu                                            GMainContext *context)
163ed8ee42cSDaniel P. Berrange {
164ed8ee42cSDaniel P. Berrange     Error *err = NULL;
165ed8ee42cSDaniel P. Berrange     QCryptoTLSSessionHandshakeStatus status;
166ed8ee42cSDaniel P. Berrange 
167ed8ee42cSDaniel P. Berrange     if (qcrypto_tls_session_handshake(ioc->session, &err) < 0) {
168ed8ee42cSDaniel P. Berrange         trace_qio_channel_tls_handshake_fail(ioc);
16960e705c5SDaniel P. Berrange         qio_task_set_error(task, err);
17060e705c5SDaniel P. Berrange         qio_task_complete(task);
17160e705c5SDaniel P. Berrange         return;
172ed8ee42cSDaniel P. Berrange     }
173ed8ee42cSDaniel P. Berrange 
174ed8ee42cSDaniel P. Berrange     status = qcrypto_tls_session_get_handshake_status(ioc->session);
175ed8ee42cSDaniel P. Berrange     if (status == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
176ed8ee42cSDaniel P. Berrange         trace_qio_channel_tls_handshake_complete(ioc);
177ed8ee42cSDaniel P. Berrange         if (qcrypto_tls_session_check_credentials(ioc->session,
178ed8ee42cSDaniel P. Berrange                                                   &err) < 0) {
179ed8ee42cSDaniel P. Berrange             trace_qio_channel_tls_credentials_deny(ioc);
18060e705c5SDaniel P. Berrange             qio_task_set_error(task, err);
18160e705c5SDaniel P. Berrange         } else {
182ed8ee42cSDaniel P. Berrange             trace_qio_channel_tls_credentials_allow(ioc);
18360e705c5SDaniel P. Berrange         }
184ed8ee42cSDaniel P. Berrange         qio_task_complete(task);
185ed8ee42cSDaniel P. Berrange     } else {
186ed8ee42cSDaniel P. Berrange         GIOCondition condition;
1871939ccdaSPeter Xu         QIOChannelTLSData *data = g_new0(typeof(*data), 1);
1881939ccdaSPeter Xu 
1891939ccdaSPeter Xu         data->task = task;
1901939ccdaSPeter Xu         data->context = context;
1911939ccdaSPeter Xu 
1921939ccdaSPeter Xu         if (context) {
1931939ccdaSPeter Xu             g_main_context_ref(context);
1941939ccdaSPeter Xu         }
1951939ccdaSPeter Xu 
196ed8ee42cSDaniel P. Berrange         if (status == QCRYPTO_TLS_HANDSHAKE_SENDING) {
197ed8ee42cSDaniel P. Berrange             condition = G_IO_OUT;
198ed8ee42cSDaniel P. Berrange         } else {
199ed8ee42cSDaniel P. Berrange             condition = G_IO_IN;
200ed8ee42cSDaniel P. Berrange         }
201ed8ee42cSDaniel P. Berrange 
202ed8ee42cSDaniel P. Berrange         trace_qio_channel_tls_handshake_pending(ioc, status);
20310be627dSDaniel P. Berrangé         ioc->hs_ioc_tag =
2041939ccdaSPeter Xu             qio_channel_add_watch_full(ioc->master,
205ed8ee42cSDaniel P. Berrange                                        condition,
206ed8ee42cSDaniel P. Berrange                                        qio_channel_tls_handshake_io,
2071939ccdaSPeter Xu                                        data,
2081939ccdaSPeter Xu                                        NULL,
2091939ccdaSPeter Xu                                        context);
210ed8ee42cSDaniel P. Berrange     }
211ed8ee42cSDaniel P. Berrange }
212ed8ee42cSDaniel P. Berrange 
213ed8ee42cSDaniel P. Berrange 
qio_channel_tls_handshake_io(QIOChannel * ioc,GIOCondition condition,gpointer user_data)214ed8ee42cSDaniel P. Berrange static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc,
215ed8ee42cSDaniel P. Berrange                                              GIOCondition condition,
216ed8ee42cSDaniel P. Berrange                                              gpointer user_data)
217ed8ee42cSDaniel P. Berrange {
2181939ccdaSPeter Xu     QIOChannelTLSData *data = user_data;
2191939ccdaSPeter Xu     QIOTask *task = data->task;
2201939ccdaSPeter Xu     GMainContext *context = data->context;
221ed8ee42cSDaniel P. Berrange     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(
222ed8ee42cSDaniel P. Berrange         qio_task_get_source(task));
223ed8ee42cSDaniel P. Berrange 
22410be627dSDaniel P. Berrangé     tioc->hs_ioc_tag = 0;
2251939ccdaSPeter Xu     g_free(data);
2261939ccdaSPeter Xu     qio_channel_tls_handshake_task(tioc, task, context);
2271939ccdaSPeter Xu 
2281939ccdaSPeter Xu     if (context) {
2291939ccdaSPeter Xu         g_main_context_unref(context);
2301939ccdaSPeter Xu     }
231ed8ee42cSDaniel P. Berrange 
232ed8ee42cSDaniel P. Berrange     return FALSE;
233ed8ee42cSDaniel P. Berrange }
234ed8ee42cSDaniel P. Berrange 
qio_channel_tls_handshake(QIOChannelTLS * ioc,QIOTaskFunc func,gpointer opaque,GDestroyNotify destroy,GMainContext * context)235ed8ee42cSDaniel P. Berrange void qio_channel_tls_handshake(QIOChannelTLS *ioc,
236ed8ee42cSDaniel P. Berrange                                QIOTaskFunc func,
237ed8ee42cSDaniel P. Berrange                                gpointer opaque,
2381939ccdaSPeter Xu                                GDestroyNotify destroy,
2391939ccdaSPeter Xu                                GMainContext *context)
240ed8ee42cSDaniel P. Berrange {
241ed8ee42cSDaniel P. Berrange     QIOTask *task;
242ed8ee42cSDaniel P. Berrange 
243ed8ee42cSDaniel P. Berrange     task = qio_task_new(OBJECT(ioc),
244ed8ee42cSDaniel P. Berrange                         func, opaque, destroy);
245ed8ee42cSDaniel P. Berrange 
246ed8ee42cSDaniel P. Berrange     trace_qio_channel_tls_handshake_start(ioc);
2471939ccdaSPeter Xu     qio_channel_tls_handshake_task(ioc, task, context);
248ed8ee42cSDaniel P. Berrange }
249ed8ee42cSDaniel P. Berrange 
250ed8ee42cSDaniel P. Berrange 
qio_channel_tls_init(Object * obj G_GNUC_UNUSED)251ed8ee42cSDaniel P. Berrange static void qio_channel_tls_init(Object *obj G_GNUC_UNUSED)
252ed8ee42cSDaniel P. Berrange {
253ed8ee42cSDaniel P. Berrange }
254ed8ee42cSDaniel P. Berrange 
255ed8ee42cSDaniel P. Berrange 
qio_channel_tls_finalize(Object * obj)256ed8ee42cSDaniel P. Berrange static void qio_channel_tls_finalize(Object *obj)
257ed8ee42cSDaniel P. Berrange {
258ed8ee42cSDaniel P. Berrange     QIOChannelTLS *ioc = QIO_CHANNEL_TLS(obj);
259ed8ee42cSDaniel P. Berrange 
260ed8ee42cSDaniel P. Berrange     object_unref(OBJECT(ioc->master));
261ed8ee42cSDaniel P. Berrange     qcrypto_tls_session_free(ioc->session);
262ed8ee42cSDaniel P. Berrange }
263ed8ee42cSDaniel P. Berrange 
264ed8ee42cSDaniel P. Berrange 
qio_channel_tls_readv(QIOChannel * ioc,const struct iovec * iov,size_t niov,int ** fds,size_t * nfds,int flags,Error ** errp)265ed8ee42cSDaniel P. Berrange static ssize_t qio_channel_tls_readv(QIOChannel *ioc,
266ed8ee42cSDaniel P. Berrange                                      const struct iovec *iov,
267ed8ee42cSDaniel P. Berrange                                      size_t niov,
268ed8ee42cSDaniel P. Berrange                                      int **fds,
269ed8ee42cSDaniel P. Berrange                                      size_t *nfds,
27084615a19Smanish.mishra                                      int flags,
271ed8ee42cSDaniel P. Berrange                                      Error **errp)
272ed8ee42cSDaniel P. Berrange {
273ed8ee42cSDaniel P. Berrange     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
274ed8ee42cSDaniel P. Berrange     size_t i;
275ed8ee42cSDaniel P. Berrange     ssize_t got = 0;
276ed8ee42cSDaniel P. Berrange 
277ed8ee42cSDaniel P. Berrange     for (i = 0 ; i < niov ; i++) {
27857941c9cSDaniel P. Berrangé         ssize_t ret = qcrypto_tls_session_read(
27957941c9cSDaniel P. Berrangé             tioc->session,
280ed8ee42cSDaniel P. Berrange             iov[i].iov_base,
28157941c9cSDaniel P. Berrangé             iov[i].iov_len,
28257941c9cSDaniel P. Berrangé             qatomic_load_acquire(&tioc->shutdown) & QIO_CHANNEL_SHUTDOWN_READ,
28357941c9cSDaniel P. Berrangé             errp);
28457941c9cSDaniel P. Berrangé         if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
285ed8ee42cSDaniel P. Berrange             if (got) {
286ed8ee42cSDaniel P. Berrange                 return got;
287ed8ee42cSDaniel P. Berrange             } else {
288ed8ee42cSDaniel P. Berrange                 return QIO_CHANNEL_ERR_BLOCK;
289ed8ee42cSDaniel P. Berrange             }
29057941c9cSDaniel P. Berrangé         } else if (ret < 0) {
291ed8ee42cSDaniel P. Berrange             return -1;
292ed8ee42cSDaniel P. Berrange         }
293ed8ee42cSDaniel P. Berrange         got += ret;
294ed8ee42cSDaniel P. Berrange         if (ret < iov[i].iov_len) {
295ed8ee42cSDaniel P. Berrange             break;
296ed8ee42cSDaniel P. Berrange         }
297ed8ee42cSDaniel P. Berrange     }
298ed8ee42cSDaniel P. Berrange     return got;
299ed8ee42cSDaniel P. Berrange }
300ed8ee42cSDaniel P. Berrange 
301ed8ee42cSDaniel P. Berrange 
qio_channel_tls_writev(QIOChannel * ioc,const struct iovec * iov,size_t niov,int * fds,size_t nfds,int flags,Error ** errp)302ed8ee42cSDaniel P. Berrange static ssize_t qio_channel_tls_writev(QIOChannel *ioc,
303ed8ee42cSDaniel P. Berrange                                       const struct iovec *iov,
304ed8ee42cSDaniel P. Berrange                                       size_t niov,
305ed8ee42cSDaniel P. Berrange                                       int *fds,
306ed8ee42cSDaniel P. Berrange                                       size_t nfds,
307b88651cbSLeonardo Bras                                       int flags,
308ed8ee42cSDaniel P. Berrange                                       Error **errp)
309ed8ee42cSDaniel P. Berrange {
310ed8ee42cSDaniel P. Berrange     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
311ed8ee42cSDaniel P. Berrange     size_t i;
312ed8ee42cSDaniel P. Berrange     ssize_t done = 0;
313ed8ee42cSDaniel P. Berrange 
314ed8ee42cSDaniel P. Berrange     for (i = 0 ; i < niov ; i++) {
315ed8ee42cSDaniel P. Berrange         ssize_t ret = qcrypto_tls_session_write(tioc->session,
316ed8ee42cSDaniel P. Berrange                                                 iov[i].iov_base,
31757941c9cSDaniel P. Berrangé                                                 iov[i].iov_len,
31857941c9cSDaniel P. Berrangé                                                 errp);
31957941c9cSDaniel P. Berrangé         if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
320ed8ee42cSDaniel P. Berrange             if (done) {
321ed8ee42cSDaniel P. Berrange                 return done;
322ed8ee42cSDaniel P. Berrange             } else {
323ed8ee42cSDaniel P. Berrange                 return QIO_CHANNEL_ERR_BLOCK;
324ed8ee42cSDaniel P. Berrange             }
32557941c9cSDaniel P. Berrangé         } else if (ret < 0) {
326ed8ee42cSDaniel P. Berrange             return -1;
327ed8ee42cSDaniel P. Berrange         }
328ed8ee42cSDaniel P. Berrange         done += ret;
329ed8ee42cSDaniel P. Berrange         if (ret < iov[i].iov_len) {
330ed8ee42cSDaniel P. Berrange             break;
331ed8ee42cSDaniel P. Berrange         }
332ed8ee42cSDaniel P. Berrange     }
333ed8ee42cSDaniel P. Berrange     return done;
334ed8ee42cSDaniel P. Berrange }
335ed8ee42cSDaniel P. Berrange 
qio_channel_tls_set_blocking(QIOChannel * ioc,bool enabled,Error ** errp)336ed8ee42cSDaniel P. Berrange static int qio_channel_tls_set_blocking(QIOChannel *ioc,
337ed8ee42cSDaniel P. Berrange                                         bool enabled,
338ed8ee42cSDaniel P. Berrange                                         Error **errp)
339ed8ee42cSDaniel P. Berrange {
340ed8ee42cSDaniel P. Berrange     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
341ed8ee42cSDaniel P. Berrange 
342ed8ee42cSDaniel P. Berrange     return qio_channel_set_blocking(tioc->master, enabled, errp);
343ed8ee42cSDaniel P. Berrange }
344ed8ee42cSDaniel P. Berrange 
qio_channel_tls_set_delay(QIOChannel * ioc,bool enabled)345ed8ee42cSDaniel P. Berrange static void qio_channel_tls_set_delay(QIOChannel *ioc,
346ed8ee42cSDaniel P. Berrange                                       bool enabled)
347ed8ee42cSDaniel P. Berrange {
348ed8ee42cSDaniel P. Berrange     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
349ed8ee42cSDaniel P. Berrange 
350ed8ee42cSDaniel P. Berrange     qio_channel_set_delay(tioc->master, enabled);
351ed8ee42cSDaniel P. Berrange }
352ed8ee42cSDaniel P. Berrange 
qio_channel_tls_set_cork(QIOChannel * ioc,bool enabled)353ed8ee42cSDaniel P. Berrange static void qio_channel_tls_set_cork(QIOChannel *ioc,
354ed8ee42cSDaniel P. Berrange                                      bool enabled)
355ed8ee42cSDaniel P. Berrange {
356ed8ee42cSDaniel P. Berrange     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
357ed8ee42cSDaniel P. Berrange 
358ed8ee42cSDaniel P. Berrange     qio_channel_set_cork(tioc->master, enabled);
359ed8ee42cSDaniel P. Berrange }
360ed8ee42cSDaniel P. Berrange 
qio_channel_tls_shutdown(QIOChannel * ioc,QIOChannelShutdown how,Error ** errp)361ed8ee42cSDaniel P. Berrange static int qio_channel_tls_shutdown(QIOChannel *ioc,
362ed8ee42cSDaniel P. Berrange                                     QIOChannelShutdown how,
363ed8ee42cSDaniel P. Berrange                                     Error **errp)
364ed8ee42cSDaniel P. Berrange {
365ed8ee42cSDaniel P. Berrange     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
366ed8ee42cSDaniel P. Berrange 
367e4d2bfb1SLukas Straub     qatomic_or(&tioc->shutdown, how);
368a2458b6fSDaniel P. Berrangé 
369ed8ee42cSDaniel P. Berrange     return qio_channel_shutdown(tioc->master, how, errp);
370ed8ee42cSDaniel P. Berrange }
371ed8ee42cSDaniel P. Berrange 
qio_channel_tls_close(QIOChannel * ioc,Error ** errp)372ed8ee42cSDaniel P. Berrange static int qio_channel_tls_close(QIOChannel *ioc,
373ed8ee42cSDaniel P. Berrange                                  Error **errp)
374ed8ee42cSDaniel P. Berrange {
375ed8ee42cSDaniel P. Berrange     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
376ed8ee42cSDaniel P. Berrange 
37710be627dSDaniel P. Berrangé     if (tioc->hs_ioc_tag) {
378003f1536SDaniel P. Berrangé         trace_qio_channel_tls_handshake_cancel(ioc);
37910be627dSDaniel P. Berrangé         g_clear_handle_id(&tioc->hs_ioc_tag, g_source_remove);
38010be627dSDaniel P. Berrangé     }
38110be627dSDaniel P. Berrangé 
382ed8ee42cSDaniel P. Berrange     return qio_channel_close(tioc->master, errp);
383ed8ee42cSDaniel P. Berrange }
384ed8ee42cSDaniel P. Berrange 
qio_channel_tls_set_aio_fd_handler(QIOChannel * ioc,AioContext * read_ctx,IOHandler * io_read,AioContext * write_ctx,IOHandler * io_write,void * opaque)385bf88c124SPaolo Bonzini static void qio_channel_tls_set_aio_fd_handler(QIOChannel *ioc,
38606e0f098SStefan Hajnoczi                                                AioContext *read_ctx,
387bf88c124SPaolo Bonzini                                                IOHandler *io_read,
38806e0f098SStefan Hajnoczi                                                AioContext *write_ctx,
389bf88c124SPaolo Bonzini                                                IOHandler *io_write,
390bf88c124SPaolo Bonzini                                                void *opaque)
391bf88c124SPaolo Bonzini {
392bf88c124SPaolo Bonzini     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
393bf88c124SPaolo Bonzini 
39406e0f098SStefan Hajnoczi     qio_channel_set_aio_fd_handler(tioc->master, read_ctx, io_read,
39506e0f098SStefan Hajnoczi             write_ctx, io_write, opaque);
396bf88c124SPaolo Bonzini }
397bf88c124SPaolo Bonzini 
398ffda5db6SAntoine Damhet typedef struct QIOChannelTLSSource QIOChannelTLSSource;
399ffda5db6SAntoine Damhet struct QIOChannelTLSSource {
400ffda5db6SAntoine Damhet     GSource parent;
401ffda5db6SAntoine Damhet     QIOChannelTLS *tioc;
402ffda5db6SAntoine Damhet };
403ffda5db6SAntoine Damhet 
404ffda5db6SAntoine Damhet static gboolean
qio_channel_tls_source_check(GSource * source)405ffda5db6SAntoine Damhet qio_channel_tls_source_check(GSource *source)
406ffda5db6SAntoine Damhet {
407ffda5db6SAntoine Damhet     QIOChannelTLSSource *tsource = (QIOChannelTLSSource *)source;
408ffda5db6SAntoine Damhet 
409ffda5db6SAntoine Damhet     return qcrypto_tls_session_check_pending(tsource->tioc->session) > 0;
410ffda5db6SAntoine Damhet }
411ffda5db6SAntoine Damhet 
412ffda5db6SAntoine Damhet static gboolean
qio_channel_tls_source_prepare(GSource * source,gint * timeout)413ffda5db6SAntoine Damhet qio_channel_tls_source_prepare(GSource *source, gint *timeout)
414ffda5db6SAntoine Damhet {
415ffda5db6SAntoine Damhet     *timeout = -1;
416ffda5db6SAntoine Damhet     return qio_channel_tls_source_check(source);
417ffda5db6SAntoine Damhet }
418ffda5db6SAntoine Damhet 
419ffda5db6SAntoine Damhet static gboolean
qio_channel_tls_source_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)420ffda5db6SAntoine Damhet qio_channel_tls_source_dispatch(GSource *source, GSourceFunc callback,
421ffda5db6SAntoine Damhet                                 gpointer user_data)
422ffda5db6SAntoine Damhet {
423ffda5db6SAntoine Damhet     return G_SOURCE_CONTINUE;
424ffda5db6SAntoine Damhet }
425ffda5db6SAntoine Damhet 
426ffda5db6SAntoine Damhet static void
qio_channel_tls_source_finalize(GSource * source)427ffda5db6SAntoine Damhet qio_channel_tls_source_finalize(GSource *source)
428ffda5db6SAntoine Damhet {
429ffda5db6SAntoine Damhet     QIOChannelTLSSource *tsource = (QIOChannelTLSSource *)source;
430ffda5db6SAntoine Damhet 
431ffda5db6SAntoine Damhet     object_unref(OBJECT(tsource->tioc));
432ffda5db6SAntoine Damhet }
433ffda5db6SAntoine Damhet 
434ffda5db6SAntoine Damhet static GSourceFuncs qio_channel_tls_source_funcs = {
435ffda5db6SAntoine Damhet     qio_channel_tls_source_prepare,
436ffda5db6SAntoine Damhet     qio_channel_tls_source_check,
437ffda5db6SAntoine Damhet     qio_channel_tls_source_dispatch,
438ffda5db6SAntoine Damhet     qio_channel_tls_source_finalize
439ffda5db6SAntoine Damhet };
440ffda5db6SAntoine Damhet 
441ffda5db6SAntoine Damhet static void
qio_channel_tls_read_watch(QIOChannelTLS * tioc,GSource * source)442ffda5db6SAntoine Damhet qio_channel_tls_read_watch(QIOChannelTLS *tioc, GSource *source)
443ffda5db6SAntoine Damhet {
444ffda5db6SAntoine Damhet     GSource *child;
445ffda5db6SAntoine Damhet     QIOChannelTLSSource *tlssource;
446ffda5db6SAntoine Damhet 
447ffda5db6SAntoine Damhet     child = g_source_new(&qio_channel_tls_source_funcs,
448ffda5db6SAntoine Damhet                           sizeof(QIOChannelTLSSource));
449ffda5db6SAntoine Damhet     tlssource = (QIOChannelTLSSource *)child;
450ffda5db6SAntoine Damhet 
451ffda5db6SAntoine Damhet     tlssource->tioc = tioc;
452ffda5db6SAntoine Damhet     object_ref(OBJECT(tioc));
453ffda5db6SAntoine Damhet 
454ffda5db6SAntoine Damhet     g_source_add_child_source(source, child);
455c3a2c84aSMatheus Tavares Bernardino     g_source_unref(child);
456ffda5db6SAntoine Damhet }
457ffda5db6SAntoine Damhet 
qio_channel_tls_create_watch(QIOChannel * ioc,GIOCondition condition)458ed8ee42cSDaniel P. Berrange static GSource *qio_channel_tls_create_watch(QIOChannel *ioc,
459ed8ee42cSDaniel P. Berrange                                              GIOCondition condition)
460ed8ee42cSDaniel P. Berrange {
461ed8ee42cSDaniel P. Berrange     QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
462ffda5db6SAntoine Damhet     GSource *source = qio_channel_create_watch(tioc->master, condition);
463ed8ee42cSDaniel P. Berrange 
464ffda5db6SAntoine Damhet     if (condition & G_IO_IN) {
465ffda5db6SAntoine Damhet         qio_channel_tls_read_watch(tioc, source);
466ffda5db6SAntoine Damhet     }
467ffda5db6SAntoine Damhet 
468ffda5db6SAntoine Damhet     return source;
469ed8ee42cSDaniel P. Berrange }
470ed8ee42cSDaniel P. Berrange 
471ed8ee42cSDaniel P. Berrange QCryptoTLSSession *
qio_channel_tls_get_session(QIOChannelTLS * ioc)472ed8ee42cSDaniel P. Berrange qio_channel_tls_get_session(QIOChannelTLS *ioc)
473ed8ee42cSDaniel P. Berrange {
474ed8ee42cSDaniel P. Berrange     return ioc->session;
475ed8ee42cSDaniel P. Berrange }
476ed8ee42cSDaniel P. Berrange 
qio_channel_tls_class_init(ObjectClass * klass,void * class_data G_GNUC_UNUSED)477ed8ee42cSDaniel P. Berrange static void qio_channel_tls_class_init(ObjectClass *klass,
478ed8ee42cSDaniel P. Berrange                                        void *class_data G_GNUC_UNUSED)
479ed8ee42cSDaniel P. Berrange {
480ed8ee42cSDaniel P. Berrange     QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
481ed8ee42cSDaniel P. Berrange 
482ed8ee42cSDaniel P. Berrange     ioc_klass->io_writev = qio_channel_tls_writev;
483ed8ee42cSDaniel P. Berrange     ioc_klass->io_readv = qio_channel_tls_readv;
484ed8ee42cSDaniel P. Berrange     ioc_klass->io_set_blocking = qio_channel_tls_set_blocking;
485ed8ee42cSDaniel P. Berrange     ioc_klass->io_set_delay = qio_channel_tls_set_delay;
486ed8ee42cSDaniel P. Berrange     ioc_klass->io_set_cork = qio_channel_tls_set_cork;
487ed8ee42cSDaniel P. Berrange     ioc_klass->io_close = qio_channel_tls_close;
488ed8ee42cSDaniel P. Berrange     ioc_klass->io_shutdown = qio_channel_tls_shutdown;
489ed8ee42cSDaniel P. Berrange     ioc_klass->io_create_watch = qio_channel_tls_create_watch;
490bf88c124SPaolo Bonzini     ioc_klass->io_set_aio_fd_handler = qio_channel_tls_set_aio_fd_handler;
491ed8ee42cSDaniel P. Berrange }
492ed8ee42cSDaniel P. Berrange 
493ed8ee42cSDaniel P. Berrange static const TypeInfo qio_channel_tls_info = {
494ed8ee42cSDaniel P. Berrange     .parent = TYPE_QIO_CHANNEL,
495ed8ee42cSDaniel P. Berrange     .name = TYPE_QIO_CHANNEL_TLS,
496ed8ee42cSDaniel P. Berrange     .instance_size = sizeof(QIOChannelTLS),
497ed8ee42cSDaniel P. Berrange     .instance_init = qio_channel_tls_init,
498ed8ee42cSDaniel P. Berrange     .instance_finalize = qio_channel_tls_finalize,
499ed8ee42cSDaniel P. Berrange     .class_init = qio_channel_tls_class_init,
500ed8ee42cSDaniel P. Berrange };
501ed8ee42cSDaniel P. Berrange 
qio_channel_tls_register_types(void)502ed8ee42cSDaniel P. Berrange static void qio_channel_tls_register_types(void)
503ed8ee42cSDaniel P. Berrange {
504ed8ee42cSDaniel P. Berrange     type_register_static(&qio_channel_tls_info);
505ed8ee42cSDaniel P. Berrange }
506ed8ee42cSDaniel P. Berrange 
507ed8ee42cSDaniel P. Berrange type_init(qio_channel_tls_register_types);
508