Coverage Report

Created: 2023-03-26 08:33

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