autoboot.c: Add feature to stop autobooting via SHA256 encrypted password

This patch adds the feature to only stop the autobooting, and therefor
boot into the U-Boot prompt, when the input string / password matches
a values that is encypted via a SHA256 hash and saved in the environment.

This feature is enabled by defined these config options:
     CONFIG_AUTOBOOT_KEYED
     CONFIG_AUTOBOOT_STOP_STR_SHA256

Signed-off-by: Stefan Roese <sr@denx.de>
Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Stefan Roese 2015-05-18 14:08:24 +02:00 committed by Tom Rini
parent d126e01649
commit 8f0b1e24e2
4 changed files with 152 additions and 31 deletions

View file

@ -45,9 +45,14 @@ config AUTOBOOT_PROMPT
the responsibility of the user to select only such arguments
that are valid in the given context.
config AUTOBOOT_ENCRYPTION
bool "Enable encryption in autoboot stopping"
depends on AUTOBOOT_KEYED
default n
config AUTOBOOT_DELAY_STR
string "Delay autobooting via specific input key / string"
depends on AUTOBOOT_KEYED
depends on AUTOBOOT_KEYED && !AUTOBOOT_ENCRYPTION
help
This option delays the automatic boot feature by issuing
a specific input key or string. If CONFIG_AUTOBOOT_DELAY_STR
@ -59,7 +64,7 @@ config AUTOBOOT_DELAY_STR
config AUTOBOOT_STOP_STR
string "Stop autobooting via specific input key / string"
depends on AUTOBOOT_KEYED
depends on AUTOBOOT_KEYED && !AUTOBOOT_ENCRYPTION
help
This option enables stopping (aborting) of the automatic
boot feature only by issuing a specific input key or
@ -71,7 +76,7 @@ config AUTOBOOT_STOP_STR
config AUTOBOOT_KEYED_CTRLC
bool "Enable Ctrl-C autoboot interruption"
depends on AUTOBOOT_KEYED
depends on AUTOBOOT_KEYED && !AUTOBOOT_ENCRYPTION
default n
help
This option allows for the boot sequence to be interrupted
@ -79,6 +84,15 @@ config AUTOBOOT_KEYED_CTRLC
Setting this variable provides an escape sequence from the
limited "password" strings.
config AUTOBOOT_STOP_STR_SHA256
string "Stop autobooting via SHA256 encrypted password"
depends on AUTOBOOT_KEYED && AUTOBOOT_ENCRYPTION
help
This option adds the feature to only stop the autobooting,
and therefore boot into the U-Boot prompt, when the input
string / password matches a values that is encypted via
a SHA256 hash and saved in the environment.
endmenu
comment "Commands"

View file

@ -12,6 +12,7 @@
#include <fdtdec.h>
#include <menu.h>
#include <post.h>
#include <u-boot/sha256.h>
DECLARE_GLOBAL_DATA_PTR;
@ -26,15 +27,81 @@ DECLARE_GLOBAL_DATA_PTR;
/* Stored value of bootdelay, used by autoboot_command() */
static int stored_bootdelay;
/***************************************************************************
* Watch for 'delay' seconds for autoboot stop or autoboot delay string.
* returns: 0 - no key string, allow autoboot 1 - got key string, abort
#if defined(CONFIG_AUTOBOOT_KEYED)
#if defined(CONFIG_AUTOBOOT_STOP_STR_SHA256)
/*
* Use a "constant-length" time compare function for this
* hash compare:
*
* https://crackstation.net/hashing-security.htm
*/
# if defined(CONFIG_AUTOBOOT_KEYED)
static int abortboot_keyed(int bootdelay)
static int slow_equals(u8 *a, u8 *b, int len)
{
int diff = 0;
int i;
for (i = 0; i < len; i++)
diff |= a[i] ^ b[i];
return diff == 0;
}
static int passwd_abort(uint64_t etime)
{
const char *sha_env_str = getenv("bootstopkeysha256");
u8 sha_env[SHA256_SUM_LEN];
u8 sha[SHA256_SUM_LEN];
char presskey[MAX_DELAY_STOP_STR];
const char *algo_name = "sha256";
u_int presskey_len = 0;
int abort = 0;
int size;
int ret;
if (sha_env_str == NULL)
sha_env_str = CONFIG_AUTOBOOT_STOP_STR_SHA256;
/*
* Generate the binary value from the environment hash value
* so that we can compare this value with the computed hash
* from the user input
*/
ret = hash_parse_string(algo_name, sha_env_str, sha_env);
if (ret) {
printf("Hash %s not supported!\n", algo_name);
return 0;
}
/*
* We don't know how long the stop-string is, so we need to
* generate the sha256 hash upon each input character and
* compare the value with the one saved in the environment
*/
do {
if (tstc()) {
/* Check for input string overflow */
if (presskey_len >= MAX_DELAY_STOP_STR)
return 0;
presskey[presskey_len++] = getc();
/* Calculate sha256 upon each new char */
hash_block(algo_name, (const void *)presskey,
presskey_len, sha, &size);
/* And check if sha matches saved value in env */
if (slow_equals(sha, sha_env, SHA256_SUM_LEN))
abort = 1;
}
} while (!abort && get_ticks() <= etime);
return abort;
}
#else
static int passwd_abort(uint64_t etime)
{
int abort = 0;
uint64_t etime = endtick(bootdelay);
struct {
char *str;
u_int len;
@ -50,19 +117,6 @@ static int abortboot_keyed(int bootdelay)
u_int presskey_max = 0;
u_int i;
#ifndef CONFIG_ZERO_BOOTDELAY_CHECK
if (bootdelay == 0)
return 0;
#endif
# ifdef CONFIG_AUTOBOOT_PROMPT
/*
* CONFIG_AUTOBOOT_PROMPT includes the %d for all boards.
* To print the bootdelay value upon bootup.
*/
printf(CONFIG_AUTOBOOT_PROMPT, bootdelay);
# endif
# ifdef CONFIG_AUTOBOOT_DELAY_STR
if (delaykey[0].str == NULL)
delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
@ -119,6 +173,33 @@ static int abortboot_keyed(int bootdelay)
}
} while (!abort && get_ticks() <= etime);
return abort;
}
#endif
/***************************************************************************
* Watch for 'delay' seconds for autoboot stop or autoboot delay string.
* returns: 0 - no key string, allow autoboot 1 - got key string, abort
*/
static int abortboot_keyed(int bootdelay)
{
int abort;
uint64_t etime = endtick(bootdelay);
#ifndef CONFIG_ZERO_BOOTDELAY_CHECK
if (bootdelay == 0)
return 0;
#endif
# ifdef CONFIG_AUTOBOOT_PROMPT
/*
* CONFIG_AUTOBOOT_PROMPT includes the %d for all boards.
* To print the bootdelay value upon bootup.
*/
printf(CONFIG_AUTOBOOT_PROMPT, bootdelay);
# endif
abort = passwd_abort(etime);
if (!abort)
debug_bootkeys("key timeout\n");

View file

@ -227,6 +227,26 @@ int hash_progressive_lookup_algo(const char *algo_name,
}
#ifndef USE_HOSTCC
int hash_parse_string(const char *algo_name, const char *str, uint8_t *result)
{
struct hash_algo *algo;
int ret;
int i;
ret = hash_lookup_algo(algo_name, &algo);
if (ret)
return ret;
for (i = 0; i < algo->digest_size; i++) {
char chr[3];
strncpy(chr, &str[i * 2], 2);
result[i] = simple_strtoul(chr, NULL, 16);
}
return 0;
}
/**
* store_result: Store the resulting sum to an address or variable
*
@ -315,7 +335,6 @@ static int parse_verify_sum(struct hash_algo *algo, char *verify_str,
buf = map_sysmem(addr, algo->digest_size);
memcpy(vsum, buf, algo->digest_size);
} else {
unsigned int i;
char *vsum_str;
int digits = algo->digest_size * 2;
@ -335,14 +354,7 @@ static int parse_verify_sum(struct hash_algo *algo, char *verify_str,
}
}
for (i = 0; i < algo->digest_size; i++) {
char *nullp = vsum_str + (i + 1) * 2;
char end = *nullp;
*nullp = '\0';
vsum[i] = simple_strtoul(vsum_str + (i * 2), NULL, 16);
*nullp = end;
}
hash_parse_string(algo->name, vsum_str, vsum);
}
return 0;
}

View file

@ -158,4 +158,18 @@ int hash_lookup_algo(const char *algo_name, struct hash_algo **algop);
int hash_progressive_lookup_algo(const char *algo_name,
struct hash_algo **algop);
/**
* hash_parse_string() - Parse hash string into a binary array
*
* The function parses a hash string into a binary array that
* can for example easily be used to compare to hash values.
*
* @algo_name: Hash algorithm to look up
* @str: Hash string to get parsed
* @result: Binary array of the parsed hash string
*
* @return 0 if ok, -EPROTONOSUPPORT for an unknown algorithm.
*/
int hash_parse_string(const char *algo_name, const char *str, uint8_t *result);
#endif