diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/Kconfig.boot | 65 | ||||
-rw-r--r-- | common/autoboot.c | 136 | ||||
-rw-r--r-- | common/console.c | 5 |
3 files changed, 184 insertions, 22 deletions
diff --git a/common/Kconfig.boot b/common/Kconfig.boot index b4dc49e0195..642dd9bcfbe 100644 --- a/common/Kconfig.boot +++ b/common/Kconfig.boot @@ -791,6 +791,15 @@ config AUTOBOOT_KEYED U-Boot automatic booting process and bring the device to the U-Boot prompt for user input. +config AUTOBOOT_FLUSH_STDIN + bool "Enable flushing stdin before starting to read the password" + depends on AUTOBOOT_KEYED && !SANDBOX + help + When this option is enabled stdin buffer will be flushed before + starting to read the password. + This can't be enabled for the sandbox as flushing stdin would + break the autoboot unit tests. + config AUTOBOOT_PROMPT string "Autoboot stop prompt" depends on AUTOBOOT_KEYED @@ -812,13 +821,28 @@ config AUTOBOOT_ENCRYPTION depends on AUTOBOOT_KEYED help This option allows a string to be entered into U-Boot to stop the - autoboot. The string itself is hashed and compared against the hash - in the environment variable 'bootstopkeysha256'. If it matches then - boot stops and a command-line prompt is presented. - + autoboot. + The behavior depends whether CONFIG_CRYPT_PW from lib is enabled + or not. + In case CONFIG_CRYPT_PW is enabled, the string will be forwarded + to the crypt-based functionality and be compared against the + string in the environment variable 'bootstopkeycrypt'. + In case CONFIG_CRYPT_PW is disabled the string itself is hashed + and compared against the hash in the environment variable + 'bootstopkeysha256'. + If it matches in either case then boot stops and + a command-line prompt is presented. This provides a way to ship a secure production device which can also be accessed at the U-Boot command line. +config AUTOBOOT_SHA256_FALLBACK + bool "Allow fallback from crypt-hashed password to sha256" + depends on AUTOBOOT_ENCRYPTION && CRYPT_PW + help + This option adds support to fall back from crypt-hashed + passwords to checking a SHA256 hashed password in case the + 'bootstopusesha256' environment variable is set to 'true'. + config AUTOBOOT_DELAY_STR string "Delay autobooting via specific input key / string" depends on AUTOBOOT_KEYED && !AUTOBOOT_ENCRYPTION @@ -853,10 +877,39 @@ 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" +config AUTOBOOT_NEVER_TIMEOUT + bool "Make the password entry never time-out" + depends on AUTOBOOT_KEYED && AUTOBOOT_ENCRYPTION && CRYPT_PW + help + This option removes the timeout from the password entry + when the user first presses the <Enter> key before entering + any other character. + +config AUTOBOOT_STOP_STR_ENABLE + bool "Enable fixed string to stop autobooting" depends on AUTOBOOT_KEYED && AUTOBOOT_ENCRYPTION help + This option enables the feature to add a fixed stop + string that is defined at compile time. + In every case it will be tried to load the stop + string from the environment. + In case this is enabled and there is no stop string + in the environment, this will be used as default value. + +config AUTOBOOT_STOP_STR_CRYPT + string "Stop autobooting via crypt-hashed password" + depends on AUTOBOOT_STOP_STR_ENABLE && CRYPT_PW + 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 hashed via + one of the supported crypt-style password hashing options + and saved in the environment variable "bootstopkeycrypt". + +config AUTOBOOT_STOP_STR_SHA256 + string "Stop autobooting via SHA256 hashed password" + depends on AUTOBOOT_STOP_STR_ENABLE + 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 diff --git a/common/autoboot.c b/common/autoboot.c index b42148c7291..8b9e9aa8785 100644 --- a/common/autoboot.c +++ b/common/autoboot.c @@ -23,10 +23,11 @@ #include <linux/delay.h> #include <u-boot/sha256.h> #include <bootcount.h> +#include <crypt.h> DECLARE_GLOBAL_DATA_PTR; -#define MAX_DELAY_STOP_STR 64 +#define DELAY_STOP_STR_MAX_LENGTH 64 #ifndef DEBUG_BOOTKEYS #define DEBUG_BOOTKEYS 0 @@ -38,10 +39,11 @@ DECLARE_GLOBAL_DATA_PTR; static int stored_bootdelay; static int menukey; -#ifdef CONFIG_AUTOBOOT_ENCRYPTION -#define AUTOBOOT_STOP_STR_SHA256 CONFIG_AUTOBOOT_STOP_STR_SHA256 -#else -#define AUTOBOOT_STOP_STR_SHA256 "" +#if !defined(CONFIG_AUTOBOOT_STOP_STR_CRYPT) +#define CONFIG_AUTOBOOT_STOP_STR_CRYPT "" +#endif +#if !defined(CONFIG_AUTOBOOT_STOP_STR_SHA256) +#define CONFIG_AUTOBOOT_STOP_STR_SHA256 "" #endif #ifdef CONFIG_AUTOBOOT_USE_MENUKEY @@ -50,6 +52,73 @@ static int menukey; #define AUTOBOOT_MENUKEY 0 #endif +/** + * passwd_abort_crypt() - check for a crypt-style hashed key sequence to abort booting + * + * This checks for the user entering a password within a given time. + * + * The entered password is hashed via one of the crypt-style hash methods + * and compared to the pre-defined value from either + * the environment variable "bootstopkeycrypt" + * or + * the config value CONFIG_AUTOBOOT_STOP_STR_CRYPT + * + * In case the config value CONFIG_AUTOBOOT_NEVER_TIMEOUT has been enabled + * this function never times out if the user presses the <Enter> key + * before starting to enter the password. + * + * @etime: Timeout value ticks (stop when get_ticks() reachs this) + * @return 0 if autoboot should continue, 1 if it should stop + */ +static int passwd_abort_crypt(uint64_t etime) +{ + const char *crypt_env_str = env_get("bootstopkeycrypt"); + char presskey[DELAY_STOP_STR_MAX_LENGTH]; + u_int presskey_len = 0; + int abort = 0; + int never_timeout = 0; + int err; + + if (IS_ENABLED(CONFIG_AUTOBOOT_STOP_STR_ENABLE) && !crypt_env_str) + crypt_env_str = CONFIG_AUTOBOOT_STOP_STR_CRYPT; + + if (!crypt_env_str) + return 0; + + /* We expect the stop-string to be newline-terminated */ + do { + if (tstc()) { + /* Check for input string overflow */ + if (presskey_len >= sizeof(presskey)) + return 0; + + presskey[presskey_len] = getchar(); + + if ((presskey[presskey_len] == '\r') || + (presskey[presskey_len] == '\n')) { + if (IS_ENABLED(CONFIG_AUTOBOOT_NEVER_TIMEOUT) && + !presskey_len) { + never_timeout = 1; + continue; + } + presskey[presskey_len] = '\0'; + err = crypt_compare(crypt_env_str, presskey, + &abort); + if (err) + debug_bootkeys( + "crypt_compare() failed with: %s\n", + errno_str(err)); + /* you had one chance */ + break; + } else { + presskey_len++; + } + } + } while (never_timeout || get_ticks() <= etime); + + return abort; +} + /* * Use a "constant-length" time compare function for this * hash compare: @@ -89,11 +158,11 @@ static int passwd_abort_sha256(uint64_t etime) int ret; if (sha_env_str == NULL) - sha_env_str = AUTOBOOT_STOP_STR_SHA256; + sha_env_str = CONFIG_AUTOBOOT_STOP_STR_SHA256; - presskey = malloc_cache_aligned(MAX_DELAY_STOP_STR); + presskey = malloc_cache_aligned(DELAY_STOP_STR_MAX_LENGTH); c = strstr(sha_env_str, ":"); - if (c && (c - sha_env_str < MAX_DELAY_STOP_STR)) { + if (c && (c - sha_env_str < DELAY_STOP_STR_MAX_LENGTH)) { /* preload presskey with salt */ memcpy(presskey, sha_env_str, c - sha_env_str); presskey_len = c - sha_env_str; @@ -120,7 +189,7 @@ static int passwd_abort_sha256(uint64_t etime) do { if (tstc()) { /* Check for input string overflow */ - if (presskey_len >= MAX_DELAY_STOP_STR) { + if (presskey_len >= DELAY_STOP_STR_MAX_LENGTH) { free(presskey); free(sha); return 0; @@ -164,7 +233,7 @@ static int passwd_abort_key(uint64_t etime) { .str = env_get("bootstopkey"), .retry = 0 }, }; - char presskey[MAX_DELAY_STOP_STR]; + char presskey[DELAY_STOP_STR_MAX_LENGTH]; int presskey_len = 0; int presskey_max = 0; int i; @@ -181,8 +250,8 @@ static int passwd_abort_key(uint64_t etime) for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) { delaykey[i].len = delaykey[i].str == NULL ? 0 : strlen(delaykey[i].str); - delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ? - MAX_DELAY_STOP_STR : delaykey[i].len; + delaykey[i].len = delaykey[i].len > DELAY_STOP_STR_MAX_LENGTH ? + DELAY_STOP_STR_MAX_LENGTH : delaykey[i].len; presskey_max = presskey_max > delaykey[i].len ? presskey_max : delaykey[i].len; @@ -228,6 +297,35 @@ static int passwd_abort_key(uint64_t etime) return abort; } +/** + * flush_stdin() - drops all pending characters from stdin + */ +static void flush_stdin(void) +{ + while (tstc()) + (void)getchar(); +} + +/** + * fallback_to_sha256() - check whether we should fall back to sha256 + * password checking + * + * This checks for the environment variable `bootstopusesha256` in case + * sha256-fallback has been enabled via the config setting + * `AUTOBOOT_SHA256_FALLBACK`. + * + * @return `false` if we must not fall-back, `true` if plain sha256 should be tried + */ +static bool fallback_to_sha256(void) +{ + if (IS_ENABLED(CONFIG_AUTOBOOT_SHA256_FALLBACK)) + return env_get_yesno("bootstopusesha256") == 1; + else if (IS_ENABLED(CONFIG_CRYPT_PW)) + return false; + else + return true; +} + /*************************************************************************** * Watch for 'delay' seconds for autoboot stop or autoboot delay string. * returns: 0 - no key string, allow autoboot 1 - got key string, abort @@ -237,6 +335,8 @@ static int abortboot_key_sequence(int bootdelay) int abort; uint64_t etime = endtick(bootdelay); + if (IS_ENABLED(CONFIG_AUTOBOOT_FLUSH_STDIN)) + flush_stdin(); # ifdef CONFIG_AUTOBOOT_PROMPT /* * CONFIG_AUTOBOOT_PROMPT includes the %d for all boards. @@ -245,10 +345,14 @@ static int abortboot_key_sequence(int bootdelay) printf(CONFIG_AUTOBOOT_PROMPT, bootdelay); # endif - if (IS_ENABLED(CONFIG_AUTOBOOT_ENCRYPTION)) - abort = passwd_abort_sha256(etime); - else + if (IS_ENABLED(CONFIG_AUTOBOOT_ENCRYPTION)) { + if (IS_ENABLED(CONFIG_CRYPT_PW) && !fallback_to_sha256()) + abort = passwd_abort_crypt(etime); + else + abort = passwd_abort_sha256(etime); + } else { abort = passwd_abort_key(etime); + } if (!abort) debug_bootkeys("key timeout\n"); @@ -394,4 +498,4 @@ void autoboot_command(const char *s) if (s) run_command_list(s, -1, 0); } -} +}
\ No newline at end of file diff --git a/common/console.c b/common/console.c index 73edb287992..0013d183aeb 100644 --- a/common/console.c +++ b/common/console.c @@ -773,6 +773,11 @@ int console_record_avail(void) return membuff_avail((struct membuff *)&gd->console_out); } +int console_in_puts(const char *str) +{ + return membuff_put((struct membuff *)&gd->console_in, str, strlen(str)); +} + #endif /* test if ctrl-c was pressed */ |