Coverage Report

Created: 2025-11-16 06:46

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
4.99k
{
61
4.99k
  gnutls_datum_t pwd_psk = { NULL, 0 };
62
4.99k
  size_t dh_secret_size;
63
4.99k
  uint8_t *p;
64
4.99k
  int ret;
65
66
4.99k
  if (dh_secret == NULL)
67
298
    dh_secret_size = ppsk->size;
68
4.69k
  else
69
4.69k
    dh_secret_size = dh_secret->size;
70
71
  /* set the session key
72
   */
73
4.99k
  session->key.key.size = 4 + dh_secret_size + ppsk->size;
74
4.99k
  session->key.key.data = gnutls_malloc(session->key.key.size);
75
4.99k
  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
4.99k
  p = session->key.key.data;
88
4.99k
  _gnutls_write_uint16(dh_secret_size, p);
89
4.99k
  p += 2;
90
4.99k
  if (dh_secret == NULL)
91
298
    memset(p, 0, dh_secret_size);
92
4.69k
  else
93
4.69k
    memcpy(p, dh_secret->data, dh_secret->size);
94
95
4.99k
  p += dh_secret_size;
96
4.99k
  _gnutls_write_uint16(ppsk->size, p);
97
4.99k
  if (ppsk->data != NULL)
98
4.99k
    memcpy(p + 2, ppsk->data, ppsk->size);
99
100
4.99k
  ret = 0;
101
102
4.99k
error:
103
4.99k
  _gnutls_free_key_datum(&pwd_psk);
104
4.99k
  return ret;
105
4.99k
}
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
170
{
119
170
  int ret, free;
120
170
  gnutls_datum_t username = { NULL, 0 };
121
170
  gnutls_datum_t key;
122
170
  gnutls_psk_client_credentials_t cred;
123
170
  psk_auth_info_t info;
124
125
170
  cred = (gnutls_psk_client_credentials_t)_gnutls_get_cred(
126
170
    session, GNUTLS_CRD_PSK);
127
128
170
  if (cred == NULL) {
129
0
    gnutls_assert();
130
0
    return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
131
0
  }
132
133
170
  info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
134
170
  if (info == NULL) {
135
0
    gnutls_assert();
136
0
    return GNUTLS_E_INTERNAL_ERROR;
137
0
  }
138
139
170
  ret = _gnutls_find_psk_key(session, cred, &username, &key, NULL, &free);
140
170
  if (ret < 0)
141
0
    return gnutls_assert_val(ret);
142
143
170
  ret = _gnutls_set_psk_session_key(session, &key, NULL);
144
170
  if (ret < 0) {
145
0
    gnutls_assert();
146
0
    goto cleanup;
147
0
  }
148
149
170
  ret = _gnutls_buffer_append_data_prefix(data, 16, username.data,
150
170
            username.size);
151
170
  if (ret < 0) {
152
0
    gnutls_assert();
153
0
  }
154
155
170
  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
170
  assert(username.data != NULL);
162
170
  ret = _gnutls_copy_psk_username(info, username);
163
170
  if (ret < 0) {
164
0
    gnutls_assert();
165
0
    goto cleanup;
166
0
  }
167
168
170
cleanup:
169
170
  if (free) {
170
0
    gnutls_free(username.data);
171
0
    _gnutls_free_key_datum(&key);
172
0
  }
173
174
170
  return ret;
175
170
}
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
141
{
182
141
  ssize_t data_size = _data_size;
183
141
  int ret;
184
141
  gnutls_datum_t username, psk_key;
185
141
  gnutls_psk_server_credentials_t cred;
186
141
  psk_auth_info_t info;
187
188
141
  cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred(
189
141
    session, GNUTLS_CRD_PSK);
190
191
141
  if (cred == NULL) {
192
0
    gnutls_assert();
193
0
    return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
194
0
  }
195
196
141
  if ((ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK,
197
141
            sizeof(psk_auth_info_st), 1)) < 0) {
198
0
    gnutls_assert();
199
0
    return ret;
200
0
  }
201
202
141
  DECR_LEN(data_size, 2);
203
139
  username.size = _gnutls_read_uint16(&data[0]);
204
205
139
  DECR_LEN(data_size, username.size);
206
207
128
  username.data = &data[2];
208
209
  /* copy the username to the auth info structures
210
   */
211
128
  info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
212
128
  if (info == NULL) {
213
0
    gnutls_assert();
214
0
    return GNUTLS_E_INTERNAL_ERROR;
215
0
  }
216
217
128
  if (username.size > MAX_USERNAME_SIZE) {
218
0
    gnutls_assert();
219
0
    return GNUTLS_E_ILLEGAL_SRP_USERNAME;
220
0
  }
221
222
128
  ret = _gnutls_copy_psk_username(info, username);
223
128
  if (ret < 0)
224
0
    return gnutls_assert_val(ret);
225
226
128
  ret = _gnutls_psk_pwd_find_entry(session, info->username,
227
128
           info->username_len, &psk_key, NULL);
228
128
  if (ret < 0)
229
0
    return gnutls_assert_val(ret);
230
231
128
  ret = _gnutls_set_psk_session_key(session, &psk_key, NULL);
232
128
  if (ret < 0) {
233
0
    gnutls_assert();
234
0
    goto error;
235
0
  }
236
237
128
  ret = 0;
238
239
128
error:
240
128
  _gnutls_free_key_datum(&psk_key);
241
242
128
  return ret;
243
128
}
244
245
/* Generates the PSK server key exchange
246
 *
247
 * struct {
248
 *     select (KeyExchangeAlgorithm) {
249
 *   // other cases for rsa, diffie_hellman, etc.
250
 *   case psk:  // NEW
251
 *       uint8_t psk_identity_hint<0..2^16-1>;
252
 *     };
253
 * } ServerKeyExchange;
254
 *
255
 */
256
int _gnutls_gen_psk_server_kx(gnutls_session_t session, gnutls_buffer_st *data)
257
329
{
258
329
  gnutls_psk_server_credentials_t cred;
259
329
  gnutls_datum_t hint;
260
261
329
  cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred(
262
329
    session, GNUTLS_CRD_PSK);
263
264
329
  if (cred == NULL) {
265
0
    gnutls_assert();
266
0
    return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
267
0
  }
268
269
  /* Abort sending this message if there is no PSK identity hint. */
270
329
  if (cred->hint == NULL) {
271
329
    gnutls_assert();
272
329
    return GNUTLS_E_INT_RET_0;
273
329
  }
274
275
0
  hint.data = (uint8_t *)cred->hint;
276
0
  hint.size = strlen(cred->hint);
277
278
0
  return _gnutls_buffer_append_data_prefix(data, 16, hint.data,
279
0
             hint.size);
280
329
}
281
282
/* Read the hint from the server key exchange */
283
static int _gnutls_proc_psk_server_kx(gnutls_session_t session, uint8_t *data,
284
              size_t _data_size)
285
216
{
286
216
  int ret;
287
216
  ssize_t data_size = _data_size;
288
216
  gnutls_psk_client_credentials_t cred;
289
216
  psk_auth_info_t info;
290
216
  gnutls_datum_t hint;
291
292
216
  cred = (gnutls_psk_client_credentials_t)_gnutls_get_cred(
293
216
    session, GNUTLS_CRD_PSK);
294
216
  if (cred == NULL)
295
0
    return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
296
297
216
  ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK,
298
216
             sizeof(psk_auth_info_st), 1);
299
216
  if (ret < 0)
300
0
    return gnutls_assert_val(ret);
301
302
216
  DECR_LENGTH_RET(data_size, 2, 0);
303
17
  hint.size = _gnutls_read_uint16(&data[0]);
304
305
17
  DECR_LEN(data_size, hint.size);
306
8
  hint.data = &data[2];
307
308
8
  info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
309
8
  if (info == NULL)
310
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
311
312
8
  if (hint.size > MAX_USERNAME_SIZE)
313
0
    return gnutls_assert_val(GNUTLS_E_ILLEGAL_SRP_USERNAME);
314
315
8
  ret = _gnutls_copy_psk_hint(info, hint);
316
8
  return ret;
317
8
}
318
319
#endif /* ENABLE_PSK */