From 8f0b1e24e2887713bdcbf35b08902e9555ee7b92 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 18 May 2015 14:08:24 +0200 Subject: 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 Reviewed-by: Simon Glass --- common/Kconfig | 20 +++++++-- common/autoboot.c | 119 +++++++++++++++++++++++++++++++++++++++++++++--------- common/hash.c | 30 +++++++++----- include/hash.h | 14 +++++++ 4 files changed, 152 insertions(+), 31 deletions(-) diff --git a/common/Kconfig b/common/Kconfig index 6b5d166429..f6478fad0b 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -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" diff --git a/common/autoboot.c b/common/autoboot.c index f72eb1860c..c367076257 100644 --- a/common/autoboot.c +++ b/common/autoboot.c @@ -12,6 +12,7 @@ #include #include #include +#include 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"); diff --git a/common/hash.c b/common/hash.c index c94c98be9e..a1b048204d 100644 --- a/common/hash.c +++ b/common/hash.c @@ -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; } diff --git a/include/hash.h b/include/hash.h index f4eb100de0..e6d0f1db92 100644 --- a/include/hash.h +++ b/include/hash.h @@ -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 -- cgit