Coverage Report

Created: 2023-03-26 08:33

/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
32
psk_ke_modes_send_params(gnutls_session_t session, 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; i++) {
62
0
    if (session->internals.priorities->_kx.priorities[i] ==
63
0
        GNUTLS_KX_PSK && !have_psk) {
64
0
      assert(pos <= 1);
65
0
      data[pos++] = PSK_KE;
66
0
      session->internals.hsk_flags |= HSK_PSK_KE_MODE_PSK;
67
0
      have_psk = 1;
68
0
    } else
69
0
        if ((session->internals.priorities->_kx.priorities[i] ==
70
0
       GNUTLS_KX_DHE_PSK
71
0
       || session->internals.priorities->_kx.priorities[i] ==
72
0
       GNUTLS_KX_ECDHE_PSK) && !have_dhpsk) {
73
0
      assert(pos <= 1);
74
0
      data[pos++] = PSK_DHE_KE;
75
0
      session->internals.hsk_flags |= HSK_PSK_KE_MODE_DHE_PSK;
76
0
      have_dhpsk = 1;
77
0
    }
78
79
0
    if (have_psk && have_dhpsk)
80
0
      break;
81
0
  }
82
83
  /* For session resumption we need to send at least one */
84
0
  if (pos == 0) {
85
0
    if (session->internals.flags & GNUTLS_NO_TICKETS)
86
0
      return 0;
87
88
0
    data[pos++] = PSK_DHE_KE;
89
0
    data[pos++] = PSK_KE;
90
0
    session->internals.hsk_flags |= HSK_PSK_KE_MODE_DHE_PSK;
91
0
    session->internals.hsk_flags |= HSK_PSK_KE_MODE_PSK;
92
0
  }
93
94
0
  ret = _gnutls_buffer_append_data_prefix(extdata, 8, data, pos);
95
0
  if (ret < 0)
96
0
    return gnutls_assert_val(ret);
97
98
0
  session->internals.hsk_flags |= HSK_PSK_KE_MODES_SENT;
99
100
0
  return 0;
101
0
}
102
103
0
#define MAX_POS INT_MAX
104
105
/*
106
 * Since we only support ECDHE-authenticated PSKs, the server
107
 * just verifies that a "psk_key_exchange_modes" extension was received,
108
 * and that it contains the value one.
109
 */
110
static int
111
psk_ke_modes_recv_params(gnutls_session_t session,
112
       const unsigned char *data, size_t len)
113
0
{
114
0
  uint8_t ke_modes_len;
115
0
  const version_entry_st *vers = get_version(session);
116
0
  gnutls_psk_server_credentials_t cred;
117
0
  int dhpsk_pos = MAX_POS;
118
0
  int psk_pos = MAX_POS;
119
0
  int cli_psk_pos = MAX_POS;
120
0
  int cli_dhpsk_pos = MAX_POS;
121
0
  unsigned i;
122
123
  /* Client doesn't receive psk_key_exchange_modes */
124
0
  if (session->security_parameters.entity == GNUTLS_CLIENT)
125
0
    return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
126
127
  /* we set hsk_flags to HSK_PSK_KE_MODE_INVALID on failure to ensure that
128
   * when we parse the pre-shared key extension we detect PSK_KE_MODES as
129
   * received. */
130
0
  if (!vers || !vers->tls13_sem) {
131
0
    session->internals.hsk_flags |= HSK_PSK_KE_MODE_INVALID;
132
0
    return gnutls_assert_val(0);
133
0
  }
134
135
0
  cred =
136
0
      (gnutls_psk_server_credentials_t) _gnutls_get_cred(session,
137
0
                     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; i++) {
147
0
    if (session->internals.priorities->_kx.priorities[i] ==
148
0
        GNUTLS_KX_PSK && psk_pos == MAX_POS) {
149
0
      psk_pos = i;
150
0
    } else
151
0
        if ((session->internals.priorities->_kx.priorities[i] ==
152
0
       GNUTLS_KX_DHE_PSK
153
0
       || session->internals.priorities->_kx.priorities[i] ==
154
0
       GNUTLS_KX_ECDHE_PSK) && dhpsk_pos == MAX_POS) {
155
0
      dhpsk_pos = i;
156
0
    }
157
158
0
    if (dhpsk_pos != MAX_POS && psk_pos != MAX_POS)
159
0
      break;
160
0
  }
161
162
0
  if (psk_pos == MAX_POS && dhpsk_pos == MAX_POS) {
163
0
    if (!(session->internals.flags & GNUTLS_NO_TICKETS))
164
0
      dhpsk_pos = 0;
165
0
    else if (session->internals.priorities->groups.size == 0)
166
0
      return gnutls_assert_val(0);
167
0
  }
168
169
0
  for (i = 0; i < ke_modes_len; i++) {
170
0
    DECR_LEN(len, 1);
171
0
    if (data[i] == PSK_DHE_KE)
172
0
      cli_dhpsk_pos = i;
173
0
    else if (data[i] == PSK_KE)
174
0
      cli_psk_pos = i;
175
176
0
    _gnutls_handshake_log("EXT[%p]: PSK KE mode %.2x received\n",
177
0
              session, (unsigned)data[i]);
178
0
    if (cli_psk_pos != MAX_POS && cli_dhpsk_pos != MAX_POS)
179
0
      break;
180
0
  }
181
182
0
  if (session->internals.priorities->server_precedence) {
183
0
    if (dhpsk_pos != MAX_POS && cli_dhpsk_pos != MAX_POS
184
0
        && (dhpsk_pos < psk_pos || cli_psk_pos == MAX_POS))
185
0
      session->internals.hsk_flags |= HSK_PSK_KE_MODE_DHE_PSK;
186
0
    else if (psk_pos != MAX_POS && cli_psk_pos != MAX_POS
187
0
       && (psk_pos < dhpsk_pos || cli_dhpsk_pos == MAX_POS))
188
0
      session->internals.hsk_flags |= HSK_PSK_KE_MODE_PSK;
189
0
  } else {
190
0
    if (dhpsk_pos != MAX_POS && cli_dhpsk_pos != MAX_POS
191
0
        && (cli_dhpsk_pos < cli_psk_pos || psk_pos == MAX_POS))
192
0
      session->internals.hsk_flags |= HSK_PSK_KE_MODE_DHE_PSK;
193
0
    else if (psk_pos != MAX_POS && cli_psk_pos != MAX_POS
194
0
       && (cli_psk_pos < cli_dhpsk_pos
195
0
           || dhpsk_pos == MAX_POS))
196
0
      session->internals.hsk_flags |= HSK_PSK_KE_MODE_PSK;
197
0
  }
198
199
0
  if ((session->internals.hsk_flags & HSK_PSK_KE_MODE_PSK) ||
200
0
      (session->internals.hsk_flags & HSK_PSK_KE_MODE_DHE_PSK)) {
201
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 =
216
      GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
217
      GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO,
218
  .send_func = psk_ke_modes_send_params,
219
  .recv_func = psk_ke_modes_recv_params
220
};