Coverage Report

Created: 2026-08-14 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/lib/auth/psk.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2005-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
25
#ifdef ENABLE_PSK
26
27
#include "errors.h"
28
#include "auth.h"
29
#include "debug.h"
30
#include "num.h"
31
#include "auth/psk.h"
32
#include "auth/psk_passwd.h"
33
#include "str.h"
34
#include "datum.h"
35
36
static int _gnutls_proc_psk_client_kx(gnutls_session_t, uint8_t *, size_t);
37
static int _gnutls_proc_psk_server_kx(gnutls_session_t session, uint8_t *data,
38
              size_t data_size);
39
40
const mod_auth_st psk_auth_struct = { "PSK",
41
              NULL,
42
              NULL,
43
              _gnutls_gen_psk_server_kx,
44
              _gnutls_gen_psk_client_kx,
45
              NULL,
46
              NULL,
47
48
              NULL,
49
              NULL, /* certificate */
50
              _gnutls_proc_psk_server_kx,
51
              _gnutls_proc_psk_client_kx,
52
              NULL,
53
              NULL };
54
55
/* Set the PSK premaster secret.
56
 */
57
int _gnutls_set_psk_session_key(gnutls_session_t session,
58
        gnutls_datum_t *ppsk /* key */,
59
        gnutls_datum_t *dh_secret)
60
0
{
61
0
  gnutls_datum_t pwd_psk = { NULL, 0 };
62
0
  size_t dh_secret_size;
63
0
  uint8_t *p;
64
0
  int ret;
65
66
0
  if (dh_secret == NULL)
67
0
    dh_secret_size = ppsk->size;
68
0
  else
69
0
    dh_secret_size = dh_secret->size;
70
71
  /* set the session key
72
   */
73
0
  session->key.key.size = 4 + dh_secret_size + ppsk->size;
74
0
  session->key.key.data = gnutls_malloc(session->key.key.size);
75
0
  if (session->key.key.data == NULL) {
76
0
    gnutls_assert();
77
0
    ret = GNUTLS_E_MEMORY_ERROR;
78
0
    goto error;
79
0
  }
80
81
  /* format of the premaster secret:
82
   * (uint16_t) psk_size
83
   * psk_size bytes of (0)s
84
   * (uint16_t) psk_size
85
   * the psk
86
   */
87
0
  p = session->key.key.data;
88
0
  _gnutls_write_uint16(dh_secret_size, p);
89
0
  p += 2;
90
0
  if (dh_secret == NULL)
91
0
    memset(p, 0, dh_secret_size);
92
0
  else
93
0
    memcpy(p, dh_secret->data, dh_secret->size);
94
95
0
  p += dh_secret_size;
96
0
  _gnutls_write_uint16(ppsk->size, p);
97
0
  if (ppsk->data != NULL)
98
0
    memcpy(p + 2, ppsk->data, ppsk->size);
99
100
0
  ret = 0;
101
102
0
error:
103
0
  _gnutls_free_key_datum(&pwd_psk);
104
0
  return ret;
105
0
}
106
107
/* Generates the PSK client key exchange
108
 *
109
 * 
110
 * struct {
111
 *    select (KeyExchangeAlgorithm) {
112
 *       uint8_t psk_identity<0..2^16-1>;
113
 *    } exchange_keys;
114
 * } ClientKeyExchange;
115
 *
116
 */
117
int _gnutls_gen_psk_client_kx(gnutls_session_t session, gnutls_buffer_st *data)
118
0
{
119
0
  int ret, free;
120
0
  gnutls_datum_t username = { NULL, 0 };
121
0
  gnutls_datum_t key;
122
0
  gnutls_psk_client_credentials_t cred;
123
0
  psk_auth_info_t info;
124
125
0
  cred = (gnutls_psk_client_credentials_t)_gnutls_get_cred(
126
0
    session, GNUTLS_CRD_PSK);
127
128
0
  if (cred == NULL) {
129
0
    gnutls_assert();
130
0
    return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
131
0
  }
132
133
0
  info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
134
0
  if (info == NULL) {
135
0
    gnutls_assert();
136
0
    return GNUTLS_E_INTERNAL_ERROR;
137
0
  }
138
139
0
  ret = _gnutls_find_psk_key(session, cred, &username, &key, NULL, &free);
140
0
  if (ret < 0)
141
0
    return gnutls_assert_val(ret);
142
143
0
  ret = _gnutls_set_psk_session_key(session, &key, NULL);
144
0
  if (ret < 0) {
145
0
    gnutls_assert();
146
0
    goto cleanup;
147
0
  }
148
149
0
  ret = _gnutls_buffer_append_data_prefix16(data, username.data,
150
0
              username.size);
151
0
  if (ret < 0) {
152
0
    gnutls_assert();
153
0
  }
154
155
0
  if (username.size > MAX_USERNAME_SIZE) {
156
0
    gnutls_assert();
157
0
    ret = GNUTLS_E_ILLEGAL_SRP_USERNAME;
158
0
    goto cleanup;
159
0
  }
160
161
0
  assert(username.data != NULL);
162
0
  ret = _gnutls_copy_psk_username(info, username);
163
0
  if (ret < 0) {
164
0
    gnutls_assert();
165
0
    goto cleanup;
166
0
  }
167
168
0
cleanup:
169
0
  if (free) {
170
0
    gnutls_free(username.data);
171
0
    _gnutls_free_key_datum(&key);
172
0
  }
173
174
0
  return ret;
175
0
}
176
177
/* just read the username from the client key exchange.
178
 */
179
static int _gnutls_proc_psk_client_kx(gnutls_session_t session, uint8_t *data,
180
              size_t data_size)
181
0
{
182
0
  int ret;
183
0
  gnutls_datum_t username, psk_key;
184
0
  gnutls_psk_server_credentials_t cred;
185
0
  psk_auth_info_t info;
186
187
0
  cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred(
188
0
    session, GNUTLS_CRD_PSK);
189
190
0
  if (cred == NULL) {
191
0
    gnutls_assert();
192
0
    return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
193
0
  }
194
195
0
  if ((ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK,
196
0
            sizeof(psk_auth_info_st), 1)) < 0) {
197
0
    gnutls_assert();
198
0
    return ret;
199
0
  }
200
201
0
  DECR_LEN(data_size, 2);
202
0
  username.size = _gnutls_read_uint16(&data[0]);
203
204
0
  DECR_LEN(data_size, username.size);
205
206
0
  username.data = &data[2];
207
208
  /* copy the username to the auth info structures
209
   */
210
0
  info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
211
0
  if (info == NULL) {
212
0
    gnutls_assert();
213
0
    return GNUTLS_E_INTERNAL_ERROR;
214
0
  }
215
216
0
  if (username.size > MAX_USERNAME_SIZE) {
217
0
    gnutls_assert();
218
0
    return GNUTLS_E_ILLEGAL_SRP_USERNAME;
219
0
  }
220
221
0
  ret = _gnutls_copy_psk_username(info, username);
222
0
  if (ret < 0)
223
0
    return gnutls_assert_val(ret);
224
225
0
  ret = _gnutls_psk_pwd_find_entry(session, info->username,
226
0
           info->username_len, &psk_key, NULL);
227
0
  if (ret < 0)
228
0
    return gnutls_assert_val(ret);
229
230
0
  ret = _gnutls_set_psk_session_key(session, &psk_key, NULL);
231
0
  if (ret < 0) {
232
0
    gnutls_assert();
233
0
    goto error;
234
0
  }
235
236
0
  ret = 0;
237
238
0
error:
239
0
  _gnutls_free_key_datum(&psk_key);
240
241
0
  return ret;
242
0
}
243
244
/* Generates the PSK server key exchange
245
 *
246
 * struct {
247
 *     select (KeyExchangeAlgorithm) {
248
 *   // other cases for rsa, diffie_hellman, etc.
249
 *   case psk:  // NEW
250
 *       uint8_t psk_identity_hint<0..2^16-1>;
251
 *     };
252
 * } ServerKeyExchange;
253
 *
254
 */
255
int _gnutls_gen_psk_server_kx(gnutls_session_t session, gnutls_buffer_st *data)
256
0
{
257
0
  gnutls_psk_server_credentials_t cred;
258
0
  gnutls_datum_t hint;
259
260
0
  cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred(
261
0
    session, GNUTLS_CRD_PSK);
262
263
0
  if (cred == NULL) {
264
0
    gnutls_assert();
265
0
    return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
266
0
  }
267
268
  /* Abort sending this message if there is no PSK identity hint. */
269
0
  if (cred->hint == NULL) {
270
0
    gnutls_assert();
271
0
    return GNUTLS_E_INT_RET_0;
272
0
  }
273
274
0
  hint.data = (uint8_t *)cred->hint;
275
0
  hint.size = strlen(cred->hint);
276
277
0
  return _gnutls_buffer_append_data_prefix16(data, hint.data, hint.size);
278
0
}
279
280
/* Read the hint from the server key exchange */
281
static int _gnutls_proc_psk_server_kx(gnutls_session_t session, uint8_t *data,
282
              size_t data_size)
283
0
{
284
0
  int ret;
285
0
  gnutls_psk_client_credentials_t cred;
286
0
  psk_auth_info_t info;
287
0
  gnutls_datum_t hint;
288
289
0
  cred = (gnutls_psk_client_credentials_t)_gnutls_get_cred(
290
0
    session, GNUTLS_CRD_PSK);
291
0
  if (cred == NULL)
292
0
    return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
293
294
0
  ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK,
295
0
             sizeof(psk_auth_info_st), 1);
296
0
  if (ret < 0)
297
0
    return gnutls_assert_val(ret);
298
299
0
  DECR_LENGTH_RET(data_size, 2, 0);
300
0
  hint.size = _gnutls_read_uint16(&data[0]);
301
302
0
  DECR_LEN(data_size, hint.size);
303
0
  hint.data = &data[2];
304
305
0
  info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
306
0
  if (info == NULL)
307
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
308
309
0
  if (hint.size > MAX_USERNAME_SIZE)
310
0
    return gnutls_assert_val(GNUTLS_E_ILLEGAL_SRP_USERNAME);
311
312
0
  ret = _gnutls_copy_psk_hint(info, hint);
313
0
  return ret;
314
0
}
315
316
#endif /* ENABLE_PSK */