Coverage Report

Created: 2023-03-26 07:33

/src/gnutls/lib/system/ktls.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2021 Free Software Foundation, Inc.
3
 *
4
 * Author: Fratnišek Krenželok
5
 *
6
 * This file is part of GnuTLS.
7
 *
8
 * The GnuTLS is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public License
10
 * as published by the Free Software Foundation; either version 2.1 of
11
 * the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
20
 *
21
 */
22
23
#include "config.h"
24
#include "system/ktls.h"
25
26
#ifdef ENABLE_KTLS
27
28
# include <linux/tls.h>
29
# include <record.h>
30
# include <sys/socket.h>
31
# include <netinet/tcp.h>
32
# include <unistd.h>
33
# include <errno.h>
34
# include "ext/session_ticket.h"
35
# include <sys/sendfile.h>
36
37
/**
38
 * gnutls_transport_is_ktls_enabled:
39
 * @session: is a #gnutls_session_t type.
40
 *
41
 * Checks if KTLS is now enabled and was properly inicialized.
42
 *
43
 * Returns: %GNUTLS_KTLS_RECV, %GNUTLS_KTLS_SEND, %GNUTLS_KTLS_DUPLEX, otherwise 0
44
 *
45
 * Since: 3.7.3
46
 **/
47
gnutls_transport_ktls_enable_flags_t
48
gnutls_transport_is_ktls_enabled(gnutls_session_t session)
49
{
50
  if (unlikely(!session->internals.initial_negotiation_completed)) {
51
    _gnutls_debug_log("Initial negotiation is not yet complete\n");
52
    return 0;
53
  }
54
55
  return session->internals.ktls_enabled;
56
}
57
58
void _gnutls_ktls_enable(gnutls_session_t session)
59
{
60
  int sockin, sockout;
61
62
  gnutls_transport_get_int2(session, &sockin, &sockout);
63
64
  if (setsockopt(sockin, SOL_TCP, TCP_ULP, "tls", sizeof("tls")) == 0) {
65
    session->internals.ktls_enabled |= GNUTLS_KTLS_RECV;
66
    if (sockin == sockout) {
67
      session->internals.ktls_enabled |= GNUTLS_KTLS_SEND;
68
    }
69
  } else {
70
    _gnutls_record_log
71
        ("Unable to set TCP_ULP for read socket: %d\n", errno);
72
  }
73
74
  if (sockin != sockout) {
75
    if (setsockopt(sockout, SOL_TCP, TCP_ULP, "tls", sizeof("tls"))
76
        == 0) {
77
      session->internals.ktls_enabled |= GNUTLS_KTLS_SEND;
78
    } else {
79
      _gnutls_record_log
80
          ("Unable to set TCP_ULP for write socket: %d\n",
81
           errno);
82
    }
83
  }
84
}
85
86
int _gnutls_ktls_set_keys(gnutls_session_t session,
87
        gnutls_transport_ktls_enable_flags_t in)
88
{
89
  gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(session);
90
  gnutls_datum_t mac_key;
91
  gnutls_datum_t iv;
92
  gnutls_datum_t cipher_key;
93
  unsigned char seq_number[12];
94
  int sockin, sockout;
95
  int ret;
96
97
  gnutls_transport_get_int2(session, &sockin, &sockout);
98
99
  /* check whether or not cipher suite supports ktls
100
   */
101
  int version = gnutls_protocol_get_version(session);
102
  if ((version != GNUTLS_TLS1_3 && version != GNUTLS_TLS1_2) ||
103
      (gnutls_cipher_get(session) != GNUTLS_CIPHER_AES_128_GCM &&
104
       gnutls_cipher_get(session) != GNUTLS_CIPHER_AES_256_GCM &&
105
       gnutls_cipher_get(session) != GNUTLS_CIPHER_AES_128_CCM &&
106
       gnutls_cipher_get(session) != GNUTLS_CIPHER_CHACHA20_POLY1305)) {
107
    return GNUTLS_E_UNIMPLEMENTED_FEATURE;
108
  }
109
110
  ret = gnutls_record_get_state(session, 1, &mac_key, &iv, &cipher_key,
111
              seq_number);
112
  if (ret < 0) {
113
    return ret;
114
  }
115
116
  in &= session->internals.ktls_enabled;
117
118
  if (in & GNUTLS_KTLS_RECV) {
119
    switch (cipher) {
120
    case GNUTLS_CIPHER_AES_128_GCM:
121
      {
122
        struct tls12_crypto_info_aes_gcm_128
123
            crypto_info;
124
        memset(&crypto_info, 0, sizeof(crypto_info));
125
126
        crypto_info.info.cipher_type =
127
            TLS_CIPHER_AES_GCM_128;
128
        assert(cipher_key.size ==
129
               TLS_CIPHER_AES_GCM_128_KEY_SIZE);
130
131
        /* for TLS 1.2 IV is generated in kernel */
132
        if (version == GNUTLS_TLS1_2) {
133
          crypto_info.info.version =
134
              TLS_1_2_VERSION;
135
          memcpy(crypto_info.iv, seq_number,
136
                 TLS_CIPHER_AES_GCM_128_IV_SIZE);
137
        } else {
138
          crypto_info.info.version =
139
              TLS_1_3_VERSION;
140
          assert(iv.size ==
141
                 TLS_CIPHER_AES_GCM_128_SALT_SIZE
142
                 +
143
                 TLS_CIPHER_AES_GCM_128_IV_SIZE);
144
145
          memcpy(crypto_info.iv, iv.data +
146
                 TLS_CIPHER_AES_GCM_128_SALT_SIZE,
147
                 TLS_CIPHER_AES_GCM_128_IV_SIZE);
148
        }
149
150
        memcpy(crypto_info.salt, iv.data,
151
               TLS_CIPHER_AES_GCM_128_SALT_SIZE);
152
        memcpy(crypto_info.rec_seq, seq_number,
153
               TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
154
        memcpy(crypto_info.key, cipher_key.data,
155
               TLS_CIPHER_AES_GCM_128_KEY_SIZE);
156
157
        if (setsockopt(sockin, SOL_TLS, TLS_RX,
158
                 &crypto_info,
159
                 sizeof(crypto_info))) {
160
          session->internals.ktls_enabled &=
161
              ~GNUTLS_KTLS_RECV;
162
          return
163
              gnutls_assert_val
164
              (GNUTLS_E_INTERNAL_ERROR);
165
        }
166
      }
167
      break;
168
    case GNUTLS_CIPHER_AES_256_GCM:
169
      {
170
        struct tls12_crypto_info_aes_gcm_256
171
            crypto_info;
172
        memset(&crypto_info, 0, sizeof(crypto_info));
173
174
        crypto_info.info.cipher_type =
175
            TLS_CIPHER_AES_GCM_256;
176
        assert(cipher_key.size ==
177
               TLS_CIPHER_AES_GCM_256_KEY_SIZE);
178
179
        /* for TLS 1.2 IV is generated in kernel */
180
        if (version == GNUTLS_TLS1_2) {
181
          crypto_info.info.version =
182
              TLS_1_2_VERSION;
183
          memcpy(crypto_info.iv, seq_number,
184
                 TLS_CIPHER_AES_GCM_256_IV_SIZE);
185
        } else {
186
          crypto_info.info.version =
187
              TLS_1_3_VERSION;
188
          assert(iv.size ==
189
                 TLS_CIPHER_AES_GCM_256_SALT_SIZE
190
                 +
191
                 TLS_CIPHER_AES_GCM_256_IV_SIZE);
192
193
          memcpy(crypto_info.iv,
194
                 iv.data +
195
                 TLS_CIPHER_AES_GCM_256_SALT_SIZE,
196
                 TLS_CIPHER_AES_GCM_256_IV_SIZE);
197
        }
198
199
        memcpy(crypto_info.salt, iv.data,
200
               TLS_CIPHER_AES_GCM_256_SALT_SIZE);
201
        memcpy(crypto_info.rec_seq, seq_number,
202
               TLS_CIPHER_AES_GCM_256_REC_SEQ_SIZE);
203
        memcpy(crypto_info.key, cipher_key.data,
204
               TLS_CIPHER_AES_GCM_256_KEY_SIZE);
205
206
        if (setsockopt(sockin, SOL_TLS, TLS_RX,
207
                 &crypto_info,
208
                 sizeof(crypto_info))) {
209
          session->internals.ktls_enabled &=
210
              ~GNUTLS_KTLS_RECV;
211
          return
212
              gnutls_assert_val
213
              (GNUTLS_E_INTERNAL_ERROR);
214
        }
215
      }
216
      break;
217
    case GNUTLS_CIPHER_AES_128_CCM:
218
      {
219
        struct tls12_crypto_info_aes_ccm_128
220
            crypto_info;
221
        memset(&crypto_info, 0, sizeof(crypto_info));
222
223
        crypto_info.info.cipher_type =
224
            TLS_CIPHER_AES_CCM_128;
225
        assert(cipher_key.size ==
226
               TLS_CIPHER_AES_CCM_128_KEY_SIZE);
227
228
        /* for TLS 1.2 IV is generated in kernel */
229
        if (version == GNUTLS_TLS1_2) {
230
          crypto_info.info.version =
231
              TLS_1_2_VERSION;
232
          memcpy(crypto_info.iv, seq_number,
233
                 TLS_CIPHER_AES_CCM_128_IV_SIZE);
234
        } else {
235
          crypto_info.info.version =
236
              TLS_1_3_VERSION;
237
          assert(iv.size ==
238
                 TLS_CIPHER_AES_CCM_128_SALT_SIZE
239
                 +
240
                 TLS_CIPHER_AES_CCM_128_IV_SIZE);
241
242
          memcpy(crypto_info.iv, iv.data +
243
                 TLS_CIPHER_AES_CCM_128_SALT_SIZE,
244
                 TLS_CIPHER_AES_CCM_128_IV_SIZE);
245
        }
246
247
        memcpy(crypto_info.salt, iv.data,
248
               TLS_CIPHER_AES_CCM_128_SALT_SIZE);
249
        memcpy(crypto_info.rec_seq, seq_number,
250
               TLS_CIPHER_AES_CCM_128_REC_SEQ_SIZE);
251
        memcpy(crypto_info.key, cipher_key.data,
252
               TLS_CIPHER_AES_CCM_128_KEY_SIZE);
253
254
        if (setsockopt(sockin, SOL_TLS, TLS_RX,
255
                 &crypto_info,
256
                 sizeof(crypto_info))) {
257
          session->internals.ktls_enabled &=
258
              ~GNUTLS_KTLS_RECV;
259
          return
260
              gnutls_assert_val
261
              (GNUTLS_E_INTERNAL_ERROR);
262
        }
263
      }
264
      break;
265
    case GNUTLS_CIPHER_CHACHA20_POLY1305:
266
      {
267
        struct tls12_crypto_info_chacha20_poly1305
268
            crypto_info;
269
        memset(&crypto_info, 0, sizeof(crypto_info));
270
271
        crypto_info.info.cipher_type =
272
            TLS_CIPHER_CHACHA20_POLY1305;
273
        assert(cipher_key.size ==
274
               TLS_CIPHER_CHACHA20_POLY1305_KEY_SIZE);
275
276
        /* for TLS 1.2 IV is generated in kernel */
277
        if (version == GNUTLS_TLS1_2) {
278
          crypto_info.info.version =
279
              TLS_1_2_VERSION;
280
          memcpy(crypto_info.iv, seq_number,
281
                 TLS_CIPHER_CHACHA20_POLY1305_IV_SIZE);
282
        } else {
283
          crypto_info.info.version =
284
              TLS_1_3_VERSION;
285
          assert(iv.size ==
286
                 TLS_CIPHER_CHACHA20_POLY1305_SALT_SIZE
287
                 +
288
                 TLS_CIPHER_CHACHA20_POLY1305_IV_SIZE);
289
290
          memcpy(crypto_info.iv, iv.data +
291
                 TLS_CIPHER_CHACHA20_POLY1305_SALT_SIZE,
292
                 TLS_CIPHER_CHACHA20_POLY1305_IV_SIZE);
293
        }
294
295
        memcpy(crypto_info.salt, iv.data,
296
               TLS_CIPHER_CHACHA20_POLY1305_SALT_SIZE);
297
        memcpy(crypto_info.rec_seq, seq_number,
298
               TLS_CIPHER_CHACHA20_POLY1305_REC_SEQ_SIZE);
299
        memcpy(crypto_info.key, cipher_key.data,
300
               TLS_CIPHER_CHACHA20_POLY1305_KEY_SIZE);
301
302
        if (setsockopt(sockin, SOL_TLS, TLS_RX,
303
                 &crypto_info,
304
                 sizeof(crypto_info))) {
305
          session->internals.ktls_enabled &=
306
              ~GNUTLS_KTLS_RECV;
307
          return
308
              gnutls_assert_val
309
              (GNUTLS_E_INTERNAL_ERROR);
310
        }
311
      }
312
      break;
313
    default:
314
      assert(0);
315
    }
316
317
  }
318
319
  ret = gnutls_record_get_state(session, 0, &mac_key, &iv, &cipher_key,
320
              seq_number);
321
  if (ret < 0) {
322
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
323
  }
324
325
  if (in & GNUTLS_KTLS_SEND) {
326
    switch (cipher) {
327
    case GNUTLS_CIPHER_AES_128_GCM:
328
      {
329
        struct tls12_crypto_info_aes_gcm_128
330
            crypto_info;
331
        memset(&crypto_info, 0, sizeof(crypto_info));
332
333
        crypto_info.info.cipher_type =
334
            TLS_CIPHER_AES_GCM_128;
335
336
        assert(cipher_key.size ==
337
               TLS_CIPHER_AES_GCM_128_KEY_SIZE);
338
339
        /* for TLS 1.2 IV is generated in kernel */
340
        if (version == GNUTLS_TLS1_2) {
341
          crypto_info.info.version =
342
              TLS_1_2_VERSION;
343
          memcpy(crypto_info.iv, seq_number,
344
                 TLS_CIPHER_AES_GCM_128_IV_SIZE);
345
        } else {
346
          crypto_info.info.version =
347
              TLS_1_3_VERSION;
348
          assert(iv.size ==
349
                 TLS_CIPHER_AES_GCM_128_SALT_SIZE
350
                 +
351
                 TLS_CIPHER_AES_GCM_128_IV_SIZE);
352
353
          memcpy(crypto_info.iv,
354
                 iv.data +
355
                 TLS_CIPHER_AES_GCM_128_SALT_SIZE,
356
                 TLS_CIPHER_AES_GCM_128_IV_SIZE);
357
        }
358
359
        memcpy(crypto_info.salt, iv.data,
360
               TLS_CIPHER_AES_GCM_128_SALT_SIZE);
361
        memcpy(crypto_info.rec_seq, seq_number,
362
               TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
363
        memcpy(crypto_info.key, cipher_key.data,
364
               TLS_CIPHER_AES_GCM_128_KEY_SIZE);
365
366
        if (setsockopt(sockout, SOL_TLS, TLS_TX,
367
                 &crypto_info,
368
                 sizeof(crypto_info))) {
369
          session->internals.ktls_enabled &=
370
              ~GNUTLS_KTLS_SEND;
371
          return
372
              gnutls_assert_val
373
              (GNUTLS_E_INTERNAL_ERROR);
374
        }
375
      }
376
      break;
377
    case GNUTLS_CIPHER_AES_256_GCM:
378
      {
379
        struct tls12_crypto_info_aes_gcm_256
380
            crypto_info;
381
        memset(&crypto_info, 0, sizeof(crypto_info));
382
383
        crypto_info.info.cipher_type =
384
            TLS_CIPHER_AES_GCM_256;
385
        assert(cipher_key.size ==
386
               TLS_CIPHER_AES_GCM_256_KEY_SIZE);
387
388
        /* for TLS 1.2 IV is generated in kernel */
389
        if (version == GNUTLS_TLS1_2) {
390
          crypto_info.info.version =
391
              TLS_1_2_VERSION;
392
          memcpy(crypto_info.iv, seq_number,
393
                 TLS_CIPHER_AES_GCM_256_IV_SIZE);
394
        } else {
395
          crypto_info.info.version =
396
              TLS_1_3_VERSION;
397
          assert(iv.size ==
398
                 TLS_CIPHER_AES_GCM_256_SALT_SIZE
399
                 +
400
                 TLS_CIPHER_AES_GCM_256_IV_SIZE);
401
402
          memcpy(crypto_info.iv,
403
                 iv.data +
404
                 TLS_CIPHER_AES_GCM_256_SALT_SIZE,
405
                 TLS_CIPHER_AES_GCM_256_IV_SIZE);
406
        }
407
408
        memcpy(crypto_info.salt, iv.data,
409
               TLS_CIPHER_AES_GCM_256_SALT_SIZE);
410
        memcpy(crypto_info.rec_seq, seq_number,
411
               TLS_CIPHER_AES_GCM_256_REC_SEQ_SIZE);
412
        memcpy(crypto_info.key, cipher_key.data,
413
               TLS_CIPHER_AES_GCM_256_KEY_SIZE);
414
415
        if (setsockopt(sockout, SOL_TLS, TLS_TX,
416
                 &crypto_info,
417
                 sizeof(crypto_info))) {
418
          session->internals.ktls_enabled &=
419
              ~GNUTLS_KTLS_SEND;
420
          return
421
              gnutls_assert_val
422
              (GNUTLS_E_INTERNAL_ERROR);
423
        }
424
      }
425
      break;
426
    case GNUTLS_CIPHER_AES_128_CCM:
427
      {
428
        struct tls12_crypto_info_aes_ccm_128
429
            crypto_info;
430
        memset(&crypto_info, 0, sizeof(crypto_info));
431
432
        crypto_info.info.cipher_type =
433
            TLS_CIPHER_AES_CCM_128;
434
        assert(cipher_key.size ==
435
               TLS_CIPHER_AES_CCM_128_KEY_SIZE);
436
437
        /* for TLS 1.2 IV is generated in kernel */
438
        if (version == GNUTLS_TLS1_2) {
439
          crypto_info.info.version =
440
              TLS_1_2_VERSION;
441
          memcpy(crypto_info.iv, seq_number,
442
                 TLS_CIPHER_AES_CCM_128_IV_SIZE);
443
        } else {
444
          crypto_info.info.version =
445
              TLS_1_3_VERSION;
446
          assert(iv.size ==
447
                 TLS_CIPHER_AES_CCM_128_SALT_SIZE
448
                 +
449
                 TLS_CIPHER_AES_CCM_128_IV_SIZE);
450
451
          memcpy(crypto_info.iv,
452
                 iv.data +
453
                 TLS_CIPHER_AES_CCM_128_SALT_SIZE,
454
                 TLS_CIPHER_AES_CCM_128_IV_SIZE);
455
        }
456
457
        memcpy(crypto_info.salt, iv.data,
458
               TLS_CIPHER_AES_CCM_128_SALT_SIZE);
459
        memcpy(crypto_info.rec_seq, seq_number,
460
               TLS_CIPHER_AES_CCM_128_REC_SEQ_SIZE);
461
        memcpy(crypto_info.key, cipher_key.data,
462
               TLS_CIPHER_AES_CCM_128_KEY_SIZE);
463
464
        if (setsockopt(sockout, SOL_TLS, TLS_TX,
465
                 &crypto_info,
466
                 sizeof(crypto_info))) {
467
          session->internals.ktls_enabled &=
468
              ~GNUTLS_KTLS_SEND;
469
          return
470
              gnutls_assert_val
471
              (GNUTLS_E_INTERNAL_ERROR);
472
        }
473
      }
474
      break;
475
    case GNUTLS_CIPHER_CHACHA20_POLY1305:
476
      {
477
        struct tls12_crypto_info_chacha20_poly1305
478
            crypto_info;
479
        memset(&crypto_info, 0, sizeof(crypto_info));
480
481
        crypto_info.info.cipher_type =
482
            TLS_CIPHER_CHACHA20_POLY1305;
483
        assert(cipher_key.size ==
484
               TLS_CIPHER_CHACHA20_POLY1305_KEY_SIZE);
485
486
        /* for TLS 1.2 IV is generated in kernel */
487
        if (version == GNUTLS_TLS1_2) {
488
          crypto_info.info.version =
489
              TLS_1_2_VERSION;
490
          memcpy(crypto_info.iv, seq_number,
491
                 TLS_CIPHER_CHACHA20_POLY1305_IV_SIZE);
492
        } else {
493
          crypto_info.info.version =
494
              TLS_1_3_VERSION;
495
          assert(iv.size ==
496
                 TLS_CIPHER_CHACHA20_POLY1305_SALT_SIZE
497
                 +
498
                 TLS_CIPHER_CHACHA20_POLY1305_IV_SIZE);
499
500
          memcpy(crypto_info.iv,
501
                 iv.data +
502
                 TLS_CIPHER_CHACHA20_POLY1305_SALT_SIZE,
503
                 TLS_CIPHER_CHACHA20_POLY1305_IV_SIZE);
504
        }
505
506
        memcpy(crypto_info.salt, iv.data,
507
               TLS_CIPHER_CHACHA20_POLY1305_SALT_SIZE);
508
        memcpy(crypto_info.rec_seq, seq_number,
509
               TLS_CIPHER_CHACHA20_POLY1305_REC_SEQ_SIZE);
510
        memcpy(crypto_info.key, cipher_key.data,
511
               TLS_CIPHER_CHACHA20_POLY1305_KEY_SIZE);
512
513
        if (setsockopt(sockout, SOL_TLS, TLS_TX,
514
                 &crypto_info,
515
                 sizeof(crypto_info))) {
516
          session->internals.ktls_enabled &=
517
              ~GNUTLS_KTLS_SEND;
518
          return
519
              gnutls_assert_val
520
              (GNUTLS_E_INTERNAL_ERROR);
521
        }
522
      }
523
      break;
524
    default:
525
      assert(0);
526
    }
527
528
    // set callback for sending handshake messages
529
    gnutls_handshake_set_read_function(session,
530
               _gnutls_ktls_send_handshake_msg);
531
532
    // set callback for sending alert messages
533
    gnutls_alert_set_read_function(session,
534
                 _gnutls_ktls_send_alert_msg);
535
  }
536
537
  return in;
538
}
539
540
ssize_t _gnutls_ktls_send_file(gnutls_session_t session, int fd,
541
             off_t * offset, size_t count)
542
{
543
  ssize_t ret;
544
  int sockin, sockout;
545
546
  assert(session != NULL);
547
548
  gnutls_transport_get_int2(session, &sockin, &sockout);
549
550
  ret = sendfile(sockout, fd, offset, count);
551
  if (ret == -1) {
552
    switch (errno) {
553
    case EINTR:
554
      return GNUTLS_E_INTERRUPTED;
555
    case EAGAIN:
556
      return GNUTLS_E_AGAIN;
557
    default:
558
      return GNUTLS_E_PUSH_ERROR;
559
    }
560
  }
561
562
  return ret;
563
}
564
565
int _gnutls_ktls_send_control_msg(gnutls_session_t session,
566
          unsigned char record_type, const void *data,
567
          size_t data_size)
568
{
569
  const char *buf = data;
570
  ssize_t ret;
571
  int sockin, sockout;
572
  size_t data_to_send = data_size;
573
574
  assert(session != NULL);
575
576
  gnutls_transport_get_int2(session, &sockin, &sockout);
577
578
  while (data_to_send > 0) {
579
    char cmsg[CMSG_SPACE(sizeof(unsigned char))];
580
    struct msghdr msg = { 0 };
581
    struct iovec msg_iov; /* Vector of data to send/receive into. */
582
    struct cmsghdr *hdr;
583
584
    msg.msg_control = cmsg;
585
    msg.msg_controllen = sizeof cmsg;
586
587
    hdr = CMSG_FIRSTHDR(&msg);
588
    hdr->cmsg_level = SOL_TLS;
589
    hdr->cmsg_type = TLS_SET_RECORD_TYPE;
590
    hdr->cmsg_len = CMSG_LEN(sizeof(unsigned char));
591
592
    // construct record header
593
    *CMSG_DATA(hdr) = record_type;
594
    msg.msg_controllen = hdr->cmsg_len;
595
596
    msg_iov.iov_base = (void *)buf;
597
    msg_iov.iov_len = data_to_send;
598
599
    msg.msg_iov = &msg_iov;
600
    msg.msg_iovlen = 1;
601
602
    ret = sendmsg(sockout, &msg, MSG_DONTWAIT);
603
604
    if (ret == -1) {
605
      switch (errno) {
606
      case EINTR:
607
        if (data_to_send < data_size) {
608
          return data_size - data_to_send;
609
        } else {
610
          return GNUTLS_E_INTERRUPTED;
611
        }
612
      case EAGAIN:
613
        if (data_to_send < data_size) {
614
          return data_size - data_to_send;
615
        } else {
616
          return GNUTLS_E_AGAIN;
617
        }
618
      default:
619
        return GNUTLS_E_PUSH_ERROR;
620
      }
621
    }
622
623
    buf += ret;
624
    data_to_send -= ret;
625
  }
626
627
  return data_size;
628
}
629
630
int _gnutls_ktls_send_handshake_msg(gnutls_session_t session,
631
            gnutls_record_encryption_level_t level,
632
            gnutls_handshake_description_t htype,
633
            const void *data, size_t data_size)
634
{
635
  return _gnutls_ktls_send_control_msg(session, GNUTLS_HANDSHAKE,
636
               data, data_size);
637
}
638
639
int _gnutls_ktls_send_alert_msg(gnutls_session_t session,
640
        gnutls_record_encryption_level_t level,
641
        gnutls_alert_level_t alert_level,
642
        gnutls_alert_description_t alert_desc)
643
{
644
  uint8_t data[2];
645
  data[0] = (uint8_t) alert_level;
646
  data[1] = (uint8_t) alert_desc;
647
  return _gnutls_ktls_send_control_msg(session, GNUTLS_ALERT, data, 2);
648
}
649
650
int _gnutls_ktls_recv_control_msg(gnutls_session_t session,
651
          unsigned char *record_type, void *data,
652
          size_t data_size)
653
{
654
  char *buf = data;
655
  ssize_t ret;
656
  int sockin, sockout;
657
658
  char cmsg[CMSG_SPACE(sizeof(unsigned char))];
659
  struct msghdr msg = { 0 };
660
  struct iovec msg_iov;
661
  struct cmsghdr *hdr;
662
663
  assert(session != NULL);
664
665
  gnutls_transport_get_int2(session, &sockin, &sockout);
666
667
  if (session->internals.read_eof != 0) {
668
    return 0;
669
  } else if (session->internals.invalid_connection != 0 ||
670
       session->internals.may_not_read != 0)
671
    return GNUTLS_E_INVALID_SESSION;
672
673
  /* receive message */
674
  msg.msg_control = cmsg;
675
  msg.msg_controllen = sizeof cmsg;
676
677
  msg_iov.iov_base = buf;
678
  msg_iov.iov_len = data_size;
679
680
  msg.msg_iov = &msg_iov;
681
  msg.msg_iovlen = 1;
682
683
  ret = recvmsg(sockin, &msg, MSG_DONTWAIT);
684
685
  if (ret == -1) {
686
    switch (errno) {
687
    case EAGAIN:
688
      return GNUTLS_E_AGAIN;
689
    case EINVAL:
690
      return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
691
    case EMSGSIZE:
692
      return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
693
    case EBADMSG:
694
      return GNUTLS_E_DECRYPTION_FAILED;
695
    default:
696
      return GNUTLS_E_PULL_ERROR;
697
    }
698
  }
699
700
  /* connection closed */
701
  if (ret == 0)
702
    return 0;
703
704
  /* get record type from header */
705
  hdr = CMSG_FIRSTHDR(&msg);
706
  if (hdr == NULL) {
707
    return GNUTLS_E_PULL_ERROR;
708
  }
709
  if (hdr->cmsg_level == SOL_TLS && hdr->cmsg_type == TLS_GET_RECORD_TYPE)
710
    *record_type = *(unsigned char *)CMSG_DATA(hdr);
711
  else
712
    *record_type = GNUTLS_APPLICATION_DATA;
713
714
  return ret;
715
}
716
717
int _gnutls_ktls_recv_int(gnutls_session_t session, content_type_t type,
718
        void *data, size_t data_size)
719
{
720
  unsigned char record_type;
721
  int ret;
722
723
  ret = _gnutls_ktls_recv_control_msg(session,
724
              &record_type, data, data_size);
725
726
  if (ret > 0) {
727
    switch (record_type) {
728
    case GNUTLS_CHANGE_CIPHER_SPEC:
729
      return
730
          gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
731
      break;
732
    case GNUTLS_ALERT:
733
      session_invalidate(session);
734
      ret = 0;
735
      break;
736
    case GNUTLS_HANDSHAKE:
737
      ret = gnutls_handshake_write(session,
738
                 GNUTLS_ENCRYPTION_LEVEL_APPLICATION,
739
                 data, ret);
740
741
      if (ret < 0)
742
        return gnutls_assert_val(ret);
743
744
      if (type != record_type)
745
        return GNUTLS_E_AGAIN;
746
      break;
747
    case GNUTLS_APPLICATION_DATA:
748
      if (type != record_type)
749
        ret = GNUTLS_E_GOT_APPLICATION_DATA;
750
      break;
751
    case GNUTLS_HEARTBEAT:
752
      break;
753
    default:
754
      gnutls_assert();
755
      return GNUTLS_E_UNEXPECTED_PACKET;
756
    }
757
  }
758
  return ret;
759
}
760
761
#else       //ENABLE_KTLS
762
gnutls_transport_ktls_enable_flags_t
763
gnutls_transport_is_ktls_enabled(gnutls_session_t session)
764
0
{
765
0
  return 0;
766
0
}
767
768
void _gnutls_ktls_enable(gnutls_session_t session)
769
0
{
770
0
}
771
772
int _gnutls_ktls_set_keys(gnutls_session_t sessioni,
773
        gnutls_transport_ktls_enable_flags_t in)
774
0
{
775
0
  return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
776
0
}
777
778
ssize_t _gnutls_ktls_send_file(gnutls_session_t session, int fd,
779
             off_t * offset, size_t count)
780
0
{
781
0
  return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
782
0
}
783
784
int _gnutls_ktls_send_control_msg(gnutls_session_t session,
785
          unsigned char record_type, const void *data,
786
          size_t data_size)
787
0
{
788
0
  return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
789
0
}
790
791
int _gnutls_ktls_send_handshake_msg(gnutls_session_t session,
792
            gnutls_record_encryption_level_t level,
793
            gnutls_handshake_description_t htype,
794
            const void *data, size_t data_size)
795
0
{
796
0
  (void)level;
797
0
  return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
798
0
}
799
800
int _gnutls_ktls_recv_int(gnutls_session_t session, content_type_t type,
801
        void *data, size_t data_size)
802
0
{
803
0
  return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
804
0
}
805
806
#endif        //ENABLE_KTLS