From 07c19981da0607dc442fadc4079b1d71fbef8f83 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Sun, 23 Sep 2018 14:10:17 -0400 Subject: [PATCH] gpg: add --passphrase-env VARNAME to read passphrase from environment * g10/keydb.h: declare set_passphrase_from_environment_variable() * g10/passphrase.c: set_passphrase_from_environment_variable() new function * g10/gpg.c: add new --passphrase-env argument, handle it. -- There are problems or difficulties (to varying degrees) with all of the techniques available for sending a passphrase directly to the GnuPG process when --pinentry-mode=loopback: * Passphrases on the command line often leak into the process table. * Passphrases in a file often leak into the disk. * Using an extra file descriptor to send a passphrase works well on platforms that make it easy to allocate and use extra file descriptors, but is pretty awkward on platforms that don't facilitate this. So this patch adds a new form of passphrase-passing, using an environment variable. In POSIX shell, this looks like (for example): mypass="IUuKctdEhH8' gpg --batch --pinentry-mode=loopback\ --passphrase-env=mypass --decrypt < message.txt Hopefully, this is easier to use than --passphrase-fd on platforms or language toolkits that don't facilitate file descriptor manipulation. Signed-off-by: Daniel Kahn Gillmor --- doc/gpg.texi | 11 ++++++++++- g10/gpg.c | 5 +++++ g10/keydb.h | 1 + g10/passphrase.c | 13 +++++++++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index 7f55cc7e3..55e31d2e7 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -670,7 +670,8 @@ used for no expiration date. If this command is used with @option{--batch}, @option{--pinentry-mode} has been set to @code{loopback}, and one of the passphrase options (@option{--passphrase}, -@option{--passphrase-fd}, or @option{passphrase-file}) is used, the +@option{--passphrase-fd}, @option{--passphrase-env}, or +@option{passphrase-file}) is used, the supplied passphrase is used for the new key and the agent does not ask for it. To create a key without any protection @code{--passphrase ''} may be used. @@ -3172,6 +3173,14 @@ Note that since Version 2.0 this passphrase is only used if the option @option{--batch} has also been given. Since Version 2.1 the @option{--pinentry-mode} also needs to be set to @code{loopback}. +@item --passphrase-env @var{string} +@opindex passphrase-env +Use the value of the environment variable @var{string} as the passphrase. +This can only be used if only one passphrase is supplied. + +This passphrase is only used if the option @option{--batch} has also +been given, and if @option{--pinentry-mode} is set to @code{loopback}. + @item --pinentry-mode @var{mode} @opindex pinentry-mode Set the pinentry mode to @var{mode}. Allowed values for @var{mode} diff --git a/g10/gpg.c b/g10/gpg.c index f04a3400a..36adbaaa2 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -257,6 +257,7 @@ enum cmd_and_opt_values oBZ2CompressLevel, oBZ2DecompressLowmem, oPassphrase, + oPassphraseEnv, oPassphraseFD, oPassphraseFile, oPassphraseRepeat, @@ -709,6 +710,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_c (aRebuildKeydbCaches, "rebuild-keydb-caches", "@"), ARGPARSE_s_s (oPassphrase, "passphrase", "@"), + ARGPARSE_s_s (oPassphraseEnv, "passphrase-env", "@"), ARGPARSE_s_i (oPassphraseFD, "passphrase-fd", "@"), ARGPARSE_s_s (oPassphraseFile, "passphrase-file", "@"), ARGPARSE_s_i (oPassphraseRepeat,"passphrase-repeat", "@"), @@ -3151,6 +3153,9 @@ main (int argc, char **argv) case oPassphrase: set_passphrase_from_string(pargs.r.ret_str); break; + case oPassphraseEnv: + set_passphrase_from_environment_variable(pargs.r.ret_str); + break; case oPassphraseFD: pwfd = translate_sys2libc_fd_int (pargs.r.ret_int, 0); break; diff --git a/g10/keydb.h b/g10/keydb.h index 1def2bb81..db88df9f8 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -279,6 +279,7 @@ gpg_error_t build_sk_list (ctrl_t ctrl, strlist_t locusr, unsigned char encode_s2k_iterations (int iterations); int have_static_passphrase(void); const char *get_static_passphrase (void); +void set_passphrase_from_environment_variable(const char *envvar); void set_passphrase_from_string(const char *pass); void read_passphrase_from_fd( int fd ); void passphrase_clear_cache (const char *cacheid); diff --git a/g10/passphrase.c b/g10/passphrase.c index 10574ec6a..17e259695 100644 --- a/g10/passphrase.c +++ b/g10/passphrase.c @@ -159,6 +159,19 @@ set_passphrase_from_string(const char *pass) strcpy (fd_passwd, pass); } +void +set_passphrase_from_environment_variable(const char *envvar) +{ + const char *val = getenv(envvar); + if (val == NULL) + val = ""; + xfree (fd_passwd); + fd_passwd = xmalloc_secure(strlen(val)+1); + strcpy (fd_passwd, val); + /* clean up sensitive environment variable to avoid accidental + propagation: */ + unsetenv(envvar); +} void read_passphrase_from_fd( int fd )