Coverage Report

Created: 2026-08-14 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/lib/auth/dhe_psk.c
Line
Count
Source
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_prefix16(data, 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_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_prefix16(data, 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_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_prefix16(data, 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_prefix16(data, 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
268
0
  cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred(
269
0
    session, GNUTLS_CRD_PSK);
270
271
0
  if (cred == NULL) {
272
0
    gnutls_assert();
273
0
    return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
274
0
  }
275
276
0
  if ((ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK,
277
0
            sizeof(psk_auth_info_st), 1)) < 0) {
278
0
    gnutls_assert();
279
0
    return ret;
280
0
  }
281
282
0
  DECR_LEN(data_size, 2);
283
0
  username.size = _gnutls_read_uint16(&data[0]);
284
285
0
  DECR_LEN(data_size, username.size);
286
287
0
  username.data = &data[2];
288
289
  /* copy the username to the auth info structures
290
   */
291
0
  info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
292
0
  if (info == NULL) {
293
0
    gnutls_assert();
294
0
    return GNUTLS_E_INTERNAL_ERROR;
295
0
  }
296
297
0
  if (username.size > MAX_USERNAME_SIZE) {
298
0
    gnutls_assert();
299
0
    return GNUTLS_E_ILLEGAL_SRP_USERNAME;
300
0
  }
301
302
0
  ret = _gnutls_copy_psk_username(info, username);
303
0
  if (ret < 0)
304
0
    return gnutls_assert_val(ret);
305
306
  /* Adjust the data */
307
0
  data += username.size + 2;
308
309
0
  ret = _gnutls_psk_pwd_find_entry(session, info->username,
310
0
           info->username_len, &psk_key, NULL);
311
0
  if (ret < 0)
312
0
    return gnutls_assert_val(ret);
313
314
0
  ret = _gnutls_proc_dh_common_client_kx(session, data, data_size,
315
0
                 &psk_key);
316
317
0
  _gnutls_free_key_datum(&psk_key);
318
319
0
  return ret;
320
0
}
321
322
static int proc_ecdhe_psk_client_kx(gnutls_session_t session, uint8_t *data,
323
            size_t data_size)
324
0
{
325
0
  int ret;
326
0
  gnutls_psk_server_credentials_t cred;
327
0
  gnutls_datum_t psk_key;
328
0
  psk_auth_info_t info;
329
0
  gnutls_datum_t username;
330
331
0
  cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred(
332
0
    session, GNUTLS_CRD_PSK);
333
334
0
  if (cred == NULL) {
335
0
    gnutls_assert();
336
0
    return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
337
0
  }
338
339
0
  if ((ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK,
340
0
            sizeof(psk_auth_info_st), 1)) < 0) {
341
0
    gnutls_assert();
342
0
    return ret;
343
0
  }
344
345
0
  DECR_LEN(data_size, 2);
346
0
  username.size = _gnutls_read_uint16(&data[0]);
347
348
0
  DECR_LEN(data_size, username.size);
349
350
0
  username.data = &data[2];
351
352
  /* copy the username to the auth info structures
353
   */
354
0
  info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
355
0
  if (info == NULL) {
356
0
    gnutls_assert();
357
0
    return GNUTLS_E_INTERNAL_ERROR;
358
0
  }
359
360
0
  if (username.size > MAX_USERNAME_SIZE) {
361
0
    gnutls_assert();
362
0
    return GNUTLS_E_ILLEGAL_SRP_USERNAME;
363
0
  }
364
365
0
  ret = _gnutls_copy_psk_username(info, username);
366
0
  if (ret < 0)
367
0
    return gnutls_assert_val(ret);
368
369
  /* Adjust the data */
370
0
  data += username.size + 2;
371
372
  /* should never fail. It will always return a key even if it is
373
   * a random one */
374
0
  ret = _gnutls_psk_pwd_find_entry(session, info->username,
375
0
           info->username_len, &psk_key, NULL);
376
0
  if (ret < 0)
377
0
    return gnutls_assert_val(ret);
378
379
0
  ret = _gnutls_proc_ecdh_common_client_kx(session, data, data_size,
380
0
             get_group(session), &psk_key);
381
382
0
  _gnutls_free_key_datum(&psk_key);
383
384
0
  return ret;
385
0
}
386
387
static int proc_dhe_psk_server_kx(gnutls_session_t session, uint8_t *data,
388
          size_t data_size)
389
0
{
390
0
  int ret;
391
0
  psk_auth_info_t info;
392
0
  gnutls_datum_t hint;
393
394
  /* set auth_info */
395
0
  if ((ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK,
396
0
            sizeof(psk_auth_info_st), 1)) < 0) {
397
0
    gnutls_assert();
398
0
    return ret;
399
0
  }
400
401
0
  DECR_LEN(data_size, 2);
402
403
0
  hint.size = _gnutls_read_uint16(&data[0]);
404
0
  hint.data = &data[2];
405
406
0
  DECR_LEN(data_size, hint.size);
407
0
  data += 2 + hint.size;
408
409
0
  ret = _gnutls_proc_dh_common_server_kx(session, data, data_size);
410
0
  if (ret < 0) {
411
0
    gnutls_assert();
412
0
    return ret;
413
0
  }
414
415
0
  info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
416
0
  if (info == NULL)
417
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
418
419
0
  if (hint.size > MAX_USERNAME_SIZE)
420
0
    return gnutls_assert_val(GNUTLS_E_ILLEGAL_SRP_USERNAME);
421
422
0
  ret = _gnutls_copy_psk_hint(info, hint);
423
0
  if (ret < 0) {
424
0
    gnutls_assert();
425
0
    return ret;
426
0
  }
427
428
0
  return 0;
429
0
}
430
431
static int proc_ecdhe_psk_server_kx(gnutls_session_t session, uint8_t *data,
432
            size_t data_size)
433
0
{
434
0
  int ret;
435
0
  psk_auth_info_t info;
436
0
  gnutls_datum_t hint;
437
438
  /* set auth_info */
439
0
  if ((ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK,
440
0
            sizeof(psk_auth_info_st), 1)) < 0) {
441
0
    gnutls_assert();
442
0
    return ret;
443
0
  }
444
445
0
  DECR_LEN(data_size, 2);
446
447
0
  hint.size = _gnutls_read_uint16(&data[0]);
448
0
  hint.data = &data[2];
449
450
0
  DECR_LEN(data_size, hint.size);
451
0
  data += 2 + hint.size;
452
453
0
  ret = _gnutls_proc_ecdh_common_server_kx(session, data, data_size);
454
0
  if (ret < 0) {
455
0
    gnutls_assert();
456
0
    return ret;
457
0
  }
458
459
0
  info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
460
0
  if (info == NULL)
461
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
462
463
0
  if (hint.size > MAX_USERNAME_SIZE)
464
0
    return gnutls_assert_val(GNUTLS_E_ILLEGAL_SRP_USERNAME);
465
466
0
  ret = _gnutls_copy_psk_hint(info, hint);
467
0
  if (ret < 0) {
468
0
    gnutls_assert();
469
0
    return ret;
470
0
  }
471
472
0
  return 0;
473
0
}
474
475
#endif /* ENABLE_PSK */