Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*.dSYM
*.elf
*.exe
etctmp/
*.gcno
*.gcda
*.hex
Expand Down
95 changes: 95 additions & 0 deletions Documentation/components/tools/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,98 @@ and host C programs that are important parts of the NuttX build system:
:glob:

./*

.. _mkpasswd_autogen:

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.

Why build-time generation?
~~~~~~~~~~~~~~~~~~~~~~~~~~

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.

For improved baseline security, the configured password must be at least
8 characters long.

How it works
~~~~~~~~~~~~

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**.

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="admin" # default: admin
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="/"

The TEA encryption keys can be changed from their defaults via
``CONFIG_FSUTILS_PASSWD_KEY1..4``.

``/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
admin:s1IZjGjjmo/x8u5m5uY2jB: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
Original file line number Diff line number Diff line change
Expand Up @@ -491,21 +491,21 @@ mounted at /etc and will look like this at run-time:
nsh>

``/etc/init.d/rc.sysinit`` is system init script; ``/etc/init.d/rcS`` is the
start-up script; ``/etc/passwd`` is a the password file. It supports a single
user:
start-up script; ``/etc/passwd`` is the password file.

.. code:: text
The ``/etc/passwd`` file is auto-generated at build time when
``CONFIG_BOARD_ETC_ROMFS_PASSWD_ENABLE`` is set. Enable the option and set
credentials via ``make menuconfig``:

USERNAME: admin
PASSWORD: Administrator
* ``CONFIG_BOARD_ETC_ROMFS_PASSWD_ENABLE=y``
* ``CONFIG_BOARD_ETC_ROMFS_PASSWD_USER`` (default: ``admin``)
* ``CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD`` (required, build fails if empty)

nsh> cat /etc/passwd
admin:8Tv+Hbmr3pLVb5HHZgd26D:0:0:/
The password is hashed with TEA at build time by the host tool
``tools/mkpasswd``; the plaintext is **not** stored in the firmware.

The encrypted passwords in the provided passwd file are only valid if the TEA
key is set to: 012345678 9abcdef0 012345678 9abcdef0. Changes to either the key
or the password word will require regeneration of the ``nsh_romfimg.h`` header
file.
For the full description of the mechanism, TEA key configuration, file format,
and verification steps, see :ref:`mkpasswd_autogen`.

The format of the password file is:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,22 @@ README
nsh>

/etc/init.d/rc.sysinit is system init script; /etc/init.d/rcS is the start-up
script; /etc/passwd is a the password file. It supports a single user:
script; /etc/passwd is the password file.

USERNAME: admin
PASSWORD: Administrator
The /etc/passwd file is auto-generated at build time when
CONFIG_BOARD_ETC_ROMFS_PASSWD_ENABLE is set. To configure the admin user and
password, run 'make menuconfig' and set:

nsh> cat /etc/passwd
admin:8Tv+Hbmr3pLVb5HHZgd26D:0:0:/
CONFIG_BOARD_ETC_ROMFS_PASSWD_ENABLE=y
CONFIG_BOARD_ETC_ROMFS_PASSWD_USER (default: admin)
CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD (required, build fails if empty)

The encrypted passwords in the provided passwd file are only valid if the
TEA key is set to: 012345678 9abcdef0 012345678 9abcdef0. Changes to either
the key or the password word will require regeneration of the nsh_romfimg.h
header file.
The password is hashed with TEA at build time by the host tool
tools/mkpasswd; the plaintext is NOT stored in the firmware image.

For the full description of the mechanism, TEA key configuration, file
format, and verification steps, see Documentation/components/tools/index.rst
(mkpasswd section).

The format of the password file is:

Expand Down
42 changes: 28 additions & 14 deletions Documentation/platforms/sim/sim/boards/sim/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2008,24 +2008,23 @@ mounted at ``/etc`` and will look like this at run-time:
nsh>

``/etc/init.d/rc.sysinit`` is system init script; ``/etc/init.d/rcS`` is the
start-up script; ``/etc/passwd`` is a the password file. It supports a single
user:
start-up script; ``/etc/passwd`` is the password file.

.. code:: text

USERNAME: admin
PASSWORD: Administrator

.. code:: console
The ``/etc/passwd`` file is auto-generated at build time when
``CONFIG_BOARD_ETC_ROMFS_PASSWD_ENABLE`` is set. Enable the option and set
credentials via ``make menuconfig``:

nsh> cat /etc/passwd
admin:8Tv+Hbmr3pLVb5HHZgd26D:0:0:/
* ``CONFIG_BOARD_ETC_ROMFS_PASSWD_ENABLE=y``
* ``CONFIG_NSH_CONSOLE_LOGIN=y`` (required, otherwise login is not enforced)
* ``CONFIG_BOARD_ETC_ROMFS_PASSWD_USER`` (default: ``admin``)
* ``CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD`` (required, build fails if empty or shorter than 8 characters)

The encrypted passwords in the provided passwd file are only valid if the
TEA key is set to: 012345678 9abcdef0 012345678 9abcdef0.
The password is hashed with TEA at build time by the host tool
``tools/mkpasswd``; the plaintext is **not** stored in the firmware.

Changes to either the key or the password word will require regeneration of the
``nsh_romfimg.h`` header file.
For the full description of the build-time password generation mechanism,
TEA key configuration, file format, and verification steps, see
:ref:`mkpasswd_autogen`.

The format of the password file is:

Expand All @@ -2041,6 +2040,21 @@ Where:
* gid: Group ID (0 for now)
* home: Login directory (/ for now)

For configuration, verification steps, and TEA key details, see
:ref:`mkpasswd_autogen`.

Login test inside the simulator
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code:: console

$ ./nuttx
NuttShell (NSH) NuttX-<version>
nsh login: admin
Password:
User Logged-in!
nsh>

``/etc/group`` is a group file. It is not currently used.

.. code:: console
Expand Down
39 changes: 39 additions & 0 deletions boards/Board.mk
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,45 @@ $(ETCSRC): $(foreach raw,$(RCRAWS), $(if $(wildcard $(BOARD_DIR)$(DELIM)src$(DEL
$(shell rm -rf $(ETCDIR)$(DELIM)$(raw)) \
$(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 ($(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' to set a password.)
endif
ifeq ($(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' to set a password.)
endif
$(Q) passwd=$(CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD); \
passwd=$${passwd#\"}; \
passwd=$${passwd%\"}; \
if [ $${#passwd} -lt 8 ]; then \
echo "ERROR: CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD must be at least 8 characters."; \
exit 1; \
fi
$(Q) if [ ! -f $(TOPDIR)$(DELIM)tools$(DELIM)mkpasswd$(HOSTEXEEXT) ]; then \
$(MAKE) -C $(TOPDIR)$(DELIM)tools -f Makefile.host mkpasswd$(HOSTEXEEXT); \
fi
$(Q) mkdir -p $(ETCDIR)$(DELIM)$(CONFIG_ETC_ROMFSMOUNTPT)
$(Q) user=$(CONFIG_BOARD_ETC_ROMFS_PASSWD_USER); \
user=$${user#\"}; \
user=$${user%\"}; \
home=$(CONFIG_BOARD_ETC_ROMFS_PASSWD_HOME); \
home=$${home#\"}; \
home=$${home%\"}; \
passwd=$(CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD); \
passwd=$${passwd#\"}; \
passwd=$${passwd%\"}; \
$(TOPDIR)$(DELIM)tools$(DELIM)mkpasswd$(HOSTEXEEXT) \
--user "$${user}" \
--password "$${passwd}" \
--uid $(CONFIG_BOARD_ETC_ROMFS_PASSWD_UID) \
--gid $(CONFIG_BOARD_ETC_ROMFS_PASSWD_GID) \
--home "$${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)) \
-o $(ETCDIR)$(DELIM)$(CONFIG_ETC_ROMFSMOUNTPT)$(DELIM)passwd
endif
$(Q) genromfs -f romfs.img -d $(ETCDIR)$(DELIM)$(CONFIG_ETC_ROMFSMOUNTPT) -V "NSHInitVol"
$(Q) echo "#include <nuttx/compiler.h>" > $@
$(Q) xxd -i romfs.img | sed -e "s/^unsigned char/const unsigned char aligned_data(4)/g" >> $@
Expand Down
50 changes: 50 additions & 0 deletions boards/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -5423,3 +5423,53 @@ config BOARD_MEMORY_RANGE
end: end address of memory range
flags: Executable 0x1, Writable 0x2, Readable 0x4
example:{0x1000,0x2000,0x4},{0x2000,0x3000,0x6},{0x3000,0x4000,0x7} ... {0x0,0x0,0x0}

config BOARD_ETC_ROMFS_PASSWD_ENABLE
bool "Auto-generate /etc/passwd at build time"
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.

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.

See Documentation/components/passwd_autogen.rst for details.

if BOARD_ETC_ROMFS_PASSWD_ENABLE

config BOARD_ETC_ROMFS_PASSWD_USER
string "Admin username"
default "admin"
---help---
The username for the auto-generated /etc/passwd entry.

config BOARD_ETC_ROMFS_PASSWD_PASSWORD
string "Admin password (required)"
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'.

config BOARD_ETC_ROMFS_PASSWD_UID
int "Admin user ID"
default 0

config BOARD_ETC_ROMFS_PASSWD_GID
int "Admin group ID"
default 0

config BOARD_ETC_ROMFS_PASSWD_HOME
string "Admin home directory"
default "/"

endif # BOARD_ETC_ROMFS_PASSWD_ENABLE
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ endif

ifeq ($(CONFIG_ETC_ROMFS),y)
RCSRCS = etc/init.d/rc.sysinit etc/init.d/rcS
RCRAWS = etc/group etc/passwd
RCRAWS = etc/group
endif

DEPPATH += --dep-path board
Expand Down

This file was deleted.

3 changes: 3 additions & 0 deletions boards/sim/sim/sim/configs/login/defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ CONFIG_ARCH_BOARD="sim"
CONFIG_ARCH_BOARD_SIM=y
CONFIG_ARCH_CHIP="sim"
CONFIG_ARCH_SIM=y
CONFIG_BOARD_ETC_ROMFS_PASSWD_ENABLE=y
CONFIG_BOARD_ETC_ROMFS_PASSWD_USER="admin"
CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD="Administrator"
CONFIG_BOARDCTL_APP_SYMTAB=y
CONFIG_BOARDCTL_POWEROFF=y
CONFIG_BOARD_LOOPSPERMSEC=0
Expand Down
1 change: 0 additions & 1 deletion boards/sim/sim/sim/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ if(CONFIG_ETC_ROMFS)
etc/init.d/rc.sysinit
RCRAWS
etc/group
etc/passwd
PATH
${CMAKE_CURRENT_BINARY_DIR}/etc)

Expand Down
2 changes: 1 addition & 1 deletion boards/sim/sim/sim/src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ endif

ifeq ($(CONFIG_ETC_ROMFS),y)
RCSRCS = etc/init.d/rc.sysinit etc/init.d/rcS
RCRAWS = etc/group etc/passwd
RCRAWS = etc/group
endif

ifeq ($(CONFIG_ARCH_BUTTONS),y)
Expand Down
1 change: 0 additions & 1 deletion boards/sim/sim/sim/src/etc/passwd

This file was deleted.

Loading
Loading