aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--agent/call-pinentry.c17
-rw-r--r--agent/divert-scd.c119
-rw-r--r--build-aux/speedo.mk167
-rw-r--r--build-aux/speedo/w32/wixlib.wxs664
-rw-r--r--common/asshelp.c12
-rw-r--r--common/name-value.c6
-rw-r--r--common/openpgpdefs.h2
-rw-r--r--common/sysutils.c4
-rw-r--r--configure.ac21
-rw-r--r--dirmngr/dns.c2
-rw-r--r--dirmngr/http.c2
-rw-r--r--doc/DETAILS5
-rw-r--r--doc/Makefile.am4
-rw-r--r--doc/debugging.texi8
-rw-r--r--doc/dirmngr.texi10
-rw-r--r--doc/gpg-agent.texi31
-rw-r--r--doc/gpg.texi27
-rw-r--r--doc/gpgsm.texi30
-rw-r--r--doc/help.txt8
-rw-r--r--doc/scdaemon.texi32
-rw-r--r--doc/wks.texi6
-rw-r--r--g10/Makefile.am1
-rw-r--r--g10/build-packet.c2
-rw-r--r--g10/call-agent.c27
-rw-r--r--g10/call-agent.h2
-rw-r--r--g10/card-util.c55
-rw-r--r--g10/dek.h6
-rw-r--r--g10/exec.c538
-rw-r--r--g10/exec.h27
-rw-r--r--g10/expand-group.c73
-rw-r--r--g10/export.c190
-rw-r--r--g10/getkey.c77
-rw-r--r--g10/gpg.c33
-rw-r--r--g10/import.c2
-rw-r--r--g10/key-clean.c2
-rw-r--r--g10/keydb.c17
-rw-r--r--g10/keydb.h13
-rw-r--r--g10/keyedit.c14
-rw-r--r--g10/keygen.c349
-rw-r--r--g10/keylist.c15
-rw-r--r--g10/keyserver.c10
-rw-r--r--g10/mainproc.c9
-rw-r--r--g10/options.h6
-rw-r--r--g10/packet.h99
-rw-r--r--g10/parse-packet.c122
-rw-r--r--g10/photoid.c406
-rw-r--r--g10/photoid.h2
-rw-r--r--g10/pkclist.c53
-rw-r--r--g10/sign.c8
-rw-r--r--g10/trustdb.c4
-rw-r--r--kbx/keybox-blob.c2
-rw-r--r--kbx/keybox-dump.c7
-rw-r--r--kbx/keybox-update.c4
-rw-r--r--scd/apdu.c560
-rw-r--r--scd/apdu.h2
-rw-r--r--scd/app-common.h6
-rw-r--r--scd/app-nks.c37
-rw-r--r--scd/app-openpgp.c11
-rw-r--r--scd/app-p15.c2
-rw-r--r--scd/app-piv.c27
-rw-r--r--scd/app-sc-hsm.c2
-rw-r--r--scd/app.c558
-rw-r--r--scd/ccid-driver.c26
-rw-r--r--scd/ccid-driver.h8
-rw-r--r--scd/command.c102
-rw-r--r--scd/iso7816.c1
-rw-r--r--scd/scdaemon.c1
-rw-r--r--scd/scdaemon.h3
-rw-r--r--sm/call-agent.c23
-rw-r--r--sm/decrypt.c6
-rw-r--r--sm/keydb.c5
-rw-r--r--tools/Makefile.am6
-rw-r--r--tools/gpg-card.c4
-rw-r--r--tools/gpg-pair-tool.c92
-rw-r--r--tools/gpgconf-comp.c2
76 files changed, 3124 insertions, 1713 deletions
diff --git a/Makefile.am b/Makefile.am
index b59e9e3ec..6cbb9c36d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -55,6 +55,7 @@ EXTRA_DIST = build-aux/config.rpath build-aux/potomo autogen.sh autogen.rc \
build-aux/speedo/w32/README.txt \
build-aux/speedo/w32/gnupg-logo-150x57.bmp \
build-aux/speedo/w32/gnupg-logo-164x314.bmp \
+ build-aux/speedo/w32/wixlib.wxs \
build-aux/speedo/patches/atk-1.32.0.patch \
build-aux/speedo/patches/libiconv-1.14.patch \
build-aux/speedo/patches/pango-1.29.4.patch \
diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c
index a895a8b8f..34eb77cfb 100644
--- a/agent/call-pinentry.c
+++ b/agent/call-pinentry.c
@@ -1481,15 +1481,16 @@ agent_get_confirmation (ctrl_t ctrl,
npth_t thread;
rc = watch_sock_start (&sock_watched, &thread);
- if (rc)
- return rc;
-
- rc = assuan_transact (entry_ctx, "CONFIRM",
- NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
- rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
+ if (!rc)
+ {
+ rc = assuan_transact (entry_ctx, "CONFIRM",
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ if (rc && gpg_err_source (rc)
+ && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
+ rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
- watch_sock_end (&sock_watched, &thread);
+ watch_sock_end (&sock_watched, &thread);
+ }
return unlock_pinentry (ctrl, rc);
}
diff --git a/agent/divert-scd.c b/agent/divert-scd.c
index cfa2347c7..ee97a7e7e 100644
--- a/agent/divert-scd.c
+++ b/agent/divert-scd.c
@@ -36,128 +36,81 @@ static gpg_error_t
ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info,
const unsigned char *grip, char **r_kid)
{
- int i;
char *serialno;
- int no_card = 0;
char *desc;
- char *want_sn, *want_kid, *want_sn_disp;
+ char *want_sn;
int len;
- struct card_key_info_s *keyinfo;
gpg_error_t err;
char hexgrip[41];
*r_kid = NULL;
+ bin2hex (grip, 20, hexgrip);
- /* Scan device(s), and check if key for GRIP is available. */
- err = agent_card_serialno (ctrl, &serialno, NULL);
- if (!err)
- {
- xfree (serialno);
- bin2hex (grip, 20, hexgrip);
- err = agent_card_keyinfo (ctrl, hexgrip, &keyinfo);
- if (!err)
- {
- /* Key for GRIP found, use it directly. */
- agent_card_free_keyinfo (keyinfo);
- if ((*r_kid = xtrystrdup (hexgrip)))
- return 0;
- else
- return gpg_error_from_syserror ();
- }
- }
-
- err = parse_shadow_info (shadow_info, &want_sn, &want_kid, NULL);
+ err = parse_shadow_info (shadow_info, &want_sn, NULL, NULL);
if (err)
return err;
- want_sn_disp = xtrystrdup (want_sn);
- if (!want_sn_disp)
- {
- err = gpg_error_from_syserror ();
- xfree (want_sn);
- xfree (want_kid);
- return err;
- }
- len = strlen (want_sn_disp);
- if (len == 32 && !strncmp (want_sn_disp, "D27600012401", 12))
+ len = strlen (want_sn);
+ if (len == 32 && !strncmp (want_sn, "D27600012401", 12))
{
/* This is an OpenPGP card - reformat */
- memmove (want_sn_disp, want_sn_disp+16, 4);
- want_sn_disp[4] = ' ';
- memmove (want_sn_disp+5, want_sn_disp+20, 8);
- want_sn_disp[13] = 0;
+ memmove (want_sn, want_sn+16, 4);
+ want_sn[4] = ' ';
+ memmove (want_sn+5, want_sn+20, 8);
+ want_sn[13] = 0;
}
- else if (len == 20 && want_sn_disp[19] == '0')
+ else if (len == 20 && want_sn[19] == '0')
{
/* We assume that a 20 byte serial number is a standard one
* which has the property to have a zero in the last nibble (Due
* to BCD representation). We don't display this '0' because it
* may confuse the user. */
- want_sn_disp[19] = 0;
+ want_sn[19] = 0;
}
for (;;)
{
- err = agent_card_serialno (ctrl, &serialno, want_sn);
+ /* Scan device(s), and check if key for GRIP is available. */
+ err = agent_card_serialno (ctrl, &serialno, NULL);
if (!err)
{
- log_debug ("detected card with S/N %s\n", serialno);
- i = strcmp (serialno, want_sn);
+ struct card_key_info_s *keyinfo;
+
xfree (serialno);
- serialno = NULL;
- if (!i)
+ err = agent_card_keyinfo (ctrl, hexgrip, &keyinfo);
+ if (!err)
{
- xfree (want_sn_disp);
+ /* Key for GRIP found, use it directly. */
+ agent_card_free_keyinfo (keyinfo);
xfree (want_sn);
- *r_kid = want_kid;
- return 0; /* yes, we have the correct card */
+ if ((*r_kid = xtrystrdup (hexgrip)))
+ return 0;
+ else
+ return gpg_error_from_syserror ();
}
}
- else if (gpg_err_code (err) == GPG_ERR_ENODEV)
- {
- log_debug ("no device present\n");
- err = 0;
- no_card = 1;
- }
- else if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
+
+ if (asprintf (&desc,
+ "%s:%%0A%%0A"
+ " %s",
+ L_("Please insert the card with serial number"),
+ want_sn) < 0)
{
- log_debug ("no card present\n");
- err = 0;
- no_card = 2;
+ err = out_of_core ();
}
else
{
- log_error ("error accessing card: %s\n", gpg_strerror (err));
- }
-
- if (!err)
- {
- if (asprintf (&desc,
- "%s:%%0A%%0A"
- " %s",
- no_card
- ? L_("Please insert the card with serial number")
- : L_("Please remove the current card and "
- "insert the one with serial number"),
- want_sn_disp) < 0)
- {
- err = out_of_core ();
- }
- else
- {
- err = agent_get_confirmation (ctrl, desc, NULL, NULL, 0);
- if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK &&
- gpg_err_code (err) == GPG_ERR_NO_PIN_ENTRY)
- err = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
+ err = agent_get_confirmation (ctrl, desc, NULL, NULL, 0);
+ if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK &&
+ gpg_err_code (err) == GPG_ERR_NO_PIN_ENTRY)
+ err = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
- xfree (desc);
- }
+ xfree (desc);
}
+
if (err)
{
- xfree (want_sn_disp);
xfree (want_sn);
- xfree (want_kid);
return err;
}
}
diff --git a/build-aux/speedo.mk b/build-aux/speedo.mk
index 569940099..8217ef46e 100644
--- a/build-aux/speedo.mk
+++ b/build-aux/speedo.mk
@@ -1,5 +1,5 @@
# speedo.mk - Speedo rebuilds speedily.
-# Copyright (C) 2008, 2014 g10 Code GmbH
+# Copyright (C) 2008, 2014, 2019 g10 Code GmbH
#
# speedo is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -45,7 +45,7 @@
# We need to know our own name.
SPEEDO_MK := $(realpath $(lastword $(MAKEFILE_LIST)))
-.PHONY : help native native-gui w32-installer w32-source
+.PHONY : help native native-gui w32-installer w32-source w32-wixlib
.PHONY : git-native git-native-gui git-w32-installer git-w32-source
.PHONY : this-native this-native-gui this-w32-installer this-w32-source
@@ -58,6 +58,7 @@ help:
@echo ' w32-installer Build a Windows installer'
@echo ' w32-source Pack a source archive'
@echo ' w32-release Build a Windows release'
+ @echo ' w32-wixlib Build a wixlib for MSI packages'
@echo ' w32-sign-installer Sign the installer'
@echo
@echo 'You may append INSTALL_PREFIX=<dir> for native builds.'
@@ -66,6 +67,8 @@ help:
@echo 'Use STATIC=1 to build with statically linked libraries.'
@echo 'Use SELFCHECK=0 for a non-released version.'
@echo 'Use CUSTOM_SWDB=1 for an already downloaded swdb.lst.'
+ @echo 'Use WIXPREFIX to provide the WIX binaries for the MSI package.'
+ @echo ' Using WIX also requires wine with installed wine mono.'
SPEEDOMAKE := $(MAKE) -f $(SPEEDO_MK) UPD_SWDB=1
@@ -96,6 +99,15 @@ git-w32-installer: check-tools
this-w32-installer: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=this WITH_GUI=0 \
CUSTOM_SWDB=1 installer
+w32-wixlib: check-tools
+ $(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 wixlib
+
+git-w32-wixlib: check-tools
+ $(SPEEDOMAKE) TARGETOS=w32 WHAT=git WITH_GUI=0 wixlib
+
+this-w32-wixlib: check-tools
+ $(SPEEDOMAKE) TARGETOS=w32 WHAT=this WITH_GUI=0 \
+ CUSTOM_SWDB=1 wixlib
w32-source: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 dist-source
@@ -157,9 +169,44 @@ INST_NAME=gnupg-w32
# Use this to override the installaion directory for native builds.
INSTALL_PREFIX=none
-# The Authenticode key and cert chain used to sign the Windows installer
+# Set this to the location of wixtools
+WIXPREFIX=
+
+# The Authenticode key and cert chain used to sign the Windows
+# installer If AUTHENTICODE_SIGNHOST is specified, signing is done on
+# that host using the Windows signtool. The signhost is usually an
+# entry in .ssh/config. Depending on the used token it might be
+# necessary to allow single signon and unlock the token before running
+# this makefile. All files given in AUTHENTICODE_FILES are signed
+# before they are put into the installer.
+AUTHENTICODE_SIGNHOST=authenticode-signhost
+AUTHENTICODE_TOOL='"C:\Program Files (x86)\Windows Kits\10\bin\signtool.exe"'
AUTHENTICODE_KEY=${HOME}/.gnupg/g10code-authenticode-key.p12
AUTHENTICODE_CERTS=${HOME}/.gnupg/g10code-authenticode-certs.pem
+AUTHENTICODE_FILES= \
+ dirmngr.exe \
+ dirmngr_ldap.exe \
+ gpg-agent.exe \
+ gpg-connect-agent.exe \
+ gpg-preset-passphrase.exe \
+ gpg-wks-client.exe \
+ gpg.exe \
+ gpgconf.exe \
+ gpgme-w32spawn.exe \
+ gpgsm.exe \
+ gpgtar.exe \
+ gpgv.exe \
+ libassuan-0.dll \
+ libgcrypt-20.dll \
+ libgpg-error-0.dll \
+ libgpgme-11.dll \
+ libksba-8.dll \
+ libnpth-0.dll \
+ libsqlite3-0.dll \
+ pinentry-w32.exe \
+ scdaemon.exe \
+ zlib1.dll
+
# Directory names.
@@ -699,6 +746,8 @@ W32CC = i686-w64-mingw32-gcc
MKDIR=mkdir
MAKENSIS=makensis
+WINE=wine
+
SHA1SUM := $(shell $(topsrc)/build-aux/getswdb.sh --find-sha1sum)
ifeq ($(SHA1SUM),false)
$(error The sha1sum tool is missing)
@@ -1211,7 +1260,22 @@ ifeq ($(WITH_GUI),1)
extra_installer_options += -DWITH_GUI=1
endif
+# Note that we sign only when doing the final installer.
installer: all w32_insthelpers $(w32src)/inst-options.ini $(bdir)/README.txt
+ (set -e;\
+ cd "$(idir)"; \
+ if echo "$(idir)" | grep -q '/PLAY-release/' ; then \
+ for f in $(AUTHENTICODE_FILES); do \
+ if [ -f "bin/$$f" ]; then \
+ $(call AUTHENTICODE_sign,"bin/$$f","bin/$$f");\
+ elif [ -f "libexec/$$f" ]; then \
+ $(call AUTHENTICODE_sign,"libexec/$$f","libexec/$$f");\
+ else \
+ echo "speedo: WARNING: file '$$f' not available for signing";\
+ fi;\
+ done; \
+ fi \
+ )
(nsis3_args=$$(makensis -version | grep -q "^v3" && \
echo "-INPUTCHARSET CP1252"); \
$(MAKENSIS) -V2 $$nsis3_args \
@@ -1228,6 +1292,59 @@ installer: all w32_insthelpers $(w32src)/inst-options.ini $(bdir)/README.txt
$(extra_installer_options) $(w32src)/inst.nsi)
@echo "Ready: $(idir)/$(INST_NAME)-$(INST_VERSION)_$(BUILD_DATESTR).exe"
+# We use the installer target to ensure everything is done and signed
+wixlib: installer $(bdir)/README.txt $(w32src)/wixlib.wxs
+ if [ -z "$$(which $(WINE))" ]; then \
+ echo "ERROR: For the w32-wixlib wine needs to be installed."; \
+ exit 1; \
+ fi;
+ if [ -z "$(WIXPREFIX)" ]; then \
+ echo "ERROR: You must set WIXPREFIX to an installation of wixtools."; \
+ exit 1; \
+ fi;
+ (if [ -z "$$WINEPREFIX" ]; then \
+ WINEPREFIX="$$HOME/.wine"; \
+ if [ ! -e "$$WINEPREFIX/dosdevices" ]; then \
+ echo "ERROR: No wine prefix found under $$WINEPREFIX"; \
+ exit 1; \
+ fi; \
+ fi; \
+ WINEINST=$$WINEPREFIX/dosdevices/k:; \
+ WINESRC=$$WINEPREFIX/dosdevices/i:; \
+ WINEBUILD=$$WINEPREFIX/dosdevices/j:; \
+ if [ -e "$$WINEINST" ]; then \
+ echo "ERROR: $$WINEINST already exists. Please remove."; \
+ exit 1; \
+ fi; \
+ if [ -e "$$WINESRC" ]; then \
+ echo "ERROR: $$WINESRC already exists. Please remove."; \
+ exit 1; \
+ fi; \
+ if [ -e "$$WINEBUILD" ]; then \
+ echo "ERROR: $$WINEBUILD already exists. Please remove."; \
+ exit 1; \
+ fi; \
+ echo "$(INST_NAME)" > $(bdir)/VERSION; \
+ echo "$(INST_VERSION)" >> $(bdir)/VERSION; \
+ MSI_VERSION=$$(echo $(INST_VERSION) | tr -s \\-beta .); \
+ (ln -s $(idir) $$WINEINST; \
+ ln -s $(w32src) $$WINESRC; \
+ ln -s $(bdir) $$WINEBUILD; \
+ $(WINE) $(WIXPREFIX)/candle.exe \
+ -dSourceDir=k: \
+ -dBuildDir=j: \
+ -dVersion=$$MSI_VERSION \
+ -out k:\\$(INST_NAME).wixobj \
+ -pedantic -wx i:\\wixlib.wxs ;\
+ $(WINE) $(WIXPREFIX)/lit.exe \
+ -out k:\\$(INST_NAME)-$(INST_VERSION)_$(BUILD_DATESTR).wixlib \
+ -bf \
+ -wx \
+ -pedantic \
+ k:\\$(INST_NAME).wixobj \
+ ); \
+ (rm $$WINEINST; rm $$WINESRC; rm $$WINEBUILD;) \
+ )
define MKSWDB_commands
( pref="#+macro: gnupg24_w32_" ;\
@@ -1239,6 +1356,28 @@ define MKSWDB_commands
) | tee $(1).swdb
endef
+# Sign the file $1 and save the result as $2
+define AUTHENTICODE_sign
+ set -e;\
+ if [ -n "$(AUTHENTICODE_SIGNHOST)" ]; then \
+ echo "speedo: Signing via host $(AUTHENTICODE_SIGNHOST)";\
+ scp $(1) "$(AUTHENTICODE_SIGNHOST):a.exe" ;\
+ ssh "$(AUTHENTICODE_SIGNHOST)" $(AUTHENTICODE_TOOL) sign \
+ /n '"g10 Code GmbH"' \
+ /tr 'http://rfc3161timestamp.globalsign.com/advanced' /td sha256 \
+ /fd sha256 /du https://gnupg.org a.exe ;\
+ scp "$(AUTHENTICODE_SIGNHOST):a.exe" $(2);\
+ echo "speedo: signed file is '$(2)'" ;\
+ else \
+ echo "speedo: Signing using key $(AUTHENTICODE_KEY)";\
+ osslsigncode sign -certs $(AUTHENTICODE_CERTS) \
+ -pkcs12 $(AUTHENTICODE_KEY) -askpass \
+ -ts "http://timestamp.globalsign.com/scripts/timstamp.dll" \
+ -h sha256 -n GnuPG -i https://gnupg.org \
+ -in $(1) -out $(2) ;\
+ fi
+endef
+
# Build the installer from the source tarball.
installer-from-source: dist-source
@@ -1249,11 +1388,21 @@ installer-from-source: dist-source
tar xJf "../$(INST_NAME)-$(INST_VERSION)_$(BUILD_DATESTR).tar.xz";\
cd $(INST_NAME)-$(INST_VERSION); \
$(MAKE) -f build-aux/speedo.mk this-w32-installer SELFCHECK=0;\
+ if [ -n "$(WIXPREFIX)" ]; then \
+ cd $(INST_NAME)-$(INST_VERSION); \
+ $(MAKE) -f build-aux/speedo.mk this-w32-wixlib SELFCHECK=0;\
+ fi; \
reldate="$$(date -u +%Y-%m-%d)" ;\
exefile="$(INST_NAME)-$(INST_VERSION)_$(BUILD_DATESTR).exe" ;\
cp "PLAY/inst/$$exefile" ../.. ;\
exefile="../../$$exefile" ;\
$(call MKSWDB_commands,$${exefile},$${reldate}); \
+ msifile="$(INST_NAME)-$(INST_VERSION)_$(BUILD_DATESTR).wixlib"; \
+ if [ -e "$${msifile}" ]; then \
+ cp "PLAY/inst/$$msifile" ../..; \
+ msifile="../../$$msifile" ; \
+ $(call MKSWDB_commands,$${msifile},$${reldate}); \
+ fi \
)
# This target repeats some of the installer-from-source steps but it
@@ -1265,17 +1414,17 @@ sign-installer:
cd $(INST_NAME)-$(INST_VERSION); \
reldate="$$(date -u +%Y-%m-%d)" ;\
exefile="$(INST_NAME)-$(INST_VERSION)_$(BUILD_DATESTR).exe" ;\
+ msifile="$(INST_NAME)-$(INST_VERSION)_$(BUILD_DATESTR).wixlib ;\
echo "speedo: /*" ;\
echo "speedo: * Signing installer" ;\
- echo "speedo: * Key: $(AUTHENTICODE_KEY)";\
echo "speedo: */" ;\
- osslsigncode sign -certs $(AUTHENTICODE_CERTS)\
- -pkcs12 $(AUTHENTICODE_KEY) -askpass \
- -ts "http://timestamp.globalsign.com/scripts/timstamp.dll" \
- -h sha256 -n GnuPG -i https://gnupg.org \
- -in "PLAY/inst/$$exefile" -out "../../$$exefile" ;\
+ $(call AUTHENTICODE_sign,"PLAY/inst/$$exefile","../../$$exefile");\
exefile="../../$$exefile" ;\
+ msifile="../../$$msifile" ;\
$(call MKSWDB_commands,$${exefile},$${reldate}); \
+ if [ -e "$${msifile}" ]; then \
+ $(call MKSWDB_commands,$${msifile},$${reldate}); \
+ fi; \
echo "speedo: /*" ;\
echo "speedo: * Verification result" ;\
echo "speedo: */" ;\
diff --git a/build-aux/speedo/w32/wixlib.wxs b/build-aux/speedo/w32/wixlib.wxs
new file mode 100644
index 000000000..a92fbf6c1
--- /dev/null
+++ b/build-aux/speedo/w32/wixlib.wxs
@@ -0,0 +1,664 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- - Installer module for GnuPG on Windows using WiX -*- coding: utf-8; -*-
+ Copyright (C) 2019 g10 Code GmbH
+
+ This file is part of GnuPG.
+
+ GnuPG is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ GnuPG is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+-->
+
+<!-- Components of GnuPG
+generated with:
+heat dir "C:\GnuPG" -var var.SourceDir -cg CMP_GnuPG -dr GnuPG -g1
+and then manually edited:
+ - Changed some files that are in libexec but should be in bin on windows
+ - Change filenames of the dll.a files to .imp
+ - Changed pinentry-basic.exe to pinentry-w32.exe
+ - Added the "gpg_env_cmp"
+ - Added the "gpg_reg_cmp"
+-->
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+ <Fragment>
+ <DirectoryRef Id="DIR_GnuPG">
+ <Directory Id="dirEF4D3E0A6DFFD685C7634E46091895D9"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <ComponentGroup Id="CMP_GnuPG">
+ <Component Id="gpg_reg_cmp" Guid="7F122F29-DB6A-4DE5-9DD2-0DAF1A24A61F" Directory="dirEF4D3E0A6DFFD685C7634E46091895D9">
+ <RegistryValue Id="r_gpg4win_0" Root="HKMU" Key="Software\GnuPG" Name="Install Directory" Action="write"
+ Type="string" Value="[DIR_GnuPG]" KeyPath="yes"/>
+ </Component>
+ <Component Id="gpg_env_cmp" Guid="27C32EC9-A1D3-44E1-B2F4-4B28DE1D49CB" Directory="dirEF4D3E0A6DFFD685C7634E46091895D9" KeyPath="yes">
+ <Environment Id="env_path" Name="PATH" Action="set" System="yes" Part="last" Value="[DIR_GnuPG]bin"/>
+ </Component>
+ <Component Id="cmp066CEAEFCC5CBE9211D9560CDD8A928D" Directory="dirEF4D3E0A6DFFD685C7634E46091895D9" Guid="001FC107-D3D7-455B-BE11-B95F6B4589F7">
+ <File Id="fil4FE0B52B2DB214DE5A85EE13B4D94708" KeyPath="yes" Source="$(var.BuildDir)\README.txt"/>
+ </Component>
+ <Component Id="cmp61470F19F532AFC30F74AE2799652CD5" Directory="dirEF4D3E0A6DFFD685C7634E46091895D9" Guid="1877EDF3-23B6-4A42-A8C7-9AB19D1B63D4">
+ <File Id="fil83721933C9B66170CE8F86C39E540277" KeyPath="yes" Source="$(var.BuildDir)\VERSION"/>
+ </Component>
+ <Component Id="cmpA047B2C8287DF1A20F8977FC5862B2F1" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="A67CDD27-50B5-4BD2-9BFE-E460402EF46F">
+ <File Id="filEE6B373B4AA5B761B6A9F70711499CC1" KeyPath="yes" Source="$(var.SourceDir)\bin\dirmngr.exe"/>
+ </Component>
+ <Component Id="cmp7B127BD0DBE7CC36F6D0F9CFCE7FCA25" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="39806F99-5DC9-48C3-90A0-12B634877C03">
+ <File Id="fil3F415158125B773933CC11545A216DE1" KeyPath="yes" Source="$(var.SourceDir)\libexec\dirmngr_ldap.exe"/>
+ </Component>
+ <Component Id="cmp3B8F4C481B336EF2822290BB0E9C9B5C" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="E211E222-E13B-4015-9103-D99E955E5CBC">
+ <File Id="fil4F17D9143148344A04FF0BDD3A3BCCAE" KeyPath="yes" Source="$(var.SourceDir)\bin\gpg-agent.exe"/>
+ </Component>
+ <Component Id="cmp74961776CCC7B203F500FE261DC12F92" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="FBA2569C-554D-4C06-88FC-0FD6541B5B4B">
+ <File Id="filB82A767EB9971018C006215A9FDE77EF" KeyPath="yes" Source="$(var.SourceDir)\bin\gpg-connect-agent.exe"/>
+ </Component>
+ <Component Id="cmp6C1FB70721B208E33DB24296B93AB93F" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="FE29D2AA-3151-4421-B8C0-355F69F267A1">
+ <File Id="fil563D2C0464DCE7ECADE6E15C0FC65821" KeyPath="yes" Source="$(var.SourceDir)\libexec\gpg-preset-passphrase.exe"/>
+ </Component>
+ <Component Id="cmpB87CCF9DDCB6D9B36B92B0F9FA24FDC9" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="9BB809F3-C09B-4A1E-B52D-B68CBE59AE3B">
+ <File Id="fil8A3F9D3F6E36120B183DDF4981D84C1B" KeyPath="yes" Source="$(var.SourceDir)\libexec\gpg-wks-client.exe"/>
+ </Component>
+ <Component Id="cmpEC270B071977C15E14328A04D3BBC3E8" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="4BE9D7E7-6054-4D78-9292-4D58DBA81684">
+ <File Id="fil822B20E83B1A966BABB0574CE6611B02" KeyPath="yes" Source="$(var.SourceDir)\bin\gpg.exe"/>
+ </Component>
+ <Component Id="cmpAF601EA2DF4EFD403CBF65A0D5162912" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="28A7D50E-4BC0-4A38-8420-52C5D1EB3F55">
+ <File Id="fil00B1F6AD370147577D6F7C998ACE6121" KeyPath="yes" Source="$(var.SourceDir)\bin\gpgconf.exe"/>
+ </Component>
+ <Component Id="cmp3BA8A06E4085F542FDAA78BAFB507AD4" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="E026569F-F37A-49FC-A529-68BDE3097218">
+ <File Id="fil1A596ECA8DC19F8EC626168033269CFE" KeyPath="yes" Source="$(var.SourceDir)\libexec\gpgme-w32spawn.exe"/>
+ </Component>
+ <Component Id="cmp28685CE9EF72251E2DB49488E4F253A0" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="BC5A0A60-3E5C-4FDD-BFEC-EA0C3F370958">
+ <File Id="fil3632B0ED7374F4D2C34F884D0AB1CD55" KeyPath="yes" Source="$(var.SourceDir)\bin\gpgsm.exe"/>
+ </Component>
+ <Component Id="cmp54C435FEA8B2269F880E08CA5A5E6958" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="5221235C-B773-4FB1-8DF1-6DA0F2CB509F">
+ <File Id="fil980DF38F855EAF59B36B0E59629174C6" KeyPath="yes" Source="$(var.SourceDir)\bin\gpgtar.exe"/>
+ </Component>
+ <Component Id="cmp2D1FC2D5A2C9B057FC22A0EBE475D6C2" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="AF6741CB-C010-436E-BD56-B622EEED11D9">
+ <File Id="fil8403D82C4985B5B7EAF7365C15C2A799" KeyPath="yes" Source="$(var.SourceDir)\bin\gpgv.exe"/>
+ </Component>
+ <Component Id="cmpF92C3483916C55841364708FCE4E1773" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="A8AEC3EA-1634-43C1-B47B-1A87BC39CF6B">
+ <File Id="filEE96FA35D6EEEBB2244C7F37E619364D" KeyPath="yes" Source="$(var.SourceDir)\bin\libassuan-0.dll"/>
+ </Component>
+ <Component Id="cmp387993E51EFE71AAD3DB75D48EF2C869" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="B40F4166-2B27-4F9C-A6C5-9788042EE134">
+ <File Id="filEE39C3CE2166E1496C1618124EDBBB7E" KeyPath="yes" Source="$(var.SourceDir)\bin\libgcrypt-20.dll"/>
+ </Component>
+ <Component Id="cmpA55348E1B63D2B8001A86EBE5A88B479" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="475D7E3F-8FA7-4B68-801C-083210A63B03">
+ <File Id="filEF34E24421329153F11FC15FBA8812A0" KeyPath="yes" Source="$(var.SourceDir)\bin\libgpg-error-0.dll"/>
+ </Component>
+ <Component Id="cmpDBDFA95FDDD0A86801D39E55BF3BC868" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="5BE73ECB-4F28-4320-9ED6-1ECC2536E547">
+ <File Id="fil6AC228365277B587545F74B1089D5476" KeyPath="yes" Source="$(var.SourceDir)\bin\libgpgme-11.dll"/>
+ </Component>
+ <Component Id="cmp9304510805DD3179141F4262F000041B" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="A824D70D-80C0-45E6-8FE8-A3B316384173">
+ <File Id="filC065951849A7371A734CB3174EF3FE0E" KeyPath="yes" Source="$(var.SourceDir)\bin\libksba-8.dll"/>
+ </Component>
+ <Component Id="cmp57527A666119B7A83597EA85962DEEFD" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="8A712561-DAD0-48C8-8BED-7035BACFFF7C">
+ <File Id="filF3D2E6F605C5B15E24519F7F015480CC" KeyPath="yes" Source="$(var.SourceDir)\bin\libnpth-0.dll"/>
+ </Component>
+ <Component Id="cmpC056F063A80E93157FDD8E5EFB2CE016" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="20439DF2-C028-43DD-9BC1-482FDE51C8C5">
+ <File Id="filF97663792C6DE115203B57642F12933C" KeyPath="yes" Source="$(var.SourceDir)\bin\libsqlite3-0.dll"/>
+ </Component>
+ <Component Id="cmp1EA054F1DCA27F5E05A6BB12C0FD5037" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="C4BB5B91-A126-4E9E-9E59-194CB722E8A5">
+ <File Id="fil52E5309B19823ED3214CA9CA0F5E434D" KeyPath="yes" Source="$(var.SourceDir)\bin\pinentry-w32.exe" Name="pinentry-basic.exe"/>
+ </Component>
+ <Component Id="cmpAA05573F0D76C9310DCD01BFB4DB4305" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="66C19BF2-D4FA-4634-9ED1-1A00F683A600">
+ <File Id="fil9E22630F67B9B40257D95BADF833F086" KeyPath="yes" Source="$(var.SourceDir)\libexec\scdaemon.exe"/>
+ </Component>
+ <Component Id="cmp7C407BC67635AF8AC77E3A5834574ABB" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="409840AF-C584-4F80-BFDA-F18E011EE7BD">
+ <File Id="filA7AF69726FFAE45C70D1433D00CB88FC" KeyPath="yes" Source="$(var.SourceDir)\bin\zlib1.dll"/>
+ </Component>
+ <Component Id="cmp65E1A11E56D561E0DAB42C9A35916855" Directory="dir39F5678CDEA54A3E48058808B3D68E81" Guid="40E7AA38-7E94-4F4D-87B2-3816ADB0C42E">
+ <File Id="fil5B2ABA47FA067CDCB130F32840CFC387" KeyPath="yes" Source="$(var.SourceDir)\include\assuan.h"/>
+ </Component>
+ <Component Id="cmp3FE689F1A58AD9B69436C579C9259821" Directory="dir39F5678CDEA54A3E48058808B3D68E81" Guid="A426A94C-9A5B-498D-8409-DD08822C388B">
+ <File Id="fil387A3FD45F5E34C55EFF0DCD23F22208" KeyPath="yes" Source="$(var.SourceDir)\include\gcrypt.h"/>
+ </Component>
+ <Component Id="cmp60C98038298D866C96CD9E8B567D506E" Directory="dir39F5678CDEA54A3E48058808B3D68E81" Guid="E9EAFCE0-373A-4F8F-8804-9A478A8B3F46">
+ <File Id="fil0CA9A6FD42409FBE4DE71D8307617803" KeyPath="yes" Source="$(var.SourceDir)\include\gpg-error.h"/>
+ </Component>
+ <Component Id="cmp6DFA25F5C06C7D4378B57B4972B9ABF9" Directory="dir39F5678CDEA54A3E48058808B3D68E81" Guid="3A0D85D2-F3FA-46FC-84A3-DB5EC1E5EFFE">
+ <File Id="fil12216064300F3BD74F304FB7BBF82DF8" KeyPath="yes" Source="$(var.SourceDir)\include\gpgme.h"/>
+ </Component>
+ <Component Id="cmp24395F851942E67A35947276D2E7898E" Directory="dir39F5678CDEA54A3E48058808B3D68E81" Guid="3B75734A-329A-4ECA-BD49-6118D2AC1192">
+ <File Id="filA775AF0DD0F9ED50A0D55FF9CDE33975" KeyPath="yes" Source="$(var.SourceDir)\include\ksba.h"/>
+ </Component>
+ <Component Id="cmpA1D8400F87F838D27D13A63CA2580834" Directory="dir39F5678CDEA54A3E48058808B3D68E81" Guid="C42872EF-5741-47F2-A5BD-68B73496ED61">
+ <File Id="fil8BBD19F8D3F29F086038916A0D759B98" KeyPath="yes" Source="$(var.SourceDir)\include\npth.h"/>
+ </Component>
+ <Component Id="cmp7559C87436CE56F0C09DF9E12FE7F743" Directory="dir6694D0A4AAD84EF827096DD86D1B4FA2" Guid="85A4893D-6264-43B9-A43D-0B56F908DB7C">
+ <File Id="filB5A2BAF9AF20045FB9FB5B6DE48D00DF" KeyPath="yes" Source="$(var.SourceDir)\lib\libassuan.dll.a" Name="libassuan.imp"/>
+ </Component>
+ <Component Id="cmp902C045469438D8239D32F4D15D4DE06" Directory="dir6694D0A4AAD84EF827096DD86D1B4FA2" Guid="C3427945-C116-4359-BD23-7B158E21B641">
+ <File Id="filB9244BC5F732BC08D6E9442A1ADBE51A" KeyPath="yes" Source="$(var.SourceDir)\lib\libgcrypt.dll.a" Name="libgcrypt.imp"/>
+ </Component>
+ <Component Id="cmpF41B20B2A8CAD3CBA8917622CABACA0D" Directory="dir6694D0A4AAD84EF827096DD86D1B4FA2" Guid="591391E9-D3DD-45F2-A038-14D1B8542778">
+ <File Id="filA6EB6699DCA86B1FBE961D53E2E24440" KeyPath="yes" Source="$(var.SourceDir)\lib\libgpg-error.dll.a" Name="libgpg-error.imp"/>
+ </Component>
+ <Component Id="cmp51A12EB5E7192912DCC1637F9417A39E" Directory="dir6694D0A4AAD84EF827096DD86D1B4FA2" Guid="E15FE761-BF44-4130-B354-EBE8F6A0F5D8">
+ <File Id="fil710653D37212C7F55D9AF2FCF7189BA7" KeyPath="yes" Source="$(var.SourceDir)\lib\libgpgme.dll.a" Name="libgpgme.imp"/>
+ </Component>
+ <Component Id="cmp30558FA612DCFC9CE144A01F3B4BC87A" Directory="dir6694D0A4AAD84EF827096DD86D1B4FA2" Guid="CBC1DADD-384C-4C28-B535-DCADD5C5D958">
+ <File Id="fil972A246C4D46A8ECD31DD7C6CC4D5B58" KeyPath="yes" Source="$(var.SourceDir)\lib\libksba.dll.a" Name="libksba.imp"/>
+ </Component>
+ <Component Id="cmpB5509E83C14EE3080355A3EAF09D1C8D" Directory="dir6694D0A4AAD84EF827096DD86D1B4FA2" Guid="FEC81836-944E-4613-A498-E620B981EB04">
+ <File Id="fil0615847C26E386E0B892124531F2ABBC" KeyPath="yes" Source="$(var.SourceDir)\lib\libnpth.dll.a" Name="libnpth.imp"/>
+ </Component>
+ <Component Id="cmp909B0412FDFCFD5092D93932AF982A72" Directory="dirC2E6BF1CC65903EA3A1AD83349586122" Guid="D30E7138-0D1C-48F4-8F53-E1EC6333F610">
+ <File Id="fil322067E40CE41C36574A7CC520D75876" KeyPath="yes" Source="$(var.SourceDir)\share\doc\gnupg\examples\vsnfd.prf" Name="VS-NfD.prf"/>
+ </Component>
+ <Component Id="cmp59D652F2B6BBFD90563BF58D6CE6BE7B" Directory="dirF4B1502A83344E3C92AB58989653B465" Guid="1C51D4AF-B308-40A3-B8D8-CEDA5AB2A383">
+ <File Id="filCB1BD20C87EE88A17D7502E26268DA65" KeyPath="yes" Source="$(var.SourceDir)\share\gnupg\distsigkey.gpg"/>
+ </Component>
+ <Component Id="cmpB3614EC83F6377F9DB10BC5C5A78AA47" Directory="dirF4B1502A83344E3C92AB58989653B465" Guid="BACEBFAD-8B9A-4A40-9402-42B3D8DDFDE3">
+ <File Id="fil0E0180B133150E83BBEDA55A98F3EF53" KeyPath="yes" Source="$(var.SourceDir)\share\gnupg\sks-keyservers.netCA.pem"/>
+ </Component>
+ <Component Id="cmp546709111F313BA25B92228092A64615" Directory="dirC8F3DBB83340CAA01AAA7A2A483F2C9D" Guid="03FC08BD-E454-4F57-BC28-226C3784F391">
+ <File Id="filB3D8051BA1609D83EEA2EE794DF525CD" KeyPath="yes" Source="$(var.SourceDir)\share\locale\ca\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmp0B01FD63A8971642DB9EC8902AE64467" Directory="dir141CB5729CD460F84352D7BFBCF4386E" Guid="B67AEAE8-891E-4D08-AB1B-F2E735C0D0BB">
+ <File Id="fil811398B2F4B9063CE8B46D51462204E6" KeyPath="yes" Source="$(var.SourceDir)\share\locale\cs\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmpFEA38F2E83B626E2DB8C64EBFDD5F87F" Directory="dir141CB5729CD460F84352D7BFBCF4386E" Guid="F8ED9E6E-C30F-47BB-B17F-8A2516573271">
+ <File Id="filFABAC9AECF9EBB85C304D09AF59AF2A9" KeyPath="yes" Source="$(var.SourceDir)\share\locale\cs\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ <Component Id="cmpA1D261AF329A02C03DA43105A4870E9B" Directory="dir219EE67997F4683B56B7B40BEE76BECA" Guid="827F592D-1E65-47FF-8BFB-DC95482355AB">
+ <File Id="fil3E0196FD51F525407A0404DDD6EF9950" KeyPath="yes" Source="$(var.SourceDir)\share\locale\da\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmp9524F383B8CA244F4358210CA093CE53" Directory="dir219EE67997F4683B56B7B40BEE76BECA" Guid="9B1B3B43-FF0D-4018-B80D-2C6DFE2A8BC6">
+ <File Id="filB1426F1BBEAFE0D062117DE8B5F5EC60" KeyPath="yes" Source="$(var.SourceDir)\share\locale\da\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ <Component Id="cmp453C1B1DFFA1D3F5F77C20ABED4FB501" Directory="dirD54A193F36E233547636F2C139EE1FF4" Guid="9ED93287-D2BD-481E-A924-25420319B3A3">
+ <File Id="filBED78A4CC27F6AB64486763E8575A682" KeyPath="yes" Source="$(var.SourceDir)\share\locale\de\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmp3579BBDFDECAD8E12F0DCBB423B27BDE" Directory="dirD54A193F36E233547636F2C139EE1FF4" Guid="9AD79F61-111B-4365-ABC6-9A0D509016D5">
+ <File Id="filA78CD7B4A920A5F00F5A35EE4047DAFD" KeyPath="yes" Source="$(var.SourceDir)\share\locale\de\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ <Component Id="cmpBD95AF2DBA6797BABBD361E77D660844" Directory="dir413F01097C66B82C5F6BEC66B78FF01A" Guid="AF0381F1-27A6-4ECF-A04E-A6194470CF4A">
+ <File Id="fil5051D9DDD25D14F2072FE671D9BE4A88" KeyPath="yes" Source="$(var.SourceDir)\share\locale\el\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmpB2EE1A46945B665B245BDEAC20C07C59" Directory="dirD30F6EC4D19878BC1D4AD48D1D7B5B87" Guid="98939176-31EF-46B1-A1E8-04C741EB2E42">
+ <File Id="filF903A2E0B4F19FAB403ACB58C8A36F46" KeyPath="yes" Source="$(var.SourceDir)\share\locale\en@boldquot\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmp5E48E37FE117181CACBE2E2F8317B299" Directory="dir3BBFD6070062CD151BFE332233C479AC" Guid="F18A4CD6-5C64-43E4-961C-BF2D1520D38C">
+ <File Id="filEF5659796AD116AFB2058F362B56F1CB" KeyPath="yes" Source="$(var.SourceDir)\share\locale\en@quot\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmpAE36863359F64D5B7D0083B6F3072B2B" Directory="dirC78504765289243B95E8A367FB5AE790" Guid="FF25CA11-581A-4AC3-AA15-B09B7C70C57F">
+ <File Id="filF2B163C929DD753B4A7AE927F75B2AAA" KeyPath="yes" Source="$(var.SourceDir)\share\locale\eo\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmp58E07898FC1EABA8C96B5099DE73CE56" Directory="dirC78504765289243B95E8A367FB5AE790" Guid="25D5E4B1-0585-4011-9F43-2E8027080AE5">
+ <File Id="fil4C012DF8082F3BB8103B19C99E305785" KeyPath="yes" Source="$(var.SourceDir)\share\locale\eo\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ <Component Id="cmpCB3F1506E7156F718DB761C6A14685FE" Directory="dir5AD787E17B0242315401083D50AE9954" Guid="96A724A3-2DF0-436A-B408-9DD2CBCEF57C">
+ <File Id="fil0CE86D5A00D6BE8DB27459FD15D7CC17" KeyPath="yes" Source="$(var.SourceDir)\share\locale\es\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmpB54C2AADB54A2E3EC76B0F7E64E5D515" Directory="dir5AD787E17B0242315401083D50AE9954" Guid="12C99424-2F85-466B-B5D0-DCB530EA805F">
+ <File Id="fil79F29C03578FB1881FB72BD77C0DE911" KeyPath="yes" Source="$(var.SourceDir)\share\locale\es\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ <Component Id="cmp395184651FCD4192805C52F6CCF8F857" Directory="dir03482DEF59807192455649DD930D56F9" Guid="F2FECA4A-D7B4-455B-B46A-301A59F6537F">
+ <File Id="filDDE34C283CF00D2E00C773BBAE5E7790" KeyPath="yes" Source="$(var.SourceDir)\share\locale\et\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmp41602D9FC6BEA689FC0055C519834BC9" Directory="dir7258CFD55BE72CAA15463E0C4367D933" Guid="6850B5E4-BB31-458D-93EA-F75F11F5D3DF">
+ <File Id="filE58B5D56A326026B4F8B14A4D1EBF228" KeyPath="yes" Source="$(var.SourceDir)\share\locale\fi\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmp3B741FA3C43918B7E61B1385BA857CC5" Directory="dir80EBECAD50382115BFB3623AB7C5CABB" Guid="492A7496-CB3E-4BFE-B62B-EF29174477D6">
+ <File Id="filBCCEAD5A71A6CB99E838F38D14FD6720" KeyPath="yes" Source="$(var.SourceDir)\share\locale\fr\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmp04E88B936153B4524F20916881D87C54" Directory="dir80EBECAD50382115BFB3623AB7C5CABB" Guid="007B9CA6-2493-482E-8586-7E3B23083E55">
+ <File Id="fil36741F053CE48197E6844A8DBCD9EE5A" KeyPath="yes" Source="$(var.SourceDir)\share\locale\fr\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ <Component Id="cmpCE4A03AF9717BC3514250310A93AC516" Directory="dirB413C8D9BB72BA2ACF4475C5ED540B29" Guid="7901B164-D5C2-4A5B-958E-83CE87F9EBF3">
+ <File Id="fil392B26641E4A84053B893C71C9A8B3DA" KeyPath="yes" Source="$(var.SourceDir)\share\locale\gl\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmp40EABC79B84039E2A85BCCD27D33217C" Directory="dirAC75323D1E05EB729A23BF8CC19F6CE1" Guid="9A170067-0AAD-48FE-933D-BFA4BB5737DF">
+ <File Id="fil23841F8CEE8D77C8292145F90B4127A0" KeyPath="yes" Source="$(var.SourceDir)\share\locale\hu\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmp69E8684ED1EE085A450C3DB3E4FEC1DF" Directory="dirAC75323D1E05EB729A23BF8CC19F6CE1" Guid="27160F4D-FCE5-4286-8CE6-92DA7902121D">
+ <File Id="fil015280FE4A4A4A03BE986ED8A41496D8" KeyPath="yes" Source="$(var.SourceDir)\share\locale\hu\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ <Component Id="cmp4C11B77F811ADD2D41DB2E491925688B" Directory="dirB53C46AD0FE0B9E9F4ED6E068BDE8EBD" Guid="9B8A4557-FFF7-4FB5-86C2-230514DC57FE">
+ <File Id="filDF9BF4DA4EFC2138E35BF0886EBC08C0" KeyPath="yes" Source="$(var.SourceDir)\share\locale\id\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmpC1D2F0D1498E07D5394E670945473CDD" Directory="dir6947822B32929E5EE9E2F5BB37E33C99" Guid="9F0EA006-3C9E-4AD7-8CF1-8BC5143B5BAD">
+ <File Id="fil778D477BBD9EB473266BA40BFFC806E2" KeyPath="yes" Source="$(var.SourceDir)\share\locale\it\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmp7E5A87AA208D9D1BA7B7EC2AB884BB61" Directory="dir6947822B32929E5EE9E2F5BB37E33C99" Guid="0D1565C6-B32A-4997-928B-36E1DC604886">
+ <File Id="fil3654A2F71B3000371FF3A607EB058394" KeyPath="yes" Source="$(var.SourceDir)\share\locale\it\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ <Component Id="cmp7705EC95E7BA4142FFF90BC6A10268A6" Directory="dir0F00EB134F84CCFA6585F3AA2B092ED5" Guid="76DC6A7A-6C55-4738-8C6D-81B5EEF00680">
+ <File Id="filB514C4C69CD922C01058D9DA912A2950" KeyPath="yes" Source="$(var.SourceDir)\share\locale\ja\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmp5BA4E78E60402DE65E67F674320470A6" Directory="dir0F00EB134F84CCFA6585F3AA2B092ED5" Guid="83978CB6-0C1C-45BB-A394-8FFE7257C1D6">
+ <File Id="filFD7D0D79172CE8755D21593034699CF8" KeyPath="yes" Source="$(var.SourceDir)\share\locale\ja\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ <Component Id="cmp5A2891458CB34BEA5C6EACC1B3C4B881" Directory="dir7D7752BA12ED1126D964503F2919F42D" Guid="C871047C-759E-443D-A6CE-7AC5CED25592">
+ <File Id="filCC4AD270C5FBA0E3C96A919250019018" KeyPath="yes" Source="$(var.SourceDir)\share\locale\nb\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmpE127926655EFAB9AA602584CEB9E9D1B" Directory="dirA9625026AF72FEFB1FAD1F94501AEF83" Guid="5A4B3DE7-94E2-4265-9BA0-2AC7AFF409BA">
+ <File Id="filEF9D2291E34CF54043445C689D49DD8B" KeyPath="yes" Source="$(var.SourceDir)\share\locale\nl\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ <Component Id="cmp0D8D30445E1BB80DF1DCC38F6C8C4FB1" Directory="dir3AF4D2B9487DCDDC8A57062D4C6901EC" Guid="A85DF60D-4ABD-4649-AF8C-4F8CEC001A23">
+ <File Id="filC14FDE5CC6F0A330FB85D37C24BAB178" KeyPath="yes" Source="$(var.SourceDir)\share\locale\pl\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmpF7830AE39E55351DBB29A3D8641DDCF7" Directory="dir3AF4D2B9487DCDDC8A57062D4C6901EC" Guid="D7819086-08A0-4DFE-ACBF-806D4EF13B8F">
+ <File Id="fil14BA82E453CCF0FF276383023C69FFC6" KeyPath="yes" Source="$(var.SourceDir)\share\locale\pl\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ <Component Id="cmpE4AF04300A648AF46772477B4BCD50A9" Directory="dirD80A015C242F188C2E1454B5A4D2010E" Guid="B2AC4417-31C5-486F-B916-414298C4C311">
+ <File Id="filD0B5C04E092E0EE30E716E50ECAC72EF" KeyPath="yes" Source="$(var.SourceDir)\share\locale\pt\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmp533CEE1F897C777253CA0F688CEAD4B3" Directory="dirD80A015C242F188C2E1454B5A4D2010E" Guid="DB7493C1-9247-4F58-A4F4-C75464E1295C">
+ <File Id="filB72FA9BA953EB2E2D4985179FFACC6DC" KeyPath="yes" Source="$(var.SourceDir)\share\locale\pt\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ <Component Id="cmp4A2F6505F6FF8C55E6D589F3F661F983" Directory="dir8E149DF65F3B10EA3AD2436850623AEF" Guid="1F1258EA-A31F-4220-9E11-9968C385DEA5">
+ <File Id="filBEED76EC0BF8B09FD32ABA8EE7A3B1BA" KeyPath="yes" Source="$(var.SourceDir)\share\locale\ro\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmp35F0B761EF52F231FDCF18F90101C243" Directory="dir8E149DF65F3B10EA3AD2436850623AEF" Guid="BC99F8F6-2C26-4B0F-8295-3227D982A601">
+ <File Id="filB8B8C8B4336151105E454757B13CCEAD" KeyPath="yes" Source="$(var.SourceDir)\share\locale\ro\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ <Component Id="cmp139163DE87471A416369EF26F8CD95DE" Directory="dirEDC8B39F817DC0C264AF78A4861B98A5" Guid="A7CA5650-72CD-418F-8ABD-5C703422BF6C">
+ <File Id="fil476570A41ADB583A8EBE0E899D741C1D" KeyPath="yes" Source="$(var.SourceDir)\share\locale\ru\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmpB8918417A4AE4B54CC8327692BF86794" Directory="dirEDC8B39F817DC0C264AF78A4861B98A5" Guid="8E45AA5B-8D64-4E47-9899-D9D712D7A9B4">
+ <File Id="fil22C7ED660A4A562E2E805A54247A3A8D" KeyPath="yes" Source="$(var.SourceDir)\share\locale\ru\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ <Component Id="cmpF8B71E49E683C025CD601C29B85D4C1A" Directory="dir2E9ED3D3A42B560362582A080F2D8EB7" Guid="419A6E51-364D-49E5-9353-7E37EC7A0126">
+ <File Id="fil3CD6A360EBA3B678A69601849455308B" KeyPath="yes" Source="$(var.SourceDir)\share\locale\sk\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmp01CE203B24E5F0B3D3426CFCD6091596" Directory="dirF73F41B3426675E91A925612314E760D" Guid="097D3693-A8B3-4DFC-B0FF-D14610DB0200">
+ <File Id="fil757033D78BBF57A8700AA388B496D4B1" KeyPath="yes" Source="$(var.SourceDir)\share\locale\sr\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ <Component Id="cmp13FA2CA1F2386382384F0BFE8BD4ADB4" Directory="dirCAB2D2CE70E9126EBD48DDFEE60E7781" Guid="F47BC1D4-EDD7-4376-9F09-45150463BE8D">
+ <File Id="fil2240B649D5A4A6EFDE64D63943510803" KeyPath="yes" Source="$(var.SourceDir)\share\locale\sv\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmpE5E3020E114EB5CF185D0172FF66796D" Directory="dirCAB2D2CE70E9126EBD48DDFEE60E7781" Guid="EB6C57F3-3A35-4746-B502-B871B093DD70">
+ <File Id="filCA62F18DC52CD983C794CBB0782841F6" KeyPath="yes" Source="$(var.SourceDir)\share\locale\sv\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ <Component Id="cmp48640C4F90991656CDAB5867F14089C5" Directory="dir5D2CF7C0932EADDFECCD159795AC414C" Guid="ED13C94B-16F6-41EC-B384-A4789FFDDF1C">
+ <File Id="fil9E4D4968B6514B941ED29456945457FB" KeyPath="yes" Source="$(var.SourceDir)\share\locale\tr\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmp4551AA101DFA1C1973F11346D4FE85D8" Directory="dir13556507D1D7C34DAAA5E416583DA3BA" Guid="B4D0F8D3-624B-4D70-A860-6780C98CAF3A">
+ <File Id="filABB395BD133D2ABF362DB6322EF3E6E0" KeyPath="yes" Source="$(var.SourceDir)\share\locale\uk\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmpDC700475DBB14F58460607F4C6D7C808" Directory="dir13556507D1D7C34DAAA5E416583DA3BA" Guid="DFA12ED0-0DBB-44A3-828B-544E42848ECA">
+ <File Id="fil0A499A3437867D3591AADB00D373CFB6" KeyPath="yes" Source="$(var.SourceDir)\share\locale\uk\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ <Component Id="cmp56309B32C0E45B2040DB0FBF16C05D40" Directory="dir721ABBF14E4EE3A800878547BA5529B8" Guid="17A1D9DA-801B-4C23-B1AC-D405E9A7FB76">
+ <File Id="filCC31A85EF9124C55B9E4B83ED1190CBE" KeyPath="yes" Source="$(var.SourceDir)\share\locale\vi\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ <Component Id="cmp48AA79D88C3B058F88BAE0F89EC07964" Directory="dirB2160A461FB69C07887EEC237C628C3F" Guid="F7849778-675B-4E81-97F7-2C2BBC1A66C0">
+ <File Id="fil1B7A20D6971217F00EEF33F1CD815BF4" KeyPath="yes" Source="$(var.SourceDir)\share\locale\zh_CN\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmpDAD1E61B19B57AA9F0C18F979E2DB953" Directory="dirB2160A461FB69C07887EEC237C628C3F" Guid="1149BDED-4DB9-4D71-B904-60A41D3DC002">
+ <File Id="fil98F23973F18C7612B4EF19D180934A13" KeyPath="yes" Source="$(var.SourceDir)\share\locale\zh_CN\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ <Component Id="cmp6DE01ED3D9CF376BAE71CEF2CFBE87FA" Directory="dirBA8895851647F6285902F09081099B1C" Guid="04956C7A-BD53-4D06-8E91-C546D978E945">
+ <File Id="fil404A4C6020D045EAB28BCFB83D054DDA" KeyPath="yes" Source="$(var.SourceDir)\share\locale\zh_TW\LC_MESSAGES\gnupg2.mo"/>
+ </Component>
+ <Component Id="cmp8AA8F263229FC31A4B134E9E3B5CBD2A" Directory="dirBA8895851647F6285902F09081099B1C" Guid="0677C519-752D-448D-8D23-05CBA7B384B4">
+ <File Id="filBF66E344620143485028A132A7065F2C" KeyPath="yes" Source="$(var.SourceDir)\share\locale\zh_TW\LC_MESSAGES\libgpg-error.mo"/>
+ </Component>
+ </ComponentGroup>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir45F9BF0D9027944353D2097BEA229C4B">
+ <Directory Id="dir03482DEF59807192455649DD930D56F9" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dir0388F8EB0714C4C03EEE51D81D96767B" Name="sv"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dir05D708F44AE366B2A1B3515757353BF8" Name="pt"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir78781F0EC0F0500B48FDBEE640A12270">
+ <Directory Id="dir0F00EB134F84CCFA6585F3AA2B092ED5" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir91BE2823B1F0AFFD0216A44DE5D4EE94">
+ <Directory Id="dir13556507D1D7C34DAAA5E416583DA3BA" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dirE46249598446819F7AA7C9A2914C6D83">
+ <Directory Id="dir141CB5729CD460F84352D7BFBCF4386E" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dir17DA43D7EF00B3DBBFEE8ED3BE893755" Name="zh_TW"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dir1C070A4A8EAFE1AEDA2C3879FD9D478A" Name="pl"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dir1C59FE40E4A3D1C252E8DC21ED3FD35F" Name="sk"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dir1CE84C7F92B3B82920AFF2CB0BAD8C92" Name="fr"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dir1DDB41C9C53372E27617C37DE057F0A2" Name="en@boldquot"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dirFEC9F97E00E1DB82803BCC2C95BD967E">
+ <Directory Id="dir219EE67997F4683B56B7B40BEE76BECA" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir1C59FE40E4A3D1C252E8DC21ED3FD35F">
+ <Directory Id="dir2E9ED3D3A42B560362582A080F2D8EB7" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dirEF4D3E0A6DFFD685C7634E46091895D9">
+ <Directory Id="dir39F5678CDEA54A3E48058808B3D68E81" Name="include"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir1C070A4A8EAFE1AEDA2C3879FD9D478A">
+ <Directory Id="dir3AF4D2B9487DCDDC8A57062D4C6901EC" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dirACF0C8FF72868611C9823E3AF7C96E11">
+ <Directory Id="dir3BBFD6070062CD151BFE332233C479AC" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dir406CDA0C2AF347056FF1F29C50A512A2" Name="vi"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dirBB0EE79F9E6AB87660CAAC61EDDB7432">
+ <Directory Id="dir413F01097C66B82C5F6BEC66B78FF01A" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dir45F9BF0D9027944353D2097BEA229C4B" Name="et"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dir49983B200CB1A1C893A5BC026452B90E" Name="ro"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir7BFF80ABAF1D317F0C75F1491A11C917">
+ <Directory Id="dir4F1B7A79DBDF2C05F29C779072E6C575" Name="locale"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir75C3ECEBFB2717BED8681E7513E6AD58">
+ <Directory Id="dir5AD787E17B0242315401083D50AE9954" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dirBD37452189F56F813660FF9E60B6DA4F">
+ <Directory Id="dir5D2CF7C0932EADDFECCD159795AC414C" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dirEF4D3E0A6DFFD685C7634E46091895D9">
+ <Directory Id="dir6694D0A4AAD84EF827096DD86D1B4FA2" Name="lib"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir70DD220968FA035FF9A88BA8C6E72D41">
+ <Directory Id="dir6947822B32929E5EE9E2F5BB37E33C99" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dir70DD220968FA035FF9A88BA8C6E72D41" Name="it"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir406CDA0C2AF347056FF1F29C50A512A2">
+ <Directory Id="dir721ABBF14E4EE3A800878547BA5529B8" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dirD00B86267339B6DD4ABBD3CE21ABF020">
+ <Directory Id="dir7258CFD55BE72CAA15463E0C4367D933" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dir73F71F2B5EA5C0BEE7C1AC62BC1CDD00" Name="hu"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dir75C3ECEBFB2717BED8681E7513E6AD58" Name="es"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dir78781F0EC0F0500B48FDBEE640A12270" Name="ja"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dir7A5947AF5A504DECDE3201037F256CB1" Name="de"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dirEF4D3E0A6DFFD685C7634E46091895D9">
+ <Directory Id="dir7BFF80ABAF1D317F0C75F1491A11C917" Name="share"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dirD211F027155495F926B97F997DD06573">
+ <Directory Id="dir7D7752BA12ED1126D964503F2919F42D" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir1CE84C7F92B3B82920AFF2CB0BAD8C92">
+ <Directory Id="dir80EBECAD50382115BFB3623AB7C5CABB" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dir837961AB354A543B79D765904301D522" Name="eo"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dir8D24EE6C11C3CBEC565C048AF1E690E8" Name="id"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir49983B200CB1A1C893A5BC026452B90E">
+ <Directory Id="dir8E149DF65F3B10EA3AD2436850623AEF" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dir91BE2823B1F0AFFD0216A44DE5D4EE94" Name="uk"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dirA58838A162DA815C458A68D5A3A53B58">
+ <Directory Id="dir926A54C6CC889938C4091ECCB93FB640" Name="gnupg"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir7BFF80ABAF1D317F0C75F1491A11C917">
+ <Directory Id="dirA58838A162DA815C458A68D5A3A53B58" Name="doc"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dirE2D6A167979D9DAF78E0DC18293E05DD">
+ <Directory Id="dirA9625026AF72FEFB1FAD1F94501AEF83" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dirEF4D3E0A6DFFD685C7634E46091895D9">
+ <Directory Id="dirAA72FFDDFA224FB221D53750596B0142" Name="bin"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir73F71F2B5EA5C0BEE7C1AC62BC1CDD00">
+ <Directory Id="dirAC75323D1E05EB729A23BF8CC19F6CE1" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dirACF0C8FF72868611C9823E3AF7C96E11" Name="en@quot"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dirCC1090D8BE2128FA3CA703FAD54F41A0">
+ <Directory Id="dirB2160A461FB69C07887EEC237C628C3F" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dirE7E0782B19315880FE9BD84AF1682721">
+ <Directory Id="dirB413C8D9BB72BA2ACF4475C5ED540B29" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir8D24EE6C11C3CBEC565C048AF1E690E8">
+ <Directory Id="dirB53C46AD0FE0B9E9F4ED6E068BDE8EBD" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir17DA43D7EF00B3DBBFEE8ED3BE893755">
+ <Directory Id="dirBA8895851647F6285902F09081099B1C" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dirBB0EE79F9E6AB87660CAAC61EDDB7432" Name="el"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dirBD37452189F56F813660FF9E60B6DA4F" Name="tr"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir926A54C6CC889938C4091ECCB93FB640">
+ <Directory Id="dirC2E6BF1CC65903EA3A1AD83349586122" Name="examples"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir837961AB354A543B79D765904301D522">
+ <Directory Id="dirC78504765289243B95E8A367FB5AE790" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dirD39E83202D907BF20C7103C263E10E78">
+ <Directory Id="dirC8F3DBB83340CAA01AAA7A2A483F2C9D" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir0388F8EB0714C4C03EEE51D81D96767B">
+ <Directory Id="dirCAB2D2CE70E9126EBD48DDFEE60E7781" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dirCC1090D8BE2128FA3CA703FAD54F41A0" Name="zh_CN"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dirD00B86267339B6DD4ABBD3CE21ABF020" Name="fi"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dirD14BA95A8404FE8F595737D4EB6D0ECC" Name="ru"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dirD211F027155495F926B97F997DD06573" Name="nb"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir1DDB41C9C53372E27617C37DE057F0A2">
+ <Directory Id="dirD30F6EC4D19878BC1D4AD48D1D7B5B87" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dirD39E83202D907BF20C7103C263E10E78" Name="ca"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir7A5947AF5A504DECDE3201037F256CB1">
+ <Directory Id="dirD54A193F36E233547636F2C139EE1FF4" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir05D708F44AE366B2A1B3515757353BF8">
+ <Directory Id="dirD80A015C242F188C2E1454B5A4D2010E" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dirE2D6A167979D9DAF78E0DC18293E05DD" Name="nl"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dirE46249598446819F7AA7C9A2914C6D83" Name="cs"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dirE62A81CFBBCD8D97197ABD459F171516" Name="sr"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dirE7E0782B19315880FE9BD84AF1682721" Name="gl"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dirD14BA95A8404FE8F595737D4EB6D0ECC">
+ <Directory Id="dirEDC8B39F817DC0C264AF78A4861B98A5" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir7BFF80ABAF1D317F0C75F1491A11C917">
+ <Directory Id="dirF4B1502A83344E3C92AB58989653B465" Name="gnupg"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dirE62A81CFBBCD8D97197ABD459F171516">
+ <Directory Id="dirF73F41B3426675E91A925612314E760D" Name="LC_MESSAGES"/>
+ </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <DirectoryRef Id="dir4F1B7A79DBDF2C05F29C779072E6C575">
+ <Directory Id="dirFEC9F97E00E1DB82803BCC2C95BD967E" Name="da"/>
+ </DirectoryRef>
+ </Fragment>
+</Wix>
diff --git a/common/asshelp.c b/common/asshelp.c
index 174933a83..83c378786 100644
--- a/common/asshelp.c
+++ b/common/asshelp.c
@@ -527,8 +527,18 @@ start_new_service (assuan_context_t *r_ctx,
if (!(err = lock_spawning (&lock, gnupg_homedir (), lock_name, verbose))
&& assuan_socket_connect (ctx, sockname, 0, connect_flags))
{
+#ifdef HAVE_W32_SYSTEM
err = gnupg_spawn_process_detached (program? program : program_name,
argv, NULL);
+#else /*!W32*/
+ pid_t pid;
+
+ err = gnupg_spawn_process_fd (program? program : program_name,
+ argv, -1, -1, -1, &pid);
+ if (!err)
+ err = gnupg_wait_process (program? program : program_name,
+ pid, 1, NULL);
+#endif /*!W32*/
if (err)
log_error ("failed to start %s '%s': %s\n",
printed_name, program? program : program_name,
@@ -640,7 +650,7 @@ start_new_dirmngr (assuan_context_t *r_ctx,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg)
{
-#ifdef USE_DIRMNGR_AUTO_START
+#ifndef USE_DIRMNGR_AUTO_START
autostart = 0;
#endif
return start_new_service (r_ctx, GNUPG_MODULE_NAME_DIRMNGR,
diff --git a/common/name-value.c b/common/name-value.c
index 989a5b111..f663ecfe1 100644
--- a/common/name-value.c
+++ b/common/name-value.c
@@ -195,11 +195,11 @@ assert_raw_value (nve_t entry)
size_t i;
/* Find a suitable space to break on. */
- for (i = linelen - 1; linelen - i < 30 && linelen - i > offset; i--)
- if (ascii_isspace (entry->value[i]))
+ for (i = linelen - 1; linelen - i < 30; i--)
+ if (ascii_isspace (entry->value[offset+i]))
break;
- if (ascii_isspace (entry->value[i]))
+ if (ascii_isspace (entry->value[offset+i]))
{
/* Found one. */
amount = i;
diff --git a/common/openpgpdefs.h b/common/openpgpdefs.h
index 2f7ff456e..868e141ce 100644
--- a/common/openpgpdefs.h
+++ b/common/openpgpdefs.h
@@ -119,6 +119,8 @@ typedef enum
SIGSUBPKT_ISSUER_FPR = 33, /* Issuer fingerprint. */
SIGSUBPKT_PREF_AEAD = 34, /* Preferred AEAD algorithms. */
+ SIGSUBPKT_ATTST_SIGS = 37, /* Attested Certifications. */
+
SIGSUBPKT_FLAG_CRITICAL = 128
}
sigsubpkttype_t;
diff --git a/common/sysutils.c b/common/sysutils.c
index 0a3dc2eaf..f2abd924e 100644
--- a/common/sysutils.c
+++ b/common/sysutils.c
@@ -380,7 +380,7 @@ translate_sys2libc_fd (gnupg_fd_t fd, int for_write)
/* Note that _open_osfhandle is currently defined to take and return
a long. */
- x = _open_osfhandle ((long)fd, for_write ? 1 : 0);
+ x = _open_osfhandle ((intptr_t)fd, for_write ? 1 : 0);
if (x == -1)
log_error ("failed to translate osfhandle %p\n", (void *) fd);
return x;
@@ -511,7 +511,7 @@ gnupg_tmpfile (void)
int fd = (int)file;
fp = _wfdopen (fd, L"w+b");
#else
- int fd = _open_osfhandle ((long)file, 0);
+ int fd = _open_osfhandle ((intptr_t)file, 0);
if (fd == -1)
{
CloseHandle (file);
diff --git a/configure.ac b/configure.ac
index f18e7a26e..5bb366e76 100644
--- a/configure.ac
+++ b/configure.ac
@@ -810,7 +810,26 @@ AM_PATH_GPG_ERROR("$NEED_GPG_ERROR_VERSION",
#
AM_PATH_LIBGCRYPT("$NEED_LIBGCRYPT_API:$NEED_LIBGCRYPT_VERSION",
have_libgcrypt=yes,have_libgcrypt=no)
-
+# And, then, check if it's newer than 1.9.0.
+have_libgcrypt_newer=no
+if test $ok = yes; then
+ if test "$major" -gt 1; then
+ have_libgcrypt_newer=yes
+ else
+ if test "$major" -eq 1; then
+ if test "$minor" -gt 9; then
+ have_libgcrypt_newer=yes
+ else
+ if test "$minor" -eq 9; then
+ if test "$micro" -ge 0; then
+ have_libgcrypt_newer=yes
+ fi
+ fi
+ fi
+ fi
+ fi
+fi
+AM_CONDITIONAL(HAVE_NEWER_LIBGCRYPT, [test $have_libgcrypt_newer = yes])
#
# libassuan is used for IPC
diff --git a/dirmngr/dns.c b/dirmngr/dns.c
index 142e8d2c1..2cc1c7049 100644
--- a/dirmngr/dns.c
+++ b/dirmngr/dns.c
@@ -4505,8 +4505,6 @@ struct dns_trace *dns_trace_open(FILE *fp, dns_error_t *error) {
if (fp) {
trace->fp = fp;
- } else if (!(fp = tmpfile())) {
- goto syerr;
}
trace->id = dns_trace_mkid();
diff --git a/dirmngr/http.c b/dirmngr/http.c
index 81b7ba897..8e0701fab 100644
--- a/dirmngr/http.c
+++ b/dirmngr/http.c
@@ -792,6 +792,8 @@ http_session_new (http_session_t *r_session,
pemname, gnutls_strerror (rc));
xfree (pemname);
}
+
+ add_system_cas = 0;
}
/* Add configured certificates to the session. */
diff --git a/doc/DETAILS b/doc/DETAILS
index 0610108f4..315f56e31 100644
--- a/doc/DETAILS
+++ b/doc/DETAILS
@@ -177,8 +177,9 @@ described here.
Signature class as per RFC-4880. This is a 2 digit hexnumber
followed by either the letter 'x' for an exportable signature or
the letter 'l' for a local-only signature. The class byte of an
- revocation key is also given here, 'x' and 'l' is used the same
- way. This field if not used for X.509.
+ revocation key is also given here, by a 2 digit hexnumber and
+ optionally followed by the letter 's' for the "sensitive"
+ flag. This field is not used for X.509.
"rev" and "rvs" may be followed by a comma and a 2 digit hexnumber
with the revocation reason.
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 0c44217d0..541c2fc20 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -46,6 +46,7 @@ profiles =
EXTRA_DIST = samplekeys.asc mksamplekeys com-certs.pem \
gnupg-logo.eps gnupg-logo.pdf gnupg-logo.png gnupg-logo-tr.png \
gnupg-module-overview.png gnupg-module-overview.pdf \
+ gnupg-module-overview.eps gnupg-card-architecture.eps \
gnupg-card-architecture.png gnupg-card-architecture.pdf \
FAQ gnupg7.texi mkdefsinc.c defsincdate \
opt-homedir.texi see-also-note.texi specify-user-id.texi \
@@ -53,6 +54,7 @@ EXTRA_DIST = samplekeys.asc mksamplekeys com-certs.pem \
trust-values.texi
BUILT_SOURCES = gnupg-module-overview.png gnupg-module-overview.pdf \
+ gnupg-module-overview.eps gnupg-card-architecture.eps \
gnupg-card-architecture.png gnupg-card-architecture.pdf \
defsincdate defs.inc
@@ -110,8 +112,6 @@ watchgnupg_SOURCE = gnupg.texi
CLEANFILES = yat2m mkdefsinc defs.inc
DISTCLEANFILES = gnupg.tmp gnupg.ops yat2m-stamp.tmp yat2m-stamp \
- gnupg-card-architecture.eps \
- gnupg-module-overview.eps \
$(myman_pages) gnupg.7
yat2m: yat2m.c
diff --git a/doc/debugging.texi b/doc/debugging.texi
index 42a1a159e..6639e184b 100644
--- a/doc/debugging.texi
+++ b/doc/debugging.texi
@@ -38,10 +38,8 @@ and solving problems.
A keybox is a file format used to store public keys along with meta
information and indices. The commonly used one is the file
-@file{pubring.kbx} in the @file{.gnupg} directory. It contains all
-X.509 certificates as well as OpenPGP keys@footnote{Well, OpenPGP keys
-are not implemented, @command{gpg} still used the keyring file
-@file{pubring.gpg}.}.
+@file{pubring.kbx} in the @file{.gnupg} directory. It contains all
+X.509 certificates as well as OpenPGP keys.
@noindent
When called the standard way, e.g.:
@@ -287,5 +285,3 @@ use of a smartcard:
@caption{GnuPG card architecture}
@center @image{gnupg-card-architecture, 150mm,, GnuPG card architecture}
@end float
-
-
diff --git a/doc/dirmngr.texi b/doc/dirmngr.texi
index eb49ad96c..eb9a92160 100644
--- a/doc/dirmngr.texi
+++ b/doc/dirmngr.texi
@@ -198,11 +198,11 @@ however carefully selected to best aid in debugging.
@item --debug @var{flags}
@opindex debug
-Set debugging flags. This option is only useful for debugging and its
-behavior may change with a new release. All flags are or-ed and may
-be given in C syntax (e.g. 0x0042) or as a comma separated list of
-flag names. To get a list of all supported flags the single word
-"help" can be used.
+Set debug flags. All flags are or-ed and @var{flags} may be given in
+C syntax (e.g. 0x0042) or as a comma separated list of flag names. To
+get a list of all supported flags the single word "help" can be used.
+This option is only useful for debugging and the behavior may change
+at any time without notice.
@item --debug-all
@opindex debug-all
diff --git a/doc/gpg-agent.texi b/doc/gpg-agent.texi
index d518c246b..9d0dcea6c 100644
--- a/doc/gpg-agent.texi
+++ b/doc/gpg-agent.texi
@@ -256,30 +256,11 @@ however carefully selected to best aid in debugging.
@item --debug @var{flags}
@opindex debug
-This option is only useful for debugging and the behavior may change at
-any time without notice. FLAGS are bit encoded and may be given in
-usual C-Syntax. The currently defined bits are:
-
-@table @code
-@item 0 (1)
-X.509 or OpenPGP protocol related data
-@item 1 (2)
-values of big number integers
-@item 2 (4)
-low level crypto operations
-@item 5 (32)
-memory allocation
-@item 6 (64)
-caching
-@item 7 (128)
-show memory statistics
-@item 9 (512)
-write hashed data to files named @code{dbgmd-000*}
-@item 10 (1024)
-trace Assuan protocol
-@item 12 (4096)
-bypass all certificate validation
-@end table
+Set debug flags. All flags are or-ed and @var{flags} may be given
+in C syntax (e.g. 0x0042) or as a comma separated list of flag names.
+To get a list of all supported flags the single word "help" can be
+used. This option is only useful for debugging and the behavior may
+change at any time without notice.
@item --debug-all
@opindex debug-all
@@ -1491,7 +1472,7 @@ Incremented with any change of any of the other counters.
@item KEY
Incremented for added or removed private keys.
@item CARD
-Incremented for changes of the card readers stati.
+Incremented for each change of the card reader's status.
@end table
@node Agent GETINFO
diff --git a/doc/gpg.texi b/doc/gpg.texi
index 80c7f48f5..fe9e0bfbe 100644
--- a/doc/gpg.texi
+++ b/doc/gpg.texi
@@ -198,7 +198,7 @@ Make a detached signature.
@opindex encrypt
Encrypt data to one or more public keys. This command may be combined
with @option{--sign} (to sign and encrypt a message),
-@option{--symmetric} (to encrypt a message that can decrypted using a
+@option{--symmetric} (to encrypt a message that can be decrypted using a
secret key or a passphrase), or @option{--sign} and
@option{--symmetric} together (for a signed message that can be
decrypted using a secret key or a passphrase). @option{--recipient}
@@ -683,6 +683,15 @@ supplied passphrase is used for the new key and the agent does not ask
for it. To create a key without any protection @code{--passphrase ''}
may be used.
+To create an OpenPGP key from the keys available on the currently
+inserted smartcard, the special string ``card'' can be used for
+@var{algo}. If the card features an encryption and a signing key, gpg
+will figure them out and creates an OpenPGP key consisting of the
+usual primary key and one subkey. This works only with certain
+smartcards. Note that the interactive @option{--full-gen-key} command
+allows to do the same but with greater flexibility in the selection of
+the smartcard keys.
+
Note that it is possible to create a primary key and a subkey using
non-default algorithms by using ``default'' and changing the default
parameters using the option @option{--default-new-key-algo}.
@@ -1091,7 +1100,7 @@ Directly sign a key from the passphrase without any further user
interaction. The @var{fpr} must be the verified primary fingerprint
of a key in the local keyring. If no @var{names} are given, all
useful user ids are signed; with given [@var{names}] only useful user
-ids matching one of theses names are signed. By default, or if a name
+ids matching one of these names are signed. By default, or if a name
is prefixed with a '*', a case insensitive substring match is used.
If a name is prefixed with a '=' a case sensitive exact match is done.
@@ -2885,10 +2894,11 @@ however carefully selected to best aid in debugging.
@item --debug @var{flags}
@opindex debug
-Set debugging flags. All flags are or-ed and @var{flags} may be given
+Set debug flags. All flags are or-ed and @var{flags} may be given
in C syntax (e.g. 0x0042) or as a comma separated list of flag names.
To get a list of all supported flags the single word "help" can be
-used.
+used. This option is only useful for debugging and the behavior may
+change at any time without notice.
@item --debug-all
@opindex debug-all
@@ -3516,6 +3526,13 @@ file and returns with failure if the configuration file would prevent
@command{@gpgname} from startup. Thus it may be used to run a syntax check
on the configuration file.
+@c @item --use-only-openpgp-card
+@c @opindex use-only-openpgp-card
+@c Only access OpenPGP card's and no other cards. This is a hidden
+@c option which could be used in case an old use case required the
+@c OpenPGP card while several cards are avaiable. This option might be
+@c removed if it turns out that nobody requires it.
+
@end table
@c *******************************
@@ -3655,7 +3672,7 @@ files; They all live in the current home directory (@pxref{option
certificates. The file name corresponds to the OpenPGP fingerprint of
the respective key. It is suggested to backup those certificates and
if the primary private key is not stored on the disk to move them to
- an external storage device. Anyone who can access theses files is
+ an external storage device. Anyone who can access these files is
able to revoke the corresponding key. You may want to print them out.
You should backup all files in this directory and take care to keep
this backup closed away.
diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi
index 75ccdc3ba..ecc43cd3c 100644
--- a/doc/gpgsm.texi
+++ b/doc/gpgsm.texi
@@ -224,7 +224,7 @@ mainly for debugging.
@item --keydb-clear-some-cert-flags
@opindex keydb-clear-some-cert-flags
This is a debugging aid to reset certain flags in the key database
-which are used to cache certain certificate stati. It is especially
+which are used to cache certain certificate statuses. It is especially
useful if a bad CRL or a weird running OCSP responder did accidentally
revoke certificate. There is no security issue with this command
because @command{gpgsm} always make sure that the validity of a certificate is
@@ -688,29 +688,11 @@ however carefully selected to best aid in debugging.
@item --debug @var{flags}
@opindex debug
-This option is only useful for debugging and the behaviour may change
-at any time without notice; using @code{--debug-levels} is the
-preferred method to select the debug verbosity. FLAGS are bit encoded
-and may be given in usual C-Syntax. The currently defined bits are:
-
-@table @code
-@item 0 (1)
-X.509 or OpenPGP protocol related data
-@item 1 (2)
-values of big number integers
-@item 2 (4)
-low level crypto operations
-@item 5 (32)
-memory allocation
-@item 6 (64)
-caching
-@item 7 (128)
-show memory statistics
-@item 9 (512)
-write hashed data to files named @code{dbgmd-000*}
-@item 10 (1024)
-trace Assuan protocol
-@end table
+Set debug flags. All flags are or-ed and @var{flags} may be given
+in C syntax (e.g. 0x0042) or as a comma separated list of flag names.
+To get a list of all supported flags the single word "help" can be
+used. This option is only useful for debugging and the behavior may
+change at any time without notice.
Note, that all flags set using this option may get overridden by
@code{--debug-level}.
diff --git a/doc/help.txt b/doc/help.txt
index 38f25cd3e..4d748c4e7 100644
--- a/doc/help.txt
+++ b/doc/help.txt
@@ -133,6 +133,14 @@ encryption. This algorithm should only be used in certain domains.
Please consult your security expert first.
.
+.gpg.keygen.cardkey
+Select which key from the card shall be used.
+
+The listing shows the selection index, the keygrip (a string of hex
+digits), the card specific key reference, the algorithm used for this
+key, and in parentheses the usage of the key (cert, sign, auth, encr).
+If known the standard usage for a key is marked with an asterisk.
+.
.gpg.keygen.flags
Toggle the capabilities of the key.
diff --git a/doc/scdaemon.texi b/doc/scdaemon.texi
index 21c3fd826..c1ca443b9 100644
--- a/doc/scdaemon.texi
+++ b/doc/scdaemon.texi
@@ -160,33 +160,11 @@ helpers to debug problems.
@item --debug @var{flags}
@opindex debug
-This option is only useful for debugging and the behavior may change at
-any time without notice. FLAGS are bit encoded and may be given in
-usual C-Syntax. The currently defined bits are:
-
-@table @code
-@item 0 (1)
-command I/O
-@item 1 (2)
-values of big number integers
-@item 2 (4)
-low level crypto operations
-@item 5 (32)
-memory allocation
-@item 6 (64)
-caching
-@item 7 (128)
-show memory statistics
-@item 9 (512)
-write hashed data to files named @code{dbgmd-000*}
-@item 10 (1024)
-trace Assuan protocol.
-See also option @option{--debug-assuan-log-cats}.
-@item 11 (2048)
-trace APDU I/O to the card. This may reveal sensitive data.
-@item 12 (4096)
-trace some card reader related function calls.
-@end table
+Set debug flags. All flags are or-ed and @var{flags} may be given
+in C syntax (e.g. 0x0042) or as a comma separated list of flag names.
+To get a list of all supported flags the single word "help" can be
+used. This option is only useful for debugging and the behavior may
+change at any time without notice.
@item --debug-all
@opindex debug-all
diff --git a/doc/wks.texi b/doc/wks.texi
index 9f1fff2a8..d6f442dfc 100644
--- a/doc/wks.texi
+++ b/doc/wks.texi
@@ -260,7 +260,7 @@ Display a brief help page and exit.
@end ifset
@mansect description
-The @command{gpg-wks-server} is a server site implementation of the
+The @command{gpg-wks-server} is a server side implementation of the
Web Key Service. It receives requests for publication, sends
confirmation requests, receives confirmations, and published the key.
It also has features to ease the setup and maintenance of a Web Key
@@ -268,7 +268,7 @@ Directory.
When used with the command @option{--receive} a single Web Key Service
mail is processed. Commonly this command is used with the option
-@option{--send} to directly send the crerated mails back. See below
+@option{--send} to directly send the created mails back. See below
for an installation example.
The command @option{--cron} is used for regular cleanup tasks. For
@@ -400,7 +400,7 @@ be the same address for all configured domains, for example:
$ echo key-submission@@example.net >submission-address
@end example
-The protocol requires that the key to be published is send with an
+The protocol requires that the key to be published is sent with an
encrypted mail to the service. Thus you need to create a key for
the submission address:
diff --git a/g10/Makefile.am b/g10/Makefile.am
index fd2cd21b9..2b92daf33 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -99,6 +99,7 @@ common_source = \
filter.h \
free-packet.c \
getkey.c \
+ expand-group.c \
keydb.h \
keydb-private.h \
call-keyboxd.c \
diff --git a/g10/build-packet.c b/g10/build-packet.c
index 2a95df694..865f2b500 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -1527,7 +1527,7 @@ sig_to_notation(PKT_signature *sig)
- n1 bytes of name data
- n2 bytes of value data
*/
- while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION,&len,&seq,&crit)))
+ while((p=enum_sig_subpkt (sig, 1, SIGSUBPKT_NOTATION, &len, &seq, &crit)))
{
int n1,n2;
struct notation *n=NULL;
diff --git a/g10/call-agent.c b/g10/call-agent.c
index 19deb73d7..9e510ae98 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -367,7 +367,9 @@ start_agent (ctrl_t ctrl, int flag_for_card)
if (!(flag_for_card & FLAG_FOR_CARD_SUPPRESS_ERRORS))
rc = warn_version_mismatch (agent_ctx, SCDAEMON_NAME, 2);
if (!rc)
- rc = assuan_transact (agent_ctx, "SCD SERIALNO",
+ rc = assuan_transact (agent_ctx,
+ opt.flags.use_only_openpgp_card?
+ "SCD SERIALNO openpgp" : "SCD SERIALNO",
NULL, NULL, NULL, NULL,
learn_status_cb, &info);
if (rc && !(flag_for_card & FLAG_FOR_CARD_SUPPRESS_ERRORS))
@@ -740,7 +742,15 @@ learn_status_cb (void *opaque, const char *line)
}
else if (keywordlen == 3 && !memcmp (keyword, "KDF", 3))
{
- parm->kdf_do_enabled = 1;
+ unsigned char *data = unescape_status_string (line);
+
+ if (data[2] != 0x03)
+ parm->kdf_do_enabled = 0;
+ else if (data[22] != 0x85)
+ parm->kdf_do_enabled = 1;
+ else
+ parm->kdf_do_enabled = 2;
+ xfree (data);
}
else if (keywordlen == 5 && !memcmp (keyword, "UIF-", 4)
&& strchr("123", keyword[4]))
@@ -2315,25 +2325,28 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
return err;
}
- put_membuf (&data, "", 1); /* Make sure it is 0 terminated. */
buf = get_membuf (&data, &len);
if (!buf)
return gpg_error_from_syserror ();
- log_assert (len); /* (we forced Nul termination.) */
- if (*buf != '(')
+ if (len == 0 || *buf != '(')
{
xfree (buf);
return gpg_error (GPG_ERR_INV_SEXP);
}
- if (len < 13 || memcmp (buf, "(5:value", 8) ) /* "(5:valueN:D)\0" */
+ if (len < 12 || memcmp (buf, "(5:value", 8) ) /* "(5:valueN:D)" */
{
xfree (buf);
return gpg_error (GPG_ERR_INV_SEXP);
}
- len -= 10; /* Count only the data of the second part. */
+ while (buf[len-1] == 0)
+ len--;
+ if (buf[len-1] != ')')
+ return gpg_error (GPG_ERR_INV_SEXP);
+ len--; /* Drop the final close-paren. */
p = buf + 8; /* Skip leading parenthesis and the value tag. */
+ len -= 8; /* Count only the data of the second part. */
n = strtoul (p, &endp, 10);
if (!n || *endp != ':')
diff --git a/g10/call-agent.h b/g10/call-agent.h
index c4d0a9de1..5512fc847 100644
--- a/g10/call-agent.h
+++ b/g10/call-agent.h
@@ -72,7 +72,7 @@ struct agent_card_info_s
unsigned int bt:1; /* Button for confirmation available. */
} extcap;
unsigned int status_indicator;
- int kdf_do_enabled; /* True if card has a KDF object. */
+ int kdf_do_enabled; /* Non-zero if card has a KDF object, 0 if not. */
int uif[3]; /* True if User Interaction Flag is on. */
};
diff --git a/g10/card-util.c b/g10/card-util.c
index 1b9461e0a..78699914f 100644
--- a/g10/card-util.c
+++ b/g10/card-util.c
@@ -521,7 +521,16 @@ current_card_status (ctrl_t ctrl, estream_t fp,
es_fprintf (fp, "sigcount:%lu:::\n", info.sig_counter);
if (info.extcap.kdf)
{
- es_fprintf (fp, "kdf:%s:\n", info.kdf_do_enabled ? "on" : "off");
+ const char *setup;
+
+ if (info.kdf_do_enabled == 0)
+ setup = "off";
+ else if (info.kdf_do_enabled == 1)
+ setup = "single";
+ else
+ setup = "on";
+
+ es_fprintf (fp, "kdf:%s:\n", setup);
}
if (info.extcap.bt)
{
@@ -578,7 +587,7 @@ current_card_status (ctrl_t ctrl, estream_t fp,
print_name (fp, "Language prefs ...: ", info.disp_lang);
tty_fprintf (fp, "Salutation .......: %s\n",
info.disp_sex == 1? _("Mr."):
- info.disp_sex == 2? _("Mrs.") : "");
+ info.disp_sex == 2? _("Ms.") : "");
print_name (fp, "URL of public key : ", info.pubkey_url);
print_name (fp, "Login data .......: ", info.login_data);
if (info.private_do[0])
@@ -636,8 +645,16 @@ current_card_status (ctrl_t ctrl, estream_t fp,
tty_fprintf (fp, "Signature counter : %lu\n", info.sig_counter);
if (info.extcap.kdf)
{
- tty_fprintf (fp, "KDF setting ......: %s\n",
- info.kdf_do_enabled ? "on" : "off");
+ const char *setup;
+
+ if (info.kdf_do_enabled == 0)
+ setup = "off";
+ else if (info.kdf_do_enabled == 1)
+ setup = "single";
+ else
+ setup = "on";
+
+ tty_fprintf (fp, "KDF setting ......: %s\n", setup);
}
if (info.extcap.bt)
{
@@ -1160,7 +1177,7 @@ change_sex (void)
int rc;
data = cpr_get ("cardedit.change_sex",
- _("Salutation (M = Mr., F = Mrs., or space): "));
+ _("Salutation (M = Mr., F = Ms., or space): "));
if (!data)
return -1;
trim_spaces (data);
@@ -2103,7 +2120,7 @@ kdf_setup (const char *args)
struct agent_card_info_s info;
gpg_error_t err;
unsigned char kdf_data[KDF_DATA_LENGTH_MAX];
- int single = (*args != 0);
+ size_t len;
memset (&info, 0, sizeof info);
@@ -2120,12 +2137,25 @@ kdf_setup (const char *args)
goto leave;
}
- err = gen_kdf_data (kdf_data, single);
- if (err)
- goto leave_error;
+ if (!strcmp (args, "off"))
+ {
+ len = 5;
+ memcpy (kdf_data, "\xF9\x03\x81\x01\x00", len);
+ }
+ else
+ {
+ int single = 0;
+
+ if (*args != 0)
+ single = 1;
+
+ len = single ? KDF_DATA_LENGTH_MIN: KDF_DATA_LENGTH_MAX;
+ err = gen_kdf_data (kdf_data, single);
+ if (err)
+ goto leave_error;
+ }
- err = agent_scd_setattr ("KDF", kdf_data,
- single ? KDF_DATA_LENGTH_MIN : KDF_DATA_LENGTH_MAX);
+ err = agent_scd_setattr ("KDF", kdf_data, len);
if (err)
goto leave_error;
@@ -2225,7 +2255,8 @@ static struct
{ "verify" , cmdVERIFY, 0, N_("verify the PIN and list all data")},
{ "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code")},
{ "factory-reset", cmdFACTORYRESET, 1, N_("destroy all keys and data")},
- { "kdf-setup", cmdKDFSETUP, 1, N_("setup KDF for PIN authentication")},
+ { "kdf-setup", cmdKDFSETUP, 1,
+ N_("setup KDF for PIN authentication (on/single/off)")},
{ "key-attr", cmdKEYATTR, 1, N_("change the key attribute")},
{ "uif", cmdUIF, 1, N_("change the User Interaction Flag")},
/* Note, that we do not announce these command yet. */
diff --git a/g10/dek.h b/g10/dek.h
index 1e861f565..88f8bc5f7 100644
--- a/g10/dek.h
+++ b/g10/dek.h
@@ -30,16 +30,16 @@ typedef struct
/* Whether we've already printed information about this key. This
* is currently only used in decrypt_data() and only if we are in
* verbose mode. */
- int algo_info_printed : 1;
+ unsigned int algo_info_printed : 1;
/* AEAD shall be used. The value is the AEAD algo. */
int use_aead : 4;
/* MDC shall be used. */
- int use_mdc : 1;
+ unsigned int use_mdc : 1;
/* This key was read from a SK-ESK packet (see proc_symkey_enc). */
- int symmetric : 1;
+ unsigned int symmetric : 1;
/* This is the largest used keylen (256 bit). */
byte key[32];
diff --git a/g10/exec.c b/g10/exec.c
index 3e5dc278b..f63904b39 100644
--- a/g10/exec.c
+++ b/g10/exec.c
@@ -17,64 +17,29 @@
* along with this program; if not, see <https://www.gnu.org/licenses/>.
*/
-/*
- FIXME: We should replace most code in this module by our
- spawn implementation from common/exechelp.c.
- */
-
-
#include <config.h>
#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#ifndef EXEC_TEMPFILE_ONLY
-#include <sys/wait.h>
-#endif
#ifdef HAVE_DOSISH_SYSTEM
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
# endif
# include <windows.h>
#endif
-#include <fcntl.h>
-#include <unistd.h>
#include <string.h>
-#include <errno.h>
#include "gpg.h"
#include "options.h"
#include "../common/i18n.h"
-#include "../common/iobuf.h"
-#include "../common/util.h"
-#include "../common/membuf.h"
-#include "../common/sysutils.h"
#include "exec.h"
#ifdef NO_EXEC
-int
-exec_write(struct exec_info **info,const char *program,
- const char *args_in,const char *name,int writeonly,int binary)
-{
- log_error(_("no remote program execution supported\n"));
- return GPG_ERR_GENERAL;
-}
-
-int
-exec_read(struct exec_info *info) { return GPG_ERR_GENERAL; }
-int
-exec_finish(struct exec_info *info) { return GPG_ERR_GENERAL; }
-int
-set_exec_path(const char *path) { return GPG_ERR_GENERAL; }
-
-#else /* ! 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. */
-static int
+int
w32_system(const char *command)
{
if (!strncmp (command, "!ShellExecute ", 14))
@@ -197,501 +162,4 @@ set_exec_path(const char *path)
return 0;
#endif
}
-
-/* Makes a temp directory and filenames */
-static int
-make_tempdir(struct exec_info *info)
-{
- char *tmp=opt.temp_dir,*namein=info->name,*nameout;
-
- if(!namein)
- namein=info->flags.binary?"tempin" EXTSEP_S "bin":"tempin" EXTSEP_S "txt";
-
- nameout=info->flags.binary?"tempout" EXTSEP_S "bin":"tempout" EXTSEP_S "txt";
-
- /* Make up the temp dir and files in case we need them */
-
- if(tmp==NULL)
- {
-#if defined (_WIN32)
- int err;
-
- tmp=xmalloc(MAX_PATH+2);
- err=GetTempPath(MAX_PATH+1,tmp);
- if(err==0 || err>MAX_PATH+1)
- strcpy(tmp,"c:\\windows\\temp");
- else
- {
- int len=strlen(tmp);
-
- /* GetTempPath may return with \ on the end */
- while(len>0 && tmp[len-1]=='\\')
- {
- tmp[len-1]='\0';
- len--;
- }
- }
-#else /* More unixish systems */
- tmp=getenv("TMPDIR");
- if(tmp==NULL)
- {
- tmp=getenv("TMP");
- if(tmp==NULL)
- {
-#ifdef __riscos__
- tmp="<Wimp$ScrapDir>.GnuPG";
- mkdir(tmp,0700); /* Error checks occur later on */
-#else
- tmp="/tmp";
-#endif
- }
- }
-#endif
- }
-
- info->tempdir=xmalloc(strlen(tmp)+strlen(DIRSEP_S)+10+1);
-
- sprintf(info->tempdir,"%s" DIRSEP_S "gpg-XXXXXX",tmp);
-
-#if defined (_WIN32)
- xfree(tmp);
-#endif
-
- if (!gnupg_mkdtemp(info->tempdir))
- log_error(_("can't create directory '%s': %s\n"),
- info->tempdir,strerror(errno));
- else
- {
- info->flags.madedir=1;
-
- info->tempfile_in=xmalloc(strlen(info->tempdir)+
- strlen(DIRSEP_S)+strlen(namein)+1);
- sprintf(info->tempfile_in,"%s" DIRSEP_S "%s",info->tempdir,namein);
-
- if(!info->flags.writeonly)
- {
- info->tempfile_out=xmalloc(strlen(info->tempdir)+
- strlen(DIRSEP_S)+strlen(nameout)+1);
- sprintf(info->tempfile_out,"%s" DIRSEP_S "%s",info->tempdir,nameout);
- }
- }
-
- return info->flags.madedir? 0 : GPG_ERR_GENERAL;
-}
-
-/* Expands %i and %o in the args to the full temp files within the
- temp directory. */
-static int
-expand_args(struct exec_info *info,const char *args_in)
-{
- const char *ch = args_in;
- membuf_t command;
-
- info->flags.use_temp_files=0;
- info->flags.keep_temp_files=0;
-
- if(DBG_EXTPROG)
- log_debug("expanding string \"%s\"\n",args_in);
-
- init_membuf (&command, 100);
-
- while(*ch!='\0')
- {
- if(*ch=='%')
- {
- char *append=NULL;
-
- ch++;
-
- switch(*ch)
- {
- case 'O':
- info->flags.keep_temp_files=1;
- /* fall through */
-
- case 'o': /* out */
- if(!info->flags.madedir)
- {
- if(make_tempdir(info))
- goto fail;
- }
- append=info->tempfile_out;
- info->flags.use_temp_files=1;
- break;
-
- case 'I':
- info->flags.keep_temp_files=1;
- /* fall through */
-
- case 'i': /* in */
- if(!info->flags.madedir)
- {
- if(make_tempdir(info))
- goto fail;
- }
- append=info->tempfile_in;
- info->flags.use_temp_files=1;
- break;
-
- case '%':
- append="%";
- break;
- }
-
- if(append)
- put_membuf_str (&command, append);
- }
- else
- put_membuf (&command, ch, 1);
-
- ch++;
- }
-
- put_membuf (&command, "", 1); /* Terminate string. */
-
- info->command = get_membuf (&command, NULL);
- if (!info->command)
- return gpg_error_from_syserror ();
-
- if(DBG_EXTPROG)
- log_debug("args expanded to \"%s\", use %u, keep %u\n",info->command,
- info->flags.use_temp_files,info->flags.keep_temp_files);
-
- return 0;
-
- fail:
- xfree (get_membuf (&command, NULL));
- return GPG_ERR_GENERAL;
-}
-
-/* Either handles the tempfile creation, or the fork/exec. If it
- returns ok, then info->tochild is a FILE * that can be written to.
- The rules are: if there are no args, then it's a fork/exec/pipe.
- If there are args, but no tempfiles, then it's a fork/exec/pipe via
- shell -c. If there are tempfiles, then it's a system. */
-
-int
-exec_write(struct exec_info **info,const char *program,
- const char *args_in,const char *name,int writeonly,int binary)
-{
- int ret = GPG_ERR_GENERAL;
-
- if(opt.exec_disable && !opt.no_perm_warn)
- {
- log_info(_("external program calls are disabled due to unsafe "
- "options file permissions\n"));
-
- return ret;
- }
-
-#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
- /* There should be no way to get to this spot while still carrying
- setuid privs. Just in case, bomb out if we are. */
- if ( getuid () != geteuid ())
- BUG ();
-#endif
-
- if(program==NULL && args_in==NULL)
- BUG();
-
- *info=xmalloc_clear(sizeof(struct exec_info));
-
- if(name)
- (*info)->name=xstrdup(name);
- (*info)->flags.binary=binary;
- (*info)->flags.writeonly=writeonly;
-
- /* Expand the args, if any */
- if(args_in && expand_args(*info,args_in))
- goto fail;
-
-#ifdef EXEC_TEMPFILE_ONLY
- if(!(*info)->flags.use_temp_files)
- {
- log_error(_("this platform requires temporary files when calling"
- " external programs\n"));
- goto fail;
- }
-
-#else /* !EXEC_TEMPFILE_ONLY */
-
- /* If there are no args, or there are args, but no temp files, we
- can use fork/exec/pipe */
- if(args_in==NULL || (*info)->flags.use_temp_files==0)
- {
- int to[2],from[2];
-
- if(pipe(to)==-1)
- goto fail;
-
- if(pipe(from)==-1)
- {
- close(to[0]);
- close(to[1]);
- goto fail;
- }
-
- if(((*info)->child=fork())==-1)
- {
- close(to[0]);
- close(to[1]);
- close(from[0]);
- close(from[1]);
- goto fail;
- }
-
- if((*info)->child==0)
- {
- char *shell=getenv("SHELL");
-
- if(shell==NULL)
- shell="/bin/sh";
-
- /* I'm the child */
-
- /* If the program isn't going to respond back, they get to
- keep their stdout/stderr */
- if(!(*info)->flags.writeonly)
- {
- /* implied close of STDERR */
- if(dup2(STDOUT_FILENO,STDERR_FILENO)==-1)
- _exit(1);
-
- /* implied close of STDOUT */
- close(from[0]);
- if(dup2(from[1],STDOUT_FILENO)==-1)
- _exit(1);
- }
-
- /* implied close of STDIN */
- close(to[1]);
- if(dup2(to[0],STDIN_FILENO)==-1)
- _exit(1);
-
- if(args_in==NULL)
- {
- if(DBG_EXTPROG)
- log_debug("execlp: %s\n",program);
-
- execlp(program,program,(void *)NULL);
- }
- else
- {
- if(DBG_EXTPROG)
- log_debug("execlp: %s -c %s\n",shell,(*info)->command);
-
- execlp(shell,shell,"-c",(*info)->command,(void *)NULL);
- }
-
- /* If we get this far the exec failed. Clean up and return. */
-
- if(args_in==NULL)
- log_error(_("unable to execute program '%s': %s\n"),
- program,strerror(errno));
- else
- log_error(_("unable to execute shell '%s': %s\n"),
- shell,strerror(errno));
-
- /* This mimics the POSIX sh behavior - 127 means "not found"
- from the shell. */
- if(errno==ENOENT)
- _exit(127);
-
- _exit(1);
- }
-
- /* I'm the parent */
-
- close(to[0]);
-
- (*info)->tochild=fdopen(to[1],binary?"wb":"w");
- if((*info)->tochild==NULL)
- {
- ret = gpg_error_from_syserror ();
- close(to[1]);
- goto fail;
- }
-
- close(from[1]);
-
- (*info)->fromchild=iobuf_fdopen(from[0],"r");
- if((*info)->fromchild==NULL)
- {
- ret = gpg_error_from_syserror ();
- close(from[0]);
- goto fail;
- }
-
- /* fd iobufs are cached! */
- iobuf_ioctl((*info)->fromchild, IOBUF_IOCTL_NO_CACHE, 1, NULL);
-
- return 0;
- }
-#endif /* !EXEC_TEMPFILE_ONLY */
-
- if(DBG_EXTPROG)
- log_debug("using temp file '%s'\n",(*info)->tempfile_in);
-
- /* It's not fork/exec/pipe, so create a temp file */
- if( is_secured_filename ((*info)->tempfile_in) )
- {
- (*info)->tochild = NULL;
- gpg_err_set_errno (EPERM);
- }
- else
- (*info)->tochild=fopen((*info)->tempfile_in,binary?"wb":"w");
- if((*info)->tochild==NULL)
- {
- ret = gpg_error_from_syserror ();
- log_error(_("can't create '%s': %s\n"),
- (*info)->tempfile_in,strerror(errno));
- goto fail;
- }
-
- ret=0;
-
- fail:
- if (ret)
- {
- xfree (*info);
- *info = NULL;
- }
- return ret;
-}
-
-int
-exec_read(struct exec_info *info)
-{
- int ret = GPG_ERR_GENERAL;
-
- fclose(info->tochild);
- info->tochild=NULL;
-
- if(info->flags.use_temp_files)
- {
- if(DBG_EXTPROG)
- log_debug ("running command: %s\n",info->command);
-
-#if defined (_WIN32)
- info->progreturn=w32_system(info->command);
-#else
- info->progreturn=system(info->command);
-#endif
-
- if(info->progreturn==-1)
- {
- log_error(_("system error while calling external program: %s\n"),
- strerror(errno));
- info->progreturn=127;
- goto fail;
- }
-
-#if defined(WIFEXITED) && defined(WEXITSTATUS)
- if(WIFEXITED(info->progreturn))
- info->progreturn=WEXITSTATUS(info->progreturn);
- else
- {
- log_error(_("unnatural exit of external program\n"));
- info->progreturn=127;
- goto fail;
- }
-#else
- /* If we don't have the macros, do the best we can. */
- info->progreturn = (info->progreturn & 0xff00) >> 8;
-#endif
-
- /* 127 is the magic value returned from system() to indicate
- that the shell could not be executed, or from /bin/sh to
- indicate that the program could not be executed. */
-
- if(info->progreturn==127)
- {
- log_error(_("unable to execute external program\n"));
- goto fail;
- }
-
- if(!info->flags.writeonly)
- {
- info->fromchild=iobuf_open(info->tempfile_out);
- if (info->fromchild
- && is_secured_file (iobuf_get_fd (info->fromchild)))
- {
- iobuf_close (info->fromchild);
- info->fromchild = NULL;
- gpg_err_set_errno (EPERM);
- }
- if(info->fromchild==NULL)
- {
- ret = gpg_error_from_syserror ();
- log_error(_("unable to read external program response: %s\n"),
- strerror(errno));
- goto fail;
- }
-
- /* Do not cache this iobuf on close */
- iobuf_ioctl(info->fromchild, IOBUF_IOCTL_NO_CACHE, 1, NULL);
- }
- }
-
- ret=0;
-
- fail:
- return ret;
-}
-
-int
-exec_finish(struct exec_info *info)
-{
- int ret=info->progreturn;
-
- if(info->fromchild)
- iobuf_close(info->fromchild);
-
- if(info->tochild)
- fclose(info->tochild);
-
-#ifndef EXEC_TEMPFILE_ONLY
- if(info->child>0)
- {
- if(waitpid(info->child,&info->progreturn,0)!=0 &&
- WIFEXITED(info->progreturn))
- ret=WEXITSTATUS(info->progreturn);
- else
- {
- log_error(_("unnatural exit of external program\n"));
- ret=127;
- }
- }
-#endif
-
- if(info->flags.madedir && !info->flags.keep_temp_files)
- {
- if(info->tempfile_in)
- {
- if(unlink(info->tempfile_in)==-1)
- log_info(_("WARNING: unable to remove tempfile (%s) '%s': %s\n"),
- "in",info->tempfile_in,strerror(errno));
- }
-
- if(info->tempfile_out)
- {
- if(unlink(info->tempfile_out)==-1)
- log_info(_("WARNING: unable to remove tempfile (%s) '%s': %s\n"),
- "out",info->tempfile_out,strerror(errno));
- }
-
- if(rmdir(info->tempdir)==-1)
- log_info(_("WARNING: unable to remove temp directory '%s': %s\n"),
- info->tempdir,strerror(errno));
- }
-
- xfree(info->command);
- xfree(info->name);
- xfree(info->tempdir);
- xfree(info->tempfile_in);
- xfree(info->tempfile_out);
- xfree(info);
-
- return ret;
-}
#endif /* ! NO_EXEC */
diff --git a/g10/exec.h b/g10/exec.h
index 1cb1c7208..6b24d1c51 100644
--- a/g10/exec.h
+++ b/g10/exec.h
@@ -20,32 +20,7 @@
#ifndef _EXEC_H_
#define _EXEC_H_
-#include <unistd.h>
-#include <stdio.h>
-
-#include "../common/iobuf.h"
-
-struct exec_info
-{
- int progreturn;
- struct
- {
- unsigned int binary:1;
- unsigned int writeonly:1;
- unsigned int madedir:1;
- unsigned int use_temp_files:1;
- unsigned int keep_temp_files:1;
- } flags;
- pid_t child;
- FILE *tochild;
- iobuf_t fromchild;
- char *command,*name,*tempdir,*tempfile_in,*tempfile_out;
-};
-
-int exec_write(struct exec_info **info,const char *program,
- const char *args_in,const char *name,int writeonly,int binary);
-int exec_read(struct exec_info *info);
-int exec_finish(struct exec_info *info);
int set_exec_path(const char *path);
+int w32_system(const char *command);
#endif /* !_EXEC_H_ */
diff --git a/g10/expand-group.c b/g10/expand-group.c
new file mode 100644
index 000000000..e09a4fff6
--- /dev/null
+++ b/g10/expand-group.c
@@ -0,0 +1,73 @@
+/* expand-group.c - expand GPG group definitions
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+ * 2008, 2009, 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include "gpg.h"
+#include "options.h"
+#include "keydb.h"
+
+int
+expand_id (const char *id, strlist_t *into, unsigned int flags)
+{
+ struct groupitem *groups;
+ int count=0;
+
+ for (groups = opt.grouplist; groups; groups=groups->next)
+ {
+ /* need strcasecmp() here, as this should be localized */
+ if (strcasecmp (groups->name,id) == 0)
+ {
+ strlist_t each,sl;
+
+ /* This maintains the current utf8-ness */
+ for (each = groups->values; each; each=each->next)
+ {
+ sl = add_to_strlist (into, each->d);
+ sl->flags = flags;
+ count++;
+ }
+
+ break;
+ }
+ }
+
+ return count;
+}
+
+/* For simplicity, and to avoid potential loops, we only expand once -
+ * you can't make an alias that points to an alias. */
+strlist_t
+expand_group (strlist_t input)
+{
+ strlist_t output = NULL;
+ strlist_t sl, rover;
+
+ for (rover = input; rover; rover = rover->next)
+ if (!(rover->flags & PK_LIST_FROM_FILE)
+ && !expand_id (rover->d, &output, rover->flags))
+ {
+ /* Didn't find any groups, so use the existing string */
+ sl = add_to_strlist (&output, rover->d);
+ sl->flags = rover->flags;
+ }
+
+ return output;
+}
diff --git a/g10/export.c b/g10/export.c
index 15861cc0d..3517be72c 100644
--- a/g10/export.c
+++ b/g10/export.c
@@ -2142,6 +2142,105 @@ key_to_sshblob (membuf_t *mb, const char *identifier, ...)
return err;
}
+
+static gpg_error_t
+export_one_ssh_key (estream_t fp, PKT_public_key *pk)
+{
+ gpg_error_t err;
+ const char *identifier = NULL;
+ membuf_t mb;
+ struct b64state b64_state;
+ void *blob;
+ size_t bloblen;
+
+ init_membuf (&mb, 4096);
+
+ switch (pk->pubkey_algo)
+ {
+ case PUBKEY_ALGO_DSA:
+ identifier = "ssh-dss";
+ err = key_to_sshblob (&mb, identifier,
+ pk->pkey[0], pk->pkey[1], pk->pkey[2], pk->pkey[3],
+ NULL);
+ break;
+
+ case PUBKEY_ALGO_RSA:
+ case PUBKEY_ALGO_RSA_S:
+ identifier = "ssh-rsa";
+ err = key_to_sshblob (&mb, identifier, pk->pkey[1], pk->pkey[0], NULL);
+ break;
+
+ case PUBKEY_ALGO_ECDSA:
+ {
+ char *curveoid;
+ const char *curve;
+
+ curveoid = openpgp_oid_to_str (pk->pkey[0]);
+ if (!curveoid)
+ err = gpg_error_from_syserror ();
+ else if (!(curve = openpgp_oid_to_curve (curveoid, 0)))
+ err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
+ else
+ {
+ if (!strcmp (curve, "nistp256"))
+ identifier = "ecdsa-sha2-nistp256";
+ else if (!strcmp (curve, "nistp384"))
+ identifier = "ecdsa-sha2-nistp384";
+ else if (!strcmp (curve, "nistp521"))
+ identifier = "ecdsa-sha2-nistp521";
+
+ if (!identifier)
+ err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
+ else
+ err = key_to_sshblob (&mb, identifier, pk->pkey[1], NULL);
+ }
+ xfree (curveoid);
+ }
+ break;
+
+ case PUBKEY_ALGO_EDDSA:
+ if (!openpgp_oid_is_ed25519 (pk->pkey[0]))
+ err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
+ else
+ {
+ identifier = "ssh-ed25519";
+ err = key_to_sshblob (&mb, identifier, pk->pkey[1], NULL);
+ }
+ break;
+
+ case PUBKEY_ALGO_ELGAMAL_E:
+ case PUBKEY_ALGO_ELGAMAL:
+ err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
+ break;
+
+ default:
+ err = GPG_ERR_PUBKEY_ALGO;
+ break;
+ }
+
+ if (err)
+ goto leave;
+
+ err = b64enc_start_es (&b64_state, fp, "");
+ if (err)
+ goto leave;
+
+ blob = get_membuf (&mb, &bloblen);
+ if (blob)
+ {
+ es_fprintf (fp, "%s ", identifier);
+ err = b64enc_write (&b64_state, blob, bloblen);
+ es_fprintf (fp, " openpgp:0x%08lX\n", (ulong)keyid_from_pk (pk, NULL));
+ xfree (blob);
+ }
+
+ b64enc_finish (&b64_state);
+
+ leave:
+ xfree (get_membuf (&mb, NULL));
+ return err;
+}
+
/* Export the key identified by USERID in the SSH public key format.
The function exports the latest subkey with Authentication
capability unless the '!' suffix is used to export a specific
@@ -2156,14 +2255,9 @@ export_ssh_key (ctrl_t ctrl, const char *userid)
u32 curtime = make_timestamp ();
kbnode_t latest_key, node;
PKT_public_key *pk;
- const char *identifier = NULL;
- membuf_t mb;
estream_t fp = NULL;
- struct b64state b64_state;
const char *fname = "-";
- init_membuf (&mb, 4096);
-
/* We need to know whether the key has been specified using the
exact syntax ('!' suffix). Thus we need to run a
classify_user_id on our own. */
@@ -2319,72 +2413,6 @@ export_ssh_key (ctrl_t ctrl, const char *userid)
if (DBG_LOOKUP)
log_debug ("\tusing key %08lX\n", (ulong) keyid_from_pk (pk, NULL));
- switch (pk->pubkey_algo)
- {
- case PUBKEY_ALGO_DSA:
- identifier = "ssh-dss";
- err = key_to_sshblob (&mb, identifier,
- pk->pkey[0], pk->pkey[1], pk->pkey[2], pk->pkey[3],
- NULL);
- break;
-
- case PUBKEY_ALGO_RSA:
- case PUBKEY_ALGO_RSA_S:
- identifier = "ssh-rsa";
- err = key_to_sshblob (&mb, identifier, pk->pkey[1], pk->pkey[0], NULL);
- break;
-
- case PUBKEY_ALGO_ECDSA:
- {
- char *curveoid;
- const char *curve;
-
- curveoid = openpgp_oid_to_str (pk->pkey[0]);
- if (!curveoid)
- err = gpg_error_from_syserror ();
- else if (!(curve = openpgp_oid_to_curve (curveoid, 0)))
- err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
- else
- {
- if (!strcmp (curve, "nistp256"))
- identifier = "ecdsa-sha2-nistp256";
- else if (!strcmp (curve, "nistp384"))
- identifier = "ecdsa-sha2-nistp384";
- else if (!strcmp (curve, "nistp521"))
- identifier = "ecdsa-sha2-nistp521";
-
- if (!identifier)
- err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
- else
- err = key_to_sshblob (&mb, identifier, pk->pkey[1], NULL);
- }
- xfree (curveoid);
- }
- break;
-
- case PUBKEY_ALGO_EDDSA:
- if (!openpgp_oid_is_ed25519 (pk->pkey[0]))
- err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
- else
- {
- identifier = "ssh-ed25519";
- err = key_to_sshblob (&mb, identifier, pk->pkey[1], NULL);
- }
- break;
-
- case PUBKEY_ALGO_ELGAMAL_E:
- case PUBKEY_ALGO_ELGAMAL:
- err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
- break;
-
- default:
- err = GPG_ERR_PUBKEY_ALGO;
- break;
- }
-
- if (!identifier)
- goto leave;
-
if (opt.outfile && *opt.outfile && strcmp (opt.outfile, "-"))
fp = es_fopen ((fname = opt.outfile), "w");
else
@@ -2396,26 +2424,9 @@ export_ssh_key (ctrl_t ctrl, const char *userid)
goto leave;
}
- es_fprintf (fp, "%s ", identifier);
- err = b64enc_start_es (&b64_state, fp, "");
- if (!err)
- {
- void *blob;
- size_t bloblen;
-
- blob = get_membuf (&mb, &bloblen);
- if (blob)
- {
- err = b64enc_write (&b64_state, blob, bloblen);
- xfree (blob);
- if (err)
- goto leave;
- }
- err = b64enc_finish (&b64_state);
- }
+ err = export_one_ssh_key (fp, pk);
if (err)
goto leave;
- es_fprintf (fp, " openpgp:0x%08lX\n", (ulong)keyid_from_pk (pk, NULL));
if (es_ferror (fp))
err = gpg_error_from_syserror ();
@@ -2431,7 +2442,6 @@ export_ssh_key (ctrl_t ctrl, const char *userid)
leave:
es_fclose (fp);
- xfree (get_membuf (&mb, NULL));
release_kbnode (keyblock);
return err;
}
diff --git a/g10/getkey.c b/g10/getkey.c
index 2cc56cdbd..de5024198 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -729,7 +729,7 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist,
{
int rc = 0;
int n;
- strlist_t r;
+ strlist_t r, namelist_expanded = NULL, link = NULL;
GETKEY_CTX ctx;
KBNODE help_kb = NULL;
KBNODE found_key = NULL;
@@ -758,6 +758,19 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist,
}
else
{
+ namelist_expanded = expand_group (namelist);
+
+ /* Chain namelist and namelist_expanded */
+ for (r = namelist; r; r = r->next)
+ {
+ if (!r->next)
+ {
+ r->next = namelist_expanded;
+ link = r;
+ break;
+ }
+ }
+
/* Build the search context. */
for (n = 0, r = namelist; r; r = r->next)
n++;
@@ -779,7 +792,8 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist,
if (err)
{
xfree (ctx);
- return gpg_err_code (err); /* FIXME: remove gpg_err_code. */
+ rc = gpg_err_code (err); /* FIXME: remove gpg_err_code. */
+ goto leave;
}
if (!include_unusable
&& ctx->items[n].mode != KEYDB_SEARCH_MODE_SHORT_KID
@@ -798,7 +812,7 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist,
{
rc = gpg_error_from_syserror ();
getkey_end (ctrl, ctx);
- return rc;
+ goto leave;
}
if (!ret_kb)
@@ -829,6 +843,12 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist,
getkey_end (ctrl, ctx);
}
+leave:
+ if (namelist_expanded)
+ free_strlist(namelist_expanded);
+ /* Un-chain namelist and namelist_expanded */
+ if (link)
+ link->next = NULL;
return rc;
}
@@ -2151,7 +2171,7 @@ parse_key_usage (PKT_signature * sig)
size_t n;
byte flags;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_FLAGS, &n);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_KEY_FLAGS, &n);
if (p && n)
{
/* First octet of the keyflags. */
@@ -2249,7 +2269,7 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated)
uid->help_key_usage = parse_key_usage (sig);
/* Ditto for the key expiration. */
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_KEY_EXPIRE, NULL);
if (p && buf32_to_u32 (p))
uid->help_key_expire = keycreated + buf32_to_u32 (p);
else
@@ -2258,7 +2278,7 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated)
/* Set the primary user ID flag - we will later wipe out some
* of them to only have one in our keyblock. */
uid->flags.primary = 0;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PRIMARY_UID, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_PRIMARY_UID, NULL);
if (p && *p)
uid->flags.primary = 2;
@@ -2270,16 +2290,16 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated)
/* Now build the preferences list. These must come from the
hashed section so nobody can modify the ciphers a key is
willing to accept. */
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_SYM, &n);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_PREF_SYM, &n);
sym = p;
nsym = p ? n : 0;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_AEAD, &n);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_PREF_AEAD, &n);
aead = p;
naead = p ? n : 0;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_HASH, &n);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_PREF_HASH, &n);
hash = p;
nhash = p ? n : 0;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_COMPR, &n);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_PREF_COMPR, &n);
zip = p;
nzip = p ? n : 0;
if (uid->prefs)
@@ -2317,19 +2337,19 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated)
/* See whether we have the MDC feature. */
uid->flags.mdc = 0;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_FEATURES, &n);
if (p && n && (p[0] & 0x01))
uid->flags.mdc = 1;
/* See whether we have the AEAD feature. */
uid->flags.aead = 0;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_FEATURES, &n);
if (p && n && (p[0] & 0x02))
uid->flags.aead = 1;
/* And the keyserver modify flag. */
uid->flags.ks_modify = 1;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KS_FLAGS, &n);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_KS_FLAGS, &n);
if (p && n && (p[0] & 0x80))
uid->flags.ks_modify = 0;
}
@@ -2564,7 +2584,7 @@ merge_selfsigs_main (ctrl_t ctrl, kbnode_t keyblock, int *r_revoked,
key_usage = parse_key_usage (sig);
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_KEY_EXPIRE, NULL);
if (p && buf32_to_u32 (p))
{
key_expire = keytimestamp + buf32_to_u32 (p);
@@ -3052,7 +3072,7 @@ merge_selfsigs_subkey (ctrl_t ctrl, kbnode_t keyblock, kbnode_t subnode)
subpk->pubkey_usage = key_usage;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_KEY_EXPIRE, NULL);
if (p && buf32_to_u32 (p))
key_expire = keytimestamp + buf32_to_u32 (p);
else
@@ -3079,8 +3099,8 @@ merge_selfsigs_subkey (ctrl_t ctrl, kbnode_t keyblock, kbnode_t subnode)
/* We do this while() since there may be other embedded
* signatures in the future. We only want 0x19 here. */
- while ((p = enum_sig_subpkt (sig->hashed,
- SIGSUBPKT_SIGNATURE, &n, &seq, NULL)))
+ while ((p = enum_sig_subpkt (sig, 1, SIGSUBPKT_SIGNATURE,
+ &n, &seq, NULL)))
if (n > 3
&& ((p[0] == 3 && p[2] == 0x19) || (p[0] == 4 && p[1] == 0x19)))
{
@@ -3104,8 +3124,7 @@ merge_selfsigs_subkey (ctrl_t ctrl, kbnode_t keyblock, kbnode_t subnode)
/* It is safe to have this in the unhashed area since the 0x19
* is located on the selfsig for convenience, not security. */
-
- while ((p = enum_sig_subpkt (sig->unhashed, SIGSUBPKT_SIGNATURE,
+ while ((p = enum_sig_subpkt (sig, 0, SIGSUBPKT_SIGNATURE,
&n, &seq, NULL)))
if (n > 3
&& ((p[0] == 3 && p[2] == 0x19) || (p[0] == 4 && p[1] == 0x19)))
@@ -3924,6 +3943,26 @@ release_akl (void)
}
}
+
+/* Returns true if the AKL is empty or has only the local method
+ * active. */
+int
+akl_empty_or_only_local (void)
+{
+ struct akl *akl;
+ int any = 0;
+
+ for (akl = opt.auto_key_locate; akl; akl = akl->next)
+ if (akl->type != AKL_NODEFAULT && akl->type != AKL_LOCAL)
+ {
+ any = 1;
+ break;
+ }
+
+ return !any;
+}
+
+
/* Returns false on error. */
int
parse_auto_key_locate (const char *options_arg)
diff --git a/g10/gpg.c b/g10/gpg.c
index 821d3959b..b9b6de4e6 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -429,6 +429,7 @@ enum cmd_and_opt_values
oKeyOrigin,
oRequestOrigin,
oNoSymkeyCache,
+ oUseOnlyOpenPGPCard,
oNoop
};
@@ -714,7 +715,7 @@ static ARGPARSE_OPTS opts[] = {
"delete-secret-and-public-keys", "@"),
ARGPARSE_c (aRebuildKeydbCaches, "rebuild-keydb-caches", "@"),
- ARGPARSE_s_s (oPassphrase, "passphrase", "@"),
+ ARGPARSE_o_s (oPassphrase, "passphrase", "@"),
ARGPARSE_s_i (oPassphraseFD, "passphrase-fd", "@"),
ARGPARSE_s_s (oPassphraseFile, "passphrase-file", "@"),
ARGPARSE_s_i (oPassphraseRepeat,"passphrase-repeat", "@"),
@@ -901,6 +902,10 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_n (oNoSymkeyCache, "no-symkey-cache", "@"),
ARGPARSE_s_n (oUseKeyboxd, "use-keyboxd", "@"),
+ /* 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", "@"),
+
/* Dummy options with warnings. */
ARGPARSE_s_n (oUseAgent, "use-agent", "@"),
ARGPARSE_s_n (oNoUseAgent, "no-use-agent", "@"),
@@ -961,6 +966,9 @@ static struct debug_flags_s debug_flags [] =
#define ALWAYS_ADD_KEYRINGS 0
#endif
+/* The list of the default AKL methods. */
+#define DEFAULT_AKL_LIST "local,wkd"
+
int g10_errors_seen = 0;
@@ -2539,7 +2547,7 @@ main (int argc, char **argv)
/* Set default options which require that malloc stuff is ready. */
additional_weak_digest ("MD5");
- parse_auto_key_locate ("local,wkd");
+ parse_auto_key_locate (DEFAULT_AKL_LIST);
/* Try for a version specific config file first */
default_configname = get_default_configname ();
@@ -3178,7 +3186,7 @@ main (int argc, char **argv)
case oBZ2CompressLevel: opt.bz2_compress_level = pargs.r.ret_int; break;
case oBZ2DecompressLowmem: opt.bz2_decompress_lowmem=1; break;
case oPassphrase:
- set_passphrase_from_string(pargs.r.ret_str);
+ set_passphrase_from_string (pargs.r_type ? pargs.r.ret_str : "");
break;
case oPassphraseFD:
pwfd = translate_sys2libc_fd_int (pargs.r.ret_int, 0);
@@ -3657,6 +3665,10 @@ main (int argc, char **argv)
opt.def_new_key_algo = pargs.r.ret_str;
break;
+ case oUseOnlyOpenPGPCard:
+ opt.flags.use_only_openpgp_card = 1;
+ break;
+
case oNoop: break;
default:
@@ -3765,7 +3777,10 @@ main (int argc, char **argv)
log_info(_("WARNING: program may create a core file!\n"));
if (opt.flags.rfc4880bis)
- log_info ("Note: RFC4880bis features are enabled.\n");
+ {
+ if (!opt.quiet)
+ log_info ("Note: RFC4880bis features are enabled.\n");
+ }
else
{
opt.mimemode = 0; /* This will use text mode instead. */
@@ -4555,7 +4570,17 @@ main (int argc, char **argv)
sl = NULL;
for (; argc; argc--, argv++)
add_to_strlist2( &sl, *argv, utf8_strings );
+ if (cmd == aLocateExtKeys && akl_empty_or_only_local ())
+ {
+ /* This is a kludge to let --locate-external-keys even
+ * work if the config file has --no-auto-key-locate. This
+ * better matches the expectations of the user. */
+ release_akl ();
+ parse_auto_key_locate (DEFAULT_AKL_LIST);
+ }
public_key_list (ctrl, sl, 1, cmd == aLocateExtKeys);
+
+
free_strlist (sl);
break;
diff --git a/g10/import.c b/g10/import.c
index 17afaa6f6..47014b948 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -3151,7 +3151,7 @@ get_revocation_reason (PKT_signature *sig, char **r_reason,
*r_comment = NULL;
/* Skip over empty reason packets. */
- while ((reason_p = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REVOC_REASON,
+ while ((reason_p = enum_sig_subpkt (sig, 1, SIGSUBPKT_REVOC_REASON,
&reason_n, &reason_seq, NULL))
&& !reason_n)
;
diff --git a/g10/key-clean.c b/g10/key-clean.c
index d701a6665..496d0194e 100644
--- a/g10/key-clean.c
+++ b/g10/key-clean.c
@@ -192,7 +192,7 @@ mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
const byte *p;
u32 expire;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_EXPIRE, NULL );
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_SIG_EXPIRE, NULL );
expire = p? sig->timestamp + buf32_to_u32(p) : 0;
if (expire==0 || expire > curtime )
diff --git a/g10/keydb.c b/g10/keydb.c
index 39ec5442e..aeb62abfc 100644
--- a/g10/keydb.c
+++ b/g10/keydb.c
@@ -730,14 +730,27 @@ keydb_add_resource (const char *url, unsigned int flags)
err = gpg_error (GPG_ERR_RESOURCE_LIMIT);
else
{
+ KEYBOX_HANDLE kbxhd;
+
if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY))
primary_keydb = token;
all_resources[used_resources].type = rt;
all_resources[used_resources].u.kb = NULL; /* Not used here */
all_resources[used_resources].token = token;
- /* FIXME: Do a compress run if needed and no other
- user is currently using the keybox. */
+ /* Do a compress run if needed and no other user is
+ * currently using the keybox. */
+ kbxhd = keybox_new_openpgp (token, 0);
+ if (kbxhd)
+ {
+ if (!keybox_lock (kbxhd, 1, 0))
+ {
+ keybox_compress (kbxhd);
+ keybox_lock (kbxhd, 0, 0);
+ }
+
+ keybox_release (kbxhd);
+ }
used_resources++;
}
diff --git a/g10/keydb.h b/g10/keydb.h
index cc6f05956..f94b14659 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -29,11 +29,17 @@
/* What qualifies as a certification (key-signature in contrast to a
* data signature)? Note that a back signature is special and can be
* made by key and data signatures capable subkeys.) */
-#define IS_CERT(s) (IS_KEY_SIG(s) || IS_UID_SIG(s) || IS_SUBKEY_SIG(s) \
- || IS_KEY_REV(s) || IS_UID_REV(s) || IS_SUBKEY_REV(s))
+#define IS_CERT(s) (IS_KEY_SIG(s) \
+ || IS_UID_SIG(s) \
+ || IS_SUBKEY_SIG(s) \
+ || IS_KEY_REV(s) \
+ || IS_UID_REV(s) \
+ || IS_SUBKEY_REV(s) \
+ || IS_ATTST_SIGS(s) )
#define IS_SIG(s) (!IS_CERT(s))
#define IS_KEY_SIG(s) ((s)->sig_class == 0x1f)
#define IS_UID_SIG(s) (((s)->sig_class & ~3) == 0x10)
+#define IS_ATTST_SIGS(s) ((s)->sig_class == 0x16)
#define IS_SUBKEY_SIG(s) ((s)->sig_class == 0x18)
#define IS_BACK_SIG(s) ((s)->sig_class == 0x19)
#define IS_KEY_REV(s) ((s)->sig_class == 0x20)
@@ -260,6 +266,8 @@ void show_revocation_reason (ctrl_t ctrl, PKT_public_key *pk, int mode );
int check_signatures_trust (ctrl_t ctrl, PKT_signature *sig);
void release_pk_list (PK_LIST pk_list);
+int expand_id (const char *id, strlist_t *into, unsigned int flags);
+strlist_t expand_group (strlist_t input);
int build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list);
gpg_error_t find_and_check_key (ctrl_t ctrl,
const char *name, unsigned int use,
@@ -454,6 +462,7 @@ char *get_user_id_native (ctrl_t ctrl, u32 *keyid);
char *get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr, size_t fprlen);
void release_akl(void);
+int akl_empty_or_only_local (void);
int parse_auto_key_locate(const char *options);
int parse_key_origin (char *string);
const char *key_origin_string (int origin);
diff --git a/g10/keyedit.c b/g10/keyedit.c
index 9238d5d53..2ac52d315 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -299,11 +299,11 @@ keyedit_print_one_sig (ctrl_t ctrl, estream_t fp,
PKT_public_key *pk = keyblock->pkt->pkt.public_key;
const unsigned char *s;
- s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PRIMARY_UID, NULL);
+ s = parse_sig_subpkt (sig, 1, SIGSUBPKT_PRIMARY_UID, NULL);
if (s && *s)
tty_fprintf (fp, " [primary]\n");
- s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
+ s = parse_sig_subpkt (sig, 1, SIGSUBPKT_KEY_EXPIRE, NULL);
if (s && buf32_to_u32 (s))
tty_fprintf (fp, " [expires: %s]\n",
isotimestamp (pk->timestamp + buf32_to_u32 (s)));
@@ -3158,8 +3158,8 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
const byte *pref_ks;
size_t pref_ks_len;
- pref_ks = parse_sig_subpkt (selfsig->hashed,
- SIGSUBPKT_PREF_KS, &pref_ks_len);
+ pref_ks = parse_sig_subpkt (selfsig, 1,
+ SIGSUBPKT_PREF_KS, &pref_ks_len);
if (pref_ks && pref_ks_len)
{
tty_printf (" ");
@@ -4870,10 +4870,10 @@ menu_set_primary_uid (ctrl_t ctrl, kbnode_t pub_keyblock)
int action;
/* See whether this signature has the primary UID flag. */
- p = parse_sig_subpkt (sig->hashed,
+ p = parse_sig_subpkt (sig, 1,
SIGSUBPKT_PRIMARY_UID, NULL);
if (!p)
- p = parse_sig_subpkt (sig->unhashed,
+ p = parse_sig_subpkt (sig, 0,
SIGSUBPKT_PRIMARY_UID, NULL);
if (p && *p) /* yes */
action = selected ? 0 : -1;
@@ -5086,7 +5086,7 @@ menu_set_keyserver_url (ctrl_t ctrl, const char *url, kbnode_t pub_keyblock)
const byte *p;
size_t plen;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_KS, &plen);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_PREF_KS, &plen);
if (p && plen)
{
tty_printf ("Current preferred keyserver for user"
diff --git a/g10/keygen.c b/g10/keygen.c
index 5aeda36ce..61682158e 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -151,7 +151,8 @@ static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
const char *expirestr,
int *r_algo, unsigned int *r_usage,
u32 *r_expire, unsigned int *r_nbits,
- const char **r_curve, int *r_version);
+ const char **r_curve, int *r_version,
+ char **r_keygrip);
static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
struct output_control_s *outctrl, int card );
static int write_keyblock (iobuf_t out, kbnode_t node);
@@ -691,7 +692,7 @@ add_feature_mdc (PKT_signature *sig,int enabled)
int i;
char *buf;
- s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n );
+ s = parse_sig_subpkt (sig, 1, SIGSUBPKT_FEATURES, &n );
/* Already set or cleared */
if (s && n &&
((enabled && (s[0] & 0x01)) || (!enabled && !(s[0] & 0x01))))
@@ -733,7 +734,7 @@ add_feature_aead (PKT_signature *sig, int enabled)
int i;
char *buf;
- s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n );
+ s = parse_sig_subpkt (sig, 1, SIGSUBPKT_FEATURES, &n );
if (s && n && ((enabled && (s[0] & 0x02)) || (!enabled && !(s[0] & 0x02))))
return; /* Already set or cleared */
@@ -775,7 +776,7 @@ add_feature_v5 (PKT_signature *sig, int enabled)
int i;
char *buf;
- s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n );
+ s = parse_sig_subpkt (sig, 1, SIGSUBPKT_FEATURES, &n );
if (s && n && ((enabled && (s[0] & 0x04)) || (!enabled && !(s[0] & 0x04))))
return; /* Already set or cleared */
@@ -820,7 +821,7 @@ add_keyserver_modify (PKT_signature *sig,int enabled)
/* The keyserver modify flag is a negative flag (i.e. no-modify) */
enabled=!enabled;
- s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KS_FLAGS, &n );
+ s = parse_sig_subpkt (sig, 1, SIGSUBPKT_KS_FLAGS, &n );
/* Already set or cleared */
if (s && n &&
((enabled && (s[0] & 0x80)) || (!enabled && !(s[0] & 0x80))))
@@ -2268,6 +2269,12 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
do
{
+ char *authkeyref, *encrkeyref, *signkeyref;
+
+ agent_scd_getattr_one ("$AUTHKEYID", &authkeyref);
+ agent_scd_getattr_one ("$ENCRKEYID", &encrkeyref);
+ agent_scd_getattr_one ("$SIGNKEYID", &signkeyref);
+
tty_printf (_("Available keys:\n"));
for (count=1,sl=keypairlist; sl; sl = sl->next, count++)
{
@@ -2297,6 +2304,10 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
&& algostr && !strncmp (algostr, "nistp", 5)
&& !(sl->flags & GCRY_PK_USAGE_ENCR))
sl->flags |= (PUBKEY_ALGO_ECDSA << 8);
+ else if (algoid == GCRY_PK_ECC
+ && algostr && !strcmp (algostr, "ed25519")
+ && !(sl->flags & GCRY_PK_USAGE_ENCR))
+ sl->flags = (PUBKEY_ALGO_EDDSA << 8);
else
sl->flags |= (map_pk_gcry_to_openpgp (algoid) << 8);
@@ -2308,17 +2319,23 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
}
if ((sl->flags & GCRY_PK_USAGE_SIGN))
{
- tty_printf ("%ssign", any?",":" (");
+ tty_printf ("%ssign%s", any?",":" (",
+ (signkeyref && keyref
+ && !strcmp (signkeyref, keyref))? "*":"");
any = 1;
}
if ((sl->flags & GCRY_PK_USAGE_AUTH))
{
- tty_printf ("%sauth", any?",":" (");
+ tty_printf ("%sauth%s", any?",":" (",
+ (authkeyref && keyref
+ && !strcmp (authkeyref, keyref))? "*":"");
any = 1;
}
if ((sl->flags & GCRY_PK_USAGE_ENCR))
{
- tty_printf ("%sencr", any?",":" (");
+ tty_printf ("%sencr%s", any?",":" (",
+ (encrkeyref && keyref
+ && !strcmp (encrkeyref, keyref))? "*":"");
any = 1;
}
tty_printf ("%s\n", any?")":"");
@@ -2330,6 +2347,10 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
cpr_kill_prompt ();
trim_spaces (answer);
selection = atoi (answer);
+ xfree (authkeyref);
+ xfree (encrkeyref);
+ xfree (signkeyref);
+
}
while (!(selection > 0 && selection < count));
@@ -3210,11 +3231,14 @@ generate_user_id (KBNODE keyblock, const char *uidstr)
* the key; this is currently 4 but can be changed with the flag "v5"
* to create a v5 key. */
static gpg_error_t
-parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
+parse_key_parameter_part (ctrl_t ctrl,
+ char *string, int for_subkey, int clear_cert,
int *r_algo, unsigned int *r_size,
unsigned int *r_keyuse,
- char const **r_curve, int *r_keyversion)
+ char const **r_curve, int *r_keyversion,
+ char **r_keygrip)
{
+ gpg_error_t err;
char *flags;
int algo;
char *endp;
@@ -3225,6 +3249,8 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
int keyversion = 4;
int i;
const char *s;
+ int from_card = 0;
+ char *keygrip = NULL;
if (!string || !*string)
return 0; /* Success. */
@@ -3234,7 +3260,9 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
*flags++ = 0;
algo = 0;
- if (strlen (string) >= 3 && (digitp (string+3) || !string[3]))
+ if (!ascii_strcasecmp (string, "card"))
+ from_card = 1;
+ else if (strlen (string) >= 3 && (digitp (string+3) || !string[3]))
{
if (!ascii_memcasecmp (string, "rsa", 3))
algo = PUBKEY_ALGO_RSA;
@@ -3243,7 +3271,10 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
else if (!ascii_memcasecmp (string, "elg", 3))
algo = PUBKEY_ALGO_ELGAMAL_E;
}
- if (algo)
+
+ if (from_card)
+ ; /* We need the flags before we can figure out the key to use. */
+ else if (algo)
{
if (!string[3])
size = get_keysize_range (algo, NULL, NULL);
@@ -3288,7 +3319,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
keyuse |= PUBKEY_USAGE_AUTH;
else if (!ascii_strcasecmp (s, "cert"))
keyuse |= PUBKEY_USAGE_CERT;
- else if (!ascii_strcasecmp (s, "ecdsa"))
+ else if (!ascii_strcasecmp (s, "ecdsa") && !from_card)
{
if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
algo = PUBKEY_ALGO_ECDSA;
@@ -3299,7 +3330,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
}
ecdh_or_ecdsa = 0;
}
- else if (!ascii_strcasecmp (s, "ecdh"))
+ else if (!ascii_strcasecmp (s, "ecdh") && !from_card)
{
if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
algo = PUBKEY_ALGO_ECDH;
@@ -3310,7 +3341,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
}
ecdh_or_ecdsa = 0;
}
- else if (!ascii_strcasecmp (s, "eddsa"))
+ else if (!ascii_strcasecmp (s, "eddsa") && !from_card)
{
/* Not required but we allow it for consistency. */
if (algo == PUBKEY_ALGO_EDDSA)
@@ -3338,8 +3369,115 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
xfree (tokens);
}
- /* If not yet decided switch between ecdh and ecdsa. */
- if (ecdh_or_ecdsa && keyuse)
+ /* If not yet decided switch between ecdh and ecdsa unless we want
+ * to read the algo from the current card. */
+ if (from_card)
+ {
+ strlist_t keypairlist, sl;
+ char *reqkeyref;
+
+ if (!keyuse)
+ keyuse = (for_subkey? PUBKEY_USAGE_ENC
+ /* */ : (PUBKEY_USAGE_CERT|PUBKEY_USAGE_SIG));
+
+ /* Access the card to make sure we have one and to show the S/N. */
+ {
+ char *serialno;
+
+ err = agent_scd_serialno (&serialno, NULL);
+ if (err)
+ {
+ log_error (_("error reading the card: %s\n"), gpg_strerror (err));
+ return err;
+ }
+ if (!opt.quiet)
+ log_info (_("Serial number of the card: %s\n"), serialno);
+ xfree (serialno);
+ }
+
+ err = agent_scd_keypairinfo (ctrl, NULL, &keypairlist);
+ if (err)
+ {
+ log_error (_("error reading the card: %s\n"), gpg_strerror (err));
+ return err;
+ }
+ agent_scd_getattr_one ((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_CERT))
+ ? "$SIGNKEYID":"$ENCRKEYID", &reqkeyref);
+
+ algo = 0; /* Should already be the case. */
+ for (sl=keypairlist; sl && !algo; sl = sl->next)
+ {
+ gcry_sexp_t s_pkey;
+ char *algostr = NULL;
+ enum gcry_pk_algos algoid = 0;
+ const char *keyref;
+
+ if (!reqkeyref)
+ continue; /* Card does not provide the info (skip all). */
+
+ keyref = strchr (sl->d, ' ');
+ if (!keyref)
+ continue; /* Ooops. */
+ keyref++;
+ if (strcmp (reqkeyref, keyref))
+ continue; /* This is not the requested keyref. */
+
+ if ((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_CERT))
+ && (sl->flags & (GCRY_PK_USAGE_SIGN|GCRY_PK_USAGE_CERT)))
+ ; /* Okay */
+ else if ((keyuse & PUBKEY_USAGE_ENC)
+ && (sl->flags & GCRY_PK_USAGE_ENCR))
+ ; /* Okay */
+ else
+ continue; /* Not usable for us. */
+
+ if (agent_scd_readkey (keyref, &s_pkey))
+ continue; /* Could not read the key. */
+
+ algostr = pubkey_algo_string (s_pkey, &algoid);
+ gcry_sexp_release (s_pkey);
+
+
+ /* Map to OpenPGP algo number.
+ * We need to tweak the algo in case GCRY_PK_ECC is returned
+ * because pubkey_algo_string is not aware of the OpenPGP
+ * algo mapping. FIXME: This is an ugly hack. */
+ if (algoid == GCRY_PK_ECC
+ && algostr && !strncmp (algostr, "nistp", 5)
+ && !(sl->flags & GCRY_PK_USAGE_ENCR))
+ algo = PUBKEY_ALGO_ECDSA;
+ else if (algoid == GCRY_PK_ECC
+ && algostr && !strcmp (algostr, "ed25519")
+ && !(sl->flags & GCRY_PK_USAGE_ENCR))
+ algo = PUBKEY_ALGO_EDDSA;
+ else
+ algo = map_pk_gcry_to_openpgp (algoid);
+
+ xfree (algostr);
+ xfree (keygrip);
+ keygrip = xtrystrdup (sl->d);
+ if (!keygrip)
+ {
+ err = gpg_error_from_syserror ();
+ xfree (reqkeyref);
+ free_strlist (keypairlist);
+ return err;
+ }
+ if ((endp = strchr (keygrip, ' ')))
+ *endp = 0;
+ }
+
+ xfree (reqkeyref);
+ free_strlist (keypairlist);
+ if (!algo || !keygrip)
+ {
+ err = gpg_error (GPG_ERR_PUBKEY_ALGO);
+ log_error ("no usable key on the card: %s\n", gpg_strerror (err));
+ xfree (keygrip);
+ return err;
+ }
+ }
+ else if (ecdh_or_ecdsa && keyuse)
algo = (keyuse & PUBKEY_USAGE_ENC)? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA;
else if (ecdh_or_ecdsa)
algo = for_subkey? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA;
@@ -3379,7 +3517,10 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
|| ((keyuse & PUBKEY_USAGE_ENC)
&& !pubkey_get_nenc (algo))
|| (for_subkey && (keyuse & PUBKEY_USAGE_CERT)))
- return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+ {
+ xfree (keygrip);
+ return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+ }
/* Return values. */
if (r_algo)
@@ -3399,6 +3540,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
*r_size = fixup_keysize (size, algo, 1);
}
+
if (r_keyuse)
*r_keyuse = keyuse;
if (r_curve)
@@ -3406,6 +3548,11 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
if (r_keyversion)
*r_keyversion = keyversion;
+ if (r_keygrip)
+ *r_keygrip = keygrip;
+ else
+ xfree (keygrip);
+
return 0;
}
@@ -3427,7 +3574,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
*
* All strings with an unknown prefix are considered an elliptic
* curve. Curves which have no implicit algorithm require that FLAGS
- * is given to select whether ECDSA or ECDH is used; this can eoither
+ * is given to select whether ECDSA or ECDH is used; this can either
* be done using an algorithm keyword or usage keywords.
*
* FLAGS is a comma delimited string of keywords:
@@ -3454,16 +3601,19 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
*
*/
gpg_error_t
-parse_key_parameter_string (const char *string, int part,
+parse_key_parameter_string (ctrl_t ctrl,
+ const char *string, int part,
unsigned int suggested_use,
int *r_algo, unsigned int *r_size,
unsigned int *r_keyuse,
char const **r_curve,
int *r_version,
+ char **r_keygrip,
int *r_subalgo, unsigned int *r_subsize,
unsigned int *r_subkeyuse,
char const **r_subcurve,
- int *r_subversion)
+ int *r_subversion,
+ char **r_subkeygrip)
{
gpg_error_t err = 0;
char *primary, *secondary;
@@ -3478,6 +3628,8 @@ parse_key_parameter_string (const char *string, int part,
*r_curve = NULL;
if (r_version)
*r_version = 4;
+ if (r_keygrip)
+ *r_keygrip = NULL;
if (r_subalgo)
*r_subalgo = 0;
if (r_subsize)
@@ -3488,6 +3640,8 @@ parse_key_parameter_string (const char *string, int part,
*r_subcurve = NULL;
if (r_subversion)
*r_subversion = 4;
+ if (r_subkeygrip)
+ *r_subkeygrip = NULL;
if (!string || !*string
|| !ascii_strcasecmp (string, "default") || !strcmp (string, "-"))
@@ -3495,6 +3649,8 @@ parse_key_parameter_string (const char *string, int part,
else if (!ascii_strcasecmp (string, "future-default")
|| !ascii_strcasecmp (string, "futuredefault"))
string = FUTURE_STD_KEY_PARAM;
+ else if (!ascii_strcasecmp (string, "card"))
+ string = "card/cert,sign+card/encr";
primary = xstrdup (string);
secondary = strchr (primary, '+');
@@ -3502,11 +3658,14 @@ parse_key_parameter_string (const char *string, int part,
*secondary++ = 0;
if (part == -1 || part == 0)
{
- err = parse_key_parameter_part (primary, 0, 0, r_algo, r_size,
- r_keyuse, r_curve, r_version);
+ err = parse_key_parameter_part (ctrl, primary,
+ 0, 0, r_algo, r_size,
+ r_keyuse, r_curve, r_version, r_keygrip);
if (!err && part == -1)
- err = parse_key_parameter_part (secondary, 1, 0, r_subalgo, r_subsize,
- r_subkeyuse, r_subcurve, r_subversion);
+ err = parse_key_parameter_part (ctrl, secondary,
+ 1, 0, r_subalgo, r_subsize,
+ r_subkeyuse, r_subcurve, r_subversion,
+ r_subkeygrip);
}
else if (part == 1)
{
@@ -3518,18 +3677,21 @@ parse_key_parameter_string (const char *string, int part,
* to force clearing the cert usage. */
if (secondary)
{
- err = parse_key_parameter_part (secondary, 1, 0,
+ err = parse_key_parameter_part (ctrl, secondary,
+ 1, 0,
r_algo, r_size, r_keyuse, r_curve,
- r_version);
+ r_version, r_keygrip);
if (!err && suggested_use && r_keyuse && !(suggested_use & *r_keyuse))
- err = parse_key_parameter_part (primary, 1, 1 /*(clear cert)*/,
+ err = parse_key_parameter_part (ctrl, primary,
+ 1, 1 /*(clear cert)*/,
r_algo, r_size, r_keyuse, r_curve,
- r_version);
+ r_version, r_keygrip);
}
else
- err = parse_key_parameter_part (primary, 1, 0,
+ err = parse_key_parameter_part (ctrl, primary,
+ 1, 0,
r_algo, r_size, r_keyuse, r_curve,
- r_version);
+ r_version, r_keygrip);
}
xfree (primary);
@@ -3594,7 +3756,7 @@ get_parameter_passphrase (struct para_data_s *para)
static int
-get_parameter_algo( struct para_data_s *para, enum para_name key,
+get_parameter_algo (ctrl_t ctrl, struct para_data_s *para, enum para_name key,
int *r_default)
{
int i;
@@ -3616,9 +3778,9 @@ get_parameter_algo( struct para_data_s *para, enum para_name key,
* for the curve etc. That is a ugly but demanded for backward
* compatibility with the batch key generation. It would be
* better to make full use of parse_key_parameter_string. */
- parse_key_parameter_string (NULL, 0, 0,
- &i, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL);
+ parse_key_parameter_string (ctrl, NULL, 0, 0,
+ &i, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL);
if (r_default)
*r_default = 1;
}
@@ -3815,7 +3977,7 @@ proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname,
r = get_parameter( para, pKEYTYPE );
if(r)
{
- algo = get_parameter_algo (para, pKEYTYPE, &is_default);
+ algo = get_parameter_algo (ctrl, para, pKEYTYPE, &is_default);
if (openpgp_pk_test_algo2 (algo, PUBKEY_USAGE_SIG))
{
log_error ("%s:%d: invalid algorithm\n", fname, r->lnr );
@@ -3857,7 +4019,7 @@ proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname,
r = get_parameter( para, pSUBKEYTYPE );
if(r)
{
- algo = get_parameter_algo (para, pSUBKEYTYPE, &is_default);
+ algo = get_parameter_algo (ctrl, para, pSUBKEYTYPE, &is_default);
if (openpgp_pk_test_algo (algo))
{
log_error ("%s:%d: invalid algorithm\n", fname, r->lnr );
@@ -4225,7 +4387,7 @@ read_parameter_file (ctrl_t ctrl, const char *fname )
static struct para_data_s *
quickgen_set_para (struct para_data_s *para, int for_subkey,
int algo, int nbits, const char *curve, unsigned int use,
- int version)
+ int version, const char *keygrip)
{
struct para_data_s *r;
@@ -4247,7 +4409,15 @@ quickgen_set_para (struct para_data_s *para, int for_subkey,
r->next = para;
para = r;
- if (curve)
+ if (keygrip)
+ {
+ r = xmalloc_clear (sizeof *r + strlen (keygrip));
+ r->key = for_subkey? pSUBKEYGRIP : pKEYGRIP;
+ strcpy (r->u.value, keygrip);
+ r->next = para;
+ para = r;
+ }
+ else if (curve)
{
r = xmalloc_clear (sizeof *r + strlen (curve));
r->key = for_subkey? pSUBKEYCURVE : pKEYCURVE;
@@ -4360,7 +4530,8 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
if ((!*algostr || !ascii_strcasecmp (algostr, "default")
|| !ascii_strcasecmp (algostr, "future-default")
- || !ascii_strcasecmp (algostr, "futuredefault"))
+ || !ascii_strcasecmp (algostr, "futuredefault")
+ || !ascii_strcasecmp (algostr, "card"))
&& (!*usagestr || !ascii_strcasecmp (usagestr, "default")
|| !strcmp (usagestr, "-")))
{
@@ -4369,23 +4540,25 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
unsigned int size, subsize;
unsigned int keyuse, subkeyuse;
const char *curve, *subcurve;
+ char *keygrip, *subkeygrip;
- err = parse_key_parameter_string (algostr, -1, 0,
+ err = parse_key_parameter_string (ctrl, algostr, -1, 0,
&algo, &size, &keyuse, &curve, &version,
+ &keygrip,
&subalgo, &subsize, &subkeyuse,
- &subcurve, &subversion);
+ &subcurve, &subversion, &subkeygrip);
if (err)
{
log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
goto leave;
}
- para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version);
+ para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version,
+ keygrip);
if (subalgo)
para = quickgen_set_para (para, 1,
subalgo, subsize, subcurve, subkeyuse,
- subversion);
-
+ subversion, subkeygrip);
if (*expirestr)
{
u32 expire;
@@ -4403,6 +4576,9 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
r->next = para;
para = r;
}
+
+ xfree (keygrip);
+ xfree (subkeygrip);
}
else
{
@@ -4412,22 +4588,26 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
u32 expire;
unsigned int nbits;
const char *curve;
+ char *keygrip;
err = parse_algo_usage_expire (ctrl, 0, algostr, usagestr, expirestr,
&algo, &use, &expire, &nbits, &curve,
- &version);
+ &version, &keygrip);
if (err)
{
log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
goto leave;
}
- para = quickgen_set_para (para, 0, algo, nbits, curve, use, version);
+ para = quickgen_set_para (para, 0, algo, nbits, curve, use, version,
+ keygrip);
r = xmalloc_clear (sizeof *r + 20);
r->key = pKEYEXPIRE;
r->u.expire = expire;
r->next = para;
para = r;
+
+ xfree (keygrip);
}
/* If the pinentry loopback mode is not and we have a static
@@ -4740,6 +4920,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
unsigned int size, subsize;
unsigned int keyuse, subkeyuse;
const char *curve, *subcurve;
+ char *keygrip, *subkeygrip;
tty_printf ( _("Note: Use \"%s %s\""
" for a full featured key generation dialog.\n"),
@@ -4750,22 +4931,27 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
#endif
, "--full-generate-key" );
- err = parse_key_parameter_string (NULL, -1, 0,
+ err = parse_key_parameter_string (ctrl, NULL, -1, 0,
&algo, &size, &keyuse, &curve, &version,
+ &keygrip,
&subalgo, &subsize,
- &subkeyuse, &subcurve, &subversion);
+ &subkeyuse, &subcurve, &subversion,
+ &subkeygrip);
if (err)
{
log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
return;
}
- para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version);
+ para = quickgen_set_para (para, 0,
+ algo, size, curve, keyuse,
+ version, keygrip);
if (subalgo)
para = quickgen_set_para (para, 1,
subalgo, subsize, subcurve, subkeyuse,
- subversion);
-
+ subversion, subkeygrip);
+ xfree (keygrip);
+ xfree (subkeygrip);
}
@@ -5049,7 +5235,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
node of the subkey but that is more work than just to pass the
current timestamp. */
- algo = get_parameter_algo( para, pKEYTYPE, NULL );
+ algo = get_parameter_algo (ctrl, para, pKEYTYPE, NULL );
expire = get_parameter_u32( para, pKEYEXPIRE );
key_from_hexgrip = get_parameter_value (para, pKEYGRIP);
@@ -5112,7 +5298,8 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
if (!err && card && get_parameter (para, pAUTHKEYTYPE))
{
- err = gen_card_key (3, get_parameter_algo( para, pAUTHKEYTYPE, NULL ),
+ err = gen_card_key (3, get_parameter_algo (ctrl, para,
+ pAUTHKEYTYPE, NULL ),
0, pub_root, &timestamp, expire, keygen_flags);
if (!err)
err = write_keybinding (ctrl, pub_root, pri_psk, NULL,
@@ -5121,7 +5308,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
if (!err && get_parameter (para, pSUBKEYTYPE))
{
- int subkey_algo = get_parameter_algo (para, pSUBKEYTYPE, NULL);
+ int subkey_algo = get_parameter_algo (ctrl, para, pSUBKEYTYPE, NULL);
s = NULL;
key_from_hexgrip = get_parameter_value (para, pSUBKEYGRIP);
@@ -5216,7 +5403,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
int no_enc_rsa;
PKT_public_key *pk;
- no_enc_rsa = ((get_parameter_algo (para, pKEYTYPE, NULL)
+ no_enc_rsa = ((get_parameter_algo (ctrl, para, pKEYTYPE, NULL)
== PUBKEY_ALGO_RSA)
&& get_parameter_uint (para, pKEYUSAGE)
&& !((get_parameter_uint (para, pKEYUSAGE)
@@ -5249,7 +5436,8 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
if (!opt.batch
- && (get_parameter_algo (para, pKEYTYPE, NULL) == PUBKEY_ALGO_DSA
+ && (get_parameter_algo (ctrl, para,
+ pKEYTYPE, NULL) == PUBKEY_ALGO_DSA
|| no_enc_rsa )
&& !get_parameter (para, pSUBKEYTYPE) )
{
@@ -5289,7 +5477,7 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
const char *expirestr,
int *r_algo, unsigned int *r_usage, u32 *r_expire,
unsigned int *r_nbits, const char **r_curve,
- int *r_version)
+ int *r_version, char **r_keygrip)
{
gpg_error_t err;
int algo;
@@ -5300,6 +5488,8 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
const char *curve = NULL;
*r_curve = NULL;
+ if (r_keygrip)
+ *r_keygrip = NULL;
nbits = 0;
@@ -5312,12 +5502,20 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
}
- err = parse_key_parameter_string (algostr, for_subkey? 1 : 0,
+ err = parse_key_parameter_string (ctrl, algostr, for_subkey? 1 : 0,
usagestr? parse_usagestr (usagestr):0,
&algo, &nbits, &use, &curve, &version,
- NULL, NULL, NULL, NULL, NULL);
+ r_keygrip,
+ NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
- return err;
+ {
+ if (r_keygrip)
+ {
+ xfree (*r_keygrip);
+ *r_keygrip = NULL;
+ }
+ return err;
+ }
/* Parse the usage string. */
if (!usagestr || !*usagestr
@@ -5326,7 +5524,14 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
else if ((wantuse = parse_usagestr (usagestr)) != -1)
use = wantuse;
else
- return gpg_error (GPG_ERR_INV_VALUE);
+ {
+ if (r_keygrip)
+ {
+ xfree (*r_keygrip);
+ *r_keygrip = NULL;
+ }
+ return gpg_error (GPG_ERR_INV_VALUE);
+ }
/* Make sure a primary key has the CERT usage. */
if (!for_subkey)
@@ -5340,12 +5545,26 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
|| ((use & PUBKEY_USAGE_ENC)
&& !pubkey_get_nenc (algo))
|| (for_subkey && (use & PUBKEY_USAGE_CERT)))
- return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+ {
+ if (r_keygrip)
+ {
+ xfree (*r_keygrip);
+ *r_keygrip = NULL;
+ }
+ return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+ }
/* Parse the expire string. */
expire = parse_expire_string (expirestr);
if (expire == (u32)-1 )
- return gpg_error (GPG_ERR_INV_VALUE);
+ {
+ if (r_keygrip)
+ {
+ xfree (*r_keygrip);
+ *r_keygrip = NULL;
+ }
+ return gpg_error (GPG_ERR_INV_VALUE);
+ }
if (curve)
*r_curve = curve;
@@ -5467,7 +5686,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
err = parse_algo_usage_expire (ctrl, 1, algostr, usagestr, expirestr,
&algo, &use, &expire, &nbits, &curve,
- &version);
+ &version, &key_from_hexgrip);
if (err)
goto leave;
diff --git a/g10/keylist.c b/g10/keylist.c
index 5f5fe9d34..dacc13788 100644
--- a/g10/keylist.c
+++ b/g10/keylist.c
@@ -338,8 +338,7 @@ show_policy_url (PKT_signature * sig, int indent, int mode)
int seq = 0, crit;
estream_t fp = mode < 0? NULL : mode ? log_get_stream () : es_stdout;
- while ((p =
- enum_sig_subpkt (sig->hashed, SIGSUBPKT_POLICY, &len, &seq, &crit)))
+ while ((p = enum_sig_subpkt (sig, 1, SIGSUBPKT_POLICY, &len, &seq, &crit)))
{
if (mode != 2)
{
@@ -379,9 +378,7 @@ show_keyserver_url (PKT_signature * sig, int indent, int mode)
int seq = 0, crit;
estream_t fp = mode < 0? NULL : mode ? log_get_stream () : es_stdout;
- while ((p =
- enum_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_KS, &len, &seq,
- &crit)))
+ while ((p = enum_sig_subpkt (sig, 1, SIGSUBPKT_PREF_KS, &len, &seq, &crit)))
{
if (mode != 2)
{
@@ -542,7 +539,11 @@ list_all (ctrl_t ctrl, int secret, int mark_secret)
lastresname = NULL;
do
{
+ if (secret)
+ glo_ctrl.silence_parse_warnings++;
rc = keydb_get_keyblock (hd, &keyblock);
+ if (secret)
+ glo_ctrl.silence_parse_warnings--;
if (rc)
{
if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
@@ -870,12 +871,12 @@ print_subpackets_colon (PKT_signature * sig)
seq = 0;
- while ((p = enum_sig_subpkt (sig->hashed, *i, &len, &seq, &crit)))
+ while ((p = enum_sig_subpkt (sig, 1, *i, &len, &seq, &crit)))
print_one_subpacket (*i, len, 0x01 | (crit ? 0x02 : 0), p);
seq = 0;
- while ((p = enum_sig_subpkt (sig->unhashed, *i, &len, &seq, &crit)))
+ while ((p = enum_sig_subpkt (sig, 0, *i, &len, &seq, &crit)))
print_one_subpacket (*i, len, 0x00 | (crit ? 0x02 : 0), p);
}
}
diff --git a/g10/keyserver.c b/g10/keyserver.c
index 030bc9297..c2e304f09 100644
--- a/g10/keyserver.c
+++ b/g10/keyserver.c
@@ -31,7 +31,6 @@
#include "filter.h"
#include "keydb.h"
#include "../common/status.h"
-#include "exec.h"
#include "main.h"
#include "../common/i18n.h"
#include "../common/ttyio.h"
@@ -453,7 +452,7 @@ parse_preferred_keyserver(PKT_signature *sig)
const byte *p;
size_t plen;
- p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_PREF_KS,&plen);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_PREF_KS, &plen);
if(p && plen)
{
byte *dupe=xmalloc(plen+1);
@@ -1812,9 +1811,10 @@ keyserver_put (ctrl_t ctrl, strlist_t keyspecs)
log_error (_("skipped \"%s\": %s\n"), kspec->d, gpg_strerror (err));
else
{
- log_info (_("sending key %s to %s\n"),
- keystr (keyblock->pkt->pkt.public_key->keyid),
- ksurl?ksurl:"[?]");
+ if (!opt.quiet)
+ log_info (_("sending key %s to %s\n"),
+ keystr (keyblock->pkt->pkt.public_key->keyid),
+ ksurl?ksurl:"[?]");
err = gpg_dirmngr_ks_put (ctrl, data, datalen, keyblock);
release_kbnode (keyblock);
diff --git a/g10/mainproc.c b/g10/mainproc.c
index 8a9005c21..c12039e6d 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -325,7 +325,8 @@ symkey_decrypt_seskey (DEK *dek, byte *seskey, size_t slen)
* the gnupg < 2.2 bug compatible case which would terminate the
* process on GPG_ERR_CIPHER_ALGO. Note that with AEAD (above)
* we will have a reliable test here. */
- if (openpgp_cipher_test_algo (seskey[0]))
+ if (openpgp_cipher_test_algo (seskey[0])
+ || openpgp_cipher_get_algo_keylen (seskey[0]) != slen - 1)
{
err = gpg_error (GPG_ERR_CHECKSUM);
goto leave;
@@ -583,7 +584,7 @@ proc_encrypted (CTX c, PACKET *pkt)
struct pubkey_enc_list *list;
for (list = c->pkenc_list; list; list = list->next)
- if (list->result != -1)
+ if (list->result && list->result != -1)
{
char buf[20];
snprintf (buf, sizeof buf, "%08lX%08lX",
@@ -1783,7 +1784,7 @@ issuer_fpr_raw (PKT_signature *sig, size_t *r_len)
const byte *p;
size_t n;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &n);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_ISSUER_FPR, &n);
if (p && ((n == 21 && p[0] == 4) || (n == 33 && p[0] == 5)))
{
*r_len = n - 1;
@@ -2016,7 +2017,7 @@ check_sig_and_print (CTX c, kbnode_t node)
size_t n;
int any_pref_ks = 0;
- while ((p=enum_sig_subpkt (sig->hashed,SIGSUBPKT_PREF_KS,&n,&seq,NULL)))
+ while ((p=enum_sig_subpkt (sig, 1, SIGSUBPKT_PREF_KS, &n, &seq, NULL)))
{
/* According to my favorite copy editor, in English grammar,
you say "at" if the key is located on a web page, but
diff --git a/g10/options.h b/g10/options.h
index bfa2cc31e..26c8439b6 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -252,6 +252,9 @@ struct
unsigned int rfc4880bis:1;
/* Hack: --output is not given but OUTFILE was temporary set to "-". */
unsigned int dummy_outfile:1;
+ /* Force the use of the OpenPGP card and do not allow the use of
+ * another card. */
+ unsigned int use_only_openpgp_card:1;
} flags;
/* Linked list of ways to find a key if the key isn't on the local
@@ -301,6 +304,9 @@ struct {
codes. Thus for the --server purposes we store some of the error
codes here. FIXME! */
gpg_error_t lasterr;
+
+ /* Kludge to silence some warnings using --secret-key-list. */
+ int silence_parse_warnings;
} glo_ctrl;
#define DBG_PACKET_VALUE 1 /* debug packet reading/writing */
diff --git a/g10/packet.h b/g10/packet.h
index 479f25044..5023903d2 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -775,58 +775,61 @@ int skip_some_packets (iobuf_t inp, unsigned int n);
int parse_signature( iobuf_t inp, int pkttype, unsigned long pktlen,
PKT_signature *sig );
-/* Given a subpacket area (typically either PKT_signature.hashed or
- PKT_signature.unhashed), either:
-
- - test whether there are any subpackets with the critical bit set
- that we don't understand,
-
- - list the subpackets, or,
-
- - find a subpacket with a specific type.
-
- REQTYPE indicates the type of operation.
-
- If REQTYPE is SIGSUBPKT_TEST_CRITICAL, then this function checks
- whether there are any subpackets that have the critical bit and
- which GnuPG cannot handle. If GnuPG understands all subpackets
- whose critical bit is set, then this function returns simply
- returns SUBPKTS. If there is a subpacket whose critical bit is set
- and which GnuPG does not understand, then this function returns
- NULL and, if START is not NULL, sets *START to the 1-based index of
- the subpacket that violates the constraint.
-
- If REQTYPE is SIGSUBPKT_LIST_HASHED or SIGSUBPKT_LIST_UNHASHED, the
- packets are dumped. Note: if REQTYPE is SIGSUBPKT_LIST_HASHED,
- this function does not check whether the hash is correct; this is
- merely an indication of the section that the subpackets came from.
-
- If REQTYPE is anything else, then this function interprets the
- values as a subpacket type and looks for the first subpacket with
- that type. If such a packet is found, *CRITICAL (if not NULL) is
- set if the critical bit was set, *RET_N is set to the offset of the
- subpacket's content within the SUBPKTS buffer, *START is set to the
- 1-based index of the subpacket within the buffer, and returns
- &SUBPKTS[*RET_N].
-
- *START is the number of initial subpackets to not consider. Thus,
- if *START is 2, then the first 2 subpackets are ignored. */
-const byte *enum_sig_subpkt ( const subpktarea_t *subpkts,
- sigsubpkttype_t reqtype,
- size_t *ret_n, int *start, int *critical );
+/* Given a signature packet, either:
+ *
+ * - test whether there are any subpackets with the critical bit set
+ * that we don't understand,
+ *
+ * - list the subpackets, or,
+ *
+ * - find a subpacket with a specific type.
+ *
+ * The WANT_HASHED flag indicates that the hashed area shall be
+ * considered.
+ *
+ * REQTYPE indicates the type of operation.
+ *
+ * If REQTYPE is SIGSUBPKT_TEST_CRITICAL, then this function checks
+ * whether there are any subpackets that have the critical bit and
+ * which GnuPG cannot handle. If GnuPG understands all subpackets
+ * whose critical bit is set, then this function returns simply
+ * returns SUBPKTS. If there is a subpacket whose critical bit is set
+ * and which GnuPG does not understand, then this function returns
+ * NULL and, if START is not NULL, sets *START to the 1-based index of
+ * the subpacket that violates the constraint.
+ *
+ * If REQTYPE is SIGSUBPKT_LIST_HASHED or SIGSUBPKT_LIST_UNHASHED, the
+ * packets are dumped. Note: if REQTYPE is SIGSUBPKT_LIST_HASHED,
+ * this function does not check whether the hash is correct; this is
+ * merely an indication of the section that the subpackets came from.
+ *
+ * If REQTYPE is anything else, then this function interprets the
+ * values as a subpacket type and looks for the first subpacket with
+ * that type. If such a packet is found, *CRITICAL (if not NULL) is
+ * set if the critical bit was set, *RET_N is set to the offset of the
+ * subpacket's content within the SUBPKTS buffer, *START is set to the
+ * 1-based index of the subpacket within the buffer, and returns
+ * &SUBPKTS[*RET_N].
+ *
+ * *START is the number of initial subpackets to not consider. Thus,
+ * if *START is 2, then the first 2 subpackets are ignored.
+ */
+const byte *enum_sig_subpkt (PKT_signature *sig, int want_hashed,
+ sigsubpkttype_t reqtype,
+ size_t *ret_n, int *start, int *critical );
/* Shorthand for:
-
- enum_sig_subpkt (buffer, reqtype, ret_n, NULL, NULL); */
-const byte *parse_sig_subpkt ( const subpktarea_t *buffer,
- sigsubpkttype_t reqtype,
- size_t *ret_n );
+ *
+ * enum_sig_subpkt (sig, want_hashed, reqtype, ret_n, NULL, NULL);
+ */
+const byte *parse_sig_subpkt (PKT_signature *sig, int want_hashed,
+ sigsubpkttype_t reqtype,
+ size_t *ret_n );
/* This calls parse_sig_subpkt first on the hashed signature area in
- SIG and then, if that returns NULL, calls parse_sig_subpkt on the
- unhashed subpacket area in SIG. */
-const byte *parse_sig_subpkt2 ( PKT_signature *sig,
- sigsubpkttype_t reqtype);
+ * SIG and then, if that returns NULL, calls parse_sig_subpkt on the
+ * unhashed subpacket area in SIG. */
+const byte *parse_sig_subpkt2 (PKT_signature *sig, sigsubpkttype_t reqtype);
/* Returns whether the N byte large buffer BUFFER is sufficient to
hold a subpacket of type TYPE. Note: the buffer refers to the
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index ab82d475a..874ff76b0 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -270,7 +270,7 @@ unknown_pubkey_warning (int algo)
encryption/signing. */
if (pubkey_get_npkey (algo))
{
- if (opt.verbose)
+ if (opt.verbose && !glo_ctrl.silence_parse_warnings)
{
if (!pubkey_get_nsig (algo))
log_info ("public key algorithm %s not suitable for %s\n",
@@ -285,7 +285,7 @@ unknown_pubkey_warning (int algo)
algo &= 0xff;
if (!unknown_pubkey_algos[algo])
{
- if (opt.verbose)
+ if (opt.verbose && !glo_ctrl.silence_parse_warnings)
log_info (_("can't handle public key algorithm %d\n"), algo);
unknown_pubkey_algos[algo] = 1;
}
@@ -1360,17 +1360,20 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
/* Dump a subpacket to LISTFP. BUFFER contains the subpacket in
- question and points to the type field in the subpacket header (not
- the start of the header). TYPE is the subpacket's type with the
- critical bit cleared. CRITICAL is the value of the CRITICAL bit.
- BUFLEN is the length of the buffer and LENGTH is the length of the
- subpacket according to the subpacket's header. */
+ * question and points to the type field in the subpacket header (not
+ * the start of the header). TYPE is the subpacket's type with the
+ * critical bit cleared. CRITICAL is the value of the CRITICAL bit.
+ * BUFLEN is the length of the buffer and LENGTH is the length of the
+ * subpacket according to the subpacket's header. DIGEST_ALGO is the
+ * digest algo of the signature. */
static void
dump_sig_subpkt (int hashed, int type, int critical,
- const byte * buffer, size_t buflen, size_t length)
+ const byte * buffer, size_t buflen, size_t length,
+ int digest_algo)
{
const char *p = NULL;
int i;
+ int nprinted;
/* The CERT has warning out with explains how to use GNUPG to detect
* the ARRs - we print our old message here when it is a faked ARR
@@ -1388,9 +1391,11 @@ dump_sig_subpkt (int hashed, int type, int critical,
buffer++;
length--;
- es_fprintf (listfp, "\t%s%ssubpkt %d len %u (", /*) */
- critical ? "critical " : "",
- hashed ? "hashed " : "", type, (unsigned) length);
+ nprinted = es_fprintf (listfp, "\t%s%ssubpkt %d len %u (", /*) */
+ critical ? "critical " : "",
+ hashed ? "hashed " : "", type, (unsigned) length);
+ if (nprinted < 1)
+ nprinted = 1; /*(we use (nprinted-1) later.)*/
if (length > buflen)
{
es_fprintf (listfp, "too short: buffer is only %u)\n", (unsigned) buflen);
@@ -1585,6 +1590,32 @@ dump_sig_subpkt (int hashed, int type, int critical,
buffer[0] == 3 ? buffer[15] : buffer[2],
buffer[0] == 3 ? buffer[16] : buffer[3]);
break;
+
+ case SIGSUBPKT_ATTST_SIGS:
+ {
+ unsigned int hlen;
+
+ es_fputs ("attst-sigs: ", listfp);
+ hlen = gcry_md_get_algo_dlen (map_md_openpgp_to_gcry (digest_algo));
+ if (!hlen)
+ p = "[unknown digest algo]";
+ else if ((length % hlen))
+ p = "[invalid length]";
+ else
+ {
+ es_fprintf (listfp, "%d", length/hlen);
+ while (length)
+ {
+ es_fprintf (listfp, "\n\t%*s", nprinted-1, "");
+ es_write_hexstring (listfp, buffer, hlen, 0, NULL);
+ buffer += hlen;
+ length -= hlen;
+ }
+ }
+ }
+ break;
+
+
default:
if (type >= 100 && type <= 110)
p = "experimental / private subpacket";
@@ -1627,6 +1658,7 @@ parse_one_sig_subpkt (const byte * buffer, size_t n, int type)
case SIGSUBPKT_PREF_KS:
case SIGSUBPKT_FEATURES:
case SIGSUBPKT_REGEXP:
+ case SIGSUBPKT_ATTST_SIGS:
return 0;
case SIGSUBPKT_SIGNATURE:
case SIGSUBPKT_EXPORTABLE:
@@ -1679,7 +1711,7 @@ can_handle_critical_notation (const byte *name, size_t len)
if (sl->flags == len && !memcmp (sl->d, name, len))
return 1; /* Known */
- if (opt.verbose)
+ if (opt.verbose && !glo_ctrl.silence_parse_warnings)
{
log_info(_("Unknown critical signature notation: ") );
print_utf8_buffer (log_get_stream(), name, len);
@@ -1721,6 +1753,7 @@ can_handle_critical (const byte * buffer, size_t n, int type)
case SIGSUBPKT_FEATURES:
case SIGSUBPKT_TRUST:
case SIGSUBPKT_REGEXP:
+ case SIGSUBPKT_ATTST_SIGS:
/* Is it enough to show the policy or keyserver? */
case SIGSUBPKT_POLICY:
case SIGSUBPKT_PREF_KS:
@@ -1734,8 +1767,8 @@ can_handle_critical (const byte * buffer, size_t n, int type)
const byte *
-enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
- size_t * ret_n, int *start, int *critical)
+enum_sig_subpkt (PKT_signature *sig, int want_hashed, sigsubpkttype_t reqtype,
+ size_t *ret_n, int *start, int *critical)
{
const byte *buffer;
int buflen;
@@ -1743,6 +1776,7 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
int critical_dummy;
int offset;
size_t n;
+ const subpktarea_t *pktbuf = want_hashed? sig->hashed : sig->unhashed;
int seq = 0;
int reqseq = start ? *start : 0;
@@ -1800,7 +1834,7 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
goto too_short;
if (!can_handle_critical (buffer + 1, n - 1, type))
{
- if (opt.verbose)
+ if (opt.verbose && !glo_ctrl.silence_parse_warnings)
log_info (_("subpacket of type %d has "
"critical bit set\n"), type);
if (start)
@@ -1811,7 +1845,7 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
}
else if (reqtype < 0) /* List packets. */
dump_sig_subpkt (reqtype == SIGSUBPKT_LIST_HASHED,
- type, *critical, buffer, buflen, n);
+ type, *critical, buffer, buflen, n, sig->digest_algo);
else if (type == reqtype) /* Found. */
{
buffer++;
@@ -1851,14 +1885,14 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
return NULL; /* End of packets; not found. */
too_short:
- if (opt.verbose)
+ if (opt.verbose && !glo_ctrl.silence_parse_warnings)
log_info ("buffer shorter than subpacket\n");
if (start)
*start = -1;
return NULL;
no_type_byte:
- if (opt.verbose)
+ if (opt.verbose && !glo_ctrl.silence_parse_warnings)
log_info ("type octet missing in subpacket\n");
if (start)
*start = -1;
@@ -1867,21 +1901,21 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
const byte *
-parse_sig_subpkt (const subpktarea_t * buffer, sigsubpkttype_t reqtype,
- size_t * ret_n)
+parse_sig_subpkt (PKT_signature *sig, int want_hashed, sigsubpkttype_t reqtype,
+ size_t *ret_n)
{
- return enum_sig_subpkt (buffer, reqtype, ret_n, NULL, NULL);
+ return enum_sig_subpkt (sig, want_hashed, reqtype, ret_n, NULL, NULL);
}
const byte *
-parse_sig_subpkt2 (PKT_signature * sig, sigsubpkttype_t reqtype)
+parse_sig_subpkt2 (PKT_signature *sig, sigsubpkttype_t reqtype)
{
const byte *p;
- p = parse_sig_subpkt (sig->hashed, reqtype, NULL);
+ p = parse_sig_subpkt (sig, 1, reqtype, NULL);
if (!p)
- p = parse_sig_subpkt (sig->unhashed, reqtype, NULL);
+ p = parse_sig_subpkt (sig, 0, reqtype, NULL);
return p;
}
@@ -1897,8 +1931,8 @@ parse_revkeys (PKT_signature * sig)
if (sig->sig_class != 0x1F)
return;
- while ((revkey = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REV_KEY,
- &len, &seq, NULL)))
+ while ((revkey = enum_sig_subpkt (sig, 1, SIGSUBPKT_REV_KEY,
+ &len, &seq, NULL)))
{
/* Consider only valid packets. They must have a length of
* either 2+20 or 2+32 octets and bit 7 of the class octet must
@@ -2062,21 +2096,21 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
/* Set sig->flags.unknown_critical if there is a critical bit
* set for packets which we do not understand. */
- if (!parse_sig_subpkt (sig->hashed, SIGSUBPKT_TEST_CRITICAL, NULL)
- || !parse_sig_subpkt (sig->unhashed, SIGSUBPKT_TEST_CRITICAL, NULL))
+ if (!parse_sig_subpkt (sig, 1, SIGSUBPKT_TEST_CRITICAL, NULL)
+ || !parse_sig_subpkt (sig, 0, SIGSUBPKT_TEST_CRITICAL, NULL))
sig->flags.unknown_critical = 1;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_CREATED, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_SIG_CREATED, NULL);
if (p)
sig->timestamp = buf32_to_u32 (p);
else if (!(sig->pubkey_algo >= 100 && sig->pubkey_algo <= 110)
- && opt.verbose)
+ && opt.verbose && !glo_ctrl.silence_parse_warnings)
log_info ("signature packet without timestamp\n");
/* Set the key id. We first try the issuer fingerprint and if
* it is a v4 signature the fallback to the issuer. Note that
* only the issuer packet is also searched in the unhashed area. */
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &len);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_ISSUER_FPR, &len);
if (p && len == 21 && p[0] == 4)
{
sig->keyid[0] = buf32_to_u32 (p + 1 + 12);
@@ -2093,24 +2127,24 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
sig->keyid[1] = buf32_to_u32 (p + 4);
}
else if (!(sig->pubkey_algo >= 100 && sig->pubkey_algo <= 110)
- && opt.verbose)
+ && opt.verbose && !glo_ctrl.silence_parse_warnings)
log_info ("signature packet without keyid\n");
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_EXPIRE, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_SIG_EXPIRE, NULL);
if (p && buf32_to_u32 (p))
sig->expiredate = sig->timestamp + buf32_to_u32 (p);
if (sig->expiredate && sig->expiredate <= make_timestamp ())
sig->flags.expired = 1;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_POLICY, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_POLICY, NULL);
if (p)
sig->flags.policy_url = 1;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_KS, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_PREF_KS, NULL);
if (p)
sig->flags.pref_ks = 1;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIGNERS_UID, &len);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_SIGNERS_UID, &len);
if (p && len)
{
char *mbox;
@@ -2129,15 +2163,15 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
}
}
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_NOTATION, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_NOTATION, NULL);
if (p)
sig->flags.notation = 1;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_REVOCABLE, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_REVOCABLE, NULL);
if (p && *p == 0)
sig->flags.revocable = 0;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_TRUST, &len);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_TRUST, &len);
if (p && len == 2)
{
sig->trust_depth = p[0];
@@ -2146,7 +2180,7 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
/* Only look for a regexp if there is also a trust
subpacket. */
sig->trust_regexp =
- parse_sig_subpkt (sig->hashed, SIGSUBPKT_REGEXP, &len);
+ parse_sig_subpkt (sig, 1, SIGSUBPKT_REGEXP, &len);
/* If the regular expression is of 0 length, there is no
regular expression. */
@@ -2179,8 +2213,8 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
sig->digest_algo, sig->digest_start[0], sig->digest_start[1]);
if (is_v4or5)
{
- parse_sig_subpkt (sig->hashed, SIGSUBPKT_LIST_HASHED, NULL);
- parse_sig_subpkt (sig->unhashed, SIGSUBPKT_LIST_UNHASHED, NULL);
+ parse_sig_subpkt (sig, 1, SIGSUBPKT_LIST_HASHED, NULL);
+ parse_sig_subpkt (sig, 0, SIGSUBPKT_LIST_UNHASHED, NULL);
}
}
@@ -2344,7 +2378,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
{
/* Not anymore supported since 2.1. Use an older gpg version
* (i.e. gpg 1.4) to parse v3 packets. */
- if (opt.verbose > 1)
+ if (opt.verbose > 1 && !glo_ctrl.silence_parse_warnings)
log_info ("packet(%d) with obsolete version %d\n", pkttype, version);
if (list_mode)
es_fprintf (listfp, ":key packet: [obsolete version %d]\n", version);
@@ -2866,7 +2900,7 @@ parse_attribute_subpkts (PKT_user_id * uid)
return count;
too_short:
- if (opt.verbose)
+ if (opt.verbose && !glo_ctrl.silence_parse_warnings)
log_info ("buffer shorter than attribute subpacket\n");
uid->attribs = attribs;
uid->numattribs = count;
diff --git a/g10/photoid.c b/g10/photoid.c
index 9bb4ab58f..f7ada2729 100644
--- a/g10/photoid.c
+++ b/g10/photoid.c
@@ -21,6 +21,7 @@
#include <errno.h>
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
#ifdef _WIN32
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
@@ -233,9 +234,10 @@ int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len)
make sure it is not too big (see parse-packet.c:parse_attribute).
Extensions should be 3 characters long for the best cross-platform
compatibility. */
-char *image_type_to_string(byte type,int style)
+const char *
+image_type_to_string(byte type,int style)
{
- char *string;
+ const char *string;
switch(type)
{
@@ -279,8 +281,6 @@ get_default_photo_command(void)
#elif defined(__APPLE__)
/* OS X. This really needs more than just __APPLE__. */
return "open %I";
-#elif defined(__riscos__)
- return "Filer_Run %I";
#else
if (!path_access ("xloadimage", X_OK))
return "xloadimage -fork -quiet -title 'KeyID 0x%k' stdin";
@@ -294,6 +294,322 @@ get_default_photo_command(void)
}
#endif
+#ifndef DISABLE_PHOTO_VIEWER
+struct spawn_info
+{
+ unsigned int keep_temp_file;
+ char *command;
+ char *tempdir;
+ char *tempfile;
+};
+
+#ifdef NO_EXEC
+static void
+show_photo (const char *command, const char *name, const void *image, u32 len)
+{
+ log_error(_("no remote program execution supported\n"));
+ return GPG_ERR_GENERAL;
+}
+#else /* ! NO_EXEC */
+#include "../common/membuf.h"
+#include "../common/exechelp.h"
+
+/* Makes a temp directory and filenames */
+static int
+setup_input_file (struct spawn_info *info, const char *name)
+{
+ char *tmp = opt.temp_dir;
+ int len;
+#define TEMPLATE "gpg-XXXXXX"
+
+ /* Initialize by the length of last part in the path + 1 */
+ len = strlen (DIRSEP_S) + strlen (TEMPLATE) + 1;
+
+ /* Make up the temp dir and file in case we need them */
+ if (tmp)
+ {
+ len += strlen (tmp);
+ info->tempdir = xmalloc (len);
+ }
+ else
+ {
+#if defined (_WIN32)
+ int ret;
+
+ tmp = xmalloc (MAX_PATH+1);
+ if (!tmp)
+ return -1;
+
+ ret = GetTempPath (MAX_PATH-len, tmp);
+ if (ret == 0 || ret >= MAX_PATH-len)
+ strcpy (tmp, "c:\\windows\\temp");
+ else
+ {
+ /* GetTempPath may return with \ on the end */
+ while (ret > 0 && tmp[ret-1] == '\\')
+ {
+ tmp[ret-1]='\0';
+ ret--;
+ }
+ }
+
+ len += ret;
+ info->tempdir = tmp;
+#else /* More unixish systems */
+ if (!(tmp = getenv ("TMPDIR"))
+ && !(tmp = getenv ("TMP")))
+ tmp = "/tmp";
+
+ len += strlen (tmp);
+ info->tempdir = xmalloc (len);
+#endif
+ }
+
+ if (info->tempdir == NULL)
+ return -1;
+
+ sprintf (info->tempdir, "%s" DIRSEP_S TEMPLATE, tmp);
+
+ if (gnupg_mkdtemp (info->tempdir) == NULL)
+ {
+ log_error (_("can't create directory '%s': %s\n"),
+ info->tempdir, strerror (errno));
+ return -1;
+ }
+
+ info->tempfile = xmalloc (strlen (info->tempdir) + strlen (DIRSEP_S)
+ + strlen (name) + 1);
+ if (info->tempfile == NULL)
+ {
+ xfree (info->tempdir);
+ info->tempdir = NULL;
+ return -1;
+ }
+ sprintf (info->tempfile, "%s" DIRSEP_S "%s", info->tempdir, name);
+ return 0;
+}
+
+/* Expands %i or %I in the args to the full temp file within the temp
+ directory. */
+static int
+expand_args (struct spawn_info *info, const char *args_in, const char *name)
+{
+ const char *ch = args_in;
+ membuf_t command;
+
+ info->keep_temp_file = 0;
+
+ if (DBG_EXTPROG)
+ log_debug ("expanding string \"%s\"\n", args_in);
+
+ init_membuf (&command, 100);
+
+ while (*ch != '\0')
+ {
+ if (*ch == '%')
+ {
+ const char *append = NULL;
+
+ ch++;
+
+ switch (*ch)
+ {
+ case 'I':
+ info->keep_temp_file = 1;
+ /* fall through */
+
+ case 'i': /* in */
+ if (info->tempfile == NULL)
+ {
+ if (setup_input_file (info, name) < 0)
+ goto fail;
+ }
+ append = info->tempfile;
+ break;
+
+ case '%':
+ append = "%";
+ break;
+ }
+
+ if (append)
+ put_membuf_str (&command, append);
+ }
+ else
+ put_membuf (&command, ch, 1);
+
+ ch++;
+ }
+
+ put_membuf (&command, "", 1); /* Terminate string. */
+
+ info->command = get_membuf (&command, NULL);
+ if (!info->command)
+ return -1;
+
+ if(DBG_EXTPROG)
+ log_debug("args expanded to \"%s\", use %s, keep %u\n", info->command,
+ info->tempfile, info->keep_temp_file);
+
+ return 0;
+
+ fail:
+ xfree (get_membuf (&command, NULL));
+ return -1;
+}
+
+#ifndef EXEC_TEMPFILE_ONLY
+static void
+fill_command_argv (const char *argv[4], const char *command)
+{
+ argv[0] = getenv ("SHELL");
+ if (argv[0] == NULL)
+ argv[0] = "/bin/sh";
+
+ argv[1] = "-c";
+ argv[2] = command;
+ argv[3] = NULL;
+}
+#endif
+
+static void
+run_with_pipe (struct spawn_info *info, const void *image, u32 len)
+{
+#ifdef EXEC_TEMPFILE_ONLY
+ (void)info;
+ (void)image;
+ (void)len;
+ log_error (_("this platform requires temporary files when calling"
+ " external programs\n"));
+ return;
+#else /* !EXEC_TEMPFILE_ONLY */
+ int to[2];
+ pid_t pid;
+ gpg_error_t err;
+ const char *argv[4];
+
+ err = gnupg_create_pipe (to);
+ if (err)
+ return;
+
+ fill_command_argv (argv, info->command);
+ err = gnupg_spawn_process_fd (argv[0], argv+1, to[0], -1, -1, &pid);
+
+ close (to[0]);
+
+ if (err)
+ {
+ log_error (_("unable to execute shell '%s': %s\n"),
+ argv[0], gpg_strerror (err));
+ close (to[1]);
+ }
+ else
+ {
+ write (to[1], image, len);
+ close (to[1]);
+
+ err = gnupg_wait_process (argv[0], pid, 1, NULL);
+ if (err)
+ log_error (_("unnatural exit of external program\n"));
+ }
+#endif /* !EXEC_TEMPFILE_ONLY */
+}
+
+static int
+create_temp_file (struct spawn_info *info, const void *ptr, u32 len)
+{
+ if (DBG_EXTPROG)
+ log_debug ("using temp file '%s'\n", info->tempfile);
+
+ /* It's not fork/exec/pipe, so create a temp file */
+ if ( is_secured_filename (info->tempfile) )
+ {
+ log_error (_("can't create '%s': %s\n"),
+ info->tempfile, strerror (EPERM));
+ gpg_err_set_errno (EPERM);
+ return -1;
+ }
+ else
+ {
+ FILE *fp = fopen (info->tempfile, "wb");
+
+ if (fp)
+ {
+ fwrite (ptr, len, 1, fp);
+ fclose (fp);
+ return 0;
+ }
+ else
+ {
+ int save = errno;
+ log_error (_("can't create '%s': %s\n"),
+ info->tempfile, strerror(errno));
+ gpg_err_set_errno (save);
+ return -1;
+ }
+ }
+}
+
+static void
+show_photo (const char *command, const char *name, const void *image, u32 len)
+{
+ struct spawn_info *spawn;
+
+ spawn = xmalloc_clear (sizeof (struct spawn_info));
+ if (!spawn)
+ return;
+
+ /* Expand the args */
+ if (expand_args (spawn, command, name) < 0)
+ {
+ xfree (spawn);
+ return;
+ }
+
+ if (DBG_EXTPROG)
+ log_debug ("running command: %s\n", spawn->command);
+
+ if (spawn->tempfile == NULL)
+ run_with_pipe (spawn, image, len);
+ else if (create_temp_file (spawn, image, len) == 0)
+ {
+#if defined (_WIN32)
+ if (w32_system (spawn->command) < 0)
+ log_error (_("system error while calling external program: %s\n"),
+ strerror (errno));
+#else
+ pid_t pid;
+ gpg_error_t err;
+ const char *argv[4];
+
+ fill_command_argv (argv, spawn->command);
+ err = gnupg_spawn_process_fd (argv[0], argv+1, -1, -1, -1, &pid);
+ if (!err)
+ err = gnupg_wait_process (argv[0], pid, 1, NULL);
+ if (err)
+ log_error (_("unnatural exit of external program\n"));
+#endif
+
+ if (!spawn->keep_temp_file)
+ {
+ if (unlink (spawn->tempfile) < 0)
+ log_info (_("WARNING: unable to remove tempfile (%s) '%s': %s\n"),
+ "in", spawn->tempfile, strerror(errno));
+
+ if (rmdir (spawn->tempdir) < 0)
+ log_info (_("WARNING: unable to remove temp directory '%s': %s\n"),
+ spawn->tempdir, strerror(errno));
+ }
+ }
+
+ xfree(spawn->command);
+ xfree(spawn->tempdir);
+ xfree(spawn->tempfile);
+ xfree(spawn);
+}
+#endif
+#endif
+
void
show_photos (ctrl_t ctrl, const struct user_attribute *attrs, int count,
@@ -310,6 +626,20 @@ show_photos (ctrl_t ctrl, const struct user_attribute *attrs, int count,
u32 len;
u32 kid[2]={0,0};
+ if (opt.exec_disable && !opt.no_perm_warn)
+ {
+ log_info (_("external program calls are disabled due to unsafe "
+ "options file permissions\n"));
+ return;
+ }
+
+#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
+ /* There should be no way to get to this spot while still carrying
+ setuid privs. Just in case, bomb out if we are. */
+ if ( getuid () != geteuid ())
+ BUG ();
+#endif
+
memset (&args, 0, sizeof(args));
args.pk = pk;
args.validity_info = get_validity_info (ctrl, NULL, pk, uid);
@@ -322,28 +652,33 @@ show_photos (ctrl_t ctrl, const struct user_attribute *attrs, int count,
es_fflush (es_stdout);
- for(i=0;i<count;i++)
- if(attrs[i].type==ATTRIB_IMAGE &&
- parse_image_header(&attrs[i],&args.imagetype,&len))
- {
- char *command,*name;
- struct exec_info *spawn;
- int offset=attrs[i].len-len;
-
#ifdef FIXED_PHOTO_VIEWER
- opt.photo_viewer=FIXED_PHOTO_VIEWER;
+ opt.photo_viewer = FIXED_PHOTO_VIEWER;
#else
- if(!opt.photo_viewer)
- opt.photo_viewer=get_default_photo_command();
+ if (!opt.photo_viewer)
+ opt.photo_viewer = get_default_photo_command ();
#endif
+ for (i=0; i<count; i++)
+ if (attrs[i].type == ATTRIB_IMAGE
+ && parse_image_header (&attrs[i], &args.imagetype, &len))
+ {
+ char *command, *name;
+ int offset = attrs[i].len-len;
+
/* make command grow */
- command=pct_expando (ctrl, opt.photo_viewer,&args);
+ command = pct_expando (ctrl, opt.photo_viewer,&args);
if(!command)
goto fail;
- name=xmalloc(16+strlen(EXTSEP_S)+
- strlen(image_type_to_string(args.imagetype,0))+1);
+ name = xmalloc (1 + 16 + strlen(EXTSEP_S)
+ + strlen (image_type_to_string (args.imagetype, 0)));
+
+ if (!name)
+ {
+ xfree (command);
+ goto fail;
+ }
/* Make the filename. Notice we are not using the image
encoding type for more than cosmetics. Most external image
@@ -352,36 +687,17 @@ show_photos (ctrl_t ctrl, const struct user_attribute *attrs, int count,
which. The spec permits this, by the way. -dms */
#ifdef USE_ONLY_8DOT3
- sprintf(name,"%08lX" EXTSEP_S "%s",(ulong)kid[1],
- image_type_to_string(args.imagetype,0));
+ sprintf (name,"%08lX" EXTSEP_S "%s", (ulong)kid[1],
+ image_type_to_string (args.imagetype, 0));
#else
- sprintf(name,"%08lX%08lX" EXTSEP_S "%s",(ulong)kid[0],(ulong)kid[1],
- image_type_to_string(args.imagetype,0));
-#endif
-
- if(exec_write(&spawn,NULL,command,name,1,1)!=0)
- {
- xfree(name);
- goto fail;
- }
-
-#ifdef __riscos__
- riscos_set_filetype_by_mimetype(spawn->tempfile_in,
- image_type_to_string(args.imagetype,2));
+ sprintf (name, "%08lX%08lX" EXTSEP_S "%s",
+ (ulong)kid[0], (ulong)kid[1],
+ image_type_to_string (args.imagetype, 0));
#endif
- xfree(name);
-
- fwrite(&attrs[i].data[offset],attrs[i].len-offset,1,spawn->tochild);
-
- if(exec_read(spawn)!=0)
- {
- exec_finish(spawn);
- goto fail;
- }
-
- if(exec_finish(spawn)!=0)
- goto fail;
+ show_photo (command, name, &attrs[i].data[offset], len);
+ xfree (name);
+ xfree (command);
}
return;
diff --git a/g10/photoid.h b/g10/photoid.h
index fc7ec6fbc..bbf1f493e 100644
--- a/g10/photoid.h
+++ b/g10/photoid.h
@@ -27,7 +27,7 @@
PKT_user_id *generate_photo_id (ctrl_t ctrl,
PKT_public_key *pk,const char *filename);
int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len);
-char *image_type_to_string(byte type,int style);
+const char *image_type_to_string(byte type,int style);
void show_photos (ctrl_t ctrl, const struct user_attribute *attrs, int count,
PKT_public_key *pk, PKT_user_id *uid);
diff --git a/g10/pkclist.c b/g10/pkclist.c
index 1fd23a3e4..996b3ba6e 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -63,8 +63,8 @@ do_show_revocation_reason( PKT_signature *sig )
int seq = 0;
const char *text;
- while( (p = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REVOC_REASON,
- &n, &seq, NULL )) ) {
+ while ((p = enum_sig_subpkt (sig, 1, SIGSUBPKT_REVOC_REASON,
+ &n, &seq, NULL)) ) {
if( !n )
continue; /* invalid - just skip it */
@@ -759,55 +759,6 @@ default_recipient (ctrl_t ctrl)
}
-static int
-expand_id(const char *id,strlist_t *into,unsigned int flags)
-{
- struct groupitem *groups;
- int count=0;
-
- for(groups=opt.grouplist;groups;groups=groups->next)
- {
- /* need strcasecmp() here, as this should be localized */
- if(strcasecmp(groups->name,id)==0)
- {
- strlist_t each,sl;
-
- /* this maintains the current utf8-ness */
- for(each=groups->values;each;each=each->next)
- {
- sl=add_to_strlist(into,each->d);
- sl->flags=flags;
- count++;
- }
-
- break;
- }
- }
-
- return count;
-}
-
-/* For simplicity, and to avoid potential loops, we only expand once -
- * you can't make an alias that points to an alias. */
-static strlist_t
-expand_group (strlist_t input)
-{
- strlist_t output = NULL;
- strlist_t sl, rover;
-
- for (rover = input; rover; rover = rover->next)
- if (!(rover->flags & PK_LIST_FROM_FILE)
- && !expand_id(rover->d,&output,rover->flags))
- {
- /* Didn't find any groups, so use the existing string */
- sl=add_to_strlist(&output,rover->d);
- sl->flags=rover->flags;
- }
-
- return output;
-}
-
-
/* Helper for build_pk_list to find and check one key. This helper is
* also used directly in server mode by the RECIPIENTS command. On
* success the new key is added to PK_LIST_ADDR. NAME is the user id
diff --git a/g10/sign.c b/g10/sign.c
index 8c70b0a2e..250c0cfeb 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -86,7 +86,9 @@ mk_notation_policy_etc (ctrl_t ctrl, PKT_signature *sig,
args.pksk = pksk;
/* Notation data. */
- if (IS_SIG(sig) && opt.sig_notations)
+ if (IS_ATTST_SIGS(sig))
+ ;
+ else if (IS_SIG(sig) && opt.sig_notations)
nd = opt.sig_notations;
else if (IS_CERT(sig) && opt.cert_notations)
nd = opt.cert_notations;
@@ -113,7 +115,9 @@ mk_notation_policy_etc (ctrl_t ctrl, PKT_signature *sig,
}
/* Set policy URL. */
- if (IS_SIG(sig) && opt.sig_policy_url)
+ if (IS_ATTST_SIGS(sig))
+ ;
+ else if (IS_SIG(sig) && opt.sig_policy_url)
pu = opt.sig_policy_url;
else if (IS_CERT(sig) && opt.cert_policy_url)
pu = opt.cert_policy_url;
diff --git a/g10/trustdb.c b/g10/trustdb.c
index 352aecede..64e6ec349 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -303,7 +303,9 @@ verify_own_keys (ctrl_t ctrl)
release_public_key_parts (&pk);
}
- log_info (_("key %s marked as ultimately trusted\n"),keystr(k->kid));
+ if (!opt.quiet)
+ log_info (_("key %s marked as ultimately trusted\n"),
+ keystr(k->kid));
}
}
diff --git a/kbx/keybox-blob.c b/kbx/keybox-blob.c
index ac49ac79c..0fced7e1c 100644
--- a/kbx/keybox-blob.c
+++ b/kbx/keybox-blob.c
@@ -1113,7 +1113,7 @@ _keybox_update_header_blob (KEYBOXBLOB blob, int for_openpgp)
{
u32 val = make_timestamp ();
- /* Update the last maintenance run times tamp. */
+ /* Update the last maintenance run timestamp. */
blob->blob[20] = (val >> 24);
blob->blob[20+1] = (val >> 16);
blob->blob[20+2] = (val >> 8);
diff --git a/kbx/keybox-dump.c b/kbx/keybox-dump.c
index 37646832e..55a47a403 100644
--- a/kbx/keybox-dump.c
+++ b/kbx/keybox-dump.c
@@ -631,6 +631,7 @@ _keybox_dump_file (const char *filename, int stats_only, FILE *outfp)
int rc;
unsigned long count = 0;
struct file_stats_s stats;
+ int skipped_deleted;
memset (&stats, 0, sizeof stats);
@@ -639,7 +640,7 @@ _keybox_dump_file (const char *filename, int stats_only, FILE *outfp)
for (;;)
{
- rc = _keybox_read_blob (&blob, fp, NULL);
+ rc = _keybox_read_blob (&blob, fp, &skipped_deleted);
if (gpg_err_code (rc) == GPG_ERR_TOO_LARGE
&& gpg_err_source (rc) == GPG_ERR_SOURCE_KEYBOX)
{
@@ -656,8 +657,12 @@ _keybox_dump_file (const char *filename, int stats_only, FILE *outfp)
if (rc)
break;
+ count += skipped_deleted;
+
if (stats_only)
{
+ stats.total_blob_count += skipped_deleted;
+ stats.empty_blob_count += skipped_deleted;
update_stats (blob, &stats);
}
else
diff --git a/kbx/keybox-update.c b/kbx/keybox-update.c
index d22da1bf8..fbcaec7b9 100644
--- a/kbx/keybox-update.c
+++ b/kbx/keybox-update.c
@@ -675,7 +675,7 @@ keybox_compress (KEYBOX_HANDLE hd)
{
u32 last_maint = buf32_to_u32 (buffer+20);
- if ( (last_maint + 3*3600) > time (NULL) )
+ if ( (last_maint + 3*3600) > make_timestamp () )
{
fclose (fp);
_keybox_release_blob (blob);
@@ -700,7 +700,7 @@ keybox_compress (KEYBOX_HANDLE hd)
automagically skip any blobs flagged as deleted. Thus what we
only have to do is to check all ephemeral flagged blocks whether
their time has come and write out all other blobs. */
- cut_time = time(NULL) - 86400;
+ cut_time = make_timestamp () - 86400;
first_blob = 1;
skipped_deleted = 0;
for (rc=0; !(read_rc = _keybox_read_blob (&blob, fp, &skipped_deleted));
diff --git a/scd/apdu.c b/scd/apdu.c
index 2df113c5e..f86a63897 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -55,7 +55,7 @@
#include "ccid-driver.h"
struct dev_list {
- struct ccid_dev_table *ccid_table;
+ void *table;
const char *portstr;
int idx;
int idx_max;
@@ -76,6 +76,19 @@ typedef unsigned int pcsc_dword_t;
typedef unsigned long pcsc_dword_t;
#endif
+#ifdef HAVE_W32_SYSTEM
+#define HANDLE uintptr_t
+#else
+#define HANDLE long
+#endif
+
+/* PC/SC context to access readers. Shared among all readers. */
+static struct pcsc_global_data {
+ HANDLE context;
+ int count;
+ const char *rdrname[MAX_READER];
+} pcsc;
+
/* A structure to collect information pertaining to one reader
slot. */
struct reader_table_s {
@@ -101,8 +114,7 @@ struct reader_table_s {
ccid_driver_t handle;
} ccid;
struct {
- long context;
- long card;
+ HANDLE card;
pcsc_dword_t protocol;
pcsc_dword_t verify_ioctl;
pcsc_dword_t modify_ioctl;
@@ -288,35 +300,35 @@ typedef struct pcsc_readerstate_s *pcsc_readerstate_t;
long (* DLSTDCALL pcsc_establish_context) (pcsc_dword_t scope,
const void *reserved1,
const void *reserved2,
- long *r_context);
-long (* DLSTDCALL pcsc_release_context) (long context);
-long (* DLSTDCALL pcsc_list_readers) (long context,
+ HANDLE *r_context);
+long (* DLSTDCALL pcsc_release_context) (HANDLE context);
+long (* DLSTDCALL pcsc_list_readers) (HANDLE context,
const char *groups,
char *readers, pcsc_dword_t*readerslen);
-long (* DLSTDCALL pcsc_get_status_change) (long context,
+long (* DLSTDCALL pcsc_get_status_change) (HANDLE context,
pcsc_dword_t timeout,
pcsc_readerstate_t readerstates,
pcsc_dword_t nreaderstates);
-long (* DLSTDCALL pcsc_connect) (long context,
+long (* DLSTDCALL pcsc_connect) (HANDLE context,
const char *reader,
pcsc_dword_t share_mode,
pcsc_dword_t preferred_protocols,
- long *r_card,
+ HANDLE *r_card,
pcsc_dword_t *r_active_protocol);
-long (* DLSTDCALL pcsc_reconnect) (long card,
+long (* DLSTDCALL pcsc_reconnect) (HANDLE card,
pcsc_dword_t share_mode,
pcsc_dword_t preferred_protocols,
pcsc_dword_t initialization,
pcsc_dword_t *r_active_protocol);
-long (* DLSTDCALL pcsc_disconnect) (long card,
+long (* DLSTDCALL pcsc_disconnect) (HANDLE card,
pcsc_dword_t disposition);
-long (* DLSTDCALL pcsc_status) (long card,
+long (* DLSTDCALL pcsc_status) (HANDLE card,
char *reader, pcsc_dword_t *readerlen,
pcsc_dword_t *r_state,
pcsc_dword_t *r_protocol,
unsigned char *atr, pcsc_dword_t *atrlen);
long (* DLSTDCALL pcsc_begin_transaction) (long card);
-long (* DLSTDCALL pcsc_end_transaction) (long card,
+long (* DLSTDCALL pcsc_end_transaction) (HANDLE card,
pcsc_dword_t disposition);
long (* DLSTDCALL pcsc_transmit) (long card,
const pcsc_io_request_t send_pci,
@@ -325,9 +337,9 @@ long (* DLSTDCALL pcsc_transmit) (long card,
pcsc_io_request_t recv_pci,
unsigned char *recv_buffer,
pcsc_dword_t *recv_len);
-long (* DLSTDCALL pcsc_set_timeout) (long context,
+long (* DLSTDCALL pcsc_set_timeout) (HANDLE context,
pcsc_dword_t timeout);
-long (* DLSTDCALL pcsc_control) (long card,
+long (* DLSTDCALL pcsc_control) (HANDLE card,
pcsc_dword_t control_code,
const void *send_buffer,
pcsc_dword_t send_len,
@@ -652,9 +664,7 @@ pcsc_get_status (int slot, unsigned int *status, int on_wire)
memset (rdrstates, 0, sizeof *rdrstates);
rdrstates[0].reader = reader_table[slot].rdrname;
rdrstates[0].current_state = reader_table[slot].pcsc.current_state;
- err = pcsc_get_status_change (reader_table[slot].pcsc.context,
- 0,
- rdrstates, 1);
+ err = pcsc_get_status_change (pcsc.context, 0, rdrstates, 1);
if (err == PCSC_E_TIMEOUT)
err = 0; /* Timeout is no error here. */
if (err)
@@ -788,7 +798,16 @@ control_pcsc (int slot, pcsc_dword_t ioctl_code,
static int
close_pcsc_reader (int slot)
{
- pcsc_release_context (reader_table[slot].pcsc.context);
+ (void)slot;
+ if (--pcsc.count == 0)
+ {
+ int i;
+
+ pcsc_release_context (pcsc.context);
+ pcsc.context = 0;
+ for (i = 0; i < MAX_READER; i++)
+ pcsc.rdrname[i] = NULL;
+ }
return 0;
}
@@ -807,7 +826,7 @@ connect_pcsc_card (int slot)
reader_table[slot].atrlen = 0;
reader_table[slot].is_t0 = 0;
- err = pcsc_connect (reader_table[slot].pcsc.context,
+ err = pcsc_connect (pcsc.context,
reader_table[slot].rdrname,
PCSC_SHARE_EXCLUSIVE,
PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
@@ -829,7 +848,7 @@ connect_pcsc_card (int slot)
pcsc_vendor_specific_init (slot);
atrlen = DIM (reader_table[0].atr);
- readerlen = sizeof reader -1 ;
+ readerlen = sizeof reader - 1;
err = pcsc_status (reader_table[slot].pcsc.card,
reader, &readerlen,
&card_state, &card_protocol,
@@ -1042,94 +1061,128 @@ pcsc_vendor_specific_init (int slot)
return 0;
}
-
-/* Open the PC/SC reader without using the wrapper. Returns -1 on
- error or a slot number for the reader. */
static int
-open_pcsc_reader (const char *portstr)
+pcsc_init (void)
{
+ static int pcsc_api_loaded;
long err;
- int slot;
- char *list = NULL;
- char *rdrname = NULL;
- pcsc_dword_t nreader;
- char *p;
-
- slot = new_reader_slot ();
- if (slot == -1)
- return -1;
- /* Fixme: Allocating a context for each slot is not required. One
- global context should be sufficient. */
- err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL,
- &reader_table[slot].pcsc.context);
- if (err)
+ /* Lets try the PC/SC API */
+ if (!pcsc_api_loaded)
{
- log_error ("pcsc_establish_context failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- reader_table[slot].used = 0;
- unlock_slot (slot);
- return -1;
- }
+ void *handle;
- err = pcsc_list_readers (reader_table[slot].pcsc.context,
- NULL, NULL, &nreader);
- if (!err)
- {
- list = xtrymalloc (nreader+1); /* Better add 1 for safety reasons. */
- if (!list)
+ handle = dlopen (opt.pcsc_driver, RTLD_LAZY);
+ if (!handle)
{
- log_error ("error allocating memory for reader list\n");
- pcsc_release_context (reader_table[slot].pcsc.context);
- reader_table[slot].used = 0;
- unlock_slot (slot);
- return -1 /*SW_HOST_OUT_OF_CORE*/;
+ log_error ("apdu_open_reader: failed to open driver '%s': %s\n",
+ opt.pcsc_driver, dlerror ());
+ return -1;
+ }
+
+ pcsc_establish_context = dlsym (handle, "SCardEstablishContext");
+ pcsc_release_context = dlsym (handle, "SCardReleaseContext");
+ pcsc_list_readers = dlsym (handle, "SCardListReaders");
+#if defined(_WIN32) || defined(__CYGWIN__)
+ if (!pcsc_list_readers)
+ pcsc_list_readers = dlsym (handle, "SCardListReadersA");
+#endif
+ pcsc_get_status_change = dlsym (handle, "SCardGetStatusChange");
+#if defined(_WIN32) || defined(__CYGWIN__)
+ if (!pcsc_get_status_change)
+ pcsc_get_status_change = dlsym (handle, "SCardGetStatusChangeA");
+#endif
+ pcsc_connect = dlsym (handle, "SCardConnect");
+#if defined(_WIN32) || defined(__CYGWIN__)
+ if (!pcsc_connect)
+ pcsc_connect = dlsym (handle, "SCardConnectA");
+#endif
+ pcsc_reconnect = dlsym (handle, "SCardReconnect");
+#if defined(_WIN32) || defined(__CYGWIN__)
+ if (!pcsc_reconnect)
+ pcsc_reconnect = dlsym (handle, "SCardReconnectA");
+#endif
+ pcsc_disconnect = dlsym (handle, "SCardDisconnect");
+ pcsc_status = dlsym (handle, "SCardStatus");
+#if defined(_WIN32) || defined(__CYGWIN__)
+ if (!pcsc_status)
+ pcsc_status = dlsym (handle, "SCardStatusA");
+#endif
+ pcsc_begin_transaction = dlsym (handle, "SCardBeginTransaction");
+ pcsc_end_transaction = dlsym (handle, "SCardEndTransaction");
+ pcsc_transmit = dlsym (handle, "SCardTransmit");
+ pcsc_set_timeout = dlsym (handle, "SCardSetTimeout");
+ pcsc_control = dlsym (handle, "SCardControl");
+
+ if (!pcsc_establish_context
+ || !pcsc_release_context
+ || !pcsc_list_readers
+ || !pcsc_get_status_change
+ || !pcsc_connect
+ || !pcsc_reconnect
+ || !pcsc_disconnect
+ || !pcsc_status
+ || !pcsc_begin_transaction
+ || !pcsc_end_transaction
+ || !pcsc_transmit
+ || !pcsc_control
+ /* || !pcsc_set_timeout */)
+ {
+ /* Note that set_timeout is currently not used and also not
+ available under Windows. */
+ log_error ("apdu_open_reader: invalid PC/SC driver "
+ "(%d%d%d%d%d%d%d%d%d%d%d%d%d)\n",
+ !!pcsc_establish_context,
+ !!pcsc_release_context,
+ !!pcsc_list_readers,
+ !!pcsc_get_status_change,
+ !!pcsc_connect,
+ !!pcsc_reconnect,
+ !!pcsc_disconnect,
+ !!pcsc_status,
+ !!pcsc_begin_transaction,
+ !!pcsc_end_transaction,
+ !!pcsc_transmit,
+ !!pcsc_set_timeout,
+ !!pcsc_control );
+ dlclose (handle);
+ return -1;
}
- err = pcsc_list_readers (reader_table[slot].pcsc.context,
- NULL, list, &nreader);
+ pcsc_api_loaded = 1;
}
+
+ err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL,
+ &pcsc.context);
if (err)
{
- log_error ("pcsc_list_readers failed: %s (0x%lx)\n",
+ log_error ("pcsc_establish_context failed: %s (0x%lx)\n",
pcsc_error_string (err), err);
- pcsc_release_context (reader_table[slot].pcsc.context);
- reader_table[slot].used = 0;
- xfree (list);
- unlock_slot (slot);
return -1;
}
- p = list;
- while (nreader)
- {
- if (!*p && !p[1])
- break;
- log_info ("detected reader '%s'\n", p);
- if (nreader < (strlen (p)+1))
- {
- log_error ("invalid response from pcsc_list_readers\n");
- break;
- }
- if (!rdrname && portstr && !strncmp (p, portstr, strlen (portstr)))
- rdrname = p;
- nreader -= strlen (p)+1;
- p += strlen (p) + 1;
- }
+ return 0;
+}
- if (!rdrname)
- rdrname = list;
+/* Open the PC/SC reader. Returns -1 on error or a slot number for
+ the reader. */
+static int
+open_pcsc_reader (const char *rdrname)
+{
+ int slot;
+
+ slot = new_reader_slot ();
+ if (slot == -1)
+ return -1;
reader_table[slot].rdrname = xtrystrdup (rdrname);
if (!reader_table[slot].rdrname)
{
log_error ("error allocating memory for reader name\n");
- pcsc_release_context (reader_table[slot].pcsc.context);
+ close_pcsc_reader (0);
reader_table[slot].used = 0;
unlock_slot (slot);
return -1;
}
- xfree (list);
- list = NULL;
reader_table[slot].pcsc.card = 0;
reader_table[slot].atrlen = 0;
@@ -1142,6 +1195,7 @@ open_pcsc_reader (const char *portstr)
reader_table[slot].send_apdu_reader = pcsc_send_apdu;
reader_table[slot].dump_status_reader = dump_pcsc_reader_status;
+ pcsc.count++;
dump_reader_status (slot);
unlock_slot (slot);
return slot;
@@ -1520,7 +1574,7 @@ open_ccid_reader (struct dev_list *dl)
return -1;
slotp = reader_table + slot;
- err = ccid_open_reader (dl->portstr, dl->idx, dl->ccid_table,
+ err = ccid_open_reader (dl->portstr, dl->idx, dl->table,
&slotp->ccid.handle, &slotp->rdrname);
if (!err)
{
@@ -1866,51 +1920,111 @@ gpg_error_t
apdu_dev_list_start (const char *portstr, struct dev_list **l_p)
{
struct dev_list *dl = xtrymalloc (sizeof (struct dev_list));
+ gpg_error_t err;
*l_p = NULL;
if (!dl)
return gpg_error_from_syserror ();
+ dl->table = NULL;
dl->portstr = portstr;
dl->idx = 0;
+ dl->idx_max = 0;
npth_mutex_lock (&reader_table_lock);
#ifdef HAVE_LIBUSB
- if (opt.disable_ccid)
+ if (!opt.disable_ccid)
{
- dl->ccid_table = NULL;
- dl->idx_max = 1;
+ err = ccid_dev_scan (&dl->idx_max, &dl->table);
+ if (err)
+ {
+ npth_mutex_unlock (&reader_table_lock);
+ return err;
+ }
+
+ if (dl->idx_max == 0)
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_open_reader => slot=-1 (no ccid)\n");
+
+ xfree (dl);
+ npth_mutex_unlock (&reader_table_lock);
+ return gpg_error (GPG_ERR_ENODEV);
+ }
}
else
- {
- gpg_error_t err;
+#endif
+ { /* PC/SC readers. */
+ long r;
+ pcsc_dword_t nreader;
+ char *p = NULL;
- err = ccid_dev_scan (&dl->idx_max, &dl->ccid_table);
- if (err)
- return err;
+ if (!pcsc.context)
+ if (pcsc_init () < 0)
+ {
+ npth_mutex_unlock (&reader_table_lock);
+ return gpg_error (GPG_ERR_NO_SERVICE);
+ }
- if (dl->idx_max == 0)
+ r = pcsc_list_readers (pcsc.context, NULL, NULL, &nreader);
+ if (!r)
{
- /* If a CCID reader specification has been given, the user does
- not want a fallback to other drivers. */
- if (portstr && strlen (portstr) > 5 && portstr[4] == ':')
+ p = xtrymalloc (nreader);
+ if (!p)
{
- if (DBG_READER)
- log_debug ("leave: apdu_open_reader => slot=-1 (no ccid)\n");
+ err = gpg_error_from_syserror ();
- xfree (dl);
+ log_error ("error allocating memory for reader list\n");
+ close_pcsc_reader (0);
npth_mutex_unlock (&reader_table_lock);
- return gpg_error (GPG_ERR_ENODEV);
+ return err;
+ }
+ r = pcsc_list_readers (pcsc.context, NULL, p, &nreader);
+ }
+ if (r)
+ {
+ log_error ("pcsc_list_readers failed: %s (0x%lx)\n",
+ pcsc_error_string (r), r);
+ xfree (p);
+ close_pcsc_reader (0);
+ npth_mutex_unlock (&reader_table_lock);
+ return gpg_error (GPG_ERR_NO_SERVICE);
+ }
+
+ dl->table = p;
+ dl->idx_max = 0;
+
+ while (nreader > 0)
+ {
+ size_t n;
+
+ if (!*p)
+ break;
+
+ for (n = 0; n < nreader; n++)
+ if (!p[n])
+ break;
+
+ if (n >= nreader)
+ {
+ log_error ("invalid response from pcsc_list_readers\n");
+ break;
+ }
+
+ log_info ("detected reader '%s'\n", p);
+ pcsc.rdrname[dl->idx_max] = p;
+ nreader -= n + 1;
+ p += n + 1;
+ dl->idx_max++;
+ if (dl->idx_max > MAX_READER)
+ {
+ log_error ("too many readers from pcsc_list_readers\n");
+ dl->idx_max--;
+ break;
}
- else
- dl->idx_max = 1;
}
}
-#else
- dl->ccid_table = NULL;
- dl->idx_max = 1;
-#endif /* HAVE_LIBUSB */
*l_p = dl;
return 0;
@@ -1920,161 +2034,65 @@ void
apdu_dev_list_finish (struct dev_list *dl)
{
#ifdef HAVE_LIBUSB
- if (dl->ccid_table)
- ccid_dev_scan_finish (dl->ccid_table, dl->idx_max);
+ if (!opt.disable_ccid)
+ {
+ if (dl->table)
+ ccid_dev_scan_finish (dl->table, dl->idx_max);
+ }
+ else
#endif
+ { /* PC/SC readers. */
+ int i;
+
+ xfree (dl->table);
+ for (i = 0; i < MAX_READER; i++)
+ pcsc.rdrname[i] = NULL;
+ }
xfree (dl);
npth_mutex_unlock (&reader_table_lock);
}
-/* Open the reader and return an internal slot number or -1 on
- error. If PORTSTR is NULL we default to a suitable port (for ctAPI:
- the first USB reader. For PC/SC the first listed reader). */
-static int
-apdu_open_one_reader (const char *portstr)
+int
+apdu_open_reader (struct dev_list *dl)
{
- static int pcsc_api_loaded;
int slot;
+ int readerno;
- if (DBG_READER)
- log_debug ("enter: apdu_open_reader: portstr=%s\n", portstr);
+ if (!dl->table)
+ return -1;
- /* Lets try the PC/SC API */
- if (!pcsc_api_loaded)
+ /* See whether we want to use the reader ID string or a reader
+ number. A readerno of -1 indicates that the reader ID string is
+ to be used. */
+ if (dl->portstr && strchr (dl->portstr, ':'))
+ readerno = -1; /* We want to use the readerid. */
+ else if (dl->portstr)
{
- void *handle;
-
- handle = dlopen (opt.pcsc_driver, RTLD_LAZY);
- if (!handle)
- {
- log_error ("apdu_open_reader: failed to open driver '%s': %s\n",
- opt.pcsc_driver, dlerror ());
- return -1;
- }
+ readerno = atoi (dl->portstr);
+ if (readerno < 0 || readerno >= dl->idx_max)
+ return -1;
- pcsc_establish_context = dlsym (handle, "SCardEstablishContext");
- pcsc_release_context = dlsym (handle, "SCardReleaseContext");
- pcsc_list_readers = dlsym (handle, "SCardListReaders");
-#if defined(_WIN32) || defined(__CYGWIN__)
- if (!pcsc_list_readers)
- pcsc_list_readers = dlsym (handle, "SCardListReadersA");
-#endif
- pcsc_get_status_change = dlsym (handle, "SCardGetStatusChange");
-#if defined(_WIN32) || defined(__CYGWIN__)
- if (!pcsc_get_status_change)
- pcsc_get_status_change = dlsym (handle, "SCardGetStatusChangeA");
-#endif
- pcsc_connect = dlsym (handle, "SCardConnect");
-#if defined(_WIN32) || defined(__CYGWIN__)
- if (!pcsc_connect)
- pcsc_connect = dlsym (handle, "SCardConnectA");
-#endif
- pcsc_reconnect = dlsym (handle, "SCardReconnect");
-#if defined(_WIN32) || defined(__CYGWIN__)
- if (!pcsc_reconnect)
- pcsc_reconnect = dlsym (handle, "SCardReconnectA");
-#endif
- pcsc_disconnect = dlsym (handle, "SCardDisconnect");
- pcsc_status = dlsym (handle, "SCardStatus");
-#if defined(_WIN32) || defined(__CYGWIN__)
- if (!pcsc_status)
- pcsc_status = dlsym (handle, "SCardStatusA");
-#endif
- pcsc_begin_transaction = dlsym (handle, "SCardBeginTransaction");
- pcsc_end_transaction = dlsym (handle, "SCardEndTransaction");
- pcsc_transmit = dlsym (handle, "SCardTransmit");
- pcsc_set_timeout = dlsym (handle, "SCardSetTimeout");
- pcsc_control = dlsym (handle, "SCardControl");
-
- if (!pcsc_establish_context
- || !pcsc_release_context
- || !pcsc_list_readers
- || !pcsc_get_status_change
- || !pcsc_connect
- || !pcsc_reconnect
- || !pcsc_disconnect
- || !pcsc_status
- || !pcsc_begin_transaction
- || !pcsc_end_transaction
- || !pcsc_transmit
- || !pcsc_control
- /* || !pcsc_set_timeout */)
- {
- /* Note that set_timeout is currently not used and also not
- available under Windows. */
- log_error ("apdu_open_reader: invalid PC/SC driver "
- "(%d%d%d%d%d%d%d%d%d%d%d%d%d)\n",
- !!pcsc_establish_context,
- !!pcsc_release_context,
- !!pcsc_list_readers,
- !!pcsc_get_status_change,
- !!pcsc_connect,
- !!pcsc_reconnect,
- !!pcsc_disconnect,
- !!pcsc_status,
- !!pcsc_begin_transaction,
- !!pcsc_end_transaction,
- !!pcsc_transmit,
- !!pcsc_set_timeout,
- !!pcsc_control );
- dlclose (handle);
- return -1;
- }
- pcsc_api_loaded = 1;
+ dl->idx = readerno;
+ dl->portstr = NULL;
}
-
- slot = open_pcsc_reader (portstr);
-
- if (DBG_READER)
- log_debug ("leave: apdu_open_reader => slot=%d [pc/sc]\n", slot);
- return slot;
-}
-
-int
-apdu_open_reader (struct dev_list *dl, int app_empty)
-{
- int slot;
+ else
+ readerno = 0; /* Default. */
#ifdef HAVE_LIBUSB
- if (dl->ccid_table)
+ if (!opt.disable_ccid)
{ /* CCID readers. */
- int readerno;
-
- /* See whether we want to use the reader ID string or a reader
- number. A readerno of -1 indicates that the reader ID string is
- to be used. */
- if (dl->portstr && strchr (dl->portstr, ':'))
- readerno = -1; /* We want to use the readerid. */
- else if (dl->portstr)
- {
- readerno = atoi (dl->portstr);
- if (readerno < 0)
- {
- return -1;
- }
- }
- else
- readerno = 0; /* Default. */
-
if (readerno > 0)
{ /* Use single, the specific reader. */
- if (readerno >= dl->idx_max)
- return -1;
-
- dl->idx = readerno;
- dl->portstr = NULL;
slot = open_ccid_reader (dl);
+ /* And stick the reader and no scan. */
dl->idx = dl->idx_max;
- if (slot >= 0)
- return slot;
- else
- return -1;
+ return slot;
}
while (dl->idx < dl->idx_max)
{
- unsigned int bai = ccid_get_BAI (dl->idx, dl->ccid_table);
+ unsigned int bai = ccid_get_BAI (dl->idx, dl->table);
if (DBG_READER)
log_debug ("apdu_open_reader: BAI=%x\n", bai);
@@ -2107,25 +2125,60 @@ apdu_open_reader (struct dev_list *dl, int app_empty)
dl->idx++;
}
- /* Not found. Try one for PC/SC, only when it's the initial scan. */
- if (app_empty && dl->idx == dl->idx_max)
- {
- dl->idx++;
- slot = apdu_open_one_reader (dl->portstr);
- }
- else
- slot = -1;
+ /* Not found. */
+ slot = -1;
}
else
#endif
{ /* PC/SC readers. */
- if (app_empty && dl->idx == 0)
+ if (readerno > 0)
+ { /* Use single, the specific reader. */
+ slot = open_pcsc_reader (pcsc.rdrname[readerno]);
+ /* And stick the reader and no scan. */
+ dl->idx = dl->idx_max;
+ return slot;
+ }
+
+ while (dl->idx < dl->idx_max)
{
- dl->idx++;
- slot = apdu_open_one_reader (dl->portstr);
+ const char *rdrname = pcsc.rdrname[dl->idx];
+
+ if (DBG_READER)
+ log_debug ("apdu_open_reader: %s\n", rdrname);
+
+ /* Check the identity of reader against already opened one. */
+ for (slot = 0; slot < MAX_READER; slot++)
+ if (reader_table[slot].used
+ && !strcmp (reader_table[slot].rdrname, rdrname))
+ break;
+
+ if (slot == MAX_READER)
+ { /* Found a new device. */
+ if (DBG_READER)
+ log_debug ("apdu_open_reader: new device=%s\n", rdrname);
+
+ /* When reader string is specified, check if it is the one. */
+ if (readerno < 0 && strcmp (rdrname, dl->portstr) != 0)
+ continue;
+
+ slot = open_pcsc_reader (rdrname);
+
+ dl->idx++;
+ if (slot >= 0)
+ return slot;
+ else
+ {
+ /* Skip this reader. */
+ log_error ("pcsc open error: skip\n");
+ continue;
+ }
+ }
+ else
+ dl->idx++;
}
- else
- slot = -1;
+
+ /* Not found. */
+ slot = -1;
}
return slot;
@@ -3305,6 +3358,11 @@ apdu_init (void)
gpg_error_t err;
int i;
+ pcsc.count = 0;
+ pcsc.context = 0;
+ for (i = 0; i < MAX_READER; i++)
+ pcsc.rdrname[i] = NULL;
+
if (npth_mutex_init (&reader_table_lock, NULL))
goto leave;
diff --git a/scd/apdu.h b/scd/apdu.h
index 89df45cb8..cdf94ccca 100644
--- a/scd/apdu.h
+++ b/scd/apdu.h
@@ -93,7 +93,7 @@ gpg_error_t apdu_dev_list_start (const char *portstr, struct dev_list **l_p);
void apdu_dev_list_finish (struct dev_list *l);
/* Note, that apdu_open_reader returns no status word but -1 on error. */
-int apdu_open_reader (struct dev_list *l, int app_empty);
+int apdu_open_reader (struct dev_list *l);
int apdu_open_remote_reader (const char *portstr,
const unsigned char *cookie, size_t length,
int (*readfnc) (void *opaque,
diff --git a/scd/app-common.h b/scd/app-common.h
index 5866c9b32..87f63bb7e 100644
--- a/scd/app-common.h
+++ b/scd/app-common.h
@@ -39,9 +39,13 @@
/* Flags used with app_readkey. */
#define APP_READKEY_FLAG_INFO 1 /* Send also a KEYPAIRINFO line. */
-/* Bit flags set by the decipher function into R_INFO. */
+/* Flags set by the decipher function into R_INFO. */
#define APP_DECIPHER_INFO_NOPAD 1 /* Padding has been removed. */
+/* Flags used by the app_write_learn_status. */
+#define APP_LEARN_FLAG_KEYPAIRINFO 1 /* Return only keypair infos. */
+#define APP_LEARN_FLAG_MULTI 2 /* Return info for all apps. */
+
/* List of supported card types. Generic is the usual ISO7817-4
* compliant card. More specific card or token versions can be given
diff --git a/scd/app-nks.c b/scd/app-nks.c
index d12720cf6..bb5329bfe 100644
--- a/scd/app-nks.c
+++ b/scd/app-nks.c
@@ -309,8 +309,10 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
int special;
} table[] = {
{ "$AUTHKEYID", 1 },
- { "NKS-VERSION", 2 },
- { "CHV-STATUS", 3 },
+ { "$ENCRKEYID", 2 },
+ { "$SIGNKEYID", 3 },
+ { "NKS-VERSION", 4 },
+ { "CHV-STATUS", 5 },
{ NULL, 0 }
};
gpg_error_t err = 0;
@@ -340,13 +342,27 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
}
break;
- case 2: /* NKS-VERSION */
+ case 2: /* $ENCRKEYID */
+ {
+ char const tmp[] = "NKS-NKS3.45B1";
+ send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
+ }
+ break;
+
+ case 3: /* $SIGNKEYID */
+ {
+ char const tmp[] = "NKS-NKS3.4531";
+ send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
+ }
+ break;
+
+ case 4: /* NKS-VERSION */
snprintf (buffer, sizeof buffer, "%d", app->app_local->nks_version);
send_status_info (ctrl, table[idx].name,
buffer, strlen (buffer), NULL, 0);
break;
- case 3: /* CHV-STATUS */
+ case 5: /* CHV-STATUS */
{
/* Returns: PW1.CH PW2.CH PW1.CH.SIG PW2.CH.SIG That are the
two global passwords followed by the two SigG passwords.
@@ -386,6 +402,7 @@ do_learn_status_core (app_t app, ctrl_t ctrl, unsigned int flags, int is_sigg)
char ct_buf[100], id_buf[100];
int i;
const char *tag;
+ const char *usage;
if (is_sigg)
tag = "SIGG";
@@ -403,7 +420,7 @@ do_learn_status_core (app_t app, ctrl_t ctrl, unsigned int flags, int is_sigg)
if (!!filelist[i].is_sigg != !!is_sigg)
continue;
- if (filelist[i].certtype && !(flags &1))
+ if (filelist[i].certtype && !(flags & APP_LEARN_FLAG_KEYPAIRINFO))
{
size_t len;
@@ -435,9 +452,19 @@ do_learn_status_core (app_t app, ctrl_t ctrl, unsigned int flags, int is_sigg)
{
snprintf (id_buf, sizeof id_buf, "NKS-%s.%04X",
tag, filelist[i].fid);
+ if (filelist[i].issignkey && filelist[i].isenckey)
+ usage = "sae";
+ else if (filelist[i].issignkey)
+ usage = "sa";
+ else if (filelist[i].isenckey)
+ usage = "e";
+ else
+ usage = "";
+
send_status_info (ctrl, "KEYPAIRINFO",
gripstr, 40,
id_buf, strlen (id_buf),
+ usage, strlen (usage),
NULL, (size_t)0);
}
}
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index 767f29d26..4f76caac3 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -4296,7 +4296,8 @@ check_against_given_fingerprint (app_t app, const char *fpr, int key)
KEYIDSTR is either:
(1) Serial number
(2) Serial number "/" fingerprint
- (3) keygrip
+ (3) Serial number "[CHV3]"
+ (4) keygrip
When KEYNO is 0 and KEYIDSTR is for a keygrip, the keygrip should
be to be compared is the first one (keygrip for signing).
@@ -4335,8 +4336,6 @@ check_keyidstr (app_t app, const char *keyidstr, int keyno)
; /* no fingerprint given: we allow this for now. */
else if (*s == '/')
fpr = s + 1;
- else
- return gpg_error (GPG_ERR_INV_ID);
for (s=keyidstr, n=0; n < 16; s += 2, n++)
tmp_sn[n] = xtoi_2 (s);
@@ -5229,6 +5228,12 @@ do_reselect (app_t app, ctrl_t ctrl)
* a special flag value. */
err = iso7816_select_application (app_get_slot (app),
openpgp_aid, sizeof openpgp_aid, 0x0001);
+ if (!err)
+ {
+ app->did_chv1 = 0;
+ app->did_chv2 = 0;
+ app->did_chv3 = 0;
+ }
return err;
}
diff --git a/scd/app-p15.c b/scd/app-p15.c
index ce82b34a9..348242f4f 100644
--- a/scd/app-p15.c
+++ b/scd/app-p15.c
@@ -2500,7 +2500,7 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
{
gpg_error_t err;
- if ((flags & 1))
+ if ((flags & APP_LEARN_FLAG_KEYPAIRINFO))
err = 0;
else
{
diff --git a/scd/app-piv.c b/scd/app-piv.c
index 3b94a28e4..3cc7754df 100644
--- a/scd/app-piv.c
+++ b/scd/app-piv.c
@@ -1176,7 +1176,8 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
for (i=0; data_objects[i].tag; i++)
if (data_objects[i].keypair)
- send_keypair_and_cert_info (app, ctrl, data_objects + i, !!(flags & 1));
+ send_keypair_and_cert_info (app, ctrl, data_objects + i,
+ !!(flags & APP_LEARN_FLAG_KEYPAIRINFO));
return 0;
@@ -1365,7 +1366,7 @@ find_dobj_by_keyref (app_t app, const char *keyref)
(void)app;
- if (!ascii_strncasecmp (keyref, "PIV.", 4))
+ if (!ascii_strncasecmp (keyref, "PIV.", 4)) /* Standard keyref */
{
keyref += 4;
for (i=0; data_objects[i].tag; i++)
@@ -1375,7 +1376,7 @@ find_dobj_by_keyref (app_t app, const char *keyref)
return data_objects + i;
}
}
- else if (!strncmp (keyref, "2.16.840.1.101.3.7.", 19))
+ else if (!strncmp (keyref, "2.16.840.1.101.3.7.", 19)) /* OID */
{
keyref += 19;
for (i=0; data_objects[i].tag; i++)
@@ -1385,6 +1386,26 @@ find_dobj_by_keyref (app_t app, const char *keyref)
return data_objects + i;
}
}
+ else if (strlen (keyref) == 40) /* A keygrip */
+ {
+ char *keygripstr = NULL;
+ int tag, dummy_got_cert;
+
+ for (i=0; (tag=data_objects[i].tag); i++)
+ {
+ if (!data_objects[i].keypair)
+ continue;
+ xfree (keygripstr);
+ if (get_keygrip_by_tag (app, tag, &keygripstr, &dummy_got_cert))
+ continue;
+ if (!strcmp (keygripstr, keyref))
+ {
+ xfree (keygripstr);
+ return data_objects + i;
+ }
+ }
+ xfree (keygripstr);
+ }
return NULL;
}
diff --git a/scd/app-sc-hsm.c b/scd/app-sc-hsm.c
index 16d25b581..2f1ab2074 100644
--- a/scd/app-sc-hsm.c
+++ b/scd/app-sc-hsm.c
@@ -1407,7 +1407,7 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
{
gpg_error_t err;
- if ((flags & 1))
+ if ((flags & APP_LEARN_FLAG_KEYPAIRINFO))
err = 0;
else
{
diff --git a/scd/app.c b/scd/app.c
index 57c4b7743..fff2b307f 100644
--- a/scd/app.c
+++ b/scd/app.c
@@ -30,6 +30,11 @@
#include "apdu.h"
#include "../common/tlv.h"
+
+/* Forward declaration of internal function. */
+static gpg_error_t
+select_additional_application_internal (card_t card, apptype_t req_apptype);
+
/* Lock to protect the list of cards and its associated
* applications. */
static npth_mutex_t card_list_lock;
@@ -91,6 +96,13 @@ strapptype (apptype_t t)
}
+const char *
+xstrapptype (app_t app)
+{
+ return app? strapptype (app->apptype) : "[no_app]";
+}
+
+
/* Return the apptype for NAME. */
static apptype_t
apptype_from_name (const char *name)
@@ -109,6 +121,31 @@ apptype_from_name (const char *name)
}
+/* Return the apptype for KEYREF. This is the first part of the
+ * KEYREF up to the dot. */
+static apptype_t
+apptype_from_keyref (const char *keyref)
+{
+ int i;
+ unsigned int n;
+ const char *s;
+
+ if (!keyref)
+ return APPTYPE_NONE;
+ s = strchr (keyref, '.');
+ if (!s || s == keyref || !s[1])
+ return APPTYPE_NONE; /* Not a valid keyref. */
+ n = s - keyref;
+
+ for (i=0; app_priority_list[i].apptype; i++)
+ if (strlen (app_priority_list[i].name) == n
+ && !ascii_strncasecmp (app_priority_list[i].name, keyref, n))
+ return app_priority_list[i].apptype;
+
+ return APPTYPE_NONE;
+}
+
+
/* Initialization function to change the default app_priority_list.
* LIST is a list of comma or space separated strings with application
* names. Unknown names will only result in warning message.
@@ -231,6 +268,7 @@ app_dump_state (void)
{
log_info ("app_dump_state: card=%p slot=%d type=%s\n",
c, c->slot, strcardtype (c->cardtype));
+ /* FIXME The use of log_info risks a race! */
for (a=c->app; a; a = a->next)
log_info ("app_dump_state: app=%p type='%s'\n",
a, strapptype (a->apptype));
@@ -270,7 +308,7 @@ check_application_conflict (card_t card, const char *name,
const unsigned char *serialno_bin,
size_t serialno_bin_len)
{
- app_t app;
+ apptype_t apptype;
if (!card || !name)
return 0;
@@ -284,11 +322,9 @@ check_application_conflict (card_t card, const char *name,
return 0; /* The card does not match the requested S/N. */
}
- /* Check whether the requested NAME matches any already selected
- * application. */
- for (app = card->app; app; app = app->next)
- if (!ascii_strcasecmp (strapptype (app->apptype), name))
- return 0;
+ apptype = apptype_from_name (name);
+ if (card->app->apptype == apptype)
+ return 0;
if (card->app->apptype == APPTYPE_UNDEFINED)
return 0;
@@ -339,6 +375,7 @@ card_reset (card_t card, ctrl_t ctrl, int send_reset)
else
{
ctrl->card_ctx = NULL;
+ ctrl->current_apptype = APPTYPE_NONE;
card_unref (card);
}
@@ -608,7 +645,7 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card,
int slot;
int periodical_check_needed_this;
- slot = apdu_open_reader (l, !card_top);
+ slot = apdu_open_reader (l);
if (slot < 0)
break;
@@ -652,6 +689,22 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card,
{
err = check_application_conflict (card, name, NULL, 0);
if (!err)
+ ctrl->current_apptype = card->app ? card->app->apptype : APPTYPE_NONE;
+ else if (gpg_err_code (err) == GPG_ERR_FALSE)
+ {
+ apptype_t req_apptype = apptype_from_name (name);
+
+ if (!req_apptype)
+ err = gpg_error (GPG_ERR_NOT_FOUND);
+ else
+ {
+ err = select_additional_application_internal (card, req_apptype);
+ if (!err)
+ ctrl->current_apptype = req_apptype;
+ }
+ }
+
+ if (!err)
{
/* Note: We do not use card_ref as we are already locked. */
card->ref_count++;
@@ -662,8 +715,6 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card,
card->next = card_top;
card_top = card;
}
-
- ctrl->current_apptype = card->app ? card->app->apptype : 0;
}
unlock_card (card);
}
@@ -676,32 +727,13 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card,
}
-/* This function needs to be called with the NAME of the new
- * application to be selected on CARD. On success the application is
- * added to the list of the card's active applications as currently
- * active application. On error no new application is allocated.
- * Selecting an already selected application has no effect. */
-gpg_error_t
-select_additional_application (ctrl_t ctrl, const char *name)
+static gpg_error_t
+select_additional_application_internal (card_t card, apptype_t req_apptype)
{
gpg_error_t err = 0;
- apptype_t req_apptype;
- card_t card;
- app_t app = NULL;
+ app_t app;
int i;
- req_apptype = apptype_from_name (name);
- if (!req_apptype)
- err = gpg_error (GPG_ERR_NOT_FOUND);
-
- card = ctrl->card_ctx;
- if (!card)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
-
- err = lock_card (card, ctrl);
- if (err)
- return err;
-
/* Check that the requested app has not yet been put onto the list. */
for (app = card->app; app; app = app->next)
if (app->apptype == req_apptype)
@@ -713,7 +745,6 @@ select_additional_application (ctrl_t ctrl, const char *name)
app = NULL;
goto leave;
}
- app = NULL;
/* Allocate a new app object. */
app = xtrycalloc (1, sizeof *app);
@@ -723,13 +754,17 @@ select_additional_application (ctrl_t ctrl, const char *name)
log_info ("error allocating app context: %s\n", gpg_strerror (err));
goto leave;
}
+ app->card = card;
/* Find the app and run the select. */
for (i=0; app_priority_list[i].apptype; i++)
{
if (app_priority_list[i].apptype == req_apptype
&& is_app_allowed (app_priority_list[i].name))
- err = app_priority_list[i].select_func (app);
+ {
+ err = app_priority_list[i].select_func (app);
+ break;
+ }
}
if (!app_priority_list[i].apptype
|| (err && gpg_err_code (err) != GPG_ERR_OBJ_TERM_STATE))
@@ -742,12 +777,131 @@ select_additional_application (ctrl_t ctrl, const char *name)
* reselect by maybe_switch_app after the select we just did. */
app->next = card->app;
card->app = app;
- ctrl->current_apptype = app->apptype;
- log_error ("added app '%s' to the card context\n", strapptype(app->apptype));
+ log_info ("added app '%s' to the card context and switched\n",
+ strapptype (app->apptype));
leave:
+ if (err)
+ xfree (app);
+ return err;
+}
+
+
+/* Add all possible additional applications to the card context but do
+ * not change the current one. This current works only for Yubikeys. */
+static gpg_error_t
+select_all_additional_applications_internal (card_t card)
+{
+ gpg_error_t err = 0;
+ apptype_t candidates[3];
+ int i, j;
+
+ if (card->cardtype == CARDTYPE_YUBIKEY)
+ {
+ candidates[0] = APPTYPE_OPENPGP;
+ candidates[1] = APPTYPE_PIV;
+ candidates[2] = APPTYPE_NONE;
+ }
+ else
+ {
+ candidates[0] = APPTYPE_NONE;
+ }
+
+ /* Find the app and run the select. */
+ for (i=0; app_priority_list[i].apptype; i++)
+ {
+ app_t app, app_r, app_prev;
+
+ for (j=0; candidates[j]; j++)
+ if (candidates[j] == app_priority_list[i].apptype
+ && is_app_allowed (app_priority_list[i].name))
+ break;
+ if (!candidates[j])
+ continue;
+
+ for (app = card->app; app; app = app->next)
+ if (app->apptype == candidates[j])
+ break;
+ if (app)
+ continue; /* Already on the list of apps. */
+
+ app = xtrycalloc (1, sizeof *app);
+ if (!app)
+ {
+ err = gpg_error_from_syserror ();
+ log_info ("error allocating app context: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+ app->card = card;
+ err = app_priority_list[i].select_func (app);
+ if (err)
+ {
+ log_error ("error selecting additional app '%s': %s - skipped\n",
+ strapptype (candidates[j]), gpg_strerror (err));
+ err = 0;
+ xfree (app);
+ }
+ else
+ {
+ /* Append to the list of apps. */
+ app_prev = card->app;
+ for (app_r=app_prev->next; app_r; app_prev=app_r, app_r=app_r->next)
+ ;
+ app_prev->next = app;
+ log_info ("added app '%s' to the card context\n",
+ strapptype (app->apptype));
+ }
+ }
+
+ leave:
+ return err;
+}
+
+
+/* This function needs to be called with the NAME of the new
+ * application to be selected on CARD. On success the application is
+ * added to the list of the card's active applications as currently
+ * active application. On error no new application is allocated.
+ * Selecting an already selected application has no effect. */
+gpg_error_t
+select_additional_application (ctrl_t ctrl, const char *name)
+{
+ gpg_error_t err = 0;
+ apptype_t req_apptype;
+ card_t card;
+
+ if (!name)
+ req_apptype = 0;
+ else
+ {
+ req_apptype = apptype_from_name (name);
+ if (!req_apptype)
+ return gpg_error (GPG_ERR_NOT_FOUND);
+ }
+
+ card = ctrl->card_ctx;
+ if (!card)
+ return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
+
+ err = lock_card (card, ctrl);
+ if (err)
+ return err;
+
+ if (req_apptype)
+ {
+ err = select_additional_application_internal (card, req_apptype);
+ if (!err)
+ {
+ ctrl->current_apptype = req_apptype;
+ log_debug ("current_apptype is set to %s\n", name);
+ }
+ }
+ else
+ {
+ err = select_all_additional_applications_internal (card);
+ }
+
unlock_card (card);
- xfree (app);
return err;
}
@@ -809,8 +963,6 @@ deallocate_card (card_t card)
xfree (a);
}
- scd_clear_current_app (card);
-
xfree (card->serialno);
unlock_card (card);
xfree (card);
@@ -944,10 +1096,12 @@ app_get_serialno (app_t app)
* that the new active app will be moved to the head of the list at
* CARD->app. Thus function must be called with the card lock held. */
static gpg_error_t
-maybe_switch_app (ctrl_t ctrl, card_t card)
+maybe_switch_app (ctrl_t ctrl, card_t card, const char *keyref)
{
gpg_error_t err;
- app_t app, app_prev;
+ app_t app;
+ app_t app_prev = NULL;
+ apptype_t apptype;
if (!card->ref_count || !card->app)
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
@@ -958,51 +1112,117 @@ maybe_switch_app (ctrl_t ctrl, card_t card)
ctrl->current_apptype = card->app->apptype;
return 0;
}
- log_debug ("card=%p want=%s card->app=%s\n",
- card, strapptype (ctrl->current_apptype),
- strapptype (card->app->apptype));
- app_dump_state ();
- if (ctrl->current_apptype == card->app->apptype)
- return 0; /* No need to switch. */
- app_prev = card->app;
- for (app = app_prev->next; app; app_prev = app, app = app->next)
- if (app->apptype == ctrl->current_apptype)
- break;
+ if (DBG_APP)
+ log_debug ("slot %d: have=%s want=%s keyref=%s\n",
+ card->slot, strapptype (card->app->apptype),
+ strapptype (ctrl->current_apptype),
+ keyref? keyref:"[none]");
+
+ app = NULL;
+ if (keyref)
+ {
+ /* Switch based on the requested KEYREF. */
+ apptype = apptype_from_keyref (keyref);
+ if (apptype)
+ {
+ for (app = card->app; app; app_prev = app, app = app->next)
+ if (app->apptype == apptype)
+ break;
+ if (!app_prev && ctrl->current_apptype == card->app->apptype)
+ return 0; /* Already the first app - no need to switch. */
+ }
+ else if (strlen (keyref) == 40)
+ {
+ /* This looks like a keygrip. Iterate over all apps to find
+ * the corresponding app. */
+ for (app = card->app; app; app_prev = app, app = app->next)
+ if (app->fnc.with_keygrip
+ && !app->fnc.with_keygrip (app, ctrl,
+ KEYGRIP_ACTION_LOOKUP, keyref))
+ break;
+ if (!app_prev && ctrl->current_apptype == card->app->apptype)
+ return 0; /* Already the first app - no need to switch. */
+ }
+ }
+
+ if (!app)
+ {
+ /* Switch based on the current application of this connection or
+ * if a keyref based switch didn't worked. */
+ if (ctrl->current_apptype == card->app->apptype)
+ return 0; /* No need to switch. */
+ app_prev = card->app;
+ for (app = app_prev->next; app; app_prev = app, app = app->next)
+ if (app->apptype == ctrl->current_apptype)
+ break;
+ }
if (!app)
return gpg_error (GPG_ERR_WRONG_CARD);
if (!app->fnc.reselect)
{
log_error ("oops: reselect function missing for '%s'\n",
- strapptype(app->apptype));
+ strapptype (app->apptype));
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
}
err = app->fnc.reselect (app, ctrl);
if (err)
{
- log_error ("error re-selecting '%s': %s\n",
- strapptype(app->apptype), gpg_strerror (err));
+ log_error ("card %d: error re-selecting '%s': %s\n",
+ card->slot, xstrapptype (app), gpg_strerror (err));
return err;
}
- /* Swap APP with the head of the app list. Note that APP is not the
- * head of the list. */
- app_prev->next = app->next;
- app->next = card->app;
- card->app = app;
+
+ /* Swap APP with the head of the app list if needed. Note that APP
+ * is not the head of the list. */
+ if (app_prev)
+ {
+ app_prev->next = app->next;
+ app->next = card->app;
+ card->app = app;
+ }
+
+ if (opt.verbose)
+ log_info ("card %d: %s '%s'\n",
+ card->slot, app_prev? "switched to":"re-selected",
+ xstrapptype (app));
+
ctrl->current_apptype = app->apptype;
- log_error ("switched to '%s'\n", strapptype(app->apptype));
return 0;
}
+/* Helper for app_write_learn_status. */
+static gpg_error_t
+write_learn_status_core (card_t card, app_t app, ctrl_t ctrl,
+ unsigned int flags)
+{
+ /* We do not send CARD and APPTYPE if only keypairinfo is requested. */
+ if (!(flags & APP_LEARN_FLAG_KEYPAIRINFO))
+ {
+ if (card && card->cardtype)
+ send_status_direct (ctrl, "CARDTYPE", strcardtype (card->cardtype));
+ if (card && card->cardversion)
+ send_status_printf (ctrl, "CARDVERSION", "%X", card->cardversion);
+ if (app->apptype)
+ send_status_direct (ctrl, "APPTYPE", strapptype (app->apptype));
+ if (app->appversion)
+ send_status_printf (ctrl, "APPVERSION", "%X", app->appversion);
+ }
+
+ return app->fnc.learn_status (app, ctrl, flags);
+}
+
+
/* Write out the application specific status lines for the LEARN
command. */
gpg_error_t
app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags)
{
- gpg_error_t err;
+ gpg_error_t err, err2;
app_t app;
+ int any_reselect = 0;
if (!card)
return gpg_error (GPG_ERR_INV_VALUE);
@@ -1011,29 +1231,43 @@ app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags)
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ /* Always make sure that the current app for this connection has
+ * been selected and is at the top of the list. */
+ if ((err = maybe_switch_app (ctrl, card, NULL)))
;
else if (!card->app->fnc.learn_status)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
{
- app = card->app;
-
- /* We do not send CARD and APPTYPE if only keypairinfo is requested. */
- if (!(flags &1))
+ err = write_learn_status_core (card, card->app, ctrl, flags);
+ if (!err && card->app->fnc.reselect && (flags & APP_LEARN_FLAG_MULTI))
{
- if (card->cardtype)
- send_status_direct (ctrl, "CARDTYPE", strcardtype (card->cardtype));
- if (card->cardversion)
- send_status_printf (ctrl, "CARDVERSION", "%X", card->cardversion);
- if (app->apptype)
- send_status_direct (ctrl, "APPTYPE", strapptype (app->apptype));
- if (app->appversion)
- send_status_printf (ctrl, "APPVERSION", "%X", app->appversion);
- /* FIXME: Send info for the other active apps of the card? */
+ /* The current app has the reselect feature so that we can
+ * loop over all other apps which are capable of a reselect
+ * and finally reselect the first app again. Note that we
+ * did the learn for the currently selected card above. */
+ app = card->app;
+ for (app = app->next; app && !err; app = app->next)
+ if (app->fnc.reselect)
+ {
+ any_reselect = 1;
+ err = app->fnc.reselect (app, ctrl);
+ if (!err)
+ err = write_learn_status_core (NULL, app, ctrl, flags);
+ }
+ app = card->app;
+ if (any_reselect)
+ {
+ err2 = app->fnc.reselect (app, ctrl);
+ if (err2)
+ {
+ log_error ("error re-selecting '%s': %s\n",
+ strapptype(app->apptype), gpg_strerror (err2));
+ if (!err)
+ err = err2;
+ }
+ }
}
-
- err = app->fnc.learn_status (app, ctrl, flags);
}
unlock_card (card);
@@ -1057,12 +1291,17 @@ app_readcert (card_t card, ctrl_t ctrl, const char *certid,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, certid)))
;
else if (!card->app->fnc.readcert)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.readcert (card->app, certid, cert, certlen);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling readcert(%s)\n",
+ card->slot, xstrapptype (card->app), certid);
+ err = card->app->fnc.readcert (card->app, certid, cert, certlen);
+ }
unlock_card (card);
return err;
@@ -1094,12 +1333,17 @@ app_readkey (card_t card, ctrl_t ctrl, const char *keyid, unsigned int flags,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, keyid)))
;
else if (!card->app->fnc.readkey)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.readkey (card->app, ctrl, keyid, flags, pk, pklen);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling readkey(%s)\n",
+ card->slot, xstrapptype (card->app), keyid);
+ err = card->app->fnc.readkey (card->app, ctrl, keyid, flags, pk, pklen);
+ }
unlock_card (card);
return err;
@@ -1118,7 +1362,7 @@ app_getattr (card_t card, ctrl_t ctrl, const char *name)
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, NULL)))
;
else if (name && !strcmp (name, "CARDTYPE"))
{
@@ -1144,7 +1388,12 @@ app_getattr (card_t card, ctrl_t ctrl, const char *name)
else if (!card->app->fnc.getattr)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.getattr (card->app, ctrl, name);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling getattr(%s)\n",
+ card->slot, xstrapptype (card->app), name);
+ err = card->app->fnc.getattr (card->app, ctrl, name);
+ }
unlock_card (card);
return err;
@@ -1166,13 +1415,18 @@ app_setattr (card_t card, ctrl_t ctrl, const char *name,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, NULL)))
;
else if (!card->app->fnc.setattr)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.setattr (card->app, name, pincb, pincb_arg,
- value, valuelen);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling setattr(%s)\n",
+ card->slot, xstrapptype (card->app), name);
+ err = card->app->fnc.setattr (card->app, name, pincb, pincb_arg,
+ value, valuelen);
+ }
unlock_card (card);
return err;
@@ -1197,15 +1451,20 @@ app_sign (card_t card, ctrl_t ctrl, const char *keyidstr, int hashalgo,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, keyidstr)))
;
else if (!card->app->fnc.sign)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.sign (card->app, keyidstr, hashalgo,
- pincb, pincb_arg,
- indata, indatalen,
- outdata, outdatalen);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling sign(%s)\n",
+ card->slot, xstrapptype (card->app), keyidstr);
+ err = card->app->fnc.sign (card->app, keyidstr, hashalgo,
+ pincb, pincb_arg,
+ indata, indatalen,
+ outdata, outdatalen);
+ }
unlock_card (card);
if (opt.verbose)
@@ -1233,15 +1492,20 @@ app_auth (card_t card, ctrl_t ctrl, const char *keyidstr,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, keyidstr)))
;
else if (!card->app->fnc.auth)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.auth (card->app, keyidstr,
- pincb, pincb_arg,
- indata, indatalen,
- outdata, outdatalen);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling auth(%s)\n",
+ card->slot, xstrapptype (card->app), keyidstr);
+ err = card->app->fnc.auth (card->app, keyidstr,
+ pincb, pincb_arg,
+ indata, indatalen,
+ outdata, outdatalen);
+ }
unlock_card (card);
if (opt.verbose)
@@ -1271,16 +1535,21 @@ app_decipher (card_t card, ctrl_t ctrl, const char *keyidstr,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, keyidstr)))
;
else if (!card->app->fnc.decipher)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.decipher (card->app, keyidstr,
- pincb, pincb_arg,
- indata, indatalen,
- outdata, outdatalen,
- r_info);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling decipher(%s)\n",
+ card->slot, xstrapptype (card->app), keyidstr);
+ err = card->app->fnc.decipher (card->app, keyidstr,
+ pincb, pincb_arg,
+ indata, indatalen,
+ outdata, outdatalen,
+ r_info);
+ }
unlock_card (card);
if (opt.verbose)
@@ -1305,13 +1574,18 @@ app_writecert (card_t card, ctrl_t ctrl,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, certidstr)))
;
else if (!card->app->fnc.writecert)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.writecert (card->app, ctrl, certidstr,
- pincb, pincb_arg, data, datalen);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling writecert(%s)\n",
+ card->slot, xstrapptype (card->app), certidstr);
+ err = card->app->fnc.writecert (card->app, ctrl, certidstr,
+ pincb, pincb_arg, data, datalen);
+ }
unlock_card (card);
if (opt.verbose)
@@ -1336,13 +1610,18 @@ app_writekey (card_t card, ctrl_t ctrl,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, keyidstr)))
;
else if (!card->app->fnc.writekey)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.writekey (card->app, ctrl, keyidstr, flags,
- pincb, pincb_arg, keydata, keydatalen);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling writekey(%s)\n",
+ card->slot, xstrapptype (card->app), keyidstr);
+ err = card->app->fnc.writekey (card->app, ctrl, keyidstr, flags,
+ pincb, pincb_arg, keydata, keydatalen);
+ }
unlock_card (card);
if (opt.verbose)
@@ -1366,13 +1645,18 @@ app_genkey (card_t card, ctrl_t ctrl, const char *keynostr,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, keynostr)))
;
else if (!card->app->fnc.genkey)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.genkey (card->app, ctrl, keynostr, keytype, flags,
- createtime, pincb, pincb_arg);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling genkey(%s)\n",
+ card->slot, xstrapptype (card->app), keynostr);
+ err = card->app->fnc.genkey (card->app, ctrl, keynostr, keytype, flags,
+ createtime, pincb, pincb_arg);
+ }
unlock_card (card);
if (opt.verbose)
@@ -1421,13 +1705,18 @@ app_change_pin (card_t card, ctrl_t ctrl, const char *chvnostr,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, NULL)))
;
else if (!card->app->fnc.change_pin)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.change_pin (card->app, ctrl,
- chvnostr, flags, pincb, pincb_arg);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling change_pin(%s)\n",
+ card->slot, xstrapptype (card->app), chvnostr);
+ err = card->app->fnc.change_pin (card->app, ctrl,
+ chvnostr, flags, pincb, pincb_arg);
+ }
unlock_card (card);
if (opt.verbose)
@@ -1452,12 +1741,17 @@ app_check_pin (card_t card, ctrl_t ctrl, const char *keyidstr,
if (err)
return err;
- if ((err = maybe_switch_app (ctrl, card)))
+ if ((err = maybe_switch_app (ctrl, card, NULL)))
;
else if (!card->app->fnc.check_pin)
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
else
- err = card->app->fnc.check_pin (card->app, keyidstr, pincb, pincb_arg);
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling check_pin(%s)\n",
+ card->slot, xstrapptype (card->app), keyidstr);
+ err = card->app->fnc.check_pin (card->app, keyidstr, pincb, pincb_arg);
+ }
unlock_card (card);
if (opt.verbose)
@@ -1691,24 +1985,33 @@ app_send_card_list (ctrl_t ctrl)
card_t
app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str)
{
- gpg_error_t err;
+ int locked = 0;
card_t c;
app_t a;
npth_mutex_lock (&card_list_lock);
for (c = card_top; c; c = c->next)
- for (a = c->app; a; a = a->next)
- if (a->fnc.with_keygrip)
+ {
+ if (lock_card (c, ctrl))
{
- if (!lock_card (c, ctrl))
- {
- err = a->fnc.with_keygrip (a, ctrl, action, keygrip_str);
- unlock_card (c);
- if (!err)
- goto leave_the_loop;
- }
+ c = NULL;
+ goto leave_the_loop;
}
+ locked = 1;
+ for (a = c->app; a; a = a->next)
+ if (a->fnc.with_keygrip)
+ {
+ if (DBG_APP)
+ log_debug ("slot %d app %s: calling with_keygrip(action=%d)\n",
+ c->slot, xstrapptype (a), action);
+ if (!a->fnc.with_keygrip (a, ctrl, action, keygrip_str))
+ goto leave_the_loop;
+ }
+ unlock_card (c);
+ locked = 0;
+ }
+
leave_the_loop:
@@ -1721,6 +2024,11 @@ app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str)
if (c && c->app && c->app->apptype != a->apptype)
ctrl->current_apptype = a->apptype;
+ if (locked && c)
+ {
+ unlock_card (c);
+ locked = 0;
+ }
npth_mutex_unlock (&card_list_lock);
return c;
}
diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c
index d762490c8..d3e9ef024 100644
--- a/scd/ccid-driver.c
+++ b/scd/ccid-driver.c
@@ -1276,7 +1276,7 @@ static libusb_device **ccid_usb_dev_list;
static struct ccid_dev_table ccid_dev_table[MAX_DEVICE];
gpg_error_t
-ccid_dev_scan (int *idx_max_p, struct ccid_dev_table **t_p)
+ccid_dev_scan (int *idx_max_p, void **t_p)
{
ssize_t n;
libusb_device *dev;
@@ -1403,9 +1403,10 @@ ccid_dev_scan (int *idx_max_p, struct ccid_dev_table **t_p)
}
void
-ccid_dev_scan_finish (struct ccid_dev_table *tbl, int max)
+ccid_dev_scan_finish (void *tbl0, int max)
{
int i;
+ struct ccid_dev_table *tbl = tbl0;
for (i = 0; i < max; i++)
{
@@ -1424,12 +1425,13 @@ ccid_dev_scan_finish (struct ccid_dev_table *tbl, int max)
}
unsigned int
-ccid_get_BAI (int idx, struct ccid_dev_table *tbl)
+ccid_get_BAI (int idx, void *tbl0)
{
int n;
int bus, addr, intf;
unsigned int bai;
libusb_device *dev;
+ struct ccid_dev_table *tbl = tbl0;
n = tbl[idx].n;
dev = ccid_usb_dev_list[n];
@@ -1537,7 +1539,7 @@ ccid_usb_thread (void *arg)
static int
ccid_open_usb_reader (const char *spec_reader_name,
- int idx, struct ccid_dev_table *ccid_table,
+ int idx, void *ccid_table0,
ccid_driver_t *handle, char **rdrname_p)
{
libusb_device *dev;
@@ -1549,6 +1551,7 @@ ccid_open_usb_reader (const char *spec_reader_name,
int n;
int bus, addr;
unsigned int bai;
+ struct ccid_dev_table *ccid_table = ccid_table0;
n = ccid_table[idx].n;
ifc_no = ccid_table[idx].interface_number;
@@ -1678,9 +1681,11 @@ ccid_open_usb_reader (const char *spec_reader_name,
pointer to be used as handle in HANDLE. Returns 0 on success. */
int
ccid_open_reader (const char *spec_reader_name, int idx,
- struct ccid_dev_table *ccid_table,
+ void *ccid_table0,
ccid_driver_t *handle, char **rdrname_p)
{
+ struct ccid_dev_table *ccid_table = ccid_table0;
+
*handle = calloc (1, sizeof **handle);
if (!*handle)
{
@@ -1940,6 +1945,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
int rc;
int msglen;
int notified = 0;
+ int bwi = 1;
/* Fixme: The next line for the current Valgrind without support
for USB IOCTLs. */
@@ -1950,7 +1956,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
npth_unprotect ();
#endif
rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_in,
- buffer, length, &msglen, timeout);
+ buffer, length, &msglen, bwi*timeout);
#ifdef USE_NPTH
npth_protect ();
#endif
@@ -1998,6 +2004,10 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
DEBUGOUT_2 ("time extension requested (%02X,%02X)\n",
buffer[7], buffer[8]);
+ bwi = 1;
+ if (buffer[8] != 0 && buffer[8] != 0xff)
+ bwi = buffer[8];
+
/* Gnuk enhancement to prompt user input by ack button */
if (buffer[8] == 0xff && !notified)
{
@@ -2855,7 +2865,7 @@ ccid_transceive_apdu_level (ccid_driver_t handle,
size_t apdu_part_len;
size_t msglen;
unsigned char seqno;
- int bwi = 4;
+ int bwi = 0;
unsigned char chain = 0;
if (apdu_len == 0 || apdu_len > sizeof (msg) - 10)
@@ -3107,7 +3117,7 @@ ccid_transceive (ccid_driver_t handle,
msg[0] = PC_to_RDR_XfrBlock;
msg[5] = 0; /* slot */
msg[6] = seqno = handle->seqno++;
- msg[7] = (wait_more ? wait_more : 1); /* bBWI */
+ msg[7] = wait_more; /* bBWI */
msg[8] = 0; /* RFU */
msg[9] = 0; /* RFU */
set_msg_len (msg, tpdulen);
diff --git a/scd/ccid-driver.h b/scd/ccid-driver.h
index 1550b3eba..8e7ff4482 100644
--- a/scd/ccid-driver.h
+++ b/scd/ccid-driver.h
@@ -116,12 +116,12 @@ struct ccid_dev_table;
int ccid_set_debug_level (int level);
char *ccid_get_reader_list (void);
-gpg_error_t ccid_dev_scan (int *idx_max, struct ccid_dev_table **t_p);
-void ccid_dev_scan_finish (struct ccid_dev_table *tbl, int max);
-unsigned int ccid_get_BAI (int, struct ccid_dev_table *tbl);
+gpg_error_t ccid_dev_scan (int *idx_max, void **t_p);
+void ccid_dev_scan_finish (void *tbl0, int max);
+unsigned int ccid_get_BAI (int, void *tbl0);
int ccid_compare_BAI (ccid_driver_t handle, unsigned int);
int ccid_open_reader (const char *spec_reader_name,
- int idx, struct ccid_dev_table *ccid_table,
+ int idx, void *ccid_table0,
ccid_driver_t *handle, char **rdrname_p);
int ccid_set_progress_cb (ccid_driver_t handle,
void (*cb)(void *, const char *, int, int, int),
diff --git a/scd/command.c b/scd/command.c
index 0096ca96d..73a524b49 100644
--- a/scd/command.c
+++ b/scd/command.c
@@ -105,6 +105,12 @@ static struct server_local_s *session_list;
in this variable. */
static struct server_local_s *locked_session;
+
+
+/* Local prototypes. */
+static int command_has_option (const char *cmd, const char *cmdopt);
+
+
/* Convert the STRING into a newly allocated buffer while translating
the hex numbers. Stops at the first invalid character. Blanks and
@@ -218,10 +224,12 @@ open_card (ctrl_t ctrl)
return select_application (ctrl, NULL, &ctrl->card_ctx, 0, NULL, 0);
}
-/* Explicitly open a card for a specific use of APPTYPE or SERIALNO. */
+/* Explicitly open a card for a specific use of APPTYPE or SERIALNO.
+ * If OPT_ALL ist set also add all possible additional apps. */
static gpg_error_t
open_card_with_request (ctrl_t ctrl,
- const char *apptypestr, const char *serialno)
+ const char *apptypestr, const char *serialno,
+ int opt_all)
{
gpg_error_t err;
unsigned char *serialno_bin = NULL;
@@ -249,10 +257,13 @@ open_card_with_request (ctrl_t ctrl,
/* Re-scan USB devices. Release CARD, before the scan. */
/* FIXME: Is a card_unref sufficient or do we need to deallocate? */
ctrl->card_ctx = NULL;
+ ctrl->current_apptype = APPTYPE_NONE;
card_unref (card);
err = select_application (ctrl, apptypestr, &ctrl->card_ctx, 1,
serialno_bin, serialno_bin_len);
+ if (!err && opt_all)
+ err = select_additional_application (ctrl, APPTYPE_NONE);
leave:
xfree (serialno_bin);
@@ -261,7 +272,7 @@ open_card_with_request (ctrl_t ctrl,
static const char hlp_serialno[] =
- "SERIALNO [--demand=<serialno>] [<apptype>]\n"
+ "SERIALNO [--demand=<serialno>] [--all] [<apptype>]\n"
"\n"
"Return the serial number of the card using a status response. This\n"
"function should be used to check for the presence of a card.\n"
@@ -269,6 +280,9 @@ static const char hlp_serialno[] =
"If --demand is given, an application on the card with SERIALNO is\n"
"selected and an error is returned if no such card available.\n"
"\n"
+ "If --all is given, all possible other applications of the card are\n"
+ "will also be selected for on-the-fly swicthing.\n"
+ "\n"
"If APPTYPE is given, an application of that type is selected and an\n"
"error is returned if the application is not supported or available.\n"
"The default is to auto-select the application using a hardwired\n"
@@ -290,6 +304,7 @@ cmd_serialno (assuan_context_t ctx, char *line)
int rc = 0;
char *serial;
const char *demand;
+ int opt_all = has_option (line, "--all");
if ( IS_LOCKED (ctrl) )
return gpg_error (GPG_ERR_LOCKED);
@@ -307,11 +322,13 @@ cmd_serialno (assuan_context_t ctx, char *line)
else
demand = NULL;
+ line = skip_options (line);
+
/* Clear the remove flag so that the open_card is able to reread it. */
if (ctrl->server_local->card_removed)
ctrl->server_local->card_removed = 0;
- if ((rc = open_card_with_request (ctrl, *line? line:NULL, demand)))
+ if ((rc = open_card_with_request (ctrl, *line? line:NULL, demand, opt_all)))
{
ctrl->server_local->card_removed = 1;
return rc;
@@ -337,7 +354,7 @@ cmd_serialno (assuan_context_t ctx, char *line)
static const char hlp_learn[] =
- "LEARN [--force] [--keypairinfo]\n"
+ "LEARN [--force] [--keypairinfo] [--multi]\n"
"\n"
"Learn all useful information of the currently inserted card. When\n"
"used without the force options, the command might do an INQUIRE\n"
@@ -365,7 +382,8 @@ static const char hlp_learn[] =
" PIV = PIV card\n"
" NKS = NetKey card\n"
"\n"
- "are implemented. These strings are aliases for the AID\n"
+ "are implemented. These strings are aliases for the AID. With option\n"
+ "--multi information for all switchable apps are returned.\n"
"\n"
" S KEYPAIRINFO <hexstring_with_keygrip> <hexstring_with_id> [<usage>]\n"
"\n"
@@ -412,6 +430,7 @@ cmd_learn (assuan_context_t ctx, char *line)
ctrl_t ctrl = assuan_get_pointer (ctx);
int rc = 0;
int only_keypairinfo = has_option (line, "--keypairinfo");
+ int opt_multi = has_option (line, "--multi");
if ((rc = open_card (ctrl)))
return rc;
@@ -474,7 +493,10 @@ cmd_learn (assuan_context_t ctx, char *line)
/* Let the application print out its collection of useful status
information. */
if (!rc)
- rc = app_write_learn_status (ctrl->card_ctx, ctrl, only_keypairinfo);
+ rc = app_write_learn_status
+ (ctrl->card_ctx, ctrl,
+ ( (only_keypairinfo? APP_LEARN_FLAG_KEYPAIRINFO : 0)
+ | (opt_multi? APP_LEARN_FLAG_MULTI : 0)) );
return rc;
}
@@ -1557,7 +1579,9 @@ static const char hlp_getinfo[] =
" application per line, fields delimited by colons,\n"
" first field is the name.\n"
" card_list - Return a list of serial numbers of active cards,\n"
- " using a status response.";
+ " using a status response.\n"
+ " cmd_has_option CMD OPT\n"
+ " - Returns OK if command CMD has option OPT.\n";
static gpg_error_t
cmd_getinfo (assuan_context_t ctx, char *line)
{
@@ -1575,6 +1599,38 @@ cmd_getinfo (assuan_context_t ctx, char *line)
snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
}
+ else if (!strncmp (line, "cmd_has_option", 14)
+ && (line[14] == ' ' || line[14] == '\t' || !line[14]))
+ {
+ char *cmd, *cmdopt;
+ line += 14;
+ while (*line == ' ' || *line == '\t')
+ line++;
+ if (!*line)
+ rc = gpg_error (GPG_ERR_MISSING_VALUE);
+ else
+ {
+ cmd = line;
+ while (*line && (*line != ' ' && *line != '\t'))
+ line++;
+ if (!*line)
+ rc = gpg_error (GPG_ERR_MISSING_VALUE);
+ else
+ {
+ *line++ = 0;
+ while (*line == ' ' || *line == '\t')
+ line++;
+ if (!*line)
+ rc = gpg_error (GPG_ERR_MISSING_VALUE);
+ else
+ {
+ cmdopt = line;
+ if (!command_has_option (cmd, cmdopt))
+ rc = gpg_error (GPG_ERR_FALSE);
+ }
+ }
+ }
+ }
else if (!strcmp (line, "socket_name"))
{
const char *s = scd_get_socket_name ();
@@ -1661,6 +1717,7 @@ cmd_restart (assuan_context_t ctx, char *line)
if (card)
{
ctrl->card_ctx = NULL;
+ ctrl->current_apptype = APPTYPE_NONE;
card_unref (card);
}
if (locked_session && ctrl->server_local == locked_session)
@@ -1917,6 +1974,20 @@ send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str,
+/* Return true if the command CMD implements the option OPT. */
+static int
+command_has_option (const char *cmd, const char *cmdopt)
+{
+ if (!strcmp (cmd, "SERIALNO"))
+ {
+ if (!strcmp (cmdopt, "all"))
+ return 1;
+ }
+
+ return 0;
+}
+
+
/* Tell the assuan library about our commands */
static int
register_commands (assuan_context_t ctx)
@@ -2079,20 +2150,6 @@ scd_command_handler (ctrl_t ctrl, int fd)
}
-/* Clear the current application info for CARD from all sessions.
- * This is used while deallocating a card. */
-void
-scd_clear_current_app (card_t card)
-{
- struct server_local_s *sl;
-
- for (sl=session_list; sl; sl = sl->next_session)
- {
- if (sl->ctrl_backlink->card_ctx == card)
- sl->ctrl_backlink->current_apptype = APPTYPE_NONE;
- }
-}
-
/* Send a line with status information via assuan and escape all given
buffers. The variable elements are pairs of (char *, size_t),
terminated with a (NULL, 0). */
@@ -2234,6 +2291,7 @@ send_client_notifications (card_t card, int removal)
if (removal)
{
sl->ctrl_backlink->card_ctx = NULL;
+ sl->ctrl_backlink->current_apptype = APPTYPE_NONE;
sl->card_removed = 1;
card_unref_locked (card);
}
diff --git a/scd/iso7816.c b/scd/iso7816.c
index 954aa3d4a..d44046e67 100644
--- a/scd/iso7816.c
+++ b/scd/iso7816.c
@@ -67,6 +67,7 @@ map_sw (int sw)
case SW_FILE_NOT_FOUND: ec = GPG_ERR_ENOENT; break;
case SW_RECORD_NOT_FOUND:ec= GPG_ERR_NOT_FOUND; break;
case SW_REF_NOT_FOUND: ec = GPG_ERR_NO_OBJ; break;
+ case SW_INCORRECT_P0_P1:ec = GPG_ERR_INV_VALUE; break;
case SW_BAD_P0_P1: ec = GPG_ERR_INV_VALUE; break;
case SW_EXACT_LENGTH: ec = GPG_ERR_INV_VALUE; break;
case SW_INS_NOT_SUP: ec = GPG_ERR_CARD; break;
diff --git a/scd/scdaemon.c b/scd/scdaemon.c
index e89569e5d..1796db386 100644
--- a/scd/scdaemon.c
+++ b/scd/scdaemon.c
@@ -177,6 +177,7 @@ static struct debug_flags_s debug_flags [] =
{ DBG_IPC_VALUE , "ipc" },
{ DBG_CARD_IO_VALUE, "cardio" },
{ DBG_READER_VALUE , "reader" },
+ { DBG_APP_VALUE , "app" },
{ 0, NULL }
};
diff --git a/scd/scdaemon.h b/scd/scdaemon.h
index b709b1cbc..3f2e3ed55 100644
--- a/scd/scdaemon.h
+++ b/scd/scdaemon.h
@@ -67,6 +67,7 @@ struct
} opt;
+#define DBG_APP_VALUE 1 /* Debug app speific stuff. */
#define DBG_MPI_VALUE 2 /* debug mpi details */
#define DBG_CRYPTO_VALUE 4 /* debug low level crypto */
#define DBG_MEMORY_VALUE 32 /* debug memory allocation stuff */
@@ -77,6 +78,7 @@ struct
#define DBG_CARD_IO_VALUE 2048
#define DBG_READER_VALUE 4096 /* Trace reader related functions. */
+#define DBG_APP (opt.debug & DBG_APP_VALUE)
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
#define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE)
#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
@@ -127,7 +129,6 @@ const char *scd_get_socket_name (void);
/*-- command.c --*/
gpg_error_t initialize_module_command (void);
int scd_command_handler (ctrl_t, int);
-void scd_clear_current_app (card_t card);
void send_status_info (ctrl_t ctrl, const char *keyword, ...)
GPGRT_ATTR_SENTINEL(1);
void send_status_direct (ctrl_t ctrl, const char *keyword, const char *args);
diff --git a/sm/call-agent.c b/sm/call-agent.c
index b37c2e53d..7ee728b74 100644
--- a/sm/call-agent.c
+++ b/sm/call-agent.c
@@ -477,7 +477,7 @@ gpgsm_agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
{
int rc;
char line[ASSUAN_LINELENGTH];
- membuf_t data;
+ membuf_t data;
struct cipher_parm_s cipher_parm;
size_t n, len;
char *p, *buf, *endp;
@@ -528,7 +528,8 @@ gpgsm_agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
return rc;
}
- put_membuf (&data, "", 1); /* Make sure it is 0 terminated. */
+ /* Make sure it is 0 terminated so we can invoke strtoul safely. */
+ put_membuf (&data, "", 1);
buf = get_membuf (&data, &len);
if (!buf)
return gpg_error (GPG_ERR_ENOMEM);
@@ -538,14 +539,20 @@ gpgsm_agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
{
if (len < 13 || memcmp (buf, "(5:value", 8) ) /* "(5:valueN:D)\0" */
return gpg_error (GPG_ERR_INV_SEXP);
- len -= 11; /* Count only the data of the second part. */
- p = buf + 8; /* Skip leading parenthesis and the value tag. */
+ /* Trim any spurious trailing Nuls: */
+ while (buf[len-1] == 0)
+ len--;
+ if (buf[len-1] != ')')
+ return gpg_error (GPG_ERR_INV_SEXP);
+ len--; /* Drop the final close-paren: */
+ p = buf + 8; /* Skip leading parenthesis and the value tag. */
+ len -= 8; /* Count only the data of the second part. */
}
else
{
/* For compatibility with older gpg-agents handle the old style
- incomplete S-exps. */
- len--; /* Do not count the Nul. */
+ incomplete S-exps. */
+ len--; /* Do not count the Nul. */
p = buf;
}
@@ -553,8 +560,8 @@ gpgsm_agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
if (!n || *endp != ':')
return gpg_error (GPG_ERR_INV_SEXP);
endp++;
- if (endp-p+n > len)
- return gpg_error (GPG_ERR_INV_SEXP); /* Oops: Inconsistent S-Exp. */
+ if (endp-p+n != len)
+ return gpg_error (GPG_ERR_INV_SEXP); /* Oops: Inconsistent S-Exp. */
memmove (buf, endp, n);
diff --git a/sm/decrypt.c b/sm/decrypt.c
index ec9800840..02b5509e6 100644
--- a/sm/decrypt.c
+++ b/sm/decrypt.c
@@ -75,10 +75,10 @@ prepare_decryption (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
log_printhex (seskey, seskeylen, "pkcs1 encoded session key:");
n=0;
- if (seskeylen == 24 || seskeylen == 16)
+ if (seskeylen == 32 || seskeylen == 24 || seskeylen == 16)
{
- /* Smells like a 3-DES or AES-128 key. This might happen
- * because a SC has already done the unpacking. A better
+ /* Smells like an AES-128, 3-DES, or AES-256 key. This might
+ * happen because a SC has already done the unpacking. A better
* solution would be to test for this only after we triggered
* the GPG_ERR_INV_SESSION_KEY. */
}
diff --git a/sm/keydb.c b/sm/keydb.c
index cf643abcd..5c7ff6fce 100644
--- a/sm/keydb.c
+++ b/sm/keydb.c
@@ -362,7 +362,10 @@ keydb_add_resource (ctrl_t ctrl, const char *url, int force, int *auto_created)
if (kbxhd)
{
if (!keybox_lock (kbxhd, 1, 0))
- keybox_compress (kbxhd);
+ {
+ keybox_compress (kbxhd);
+ keybox_lock (kbxhd, 0, 0);
+ }
keybox_release (kbxhd);
}
diff --git a/tools/Makefile.am b/tools/Makefile.am
index fb37c05e7..9df9d4c46 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -49,7 +49,7 @@ else
gpg_wks_server =
endif
-libexec_PROGRAMS = gpg-wks-client gpg-pair-tool
+libexec_PROGRAMS = gpg-wks-client
bin_PROGRAMS = gpgconf gpg-connect-agent gpg-card ${symcryptrun}
if !HAVE_W32_SYSTEM
@@ -187,6 +187,8 @@ gpg_wks_client_LDADD = $(libcommon) \
$(LIBASSUAN_LIBS) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
$(LIBINTL) $(LIBICONV)
+if HAVE_NEWER_LIBGCRYPT
+libexec_PROGRAMS += gpg-pair-tool
gpg_pair_tool_SOURCES = \
gpg-pair-tool.c
@@ -194,7 +196,7 @@ gpg_pair_tool_CFLAGS = $(GPG_ERROR_CFLAGS) $(INCICONV)
gpg_pair_tool_LDADD = $(libcommon) \
$(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
$(LIBINTL) $(LIBICONV) $(W32SOCKLIBS)
-
+endif
# Make sure that all libs are build before we use them. This is
# important for things like make -j2.
diff --git a/tools/gpg-card.c b/tools/gpg-card.c
index ddc4d12bf..e9dc8ebfd 100644
--- a/tools/gpg-card.c
+++ b/tools/gpg-card.c
@@ -815,7 +815,7 @@ list_openpgp (card_info_t info, estream_t fp)
print_string (fp, "Language prefs ...: ", info->disp_lang);
tty_fprintf (fp, "Salutation .......: %s\n",
info->disp_sex == 1? _("Mr."):
- info->disp_sex == 2? _("Mrs.") : "");
+ info->disp_sex == 2? _("Ms.") : "");
print_string (fp, "URL of public key : ", info->pubkey_url);
print_string (fp, "Login data .......: ", info->login_data);
if (info->private_do[0])
@@ -1464,7 +1464,7 @@ cmd_salut (card_info_t info, const char *argstr)
str = "9";
else
{
- data = tty_get (_("Salutation (M = Mr., F = Mrs., or space): "));
+ data = tty_get (_("Salutation (M = Mr., F = Ms., or space): "));
trim_spaces (data);
tty_kill_prompt ();
if (*data == CONTROL_D)
diff --git a/tools/gpg-pair-tool.c b/tools/gpg-pair-tool.c
index 9a781def1..4a18b97bd 100644
--- a/tools/gpg-pair-tool.c
+++ b/tools/gpg-pair-tool.c
@@ -1021,50 +1021,31 @@ create_dh_keypair (unsigned char *dh_secret, size_t dh_secret_len,
unsigned char *dh_public, size_t dh_public_len)
{
gpg_error_t err;
- gcry_sexp_t sexp;
- gcry_sexp_t s_keypair;
- gcry_buffer_t secret;
- gcry_buffer_t public;
- unsigned char publicbuf[33];
+ unsigned char *p;
/* We need a temporary buffer for the public key. Check the length
* for the later memcpy. */
- if (dh_public_len < 32)
+ if (dh_public_len < 32 || dh_secret_len < 32)
return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
- secret.size = dh_secret_len;
- secret.data = dh_secret;
- secret.off = 0;
- public.size = sizeof publicbuf;
- public.data = publicbuf;
- public.off = 0;
+ if (gcry_ecc_get_algo_keylen (GCRY_ECC_CURVE25519) > dh_public_len)
+ return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
- err = gcry_sexp_build (&sexp, NULL,
- "(genkey(ecc(curve Curve25519)(flags djb-tweak)))");
- if (err)
- return err;
- err = gcry_pk_genkey (&s_keypair, sexp);
- gcry_sexp_release (sexp);
- if (err)
- return err;
- err = gcry_sexp_extract_param (s_keypair, "key-data!private-key",
- "&dq", &secret, &public, NULL);
- gcry_sexp_release (s_keypair);
+ p = gcry_random_bytes (32, GCRY_VERY_STRONG_RANDOM);
+ if (!p)
+ return gpg_error_from_syserror ();
+
+ memcpy (dh_secret, p, 32);
+ xfree (p);
+
+ err = gcry_ecc_mul_point (GCRY_ECC_CURVE25519, dh_public, dh_secret, NULL);
if (err)
return err;
- /* Gcrypt prepends a 0x40 indicator - remove that. */
- if (public.len == 33)
- {
- public.len = 32;
- memmove (public.data, publicbuf+1, 32);
- }
- memcpy (dh_public, public.data, public.len);
-
if (DBG_CRYPTO)
{
- log_printhex (secret.data, secret.len, "DH secret:");
- log_printhex (public.data, public.len, "DH public:");
+ log_printhex (dh_secret, 32, "DH secret:");
+ log_printhex (dh_public, 32, "DH public:");
}
return 0;
@@ -1189,52 +1170,15 @@ compute_master_secret (unsigned char *master, size_t masterlen,
const unsigned char *pk_b, size_t pk_b_len)
{
gpg_error_t err;
- gcry_sexp_t s_sk_a = NULL;
- gcry_sexp_t s_pk_b = NULL;
- gcry_sexp_t s_shared = NULL;
- gcry_sexp_t s_tmp;
- const char *s;
- size_t n;
log_assert (masterlen == 32);
+ log_assert (sk_a_len == 32);
+ log_assert (pk_b_len == 32);
- err = gcry_sexp_build (&s_sk_a, NULL, "%b", (int)sk_a_len, sk_a);
- if (!err)
- err = gcry_sexp_build (&s_pk_b, NULL,
- "(public-key(ecdh(curve Curve25519)"
- " (flags djb-tweak)(q%b)))",
- (int)pk_b_len, pk_b);
- if (err)
- {
- log_error ("error building S-expression: %s\n", gpg_strerror (err));
- goto leave;
- }
-
- err = gcry_pk_encrypt (&s_shared, s_sk_a, s_pk_b);
+ err = gcry_ecc_mul_point (GCRY_ECC_CURVE25519, master, sk_a, pk_b);
if (err)
- {
- log_error ("error computing DH: %s\n", gpg_strerror (err));
- goto leave;
- }
- /* gcry_log_debugsxp ("sk_a", s_sk_a); */
- /* gcry_log_debugsxp ("pk_b", s_pk_b); */
- /* gcry_log_debugsxp ("shared", s_shared); */
+ log_error ("error computing DH: %s\n", gpg_strerror (err));
- s_tmp = gcry_sexp_find_token (s_shared, "s", 0);
- if (!s_tmp || !(s = gcry_sexp_nth_data (s_tmp, 1, &n))
- || n != 33 || s[0] != 0x40)
- {
- err = gpg_error (GPG_ERR_INTERNAL);
- log_error ("error computing DH: %s\n", gpg_strerror (err));
- goto leave;
- }
- memcpy (master, s+1, 32);
-
-
- leave:
- gcry_sexp_release (s_sk_a);
- gcry_sexp_release (s_pk_b);
- gcry_sexp_release (s_shared);
return err;
}
diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c
index 628ca358f..e6dc91d21 100644
--- a/tools/gpgconf-comp.c
+++ b/tools/gpgconf-comp.c
@@ -1283,7 +1283,7 @@ gc_component_launch (int component)
gc_component[component].name);
if (!opt.quiet)
log_info (_("Note: Use the command \"%s%s\" to get details.\n"),
- "gpgconf --check-options ", gc_component[component].name);
+ gc_component[component].name, " --gpgconf-test");
gpgconf_failure (0);
}