Coverage Report

Created: 2023-03-26 08:33

/src/gnutls/lib/tls13/key_update.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2017 Red Hat, Inc.
3
 *
4
 * Author: Nikos Mavrogiannopoulos
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 "gnutls_int.h"
24
#include "errors.h"
25
#include "handshake.h"
26
#include "tls13/key_update.h"
27
#include "mem.h"
28
#include "mbuffers.h"
29
#include "secrets.h"
30
#include "system/ktls.h"
31
32
0
#define KEY_UPDATES_WINDOW 1000
33
#define KEY_UPDATES_PER_WINDOW 8
34
35
/*
36
 * Sets kTLS keys if enabled.
37
 * If this operation fails with GNUTLS_E_INTERNAL_ERROR, KTLS is disabled
38
 * because KTLS most likely doesn't support key update.
39
 */
40
static inline int set_ktls_keys(gnutls_session_t session,
41
        gnutls_transport_ktls_enable_flags_t iface)
42
0
{
43
0
  if (_gnutls_ktls_set_keys(session, iface) < 0) {
44
0
    session->internals.ktls_enabled = 0;
45
0
    session->internals.invalid_connection = true;
46
0
    session->internals.resumable = false;
47
0
    _gnutls_audit_log(session,
48
0
          "invalidating session: KTLS - couldn't update keys\n");
49
0
    return GNUTLS_E_INTERNAL_ERROR;
50
0
  }
51
0
  return 0;
52
0
}
53
54
static int update_keys(gnutls_session_t session, hs_stage_t stage)
55
0
{
56
0
  int ret;
57
58
0
  ret =
59
0
      _tls13_update_secret(session, session->key.proto.tls13.temp_secret,
60
0
         session->key.proto.tls13.temp_secret_size);
61
0
  if (ret < 0)
62
0
    return gnutls_assert_val(ret);
63
64
0
  _gnutls_epoch_bump(session);
65
0
  ret = _gnutls_epoch_dup(session, EPOCH_READ_CURRENT);
66
0
  if (ret < 0)
67
0
    return gnutls_assert_val(ret);
68
69
  /* If we send a key update during early start, only update our
70
   * write keys */
71
0
  if (session->internals.recv_state == RECV_STATE_EARLY_START) {
72
0
    ret = _tls13_write_connection_state_init(session, stage);
73
0
    if (ret < 0)
74
0
      return gnutls_assert_val(ret);
75
76
0
    if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_SEND))
77
0
      ret = set_ktls_keys(session, GNUTLS_KTLS_SEND);
78
0
  } else {
79
0
    ret = _tls13_connection_state_init(session, stage);
80
0
    if (ret < 0)
81
0
      return gnutls_assert_val(ret);
82
83
0
    if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_SEND)
84
0
        && stage == STAGE_UPD_OURS)
85
0
      ret = set_ktls_keys(session, GNUTLS_KTLS_SEND);
86
0
    else if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_RECV)
87
0
       && stage == STAGE_UPD_PEERS)
88
0
      ret = set_ktls_keys(session, GNUTLS_KTLS_RECV);
89
0
  }
90
0
  if (ret < 0)
91
0
    return gnutls_assert_val(ret);
92
93
0
  return 0;
94
0
}
95
96
int _gnutls13_recv_key_update(gnutls_session_t session, gnutls_buffer_st * buf)
97
0
{
98
0
  int ret;
99
0
  struct timespec now;
100
101
0
  if (buf->length != 1)
102
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
103
104
0
  gnutls_gettime(&now);
105
106
  /* Roll over the counter if the time window has elapsed */
107
0
  if (session->internals.key_update_count == 0 ||
108
0
      timespec_sub_ms(&now, &session->internals.last_key_update) >
109
0
      KEY_UPDATES_WINDOW) {
110
0
    session->internals.last_key_update = now;
111
0
    session->internals.key_update_count = 0;
112
0
  }
113
114
0
  if (unlikely(++session->internals.key_update_count >
115
0
         KEY_UPDATES_PER_WINDOW)) {
116
0
    _gnutls_debug_log
117
0
        ("reached maximum number of key updates per %d milliseconds (%d)\n",
118
0
         KEY_UPDATES_WINDOW, KEY_UPDATES_PER_WINDOW);
119
0
    return gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS);
120
0
  }
121
122
0
  _gnutls_epoch_gc(session);
123
124
0
  _gnutls_handshake_log("HSK[%p]: received TLS 1.3 key update (%u)\n",
125
0
            session, (unsigned)buf->data[0]);
126
127
0
  switch (buf->data[0]) {
128
0
  case 0:
129
    /* peer updated its key, not requested our key update */
130
0
    ret = update_keys(session, STAGE_UPD_PEERS);
131
0
    if (ret < 0)
132
0
      return gnutls_assert_val(ret);
133
134
0
    break;
135
0
  case 1:
136
0
    if (session->internals.hsk_flags & HSK_KEY_UPDATE_ASKED) {
137
      /* if we had asked a key update we shouldn't get this
138
       * reply */
139
0
      return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
140
0
    }
141
142
    /* peer updated its key, requested our key update */
143
0
    ret = update_keys(session, STAGE_UPD_PEERS);
144
0
    if (ret < 0)
145
0
      return gnutls_assert_val(ret);
146
147
    /* we mark that a key update is schedule, and it
148
     * will be performed prior to sending the next application
149
     * message.
150
     */
151
0
    if (session->internals.rsend_state == RECORD_SEND_NORMAL)
152
0
      session->internals.rsend_state =
153
0
          RECORD_SEND_KEY_UPDATE_1;
154
0
    else if (session->internals.rsend_state == RECORD_SEND_CORKED)
155
0
      session->internals.rsend_state =
156
0
          RECORD_SEND_CORKED_TO_KU;
157
158
0
    break;
159
0
  default:
160
0
    return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
161
0
  }
162
163
0
  session->internals.hsk_flags &= ~(unsigned)(HSK_KEY_UPDATE_ASKED);
164
165
0
  return 0;
166
0
}
167
168
int _gnutls13_send_key_update(gnutls_session_t session, unsigned again,
169
            unsigned flags /* GNUTLS_KU_* */ )
170
0
{
171
0
  int ret;
172
0
  mbuffer_st *bufel = NULL;
173
0
  uint8_t val;
174
175
0
  if (again == 0) {
176
0
    if (flags & GNUTLS_KU_PEER) {
177
      /* mark that we asked a key update to prevent an
178
       * infinite ping pong when receiving the reply */
179
0
      session->internals.hsk_flags |= HSK_KEY_UPDATE_ASKED;
180
0
      val = 0x01;
181
0
    } else {
182
0
      val = 0x00;
183
0
    }
184
185
0
    _gnutls_handshake_log("HSK[%p]: sending key update (%u)\n",
186
0
              session, (unsigned)val);
187
188
0
    bufel = _gnutls_handshake_alloc(session, 1);
189
0
    if (bufel == NULL)
190
0
      return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
191
192
0
    _mbuffer_set_udata_size(bufel, 0);
193
0
    ret = _mbuffer_append_data(bufel, &val, 1);
194
0
    if (ret < 0) {
195
0
      gnutls_assert();
196
0
      goto cleanup;
197
0
    }
198
199
0
  }
200
201
0
  return _gnutls_send_handshake(session, bufel,
202
0
              GNUTLS_HANDSHAKE_KEY_UPDATE);
203
204
0
 cleanup:
205
0
  _mbuffer_xfree(&bufel);
206
0
  return ret;
207
0
}
208
209
/**
210
 * gnutls_session_key_update:
211
 * @session: is a #gnutls_session_t type.
212
 * @flags: zero of %GNUTLS_KU_PEER
213
 *
214
 * This function will update/refresh the session keys when the
215
 * TLS protocol is 1.3 or better. The peer is notified of the
216
 * update by sending a message, so this function should be
217
 * treated similarly to gnutls_record_send() --i.e., it may
218
 * return %GNUTLS_E_AGAIN or %GNUTLS_E_INTERRUPTED.
219
 *
220
 * When this flag %GNUTLS_KU_PEER is specified, this function
221
 * in addition to updating the local keys, will ask the peer to
222
 * refresh its keys too.
223
 *
224
 * If the negotiated version is not TLS 1.3 or better this
225
 * function will return %GNUTLS_E_INVALID_REQUEST.
226
 *
227
 * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
228
 *
229
 * Since: 3.6.3
230
 **/
231
int gnutls_session_key_update(gnutls_session_t session, unsigned flags)
232
0
{
233
0
  int ret;
234
0
  const version_entry_st *vers = get_version(session);
235
236
0
  if (!vers->tls13_sem)
237
0
    return GNUTLS_E_INVALID_REQUEST;
238
239
0
  ret = _gnutls13_send_key_update(session, AGAIN(STATE150), flags);
240
0
  STATE = STATE150;
241
242
0
  if (ret < 0) {
243
0
    gnutls_assert();
244
0
    return ret;
245
0
  }
246
0
  STATE = STATE0;
247
248
0
  _gnutls_epoch_gc(session);
249
250
  /* it was completely sent, update the keys */
251
0
  ret = update_keys(session, STAGE_UPD_OURS);
252
0
  if (ret < 0)
253
0
    return gnutls_assert_val(ret);
254
255
0
  return 0;
256
0
}