qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

channel-tls.c (12743B)


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