diff options
author | JinWang An <jinwang.an@samsung.com> | 2023-02-01 18:02:19 +0900 |
---|---|---|
committer | JinWang An <jinwang.an@samsung.com> | 2023-02-01 18:02:19 +0900 |
commit | 0d6c0bc071b2e571c18781271972f6f9ee62dc8a (patch) | |
tree | c5e1a47f591d580b340ebc524b0061ebc1f56f29 /g10 | |
parent | 7909696cfccd5cb051854ae81d49750d09b23ff7 (diff) | |
download | gpg2-upstream.tar.gz gpg2-upstream.tar.bz2 gpg2-upstream.zip |
Imported Upstream version 2.4.0upstream/2.4.0upstream
Diffstat (limited to 'g10')
-rw-r--r-- | g10/Makefile.am | 22 | ||||
-rw-r--r-- | g10/Makefile.in | 60 | ||||
-rw-r--r-- | g10/all-tests.scm | 7 | ||||
-rw-r--r-- | g10/armor.c | 30 | ||||
-rw-r--r-- | g10/build-packet.c | 24 | ||||
-rw-r--r-- | g10/call-agent.c | 20 | ||||
-rw-r--r-- | g10/call-agent.h | 2 | ||||
-rw-r--r-- | g10/call-keyboxd.c | 2 | ||||
-rw-r--r-- | g10/card-util.c | 1 | ||||
-rw-r--r-- | g10/cipher-aead.c | 4 | ||||
-rw-r--r-- | g10/decrypt-data.c | 14 | ||||
-rw-r--r-- | g10/ecdh.c | 23 | ||||
-rw-r--r-- | g10/encrypt.c | 17 | ||||
-rw-r--r-- | g10/exec.c | 115 | ||||
-rw-r--r-- | g10/exec.h | 1 | ||||
-rw-r--r-- | g10/export.c | 446 | ||||
-rw-r--r-- | g10/gpg.c | 148 | ||||
-rw-r--r-- | g10/gpgv.c | 8 | ||||
-rw-r--r-- | g10/import.c | 135 | ||||
-rw-r--r-- | g10/kbnode.c | 13 | ||||
-rw-r--r-- | g10/keydb.h | 1 | ||||
-rw-r--r-- | g10/keyedit.c | 208 | ||||
-rw-r--r-- | g10/keyedit.h | 1 | ||||
-rw-r--r-- | g10/keygen.c | 57 | ||||
-rw-r--r-- | g10/keylist.c | 254 | ||||
-rw-r--r-- | g10/main.h | 11 | ||||
-rw-r--r-- | g10/mainproc.c | 2 | ||||
-rw-r--r-- | g10/misc.c | 11 | ||||
-rw-r--r-- | g10/options.h | 14 | ||||
-rw-r--r-- | g10/parse-packet.c | 48 | ||||
-rw-r--r-- | g10/photoid.c | 109 | ||||
-rw-r--r-- | g10/pkclist.c | 4 | ||||
-rw-r--r-- | g10/test-stubs.c | 8 | ||||
-rw-r--r-- | g10/trustdb.c | 50 |
34 files changed, 1202 insertions, 668 deletions
diff --git a/g10/Makefile.am b/g10/Makefile.am index eb23573..80b5b89 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -47,9 +47,7 @@ endif # NB: We use noinst_ for gpg and gpgv so that we can install them with # the install-hook target under the name gpg2/gpgv2. noinst_PROGRAMS = gpg -if !HAVE_W32CE_SYSTEM noinst_PROGRAMS += gpgv -endif noinst_PROGRAMS += $(module_tests) if DISABLE_TESTS TESTS = @@ -170,15 +168,15 @@ gpgv_SOURCES = gpgv.c \ verify.c LDADD = $(needed_libs) ../common/libgpgrl.a \ - $(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS) + $(ZLIBS) $(LIBINTL) $(CAPLIBS) gpg_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \ - $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ - $(LIBICONV) $(resource_objs) $(extra_sys_libs) -gpg_LDFLAGS = $(extra_bin_ldflags) + $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) $(NETLIBS) \ + $(LIBICONV) $(resource_objs) +gpg_LDFLAGS = gpgv_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ - $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ - $(LIBICONV) $(resource_objs) $(extra_sys_libs) -gpgv_LDFLAGS = $(extra_bin_ldflags) + $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) $(NETLIBS) \ + $(LIBICONV) $(resource_objs) +gpgv_LDFLAGS = t_common_ldadd = @@ -187,17 +185,17 @@ t_rmd160_SOURCES = t-rmd160.c rmd160.c t_rmd160_LDADD = $(t_common_ldadd) t_keydb_SOURCES = t-keydb.c test-stubs.c $(common_source) t_keydb_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ - $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ + $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) $(NETLIBS) \ $(LIBICONV) $(t_common_ldadd) t_keydb_get_keyblock_SOURCES = t-keydb-get-keyblock.c test-stubs.c \ $(common_source) t_keydb_get_keyblock_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ - $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ + $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) $(NETLIBS) \ $(LIBICONV) $(t_common_ldadd) t_stutter_SOURCES = t-stutter.c test-stubs.c \ $(common_source) t_stutter_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ - $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ + $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) $(NETLIBS) \ $(LIBICONV) $(t_common_ldadd) diff --git a/g10/Makefile.in b/g10/Makefile.in index 8574cff..77ae8a8 100644 --- a/g10/Makefile.in +++ b/g10/Makefile.in @@ -142,10 +142,9 @@ host_triplet = @host@ @GNUPG_DIRMNGR_PGM_TRUE@am__append_6 = -DGNUPG_DEFAULT_DIRMNGR="\"@GNUPG_DIRMNGR_PGM@\"" @GNUPG_PROTECT_TOOL_PGM_TRUE@am__append_7 = -DGNUPG_DEFAULT_PROTECT_TOOL="\"@GNUPG_PROTECT_TOOL_PGM@\"" @GNUPG_DIRMNGR_LDAP_PGM_TRUE@am__append_8 = -DGNUPG_DEFAULT_DIRMNGR_LDAP="\"@GNUPG_DIRMNGR_LDAP_PGM@\"" -noinst_PROGRAMS = gpg$(EXEEXT) $(am__EXEEXT_1) $(am__EXEEXT_2) -@HAVE_W32CE_SYSTEM_FALSE@am__append_9 = gpgv -@DISABLE_TESTS_FALSE@TESTS = $(am__EXEEXT_2) -@HAVE_W32_SYSTEM_TRUE@am__append_10 = gpg-w32info.o +noinst_PROGRAMS = gpg$(EXEEXT) gpgv$(EXEEXT) $(am__EXEEXT_1) +@DISABLE_TESTS_FALSE@TESTS = $(am__EXEEXT_1) +@HAVE_W32_SYSTEM_TRUE@am__append_9 = gpg-w32info.o subdir = g10 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/autobuild.m4 \ @@ -167,8 +166,7 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/build-aux/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = gpg.w32-manifest CONFIG_CLEAN_VPATH_FILES = -@HAVE_W32CE_SYSTEM_FALSE@am__EXEEXT_1 = gpgv$(EXEEXT) -am__EXEEXT_2 = t-rmd160$(EXEEXT) t-keydb$(EXEEXT) \ +am__EXEEXT_1 = t-rmd160$(EXEEXT) t-keydb$(EXEEXT) \ t-keydb-get-keyblock$(EXEEXT) t-stutter$(EXEEXT) PROGRAMS = $(noinst_PROGRAMS) am__gpg_SOURCES_DIST = gpg.c keyedit.c keyedit.h server.c gpg.h dek.h \ @@ -217,13 +215,12 @@ am_gpg_OBJECTS = gpg.$(OBJEXT) keyedit.$(OBJEXT) $(am__objects_6) gpg_OBJECTS = $(am_gpg_OBJECTS) am__DEPENDENCIES_1 = am__DEPENDENCIES_2 = $(needed_libs) ../common/libgpgrl.a \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) gpg_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) $(resource_objs) \ - $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(resource_objs) gpg_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(gpg_LDFLAGS) $(LDFLAGS) -o \ $@ am__gpgv_SOURCES_DIST = gpgv.c gpg.h dek.h build-packet.c compress.c \ @@ -238,8 +235,8 @@ am_gpgv_OBJECTS = gpgv.$(OBJEXT) $(am__objects_2) verify.$(OBJEXT) gpgv_OBJECTS = $(am_gpgv_OBJECTS) gpgv_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) $(resource_objs) \ - $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(resource_objs) gpgv_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(gpgv_LDFLAGS) $(LDFLAGS) \ -o $@ am__t_keydb_SOURCES_DIST = t-keydb.c test-stubs.c gpg.h dek.h \ @@ -256,7 +253,7 @@ t_keydb_OBJECTS = $(am_t_keydb_OBJECTS) t_keydb_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am__t_keydb_get_keyblock_SOURCES_DIST = t-keydb-get-keyblock.c \ test-stubs.c gpg.h dek.h build-packet.c compress.c \ compress-bz2.c filter.h free-packet.c getkey.c expand-group.c \ @@ -272,7 +269,8 @@ t_keydb_get_keyblock_OBJECTS = $(am_t_keydb_get_keyblock_OBJECTS) t_keydb_get_keyblock_DEPENDENCIES = $(am__DEPENDENCIES_2) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) am_t_rmd160_OBJECTS = t-rmd160.$(OBJEXT) rmd160.$(OBJEXT) t_rmd160_OBJECTS = $(am_t_rmd160_OBJECTS) t_rmd160_DEPENDENCIES = $(am__DEPENDENCIES_1) @@ -290,7 +288,7 @@ t_stutter_OBJECTS = $(am_t_stutter_OBJECTS) t_stutter_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false @@ -615,17 +613,7 @@ AM_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" $(am__append_1) \ $(am__append_2) $(am__append_3) $(am__append_4) \ $(am__append_5) $(am__append_6) $(am__append_7) \ $(am__append_8) -@HAVE_W32CE_SYSTEM_FALSE@extra_sys_libs = - -# Under Windows we use LockFileEx. WindowsCE provides this only on -# the WindowsMobile 6 platform and thus we need to use the coredll6 -# import library. We also want to use a stacksize of 256k instead of -# the 2MB which is the default with cegcc. 256k is the largest stack -# we use with pth. -@HAVE_W32CE_SYSTEM_TRUE@extra_sys_libs = -lcoredll6 -@HAVE_W32CE_SYSTEM_FALSE@extra_bin_ldflags = -@HAVE_W32CE_SYSTEM_TRUE@extra_bin_ldflags = -Wl,--stack=0x40000 -resource_objs = $(am__append_10) +resource_objs = $(am__append_9) # Convenience macros libcommon = ../common/libcommon.a @@ -734,39 +722,39 @@ gpgv_SOURCES = gpgv.c \ verify.c LDADD = $(needed_libs) ../common/libgpgrl.a \ - $(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS) + $(ZLIBS) $(LIBINTL) $(CAPLIBS) gpg_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \ - $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ - $(LIBICONV) $(resource_objs) $(extra_sys_libs) + $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) $(NETLIBS) \ + $(LIBICONV) $(resource_objs) -gpg_LDFLAGS = $(extra_bin_ldflags) +gpg_LDFLAGS = gpgv_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ - $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ - $(LIBICONV) $(resource_objs) $(extra_sys_libs) + $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) $(NETLIBS) \ + $(LIBICONV) $(resource_objs) -gpgv_LDFLAGS = $(extra_bin_ldflags) +gpgv_LDFLAGS = t_common_ldadd = module_tests = t-rmd160 t-keydb t-keydb-get-keyblock t-stutter t_rmd160_SOURCES = t-rmd160.c rmd160.c t_rmd160_LDADD = $(t_common_ldadd) t_keydb_SOURCES = t-keydb.c test-stubs.c $(common_source) t_keydb_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ - $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ + $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) $(NETLIBS) \ $(LIBICONV) $(t_common_ldadd) t_keydb_get_keyblock_SOURCES = t-keydb-get-keyblock.c test-stubs.c \ $(common_source) t_keydb_get_keyblock_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ - $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ + $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) $(NETLIBS) \ $(LIBICONV) $(t_common_ldadd) t_stutter_SOURCES = t-stutter.c test-stubs.c \ $(common_source) t_stutter_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ - $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ + $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) $(NETLIBS) \ $(LIBICONV) $(t_common_ldadd) all: all-am diff --git a/g10/all-tests.scm b/g10/all-tests.scm index 982220b..02fcde7 100644 --- a/g10/all-tests.scm +++ b/g10/all-tests.scm @@ -27,9 +27,10 @@ (parse-makefile-expand filename expander key)) (map (lambda (name) - (test::binary #f - (path-join "g10" name) - (path-join (getenv "objdir") "g10" name))) + (let ((name-ext (string-append name (getenv "EXEEXT")))) + (test::binary #f + (path-join "g10" name-ext) + (path-join (getenv "objdir") "g10" name-ext)))) (parse-makefile-expand (in-srcdir "g10" "Makefile.am") (lambda (filename port key) (parse-makefile port key)) "module_tests"))) diff --git a/g10/armor.c b/g10/armor.c index 7693483..b47c04a 100644 --- a/g10/armor.c +++ b/g10/armor.c @@ -247,6 +247,7 @@ is_armored (const byte *buf) case PKT_COMPRESSED: case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: + case PKT_ENCRYPTED_AEAD: case PKT_PLAINTEXT: case PKT_OLD_COMMENT: case PKT_COMMENT: @@ -649,6 +650,7 @@ fake_packet( armor_filter_context_t *afx, IOBUF a, byte *p; byte tempbuf[PARTIAL_CHUNK]; size_t tempbuf_len=0; + int this_truncated; while( !rc && size-len>=(PARTIAL_CHUNK+1)) { /* copy what we have in the line buffer */ @@ -683,7 +685,13 @@ fake_packet( armor_filter_context_t *afx, IOBUF a, continue; } if( !maxlen ) + { afx->truncated++; + this_truncated = 1; + } + else + this_truncated = 0; + p = afx->buffer; n = afx->buffer_len; @@ -736,7 +744,7 @@ fake_packet( armor_filter_context_t *afx, IOBUF a, } /* Now handle the end-of-line canonicalization */ - if( !afx->not_dash_escaped ) + if( !afx->not_dash_escaped || this_truncated) { int crlf = n > 1 && p[n-2] == '\r' && p[n-1]=='\n'; @@ -753,10 +761,17 @@ fake_packet( armor_filter_context_t *afx, IOBUF a, * or calculate the hash here in this module and somehow find * a way to send the hash down the processing line (well, a special * faked packet could do the job). + * + * To make sure that a truncated line triggers a bad + * signature error we replace a removed LF by a FF or + * append a FF. Right, this is a hack but better than a + * global variable and way easier than to introduce a new + * control packet or insert a line like "[truncated]\n" + * into the filter output. */ if( crlf ) afx->buffer[afx->buffer_len++] = '\r'; - afx->buffer[afx->buffer_len++] = '\n'; + afx->buffer[afx->buffer_len++] = this_truncated? '\f':'\n'; afx->buffer[afx->buffer_len] = '\0'; } } @@ -1125,11 +1140,11 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn, rc = 0; else if( rc == 2 ) { log_error(_("premature eof (in trailer)\n")); - rc = GPG_ERR_INVALID_ARMOR; + rc = GPG_ERR_INV_ARMOR; } else { log_error(_("error in trailer line\n")); - rc = GPG_ERR_INVALID_ARMOR; + rc = GPG_ERR_INV_ARMOR; } #endif } @@ -1277,7 +1292,7 @@ armor_filter( void *opaque, int control, if( !fp ) { fp = fopen("armor.out", "w"); - assert(fp); + log_assert(fp); } #endif @@ -1538,6 +1553,11 @@ armor_filter( void *opaque, int control, afx->no_openpgp_data = 1; write_status_text( STATUS_NODATA, "1" ); } + /* Note that in a cleartext signature truncated lines in the + * plaintext are detected and propagated to the signature + * checking code by inserting a \f into the plaintext. We do + * not use log_info here because some of the truncated lines + * are harmless. */ if( afx->truncated ) log_info(_("invalid armor: line longer than %d characters\n"), MAX_LINELEN ); diff --git a/g10/build-packet.c b/g10/build-packet.c index cc95355..f33d156 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -674,7 +674,8 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk) count += 8; /* Salt. */ if (ski->s2k.mode == 3) count++; /* S2K.COUNT */ - if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002) + if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002 + && ski->s2k.mode != 1003) count += ski->ivlen; iobuf_put (a, count); @@ -704,8 +705,9 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk) if (ski->s2k.mode == 3) iobuf_put (a, ski->s2k.count); - /* For our special modes 1001, 1002 we do not need an IV. */ - if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002) + /* For our special modes 1001..1003 we do not need an IV. */ + if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002 + && ski->s2k.mode != 1003) iobuf_write (a, ski->iv, ski->ivlen); } @@ -733,6 +735,22 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk) /* The serial number gets stored in the IV field. */ iobuf_write (a, ski->iv, ski->ivlen); } + else if (ski->s2k.mode == 1003) + { + /* GnuPG extension - Store raw s-expression. */ + byte *p; + unsigned int ndatabits; + + log_assert (gcry_mpi_get_flag (pk->pkey[npkey], GCRYMPI_FLAG_OPAQUE)); + + p = gcry_mpi_get_opaque (pk->pkey[npkey], &ndatabits); + /* For v5 keys we first write the number of octets of the + * following key material. */ + if (is_v5) + write_32 (a, p? (ndatabits+7)/8 : 0); + if (p) + iobuf_write (a, p, (ndatabits+7)/8 ); + } else if (ski->is_protected) { /* The secret key is protected - write it out as it is. */ diff --git a/g10/call-agent.c b/g10/call-agent.c index 27b5cac..66812e9 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -2997,13 +2997,15 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr, keygrip, DESC a prompt to be displayed with the agent's passphrase question (needs to be plus+percent escaped). if OPENPGP_PROTECTED is not zero, ensure that the key material is returned in RFC - 4880-compatible passphrased-protected form. If CACHE_NONCE_ADDR is - not NULL the agent is advised to first try a passphrase associated - with that nonce. On success the key is stored as a canonical - S-expression at R_RESULT and R_RESULTLEN. */ + 4880-compatible passphrased-protected form; if instead MODE1003 is + not zero the raw gpg-agent private key format is requested (either + protected or unprotected). If CACHE_NONCE_ADDR is not NULL the + agent is advised to first try a passphrase associated with that + nonce. On success the key is stored as a canonical S-expression at + R_RESULT and R_RESULTLEN. */ gpg_error_t agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc, - int openpgp_protected, char **cache_nonce_addr, + int openpgp_protected, int mode1003, char **cache_nonce_addr, unsigned char **r_result, size_t *r_resultlen, u32 *keyid, u32 *mainkeyid, int pubkey_algo) { @@ -3028,6 +3030,12 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc, return err; dfltparm.ctx = agent_ctx; + /* Check that the gpg-agent supports the --mode1003 option. */ + if (mode1003 && assuan_transact (agent_ctx, + "GETINFO cmd_has_option EXPORT_KEY mode1003", + NULL, NULL, NULL, NULL, NULL, NULL)) + return gpg_error (GPG_ERR_NOT_SUPPORTED); + if (desc) { snprintf (line, DIM(line), "SETKEYDESC %s", desc); @@ -3038,7 +3046,7 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc, } snprintf (line, DIM(line), "EXPORT_KEY %s%s%s %s", - openpgp_protected ? "--openpgp ":"", + mode1003? "--mode1003" : openpgp_protected ? "--openpgp ":"", cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"", cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"", hexkeygrip); diff --git a/g10/call-agent.h b/g10/call-agent.h index a4cbc31..a3f234a 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -231,7 +231,7 @@ gpg_error_t agent_import_key (ctrl_t ctrl, const char *desc, /* Receive a key from the agent. */ gpg_error_t agent_export_key (ctrl_t ctrl, const char *keygrip, const char *desc, int openpgp_protected, - char **cache_nonce_addr, + int mode1003, char **cache_nonce_addr, unsigned char **r_result, size_t *r_resultlen, u32 *keyid, u32 *mainkeyid, int pubkey_algo); diff --git a/g10/call-keyboxd.c b/g10/call-keyboxd.c index e2fede2..7f4d5f4 100644 --- a/g10/call-keyboxd.c +++ b/g10/call-keyboxd.c @@ -106,7 +106,7 @@ gpg_keyboxd_deinit_session_data (ctrl_t ctrl) err = assuan_transact (kbl->ctx, "TRANSACTION commit", NULL, NULL, NULL, NULL, NULL, NULL); if (err) - log_error ("error commiting last transaction: %s\n", + log_error ("error committing last transaction: %s\n", gpg_strerror (err)); in_transaction = 0; } diff --git a/g10/card-util.c b/g10/card-util.c index 339194f..02de241 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -843,7 +843,6 @@ change_name (void) { tty_printf (_("Error: Combined name too long " "(limit is %d characters).\n"), 39); - xfree (isoname); rc = gpg_error (GPG_ERR_TOO_LARGE); goto leave; } diff --git a/g10/cipher-aead.c b/g10/cipher-aead.c index 8eea703..640d843 100644 --- a/g10/cipher-aead.c +++ b/g10/cipher-aead.c @@ -295,9 +295,9 @@ do_flush (cipher_filter_context_t *cfx, iobuf_t a, byte *buf, size_t size) size_t n1 = cfx->chunksize - (cfx->chunklen + cfx->buflen); finalize = 1; if (DBG_FILTER) - log_debug ("chunksize %"PRIu64" reached;" + log_debug ("chunksize %llu reached;" " cur buflen=%zu using %zu of %zu\n", - cfx->chunksize, cfx->buflen, + (unsigned long long)cfx->chunksize, cfx->buflen, n1, n); n = n1; } diff --git a/g10/decrypt-data.c b/g10/decrypt-data.c index bdc3e22..86e208d 100644 --- a/g10/decrypt-data.c +++ b/g10/decrypt-data.c @@ -675,8 +675,10 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len) /* Decrypt the buffer. This first requires a loop to handle the * case when a chunk ends within the buffer. */ if (DBG_FILTER) - log_debug ("decrypt: chunklen=%"PRIu64" total=%"PRIu64" size=%zu len=%zu%s\n", - dfx->chunklen, dfx->total, size, len, + log_debug ("decrypt: chunklen=%llu total=%llu size=%zu len=%zu%s\n", + (unsigned long long)dfx->chunklen, + (unsigned long long)dfx->total, + size, len, dfx->eof_seen? " eof":""); while (len && dfx->chunklen + len >= dfx->chunksize) @@ -712,8 +714,8 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len) len -= n; if (DBG_FILTER) - log_debug ("ndecrypted: %zu (nchunk=%"PRIu64") bytes left: %zu at off=%zu\n", - totallen, dfx->chunklen, len, off); + log_debug ("ndecrypted: %zu (nchunk=%llu) bytes left: %zu at off=%zu\n", + totallen, (unsigned long long)dfx->chunklen, len, off); /* Check the tag. */ if (len < 16) @@ -794,8 +796,8 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len) dfx->chunklen += len; dfx->total += len; if (DBG_FILTER) - log_debug ("ndecrypted: %zu (nchunk=%"PRIu64")\n", - totallen, dfx->chunklen); + log_debug ("ndecrypted: %zu (nchunk=%llu)\n", + totallen, (unsigned long long)dfx->chunklen); } if (dfx->eof_seen) @@ -189,6 +189,28 @@ derive_kek (size_t kek_size, const unsigned char *kdf_params, size_t kdf_params_size) { gpg_error_t err; +#if 0 /* GCRYPT_VERSION_NUMBER >= 0x010b00 */ + /* + * Experimental: We will remove this if/endif-conditional + * compilation when we update NEED_LIBGCRYPT_VERSION to 1.11.0. + */ + gcry_kdf_hd_t hd; + unsigned long param[1]; + + param[0] = kek_size; + err = gcry_kdf_open (&hd, GCRY_KDF_ONESTEP_KDF, kdf_hash_algo, + param, 1, + secret_x, secret_x_size, NULL, 0, NULL, 0, + kdf_params, kdf_params_size); + if (!err) + { + gcry_kdf_compute (hd, NULL); + gcry_kdf_final (hd, kek_size, secret_x); + gcry_kdf_close (hd); + /* Clean the tail before returning. */ + memset (secret_x+kek_size, 0, secret_x_size - kek_size); + } +#else gcry_md_hd_t h; log_assert( gcry_md_get_algo_dlen (kdf_hash_algo) >= 32 ); @@ -208,6 +230,7 @@ derive_kek (size_t kek_size, gcry_md_close (h); /* Clean the tail before returning. */ memset (secret_x+kek_size, 0, secret_x_size - kek_size); +#endif if (DBG_CRYPTO) log_printhex (secret_x, kek_size, "ecdh KEK is:"); return err; diff --git a/g10/encrypt.c b/g10/encrypt.c index 019bf0b..d0e1427 100644 --- a/g10/encrypt.c +++ b/g10/encrypt.c @@ -219,7 +219,7 @@ check_encryption_compliance (DEK *dek, pk_list_t pk_list) * stored at R_SESKEY. If AEAD_ALGO is not 0 the given AEAD algorithm * is used for encryption. */ -gpg_error_t +static gpg_error_t encrypt_seskey (DEK *dek, aead_algo_t aead_algo, DEK **r_seskey, void **r_enckey, size_t *r_enckeylen) { @@ -344,14 +344,6 @@ use_aead (pk_list_t pk_list, int algo) { int can_use; - if (!opt.flags.rfc4880bis) - { - if (opt.force_aead) - log_info ("Warning: Option %s currently requires option '%s'\n", - "--force-aead", "--rfc4880bis"); - return 0; - } - can_use = openpgp_cipher_get_algo_blklen (algo) == 16; /* With --force-aead we want AEAD. */ @@ -359,11 +351,11 @@ use_aead (pk_list_t pk_list, int algo) { if (!can_use) { - log_info ("Warning: request to use AEAD ignored for cipher '%s'\n", + log_info ("Warning: request to use OCB ignored for cipher '%s'\n", openpgp_cipher_algo_name (algo)); return 0; } - return default_aead_algo (); + return AEAD_ALGO_OCB; } /* AEAD does only work with 128 bit cipher blocklength. */ @@ -478,8 +470,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey) if (use_seskey && s2k->mode != 1 && s2k->mode != 3) { use_seskey = 0; - log_info (_("can't use a symmetric ESK packet " - "due to the S2K mode\n")); + log_info (_("can't use a SKESK packet due to the S2K mode\n")); } /* See whether we want to use AEAD. */ @@ -19,12 +19,6 @@ #include <config.h> #include <stdlib.h> -#ifdef HAVE_DOSISH_SYSTEM -# ifdef HAVE_WINSOCK2_H -# include <winsock2.h> -# endif -# include <windows.h> -#endif #include <string.h> #include "gpg.h" @@ -35,115 +29,6 @@ #ifdef NO_EXEC int set_exec_path(const char *path) { return GPG_ERR_GENERAL; } #else -#if defined (_WIN32) -/* This is a nicer system() for windows that waits for programs to - return before returning control to the caller. I hate helpful - computers. */ -int -w32_system(const char *command) -{ - if (!strncmp (command, "!ShellExecute ", 14)) - { - SHELLEXECUTEINFOW see; - wchar_t *wname; - int waitms; - - command = command + 14; - while (spacep (command)) - command++; - waitms = atoi (command); - if (waitms < 0) - waitms = 0; - else if (waitms > 60*1000) - waitms = 60000; - while (*command && !spacep (command)) - command++; - while (spacep (command)) - command++; - - wname = utf8_to_wchar (command); - if (!wname) - return -1; - - memset (&see, 0, sizeof see); - see.cbSize = sizeof see; - see.fMask = (SEE_MASK_NOCLOSEPROCESS - | SEE_MASK_NOASYNC - | SEE_MASK_FLAG_NO_UI - | SEE_MASK_NO_CONSOLE); - see.lpVerb = L"open"; - see.lpFile = (LPCWSTR)wname; - see.nShow = SW_SHOW; - - if (DBG_EXTPROG) - log_debug ("running ShellExecuteEx(open,'%s')\n", command); - if (!ShellExecuteExW (&see)) - { - if (DBG_EXTPROG) - log_debug ("ShellExecuteEx failed: rc=%d\n", (int)GetLastError ()); - xfree (wname); - return -1; - } - if (DBG_EXTPROG) - log_debug ("ShellExecuteEx succeeded (hProcess=%p,hInstApp=%d)\n", - see.hProcess, (int)see.hInstApp); - - if (!see.hProcess) - { - gnupg_usleep (waitms*1000); - if (DBG_EXTPROG) - log_debug ("ShellExecuteEx ready (wait=%dms)\n", waitms); - } - else - { - WaitForSingleObject (see.hProcess, INFINITE); - if (DBG_EXTPROG) - log_debug ("ShellExecuteEx ready\n"); - } - CloseHandle (see.hProcess); - - xfree (wname); - } - else - { - char *string; - wchar_t *wstring; - PROCESS_INFORMATION pi; - STARTUPINFOW si; - - /* We must use a copy of the command as CreateProcess modifies - * this argument. */ - string = xstrdup (command); - wstring = utf8_to_wchar (string); - xfree (string); - if (!wstring) - return -1; - - memset (&pi, 0, sizeof(pi)); - memset (&si, 0, sizeof(si)); - si.cb = sizeof (si); - - if (!CreateProcessW (NULL, wstring, NULL, NULL, FALSE, - DETACHED_PROCESS, - NULL, NULL, &si, &pi)) - { - xfree (wstring); - return -1; - } - - /* Wait for the child to exit */ - WaitForSingleObject (pi.hProcess, INFINITE); - - CloseHandle (pi.hProcess); - CloseHandle (pi.hThread); - xfree (wstring); - } - - return 0; -} -#endif /*_W32*/ - - /* Replaces current $PATH */ int set_exec_path(const char *path) @@ -21,6 +21,5 @@ #define _EXEC_H_ int set_exec_path(const char *path); -int w32_system(const char *command); #endif /* !_EXEC_H_ */ diff --git a/g10/export.c b/g10/export.c index edf27bc..b3ad697 100644 --- a/g10/export.c +++ b/g10/export.c @@ -2,6 +2,7 @@ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, * 2005, 2010 Free Software Foundation, Inc. * Copyright (C) 1998-2016 Werner Koch + * Copyright (C) 2022 g10 Code GmbH * * This file is part of GnuPG. * @@ -63,15 +64,17 @@ struct export_stats_s }; -/* A global variable to store the selector created from +/* Global variables to store the selectors created from * --export-filter keep-uid=EXPR. * --export-filter drop-subkey=EXPR. + * --export-filter select=EXPR. * * FIXME: We should put this into the CTRL object but that requires a * lot more changes right now. */ static recsel_expr_t export_keep_uid; static recsel_expr_t export_drop_subkey; +static recsel_expr_t export_select_filter; /* An object used for a linked list to implement the @@ -81,6 +84,7 @@ struct export_filter_attic_s struct export_filter_attic_s *next; recsel_expr_t export_keep_uid; recsel_expr_t export_drop_subkey; + recsel_expr_t export_select_filter; }; static struct export_filter_attic_s *export_filter_attic; @@ -105,6 +109,8 @@ cleanup_export_globals (void) export_keep_uid = NULL; recsel_release (export_drop_subkey); export_drop_subkey = NULL; + recsel_release (export_select_filter); + export_select_filter = NULL; } @@ -128,10 +134,16 @@ parse_export_options(char *str,unsigned int *options,int noisy) {"export-dane", EXPORT_DANE_FORMAT, NULL, NULL }, + {"export-revocs", EXPORT_REVOCS, NULL, + N_("export only revocation certificates") }, + {"backup", EXPORT_BACKUP, NULL, N_("use the GnuPG key backup format")}, {"export-backup", EXPORT_BACKUP, NULL, NULL }, + {"mode1003", EXPORT_MODE1003, NULL, + N_("export secret keys using the GnuPG format") }, + /* Aliases for backward compatibility */ {"include-local-sigs",EXPORT_LOCAL_SIGS,NULL,NULL}, {"include-attributes",EXPORT_ATTRIBUTES,NULL,NULL}, @@ -184,6 +196,8 @@ parse_export_options(char *str,unsigned int *options,int noisy) * * - secret :: 1 for a secret subkey, else 0. * - key_algo :: Public key algorithm id + * + * - select :: The key is only exported if the filter returns true. */ gpg_error_t parse_and_set_export_filter (const char *string) @@ -197,6 +211,8 @@ parse_and_set_export_filter (const char *string) err = recsel_parse_expr (&export_keep_uid, string+9); else if (!strncmp (string, "drop-subkey=", 12)) err = recsel_parse_expr (&export_drop_subkey, string+12); + else if (!strncmp (string, "select=", 7)) + err = recsel_parse_expr (&export_select_filter, string+7); else err = gpg_error (GPG_ERR_INV_NAME); @@ -217,6 +233,8 @@ push_export_filters (void) export_keep_uid = NULL; item->export_drop_subkey = export_drop_subkey; export_drop_subkey = NULL; + item->export_select_filter = export_select_filter; + export_select_filter = NULL; item->next = export_filter_attic; export_filter_attic = item; } @@ -235,6 +253,7 @@ pop_export_filters (void) cleanup_export_globals (); export_keep_uid = item->export_keep_uid; export_drop_subkey = item->export_drop_subkey; + export_select_filter = item->export_select_filter; } @@ -624,6 +643,183 @@ canon_pk_algo (enum gcry_pk_algos algo) } +/* Take an s-expression wit the public and private key and change the + * parameter array in PK to include the secret parameters. */ +static gpg_error_t +secret_key_to_mode1003 (gcry_sexp_t s_key, PKT_public_key *pk) +{ + gpg_error_t err; + gcry_sexp_t list = NULL; + gcry_sexp_t l2; + enum gcry_pk_algos pk_algo; + struct seckey_info *ski; + int idx; + char *string; + size_t npkey, nskey; + gcry_mpi_t pub_params[10] = { NULL }; + + /* We look for a private-key, then the first element in it tells us + the type */ + list = gcry_sexp_find_token (s_key, "protected-private-key", 0); + if (!list) + list = gcry_sexp_find_token (s_key, "private-key", 0); + if (!list) + { + err = gpg_error (GPG_ERR_BAD_SECKEY); + goto leave; + } + + log_assert (!pk->seckey_info); + + /* Parse the gcrypt PK algo and check that it is okay. */ + l2 = gcry_sexp_cadr (list); + if (!l2) + { + err = gpg_error (GPG_ERR_BAD_SECKEY); + goto leave; + } + gcry_sexp_release (list); + list = l2; + string = gcry_sexp_nth_string (list, 0); + if (!string) + { + err = gpg_error (GPG_ERR_BAD_SECKEY); + goto leave; + } + pk_algo = gcry_pk_map_name (string); + xfree (string); string = NULL; + if (gcry_pk_algo_info (pk_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey) + || gcry_pk_algo_info (pk_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey) + || !npkey || npkey >= nskey) + { + err = gpg_error (GPG_ERR_BAD_SECKEY); + goto leave; + } + + /* Check that the pubkey algo and the received parameters matches + * those from the public key. */ + switch (canon_pk_algo (pk_algo)) + { + case GCRY_PK_RSA: + if (!is_RSA (pk->pubkey_algo) || npkey != 2) + err = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Does not match. */ + else + err = gcry_sexp_extract_param (list, NULL, "ne", + &pub_params[0], + &pub_params[1], + NULL); + break; + + case GCRY_PK_DSA: + if (!is_DSA (pk->pubkey_algo) || npkey != 4) + err = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Does not match. */ + else + err = gcry_sexp_extract_param (list, NULL, "pqgy", + &pub_params[0], + &pub_params[1], + &pub_params[2], + &pub_params[3], + NULL); + break; + + case GCRY_PK_ELG: + if (!is_ELGAMAL (pk->pubkey_algo) || npkey != 3) + err = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Does not match. */ + else + err = gcry_sexp_extract_param (list, NULL, "pgy", + &pub_params[0], + &pub_params[1], + &pub_params[2], + NULL); + break; + + case GCRY_PK_ECC: + err = 0; + if (!(pk->pubkey_algo == PUBKEY_ALGO_ECDSA + || pk->pubkey_algo == PUBKEY_ALGO_ECDH + || pk->pubkey_algo == PUBKEY_ALGO_EDDSA)) + { + err = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Does not match. */ + goto leave; + } + npkey = 2; + if (pk->pubkey_algo == PUBKEY_ALGO_ECDH) + npkey++; + /* Dedicated check of the curve. */ + pub_params[0] = NULL; + err = match_curve_skey_pk (list, pk); + if (err) + goto leave; + /* ... and of the Q parameter. */ + err = sexp_extract_param_sos (list, "q", &pub_params[1]); + if (!err && (gcry_mpi_cmp (pk->pkey[1], pub_params[1]))) + err = gpg_error (GPG_ERR_BAD_PUBKEY); + break; + + default: + err = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Unknown. */ + break; + } + if (err) + goto leave; + + nskey = npkey + 1; /* We only have one skey param. */ + if (nskey > PUBKEY_MAX_NSKEY) + { + err = gpg_error (GPG_ERR_BAD_SECKEY); + goto leave; + } + + /* Check that the public key parameters match. For ECC we already + * did this in the switch above. */ + if (canon_pk_algo (pk_algo) != GCRY_PK_ECC) + { + for (idx=0; idx < npkey; idx++) + if (gcry_mpi_cmp (pk->pkey[idx], pub_params[idx])) + { + err = gpg_error (GPG_ERR_BAD_PUBKEY); + goto leave; + } + } + + /* Store the maybe protected secret key as an s-expression. */ + pk->seckey_info = ski = xtrycalloc (1, sizeof *ski); + if (!ski) + { + err = gpg_error_from_syserror (); + goto leave; + } + + pk->seckey_info = ski = xtrycalloc (1, sizeof *ski); + if (!ski) + { + err = gpg_error_from_syserror (); + goto leave; + } + + ski->is_protected = 1; + ski->s2k.mode = 1003; + + { + unsigned char *buf; + size_t buflen; + + err = make_canon_sexp (s_key, &buf, &buflen); + if (err) + goto leave; + pk->pkey[npkey] = gcry_mpi_set_opaque (NULL, buf, buflen*8); + for (idx=npkey+1; idx < PUBKEY_MAX_NSKEY; idx++) + pk->pkey[idx] = NULL; + } + + leave: + gcry_sexp_release (list); + for (idx=0; idx < DIM(pub_params); idx++) + gcry_mpi_release (pub_params[idx]); + return err; +} + + /* Take a cleartext dump of a secret key in PK and change the * parameter array in PK to include the secret parameters. */ static gpg_error_t @@ -1233,29 +1429,51 @@ print_status_exported (PKT_public_key *pk) * passphrase-protected. Otherwise, store secret key material in the * clear. * + * If MODE1003 is set, the key is requested in raw GnuPG format from + * the agent. This usually does not require a passphrase unless the + * gpg-agent has not yet used the key and needs to convert it to its + * internal format first. + * * CACHE_NONCE_ADDR is used to share nonce for multiple key retrievals. + * + * If PK is NULL, the raw key is returned (e.g. for ssh export) at + * R_KEY. CLEARTEXT and CACHE_NONCE_ADDR ared ignored in this case. */ gpg_error_t receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd, - int cleartext, + int cleartext, int mode1003, char **cache_nonce_addr, const char *hexgrip, - PKT_public_key *pk) + PKT_public_key *pk, gcry_sexp_t *r_key) { gpg_error_t err = 0; unsigned char *wrappedkey = NULL; size_t wrappedkeylen; unsigned char *key = NULL; size_t keylen, realkeylen; - gcry_sexp_t s_skey; + gcry_sexp_t s_skey = NULL; char *prompt; + if (r_key) + *r_key = NULL; if (opt.verbose) log_info ("key %s: asking agent for the secret parts\n", hexgrip); - prompt = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_EXPORT,1); - err = agent_export_key (ctrl, hexgrip, prompt, !cleartext, cache_nonce_addr, - &wrappedkey, &wrappedkeylen, - pk->keyid, pk->main_keyid, pk->pubkey_algo); + if (pk) + { + prompt = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_EXPORT, 1); + err = agent_export_key (ctrl, hexgrip, prompt, !cleartext, mode1003, + cache_nonce_addr, + &wrappedkey, &wrappedkeylen, + pk->keyid, pk->main_keyid, pk->pubkey_algo); + } + else + { + prompt = gpg_format_keydesc (ctrl, NULL, FORMAT_KEYDESC_KEYGRIP, 1); + err = agent_export_key (ctrl, hexgrip, prompt, 0, 0, + NULL, + &wrappedkey, &wrappedkeylen, + NULL, NULL, 0); + } xfree (prompt); if (err) @@ -1282,14 +1500,21 @@ receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd, err = gcry_sexp_sscan (&s_skey, NULL, key, realkeylen); if (!err) { - if (cleartext) + if (pk && mode1003) + err = secret_key_to_mode1003 (s_skey, pk); + else if (pk && cleartext) err = cleartext_secret_key_to_openpgp (s_skey, pk); - else + else if (pk) err = transfer_format_to_openpgp (s_skey, pk); - gcry_sexp_release (s_skey); + else if (r_key) + { + *r_key = s_skey; + s_skey = NULL; + } } unwraperror: + gcry_sexp_release (s_skey); xfree (key); xfree (wrappedkey); if (err) @@ -1795,11 +2020,22 @@ do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, else if (!err) { err = receive_seckey_from_agent (ctrl, cipherhd, - cleartext, &cache_nonce, - hexgrip, pk); + cleartext, + !!(options & EXPORT_MODE1003), + &cache_nonce, + hexgrip, pk, NULL); if (err) { - if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED) + /* If we receive a fully canceled error we stop + * immediately. If we receive a cancel for a public + * key we also stop immediately because a + * public/secret key is always required first + * (right, we could instead write a stub key but + * that is also kind of surprising). If we receive + * a subkey we skip to the next subkey. */ + if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED + || (node->pkt->pkttype == PKT_PUBLIC_KEY + && gpg_err_code (err) == GPG_ERR_CANCELED)) goto leave; write_status_error ("export_keys.secret", err); skip_until_subkey = 1; @@ -1872,6 +2108,78 @@ do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, } +/* Helper for do_export_stream which writes the own revocations + * certificates (if any) from KEYBLOCK to OUT. */ +static gpg_error_t +do_export_revocs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, + iobuf_t out, unsigned int options, int *any) +{ + gpg_error_t err = 0; + kbnode_t kbctx, node; + PKT_signature *sig; + + (void)ctrl; + + /* NB: walk_kbnode skips packets marked as deleted. */ + for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); ) + { + if (node->pkt->pkttype != PKT_SIGNATURE) + continue; + sig = node->pkt->pkt.signature; + + /* We are only interested in revocation certifcates. */ + if (!(IS_KEY_REV (sig) || IS_UID_REV (sig) || IS_SUBKEY_REV (sig))) + continue; + + if (!(sig->keyid[0] == keyid[0] && sig->keyid[1] == keyid[1])) + continue; /* Not a self-signature. */ + + /* Do not export signature packets which are marked as not + * exportable. */ + if (!(options & EXPORT_LOCAL_SIGS) + && !sig->flags.exportable) + continue; /* not exportable */ + + /* Do not export packets with a "sensitive" revocation key + * unless the user wants us to. */ + if (!(options & EXPORT_SENSITIVE_REVKEYS) + && sig->revkey) + { + int i; + + for (i = 0; i < sig->numrevkeys; i++) + if ((sig->revkey[i].class & 0x40)) + break; + if (i < sig->numrevkeys) + continue; + } + + if (!sig->flags.checked) + { + log_info ("signature not marked as checked - ignored\n"); + continue; + } + if (!sig->flags.valid) + { + log_info ("signature not not valid - ignored\n"); + continue; + } + + err = build_packet (out, node->pkt); + if (err) + { + log_error ("build_packet(%d) failed: %s\n", + node->pkt->pkttype, gpg_strerror (err)); + goto leave; + } + *any = 1; + } + + leave: + return err; +} + + /* For secret key export we need to setup a decryption context. * Returns 0 and the context at r_cipherhd. */ static gpg_error_t @@ -2066,13 +2374,33 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, NULL, NULL); commit_kbnode (&keyblock); } - else if (export_keep_uid || export_drop_subkey) + else if (export_keep_uid || export_drop_subkey || export_select_filter) { /* Need to merge so that for example the "usage" property * has been setup. */ merge_keys_and_selfsig (ctrl, keyblock); } + + if (export_select_filter) + { + int selected = 0; + struct impex_filter_parm_s parm; + parm.ctrl = ctrl; + + for (parm.node = keyblock; parm.node; parm.node = parm.node->next) + { + if (recsel_select (export_select_filter, + impex_filter_getval, &parm)) + { + selected = 1; + break; + } + } + if (!selected) + continue; /* Skip this keyblock. */ + } + if (export_keep_uid) { commit_kbnode (&keyblock); @@ -2088,10 +2416,15 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, } /* And write it. */ - err = do_export_one_keyblock (ctrl, keyblock, keyid, - out_help? out_help : out, - secret, options, stats, any, - desc, ndesc, descindex, cipherhd); + if ((options & EXPORT_REVOCS)) + err = do_export_revocs (ctrl, keyblock, keyid, + out_help? out_help : out, + options, any); + else + err = do_export_one_keyblock (ctrl, keyblock, keyid, + out_help? out_help : out, + secret, options, stats, any, + desc, ndesc, descindex, cipherhd); if (err) break; @@ -2131,8 +2464,8 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, keydb_release (kdbhd); if (err || !keyblock_out) release_kbnode( keyblock ); - if( !*any ) - log_info(_("WARNING: nothing exported\n")); + if( !*any && !opt.quiet) + log_info (_("WARNING: nothing exported\n")); return err; } @@ -2602,74 +2935,6 @@ export_ssh_key (ctrl_t ctrl, const char *userid) } -/* Simplified version of receive_seckey_from_agent used to get the raw - * key. */ -gpg_error_t -receive_raw_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd, - const char *hexgrip, gcry_sexp_t *r_key) -{ - gpg_error_t err = 0; - unsigned char *wrappedkey = NULL; - size_t wrappedkeylen; - unsigned char *key = NULL; - size_t keylen, realkeylen; - gcry_sexp_t s_skey = NULL; - - *r_key = NULL; - if (opt.verbose) - log_info ("key %s: asking agent for the secret parts\n", hexgrip); - - { - char * prompt = gpg_format_keydesc (ctrl, NULL, FORMAT_KEYDESC_KEYGRIP, 1); - err = agent_export_key (ctrl, hexgrip, prompt, 0, NULL, - &wrappedkey, &wrappedkeylen, - NULL, NULL, 0); - xfree (prompt); - } - if (err) - goto leave; - - if (wrappedkeylen < 24) - { - err = gpg_error (GPG_ERR_INV_LENGTH); - goto leave; - } - keylen = wrappedkeylen - 8; - key = xtrymalloc_secure (keylen); - if (!key) - { - err = gpg_error_from_syserror (); - goto leave; - } - err = gcry_cipher_decrypt (cipherhd, key, keylen, wrappedkey, wrappedkeylen); - if (err) - goto leave; - realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err); - if (!realkeylen) - goto leave; /* Invalid csexp. */ - - err = gcry_sexp_sscan (&s_skey, NULL, key, realkeylen); - if (!err) - { - gcry_log_debugsxp ("skey", s_skey); - *r_key = s_skey; - s_skey = NULL; - } - - leave: - gcry_sexp_release (s_skey); - xfree (key); - xfree (wrappedkey); - if (err) - { - log_error ("key %s: error receiving key from agent:" - " %s%s\n", hexgrip, gpg_strerror (err), - ""); - } - return err; -} - - /* Export the key identified by USERID in the SSH secret key format. * The USERID must be given in keygrip format (prefixed with a '&') * and thus no OpenPGP key is required. The exported key is not @@ -2715,7 +2980,8 @@ export_secret_ssh_key (ctrl_t ctrl, const char *userid) if ((err = get_keywrap_key (ctrl, &cipherhd))) goto leave; - err = receive_raw_seckey_from_agent (ctrl, cipherhd, hexgrip, &skey); + err = receive_seckey_from_agent (ctrl, cipherhd, 0, 0, NULL, hexgrip, NULL, + &skey); if (err) goto leave; @@ -1,7 +1,7 @@ /* gpg.c - The GnuPG OpenPGP tool * Copyright (C) 1998-2020 Free Software Foundation, Inc. * Copyright (C) 1997-2019 Werner Koch - * Copyright (C) 2015-2021 g10 Code GmbH + * Copyright (C) 2015-2022 g10 Code GmbH * * This file is part of GnuPG. * @@ -133,6 +133,7 @@ enum cmd_and_opt_values aQuickRevUid, aQuickSetExpire, aQuickSetPrimaryUid, + aQuickUpdatePref, aListConfig, aListGcryptConfig, aGPGConfList, @@ -245,7 +246,6 @@ enum cmd_and_opt_values oGnuPG, oRFC2440, oRFC4880, - oRFC4880bis, oOpenPGP, oPGP7, oPGP8, @@ -254,7 +254,6 @@ enum cmd_and_opt_values oRFC2440Text, oNoRFC2440Text, oCipherAlgo, - oAEADAlgo, oDigestAlgo, oCertDigestAlgo, oCompressAlgo, @@ -328,6 +327,7 @@ enum cmd_and_opt_values oExportOptions, oExportFilter, oListOptions, + oListFilter, oVerifyOptions, oTempDir, oExecPath, @@ -383,7 +383,6 @@ enum cmd_and_opt_values oDefaultPreferenceList, oDefaultKeyserverURL, oPersonalCipherPreferences, - oPersonalAEADPreferences, oPersonalDigestPreferences, oPersonalCompressPreferences, oAgentProgram, @@ -444,6 +443,7 @@ enum cmd_and_opt_values oForceSignKey, oForbidGenKey, oRequireCompliance, + oCompatibilityFlags, oNoop }; @@ -491,6 +491,7 @@ static gpgrt_opt_t opts[] = { ARGPARSE_c (aQuickSetExpire, "quick-set-expire", N_("quickly set a new expiration date")), ARGPARSE_c (aQuickSetPrimaryUid, "quick-set-primary-uid", "@"), + ARGPARSE_c (aQuickUpdatePref, "quick-update-pref", "@"), ARGPARSE_c (aFullKeygen, "full-generate-key" , N_("full featured key pair generation")), ARGPARSE_c (aFullKeygen, "full-gen-key", "@"), @@ -629,7 +630,6 @@ static gpgrt_opt_t opts[] = { ARGPARSE_s_n (oGnuPG, "no-pgp8", "@"), ARGPARSE_s_n (oRFC2440, "rfc2440", "@"), ARGPARSE_s_n (oRFC4880, "rfc4880", "@"), - ARGPARSE_s_n (oRFC4880bis, "rfc4880bis", "@"), ARGPARSE_s_n (oOpenPGP, "openpgp", N_("use strict OpenPGP behavior")), ARGPARSE_s_n (oPGP7, "pgp6", "@"), ARGPARSE_s_n (oPGP7, "pgp7", "@"), @@ -674,7 +674,6 @@ static gpgrt_opt_t opts[] = { ARGPARSE_s_n (oEnableDSA2, "enable-dsa2", "@"), ARGPARSE_s_n (oDisableDSA2, "disable-dsa2", "@"), ARGPARSE_s_s (oPersonalCipherPreferences, "personal-cipher-preferences","@"), - ARGPARSE_s_s (oPersonalAEADPreferences, "personal-aead-preferences","@"), ARGPARSE_s_s (oPersonalDigestPreferences, "personal-digest-preferences","@"), ARGPARSE_s_s (oPersonalCompressPreferences, "personal-compress-preferences", "@"), @@ -796,6 +795,7 @@ static gpgrt_opt_t opts[] = { ARGPARSE_header ("Keylist", N_("Options controlling key listings")), ARGPARSE_s_s (oListOptions, "list-options", "@"), + ARGPARSE_s_s (oListFilter, "list-filter", "@"), ARGPARSE_s_n (oFullTimestrings, "full-timestrings", "@"), ARGPARSE_s_n (oShowPhotos, "show-photos", "@"), ARGPARSE_s_n (oNoShowPhotos, "no-show-photos", "@"), @@ -854,7 +854,8 @@ static gpgrt_opt_t opts[] = { ARGPARSE_s_s (oS2KDigest, "s2k-digest-algo", "@"), ARGPARSE_s_s (oS2KCipher, "s2k-cipher-algo", "@"), ARGPARSE_s_i (oS2KCount, "s2k-count", "@"), - ARGPARSE_s_n (oForceAEAD, "force-aead", "@"), + ARGPARSE_s_n (oForceAEAD, "force-ocb", "@"), + ARGPARSE_s_n (oForceAEAD, "force-aead", "@"), /*(old name)*/ ARGPARSE_s_n (oRequireCrossCert, "require-backsigs", "@"), ARGPARSE_s_n (oRequireCrossCert, "require-cross-certification", "@"), ARGPARSE_s_n (oNoRequireCrossCert, "no-require-backsigs", "@"), @@ -875,7 +876,6 @@ static gpgrt_opt_t opts[] = { ARGPARSE_s_s (oDisableCipherAlgo, "disable-cipher-algo", "@"), ARGPARSE_s_s (oDisablePubkeyAlgo, "disable-pubkey-algo", "@"), ARGPARSE_s_s (oCipherAlgo, "cipher-algo", "@"), - ARGPARSE_s_s (oAEADAlgo, "aead-algo", "@"), ARGPARSE_s_s (oDigestAlgo, "digest-algo", "@"), ARGPARSE_s_s (oCertDigestAlgo, "cert-digest-algo", "@"), ARGPARSE_s_n (oOverrideComplianceCheck, "override-compliance-check", "@"), @@ -914,6 +914,7 @@ static gpgrt_opt_t opts[] = { ARGPARSE_s_n (oUseKeyboxd, "use-keyboxd", "@"), ARGPARSE_s_n (oForbidGenKey, "forbid-gen-key", "@"), ARGPARSE_s_n (oRequireCompliance, "require-compliance", "@"), + ARGPARSE_s_s (oCompatibilityFlags, "compatibility-flags", "@"), /* Options which can be used in special circumstances. They are not * published and we hope they are never required. */ ARGPARSE_s_n (oUseOnlyOpenPGPCard, "use-only-openpgp-card", "@"), @@ -926,8 +927,6 @@ static gpgrt_opt_t opts[] = { /* Aliases. I constantly mistype these, and assume other people do as well. */ ARGPARSE_s_s (oPersonalCipherPreferences, "personal-cipher-prefs", "@"), - ARGPARSE_s_s (oPersonalAEADPreferences, "personal-aead-prefs", "@"), - ARGPARSE_s_s (oPersonalDigestPreferences, "personal-digest-prefs", "@"), ARGPARSE_s_s (oPersonalCompressPreferences, "personal-compress-prefs", "@"), /* These two are aliases to help users of the PGP command line @@ -970,6 +969,9 @@ static gpgrt_opt_t opts[] = { ARGPARSE_s_n (oNoop, "allow-multisig-verification", "@"), ARGPARSE_s_n (oNoop, "allow-multiple-messages", "@"), ARGPARSE_s_n (oNoop, "no-allow-multiple-messages", "@"), + ARGPARSE_s_s (oNoop, "aead-algo", "@"), + ARGPARSE_s_s (oNoop, "personal-aead-preferences","@"), + ARGPARSE_s_n (oNoop, "rfc4880bis", "@"), ARGPARSE_group (302, N_( @@ -1009,6 +1011,13 @@ static struct debug_flags_s debug_flags [] = }; +/* The list of compatibility flags. */ +static struct compatibility_flags_s compatibility_flags [] = + { + { 0, NULL } + }; + + #ifdef ENABLE_SELINUX_HACKS #define ALWAYS_ADD_KEYRINGS 1 #else @@ -1104,18 +1113,6 @@ build_list_cipher_algo_name (int algo) } static int -build_list_aead_test_algo (int algo) -{ - return openpgp_aead_test_algo (algo); -} - -static const char * -build_list_aead_algo_name (int algo) -{ - return openpgp_aead_algo_name (algo); -} - -static int build_list_md_test_algo (int algo) { /* By default we do not accept MD5 based signatures. To avoid @@ -1136,7 +1133,7 @@ build_list_md_algo_name (int algo) static const char * my_strusage( int level ) { - static char *digests, *pubkeys, *ciphers, *zips, *aeads, *ver_gcry; + static char *digests, *pubkeys, *ciphers, *zips, *ver_gcry; const char *p; switch( level ) { @@ -1198,13 +1195,6 @@ my_strusage( int level ) build_list_cipher_test_algo ); p = ciphers; break; - case 36: - if (!aeads) - aeads = build_list ("AEAD: ", 'A', - build_list_aead_algo_name, - build_list_aead_test_algo); - p = aeads; - break; case 37: if( !digests ) digests = build_list(_("Hash: "), 'H', @@ -2084,6 +2074,10 @@ parse_list_options(char *str) N_("show the keyring name in key listings")}, {"show-sig-expire",LIST_SHOW_SIG_EXPIRE,NULL, N_("show expiration dates during signature listings")}, + {"show-pref", LIST_SHOW_PREF, NULL, + N_("show preferences")}, + {"show-pref-verbose", LIST_SHOW_PREF_VERBOSE, NULL, + N_("show preferences")}, {"show-sig-subpackets",LIST_SHOW_SIG_SUBPACKETS,NULL, NULL}, {"show-only-fpr-mbox",LIST_SHOW_ONLY_FPR_MBOX, NULL, @@ -2211,7 +2205,7 @@ static struct gnupg_compliance_option compliance_options[] = { { "gnupg", oGnuPG }, { "openpgp", oOpenPGP }, - { "rfc4880bis", oRFC4880bis }, + { "rfc4880bis", oGnuPG }, { "rfc4880", oRFC4880 }, { "rfc2440", oRFC2440 }, { "pgp6", oPGP7 }, @@ -2227,29 +2221,8 @@ static struct gnupg_compliance_option compliance_options[] = static void set_compliance_option (enum cmd_and_opt_values option) { - opt.flags.rfc4880bis = 0; /* Clear because it is initially set. */ - switch (option) { - case oRFC4880bis: - opt.flags.rfc4880bis = 1; - opt.compliance = CO_RFC4880; - opt.flags.dsa2 = 1; - opt.flags.require_cross_cert = 1; - opt.rfc2440_text = 0; - opt.allow_non_selfsigned_uid = 1; - opt.allow_freeform_uid = 1; - opt.escape_from = 1; - opt.not_dash_escaped = 0; - opt.def_cipher_algo = 0; - opt.def_aead_algo = 0; - opt.def_digest_algo = 0; - opt.cert_digest_algo = 0; - opt.compress_algo = -1; - opt.s2k_mode = 3; /* iterated+salted */ - opt.s2k_digest_algo = DIGEST_ALGO_SHA256; - opt.s2k_cipher_algo = CIPHER_ALGO_AES256; - break; case oOpenPGP: case oRFC4880: /* This is effectively the same as RFC2440, but with @@ -2264,7 +2237,6 @@ set_compliance_option (enum cmd_and_opt_values option) opt.escape_from = 1; opt.not_dash_escaped = 0; opt.def_cipher_algo = 0; - opt.def_aead_algo = 0; opt.def_digest_algo = 0; opt.cert_digest_algo = 0; opt.compress_algo = -1; @@ -2282,7 +2254,6 @@ set_compliance_option (enum cmd_and_opt_values option) opt.escape_from = 0; opt.not_dash_escaped = 0; opt.def_cipher_algo = 0; - opt.def_aead_algo = 0; opt.def_digest_algo = 0; opt.cert_digest_algo = 0; opt.compress_algo = -1; @@ -2295,13 +2266,11 @@ set_compliance_option (enum cmd_and_opt_values option) case oPGP8: opt.compliance = CO_PGP8; break; case oGnuPG: opt.compliance = CO_GNUPG; - opt.flags.rfc4880bis = 1; break; case oDE_VS: set_compliance_option (oOpenPGP); opt.compliance = CO_DE_VS; - opt.def_aead_algo = 0; /* We divert here from the backward compatible rfc4880 algos. */ opt.s2k_digest_algo = DIGEST_ALGO_SHA256; opt.s2k_cipher_algo = CIPHER_ALGO_AES256; @@ -2382,14 +2351,12 @@ main (int argc, char **argv) const char *trustdb_name = NULL; #endif /*!NO_TRUST_MODELS*/ char *def_cipher_string = NULL; - char *def_aead_string = NULL; char *def_digest_string = NULL; char *compress_algo_string = NULL; char *cert_digest_string = NULL; char *s2k_cipher_string = NULL; char *s2k_digest_string = NULL; char *pers_cipher_list = NULL; - char *pers_aead_list = NULL; char *pers_digest_list = NULL; char *pers_compress_list = NULL; int eyes_only=0; @@ -2455,7 +2422,6 @@ main (int argc, char **argv) opt.bz2_compress_level = -1; /* defaults to standard compress level */ /* note: if you change these lines, look at oOpenPGP */ opt.def_cipher_algo = 0; - opt.def_aead_algo = 0; opt.def_digest_algo = 0; opt.cert_digest_algo = 0; opt.compress_algo = -1; /* defaults to DEFAULT_COMPRESS_ALGO */ @@ -2502,7 +2468,6 @@ main (int argc, char **argv) opt.emit_version = 0; opt.weak_digests = NULL; opt.compliance = CO_GNUPG; - opt.flags.rfc4880bis = 1; /* Check special options given on the command line. */ orig_argc = argc; @@ -2716,6 +2681,7 @@ main (int argc, char **argv) case aQuickRevUid: case aQuickSetExpire: case aQuickSetPrimaryUid: + case aQuickUpdatePref: case aExportOwnerTrust: case aImportOwnerTrust: case aRebuildKeydbCaches: @@ -2861,6 +2827,15 @@ main (int argc, char **argv) allow_large_chunks = 1; 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_ERROR; + } + break; + case oStatusFD: set_status_fd ( translate_sys2libc_fd_int (pargs.r.ret_int, 1) ); break; @@ -3031,7 +3006,6 @@ main (int argc, char **argv) case oOpenPGP: case oRFC2440: case oRFC4880: - case oRFC4880bis: case oPGP7: case oPGP8: case oGnuPG: @@ -3269,9 +3243,6 @@ main (int argc, char **argv) case oCipherAlgo: def_cipher_string = xstrdup(pargs.r.ret_str); break; - case oAEADAlgo: - def_aead_string = xstrdup (pargs.r.ret_str); - break; case oDigestAlgo: def_digest_string = xstrdup(pargs.r.ret_str); break; @@ -3388,6 +3359,11 @@ main (int argc, char **argv) if (rc) log_error (_("invalid filter option: %s\n"), gpg_strerror (rc)); break; + case oListFilter: + rc = parse_and_set_list_filter (pargs.r.ret_str); + if (rc) + log_error (_("invalid filter option: %s\n"), gpg_strerror (rc)); + break; case oListOptions: if(!parse_list_options(pargs.r.ret_str)) { @@ -3553,9 +3529,6 @@ main (int argc, char **argv) case oPersonalCipherPreferences: pers_cipher_list=pargs.r.ret_str; break; - case oPersonalAEADPreferences: - pers_aead_list = pargs.r.ret_str; - break; case oPersonalDigestPreferences: pers_digest_list=pargs.r.ret_str; break; @@ -3849,11 +3822,6 @@ main (int argc, char **argv) if( may_coredump && !opt.quiet ) log_info(_("WARNING: program may create a core file!\n")); - if (!opt.flags.rfc4880bis) - { - opt.mimemode = 0; /* This will use text mode instead. */ - } - if (eyes_only) { if (opt.set_filename) log_info(_("WARNING: %s overrides %s\n"), @@ -3920,6 +3888,8 @@ main (int argc, char **argv) } set_debug (debug_level); + if (opt.verbose) /* Print the compatibility flags. */ + parse_compatibility_flags (NULL, &opt.compat_flags, compatibility_flags); gnupg_set_compliance_extra_info (opt.min_rsa_length); if (DBG_CLOCK) log_clock ("start"); @@ -3944,13 +3914,6 @@ main (int argc, char **argv) if ( openpgp_cipher_test_algo (opt.def_cipher_algo) ) log_error(_("selected cipher algorithm is invalid\n")); } - if (def_aead_string) - { - opt.def_aead_algo = string_to_aead_algo (def_aead_string); - xfree (def_aead_string); def_aead_string = NULL; - if (openpgp_aead_test_algo (opt.def_aead_algo)) - log_error(_("selected AEAD algorithm is invalid\n")); - } if( def_digest_string ) { opt.def_digest_algo = string_to_digest_algo (def_digest_string); xfree(def_digest_string); def_digest_string = NULL; @@ -4011,9 +3974,6 @@ main (int argc, char **argv) keygen_set_std_prefs(pers_cipher_list,PREFTYPE_SYM)) log_error(_("invalid personal cipher preferences\n")); - if (pers_aead_list && keygen_set_std_prefs (pers_aead_list, PREFTYPE_AEAD)) - log_error(_("invalid personal AEAD preferences\n")); - if(pers_digest_list && keygen_set_std_prefs(pers_digest_list,PREFTYPE_HASH)) log_error(_("invalid personal digest preferences\n")); @@ -4087,7 +4047,7 @@ main (int argc, char **argv) /* Check our chosen algorithms against the list of legal algorithms. */ - if(!GNUPG && !opt.flags.rfc4880bis) + if(!GNUPG) { const char *badalg=NULL; preftype_t badtype=PREFTYPE_NONE; @@ -4098,12 +4058,6 @@ main (int argc, char **argv) badalg = openpgp_cipher_algo_name (opt.def_cipher_algo); badtype = PREFTYPE_SYM; } - else if(opt.def_aead_algo - && !algo_available(PREFTYPE_AEAD, opt.def_aead_algo, NULL)) - { - badalg = openpgp_aead_algo_name (opt.def_aead_algo); - badtype = PREFTYPE_AEAD; - } else if(opt.def_digest_algo && !algo_available(PREFTYPE_HASH,opt.def_digest_algo,NULL)) { @@ -4133,12 +4087,6 @@ main (int argc, char **argv) badalg, gnupg_compliance_option_string (opt.compliance)); break; - case PREFTYPE_AEAD: - log_info (_("AEAD algorithm '%s'" - " may not be used in %s mode\n"), - badalg, - gnupg_compliance_option_string (opt.compliance)); - break; case PREFTYPE_HASH: log_info (_("digest algorithm '%s'" " may not be used in %s mode\n"), @@ -4164,7 +4112,6 @@ main (int argc, char **argv) * is not. This is us being nice to the user informing her early * that the chosen algorithms are not available. We also check * and enforce this right before the actual operation. */ - /* FIXME: We also need to check the AEAD algo. */ if (opt.def_cipher_algo && ! gnupg_cipher_is_allowed (opt.compliance, cmd == aEncr @@ -4343,6 +4290,7 @@ main (int argc, char **argv) case aQuickAddKey: case aQuickRevUid: case aQuickSetPrimaryUid: + case aQuickUpdatePref: case aFullKeygen: case aKeygen: case aImport: @@ -4843,6 +4791,14 @@ main (int argc, char **argv) } break; + case aQuickUpdatePref: + { + if (argc != 1) + wrong_args ("--quick-update-pref USER-ID"); + keyedit_quick_update_pref (ctrl, *argv); + } + break; + case aFastImport: opt.import_options |= IMPORT_FAST; /* fall through */ case aImport: @@ -812,3 +812,11 @@ get_revocation_reason (PKT_signature *sig, char **r_reason, *r_comment = NULL; return 0; } + +const char * +impex_filter_getval (void *cookie, const char *propname) +{ + (void)cookie; + (void)propname; + return NULL; +} diff --git a/g10/import.c b/g10/import.c index bb0bf67..9fab46c 100644 --- a/g10/import.c +++ b/g10/import.c @@ -126,7 +126,8 @@ static int import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options, static int chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, int *non_self); static int delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock, - u32 *keyid, unsigned int options); + u32 *keyid, unsigned int options, + kbnode_t *r_otherrevsigs); static int any_uid_left (kbnode_t keyblock); static void remove_all_non_self_sigs (kbnode_t *keyblock, u32 *keyid); static int merge_blocks (ctrl_t ctrl, unsigned int options, @@ -438,7 +439,7 @@ read_key_from_file_or_buffer (ctrl_t ctrl, const char *fname, goto leave; } - if (!delete_inv_parts (ctrl, keyblock, keyid, 0) ) + if (!delete_inv_parts (ctrl, keyblock, keyid, 0, NULL) ) { err = gpg_error (GPG_ERR_NO_USER_ID); goto leave; @@ -1429,7 +1430,8 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock) } -/* Helper for apply_*_filter in import.c and export.c. */ +/* Helper for apply_*_filter in import.c and export.c and also used by + * keylist.c. */ const char * impex_filter_getval (void *cookie, const char *propname) { @@ -1439,11 +1441,32 @@ impex_filter_getval (void *cookie, const char *propname) kbnode_t node = parm->node; static char numbuf[20]; const char *result; + const char *s; + enum { scpNone = 0, scpPub, scpSub, scpUid, scpSig} scope = 0; log_assert (ctrl && ctrl->magic == SERVER_CONTROL_MAGIC); - if (node->pkt->pkttype == PKT_USER_ID - || node->pkt->pkttype == PKT_ATTRIBUTE) + /* We allow a prefix delimited by a slash to limit the scope of the + * keyword. Note that "pub" also includes "sec" and "sub" includes + * "ssb". */ + if ((s=strchr (propname, '/')) && s != propname) + { + size_t n = s - propname; + if (!strncmp (propname, "pub", n)) + scope = scpPub; + else if (!strncmp (propname, "sub", n)) + scope = scpSub; + else if (!strncmp (propname, "uid", n)) + scope = scpUid; + else if (!strncmp (propname, "sig", n)) + scope = scpSig; + + propname = s + 1; + } + + if ((node->pkt->pkttype == PKT_USER_ID + || node->pkt->pkttype == PKT_ATTRIBUTE) + && (!scope || scope == scpUid)) { PKT_user_id *uid = node->pkt->pkt.user_id; @@ -1472,7 +1495,8 @@ impex_filter_getval (void *cookie, const char *propname) else result = NULL; } - else if (node->pkt->pkttype == PKT_SIGNATURE) + else if (node->pkt->pkttype == PKT_SIGNATURE + && (!scope || scope == scpSig)) { PKT_signature *sig = node->pkt->pkt.signature; @@ -1502,10 +1526,12 @@ impex_filter_getval (void *cookie, const char *propname) else result = NULL; } - else if (node->pkt->pkttype == PKT_PUBLIC_KEY - || node->pkt->pkttype == PKT_SECRET_KEY - || node->pkt->pkttype == PKT_PUBLIC_SUBKEY - || node->pkt->pkttype == PKT_SECRET_SUBKEY) + else if (((node->pkt->pkttype == PKT_PUBLIC_KEY + || node->pkt->pkttype == PKT_SECRET_KEY) + && (!scope || scope == scpPub)) + || ((node->pkt->pkttype == PKT_PUBLIC_SUBKEY + || node->pkt->pkttype == PKT_SECRET_SUBKEY) + && (!scope || scope == scpSub))) { PKT_public_key *pk = node->pkt->pkt.public_key; @@ -1519,6 +1545,16 @@ impex_filter_getval (void *cookie, const char *propname) snprintf (numbuf, sizeof numbuf, "%d", pk->pubkey_algo); result = numbuf; } + else if (!strcmp (propname, "key_size")) + { + snprintf (numbuf, sizeof numbuf, "%u", nbits_from_pk (pk)); + result = numbuf; + } + else if (!strcmp (propname, "algostr")) + { + pubkey_string (pk, parm->hexfpr, sizeof parm->hexfpr); + result = parm->hexfpr; + } else if (!strcmp (propname, "key_created")) { snprintf (numbuf, sizeof numbuf, "%lu", (ulong)pk->timestamp); @@ -1555,6 +1591,26 @@ impex_filter_getval (void *cookie, const char *propname) hexfingerprint (pk, parm->hexfpr, sizeof parm->hexfpr); result = parm->hexfpr; } + else if (!strcmp (propname, "origin")) + { + result = key_origin_string (pk->keyorg); + } + else if (!strcmp (propname, "lastupd")) + { + snprintf (numbuf, sizeof numbuf, "%lu", (ulong)pk->keyupdate); + result = numbuf; + } + else if (!strcmp (propname, "url")) + { + if (pk->updateurl && *pk->updateurl) + { + /* Fixme: This might get truncated. */ + mem2str (parm->hexfpr, pk->updateurl, sizeof parm->hexfpr); + result = parm->hexfpr; + } + else + result = ""; + } else result = NULL; } @@ -1871,8 +1927,9 @@ update_key_origin (kbnode_t keyblock, u32 curtime, int origin, const char *url) * even most error messages are suppressed. ORIGIN is the origin of * the key (0 for unknown) and URL the corresponding URL. FROM_SK * indicates that the key has been made from a secret key. If R_SAVED - * is not NULL a boolean will be stored indicating whether the keyblock - * has valid parts. + * is not NULL a boolean will be stored indicating whether the + * keyblock has valid parts. Unless OTHERREVSIGS is NULL it is + * updated with encountered new revocation signatures. */ static gpg_error_t import_one_real (ctrl_t ctrl, @@ -1880,7 +1937,8 @@ import_one_real (ctrl_t ctrl, unsigned char **fpr, size_t *fpr_len, unsigned int options, int from_sk, int silent, import_screener_t screener, void *screener_arg, - int origin, const char *url, int *r_valid) + int origin, const char *url, int *r_valid, + kbnode_t *otherrevsigs) { gpg_error_t err = 0; PKT_public_key *pk; @@ -2021,7 +2079,7 @@ import_one_real (ctrl_t ctrl, } /* Delete invalid parts and bail out if there are no user ids left. */ - if (!delete_inv_parts (ctrl, keyblock, keyid, options)) + if (!delete_inv_parts (ctrl, keyblock, keyid, options, otherrevsigs)) { if (!silent) { @@ -2413,10 +2471,12 @@ import_one (ctrl_t ctrl, int origin, const char *url, int *r_valid) { gpg_error_t err; + kbnode_t otherrevsigs = NULL; + kbnode_t node; err = import_one_real (ctrl, keyblock, stats, fpr, fpr_len, options, from_sk, silent, screener, screener_arg, - origin, url, r_valid); + origin, url, r_valid, &otherrevsigs); if (gpg_err_code (err) == GPG_ERR_TOO_LARGE && gpg_err_source (err) == GPG_ERR_SOURCE_KEYBOX && ((options & (IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN)) @@ -2432,8 +2492,17 @@ import_one (ctrl_t ctrl, options |= IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN; err = import_one_real (ctrl, keyblock, stats, fpr, fpr_len, options, from_sk, silent, screener, screener_arg, - origin, url, r_valid); + origin, url, r_valid, &otherrevsigs); + } + + /* Finally try to import other revocation certificates. For example + * those of a former key appended to the current key. */ + if (!err) + { + for (node = otherrevsigs; node; node = node->next) + import_revoke_cert (ctrl, node, options, stats); } + release_kbnode (otherrevsigs); return err; } @@ -3422,9 +3491,8 @@ list_standalone_revocation (ctrl_t ctrl, PKT_signature *sig, int sigrc) } -/**************** - * Import a revocation certificate; this is a single signature packet. - */ +/* Import a revocation certificate; only the first packet in the + * NODE-list is considered. */ static int import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options, struct import_stats_s *stats) @@ -3441,10 +3509,12 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options, /* No error output for --show-keys. */ silent = (options & (IMPORT_SHOW | IMPORT_DRY_RUN)); - log_assert (!node->next ); log_assert (node->pkt->pkttype == PKT_SIGNATURE ); log_assert (IS_KEY_REV (node->pkt->pkt.signature)); + /* FIXME: We can do better here by using the issuer fingerprint if + * available. We should also make use of get_keyblock_byfprint_fast. */ + keyid[0] = node->pkt->pkt.signature->keyid[0]; keyid[1] = node->pkt->pkt.signature->keyid[1]; @@ -3788,12 +3858,15 @@ chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, int *non_self) /* Delete all parts which are invalid and those signatures whose * public key algorithm is not available in this implementation; but * consider RSA as valid, because parse/build_packets knows about it. + * If R_OTHERREVSIGS is not NULL, it is used to return a list of + * revocation certificates which have been deleted from KEYBLOCK but + * should be handled later. * * Returns: True if at least one valid user-id is left over. */ static int delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, - unsigned int options) + unsigned int options, kbnode_t *r_otherrevsigs) { kbnode_t node; int nvalid=0, uid_seen=0, subkey_seen=0; @@ -3883,6 +3956,16 @@ delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, if(opt.verbose) log_info( _("key %s: revocation certificate" " at wrong place - skipped\n"),keystr(keyid)); + if (r_otherrevsigs) + { + PACKET *pkt; + + pkt = xcalloc (1, sizeof *pkt); + pkt->pkttype = PKT_SIGNATURE; + pkt->pkt.signature = copy_signature + (NULL, node->pkt->pkt.signature); + *r_otherrevsigs = new_kbnode2 (*r_otherrevsigs, pkt); + } delete_kbnode( node ); } else @@ -3905,6 +3988,16 @@ delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, delete_kbnode( node ); } } + else if (r_otherrevsigs) + { + PACKET *pkt; + + pkt = xcalloc (1, sizeof *pkt); + pkt->pkttype = PKT_SIGNATURE; + pkt->pkt.signature = copy_signature + (NULL, node->pkt->pkt.signature); + *r_otherrevsigs = new_kbnode2 (*r_otherrevsigs, pkt); + } } } else if (node->pkt->pkttype == PKT_SIGNATURE diff --git a/g10/kbnode.c b/g10/kbnode.c index 93035e8..1f2328d 100644 --- a/g10/kbnode.c +++ b/g10/kbnode.c @@ -98,6 +98,19 @@ new_kbnode( PACKET *pkt ) } +/* Same as new_kbnode but insert the new node in front of LIST. Returns + * the new list. */ +kbnode_t +new_kbnode2 (kbnode_t list, PACKET *pkt) +{ + kbnode_t n; + + n = new_kbnode (pkt); + n->next = list; + return n; +} + + KBNODE clone_kbnode( KBNODE node ) { diff --git a/g10/keydb.h b/g10/keydb.h index a91309a..771bc8e 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -569,6 +569,7 @@ gpg_error_t hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip); /*-- kbnode.c --*/ KBNODE new_kbnode( PACKET *pkt ); +kbnode_t new_kbnode2 (kbnode_t list, PACKET *pkt); KBNODE clone_kbnode( KBNODE node ); void release_kbnode( KBNODE n ); void delete_kbnode( KBNODE node ); diff --git a/g10/keyedit.c b/g10/keyedit.c index 0453801..83c20b8 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -1,7 +1,7 @@ /* keyedit.c - Edit properties of a key * Copyright (C) 1998-2010 Free Software Foundation, Inc. * Copyright (C) 1998-2017 Werner Koch - * Copyright (C) 2015, 2016 g10 Code GmbH + * Copyright (C) 2015, 2016, 2022 g10 Code GmbH * * This file is part of GnuPG. * @@ -78,7 +78,8 @@ static gpg_error_t menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock, static int menu_changeusage (ctrl_t ctrl, kbnode_t keyblock); static int menu_backsign (ctrl_t ctrl, kbnode_t pub_keyblock); static int menu_set_primary_uid (ctrl_t ctrl, kbnode_t pub_keyblock); -static int menu_set_preferences (ctrl_t ctrl, kbnode_t pub_keyblock); +static int menu_set_preferences (ctrl_t ctrl, kbnode_t pub_keyblock, + int unattended); static int menu_set_keyserver_url (ctrl_t ctrl, const char *url, kbnode_t pub_keyblock); static int menu_set_notation (ctrl_t ctrl, @@ -2157,7 +2158,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, " for the selected user IDs? (y/N) ") : _("Really update the preferences? (y/N) "))) { - if (menu_set_preferences (ctrl, keyblock)) + if (menu_set_preferences (ctrl, keyblock, 0)) { merge_keys_and_selfsig (ctrl, keyblock); modified = 1; @@ -2654,6 +2655,45 @@ keyedit_quick_set_primary (ctrl_t ctrl, const char *username, } +/* Unattended updating of the preference tro the standard preferences. + * USERNAME specifies the key. This is basically the same as + * gpg --edit-key <<userif> updpref save + */ +void +keyedit_quick_update_pref (ctrl_t ctrl, const char *username) +{ + gpg_error_t err; + KEYDB_HANDLE kdbhd = NULL; + kbnode_t keyblock = NULL; + +#ifdef HAVE_W32_SYSTEM + /* See keyedit_menu for why we need this. */ + check_trustdb_stale (ctrl); +#endif + + err = quick_find_keyblock (ctrl, username, 1, &kdbhd, &keyblock); + if (err) + goto leave; + + if (menu_set_preferences (ctrl, keyblock, 1)) + { + merge_keys_and_selfsig (ctrl, keyblock); + err = keydb_update_keyblock (ctrl, kdbhd, keyblock); + if (err) + { + log_error (_("update failed: %s\n"), gpg_strerror (err)); + goto leave; + } + } + + leave: + if (err) + write_status_error ("keyedit.updpref", err); + release_kbnode (keyblock); + keydb_release (kdbhd); +} + + /* Find a keyblock by fingerprint because only this uniquely * identifies a key and may thus be used to select a key for * unattended subkey creation os key signing. */ @@ -3353,145 +3393,12 @@ tty_print_notations (int indent, PKT_signature * sig) static void show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose) { - const prefitem_t fake = { 0, 0 }; - const prefitem_t *prefs; - int i; - if (!uid) return; - if (uid->prefs) - prefs = uid->prefs; - else if (verbose) - prefs = &fake; - else - return; - if (verbose) { - int any, des_seen = 0, sha1_seen = 0, uncomp_seen = 0; - - tty_printf (" "); - tty_printf (_("Cipher: ")); - for (i = any = 0; prefs[i].type; i++) - { - if (prefs[i].type == PREFTYPE_SYM) - { - if (any) - tty_printf (", "); - any = 1; - /* We don't want to display strings for experimental algos */ - if (!openpgp_cipher_test_algo (prefs[i].value) - && prefs[i].value < 100) - tty_printf ("%s", openpgp_cipher_algo_name (prefs[i].value)); - else - tty_printf ("[%d]", prefs[i].value); - if (prefs[i].value == CIPHER_ALGO_3DES) - des_seen = 1; - } - } - if (!des_seen) - { - if (any) - tty_printf (", "); - tty_printf ("%s", openpgp_cipher_algo_name (CIPHER_ALGO_3DES)); - } - tty_printf ("\n "); - tty_printf (_("AEAD: ")); - for (i = any = 0; prefs[i].type; i++) - { - if (prefs[i].type == PREFTYPE_AEAD) - { - if (any) - tty_printf (", "); - any = 1; - /* We don't want to display strings for experimental algos */ - if (!openpgp_aead_test_algo (prefs[i].value) - && prefs[i].value < 100) - tty_printf ("%s", openpgp_aead_algo_name (prefs[i].value)); - else - tty_printf ("[%d]", prefs[i].value); - } - } - tty_printf ("\n "); - tty_printf (_("Digest: ")); - for (i = any = 0; prefs[i].type; i++) - { - if (prefs[i].type == PREFTYPE_HASH) - { - if (any) - tty_printf (", "); - any = 1; - /* We don't want to display strings for experimental algos */ - if (!gcry_md_test_algo (prefs[i].value) && prefs[i].value < 100) - tty_printf ("%s", gcry_md_algo_name (prefs[i].value)); - else - tty_printf ("[%d]", prefs[i].value); - if (prefs[i].value == DIGEST_ALGO_SHA1) - sha1_seen = 1; - } - } - if (!sha1_seen) - { - if (any) - tty_printf (", "); - tty_printf ("%s", gcry_md_algo_name (DIGEST_ALGO_SHA1)); - } - tty_printf ("\n "); - tty_printf (_("Compression: ")); - for (i = any = 0; prefs[i].type; i++) - { - if (prefs[i].type == PREFTYPE_ZIP) - { - const char *s = compress_algo_to_string (prefs[i].value); - - if (any) - tty_printf (", "); - any = 1; - /* We don't want to display strings for experimental algos */ - if (s && prefs[i].value < 100) - tty_printf ("%s", s); - else - tty_printf ("[%d]", prefs[i].value); - if (prefs[i].value == COMPRESS_ALGO_NONE) - uncomp_seen = 1; - } - } - if (!uncomp_seen) - { - if (any) - tty_printf (", "); - else - { - tty_printf ("%s", compress_algo_to_string (COMPRESS_ALGO_ZIP)); - tty_printf (", "); - } - tty_printf ("%s", compress_algo_to_string (COMPRESS_ALGO_NONE)); - } - if (uid->flags.mdc || uid->flags.aead || !uid->flags.ks_modify) - { - tty_printf ("\n "); - tty_printf (_("Features: ")); - any = 0; - if (uid->flags.mdc) - { - tty_printf ("MDC"); - any = 1; - } - if (uid->flags.aead) - { - if (any) - tty_printf (", "); - tty_printf ("AEAD"); - } - if (!uid->flags.ks_modify) - { - if (any) - tty_printf (", "); - tty_printf (_("Keyserver no-modify")); - } - } - tty_printf ("\n"); + show_preferences (uid, 4, -1, 1); if (selfsig) { @@ -3518,22 +3425,7 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose) } else { - tty_printf (" "); - for (i = 0; prefs[i].type; i++) - { - tty_printf (" %c%d", prefs[i].type == PREFTYPE_SYM ? 'S' : - prefs[i].type == PREFTYPE_AEAD ? 'A' : - prefs[i].type == PREFTYPE_HASH ? 'H' : - prefs[i].type == PREFTYPE_ZIP ? 'Z' : '?', - prefs[i].value); - } - if (uid->flags.mdc) - tty_printf (" [mdc]"); - if (uid->flags.aead) - tty_printf (" [aead]"); - if (!uid->flags.ks_modify) - tty_printf (" [no-ks-modify]"); - tty_printf ("\n"); + show_preferences (uid, 4, -1, 0); } } @@ -5260,10 +5152,11 @@ menu_set_primary_uid (ctrl_t ctrl, kbnode_t pub_keyblock) /* - * Set preferences to new values for the selected user IDs + * Set preferences to new values for the selected user IDs. + * --quick-update-pred calls this with UNATTENDED set. */ static int -menu_set_preferences (ctrl_t ctrl, kbnode_t pub_keyblock) +menu_set_preferences (ctrl_t ctrl, kbnode_t pub_keyblock, int unattended) { PKT_public_key *main_pk; PKT_user_id *uid; @@ -5272,9 +5165,10 @@ menu_set_preferences (ctrl_t ctrl, kbnode_t pub_keyblock) int selected, select_all; int modified = 0; - no_primary_warning (pub_keyblock); + if (!unattended) + no_primary_warning (pub_keyblock); - select_all = !count_selected_uids (pub_keyblock); + select_all = unattended? 1 : !count_selected_uids (pub_keyblock); /* Now we can actually change the self signature(s) */ main_pk = NULL; diff --git a/g10/keyedit.h b/g10/keyedit.h index b6e5b58..ea4fd25 100644 --- a/g10/keyedit.h +++ b/g10/keyedit.h @@ -55,6 +55,7 @@ void keyedit_quick_set_expire (ctrl_t ctrl, char **subkeyfprs); void keyedit_quick_set_primary (ctrl_t ctrl, const char *username, const char *primaryuid); +void keyedit_quick_update_pref (ctrl_t ctrl, const char *username); void show_basic_key_info (ctrl_t ctrl, kbnode_t keyblock, int print_sec); int keyedit_print_one_sig (ctrl_t ctrl, estream_t fp, int rc, kbnode_t keyblock, diff --git a/g10/keygen.c b/g10/keygen.c index 7a79b37..4dcf7a4 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -407,7 +407,7 @@ keygen_set_std_prefs (const char *string,int personal) strcat(dummy_string,"S7 "); strcat(dummy_string,"S2 "); /* 3DES */ - if (opt.flags.rfc4880bis && !openpgp_aead_test_algo (AEAD_ALGO_OCB)) + if (!openpgp_aead_test_algo (AEAD_ALGO_OCB)) strcat(dummy_string,"A2 "); if (personal) @@ -564,29 +564,6 @@ keygen_set_std_prefs (const char *string,int personal) opt.personal_cipher_prefs[i].value = 0; } } - else if (personal == PREFTYPE_AEAD) - { - xfree(opt.personal_aead_prefs); - - if (!naead) - opt.personal_aead_prefs = NULL; - else - { - int i; - - opt.personal_aead_prefs= - xmalloc(sizeof(prefitem_t *)*(naead+1)); - - for (i=0; i<naead; i++) - { - opt.personal_aead_prefs[i].type = PREFTYPE_AEAD; - opt.personal_aead_prefs[i].value = aead[i]; - } - - opt.personal_aead_prefs[i].type = PREFTYPE_NONE; - opt.personal_aead_prefs[i].value = 0; - } - } else if(personal==PREFTYPE_HASH) { xfree(opt.personal_digest_prefs); @@ -915,7 +892,7 @@ keygen_upd_std_prefs (PKT_signature *sig, void *opaque) /* Make sure that the MDC feature flag is set if needed. */ add_feature_mdc (sig,mdc_available); add_feature_aead (sig, aead_available); - add_feature_v5 (sig, opt.flags.rfc4880bis); + add_feature_v5 (sig, 1); add_keyserver_modify (sig,ks_modify); keygen_add_keyserver_url(sig,NULL); @@ -3410,10 +3387,7 @@ parse_key_parameter_part (ctrl_t ctrl, } } else if (!ascii_strcasecmp (s, "v5")) - { - if (opt.flags.rfc4880bis) - keyversion = 5; - } + keyversion = 5; else if (!ascii_strcasecmp (s, "v4")) keyversion = 4; else @@ -3672,7 +3646,7 @@ parse_key_parameter_part (ctrl_t ctrl, * ecdsa := Use algorithm ECDSA. * eddsa := Use algorithm EdDSA. * ecdh := Use algorithm ECDH. - * v5 := Create version 5 key (requires option --rfc4880bis) + * v5 := Create version 5 key * * There are several defaults and fallbacks depending on the * algorithm. PART can be used to select which part of STRING is @@ -4454,9 +4428,9 @@ read_parameter_file (ctrl_t ctrl, const char *fname ) } } - if (!opt.flags.rfc4880bis && (keywords[i].key == pVERSION - || keywords[i].key == pSUBVERSION)) - ; /* Ignore version unless --rfc4880bis is active. */ + if ((keywords[i].key == pVERSION + || keywords[i].key == pSUBVERSION)) + ; /* Ignore version. */ else { r = xmalloc_clear( sizeof *r + strlen( value ) ); @@ -4551,14 +4525,11 @@ quickgen_set_para (struct para_data_s *para, int for_subkey, para = r; } - if (opt.flags.rfc4880bis) - { - r = xmalloc_clear (sizeof *r + 20); - r->key = for_subkey? pSUBVERSION : pVERSION; - snprintf (r->u.value, 20, "%d", version); - r->next = para; - para = r; - } + r = xmalloc_clear (sizeof *r + 20); + r->key = for_subkey? pSUBVERSION : pVERSION; + snprintf (r->u.value, 20, "%d", version); + r->next = para; + para = r; if (keytime) { @@ -5315,8 +5286,8 @@ card_store_key_with_backup (ctrl_t ctrl, PKT_public_key *sub_psk, goto leave; } - err = receive_seckey_from_agent (ctrl, cipherhd, 0, - &cache_nonce, hexgrip, sk); + err = receive_seckey_from_agent (ctrl, cipherhd, 0, 0, + &cache_nonce, hexgrip, sk, NULL); if (err) { log_error ("error getting secret key from agent: %s\n", diff --git a/g10/keylist.c b/g10/keylist.c index e785aa0..1ced732 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -44,6 +44,8 @@ #include "../common/mbox-util.h" #include "../common/zb32.h" #include "tofu.h" +#include "../common/init.h" +#include "../common/recsel.h" #include "../common/compliance.h" #include "../common/pkscreening.h" @@ -64,16 +66,26 @@ struct keylist_context int no_validity; /* Do not show validity. */ }; - -static void list_keyblock (ctrl_t ctrl, - kbnode_t keyblock, int secret, int has_secret, - int fpr, struct keylist_context *listctx); +/* An object and a global instance to store selectors created from + * --list-filter select=EXPR. + */ +struct list_filter_s +{ + recsel_expr_t selkey; +}; +struct list_filter_s list_filter; /* The stream used to write attribute packets to. */ static estream_t attrib_fp; + + +static void list_keyblock (ctrl_t ctrl, + kbnode_t keyblock, int secret, int has_secret, + int fpr, struct keylist_context *listctx); + /* Release resources from a keylist context. */ static void keylist_context_release (struct keylist_context *listctx) @@ -82,6 +94,49 @@ keylist_context_release (struct keylist_context *listctx) } +static void +release_list_filter (struct list_filter_s *filt) +{ + recsel_release (filt->selkey); + filt->selkey = NULL; +} + + +static void +cleanup_keylist_globals (void) +{ + release_list_filter (&list_filter); +} + + +/* Parse and set an list filter from string. STRING has the format + * "NAME=EXPR" with NAME being the name of the filter. Spaces before + * and after NAME are not allowed. If this function is all called + * several times all expressions for the same NAME are concatenated. + * Supported filter names are: + * + * - select :: If the expression evaluates to true for a certain key + * this key will be listed. The expression may use any + * variable defined for the export and import filters. + * + */ +gpg_error_t +parse_and_set_list_filter (const char *string) +{ + gpg_error_t err; + + /* Auto register the cleanup function. */ + register_mem_cleanup_func (cleanup_keylist_globals); + + if (!strncmp (string, "select=", 7)) + err = recsel_parse_expr (&list_filter.selkey, string+7); + else + err = gpg_error (GPG_ERR_INV_NAME); + + return err; +} + + /* List the keys. If list is NULL, all available keys are listed. * With LOCATE_MODE set the locate algorithm is used to find a key; if * in addition NO_LOCAL is set the locate does not look into the local @@ -306,6 +361,173 @@ print_card_key_info (estream_t fp, kbnode_t keyblock) #endif /*ENABLE_CARD_SUPPORT*/ +/* Print the preferences line. Allowed values for MODE are: + * -1 - print to the TTY + * 0 - print to stdout. + * 1 - use log_info + */ +void +show_preferences (PKT_user_id *uid, int indent, int mode, int verbose) +{ + estream_t fp = mode < 0? NULL : mode ? log_get_stream () : es_stdout; + const prefitem_t fake = { 0, 0 }; + const prefitem_t *prefs; + int i; + + if (!uid) + return; + + if (uid->prefs) + prefs = uid->prefs; + else if (verbose) + prefs = &fake; + else + return; + + if (verbose) + { + int any, des_seen = 0, sha1_seen = 0, uncomp_seen = 0; + + tty_fprintf (fp, "%*s %s", indent, "", _("Cipher: ")); + for (i = any = 0; prefs[i].type; i++) + { + if (prefs[i].type == PREFTYPE_SYM) + { + if (any) + tty_fprintf (fp, ", "); + any = 1; + /* We don't want to display strings for experimental algos */ + if (!openpgp_cipher_test_algo (prefs[i].value) + && prefs[i].value < 100) + tty_fprintf (fp, "%s", openpgp_cipher_algo_name (prefs[i].value)); + else + tty_fprintf (fp, "[%d]", prefs[i].value); + if (prefs[i].value == CIPHER_ALGO_3DES) + des_seen = 1; + } + } + if (!des_seen) + { + if (any) + tty_fprintf (fp, ", "); + tty_fprintf (fp, "%s", openpgp_cipher_algo_name (CIPHER_ALGO_3DES)); + } + tty_fprintf (fp, "\n%*s %s", indent, "", _("AEAD: ")); + for (i = any = 0; prefs[i].type; i++) + { + if (prefs[i].type == PREFTYPE_AEAD) + { + if (any) + tty_fprintf (fp, ", "); + any = 1; + /* We don't want to display strings for experimental algos */ + if (!openpgp_aead_test_algo (prefs[i].value) + && prefs[i].value < 100) + tty_fprintf (fp, "%s", openpgp_aead_algo_name (prefs[i].value)); + else + tty_fprintf (fp, "[%d]", prefs[i].value); + } + } + tty_fprintf (fp, "\n%*s %s", indent, "", _("Digest: ")); + for (i = any = 0; prefs[i].type; i++) + { + if (prefs[i].type == PREFTYPE_HASH) + { + if (any) + tty_fprintf (fp, ", "); + any = 1; + /* We don't want to display strings for experimental algos */ + if (!gcry_md_test_algo (prefs[i].value) && prefs[i].value < 100) + tty_fprintf (fp, "%s", gcry_md_algo_name (prefs[i].value)); + else + tty_fprintf (fp, "[%d]", prefs[i].value); + if (prefs[i].value == DIGEST_ALGO_SHA1) + sha1_seen = 1; + } + } + if (!sha1_seen) + { + if (any) + tty_fprintf (fp, ", "); + tty_fprintf (fp, "%s", gcry_md_algo_name (DIGEST_ALGO_SHA1)); + } + tty_fprintf (fp, "\n%*s %s", indent, "", _("Compression: ")); + for (i = any = 0; prefs[i].type; i++) + { + if (prefs[i].type == PREFTYPE_ZIP) + { + const char *s = compress_algo_to_string (prefs[i].value); + + if (any) + tty_fprintf (fp, ", "); + any = 1; + /* We don't want to display strings for experimental algos */ + if (s && prefs[i].value < 100) + tty_fprintf (fp, "%s", s); + else + tty_fprintf (fp, "[%d]", prefs[i].value); + if (prefs[i].value == COMPRESS_ALGO_NONE) + uncomp_seen = 1; + } + } + if (!uncomp_seen) + { + if (any) + tty_fprintf (fp, ", "); + else + { + tty_fprintf (fp, "%s", + compress_algo_to_string (COMPRESS_ALGO_ZIP)); + tty_fprintf (fp, ", "); + } + tty_fprintf (fp, "%s", compress_algo_to_string (COMPRESS_ALGO_NONE)); + } + if (uid->flags.mdc || uid->flags.aead || !uid->flags.ks_modify) + { + tty_fprintf (fp, "\n%*s %s", indent, "", _("Features: ")); + any = 0; + if (uid->flags.mdc) + { + tty_fprintf (fp, "MDC"); + any = 1; + } + if (uid->flags.aead) + { + if (any) + tty_fprintf (fp, ", "); + tty_fprintf (fp, "AEAD"); + } + if (!uid->flags.ks_modify) + { + if (any) + tty_fprintf (fp, ", "); + tty_fprintf (fp, _("Keyserver no-modify")); + } + } + tty_fprintf (fp, "\n"); + } + else + { + tty_fprintf (fp, "%*s", indent, ""); + for (i = 0; prefs[i].type; i++) + { + tty_fprintf (fp, " %c%d", prefs[i].type == PREFTYPE_SYM ? 'S' : + prefs[i].type == PREFTYPE_AEAD ? 'A' : + prefs[i].type == PREFTYPE_HASH ? 'H' : + prefs[i].type == PREFTYPE_ZIP ? 'Z' : '?', + prefs[i].value); + } + if (uid->flags.mdc) + tty_fprintf (fp, " [mdc]"); + if (uid->flags.aead) + tty_fprintf (fp, " [aead]"); + if (!uid->flags.ks_modify) + tty_fprintf (fp, " [no-ks-modify]"); + tty_fprintf (fp, "\n"); + } +} + + /* Flags = 0x01 hashed 0x02 critical. */ static void status_one_subpacket (sigsubpkttype_t type, size_t len, int flags, @@ -1269,6 +1491,11 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, print_utf8_buffer (es_stdout, uid->name, uid->len); es_putc ('\n', es_stdout); + if ((opt.list_options & LIST_SHOW_PREF_VERBOSE)) + show_preferences (uid, indent+2, 0, 1); + else if ((opt.list_options & LIST_SHOW_PREF)) + show_preferences (uid, indent+2, 0, 0); + if (opt.with_wkd_hash) { char *mbox, *hash, *p; @@ -1991,6 +2218,7 @@ reorder_keyblock (KBNODE keyblock) do_reorder_keyblock (keyblock, 0); } + static void list_keyblock (ctrl_t ctrl, KBNODE keyblock, int secret, int has_secret, int fpr, @@ -1998,6 +2226,24 @@ list_keyblock (ctrl_t ctrl, { reorder_keyblock (keyblock); + if (list_filter.selkey) + { + int selected = 0; + struct impex_filter_parm_s parm; + parm.ctrl = ctrl; + + for (parm.node = keyblock; parm.node; parm.node = parm.node->next) + { + if (recsel_select (list_filter.selkey, impex_filter_getval, &parm)) + { + selected = 1; + break; + } + } + if (!selected) + return; /* Skip this one. */ + } + if (opt.with_colons) list_keyblock_colon (ctrl, keyblock, secret, has_secret); else if ((opt.list_options & LIST_SHOW_ONLY_FPR_MBOX)) @@ -41,8 +41,6 @@ # define DEFAULT_CIPHER_ALGO CIPHER_ALGO_3DES #endif -#define DEFAULT_AEAD_ALGO AEAD_ALGO_OCB - #define DEFAULT_DIGEST_ALGO ((GNUPG)? DIGEST_ALGO_SHA256:DIGEST_ALGO_SHA1) #define DEFAULT_S2K_DIGEST_ALGO DIGEST_ALGO_SHA1 #ifdef HAVE_ZIP @@ -169,7 +167,6 @@ const char *compress_algo_to_string(int algo); int string_to_compress_algo(const char *string); int check_compress_algo(int algo); int default_cipher_algo(void); -aead_algo_t default_aead_algo(void); int default_compress_algo(void); void compliance_failure(void); @@ -240,8 +237,6 @@ void display_online_help( const char *keyword ); /*-- encode.c --*/ gpg_error_t setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek); -gpg_error_t encrypt_seskey (DEK *dek, aead_algo_t aead_algo, DEK **r_seskey, - void **r_enckey, size_t *r_enckeylen); aead_algo_t use_aead (pk_list_t pk_list, int algo); int use_mdc (pk_list_t pk_list,int algo); int encrypt_symmetric (const char *filename ); @@ -436,10 +431,10 @@ gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, void **r_data, size_t *r_datalen); gpg_error_t receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd, - int cleartext, + int cleartext, int mode1003, char **cache_nonce_addr, const char *hexgrip, - PKT_public_key *pk); + PKT_public_key *pk, gcry_sexp_t *r_key); gpg_error_t write_keyblock_to_output (kbnode_t keyblock, int with_armor, unsigned int options); @@ -469,6 +464,7 @@ void release_revocation_reason_info (struct revocation_reason_info *reason); void public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode, int no_local); void secret_key_list (ctrl_t ctrl, strlist_t list ); +gpg_error_t parse_and_set_list_filter (const char *string); void print_subpackets_colon(PKT_signature *sig); void reorder_keyblock (KBNODE keyblock); void list_keyblock_direct (ctrl_t ctrl, kbnode_t keyblock, int secret, @@ -477,6 +473,7 @@ int cmp_signodes (const void *av, const void *bv); void print_fingerprint (ctrl_t ctrl, estream_t fp, PKT_public_key *pk, int mode); void print_revokers (estream_t fp, PKT_public_key *pk); +void show_preferences (PKT_user_id *uid, int indent, int mode, int verbose); void show_policy_url(PKT_signature *sig,int indent,int mode); void show_keyserver_url(PKT_signature *sig,int indent,int mode); void show_notation(PKT_signature *sig,int indent,int mode,int which); diff --git a/g10/mainproc.c b/g10/mainproc.c index f8f3c15..330ad10 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -726,7 +726,7 @@ proc_encrypted (CTX c, PACKET *pkt) } /* Compute compliance with CO_DE_VS. */ - if (!result && is_status_enabled () + if (!result && (is_status_enabled () || opt.flags.require_compliance) /* Overriding session key voids compliance. */ && !opt.override_session_key /* Check symmetric cipher. */ @@ -1387,17 +1387,6 @@ default_cipher_algo(void) } -aead_algo_t -default_aead_algo(void) -{ - if(opt.def_aead_algo) - return opt.def_aead_algo; - else if(opt.personal_aead_prefs) - return opt.personal_aead_prefs[0].value; - else - return DEFAULT_AEAD_ALGO; -} - /* There is no default_digest_algo function, but see sign.c:hash_for() */ diff --git a/g10/options.h b/g10/options.h index 10e61ea..c108626 100644 --- a/g10/options.h +++ b/g10/options.h @@ -92,7 +92,6 @@ struct int no_armor; int list_packets; /* Option --list-packets active. */ int def_cipher_algo; - int def_aead_algo; int force_mdc; int disable_mdc; int force_aead; @@ -180,7 +179,6 @@ struct const char *def_preference_list; const char *def_keyserver_url; prefitem_t *personal_cipher_prefs; - prefitem_t *personal_aead_prefs; prefitem_t *personal_digest_prefs; prefitem_t *personal_compress_prefs; struct weakhash *weak_digests; @@ -308,6 +306,9 @@ struct int no_symkey_cache; /* Disable the cache used for --symmetric. */ int use_keyboxd; /* Use the external keyboxd as storage backend. */ + + /* Compatibility flags (COMPAT_FLAG_xxxx). */ + unsigned int compat_flags; } opt; /* CTRL is used to keep some global variables we currently can't @@ -363,8 +364,11 @@ struct { EXTERN_UNLESS_MAIN_MODULE int memory_debug_mode; EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode; +/* Compatibility flags */ +/* #define COMPAT_FOO 1 */ + -/* Compatibility flags. */ +/* Compliance test macors. */ #define GNUPG (opt.compliance==CO_GNUPG || opt.compliance==CO_DE_VS) #define RFC2440 (opt.compliance==CO_RFC2440) #define RFC4880 (opt.compliance==CO_RFC4880) @@ -402,6 +406,8 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode; #define EXPORT_CLEAN (1<<5) #define EXPORT_DANE_FORMAT (1<<7) #define EXPORT_BACKUP (1<<10) +#define EXPORT_REVOCS (1<<11) +#define EXPORT_MODE1003 (1<<12) #define LIST_SHOW_PHOTOS (1<<0) #define LIST_SHOW_POLICY_URLS (1<<1) @@ -418,6 +424,8 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode; #define LIST_SHOW_USAGE (1<<11) #define LIST_SHOW_ONLY_FPR_MBOX (1<<12) #define LIST_SORT_SIGS (1<<13) +#define LIST_SHOW_PREF (1<<14) +#define LIST_SHOW_PREF_VERBOSE (1<<15) #define VERIFY_SHOW_PHOTOS (1<<0) #define VERIFY_SHOW_POLICY_URLS (1<<1) diff --git a/g10/parse-packet.c b/g10/parse-packet.c index b6aebbb..a033732 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -2752,11 +2752,15 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, break; case 1001: if (list_mode) - es_fprintf (listfp, "\tgnu-dummy S2K"); + es_fprintf (listfp, "\tgnu-dummy"); break; case 1002: if (list_mode) - es_fprintf (listfp, "\tgnu-divert-to-card S2K"); + es_fprintf (listfp, "\tgnu-divert-to-card"); + break; + case 1003: + if (list_mode) + es_fprintf (listfp, "\tgnu-mode1003"); break; default: if (list_mode) @@ -2768,7 +2772,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, } /* Print some info. */ - if (list_mode) + if (list_mode && ski->s2k.mode != 1003) { es_fprintf (listfp, ", algo: %d,%s hash: %d", ski->algo, @@ -2779,8 +2783,9 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, es_fprintf (listfp, ", salt: "); es_write_hexstring (listfp, ski->s2k.salt, 8, 0, NULL); } - es_putc ('\n', listfp); - } + } + if (list_mode) + es_putc ('\n', listfp); /* Read remaining protection parameters. */ if (ski->s2k.mode == 3) @@ -2838,7 +2843,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, ski->ivlen = openpgp_cipher_blocklen (ski->algo); log_assert (ski->ivlen <= sizeof (temp)); - if (ski->s2k.mode == 1001) + if (ski->s2k.mode == 1001 || ski->s2k.mode == 1003) ski->ivlen = 0; else if (ski->s2k.mode == 1002) ski->ivlen = snlen < 16 ? snlen : 16; @@ -2850,7 +2855,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, } for (i = 0; i < ski->ivlen; i++, pktlen--) temp[i] = iobuf_get_noeof (inp); - if (list_mode) + if (list_mode && ski->s2k.mode != 1003) { es_fprintf (listfp, ski->s2k.mode == 1002 ? "\tserial-number: " @@ -2888,6 +2893,35 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, 10 * 8); pktlen = 0; } + else if (ski->s2k.mode == 1003) + { + void *tmpp; + + if (pktlen < 2) /* At least two bytes for parenthesis. */ + { + err = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + + tmpp = read_rest (inp, pktlen); + if (list_mode) + { + if (mpi_print_mode) + { + char *tmpsxp = canon_sexp_to_string (tmpp, pktlen); + es_fprintf (listfp, "\tskey[%d]: %s\n", npkey, + tmpsxp? trim_trailing_spaces (tmpsxp) + /* */: "[invalid S-expression]"); + xfree (tmpsxp); + } + else + es_fprintf (listfp, "\tskey[%d]: [s-expression %lu octets]\n", + npkey, pktlen); + } + pk->pkey[npkey] = gcry_mpi_set_opaque (NULL, + tmpp, tmpp? pktlen * 8 : 0); + pktlen = 0; + } else if (ski->is_protected) { void *tmpp; diff --git a/g10/photoid.c b/g10/photoid.c index 2c95930..72e6acf 100644 --- a/g10/photoid.c +++ b/g10/photoid.c @@ -36,7 +36,6 @@ #include "../common/util.h" #include "packet.h" #include "../common/status.h" -#include "exec.h" #include "keydb.h" #include "../common/i18n.h" #include "../common/iobuf.h" @@ -46,6 +45,114 @@ #include "../common/ttyio.h" #include "trustdb.h" +#if defined (_WIN32) +/* This is a nicer system() for windows that waits for programs to + return before returning control to the caller. I hate helpful + computers. */ +static int +w32_system (const char *command) +{ + if (!strncmp (command, "!ShellExecute ", 14)) + { + SHELLEXECUTEINFOW see; + wchar_t *wname; + int waitms; + + command = command + 14; + while (spacep (command)) + command++; + waitms = atoi (command); + if (waitms < 0) + waitms = 0; + else if (waitms > 60*1000) + waitms = 60000; + while (*command && !spacep (command)) + command++; + while (spacep (command)) + command++; + + wname = utf8_to_wchar (command); + if (!wname) + return -1; + + memset (&see, 0, sizeof see); + see.cbSize = sizeof see; + see.fMask = (SEE_MASK_NOCLOSEPROCESS + | SEE_MASK_NOASYNC + | SEE_MASK_FLAG_NO_UI + | SEE_MASK_NO_CONSOLE); + see.lpVerb = L"open"; + see.lpFile = (LPCWSTR)wname; + see.nShow = SW_SHOW; + + if (DBG_EXTPROG) + log_debug ("running ShellExecuteEx(open,'%s')\n", command); + if (!ShellExecuteExW (&see)) + { + if (DBG_EXTPROG) + log_debug ("ShellExecuteEx failed: rc=%d\n", (int)GetLastError ()); + xfree (wname); + return -1; + } + if (DBG_EXTPROG) + log_debug ("ShellExecuteEx succeeded (hProcess=%p,hInstApp=%d)\n", + see.hProcess, (int)see.hInstApp); + + if (!see.hProcess) + { + gnupg_usleep (waitms*1000); + if (DBG_EXTPROG) + log_debug ("ShellExecuteEx ready (wait=%dms)\n", waitms); + } + else + { + WaitForSingleObject (see.hProcess, INFINITE); + if (DBG_EXTPROG) + log_debug ("ShellExecuteEx ready\n"); + } + CloseHandle (see.hProcess); + + xfree (wname); + } + else + { + char *string; + wchar_t *wstring; + PROCESS_INFORMATION pi; + STARTUPINFOW si; + + /* We must use a copy of the command as CreateProcess modifies + * this argument. */ + string = xstrdup (command); + wstring = utf8_to_wchar (string); + xfree (string); + if (!wstring) + return -1; + + memset (&pi, 0, sizeof(pi)); + memset (&si, 0, sizeof(si)); + si.cb = sizeof (si); + + if (!CreateProcessW (NULL, wstring, NULL, NULL, FALSE, + DETACHED_PROCESS, + NULL, NULL, &si, &pi)) + { + xfree (wstring); + return -1; + } + + /* Wait for the child to exit */ + WaitForSingleObject (pi.hProcess, INFINITE); + + CloseHandle (pi.hProcess); + CloseHandle (pi.hThread); + xfree (wstring); + } + + return 0; +} +#endif /*_W32*/ + /* Generate a new photo id packet, or return NULL if canceled. FIXME: Should we add a duplicates check similar to generate_user_id? */ PKT_user_id * diff --git a/g10/pkclist.c b/g10/pkclist.c index 9b08cc4..459e759 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -1603,8 +1603,6 @@ select_algo_from_prefs(PK_LIST pk_list, int preftype, prefs=NULL; if(preftype==PREFTYPE_SYM && opt.personal_cipher_prefs) prefs=opt.personal_cipher_prefs; - else if(preftype==PREFTYPE_AEAD && opt.personal_aead_prefs) - prefs=opt.personal_aead_prefs; else if(preftype==PREFTYPE_HASH && opt.personal_digest_prefs) prefs=opt.personal_digest_prefs; else if(preftype==PREFTYPE_ZIP && opt.personal_compress_prefs) @@ -1720,7 +1718,7 @@ select_aead_from_pklist (PK_LIST pk_list) return 0; /* At least one recipient does not support it. */ } - return default_aead_algo (); /* Yes, AEAD can be used. */ + return AEAD_ALGO_OCB; /* Yes, AEAD can be used. */ } diff --git a/g10/test-stubs.c b/g10/test-stubs.c index cfe33b1..6ae0f4e 100644 --- a/g10/test-stubs.c +++ b/g10/test-stubs.c @@ -572,3 +572,11 @@ get_revocation_reason (PKT_signature *sig, char **r_reason, *r_comment = NULL; return 0; } + +const char * +impex_filter_getval (void *cookie, const char *propname) +{ + (void)cookie; + (void)propname; + return NULL; +} diff --git a/g10/trustdb.c b/g10/trustdb.c index 7e24864..051a534 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -1707,38 +1707,50 @@ sanitize_regexp(const char *old) return new; } + /* Used by validate_one_keyblock to confirm a regexp within a trust - signature. Returns 1 for match, and 0 for no match or regex - error. */ + * signature. Returns 1 for match, and 0 for no match or regex + * error. */ static int -check_regexp(const char *expr,const char *string) +check_regexp (const char *expr,const char *string) { int ret; char *regexp; + char *stringbuf = NULL; + regex_t pat; - regexp=sanitize_regexp(expr); - - { - regex_t pat; + regexp = sanitize_regexp (expr); - ret=regcomp(&pat,regexp,REG_ICASE|REG_EXTENDED); - if(ret==0) - { - ret=regexec(&pat,string,0,NULL,0); - regfree(&pat); - } - ret=(ret==0); - } + ret = regcomp (&pat, regexp, (REG_ICASE|REG_EXTENDED)); + if (!ret) + { + if (*regexp == '<' && !strchr (string, '<') + && is_valid_mailbox (string)) + { + /* The R.E. starts with an angle bracket but STRING seems to + * be a plain mailbox (e.g. "foo@example.org"). The + * commonly used R.E. pattern "<[^>]+[@.]example\.org>$" + * won't be able to detect this. Thus we enclose STRING + * into angle brackets for checking. */ + stringbuf = xstrconcat ("<", string, ">", NULL); + string = stringbuf; + } + ret = regexec (&pat, string, 0, NULL, 0); + regfree (&pat); + } - if(DBG_TRUST) - log_debug("regexp '%s' ('%s') on '%s': %s\n", - regexp,expr,string,ret?"YES":"NO"); + ret = !ret; - xfree(regexp); + if (DBG_TRUST) + log_debug ("regexp '%s' ('%s') on '%s'%s: %s\n", + regexp, expr, string, stringbuf? " (fixed)":"", ret? "YES":"NO"); + xfree (regexp); + xfree (stringbuf); return ret; } + /* * Return true if the key is signed by one of the keys in the given * key ID list. User IDs with a valid signature are marked by node |