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/NEWS b/NEWS
index a4d4a5098..d2560a665 100644
--- a/NEWS
+++ b/NEWS
@@ -2,9 +2,75 @@ Noteworthy changes in version 2.5.0 (unreleased)
------------------------------------------------
+ Changes also found in 2.4.3:
+
+ * 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: Make signing work for Nexus cards. [rGb83d86b988]
+
+ * scd: Fix authentication with Administration Key for PIV.
+ [rG25b59cf6ce]
+
+ Changes also found in 2.4.2:
+
+ * gpg: Print a warning if no more encryption subkeys are left over
+ after changing 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 dates of 2.4 versions
-----------------------------
+Version 2.4.3 (2023-07-04) https://dev.gnupg.org/T6509
Version 2.4.2 (2023-05-30) https://dev.gnupg.org/T6506
Version 2.4.1 (2023-04-28) https://dev.gnupg.org/T6454
Version 2.4.0 (2022-12-16) https://dev.gnupg.org/T6302
diff --git a/agent/call-daemon.c b/agent/call-daemon.c
index 732e485e3..2699595e2 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;
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} \
)
diff --git a/common/iobuf.c b/common/iobuf.c
index 2adf61e3c..fb87ff65d 100644
--- a/common/iobuf.c
+++ b/common/iobuf.c
@@ -505,7 +505,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,9 +574,10 @@ 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);
- log_error ("%s: write error: ec=%d\n", a->fname, 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;
}
p += n;
@@ -634,7 +636,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;
}
@@ -883,7 +886,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;
}
@@ -2606,13 +2610,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 )
;
@@ -2625,56 +2626,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 ad416fe86..04e6b4421 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/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/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/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);
diff --git a/common/sysutils.c b/common/sysutils.c
index 8a1554a28..fc60af49c 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 7fd01bae1..50e59175f 100644
--- a/common/sysutils.h
+++ b/common/sysutils.h
@@ -111,7 +111,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"
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/dirmngr/crlcache.c b/dirmngr/crlcache.c
index 9f0b910f3..ac673a8d5 100644
--- a/dirmngr/crlcache.c
+++ b/dirmngr/crlcache.c
@@ -2356,11 +2356,21 @@ 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)
err2 = gpg_error (GPG_ERR_INV_CRL);
invalidate_crl |= INVCRL_UNKNOWN_EXTN;
diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c
index 50338f216..799f7cd5f 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,
@@ -159,6 +160,7 @@ enum cmd_and_opt_values {
oConnectQuickTimeout,
oListenBacklog,
oFakeCRL,
+ oCompatibilityFlags,
aTest
};
@@ -223,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")),
@@ -297,6 +300,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 +333,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 */
@@ -699,6 +711,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);
@@ -715,6 +728,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;
}
@@ -811,6 +825,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;
@@ -882,6 +900,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..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;
@@ -154,6 +159,9 @@ struct
current after nextUpdate. */
strlist_t keyserver; /* List of default keyservers. */
+
+ /* Compatibility flags (COMPAT_FLAG_xxxx). */
+ unsigned int compat_flags;
} opt;
@@ -182,6 +190,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/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/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);
}
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)
diff --git a/doc/dirmngr.texi b/doc/dirmngr.texi
index 8e0979c3e..0bf35b72f 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
@@ -590,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
diff --git a/doc/gpg.texi b/doc/gpg.texi
index 6b584a913..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
@@ -2671,6 +2676,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/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/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/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/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;
diff --git a/g10/encrypt.c b/g10/encrypt.c
index 00d9a0c44..b335b9797 100644
--- a/g10/encrypt.c
+++ b/g10/encrypt.c
@@ -559,12 +559,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
@@ -903,11 +903,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..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;
@@ -3499,7 +3506,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/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";
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
diff --git a/g10/photoid.c b/g10/photoid.c
index 5f4bf5e2b..8cc7e3a20 100644
--- a/g10/photoid.c
+++ b/g10/photoid.c
@@ -164,12 +164,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 */
@@ -237,11 +236,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 fcb1bb749..d6ab396af 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
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)
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..7506778cd 100644
--- a/po/cs.po
+++ b/po/cs.po
@@ -4,7 +4,7 @@
# Magda Procházková 2001,
# Roman Pavlik