Coverage Report

Created: 2023-03-26 08:33

/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
static bool username_matches(const gnutls_datum_t * username,
78
           const char *line, size_t line_size)
79
0
{
80
0
  int retval;
81
0
  unsigned i;
82
0
  gnutls_datum_t hexline, hex_username = { NULL, 0 };
83
84
  /*
85
   * Guard against weird behavior - we don't check 'line',
86
   * as it's returned by getline(), which will never return NULL
87
   * if successful.
88
   */
89
0
  if (username->data == NULL)
90
0
    return false;
91
92
0
  if (line_size == 0)
93
0
    return (username->size == 0);
94
95
  /* move to first ':' */
96
0
  i = 0;
97
0
  while ((i < line_size) && (line[i] != '\0')
98
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 =
112
0
          memcmp(username->data, hex_username.data,
113
0
           username->size);
114
0
    else
115
0
      retval = -1;
116
117
0
    _gnutls_free_datum(&hex_username);
118
0
  } else {
119
0
    retval =
120
0
        strncmp((const char *)username->data, line,
121
0
          MAX(i, username->size));
122
0
  }
123
124
0
  return (retval == 0);
125
0
}
126
127
/* Randomizes the given password entry. It actually sets a random password. 
128
 * Returns 0 on success.
129
 */
130
static int _randomize_psk(gnutls_datum_t * psk)
131
0
{
132
0
  int ret;
133
134
0
  psk->data = gnutls_malloc(16);
135
0
  if (psk->data == NULL) {
136
0
    gnutls_assert();
137
0
    return GNUTLS_E_MEMORY_ERROR;
138
0
  }
139
140
0
  psk->size = 16;
141
142
0
  ret = gnutls_rnd(GNUTLS_RND_NONCE, (char *)psk->data, 16);
143
0
  if (ret < 0) {
144
0
    gnutls_assert();
145
0
    return ret;
146
0
  }
147
148
0
  return 0;
149
0
}
150
151
/* Returns the PSK key of the given user. 
152
 * If the user doesn't exist a random password is returned instead.
153
 */
154
int
155
_gnutls_psk_pwd_find_entry(gnutls_session_t session,
156
         const char *username, uint16_t username_len,
157
         gnutls_datum_t * psk)
158
0
{
159
0
  gnutls_psk_server_credentials_t cred;
160
0
  FILE *fp;
161
0
  char *line = NULL;
162
0
  size_t line_size = 0;
163
0
  int ret;
164
0
  gnutls_datum_t username_datum = {
165
0
    .data = (unsigned char *)username,
166
0
    .size = username_len
167
0
  };
168
169
0
  cred = (gnutls_psk_server_credentials_t)
170
0
      _gnutls_get_cred(session, GNUTLS_CRD_PSK);
171
0
  if (cred == NULL) {
172
0
    gnutls_assert();
173
0
    return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
174
0
  }
175
176
  /* if the callback which sends the parameters is
177
   * set, use it.
178
   */
179
0
  if (cred->pwd_callback != NULL) {
180
0
    ret = cred->pwd_callback(session, &username_datum, psk);
181
182
0
    if (ret == 1) { /* the user does not exist */
183
0
      ret = _randomize_psk(psk);
184
0
      if (ret < 0) {
185
0
        gnutls_assert();
186
0
        return ret;
187
0
      }
188
0
      return 0;
189
0
    }
190
191
0
    if (ret < 0) {
192
0
      gnutls_assert();
193
0
      return GNUTLS_E_SRP_PWD_ERROR;
194
0
    }
195
196
0
    return 0;
197
0
  }
198
199
  /* The callback was not set. Proceed.
200
   */
201
0
  if (cred->password_file == NULL) {
202
0
    gnutls_assert();
203
0
    return GNUTLS_E_SRP_PWD_ERROR;
204
0
  }
205
206
  /* Open the selected password file.
207
   */
208
0
  fp = fopen(cred->password_file, "re");
209
0
  if (fp == NULL) {
210
0
    gnutls_assert();
211
0
    return GNUTLS_E_SRP_PWD_ERROR;
212
0
  }
213
214
0
  while (getline(&line, &line_size, fp) > 0) {
215
0
    if (username_matches(&username_datum, line, line_size)) {
216
0
      ret = pwd_put_values(psk, line);
217
0
      if (ret < 0) {
218
0
        gnutls_assert();
219
0
        ret = GNUTLS_E_SRP_PWD_ERROR;
220
0
        goto cleanup;
221
0
      }
222
0
      ret = 0;
223
0
      goto cleanup;
224
0
    }
225
0
  }
226
227
  /* user was not found. Fake him. 
228
   */
229
0
  ret = _randomize_psk(psk);
230
0
  if (ret < 0) {
231
0
    goto cleanup;
232
0
  }
233
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
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
       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
  } else if (cred->get_function != NULL) {
264
0
    ret = cred->get_function(session, username, key);
265
266
0
    if (ret)
267
0
      return gnutls_assert_val(ret);
268
269
0
    *free = 1;
270
0
  } else
271
0
    return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
272
273
0
  return 0;
274
0
}