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 <dkg@fifthhorseman.net>
This commit is contained in:
Daniel Kahn Gillmor 2018-09-23 14:10:17 -04:00
parent fe8b633954
commit 07c19981da
4 changed files with 29 additions and 1 deletions

View File

@ -670,7 +670,8 @@ used for no expiration date.
If this command is used with @option{--batch}, If this command is used with @option{--batch},
@option{--pinentry-mode} has been set to @code{loopback}, and one of @option{--pinentry-mode} has been set to @code{loopback}, and one of
the passphrase options (@option{--passphrase}, 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 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 ''} for it. To create a key without any protection @code{--passphrase ''}
may be used. 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 option @option{--batch} has also been given. Since Version 2.1
the @option{--pinentry-mode} also needs to be set to @code{loopback}. 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} @item --pinentry-mode @var{mode}
@opindex pinentry-mode @opindex pinentry-mode
Set the pinentry mode to @var{mode}. Allowed values for @var{mode} Set the pinentry mode to @var{mode}. Allowed values for @var{mode}

View File

@ -257,6 +257,7 @@ enum cmd_and_opt_values
oBZ2CompressLevel, oBZ2CompressLevel,
oBZ2DecompressLowmem, oBZ2DecompressLowmem,
oPassphrase, oPassphrase,
oPassphraseEnv,
oPassphraseFD, oPassphraseFD,
oPassphraseFile, oPassphraseFile,
oPassphraseRepeat, oPassphraseRepeat,
@ -709,6 +710,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_c (aRebuildKeydbCaches, "rebuild-keydb-caches", "@"), ARGPARSE_c (aRebuildKeydbCaches, "rebuild-keydb-caches", "@"),
ARGPARSE_s_s (oPassphrase, "passphrase", "@"), ARGPARSE_s_s (oPassphrase, "passphrase", "@"),
ARGPARSE_s_s (oPassphraseEnv, "passphrase-env", "@"),
ARGPARSE_s_i (oPassphraseFD, "passphrase-fd", "@"), ARGPARSE_s_i (oPassphraseFD, "passphrase-fd", "@"),
ARGPARSE_s_s (oPassphraseFile, "passphrase-file", "@"), ARGPARSE_s_s (oPassphraseFile, "passphrase-file", "@"),
ARGPARSE_s_i (oPassphraseRepeat,"passphrase-repeat", "@"), ARGPARSE_s_i (oPassphraseRepeat,"passphrase-repeat", "@"),
@ -3151,6 +3153,9 @@ main (int argc, char **argv)
case oPassphrase: case oPassphrase:
set_passphrase_from_string(pargs.r.ret_str); set_passphrase_from_string(pargs.r.ret_str);
break; break;
case oPassphraseEnv:
set_passphrase_from_environment_variable(pargs.r.ret_str);
break;
case oPassphraseFD: case oPassphraseFD:
pwfd = translate_sys2libc_fd_int (pargs.r.ret_int, 0); pwfd = translate_sys2libc_fd_int (pargs.r.ret_int, 0);
break; break;

View File

@ -279,6 +279,7 @@ gpg_error_t build_sk_list (ctrl_t ctrl, strlist_t locusr,
unsigned char encode_s2k_iterations (int iterations); unsigned char encode_s2k_iterations (int iterations);
int have_static_passphrase(void); int have_static_passphrase(void);
const char *get_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 set_passphrase_from_string(const char *pass);
void read_passphrase_from_fd( int fd ); void read_passphrase_from_fd( int fd );
void passphrase_clear_cache (const char *cacheid); void passphrase_clear_cache (const char *cacheid);

View File

@ -159,6 +159,19 @@ set_passphrase_from_string(const char *pass)
strcpy (fd_passwd, 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 void
read_passphrase_from_fd( int fd ) read_passphrase_from_fd( int fd )