From 7e40c5efbea65c7804b06d62dfcd7f991557bfaa Mon Sep 17 00:00:00 2001 From: Ben McGinnes Date: Wed, 7 Mar 2018 10:28:48 +1100 Subject: doc: man page grammar -- Fixed two grammatical errors: their vs. there and oneself vs. one (one's self would still be too stilted). --- doc/gpg.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index ddebc692c..e3c3662a8 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -2213,8 +2213,8 @@ handy in case where an encrypted message contains a bogus key ID. @opindex skip-hidden-recipients @opindex no-skip-hidden-recipients During decryption skip all anonymous recipients. This option helps in -the case that people use the hidden recipients feature to hide there -own encrypt-to key from others. If oneself has many secret keys this +the case that people use the hidden recipients feature to hide their +own encrypt-to key from others. If one has many secret keys this may lead to a major annoyance because all keys are tried in turn to decrypt something which was not really intended for it. The drawback of this option is that it is currently not possible to decrypt a -- cgit v1.2.3 From 334b94898112b5d2c7c97ff0496b9a67b3de0d26 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 8 Mar 2018 14:08:51 +0900 Subject: gpg: Fix build on Windows. -- WIN32_LEAN_AND_MEAN is required to avoid definitions of grp1, grp2, and grp3 in dlgs.h, which is included by windows.h. Fixes-commit: fd595c9d3642dba437fbe0f6e25d7aaaae095f94 Signed-off-by: NIIBE Yutaka --- g10/gpg.h | 4 ++++ g10/misc.c | 1 + 2 files changed, 5 insertions(+) diff --git a/g10/gpg.h b/g10/gpg.h index 9b8b77ca0..1bad5515a 100644 --- a/g10/gpg.h +++ b/g10/gpg.h @@ -24,6 +24,10 @@ correct value and may be of advantage if we ever have to do special things. */ +#ifdef HAVE_W32_SYSTEM +# define WIN32_LEAN_AND_MEAN 1 +#endif + #ifdef GPG_ERR_SOURCE_DEFAULT #error GPG_ERR_SOURCE_DEFAULT already defined #endif diff --git a/g10/misc.c b/g10/misc.c index 77c8f269c..97809692e 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -42,6 +42,7 @@ #include #include #ifdef HAVE_WINSOCK2_H +# define WIN32_LEAN_AND_MEAN 1 # include #endif #include -- cgit v1.2.3 From f8b8b6aac2ca1cb34d7a346aee1d874e7650557b Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 8 Mar 2018 16:51:51 +0900 Subject: scd: Fix status check when using PC/SC. * scd/apdu.c (struct reader_table_s): Add field of current_state. (new_reader_slot): Initialize current_state. (pcsc_get_status): Keep the status in READER_TABLE array. Return SW_HOST_NO_READER when PCSC_STATE_CHANGED. * scd/scdaemon.c (handle_connections): Silence a warning. -- To detect some change of card status, including suspend/resume possibly, SCardGetStatusChange should be used keeping the dwCurrentState field. This change could improve situation for suspend/resume with Yubikey on Windows. Even not, this is doing the Right Thing. Signed-off-by: NIIBE Yutaka --- scd/apdu.c | 15 ++++++++++++--- scd/scdaemon.c | 2 ++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/scd/apdu.c b/scd/apdu.c index c50afbde2..6758e69e8 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -119,6 +119,7 @@ struct reader_table_s { pcsc_dword_t modify_ioctl; int pinmin; int pinmax; + pcsc_dword_t current_state; } pcsc; #ifdef USE_G10CODE_RAPDU struct { @@ -453,6 +454,7 @@ new_reader_slot (void) reader_table[reader].pcsc.modify_ioctl = 0; reader_table[reader].pcsc.pinmin = -1; reader_table[reader].pcsc.pinmax = -1; + reader_table[reader].pcsc.current_state = PCSC_STATE_UNAWARE; return reader; } @@ -652,12 +654,12 @@ pcsc_get_status (int slot, unsigned int *status, int on_wire) (void)on_wire; memset (rdrstates, 0, sizeof *rdrstates); rdrstates[0].reader = reader_table[slot].rdrname; - rdrstates[0].current_state = PCSC_STATE_UNAWARE; + rdrstates[0].current_state = reader_table[slot].pcsc.current_state; err = pcsc_get_status_change (reader_table[slot].pcsc.context, 0, rdrstates, 1); if (err == PCSC_E_TIMEOUT) - err = 0; /* Timeout is no error error here. */ + err = 0; /* Timeout is no error here. */ if (err) { log_error ("pcsc_get_status_change failed: %s (0x%lx)\n", @@ -665,6 +667,9 @@ pcsc_get_status (int slot, unsigned int *status, int on_wire) return pcsc_error_to_sw (err); } + reader_table[slot].pcsc.current_state = + (rdrstates[0].event_state & ~PCSC_STATE_CHANGED); + /* log_debug */ /* ("pcsc_get_status_change: %s%s%s%s%s%s%s%s%s%s\n", */ /* (rdrstates[0].event_state & PCSC_STATE_IGNORE)? " ignore":"", */ @@ -701,7 +706,11 @@ pcsc_get_status (int slot, unsigned int *status, int on_wire) *status |= APDU_CARD_USABLE; #endif - return 0; + if (!on_wire && (rdrstates[0].event_state & PCSC_STATE_CHANGED)) + /* Event like sleep/resume occurs, which requires RESET. */ + return SW_HOST_NO_READER; + else + return 0; } diff --git a/scd/scdaemon.c b/scd/scdaemon.c index cebeea9d3..91b559925 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -1348,6 +1348,8 @@ handle_connections (int listen_fd) FD_SET (pipe_fd[0], &read_fdset); if (max_fd < pipe_fd[0]) max_fd = pipe_fd[0]; +#else + (void)max_fd; #endif #ifndef HAVE_W32_SYSTEM -- cgit v1.2.3 From 1e27c0e04cd3280d498dc8b72d2e410f6287f656 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 9 Mar 2018 08:56:50 +0900 Subject: scd: More fix with PC/SC for Windows. * scd/apdu.c (pcsc_get_status): Return status based on CURRENT_STATUS. Add debug log. -- GnuPG-bug-id: 3825 Signed-off-by: NIIBE Yutaka --- scd/apdu.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/scd/apdu.c b/scd/apdu.c index 6758e69e8..e797c09a1 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -667,27 +667,29 @@ pcsc_get_status (int slot, unsigned int *status, int on_wire) return pcsc_error_to_sw (err); } - reader_table[slot].pcsc.current_state = - (rdrstates[0].event_state & ~PCSC_STATE_CHANGED); - - /* log_debug */ - /* ("pcsc_get_status_change: %s%s%s%s%s%s%s%s%s%s\n", */ - /* (rdrstates[0].event_state & PCSC_STATE_IGNORE)? " ignore":"", */ - /* (rdrstates[0].event_state & PCSC_STATE_CHANGED)? " changed":"", */ - /* (rdrstates[0].event_state & PCSC_STATE_UNKNOWN)? " unknown":"", */ - /* (rdrstates[0].event_state & PCSC_STATE_UNAVAILABLE)?" unavail":"", */ - /* (rdrstates[0].event_state & PCSC_STATE_EMPTY)? " empty":"", */ - /* (rdrstates[0].event_state & PCSC_STATE_PRESENT)? " present":"", */ - /* (rdrstates[0].event_state & PCSC_STATE_ATRMATCH)? " atr":"", */ - /* (rdrstates[0].event_state & PCSC_STATE_EXCLUSIVE)? " excl":"", */ - /* (rdrstates[0].event_state & PCSC_STATE_INUSE)? " unuse":"", */ - /* (rdrstates[0].event_state & PCSC_STATE_MUTE)? " mute":"" ); */ + if ((rdrstates[0].event_state & PCSC_STATE_CHANGED)) + reader_table[slot].pcsc.current_state = + (rdrstates[0].event_state & ~PCSC_STATE_CHANGED); + + if (DBG_CARD_IO) + log_debug + ("pcsc_get_status_change: %s%s%s%s%s%s%s%s%s%s\n", + (rdrstates[0].event_state & PCSC_STATE_IGNORE)? " ignore":"", + (rdrstates[0].event_state & PCSC_STATE_CHANGED)? " changed":"", + (rdrstates[0].event_state & PCSC_STATE_UNKNOWN)? " unknown":"", + (rdrstates[0].event_state & PCSC_STATE_UNAVAILABLE)?" unavail":"", + (rdrstates[0].event_state & PCSC_STATE_EMPTY)? " empty":"", + (rdrstates[0].event_state & PCSC_STATE_PRESENT)? " present":"", + (rdrstates[0].event_state & PCSC_STATE_ATRMATCH)? " atr":"", + (rdrstates[0].event_state & PCSC_STATE_EXCLUSIVE)? " excl":"", + (rdrstates[0].event_state & PCSC_STATE_INUSE)? " unuse":"", + (rdrstates[0].event_state & PCSC_STATE_MUTE)? " mute":"" ); *status = 0; - if ( (rdrstates[0].event_state & PCSC_STATE_PRESENT) ) + if ( (reader_table[slot].pcsc.current_state & PCSC_STATE_PRESENT) ) { *status |= APDU_CARD_PRESENT; - if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) ) + if ( !(reader_table[slot].pcsc.current_state & PCSC_STATE_MUTE) ) *status |= APDU_CARD_ACTIVE; } #ifndef HAVE_W32_SYSTEM @@ -696,7 +698,7 @@ pcsc_get_status (int slot, unsigned int *status, int on_wire) mode. */ if ( (*status & (APDU_CARD_PRESENT|APDU_CARD_ACTIVE)) == (APDU_CARD_PRESENT|APDU_CARD_ACTIVE) - && !(rdrstates[0].event_state & PCSC_STATE_INUSE) ) + && !(reader_table[slot].pcsc.current_state & PCSC_STATE_INUSE) ) *status |= APDU_CARD_USABLE; #else /* Some winscard drivers may set EXCLUSIVE and INUSE at the same -- cgit v1.2.3 From 655f0b9ad0138e6f960bf4befaf0eea569256614 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Mon, 12 Mar 2018 10:17:05 +0900 Subject: scd: Fix typo in previous commit. Signed-off-by: NIIBE Yutaka --- scd/apdu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scd/apdu.c b/scd/apdu.c index e797c09a1..2ae6253ff 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -682,7 +682,7 @@ pcsc_get_status (int slot, unsigned int *status, int on_wire) (rdrstates[0].event_state & PCSC_STATE_PRESENT)? " present":"", (rdrstates[0].event_state & PCSC_STATE_ATRMATCH)? " atr":"", (rdrstates[0].event_state & PCSC_STATE_EXCLUSIVE)? " excl":"", - (rdrstates[0].event_state & PCSC_STATE_INUSE)? " unuse":"", + (rdrstates[0].event_state & PCSC_STATE_INUSE)? " inuse":"", (rdrstates[0].event_state & PCSC_STATE_MUTE)? " mute":"" ); *status = 0; -- cgit v1.2.3 From 71e5282c25ba812c7091e587edd721839bc4c2ac Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 13 Mar 2018 12:05:57 +0900 Subject: scd: Fix for GNU/Linux suspend/resume. * configure.ac (require_pipe_to_unblock_pselect): Default is "yes". * scd/scdaemon.c (scd_kick_the_loop): Minor clean up. -- Normally SIGCONT or SIGUSR2 works for unblocking pselect. But on my machine with GNU/Linux, when a machine is suspend/resume-ed, pselect keeps blocked, while signal itself is delivered. It's better to use pipe. Signed-off-by: NIIBE Yutaka --- configure.ac | 3 ++- scd/scdaemon.c | 6 ++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 8252db9a1..086af12ec 100644 --- a/configure.ac +++ b/configure.ac @@ -639,7 +639,7 @@ have_android_system=no use_simple_gettext=no use_ldapwrapper=yes mmap_needed=yes -require_pipe_to_unblock_pselect=no +require_pipe_to_unblock_pselect=yes case "${host}" in *-mingw32*) # special stuff for Windoze NT @@ -654,6 +654,7 @@ case "${host}" in have_w32_system=yes require_iconv=no use_ldapwrapper=no # Fixme: Do this only for CE. + require_pipe_to_unblock_pselect=no case "${host}" in *-mingw32ce*) have_w32ce_system=yes diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 91b559925..e63aca72f 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -1206,18 +1206,16 @@ start_connection_thread (void *arg) void scd_kick_the_loop (void) { - int ret; - /* Kick the select loop. */ #ifdef HAVE_W32_SYSTEM - ret = SetEvent (the_event); + int ret = SetEvent (the_event); if (ret == 0) log_error ("SetEvent for scd_kick_the_loop failed: %s\n", w32_strerror (-1)); #elif defined(HAVE_PSELECT_NO_EINTR) write (notify_fd, "", 1); #else - ret = kill (main_thread_pid, SIGCONT); + int ret = kill (main_thread_pid, SIGCONT); if (ret < 0) log_error ("SetEvent for scd_kick_the_loop failed: %s\n", gpg_strerror (gpg_error_from_syserror ())); -- cgit v1.2.3 From c84bae69e9e02923f7180e09d161cb0b13257436 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 13 Mar 2018 12:53:49 +0900 Subject: scd: After fatal error, shutdown a reader. * scd/apdu.c (pcsc_send_apdu): Notify main loop after fatal errors. -- GnuPG-bug-id: 3825 Signed-off-by: NIIBE Yutaka --- scd/apdu.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scd/apdu.c b/scd/apdu.c index 2ae6253ff..cd98cc91c 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -229,6 +229,7 @@ static npth_mutex_t reader_table_lock; #define PCSC_E_READER_UNAVAILABLE 0x80100017 #define PCSC_E_NO_SERVICE 0x8010001D #define PCSC_E_SERVICE_STOPPED 0x8010001E +#define PCSC_W_RESET_CARD 0x80100068 #define PCSC_W_REMOVED_CARD 0x80100069 /* Fix pcsc-lite ABI incompatibility. */ @@ -751,6 +752,14 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen, log_error ("pcsc_transmit failed: %s (0x%lx)\n", pcsc_error_string (err), err); + /* Handle fatal errors which require shutdown of reader. */ + if (err == PCSC_E_NOT_TRANSACTED || err == PCSC_W_RESET_CARD + || err == PCSC_W_REMOVED_CARD) + { + reader_table[slot].pcsc.current_state = PCSC_STATE_UNAWARE; + scd_kick_the_loop (); + } + return pcsc_error_to_sw (err); } -- cgit v1.2.3 From fd23a0524d8060ed12d87c679b7823686614aaee Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 15 Mar 2018 23:59:22 +0900 Subject: scd: Fix suspend/resume handling for CCID driver. * scd/ccid-driver.c (intr_cb): Try submitting INTERRUPT urb to see if it's suspend/resume. -- Upon suspend/resume, LIBUSB_TRANSFER_NO_DEVICE is returned, since all URBs are cancelled. We need to see if it's real NODEV error or its by suspend/resume. We can distinguish by sending URB again. Signed-off-by: NIIBE Yutaka --- scd/ccid-driver.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index 5046da555..f33a36c83 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -1467,7 +1467,8 @@ intr_cb (struct libusb_transfer *transfer) DEBUGOUT_1 ("CCID: interrupt callback %d\n", transfer->status); - if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) + if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT + || transfer->status == LIBUSB_TRANSFER_NO_DEVICE) { int err; -- cgit v1.2.3 From 2c85e202bc30231b9555100dec0c490c60d7b88c Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 16 Mar 2018 11:27:33 +0900 Subject: scd: Better user interaction for factory-reset. * g10/card-util.c (factory_reset): Dummy PIN size is now 32-byte. Connect the card again at the last step. -- Before the change, a user has to quit the session to continue. Now, it is possible to type RET in the session and see if it's really done. Signed-off-by: NIIBE Yutaka --- g10/card-util.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/g10/card-util.c b/g10/card-util.c index bda4e83b9..7616dbb5b 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -659,7 +659,7 @@ current_card_status (ctrl_t ctrl, estream_t fp, /* Print all available information for specific card with SERIALNO. Print all available information for current card when SERIALNO is NULL. - Or print llfor all cards when SERIALNO is "all". */ + Or print for all cards when SERIALNO is "all". */ void card_status (ctrl_t ctrl, estream_t fp, const char *serialno) { @@ -1792,6 +1792,7 @@ factory_reset (void) scd apdu 00 20 00 83 08 40 40 40 40 40 40 40 40 scd apdu 00 e6 00 00 scd apdu 00 44 00 00 + scd reset /echo Card has been reset to factory defaults but tries to find out something about the card first. @@ -1804,7 +1805,7 @@ factory_reset (void) else if (err) { log_error (_("OpenPGP card not available: %s\n"), gpg_strerror (err)); - return; + goto leave; } if (!termstate) @@ -1854,10 +1855,16 @@ factory_reset (void) command because there is no machinery in scdaemon to catch the verify command and ask for the PIN when the "APDU" command is used. */ + /* Here, the length of dummy wrong PIN is 32-byte, also + supporting authentication with KDF DO. */ for (i=0; i < 4; i++) - send_apdu ("00200081084040404040404040", "VERIFY", 0xffff); + send_apdu ("0020008120" + "40404040404040404040404040404040" + "40404040404040404040404040404040", "VERIFY", 0xffff); for (i=0; i < 4; i++) - send_apdu ("00200083084040404040404040", "VERIFY", 0xffff); + send_apdu ("0020008320" + "40404040404040404040404040404040" + "40404040404040404040404040404040", "VERIFY", 0xffff); /* Send terminate datafile command. */ err = send_apdu ("00e60000", "TERMINATE DF", 0x6985); @@ -1873,8 +1880,16 @@ factory_reset (void) /* Finally we reset the card reader once more. */ err = send_apdu (NULL, "RESET", 0); - if (err) - goto leave; + + /* Then, connect the card again. */ + if (!err) + { + char *serialno0; + + err = agent_scd_serialno (&serialno0, NULL); + if (!err) + xfree (serialno0); + } leave: xfree (answer); -- cgit v1.2.3 From 11bbd99477ef5ba5b7db0c17607b10af03c68afb Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Mon, 19 Mar 2018 16:36:30 +0900 Subject: scd: signal mask should be set just after npth_init. * scd/scdaemon.c (setup_signal_mask): New. (main): Call setup_signal_mask. (handle_connections): Remove signal mask setup. -- For new thread, signal mask is inherited by thread creation. Thus, it is best to setup signal mask just after npth_init. Signed-off-by: NIIBE Yutaka --- scd/scdaemon.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/scd/scdaemon.c b/scd/scdaemon.c index e63aca72f..8f8a02619 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -393,7 +393,21 @@ cleanup (void) } } - +static void +setup_signal_mask (void) +{ +#ifndef HAVE_W32_SYSTEM + npth_sigev_init (); + npth_sigev_add (SIGHUP); + npth_sigev_add (SIGUSR1); + npth_sigev_add (SIGUSR2); + npth_sigev_add (SIGINT); + npth_sigev_add (SIGCONT); + npth_sigev_add (SIGTERM); + npth_sigev_fini (); + main_thread_pid = getpid (); +#endif +} int main (int argc, char **argv ) @@ -744,6 +758,7 @@ main (int argc, char **argv ) #endif npth_init (); + setup_signal_mask (); gpgrt_set_syscall_clamp (npth_unprotect, npth_protect); /* If --debug-allow-core-dump has been given we also need to @@ -884,6 +899,7 @@ main (int argc, char **argv ) /* This is the child. */ npth_init (); + setup_signal_mask (); gpgrt_set_syscall_clamp (npth_unprotect, npth_protect); /* Detach from tty and put process into a new session. */ @@ -1290,16 +1306,6 @@ handle_connections (int listen_fd) events[0] = the_event = h2; } } -#else - npth_sigev_init (); - npth_sigev_add (SIGHUP); - npth_sigev_add (SIGUSR1); - npth_sigev_add (SIGUSR2); - npth_sigev_add (SIGINT); - npth_sigev_add (SIGCONT); - npth_sigev_add (SIGTERM); - npth_sigev_fini (); - main_thread_pid = getpid (); #endif FD_ZERO (&fdset); -- cgit v1.2.3 From 983f7b2acbd1e7580652bbeb0c3d64f9dd19d9e4 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 15 Mar 2018 08:44:52 +0100 Subject: gpg: Fix out-of-bound read in subpacket enumeration * g10/parse-packet.c (enum_sig_subpkt): Check buflen before reading the type octet. Print diagnostic. -- If the final subpacket has only a length header evaluating to zero and missing the type octet, a read could happen right behind the buffer. Valgrind detected this. Fix is obvious. Note that the further parsing of the subpacket is still okay because it always checks the length. Note further that --list-packets uses a different code path and already reported an error. Reported-by: Philippe Antoine He provided a test file copied below. Running "gpg -v --verify" on it triggered the bug. -----BEGIN PGP ARMORED FILE----- Comment: Use "gpg --dearmor" for unpacking kA0DAAoBov87N383R0QBrQJhYgZsb2wucHlaqTVWYnl0ZXMgPSBbMHg1LCAweDY0 LCAweDRjLCAweGM0LCAweDMsIDB4MCwgMHg0LCAweDAsIDB4YWMsIDB4YSwgMHhj MSwgMHhjMSwgMHgyLCAweDEsIDB4MiwgMHg3LCAweDQwLCAweDIsIDB4MiwgMHgy LCAweDIsIDB4MiwgMHgyLCAweDIsIDB4MiwgMHgyLCAweDJkLCAweGRkLCAweDIs IDB4MiwgMHgyLCAweDIsIDB4MiwgMHgyLCAweDIsIDB4MiwgMHgyLCAweDIsIDB4 MiwgMHgyLCAweDIsIDB4MiwgMHgyLCAweDIsIDB4NzcsIDB4ODcsIDB4MiwgMHgy LCAweDIsIDB4MiwgMHgyLCAweDIsIDB4MiwgMHgyLCAweDIsIDB4MiwgMHgyLCAw eDIsIDB4MiwgMHgyLCAweDIsIDB4MiwgMHg3NywgMHg4NywgMHgyLCAweDIsIDB4 MiwgMHgyLCAweDIsIDB4MiwgMHgyLCAweDIsIDB4MiwgMHgyLCAweDIsIDB4Miwg MHgyLCAweDIsIDB4MiwgMHgyLCAweDc3LCAweDg3LCAweDIsIDB4MiwgMHgyLCAw eDIsIDB4MiwgMHgyLCAweDIsIDB4MCwgMHhhZF0KCmZvciBpIGluIHJhbmdlKGxl bihieXRlcykpOgogICAgaWYgaSUxNiA9PSAwOgogICAgICAgIHByaW50CiAgICAg ICAgcHJpbnQgIiUwNngiICUgaSwKICAgIHByaW50ICIlMDJ4ICIgJSBieXRlc1tp XSwKiQJNBAABCgAeFiEEU+Y3aLjDLA3x+9Epov87N383R0QFAlqpNVYAAAoJEKL/ Ozd/N0dElccP/jBAcFHyeMl7kop71Q7/5NPu3DNULmdUzOZPle8PVjNURT4PSELF qpJ8bd9PAsO4ZkUGwssY4Kfb1iG5cR/a8ADknNd0Cj9/QA2KMVNmgYtReuttAjvn hQRm2VY0tvDCVAPI/z8OnV/NpOcbk8kSwE+shLsP7EwqL5MJNMXKqzm1uRxGNYxr 8TNuECo3DO64O2NZLkMDXqq6lg+lSxvDtXKxzKXgVC+GMtOE56lDwxWLqr39f9Ae Pn0q2fVBKhJfpUODeEbYSYUp2hhmMUIJL/ths9MvyRZ9Z/bHCseFPT58Pgx6g+MP q+iHnVZEIVb38XG+rTYW9hvctkRZP/azhpa7eO8JAZuFNeBGr4IGapwzFPvQSF4B wBXBu0+PPrV9VJVe98P4nw2xcuJmkn6mgZhRVYSqDIhY64bSTgQxb/pdtGwrTjtL WoUKVI+joLRPnDmwexH9+QJCB+uA6RsN/LqsQfDseyr40Z6dHJRqWGgP3ll6iZgw WF768uiIDJD8d4fegVnkpcH98Hm0I/dKsMR1MGV/sBxYC8mAOcOWwSPNGDqPlwwR eWPdr1O6CoYEWwiZMicSe0b5TsjB5nkAWMy7c9RyhtMJzCQ/hFpycpj0A0Zs+OGa eJQMZZV0s8AQZ04JzoX0zRpe0RcTyJn3Tr6QGbVi9tr+QdKHFuDMUqoX =qYZP -----END PGP ARMORED FILE----- Signed-off-by: Werner Koch --- g10/parse-packet.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/g10/parse-packet.c b/g10/parse-packet.c index eee14f64e..db4e3ab69 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -1702,6 +1702,8 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype, } if (buflen < n) goto too_short; + if (!buflen) + goto no_type_byte; type = *buffer; if (type & 0x80) { @@ -1776,6 +1778,13 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype, if (start) *start = -1; return NULL; + + no_type_byte: + if (opt.verbose) + log_info ("type octet missing in subpacket\n"); + if (start) + *start = -1; + return NULL; } -- cgit v1.2.3 From 34ec0125614674725cb78cf9f8d5e6b0f8c64064 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 21 Mar 2018 19:45:31 +0100 Subject: doc: Typo fix in comment. -- --- g10/parse-packet.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/g10/parse-packet.c b/g10/parse-packet.c index db4e3ab69..a64d4f723 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -964,10 +964,10 @@ skip_packet (IOBUF inp, int pkttype, unsigned long pktlen, int partial) } -/* Read PKTLEN bytes form INP and return them in a newly allocated - buffer. In case of an error (including reading fewer than PKTLEN - bytes from INP before EOF is returned), NULL is returned and an - error message is logged. */ +/* Read PKTLEN bytes from INP and return them in a newly allocated + * buffer. In case of an error (including reading fewer than PKTLEN + * bytes from INP before EOF is returned), NULL is returned and an + * error message is logged. */ static void * read_rest (IOBUF inp, size_t pktlen) { -- cgit v1.2.3 From 0152ba7c987443d641ce1091c79f90ef2cc46498 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 22 Mar 2018 15:50:31 +0900 Subject: scd: Support KDF DO setup. * g10/call-agent.c (learn_status_cb): Parse the capability for KDF. * g10/card-util.c (gen_kdf_data, kdf_setup): New. (card_edit): New admin command cmdKDFSETUP to call kdf_setup. * scd/app-openpgp.c (do_getattr): Emit KDF capability. -- GnuPG-bug-id: 3823 Signed-off-by: NIIBE Yutaka --- g10/call-agent.c | 2 ++ g10/call-agent.h | 1 + g10/card-util.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++- scd/app-openpgp.c | 5 +-- 4 files changed, 110 insertions(+), 3 deletions(-) diff --git a/g10/call-agent.c b/g10/call-agent.c index ea530e7ac..fdacf6a90 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -591,6 +591,8 @@ learn_status_cb (void *opaque, const char *line) parm->extcap.ki = abool; else if (!strcmp (p, "aac")) parm->extcap.aac = abool; + else if (!strcmp (p, "kdf")) + parm->extcap.kdf = abool; else if (!strcmp (p, "si")) parm->status_indicator = strtoul (p2, NULL, 10); } diff --git a/g10/call-agent.h b/g10/call-agent.h index 53775c5c8..8de0d13fd 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -67,6 +67,7 @@ struct agent_card_info_s struct { unsigned int ki:1; /* Key import available. */ unsigned int aac:1; /* Algorithm attributes are changeable. */ + unsigned int kdf:1; /* KDF object to support PIN hashing available. */ } extcap; unsigned int status_indicator; }; diff --git a/g10/card-util.c b/g10/card-util.c index 7616dbb5b..d78e9bd8e 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -1897,6 +1897,104 @@ factory_reset (void) } +#define USER_PIN_DEFAULT "123456" +#define ADMIN_PIN_DEFAULT "12345678" +#define KDF_DATA_LENGTH 110 + +/* Generate KDF data. */ +static gpg_error_t +gen_kdf_data (unsigned char *data) +{ + const unsigned char h0[] = { 0x81, 0x01, 0x03, + 0x82, 0x01, 0x08, + 0x83, 0x04 }; + const unsigned char h1[] = { 0x84, 0x08 }; + const unsigned char h2[] = { 0x85, 0x08 }; + const unsigned char h3[] = { 0x86, 0x08 }; + const unsigned char h4[] = { 0x87, 0x20 }; + const unsigned char h5[] = { 0x88, 0x20 }; + unsigned char *p, *salt_user, *salt_admin; + unsigned char s2k_char; + unsigned int iterations; + unsigned char count_4byte[4]; + gpg_error_t err = 0; + + p = data; + + s2k_char = encode_s2k_iterations (0); + iterations = S2K_DECODE_COUNT (s2k_char); + count_4byte[0] = (iterations >> 24) & 0xff; + count_4byte[1] = (iterations >> 16) & 0xff; + count_4byte[2] = (iterations >> 8) & 0xff; + count_4byte[3] = (iterations & 0xff); + + memcpy (p, h0, sizeof h0); + p += sizeof h0; + memcpy (p, count_4byte, sizeof count_4byte); + p += sizeof count_4byte; + memcpy (p, h1, sizeof h1); + salt_user = (p += sizeof h1); + gcry_randomize (p, 8, GCRY_STRONG_RANDOM); + p += 8; + memcpy (p, h2, sizeof h2); + p += sizeof h2; + gcry_randomize (p, 8, GCRY_STRONG_RANDOM); + p += 8; + memcpy (p, h3, sizeof h3); + salt_admin = (p += sizeof h3); + gcry_randomize (p, 8, GCRY_STRONG_RANDOM); + p += 8; + memcpy (p, h4, sizeof h4); + p += sizeof h4; + err = gcry_kdf_derive (USER_PIN_DEFAULT, strlen (USER_PIN_DEFAULT), + GCRY_KDF_ITERSALTED_S2K, DIGEST_ALGO_SHA256, + salt_user, 8, iterations, 32, p); + p += 32; + if (!err) + { + memcpy (p, h5, sizeof h5); + p += sizeof h5; + err = gcry_kdf_derive (ADMIN_PIN_DEFAULT, strlen (ADMIN_PIN_DEFAULT), + GCRY_KDF_ITERSALTED_S2K, DIGEST_ALGO_SHA256, + salt_admin, 8, iterations, 32, p); + } + + return err; +} + +/* Setup KDF data object which is used for PIN authentication. */ +static void +kdf_setup (void) +{ + struct agent_card_info_s info; + gpg_error_t err; + unsigned char kdf_data[KDF_DATA_LENGTH]; + + memset (&info, 0, sizeof info); + + err = agent_scd_getattr ("EXTCAP", &info); + if (err) + { + log_error (_("error getting card info: %s\n"), gpg_strerror (err)); + return; + } + + if (!info.extcap.kdf) + { + log_error (_("This command is not supported by this card\n")); + goto leave; + } + + if (!(err = gen_kdf_data (kdf_data)) + && !(err = agent_scd_setattr ("KDF", kdf_data, KDF_DATA_LENGTH, NULL))) + err = agent_scd_getattr ("KDF", &info); + + if (err) + log_error (_("error for setup KDF: %s\n"), gpg_strerror (err)); + + leave: + agent_release_card_info (&info); +} /* Data used by the command parser. This needs to be outside of the function scope to allow readline based command completion. */ @@ -1906,7 +2004,7 @@ enum cmdids cmdQUIT, cmdADMIN, cmdHELP, cmdLIST, cmdDEBUG, cmdVERIFY, cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSEX, cmdCAFPR, cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT, - cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET, + cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET, cmdKDFSETUP, cmdINVCMD }; @@ -1939,6 +2037,7 @@ static struct { "verify" , cmdVERIFY, 0, N_("verify the PIN and list all data")}, { "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code") }, { "factory-reset", cmdFACTORYRESET, 1, N_("destroy all keys and data")}, + { "kdf-setup", cmdKDFSETUP, 1, N_("setup KDF for PIN authentication")}, /* Note, that we do not announce these command yet. */ { "privatedo", cmdPRIVATEDO, 0, NULL }, { "readcert", cmdREADCERT, 0, NULL }, @@ -2222,6 +2321,10 @@ card_edit (ctrl_t ctrl, strlist_t commands) factory_reset (); break; + case cmdKDFSETUP: + kdf_setup (); + break; + case cmdQUIT: goto leave; diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index f3065edf0..e0c9d5959 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1018,7 +1018,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) snprintf (tmp, sizeof tmp, "gc=%d ki=%d fc=%d pd=%d mcl3=%u aac=%d " - "sm=%d si=%u dec=%d bt=%d", + "sm=%d si=%u dec=%d bt=%d kdf=%d", app->app_local->extcap.get_challenge, app->app_local->extcap.key_import, app->app_local->extcap.change_force_chv, @@ -1032,7 +1032,8 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) : 0), app->app_local->status_indicator, app->app_local->extcap.has_decrypt, - app->app_local->extcap.has_button); + app->app_local->extcap.has_button, + app->app_local->extcap.kdf_do); send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0); return 0; } -- cgit v1.2.3 From 165bc38cefbc03515403b60b704cabf4dc0b71f4 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 22 Mar 2018 10:23:00 +0100 Subject: gpg: Implement --dry-run for --passwd. * g10/keyedit.c (change_passphrase): Take care of --dry-run. Signed-off-by: Werner Koch --- doc/gpg.texi | 4 +++- g10/keyedit.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index e3c3662a8..ad044ffc0 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -1126,7 +1126,9 @@ all affected self-signatures is set one second ahead. @opindex passwd Change the passphrase of the secret key belonging to the certificate specified as @var{user-id}. This is a shortcut for the sub-command -@code{passwd} of the edit key menu. +@code{passwd} of the edit key menu. When using together with the +option @option{--dry-run} this will not actually change the passphrase +but check that the current passphrase is correct. @end table diff --git a/g10/keyedit.c b/g10/keyedit.c index 17cf7d6ea..4ade5cdba 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -1134,8 +1134,10 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock) if (err) goto leave; + /* Note that when using --dry-run we don't change the + * passphrase but merely verify the current passphrase. */ desc = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_NORMAL, 1); - err = agent_passwd (ctrl, hexgrip, desc, 0, + err = agent_passwd (ctrl, hexgrip, desc, !!opt.dry_run, &cache_nonce, &passwd_nonce); xfree (desc); -- cgit v1.2.3 From 5400a5bb77bddcb14c94d9405312d6181322b090 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 23 Mar 2018 15:16:16 +0900 Subject: build: Fix the manual source field. Signed-off-by: NIIBE Yutaka --- doc/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Makefile.am b/doc/Makefile.am index aba84ba3c..a857c8e6e 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -85,7 +85,7 @@ DVIPS = TEXINPUTS="$(srcdir)$(PATH_SEPARATOR)$$TEXINPUTS" dvips AM_MAKEINFOFLAGS = -I $(srcdir) --css-ref=/share/site.css YAT2M_OPTIONS = -I $(srcdir) \ - --release "GnuPG @PACKAGE_VERSION@" --source "GNU Privacy Guard 2.1" + --release "GnuPG @PACKAGE_VERSION@" --source "GNU Privacy Guard 2.2" myman_sources = gnupg7.texi gpg.texi gpgsm.texi gpg-agent.texi \ dirmngr.texi scdaemon.texi tools.texi wks.texi -- cgit v1.2.3 From 05c55ee260edc07cd19da56dfd00347bfe3f529c Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 23 Mar 2018 08:14:58 +0100 Subject: agent: New OPTION pretend-request-origin * common/shareddefs.h (request_origin_t): New. * common/agent-opt.c (parse_request_origin): New. (str_request_origin): New. * agent/command.c (option_handler): Implement new option. -- This allows to pretend that a request originated from the extra or browser socket. Signed-off-by: Werner Koch --- agent/command.c | 15 +++++++++++++++ common/agent-opt.c | 35 +++++++++++++++++++++++++++++++++++ common/shareddefs.h | 13 +++++++++++++ doc/gpg-agent.texi | 21 +++++++++++++++++++++ 4 files changed, 84 insertions(+) diff --git a/agent/command.c b/agent/command.c index f9bc6ca96..8bb9b6a70 100644 --- a/agent/command.c +++ b/agent/command.c @@ -3101,6 +3101,21 @@ option_handler (assuan_context_t ctx, const char *key, const char *value) ctrl->s2k_count = 0; } } + else if (!strcmp (key, "pretend-request-origin")) + { + log_assert (!ctrl->restricted); + switch (parse_request_origin (value)) + { + case REQUEST_ORIGIN_LOCAL: ctrl->restricted = 0; break; + case REQUEST_ORIGIN_REMOTE: ctrl->restricted = 1; break; + case REQUEST_ORIGIN_BROWSER: ctrl->restricted = 2; break; + default: + err = gpg_error (GPG_ERR_INV_VALUE); + /* Better pretend to be remote in case of a bad value. */ + ctrl->restricted = 1; + break; + } + } else err = gpg_error (GPG_ERR_UNKNOWN_OPTION); diff --git a/common/agent-opt.c b/common/agent-opt.c index b32448242..6d9f9e77e 100644 --- a/common/agent-opt.c +++ b/common/agent-opt.c @@ -69,3 +69,38 @@ str_pinentry_mode (pinentry_mode_t mode) } return "?"; } + + +/* Parse VALUE and return an integer representing a request_origin_t. + * (-1) is returned for an invalid VALUE. */ +int +parse_request_origin (const char *value) +{ + int result; + + if (!strcmp (value, "none") || !strcmp (value, "local")) + result = REQUEST_ORIGIN_LOCAL; + else if (!strcmp (value, "remote")) + result = REQUEST_ORIGIN_REMOTE; + else if (!strcmp (value, "browser")) + result = REQUEST_ORIGIN_BROWSER; + else + result = -1; + + return result; +} + + +/* Return the string representation for the request origin. Returns + * "?" for an invalid mode. */ +const char * +str_request_origin (request_origin_t mode) +{ + switch (mode) + { + case REQUEST_ORIGIN_LOCAL: return "local"; + case REQUEST_ORIGIN_REMOTE: return "remote"; + case REQUEST_ORIGIN_BROWSER: return "browser"; + } + return "?"; +} diff --git a/common/shareddefs.h b/common/shareddefs.h index 1594f6650..4b1442133 100644 --- a/common/shareddefs.h +++ b/common/shareddefs.h @@ -39,10 +39,23 @@ typedef enum pinentry_mode_t; +/* Values for the request origin. */ +typedef enum + { + REQUEST_ORIGIN_LOCAL = 0, + REQUEST_ORIGIN_REMOTE, + REQUEST_ORIGIN_BROWSER + } +request_origin_t; + + /*-- agent-opt.c --*/ int parse_pinentry_mode (const char *value); const char *str_pinentry_mode (pinentry_mode_t mode); +int parse_request_origin (const char *value); +const char *str_request_origin (request_origin_t mode); + #endif /*GNUPG_COMMON_SHAREDDEFS_H*/ diff --git a/doc/gpg-agent.texi b/doc/gpg-agent.texi index 4781bbdca..bcce03329 100644 --- a/doc/gpg-agent.texi +++ b/doc/gpg-agent.texi @@ -1581,6 +1581,27 @@ option is valid for the entire session or until reset to 0. This option is useful if the key is later used on boxes which are either much slower or faster than the actual box. +@item pretend-request-origin +This option switches the connection into a restricted mode which +handles all further commands in the same way as they would be handled +when originating from the extra or browser socket. Note that this +option is not available in the restricted mode. Valid values for this +option are: + + @table @code + @item none + @itemx local + This is a NOP and leaves the connection in the standard way. + + @item remote + Pretend to come from a remote origin in the same way as connections + from the @option{--extra-socket}. + + @item browser + Pretend to come from a local web browser in the same way as connections + from the @option{--browser-socket}. + @end table + @end table -- cgit v1.2.3 From 2cd35df5db3c4dfe37616dcfb1fcc644959449ef Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 23 Mar 2018 09:06:20 +0100 Subject: gpg,sm: New option --request-origin. * g10/gpg.c (oRequestOrigin): New const. (opts): New option --request-origin. (main): Parse that option. * g10/options.h (struct opt): Add field request_origin. * g10/call-agent.c (start_agent): Send option to the agent. * sm/gpgsm.c (oRequestOrigin): New const. (opts): New option --request-origin. (main): Parse that option. * sm/gpgsm.h (struct opt): Add field request_origin. * sm/call-agent.c (start_agent): Send option to the agent. Signed-off-by: Werner Koch --- doc/gpg.texi | 9 +++++++++ doc/gpgsm.texi | 9 +++++++++ g10/call-agent.c | 17 +++++++++++++++++ g10/gpg.c | 8 ++++++++ g10/options.h | 1 + sm/call-agent.c | 14 ++++++++++++++ sm/gpgsm.c | 8 ++++++++ sm/gpgsm.h | 1 + 8 files changed, 67 insertions(+) diff --git a/doc/gpg.texi b/doc/gpg.texi index ad044ffc0..d840b8573 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -3131,6 +3131,15 @@ are: Pinentry the user is not prompted again if he enters a bad password. @end table +@item --request-origin @var{origin} +@opindex request-origin +Tell gpg to assume that the operation ultimately originated at +@var{origin}. Depending on the origin certain restrictions are applied +and the Pinentry may include an extra note on the origin. Supported +values for @var{origin} are: @code{local} which is the default, +@code{remote} to indicate a remote origin or @code{browser} for an +operation requested by a web browser. + @item --command-fd @var{n} @opindex command-fd This is a replacement for the deprecated shared-memory IPC mode. diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi index 7c6c3153f..ebe58bc61 100644 --- a/doc/gpgsm.texi +++ b/doc/gpgsm.texi @@ -765,6 +765,15 @@ are: Pinentry the user is not prompted again if he enters a bad password. @end table +@item --request-origin @var{origin} +@opindex request-origin +Tell gpgsm to assume that the operation ultimately originated at +@var{origin}. Depending on the origin certain restrictions are applied +and the Pinentry may include an extra note on the origin. Supported +values for @var{origin} are: @code{local} which is the default, +@code{remote} to indicate a remote origin or @code{browser} for an +operation requested by a web browser. + @item --no-common-certs-import @opindex no-common-certs-import Suppress the import of common certificates on keybox creation. diff --git a/g10/call-agent.c b/g10/call-agent.c index fdacf6a90..6ee82a5a4 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -289,6 +289,23 @@ start_agent (ctrl_t ctrl, int flag_for_card) } } + /* Pass on the request origin. */ + if (opt.request_origin) + { + char *tmp = xasprintf ("OPTION pretend-request-origin=%s", + str_request_origin (opt.request_origin)); + rc = assuan_transact (agent_ctx, tmp, + NULL, NULL, NULL, NULL, NULL, NULL); + xfree (tmp); + if (rc) + { + log_error ("setting request origin '%s' failed: %s\n", + str_request_origin (opt.request_origin), + gpg_strerror (rc)); + write_status_error ("set_request_origin", rc); + } + } + /* In DE_VS mode under Windows we require that the JENT RNG * is active. */ #ifdef HAVE_W32_SYSTEM diff --git a/g10/gpg.c b/g10/gpg.c index 62d6131ba..bfff7a567 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -422,6 +422,7 @@ enum cmd_and_opt_values oDisableSignerUID, oSender, oKeyOrigin, + oRequestOrigin, oNoop }; @@ -708,6 +709,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_s (oPassphraseFile, "passphrase-file", "@"), ARGPARSE_s_i (oPassphraseRepeat,"passphrase-repeat", "@"), ARGPARSE_s_s (oPinentryMode, "pinentry-mode", "@"), + ARGPARSE_s_s (oRequestOrigin, "request-origin", "@"), ARGPARSE_s_i (oCommandFD, "command-fd", "@"), ARGPARSE_s_s (oCommandFile, "command-file", "@"), ARGPARSE_s_n (oQuickRandom, "debug-quick-random", "@"), @@ -3096,6 +3098,12 @@ main (int argc, char **argv) log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str); break; + case oRequestOrigin: + opt.request_origin = parse_request_origin (pargs.r.ret_str); + if (opt.request_origin == -1) + log_error (_("invalid request origin '%s'\n"), pargs.r.ret_str); + break; + case oCommandFD: opt.command_fd = translate_sys2libc_fd_int (pargs.r.ret_int, 0); if (! gnupg_fd_valid (opt.command_fd)) diff --git a/g10/options.h b/g10/options.h index 130bec84c..e1bf97fb1 100644 --- a/g10/options.h +++ b/g10/options.h @@ -271,6 +271,7 @@ struct int passphrase_repeat; int pinentry_mode; + int request_origin; int unwrap_encryption; int only_sign_text_ids; diff --git a/sm/call-agent.c b/sm/call-agent.c index 772c9c312..20d879fa4 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -179,6 +179,20 @@ start_agent (ctrl_t ctrl) gpg_strerror (rc)); } + /* Pass on the request origin. */ + if (opt.request_origin) + { + char *tmp = xasprintf ("OPTION pretend-request-origin=%s", + str_request_origin (opt.request_origin)); + rc = assuan_transact (agent_ctx, tmp, + NULL, NULL, NULL, NULL, NULL, NULL); + xfree (tmp); + if (rc) + log_error ("setting request origin '%s' failed: %s\n", + str_request_origin (opt.request_origin), + gpg_strerror (rc)); + } + /* In DE_VS mode under Windows we require that the JENT RNG * is active. */ #ifdef HAVE_W32_SYSTEM diff --git a/sm/gpgsm.c b/sm/gpgsm.c index ab08a52f0..b81e3b6e8 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -125,6 +125,7 @@ enum cmd_and_opt_values { oPassphraseFD, oPinentryMode, + oRequestOrigin, oAssumeArmor, oAssumeBase64, @@ -254,6 +255,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_i (oPassphraseFD, "passphrase-fd", "@"), ARGPARSE_s_s (oPinentryMode, "pinentry-mode", "@"), + ARGPARSE_s_s (oRequestOrigin, "request-origin", "@"), ARGPARSE_s_n (oAssumeArmor, "assume-armor", N_("assume input is in PEM format")), @@ -1160,6 +1162,12 @@ main ( int argc, char **argv) log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str); break; + case oRequestOrigin: + opt.request_origin = parse_request_origin (pargs.r.ret_str); + if (opt.request_origin == -1) + log_error (_("invalid request origin '%s'\n"), pargs.r.ret_str); + break; + /* Input encoding selection. */ case oAssumeArmor: ctrl.autodetect_encoding = 0; diff --git a/sm/gpgsm.h b/sm/gpgsm.h index cd4fc995f..325948aff 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -86,6 +86,7 @@ struct int with_keygrip; /* Option --with-keygrip active. */ int pinentry_mode; + int request_origin; int armor; /* force base64 armoring (see also ctrl.with_base64) */ int no_armor; /* don't try to figure out whether data is base64 armored*/ -- cgit v1.2.3 From 137644c9cb58deaaba6850f2763d9c5f9241cb0b Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 23 Mar 2018 15:07:56 +0100 Subject: sm: Add OPTION request-origin. * sm/server.c: Include shareddefs.h. (option_handler): Add option. -- This is required when running gpgsm in server mode as done by GPGME. Noet that a command line option takes precedence. Signed-off-by: Werner Koch --- sm/server.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sm/server.c b/sm/server.c index 721f3faf0..98505e26d 100644 --- a/sm/server.c +++ b/sm/server.c @@ -32,6 +32,7 @@ #include "../common/sysutils.h" #include "../common/server-help.h" #include "../common/asshelp.h" +#include "../common/shareddefs.h" #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t)) @@ -289,6 +290,17 @@ option_handler (assuan_context_t ctx, const char *key, const char *value) ctrl->offline = i; } } + else if (!strcmp (key, "request-origin")) + { + if (!opt.request_origin) + { + int i = parse_request_origin (value); + if (i == -1) + err = gpg_error (GPG_ERR_INV_VALUE); + else + opt.request_origin = i; + } + } else err = gpg_error (GPG_ERR_UNKNOWN_OPTION); -- cgit v1.2.3 From 5f00531463ebc0e606c502696962426007545bb7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 26 Mar 2018 16:26:46 +0200 Subject: gpg: Disable unused code parts in tdbio.c * g10/tdbio.c (in_transaction): Comment this var. (put_record_into_cache): Comment the transaction code. (tdbio_sync): Ditto Signed-off-by: Werner Koch --- g10/tdbio.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/g10/tdbio.c b/g10/tdbio.c index 7572b9aeb..fb3cf1504 100644 --- a/g10/tdbio.c +++ b/g10/tdbio.c @@ -114,7 +114,7 @@ static int is_locked; static int db_fd = -1; /* A flag indicating that a transaction is active. */ -static int in_transaction; +/* static int in_transaction; Not yet used. */ @@ -125,7 +125,7 @@ static void create_hashtable (ctrl_t ctrl, TRUSTREC *vr, int type); /* * Take a lock on the trustdb file name. I a lock file can't be - * created the function terminates the process. Excvept for a + * created the function terminates the process. Except for a * different return code the function does nothing if the lock has * already been taken. * @@ -329,6 +329,7 @@ put_record_into_cache (ulong recno, const char *data) } /* No clean entries: We have to flush some dirty entries. */ +#if 0 /* Transactions are not yet used. */ if (in_transaction) { /* But we can't do this while in a transaction. Thus we @@ -352,6 +353,7 @@ put_record_into_cache (ulong recno, const char *data) log_info (_("trustdb transaction too large\n")); return GPG_ERR_RESOURCE_LIMIT; } +#endif if (dirty_count) { @@ -418,8 +420,10 @@ tdbio_sync() if( db_fd == -1 ) open_db(); +#if 0 /* Transactions are not yet used. */ if( in_transaction ) log_bug("tdbio: syncing while in transaction\n"); +#endif if( !cache_is_dirty ) return 0; @@ -560,7 +564,7 @@ tdbio_update_version_record (ctrl_t ctrl) /* * Create and write the trustdb version record. - * + * This is called with the writelock activ. * Returns: 0 on success or an error code. */ static int -- cgit v1.2.3 From 456a3a8e93ea14f821e0e98fb515f284ece98685 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 26 Mar 2018 16:57:04 +0200 Subject: gpg: Fix trustdb updates without lock held. * g10/tdbio.c (is_locked): Turn into a counter. (take_write_lock, release_write_lock): Implement recursive locks. -- On trustdb creation we have this call sequence: init_trustdb -> takes lock tdbio_set_dbname create_version_record tdbio_write_record put_record_into_cache -> takes lock put_record_into_cache -> releases lock init_trustdb -> releases lock The second take lock does noting but the first release lock has already released the lock and the second release lock is a thus a NOP. This is likely the cause for the corrupted trustdb as reported in GnuPG-bug-id: 3839 Signed-off-by: Werner Koch --- g10/tdbio.c | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/g10/tdbio.c b/g10/tdbio.c index fb3cf1504..4940c5ce2 100644 --- a/g10/tdbio.c +++ b/g10/tdbio.c @@ -105,10 +105,11 @@ struct cmp_xdir_struct /* The name of the trustdb file. */ static char *db_name; -/* The handle for locking the trustdb file and a flag to record - whether a lock has been taken. */ +/* The handle for locking the trustdb file and a counter to record how + * often this lock has been taken. That counter is required becuase + * dotlock does not implemen recursive locks. */ static dotlock_t lockhandle; -static int is_locked; +static unsigned int is_locked; /* The file descriptor of the trustdb. */ static int db_fd = -1; @@ -135,6 +136,8 @@ static void create_hashtable (ctrl_t ctrl, TRUSTREC *vr, int type); static int take_write_lock (void) { + int rc; + if (!lockhandle) lockhandle = dotlock_create (db_name, 0); if (!lockhandle) @@ -144,12 +147,16 @@ take_write_lock (void) { if (dotlock_take (lockhandle, -1) ) log_fatal ( _("can't lock '%s'\n"), db_name ); - else - is_locked = 1; - return 0; + rc = 0; } else - return 1; + rc = 1; + + if (opt.lock_once) + is_locked = 1; + else + is_locked++; + return rc; } @@ -160,10 +167,22 @@ take_write_lock (void) static void release_write_lock (void) { - if (!opt.lock_once) - if (!dotlock_release (lockhandle)) - is_locked = 0; + if (opt.lock_once) + return; /* Don't care; here IS_LOCKED is fixed to 1. */ + + if (!is_locked) + { + log_error ("Ooops, tdbio:release_write_lock with no lock held\n"); + return; + } + if (--is_locked) + return; + + if (dotlock_release (lockhandle)) + log_error ("Oops, tdbio:release_write_locked failed\n"); } + + /************************************* ************* record cache ********** -- cgit v1.2.3 From 403aa70c52e56614d65490dea9344113f9cf3d29 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 26 Mar 2018 17:43:40 +0200 Subject: gpg: Return better error codes in case of a too short trustdb. * g10/tdbio.c (tdbio_read_record): Return GPG_ERR_EOF. (tdbio_new_recnum): Never return on error. (lookup_hashtable): Print a more descriptive error in case of !TABLE. -- Also: tdbio_new_recnum had a bug in that it returned an error code and not a record number in the error case. The function is expected to always return a valid new record number. Signed-off-by: Werner Koch --- g10/tdbio.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/g10/tdbio.c b/g10/tdbio.c index 4940c5ce2..7314143af 100644 --- a/g10/tdbio.c +++ b/g10/tdbio.c @@ -1292,6 +1292,13 @@ lookup_hashtable (ulong table, const byte *key, size_t keylen, int msb; int level = 0; + if (!table) + { + rc = gpg_error (GPG_ERR_INV_RECORD); + log_error("lookup_hashtable failed: %s\n", "request for record 0"); + return rc; + } + hashrec = table; next_level: msb = key[level]; @@ -1464,7 +1471,7 @@ tdbio_dump_record (TRUSTREC *rec, estream_t fp) * EXPECTED is not 0 reading any other record type will return an * error. * - * Return: 0 on success, -1 on EOF, or an error code. + * Return: 0 on success or an error code. */ int tdbio_read_record (ulong recnum, TRUSTREC *rec, int expected) @@ -1489,7 +1496,7 @@ tdbio_read_record (ulong recnum, TRUSTREC *rec, int expected) n = read (db_fd, readbuf, TRUST_RECORD_LEN); if (!n) { - return -1; /* eof */ + return gpg_error (GPG_ERR_EOF); } else if (n != TRUST_RECORD_LEN) { @@ -1769,20 +1776,14 @@ tdbio_new_recnum (ctrl_t ctrl) recnum = vr.r.ver.firstfree; rc = tdbio_read_record (recnum, &rec, RECTYPE_FREE); if (rc) - { - log_error (_("%s: error reading free record: %s\n"), - db_name, gpg_strerror (rc)); - return rc; - } + log_fatal (_("%s: error reading free record: %s\n"), + db_name, gpg_strerror (rc)); /* Update dir record. */ vr.r.ver.firstfree = rec.r.free.next; rc = tdbio_write_record (ctrl, &vr); if (rc) - { - log_error (_("%s: error writing dir record: %s\n"), - db_name, gpg_strerror (rc)); - return rc; - } + log_fatal (_("%s: error writing dir record: %s\n"), + db_name, gpg_strerror (rc)); /* Zero out the new record. */ memset (&rec, 0, sizeof rec); rec.rectype = 0; /* Mark as unused record (actually already done @@ -1799,7 +1800,7 @@ tdbio_new_recnum (ctrl_t ctrl) if (offset == (off_t)(-1)) log_fatal ("trustdb: lseek to end failed: %s\n", strerror (errno)); recnum = offset / TRUST_RECORD_LEN; - log_assert (recnum); /* this is will never be the first record */ + log_assert (recnum); /* This will never be the first record */ /* We must write a record, so that the next call to this * function returns another recnum. */ memset (&rec, 0, sizeof rec); @@ -1821,13 +1822,13 @@ tdbio_new_recnum (ctrl_t ctrl) { rc = gpg_error_from_syserror (); log_error (_("trustdb rec %lu: write failed (n=%d): %s\n"), - recnum, n, strerror (errno)); + recnum, n, gpg_strerror (rc)); } } if (rc) log_fatal (_("%s: failed to append a record: %s\n"), - db_name, gpg_strerror (rc)); + db_name, gpg_strerror (rc)); } return recnum ; -- cgit v1.2.3 From a750ebebf35a392f1c72d6aee5618df0d9f25ff7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 26 Mar 2018 18:06:43 +0200 Subject: gpg: Pass CTRL arg to get_trusthashrec. * g10/tdbio.c (get_trusthashrec): Add arg CTRL. (tdbio_search_trust_byfpr): Ditto. (tdbio_search_trust_bypk): Ditto. Signed-off-by: Werner Koch --- g10/tdbdump.c | 2 +- g10/tdbio.c | 16 +++++++++------- g10/tdbio.h | 6 ++++-- g10/trustdb.c | 2 +- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/g10/tdbdump.c b/g10/tdbdump.c index 5ea903f45..2c6f5c2fa 100644 --- a/g10/tdbdump.c +++ b/g10/tdbdump.c @@ -189,7 +189,7 @@ import_ownertrust (ctrl_t ctrl, const char *fname ) while (fprlen < 20) fpr[fprlen++] = 0; - rc = tdbio_search_trust_byfpr (fpr, &rec); + rc = tdbio_search_trust_byfpr (ctrl, fpr, &rec); if( !rc ) { /* found: update */ if (rec.r.trust.ownertrust != otrust) { diff --git a/g10/tdbio.c b/g10/tdbio.c index 7314143af..1e454869d 100644 --- a/g10/tdbio.c +++ b/g10/tdbio.c @@ -974,10 +974,12 @@ tdbio_write_nextcheck (ctrl_t ctrl, ulong stamp) * Return: record number */ static ulong -get_trusthashrec(void) +get_trusthashrec (ctrl_t ctrl) { static ulong trusthashtbl; /* Record number of the trust hashtable. */ + (void)ctrl; + if (!trusthashtbl) { TRUSTREC vr; @@ -1388,7 +1390,7 @@ lookup_hashtable (ulong table, const byte *key, size_t keylen, static int update_trusthashtbl (ctrl_t ctrl, TRUSTREC *tr) { - return upd_hashtable (ctrl, get_trusthashrec (), + return upd_hashtable (ctrl, get_trusthashrec (ctrl), tr->r.trust.fingerprint, 20, tr->recnum); } @@ -1730,7 +1732,7 @@ tdbio_delete_record (ctrl_t ctrl, ulong recnum) ; else if (rec.rectype == RECTYPE_TRUST) { - rc = drop_from_hashtable (ctrl, get_trusthashrec(), + rc = drop_from_hashtable (ctrl, get_trusthashrec (ctrl), rec.r.trust.fingerprint, 20, rec.recnum); } @@ -1852,12 +1854,12 @@ cmp_trec_fpr ( const void *fpr, const TRUSTREC *rec ) * Return: 0 if found, GPG_ERR_NOT_FOUND, or another error code. */ gpg_error_t -tdbio_search_trust_byfpr (const byte *fingerprint, TRUSTREC *rec) +tdbio_search_trust_byfpr (ctrl_t ctrl, const byte *fingerprint, TRUSTREC *rec) { int rc; /* Locate the trust record using the hash table */ - rc = lookup_hashtable (get_trusthashrec(), fingerprint, 20, + rc = lookup_hashtable (get_trusthashrec (ctrl), fingerprint, 20, cmp_trec_fpr, fingerprint, rec ); return rc; } @@ -1870,7 +1872,7 @@ tdbio_search_trust_byfpr (const byte *fingerprint, TRUSTREC *rec) * Return: 0 if found, GPG_ERR_NOT_FOUND, or another error code. */ gpg_error_t -tdbio_search_trust_bypk (PKT_public_key *pk, TRUSTREC *rec) +tdbio_search_trust_bypk (ctrl_t ctrl, PKT_public_key *pk, TRUSTREC *rec) { byte fingerprint[MAX_FINGERPRINT_LEN]; size_t fingerlen; @@ -1878,7 +1880,7 @@ tdbio_search_trust_bypk (PKT_public_key *pk, TRUSTREC *rec) fingerprint_from_pk( pk, fingerprint, &fingerlen ); for (; fingerlen < 20; fingerlen++) fingerprint[fingerlen] = 0; - return tdbio_search_trust_byfpr (fingerprint, rec); + return tdbio_search_trust_byfpr (ctrl, fingerprint, rec); } diff --git a/g10/tdbio.h b/g10/tdbio.h index beaa30876..267a37970 100644 --- a/g10/tdbio.h +++ b/g10/tdbio.h @@ -110,8 +110,10 @@ int tdbio_end_transaction(void); int tdbio_cancel_transaction(void); int tdbio_delete_record (ctrl_t ctrl, ulong recnum); ulong tdbio_new_recnum (ctrl_t ctrl); -gpg_error_t tdbio_search_trust_byfpr (const byte *fingerprint, TRUSTREC *rec); -gpg_error_t tdbio_search_trust_bypk (PKT_public_key *pk, TRUSTREC *rec); +gpg_error_t tdbio_search_trust_byfpr (ctrl_t ctrl, const byte *fingerprint, + TRUSTREC *rec); +gpg_error_t tdbio_search_trust_bypk (ctrl_t ctrl, PKT_public_key *pk, + TRUSTREC *rec); void tdbio_how_to_fix (void); void tdbio_invalid(void); diff --git a/g10/trustdb.c b/g10/trustdb.c index 0a98c129f..2c2d2394a 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -649,7 +649,7 @@ read_trust_record (ctrl_t ctrl, PKT_public_key *pk, TRUSTREC *rec) int rc; init_trustdb (ctrl, 0); - rc = tdbio_search_trust_bypk (pk, rec); + rc = tdbio_search_trust_bypk (ctrl, pk, rec); if (rc) { if (gpg_err_code (rc) != GPG_ERR_NOT_FOUND) -- cgit v1.2.3 From eb68c2d3d1b03a18cd24406fa46d4c30cb13d9f7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 26 Mar 2018 18:20:16 +0200 Subject: gpg: Auto-fix a broken trustdb with just the version record. * g10/tdbio.c (get_trusthashrec): Create hashtable on error. GnuPG-bug-id: 3839 Signed-off-by: Werner Koch --- g10/tdbio.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/g10/tdbio.c b/g10/tdbio.c index 1e454869d..fed0cf5ab 100644 --- a/g10/tdbio.c +++ b/g10/tdbio.c @@ -990,6 +990,20 @@ get_trusthashrec (ctrl_t ctrl) log_fatal (_("%s: error reading version record: %s\n"), db_name, gpg_strerror (rc) ); + if (!vr.r.ver.trusthashtbl) + { + /* Oops: the trustdb is corrupt because the hashtable is + * always created along with the version record. However, + * if something went initially wrong it may happen that + * there is just the version record. We try to fix it here. + * If we can't do that we return 0 - this is the version + * record and thus the actual read will detect the mismatch + * and bail out. Note that create_hashtable updates VR. */ + take_write_lock (); + if (lseek (db_fd, 0, SEEK_END) == TRUST_RECORD_LEN) + create_hashtable (ctrl, &vr, 0); + release_write_lock (); + } trusthashtbl = vr.r.ver.trusthashtbl; } -- cgit v1.2.3 From 02dce8c0cc57deb2095a9b06aeb8f4dea34eef7e Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 27 Mar 2018 08:40:58 +0200 Subject: agent: Make the request origin a part of the cache items. * agent/cache.c (agent_put_cache): Add arg 'ctrl' and change all callers to pass it. (agent_get_cache): Ditto. * agent/cache.c (struct cache_items_s): Add field 'restricted'. (housekeeping): Adjust debug output. (agent_flush_cache): Ditto. (agent_put_cache): Ditto. Take RESTRICTED into account. (agent_get_cache): Ditto. -- If requests are coming from different sources they should not share the same cache. This way we make sure that a Pinentry pops up for a remote request to a key we have already used locally. GnuPG-bug-id: 3858 Signed-off-by: Werner Koch --- agent/agent.h | 4 ++-- agent/cache.c | 38 ++++++++++++++++++++++---------------- agent/command-ssh.c | 2 +- agent/command.c | 31 ++++++++++++++++--------------- agent/cvt-openpgp.c | 2 +- agent/findkey.c | 8 ++++---- agent/genkey.c | 6 +++--- agent/protect-tool.c | 3 ++- 8 files changed, 51 insertions(+), 43 deletions(-) diff --git a/agent/agent.h b/agent/agent.h index 743b76595..cf50d9280 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -452,9 +452,9 @@ void initialize_module_cache (void); void deinitialize_module_cache (void); void agent_cache_housekeeping (void); void agent_flush_cache (void); -int agent_put_cache (const char *key, cache_mode_t cache_mode, +int agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode, const char *data, int ttl); -char *agent_get_cache (const char *key, cache_mode_t cache_mode); +char *agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode); void agent_store_cache_hit (const char *key); diff --git a/agent/cache.c b/agent/cache.c index ed5c97cd2..238b6e214 100644 --- a/agent/cache.c +++ b/agent/cache.c @@ -58,6 +58,7 @@ struct cache_item_s { int ttl; /* max. lifetime given in seconds, -1 one means infinite */ struct secret_data_s *pw; cache_mode_t cache_mode; + int restricted; /* The value of ctrl->restricted is part of the key. */ char key[1]; }; @@ -202,8 +203,8 @@ housekeeping (void) if (r->pw && r->ttl >= 0 && r->accessed + r->ttl < current) { if (DBG_CACHE) - log_debug (" expired '%s' (%ds after last access)\n", - r->key, r->ttl); + log_debug (" expired '%s'.%d (%ds after last access)\n", + r->key, r->restricted, r->ttl); release_data (r->pw); r->pw = NULL; r->accessed = current; @@ -224,8 +225,8 @@ housekeeping (void) if (r->pw && r->created + maxttl < current) { if (DBG_CACHE) - log_debug (" expired '%s' (%lus after creation)\n", - r->key, opt.max_cache_ttl); + log_debug (" expired '%s'.%d (%lus after creation)\n", + r->key, r->restricted, opt.max_cache_ttl); release_data (r->pw); r->pw = NULL; r->accessed = current; @@ -233,15 +234,15 @@ housekeeping (void) } /* Third, make sure that we don't have too many items in the list. - Expire old and unused entries after 30 minutes */ + * Expire old and unused entries after 30 minutes. */ for (rprev=NULL, r=thecache; r; ) { if (!r->pw && r->ttl >= 0 && r->accessed + 60*30 < current) { ITEM r2 = r->next; if (DBG_CACHE) - log_debug (" removed '%s' (mode %d) (slot not used for 30m)\n", - r->key, r->cache_mode); + log_debug (" removed '%s'.%d (mode %d) (slot not used for 30m)\n", + r->key, r->restricted, r->cache_mode); xfree (r); if (!rprev) thecache = r2; @@ -296,7 +297,7 @@ agent_flush_cache (void) if (r->pw) { if (DBG_CACHE) - log_debug (" flushing '%s'\n", r->key); + log_debug (" flushing '%s'.%d\n", r->key, r->restricted); release_data (r->pw); r->pw = NULL; r->accessed = 0; @@ -326,20 +327,21 @@ cache_mode_equal (cache_mode_t a, cache_mode_t b) set infinite timeout. CACHE_MODE is stored with the cache entry and used to select different timeouts. */ int -agent_put_cache (const char *key, cache_mode_t cache_mode, +agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode, const char *data, int ttl) { gpg_error_t err = 0; ITEM r; int res; + int restricted = ctrl? ctrl->restricted : -1; res = npth_mutex_lock (&cache_lock); if (res) log_fatal ("failed to acquire cache mutex: %s\n", strerror (res)); if (DBG_CACHE) - log_debug ("agent_put_cache '%s' (mode %d) requested ttl=%d\n", - key, cache_mode, ttl); + log_debug ("agent_put_cache '%s'.%d (mode %d) requested ttl=%d\n", + key, restricted, cache_mode, ttl); housekeeping (); if (!ttl) @@ -358,6 +360,7 @@ agent_put_cache (const char *key, cache_mode_t cache_mode, if (((cache_mode != CACHE_MODE_USER && cache_mode != CACHE_MODE_NONCE) || cache_mode_equal (r->cache_mode, cache_mode)) + && r->restricted == restricted && !strcmp (r->key, key)) break; } @@ -386,6 +389,7 @@ agent_put_cache (const char *key, cache_mode_t cache_mode, else { strcpy (r->key, key); + r->restricted = restricted; r->created = r->accessed = gnupg_get_time (); r->ttl = ttl; r->cache_mode = cache_mode; @@ -415,13 +419,14 @@ agent_put_cache (const char *key, cache_mode_t cache_mode, make use of CACHE_MODE except for CACHE_MODE_NONCE and CACHE_MODE_USER. */ char * -agent_get_cache (const char *key, cache_mode_t cache_mode) +agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode) { gpg_error_t err; ITEM r; char *value = NULL; int res; int last_stored = 0; + int restricted = ctrl? ctrl->restricted : -1; if (cache_mode == CACHE_MODE_IGNORE) return NULL; @@ -439,8 +444,8 @@ agent_get_cache (const char *key, cache_mode_t cache_mode) } if (DBG_CACHE) - log_debug ("agent_get_cache '%s' (mode %d)%s ...\n", - key, cache_mode, + log_debug ("agent_get_cache '%s'.%d (mode %d)%s ...\n", + key, ctrl->restricted, cache_mode, last_stored? " (stored cache key)":""); housekeeping (); @@ -450,6 +455,7 @@ agent_get_cache (const char *key, cache_mode_t cache_mode) && ((cache_mode != CACHE_MODE_USER && cache_mode != CACHE_MODE_NONCE) || cache_mode_equal (r->cache_mode, cache_mode)) + && r->restricted == restricted && !strcmp (r->key, key)) { /* Note: To avoid races KEY may not be accessed anymore below. */ @@ -472,8 +478,8 @@ agent_get_cache (const char *key, cache_mode_t cache_mode) { xfree (value); value = NULL; - log_error ("retrieving cache entry '%s' failed: %s\n", - key, gpg_strerror (err)); + log_error ("retrieving cache entry '%s'.%d failed: %s\n", + key, restricted, gpg_strerror (err)); } break; } diff --git a/agent/command-ssh.c b/agent/command-ssh.c index e0b723839..517231a8c 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -3140,7 +3140,7 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec, goto out; /* Cache this passphrase. */ - err = agent_put_cache (key_grip, CACHE_MODE_SSH, pi->pin, ttl); + err = agent_put_cache (ctrl, key_grip, CACHE_MODE_SSH, pi->pin, ttl); if (err) goto out; diff --git a/agent/command.c b/agent/command.c index 8bb9b6a70..f2d0389c7 100644 --- a/agent/command.c +++ b/agent/command.c @@ -199,14 +199,14 @@ clear_nonce_cache (ctrl_t ctrl) { if (ctrl->server_local->last_cache_nonce) { - agent_put_cache (ctrl->server_local->last_cache_nonce, + agent_put_cache (ctrl, ctrl->server_local->last_cache_nonce, CACHE_MODE_NONCE, NULL, 0); xfree (ctrl->server_local->last_cache_nonce); ctrl->server_local->last_cache_nonce = NULL; } if (ctrl->server_local->last_passwd_nonce) { - agent_put_cache (ctrl->server_local->last_passwd_nonce, + agent_put_cache (ctrl, ctrl->server_local->last_passwd_nonce, CACHE_MODE_NONCE, NULL, 0); xfree (ctrl->server_local->last_passwd_nonce); ctrl->server_local->last_passwd_nonce = NULL; @@ -930,7 +930,7 @@ cmd_genkey (assuan_context_t ctx, char *line) } else if (passwd_nonce) - newpasswd = agent_get_cache (passwd_nonce, CACHE_MODE_NONCE); + newpasswd = agent_get_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE); rc = agent_genkey (ctrl, cache_nonce, (char*)value, valuelen, no_protection, newpasswd, opt_preset, &outbuf); @@ -1179,7 +1179,7 @@ do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx, /* Here we have a little race by doing the cache check separately from the retrieval function. Given that the cache flag is only a hint, it should not really matter. */ - pw = agent_get_cache (hexgrip, CACHE_MODE_NORMAL); + pw = agent_get_cache (ctrl, hexgrip, CACHE_MODE_NORMAL); cached = pw ? "1" : "-"; xfree (pw); @@ -1484,7 +1484,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line) if (!strcmp (desc, "X")) desc = NULL; - pw = cacheid ? agent_get_cache (cacheid, CACHE_MODE_USER) : NULL; + pw = cacheid ? agent_get_cache (ctrl, cacheid, CACHE_MODE_USER) : NULL; if (pw) { rc = send_back_passphrase (ctx, opt_data, pw); @@ -1551,7 +1551,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line) if (!rc) { if (cacheid) - agent_put_cache (cacheid, CACHE_MODE_USER, response, 0); + agent_put_cache (ctrl, cacheid, CACHE_MODE_USER, response, 0); rc = send_back_passphrase (ctx, opt_data, response); } xfree (response); @@ -1593,7 +1593,8 @@ cmd_clear_passphrase (assuan_context_t ctx, char *line) if (!*cacheid || strlen (cacheid) > 50) return set_error (GPG_ERR_ASS_PARAMETER, "invalid length of cacheID"); - agent_put_cache (cacheid, opt_normal ? CACHE_MODE_NORMAL : CACHE_MODE_USER, + agent_put_cache (ctrl, cacheid, + opt_normal ? CACHE_MODE_NORMAL : CACHE_MODE_USER, NULL, 0); agent_clear_passphrase (ctrl, cacheid, @@ -1770,7 +1771,7 @@ cmd_passwd (assuan_context_t ctx, char *line) passwd_nonce = bin2hex (buf, 12, NULL); } if (passwd_nonce - && !agent_put_cache (passwd_nonce, CACHE_MODE_NONCE, + && !agent_put_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE, passphrase, CACHE_TTL_NONCE)) { assuan_write_status (ctx, "PASSWD_NONCE", passwd_nonce); @@ -1785,7 +1786,7 @@ cmd_passwd (assuan_context_t ctx, char *line) char *newpass = NULL; if (passwd_nonce) - newpass = agent_get_cache (passwd_nonce, CACHE_MODE_NONCE); + newpass = agent_get_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE); err = agent_protect_and_store (ctrl, s_skey, &newpass); if (!err && passphrase) { @@ -1800,7 +1801,7 @@ cmd_passwd (assuan_context_t ctx, char *line) cache_nonce = bin2hex (buf, 12, NULL); } if (cache_nonce - && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE, + && !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE, passphrase, CACHE_TTL_NONCE)) { assuan_write_status (ctx, "CACHE_NONCE", cache_nonce); @@ -1820,7 +1821,7 @@ cmd_passwd (assuan_context_t ctx, char *line) passwd_nonce = bin2hex (buf, 12, NULL); } if (passwd_nonce - && !agent_put_cache (passwd_nonce, CACHE_MODE_NONCE, + && !agent_put_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE, newpass, CACHE_TTL_NONCE)) { assuan_write_status (ctx, "PASSWD_NONCE", passwd_nonce); @@ -1834,7 +1835,7 @@ cmd_passwd (assuan_context_t ctx, char *line) { char hexgrip[40+1]; bin2hex(grip, 20, hexgrip); - err = agent_put_cache (hexgrip, CACHE_MODE_ANY, newpass, + err = agent_put_cache (ctrl, hexgrip, CACHE_MODE_ANY, newpass, ctrl->cache_ttl_opt_preset); } xfree (newpass); @@ -1939,7 +1940,7 @@ cmd_preset_passphrase (assuan_context_t ctx, char *line) if (!rc) { - rc = agent_put_cache (grip_clear, CACHE_MODE_ANY, passphrase, ttl); + rc = agent_put_cache (ctrl, grip_clear, CACHE_MODE_ANY, passphrase, ttl); if (opt_inquire) xfree (passphrase); } @@ -2174,7 +2175,7 @@ cmd_import_key (assuan_context_t ctx, char *line) cache_nonce = bin2hex (buf, 12, NULL); } if (cache_nonce - && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE, + && !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE, passphrase, CACHE_TTL_NONCE)) assuan_write_status (ctx, "CACHE_NONCE", cache_nonce); } @@ -2336,7 +2337,7 @@ cmd_export_key (assuan_context_t ctx, char *line) cache_nonce = bin2hex (buf, 12, NULL); } if (cache_nonce - && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE, + && !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE, passphrase, CACHE_TTL_NONCE)) { assuan_write_status (ctx, "CACHE_NONCE", cache_nonce); diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c index ee1222113..bf05174fa 100644 --- a/agent/cvt-openpgp.c +++ b/agent/cvt-openpgp.c @@ -951,7 +951,7 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp, int dontcare_exist, { char *cache_value; - cache_value = agent_get_cache (cache_nonce, CACHE_MODE_NONCE); + cache_value = agent_get_cache (ctrl, cache_nonce, CACHE_MODE_NONCE); if (cache_value) { if (strlen (cache_value) < pi->max_length) diff --git a/agent/findkey.c b/agent/findkey.c index e3e9a123f..78c3b1a47 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -511,7 +511,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, { char *pw; - pw = agent_get_cache (cache_nonce, CACHE_MODE_NONCE); + pw = agent_get_cache (ctrl, cache_nonce, CACHE_MODE_NONCE); if (pw) { rc = agent_unprotect (ctrl, *keybuf, pw, NULL, &result, &resultlen); @@ -536,7 +536,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, char *pw; retry: - pw = agent_get_cache (hexgrip, cache_mode); + pw = agent_get_cache (ctrl, hexgrip, cache_mode); if (pw) { rc = agent_unprotect (ctrl, *keybuf, pw, NULL, &result, &resultlen); @@ -574,7 +574,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, We can often avoid the passphrase entry in the second step. We do this only in normal mode, so not to interfere with unrelated cache entries. */ - pw = agent_get_cache (NULL, cache_mode); + pw = agent_get_cache (ctrl, NULL, cache_mode); if (pw) { rc = agent_unprotect (ctrl, *keybuf, pw, NULL, @@ -670,7 +670,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, else { /* Passphrase is fine. */ - agent_put_cache (hexgrip, cache_mode, pi->pin, + agent_put_cache (ctrl, hexgrip, cache_mode, pi->pin, lookup_ttl? lookup_ttl (hexgrip) : 0); agent_store_cache_hit (hexgrip); if (r_passphrase && *pi->pin) diff --git a/agent/genkey.c b/agent/genkey.c index a3e37ee3a..d5c80d0aa 100644 --- a/agent/genkey.c +++ b/agent/genkey.c @@ -468,7 +468,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, passphrase = NULL; else { - passphrase_buffer = agent_get_cache (cache_nonce, CACHE_MODE_NONCE); + passphrase_buffer = agent_get_cache (ctrl, cache_nonce, CACHE_MODE_NONCE); passphrase = passphrase_buffer; } @@ -528,7 +528,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, } if (cache_nonce && !no_protection - && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE, + && !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE, passphrase, ctrl->cache_ttl_opt_preset)) agent_write_status (ctrl, "CACHE_NONCE", cache_nonce, NULL); if (preset && !no_protection) @@ -538,7 +538,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, if (gcry_pk_get_keygrip (s_private, grip)) { bin2hex(grip, 20, hexgrip); - rc = agent_put_cache (hexgrip, CACHE_MODE_ANY, passphrase, + rc = agent_put_cache (ctrl, hexgrip, CACHE_MODE_ANY, passphrase, ctrl->cache_ttl_opt_preset); } } diff --git a/agent/protect-tool.c b/agent/protect-tool.c index a193e4969..ec7b47695 100644 --- a/agent/protect-tool.c +++ b/agent/protect-tool.c @@ -749,8 +749,9 @@ agent_key_available (const unsigned char *grip) } char * -agent_get_cache (const char *key, cache_mode_t cache_mode) +agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode) { + (void)ctrl; (void)key; (void)cache_mode; return NULL; -- cgit v1.2.3