Coverage Report

Created: 2026-09-03 07:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/third_party/quic/libquic/handshake.c
Line
Count
Source
1
/*
2
 * Provide APIs for QUIC handshake.
3
 *
4
 * Copyright (c) 2024 Red Hat, Inc.
5
 *
6
 * libquic is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License as
8
 * published by the Free Software Foundation; either version 2.1 of
9
 * 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 License
17
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
18
 */
19
20
#include <sys/syslog.h>
21
#include <linux/tls.h>
22
#include <stdlib.h>
23
#include <string.h>
24
#include <errno.h>
25
#include <stdio.h>
26
#include <poll.h>
27
28
#include "netinet/quic.h"
29
30
0
#define QUIC_TLSEXT_TP_PARAM  0x39u
31
32
#define QUIC_MSG_STREAM_FLAGS \
33
0
  (MSG_STREAM_NEW | MSG_STREAM_FIN | MSG_STREAM_UNI | MSG_STREAM_DONTWAIT)
34
35
struct quic_rmsg {
36
  char cmsg[CMSG_SPACE(sizeof(struct quic_handshake_info))];
37
  struct iovec iov;
38
  struct msghdr msg;
39
  unsigned flags;
40
  uint8_t level;
41
  uint8_t data[65536];
42
};
43
44
struct quic_smsg {
45
  struct quic_smsg *next;
46
  char cmsg[CMSG_SPACE(sizeof(struct quic_handshake_info))];
47
  struct iovec iov;
48
  struct msghdr msg;
49
  unsigned flags;
50
  uint8_t level;
51
  uint8_t data[];
52
};
53
54
struct quic_handshake_ctx;
55
56
typedef int (*quic_handshake_step_process_fn_t)(struct quic_handshake_ctx *ctx);
57
58
struct quic_handshake_step_internal {
59
  struct quic_handshake_step step;
60
  quic_handshake_step_process_fn_t process_fn;
61
};
62
63
struct quic_handshake_ctx {
64
  gnutls_session_t session;
65
  struct quic_smsg *send_list;
66
  struct quic_smsg *send_last;
67
  struct quic_rmsg rmsg;
68
  uint8_t completed:1;
69
  uint8_t is_serv:1;
70
  struct quic_handshake_step_internal next_step;
71
};
72
73
static struct quic_handshake_ctx *quic_handshake_ctx_get(gnutls_session_t session)
74
0
{
75
0
  gnutls_ext_priv_data_t data = NULL;
76
77
0
  if (gnutls_ext_get_data(session, QUIC_TLSEXT_TP_PARAM, &data) != 0)
78
0
    return NULL;
79
80
0
  return data;
81
0
}
82
83
/*
84
 * The caller needs to opt-in in order
85
 * to get log messages
86
 */
87
static int quic_log_level = -1;
88
static quic_set_log_func_t quic_log_func;
89
90
static void quic_log_error(char const *fmt, ...);
91
92
/**
93
 * quic_log_debug - log msg with debug level
94
 *
95
 */
96
static void quic_log_debug(char const *fmt, ...)
97
0
{
98
0
  char msg[128];
99
0
  va_list arg;
100
0
  int rc;
101
102
0
  if (quic_log_level < LOG_DEBUG)
103
0
    return;
104
105
0
  va_start(arg, fmt);
106
0
  rc = vsnprintf(msg, sizeof(msg), fmt, arg);
107
0
  va_end(arg);
108
0
  if (rc < 0) {
109
0
    quic_log_error("%s: msg size is greater than 128 bytes!",
110
0
             __func__);
111
0
    return;
112
0
  }
113
114
0
  if (quic_log_func) {
115
0
    quic_log_func(LOG_DEBUG, msg);
116
0
    return;
117
0
  }
118
0
  printf("[DEBUG] %s\n", msg);
119
0
}
120
121
/**
122
 * quic_log_notice - log msg with notice level
123
 *
124
 */
125
static void quic_log_notice(char const *fmt, ...)
126
0
{
127
0
  char msg[128];
128
0
  va_list arg;
129
0
  int rc;
130
131
0
  if (quic_log_level < LOG_NOTICE)
132
0
    return;
133
134
0
  va_start(arg, fmt);
135
0
  rc = vsnprintf(msg, sizeof(msg), fmt, arg);
136
0
  va_end(arg);
137
0
  if (rc < 0) {
138
0
    quic_log_error("%s: msg size is greater than 128 bytes!",
139
0
             __func__);
140
0
    return;
141
0
  }
142
143
0
  if (quic_log_func) {
144
0
    quic_log_func(LOG_NOTICE, msg);
145
0
    return;
146
0
  }
147
0
  printf("[NOTICE] %s\n", msg);
148
0
}
149
150
/**
151
 * quic_log_error - log msg with error level
152
 *
153
 */
154
static void quic_log_error(char const *fmt, ...)
155
0
{
156
0
  char msg[128];
157
0
  va_list arg;
158
0
  int rc;
159
160
0
  if (quic_log_level < LOG_ERR)
161
0
    return;
162
163
0
  va_start(arg, fmt);
164
0
  rc = vsnprintf(msg, sizeof(msg), fmt, arg);
165
0
  va_end(arg);
166
0
  if (rc < 0) {
167
0
    snprintf(msg, sizeof(msg),
168
0
       "%s: msg size is greater than 128 bytes!",
169
0
       __func__);
170
0
  }
171
172
0
  if (quic_log_func) {
173
0
    quic_log_func(LOG_ERR, msg);
174
0
    return;
175
0
  }
176
0
  printf("[ERROR] %s\n", msg);
177
0
}
178
179
/**
180
 * quic_log_gnutls_error - log msg with error level and gnutls strerror converted
181
 * @error: the error code returned from gnutls APIs
182
 *
183
 */
184
static void quic_log_gnutls_error(int error)
185
0
{
186
0
  quic_log_error("gnutls: %s (%d)", gnutls_strerror(error), error);
187
0
}
188
189
/**
190
 * quic_set_log_level - change the log_level
191
 * @level: the level it changes to (LOG_XXX from sys/syslog.h)
192
 *
193
 * Return values:
194
 * - The old @level
195
 */
196
int quic_set_log_level(int level)
197
0
{
198
0
  int old = quic_log_level;
199
0
  quic_log_level = level;
200
0
  return old;
201
0
}
202
203
/**
204
 * quic_set_log_func - change the log func
205
 * @func: the log func it changes to
206
 *
207
 * Return values:
208
 * - The old @func
209
 */
210
quic_set_log_func_t quic_set_log_func(quic_set_log_func_t func)
211
0
{
212
0
  quic_set_log_func_t old = quic_log_func;
213
0
  quic_log_func = func;
214
0
  return old;
215
0
}
216
217
static void quic_prepare_sendmsg_step(struct quic_handshake_ctx *ctx,
218
              quic_handshake_step_process_fn_t process_fn,
219
              const struct msghdr *msg,
220
              int flags)
221
0
{
222
0
  struct quic_handshake_step_sendmsg *s = &ctx->next_step.step.s_sendmsg;
223
224
0
  ctx->next_step.step.op = QUIC_HANDSHAKE_STEP_OP_SENDMSG;
225
0
  *s = (struct quic_handshake_step_sendmsg) {
226
0
    .msg = msg,
227
0
    .flags = flags,
228
0
    .retval = -EUCLEAN,
229
0
  };
230
231
0
  ctx->next_step.process_fn = process_fn;
232
0
}
233
234
static void quic_prepare_recvmsg_step(struct quic_handshake_ctx *ctx,
235
              quic_handshake_step_process_fn_t process_fn,
236
              struct msghdr *msg,
237
              int flags)
238
0
{
239
0
  struct quic_handshake_step_recvmsg *s = &ctx->next_step.step.s_recvmsg;
240
241
0
  ctx->next_step.step.op = QUIC_HANDSHAKE_STEP_OP_RECVMSG;
242
0
  *s = (struct quic_handshake_step_recvmsg) {
243
0
    .msg = msg,
244
0
    .flags = flags,
245
0
    .retval = -EUCLEAN,
246
0
  };
247
248
0
  ctx->next_step.process_fn = process_fn;
249
0
}
250
251
/**
252
 * quic_recvmsg - receive msg and also get stream ID and flag
253
 * @sockfd: IPPROTO_QUIC type socket
254
 * @msg: msg buffer
255
 * @len: msg buffer length
256
 * @sid: stream ID got from kernel
257
 * @flag: stream flag got from kernel
258
 *
259
 * Return values:
260
 * - On success, the number of bytes received is returned.
261
 * - On error, -1 is returned, and errno is set to indicate the error.
262
 */
263
ssize_t quic_recvmsg(int sockfd, void *msg, size_t len, int64_t *sid, uint32_t *flags)
264
0
{
265
0
  char incmsg[CMSG_SPACE(sizeof(struct quic_stream_info))];
266
0
  struct quic_stream_info *info;
267
0
  struct cmsghdr *cmsg;
268
0
  struct msghdr inmsg;
269
0
  struct iovec iov;
270
0
  ssize_t ret;
271
272
0
  iov.iov_base = msg;
273
0
  iov.iov_len = len;
274
275
0
  memset(&inmsg, 0, sizeof(inmsg));
276
0
  inmsg.msg_iov = &iov;
277
0
  inmsg.msg_iovlen = 1;
278
0
  inmsg.msg_control = incmsg;
279
0
  inmsg.msg_controllen = sizeof(incmsg);
280
281
0
  ret = recvmsg(sockfd, &inmsg, flags ? (int)*flags : 0);
282
0
  if (ret < 0)
283
0
    return ret;
284
285
0
  if (flags)
286
0
    *flags = inmsg.msg_flags;
287
288
0
  cmsg = CMSG_FIRSTHDR(&inmsg);
289
0
  if (!cmsg)
290
0
    return ret;
291
292
0
  if (SOL_QUIC == cmsg->cmsg_level &&  QUIC_STREAM_INFO == cmsg->cmsg_type) {
293
0
    info = (struct quic_stream_info *)CMSG_DATA(cmsg);
294
0
    if (sid)
295
0
      *sid = info->stream_id;
296
0
    if (flags)
297
0
      *flags |= info->stream_flags;
298
0
  }
299
0
  return ret;
300
0
}
301
302
/**
303
 * quic_sendmsg - send msg with stream ID and flag
304
 * @sockfd: IPPROTO_QUIC type socket
305
 * @msg: msg to send
306
 * @len: the length of the msg to send
307
 * @sid: stream ID
308
 * @flag: stream flag
309
 *
310
 * Return values:
311
 * - On success, the number of bytes sent is returned.
312
 * - On error, -1 is returned, and errno is set to indicate the error.
313
 */
314
ssize_t quic_sendmsg(int sockfd, const void *msg, size_t len, int64_t sid, uint32_t flags)
315
0
{
316
0
  char outcmsg[CMSG_SPACE(sizeof(struct quic_stream_info))];
317
0
  struct quic_stream_info *info;
318
0
  struct msghdr outmsg;
319
0
  struct cmsghdr *cmsg;
320
0
  struct iovec iov;
321
322
0
  iov.iov_base = (void *)msg;
323
0
  iov.iov_len = len;
324
325
0
  memset(&outmsg, 0, sizeof(outmsg));
326
0
  outmsg.msg_iov = &iov;
327
0
  outmsg.msg_iovlen = 1;
328
0
  outmsg.msg_control = outcmsg;
329
0
  outmsg.msg_controllen = sizeof(outcmsg);
330
331
0
  cmsg = CMSG_FIRSTHDR(&outmsg);
332
0
  cmsg->cmsg_level = SOL_QUIC;
333
0
  cmsg->cmsg_type = QUIC_STREAM_INFO;
334
0
  cmsg->cmsg_len = CMSG_LEN(sizeof(*info));
335
336
0
  outmsg.msg_controllen = cmsg->cmsg_len;
337
0
  info = (struct quic_stream_info *)CMSG_DATA(cmsg);
338
0
  info->stream_id = sid;
339
0
  info->stream_flags = (flags & QUIC_MSG_STREAM_FLAGS);
340
341
0
  return sendmsg(sockfd, &outmsg, (int)(flags & ~QUIC_MSG_STREAM_FLAGS));
342
0
}
343
344
static uint32_t quic_tls_cipher_type(gnutls_cipher_algorithm_t cipher)
345
0
{
346
0
  switch (cipher) {
347
0
  case GNUTLS_CIPHER_AES_128_GCM:
348
0
    return TLS_CIPHER_AES_GCM_128;
349
0
  case GNUTLS_CIPHER_AES_128_CCM:
350
0
    return TLS_CIPHER_AES_CCM_128;
351
0
  case GNUTLS_CIPHER_AES_256_GCM:
352
0
    return TLS_CIPHER_AES_GCM_256;
353
0
  case GNUTLS_CIPHER_CHACHA20_POLY1305:
354
0
    return TLS_CIPHER_CHACHA20_POLY1305;
355
0
  default:
356
0
    quic_log_notice("%s: %d", __func__, cipher);
357
0
    return 0;
358
0
  }
359
0
}
360
361
static uint8_t quic_crypto_level(gnutls_record_encryption_level_t level)
362
0
{
363
0
  switch (level) {
364
0
  case GNUTLS_ENCRYPTION_LEVEL_INITIAL:
365
0
    return QUIC_CRYPTO_INITIAL;
366
0
  case GNUTLS_ENCRYPTION_LEVEL_HANDSHAKE:
367
0
    return QUIC_CRYPTO_HANDSHAKE;
368
0
  case GNUTLS_ENCRYPTION_LEVEL_APPLICATION:
369
0
    return QUIC_CRYPTO_APP;
370
0
  case GNUTLS_ENCRYPTION_LEVEL_EARLY:
371
0
    return QUIC_CRYPTO_EARLY;
372
0
  default:
373
0
    quic_log_notice("%s: %d", __func__, level);
374
0
    return QUIC_CRYPTO_MAX;
375
0
  }
376
0
}
377
378
static gnutls_record_encryption_level_t quic_tls_crypto_level(uint8_t level)
379
0
{
380
0
  switch (level) {
381
0
  case QUIC_CRYPTO_INITIAL:
382
0
    return GNUTLS_ENCRYPTION_LEVEL_INITIAL;
383
0
  case QUIC_CRYPTO_HANDSHAKE:
384
0
    return GNUTLS_ENCRYPTION_LEVEL_HANDSHAKE;
385
0
  case QUIC_CRYPTO_APP:
386
0
    return GNUTLS_ENCRYPTION_LEVEL_APPLICATION;
387
0
  case QUIC_CRYPTO_EARLY:
388
0
    return GNUTLS_ENCRYPTION_LEVEL_EARLY;
389
0
  default:
390
0
    quic_log_notice("%s: %d", __func__, level);
391
0
    return GNUTLS_ENCRYPTION_LEVEL_APPLICATION + 1;
392
0
  }
393
0
}
394
395
static int quic_set_secret(gnutls_session_t session, gnutls_record_encryption_level_t level,
396
         const void *rx_secret, const void *tx_secret, size_t secretlen)
397
0
{
398
0
  gnutls_cipher_algorithm_t type  = gnutls_cipher_get(session);
399
0
  struct quic_handshake_ctx *ctx = quic_handshake_ctx_get(session);
400
0
  struct quic_crypto_secret secret = {};
401
0
  int sockfd, ret, len = sizeof(secret);
402
403
0
  if (!ctx || ctx->completed)
404
0
    return 0;
405
406
0
  if (secretlen > QUIC_CRYPTO_SECRET_BUFFER_SIZE) {
407
0
    quic_log_error("secretlen[%zu] > %u",
408
0
             secretlen, QUIC_CRYPTO_SECRET_BUFFER_SIZE);
409
0
    return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
410
0
  }
411
412
0
  if (level == GNUTLS_ENCRYPTION_LEVEL_EARLY)
413
0
    type = gnutls_early_cipher_get(session);
414
415
0
  sockfd = gnutls_transport_get_int(session);
416
0
  secret.level = quic_crypto_level(level);
417
0
  secret.type = quic_tls_cipher_type(type);
418
0
  if (tx_secret) {
419
0
    secret.send = 1;
420
0
    memcpy(secret.secret, tx_secret, secretlen);
421
0
    ret = setsockopt(sockfd, SOL_QUIC, QUIC_SOCKOPT_CRYPTO_SECRET, &secret, len);
422
0
    gnutls_memset(secret.secret, 0, secretlen);
423
0
    if (ret) {
424
0
      quic_log_error("socket setsockopt tx secret error %d %u", errno, level);
425
0
      return -1;
426
0
    }
427
0
  }
428
0
  if (rx_secret) {
429
0
    secret.send = 0;
430
0
    memcpy(secret.secret, rx_secret, secretlen);
431
0
    ret = setsockopt(sockfd, SOL_QUIC, QUIC_SOCKOPT_CRYPTO_SECRET, &secret, len);
432
0
    gnutls_memset(secret.secret, 0, secretlen);
433
0
    if (ret) {
434
0
      quic_log_error("socket setsockopt rx secret error %d %u", errno, level);
435
0
      return -1;
436
0
    }
437
0
    if (secret.level == QUIC_CRYPTO_APP) {
438
0
      if (ctx->is_serv) {
439
0
        ret = gnutls_session_ticket_send(session, 1, 0);
440
0
        if (ret) {
441
0
          quic_log_gnutls_error(ret);
442
0
          return ret;
443
0
        }
444
0
      }
445
0
      ctx->completed = 1;
446
0
    }
447
0
  }
448
0
  quic_log_debug("  Secret func: %u %u %u", secret.level, !!tx_secret, !!rx_secret);
449
0
  return 0;
450
0
}
451
452
static int quic_alert_read(gnutls_session_t session,
453
         gnutls_record_encryption_level_t gtls_level,
454
         gnutls_alert_level_t alert_level,
455
         gnutls_alert_description_t alert_desc)
456
0
{
457
0
  quic_log_notice("%s: %u %u %u %u", __func__,
458
0
      !!session, gtls_level, alert_level, alert_desc);
459
0
  return 0;
460
0
}
461
462
static int quic_tp_recv(gnutls_session_t session, const uint8_t *buf, size_t len)
463
0
{
464
0
  int sockfd = gnutls_transport_get_int(session);
465
466
0
  if (setsockopt(sockfd, SOL_QUIC, QUIC_SOCKOPT_TRANSPORT_PARAM_EXT, buf, len)) {
467
0
    quic_log_error("socket setsockopt transport_param_ext error %d", errno);
468
0
    return -1;
469
0
  }
470
0
  return 0;
471
0
}
472
473
static int quic_tp_send(gnutls_session_t session, gnutls_buffer_t extdata)
474
0
{
475
0
  int ret, sockfd = gnutls_transport_get_int(session);
476
0
  uint8_t buf[256];
477
0
  unsigned int len;
478
479
0
  len = sizeof(buf);
480
0
  if (getsockopt(sockfd, SOL_QUIC, QUIC_SOCKOPT_TRANSPORT_PARAM_EXT, buf, &len)) {
481
0
    quic_log_error("socket getsockopt transport_param_ext error %d", errno);
482
0
    return -1;
483
0
  }
484
485
0
  ret = gnutls_buffer_append_data(extdata, buf, len);
486
0
  if (ret) {
487
0
    quic_log_gnutls_error(ret);
488
0
    return ret;
489
0
  }
490
491
0
  return 0;
492
0
}
493
494
static struct quic_smsg *quic_smsg_create(uint8_t level,
495
            const void *data,
496
            size_t datalen)
497
0
{
498
0
  struct quic_handshake_info *info;
499
0
  struct quic_smsg *smsg;
500
0
  struct cmsghdr *cmsg;
501
502
0
  smsg = malloc(sizeof(*smsg) + datalen);
503
0
  if (!smsg)
504
0
    return NULL;
505
506
0
  memset(smsg, 0, sizeof(*smsg));
507
0
  memcpy(smsg->data, data, datalen);
508
509
0
  smsg->iov.iov_base = smsg->data;
510
0
  smsg->iov.iov_len = datalen;
511
512
0
  smsg->msg.msg_iov = &smsg->iov;
513
0
  smsg->msg.msg_iovlen = 1;
514
0
  smsg->msg.msg_control = smsg->cmsg;
515
0
  smsg->msg.msg_controllen = sizeof(smsg->cmsg);
516
517
0
  cmsg = CMSG_FIRSTHDR(&smsg->msg);
518
0
  cmsg->cmsg_level = SOL_QUIC;
519
0
  cmsg->cmsg_type = QUIC_HANDSHAKE_INFO;
520
0
  cmsg->cmsg_len = CMSG_LEN(sizeof(*info));
521
522
0
  info = (struct quic_handshake_info *)CMSG_DATA(cmsg);
523
0
  info->crypto_level = level;
524
525
0
  smsg->flags = MSG_NOSIGNAL;
526
0
  smsg->level = level;
527
528
0
  return smsg;
529
0
}
530
531
static void quic_smsg_append_list(struct quic_handshake_ctx *ctx,
532
          struct quic_smsg *smsg)
533
0
{
534
0
  if (!ctx->send_list)
535
0
    ctx->send_list = smsg;
536
0
  else {
537
0
    ctx->send_last->flags |= MSG_MORE;
538
0
    ctx->send_last->next = smsg;
539
0
  }
540
0
  ctx->send_last = smsg;
541
0
}
542
543
static void quic_smsg_destroy(struct quic_smsg *smsg)
544
0
{
545
0
  gnutls_memset(smsg, 0, sizeof(*smsg) + smsg->iov.iov_len);
546
0
  free(smsg);
547
0
}
548
549
static int quic_msg_read(gnutls_session_t session, gnutls_record_encryption_level_t level,
550
       gnutls_handshake_description_t htype, const void *data, size_t datalen)
551
0
{
552
0
  struct quic_handshake_ctx *ctx = quic_handshake_ctx_get(session);
553
0
  uint8_t qlevel = quic_crypto_level(level);
554
0
  struct quic_smsg *smsg;
555
556
0
  if (!ctx || htype == GNUTLS_HANDSHAKE_KEY_UPDATE)
557
0
    return 0;
558
559
0
  smsg = quic_smsg_create(qlevel, data, datalen);
560
0
  if (!smsg) {
561
0
    quic_log_error("msg create error %d", ENOMEM);
562
0
    return -1;
563
0
  }
564
565
0
  quic_smsg_append_list(ctx, smsg);
566
567
0
  quic_log_debug("  Read func: %u %u %zu", level, htype, datalen);
568
0
  return 0;
569
0
}
570
571
static int quic_handshake_process(gnutls_session_t session, uint8_t level,
572
          const uint8_t *data, size_t datalen)
573
0
{
574
0
  gnutls_record_encryption_level_t l;
575
0
  int ret;
576
577
0
  l = quic_tls_crypto_level(level);
578
0
  if (datalen > 0) {
579
0
    ret = gnutls_handshake_write(session, l, data, datalen);
580
0
    if (ret != 0) {
581
0
      if (!gnutls_error_is_fatal(ret))
582
0
        return 0;
583
0
      goto err;
584
0
    }
585
0
  }
586
587
0
  ret = gnutls_handshake(session);
588
0
  if (ret < 0) {
589
0
    if (!gnutls_error_is_fatal(ret))
590
0
      return 0;
591
0
    goto err;
592
0
  }
593
0
  return 0;
594
0
err:
595
0
  gnutls_alert_send_appropriate(session, ret);
596
0
  quic_log_gnutls_error(ret);
597
0
  return ret;
598
0
}
599
600
static void quic_prepare_rmsg(struct quic_rmsg *rmsg)
601
0
{
602
0
  gnutls_memset(rmsg, 0, sizeof(*rmsg));
603
604
0
  rmsg->iov.iov_base = rmsg->data;
605
0
  rmsg->iov.iov_len = sizeof(rmsg->data);
606
607
0
  rmsg->msg.msg_iov = &rmsg->iov;
608
0
  rmsg->msg.msg_iovlen = 1;
609
0
  rmsg->msg.msg_control = rmsg->cmsg;
610
0
  rmsg->msg.msg_controllen = sizeof(rmsg->cmsg);
611
612
0
  rmsg->flags = MSG_DONTWAIT;
613
0
}
614
615
static int quic_check_rmsg_level(struct quic_rmsg *rmsg)
616
0
{
617
0
  struct quic_handshake_info *info;
618
0
  struct cmsghdr *cmsg;
619
620
0
  if (rmsg->msg.msg_flags & MSG_CTRUNC) {
621
0
    quic_log_error("rmsg: got MSG_CTRUNC");
622
0
    return -1;
623
0
  }
624
625
0
  cmsg = CMSG_FIRSTHDR(&rmsg->msg);
626
0
  if (!cmsg) {
627
0
    quic_log_error("rmsg: got no CMSG_FIRSTHDR");
628
0
    return -1;
629
0
  }
630
631
0
  if (SOL_QUIC != cmsg->cmsg_level) {
632
0
    quic_log_error("rmsg: got no %d instead of SOL_QUIC[%d]",
633
0
             cmsg->cmsg_level, SOL_QUIC);
634
0
    return -1;
635
0
  }
636
637
0
  if (QUIC_HANDSHAKE_INFO != cmsg->cmsg_type) {
638
0
    quic_log_error("rmsg: got no %d instead of QUIC_HANDSHAKE_INFO[%d]",
639
0
             cmsg->cmsg_type, QUIC_HANDSHAKE_INFO);
640
0
    return -1;
641
0
  }
642
643
0
  info = (struct quic_handshake_info *)CMSG_DATA(cmsg);
644
0
  rmsg->level = info->crypto_level;
645
646
0
  return 0;
647
0
}
648
649
static int quic_storage_add(void *dbf, time_t exp_time, const gnutls_datum_t *key,
650
          const gnutls_datum_t *data)
651
0
{
652
0
  return 0;
653
0
}
654
655
static gnutls_anti_replay_t quic_anti_replay;
656
657
static int quic_handshake_next_step(struct quic_handshake_ctx *ctx,
658
            struct quic_handshake_step **pstep);
659
660
int quic_handshake_init(gnutls_session_t session,
661
      struct quic_handshake_step **pstep)
662
0
{
663
0
  int sockfd = gnutls_transport_get_int(session);
664
0
  struct quic_handshake_ctx *ctx;
665
0
  unsigned int len;
666
0
  uint8_t opt[128];
667
0
  int ret;
668
669
0
  if (pstep == NULL || *pstep != NULL)
670
0
    return -EINVAL;
671
672
0
  ctx = malloc(sizeof(*ctx));
673
0
  if (!ctx) {
674
0
    quic_log_error("ctx malloc error %d", ENOMEM);
675
0
    return -ENOMEM;
676
0
  }
677
0
  memset(ctx, 0, sizeof(*ctx));
678
679
0
  ctx->session = session;
680
681
0
  ret = gnutls_session_ext_register(
682
0
    session, "QUIC Transport Parameters", QUIC_TLSEXT_TP_PARAM,
683
0
    GNUTLS_EXT_TLS, quic_tp_recv, quic_tp_send, NULL, NULL, NULL,
684
0
    GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_EE);
685
0
  if (ret) {
686
0
    free(ctx);
687
0
    quic_log_gnutls_error(ret);
688
0
    return ret;
689
0
  }
690
0
  gnutls_ext_set_data(session, QUIC_TLSEXT_TP_PARAM, ctx);
691
0
  gnutls_handshake_set_secret_function(session, quic_set_secret);
692
0
  gnutls_handshake_set_read_function(session, quic_msg_read);
693
0
  gnutls_alert_set_read_function(session, quic_alert_read);
694
695
0
  len = sizeof(opt);
696
0
  ret = getsockopt(sockfd, SOL_QUIC, QUIC_SOCKOPT_TOKEN, opt, &len);
697
0
  ctx->is_serv = !!ret;
698
699
0
  if (ctx->is_serv) {
700
0
    if (!quic_anti_replay) {
701
0
      ret = gnutls_anti_replay_init(&quic_anti_replay);
702
0
      if (ret)
703
0
        goto deinit;
704
0
      gnutls_anti_replay_set_add_function(quic_anti_replay,
705
0
                  quic_storage_add);
706
0
      gnutls_anti_replay_set_ptr(quic_anti_replay, NULL);
707
0
    }
708
0
    gnutls_anti_replay_enable(ctx->session, quic_anti_replay);
709
0
  }
710
711
0
  if (!ctx->is_serv) {
712
0
    ret = quic_handshake_process(ctx->session,
713
0
               QUIC_CRYPTO_INITIAL,
714
0
               NULL, 0);
715
0
    if (ret)
716
0
      goto deinit;
717
0
  }
718
719
0
  ret = quic_handshake_next_step(ctx, pstep);
720
0
  if (ret)
721
0
    goto deinit;
722
0
  return 0;
723
0
deinit:
724
0
  quic_handshake_deinit(session);
725
0
  return ret;
726
0
}
727
728
static int quic_handshake_sendmsg_process(struct quic_handshake_ctx *ctx);
729
static int quic_handshake_recvmsg_process(struct quic_handshake_ctx *ctx);
730
731
static int quic_handshake_next_step(struct quic_handshake_ctx *ctx,
732
            struct quic_handshake_step **pstep)
733
0
{
734
0
  gnutls_memset(&ctx->next_step, 0, sizeof(ctx->next_step));
735
736
0
  if (ctx->send_list != NULL) {
737
0
    struct quic_smsg *smsg = ctx->send_list;
738
739
0
    quic_prepare_sendmsg_step(ctx,
740
0
            quic_handshake_sendmsg_process,
741
0
            &smsg->msg,
742
0
            smsg->flags);
743
0
    goto prepared;
744
0
  }
745
746
0
  if (!ctx->completed) {
747
0
    struct quic_rmsg *rmsg = &ctx->rmsg;
748
749
0
    quic_prepare_rmsg(rmsg);
750
0
    quic_prepare_recvmsg_step(ctx,
751
0
            quic_handshake_recvmsg_process,
752
0
            &rmsg->msg,
753
0
            rmsg->flags);
754
0
    goto prepared;
755
0
  }
756
757
0
prepared:
758
0
  if (ctx->next_step.process_fn != NULL)
759
0
    *pstep = &ctx->next_step.step;
760
0
  else
761
0
    *pstep = NULL;
762
763
0
  return 0;
764
0
}
765
766
static int quic_handshake_sendmsg_process(struct quic_handshake_ctx *ctx)
767
0
{
768
0
  struct quic_handshake_step_sendmsg *s = &ctx->next_step.step.s_sendmsg;
769
0
  struct quic_smsg *smsg = ctx->send_list;
770
0
  ssize_t slen = s->retval;
771
772
0
  if (slen < 0) {
773
0
    quic_log_error("socket sendmsg(%u, %u) error %zd",
774
0
             smsg->iov.iov_len,
775
0
             slen);
776
0
    return slen;
777
0
  }
778
0
  if (slen != smsg->iov.iov_len) {
779
0
    quic_log_error("socket sendmsg(%u, %u) short %zd",
780
0
             smsg->iov.iov_len,
781
0
             slen);
782
0
    return -EMSGSIZE;
783
0
  }
784
785
0
  quic_log_debug("> Handshake SENT: %zu %u", slen, smsg->level);
786
0
  ctx->send_list = smsg->next;
787
0
  quic_smsg_destroy(smsg);
788
789
0
  return 0;
790
0
}
791
792
static int quic_handshake_recvmsg_process(struct quic_handshake_ctx *ctx)
793
0
{
794
0
  struct quic_handshake_step_recvmsg *s = &ctx->next_step.step.s_recvmsg;
795
0
  struct quic_rmsg *rmsg = &ctx->rmsg;
796
0
  ssize_t rlen = s->retval;
797
0
  int ret;
798
799
0
  if (rlen < 0) {
800
0
    quic_log_error("socket recvmsg(%u) error %zd",
801
0
             rmsg->iov.iov_len,
802
0
             rlen);
803
0
    return rlen;
804
0
  }
805
806
0
  if (rlen == 0) {
807
0
    quic_log_error("socket recvmsg(%u) EOF",
808
0
             rmsg->iov.iov_len);
809
0
    return -ECONNRESET;
810
0
  }
811
812
0
  if (rmsg->msg.msg_flags & MSG_TRUNC) {
813
0
    quic_log_error("socket recvmsg(%u) got MSG_TRUNC %zd",
814
0
             rmsg->iov.iov_len,
815
0
             rlen);
816
0
    return -EMSGSIZE;
817
0
  }
818
819
0
  ret = quic_check_rmsg_level(rmsg);
820
0
  if (ret < 0) {
821
0
    quic_log_error("socket recvmsg(%u) no QUIC_HANDSHAKE_INFO",
822
0
             rmsg->iov.iov_len);
823
0
    return -EBADMSG;
824
0
  }
825
826
0
  quic_log_debug("> Handshake RECV: %zu %u", rlen, rmsg->level);
827
0
  ret = quic_handshake_process(ctx->session, rmsg->level, rmsg->data, rlen);
828
0
  if (ret != 0)
829
0
    return ret;
830
831
0
  return 0;
832
0
}
833
834
int quic_handshake_step(gnutls_session_t session,
835
      struct quic_handshake_step **pstep)
836
0
{
837
0
  struct quic_handshake_ctx *ctx = quic_handshake_ctx_get(session);
838
0
  quic_handshake_step_process_fn_t process_fn = ctx->next_step.process_fn;
839
0
  int ret;
840
841
0
  ctx->next_step.process_fn = NULL;
842
843
0
  if (pstep == NULL)
844
0
    return -EINVAL;
845
846
0
  if (*pstep != &ctx->next_step.step) {
847
0
    quic_log_error("ctx invalid step[%p] != expected[%p] %d",
848
0
             *pstep, &ctx->next_step.step, EINVAL);
849
0
    return -EINVAL;
850
0
  }
851
852
0
  if (process_fn == NULL) {
853
0
    quic_log_error("ctx no process_fn %d",
854
0
             EINVAL);
855
0
    return -EINVAL;
856
0
  }
857
858
0
  ret = process_fn(ctx);
859
0
  if (ret)
860
0
    return ret;
861
862
0
  return quic_handshake_next_step(ctx, pstep);
863
0
}
864
865
void quic_handshake_deinit(gnutls_session_t session)
866
0
{
867
0
  struct quic_handshake_ctx *ctx = quic_handshake_ctx_get(session);
868
0
  struct quic_smsg *smsg;
869
870
0
  if (ctx == NULL)
871
0
    return;
872
873
0
  gnutls_ext_set_data(session, QUIC_TLSEXT_TP_PARAM, NULL);
874
875
0
  smsg = ctx->send_list;
876
0
  while (smsg) {
877
0
    ctx->send_list = smsg->next;
878
0
    quic_smsg_destroy(smsg);
879
0
    smsg = ctx->send_list;
880
0
  }
881
882
0
  gnutls_memset(ctx, 0, sizeof(*ctx));
883
0
  free(ctx);
884
0
}
885
886
/**
887
 * quic_handshake - Drive the handshake interaction with TLS session
888
 * @session: TLS session
889
 *
890
 * Return values:
891
 * - On success, 0 is returned.
892
 * - On error, a negative error value is returned.
893
 */
894
int quic_handshake(gnutls_session_t session)
895
0
{
896
0
  int ret, sockfd = gnutls_transport_get_int(session);
897
0
  struct quic_handshake_step *step = NULL;
898
899
0
  ret = quic_handshake_init(session, &step);
900
0
  if (ret != 0)
901
0
    return ret;
902
903
0
  while (ret == 0 && step != NULL) {
904
0
    switch (step->op) {
905
0
    case QUIC_HANDSHAKE_STEP_OP_RECVMSG: {
906
0
      struct quic_handshake_step_recvmsg *s = &step->s_recvmsg;
907
0
      ssize_t rlen;
908
909
0
      rlen = recvmsg(sockfd, s->msg, s->flags);
910
0
      if (rlen == -1 && errno == EINTR)
911
0
        continue;
912
0
      if (rlen == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
913
0
        struct pollfd pfd = {
914
0
          .fd = sockfd,
915
0
          .events = POLLIN,
916
0
        };
917
0
        int prc;
918
919
0
        prc = poll(&pfd, 1, 1000);
920
0
        if (prc < 0) {
921
0
          quic_log_error("socket poll() error %d", errno);
922
0
          ret = -errno;
923
0
          goto out;
924
0
        }
925
0
        continue;
926
0
      }
927
928
0
      if (rlen == -1)
929
0
        rlen = -errno;
930
931
0
      s->retval = rlen;
932
0
      ret = quic_handshake_step(session, &step);
933
0
      if (ret)
934
0
        goto out;
935
936
0
      continue;
937
0
      }
938
0
    case QUIC_HANDSHAKE_STEP_OP_SENDMSG: {
939
0
      struct quic_handshake_step_sendmsg *s = &step->s_sendmsg;
940
0
      ssize_t slen;
941
942
0
      slen = sendmsg(sockfd, s->msg, s->flags);
943
0
      if (slen == -1 && errno == EINTR)
944
0
        continue;
945
0
      if (slen == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
946
0
        struct pollfd pfd = {
947
0
          .fd = sockfd,
948
0
          .events = POLLOUT,
949
0
        };
950
0
        int prc;
951
952
0
        prc = poll(&pfd, 1, 1000);
953
0
        if (prc < 0) {
954
0
          quic_log_error("socket poll() error %d", errno);
955
0
          ret = -errno;
956
0
          goto out;
957
0
        }
958
0
        continue;
959
0
      }
960
961
0
      if (slen == -1)
962
0
        slen = -errno;
963
964
0
      s->retval = slen;
965
0
      ret = quic_handshake_step(session, &step);
966
0
      if (ret)
967
0
        goto out;
968
969
0
      continue;
970
0
      }
971
0
    }
972
973
0
    ret = -EUCLEAN;
974
0
  }
975
976
0
out:
977
0
  quic_handshake_deinit(session);
978
0
  return ret < 0 ? ret : 0;
979
0
}
980
981
/**
982
 * quic_session_get_data - Get session data from a TLS session
983
 * @session: TLS session
984
 * @data: pre-allocated buffer to hold session data
985
 * @size: session data's size
986
 *
987
 * Return values:
988
 * - On success, 0 is returned.
989
 * - On error, a negative error value is returned.
990
 */
991
int quic_session_get_data(gnutls_session_t session, void *data, size_t *size)
992
0
{
993
0
  int ret, sockfd = gnutls_transport_get_int(session);
994
0
  unsigned int len = *size;
995
996
0
  if (getsockopt(sockfd, SOL_QUIC, QUIC_SOCKOPT_SESSION_TICKET, data, &len)) {
997
0
    quic_log_error("socket getsockopt session ticket error %d", errno);
998
0
    return -errno;
999
0
  }
1000
0
  if (!len) {
1001
0
    *size = 0;
1002
0
    return 0;
1003
0
  }
1004
1005
0
  ret = quic_handshake_process(session, QUIC_CRYPTO_APP, data, len);
1006
0
  if (ret)
1007
0
    return ret;
1008
0
  return gnutls_session_get_data(session, data, size);
1009
0
}
1010
1011
/**
1012
 * quic_session_set_data - Set session data to a TLS session
1013
 * @session: TLS session
1014
 * @data: buffer to hold the session
1015
 * @size: session data's size
1016
 *
1017
 * Return values:
1018
 * - On success, 0 is returned.
1019
 * - On error, a negative error value is returned.
1020
 */
1021
int quic_session_set_data(gnutls_session_t session, const void *data, size_t size)
1022
0
{
1023
0
  return gnutls_session_set_data(session, data, size);
1024
0
}
1025
1026
/**
1027
 * quic_session_get_alpn - Get session alpn from a TLS session
1028
 * @session: TLS session
1029
 * @data: pre-allocated string buffer to hold session alpn
1030
 * @size: session alpn's size
1031
 *
1032
 * Return values:
1033
 * - On success, 0 is returned.
1034
 * - On error, a negative error value is returned.
1035
 */
1036
int quic_session_get_alpn(gnutls_session_t session, void *alpn, size_t *size)
1037
0
{
1038
0
  gnutls_datum_t alpn_data;
1039
0
  int ret;
1040
1041
0
  ret = gnutls_alpn_get_selected_protocol(session, &alpn_data);
1042
0
  if (ret)
1043
0
    return ret;
1044
1045
0
  if (*size < alpn_data.size)
1046
0
    return -EINVAL;
1047
1048
0
  memcpy(alpn, alpn_data.data, alpn_data.size);
1049
0
  *size = alpn_data.size;
1050
0
  return 0;
1051
0
}
1052
1053
/**
1054
 * quic_session_set_alpn - Set session alpn to a TLS session
1055
 * @session: TLS session
1056
 * @data: string buffer to hold the session
1057
 * @size: session alpn's size
1058
 *
1059
 * Return values:
1060
 * - On success, 0 is returned.
1061
 * - On error, a negative error value is returned.
1062
 */
1063
int quic_session_set_alpn(gnutls_session_t session, const void *alpns, size_t size)
1064
0
{
1065
0
  gnutls_datum_t alpn_data[5];
1066
0
  char *s, data[64] = {};
1067
0
  int count = 0;
1068
1069
0
  if (size >= 64)
1070
0
    return -EINVAL;
1071
1072
0
  memcpy(data, alpns, size);
1073
0
  s = strtok(data, ",");
1074
0
  while (s) {
1075
0
    while (*s == ' ')
1076
0
      s++;
1077
0
    alpn_data[count].data = (unsigned char *)s;
1078
0
    alpn_data[count].size = strlen(s);
1079
0
    count++;
1080
0
    s = strtok(NULL, ",");
1081
0
  }
1082
1083
0
  return gnutls_alpn_set_protocols(session, alpn_data, count,
1084
0
           GNUTLS_ALPN_MANDATORY);
1085
0
}