qemu

Форк
0
/
channel-tls.c 
507 строк · 14.4 Кб
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

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.