Coverage Report

Created: 2024-06-20 06:28

/src/gnutls/lib/ext/psk_ke_modes.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2017 Free Software Foundation, Inc.
3
 *
4
 * Author: Ander Juaristi
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 "ext/psk_ke_modes.h"
25
#include "ext/pre_shared_key.h"
26
#include <assert.h>
27
28
0
#define PSK_KE 0
29
0
#define PSK_DHE_KE 1
30
31
static int psk_ke_modes_send_params(gnutls_session_t session,
32
            gnutls_buffer_t extdata)
33
0
{
34
0
  int ret;
35
0
  const version_entry_st *vers;
36
0
  uint8_t data[2];
37
0
  unsigned pos, i;
38
0
  unsigned have_dhpsk = 0;
39
0
  unsigned have_psk = 0;
40
41
  /* Server doesn't send psk_key_exchange_modes */
42
0
  if (session->security_parameters.entity == GNUTLS_SERVER)
43
0
    return 0;
44
45
  /* If session ticket is disabled and no PSK key exchange is
46
   * enabled, don't send the extension */
47
0
  if ((session->internals.flags & GNUTLS_NO_TICKETS) &&
48
0
      !session->internals.priorities->have_psk)
49
0
    return 0;
50
51
0
  vers = _gnutls_version_max(session);
52
0
  if (!vers || !vers->tls13_sem)
53
0
    return 0;
54
55
  /* We send the list prioritized according to our preferences as a convention
56
   * (used throughout the protocol), even if the protocol doesn't mandate that
57
   * for this particular message. That way we can keep the TLS 1.2 semantics/
58
   * prioritization when negotiating PSK or DHE-PSK. Receiving servers would
59
   * very likely respect our prioritization if they parse the message serially. */
60
0
  pos = 0;
61
0
  for (i = 0; i < session->internals.priorities->_kx.num_priorities;
62
0
       i++) {
63
0
    if (session->internals.priorities->_kx.priorities[i] ==
64
0
          GNUTLS_KX_PSK &&
65
0
        !have_psk) {
66
0
      assert(pos <= 1);
67
0
      data[pos++] = PSK_KE;
68
0
      session->internals.hsk_flags |= HSK_PSK_KE_MODE_PSK;
69
0
      have_psk = 1;
70
0
    } else if ((session->internals.priorities->_kx.priorities[i] ==
71
0
            GNUTLS_KX_DHE_PSK ||
72
0
          session->internals.priorities->_kx.priorities[i] ==
73
0
            GNUTLS_KX_ECDHE_PSK) &&
74
0
         !have_dhpsk) {
75
0
      assert(pos <= 1);
76
0
      data[pos++] = PSK_DHE_KE;
77
0
      session->internals.hsk_flags |= HSK_PSK_KE_MODE_DHE_PSK;
78
0
      have_dhpsk = 1;
79
0
    }
80
81
0
    if (have_psk && have_dhpsk)
82
0
      break;
83
0
  }
84
85
  /* For session resumption we need to send at least one */
86
0
  if (pos == 0) {
87
0
    if (session->internals.flags & GNUTLS_NO_TICKETS)
88
0
      return 0;
89
90
0
    data[pos++] = PSK_DHE_KE;
91
0
    data[pos++] = PSK_KE;
92
0
    session->internals.hsk_flags |= HSK_PSK_KE_MODE_DHE_PSK;
93
0
    session->internals.hsk_flags |= HSK_PSK_KE_MODE_PSK;
94
0
  }
95
96
0
  ret = _gnutls_buffer_append_data_prefix(extdata, 8, data, pos);
97
0
  if (ret < 0)
98
0
    return gnutls_assert_val(ret);
99
100
0
  session->internals.hsk_flags |= HSK_PSK_KE_MODES_SENT;
101
102
0
  return 0;
103
0
}
104
105
0
#define MAX_POS INT_MAX
106
107
/*
108
 * Since we only support ECDHE-authenticated PSKs, the server
109
 * just verifies that a "psk_key_exchange_modes" extension was received,
110
 * and that it contains the value one.
111
 */
112
static int psk_ke_modes_recv_params(gnutls_session_t session,
113
            const unsigned char *data, size_t len)
114
0
{
115
0
  uint8_t ke_modes_len;
116
0
  const version_entry_st *vers = get_version(session);
117
0
  gnutls_psk_server_credentials_t cred;
118
0
  int dhpsk_pos = MAX_POS;
119
0
  int psk_pos = MAX_POS;
120
0
  int cli_psk_pos = MAX_POS;
121
0
  int cli_dhpsk_pos = MAX_POS;
122
0
  unsigned i;
123
124
  /* Client doesn't receive psk_key_exchange_modes */
125
0
  if (session->security_parameters.entity == GNUTLS_CLIENT)
126
0
    return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
127
128
  /* we set hsk_flags to HSK_PSK_KE_MODE_INVALID on failure to ensure that
129
   * when we parse the pre-shared key extension we detect PSK_KE_MODES as
130
   * received. */
131
0
  if (!vers || !vers->tls13_sem) {
132
0
    session->internals.hsk_flags |= HSK_PSK_KE_MODE_INVALID;
133
0
    return gnutls_assert_val(0);
134
0
  }
135
136
0
  cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred(
137
0
    session, GNUTLS_CRD_PSK);
138
0
  if (cred == NULL && (session->internals.flags & GNUTLS_NO_TICKETS)) {
139
0
    session->internals.hsk_flags |= HSK_PSK_KE_MODE_INVALID;
140
0
    return gnutls_assert_val(0);
141
0
  }
142
143
0
  DECR_LEN(len, 1);
144
0
  ke_modes_len = *(data++);
145
146
0
  for (i = 0; i < session->internals.priorities->_kx.num_priorities;
147
0
       i++) {
148
0
    if (session->internals.priorities->_kx.priorities[i] ==
149
0
          GNUTLS_KX_PSK &&
150
0
        psk_pos == MAX_POS) {
151
0
      psk_pos = i;
152
0
    } else if ((session->internals.priorities->_kx.priorities[i] ==
153
0
            GNUTLS_KX_DHE_PSK ||
154
0
          session->internals.priorities->_kx.priorities[i] ==
155
0
            GNUTLS_KX_ECDHE_PSK) &&
156
0
         dhpsk_pos == MAX_POS) {
157
0
      dhpsk_pos = i;
158
0
    }
159
160
0
    if (dhpsk_pos != MAX_POS && psk_pos != MAX_POS)
161
0
      break;
162
0
  }
163
164
0
  if (psk_pos == MAX_POS && dhpsk_pos == MAX_POS) {
165
0
    if (!(session->internals.flags & GNUTLS_NO_TICKETS))
166
0
      dhpsk_pos = 0;
167
0
    else if (session->internals.priorities->groups.size == 0)
168
0
      return gnutls_assert_val(0);
169
0
  }
170
171
0
  for (i = 0; i < ke_modes_len; i++) {
172
0
    DECR_LEN(len, 1);
173
0
    if (data[i] == PSK_DHE_KE)
174
0
      cli_dhpsk_pos = i;
175
0
    else if (data[i] == PSK_KE)
176
0
      cli_psk_pos = i;
177
178
0
    _gnutls_handshake_log("EXT[%p]: PSK KE mode %.2x received\n",
179
0
              session, (unsigned)data[i]);
180
0
    if (cli_psk_pos != MAX_POS && cli_dhpsk_pos != MAX_POS)
181
0
      break;
182
0
  }
183
184
0
  if (session->internals.priorities->server_precedence) {
185
0
    if (dhpsk_pos != MAX_POS && cli_dhpsk_pos != MAX_POS &&
186
0
        (dhpsk_pos < psk_pos || cli_psk_pos == MAX_POS))
187
0
      session->internals.hsk_flags |= HSK_PSK_KE_MODE_DHE_PSK;
188
0
    else if (psk_pos != MAX_POS && cli_psk_pos != MAX_POS &&
189
0
       (psk_pos < dhpsk_pos || cli_dhpsk_pos == MAX_POS))
190
0
      session->internals.hsk_flags |= HSK_PSK_KE_MODE_PSK;
191
0
  } else {
192
0
    if (dhpsk_pos != MAX_POS && cli_dhpsk_pos != MAX_POS &&
193
0
        (cli_dhpsk_pos < cli_psk_pos || psk_pos == MAX_POS))
194
0
      session->internals.hsk_flags |= HSK_PSK_KE_MODE_DHE_PSK;
195
0
    else if (psk_pos != MAX_POS && cli_psk_pos != MAX_POS &&
196
0
       (cli_psk_pos < cli_dhpsk_pos || dhpsk_pos == MAX_POS))
197
0
      session->internals.hsk_flags |= HSK_PSK_KE_MODE_PSK;
198
0
  }
199
200
0
  if ((session->internals.hsk_flags & HSK_PSK_KE_MODE_PSK) ||
201
0
      (session->internals.hsk_flags & HSK_PSK_KE_MODE_DHE_PSK)) {
202
0
    return 0;
203
0
  } else {
204
0
    session->internals.hsk_flags |= HSK_PSK_KE_MODE_INVALID;
205
0
    return gnutls_assert_val(0);
206
0
  }
207
0
}
208
209
const hello_ext_entry_st ext_mod_psk_ke_modes = {
210
  .name = "PSK Key Exchange Modes",
211
  .tls_id = 45,
212
  .gid = GNUTLS_EXTENSION_PSK_KE_MODES,
213
  .client_parse_point = GNUTLS_EXT_TLS,
214
  .server_parse_point = GNUTLS_EXT_TLS,
215
  .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
216
        GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO,
217
  .send_func = psk_ke_modes_send_params,
218
  .recv_func = psk_ke_modes_recv_params
219
};