Coverage Report

Created: 2025-03-18 06:55

/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(
48
0
      session,
49
0
      "invalidating session: KTLS - couldn't update keys\n");
50
0
    return GNUTLS_E_INTERNAL_ERROR;
51
0
  }
52
0
  return 0;
53
0
}
54
55
static int update_keys(gnutls_session_t session, hs_stage_t stage)
56
0
{
57
0
  int ret;
58
59
0
  ret = _tls13_update_secret(session,
60
0
           session->key.proto.tls13.temp_secret,
61
0
           session->key.proto.tls13.temp_secret_size);
62
0
  if (ret < 0)
63
0
    return gnutls_assert_val(ret);
64
65
0
  _gnutls_epoch_bump(session);
66
0
  ret = _gnutls_epoch_dup(session, EPOCH_READ_CURRENT);
67
0
  if (ret < 0)
68
0
    return gnutls_assert_val(ret);
69
70
  /* If we send a key update during early start, only update our
71
   * write keys */
72
0
  if (session->internals.recv_state == RECV_STATE_EARLY_START) {
73
0
    ret = _tls13_write_connection_state_init(session, stage);
74
0
    if (ret < 0)
75
0
      return gnutls_assert_val(ret);
76
77
0
    if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_SEND))
78
0
      ret = set_ktls_keys(session, GNUTLS_KTLS_SEND);
79
0
  } else {
80
0
    ret = _tls13_connection_state_init(session, stage);
81
0
    if (ret < 0)
82
0
      return gnutls_assert_val(ret);
83
84
0
    if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_SEND) &&
85
0
        stage == STAGE_UPD_OURS)
86
0
      ret = set_ktls_keys(session, GNUTLS_KTLS_SEND);
87
0
    else if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_RECV) &&
88
0
       stage == STAGE_UPD_PEERS)
89
0
      ret = set_ktls_keys(session, GNUTLS_KTLS_RECV);
90
0
  }
91
0
  if (ret < 0)
92
0
    return gnutls_assert_val(ret);
93
94
0
  return 0;
95
0
}
96
97
int _gnutls13_recv_key_update(gnutls_session_t session, gnutls_buffer_st *buf)
98
0
{
99
0
  int ret;
100
0
  struct timespec now;
101
102
0
  if (buf->length != 1)
103
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
104
105
0
  gnutls_gettime(&now);
106
107
  /* Roll over the counter if the time window has elapsed */
108
0
  if (session->internals.key_update_count == 0 ||
109
0
      timespec_sub_ms(&now, &session->internals.last_key_update) >
110
0
        KEY_UPDATES_WINDOW) {
111
0
    session->internals.last_key_update = now;
112
0
    session->internals.key_update_count = 0;
113
0
  }
114
115
0
  if (unlikely(++session->internals.key_update_count >
116
0
         KEY_UPDATES_PER_WINDOW)) {
117
0
    _gnutls_debug_log(
118
0
      "reached maximum number of key updates per %d milliseconds (%d)\n",
119
0
      KEY_UPDATES_WINDOW, KEY_UPDATES_PER_WINDOW);
120
0
    return gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS);
121
0
  }
122
123
0
  _gnutls_epoch_gc(session);
124
125
0
  _gnutls_handshake_log("HSK[%p]: received TLS 1.3 key update (%u)\n",
126
0
            session, (unsigned)buf->data[0]);
127
128
0
  switch (buf->data[0]) {
129
0
  case 0:
130
    /* peer updated its key, not requested our key update */
131
0
    ret = update_keys(session, STAGE_UPD_PEERS);
132
0
    if (ret < 0)
133
0
      return gnutls_assert_val(ret);
134
135
0
    break;
136
0
  case 1:
137
0
    if (session->internals.hsk_flags & HSK_KEY_UPDATE_ASKED) {
138
      /* if we had asked a key update we shouldn't get this
139
       * reply */
140
0
      return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
141
0
    }
142
143
    /* peer updated its key, requested our key update */
144
0
    ret = update_keys(session, STAGE_UPD_PEERS);
145
0
    if (ret < 0)
146
0
      return gnutls_assert_val(ret);
147
148
    /* we mark that a key update is schedule, and it
149
     * will be performed prior to sending the next application
150
     * message.
151
     */
152
0
    if (session->internals.rsend_state == RECORD_SEND_NORMAL)
153
0
      session->internals.rsend_state =
154
0
        RECORD_SEND_KEY_UPDATE_1;
155
0
    else if (session->internals.rsend_state == RECORD_SEND_CORKED)
156
0
      session->internals.rsend_state =
157
0
        RECORD_SEND_CORKED_TO_KU;
158
159
0
    break;
160
0
  default:
161
0
    return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
162
0
  }
163
164
0
  session->internals.hsk_flags &= ~(unsigned)(HSK_KEY_UPDATE_ASKED);
165
166
0
  return 0;
167
0
}
168
169
int _gnutls13_send_key_update(gnutls_session_t session, unsigned again,
170
            unsigned flags /* GNUTLS_KU_* */)
171
0
{
172
0
  int ret;
173
0
  mbuffer_st *bufel = NULL;
174
0
  uint8_t val;
175
176
0
  if (again == 0) {
177
0
    if (flags & GNUTLS_KU_PEER) {
178
      /* mark that we asked a key update to prevent an
179
       * infinite ping pong when receiving the reply */
180
0
      session->internals.hsk_flags |= HSK_KEY_UPDATE_ASKED;
181
0
      val = 0x01;
182
0
    } else {
183
0
      val = 0x00;
184
0
    }
185
186
0
    _gnutls_handshake_log("HSK[%p]: sending key update (%u)\n",
187
0
              session, (unsigned)val);
188
189
0
    bufel = _gnutls_handshake_alloc(session, 1);
190
0
    if (bufel == NULL)
191
0
      return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
192
193
0
    _mbuffer_set_udata_size(bufel, 0);
194
0
    ret = _mbuffer_append_data(bufel, &val, 1);
195
0
    if (ret < 0) {
196
0
      gnutls_assert();
197
0
      goto cleanup;
198
0
    }
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
}