Coverage Report

Created: 2026-05-16 07:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/lib/auth/psk_passwd.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
/* Functions for operating in an PSK passwd file are included here */
24
25
#include "gnutls_int.h"
26
27
#include "x509_b64.h"
28
#include "errors.h"
29
#include "auth/psk_passwd.h"
30
#include "auth/psk.h"
31
#include "auth.h"
32
#include "dh.h"
33
#include "debug.h"
34
#include "str.h"
35
#include "datum.h"
36
#include "num.h"
37
#include "random.h"
38
39
/* this function parses passwd.psk file. Format is:
40
 * string(username):hex(passwd)
41
 */
42
static int pwd_put_values(gnutls_datum_t *psk, char *str)
43
0
{
44
0
  char *p;
45
0
  int len, ret;
46
0
  gnutls_datum_t tmp;
47
48
0
  p = strchr(str, ':');
49
0
  if (p == NULL) {
50
0
    gnutls_assert();
51
0
    return GNUTLS_E_SRP_PWD_PARSING_ERROR;
52
0
  }
53
54
0
  *p = '\0';
55
0
  p++;
56
57
  /* skip username
58
   */
59
60
  /* read the key
61
   */
62
0
  len = strlen(p);
63
0
  if (p[len - 1] == '\n' || p[len - 1] == ' ')
64
0
    len--;
65
66
0
  tmp.data = (void *)p;
67
0
  tmp.size = len;
68
0
  ret = gnutls_hex_decode2(&tmp, psk);
69
0
  if (ret < 0) {
70
0
    gnutls_assert();
71
0
    return ret;
72
0
  }
73
74
0
  return 0;
75
0
}
76
77
ATTRIBUTE_NONNULL((1, 2))
78
static bool username_matches(const gnutls_datum_t *username, const char *line,
79
           size_t line_size)
80
0
{
81
0
  bool retval;
82
0
  unsigned i;
83
0
  gnutls_datum_t hexline, hex_username = { NULL, 0 };
84
85
  /*
86
   * Guard against weird behavior - we don't check 'line',
87
   * as it's returned by getline(), which will never return NULL
88
   * if successful.
89
   */
90
0
  if (username->data == NULL)
91
0
    return false;
92
93
0
  if (line_size == 0)
94
0
    return false;
95
96
  /* move to first ':' */
97
0
  i = 0;
98
0
  while ((i < line_size) && (line[i] != '\0') && (line[i] != ':')) {
99
0
    i++;
100
0
  }
101
102
0
  if (line[i] != ':')
103
0
    return false;
104
105
  /* if format is in hex, e.g. #FAFAFA */
106
0
  if (line[0] == '#' && line_size > 1) {
107
0
    hexline.data = (void *)&line[1];
108
0
    hexline.size = i - 1;
109
110
0
    if (gnutls_hex_decode2(&hexline, &hex_username) < 0)
111
0
      return gnutls_assert_val(0);
112
113
0
    retval = hex_username.size == username->size &&
114
0
       memcmp(username->data, hex_username.data,
115
0
        username->size) == 0;
116
117
0
    _gnutls_free_datum(&hex_username);
118
0
  } else {
119
0
    retval = i == username->size &&
120
0
       strncmp((const char *)username->data, line, i) == 0;
121
0
  }
122
123
0
  return retval;
124
0
}
125
126
/* Randomizes the given password entry. It actually sets a random password. 
127
 * Returns 0 on success.
128
 */
129
static int _randomize_psk(gnutls_datum_t *psk)
130
0
{
131
0
  int ret;
132
133
0
  psk->data = gnutls_malloc(16);
134
0
  if (psk->data == NULL) {
135
0
    gnutls_assert();
136
0
    return GNUTLS_E_MEMORY_ERROR;
137
0
  }
138
139
0
  psk->size = 16;
140
141
0
  ret = gnutls_rnd(GNUTLS_RND_NONCE, (char *)psk->data, 16);
142
0
  if (ret < 0) {
143
0
    gnutls_assert();
144
0
    return ret;
145
0
  }
146
147
0
  return 0;
148
0
}
149
150
/* Returns the PSK key of the given user. 
151
 * If the user doesn't exist a random password is returned instead.
152
 */
153
int _gnutls_psk_pwd_find_entry(gnutls_session_t session, const char *username,
154
             uint16_t username_len, gnutls_datum_t *psk,
155
             gnutls_psk_key_flags *flags)
156
0
{
157
0
  gnutls_psk_server_credentials_t cred;
158
0
  FILE *fp;
159
0
  char *line = NULL;
160
0
  size_t line_size = 0;
161
0
  int ret;
162
0
  gnutls_datum_t username_datum = { .data = (unsigned char *)username,
163
0
            .size = username_len };
164
165
0
  cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred(
166
0
    session, GNUTLS_CRD_PSK);
167
0
  if (cred == NULL) {
168
0
    gnutls_assert();
169
0
    return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
170
0
  }
171
172
  /* if the callback which sends the parameters is
173
   * set, use it.
174
   */
175
0
  if (cred->pwd_callback != NULL) {
176
0
    ret = cred->pwd_callback(session, &username_datum, psk, flags);
177
0
    if (ret == 1) { /* the user does not exist */
178
0
      ret = _randomize_psk(psk);
179
0
      if (ret < 0) {
180
0
        gnutls_assert();
181
0
        return ret;
182
0
      }
183
0
      return 0;
184
0
    }
185
186
0
    if (ret < 0) {
187
0
      gnutls_assert();
188
0
      return GNUTLS_E_SRP_PWD_ERROR;
189
0
    }
190
191
0
    return 0;
192
0
  }
193
194
  /* The callback was not set. Proceed.
195
   */
196
0
  if (cred->password_file == NULL) {
197
0
    gnutls_assert();
198
0
    return GNUTLS_E_SRP_PWD_ERROR;
199
0
  }
200
201
  /* Open the selected password file.
202
   */
203
0
  fp = fopen(cred->password_file, "re");
204
0
  if (fp == NULL) {
205
0
    gnutls_assert();
206
0
    return GNUTLS_E_SRP_PWD_ERROR;
207
0
  }
208
209
0
  while (getline(&line, &line_size, fp) > 0) {
210
0
    if (username_matches(&username_datum, line, line_size)) {
211
0
      ret = pwd_put_values(psk, line);
212
0
      if (ret < 0) {
213
0
        gnutls_assert();
214
0
        ret = GNUTLS_E_SRP_PWD_ERROR;
215
0
        goto cleanup;
216
0
      }
217
0
      if (flags) {
218
0
        *flags = 0;
219
0
      }
220
0
      ret = 0;
221
0
      goto cleanup;
222
0
    }
223
0
  }
224
225
  /* user was not found. Fake him. 
226
   */
227
0
  ret = _randomize_psk(psk);
228
0
  if (ret < 0) {
229
0
    goto cleanup;
230
0
  }
231
232
0
  if (flags) {
233
0
    *flags = 0;
234
0
  }
235
0
  ret = 0;
236
0
cleanup:
237
0
  if (fp != NULL)
238
0
    fclose(fp);
239
240
0
  zeroize_key(line, line_size);
241
0
  free(line);
242
243
0
  return ret;
244
0
}
245
246
/* returns the username and they key for the PSK session.
247
 * Free is non (0) if they have to be freed.
248
 */
249
int _gnutls_find_psk_key(gnutls_session_t session,
250
       gnutls_psk_client_credentials_t cred,
251
       gnutls_datum_t *username, gnutls_datum_t *key,
252
       gnutls_psk_key_flags *flags, int *free)
253
0
{
254
0
  int ret;
255
256
0
  *free = 0;
257
258
0
  if (cred->username.data != NULL && cred->key.data != NULL) {
259
0
    username->data = cred->username.data;
260
0
    username->size = cred->username.size;
261
0
    key->data = cred->key.data;
262
0
    key->size = cred->key.size;
263
0
    if (flags) {
264
0
      *flags = 0;
265
0
    }
266
0
  } else if (cred->get_function != NULL) {
267
0
    ret = cred->get_function(session, username, key, flags);
268
0
    if (ret) {
269
0
      return gnutls_assert_val(ret);
270
0
    }
271
272
0
    *free = 1;
273
0
  } else
274
0
    return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
275
276
0
  return 0;
277
0
}