Coverage Report

Created: 2025-03-18 06:55

/src/gnutls/lib/auth/psk_passwd.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
/* 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
  int 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 (username->size == 0);
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
  /* if format is in hex, e.g. #FAFAFA */
103
0
  if (line[0] == '#' && line_size > 1) {
104
0
    hexline.data = (void *)&line[1];
105
0
    hexline.size = i - 1;
106
107
0
    if (gnutls_hex_decode2(&hexline, &hex_username) < 0)
108
0
      return gnutls_assert_val(0);
109
110
0
    if (hex_username.size == username->size)
111
0
      retval = memcmp(username->data, hex_username.data,
112
0
          username->size);
113
0
    else
114
0
      retval = -1;
115
116
0
    _gnutls_free_datum(&hex_username);
117
0
  } else {
118
0
    retval = strncmp((const char *)username->data, line,
119
0
         MAX(i, username->size));
120
0
  }
121
122
0
  return (retval == 0);
123
0
}
124
125
/* Randomizes the given password entry. It actually sets a random password. 
126
 * Returns 0 on success.
127
 */
128
static int _randomize_psk(gnutls_datum_t *psk)
129
0
{
130
0
  int ret;
131
132
0
  psk->data = gnutls_malloc(16);
133
0
  if (psk->data == NULL) {
134
0
    gnutls_assert();
135
0
    return GNUTLS_E_MEMORY_ERROR;
136
0
  }
137
138
0
  psk->size = 16;
139
140
0
  ret = gnutls_rnd(GNUTLS_RND_NONCE, (char *)psk->data, 16);
141
0
  if (ret < 0) {
142
0
    gnutls_assert();
143
0
    return ret;
144
0
  }
145
146
0
  return 0;
147
0
}
148
149
/* Returns the PSK key of the given user. 
150
 * If the user doesn't exist a random password is returned instead.
151
 */
152
int _gnutls_psk_pwd_find_entry(gnutls_session_t session, const char *username,
153
             uint16_t username_len, gnutls_datum_t *psk,
154
             gnutls_psk_key_flags *flags)
155
0
{
156
0
  gnutls_psk_server_credentials_t cred;
157
0
  FILE *fp;
158
0
  char *line = NULL;
159
0
  size_t line_size = 0;
160
0
  int ret;
161
0
  gnutls_datum_t username_datum = { .data = (unsigned char *)username,
162
0
            .size = username_len };
163
164
0
  cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred(
165
0
    session, GNUTLS_CRD_PSK);
166
0
  if (cred == NULL) {
167
0
    gnutls_assert();
168
0
    return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
169
0
  }
170
171
  /* if the callback which sends the parameters is
172
   * set, use it.
173
   */
174
0
  if (cred->pwd_callback != NULL) {
175
0
    ret = cred->pwd_callback(session, &username_datum, psk, flags);
176
0
    if (ret == 1) { /* the user does not exist */
177
0
      ret = _randomize_psk(psk);
178
0
      if (ret < 0) {
179
0
        gnutls_assert();
180
0
        return ret;
181
0
      }
182
0
      return 0;
183
0
    }
184
185
0
    if (ret < 0) {
186
0
      gnutls_assert();
187
0
      return GNUTLS_E_SRP_PWD_ERROR;
188
0
    }
189
190
0
    return 0;
191
0
  }
192
193
  /* The callback was not set. Proceed.
194
   */
195
0
  if (cred->password_file == NULL) {
196
0
    gnutls_assert();
197
0
    return GNUTLS_E_SRP_PWD_ERROR;
198
0
  }
199
200
  /* Open the selected password file.
201
   */
202
0
  fp = fopen(cred->password_file, "re");
203
0
  if (fp == NULL) {
204
0
    gnutls_assert();
205
0
    return GNUTLS_E_SRP_PWD_ERROR;
206
0
  }
207
208
0
  while (getline(&line, &line_size, fp) > 0) {
209
0
    if (username_matches(&username_datum, line, line_size)) {
210
0
      ret = pwd_put_values(psk, line);
211
0
      if (ret < 0) {
212
0
        gnutls_assert();
213
0
        ret = GNUTLS_E_SRP_PWD_ERROR;
214
0
        goto cleanup;
215
0
      }
216
0
      if (flags) {
217
0
        *flags = 0;
218
0
      }
219
0
      ret = 0;
220
0
      goto cleanup;
221
0
    }
222
0
  }
223
224
  /* user was not found. Fake him. 
225
   */
226
0
  ret = _randomize_psk(psk);
227
0
  if (ret < 0) {
228
0
    goto cleanup;
229
0
  }
230
231
0
  if (flags) {
232
0
    *flags = 0;
233
0
  }
234
0
  ret = 0;
235
0
cleanup:
236
0
  if (fp != NULL)
237
0
    fclose(fp);
238
239
0
  zeroize_key(line, line_size);
240
0
  free(line);
241
242
0
  return ret;
243
0
}
244
245
/* returns the username and they key for the PSK session.
246
 * Free is non (0) if they have to be freed.
247
 */
248
int _gnutls_find_psk_key(gnutls_session_t session,
249
       gnutls_psk_client_credentials_t cred,
250
       gnutls_datum_t *username, gnutls_datum_t *key,
251
       gnutls_psk_key_flags *flags, int *free)
252
0
{
253
0
  int ret;
254
255
0
  *free = 0;
256
257
0
  if (cred->username.data != NULL && cred->key.data != NULL) {
258
0
    username->data = cred->username.data;
259
0
    username->size = cred->username.size;
260
0
    key->data = cred->key.data;
261
0
    key->size = cred->key.size;
262
0
    if (flags) {
263
0
      *flags = 0;
264
0
    }
265
0
  } else if (cred->get_function != NULL) {
266
0
    ret = cred->get_function(session, username, key, flags);
267
0
    if (ret) {
268
0
      return gnutls_assert_val(ret);
269
0
    }
270
271
0
    *free = 1;
272
0
  } else
273
0
    return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
274
275
0
  return 0;
276
0
}