From 6944aefa3c2ef79cf3f14306ed384d22de36ba7f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 17 May 2023 15:54:40 +0200 Subject: [PATCH 01/56] kbx,w32: Disable the fd-passing. * kbx/kbxserver.c (kbxd_start_command_handler): No fd-passing udner Windows. -- file descriptor passing does not work reliable in libassuan for Windows and we actually don't need it here. It is not even used by gpg or gpgsm. As soon as we enable fd-passing in gpgme for Windows and see that it is robust enough we should back out this patch. --- kbx/kbxserver.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kbx/kbxserver.c b/kbx/kbxserver.c index 990840980..ae9ae5c75 100644 --- a/kbx/kbxserver.c +++ b/kbx/kbxserver.c @@ -946,9 +946,15 @@ kbxd_start_command_handler (ctrl_t ctrl, gnupg_fd_t fd, unsigned int session_id) } else { + /* The fd-passing does not work reliable on Windows, and even it + * it is not used by gpg and gpgsm the current libassuan slows + * down things if it is allowed for the server.*/ rc = assuan_init_socket_server (ctx, fd, (ASSUAN_SOCKET_SERVER_ACCEPTED - |ASSUAN_SOCKET_SERVER_FDPASSING)); +#ifndef HAVE_W32_SYSTEM + |ASSUAN_SOCKET_SERVER_FDPASSING +#endif + )); } if (rc) From cd7f286486f23f89367048730e651ac17b7f8b3f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 19 May 2023 13:06:18 +0200 Subject: [PATCH 02/56] gpgtar: Emit FAILURE status line. * tools/gpgtar.c (main): Write status line before exit. -- Due to the new way we support gpgtar in GPGME we need status lines to detect a final error. GnuPG-bug-id: 6497 --- tools/gpgtar.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/gpgtar.c b/tools/gpgtar.c index b2ccc9f8a..492b3d5e5 100644 --- a/tools/gpgtar.c +++ b/tools/gpgtar.c @@ -588,9 +588,19 @@ main (int argc, char **argv) default: log_error (_("invalid command (there is no implicit command)\n")); + err = 0; break; } + if (opt.status_stream) + { + if (err || log_get_errorcount (0)) + es_fprintf (opt.status_stream, "[GNUPG:] FAILURE - %u\n", + err? err : gpg_error (GPG_ERR_GENERAL)); + else + es_fprintf (opt.status_stream, "[GNUPG:] SUCCESS\n"); + } + return log_get_errorcount (0)? 1:0; } From 5f46bcaaa0826a7b32f3f3bb5ef7a528ec0515a6 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 22 May 2023 17:00:54 +0200 Subject: [PATCH 03/56] sm: Emit STATUS_FAILURE for non-implemented commands. * sm/gpgsm.c (main): Do it here. --- sm/gpgsm.c | 16 ++++++++++++---- sm/server.c | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 55173f8a2..07c3ff480 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -1951,11 +1951,17 @@ main ( int argc, char **argv) break; case aSignEncr: /* sign and encrypt the given file */ - log_error ("this command has not yet been implemented\n"); + log_error ("the command '%s' has not yet been implemented\n", + "--sign --encrypt"); + gpgsm_status_with_error (&ctrl, STATUS_FAILURE, "option-parser", + gpg_error (GPG_ERR_NOT_IMPLEMENTED)); break; case aClearsign: /* make a clearsig */ - log_error ("this command has not yet been implemented\n"); + log_error ("the command '%s' has not yet been implemented\n", + "--clearsign"); + gpgsm_status_with_error (&ctrl, STATUS_FAILURE, "option-parser", + gpg_error (GPG_ERR_NOT_IMPLEMENTED)); break; case aVerify: @@ -2188,8 +2194,10 @@ main ( int argc, char **argv) default: - log_error (_("invalid command (there is no implicit command)\n")); - break; + log_error (_("invalid command (there is no implicit command)\n")); + gpgsm_status_with_error (&ctrl, STATUS_FAILURE, "option-parser", + gpg_error (GPG_ERR_MISSING_ACTION)); + break; } /* Print the audit result if needed. */ diff --git a/sm/server.c b/sm/server.c index e44856ab9..3ec1c0c4b 100644 --- a/sm/server.c +++ b/sm/server.c @@ -1530,7 +1530,7 @@ gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text, { char buf[30]; - sprintf (buf, "%u", (unsigned int)ec); + snprintf (buf, sizeof buf, "%u", (unsigned int)ec); if (text) return gpgsm_status2 (ctrl, no, text, buf, NULL); else From 48b56485548e11e901b762f39f9dcd14aa650184 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 23 May 2023 14:50:22 +0200 Subject: [PATCH 04/56] common,w32: Set a proper error code when creating an output file. * common/iobuf.c (direct_open) [W32]: Set errno. (fd_cache_open): Ditto. -- --- common/iobuf.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/common/iobuf.c b/common/iobuf.c index 62cde27f9..825b97704 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -311,6 +311,13 @@ direct_open (const char *fname, const char *mode, int mode700) { hfile = CreateFileW (wfname, da, sm, NULL, cd, FILE_ATTRIBUTE_NORMAL, NULL); + if (hfile == INVALID_HANDLE_VALUE) + { + gnupg_w32_set_errno (-1); + if (DBG_IOBUF) + log_debug ("iobuf:direct_open '%s' CreateFile failed: %s\n", + fname, gpg_strerror (gpg_error_from_syserror())); + } xfree (wfname); } else @@ -426,8 +433,9 @@ fd_cache_open (const char *fname, const char *mode) #ifdef HAVE_W32_SYSTEM if (SetFilePointer (fp, 0, NULL, FILE_BEGIN) == 0xffffffff) { - log_error ("rewind file failed on handle %p: ec=%d\n", - fp, (int) GetLastError ()); + int ec = (int) GetLastError (); + log_error ("rewind file failed on handle %p: ec=%d\n", fp, ec); + gnupg_w32_set_errno (ec); fp = GNUPG_INVALID_FD; } #else From 3fbe10172f0a0d9fddad19c1e04a4f7870c88fbe Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 24 May 2023 12:06:37 +0200 Subject: [PATCH 05/56] w32: Add missing manifests and set a requestedExecutionLevel. * agent/gpg-agent.w32-manifest.in: New. * dirmngr/dirmngr-client-w32info.rc: New. * dirmngr/dirmngr-client.w32-manifest.in: New. * dirmngr/dirmngr-w32info.rc: New. * dirmngr/dirmngr.w32-manifest.in: New. * dirmngr/dirmngr_ldap-w32info.rc: New. * dirmngr/dirmngr_ldap.w32-manifest.in: New. * g10/gpgv-w32info.rc: New. * g10/gpgv.w32-manifest.in: New. * kbx/keyboxd.w32-manifest.in: New. * scd/scdaemon.w32-manifest.in: New. * sm/gpgsm.w32-manifest.in: New. -- This avoids the use of the VirtualStore uner Windows. GnuPG-bug-id: 6503 --- agent/Makefile.am | 7 +++- agent/gpg-agent-w32info.rc | 2 + agent/gpg-agent.w32-manifest.in | 24 ++++++++++++ configure.ac | 8 ++++ dirmngr/Makefile.am | 30 ++++++++++++-- dirmngr/dirmngr-client-w32info.rc | 52 +++++++++++++++++++++++++ dirmngr/dirmngr-client.w32-manifest.in | 25 ++++++++++++ dirmngr/dirmngr-w32info.rc | 52 +++++++++++++++++++++++++ dirmngr/dirmngr.w32-manifest.in | 25 ++++++++++++ dirmngr/dirmngr_ldap-w32info.rc | 52 +++++++++++++++++++++++++ dirmngr/dirmngr_ldap.w32-manifest.in | 25 ++++++++++++ g10/Makefile.am | 17 ++++---- g10/gpg.w32-manifest.in | 7 ++++ g10/gpgv-w32info.rc | 52 +++++++++++++++++++++++++ g10/gpgv.w32-manifest.in | 24 ++++++++++++ kbx/Makefile.am | 5 ++- kbx/keyboxd-w32info.rc | 2 + kbx/keyboxd.w32-manifest.in | 24 ++++++++++++ scd/Makefile.am | 7 +++- scd/scdaemon-w32info.rc | 2 + scd/scdaemon.w32-manifest.in | 24 ++++++++++++ sm/Makefile.am | 5 ++- sm/gpgsm-w32info.rc | 2 + sm/gpgsm.w32-manifest.in | 24 ++++++++++++ tools/Makefile.am | 17 +++++--- tools/gpg-card.w32-manifest.in | 7 ++++ tools/gpg-check-pattern.w32-manifest.in | 7 ++++ tools/gpg-connect-agent.w32-manifest.in | 7 ++++ tools/gpg-wks-client.w32-manifest.in | 7 ++++ tools/gpgconf.w32-manifest.in | 7 ++++ tools/gpgtar.w32-manifest.in | 7 ++++ 31 files changed, 534 insertions(+), 22 deletions(-) create mode 100644 agent/gpg-agent.w32-manifest.in create mode 100644 dirmngr/dirmngr-client-w32info.rc create mode 100644 dirmngr/dirmngr-client.w32-manifest.in create mode 100644 dirmngr/dirmngr-w32info.rc create mode 100644 dirmngr/dirmngr.w32-manifest.in create mode 100644 dirmngr/dirmngr_ldap-w32info.rc create mode 100644 dirmngr/dirmngr_ldap.w32-manifest.in create mode 100644 g10/gpgv-w32info.rc create mode 100644 g10/gpgv.w32-manifest.in create mode 100644 kbx/keyboxd.w32-manifest.in create mode 100644 scd/scdaemon.w32-manifest.in create mode 100644 sm/gpgsm.w32-manifest.in diff --git a/agent/Makefile.am b/agent/Makefile.am index 4da1ea9d8..b2a32b1fd 100644 --- a/agent/Makefile.am +++ b/agent/Makefile.am @@ -1,3 +1,4 @@ +# Makefile.am - agent # Copyright (C) 2001, 2003, 2004, 2005 Free Software Foundation, Inc. # # This file is part of GnuPG. @@ -23,8 +24,8 @@ libexec_PROGRAMS = gpg-protect-tool libexec_PROGRAMS += gpg-preset-passphrase noinst_PROGRAMS = $(TESTS) -EXTRA_DIST = ChangeLog-2011 gpg-agent-w32info.rc all-tests.scm - +EXTRA_DIST = ChangeLog-2011 all-tests.scm \ + gpg-agent-w32info.rc gpg-agent.w32-manifest.in AM_CPPFLAGS = @@ -32,6 +33,8 @@ include $(top_srcdir)/am/cmacros.am if HAVE_W32_SYSTEM resource_objs += gpg-agent-w32info.o + +gpg-agent-w32info.o : gpg-agent.w32-manifest ../common/w32info-rc.h endif AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS) diff --git a/agent/gpg-agent-w32info.rc b/agent/gpg-agent-w32info.rc index d586cad0c..a0311b2cd 100644 --- a/agent/gpg-agent-w32info.rc +++ b/agent/gpg-agent-w32info.rc @@ -48,3 +48,5 @@ VALUE "Translation", 0x409, 0x4b0 END END + +1 RT_MANIFEST "gpg-agent.w32-manifest" diff --git a/agent/gpg-agent.w32-manifest.in b/agent/gpg-agent.w32-manifest.in new file mode 100644 index 000000000..87f09aa49 --- /dev/null +++ b/agent/gpg-agent.w32-manifest.in @@ -0,0 +1,24 @@ + + +GNU Privacy Guard (Private Key Daemon) + + + + + + + + + + + + + + + + + diff --git a/configure.ac b/configure.ac index 24448c157..a54740108 100644 --- a/configure.ac +++ b/configure.ac @@ -2102,6 +2102,14 @@ tests/tpm2dtests/Makefile tests/gpgme/Makefile tests/pkits/Makefile g10/gpg.w32-manifest +g10/gpgv.w32-manifest +sm/gpgsm.w32-manifest +kbx/keyboxd.w32-manifest +agent/gpg-agent.w32-manifest +scd/scdaemon.w32-manifest +dirmngr/dirmngr.w32-manifest +dirmngr/dirmngr_ldap.w32-manifest +dirmngr/dirmngr-client.w32-manifest tools/gpg-connect-agent.w32-manifest tools/gpgconf.w32-manifest tools/gpgtar.w32-manifest diff --git a/dirmngr/Makefile.am b/dirmngr/Makefile.am index feee2f5c8..3846fdf35 100644 --- a/dirmngr/Makefile.am +++ b/dirmngr/Makefile.am @@ -21,7 +21,14 @@ ## Process this file with automake to produce Makefile.in -EXTRA_DIST = OAUTHORS ONEWS ChangeLog-2011 tls-ca.pem +EXTRA_DIST = OAUTHORS ONEWS ChangeLog-2011 tls-ca.pem \ + dirmngr-w32info.rc dirmngr.w32-manifest.in \ + dirmngr_ldap-w32info.rc dirmngr_ldap.w32-manifest.in \ + dirmngr-client-w32info.rc dirmngr-client.w32-manifest.in + + + + dist_pkgdata_DATA = sks-keyservers.netCA.pem bin_PROGRAMS = dirmngr dirmngr-client @@ -43,6 +50,16 @@ AM_CPPFLAGS = include $(top_srcdir)/am/cmacros.am +if HAVE_W32_SYSTEM +dirmngr_rc_objs = dirmngr-w32info.o +dirmngr_ldap_rc_objs = dirmngr_ldap-w32info.o +dirmngr_client_rc_objs = dirmngr-client-w32info.o + +dirmngr-w32info.o : dirmngr.w32-manifest ../common/w32info-rc.h +dirmngr_ldap-w32info.o : dirmngr_ldap.w32-manifest ../common/w32info-rc.h +dirmngr-client-w32info.o : dirmngr-client.w32-manifest ../common/w32info-rc.h +endif + AM_CFLAGS = $(USE_C99_CFLAGS) \ $(LIBGCRYPT_CFLAGS) $(KSBA_CFLAGS) $(LIBASSUAN_CFLAGS) \ $(GPG_ERROR_CFLAGS) $(NPTH_CFLAGS) $(NTBTLS_CFLAGS) \ @@ -89,12 +106,13 @@ dirmngr_LDADD = $(libcommonpth) \ $(DNSLIBS) $(LIBASSUAN_LIBS) \ $(KSBA_LIBS) $(NPTH_LIBS) $(NTBTLS_LIBS) $(LIBGNUTLS_LIBS) \ $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV) \ - $(NETLIBS) + $(NETLIBS) $(dirmngr_rc_objs) if USE_LDAP dirmngr_LDADD += $(ldaplibs) $(LBER_LIBS) endif dirmngr_LDFLAGS = +dirmngr_DEPENDENCIES = $(dirmngr_rc_objs) if USE_LDAP dirmngr_ldap_SOURCES = dirmngr_ldap.c ldap-misc.c ldap-misc.h $(ldap_url) @@ -102,14 +120,18 @@ dirmngr_ldap_CFLAGS = $(GPG_ERROR_CFLAGS) $(LIBGCRYPT_CFLAGS) dirmngr_ldap_LDFLAGS = dirmngr_ldap_LDADD = $(libcommon) \ $(GPG_ERROR_LIBS) $(LIBGCRYPT_LIBS) $(LDAPLIBS) \ - $(LBER_LIBS) $(LIBINTL) $(LIBICONV) $(NETLIBS) + $(LBER_LIBS) $(LIBINTL) $(LIBICONV) $(NETLIBS) \ + $(dirmngr_ldap_rc_objs) +dirmngr_ldap_DEPENDENCIES = $(dirmngr_ldap_rc_objs) endif dirmngr_client_SOURCES = dirmngr-client.c dirmngr_client_LDADD = $(libcommon) \ $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \ - $(LIBGCRYPT_LIBS) $(NETLIBS) $(LIBINTL) $(LIBICONV) + $(LIBGCRYPT_LIBS) $(NETLIBS) $(LIBINTL) $(LIBICONV) \ + $(dirmngr_client_rc_objs) dirmngr_client_LDFLAGS = +dirmngr_client_DEPENDENCIES = $(dirmngr_client_rc_objs) t_common_src = t-support.h t-support.c diff --git a/dirmngr/dirmngr-client-w32info.rc b/dirmngr/dirmngr-client-w32info.rc new file mode 100644 index 000000000..020447bca --- /dev/null +++ b/dirmngr/dirmngr-client-w32info.rc @@ -0,0 +1,52 @@ +/* dirmngr-client-w32info.rc -*- c -*- + * Copyright (C) 2023 g10 Code GmbH + * + * This file is free software; as a special exception the author gives + * unlimited permission to copy and/or distribute it, with or without + * modifications, as long as this notice is preserved. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "afxres.h" +#include "../common/w32info-rc.h" + +1 ICON "../common/gnupg.ico" + +1 VERSIONINFO + FILEVERSION W32INFO_VI_FILEVERSION + PRODUCTVERSION W32INFO_VI_PRODUCTVERSION + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x01L /* VS_FF_DEBUG (0x1)*/ +#else + FILEFLAGS 0x00L +#endif + FILEOS 0x40004L /* VOS_NT (0x40000) | VOS__WINDOWS32 (0x4) */ + FILETYPE 0x1L /* VFT_APP (0x1) */ + FILESUBTYPE 0x0L /* VFT2_UNKNOWN */ + BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" /* US English (0409), Unicode (04b0) */ + BEGIN + VALUE "FileDescription", L"GnuPG\x2019s dirmngr client\0" + VALUE "InternalName", "dirmngr-client\0" + VALUE "OriginalFilename", "dirmngr-client.exe\0" + VALUE "ProductName", W32INFO_PRODUCTNAME + VALUE "ProductVersion", W32INFO_PRODUCTVERSION + VALUE "CompanyName", W32INFO_COMPANYNAME + VALUE "FileVersion", W32INFO_FILEVERSION + VALUE "LegalCopyright", W32INFO_LEGALCOPYRIGHT + VALUE "Comments", W32INFO_COMMENTS + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 0x4b0 + END + END + +1 RT_MANIFEST "dirmngr-client.w32-manifest" diff --git a/dirmngr/dirmngr-client.w32-manifest.in b/dirmngr/dirmngr-client.w32-manifest.in new file mode 100644 index 000000000..1d46d19ff --- /dev/null +++ b/dirmngr/dirmngr-client.w32-manifest.in @@ -0,0 +1,25 @@ + + +GNU Privacy Guard (Dirmngr Client) + + + + + + + + + + + + + + + + + + diff --git a/dirmngr/dirmngr-w32info.rc b/dirmngr/dirmngr-w32info.rc new file mode 100644 index 000000000..cc1475b8e --- /dev/null +++ b/dirmngr/dirmngr-w32info.rc @@ -0,0 +1,52 @@ +/* dirmngr-w32info.rc -*- c -*- + * Copyright (C) 2023 g10 Code GmbH + * + * This file is free software; as a special exception the author gives + * unlimited permission to copy and/or distribute it, with or without + * modifications, as long as this notice is preserved. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "afxres.h" +#include "../common/w32info-rc.h" + +1 ICON "../common/gnupg.ico" + +1 VERSIONINFO + FILEVERSION W32INFO_VI_FILEVERSION + PRODUCTVERSION W32INFO_VI_PRODUCTVERSION + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x01L /* VS_FF_DEBUG (0x1)*/ +#else + FILEFLAGS 0x00L +#endif + FILEOS 0x40004L /* VOS_NT (0x40000) | VOS__WINDOWS32 (0x4) */ + FILETYPE 0x1L /* VFT_APP (0x1) */ + FILESUBTYPE 0x0L /* VFT2_UNKNOWN */ + BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" /* US English (0409), Unicode (04b0) */ + BEGIN + VALUE "FileDescription", L"GnuPG\x2019s network access daemon\0" + VALUE "InternalName", "dirmngr\0" + VALUE "OriginalFilename", "dirmngr.exe\0" + VALUE "ProductName", W32INFO_PRODUCTNAME + VALUE "ProductVersion", W32INFO_PRODUCTVERSION + VALUE "CompanyName", W32INFO_COMPANYNAME + VALUE "FileVersion", W32INFO_FILEVERSION + VALUE "LegalCopyright", W32INFO_LEGALCOPYRIGHT + VALUE "Comments", W32INFO_COMMENTS + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 0x4b0 + END + END + +1 RT_MANIFEST "dirmngr.w32-manifest" diff --git a/dirmngr/dirmngr.w32-manifest.in b/dirmngr/dirmngr.w32-manifest.in new file mode 100644 index 000000000..115548b5c --- /dev/null +++ b/dirmngr/dirmngr.w32-manifest.in @@ -0,0 +1,25 @@ + + +GNU Privacy Guard (Archive tool) + + + + + + + + + + + + + + + + + + diff --git a/dirmngr/dirmngr_ldap-w32info.rc b/dirmngr/dirmngr_ldap-w32info.rc new file mode 100644 index 000000000..779d85837 --- /dev/null +++ b/dirmngr/dirmngr_ldap-w32info.rc @@ -0,0 +1,52 @@ +/* dirmngr_ldap-w32info.rc -*- c -*- + * Copyright (C) 2023 g10 Code GmbH + * + * This file is free software; as a special exception the author gives + * unlimited permission to copy and/or distribute it, with or without + * modifications, as long as this notice is preserved. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "afxres.h" +#include "../common/w32info-rc.h" + +1 ICON "../common/gnupg.ico" + +1 VERSIONINFO + FILEVERSION W32INFO_VI_FILEVERSION + PRODUCTVERSION W32INFO_VI_PRODUCTVERSION + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x01L /* VS_FF_DEBUG (0x1)*/ +#else + FILEFLAGS 0x00L +#endif + FILEOS 0x40004L /* VOS_NT (0x40000) | VOS__WINDOWS32 (0x4) */ + FILETYPE 0x1L /* VFT_APP (0x1) */ + FILESUBTYPE 0x0L /* VFT2_UNKNOWN */ + BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" /* US English (0409), Unicode (04b0) */ + BEGIN + VALUE "FileDescription", L"GnuPG\x2019s LDAP helper\0" + VALUE "InternalName", "dirmngr_ldap\0" + VALUE "OriginalFilename", "dirmngr_ldap.exe\0" + VALUE "ProductName", W32INFO_PRODUCTNAME + VALUE "ProductVersion", W32INFO_PRODUCTVERSION + VALUE "CompanyName", W32INFO_COMPANYNAME + VALUE "FileVersion", W32INFO_FILEVERSION + VALUE "LegalCopyright", W32INFO_LEGALCOPYRIGHT + VALUE "Comments", W32INFO_COMMENTS + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 0x4b0 + END + END + +1 RT_MANIFEST "dirmngr_ldap.w32-manifest" diff --git a/dirmngr/dirmngr_ldap.w32-manifest.in b/dirmngr/dirmngr_ldap.w32-manifest.in new file mode 100644 index 000000000..67db0841c --- /dev/null +++ b/dirmngr/dirmngr_ldap.w32-manifest.in @@ -0,0 +1,25 @@ + + +GNU Privacy Guard (LDAP Helper) + + + + + + + + + + + + + + + + + + diff --git a/g10/Makefile.am b/g10/Makefile.am index 80b5b8919..c5691f551 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -1,3 +1,4 @@ +# Makefile.am - g10 # Copyright (C) 1998, 1999, 2000, 2001, 2002, # 2003, 2006, 2010 Free Software Foundation, Inc. # @@ -19,8 +20,9 @@ ## Process this file with automake to produce Makefile.in EXTRA_DIST = distsigkey.gpg \ - ChangeLog-2011 gpg-w32info.rc \ - gpg.w32-manifest.in test.c t-keydb-keyring.kbx \ + gpg-w32info.rc gpg.w32-manifest.in \ + gpgv-w32info.rc gpgv.w32-manifest.in \ + ChangeLog-2011 test.c t-keydb-keyring.kbx \ t-keydb-get-keyblock.gpg t-stutter-data.asc \ all-tests.scm @@ -83,10 +85,11 @@ endif if HAVE_W32_SYSTEM -resource_objs += gpg-w32info.o - -gpg-w32info.o : gpg.w32-manifest +gpg_rc_objs = gpg-w32info.o +gpgv_rc_objs = gpgv-w32info.o +gpg-w32info.o : gpg.w32-manifest ../common/w32info-rc.h +gpgv-w32info.o : gpgv.w32-manifest ../common/w32info-rc.h endif common_source = \ @@ -171,11 +174,11 @@ LDADD = $(needed_libs) ../common/libgpgrl.a \ $(ZLIBS) $(LIBINTL) $(CAPLIBS) gpg_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) $(NETLIBS) \ - $(LIBICONV) $(resource_objs) + $(LIBICONV) $(gpg_rc_objs) gpg_LDFLAGS = gpgv_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) $(NETLIBS) \ - $(LIBICONV) $(resource_objs) + $(LIBICONV) $(gpgv_rc_objs) gpgv_LDFLAGS = diff --git a/g10/gpg.w32-manifest.in b/g10/gpg.w32-manifest.in index 8c98dc5a7..bf7723925 100644 --- a/g10/gpg.w32-manifest.in +++ b/g10/gpg.w32-manifest.in @@ -14,4 +14,11 @@ + + + + + + + diff --git a/g10/gpgv-w32info.rc b/g10/gpgv-w32info.rc new file mode 100644 index 000000000..a6c1b6cd3 --- /dev/null +++ b/g10/gpgv-w32info.rc @@ -0,0 +1,52 @@ +/* gpgv-w32info.rc -*- c -*- + * Copyright (C) 2013 g10 Code GmbH + * + * This file is free software; as a special exception the author gives + * unlimited permission to copy and/or distribute it, with or without + * modifications, as long as this notice is preserved. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "afxres.h" +#include "../common/w32info-rc.h" + +1 ICON "../common/gnupg.ico" + +1 VERSIONINFO + FILEVERSION W32INFO_VI_FILEVERSION + PRODUCTVERSION W32INFO_VI_PRODUCTVERSION + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x01L /* VS_FF_DEBUG (0x1)*/ +#else + FILEFLAGS 0x00L +#endif + FILEOS 0x40004L /* VOS_NT (0x40000) | VOS__WINDOWS32 (0x4) */ + FILETYPE 0x1L /* VFT_APP (0x1) */ + FILESUBTYPE 0x0L /* VFT2_UNKNOWN */ + BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" /* US English (0409), Unicode (04b0) */ + BEGIN + VALUE "FileDescription", L"GnuPG\x2019s OpenPGP verify tool\0" + VALUE "InternalName", "gpgv\0" + VALUE "OriginalFilename", "gpgv.exe\0" + VALUE "ProductName", W32INFO_PRODUCTNAME + VALUE "ProductVersion", W32INFO_PRODUCTVERSION + VALUE "CompanyName", W32INFO_COMPANYNAME + VALUE "FileVersion", W32INFO_FILEVERSION + VALUE "LegalCopyright", W32INFO_LEGALCOPYRIGHT + VALUE "Comments", W32INFO_COMMENTS + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 0x4b0 + END + END + +1 RT_MANIFEST "gpgv.w32-manifest" diff --git a/g10/gpgv.w32-manifest.in b/g10/gpgv.w32-manifest.in new file mode 100644 index 000000000..794ab15c3 --- /dev/null +++ b/g10/gpgv.w32-manifest.in @@ -0,0 +1,24 @@ + + +GNU Privacy Guard (OpenPGP verify tool) + + + + + + + + + + + + + + + + + diff --git a/kbx/Makefile.am b/kbx/Makefile.am index 66214fa5c..19bdb1061 100644 --- a/kbx/Makefile.am +++ b/kbx/Makefile.am @@ -18,13 +18,16 @@ ## Process this file with automake to produce Makefile.in -EXTRA_DIST = mkerrors keyboxd-w32info.rc +EXTRA_DIST = mkerrors keyboxd-w32info.rc keyboxd.w32-manifest.in AM_CPPFLAGS = include $(top_srcdir)/am/cmacros.am + if HAVE_W32_SYSTEM resource_objs += keyboxd-w32info.o + +keyboxd-w32info.o : keyboxd.w32-manifest ../common/w32info-rc.h endif AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(KSBA_CFLAGS) diff --git a/kbx/keyboxd-w32info.rc b/kbx/keyboxd-w32info.rc index 421747499..c38d9f366 100644 --- a/kbx/keyboxd-w32info.rc +++ b/kbx/keyboxd-w32info.rc @@ -48,3 +48,5 @@ VALUE "Translation", 0x409, 0x4b0 END END + +1 RT_MANIFEST "keyboxd.w32-manifest" diff --git a/kbx/keyboxd.w32-manifest.in b/kbx/keyboxd.w32-manifest.in new file mode 100644 index 000000000..f2e50fb4b --- /dev/null +++ b/kbx/keyboxd.w32-manifest.in @@ -0,0 +1,24 @@ + + +GNU Privacy Guard (Public Key Daemon) + + + + + + + + + + + + + + + + + diff --git a/scd/Makefile.am b/scd/Makefile.am index 0cc50dca8..8cbcd6e05 100644 --- a/scd/Makefile.am +++ b/scd/Makefile.am @@ -1,3 +1,4 @@ +# Makefile.am - scd # Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. # # This file is part of GnuPG. @@ -17,7 +18,8 @@ ## Process this file with automake to produce Makefile.in -EXTRA_DIST = ChangeLog-2011 scdaemon-w32info.rc +EXTRA_DIST = ChangeLog-2011 \ + scdaemon-w32info.rc scdaemon.w32-manifest.in libexec_PROGRAMS = scdaemon @@ -27,6 +29,7 @@ include $(top_srcdir)/am/cmacros.am if HAVE_W32_SYSTEM resource_objs += scdaemon-w32info.o +scdaemon-w32info.o : scdaemon.w32-manifest ../common/w32info-rc.h endif AM_CFLAGS = $(LIBGCRYPT_CFLAGS) \ @@ -50,3 +53,5 @@ scdaemon_LDADD = $(libcommonpth) \ $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \ $(LIBUSB_LIBS) $(GPG_ERROR_LIBS) \ $(LIBINTL) $(DL_LIBS) $(NETLIBS) $(LIBICONV) $(resource_objs) + +scdaemon_DEPENDENCIES = $(resource_objs) diff --git a/scd/scdaemon-w32info.rc b/scd/scdaemon-w32info.rc index aa0eba4e5..c1dae5421 100644 --- a/scd/scdaemon-w32info.rc +++ b/scd/scdaemon-w32info.rc @@ -48,3 +48,5 @@ VALUE "Translation", 0x409, 0x4b0 END END + +1 RT_MANIFEST "scdaemon.w32-manifest" diff --git a/scd/scdaemon.w32-manifest.in b/scd/scdaemon.w32-manifest.in new file mode 100644 index 000000000..aa0ccb206 --- /dev/null +++ b/scd/scdaemon.w32-manifest.in @@ -0,0 +1,24 @@ + + +GNU Privacy Guard (Smartcard Daemon) + + + + + + + + + + + + + + + + + diff --git a/sm/Makefile.am b/sm/Makefile.am index cfcc36c63..03de7026a 100644 --- a/sm/Makefile.am +++ b/sm/Makefile.am @@ -17,7 +17,8 @@ ## Process this file with automake to produce Makefile.in -EXTRA_DIST = ChangeLog-2011 gpgsm-w32info.rc +EXTRA_DIST = ChangeLog-2011 \ + gpgsm-w32info.rc gpgsm.w32-manifest.in bin_PROGRAMS = gpgsm noinst_PROGRAMS = $(module_tests) $(module_maint_tests) @@ -36,6 +37,7 @@ include $(top_srcdir)/am/cmacros.am if HAVE_W32_SYSTEM resource_objs += gpgsm-w32info.o +gpgsm-w32info.o : gpgsm.w32-manifest ../common/w32info-rc.h endif gpgsm_SOURCES = \ @@ -72,6 +74,7 @@ gpgsm_LDADD = $(common_libs) ../common/libgpgrl.a \ $(NPTH_LIBS) $(GPG_ERROR_LIBS) $(LIBREADLINE) $(LIBINTL) \ $(LIBICONV) $(resource_objs) $(NETLIBS) gpgsm_LDFLAGS = +gpgsm_DEPENDENCIES = $(resource_objs) module_tests = diff --git a/sm/gpgsm-w32info.rc b/sm/gpgsm-w32info.rc index d813b0dc8..537afdbc7 100644 --- a/sm/gpgsm-w32info.rc +++ b/sm/gpgsm-w32info.rc @@ -48,3 +48,5 @@ VALUE "Translation", 0x409, 0x4b0 END END + +1 RT_MANIFEST "gpgsm.w32-manifest" diff --git a/sm/gpgsm.w32-manifest.in b/sm/gpgsm.w32-manifest.in new file mode 100644 index 000000000..7764be394 --- /dev/null +++ b/sm/gpgsm.w32-manifest.in @@ -0,0 +1,24 @@ + + +GNU Privacy Guard (X.509/CMS Tool) + + + + + + + + + + + + + + + + + diff --git a/tools/Makefile.am b/tools/Makefile.am index 39374e42a..769a81a00 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -38,12 +38,17 @@ gpg_card_rc_objs = gpg-card-w32info.o gpgtar_rc_objs = gpgtar-w32info.o gpg_check_pattern_rc_objs = gpg-check-pattern-w32info.o gpg_wks_client_rc_objs = gpg-wks-client-w32info.o -resource_objs += $(gpg_connect_agent_rc_objs) -resource_objs += $(gpgconf_rc_objs) -resource_objs += $(gpg_card_tool_rc_objs) -resource_objs += $(gpgtar_rc_objs) -resource_objs += $(gpg_check_pattern_rc_objs) -resource_objs += $(gpg_wks_client_rc_objs) + +gpg-connect-agent-w32info.o : gpg-connect-agent.w32-manifest \ + ../common/w32info-rc.h +gpgconf-w32info.o : gpgconf.w32-manifest ../common/w32info-rc.h +gpg-card-w32info.o : gpg-card.w32-manifest ../common/w32info-rc.h +gpgtar-w32info.o : gpgtar.w32-manifest ../common/w32info-rc.h +gpg-check-pattern-w32info.o : gpg-check-pattern.w32-manifest \ + ../common/w32info-rc.h +gpg-wks-client-w32info.o : gpg-wks-client.w32-manifest \ + ../common/w32info-rc.h + endif AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS) $(LIBASSUAN_CFLAGS) diff --git a/tools/gpg-card.w32-manifest.in b/tools/gpg-card.w32-manifest.in index ab853f810..4630fce3e 100644 --- a/tools/gpg-card.w32-manifest.in +++ b/tools/gpg-card.w32-manifest.in @@ -15,4 +15,11 @@ + + + + + + + diff --git a/tools/gpg-check-pattern.w32-manifest.in b/tools/gpg-check-pattern.w32-manifest.in index 2a5f8ec72..acb7c914a 100644 --- a/tools/gpg-check-pattern.w32-manifest.in +++ b/tools/gpg-check-pattern.w32-manifest.in @@ -15,4 +15,11 @@ + + + + + + + diff --git a/tools/gpg-connect-agent.w32-manifest.in b/tools/gpg-connect-agent.w32-manifest.in index aba542052..c222a6794 100644 --- a/tools/gpg-connect-agent.w32-manifest.in +++ b/tools/gpg-connect-agent.w32-manifest.in @@ -15,4 +15,11 @@ + + + + + + + diff --git a/tools/gpg-wks-client.w32-manifest.in b/tools/gpg-wks-client.w32-manifest.in index ba2508e5f..c44620f0e 100644 --- a/tools/gpg-wks-client.w32-manifest.in +++ b/tools/gpg-wks-client.w32-manifest.in @@ -15,4 +15,11 @@ + + + + + + + diff --git a/tools/gpgconf.w32-manifest.in b/tools/gpgconf.w32-manifest.in index d7a1b01ec..ab5f17d04 100644 --- a/tools/gpgconf.w32-manifest.in +++ b/tools/gpgconf.w32-manifest.in @@ -15,4 +15,11 @@ + + + + + + + diff --git a/tools/gpgtar.w32-manifest.in b/tools/gpgtar.w32-manifest.in index 62d5937fa..b949a6baa 100644 --- a/tools/gpgtar.w32-manifest.in +++ b/tools/gpgtar.w32-manifest.in @@ -15,4 +15,11 @@ + + + + + + + From 6657230f9ee40ca0cfcfd16c12b3288a975944b0 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 24 May 2023 14:16:10 +0200 Subject: [PATCH 06/56] w32: Add missing supportedOS Ids for Windows-10 -- --- agent/gpg-agent.w32-manifest.in | 1 + dirmngr/dirmngr-client.w32-manifest.in | 2 +- dirmngr/dirmngr_ldap.w32-manifest.in | 2 +- g10/gpg.w32-manifest.in | 1 + g10/gpgv.w32-manifest.in | 1 + kbx/keyboxd.w32-manifest.in | 1 + scd/scdaemon.w32-manifest.in | 1 + sm/gpgsm.w32-manifest.in | 1 + 8 files changed, 8 insertions(+), 2 deletions(-) diff --git a/agent/gpg-agent.w32-manifest.in b/agent/gpg-agent.w32-manifest.in index 87f09aa49..7991a9699 100644 --- a/agent/gpg-agent.w32-manifest.in +++ b/agent/gpg-agent.w32-manifest.in @@ -12,6 +12,7 @@ + diff --git a/dirmngr/dirmngr-client.w32-manifest.in b/dirmngr/dirmngr-client.w32-manifest.in index 1d46d19ff..670bb60f1 100644 --- a/dirmngr/dirmngr-client.w32-manifest.in +++ b/dirmngr/dirmngr-client.w32-manifest.in @@ -3,7 +3,7 @@ GNU Privacy Guard (Dirmngr Client) diff --git a/dirmngr/dirmngr_ldap.w32-manifest.in b/dirmngr/dirmngr_ldap.w32-manifest.in index 67db0841c..509b5e0d1 100644 --- a/dirmngr/dirmngr_ldap.w32-manifest.in +++ b/dirmngr/dirmngr_ldap.w32-manifest.in @@ -3,7 +3,7 @@ GNU Privacy Guard (LDAP Helper) diff --git a/g10/gpg.w32-manifest.in b/g10/gpg.w32-manifest.in index bf7723925..9a7752382 100644 --- a/g10/gpg.w32-manifest.in +++ b/g10/gpg.w32-manifest.in @@ -12,6 +12,7 @@ + diff --git a/g10/gpgv.w32-manifest.in b/g10/gpgv.w32-manifest.in index 794ab15c3..66291a2bc 100644 --- a/g10/gpgv.w32-manifest.in +++ b/g10/gpgv.w32-manifest.in @@ -12,6 +12,7 @@ + diff --git a/kbx/keyboxd.w32-manifest.in b/kbx/keyboxd.w32-manifest.in index f2e50fb4b..ff75ea504 100644 --- a/kbx/keyboxd.w32-manifest.in +++ b/kbx/keyboxd.w32-manifest.in @@ -12,6 +12,7 @@ + diff --git a/scd/scdaemon.w32-manifest.in b/scd/scdaemon.w32-manifest.in index aa0ccb206..224646661 100644 --- a/scd/scdaemon.w32-manifest.in +++ b/scd/scdaemon.w32-manifest.in @@ -12,6 +12,7 @@ + diff --git a/sm/gpgsm.w32-manifest.in b/sm/gpgsm.w32-manifest.in index 7764be394..d477cce32 100644 --- a/sm/gpgsm.w32-manifest.in +++ b/sm/gpgsm.w32-manifest.in @@ -12,6 +12,7 @@ + From 80097bc78bf7bcc0bef9f125af3c545620cd5cc7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 24 May 2023 16:02:39 +0200 Subject: [PATCH 07/56] gpg: Return ERROR status for --quick-sign-key. * g10/keyedit.c (keyedit_quick_sign): Return an error status line. -- --- g10/keyedit.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/g10/keyedit.c b/g10/keyedit.c index 4b767aed6..e16a40ead 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -2810,7 +2810,7 @@ void keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids, strlist_t locusr, int local) { - gpg_error_t err; + gpg_error_t err = 0; kbnode_t keyblock = NULL; KEYDB_HANDLE kdbhd = NULL; int modified = 0; @@ -2848,6 +2848,7 @@ keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids, if (!opt.verbose) show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 0, 0, 0, 0, 1); log_error ("%s%s", _("Key is revoked."), _(" Unable to sign.\n")); + err = gpg_error (GPG_ERR_CERT_REVOKED); goto leave; } @@ -2925,6 +2926,7 @@ keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids, sl->d, gpg_strerror (GPG_ERR_NOT_FOUND)); } log_error ("%s %s", _("No matching user IDs."), _("Nothing to sign.\n")); + err = gpg_error (GPG_ERR_NO_USER_ID); goto leave; } @@ -2947,8 +2949,9 @@ keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids, if (update_trust) revalidation_mark (ctrl); - leave: + if (err) + write_status_error ("keyedit.sign-key", err); release_kbnode (keyblock); keydb_release (kdbhd); } @@ -2964,7 +2967,7 @@ void keyedit_quick_revsig (ctrl_t ctrl, const char *username, const char *sigtorev, strlist_t affected_uids) { - gpg_error_t err; + gpg_error_t err = 0; int no_signing_key = 0; KEYDB_HANDLE kdbhd = NULL; kbnode_t keyblock = NULL; From 6a2cb8cfd71457599fee4a63da6f649fdd07deb5 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 25 May 2023 11:07:51 +0900 Subject: [PATCH 08/56] agent,w32: Fix resource leak for a process. * agent/call-daemon.c (wait_child_thread): Call assuan_set_flag only for !HAVE_W32_SYSTEM. Signed-off-by: NIIBE Yutaka --- agent/call-daemon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/agent/call-daemon.c b/agent/call-daemon.c index 0c3605274..e1c5669e9 100644 --- a/agent/call-daemon.c +++ b/agent/call-daemon.c @@ -153,6 +153,8 @@ wait_child_thread (void *arg) name, WSTOPSIG (wstatus)); goto again; } + + assuan_set_flag (g->primary_ctx, ASSUAN_NO_WAITPID, 1); } #endif /*!HAVE_W32_SYSTEM*/ @@ -166,8 +168,6 @@ wait_child_thread (void *arg) } else { - assuan_set_flag (g->primary_ctx, ASSUAN_NO_WAITPID, 1); - for (sl = g->local_list; sl; sl = sl->next_local) { sl->invalid = 1; From 0f8e5f1c1db03c88416eb5b21091251f4a7a8176 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 25 May 2023 11:13:07 +0900 Subject: [PATCH 09/56] po: Update Japanese Translation. -- Signed-off-by: NIIBE Yutaka --- po/ja.po | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/po/ja.po b/po/ja.po index 9d286148b..236d78ced 100644 --- a/po/ja.po +++ b/po/ja.po @@ -11,7 +11,7 @@ msgid "" msgstr "" "Project-Id-Version: gnupg 2.4.1\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n" -"PO-Revision-Date: 2023-04-26 13:35+0900\n" +"PO-Revision-Date: 2023-05-25 11:12+0900\n" "Last-Translator: NIIBE Yutaka \n" "Language-Team: none\n" "Language: ja\n" @@ -226,8 +226,8 @@ msgid "" "Please enter a passphrase to protect the received secret key%%0A %s%%0A " "%s%%0Awithin gpg-agent's key storage" msgstr "" -"パスフレーズを入力してください。gpg-agentの鍵の保管で受信した秘密鍵%%0A %s" -"%%0A %s%%0Aを保護します。" +"パスフレーズを入力してください。gpg-agentの鍵の保管で受信した秘密鍵%%0A " +"%s%%0A %s%%0Aを保護します。" #, c-format msgid "failed to create stream from socket: %s\n" @@ -759,8 +759,8 @@ msgstr "" #, c-format msgid "" -"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C" -"%%0A?" +"Do you really want to delete the key identified by keygrip%%0A %s%%0A " +"%%C%%0A?" msgstr "本当にこの鍵: keygrip%%0A %s%%0A %%C%%0Aを削除しますか?" msgid "Delete key" @@ -3710,6 +3710,10 @@ msgstr "*警告*: あなたの暗号副鍵はもうすぐ期限切れとなり msgid "You may want to change its expiration date too.\n" msgstr "その有効期限も変更したいでしょう\n" +#, c-format +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "*警告*: 有効な暗号副鍵がひとつも残っていません。\n" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" From 14828c75be10d61f35a46c58541aa39884b33bcd Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 25 May 2023 11:57:04 +0200 Subject: [PATCH 10/56] gpg: Fix searching for the ADSK key when adding an ADSK. * g10/keyedit.c (menu_addadsk): Request an exact search. * g10/getkey.c (finish_lookup): Add an debug output. -- GnuPG-bug-id: 6504 --- g10/getkey.c | 3 +++ g10/keyedit.c | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/g10/getkey.c b/g10/getkey.c index 15905dc63..68d7ee61d 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -3655,6 +3655,9 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact, break; } } + if (DBG_LOOKUP) + log_debug ("finish_lookup: exact search requested: %sfound\n", + foundk? "":"not "); } /* Get the user id that matched that low-level search criteria. */ diff --git a/g10/keyedit.c b/g10/keyedit.c index e16a40ead..21c1ee8d8 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -4844,6 +4844,15 @@ menu_addadsk (ctrl_t ctrl, kbnode_t pub_keyblock, const char *adskfpr) continue; } + /* Force searching for that exact fingerprint and for any key + * which has a key with that fingerprint. */ + if (!strchr (answer, '!')) + { + char *tmpstr = xstrconcat (answer, "!", NULL); + xfree (answer); + answer = tmpstr; + } + free_public_key (adsk_pk); adsk_pk = xcalloc (1, sizeof *adsk_pk); adsk_pk->req_usage = PUBKEY_USAGE_ENC; From 9f2f7a51b2430056168363828722afc6c7488946 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 25 May 2023 16:43:37 +0200 Subject: [PATCH 11/56] gpg: Skip keys found via ADSKs. * g10/encrypt.c (write_pubkey_enc): Indicate encryption to an ADSK. * g10/getkey.c (finish_lookup): Skip ADKS keys. -- If a key is searched by fingerprint or keyid and it happens that this is an ADSK (subkey with the RENC usage), we need to skip this key because it is not the key we actually want to encrypt to. The actual ADSK key is taken later by looking at all subkeys of the actual selected key. This is related to GnuPG-bug-id: 6504 --- g10/encrypt.c | 6 ++++++ g10/getkey.c | 37 ++++++++++++++++++++++--------------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/g10/encrypt.c b/g10/encrypt.c index 687b4344e..ff1c6be85 100644 --- a/g10/encrypt.c +++ b/g10/encrypt.c @@ -1171,6 +1171,12 @@ write_pubkey_enc (ctrl_t ctrl, if ( opt.verbose ) { char *ustr = get_user_id_string_native (ctrl, enc->keyid); + if ((pk->pubkey_usage & PUBKEY_USAGE_RENC)) + { + char *tmpustr = xstrconcat (ustr, " [ADSK]", NULL); + xfree (ustr); + ustr = tmpustr; + } log_info (_("%s/%s.%s encrypted for: \"%s\"\n"), openpgp_pk_algo_name (enc->pubkey_algo), openpgp_cipher_algo_name (dek->algo), diff --git a/g10/getkey.c b/g10/getkey.c index 68d7ee61d..21ffd5cfa 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -3640,24 +3640,31 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact, log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY); /* For an exact match mark the primary or subkey that matched the - low-level search criteria. */ - if (want_exact) + * low-level search criteria. Use this loop also to sort our keys + * found using an ADSK fingerprint. */ + for (k = keyblock; k; k = k->next) { - for (k = keyblock; k; k = k->next) - { - if ((k->flag & 1)) - { - log_assert (k->pkt->pkttype == PKT_PUBLIC_KEY - || k->pkt->pkttype == PKT_PUBLIC_SUBKEY); - foundk = k; + if ((k->flag & 1) && (k->pkt->pkttype == PKT_PUBLIC_KEY + || k->pkt->pkttype == PKT_PUBLIC_SUBKEY)) + { + if (want_exact) + { + if (DBG_LOOKUP) + log_debug ("finish_lookup: exact search requested and found\n"); + foundk = k; pk = k->pkt->pkt.public_key; pk->flags.exact = 1; - break; - } - } - if (DBG_LOOKUP) - log_debug ("finish_lookup: exact search requested: %sfound\n", - foundk? "":"not "); + break; + } + else if ((k->pkt->pkt.public_key->pubkey_usage == PUBKEY_USAGE_RENC)) + { + if (DBG_LOOKUP) + log_debug ("finish_lookup: found via ADSK - not selected\n"); + if (r_flags) + *r_flags |= LOOKUP_NOT_SELECTED; + return NULL; /* Not found. */ + } + } } /* Get the user id that matched that low-level search criteria. */ From a048a93ed2c3171cfc21b830762adada8965d92c Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 26 May 2023 11:56:36 +0200 Subject: [PATCH 12/56] common: New function nve_set * common/name-value.c (nve_set): New. -- Taken from 2.2 commit 706adf669173ec604158e4a2f4337e3da6cb1e45 --- common/name-value.c | 24 ++++++++++++++++++++++++ common/name-value.h | 3 +++ 2 files changed, 27 insertions(+) diff --git a/common/name-value.c b/common/name-value.c index 67429e47f..6f3df5a8d 100644 --- a/common/name-value.c +++ b/common/name-value.c @@ -497,6 +497,30 @@ nvc_set (nvc_t pk, const char *name, const char *value) } +/* Update entry E to VALUE. */ +gpg_error_t +nve_set (nve_t e, const char *value) +{ + char *v; + + if (!e) + return GPG_ERR_INV_ARG; + + v = xtrystrdup (value? value:""); + if (!v) + return my_error_from_syserror (); + + free_strlist_wipe (e->raw_value); + e->raw_value = NULL; + if (e->value) + wipememory (e->value, strlen (e->value)); + xfree (e->value); + e->value = v; + + return 0; +} + + /* Delete the given entry from PK. */ void nvc_delete (nvc_t pk, nve_t entry) diff --git a/common/name-value.h b/common/name-value.h index 504b5d0f0..b3fc2f63c 100644 --- a/common/name-value.h +++ b/common/name-value.h @@ -92,6 +92,9 @@ gpg_error_t nvc_add (nvc_t pk, const char *name, const char *value); first entry is updated. */ gpg_error_t nvc_set (nvc_t pk, const char *name, const char *value); +/* Update entry E to VALUE. */ +gpg_error_t nve_set (nve_t e, const char *value); + /* Delete the given entry from PK. */ void nvc_delete (nvc_t pk, nve_t pke); From 13013ec1c0d308b5d22f176f3850840cbbf21f05 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 26 May 2023 11:59:46 +0200 Subject: [PATCH 13/56] agent: Create and use Token entries to track the display s/n. * agent/findkey.c (agent_write_private_key): Add arg dispserialno and update the token. (agent_write_shadow_key): Add arg dispserialno and adjust all callers. -- GnuPG-bug-id: 6135 Note that this has been forward ported from 2.2 --- agent/agent.h | 13 ++++++---- agent/command-ssh.c | 9 +++++-- agent/command.c | 15 ++++++++--- agent/cvt-openpgp.c | 4 +-- agent/divert-tpm2.c | 2 +- agent/findkey.c | 61 ++++++++++++++++++++++++++++++++++++-------- agent/genkey.c | 3 ++- agent/learncard.c | 10 +++++++- agent/pksign.c | 9 ++++++- agent/protect-tool.c | 5 ++-- 10 files changed, 102 insertions(+), 29 deletions(-) diff --git a/agent/agent.h b/agent/agent.h index 4e7452eee..531fad210 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -452,10 +452,12 @@ void start_command_handler_ssh (ctrl_t, gnupg_fd_t); /*-- findkey.c --*/ gpg_error_t agent_modify_description (const char *in, const char *comment, const gcry_sexp_t key, char **result); -int agent_write_private_key (const unsigned char *grip, - const void *buffer, size_t length, int force, - const char *serialno, const char *keyref, - time_t timestamp); +gpg_error_t agent_write_private_key (const unsigned char *grip, + const void *buffer, size_t length, + int force, + const char *serialno, const char *keyref, + const char *dispserialno, + time_t timestamp); gpg_error_t agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, @@ -587,7 +589,8 @@ gpg_error_t s2k_hash_passphrase (const char *passphrase, int hashalgo, unsigned char *key, size_t keylen); gpg_error_t agent_write_shadow_key (const unsigned char *grip, const char *serialno, const char *keyid, - const unsigned char *pkbuf, int force); + const unsigned char *pkbuf, int force, + const char *dispserialno); /*-- trustlist.c --*/ diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 51111a60d..ca3993321 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -2432,9 +2432,14 @@ card_key_available (ctrl_t ctrl, const struct card_key_info_s *keyinfo, hex2bin (keyinfo->keygrip, grip, sizeof (grip)); if ( agent_key_available (grip) ) { + char *dispserialno; + /* (Shadow)-key is not available in our key storage. */ + agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno, + keyinfo->keygrip); err = agent_write_shadow_key (grip, keyinfo->serialno, - keyinfo->idstr, pkbuf, 0); + keyinfo->idstr, pkbuf, 0, dispserialno); + xfree (dispserialno); if (err) { xfree (pkbuf); @@ -3282,7 +3287,7 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec, /* Store this key to our key storage. We do not store a creation * timestamp because we simply do not know. */ err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0, - NULL, NULL, 0); + NULL, NULL, NULL, 0); if (err) goto out; diff --git a/agent/command.c b/agent/command.c index dd7cb5e57..b7a71cbe5 100644 --- a/agent/command.c +++ b/agent/command.c @@ -1359,7 +1359,14 @@ cmd_readkey (assuan_context_t ctx, char *line) if (agent_key_available (grip)) { /* (Shadow)-key is not available in our key storage. */ - rc = agent_write_shadow_key (grip, serialno, keyid, pkbuf, 0); + char *dispserialno; + char hexgrip[40+1]; + + bin2hex (grip, 20, hexgrip); + agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno, hexgrip); + rc = agent_write_shadow_key (grip, serialno, keyid, pkbuf, 0, + dispserialno); + xfree (dispserialno); if (rc) goto leave; } @@ -2916,11 +2923,11 @@ cmd_import_key (assuan_context_t ctx, char *line) ctrl->s2k_count); if (!err) err = agent_write_private_key (grip, finalkey, finalkeylen, force, - NULL, NULL, opt_timestamp); + NULL, NULL, NULL, opt_timestamp); } else - err = agent_write_private_key (grip, key, realkeylen, force, NULL, NULL, - opt_timestamp); + err = agent_write_private_key (grip, key, realkeylen, force, + NULL, NULL, NULL, opt_timestamp); leave: gcry_sexp_release (openpgp_sexp); diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c index 9bb815ff8..6aad35bff 100644 --- a/agent/cvt-openpgp.c +++ b/agent/cvt-openpgp.c @@ -1148,7 +1148,7 @@ convert_from_openpgp_native (ctrl_t ctrl, &protectedkey, &protectedkeylen, ctrl->s2k_count)) agent_write_private_key (grip, protectedkey, protectedkeylen, 1, - NULL, NULL, 0); + NULL, NULL, NULL, 0); xfree (protectedkey); } else @@ -1157,7 +1157,7 @@ convert_from_openpgp_native (ctrl_t ctrl, agent_write_private_key (grip, *r_key, gcry_sexp_canon_len (*r_key, 0, NULL,NULL), - 1, NULL, NULL, 0); + 1, NULL, NULL, NULL, 0); } } diff --git a/agent/divert-tpm2.c b/agent/divert-tpm2.c index 4cae66218..b2f884f93 100644 --- a/agent/divert-tpm2.c +++ b/agent/divert-tpm2.c @@ -50,7 +50,7 @@ agent_write_tpm2_shadow_key (ctrl_t ctrl, const unsigned char *grip, len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL); err = agent_write_private_key (grip, shdkey, len, 1 /*force*/, - NULL, NULL, 0); + NULL, NULL, NULL, 0); xfree (shdkey); if (err) log_error ("error writing key: %s\n", gpg_strerror (err)); diff --git a/agent/findkey.c b/agent/findkey.c index 098d5224f..a9cb96a0c 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -84,12 +84,13 @@ linefeed_to_percent0A (const char *string) * storage. With FORCE passed as true an existing key with the given * GRIP will get overwritten. If SERIALNO and KEYREF are given a * Token line is added to the key if the extended format is used. If - * TIMESTAMP is not zero and the key doies not yet exists it will be + * TIMESTAMP is not zero and the key does not yet exists it will be * recorded as creation date. */ -int +gpg_error_t agent_write_private_key (const unsigned char *grip, const void *buffer, size_t length, int force, const char *serialno, const char *keyref, + const char *dispserialno, time_t timestamp) { gpg_error_t err; @@ -100,7 +101,10 @@ agent_write_private_key (const unsigned char *grip, nvc_t pk = NULL; gcry_sexp_t key = NULL; int remove = 0; + char *token0 = NULL; char *token = NULL; + char *dispserialno_buffer = NULL; + char **tokenfields = NULL; bin2hex (grip, 20, hexgrip); strcpy (hexgrip+40, ".key"); @@ -225,19 +229,34 @@ agent_write_private_key (const unsigned char *grip, { nve_t item; const char *s; + size_t token0len; - token = strconcat (serialno, " ", keyref, NULL); - if (!token) + if (dispserialno) + { + /* Escape the DISPSERIALNO. */ + dispserialno_buffer = percent_plus_escape (dispserialno); + if (!dispserialno_buffer) + { + err = gpg_error_from_syserror (); + goto leave; + } + dispserialno = dispserialno_buffer; + } + + token0 = strconcat (serialno, " ", keyref, NULL); + if (token0) + token = strconcat (token0, " - ", dispserialno? dispserialno:"-", NULL); + if (!token0 || !token) { err = gpg_error_from_syserror (); goto leave; } - /* fixme: the strcmp should compare only the first two strings. */ + token0len = strlen (token0); for (item = nvc_lookup (pk, "Token:"); item; item = nve_next_value (item, "Token:")) - if ((s = nve_value (item)) && !strcmp (s, token)) + if ((s = nve_value (item)) && !strncmp (s, token0, token0len)) break; if (!item) { @@ -248,6 +267,23 @@ agent_write_private_key (const unsigned char *grip, if (err) goto leave; } + else + { + /* Token exists: Update the display s/n. It may have + * changed due to changes in a newer software version. */ + if (s && (tokenfields = strtokenize (s, " \t\n")) + && tokenfields[0] && tokenfields[1] && tokenfields[2] + && tokenfields[3] + && !strcmp (tokenfields[3], dispserialno)) + ; /* No need to update Token entry. */ + else + { + err = nve_set (item, token); + if (err) + goto leave; + } + } + } /* If a timestamp has been supplied and the key is new, write a @@ -300,12 +336,15 @@ agent_write_private_key (const unsigned char *grip, leave: es_fclose (fp); - if (remove) + if (remove && fname) gnupg_remove (fname); xfree (fname); + xfree (token); + xfree (token0); + xfree (dispserialno_buffer); + xfree (tokenfields); gcry_sexp_release (key); nvc_release (pk); - xfree (token); return err; } @@ -1794,7 +1833,8 @@ agent_delete_key (ctrl_t ctrl, const char *desc_text, gpg_error_t agent_write_shadow_key (const unsigned char *grip, const char *serialno, const char *keyid, - const unsigned char *pkbuf, int force) + const unsigned char *pkbuf, int force, + const char *dispserialno) { gpg_error_t err; unsigned char *shadow_info; @@ -1821,7 +1861,8 @@ agent_write_shadow_key (const unsigned char *grip, } len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL); - err = agent_write_private_key (grip, shdkey, len, force, serialno, keyid, 0); + err = agent_write_private_key (grip, shdkey, len, force, + serialno, keyid, dispserialno, 0); xfree (shdkey); if (err) log_error ("error writing key: %s\n", gpg_strerror (err)); diff --git a/agent/genkey.c b/agent/genkey.c index 7660443ca..741c05f4f 100644 --- a/agent/genkey.c +++ b/agent/genkey.c @@ -67,7 +67,8 @@ store_key (gcry_sexp_t private, const char *passphrase, int force, buf = p; } - rc = agent_write_private_key (grip, buf, len, force, NULL, NULL, timestamp); + rc = agent_write_private_key (grip, buf, len, force, + NULL, NULL, NULL, timestamp); xfree (buf); return rc; } diff --git a/agent/learncard.c b/agent/learncard.c index 678ff9b96..8d80b809d 100644 --- a/agent/learncard.c +++ b/agent/learncard.c @@ -408,7 +408,15 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force) goto leave; } - rc = agent_write_shadow_key (grip, serialno, item->id, pubkey, force); + { + char *dispserialno; + + agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno, + item->hexgrip); + rc = agent_write_shadow_key (grip, serialno, item->id, pubkey, force, + dispserialno); + xfree (dispserialno); + } xfree (pubkey); if (rc) goto leave; diff --git a/agent/pksign.c b/agent/pksign.c index dfed0e398..a7b5c579f 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -372,8 +372,15 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce, } if (keyref) - agent_write_shadow_key (ctrl->keygrip, serialno, keyref, pkbuf, 0); + { + char *dispserialno; + agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno, + hexgrip); + agent_write_shadow_key (ctrl->keygrip, serialno, keyref, pkbuf, + 0, dispserialno); + xfree (dispserialno); + } algo = get_pk_algo_from_key (s_pkey); xfree (serialno); diff --git a/agent/protect-tool.c b/agent/protect-tool.c index 87cf36814..17f6fd559 100644 --- a/agent/protect-tool.c +++ b/agent/protect-tool.c @@ -813,11 +813,11 @@ agent_askpin (ctrl_t ctrl, /* Replacement for the function in findkey.c. Here we write the key * to stdout. */ -int +gpg_error_t agent_write_private_key (const unsigned char *grip, const void *buffer, size_t length, int force, const char *serialno, const char *keyref, - time_t timestamp) + const char *dispserialno, time_t timestamp) { char hexgrip[40+4+1]; char *p; @@ -826,6 +826,7 @@ agent_write_private_key (const unsigned char *grip, (void)serialno; (void)keyref; (void)timestamp; + (void)dispserialno; bin2hex (grip, 20, hexgrip); strcpy (hexgrip+40, ".key"); From 05f29b5c7caa6cdac94218029153a2b5451c8281 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 26 May 2023 13:57:36 +0200 Subject: [PATCH 14/56] agent: Update key files by first writing to a temp file. * agent/findkey.c (fname_from_keygrip): New. (agent_write_private_key): Use here. Use temp file for updating. (agent_update_private_key): Use fname_from_keygrip and use gnupg rename function instead of a vanilla rename. --- agent/findkey.c | 169 ++++++++++++++++++++++++++++-------------------- 1 file changed, 100 insertions(+), 69 deletions(-) diff --git a/agent/findkey.c b/agent/findkey.c index a9cb96a0c..2d0636cd2 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -50,6 +50,22 @@ struct try_unprotect_arg_s }; +/* Return the file name for the 20 byte keygrip GRIP. With FOR_NEW + * create a file name for later renaming to the actual name. Return + * NULL on error. */ +static char * +fname_from_keygrip (const unsigned char *grip, int for_new) +{ + char hexgrip[40+4+4+1]; + + bin2hex (grip, 20, hexgrip); + strcpy (hexgrip+40, for_new? ".key.tmp" : ".key"); + + return make_filename_try (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR, + hexgrip, NULL); +} + + /* Replace all linefeeds in STRING by "%0A" and return a new malloced * string. May return NULL on memory error. */ static char * @@ -94,26 +110,22 @@ agent_write_private_key (const unsigned char *grip, time_t timestamp) { gpg_error_t err; - char *fname; + char *fname = NULL; + char *tmpfname = NULL; estream_t fp; - char hexgrip[40+4+1]; int update, newkey; nvc_t pk = NULL; gcry_sexp_t key = NULL; - int remove = 0; + int removetmp = 0; char *token0 = NULL; char *token = NULL; char *dispserialno_buffer = NULL; char **tokenfields = NULL; + int blocksigs = 0; - bin2hex (grip, 20, hexgrip); - strcpy (hexgrip+40, ".key"); - - fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR, - hexgrip, NULL); - - /* FIXME: Write to a temp file first so that write failures during - key updates won't lead to a key loss. */ + fname = fname_from_keygrip (grip, 0); + if (!fname) + return gpg_error_from_syserror (); if (!force && !gnupg_access (fname, F_OK)) { @@ -213,7 +225,8 @@ agent_write_private_key (const unsigned char *grip, goto leave; } } - es_clearerr (fp); + es_fclose (fp); + fp = NULL; /* Turn (BUFFER,LENGTH) into a gcrypt s-expression and set it into * our name value container. */ @@ -299,46 +312,55 @@ agent_write_private_key (const unsigned char *grip, goto leave; } - /* Back to start and write. */ - err = es_fseek (fp, 0, SEEK_SET); - if (err) - goto leave; - - err = nvc_write (pk, fp); - if (!err) - err = es_fflush (fp); - if (err) + /* Create a temporary file for writing. */ + tmpfname = fname_from_keygrip (grip, 1); + fp = tmpfname ? es_fopen (tmpfname, "wbx,mode=-rw") : NULL; + if (!fp) { - log_error ("error writing '%s': %s\n", fname, gpg_strerror (err)); - remove = 1; + err = gpg_error_from_syserror (); + log_error ("can't create '%s': %s\n", tmpfname, gpg_strerror (err)); goto leave; } - if (ftruncate (es_fileno (fp), es_ftello (fp))) + err = nvc_write (pk, fp); + if (!err && es_fflush (fp)) + err = gpg_error_from_syserror (); + if (err) { - err = gpg_error_from_syserror (); - log_error ("error truncating '%s': %s\n", fname, gpg_strerror (err)); - remove = 1; + log_error ("error writing '%s': %s\n", tmpfname, gpg_strerror (err)); + removetmp = 1; goto leave; } if (es_fclose (fp)) { err = gpg_error_from_syserror (); - log_error ("error closing '%s': %s\n", fname, gpg_strerror (err)); - remove = 1; + log_error ("error closing '%s': %s\n", tmpfname, gpg_strerror (err)); + removetmp = 1; goto leave; } else fp = NULL; + err = gnupg_rename_file (tmpfname, fname, &blocksigs); + if (err) + { + err = gpg_error_from_syserror (); + log_error ("error renaming '%s': %s\n", tmpfname, gpg_strerror (err)); + removetmp = 1; + goto leave; + } + bump_key_eventcounter (); leave: + if (blocksigs) + gnupg_unblock_all_signals (); es_fclose (fp); - if (remove && fname) + if (removetmp && fname) gnupg_remove (fname); xfree (fname); + xfree (tmpfname); xfree (token); xfree (token0); xfree (dispserialno_buffer); @@ -352,53 +374,63 @@ agent_write_private_key (const unsigned char *grip, gpg_error_t agent_update_private_key (const unsigned char *grip, nvc_t pk) { - char *fname, *fname0; - estream_t fp; - char hexgrip[40+8+1]; gpg_error_t err; + char *fname0 = NULL; /* The existing file name. */ + char *fname = NULL; /* The temporary new file name. */ + estream_t fp = NULL; + int removetmp = 0; + int blocksigs = 0; - bin2hex (grip, 20, hexgrip); - strcpy (hexgrip+40, ".key.tmp"); - - fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR, - hexgrip, NULL); - fname0 = xstrdup (fname); - if (!fname0) + fname0 = fname_from_keygrip (grip, 0); + if (!fname) { err = gpg_error_from_syserror (); - xfree (fname); - return err; + goto leave; + } + fname = fname_from_keygrip (grip, 1); + if (!fname) + { + err = gpg_error_from_syserror (); + goto leave; } - fname0[strlen (fname)-4] = 0; fp = es_fopen (fname, "wbx,mode=-rw"); if (!fp) { err = gpg_error_from_syserror (); - log_error ("can't create '%s': %s\n", fname, gpg_strerror (err)); - xfree (fname); - return err; + goto leave; } err = nvc_write (pk, fp); if (err) - log_error ("error writing '%s': %s\n", fname, gpg_strerror (err)); - - es_fclose (fp); - -#ifdef HAVE_W32_SYSTEM - /* No atomic mv on W32 systems. */ - gnupg_remove (fname0); -#endif - if (rename (fname, fname0)) { - err = gpg_error_from_errno (errno); - log_error (_("error renaming '%s' to '%s': %s\n"), - fname, fname0, strerror (errno)); + log_error ("error writing '%s': %s\n", fname, gpg_strerror (err)); + removetmp = 1; + goto leave; } + es_fclose (fp); + fp = NULL; + + err = gnupg_rename_file (fname, fname0, &blocksigs); + if (err) + { + err = gpg_error_from_syserror (); + log_error ("error renaming '%s': %s\n", fname, gpg_strerror (err)); + removetmp = 1; + goto leave; + } + + + leave: + if (blocksigs) + gnupg_unblock_all_signals (); + es_fclose (fp); + if (removetmp && fname) + gnupg_remove (fname); xfree (fname); + xfree (fname0); return err; } @@ -885,18 +917,17 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta) unsigned char *buf; size_t buflen, erroff; gcry_sexp_t s_skey; - char hexgrip[40+4+1]; char first; *result = NULL; if (r_keymeta) *r_keymeta = NULL; - bin2hex (grip, 20, hexgrip); - strcpy (hexgrip+40, ".key"); - - fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR, - hexgrip, NULL); + fname = fname_from_keygrip (grip, 0); + if (!fname) + { + return gpg_error_from_syserror (); + } fp = es_fopen (fname, "rb"); if (!fp) { @@ -1012,12 +1043,12 @@ remove_key_file (const unsigned char *grip) { gpg_error_t err = 0; char *fname; - char hexgrip[40+4+1]; - bin2hex (grip, 20, hexgrip); - strcpy (hexgrip+40, ".key"); - fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR, - hexgrip, NULL); + fname = fname_from_keygrip (grip, 0); + if (!fname) + { + return gpg_error_from_syserror (); + } if (gnupg_remove (fname)) err = gpg_error_from_syserror (); xfree (fname); From a1015bf2fc07dabb1200eab5fa41f13e7bf98202 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 26 May 2023 14:24:55 +0200 Subject: [PATCH 15/56] agent: Do not overwrite a key file by a shadow key file. * agent/findkey.c (agent_write_private_key): Partly rewrite to align with 2.2 code and to make sure that we don't overwrite a real key. (is_shadowed_key): New. -- This change is now also needed in 2.4 due to the the former change "Create and use Token entries to track the display s/n". GnuPG-bug-id: 6386 --- agent/findkey.c | 154 ++++++++++++++++++++---------------------------- 1 file changed, 64 insertions(+), 90 deletions(-) diff --git a/agent/findkey.c b/agent/findkey.c index 2d0636cd2..41f911cf8 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -39,6 +39,12 @@ #define O_BINARY 0 #endif + +static gpg_error_t read_key_file (const unsigned char *grip, + gcry_sexp_t *result, nvc_t *r_keymeta); +static gpg_error_t is_shadowed_key (gcry_sexp_t s_skey); + + /* Helper to pass data to the check callback of the unprotect function. */ struct try_unprotect_arg_s { @@ -113,7 +119,7 @@ agent_write_private_key (const unsigned char *grip, char *fname = NULL; char *tmpfname = NULL; estream_t fp; - int update, newkey; + int newkey; nvc_t pk = NULL; gcry_sexp_t key = NULL; int removetmp = 0; @@ -121,103 +127,29 @@ agent_write_private_key (const unsigned char *grip, char *token = NULL; char *dispserialno_buffer = NULL; char **tokenfields = NULL; + int is_regular; int blocksigs = 0; fname = fname_from_keygrip (grip, 0); if (!fname) return gpg_error_from_syserror (); - if (!force && !gnupg_access (fname, F_OK)) + err = read_key_file (grip, &key, &pk); + if (err) { - log_error ("secret key file '%s' already exists\n", fname); - xfree (fname); - return gpg_error (GPG_ERR_EEXIST); - } - - fp = es_fopen (fname, force? "rb+,mode=-rw" : "wbx,mode=-rw"); - if (!fp) - { - gpg_error_t tmperr = gpg_error_from_syserror (); - - if (force && gpg_err_code (tmperr) == GPG_ERR_ENOENT) - { - fp = es_fopen (fname, "wbx,mode=-rw"); - if (!fp) - tmperr = gpg_error_from_syserror (); - } - if (!fp) - { - log_error ("can't create '%s': %s\n", fname, gpg_strerror (tmperr)); - xfree (fname); - return tmperr; - } - update = 0; - newkey = 1; - } - else if (force) - { - gpg_error_t rc; - char first; - - /* See if an existing key is in extended format. */ - if (es_fread (&first, 1, 1, fp) != 1) - { - rc = gpg_error_from_syserror (); - log_error ("error reading first byte from '%s': %s\n", - fname, strerror (errno)); - xfree (fname); - es_fclose (fp); - return rc; - } - - rc = es_fseek (fp, 0, SEEK_SET); - if (rc) - { - log_error ("error seeking in '%s': %s\n", fname, strerror (errno)); - xfree (fname); - es_fclose (fp); - return rc; - } - - if (first == '(') - { - /* Key is still in the old format - force it into extended - * format. We do not request an update here because an - * existing key is not yet in extended key format and no - * extended infos are yet available. */ - update = 0; - newkey = 0; - } + if (gpg_err_code (err) == GPG_ERR_ENOENT) + newkey = 1; else { - /* Key is already in the extended format. */ - update = 1; - newkey = 0; - } - } - else - { - /* The key file did not exist: we assume this is a new key and - * write the Created: entry. */ - update = 0; - newkey = 1; - } - - - if (update) - { - int line; - - err = nvc_parse_private_key (&pk, &line, fp); - if (err && gpg_err_code (err) != GPG_ERR_ENOENT) - { - log_error ("error parsing '%s' line %d: %s\n", - fname, line, gpg_strerror (err)); + log_error ("can't open '%s': %s\n", fname, gpg_strerror (err)); goto leave; } } - else + + if (!pk) { + /* Key is still in the old format or does not exist - create a + * new container. */ pk = nvc_new_private_key (); if (!pk) { @@ -225,11 +157,13 @@ agent_write_private_key (const unsigned char *grip, goto leave; } } - es_fclose (fp); - fp = NULL; + + /* Check whether we already have a regular key. */ + is_regular = (key && gpg_err_code (is_shadowed_key (key)) != GPG_ERR_TRUE); /* Turn (BUFFER,LENGTH) into a gcrypt s-expression and set it into * our name value container. */ + gcry_sexp_release (key); err = gcry_sexp_sscan (&key, NULL, buffer, length); if (err) goto leave; @@ -237,6 +171,23 @@ agent_write_private_key (const unsigned char *grip, if (err) goto leave; + /* Check that we do not update a regular key with a shadow key. */ + if (is_regular && gpg_err_code (is_shadowed_key (key)) == GPG_ERR_TRUE) + { + log_info ("updating regular key file '%s'" + " by a shadow key inhibited\n", fname); + err = 0; /* Simply ignore the error. */ + goto leave; + } + + /* Check that we update a regular key only in force mode. */ + if (is_regular && !force) + { + log_error ("secret key file '%s' already exists\n", fname); + err = gpg_error (GPG_ERR_EEXIST); + goto leave; + } + /* If requested write a Token line. */ if (serialno && keyref) { @@ -357,8 +308,8 @@ agent_write_private_key (const unsigned char *grip, if (blocksigs) gnupg_unblock_all_signals (); es_fclose (fp); - if (removetmp && fname) - gnupg_remove (fname); + if (removetmp && tmpfname) + gnupg_remove (tmpfname); xfree (fname); xfree (tmpfname); xfree (token); @@ -903,7 +854,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, /* Read the key identified by GRIP from the private key directory and * return it as an gcrypt S-expression object in RESULT. If R_KEYMETA - * is not NULl and the extended key format is used, the meta data + * is not NULL and the extended key format is used, the meta data * items are stored there. However the "Key:" item is removed from * it. On failure returns an error code and stores NULL at RESULT and * R_KEYMETA. */ @@ -1447,6 +1398,29 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, } +/* This function returns GPG_ERR_TRUE if S_SKEY represents a shadowed + * key. 0 is return for other key types. Any other error may occur + * if S_SKEY is not valid. */ +static gpg_error_t +is_shadowed_key (gcry_sexp_t s_skey) +{ + gpg_error_t err; + unsigned char *buf; + size_t buflen; + + err = make_canon_sexp (s_skey, &buf, &buflen); + if (err) + return err; + + if (agent_private_key_type (buf) == PRIVATE_KEY_SHADOWED) + err = gpg_error (GPG_ERR_TRUE); + + wipememory (buf, buflen); + xfree (buf); + return err; +} + + /* Return the key for the keygrip GRIP. The result is stored at RESULT. This function extracts the key from the private key database and returns it as an S-expression object as it is. On From f953d67446faaa5a4e3343900d933d8b0351d8f7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 26 May 2023 15:53:52 +0200 Subject: [PATCH 16/56] Prepare the NEWS for the next release -- --- NEWS | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/NEWS b/NEWS index af2064199..d58b0f3c1 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,28 @@ Noteworthy changes in version 2.4.2 (unreleased) ------------------------------------------------ + * gpg: Print a warning if no more encryption subkeys are left over + after chnaging the expiration date. [rGef2c3d50fa] + + * gpg: Fix searching for the ADSK key when adding an ADSK. [T6504] + + * gpgsm: Speed up key listings on Windows. [rG08ff55bd44] + + * gpgsm: Reduce the number of "failed to open policy file" + diagnostics. [rG68613a6a9d] + + * agent: Make updating of private key files more robust and track + display S/N. [T6135] + + * keyboxd: Avoid longish delays on Windows when listing keys. + [rG6944aefa3c] + + * gpgtar: Emit extra status lines to help GPGME. [T6497] + + * w32: Avoid using the VirtualStore. [T6403] + + Release-info: https://dev.gnupg.org/T6506 + Noteworthy changes in version 2.4.1 (2023-04-28) ------------------------------------------------ From 4cfa2efdc6f8b1bd1056cf4d2a25f51ff79a2249 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 30 May 2023 13:47:39 +0200 Subject: [PATCH 17/56] po: Translated one new string to German. -- --- po/de.po | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/po/de.po b/po/de.po index 64e444d01..bf4bda4a0 100644 --- a/po/de.po +++ b/po/de.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: gnupg-2.4.1\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n" -"PO-Revision-Date: 2023-03-21 09:31+0100\n" +"PO-Revision-Date: 2023-05-30 13:46+0200\n" "Last-Translator: Werner Koch \n" "Language-Team: German\n" "Language: de\n" @@ -745,10 +745,6 @@ msgstr "Korrekt" msgid "Wrong" msgstr "Falsch" -#, c-format -msgid "error renaming '%s' to '%s': %s\n" -msgstr "Fehler beim Umbenennen von `%s` nach `%s': %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -3834,6 +3830,10 @@ msgstr "WARNUNG: Ihr Unterschlüssel zum Verschlüsseln wird bald verfallen.\n" msgid "You may want to change its expiration date too.\n" msgstr "Bitte erwägen Sie, dessen Verfallsdatum auch zu ändern.\n" +#, c-format +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "WARNUNG: Es sind keine Unterschlüssel zum Verschlüsseln mehr vorhanden.\n" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -7934,6 +7934,10 @@ msgstr "" "Die temporäre Zwischenspeicherverzeichnisdatei `%s' konnte nicht erzeugt " "werden: %s\n" +#, c-format +msgid "error renaming '%s' to '%s': %s\n" +msgstr "Fehler beim Umbenennen von `%s` nach `%s': %s\n" + #, c-format msgid "can't hash '%s': %s\n" msgstr "Hashwert von `%s' kann nicht gebildet werden: %s\n" From 550bc15b006d6f2a6e7305a3e58be1dd6ed2295e Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 30 May 2023 13:49:57 +0200 Subject: [PATCH 18/56] po: msgmerge done -- --- po/ca.po | 14 ++++++--- po/cs.po | 13 +++++--- po/da.po | 14 ++++++--- po/el.po | 14 ++++++--- po/eo.po | 14 ++++++--- po/es.po | 13 +++++--- po/et.po | 14 ++++++--- po/fi.po | 14 ++++++--- po/fr.po | 13 +++++--- po/gl.po | 14 ++++++--- po/hu.po | 14 ++++++--- po/id.po | 14 ++++++--- po/it.po | 13 +++++--- po/ja.po | 16 +++++----- po/nb.po | 13 +++++--- po/pl.po | 13 +++++--- po/pt.po | 14 ++++++--- po/ro.po | 14 ++++++--- po/ru.po | 13 +++++--- po/sk.po | 14 ++++++--- po/sv.po | 14 ++++++--- po/tr.po | 90 ++++++++++++++++++++++++----------------------------- po/uk.po | 13 +++++--- po/zh_CN.po | 13 +++++--- po/zh_TW.po | 13 +++++--- 25 files changed, 256 insertions(+), 162 deletions(-) diff --git a/po/ca.po b/po/ca.po index 3add69bb1..d6840dbc1 100644 --- a/po/ca.po +++ b/po/ca.po @@ -784,11 +784,6 @@ msgstr "" msgid "Wrong" msgstr "" -#, fuzzy, c-format -#| msgid "error reading `%s': %s\n" -msgid "error renaming '%s' to '%s': %s\n" -msgstr "error en la lectura de «%s»: %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -4116,6 +4111,10 @@ msgstr "" msgid "You may want to change its expiration date too.\n" msgstr "No podeu canviar la data de caducitat de les claus v3\n" +#, c-format +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "" + # Photo ID com abans. ivb msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " @@ -8289,6 +8288,11 @@ msgstr "" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "no es pot crear el directori «%s»: %s\n" +#, fuzzy, c-format +#| msgid "error reading `%s': %s\n" +msgid "error renaming '%s' to '%s': %s\n" +msgstr "error en la lectura de «%s»: %s\n" + # No em passe! ;) ivb #, fuzzy, c-format msgid "can't hash '%s': %s\n" diff --git a/po/cs.po b/po/cs.po index d72bd673f..c790c768b 100644 --- a/po/cs.po +++ b/po/cs.po @@ -761,10 +761,6 @@ msgstr "V pořádku" msgid "Wrong" msgstr "Špatně" -#, c-format -msgid "error renaming '%s' to '%s': %s\n" -msgstr "chyba při přejmenování „%s“ na „%s“: %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "Poznámka: Toto heslo nikdy nebylo změněno.%0AProsím, nyní jej změňte." @@ -3809,6 +3805,11 @@ msgstr "POZOR: Vašemu šifrovacímu podklíči brzy vyprší platnost.\n" msgid "You may want to change its expiration date too.\n" msgstr "Dobu platnosti také můžete změnit.\n" +#, fuzzy, c-format +#| msgid "WARNING: Your encryption subkey expires soon.\n" +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "POZOR: Vašemu šifrovacímu podklíči brzy vyprší platnost.\n" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -7831,6 +7832,10 @@ msgstr "prosím, zjistěte příčinu a soubor ručně smažte\n" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "vytvoření dočasného kešového dir souboru „%s“ selhalo: %s\n" +#, c-format +msgid "error renaming '%s' to '%s': %s\n" +msgstr "chyba při přejmenování „%s“ na „%s“: %s\n" + #, c-format msgid "can't hash '%s': %s\n" msgstr "nelze vypočítat haš „%s“: %s\n" diff --git a/po/da.po b/po/da.po index 404d79eb4..011ea7d0d 100644 --- a/po/da.po +++ b/po/da.po @@ -835,11 +835,6 @@ msgstr "Korrekt" msgid "Wrong" msgstr "Forkert" -#, fuzzy, c-format -#| msgid "error reading `%s': %s\n" -msgid "error renaming '%s' to '%s': %s\n" -msgstr "fejl ved læsning af »%s«: %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "Bemærk: Denne adgangsfrase er aldrig blevet ændret.%0AÆndr den nu." @@ -4129,6 +4124,10 @@ msgstr "" msgid "You may want to change its expiration date too.\n" msgstr "Du kan ikke ændre udløbsdatoen for en v3-nøgle\n" +#, c-format +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -8372,6 +8371,11 @@ msgstr "" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "kunne ikke oprette midlertidig fil »%s«: %s\n" +#, fuzzy, c-format +#| msgid "error reading `%s': %s\n" +msgid "error renaming '%s' to '%s': %s\n" +msgstr "fejl ved læsning af »%s«: %s\n" + #, fuzzy, c-format #| msgid "can't access `%s': %s\n" msgid "can't hash '%s': %s\n" diff --git a/po/el.po b/po/el.po index a45232fd8..7d4e8e738 100644 --- a/po/el.po +++ b/po/el.po @@ -751,11 +751,6 @@ msgstr "" msgid "Wrong" msgstr "" -#, fuzzy, c-format -#| msgid "error reading `%s': %s\n" -msgid "error renaming '%s' to '%s': %s\n" -msgstr "σφάλμα κατά την ανάγνωση του `%s': %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -4013,6 +4008,10 @@ msgstr "" msgid "You may want to change its expiration date too.\n" msgstr "Δεν μπορείτε να αλλάξετε την ημερομηνία λήξης σε ένα v3 κλειδί\n" +#, c-format +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -8127,6 +8126,11 @@ msgstr "" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "αδυναμία δημιουργίας καταλόγου `%s': %s\n" +#, fuzzy, c-format +#| msgid "error reading `%s': %s\n" +msgid "error renaming '%s' to '%s': %s\n" +msgstr "σφάλμα κατά την ανάγνωση του `%s': %s\n" + #, fuzzy, c-format msgid "can't hash '%s': %s\n" msgstr "αδυναμία κλεισίματος του `%s': %s\n" diff --git a/po/eo.po b/po/eo.po index e9b007c41..a142ce1aa 100644 --- a/po/eo.po +++ b/po/eo.po @@ -750,11 +750,6 @@ msgstr "" msgid "Wrong" msgstr "" -#, fuzzy, c-format -#| msgid "error reading `%s': %s\n" -msgid "error renaming '%s' to '%s': %s\n" -msgstr "eraro dum legado de '%s': %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -3986,6 +3981,10 @@ msgstr "" msgid "You may want to change its expiration date too.\n" msgstr "Vi ne povas ŝanĝi la daton de eksvalidiĝo de v3-ŝlosilo\n" +#, c-format +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -8038,6 +8037,11 @@ msgstr "" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "%s: ne povas krei dosierujon: %s\n" +#, fuzzy, c-format +#| msgid "error reading `%s': %s\n" +msgid "error renaming '%s' to '%s': %s\n" +msgstr "eraro dum legado de '%s': %s\n" + #, fuzzy, c-format msgid "can't hash '%s': %s\n" msgstr "ne povas fermi '%s': %s\n" diff --git a/po/es.po b/po/es.po index 03e50d3ca..4409ce443 100644 --- a/po/es.po +++ b/po/es.po @@ -788,10 +788,6 @@ msgstr "Correcto" msgid "Wrong" msgstr "Incorrecto" -#, c-format -msgid "error renaming '%s' to '%s': %s\n" -msgstr "error al renombrar '%s' a '%s': %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -3886,6 +3882,11 @@ msgstr "AVISO: Tu subclave de cifrado caduca pronto.\n" msgid "You may want to change its expiration date too.\n" msgstr "Puede que también quieras cambiar su fecha de caducidad.\n" +#, fuzzy, c-format +#| msgid "WARNING: Your encryption subkey expires soon.\n" +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "AVISO: Tu subclave de cifrado caduca pronto.\n" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -7954,6 +7955,10 @@ msgstr "chequea el problema y borra este archivo manualmente\n" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "no se puede crear el fichero de cache '%s': %s\n" +#, c-format +msgid "error renaming '%s' to '%s': %s\n" +msgstr "error al renombrar '%s' a '%s': %s\n" + #, c-format msgid "can't hash '%s': %s\n" msgstr "no se puede hacer el hash de '%s': %s\n" diff --git a/po/et.po b/po/et.po index 6c6f7bfbb..5e106d6f5 100644 --- a/po/et.po +++ b/po/et.po @@ -748,11 +748,6 @@ msgstr "" msgid "Wrong" msgstr "" -#, fuzzy, c-format -#| msgid "error reading `%s': %s\n" -msgid "error renaming '%s' to '%s': %s\n" -msgstr "viga `%s' lugemisel: %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -3985,6 +3980,10 @@ msgstr "" msgid "You may want to change its expiration date too.\n" msgstr "v3 võtme aegumise aega ei saa muuta.\n" +#, c-format +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -8044,6 +8043,11 @@ msgstr "" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "kataloogi `%s' ei õnnestu luua: %s\n" +#, fuzzy, c-format +#| msgid "error reading `%s': %s\n" +msgid "error renaming '%s' to '%s': %s\n" +msgstr "viga `%s' lugemisel: %s\n" + #, fuzzy, c-format msgid "can't hash '%s': %s\n" msgstr "`%s' ei õnnestu sulgeda: %s\n" diff --git a/po/fi.po b/po/fi.po index 15fd0471a..3af8e811e 100644 --- a/po/fi.po +++ b/po/fi.po @@ -765,11 +765,6 @@ msgstr "" msgid "Wrong" msgstr "" -#, fuzzy, c-format -#| msgid "error reading `%s': %s\n" -msgid "error renaming '%s' to '%s': %s\n" -msgstr "virhe luettaessa tiedostoa \"%s\": %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -4009,6 +4004,10 @@ msgstr "" msgid "You may want to change its expiration date too.\n" msgstr "Et voi muuttaa v3-avainten vanhentumispäivää\n" +#, c-format +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -8110,6 +8109,11 @@ msgstr "" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "hakemiston \"%s\" luominen ei onnistu: %s\n" +#, fuzzy, c-format +#| msgid "error reading `%s': %s\n" +msgid "error renaming '%s' to '%s': %s\n" +msgstr "virhe luettaessa tiedostoa \"%s\": %s\n" + #, fuzzy, c-format msgid "can't hash '%s': %s\n" msgstr "tiedostoa \"%s\" ei voi sulkea: %s\n" diff --git a/po/fr.po b/po/fr.po index 239307ec4..6530e7768 100644 --- a/po/fr.po +++ b/po/fr.po @@ -789,10 +789,6 @@ msgstr "Exact" msgid "Wrong" msgstr "Faux" -#, c-format -msgid "error renaming '%s' to '%s': %s\n" -msgstr "erreur en renommant « %s » en « %s » : %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -4015,6 +4011,11 @@ msgstr "Attention : votre sous-clef de chiffrement expire bientôt.\n" msgid "You may want to change its expiration date too.\n" msgstr "Vous pourriez modifier aussi sa date d’expiration.\n" +#, fuzzy, c-format +#| msgid "WARNING: Your encryption subkey expires soon.\n" +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "Attention : votre sous-clef de chiffrement expire bientôt.\n" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -8258,6 +8259,10 @@ msgstr "veuillez vérifier la raison et effacer vous-même ce fichier\n" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "impossible de créer le répertoire de cache temporaire « %s » : %s\n" +#, c-format +msgid "error renaming '%s' to '%s': %s\n" +msgstr "erreur en renommant « %s » en « %s » : %s\n" + #, c-format msgid "can't hash '%s': %s\n" msgstr "impossible de hacher « %s » : %s\n" diff --git a/po/gl.po b/po/gl.po index af75e558c..d6972580a 100644 --- a/po/gl.po +++ b/po/gl.po @@ -753,11 +753,6 @@ msgstr "" msgid "Wrong" msgstr "" -#, fuzzy, c-format -#| msgid "error reading `%s': %s\n" -msgid "error renaming '%s' to '%s': %s\n" -msgstr "erro lendo `%s': %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -4009,6 +4004,10 @@ msgstr "" msgid "You may want to change its expiration date too.\n" msgstr "Non pode cambia-la data de expiración dunha chave v3\n" +#, c-format +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -8118,6 +8117,11 @@ msgstr "" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "non se pode crea-lo directorio `%s': %s\n" +#, fuzzy, c-format +#| msgid "error reading `%s': %s\n" +msgid "error renaming '%s' to '%s': %s\n" +msgstr "erro lendo `%s': %s\n" + #, fuzzy, c-format msgid "can't hash '%s': %s\n" msgstr "non se pode pechar `%s': %s\n" diff --git a/po/hu.po b/po/hu.po index b506d8a68..e875d074b 100644 --- a/po/hu.po +++ b/po/hu.po @@ -748,11 +748,6 @@ msgstr "" msgid "Wrong" msgstr "" -#, fuzzy, c-format -#| msgid "error reading `%s': %s\n" -msgid "error renaming '%s' to '%s': %s\n" -msgstr "Hiba \"%s\" olvasásakor: %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -3986,6 +3981,10 @@ msgstr "" msgid "You may want to change its expiration date too.\n" msgstr "Nem változtathatja meg egy v3 kulcs lejárati dátumát!\n" +#, c-format +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -8071,6 +8070,11 @@ msgstr "" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "Nem tudom a \"%s\" könyvtárat létrehozni: %s.\n" +#, fuzzy, c-format +#| msgid "error reading `%s': %s\n" +msgid "error renaming '%s' to '%s': %s\n" +msgstr "Hiba \"%s\" olvasásakor: %s\n" + #, fuzzy, c-format msgid "can't hash '%s': %s\n" msgstr "Nem tudom bezárni a(z) \"%s\" állományt: %s.\n" diff --git a/po/id.po b/po/id.po index 5334da392..363bad315 100644 --- a/po/id.po +++ b/po/id.po @@ -753,11 +753,6 @@ msgstr "" msgid "Wrong" msgstr "" -#, fuzzy, c-format -#| msgid "error reading `%s': %s\n" -msgid "error renaming '%s' to '%s': %s\n" -msgstr "kesalahan membaca `%s': %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -3992,6 +3987,10 @@ msgstr "" msgid "You may want to change its expiration date too.\n" msgstr "Anda tidak dapat merubah batas waktu kunci v3\n" +#, c-format +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -8070,6 +8069,11 @@ msgstr "" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "tidak dapat membuat direktori `%s': %s\n" +#, fuzzy, c-format +#| msgid "error reading `%s': %s\n" +msgid "error renaming '%s' to '%s': %s\n" +msgstr "kesalahan membaca `%s': %s\n" + #, fuzzy, c-format msgid "can't hash '%s': %s\n" msgstr "tidak dapat menutup `%s': %s\n" diff --git a/po/it.po b/po/it.po index 85f9b817c..8f04c7afa 100644 --- a/po/it.po +++ b/po/it.po @@ -737,10 +737,6 @@ msgstr "Corretto" msgid "Wrong" msgstr "Sbagliato" -#, c-format -msgid "error renaming '%s' to '%s': %s\n" -msgstr "errore durante la ridenominazione di '%s' in '%s': %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -3826,6 +3822,11 @@ msgstr "AVVISO: la sottochiave di crittografia scade a breve.\n" msgid "You may want to change its expiration date too.\n" msgstr "Si consiglia di modificare anche la sua data di scadenza.\n" +#, fuzzy, c-format +#| msgid "WARNING: Your encryption subkey expires soon.\n" +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "AVVISO: la sottochiave di crittografia scade a breve.\n" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -7883,6 +7884,10 @@ msgstr "si prega di controllare il motivo ed eliminare manualmente quel file\n" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "impossibile creare il file dir della cache temporanea '%s': %s\n" +#, c-format +msgid "error renaming '%s' to '%s': %s\n" +msgstr "errore durante la ridenominazione di '%s' in '%s': %s\n" + #, c-format msgid "can't hash '%s': %s\n" msgstr "impossibile eseguire l'hashing '%s': %s\n" diff --git a/po/ja.po b/po/ja.po index 236d78ced..d9a1dcd71 100644 --- a/po/ja.po +++ b/po/ja.po @@ -226,8 +226,8 @@ msgid "" "Please enter a passphrase to protect the received secret key%%0A %s%%0A " "%s%%0Awithin gpg-agent's key storage" msgstr "" -"パスフレーズを入力してください。gpg-agentの鍵の保管で受信した秘密鍵%%0A " -"%s%%0A %s%%0Aを保護します。" +"パスフレーズを入力してください。gpg-agentの鍵の保管で受信した秘密鍵%%0A %s" +"%%0A %s%%0Aを保護します。" #, c-format msgid "failed to create stream from socket: %s\n" @@ -727,10 +727,6 @@ msgstr "正しい" msgid "Wrong" msgstr "誤り" -#, c-format -msgid "error renaming '%s' to '%s': %s\n" -msgstr "'%s'から'%s'へ名前変更のエラー: %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "注意: パスフレーズは変更されていません。%0A今、変更してください。" @@ -759,8 +755,8 @@ msgstr "" #, c-format msgid "" -"Do you really want to delete the key identified by keygrip%%0A %s%%0A " -"%%C%%0A?" +"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C" +"%%0A?" msgstr "本当にこの鍵: keygrip%%0A %s%%0A %%C%%0Aを削除しますか?" msgid "Delete key" @@ -7588,6 +7584,10 @@ msgstr "理由を確認し、手動でそのファイルを削除してくださ msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "一時キャッシュ・ディレクトリ・ファイル'%s'が作成できません: %s\n" +#, c-format +msgid "error renaming '%s' to '%s': %s\n" +msgstr "'%s'から'%s'へ名前変更のエラー: %s\n" + #, c-format msgid "can't hash '%s': %s\n" msgstr "'%s'をハッシュできません: %s\n" diff --git a/po/nb.po b/po/nb.po index 19c2a4d19..922cb4957 100644 --- a/po/nb.po +++ b/po/nb.po @@ -749,10 +749,6 @@ msgstr "Riktig" msgid "Wrong" msgstr "Feil" -#, c-format -msgid "error renaming '%s' to '%s': %s\n" -msgstr "klarte ikke å gi «%s» det nye navnet «%s»: %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -3849,6 +3845,11 @@ msgstr "ADVARSEL: Undernøkkel for kryptering utløper snart.\n" msgid "You may want to change its expiration date too.\n" msgstr "Du bør vurdere å endre utløpsdato samtidig.\n" +#, fuzzy, c-format +#| msgid "WARNING: Your encryption subkey expires soon.\n" +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "ADVARSEL: Undernøkkel for kryptering utløper snart.\n" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -7873,6 +7874,10 @@ msgstr "kontroller årsaken og slett fila manuelt\n" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "klarte ikke å lage midlertidig hurtiglagermappe-fil «%s»: %s\n" +#, c-format +msgid "error renaming '%s' to '%s': %s\n" +msgstr "klarte ikke å gi «%s» det nye navnet «%s»: %s\n" + #, c-format msgid "can't hash '%s': %s\n" msgstr "klarte ikke å summere «%s»: %s\n" diff --git a/po/pl.po b/po/pl.po index dd97fdbdc..555da9661 100644 --- a/po/pl.po +++ b/po/pl.po @@ -744,10 +744,6 @@ msgstr "Akceptuj" msgid "Wrong" msgstr "Odrzuć" -#, c-format -msgid "error renaming '%s' to '%s': %s\n" -msgstr "błąd zmiany nazwy ,,%s'' na ,,%s'': %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "Uwaga: To hasło nie było nigdy zmieniane.%0AProszę zmienić je teraz." @@ -3862,6 +3858,11 @@ msgstr "OSTRZEŻENIE: podklucz do szyfrowania wkrótce wygaśnie.\n" msgid "You may want to change its expiration date too.\n" msgstr "Może warto także zmienić jego datę ważności.\n" +#, fuzzy, c-format +#| msgid "WARNING: Your encryption subkey expires soon.\n" +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "OSTRZEŻENIE: podklucz do szyfrowania wkrótce wygaśnie.\n" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -7982,6 +7983,10 @@ msgstr "" "nie udało się utworzyć pliku tymczasowego katalogu pamięci podręcznej ,," "%s'': %s\n" +#, c-format +msgid "error renaming '%s' to '%s': %s\n" +msgstr "błąd zmiany nazwy ,,%s'' na ,,%s'': %s\n" + #, c-format msgid "can't hash '%s': %s\n" msgstr "nie można policzyć skrótu ,,%s'': %s\n" diff --git a/po/pt.po b/po/pt.po index d20eb0138..e7ba4118c 100644 --- a/po/pt.po +++ b/po/pt.po @@ -752,11 +752,6 @@ msgstr "" msgid "Wrong" msgstr "" -#, fuzzy, c-format -#| msgid "error reading `%s': %s\n" -msgid "error renaming '%s' to '%s': %s\n" -msgstr "erro na leitura de `%s': %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -3996,6 +3991,10 @@ msgstr "" msgid "You may want to change its expiration date too.\n" msgstr "Você não pode modificar a data de validade de uma chave v3\n" +#, c-format +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -8067,6 +8066,11 @@ msgstr "" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "%s: impossível criar directoria: %s\n" +#, fuzzy, c-format +#| msgid "error reading `%s': %s\n" +msgid "error renaming '%s' to '%s': %s\n" +msgstr "erro na leitura de `%s': %s\n" + #, fuzzy, c-format msgid "can't hash '%s': %s\n" msgstr "impossível fechar `%s': %s\n" diff --git a/po/ro.po b/po/ro.po index e60784d33..b32a1dcd5 100644 --- a/po/ro.po +++ b/po/ro.po @@ -762,11 +762,6 @@ msgstr "" msgid "Wrong" msgstr "" -#, fuzzy, c-format -#| msgid "error reading `%s': %s\n" -msgid "error renaming '%s' to '%s': %s\n" -msgstr "eroare la citire `%s': %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -4044,6 +4039,10 @@ msgstr "" msgid "You may want to change its expiration date too.\n" msgstr "Nu puteţi schimba data de expirare a unei chei v3\n" +#, c-format +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -8193,6 +8192,11 @@ msgstr "" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "nu pot crea directorul `%s': %s\n" +#, fuzzy, c-format +#| msgid "error reading `%s': %s\n" +msgid "error renaming '%s' to '%s': %s\n" +msgstr "eroare la citire `%s': %s\n" + #, fuzzy, c-format #| msgid "can't access `%s': %s\n" msgid "can't hash '%s': %s\n" diff --git a/po/ru.po b/po/ru.po index 80e4e7aa6..a144acd53 100644 --- a/po/ru.po +++ b/po/ru.po @@ -754,10 +754,6 @@ msgstr "Подтверждаю" msgid "Wrong" msgstr "Неверно" -#, c-format -msgid "error renaming '%s' to '%s': %s\n" -msgstr "ошибка переименования '%s' в '%s': %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -3866,6 +3862,11 @@ msgstr "Внимание: Срок действия Вашего подключ msgid "You may want to change its expiration date too.\n" msgstr "Возможно, надо поменять также срок действия.\n" +#, fuzzy, c-format +#| msgid "WARNING: Your encryption subkey expires soon.\n" +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "Внимание: Срок действия Вашего подключа для шифрования истекает.\n" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -7942,6 +7943,10 @@ msgstr "выясните причину и удалите этот файл вр msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "невозможно создание временного файла '%s': %s\n" +#, c-format +msgid "error renaming '%s' to '%s': %s\n" +msgstr "ошибка переименования '%s' в '%s': %s\n" + #, c-format msgid "can't hash '%s': %s\n" msgstr "невозможно получить хеш '%s': %s\n" diff --git a/po/sk.po b/po/sk.po index 50e9070b8..743ce6b0a 100644 --- a/po/sk.po +++ b/po/sk.po @@ -753,11 +753,6 @@ msgstr "" msgid "Wrong" msgstr "" -#, fuzzy, c-format -#| msgid "error reading `%s': %s\n" -msgid "error renaming '%s' to '%s': %s\n" -msgstr "chyba pri čítaní `%s': %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -4012,6 +4007,10 @@ msgstr "" msgid "You may want to change its expiration date too.\n" msgstr "Nemôžete zmeniť dobu platnosti kľúča verzie 3\n" +#, c-format +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -8101,6 +8100,11 @@ msgstr "" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "nemôžem vytvoriť adresár `%s': %s\n" +#, fuzzy, c-format +#| msgid "error reading `%s': %s\n" +msgid "error renaming '%s' to '%s': %s\n" +msgstr "chyba pri čítaní `%s': %s\n" + #, fuzzy, c-format msgid "can't hash '%s': %s\n" msgstr "nemôžem zavrieť `%s': %s\n" diff --git a/po/sv.po b/po/sv.po index c8405d50c..2a62fe1d7 100644 --- a/po/sv.po +++ b/po/sv.po @@ -851,11 +851,6 @@ msgstr "Korrekt" msgid "Wrong" msgstr "Fel" -#, fuzzy, c-format -#| msgid "error reading `%s': %s\n" -msgid "error renaming '%s' to '%s': %s\n" -msgstr "fel vid läsning av \"%s\": %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -4194,6 +4189,10 @@ msgstr "" msgid "You may want to change its expiration date too.\n" msgstr "Du kan inte ändra giltighetsdatum för en v3-nyckel\n" +#, c-format +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -8506,6 +8505,11 @@ msgstr "" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "misslyckades med att skapa temporärfilen \"%s\": %s\n" +#, fuzzy, c-format +#| msgid "error reading `%s': %s\n" +msgid "error renaming '%s' to '%s': %s\n" +msgstr "fel vid läsning av \"%s\": %s\n" + #, fuzzy, c-format #| msgid "can't access `%s': %s\n" msgid "can't hash '%s': %s\n" diff --git a/po/tr.po b/po/tr.po index 3f15ce679..b7730c7ae 100644 --- a/po/tr.po +++ b/po/tr.po @@ -1,12 +1,12 @@ # Turkish translations for GnuPG messages. # Nilgün Belma Bugüner , 2001-2008, -# Emir SARI , 2022 +# Emir SARI , 2022, 2023 # msgid "" msgstr "" -"Project-Id-Version: gnupg 2.3.4\n" +"Project-Id-Version: gnupg 2.4.0\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n" -"PO-Revision-Date: 2022-04-23 15:00+0300\n" +"PO-Revision-Date: 2023-02-05 18:00+0300\n" "Last-Translator: Emir SARI \n" "Language-Team: Turkish\n" "Language: tr\n" @@ -14,7 +14,6 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: KBabel 1.11.4\n" #, c-format msgid "failed to acquire the pinentry lock: %s\n" @@ -325,7 +324,7 @@ msgstr "Yine de bunu kullan" #, c-format msgid "Please enter the passphrase to%0Aprotect your new key" -msgstr "Yeni anahtarınızı korumak için lütfen%0Aanahtar parolanızı girin" +msgstr "Yeni anahtarınızı korumak için lütfen anahtar%0Aparolanızı girin" msgid "Please enter the new passphrase" msgstr "Lütfen yeni anahtar parolasını girin" @@ -393,10 +392,8 @@ msgstr "|ALGO|ssh parmak izlerini göstermek için ALGO kullan" msgid "enable putty support" msgstr "putty desteğini etkinleştir" -#, fuzzy -#| msgid "enable putty support" msgid "enable Win32-OpenSSH support" -msgstr "putty desteğini etkinleştir" +msgstr "Win32-OpenSSH desteğini etkinleştir" msgid "Options controlling the security" msgstr "Güvenliği denetleyen seçenekler" @@ -736,10 +733,6 @@ msgstr "Doğru" msgid "Wrong" msgstr "Yanlış" -#, c-format -msgid "error renaming '%s' to '%s': %s\n" -msgstr "'%s > '%s' olarak yeniden adlandırırken hata: %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -763,22 +756,19 @@ msgid "Please insert the card with serial number" msgstr "Lütfen seri numarayı içeren kartı takın" # Check -#, fuzzy, c-format -#| msgid "" -#| "An ssh process requested the use of key%%0A %s%%0A (%s)%%0ADo you want " -#| "to allow this?" +#, c-format msgid "Requested the use of key%%0A %s%%0A %s%%0ADo you want to allow this?" msgstr "" -"Bir ssh işlemi,%%0A %s%%A (%s)%%0Aanahtarının kullanımı için istekte " -"bulundu. Buna izin vermek istiyor musunuz?" +"%%0A %s%%0A %s%%0Aanahtarının kullanımı için istekte bulunuldu. Buna izin " +"vermek istiyor musunuz?" #, c-format msgid "" "Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C" "%%0A?" msgstr "" -"Anahtar maşası tarafından tanımlanan şu anahtarı silmek istediğnizden emin " -"misiniz:%%0A %s%%0A %%C%%0A?" +"%%0A %s%%0A %%C%%0A anahtar maşası tarafından tanımlanan anahtarı silmek " +"istediğnizden emin misiniz?" msgid "Delete key" msgstr "Anahtarı sil" @@ -1516,7 +1506,7 @@ msgstr "%u bite yuvarlandı\n" #, c-format msgid "%s keysizes must be in the range %u-%u\n" -msgstr "%s anahtar uzunlukları %u-%u eriminde olmalı\n" +msgstr "%s anahtar uzunlukları %u-%u eriminde olmalıdır\n" msgid "Changing card key attribute for: " msgstr "Şunun için anahtar özniteliği değiştiriliyor: " @@ -1531,7 +1521,7 @@ msgid "Authentication key\n" msgstr "Kimlik doğrulama anahtarı\n" msgid "Please select what kind of key you want:\n" -msgstr "Lütfen istediğiniz anahtar türünü seçiniz:\n" +msgstr "Lütfen istediğiniz anahtar türünü seçin:\n" #, c-format msgid " (%d) RSA\n" @@ -1574,7 +1564,7 @@ msgid "Note: keys are already stored on the card!\n" msgstr "Not: Anahtarlar halihazırda kart üzerinde depolanıyor!\n" msgid "Replace existing keys? (y/N) " -msgstr "Mevcut anahtarlar başkalarıyla değiştirilsin mi? (e/H) " +msgstr "Var olan anahtarlar başkalarıyla değiştirilsin mi? (e/H) " #, c-format msgid "" @@ -1587,7 +1577,7 @@ msgstr "" "Bunları --change-pin komutunu kullanarak değiştirmelisiniz\n" msgid "Please select the type of key to generate:\n" -msgstr "Lütfen üretilecek anahtar türünü seçiniz:\n" +msgstr "Lütfen üretilecek anahtar türünü seçin:\n" msgid " (1) Signature key\n" msgstr " (1) İmzalama anahtarı\n" @@ -1599,7 +1589,7 @@ msgid " (3) Authentication key\n" msgstr " (3) Kimlik doğrulama anahtarı\n" msgid "Please select where to store the key:\n" -msgstr "Lütfen anahtarın depolanacağı yeri seçiniz:\n" +msgstr "Lütfen anahtarın depolanacağı yeri seçin:\n" #, c-format msgid "KEYTOCARD failed: %s\n" @@ -1803,10 +1793,9 @@ msgstr "UYARI: %s anahtarı, %s kipinde şifreleme için uygun değil\n" msgid "error creating passphrase: %s\n" msgstr "anahtar parolası oluşturulurken hata: %s\n" -#, fuzzy, c-format -#| msgid "can't use a symmetric ESK packet due to the S2K mode\n" +#, c-format msgid "can't use a SKESK packet due to the S2K mode\n" -msgstr "S2K kipi sayesinde bir simetrik ESK paketi kullanılamıyor\n" +msgstr "S2K kipi nedeniyle bir SKESK paketi kullanılamıyor\n" #, c-format msgid "using cipher %s.%s\n" @@ -1877,18 +1866,14 @@ msgstr "dışa aktarım sırasında anahtardan kullanışsız parçaları kaldı msgid "remove as much as possible from key during export" msgstr "dışa aktarım sırasında anahtardan olabildiğince çok şey kaldır" -#, fuzzy -#| msgid "generate a revocation certificate" msgid "export only revocation certificates" -msgstr "bir yürürlükten kaldırma sertifikası üret" +msgstr "yalnızca yürürlükten kaldırma sertifikalarını dışa aktar" msgid "use the GnuPG key backup format" msgstr "GnuPG yedekleme biçimini kullan" -#, fuzzy -#| msgid "exporting secret keys not allowed\n" msgid "export secret keys using the GnuPG format" -msgstr "gizli anahtarların dışa aktarımına izin verilmez\n" +msgstr "GnuPG biçimini kullanan gizli anahtarları dışa aktar" msgid " - skipped" msgstr " - atlandı" @@ -2330,10 +2315,8 @@ msgstr "anahtar zinciri adını anahtar listelerinde göster" msgid "show expiration dates during signature listings" msgstr "imza listelemesi sırasında zaman aşımı tarihleri göster" -#, fuzzy -#| msgid "list preferences (expert)" msgid "show preferences" -msgstr "tercihleri listele (uzman)" +msgstr "tercihleri göster" #, c-format msgid "unknown TOFU policy '%s'\n" @@ -2503,23 +2486,23 @@ msgstr "seçili sertifikalama özet algoritması geçersiz\n" #, c-format msgid "completes-needed must be greater than 0\n" -msgstr "\"completes-needed\" 0'dan büyük olmalı\n" +msgstr "\"completes-needed\" 0'dan büyük olmalıdır\n" #, c-format msgid "marginals-needed must be greater than 1\n" -msgstr "\"marginals-needed\" 1'den büyük olmalı\n" +msgstr "\"marginals-needed\" 1'den büyük olmalıdır\n" #, c-format msgid "max-cert-depth must be in the range from 1 to 255\n" -msgstr "\"max-cert-depth\" 1-255 arasında olmalı\n" +msgstr "\"max-cert-depth\" 1-255 arasında olmalıdır\n" #, c-format msgid "invalid default-cert-level; must be 0, 1, 2, or 3\n" -msgstr "öntanımlı sertifika düzeyi geçersiz; 0, 1, 2 veya 3 olmalı\n" +msgstr "öntanımlı sertifika düzeyi geçersiz; 0, 1, 2 veya 3 olmalıdır\n" #, c-format msgid "invalid min-cert-level; must be 1, 2, or 3\n" -msgstr "asgari sertifika düzeyi geçersiz; 1, 2 veya 3 olmalı\n" +msgstr "en küçük sertifika düzeyi geçersiz; 1, 2 veya 3 olmalıdır\n" #, c-format msgid "Note: simple S2K mode (0) is strongly discouraged\n" @@ -2527,7 +2510,7 @@ msgstr "Not: Basit S2K kipi (0) kesinlikle tavsiye edilmez\n" #, c-format msgid "invalid S2K mode; must be 0, 1 or 3\n" -msgstr "geçersiz S2K kipi; 0, 1 veya 3 olmalı\n" +msgstr "geçersiz S2K kipi; 0, 1 veya 3 olmalıdır\n" #, c-format msgid "invalid default preferences\n" @@ -3800,6 +3783,11 @@ msgstr "UYARI: Şifreleme yardımcı anahtarının yakın zamanda süresi dolaca msgid "You may want to change its expiration date too.\n" msgstr "Son kullanma tarihini de değiştirmek isteyebilirsiniz.\n" +#, fuzzy, c-format +#| msgid "WARNING: Your encryption subkey expires soon.\n" +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "UYARI: Şifreleme yardımcı anahtarının yakın zamanda süresi dolacak.\n" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -4249,7 +4237,7 @@ msgstr "%u bite yuvarlandı\n" #, c-format msgid "%s keys may be between %u and %u bits long.\n" -msgstr "%s anahtarları %u bit ile %u bit arasında olmalı.\n" +msgstr "%s anahtarları %u bit ile %u bit arasında olmalıdır.\n" #, c-format msgid "What keysize do you want for the subkey? (%u) " @@ -4303,10 +4291,10 @@ msgid "invalid value\n" msgstr "geçersiz değer\n" msgid "Key does not expire at all\n" -msgstr "Anahtar hep geçerli olacak\n" +msgstr "Anahtarın geçerliliği hiçbir zaman bitmeyecek\n" msgid "Signature does not expire at all\n" -msgstr "İmza hep geçerli olacak\n" +msgstr "İmzanın geçerliliği hiçbir zaman bitmeyecek\n" #, c-format msgid "Key expires at %s\n" @@ -5248,7 +5236,7 @@ msgid "" "The minimum trust level for this key is: %s\n" "\n" msgstr "" -"Bu anahtar için asgari güvence düzeyi: %s\n" +"Bu anahtar için en düşük güvence düzeyi: %s\n" "\n" msgid "Your decision? " @@ -6662,7 +6650,7 @@ msgstr "||Lütfen kart kilidini açın" #, c-format msgid "PIN for CHV%d is too short; minimum length is %d\n" -msgstr "CHV%d için PIN çok kısa; asgari uzunluk: %d\n" +msgstr "CHV%d için PIN çok kısa; gereken en kısa uzunluk %d\n" #, c-format msgid "verify CHV%d failed: %s\n" @@ -6693,7 +6681,7 @@ msgstr "||Lütfen kart için Sıfırlama Kodunu giriniz" #, c-format msgid "Reset Code is too short; minimum length is %d\n" -msgstr "Sıfırlama Kodu çok kısa; asgari uzunluk: %d\n" +msgstr "Sıfırlama Kodu çok kısa; gereken en kısa uzunluk %d\n" #. TRANSLATORS: Do not translate the "|*|" prefixes but #. keep it at the start of the string. We need this elsewhere @@ -7782,6 +7770,10 @@ msgstr "lütfen nedenini denetleyin ve o dosyayı el ile silin\n" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "geçici önbellek dizin dosyası '%s' oluşturulamadı: %s\n" +#, c-format +msgid "error renaming '%s' to '%s': %s\n" +msgstr "'%s > '%s' olarak yeniden adlandırırken hata: %s\n" + #, c-format msgid "can't hash '%s': %s\n" msgstr "'%s' sağlaması yapılamıyor: %s\n" diff --git a/po/uk.po b/po/uk.po index d81fd7d64..730e9e135 100644 --- a/po/uk.po +++ b/po/uk.po @@ -754,10 +754,6 @@ msgstr "Підтверджую" msgid "Wrong" msgstr "Не підтверджую" -#, c-format -msgid "error renaming '%s' to '%s': %s\n" -msgstr "помилка під час спроби перейменування «%s» на «%s»: %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -3905,6 +3901,11 @@ msgstr "УВАГА: строк дії вашого підключа імпорт msgid "You may want to change its expiration date too.\n" msgstr "Ймовірно, вам варто змінити також і його строк дії.\n" +#, fuzzy, c-format +#| msgid "WARNING: Your encryption subkey expires soon.\n" +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "УВАГА: строк дії вашого підключа імпортування невдовзі завершиться.\n" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -8052,6 +8053,10 @@ msgstr "будь ласка, перевірте причину і вилучіт msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "не вдалося створити тимчасовий файл каталогу кешу «%s»: %s\n" +#, c-format +msgid "error renaming '%s' to '%s': %s\n" +msgstr "помилка під час спроби перейменування «%s» на «%s»: %s\n" + #, c-format msgid "can't hash '%s': %s\n" msgstr "не вдалося хешувати «%s»: %s\n" diff --git a/po/zh_CN.po b/po/zh_CN.po index 1b6a221d9..ef737a37d 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -717,10 +717,6 @@ msgstr "正确" msgid "Wrong" msgstr "错误" -#, c-format -msgid "error renaming '%s' to '%s': %s\n" -msgstr "将‘%s’重命名为‘%s’时出现错误:%s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "注意:此密码从未被修改过。%0A请立即修改。" @@ -3692,6 +3688,11 @@ msgstr "警告: 您的加密用子密钥将在不久后过期。\n" msgid "You may want to change its expiration date too.\n" msgstr "您可能也想要变更它的过期日期。\n" +#, fuzzy, c-format +#| msgid "WARNING: Your encryption subkey expires soon.\n" +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "警告: 您的加密用子密钥将在不久后过期。\n" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -7528,6 +7529,10 @@ msgstr "请检查理由并手动删除那个文件\n" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "创建临时缓存目录文件‘%s’时失败:%s\n" +#, c-format +msgid "error renaming '%s' to '%s': %s\n" +msgstr "将‘%s’重命名为‘%s’时出现错误:%s\n" + #, c-format msgid "can't hash '%s': %s\n" msgstr "无法取‘%s’的散列:%s\n" diff --git a/po/zh_TW.po b/po/zh_TW.po index 066dd0521..f14cce879 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -753,10 +753,6 @@ msgstr "正確" msgid "Wrong" msgstr "錯了" -#, c-format -msgid "error renaming '%s' to '%s': %s\n" -msgstr "把 '%s' 重新命名成 '%s' 時出錯: %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "請注意: 密語從未變更過.%0A請現在就變更." @@ -3882,6 +3878,11 @@ msgstr "警告: 你的加密子鑰很快將到期.\n" msgid "You may want to change its expiration date too.\n" msgstr "你可能也會想變更其使用期限.\n" +#, fuzzy, c-format +#| msgid "WARNING: Your encryption subkey expires soon.\n" +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "警告: 你的加密子鑰很快將到期.\n" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -7871,6 +7872,10 @@ msgstr "請檢查其原因並手動刪除該檔案\n" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "建立暫存快取目錄檔案 '%s' 失敗: %s\n" +#, c-format +msgid "error renaming '%s' to '%s': %s\n" +msgstr "把 '%s' 重新命名成 '%s' 時出錯: %s\n" + #, c-format msgid "can't hash '%s': %s\n" msgstr "無法計算 '%s' 的雜湊: %s\n" From 9e86dac84f3704cb12fddc559b8604f5fe202f06 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 30 May 2023 13:53:01 +0200 Subject: [PATCH 19/56] Release 2.4.2 --- NEWS | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index d58b0f3c1..08fb5bd9a 100644 --- a/NEWS +++ b/NEWS @@ -1,8 +1,8 @@ -Noteworthy changes in version 2.4.2 (unreleased) +Noteworthy changes in version 2.4.2 (2023-05-30) ------------------------------------------------ * gpg: Print a warning if no more encryption subkeys are left over - after chnaging the expiration date. [rGef2c3d50fa] + after changing the expiration date. [rGef2c3d50fa] * gpg: Fix searching for the ADSK key when adding an ADSK. [T6504] @@ -21,6 +21,7 @@ Noteworthy changes in version 2.4.2 (unreleased) * w32: Avoid using the VirtualStore. [T6403] + See-also: gnupg-announce/2023q2/000479.html Release-info: https://dev.gnupg.org/T6506 From 3c97dc2714b613ed5340f2dfebd718ca141c84c7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 30 May 2023 16:44:00 +0200 Subject: [PATCH 20/56] Post release updates -- --- NEWS | 6 ++++++ configure.ac | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 08fb5bd9a..14c2251bf 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,9 @@ +Noteworthy changes in version 2.4.3 (unreleased) +------------------------------------------------ + + Release-info: https://dev.gnupg.org/T6506 + + Noteworthy changes in version 2.4.2 (2023-05-30) ------------------------------------------------ diff --git a/configure.ac b/configure.ac index a54740108..e68b779c5 100644 --- a/configure.ac +++ b/configure.ac @@ -29,7 +29,7 @@ min_automake_version="1.16.3" m4_define([mym4_package],[gnupg]) m4_define([mym4_major], [2]) m4_define([mym4_minor], [4]) -m4_define([mym4_micro], [2]) +m4_define([mym4_micro], [3]) # To start a new development series, i.e a new major or minor number # you need to mark an arbitrary commit before the first beta release From c8f6fdcd359ac22466db880b5f13e272dcd65a8b Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 30 May 2023 17:38:27 +0200 Subject: [PATCH 21/56] build: Always build the wixlib with a release -- Forgot it today again; better do it by default. Also disable sslsigncode verify due to missing certificate problem (for signing we use Scute). --- Makefile.am | 4 ++-- build-aux/speedo.mk | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Makefile.am b/Makefile.am index 0f2075089..1cd009811 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,8 +18,8 @@ ## Process this file with automake to produce Makefile.in -# To include the wixlibs for building an MSI installer in a release use -# make release WITH_MSI=1 +# We want to also build the wixlib for use by GnuPG Desktop +WITH_MSI=1 # Location of the released tarball archives. This is prefixed by # the variable RELEASE_ARCHIVE in ~/.gnupg-autogen.rc. For example: diff --git a/build-aux/speedo.mk b/build-aux/speedo.mk index db78afa50..170c20b79 100644 --- a/build-aux/speedo.mk +++ b/build-aux/speedo.mk @@ -1543,10 +1543,8 @@ sign-installer: if [ -f "$${msifile}" ]; then \ $(call MKSWDB_commands,$${msifile},$${reldate},"wixlib_"); \ fi; \ - echo "speedo: /*" ;\ - echo "speedo: * Verification result" ;\ - echo "speedo: */" ;\ - osslsigncode verify $${exefile} \ + echo "speedo: /* (osslsigncode verify disabled) */" ;\ + echo osslsigncode verify $${exefile} \ ) From 89da4a32ab77e47fc1d6893993b298f1acaf418e Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 1 Jun 2023 12:42:51 +0200 Subject: [PATCH 22/56] doc: Replace remaining "gpg2" by "gpg". -- --- doc/gnupg7.texi | 17 ++++++++--------- doc/gpgsm.texi | 2 +- doc/scdaemon.texi | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/doc/gnupg7.texi b/doc/gnupg7.texi index c48dca96f..a77bf98f9 100644 --- a/doc/gnupg7.texi +++ b/doc/gnupg7.texi @@ -11,19 +11,18 @@ @ifset isman GnuPG is a set of programs for public key encryption and digital signatures. The program most users will want to use is the OpenPGP -command line tool, named @command{gpg2}. @command{gpgv}is a stripped -down version of @command{gpg2} with no encryption functionality, used +command line tool, named @command{gpg}. @command{gpgv}is a stripped +down version of @command{gpg} with no encryption functionality, used only to verify signatures against a trusted keyring. @command{gpgsm} is the X.509/CMS (for S/MIME) counterpart of -@command{gpg2}. @command{gpg-agent} is a passphrase and private key +@command{gpg}. @command{gpg-agent} is a passphrase and private key daemon which may also emulate the @command{ssh-agent}. @mansect see also -@command{gpg}(1), -@command{gpg2}(1), -@command{gpgv}(1), -@command{gpgsm}(1), -@command{gpg-agent}(1), -@command{dirmngr}(8), +@command{gpg}(1), +@command{gpgv}(1), +@command{gpgsm}(1), +@command{gpg-agent}(1), +@command{dirmngr}(8), @command{scdaemon}(1) @include see-also-note.texi @end ifset diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi index 364345741..11c5c1962 100644 --- a/doc/gpgsm.texi +++ b/doc/gpgsm.texi @@ -1725,7 +1725,7 @@ option @option{--disable-dirmngr}. @mansect see also @ifset isman -@command{gpg2}(1), +@command{gpg}(1), @command{gpg-agent}(1) @end ifset @include see-also-note.texi diff --git a/doc/scdaemon.texi b/doc/scdaemon.texi index a1d1cbc08..6f56585e6 100644 --- a/doc/scdaemon.texi +++ b/doc/scdaemon.texi @@ -757,6 +757,6 @@ length up to N bytes. If N is not given a default value is used @ifset isman @command{gpg-agent}(1), @command{gpgsm}(1), -@command{gpg2}(1) +@command{gpg}(1) @end ifset @include see-also-note.texi From 2c1d5d5cd35c4896f55d7fe95cbd3a5fa8ec8f46 Mon Sep 17 00:00:00 2001 From: Petr Pisar Date: Mon, 5 Jun 2023 14:38:26 +0200 Subject: [PATCH 23/56] po: Update Czech translation -- --- po/cs.po | 164 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 112 insertions(+), 52 deletions(-) diff --git a/po/cs.po b/po/cs.po index c790c768b..a05a18e84 100644 --- a/po/cs.po +++ b/po/cs.po @@ -4,7 +4,7 @@ # Magda Procházková 2001, # Roman Pavlik 2001, 2002, 2003, 2004, 2005. # Petr Pisar , 2009, 2010, 2011, 2013, 2014, 2015, 2016. -# Petr Pisar , 2017, 2018, 2019, 2020, 2021, 2022. +# Petr Pisar , 2017, 2018, 2019, 2020, 2021, 2022, 2023. # # A "%%0A" is used by Pinentry to insert a line break. The double percent # sign is actually needed because it is also a printf format string. If you @@ -26,6 +26,7 @@ # kvalifikovaný certifikát/podpis # # action → způsob užití (klíče) +# additional decryption subkey → dodatečný dešifrovací klíč # administrator → správce # cache → keš # compliance rules → pravidla normy @@ -38,9 +39,9 @@ # msgid "" msgstr "" -"Project-Id-Version: gnupg2 2.3.8\n" +"Project-Id-Version: gnupg2 2.4.2\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n" -"PO-Revision-Date: 2022-11-13 14:21+01:00\n" +"PO-Revision-Date: 2023-06-03 15:45+02:00\n" "Last-Translator: Petr Pisar \n" "Language-Team: Czech \n" "Language: cs\n" @@ -153,14 +154,13 @@ msgstr "Heslo:" msgid "does not match - try again" msgstr "neshodují se – zkuste to znovu" -#, fuzzy -#| msgid "Passphrase" msgid "Passphrases match." -msgstr "Heslo" +msgstr "Heslo se shoduje." #. TRANSLATORS: The string is appended to an error message in #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. +# TODO: Pluralize #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "SETERROR %s (pokus %d z %d)" @@ -423,7 +423,7 @@ msgid "enable putty support" msgstr "zapnout podporu pro PuTTY" msgid "enable Win32-OpenSSH support" -msgstr "zapnout podporu pro Win32-OpenSSH" +msgstr "zapnout podporu Win32-OpenSSH" msgid "Options controlling the security" msgstr "Volby ovlivňující bezpečnost" @@ -786,8 +786,8 @@ msgstr "Vyžádáno použití klíče%%0A %s%%0A %s%%0APřejete si to povolit? #, c-format msgid "" -"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C" -"%%0A?" +"Do you really want to delete the key identified by keygrip%%0A %s%%0A " +"%%C%%0A?" msgstr "" "Opravdu chcete smazat klíč určený pomocí keygripu%%0A %s%%0A %%C%%0A?" @@ -1431,7 +1431,7 @@ msgstr "vyžadováno" #, c-format msgid "Please try command \"%s\" if the listing does not look correct\n" -msgstr "" +msgstr "Pokud výpis nevypadá v pořádku, zkuste příkaz „%s“\n" msgid "Error: Only plain ASCII is currently allowed.\n" msgstr "Chyba: V současné verzi je povolenou pouze plain ASCII.\n" @@ -1697,7 +1697,7 @@ msgid "change the User Interaction Flag" msgstr "změní příznak interakce uživatele (UIF)" msgid "switch to the OpenPGP app" -msgstr "" +msgstr "přepne do aplikace OpenPGP" msgid "gpg/card> " msgstr "gpg/karta> " @@ -1825,7 +1825,7 @@ msgstr "chyba při vytváření hesla: %s\n" #, c-format msgid "can't use a SKESK packet due to the S2K mode\n" -msgstr "v režimu S2K nelze použít symetrický ESK paket\n" +msgstr "v režimu S2K nelze použít SKESK paket\n" #, c-format msgid "using cipher %s.%s\n" @@ -1895,18 +1895,14 @@ msgstr "odstranit nepoužitelné části z klíče při exportu" msgid "remove as much as possible from key during export" msgstr "odstranit při exportu z klíče vše, co lze" -#, fuzzy -#| msgid "generate a revocation certificate" msgid "export only revocation certificates" -msgstr "vytvořit revokační certifikát" +msgstr "exportovat pouze revokační certifikáty" msgid "use the GnuPG key backup format" msgstr "použít záložní formát klíče GnuPG" -#, fuzzy -#| msgid "exporting secret keys not allowed\n" msgid "export secret keys using the GnuPG format" -msgstr "exportování tajného klíče není povoleno\n" +msgstr "exportovat tajné klíče do formátu GnuPG" msgid " - skipped" msgstr " – přeskočeno" @@ -2342,10 +2338,8 @@ msgstr "ukazovat odvolané a prošlé ID uživatelů při výpisu klíčů" msgid "show revoked and expired subkeys in key listings" msgstr "ukazovat odvolané a prošlé podklíče při výpisu klíčů" -#, fuzzy -#| msgid "show expiration dates during signature listings" msgid "show signatures with invalid algorithms during signature listings" -msgstr "ukazovat data expirace během výpisu podpisů" +msgstr "ukazovat podpisy s neplatnými algoritmy během výpisu podpisů" msgid "show the keyring name in key listings" msgstr "ukazovat název souboru s klíči při výpisu klíčů" @@ -2353,10 +2347,8 @@ msgstr "ukazovat název souboru s klíči při výpisu klíčů" msgid "show expiration dates during signature listings" msgstr "ukazovat data expirace během výpisu podpisů" -#, fuzzy -#| msgid "list preferences (expert)" msgid "show preferences" -msgstr "vypsat seznam předvoleb (pro experty)" +msgstr "vypsat předvolby" #, c-format msgid "unknown TOFU policy '%s'\n" @@ -2964,7 +2956,7 @@ msgstr "klíč %s: chyba při odesílání dat agentovi: %s\n" #, c-format msgid "key %s: card reference is overridden by key material\n" -msgstr "" +msgstr "klíč %s: odkaz na kartu je přebit hodnotou klíče\n" #. TRANSLATORS: For a smartcard, each private key on host has a #. * reference (stub) to a smartcard and actual private key data @@ -3481,10 +3473,8 @@ msgstr "smazat vybrané podklíče" msgid "add a revocation key" msgstr "přidat revokační klíč" -#, fuzzy -#| msgid "Data decryption succeeded" msgid "add an additional decryption subkey" -msgstr "Dešifrování dat uspělo" +msgstr "přidat dodatečný dešifrovací podklíč" msgid "delete signatures from the selected user IDs" msgstr "smazat podpisy z vybraných uživatelských ID" @@ -3547,11 +3537,10 @@ msgstr "Tajný klíč je dostupný.\n" msgid "Secret subkeys are available.\n" msgstr "Tajné podklíče jsou dostupné.\n" -#, fuzzy -#| msgid "Note: Only the secret part of the shown subkey will be deleted.\n" msgid "" "Note: the local copy of the secret key will only be deleted with \"save\".\n" -msgstr "Poznámka: Smazána bude pouze tajná část zobrazeného podklíče.\n" +msgstr "" +"Poznámka: Místní kopie tajného klíče bude smazána až s příkazem „save“.\n" msgid "Need the secret key to do this.\n" msgstr "Pro provedení této operace je potřeba tajný klíč.\n" @@ -3661,11 +3650,9 @@ msgstr "Uložit změny? (a/N) " msgid "Quit without saving? (y/N) " msgstr "Ukončit bez uložení? (a/N) " -# The first argument is a "key" or "subkey" -#, fuzzy, c-format -#| msgid "deleting secret %s failed: %s\n" +#, c-format msgid "deleting copy of secret key failed: %s\n" -msgstr "smazání tajného %s se nezdařilo: %s\n" +msgstr "smazání kopie tajného klíče se nezdařilo: %s\n" #, c-format msgid "Key not changed so no update needed.\n" @@ -3805,10 +3792,9 @@ msgstr "POZOR: Vašemu šifrovacímu podklíči brzy vyprší platnost.\n" msgid "You may want to change its expiration date too.\n" msgstr "Dobu platnosti také můžete změnit.\n" -#, fuzzy, c-format -#| msgid "WARNING: Your encryption subkey expires soon.\n" +#, c-format msgid "WARNING: No valid encryption subkey left over.\n" -msgstr "POZOR: Vašemu šifrovacímu podklíči brzy vyprší platnost.\n" +msgstr "POZOR: Nezbyl žádný platný šifrovací podklíč.\n" msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " @@ -3905,17 +3891,15 @@ msgid "" msgstr "Jste si jistí, že tento klíč chcete pověřit odvoláním? (a/N) " msgid "Enter the fingerprint of the additional decryption subkey: " -msgstr "" +msgstr "Zadejte otisk dodatečného dešifrovacího podklíče: " -#, fuzzy, c-format -#| msgid "(unless you specify the key by fingerprint)\n" +#, c-format msgid "Did you specify the fingerprint of a subkey?\n" -msgstr "(dokud neurčíte klíč jeho otiskem)\n" +msgstr "Zadali jste otisk podklíče?\n" -#, fuzzy, c-format -#| msgid "Subkey %s is already revoked.\n" +#, c-format msgid "key \"%s\" is already on this keyblock\n" -msgstr "Podklíč %s je již odvolán.\n" +msgstr "klíč „%s“ je již v tomto bloku klíče.\n" msgid "" "Are you sure you want to change the expiration time for multiple subkeys? (y/" @@ -8996,24 +8980,30 @@ msgstr "Příkazy pro správu Yubikey" msgid "manage the command history" msgstr "spravuje historii příkazů" -#~ msgid "continuing verification anyway due to option %s\n" -#~ msgstr "přesto se pokračuje v ověřování kvůli volbě %s\n" - +#, c-format #~ msgid "selected AEAD algorithm is invalid\n" #~ msgstr "vybraný algoritmus AEAD je neplatný\n" +#, c-format #~ msgid "invalid personal AEAD preferences\n" #~ msgstr "neplatné uživatelské předvolby pro AEAD\n" +#, c-format #~ msgid "AEAD algorithm '%s' may not be used in %s mode\n" #~ msgstr "AEAD algoritmus „%s“ se nesmí používat v režimu %s\n" +#, c-format +#~ msgid "continuing verification anyway due to option %s\n" +#~ msgstr "přesto se pokračuje v ověřování kvůli volbě %s\n" + +#, c-format #~ msgid "error writing to temporary file: %s\n" #~ msgstr "chyba při zápisu do dočasného souboru: %s\n" #~ msgid "run in supervised mode" #~ msgstr "poběží v režimu dohledu" +#, c-format #~ msgid "forcing symmetric cipher %s (%d) violates recipient preferences\n" #~ msgstr "vyžádaná symetrická šifra %s (%d) nevyhovuje předvolbám příjemce\n" @@ -9029,12 +9019,15 @@ msgstr "spravuje historii příkazů" #~ msgid "Configuration of LDAP servers to use" #~ msgstr "Nastavení používaných LDAP serverů" +#, c-format #~ msgid "selfsigned certificate has a BAD signature" #~ msgstr "sám sebou podepsaný certifikát má CHYBNÝ podpis" +#, c-format #~ msgid "detected card with S/N: %s\n" #~ msgstr "nalezena karta se sériovým číslem: %s\n" +#, c-format #~ msgid "no authentication key for ssh on card: %s\n" #~ msgstr "na kartě není autentizační klíč pro SSH: %s\n" @@ -9044,15 +9037,19 @@ msgstr "spravuje historii příkazů" #~ msgid "use a log file for the server" #~ msgstr "použít pro server soubor s protokolem" +#, c-format #~ msgid "Note: no default option file '%s'\n" #~ msgstr "Poznámka: neexistuje implicitní soubor s možnostmi „%s“\n" +#, c-format #~ msgid "option file '%s': %s\n" #~ msgstr "soubor s možnostmi „%s“: %s\n" +#, c-format #~ msgid "connection to %s established\n" #~ msgstr "spojení k programu %s ustanoveno\n" +#, c-format #~ msgid "no running gpg-agent - starting '%s'\n" #~ msgstr "gpg-agent neběží – spouští se „%s“\n" @@ -9083,33 +9080,43 @@ msgstr "spravuje historii příkazů" #~ msgid "invalid option" #~ msgstr "neplatný parametr" +#, c-format #~ msgid "missing argument for option \"%.50s\"\n" #~ msgstr "postrádám argument u volby „%.50s“\n" +#, c-format #~ msgid "option \"%.50s\" does not expect an argument\n" #~ msgstr "volba „%.50s“ nečeká argument\n" +#, c-format #~ msgid "invalid command \"%.50s\"\n" #~ msgstr "neplatný příkaz „%.50s“\n" +#, c-format #~ msgid "option \"%.50s\" is ambiguous\n" #~ msgstr "volba „%.50s“ není jednoznačná\n" +#, c-format #~ msgid "command \"%.50s\" is ambiguous\n" #~ msgstr "příkaz „%.50s“ není jednoznačný\n" +#, c-format #~ msgid "invalid option \"%.50s\"\n" #~ msgstr "neplatný parametr „%.50s“\n" +#, c-format #~ msgid "unable to execute program '%s': %s\n" #~ msgstr "nelze spustit program „%s“: %s\n" +#, c-format #~ msgid "unable to execute external program\n" #~ msgstr "nelze spustit externí program\n" +#, c-format #~ msgid "unable to read external program response: %s\n" #~ msgstr "nelze přečíst odpověď externího programu: %s\n" +#, c-format #~ msgid "Note: old default options file '%s' ignored\n" #~ msgstr "Poznámka: starý implicitní soubor s možnostmi „%s“ ignorován\n" @@ -9119,34 +9126,42 @@ msgstr "spravuje historii příkazů" #~ msgid "elevate the trust of signatures with valid PKA data" #~ msgstr "vyzvednout důvěru podpisů s platnými daty PKA" +#, c-format #~ msgid " (%d) ECC and ECC\n" #~ msgstr " (%d) ECC a ECC\n" #~ msgid "honor the PKA record set on a key when retrieving keys" #~ msgstr "respektovat PKA záznamy klíče při získávání klíčů" +#, c-format #~ msgid "requesting key %s from %s server %s\n" #~ msgstr "požaduji klíč %s z %s serveru %s\n" +#, c-format #~ msgid "Note: Verified signer's address is '%s'\n" #~ msgstr "Poznámka: Podepisovatelova ověřená adresa je „%s“\n" +#, c-format #~ msgid "Note: Signer's address '%s' does not match DNS entry\n" #~ msgstr "" #~ "Poznámka: Podepisovatelova adresa „%s“ se neshoduje s DNS záznamem\n" +#, c-format #~ msgid "trustlevel adjusted to FULL due to valid PKA info\n" #~ msgstr "úroveň důvěry opravena na PLNOU, kvůli platné PKA informaci\n" +#, c-format #~ msgid "trustlevel adjusted to NEVER due to bad PKA info\n" #~ msgstr "úroveň důvěry opravena na ŽÁDNOU, kvůli špatné PKA informaci\n" #~ msgid "|FILE|write a server mode log to FILE" #~ msgstr "|SOUBOR|zapisovat protokol režimu server do SOUBORU" +#, c-format #~ msgid "%s:%u: no hostname given\n" #~ msgstr "%s:%u: nebyl zadán název stroje\n" +#, c-format #~ msgid "could not parse keyserver\n" #~ msgstr "nelze rozebrat serveru klíčů\n" @@ -9195,66 +9210,87 @@ msgstr "spravuje historii příkazů" #~ "Vnitřní LDAP pomůcka pro pro Dirmngr.\n" #~ "Rozhraní a volby se mohou bez upozornění změnit.\n" +#, c-format #~ msgid "invalid port number %d\n" #~ msgstr "neplatné číslo portu %d\n" +#, c-format #~ msgid "scanning result for attribute '%s'\n" #~ msgstr "ve výsledku se hledá atribut „%s“\n" +#, c-format #~ msgid "error writing to stdout: %s\n" #~ msgstr "chyba při zápisu na standardní výstup: %s\n" +#, c-format #~ msgid " available attribute '%s'\n" #~ msgstr " dostupný atribut „%s“\n" +#, c-format #~ msgid "attribute '%s' not found\n" #~ msgstr "atribut „%s“ nenalezen\n" +#, c-format #~ msgid "found attribute '%s'\n" #~ msgstr "nalezen atribut „%s“\n" +#, c-format #~ msgid "processing url '%s'\n" #~ msgstr "zpracovává se URL „%s“\n" +#, c-format #~ msgid " user '%s'\n" #~ msgstr " uživatel „%s“\n" +#, c-format #~ msgid " pass '%s'\n" #~ msgstr " heslo „%s“\n" +#, c-format #~ msgid " host '%s'\n" #~ msgstr " stroj „%s“\n" +#, c-format #~ msgid " port %d\n" #~ msgstr " port %d\n" +#, c-format #~ msgid " DN '%s'\n" #~ msgstr " DN „%s“\n" +#, c-format #~ msgid " filter '%s'\n" #~ msgstr " filtr „%s“\n" +#, c-format #~ msgid " attr '%s'\n" #~ msgstr " atribut „%s“\n" +#, c-format #~ msgid "no host name in '%s'\n" #~ msgstr "v „%s“ chybí název stroje\n" +#, c-format #~ msgid "no attribute given for query '%s'\n" #~ msgstr "u dotazu „%s“ nezadán žádný atribut\n" +#, c-format #~ msgid "WARNING: using first attribute only\n" #~ msgstr "POZOR: použije se pouze první atribut\n" +#, c-format #~ msgid "LDAP init to '%s:%d' failed: %s\n" #~ msgstr "Inicializace LDAP u „%s:%d“ selhala: %s\n" +#, c-format #~ msgid "binding to '%s:%d' failed: %s\n" #~ msgstr "napojení k „%s:%d“ selhalo: %s\n" +#, c-format #~ msgid "searching '%s' failed: %s\n" #~ msgstr "hledávání „%s“ neuspělo: %s\n" +#, c-format #~ msgid "start_cert_fetch: invalid pattern '%s'\n" #~ msgstr "start_cert_fetch: chybný vzor „%s“\n" @@ -9311,72 +9347,95 @@ msgstr "spravuje historii příkazů" #~ "Syntaxe: symcryptrun --class TŘÍDA --program PROGRAM --keyfile SOUBOR " #~ "[VOLBY…] PŘÍKAZ [VSTUPNÍ_SOUBOR]\n" +#, c-format #~ msgid "%s on %s aborted with status %i\n" #~ msgstr "%s nad %s byl ukončen s kódem %i\n" +#, c-format #~ msgid "%s on %s failed with status %i\n" #~ msgstr "%s nad %s selhal s kódem %i\n" +#, c-format #~ msgid "can't create temporary directory '%s': %s\n" #~ msgstr "nelze vytvořit dočasný adresář „%s“: %s\n" +#, c-format #~ msgid "could not open %s for writing: %s\n" #~ msgstr "%s nelze otevřít pro zápis: %s\n" +#, c-format #~ msgid "error closing %s: %s\n" #~ msgstr "chyba při zavírání chyba %s: %s\n" +#, c-format #~ msgid "no --program option provided\n" #~ msgstr "nebyla zadána volba --program\n" +#, c-format #~ msgid "only --decrypt and --encrypt are supported\n" #~ msgstr "pouze --decrypt a --encrypt jsou podporovány\n" +#, c-format #~ msgid "no --keyfile option provided\n" #~ msgstr "nebyla zadána volba --keyfile\n" +#, c-format #~ msgid "cannot allocate args vector\n" #~ msgstr "nelze alokovat pole argumentů\n" +#, c-format #~ msgid "could not create pipe: %s\n" #~ msgstr "nelze vytvořit rouru: %s\n" +#, c-format #~ msgid "could not create pty: %s\n" #~ msgstr "nelze vytvořit PTY: %s\n" +#, c-format #~ msgid "could not fork: %s\n" #~ msgstr "nelze se rozdvojit (fork): %s\n" +#, c-format #~ msgid "execv failed: %s\n" #~ msgstr "execv selhalo: %s\n" +#, c-format #~ msgid "select failed: %s\n" #~ msgstr "služba select() selhala: %s\n" +#, c-format #~ msgid "read failed: %s\n" #~ msgstr "čtení selhalo: %s\n" +#, c-format #~ msgid "pty read failed: %s\n" #~ msgstr "čtení z PTY selhalo: %s\n" +#, c-format #~ msgid "waitpid failed: %s\n" #~ msgstr "služba waitpid() selhala: %s\n" +#, c-format #~ msgid "child aborted with status %i\n" #~ msgstr "potomek byl ukončen s kódem %i\n" +#, c-format #~ msgid "cannot allocate infile string: %s\n" #~ msgstr "nelze alokovat řetězec infile: %s\n" +#, c-format #~ msgid "cannot allocate outfile string: %s\n" #~ msgstr "nelze alokovat řetězec outfile: %s\n" +#, c-format #~ msgid "either %s or %s must be given\n" #~ msgstr "musí být zadáno buď %s, nebo %s\n" +#, c-format #~ msgid "no class provided\n" #~ msgstr "nezadána žádná třída\n" +#, c-format #~ msgid "class %s is not supported\n" #~ msgstr "třída %s není podporována\n" @@ -9392,6 +9451,7 @@ msgstr "spravuje historii příkazů" #~ msgid "Sex ((M)ale, (F)emale or space): " #~ msgstr "Zadejte pohlaví: M – mužské, F – ženské, nebo stiskněte mezerník: " +#, c-format #~ msgid " using certificate ID 0x%08lX\n" #~ msgstr " pomocí certifikátu s ID 0x%08lX\n" @@ -10584,8 +10644,8 @@ msgstr "spravuje historii příkazů" #~ "\n" #~ "Note that the examples given above for levels 2 and 3 are *only* " #~ "examples.\n" -#~ "In the end, it is up to you to decide just what \"casual\" and \"extensive" -#~ "\"\n" +#~ "In the end, it is up to you to decide just what \"casual\" and " +#~ "\"extensive\"\n" #~ "mean to you when you sign other keys.\n" #~ "\n" #~ "If you don't know what the right answer is, answer \"0\"." @@ -10632,8 +10692,8 @@ msgstr "spravuje historii příkazů" #~ "Answer \"yes\" if you really want to delete this user ID.\n" #~ "All certificates are then also lost!" #~ msgstr "" -#~ "Pokud opravdu chcete smazat tento identifikátor uživatele, odpovězte \"ano" -#~ "\".\n" +#~ "Pokud opravdu chcete smazat tento identifikátor uživatele, odpovězte " +#~ "\"ano\".\n" #~ "Všechny certifikáty budou také ztraceny!" #~ msgid "Answer \"yes\" if it is okay to delete the subkey" From baa88832153d99adbbbb70d6a420784cc1267e84 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 5 Jun 2023 15:07:22 +0200 Subject: [PATCH 24/56] gpg: Set default expiration date to 3 years. * g10/keygen.c (default_expiration_interval): Change. -- This is a revision of GnuPG-bug-id: 2701 --- g10/keygen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/g10/keygen.c b/g10/keygen.c index 7f54f7da0..d5099dbb9 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -56,7 +56,7 @@ /* When generating keys using the streamlined key generation dialog, use this as a default expiration interval. */ -const char *default_expiration_interval = "2y"; +const char *default_expiration_interval = "3y"; /* Flag bits used during key generation. */ #define KEYGEN_FLAG_NO_PROTECTION 1 From 7b7fdf45e5d8b3b066c5efbf6ec872e1249f3a24 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 6 Jun 2023 18:19:37 +0200 Subject: [PATCH 25/56] common: New function substitute_vars. * common/stringhelp.c (substitute_envvars): Factor code out to (substitute_vars): new. (subst_getenv): New. -- This is a generalized version of substitute_envvars. --- common/stringhelp.c | 44 ++++++++++++++++++++++++++++++++++++++------ common/stringhelp.h | 5 ++++- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/common/stringhelp.c b/common/stringhelp.c index 6959299e4..1049c78e2 100644 --- a/common/stringhelp.c +++ b/common/stringhelp.c @@ -1689,10 +1689,16 @@ format_text (const char *text_in, int target_cols, int max_cols) } -/* Substitute environment variables in STRING and return a new string. - * On error the function returns NULL. */ +/* Substitute variables in STRING and return a new string. GETVAL is + * a function which maps NAME to its value; that value is a string + * which may not change during the execution time of this function. + * If GETVAL returns NULL substitute_vars returns NULL and the caller + * may inspect ERRNO for the reason. In all other error cases this + * function also returns NULL. Caller must free the returned string. */ char * -substitute_envvars (const char *string) +substitute_vars (const char *string, + const char *(*getval)(void *cookie, const char *name), + void *cookie) { char *line, *p, *pend; const char *value; @@ -1743,19 +1749,22 @@ substitute_envvars (const char *string) { int save = *pend; *pend = 0; - value = getenv (p+2); + value = getval (cookie, p+2); *pend++ = save; } else { int save = *pend; *pend = 0; - value = getenv (p+1); + value = getval (cookie, p+1); *pend = save; } if (!value) - value = ""; + { + xfree (result); + return NULL; + } valuelen = strlen (value); if (valuelen <= pend - p) { @@ -1791,3 +1800,26 @@ substitute_envvars (const char *string) leave: return result; } + + +/* Helper for substitute_envvars. */ +static const char * +subst_getenv (void *cookie, const char *name) +{ + const char *s; + + (void)cookie; + + s = getenv (name); + return s? s : ""; +} + + +/* Substitute environment variables in STRING and return a new string. + * On error the function returns NULL. */ +char * +substitute_envvars (const char *string) +{ + return substitute_vars (string, subst_getenv, NULL); + +} diff --git a/common/stringhelp.h b/common/stringhelp.h index 915b3aa72..cd185e49a 100644 --- a/common/stringhelp.h +++ b/common/stringhelp.h @@ -169,7 +169,10 @@ int compare_version_strings (const char *my_version, const char *req_version); /* Format a string so that it fits within about TARGET_COLS columns. */ char *format_text (const char *text, int target_cols, int max_cols); -/* Substitute environmen variabales in STRING. */ +/* Substitute variables in STRING. */ +char *substitute_vars (const char *string, + const char *(*getval)(void *cookie, const char *name), + void *cookie); char *substitute_envvars (const char *string); From 207c99567ced260aab04c471c77f179943d492f4 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 7 Jun 2023 10:03:48 +0200 Subject: [PATCH 26/56] dirmngr: Extend the AD_QUERY command. * dirmngr/server.c (cmd_ad_query): Add options --help and --subst. (cmd_getinfo): Add sub-command "sid". * dirmngr/ks-engine.h (KS_GET_FLAG_SUBST): New. * dirmngr/ks-engine-ldap.c (ks_ldap_help_variables): New. (getval_for_filter): New. (map_rid_to_dn): New. (ks_ldap_query): Support variables. -- The new variables features makes it easier to write AD queries without requiring domain specific expressions. --- common/name-value.c | 2 +- dirmngr/ks-engine-ldap.c | 191 +++++++++++++++++++++++++++++++++++++++ dirmngr/ks-engine.h | 2 + dirmngr/server.c | 66 ++++++++++++-- 4 files changed, 252 insertions(+), 9 deletions(-) diff --git a/common/name-value.c b/common/name-value.c index 6f3df5a8d..0dffc63b4 100644 --- a/common/name-value.c +++ b/common/name-value.c @@ -616,7 +616,7 @@ nve_next_value (nve_t entry, const char *name) /* Return the string for the first entry in NVC with NAME. If an * entry with NAME is missing in NVC or its value is the empty string - * NULL is returned. Note that the The returned string is a pointer + * NULL is returned. Note that the the returned string is a pointer * into NVC. */ const char * nvc_get_string (nvc_t nvc, const char *name) diff --git a/dirmngr/ks-engine-ldap.c b/dirmngr/ks-engine-ldap.c index 1ffd30ecb..c2a210542 100644 --- a/dirmngr/ks-engine-ldap.c +++ b/dirmngr/ks-engine-ldap.c @@ -26,6 +26,13 @@ #include #include #include +#ifdef HAVE_W32_SYSTEM +# ifndef WINVER +# define WINVER 0x0500 /* Same as in common/sysutils.c */ +# endif +# include +# include +#endif #include "dirmngr.h" @@ -73,6 +80,9 @@ struct ks_engine_ldap_local_s int more_pages; /* More pages announced by server. */ }; +/*-- prototypes --*/ +static char *map_rid_to_dn (ctrl_t ctrl, const char *rid); +static char *basedn_from_rootdse (ctrl_t ctrl, parsed_uri_t uri); @@ -150,6 +160,114 @@ my_ldap_value_free (char **vals) } +/* Print a description of supported variables. */ +void +ks_ldap_help_variables (ctrl_t ctrl) +{ + const char data[] = + "Supported variables in LDAP filter expressions:\n" + "\n" + "domain - The defaultNamingContext.\n" + "domain_admins - Group of domain admins.\n" + "domain_users - Group with all user accounts.\n" + "domain_guests - Group with the builtin gues account.\n" + "domain_computers - Group with all clients and servers.\n" + "cert_publishers - Group with all cert issuing computers.\n" + "protected_users - Group of users with extra protection.\n" + "key_admins - Group for delegated access to msdsKeyCredentialLink.\n" + "enterprise_key_admins - Similar to key_admins.\n" + "domain_domain_controllers - Group with all domain controllers.\n" + "sid_domain - SubAuthority numbers.\n"; + + ks_print_help (ctrl, data); +} + + +/* Helper function for substitute_vars. */ +static const char * +getval_for_filter (void *cookie, const char *name) +{ + ctrl_t ctrl = cookie; + const char *result = NULL; + + if (!strcmp (name, "sid_domain")) + { +#ifdef HAVE_W32_SYSTEM + PSID mysid; + static char *sidstr; + char *s, *s0; + int i; + + if (!sidstr) + { + mysid = w32_get_user_sid (); + if (!mysid) + { + gpg_err_set_errno (ENOENT); + goto leave; + } + + if (!ConvertSidToStringSid (mysid, &sidstr)) + { + gpg_err_set_errno (EINVAL); + goto leave; + } + /* Example for SIDSTR: + * S-1-5-21-3636969917-2569447256-918939550-1127 */ + for (s0=NULL,s=sidstr,i=0; (s=strchr (s, '-')); i++) + { + s++; + if (i == 3) + s0 = s; + else if (i==6) + { + s[-1] = 0; + break; + } + } + if (!s0) + { + log_error ("oops: invalid SID received from OS"); + gpg_err_set_errno (EINVAL); + LocalFree (sidstr); + goto leave; + } + sidstr = s0; /* (We never release SIDSTR thus no memmove.) */ + } + result = sidstr; +#else + gpg_err_set_errno (ENOSYS); + goto leave; +#endif + } + else if (!strcmp (name, "domain")) + result = basedn_from_rootdse (ctrl, NULL); + else if (!strcmp (name, "domain_admins")) + result = map_rid_to_dn (ctrl, "512"); + else if (!strcmp (name, "domain_users")) + result = map_rid_to_dn (ctrl, "513"); + else if (!strcmp (name, "domain_guests")) + result = map_rid_to_dn (ctrl, "514"); + else if (!strcmp (name, "domain_computers")) + result = map_rid_to_dn (ctrl, "515"); + else if (!strcmp (name, "domain_domain_controllers")) + result = map_rid_to_dn (ctrl, "516"); + else if (!strcmp (name, "cert_publishers")) + result = map_rid_to_dn (ctrl, "517"); + else if (!strcmp (name, "protected_users")) + result = map_rid_to_dn (ctrl, "525"); + else if (!strcmp (name, "key_admins")) + result = map_rid_to_dn (ctrl, "526"); + else if (!strcmp (name, "enterprise_key_admins")) + result = map_rid_to_dn (ctrl, "527"); + else + result = ""; /* Unknown variables are empty. */ + + leave: + return result; +} + + /* Print a help output for the schemata supported by this module. */ gpg_error_t @@ -1396,6 +1514,63 @@ fetch_rootdse (ctrl_t ctrl, parsed_uri_t uri) } +/* Return the DN for the given RID. This is used with the Active + * Directory. */ +static char * +map_rid_to_dn (ctrl_t ctrl, const char *rid) +{ + gpg_error_t err; + char *result = NULL; + estream_t infp = NULL; + uri_item_t puri; /* The broken down URI. */ + nvc_t nvc = NULL; + char *filter = NULL; + const char *s; + char *attr[2] = {"dn", NULL}; + + err = ks_action_parse_uri ("ldap:///", &puri); + if (err) + return NULL; + + filter = strconcat ("(objectSid=S-1-5-21-$sid_domain-", rid, ")", NULL); + if (!filter) + goto leave; + + err = ks_ldap_query (ctrl, puri->parsed_uri, KS_GET_FLAG_SUBST, + filter, attr, NULL, &infp); + if (err) + { + log_error ("ldap: AD query '%s' failed: %s\n", filter,gpg_strerror (err)); + goto leave; + } + if ((err = nvc_parse (&nvc, NULL, infp))) + { + log_error ("ldap: parsing the result failed: %s\n",gpg_strerror (err)); + goto leave; + } + if (!(s = nvc_get_string (nvc, "Dn:"))) + { + err = gpg_error (GPG_ERR_NOT_FOUND); + log_error ("ldap: mapping rid '%s'failed: %s\n", rid, gpg_strerror (err)); + goto leave; + } + result = xtrystrdup (s); + if (!result) + { + err = gpg_error_from_syserror (); + log_error ("ldap: strdup failed: %s\n", gpg_strerror (err)); + goto leave; + } + + leave: + es_fclose (infp); + release_uri_item_list (puri); + xfree (filter); + nvc_release (nvc); + return result; +} + + /* Return the baseDN for URI which might have already been cached for * this session. */ static char * @@ -2824,6 +2999,7 @@ ks_ldap_query (ctrl_t ctrl, parsed_uri_t uri, unsigned int ks_get_flags, LDAP *ldap_conn = NULL; char *basedn = NULL; estream_t fp = NULL; + char *filter_arg_buffer = NULL; char *filter = NULL; int scope = LDAP_SCOPE_SUBTREE; LDAPMessage *message = NULL; @@ -2839,6 +3015,20 @@ ks_ldap_query (ctrl_t ctrl, parsed_uri_t uri, unsigned int ks_get_flags, if ((!filter_arg || !*filter_arg) && (ks_get_flags & KS_GET_FLAG_ROOTDSE)) filter_arg = "^&base&(objectclass=*)"; + if ((ks_get_flags & KS_GET_FLAG_SUBST) + && filter_arg && strchr (filter_arg, '$')) + { + filter_arg_buffer = substitute_vars (filter_arg, getval_for_filter, ctrl); + if (!filter_arg_buffer) + { + err = gpg_error_from_syserror (); + log_error ("substituting filter variables failed: %s\n", + gpg_strerror (err)); + goto leave; + } + filter_arg = filter_arg_buffer; + } + err = ks_ldap_prepare_my_state (ctrl, ks_get_flags, &first_mode, &next_mode); if (err) goto leave; @@ -3048,6 +3238,7 @@ ks_ldap_query (ctrl_t ctrl, parsed_uri_t uri, unsigned int ks_get_flags, ldap_unbind (ldap_conn); xfree (filter); + xfree (filter_arg_buffer); return err; } diff --git a/dirmngr/ks-engine.h b/dirmngr/ks-engine.h index 03588a4d3..6de77ccb2 100644 --- a/dirmngr/ks-engine.h +++ b/dirmngr/ks-engine.h @@ -29,6 +29,7 @@ #define KS_GET_FLAG_NEXT 4 #define KS_GET_FLAG_ONLY_AD 8 /* Do this only if we have an AD. */ #define KS_GET_FLAG_ROOTDSE 16 /* Get the rootDSE. */ +#define KS_GET_FLAG_SUBST 32 /* Substiture variables. */ /*-- ks-action.c --*/ @@ -70,6 +71,7 @@ gpg_error_t ks_kdns_help (ctrl_t ctrl, parsed_uri_t uri); gpg_error_t ks_kdns_fetch (ctrl_t ctrl, parsed_uri_t uri, estream_t *r_fp); /*-- ks-engine-ldap.c --*/ +void ks_ldap_help_variables (ctrl_t ctrl); gpg_error_t ks_ldap_help (ctrl_t ctrl, parsed_uri_t uri); void ks_ldap_free_state (struct ks_engine_ldap_local_s *state); gpg_error_t ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, diff --git a/dirmngr/server.c b/dirmngr/server.c index 2c5a41b07..51a149cb2 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -32,6 +32,13 @@ #include #include #include +#ifdef HAVE_W32_SYSTEM +# ifndef WINVER +# define WINVER 0x0500 /* Same as in common/sysutils.c */ +# endif +# include +# include +#endif #include "dirmngr.h" #include @@ -2701,15 +2708,21 @@ cmd_ks_put (assuan_context_t ctx, char *line) static const char hlp_ad_query[] = - "AD_QUERY [--first|--next] [--] \n" + "AD_QUERY [--first|--next] [--] \n" "\n" "Query properties from a Windows Active Directory.\n" - "Our extended filter syntax may be used for the filter\n" - "expression; see gnupg/dirmngr/ldap-misc.c. There are\n" - "a couple of other options available:\n\n" - " --rootdse - Query the root using serverless binding,\n" + "Options:\n" + "\n" + " --rootdse - Query the root using serverless binding,\n" + " --subst - Substitute variables in the filter\n" " --attr= - Comma delimited list of attributes\n" " to return.\n" + " --help - List supported variables\n" + "\n" + "Extended filter syntax is allowed:\n" + " ^[][&]&[]\n" + "Usual escaping rules apply. An ampersand in must\n" + "doubled. may be \"base\", \"one\", or \"sub\"." ; static gpg_error_t cmd_ad_query (assuan_context_t ctx, char *line) @@ -2723,6 +2736,7 @@ cmd_ad_query (assuan_context_t ctx, char *line) char **opt_attr = NULL; const char *s; gnupg_isotime_t opt_newer; + int opt_help = 0; *opt_newer = 0; @@ -2733,6 +2747,10 @@ cmd_ad_query (assuan_context_t ctx, char *line) flags |= KS_GET_FLAG_NEXT; if (has_option (line, "--rootdse")) flags |= KS_GET_FLAG_ROOTDSE; + if (has_option (line, "--subst")) + flags |= KS_GET_FLAG_SUBST; + if (has_option (line, "--help")) + opt_help = 1; if ((s = option_value (line, "--newer")) && !string2isotime (opt_newer, s)) { @@ -2756,6 +2774,13 @@ cmd_ad_query (assuan_context_t ctx, char *line) line = skip_options (line); filter = line; + if (opt_help) + { + ks_ldap_help_variables (ctrl); + err = 0; + goto leave; + } + if ((flags & KS_GET_FLAG_NEXT)) { if (*filter || (flags & ~KS_GET_FLAG_NEXT)) @@ -2907,14 +2932,39 @@ cmd_getinfo (assuan_context_t ctx, char *line) { const char *s = getenv (line); if (!s) - err = set_error (GPG_ERR_NOT_FOUND, "No such envvar"); - else - err = assuan_send_data (ctx, s, strlen (s)); + { + err = set_error (GPG_ERR_NOT_FOUND, "No such envvar"); + goto leave; + } + err = assuan_send_data (ctx, s, strlen (s)); } } +#ifdef HAVE_W32_SYSTEM + else if (!strcmp (line, "sid")) + { + PSID mysid; + char *sidstr; + + mysid = w32_get_user_sid (); + if (!mysid) + { + err = set_error (GPG_ERR_NOT_FOUND, "Error getting my SID"); + goto leave; + } + + if (!ConvertSidToStringSid (mysid, &sidstr)) + { + err = set_error (GPG_ERR_BUG, "Error converting SID to a string"); + goto leave; + } + err = assuan_send_data (ctx, sidstr, strlen (sidstr)); + LocalFree (sidstr); + } +#endif /*HAVE_W32_SYSTEM*/ else err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT"); + leave: return leave_cmd (ctx, err); } From c68dd22872375ab02223e2900ffa3bfe99e8b841 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 9 Jun 2023 16:16:56 +0200 Subject: [PATCH 27/56] gpg: Add --list-filter properties key_expires and key_expires_d. * g10/import.c (impex_filter_getval): Support new filter properties. -- Here is how to list all subkeys expiring in the year 2061: gpg --list-keys --list-filter 'select= sub/key_expires_d -gt 2061-01-01 \ && sub/key_expires_d -lt 2061-12-31' To list all primary key expirations, use the "pub/" prefix and to list all expiration dates use no prefix. GnuPG-bug-id: 6509 --- doc/gpg.texi | 6 ++++++ g10/import.c | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/doc/gpg.texi b/doc/gpg.texi index 6b584a913..61f047cc7 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -2671,6 +2671,12 @@ The available properties are: created. The second is the same but given as an ISO string, e.g. "2016-08-17". (drop-subkey) + @item key_expires + @itemx key_expires_d + The expiration time of a public key or subkey or 0 if it does not + expire. The second is the same but given as an ISO date string or + an empty string e.g. "2038-01-19". + @item fpr The hexified fingerprint of the current subkey or primary key. (drop-subkey) diff --git a/g10/import.c b/g10/import.c index 987fef3cd..d84a083cc 100644 --- a/g10/import.c +++ b/g10/import.c @@ -1564,6 +1564,20 @@ impex_filter_getval (void *cookie, const char *propname) { result = dateonlystr_from_pk (pk); } + else if (!strcmp (propname, "key_expires")) + { + snprintf (numbuf, sizeof numbuf, "%lu", (ulong)pk->expiredate); + result = numbuf; + } + else if (!strcmp (propname, "key_expires_d")) + { + static char exdatestr[MK_DATESTR_SIZE]; + + if (pk->expiredate) + result = mk_datestr (exdatestr, sizeof exdatestr, pk->expiredate); + else + result = ""; + } else if (!strcmp (propname, "expired")) { result = pk->has_expired? "1":"0"; From ca3f0e66bcf669181ec0bf50c83130eee2648acc Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 9 Jun 2023 13:46:11 +0200 Subject: [PATCH 28/56] w32: Map ERROR_FILE_INVALID to EIO. * common/sysutils.c (map_w32_to_errno): Add mapping. -- We see this error sometimes when writing to an USB connected disk. --- common/sysutils.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/sysutils.c b/common/sysutils.c index 01510ddb0..231565177 100644 --- a/common/sysutils.c +++ b/common/sysutils.c @@ -252,6 +252,9 @@ map_w32_to_errno (DWORD w32_err) case ERROR_ALREADY_EXISTS: return EEXIST; + case ERROR_FILE_INVALID: + return EIO; + /* This mapping has been taken from reactOS. */ case ERROR_TOO_MANY_OPEN_FILES: return EMFILE; case ERROR_ARENA_TRASHED: return ENOMEM; From 64509134d47a13c87481e39895cd58ea77eec61a Mon Sep 17 00:00:00 2001 From: Andre Heinecke Date: Wed, 7 Jun 2023 14:43:41 +0200 Subject: [PATCH 29/56] speedo,w32: Call gpgconf --kill all * build-aux/speedo/w32/inst.nsi: Use kill all instead of explicitly killing processes. --- build-aux/speedo/w32/inst.nsi | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build-aux/speedo/w32/inst.nsi b/build-aux/speedo/w32/inst.nsi index 283166835..6c4b84969 100644 --- a/build-aux/speedo/w32/inst.nsi +++ b/build-aux/speedo/w32/inst.nsi @@ -1067,9 +1067,7 @@ Section "-un.gnupglast" nsExec::ExecToLog '"$INSTDIR\bin\launch-gpa" "--stop-server"' no_uiserver: ifFileExists "$INSTDIR\bin\gpgconf.exe" 0 no_gpgconf - nsExec::ExecToLog '"$INSTDIR\bin\gpgconf" "--kill" "gpg-agent"' - nsExec::ExecToLog '"$INSTDIR\bin\gpgconf" "--kill" "dirmngr"' - nsExec::ExecToLog '"$INSTDIR\bin\gpgconf" "--kill" "keyboxd"' + nsExec::ExecToLog '"$INSTDIR\bin\gpgconf" "--kill" "all"' no_gpgconf: SectionEnd From 695cb04af5218cd7b42c7eaaefc186472b99a995 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 9 Jun 2023 17:40:53 +0200 Subject: [PATCH 30/56] gpg: Print status line and proper diagnostics for write errors. * common/iobuf.c (file_filter): Improve diagnostics. * g10/build-packet.c (do_plaintext): Make sure to cache all error cases. -- GnuPG-bug-id: 6528 --- common/iobuf.c | 9 ++++++--- g10/build-packet.c | 14 +++++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/common/iobuf.c b/common/iobuf.c index 825b97704..dee3b46b1 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -503,7 +503,8 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf, if (ec != ERROR_BROKEN_PIPE) { rc = gpg_error_from_errno (ec); - log_error ("%s: read error: ec=%d\n", a->fname, ec); + log_error ("%s: read error: %s (ec=%d)\n", + a->fname, gpg_strerror (rc), ec); } } else if (!nread) @@ -573,7 +574,8 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf, { int ec = (int) GetLastError (); rc = gpg_error_from_errno (ec); - log_error ("%s: write error: ec=%d\n", a->fname, ec); + log_error ("%s: write error: %s (ec=%d)\n", + a->fname, gpg_strerror (rc), ec); break; } p += n; @@ -632,7 +634,8 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf, if (ec != ERROR_BROKEN_PIPE) { rc = gpg_error_from_errno (ec); - log_error ("%s: read error: ec=%d\n", a->fname, ec); + log_error ("%s: read error: %s (ec=%d)\n", + a->fname, gpg_strerror (rc), ec); } a->npeeked = 0; } diff --git a/g10/build-packet.c b/g10/build-packet.c index 192dfaef5..67d4a6eef 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -991,12 +991,20 @@ do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt ) if (nbytes == (size_t)(-1) && (iobuf_error (out) || iobuf_error (pt->buf))) return iobuf_error (out)? iobuf_error (out):iobuf_error (pt->buf); + /* Always get the error to catch write errors because + * iobuf_copy does not reliable return (-1) in that case. */ + rc = iobuf_error (out); if(ctb_new_format_p (ctb) && !pt->len) /* Turn off partial body length mode. */ iobuf_set_partial_body_length_mode (out, 0); - if( pt->len && nbytes != pt->len ) - log_error("do_plaintext(): wrote %lu bytes but expected %lu bytes\n", - (ulong)nbytes, (ulong)pt->len ); + if (pt->len && nbytes != pt->len) + { + log_error ("do_plaintext(): wrote %lu bytes" + " but expected %lu bytes\n", + (ulong)nbytes, (ulong)pt->len ); + if (!rc) /* Just in case no error was set */ + rc = gpg_error (GPG_ERR_EIO); + } } return rc; From 808494b48577c2efb894a0877f59d9c4ed664f56 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 13 Jun 2023 10:07:07 +0200 Subject: [PATCH 31/56] gpg: Make progress work for large files on Windows. * common/iobuf.c (iobuf_get_filelength): Change return type to uint64_t and remove the overflow args. For Windows always use GetFileSizeEx which is available since the long EOL-ed Windows XP. * g10/sign.c (write_plaintext_packet): Adjust for changed iobuf_get_filelength. * g10/encrypt.c (encrypt_simple, encrypt_crypt): Ditto. * g10/photoid.c (generate_photo_id): Ditto. Also add an upper limit. * g10/filter.h (progress_filter_context_t): Change amount values to use uint64_t. * g10/progress.c (write_status_progress): Change accordingly. -- GnuPG-bug-id: 6534 --- common/iobuf.c | 61 +++++++++----------------------------------------- common/iobuf.h | 8 ++----- g10/encrypt.c | 15 ++++++------- g10/filter.h | 6 ++--- g10/gpg.c | 8 ++++++- g10/photoid.c | 18 ++++++++++----- g10/progress.c | 15 +++++++------ g10/sign.c | 7 +++--- 8 files changed, 52 insertions(+), 86 deletions(-) diff --git a/common/iobuf.c b/common/iobuf.c index dee3b46b1..627d33900 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -2608,13 +2608,10 @@ iobuf_set_limit (iobuf_t a, off_t nlimit) } - -off_t -iobuf_get_filelength (iobuf_t a, int *overflow) +/* Return the length of the file behind A. If there is no file, return 0. */ +uint64_t +iobuf_get_filelength (iobuf_t a) { - if (overflow) - *overflow = 0; - /* Hmmm: file_filter may have already been removed */ for ( ; a->chain; a = a->chain ) ; @@ -2627,56 +2624,18 @@ iobuf_get_filelength (iobuf_t a, int *overflow) gnupg_fd_t fp = b->fp; #if defined(HAVE_W32_SYSTEM) - ulong size; - static int (* __stdcall get_file_size_ex) (void *handle, - LARGE_INTEGER *r_size); - static int get_file_size_ex_initialized; + LARGE_INTEGER exsize; - if (!get_file_size_ex_initialized) - { - void *handle; - - handle = dlopen ("kernel32.dll", RTLD_LAZY); - if (handle) - { - get_file_size_ex = dlsym (handle, "GetFileSizeEx"); - if (!get_file_size_ex) - dlclose (handle); - } - get_file_size_ex_initialized = 1; - } - - if (get_file_size_ex) - { - /* This is a newer system with GetFileSizeEx; we use this - then because it seem that GetFileSize won't return a - proper error in case a file is larger than 4GB. */ - LARGE_INTEGER exsize; - - if (get_file_size_ex (fp, &exsize)) - { - if (!exsize.u.HighPart) - return exsize.u.LowPart; - if (overflow) - *overflow = 1; - return 0; - } - } - else - { - if ((size=GetFileSize (fp, NULL)) != 0xffffffff) - return size; - } + if (GetFileSizeEx (fp, &exsize)) + return exsize.QuadPart; log_error ("GetFileSize for handle %p failed: %s\n", fp, w32_strerror (-1)); #else /*!HAVE_W32_SYSTEM*/ - { - struct stat st; + struct stat st; - if ( !fstat (fp, &st) ) - return st.st_size; - log_error("fstat() failed: %s\n", strerror(errno) ); - } + if ( !fstat (fp, &st) ) + return st.st_size; + log_error("fstat() failed: %s\n", strerror(errno) ); #endif /*!HAVE_W32_SYSTEM*/ } diff --git a/common/iobuf.h b/common/iobuf.h index c132c2f3c..751ae73c3 100644 --- a/common/iobuf.h +++ b/common/iobuf.h @@ -584,12 +584,8 @@ size_t iobuf_temp_to_buffer (iobuf_t a, byte * buffer, size_t buflen); size_t iobuf_copy (iobuf_t dest, iobuf_t source); /* Return the size of any underlying file. This only works with - file_filter based pipelines. - - On Win32, it is sometimes not possible to determine the size of - files larger than 4GB. In this case, *OVERFLOW (if not NULL) is - set to 1. Otherwise, *OVERFLOW is set to 0. */ -off_t iobuf_get_filelength (iobuf_t a, int *overflow); + file_filter based pipelines. */ +uint64_t iobuf_get_filelength (iobuf_t a); #define IOBUF_FILELENGTH_LIMIT 0xffffffff /* Return the file descriptor designating the underlying file. This diff --git a/g10/encrypt.c b/g10/encrypt.c index ff1c6be85..9aeafa292 100644 --- a/g10/encrypt.c +++ b/g10/encrypt.c @@ -580,12 +580,12 @@ encrypt_simple (const char *filename, int mode, int use_seskey) if ( !iobuf_is_pipe_filename (filename) && *filename && !opt.textmode ) { - off_t tmpsize; - int overflow; + uint64_t tmpsize; - if ( !(tmpsize = iobuf_get_filelength(inp, &overflow)) - && !overflow && opt.verbose) + tmpsize = iobuf_get_filelength(inp); + if (!tmpsize && opt.verbose) log_info(_("WARNING: '%s' is an empty file\n"), filename ); + /* We can't encode the length of very large files because OpenPGP uses only 32 bit for file sizes. So if the size of a file is larger than 2^32 minus some bytes for @@ -942,11 +942,10 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, if (filename && *filename && !iobuf_is_pipe_filename (filename) && !opt.textmode ) { - off_t tmpsize; - int overflow; + uint64_t tmpsize; - if ( !(tmpsize = iobuf_get_filelength(inp, &overflow)) - && !overflow && opt.verbose) + tmpsize = iobuf_get_filelength (inp); + if (!tmpsize && opt.verbose) log_info(_("WARNING: '%s' is an empty file\n"), filename ); /* We can't encode the length of very large files because OpenPGP uses only 32 bit for file sizes. So if the size diff --git a/g10/filter.h b/g10/filter.h index 46342d2ad..4b4fc55ff 100644 --- a/g10/filter.h +++ b/g10/filter.h @@ -155,9 +155,9 @@ typedef struct { typedef struct { char *what; /* description */ u32 last_time; /* last time reported */ - unsigned long last; /* last amount reported */ - unsigned long offset; /* current amount */ - unsigned long total; /* total amount */ + uint64_t last; /* last amount reported */ + uint64_t offset; /* current amount */ + uint64_t total; /* total amount */ int refcount; } progress_filter_context_t; diff --git a/g10/gpg.c b/g10/gpg.c index 6e54aa763..39776c3d1 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -3499,7 +3499,13 @@ main (int argc, char **argv) case oAllowFreeformUID: opt.allow_freeform_uid = 1; break; case oNoAllowFreeformUID: opt.allow_freeform_uid = 0; break; case oNoLiteral: opt.no_literal = 1; break; - case oSetFilesize: opt.set_filesize = pargs.r.ret_ulong; break; + + case oSetFilesize: + /* There are restricts on the value (e.g. < 2^32); you + * need to check the entire code to understand this. */ + opt.set_filesize = pargs.r.ret_ulong; + break; + case oFastListMode: opt.fast_list_mode = 1; break; case oFixedListMode: /* Dummy */ break; case oLegacyListMode: opt.legacy_list_mode = 1; break; diff --git a/g10/photoid.c b/g10/photoid.c index 72e6acf7d..fc8866121 100644 --- a/g10/photoid.c +++ b/g10/photoid.c @@ -160,12 +160,11 @@ generate_photo_id (ctrl_t ctrl, PKT_public_key *pk,const char *photo_name) { PKT_user_id *uid; int error=1,i; - unsigned int len; + uint64_t len; char *filename; byte *photo=NULL; byte header[16]; IOBUF file; - int overflow; header[0]=0x10; /* little side of photo header length */ header[1]=0; /* big side of photo header length */ @@ -233,11 +232,18 @@ generate_photo_id (ctrl_t ctrl, PKT_public_key *pk,const char *photo_name) } - len=iobuf_get_filelength(file, &overflow); - if(len>6144 || overflow) + len = iobuf_get_filelength(file); + if(len>6144) { - tty_printf( _("This JPEG is really large (%d bytes) !\n"),len); - if(!cpr_get_answer_is_yes("photoid.jpeg.size", + /* We silently skip JPEGs larger than 1MiB because we have a + * 2MiB limit on the user ID packets and we need some limit + * anyway because the returned u64 is larger than the u32 or + * OpenPGP. Note that the diagnostic may print a wrong + * value if the value is really large; we don't fix this to + * avoid a string change. */ + tty_printf( _("This JPEG is really large (%d bytes) !\n"), (int)len); + if(len > 1024*1024 + || !cpr_get_answer_is_yes("photoid.jpeg.size", _("Are you sure you want to use it? (y/N) "))) { iobuf_close(file); diff --git a/g10/progress.c b/g10/progress.c index 7e777d4ab..7ee8b1e04 100644 --- a/g10/progress.c +++ b/g10/progress.c @@ -72,13 +72,11 @@ release_progress_context (progress_filter_context_t *pfx) static void -write_status_progress (const char *what, - unsigned long current, unsigned long total_arg) +write_status_progress (const char *what, uint64_t current, uint64_t total) { char buffer[60]; char units[] = "BKMGTPEZY?"; int unitidx = 0; - uint64_t total = total_arg; /* Although we use an unsigned long for the values, 32 bit * applications using GPGME will use an "int" and thus are limited @@ -91,7 +89,10 @@ write_status_progress (const char *what, * to display how many percent of the operation has been done and * thus scaling CURRENT and TOTAL down before they get to large, * should not have a noticeable effect except for rounding - * imprecision. */ + * imprecision. + * Update 2023-06-13: We now use uint64_t but to keep the API stable + * we still do the scaling. + */ if (!total && opt.input_size_hint) total = opt.input_size_hint; @@ -121,7 +122,7 @@ write_status_progress (const char *what, unitidx = 9; snprintf (buffer, sizeof buffer, "%.20s ? %lu %lu %c%s", - what? what : "?", current, (unsigned long)total, + what? what : "?", (unsigned long)current, (unsigned long)total, units[unitidx], unitidx? "iB" : ""); write_status_text (STATUS_PROGRESS, buffer); @@ -181,7 +182,7 @@ progress_filter (void *opaque, int control, void handle_progress (progress_filter_context_t *pfx, IOBUF inp, const char *name) { - off_t filesize = 0; + uint64_t filesize = 0; if (!pfx) return; @@ -190,7 +191,7 @@ handle_progress (progress_filter_context_t *pfx, IOBUF inp, const char *name) log_assert (is_status_enabled ()); if ( !iobuf_is_pipe_filename (name) && *name ) - filesize = iobuf_get_filelength (inp, NULL); + filesize = iobuf_get_filelength (inp); else if (opt.set_filesize) filesize = opt.set_filesize; diff --git a/g10/sign.c b/g10/sign.c index b5e9d422d..f9984f811 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -823,11 +823,10 @@ write_plaintext_packet (iobuf_t out, iobuf_t inp, /* Try to calculate the length of the data. */ if ( !iobuf_is_pipe_filename (fname) && *fname) { - off_t tmpsize; - int overflow; + uint64_t tmpsize; - if (!(tmpsize = iobuf_get_filelength (inp, &overflow)) - && !overflow && opt.verbose) + tmpsize = iobuf_get_filelength (inp); + if (!tmpsize && opt.verbose) log_info (_("WARNING: '%s' is an empty file\n"), fname); /* We can't encode the length of very large files because From c58067415fe93fbd5d3de2594ccca4761ad25103 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 15 Jun 2023 10:37:07 +0200 Subject: [PATCH 32/56] gpgsm: Print PROGRESS status lines. * common/ksba-io-support.c (struct writer_cb_parm_s): Add field progress. (struct gnupg_ksba_io_s): Add field is_writer. (update_write_progress): New. (base64_writer_cb, plain_writer_cb): Call update_write_progress. (base64_finish_write): Ditto. (gnupg_ksba_create_writer): Set is_writer. (gnupg_ksba_set_progress_cb): New. (gnupg_ksba_set_total): New. * common/ksba-io-support.h (gnupg_ksba_progress_cb_t): New type. * sm/server.c (gpgsm_status2): Return error from statusfp writes. (gpgsm_progress_cb): New. * sm/decrypt.c (gpgsm_decrypt): Set progress handler. * sm/encrypt.c (gpgsm_encrypt): Ditto. * sm/sign.c (gpgsm_sign): Ditto. * sm/verify.c (gpgsm_verify): Ditto. -- GnuPG-bug-id: 6534 --- common/ksba-io-support.c | 98 +++++++++++++++++++++++++++++++++++++--- common/ksba-io-support.h | 10 +++- sm/decrypt.c | 2 + sm/encrypt.c | 4 +- sm/gpgsm.h | 1 + sm/server.c | 56 ++++++++++++++++++++++- sm/sign.c | 4 +- sm/verify.c | 2 + 8 files changed, 167 insertions(+), 10 deletions(-) diff --git a/common/ksba-io-support.c b/common/ksba-io-support.c index a279b67ad..352485ffa 100644 --- a/common/ksba-io-support.c +++ b/common/ksba-io-support.c @@ -1,6 +1,6 @@ /* kska-io-support.c - Supporting functions for ksba reader and writer * Copyright (C) 2001-2005, 2007, 2010-2011, 2017 Werner Koch - * Copyright (C) 2006 g10 Code GmbH + * Copyright (C) 2006, 2023 g10 Code GmbH * * This file is part of GnuPG. * @@ -26,6 +26,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see . + * SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later) */ #include @@ -96,6 +97,15 @@ struct writer_cb_parm_s char *pem_name; /* Malloced. */ + struct { + gnupg_ksba_progress_cb_t cb; + ctrl_t ctrl; + u32 last_time; /* last time reported */ + uint64_t last; /* last amount reported */ + uint64_t current; /* current amount */ + uint64_t total; /* total amount */ + } progress; + int wrote_begin; int did_finish; @@ -110,6 +120,7 @@ struct writer_cb_parm_s /* Context for this module's functions. */ struct gnupg_ksba_io_s { + int is_writer; /* True if this context refers a writer object. */ union { struct reader_cb_parm_s rparm; struct writer_cb_parm_s wparm; @@ -527,6 +538,33 @@ simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread) +/* Call the progress callback if its time. We do this very 2 seconds + * or if FORCE is set. However, we also require that at least 64KiB + * have been written to avoid unnecessary progress lines for small + * files. */ +static gpg_error_t +update_write_progress (struct writer_cb_parm_s *parm, size_t count, int force) +{ + gpg_error_t err = 0; + u32 timestamp; + + parm->progress.current += count; + if (parm->progress.current >= (64*1024)) + { + timestamp = make_timestamp (); + if (force || (timestamp - parm->progress.last_time > 1)) + { + parm->progress.last = parm->progress.current; + parm->progress.last_time = timestamp; + err = parm->progress.cb (parm->progress.ctrl, + parm->progress.current, + parm->progress.total); + } + } + return err; +} + + static int base64_writer_cb (void *cb_value, const void *buffer, size_t count) { @@ -535,6 +573,8 @@ base64_writer_cb (void *cb_value, const void *buffer, size_t count) int i, c, idx, quad_count; const unsigned char *p; estream_t stream = parm->stream; + int rc; + size_t nleft; if (!count) return 0; @@ -557,7 +597,7 @@ base64_writer_cb (void *cb_value, const void *buffer, size_t count) for (i=0; i < idx; i++) radbuf[i] = parm->base64.radbuf[i]; - for (p=buffer; count; p++, count--) + for (p=buffer, nleft = count; nleft; p++, nleft--) { radbuf[idx++] = *p; if (idx > 2) @@ -583,7 +623,11 @@ base64_writer_cb (void *cb_value, const void *buffer, size_t count) parm->base64.idx = idx; parm->base64.quad_count = quad_count; - return es_ferror (stream)? gpg_error_from_syserror () : 0; + rc = es_ferror (stream)? gpg_error_from_syserror () : 0; + /* Note that we use the unencoded count for the progress. */ + if (!rc && parm->progress.cb) + rc = update_write_progress (parm, count, 0); + return rc; } @@ -594,13 +638,16 @@ plain_writer_cb (void *cb_value, const void *buffer, size_t count) { struct writer_cb_parm_s *parm = cb_value; estream_t stream = parm->stream; + int rc; if (!count) return 0; es_write (stream, buffer, count, NULL); - - return es_ferror (stream)? gpg_error_from_syserror () : 0; + rc = es_ferror (stream)? gpg_error_from_syserror () : 0; + if (!rc && parm->progress.cb) + rc = update_write_progress (parm, count, 0); + return rc; } @@ -610,6 +657,7 @@ base64_finish_write (struct writer_cb_parm_s *parm) unsigned char *radbuf; int c, idx, quad_count; estream_t stream = parm->stream; + int rc; if (!parm->wrote_begin) return 0; /* Nothing written or we are not called in base-64 mode. */ @@ -656,7 +704,10 @@ base64_finish_write (struct writer_cb_parm_s *parm) es_fputs ("-----\n", stream); } - return es_ferror (stream)? gpg_error_from_syserror () : 0; + rc = es_ferror (stream)? gpg_error_from_syserror () : 0; + if (!rc && parm->progress.cb) + rc = update_write_progress (parm, 0, 1); + return rc; } @@ -788,6 +839,7 @@ gnupg_ksba_create_writer (gnupg_ksba_io_t *ctx, unsigned int flags, *ctx = xtrycalloc (1, sizeof **ctx); if (!*ctx) return gpg_error_from_syserror (); + (*ctx)->is_writer = 1; rc = ksba_writer_new (&w); if (rc) @@ -865,3 +917,37 @@ gnupg_ksba_destroy_writer (gnupg_ksba_io_t ctx) xfree (ctx->u.wparm.pem_name); xfree (ctx); } + + +/* Set a callback to the writer object. CTRL will be bassed to the + * callback. */ +void +gnupg_ksba_set_progress_cb (gnupg_ksba_io_t ctx, + gnupg_ksba_progress_cb_t cb, ctrl_t ctrl) +{ + struct writer_cb_parm_s *parm; + + if (!ctx || !ctx->is_writer) + return; /* Currently only supported for writer objects. */ + parm = &ctx->u.wparm; + + parm->progress.cb = cb; + parm->progress.ctrl = ctrl; + parm->progress.last_time = 0; + parm->progress.last = 0; + parm->progress.current = 0; + parm->progress.total = 0; +} + + +/* Update the total count for the progress thingy. */ +void +gnupg_ksba_set_total (gnupg_ksba_io_t ctx, uint64_t total) +{ + struct writer_cb_parm_s *parm; + + if (!ctx || !ctx->is_writer) + return; /* Currently only supported for writer objects. */ + parm = &ctx->u.wparm; + parm->progress.total = total; +} diff --git a/common/ksba-io-support.h b/common/ksba-io-support.h index 02e541b16..1dbc303c8 100644 --- a/common/ksba-io-support.h +++ b/common/ksba-io-support.h @@ -25,6 +25,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see . + * SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later) */ #ifndef GNUPG_KSBA_IO_SUPPORT_H @@ -42,6 +43,10 @@ /* Context object. */ typedef struct gnupg_ksba_io_s *gnupg_ksba_io_t; +/* Progress callback type. */ +typedef gpg_error_t (*gnupg_ksba_progress_cb_t)(ctrl_t ctrl, + uint64_t current, + uint64_t total); gpg_error_t gnupg_ksba_create_reader (gnupg_ksba_io_t *ctx, @@ -57,10 +62,13 @@ gpg_error_t gnupg_ksba_create_writer (gnupg_ksba_io_t *ctx, const char *pem_name, estream_t stream, ksba_writer_t *r_writer); - gpg_error_t gnupg_ksba_finish_writer (gnupg_ksba_io_t ctx); void gnupg_ksba_destroy_writer (gnupg_ksba_io_t ctx); +void gnupg_ksba_set_progress_cb (gnupg_ksba_io_t ctx, + gnupg_ksba_progress_cb_t cb, ctrl_t ctrl); +void gnupg_ksba_set_total (gnupg_ksba_io_t ctx, uint64_t total); + diff --git a/sm/decrypt.c b/sm/decrypt.c index 68b362b45..abc1f2602 100644 --- a/sm/decrypt.c +++ b/sm/decrypt.c @@ -1107,6 +1107,8 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) goto leave; } + gnupg_ksba_set_progress_cb (b64writer, gpgsm_progress_cb, ctrl); + rc = ksba_cms_new (&cms); if (rc) goto leave; diff --git a/sm/encrypt.c b/sm/encrypt.c index 4fd4f93b9..b0e59f73e 100644 --- a/sm/encrypt.c +++ b/sm/encrypt.c @@ -653,6 +653,8 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp) goto leave; } + gnupg_ksba_set_progress_cb (b64writer, gpgsm_progress_cb, ctrl); + err = ksba_cms_new (&cms); if (err) { @@ -828,7 +830,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp) err = ksba_cms_build (cms, &stopreason); if (err) { - log_debug ("ksba_cms_build failed: %s\n", gpg_strerror (err)); + log_error ("creating CMS object failed: %s\n", gpg_strerror (err)); rc = err; goto leave; } diff --git a/sm/gpgsm.h b/sm/gpgsm.h index cef39ff2a..46c77803d 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -316,6 +316,7 @@ gpg_error_t gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text, gpg_err_code_t ec); gpg_error_t gpgsm_status_with_error (ctrl_t ctrl, int no, const char *text, gpg_error_t err); +gpg_error_t gpgsm_progress_cb (ctrl_t ctrl, uint64_t current, uint64_t total); gpg_error_t gpgsm_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line); diff --git a/sm/server.c b/sm/server.c index 3ec1c0c4b..455f5707a 100644 --- a/sm/server.c +++ b/sm/server.c @@ -1506,7 +1506,14 @@ gpgsm_status2 (ctrl_t ctrl, int no, ...) } } putc ('\n', statusfp); - fflush (statusfp); + if (ferror (statusfp)) + err = gpg_error_from_syserror (); + else + { + fflush (statusfp); + if (ferror (statusfp)) + err = gpg_error_from_syserror (); + } } else { @@ -1551,6 +1558,53 @@ gpgsm_status_with_error (ctrl_t ctrl, int no, const char *text, } +/* This callback is used to emit progress status lines. */ +gpg_error_t +gpgsm_progress_cb (ctrl_t ctrl, uint64_t current, uint64_t total) +{ + char buffer[60]; + char units[] = "BKMGTPEZY?"; + int unitidx = 0; + + if (current > 1024*1024*20) + { + static int closed; + if (closed) + close (5); + closed = 1; + } + + if (total) + { + if (total > current) + current = total; + + while (total > 1024*1024) + { + total /= 1024; + current /= 1024; + unitidx++; + } + } + else + { + while (current > 1024*1024) + { + current /= 1024; + unitidx++; + } + } + + if (unitidx > 9) + unitidx = 9; + + snprintf (buffer, sizeof buffer, "? %lu %lu %c%s", + (unsigned long)current, (unsigned long)total, + units[unitidx], unitidx? "iB" : ""); + return gpgsm_status2 (ctrl, STATUS_PROGRESS, "?", buffer, NULL); +} + + /* Helper to notify the client about Pinentry events. Because that might disturb some older clients, this is only done when enabled via an option. Returns an gpg error code. */ diff --git a/sm/sign.c b/sm/sign.c index b3b7e1883..4f5e8e3a0 100644 --- a/sm/sign.c +++ b/sm/sign.c @@ -687,6 +687,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, goto leave; } + gnupg_ksba_set_progress_cb (b64writer, gpgsm_progress_cb, ctrl); + err = ksba_cms_new (&cms); if (err) { @@ -1027,7 +1029,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, err = ksba_cms_build (cms, &stopreason); if (err) { - log_debug ("ksba_cms_build failed: %s\n", gpg_strerror (err)); + log_error ("creating CMS object failed: %s\n", gpg_strerror (err)); rc = err; goto leave; } diff --git a/sm/verify.c b/sm/verify.c index a07d1c9c7..9125b2b06 100644 --- a/sm/verify.c +++ b/sm/verify.c @@ -158,6 +158,8 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) } } + gnupg_ksba_set_progress_cb (b64writer, gpgsm_progress_cb, ctrl); + rc = ksba_cms_new (&cms); if (rc) goto leave; From a88aeee12990478c218abff7f38728e47ee824bc Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 15 Jun 2023 12:20:11 +0200 Subject: [PATCH 33/56] gpgsm: Fix last commit -- There was some test code left over and a check reversed. --- sm/server.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/sm/server.c b/sm/server.c index 455f5707a..1510590a7 100644 --- a/sm/server.c +++ b/sm/server.c @@ -1566,17 +1566,9 @@ gpgsm_progress_cb (ctrl_t ctrl, uint64_t current, uint64_t total) char units[] = "BKMGTPEZY?"; int unitidx = 0; - if (current > 1024*1024*20) - { - static int closed; - if (closed) - close (5); - closed = 1; - } - if (total) { - if (total > current) + if (current > total) current = total; while (total > 1024*1024) From e9c337c0b94b0db4c1bf8ce668477ff7675c0199 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 15 Jun 2023 12:28:55 +0200 Subject: [PATCH 34/56] gpgsm: New option --input-size-hint. * sm/gpgsm.c (oInputSizeHint): New. (opts): Add "--input-size-hint". (main): Set option. * sm/server.c (option_handler): Add option "input-size-hint". * sm/gpgsm.h (struct server_control_s): Add field input_size_hint. * sm/encrypt.c (gpgsm_encrypt): Set the toatl file size. * sm/decrypt.c (gpgsm_decrypt): Ditto. * sm/sign.c (gpgsm_sign): Ditto. * sm/verify.c (gpgsm_verify): Ditto. -- This option allows to set a value for the progress output line. Note that as of now there is no other way to set the file size. GnuPG-bug-id: 6534 --- doc/gpgsm.texi | 10 ++++++++++ sm/decrypt.c | 2 ++ sm/encrypt.c | 2 ++ sm/gpgsm.c | 6 ++++++ sm/gpgsm.h | 5 +++++ sm/server.c | 4 ++++ sm/sign.c | 2 ++ sm/verify.c | 2 ++ 8 files changed, 33 insertions(+) diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi index 11c5c1962..e976767f6 100644 --- a/doc/gpgsm.texi +++ b/doc/gpgsm.texi @@ -554,6 +554,13 @@ Assume the input data is plain base-64 encoded. @opindex assume-binary Assume the input data is binary encoded. +@item --input-size-hint @var{n} +@opindex input-size-hint +This option can be used to tell GPGSM the size of the input data in +bytes. @var{n} must be a positive base-10 number. It is used by the +@option{--status-fd} line ``PROGRESS'' to provide a value for +``total'' if that is not available by other means. + @anchor{option --p12-charset} @item --p12-charset @var{name} @opindex p12-charset @@ -1721,6 +1728,9 @@ If @var{value} is true or @var{value} is not given all network access is disabled for this session. This is the same as the command line option @option{--disable-dirmngr}. +@item input-size-hint +This is the same as the @option{--input-size-hint} command line option. + @end table @mansect see also diff --git a/sm/decrypt.c b/sm/decrypt.c index abc1f2602..62983fe9c 100644 --- a/sm/decrypt.c +++ b/sm/decrypt.c @@ -1108,6 +1108,8 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) } gnupg_ksba_set_progress_cb (b64writer, gpgsm_progress_cb, ctrl); + if (ctrl->input_size_hint) + gnupg_ksba_set_total (b64writer, ctrl->input_size_hint); rc = ksba_cms_new (&cms); if (rc) diff --git a/sm/encrypt.c b/sm/encrypt.c index b0e59f73e..6e78a0620 100644 --- a/sm/encrypt.c +++ b/sm/encrypt.c @@ -654,6 +654,8 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp) } gnupg_ksba_set_progress_cb (b64writer, gpgsm_progress_cb, ctrl); + if (ctrl->input_size_hint) + gnupg_ksba_set_total (b64writer, ctrl->input_size_hint); err = ksba_cms_new (&cms); if (err) diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 07c3ff480..ad7652c7d 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -139,6 +139,7 @@ enum cmd_and_opt_values { oAssumeArmor, oAssumeBase64, oAssumeBinary, + oInputSizeHint, oBase64, oNoArmor, @@ -326,6 +327,7 @@ static gpgrt_opt_t opts[] = { N_("assume input is in base-64 format")), ARGPARSE_s_n (oAssumeBinary, "assume-binary", N_("assume input is in binary format")), + ARGPARSE_s_s (oInputSizeHint, "input-size-hint", "@"), ARGPARSE_header ("Output", N_("Options controlling the output")), @@ -1188,6 +1190,10 @@ main ( int argc, char **argv) ctrl.is_base64 = 0; break; + case oInputSizeHint: + ctrl.input_size_hint = string_to_u64 (pargs.r.ret_str); + break; + case oDisableCRLChecks: opt.no_crl_check = 1; break; diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 46c77803d..e1aca8bb7 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -250,6 +250,11 @@ struct server_control_s int is_pem; /* Is in PEM format */ int is_base64; /* is in plain base-64 format */ + /* If > 0 a hint with the expected number of input data bytes. This + * is not necessary an exact number but intended to be used for + * progress info and to decide on how to allocate buffers. */ + uint64_t input_size_hint; + int create_base64; /* Create base64 encoded output */ int create_pem; /* create PEM output */ const char *pem_name; /* PEM name to use */ diff --git a/sm/server.c b/sm/server.c index 1510590a7..b545c1bfb 100644 --- a/sm/server.c +++ b/sm/server.c @@ -298,6 +298,10 @@ option_handler (assuan_context_t ctx, const char *key, const char *value) opt.request_origin = i; } } + else if (!strcmp (key, "input-size-hint")) + { + ctrl->input_size_hint = string_to_u64 (value); + } else err = gpg_error (GPG_ERR_UNKNOWN_OPTION); diff --git a/sm/sign.c b/sm/sign.c index 4f5e8e3a0..235dac8cb 100644 --- a/sm/sign.c +++ b/sm/sign.c @@ -688,6 +688,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, } gnupg_ksba_set_progress_cb (b64writer, gpgsm_progress_cb, ctrl); + if (ctrl->input_size_hint) + gnupg_ksba_set_total (b64writer, ctrl->input_size_hint); err = ksba_cms_new (&cms); if (err) diff --git a/sm/verify.c b/sm/verify.c index 9125b2b06..c7f4492ce 100644 --- a/sm/verify.c +++ b/sm/verify.c @@ -159,6 +159,8 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) } gnupg_ksba_set_progress_cb (b64writer, gpgsm_progress_cb, ctrl); + if (ctrl->input_size_hint) + gnupg_ksba_set_total (b64writer, ctrl->input_size_hint); rc = ksba_cms_new (&cms); if (rc) From 2178f35dffdc0d0129ad1da2e34ba243d7869378 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 15 Jun 2023 13:58:35 +0200 Subject: [PATCH 35/56] gpg: New option --no-compress as alias for -z0. --- doc/gpg.texi | 19 ++++++++++++------- g10/gpg.c | 7 +++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index 61f047cc7..15b3243d0 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -1675,24 +1675,29 @@ prevent the creation of a @file{~/.gnupg} homedir. @item -z @var{n} @itemx --compress-level @var{n} @itemx --bzip2-compress-level @var{n} +@itemx --no-compress @opindex compress-level @opindex bzip2-compress-level +@opindex no-compress Set compression level to @var{n} for the ZIP and ZLIB compression algorithms. The default is to use the default compression level of zlib (normally 6). @option{--bzip2-compress-level} sets the compression level for the BZIP2 compression algorithm (defaulting to 6 as well). This is a different option from @option{--compress-level} since BZIP2 uses a significant amount of memory for each additional compression level. -@option{-z} sets both. A value of 0 for @var{n} disables compression. -A value of -1 forces compression using the default level. + +Option @option{-z} sets both. A value of 0 for @var{n} disables +compression. A value of -1 forces compression using the default +level. Option @option{--no-compress} is identical to @option{-z0}. Except for the @option{--store} command compression is always used unless @command{gpg} detects that the input is already compressed. To -inhibit the use of compression use @option{-z0}; to force compression -use @option{-z-1} or option @option{z} with another compression level -than the default as indicated by -1. Note that this overriding of the -default deection works only with @option{z} and not with the long -variant of this option. +inhibit the use of compression use @option{-z0} or +@option{--no-compress}; to force compression use @option{-z-1} or +option @option{z} with another compression level than the default as +indicated by -1. Note that this overriding of the default deection +works only with @option{z} and not with the long variant of this +option. @item --bzip2-decompress-lowmem diff --git a/g10/gpg.c b/g10/gpg.c index 39776c3d1..2ae3750a9 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -259,6 +259,7 @@ enum cmd_and_opt_values oCipherAlgo, oDigestAlgo, oCertDigestAlgo, + oNoCompress, oCompressAlgo, oCompressLevel, oBZ2CompressLevel, @@ -697,6 +698,7 @@ static gpgrt_opt_t opts[] = { ARGPARSE_s_n (oLockOnce, "lock-once", "@"), ARGPARSE_s_n (oLockMultiple, "lock-multiple", "@"), ARGPARSE_s_n (oLockNever, "lock-never", "@"), + ARGPARSE_s_n (oNoCompress, "no-compress", "@"), ARGPARSE_s_s (oCompressAlgo,"compress-algo", "@"), ARGPARSE_s_s (oCompressAlgo, "compression-algo", "@"), /* Alias */ ARGPARSE_s_n (oBZ2DecompressLowmem, "bzip2-decompress-lowmem", "@"), @@ -3238,6 +3240,11 @@ main (int argc, char **argv) opt.compress_level = opt.bz2_compress_level = pargs.r.ret_int; opt.explicit_compress_option = 1; break; + case oNoCompress: + /* --no-compress is the same as -z0 */ + opt.compress_level = opt.bz2_compress_level = 0; + opt.explicit_compress_option = 1; + break; case oCompressLevel: opt.compress_level = pargs.r.ret_int; break; case oBZ2CompressLevel: opt.bz2_compress_level = pargs.r.ret_int; break; case oBZ2DecompressLowmem: opt.bz2_decompress_lowmem=1; break; From 3bab25d7d5197cd6178be653feb1182cd313ecbe Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 15 Jun 2023 13:52:18 +0200 Subject: [PATCH 36/56] gpgtar: New option --no-compress. * tools/gpgtar.c: Add option --no-compress. * tools/gpgtar.h (opt): Add field no_compress. * tools/gpgtar-create.c (gpgtar_create): Pass -z0 to gpg. -- This option is probably easier to remember than --gpg-args '-z0'. --- doc/tools.texi | 6 ++++++ tools/gpgtar-create.c | 2 ++ tools/gpgtar.c | 3 +++ tools/gpgtar.h | 1 + 4 files changed, 12 insertions(+) diff --git a/doc/tools.texi b/doc/tools.texi index 5fa21c66a..eefa4f9d6 100644 --- a/doc/tools.texi +++ b/doc/tools.texi @@ -2049,6 +2049,12 @@ default is to take the directory name from the input filename. If no input filename is known a directory named @file{GPGARCH} is used. This option is deprecated in favor of option @option{--directory}. +@item --no-compress +@opindex no-compress +This option tells gpg to disable compression (i.e. using option -z0). +It is useful for archiving only large files which are are already +compressed (e.g. a set of videos). + @item --gpg @var{gpgcmd} @opindex gpg Use the specified command @var{gpgcmd} instead of @command{gpg}. diff --git a/tools/gpgtar-create.c b/tools/gpgtar-create.c index 26d37a332..0994322ea 100644 --- a/tools/gpgtar-create.c +++ b/tools/gpgtar-create.c @@ -1273,6 +1273,8 @@ gpgtar_create (char **inpattern, const char *files_from, int null_names, ccparray_put (&ccp, "--recipient"); ccparray_put (&ccp, arg->d); } + if (opt.no_compress) + ccparray_put (&ccp, "-z0"); for (arg = opt.gpg_arguments; arg; arg = arg->next) ccparray_put (&ccp, arg->d); diff --git a/tools/gpgtar.c b/tools/gpgtar.c index 492b3d5e5..ea1e1e751 100644 --- a/tools/gpgtar.c +++ b/tools/gpgtar.c @@ -76,6 +76,7 @@ enum cmd_and_opt_values oSetFilename, oNull, oUtf8Strings, + oNoCompress, oBatch, oAnswerYes, @@ -121,6 +122,7 @@ static gpgrt_opt_t opts[] = { ARGPARSE_s_s (oSetFilename, "set-filename", "@"), ARGPARSE_s_n (oOpenPGP, "openpgp", "@"), ARGPARSE_s_n (oCMS, "cms", "@"), + ARGPARSE_s_n (oNoCompress, "no-compress", "@"), ARGPARSE_s_n (oBatch, "batch", "@"), ARGPARSE_s_n (oAnswerYes, "yes", "@"), @@ -350,6 +352,7 @@ parse_arguments (gpgrt_argparse_t *pargs, gpgrt_opt_t *popts) case oFilesFrom: files_from = pargs->r.ret_str; break; case oNull: null_names = 1; break; case oUtf8Strings: opt.utf8strings = 1; break; + case oNoCompress: opt.no_compress = 1; break; case aList: case aDecrypt: diff --git a/tools/gpgtar.h b/tools/gpgtar.h index 9177fcfcb..d86010476 100644 --- a/tools/gpgtar.h +++ b/tools/gpgtar.h @@ -33,6 +33,7 @@ struct int quiet; int dry_run; int utf8strings; + int no_compress; const char *gpg_program; strlist_t gpg_arguments; const char *outfile; From bf04b07327a5d2a7197df36daaa764b8ad5706e4 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 15 Jun 2023 15:00:28 +0200 Subject: [PATCH 37/56] dirmngr: New option --compatibility-flags. * dirmngr/dirmngr.c (oCompatibilityFlags): NEw. (opts): Add option --compatibility-flags. (compatibility_flags): New. (parse_rereadable_options): Parse them. --- dirmngr/dirmngr.c | 20 ++++++++++++++++++++ dirmngr/dirmngr.h | 15 +++++++++++++++ doc/dirmngr.texi | 8 ++++++++ 3 files changed, 43 insertions(+) diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index bb54f4edd..46521085f 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -159,6 +159,7 @@ enum cmd_and_opt_values { oConnectQuickTimeout, oListenBacklog, oFakeCRL, + oCompatibilityFlags, aTest }; @@ -297,6 +298,7 @@ static gpgrt_opt_t opts[] = { ARGPARSE_s_s (oSocketName, "socket-name", "@"), /* Only for debugging. */ ARGPARSE_s_n (oDebugCacheExpiredCerts, "debug-cache-expired-certs", "@"), + ARGPARSE_s_s (oCompatibilityFlags, "compatibility-flags", "@"), ARGPARSE_header (NULL, ""), /* Stop the header group. */ @@ -329,6 +331,14 @@ static struct debug_flags_s debug_flags [] = { 77, NULL } /* 77 := Do not exit on "help" or "?". */ }; +/* The list of compatibility flags. */ +static struct compatibility_flags_s compatibility_flags [] = + { + { COMPAT_RESTRICT_HTTP_REDIR, "restrict-http-redir" }, + { 0, NULL } + }; + + #define DEFAULT_MAX_REPLIES 10 #define DEFAULT_LDAP_TIMEOUT 15 /* seconds */ @@ -712,6 +722,7 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread) opt.debug_cache_expired_certs = 0; xfree (opt.fake_crl); opt.fake_crl = NULL; + opt.compat_flags = 0; return 1; } @@ -879,6 +890,15 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread) opt.fake_crl = *pargs->r.ret_str? xstrdup (pargs->r.ret_str) : NULL; break; + case oCompatibilityFlags: + if (parse_compatibility_flags (pargs->r.ret_str, &opt.compat_flags, + compatibility_flags)) + { + pargs->r_opt = ARGPARSE_INVALID_ARG; + pargs->err = ARGPARSE_PRINT_WARNING; + } + break; + default: return 0; /* Not handled. */ } diff --git a/dirmngr/dirmngr.h b/dirmngr/dirmngr.h index 1128e118b..5571d6181 100644 --- a/dirmngr/dirmngr.h +++ b/dirmngr/dirmngr.h @@ -154,6 +154,9 @@ struct current after nextUpdate. */ strlist_t keyserver; /* List of default keyservers. */ + + /* Compatibility flags (COMPAT_FLAG_xxxx). */ + unsigned int compat_flags; } opt; @@ -182,6 +185,18 @@ struct #define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE) #define DBG_KEEPTMP (opt.debug & DBG_KEEPTMP_VALUE) +/* Compatibility flags */ + +/* Since version 2.2.12 dirmngr restricted HTTP redirection in an + * attempt to mitigate certain CSRF attacks. It turned out that this + * breaks too many WKD deployments and that the attack scenario is not + * due to gnupg's redirecting but due to insecure configured systems. + * Thus from 2.4.3 on we disable this restriction but allow to use the + * old behaviour by using this compatibility flag. For details see + * https://dev.gnupg.org/T6477. */ +#define COMPAT_RESTRICT_HTTP_REDIR 1 + + /* A simple list of certificate references. FIXME: Better use certlist_t also for references (Store NULL at .cert) */ struct cert_ref_s diff --git a/doc/dirmngr.texi b/doc/dirmngr.texi index 8e0979c3e..f17c6206c 100644 --- a/doc/dirmngr.texi +++ b/doc/dirmngr.texi @@ -167,6 +167,14 @@ Append all logging output to @var{file}. This is very helpful in seeing what the agent actually does. Use @file{socket://} to log to socket. +@item --compatibility-flags @var{flags} +@opindex compatibility-flags +Set compatibility flags to work around certain problems or to emulate +bugs. The @var{flags} are given as a comma separated list of flag +names and are OR-ed together. The special flag "none" clears the list +and allows to start over with an empty list. To get a list of +available flags the sole word "help" can be used. + @item --debug-level @var{level} @opindex debug-level Select the debug level for investigating problems. @var{level} may be a From 0a63afc79a0466a0554870d5e8aa6c3d8a048b3d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 15 Jun 2023 15:06:21 +0200 Subject: [PATCH 38/56] dirmngr: Disable the HTTP redirect rewriting. * dirmngr/http.h (struct http_redir_info_s): Add restrict_redir. * dirmngr/ks-engine-hkp.c (send_request): Set it depending on flags. * dirmngr/ks-engine-http.c (ks_http_fetch): Ditto. * dirmngr/t-http-basic.c (test_http_prepare_redirect): Always set it. * dirmngr/http.c (http_prepare_redirect): Remove location rewriting unless the flag is set. -- GnuPG-bug-id: 6477 --- dirmngr/http.c | 9 +++++---- dirmngr/http.h | 1 + dirmngr/ks-engine-hkp.c | 5 +++-- dirmngr/ks-engine-http.c | 1 + dirmngr/t-http-basic.c | 1 + 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/dirmngr/http.c b/dirmngr/http.c index b4c501736..8153fcef4 100644 --- a/dirmngr/http.c +++ b/dirmngr/http.c @@ -3741,10 +3741,11 @@ http_prepare_redirect (http_redir_info_t *info, unsigned int status_code, http_release_parsed_uri (locuri); return err; } - else if (same_host_p (origuri, locuri)) + else if (!info->restrict_redir || same_host_p (origuri, locuri)) { - /* The host is the same or on an exception list and thus we can - * take the location verbatim. */ + /* Take the syntactically correct location or if restrict_redir + * is set the host is the same or on an exception list and thus + * we can take the location verbatim. */ http_release_parsed_uri (origuri); http_release_parsed_uri (locuri); newurl = xtrystrdup (location); @@ -3754,7 +3755,7 @@ http_prepare_redirect (http_redir_info_t *info, unsigned int status_code, return err; } } - else + else /* Strictly rectricted redirection which we used in the past. */ { /* We take only the host and port from the URL given in the * Location. This limits the effects of redirection attacks by diff --git a/dirmngr/http.h b/dirmngr/http.h index 18420c925..e60212761 100644 --- a/dirmngr/http.h +++ b/dirmngr/http.h @@ -117,6 +117,7 @@ struct http_redir_info_s unsigned int silent:1; /* No diagnostics. */ unsigned int allow_downgrade:1;/* Allow a downgrade from https to http. */ unsigned int trust_location:1; /* Trust the received Location header. */ + unsigned int restrict_redir:1; /* Use legacy restricted redirection. */ }; typedef struct http_redir_info_s http_redir_info_t; diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index 5292da844..66291bc02 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -1242,8 +1242,9 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr, redirinfo.orig_url = request; redirinfo.orig_onion = uri->onion; redirinfo.allow_downgrade = 1; - /* FIXME: I am not sure whey we allow a downgrade for hkp requests. - * Needs at least an explanation here.. */ + /* FIXME: I am not sure why we allow a downgrade for hkp requests. + * Needs at least an explanation here. */ + redirinfo.restrict_redir = !!(opt.compat_flags & COMPAT_RESTRICT_HTTP_REDIR); once_more: err = http_session_new (&session, httphost, diff --git a/dirmngr/ks-engine-http.c b/dirmngr/ks-engine-http.c index f55a25774..3dca80ee6 100644 --- a/dirmngr/ks-engine-http.c +++ b/dirmngr/ks-engine-http.c @@ -88,6 +88,7 @@ ks_http_fetch (ctrl_t ctrl, const char *url, unsigned int flags, redirinfo.orig_onion = uri->onion; redirinfo.orig_https = uri->use_tls; redirinfo.allow_downgrade = !!(flags & KS_HTTP_FETCH_ALLOW_DOWNGRADE); + redirinfo.restrict_redir = !!(opt.compat_flags & COMPAT_RESTRICT_HTTP_REDIR); /* By default we only use the system provided certificates with this * fetch command. */ diff --git a/dirmngr/t-http-basic.c b/dirmngr/t-http-basic.c index edf82efb9..ba3d07a8c 100644 --- a/dirmngr/t-http-basic.c +++ b/dirmngr/t-http-basic.c @@ -165,6 +165,7 @@ test_http_prepare_redirect (void) ri.silent = 1; ri.redirects_left = 1; ri.orig_url = tests[tidx].url; + ri.restrict_redir = 1; /* This is what we used to test here. */ err = http_prepare_redirect (&ri, 301, tests[tidx].location, &newurl); if (err && newurl) From 701a8b30f0be24552772fc2818ad07402eb14478 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 19 Jun 2023 14:05:22 +0200 Subject: [PATCH 39/56] gpgsm: Support SENDCERT_SKI for --call-dirmngr * sm/call-dirmngr.c (run_command_inq_cb): Support SENDCERT_SKI. * dirmngr/crlcache.c (crl_cache_insert): Print the CRL name along with the unknown OID nortice. --- dirmngr/crlcache.c | 1 + sm/call-dirmngr.c | 45 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/dirmngr/crlcache.c b/dirmngr/crlcache.c index 9f0b910f3..64f4de97f 100644 --- a/dirmngr/crlcache.c +++ b/dirmngr/crlcache.c @@ -2361,6 +2361,7 @@ crl_cache_insert (ctrl_t ctrl, const char *url, ksba_reader_t reader) || !strcmp (oid, oidstr_crlNumber) ) continue; log_error (_("unknown critical CRL extension %s\n"), oid); + log_info ("(CRL='%s')\n", url); if (!err2) err2 = gpg_error (GPG_ERR_INV_CRL); invalidate_crl |= INVCRL_UNKNOWN_EXTN; diff --git a/sm/call-dirmngr.c b/sm/call-dirmngr.c index 86beeedc1..7fe7a68f5 100644 --- a/sm/call-dirmngr.c +++ b/sm/call-dirmngr.c @@ -1001,16 +1001,17 @@ static gpg_error_t run_command_inq_cb (void *opaque, const char *line) { struct run_command_parm_s *parm = opaque; + gpg_error_t err; const char *s; int rc = 0; + ksba_cert_t cert = NULL; + ksba_sexp_t ski = NULL; + const unsigned char *der; + size_t derlen, n; if ((s = has_leading_keyword (line, "SENDCERT"))) - { /* send the given certificate */ - int err; - ksba_cert_t cert; - const unsigned char *der; - size_t derlen; - + { + /* Send the given certificate. */ line = s; if (!*line) return gpg_error (GPG_ERR_ASS_PARAMETER); @@ -1029,11 +1030,36 @@ run_command_inq_cb (void *opaque, const char *line) rc = gpg_error (GPG_ERR_INV_CERT_OBJ); else rc = assuan_send_data (parm->ctx, der, derlen); - ksba_cert_release (cert); + } + } + else if ((s = has_leading_keyword (line, "SENDCERT_SKI"))) + { + /* Send a certificate where a sourceKeyIdentifier is included. */ + line = s; + ski = make_simple_sexp_from_hexstr (line, &n); + line += n; + while (*line == ' ') + line++; + + err = gpgsm_find_cert (parm->ctrl, line, ski, &cert, + FIND_CERT_ALLOW_AMBIG|FIND_CERT_WITH_EPHEM); + if (err) + { + log_error ("certificate not found: %s\n", gpg_strerror (err)); + rc = gpg_error (GPG_ERR_NOT_FOUND); + } + else + { + der = ksba_cert_get_image (cert, &derlen); + if (!der) + rc = gpg_error (GPG_ERR_INV_CERT_OBJ); + else + rc = assuan_send_data (parm->ctx, der, derlen); } } else if ((s = has_leading_keyword (line, "PRINTINFO"))) - { /* Simply show the message given in the argument. */ + { + /* Simply show the message given in the argument. */ line = s; log_info ("dirmngr: %s\n", line); } @@ -1043,7 +1069,6 @@ run_command_inq_cb (void *opaque, const char *line) root certificate. */ char fpr[41]; struct rootca_flags_s rootca_flags; - int n; line = s; @@ -1067,6 +1092,8 @@ run_command_inq_cb (void *opaque, const char *line) rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE); } + ksba_cert_release (cert); + xfree (ski); return rc; } From b1ecc8353ae37e48b586a315a228bce964253ffe Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 19 Jun 2023 14:25:47 +0200 Subject: [PATCH 40/56] dirmngr: New option --ignore-crl-extensions. * dirmngr/dirmngr.c (oIgnoreCRLExtension): New. (opts): Add --ignore-crl-extension. (parse_rereadable_options): Add to list/ * dirmngr/dirmngr.h (opt): Add ignored_crl_extensions. * dirmngr/crlcache.c (crl_cache_insert): Implement option. -- This option is is useful for debugging problems with new CRL extensions. It is similar to --ignore-cert-extension. GnuPG-bug-id: 6545 --- dirmngr/crlcache.c | 9 +++++++++ dirmngr/dirmngr.c | 7 +++++++ dirmngr/dirmngr.h | 5 +++++ doc/dirmngr.texi | 9 +++++++++ 4 files changed, 30 insertions(+) diff --git a/dirmngr/crlcache.c b/dirmngr/crlcache.c index 64f4de97f..ac673a8d5 100644 --- a/dirmngr/crlcache.c +++ b/dirmngr/crlcache.c @@ -2356,10 +2356,19 @@ crl_cache_insert (ctrl_t ctrl, const char *url, ksba_reader_t reader) for (idx=0; !(err=ksba_crl_get_extension (crl, idx, &oid, &critical, NULL, NULL)); idx++) { + strlist_t sl; + if (!critical || !strcmp (oid, oidstr_authorityKeyIdentifier) || !strcmp (oid, oidstr_crlNumber) ) continue; + + for (sl=opt.ignored_crl_extensions; + sl && strcmp (sl->d, oid); sl = sl->next) + ; + if (sl) + continue; /* Is in ignored list. */ + log_error (_("unknown critical CRL extension %s\n"), oid); log_info ("(CRL='%s')\n", url); if (!err2) diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index 46521085f..b460ed3b3 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -147,6 +147,7 @@ enum cmd_and_opt_values { oHTTPWrapperProgram, oIgnoreCert, oIgnoreCertExtension, + oIgnoreCRLExtension, oUseTor, oNoUseTor, oKeyServer, @@ -224,6 +225,7 @@ static gpgrt_opt_t opts[] = { ARGPARSE_s_n (oDisableCheckOwnSocket, "disable-check-own-socket", "@"), ARGPARSE_s_s (oIgnoreCert,"ignore-cert", "@"), ARGPARSE_s_s (oIgnoreCertExtension,"ignore-cert-extension", "@"), + ARGPARSE_s_s (oIgnoreCRLExtension,"ignore-crl-extension", "@"), ARGPARSE_header ("Network", N_("Network related options")), @@ -706,6 +708,7 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread) opt.ignored_certs = tmp; } FREE_STRLIST (opt.ignored_cert_extensions); + FREE_STRLIST (opt.ignored_crl_extensions); http_register_tls_ca (NULL); FREE_STRLIST (hkp_cacert_filenames); FREE_STRLIST (opt.keyserver); @@ -819,6 +822,10 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread) add_to_strlist (&opt.ignored_cert_extensions, pargs->r.ret_str); break; + case oIgnoreCRLExtension: + add_to_strlist (&opt.ignored_crl_extensions, pargs->r.ret_str); + break; + case oUseTor: tor_mode = TOR_MODE_FORCE; break; diff --git a/dirmngr/dirmngr.h b/dirmngr/dirmngr.h index 5571d6181..50c97f140 100644 --- a/dirmngr/dirmngr.h +++ b/dirmngr/dirmngr.h @@ -132,6 +132,11 @@ struct OID per string. */ strlist_t ignored_cert_extensions; + /* A list of CRL extension OIDs which are ignored so that one can + * claim that a critical extension has been handled. One OID per + * string. */ + strlist_t ignored_crl_extensions; + /* Allow expired certificates in the cache. */ int debug_cache_expired_certs; diff --git a/doc/dirmngr.texi b/doc/dirmngr.texi index f17c6206c..0bf35b72f 100644 --- a/doc/dirmngr.texi +++ b/doc/dirmngr.texi @@ -598,6 +598,15 @@ won't be rejected due to an unknown critical extension. Use this option with care because extensions are usually flagged as critical for a reason. +@item --ignore-crl-extension @var{oid} +@opindex ignore-crl-extension +Add @var{oid} to the list of ignored CRL extensions. The @var{oid} is +expected to be in dotted decimal form. Critical flagged CRL +extensions matching one of the OIDs in the list are treated as if they +are actually handled and thus the certificate won't be rejected due to +an unknown critical extension. Use this option with care because +extensions are usually flagged as critical for a reason. + @item --ignore-cert @var{fpr}|@var{file} @opindex ignore-cert Entirely ignore certificates with the fingerprint @var{fpr}. As an From 40090dbbf9ead365cb9350828da8b5ebad426f5e Mon Sep 17 00:00:00 2001 From: zhangguangzhi Date: Thu, 11 May 2023 16:34:23 +0800 Subject: [PATCH 41/56] delete redundant characters -- GnuPG-bug-id: 6482 Signed-off-by: zhangguangzhi --- README | 2 +- dirmngr/ChangeLog-2011 | 2 +- g10/ChangeLog-2011 | 2 +- tools/gpg-card.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index 84a8bacfd..c7887fc0f 100644 --- a/README +++ b/README @@ -170,7 +170,7 @@ * DOCUMENTATION The complete documentation is in the texinfo manual named - `gnupg.info'. Run "info gnupg" to read it. If you want a a + `gnupg.info'. Run "info gnupg" to read it. If you want a printable copy of the manual, change to the "doc" directory and enter "make pdf" For a HTML version enter "make html" and point your browser to gnupg.html/index.html. Standard man pages for all diff --git a/dirmngr/ChangeLog-2011 b/dirmngr/ChangeLog-2011 index 243f2b56f..30e026ff8 100644 --- a/dirmngr/ChangeLog-2011 +++ b/dirmngr/ChangeLog-2011 @@ -1373,7 +1373,7 @@ truncated search. * ldap.c (add_server_to_servers): Reactivated. (url_fetch_ldap): Call it here and try all configured servers in - case of a a failed lookup. + case of a failed lookup. (fetch_next_cert_ldap): Detect the truncation error flag. * misc.c (host_and_port_from_url, remove_percent_escapes): New. diff --git a/g10/ChangeLog-2011 b/g10/ChangeLog-2011 index 37da37bf5..4737b1fa1 100644 --- a/g10/ChangeLog-2011 +++ b/g10/ChangeLog-2011 @@ -4798,7 +4798,7 @@ * g10.c (main): Try to create the trustdb even for non-colon-mode list-key operations. This is required because getkey needs to - know whether a a key is ultimately trusted. From Werner on stable + know whether a key is ultimately trusted. From Werner on stable branch. * exec.c [__CYGWIN32__]: Keep cygwin separate from Mingw32; diff --git a/tools/gpg-card.c b/tools/gpg-card.c index a94aabea9..290ed485d 100644 --- a/tools/gpg-card.c +++ b/tools/gpg-card.c @@ -2822,7 +2822,7 @@ cmd_passwd (card_info_t info, char *argstr) log_assert (DIM (info->chvinfo) >= 4); - /* If there is a qualified signature use a a menu to select + /* If there is a qualified signature use a menu to select * between standard PIN and QES PINs. */ if (info->chvinfo[2] != -2 || info->chvinfo[3] != -2) { From 06aeb2b45c606d948d84d47402c1c8402a33b584 Mon Sep 17 00:00:00 2001 From: zhangguangzhi Date: Thu, 18 May 2023 20:24:41 +0800 Subject: [PATCH 42/56] kbx: Close file handle when return. * kbx/keybox-dump.c (_keybox_dump_find_dups): Close FP on the error paths. -- GnuPG-bug-id: 6495 Signed-off-by: zhangguangzhi --- kbx/keybox-dump.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kbx/keybox-dump.c b/kbx/keybox-dump.c index 38608ceaa..bad664721 100644 --- a/kbx/keybox-dump.c +++ b/kbx/keybox-dump.c @@ -810,6 +810,8 @@ _keybox_dump_find_dups (const char *filename, int print_them, FILE *outfp) gpg_error_t tmperr = gpg_error_from_syserror (); fprintf (outfp, "error allocating array for '%s': %s\n", filename, strerror(errno)); + if (fp != es_stdin) + es_fclose (fp); return tmperr; } dupitems_count = 0; @@ -834,6 +836,8 @@ _keybox_dump_find_dups (const char *filename, int print_them, FILE *outfp) fprintf (outfp, "error reallocating array for '%s': %s\n", filename, strerror(errno)); free (dupitems); + if (fp != es_stdin) + es_fclose (fp); return tmperr; } dupitems = tmp; From 2c7f7a5a278ce669246b4d2dce3361f505d46ba6 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 21 Jun 2023 11:33:41 +0200 Subject: [PATCH 43/56] wks: Use export-clean for --mirror and --create. * tools/wks-util.c (wks_get_key): Change from export-minimal to export-clean -- To properly work with tusted introducers et al. it is important to also upload valid key signatures to the Web Key Directory. --- tools/wks-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/wks-util.c b/tools/wks-util.c index 0aeb94b1d..ee1305b00 100644 --- a/tools/wks-util.c +++ b/tools/wks-util.c @@ -246,7 +246,7 @@ wks_get_key (estream_t *r_key, const char *fingerprint, const char *addrspec, ccparray_put (&ccp, "--always-trust"); if (!binary) ccparray_put (&ccp, "--armor"); - ccparray_put (&ccp, "--export-options=export-minimal"); + ccparray_put (&ccp, "--export-options=export-clean"); ccparray_put (&ccp, "--export-filter"); ccparray_put (&ccp, filterexp); ccparray_put (&ccp, "--export"); From 10c937ee68cbf784942630115449f32cd82089fe Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 21 Jun 2023 11:34:58 +0200 Subject: [PATCH 44/56] wks: Make --add-revocs the default. * tools/gpg-wks-client.c (opt): New option --no-add-revocs. (main): Make --add-revocs the default. (command_send): Rename to ... (command_create): to match the command name. --- doc/wks.texi | 4 +++- tools/gpg-wks-client.c | 13 ++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/doc/wks.texi b/doc/wks.texi index 39e345f15..26d8b96f6 100644 --- a/doc/wks.texi +++ b/doc/wks.texi @@ -216,12 +216,14 @@ addrspec, e.g. "postel@@isi.edu") per line. Empty lines and lines starting with a '#' are ignored. @item --add-revocs +@itemx --no-add-revocs @opindex add-revocs +@opindex no-add-revocs If enabled append revocation certificates for the same addrspec as used in the WKD to the key. Modern gpg version are able to import and apply them for existing keys. Note that when used with the @option{--mirror} command the revocation are searched in the local -keyring and not in an LDAP directory. +keyring and not in an LDAP directory. The default is @option{--add-revocs}. @item --verbose @opindex verbose diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c index 521222631..fa0278ae0 100644 --- a/tools/gpg-wks-client.c +++ b/tools/gpg-wks-client.c @@ -77,6 +77,7 @@ enum cmd_and_opt_values oBlacklist, oNoAutostart, oAddRevocs, + oNoAddRevocs, oDummy }; @@ -121,6 +122,7 @@ static gpgrt_opt_t opts[] = { ARGPARSE_s_s (oBlacklist, "blacklist", "@"), ARGPARSE_s_s (oDirectory, "directory", "@"), ARGPARSE_s_n (oAddRevocs, "add-revocs", "add revocation certificates"), + ARGPARSE_s_n (oNoAddRevocs, "no-add-revocs", "do not add revocation certificates"), ARGPARSE_s_s (oFakeSubmissionAddr, "fake-submission-addr", "@"), @@ -158,7 +160,7 @@ static gpg_error_t proc_userid_from_stdin (gpg_error_t (*func)(const char *), const char *text); static gpg_error_t command_supported (char *userid); static gpg_error_t command_check (char *userid); -static gpg_error_t command_send (const char *fingerprint, const char *userid); +static gpg_error_t command_create (const char *fingerprint, const char *userid); static gpg_error_t encrypt_response (estream_t *r_output, estream_t input, const char *addrspec, const char *fingerprint); @@ -262,6 +264,9 @@ parse_arguments (gpgrt_argparse_t *pargs, gpgrt_opt_t *popts) case oAddRevocs: opt.add_revocs = 1; break; + case oNoAddRevocs: + opt.add_revocs = 0; + break; case aSupported: case aCreate: @@ -304,6 +309,8 @@ main (int argc, char **argv) assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT); setup_libassuan_logging (&opt.debug, NULL); + opt.add_revocs = 1; /* Default add revocation certs. */ + /* Parse the command line. */ pargs.argc = &argc; pargs.argv = &argv; @@ -397,7 +404,7 @@ main (int argc, char **argv) case aCreate: if (argc != 2) wrong_args ("--create FINGERPRINT USER-ID"); - err = command_send (argv[0], argv[1]); + err = command_create (argv[0], argv[1]); if (err) log_error ("creating request failed: %s\n", gpg_strerror (err)); break; @@ -1153,7 +1160,7 @@ command_check (char *userid) /* Locate the key by fingerprint and userid and send a publication * request. */ static gpg_error_t -command_send (const char *fingerprint, const char *userid) +command_create (const char *fingerprint, const char *userid) { gpg_error_t err; KEYDB_SEARCH_DESC desc; From 25b59cf6ce86dcd50845cdd2e1cf0645531e7a46 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 27 Jun 2023 15:43:35 +0900 Subject: [PATCH 45/56] scd:piv: Fix authentication with Administration Key. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * scd/app-piv.c (auth_adm_key): Fix the value of the Response Tag. (do_setattr): Fix the comment. -- Cherry-pick master commit of: 7cfbf0dd72d8d5c14fbf19c13722d153bd1cbd70 Reported-by: Heiko Schäfer Signed-off-by: NIIBE Yutaka --- scd/app-piv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scd/app-piv.c b/scd/app-piv.c index a51ac31ec..c8ef7b43a 100644 --- a/scd/app-piv.c +++ b/scd/app-piv.c @@ -928,7 +928,7 @@ auth_adm_key (app_t app, const unsigned char *value, size_t valuelen) tmpl[12] = 0x81; tmpl[13] = 8; gcry_create_nonce (tmpl+14, 8); - tmpl[22] = 0x80; + tmpl[22] = 0x82; tmpl[23] = 0; tmpllen = 24; xfree (outdata); @@ -1039,7 +1039,7 @@ do_setattr (app_t app, ctrl_t ctrl, const char *name, int special; /* Special mode to use for thus NAME. */ } table[] = { /* Authenticate using the PIV Card Application Administration Key - * (0x0B). Note that Yubico calls this key the "management key" + * (0x9B). Note that Yubico calls this key the "management key" * which we don't do because that term is too similar to "Cert * Management Key" (0x9D). */ { "AUTH-ADM-KEY", 0x0000, 0x0000, 1 }, From c926967d8558df114e14ba40595093d522d049a9 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 22 Jun 2023 18:42:55 +0200 Subject: [PATCH 46/56] sm: Remove duplicated code. * sm/minip12.c (struct tag_info): Change type of length and nhdr. (dump_tag_info): Adjust. (parse_tag): Re-implement using the parse_ber_header. --- common/tlv.c | 9 +++-- sm/minip12.c | 109 +++++++++++++-------------------------------------- 2 files changed, 34 insertions(+), 84 deletions(-) diff --git a/common/tlv.c b/common/tlv.c index 4cc1dc7cf..4ba9ef20d 100644 --- a/common/tlv.c +++ b/common/tlv.c @@ -150,13 +150,16 @@ find_tlv_unchecked (const unsigned char *buffer, size_t length, /* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag - and the length part from the TLV triplet. Update BUFFER and SIZE - on success. */ + * and the length part from the TLV triplet. Update BUFFER and SIZE + * on success. Note that this function does not check that the value + * fits into the provided buffer; this allows to work on the TL part + * of a TLV. */ gpg_error_t parse_ber_header (unsigned char const **buffer, size_t *size, int *r_class, int *r_tag, int *r_constructed, int *r_ndef, - size_t *r_length, size_t *r_nhdr){ + size_t *r_length, size_t *r_nhdr) +{ int c; unsigned long tag; const unsigned char *buf = *buffer; diff --git a/sm/minip12.c b/sm/minip12.c index 29b48984e..695c60ff1 100644 --- a/sm/minip12.c +++ b/sm/minip12.c @@ -138,8 +138,8 @@ struct tag_info int class; int is_constructed; unsigned long tag; - unsigned long length; /* length part of the TLV */ - int nhdr; + size_t length; /* length part of the TLV */ + size_t nhdr; int ndef; /* It is an indefinite length */ }; @@ -174,14 +174,17 @@ p12_set_verbosity (int verbose) } -/* static void */ -/* dump_tag_info (struct tag_info *ti) */ -/* { */ -/* log_debug ("p12_parse: ti.class=%d tag=%lu len=%lu nhdr=%d %s%s\n", */ -/* ti->class, ti->tag, ti->length, ti->nhdr, */ -/* ti->is_constructed?" cons":"", */ -/* ti->ndef?" ndef":""); */ -/* } */ +#if 0 +static void +dump_tag_info (const char *text, struct tag_info *ti) +{ + log_debug ("p12_parse(%s): ti.class=%d tag=%lu len=%zu nhdr=%zu %s%s\n", + text, + ti->class, ti->tag, ti->length, ti->nhdr, + ti->is_constructed?" cons":"", + ti->ndef?" ndef":""); +} +#endif /* Wrapper around tlv_builder_add_ptr to add an OID. When we @@ -277,84 +280,28 @@ builder_add_mpi (tlv_builder_t tb, int class, int tag, gcry_mpi_t mpi, /* Parse the buffer at the address BUFFER which is of SIZE and return - the tag and the length part from the TLV triplet. Update BUFFER - and SIZE on success. Checks that the encoded length does not - exhaust the length of the provided buffer. */ + * the tag and the length part from the TLV triplet. Update BUFFER + * and SIZE on success. Checks that the encoded length does not + * exhaust the length of the provided buffer. */ static int parse_tag (unsigned char const **buffer, size_t *size, struct tag_info *ti) { - int c; - unsigned long tag; - const unsigned char *buf = *buffer; - size_t length = *size; + gpg_error_t err; + int tag; - ti->length = 0; - ti->ndef = 0; - ti->nhdr = 0; - - /* Get the tag */ - if (!length) - return -1; /* premature eof */ - c = *buf++; length--; - ti->nhdr++; - - ti->class = (c & 0xc0) >> 6; - ti->is_constructed = !!(c & 0x20); - tag = c & 0x1f; - - if (tag == 0x1f) - { - tag = 0; - do - { - tag <<= 7; - if (!length) - return -1; /* premature eof */ - c = *buf++; length--; - ti->nhdr++; - tag |= c & 0x7f; - } - while (c & 0x80); - } + err = parse_ber_header (buffer, size, + &ti->class, &tag, + &ti->is_constructed, &ti->ndef, + &ti->length, &ti->nhdr); + if (err) + return err; + if (tag < 0) + return gpg_error (GPG_ERR_EOVERFLOW); ti->tag = tag; - /* Get the length */ - if (!length) - return -1; /* prematureeof */ - c = *buf++; length--; - ti->nhdr++; + if (ti->length > *size) + return gpg_error (GPG_ERR_BUFFER_TOO_SHORT); /* data larger than buffer. */ - if ( !(c & 0x80) ) - ti->length = c; - else if (c == 0x80) - ti->ndef = 1; - else if (c == 0xff) - return -1; /* forbidden length value */ - else - { - unsigned long len = 0; - int count = c & 0x7f; - - for (; count; count--) - { - len <<= 8; - if (!length) - return -1; /* premature_eof */ - c = *buf++; length--; - ti->nhdr++; - len |= c & 0xff; - } - ti->length = len; - } - - if (ti->class == CLASS_UNIVERSAL && !ti->tag) - ti->length = 0; - - if (ti->length > length) - return -1; /* data larger than buffer. */ - - *buffer = buf; - *size = length; return 0; } From 101433dfb42b333e48427baf9dd58ac4787c9786 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 28 Jun 2023 17:33:24 +0200 Subject: [PATCH 47/56] sm: Major rewrite of the PKCS#12 parser * sm/minip12.c: Reworked most of the parser. (p12_set_verbosity): Add arg debug and change all callers. * sm/t-minip12.c: Major rewrite to run regression tests unattended. * sm/Makefile.am (module_maint_tests): Move t-Minit to ... (module_tests): here. * tests/cms/samplekeys/Description-p12: New. -- Note that cram_octet_string stuff has not yet been reworked. I need to locate the sample files first. GnuPG-bug-id: 6536 --- sm/Makefile.am | 4 +- sm/gpgsm.c | 2 +- sm/minip12.c | 2043 ++++++++++++++++---------- sm/minip12.h | 2 +- sm/t-minip12.c | 742 +++++++++- tests/cms/samplekeys/Description-p12 | 20 + tests/cms/samplekeys/README | 8 +- 7 files changed, 1951 insertions(+), 870 deletions(-) create mode 100644 tests/cms/samplekeys/Description-p12 diff --git a/sm/Makefile.am b/sm/Makefile.am index 03de7026a..ee728e851 100644 --- a/sm/Makefile.am +++ b/sm/Makefile.am @@ -77,8 +77,8 @@ gpgsm_LDFLAGS = gpgsm_DEPENDENCIES = $(resource_objs) -module_tests = -module_maint_tests = t-minip12 +module_tests = t-minip12 +module_maint_tests = t_common_src = t_common_ldadd = $(libcommon) $(LIBGCRYPT_LIBS) $(KSBA_LIBS) \ diff --git a/sm/gpgsm.c b/sm/gpgsm.c index ad7652c7d..ce977413d 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -804,7 +804,7 @@ set_debug (void) /* minip12.c may be used outside of GnuPG, thus we don't have the * opt structure over there. */ - p12_set_verbosity (opt.verbose); + p12_set_verbosity (opt.verbose, opt.debug); } diff --git a/sm/minip12.c b/sm/minip12.c index 695c60ff1..69e23455a 100644 --- a/sm/minip12.c +++ b/sm/minip12.c @@ -1,7 +1,7 @@ /* minip12.c - A minimal pkcs-12 implementation. * Copyright (C) 2002, 2003, 2004, 2006, 2011 Free Software Foundation, Inc. * Copyright (C) 2014 Werner Koch - * Copyright (C) 2022 g10 Code GmbH + * Copyright (C) 2022, 2023 g10 Code GmbH * * This file is part of GnuPG. * @@ -78,6 +78,8 @@ static unsigned char const oid_pkcs5PBES2[9] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0D }; static unsigned char const oid_aes128_CBC[9] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02 }; +static unsigned char const oid_aes256_CBC[9] = { + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2A }; static unsigned char const oid_rsaEncryption[9] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 }; @@ -143,6 +145,35 @@ struct tag_info int ndef; /* It is an indefinite length */ }; + +#define TLV_MAX_DEPTH 20 + +/* An object to control the ASN.1 parsing. */ +struct tlv_ctx_s +{ + /* The current buffer we are working on and its length. */ + const unsigned char *buffer; + size_t bufsize; + + size_t offset; /* The current offset into this buffer. */ + int in_ndef; /* Flag indicating that we are in a NDEF. */ + int pending; /* The last tlv_next has not yet been processed. */ + + struct tag_info ti; /* The current tag. */ + gpg_error_t lasterr; /* Last error from tlv function. */ + const char *lastfunc;/* Name of last called function. */ + + unsigned int pop_count;/* Number of pops by tlv_next. */ + unsigned int stacklen; /* Used size of the stack. */ + struct { + const unsigned char *buffer; /* Saved value of BUFFER. */ + size_t bufsize; /* Saved value of BUFSIZE. */ + size_t offset; /* Saved value of OFFSET. */ + int in_ndef; /* Saved IN_NDEF flag. */ + } stack[TLV_MAX_DEPTH]; +}; + + /* Parser communication object. */ struct p12_parse_ctx_s { @@ -168,23 +199,24 @@ static int opt_verbose; void -p12_set_verbosity (int verbose) +p12_set_verbosity (int verbose, int debug) { - opt_verbose = verbose; + opt_verbose = !!verbose; + if (debug) + opt_verbose = 2; } -#if 0 static void dump_tag_info (const char *text, struct tag_info *ti) { - log_debug ("p12_parse(%s): ti.class=%d tag=%lu len=%zu nhdr=%zu %s%s\n", - text, - ti->class, ti->tag, ti->length, ti->nhdr, - ti->is_constructed?" cons":"", - ti->ndef?" ndef":""); + if (opt_verbose > 1) + log_debug ("p12_parse(%s): ti.class=%d tag=%lu len=%zu nhdr=%zu %s%s\n", + text, + ti->class, ti->tag, ti->length, ti->nhdr, + ti->is_constructed?" cons":"", + ti->ndef?" ndef":""); } -#endif /* Wrapper around tlv_builder_add_ptr to add an OID. When we @@ -279,6 +311,7 @@ builder_add_mpi (tlv_builder_t tb, int class, int tag, gcry_mpi_t mpi, } + /* Parse the buffer at the address BUFFER which is of SIZE and return * the tag and the length part from the TLV triplet. Update BUFFER * and SIZE on success. Checks that the encoded length does not @@ -306,6 +339,382 @@ parse_tag (unsigned char const **buffer, size_t *size, struct tag_info *ti) } +/* Create a new TLV object. */ +static struct tlv_ctx_s * +tlv_new (const unsigned char *buffer, size_t bufsize) +{ + struct tlv_ctx_s *tlv; + tlv = xtrycalloc (1, sizeof *tlv); + if (tlv) + { + tlv->buffer = buffer; + tlv->bufsize = bufsize; + } + return tlv; +} + + +static void +tlv_release (struct tlv_ctx_s *tlv) +{ + xfree (tlv); +} + + +/* Helper for tlv_next and tlv_peek. */ +static gpg_error_t +_tlv_peek (struct tlv_ctx_s *tlv, size_t *r_n) +{ + const unsigned char *p; + + if (tlv->offset > tlv->bufsize) + return gpg_error (GPG_ERR_BUG); + p = tlv->buffer + tlv->offset; + *r_n = tlv->bufsize - tlv->offset; + return parse_tag (&p, r_n, &tlv->ti); +} + + +/* Helper for tlv_expect_sequence and tlv_expect_context_tag. */ +static gpg_error_t +_tlv_push (struct tlv_ctx_s *tlv) +{ + if (tlv->stacklen >= TLV_MAX_DEPTH) + return (tlv->lasterr = gpg_error (GPG_ERR_TOO_MANY)); + tlv->stack[tlv->stacklen].buffer = tlv->buffer; + tlv->stack[tlv->stacklen].bufsize = tlv->bufsize; + tlv->stack[tlv->stacklen].offset = tlv->offset; + tlv->stack[tlv->stacklen].in_ndef = tlv->in_ndef; + tlv->stacklen++; + tlv->buffer += tlv->offset; + tlv->bufsize = tlv->ti.length; + tlv->offset = 0; + tlv->in_ndef = tlv->ti.ndef; + return 0; +} + + +/* Helper for tlv_next. */ +static gpg_error_t +_tlv_pop (struct tlv_ctx_s *tlv) +{ + size_t saveoff; + + if (!tlv->stacklen) + return gpg_error (GPG_ERR_EOF); + + saveoff = tlv->offset; + + tlv->stacklen--; + tlv->buffer = tlv->stack[tlv->stacklen].buffer; + tlv->bufsize = tlv->stack[tlv->stacklen].bufsize; + tlv->offset = tlv->stack[tlv->stacklen].offset; + tlv->in_ndef = tlv->stack[tlv->stacklen].in_ndef; + + /* Move offset of the container to the end of the container. */ + tlv->offset += saveoff; + if (tlv->offset > tlv->bufsize) + return gpg_error (GPG_ERR_INV_BER); + + tlv->pop_count++; + return 0; +} + + +/* Parse the next tag and value. Also detect the end of a container; + * tlv_popped() can be used to detect this. */ +static gpg_error_t +tlv_next (struct tlv_ctx_s *tlv) +{ + gpg_error_t err; + size_t n; + + tlv->pop_count = 0; + tlv->lasterr = 0; + tlv->lastfunc = __func__; + if (tlv->pending) + { + tlv->pending = 0; + return 0; + } + + if (!tlv->in_ndef && tlv->offset == tlv->bufsize) + { + /* We are at the end of a container. Pop the stack. */ + do + err = _tlv_pop (tlv); + while (!err && !tlv->in_ndef && tlv->offset == tlv->bufsize); + if (err) + return (tlv->lasterr = err); + } + + err = _tlv_peek (tlv, &n); + if (err) + return err; + if (tlv->in_ndef && (tlv->ti.class == CLASS_UNIVERSAL + && !tlv->ti.tag && !tlv->ti.is_constructed)) + { + /* End tag while in ndef container. Skip the tag, and pop. */ + tlv->offset += n - (tlv->bufsize - tlv->offset); + err = _tlv_pop (tlv); + // FIXME see above and run peek again. + if (err) + return (tlv->lasterr = err); + } + + /* Set offset to the value of the TLV. */ + tlv->offset += tlv->bufsize - tlv->offset - n; + dump_tag_info ("tlv_next", &tlv->ti); + return 0; +} + + +/* Return the current neting level of the TLV object. */ +static unsigned int +tlv_level (struct tlv_ctx_s *tlv) +{ + return tlv->stacklen; +} + + +/* If called right after tlv_next the number of container levels + * popped are returned. */ +static unsigned int +tlv_popped (struct tlv_ctx_s *tlv) +{ + return tlv->pop_count; +} + + +/* Set a flag to indicate that the last tlv_next has not yet been + * consumed. */ +static void +tlv_set_pending (struct tlv_ctx_s *tlv) +{ + tlv->pending = 1; +} + + +/* Skip over the value of the current tag. */ +static void +tlv_skip (struct tlv_ctx_s *tlv) +{ + tlv->lastfunc = __func__; + tlv->offset += tlv->ti.length; +} + + +/* Expect that the current tag is a sequence and setup the context for + * processing. */ +static gpg_error_t +tlv_expect_sequence (struct tlv_ctx_s *tlv) +{ + tlv->lastfunc = __func__; + if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_SEQUENCE + && tlv->ti.is_constructed)) + return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ)); + return _tlv_push (tlv); +} + +/* Variant of tlv_expect_sequence to be used for the ouyter sequence + * of an object which might have padding after the ASN.1 data. */ +static gpg_error_t +tlv_expect_top_sequence (struct tlv_ctx_s *tlv) +{ + tlv->lastfunc = __func__; + if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_SEQUENCE + && tlv->ti.is_constructed)) + return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ)); + tlv->bufsize = tlv->ti.nhdr + tlv->ti.length; + return _tlv_push (tlv); +} + + +/* Expect that the current tag is a context tag and setup the context + * for processing. The tag of the context is returned at R_TAG. */ +static gpg_error_t +tlv_expect_context_tag (struct tlv_ctx_s *tlv, int *r_tag) +{ + tlv->lastfunc = __func__; + if (!(tlv->ti.class == CLASS_CONTEXT && tlv->ti.is_constructed)) + return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ)); + *r_tag = tlv->ti.tag; + return _tlv_push (tlv); +} + + +/* Expect that the current tag is a SET and setup the context for + * processing. */ +static gpg_error_t +tlv_expect_set (struct tlv_ctx_s *tlv) +{ + tlv->lastfunc = __func__; + if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_SET + && tlv->ti.is_constructed)) + return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ)); + return _tlv_push (tlv); +} + + +/* Expect an object of CLASS with TAG and store its value at + * (R_DATA,R_DATALEN). Then skip over its value to the next tag. + * Note that the stored value are not allocated but point into + * TLV. */ +static gpg_error_t +tlv_expect_object (struct tlv_ctx_s *tlv, int class, int tag, + unsigned char const **r_data, size_t *r_datalen) +{ + const unsigned char *p; + + tlv->lastfunc = __func__; + if (!(tlv->ti.class == class && tlv->ti.tag == tag + && !tlv->ti.is_constructed)) + return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ)); + p = tlv->buffer + tlv->offset; + if (!tlv->ti.length) + return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT)); + + *r_data = p; + *r_datalen = tlv->ti.length; + + tlv->offset += tlv->ti.length; + return 0; +} + + +/* Expect that the current tag is an object string and store its value + * at (R_DATA,R_DATALEN). Then skip over its value to the next tag. + * Note that the stored value are not allocated but point into TLV. + * If ENCAPSULATES is set the octet string is used as a new + * container. R_DATA and R_DATALEN are optional. */ +static gpg_error_t +tlv_expect_octet_string (struct tlv_ctx_s *tlv, int encapsulates, + unsigned char const **r_data, size_t *r_datalen) +{ + const unsigned char *p; + size_t n; + + tlv->lastfunc = __func__; + if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_OCTET_STRING + && !tlv->ti.is_constructed)) + return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ)); + p = tlv->buffer + tlv->offset; + if (!(n=tlv->ti.length)) + return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT)); + + if (r_data) + *r_data = p; + if (r_datalen) + *r_datalen = tlv->ti.length; + if (encapsulates) + return _tlv_push (tlv); + + tlv->offset += tlv->ti.length; + return 0; +} + + +/* Expect a NULL tag. */ +static gpg_error_t +tlv_expect_null (struct tlv_ctx_s *tlv) +{ + tlv->lastfunc = __func__; + if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_NULL + && !tlv->ti.is_constructed && !tlv->ti.length)) + return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ)); + return 0; +} + + +/* Expect that the current tag is an integer and return its value at + * R_VALUE. Then skip over its value to the next tag. */ +static gpg_error_t +tlv_expect_integer (struct tlv_ctx_s *tlv, int *r_value) +{ + const unsigned char *p; + size_t n; + int value; + + tlv->lastfunc = __func__; + if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_INTEGER + && !tlv->ti.is_constructed)) + return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ)); + p = tlv->buffer + tlv->offset; + if (!(n=tlv->ti.length)) + return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT)); + + /* We currently support only positive values. */ + if ((*p & 0x80)) + return (tlv->lasterr = gpg_error (GPG_ERR_ERANGE)); + + for (value = 0; n; n--) + { + value <<= 8; + value |= (*p++) & 0xff; + if (value < 0) + return (tlv->lasterr = gpg_error (GPG_ERR_EOVERFLOW)); + } + *r_value = value; + tlv->offset += tlv->ti.length; + return 0; +} + + +/* Variant of tlv_expect_integer which returns an MPI. If IGNORE_ZERO + * is set a value of 0 is ignored and R_VALUE not changed and the + * function returns GPG_ERR_FALSE. No check for negative encoded + * integers is doe because the old code here worked the same and we + * can't foreclose invalid encoded PKCS#12 stuff - after all it is + * PKCS#12 see https://www.cs.auckland.ac.nz/~pgut001/pubs/pfx.html */ +static gpg_error_t +tlv_expect_mpinteger (struct tlv_ctx_s *tlv, int ignore_zero, + gcry_mpi_t *r_value) +{ + const unsigned char *p; + size_t n; + + tlv->lastfunc = __func__; + if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_INTEGER + && !tlv->ti.is_constructed)) + return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ)); + p = tlv->buffer + tlv->offset; + if (!(n=tlv->ti.length)) + return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT)); + + tlv->offset += tlv->ti.length; + if (ignore_zero && n == 1 && !*p) + return gpg_error (GPG_ERR_FALSE); + + return gcry_mpi_scan (r_value, GCRYMPI_FMT_USG, p, n, NULL); +} + + +/* Expect that the current tag is an object id and store its value at + * (R_OID,R_OIDLEN). Then skip over its value to the next tag. Note + * that the stored value is not allocated but points into TLV. */ +static gpg_error_t +tlv_expect_object_id (struct tlv_ctx_s *tlv, + unsigned char const **r_oid, size_t *r_oidlen) +{ + const unsigned char *p; + size_t n; + + tlv->lastfunc = __func__; + if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_OBJECT_ID + && !tlv->ti.is_constructed)) + return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ)); + p = tlv->buffer + tlv->offset; + if (!(n=tlv->ti.length)) + return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT)); + + *r_oid = p; + *r_oidlen = tlv->ti.length; + tlv->offset += tlv->ti.length; + return 0; +} + + + /* Given an ASN.1 chunk of a structure like: 24 NDEF: OCTET STRING -- This is not passed to us @@ -561,7 +970,7 @@ crypt_block (unsigned char *buffer, size_t length, char *salt, size_t saltlen, return; } - if (cipher_algo == GCRY_CIPHER_AES128 + if ((cipher_algo == GCRY_CIPHER_AES128 || cipher_algo == GCRY_CIPHER_AES256) ? set_key_iv_pbes2 (chd, salt, saltlen, iter, iv, ivlen, pw, cipher_algo) : set_key_iv (chd, salt, saltlen, iter, pw, cipher_algo == GCRY_CIPHER_RFC2268_40? 5:24)) @@ -708,482 +1117,508 @@ bag_decrypted_data_p (const void *plaintext, size_t length) static int -parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, - const unsigned char *buffer, size_t length, - int startoffset, size_t *r_consumed) +parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv) { - struct tag_info ti; - const unsigned char *p = buffer; - const unsigned char *p_start = buffer; - size_t n = length; + gpg_error_t err = 0; const char *where; + const unsigned char *oid; + size_t oidlen; + const unsigned char *data; + size_t datalen; + int intval; char salt[20]; size_t saltlen; char iv[16]; unsigned int iter; unsigned char *plain = NULL; - unsigned char *cram_buffer = NULL; - size_t consumed = 0; /* Number of bytes consumed from the original buffer. */ int is_3des = 0; int is_pbes2 = 0; + int is_aes256 = 0; int keyelem_count; + int renewed_tlv = 0; + int loopcount; + unsigned int startlevel; - where = "start"; - if (parse_tag (&p, &n, &ti)) + where = "bag.encryptedData"; + if (opt_verbose) + log_info ("processing %s\n", where); + + if (tlv_next (tlv)) goto bailout; - if (ti.class != CLASS_CONTEXT || ti.tag) + if (tlv_expect_context_tag (tlv, &intval) || intval != 0 ) goto bailout; - if (parse_tag (&p, &n, &ti)) + + if (tlv_next (tlv)) goto bailout; - if (ti.tag != TAG_SEQUENCE) + if (tlv_expect_sequence (tlv)) goto bailout; where = "bag.encryptedData.version"; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (ti.tag != TAG_INTEGER || ti.length != 1 || *p != 0) + if ((err = tlv_expect_integer (tlv, &intval))) goto bailout; - p++; n--; - if (parse_tag (&p, &n, &ti)) + if (intval) + { + err = gpg_error (GPG_ERR_INV_VALUE); + goto bailout; + } + + if (tlv_next (tlv)) goto bailout; - if (ti.tag != TAG_SEQUENCE) + if (tlv_expect_sequence (tlv)) goto bailout; where = "bag.encryptedData.data"; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (ti.tag != TAG_OBJECT_ID || ti.length != DIM(oid_data) - || memcmp (p, oid_data, DIM(oid_data))) + if (tlv_expect_object_id (tlv, &oid, &oidlen)) + goto bailout; + if (oidlen != DIM(oid_data) || memcmp (oid, oid_data, DIM(oid_data))) goto bailout; - p += DIM(oid_data); - n -= DIM(oid_data); where = "bag.encryptedData.keyinfo"; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (!ti.class && ti.tag == TAG_OBJECT_ID - && ti.length == DIM(oid_pbeWithSHAAnd40BitRC2_CBC) - && !memcmp (p, oid_pbeWithSHAAnd40BitRC2_CBC, - DIM(oid_pbeWithSHAAnd40BitRC2_CBC))) - { - p += DIM(oid_pbeWithSHAAnd40BitRC2_CBC); - n -= DIM(oid_pbeWithSHAAnd40BitRC2_CBC); - } - else if (!ti.class && ti.tag == TAG_OBJECT_ID - && ti.length == DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC) - && !memcmp (p, oid_pbeWithSHAAnd3_KeyTripleDES_CBC, - DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC))) - { - p += DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC); - n -= DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC); - is_3des = 1; - } - else if (!ti.class && ti.tag == TAG_OBJECT_ID - && ti.length == DIM(oid_pkcs5PBES2) - && !memcmp (p, oid_pkcs5PBES2, ti.length)) - { - p += ti.length; - n -= ti.length; - is_pbes2 = 1; - } - else + if (tlv_expect_sequence (tlv)) goto bailout; + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_object_id (tlv, &oid, &oidlen)) + goto bailout; + if (oidlen == DIM(oid_pbeWithSHAAnd40BitRC2_CBC) + && !memcmp (oid, oid_pbeWithSHAAnd40BitRC2_CBC, + DIM(oid_pbeWithSHAAnd40BitRC2_CBC))) + ; + else if (oidlen == DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC) + && !memcmp (oid, oid_pbeWithSHAAnd3_KeyTripleDES_CBC, + DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC))) + is_3des = 1; + else if (oidlen == DIM(oid_pkcs5PBES2) + && !memcmp (oid, oid_pkcs5PBES2, oidlen)) + is_pbes2 = 1; + else + { + err = gpg_error (GPG_ERR_UNKNOWN_ALGORITHM); + goto bailout; + } + + /*FIXME: This code is duplicated in parse_shrouded_key_bag. */ if (is_pbes2) { where = "pkcs5PBES2-params"; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) + if (tlv_expect_sequence (tlv)) goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (!(!ti.class && ti.tag == TAG_OBJECT_ID - && ti.length == DIM(oid_pkcs5PBKDF2) - && !memcmp (p, oid_pkcs5PBKDF2, ti.length))) - goto bailout; /* Not PBKDF2. */ - p += ti.length; - n -= ti.length; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (!(!ti.class && ti.tag == TAG_OCTET_STRING - && ti.length >= 8 && ti.length < sizeof salt)) - goto bailout; /* No salt or unsupported length. */ - saltlen = ti.length; - memcpy (salt, p, saltlen); - p += saltlen; - n -= saltlen; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (!(!ti.class && ti.tag == TAG_INTEGER && ti.length)) - goto bailout; /* No valid iteration count. */ - for (iter=0; ti.length; ti.length--) + if (tlv_expect_sequence (tlv)) + goto bailout; + + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_object_id (tlv, &oid, &oidlen)) + goto bailout; + if (oidlen != DIM(oid_pkcs5PBKDF2) + || memcmp (oid, oid_pkcs5PBKDF2, oidlen)) { - iter <<= 8; - iter |= (*p++) & 0xff; - n--; + err = gpg_error (GPG_ERR_INV_BER); /* Not PBKDF2. */ + goto bailout; } + + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_sequence (tlv)) + goto bailout; + + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_octet_string (tlv, 0, &data, &datalen)) + goto bailout; + if (datalen < 8 || datalen > sizeof salt) + { + log_info ("bad length of salt (%zu)\n", datalen); + err = gpg_error (GPG_ERR_INV_LENGTH); + goto bailout; + } + saltlen = datalen; + memcpy (salt, data, saltlen); + + if (tlv_next (tlv)) + goto bailout; + if ((err = tlv_expect_integer (tlv, &intval))) + goto bailout; + if (!intval) /* Not a valid iteration count. */ + { + err = gpg_error (GPG_ERR_INV_VALUE); + goto bailout; + } + iter = intval; + /* Note: We don't support the optional parameters but assume that the algorithmIdentifier follows. */ - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) + if (tlv_expect_sequence (tlv)) goto bailout; - if (parse_tag (&p, &n, &ti)) + + if (tlv_next (tlv)) goto bailout; - if (!(!ti.class && ti.tag == TAG_OBJECT_ID - && ti.length == DIM(oid_aes128_CBC) - && !memcmp (p, oid_aes128_CBC, ti.length))) - goto bailout; /* Not AES-128. */ - p += ti.length; - n -= ti.length; - if (parse_tag (&p, &n, &ti)) + if (tlv_expect_object_id (tlv, &oid, &oidlen)) goto bailout; - if (!(!ti.class && ti.tag == TAG_OCTET_STRING && ti.length == sizeof iv)) - goto bailout; /* Bad IV. */ - memcpy (iv, p, sizeof iv); - p += sizeof iv; - n -= sizeof iv; + + if (oidlen == DIM(oid_aes128_CBC) + && !memcmp (oid, oid_aes128_CBC, oidlen)) + ; + else if (oidlen == DIM(oid_aes256_CBC) + && !memcmp (oid, oid_aes256_CBC, oidlen)) + is_aes256 = 1; + else + { + gpgrt_log_printhex (oid, oidlen, "cipher algo:"); + err = gpg_error (GPG_ERR_CIPHER_ALGO); + goto bailout; + } + + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_octet_string (tlv, 0, &data, &datalen)) + goto bailout; + if (datalen != sizeof iv) + { + err = gpg_error (GPG_ERR_INV_LENGTH); + goto bailout; /* Bad IV. */ + } + memcpy (iv, data, datalen); } else { where = "rc2or3des-params"; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) + if (tlv_expect_sequence (tlv)) goto bailout; - if (parse_tag (&p, &n, &ti)) + + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_OCTET_STRING - || ti.length < 8 || ti.length > 20 ) + if (tlv_expect_octet_string (tlv, 0, &data, &datalen)) goto bailout; - saltlen = ti.length; - memcpy (salt, p, saltlen); - p += saltlen; - n -= saltlen; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_INTEGER || !ti.length ) - goto bailout; - for (iter=0; ti.length; ti.length--) + if (datalen < 8 || datalen > 20) { - iter <<= 8; - iter |= (*p++) & 0xff; - n--; + log_info ("bad length of salt (%zu) for 3DES\n", datalen); + err = gpg_error (GPG_ERR_INV_LENGTH); + goto bailout; } + saltlen = datalen; + memcpy (salt, data, saltlen); + + if (tlv_next (tlv)) + goto bailout; + if ((err = tlv_expect_integer (tlv, &intval))) + goto bailout; + if (!intval) + { + err = gpg_error (GPG_ERR_INV_VALUE); + goto bailout; + } + iter = intval; } where = "rc2or3desoraes-ciphertext"; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - consumed = p - p_start; - if (ti.class == CLASS_CONTEXT && ti.tag == 0 && ti.is_constructed && ti.ndef) - { - /* Mozilla exported certs now come with single byte chunks of - octet strings. (Mozilla Firefox 1.0.4). Arghh. */ - where = "cram-rc2or3des-ciphertext"; - cram_buffer = cram_octet_string ( p, &n, &consumed); - if (!cram_buffer) - goto bailout; - p = p_start = cram_buffer; - if (r_consumed) - *r_consumed = consumed; - r_consumed = NULL; /* Donot update that value on return. */ - ti.length = n; - } - else if (ti.class == CLASS_CONTEXT && ti.tag == 0 && ti.is_constructed) - { - where = "octets-rc2or3des-ciphertext"; - n = ti.length; - cram_buffer = cram_octet_string ( p, &n, &consumed); - if (!cram_buffer) - goto bailout; - p = p_start = cram_buffer; - if (r_consumed) - *r_consumed = consumed; - r_consumed = NULL; /* Do not update that value on return. */ - ti.length = n; - } - else if (ti.class == CLASS_CONTEXT && ti.tag == 0 && ti.length ) - ; - else + /* consumed = p - p_start; */ + /* if (ti.class == CLASS_CONTEXT && ti.tag == 0 && ti.is_constructed && ti.ndef) */ + /* { */ + /* /\* Mozilla exported certs now come with single byte chunks of */ + /* octet strings. (Mozilla Firefox 1.0.4). Arghh. *\/ */ + /* where = "cram-rc2or3des-ciphertext"; */ + /* cram_buffer = cram_octet_string ( p, &n, &consumed); */ + /* if (!cram_buffer) */ + /* goto bailout; */ + /* p = p_start = cram_buffer; */ + /* if (r_consumed) */ + /* *r_consumed = consumed; */ + /* r_consumed = NULL; /\* Donot update that value on return. *\/ */ + /* ti.length = n; */ + /* } */ + /* else if (ti.class == CLASS_CONTEXT && ti.tag == 0 && ti.is_constructed) */ + /* { */ + /* where = "octets-rc2or3des-ciphertext"; */ + /* n = ti.length; */ + /* cram_buffer = cram_octet_string ( p, &n, &consumed); */ + /* if (!cram_buffer) */ + /* goto bailout; */ + /* p = p_start = cram_buffer; */ + /* if (r_consumed) */ + /* *r_consumed = consumed; */ + /* r_consumed = NULL; /\* Do not update that value on return. *\/ */ + /* ti.length = n; */ + /* } */ + /* else if (ti.class == CLASS_CONTEXT && ti.tag == 0 && ti.length ) */ + /* ; */ + /* else */ + /* goto bailout; */ + if (tlv_expect_object (tlv, CLASS_CONTEXT, 0, &data, &datalen)) goto bailout; if (opt_verbose) - log_info ("%lu bytes of %s encrypted text\n",ti.length, - is_pbes2?"AES128":is_3des?"3DES":"RC2"); + log_info ("%zu bytes of %s encrypted text\n", datalen, + is_pbes2?(is_aes256?"AES256":"AES128"):is_3des?"3DES":"RC2"); - plain = gcry_malloc_secure (ti.length); + plain = gcry_malloc_secure (datalen); if (!plain) { + err = gpg_error_from_syserror (); log_error ("error allocating decryption buffer\n"); goto bailout; } - decrypt_block (p, plain, ti.length, salt, saltlen, iter, + decrypt_block (data, plain, datalen, salt, saltlen, iter, iv, is_pbes2?16:0, ctx->password, - is_pbes2 ? GCRY_CIPHER_AES128 : + is_pbes2 ? (is_aes256?GCRY_CIPHER_AES256:GCRY_CIPHER_AES128) : is_3des ? GCRY_CIPHER_3DES : GCRY_CIPHER_RFC2268_40, bag_decrypted_data_p); - n = ti.length; - startoffset = 0; - p_start = p = plain; - where = "outer.outer.seq"; - if (parse_tag (&p, &n, &ti)) + /* We do not need the TLV anymore and allocated a new one. */ + where = "bag.encryptedData.decrypted-text"; + tlv = tlv_new (plain, datalen); + if (!tlv) + { + err = gpg_error_from_syserror (); + goto bailout; + } + renewed_tlv = 1; + + if (tlv_next (tlv)) { ctx->badpass = 1; goto bailout; } - if (ti.class || ti.tag != TAG_SEQUENCE) - { - ctx->badpass = 1; - goto bailout; - } - - if (parse_tag (&p, &n, &ti)) + if (tlv_expect_top_sequence (tlv)) { ctx->badpass = 1; goto bailout; } /* Loop over all certificates inside the bag. */ - while (n) + loopcount = 0; + startlevel = tlv_level (tlv); + while (!(err = tlv_next (tlv)) && tlv_level (tlv) == startlevel) { int iscrlbag = 0; int iskeybag = 0; + loopcount++; where = "certbag.nextcert"; - if (ti.class || ti.tag != TAG_SEQUENCE) + if (tlv_expect_sequence (tlv)) goto bailout; - where = "certbag.objectidentifier"; - if (parse_tag (&p, &n, &ti)) + where = "certbag.oid"; + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_OBJECT_ID) + if (tlv_expect_object_id (tlv, &oid, &oidlen)) goto bailout; - if ( ti.length == DIM(oid_pkcs_12_CertBag) - && !memcmp (p, oid_pkcs_12_CertBag, DIM(oid_pkcs_12_CertBag))) - { - p += DIM(oid_pkcs_12_CertBag); - n -= DIM(oid_pkcs_12_CertBag); - } - else if ( ti.length == DIM(oid_pkcs_12_CrlBag) - && !memcmp (p, oid_pkcs_12_CrlBag, DIM(oid_pkcs_12_CrlBag))) - { - p += DIM(oid_pkcs_12_CrlBag); - n -= DIM(oid_pkcs_12_CrlBag); - iscrlbag = 1; - } - else if ( ti.length == DIM(oid_pkcs_12_keyBag) - && !memcmp (p, oid_pkcs_12_keyBag, DIM(oid_pkcs_12_keyBag))) + if (oidlen == DIM(oid_pkcs_12_CertBag) + && !memcmp (oid, oid_pkcs_12_CertBag, DIM(oid_pkcs_12_CertBag))) + ; + else if (oidlen == DIM(oid_pkcs_12_CrlBag) + && !memcmp (oid, oid_pkcs_12_CrlBag, DIM(oid_pkcs_12_CrlBag))) + iscrlbag = 1; + else if (oidlen == DIM(oid_pkcs_12_keyBag) + && !memcmp (oid, oid_pkcs_12_keyBag, DIM(oid_pkcs_12_keyBag))) { /* The TrustedMIME plugin for MS Outlook started to create files with just one outer 3DES encrypted container and inside the certificates as well as the key. */ - p += DIM(oid_pkcs_12_keyBag); - n -= DIM(oid_pkcs_12_keyBag); iskeybag = 1; } else - goto bailout; + { + gpgrt_log_printhex (oid, oidlen, "cert bag type OID:"); + err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); + goto bailout; + } where = "certbag.before.certheader"; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (ti.class != CLASS_CONTEXT || ti.tag) + if (tlv_expect_context_tag (tlv, &intval) || intval != 0 ) goto bailout; + if (iscrlbag) { log_info ("skipping unsupported crlBag\n"); - p += ti.length; - n -= ti.length; } else if (iskeybag && ctx->privatekey) { log_info ("one keyBag already processed; skipping this one\n"); - p += ti.length; - n -= ti.length; } else if (iskeybag) { - int len; - if (opt_verbose) log_info ("processing simple keyBag\n"); - /* Fixme: This code is duplicated from parse_bag_data. */ - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE) + if (tlv_next (tlv)) goto bailout; - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER - || ti.length != 1 || *p) + if (tlv_expect_sequence (tlv)) goto bailout; - p++; n--; - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - len = ti.length; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (len < ti.nhdr) - goto bailout; - len -= ti.nhdr; - if (ti.class || ti.tag != TAG_OBJECT_ID - || ti.length != DIM(oid_rsaEncryption) - || memcmp (p, oid_rsaEncryption, - DIM(oid_rsaEncryption))) - goto bailout; - p += DIM (oid_rsaEncryption); - n -= DIM (oid_rsaEncryption); - if (len < ti.length) - goto bailout; - len -= ti.length; - if (n < len) - goto bailout; - p += len; - n -= len; - if ( parse_tag (&p, &n, &ti) - || ti.class || ti.tag != TAG_OCTET_STRING) - goto bailout; - if ( parse_tag (&p, &n, &ti) - || ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - len = ti.length; - log_assert (!ctx->privatekey); + if (tlv_next (tlv)) + goto bailout; + if ((err = tlv_expect_integer (tlv, &intval))) + goto bailout; + if (intval) + { + err = gpg_error (GPG_ERR_INV_VALUE); + goto bailout; + } + + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_sequence (tlv)) + goto bailout; + + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_object_id (tlv, &oid, &oidlen)) + goto bailout; + if (oidlen != DIM(oid_rsaEncryption) + || memcmp (oid, oid_rsaEncryption, oidlen)) + { + err = gpg_error (GPG_ERR_PUBKEY_ALGO); + goto bailout; + } + + /* We ignore the next octet string. */ + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_octet_string (tlv, 0, &data, &datalen)) + goto bailout; + + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_sequence (tlv)) + goto bailout; + + if (ctx->privatekey) + { + err = gpg_error (GPG_ERR_DUP_VALUE); + log_error ("a private key has already been received\n"); + goto bailout; + } ctx->privatekey = gcry_calloc (10, sizeof *ctx->privatekey); if (!ctx->privatekey) { + err = gpg_error_from_syserror (); log_error ("error allocating private key element array\n"); goto bailout; } - keyelem_count = 0; where = "reading.keybag.key-parameters"; - for (keyelem_count = 0; len && keyelem_count < 9;) + keyelem_count = 0; + while (!(err = tlv_next (tlv)) && !tlv_popped (tlv)) { - if ( parse_tag (&p, &n, &ti) - || ti.class || ti.tag != TAG_INTEGER) - goto bailout; - if (len < ti.nhdr) - goto bailout; - len -= ti.nhdr; - if (len < ti.length) - goto bailout; - len -= ti.length; - if (!keyelem_count && ti.length == 1 && !*p) - ; /* ignore the very first one if it is a 0 */ - else + if (keyelem_count >= 9) { - int rc; - - rc = gcry_mpi_scan (ctx->privatekey+keyelem_count, - GCRYMPI_FMT_USG, p, - ti.length, NULL); - if (rc) - { - log_error ("error parsing key parameter: %s\n", - gpg_strerror (rc)); - goto bailout; - } - keyelem_count++; + err = gpg_error (GPG_ERR_TOO_MANY); + goto bailout; } - p += ti.length; - n -= ti.length; + + err = tlv_expect_mpinteger (tlv, !keyelem_count, + ctx->privatekey+keyelem_count); + if (!keyelem_count && gpg_err_code (err) == GPG_ERR_FALSE) + ; /* Ignore the first value iff it is zero. */ + else if (err) + { + log_error ("error parsing RSA key parameter %d: %s\n", + keyelem_count, gpg_strerror (err)); + goto bailout; + } + log_debug ("RSA key parameter %d found\n", keyelem_count); + keyelem_count++; } - if (len) + if (err && gpg_err_code (err) != GPG_ERR_EOF) goto bailout; + err = 0; } else { if (opt_verbose) log_info ("processing certBag\n"); - if (parse_tag (&p, &n, &ti)) + + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) + if (tlv_expect_sequence (tlv)) goto bailout; - if (parse_tag (&p, &n, &ti)) + + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_OBJECT_ID - || ti.length != DIM(oid_x509Certificate_for_pkcs_12) - || memcmp (p, oid_x509Certificate_for_pkcs_12, + if (tlv_expect_object_id (tlv, &oid, &oidlen)) + goto bailout; + if (oidlen != DIM(oid_x509Certificate_for_pkcs_12) + || memcmp (oid, oid_x509Certificate_for_pkcs_12, DIM(oid_x509Certificate_for_pkcs_12))) - goto bailout; - p += DIM(oid_x509Certificate_for_pkcs_12); - n -= DIM(oid_x509Certificate_for_pkcs_12); + { + err = gpg_error (GPG_ERR_UNSUPPORTED_CERT); + goto bailout; + } where = "certbag.before.octetstring"; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (ti.class != CLASS_CONTEXT || ti.tag) + if (tlv_expect_context_tag (tlv, &intval)) goto bailout; - if (parse_tag (&p, &n, &ti)) + if (intval) + { + err = gpg_error (GPG_ERR_BAD_BER); + goto bailout; + } + + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_OCTET_STRING || ti.ndef) + if (tlv_expect_octet_string (tlv, 0, &data, &datalen)) goto bailout; /* Return the certificate. */ if (ctx->certcb) - ctx->certcb (ctx->certcbarg, p, ti.length); - - p += ti.length; - n -= ti.length; + ctx->certcb (ctx->certcbarg, data, datalen); } - /* Ugly hack to cope with the padding: Forget about the rest if - that is less or equal to the cipher's block length. We can - reasonable assume that all valid data will be longer than - just one block. */ - if (n <= (is_pbes2? 16:8)) - n = 0; - /* Skip the optional SET with the pkcs12 cert attributes. */ - if (n) - { - where = "bag.attributes"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (!ti.class && ti.tag == TAG_SEQUENCE) - ; /* No attributes. */ - else if (!ti.class && ti.tag == TAG_SET && !ti.ndef) - { /* The optional SET. */ - p += ti.length; - n -= ti.length; - if (n <= (is_pbes2?16:8)) - n = 0; - if (n && parse_tag (&p, &n, &ti)) - goto bailout; - } - else - goto bailout; + where = "bag.attribute_set"; + err = tlv_next (tlv); + if (gpg_err_code (err) == GPG_ERR_EOF) + break; + if (err) + goto bailout; + err = tlv_expect_set (tlv); + if (!err) + { /* This is the optional set of attributes. Skip it. */ + tlv_skip (tlv); + if (opt_verbose) + log_info ("skipping bag.attribute_set\n"); } + else if (gpg_err_code (err) == GPG_ERR_INV_OBJ) + tlv_set_pending (tlv); /* The next tlv_next will be skipped. */ + else + goto bailout; } + if (err && gpg_err_code (err) != GPG_ERR_EOF) + { + if (!loopcount) /* The first while(tlv_next) failed. */ + ctx->badpass = 1; + goto bailout; + } + err = 0; - if (r_consumed) - *r_consumed = consumed; + leave: + if (renewed_tlv) + tlv_release (tlv); gcry_free (plain); - gcry_free (cram_buffer); - return 0; - - bailout: - if (r_consumed) - *r_consumed = consumed; - gcry_free (plain); - gcry_free (cram_buffer); - log_error ("encryptedData error at \"%s\", offset %u\n", - where, (unsigned int)((p - p_start)+startoffset)); if (ctx->badpass) { /* Note, that the following string might be used by other programs @@ -1191,7 +1626,19 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, translated or changed. */ log_error ("possibly bad passphrase given\n"); } - return -1; + return err; + + bailout: + if (!err) + err = gpg_error (GPG_ERR_GENERAL); + log_error ("%s(%s): offset %u.%zu (%s): %s - %s\n", + __func__, where, + tlv? tlv->stacklen : 0, + tlv? tlv->offset : 0, + tlv? tlv->lastfunc : "", + tlv ? gpg_strerror (tlv->lasterr) : "init failed", + gpg_strerror (err)); + goto leave; } @@ -1223,363 +1670,403 @@ bag_data_p (const void *plaintext, size_t length) static gpg_error_t -parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, - const unsigned char *buffer, size_t length, - int startoffset, - size_t *r_consumed) +parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv) { gpg_error_t err = 0; - struct tag_info ti; - const unsigned char *p = buffer; - const unsigned char *p_start = buffer; - size_t n = length; const char *where; + const unsigned char *oid; + size_t oidlen; + const unsigned char *data; + size_t datalen; + int intval; char salt[20]; size_t saltlen; char iv[16]; unsigned int iter; - int len; + int renewed_tlv = 0; /* True if the TLV must be released. */ unsigned char *plain = NULL; - unsigned char *cram_buffer = NULL; - size_t consumed = 0; /* Number of bytes consumed from the original buffer. */ int is_pbes2 = 0; - int keyelem_count = 0; + int is_aes256 = 0; where = "shrouded_key_bag"; - if (parse_tag (&p, &n, &ti)) + if (opt_verbose) + log_info ("processing %s\n", where); + + if (tlv_next (tlv)) goto bailout; - if (ti.class != CLASS_CONTEXT || ti.tag) + if (tlv_expect_context_tag (tlv, &intval) || intval != 0 ) goto bailout; - if (parse_tag (&p, &n, &ti)) + + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) + if (tlv_expect_sequence (tlv)) goto bailout; - if (parse_tag (&p, &n, &ti)) + + where = "shrouded_key_bag.cipherinfo"; + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) + if (tlv_expect_sequence (tlv)) goto bailout; - if (parse_tag (&p, &n, &ti)) + + if (tlv_next (tlv)) goto bailout; - if (ti.class == 0 && ti.tag == TAG_OBJECT_ID - && ti.length == DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC) - && !memcmp (p, oid_pbeWithSHAAnd3_KeyTripleDES_CBC, + if (tlv_expect_object_id (tlv, &oid, &oidlen)) + goto bailout; + + if (oidlen == DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC) + && !memcmp (oid, oid_pbeWithSHAAnd3_KeyTripleDES_CBC, DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC))) - { - p += DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC); - n -= DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC); - } - else if (ti.class == 0 && ti.tag == TAG_OBJECT_ID - && ti.length == DIM(oid_pkcs5PBES2) - && !memcmp (p, oid_pkcs5PBES2, DIM(oid_pkcs5PBES2))) - { - p += DIM(oid_pkcs5PBES2); - n -= DIM(oid_pkcs5PBES2); - is_pbes2 = 1; - } + ; /* Standard cipher. */ + else if (oidlen == DIM(oid_pkcs5PBES2) + && !memcmp (oid, oid_pkcs5PBES2, DIM(oid_pkcs5PBES2))) + is_pbes2 = 1; else - goto bailout; + { + err = gpg_error (GPG_ERR_UNKNOWN_ALGORITHM); + goto bailout; + } if (is_pbes2) { where = "shrouded_key_bag.pkcs5PBES2-params"; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) + if (tlv_expect_sequence (tlv)) goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (!(!ti.class && ti.tag == TAG_OBJECT_ID - && ti.length == DIM(oid_pkcs5PBKDF2) - && !memcmp (p, oid_pkcs5PBKDF2, ti.length))) - goto bailout; /* Not PBKDF2. */ - p += ti.length; - n -= ti.length; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (!(!ti.class && ti.tag == TAG_OCTET_STRING - && ti.length >= 8 && ti.length < sizeof salt)) - goto bailout; /* No salt or unsupported length. */ - saltlen = ti.length; - memcpy (salt, p, saltlen); - p += saltlen; - n -= saltlen; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (!(!ti.class && ti.tag == TAG_INTEGER && ti.length)) - goto bailout; /* No valid iteration count. */ - for (iter=0; ti.length; ti.length--) + if (tlv_expect_sequence (tlv)) + goto bailout; + + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_object_id (tlv, &oid, &oidlen)) + goto bailout; + if (!(oidlen == DIM(oid_pkcs5PBKDF2) + && !memcmp (oid, oid_pkcs5PBKDF2, oidlen))) + goto bailout; /* Not PBKDF2. */ + + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_sequence (tlv)) + goto bailout; + + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_octet_string (tlv, 0, &data, &datalen)) + goto bailout; + if (datalen < 8 || datalen > sizeof salt) { - iter <<= 8; - iter |= (*p++) & 0xff; - n--; + log_info ("bad length of salt (%zu) for AES\n", datalen); + err = gpg_error (GPG_ERR_INV_LENGTH); + goto bailout; } + saltlen = datalen; + memcpy (salt, data, saltlen); + + if (tlv_next (tlv)) + goto bailout; + if ((err = tlv_expect_integer (tlv, &intval))) + goto bailout; + if (!intval) /* Not a valid iteration count. */ + { + err = gpg_error (GPG_ERR_INV_VALUE); + goto bailout; + } + iter = intval; + /* Note: We don't support the optional parameters but assume that the algorithmIdentifier follows. */ - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) + if (tlv_expect_sequence (tlv)) goto bailout; - if (parse_tag (&p, &n, &ti)) + + if (tlv_next (tlv)) goto bailout; - if (!(!ti.class && ti.tag == TAG_OBJECT_ID - && ti.length == DIM(oid_aes128_CBC) - && !memcmp (p, oid_aes128_CBC, ti.length))) - goto bailout; /* Not AES-128. */ - p += ti.length; - n -= ti.length; - if (parse_tag (&p, &n, &ti)) + if (tlv_expect_object_id (tlv, &oid, &oidlen)) goto bailout; - if (!(!ti.class && ti.tag == TAG_OCTET_STRING && ti.length == sizeof iv)) + if (oidlen == DIM(oid_aes128_CBC) + && !memcmp (oid, oid_aes128_CBC, oidlen)) + ; + else if (oidlen == DIM(oid_aes256_CBC) + && !memcmp (oid, oid_aes256_CBC, oidlen)) + is_aes256 = 1; + else + { + gpgrt_log_printhex (oid, oidlen, "cipher is:"); + err = gpg_error (GPG_ERR_CIPHER_ALGO); + goto bailout; + } + + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_octet_string (tlv, 0, &data, &datalen)) + goto bailout; + if (datalen != sizeof iv) goto bailout; /* Bad IV. */ - memcpy (iv, p, sizeof iv); - p += sizeof iv; - n -= sizeof iv; + memcpy (iv, data, datalen); } else { where = "shrouded_key_bag.3des-params"; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) + if (tlv_expect_sequence (tlv)) goto bailout; - if (parse_tag (&p, &n, &ti)) + + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_OCTET_STRING - || ti.length < 8 || ti.length > 20) + if (tlv_expect_octet_string (tlv, 0, &data, &datalen)) goto bailout; - saltlen = ti.length; - memcpy (salt, p, saltlen); - p += saltlen; - n -= saltlen; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_INTEGER || !ti.length ) - goto bailout; - for (iter=0; ti.length; ti.length--) + if (datalen < 8 || datalen > 20) { - iter <<= 8; - iter |= (*p++) & 0xff; - n--; + log_info ("bad length of salt (%zu) for 3DES\n", datalen); + err = gpg_error (GPG_ERR_INV_LENGTH); + goto bailout; } + saltlen = datalen; + memcpy (salt, data, saltlen); + + if (tlv_next (tlv)) + goto bailout; + if ((err = tlv_expect_integer (tlv, &intval))) + goto bailout; + if (!intval) + { + err = gpg_error (GPG_ERR_INV_VALUE); + goto bailout; + } + iter = intval; } where = "shrouded_key_bag.3desoraes-ciphertext"; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_OCTET_STRING || !ti.length ) + if (tlv_expect_octet_string (tlv, 0, &data, &datalen)) goto bailout; if (opt_verbose) - log_info ("%lu bytes of %s encrypted text\n", - ti.length, is_pbes2? "AES128":"3DES"); + log_info ("%zu bytes of %s encrypted text\n", + datalen, is_pbes2? (is_aes256?"AES256":"AES128"):"3DES"); + + plain = gcry_malloc_secure (datalen); - plain = gcry_malloc_secure (ti.length); if (!plain) { + err = gpg_error_from_syserror (); log_error ("error allocating decryption buffer\n"); goto bailout; } - consumed += p - p_start + ti.length; - decrypt_block (p, plain, ti.length, salt, saltlen, iter, + decrypt_block (data, plain, datalen, salt, saltlen, iter, iv, is_pbes2? 16:0, ctx->password, - is_pbes2? GCRY_CIPHER_AES128 : GCRY_CIPHER_3DES, + is_pbes2 ? (is_aes256?GCRY_CIPHER_AES256:GCRY_CIPHER_AES128) + : GCRY_CIPHER_3DES, bag_data_p); - n = ti.length; - startoffset = 0; - p_start = p = plain; + /* We do not need the TLV anymore and allocated a new one. */ where = "shrouded_key_bag.decrypted-text"; - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER - || ti.length != 1 || *p) - goto bailout; - p++; n--; - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - len = ti.length; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (len < ti.nhdr) - goto bailout; - len -= ti.nhdr; - if (ti.class || ti.tag != TAG_OBJECT_ID) - goto bailout; - /* gpgrt_log_printhex (p, ti.length, "OID:"); */ - if (ti.length == DIM(oid_rsaEncryption) - && !memcmp (p, oid_rsaEncryption, DIM(oid_rsaEncryption))) + tlv = tlv_new (plain, datalen); + if (!tlv) { - p += DIM (oid_rsaEncryption); - n -= DIM (oid_rsaEncryption); + err = gpg_error_from_syserror (); + goto bailout; } - else if (ti.length == DIM(oid_pcPublicKey) - && !memcmp (p, oid_pcPublicKey, DIM(oid_pcPublicKey))) + renewed_tlv = 1; + + if (tlv_next (tlv)) + { + ctx->badpass = 1; + goto bailout; + } + if (tlv_expect_top_sequence (tlv)) + { + ctx->badpass = 1; + goto bailout; + } + + if (tlv_next (tlv)) + { + ctx->badpass = 1; + goto bailout; + } + if ((err = tlv_expect_integer (tlv, &intval))) + { + ctx->badpass = 1; + goto bailout; + } + if (intval) + { + ctx->badpass = 1; + err = gpg_error (GPG_ERR_INV_VALUE); + goto bailout; + } + + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_sequence (tlv)) + goto bailout; + + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_object_id (tlv, &oid, &oidlen)) + goto bailout; + if (oidlen == DIM(oid_rsaEncryption) + && !memcmp (oid, oid_rsaEncryption, oidlen)) + { + if (opt_verbose > 1) + log_debug ("RSA parameters\n"); + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_null (tlv)) + tlv_set_pending (tlv); /* NULL tag missing - ignore this. */ + } + else if (oidlen == DIM(oid_pcPublicKey) + && !memcmp (oid, oid_pcPublicKey, oidlen)) { /* See RFC-5915 for the format. */ - p += DIM (oid_pcPublicKey); - n -= DIM (oid_pcPublicKey); - if (len < ti.length) + if (tlv_next (tlv)) goto bailout; - len -= ti.length; - if (n < len) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - /* gpgrt_log_debug ("ti=%d/%lu len=%lu\n",ti.class,ti.tag,ti.length); */ - if (len < ti.nhdr) - goto bailout; - len -= ti.nhdr; - if (ti.class || ti.tag != TAG_OBJECT_ID) + if (tlv_expect_object_id (tlv, &oid, &oidlen)) goto bailout; ksba_free (ctx->curve); - ctx->curve = ksba_oid_to_str (p, ti.length); + ctx->curve = ksba_oid_to_str (oid, oidlen); if (!ctx->curve) - goto bailout; - /* log_debug ("OID of curve is: %s\n", curve); */ - p += ti.length; - n -= ti.length; + { + err = gpg_error (GPG_ERR_INV_OID_STRING); + goto bailout; + } + if (opt_verbose > 1) + log_debug ("OID of curve is: %s\n", ctx->curve); } - else + else /* Unknown key format */ + { + gpgrt_log_printhex (oid, oidlen, "key format OID:"); + err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); + goto bailout; + } + + /* An octet string to encapsulate the key elements. */ + if (tlv_next (tlv)) goto bailout; - if (len < ti.length) + if (tlv_expect_octet_string (tlv, 1, &data, &datalen)) goto bailout; - len -= ti.length; - if (n < len) + + if (tlv_next (tlv)) goto bailout; - p += len; - n -= len; - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_OCTET_STRING) + if (tlv_expect_sequence (tlv)) goto bailout; - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - len = ti.length; if (ctx->privatekey) { - log_error ("a key has already been received\n"); + err = gpg_error (GPG_ERR_DUP_VALUE); + log_error ("a private key has already been received\n"); goto bailout; } ctx->privatekey = gcry_calloc (10, sizeof *ctx->privatekey); if (!ctx->privatekey) { - + err = gpg_error_from_syserror (); log_error ("error allocating privatekey element array\n"); goto bailout; } - keyelem_count = 0; where = "shrouded_key_bag.reading.key-parameters"; if (ctx->curve) /* ECC case. */ { - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER) + if (tlv_next (tlv)) goto bailout; - if (len < ti.nhdr) + if ((err = tlv_expect_integer (tlv, &intval))) goto bailout; - len -= ti.nhdr; - if (len < ti.length) - goto bailout; - len -= ti.length; - if (ti.length != 1 && *p != 1) + if (intval != 1) { + err = gpg_error (GPG_ERR_INV_VALUE); log_error ("error parsing private ecPublicKey parameter: %s\n", "bad version"); goto bailout; } - p += ti.length; - n -= ti.length; - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_OCTET_STRING) + + if (tlv_next (tlv)) goto bailout; - if (len < ti.nhdr) + if (tlv_expect_octet_string (tlv, 0, &data, &datalen)) goto bailout; - len -= ti.nhdr; - if (len < ti.length) - goto bailout; - len -= ti.length; - /* log_printhex (p, ti.length, "ecc q="); */ + if (opt_verbose > 1) + log_printhex (data, datalen, "ecc q="); err = gcry_mpi_scan (ctx->privatekey, GCRYMPI_FMT_USG, - p, ti.length, NULL); + data, datalen, NULL); if (err) { log_error ("error parsing key parameter: %s\n", gpg_strerror (err)); goto bailout; } - p += ti.length; - n -= ti.length; - - len = 0; /* Skip the rest. */ } else /* RSA case */ { - for (keyelem_count=0; len && keyelem_count < 9;) + int keyelem_count = 0; + int firstparam = 1; + + while (!(err = tlv_next (tlv)) && !tlv_popped (tlv)) { - if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER) - goto bailout; - if (len < ti.nhdr) - goto bailout; - len -= ti.nhdr; - if (len < ti.length) - goto bailout; - len -= ti.length; - if (!keyelem_count && ti.length == 1 && !*p) - ; /* ignore the very first one if it is a 0 */ + if (keyelem_count >= 9) + { + err = gpg_error (GPG_ERR_TOO_MANY); + goto bailout; + } + + err = tlv_expect_mpinteger (tlv, firstparam, + ctx->privatekey+keyelem_count); + if (firstparam && gpg_err_code (err) == GPG_ERR_FALSE) + ; /* Ignore the first value iff it is zero. */ + else if (err) + { + log_error ("error parsing RSA key parameter %d: %s\n", + keyelem_count, gpg_strerror (err)); + goto bailout; + } else { - err = gcry_mpi_scan (ctx->privatekey+keyelem_count, - GCRYMPI_FMT_USG, p, ti.length, NULL); - if (err) - { - log_error ("error parsing key parameter: %s\n", - gpg_strerror (err)); - goto bailout; - } + if (opt_verbose > 1) + log_debug ("RSA key parameter %d found\n", keyelem_count); keyelem_count++; } - p += ti.length; - n -= ti.length; + firstparam = 0; } + if (err && gpg_err_code (err) != GPG_ERR_EOF) + goto bailout; + err = 0; } - if (len) - goto bailout; - - goto leave; - - bailout: - gcry_free (plain); - log_error ("data error at \"%s\", offset %zu\n", - where, (size_t)((p - p_start) + startoffset)); - if (!err) - err = gpg_error (GPG_ERR_GENERAL); leave: - gcry_free (cram_buffer); - if (r_consumed) - *r_consumed = consumed; + gcry_free (plain); + if (renewed_tlv) + tlv_release (tlv); return err; + + bailout: + if (!err) + err = gpg_error (GPG_ERR_GENERAL); + log_error ("%s(%s): offset %u.%zu (%s): %s - %s\n", + __func__, where, + tlv? tlv->stacklen : 0, + tlv? tlv->offset : 0, + tlv? tlv->lastfunc : "", + tlv ? gpg_strerror (tlv->lasterr) : "init failed", + gpg_strerror (err)); + goto leave; } static gpg_error_t -parse_cert_bag (struct p12_parse_ctx_s *ctx, - const unsigned char *buffer, size_t length, - int startoffset, - size_t *r_consumed) +parse_cert_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv) { gpg_error_t err = 0; - struct tag_info ti; - const unsigned char *p = buffer; - const unsigned char *p_start = buffer; - size_t n = length; const char *where; - size_t consumed = 0; /* Number of bytes consumed from the original buffer. */ + int intval; + const unsigned char *oid; + size_t oidlen; + const unsigned char *data; + size_t datalen; if (opt_verbose) log_info ("processing certBag\n"); @@ -1590,181 +2077,182 @@ parse_cert_bag (struct p12_parse_ctx_s *ctx, * OBJECT IDENTIFIER pkcs-12-certBag */ where = "certbag.before.certheader"; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (ti.class != CLASS_CONTEXT || ti.tag) + if (tlv_expect_context_tag (tlv, &intval)) goto bailout; - if (parse_tag (&p, &n, &ti)) + if (intval) + { + err = gpg_error (GPG_ERR_INV_VALUE); + goto bailout; + } + + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) + if (tlv_expect_sequence (tlv)) goto bailout; - if (parse_tag (&p, &n, &ti)) + + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_OBJECT_ID - || ti.length != DIM(oid_x509Certificate_for_pkcs_12) - || memcmp (p, oid_x509Certificate_for_pkcs_12, - DIM(oid_x509Certificate_for_pkcs_12))) + if (tlv_expect_object_id (tlv, &oid, &oidlen)) goto bailout; - p += DIM(oid_x509Certificate_for_pkcs_12); - n -= DIM(oid_x509Certificate_for_pkcs_12); + if (oidlen != DIM(oid_x509Certificate_for_pkcs_12) + || memcmp (oid, oid_x509Certificate_for_pkcs_12, oidlen)) + goto bailout; + /* Expect: * [0] * OCTET STRING encapsulates -- the certificates */ where = "certbag.before.octetstring"; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (ti.class != CLASS_CONTEXT || ti.tag) + if (tlv_expect_context_tag (tlv, &intval) || intval != 0 ) goto bailout; - if (parse_tag (&p, &n, &ti)) + + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_OCTET_STRING || ti.ndef) + if (tlv_expect_octet_string (tlv, 0, &data, &datalen)) goto bailout; /* Return the certificate from the octet string. */ if (ctx->certcb) - ctx->certcb (ctx->certcbarg, p, ti.length); + ctx->certcb (ctx->certcbarg, data, datalen); - p += ti.length; - n -= ti.length; - - if (!n) - goto leave; /* ready. */ - - /* Expect: + /* Expect optional: * SET * SEQUENCE -- we actually ignore this. */ where = "certbag.attribute_set"; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (!ti.class && ti.tag == TAG_SET && !ti.ndef) - { /* Comsume the optional SET. */ - p += ti.length; - n -= ti.length; - if (parse_tag (&p, &n, &ti)) - goto bailout; + err = tlv_expect_set (tlv); + if (!err) + { /* This is the optional set of attributes. Skip it. */ + tlv_skip (tlv); + if (opt_verbose) + log_info ("skipping certbag.attribute_set\n"); } - - goto leave; - - bailout: - log_error ( "data error at \"%s\", offset %u\n", - where, (unsigned int)((p - p_start) + startoffset)); - err = gpg_error (GPG_ERR_GENERAL); + else if (gpg_err_code (err) == GPG_ERR_INV_OBJ) + tlv_set_pending (tlv); /* The next tlv_next will be skipped. */ + else + goto bailout; leave: - if (r_consumed) - *r_consumed = consumed; return err; + + bailout: + log_error ("%s(%s): offset %u.%zu (%s): %s - %s\n", + __func__, where, + tlv? tlv->stacklen : 0, + tlv? tlv->offset : 0, + tlv? tlv->lastfunc : "", + tlv ? gpg_strerror (tlv->lasterr) : "init failed", + gpg_strerror (err)); + if (!err) + err = gpg_error (GPG_ERR_GENERAL); + goto leave; } static gpg_error_t -parse_bag_data (struct p12_parse_ctx_s *ctx, - const unsigned char *buffer, size_t length, int startoffset, - size_t *r_consumed) +parse_bag_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv) { gpg_error_t err = 0; - struct tag_info ti; - const unsigned char *p = buffer; - const unsigned char *p_start = buffer; - size_t n = length; const char *where; - unsigned char *cram_buffer = NULL; - size_t consumed = 0; /* Number of bytes consumed from the original buffer. */ + int intval; + const unsigned char *oid; + size_t oidlen; + unsigned int startlevel; + + if (opt_verbose) + log_info ("processing bag data\n"); /* Expect: * [0] * OCTET STRING, encapsulates */ where = "data"; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (ti.class != CLASS_CONTEXT || ti.tag) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_OCTET_STRING) + if (tlv_expect_context_tag (tlv, &intval) || intval != 0 ) goto bailout; + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_octet_string (tlv, 1, NULL, NULL)) + goto bailout; - consumed = p - p_start; - if (ti.is_constructed && ti.ndef) - { - /* Mozilla exported certs now come with single byte chunks of - octet strings. (Mozilla Firefox 1.0.4). Arghh. */ - where = "data.cram_os"; - cram_buffer = cram_octet_string ( p, &n, &consumed); - if (!cram_buffer) - goto bailout; - p = p_start = cram_buffer; - if (r_consumed) - *r_consumed = consumed; - r_consumed = NULL; /* Ugly hack to not update that value on return. */ - } /* Expect: * SEQUENCE - * SEQUENCE */ - where = "data.2seqs"; - if (parse_tag (&p, &n, &ti)) + where = "data.outerseqs"; + if (tlv_next (tlv)) goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_SEQUENCE) + if (tlv_expect_sequence (tlv)) goto bailout; - /* Expect: - * OBJECT IDENTIFIER - */ - where = "data.oid"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class || ti.tag != TAG_OBJECT_ID) - goto bailout; - - /* Now divert to the actual parser. */ - if (ti.length == DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag) - && !memcmp (p, oid_pkcs_12_pkcs_8ShroudedKeyBag, - DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag))) + startlevel = tlv_level (tlv); + while (!(err = tlv_next (tlv)) && tlv_level (tlv) == startlevel) { - p += DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag); - n -= DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag); - - if (parse_shrouded_key_bag (ctx, p, n, - startoffset + (p - p_start), r_consumed)) + /* Expect: + * SEQUENCE + */ + where = "data.innerseqs"; + if (tlv_expect_sequence (tlv)) goto bailout; - } - else if ( ti.length == DIM(oid_pkcs_12_CertBag) - && !memcmp (p, oid_pkcs_12_CertBag, DIM(oid_pkcs_12_CertBag))) - { - p += DIM(oid_pkcs_12_CertBag); - n -= DIM(oid_pkcs_12_CertBag); - if (parse_cert_bag (ctx, p, n, - startoffset + (p - p_start), r_consumed)) + /* Expect: + * OBJECT IDENTIFIER + */ + where = "data.oid"; + if (tlv_next (tlv)) goto bailout; + if (tlv_expect_object_id (tlv, &oid, &oidlen)) + goto bailout; + + /* Divert to the actual parser. */ + if (oidlen == DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag) + && !memcmp (oid, oid_pkcs_12_pkcs_8ShroudedKeyBag, + DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag))) + { + if ((err = parse_shrouded_key_bag (ctx, tlv))) + goto bailout; + } + else if (oidlen == DIM(oid_pkcs_12_CertBag) + && !memcmp (oid, oid_pkcs_12_CertBag, DIM(oid_pkcs_12_CertBag))) + { + if ((err = parse_cert_bag (ctx, tlv))) + goto bailout; + } + else + { + tlv_skip (tlv); + log_info ("unknown inner data type - skipped\n"); + } } - else + if (err && gpg_err_code (err) != GPG_ERR_EOF) goto bailout; - - goto leave; - - bailout: - log_error ( "data error at \"%s\", offset %u\n", - where, (unsigned int)((p - p_start) + startoffset)); - err = gpg_error (GPG_ERR_GENERAL); + err = 0; + if (tlv_popped (tlv)) + tlv_set_pending (tlv); leave: - gcry_free (cram_buffer); - if (r_consumed) /* Store the number of consumed bytes unless already done. */ - *r_consumed = consumed; return err; + + bailout: + if (!err) + err = gpg_error (GPG_ERR_GENERAL); + log_error ("%s(%s): offset %u.%zu (%s): %s - %s\n", + __func__, where, + tlv? tlv->stacklen : 0, + tlv? tlv->offset : 0, + tlv? tlv->lastfunc : "", + tlv ? gpg_strerror (tlv->lasterr) : "init failed", + gpg_strerror (err)); + goto leave; } @@ -1772,7 +2260,7 @@ parse_bag_data (struct p12_parse_ctx_s *ctx, secret key parameters. This is a very limited implementation in that it is only able to look for 3DES encoded encryptedData and tries to extract the first private key object it finds. In case of - an error NULL is returned. CERTCB and CERRTCBARG are used to pass + an error NULL is returned. CERTCB and CERTCBARG are used to pass X.509 certificates back to the caller. If R_CURVE is not NULL and an ECC key was found the OID of the curve is stored there. */ gcry_mpi_t * @@ -1780,16 +2268,14 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw, void (*certcb)(void*, const unsigned char*, size_t), void *certcbarg, int *r_badpass, char **r_curve) { - struct tag_info ti; - const unsigned char *p = buffer; - const unsigned char *p_start = buffer; - size_t n = length; + gpg_error_t err; const char *where; - int bagseqlength, len; - int bagseqndef, lenndef; - unsigned char *cram_buffer = NULL; - size_t consumed; + struct tlv_ctx_s *tlv; struct p12_parse_ctx_s ctx = { NULL }; + const unsigned char *oid; + size_t oidlen; + int intval; + unsigned int startlevel; *r_badpass = 0; @@ -1797,146 +2283,111 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw, ctx.certcbarg = certcbarg; ctx.password = pw; + tlv = tlv_new (buffer, length); + if (!tlv) + { + err = gpg_error_from_syserror (); + goto bailout; + } where = "pfx"; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (ti.tag != TAG_SEQUENCE) + if (tlv_expect_sequence (tlv)) goto bailout; where = "pfxVersion"; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (ti.tag != TAG_INTEGER || ti.length != 1 || *p != 3) + if (tlv_expect_integer (tlv, &intval) || intval != 3) goto bailout; - p++; n--; where = "authSave"; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (ti.tag != TAG_SEQUENCE) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.tag != TAG_OBJECT_ID || ti.length != DIM(oid_data) - || memcmp (p, oid_data, DIM(oid_data))) - goto bailout; - p += DIM(oid_data); - n -= DIM(oid_data); - - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class != CLASS_CONTEXT || ti.tag) - goto bailout; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (ti.class != CLASS_UNIVERSAL || ti.tag != TAG_OCTET_STRING) + if (tlv_expect_sequence (tlv)) goto bailout; - if (ti.is_constructed && ti.ndef) + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_object_id (tlv, &oid, &oidlen)) + goto bailout; + if (oidlen != DIM(oid_data) || memcmp (oid, oid_data, DIM(oid_data))) + goto bailout; + + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_context_tag (tlv, &intval) || intval != 0 ) + goto bailout; + + if (tlv_next (tlv)) + goto bailout; + if (tlv->ti.is_constructed && tlv->ti.ndef) { - /* Mozilla exported certs now come with single byte chunks of - octet strings. (Mozilla Firefox 1.0.4). Arghh. */ - where = "cram-bags"; - cram_buffer = cram_octet_string ( p, &n, NULL); - if (!cram_buffer) - goto bailout; - p = p_start = cram_buffer; + log_debug ("FIXME Put this into our TLV machinery.\n"); + /* /\* Mozilla exported certs now come with single byte chunks of */ + /* octet strings. (Mozilla Firefox 1.0.4). Arghh. *\/ */ + /* where = "cram-bags"; */ + /* cram_buffer = cram_octet_string ( p, &n, NULL); */ + /* if (!cram_buffer) */ + /* goto bailout; */ + /* p = p_start = cram_buffer; */ } + if (tlv_expect_octet_string (tlv, 1, NULL, NULL)) + goto bailout; + where = "bags"; - if (parse_tag (&p, &n, &ti)) + if (tlv_next (tlv)) goto bailout; - if (ti.class != CLASS_UNIVERSAL || ti.tag != TAG_SEQUENCE) + if (tlv_expect_sequence (tlv)) goto bailout; - bagseqndef = ti.ndef; - bagseqlength = ti.length; - while (bagseqlength || bagseqndef) + + startlevel = tlv_level (tlv); + while (!(err = tlv_next (tlv)) && tlv_level (tlv) == startlevel) { - /* log_debug ("p12_parse: at offset %ld\n", (p - p_start)); */ where = "bag-sequence"; - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (bagseqndef && ti.class == CLASS_UNIVERSAL - && !ti.tag && !ti.is_constructed) - break; /* Ready */ - if (ti.class != CLASS_UNIVERSAL || ti.tag != TAG_SEQUENCE) + if (tlv_expect_sequence (tlv)) goto bailout; - if (!bagseqndef) + if (tlv_next (tlv)) + goto bailout; + if (tlv_expect_object_id (tlv, &oid, &oidlen)) + goto bailout; + + if (oidlen == DIM(oid_encryptedData) + && !memcmp (oid, oid_encryptedData, DIM(oid_encryptedData))) { - if (bagseqlength < ti.nhdr) - goto bailout; - bagseqlength -= ti.nhdr; - if (bagseqlength < ti.length) - goto bailout; - bagseqlength -= ti.length; - } - lenndef = ti.ndef; - len = ti.length; - - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (lenndef) - len = ti.nhdr; - else - len -= ti.nhdr; - - if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_encryptedData) - && !memcmp (p, oid_encryptedData, DIM(oid_encryptedData))) - { - - p += DIM(oid_encryptedData); - n -= DIM(oid_encryptedData); - if (!lenndef) - len -= DIM(oid_encryptedData); where = "bag.encryptedData"; - consumed = 0; - if (parse_bag_encrypted_data (&ctx, p, n, (p - p_start), &consumed)) - { - *r_badpass = ctx.badpass; - goto bailout; - } - if (lenndef) - len += consumed; - } - else if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_data) - && !memcmp (p, oid_data, DIM(oid_data))) - { - p += DIM(oid_data); - n -= DIM(oid_data); - if (!lenndef) - len -= DIM(oid_data); - - where = "bag.data"; - consumed = 0; - if (parse_bag_data (&ctx, p, n, (p - p_start), &consumed)) + if ((err=parse_bag_encrypted_data (&ctx, tlv))) + goto bailout; + } + else if (oidlen == DIM(oid_data) + && !memcmp (oid, oid_data, DIM(oid_data))) + { + where = "bag.data"; + if ((err=parse_bag_data (&ctx, tlv))) + goto bailout; + } + else if (oidlen == DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag) + && !memcmp (oid, oid_pkcs_12_pkcs_8ShroudedKeyBag, + DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag))) + { + where = "bag.shroudedkeybag"; + if ((err = parse_shrouded_key_bag (&ctx, tlv))) goto bailout; - if (lenndef) - len += consumed; } else { + tlv_skip (tlv); log_info ("unknown outer bag type - skipped\n"); - p += ti.length; - n -= ti.length; - } - - if (len < 0 || len > n) - goto bailout; - p += len; - n -= len; - if (lenndef) - { - /* Need to skip the Null Tag. */ - if (parse_tag (&p, &n, &ti)) - goto bailout; - if (!(ti.class == CLASS_UNIVERSAL && !ti.tag && !ti.is_constructed)) - goto bailout; } } + if (err && gpg_err_code (err) != GPG_ERR_EOF) + goto bailout; + err = 0; - gcry_free (cram_buffer); + tlv_release (tlv); if (r_curve) *r_curve = ctx.curve; else @@ -1945,8 +2396,14 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw, return ctx.privatekey; bailout: - log_error ("error at \"%s\", offset %u\n", - where, (unsigned int)(p - p_start)); + *r_badpass = ctx.badpass; + log_error ("%s(%s): offset %u.%zu (%s): %s - %s\n", + __func__, where, + tlv? tlv->stacklen : 0, + tlv? tlv->offset : 0, + tlv? tlv->lastfunc : "", + tlv ? gpg_strerror (tlv->lasterr) : "init failed", + gpg_strerror (err)); if (ctx.privatekey) { int i; @@ -1956,7 +2413,7 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw, gcry_free (ctx.privatekey); ctx.privatekey = NULL; } - gcry_free (cram_buffer); + tlv_release (tlv); gcry_free (ctx.curve); if (r_curve) *r_curve = NULL; diff --git a/sm/minip12.h b/sm/minip12.h index 84c5f5f79..654cab0e6 100644 --- a/sm/minip12.h +++ b/sm/minip12.h @@ -23,7 +23,7 @@ #include -void p12_set_verbosity (int verbose); +void p12_set_verbosity (int verbose, int debug); gcry_mpi_t *p12_parse (const unsigned char *buffer, size_t length, const char *pw, diff --git a/sm/t-minip12.c b/sm/t-minip12.c index 97bbcb9dc..80ba4c69e 100644 --- a/sm/t-minip12.c +++ b/sm/t-minip12.c @@ -1,5 +1,5 @@ /* t-minip12.c - Test driver for minip12.c - * Copyright (C) 2020 g10 Code GmbH + * Copyright (C) 2020, 2023 g10 Code GmbH * * This file is part of GnuPG. * @@ -15,6 +15,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see . + * SPDX-License-Identifier: GPL-3.0-or-later */ #include @@ -22,6 +23,8 @@ #include #include #include +#include +#include #include "../common/util.h" #include "minip12.h" @@ -31,7 +34,336 @@ static int verbose; static int debug; +static int any_error; +static void die (const char *format, ...) GPGRT_ATTR_NR_PRINTF(1,2); +static void err (const char *format, ...) GPGRT_ATTR_PRINTF(1,2); +static void inf (const char *format, ...) GPGRT_ATTR_PRINTF(1,2); +/* static void dbg (const char *format, ...) GPGRT_ATTR_PRINTF(1,2); */ +static void printresult (const char *format, ...) GPGRT_ATTR_PRINTF(1,2); +static char *my_xstrconcat (const char *s1, ...) GPGRT_ATTR_SENTINEL(0); + +#define xstrconcat my_xstrconcat +#define trim_spaces(a) my_trim_spaces ((a)) +#define my_isascii(c) (!((c) & 0x80)) + + + + + +/* Print diagnostic message and exit with failure. */ +static void +die (const char *format, ...) +{ + va_list arg_ptr; + + fflush (stdout); + fprintf (stderr, "%s: ", PGM); + + va_start (arg_ptr, format); + vfprintf (stderr, format, arg_ptr); + va_end (arg_ptr); + if (!*format || format[strlen(format)-1] != '\n') + putc ('\n', stderr); + + exit (1); +} + + +/* Print diagnostic message. */ +static void +err (const char *format, ...) +{ + va_list arg_ptr; + + any_error = 1; + + fflush (stdout); + fprintf (stderr, "%s: ", PGM); + + va_start (arg_ptr, format); + vfprintf (stderr, format, arg_ptr); + va_end (arg_ptr); + if (!*format || format[strlen(format)-1] != '\n') + putc ('\n', stderr); +} + + +/* Print an info message. */ +static void +inf (const char *format, ...) +{ + va_list arg_ptr; + + if (verbose) + { + fprintf (stderr, "%s: ", PGM); + + va_start (arg_ptr, format); + vfprintf (stderr, format, arg_ptr); + va_end (arg_ptr); + if (!*format || format[strlen(format)-1] != '\n') + putc ('\n', stderr); + } +} + + +/* Print a debug message. */ +/* static void */ +/* dbg (const char *format, ...) */ +/* { */ +/* va_list arg_ptr; */ + +/* if (debug) */ +/* { */ +/* fprintf (stderr, "%s: DBG: ", PGM); */ + +/* va_start (arg_ptr, format); */ +/* vfprintf (stderr, format, arg_ptr); */ +/* va_end (arg_ptr); */ +/* if (!*format || format[strlen(format)-1] != '\n') */ +/* putc ('\n', stderr); */ +/* } */ +/* } */ + + +/* Print a result line to stdout. */ +static void +printresult (const char *format, ...) +{ + va_list arg_ptr; + + fflush (stdout); +#ifdef HAVE_FLOCKFILE + flockfile (stdout); +#endif + va_start (arg_ptr, format); + vfprintf (stdout, format, arg_ptr); + if (*format && format[strlen(format)-1] != '\n') + putc ('\n', stdout); + va_end (arg_ptr); + fflush (stdout); +#ifdef HAVE_FLOCKFILE + funlockfile (stdout); +#endif +} + + +/* Helper for xstrconcat and strconcat. */ +static char * +do_strconcat (int xmode, const char *s1, va_list arg_ptr) +{ + const char *argv[48]; + size_t argc; + size_t needed; + char *buffer, *p; + + argc = 0; + argv[argc++] = s1; + needed = strlen (s1); + while (((argv[argc] = va_arg (arg_ptr, const char *)))) + { + needed += strlen (argv[argc]); + if (argc >= DIM (argv)-1) + die ("too may args for strconcat\n"); + argc++; + } + needed++; + buffer = xmode? xmalloc (needed) : malloc (needed); + for (p = buffer, argc=0; argv[argc]; argc++) + p = stpcpy (p, argv[argc]); + + return buffer; +} + + +/* Concatenate the string S1 with all the following strings up to a + NULL. Returns a malloced buffer with the new string or dies on error. */ +static char * +my_xstrconcat (const char *s1, ...) +{ + va_list arg_ptr; + char *result; + + if (!s1) + result = xstrdup (""); + else + { + va_start (arg_ptr, s1); + result = do_strconcat (1, s1, arg_ptr); + va_end (arg_ptr); + } + return result; +} + + +static char * +my_trim_spaces (char *str ) +{ + char *string, *p, *mark; + + string = str; + for (p=string; *p && isspace (*(unsigned char *)p) ; p++) + ; + for (mark=NULL; (*string = *p); string++, p++ ) + if (isspace (*(unsigned char *)p)) + { + if (!mark) + mark = string; + } + else + mark = NULL; + if (mark) + *mark = '\0'; + + return str ; +} + + +/* Prepend FNAME with the srcdir environment variable's value and + * return an allocated filename. */ +static char * +prepend_srcdir (const char *fname) +{ + static const char *srcdir; + + if (!srcdir && !(srcdir = getenv ("srcdir"))) + return xstrdup (fname); + else + return xstrconcat (srcdir, "/", fname, NULL); +} + + +/* (BUFFER,BUFLEN) and return a malloced hexstring. */ +static char * +hash_buffer (const void *buffer, size_t buflen) +{ + unsigned char hash[20]; + char *result; + int i; + + gcry_md_hash_buffer (GCRY_MD_SHA1, hash, buffer, buflen); + result = xmalloc (41); + for (i=0; i < 20; i++) + snprintf (result + 2*i, 3, "%02x", hash[i]); + return result; +} + + +/* Read next line but skip over empty and comment lines. Caller must + xfree the result. */ +static char * +read_textline (FILE *fp, int *lineno) +{ + char line[4096]; + char *p; + + do + { + if (!fgets (line, sizeof line, fp)) + { + if (feof (fp)) + return NULL; + die ("error reading input line: %s\n", strerror (errno)); + } + ++*lineno; + p = strchr (line, '\n'); + if (!p) + die ("input line %d not terminated or too long\n", *lineno); + *p = 0; + for (p--;p > line && my_isascii (*p) && isspace (*p); p--) + *p = 0; + } + while (!*line || *line == '#'); + return xstrdup (line); +} + + +/* Copy the data after the tag to BUFFER. BUFFER will be allocated as + needed. */ +static void +copy_data (char **buffer, const char *line, int lineno) +{ + const char *s; + + xfree (*buffer); + *buffer = NULL; + + s = strchr (line, ':'); + if (!s) + { + err ("syntax error at input line %d", lineno); + return; + } + for (s++; my_isascii (*s) && isspace (*s); s++) + ; + *buffer = xstrdup (s); +} + + +static void +hexdowncase (char *string) +{ + char *p; + + if (string) + for (p=string; *p; p++) + if (my_isascii (*p)) + *p = tolower (*p); +} + + +/* Return the value of the variable VARNAME from ~/.gnupg-autogen.rc + * or NULL if it does not exists or is empty. */ +static char * +value_from_gnupg_autogen_rc (const char *varname) +{ + const char *home; + char *fname; + FILE *fp; + char *line = NULL; + char *p; + int lineno = 0; + + if (!(home = getenv ("HOME"))) + home = ""; + fname = xstrconcat (home, "/.gnupg-autogen.rc", NULL); + fp = fopen (fname, "r"); + if (!fp) + goto leave; + + while ((line = read_textline (fp, &lineno))) + { + p = strchr (line, '='); + if (p) + { + *p++ = 0; + trim_spaces (line); + if (!strcmp (line, varname)) + { + trim_spaces (p); + if (*p) + { + memmove (line, p, strlen (p)+1); + if (*line == '~' && line[1] == '/') + { + p = xstrconcat (home, line+1, NULL); + xfree (line); + line = p; + } + break; /* found. */ + } + } + } + xfree (line); + } + + leave: + if (fp) + fclose (fp); + xfree (fname); + return line; +} static void @@ -45,13 +377,10 @@ cert_cb (void *opaque, const unsigned char *cert, size_t certlen) } - -int -main (int argc, char **argv) +/* Parse one PKCS#12 file. Returns zero on success. */ +static int +one_file (const char *name, const char *pass) { - int last_argc = -1; - char const *name = NULL; - char const *pass = NULL; FILE *fp; struct stat st; unsigned char *buf; @@ -60,63 +389,6 @@ main (int argc, char **argv) int badpass; char *curve = NULL; - if (argc) - { argc--; argv++; } - while (argc && last_argc != argc ) - { - last_argc = argc; - if (!strcmp (*argv, "--")) - { - argc--; argv++; - break; - } - else if (!strcmp (*argv, "--help")) - { - fputs ("usage: " PGM " []\n" - "Options:\n" - " --verbose print timings etc.\n" - " --debug flyswatter\n" - , stdout); - exit (0); - } - else if (!strcmp (*argv, "--verbose")) - { - verbose++; - argc--; argv++; - } - else if (!strcmp (*argv, "--debug")) - { - verbose += 2; - debug++; - argc--; argv++; - } - else if (!strncmp (*argv, "--", 2)) - { - fprintf (stderr, PGM ": unknown option '%s'\n", *argv); - exit (1); - } - } - - if (argc == 1) - { - name = argv[0]; - pass = ""; - } - else if (argc == 2) - { - name = argv[0]; - pass = argv[1]; - } - else - { - fprintf (stderr, "usage: " PGM " []\n"); - exit (1); - } - - gcry_control (GCRYCTL_DISABLE_SECMEM, NULL); - gcry_control (GCRYCTL_INITIALIZATION_FINISHED, NULL); - - fp = fopen (name, "rb"); if (!fp) { @@ -131,8 +403,8 @@ main (int argc, char **argv) } buflen = st.st_size; - buf = gcry_malloc (buflen+1); - if (!buf || fread (buf, buflen, 1, fp) != 1) + buf = xmalloc (buflen+1); + if (fread (buf, buflen, 1, fp) != 1) { fprintf (stderr, "error reading '%s': %s\n", name, strerror (errno)); return 1; @@ -160,6 +432,344 @@ main (int argc, char **argv) } } } + if (badpass) + log_error ("Bad password given?\n"); + xfree (buf); return 0; } + + +static void +cert_collect_cb (void *opaque, const unsigned char *cert, size_t certlen) +{ + char **certstr = opaque; + char *hash; + + hash = hash_buffer (cert, certlen); + if (*certstr) + { + *certstr = xstrconcat (*certstr, ",", hash, NULL); + xfree (hash); + } + else + *certstr = hash; +} + + +static int +run_one_test (const char *name, const char *desc, const char *pass, + const char *certexpected, const char *keyexpected) +{ + FILE *fp; + struct stat st; + unsigned char *buf; + size_t buflen; + gcry_mpi_t *result; + int badpass; + char *curve = NULL; + char *resulthash = NULL; + char *p; + char *certstr = NULL; + int ret; + + inf ("testing '%s' (%s)", name , desc? desc:""); + fp = fopen (name, "rb"); + if (!fp) + { + err ("can't open '%s': %s\n", name, strerror (errno)); + printresult ("FAIL: %s - test file not found\n", name); + return 1; + } + + if (fstat (fileno (fp), &st)) + { + err ("can't stat '%s': %s\n", name, strerror (errno)); + printresult ("FAIL: %s - error stating test file\n", name); + fclose (fp); + return 1; + } + + buflen = st.st_size; + buf = xmalloc (buflen+1); + if (fread (buf, buflen, 1, fp) != 1) + { + err ("error reading '%s': %s\n", name, strerror (errno)); + printresult ("FAIL: %s - error reading test file\n", name); + fclose (fp); + xfree (buf); + return 1; + } + fclose (fp); + + result = p12_parse (buf, buflen, pass? pass:"", cert_collect_cb, &certstr, + &badpass, &curve); + if (result) + { + int i, rc; + char *tmpstring; + unsigned char *tmpbuf; + char numbuf[20]; + + if (curve) + { + if (verbose > 1) + inf ("curve: %s\n", curve); + tmpstring = xstrconcat ("curve:", curve, "\n", NULL); + } + else + tmpstring = xstrdup ("\n"); + for (i=0; result[i]; i++) + { + rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, &tmpbuf, NULL, result[i]); + if (rc) + die ("result %d: [error printing number: %s]\n", + i, gpg_strerror (rc)); + else + { + if (verbose > 1) + inf ("result %d: %s\n", i, tmpbuf); + snprintf (numbuf, sizeof numbuf, "%d:", i); + p = xstrconcat (tmpstring, numbuf, tmpbuf, "\n", NULL); + xfree (tmpstring); + tmpstring = p; + gcry_free (tmpbuf); + } + } + + resulthash = hash_buffer (tmpstring, strlen (tmpstring)); + xfree (tmpstring); + } + + if (verbose > 1) + { + inf ("cert(exp)=%s", certexpected); + inf ("cert(got)=%s", certstr? certstr:"[null]"); + inf ("key(exp)=%s", keyexpected); + inf ("key(got)=%s", resulthash? resulthash:"[null]"); + } + + ret = 1; + if (!result) + printresult ("FAIL: %s - error from parser\n", name); + else if (certexpected && !certstr) + printresult ("FAIL: %s - expected certs but got none\n", name); + else if (!certexpected && certstr) + printresult ("FAIL: %s - no certs expected but got one\n", name); + else if (certexpected && certstr && strcmp (certexpected, certstr)) + printresult ("FAIL: %s - certs not as expected\n", name); + else if (keyexpected && !resulthash) + printresult ("FAIL: %s - expected key but got none\n", name); + else if (!keyexpected && resulthash) + printresult ("FAIL: %s - key not expected but got one\n", name); + else if (keyexpected && resulthash && strcmp (keyexpected, resulthash)) + printresult ("FAIL: %s - keys not as expected\n", name); + else + { + printresult ("PASS: %s\n", name); + ret = 0; + } + + if (result) + { + int i; + for (i=0; result[i]; i++) + gcry_mpi_release (result[i]); + gcry_free (result); + } + xfree (certstr); + xfree (resulthash); + xfree (curve); + xfree (buf); + return ret; +} + + +/* Run a regression test using the Info take from DESCFNAME. */ +static int +run_tests_from_file (const char *descfname) +{ + FILE *fp; + char *descdir; + int lineno, ntests; + char *line; + char *name = NULL; + char *desc = NULL; + char *pass = NULL; + char *cert = NULL; + char *key = NULL; + int ret = 0; + char *p; + + inf ("Running tests from '%s'", descfname); + descdir = xstrdup (descfname); + p = strrchr (descdir, '/'); + if (p) + *p = 0; + else + { + xfree (descdir); + descdir = xstrdup ("."); + } + + fp = fopen (descfname, "r"); + if (!fp) + die ("error opening '%s': %s\n", descfname, strerror (errno)); + + lineno = ntests = 0; + while ((line = read_textline (fp, &lineno))) + { + if (!strncmp (line, "Name:", 5)) + { + if (name) + ret |= run_one_test (name, desc, pass, cert, key); + xfree (cert); cert = NULL; + xfree (desc); desc = NULL; + xfree (pass); pass = NULL; + xfree (key); key = NULL; + copy_data (&name, line, lineno); + if (name) + { + p = xstrconcat (descdir, "/", name, NULL); + xfree (name); + name = p; + } + } + else if (!strncmp (line, "Desc:", 5)) + copy_data (&desc, line, lineno); + else if (!strncmp (line, "Pass:", 5)) + copy_data (&pass, line, lineno); + else if (!strncmp (line, "Cert:", 5)) + { + p = NULL; + copy_data (&p, line, lineno); + hexdowncase (p); + if (p && cert) + cert = xstrconcat (cert, ",", p, NULL); + else + cert = p; + } + else if (!strncmp (line, "Key:", 4)) + { + copy_data (&key, line, lineno); + hexdowncase (key); + } + else + inf ("%s:%d: unknown tag ignored", descfname, lineno); + + xfree (line); + } + if (name) + ret |= run_one_test (name, desc, pass, cert, key); + xfree (name); + xfree (desc); + xfree (pass); + xfree (cert); + xfree (key); + + fclose (fp); + xfree (descdir); + return ret; +} + + + +int +main (int argc, char **argv) +{ + int last_argc = -1; + char const *name = NULL; + char const *pass = NULL; + int ret; + + if (argc) + { argc--; argv++; } + while (argc && last_argc != argc ) + { + last_argc = argc; + if (!strcmp (*argv, "--")) + { + argc--; argv++; + break; + } + else if (!strcmp (*argv, "--help")) + { + fputs ("usage: " PGM " []\n" + "Without a regression test is run\n" + "Options:\n" + " --verbose print timings etc.\n" + " given twice shows more\n" + " --debug flyswatter\n" + , stdout); + exit (0); + } + else if (!strcmp (*argv, "--verbose")) + { + verbose++; + argc--; argv++; + } + else if (!strcmp (*argv, "--debug")) + { + verbose += 2; + debug++; + argc--; argv++; + } + else if (!strncmp (*argv, "--", 2)) + { + fprintf (stderr, PGM ": unknown option '%s'\n", *argv); + exit (1); + } + } + + if (!argc) + { + name = NULL; + pass = NULL; + } + else if (argc == 1) + { + name = argv[0]; + pass = ""; + } + else if (argc == 2) + { + name = argv[0]; + pass = argv[1]; + } + else + { + fprintf (stderr, "usage: " PGM " [ []]\n"); + exit (1); + } + + gcry_control (GCRYCTL_DISABLE_SECMEM, NULL); + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, NULL); + + if (name) + { + p12_set_verbosity (verbose, debug); + ret = one_file (name, pass); + } + else + { + char *descfname, *p; + + if (verbose > 1) + p12_set_verbosity (verbose > 1? (verbose - 1):0, debug); + descfname = prepend_srcdir ("../tests/cms/samplekeys/Description-p12"); + ret = run_tests_from_file (descfname); + xfree (descfname); + + /* Check whether we have non-public regression test cases. */ + p = value_from_gnupg_autogen_rc ("GNUPG_EXTRA_TESTS_DIR"); + if (p) + { + descfname = xstrconcat (p, "/pkcs12/Description", NULL); + xfree (p); + ret |= run_tests_from_file (descfname); + xfree (descfname); + } + } + + return ret; +} diff --git a/tests/cms/samplekeys/Description-p12 b/tests/cms/samplekeys/Description-p12 new file mode 100644 index 000000000..bd1e35c91 --- /dev/null +++ b/tests/cms/samplekeys/Description-p12 @@ -0,0 +1,20 @@ +# Description-p12 - Machine readable description of our P12 test vectors + +Name: ov-user.p12 +Desc: Private test key from www.openvalidation.org +Pass: start +Cert: 4753a910e0c8b4caa8663ca0e4273a884eb5397d +Key: 93be89edd11214ab74280d988a665b6beef876c5 + +Name: ov-server.p12 +Desc: Private test key from www.openvalidation.org +Pass: start +Cert: 1997fadf6cc1af03e4845c4cba38fb2397315143 +Key: 63b1d7233e75c3a462cb4b8ea3ad285e8ecba91c + +Name: opensc-test.p12 +Desc: PKCS#12 key and certificates taken from OpenSC (RC2+3DES,PKCS#8) +Pass: password +Cert: 115abfc3ae554092a57ade74177fedf9459af5d2 +Cert: a0d6d318952c313ff8c33cd3f629647ff1de76b3 +Key: 5a36c61706367ecdb52e8779e3a32bbac1069fa1 diff --git a/tests/cms/samplekeys/README b/tests/cms/samplekeys/README index 65255cb61..14bbf2bdc 100644 --- a/tests/cms/samplekeys/README +++ b/tests/cms/samplekeys/README @@ -1,10 +1,5 @@ This is a collection of keys we use with the regression tests. - -opensc-tests.p12 PKCS#12 key and certificates taken from OpenSC. - Passphrase is "password" - -ov-user.p12 Private tests keys from www.openvalidation.org. -ov-server.p12 Passphrase for both is "start" +For the *.p12 files see Description-p12 ossl-rentec-user.pem An OpenSSL generated user certificate using a bunch of attributes and DC RDNs. @@ -21,4 +16,3 @@ steed-self-signing-nonthority.pem The STEED Self-Signing Nonthority. 68A638998DFABAC510EA645CE34F9686B2EDF7EA.key The private Key of The STEED Self-Signing Nonthority. - From 5f694dc0be994e8cd3bc009139d1349f3b1fcf62 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 29 Jun 2023 16:33:03 +0200 Subject: [PATCH 48/56] sm: Adding missing stuff to the PKCS#12 parser rewrite. * sm/minip12.c (struct bufferlist_s): New. (struct tlv_ctx_s): Add bufferlist. (tlv_register_buffer): New. (tlv_release): Release bufferlist. (tlv_expect_object): Handle octet string cramming. (tlv_expect_octet_string): Ditto. (cram_octet_string): Changed interface. We don't need the input_consumed value anymore. * sm/minip12.c (parse_shrouded_key_bag): Also parse the attribute set. * sm/t-minip12.c (main): Add option --no-extra. (cert_collect_cb, run_tests_from_file): Fix memory leak * tests/cms/samplekeys/t5793-openssl.pfx: New from T5793. * tests/cms/samplekeys/t5793-test.pfx: Ditto. * tests/cms/samplekeys/Description-p12: Add them. * tests/cms/Makefile.am (EXTRA_DIST): Add samplekeys. -- This should finish the rewrite of the pkcsc#12 parser for now. More fun is likely to come. GnuPG-bug-id: 6536, 5793 --- sm/minip12.c | 238 ++++++++++++++++--------- sm/t-minip12.c | 22 ++- tests/cms/Makefile.am | 8 +- tests/cms/samplekeys/Description-p12 | 12 ++ tests/cms/samplekeys/t5793-openssl.pfx | Bin 0 -> 4285 bytes tests/cms/samplekeys/t5793-test.pfx | Bin 0 -> 4328 bytes 6 files changed, 190 insertions(+), 90 deletions(-) create mode 100644 tests/cms/samplekeys/t5793-openssl.pfx create mode 100644 tests/cms/samplekeys/t5793-test.pfx diff --git a/sm/minip12.c b/sm/minip12.c index 69e23455a..eafebfe67 100644 --- a/sm/minip12.c +++ b/sm/minip12.c @@ -148,6 +148,14 @@ struct tag_info #define TLV_MAX_DEPTH 20 + +struct bufferlist_s +{ + struct bufferlist_s *next; + char *buffer; +}; + + /* An object to control the ASN.1 parsing. */ struct tlv_ctx_s { @@ -163,6 +171,8 @@ struct tlv_ctx_s gpg_error_t lasterr; /* Last error from tlv function. */ const char *lastfunc;/* Name of last called function. */ + struct bufferlist_s *bufferlist; /* To keep track of amlloced buffers. */ + unsigned int pop_count;/* Number of pops by tlv_next. */ unsigned int stacklen; /* Used size of the stack. */ struct { @@ -198,6 +208,12 @@ struct p12_parse_ctx_s static int opt_verbose; +static unsigned char *cram_octet_string (const unsigned char *input, + size_t length, size_t *r_newlength); + + + + void p12_set_verbosity (int verbose, int debug) { @@ -354,9 +370,36 @@ tlv_new (const unsigned char *buffer, size_t bufsize) } +/* This function can be used to store a malloced buffer into the TLV + * object. Ownership of BUFFER is thus transferred to TLV. This + * buffer will then only be released by tlv_release. */ +static gpg_error_t +tlv_register_buffer (struct tlv_ctx_s *tlv, char *buffer) +{ + struct bufferlist_s *item; + + item = xtrycalloc (1, sizeof *item); + if (!item) + return gpg_error_from_syserror (); + item->buffer = buffer; + item->next = tlv->bufferlist; + tlv->bufferlist = item; + return 0; +} + + static void tlv_release (struct tlv_ctx_s *tlv) { + if (!tlv) + return; + while (tlv->bufferlist) + { + struct bufferlist_s *save = tlv->bufferlist->next; + xfree (tlv->bufferlist->buffer); + xfree (tlv->bufferlist); + tlv->bufferlist = save; + } xfree (tlv); } @@ -457,7 +500,8 @@ tlv_next (struct tlv_ctx_s *tlv) /* End tag while in ndef container. Skip the tag, and pop. */ tlv->offset += n - (tlv->bufsize - tlv->offset); err = _tlv_pop (tlv); - // FIXME see above and run peek again. + /* FIXME: We need to peek whether there is another end tag and + * pop again. We can't modify the TLV object, though. */ if (err) return (tlv->lasterr = err); } @@ -558,24 +602,42 @@ tlv_expect_set (struct tlv_ctx_s *tlv) /* Expect an object of CLASS with TAG and store its value at * (R_DATA,R_DATALEN). Then skip over its value to the next tag. - * Note that the stored value are not allocated but point into + * Note that the stored value is not allocated but points into * TLV. */ static gpg_error_t tlv_expect_object (struct tlv_ctx_s *tlv, int class, int tag, unsigned char const **r_data, size_t *r_datalen) { + gpg_error_t err; const unsigned char *p; tlv->lastfunc = __func__; - if (!(tlv->ti.class == class && tlv->ti.tag == tag - && !tlv->ti.is_constructed)) + if (!(tlv->ti.class == class && tlv->ti.tag == tag)) return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ)); p = tlv->buffer + tlv->offset; if (!tlv->ti.length) return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT)); - *r_data = p; - *r_datalen = tlv->ti.length; + if (class == CLASS_CONTEXT && tag == 0 && tlv->ti.is_constructed) + { + char *newbuffer; + + newbuffer = cram_octet_string (p, tlv->ti.length, r_datalen); + if (!newbuffer) + return (tlv->lasterr = gpg_error (GPG_ERR_BAD_BER)); + err = tlv_register_buffer (tlv, newbuffer); + if (err) + { + xfree (newbuffer); + return (tlv->lasterr = err); + } + *r_data = newbuffer; + } + else + { + *r_data = p; + *r_datalen = tlv->ti.length; + } tlv->offset += tlv->ti.length; return 0; @@ -591,21 +653,40 @@ static gpg_error_t tlv_expect_octet_string (struct tlv_ctx_s *tlv, int encapsulates, unsigned char const **r_data, size_t *r_datalen) { + gpg_error_t err; const unsigned char *p; size_t n; tlv->lastfunc = __func__; if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_OCTET_STRING - && !tlv->ti.is_constructed)) + && (!tlv->ti.is_constructed || encapsulates))) return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ)); p = tlv->buffer + tlv->offset; if (!(n=tlv->ti.length)) return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT)); - if (r_data) - *r_data = p; - if (r_datalen) - *r_datalen = tlv->ti.length; + if (encapsulates && tlv->ti.is_constructed) + { + char *newbuffer; + + newbuffer = cram_octet_string (p, n, r_datalen); + if (!newbuffer) + return (tlv->lasterr = gpg_error (GPG_ERR_BAD_BER)); + err = tlv_register_buffer (tlv, newbuffer); + if (err) + { + xfree (newbuffer); + return (tlv->lasterr = err); + } + *r_data = newbuffer; + } + else + { + if (r_data) + *r_data = p; + if (r_datalen) + *r_datalen = tlv->ti.length; + } if (encapsulates) return _tlv_push (tlv); @@ -716,37 +797,37 @@ tlv_expect_object_id (struct tlv_ctx_s *tlv, /* Given an ASN.1 chunk of a structure like: - - 24 NDEF: OCTET STRING -- This is not passed to us - 04 1: OCTET STRING -- INPUT point s to here - : 30 - 04 1: OCTET STRING - : 80 - [...] - 04 2: OCTET STRING - : 00 00 - : } -- This denotes a Null tag and are the last - -- two bytes in INPUT. - - Create a new buffer with the content of that octet string. INPUT - is the original buffer with a length as stored at LENGTH. Returns - NULL on error or a new malloced buffer with the length of this new - buffer stored at LENGTH and the number of bytes parsed from input - are added to the value stored at INPUT_CONSUMED. INPUT_CONSUMED is - allowed to be passed as NULL if the caller is not interested in - this value. */ + * + * 24 NDEF: OCTET STRING -- This is not passed to us + * 04 1: OCTET STRING -- INPUT point s to here + * : 30 + * 04 1: OCTET STRING + * : 80 + * [...] + * 04 2: OCTET STRING + * : 00 00 + * : } -- This denotes a Null tag and are the last + * -- two bytes in INPUT. + * + * The example is from Mozilla Firefox 1.0.4 which actually exports + * certs as single byte chunks of octet strings. + * + * Create a new buffer with the content of that octet string. INPUT + * is the original buffer with a LENGTH. Returns + * NULL on error or a new malloced buffer with its actual used length + * stored at R_NEWLENGTH. */ static unsigned char * -cram_octet_string (const unsigned char *input, size_t *length, - size_t *input_consumed) +cram_octet_string (const unsigned char *input, size_t length, + size_t *r_newlength) { const unsigned char *s = input; - size_t n = *length; + size_t n = length; unsigned char *output, *d; struct tag_info ti; /* Allocate output buf. We know that it won't be longer than the input buffer. */ - d = output = gcry_malloc (n); + d = output = gcry_malloc (length); if (!output) goto bailout; @@ -769,20 +850,15 @@ cram_octet_string (const unsigned char *input, size_t *length, } - *length = d - output; - if (input_consumed) - *input_consumed += s - input; + *r_newlength = d - output; return output; bailout: - if (input_consumed) - *input_consumed += s - input; gcry_free (output); return NULL; } - static int string_to_key (int id, char *salt, size_t saltlen, int iter, const char *pw, int req_keylen, unsigned char *keybuf) @@ -1331,38 +1407,6 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv) if (tlv_next (tlv)) goto bailout; - /* consumed = p - p_start; */ - /* if (ti.class == CLASS_CONTEXT && ti.tag == 0 && ti.is_constructed && ti.ndef) */ - /* { */ - /* /\* Mozilla exported certs now come with single byte chunks of */ - /* octet strings. (Mozilla Firefox 1.0.4). Arghh. *\/ */ - /* where = "cram-rc2or3des-ciphertext"; */ - /* cram_buffer = cram_octet_string ( p, &n, &consumed); */ - /* if (!cram_buffer) */ - /* goto bailout; */ - /* p = p_start = cram_buffer; */ - /* if (r_consumed) */ - /* *r_consumed = consumed; */ - /* r_consumed = NULL; /\* Donot update that value on return. *\/ */ - /* ti.length = n; */ - /* } */ - /* else if (ti.class == CLASS_CONTEXT && ti.tag == 0 && ti.is_constructed) */ - /* { */ - /* where = "octets-rc2or3des-ciphertext"; */ - /* n = ti.length; */ - /* cram_buffer = cram_octet_string ( p, &n, &consumed); */ - /* if (!cram_buffer) */ - /* goto bailout; */ - /* p = p_start = cram_buffer; */ - /* if (r_consumed) */ - /* *r_consumed = consumed; */ - /* r_consumed = NULL; /\* Do not update that value on return. *\/ */ - /* ti.length = n; */ - /* } */ - /* else if (ti.class == CLASS_CONTEXT && ti.tag == 0 && ti.length ) */ - /* ; */ - /* else */ - /* goto bailout; */ if (tlv_expect_object (tlv, CLASS_CONTEXT, 0, &data, &datalen)) goto bailout; @@ -1538,7 +1582,8 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv) keyelem_count, gpg_strerror (err)); goto bailout; } - log_debug ("RSA key parameter %d found\n", keyelem_count); + if (opt_verbose > 1) + log_debug ("RSA key parameter %d found\n", keyelem_count); keyelem_count++; } if (err && gpg_err_code (err) != GPG_ERR_EOF) @@ -1683,6 +1728,7 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv) size_t saltlen; char iv[16]; unsigned int iter; + struct tlv_ctx_s *saved_tlv = NULL; int renewed_tlv = 0; /* True if the TLV must be released. */ unsigned char *plain = NULL; int is_pbes2 = 0; @@ -1865,8 +1911,10 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv) : GCRY_CIPHER_3DES, bag_data_p); + /* We do not need the TLV anymore and allocated a new one. */ where = "shrouded_key_bag.decrypted-text"; + saved_tlv = tlv; tlv = tlv_new (plain, datalen); if (!tlv) { @@ -1874,6 +1922,8 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv) goto bailout; } renewed_tlv = 1; + if (opt_verbose > 1) + log_debug ("new parser context\n"); if (tlv_next (tlv)) { @@ -2037,10 +2087,39 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv) err = 0; } + if (opt_verbose > 1) + log_debug ("restoring parser context\n"); + tlv_release (tlv); + renewed_tlv = 0; + tlv = saved_tlv; + + where = "shrouded_key_bag.attribute_set"; + err = tlv_next (tlv); + if (gpg_err_code (err) == GPG_ERR_EOF) + goto leave; + if (err) + goto bailout; + err = tlv_expect_set (tlv); + if (!err) + { /* This is the optional set of attributes. Skip it. */ + tlv_skip (tlv); + if (opt_verbose) + log_info ("skipping %s\n", where); + } + else if (gpg_err_code (err) == GPG_ERR_INV_OBJ) + tlv_set_pending (tlv); /* The next tlv_next will be skipped. */ + else /* Other error. */ + goto bailout; + + leave: gcry_free (plain); if (renewed_tlv) - tlv_release (tlv); + { + tlv_release (tlv); + if (opt_verbose > 1) + log_debug ("parser context released\n"); + } return err; bailout: @@ -2322,17 +2401,6 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw, if (tlv_next (tlv)) goto bailout; - if (tlv->ti.is_constructed && tlv->ti.ndef) - { - log_debug ("FIXME Put this into our TLV machinery.\n"); - /* /\* Mozilla exported certs now come with single byte chunks of */ - /* octet strings. (Mozilla Firefox 1.0.4). Arghh. *\/ */ - /* where = "cram-bags"; */ - /* cram_buffer = cram_octet_string ( p, &n, NULL); */ - /* if (!cram_buffer) */ - /* goto bailout; */ - /* p = p_start = cram_buffer; */ - } if (tlv_expect_octet_string (tlv, 1, NULL, NULL)) goto bailout; diff --git a/sm/t-minip12.c b/sm/t-minip12.c index 80ba4c69e..de6b7e5cc 100644 --- a/sm/t-minip12.c +++ b/sm/t-minip12.c @@ -444,12 +444,14 @@ static void cert_collect_cb (void *opaque, const unsigned char *cert, size_t certlen) { char **certstr = opaque; - char *hash; + char *hash, *save; hash = hash_buffer (cert, certlen); if (*certstr) { - *certstr = xstrconcat (*certstr, ",", hash, NULL); + save = *certstr; + *certstr = xstrconcat (save, ",", hash, NULL); + xfree (save); xfree (hash); } else @@ -645,7 +647,12 @@ run_tests_from_file (const char *descfname) copy_data (&p, line, lineno); hexdowncase (p); if (p && cert) - cert = xstrconcat (cert, ",", p, NULL); + { + char *save = cert; + cert = xstrconcat (save, ",", p, NULL); + xfree (save); + xfree (p); + } else cert = p; } @@ -681,6 +688,7 @@ main (int argc, char **argv) char const *name = NULL; char const *pass = NULL; int ret; + int no_extra = 0; if (argc) { argc--; argv++; } @@ -697,12 +705,18 @@ main (int argc, char **argv) fputs ("usage: " PGM " []\n" "Without a regression test is run\n" "Options:\n" + " --no-extra do not run extra tests\n" " --verbose print timings etc.\n" " given twice shows more\n" " --debug flyswatter\n" , stdout); exit (0); } + else if (!strcmp (*argv, "--no-extra")) + { + no_extra = 1; + argc--; argv++; + } else if (!strcmp (*argv, "--verbose")) { verbose++; @@ -761,7 +775,7 @@ main (int argc, char **argv) xfree (descfname); /* Check whether we have non-public regression test cases. */ - p = value_from_gnupg_autogen_rc ("GNUPG_EXTRA_TESTS_DIR"); + p = no_extra? NULL:value_from_gnupg_autogen_rc ("GNUPG_EXTRA_TESTS_DIR"); if (p) { descfname = xstrconcat (p, "/pkcs12/Description", NULL); diff --git a/tests/cms/Makefile.am b/tests/cms/Makefile.am index 60fdf0281..7efdf37b1 100644 --- a/tests/cms/Makefile.am +++ b/tests/cms/Makefile.am @@ -86,13 +86,19 @@ TEST_FILES = plain-1.cms.asc \ testscripts = sm-sign+verify sm-verify EXTRA_DIST = $(XTESTS) $(KEYS) $(CERTS) $(TEST_FILES) \ + samplemsgs/README \ + samplekeys/Description-p12 \ samplekeys/steed-self-signing-nonthority.pem \ samplekeys/68A638998DFABAC510EA645CE34F9686B2EDF7EA.key \ samplekeys/32100C27173EF6E9C4E9A25D3D69F86D37A4F939.key \ samplekeys/cert_g10code_pete1.pem \ samplekeys/cert_g10code_test1.pem \ samplekeys/cert_g10code_theo1.pem \ - samplemsgs/README \ + samplekeys/ov-user.p12 \ + samplekeys/ov-server.p12 \ + samplekeys/opensc-test.p12 \ + samplekeys/t5793-openssl.pfx \ + samplekeys/t5793-test.pfx \ samplemsgs/pwri-sample.cbc.p7m \ samplemsgs/pwri-sample.cbc-2.p7m \ samplemsgs/pwri-sample.gcm.p7m \ diff --git a/tests/cms/samplekeys/Description-p12 b/tests/cms/samplekeys/Description-p12 index bd1e35c91..f882de9ea 100644 --- a/tests/cms/samplekeys/Description-p12 +++ b/tests/cms/samplekeys/Description-p12 @@ -18,3 +18,15 @@ Pass: password Cert: 115abfc3ae554092a57ade74177fedf9459af5d2 Cert: a0d6d318952c313ff8c33cd3f629647ff1de76b3 Key: 5a36c61706367ecdb52e8779e3a32bbac1069fa1 + +Name: t5793-openssl.pfx +Desc: self-signed key issued keys +Pass: test +Cert: 80348a438e4b803b99e708da0b7fdd0659dedd15 +Key: c271e44ab4fb19ca1aae71102ea4d7292ccc981d + +Name: t5793-test.pfx +Desc: QuaVadis format of t5793-openssl +Pass: test +Cert: 80348a438e4b803b99e708da0b7fdd0659dedd15 +Key: c271e44ab4fb19ca1aae71102ea4d7292ccc981d diff --git a/tests/cms/samplekeys/t5793-openssl.pfx b/tests/cms/samplekeys/t5793-openssl.pfx new file mode 100644 index 0000000000000000000000000000000000000000..0f1beed0fb3edbcec8a8298096fac4c333606496 GIT binary patch literal 4285 zcmY+GWmFW5vxkY@r9(=(L8MbbS}8$+mu`urV+nx;=?0NlQjkuGrE^881qtb1N>WOe zMqrogd(OT0fA5DmbI$WSGau&}(Fn>8JY0Oy2+B|p5r2$E%oQ0f0d8Rgr6(YQ((NyH z5{&>A{3ikxMu1ZOqC`AgoWCvlKMAfVGl=-VH<03jM9Be!y4(ZunJSghczA?3VG$sc z#uv4MPwPBKfoEU_re)y>VU{l*_7}$6*I9clKx>=#YdhDz1jkPWRpp)p4ErDeye!mk zDJ*o8H!L-oS32SCTX%Va^3PO>%`@MIu8DEWo18idhW8kD7WHPyaeze|5)>J>V;&OK zKGXBfsl-~K@1Bw|)6wI*9uSWy3@@rG$s||4jTDy! z-x~VIj_5E+RZM+`nlUEwCGOd3LnCCt>tW#MCfghy>o(^)on(%bBZyXTRJ-7X%fiwwWAiRcpC0XplF1ee-T{^|Fdm!FK) z^BfnOqFg>)5gw`;!1j@PnszwoWH1GooY;D4(&YB`O$tF1>_I=+FR*W*Pu_8ikT#Jm z)Q1V=_V3OySx5iw%Spxze$u-b!dg-ve+9jHuU|3SE>mzctaq3VQ}qXEptl%eauUXI zbJn=M&K3Z>NcE>X8uy6G%C5aZ9Boq|!ka+^t9zflTGOA$5WrgSb*8OFHy z6@gnn6U?*l4@5Ntl8>+Ky&!RHU01SFN6(%B^_UK9t6(@q0$JAMibp?D)nyF;r6=L} z(W{(ox}Qu3LRMwMo3E+rw0}p5!OR^WJYw5fvUuS(B;f3b;@3}6ZH~O&dlpFG1^Gn% zZB6YJLE@pA7_d3rEBiO+2jIrjj1SUn)es7)Yq z`iiu5YE1`&M$<0<8|)$N!aj=nE@O$(`n(%-St$zQ0eLsA&s!q)Qbh}tPP5FhX!h=U zSk2Ox5-Q?4Rjns9>w2esjJB0Gx~^=`E(UaS1CS@Bb5rr)BHu7pQPe13&wD5Ma<5Tm z=05n~ax|6Q`vDaZ_sOmJnoo!MuV3ZPicK%6Q9na0D+k`dIiWf@nQ=!<^;3+6qUlme zR9E~K13;H~4L)#(vD%}o`fd-u8{2%ZKttS9fvW6kI_vflMsioJSbC(qM3?NPhOI&? z`@rCb;rjl&tF2|5khc;stT@3H(7kA+HFuoOXqU=#CB95brzv8F4W}92VaQ#N^Ji)+vZWgO@@wX*;C&i;x}*< zYM2yIWBj zcODJoQr_$Ht|MG_Wvy}*x?>w?Wofe>YqorR6H%^xd1v|&H?w6cqw+zews1mAPi`AmTEUD3G3uTics}k;wKAxba=lem!grOUDL_cLyZ&V zI%HZNu=)I2yN00&hrTd}<}7Y=@V>qDKMYkt*dCF=6S(w0a`>jcO|9RAPorS&h8*on ztDX~dngtyV%nk@+$yc4YU^3)SW;~19-A@t*(r(tpvAyP)dIQr7g60erTG`S4u5f-* zo@sl2X@iy;UeO4mp8q4F!U&>9Km-x|FRuDqs?upx|46l zNfC>{X^rB`FD`_ryR3=)Hf=n? z@hZsL%ket~A69J?;iyNFdzsyj8*H-)<_uyKs=15ZcnC#H;V*0nIFMiTs86a^LvIz* zn*4q?!(9VbQyDgKZH(_Et@61*iAEfd04`%o_-M!4QFH~)O8%ze)eHAF`tZFIQ@G)9 zg}wpOqK%}?Z&_FZNCnesHupyx!NNzy+(VP6UyY4r9ixL_+M8w9n4{T!;wI0C{aPnp zzv9TJGFjd3wLvIP2c<6PSf=%JCRFTvkajEaX^BUl;(q)0&=1w?UWok^u~g!L`U6P% zP_3Rc@amD0aDjgIYbEJ*^#m@q@k|5kWAEb*C-X=G_4f~YeU|gS736qVbenv^7Q21H zlK7g9!`6aJk1yhA%VIKahKA`t2-Zm%rXKImKqLY)MmbO`)u z^-ez6AEN73Y3NDZ<$fOBUoz=SkTdO7sF?bgB@Yroexl2ab7aw<`2Gx@ze3I~-Z7v@h9u?rb;X8{;J}L?g-A&YW zOL=>)bY7!K>u}hh`)Fdvpw(wzU#D^s@#U*DEu@X|1`KGm zti{new(UNJ9_Lj=GVdq9c_%x@JiC-)E^HsJE42K~`gd^FSM#=ig2>$h8a;OVMJ$WC z1Qd$Q1wra&1To_`o zo@@Ssg~y7{;=ok)tj;{{Id)wqv}Yx_Uu<(k=csq2^X^jzvM+41)hp~^^X9YNW8jn_ z`nC&K?)gRTgV5?T4vwT_sfgnE*mY4gxZqd+WM?5nlNC*`8RakhkAC;)jgYH)q}w4X zI6mGyc5~aYv?H#Xs2=`8A{3X!kBux=CKPUP^E=*GRRFVZPyDV~_d3mwI)|$yl_Q@l zQrcVE7y;9ld%~L1X#O&u8a%k>9TYT}cPFc4JI3jA*>a5|w9PKdeCjIe&=ti#HGpD1 zFMEFgEa$X7bAZ#ut%rLliNsKxU0<%>Vdi+|_)ODvc-DkZ*c#^ob$rpOl^P^n zHYH^YOg$P&1vjr>S#y4|$EgBRe*co?M&ODjTN3D&s8!p&U_FfkMmE~@PoIo+*SwAq zdp616>`eYE)^XOq%?9E3Xcr_B!r@1L2$TFdCfYx9_jguawF8D4)wf zxDjPMlf~n9DcjM66%$`w^LR-60%o+omvtnYNQ{2Rxe@&6XVqC~w)l|h*fJ|lAS#2u ziYcSQOn)$I7MvDHyEZ$*w?tB|v`(tda`$wBkvGAI0RyJ_-NwZ@x;+vmIfLVxMnZ+I zgLX%6hs(K!z?NzqD{t>D3N+tlf`uM_q3GK_LNig0Ln0<>Zpfk`I!-`6SJSfB(J)E_ z2xmG~L2%og#q?Vx*Y1nWewfkKH94;!a^kD$)z3%+@`C2)p0#2eqdZ9u0SGlClfcZa zD-l0pE=$}WWiN(#H3Y?^Vul-blFrsouo9V=QX$L#B`>6_Dxb3azM^D2FH!2q-{~kH-ka0nkX>9QPB{ox8C_ cujDZ|LX+opIQ||~Ct}N@Gm9v{f4{W<0(8!4BvoPr1^#q9z|b*-q;!Kw3@J#bbk~Sd0}|3bl%$jl zjljU=uJyk6uKQu1eb(>U&;ELzBN9rnfs2DD5=v1HCgh8RL|%~M;N#?lQe*)`Dbnw8 zvPdZ5#{Wo!)4))|@q7I9z6QX=|K}nh!okf8C3Lxm4kAooqW{PD%gKNQdpks4%pwH)o;yg7J^b2!eg`RE^_KYyUHcZ4#bTzruSJ9`?>!4d;Y-TEdDZP} zxA9z(2nXRf!pM?(@VBn~x9%>F19C?12y*TOwLUd@NTan&$9K4mWj@rK?4<5QmBoFIY%VMy zvnLr-+Pa89mQO#B9(7N7IX_O^ow06+Q8kKAoIRMTv9J0lkOgLTdtdCYYUi1Hl+Vn6 zT&XbDZ`l7`G4hY#-k1{K;qvMHf?vVb+!)uQ_?`VZUK`(Ovel`$d-PI;5ZjZXp0xu# zAqc7Mc8Taq!}*^%m^@2xZbC?{8*j>w4cF(3#1`SXwyUuAvok@e4k)45x`it&MhR7Q zK6*p%!J>gC7~UF+mM}gsg5gG_*}~;H+cPO ztakKWPNHAOu`sxiFwfxx$LX`feK`%xs)yTF4kAhcOF8Qb7cZS#=t6dmjH>kpOLcTn zrY*$9UW-EFAWDRKqlq_09}zMv>Kv3X`Fdm|{Sf1i&{!|N#2!rV5;eGn?pE3Hcol>_ zl}_(;uJT8_+9-DTjHE$dFruSo{WY42jtgCS6n0yG1bwVnbwlnZiY5{D)$YMl2CB5B zKo^e`g>rQ=-Y80~s>X7%j;86}K6XEBvoi_9SN-sy+hZ~Ndv2zCX{X`W+XAPrx5S>t zqllG&qQkRjn&QaRtARmUFp_0lnz740$Pb0Yj!^WO~Kh>-MZ5MP%UD~vpSGZ%=|G3xiavE-VoWkSLp$i=TQ-d3PF?NO3+R}} zqea#S9G~o!94Qj}NRV~ArpwQ_IS)btIS+De!fUS7;f(cPOQ4np1>rG~lWVIJQ;^`@0* zTHBWGr#^?-rD06F32)!aj4(|vB$^0WhiC~dK7;-VNdIQi@{d26lW)DtcCWBm0jFGh zOY1%?&SH{}1dJB!)Z){K(DRR_9Wz?PUq#aIX4}!F<=d)R!nY3hUo1KjeJ5JIQic`& z4T;~^G5?@n{#!^;q06VK-pcl|mn8wwzH7;l`r(D2^iA35S9sB}prw2#p_9d>cnYTx z>W$P~H18ddARjWAr@LI?Rc>AoyM~u)N&~~T@n1+fIMsY)*r;OdpoCV4dON~ zWC37dxDWQD7puph2|dhp z2afEEv#bX}6({WM@rRP31u;>pA}ZAa-@Fs-1(6Nr)ZNAuzwthK-C@=OFKSUv`{;m} z7?Y^=P1~Zj=nBHx>X+g{ILuzGq*2mA)w)-IVmy`kvAfnp?;Eu)lf9@iISZ56b4bIa z+@%bV2p!ocEQ$3duVScR{VVSN{{7iEGK!WX93JOQmjJ;{HW{X4M;V)raJGp)G}CGE zhdodU2lT|Inl^eh#7$8+lKkZIeDwx9!{hY4YY)O}l%mPKB6P%BKjWwAiAgGh5O-J< z7Sl6!LE>|--n@o#e6rVcZyf3Y@e|lM}xxZt$HVqMmj6sM2bEe z=WDbldpp+Yn`L=7?vAh0?VR4J8e~z))V!3u6os|s4Bq!LwozFfE_8@0`H_r$&sm!0 zN3$s4tMn0%(Uw0;Hb`SAhrhCO1UgMAL`_>KaYiY>kaA12abtAHX3(HE1d-;}lT1)C z@ZQFoHg}~Y^RU6h7y%==SeP1cODtFBH?*pmV>9ECojEI1)3qRmiiwz8lYV`ViW^UC zL=>d%wZ1-Nf`yJVpIweo{tF59SkSFU0g)IN@8n-;tH_5<`CAjMJ%$FS-V_uGE@gpX zr7xvwjD_^1OreRA>+0IsO26XAzg^3z!l~R2JE}p|>oEvwz~Z|P7bzFd$#^MVNW;01 z#oXfsqgIKV5d@`U-yE~KNqT&zG=3DfB^Zhi{{UPGeDX4H&oiEXNO@?M9?c(~%2&>q zT57D*pFRys_M=&u9^zdfE>T=1QDwe)I>*2h>p_o&QU7V-WEkEY3YM4xI3^QQVrqOk zBQ`^19Rm>yRkmfU zg)%pwWyW;!ouXss*?KQR|KgI2M*ubU&FJD+m@Zjv;|td+QTAc(_=iBGioT&=+Qx;j z7ZIl!&d=hPgFFxcQOU@`x~=$=)uUVSH0|VS@lxoUYJGak8t?i76EY4_VFbhPp^uA`IRxR+Emv~|@BKGV%+i-lU zkD^bZ>8BgG#G@|!3LfMFf6iS4s$1LLm;RSM4U=rA_FT0Thy8wQ)^#Iq06;F$WpP;| zM{qZrB+6O-lM{{pmJ?`cE&a8Ea5F?Yk2q~NGMx){rT8?z&m`KXoB&r8BEtEfbVf)c zN(-b8mWX{BuO2M(X`5hyIA{rMw7f(k!v5bOYEfzyO29jSHNfNk6a-k^-`oN3L_)!( z{~5vu=Y@hZ?okRZ4&c6h{I7!ZKj9Ai?{KHZ)hCyxR2K2?aCh&60z+|5>t9w0JgspZ z2A#m@85e~@g_ys(Sf3eeUZ(FffuI&2R<phsFZn_l*Esck;F1WZq`|H&cW{S(YhHVr3;@bs6DLo#9B~n^@R*!!Od?VT z|8SLvoQxRVc7eN0V0qBx@rGG)H4H`buM(TLRy_Qm;gXt`DdLJ~FSRs?t$lBR|6@VjUxV~#qnz`S)749j zZMid}pFaoK*r^DP2rUMiJ{F~6qwb9e^-j}LHOAcjOC1@i9R`dOIh{RH6&`$T5!xZJ1+v#74k)ss_}l9>D>ojc?K&ztL9w{M zBs5UjciThaYSd<8YYqO%c6R&L=gE8aA(95tx!Pd(MeFu5eUaWw8Hrd0U?>oF;WQPudZp-}oG4<CQZ%7-<7 z!JlR3>kF^*BO6`Xc}Z;BysBufikUtFX*2FwmLmZ9{OQn9g@a${isCw;;**e^h-Hoz zte%jhB=)8h^q?5hk_|9YVwVf_rSC%<$etI~^{N))Hw9wW<1~NzWC_0p!c!$h6#8SSQt*`&% zU~TWs#m1sV;5+e17C=A)01Ft~WE@N*{GI}>U=N6~U)Sh4GPFq~;=7 z!stAoFyN5v{J~9^%f&oQ8ry-i<+nAXN$Wyl;X0oTRqiJJ;xg2`;f>@VAX9J`et}@8 zsrY_4a!VzIqzKdeI; z;Y12Fu(NCX&XJWP6X`u#zEYwAi0}-`xvGgV<$^%DDKW5o5+LXG4;$@#=E)ti7+PV* z&Ix1GqA8+vs~r`cl%q`H7MzhCPp(PsUH%6au(wa6>%N~?z2*oyaWd$(!Y%?7H zhW@abR(>zf>AZ=*v}Rhyvg$tiO4&gHglFJHJ`@~DriX@ql`1sF<6 z<4q7e8n6CS?2&ax Date: Fri, 30 Jun 2023 10:59:06 +0200 Subject: [PATCH 49/56] Prepare NEWS for the next release -- --- NEWS | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 14c2251bf..a30440b47 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,45 @@ Noteworthy changes in version 2.4.3 (unreleased) ------------------------------------------------ - Release-info: https://dev.gnupg.org/T6506 + * gpg: Set default expiration date to 3 years. [T2701] + + * gpg: Add --list-filter properties "key_expires" and + "key_expires_d". [T6529] + + * gpg: Emit status line and proper diagnostics for write errors. + [T6528] + + * gpg: Make progress work for large files on Windows. [T6534] + + * gpg: New option --no-compress as alias for -z0. + + * gpgsm: Print PROGRESS status lines. Add new --input-size-hint. + [T6534] + + * gpgsm: Support SENDCERT_SKI for --call-dirmngr. [rG701a8b30f0] + + * gpgsm: Major rewrite of the PKCS#12 parser. [T6536] + + * gpgtar: New option --no-compress. + + * dirmngr: Extend the AD_QUERY command. [rG207c99567c] + + * dirmngr: Disable the HTTP redirect rewriting. [T6477] + + * dirmngr: New option --compatibility-flags. [rGbf04b07327] + + * dirmngr: New option --ignore-crl-extensions. [T6545] + + * wkd: Use export-clean for gpg-wks-client's --mirror and --create + commands. [rG2c7f7a5a27] + + * wkd: Make --add-revocs the default in gpg-wks-client. New option + --no-add-revocs. [rG10c937ee68] + + * scd: Fix authentication with Administration Key for PIV. + [rG25b59cf6ce] + + Release-info: https://dev.gnupg.org/T6509 Noteworthy changes in version 2.4.2 (2023-05-30) From 5e94470d053ec93f79acb03635e67839a5a1e6a8 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 4 Jul 2023 09:19:05 +0200 Subject: [PATCH 50/56] common,w32: Add missing GetLastError->errno mapping. * common/iobuf.c (file_filter, sock_filter): Add missing mapping. -- GnuPG-bug-id: 6528 --- common/iobuf.c | 7 ++++--- common/sysutils.c | 5 +++-- common/sysutils.h | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/common/iobuf.c b/common/iobuf.c index 627d33900..161769a35 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -572,8 +572,8 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf, { if (size && !WriteFile (f, p, nbytes, &n, NULL)) { - int ec = (int) GetLastError (); - rc = gpg_error_from_errno (ec); + int ec = gnupg_w32_set_errno (-1); + rc = gpg_error_from_syserror (); log_error ("%s: write error: %s (ec=%d)\n", a->fname, gpg_strerror (rc), ec); break; @@ -884,7 +884,8 @@ sock_filter (void *opaque, int control, iobuf_t chain, byte * buf, if (n == SOCKET_ERROR) { int ec = (int) WSAGetLastError (); - rc = gpg_error_from_errno (ec); + gnupg_w32_set_errno (ec); + rc = gpg_error_from_syserror (); log_error ("socket write error: ec=%d\n", ec); break; } diff --git a/common/sysutils.c b/common/sysutils.c index 231565177..f8e6d86fc 100644 --- a/common/sysutils.c +++ b/common/sysutils.c @@ -327,9 +327,10 @@ map_w32_to_errno (DWORD w32_err) #endif /*HAVE_W32_SYSTEM*/ -/* Set ERRNO from the Windows error. EC may be -1 to use the last error. */ +/* Set ERRNO from the Windows error. EC may be -1 to use the last + * error. Returns the Windows error code. */ #ifdef HAVE_W32_SYSTEM -void +int gnupg_w32_set_errno (int ec) { /* FIXME: Replace by gpgrt_w32_set_errno. */ diff --git a/common/sysutils.h b/common/sysutils.h index 7063da067..a78a81c64 100644 --- a/common/sysutils.h +++ b/common/sysutils.h @@ -110,7 +110,7 @@ int gnupg_inotify_has_name (int fd, const char *name); #ifdef HAVE_W32_SYSTEM -void gnupg_w32_set_errno (int ec); +int gnupg_w32_set_errno (int ec); void *w32_get_user_sid (void); #include "../common/w32help.h" From 7a2831bc0ef00559d2a2b938e0f2401f0e35d30a Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 4 Jul 2023 09:26:10 +0200 Subject: [PATCH 51/56] gpgsm: Init a diagnostic var. * sm/minip12.c (p12_parse): Init where. -- --- sm/minip12.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sm/minip12.c b/sm/minip12.c index eafebfe67..265243f3e 100644 --- a/sm/minip12.c +++ b/sm/minip12.c @@ -2348,7 +2348,7 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw, void *certcbarg, int *r_badpass, char **r_curve) { gpg_error_t err; - const char *where; + const char *where = ""; struct tlv_ctx_s *tlv; struct p12_parse_ctx_s ctx = { NULL }; const unsigned char *oid; From b83d86b988bbb05b25dba250a5f01b33b3dbb824 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 4 Jul 2023 14:32:08 +0200 Subject: [PATCH 52/56] scd:p15: Make signing work for Nexus cards. * scd/app-p15.c (CARD_PRODUCT_NEXUS): New. (read_p15_info): Detect Nexus cards. (get_dispserialno): Use product_id instead of comparing the manufacturer_id. (do_sign): Handle Nexus like BELPIC. --- scd/app-p15.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/scd/app-p15.c b/scd/app-p15.c index 92628b926..4338a623e 100644 --- a/scd/app-p15.c +++ b/scd/app-p15.c @@ -87,7 +87,8 @@ typedef enum CARD_PRODUCT_UNKNOWN, CARD_PRODUCT_RSCS, /* Rohde&Schwarz Cybersecurity */ CARD_PRODUCT_DTRUST, /* D-Trust GmbH (bundesdruckerei.de) */ - CARD_PRODUCT_GENUA /* GeNUA mbH */ + CARD_PRODUCT_GENUA, /* GeNUA mbH */ + CARD_PRODUCT_NEXUS /* Technology Nexus */ } card_product_t; @@ -550,6 +551,7 @@ cardproduct2str (card_product_t cardproduct) case CARD_PRODUCT_RSCS: return "R&S"; case CARD_PRODUCT_DTRUST: return "D-Trust"; case CARD_PRODUCT_GENUA: return "GeNUA"; + case CARD_PRODUCT_NEXUS: return "Nexus"; } return ""; } @@ -3605,14 +3607,20 @@ read_p15_info (app_t app) release_lists (app); - if (IS_CARDOS_5 (app) - && app->app_local->manufacturer_id - && !ascii_strcasecmp (app->app_local->manufacturer_id, "GeNUA mbH")) + /* Set a product type from the manufacturer_id. */ + if (IS_CARDOS_5 (app) && app->app_local->manufacturer_id) { - if (!app->app_local->card_product) + const char *manu = app->app_local->manufacturer_id; + + if (app->app_local->card_product) + ; /* Already set. */ + else if (!ascii_strcasecmp (manu, "GeNUA mbH")) app->app_local->card_product = CARD_PRODUCT_GENUA; + else if (!ascii_strcasecmp (manu, "Technology Nexus")) + app->app_local->card_product = CARD_PRODUCT_NEXUS; } + /* Read the ODF so that we know the location of all directory files. */ /* Fixme: We might need to get a non-standard ODF FID from TokenInfo. */ @@ -5079,9 +5087,7 @@ get_dispserialno (app_t app, prkdf_object_t prkdf) if (serial && (n=strlen (serial)) > 8) memmove (serial, serial + n - 8, 9); } - else if (IS_CARDOS_5 (app) && app->app_local->manufacturer_id - && !ascii_strcasecmp (app->app_local->manufacturer_id, - "Technology Nexus") + else if (app->app_local->card_product == CARD_PRODUCT_NEXUS && APP_CARD(app)->serialno && APP_CARD(app)->serialnolen == 4+9 && !memcmp (APP_CARD(app)->serialno, "\xff\x00\x00\xff", 4) && !any_control_or_space_mem (APP_CARD(app)->serialno + 4, 9)) @@ -5615,11 +5621,12 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo, err = gpg_error_from_syserror (); goto leave; } - if (app->app_local->card_type == CARD_TYPE_BELPIC) + if (app->app_local->card_type == CARD_TYPE_BELPIC + || app->app_local->card_product == CARD_PRODUCT_NEXUS) { - /* This card wants only the plain hash w/o any prefix. */ - /* FIXME: We may want to remove this code because it is unlikely - * that such cards are still in use. */ + /* The default for these cards is to use a plain hash. We + * assume that due to the used certificate the correct hash + * algo is used. */ memcpy (frame, indata, indatalen); framelen = indatalen; } From 7f8ea1c9be120b0a78eb6c04551277747f711d56 Mon Sep 17 00:00:00 2001 From: Emir SARI Date: Tue, 4 Jul 2023 15:52:05 +0200 Subject: [PATCH 53/56] po: Update Turkish translation -- --- po/tr.po | 73 ++++++++++++++++---------------------------------------- 1 file changed, 20 insertions(+), 53 deletions(-) diff --git a/po/tr.po b/po/tr.po index b7730c7ae..24313f22a 100644 --- a/po/tr.po +++ b/po/tr.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gnupg 2.4.0\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n" -"PO-Revision-Date: 2023-02-05 18:00+0300\n" +"PO-Revision-Date: 2023-05-30 23:45+0300\n" "Last-Translator: Emir SARI \n" "Language-Team: Turkish\n" "Language: tr\n" @@ -123,10 +123,8 @@ msgstr "Anahtar Parolası:" msgid "does not match - try again" msgstr "eşleşmiyor - yeniden deneyin" -#, fuzzy -#| msgid "Passphrase Entry" msgid "Passphrases match." -msgstr "Anahtar Parolası Girişi" +msgstr "Anahtar parolaları eşleşiyor." #. TRANSLATORS: The string is appended to an error message in #. the pinentry. The %s is the actual error message, the @@ -733,6 +731,10 @@ msgstr "Doğru" msgid "Wrong" msgstr "Yanlış" +#, c-format +msgid "error renaming '%s' to '%s': %s\n" +msgstr "'%s > '%s' olarak yeniden adlandırırken hata: %s\n" + #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -1409,7 +1411,7 @@ msgstr "zorlandı" #, c-format msgid "Please try command \"%s\" if the listing does not look correct\n" -msgstr "" +msgstr "Listeleme doğru görünmüyorsa lütfen \"%s\" komutunu deneyin\n" msgid "Error: Only plain ASCII is currently allowed.\n" msgstr "Hata: Şimdilik yalnızca US-ASCII mümkün.\n" @@ -1674,7 +1676,7 @@ msgid "change the User Interaction Flag" msgstr "Kullanıcı etkileşim bayrağını değiştir" msgid "switch to the OpenPGP app" -msgstr "" +msgstr "OpenPGP uygulamasına geç" msgid "gpg/card> " msgstr "gpg/card> " @@ -2304,10 +2306,8 @@ msgstr "" "anahtar listelerinde yürürlükten kaldırılmış ve zaman aşımına uğramış " "yardımcı anahtarlar göster" -#, fuzzy -#| msgid "show expiration dates during signature listings" msgid "show signatures with invalid algorithms during signature listings" -msgstr "imza listelemesi sırasında zaman aşımı tarihleri göster" +msgstr "imza listelemesi sırasında geçersiz algoritmalı imzaları göster" msgid "show the keyring name in key listings" msgstr "anahtar zinciri adını anahtar listelerinde göster" @@ -2927,6 +2927,7 @@ msgstr "%s anahtarı: Aracıya gönderirken hata: %s\n" #, c-format msgid "key %s: card reference is overridden by key material\n" msgstr "" +"%s anahtarı: Kart başvurusu, anahtar malzemesi tarafından geçersiz kılındı\n" #. TRANSLATORS: For a smartcard, each private key on host has a #. * reference (stub) to a smartcard and actual private key data @@ -3449,10 +3450,8 @@ msgstr "seçili yardımcı anahtarları sil" msgid "add a revocation key" msgstr "bir yürürlükten kaldırma anahtarı ekle" -#, fuzzy -#| msgid "Data decryption succeeded" msgid "add an additional decryption subkey" -msgstr "Veri şifresi çözülmesi başarılı" +msgstr "ek bir şifre çözümü alt anahtarı ekle" msgid "delete signatures from the selected user IDs" msgstr "seçili kullanıcı kimliklerinden imzaları sile" @@ -3519,11 +3518,10 @@ msgstr "Gizli anahtar mevcut.\n" msgid "Secret subkeys are available.\n" msgstr "Gizli yardımcı anahtarlar mevcut.\n" -#, fuzzy -#| msgid "Note: Only the secret part of the shown subkey will be deleted.\n" msgid "" "Note: the local copy of the secret key will only be deleted with \"save\".\n" -msgstr "Not: Yalnızca gösterilen yardımcı anahtarın gizli kısmı silinecek.\n" +msgstr "" +"Not: Gizli anahtarın yerel kopyası yalnızca \"save\" ile silinir.\n" msgid "Need the secret key to do this.\n" msgstr "Bunu yapmak için gizli anahtar gerekli.\n" @@ -3639,10 +3637,9 @@ msgstr "Değişiklikler kaydedilsin mi? (e/H) " msgid "Quit without saving? (y/N) " msgstr "Kaydetmeden çıkılsın mı? (e/H) " -#, fuzzy, c-format -#| msgid "deleting secret %s failed: %s\n" +#, c-format msgid "deleting copy of secret key failed: %s\n" -msgstr "gizli %s silinmesi başarısız: %s\n" +msgstr "gizli anahtarın kopyasının silinmesi başarısız: %s\n" #, c-format msgid "Key not changed so no update needed.\n" @@ -3783,11 +3780,6 @@ msgstr "UYARI: Şifreleme yardımcı anahtarının yakın zamanda süresi dolaca msgid "You may want to change its expiration date too.\n" msgstr "Son kullanma tarihini de değiştirmek isteyebilirsiniz.\n" -#, fuzzy, c-format -#| msgid "WARNING: Your encryption subkey expires soon.\n" -msgid "WARNING: No valid encryption subkey left over.\n" -msgstr "UYARI: Şifreleme yardımcı anahtarının yakın zamanda süresi dolacak.\n" - msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -3894,17 +3886,15 @@ msgstr "" "misiniz? (e/H) " msgid "Enter the fingerprint of the additional decryption subkey: " -msgstr "" +msgstr "Ek şifre çözümü alt anahtarının parmak izini gir: " -#, fuzzy, c-format -#| msgid "(unless you specify the key by fingerprint)\n" +#, c-format msgid "Did you specify the fingerprint of a subkey?\n" -msgstr "(anahtar parmak izi ile belirtilmedikçe)\n" +msgstr "Bir alt anahtarın parmak izini mi belirttiniz?\n" -#, fuzzy, c-format -#| msgid "Subkey %s is already revoked.\n" +#, c-format msgid "key \"%s\" is already on this keyblock\n" -msgstr "%s yardımcı anahtarı zaten yürürlükten kaldırılmış.\n" +msgstr "\"%s\" anahtarı halihazırda bu anahtar blokunda\n" msgid "" "Are you sure you want to change the expiration time for multiple subkeys? (y/" @@ -7770,10 +7760,6 @@ msgstr "lütfen nedenini denetleyin ve o dosyayı el ile silin\n" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "geçici önbellek dizin dosyası '%s' oluşturulamadı: %s\n" -#, c-format -msgid "error renaming '%s' to '%s': %s\n" -msgstr "'%s > '%s' olarak yeniden adlandırırken hata: %s\n" - #, c-format msgid "can't hash '%s': %s\n" msgstr "'%s' sağlaması yapılamıyor: %s\n" @@ -8925,22 +8911,3 @@ msgstr "Yubikey yönetim konsolu" msgid "manage the command history" msgstr "komut geçmişini yönet" - -#~ msgid "continuing verification anyway due to option %s\n" -#~ msgstr "%s seçeneğinden dolayı doğrulama yine de sürdürülüyor\n" - -#~ msgid "selected AEAD algorithm is invalid\n" -#~ msgstr "seçili AEAD algoritması geçersiz\n" - -#~ msgid "invalid personal AEAD preferences\n" -#~ msgstr "geçersiz kişisel AEAD tercihler\n" - -#~ msgid "AEAD algorithm '%s' may not be used in %s mode\n" -#~ msgstr "'%s' AEAD algoritması, %s kipinde kullanılamayabilir\n" - -#~ msgid "run in supervised mode" -#~ msgstr "yönetilen kipte çalıştır" - -#~ msgid "forcing symmetric cipher %s (%d) violates recipient preferences\n" -#~ msgstr "" -#~ "simetrik şifreleme %s (%d) zorlamak alıcı tercihlerine karşı geliyor\n" From 7c04a6a28409f8fbf49a27703ad9955d8a04ce6f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 4 Jul 2023 16:06:48 +0200 Subject: [PATCH 54/56] po: msgmerge -- --- po/cs.po | 90 +++++--------------------------------------------------- po/de.po | 3 +- po/tr.po | 16 ++++++---- 3 files changed, 19 insertions(+), 90 deletions(-) diff --git a/po/cs.po b/po/cs.po index a05a18e84..7506778cd 100644 --- a/po/cs.po +++ b/po/cs.po @@ -157,10 +157,10 @@ msgstr "neshodují se – zkuste to znovu" msgid "Passphrases match." msgstr "Heslo se shoduje." +# TODO: Pluralize #. TRANSLATORS: The string is appended to an error message in #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. -# TODO: Pluralize #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "SETERROR %s (pokus %d z %d)" @@ -786,8 +786,8 @@ msgstr "Vyžádáno použití klíče%%0A %s%%0A %s%%0APřejete si to povolit? #, c-format msgid "" -"Do you really want to delete the key identified by keygrip%%0A %s%%0A " -"%%C%%0A?" +"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C" +"%%0A?" msgstr "" "Opravdu chcete smazat klíč určený pomocí keygripu%%0A %s%%0A %%C%%0A?" @@ -8980,30 +8980,24 @@ msgstr "Příkazy pro správu Yubikey" msgid "manage the command history" msgstr "spravuje historii příkazů" -#, c-format #~ msgid "selected AEAD algorithm is invalid\n" #~ msgstr "vybraný algoritmus AEAD je neplatný\n" -#, c-format #~ msgid "invalid personal AEAD preferences\n" #~ msgstr "neplatné uživatelské předvolby pro AEAD\n" -#, c-format #~ msgid "AEAD algorithm '%s' may not be used in %s mode\n" #~ msgstr "AEAD algoritmus „%s“ se nesmí používat v režimu %s\n" -#, c-format #~ msgid "continuing verification anyway due to option %s\n" #~ msgstr "přesto se pokračuje v ověřování kvůli volbě %s\n" -#, c-format #~ msgid "error writing to temporary file: %s\n" #~ msgstr "chyba při zápisu do dočasného souboru: %s\n" #~ msgid "run in supervised mode" #~ msgstr "poběží v režimu dohledu" -#, c-format #~ msgid "forcing symmetric cipher %s (%d) violates recipient preferences\n" #~ msgstr "vyžádaná symetrická šifra %s (%d) nevyhovuje předvolbám příjemce\n" @@ -9019,15 +9013,12 @@ msgstr "spravuje historii příkazů" #~ msgid "Configuration of LDAP servers to use" #~ msgstr "Nastavení používaných LDAP serverů" -#, c-format #~ msgid "selfsigned certificate has a BAD signature" #~ msgstr "sám sebou podepsaný certifikát má CHYBNÝ podpis" -#, c-format #~ msgid "detected card with S/N: %s\n" #~ msgstr "nalezena karta se sériovým číslem: %s\n" -#, c-format #~ msgid "no authentication key for ssh on card: %s\n" #~ msgstr "na kartě není autentizační klíč pro SSH: %s\n" @@ -9037,19 +9028,15 @@ msgstr "spravuje historii příkazů" #~ msgid "use a log file for the server" #~ msgstr "použít pro server soubor s protokolem" -#, c-format #~ msgid "Note: no default option file '%s'\n" #~ msgstr "Poznámka: neexistuje implicitní soubor s možnostmi „%s“\n" -#, c-format #~ msgid "option file '%s': %s\n" #~ msgstr "soubor s možnostmi „%s“: %s\n" -#, c-format #~ msgid "connection to %s established\n" #~ msgstr "spojení k programu %s ustanoveno\n" -#, c-format #~ msgid "no running gpg-agent - starting '%s'\n" #~ msgstr "gpg-agent neběží – spouští se „%s“\n" @@ -9080,43 +9067,33 @@ msgstr "spravuje historii příkazů" #~ msgid "invalid option" #~ msgstr "neplatný parametr" -#, c-format #~ msgid "missing argument for option \"%.50s\"\n" #~ msgstr "postrádám argument u volby „%.50s“\n" -#, c-format #~ msgid "option \"%.50s\" does not expect an argument\n" #~ msgstr "volba „%.50s“ nečeká argument\n" -#, c-format #~ msgid "invalid command \"%.50s\"\n" #~ msgstr "neplatný příkaz „%.50s“\n" -#, c-format #~ msgid "option \"%.50s\" is ambiguous\n" #~ msgstr "volba „%.50s“ není jednoznačná\n" -#, c-format #~ msgid "command \"%.50s\" is ambiguous\n" #~ msgstr "příkaz „%.50s“ není jednoznačný\n" -#, c-format #~ msgid "invalid option \"%.50s\"\n" #~ msgstr "neplatný parametr „%.50s“\n" -#, c-format #~ msgid "unable to execute program '%s': %s\n" #~ msgstr "nelze spustit program „%s“: %s\n" -#, c-format #~ msgid "unable to execute external program\n" #~ msgstr "nelze spustit externí program\n" -#, c-format #~ msgid "unable to read external program response: %s\n" #~ msgstr "nelze přečíst odpověď externího programu: %s\n" -#, c-format #~ msgid "Note: old default options file '%s' ignored\n" #~ msgstr "Poznámka: starý implicitní soubor s možnostmi „%s“ ignorován\n" @@ -9126,42 +9103,34 @@ msgstr "spravuje historii příkazů" #~ msgid "elevate the trust of signatures with valid PKA data" #~ msgstr "vyzvednout důvěru podpisů s platnými daty PKA" -#, c-format #~ msgid " (%d) ECC and ECC\n" #~ msgstr " (%d) ECC a ECC\n" #~ msgid "honor the PKA record set on a key when retrieving keys" #~ msgstr "respektovat PKA záznamy klíče při získávání klíčů" -#, c-format #~ msgid "requesting key %s from %s server %s\n" #~ msgstr "požaduji klíč %s z %s serveru %s\n" -#, c-format #~ msgid "Note: Verified signer's address is '%s'\n" #~ msgstr "Poznámka: Podepisovatelova ověřená adresa je „%s“\n" -#, c-format #~ msgid "Note: Signer's address '%s' does not match DNS entry\n" #~ msgstr "" #~ "Poznámka: Podepisovatelova adresa „%s“ se neshoduje s DNS záznamem\n" -#, c-format #~ msgid "trustlevel adjusted to FULL due to valid PKA info\n" #~ msgstr "úroveň důvěry opravena na PLNOU, kvůli platné PKA informaci\n" -#, c-format #~ msgid "trustlevel adjusted to NEVER due to bad PKA info\n" #~ msgstr "úroveň důvěry opravena na ŽÁDNOU, kvůli špatné PKA informaci\n" #~ msgid "|FILE|write a server mode log to FILE" #~ msgstr "|SOUBOR|zapisovat protokol režimu server do SOUBORU" -#, c-format #~ msgid "%s:%u: no hostname given\n" #~ msgstr "%s:%u: nebyl zadán název stroje\n" -#, c-format #~ msgid "could not parse keyserver\n" #~ msgstr "nelze rozebrat serveru klíčů\n" @@ -9210,87 +9179,66 @@ msgstr "spravuje historii příkazů" #~ "Vnitřní LDAP pomůcka pro pro Dirmngr.\n" #~ "Rozhraní a volby se mohou bez upozornění změnit.\n" -#, c-format #~ msgid "invalid port number %d\n" #~ msgstr "neplatné číslo portu %d\n" -#, c-format #~ msgid "scanning result for attribute '%s'\n" #~ msgstr "ve výsledku se hledá atribut „%s“\n" -#, c-format #~ msgid "error writing to stdout: %s\n" #~ msgstr "chyba při zápisu na standardní výstup: %s\n" -#, c-format #~ msgid " available attribute '%s'\n" #~ msgstr " dostupný atribut „%s“\n" -#, c-format #~ msgid "attribute '%s' not found\n" #~ msgstr "atribut „%s“ nenalezen\n" -#, c-format #~ msgid "found attribute '%s'\n" #~ msgstr "nalezen atribut „%s“\n" -#, c-format #~ msgid "processing url '%s'\n" #~ msgstr "zpracovává se URL „%s“\n" -#, c-format #~ msgid " user '%s'\n" #~ msgstr " uživatel „%s“\n" -#, c-format #~ msgid " pass '%s'\n" #~ msgstr " heslo „%s“\n" -#, c-format #~ msgid " host '%s'\n" #~ msgstr " stroj „%s“\n" -#, c-format #~ msgid " port %d\n" #~ msgstr " port %d\n" -#, c-format #~ msgid " DN '%s'\n" #~ msgstr " DN „%s“\n" -#, c-format #~ msgid " filter '%s'\n" #~ msgstr " filtr „%s“\n" -#, c-format #~ msgid " attr '%s'\n" #~ msgstr " atribut „%s“\n" -#, c-format #~ msgid "no host name in '%s'\n" #~ msgstr "v „%s“ chybí název stroje\n" -#, c-format #~ msgid "no attribute given for query '%s'\n" #~ msgstr "u dotazu „%s“ nezadán žádný atribut\n" -#, c-format #~ msgid "WARNING: using first attribute only\n" #~ msgstr "POZOR: použije se pouze první atribut\n" -#, c-format #~ msgid "LDAP init to '%s:%d' failed: %s\n" #~ msgstr "Inicializace LDAP u „%s:%d“ selhala: %s\n" -#, c-format #~ msgid "binding to '%s:%d' failed: %s\n" #~ msgstr "napojení k „%s:%d“ selhalo: %s\n" -#, c-format #~ msgid "searching '%s' failed: %s\n" #~ msgstr "hledávání „%s“ neuspělo: %s\n" -#, c-format #~ msgid "start_cert_fetch: invalid pattern '%s'\n" #~ msgstr "start_cert_fetch: chybný vzor „%s“\n" @@ -9347,95 +9295,72 @@ msgstr "spravuje historii příkazů" #~ "Syntaxe: symcryptrun --class TŘÍDA --program PROGRAM --keyfile SOUBOR " #~ "[VOLBY…] PŘÍKAZ [VSTUPNÍ_SOUBOR]\n" -#, c-format #~ msgid "%s on %s aborted with status %i\n" #~ msgstr "%s nad %s byl ukončen s kódem %i\n" -#, c-format #~ msgid "%s on %s failed with status %i\n" #~ msgstr "%s nad %s selhal s kódem %i\n" -#, c-format #~ msgid "can't create temporary directory '%s': %s\n" #~ msgstr "nelze vytvořit dočasný adresář „%s“: %s\n" -#, c-format #~ msgid "could not open %s for writing: %s\n" #~ msgstr "%s nelze otevřít pro zápis: %s\n" -#, c-format #~ msgid "error closing %s: %s\n" #~ msgstr "chyba při zavírání chyba %s: %s\n" -#, c-format #~ msgid "no --program option provided\n" #~ msgstr "nebyla zadána volba --program\n" -#, c-format #~ msgid "only --decrypt and --encrypt are supported\n" #~ msgstr "pouze --decrypt a --encrypt jsou podporovány\n" -#, c-format #~ msgid "no --keyfile option provided\n" #~ msgstr "nebyla zadána volba --keyfile\n" -#, c-format #~ msgid "cannot allocate args vector\n" #~ msgstr "nelze alokovat pole argumentů\n" -#, c-format #~ msgid "could not create pipe: %s\n" #~ msgstr "nelze vytvořit rouru: %s\n" -#, c-format #~ msgid "could not create pty: %s\n" #~ msgstr "nelze vytvořit PTY: %s\n" -#, c-format #~ msgid "could not fork: %s\n" #~ msgstr "nelze se rozdvojit (fork): %s\n" -#, c-format #~ msgid "execv failed: %s\n" #~ msgstr "execv selhalo: %s\n" -#, c-format #~ msgid "select failed: %s\n" #~ msgstr "služba select() selhala: %s\n" -#, c-format #~ msgid "read failed: %s\n" #~ msgstr "čtení selhalo: %s\n" -#, c-format #~ msgid "pty read failed: %s\n" #~ msgstr "čtení z PTY selhalo: %s\n" -#, c-format #~ msgid "waitpid failed: %s\n" #~ msgstr "služba waitpid() selhala: %s\n" -#, c-format #~ msgid "child aborted with status %i\n" #~ msgstr "potomek byl ukončen s kódem %i\n" -#, c-format #~ msgid "cannot allocate infile string: %s\n" #~ msgstr "nelze alokovat řetězec infile: %s\n" -#, c-format #~ msgid "cannot allocate outfile string: %s\n" #~ msgstr "nelze alokovat řetězec outfile: %s\n" -#, c-format #~ msgid "either %s or %s must be given\n" #~ msgstr "musí být zadáno buď %s, nebo %s\n" -#, c-format #~ msgid "no class provided\n" #~ msgstr "nezadána žádná třída\n" -#, c-format #~ msgid "class %s is not supported\n" #~ msgstr "třída %s není podporována\n" @@ -9451,7 +9376,6 @@ msgstr "spravuje historii příkazů" #~ msgid "Sex ((M)ale, (F)emale or space): " #~ msgstr "Zadejte pohlaví: M – mužské, F – ženské, nebo stiskněte mezerník: " -#, c-format #~ msgid " using certificate ID 0x%08lX\n" #~ msgstr " pomocí certifikátu s ID 0x%08lX\n" @@ -10644,8 +10568,8 @@ msgstr "spravuje historii příkazů" #~ "\n" #~ "Note that the examples given above for levels 2 and 3 are *only* " #~ "examples.\n" -#~ "In the end, it is up to you to decide just what \"casual\" and " -#~ "\"extensive\"\n" +#~ "In the end, it is up to you to decide just what \"casual\" and \"extensive" +#~ "\"\n" #~ "mean to you when you sign other keys.\n" #~ "\n" #~ "If you don't know what the right answer is, answer \"0\"." @@ -10692,8 +10616,8 @@ msgstr "spravuje historii příkazů" #~ "Answer \"yes\" if you really want to delete this user ID.\n" #~ "All certificates are then also lost!" #~ msgstr "" -#~ "Pokud opravdu chcete smazat tento identifikátor uživatele, odpovězte " -#~ "\"ano\".\n" +#~ "Pokud opravdu chcete smazat tento identifikátor uživatele, odpovězte \"ano" +#~ "\".\n" #~ "Všechny certifikáty budou také ztraceny!" #~ msgid "Answer \"yes\" if it is okay to delete the subkey" diff --git a/po/de.po b/po/de.po index bf4bda4a0..04ed2a697 100644 --- a/po/de.po +++ b/po/de.po @@ -3832,7 +3832,8 @@ msgstr "Bitte erwägen Sie, dessen Verfallsdatum auch zu ändern.\n" #, c-format msgid "WARNING: No valid encryption subkey left over.\n" -msgstr "WARNUNG: Es sind keine Unterschlüssel zum Verschlüsseln mehr vorhanden.\n" +msgstr "" +"WARNUNG: Es sind keine Unterschlüssel zum Verschlüsseln mehr vorhanden.\n" msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " diff --git a/po/tr.po b/po/tr.po index 24313f22a..27f15bc61 100644 --- a/po/tr.po +++ b/po/tr.po @@ -731,10 +731,6 @@ msgstr "Doğru" msgid "Wrong" msgstr "Yanlış" -#, c-format -msgid "error renaming '%s' to '%s': %s\n" -msgstr "'%s > '%s' olarak yeniden adlandırırken hata: %s\n" - #, c-format msgid "Note: This passphrase has never been changed.%0APlease change it now." msgstr "" @@ -3520,8 +3516,7 @@ msgstr "Gizli yardımcı anahtarlar mevcut.\n" msgid "" "Note: the local copy of the secret key will only be deleted with \"save\".\n" -msgstr "" -"Not: Gizli anahtarın yerel kopyası yalnızca \"save\" ile silinir.\n" +msgstr "Not: Gizli anahtarın yerel kopyası yalnızca \"save\" ile silinir.\n" msgid "Need the secret key to do this.\n" msgstr "Bunu yapmak için gizli anahtar gerekli.\n" @@ -3780,6 +3775,11 @@ msgstr "UYARI: Şifreleme yardımcı anahtarının yakın zamanda süresi dolaca msgid "You may want to change its expiration date too.\n" msgstr "Son kullanma tarihini de değiştirmek isteyebilirsiniz.\n" +#, fuzzy, c-format +#| msgid "WARNING: Your encryption subkey expires soon.\n" +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "UYARI: Şifreleme yardımcı anahtarının yakın zamanda süresi dolacak.\n" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -7760,6 +7760,10 @@ msgstr "lütfen nedenini denetleyin ve o dosyayı el ile silin\n" msgid "failed to create temporary cache dir file '%s': %s\n" msgstr "geçici önbellek dizin dosyası '%s' oluşturulamadı: %s\n" +#, c-format +msgid "error renaming '%s' to '%s': %s\n" +msgstr "'%s > '%s' olarak yeniden adlandırırken hata: %s\n" + #, c-format msgid "can't hash '%s': %s\n" msgstr "'%s' sağlaması yapılamıyor: %s\n" From d073f26d81ff51afc94c908c8736eb31a31892d1 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 4 Jul 2023 15:55:19 +0200 Subject: [PATCH 55/56] Release 2.4.3 --- NEWS | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index a30440b47..f7b447160 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -Noteworthy changes in version 2.4.3 (unreleased) +Noteworthy changes in version 2.4.3 (2023-07-04) ------------------------------------------------ * gpg: Set default expiration date to 3 years. [T2701] @@ -34,11 +34,14 @@ Noteworthy changes in version 2.4.3 (unreleased) commands. [rG2c7f7a5a27] * wkd: Make --add-revocs the default in gpg-wks-client. New option - --no-add-revocs. [rG10c937ee68] + --no-add-revocs. [rG10c937ee68] + + * scd: Make signing work for Nexus cards. [rGb83d86b988] * scd: Fix authentication with Administration Key for PIV. [rG25b59cf6ce] + See-also: gnupg-announce/2023q3/000480.html Release-info: https://dev.gnupg.org/T6509 From 2378ccf97c65d2f1122f7900a5232049d13e7bd8 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 4 Jul 2023 16:44:01 +0200 Subject: [PATCH 56/56] Post release updates -- --- NEWS | 6 ++++++ configure.ac | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index f7b447160..94cd00c9f 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,9 @@ +Noteworthy changes in version 2.4.4 (unreleased) +------------------------------------------------ + + Release-info: https://dev.gnupg.org/T6578 + + Noteworthy changes in version 2.4.3 (2023-07-04) ------------------------------------------------ diff --git a/configure.ac b/configure.ac index e68b779c5..953e2616f 100644 --- a/configure.ac +++ b/configure.ac @@ -29,7 +29,7 @@ min_automake_version="1.16.3" m4_define([mym4_package],[gnupg]) m4_define([mym4_major], [2]) m4_define([mym4_minor], [4]) -m4_define([mym4_micro], [3]) +m4_define([mym4_micro], [4]) # To start a new development series, i.e a new major or minor number # you need to mark an arbitrary commit before the first beta release