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 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,11 +154,10 @@ 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." +# 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. @@ -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" @@ -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." @@ -1435,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" @@ -1701,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> " @@ -1829,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" @@ -1899,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" @@ -2346,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íčů" @@ -2357,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" @@ -2968,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 @@ -3485,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" @@ -3551,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" @@ -3665,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" @@ -3809,6 +3792,10 @@ 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" +#, c-format +msgid "WARNING: No valid encryption subkey left over.\n" +msgstr "POZOR: Nezbyl žádný platný šifrovací podklíč.\n" + msgid "" "WARNING: This is a PGP2-style key. Adding a photo ID may cause some " "versions\n" @@ -3904,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/" @@ -7831,6 +7816,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" @@ -8991,9 +8980,6 @@ 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" - #~ msgid "selected AEAD algorithm is invalid\n" #~ msgstr "vybraný algoritmus AEAD je neplatný\n" @@ -9003,6 +8989,9 @@ msgstr "spravuje historii příkazů" #~ 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" +#~ msgid "continuing verification anyway due to option %s\n" +#~ msgstr "přesto se pokračuje v ověřování kvůli volbě %s\n" + #~ msgid "error writing to temporary file: %s\n" #~ msgstr "chyba při zápisu do dočasného souboru: %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/de.po b/po/de.po index 64e444d01..04ed2a697 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,11 @@ 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 +7935,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" 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..73d141545 100644 --- a/po/ja.po +++ b/po/ja.po @@ -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今、変更してください。" @@ -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..27f15bc61 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-05-30 23:45+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" @@ -124,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 @@ -325,7 +322,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 +390,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 +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 "" @@ -763,22 +754,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" @@ -1419,7 +1407,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" @@ -1516,7 +1504,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 +1519,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 +1562,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 +1575,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 +1587,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" @@ -1684,7 +1672,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> " @@ -1803,10 +1791,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 +1864,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ı" @@ -2319,10 +2302,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" @@ -2330,10 +2311,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 +2482,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 +2506,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" @@ -2944,6 +2923,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 @@ -3466,10 +3446,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" @@ -3536,11 +3514,9 @@ 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" @@ -3656,10 +3632,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" @@ -3800,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" @@ -3906,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/" @@ -4249,7 +4227,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 +4281,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 +5226,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 +6640,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 +6671,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 +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" @@ -8933,22 +8915,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" 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" 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; } 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/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; } diff --git a/sm/decrypt.c b/sm/decrypt.c index 68b362b45..62983fe9c 100644 --- a/sm/decrypt.c +++ b/sm/decrypt.c @@ -1107,6 +1107,10 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) goto leave; } + 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) goto leave; diff --git a/sm/encrypt.c b/sm/encrypt.c index 4fd4f93b9..6e78a0620 100644 --- a/sm/encrypt.c +++ b/sm/encrypt.c @@ -653,6 +653,10 @@ 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); + if (ctrl->input_size_hint) + gnupg_ksba_set_total (b64writer, ctrl->input_size_hint); + err = ksba_cms_new (&cms); if (err) { @@ -828,7 +832,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.c b/sm/gpgsm.c index 07c3ff480..ce977413d 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")), @@ -802,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); } @@ -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 cef39ff2a..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 */ @@ -316,6 +321,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/minip12.c b/sm/minip12.c index 29b48984e..265243f3e 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 }; @@ -138,11 +140,50 @@ 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 */ }; + +#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 +{ + /* 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. */ + + 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 { + 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 { @@ -167,21 +208,31 @@ 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) +p12_set_verbosity (int verbose, int debug) { - opt_verbose = verbose; + opt_verbose = !!verbose; + if (debug) + opt_verbose = 2; } -/* 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":""); */ -/* } */ +static void +dump_tag_info (const char *text, struct tag_info *ti) +{ + 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":""); +} /* Wrapper around tlv_builder_add_ptr to add an OID. When we @@ -276,121 +327,507 @@ 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; } +/* 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; +} + + +/* 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); +} + + +/* 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: 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); + } + + /* 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 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)) + 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)); + + 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; +} + + +/* 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) +{ + 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 || 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 (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); + + 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 - 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; @@ -413,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) @@ -614,7 +1046,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)) @@ -761,482 +1193,477 @@ 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 + 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; + } + if (opt_verbose > 1) + 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 @@ -1244,7 +1671,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; } @@ -1276,363 +1715,437 @@ 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; + struct tlv_ctx_s *saved_tlv = NULL; + 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))) + saved_tlv = tlv; + 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 (opt_verbose > 1) + log_debug ("new parser context\n"); + + 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) + + 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; - 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); + if (opt_verbose > 1) + log_debug ("parser context released\n"); + } 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"); @@ -1643,181 +2156,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; } @@ -1825,7 +2339,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 * @@ -1833,16 +2347,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; - const char *where; - int bagseqlength, len; - int bagseqndef, lenndef; - unsigned char *cram_buffer = NULL; - size_t consumed; + gpg_error_t err; + const char *where = ""; + 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; @@ -1850,146 +2362,100 @@ 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 (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_expect_octet_string (tlv, 1, NULL, NULL)) goto bailout; - 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 = "cram-bags"; - cram_buffer = cram_octet_string ( p, &n, NULL); - if (!cram_buffer) - goto bailout; - p = p_start = cram_buffer; - } 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 @@ -1998,8 +2464,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; @@ -2009,7 +2481,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/server.c b/sm/server.c index 3ec1c0c4b..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); @@ -1506,7 +1510,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 +1562,45 @@ 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 (total) + { + if (current > total) + 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..235dac8cb 100644 --- a/sm/sign.c +++ b/sm/sign.c @@ -687,6 +687,10 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, goto leave; } + 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) { @@ -1027,7 +1031,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/t-minip12.c b/sm/t-minip12.c index 97bbcb9dc..de6b7e5cc 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,358 @@ 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, *save; + + hash = hash_buffer (cert, certlen); + if (*certstr) + { + save = *certstr; + *certstr = xstrconcat (save, ",", hash, NULL); + xfree (save); + 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) + { + char *save = cert; + cert = xstrconcat (save, ",", p, NULL); + xfree (save); + xfree (p); + } + 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; + int no_extra = 0; + + 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" + " --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++; + 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 = no_extra? NULL: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/sm/verify.c b/sm/verify.c index a07d1c9c7..c7f4492ce 100644 --- a/sm/verify.c +++ b/sm/verify.c @@ -158,6 +158,10 @@ 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) goto leave; 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 new file mode 100644 index 000000000..f882de9ea --- /dev/null +++ b/tests/cms/samplekeys/Description-p12 @@ -0,0 +1,32 @@ +# 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 + +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/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. - diff --git a/tests/cms/samplekeys/t5793-openssl.pfx b/tests/cms/samplekeys/t5793-openssl.pfx new file mode 100644 index 000000000..0f1beed0f Binary files /dev/null and b/tests/cms/samplekeys/t5793-openssl.pfx differ diff --git a/tests/cms/samplekeys/t5793-test.pfx b/tests/cms/samplekeys/t5793-test.pfx new file mode 100644 index 000000000..c8b256f19 Binary files /dev/null and b/tests/cms/samplekeys/t5793-test.pfx differ 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; diff --git a/tools/gpgtar-create.c b/tools/gpgtar-create.c index 534141cc1..7af5a2ede 100644 --- a/tools/gpgtar-create.c +++ b/tools/gpgtar-create.c @@ -1283,6 +1283,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 ace5e5978..f93ba2e65 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 26b405f0b..4e36deaeb 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; 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");