Coverage Report

Created: 2023-03-26 08:33

/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,
59
   GNUTLS_CRD_CERTIFICATE},
60
  {GNUTLS_KX_ECDHE_ECDSA, GNUTLS_CRD_CERTIFICATE,
61
   GNUTLS_CRD_CERTIFICATE},
62
  {GNUTLS_KX_RSA, GNUTLS_CRD_CERTIFICATE, GNUTLS_CRD_CERTIFICATE},
63
  {GNUTLS_KX_DHE_DSS, GNUTLS_CRD_CERTIFICATE,
64
   GNUTLS_CRD_CERTIFICATE},
65
  {GNUTLS_KX_DHE_RSA, GNUTLS_CRD_CERTIFICATE,
66
   GNUTLS_CRD_CERTIFICATE},
67
  {GNUTLS_KX_ECDHE_PSK, GNUTLS_CRD_PSK, GNUTLS_CRD_PSK},
68
  {GNUTLS_KX_PSK, GNUTLS_CRD_PSK, GNUTLS_CRD_PSK},
69
  {GNUTLS_KX_DHE_PSK, GNUTLS_CRD_PSK, GNUTLS_CRD_PSK},
70
  {GNUTLS_KX_RSA_PSK, GNUTLS_CRD_PSK, GNUTLS_CRD_CERTIFICATE},
71
  {GNUTLS_KX_SRP, GNUTLS_CRD_SRP, GNUTLS_CRD_SRP},
72
  {GNUTLS_KX_SRP_RSA, GNUTLS_CRD_SRP, GNUTLS_CRD_CERTIFICATE},
73
  {GNUTLS_KX_SRP_DSS, GNUTLS_CRD_SRP, GNUTLS_CRD_CERTIFICATE},
74
  {GNUTLS_KX_ANON_DH, GNUTLS_CRD_ANON, GNUTLS_CRD_ANON},
75
  {GNUTLS_KX_ANON_ECDH, GNUTLS_CRD_ANON, GNUTLS_CRD_ANON},
76
  {GNUTLS_KX_VKO_GOST_12, GNUTLS_CRD_CERTIFICATE, GNUTLS_CRD_CERTIFICATE},
77
  {0, 0, 0}
78
};
79
80
#define GNUTLS_KX_MAP_LOOP(b) \
81
0
  const gnutls_cred_map *p; \
82
0
    for(p = cred_mappings; p->algorithm != 0; p++) { b ; }
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,
97
   0, 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++) { b ; }
140
141
#define GNUTLS_KX_ALG_LOOP(a) \
142
0
      GNUTLS_KX_LOOP( if(p->algorithm == algorithm) { a; break; } )
143
144
/* Key EXCHANGE functions */
145
mod_auth_st *_gnutls_kx_auth_struct(gnutls_kx_algorithm_t algorithm)
146
0
{
147
0
  mod_auth_st *ret = NULL;
148
0
  GNUTLS_KX_ALG_LOOP(ret = p->auth_struct);
149
0
  return ret;
150
151
0
}
152
153
/**
154
 * gnutls_kx_get_name:
155
 * @algorithm: is a key exchange algorithm
156
 *
157
 * Convert a #gnutls_kx_algorithm_t value to a string.
158
 *
159
 * Returns: a pointer to a string that contains the name of the
160
 *   specified key exchange algorithm, or %NULL.
161
 **/
162
const char *gnutls_kx_get_name(gnutls_kx_algorithm_t algorithm)
163
0
{
164
0
  const char *ret = NULL;
165
166
  /* avoid prefix */
167
0
  GNUTLS_KX_ALG_LOOP(ret = p->name);
168
169
0
  return ret;
170
0
}
171
172
/**
173
 * gnutls_kx_get_id:
174
 * @name: is a KX name
175
 *
176
 * Convert a string to a #gnutls_kx_algorithm_t value.  The names are
177
 * compared in a case insensitive way.
178
 *
179
 * Returns: an id of the specified KX algorithm, or %GNUTLS_KX_UNKNOWN
180
 *   on error.
181
 **/
182
gnutls_kx_algorithm_t gnutls_kx_get_id(const char *name)
183
0
{
184
0
  gnutls_kx_algorithm_t ret = GNUTLS_KX_UNKNOWN;
185
186
0
  GNUTLS_KX_LOOP(if
187
0
           (c_strcasecmp(p->name, name) == 0
188
0
      && (int)p->algorithm != GNUTLS_KX_INVALID) {
189
0
           ret = p->algorithm; break;}
190
0
  ) ;
191
192
0
  return ret;
193
0
}
194
195
/* As with gnutls_kx_get_id(), but it returns all known
196
 * key exchange algorithms (even legacy), with GNUTLS_KX_INVALID
197
 * value.
198
 */
199
int _gnutls_kx_get_id(const char *name)
200
0
{
201
0
  gnutls_kx_algorithm_t ret = GNUTLS_KX_UNKNOWN;
202
203
0
  GNUTLS_KX_LOOP(if (c_strcasecmp(p->name, name) == 0) {
204
0
           ret = p->algorithm; break;}
205
0
  ) ;
206
207
0
  return ret;
208
0
}
209
210
/**
211
 * gnutls_kx_list:
212
 *
213
 * Get a list of supported key exchange algorithms.
214
 *
215
 * This function is not thread safe.
216
 *
217
 * Returns: a (0)-terminated list of #gnutls_kx_algorithm_t integers
218
 * indicating the available key exchange algorithms.
219
 **/
220
const gnutls_kx_algorithm_t *gnutls_kx_list(void)
221
0
{
222
0
  static gnutls_kx_algorithm_t supported_kxs[MAX_ALGOS] = { 0 };
223
224
0
  if (supported_kxs[0] == 0) {
225
0
    int i = 0;
226
227
0
    GNUTLS_KX_LOOP(supported_kxs[i++] = p->algorithm);
228
0
    supported_kxs[i++] = 0;
229
0
  }
230
231
0
  return supported_kxs;
232
0
}
233
234
int _gnutls_kx_is_ok(gnutls_kx_algorithm_t algorithm)
235
0
{
236
0
  ssize_t ret = -1;
237
0
  GNUTLS_KX_ALG_LOOP(ret = p->algorithm);
238
0
  if (ret >= 0)
239
0
    ret = 0;
240
0
  else
241
0
    ret = 1;
242
0
  return ret;
243
0
}
244
245
bool _gnutls_kx_allows_false_start(gnutls_session_t session)
246
0
{
247
0
  unsigned algorithm = session->security_parameters.cs->kx_algorithm;
248
0
  bool needs_dh = 0;
249
0
  int bits;
250
251
0
  ssize_t ret = 0;
252
0
  GNUTLS_KX_ALG_LOOP(ret = p->false_start; needs_dh = p->needs_dh_params);
253
254
0
  if (ret != 0) {
255
0
    const gnutls_group_entry_st *e;
256
257
0
    e = get_group(session);
258
259
0
#if defined(ENABLE_DHE) || defined(ENABLE_ANON)
260
0
    if (needs_dh != 0) {
261
0
      bits =
262
0
          gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
263
0
              GNUTLS_SEC_PARAM_HIGH);
264
      /* check whether sizes are sufficient */
265
0
      if (e && e->prime) {
266
0
        if (e->prime->size * 8 < (unsigned)bits)
267
0
          ret = 0;
268
0
      } else if (gnutls_dh_get_prime_bits(session) < bits)
269
0
        ret = 0;
270
0
    } else
271
0
#endif
272
0
    if (algorithm == GNUTLS_KX_ECDHE_RSA
273
0
          || algorithm == GNUTLS_KX_ECDHE_ECDSA) {
274
0
      bits =
275
0
          gnutls_sec_param_to_pk_bits(GNUTLS_PK_EC,
276
0
              GNUTLS_SEC_PARAM_HIGH);
277
278
0
      if (e != NULL
279
0
          && gnutls_ecc_curve_get_size(e->curve) * 8 < bits)
280
0
        ret = 0;
281
0
    }
282
0
  }
283
0
  return ret;
284
0
}
285
286
bool _gnutls_kx_needs_dh_params(gnutls_kx_algorithm_t algorithm)
287
0
{
288
0
  ssize_t ret = 0;
289
0
  GNUTLS_KX_ALG_LOOP(ret = p->needs_dh_params);
290
0
  return ret;
291
0
}
292
293
/* Returns the credentials type required for this
294
 * Key exchange method.
295
 */
296
gnutls_credentials_type_t
297
_gnutls_map_kx_get_cred(gnutls_kx_algorithm_t algorithm, int server)
298
0
{
299
0
  gnutls_credentials_type_t ret = -1;
300
0
  if (server) {
301
0
    GNUTLS_KX_MAP_LOOP(if (p->algorithm == algorithm) {
302
0
           ret = p->server_type; break;}
303
0
    ) ;
304
0
  } else {
305
0
    GNUTLS_KX_MAP_LOOP(if (p->algorithm == algorithm) {
306
0
           ret = p->client_type; break;}
307
0
    ) ;
308
0
  }
309
310
0
  return ret;
311
0
}