Skip to content

!boards/nsh: Replace TEA password storage with PBKDF2-HMAC-SHA256 hashing #19209

Open
Abhishekmishra2808 wants to merge 3 commits into
apache:masterfrom
Abhishekmishra2808:passwd-empty-default-hardening
Open

!boards/nsh: Replace TEA password storage with PBKDF2-HMAC-SHA256 hashing #19209
Abhishekmishra2808 wants to merge 3 commits into
apache:masterfrom
Abhishekmishra2808:passwd-empty-default-hardening

Conversation

@Abhishekmishra2808

@Abhishekmishra2808 Abhishekmishra2808 commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Replace reversible TEA password storage in /etc/passwd with one-way PBKDF2-HMAC-SHA256 hashing in modular crypt format (MCF): $pbkdf2-sha256$<iterations>$<base64url-salt>$<base64url-hash>

BREAKING CHANGE: TEA-encoded /etc/passwd entries no longer verify.
Regenerate with tools/mkpasswd or NSH passwd/useradd after upgrading nuttx-apps.

Changes:

  • Add apps/crypto/pbkdf2 (PBKDF2-HMAC-SHA256; Mbed TLS backend when available, self-contained SHA-256 fallback otherwise)
  • Rewrite passwd_encrypt.c / passwd_verify.c to use PBKDF2 and timingsafe_bcmp() for verification
  • Add shared passwd_base64.c for base64url encode/decode
  • Enforce password complexity when setting passwords (min 8 chars, upper, lower, digit, special character)
  • Add testing/pbkdf2 (RFC 6070 vectors + passwd round-trip test)

Companion nuttx PR (host mkpasswd tool and ROMFS build integration): apache/nuttx-apps#3557

Impact

Security

  • Passwords are stored as one-way hashes with per-password random salt and configurable iteration count (default 10000).
  • Plaintext passwords are never written to /etc/passwd.

Compatibility (breaking)

  • Existing TEA-encoded /etc/passwd entries will not verify. Users must regenerate passwords with NSH passwd / useradd or build-time mkpasswd after upgrading.
  • Depends on companion nuttx PR for ROMFS autogen and host tooling.

Build

  • Selects CRYPTO_PBKDF2 automatically when FSUTILS_PASSWD is enabled.

Runtime

  • Login latency increases slightly on low MHz MCUs due to PBKDF2 iterations (tunable via CONFIG_FSUTILS_PASSWD_PBKDF2_ITERATIONS).

Testing

Host: WSL2 Linux, x86_64

Sim (sim:nsh or login-enabled config)

  • Build succeeds with FSUTILS_PASSWD and TESTING_PBKDF2
abhishek@Lethallaptop:~/nuttx$ time make -j$(nproc)
Create version.h
LN: platform/board to /home/abhishek/nuttx-apps/platform/dummy
Register: gpio
Register: dd
Register: dumpstack
Register: nsh
Register: sh
Register: hello
CP:  /home/abhishek/nuttx/include/nuttx/config.h
CP:  /home/abhishek/nuttx/include/nuttx/fs/hostfs.h
ROMFS root password (min 8 characters): 
LD:  nuttx
Pac SIM with dynamic libs..
'/lib/x86_64-linux-gnu/libz.so.1' -> 'sim-pac/libs/libz.so.1'
'/lib/x86_64-linux-gnu/libc.so.6' -> 'sim-pac/libs/libc.so.6'
'/lib64/ld-linux-x86-64.so.2' -> 'sim-pac/ld-linux-x86-64.so.2'
SIM elf with dynamic libs archive in nuttx.tgz

real    0m51.470s
user    3m38.379s
sys     2m34.115s

ESP32-C3 (esp32c3-devkit:login, local test config, not in this PR)

  • ROMFS /etc/passwd with PBKDF2 hash
  • NSH console login over USB serial (/dev/ttyACM0) succeeds with configured password; wrong password rejected
abhishek@Lethallaptop:~/nuttx$ make -j$(nproc) CROSSDEV=riscv32-esp-elf-
Create version.h
Cloning Espressif HAL for 3rd Party Platforms
Clone: chip/esp-hal-3rdparty LN: platform/board to /home/abhishek/nuttx-apps/platform/dummy
Register: dumpstack
Register: nsh
Register: sh
Register: dd
Register: ostest
Register: pbkdf2_test
Register: getprime
Espressif HAL for 3rd Party Platforms: cleaning current repository...
Espressif HAL for 3rd Party Platforms: 0eb59f7e02a4735f2b9a78797e691b66740fcadb
ROMFS root password (min 8 characters): 
LD: nuttx
Memory region         Used Size  Region Size  %age Used
             ROM:      310900 B         4 MB      7.41%
     iram0_0_seg:       14768 B     321296 B      4.60%
     irom0_0_seg:      139684 B         4 MB      3.33%
     dram0_0_seg:       24512 B     321296 B      7.63%
     drom0_0_seg:      245328 B         4 MB      5.85%
    rtc_iram_seg:          52 B       8168 B      0.64%
rtc_reserved_seg:          0 GB         24 B      0.00%
CP: nuttx.hex
MKIMAGE: NuttX binary
esptool.py -c esp32c3 elf2image --ram-only-header -fs 4MB -fm dio -ff "80m" -o nuttx.bin nuttx
Warning: DEPRECATED: 'esptool.py' is deprecated. Please use 'esptool' instead. The '.py' suffix will be removed in a future major release.
esptool v5.3.0
Creating ESP32-C3 image...
Image has only RAM segments visible. ROM segments are hidden and SHA256 digest is not appended.
Merged 1 ELF section.
Successfully created ESP32-C3 image.
Generated: nuttx.bin

Manual verification

  • useradd / passwd reject weak passwords (no special char, too short)
  • Valid password produces $pbkdf2-sha256$... hash in /etc/passwd

@github-actions github-actions Bot added Area: Build system Size: M The size of the change in this PR is medium Board: risc-v Board: simulator labels Jun 24, 2026
@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

@Abhishekmishra2808

Copy link
Copy Markdown
Contributor Author

@acassis, Checks are failing because the password is currently empty, and CI expects some passwd value.
What would be the right way to fix CI?

@acassis

acassis commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

@acassis, Checks are failing because the password is currently empty, and CI expects some passwd value. What would be the right way to fix CI?

Let's wait for @simbit18 suggestion. I think one option will be removing the board profile from CI testing

Comment thread boards/Kconfig Outdated
@github-actions github-actions Bot added Size: XL The size of the change in this PR is very large. Consider breaking down the PR into smaller pieces. and removed Size: M The size of the change in this PR is medium labels Jun 25, 2026
@Abhishekmishra2808
Abhishekmishra2808 marked this pull request as draft June 25, 2026 15:35
@Abhishekmishra2808
Abhishekmishra2808 force-pushed the passwd-empty-default-hardening branch from f4a6ce2 to aeec705 Compare June 25, 2026 16:43
@Abhishekmishra2808 Abhishekmishra2808 changed the title !boards/nsh: Require explicit ROMFS passwd password at build time !boards/nsh: Replace reversible TEA password storage in /etc/passwd with one-way PBKDF2-HMAC-SHA256 hashing Jun 25, 2026
@Abhishekmishra2808
Abhishekmishra2808 force-pushed the passwd-empty-default-hardening branch from aeec705 to 084e043 Compare June 25, 2026 16:47
@Abhishekmishra2808

Copy link
Copy Markdown
Contributor Author

@acassis, @xiaoxiang781216 PTAL !

@acassis

acassis commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

@Abhishekmishra2808 why did you disable the Crypto for Dropbear? I think @FelipeMdeO is already fixing this issue.

@FelipeMdeO is it ok for you to let disable it?

@Abhishekmishra2808

Copy link
Copy Markdown
Contributor Author

They caused base64 symbol collisions with libtomcrypt at link time, so I reverted only the CODECS/CRYPTO lines I'd added for Kconfig deps. Dropbear still uses CRYPTO_MBEDTLS as upstream.

I think I should coordinate with @FelipeMdeO for this.

@FelipeMdeO

Copy link
Copy Markdown
Contributor

They caused base64 symbol collisions with libtomcrypt at link time, so I reverted only the CODECS/CRYPTO lines I'd added for Kconfig deps. Dropbear still uses CRYPTO_MBEDTLS as upstream.

I think I should coordinate with @FelipeMdeO for this.

Hello @Abhishekmishra2808 , I cannot access my environment now, but more late I will take a look and ping you.

@FelipeMdeO

FelipeMdeO commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Hello @acassis , @Abhishekmishra2808 , sorry, combining your 2 PR will "crash" dropbear.
I followed the steps below to have this conclusion:

git clone git@github.com:apache/nuttx.git nuttx-repro && cd nuttx-repro
git fetch origin pull/19209/head:pr-19209 && git checkout pr-19209

cd .. && git clone git@github.com:apache/nuttx-apps.git apps && cd apps
git fetch origin pull/3557/head:pr-3557 && git checkout pr-3557

cd ../nuttx-repro
./tools/configure.sh sim:dropbear
make -j$(nproc)                     # builda com sucesso, sem dropbear dentro

After build, you will see:

➜  nuttx-repro git:(pr-19209) grep CONFIG_NETUTILS_DROPBEAR .config
➜  nuttx-repro git:(pr-19209) ./nuttx 

NuttShell (NSH) NuttX-13.0.0
nsh> help
help usage:  help [-v] [<cmd>]

    .           cmp         free        mkfifo      rmdir       uname       
    [           dirname     help        mkrd        set         umount      
    ?           df          hexdump     mount       kill        unset       
    alias       dmesg       ifconfig    mv          pkill       uptime      
    unalias     echo        ifdown      nslookup    sleep       watch       
    arp         env         ifup        pidof       usleep      xd          
    basename    exec        losetup     printf      source      wait        
    break       exit        ln          ps          test        
    cat         expr        ls          pwd         time        
    cd          false       mkdir       readlink    true        
    cp          fdinfo      mkfatfs     rm          truncate    

Builtin Apps:
    aescbc       aesxts       des3cbc      gpio         hmac         ping         
    aesctr       dd           dumpstack    hello        nsh          sh           
nsh> 

So the dropbear was silently disabled.
I will start to look right now why its happen and how can we solve this issue.

@FelipeMdeO

FelipeMdeO commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Hello @Abhishekmishra2808 .

Please revert commit a4c807a (your last commit), the base64/ecc collision it worked around is already handled by the symbol renaming in netutils/dropbear/Makefile, so the strip is redundant. When restoring the lines, also add CONFIG_CRYPTO_CRYPTODEV_SOFTWARE_CRYPTO=y (+ CONFIG_CRYPTO_SW_AES=y), or /dev/crypto won't have the swcr_pbkdf2 backend and PBKDF2 login fails at runtime.

Look for git diff from your last commit:

diff --git a/boards/sim/sim/sim/configs/dropbear/defconfig b/boards/sim/sim/sim/configs/dropbear/defconfig
index e5990f622c..3905398c47 100644
--- a/boards/sim/sim/sim/configs/dropbear/defconfig
+++ b/boards/sim/sim/sim/configs/dropbear/defconfig
@@ -16,7 +16,13 @@ CONFIG_ARCH_SIM=y
 CONFIG_BOARD_LOOPSPERMSEC=0
 CONFIG_BOOT_RUNFROMEXTSRAM=y
 CONFIG_BUILTIN=y
+CONFIG_CODECS_BASE64=y
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_CRYPTODEV=y
+CONFIG_CRYPTO_CRYPTODEV_SOFTWARE_CRYPTO=y
 CONFIG_CRYPTO_MBEDTLS=y
+CONFIG_CRYPTO_RANDOM_POOL=y
+CONFIG_CRYPTO_SW_AES=y
 CONFIG_DEBUG_SYMBOLS=y
 CONFIG_DEV_GPIO=y
 CONFIG_DEV_LOOP=y
@@ -55,6 +61,7 @@ CONFIG_NET=y
 CONFIG_NETDEV_LATEINIT=y
 CONFIG_NETINIT_DRIPADDR=0x0a000101
 CONFIG_NETINIT_IPADDR=0x0a000102
+CONFIG_NETUTILS_CODECS=y
 CONFIG_NETUTILS_DROPBEAR=y
 CONFIG_NETUTILS_DROPBEAR_HOSTKEY_PATH="/tmp/dropbear_ecdsa_host_key"
 CONFIG_NET_BROADCAST=y

PS: You changed the password policy, right?
What do you think about explicitly stating that the password does not meet the security policies, and perhaps adding some information that makes it easier for the user to identify the security policy?

I don't have relevant background on this point, could you give your opinion, @acassis , @xiaoxiang781216 , @ThePassionate ?

I took some time to get issue when I tested dropbear after your change, the current output for password out of policy is:

./nuttx

dropbear [6:100]

NuttShell (NSH) NuttX-13.0.0
nsh> [6] Jun 01 00:00:00 using NuttX passwd auth at /tmp/passwd
dropbear: listening on port 2222

nsh> useradd test dropbear
nsh: useradd: passwd_adduser failed: 22
nsh> 


jerpelea
jerpelea previously approved these changes Jul 17, 2026
Enable CONFIG_CRYPTO_CRYPTODEV_SOFTWARE_CRYPTO and CONFIG_CRYPTO_SW_AES on
dropbear defconfigs so /dev/crypto provides the swcr_pbkdf2 backend required
for PBKDF2 login at runtime.

Signed-off-by: Abhishek Mishra <mishra.abhishek2808@gmail.com>
@Abhishekmishra2808
Abhishekmishra2808 force-pushed the passwd-empty-default-hardening branch from a4c807a to 5856e38 Compare July 18, 2026 13:02
@Abhishekmishra2808

Abhishekmishra2808 commented Jul 18, 2026

Copy link
Copy Markdown
Contributor Author

@FelipeMdeO I restored the dropbear crypto defconfig options (reverting a4c807adcb), added CRYPTO_CRYPTODEV_SOFTWARE_CRYPTO and CRYPTO_SW_AES, and verified sim:dropbear builds with dropbear enabled and PBKDF2 login works. Password policy failures now show a clearer message in nuttx-apps. PTAL when you have a chance.

Thanks for giving a detailed review and a fix too :)

@Abhishekmishra2808

Copy link
Copy Markdown
Contributor Author

@FelipeMdeO, while testing sim:dropbear with nuttx PR #19209 and nuttx-apps PR #3557 (after the defconfig/crypto fixes), I ran into a separate issue that looks unrelated to the PBKDF2/passwd changes. Reporting it here in case it helps.

SSH login succeeds and the client shows nsh>, but keyboard input does not work (commands are not accepted).

Logs (sim)

nsh> useradd admin 'Dropbear1!'
nsh> [6] Jun 01 00:01:27 connection from 10.255.255.254:44222
[6] Jun 01 00:01:29 Password auth succeeded for 'admin' from 10.255.255.254:44222
[6] Jun 01 00:01:29 NSH PTY session started
[6] Jun 01 00:01:29 NSH session wait failed: Unknown error 10
(Unknown error 10 is ECHILD on NuttX.)

What seems to be happening
From netutils/dropbear/dropbear_nshsession.c:

NSH is started with task_spawn() from the dropbear task.
A pthread waiter calls waitpid(sess->nsh_pid, ...).
On NuttX, waitpid() appears to return ECHILD immediately (waiter thread is not the spawning parent).
On failure, the code still sets sess->done = true, which makes dropbear_sesscheckclose() treat the SSH channel as closed. So the session stops accepting input even though the nsh> prompt was already sent.

PTAL !! When you have a chance. :-)

@Abhishekmishra2808

Copy link
Copy Markdown
Contributor Author

@acassis, @FelipeMdeO . Both PRs fail CI in isolation: nuttx #19209 uses apps master (no dropbear symbol rename → sim/dropbear link errors), and #3557 uses nuttx master (no PBKDF2/mkpasswd yet). They work together locally. Can we split the dropbear Makefile renames into a small apps PR to merge first?

@FelipeMdeO

Copy link
Copy Markdown
Contributor

@FelipeMdeO, while testing sim:dropbear with nuttx PR #19209 and nuttx-apps PR #3557 (after the defconfig/crypto fixes), I ran into a separate issue that looks unrelated to the PBKDF2/passwd changes. Reporting it here in case it helps.

SSH login succeeds and the client shows nsh>, but keyboard input does not work (commands are not accepted).

Logs (sim)

nsh> useradd admin 'Dropbear1!'
nsh> [6] Jun 01 00:01:27 connection from 10.255.255.254:44222
[6] Jun 01 00:01:29 Password auth succeeded for 'admin' from 10.255.255.254:44222
[6] Jun 01 00:01:29 NSH PTY session started
[6] Jun 01 00:01:29 NSH session wait failed: Unknown error 10
(Unknown error 10 is ECHILD on NuttX.)

What seems to be happening From netutils/dropbear/dropbear_nshsession.c:

NSH is started with task_spawn() from the dropbear task. A pthread waiter calls waitpid(sess->nsh_pid, ...). On NuttX, waitpid() appears to return ECHILD immediately (waiter thread is not the spawning parent). On failure, the code still sets sess->done = true, which makes dropbear_sesscheckclose() treat the SSH channel as closed. So the session stops accepting input even though the nsh> prompt was already sent.

PTAL !! When you have a chance. :-)

Looking it right now, please give me some minutes.

@FelipeMdeO

Copy link
Copy Markdown
Contributor

Hello @Abhishekmishra2808 , dropbear is ok now. Don't worry about ECHILD issue, I will open a PR to solve this issue.
Let's fix the pipeline

@FelipeMdeO

Copy link
Copy Markdown
Contributor

Hello @Abhishekmishra2808 , to solve pipeline issue, please open and merge your commit 8630ed7d9 first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: Build system Board: arm Board: risc-v Board: simulator Size: XL The size of the change in this PR is very large. Consider breaking down the PR into smaller pieces.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants