mirror of
https://github.com/apache/nuttx.git
synced 2026-08-01 20:28:58 +00:00
!boards: enforce secure ROMFS passwd and TEA key setup
Remove implicit default credentials and add build-time validation. Add check_passwd_keys.sh and gen_passwd_keys.sh; run key setup via passwd_keys.mk before config.h is generated. Mirror the same logic in cmake/nuttx_add_romfs.cmake for CMake builds. BREAKING CHANGE: Builds with CONFIG_BOARD_ETC_ROMFS_PASSWD_ENABLE=y now require an explicit admin password and non-default TEA keys. The Kconfig default password "Administrator" and default TEA keys are no longer accepted. Fix: run make menuconfig, set Admin password under Board Selection -> Auto-generate /etc/passwd, enable random TEA keys or set CONFIG_FSUTILS_PASSWD_KEY1..4 manually, and use NSH login with Encrypted password file verification. Signed-off-by: Abhishek Mishra <mishra.abhishek2808@gmail.com>
This commit is contained in:
parent
a38fd1603c
commit
ffa6ba222f
9 changed files with 449 additions and 135 deletions
|
|
@ -17,107 +17,77 @@ and host C programs that are important parts of the NuttX build system:
|
|||
mkpasswd — Build-time ``/etc/passwd`` Generation
|
||||
-------------------------------------------------
|
||||
|
||||
``tools/mkpasswd`` is a C host tool (compiled from ``tools/mkpasswd.c``) that
|
||||
generates a single ``/etc/passwd`` entry at build time. It is invoked
|
||||
automatically by the ROMFS build step when
|
||||
``CONFIG_BOARD_ETC_ROMFS_PASSWD_ENABLE=y`` is set.
|
||||
``tools/mkpasswd`` is a host tool (``tools/mkpasswd.c``) that generates a
|
||||
single ``/etc/passwd`` entry at build time. It runs automatically when
|
||||
``CONFIG_BOARD_ETC_ROMFS_PASSWD_ENABLE=y``.
|
||||
|
||||
Why build-time generation?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The plaintext password is hashed with TEA and is not stored in the firmware.
|
||||
The build fails if the password is empty or uses known insecure defaults.
|
||||
|
||||
Shipping a hard-coded default password in firmware is a well-known security
|
||||
weakness (CWE-798). By generating the ``/etc/passwd`` entry from a
|
||||
user-supplied plaintext password at build time, each firmware image carries
|
||||
unique credentials. The build will fail if the password is left empty,
|
||||
preventing accidental deployments with no credentials.
|
||||
Setup
|
||||
~~~~~
|
||||
|
||||
For improved baseline security, the configured password must be at least
|
||||
8 characters long.
|
||||
1. Run ``make menuconfig`` and configure:
|
||||
|
||||
How it works
|
||||
~~~~~~~~~~~~
|
||||
* **Board Selection** → Auto-generate /etc/passwd at build time
|
||||
* Set the admin password (required, minimum 8 characters)
|
||||
* Enable random TEA key generation, or set keys manually (see below)
|
||||
* **Application Configuration** → NSH Library → Console Login
|
||||
* Set verification method to **Encrypted password file**
|
||||
* **Application Configuration** → File System Utilities → Password file support
|
||||
* Enable password file support
|
||||
|
||||
1. The host tool reads the plaintext password from
|
||||
``CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD``.
|
||||
2. The password is hashed using the Tiny Encryption Algorithm (TEA) — the
|
||||
same implementation used at runtime in
|
||||
``libs/libc/misc/lib_tea_encrypt.c`` — with custom base64 encoding
|
||||
matching ``apps/fsutils/passwd/passwd_encrypt.c``.
|
||||
3. The resulting hashed entry is written to
|
||||
``etctmp/<mountpoint>/passwd`` and then embedded into the ROMFS image.
|
||||
4. The **plaintext password is never stored in the firmware image**.
|
||||
2. Run ``make``.
|
||||
|
||||
TEA encryption keys
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Keys must match between the build (``mkpasswd``) and the firmware
|
||||
(``CONFIG_FSUTILS_PASSWD_KEY1..4``). Choose one option:
|
||||
|
||||
* **Random generation** (``CONFIG_BOARD_ETC_ROMFS_PASSWD_RANDOMIZE_KEYS=y``):
|
||||
On the first build, four keys are generated from ``/dev/urandom`` and
|
||||
written to ``.config``. Key values are not printed in the build log.
|
||||
Search ``.config`` for ``CONFIG_FSUTILS_PASSWD_KEY`` to view them.
|
||||
|
||||
* **Manual**: Set ``CONFIG_FSUTILS_PASSWD_KEY1..4`` under Password file
|
||||
support to unique non-zero values.
|
||||
|
||||
Kconfig options
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Enable the feature and configure credentials via ``make menuconfig``:
|
||||
|
||||
.. code:: kconfig
|
||||
|
||||
CONFIG_BOARD_ETC_ROMFS_PASSWD_ENABLE=y
|
||||
CONFIG_NSH_CONSOLE_LOGIN=y # required to enforce login prompt
|
||||
CONFIG_BOARD_ETC_ROMFS_PASSWD_USER="root" # default: root
|
||||
CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD="<secret>" # required, min length 8
|
||||
CONFIG_BOARD_ETC_ROMFS_PASSWD_UID=0
|
||||
CONFIG_BOARD_ETC_ROMFS_PASSWD_GID=0
|
||||
CONFIG_BOARD_ETC_ROMFS_PASSWD_HOME="/"
|
||||
CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD="<secret>"
|
||||
CONFIG_BOARD_ETC_ROMFS_PASSWD_RANDOMIZE_KEYS=y
|
||||
CONFIG_NSH_CONSOLE_LOGIN=y
|
||||
CONFIG_NSH_LOGIN_PASSWD=y
|
||||
CONFIG_FSUTILS_PASSWD=y
|
||||
|
||||
The TEA encryption keys can be changed from their defaults via
|
||||
``CONFIG_FSUTILS_PASSWD_KEY1..4``.
|
||||
How it works
|
||||
~~~~~~~~~~~~
|
||||
|
||||
1. ``tools/passwd_keys.mk`` checks the password and TEA keys before
|
||||
``config.h`` is generated.
|
||||
2. If random generation is enabled and keys are not set, ``gen_passwd_keys.sh``
|
||||
writes new keys to ``.config``.
|
||||
3. ``mkpasswd`` hashes the password with the configured TEA keys.
|
||||
4. The entry is embedded in the ROMFS image as ``/etc/passwd``.
|
||||
|
||||
``/etc/passwd`` file format
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: text
|
||||
|
||||
user:x:uid:gid:home
|
||||
|
||||
Where:
|
||||
|
||||
* ``user`` — user name
|
||||
* ``x`` — TEA-hashed, base64-encoded password
|
||||
* ``uid`` — numeric user ID
|
||||
* ``gid`` — numeric group ID
|
||||
* ``home`` — login directory
|
||||
|
||||
Verifying the generated entry
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
After enabling ``CONFIG_BOARD_ETC_ROMFS_PASSWD_ENABLE`` and setting a
|
||||
password, rebuild and verify:
|
||||
|
||||
1. **Configure and build**:
|
||||
|
||||
.. code:: console
|
||||
|
||||
$ make menuconfig # enable BOARD_ETC_ROMFS_PASSWD_ENABLE and set password
|
||||
$ make
|
||||
|
||||
2. **Inspect the generated passwd line** (written to the board build tree):
|
||||
|
||||
.. code:: console
|
||||
|
||||
$ cat boards/<arch>/<chip>/<board>/src/etctmp/etc/passwd
|
||||
root:8Tv+Hbmr3pLVb5HHZgd26D:0:0:/
|
||||
|
||||
3. **Verify the plaintext is absent from firmware**:
|
||||
|
||||
.. code:: console
|
||||
|
||||
$ grep <your-password> boards/<arch>/<chip>/<board>/src/etctmp.c
|
||||
# must print nothing
|
||||
user:encrypted_hash:uid:gid:home
|
||||
|
||||
Notes on ``savedefconfig``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To avoid leaking credentials into board defconfigs, ``make savedefconfig``
|
||||
does not save the following options in the generated defconfig:
|
||||
``make savedefconfig`` does not save these options:
|
||||
|
||||
* ``CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD``
|
||||
* ``CONFIG_FSUTILS_PASSWD_KEY1``
|
||||
* ``CONFIG_FSUTILS_PASSWD_KEY2``
|
||||
* ``CONFIG_FSUTILS_PASSWD_KEY3``
|
||||
* ``CONFIG_FSUTILS_PASSWD_KEY4``
|
||||
* ``CONFIG_FSUTILS_PASSWD_KEY1`` through ``CONFIG_FSUTILS_PASSWD_KEY4``
|
||||
|
||||
If you need these values for local development, add them manually to your
|
||||
local defconfig after running ``make savedefconfig``.
|
||||
Do not copy them into a defconfig or commit them to version control.
|
||||
1
Makefile
1
Makefile
|
|
@ -31,6 +31,7 @@ ifeq ($(wildcard .config),)
|
|||
@echo " tools/configure.sh -L"
|
||||
else
|
||||
include .config
|
||||
include tools/passwd_keys.mk
|
||||
|
||||
# Include the correct Makefile for the selected architecture.
|
||||
|
||||
|
|
|
|||
|
|
@ -36,9 +36,6 @@ $(ETCSRC): $(foreach raw,$(RCRAWS), $(if $(wildcard $(BOARD_DIR)$(DELIM)src$(DEL
|
|||
$(shell mkdir -p $(dir $(ETCDIR)$(DELIM)$(raw))) \
|
||||
$(shell cp -rfp $(if $(wildcard $(BOARD_DIR)$(DELIM)src$(DELIM)$(raw)), $(BOARD_DIR)$(DELIM)src$(DELIM)$(raw), $(if $(wildcard $(BOARD_COMMON_DIR)$(DELIM)$(raw)), $(BOARD_COMMON_DIR)$(DELIM)$(raw), $(BOARD_DIR)$(DELIM)src$(DELIM)$(raw))) $(ETCDIR)$(DELIM)$(raw)))
|
||||
ifeq ($(CONFIG_BOARD_ETC_ROMFS_PASSWD_ENABLE),y)
|
||||
ifeq ($(strip $(patsubst "%",%,$(CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD))),)
|
||||
$(error CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD must be set when BOARD_ETC_ROMFS_PASSWD_ENABLE is enabled. Run 'make menuconfig' and select a password at: Board Selection ---> Auto-generate /etc/passwd at build time ---> Admin password)
|
||||
endif
|
||||
$(Q) mkdir -p $(ETCDIR)$(DELIM)$(CONFIG_ETC_ROMFSMOUNTPT)
|
||||
$(Q) $(TOPDIR)$(DELIM)tools$(DELIM)mkpasswd$(HOSTEXEEXT) \
|
||||
--user $(CONFIG_BOARD_ETC_ROMFS_PASSWD_USER) \
|
||||
|
|
@ -46,10 +43,10 @@ endif
|
|||
--uid $(CONFIG_BOARD_ETC_ROMFS_PASSWD_UID) \
|
||||
--gid $(CONFIG_BOARD_ETC_ROMFS_PASSWD_GID) \
|
||||
--home $(CONFIG_BOARD_ETC_ROMFS_PASSWD_HOME) \
|
||||
$(if $(CONFIG_FSUTILS_PASSWD_KEY1),--key1 $(CONFIG_FSUTILS_PASSWD_KEY1)) \
|
||||
$(if $(CONFIG_FSUTILS_PASSWD_KEY2),--key2 $(CONFIG_FSUTILS_PASSWD_KEY2)) \
|
||||
$(if $(CONFIG_FSUTILS_PASSWD_KEY3),--key3 $(CONFIG_FSUTILS_PASSWD_KEY3)) \
|
||||
$(if $(CONFIG_FSUTILS_PASSWD_KEY4),--key4 $(CONFIG_FSUTILS_PASSWD_KEY4)) \
|
||||
--key1 $(CONFIG_FSUTILS_PASSWD_KEY1) \
|
||||
--key2 $(CONFIG_FSUTILS_PASSWD_KEY2) \
|
||||
--key3 $(CONFIG_FSUTILS_PASSWD_KEY3) \
|
||||
--key4 $(CONFIG_FSUTILS_PASSWD_KEY4) \
|
||||
-o $(ETCDIR)$(DELIM)$(CONFIG_ETC_ROMFSMOUNTPT)$(DELIM)passwd
|
||||
endif
|
||||
$(Q) genromfs -f romfs.img -d $(ETCDIR)$(DELIM)$(CONFIG_ETC_ROMFSMOUNTPT) -V "NSHInitVol"
|
||||
|
|
|
|||
|
|
@ -5592,21 +5592,23 @@ config BOARD_ETC_ROMFS_PASSWD_ENABLE
|
|||
default n
|
||||
depends on ETC_ROMFS
|
||||
---help---
|
||||
Generate the /etc/passwd file at build time from a user-supplied
|
||||
password. This avoids shipping a hard-coded default password
|
||||
(CWE-798). When enabled, the build will fail if no password
|
||||
is configured, forcing each build to set its own credentials.
|
||||
Generate /etc/passwd at build time. The password is hashed with TEA
|
||||
by tools/mkpasswd; the plaintext is not stored in the firmware.
|
||||
|
||||
The password is hashed at build time by the host tool
|
||||
tools/mkpasswd (compiled from tools/mkpasswd.c) using the Tiny
|
||||
Encryption Algorithm (TEA) — the same algorithm used at runtime
|
||||
in libs/libc/misc/lib_tea_encrypt.c. The plaintext password is
|
||||
never stored in the firmware image.
|
||||
Before building, set:
|
||||
1. Admin password (below)
|
||||
2. TEA keys — enable random generation below, or set
|
||||
CONFIG_FSUTILS_PASSWD_KEY1..4 in Application Configuration ->
|
||||
File System Utilities -> Password file support
|
||||
|
||||
See Documentation/components/passwd_autogen.rst for details.
|
||||
Also enable NSH login with "Encrypted password file" verification.
|
||||
|
||||
Password and keys are not saved in defconfig. Do not commit them.
|
||||
|
||||
if BOARD_ETC_ROMFS_PASSWD_ENABLE
|
||||
|
||||
comment "--- Step 1: set the admin password below ---"
|
||||
|
||||
config BOARD_ETC_ROMFS_PASSWD_USER
|
||||
string "Admin username"
|
||||
default "root"
|
||||
|
|
@ -5614,14 +5616,39 @@ config BOARD_ETC_ROMFS_PASSWD_USER
|
|||
The username for the auto-generated /etc/passwd entry.
|
||||
|
||||
config BOARD_ETC_ROMFS_PASSWD_PASSWORD
|
||||
string "Admin password (required)"
|
||||
default "Administrator"
|
||||
string "Admin password (required, no default)"
|
||||
---help---
|
||||
The plaintext password for the auto-generated /etc/passwd entry.
|
||||
This value is hashed with TEA at build time; the plaintext is NOT
|
||||
stored in the firmware image. The build will fail if this is left
|
||||
empty or shorter than 8 characters. Set this via
|
||||
'make menuconfig'.
|
||||
The plaintext password for the /etc/passwd entry. No default is
|
||||
provided. The build fails if this is empty or shorter than 8
|
||||
characters.
|
||||
|
||||
Not saved in defconfig.
|
||||
|
||||
comment "--- Step 2: choose how to supply the TEA encryption keys ---"
|
||||
|
||||
config BOARD_ETC_ROMFS_PASSWD_RANDOMIZE_KEYS
|
||||
bool "Generate random TEA encryption keys automatically"
|
||||
default n
|
||||
---help---
|
||||
Generate four random TEA keys from /dev/urandom and write them
|
||||
to .config on the first build. The same keys are used for the
|
||||
/etc/passwd hash and the firmware.
|
||||
|
||||
make menuconfig # set password, enable this option
|
||||
make
|
||||
|
||||
Key values are not printed in the build log. Search .config for
|
||||
CONFIG_FSUTILS_PASSWD_KEY to view them.
|
||||
|
||||
Do not copy keys or the password into a defconfig or commit
|
||||
them to version control.
|
||||
|
||||
If disabled, set CONFIG_FSUTILS_PASSWD_KEY1..4 manually under
|
||||
Application Configuration -> File System Utilities ->
|
||||
Password file support.
|
||||
|
||||
comment " If not randomizing: set KEY1..4 at App Config -> File System Utilities -> Password file support"
|
||||
depends on !BOARD_ETC_ROMFS_PASSWD_RANDOMIZE_KEYS
|
||||
|
||||
config BOARD_ETC_ROMFS_PASSWD_UID
|
||||
int "Admin user ID"
|
||||
|
|
|
|||
|
|
@ -287,9 +287,17 @@ function(process_all_directory_romfs)
|
|||
if("${CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD}" STREQUAL "")
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD must be set when "
|
||||
"BOARD_ETC_ROMFS_PASSWD_ENABLE is enabled. Run 'make menuconfig' "
|
||||
"to set a password.")
|
||||
"\n"
|
||||
" BUILD ERROR: Admin password not set.\n"
|
||||
"\n"
|
||||
" Run make menuconfig and set:\n"
|
||||
" Board Selection -> Auto-generate /etc/passwd -> Admin password\n"
|
||||
"\n"
|
||||
" For TEA keys, either enable random generation in the same menu,\n"
|
||||
" or set CONFIG_FSUTILS_PASSWD_KEY1..4 under Application Configuration\n"
|
||||
" -> File System Utilities -> Password file support.\n"
|
||||
"\n"
|
||||
" Password and keys are not saved in defconfig.\n")
|
||||
endif()
|
||||
|
||||
# Determine host executable suffix (.exe on Windows, empty elsewhere)
|
||||
|
|
@ -317,22 +325,77 @@ function(process_all_directory_romfs)
|
|||
add_custom_target(build_host_mkpasswd DEPENDS ${MKPASSWD_BIN})
|
||||
endif()
|
||||
|
||||
# Pass TEA key overrides when the user has changed them from defaults
|
||||
set(MKPASSWD_KEY_ARGS "")
|
||||
if(CONFIG_FSUTILS_PASSWD_KEY1)
|
||||
list(APPEND MKPASSWD_KEY_ARGS --key1 ${CONFIG_FSUTILS_PASSWD_KEY1})
|
||||
endif()
|
||||
if(CONFIG_FSUTILS_PASSWD_KEY2)
|
||||
list(APPEND MKPASSWD_KEY_ARGS --key2 ${CONFIG_FSUTILS_PASSWD_KEY2})
|
||||
endif()
|
||||
if(CONFIG_FSUTILS_PASSWD_KEY3)
|
||||
list(APPEND MKPASSWD_KEY_ARGS --key3 ${CONFIG_FSUTILS_PASSWD_KEY3})
|
||||
endif()
|
||||
if(CONFIG_FSUTILS_PASSWD_KEY4)
|
||||
list(APPEND MKPASSWD_KEY_ARGS --key4 ${CONFIG_FSUTILS_PASSWD_KEY4})
|
||||
set(GENPASSWD_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/etc/passwd)
|
||||
|
||||
# Delegate detection and generation to the shell helpers so the logic is
|
||||
# testable outside of cmake. check_passwd_keys.sh prints "yes" when keys
|
||||
# are absent or at insecure defaults; gen_passwd_keys.sh writes fresh
|
||||
# /dev/urandom values in-place.
|
||||
#
|
||||
# RANDOMIZE_KEYS — single-invocation path: 1. gen_passwd_keys.sh writes new
|
||||
# keys to .config at configure time. 2. We re-read .config below so
|
||||
# CONFIG_FSUTILS_PASSWD_KEY1..4 carry the new values for the rest of this
|
||||
# cmake configure run. 3. add_custom_command is registered with the updated
|
||||
# key values, so both mkpasswd (passwd hash) and the firmware use the same
|
||||
# keys — login works without a second cmake invocation.
|
||||
#
|
||||
# Note: config.h is regenerated at build time from .config (its dependency),
|
||||
# so the firmware uses the correct keys automatically.
|
||||
|
||||
execute_process(
|
||||
COMMAND "${NUTTX_DIR}/tools/check_passwd_keys.sh" "${NUTTX_DIR}/.config"
|
||||
OUTPUT_VARIABLE _passwd_keys_need_setup
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
RESULT_VARIABLE _check_rc)
|
||||
if(NOT _check_rc EQUAL 0)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"check_passwd_keys.sh failed — check ${NUTTX_DIR}/tools/check_passwd_keys.sh"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(GENPASSWD_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/etc/passwd)
|
||||
if(_passwd_keys_need_setup STREQUAL "yes")
|
||||
if(CONFIG_BOARD_ETC_ROMFS_PASSWD_RANDOMIZE_KEYS)
|
||||
# Generate keys and write to .config (no key values printed here)
|
||||
execute_process(
|
||||
COMMAND "${NUTTX_DIR}/tools/gen_passwd_keys.sh" "${NUTTX_DIR}/.config"
|
||||
RESULT_VARIABLE _gen_rc
|
||||
OUTPUT_QUIET)
|
||||
if(NOT _gen_rc EQUAL 0)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"gen_passwd_keys.sh failed — check ${NUTTX_DIR}/.config permissions"
|
||||
)
|
||||
endif()
|
||||
message(
|
||||
STATUS
|
||||
"[passwd] TEA keys written to .config (search for CONFIG_FSUTILS_PASSWD_KEY to view)"
|
||||
)
|
||||
|
||||
# Re-read .config so the new key values are live for this configure run
|
||||
# (mirrors Board.mk's second -include).
|
||||
file(STRINGS "${NUTTX_DIR}/.config" _fresh_config
|
||||
REGEX "^CONFIG_FSUTILS_PASSWD_KEY[1-4]=")
|
||||
foreach(_line ${_fresh_config})
|
||||
if(_line MATCHES "^CONFIG_FSUTILS_PASSWD_KEY([1-4])=(.+)$")
|
||||
set(CONFIG_FSUTILS_PASSWD_KEY${CMAKE_MATCH_1} "${CMAKE_MATCH_2}")
|
||||
endif()
|
||||
endforeach()
|
||||
else()
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"\n"
|
||||
" BUILD ERROR: TEA encryption keys not configured.\n"
|
||||
"\n"
|
||||
" Run make menuconfig and either:\n"
|
||||
" - enable Generate random TEA keys automatically, or\n"
|
||||
" - set CONFIG_FSUTILS_PASSWD_KEY1..4 under Application Configuration\n"
|
||||
" -> File System Utilities -> Password file support\n")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# At this point KEY1..4 are guaranteed to be correct (either freshly
|
||||
# generated above, or manually set by the user).
|
||||
add_custom_command(
|
||||
OUTPUT ${GENPASSWD_OUTPUT}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/etc
|
||||
|
|
@ -341,10 +404,13 @@ function(process_all_directory_romfs)
|
|||
--password "${CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD}" --uid
|
||||
${CONFIG_BOARD_ETC_ROMFS_PASSWD_UID} --gid
|
||||
${CONFIG_BOARD_ETC_ROMFS_PASSWD_GID} --home
|
||||
"${CONFIG_BOARD_ETC_ROMFS_PASSWD_HOME}" ${MKPASSWD_KEY_ARGS} -o
|
||||
${GENPASSWD_OUTPUT}
|
||||
"${CONFIG_BOARD_ETC_ROMFS_PASSWD_HOME}" --key1
|
||||
${CONFIG_FSUTILS_PASSWD_KEY1} --key2 ${CONFIG_FSUTILS_PASSWD_KEY2}
|
||||
--key3 ${CONFIG_FSUTILS_PASSWD_KEY3} --key4
|
||||
${CONFIG_FSUTILS_PASSWD_KEY4} -o ${GENPASSWD_OUTPUT}
|
||||
DEPENDS ${MKPASSWD_BIN} ${NUTTX_DIR}/.config
|
||||
COMMENT "Generating /etc/passwd from Kconfig values")
|
||||
COMMENT "Generating /etc/passwd from .config TEA keys")
|
||||
|
||||
add_custom_target(generate_passwd DEPENDS ${GENPASSWD_OUTPUT})
|
||||
add_dependencies(generate_passwd build_host_mkpasswd)
|
||||
list(APPEND RCRAWS ${GENPASSWD_OUTPUT})
|
||||
|
|
|
|||
82
tools/check_passwd_keys.sh
Executable file
82
tools/check_passwd_keys.sh
Executable file
|
|
@ -0,0 +1,82 @@
|
|||
#!/usr/bin/env sh
|
||||
# tools/check_passwd_keys.sh
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership. The
|
||||
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance with the
|
||||
# License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Usage:
|
||||
# check_passwd_keys.sh <path-to-.config>
|
||||
#
|
||||
# Prints "yes" to stdout when CONFIG_FSUTILS_PASSWD_KEY1..4 need setup:
|
||||
# - any key is absent or "is not set"
|
||||
# - all four equal the known-insecure Kconfig defaults
|
||||
# Prints "no" when all four are present and non-default.
|
||||
# Idempotent; no side effects.
|
||||
|
||||
set -e
|
||||
|
||||
CONFIG="${1}"
|
||||
if [ -z "${CONFIG}" ]; then
|
||||
printf 'Usage: check_passwd_keys.sh <path-to-.config>\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "${CONFIG}" ]; then
|
||||
printf 'check_passwd_keys: file not found: %s\n' "${CONFIG}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Known-insecure placeholder/default values — must not be used in a build.
|
||||
DEFAULT1=0x12345678
|
||||
DEFAULT2=0x9abcdef0
|
||||
DEFAULT3=0x12345678
|
||||
DEFAULT4=0x9abcdef0
|
||||
|
||||
# Return the assigned value of CONFIG_FSUTILS_PASSWD_KEY<n>, or empty
|
||||
# string when the line is absent or commented as "is not set".
|
||||
get_val() {
|
||||
grep -E "^CONFIG_FSUTILS_PASSWD_KEY${1}=" "${CONFIG}" 2>/dev/null \
|
||||
| tail -n 1 \
|
||||
| sed 's/^[^=]*=//'
|
||||
}
|
||||
|
||||
# True when the value is unset or still at the Kconfig placeholder (0).
|
||||
is_placeholder() {
|
||||
case "$1" in
|
||||
''|0|0x0|0x00000000) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
K1=$(get_val 1)
|
||||
K2=$(get_val 2)
|
||||
K3=$(get_val 3)
|
||||
K4=$(get_val 4)
|
||||
|
||||
# Any key absent, empty, or placeholder → needs setup
|
||||
if is_placeholder "${K1}" || is_placeholder "${K2}" || \
|
||||
is_placeholder "${K3}" || is_placeholder "${K4}"; then
|
||||
echo yes
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# All four at the known insecure defaults → needs setup
|
||||
if [ "${K1}" = "${DEFAULT1}" ] && [ "${K2}" = "${DEFAULT2}" ] && \
|
||||
[ "${K3}" = "${DEFAULT3}" ] && [ "${K4}" = "${DEFAULT4}" ]; then
|
||||
echo yes
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo no
|
||||
89
tools/gen_passwd_keys.sh
Executable file
89
tools/gen_passwd_keys.sh
Executable file
|
|
@ -0,0 +1,89 @@
|
|||
#!/usr/bin/env sh
|
||||
# tools/gen_passwd_keys.sh
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership. The
|
||||
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance with the
|
||||
# License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Usage:
|
||||
# gen_passwd_keys.sh <path-to-.config>
|
||||
#
|
||||
# Generates four random 32-bit TEA key values from /dev/urandom and
|
||||
# writes/replaces CONFIG_FSUTILS_PASSWD_KEY1..4 in the target .config file.
|
||||
# Handles both "line exists (replace)" and "line missing (append)" cases.
|
||||
#
|
||||
# Key values are NOT printed to stdout or stderr. Search the .config file
|
||||
# for CONFIG_FSUTILS_PASSWD_KEY to view them if needed.
|
||||
#
|
||||
# Exit 0 on success, non-zero with a message on failure.
|
||||
|
||||
set -e
|
||||
|
||||
CONFIG="${1}"
|
||||
if [ -z "${CONFIG}" ]; then
|
||||
printf 'Usage: gen_passwd_keys.sh <path-to-.config>\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "${CONFIG}" ]; then
|
||||
printf 'gen_passwd_keys: file not found: %s\n' "${CONFIG}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Generate a random 32-bit hex value via /dev/urandom.
|
||||
# Uses od -tx4 which always produces exactly 8 hex digits.
|
||||
rand_key() {
|
||||
dd if=/dev/urandom bs=4 count=1 2>/dev/null \
|
||||
| od -An -tx4 \
|
||||
| tr -d ' \n'
|
||||
}
|
||||
|
||||
K1="0x$(rand_key)"
|
||||
K2="0x$(rand_key)"
|
||||
K3="0x$(rand_key)"
|
||||
K4="0x$(rand_key)"
|
||||
|
||||
# Remove any existing definitions (assigned or "is not set") everywhere.
|
||||
sed -i \
|
||||
'/^# CONFIG_FSUTILS_PASSWD_KEY[1-4] is not set/d;
|
||||
/^CONFIG_FSUTILS_PASSWD_KEY[1-4]=/d' \
|
||||
"${CONFIG}" || {
|
||||
printf 'gen_passwd_keys: ERROR: failed to edit %s (check permissions)\n' \
|
||||
"${CONFIG}" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Insert keys in the FSUTILS_PASSWD section when it exists so menuconfig
|
||||
# and mkconfig see a single canonical copy (not orphaned lines at EOF).
|
||||
if grep -q '^CONFIG_FSUTILS_PASSWD_IOBUFFER_SIZE=' "${CONFIG}"; then
|
||||
sed -i "/^CONFIG_FSUTILS_PASSWD_IOBUFFER_SIZE=/a\\
|
||||
CONFIG_FSUTILS_PASSWD_KEY1=${K1}\\
|
||||
CONFIG_FSUTILS_PASSWD_KEY2=${K2}\\
|
||||
CONFIG_FSUTILS_PASSWD_KEY3=${K3}\\
|
||||
CONFIG_FSUTILS_PASSWD_KEY4=${K4}" "${CONFIG}" || {
|
||||
printf 'gen_passwd_keys: ERROR: failed to insert keys into %s\n' \
|
||||
"${CONFIG}" >&2
|
||||
exit 1
|
||||
}
|
||||
else
|
||||
printf 'CONFIG_FSUTILS_PASSWD_KEY1=%s\nCONFIG_FSUTILS_PASSWD_KEY2=%s\nCONFIG_FSUTILS_PASSWD_KEY3=%s\nCONFIG_FSUTILS_PASSWD_KEY4=%s\n' \
|
||||
"${K1}" "${K2}" "${K3}" "${K4}" >> "${CONFIG}" || {
|
||||
printf 'gen_passwd_keys: ERROR: failed to append keys to %s\n' \
|
||||
"${CONFIG}" >&2
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
printf 'TEA keys generated and written to %s.\nSearch %s for CONFIG_FSUTILS_PASSWD_KEY to view if needed.\n' \
|
||||
"${CONFIG}" "${CONFIG}"
|
||||
|
|
@ -529,7 +529,10 @@ int main(int argc, char **argv)
|
|||
|
||||
if (password[0] == '\0')
|
||||
{
|
||||
fprintf(stderr, "mkpasswd: --password must not be empty\n");
|
||||
fprintf(stderr,
|
||||
"mkpasswd: ERROR: password must not be empty.\n"
|
||||
" Set it in menuconfig: Board Selection -> "
|
||||
"Auto-generate /etc/passwd -> Admin password\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -541,30 +544,35 @@ int main(int argc, char **argv)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* Warn if the board Kconfig default password is still being used. */
|
||||
/* Reject the well-known default password. The build system should have
|
||||
* caught this already; mkpasswd is the last line of defence.
|
||||
*/
|
||||
|
||||
if (strcmp(password, "Administrator") == 0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
">>>> WARNING: YOU ARE USING THE DEFAULT ADMIN PASSWORD "
|
||||
"(CONFIG_BOARD_ETC_ROMFS_"
|
||||
"PASSWD_PASSWORD=\"Administrator\")!!! PLEASE CHANGE "
|
||||
"IT!!! <<<<\n");
|
||||
"mkpasswd: ERROR: password \"Administrator\" is not allowed.\n"
|
||||
" Set a unique password in menuconfig: Board Selection -> "
|
||||
"Auto-generate /etc/passwd -> Admin password\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Warn when the user has not changed the default TEA keys.
|
||||
* The default values are identical across all NuttX builds, so any
|
||||
* attacker with access to the firmware image can recover the plaintext
|
||||
* password. This is a warning only; the build is not aborted.
|
||||
/* Reject the default TEA keys. Using the published defaults means any
|
||||
* attacker who has a copy of the NuttX source can decrypt the password
|
||||
* hash directly from the firmware image (CWE-321).
|
||||
*/
|
||||
|
||||
if (key[0] == DEFAULT_KEY1 && key[1] == DEFAULT_KEY2 &&
|
||||
key[2] == DEFAULT_KEY3 && key[3] == DEFAULT_KEY4)
|
||||
{
|
||||
fprintf(stderr,
|
||||
">>>> WARNING: YOU ARE USING DEFAULT PASSWORD KEYS "
|
||||
"(CONFIG_FSUTILS_"
|
||||
"PASSWD_KEY1-4)!!! PLEASE CHANGE IT!!! <<<<\n");
|
||||
"mkpasswd: ERROR: default TEA encryption keys "
|
||||
"are not allowed.\n"
|
||||
" Set keys in menuconfig: Application Configuration -> "
|
||||
"File System Utilities -> Password file support\n"
|
||||
" Or enable random key generation under Board Selection -> "
|
||||
"Auto-generate /etc/passwd\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Encrypt the password using TEA + custom base64.
|
||||
|
|
|
|||
74
tools/passwd_keys.mk
Normal file
74
tools/passwd_keys.mk
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
############################################################################
|
||||
# tools/passwd_keys.mk
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Passwd / TEA-key validation and generation. Included from the top-level
|
||||
# Makefile immediately after .config is loaded, BEFORE tools/Unix.mk builds
|
||||
# include/nuttx/config.h. This ordering guarantees that freshly generated
|
||||
# keys are present in .config when config.h is created, so the firmware and
|
||||
# mkpasswd always agree on the same key values in a single make invocation.
|
||||
#
|
||||
# Board.mk only consumes CONFIG_FSUTILS_PASSWD_KEY1..4 in the ROMFS recipe.
|
||||
############################################################################
|
||||
|
||||
TOPDIR ?= .
|
||||
|
||||
# Skip enforcement during configuration-only make invocations (menuconfig,
|
||||
# olddefconfig, clean_context, etc.) so the user can set the password first.
|
||||
PASSWD_SKIP_GOALS := config menuconfig oldconfig olddefconfig savedefconfig \
|
||||
nconfig qconfig gconfig clean_context apps_preconfig \
|
||||
apps_config apps_menuconfig apps_oldconfig apps_olddefconfig \
|
||||
apps_savedefconfig apps_nconfig apps_qconfig apps_gconfig \
|
||||
distclean clean
|
||||
|
||||
ifeq ($(MAKECMDGOALS),)
|
||||
_PASSWD_ENFORCE := y
|
||||
else
|
||||
_PASSWD_ENFORCE := $(if $(filter-out $(PASSWD_SKIP_GOALS),$(MAKECMDGOALS)),y,)
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BOARD_ETC_ROMFS_PASSWD_ENABLE),y)
|
||||
ifeq ($(_PASSWD_ENFORCE),y)
|
||||
|
||||
# --- password check ---
|
||||
ifeq ($(strip $(patsubst "%",%,$(CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD))),)
|
||||
$(info )
|
||||
$(info BUILD ERROR: Admin password not set.)
|
||||
$(info )
|
||||
$(info Run make menuconfig and set:)
|
||||
$(info Board Selection -> Auto-generate /etc/passwd -> Admin password)
|
||||
$(info )
|
||||
$(info For TEA keys, either enable random generation in the same menu,)
|
||||
$(info or set CONFIG_FSUTILS_PASSWD_KEY1..4 under Application Configuration)
|
||||
$(info -> File System Utilities -> Password file support.)
|
||||
$(info )
|
||||
$(info Password and keys are not saved in defconfig.)
|
||||
$(info )
|
||||
$(error Aborting: CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD is not set)
|
||||
endif
|
||||
|
||||
# --- TEA key check / generation ---
|
||||
_PASSWD_KEYS_NEED_SETUP := $(shell \
|
||||
$(TOPDIR)/tools/check_passwd_keys.sh $(TOPDIR)/.config 2>/dev/null)
|
||||
|
||||
ifneq ($(_PASSWD_KEYS_NEED_SETUP),no)
|
||||
ifeq ($(CONFIG_BOARD_ETC_ROMFS_PASSWD_RANDOMIZE_KEYS),y)
|
||||
$(shell $(TOPDIR)/tools/gen_passwd_keys.sh $(TOPDIR)/.config >/dev/null)
|
||||
$(info [passwd] TEA keys written to .config (search for CONFIG_FSUTILS_PASSWD_KEY to view))
|
||||
include $(TOPDIR)/.config
|
||||
else
|
||||
$(info )
|
||||
$(info BUILD ERROR: TEA encryption keys not configured.)
|
||||
$(info )
|
||||
$(info Run make menuconfig and either:)
|
||||
$(info - enable Generate random TEA keys automatically, or)
|
||||
$(info - set CONFIG_FSUTILS_PASSWD_KEY1..4 under Application Configuration)
|
||||
$(info -> File System Utilities -> Password file support)
|
||||
$(info )
|
||||
$(error Aborting: CONFIG_FSUTILS_PASSWD_KEY1..4 must be set to non-default values)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue