Coverage Report

Created: 2025-03-18 06:55

/src/gnutls/lib/algorithms/kx.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2011-2012 Free Software Foundation, 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 "algorithms.h"
25
#include "errors.h"
26
#include "x509/common.h"
27
#include "state.h"
28
#include "c-strcase.h"
29
30
extern mod_auth_st rsa_auth_struct;
31
extern mod_auth_st dhe_rsa_auth_struct;
32
extern mod_auth_st ecdhe_rsa_auth_struct;
33
extern mod_auth_st ecdhe_psk_auth_struct;
34
extern mod_auth_st ecdhe_ecdsa_auth_struct;
35
extern mod_auth_st dhe_dss_auth_struct;
36
extern mod_auth_st anon_auth_struct;
37
extern mod_auth_st anon_ecdh_auth_struct;
38
extern mod_auth_st srp_auth_struct;
39
extern mod_auth_st psk_auth_struct;
40
extern mod_auth_st dhe_psk_auth_struct;
41
extern mod_auth_st rsa_psk_auth_struct;
42
extern mod_auth_st srp_rsa_auth_struct;
43
extern mod_auth_st srp_dss_auth_struct;
44
extern mod_auth_st vko_gost_auth_struct;
45
46
/* Cred type mappings to KX algorithms
47
 * The mappings are not 1-1. Some KX such as SRP_RSA require
48
 * more than one credentials type.
49
 */
50
typedef struct {
51
  gnutls_kx_algorithm_t algorithm;
52
  gnutls_credentials_type_t client_type;
53
  gnutls_credentials_type_t server_type; /* The type of credentials a server
54
             * needs to set */
55
} gnutls_cred_map;
56
57
static const gnutls_cred_map cred_mappings[] = {
58
  { GNUTLS_KX_ECDHE_RSA, GNUTLS_CRD_CERTIFICATE, GNUTLS_CRD_CERTIFICATE },
59
  { GNUTLS_KX_ECDHE_ECDSA, GNUTLS_CRD_CERTIFICATE,
60
    GNUTLS_CRD_CERTIFICATE },
61
  { GNUTLS_KX_RSA, GNUTLS_CRD_CERTIFICATE, GNUTLS_CRD_CERTIFICATE },
62
  { GNUTLS_KX_DHE_DSS, GNUTLS_CRD_CERTIFICATE, GNUTLS_CRD_CERTIFICATE },
63
  { GNUTLS_KX_DHE_RSA, GNUTLS_CRD_CERTIFICATE, GNUTLS_CRD_CERTIFICATE },
64
  { GNUTLS_KX_ECDHE_PSK, GNUTLS_CRD_PSK, GNUTLS_CRD_PSK },
65
  { GNUTLS_KX_PSK, GNUTLS_CRD_PSK, GNUTLS_CRD_PSK },
66
  { GNUTLS_KX_DHE_PSK, GNUTLS_CRD_PSK, GNUTLS_CRD_PSK },
67
  { GNUTLS_KX_RSA_PSK, GNUTLS_CRD_PSK, GNUTLS_CRD_CERTIFICATE },
68
  { GNUTLS_KX_SRP, GNUTLS_CRD_SRP, GNUTLS_CRD_SRP },
69
  { GNUTLS_KX_SRP_RSA, GNUTLS_CRD_SRP, GNUTLS_CRD_CERTIFICATE },
70
  { GNUTLS_KX_SRP_DSS, GNUTLS_CRD_SRP, GNUTLS_CRD_CERTIFICATE },
71
  { GNUTLS_KX_ANON_DH, GNUTLS_CRD_ANON, GNUTLS_CRD_ANON },
72
  { GNUTLS_KX_ANON_ECDH, GNUTLS_CRD_ANON, GNUTLS_CRD_ANON },
73
  { GNUTLS_KX_VKO_GOST_12, GNUTLS_CRD_CERTIFICATE,
74
    GNUTLS_CRD_CERTIFICATE },
75
  { 0, 0, 0 }
76
};
77
78
#define GNUTLS_KX_MAP_LOOP(b)                             \
79
0
  const gnutls_cred_map *p;                         \
80
0
  for (p = cred_mappings; p->algorithm != 0; p++) { \
81
0
    b;                                        \
82
0
  }
83
84
struct gnutls_kx_algo_entry {
85
  const char *name;
86
  gnutls_kx_algorithm_t algorithm;
87
  mod_auth_st *auth_struct;
88
  bool needs_dh_params;
89
  bool false_start;
90
};
91
typedef struct gnutls_kx_algo_entry gnutls_kx_algo_entry;
92
93
static const gnutls_kx_algo_entry _gnutls_kx_algorithms[] = {
94
#ifdef ENABLE_ECDHE
95
  { "ECDHE-RSA", GNUTLS_KX_ECDHE_RSA, &ecdhe_rsa_auth_struct, 0, 1 },
96
  { "ECDHE-ECDSA", GNUTLS_KX_ECDHE_ECDSA, &ecdhe_ecdsa_auth_struct, 0,
97
    1 },
98
#endif
99
  { "RSA", GNUTLS_KX_RSA, &rsa_auth_struct, 0, 0 },
100
#ifdef ENABLE_DHE
101
  { "DHE-RSA", GNUTLS_KX_DHE_RSA, &dhe_rsa_auth_struct, 1, 1 },
102
  { "DHE-DSS", GNUTLS_KX_DHE_DSS, &dhe_dss_auth_struct, 1, 1 },
103
#endif
104
#ifdef ENABLE_PSK
105
  { "PSK", GNUTLS_KX_PSK, &psk_auth_struct, 0, 0 },
106
  { "RSA-PSK", GNUTLS_KX_RSA_PSK, &rsa_psk_auth_struct, 0, 0 },
107
#ifdef ENABLE_DHE
108
  { "DHE-PSK", GNUTLS_KX_DHE_PSK, &dhe_psk_auth_struct,
109
    1 /* needs DHE params */, 0 },
110
#endif
111
#ifdef ENABLE_ECDHE
112
  { "ECDHE-PSK", GNUTLS_KX_ECDHE_PSK, &ecdhe_psk_auth_struct, 0, 0 },
113
#endif
114
#endif
115
#ifdef ENABLE_SRP
116
  { "SRP-DSS", GNUTLS_KX_SRP_DSS, &srp_dss_auth_struct, 0, 0 },
117
  { "SRP-RSA", GNUTLS_KX_SRP_RSA, &srp_rsa_auth_struct, 0, 0 },
118
  { "SRP", GNUTLS_KX_SRP, &srp_auth_struct, 0, 0 },
119
#endif
120
#if defined(ENABLE_ANON) && defined(ENABLE_DHE)
121
  { "ANON-DH", GNUTLS_KX_ANON_DH, &anon_auth_struct, 1, 0 },
122
#endif
123
#if defined(ENABLE_ANON) && defined(ENABLE_ECDHE)
124
  { "ANON-ECDH", GNUTLS_KX_ANON_ECDH, &anon_ecdh_auth_struct, 0, 0 },
125
#endif
126
#ifdef ENABLE_GOST
127
  { "VKO-GOST-12", GNUTLS_KX_VKO_GOST_12, &vko_gost_auth_struct, 0, 0 },
128
#endif
129
  /* for deprecated and legacy algorithms no longer supported, use
130
   * GNUTLS_KX_INVALID as an entry. This will make them available
131
   * as priority strings, but they will be a no-op.
132
   */
133
  { "RSA-EXPORT", GNUTLS_KX_INVALID, NULL, 0, 0 },
134
  { 0, 0, 0, 0, 0 }
135
};
136
137
#define GNUTLS_KX_LOOP(b)                                       \
138
0
  const gnutls_kx_algo_entry *p;                          \
139
0
  for (p = _gnutls_kx_algorithms; p->name != NULL; p++) { \
140
0
    b;                                              \
141
0
  }
142
143
#define GNUTLS_KX_ALG_LOOP(a)                           \
144
0
  GNUTLS_KX_LOOP(if (p->algorithm == algorithm) { \
145
0
    a;                                      \
146
0
    break;                                  \
147
0
  })
148
149
/* Key EXCHANGE functions */
150
mod_auth_st *_gnutls_kx_auth_struct(gnutls_kx_algorithm_t algorithm)
151
0
{
152
0
  mod_auth_st *ret = NULL;
153
0
  GNUTLS_KX_ALG_LOOP(ret = p->auth_struct);
154
0
  return ret;
155
0
}
156
157
/**
158
 * gnutls_kx_get_name:
159
 * @algorithm: is a key exchange algorithm
160
 *
161
 * Convert a #gnutls_kx_algorithm_t value to a string.
162
 *
163
 * Returns: a pointer to a string that contains the name of the
164
 *   specified key exchange algorithm, or %NULL.
165
 **/
166
const char *gnutls_kx_get_name(gnutls_kx_algorithm_t algorithm)
167
0
{
168
0
  const char *ret = NULL;
169
170
  /* avoid prefix */
171
0
  GNUTLS_KX_ALG_LOOP(ret = p->name);
172
173
0
  return ret;
174
0
}
175
176
/**
177
 * gnutls_kx_get_id:
178
 * @name: is a KX name
179
 *
180
 * Convert a string to a #gnutls_kx_algorithm_t value.  The names are
181
 * compared in a case insensitive way.
182
 *
183
 * Returns: an id of the specified KX algorithm, or %GNUTLS_KX_UNKNOWN
184
 *   on error.
185
 **/
186
gnutls_kx_algorithm_t gnutls_kx_get_id(const char *name)
187
0
{
188
0
  gnutls_kx_algorithm_t ret = GNUTLS_KX_UNKNOWN;
189
190
0
  GNUTLS_KX_LOOP(if (c_strcasecmp(p->name, name) == 0 &&
191
0
         (int)p->algorithm != GNUTLS_KX_INVALID) {
192
0
    ret = p->algorithm;
193
0
    break;
194
0
  });
195
196
0
  return ret;
197
0
}
198
199
/* As with gnutls_kx_get_id(), but it returns all known
200
 * key exchange algorithms (even legacy), with GNUTLS_KX_INVALID
201
 * value.
202
 */
203
int _gnutls_kx_get_id(const char *name)
204
0
{
205
0
  gnutls_kx_algorithm_t ret = GNUTLS_KX_UNKNOWN;
206
207
0
  GNUTLS_KX_LOOP(if (c_strcasecmp(p->name, name) == 0) {
208
0
    ret = p->algorithm;
209
0
    break;
210
0
  });
211
212
0
  return ret;
213
0
}
214
215
/**
216
 * gnutls_kx_list:
217
 *
218
 * Get a list of supported key exchange algorithms.
219
 *
220
 * This function is not thread safe.
221
 *
222
 * Returns: a (0)-terminated list of #gnutls_kx_algorithm_t integers
223
 * indicating the available key exchange algorithms.
224
 **/
225
const gnutls_kx_algorithm_t *gnutls_kx_list(void)
226
0
{
227
0
  static gnutls_kx_algorithm_t supported_kxs[MAX_ALGOS] = { 0 };
228
229
0
  if (supported_kxs[0] == 0) {
230
0
    int i = 0;
231
232
0
    GNUTLS_KX_LOOP(supported_kxs[i++] = p->algorithm);
233
0
    supported_kxs[i++] = 0;
234
0
  }
235
236
0
  return supported_kxs;
237
0
}
238
239
int _gnutls_kx_is_ok(gnutls_kx_algorithm_t algorithm)
240
0
{
241
0
  ssize_t ret = -1;
242
0
  GNUTLS_KX_ALG_LOOP(ret = p->algorithm);
243
0
  if (ret >= 0)
244
0
    ret = 0;
245
0
  else
246
0
    ret = 1;
247
0
  return ret;
248
0
}
249
250
bool _gnutls_kx_allows_false_start(gnutls_session_t session)
251
0
{
252
0
  unsigned algorithm = session->security_parameters.cs->kx_algorithm;
253
0
  bool needs_dh = 0;
254
0
  int bits;
255
256
0
  ssize_t ret = 0;
257
0
  GNUTLS_KX_ALG_LOOP(ret = p->false_start; needs_dh = p->needs_dh_params);
258
259
0
  if (ret != 0) {
260
0
    const gnutls_group_entry_st *e;
261
262
0
    e = get_group(session);
263
264
0
#if defined(ENABLE_DHE) || defined(ENABLE_ANON)
265
0
    if (needs_dh != 0) {
266
0
      bits = gnutls_sec_param_to_pk_bits(
267
0
        GNUTLS_PK_DH, GNUTLS_SEC_PARAM_HIGH);
268
      /* check whether sizes are sufficient */
269
0
      if (e && e->prime) {
270
0
        if (e->prime->size * 8 < (unsigned)bits)
271
0
          ret = 0;
272
0
      } else if (gnutls_dh_get_prime_bits(session) < bits)
273
0
        ret = 0;
274
0
    } else
275
0
#endif
276
0
      if (algorithm == GNUTLS_KX_ECDHE_RSA ||
277
0
          algorithm == GNUTLS_KX_ECDHE_ECDSA) {
278
0
      bits = gnutls_sec_param_to_pk_bits(
279
0
        GNUTLS_PK_EC, GNUTLS_SEC_PARAM_HIGH);
280
281
0
      if (e != NULL &&
282
0
          gnutls_ecc_curve_get_size(e->curve) * 8 < bits)
283
0
        ret = 0;
284
0
    }
285
0
  }
286
0
  return ret;
287
0
}
288
289
bool _gnutls_kx_needs_dh_params(gnutls_kx_algorithm_t algorithm)
290
0
{
291
0
  ssize_t ret = 0;
292
0
  GNUTLS_KX_ALG_LOOP(ret = p->needs_dh_params);
293
0
  return ret;
294
0
}
295
296
/* Returns the credentials type required for this
297
 * Key exchange method.
298
 */
299
gnutls_credentials_type_t
300
_gnutls_map_kx_get_cred(gnutls_kx_algorithm_t algorithm, int server)
301
0
{
302
0
  gnutls_credentials_type_t ret = -1;
303
0
  if (server) {
304
0
    GNUTLS_KX_MAP_LOOP(if (p->algorithm == algorithm) {
305
0
      ret = p->server_type;
306
0
      break;
307
0
    });
308
0
  } else {
309
0
    GNUTLS_KX_MAP_LOOP(if (p->algorithm == algorithm) {
310
0
      ret = p->client_type;
311
0
      break;
312
0
    });
313
0
  }
314
315
0
  return ret;
316
0
}