diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi index dc57e4b7c..b585975ad 100644 --- a/doc/gpgsm.texi +++ b/doc/gpgsm.texi @@ -737,6 +737,34 @@ This is actually not a debugging option but only useful as such. It lets @command{gpgsm} ignore all notAfter dates, this is used by the regression tests. +@item --passphrase-fd @code{n} +@opindex passphrase-fd +Read the passphrase from file descriptor @code{n}. Only the first line +will be read from file descriptor @code{n}. If you use 0 for @code{n}, +the passphrase will be read from STDIN. This can only be used if only +one passphrase is supplied. + +Note that this passphrase is only used if the option @option{--batch} +has also been given. + +@item --pinentry-mode @code{mode} +@opindex pinentry-mode +Set the pinentry mode to @code{mode}. Allowed values for @code{mode} +are: +@table @asis + @item default + Use the default of the agent, which is @code{ask}. + @item ask + Force the use of the Pinentry. + @item cancel + Emulate use of Pinentry's cancel button. + @item error + Return a Pinentry error (``No Pinentry''). + @item loopback + Redirect Pinentry queries to the caller. Note that in contrast to + Pinentry the user is not prompted again if he enters a bad password. +@end table + @item --no-common-certs-import @opindex no-common-certs-import Suppress the import of common certificates on keybox creation. diff --git a/sm/Makefile.am b/sm/Makefile.am index 43e3598bd..11f86e9a4 100644 --- a/sm/Makefile.am +++ b/sm/Makefile.am @@ -54,7 +54,8 @@ gpgsm_SOURCES = \ certreqgen.c \ certreqgen-ui.c \ minip12.c minip12.h \ - qualified.c + qualified.c \ + passphrase.c passphrase.h common_libs = ../kbx/libkeybox509.a $(libcommon) diff --git a/sm/call-agent.c b/sm/call-agent.c index c7d4c5a88..8c1c7276c 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -37,6 +37,8 @@ #include "asshelp.h" #include "keydb.h" /* fixme: Move this to import.c */ #include "membuf.h" +#include "shareddefs.h" +#include "passphrase.h" static assuan_context_t agent_ctx = NULL; @@ -74,6 +76,11 @@ struct import_key_parm_s size_t keylen; }; +struct default_inq_parm_s +{ + ctrl_t ctrl; + assuan_context_t ctx; +}; /* Print a warning if the server's version number is less than our @@ -151,6 +158,20 @@ start_agent (ctrl_t ctrl) agents. */ assuan_transact (agent_ctx, "OPTION allow-pinentry-notify", NULL, NULL, NULL, NULL, NULL, NULL); + + /* Pass on the pinentry mode. */ + if (opt.pinentry_mode) + { + char *tmp = xasprintf ("OPTION pinentry-mode=%s", + str_pinentry_mode (opt.pinentry_mode)); + rc = assuan_transact (agent_ctx, tmp, + NULL, NULL, NULL, NULL, NULL, NULL); + xfree (tmp); + if (rc) + log_error ("setting pinentry mode '%s' failed: %s\n", + str_pinentry_mode (opt.pinentry_mode), + gpg_strerror (rc)); + } } } @@ -163,14 +184,14 @@ start_agent (ctrl_t ctrl) return rc; } - /* This is the default inquiry callback. It mainly handles the Pinentry notifications. */ static gpg_error_t default_inq_cb (void *opaque, const char *line) { - gpg_error_t err; - ctrl_t ctrl = opaque; + gpg_error_t err = 0; + struct default_inq_parm_s *parm = opaque; + ctrl_t ctrl = parm->ctrl; if (has_leading_keyword (line, "PINENTRY_LAUNCHED")) { @@ -180,10 +201,18 @@ default_inq_cb (void *opaque, const char *line) "PINENTRY_LAUNCHED"); /* We do not pass errors to avoid breaking other code. */ } + else if ((has_leading_keyword (line, "PASSPHRASE") + || has_leading_keyword (line, "NEW_PASSPHRASE")) + && opt.pinentry_mode == PINENTRY_MODE_LOOPBACK + && have_static_passphrase ()) + { + const char *s = get_static_passphrase (); + err = assuan_send_data (parm->ctx, s, strlen (s)); + } else log_error ("ignoring gpg-agent inquiry '%s'\n", line); - return 0; + return err; } @@ -200,6 +229,7 @@ gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc, char *p, line[ASSUAN_LINELENGTH]; membuf_t data; size_t len; + struct default_inq_parm_s inq_parm = { ctrl, agent_ctx }; *r_buf = NULL; rc = start_agent (ctrl); @@ -239,7 +269,7 @@ gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc, init_membuf (&data, 1024); rc = assuan_transact (agent_ctx, "PKSIGN", - put_membuf_cb, &data, default_inq_cb, ctrl, + put_membuf_cb, &data, default_inq_cb, &inq_parm, NULL, NULL); if (rc) { @@ -272,6 +302,7 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc, const char *hashopt; unsigned char *sigbuf; size_t sigbuflen; + struct default_inq_parm_s inq_parm = { ctrl, agent_ctx }; (void)desc; @@ -306,7 +337,7 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc, snprintf (line, DIM(line)-1, "SCD PKSIGN %s %s", hashopt, keyid); line[DIM(line)-1] = 0; rc = assuan_transact (agent_ctx, line, - put_membuf_cb, &data, default_inq_cb, ctrl, + put_membuf_cb, &data, default_inq_cb, &inq_parm, NULL, NULL); if (rc) { @@ -356,7 +387,10 @@ inq_ciphertext_cb (void *opaque, const char *line) assuan_end_confidential (parm->ctx); } else - rc = default_inq_cb (parm->ctrl, line); + { + struct default_inq_parm_s inq_parm = { parm->ctrl, parm->ctx }; + rc = default_inq_cb (&inq_parm, line); + } return rc; } @@ -476,7 +510,10 @@ inq_genkey_parms (void *opaque, const char *line) rc = assuan_send_data (parm->ctx, parm->sexp, parm->sexplen); } else - rc = default_inq_cb (parm->ctrl, line); + { + struct default_inq_parm_s inq_parm = { parm->ctrl, parm->ctx }; + rc = default_inq_cb (&inq_parm, line); + } return rc; } @@ -544,6 +581,7 @@ gpgsm_agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip, size_t len; unsigned char *buf; char line[ASSUAN_LINELENGTH]; + struct default_inq_parm_s inq_parm = { ctrl, agent_ctx }; *r_pubkey = NULL; rc = start_agent (ctrl); @@ -561,7 +599,7 @@ gpgsm_agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip, init_membuf (&data, 1024); rc = assuan_transact (agent_ctx, line, put_membuf_cb, &data, - default_inq_cb, ctrl, NULL, NULL); + default_inq_cb, &inq_parm, NULL, NULL); if (rc) { xfree (get_membuf (&data, &len)); @@ -631,6 +669,7 @@ gpgsm_agent_scd_serialno (ctrl_t ctrl, char **r_serialno) { int rc; char *serialno = NULL; + struct default_inq_parm_s inq_parm = { ctrl, agent_ctx }; *r_serialno = NULL; rc = start_agent (ctrl); @@ -639,7 +678,7 @@ gpgsm_agent_scd_serialno (ctrl_t ctrl, char **r_serialno) rc = assuan_transact (agent_ctx, "SCD SERIALNO", NULL, NULL, - default_inq_cb, ctrl, + default_inq_cb, &inq_parm, scd_serialno_status_cb, &serialno); if (!rc && !serialno) rc = gpg_error (GPG_ERR_INTERNAL); @@ -700,6 +739,7 @@ gpgsm_agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list) { int rc; strlist_t list = NULL; + struct default_inq_parm_s inq_parm = { ctrl, agent_ctx }; *r_list = NULL; rc = start_agent (ctrl); @@ -708,7 +748,7 @@ gpgsm_agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list) rc = assuan_transact (agent_ctx, "SCD LEARN --force", NULL, NULL, - default_inq_cb, ctrl, + default_inq_cb, &inq_parm, scd_keypairinfo_status_cb, &list); if (!rc && !list) rc = gpg_error (GPG_ERR_NO_DATA); @@ -797,6 +837,7 @@ gpgsm_agent_marktrusted (ctrl_t ctrl, ksba_cert_t cert) int rc; char *fpr, *dn, *dnfmt; char line[ASSUAN_LINELENGTH]; + struct default_inq_parm_s inq_parm = { ctrl, agent_ctx }; rc = start_agent (ctrl); if (rc) @@ -825,7 +866,7 @@ gpgsm_agent_marktrusted (ctrl_t ctrl, ksba_cert_t cert) xfree (fpr); rc = assuan_transact (agent_ctx, line, NULL, NULL, - default_inq_cb, ctrl, NULL, NULL); + default_inq_cb, &inq_parm, NULL, NULL); return rc; } @@ -983,6 +1024,7 @@ gpgsm_agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc) { int rc; char line[ASSUAN_LINELENGTH]; + struct default_inq_parm_s inq_parm = { ctrl, agent_ctx }; rc = start_agent (ctrl); if (rc) @@ -1005,7 +1047,7 @@ gpgsm_agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc) line[DIM(line)-1] = 0; rc = assuan_transact (agent_ctx, line, NULL, NULL, - default_inq_cb, ctrl, NULL, NULL); + default_inq_cb, &inq_parm, NULL, NULL); return rc; } @@ -1018,6 +1060,7 @@ gpgsm_agent_get_confirmation (ctrl_t ctrl, const char *desc) { int rc; char line[ASSUAN_LINELENGTH]; + struct default_inq_parm_s inq_parm = { ctrl, agent_ctx }; rc = start_agent (ctrl); if (rc) @@ -1027,7 +1070,7 @@ gpgsm_agent_get_confirmation (ctrl_t ctrl, const char *desc) line[DIM(line)-1] = 0; rc = assuan_transact (agent_ctx, line, NULL, NULL, - default_inq_cb, ctrl, NULL, NULL); + default_inq_cb, &inq_parm, NULL, NULL); return rc; } @@ -1128,6 +1171,7 @@ gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, int repeat, char line[ASSUAN_LINELENGTH]; char *arg4 = NULL; membuf_t data; + struct default_inq_parm_s inq_parm = { ctrl, agent_ctx }; *r_passphrase = NULL; @@ -1146,7 +1190,7 @@ gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, int repeat, init_membuf_secure (&data, 64); err = assuan_transact (agent_ctx, line, put_membuf_cb, &data, - default_inq_cb, NULL, NULL, NULL); + default_inq_cb, &inq_parm, NULL, NULL); if (err) xfree (get_membuf (&data, NULL)); @@ -1174,6 +1218,7 @@ gpgsm_agent_keywrap_key (ctrl_t ctrl, int forexport, size_t len; unsigned char *buf; char line[ASSUAN_LINELENGTH]; + struct default_inq_parm_s inq_parm = { ctrl, agent_ctx }; *r_kek = NULL; err = start_agent (ctrl); @@ -1186,7 +1231,7 @@ gpgsm_agent_keywrap_key (ctrl_t ctrl, int forexport, init_membuf_secure (&data, 64); err = assuan_transact (agent_ctx, line, put_membuf_cb, &data, - default_inq_cb, ctrl, NULL, NULL); + default_inq_cb, &inq_parm, NULL, NULL); if (err) { xfree (get_membuf (&data, &len)); @@ -1217,7 +1262,10 @@ inq_import_key_parms (void *opaque, const char *line) assuan_end_confidential (parm->ctx); } else - err = default_inq_cb (parm->ctrl, line); + { + struct default_inq_parm_s inq_parm = { parm->ctrl, parm->ctx }; + err = default_inq_cb (&inq_parm, line); + } return err; } @@ -1259,6 +1307,7 @@ gpgsm_agent_export_key (ctrl_t ctrl, const char *keygrip, const char *desc, size_t len; unsigned char *buf; char line[ASSUAN_LINELENGTH]; + struct default_inq_parm_s inq_parm = { ctrl, agent_ctx }; *r_result = NULL; @@ -1280,7 +1329,7 @@ gpgsm_agent_export_key (ctrl_t ctrl, const char *keygrip, const char *desc, init_membuf_secure (&data, 1024); err = assuan_transact (agent_ctx, line, put_membuf_cb, &data, - default_inq_cb, ctrl, NULL, NULL); + default_inq_cb, &inq_parm, NULL, NULL); if (err) { xfree (get_membuf (&data, &len)); diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 364dd43ff..fc6d1c75a 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -32,6 +32,8 @@ #include #include /* malloc hooks */ +#include "passphrase.h" +#include "../common/shareddefs.h" #include "../kbx/keybox.h" /* malloc hooks */ #include "i18n.h" #include "keydb.h" @@ -120,6 +122,8 @@ enum cmd_and_opt_values { oProtectToolProgram, oFakedSystemTime, + oPassphraseFD, + oPinentryMode, oAssumeArmor, oAssumeBase64, @@ -243,6 +247,9 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_s (oP12Charset, "p12-charset", "@"), + ARGPARSE_s_i (oPassphraseFD, "passphrase-fd", "@"), + ARGPARSE_s_s (oPinentryMode, "pinentry-mode", "@"), + ARGPARSE_s_n (oAssumeArmor, "assume-armor", N_("assume input is in PEM format")), ARGPARSE_s_n (oAssumeBase64, "assume-base64", @@ -910,7 +917,7 @@ main ( int argc, char **argv) estream_t auditfp = NULL; estream_t htmlauditfp = NULL; struct assuan_malloc_hooks malloc_hooks; - + int pwfd = -1; /*mtrace();*/ early_system_init (); @@ -1150,6 +1157,16 @@ main ( int argc, char **argv) opt.p12_charset = pargs.r.ret_str; break; + case oPassphraseFD: + pwfd = translate_sys2libc_fd_int (pargs.r.ret_int, 0); + break; + + case oPinentryMode: + opt.pinentry_mode = parse_pinentry_mode (pargs.r.ret_str); + if (opt.pinentry_mode == -1) + log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str); + break; + /* Input encoding selection. */ case oAssumeArmor: ctrl.autodetect_encoding = 0; @@ -1458,6 +1475,9 @@ main ( int argc, char **argv) if (log_get_errorcount(0)) gpgsm_exit(2); + if (pwfd != -1) /* Read the passphrase now. */ + read_passphrase_from_fd (pwfd); + /* Now that we have the options parsed we need to update the default control structure. */ gpgsm_init_default_ctrl (&ctrl); diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 44b4798ff..5aad4b152 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -84,6 +84,8 @@ struct int with_keygrip; /* Option --with-keygrip active. */ + int pinentry_mode; + int armor; /* force base64 armoring (see also ctrl.with_base64) */ int no_armor; /* don't try to figure out whether data is base64 armored*/ diff --git a/sm/passphrase.c b/sm/passphrase.c new file mode 100644 index 000000000..6ad2b0a20 --- /dev/null +++ b/sm/passphrase.c @@ -0,0 +1,90 @@ +/* passphrase.c - Get a passphrase + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, + * 2005, 2006, 2007, 2009, 2011 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include + +#include "passphrase.h" +#include "gpgsm.h" +#include "../common/shareddefs.h" +#include "../common/ttyio.h" + +static char *fd_passwd = NULL; + +int +have_static_passphrase () +{ + return (!!fd_passwd + && (opt.batch || opt.pinentry_mode == PINENTRY_MODE_LOOPBACK)); +} + +/* Return a static passphrase. The returned value is only valid as + long as no other passphrase related function is called. NULL may + be returned if no passphrase has been set; better use + have_static_passphrase first. */ +const char * +get_static_passphrase (void) +{ + return fd_passwd; +} + +void +read_passphrase_from_fd (int fd) +{ + int i, len; + char *pw; + + if (!opt.batch && opt.pinentry_mode != PINENTRY_MODE_LOOPBACK) + { /* Not used but we have to do a dummy read, so that it won't end + up at the begin of the message if the quite usual trick to + prepend the passphtrase to the message is used. */ + char buf[1]; + + while (!(read (fd, buf, 1) != 1 || *buf == '\n')) + ; + *buf = 0; + return; + } + + for (pw = NULL, i = len = 100; ; i++) + { + if (i >= len-1) + { + char *pw2 = pw; + len += 100; + pw = xmalloc_secure (len); + if (pw2) + { + memcpy (pw, pw2, i); + xfree (pw2); + } + else + i = 0; + } + if (read (fd, pw+i, 1) != 1 || pw[i] == '\n') + break; + } + pw[i] = 0; + if (!opt.batch && opt.pinentry_mode != PINENTRY_MODE_LOOPBACK) + tty_printf("\b\b\b \n" ); + + xfree (fd_passwd); + fd_passwd = pw; +} diff --git a/sm/passphrase.h b/sm/passphrase.h new file mode 100644 index 000000000..3401a0b0c --- /dev/null +++ b/sm/passphrase.h @@ -0,0 +1,27 @@ +/* passphrase.h - Get a passphrase + * Copyright (C) 2016 g10 Code GmbH + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef GPGSM_PASSPHRASE_H +#define GPGSM_PASSPHRASE_H + +int have_static_passphrase (void); +const char *get_static_passphrase (void); +void read_passphrase_from_fd (int fd); + +#endif /* GPGSM_PASSPHRASE_H */