Coverage Report

Created: 2025-03-18 06:55

/src/gnutls/lib/auth/dhe_psk.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2005-2012 Free Software Foundation, Inc.
3
 * Copyright (C) 2017 Red Hat, Inc.
4
 *
5
 * Author: Nikos Mavrogiannopoulos
6
 *
7
 * This file is part of GnuTLS.
8
 *
9
 * The GnuTLS is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public License
11
 * as published by the Free Software Foundation; either version 2.1 of
12
 * the License, or (at your option) any later version.
13
 *
14
 * This library is distributed in the hope that it will be useful, but
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
21
 *
22
 */
23
24
/* This file contains the PSK Diffie-Hellman key exchange part of the
25
 * PSK authentication.  The functions here are used in the handshake.
26
 */
27
28
#include "gnutls_int.h"
29
30
#ifdef ENABLE_PSK
31
32
/* Contains PSK code for DHE and ECDHE
33
 */
34
35
#include "auth.h"
36
#include "errors.h"
37
#include "dh.h"
38
#include "auth/psk.h"
39
#include "num.h"
40
#include "mpi.h"
41
#include "state.h"
42
#include "auth/dh_common.h"
43
#include "auth/ecdhe.h"
44
#include "datum.h"
45
#include "auth/psk_passwd.h"
46
47
static int proc_ecdhe_psk_server_kx(gnutls_session_t session, uint8_t *data,
48
            size_t _data_size);
49
static int gen_dhe_psk_server_kx(gnutls_session_t, gnutls_buffer_st *);
50
static int gen_dhe_psk_client_kx(gnutls_session_t, gnutls_buffer_st *);
51
static int gen_ecdhe_psk_client_kx(gnutls_session_t, gnutls_buffer_st *);
52
static int proc_ecdhe_psk_client_kx(gnutls_session_t, uint8_t *, size_t);
53
static int proc_dhe_psk_server_kx(gnutls_session_t, uint8_t *, size_t);
54
static int gen_ecdhe_psk_server_kx(gnutls_session_t session,
55
           gnutls_buffer_st *data);
56
static int proc_dhe_psk_client_kx(gnutls_session_t session, uint8_t *data,
57
          size_t _data_size);
58
#ifdef ENABLE_DHE
59
const mod_auth_st dhe_psk_auth_struct = { "DHE PSK",
60
            NULL,
61
            NULL,
62
            gen_dhe_psk_server_kx,
63
            gen_dhe_psk_client_kx,
64
            NULL,
65
            NULL,
66
67
            NULL,
68
            NULL, /* certificate */
69
            proc_dhe_psk_server_kx,
70
            proc_dhe_psk_client_kx,
71
            NULL,
72
            NULL };
73
#endif
74
75
#ifdef ENABLE_ECDHE
76
const mod_auth_st ecdhe_psk_auth_struct = { "ECDHE PSK",
77
              NULL,
78
              NULL,
79
              gen_ecdhe_psk_server_kx,
80
              gen_ecdhe_psk_client_kx,
81
              NULL,
82
              NULL,
83
84
              NULL,
85
              NULL, /* certificate */
86
              proc_ecdhe_psk_server_kx,
87
              proc_ecdhe_psk_client_kx,
88
              NULL,
89
              NULL };
90
#endif
91
92
static int gen_ecdhe_psk_client_kx(gnutls_session_t session,
93
           gnutls_buffer_st *data)
94
0
{
95
0
  int ret, free;
96
0
  gnutls_psk_client_credentials_t cred;
97
0
  gnutls_datum_t username, key;
98
0
  unsigned init_pos = data->length;
99
100
0
  cred = (gnutls_psk_client_credentials_t)_gnutls_get_cred(
101
0
    session, GNUTLS_CRD_PSK);
102
103
0
  if (cred == NULL)
104
0
    return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
105
106
0
  ret = _gnutls_find_psk_key(session, cred, &username, &key, NULL, &free);
107
0
  if (ret < 0)
108
0
    return gnutls_assert_val(ret);
109
110
0
  ret = _gnutls_buffer_append_data_prefix(data, 16, username.data,
111
0
            username.size);
112
0
  if (ret < 0) {
113
0
    gnutls_assert();
114
0
    goto cleanup;
115
0
  }
116
117
  /* The PSK key is set in there */
118
0
  ret = _gnutls_gen_ecdh_common_client_kx_int(session, data, &key);
119
0
  if (ret < 0) {
120
0
    gnutls_assert();
121
0
    goto cleanup;
122
0
  }
123
124
0
  ret = data->length - init_pos;
125
126
0
cleanup:
127
0
  if (free) {
128
0
    _gnutls_free_datum(&username);
129
0
    _gnutls_free_temp_key_datum(&key);
130
0
  }
131
132
0
  return ret;
133
0
}
134
135
static int gen_dhe_psk_client_kx(gnutls_session_t session,
136
         gnutls_buffer_st *data)
137
0
{
138
0
  int ret, free;
139
0
  gnutls_psk_client_credentials_t cred;
140
0
  gnutls_datum_t username, key;
141
0
  unsigned init_pos = data->length;
142
143
0
  cred = (gnutls_psk_client_credentials_t)_gnutls_get_cred(
144
0
    session, GNUTLS_CRD_PSK);
145
146
0
  if (cred == NULL)
147
0
    return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
148
149
0
  ret = _gnutls_find_psk_key(session, cred, &username, &key, NULL, &free);
150
0
  if (ret < 0)
151
0
    return gnutls_assert_val(ret);
152
153
0
  ret = _gnutls_buffer_append_data_prefix(data, 16, username.data,
154
0
            username.size);
155
0
  if (ret < 0) {
156
0
    gnutls_assert();
157
0
    goto cleanup;
158
0
  }
159
160
  /* The PSK key is set in there */
161
0
  ret = _gnutls_gen_dh_common_client_kx_int(session, data, &key);
162
0
  if (ret < 0) {
163
0
    gnutls_assert();
164
0
    goto cleanup;
165
0
  }
166
167
0
  ret = data->length - init_pos;
168
169
0
cleanup:
170
0
  if (free) {
171
0
    _gnutls_free_datum(&username);
172
0
    _gnutls_free_temp_key_datum(&key);
173
0
  }
174
175
0
  return ret;
176
0
}
177
178
static int gen_dhe_psk_server_kx(gnutls_session_t session,
179
         gnutls_buffer_st *data)
180
0
{
181
0
  int ret;
182
0
  gnutls_psk_server_credentials_t cred;
183
0
  gnutls_datum_t hint = { NULL, 0 };
184
185
0
  cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred(
186
0
    session, GNUTLS_CRD_PSK);
187
0
  if (cred == NULL) {
188
0
    gnutls_assert();
189
0
    return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
190
0
  }
191
192
0
  if ((ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK,
193
0
            sizeof(psk_auth_info_st), 1)) < 0) {
194
0
    gnutls_assert();
195
0
    return ret;
196
0
  }
197
198
0
  ret = _gnutls_figure_dh_params(session, cred->dh_params,
199
0
               cred->params_func, cred->dh_sec_param);
200
0
  if (ret < 0) {
201
0
    gnutls_assert();
202
0
    return ret;
203
0
  }
204
205
0
  if (cred->hint) {
206
0
    hint.data = (uint8_t *)cred->hint;
207
0
    hint.size = strlen(cred->hint);
208
0
  }
209
210
0
  ret = _gnutls_buffer_append_data_prefix(data, 16, hint.data, hint.size);
211
0
  if (ret < 0)
212
0
    return gnutls_assert_val(ret);
213
214
0
  ret = _gnutls_dh_common_print_server_kx(session, data);
215
0
  if (ret < 0)
216
0
    gnutls_assert();
217
218
0
  return ret;
219
0
}
220
221
static int gen_ecdhe_psk_server_kx(gnutls_session_t session,
222
           gnutls_buffer_st *data)
223
0
{
224
0
  int ret;
225
0
  gnutls_psk_server_credentials_t cred;
226
0
  gnutls_datum_t hint = { NULL, 0 };
227
228
0
  if ((ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK,
229
0
            sizeof(psk_auth_info_st), 1)) < 0) {
230
0
    gnutls_assert();
231
0
    return ret;
232
0
  }
233
234
0
  cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred(
235
0
    session, GNUTLS_CRD_PSK);
236
237
0
  if (cred == NULL) {
238
0
    gnutls_assert();
239
0
    return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
240
0
  }
241
242
0
  if (cred->hint) {
243
0
    hint.data = (uint8_t *)cred->hint;
244
0
    hint.size = strlen(cred->hint);
245
0
  }
246
247
0
  ret = _gnutls_buffer_append_data_prefix(data, 16, hint.data, hint.size);
248
0
  if (ret < 0)
249
0
    return gnutls_assert_val(ret);
250
251
0
  ret = _gnutls_ecdh_common_print_server_kx(session, data,
252
0
              get_group(session));
253
0
  if (ret < 0)
254
0
    gnutls_assert();
255
256
0
  return ret;
257
0
}
258
259
static int proc_dhe_psk_client_kx(gnutls_session_t session, uint8_t *data,
260
          size_t _data_size)
261
0
{
262
0
  int ret;
263
0
  gnutls_datum_t psk_key;
264
0
  gnutls_psk_server_credentials_t cred;
265
0
  psk_auth_info_t info;
266
0
  gnutls_datum_t username;
267
0
  ssize_t data_size = _data_size;
268
269
0
  cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred(
270
0
    session, GNUTLS_CRD_PSK);
271
272
0
  if (cred == NULL) {
273
0
    gnutls_assert();
274
0
    return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
275
0
  }
276
277
0
  if ((ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK,
278
0
            sizeof(psk_auth_info_st), 1)) < 0) {
279
0
    gnutls_assert();
280
0
    return ret;
281
0
  }
282
283
0
  DECR_LEN(data_size, 2);
284
0
  username.size = _gnutls_read_uint16(&data[0]);
285
286
0
  DECR_LEN(data_size, username.size);
287
288
0
  username.data = &data[2];
289
290
  /* copy the username to the auth info structures
291
   */
292
0
  info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
293
0
  if (info == NULL) {
294
0
    gnutls_assert();
295
0
    return GNUTLS_E_INTERNAL_ERROR;
296
0
  }
297
298
0
  if (username.size > MAX_USERNAME_SIZE) {
299
0
    gnutls_assert();
300
0
    return GNUTLS_E_ILLEGAL_SRP_USERNAME;
301
0
  }
302
303
0
  ret = _gnutls_copy_psk_username(info, username);
304
0
  if (ret < 0)
305
0
    return gnutls_assert_val(ret);
306
307
  /* Adjust the data */
308
0
  data += username.size + 2;
309
310
0
  ret = _gnutls_psk_pwd_find_entry(session, info->username,
311
0
           info->username_len, &psk_key, NULL);
312
0
  if (ret < 0)
313
0
    return gnutls_assert_val(ret);
314
315
0
  ret = _gnutls_proc_dh_common_client_kx(session, data, data_size,
316
0
                 &psk_key);
317
318
0
  _gnutls_free_key_datum(&psk_key);
319
320
0
  return ret;
321
0
}
322
323
static int proc_ecdhe_psk_client_kx(gnutls_session_t session, uint8_t *data,
324
            size_t _data_size)
325
0
{
326
0
  int ret;
327
0
  gnutls_psk_server_credentials_t cred;
328
0
  gnutls_datum_t psk_key;
329
0
  psk_auth_info_t info;
330
0
  gnutls_datum_t username;
331
0
  ssize_t data_size = _data_size;
332
333
0
  cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred(
334
0
    session, GNUTLS_CRD_PSK);
335
336
0
  if (cred == NULL) {
337
0
    gnutls_assert();
338
0
    return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
339
0
  }
340
341
0
  if ((ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK,
342
0
            sizeof(psk_auth_info_st), 1)) < 0) {
343
0
    gnutls_assert();
344
0
    return ret;
345
0
  }
346
347
0
  DECR_LEN(data_size, 2);
348
0
  username.size = _gnutls_read_uint16(&data[0]);
349
350
0
  DECR_LEN(data_size, username.size);
351
352
0
  username.data = &data[2];
353
354
  /* copy the username to the auth info structures
355
   */
356
0
  info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
357
0
  if (info == NULL) {
358
0
    gnutls_assert();
359
0
    return GNUTLS_E_INTERNAL_ERROR;
360
0
  }
361
362
0
  if (username.size > MAX_USERNAME_SIZE) {
363
0
    gnutls_assert();
364
0
    return GNUTLS_E_ILLEGAL_SRP_USERNAME;
365
0
  }
366
367
0
  ret = _gnutls_copy_psk_username(info, username);
368
0
  if (ret < 0)
369
0
    return gnutls_assert_val(ret);
370
371
  /* Adjust the data */
372
0
  data += username.size + 2;
373
374
  /* should never fail. It will always return a key even if it is
375
   * a random one */
376
0
  ret = _gnutls_psk_pwd_find_entry(session, info->username,
377
0
           info->username_len, &psk_key, NULL);
378
0
  if (ret < 0)
379
0
    return gnutls_assert_val(ret);
380
381
0
  ret = _gnutls_proc_ecdh_common_client_kx(session, data, data_size,
382
0
             get_group(session), &psk_key);
383
384
0
  _gnutls_free_key_datum(&psk_key);
385
386
0
  return ret;
387
0
}
388
389
static int proc_dhe_psk_server_kx(gnutls_session_t session, uint8_t *data,
390
          size_t _data_size)
391
0
{
392
0
  int ret;
393
0
  ssize_t data_size = _data_size;
394
0
  psk_auth_info_t info;
395
0
  gnutls_datum_t hint;
396
397
  /* set auth_info */
398
0
  if ((ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK,
399
0
            sizeof(psk_auth_info_st), 1)) < 0) {
400
0
    gnutls_assert();
401
0
    return ret;
402
0
  }
403
404
0
  DECR_LEN(data_size, 2);
405
406
0
  hint.size = _gnutls_read_uint16(&data[0]);
407
0
  hint.data = &data[2];
408
409
0
  DECR_LEN(data_size, hint.size);
410
0
  data += 2 + hint.size;
411
412
0
  ret = _gnutls_proc_dh_common_server_kx(session, data, data_size);
413
0
  if (ret < 0) {
414
0
    gnutls_assert();
415
0
    return ret;
416
0
  }
417
418
0
  info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
419
0
  if (info == NULL)
420
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
421
422
0
  if (hint.size > MAX_USERNAME_SIZE)
423
0
    return gnutls_assert_val(GNUTLS_E_ILLEGAL_SRP_USERNAME);
424
425
0
  ret = _gnutls_copy_psk_hint(info, hint);
426
0
  if (ret < 0) {
427
0
    gnutls_assert();
428
0
    return ret;
429
0
  }
430
431
0
  return 0;
432
0
}
433
434
static int proc_ecdhe_psk_server_kx(gnutls_session_t session, uint8_t *data,
435
            size_t _data_size)
436
0
{
437
0
  int ret;
438
0
  ssize_t data_size = _data_size;
439
0
  psk_auth_info_t info;
440
0
  gnutls_datum_t hint;
441
442
  /* set auth_info */
443
0
  if ((ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK,
444
0
            sizeof(psk_auth_info_st), 1)) < 0) {
445
0
    gnutls_assert();
446
0
    return ret;
447
0
  }
448
449
0
  DECR_LEN(data_size, 2);
450
451
0
  hint.size = _gnutls_read_uint16(&data[0]);
452
0
  hint.data = &data[2];
453
454
0
  DECR_LEN(data_size, hint.size);
455
0
  data += 2 + hint.size;
456
457
0
  ret = _gnutls_proc_ecdh_common_server_kx(session, data, data_size);
458
0
  if (ret < 0) {
459
0
    gnutls_assert();
460
0
    return ret;
461
0
  }
462
463
0
  info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
464
0
  if (info == NULL)
465
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
466
467
0
  if (hint.size > MAX_USERNAME_SIZE)
468
0
    return gnutls_assert_val(GNUTLS_E_ILLEGAL_SRP_USERNAME);
469
470
0
  ret = _gnutls_copy_psk_hint(info, hint);
471
0
  if (ret < 0) {
472
0
    gnutls_assert();
473
0
    return ret;
474
0
  }
475
476
0
  return 0;
477
0
}
478
479
#endif /* ENABLE_PSK */