Coverage Report

Created: 2026-10-13 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/barebox/security/password.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
 * Copyright (c) 2008-2010 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
4
 */
5
6
#include <common.h>
7
#include <password.h>
8
#include <errno.h>
9
#include <readkey.h>
10
#include <fs.h>
11
#include <fcntl.h>
12
#include <digest.h>
13
#include <malloc.h>
14
#include <xfuncs.h>
15
#include <command.h>
16
#include <magicvar.h>
17
#include <clock.h>
18
#include <init.h>
19
#include <stdlib.h>
20
#include <globalvar.h>
21
#include <crypto.h>
22
#include <generated/passwd.h>
23
#include <crypto/pbkdf2.h>
24
25
#if defined(CONFIG_PASSWD_SUM_MD5)
26
#define PASSWD_SUM "md5"
27
#elif defined(CONFIG_PASSWD_SUM_SHA1)
28
#define PASSWD_SUM "sha1"
29
#elif defined(CONFIG_PASSWD_SUM_SHA256)
30
#define PASSWD_SUM "sha256"
31
#elif defined(CONFIG_PASSWD_SUM_SHA512)
32
#define PASSWD_SUM "sha512"
33
#else
34
0
#define PASSWD_SUM  NULL
35
#endif
36
37
0
#define PBKDF2_SALT_LEN 32
38
0
#define PBKDF2_LENGTH 64
39
0
#define PBKDF2_COUNT  10000
40
41
int password(unsigned char *passwd, size_t length, int flags, int timeout)
42
0
{
43
0
  unsigned char *buf = passwd;
44
0
  int pos = 0;
45
0
  unsigned char ch;
46
0
  uint64_t start;
47
48
0
  if (!passwd)
49
0
    return -EINVAL;
50
51
0
  start = get_time_ns();
52
53
0
  do {
54
0
    if (tstc()) {
55
0
      ch = getchar();
56
57
0
      switch (ch) {
58
0
      case '\r':
59
0
      case '\n':
60
0
        *buf = '\0';
61
0
        puts("\r\n");
62
0
        return pos;
63
0
      case '\0':
64
0
      case '\t':
65
0
        continue;
66
0
      case CTL_CH('c'):
67
0
        passwd[0] = '\0';
68
0
        puts("\r\n");
69
0
        return -EINTR;
70
0
      case CTL_CH('h'):
71
0
      case BB_KEY_DEL7:
72
0
      case BB_KEY_DEL:
73
0
        if (pos > 0) {
74
0
          if (flags & STAR)
75
0
            puts("\b \b");
76
77
0
          *buf = '\0';
78
0
          buf--;
79
0
          pos--;
80
0
        }
81
0
        continue;
82
0
      default:
83
0
        if (pos < length - 1) {
84
0
          if (flags & STAR)
85
0
            putchar('*');
86
0
          else if (flags & CLEAR)
87
0
            putchar(ch);
88
89
0
          *buf = ch;
90
0
          buf++;
91
0
          pos++;
92
0
        } else {
93
0
          if (flags & STAR)
94
0
            putchar('\a');
95
0
        }
96
0
      }
97
0
    }
98
0
  } while (!is_timeout(start, timeout * SECOND) || timeout == 0);
99
100
0
  return -ETIMEDOUT;
101
0
}
102
EXPORT_SYMBOL(password);
103
104
static int is_passwd_default_enable(void)
105
0
{
106
0
  return strlen(default_passwd) > 0;
107
0
}
108
109
static int is_passwd_env_enable(void)
110
0
{
111
0
  int fd;
112
113
0
  fd = open(PASSWD_FILE, O_RDONLY);
114
115
0
  if (fd < 0)
116
0
    return 0;
117
118
0
  close(fd);
119
120
0
  return 1;
121
0
}
122
123
int passwd_env_disable(void)
124
0
{
125
0
  return unlink(PASSWD_FILE);
126
0
}
127
EXPORT_SYMBOL(passwd_env_disable);
128
129
static unsigned char to_digit(unsigned char c)
130
0
{
131
0
  if (c >= '0' && c <= '9')
132
0
    c -= '0';
133
0
  else
134
0
    c -= 'a' - 10;
135
136
0
  return c;
137
0
}
138
139
static unsigned char to_hexa(unsigned char c)
140
0
{
141
0
  if (c < 10)
142
0
    c += '0';
143
0
  else
144
0
    c += 'a' - 10;
145
146
0
  return c;
147
0
}
148
149
static int read_default_passwd(unsigned char *sum, size_t length)
150
0
{
151
0
  int len, i = 0;
152
0
  unsigned char *buf = (unsigned char *)default_passwd;
153
0
  unsigned char c;
154
155
0
  if (ARRAY_SIZE(default_passwd) == 1)
156
0
    return -ENOSYS;
157
158
0
  if (!sum || length < 1)
159
0
    return -EINVAL;
160
161
0
  len = strlen(default_passwd);
162
0
  for (i = 0; i < len && length > 0; i++) {
163
0
    c = buf[i];
164
0
    i++;
165
166
0
    *sum = to_digit(c) << 4;
167
168
0
    c = buf[i];
169
170
0
    *sum |= to_digit(c);
171
0
    sum++;
172
0
    length--;
173
0
  }
174
175
0
  return 0;
176
0
}
177
178
static int read_env_passwd(unsigned char *sum, size_t length)
179
0
{
180
0
  int fd;
181
0
  int ret = 0;
182
0
  unsigned char c;
183
184
0
  if (!sum && length < 1)
185
0
    return -EINVAL;
186
187
0
  fd = open(PASSWD_FILE, O_RDONLY);
188
189
0
  if (fd < 0)
190
0
    return fd;
191
192
0
  do {
193
0
    ret = read(fd, &c, sizeof(char));
194
195
0
    if (ret < 0)
196
0
      goto exit;
197
198
0
    *sum = to_digit(c) << 4;
199
200
0
    ret = read(fd, &c, sizeof(char));
201
202
0
    if (ret < 0)
203
0
      goto exit;
204
205
0
    *sum |= to_digit(c);
206
0
    sum++;
207
0
    length--;
208
0
  } while(length > 0);
209
210
0
exit:
211
212
0
  ret = 0;
213
214
0
  close(fd);
215
216
0
  return ret;
217
0
}
218
EXPORT_SYMBOL(read_env_passwd);
219
220
static int write_env_passwd(unsigned char *sum, size_t length)
221
0
{
222
0
  int fd;
223
0
  unsigned char c;
224
0
  int ret = 0;
225
226
0
  if (!sum && length < 1)
227
0
    return -EINVAL;
228
229
0
  fd = open(PASSWD_DIR, O_RDONLY);
230
231
0
  if (fd < 0)
232
0
    mkdir(PASSWD_DIR, 644);
233
234
0
  close(fd);
235
236
0
  fd = open(PASSWD_FILE, O_WRONLY | O_CREAT, 600);
237
238
0
  if (fd < 0)
239
0
    return fd;
240
241
0
  do {
242
0
    c = to_hexa(*sum >> 4 & 0xf);
243
244
0
    ret = write(fd, &c, sizeof(unsigned char));
245
246
0
    if (ret < 0)
247
0
      goto exit;
248
249
0
    c = to_hexa(*sum & 0xf);
250
251
0
    ret = write(fd, &c, sizeof(unsigned char));
252
253
0
    if (ret < 0)
254
0
      goto exit;
255
256
0
    sum++;
257
0
    length--;
258
0
  } while(length > 0);
259
260
0
  ret = 0;
261
262
0
exit:
263
0
  close(fd);
264
265
0
  return ret;
266
0
}
267
268
static int check_passwd(unsigned char *passwd, size_t length)
269
0
{
270
0
  struct digest *d = NULL;
271
0
  unsigned char *passwd1_sum;
272
0
  unsigned char *passwd2_sum;
273
0
  int ret = 0;
274
0
  int hash_len;
275
276
0
  if (IS_ENABLED(CONFIG_PASSWD_CRYPTO_PBKDF2)) {
277
0
    hash_len = PBKDF2_LENGTH;
278
0
  } else {
279
0
    d = digest_alloc(PASSWD_SUM);
280
0
    if (!d) {
281
0
      pr_err("No such digest: %s\n",
282
0
             PASSWD_SUM ? PASSWD_SUM : "NULL");
283
0
      return -ENOENT;
284
0
    }
285
286
0
    hash_len = digest_length(d);
287
0
  }
288
289
0
  passwd1_sum = calloc(hash_len * 2, sizeof(unsigned char));
290
0
  if (!passwd1_sum)
291
0
    return -ENOMEM;
292
293
0
  passwd2_sum = passwd1_sum + hash_len;
294
295
0
  if (is_passwd_env_enable())
296
0
    ret = read_env_passwd(passwd2_sum, hash_len);
297
0
  else if (is_passwd_default_enable())
298
0
    ret = read_default_passwd(passwd2_sum, hash_len);
299
0
  else
300
0
    ret = -EINVAL;
301
302
0
  if (ret < 0)
303
0
    goto err;
304
305
0
  if (IS_ENABLED(CONFIG_PASSWD_CRYPTO_PBKDF2)) {
306
0
    char *key = passwd2_sum + PBKDF2_SALT_LEN;
307
0
    char *salt = passwd2_sum;
308
0
    int keylen = PBKDF2_LENGTH - PBKDF2_SALT_LEN;
309
310
0
    ret = pkcs5_pbkdf2_hmac_sha1(passwd, length, salt,
311
0
      PBKDF2_SALT_LEN, PBKDF2_COUNT, keylen, passwd1_sum);
312
0
    if (ret)
313
0
      goto err;
314
315
0
    if (!crypto_memneq(passwd1_sum, key, keylen))
316
0
      ret = 1;
317
0
  } else {
318
0
    ret = digest_digest(d, passwd, length, passwd1_sum);
319
320
0
    if (ret)
321
0
      goto err;
322
323
0
    if (!crypto_memneq(passwd1_sum, passwd2_sum, hash_len))
324
0
      ret = 1;
325
0
  }
326
327
0
err:
328
0
  free(passwd1_sum);
329
0
  digest_free(d);
330
331
0
  return ret;
332
0
}
333
334
int set_env_passwd(unsigned char* passwd, size_t length)
335
0
{
336
0
  struct digest *d = NULL;
337
0
  unsigned char *passwd_sum;
338
0
  int ret, hash_len;
339
340
0
  if (IS_ENABLED(CONFIG_PASSWD_CRYPTO_PBKDF2)) {
341
0
    hash_len = PBKDF2_LENGTH;
342
0
  } else {
343
0
    d = digest_alloc(PASSWD_SUM);
344
0
    if (!d)
345
0
      return -EINVAL;
346
347
0
    hash_len = digest_length(d);
348
0
  }
349
350
0
  passwd_sum = calloc(hash_len, sizeof(unsigned char));
351
0
  if (!passwd_sum)
352
0
    return -ENOMEM;
353
354
0
  if (IS_ENABLED(CONFIG_PASSWD_CRYPTO_PBKDF2)) {
355
0
    char *key = passwd_sum + PBKDF2_SALT_LEN;
356
0
    char *salt = passwd_sum;
357
0
    int keylen = PBKDF2_LENGTH - PBKDF2_SALT_LEN;
358
359
0
    ret = get_crypto_bytes(passwd_sum, PBKDF2_SALT_LEN);
360
0
    if (ret) {
361
0
      pr_err("Can't get random numbers\n");
362
0
      return ret;
363
0
    }
364
365
0
    ret = pkcs5_pbkdf2_hmac_sha1(passwd, length, salt,
366
0
        PBKDF2_SALT_LEN, PBKDF2_COUNT, keylen, key);
367
0
  } else {
368
0
    ret = digest_digest(d, passwd, length, passwd_sum);
369
0
  }
370
0
  if (ret)
371
0
    goto err;
372
373
0
  ret = write_env_passwd(passwd_sum, hash_len);
374
375
0
err:
376
0
  digest_free(d);
377
0
  free(passwd_sum);
378
379
0
  return ret;
380
0
}
381
EXPORT_SYMBOL(set_env_passwd);
382
383
0
#define PASSWD_MAX_LENGTH (128 + 1)
384
385
#if defined(CONFIG_PASSWD_MODE_STAR)
386
#define LOGIN_MODE STAR
387
#elif defined(CONFIG_PASSWD_MODE_CLEAR)
388
#define LOGIN_MODE CLEAR
389
#else
390
0
#define LOGIN_MODE HIDE
391
#endif
392
393
static int logged_in;
394
static int login_timeout = 60;
395
static char *login_fail_command;
396
397
/**
398
 * login() - Prompt for password
399
 *
400
 * This function only returns when the correct password has been entered or
401
 * no password is necessary because either no password is configured or the
402
 * correct password has been entered in a previous call to this function.
403
 */
404
void login(void)
405
0
{
406
0
  unsigned char passwd[PASSWD_MAX_LENGTH];
407
0
  int ret;
408
409
0
  if (!is_passwd_default_enable() && !is_passwd_env_enable())
410
0
    return;
411
412
0
  if (logged_in)
413
0
    return;
414
415
0
  while (1) {
416
0
    printf("Password: ");
417
418
0
    ret = password(passwd, PASSWD_MAX_LENGTH, LOGIN_MODE, login_timeout);
419
0
    if (ret < 0)
420
0
      run_command("%s", login_fail_command);
421
422
0
    if (ret < 0)
423
0
      continue;
424
425
0
    if (check_passwd(passwd, ret) != 1)
426
0
      continue;
427
428
0
    logged_in = 1;
429
0
    return;
430
0
  }
431
0
}
432
433
static int login_global_init(void)
434
26
{
435
26
  login_fail_command = xstrdup("boot");
436
437
26
  globalvar_add_simple_int("login.timeout", &login_timeout, "%d");
438
26
  globalvar_add_simple_string("login.fail_command", &login_fail_command);
439
440
26
  return 0;
441
26
}
442
late_initcall(login_global_init);
443
444
BAREBOX_MAGICVAR(global.login.fail_command,
445
    "command to run when password entry failed");
446
BAREBOX_MAGICVAR(global.login.timeout,
447
    "timeout to type the password");