Skip to content

Change password input for gpg from STDIN to dedicated fd - #586

Open
Narrat wants to merge 2 commits into
dyne:masterfrom
Narrat:optim/password-input-2_fd
Open

Change password input for gpg from STDIN to dedicated fd#586
Narrat wants to merge 2 commits into
dyne:masterfrom
Narrat:optim/password-input-2_fd

Conversation

@Narrat

@Narrat Narrat commented Oct 3, 2025

Copy link
Copy Markdown
Collaborator

As a draft because of the same reasons mentioned in #585


Background of this PR is the issue that tomb has issues with passwords that try to use characters in a combination so they create control sequences for the shell. For example newline \n, form feed \f and tabulator \t.
This is due how the password is provided for the gpg call. gpg is used with --passphrase-fd 0 which reads the password from STDIN until it encounters a newline. Unfortunately this means the shell interprets those character sequences in the password itself. Especially fatal in case of \n as this will reduce the password to this point. Example: you want to set password test\ntest. gpg, while reading STDIN, will stop at \n and the resulting password will be only test.
Not sure yet what happens with the rest, but it does seem to be discarded in general and not added to or used as TOMBSECRET.

Two ways to avoid interpreting control sequences:

  • change --passphrase-fd to a dedicated descriptor above 2 (like --passphrase-fd 3 and input password like 3<<<"$password"
  • use --passphrase-file and use an anonymous pipe

In general the first option is similar to the current solution, just changing it to a different FD, which allows to avoid interpreting control sequences. But is untested if the redirect isn't visible while tracing.
This solutions changes the fd for the password input from STDIN to a new one file-descriptor (3 in this example).

@jaromil

jaromil commented Dec 15, 2025

Copy link
Copy Markdown
Member

I'm in favor of this, yet we'll need to state the introduction of a breaking change for anyone who uses passwords with control characters which were previously misinterpreted.

Remove last remnant of 9e820f3
The latest release of gpg1 is 1.4.23 from 2018. It is safe to assume, that there
is no modern distribution, which ships this specific gpg1 version.
As the workaround itself only applies to 1.4.11, any version before or after seem
to be safe.
This removal doesn't remove support for gpg1 in general as it isn't end-of-life.
All the options in use are available with gpg1 and only a broken --status-fd
seemed to be of concern.

Closes dyne#581
@Narrat
Narrat force-pushed the optim/password-input-2_fd branch from a8b0f53 to 9febdba Compare June 25, 2026 20:01
@Narrat

Narrat commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator Author

Time flew by...
Polished up the PR.
Not sure about the failing tests.

2026-06-25T20:03:36.9975564Z tomb [D] ask_key_password with tombpass: test
2026-06-25T20:03:36.9990263Z tomb [D] get_lukskey
2026-06-25T20:03:37.0005788Z tomb [D] KDF: argon2
2026-06-25T20:03:37.0020755Z tomb  .  Unlocking KDF key protection (argon2)
2026-06-25T20:03:37.0036799Z tomb [D] KDF salt: 2c705f4872e9c0db54dbb3ada38f70cb4d5a7b130a2224d705641988564a81b7
2026-06-25T20:03:37.0051182Z tomb [D] KDF ic: 3
2026-06-25T20:03:37.0065734Z tomb [D] KDF mem: 18
2026-06-25T20:03:37.0080380Z tomb [D] KDF # threads: 1
2026-06-25T20:03:37.4742514Z tomb [D] Created tempfile: /tmp/3002230798245095596
2026-06-25T20:03:37.5767465Z tomb [D] gpg: AES256.CFB encrypted data
2026-06-25T20:03:37.5782163Z tomb [D] [GNUPG:] NEED_PASSPHRASE_SYM 9 3 2
2026-06-25T20:03:37.5797549Z tomb [D] gpg: encrypted with 1 passphrase
2026-06-25T20:03:37.5812732Z tomb [D] [GNUPG:] BEGIN_DECRYPTION
2026-06-25T20:03:37.5828348Z tomb [D] [GNUPG:] DECRYPTION_INFO 2 9 0
2026-06-25T20:03:37.5843348Z tomb [D] [GNUPG:] PLAINTEXT 62 1782417816 
2026-06-25T20:03:37.5858876Z tomb [D] [GNUPG:] DECRYPTION_OKAY
2026-06-25T20:03:37.5873834Z tomb [D] [GNUPG:] GOODMDC
2026-06-25T20:03:37.5888609Z tomb [D] [GNUPG:] END_DECRYPTION
2026-06-25T20:03:37.5903757Z tomb [D] get_lukskey returns 0
2026-06-25T20:03:37.5918985Z tomb  .  Password OK.
2026-06-25T20:03:37.5952794Z tomb [D] Super user execution skipped (SUID caller)
2026-06-25T20:03:39.7311935Z No key available with this passphrase.
2026-06-25T20:03:39.7338577Z tomb [E] Failure mounting the encrypted file.
2026-06-25T20:03:39.7355378Z tomb [D] Restoring access and modification time for /tmp/tomb/argon.tomb
2026-06-25T20:03:39.7389936Z tomb [D] Restoring access and modification time for /tmp/tomb/argon.tomb.key
2026-06-25T20:03:39.7564002Z      Tomb command returns 1
2026-06-25T20:03:39.7565476Z not ok 3 - Testing argon2 KDF: tomb open & close
2026-06-25T20:03:39.7578003Z #	
2026-06-25T20:03:39.7578436Z #	        tt_open --tomb-pwd $DUMMYPASS &&
2026-06-25T20:03:39.7579092Z #	        tt_close
2026-06-25T20:03:39.7579469Z #	        
2026-06-25T20:03:39.7582979Z make[2]: *** [Makefile:40: 31_kdf-argon2.sh] Error 1
2026-06-25T20:03:39.7583900Z make[2]: Leaving directory '/home/runner/work/tomb/tomb/extras/test'
2026-06-25T20:03:39.7585930Z make[1]: *** [Makefile:34: test] Error 2
2026-06-25T20:03:39.7586636Z make[1]: Leaving directory '/home/runner/work/tomb/tomb/extras/test'
2026-06-25T20:03:39.7588021Z make: *** [Makefile:34: test] Error 2
2026-06-25T20:03:39.7615496Z ##[error]Process completed with exit code 2.
2026-06-25T20:03:39.7741127Z Node 20 is being deprecated. This workflow is running with Node 24 by default. If you need to temporarily use Node 20, you can set the ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true environment variable. For more information see: https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/
2026-06-25T20:03:39.7742693Z Post job cleanup.
2026-06-25T20:03:39.8407056Z (node:8645) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
2026-06-25T20:03:39.8407770Z (Use `node --trace-deprecation ...` to show where the warning was created)
2026-06-25T20:03:39.8440515Z [command]/usr/bin/git version
2026-06-25T20:03:39.8476606Z git version 2.54.0
2026-06-25T20:03:39.8513840Z Temporarily overriding HOME='/home/runner/work/_temp/64f17d4f-757c-4d4d-9f1d-1a3ea3e30a2d' before making global git config changes
2026-06-25T20:03:39.8515284Z Adding repository directory to the temporary git global config as a safe directory
2026-06-25T20:03:39.8517992Z [command]/usr/bin/git config --global --add safe.directory /home/runner/work/tomb/tomb
2026-06-25T20:03:39.8551091Z [command]/usr/bin/git config --local --name-only --get-regexp core\.sshCommand
2026-06-25T20:03:39.8580656Z [command]/usr/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :"
2026-06-25T20:03:39.8799103Z [command]/usr/bin/git config --local --name-only --get-regexp http\.https\:\/\/github\.com\/\.extraheader
2026-06-25T20:03:39.8825835Z http.https://github.com/.extraheader
2026-06-25T20:03:39.8836500Z [command]/usr/bin/git config --local --unset-all http.https://github.com/.extraheader
2026-06-25T20:03:39.8868324Z [command]/usr/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'http\.https\:\/\/github\.com\/\.extraheader' && git config --local --unset-all 'http.https://github.com/.extraheader' || :"
2026-06-25T20:03:39.9216018Z Cleaning up orphan processes
2026-06-25T20:03:39.9630462Z ##[warning]Node.js 20 is deprecated. The following actions target Node.js 20 but are being forced to run on Node.js 24: actions/checkout@v3. For more information see: https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/

Somewhere in the argon test cases. But running the tests locally went through without an issue.

GPG was used in way, that the password for the payload and the payload
was piped into GPG separated by a newline ("--passphrase-fd 0" where 0
is STDIN). It will then read the input until a newline is encountered
and strip it from the pipe. After which only the encrypted payload
remains.
This has some consequences for passwords in general, as the running
shell is involved and may interpret ANSI Escape Sequences.

ANSI Escape sequences can be used for various tasks and are
non-printable characters.
Build with a backslash ("\"), they create control sequences
like \n (newline), \t (horizontal tab) and \f (formfeed).
If those are used in passwords various stuff can happen.
\n for example will shorten the password depending on its position.
\ at the end of password will nullify the newline separator between the
password and the encrypted payload.
See KNOWN_BUGS.md for a table with some cases.

To solve those unintended changes the file descriptor is changed from 0
(STDIN) to 3. Which is the next free one after 1 (STDOUT) and 2 (STDERR).
The password will be redirected via "3<<<$password".

This solution won against a switch to --passphrase-file and the use of an
anonymous pipe <(print -R -n - "$password").
In general the use of --passphrase-file is discouraged, but that should
only apply if a real file is used. With the pipe only the respective file
descriptor should be seen and not its content. For which only gpg is
allowed to have access. And if gpg is completed the pipe and its content
is gone.

What changes:
pinentry or more accuratly assuan will still output a (percent)formated
password, but the shell won't interfere anymore.

This does not address passwords that contain % and the difference
between entering the password via pinentry and --tomb-pwd.

Addresses dyne#304
@Narrat
Narrat force-pushed the optim/password-input-2_fd branch from 9febdba to 974784f Compare June 25, 2026 20:22
@jaromil

jaromil commented Jun 29, 2026

Copy link
Copy Markdown
Member

Thanks, this was on my mind for long now. So good to finally fix and properly document corner cases as you did. Give me some time to test myself and perhaps cover it with some specific tests.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Drop workaround for gnupg 1.4.11 Backslash escaping in passwords and ideas on how to overcome similar problems

2 participants