qemu/io/channel-tls.c
<<
>>
Prefs
   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
  29static 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
  46static 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
  64QIOChannelTLS *
  65qio_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
 107QIOChannelTLS *
 108qio_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
 150struct QIOChannelTLSData {
 151    QIOTask *task;
 152    GMainContext *context;
 153};
 154typedef struct QIOChannelTLSData QIOChannelTLSData;
 155
 156static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc,
 157                                             GIOCondition condition,
 158                                             gpointer user_data);
 159
 160static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc,
 161                                           QIOTask *task,
 162                                           GMainContext *context)
 163{
 164    Error *err = NULL;
 165    int status;
 166
 167    status = qcrypto_tls_session_handshake(ioc->session, &err);
 168
 169    if (status < 0) {
 170        trace_qio_channel_tls_handshake_fail(ioc);
 171        qio_task_set_error(task, err);
 172        qio_task_complete(task);
 173        return;
 174    }
 175
 176    if (status == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
 177        trace_qio_channel_tls_handshake_complete(ioc);
 178        if (qcrypto_tls_session_check_credentials(ioc->session,
 179                                                  &err) < 0) {
 180            trace_qio_channel_tls_credentials_deny(ioc);
 181            qio_task_set_error(task, err);
 182        } else {
 183            trace_qio_channel_tls_credentials_allow(ioc);
 184        }
 185        qio_task_complete(task);
 186    } else {
 187        GIOCondition condition;
 188        QIOChannelTLSData *data = g_new0(typeof(*data), 1);
 189
 190        data->task = task;
 191        data->context = context;
 192
 193        if (context) {
 194            g_main_context_ref(context);
 195        }
 196
 197        if (status == QCRYPTO_TLS_HANDSHAKE_SENDING) {
 198            condition = G_IO_OUT;
 199        } else {
 200            condition = G_IO_IN;
 201        }
 202
 203        trace_qio_channel_tls_handshake_pending(ioc, status);
 204        ioc->hs_ioc_tag =
 205            qio_channel_add_watch_full(ioc->master,
 206                                       condition,
 207                                       qio_channel_tls_handshake_io,
 208                                       data,
 209                                       NULL,
 210                                       context);
 211    }
 212}
 213
 214
 215static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc,
 216                                             GIOCondition condition,
 217                                             gpointer user_data)
 218{
 219    QIOChannelTLSData *data = user_data;
 220    QIOTask *task = data->task;
 221    GMainContext *context = data->context;
 222    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(
 223        qio_task_get_source(task));
 224
 225    tioc->hs_ioc_tag = 0;
 226    g_free(data);
 227    qio_channel_tls_handshake_task(tioc, task, context);
 228
 229    if (context) {
 230        g_main_context_unref(context);
 231    }
 232
 233    return FALSE;
 234}
 235
 236void qio_channel_tls_handshake(QIOChannelTLS *ioc,
 237                               QIOTaskFunc func,
 238                               gpointer opaque,
 239                               GDestroyNotify destroy,
 240                               GMainContext *context)
 241{
 242    QIOTask *task;
 243
 244    if (qio_channel_has_feature(QIO_CHANNEL(ioc),
 245                                QIO_CHANNEL_FEATURE_CONCURRENT_IO)) {
 246        qcrypto_tls_session_require_thread_safety(ioc->session);
 247    }
 248
 249    task = qio_task_new(OBJECT(ioc),
 250                        func, opaque, destroy);
 251
 252    trace_qio_channel_tls_handshake_start(ioc);
 253    qio_channel_tls_handshake_task(ioc, task, context);
 254}
 255
 256static gboolean qio_channel_tls_bye_io(QIOChannel *ioc, GIOCondition condition,
 257                                       gpointer user_data);
 258
 259static void qio_channel_tls_bye_task(QIOChannelTLS *ioc, QIOTask *task,
 260                                     GMainContext *context)
 261{
 262    GIOCondition condition;
 263    QIOChannelTLSData *data;
 264    int status;
 265    Error *err = NULL;
 266
 267    status = qcrypto_tls_session_bye(ioc->session, &err);
 268
 269    if (status < 0) {
 270        trace_qio_channel_tls_bye_fail(ioc);
 271        qio_task_set_error(task, err);
 272        qio_task_complete(task);
 273        return;
 274    }
 275
 276    if (status == QCRYPTO_TLS_BYE_COMPLETE) {
 277        qio_task_complete(task);
 278        return;
 279    }
 280
 281    data = g_new0(typeof(*data), 1);
 282    data->task = task;
 283    data->context = context;
 284
 285    if (context) {
 286        g_main_context_ref(context);
 287    }
 288
 289    if (status == QCRYPTO_TLS_BYE_SENDING) {
 290        condition = G_IO_OUT;
 291    } else {
 292        condition = G_IO_IN;
 293    }
 294
 295    trace_qio_channel_tls_bye_pending(ioc, status);
 296    ioc->bye_ioc_tag = qio_channel_add_watch_full(ioc->master, condition,
 297                                                  qio_channel_tls_bye_io,
 298                                                  data, NULL, context);
 299}
 300
 301
 302static gboolean qio_channel_tls_bye_io(QIOChannel *ioc, GIOCondition condition,
 303                                       gpointer user_data)
 304{
 305    QIOChannelTLSData *data = user_data;
 306    QIOTask *task = data->task;
 307    GMainContext *context = data->context;
 308    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(qio_task_get_source(task));
 309
 310    tioc->bye_ioc_tag = 0;
 311    g_free(data);
 312    qio_channel_tls_bye_task(tioc, task, context);
 313
 314    if (context) {
 315        g_main_context_unref(context);
 316    }
 317
 318    return FALSE;
 319}
 320
 321static void propagate_error(QIOTask *task, gpointer opaque)
 322{
 323    qio_task_propagate_error(task, opaque);
 324}
 325
 326void qio_channel_tls_bye(QIOChannelTLS *ioc, Error **errp)
 327{
 328    QIOTask *task;
 329
 330    task = qio_task_new(OBJECT(ioc), propagate_error, errp, NULL);
 331
 332    trace_qio_channel_tls_bye_start(ioc);
 333    qio_channel_tls_bye_task(ioc, task, NULL);
 334}
 335
 336static void qio_channel_tls_init(Object *obj G_GNUC_UNUSED)
 337{
 338}
 339
 340
 341static void qio_channel_tls_finalize(Object *obj)
 342{
 343    QIOChannelTLS *ioc = QIO_CHANNEL_TLS(obj);
 344
 345    object_unref(OBJECT(ioc->master));
 346    qcrypto_tls_session_free(ioc->session);
 347}
 348
 349
 350static ssize_t qio_channel_tls_readv(QIOChannel *ioc,
 351                                     const struct iovec *iov,
 352                                     size_t niov,
 353                                     int **fds,
 354                                     size_t *nfds,
 355                                     int flags,
 356                                     Error **errp)
 357{
 358    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
 359    size_t i;
 360    ssize_t got = 0;
 361
 362    for (i = 0 ; i < niov ; i++) {
 363        ssize_t ret = qcrypto_tls_session_read(
 364            tioc->session,
 365            iov[i].iov_base,
 366            iov[i].iov_len,
 367            flags & QIO_CHANNEL_READ_FLAG_RELAXED_EOF ||
 368            qatomic_load_acquire(&tioc->shutdown) & QIO_CHANNEL_SHUTDOWN_READ,
 369            errp);
 370        if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
 371            if (got) {
 372                return got;
 373            } else {
 374                return QIO_CHANNEL_ERR_BLOCK;
 375            }
 376        } else if (ret < 0) {
 377            return -1;
 378        }
 379        got += ret;
 380        if (ret < iov[i].iov_len) {
 381            break;
 382        }
 383    }
 384    return got;
 385}
 386
 387
 388static ssize_t qio_channel_tls_writev(QIOChannel *ioc,
 389                                      const struct iovec *iov,
 390                                      size_t niov,
 391                                      int *fds,
 392                                      size_t nfds,
 393                                      int flags,
 394                                      Error **errp)
 395{
 396    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
 397    size_t i;
 398    ssize_t done = 0;
 399
 400    for (i = 0 ; i < niov ; i++) {
 401        ssize_t ret = qcrypto_tls_session_write(tioc->session,
 402                                                iov[i].iov_base,
 403                                                iov[i].iov_len,
 404                                                errp);
 405        if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
 406            if (done) {
 407                return done;
 408            } else {
 409                return QIO_CHANNEL_ERR_BLOCK;
 410            }
 411        } else if (ret < 0) {
 412            return -1;
 413        }
 414        done += ret;
 415        if (ret < iov[i].iov_len) {
 416            break;
 417        }
 418    }
 419    return done;
 420}
 421
 422static int qio_channel_tls_set_blocking(QIOChannel *ioc,
 423                                        bool enabled,
 424                                        Error **errp)
 425{
 426    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
 427
 428    return qio_channel_set_blocking(tioc->master, enabled, errp);
 429}
 430
 431static void qio_channel_tls_set_delay(QIOChannel *ioc,
 432                                      bool enabled)
 433{
 434    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
 435
 436    qio_channel_set_delay(tioc->master, enabled);
 437}
 438
 439static void qio_channel_tls_set_cork(QIOChannel *ioc,
 440                                     bool enabled)
 441{
 442    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
 443
 444    qio_channel_set_cork(tioc->master, enabled);
 445}
 446
 447static int qio_channel_tls_shutdown(QIOChannel *ioc,
 448                                    QIOChannelShutdown how,
 449                                    Error **errp)
 450{
 451    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
 452
 453    qatomic_or(&tioc->shutdown, how);
 454
 455    return qio_channel_shutdown(tioc->master, how, errp);
 456}
 457
 458static int qio_channel_tls_close(QIOChannel *ioc,
 459                                 Error **errp)
 460{
 461    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
 462
 463    if (tioc->hs_ioc_tag) {
 464        trace_qio_channel_tls_handshake_cancel(ioc);
 465        g_clear_handle_id(&tioc->hs_ioc_tag, g_source_remove);
 466    }
 467
 468    if (tioc->bye_ioc_tag) {
 469        trace_qio_channel_tls_bye_cancel(ioc);
 470        g_clear_handle_id(&tioc->bye_ioc_tag, g_source_remove);
 471    }
 472
 473    return qio_channel_close(tioc->master, errp);
 474}
 475
 476static void qio_channel_tls_set_aio_fd_handler(QIOChannel *ioc,
 477                                               AioContext *read_ctx,
 478                                               IOHandler *io_read,
 479                                               AioContext *write_ctx,
 480                                               IOHandler *io_write,
 481                                               void *opaque)
 482{
 483    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
 484
 485    qio_channel_set_aio_fd_handler(tioc->master, read_ctx, io_read,
 486            write_ctx, io_write, opaque);
 487}
 488
 489typedef struct QIOChannelTLSSource QIOChannelTLSSource;
 490struct QIOChannelTLSSource {
 491    GSource parent;
 492    QIOChannelTLS *tioc;
 493};
 494
 495static gboolean
 496qio_channel_tls_source_check(GSource *source)
 497{
 498    QIOChannelTLSSource *tsource = (QIOChannelTLSSource *)source;
 499
 500    return qcrypto_tls_session_check_pending(tsource->tioc->session) > 0;
 501}
 502
 503static gboolean
 504qio_channel_tls_source_prepare(GSource *source, gint *timeout)
 505{
 506    *timeout = -1;
 507    return qio_channel_tls_source_check(source);
 508}
 509
 510static gboolean
 511qio_channel_tls_source_dispatch(GSource *source, GSourceFunc callback,
 512                                gpointer user_data)
 513{
 514    return G_SOURCE_CONTINUE;
 515}
 516
 517static void
 518qio_channel_tls_source_finalize(GSource *source)
 519{
 520    QIOChannelTLSSource *tsource = (QIOChannelTLSSource *)source;
 521
 522    object_unref(OBJECT(tsource->tioc));
 523}
 524
 525static GSourceFuncs qio_channel_tls_source_funcs = {
 526    qio_channel_tls_source_prepare,
 527    qio_channel_tls_source_check,
 528    qio_channel_tls_source_dispatch,
 529    qio_channel_tls_source_finalize
 530};
 531
 532static void
 533qio_channel_tls_read_watch(QIOChannelTLS *tioc, GSource *source)
 534{
 535    GSource *child;
 536    QIOChannelTLSSource *tlssource;
 537
 538    child = g_source_new(&qio_channel_tls_source_funcs,
 539                          sizeof(QIOChannelTLSSource));
 540    tlssource = (QIOChannelTLSSource *)child;
 541
 542    tlssource->tioc = tioc;
 543    object_ref(OBJECT(tioc));
 544
 545    g_source_add_child_source(source, child);
 546    g_source_unref(child);
 547}
 548
 549static GSource *qio_channel_tls_create_watch(QIOChannel *ioc,
 550                                             GIOCondition condition)
 551{
 552    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
 553    GSource *source = qio_channel_create_watch(tioc->master, condition);
 554
 555    if (condition & G_IO_IN) {
 556        qio_channel_tls_read_watch(tioc, source);
 557    }
 558
 559    return source;
 560}
 561
 562QCryptoTLSSession *
 563qio_channel_tls_get_session(QIOChannelTLS *ioc)
 564{
 565    return ioc->session;
 566}
 567
 568static void qio_channel_tls_class_init(ObjectClass *klass,
 569                                       const void *class_data G_GNUC_UNUSED)
 570{
 571    QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
 572
 573    ioc_klass->io_writev = qio_channel_tls_writev;
 574    ioc_klass->io_readv = qio_channel_tls_readv;
 575    ioc_klass->io_set_blocking = qio_channel_tls_set_blocking;
 576    ioc_klass->io_set_delay = qio_channel_tls_set_delay;
 577    ioc_klass->io_set_cork = qio_channel_tls_set_cork;
 578    ioc_klass->io_close = qio_channel_tls_close;
 579    ioc_klass->io_shutdown = qio_channel_tls_shutdown;
 580    ioc_klass->io_create_watch = qio_channel_tls_create_watch;
 581    ioc_klass->io_set_aio_fd_handler = qio_channel_tls_set_aio_fd_handler;
 582}
 583
 584static const TypeInfo qio_channel_tls_info = {
 585    .parent = TYPE_QIO_CHANNEL,
 586    .name = TYPE_QIO_CHANNEL_TLS,
 587    .instance_size = sizeof(QIOChannelTLS),
 588    .instance_init = qio_channel_tls_init,
 589    .instance_finalize = qio_channel_tls_finalize,
 590    .class_init = qio_channel_tls_class_init,
 591};
 592
 593static void qio_channel_tls_register_types(void)
 594{
 595    type_register_static(&qio_channel_tls_info);
 596}
 597
 598type_init(qio_channel_tls_register_types);
 599