diff -Nru gnupg2-2.1.6~build1/ABOUT-NLS gnupg2-2.0.28/ABOUT-NLS
--- gnupg2-2.1.6~build1/ABOUT-NLS 2015-06-17 06:39:24.000000000 +0000
+++ gnupg2-2.0.28/ABOUT-NLS 2015-06-02 08:13:55.000000000 +0000
@@ -18,35 +18,7 @@
available translations. They tell how people wanting to contribute and
work on translations can contact the appropriate team.
- When reporting bugs in the `intl/' directory or bugs which may be
-related to internationalization, you should tell about the version of
-`gettext' which is used. The information can be found in the
-`intl/VERSION' file, in internationalized packages.
-
-1.1 Quick configuration advice
-==============================
-
-If you want to exploit the full power of internationalization, you
-should configure it using
-
- ./configure --with-included-gettext
-
-to force usage of internationalizing routines provided within this
-package, despite the existence of internationalizing capabilities in the
-operating system where this package is being installed. So far, only
-the `gettext' implementation in the GNU C library version 2 provides as
-many features (such as locale alias, message inheritance, automatic
-charset conversion or plural form handling) as the implementation here.
-It is also not possible to offer this additional functionality on top
-of a `catgets' implementation. Future versions of GNU `gettext' will
-very likely convey even more functionality. So it might be a good idea
-to change to GNU `gettext' as soon as possible.
-
- So you need _not_ provide this option if you are using GNU libc 2 or
-you have installed a recent copy of the GNU gettext package with the
-included `libintl'.
-
-1.2 INSTALL Matters
+1.1 INSTALL Matters
===================
Some packages are "localizable" when properly installed; the programs
@@ -56,36 +28,19 @@
By default, this package will be installed to allow translation of
messages. It will automatically detect whether the system already
-provides the GNU `gettext' functions. If not, the included GNU
-`gettext' library will be used. This library is wholly contained
-within this package, usually in the `intl/' subdirectory, so prior
-installation of the GNU `gettext' package is _not_ required.
-Installers may use special options at configuration time for changing
-the default behaviour. The commands:
+provides the GNU `gettext' functions. Installers may use special
+options at configuration time for changing the default behaviour. The
+command:
- ./configure --with-included-gettext
./configure --disable-nls
-will, respectively, bypass any pre-existing `gettext' to use the
-internationalizing routines provided within this package, or else,
-_totally_ disable translation of messages.
+will _totally_ disable translation of messages.
When you already have GNU `gettext' installed on your system and run
configure without an option for your new package, `configure' will
-probably detect the previously built and installed `libintl.a' file and
-will decide to use this. This might not be desirable. You should use
-the more recent version of the GNU `gettext' library. I.e. if the file
-`intl/VERSION' shows that the library which comes with this package is
-more recent, you should use
-
- ./configure --with-included-gettext
-
-to prevent auto-detection.
-
- The configuration process will not test for the `catgets' function
-and therefore it will not be used. The reason is that even an
-emulation of `gettext' on top of `catgets' could not provide all the
-extensions of the GNU `gettext' library.
+probably detect the previously built and installed `libintl' library
+and will decide to use it. If not, you may have to to use the
+`--with-libintl-prefix' option to tell `configure' where to look for it.
Internationalized packages usually have many `po/LL.po' files, where
LL gives an ISO 639 two-letter code identifying the language. Unless
@@ -96,7 +51,7 @@
`LINGUAS' should then contain a space separated list of two-letter
codes, stating which languages are allowed.
-1.3 Using This Package
+1.2 Using This Package
======================
As a user, if your language has been installed for this package, you
@@ -148,7 +103,7 @@
to `de_DE' (German as spoken in Germany), and `pt' to `pt_PT'
(Portuguese as spoken in Portugal) in this context.
-1.4 Translating Teams
+1.3 Translating Teams
=====================
For the Free Translation Project to be a success, we need interested
@@ -177,859 +132,1118 @@
the terminology in use. Proven linguistic skills are praised more than
programming skills, here.
-1.5 Available Packages
+1.4 Available Packages
======================
Languages are not equally supported in all packages. The following
-matrix shows the current state of internationalization, as of November
-2007. The matrix shows, in regard of each package, for which languages
+matrix shows the current state of internationalization, as of June
+2010. The matrix shows, in regard of each package, for which languages
PO files have been submitted to translation coordination, with a
translation percentage of at least 50%.
- Ready PO files af am ar az be bg bs ca cs cy da de el en en_GB eo
- +----------------------------------------------------+
- Compendium | [] [] [] [] |
- a2ps | [] [] [] [] [] |
- aegis | () |
- ant-phone | () |
- anubis | [] |
- ap-utils | |
- aspell | [] [] [] [] [] |
- bash | [] |
- bfd | |
- bibshelf | [] |
- binutils | |
- bison | [] [] |
- bison-runtime | [] |
- bluez-pin | [] [] [] [] [] |
- cflow | [] |
- clisp | [] [] [] |
- console-tools | [] [] |
- coreutils | [] [] [] [] |
- cpio | |
- cpplib | [] [] [] |
- cryptonit | [] |
- dialog | |
- diffutils | [] [] [] [] [] [] |
- doodle | [] |
- e2fsprogs | [] [] |
- enscript | [] [] [] [] |
- fetchmail | [] [] () [] [] |
- findutils | [] |
- findutils_stable | [] [] [] |
- flex | [] [] [] |
- fslint | |
- gas | |
- gawk | [] [] [] |
- gcal | [] |
- gcc | [] |
- gettext-examples | [] [] [] [] [] |
- gettext-runtime | [] [] [] [] [] |
- gettext-tools | [] [] |
- gip | [] |
- gliv | [] [] |
- glunarclock | [] |
- gmult | [] [] |
- gnubiff | () |
- gnucash | [] [] () () [] |
- gnuedu | |
- gnulib | [] |
- gnunet | |
- gnunet-gtk | |
- gnutls | [] |
- gpe-aerial | [] [] |
- gpe-beam | [] [] |
- gpe-calendar | |
- gpe-clock | [] [] |
- gpe-conf | [] [] |
- gpe-contacts | |
- gpe-edit | [] |
- gpe-filemanager | |
- gpe-go | [] |
- gpe-login | [] [] |
- gpe-ownerinfo | [] [] |
- gpe-package | |
- gpe-sketchbook | [] [] |
- gpe-su | [] [] |
- gpe-taskmanager | [] [] |
- gpe-timesheet | [] |
- gpe-today | [] [] |
- gpe-todo | |
- gphoto2 | [] [] [] [] |
- gprof | [] [] |
- gpsdrive | |
- gramadoir | [] [] |
- grep | [] [] |
- gretl | () |
- gsasl | |
- gss | |
- gst-plugins-bad | [] [] |
- gst-plugins-base | [] [] |
- gst-plugins-good | [] [] [] |
- gst-plugins-ugly | [] [] |
- gstreamer | [] [] [] [] [] [] [] |
- gtick | () |
- gtkam | [] [] [] [] |
- gtkorphan | [] [] |
- gtkspell | [] [] [] [] |
- gutenprint | [] |
- hello | [] [] [] [] [] |
- herrie | [] |
- hylafax | |
- idutils | [] [] |
- indent | [] [] [] [] |
- iso_15924 | |
- iso_3166 | [] [] [] [] [] [] [] [] [] [] [] |
- iso_3166_2 | |
- iso_4217 | [] [] [] |
- iso_639 | [] [] [] [] |
- jpilot | [] |
- jtag | |
- jwhois | |
- kbd | [] [] [] [] |
- keytouch | [] [] |
- keytouch-editor | [] |
- keytouch-keyboa... | [] |
- latrine | () |
- ld | [] |
- leafpad | [] [] [] [] [] |
- libc | [] [] [] [] |
- libexif | [] |
- libextractor | [] |
- libgpewidget | [] [] [] |
- libgpg-error | [] |
- libgphoto2 | [] [] |
- libgphoto2_port | [] [] |
- libgsasl | |
- libiconv | [] [] |
- libidn | [] [] [] |
- lifelines | [] () |
- lilypond | [] |
- lingoteach | |
- lprng | |
- lynx | [] [] [] [] |
- m4 | [] [] [] [] |
- mailfromd | |
- mailutils | [] |
- make | [] [] |
- man-db | [] [] [] |
- minicom | [] [] [] |
- nano | [] [] [] |
- opcodes | [] |
- parted | [] [] |
- pilot-qof | |
- popt | [] [] [] |
- psmisc | [] |
- pwdutils | |
- qof | |
- radius | [] |
- recode | [] [] [] [] [] [] |
- rpm | [] |
- screem | |
- scrollkeeper | [] [] [] [] [] [] [] [] |
- sed | [] [] [] |
- shared-mime-info | [] [] [] [] () [] [] [] |
- sharutils | [] [] [] [] [] [] |
- shishi | |
- skencil | [] () |
- solfege | |
- soundtracker | [] [] |
- sp | [] |
- system-tools-ba... | [] [] [] [] [] [] [] [] [] |
- tar | [] [] |
- texinfo | [] [] [] |
- tin | () () |
- tuxpaint | [] [] [] [] [] [] |
- unicode-han-tra... | |
- unicode-transla... | |
- util-linux | [] [] [] [] |
- util-linux-ng | [] [] [] [] |
- vorbis-tools | [] |
- wastesedge | () |
- wdiff | [] [] [] [] |
- wget | [] [] [] |
- xchat | [] [] [] [] [] [] [] |
- xkeyboard-config | [] |
- xpad | [] [] [] |
- +----------------------------------------------------+
- af am ar az be bg bs ca cs cy da de el en en_GB eo
- 6 0 2 1 8 26 2 40 48 2 56 88 15 1 15 18
-
- es et eu fa fi fr ga gl gu he hi hr hu id is it
+ Ready PO files af am an ar as ast az be be@latin bg bn_IN bs ca
+--------------------------------------------------+
- Compendium | [] [] [] [] [] |
- a2ps | [] [] [] () |
+ a2ps | [] [] |
aegis | |
- ant-phone | [] |
- anubis | [] |
- ap-utils | [] [] |
- aspell | [] [] [] |
- bash | [] |
- bfd | [] [] |
- bibshelf | [] [] [] |
- binutils | [] [] [] |
- bison | [] [] [] [] [] [] |
- bison-runtime | [] [] [] [] [] |
- bluez-pin | [] [] [] [] [] |
- cflow | [] |
- clisp | [] [] |
- console-tools | |
- coreutils | [] [] [] [] [] [] |
- cpio | [] [] [] |
- cpplib | [] [] |
- cryptonit | [] |
- dialog | [] [] [] |
- diffutils | [] [] [] [] [] [] [] [] [] |
- doodle | [] [] |
- e2fsprogs | [] [] [] |
- enscript | [] [] [] |
- fetchmail | [] |
- findutils | [] [] [] |
- findutils_stable | [] [] [] [] |
- flex | [] [] [] |
- fslint | |
- gas | [] [] |
- gawk | [] [] [] [] () |
- gcal | [] [] |
- gcc | [] |
- gettext-examples | [] [] [] [] [] [] [] |
- gettext-runtime | [] [] [] [] [] [] |
- gettext-tools | [] [] [] [] |
- gip | [] [] [] [] |
- gliv | () |
- glunarclock | [] [] [] |
- gmult | [] [] [] |
- gnubiff | () () |
- gnucash | () () () |
- gnuedu | [] |
- gnulib | [] [] [] |
- gnunet | |
- gnunet-gtk | |
- gnutls | |
- gpe-aerial | [] [] |
- gpe-beam | [] [] |
- gpe-calendar | |
- gpe-clock | [] [] [] [] |
- gpe-conf | [] |
- gpe-contacts | [] [] |
- gpe-edit | [] [] [] [] |
- gpe-filemanager | [] |
- gpe-go | [] [] [] |
- gpe-login | [] [] [] |
- gpe-ownerinfo | [] [] [] [] [] |
- gpe-package | [] |
- gpe-sketchbook | [] [] |
- gpe-su | [] [] [] [] |
- gpe-taskmanager | [] [] [] |
- gpe-timesheet | [] [] [] [] |
- gpe-today | [] [] [] [] |
- gpe-todo | [] |
- gphoto2 | [] [] [] [] [] |
- gprof | [] [] [] [] [] |
- gpsdrive | [] |
- gramadoir | [] [] |
- grep | [] [] [] |
- gretl | [] [] [] () |
- gsasl | [] [] |
- gss | [] [] |
- gst-plugins-bad | [] [] [] [] |
- gst-plugins-base | [] [] [] [] |
- gst-plugins-good | [] [] [] [] [] |
- gst-plugins-ugly | [] [] [] [] |
- gstreamer | [] [] [] |
- gtick | [] [] [] |
- gtkam | [] [] [] [] |
- gtkorphan | [] [] |
- gtkspell | [] [] [] [] [] [] [] |
- gutenprint | [] |
- hello | [] [] [] [] [] [] [] [] [] [] [] [] [] |
- herrie | [] |
- hylafax | |
- idutils | [] [] [] [] [] |
- indent | [] [] [] [] [] [] [] [] [] [] |
- iso_15924 | [] |
- iso_3166 | [] [] [] [] [] [] [] [] [] [] [] [] [] |
- iso_3166_2 | [] |
- iso_4217 | [] [] [] [] [] [] |
- iso_639 | [] [] [] [] [] [] |
- jpilot | [] [] |
- jtag | [] |
- jwhois | [] [] [] [] [] |
- kbd | [] [] |
- keytouch | [] [] [] |
- keytouch-editor | [] |
- keytouch-keyboa... | [] [] |
- latrine | [] [] |
- ld | [] [] [] [] |
- leafpad | [] [] [] [] [] [] |
- libc | [] [] [] [] [] |
- libexif | [] |
- libextractor | [] |
- libgpewidget | [] [] [] [] [] |
- libgpg-error | [] |
- libgphoto2 | [] [] [] |
- libgphoto2_port | [] [] |
- libgsasl | [] [] |
- libiconv | [] [] [] |
- libidn | [] [] |
- lifelines | () |
- lilypond | [] [] [] |
- lingoteach | [] [] [] |
- lprng | |
- lynx | [] [] [] |
- m4 | [] [] [] [] |
- mailfromd | |
- mailutils | [] [] |
- make | [] [] [] [] [] [] [] [] |
- man-db | [] |
- minicom | [] [] [] [] |
- nano | [] [] [] [] [] [] [] |
- opcodes | [] [] [] [] |
- parted | [] [] [] |
- pilot-qof | |
- popt | [] [] [] [] |
- psmisc | [] [] |
- pwdutils | |
- qof | [] |
- radius | [] [] |
- recode | [] [] [] [] [] [] [] [] |
- rpm | [] [] |
- screem | |
- scrollkeeper | [] [] [] |
- sed | [] [] [] [] [] |
- shared-mime-info | [] [] [] [] [] [] |
- sharutils | [] [] [] [] [] [] [] [] |
- shishi | [] |
- skencil | [] [] |
- solfege | [] |
- soundtracker | [] [] [] |
- sp | [] |
- system-tools-ba... | [] [] [] [] [] [] [] [] [] |
- tar | [] [] [] [] [] |
- texinfo | [] [] [] |
- tin | [] () |
- tuxpaint | [] [] |
- unicode-han-tra... | |
- unicode-transla... | [] [] |
- util-linux | [] [] [] [] [] [] [] |
- util-linux-ng | [] [] [] [] [] [] [] |
- vorbis-tools | |
- wastesedge | () |
- wdiff | [] [] [] [] [] [] [] [] |
- wget | [] [] [] [] [] [] [] [] |
- xchat | [] [] [] [] [] [] [] |
- xkeyboard-config | [] [] [] [] |
- xpad | [] [] [] |
- +--------------------------------------------------+
- es et eu fa fi fr ga gl gu he hi hr hu id is it
- 85 22 14 2 48 101 61 12 2 8 2 6 53 29 1 52
-
- ja ka ko ku ky lg lt lv mk mn ms mt nb ne nl nn
- +--------------------------------------------------+
- Compendium | [] |
- a2ps | () [] [] |
- aegis | () |
- ant-phone | [] |
- anubis | [] [] [] |
- ap-utils | [] |
- aspell | [] [] |
- bash | [] |
+ ant-phone | |
+ anubis | |
+ aspell | [] [] |
+ bash | |
bfd | |
- bibshelf | [] |
+ bibshelf | [] |
binutils | |
- bison | [] [] [] |
- bison-runtime | [] [] [] |
- bluez-pin | [] [] [] |
+ bison | |
+ bison-runtime | [] |
+ bluez-pin | [] [] |
+ bombono-dvd | |
+ buzztard | |
cflow | |
- clisp | [] |
- console-tools | |
- coreutils | [] |
- cpio | [] |
- cpplib | [] |
- cryptonit | [] |
- dialog | [] [] |
- diffutils | [] [] [] |
+ clisp | |
+ coreutils | [] [] |
+ cpio | |
+ cppi | |
+ cpplib | [] |
+ cryptsetup | |
+ dfarc | |
+ dialog | [] [] |
+ dico | |
+ diffutils | [] |
+ dink | |
doodle | |
- e2fsprogs | [] |
- enscript | [] |
- fetchmail | [] [] |
- findutils | [] |
- findutils_stable | [] |
- flex | [] [] |
- fslint | |
+ e2fsprogs | [] |
+ enscript | [] |
+ exif | |
+ fetchmail | [] |
+ findutils | [] |
+ flex | [] |
+ freedink | |
gas | |
- gawk | [] [] |
- gcal | |
+ gawk | [] [] |
+ gcal | [] |
gcc | |
- gettext-examples | [] [] [] |
- gettext-runtime | [] [] [] |
- gettext-tools | [] [] |
- gip | [] [] |
- gliv | [] |
- glunarclock | [] [] |
- gmult | [] [] [] |
+ gettext-examples | [] [] [] [] |
+ gettext-runtime | [] [] |
+ gettext-tools | [] [] |
+ gip | [] |
+ gjay | |
+ gliv | [] |
+ glunarclock | [] [] |
gnubiff | |
- gnucash | () () () |
+ gnucash | [] |
gnuedu | |
- gnulib | [] [] |
+ gnulib | |
gnunet | |
gnunet-gtk | |
- gnutls | [] |
- gpe-aerial | [] |
- gpe-beam | [] |
- gpe-calendar | [] |
- gpe-clock | [] [] [] |
- gpe-conf | [] [] [] |
- gpe-contacts | [] |
- gpe-edit | [] [] [] |
- gpe-filemanager | [] [] |
- gpe-go | [] [] [] |
- gpe-login | [] [] [] |
- gpe-ownerinfo | [] [] |
- gpe-package | [] [] |
- gpe-sketchbook | [] [] |
- gpe-su | [] [] [] |
- gpe-taskmanager | [] [] [] [] |
- gpe-timesheet | [] |
- gpe-today | [] [] |
- gpe-todo | [] |
- gphoto2 | [] [] |
- gprof | [] |
- gpsdrive | [] |
- gramadoir | () |
- grep | [] [] |
- gretl | |
- gsasl | [] |
+ gnutls | |
+ gold | |
+ gpe-aerial | |
+ gpe-beam | |
+ gpe-bluetooth | |
+ gpe-calendar | |
+ gpe-clock | [] |
+ gpe-conf | |
+ gpe-contacts | |
+ gpe-edit | |
+ gpe-filemanager | |
+ gpe-go | |
+ gpe-login | |
+ gpe-ownerinfo | [] |
+ gpe-package | |
+ gpe-sketchbook | |
+ gpe-su | [] |
+ gpe-taskmanager | [] |
+ gpe-timesheet | [] |
+ gpe-today | [] |
+ gpe-todo | |
+ gphoto2 | |
+ gprof | [] |
+ gpsdrive | |
+ gramadoir | |
+ grep | |
+ grub | [] [] |
+ gsasl | |
gss | |
- gst-plugins-bad | [] |
- gst-plugins-base | [] |
- gst-plugins-good | [] |
- gst-plugins-ugly | [] |
- gstreamer | [] |
- gtick | [] |
- gtkam | [] [] |
- gtkorphan | [] |
- gtkspell | [] [] |
- gutenprint | [] |
- hello | [] [] [] [] [] [] [] |
- herrie | [] |
+ gst-plugins-bad | [] |
+ gst-plugins-base | [] |
+ gst-plugins-good | [] |
+ gst-plugins-ugly | [] |
+ gstreamer | [] [] [] |
+ gtick | |
+ gtkam | [] |
+ gtkorphan | [] |
+ gtkspell | [] [] [] |
+ gutenprint | |
+ hello | [] |
+ help2man | |
hylafax | |
- idutils | [] |
- indent | [] [] |
- iso_15924 | [] |
- iso_3166 | [] [] [] [] [] [] [] [] |
- iso_3166_2 | [] |
- iso_4217 | [] [] [] |
- iso_639 | [] [] [] [] |
- jpilot | () () |
- jtag | |
- jwhois | [] |
- kbd | [] |
- keytouch | [] |
- keytouch-editor | [] |
- keytouch-keyboa... | |
- latrine | [] |
- ld | |
- leafpad | [] [] |
- libc | [] [] [] |
- libexif | |
+ idutils | |
+ indent | [] [] |
+ iso_15924 | |
+ iso_3166 | [] [] [] [] [] [] [] |
+ iso_3166_2 | |
+ iso_4217 | |
+ iso_639 | [] [] [] [] |
+ iso_639_3 | |
+ jwhois | |
+ kbd | |
+ keytouch | [] |
+ keytouch-editor | |
+ keytouch-keyboa... | [] |
+ klavaro | [] |
+ latrine | |
+ ld | [] |
+ leafpad | [] [] |
+ libc | [] [] |
+ libexif | () |
libextractor | |
- libgpewidget | [] |
+ libgnutls | |
+ libgpewidget | |
libgpg-error | |
- libgphoto2 | [] |
- libgphoto2_port | [] |
- libgsasl | [] |
- libiconv | [] |
- libidn | [] [] |
- lifelines | [] |
- lilypond | [] |
- lingoteach | [] |
+ libgphoto2 | |
+ libgphoto2_port | |
+ libgsasl | |
+ libiconv | [] |
+ libidn | |
+ lifelines | |
+ liferea | [] [] |
+ lilypond | |
+ linkdr | [] |
+ lordsawar | |
lprng | |
- lynx | [] [] |
- m4 | [] [] |
+ lynx | [] |
+ m4 | |
mailfromd | |
mailutils | |
- make | [] [] [] |
+ make | |
man-db | |
- minicom | [] |
- nano | [] [] [] |
- opcodes | [] |
- parted | [] [] |
- pilot-qof | |
- popt | [] [] [] |
- psmisc | [] [] [] |
+ man-db-manpages | |
+ minicom | |
+ mkisofs | |
+ myserver | |
+ nano | [] [] |
+ opcodes | |
+ parted | |
+ pies | |
+ popt | |
+ psmisc | |
+ pspp | [] |
pwdutils | |
- qof | |
- radius | |
- recode | [] |
- rpm | [] [] |
- screem | [] |
- scrollkeeper | [] [] [] [] |
- sed | [] [] |
- shared-mime-info | [] [] [] [] [] [] [] |
- sharutils | [] [] |
+ radius | [] |
+ recode | [] [] |
+ rosegarden | |
+ rpm | |
+ rush | |
+ sarg | |
+ screem | |
+ scrollkeeper | [] [] [] |
+ sed | [] [] |
+ sharutils | [] [] |
shishi | |
skencil | |
- solfege | () () |
+ solfege | |
+ solfege-manual | |
soundtracker | |
- sp | () |
- system-tools-ba... | [] [] [] [] |
- tar | [] [] [] |
- texinfo | [] [] |
+ sp | |
+ sysstat | |
+ tar | [] |
+ texinfo | |
tin | |
- tuxpaint | () [] [] |
unicode-han-tra... | |
unicode-transla... | |
- util-linux | [] [] |
- util-linux-ng | [] [] |
+ util-linux-ng | [] |
+ vice | |
+ vmm | |
vorbis-tools | |
- wastesedge | [] |
- wdiff | [] [] |
- wget | [] [] |
- xchat | [] [] [] [] |
- xkeyboard-config | [] [] [] |
- xpad | [] [] [] |
- +--------------------------------------------------+
- ja ka ko ku ky lg lt lv mk mn ms mt nb ne nl nn
- 51 2 25 3 2 0 6 0 2 2 20 0 11 1 103 6
-
- or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv ta
- +--------------------------------------------------+
- Compendium | [] [] [] [] [] |
- a2ps | () [] [] [] [] [] [] |
- aegis | () () |
- ant-phone | [] [] |
- anubis | [] [] [] |
- ap-utils | () |
- aspell | [] [] [] |
- bash | [] [] |
- bfd | |
- bibshelf | [] |
- binutils | [] [] |
- bison | [] [] [] [] [] |
- bison-runtime | [] [] [] [] [] |
- bluez-pin | [] [] [] [] [] [] [] [] [] |
- cflow | [] |
- clisp | [] |
- console-tools | [] |
- coreutils | [] [] [] [] |
- cpio | [] [] [] |
- cpplib | [] |
- cryptonit | [] [] |
- dialog | [] |
- diffutils | [] [] [] [] [] [] |
- doodle | [] [] |
- e2fsprogs | [] [] |
- enscript | [] [] [] [] [] |
- fetchmail | [] [] [] |
- findutils | [] [] [] |
- findutils_stable | [] [] [] [] [] [] |
- flex | [] [] [] [] [] |
- fslint | [] |
- gas | |
- gawk | [] [] [] [] |
- gcal | [] |
- gcc | [] [] |
- gettext-examples | [] [] [] [] [] [] [] [] |
- gettext-runtime | [] [] [] [] [] [] [] [] |
- gettext-tools | [] [] [] [] [] [] [] |
- gip | [] [] [] [] |
- gliv | [] [] [] [] [] [] |
- glunarclock | [] [] [] [] [] [] |
- gmult | [] [] [] [] |
- gnubiff | () [] |
- gnucash | () [] |
- gnuedu | |
- gnulib | [] [] [] |
- gnunet | |
- gnunet-gtk | [] |
- gnutls | [] [] |
- gpe-aerial | [] [] [] [] [] [] [] |
- gpe-beam | [] [] [] [] [] [] [] |
- gpe-calendar | [] [] [] [] |
- gpe-clock | [] [] [] [] [] [] [] [] |
- gpe-conf | [] [] [] [] [] [] [] |
- gpe-contacts | [] [] [] [] [] |
- gpe-edit | [] [] [] [] [] [] [] [] [] |
- gpe-filemanager | [] [] |
- gpe-go | [] [] [] [] [] [] [] [] |
- gpe-login | [] [] [] [] [] [] [] [] |
- gpe-ownerinfo | [] [] [] [] [] [] [] [] |
- gpe-package | [] [] |
- gpe-sketchbook | [] [] [] [] [] [] [] [] |
- gpe-su | [] [] [] [] [] [] [] [] |
- gpe-taskmanager | [] [] [] [] [] [] [] [] |
- gpe-timesheet | [] [] [] [] [] [] [] [] |
- gpe-today | [] [] [] [] [] [] [] [] |
- gpe-todo | [] [] [] [] |
- gphoto2 | [] [] [] [] [] [] |
- gprof | [] [] [] |
- gpsdrive | [] [] |
- gramadoir | [] [] |
- grep | [] [] [] [] |
- gretl | [] [] [] |
- gsasl | [] [] [] |
- gss | [] [] [] [] |
- gst-plugins-bad | [] [] [] |
- gst-plugins-base | [] [] |
- gst-plugins-good | [] [] |
- gst-plugins-ugly | [] [] [] |
- gstreamer | [] [] [] [] |
- gtick | [] |
- gtkam | [] [] [] [] [] |
- gtkorphan | [] |
- gtkspell | [] [] [] [] [] [] [] [] |
- gutenprint | [] |
- hello | [] [] [] [] [] [] [] [] |
- herrie | [] [] [] |
- hylafax | |
- idutils | [] [] [] [] [] |
- indent | [] [] [] [] [] [] [] |
- iso_15924 | |
- iso_3166 | [] [] [] [] [] [] [] [] [] [] [] [] [] |
- iso_3166_2 | |
- iso_4217 | [] [] [] [] [] [] [] |
- iso_639 | [] [] [] [] [] [] [] |
- jpilot | |
- jtag | [] |
- jwhois | [] [] [] [] |
- kbd | [] [] [] |
- keytouch | [] |
- keytouch-editor | [] |
- keytouch-keyboa... | [] |
- latrine | |
- ld | [] |
- leafpad | [] [] [] [] [] [] |
- libc | [] [] [] [] |
- libexif | [] [] |
- libextractor | [] [] |
- libgpewidget | [] [] [] [] [] [] [] [] |
- libgpg-error | [] [] [] |
- libgphoto2 | [] |
- libgphoto2_port | [] [] [] |
- libgsasl | [] [] [] [] |
- libiconv | [] [] [] |
- libidn | [] [] () |
- lifelines | [] [] |
- lilypond | |
- lingoteach | [] |
- lprng | [] |
- lynx | [] [] [] |
- m4 | [] [] [] [] [] |
- mailfromd | [] |
- mailutils | [] [] [] |
- make | [] [] [] [] |
- man-db | [] [] [] [] |
- minicom | [] [] [] [] [] |
- nano | [] [] [] [] |
- opcodes | [] [] |
- parted | [] |
- pilot-qof | |
- popt | [] [] [] [] |
- psmisc | [] [] |
- pwdutils | [] [] |
- qof | [] [] |
- radius | [] [] |
- recode | [] [] [] [] [] [] [] |
- rpm | [] [] [] [] |
- screem | |
- scrollkeeper | [] [] [] [] [] [] [] |
- sed | [] [] [] [] [] [] [] [] [] |
- shared-mime-info | [] [] [] [] [] [] |
- sharutils | [] [] [] [] |
- shishi | [] |
- skencil | [] [] [] |
- solfege | [] |
- soundtracker | [] [] |
- sp | |
- system-tools-ba... | [] [] [] [] [] [] [] [] [] |
- tar | [] [] [] [] |
- texinfo | [] [] [] [] |
- tin | () |
- tuxpaint | [] [] [] [] [] [] |
- unicode-han-tra... | |
- unicode-transla... | |
- util-linux | [] [] [] [] |
- util-linux-ng | [] [] [] [] |
- vorbis-tools | [] |
wastesedge | |
- wdiff | [] [] [] [] [] [] [] |
- wget | [] [] [] [] |
- xchat | [] [] [] [] [] [] [] |
- xkeyboard-config | [] [] [] |
- xpad | [] [] [] |
+ wdiff | |
+ wget | [] [] |
+ wyslij-po | |
+ xchat | [] [] [] [] |
+ xdg-user-dirs | [] [] [] [] [] [] [] [] [] |
+ xkeyboard-config | [] [] |
+--------------------------------------------------+
- or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv ta
- 0 5 77 31 53 4 58 72 3 45 46 9 45 122 3
+ af am an ar as ast az be be@latin bg bn_IN bs ca
+ 6 0 1 2 3 19 1 10 3 28 3 1 38
+
+ crh cs da de el en en_GB en_ZA eo es et eu fa
+ +-------------------------------------------------+
+ a2ps | [] [] [] [] [] [] [] |
+ aegis | [] [] [] |
+ ant-phone | [] () |
+ anubis | [] [] |
+ aspell | [] [] [] [] [] |
+ bash | [] [] [] |
+ bfd | [] |
+ bibshelf | [] [] [] |
+ binutils | [] |
+ bison | [] [] |
+ bison-runtime | [] [] [] [] |
+ bluez-pin | [] [] [] [] [] [] |
+ bombono-dvd | [] |
+ buzztard | [] [] [] |
+ cflow | [] [] |
+ clisp | [] [] [] [] |
+ coreutils | [] [] [] [] |
+ cpio | |
+ cppi | |
+ cpplib | [] [] [] |
+ cryptsetup | [] |
+ dfarc | [] [] [] |
+ dialog | [] [] [] [] [] |
+ dico | |
+ diffutils | [] [] [] [] [] [] |
+ dink | [] [] [] |
+ doodle | [] |
+ e2fsprogs | [] [] [] |
+ enscript | [] [] [] |
+ exif | () [] [] |
+ fetchmail | [] [] () [] [] [] |
+ findutils | [] [] [] |
+ flex | [] [] |
+ freedink | [] [] [] |
+ gas | [] |
+ gawk | [] [] [] |
+ gcal | [] |
+ gcc | [] [] |
+ gettext-examples | [] [] [] [] |
+ gettext-runtime | [] [] [] [] |
+ gettext-tools | [] [] [] |
+ gip | [] [] [] [] |
+ gjay | [] |
+ gliv | [] [] [] |
+ glunarclock | [] [] |
+ gnubiff | () |
+ gnucash | [] () () () () |
+ gnuedu | [] [] |
+ gnulib | [] [] |
+ gnunet | |
+ gnunet-gtk | [] |
+ gnutls | [] [] |
+ gold | [] |
+ gpe-aerial | [] [] [] [] |
+ gpe-beam | [] [] [] [] |
+ gpe-bluetooth | [] [] |
+ gpe-calendar | [] |
+ gpe-clock | [] [] [] [] |
+ gpe-conf | [] [] [] |
+ gpe-contacts | [] [] [] |
+ gpe-edit | [] [] |
+ gpe-filemanager | [] [] [] |
+ gpe-go | [] [] [] [] |
+ gpe-login | [] [] |
+ gpe-ownerinfo | [] [] [] [] |
+ gpe-package | [] [] [] |
+ gpe-sketchbook | [] [] [] [] |
+ gpe-su | [] [] [] [] |
+ gpe-taskmanager | [] [] [] [] |
+ gpe-timesheet | [] [] [] [] |
+ gpe-today | [] [] [] [] |
+ gpe-todo | [] [] [] |
+ gphoto2 | [] [] () [] [] [] |
+ gprof | [] [] [] |
+ gpsdrive | [] [] [] |
+ gramadoir | [] [] [] |
+ grep | [] |
+ grub | [] [] |
+ gsasl | [] |
+ gss | |
+ gst-plugins-bad | [] [] [] [] [] |
+ gst-plugins-base | [] [] [] [] [] |
+ gst-plugins-good | [] [] [] [] [] [] |
+ gst-plugins-ugly | [] [] [] [] [] [] |
+ gstreamer | [] [] [] [] [] |
+ gtick | [] () [] |
+ gtkam | [] [] () [] [] |
+ gtkorphan | [] [] [] [] |
+ gtkspell | [] [] [] [] [] [] [] |
+ gutenprint | [] [] [] |
+ hello | [] [] [] [] |
+ help2man | [] |
+ hylafax | [] [] |
+ idutils | [] [] |
+ indent | [] [] [] [] [] [] [] |
+ iso_15924 | [] () [] [] |
+ iso_3166 | [] [] [] [] () [] [] [] () |
+ iso_3166_2 | () |
+ iso_4217 | [] [] [] () [] [] |
+ iso_639 | [] [] [] [] () [] [] |
+ iso_639_3 | [] |
+ jwhois | [] |
+ kbd | [] [] [] [] [] |
+ keytouch | [] [] |
+ keytouch-editor | [] [] |
+ keytouch-keyboa... | [] |
+ klavaro | [] [] [] [] |
+ latrine | [] () |
+ ld | [] [] |
+ leafpad | [] [] [] [] [] [] |
+ libc | [] [] [] [] |
+ libexif | [] [] () |
+ libextractor | |
+ libgnutls | [] |
+ libgpewidget | [] [] |
+ libgpg-error | [] [] |
+ libgphoto2 | [] () |
+ libgphoto2_port | [] () [] |
+ libgsasl | |
+ libiconv | [] [] [] [] [] |
+ libidn | [] [] [] |
+ lifelines | [] () |
+ liferea | [] [] [] [] [] |
+ lilypond | [] [] [] |
+ linkdr | [] [] [] |
+ lordsawar | [] |
+ lprng | |
+ lynx | [] [] [] [] |
+ m4 | [] [] [] [] |
+ mailfromd | |
+ mailutils | [] |
+ make | [] [] [] |
+ man-db | |
+ man-db-manpages | |
+ minicom | [] [] [] [] |
+ mkisofs | |
+ myserver | |
+ nano | [] [] [] |
+ opcodes | [] [] |
+ parted | [] [] |
+ pies | |
+ popt | [] [] [] [] [] |
+ psmisc | [] [] [] |
+ pspp | [] |
+ pwdutils | [] |
+ radius | [] |
+ recode | [] [] [] [] [] [] |
+ rosegarden | () () () |
+ rpm | [] [] [] |
+ rush | |
+ sarg | |
+ screem | |
+ scrollkeeper | [] [] [] [] [] |
+ sed | [] [] [] [] [] [] |
+ sharutils | [] [] [] [] |
+ shishi | |
+ skencil | [] () [] |
+ solfege | [] [] [] |
+ solfege-manual | [] [] |
+ soundtracker | [] [] [] |
+ sp | [] |
+ sysstat | [] [] [] |
+ tar | [] [] [] [] |
+ texinfo | [] [] [] |
+ tin | [] [] |
+ unicode-han-tra... | |
+ unicode-transla... | |
+ util-linux-ng | [] [] [] [] |
+ vice | () () |
+ vmm | [] |
+ vorbis-tools | [] [] |
+ wastesedge | [] |
+ wdiff | [] [] |
+ wget | [] [] [] |
+ wyslij-po | |
+ xchat | [] [] [] [] [] |
+ xdg-user-dirs | [] [] [] [] [] [] [] [] [] |
+ xkeyboard-config | [] [] [] [] [] [] |
+ +-------------------------------------------------+
+ crh cs da de el en en_GB en_ZA eo es et eu fa
+ 5 64 105 117 18 1 8 0 28 89 18 19 0
+
+ fi fr ga gl gu he hi hr hu hy id is it ja ka kn
+ +----------------------------------------------------+
+ a2ps | [] [] [] [] |
+ aegis | [] [] |
+ ant-phone | [] [] |
+ anubis | [] [] [] [] |
+ aspell | [] [] [] [] |
+ bash | [] [] [] [] |
+ bfd | [] [] [] |
+ bibshelf | [] [] [] [] [] |
+ binutils | [] [] [] |
+ bison | [] [] [] [] |
+ bison-runtime | [] [] [] [] [] [] |
+ bluez-pin | [] [] [] [] [] [] [] [] |
+ bombono-dvd | [] |
+ buzztard | [] |
+ cflow | [] [] [] |
+ clisp | [] |
+ coreutils | [] [] [] [] [] |
+ cpio | [] [] [] [] |
+ cppi | [] [] |
+ cpplib | [] [] [] |
+ cryptsetup | [] [] [] |
+ dfarc | [] [] [] |
+ dialog | [] [] [] [] [] [] [] |
+ dico | |
+ diffutils | [] [] [] [] [] [] [] [] [] |
+ dink | [] |
+ doodle | [] [] |
+ e2fsprogs | [] [] |
+ enscript | [] [] [] [] |
+ exif | [] [] [] [] [] [] |
+ fetchmail | [] [] [] [] |
+ findutils | [] [] [] [] [] [] |
+ flex | [] [] [] |
+ freedink | [] [] [] |
+ gas | [] [] |
+ gawk | [] [] [] [] () [] |
+ gcal | [] |
+ gcc | [] |
+ gettext-examples | [] [] [] [] [] [] [] |
+ gettext-runtime | [] [] [] [] [] [] |
+ gettext-tools | [] [] [] [] |
+ gip | [] [] [] [] [] [] |
+ gjay | [] |
+ gliv | [] () |
+ glunarclock | [] [] [] [] |
+ gnubiff | () [] () |
+ gnucash | () () () () () [] |
+ gnuedu | [] [] |
+ gnulib | [] [] [] [] [] [] |
+ gnunet | |
+ gnunet-gtk | [] |
+ gnutls | [] [] |
+ gold | [] [] |
+ gpe-aerial | [] [] [] |
+ gpe-beam | [] [] [] [] |
+ gpe-bluetooth | [] [] [] [] |
+ gpe-calendar | [] [] |
+ gpe-clock | [] [] [] [] [] |
+ gpe-conf | [] [] [] [] |
+ gpe-contacts | [] [] [] [] |
+ gpe-edit | [] [] [] |
+ gpe-filemanager | [] [] [] [] |
+ gpe-go | [] [] [] [] [] |
+ gpe-login | [] [] [] |
+ gpe-ownerinfo | [] [] [] [] [] |
+ gpe-package | [] [] [] |
+ gpe-sketchbook | [] [] [] [] |
+ gpe-su | [] [] [] [] [] [] |
+ gpe-taskmanager | [] [] [] [] [] |
+ gpe-timesheet | [] [] [] [] [] |
+ gpe-today | [] [] [] [] [] [] [] |
+ gpe-todo | [] [] [] |
+ gphoto2 | [] [] [] [] [] [] |
+ gprof | [] [] [] [] |
+ gpsdrive | [] [] [] |
+ gramadoir | [] [] [] |
+ grep | [] [] |
+ grub | [] [] [] [] |
+ gsasl | [] [] [] [] [] |
+ gss | [] [] [] [] [] |
+ gst-plugins-bad | [] [] [] [] [] [] |
+ gst-plugins-base | [] [] [] [] [] [] |
+ gst-plugins-good | [] [] [] [] [] [] |
+ gst-plugins-ugly | [] [] [] [] [] [] |
+ gstreamer | [] [] [] [] [] |
+ gtick | [] [] [] [] [] |
+ gtkam | [] [] [] [] [] |
+ gtkorphan | [] [] [] |
+ gtkspell | [] [] [] [] [] [] [] [] [] |
+ gutenprint | [] [] [] [] |
+ hello | [] [] [] |
+ help2man | [] [] |
+ hylafax | [] |
+ idutils | [] [] [] [] [] [] |
+ indent | [] [] [] [] [] [] [] [] |
+ iso_15924 | [] () [] [] |
+ iso_3166 | [] () [] [] [] [] [] [] [] [] [] [] |
+ iso_3166_2 | () [] [] [] |
+ iso_4217 | [] () [] [] [] [] |
+ iso_639 | [] () [] [] [] [] [] [] [] |
+ iso_639_3 | () [] [] |
+ jwhois | [] [] [] [] [] |
+ kbd | [] [] |
+ keytouch | [] [] [] [] [] [] |
+ keytouch-editor | [] [] [] [] [] |
+ keytouch-keyboa... | [] [] [] [] [] |
+ klavaro | [] [] |
+ latrine | [] [] [] |
+ ld | [] [] [] [] |
+ leafpad | [] [] [] [] [] [] [] () |
+ libc | [] [] [] [] [] |
+ libexif | [] |
+ libextractor | |
+ libgnutls | [] [] |
+ libgpewidget | [] [] [] [] |
+ libgpg-error | [] [] |
+ libgphoto2 | [] [] [] |
+ libgphoto2_port | [] [] [] |
+ libgsasl | [] [] [] [] [] |
+ libiconv | [] [] [] [] [] [] |
+ libidn | [] [] [] [] |
+ lifelines | () |
+ liferea | [] [] [] [] |
+ lilypond | [] [] |
+ linkdr | [] [] [] [] [] |
+ lordsawar | |
+ lprng | [] |
+ lynx | [] [] [] [] [] |
+ m4 | [] [] [] [] [] [] |
+ mailfromd | |
+ mailutils | [] [] |
+ make | [] [] [] [] [] [] [] [] [] |
+ man-db | [] [] |
+ man-db-manpages | [] |
+ minicom | [] [] [] [] [] |
+ mkisofs | [] [] [] [] |
+ myserver | |
+ nano | [] [] [] [] [] [] |
+ opcodes | [] [] [] [] |
+ parted | [] [] [] [] |
+ pies | |
+ popt | [] [] [] [] [] [] [] [] [] |
+ psmisc | [] [] [] |
+ pspp | |
+ pwdutils | [] [] |
+ radius | [] [] |
+ recode | [] [] [] [] [] [] [] [] |
+ rosegarden | () () () () () |
+ rpm | [] [] |
+ rush | |
+ sarg | [] |
+ screem | [] [] |
+ scrollkeeper | [] [] [] [] |
+ sed | [] [] [] [] [] [] [] [] |
+ sharutils | [] [] [] [] [] [] [] |
+ shishi | [] |
+ skencil | [] |
+ solfege | [] [] [] [] |
+ solfege-manual | [] [] |
+ soundtracker | [] [] |
+ sp | [] () |
+ sysstat | [] [] [] [] [] |
+ tar | [] [] [] [] [] [] [] |
+ texinfo | [] [] [] [] |
+ tin | [] |
+ unicode-han-tra... | |
+ unicode-transla... | [] [] |
+ util-linux-ng | [] [] [] [] [] [] |
+ vice | () () () |
+ vmm | [] |
+ vorbis-tools | [] |
+ wastesedge | () () |
+ wdiff | [] |
+ wget | [] [] [] [] [] [] [] [] |
+ wyslij-po | [] [] [] |
+ xchat | [] [] [] [] [] [] [] [] [] |
+ xdg-user-dirs | [] [] [] [] [] [] [] [] [] [] [] [] [] |
+ xkeyboard-config | [] [] [] [] [] |
+ +----------------------------------------------------+
+ fi fr ga gl gu he hi hr hu hy id is it ja ka kn
+ 105 121 53 20 4 8 3 5 53 2 120 5 84 67 0 4
+
+ ko ku ky lg lt lv mk ml mn mr ms mt nb nds ne
+ +-----------------------------------------------+
+ a2ps | [] |
+ aegis | |
+ ant-phone | |
+ anubis | [] [] |
+ aspell | [] |
+ bash | |
+ bfd | |
+ bibshelf | [] [] |
+ binutils | |
+ bison | [] |
+ bison-runtime | [] [] [] [] [] |
+ bluez-pin | [] [] [] [] [] |
+ bombono-dvd | |
+ buzztard | |
+ cflow | |
+ clisp | |
+ coreutils | [] |
+ cpio | |
+ cppi | |
+ cpplib | |
+ cryptsetup | |
+ dfarc | [] |
+ dialog | [] [] [] [] [] |
+ dico | |
+ diffutils | [] [] |
+ dink | |
+ doodle | |
+ e2fsprogs | |
+ enscript | |
+ exif | [] |
+ fetchmail | |
+ findutils | |
+ flex | |
+ freedink | [] |
+ gas | |
+ gawk | |
+ gcal | |
+ gcc | |
+ gettext-examples | [] [] [] [] |
+ gettext-runtime | [] |
+ gettext-tools | [] |
+ gip | [] [] |
+ gjay | |
+ gliv | |
+ glunarclock | [] |
+ gnubiff | |
+ gnucash | () () () () |
+ gnuedu | |
+ gnulib | |
+ gnunet | |
+ gnunet-gtk | |
+ gnutls | [] |
+ gold | |
+ gpe-aerial | [] |
+ gpe-beam | [] |
+ gpe-bluetooth | [] [] |
+ gpe-calendar | [] |
+ gpe-clock | [] [] [] [] [] |
+ gpe-conf | [] [] |
+ gpe-contacts | [] [] |
+ gpe-edit | [] |
+ gpe-filemanager | [] [] |
+ gpe-go | [] [] [] |
+ gpe-login | [] |
+ gpe-ownerinfo | [] [] |
+ gpe-package | [] [] |
+ gpe-sketchbook | [] [] |
+ gpe-su | [] [] [] [] [] [] |
+ gpe-taskmanager | [] [] [] [] [] [] |
+ gpe-timesheet | [] [] |
+ gpe-today | [] [] [] [] |
+ gpe-todo | [] [] |
+ gphoto2 | |
+ gprof | [] |
+ gpsdrive | |
+ gramadoir | |
+ grep | |
+ grub | |
+ gsasl | |
+ gss | |
+ gst-plugins-bad | [] [] [] [] |
+ gst-plugins-base | [] [] |
+ gst-plugins-good | [] [] |
+ gst-plugins-ugly | [] [] [] [] [] |
+ gstreamer | |
+ gtick | |
+ gtkam | [] |
+ gtkorphan | [] [] |
+ gtkspell | [] [] [] [] [] [] [] |
+ gutenprint | |
+ hello | [] [] [] |
+ help2man | |
+ hylafax | |
+ idutils | |
+ indent | |
+ iso_15924 | [] [] |
+ iso_3166 | [] [] () [] [] [] [] [] |
+ iso_3166_2 | |
+ iso_4217 | [] [] |
+ iso_639 | [] [] |
+ iso_639_3 | [] |
+ jwhois | [] |
+ kbd | |
+ keytouch | [] |
+ keytouch-editor | [] |
+ keytouch-keyboa... | [] |
+ klavaro | [] |
+ latrine | [] |
+ ld | |
+ leafpad | [] [] [] |
+ libc | [] |
+ libexif | |
+ libextractor | |
+ libgnutls | [] |
+ libgpewidget | [] [] |
+ libgpg-error | |
+ libgphoto2 | |
+ libgphoto2_port | |
+ libgsasl | |
+ libiconv | |
+ libidn | |
+ lifelines | |
+ liferea | |
+ lilypond | |
+ linkdr | |
+ lordsawar | |
+ lprng | |
+ lynx | |
+ m4 | |
+ mailfromd | |
+ mailutils | |
+ make | [] |
+ man-db | |
+ man-db-manpages | |
+ minicom | [] |
+ mkisofs | |
+ myserver | |
+ nano | [] [] |
+ opcodes | |
+ parted | |
+ pies | |
+ popt | [] [] [] |
+ psmisc | |
+ pspp | |
+ pwdutils | |
+ radius | |
+ recode | |
+ rosegarden | |
+ rpm | |
+ rush | |
+ sarg | |
+ screem | |
+ scrollkeeper | [] [] |
+ sed | |
+ sharutils | |
+ shishi | |
+ skencil | |
+ solfege | [] |
+ solfege-manual | |
+ soundtracker | |
+ sp | |
+ sysstat | [] |
+ tar | [] |
+ texinfo | [] |
+ tin | |
+ unicode-han-tra... | |
+ unicode-transla... | |
+ util-linux-ng | |
+ vice | |
+ vmm | |
+ vorbis-tools | |
+ wastesedge | |
+ wdiff | |
+ wget | [] |
+ wyslij-po | |
+ xchat | [] [] [] |
+ xdg-user-dirs | [] [] [] [] [] [] [] [] |
+ xkeyboard-config | [] [] [] |
+ +-----------------------------------------------+
+ ko ku ky lg lt lv mk ml mn mr ms mt nb nds ne
+ 20 5 10 1 13 48 4 2 2 4 24 10 20 3 1
+
+ nl nn or pa pl ps pt pt_BR ro ru rw sk sl sq sr
+ +---------------------------------------------------+
+ a2ps | [] [] [] [] [] [] [] [] |
+ aegis | [] [] [] |
+ ant-phone | [] [] |
+ anubis | [] [] [] |
+ aspell | [] [] [] [] [] |
+ bash | [] [] |
+ bfd | [] |
+ bibshelf | [] [] |
+ binutils | [] [] |
+ bison | [] [] [] |
+ bison-runtime | [] [] [] [] [] [] [] |
+ bluez-pin | [] [] [] [] [] [] [] [] |
+ bombono-dvd | [] () |
+ buzztard | [] [] |
+ cflow | [] |
+ clisp | [] [] |
+ coreutils | [] [] [] [] [] [] |
+ cpio | [] [] [] |
+ cppi | [] |
+ cpplib | [] |
+ cryptsetup | [] |
+ dfarc | [] |
+ dialog | [] [] [] [] |
+ dico | [] |
+ diffutils | [] [] [] [] [] [] |
+ dink | () |
+ doodle | [] [] |
+ e2fsprogs | [] [] |
+ enscript | [] [] [] [] [] |
+ exif | [] [] [] () [] |
+ fetchmail | [] [] [] [] |
+ findutils | [] [] [] [] [] |
+ flex | [] [] [] [] [] |
+ freedink | [] [] |
+ gas | |
+ gawk | [] [] [] [] |
+ gcal | |
+ gcc | [] |
+ gettext-examples | [] [] [] [] [] [] [] [] |
+ gettext-runtime | [] [] [] [] [] [] [] [] [] |
+ gettext-tools | [] [] [] [] [] [] |
+ gip | [] [] [] [] [] |
+ gjay | |
+ gliv | [] [] [] [] [] [] |
+ glunarclock | [] [] [] [] [] |
+ gnubiff | [] () |
+ gnucash | [] () () () |
+ gnuedu | [] |
+ gnulib | [] [] [] [] |
+ gnunet | |
+ gnunet-gtk | |
+ gnutls | [] [] |
+ gold | |
+ gpe-aerial | [] [] [] [] [] [] [] |
+ gpe-beam | [] [] [] [] [] [] [] |
+ gpe-bluetooth | [] [] |
+ gpe-calendar | [] [] [] [] |
+ gpe-clock | [] [] [] [] [] [] [] [] |
+ gpe-conf | [] [] [] [] [] [] [] |
+ gpe-contacts | [] [] [] [] [] |
+ gpe-edit | [] [] [] |
+ gpe-filemanager | [] [] [] |
+ gpe-go | [] [] [] [] [] [] [] [] |
+ gpe-login | [] [] |
+ gpe-ownerinfo | [] [] [] [] [] [] [] [] |
+ gpe-package | [] [] |
+ gpe-sketchbook | [] [] [] [] [] [] [] |
+ gpe-su | [] [] [] [] [] [] [] [] |
+ gpe-taskmanager | [] [] [] [] [] [] [] [] |
+ gpe-timesheet | [] [] [] [] [] [] [] [] |
+ gpe-today | [] [] [] [] [] [] [] [] |
+ gpe-todo | [] [] [] [] [] |
+ gphoto2 | [] [] [] [] [] [] [] [] |
+ gprof | [] [] [] |
+ gpsdrive | [] [] |
+ gramadoir | [] [] |
+ grep | [] [] [] [] |
+ grub | [] [] [] |
+ gsasl | [] [] [] [] |
+ gss | [] [] [] |
+ gst-plugins-bad | [] [] [] [] [] [] |
+ gst-plugins-base | [] [] [] [] [] |
+ gst-plugins-good | [] [] [] [] [] |
+ gst-plugins-ugly | [] [] [] [] [] [] |
+ gstreamer | [] [] [] [] [] |
+ gtick | [] [] [] |
+ gtkam | [] [] [] [] [] [] |
+ gtkorphan | [] |
+ gtkspell | [] [] [] [] [] [] [] [] [] [] |
+ gutenprint | [] [] |
+ hello | [] [] [] [] |
+ help2man | [] [] |
+ hylafax | [] |
+ idutils | [] [] [] [] [] |
+ indent | [] [] [] [] [] [] [] |
+ iso_15924 | [] [] [] [] |
+ iso_3166 | [] [] [] [] [] () [] [] [] [] [] [] [] [] |
+ iso_3166_2 | [] [] [] |
+ iso_4217 | [] [] [] [] [] [] [] [] |
+ iso_639 | [] [] [] [] [] [] [] [] [] |
+ iso_639_3 | [] [] |
+ jwhois | [] [] [] [] |
+ kbd | [] [] [] |
+ keytouch | [] [] [] |
+ keytouch-editor | [] [] [] |
+ keytouch-keyboa... | [] [] [] |
+ klavaro | [] [] |
+ latrine | [] [] |
+ ld | |
+ leafpad | [] [] [] [] [] [] [] [] [] |
+ libc | [] [] [] [] |
+ libexif | [] [] () [] |
+ libextractor | |
+ libgnutls | [] [] |
+ libgpewidget | [] [] [] |
+ libgpg-error | [] [] |
+ libgphoto2 | [] [] |
+ libgphoto2_port | [] [] [] [] [] |
+ libgsasl | [] [] [] [] [] |
+ libiconv | [] [] [] [] [] |
+ libidn | [] [] |
+ lifelines | [] [] |
+ liferea | [] [] [] [] [] () () [] |
+ lilypond | [] |
+ linkdr | [] [] [] |
+ lordsawar | |
+ lprng | [] |
+ lynx | [] [] [] |
+ m4 | [] [] [] [] [] |
+ mailfromd | [] |
+ mailutils | [] |
+ make | [] [] [] [] |
+ man-db | [] [] [] |
+ man-db-manpages | [] [] [] |
+ minicom | [] [] [] [] |
+ mkisofs | [] [] [] |
+ myserver | |
+ nano | [] [] [] [] |
+ opcodes | [] [] |
+ parted | [] [] [] [] |
+ pies | [] |
+ popt | [] [] [] [] |
+ psmisc | [] [] [] |
+ pspp | [] [] |
+ pwdutils | [] |
+ radius | [] [] [] |
+ recode | [] [] [] [] [] [] [] [] |
+ rosegarden | () () |
+ rpm | [] [] [] |
+ rush | [] [] |
+ sarg | |
+ screem | |
+ scrollkeeper | [] [] [] [] [] [] [] [] |
+ sed | [] [] [] [] [] [] [] [] [] |
+ sharutils | [] [] [] [] |
+ shishi | [] |
+ skencil | [] [] |
+ solfege | [] [] [] [] |
+ solfege-manual | [] [] [] |
+ soundtracker | [] |
+ sp | |
+ sysstat | [] [] [] [] |
+ tar | [] [] [] [] |
+ texinfo | [] [] [] [] |
+ tin | [] |
+ unicode-han-tra... | |
+ unicode-transla... | |
+ util-linux-ng | [] [] [] [] [] |
+ vice | [] |
+ vmm | [] |
+ vorbis-tools | [] [] |
+ wastesedge | [] |
+ wdiff | [] [] |
+ wget | [] [] [] [] [] [] [] |
+ wyslij-po | [] [] [] |
+ xchat | [] [] [] [] [] [] [] [] [] |
+ xdg-user-dirs | [] [] [] [] [] [] [] [] [] [] [] [] [] [] |
+ xkeyboard-config | [] [] [] |
+ +---------------------------------------------------+
+ nl nn or pa pl ps pt pt_BR ro ru rw sk sl sq sr
+ 135 10 4 7 105 1 29 62 47 91 3 54 46 9 37
- tg th tk tr uk ven vi wa xh zh_CN zh_HK zh_TW zu
+ sv sw ta te tg th tr uk vi wa zh_CN zh_HK zh_TW
+---------------------------------------------------+
- Compendium | [] [] [] [] | 19
- a2ps | [] [] [] | 19
- aegis | [] | 1
- ant-phone | [] [] | 6
- anubis | [] [] [] | 11
- ap-utils | () [] | 4
- aspell | [] [] [] | 16
- bash | [] | 6
- bfd | | 2
- bibshelf | [] | 7
- binutils | [] [] [] [] | 9
- bison | [] [] [] [] | 20
- bison-runtime | [] [] [] [] | 18
- bluez-pin | [] [] [] [] [] [] | 28
- cflow | [] [] | 5
- clisp | | 9
- console-tools | [] [] | 5
- coreutils | [] [] [] | 18
- cpio | [] [] [] [] | 11
- cpplib | [] [] [] [] [] | 12
- cryptonit | [] | 6
- dialog | [] [] [] | 9
- diffutils | [] [] [] [] [] | 29
- doodle | [] | 6
- e2fsprogs | [] [] | 10
- enscript | [] [] [] | 16
- fetchmail | [] [] | 12
- findutils | [] [] [] | 11
- findutils_stable | [] [] [] [] | 18
- flex | [] [] | 15
- fslint | [] | 2
- gas | [] | 3
- gawk | [] [] [] | 16
- gcal | [] | 5
- gcc | [] [] [] | 7
- gettext-examples | [] [] [] [] [] [] | 29
- gettext-runtime | [] [] [] [] [] [] | 28
- gettext-tools | [] [] [] [] [] | 20
- gip | [] [] | 13
- gliv | [] [] | 11
- glunarclock | [] [] [] | 15
- gmult | [] [] [] [] | 16
- gnubiff | [] | 2
- gnucash | () [] | 5
- gnuedu | [] | 2
- gnulib | [] | 10
- gnunet | | 0
- gnunet-gtk | [] [] | 3
- gnutls | | 4
- gpe-aerial | [] [] | 14
- gpe-beam | [] [] | 14
- gpe-calendar | [] [] | 7
- gpe-clock | [] [] [] [] | 21
- gpe-conf | [] [] [] | 16
- gpe-contacts | [] [] | 10
- gpe-edit | [] [] [] [] [] | 22
- gpe-filemanager | [] [] | 7
- gpe-go | [] [] [] [] | 19
- gpe-login | [] [] [] [] [] | 21
- gpe-ownerinfo | [] [] [] [] | 21
- gpe-package | [] | 6
- gpe-sketchbook | [] [] | 16
- gpe-su | [] [] [] [] | 21
- gpe-taskmanager | [] [] [] [] | 21
- gpe-timesheet | [] [] [] [] | 18
- gpe-today | [] [] [] [] [] | 21
- gpe-todo | [] [] | 8
- gphoto2 | [] [] [] [] | 21
- gprof | [] [] | 13
- gpsdrive | [] | 5
- gramadoir | [] | 7
- grep | [] | 12
- gretl | | 6
- gsasl | [] [] [] | 9
- gss | [] | 7
- gst-plugins-bad | [] [] [] | 13
- gst-plugins-base | [] [] | 11
- gst-plugins-good | [] [] [] [] [] | 16
- gst-plugins-ugly | [] [] [] | 13
- gstreamer | [] [] [] | 18
- gtick | [] [] | 7
- gtkam | [] | 16
- gtkorphan | [] | 7
- gtkspell | [] [] [] [] [] [] | 27
- gutenprint | | 4
- hello | [] [] [] [] [] | 38
- herrie | [] [] | 8
- hylafax | | 0
- idutils | [] [] | 15
- indent | [] [] [] [] [] | 28
- iso_15924 | [] [] | 4
- iso_3166 | [] [] [] [] [] [] [] [] [] | 54
- iso_3166_2 | [] [] | 4
- iso_4217 | [] [] [] [] [] | 24
- iso_639 | [] [] [] [] [] | 26
- jpilot | [] [] [] [] | 7
- jtag | [] | 3
- jwhois | [] [] [] | 13
- kbd | [] [] [] | 13
- keytouch | [] | 8
- keytouch-editor | [] | 5
- keytouch-keyboa... | [] | 5
- latrine | [] [] | 5
- ld | [] [] [] [] | 10
- leafpad | [] [] [] [] [] | 24
- libc | [] [] [] | 19
- libexif | [] | 5
- libextractor | [] | 5
- libgpewidget | [] [] [] | 20
- libgpg-error | [] | 6
- libgphoto2 | [] [] | 9
- libgphoto2_port | [] [] [] | 11
- libgsasl | [] | 8
- libiconv | [] [] | 11
- libidn | [] [] | 11
- lifelines | | 4
- lilypond | [] | 6
- lingoteach | [] | 6
- lprng | [] | 2
- lynx | [] [] [] | 15
- m4 | [] [] [] | 18
- mailfromd | [] [] | 3
- mailutils | [] [] | 8
- make | [] [] [] | 20
- man-db | [] | 9
- minicom | [] | 14
- nano | [] [] [] | 20
- opcodes | [] [] | 10
- parted | [] [] [] | 11
- pilot-qof | [] | 1
- popt | [] [] [] [] | 18
- psmisc | [] [] | 10
- pwdutils | [] | 3
- qof | [] | 4
- radius | [] [] | 7
- recode | [] [] [] | 25
- rpm | [] [] [] [] | 13
- screem | [] | 2
- scrollkeeper | [] [] [] [] | 26
- sed | [] [] [] [] | 23
- shared-mime-info | [] [] [] | 29
- sharutils | [] [] [] | 23
- shishi | [] | 3
- skencil | [] | 7
- solfege | [] | 3
- soundtracker | [] [] | 9
- sp | [] | 3
- system-tools-ba... | [] [] [] [] [] [] [] | 38
- tar | [] [] [] | 17
- texinfo | [] [] [] | 15
- tin | | 1
- tuxpaint | [] [] [] | 19
+ a2ps | [] [] [] [] [] | 27
+ aegis | [] | 9
+ ant-phone | [] [] [] [] | 9
+ anubis | [] [] [] [] | 15
+ aspell | [] [] [] | 20
+ bash | [] [] [] | 12
+ bfd | [] | 6
+ bibshelf | [] [] [] | 16
+ binutils | [] [] | 8
+ bison | [] [] | 12
+ bison-runtime | [] [] [] [] [] [] | 29
+ bluez-pin | [] [] [] [] [] [] [] [] | 37
+ bombono-dvd | [] | 4
+ buzztard | [] | 7
+ cflow | [] [] [] | 9
+ clisp | | 10
+ coreutils | [] [] [] [] | 22
+ cpio | [] [] [] [] [] [] | 13
+ cppi | [] [] | 5
+ cpplib | [] [] [] [] [] [] | 14
+ cryptsetup | [] [] | 7
+ dfarc | [] | 9
+ dialog | [] [] [] [] [] [] [] | 30
+ dico | [] | 2
+ diffutils | [] [] [] [] [] [] | 30
+ dink | | 4
+ doodle | [] [] | 7
+ e2fsprogs | [] [] [] | 11
+ enscript | [] [] [] [] | 17
+ exif | [] [] [] | 16
+ fetchmail | [] [] [] | 17
+ findutils | [] [] [] [] [] | 20
+ flex | [] [] [] [] | 15
+ freedink | [] | 10
+ gas | [] | 4
+ gawk | [] [] [] [] | 18
+ gcal | [] [] | 5
+ gcc | [] [] [] | 7
+ gettext-examples | [] [] [] [] [] [] [] | 34
+ gettext-runtime | [] [] [] [] [] [] [] | 29
+ gettext-tools | [] [] [] [] [] [] | 22
+ gip | [] [] [] [] | 22
+ gjay | [] | 3
+ gliv | [] [] [] | 14
+ glunarclock | [] [] [] [] [] | 19
+ gnubiff | [] [] | 4
+ gnucash | () [] () [] () | 10
+ gnuedu | [] [] | 7
+ gnulib | [] [] [] [] | 16
+ gnunet | [] | 1
+ gnunet-gtk | [] [] [] | 5
+ gnutls | [] [] [] | 10
+ gold | [] | 4
+ gpe-aerial | [] [] [] | 18
+ gpe-beam | [] [] [] | 19
+ gpe-bluetooth | [] [] [] | 13
+ gpe-calendar | [] [] [] [] | 12
+ gpe-clock | [] [] [] [] [] | 28
+ gpe-conf | [] [] [] [] | 20
+ gpe-contacts | [] [] [] | 17
+ gpe-edit | [] [] [] | 12
+ gpe-filemanager | [] [] [] [] | 16
+ gpe-go | [] [] [] [] [] | 25
+ gpe-login | [] [] [] | 11
+ gpe-ownerinfo | [] [] [] [] [] | 25
+ gpe-package | [] [] [] | 13
+ gpe-sketchbook | [] [] [] | 20
+ gpe-su | [] [] [] [] [] | 30
+ gpe-taskmanager | [] [] [] [] [] | 29
+ gpe-timesheet | [] [] [] [] [] | 25
+ gpe-today | [] [] [] [] [] [] | 30
+ gpe-todo | [] [] [] [] | 17
+ gphoto2 | [] [] [] [] [] | 24
+ gprof | [] [] [] | 15
+ gpsdrive | [] [] [] | 11
+ gramadoir | [] [] [] | 11
+ grep | [] [] [] | 10
+ grub | [] [] [] | 14
+ gsasl | [] [] [] [] | 14
+ gss | [] [] [] | 11
+ gst-plugins-bad | [] [] [] [] | 26
+ gst-plugins-base | [] [] [] [] [] | 24
+ gst-plugins-good | [] [] [] [] | 24
+ gst-plugins-ugly | [] [] [] [] [] | 29
+ gstreamer | [] [] [] [] | 22
+ gtick | [] [] [] | 13
+ gtkam | [] [] [] | 20
+ gtkorphan | [] [] [] | 14
+ gtkspell | [] [] [] [] [] [] [] [] [] | 45
+ gutenprint | [] | 10
+ hello | [] [] [] [] [] [] | 21
+ help2man | [] [] | 7
+ hylafax | [] | 5
+ idutils | [] [] [] [] | 17
+ indent | [] [] [] [] [] [] | 30
+ iso_15924 | () [] () [] [] | 16
+ iso_3166 | [] [] () [] [] () [] [] [] () | 53
+ iso_3166_2 | () [] () [] | 9
+ iso_4217 | [] () [] [] () [] [] | 26
+ iso_639 | [] [] [] () [] () [] [] [] [] | 38
+ iso_639_3 | [] () | 8
+ jwhois | [] [] [] [] [] | 16
+ kbd | [] [] [] [] [] | 15
+ keytouch | [] [] [] | 16
+ keytouch-editor | [] [] [] | 14
+ keytouch-keyboa... | [] [] [] | 14
+ klavaro | [] | 11
+ latrine | [] [] [] | 10
+ ld | [] [] [] [] | 11
+ leafpad | [] [] [] [] [] [] | 33
+ libc | [] [] [] [] [] | 21
+ libexif | [] () | 7
+ libextractor | [] | 1
+ libgnutls | [] [] [] | 9
+ libgpewidget | [] [] [] | 14
+ libgpg-error | [] [] [] | 9
+ libgphoto2 | [] [] | 8
+ libgphoto2_port | [] [] [] [] | 14
+ libgsasl | [] [] [] | 13
+ libiconv | [] [] [] [] | 21
+ libidn | () [] [] | 11
+ lifelines | [] | 4
+ liferea | [] [] [] | 21
+ lilypond | [] | 7
+ linkdr | [] [] [] [] [] | 17
+ lordsawar | | 1
+ lprng | [] | 3
+ lynx | [] [] [] [] | 17
+ m4 | [] [] [] [] | 19
+ mailfromd | [] [] | 3
+ mailutils | [] | 5
+ make | [] [] [] [] | 21
+ man-db | [] [] [] | 8
+ man-db-manpages | | 4
+ minicom | [] [] | 16
+ mkisofs | [] [] | 9
+ myserver | | 0
+ nano | [] [] [] [] | 21
+ opcodes | [] [] [] | 11
+ parted | [] [] [] [] [] | 15
+ pies | [] [] | 3
+ popt | [] [] [] [] [] [] | 27
+ psmisc | [] [] | 11
+ pspp | | 4
+ pwdutils | [] [] | 6
+ radius | [] [] | 9
+ recode | [] [] [] [] | 28
+ rosegarden | () | 0
+ rpm | [] [] [] | 11
+ rush | [] [] | 4
+ sarg | | 1
+ screem | [] | 3
+ scrollkeeper | [] [] [] [] [] | 27
+ sed | [] [] [] [] [] | 30
+ sharutils | [] [] [] [] [] | 22
+ shishi | [] | 3
+ skencil | [] [] | 7
+ solfege | [] [] [] [] | 16
+ solfege-manual | [] | 8
+ soundtracker | [] [] [] | 9
+ sp | [] | 3
+ sysstat | [] [] | 15
+ tar | [] [] [] [] [] [] | 23
+ texinfo | [] [] [] [] [] | 17
+ tin | | 4
unicode-han-tra... | | 0
unicode-transla... | | 2
- util-linux | [] [] [] | 20
- util-linux-ng | [] [] [] | 20
- vorbis-tools | [] [] | 4
- wastesedge | | 1
- wdiff | [] [] | 23
- wget | [] [] [] | 20
- xchat | [] [] [] [] | 29
- xkeyboard-config | [] [] [] | 14
- xpad | [] [] [] | 15
+ util-linux-ng | [] [] [] [] | 20
+ vice | () () | 1
+ vmm | [] | 4
+ vorbis-tools | [] | 6
+ wastesedge | | 2
+ wdiff | [] [] | 7
+ wget | [] [] [] [] [] | 26
+ wyslij-po | [] [] | 8
+ xchat | [] [] [] [] [] [] | 36
+ xdg-user-dirs | [] [] [] [] [] [] [] [] [] [] | 63
+ xkeyboard-config | [] [] [] | 22
+---------------------------------------------------+
- 76 teams tg th tk tr uk ven vi wa xh zh_CN zh_HK zh_TW zu
- 163 domains 0 3 1 74 51 0 143 21 1 57 7 45 0 2036
+ 85 teams sv sw ta te tg th tr uk vi wa zh_CN zh_HK zh_TW
+ 178 domains 119 1 3 3 0 10 65 51 155 17 98 7 41 2618
Some counters in the preceding matrix are higher than the number of
visible blocks let us expect. This is because a few extra PO files are
@@ -1042,12 +1256,12 @@
lag between the mere existence a PO file and its wide availability in a
distribution.
- If November 2007 seems to be old, you may fetch a more recent copy
-of this `ABOUT-NLS' file on most GNU archive sites. The most
-up-to-date matrix with full percentage details can be found at
+ If June 2010 seems to be old, you may fetch a more recent copy of
+this `ABOUT-NLS' file on most GNU archive sites. The most up-to-date
+matrix with full percentage details can be found at
`http://translationproject.org/extra/matrix.html'.
-1.6 Using `gettext' in new packages
+1.5 Using `gettext' in new packages
===================================
If you are writing a freely available program and want to
diff -Nru gnupg2-2.1.6~build1/acinclude.m4 gnupg2-2.0.28/acinclude.m4
--- gnupg2-2.1.6~build1/acinclude.m4 2015-06-17 06:39:24.000000000 +0000
+++ gnupg2-2.0.28/acinclude.m4 2015-06-02 08:13:55.000000000 +0000
@@ -7,12 +7,12 @@
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation; either version 3 of the License, or
dnl (at your option) any later version.
-dnl
+dnl
dnl GnuPG is distributed in the hope that it will be useful,
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
dnl GNU General Public License for more details.
-dnl
+dnl
dnl You should have received a copy of the GNU General Public License
dnl along with this program; if not, see .
@@ -38,7 +38,7 @@
dnl GNUPG_CHECK_GNUMAKE
dnl
AC_DEFUN([GNUPG_CHECK_GNUMAKE],
- [
+ [
if ${MAKE-make} --version 2>/dev/null | grep '^GNU ' >/dev/null 2>&1; then
:
else
@@ -59,7 +59,7 @@
if faqprog.pl -V 2>/dev/null | grep '^faqprog.pl ' >/dev/null 2>&1; then
working_faqprog=yes
FAQPROG="faqprog.pl"
- else
+ else
working_faqprog=no
FAQPROG=": "
fi
@@ -77,7 +77,7 @@
dnl *** No need to worry about this warning.
dnl ***]])
dnl fi
- ])
+ ])
dnl GNUPG_CHECK_DOCBOOK_TO_TEXI
dnl
@@ -93,7 +93,7 @@
fi
AC_MSG_RESULT($working_sgmltotexi)
AM_CONDITIONAL(HAVE_DOCBOOK_TO_TEXI, test "$working_sgmltotexi" = "yes" )
- ])
+ ])
@@ -103,7 +103,6 @@
AC_DEFUN([GNUPG_CHECK_ENDIAN],
[
tmp_assumed_endian=big
- tmp_assume_warn=""
if test "$cross_compiling" = yes; then
case "$host_cpu" in
i@<:@345678@:>@* )
@@ -112,6 +111,7 @@
*)
;;
esac
+ AC_MSG_WARN(cross compiling; assuming $tmp_assumed_endian endianess)
fi
AC_MSG_CHECKING(endianess)
AC_CACHE_VAL(gnupg_cv_c_endian,
@@ -141,11 +141,10 @@
gnupg_cv_c_endian=little,
gnupg_cv_c_endian=big,
gnupg_cv_c_endian=$tmp_assumed_endian
- tmp_assumed_warn=" (assumed)"
)
fi
])
- AC_MSG_RESULT([${gnupg_cv_c_endian}${tmp_assumed_warn}])
+ AC_MSG_RESULT([$gnupg_cv_c_endian])
if test "$gnupg_cv_c_endian" = little; then
AC_DEFINE(LITTLE_ENDIAN_HOST,1,
[Defined if the host has little endian byte ordering])
@@ -162,7 +161,7 @@
# Add a --enable-NAME option to configure an set the
# shell variable build_NAME either to "yes" or "no". DEFAULT must
# either be "yes" or "no" and decided on the default value for
-# build_NAME and whether --enable-NAME or --disable-NAME is shown with
+# build_NAME and whether --enable-NAME or --disable-NAME is shown with
# ./configure --help
AC_DEFUN([GNUPG_BUILD_PROGRAM],
[build_$1=$2
@@ -178,7 +177,7 @@
case "$build_$1" in
no|yes)
;;
- *)
+ *)
AC_MSG_ERROR([only yes or no allowed for feature --enable-$1])
;;
esac
@@ -186,23 +185,6 @@
-# GNUPG_DISABLE_GPG_ALGO(NAME,DESCRIPTION)
-#
-# Add a --disable-gpg-NAME option and the corresponding ac_define
-# GPG_USE_.
-AC_DEFUN([GNUPG_GPG_DISABLE_ALGO],
- [AC_MSG_CHECKING([whether to enable the $2 for gpg])
- AC_ARG_ENABLE([gpg-$1], AC_HELP_STRING([--disable-gpg-$1],
- [disable the $2 algorithm in gpg]),
- , enableval=yes)
- AC_MSG_RESULT($enableval)
- if test x"$enableval" = xyes ; then
- AC_DEFINE(GPG_USE_[]m4_toupper($1), 1, [Define to support the $2])
- fi
- ])
-
-
-
# Check whether mlock is broken (hpux 10.20 raises a SIGBUS if mlock
# is not called from uid 0 (not tested whether uid 0 works)
@@ -322,28 +304,5 @@
])
-# GNUPG_TIME_T_UNSIGNED
-# Check whether time_t is unsigned
-#
-AC_DEFUN([GNUPG_TIME_T_UNSIGNED],
- [ AC_CACHE_CHECK(whether time_t is unsigned, gnupg_cv_time_t_unsigned,
- [AC_REQUIRE([AC_HEADER_TIME])dnl
- AC_COMPILE_IFELSE([AC_LANG_BOOL_COMPILE_TRY(
- [AC_INCLUDES_DEFAULT([])
-#if TIME_WITH_SYS_TIME
-# include
-# include
-#else
-# if HAVE_SYS_TIME_H
-# include
-# else
-# include
-# endif
-#endif
-],
- [((time_t)-1) < 0])],
- gnupg_cv_time_t_unsigned=no, gnupg_cv_time_t_unsigned=yes)])
- if test $gnupg_cv_time_t_unsigned = yes; then
- AC_DEFINE(HAVE_UNSIGNED_TIME_T,1,[Defined if time_t is an unsigned type])
- fi
-])# GNUPG_TIME_T_UNSIGNED
+
+
diff -Nru gnupg2-2.1.6~build1/aclocal.m4 gnupg2-2.0.28/aclocal.m4
--- gnupg2-2.1.6~build1/aclocal.m4 2015-06-17 10:46:52.000000000 +0000
+++ gnupg2-2.0.28/aclocal.m4 2015-06-02 08:37:24.000000000 +0000
@@ -77,220 +77,119 @@
AC_SUBST([INTL_MACOSX_LIBS])
])
-# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
-# serial 1 (pkg-config-0.24)
-#
-# Copyright © 2004 Scott James Remnant .
-#
-# This program 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 2 of the License, or
-# (at your option) any later version.
-#
-# This program 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, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# PKG_PROG_PKG_CONFIG([MIN-VERSION])
-# ----------------------------------
-AC_DEFUN([PKG_PROG_PKG_CONFIG],
-[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
-m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
-m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
-AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
-AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
-AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
-
-if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
- AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
-fi
-if test -n "$PKG_CONFIG"; then
- _pkg_min_version=m4_default([$1], [0.9.0])
- AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
- if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- PKG_CONFIG=""
- fi
-fi[]dnl
-])# PKG_PROG_PKG_CONFIG
-
-# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-#
-# Check to see whether a particular set of modules exists. Similar
-# to PKG_CHECK_MODULES(), but does not set variables or print errors.
-#
-# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
-# only at the first occurence in configure.ac, so if the first place
-# it's called might be skipped (such as if it is within an "if", you
-# have to call PKG_CHECK_EXISTS manually
-# --------------------------------------------------------------
-AC_DEFUN([PKG_CHECK_EXISTS],
-[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
-if test -n "$PKG_CONFIG" && \
- AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
- m4_default([$2], [:])
-m4_ifvaln([$3], [else
- $3])dnl
-fi])
-
-# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
-# ---------------------------------------------
-m4_define([_PKG_CONFIG],
-[if test -n "$$1"; then
- pkg_cv_[]$1="$$1"
- elif test -n "$PKG_CONFIG"; then
- PKG_CHECK_EXISTS([$3],
- [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
- test "x$?" != "x0" && pkg_failed=yes ],
- [pkg_failed=yes])
- else
- pkg_failed=untried
-fi[]dnl
-])# _PKG_CONFIG
-
-# _PKG_SHORT_ERRORS_SUPPORTED
-# -----------------------------
-AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
-[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
- _pkg_short_errors_supported=yes
-else
- _pkg_short_errors_supported=no
-fi[]dnl
-])# _PKG_SHORT_ERRORS_SUPPORTED
-
-
-# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
-# [ACTION-IF-NOT-FOUND])
-#
-#
-# Note that if there is a possibility the first call to
-# PKG_CHECK_MODULES might not happen, you should be sure to include an
-# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
-#
-#
-# --------------------------------------------------------------
-AC_DEFUN([PKG_CHECK_MODULES],
-[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
-AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
-AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
-
-pkg_failed=no
-AC_MSG_CHECKING([for $1])
-
-_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
-_PKG_CONFIG([$1][_LIBS], [libs], [$2])
-
-m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
-and $1[]_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details.])
-
-if test $pkg_failed = yes; then
- AC_MSG_RESULT([no])
- _PKG_SHORT_ERRORS_SUPPORTED
- if test $_pkg_short_errors_supported = yes; then
- $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
- else
- $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
+# longlong.m4 serial 17
+dnl Copyright (C) 1999-2007, 2009-2014 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+# Define HAVE_LONG_LONG_INT if 'long long int' works.
+# This fixes a bug in Autoconf 2.61, and can be faster
+# than what's in Autoconf 2.62 through 2.68.
+
+# Note: If the type 'long long int' exists but is only 32 bits large
+# (as on some very old compilers), HAVE_LONG_LONG_INT will not be
+# defined. In this case you can treat 'long long int' like 'long int'.
+
+AC_DEFUN([AC_TYPE_LONG_LONG_INT],
+[
+ AC_REQUIRE([AC_TYPE_UNSIGNED_LONG_LONG_INT])
+ AC_CACHE_CHECK([for long long int], [ac_cv_type_long_long_int],
+ [ac_cv_type_long_long_int=yes
+ if test "x${ac_cv_prog_cc_c99-no}" = xno; then
+ ac_cv_type_long_long_int=$ac_cv_type_unsigned_long_long_int
+ if test $ac_cv_type_long_long_int = yes; then
+ dnl Catch a bug in Tandem NonStop Kernel (OSS) cc -O circa 2004.
+ dnl If cross compiling, assume the bug is not important, since
+ dnl nobody cross compiles for this platform as far as we know.
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[@%:@include
+ @%:@ifndef LLONG_MAX
+ @%:@ define HALF \
+ (1LL << (sizeof (long long int) * CHAR_BIT - 2))
+ @%:@ define LLONG_MAX (HALF - 1 + HALF)
+ @%:@endif]],
+ [[long long int n = 1;
+ int i;
+ for (i = 0; ; i++)
+ {
+ long long int m = n << i;
+ if (m >> i != n)
+ return 1;
+ if (LLONG_MAX / 2 < m)
+ break;
+ }
+ return 0;]])],
+ [],
+ [ac_cv_type_long_long_int=no],
+ [:])
fi
- # Put the nasty error message in config.log where it belongs
- echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
-
- m4_default([$4], [AC_MSG_ERROR(
-[Package requirements ($2) were not met:
-
-$$1_PKG_ERRORS
-
-Consider adjusting the PKG_CONFIG_PATH environment variable if you
-installed software in a non-standard prefix.
-
-_PKG_TEXT])[]dnl
- ])
-elif test $pkg_failed = untried; then
- AC_MSG_RESULT([no])
- m4_default([$4], [AC_MSG_FAILURE(
-[The pkg-config script could not be found or is too old. Make sure it
-is in your PATH or set the PKG_CONFIG environment variable to the full
-path to pkg-config.
-
-_PKG_TEXT
-
-To get pkg-config, see .])[]dnl
- ])
-else
- $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
- $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
- AC_MSG_RESULT([yes])
- $3
-fi[]dnl
-])# PKG_CHECK_MODULES
-
-
-# PKG_INSTALLDIR(DIRECTORY)
-# -------------------------
-# Substitutes the variable pkgconfigdir as the location where a module
-# should install pkg-config .pc files. By default the directory is
-# $libdir/pkgconfig, but the default can be changed by passing
-# DIRECTORY. The user can override through the --with-pkgconfigdir
-# parameter.
-AC_DEFUN([PKG_INSTALLDIR],
-[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
-m4_pushdef([pkg_description],
- [pkg-config installation directory @<:@]pkg_default[@:>@])
-AC_ARG_WITH([pkgconfigdir],
- [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
- [with_pkgconfigdir=]pkg_default)
-AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
-m4_popdef([pkg_default])
-m4_popdef([pkg_description])
-]) dnl PKG_INSTALLDIR
-
-
-# PKG_NOARCH_INSTALLDIR(DIRECTORY)
-# -------------------------
-# Substitutes the variable noarch_pkgconfigdir as the location where a
-# module should install arch-independent pkg-config .pc files. By
-# default the directory is $datadir/pkgconfig, but the default can be
-# changed by passing DIRECTORY. The user can override through the
-# --with-noarch-pkgconfigdir parameter.
-AC_DEFUN([PKG_NOARCH_INSTALLDIR],
-[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
-m4_pushdef([pkg_description],
- [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
-AC_ARG_WITH([noarch-pkgconfigdir],
- [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
- [with_noarch_pkgconfigdir=]pkg_default)
-AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
-m4_popdef([pkg_default])
-m4_popdef([pkg_description])
-]) dnl PKG_NOARCH_INSTALLDIR
-
-
-# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
-# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-# -------------------------------------------
-# Retrieves the value of the pkg-config variable for the given module.
-AC_DEFUN([PKG_CHECK_VAR],
-[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
-AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
+ fi])
+ if test $ac_cv_type_long_long_int = yes; then
+ AC_DEFINE([HAVE_LONG_LONG_INT], [1],
+ [Define to 1 if the system has the type 'long long int'.])
+ fi
+])
-_PKG_CONFIG([$1], [variable="][$3]["], [$2])
-AS_VAR_COPY([$1], [pkg_cv_][$1])
+# Define HAVE_UNSIGNED_LONG_LONG_INT if 'unsigned long long int' works.
+# This fixes a bug in Autoconf 2.61, and can be faster
+# than what's in Autoconf 2.62 through 2.68.
+
+# Note: If the type 'unsigned long long int' exists but is only 32 bits
+# large (as on some very old compilers), AC_TYPE_UNSIGNED_LONG_LONG_INT
+# will not be defined. In this case you can treat 'unsigned long long int'
+# like 'unsigned long int'.
+
+AC_DEFUN([AC_TYPE_UNSIGNED_LONG_LONG_INT],
+[
+ AC_CACHE_CHECK([for unsigned long long int],
+ [ac_cv_type_unsigned_long_long_int],
+ [ac_cv_type_unsigned_long_long_int=yes
+ if test "x${ac_cv_prog_cc_c99-no}" = xno; then
+ AC_LINK_IFELSE(
+ [_AC_TYPE_LONG_LONG_SNIPPET],
+ [],
+ [ac_cv_type_unsigned_long_long_int=no])
+ fi])
+ if test $ac_cv_type_unsigned_long_long_int = yes; then
+ AC_DEFINE([HAVE_UNSIGNED_LONG_LONG_INT], [1],
+ [Define to 1 if the system has the type 'unsigned long long int'.])
+ fi
+])
-AS_VAR_IF([$1], [""], [$5], [$4])dnl
-])# PKG_CHECK_VAR
+# Expands to a C program that can be used to test for simultaneous support
+# of 'long long' and 'unsigned long long'. We don't want to say that
+# 'long long' is available if 'unsigned long long' is not, or vice versa,
+# because too many programs rely on the symmetry between signed and unsigned
+# integer types (excluding 'bool').
+AC_DEFUN([_AC_TYPE_LONG_LONG_SNIPPET],
+[
+ AC_LANG_PROGRAM(
+ [[/* For now, do not test the preprocessor; as of 2007 there are too many
+ implementations with broken preprocessors. Perhaps this can
+ be revisited in 2012. In the meantime, code should not expect
+ #if to work with literals wider than 32 bits. */
+ /* Test literals. */
+ long long int ll = 9223372036854775807ll;
+ long long int nll = -9223372036854775807LL;
+ unsigned long long int ull = 18446744073709551615ULL;
+ /* Test constant expressions. */
+ typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll)
+ ? 1 : -1)];
+ typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1
+ ? 1 : -1)];
+ int i = 63;]],
+ [[/* Test availability of runtime routines for shift and division. */
+ long long int llmax = 9223372036854775807ll;
+ unsigned long long int ullmax = 18446744073709551615ull;
+ return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i)
+ | (llmax / ll) | (llmax % ll)
+ | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i)
+ | (ullmax / ull) | (ullmax % ull));]])
+])
# Copyright (C) 2002-2013 Free Software Foundation, Inc.
#
@@ -1039,6 +938,35 @@
fi
])
+# -*- Autoconf -*-
+# Obsolete and "removed" macros, that must however still report explicit
+# error messages when used, to smooth transition.
+#
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([AM_CONFIG_HEADER],
+[AC_DIAGNOSE([obsolete],
+['$0': this macro is obsolete.
+You should use the 'AC][_CONFIG_HEADERS' macro instead.])dnl
+AC_CONFIG_HEADERS($@)])
+
+AC_DEFUN([AM_PROG_CC_STDC],
+[AC_PROG_CC
+am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc
+AC_DIAGNOSE([obsolete],
+['$0': this macro is obsolete.
+You should simply use the 'AC][_PROG_CC' macro instead.
+Also, your code should no longer depend upon 'am_cv_prog_cc_stdc',
+but upon 'ac_cv_prog_cc_stdc'.])])
+
+AC_DEFUN([AM_C_PROTOTYPES],
+ [AC_FATAL([automatic de-ANSI-fication support has been removed])])
+AU_DEFUN([fp_C_PROTOTYPES], [AM_C_PROTOTYPES])
+
# Helper functions for option handling. -*- Autoconf -*-
# Copyright (C) 2001-2013 Free Software Foundation, Inc.
@@ -1455,9 +1383,22 @@
AC_SUBST([am__untar])
]) # _AM_PROG_TAR
+m4_include([gl/m4/absolute-header.m4])
+m4_include([gl/m4/alloca.m4])
+m4_include([gl/m4/allocsa.m4])
+m4_include([gl/m4/eealloc.m4])
+m4_include([gl/m4/gnulib-comp.m4])
+m4_include([gl/m4/gnulib-tool.m4])
+m4_include([gl/m4/mkdtemp.m4])
+m4_include([gl/m4/setenv.m4])
+m4_include([gl/m4/stdint.m4])
+m4_include([gl/m4/strpbrk.m4])
+m4_include([gl/m4/unistd_h.m4])
m4_include([m4/autobuild.m4])
m4_include([m4/codeset.m4])
+m4_include([m4/estream.m4])
m4_include([m4/gettext.m4])
+m4_include([m4/gnupg-pth.m4])
m4_include([m4/gpg-error.m4])
m4_include([m4/iconv.m4])
m4_include([m4/isc-posix.m4])
@@ -1468,14 +1409,16 @@
m4_include([m4/lib-link.m4])
m4_include([m4/lib-prefix.m4])
m4_include([m4/libassuan.m4])
+m4_include([m4/libcurl.m4])
m4_include([m4/libgcrypt.m4])
+m4_include([m4/longdouble.m4])
m4_include([m4/nls.m4])
-m4_include([m4/npth.m4])
-m4_include([m4/ntbtls.m4])
m4_include([m4/po.m4])
m4_include([m4/progtest.m4])
m4_include([m4/readline.m4])
+m4_include([m4/size_max.m4])
m4_include([m4/socklen.m4])
m4_include([m4/sys_socket_h.m4])
m4_include([m4/tar-ustar.m4])
+m4_include([m4/xsize.m4])
m4_include([acinclude.m4])
diff -Nru gnupg2-2.1.6~build1/agent/agent.h gnupg2-2.0.28/agent/agent.h
--- gnupg2-2.1.6~build1/agent/agent.h 2015-06-30 20:26:08.000000000 +0000
+++ gnupg2-2.0.28/agent/agent.h 2015-06-02 08:13:55.000000000 +0000
@@ -1,6 +1,5 @@
/* agent.h - Global definitions for the agent
- * Copyright (C) 2001, 2002, 2003, 2005, 2011 Free Software Foundation, Inc.
- * Copyright (C) 2015 g10 Code GmbH.
+ * Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -35,7 +34,6 @@
#include "../common/membuf.h"
#include "../common/sysutils.h" /* (gnupg_fd_t) */
#include "../common/session-env.h"
-#include "../common/shareddefs.h"
/* To convey some special hash algorithms we use algorithm numbers
reserved for application use. */
@@ -47,8 +45,6 @@
/* Maximum length of a digest. */
#define MAX_DIGEST_LEN 64
-
-
/* A large struct name "opt" to keep global flags */
struct
{
@@ -59,26 +55,23 @@
int batch; /* Batch mode */
const char *homedir; /* Configuration directory name */
- /* True if we handle sigusr2. */
- int sigusr2_enabled;
-
- /* Environment settings gathered at program start or changed using the
+ /* Environment setting gathered at program start or changed using the
Assuan command UPDATESTARTUPTTY. */
session_env_t startup_env;
char *startup_lc_ctype;
char *startup_lc_messages;
- /* Enable pinentry debugging (--debug 1024 should also be used). */
- int debug_pinentry;
-
- /* Filename of the program to start as pinentry. */
- const char *pinentry_program;
+ /* True if we are listening on the standard socket. */
+ int use_standard_socket;
- /* Filename of the program to handle smartcard tasks. */
- const char *scdaemon_program;
+ /* True if we handle sigusr2. */
+ int sigusr2_enabled;
+ const char *pinentry_program; /* Filename of the program to start as
+ pinentry. */
+ const char *scdaemon_program; /* Filename of the program to handle
+ smartcard tasks. */
int disable_scdaemon; /* Never use the SCdaemon. */
-
int no_grab; /* Don't let the pinentry grab the keyboard */
/* The name of the file pinentry shall tocuh before exiting. If
@@ -93,68 +86,36 @@
/* Flag disallowing bypassing of the warning. */
int enforce_passphrase_constraints;
-
/* The require minmum length of a passphrase. */
unsigned int min_passphrase_len;
-
/* The minimum number of non-alpha characters in a passphrase. */
unsigned int min_passphrase_nonalpha;
-
/* File name with a patternfile or NULL if not enabled. */
const char *check_passphrase_pattern;
-
/* If not 0 the user is asked to change his passphrase after these
number of days. */
unsigned int max_passphrase_days;
-
/* If set, a passphrase history will be written and checked at each
passphrase change. */
int enable_passhrase_history;
int running_detached; /* We are running detached from the tty. */
- /* If this global option is true, the passphrase cache is ignored
- for signing operations. */
int ignore_cache_for_signing;
-
- /* If this global option is true, the user is allowed to
- interactively mark certificate in trustlist.txt as trusted. */
int allow_mark_trusted;
-
- /* If this global option is true, the Assuan command
- PRESET_PASSPHRASE is allowed. */
int allow_preset_passphrase;
- /* If this global option is true, the Assuan option
- pinentry-mode=loopback is allowed. */
- int allow_loopback_pinentry;
-
/* Allow the use of an external password cache. If this option is
enabled (which is the default) we send an option to Pinentry
to allow it to enable such a cache. */
int allow_external_cache;
- /* If this global option is true, the Assuan option of Pinentry
- allow-emacs-prompt is allowed. */
- int allow_emacs_pinentry;
-
int keep_tty; /* Don't switch the TTY (for pinentry) on request */
int keep_display; /* Don't switch the DISPLAY (for pinentry) on request */
-
- /* This global options indicates the use of an extra socket. Note
- that we use a hack for cleanup handling in gpg-agent.c: If the
- value is less than 2 the name has not yet been malloced. */
- int extra_socket;
-
- /* This global options indicates the use of an extra socket for web
- browsers. Note that we use a hack for cleanup handling in
- gpg-agent.c: If the value is less than 2 the name has not yet
- been malloced. */
- int browser_socket;
+ int ssh_support; /* Enable ssh-agent emulation. */
} opt;
-/* Bit values for the --debug option. */
#define DBG_COMMAND_VALUE 1 /* debug commands i/o */
#define DBG_MPI_VALUE 2 /* debug mpi details */
#define DBG_CRYPTO_VALUE 4 /* debug low level crypto */
@@ -162,15 +123,14 @@
#define DBG_CACHE_VALUE 64 /* debug the caching */
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
#define DBG_HASHING_VALUE 512 /* debug hashing operations */
-#define DBG_IPC_VALUE 1024 /* Enable Assuan debugging. */
+#define DBG_ASSUAN_VALUE 1024
-/* Test macros for the debug option. */
#define DBG_COMMAND (opt.debug & DBG_COMMAND_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)
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
-#define DBG_IPC (opt.debug & DBG_IPC_VALUE)
+#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
/* Forward reference for local definitions in command.c. */
struct server_local_s;
@@ -186,35 +146,21 @@
struct server_control_s
{
/* Private data used to fire up the connection thread. We use this
- structure do avoid an extra allocation for only a few bytes while
- spawning a new connection thread. */
+ structure do avoid an extra allocation for just a few bytes. */
struct {
gnupg_fd_t fd;
} thread_startup;
- /* Flag indicating the connection is run in restricted mode.
- A value of 1 if used for --extra-socket,
- a value of 2 is used for --browser-socket. */
- int restricted;
-
/* Private data of the server (command.c). */
struct server_local_s *server_local;
/* Private data of the SCdaemon (call-scd.c). */
struct scd_local_s *scd_local;
- /* Environment settings for the connection. */
session_env_t session_env;
char *lc_ctype;
char *lc_messages;
- /* The current pinentry mode. */
- pinentry_mode_t pinentry_mode;
-
- /* The TTL used for the --preset option of certain commands. */
- int cache_ttl_opt_preset;
-
- /* Information on the currently used digest (for signing commands). */
struct {
int algo;
unsigned char value[MAX_DIGEST_LEN];
@@ -224,50 +170,34 @@
unsigned char keygrip[20];
int have_keygrip;
- /* A flag to enable a hack to send the PKAUTH command instead of the
- PKSIGN command to the scdaemon. */
- int use_auth_call;
-
- /* A flag to inhibit enforced passphrase change during an explicit
- passwd command. */
- int in_passwd;
-
- /* The current S2K which might be different from the calibrated
- count. */
- unsigned long s2k_count;
+ int use_auth_call; /* Hack to send the PKAUTH command instead of the
+ PKSIGN command to the scdaemon. */
+ int in_passwd; /* Hack to inhibit enforced passphrase change
+ during an explicit passwd command. */
};
-/* Information pertaining to pinentry requests. */
struct pin_entry_info_s
{
int min_digits; /* min. number of digits required or 0 for freeform entry */
int max_digits; /* max. number of allowed digits allowed*/
- int max_tries; /* max. number of allowed tries. */
- int failed_tries; /* Number of tries so far failed. */
+ int max_tries;
+ int failed_tries;
int with_qualitybar; /* Set if the quality bar should be displayed. */
- int with_repeat; /* Request repetition of the passphrase. */
- int repeat_okay; /* Repetition worked. */
int (*check_cb)(struct pin_entry_info_s *); /* CB used to check the PIN */
void *check_cb_arg; /* optional argument which might be of use in the CB */
- const char *cb_errtext; /* used by the cb to display a specific error */
- size_t max_length; /* Allocated length of the buffer PIN. */
- char pin[1]; /* The buffer to hold the PIN or passphrase.
- It's actual allocated length is given by
- MAX_LENGTH (above). */
+ const char *cb_errtext; /* used by the cb to displaye a specific error */
+ size_t max_length; /* allocated length of the buffer */
+ char pin[1];
};
-/* Types of the private keys. */
enum
{
- PRIVATE_KEY_UNKNOWN = 0, /* Type of key is not known. */
- PRIVATE_KEY_CLEAR = 1, /* The key is not protected. */
- PRIVATE_KEY_PROTECTED = 2, /* The key is protected. */
- PRIVATE_KEY_SHADOWED = 3, /* The key is a stub for a smartcard
- based key. */
- PROTECTED_SHARED_SECRET = 4, /* RFU. */
- PRIVATE_KEY_OPENPGP_NONE = 5 /* openpgp-native with protection "none". */
+ PRIVATE_KEY_UNKNOWN = 0,
+ PRIVATE_KEY_CLEAR = 1,
+ PRIVATE_KEY_PROTECTED = 2,
+ PRIVATE_KEY_SHADOWED = 3
};
@@ -278,67 +208,31 @@
CACHE_MODE_ANY, /* Any mode except ignore matches. */
CACHE_MODE_NORMAL, /* Normal cache (gpg-agent). */
CACHE_MODE_USER, /* GET_PASSPHRASE related cache. */
- CACHE_MODE_SSH, /* SSH related cache. */
- CACHE_MODE_NONCE /* This is a non-predictable nonce. */
+ CACHE_MODE_SSH /* SSH related cache. */
}
cache_mode_t;
-/* The TTL is seconds used for adding a new nonce mode cache item. */
-#define CACHE_TTL_NONCE 120
-
-/* The TTL in seconds used by the --preset option of some commands.
- This is the default value changeable by an OPTION command. */
-#define CACHE_TTL_OPT_PRESET 900
-
/* The type of a function to lookup a TTL by a keygrip. */
typedef int (*lookup_ttl_t)(const char *hexgrip);
-/* This is a special version of the usual _() gettext macro. It
- assumes a server connection control variable with the name "ctrl"
- and uses that to translate a string according to the locale set for
- the connection. The macro LunderscoreIMPL is used by i18n to
- actually define the inline function when needed. */
-#define L_(a) agent_Lunderscore (ctrl, (a))
-#define LunderscorePROTO \
- static inline const char *agent_Lunderscore (ctrl_t ctrl, \
- const char *string) \
- GNUPG_GCC_ATTR_FORMAT_ARG(2);
-#define LunderscoreIMPL \
- static inline const char * \
- agent_Lunderscore (ctrl_t ctrl, const char *string) \
- { \
- return ctrl? i18n_localegettext (ctrl->lc_messages, string) \
- /* */: gettext (string); \
- }
-
-
/*-- gpg-agent.c --*/
-void agent_exit (int rc) GPGRT_GCC_A_NR; /* Also implemented in other tools */
-gpg_error_t agent_copy_startup_env (ctrl_t ctrl);
+void agent_exit (int rc) JNLIB_GCC_A_NR; /* Also implemented in other tools */
const char *get_agent_socket_name (void);
const char *get_agent_ssh_socket_name (void);
#ifdef HAVE_W32_SYSTEM
void *get_agent_scd_notify_event (void);
#endif
void agent_sighup_action (void);
-int map_pk_openpgp_to_gcry (int openpgp_algo);
/*-- command.c --*/
gpg_error_t agent_inq_pinentry_launched (ctrl_t ctrl, unsigned long pid);
gpg_error_t agent_write_status (ctrl_t ctrl, const char *keyword, ...)
GNUPG_GCC_A_SENTINEL(0);
-gpg_error_t agent_print_status (ctrl_t ctrl, const char *keyword,
- const char *format, ...)
- GPGRT_GCC_A_PRINTF(3,4);
void bump_key_eventcounter (void);
void bump_card_eventcounter (void);
void start_command_handler (ctrl_t, gnupg_fd_t, gnupg_fd_t);
-gpg_error_t pinentry_loopback (ctrl_t, const char *keyword,
- unsigned char **buffer, size_t *size,
- size_t max_length);
-
#ifdef HAVE_W32_SYSTEM
int serve_mmapped_ssh_request (ctrl_t ctrl,
unsigned char *request, size_t maxreqlen);
@@ -361,27 +255,21 @@
int agent_write_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force);
gpg_error_t agent_key_from_file (ctrl_t ctrl,
- const char *cache_nonce,
const char *desc_text,
const unsigned char *grip,
unsigned char **shadow_info,
cache_mode_t cache_mode,
lookup_ttl_t lookup_ttl,
- gcry_sexp_t *result,
- char **r_passphrase);
+ gcry_sexp_t *result);
gpg_error_t agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
gcry_sexp_t *result);
gpg_error_t agent_public_key_from_file (ctrl_t ctrl,
const unsigned char *grip,
gcry_sexp_t *result);
-int agent_is_dsa_key (gcry_sexp_t s_key);
-int agent_is_eddsa_key (gcry_sexp_t s_key);
int agent_key_available (const unsigned char *grip);
gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
int *r_keytype,
unsigned char **r_shadow_info);
-gpg_error_t agent_delete_key (ctrl_t ctrl, const char *desc_text,
- const unsigned char *grip);
/*-- call-pinentry.c --*/
void initialize_module_call_pinentry (void);
@@ -406,51 +294,39 @@
int agent_clear_passphrase (ctrl_t ctrl,
const char *keyinfo, cache_mode_t cache_mode);
+
/*-- cache.c --*/
-void initialize_module_cache (void);
-void deinitialize_module_cache (void);
void agent_flush_cache (void);
int agent_put_cache (const char *key, cache_mode_t cache_mode,
const char *data, int ttl);
-char *agent_get_cache (const char *key, cache_mode_t cache_mode);
-void agent_store_cache_hit (const char *key);
+const char *agent_get_cache (const char *key, cache_mode_t cache_mode,
+ void **cache_id);
+void agent_unlock_cache_entry (void **cache_id);
/*-- pksign.c --*/
-int agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
- const char *desc_text,
+int agent_pksign_do (ctrl_t ctrl, const char *desc_text,
gcry_sexp_t *signature_sexp,
- cache_mode_t cache_mode, lookup_ttl_t lookup_ttl,
- const void *overridedata, size_t overridedatalen);
-int agent_pksign (ctrl_t ctrl, const char *cache_nonce,
- const char *desc_text,
+ cache_mode_t cache_mode, lookup_ttl_t lookup_ttl);
+int agent_pksign (ctrl_t ctrl, const char *desc_text,
membuf_t *outbuf, cache_mode_t cache_mode);
/*-- pkdecrypt.c --*/
int agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
const unsigned char *ciphertext, size_t ciphertextlen,
- membuf_t *outbuf, int *r_padding);
+ membuf_t *outbuf);
/*-- genkey.c --*/
-int check_passphrase_constraints (ctrl_t ctrl, const char *pw,
- char **failed_constraint);
-gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
- char **r_passphrase);
-int agent_genkey (ctrl_t ctrl, const char *cache_nonce,
- const char *keyparam, size_t keyparmlen,
- int no_protection, const char *override_passphrase,
- int preset, membuf_t *outbuf);
-gpg_error_t agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
- char **passphrase_addr);
+int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent);
+int agent_genkey (ctrl_t ctrl,
+ const char *keyparam, size_t keyparmlen, membuf_t *outbuf);
+int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey);
/*-- protect.c --*/
unsigned long get_standard_s2k_count (void);
-unsigned char get_standard_s2k_count_rfc4880 (void);
int agent_protect (const unsigned char *plainkey, const char *passphrase,
- unsigned char **result, size_t *resultlen,
- unsigned long s2k_count);
-int agent_unprotect (ctrl_t ctrl,
- const unsigned char *protectedkey, const char *passphrase,
+ unsigned char **result, size_t *resultlen);
+int agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
gnupg_isotime_t protected_at,
unsigned char **result, size_t *resultlen);
int agent_private_key_type (const unsigned char *privatekey);
@@ -461,12 +337,7 @@
int agent_get_shadow_info (const unsigned char *shadowkey,
unsigned char const **shadow_info);
gpg_error_t parse_shadow_info (const unsigned char *shadow_info,
- char **r_hexsn, char **r_idstr, int *r_pinlen);
-gpg_error_t s2k_hash_passphrase (const char *passphrase, int hashalgo,
- int s2kmode,
- const unsigned char *s2ksalt,
- unsigned int s2kcount,
- unsigned char *key, size_t keylen);
+ char **r_hexsn, char **r_idstr);
/*-- trustlist.c --*/
@@ -481,16 +352,13 @@
/*-- divert-scd.c --*/
int divert_pksign (ctrl_t ctrl,
const unsigned char *digest, size_t digestlen, int algo,
- const unsigned char *shadow_info, unsigned char **r_sig,
- size_t *r_siglen);
+ const unsigned char *shadow_info, unsigned char **r_sig);
int divert_pkdecrypt (ctrl_t ctrl,
const unsigned char *cipher,
const unsigned char *shadow_info,
- char **r_buf, size_t *r_len, int *r_padding);
+ char **r_buf, size_t *r_len);
int divert_generic_cmd (ctrl_t ctrl,
const char *cmdline, void *assuan_context);
-int divert_writekey (ctrl_t ctrl, int force, const char *serialno,
- const char *id, const char *keydata, size_t keydatalen);
/*-- call-scd.c --*/
@@ -512,7 +380,6 @@
const char *keyid,
int (*getpin_cb)(void *, const char *, char*, size_t),
void *getpin_cb_arg,
- int mdalgo,
const unsigned char *indata, size_t indatalen,
unsigned char **r_buf, size_t *r_buflen);
int agent_card_pkdecrypt (ctrl_t ctrl,
@@ -520,15 +387,10 @@
int (*getpin_cb)(void *, const char *, char*,size_t),
void *getpin_cb_arg,
const unsigned char *indata, size_t indatalen,
- char **r_buf, size_t *r_buflen, int *r_padding);
+ char **r_buf, size_t *r_buflen);
int agent_card_readcert (ctrl_t ctrl,
const char *id, char **r_buf, size_t *r_buflen);
int agent_card_readkey (ctrl_t ctrl, const char *id, unsigned char **r_buf);
-int agent_card_writekey (ctrl_t ctrl, int force, const char *serialno,
- const char *id, const char *keydata,
- size_t keydatalen,
- int (*getpin_cb)(void *, const char *, char*, size_t),
- void *getpin_cb_arg);
gpg_error_t agent_card_getattr (ctrl_t ctrl, const char *name, char **result);
int agent_card_scd (ctrl_t ctrl, const char *cmdline,
int (*getpin_cb)(void *, const char *, char*, size_t),
@@ -536,15 +398,7 @@
/*-- learncard.c --*/
-int agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force);
-
+int agent_handle_learn (ctrl_t ctrl, void *assuan_context);
-/*-- cvt-openpgp.c --*/
-gpg_error_t
-extract_private_key (gcry_sexp_t s_key, int req_private_key_data,
- const char **r_algoname, int *r_npkey, int *r_nskey,
- const char **r_format,
- gcry_mpi_t *mpi_array, int arraysize,
- gcry_sexp_t *r_curve, gcry_sexp_t *r_flags);
#endif /*AGENT_H*/
diff -Nru gnupg2-2.1.6~build1/agent/cache.c gnupg2-2.0.28/agent/cache.c
--- gnupg2-2.1.6~build1/agent/cache.c 2015-06-17 06:39:24.000000000 +0000
+++ gnupg2-2.0.28/agent/cache.c 2015-06-02 08:13:55.000000000 +0000
@@ -1,5 +1,5 @@
/* cache.c - keep a cache of passphrases
- * Copyright (C) 2002, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -24,31 +24,13 @@
#include
#include
#include
-#include
#include "agent.h"
-/* The size of the encryption key in bytes. */
-#define ENCRYPTION_KEYSIZE (128/8)
-
-/* A mutex used to protect the encryption. This is required because
- we use one context to do all encryption and decryption. */
-static npth_mutex_t encryption_lock;
-/* The encryption context. This is the only place where the
- encryption key for all cached entries is available. It would be nice
- to keep this (or just the key) in some hardware device, for example
- a TPM. Libgcrypt could be extended to provide such a service.
- With the current scheme it is easy to retrieve the cached entries
- if access to Libgcrypt's memory is available. The encryption
- merely avoids grepping for clear texts in the memory. Nevertheless
- the encryption provides the necessary infrastructure to make it
- more secure. */
-static gcry_cipher_hd_t encryption_handle;
-
-
struct secret_data_s {
- int totallen; /* This includes the padding and space for AESWRAP. */
- char data[1]; /* A string. */
+ int totallen; /* this includes the padding */
+ int datalen; /* actual data length */
+ char data[1];
};
typedef struct cache_item_s *ITEM;
@@ -57,89 +39,14 @@
time_t created;
time_t accessed;
int ttl; /* max. lifetime given in seconds, -1 one means infinite */
+ int lockcount;
struct secret_data_s *pw;
cache_mode_t cache_mode;
char key[1];
};
-/* The cache himself. */
-static ITEM thecache;
-
-/* NULL or the last cache key stored by agent_store_cache_hit. */
-static char *last_stored_cache_key;
-
-
-/* This function must be called once to initialize this module. It
- has to be done before a second thread is spawned. */
-void
-initialize_module_cache (void)
-{
- int err;
-
- err = npth_mutex_init (&encryption_lock, NULL);
-
- if (err)
- log_fatal ("error initializing cache module: %s\n", strerror (err));
-}
-
-
-void
-deinitialize_module_cache (void)
-{
- gcry_cipher_close (encryption_handle);
- encryption_handle = NULL;
-}
-
-
-/* We do the encryption init on the fly. We can't do it in the module
- init code because that is run before we listen for connections and
- in case we are started on demand by gpg etc. it will only wait for
- a few seconds to decide whether the agent may now accept
- connections. Thus we should get into listen state as soon as
- possible. */
-static gpg_error_t
-init_encryption (void)
-{
- gpg_error_t err;
- void *key;
- int res;
-
- if (encryption_handle)
- return 0; /* Shortcut - Already initialized. */
-
- res = npth_mutex_lock (&encryption_lock);
- if (res)
- log_fatal ("failed to acquire cache encryption mutex: %s\n", strerror (res));
-
- err = gcry_cipher_open (&encryption_handle, GCRY_CIPHER_AES128,
- GCRY_CIPHER_MODE_AESWRAP, GCRY_CIPHER_SECURE);
- if (!err)
- {
- key = gcry_random_bytes (ENCRYPTION_KEYSIZE, GCRY_STRONG_RANDOM);
- if (!key)
- err = gpg_error_from_syserror ();
- else
- {
- err = gcry_cipher_setkey (encryption_handle, key, ENCRYPTION_KEYSIZE);
- xfree (key);
- }
- if (err)
- {
- gcry_cipher_close (encryption_handle);
- encryption_handle = NULL;
- }
- }
- if (err)
- log_error ("error initializing cache encryption context: %s\n",
- gpg_strerror (err));
-
- res = npth_mutex_unlock (&encryption_lock);
- if (res)
- log_fatal ("failed to release cache encryption mutex: %s\n", strerror (res));
-
- return err? gpg_error (GPG_ERR_NOT_INITIALIZED) : 0;
-}
+static ITEM thecache;
static void
@@ -148,67 +55,31 @@
xfree (data);
}
-static gpg_error_t
-new_data (const char *string, struct secret_data_s **r_data)
+static struct secret_data_s *
+new_data (const void *data, size_t length)
{
- gpg_error_t err;
- struct secret_data_s *d, *d_enc;
- size_t length;
+ struct secret_data_s *d;
int total;
- int res;
-
- *r_data = NULL;
-
- err = init_encryption ();
- if (err)
- return err;
- length = strlen (string) + 1;
-
- /* We pad the data to 32 bytes so that it get more complicated
+ /* we pad the data to 32 bytes so that it get more complicated
finding something out by watching allocation patterns. This is
- usally not possible but we better assume nothing about our secure
- storage provider. To support the AESWRAP mode we need to add 8
- extra bytes as well. */
- total = (length + 8) + 32 - ((length+8) % 32);
-
- d = xtrymalloc_secure (sizeof *d + total - 1);
- if (!d)
- return gpg_error_from_syserror ();
- memcpy (d->data, string, length);
-
- d_enc = xtrymalloc (sizeof *d_enc + total - 1);
- if (!d_enc)
- {
- err = gpg_error_from_syserror ();
- xfree (d);
- return err;
- }
-
- d_enc->totallen = total;
- res = npth_mutex_lock (&encryption_lock);
- if (res)
- log_fatal ("failed to acquire cache encryption mutex: %s\n",
- strerror (res));
-
- err = gcry_cipher_encrypt (encryption_handle, d_enc->data, total,
- d->data, total - 8);
- xfree (d);
- res = npth_mutex_unlock (&encryption_lock);
- if (res)
- log_fatal ("failed to release cache encryption mutex: %s\n", strerror (res));
- if (err)
- {
- xfree (d_enc);
- return err;
+ usally not possible but we better assume nothing about our
+ secure storage provider*/
+ total = length + 32 - (length % 32);
+
+ d = gcry_malloc_secure (sizeof *d + total - 1);
+ if (d)
+ {
+ d->totallen = total;
+ d->datalen = length;
+ memcpy (d->data, data, length);
}
- *r_data = d_enc;
- return 0;
+ return d;
}
-/* Check whether there are items to expire. */
+/* check whether there are items to expire */
static void
housekeeping (void)
{
@@ -218,10 +89,11 @@
/* First expire the actual data */
for (r=thecache; r; r = r->next)
{
- if (r->pw && r->ttl >= 0 && r->accessed + r->ttl < current)
+ if (!r->lockcount && r->pw
+ && r->ttl >= 0 && r->accessed + r->ttl < current)
{
if (DBG_CACHE)
- log_debug (" expired '%s' (%ds after last access)\n",
+ log_debug (" expired `%s' (%ds after last access)\n",
r->key, r->ttl);
release_data (r->pw);
r->pw = NULL;
@@ -234,16 +106,16 @@
for (r=thecache; r; r = r->next)
{
unsigned long maxttl;
-
+
switch (r->cache_mode)
{
case CACHE_MODE_SSH: maxttl = opt.max_cache_ttl_ssh; break;
default: maxttl = opt.max_cache_ttl; break;
}
- if (r->pw && r->created + maxttl < current)
+ if (!r->lockcount && r->pw && r->created + maxttl < current)
{
if (DBG_CACHE)
- log_debug (" expired '%s' (%lus after creation)\n",
+ log_debug (" expired `%s' (%lus after creation)\n",
r->key, opt.max_cache_ttl);
release_data (r->pw);
r->pw = NULL;
@@ -257,16 +129,27 @@
{
if (!r->pw && r->ttl >= 0 && r->accessed + 60*30 < current)
{
- ITEM r2 = r->next;
- if (DBG_CACHE)
- log_debug (" removed '%s' (mode %d) (slot not used for 30m)\n",
- r->key, r->cache_mode);
- xfree (r);
- if (!rprev)
- thecache = r2;
+ if (r->lockcount)
+ {
+ log_error ("can't remove unused cache entry `%s' due to"
+ " lockcount=%d\n",
+ r->key, r->lockcount);
+ r->accessed += 60*10; /* next error message in 10 minutes */
+ rprev = r;
+ r = r->next;
+ }
else
- rprev->next = r2;
- r = r2;
+ {
+ ITEM r2 = r->next;
+ if (DBG_CACHE)
+ log_debug (" removed `%s' (slot not used for 30m)\n", r->key);
+ xfree (r);
+ if (!rprev)
+ thecache = r2;
+ else
+ rprev->next = r2;
+ r = r2;
+ }
}
else
{
@@ -287,35 +170,41 @@
for (r=thecache; r; r = r->next)
{
- if (r->pw)
+ if (!r->lockcount && r->pw)
{
if (DBG_CACHE)
- log_debug (" flushing '%s'\n", r->key);
+ log_debug (" flushing `%s'\n", r->key);
release_data (r->pw);
r->pw = NULL;
r->accessed = 0;
}
+ else if (r->lockcount && r->pw)
+ {
+ if (DBG_CACHE)
+ log_debug (" marked `%s' for flushing\n", r->key);
+ r->accessed = 0;
+ r->ttl = 0;
+ }
}
}
-/* Store the string DATA in the cache under KEY and mark it with a
- maximum lifetime of TTL seconds. If there is already data under
- this key, it will be replaced. Using a DATA of NULL deletes the
- entry. A TTL of 0 is replaced by the default TTL and a TTL of -1
- set infinite timeout. CACHE_MODE is stored with the cache entry
+/* Store DATA of length DATALEN in the cache under KEY and mark it
+ with a maximum lifetime of TTL seconds. If there is already data
+ under this key, it will be replaced. Using a DATA of NULL deletes
+ the entry. A TTL of 0 is replaced by the default TTL and a TTL of
+ -1 set infinite timeout. CACHE_MODE is stored with the cache entry
and used to select different timeouts. */
int
agent_put_cache (const char *key, cache_mode_t cache_mode,
const char *data, int ttl)
{
- gpg_error_t err = 0;
ITEM r;
if (DBG_CACHE)
- log_debug ("agent_put_cache '%s' (mode %d) requested ttl=%d\n",
- key, cache_mode, ttl);
+ log_debug ("agent_put_cache `%s' requested ttl=%d mode=%d\n",
+ key, ttl, cache_mode);
housekeeping ();
if (!ttl)
@@ -326,19 +215,16 @@
default: ttl = opt.def_cache_ttl; break;
}
}
- if ((!ttl && data) || cache_mode == CACHE_MODE_IGNORE)
+ if (!ttl || cache_mode == CACHE_MODE_IGNORE)
return 0;
for (r=thecache; r; r = r->next)
{
- if (((cache_mode != CACHE_MODE_USER
- && cache_mode != CACHE_MODE_NONCE)
- || r->cache_mode == cache_mode)
- && !strcmp (r->key, key))
+ if (!r->lockcount && !strcmp (r->key, key))
break;
}
- if (r) /* Replace. */
- {
+ if (r)
+ { /* replace */
if (r->pw)
{
release_data (r->pw);
@@ -346,126 +232,109 @@
}
if (data)
{
- r->created = r->accessed = gnupg_get_time ();
+ r->created = r->accessed = gnupg_get_time ();
r->ttl = ttl;
r->cache_mode = cache_mode;
- err = new_data (data, &r->pw);
- if (err)
- log_error ("error replacing cache item: %s\n", gpg_strerror (err));
+ r->pw = new_data (data, strlen (data)+1);
+ if (!r->pw)
+ log_error ("out of core while allocating new cache item\n");
}
}
- else if (data) /* Insert. */
- {
+ else if (data)
+ { /* simply insert */
r = xtrycalloc (1, sizeof *r + strlen (key));
if (!r)
- err = gpg_error_from_syserror ();
+ log_error ("out of core while allocating new cache control\n");
else
{
strcpy (r->key, key);
- r->created = r->accessed = gnupg_get_time ();
+ r->created = r->accessed = gnupg_get_time ();
r->ttl = ttl;
r->cache_mode = cache_mode;
- err = new_data (data, &r->pw);
- if (err)
- xfree (r);
+ r->pw = new_data (data, strlen (data)+1);
+ if (!r->pw)
+ {
+ log_error ("out of core while allocating new cache item\n");
+ xfree (r);
+ }
else
{
r->next = thecache;
thecache = r;
}
}
- if (err)
- log_error ("error inserting cache item: %s\n", gpg_strerror (err));
}
- return err;
+ return 0;
}
/* Try to find an item in the cache. Note that we currently don't
- make use of CACHE_MODE except for CACHE_MODE_NONCE and
- CACHE_MODE_USER. */
-char *
-agent_get_cache (const char *key, cache_mode_t cache_mode)
+ make use of CACHE_MODE. */
+const char *
+agent_get_cache (const char *key, cache_mode_t cache_mode, void **cache_id)
{
- gpg_error_t err;
ITEM r;
- char *value = NULL;
- int res;
- int last_stored = 0;
if (cache_mode == CACHE_MODE_IGNORE)
return NULL;
- if (!key)
- {
- key = last_stored_cache_key;
- if (!key)
- return NULL;
- last_stored = 1;
- }
-
-
if (DBG_CACHE)
- log_debug ("agent_get_cache '%s' (mode %d)%s ...\n",
- key, cache_mode,
- last_stored? " (stored cache key)":"");
+ log_debug ("agent_get_cache `%s'...\n", key);
housekeeping ();
+ /* first try to find one with no locks - this is an updated cache
+ entry: We might have entries with a lockcount and without a
+ lockcount. */
for (r=thecache; r; r = r->next)
{
- if (r->pw
- && ((cache_mode != CACHE_MODE_USER
- && cache_mode != CACHE_MODE_NONCE)
- || r->cache_mode == cache_mode)
- && !strcmp (r->key, key))
+ if (!r->lockcount && r->pw && !strcmp (r->key, key))
{
- /* Note: To avoid races KEY may not be accessed anymore below. */
+ /* put_cache does only put strings into the cache, so we
+ don't need the lengths */
r->accessed = gnupg_get_time ();
if (DBG_CACHE)
log_debug ("... hit\n");
- if (r->pw->totallen < 32)
- err = gpg_error (GPG_ERR_INV_LENGTH);
- else if ((err = init_encryption ()))
- ;
- else if (!(value = xtrymalloc_secure (r->pw->totallen - 8)))
- err = gpg_error_from_syserror ();
- else
- {
- res = npth_mutex_lock (&encryption_lock);
- if (res)
- log_fatal ("failed to acquire cache encryption mutex: %s\n",
- strerror (res));
- err = gcry_cipher_decrypt (encryption_handle,
- value, r->pw->totallen - 8,
- r->pw->data, r->pw->totallen);
- res = npth_mutex_unlock (&encryption_lock);
- if (res)
- log_fatal ("failed to release cache encryption mutex: %s\n",
- strerror (res));
- }
- if (err)
- {
- xfree (value);
- value = NULL;
- log_error ("retrieving cache entry '%s' failed: %s\n",
- key, gpg_strerror (err));
- }
- return value;
+ r->lockcount++;
+ *cache_id = r;
+ return r->pw->data;
+ }
+ }
+ /* again, but this time get even one with a lockcount set */
+ for (r=thecache; r; r = r->next)
+ {
+ if (r->pw && !strcmp (r->key, key))
+ {
+ r->accessed = gnupg_get_time ();
+ if (DBG_CACHE)
+ log_debug ("... hit (locked)\n");
+ r->lockcount++;
+ *cache_id = r;
+ return r->pw->data;
}
}
if (DBG_CACHE)
log_debug ("... miss\n");
+ *cache_id = NULL;
return NULL;
}
-/* Store the key for the last successful cache hit. That value is
- used by agent_get_cache if the requested KEY is given as NULL.
- NULL may be used to remove that key. */
void
-agent_store_cache_hit (const char *key)
+agent_unlock_cache_entry (void **cache_id)
{
- xfree (last_stored_cache_key);
- last_stored_cache_key = key? xtrystrdup (key) : NULL;
+ ITEM r;
+
+ for (r=thecache; r; r = r->next)
+ {
+ if (r == *cache_id)
+ {
+ if (!r->lockcount)
+ log_error ("trying to unlock non-locked cache entry `%s'\n",
+ r->key);
+ else
+ r->lockcount--;
+ return;
+ }
+ }
}
diff -Nru gnupg2-2.1.6~build1/agent/call-pinentry.c gnupg2-2.0.28/agent/call-pinentry.c
--- gnupg2-2.1.6~build1/agent/call-pinentry.c 2015-06-30 19:14:34.000000000 +0000
+++ gnupg2-2.0.28/agent/call-pinentry.c 2015-06-02 08:33:03.000000000 +0000
@@ -32,11 +32,11 @@
# include
# include
#endif
-#include
+#include
#include "agent.h"
#include
-#include "sysutils.h"
+#include "setenv.h"
#include "i18n.h"
#ifdef _POSIX_OPEN_MAX
@@ -47,8 +47,8 @@
/* Because access to the pinentry must be serialized (it is and shall
- be a global mutually exclusive dialog) we better timeout pending
- requests after some time. 1 minute seem to be a reasonable
+ be a global mutual dialog) we should better timeout further
+ requests after some time. 2 minutes seem to be a reasonable
time. */
#define LOCK_TIMEOUT (1*60)
@@ -62,10 +62,10 @@
static ctrl_t entry_owner;
/* A mutex used to serialize access to the pinentry. */
-static npth_mutex_t entry_lock;
+static pth_mutex_t entry_lock;
/* The thread ID of the popup working thread. */
-static npth_t popup_tid;
+static pth_t popup_tid;
/* A flag used in communication between the popup working thread and
its stop function. */
@@ -95,20 +95,40 @@
if (!initialized)
{
- if (npth_mutex_init (&entry_lock, NULL))
+ if (pth_mutex_init (&entry_lock))
initialized = 1;
}
}
+static void
+dump_mutex_state (pth_mutex_t *m)
+{
+#ifdef _W32_PTH_H
+ (void)m;
+ log_printf ("unknown under W32");
+#else
+ if (!(m->mx_state & PTH_MUTEX_INITIALIZED))
+ log_printf ("not_initialized");
+ else if (!(m->mx_state & PTH_MUTEX_LOCKED))
+ log_printf ("not_locked");
+ else
+ log_printf ("locked tid=0x%lx count=%lu", (long)m->mx_owner, m->mx_count);
+#endif
+}
+
+
/* This function may be called to print infromation pertaining to the
current state of this module to the log. */
void
agent_query_dump_state (void)
{
+ log_info ("agent_query_dump_state: entry_lock=");
+ dump_mutex_state (&entry_lock);
+ log_printf ("\n");
log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%p\n",
- entry_ctx, (long)assuan_get_pid (entry_ctx), (void*)popup_tid);
+ entry_ctx, (long)assuan_get_pid (entry_ctx), popup_tid);
}
/* Called to make sure that a popup window owned by the current
@@ -131,43 +151,13 @@
unlock_pinentry (int rc)
{
assuan_context_t ctx = entry_ctx;
- int err;
-
- if (rc)
- {
- if (DBG_IPC)
- log_debug ("error calling pinentry: %s <%s>\n",
- gpg_strerror (rc), gpg_strsource (rc));
-
- /* Change the source of the error to pinentry so that the final
- consumer of the error code knows that the problem is with
- pinentry. For backward compatibility we do not do that for
- some common error codes. */
- switch (gpg_err_code (rc))
- {
- case GPG_ERR_NO_PIN_ENTRY:
- case GPG_ERR_CANCELED:
- case GPG_ERR_FULLY_CANCELED:
- case GPG_ERR_ASS_UNKNOWN_INQUIRE:
- case GPG_ERR_ASS_TOO_MUCH_DATA:
- case GPG_ERR_NO_PASSPHRASE:
- case GPG_ERR_BAD_PASSPHRASE:
- case GPG_ERR_BAD_PIN:
- break;
-
- default:
- rc = gpg_err_make (GPG_ERR_SOURCE_PINENTRY, gpg_err_code (rc));
- break;
- }
- }
entry_ctx = NULL;
- err = npth_mutex_unlock (&entry_lock);
- if (err)
+ if (!pth_mutex_release (&entry_lock))
{
- log_error ("failed to release the entry lock: %s\n", strerror (err));
+ log_error ("failed to release the entry lock\n");
if (!rc)
- rc = gpg_error_from_errno (err);
+ rc = gpg_error (GPG_ERR_INTERNAL);
}
assuan_release (ctx);
return rc;
@@ -180,6 +170,16 @@
atfork_cb (void *opaque, int where)
{
ctrl_t ctrl = opaque;
+#ifndef HAVE_W32_SYSTEM
+ struct sigaction sa;
+
+ /* Pop up message should be able to be killed by SIGINT. */
+ sigemptyset (&sa.sa_mask);
+ sa.sa_handler = SIG_DFL;
+ sa.sa_flags = 0;
+ sigaction (SIGINT, &sa, NULL);
+ sigprocmask (SIG_SETMASK, &sa.sa_mask, NULL); /* Unblock all signals. */
+#endif
if (!where)
{
@@ -200,7 +200,7 @@
{
value = session_env_getenv (ctrl->session_env, name);
if (value)
- gnupg_setenv (name, value, 1);
+ setenv (name, value, 1);
}
}
}
@@ -232,32 +232,30 @@
static int
start_pinentry (ctrl_t ctrl)
{
- int rc = 0;
- const char *full_pgmname;
+ int rc;
const char *pgmname;
assuan_context_t ctx;
const char *argv[5];
- assuan_fd_t no_close_list[3];
+ int no_close_list[3];
int i;
+ pth_event_t evt;
const char *tmpstr;
unsigned long pinentry_pid;
const char *value;
- struct timespec abstime;
- int err;
- npth_clock_gettime (&abstime);
- abstime.tv_sec += LOCK_TIMEOUT;
- err = npth_mutex_timedlock (&entry_lock, &abstime);
- if (err)
+ evt = pth_event (PTH_EVENT_TIME, pth_timeout (LOCK_TIMEOUT, 0));
+ if (!pth_mutex_acquire (&entry_lock, 0, evt))
{
- if (err == ETIMEDOUT)
- rc = gpg_error (GPG_ERR_TIMEOUT);
+ if (pth_event_occurred (evt))
+ rc = gpg_error (GPG_ERR_TIMEOUT);
else
- rc = gpg_error_from_errno (rc);
+ rc = gpg_error (GPG_ERR_INTERNAL);
+ pth_event_free (evt, PTH_FREE_THIS);
log_error (_("failed to acquire the pinentry lock: %s\n"),
gpg_strerror (rc));
return rc;
}
+ pth_event_free (evt, PTH_FREE_THIS);
entry_owner = ctrl;
@@ -279,18 +277,18 @@
log_error ("error flushing pending output: %s\n", strerror (errno));
/* At least Windows XP fails here with EBADF. According to docs
and Wine an fflush(NULL) is the same as _flushall. However
- the Wine implementaion does not flush stdin,stdout and stderr
- - see above. Let's try to ignore the error. */
+ the Wime implementaion does not flush stdin,stdout and stderr
+ - see above. Lets try to ignore the error. */
#ifndef HAVE_W32_SYSTEM
return unlock_pinentry (tmperr);
#endif
}
- full_pgmname = opt.pinentry_program;
- if (!full_pgmname || !*full_pgmname)
- full_pgmname = gnupg_module_name (GNUPG_MODULE_NAME_PINENTRY);
- if ( !(pgmname = strrchr (full_pgmname, '/')))
- pgmname = full_pgmname;
+ if (!opt.pinentry_program || !*opt.pinentry_program)
+ opt.pinentry_program = gnupg_module_name (GNUPG_MODULE_NAME_PINENTRY);
+ pgmname = opt.pinentry_program;
+ if ( !(pgmname = strrchr (opt.pinentry_program, '/')))
+ pgmname = opt.pinentry_program;
else
pgmname++;
@@ -298,7 +296,7 @@
the resource bundle. For other systems we stick to the usual
convention of supplying only the name of the program. */
#ifdef __APPLE__
- argv[0] = full_pgmname;
+ argv[0] = opt.pinentry_program;
#else /*!__APPLE__*/
argv[0] = pgmname;
#endif /*__APPLE__*/
@@ -320,7 +318,7 @@
no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
no_close_list[i++] = assuan_fd_from_posix_fd (fileno (stderr));
}
- no_close_list[i] = ASSUAN_INVALID_FD;
+ no_close_list[i] = -1;
rc = assuan_new (&ctx);
if (rc)
@@ -328,30 +326,24 @@
log_error ("can't allocate assuan context: %s\n", gpg_strerror (rc));
return rc;
}
- /* We don't want to log the pinentry communication to make the logs
- easier to read. We might want to add a new debug option to enable
- pinentry logging. */
-#ifdef ASSUAN_NO_LOGGING
- assuan_set_flag (ctx, ASSUAN_NO_LOGGING, !opt.debug_pinentry);
-#endif
/* Connect to the pinentry and perform initial handshaking. Note
that atfork is used to change the environment for pinentry. We
start the server in detached mode to suppress the console window
under Windows. */
- rc = assuan_pipe_connect (ctx, full_pgmname, argv,
+ rc = assuan_pipe_connect (ctx, opt.pinentry_program, argv,
no_close_list, atfork_cb, ctrl,
ASSUAN_PIPE_CONNECT_DETACHED);
if (rc)
{
- log_error ("can't connect to the PIN entry module '%s': %s\n",
- full_pgmname, gpg_strerror (rc));
+ log_error ("can't connect to the PIN entry module: %s\n",
+ gpg_strerror (rc));
assuan_release (ctx);
return unlock_pinentry (gpg_error (GPG_ERR_NO_PIN_ENTRY));
}
entry_ctx = ctx;
- if (DBG_IPC)
+ if (DBG_ASSUAN)
log_debug ("connection to PIN entry established\n");
rc = assuan_transact (entry_ctx,
@@ -360,6 +352,7 @@
if (rc)
return unlock_pinentry (rc);
+
value = session_env_getenv (ctrl->session_env, "GPG_TTY");
if (value)
{
@@ -407,7 +400,6 @@
return unlock_pinentry (rc);
}
-
if (opt.allow_external_cache)
{
/* Indicate to the pinentry that it may read from an external cache.
@@ -423,33 +415,22 @@
return unlock_pinentry (rc);
}
- if (opt.allow_emacs_pinentry)
- {
- /* Indicate to the pinentry that it may read passphrase through
- Emacs minibuffer, if possible. */
- rc = assuan_transact (entry_ctx, "OPTION allow-emacs-prompt",
- NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc && gpg_err_code (rc) != GPG_ERR_UNKNOWN_OPTION)
- return unlock_pinentry (rc);
- }
-
{
/* Provide a few default strings for use by the pinentries. This
may help a pinentry to avoid implementing localization code. */
- static struct { const char *key, *value; int what; } tbl[] = {
+ static struct { const char *key, *value; int mode; } tbl[] = {
/* TRANSLATORS: These are labels for buttons etc used in
Pinentries. An underscore indicates that the next letter
should be used as an accelerator. Double the underscore for
a literal one. The actual to be translated text starts after
- the second vertical bar. Note that gpg-agent has been set to
- utf-8 so that the strings are in the expected encoding. */
+ the second vertical bar. */
{ "ok", N_("|pinentry-label|_OK") },
{ "cancel", N_("|pinentry-label|_Cancel") },
{ "yes", N_("|pinentry-label|_Yes") },
{ "no", N_("|pinentry-label|_No") },
{ "prompt", N_("|pinentry-label|PIN:") },
- { "pwmngr", N_("|pinentry-label|_Save in password manager"), 1 },
+ { "pwmngr", N_("|pinentry-label|_Save in password manager") },
{ "cf-visi",N_("Do you really want to make your "
"passphrase visible on the screen?") },
{ "tt-visi",N_("|pinentry-tt|Make passphrase visible") },
@@ -462,9 +443,7 @@
for (idx=0; tbl[idx].key; idx++)
{
- if (!opt.allow_external_cache && tbl[idx].what == 1)
- continue; /* No need for it. */
- s = L_(tbl[idx].value);
+ s = _(tbl[idx].value);
if (*s == '|' && (s2=strchr (s+1,'|')))
s = s2+1;
if (asprintf (&optstr, "OPTION default-%s=%s", tbl[idx].key, s) < 0 )
@@ -516,10 +495,8 @@
else
{
rc = agent_inq_pinentry_launched (ctrl, pinentry_pid);
- if (gpg_err_code (rc) == GPG_ERR_CANCELED
- || gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
- return unlock_pinentry (gpg_err_make (GPG_ERR_SOURCE_DEFAULT,
- gpg_err_code (rc)));
+ if (gpg_err_code (rc) == GPG_ERR_CANCELED)
+ return unlock_pinentry (gpg_error (GPG_ERR_CANCELED));
rc = 0;
}
@@ -527,43 +504,39 @@
}
-/* Returns True if the pinentry is currently active. If WAITSECONDS is
+/* Returns True is the pinentry is currently active. If WAITSECONDS is
greater than zero the function will wait for this many seconds
before returning. */
int
pinentry_active_p (ctrl_t ctrl, int waitseconds)
{
- int err;
(void)ctrl;
if (waitseconds > 0)
{
- struct timespec abstime;
+ pth_event_t evt;
int rc;
- npth_clock_gettime (&abstime);
- abstime.tv_sec += waitseconds;
- err = npth_mutex_timedlock (&entry_lock, &abstime);
- if (err)
+ evt = pth_event (PTH_EVENT_TIME, pth_timeout (waitseconds, 0));
+ if (!pth_mutex_acquire (&entry_lock, 0, evt))
{
- if (err == ETIMEDOUT)
+ if (pth_event_occurred (evt))
rc = gpg_error (GPG_ERR_TIMEOUT);
else
rc = gpg_error (GPG_ERR_INTERNAL);
+ pth_event_free (evt, PTH_FREE_THIS);
return rc;
}
+ pth_event_free (evt, PTH_FREE_THIS);
}
else
{
- err = npth_mutex_trylock (&entry_lock);
- if (err)
+ if (!pth_mutex_acquire (&entry_lock, 1, NULL))
return gpg_error (GPG_ERR_LOCKED);
}
- err = npth_mutex_unlock (&entry_lock);
- if (err)
- log_error ("failed to release the entry lock at %d: %s\n", __LINE__,
- strerror (errno));
+ if (!pth_mutex_release (&entry_lock))
+ log_error ("failed to release the entry lock at %d\n", __LINE__);
return 0;
}
@@ -601,7 +574,7 @@
/* Return a new malloced string by unescaping the string S. Escaping
is percent escaping and '+'/space mapping. A binary Nul will
silently be replaced by a 0xFF. Function returns NULL to indicate
- an out of memory status. Parsing stops at the end of the string or
+ an out of memory status. PArsing stops at the end of the string or
a white space character. */
static char *
unescape_passphrase_string (const unsigned char *s)
@@ -662,21 +635,24 @@
inq_quality (void *opaque, const char *line)
{
assuan_context_t ctx = opaque;
- const char *s;
char *pin;
int rc;
int percent;
char numbuf[20];
- if ((s = has_leading_keyword (line, "QUALITY")))
+ if (!strncmp (line, "QUALITY", 7) && (line[7] == ' ' || !line[7]))
{
- pin = unescape_passphrase_string (s);
+ line += 7;
+ while (*line == ' ')
+ line++;
+
+ pin = unescape_passphrase_string (line);
if (!pin)
rc = gpg_error_from_syserror ();
else
{
percent = estimate_passphrase_quality (pin);
- if (check_passphrase_constraints (NULL, pin, NULL))
+ if (check_passphrase_constraints (NULL, pin, 1))
percent = -percent;
snprintf (numbuf, sizeof numbuf, "%d", percent);
rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
@@ -685,7 +661,7 @@
}
else
{
- log_error ("unsupported inquiry '%s' from pinentry\n", line);
+ log_error ("unsupported inquiry `%s' from pinentry\n", line);
rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
}
@@ -695,7 +671,7 @@
/* Helper for agent_askpin and agent_get_passphrase. */
static int
-setup_qualitybar (ctrl_t ctrl)
+setup_qualitybar (void)
{
int rc;
char line[ASSUAN_LINELENGTH];
@@ -704,7 +680,7 @@
/* TRANSLATORS: This string is displayed by Pinentry as the label
for the quality bar. */
- tmpstr = try_percent_escape (L_("Quality:"), "\t\r\n\f\v");
+ tmpstr = try_percent_escape (_("Quality:"), "\t\r\n\f\v");
snprintf (line, DIM(line)-1, "SETQUALITYBAR %s", tmpstr? tmpstr:"");
line[DIM(line)-1] = 0;
xfree (tmpstr);
@@ -726,7 +702,7 @@
tooltip is limited to about 900 characters. If you do not
translate this entry, a default english text (see source)
will be used. */
- tooltip = L_("pinentry.qualitybar.tooltip");
+ tooltip = _("pinentry.qualitybar.tooltip");
if (!strcmp ("pinentry.qualitybar.tooltip", tooltip))
tooltip = ("The quality of the text entered above.\n"
"Please ask your administrator for "
@@ -747,10 +723,9 @@
return 0;
}
+
enum
{
- PINENTRY_STATUS_CLOSE_BUTTON = 1 << 0,
- PINENTRY_STATUS_PIN_REPEATED = 1 << 8,
PINENTRY_STATUS_PASSWORD_FROM_CACHE = 1 << 9
};
@@ -760,31 +735,18 @@
pinentry_status_cb (void *opaque, const char *line)
{
unsigned int *flag = opaque;
- const char *args;
- if ((args = has_leading_keyword (line, "BUTTON_INFO")))
- {
- if (!strcmp (args, "close"))
- *flag |= PINENTRY_STATUS_CLOSE_BUTTON;
- }
- else if (has_leading_keyword (line, "PIN_REPEATED"))
- {
- *flag |= PINENTRY_STATUS_PIN_REPEATED;
- }
- else if (has_leading_keyword (line, "PASSWORD_FROM_CACHE"))
+ if (strcmp (line, "PASSWORD_FROM_CACHE") == 0)
{
*flag |= PINENTRY_STATUS_PASSWORD_FROM_CACHE;
}
return 0;
}
-
-
-
/* Call the Entry and ask for the PIN. We do check for a valid PIN
number here and repeat it as long as we have invalid formed
- numbers. KEYINFO and CACHE_MODE are used to tell pinentry something
+ numbers. KEYINFO and CACHEMODE are used to tell pinentry something
about the key. */
int
agent_askpin (ctrl_t ctrl,
@@ -804,43 +766,14 @@
if (opt.batch)
return 0; /* fixme: we should return BAD PIN */
- if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
- {
- if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL)
- return gpg_error (GPG_ERR_CANCELED);
- if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
- {
- unsigned char *passphrase;
- size_t size;
-
- *pininfo->pin = 0; /* Reset the PIN. */
- rc = pinentry_loopback(ctrl, "PASSPHRASE", &passphrase, &size,
- pininfo->max_length);
- if (rc)
- return rc;
-
- memcpy(&pininfo->pin, passphrase, size);
- xfree(passphrase);
- pininfo->pin[size] = 0;
- if (pininfo->check_cb)
- {
- /* More checks by utilizing the optional callback. */
- pininfo->cb_errtext = NULL;
- rc = pininfo->check_cb (pininfo);
- }
- return rc;
- }
- return gpg_error(GPG_ERR_NO_PIN_ENTRY);
- }
-
if (!pininfo || pininfo->max_length < 1)
return gpg_error (GPG_ERR_INV_VALUE);
if (!desc_text && pininfo->min_digits)
- desc_text = L_("Please enter your PIN, so that the secret key "
- "can be unlocked for this session");
+ desc_text = _("Please enter your PIN, so that the secret key "
+ "can be unlocked for this session");
else if (!desc_text)
- desc_text = L_("Please enter your passphrase, so that the secret key "
- "can be unlocked for this session");
+ desc_text = _("Please enter your passphrase, so that the secret key "
+ "can be unlocked for this session");
if (prompt_text)
is_pin = !!strstr (prompt_text, "PIN");
@@ -877,7 +810,7 @@
return unlock_pinentry (rc);
snprintf (line, DIM(line)-1, "SETPROMPT %s",
- prompt_text? prompt_text : is_pin? L_("PIN:") : L_("Passphrase:"));
+ prompt_text? prompt_text : is_pin? "PIN:" : "Passphrase:");
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
@@ -888,7 +821,7 @@
to the pinentry. */
if (pininfo->with_qualitybar && opt.min_passphrase_len )
{
- rc = setup_qualitybar (ctrl);
+ rc = setup_qualitybar ();
if (rc)
return unlock_pinentry (rc);
}
@@ -903,18 +836,6 @@
return unlock_pinentry (rc);
}
- if (pininfo->with_repeat)
- {
- snprintf (line, DIM(line)-1, "SETREPEATERROR %s",
- L_("does not match - try again"));
- line[DIM(line)-1] = 0;
- rc = assuan_transact (entry_ctx, line,
- NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- pininfo->with_repeat = 0; /* Pinentry does not support it. */
- }
- pininfo->repeat_okay = 0;
-
for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
{
memset (&parm, 0, sizeof parm);
@@ -927,7 +848,7 @@
/* TRANSLATORS: The string is appended to an error message in
the pinentry. The %s is the actual error message, the
two %d give the current and maximum number of tries. */
- snprintf (line, DIM(line)-1, L_("SETERROR %s (try %d of %d)"),
+ snprintf (line, DIM(line)-1, _("SETERROR %s (try %d of %d)"),
errtext, pininfo->failed_tries+1, pininfo->max_tries);
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line,
@@ -937,22 +858,12 @@
errtext = NULL;
}
- if (pininfo->with_repeat)
- {
- snprintf (line, DIM(line)-1, "SETREPEAT %s", L_("Repeat:"));
- line[DIM(line)-1] = 0;
- rc = assuan_transact (entry_ctx, line,
- NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- return unlock_pinentry (rc);
- }
-
saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
assuan_begin_confidential (entry_ctx);
pinentry_status = 0;
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
inq_quality, entry_ctx,
- pinentry_status_cb, &pinentry_status);
+ pinentry_status_cb, &pinentry_status);
assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
/* Most pinentries out in the wild return the old Assuan error code
for canceled which gets translated to an assuan Cancel error and
@@ -961,16 +872,9 @@
&& gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
-
- /* Change error code in case the window close button was clicked
- to cancel the operation. */
- if ((pinentry_status & PINENTRY_STATUS_CLOSE_BUTTON)
- && gpg_err_code (rc) == GPG_ERR_CANCELED)
- rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
-
if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
- errtext = is_pin? L_("PIN too long")
- : L_("Passphrase too long");
+ errtext = is_pin? _("PIN too long")
+ : _("Passphrase too long");
else if (rc)
return unlock_pinentry (rc);
@@ -978,12 +882,12 @@
{
/* do some basic checks on the entered PIN. */
if (!all_digitsp (pininfo->pin))
- errtext = L_("Invalid characters in PIN");
+ errtext = _("Invalid characters in PIN");
else if (pininfo->max_digits
&& strlen (pininfo->pin) > pininfo->max_digits)
- errtext = L_("PIN too long");
+ errtext = _("PIN too long");
else if (strlen (pininfo->pin) < pininfo->min_digits)
- errtext = L_("PIN too short");
+ errtext = _("PIN too short");
}
if (!errtext && pininfo->check_cb)
@@ -995,18 +899,14 @@
errtext = pininfo->cb_errtext;
else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN)
- errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase"));
+ errtext = (is_pin? _("Bad PIN")
+ : _("Bad Passphrase"));
else if (rc)
return unlock_pinentry (rc);
}
if (!errtext)
- {
- if (pininfo->with_repeat
- && (pinentry_status & PINENTRY_STATUS_PIN_REPEATED))
- pininfo->repeat_okay = 1;
- return unlock_pinentry (0); /* okay, got a PIN or passphrase */
- }
+ return unlock_pinentry (0); /* okay, got a PIN or passphrase */
if ((pinentry_status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
/* The password was read from the cache. Don't count this
@@ -1021,7 +921,7 @@
/* Ask for the passphrase using the supplied arguments. The returned
- passphrase needs to be freed by the caller. */
+ passphrase needs to be freed by the caller. */
int
agent_get_passphrase (ctrl_t ctrl,
char **retpass, const char *desc, const char *prompt,
@@ -1033,42 +933,17 @@
char line[ASSUAN_LINELENGTH];
struct entry_parm_s parm;
int saveflag;
- unsigned int pinentry_status;
*retpass = NULL;
if (opt.batch)
return gpg_error (GPG_ERR_BAD_PASSPHRASE);
- if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
- {
- if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL)
- return gpg_error (GPG_ERR_CANCELED);
-
- if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
- {
- size_t size;
- size_t len = ASSUAN_LINELENGTH/2;
- unsigned char *buffer = gcry_malloc_secure (len);
-
- rc = pinentry_loopback(ctrl, "PASSPHRASE", &buffer, &size, len);
- if (rc)
- xfree(buffer);
- else
- {
- buffer[size] = 0;
- *retpass = buffer;
- }
- return rc;
- }
- return gpg_error (GPG_ERR_NO_PIN_ENTRY);
- }
-
rc = start_pinentry (ctrl);
if (rc)
return rc;
if (!prompt)
- prompt = desc && strstr (desc, "PIN")? L_("PIN:"): L_("Passphrase:");
+ prompt = desc && strstr (desc, "PIN")? "PIN": _("Passphrase");
/* If we have a KEYINFO string and are normal, user, or ssh cache
@@ -1108,7 +983,7 @@
if (with_qualitybar && opt.min_passphrase_len)
{
- rc = setup_qualitybar (ctrl);
+ rc = setup_qualitybar ();
if (rc)
return unlock_pinentry (rc);
}
@@ -1130,22 +1005,14 @@
saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
assuan_begin_confidential (entry_ctx);
- pinentry_status = 0;
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
- inq_quality, entry_ctx,
- pinentry_status_cb, &pinentry_status);
+ inq_quality, entry_ctx, NULL, NULL);
assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
/* Most pinentries out in the wild return the old Assuan error code
for canceled which gets translated to an assuan Cancel error and
not to the code for a user cancel. Fix this here. */
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);
- /* Change error code in case the window close button was clicked
- to cancel the operation. */
- if ((pinentry_status & PINENTRY_STATUS_CLOSE_BUTTON)
- && gpg_err_code (rc) == GPG_ERR_CANCELED)
- rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
-
if (rc)
xfree (parm.buffer);
else
@@ -1170,14 +1037,6 @@
int rc;
char line[ASSUAN_LINELENGTH];
- if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
- {
- if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL)
- return gpg_error (GPG_ERR_CANCELED);
-
- return gpg_error (GPG_ERR_NO_PIN_ENTRY);
- }
-
rc = start_pinentry (ctrl);
if (rc)
return rc;
@@ -1243,7 +1102,7 @@
/* Pop up the PINentry, display the text DESC and a button with the
- text OK_BTN (which may be NULL to use the default of "OK") and wait
+ text OK_BTN (which may be NULL to use the default of "OK") and waut
for the user to hit this button. The return value is not
relevant. */
int
@@ -1252,9 +1111,6 @@
int rc;
char line[ASSUAN_LINELENGTH];
- if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
- return gpg_error (GPG_ERR_CANCELED);
-
rc = start_pinentry (ctrl);
if (rc)
return rc;
@@ -1321,11 +1177,7 @@
{
int rc;
char line[ASSUAN_LINELENGTH];
- npth_attr_t tattr;
- int err;
-
- if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
- return gpg_error (GPG_ERR_CANCELED);
+ pth_attr_t tattr;
rc = start_pinentry (ctrl);
if (rc)
@@ -1349,22 +1201,22 @@
return unlock_pinentry (rc);
}
- err = npth_attr_init (&tattr);
- if (err)
- return unlock_pinentry (gpg_error_from_errno (err));
- npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE);
+ tattr = pth_attr_new();
+ pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
+ pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
+ pth_attr_set (tattr, PTH_ATTR_NAME, "popup-message");
popup_finished = 0;
- err = npth_create (&popup_tid, &tattr, popup_message_thread, NULL);
- npth_attr_destroy (&tattr);
- if (err)
+ popup_tid = pth_spawn (tattr, popup_message_thread, NULL);
+ if (!popup_tid)
{
- rc = gpg_error_from_errno (err);
+ rc = gpg_error_from_syserror ();
log_error ("error spawning popup message handler: %s\n",
- strerror (err) );
+ strerror (errno) );
+ pth_attr_destroy (tattr);
return unlock_pinentry (rc);
}
- npth_setname_np (popup_tid, "popup-message");
+ pth_attr_destroy (tattr);
return 0;
}
@@ -1414,19 +1266,18 @@
#endif
/* Now wait for the thread to terminate. */
- rc = npth_join (popup_tid, NULL);
- if (rc)
+ rc = pth_join (popup_tid, NULL);
+ if (!rc)
log_debug ("agent_popup_message_stop: pth_join failed: %s\n",
- strerror (rc));
- /* Thread IDs are opaque, but we try our best here by resetting it
- to the same content that a static global variable has. */
- memset (&popup_tid, '\0', sizeof (popup_tid));
+ strerror (errno));
+ popup_tid = NULL;
entry_owner = NULL;
/* Now we can close the connection. */
unlock_pinentry (0);
}
+
int
agent_clear_passphrase (ctrl_t ctrl,
const char *keyinfo, cache_mode_t cache_mode)
diff -Nru gnupg2-2.1.6~build1/agent/call-scd.c gnupg2-2.0.28/agent/call-scd.c
--- gnupg2-2.1.6~build1/agent/call-scd.c 2015-06-17 06:39:24.000000000 +0000
+++ gnupg2-2.0.28/agent/call-scd.c 2015-06-02 08:13:55.000000000 +0000
@@ -1,7 +1,5 @@
/* call-scd.c - fork of the scdaemon to do SC operations
- * Copyright (C) 2001, 2002, 2005, 2007, 2010,
- * 2011 Free Software Foundation, Inc.
- * Copyright (C) 2013 Werner Koch
+ * Copyright (C) 2001, 2002, 2005, 2007 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -27,15 +25,13 @@
#include
#include
#include
-#ifdef HAVE_SIGNAL_H
-# include
-#endif
+#include
#include
#include
#ifndef HAVE_W32_SYSTEM
#include
#endif
-#include
+#include
#include "agent.h"
#include
@@ -46,6 +42,15 @@
#define MAX_OPEN_FDS 20
#endif
+/* This Assuan flag is only available since libassuan 2.0.2. Because
+ comments lines are comments anyway we can use a replacement which
+ might not do anything. assuan_{g,s}et_flag don't return an error
+ thus there won't be any ABI problem. */
+#ifndef ASSUAN_CONVEY_COMMENTS
+#define ASSUAN_CONVEY_COMMENTS 4
+#endif
+
+
/* Definition of module local data of the CTRL structure. */
struct scd_local_s
{
@@ -78,14 +83,13 @@
void *sinfo_cb_arg;
};
-struct inq_needpin_s
+struct inq_needpin_s
{
assuan_context_t ctx;
int (*getpin_cb)(void *, const char *, char*, size_t);
void *getpin_cb_arg;
assuan_context_t passthru; /* If not NULL, pass unknown inquiries
up to the caller. */
- int any_inq_seen;
};
@@ -94,7 +98,7 @@
static struct scd_local_s *scd_local_list;
/* A Mutex used inside the start_scd function. */
-static npth_mutex_t start_scd_lock;
+static pth_mutex_t start_scd_lock;
/* A malloced string with the name of the socket to be used for
additional connections. May be NULL if not provided by
@@ -121,35 +125,53 @@
/* This function must be called once to initialize this module. This
has to be done before a second thread is spawned. We can't do the
- static initialization because NPth emulation code might not be able
+ static initialization because Pth emulation code might not be able
to do a static init; in particular, it is not possible for W32. */
void
initialize_module_call_scd (void)
{
static int initialized;
- int err;
if (!initialized)
{
- err = npth_mutex_init (&start_scd_lock, NULL);
- if (err)
- log_fatal ("error initializing mutex: %s\n", strerror (err));
+ if (!pth_mutex_init (&start_scd_lock))
+ log_fatal ("error initializing mutex: %s\n", strerror (errno));
initialized = 1;
}
}
+static void
+dump_mutex_state (pth_mutex_t *m)
+{
+#ifdef _W32_PTH_H
+ (void)m;
+ log_printf ("unknown under W32");
+#else
+ if (!(m->mx_state & PTH_MUTEX_INITIALIZED))
+ log_printf ("not_initialized");
+ else if (!(m->mx_state & PTH_MUTEX_LOCKED))
+ log_printf ("not_locked");
+ else
+ log_printf ("locked tid=0x%lx count=%lu", (long)m->mx_owner, m->mx_count);
+#endif
+}
+
+
/* This function may be called to print infromation pertaining to the
current state of this module to the log. */
void
agent_scd_dump_state (void)
{
+ log_info ("agent_scd_dump_state: scd_lock=");
+ dump_mutex_state (&start_scd_lock);
+ log_printf ("\n");
log_info ("agent_scd_dump_state: primary_scd_ctx=%p pid=%ld reusable=%d\n",
- primary_scd_ctx,
+ primary_scd_ctx,
(long)assuan_get_pid (primary_scd_ctx),
primary_scd_ctx_reusable);
if (socket_name)
- log_info ("agent_scd_dump_state: socket='%s'\n", socket_name);
+ log_info ("agent_scd_dump_state: socket=`%s'\n", socket_name);
}
@@ -160,9 +182,20 @@
called and error checked before any SCD operation. CTRL is the
usual connection context and RC the error code to be passed trhough
the function. */
-static int
+static int
unlock_scd (ctrl_t ctrl, int rc)
{
+ if (gpg_err_code (rc) == GPG_ERR_NOT_OPERATIONAL
+ && gpg_err_source (rc) == GPG_ERR_SOURCE_SCD)
+ {
+ /* If the SCdaemon returned this error, it detected a major
+ problem, like no reader connected. To finish this we need to
+ stop the connection. This simulates an explicit killing of
+ the SCdaemon. */
+ assuan_transact (primary_scd_ctx, "BYE",
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ }
+
if (ctrl->scd_local->locked != 1)
{
log_error ("unlock_scd: invalid lock count (%d)\n",
@@ -198,7 +231,7 @@
const char *pgmname;
assuan_context_t ctx = NULL;
const char *argv[3];
- assuan_fd_t no_close_list[3];
+ int no_close_list[3];
int i;
int rc;
@@ -236,11 +269,10 @@
/* We need to protect the following code. */
- rc = npth_mutex_lock (&start_scd_lock);
- if (rc)
+ if (!pth_mutex_acquire (&start_scd_lock, 0, NULL))
{
log_error ("failed to acquire the start_scd lock: %s\n",
- strerror (rc));
+ strerror (errno));
return gpg_error (GPG_ERR_INTERNAL);
}
@@ -269,7 +301,7 @@
rc = assuan_socket_connect (ctx, socket_name, 0, 0);
if (rc)
{
- log_error ("can't connect to socket '%s': %s\n",
+ log_error ("can't connect to socket `%s': %s\n",
socket_name, gpg_strerror (rc));
err = gpg_error (GPG_ERR_NO_SCDAEMON);
goto leave;
@@ -290,7 +322,7 @@
/* Nope, it has not been started. Fire it up now. */
if (opt.verbose)
log_info ("no running SCdaemon - starting it\n");
-
+
if (fflush (NULL))
{
#ifndef HAVE_W32_SYSTEM
@@ -324,7 +356,7 @@
no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
no_close_list[i++] = assuan_fd_from_posix_fd (fileno (stderr));
}
- no_close_list[i] = ASSUAN_INVALID_FD;
+ no_close_list[i] = -1;
/* Connect to the pinentry and perform initial handshaking. Use
detached flag (128) so that under W32 SCDAEMON does not show up a
@@ -342,6 +374,8 @@
if (opt.verbose)
log_debug ("first connection to SCdaemon established\n");
+ if (DBG_ASSUAN)
+ assuan_set_log_stream (ctx, log_get_stream ());
/* Get the name of the additional socket opened by scdaemon. */
{
@@ -366,29 +400,26 @@
{
memcpy (socket_name, databuf, datalen);
socket_name[datalen] = 0;
- if (DBG_IPC)
- log_debug ("additional connections at '%s'\n", socket_name);
+ if (DBG_ASSUAN)
+ log_debug ("additional connections at `%s'\n", socket_name);
}
}
xfree (databuf);
}
- /* Tell the scdaemon we want him to send us an event signal. We
- don't support this for W32CE. */
-#ifndef HAVE_W32CE_SYSTEM
+ /* Tell the scdaemon we want him to send us an event signal. */
if (opt.sigusr2_enabled)
{
char buf[100];
-
+
#ifdef HAVE_W32_SYSTEM
- snprintf (buf, sizeof buf, "OPTION event-signal=%lx",
+ snprintf (buf, sizeof buf, "OPTION event-signal=%lx",
(unsigned long)get_agent_scd_notify_event ());
#else
snprintf (buf, sizeof buf, "OPTION event-signal=%d", SIGUSR2);
#endif
assuan_transact (ctx, buf, NULL, NULL, NULL, NULL, NULL, NULL);
}
-#endif /*HAVE_W32CE_SYSTEM*/
primary_scd_ctx = ctx;
primary_scd_ctx_reusable = 0;
@@ -399,14 +430,13 @@
unlock_scd (ctrl, err);
if (ctx)
assuan_release (ctx);
- }
+ }
else
{
ctrl->scd_local->ctx = ctx;
}
- rc = npth_mutex_unlock (&start_scd_lock);
- if (rc)
- log_error ("failed to release the start_scd lock: %s\n", strerror (rc));
+ if (!pth_mutex_release (&start_scd_lock))
+ log_error ("failed to release the start_scd lock: %s\n", strerror (errno));
return err;
}
@@ -425,36 +455,35 @@
void
agent_scd_check_aliveness (void)
{
+ pth_event_t evt;
pid_t pid;
#ifdef HAVE_W32_SYSTEM
DWORD rc;
#else
int rc;
#endif
- struct timespec abstime;
- int err;
if (!primary_scd_ctx)
return; /* No scdaemon running. */
/* This is not a critical function so we use a short timeout while
acquiring the lock. */
- npth_clock_gettime (&abstime);
- abstime.tv_sec += 1;
- err = npth_mutex_timedlock (&start_scd_lock, &abstime);
- if (err)
+ evt = pth_event (PTH_EVENT_TIME, pth_timeout (1, 0));
+ if (!pth_mutex_acquire (&start_scd_lock, 0, evt))
{
- if (err == ETIMEDOUT)
+ if (pth_event_occurred (evt))
{
if (opt.verbose > 1)
log_info ("failed to acquire the start_scd lock while"
- " doing an aliveness check: %s\n", strerror (err));
+ " doing an aliveness check: %s\n", "timeout");
}
else
log_error ("failed to acquire the start_scd lock while"
- " doing an aliveness check: %s\n", strerror (err));
+ " doing an aliveness check: %s\n", strerror (errno));
+ pth_event_free (evt, PTH_FREE_THIS);
return;
}
+ pth_event_free (evt, PTH_FREE_THIS);
if (primary_scd_ctx)
{
@@ -490,7 +519,7 @@
sl->ctx = NULL;
}
}
-
+
primary_scd_ctx = NULL;
primary_scd_ctx_reusable = 0;
@@ -499,10 +528,9 @@
}
}
- err = npth_mutex_unlock (&start_scd_lock);
- if (err)
+ if (!pth_mutex_release (&start_scd_lock))
log_error ("failed to release the start_scd lock while"
- " doing the aliveness check: %s\n", strerror (err));
+ " doing the aliveness check: %s\n", strerror (errno));
}
@@ -540,7 +568,7 @@
assuan_release (ctrl->scd_local->ctx);
ctrl->scd_local->ctx = NULL;
}
-
+
/* Remove the local context from our list and release it. */
if (!scd_local_list)
BUG ();
@@ -549,7 +577,7 @@
else
{
struct scd_local_s *sl;
-
+
for (sl=scd_local_list; sl->next_local; sl = sl->next_local)
if (sl->next_local == ctrl->scd_local)
break;
@@ -589,7 +617,7 @@
{
parm->sinfo_cb (parm->sinfo_cb_arg, keyword, keywordlen, line);
}
-
+
return 0;
}
@@ -656,7 +684,7 @@
memcpy (*serialno, line, n);
(*serialno)[n] = 0;
}
-
+
return 0;
}
@@ -696,21 +724,22 @@
put_membuf (data, buffer, length);
return 0;
}
-
+
/* Handle the NEEDPIN inquiry. */
static gpg_error_t
inq_needpin (void *opaque, const char *line)
{
struct inq_needpin_s *parm = opaque;
- const char *s;
char *pin;
size_t pinlen;
int rc;
- parm->any_inq_seen = 1;
- if ((s = has_leading_keyword (line, "NEEDPIN")))
+ if (!strncmp (line, "NEEDPIN", 7) && (line[7] == ' ' || !line[7]))
{
- line = s;
+ line += 7;
+ while (*line == ' ')
+ line++;
+
pinlen = 90;
pin = gcry_malloc_secure (pinlen);
if (!pin)
@@ -721,11 +750,17 @@
rc = assuan_send_data (parm->ctx, pin, pinlen);
xfree (pin);
}
- else if ((s = has_leading_keyword (line, "POPUPPINPADPROMPT")))
+ else if (!strncmp (line, "POPUPPINPADPROMPT", 17)
+ && (line[17] == ' ' || !line[17]))
{
- rc = parm->getpin_cb (parm->getpin_cb_arg, s, NULL, 1);
+ line += 17;
+ while (*line == ' ')
+ line++;
+
+ rc = parm->getpin_cb (parm->getpin_cb_arg, line, NULL, 1);
}
- else if ((s = has_leading_keyword (line, "DISMISSPINPADPROMPT")))
+ else if (!strncmp (line, "DISMISSPINPADPROMPT", 19)
+ && (line[19] == ' ' || !line[19]))
{
rc = parm->getpin_cb (parm->getpin_cb_arg, "", NULL, 0);
}
@@ -747,7 +782,7 @@
assuan_end_confidential (parm->passthru);
if (!rc)
{
- if ((rest = (needrest
+ if ((rest = (needrest
&& !assuan_get_flag (parm->ctx, ASSUAN_CONFIDENTIAL))))
assuan_begin_confidential (parm->ctx);
rc = assuan_send_data (parm->ctx, value, valuelen);
@@ -756,12 +791,12 @@
xfree (value);
}
else
- log_error ("error forwarding inquiry '%s': %s\n",
+ log_error ("error forwarding inquiry `%s': %s\n",
line, gpg_strerror (rc));
}
else
{
- log_error ("unsupported inquiry '%s'\n", line);
+ log_error ("unsupported inquiry `%s'\n", line);
rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
}
@@ -769,63 +804,23 @@
}
-/* Helper returning a command option to describe the used hash
- algorithm. See scd/command.c:cmd_pksign. */
-static const char *
-hash_algo_option (int algo)
-{
- switch (algo)
- {
- case GCRY_MD_MD5 : return "--hash=md5";
- case GCRY_MD_RMD160: return "--hash=rmd160";
- case GCRY_MD_SHA1 : return "--hash=sha1";
- case GCRY_MD_SHA224: return "--hash=sha224";
- case GCRY_MD_SHA256: return "--hash=sha256";
- case GCRY_MD_SHA384: return "--hash=sha384";
- case GCRY_MD_SHA512: return "--hash=sha512";
- default: return "";
- }
-}
-
-
-static gpg_error_t
-cancel_inquire (ctrl_t ctrl, gpg_error_t rc)
-{
- gpg_error_t oldrc = rc;
-
- /* The inquire callback was called and transact returned a
- cancel error. We assume that the inquired process sent a
- CANCEL. The passthrough code is not able to pass on the
- CANCEL and thus scdaemon would stuck on this. As a
- workaround we send a CANCEL now. */
- rc = assuan_write_line (ctrl->scd_local->ctx, "CAN");
- if (!rc) {
- char *line;
- size_t len;
-
- rc = assuan_read_line (ctrl->scd_local->ctx, &line, &len);
- if (!rc)
- rc = oldrc;
- }
-
- return rc;
-}
-/* Create a signature using the current card. MDALGO is either 0 or
- gives the digest algorithm. */
+/* Create a signature using the current card */
int
agent_card_pksign (ctrl_t ctrl,
const char *keyid,
int (*getpin_cb)(void *, const char *, char*, size_t),
void *getpin_cb_arg,
- int mdalgo,
const unsigned char *indata, size_t indatalen,
unsigned char **r_buf, size_t *r_buflen)
{
- int rc;
- char line[ASSUAN_LINELENGTH];
+ int rc, i;
+ char *p, line[ASSUAN_LINELENGTH];
membuf_t data;
struct inq_needpin_s inqparm;
+ size_t len;
+ unsigned char *sigbuf;
+ size_t sigbuflen;
*r_buf = NULL;
rc = start_scd (ctrl);
@@ -835,8 +830,10 @@
if (indatalen*2 + 50 > DIM(line))
return unlock_scd (ctrl, gpg_error (GPG_ERR_GENERAL));
- bin2hex (indata, indatalen, stpcpy (line, "SETDATA "));
-
+ sprintf (line, "SETDATA ");
+ p = line + strlen (line);
+ for (i=0; i < indatalen ; i++, p += 2 )
+ sprintf (p, "%02X", indata[i]);
rc = assuan_transact (ctrl->scd_local->ctx, line,
NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
@@ -847,62 +844,47 @@
inqparm.getpin_cb = getpin_cb;
inqparm.getpin_cb_arg = getpin_cb_arg;
inqparm.passthru = 0;
- inqparm.any_inq_seen = 0;
- if (ctrl->use_auth_call)
- snprintf (line, sizeof line, "PKAUTH %s", keyid);
- else
- snprintf (line, sizeof line, "PKSIGN %s %s",
- hash_algo_option (mdalgo), keyid);
+ snprintf (line, DIM(line)-1,
+ ctrl->use_auth_call? "PKAUTH %s":"PKSIGN %s", keyid);
+ line[DIM(line)-1] = 0;
rc = assuan_transact (ctrl->scd_local->ctx, line,
membuf_data_cb, &data,
inq_needpin, &inqparm,
NULL, NULL);
- if (inqparm.any_inq_seen && (gpg_err_code(rc) == GPG_ERR_CANCELED ||
- gpg_err_code(rc) == GPG_ERR_ASS_CANCELED))
- rc = cancel_inquire (ctrl, rc);
-
if (rc)
{
- size_t len;
-
xfree (get_membuf (&data, &len));
return unlock_scd (ctrl, rc);
}
+ sigbuf = get_membuf (&data, &sigbuflen);
- *r_buf = get_membuf (&data, r_buflen);
- return unlock_scd (ctrl, 0);
-}
-
-
-
-
-/* Check whether there is any padding info from scdaemon. */
-static gpg_error_t
-padding_info_cb (void *opaque, const char *line)
-{
- int *r_padding = opaque;
- const char *s;
-
- if ((s=has_leading_keyword (line, "PADDING")))
- {
- *r_padding = atoi (s);
- }
+ /* Create an S-expression from it which is formatted like this:
+ "(7:sig-val(3:rsa(1:sSIGBUFLEN:SIGBUF)))" */
+ *r_buflen = 21 + 11 + sigbuflen + 4;
+ p = xtrymalloc (*r_buflen);
+ *r_buf = (unsigned char*)p;
+ if (!p)
+ return unlock_scd (ctrl, out_of_core ());
+ p = stpcpy (p, "(7:sig-val(3:rsa(1:s" );
+ sprintf (p, "%u:", (unsigned int)sigbuflen);
+ p += strlen (p);
+ memcpy (p, sigbuf, sigbuflen);
+ p += sigbuflen;
+ strcpy (p, ")))");
+ xfree (sigbuf);
- return 0;
+ assert (gcry_sexp_canon_len (*r_buf, *r_buflen, NULL, NULL));
+ return unlock_scd (ctrl, 0);
}
-
-/* Decipher INDATA using the current card. Note that the returned
- value is not an s-expression but the raw data as returned by
- scdaemon. The padding information is stored at R_PADDING with -1
- for not known. */
+/* Decipher INDATA using the current card. Note that the returned value is */
int
agent_card_pkdecrypt (ctrl_t ctrl,
const char *keyid,
int (*getpin_cb)(void *, const char *, char*, size_t),
void *getpin_cb_arg,
const unsigned char *indata, size_t indatalen,
- char **r_buf, size_t *r_buflen, int *r_padding)
+ char **r_buf, size_t *r_buflen)
{
int rc, i;
char *p, line[ASSUAN_LINELENGTH];
@@ -911,45 +893,34 @@
size_t len;
*r_buf = NULL;
- *r_padding = -1; /* Unknown. */
rc = start_scd (ctrl);
if (rc)
return rc;
/* FIXME: use secure memory where appropriate */
+ if (indatalen*2 + 50 > DIM(line))
+ return unlock_scd (ctrl, gpg_error (GPG_ERR_GENERAL));
- for (len = 0; len < indatalen;)
- {
- p = stpcpy (line, "SETDATA ");
- if (len)
- p = stpcpy (p, "--append ");
- for (i=0; len < indatalen && (i*2 < DIM(line)-50); i++, len++)
- {
- sprintf (p, "%02X", indata[len]);
- p += 2;
- }
- rc = assuan_transact (ctrl->scd_local->ctx, line,
- NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- return unlock_scd (ctrl, rc);
- }
+ sprintf (line, "SETDATA ");
+ p = line + strlen (line);
+ for (i=0; i < indatalen ; i++, p += 2 )
+ sprintf (p, "%02X", indata[i]);
+ rc = assuan_transact (ctrl->scd_local->ctx, line,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ if (rc)
+ return unlock_scd (ctrl, rc);
init_membuf (&data, 1024);
inqparm.ctx = ctrl->scd_local->ctx;
inqparm.getpin_cb = getpin_cb;
inqparm.getpin_cb_arg = getpin_cb_arg;
inqparm.passthru = 0;
- inqparm.any_inq_seen = 0;
snprintf (line, DIM(line)-1, "PKDECRYPT %s", keyid);
line[DIM(line)-1] = 0;
rc = assuan_transact (ctrl->scd_local->ctx, line,
membuf_data_cb, &data,
inq_needpin, &inqparm,
- padding_info_cb, r_padding);
- if (inqparm.any_inq_seen && (gpg_err_code(rc) == GPG_ERR_CANCELED ||
- gpg_err_code(rc) == GPG_ERR_ASS_CANCELED))
- rc = cancel_inquire (ctrl, rc);
-
+ NULL, NULL);
if (rc)
{
xfree (get_membuf (&data, &len));
@@ -1041,64 +1012,6 @@
}
-struct writekey_parm_s
-{
- assuan_context_t ctx;
- int (*getpin_cb)(void *, const char *, char*, size_t);
- void *getpin_cb_arg;
- assuan_context_t passthru;
- int any_inq_seen;
- /**/
- const unsigned char *keydata;
- size_t keydatalen;
-};
-
-/* Handle a KEYDATA inquiry. Note, we only send the data,
- assuan_transact takes care of flushing and writing the end */
-static gpg_error_t
-inq_writekey_parms (void *opaque, const char *line)
-{
- struct writekey_parm_s *parm = opaque;
-
- if (has_leading_keyword (line, "KEYDATA"))
- return assuan_send_data (parm->ctx, parm->keydata, parm->keydatalen);
- else
- return inq_needpin (opaque, line);
-}
-
-
-int
-agent_card_writekey (ctrl_t ctrl, int force, const char *serialno,
- const char *id, const char *keydata, size_t keydatalen,
- int (*getpin_cb)(void *, const char *, char*, size_t),
- void *getpin_cb_arg)
-{
- int rc;
- char line[ASSUAN_LINELENGTH];
- struct writekey_parm_s parms;
-
- (void)serialno;
- rc = start_scd (ctrl);
- if (rc)
- return rc;
-
- snprintf (line, DIM(line)-1, "WRITEKEY %s%s", force ? "--force " : "", id);
- line[DIM(line)-1] = 0;
- parms.ctx = ctrl->scd_local->ctx;
- parms.getpin_cb = getpin_cb;
- parms.getpin_cb_arg = getpin_cb_arg;
- parms.passthru = 0;
- parms.any_inq_seen = 0;
- parms.keydata = keydata;
- parms.keydatalen = keydatalen;
-
- rc = assuan_transact (ctrl->scd_local->ctx, line, NULL, NULL,
- inq_writekey_parms, &parms, NULL, NULL);
- if (parms.any_inq_seen && (gpg_err_code(rc) == GPG_ERR_CANCELED ||
- gpg_err_code(rc) == GPG_ERR_ASS_CANCELED))
- rc = cancel_inquire (ctrl, rc);
- return unlock_scd (ctrl, rc);
-}
/* Type used with the card_getattr_cb. */
struct card_getattr_parm_s {
@@ -1131,7 +1044,7 @@
if (!parm->data)
parm->error = errno;
}
-
+
return 0;
}
@@ -1159,7 +1072,7 @@
/* We assume that NAME does not need escaping. */
if (8 + strlen (name) > DIM(line)-1)
return gpg_error (GPG_ERR_TOO_LARGE);
- stpcpy (stpcpy (line, "GETATTR "), name);
+ stpcpy (stpcpy (line, "GETATTR "), name);
err = start_scd (ctrl);
if (err)
@@ -1170,10 +1083,10 @@
card_getattr_cb, &parm);
if (!err && parm.error)
err = gpg_error_from_errno (parm.error);
-
+
if (!err && !parm.data)
err = gpg_error (GPG_ERR_NO_DATA);
-
+
if (!err)
*result = parm.data;
else
@@ -1192,28 +1105,16 @@
char keyword[200];
int i;
- if (line[0] == '#' && (!line[1] || spacep (line+1)))
- {
- /* We are called in convey comments mode. Now, if we see a
- comment marker as keyword we forward the line verbatim to the
- the caller. This way the comment lines from scdaemon won't
- appear as status lines with keyword '#'. */
- assuan_write_line (ctx, line);
- }
- else
- {
- for (i=0; *line && !spacep (line) && i < DIM(keyword)-1; line++, i++)
- keyword[i] = *line;
- keyword[i] = 0;
-
- /* Truncate any remaining keyword stuff. */
- for (; *line && !spacep (line); line++)
- ;
- while (spacep (line))
- line++;
+ for (i=0; *line && !spacep (line) && i < DIM(keyword)-1; line++, i++)
+ keyword[i] = *line;
+ keyword[i] = 0;
+ /* truncate any remaining keyword stuff. */
+ for (; *line && !spacep (line); line++)
+ ;
+ while (spacep (line))
+ line++;
- assuan_write_status (ctx, keyword, line);
- }
+ assuan_write_status (ctx, keyword, line);
return 0;
}
@@ -1248,16 +1149,12 @@
inqparm.getpin_cb = getpin_cb;
inqparm.getpin_cb_arg = getpin_cb_arg;
inqparm.passthru = assuan_context;
- inqparm.any_inq_seen = 0;
saveflag = assuan_get_flag (ctrl->scd_local->ctx, ASSUAN_CONVEY_COMMENTS);
assuan_set_flag (ctrl->scd_local->ctx, ASSUAN_CONVEY_COMMENTS, 1);
rc = assuan_transact (ctrl->scd_local->ctx, cmdline,
pass_data_thru, assuan_context,
inq_needpin, &inqparm,
pass_status_thru, assuan_context);
- if (inqparm.any_inq_seen && gpg_err_code(rc) == GPG_ERR_ASS_CANCELED)
- rc = cancel_inquire (ctrl, rc);
-
assuan_set_flag (ctrl->scd_local->ctx, ASSUAN_CONVEY_COMMENTS, saveflag);
if (rc)
{
@@ -1266,3 +1163,5 @@
return unlock_scd (ctrl, 0);
}
+
+
diff -Nru gnupg2-2.1.6~build1/agent/ChangeLog-2011 gnupg2-2.0.28/agent/ChangeLog-2011
--- gnupg2-2.1.6~build1/agent/ChangeLog-2011 2015-06-17 06:39:24.000000000 +0000
+++ gnupg2-2.0.28/agent/ChangeLog-2011 2015-06-02 08:13:55.000000000 +0000
@@ -1,64 +1,14 @@
-2011-12-01 Werner Koch
+2011-12-02 Werner Koch
NB: ChangeLog files are no longer manually maintained. Starting
on December 1st, 2011 we put change information only in the GIT
commit log, and generate a top-level ChangeLog file from logs at
"make dist". See doc/HACKING for details.
-2011-11-28 Werner Koch
+2011-08-04 Werner Koch
- * command-ssh.c (card_key_available): Change wording of no key
- diagnostic.
- (ssh_handler_request_identities): Do not call card_key_available
- if the scdaemon is disabled.
-
-2011-09-12 Ben Kibbey
-
- * genkey.c (agent_ask_new_passphrase): Allow for an empty passphrase
- (no protection) in PINENTRY_MODE_LOOPBACK.
-
-2011-09-10 Ben Kibbey
-
- * agent.h (pinentry_loopback): New prototype.
- * command.c (pinentry_loopback): New function to inquire a passphrase
- from the client. For use with pinentry-mode=loopback.
- * call-pinentry.c (agent_askpin): Handle PINENTRY_MODE_LOOPBACK.
- * call-pinentry.c (agent_get_passphrase): Ditto.
- * genkey.c (agent_ask_new_passphrase): Ditto.
-
-2011-08-10 Werner Koch
-
- * genkey.c (check_passphrase_pattern): Use gpg_strerror instead of
- strerror.
- * command-ssh.c (ssh_receive_mpint_list): Remove unused var
- ELEMS_PUBLIC_N.
- * gpg-agent.c (main): Remove unused var MAY_COREDUMP.
-
-2011-08-09 Ben Kibbey
-
- * command.c (option_handler): Have option s2k-count match the
- documentation.
-
-2011-07-27 Werner Koch
-
- * call-scd.c (struct inq_needpin_s): Add field ANY_INQ_SEEN.
- (inq_needpin): Set it.
- (agent_card_scd): Send the cancel only if an inquire was actually
- used.
-
-2011-07-09 Ben Kibbey
-
- * call-scd.c (agent_card_scd): Send the CANCEL command back to SCD
- when the SCD command is cancelled from the client.
-
-2011-07-22 Werner Koch
-
- * command-ssh.c (ssh_receive_key): Do not init comment to an empty
- static string; in the error case it would be freed.
-
-2011-07-20 Werner Koch
-
- * command.c (do_one_keyinfo, cmd_keyinfo): Support option --ssh-fpr.
+ * command.c (cmd_keyinfo, do_one_keyinfo): Support options --data
+ and --ssh-fpr.
* command-ssh.c (ssh_identity_register): Display the ssh
fingerprint in the prompt.
@@ -69,165 +19,28 @@
(search_control_file): Add new arg R_CONFIRM and enhance parser.
* findkey.c (agent_raw_key_from_file): New.
(modify_description): Add format letter %F.
+
* findkey.c (agent_key_from_file): Simplify comment extraction by
using gcry_sexp_nth_string.
-2011-06-28 Ben Kibbey
-
- * command.c (option_handler): Add option s2k-count.
- * agent.h (server_control_s): Add member s2k_count.
- * genkey.c (store_key): Add parameter s2k_count.
- * protect.c (agent_protect): Add parameter s2k_count.
- * protect.c (do_encryption): Add parameter s2k_count.
-
-2011-06-01 Marcus Brinkmann
-
- * cvt-openpgp.c (convert_to_openpgp): Change type of N to unsigned
- int.
-
-2011-04-26 Werner Koch
-
- * cvt-openpgp.c (convert_to_openpgp): Use rfc4880 encoded S2K count.
- * protect.c (get_standard_s2k_count_rfc4880): New.
- (S2K_DECODE_COUNT): New.
- (s2k_hash_passphrase): Use the new macro.
-
-2011-04-21 Werner Koch
-
- * agent.h (server_control_s): Add field cache_ttl_opt_preset.
- * gpg-agent.c (agent_init_default_ctrl): Init this field.
- * genkey.c (agent_genkey): Use this new variable.
- * command.c (cmd_passwd): Ditto.
- (option_handler): Add new option cache-ttl-opt-preset.
-
-2011-04-20 Marcus Brinkmann
-
- * command.c (cmd_import_key): Release key from failed import
- before converting openpgp private key in the openpgp-private-key
- case.
-
-2011-04-17 Ben Kibbey
-
- * command.c (cmd_passwd): Check for an error before presetting.
-
-2011-04-12 Ben Kibbey
-
- * command.c (cmd_passwd): Fixed --preset when not previously cached.
-
-2011-04-12 Werner Koch
-
- * agent.h (CACHE_TTL_NONCE, CACHE_TTL_OPT_PRESET): New.
- * command.c (cmd_passwd, cmd_import_key): Use new macros.
- * genkey.c (agent_genkey): Ditto.
-
-2011-04-10 Ben Kibbey
-
- * command.c (cmd_passwd): Add option --preset.
- * command.c (cmd_genkey): Add option --preset.
- * genkey.c (agent_genkey): Add parameter preset.
-
-2011-04-06 Ben Kibbey
-
- * command.c (do_one_keyinfo): Add protection type field.
-
-2011-03-10 Werner Koch
-
- * protect.c (hash_passphrase): Use the new gcry_kdf_derive.
-
-2011-03-08 Werner Koch
-
- * cvt-openpgp.c (GCRY_PK_ECDH) [!HAVE_GCRY_PK_ECDH]: Remove.
-
-2011-03-03 Ben Kibbey
-
- * command.c (cmd_preset_passphrase): Add option --inquire.
-
-2011-03-03 Werner Koch
-
- * gpg-agent.c: Add option --allow-loopback-pinentry.
- * command.c (option_handler): Add option pinentry-mode.
- * agent.h (pinentry_mode_t): New enum.
- (struct server_local_s): Add PINENTRY_MODE.
- (struct opt): Add ALLOW_LOOPBACK_PINENTRY.
- * call-pinentry.c (agent_askpin): Implement ask, cancel and error
- pinentry modes.
- (agent_get_passphrase, agent_get_confirmation): Ditto.
- (agent_show_message): Return cancel if pinentry mode is not "ask".
- (agent_popup_message_start): Ditto.
-
-2011-03-02 Werner Koch
-
- * call-scd.c (hash_algo_option): New.
- (agent_card_pksign): Use it with PKSIGN.
-
-2011-03-02 Ben Kibbey (wk)
-
- * command.c (cmd_clear_passphrase): Add option --mode=normal.
- (cmd_keyinfo): Add option --data.
- (do_one_keyinfo): Return CACHED status. Add arg DATA.
-
-2011-02-07 Werner Koch
-
- * pksign.c (do_encode_dsa): Enforce multipe of 8 bits only for DSA.
-
-2011-02-03 Werner Koch
-
- * protect.c (protect_info): Support ECC algos.
-
- * pksign.c (do_encode_dsa): Map public key algo number. Extend
- DSA size check for ECDSA.
-
- * gpg-agent.c: Include cipher.h.
- (map_pk_openpgp_to_gcry): New.
-
- * findkey.c (key_parms_from_sexp): Support ECDH.
-
- * cvt-openpgp.c (get_keygrip): Support ECC algorithms.
- (convert_secret_key): Ditto.
- (do_unprotect): Ditto.
+2011-08-04 Werner Koch
-2011-02-02 Werner Koch
+ * genkey.c (check_passphrase_pattern): Use gpg_strerror.
- * cvt-openpgp.c (convert_secret_key): Remove algo mapping.
+ * command-ssh.c (ssh_receive_mpint_list): Remove set but unused
+ var ELEMS_PUBLIC_N.
-2011-01-31 Werner Koch
+ * gpg-agent.c (main): Remove set but unused var MAY_COREDUMP.
- * cvt-openpgp.c (convert_to_openpgp): Adjust to reverted Libgcrypt
- ABI.
-
- * protect.c (protect_info): Adjust ECDSA and ECDH parameter names.
- Add "ecc".
- * findkey.c (key_parms_from_sexp): Ditto.
-
-2011-01-19 Werner Koch
-
- * trustlist.c (read_one_trustfile): Also chop an CR.
-
-2011-01-21 Werner Koch
-
- * pksign.c (do_encode_dsa): Compare MDLEN to bytes.
-
- * cvt-openpgp.c (GCRY_PK_ECDH) [!HAVE_GCRY_PK_ECDH]: New.
-
-2010-12-02 Werner Koch
-
- * gpg-agent.c (CHECK_OWN_SOCKET_INTERVAL) [W32CE]: Set to 60
- seconds.
-
-2010-11-29 Werner Koch
-
- * cache.c (initialize_module_cache): Factor code out to ...
- (init_encryption): new.
- (new_data, agent_get_cache): Init encryption on on the fly.
-
-2010-11-26 Werner Koch
+2011-07-22 Werner Koch
- * gpg-agent.c (CHECK_OWN_SOCKET_INTERVAL): New.
- (handle_tick) [W32CE]: Don't check own socket.
+ * command-ssh.c (ssh_receive_key): Do not init comment to an empty
+ static string; in the error case it would be freed.
-2010-11-23 Werner Koch
+2011-04-29 Werner Koch
- * Makefile.am (gpg_agent_LDFLAGS): Add extra_bin_ldflags.
+ * gpg-agent.c: Include estream.h
+ (main): s/pth_kill/es_pth_kill/.
2010-11-11 Werner Koch
@@ -235,240 +48,33 @@
* gpg-agent.c (handle_connections): Set that flag.
* call-scd.c (start_scd): Enable events depending on this flag.
-2010-10-27 Werner Koch
-
- * gpg-agent.c (create_socket_name): Use TMPDIR. Change callers.
-
-2010-10-26 Werner Koch
-
- * cache.c (agent_put_cache): Allow deletion even if TTL is passwd
- as 0.
-
- * genkey.c (agent_protect_and_store): Add arg PASSPHRASE_ADDR.
- * command.c (cmd_passwd): Add option --passwd-nonce.
- (struct server_local_s): Add LAST_CACHE_NONCE and LAST_PASSWD_NONCE.
- (clear_nonce_cache): New.
- (reset_notify): Clear the nonce cache.
- (start_command_handler): Ditto.
-
-2010-10-25 Werner Koch
-
- * command.c (cmd_export_key): Free CACHE_NONCE.
- (cmd_passwd): Add option --cache-nonce.
-
-2010-10-18 Werner Koch
-
- * call-pinentry.c (start_pinentry): Print name of pinentry on
- connect error.
-
- * call-scd.c (agent_card_pksign): Make sure to return an unsigned
- number.
-
-2010-10-14 Werner Koch
-
- * command.c (cmd_genkey): Add option --no-protection.
- * genkey.c (agent_genkey): Add arg NO_PROTECTION.
-
-2010-10-13 Werner Koch
-
- * call-pinentry.c (agent_get_passphrase): Support the close_button.
-
- * gpg-agent.c (create_server_socket): Switch back to stderr
- logging if we are not starting a agent.
-
- * command.c (cmd_passwd, cmd_export_key): Move mapping of
- GPG_ERR_FULLY_CANCELED to ..
- (leave_cmd): .. here.
- (option_handler): Add option agent-awareness.
- * protect-tool.c (get_passphrase): Take care of
- GPG_ERR_FULLY_CANCELED.
- * findkey.c (try_unprotect_cb): Ditto.
- (unprotect): Remove the fully_canceled hack.
- * call-pinentry.c (start_pinentry): Ditto.
- (agent_askpin): Ditto.
- * pkdecrypt.c (agent_pkdecrypt): Ditto
- * pksign.c (agent_pksign_do): Ditto.
- * genkey.c (agent_ask_new_passphrase): Remove arg CANCEL_ALL.
-
-2010-10-06 Werner Koch
-
- * cvt-openpgp.c (convert_secret_key): Add missing break.
-
-2010-10-05 Werner Koch
-
- * gpg-agent.c (main): Don't set SSH_AGENT_PID so that ssh-agent -k
- won't kill out gpg-agent.
-
2010-09-30 Werner Koch
- * gpg-agent.c (agent_exit): Run cleanup.
- (cleanup): Run only once.
-
- * call-pinentry.c (close_button_status_cb): New.
- (agent_askpin): Add arg R_CANCEL_ALL. Change all callers.
- * genkey.c (agent_ask_new_passphrase): Ditto.
- * findkey.c (unprotect): Return GPG_ERR_FULLY_CANCELED if needed.
-
- * command.c (cmd_export_key): Add support for OpenPGP keys.
- * findkey.c (unprotect): Add optional arg R_PASSPHRASE.
- (agent_key_from_file): Ditto. Change all callers.
-
* findkey.c (unprotect): Do not put the passphrase into the cache
if it has been changed.
- * cvt-openpgp.c (convert_to_openpgp, apply_protection)
- (key_from_sexp): New.
-
-2010-09-29 Werner Koch
-
- * cvt-openpgp.c (convert_openpgp): Rename to convert_from_openpgp.
-
- * command.c (has_option): Stop at "--".
- (has_option_name, option_value): Ditto.
- (skip_options): Skip initial spaces.
-
2010-09-24 Werner Koch
* gpg-agent.c (main, reread_configuration): Always test whether
the default configuration file has been created in the meantime.
Fixes bug#1285.
-2010-09-17 Werner Koch
-
- * command.c (cmd_havekey): Allow testing of several keygrips.
-
-2010-09-15 Werner Koch
-
- * protect.c (calculate_mic): Take care of shared secret format.
-
- * agent.h (PROTECTED_SHARED_SECRET): New.
-
-2010-09-02 Werner Koch
-
- * cache.c (new_data): Change arg and callers to use a string and
- explicity return an error code. We never used raw binary data and
- thus it is easier to use a string. Adjust callers.
- (initialize_module_cache, deinitialize_module_cache): New.
- (new_data): Encrypt the cached data.
- (struct cache_item_s): Remove field LOCKCOUNT. Change all users
- accordingly.
- (agent_unlock_cache_entry): Remove.
- (agent_get_cache): Return an allocated string and remove CACHE_ID.
- * genkey.c (agent_genkey): Remove cache marker stuff.
- * findkey.c (unprotect): Ditto.
- * cvt-openpgp.c (convert_openpgp): Ditto.
- * command.c (cmd_get_passphrase): Ditto.
- * gpg-agent.c (main, cleanup): Initialize and deinitialize the
- cache module.
-
-2010-09-01 Werner Koch
-
- * call-pinentry.c (start_pinentry): Disable pinentry logging.
-
- * command.c (cmd_import_key, cmd_genkey, cmd_pksign): Add CACHE
- handling.
- * cvt-openpgp.c (convert_openpgp): Add arg CACHE_NONCE and try the
- cached nonce first.
- * genkey.c (agent_genkey): Add arg CACHE_NONCE.
- * cache.c (agent_get_cache): Require user and nonce cache modes
- to match the requested mode.
- (agent_put_cache): Ditto.
- * agent.h (CACHE_MODE_NONCE): New.
- * pksign.c (agent_pksign_do, agent_pksign): Add arg CACHE_NONCE.
- * findkey.c (agent_key_from_file): Ditto.
- (unprotect): Implement it.
-
-2010-08-31 Werner Koch
-
- * pksign.c (do_encode_dsa): Fix sign problem.
- * findkey.c (agent_is_dsa_key): Adjust to actual usage.
-
-2010-08-30 Werner Koch
-
- * protect.c (s2k_hash_passphrase): New public function.
-
-2010-08-27 Werner Koch
-
- * command.c (cmd_import_key): Support OpenPGP keys.
- * cvt-openpgp.h, cvt-openpgp.c: New. Some of the code is based on
- code taken from g10/seckey-cert.c.
-
-2010-08-26 Werner Koch
-
- * command-ssh.c (open_control_file): Use estream to create the file.
-
- * findkey.c (agent_write_private_key): Explicitly create file with
- mode 600.
- * gpg-agent.c (main): Ditto.
- * trustlist.c (agent_marktrusted): Explicitly create file with
- mode 640.
-
-2010-08-16 Werner Koch
-
- * gpg-agent.c: Replace remaining printf by es_printf.
-
2010-08-11 Werner Koch
- * call-pinentry.c (agent_get_passphrase, agent_askpin): Fix
+ * call-pinentry.c (agent_askpin, agent_get_passphrase): Fix
setting of confidential flag.
* call-scd.c (agent_card_scd): Pass assuan comment lines to the
caller.
(ASSUAN_CONVEY_COMMENTS): Provide replacement if needed.
-2010-08-09 Werner Koch
-
- * Makefile.am (t_common_ldadd): Add NETLIBS for sake of the TCP
- logging.
-
-2010-06-24 Werner Koch
-
- * genkey.c (check_passphrase_pattern): Use HANG option for
- gnupg_wait_progress. Fixes regression from 2010-06-09.
-
-2010-06-21 Werner Koch
-
- * protect-tool.c (export_p12_file, import_p12_cert_cb)
- (import_p12_file, sexp_to_kparms, store_private_key): Remove
- unused code.
-
-2010-06-18 Werner Koch
-
- * protect-tool.c (store_private_key, rsa_key_check): Remove.
-
- * command.c (cmd_export_key): New.
-
-2010-06-15 Werner Koch
-
- * command.c (cmd_keywrap_key, cmd_import_key): New.
-
- * genkey.c (agent_genkey, agent_protect_and_store): Factor common
- code out to...
- (agent_ask_new_passphrase): .. new.
-
- * findkey.c (agent_write_private_key): Return GPG_ERR_EEXIST
- instead of GPG_ERR_GENERAL.
-
-2010-06-14 Werner Koch
-
- * protect-tool.c: Remove commands --p12-import and --p12-export.
- * minip12.c, minip12.h: Move to ../sm.
- * Makefile.am (gpg_protect_tool_SOURCES): Remove them.
- * preset-passphrase.c: Remove unneeded minip12.h.
-
- * command.c (cmd_keywrap_key): New.
-
- * command.c (leave_cmd): New.
- (cmd_istrusted, cmd_listtrusted, cmd_marktrusted, cmd_pksign)
- (cmd_pkdecrypt, cmd_genkey, cmd_readkey, cmd_keyinfo)
- (cmd_get_passphrase, cmd_get_confirmation, cmd_learn)
- (cmd_passwd, cmd_preset_passphrase, cmd_getval, cmd_putval): Use it.
-
2010-05-12 Werner Koch
* preset-passphrase.c (forget_passphrase): Actually implement
this. Fixes bug#1198.
+ * gpg-agent.c (handle_tick): Do not print die message with option -q.
+
2010-05-11 Werner Koch
* agent.h (opt): Add field USE_STANDARD_SOCKET.
@@ -478,184 +84,53 @@
for non-W32 platforms.
(cmd_getinfo): New subcommands std_session_env and std_startup_env.
-2010-05-03 Werner Koch
-
- * gpg-agent.c (check_own_socket_thread): Do not release SOCKNAME
- too early.
-
-2010-04-30 Werner Koch
+2010-05-04 Werner Koch
* gpg-agent.c (main): Add command --use-standard-socket-p.
-2010-04-26 Werner Koch
-
- * gpg-agent.c (create_server_socket) [W32]: Also check for EEXIST.
-
-2010-04-19 Werner Koch
-
- * pksign.c (get_dsa_qbits, do_encode_dsa): New.
- (agent_pksign_do): Detect DSA keys and use do_encode_dsa.
- * findkey.c (agent_public_key_from_file): Factor some code out to ..
- (key_parms_from_sexp): New.
- (agent_is_dsa_key): New.
-
- * command.c (cmd_sethash): Clear digeest.RAW_VALUE.
-
-2010-04-14 Werner Koch
-
- * Makefile.am (libexec_PROGRAMS) [W32CE]: Do not build
- gpg-preset-passphrase for now.
- (pwquery_libs) [W32CE]: Set to empty.
-
- * trustlist.c (read_one_trustfile): Use estream.
-
-2010-04-13 Werner Koch
-
- * findkey.c (read_key_file): Use estream.
- (agent_write_private_key): Ditto.
-
-2010-04-07 Werner Koch
-
- * gpg-agent.c (handle_connections) [W32]: Assume that PTh support
- the handle event. Use a dummy event for W32CE.
- (get_agent_scd_notify_event) [W32CE]: Do not build.
-
- * call-pinentry.c: Remove setenv.h. Include sysutils.h.
- (atfork_cb): s/setenv/gnupg_setenv/.
-
- * gpg-agent.c: Do not include setenv.h.
- (main): s/unsetenv/gnupg_unsetenv/.
-
- * protect.c (calibrate_get_time) [W32CE]: Use GetThreadTimes.
-
-2010-04-06 Werner Koch
-
- * call-scd.c [!HAVE_SIGNAL_H]: Do not include signal.h.
+2010-05-03 Werner Koch
- * findkey.c (agent_write_private_key): s/remove/gnupg_remove/.
+ * gpg-agent.c (check_own_socket_thread): Do not release SOCKNAME
+ too early.
- * command-ssh.c (search_control_file): Replace rewind by fseek and
- clearerr.
- * genkey.c (check_passphrase_pattern): Ditto.
+2010-03-17 Werner Koch
- * gpg-agent.c [!HAVE_SIGNAL_H]: Do not include signal.h.
- (remove_socket): s/remove/gnupg_remove/.
- (create_private_keys_directory): Use gnupg_mkdir.
+ * call-scd.c (unlock_scd): Send a BYE under certain conditions.
-2010-03-11 Werner Koch
+2010-02-19 Werner Koch
- * gpg-agent.c: Include "asshelp.h".
- (main): Remove assuan_set_assuan_log_prefix. Add
- assuan_set_log_cb.
- (handle_signal): Disable pth ctrl dumping.
- (parse_rereadable_options, main): Remove assuan_set_assuan_log_stream.
- * call-scd.c (start_scd): Remove assuan_set_log_stream.
+ * call-pinentry.c (start_pinentry): Remove a translation prefix.
-2010-03-10 Werner Koch
+2010-02-18 Werner Koch
- * Makefile.am (common_libs): Remove libjnlib.a.
+ * protect.c (agent_unprotect): Initialize CLEARTEXT.
- * trustlist.c, protect-tool.c, command-ssh.c: Remove estream.h.
+ * command.c (register_commands): Unconditionally use
+ assuan_register_post_cmd_notify.
+ (start_command_handler): Undocumented use assuan_set_io_monitor.
2010-02-17 Werner Koch
* call-pinentry.c (start_pinentry): Always free OPTSTR. Send
default-xxx strings.
-2010-01-26 Werner Koch
-
- * protect.c (do_encryption): Encode the s2kcount and no not use a
- static value of 96.
-
-2009-12-21 Werner Koch
-
- * command.c (cmd_getinfo): Add sub-command s2k_count.
-
-2009-12-14 Werner Koch
-
- * protect.c (agent_unprotect): Decode the S2K count here and take
- care of the new unencoded values. Add a lower limit sanity check.
- (hash_passphrase): Do not decode here.
- (get_standard_s2k_count, calibrate_s2k_count): New.
- (calibrate_get_time, calibrate_elapsed_time): New.
- (do_encryption): Use get_standard_s2k_count.
-
-2009-12-08 Werner Koch
-
- * protect.c (agent_unprotect): Avoid compiler warning.
-
-2009-12-08 Marcus Brinkmann
-
- * call-pinentry.c (start_pinentry): Convert posix fd to assuan fd.
- * call-scd.c (start_scd): Likewise.
-
-2009-12-03 Werner Koch
-
- * gpg-agent.c (set_debug): Allow for numerical debug leveles. Print
- active debug flags.
+2010-02-11 Marcus Brinkmann
-2009-12-02 Werner Koch
+ From trunk 2009-09-23, 2009-11-02, 2009-11-04, 2009-11-05, 2009-11-25,
+ 2009-12-08:
- * trustlist.c (read_trustfiles): Store the pointer returned from
- shrinking the memory and not the orginal one. Fixes bug#1163.
- Reported by TAKAHASHI Tamotsu. Also return correct error after
- memory failure.
-
-2009-11-27 Marcus Brinkmann
-
- * command.c (start_command_handler): Do not call
- assuan_set_log_stream anymore.
- * gpg-agent.c (main): But call assuan_set_assuan_log_stream here.
-
-2009-11-25 Marcus Brinkmann
-
- * command.c (start_command_handler): Use assuan_fd_t and
- assuan_fdopen on fds.
-
-2009-11-05 Marcus Brinkmann
-
- * call-pinentry.c (start_pinentry): Call assuan_pipe_connect, not
- assuan_pipe_connect_ext.
- * command.c (start_command_handler): Change
- assuan_init_socket_server_ext into assuan_init_socket_server.
- * call-scd.c (start_scd): Update use of assuan_socket_connect and
- assuan_pipe_connect.
- * gpg-agent.c (check_own_socket_thread, check_for_running_agent):
- Update use of assuan_socket_connect.
-
-2009-11-04 Werner Koch
-
- * command.c (register_commands): Add help arg to
- assuan_register_command. Convert all command comments to help
- strings.
-
-2009-11-02 Marcus Brinkmann
-
- * command.c (reset_notify): Take LINE arg and return error.
- (register_commands): Use assuan_handler_t type.
-
-2009-10-16 Marcus Brinkmann
-
- * gpg_agent_CFLAGS, gpg_agent_LDADD: Use libassuan instead of
- libassuan-pth.
+ * Makefile.am (gpg_agent_CFLAGS, gpg_agent_LDADD): Use libassuan
+ instead of libassuan-pth.
* gpg-agent.c: Invoke ASSUAN_SYSTEM_PTH_IMPL.
- (main): Call assuan_set_system_hooks and assuan_sock_init.
- Fix invocation of assuan_socket_connect.
-
-2009-09-23 Werner Koch
-
- * command.c (register_commands) [HAVE_ASSUAN_SET_IO_MONITOR]:
- Remove cpp condition.
- (start_command_handler) [HAVE_ASSUAN_SET_IO_MONITOR]: Ditto.
-
-2009-09-23 Marcus Brinkmann
-
- * gpg-agent.c (parse_rereadable_options): Don't set global assuan
- log file (there ain't one anymore).
- (main): Update to new API.
+ (main): Update to new API. Call assuan_set_system_hooks and
+ assuan_sock_init. Fix invocation of assuan_socket_connect.
+ Call assuan_set_assuan_log_stream here.
+ (parse_rereadable_options): Don't set global assuan log
+ file (there ain't one anymore).
(check_own_socket_pid_cb): Return gpg_error_t instead of int.
(check_own_socket_thread, check_for_running_agent): Create assuan
- context before connecting to server.
+ context before connecting to server. Update use of
+ assuan_socket_connect.
* command.c: Include "scdaemon.h" before because of
GPG_ERR_SOURCE_DEFAULT check.
(write_and_clear_outbuf): Use gpg_error_t instead of
@@ -671,19 +146,58 @@
(post_cmd_notify): Change type of ERR to gpg_error_t from int.
(io_monitor): Add hook argument. Use symbols for constants.
(register_commands): Change return type of HANDLER to gpg_error_t.
+ Use assuan_handler_t type. Add NULL arg to assuan_register_command.
+ Add help arg to assuan_register_command. Convert all command
+ comments to help strings.
(start_command_handler): Allocate assuan context before starting
- server.
+ server. Change assuan_init_socket_server_ext into
+ assuan_init_socket_server. Use assuan_fd_t and assuan_fdopen on fds.
+ Do not call assuan_set_log_stream anymore.
+ (reset_notify): Take LINE arg and return error.
* call-pinentry.c: Include "scdaemon.h" before because
of GPG_ERR_SOURCE_DEFAULT check.
(unlock_pinentry): Call assuan_release instead of
assuan_disconnect.
(getinfo_pid_cb, getpin_cb): Return gpg_error_t instead of int.
(start_pinentry): Allocate assuan context before connecting to
- server.
+ server. Call assuan_pipe_connect, notassuan_pipe_connect_ext.
+ Convert posix fd to assuan fd.
* call-scd.c (membuf_data_cb, learn_status_cb, get_serialno_cb)
(membuf_data_cb, inq_needpin, card_getattr_cb, pass_status_thru)
(pass_data_thru): Change return type to gpg_error_t.
(start_scd): Allocate assuan context before connecting to server.
+ Update use of assuan_socket_connect and assuan_pipe_connect.
+ Convert posix fd to assuan fd.
+
+2010-01-26 Werner Koch
+
+ * protect.c (do_encryption): Encode the s2kcount and do not use a
+ static value of 96.
+
+2009-12-21 Werner Koch
+
+ * command.c (cmd_getinfo): Add sub-command "s2k_count".
+
+2009-12-14 Werner Koch
+
+ * protect.c (agent_unprotect): Decode the S2K count here and take
+ care of the new unencoded values. Add a lower limit sanity check.
+ (hash_passphrase): Do not decode here.
+ (get_standard_s2k_count, calibrate_s2k_count): New.
+ (calibrate_get_time, calibrate_elapsed_time): New.
+ (do_encryption): Use get_standard_s2k_count.
+
+2009-12-03 Werner Koch
+
+ * gpg-agent.c (set_debug): Allow for numerical debug leveles. Print
+ active debug flags.
+
+2009-12-02 Werner Koch
+
+ * trustlist.c (read_trustfiles): Store the pointer returned from
+ shrinking the memory and not the orginal one. Fixes bug#1163.
+ Reported by TAKAHASHI Tamotsu. Also return correct error after
+ memory failure.
2009-09-04 Marcus Brinkmann
@@ -3092,7 +2606,7 @@
Copyright 2001, 2002, 2003, 2004, 2005,
- 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+ 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without
@@ -3101,7 +2615,3 @@
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-Local Variables:
-buffer-read-only: t
-End:
diff -Nru gnupg2-2.1.6~build1/agent/command.c gnupg2-2.0.28/agent/command.c
--- gnupg2-2.1.6~build1/agent/command.c 2015-06-29 19:28:59.000000000 +0000
+++ gnupg2-2.0.28/agent/command.c 2015-06-02 08:13:55.000000000 +0000
@@ -1,7 +1,7 @@
/* command.c - gpg-agent command handler
- * Copyright (C) 2001-2011 Free Software Foundation, Inc.
- * Copyright (C) 2001-2013 Werner Koch
- * Copyright (C) 2015 g10 Code GmbH.
+ * Copyright (C) 2001, 2002, 2003, 2004, 2005,
+ * 2006, 2008, 2009 Free Software Foundation, Inc.
+ * Copyright (C) 2013 Werner Koch
*
* This file is part of GnuPG.
*
@@ -38,71 +38,33 @@
#include "agent.h"
#include
#include "i18n.h"
-#include "cvt-openpgp.h"
#include "../common/ssh-utils.h"
-#include "../common/asshelp.h"
-
-/* Maximum allowed size of the inquired ciphertext. */
+/* maximum allowed size of the inquired ciphertext */
#define MAXLEN_CIPHERTEXT 4096
-/* Maximum allowed size of the key parameters. */
+/* maximum allowed size of the key parameters */
#define MAXLEN_KEYPARAM 1024
-/* Maximum allowed size of key data as used in inquiries (bytes). */
-#define MAXLEN_KEYDATA 4096
-/* The size of the import/export KEK key (in bytes). */
-#define KEYWRAP_KEYSIZE (128/8)
-/* A shortcut to call assuan_set_error using an gpg_err_code_t and a
- text string. */
#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
-/* Check that the maximum digest length we support has at least the
- length of the keygrip. */
+
#if MAX_DIGEST_LEN < 20
#error MAX_DIGEST_LEN shorter than keygrip
#endif
-/* Data used to associate an Assuan context with local server data.
- This is this modules local part of the server_control_s struct. */
+/* Data used to associate an Assuan context with local server data */
struct server_local_s
{
- /* Our Assuan context. */
assuan_context_t assuan_ctx;
-
- /* If this flag is true, the passphrase cache is used for signing
- operations. It defaults to true but may be set on a per
- connection base. The global option opt.ignore_cache_for_signing
- takes precedence over this flag. */
+ int message_fd;
int use_cache_for_signing;
-
- /* An allocated description for the next key operation. This is
- used if a pinnetry needs to be popped up. */
- char *keydesc;
-
- /* Flags to suppress I/O logging during a command. */
- int pause_io_logging;
-
- /* If this flags is set to true the agent will be terminated after
- the end of the current session. */
- int stopme;
-
- /* Flag indicating whether pinentry notifications shall be done. */
- int allow_pinentry_notify;
-
- /* Malloced KEK (Key-Encryption-Key) for the import_key command. */
- void *import_key;
-
- /* Malloced KEK for the export_key command. */
- void *export_key;
-
- /* Client is aware of the error code GPG_ERR_FULLY_CANCELED. */
- int allow_fully_canceled;
-
- /* Last CACHE_NONCE sent as status (malloced). */
- char *last_cache_nonce;
-
- /* Last PASSWD_NONCE sent as status (malloced). */
- char *last_passwd_nonce;
+ char *keydesc; /* Allocated description for the next key
+ operation. */
+ int pause_io_logging; /* Used to suppress I/O logging during a command */
+ int stopme; /* If set to true the agent will be terminated after
+ the end of this session. */
+ int allow_pinentry_notify; /* Set if pinentry notifications should
+ be done. */
};
@@ -159,7 +121,7 @@
p = get_membuf (mb, &n);
if (p)
{
- wipememory (p, n);
+ memset (p, 0, n);
xfree (p);
}
}
@@ -184,31 +146,6 @@
}
-/* Clear the nonces used to enable the passphrase cache for certain
- multi-command command sequences. */
-static void
-clear_nonce_cache (ctrl_t ctrl)
-{
- if (ctrl->server_local->last_cache_nonce)
- {
- agent_put_cache (ctrl->server_local->last_cache_nonce,
- CACHE_MODE_NONCE, NULL, 0);
- xfree (ctrl->server_local->last_cache_nonce);
- ctrl->server_local->last_cache_nonce = NULL;
- }
- if (ctrl->server_local->last_passwd_nonce)
- {
- agent_put_cache (ctrl->server_local->last_passwd_nonce,
- CACHE_MODE_NONCE, NULL, 0);
- xfree (ctrl->server_local->last_passwd_nonce);
- ctrl->server_local->last_passwd_nonce = NULL;
- }
-}
-
-
-/* This function is called by Libassuan whenever thee client sends a
- reset. It has been registered similar to the other Assuan
- commands. */
static gpg_error_t
reset_notify (assuan_context_t ctx, char *line)
{
@@ -222,40 +159,11 @@
xfree (ctrl->server_local->keydesc);
ctrl->server_local->keydesc = NULL;
-
- clear_nonce_cache (ctrl);
-
return 0;
}
-/* Skip over options in LINE.
-
- Blanks after the options are also removed. Options are indicated
- by two leading dashes followed by a string consisting of non-space
- characters. The special option "--" indicates an explicit end of
- options; all what follows will not be considered an option. The
- first no-option string also indicates the end of option parsing. */
-static char *
-skip_options (const char *line)
-{
- while (spacep (line))
- line++;
- while ( *line == '-' && line[1] == '-' )
- {
- while (*line && !spacep (line))
- line++;
- while (spacep (line))
- line++;
- }
- return (char*)line;
-}
-
-
-/* Check whether the option NAME appears in LINE. An example for a
- line with options is:
- --algo=42 --data foo bar
- This function would then only return true if NAME is "data". */
+/* Check whether the option NAME appears in LINE */
static int
has_option (const char *line, const char *name)
{
@@ -263,12 +171,9 @@
int n = strlen (name);
s = strstr (line, name);
- if (s && s >= skip_options (line))
- return 0;
return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
}
-
/* Same as has_option but does only test for the name of the option
and ignores an argument, i.e. with NAME being "--hash" it would
return true for "--hash" as well as for "--hash=foo". */
@@ -279,15 +184,12 @@
int n = strlen (name);
s = strstr (line, name);
- if (s && s >= skip_options (line))
- return 0;
return (s && (s == line || spacep (s-1))
&& (!s[n] || spacep (s+n) || s[n] == '='));
}
-
/* Return a pointer to the argument of the option with NAME. If such
- an option is not given, NULL is retruned. */
+ an option is not given, it returns NULL. */
static char *
option_value (const char *line, const char *name)
{
@@ -295,8 +197,6 @@
int n = strlen (name);
s = strstr (line, name);
- if (s && s >= skip_options (line))
- return NULL;
if (s && (s == line || spacep (s-1))
&& s[n] && (spacep (s+n) || s[n] == '='))
{
@@ -309,7 +209,24 @@
}
-/* Replace all '+' by a blank in the string S. */
+/* Skip over options. It is assumed that leading spaces have been
+ removed (this is the case for lines passed to a handler from
+ assuan). Blanks after the options are also removed. */
+static char *
+skip_options (char *line)
+{
+ while ( *line == '-' && line[1] == '-' )
+ {
+ while (*line && !spacep (line))
+ line++;
+ while (spacep (line))
+ line++;
+ }
+ return line;
+}
+
+
+/* Replace all '+' by a blank. */
static void
plus_to_blank (char *s)
{
@@ -340,9 +257,8 @@
return 0;
}
-
/* Parse the keygrip in STRING into the provided buffer BUF. BUF must
- provide space for 20 bytes. BUF is not changed if the function
+ provide space for 20 bytes. BUF is not changed if the function
returns an error. */
static int
parse_keygrip (assuan_context_t ctx, const char *string, unsigned char *buf)
@@ -364,11 +280,7 @@
}
-/* Write an Assuan status line. KEYWORD is the first item on the
- status line. The following arguments are all separated by a space
- in the output. The last argument must be a NULL. Linefeeds and
- carriage returns characters (which are not allowed in an Assuan
- status line) are silently quoted in C-style. */
+/* Write an assuan status line. */
gpg_error_t
agent_write_status (ctrl_t ctrl, const char *keyword, ...)
{
@@ -414,22 +326,6 @@
}
-/* This function is similar to print_assuan_status but takes a CTRL
- arg instead of an assuan context as first argument. */
-gpg_error_t
-agent_print_status (ctrl_t ctrl, const char *keyword, const char *format, ...)
-{
- gpg_error_t err;
- va_list arg_ptr;
- assuan_context_t ctx = ctrl->server_local->assuan_ctx;
-
- va_start (arg_ptr, format);
- err = vprint_assuan_status (ctx, keyword, format, arg_ptr);
- va_end (arg_ptr);
- return err;
-}
-
-
/* Helper to notify the client about a launched Pinentry. Because
that might disturb some older clients, this is only done if enabled
via an option. Returns an gpg error code. */
@@ -446,42 +342,6 @@
}
-/* Helper to print a message while leaving a command. */
-static gpg_error_t
-leave_cmd (assuan_context_t ctx, gpg_error_t err)
-{
- if (err)
- {
- const char *name = assuan_get_command_name (ctx);
- if (!name)
- name = "?";
-
- /* Not all users of gpg-agent know about the fully canceled
- error code; map it back if needed. */
- if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
- {
- ctrl_t ctrl = assuan_get_pointer (ctx);
-
- if (!ctrl->server_local->allow_fully_canceled)
- err = gpg_err_make (gpg_err_source (err), GPG_ERR_CANCELED);
- }
-
- /* Most code from common/ does not know the error source, thus
- we fix this here. */
- if (gpg_err_source (err) == GPG_ERR_SOURCE_UNKNOWN)
- err = gpg_err_make (GPG_ERR_SOURCE_DEFAULT, gpg_err_code (err));
-
- if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
- log_error ("command '%s' failed: %s\n", name,
- gpg_strerror (err));
- else
- log_error ("command '%s' failed: %s <%s>\n", name,
- gpg_strerror (err), gpg_strsource (err));
- }
- return err;
-}
-
-
static const char hlp_geteventcounter[] =
"GETEVENTCOUNTER\n"
@@ -500,16 +360,21 @@
cmd_geteventcounter (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
+ char any_counter[25];
+ char key_counter[25];
+ char card_counter[25];
(void)line;
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
- return agent_print_status (ctrl, "EVENTCOUNTER", "%u %u %u",
- eventcounter.any,
- eventcounter.key,
- eventcounter.card);
+ snprintf (any_counter, sizeof any_counter, "%u", eventcounter.any);
+ snprintf (key_counter, sizeof key_counter, "%u", eventcounter.key);
+ snprintf (card_counter, sizeof card_counter, "%u", eventcounter.card);
+
+ return agent_write_status (ctrl, "EVENTCOUNTER",
+ any_counter,
+ key_counter,
+ card_counter,
+ NULL);
}
@@ -523,7 +388,6 @@
eventcounter.any++;
}
-
/* This function should be called for all card reader status
changes. This function is assured not to do any context
switches. */
@@ -570,7 +434,10 @@
else if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF )
return gpg_error (GPG_ERR_NOT_TRUSTED);
else
- return leave_cmd (ctx, rc);
+ {
+ log_error ("command is_trusted failed: %s\n", gpg_strerror (rc));
+ return rc;
+ }
}
@@ -581,16 +448,14 @@
static gpg_error_t
cmd_listtrusted (assuan_context_t ctx, char *line)
{
- ctrl_t ctrl = assuan_get_pointer (ctx);
int rc;
(void)line;
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
rc = agent_listtrusted (ctx);
- return leave_cmd (ctx, rc);
+ if (rc)
+ log_error ("command listtrusted failed: %s\n", gpg_strerror (rc));
+ return rc;
}
@@ -607,9 +472,6 @@
char fpr[41];
int flag;
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
/* parse the fingerprint value */
for (p=line,n=0; hexdigitp (p); p++, n++)
;
@@ -634,42 +496,32 @@
p++;
rc = agent_marktrusted (ctrl, p, fpr, flag);
- return leave_cmd (ctx, rc);
+ if (rc)
+ log_error ("command marktrusted failed: %s\n", gpg_strerror (rc));
+ return rc;
}
static const char hlp_havekey[] =
- "HAVEKEY \n"
+ "HAVEKEY \n"
"\n"
- "Return success if at least one of the secret keys with the given\n"
- "keygrips is available.";
+ "Return success when the secret key is available.";
static gpg_error_t
cmd_havekey (assuan_context_t ctx, char *line)
{
- gpg_error_t err;
+ int rc;
unsigned char buf[20];
- do
- {
- err = parse_keygrip (ctx, line, buf);
- if (err)
- return err;
-
- if (!agent_key_available (buf))
- return 0; /* Found. */
+ rc = parse_keygrip (ctx, line, buf);
+ if (rc)
+ return rc;
- while (*line && *line != ' ' && *line != '\t')
- line++;
- while (*line == ' ' || *line == '\t')
- line++;
- }
- while (*line);
+ if (agent_key_available (buf))
+ return gpg_error (GPG_ERR_NO_SECKEY);
- /* No leave_cmd() here because errors are expected and would clutter
- the log. */
- return gpg_error (GPG_ERR_NO_SECKEY);
+ return 0;
}
@@ -695,8 +547,8 @@
static const char hlp_setkeydesc[] =
"SETKEYDESC plus_percent_escaped_string\n"
"\n"
- "Set a description to be used for the next PKSIGN, PKDECRYPT, IMPORT_KEY\n"
- "or EXPORT_KEY operation if this operation requires a passphrase. If\n"
+ "Set a description to be used for the next PKSIGN or PKDECRYPT\n"
+ "operation if this operation requires the entry of a passphrase. If\n"
"this command is not used a default text will be used. Note, that\n"
"this description implictly selects the label used for the entry\n"
"box; if the string contains the string PIN (which in general will\n"
@@ -704,8 +556,8 @@
"\"passphrase\" is used. The description string should not contain\n"
"blanks unless they are percent or '+' escaped.\n"
"\n"
- "The description is only valid for the next PKSIGN, PKDECRYPT,\n"
- "IMPORT_KEY, EXPORT_KEY, or DELETE_KEY operation.";
+ "The description is only valid for the next PKSIGN or PKDECRYPT\n"
+ "operation.";
static gpg_error_t
cmd_setkeydesc (assuan_context_t ctx, char *line)
{
@@ -719,7 +571,7 @@
if (p)
*p = 0; /* We ignore any garbage; we might late use it for other args. */
- if (!*desc)
+ if (!desc || !*desc)
return set_error (GPG_ERR_ASS_PARAMETER, "no description given");
/* Note, that we only need to replace the + characters and should
@@ -729,16 +581,7 @@
plus_to_blank (desc);
xfree (ctrl->server_local->keydesc);
-
- if (ctrl->restricted)
- {
- ctrl->server_local->keydesc = strconcat
- ((ctrl->restricted == 2
- ? _("Note: Request from the web browser.")
- : _("Note: Request from a remote site.") ), "%0A%0A", desc, NULL);
- }
- else
- ctrl->server_local->keydesc = xtrystrdup (desc);
+ ctrl->server_local->keydesc = xtrystrdup (desc);
if (!ctrl->server_local->keydesc)
return out_of_core ();
return 0;
@@ -746,7 +589,7 @@
static const char hlp_sethash[] =
- "SETHASH (--hash=)|() \n"
+ "SETHASH --hash=| \n"
"\n"
"The client can use this command to tell the server about the data\n"
"(which usually is a hash) to be signed.";
@@ -799,7 +642,6 @@
return set_error (GPG_ERR_UNSUPPORTED_ALGORITHM, NULL);
}
ctrl->digest.algo = algo;
- ctrl->digest.raw_value = 0;
/* Parse the hash value. */
n = 0;
@@ -827,7 +669,7 @@
static const char hlp_pksign[] =
- "PKSIGN [] []\n"
+ "PKSIGN [options]\n"
"\n"
"Perform the actual sign operation. Neither input nor output are\n"
"sensitive to eavesdropping.";
@@ -838,17 +680,8 @@
cache_mode_t cache_mode = CACHE_MODE_NORMAL;
ctrl_t ctrl = assuan_get_pointer (ctx);
membuf_t outbuf;
- char *cache_nonce = NULL;
- char *p;
-
- line = skip_options (line);
- p = line;
- for (p=line; *p && *p != ' ' && *p != '\t'; p++)
- ;
- *p = '\0';
- if (*line)
- cache_nonce = xtrystrdup (line);
+ (void)line;
if (opt.ignore_cache_for_signing)
cache_mode = CACHE_MODE_IGNORE;
@@ -857,22 +690,22 @@
init_membuf (&outbuf, 512);
- rc = agent_pksign (ctrl, cache_nonce, ctrl->server_local->keydesc,
+ rc = agent_pksign (ctrl, ctrl->server_local->keydesc,
&outbuf, cache_mode);
if (rc)
clear_outbuf (&outbuf);
else
rc = write_and_clear_outbuf (ctx, &outbuf);
-
- xfree (cache_nonce);
+ if (rc)
+ log_error ("command pksign failed: %s\n", gpg_strerror (rc));
xfree (ctrl->server_local->keydesc);
ctrl->server_local->keydesc = NULL;
- return leave_cmd (ctx, rc);
+ return rc;
}
static const char hlp_pkdecrypt[] =
- "PKDECRYPT []\n"
+ "PKDECRYPT \n"
"\n"
"Perform the actual decrypt operation. Input is not\n"
"sensitive to eavesdropping.";
@@ -884,136 +717,73 @@
unsigned char *value;
size_t valuelen;
membuf_t outbuf;
- int padding;
(void)line;
/* First inquire the data to decrypt */
- rc = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%u", MAXLEN_CIPHERTEXT);
- if (!rc)
- rc = assuan_inquire (ctx, "CIPHERTEXT",
- &value, &valuelen, MAXLEN_CIPHERTEXT);
+ rc = assuan_inquire (ctx, "CIPHERTEXT",
+ &value, &valuelen, MAXLEN_CIPHERTEXT);
if (rc)
return rc;
init_membuf (&outbuf, 512);
rc = agent_pkdecrypt (ctrl, ctrl->server_local->keydesc,
- value, valuelen, &outbuf, &padding);
+ value, valuelen, &outbuf);
xfree (value);
if (rc)
clear_outbuf (&outbuf);
else
- {
- if (padding != -1)
- rc = print_assuan_status (ctx, "PADDING", "%d", padding);
- else
- rc = 0;
- if (!rc)
- rc = write_and_clear_outbuf (ctx, &outbuf);
- }
+ rc = write_and_clear_outbuf (ctx, &outbuf);
+ if (rc)
+ log_error ("command pkdecrypt failed: %s\n", gpg_strerror (rc));
xfree (ctrl->server_local->keydesc);
ctrl->server_local->keydesc = NULL;
- return leave_cmd (ctx, rc);
+ return rc;
}
static const char hlp_genkey[] =
- "GENKEY [--no-protection] [--preset] [--inq-passwd] []\n"
+ "GENKEY\n"
"\n"
"Generate a new key, store the secret part and return the public\n"
"part. Here is an example transaction:\n"
"\n"
" C: GENKEY\n"
" S: INQUIRE KEYPARAM\n"
- " C: D (genkey (rsa (nbits 2048)))\n"
+ " C: D (genkey (rsa (nbits 1024)))\n"
" C: END\n"
" S: D (public-key\n"
" S: D (rsa (n 326487324683264) (e 10001)))\n"
" S: OK key created\n"
- "\n"
- "When the --preset option is used the passphrase for the generated\n"
- "key will be added to the cache. When --inq-passwd is used an inquire\n"
- "with the keyword NEWPASSWD is used to request the passphrase for the\n"
- "new key.\n";
+ "\n";
static gpg_error_t
cmd_genkey (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
int rc;
- int no_protection;
unsigned char *value;
size_t valuelen;
- unsigned char *newpasswd = NULL;
membuf_t outbuf;
- char *cache_nonce = NULL;
- int opt_preset;
- int opt_inq_passwd;
- size_t n;
- char *p;
-
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
- no_protection = has_option (line, "--no-protection");
- opt_preset = has_option (line, "--preset");
- opt_inq_passwd = has_option (line, "--inq-passwd");
- line = skip_options (line);
- p = line;
- for (p=line; *p && *p != ' ' && *p != '\t'; p++)
- ;
- *p = '\0';
- if (*line)
- cache_nonce = xtrystrdup (line);
+ (void)line;
/* First inquire the parameters */
- rc = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%u", MAXLEN_KEYPARAM);
- if (!rc)
- rc = assuan_inquire (ctx, "KEYPARAM", &value, &valuelen, MAXLEN_KEYPARAM);
+ rc = assuan_inquire (ctx, "KEYPARAM", &value, &valuelen, MAXLEN_KEYPARAM);
if (rc)
return rc;
init_membuf (&outbuf, 512);
- /* If requested, ask for the password to be used for the key. If
- this is not used the regular Pinentry mechanism is used. */
- if (opt_inq_passwd && !no_protection)
- {
- /* (N is used as a dummy) */
- assuan_begin_confidential (ctx);
- rc = assuan_inquire (ctx, "NEWPASSWD", &newpasswd, &n, 256);
- assuan_end_confidential (ctx);
- if (rc)
- goto leave;
- if (!*newpasswd)
- {
- /* Empty password given - switch to no-protection mode. */
- xfree (newpasswd);
- newpasswd = NULL;
- no_protection = 1;
- }
-
- }
-
- rc = agent_genkey (ctrl, cache_nonce, (char*)value, valuelen, no_protection,
- newpasswd, opt_preset, &outbuf);
-
- leave:
- if (newpasswd)
- {
- /* Assuan_inquire does not allow us to read into secure memory
- thus we need to wipe it ourself. */
- wipememory (newpasswd, strlen (newpasswd));
- xfree (newpasswd);
- }
+ rc = agent_genkey (ctrl, (char*)value, valuelen, &outbuf);
xfree (value);
if (rc)
clear_outbuf (&outbuf);
else
rc = write_and_clear_outbuf (ctx, &outbuf);
- xfree (cache_nonce);
- return leave_cmd (ctx, rc);
+ if (rc)
+ log_error ("command genkey failed: %s\n", gpg_strerror (rc));
+ return rc;
}
@@ -1031,9 +801,6 @@
unsigned char grip[20];
gcry_sexp_t s_pkey = NULL;
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
rc = parse_keygrip (ctx, line, grip);
if (rc)
return rc; /* Return immediately as this is already an Assuan error code.*/
@@ -1059,7 +826,9 @@
gcry_sexp_release (s_pkey);
}
- return leave_cmd (ctx, rc);
+ if (rc)
+ log_error ("command readkey failed: %s\n", gpg_strerror (rc));
+ return rc;
}
@@ -1075,11 +844,11 @@
"information from sshcontrol is always added to the info. Unless --data\n"
"is given, the information is returned as a status line using the format:\n"
"\n"
- " KEYINFO \n"
+ " KEYINFO - - \n"
"\n"
"KEYGRIP is the keygrip.\n"
"\n"
- "TYPE is describes the type of the key:\n"
+ "TYPE describes the type of the key:\n"
" 'D' - Regular key stored on disk,\n"
" 'T' - Key is stored on a smartcard (token),\n"
" 'X' - Unknown type,\n"
@@ -1092,14 +861,6 @@
"IDSTR is the IDSTR used to distinguish keys on a smartcard. If it\n"
" is not known a dash is used instead.\n"
"\n"
- "CACHED is 1 if the passphrase for the key was found in the key cache.\n"
- " If not, a '-' is used instead.\n"
- "\n"
- "PROTECTION describes the key protection type:\n"
- " 'P' - The key is protected with a passphrase,\n"
- " 'C' - The key is not protected,\n"
- " '-' - Unknown protection.\n"
- "\n"
"FPR returns the formatted ssh-style fingerprint of the key. It is only\n"
" printed if the option --ssh-fpr has been used. It defaults to '-'.\n"
"\n"
@@ -1125,9 +886,6 @@
char *serialno = NULL;
char *idstr = NULL;
const char *keytypestr;
- const char *cached;
- const char *protectionstr;
- char *pw;
int missing_key = 0;
char ttlbuf[20];
char flagsbuf[5];
@@ -1162,21 +920,19 @@
if (missing_key)
{
- protectionstr = "-"; keytypestr = "-";
+ keytypestr = "-";
}
else
{
switch (keytype)
{
- case PRIVATE_KEY_CLEAR:
- case PRIVATE_KEY_OPENPGP_NONE:
- protectionstr = "C"; keytypestr = "D";
+ case PRIVATE_KEY_CLEAR: keytypestr = "D";
break;
- case PRIVATE_KEY_PROTECTED: protectionstr = "P"; keytypestr = "D";
+ case PRIVATE_KEY_PROTECTED: keytypestr = "D";
break;
- case PRIVATE_KEY_SHADOWED: protectionstr = "-"; keytypestr = "T";
+ case PRIVATE_KEY_SHADOWED: keytypestr = "T";
break;
- default: protectionstr = "-"; keytypestr = "X";
+ default: keytypestr = "X";
break;
}
}
@@ -1193,28 +949,24 @@
}
}
- /* Here we have a little race by doing the cache check separately
- from the retrieval function. Given that the cache flag is only a
- hint, it should not really matter. */
- pw = agent_get_cache (hexgrip, CACHE_MODE_NORMAL);
- cached = pw ? "1" : "-";
- xfree (pw);
-
if (shadow_info)
{
- err = parse_shadow_info (shadow_info, &serialno, &idstr, NULL);
+ err = parse_shadow_info (shadow_info, &serialno, &idstr);
if (err)
goto leave;
}
+ /* Note that we don't support the CACHED and PROTECTION values as
+ gnupg 2.1 does. We print '-' instead. However we support the
+ ssh fingerprint. */
if (!data)
err = agent_write_status (ctrl, "KEYINFO",
hexgrip,
keytypestr,
serialno? serialno : "-",
idstr? idstr : "-",
- cached,
- protectionstr,
+ "-",
+ "-",
fpr? fpr : "-",
ttlbuf,
flagsbuf,
@@ -1223,13 +975,14 @@
{
char *string;
- string = xtryasprintf ("%s %s %s %s %s %s %s %s %s\n",
+ string = xtryasprintf ("%s %s %s %s - - %s %s %s\n",
hexgrip, keytypestr,
serialno? serialno : "-",
- idstr? idstr : "-", cached, protectionstr,
+ idstr? idstr : "-",
fpr? fpr : "-",
ttlbuf,
flagsbuf);
+
if (!string)
err = gpg_error_from_syserror ();
else
@@ -1246,8 +999,6 @@
}
-/* Entry int for the command KEYINFO. This function handles the
- command option processing. For details see hlp_keyinfo above. */
static gpg_error_t
cmd_keyinfo (assuan_context_t ctx, char *line)
{
@@ -1261,9 +1012,6 @@
char hexgrip[41];
int disabled, ttl, confirm, is_ssh;
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
if (has_option (line, "--ssh-list"))
list_mode = 2;
else
@@ -1367,13 +1115,12 @@
if (dir)
closedir (dir);
if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND)
- leave_cmd (ctx, err);
+ log_error ("command keyinfo failed: %s\n", gpg_strerror (err));
return err;
}
-/* Helper for cmd_get_passphrase. */
static int
send_back_passphrase (assuan_context_t ctx, int via_data, const char *pw)
{
@@ -1432,17 +1179,15 @@
{
ctrl_t ctrl = assuan_get_pointer (ctx);
int rc;
- char *pw;
+ const char *pw;
char *response;
char *cacheid = NULL, *desc = NULL, *prompt = NULL, *errtext = NULL;
const char *desc2 = _("Please re-enter this passphrase");
char *p;
+ void *cache_marker;
int opt_data, opt_check, opt_no_ask, opt_qualbar;
int opt_repeat = 0;
- char *entry_errtext = NULL;
-
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
+ char *repeat_errtext = NULL;
opt_data = has_option (line, "--data");
opt_check = has_option (line, "--check");
@@ -1486,7 +1231,7 @@
}
}
}
- if (!*cacheid || strlen (cacheid) > 50)
+ if (!cacheid || !*cacheid || strlen (cacheid) > 50)
return set_error (GPG_ERR_ASS_PARAMETER, "invalid length of cacheID");
if (!desc)
return set_error (GPG_ERR_ASS_PARAMETER, "no description given");
@@ -1500,11 +1245,12 @@
if (!strcmp (desc, "X"))
desc = NULL;
- pw = cacheid ? agent_get_cache (cacheid, CACHE_MODE_USER) : NULL;
+ pw = cacheid ? agent_get_cache (cacheid, CACHE_MODE_USER, &cache_marker)
+ : NULL;
if (pw)
{
rc = send_back_passphrase (ctx, opt_data, pw);
- xfree (pw);
+ agent_unlock_cache_entry (&cache_marker);
}
else if (opt_no_ask)
rc = gpg_error (GPG_ERR_NO_DATA);
@@ -1523,16 +1269,15 @@
next_try:
rc = agent_get_passphrase (ctrl, &response, desc, prompt,
- entry_errtext? entry_errtext:errtext,
- opt_qualbar, cacheid, CACHE_MODE_USER);
- xfree (entry_errtext);
- entry_errtext = NULL;
+ repeat_errtext? repeat_errtext:errtext,
+ opt_qualbar, cacheid, CACHE_MODE_USER);
+ xfree (repeat_errtext);
+ repeat_errtext = NULL;
if (!rc)
{
int i;
- if (opt_check
- && check_passphrase_constraints (ctrl, response, &entry_errtext))
+ if (opt_check && check_passphrase_constraints (ctrl, response, 0))
{
xfree (response);
goto next_try;
@@ -1550,9 +1295,9 @@
{
xfree (response2);
xfree (response);
- entry_errtext = try_percent_escape
+ repeat_errtext = try_percent_escape
(_("does not match - try again"), NULL);
- if (!entry_errtext)
+ if (!repeat_errtext)
{
rc = gpg_error_from_syserror ();
break;
@@ -1571,30 +1316,23 @@
}
}
- return leave_cmd (ctx, rc);
+ if (rc)
+ log_error ("command get_passphrase failed: %s\n", gpg_strerror (rc));
+ return rc;
}
static const char hlp_clear_passphrase[] =
- "CLEAR_PASSPHRASE [--mode=normal] \n"
+ "CLEAR_PASSPHRASE \n"
"\n"
"may be used to invalidate the cache entry for a passphrase. The\n"
- "function returns with OK even when there is no cached passphrase.\n"
- "The --mode=normal option is used to clear an entry for a cacheid\n"
- "added by the agent.\n";
+ "function returns with OK even when there is no cached passphrase.";
static gpg_error_t
cmd_clear_passphrase (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
char *cacheid = NULL;
char *p;
- int opt_normal;
-
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
- opt_normal = has_option (line, "--mode=normal");
- line = skip_options (line);
/* parse the stuff */
for (p=line; *p == ' '; p++)
@@ -1603,14 +1341,12 @@
p = strchr (cacheid, ' ');
if (p)
*p = 0; /* ignore garbage */
- if (!*cacheid || strlen (cacheid) > 50)
+ if (!cacheid || !*cacheid || strlen (cacheid) > 50)
return set_error (GPG_ERR_ASS_PARAMETER, "invalid length of cacheID");
- agent_put_cache (cacheid, opt_normal ? CACHE_MODE_NORMAL : CACHE_MODE_USER,
- NULL, 0);
+ agent_put_cache (cacheid, CACHE_MODE_USER, NULL, 0);
- agent_clear_passphrase (ctrl, cacheid,
- opt_normal ? CACHE_MODE_NORMAL : CACHE_MODE_USER);
+ agent_clear_passphrase (ctrl, cacheid, CACHE_MODE_USER);
return 0;
}
@@ -1635,9 +1371,6 @@
char *desc = NULL;
char *p;
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
/* parse the stuff */
for (p=line; *p == ' '; p++)
;
@@ -1646,7 +1379,7 @@
if (p)
*p = 0; /* We ignore any garbage -may be later used for other args. */
- if (!*desc)
+ if (!desc || !*desc)
return set_error (GPG_ERR_ASS_PARAMETER, "no description given");
if (!strcmp (desc, "X"))
@@ -1660,222 +1393,96 @@
plus_to_blank (desc);
rc = agent_get_confirmation (ctrl, desc, NULL, NULL, 0);
- return leave_cmd (ctx, rc);
+ if (rc)
+ log_error ("command get_confirmation failed: %s\n", gpg_strerror (rc));
+ return rc;
}
static const char hlp_learn[] =
- "LEARN [--send] [--sendinfo] [--force]\n"
+ "LEARN [--send]\n"
"\n"
"Learn something about the currently inserted smartcard. With\n"
- "--sendinfo information about the card is returned; with --send\n"
- "the available certificates are returned as D lines; with --force\n"
- "private key storage will be updated by the result.";
+ "--send the new certificates are send back.";
static gpg_error_t
cmd_learn (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
- gpg_error_t err;
- int send, sendinfo, force;
-
- send = has_option (line, "--send");
- sendinfo = send? 1 : has_option (line, "--sendinfo");
- force = has_option (line, "--force");
-
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
+ int rc;
- err = agent_handle_learn (ctrl, send, sendinfo? ctx : NULL, force);
- return leave_cmd (ctx, err);
+ rc = agent_handle_learn (ctrl, has_option (line, "--send")? ctx : NULL);
+ if (rc)
+ log_error ("command learn failed: %s\n", gpg_strerror (rc));
+ return rc;
}
static const char hlp_passwd[] =
- "PASSWD [--cache-nonce=] [--passwd-nonce=] [--preset]\n"
- " [--verify] \n"
+ "PASSWD \n"
"\n"
- "Change the passphrase/PIN for the key identified by keygrip in LINE. If\n"
- "--preset is used then the new passphrase will be added to the cache.\n"
- "If --verify is used the command asks for the passphrase and verifies\n"
- "that the passphrase valid.\n";
+ "Change the passphrase/PIN for the key identified by keygrip in LINE.";
static gpg_error_t
cmd_passwd (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
- gpg_error_t err;
- int c;
- char *cache_nonce = NULL;
- char *passwd_nonce = NULL;
+ int rc;
unsigned char grip[20];
gcry_sexp_t s_skey = NULL;
unsigned char *shadow_info = NULL;
- char *passphrase = NULL;
- char *pend;
- int opt_preset, opt_verify;
-
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
- opt_preset = has_option (line, "--preset");
- cache_nonce = option_value (line, "--cache-nonce");
- opt_verify = has_option (line, "--verify");
- if (cache_nonce)
- {
- for (pend = cache_nonce; *pend && !spacep (pend); pend++)
- ;
- c = *pend;
- *pend = '\0';
- cache_nonce = xtrystrdup (cache_nonce);
- *pend = c;
- if (!cache_nonce)
- {
- err = gpg_error_from_syserror ();
- goto leave;
- }
- }
-
- passwd_nonce = option_value (line, "--passwd-nonce");
- if (passwd_nonce)
- {
- for (pend = passwd_nonce; *pend && !spacep (pend); pend++)
- ;
- c = *pend;
- *pend = '\0';
- passwd_nonce = xtrystrdup (passwd_nonce);
- *pend = c;
- if (!passwd_nonce)
- {
- err = gpg_error_from_syserror ();
- goto leave;
- }
- }
- line = skip_options (line);
-
- err = parse_keygrip (ctx, line, grip);
- if (err)
+ rc = parse_keygrip (ctx, line, grip);
+ if (rc)
goto leave;
ctrl->in_passwd++;
- err = agent_key_from_file (ctrl,
- opt_verify? NULL : cache_nonce,
- ctrl->server_local->keydesc,
- grip, &shadow_info, CACHE_MODE_IGNORE, NULL,
- &s_skey, &passphrase);
- if (err)
+ rc = agent_key_from_file (ctrl, ctrl->server_local->keydesc,
+ grip, &shadow_info, CACHE_MODE_IGNORE, NULL,
+ &s_skey);
+ if (rc)
;
- else if (shadow_info)
+ else if (!s_skey)
{
log_error ("changing a smartcard PIN is not yet supported\n");
- err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
- }
- else if (opt_verify)
- {
- /* All done. */
+ rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
}
else
- {
- char *newpass = NULL;
-
- if (passwd_nonce)
- newpass = agent_get_cache (passwd_nonce, CACHE_MODE_NONCE);
- err = agent_protect_and_store (ctrl, s_skey, &newpass);
- if (!err && passphrase)
- {
- /* A passphrase existed on the old key and the change was
- successful. Return a nonce for that old passphrase to
- let the caller try to unprotect the other subkeys with
- the same key. */
- if (!cache_nonce)
- {
- char buf[12];
- gcry_create_nonce (buf, 12);
- cache_nonce = bin2hex (buf, 12, NULL);
- }
- if (cache_nonce
- && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
- passphrase, CACHE_TTL_NONCE))
- {
- assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
- xfree (ctrl->server_local->last_cache_nonce);
- ctrl->server_local->last_cache_nonce = cache_nonce;
- cache_nonce = NULL;
- }
- if (newpass)
- {
- /* If we have a new passphrase (which might be empty) we
- store it under a passwd nonce so that the caller may
- send that nonce again to use it for another key. */
- if (!passwd_nonce)
- {
- char buf[12];
- gcry_create_nonce (buf, 12);
- passwd_nonce = bin2hex (buf, 12, NULL);
- }
- if (passwd_nonce
- && !agent_put_cache (passwd_nonce, CACHE_MODE_NONCE,
- newpass, CACHE_TTL_NONCE))
- {
- assuan_write_status (ctx, "PASSWD_NONCE", passwd_nonce);
- xfree (ctrl->server_local->last_passwd_nonce);
- ctrl->server_local->last_passwd_nonce = passwd_nonce;
- passwd_nonce = NULL;
- }
- }
- }
- if (!err && opt_preset)
- {
- char hexgrip[40+1];
- bin2hex(grip, 20, hexgrip);
- err = agent_put_cache (hexgrip, CACHE_MODE_ANY, newpass,
- ctrl->cache_ttl_opt_preset);
- }
- xfree (newpass);
- }
+ rc = agent_protect_and_store (ctrl, s_skey);
ctrl->in_passwd--;
xfree (ctrl->server_local->keydesc);
ctrl->server_local->keydesc = NULL;
leave:
- xfree (passphrase);
gcry_sexp_release (s_skey);
xfree (shadow_info);
- xfree (cache_nonce);
- return leave_cmd (ctx, err);
+ if (rc)
+ log_error ("command passwd failed: %s\n", gpg_strerror (rc));
+ return rc;
}
static const char hlp_preset_passphrase[] =
- "PRESET_PASSPHRASE [--inquire] []\n"
+ "PRESET_PASSPHRASE \n"
"\n"
"Set the cached passphrase/PIN for the key identified by the keygrip\n"
"to passwd for the given time, where -1 means infinite and 0 means\n"
"the default (currently only a timeout of -1 is allowed, which means\n"
"to never expire it). If passwd is not provided, ask for it via the\n"
- "pinentry module unless --inquire is passed in which case the passphrase\n"
- "is retrieved from the client via a server inquire.\n";
+ "pinentry module.";
static gpg_error_t
cmd_preset_passphrase (assuan_context_t ctx, char *line)
{
- ctrl_t ctrl = assuan_get_pointer (ctx);
int rc;
char *grip_clear = NULL;
- unsigned char *passphrase = NULL;
+ char *passphrase = NULL;
int ttl;
size_t len;
- int opt_inquire;
-
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
if (!opt.allow_preset_passphrase)
return set_error (GPG_ERR_NOT_SUPPORTED, "no --allow-preset-passphrase");
- opt_inquire = has_option (line, "--inquire");
- line = skip_options (line);
grip_clear = line;
while (*line && (*line != ' ' && *line != '\t'))
line++;
@@ -1906,40 +1513,21 @@
required. */
if (*line)
{
- if (opt_inquire)
- {
- rc = set_error (GPG_ERR_ASS_PARAMETER,
- "both --inquire and passphrase specified");
- goto leave;
- }
-
/* Do in-place conversion. */
passphrase = line;
if (!hex2str (passphrase, passphrase, strlen (passphrase)+1, NULL))
rc = set_error (GPG_ERR_ASS_PARAMETER, "invalid hexstring");
}
- else if (opt_inquire)
- {
- /* Note that the passphrase will be truncated at any null byte and the
- * limit is 480 characters. */
- size_t maxlen = 480;
-
- rc = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%zu", maxlen);
- if (!rc)
- rc = assuan_inquire (ctx, "PASSPHRASE", &passphrase, &len, maxlen);
- }
else
rc = set_error (GPG_ERR_NOT_IMPLEMENTED, "passphrase is required");
if (!rc)
- {
- rc = agent_put_cache (grip_clear, CACHE_MODE_ANY, passphrase, ttl);
- if (opt_inquire)
- xfree (passphrase);
- }
+ rc = agent_put_cache (grip_clear, CACHE_MODE_ANY, passphrase, ttl);
-leave:
- return leave_cmd (ctx, rc);
+ if (rc)
+ log_error ("command preset_passphrase failed: %s\n", gpg_strerror (rc));
+
+ return rc;
}
@@ -1955,9 +1543,6 @@
ctrl_t ctrl = assuan_get_pointer (ctx);
int rc;
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
rc = divert_generic_cmd (ctrl, line, ctx);
return rc;
@@ -1965,583 +1550,24 @@
-static const char hlp_keywrap_key[] =
- "KEYWRAP_KEY [--clear] \n"
+static const char hlp_getval[] =
+ "GETVAL \n"
"\n"
- "Return a key to wrap another key. For now the key is returned\n"
- "verbatim and and thus makes not much sense because an eavesdropper on\n"
- "the gpg-agent connection will see the key as well as the wrapped key.\n"
- "However, this function may either be equipped with a public key\n"
- "mechanism or not used at all if the key is a pre-shared key. In any\n"
- "case wrapping the import and export of keys is a requirement for\n"
- "certain cryptographic validations and thus useful. The key persists\n"
- "a RESET command but may be cleared using the option --clear.\n"
- "\n"
- "Supported modes are:\n"
- " --import - Return a key to import a key into gpg-agent\n"
- " --export - Return a key to export a key from gpg-agent";
+ "Return the value for KEY from the special environment as created by\n"
+ "PUTVAL.";
static gpg_error_t
-cmd_keywrap_key (assuan_context_t ctx, char *line)
+cmd_getval (assuan_context_t ctx, char *line)
{
- ctrl_t ctrl = assuan_get_pointer (ctx);
- gpg_error_t err = 0;
- int clearopt = has_option (line, "--clear");
-
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
+ int rc = 0;
+ char *key = NULL;
+ char *p;
+ struct putval_item_s *vl;
- assuan_begin_confidential (ctx);
- if (has_option (line, "--import"))
- {
- xfree (ctrl->server_local->import_key);
- if (clearopt)
- ctrl->server_local->import_key = NULL;
- else if (!(ctrl->server_local->import_key =
- gcry_random_bytes (KEYWRAP_KEYSIZE, GCRY_STRONG_RANDOM)))
- err = gpg_error_from_syserror ();
- else
- err = assuan_send_data (ctx, ctrl->server_local->import_key,
- KEYWRAP_KEYSIZE);
- }
- else if (has_option (line, "--export"))
- {
- xfree (ctrl->server_local->export_key);
- if (clearopt)
- ctrl->server_local->export_key = NULL;
- else if (!(ctrl->server_local->export_key =
- gcry_random_bytes (KEYWRAP_KEYSIZE, GCRY_STRONG_RANDOM)))
- err = gpg_error_from_syserror ();
- else
- err = assuan_send_data (ctx, ctrl->server_local->export_key,
- KEYWRAP_KEYSIZE);
- }
- else
- err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for MODE");
- assuan_end_confidential (ctx);
-
- return leave_cmd (ctx, err);
-}
-
-
-
-static const char hlp_import_key[] =
- "IMPORT_KEY [--unattended] []\n"
- "\n"
- "Import a secret key into the key store. The key is expected to be\n"
- "encrypted using the current session's key wrapping key (cf. command\n"
- "KEYWRAP_KEY) using the AESWRAP-128 algorithm. This function takes\n"
- "no arguments but uses the inquiry \"KEYDATA\" to ask for the actual\n"
- "key data. The unwrapped key must be a canonical S-expression. The\n"
- "option --unattended tries to import the key as-is without any\n"
- "re-encryption";
-static gpg_error_t
-cmd_import_key (assuan_context_t ctx, char *line)
-{
- ctrl_t ctrl = assuan_get_pointer (ctx);
- gpg_error_t err;
- int opt_unattended;
- unsigned char *wrappedkey = NULL;
- size_t wrappedkeylen;
- gcry_cipher_hd_t cipherhd = NULL;
- unsigned char *key = NULL;
- size_t keylen, realkeylen;
- char *passphrase = NULL;
- unsigned char *finalkey = NULL;
- size_t finalkeylen;
- unsigned char grip[20];
- gcry_sexp_t openpgp_sexp = NULL;
- char *cache_nonce = NULL;
- char *p;
-
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
- if (!ctrl->server_local->import_key)
- {
- err = gpg_error (GPG_ERR_MISSING_KEY);
- goto leave;
- }
-
- opt_unattended = has_option (line, "--unattended");
- line = skip_options (line);
-
- p = line;
- for (p=line; *p && *p != ' ' && *p != '\t'; p++)
- ;
- *p = '\0';
- if (*line)
- cache_nonce = xtrystrdup (line);
-
- assuan_begin_confidential (ctx);
- err = assuan_inquire (ctx, "KEYDATA",
- &wrappedkey, &wrappedkeylen, MAXLEN_KEYDATA);
- assuan_end_confidential (ctx);
- if (err)
- goto leave;
- if (wrappedkeylen < 24)
- {
- err = gpg_error (GPG_ERR_INV_LENGTH);
- goto leave;
- }
- keylen = wrappedkeylen - 8;
- key = xtrymalloc_secure (keylen);
- if (!key)
- {
- err = gpg_error_from_syserror ();
- goto leave;
- }
-
- err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
- GCRY_CIPHER_MODE_AESWRAP, 0);
- if (err)
- goto leave;
- err = gcry_cipher_setkey (cipherhd,
- ctrl->server_local->import_key, KEYWRAP_KEYSIZE);
- if (err)
- goto leave;
- err = gcry_cipher_decrypt (cipherhd, key, keylen, wrappedkey, wrappedkeylen);
- if (err)
- goto leave;
- gcry_cipher_close (cipherhd);
- cipherhd = NULL;
- xfree (wrappedkey);
- wrappedkey = NULL;
-
- realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err);
- if (!realkeylen)
- goto leave; /* Invalid canonical encoded S-expression. */
-
- err = keygrip_from_canon_sexp (key, realkeylen, grip);
- if (err)
- {
- /* This might be due to an unsupported S-expression format.
- Check whether this is openpgp-private-key and trigger that
- import code. */
- if (!gcry_sexp_sscan (&openpgp_sexp, NULL, key, realkeylen))
- {
- const char *tag;
- size_t taglen;
-
- tag = gcry_sexp_nth_data (openpgp_sexp, 0, &taglen);
- if (tag && taglen == 19 && !memcmp (tag, "openpgp-private-key", 19))
- ;
- else
- {
- gcry_sexp_release (openpgp_sexp);
- openpgp_sexp = NULL;
- }
- }
- if (!openpgp_sexp)
- goto leave; /* Note that ERR is still set. */
- }
-
-
- if (openpgp_sexp)
- {
- /* In most cases the key is encrypted and thus the conversion
- function from the OpenPGP format to our internal format will
- ask for a passphrase. That passphrase will be returned and
- used to protect the key using the same code as for regular
- key import. */
-
- xfree (key);
- key = NULL;
- err = convert_from_openpgp (ctrl, openpgp_sexp, grip,
- ctrl->server_local->keydesc, cache_nonce,
- &key, opt_unattended? NULL : &passphrase);
- if (err)
- goto leave;
- realkeylen = gcry_sexp_canon_len (key, 0, NULL, &err);
- if (!realkeylen)
- goto leave; /* Invalid canonical encoded S-expression. */
- if (passphrase)
- {
- assert (!opt_unattended);
- if (!cache_nonce)
- {
- char buf[12];
- gcry_create_nonce (buf, 12);
- cache_nonce = bin2hex (buf, 12, NULL);
- }
- if (cache_nonce
- && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
- passphrase, CACHE_TTL_NONCE))
- assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
- }
- }
- else if (opt_unattended)
- {
- err = set_error (GPG_ERR_ASS_PARAMETER,
- "\"--unattended\" may only be used with OpenPGP keys");
- goto leave;
- }
- else
- {
- if (!agent_key_available (grip))
- err = gpg_error (GPG_ERR_EEXIST);
- else
- {
- char *prompt = xtryasprintf
- (_("Please enter the passphrase to protect the "
- "imported object within the %s system."), GNUPG_NAME);
- if (!prompt)
- err = gpg_error_from_syserror ();
- else
- err = agent_ask_new_passphrase (ctrl, prompt, &passphrase);
- xfree (prompt);
- }
- if (err)
- goto leave;
- }
-
- if (passphrase)
- {
- err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
- ctrl->s2k_count);
- if (!err)
- err = agent_write_private_key (grip, finalkey, finalkeylen, 0);
- }
- else
- err = agent_write_private_key (grip, key, realkeylen, 0);
-
- leave:
- gcry_sexp_release (openpgp_sexp);
- xfree (finalkey);
- xfree (passphrase);
- xfree (key);
- gcry_cipher_close (cipherhd);
- xfree (wrappedkey);
- xfree (cache_nonce);
- xfree (ctrl->server_local->keydesc);
- ctrl->server_local->keydesc = NULL;
- return leave_cmd (ctx, err);
-}
-
-
-
-static const char hlp_export_key[] =
- "EXPORT_KEY [--cache-nonce=] [--openpgp] \n"
- "\n"
- "Export a secret key from the key store. The key will be encrypted\n"
- "using the current session's key wrapping key (cf. command KEYWRAP_KEY)\n"
- "using the AESWRAP-128 algorithm. The caller needs to retrieve that key\n"
- "prior to using this command. The function takes the keygrip as argument.\n";
-static gpg_error_t
-cmd_export_key (assuan_context_t ctx, char *line)
-{
- ctrl_t ctrl = assuan_get_pointer (ctx);
- gpg_error_t err;
- unsigned char grip[20];
- gcry_sexp_t s_skey = NULL;
- unsigned char *key = NULL;
- size_t keylen;
- gcry_cipher_hd_t cipherhd = NULL;
- unsigned char *wrappedkey = NULL;
- size_t wrappedkeylen;
- int openpgp;
- char *cache_nonce;
- char *passphrase = NULL;
- unsigned char *shadow_info = NULL;
- char *pend;
- int c;
-
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
- openpgp = has_option (line, "--openpgp");
- cache_nonce = option_value (line, "--cache-nonce");
- if (cache_nonce)
- {
- for (pend = cache_nonce; *pend && !spacep (pend); pend++)
- ;
- c = *pend;
- *pend = '\0';
- cache_nonce = xtrystrdup (cache_nonce);
- *pend = c;
- if (!cache_nonce)
- {
- err = gpg_error_from_syserror ();
- goto leave;
- }
- }
- line = skip_options (line);
-
- if (!ctrl->server_local->export_key)
- {
- err = set_error (GPG_ERR_MISSING_KEY, "did you run KEYWRAP_KEY ?");
- goto leave;
- }
-
- err = parse_keygrip (ctx, line, grip);
- if (err)
- goto leave;
-
- if (agent_key_available (grip))
- {
- err = gpg_error (GPG_ERR_NO_SECKEY);
- goto leave;
- }
-
- /* Get the key from the file. With the openpgp flag we also ask for
- the passphrase so that we can use it to re-encrypt it. */
- err = agent_key_from_file (ctrl, cache_nonce,
- ctrl->server_local->keydesc, grip,
- &shadow_info, CACHE_MODE_IGNORE, NULL, &s_skey,
- openpgp ? &passphrase : NULL);
- if (err)
- goto leave;
- if (shadow_info)
- {
- /* Key is on a smartcard. */
- err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
- goto leave;
- }
-
- if (openpgp)
- {
- /* The openpgp option changes the key format into the OpenPGP
- key transfer format. The result is already a padded
- canonical S-expression. */
- if (!passphrase)
- {
- err = agent_ask_new_passphrase
- (ctrl, _("This key (or subkey) is not protected with a passphrase."
- " Please enter a new passphrase to export it."),
- &passphrase);
- if (err)
- goto leave;
- }
- err = convert_to_openpgp (ctrl, s_skey, passphrase, &key, &keylen);
- if (!err && passphrase)
- {
- if (!cache_nonce)
- {
- char buf[12];
- gcry_create_nonce (buf, 12);
- cache_nonce = bin2hex (buf, 12, NULL);
- }
- if (cache_nonce
- && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
- passphrase, CACHE_TTL_NONCE))
- {
- assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
- xfree (ctrl->server_local->last_cache_nonce);
- ctrl->server_local->last_cache_nonce = cache_nonce;
- cache_nonce = NULL;
- }
- }
- }
- else
- {
- /* Convert into a canonical S-expression and wrap that. */
- err = make_canon_sexp_pad (s_skey, 1, &key, &keylen);
- }
- if (err)
- goto leave;
- gcry_sexp_release (s_skey);
- s_skey = NULL;
-
- err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
- GCRY_CIPHER_MODE_AESWRAP, 0);
- if (err)
- goto leave;
- err = gcry_cipher_setkey (cipherhd,
- ctrl->server_local->export_key, KEYWRAP_KEYSIZE);
- if (err)
- goto leave;
-
- wrappedkeylen = keylen + 8;
- wrappedkey = xtrymalloc (wrappedkeylen);
- if (!wrappedkey)
- {
- err = gpg_error_from_syserror ();
- goto leave;
- }
-
- err = gcry_cipher_encrypt (cipherhd, wrappedkey, wrappedkeylen, key, keylen);
- if (err)
- goto leave;
- xfree (key);
- key = NULL;
- gcry_cipher_close (cipherhd);
- cipherhd = NULL;
-
- assuan_begin_confidential (ctx);
- err = assuan_send_data (ctx, wrappedkey, wrappedkeylen);
- assuan_end_confidential (ctx);
-
-
- leave:
- xfree (cache_nonce);
- xfree (passphrase);
- xfree (wrappedkey);
- gcry_cipher_close (cipherhd);
- xfree (key);
- gcry_sexp_release (s_skey);
- xfree (ctrl->server_local->keydesc);
- ctrl->server_local->keydesc = NULL;
- xfree (shadow_info);
-
- return leave_cmd (ctx, err);
-}
-
-
-
-static const char hlp_delete_key[] =
- "DELETE_KEY \n"
- "\n"
- "Delete a secret key from the key store.\n"
- "As safeguard the agent asks the user for confirmation.\n";
-static gpg_error_t
-cmd_delete_key (assuan_context_t ctx, char *line)
-{
- ctrl_t ctrl = assuan_get_pointer (ctx);
- gpg_error_t err;
- unsigned char grip[20];
-
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
- line = skip_options (line);
-
- err = parse_keygrip (ctx, line, grip);
- if (err)
- goto leave;
-
- err = agent_delete_key (ctrl, ctrl->server_local->keydesc, grip);
- if (err)
- goto leave;
-
- leave:
- xfree (ctrl->server_local->keydesc);
- ctrl->server_local->keydesc = NULL;
-
- return leave_cmd (ctx, err);
-}
-
-
-
-static const char hlp_keytocard[] =
- "KEYTOCARD [--force] \n"
- "\n";
-static gpg_error_t
-cmd_keytocard (assuan_context_t ctx, char *line)
-{
- ctrl_t ctrl = assuan_get_pointer (ctx);
- int force;
- gpg_error_t err = 0;
- unsigned char grip[20];
- gcry_sexp_t s_skey = NULL;
- unsigned char *keydata;
- size_t keydatalen, timestamplen;
- const char *serialno, *timestamp_str, *id;
- unsigned char *shadow_info = NULL;
- time_t timestamp;
-
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
- force = has_option (line, "--force");
- line = skip_options (line);
-
- err = parse_keygrip (ctx, line, grip);
- if (err)
- return err;
-
- if (agent_key_available (grip))
- return gpg_error (GPG_ERR_NO_SECKEY);
-
- line += 40;
- while (*line && (*line == ' ' || *line == '\t'))
- line++;
- serialno = line;
- while (*line && (*line != ' ' && *line != '\t'))
- line++;
- if (!*line)
- return gpg_error (GPG_ERR_MISSING_VALUE);
- *line = '\0';
- line++;
- while (*line && (*line == ' ' || *line == '\t'))
- line++;
- id = line;
- while (*line && (*line != ' ' && *line != '\t'))
- line++;
- if (!*line)
- return gpg_error (GPG_ERR_MISSING_VALUE);
- *line = '\0';
- line++;
- while (*line && (*line == ' ' || *line == '\t'))
- line++;
- timestamp_str = line;
- while (*line && (*line != ' ' && *line != '\t'))
- line++;
- if (*line)
- *line = '\0';
- timestamplen = line - timestamp_str;
- if (timestamplen != 15)
- return gpg_error (GPG_ERR_INV_VALUE);
-
- err = agent_key_from_file (ctrl, NULL, ctrl->server_local->keydesc, grip,
- &shadow_info, CACHE_MODE_IGNORE, NULL,
- &s_skey, NULL);
- if (err)
- {
- xfree (shadow_info);
- return err;
- }
- if (shadow_info)
- {
- /* Key is on a smartcard already. */
- xfree (shadow_info);
- gcry_sexp_release (s_skey);
- return gpg_error (GPG_ERR_UNUSABLE_SECKEY);
- }
-
- keydatalen = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
- keydata = xtrymalloc_secure (keydatalen + 30);
- if (keydata == NULL)
- {
- gcry_sexp_release (s_skey);
- return gpg_error_from_syserror ();
- }
-
- gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, keydata, keydatalen);
- gcry_sexp_release (s_skey);
- keydatalen--; /* Decrement for last '\0'. */
- /* Add timestamp "created-at" in the private key */
- timestamp = isotime2epoch (timestamp_str);
- snprintf (keydata+keydatalen-1, 30, "(10:created-at10:%010lu))", timestamp);
- keydatalen += 10 + 19 - 1;
- err = divert_writekey (ctrl, force, serialno, id, keydata, keydatalen);
- xfree (keydata);
-
- return leave_cmd (ctx, err);
-}
-
-
-
-static const char hlp_getval[] =
- "GETVAL \n"
- "\n"
- "Return the value for KEY from the special environment as created by\n"
- "PUTVAL.";
-static gpg_error_t
-cmd_getval (assuan_context_t ctx, char *line)
-{
- ctrl_t ctrl = assuan_get_pointer (ctx);
- int rc = 0;
- char *key = NULL;
- char *p;
- struct putval_item_s *vl;
-
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
- for (p=line; *p == ' '; p++)
- ;
- key = p;
- p = strchr (key, ' ');
- if (p)
+ for (p=line; *p == ' '; p++)
+ ;
+ key = p;
+ p = strchr (key, ' ');
+ if (p)
{
*p++ = 0;
for (; *p == ' '; p++)
@@ -2549,7 +1575,7 @@
if (*p)
return set_error (GPG_ERR_ASS_PARAMETER, "too many arguments");
}
- if (!*key)
+ if (!key || !*key)
return set_error (GPG_ERR_ASS_PARAMETER, "no key given");
@@ -2562,7 +1588,9 @@
else
return gpg_error (GPG_ERR_NO_DATA);
- return leave_cmd (ctx, rc);
+ if (rc)
+ log_error ("command getval failed: %s\n", gpg_strerror (rc));
+ return rc;
}
@@ -2587,7 +1615,6 @@
static gpg_error_t
cmd_putval (assuan_context_t ctx, char *line)
{
- ctrl_t ctrl = assuan_get_pointer (ctx);
int rc = 0;
char *key = NULL;
char *value = NULL;
@@ -2595,9 +1622,6 @@
char *p;
struct putval_item_s *vl, *vlprev;
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
for (p=line; *p == ' '; p++)
;
key = p;
@@ -2616,7 +1640,7 @@
valuelen = percent_plus_unescape_inplace (value, 0);
}
}
- if (!*key)
+ if (!key || !*key)
return set_error (GPG_ERR_ASS_PARAMETER, "no key given");
@@ -2649,7 +1673,9 @@
}
}
- return leave_cmd (ctx, rc);
+ if (rc)
+ log_error ("command putval failed: %s\n", gpg_strerror (rc));
+ return rc;
}
@@ -2676,9 +1702,6 @@
(void)line;
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
se = session_env_new ();
if (!se)
err = gpg_error_from_syserror ();
@@ -2722,7 +1745,8 @@
static const char hlp_killagent[] =
"KILLAGENT\n"
"\n"
- "Stop the agent.";
+ "If the agent has been started using a standard socket\n"
+ "we allow a client to stop the agent.";
static gpg_error_t
cmd_killagent (assuan_context_t ctx, char *line)
{
@@ -2730,12 +1754,11 @@
(void)line;
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
+ if (!opt.use_standard_socket)
+ return set_error (GPG_ERR_NOT_SUPPORTED, "no --use-standard-socket");
ctrl->server_local->stopme = 1;
- assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1);
- return 0;
+ return gpg_error (GPG_ERR_EOF);
}
@@ -2747,13 +1770,9 @@
static gpg_error_t
cmd_reloadagent (assuan_context_t ctx, char *line)
{
- ctrl_t ctrl = assuan_get_pointer (ctx);
-
+ (void)ctx;
(void)line;
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
agent_sighup_action ();
return 0;
}
@@ -2771,13 +1790,10 @@
" socket_name - Return the name of the socket.\n"
" ssh_socket_name - Return the name of the ssh socket.\n"
" scd_running - Return OK if the SCdaemon is already running.\n"
- " s2k_count - Return the calibrated S2K count.\n"
- " std_env_names - List the names of the standard environment.\n"
" std_session_env - List the standard session environment.\n"
" std_startup_env - List the standard startup environment.\n"
" cmd_has_option\n"
- " - Returns OK if the command CMD implements the option OPT.\n"
- " restricted - Returns OK if the connection is in restricted mode.\n";
+ " - Returns OK if the command CMD implements the option OPT.";
static gpg_error_t
cmd_getinfo (assuan_context_t ctx, char *line)
{
@@ -2789,54 +1805,6 @@
const char *s = VERSION;
rc = assuan_send_data (ctx, s, strlen (s));
}
- 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_GENERAL);
- }
- }
- }
- }
- else if (!strcmp (line, "s2k_count"))
- {
- char numbuf[50];
-
- snprintf (numbuf, sizeof numbuf, "%lu", get_standard_s2k_count ());
- rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
- }
- else if (!strcmp (line, "restricted"))
- {
- rc = ctrl->restricted? 0 : gpg_error (GPG_ERR_GENERAL);
- }
- else if (ctrl->restricted)
- {
- rc = gpg_error (GPG_ERR_FORBIDDEN);
- }
- /* All sub-commands below are not allowed in restricted mode. */
else if (!strcmp (line, "pid"))
{
char numbuf[50];
@@ -2866,20 +1834,12 @@
{
rc = agent_scd_check_running ()? 0 : gpg_error (GPG_ERR_GENERAL);
}
- else if (!strcmp (line, "std_env_names"))
+ else if (!strcmp (line, "s2k_count"))
{
- int iterator;
- const char *name;
+ char numbuf[50];
- iterator = 0;
- while ((name = session_env_list_stdenvnames (&iterator, NULL)))
- {
- rc = assuan_send_data (ctx, name, strlen (name)+1);
- if (!rc)
- rc = assuan_send_data (ctx, NULL, 0);
- if (rc)
- break;
- }
+ snprintf (numbuf, sizeof numbuf, "%lu", get_standard_s2k_count ());
+ rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
}
else if (!strcmp (line, "std_session_env")
|| !strcmp (line, "std_startup_env"))
@@ -2909,6 +1869,38 @@
}
}
}
+ 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_GENERAL);
+ }
+ }
+ }
+ }
else
rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
return rc;
@@ -2916,27 +1908,13 @@
-/* This function is called by Libassuan to parse the OPTION command.
- It has been registered similar to the other Assuan commands. */
static gpg_error_t
option_handler (assuan_context_t ctx, const char *key, const char *value)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err = 0;
- if (!strcmp (key, "agent-awareness"))
- {
- /* The value is a version string telling us of which agent
- version the caller is aware of. */
- ctrl->server_local->allow_fully_canceled =
- gnupg_compare_version (value, "2.1.0");
- }
- else if (ctrl->restricted)
- {
- err = gpg_error (GPG_ERR_FORBIDDEN);
- }
- /* All options below are not allowed in restricted mode. */
- else if (!strcmp (key, "putenv"))
+ if (!strcmp (key, "putenv"))
{
/* Change the session's environment to be used for the
Pinentry. Valid values are:
@@ -2988,28 +1966,6 @@
ctrl->server_local->use_cache_for_signing = *value? atoi (value) : 0;
else if (!strcmp (key, "allow-pinentry-notify"))
ctrl->server_local->allow_pinentry_notify = 1;
- else if (!strcmp (key, "pinentry-mode"))
- {
- int tmp = parse_pinentry_mode (value);
- if (tmp == -1)
- err = gpg_error (GPG_ERR_INV_VALUE);
- else if (tmp == PINENTRY_MODE_LOOPBACK && !opt.allow_loopback_pinentry)
- err = gpg_error (GPG_ERR_NOT_SUPPORTED);
- else
- ctrl->pinentry_mode = tmp;
- }
- else if (!strcmp (key, "cache-ttl-opt-preset"))
- {
- ctrl->cache_ttl_opt_preset = *value? atoi (value) : 0;
- }
- else if (!strcmp (key, "s2k-count"))
- {
- ctrl->s2k_count = *value? strtoul(value, NULL, 10) : 0;
- if (ctrl->s2k_count && ctrl->s2k_count < 65536)
- {
- ctrl->s2k_count = 0;
- }
- }
else
err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
@@ -3074,8 +2030,7 @@
}
-/* Tell Libassuan about our commands. Also register the other Assuan
- handlers. */
+/* Tell the assuan library about our commands */
static int
register_commands (assuan_context_t ctx)
{
@@ -3107,17 +2062,12 @@
{ "INPUT", NULL },
{ "OUTPUT", NULL },
{ "SCD", cmd_scd, hlp_scd },
- { "KEYWRAP_KEY", cmd_keywrap_key, hlp_keywrap_key },
- { "IMPORT_KEY", cmd_import_key, hlp_import_key },
- { "EXPORT_KEY", cmd_export_key, hlp_export_key },
- { "DELETE_KEY", cmd_delete_key, hlp_delete_key },
{ "GETVAL", cmd_getval, hlp_getval },
{ "PUTVAL", cmd_putval, hlp_putval },
{ "UPDATESTARTUPTTY", cmd_updatestartuptty, hlp_updatestartuptty },
{ "KILLAGENT", cmd_killagent, hlp_killagent },
{ "RELOADAGENT", cmd_reloadagent,hlp_reloadagent },
{ "GETINFO", cmd_getinfo, hlp_getinfo },
- { "KEYTOCARD", cmd_keytocard, hlp_keytocard },
{ NULL }
};
int i, rc;
@@ -3146,12 +2096,6 @@
int rc;
assuan_context_t ctx = NULL;
- if (ctrl->restricted)
- {
- if (agent_copy_startup_env (ctrl))
- return;
- }
-
rc = assuan_new (&ctx);
if (rc)
{
@@ -3194,6 +2138,7 @@
assuan_set_pointer (ctx, ctrl);
ctrl->server_local = xcalloc (1, sizeof *ctrl->server_local);
ctrl->server_local->assuan_ctx = ctx;
+ ctrl->server_local->message_fd = -1;
ctrl->server_local->use_cache_for_signing = 1;
ctrl->digest.raw_value = 0;
@@ -3220,9 +2165,6 @@
}
}
- /* Reset the nonce caches. */
- clear_nonce_cache (ctrl);
-
/* Reset the SCD if needed. */
agent_reset_scd (ctrl);
@@ -3231,32 +2173,9 @@
/* Cleanup. */
assuan_release (ctx);
- xfree (ctrl->server_local->keydesc);
- xfree (ctrl->server_local->import_key);
- xfree (ctrl->server_local->export_key);
if (ctrl->server_local->stopme)
agent_exit (0);
xfree (ctrl->server_local);
ctrl->server_local = NULL;
}
-
-/* Helper for the pinentry loopback mode. It merely passes the
- parameters on to the client. */
-gpg_error_t
-pinentry_loopback(ctrl_t ctrl, const char *keyword,
- unsigned char **buffer, size_t *size,
- size_t max_length)
-{
- gpg_error_t rc;
- assuan_context_t ctx = ctrl->server_local->assuan_ctx;
-
- rc = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%zu", max_length);
- if (rc)
- return rc;
-
- assuan_begin_confidential (ctx);
- rc = assuan_inquire (ctx, keyword, buffer, size, max_length);
- assuan_end_confidential (ctx);
- return rc;
-}
diff -Nru gnupg2-2.1.6~build1/agent/command-ssh.c gnupg2-2.0.28/agent/command-ssh.c
--- gnupg2-2.1.6~build1/agent/command-ssh.c 2015-06-30 19:26:58.000000000 +0000
+++ gnupg2-2.0.28/agent/command-ssh.c 2015-06-02 08:13:55.000000000 +0000
@@ -1,6 +1,6 @@
/* command-ssh.c - gpg-agent's ssh-agent emulation layer
- * Copyright (C) 2004-2006, 2009, 2012 Free Software Foundation, Inc.
- * Copyright (C) 2004-2006, 2009, 2012-2014 Werner Koch
+ * Copyright (C) 2004, 2005, 2006, 2009, 2012 Free Software Foundation, Inc.
+ * Copyright (C) 2013 Werner Koch
*
* This file is part of GnuPG.
*
@@ -43,6 +43,7 @@
#include "agent.h"
+#include "estream.h"
#include "i18n.h"
#include "../common/ssh-utils.h"
@@ -74,7 +75,6 @@
#define SSH_DSA_SIGNATURE_ELEMS 2
#define SPEC_FLAG_USE_PKCS1V2 (1 << 0)
#define SPEC_FLAG_IS_ECDSA (1 << 1)
-#define SPEC_FLAG_IS_EdDSA (1 << 2) /*(lowercase 'd' on purpose.)*/
/* The name of the control file. */
#define SSH_CONTROL_FILE_NAME "sshcontrol"
@@ -139,7 +139,7 @@
functions are necessary. */
typedef gpg_error_t (*ssh_signature_encoder_t) (ssh_key_type_spec_t *spec,
estream_t signature_blob,
- gcry_sexp_t sig);
+ gcry_mpi_t *mpis);
/* Type, which is used for boundling all the algorithm specific
information together in a single object. */
@@ -148,9 +148,6 @@
/* Algorithm identifier as used by OpenSSH. */
const char *ssh_identifier;
- /* Human readable name of the algorithm. */
- const char *name;
-
/* Algorithm identifier as used by GnuPG. */
const char *identifier;
@@ -233,17 +230,13 @@
static gpg_error_t ssh_key_modifier_rsa (const char *elems, gcry_mpi_t *mpis);
static gpg_error_t ssh_signature_encoder_rsa (ssh_key_type_spec_t *spec,
estream_t signature_blob,
- gcry_sexp_t signature);
+ gcry_mpi_t *mpis);
static gpg_error_t ssh_signature_encoder_dsa (ssh_key_type_spec_t *spec,
estream_t signature_blob,
- gcry_sexp_t signature);
+ gcry_mpi_t *mpis);
static gpg_error_t ssh_signature_encoder_ecdsa (ssh_key_type_spec_t *spec,
estream_t signature_blob,
- gcry_sexp_t signature);
-static gpg_error_t ssh_signature_encoder_eddsa (ssh_key_type_spec_t *spec,
- estream_t signature_blob,
- gcry_sexp_t signature);
-static gpg_error_t ssh_key_extract_comment (gcry_sexp_t key, char **comment);
+ gcry_mpi_t *mpis);
@@ -274,35 +267,31 @@
static ssh_key_type_spec_t ssh_key_types[] =
{
{
- "ssh-ed25519", "Ed25519", "ecc", "qd", "q", "rs", "qd",
- NULL, ssh_signature_encoder_eddsa,
- "Ed25519", 0, SPEC_FLAG_IS_EdDSA
- },
- {
- "ssh-rsa", "RSA", "rsa", "nedupq", "en", "s", "nedpqu",
+ "ssh-rsa", "rsa", "nedupq", "en", "s", "nedpqu",
ssh_key_modifier_rsa, ssh_signature_encoder_rsa,
- NULL, 0, SPEC_FLAG_USE_PKCS1V2
+ NULL, 0, SPEC_FLAG_USE_PKCS1V2
},
{
- "ssh-dss", "DSA", "dsa", "pqgyx", "pqgy", "rs", "pqgyx",
+ "ssh-dss", "dsa", "pqgyx", "pqgy", "rs", "pqgyx",
NULL, ssh_signature_encoder_dsa,
NULL, 0, 0
},
{
- "ecdsa-sha2-nistp256", "ECDSA", "ecdsa", "qd", "q", "rs", "qd",
+ "ecdsa-sha2-nistp256", "ecdsa", "qd", "q", "rs", "qd",
NULL, ssh_signature_encoder_ecdsa,
"nistp256", GCRY_MD_SHA256, SPEC_FLAG_IS_ECDSA
},
{
- "ecdsa-sha2-nistp384", "ECDSA", "ecdsa", "qd", "q", "rs", "qd",
+ "ecdsa-sha2-nistp384", "ecdsa", "qd", "q", "rs", "qd",
NULL, ssh_signature_encoder_ecdsa,
"nistp384", GCRY_MD_SHA384, SPEC_FLAG_IS_ECDSA
},
{
- "ecdsa-sha2-nistp521", "ECDSA", "ecdsa", "qd", "q", "rs", "qd",
+ "ecdsa-sha2-nistp521", "ecdsa", "qd", "q", "rs", "qd",
NULL, ssh_signature_encoder_ecdsa,
"nistp521", GCRY_MD_SHA512, SPEC_FLAG_IS_ECDSA
}
+
};
@@ -348,20 +337,7 @@
return s;
}
-/* Lookup the ssh-identifier for the ECC curve CURVE_NAME. Returns
- NULL if not found. */
-static const char *
-ssh_identifier_from_curve_name (const char *curve_name)
-{
- int i;
-
- for (i = 0; i < DIM (ssh_key_types); i++)
- if (ssh_key_types[i].curve_name
- && !strcmp (ssh_key_types[i].curve_name, curve_name))
- return ssh_key_types[i].ssh_identifier;
- return NULL;
-}
/*
@@ -484,34 +460,6 @@
return err;
}
-/* Skip over SIZE bytes from STREAM. */
-static gpg_error_t
-stream_read_skip (estream_t stream, size_t size)
-{
- char buffer[128];
- size_t bytes_to_read, bytes_read;
- int ret;
-
- do
- {
- bytes_to_read = size;
- if (bytes_to_read > sizeof buffer)
- bytes_to_read = sizeof buffer;
-
- ret = es_read (stream, buffer, bytes_to_read, &bytes_read);
- if (ret)
- return gpg_error_from_syserror ();
- else if (bytes_read != bytes_to_read)
- return gpg_error (GPG_ERR_EOF);
- else
- size -= bytes_to_read;
- }
- while (size);
-
- return 0;
-}
-
-
/* Write SIZE bytes from BUFFER to STREAM. */
static gpg_error_t
stream_write_data (estream_t stream, const unsigned char *buffer, size_t size)
@@ -540,9 +488,6 @@
unsigned char *buffer = NULL;
u32 length = 0;
- if (string_size)
- *string_size = 0;
-
/* Read string length. */
err = stream_read_uint32 (stream, &length);
if (err)
@@ -578,68 +523,21 @@
return err;
}
-
-/* Read a binary string from STREAM and store it as an opaque MPI at
- R_MPI. Depending on SECURE use secure memory. If the string is
- too large for key material return an error. */
+/* Read a C-string from STREAM, store copy in STRING. */
static gpg_error_t
-stream_read_blob (estream_t stream, unsigned int secure, gcry_mpi_t *r_mpi)
+stream_read_cstring (estream_t stream, char **string)
{
+ unsigned char *buffer;
gpg_error_t err;
- unsigned char *buffer = NULL;
- u32 length = 0;
-
- *r_mpi = NULL;
-
- /* Read string length. */
- err = stream_read_uint32 (stream, &length);
- if (err)
- goto leave;
-
- /* To avoid excessive use of secure memory we check that an MPI is
- not too large. */
- if (length > (4096/8) + 8)
- {
- log_error (_("ssh keys greater than %d bits are not supported\n"), 4096);
- err = GPG_ERR_TOO_LARGE;
- goto leave;
- }
-
- /* Allocate space. */
- if (secure)
- buffer = xtrymalloc_secure (length? length:1);
- else
- buffer = xtrymalloc (length?length:1);
- if (!buffer)
- {
- err = gpg_error_from_syserror ();
- goto leave;
- }
- /* Read data. */
- err = stream_read_data (stream, buffer, length);
+ err = stream_read_string (stream, 0, &buffer, NULL);
if (err)
- goto leave;
-
- *r_mpi = gcry_mpi_set_opaque (NULL, buffer, 8*length);
- buffer = NULL;
-
- leave:
- xfree (buffer);
- return err;
-}
+ goto out;
+ *string = (char *) buffer;
-/* Read a C-string from STREAM, store copy in STRING. */
-static gpg_error_t
-stream_read_cstring (estream_t stream, char **string)
-{
- gpg_error_t err;
- unsigned char *buffer;
+ out:
- err = stream_read_string (stream, 0, &buffer, NULL);
- if (!err)
- *string = (char *)buffer;
return err;
}
@@ -735,7 +633,6 @@
return err;
}
-
/* Copy data from SRC to DST until EOF is reached. */
static gpg_error_t
stream_copy (estream_t dst, estream_t src)
@@ -854,7 +751,7 @@
err = gpg_error_from_syserror ();
goto leave;
}
- /* FIXME: With "a+" we are not able to check whether this will
+ /* FIXME: With "a+" we are not able to check whether this will will
be created and thus the blurb needs to be written first. */
cf->fp = fopen (cf->fname, append? "a+":"r");
if (!cf->fp && errno == ENOENT)
@@ -863,7 +760,7 @@
if (!stream)
{
err = gpg_error_from_syserror ();
- log_error (_("can't create '%s': %s\n"),
+ log_error (_("can't create `%s': %s\n"),
cf->fname, gpg_strerror (err));
goto leave;
}
@@ -875,7 +772,7 @@
if (!cf->fp)
{
err = gpg_error_from_syserror ();
- log_error (_("can't open '%s': %s\n"),
+ log_error (_("can't open `%s': %s\n"),
cf->fname, gpg_strerror (err));
goto leave;
}
@@ -1031,8 +928,7 @@
assert (strlen (hexgrip) == 40 );
- if (r_disabled)
- *r_disabled = 0;
+ *r_disabled = 0;
if (r_ttl)
*r_ttl = 0;
if (r_confirm)
@@ -1048,8 +944,7 @@
}
if (!err)
{
- if (r_disabled)
- *r_disabled = cf->item.disabled;
+ *r_disabled = cf->item.disabled;
if (r_ttl)
*r_ttl = cf->item.ttl;
if (r_confirm)
@@ -1066,8 +961,7 @@
general used to add a key received through the ssh-add function.
We can assume that the user wants to allow ssh using this key. */
static gpg_error_t
-add_control_entry (ctrl_t ctrl, ssh_key_type_spec_t *spec,
- const char *hexgrip, const char *fmtfpr,
+add_control_entry (ctrl_t ctrl, const char *hexgrip, const char *fmtfpr,
int ttl, int confirm)
{
gpg_error_t err;
@@ -1090,10 +984,9 @@
opened in append mode, we simply need to write to it. */
tp = localtime (&atime);
fprintf (cf->fp,
- ("# %s key added on: %04d-%02d-%02d %02d:%02d:%02d\n"
- "# MD5 Fingerprint: %s\n"
+ ("# Key added on: %04d-%02d-%02d %02d:%02d:%02d\n"
+ "# Fingerprint: %s\n"
"%s %d%s\n"),
- spec->name,
1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
tp->tm_hour, tp->tm_min, tp->tm_sec,
fmtfpr, hexgrip, ttl, confirm? " confirm":"");
@@ -1350,63 +1243,15 @@
/* Signature encoder function for RSA. */
static gpg_error_t
ssh_signature_encoder_rsa (ssh_key_type_spec_t *spec,
- estream_t signature_blob,
- gcry_sexp_t s_signature)
+ estream_t signature_blob, gcry_mpi_t *mpis)
{
- gpg_error_t err = 0;
- gcry_sexp_t valuelist = NULL;
- gcry_sexp_t sublist = NULL;
- gcry_mpi_t sig_value = NULL;
- gcry_mpi_t *mpis = NULL;
- const char *elems;
- size_t elems_n;
- int i;
-
unsigned char *data;
size_t data_n;
+ gpg_error_t err;
gcry_mpi_t s;
- valuelist = gcry_sexp_nth (s_signature, 1);
- if (!valuelist)
- {
- err = gpg_error (GPG_ERR_INV_SEXP);
- goto out;
- }
-
- elems = spec->elems_signature;
- elems_n = strlen (elems);
-
- mpis = xtrycalloc (elems_n + 1, sizeof *mpis);
- if (!mpis)
- {
- err = gpg_error_from_syserror ();
- goto out;
- }
-
- for (i = 0; i < elems_n; i++)
- {
- sublist = gcry_sexp_find_token (valuelist, spec->elems_signature + i, 1);
- if (!sublist)
- {
- err = gpg_error (GPG_ERR_INV_SEXP);
- break;
- }
-
- sig_value = gcry_sexp_nth_mpi (sublist, 1, GCRYMPI_FMT_USG);
- if (!sig_value)
- {
- err = gpg_error (GPG_ERR_INTERNAL); /* FIXME? */
- break;
- }
- gcry_sexp_release (sublist);
- sublist = NULL;
-
- mpis[i] = sig_value;
- }
- if (err)
- goto out;
+ (void)spec;
- /* RSA specific */
s = mpis[0];
err = gcry_mpi_aprint (GCRYMPI_FMT_USG, &data, &data_n, s);
@@ -1417,9 +1262,7 @@
xfree (data);
out:
- gcry_sexp_release (valuelist);
- gcry_sexp_release (sublist);
- mpint_list_free (mpis);
+
return err;
}
@@ -1427,63 +1270,17 @@
/* Signature encoder function for DSA. */
static gpg_error_t
ssh_signature_encoder_dsa (ssh_key_type_spec_t *spec,
- estream_t signature_blob,
- gcry_sexp_t s_signature)
+ estream_t signature_blob, gcry_mpi_t *mpis)
{
- gpg_error_t err = 0;
- gcry_sexp_t valuelist = NULL;
- gcry_sexp_t sublist = NULL;
- gcry_mpi_t sig_value = NULL;
- gcry_mpi_t *mpis = NULL;
- const char *elems;
- size_t elems_n;
- int i;
-
unsigned char buffer[SSH_DSA_SIGNATURE_PADDING * SSH_DSA_SIGNATURE_ELEMS];
- unsigned char *data = NULL;
+ unsigned char *data;
size_t data_n;
+ gpg_error_t err;
+ int i;
- valuelist = gcry_sexp_nth (s_signature, 1);
- if (!valuelist)
- {
- err = gpg_error (GPG_ERR_INV_SEXP);
- goto out;
- }
-
- elems = spec->elems_signature;
- elems_n = strlen (elems);
-
- mpis = xtrycalloc (elems_n + 1, sizeof *mpis);
- if (!mpis)
- {
- err = gpg_error_from_syserror ();
- goto out;
- }
-
- for (i = 0; i < elems_n; i++)
- {
- sublist = gcry_sexp_find_token (valuelist, spec->elems_signature + i, 1);
- if (!sublist)
- {
- err = gpg_error (GPG_ERR_INV_SEXP);
- break;
- }
-
- sig_value = gcry_sexp_nth_mpi (sublist, 1, GCRYMPI_FMT_USG);
- if (!sig_value)
- {
- err = gpg_error (GPG_ERR_INTERNAL); /* FIXME? */
- break;
- }
- gcry_sexp_release (sublist);
- sublist = NULL;
-
- mpis[i] = sig_value;
- }
- if (err)
- goto out;
+ (void)spec;
- /* DSA specific code. */
+ data = NULL;
/* FIXME: Why this complicated code? Why collecting boths mpis in a
buffer instead of writing them out one after the other? */
@@ -1513,10 +1310,9 @@
err = stream_write_string (signature_blob, buffer, sizeof (buffer));
out:
+
xfree (data);
- gcry_sexp_release (valuelist);
- gcry_sexp_release (sublist);
- mpint_list_free (mpis);
+
return err;
}
@@ -1524,62 +1320,15 @@
/* Signature encoder function for ECDSA. */
static gpg_error_t
ssh_signature_encoder_ecdsa (ssh_key_type_spec_t *spec,
- estream_t stream, gcry_sexp_t s_signature)
+ estream_t stream, gcry_mpi_t *mpis)
{
- gpg_error_t err = 0;
- gcry_sexp_t valuelist = NULL;
- gcry_sexp_t sublist = NULL;
- gcry_mpi_t sig_value = NULL;
- gcry_mpi_t *mpis = NULL;
- const char *elems;
- size_t elems_n;
- int i;
-
unsigned char *data[2] = {NULL, NULL};
size_t data_n[2];
size_t innerlen;
+ gpg_error_t err;
+ int i;
- valuelist = gcry_sexp_nth (s_signature, 1);
- if (!valuelist)
- {
- err = gpg_error (GPG_ERR_INV_SEXP);
- goto out;
- }
-
- elems = spec->elems_signature;
- elems_n = strlen (elems);
-
- mpis = xtrycalloc (elems_n + 1, sizeof *mpis);
- if (!mpis)
- {
- err = gpg_error_from_syserror ();
- goto out;
- }
-
- for (i = 0; i < elems_n; i++)
- {
- sublist = gcry_sexp_find_token (valuelist, spec->elems_signature + i, 1);
- if (!sublist)
- {
- err = gpg_error (GPG_ERR_INV_SEXP);
- break;
- }
-
- sig_value = gcry_sexp_nth_mpi (sublist, 1, GCRYMPI_FMT_USG);
- if (!sig_value)
- {
- err = gpg_error (GPG_ERR_INTERNAL); /* FIXME? */
- break;
- }
- gcry_sexp_release (sublist);
- sublist = NULL;
-
- mpis[i] = sig_value;
- }
- if (err)
- goto out;
-
- /* ECDSA specific */
+ (void)spec;
innerlen = 0;
for (i = 0; i < DIM(data); i++)
@@ -1604,212 +1353,103 @@
out:
for (i = 0; i < DIM(data); i++)
xfree (data[i]);
- gcry_sexp_release (valuelist);
- gcry_sexp_release (sublist);
- mpint_list_free (mpis);
return err;
}
-/* Signature encoder function for EdDSA. */
+/*
+ S-Expressions.
+ */
+
+
+/* This function constructs a new S-Expression for the key identified
+ by the KEY_SPEC, SECRET, CURVE_NAME, MPIS, and COMMENT, which is to
+ be stored at R_SEXP. Returns an error code. */
static gpg_error_t
-ssh_signature_encoder_eddsa (ssh_key_type_spec_t *spec,
- estream_t stream, gcry_sexp_t s_signature)
+sexp_key_construct (gcry_sexp_t *r_sexp,
+ ssh_key_type_spec_t key_spec, int secret,
+ const char *curve_name, gcry_mpi_t *mpis,
+ const char *comment)
{
- gpg_error_t err = 0;
- gcry_sexp_t valuelist = NULL;
- gcry_sexp_t sublist = NULL;
+ const char *key_identifier[] = { "public-key", "private-key" };
+ gpg_error_t err;
+ gcry_sexp_t sexp_new = NULL;
+ void *formatbuf = NULL;
+ void **arg_list = NULL;
+ int arg_idx;
+ estream_t format;
const char *elems;
size_t elems_n;
- int i;
+ unsigned int i, j;
- unsigned char *data[2] = {NULL, NULL};
- size_t data_n[2];
- size_t totallen = 0;
+ if (secret)
+ elems = key_spec.elems_sexp_order;
+ else
+ elems = key_spec.elems_key_public;
+ elems_n = strlen (elems);
- valuelist = gcry_sexp_nth (s_signature, 1);
- if (!valuelist)
+ format = es_fopenmem (0, "a+b");
+ if (!format)
{
- err = gpg_error (GPG_ERR_INV_SEXP);
+ err = gpg_error_from_syserror ();
goto out;
}
- elems = spec->elems_signature;
- elems_n = strlen (elems);
-
- if (elems_n != DIM(data))
+ /* Key identifier, algorithm identifier, mpis, comment, and a NULL
+ as a safeguard. */
+ arg_list = xtrymalloc (sizeof (*arg_list) * (2 + 1 + elems_n + 1 + 1));
+ if (!arg_list)
{
- err = gpg_error (GPG_ERR_INV_SEXP);
+ err = gpg_error_from_syserror ();
goto out;
}
+ arg_idx = 0;
- for (i = 0; i < DIM(data); i++)
+ es_fputs ("(%s(%s", format);
+ arg_list[arg_idx++] = &key_identifier[secret];
+ arg_list[arg_idx++] = &key_spec.identifier;
+ if (curve_name)
{
- sublist = gcry_sexp_find_token (valuelist, spec->elems_signature + i, 1);
- if (!sublist)
- {
- err = gpg_error (GPG_ERR_INV_SEXP);
- break;
- }
+ es_fputs ("(curve%s)", format);
+ arg_list[arg_idx++] = &curve_name;
+ }
- data[i] = gcry_sexp_nth_buffer (sublist, 1, &data_n[i]);
- if (!data[i])
+ for (i = 0; i < elems_n; i++)
+ {
+ es_fprintf (format, "(%c%%m)", elems[i]);
+ if (secret)
{
- err = gpg_error (GPG_ERR_INTERNAL); /* FIXME? */
- break;
+ for (j = 0; j < elems_n; j++)
+ if (key_spec.elems_key_secret[j] == elems[i])
+ break;
}
- totallen += data_n[i];
- gcry_sexp_release (sublist);
- sublist = NULL;
+ else
+ j = i;
+ arg_list[arg_idx++] = &mpis[j];
}
- if (err)
- goto out;
+ es_fputs (")(comment%s))", format);
+ arg_list[arg_idx++] = &comment;
+ arg_list[arg_idx] = NULL;
- err = stream_write_uint32 (stream, totallen);
- if (err)
- goto out;
-
- for (i = 0; i < DIM(data); i++)
+ es_putc (0, format);
+ if (es_ferror (format))
{
- err = stream_write_data (stream, data[i], data_n[i]);
- if (err)
- goto out;
+ err = gpg_error_from_syserror ();
+ goto out;
}
-
- out:
- for (i = 0; i < DIM(data); i++)
- xfree (data[i]);
- gcry_sexp_release (valuelist);
- gcry_sexp_release (sublist);
- return err;
-}
-
-
-/*
- S-Expressions.
- */
-
-
-/* This function constructs a new S-Expression for the key identified
- by the KEY_SPEC, SECRET, CURVE_NAME, MPIS, and COMMENT, which is to
- be stored at R_SEXP. Returns an error code. */
-static gpg_error_t
-sexp_key_construct (gcry_sexp_t *r_sexp,
- ssh_key_type_spec_t key_spec, int secret,
- const char *curve_name, gcry_mpi_t *mpis,
- const char *comment)
-{
- gpg_error_t err;
- gcry_sexp_t sexp_new = NULL;
- void *formatbuf = NULL;
- void **arg_list = NULL;
- estream_t format = NULL;
-
-
- if ((key_spec.flags & SPEC_FLAG_IS_EdDSA))
+ if (es_fclose_snatch (format, &formatbuf, NULL))
{
- /* It is much easier and more readable to use a separate code
- path for EdDSA. */
- if (!curve_name)
- err = gpg_error (GPG_ERR_INV_CURVE);
- else if (!mpis[0] || !gcry_mpi_get_flag (mpis[0], GCRYMPI_FLAG_OPAQUE))
- err = gpg_error (GPG_ERR_BAD_PUBKEY);
- else if (secret
- && (!mpis[1]
- || !gcry_mpi_get_flag (mpis[1], GCRYMPI_FLAG_OPAQUE)))
- err = gpg_error (GPG_ERR_BAD_SECKEY);
- else if (secret)
- err = gcry_sexp_build (&sexp_new, NULL,
- "(private-key(ecc(curve %s)"
- "(flags eddsa)(q %m)(d %m))"
- "(comment%s))",
- curve_name,
- mpis[0], mpis[1],
- comment? comment:"");
- else
- err = gcry_sexp_build (&sexp_new, NULL,
- "(public-key(ecc(curve %s)"
- "(flags eddsa)(q %m))"
- "(comment%s))",
- curve_name,
- mpis[0],
- comment? comment:"");
+ err = gpg_error_from_syserror ();
+ goto out;
}
- else
- {
- const char *key_identifier[] = { "public-key", "private-key" };
- int arg_idx;
- const char *elems;
- size_t elems_n;
- unsigned int i, j;
-
- if (secret)
- elems = key_spec.elems_sexp_order;
- else
- elems = key_spec.elems_key_public;
- elems_n = strlen (elems);
+ format = NULL;
- format = es_fopenmem (0, "a+b");
- if (!format)
- {
- err = gpg_error_from_syserror ();
- goto out;
- }
-
- /* Key identifier, algorithm identifier, mpis, comment, and a NULL
- as a safeguard. */
- arg_list = xtrymalloc (sizeof (*arg_list) * (2 + 1 + elems_n + 1 + 1));
- if (!arg_list)
- {
- err = gpg_error_from_syserror ();
- goto out;
- }
- arg_idx = 0;
-
- es_fputs ("(%s(%s", format);
- arg_list[arg_idx++] = &key_identifier[secret];
- arg_list[arg_idx++] = &key_spec.identifier;
- if (curve_name)
- {
- es_fputs ("(curve%s)", format);
- arg_list[arg_idx++] = &curve_name;
- }
-
- for (i = 0; i < elems_n; i++)
- {
- es_fprintf (format, "(%c%%m)", elems[i]);
- if (secret)
- {
- for (j = 0; j < elems_n; j++)
- if (key_spec.elems_key_secret[j] == elems[i])
- break;
- }
- else
- j = i;
- arg_list[arg_idx++] = &mpis[j];
- }
- es_fputs (")(comment%s))", format);
- arg_list[arg_idx++] = &comment;
- arg_list[arg_idx] = NULL;
-
- es_putc (0, format);
- if (es_ferror (format))
- {
- err = gpg_error_from_syserror ();
- goto out;
- }
- if (es_fclose_snatch (format, &formatbuf, NULL))
- {
- err = gpg_error_from_syserror ();
- goto out;
- }
- format = NULL;
-
- err = gcry_sexp_build_array (&sexp_new, NULL, formatbuf, arg_list);
- }
+ err = gcry_sexp_build_array (&sexp_new, NULL, formatbuf, arg_list);
+ if (err)
+ goto out;
- if (!err)
- *r_sexp = sexp_new;
+ *r_sexp = sexp_new;
+ err = 0;
out:
es_fclose (format);
@@ -1820,66 +1460,96 @@
}
-/* This function extracts the key from the s-expression SEXP according
- to KEY_SPEC and stores it in ssh format at (R_BLOB, R_BLOBLEN). If
- WITH_SECRET is true, the secret key parts are also extracted if
- possible. Returns 0 on success or an error code. Note that data
- stored at R_BLOB must be freed using es_free! */
-static gpg_error_t
-ssh_key_to_blob (gcry_sexp_t sexp, int with_secret,
- ssh_key_type_spec_t key_spec,
- void **r_blob, size_t *r_blob_size)
+/* This functions breaks up the key contained in the S-Expression SEXP
+ according to KEY_SPEC. The MPIs are bundled in a newly create
+ list, which is to be stored in MPIS; a newly allocated string
+ holding the curve name may be stored at RCURVE, and a comment will
+ be stored at COMMENT; SECRET will be filled with a boolean flag
+ specifying what kind of key it is. Returns an error code. */
+static gpg_error_t
+sexp_key_extract (gcry_sexp_t sexp,
+ ssh_key_type_spec_t key_spec, int *secret,
+ gcry_mpi_t **mpis, char **r_curve, char **comment)
{
gpg_error_t err = 0;
gcry_sexp_t value_list = NULL;
gcry_sexp_t value_pair = NULL;
- char *curve_name = NULL;
- estream_t stream = NULL;
- void *blob = NULL;
- size_t blob_size;
- const char *elems, *p_elems;
+ gcry_sexp_t comment_list = NULL;
+ unsigned int i;
+ char *comment_new = NULL;
const char *data;
- size_t datalen;
-
- *r_blob = NULL;
- *r_blob_size = 0;
+ size_t data_n;
+ int is_secret;
+ size_t elems_n;
+ const char *elems;
+ gcry_mpi_t *mpis_new = NULL;
+ gcry_mpi_t mpi;
+ char *curve_name = NULL;
- stream = es_fopenmem (0, "r+b");
- if (!stream)
+ data = gcry_sexp_nth_data (sexp, 0, &data_n);
+ if (! data)
{
- err = gpg_error_from_syserror ();
+ err = gpg_error (GPG_ERR_INV_SEXP);
goto out;
}
- /* Get the type of the key extpression. */
- data = gcry_sexp_nth_data (sexp, 0, &datalen);
- if (!data)
+ if ((data_n == 10 && !strncmp (data, "public-key", 10))
+ || (data_n == 21 && !strncmp (data, "protected-private-key", 21))
+ || (data_n == 20 && !strncmp (data, "shadowed-private-key", 20)))
+ {
+ is_secret = 0;
+ elems = key_spec.elems_key_public;
+ }
+ else if (data_n == 11 && !strncmp (data, "private-key", 11))
+ {
+ is_secret = 1;
+ elems = key_spec.elems_key_secret;
+ }
+ else
{
err = gpg_error (GPG_ERR_INV_SEXP);
goto out;
}
- if ((datalen == 10 && !strncmp (data, "public-key", 10))
- || (datalen == 21 && !strncmp (data, "protected-private-key", 21))
- || (datalen == 20 && !strncmp (data, "shadowed-private-key", 20)))
- elems = key_spec.elems_key_public;
- else if (datalen == 11 && !strncmp (data, "private-key", 11))
- elems = with_secret? key_spec.elems_key_secret : key_spec.elems_key_public;
- else
+ elems_n = strlen (elems);
+ mpis_new = xtrycalloc (elems_n + 1, sizeof *mpis_new );
+ if (!mpis_new)
{
- err = gpg_error (GPG_ERR_INV_SEXP);
+ err = gpg_error_from_syserror ();
goto out;
}
- /* Get the algorithm identifier. */
value_list = gcry_sexp_find_token (sexp, key_spec.identifier, 0);
- if (!value_list)
+ if (! value_list)
{
err = gpg_error (GPG_ERR_INV_SEXP);
goto out;
}
- /* Write the ssh algorithm identifier. */
+ for (i = 0; i < elems_n; i++)
+ {
+ value_pair = gcry_sexp_find_token (value_list, elems + i, 1);
+ if (! value_pair)
+ {
+ err = gpg_error (GPG_ERR_INV_SEXP);
+ break;
+ }
+
+ /* Note that we need to use STD format; i.e. prepend a 0x00 to
+ indicate a positive number if the high bit is set. */
+ mpi = gcry_sexp_nth_mpi (value_pair, 1, GCRYMPI_FMT_STD);
+ if (! mpi)
+ {
+ err = gpg_error (GPG_ERR_INV_SEXP);
+ break;
+ }
+ mpis_new[i] = mpi;
+ gcry_sexp_release (value_pair);
+ value_pair = NULL;
+ }
+ if (err)
+ goto out;
+
if ((key_spec.flags & SPEC_FLAG_IS_ECDSA))
{
/* Parse the "curve" parameter. We currently expect the curve
@@ -1887,9 +1557,7 @@
easily be changed but then we need to find the curve name
from the parameters using gcry_pk_get_curve. */
const char *mapped;
- const char *sshname;
- gcry_sexp_release (value_pair);
value_pair = gcry_sexp_find_token (value_list, "curve", 5);
if (!value_pair)
{
@@ -1923,87 +1591,48 @@
goto out;
}
}
-
- sshname = ssh_identifier_from_curve_name (curve_name);
- if (!sshname)
- {
- err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
- goto out;
- }
- err = stream_write_cstring (stream, sshname);
- if (err)
- goto out;
- err = stream_write_cstring (stream, curve_name);
- if (err)
- goto out;
- }
- else
- {
- /* Note: This is also used for EdDSA. */
- err = stream_write_cstring (stream, key_spec.ssh_identifier);
- if (err)
- goto out;
- }
-
- /* Write the parameters. */
- for (p_elems = elems; *p_elems; p_elems++)
- {
gcry_sexp_release (value_pair);
- value_pair = gcry_sexp_find_token (value_list, p_elems, 1);
- if (!value_pair)
- {
- err = gpg_error (GPG_ERR_INV_SEXP);
- goto out;
- }
- if ((key_spec.flags & SPEC_FLAG_IS_EdDSA))
- {
+ value_pair = NULL;
+ }
- data = gcry_sexp_nth_data (value_pair, 1, &datalen);
- if (!data)
- {
- err = gpg_error (GPG_ERR_INV_SEXP);
- goto out;
- }
- err = stream_write_string (stream, data, datalen);
- if (err)
- goto out;
- }
- else
- {
- gcry_mpi_t mpi;
+ /* We do not require a comment sublist to be present here. */
+ data = NULL;
+ data_n = 0;
- /* Note that we need to use STD format; i.e. prepend a 0x00
- to indicate a positive number if the high bit is set. */
- mpi = gcry_sexp_nth_mpi (value_pair, 1, GCRYMPI_FMT_STD);
- if (!mpi)
- {
- err = gpg_error (GPG_ERR_INV_SEXP);
- goto out;
- }
- err = stream_write_mpi (stream, mpi);
- gcry_mpi_release (mpi);
- if (err)
- goto out;
- }
+ comment_list = gcry_sexp_find_token (sexp, "comment", 0);
+ if (comment_list)
+ data = gcry_sexp_nth_data (comment_list, 1, &data_n);
+ if (! data)
+ {
+ data = "(none)";
+ data_n = 6;
}
- if (es_fclose_snatch (stream, &blob, &blob_size))
+ comment_new = make_cstring (data, data_n);
+ if (! comment_new)
{
err = gpg_error_from_syserror ();
goto out;
}
- stream = NULL;
- *r_blob = blob;
- blob = NULL;
- *r_blob_size = blob_size;
+ if (secret)
+ *secret = is_secret;
+ *mpis = mpis_new;
+ *comment = comment_new;
+ *r_curve = curve_name;
out:
+
gcry_sexp_release (value_list);
gcry_sexp_release (value_pair);
- xfree (curve_name);
- es_fclose (stream);
- es_free (blob);
+ gcry_sexp_release (comment_list);
+
+ if (err)
+ {
+ xfree (curve_name);
+ xfree (comment_new);
+ mpint_list_free (mpis_new);
+ }
return err;
}
@@ -2071,11 +1700,6 @@
gpg_error_t err;
unsigned int i;
- /* FIXME: Although this sees to work, it not be correct if the
- lookup is done via name which might be "ecc" but actually it need
- to check the flags to see whether it is eddsa or ecdsa. Maybe
- the entire parameter controlled logic is too complicated and we
- would do better by just switching on the ssh_name. */
for (i = 0; i < DIM (ssh_key_types); i++)
if ((ssh_name && (! strcmp (ssh_name, ssh_key_types[i].ssh_identifier)))
|| (name && (! strcmp (name, ssh_key_types[i].identifier))))
@@ -2093,6 +1717,23 @@
}
+/* Lookup the ssh-identifier for the ECC curve CURVE_NAME. Returns
+ NULL if not found. */
+static const char *
+ssh_identifier_from_curve_name (const char *curve_name)
+{
+ int i;
+
+ for (i = 0; i < DIM (ssh_key_types); i++)
+ if (ssh_key_types[i].curve_name
+ && !strcmp (ssh_key_types[i].curve_name, curve_name))
+ return ssh_key_types[i].ssh_identifier;
+
+ return NULL;
+}
+
+
+
/* Receive a key from STREAM, according to the key specification given
as KEY_SPEC. Depending on SECRET, receive a secret or a public
key. If READ_COMMENT is true, receive a comment string as well.
@@ -2112,6 +1753,7 @@
char *curve_name = NULL;
+
err = stream_read_cstring (stream, &key_type);
if (err)
goto out;
@@ -2120,65 +1762,7 @@
if (err)
goto out;
- if ((spec.flags & SPEC_FLAG_IS_EdDSA))
- {
- /* The format of an EdDSA key is:
- * string key_type ("ssh-ed25519")
- * string public_key
- * string private_key
- *
- * Note that the private key is the concatenation of the private
- * key with the public key. Thus theres are 64 bytes; however
- * we only want the real 32 byte private key - Libgcrypt expects
- * this.
- */
- mpi_list = xtrycalloc (3, sizeof *mpi_list);
- if (!mpi_list)
- {
- err = gpg_error_from_syserror ();
- goto out;
- }
-
- err = stream_read_blob (stream, 0, &mpi_list[0]);
- if (err)
- goto out;
- if (secret)
- {
- u32 len = 0;
- unsigned char *buffer;
-
- /* Read string length. */
- err = stream_read_uint32 (stream, &len);
- if (err)
- goto out;
- if (len != 32 && len != 64)
- {
- err = gpg_error (GPG_ERR_BAD_SECKEY);
- goto out;
- }
- buffer = xtrymalloc_secure (32);
- if (!buffer)
- {
- err = gpg_error_from_syserror ();
- goto out;
- }
- err = stream_read_data (stream, buffer, 32);
- if (err)
- {
- xfree (buffer);
- goto out;
- }
- mpi_list[1] = gcry_mpi_set_opaque (NULL, buffer, 8*32);
- buffer = NULL;
- if (len == 64)
- {
- err = stream_read_skip (stream, 32);
- if (err)
- goto out;
- }
- }
- }
- else if ((spec.flags & SPEC_FLAG_IS_ECDSA))
+ if ((spec.flags & SPEC_FLAG_IS_ECDSA))
{
/* The format of an ECDSA key is:
* string key_type ("ecdsa-sha2-nistp256" |
@@ -2220,95 +1804,157 @@
goto out;
}
}
+ }
+
+ err = ssh_receive_mpint_list (stream, secret, spec, &mpi_list);
+ if (err)
+ goto out;
+
+ if (read_comment)
+ {
+ err = stream_read_cstring (stream, &comment);
+ if (err)
+ goto out;
+ }
+
+ if (secret)
+ elems = spec.elems_key_secret;
+ else
+ elems = spec.elems_key_public;
+
+ if (spec.key_modifier)
+ {
+ err = (*spec.key_modifier) (elems, mpi_list);
+ if (err)
+ goto out;
+ }
+
+ err = sexp_key_construct (&key, spec, secret, curve_name, mpi_list,
+ comment? comment:"");
+ if (err)
+ goto out;
- err = ssh_receive_mpint_list (stream, secret, spec, &mpi_list);
+ if (key_spec)
+ *key_spec = spec;
+ *key_new = key;
+
+ out:
+ mpint_list_free (mpi_list);
+ xfree (curve_name);
+ xfree (key_type);
+ xfree (comment);
+
+ return err;
+}
+
+/* Converts a key of type TYPE, whose key material is given in MPIS,
+ into a newly created binary blob, which is to be stored in
+ BLOB/BLOB_SIZE. Returns zero on success or an error code. */
+static gpg_error_t
+ssh_convert_key_to_blob (unsigned char **blob, size_t *blob_size,
+ ssh_key_type_spec_t *spec,
+ const char *curve_name, gcry_mpi_t *mpis)
+{
+ unsigned char *blob_new;
+ long int blob_size_new;
+ estream_t stream;
+ gpg_error_t err;
+ unsigned int i;
+
+ *blob = NULL;
+ *blob_size = 0;
+
+ blob_new = NULL;
+ stream = NULL;
+ err = 0;
+
+ stream = es_mopen (NULL, 0, 0, 1, NULL, NULL, "r+");
+ if (! stream)
+ {
+ err = gpg_error_from_syserror ();
+ goto out;
+ }
+
+ if ((spec->flags & SPEC_FLAG_IS_ECDSA) && curve_name)
+ {
+ const char *sshname = ssh_identifier_from_curve_name (curve_name);
+ if (!curve_name)
+ {
+ err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
+ goto out;
+ }
+ err = stream_write_cstring (stream, sshname);
+ if (err)
+ goto out;
+ err = stream_write_cstring (stream, curve_name);
if (err)
goto out;
}
else
{
- err = ssh_receive_mpint_list (stream, secret, spec, &mpi_list);
+ err = stream_write_cstring (stream, spec->ssh_identifier);
if (err)
goto out;
}
- if (read_comment)
+ for (i = 0; mpis[i]; i++)
+ if ((err = stream_write_mpi (stream, mpis[i])))
+ goto out;
+
+ blob_size_new = es_ftell (stream);
+ if (blob_size_new == -1)
{
- err = stream_read_cstring (stream, &comment);
- if (err)
- goto out;
+ err = gpg_error_from_syserror ();
+ goto out;
}
- if (secret)
- elems = spec.elems_key_secret;
- else
- elems = spec.elems_key_public;
+ err = es_fseek (stream, 0, SEEK_SET);
+ if (err)
+ goto out;
- if (spec.key_modifier)
+ blob_new = xtrymalloc (blob_size_new);
+ if (! blob_new)
{
- err = (*spec.key_modifier) (elems, mpi_list);
- if (err)
- goto out;
+ err = gpg_error_from_syserror ();
+ goto out;
}
- if ((spec.flags & SPEC_FLAG_IS_EdDSA))
- {
- if (secret)
- {
- err = gcry_sexp_build (&key, NULL,
- "(private-key(ecc(curve \"Ed25519\")"
- "(flags eddsa)(q %m)(d %m))"
- "(comment%s))",
- mpi_list[0], mpi_list[1],
- comment? comment:"");
- }
- else
- {
- err = gcry_sexp_build (&key, NULL,
- "(public-key(ecc(curve \"Ed25519\")"
- "(flags eddsa)(q %m))"
- "(comment%s))",
- mpi_list[0],
- comment? comment:"");
- }
- }
- else
- {
- err = sexp_key_construct (&key, spec, secret, curve_name, mpi_list,
- comment? comment:"");
- if (err)
- goto out;
- }
+ err = stream_read_data (stream, blob_new, blob_size_new);
+ if (err)
+ goto out;
- if (key_spec)
- *key_spec = spec;
- *key_new = key;
+ *blob = blob_new;
+ *blob_size = blob_size_new;
out:
- mpint_list_free (mpi_list);
- xfree (curve_name);
- xfree (key_type);
- xfree (comment);
+
+ if (stream)
+ es_fclose (stream);
+ if (err)
+ xfree (blob_new);
return err;
}
-/* Write the public key from KEY to STREAM in SSH key format. If
+/* Write the public key KEY_PUBLIC to STREAM in SSH key format. If
OVERRIDE_COMMENT is not NULL, it will be used instead of the
comment stored in the key. */
static gpg_error_t
-ssh_send_key_public (estream_t stream, gcry_sexp_t key,
+ssh_send_key_public (estream_t stream,
+ gcry_sexp_t key_public,
const char *override_comment)
{
ssh_key_type_spec_t spec;
+ gcry_mpi_t *mpi_list = NULL;
char *key_type = NULL;
+ char *curve;
char *comment = NULL;
- void *blob = NULL;
- size_t bloblen;
+ unsigned char *blob = NULL;
+ size_t blob_n;
gpg_error_t err;
- err = sexp_extract_identifier (key, &key_type);
+ err = sexp_extract_identifier (key_public, &key_type);
if (err)
goto out;
@@ -2316,36 +1962,32 @@
if (err)
goto out;
- err = ssh_key_to_blob (key, 0, spec, &blob, &bloblen);
+ err = sexp_key_extract (key_public, spec, NULL, &mpi_list, &curve, &comment);
if (err)
goto out;
- err = stream_write_string (stream, blob, bloblen);
+ err = ssh_convert_key_to_blob (&blob, &blob_n, &spec, curve, mpi_list);
if (err)
goto out;
- if (override_comment)
- err = stream_write_cstring (stream, override_comment);
- else
- {
- err = ssh_key_extract_comment (key, &comment);
- if (err)
- err = stream_write_cstring (stream, "(none)");
- else
- err = stream_write_cstring (stream, comment);
- }
+ err = stream_write_string (stream, blob, blob_n);
if (err)
goto out;
+ err = stream_write_cstring (stream,
+ override_comment? override_comment : comment);
+
out:
- xfree (key_type);
+
+ mpint_list_free (mpi_list);
+ xfree (curve);
xfree (comment);
- es_free (blob);
+ xfree (key_type);
+ xfree (blob);
return err;
}
-
/* Read a public key out of BLOB/BLOB_SIZE according to the key
specification given as KEY_SPEC, storing the new key in KEY_PUBLIC.
Returns zero on success or an error code. */
@@ -2354,11 +1996,13 @@
gcry_sexp_t *key_public,
ssh_key_type_spec_t *key_spec)
{
- gpg_error_t err;
estream_t blob_stream;
+ gpg_error_t err;
+
+ err = 0;
- blob_stream = es_fopenmem (0, "r+b");
- if (!blob_stream)
+ blob_stream = es_mopen (NULL, 0, 0, 1, NULL, NULL, "r+");
+ if (! blob_stream)
{
err = gpg_error_from_syserror ();
goto out;
@@ -2375,7 +2019,10 @@
err = ssh_receive_key (blob_stream, key_public, 0, 0, key_spec);
out:
- es_fclose (blob_stream);
+
+ if (blob_stream)
+ es_fclose (blob_stream);
+
return err;
}
@@ -2397,6 +2044,39 @@
}
+/* Converts the secret key KEY_SECRET into a public key, storing it in
+ KEY_PUBLIC. SPEC is the according key specification. Returns zero
+ on success or an error code. */
+static gpg_error_t
+key_secret_to_public (gcry_sexp_t *key_public,
+ ssh_key_type_spec_t spec, gcry_sexp_t key_secret)
+{
+ char *curve;
+ char *comment;
+ gcry_mpi_t *mpis;
+ gpg_error_t err;
+ int is_secret;
+
+ comment = NULL;
+ mpis = NULL;
+
+ err = sexp_key_extract (key_secret, spec, &is_secret, &mpis,
+ &curve, &comment);
+ if (err)
+ goto out;
+
+ err = sexp_key_construct (key_public, spec, 0, curve, mpis, comment);
+
+ out:
+
+ mpint_list_free (mpis);
+ xfree (comment);
+ xfree (curve);
+
+ return err;
+}
+
+
/* Check whether a smartcard is available and whether it has a usable
key. Store a copy of that key at R_PK and return 0. If no key is
available store NULL at R_PK and return an error code. If CARDSN
@@ -2436,7 +2116,7 @@
}
if (err)
{
- log_error (_("no authentication key for ssh on card: %s\n"),
+ log_error (_("error getting default authentication keyID of card: %s\n"),
gpg_strerror (err));
xfree (serialno);
return err;
@@ -2600,7 +2280,7 @@
key_counter = 0;
err = 0;
- key_blobs = es_fopenmem (0, "r+b");
+ key_blobs = es_mopen (NULL, 0, 0, 1, NULL, NULL, "r+b");
if (! key_blobs)
{
err = gpg_error_from_syserror ();
@@ -2695,12 +2375,20 @@
goto out;
}
- err = ssh_send_key_public (key_blobs, key_secret, NULL);
+ err = key_secret_to_public (&key_public, spec, key_secret);
if (err)
goto out;
+
gcry_sexp_release (key_secret);
key_secret = NULL;
+ err = ssh_send_key_public (key_blobs, key_public, NULL);
+ if (err)
+ goto out;
+
+ gcry_sexp_release (key_public);
+ key_public = NULL;
+
key_counter++;
}
err = 0;
@@ -2752,27 +2440,30 @@
return 0;
}
-
-/* This function signs the data described by CTRL. If HASH is is not
- NULL, (HASH,HASHLEN) overrides the hash stored in CTRL. This is to
- allow the use of signature algorithms that implement the hashing
- internally (e.g. Ed25519). On success the created signature is
- stored in ssh format at R_SIG and it's size at R_SIGLEN; the caller
- must use es_free to releaase this memory. */
+/* This function signs the data contained in CTRL, stores the created
+ signature in newly allocated memory in SIG and it's size in SIG_N;
+ SIG_ENCODER is the signature encoder to use. */
static gpg_error_t
data_sign (ctrl_t ctrl, ssh_key_type_spec_t *spec,
- const void *hash, size_t hashlen,
- unsigned char **r_sig, size_t *r_siglen)
+ unsigned char **sig, size_t *sig_n)
{
gpg_error_t err;
gcry_sexp_t signature_sexp = NULL;
estream_t stream = NULL;
- void *blob = NULL;
- size_t bloblen;
+ gcry_sexp_t valuelist = NULL;
+ gcry_sexp_t sublist = NULL;
+ gcry_mpi_t sig_value = NULL;
+ unsigned char *sig_blob = NULL;
+ size_t sig_blob_n = 0;
+ int ret;
+ unsigned int i;
+ const char *elems;
+ size_t elems_n;
+ gcry_mpi_t *mpis = NULL;
char hexgrip[40+1];
- *r_sig = NULL;
- *r_siglen = 0;
+ *sig = NULL;
+ *sig_n = 0;
/* Quick check to see whether we have a valid keygrip and convert it
to hex. */
@@ -2804,14 +2495,14 @@
gcry_sexp_release (key);
if (err)
goto out;
- prompt = xtryasprintf (L_("An ssh process requested the use of key%%0A"
- " %s%%0A"
- " (%s)%%0A"
- "Do you want to allow this?"),
+ prompt = xtryasprintf (_("An ssh process requested the use of key%%0A"
+ " %s%%0A"
+ " (%s)%%0A"
+ "Do you want to allow this?"),
fpr, comment? comment:"");
xfree (fpr);
gcry_free (comment);
- err = agent_get_confirmation (ctrl, prompt, L_("Allow"), L_("Deny"), 0);
+ err = agent_get_confirmation (ctrl, prompt, _("Allow"), _("Deny"), 0);
xfree (prompt);
if (err)
goto out;
@@ -2819,18 +2510,24 @@
/* Create signature. */
ctrl->use_auth_call = 1;
- err = agent_pksign_do (ctrl, NULL,
- L_("Please enter the passphrase "
- "for the ssh key%%0A %F%%0A (%c)"),
+ err = agent_pksign_do (ctrl,
+ _("Please enter the passphrase "
+ "for the ssh key%%0A %F%%0A (%c)"),
&signature_sexp,
- CACHE_MODE_SSH, ttl_from_sshcontrol,
- hash, hashlen);
+ CACHE_MODE_SSH, ttl_from_sshcontrol);
ctrl->use_auth_call = 0;
if (err)
goto out;
- stream = es_fopenmem (0, "r+b");
- if (!stream)
+ valuelist = gcry_sexp_nth (signature_sexp, 1);
+ if (! valuelist)
+ {
+ err = gpg_error (GPG_ERR_INV_SEXP);
+ goto out;
+ }
+
+ stream = es_mopen (NULL, 0, 0, 1, NULL, NULL, "r+");
+ if (! stream)
{
err = gpg_error_from_syserror ();
goto out;
@@ -2840,40 +2537,99 @@
if (err)
goto out;
- err = spec->signature_encoder (spec, stream, signature_sexp);
+ elems = spec->elems_signature;
+ elems_n = strlen (elems);
+
+ mpis = xtrycalloc (elems_n + 1, sizeof *mpis);
+ if (!mpis)
+ {
+ err = gpg_error_from_syserror ();
+ goto out;
+ }
+
+ for (i = 0; i < elems_n; i++)
+ {
+ sublist = gcry_sexp_find_token (valuelist, spec->elems_signature + i, 1);
+ if (! sublist)
+ {
+ err = gpg_error (GPG_ERR_INV_SEXP);
+ break;
+ }
+
+ sig_value = gcry_sexp_nth_mpi (sublist, 1, GCRYMPI_FMT_USG);
+ if (! sig_value)
+ {
+ err = gpg_error (GPG_ERR_INTERNAL); /* FIXME? */
+ break;
+ }
+ gcry_sexp_release (sublist);
+ sublist = NULL;
+
+ mpis[i] = sig_value;
+ }
+ if (err)
+ goto out;
+
+ err = spec->signature_encoder (spec, stream, mpis);
if (err)
goto out;
- err = es_fclose_snatch (stream, &blob, &bloblen);
+ sig_blob_n = es_ftell (stream);
+ if (sig_blob_n == -1)
+ {
+ err = gpg_error_from_syserror ();
+ goto out;
+ }
+
+ sig_blob = xtrymalloc (sig_blob_n);
+ if (! sig_blob)
+ {
+ err = gpg_error_from_syserror ();
+ goto out;
+ }
+
+ ret = es_fseek (stream, 0, SEEK_SET);
+ if (ret)
+ {
+ err = gpg_error_from_syserror ();
+ goto out;
+ }
+
+ err = stream_read_data (stream, sig_blob, sig_blob_n);
if (err)
goto out;
- stream = NULL;
- *r_sig = blob; blob = NULL;
- *r_siglen = bloblen;
+ *sig = sig_blob;
+ *sig_n = sig_blob_n;
out:
- xfree (blob);
- es_fclose (stream);
+
+ if (err)
+ xfree (sig_blob);
+
+ if (stream)
+ es_fclose (stream);
+ gcry_sexp_release (valuelist);
gcry_sexp_release (signature_sexp);
+ gcry_sexp_release (sublist);
+ mpint_list_free (mpis);
return err;
}
-
/* Handler for the "sign_request" command. */
static gpg_error_t
ssh_handler_sign_request (ctrl_t ctrl, estream_t request, estream_t response)
{
- gcry_sexp_t key = NULL;
+ gcry_sexp_t key;
ssh_key_type_spec_t spec;
unsigned char hash[MAX_DIGEST_LEN];
unsigned int hash_n;
unsigned char key_grip[20];
- unsigned char *key_blob = NULL;
+ unsigned char *key_blob;
u32 key_blob_size;
- unsigned char *data = NULL;
- unsigned char *sig = NULL;
+ unsigned char *data;
+ unsigned char *sig;
size_t sig_n;
u32 data_size;
u32 flags;
@@ -2881,6 +2637,11 @@
gpg_error_t ret_err;
int hash_algo;
+ key_blob = NULL;
+ data = NULL;
+ sig = NULL;
+ key = NULL;
+
/* Receive key. */
err = stream_read_string (request, 0, &key_blob, &key_blob_size);
@@ -2904,48 +2665,42 @@
hash_algo = spec.hash_algo;
if (!hash_algo)
hash_algo = GCRY_MD_SHA1; /* Use the default. */
- ctrl->digest.algo = hash_algo;
- if ((spec.flags & SPEC_FLAG_USE_PKCS1V2))
- ctrl->digest.raw_value = 0;
- else
- ctrl->digest.raw_value = 1;
+
+ /* Hash data. */
+ hash_n = gcry_md_get_algo_dlen (hash_algo);
+ if (! hash_n)
+ {
+ err = gpg_error (GPG_ERR_INTERNAL);
+ goto out;
+ }
+ err = data_hash (data, data_size, hash_algo, hash);
+ if (err)
+ goto out;
/* Calculate key grip. */
err = ssh_key_grip (key, key_grip);
if (err)
goto out;
- ctrl->have_keygrip = 1;
- memcpy (ctrl->keygrip, key_grip, 20);
-
- /* Hash data unless we use EdDSA. */
- if ((spec.flags & SPEC_FLAG_IS_EdDSA))
- {
- ctrl->digest.valuelen = 0;
- }
- else
- {
- hash_n = gcry_md_get_algo_dlen (hash_algo);
- if (!hash_n)
- {
- err = gpg_error (GPG_ERR_INTERNAL);
- goto out;
- }
- err = data_hash (data, data_size, hash_algo, hash);
- if (err)
- goto out;
- memcpy (ctrl->digest.value, hash, hash_n);
- ctrl->digest.valuelen = hash_n;
- }
/* Sign data. */
- if ((spec.flags & SPEC_FLAG_IS_EdDSA))
- err = data_sign (ctrl, &spec, data, data_size, &sig, &sig_n);
+
+ ctrl->digest.algo = hash_algo;
+ memcpy (ctrl->digest.value, hash, hash_n);
+ ctrl->digest.valuelen = hash_n;
+ if ((spec.flags & SPEC_FLAG_USE_PKCS1V2))
+ ctrl->digest.raw_value = 0;
else
- err = data_sign (ctrl, &spec, NULL, 0, &sig, &sig_n);
+ ctrl->digest.raw_value = 1;
+ ctrl->have_keygrip = 1;
+ memcpy (ctrl->keygrip, key_grip, 20);
+
+ err = data_sign (ctrl, &spec, &sig, &sig_n);
out:
+
/* Done. */
- if (!err)
+
+ if (! err)
{
ret_err = stream_write_byte (response, SSH_RESPONSE_SIGN_RESPONSE);
if (ret_err)
@@ -2956,8 +2711,6 @@
}
else
{
- log_error ("ssh sign request failed: %s <%s>\n",
- gpg_strerror (err), gpg_strsource (err));
ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE);
if (ret_err)
goto leave;
@@ -2968,35 +2721,54 @@
gcry_sexp_release (key);
xfree (key_blob);
xfree (data);
- es_free (sig);
+ xfree (sig);
return ret_err;
}
-
/* This function extracts the comment contained in the key
- s-expression KEY and stores a copy in COMMENT. Returns usual error
+ S-Expression KEY and stores a copy in COMMENT. Returns usual error
code. */
static gpg_error_t
-ssh_key_extract_comment (gcry_sexp_t key, char **r_comment)
+ssh_key_extract_comment (gcry_sexp_t key, char **comment)
{
gcry_sexp_t comment_list;
-
- *r_comment = NULL;
+ char *comment_new;
+ const char *data;
+ size_t data_n;
+ gpg_error_t err;
comment_list = gcry_sexp_find_token (key, "comment", 0);
- if (!comment_list)
- return gpg_error (GPG_ERR_INV_SEXP);
+ if (! comment_list)
+ {
+ err = gpg_error (GPG_ERR_INV_SEXP);
+ goto out;
+ }
+
+ data = gcry_sexp_nth_data (comment_list, 1, &data_n);
+ if (! data)
+ {
+ err = gpg_error (GPG_ERR_INV_SEXP);
+ goto out;
+ }
+
+ comment_new = make_cstring (data, data_n);
+ if (! comment_new)
+ {
+ err = gpg_error_from_syserror ();
+ goto out;
+ }
+
+ *comment = comment_new;
+ err = 0;
+
+ out:
- *r_comment = gcry_sexp_nth_string (comment_list, 1);
gcry_sexp_release (comment_list);
- if (!*r_comment)
- return gpg_error (GPG_ERR_INV_SEXP);
- return 0;
+ return err;
}
-
/* This function converts the key contained in the S-Expression KEY
into a buffer, which is protected by the passphrase PASSPHRASE.
Returns usual error code. */
@@ -3020,7 +2792,7 @@
gcry_sexp_sprint (key, GCRYSEXP_FMT_CANON, buffer_new, buffer_new_n);
/* FIXME: guarantee? */
- err = agent_protect (buffer_new, passphrase, buffer, buffer_n, 0);
+ err = agent_protect (buffer_new, passphrase, buffer, buffer_n);
out:
@@ -3050,8 +2822,7 @@
our key storage, don't do anything. When entering a new key also
add an entry to the sshcontrol file. */
static gpg_error_t
-ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
- gcry_sexp_t key, int ttl, int confirm)
+ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl, int confirm)
{
gpg_error_t err;
unsigned char key_grip_raw[20];
@@ -3059,10 +2830,11 @@
unsigned char *buffer = NULL;
size_t buffer_n;
char *description = NULL;
- const char *description2 = L_("Please re-enter this passphrase");
+ const char *description2 = _("Please re-enter this passphrase");
char *comment = NULL;
char *key_fpr = NULL;
const char *initial_errtext = NULL;
+ unsigned int i;
struct pin_entry_info_s *pi = NULL, *pi2;
err = ssh_key_grip (key, key_grip_raw);
@@ -3083,11 +2855,11 @@
goto out;
if ( asprintf (&description,
- L_("Please enter a passphrase to protect"
- " the received secret key%%0A"
- " %s%%0A"
- " %s%%0A"
- "within gpg-agent's key storage"),
+ _("Please enter a passphrase to protect"
+ " the received secret key%%0A"
+ " %s%%0A"
+ " %s%%0A"
+ "within gpg-agent's key storage"),
key_fpr, comment ? comment : "") < 0)
{
err = gpg_error_from_syserror ();
@@ -3103,7 +2875,6 @@
pi2 = pi + (sizeof *pi + 100 + 1);
pi->max_length = 100;
pi->max_tries = 1;
- pi->with_repeat = 1;
pi2->max_length = 100;
pi2->max_tries = 1;
pi2->check_cb = reenter_compare_cb;
@@ -3115,15 +2886,14 @@
if (err)
goto out;
- /* Unless the passphrase is empty or the pinentry told us that
- it already did the repetition check, ask to confirm it. */
- if (*pi->pin && !pi->repeat_okay)
+ /* Unless the passphrase is empty, ask to confirm it. */
+ if (pi->pin && *pi->pin)
{
err = agent_askpin (ctrl, description2, NULL, NULL, pi2, NULL, 0);
if (err == -1)
{ /* The re-entered one did not match and the user did not
hit cancel. */
- initial_errtext = L_("does not match - try again");
+ initial_errtext = _("does not match - try again");
goto next_try;
}
}
@@ -3138,13 +2908,15 @@
goto out;
/* Cache this passphrase. */
- bin2hex (key_grip_raw, 20, key_grip);
+ for (i = 0; i < 20; i++)
+ sprintf (key_grip + 2 * i, "%02X", key_grip_raw[i]);
+
err = agent_put_cache (key_grip, CACHE_MODE_SSH, pi->pin, ttl);
if (err)
goto out;
/* And add an entry to the sshcontrol file. */
- err = add_control_entry (ctrl, spec, key_grip, key_fpr, ttl, confirm);
+ err = add_control_entry (ctrl, key_grip, key_fpr, ttl, confirm);
out:
@@ -3188,7 +2960,6 @@
ssh_handler_add_identity (ctrl_t ctrl, estream_t request, estream_t response)
{
gpg_error_t ret_err;
- ssh_key_type_spec_t spec;
gpg_error_t err;
gcry_sexp_t key;
unsigned char b;
@@ -3200,7 +2971,7 @@
ttl = 0;
/* FIXME? */
- err = ssh_receive_key (request, &key, 1, 1, &spec);
+ err = ssh_receive_key (request, &key, 1, 1, NULL);
if (err)
goto out;
@@ -3239,7 +3010,7 @@
if (err)
goto out;
- err = ssh_identity_register (ctrl, &spec, key, ttl, confirm);
+ err = ssh_identity_register (ctrl, key, ttl, confirm);
out:
@@ -3427,16 +3198,21 @@
ssh_request_process (ctrl_t ctrl, estream_t stream_sock)
{
ssh_request_spec_t *spec;
- estream_t response = NULL;
- estream_t request = NULL;
+ estream_t response;
+ estream_t request;
unsigned char request_type;
gpg_error_t err;
- int send_err = 0;
+ int send_err;
int ret;
- unsigned char *request_data = NULL;
+ unsigned char *request_data;
u32 request_data_size;
u32 response_size;
+ request_data = NULL;
+ response = NULL;
+ request = NULL;
+ send_err = 0;
+
/* Create memory streams for request/response data. The entire
request will be stored in secure memory, since it might contain
secret key material. The response does not have to be stored in
@@ -3475,9 +3251,9 @@
}
if (spec->secret_input)
- request = es_mopen (NULL, 0, 0, 1, realloc_secure, gcry_free, "r+b");
+ request = es_mopen (NULL, 0, 0, 1, realloc_secure, gcry_free, "r+");
else
- request = es_mopen (NULL, 0, 0, 1, gcry_realloc, gcry_free, "r+b");
+ request = es_mopen (NULL, 0, 0, 1, gcry_realloc, gcry_free, "r+");
if (! request)
{
err = gpg_error_from_syserror ();
@@ -3494,7 +3270,7 @@
goto out;
es_rewind (request);
- response = es_fopenmem (0, "r+b");
+ response = es_mopen (NULL, 0, 0, 1, NULL, NULL, "r+");
if (! response)
{
err = gpg_error_from_syserror ();
@@ -3570,14 +3346,48 @@
leave:
- es_fclose (request);
- es_fclose (response);
- xfree (request_data);
+ if (request)
+ es_fclose (request);
+ if (response)
+ es_fclose (response);
+ xfree (request_data); /* FIXME? */
return !!err;
}
+/* Because the ssh protocol does not send us information about the the
+ current TTY setting, we use this function to use those from startup
+ or those explictly set. */
+static gpg_error_t
+setup_ssh_env (ctrl_t ctrl)
+{
+ static const char *names[] =
+ {"GPG_TTY", "DISPLAY", "TERM", "XAUTHORITY", "PINENTRY_USER_DATA", NULL};
+ gpg_error_t err = 0;
+ int idx;
+ const char *value;
+
+ for (idx=0; !err && names[idx]; idx++)
+ if ((value = session_env_getenv (opt.startup_env, names[idx])))
+ err = session_env_setenv (ctrl->session_env, names[idx], value);
+
+ if (!err && !ctrl->lc_ctype && opt.startup_lc_ctype)
+ if (!(ctrl->lc_ctype = xtrystrdup (opt.startup_lc_ctype)))
+ err = gpg_error_from_syserror ();
+
+ if (!err && !ctrl->lc_messages && opt.startup_lc_messages)
+ if (!(ctrl->lc_messages = xtrystrdup (opt.startup_lc_messages)))
+ err = gpg_error_from_syserror ();
+
+ if (err)
+ log_error ("error setting default session environment: %s\n",
+ gpg_strerror (err));
+
+ return err;
+}
+
+
/* Start serving client on SOCK_CLIENT. */
void
start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client)
@@ -3586,7 +3396,7 @@
gpg_error_t err;
int ret;
- err = agent_copy_startup_env (ctrl);
+ err = setup_ssh_env (ctrl);
if (err)
goto out;
@@ -3649,7 +3459,7 @@
u32 msglen;
estream_t request_stream, response_stream;
- if (agent_copy_startup_env (ctrl))
+ if (setup_ssh_env (ctrl))
goto leave; /* Error setting up the environment. */
if (maxreqlen < 5)
diff -Nru gnupg2-2.1.6~build1/agent/cvt-openpgp.c gnupg2-2.0.28/agent/cvt-openpgp.c
--- gnupg2-2.1.6~build1/agent/cvt-openpgp.c 2015-06-17 06:39:24.000000000 +0000
+++ gnupg2-2.0.28/agent/cvt-openpgp.c 1970-01-01 00:00:00.000000000 +0000
@@ -1,1489 +0,0 @@
-/* cvt-openpgp.c - Convert an OpenPGP key to our internal format.
- * Copyright (C) 1998-2002, 2006, 2009, 2010 Free Software Foundation, Inc.
- * Copyright (C) 2013, 2014 Werner Koch
- *
- * 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 .
- */
-
-#include
-#include
-#include
-#include
-#include
-
-#include "agent.h"
-#include "i18n.h"
-#include "cvt-openpgp.h"
-#include "host2net.h"
-
-
-/* Helper to pass data via the callback to do_unprotect. */
-struct try_do_unprotect_arg_s
-{
- int is_v4;
- int is_protected;
- int pubkey_algo;
- const char *curve;
- int protect_algo;
- char *iv;
- int ivlen;
- int s2k_mode;
- int s2k_algo;
- byte *s2k_salt;
- u32 s2k_count;
- u16 desired_csum;
- gcry_mpi_t *skey;
- size_t skeysize;
- int skeyidx;
- gcry_sexp_t *r_key;
-};
-
-
-
-/* Compute the keygrip from the public key and store it at GRIP. */
-static gpg_error_t
-get_keygrip (int pubkey_algo, const char *curve, gcry_mpi_t *pkey,
- unsigned char *grip)
-{
- gpg_error_t err;
- gcry_sexp_t s_pkey = NULL;
-
- switch (pubkey_algo)
- {
- case GCRY_PK_DSA:
- err = gcry_sexp_build (&s_pkey, NULL,
- "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
- pkey[0], pkey[1], pkey[2], pkey[3]);
- break;
-
- case GCRY_PK_ELG:
- err = gcry_sexp_build (&s_pkey, NULL,
- "(public-key(elg(p%m)(g%m)(y%m)))",
- pkey[0], pkey[1], pkey[2]);
- break;
-
- case GCRY_PK_RSA:
- err = gcry_sexp_build (&s_pkey, NULL,
- "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
- break;
-
- case GCRY_PK_ECC:
- if (!curve)
- err = gpg_error (GPG_ERR_BAD_SECKEY);
- else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL)))
- err = gcry_sexp_build (&s_pkey, NULL,
- "(public-key(ecc(curve %s)(flags eddsa)(q%m)))",
- "Ed25519", pkey[0]);
- else
- err = gcry_sexp_build (&s_pkey, NULL,
- "(public-key(ecc(curve %s)(q%m)))",
- curve, pkey[0]);
- break;
-
- default:
- err = gpg_error (GPG_ERR_PUBKEY_ALGO);
- break;
- }
-
- if (!err && !gcry_pk_get_keygrip (s_pkey, grip))
- err = gpg_error (GPG_ERR_INTERNAL);
-
- gcry_sexp_release (s_pkey);
- return err;
-}
-
-
-/* Convert a secret key given as algorithm id and an array of key
- parameters into our s-expression based format. Note that
- PUBKEY_ALGO has an gcrypt algorithm number. */
-static gpg_error_t
-convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey,
- const char *curve)
-{
- gpg_error_t err;
- gcry_sexp_t s_skey = NULL;
-
- *r_key = NULL;
-
- switch (pubkey_algo)
- {
- case GCRY_PK_DSA:
- err = gcry_sexp_build (&s_skey, NULL,
- "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
- skey[0], skey[1], skey[2], skey[3], skey[4]);
- break;
-
- case GCRY_PK_ELG:
- case GCRY_PK_ELG_E:
- err = gcry_sexp_build (&s_skey, NULL,
- "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
- skey[0], skey[1], skey[2], skey[3]);
- break;
-
-
- case GCRY_PK_RSA:
- case GCRY_PK_RSA_E:
- case GCRY_PK_RSA_S:
- err = gcry_sexp_build (&s_skey, NULL,
- "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
- skey[0], skey[1], skey[2], skey[3], skey[4],
- skey[5]);
- break;
-
- case GCRY_PK_ECC:
- if (!curve)
- err = gpg_error (GPG_ERR_BAD_SECKEY);
- else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL)))
- {
- /* Do not store the OID as name but the real name and the
- EdDSA flag. */
- err = gcry_sexp_build (&s_skey, NULL,
- "(private-key(ecc(curve%s)(flags eddsa)"
- "(q%m)(d%m)))",
- "Ed25519", skey[0], skey[1]);
- }
- else
- err = gcry_sexp_build (&s_skey, NULL,
- "(private-key(ecc(curve%s)(q%m)(d%m)))",
- curve, skey[0], skey[1]);
- break;
-
- default:
- err = gpg_error (GPG_ERR_PUBKEY_ALGO);
- break;
- }
-
- if (!err)
- *r_key = s_skey;
- return err;
-}
-
-
-/* Convert a secret key given as algorithm id, an array of key
- parameters, and an S-expression of the original OpenPGP transfer
- key into our s-expression based format. This is a variant of
- convert_secret_key which is used for the openpgp-native protection
- mode. Note that PUBKEY_ALGO has an gcrypt algorithm number. */
-static gpg_error_t
-convert_transfer_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey,
- const char *curve, gcry_sexp_t transfer_key)
-{
- gpg_error_t err;
- gcry_sexp_t s_skey = NULL;
-
- *r_key = NULL;
-
- switch (pubkey_algo)
- {
- case GCRY_PK_DSA:
- err = gcry_sexp_build
- (&s_skey, NULL,
- "(protected-private-key(dsa(p%m)(q%m)(g%m)(y%m)"
- "(protected openpgp-native%S)))",
- skey[0], skey[1], skey[2], skey[3], transfer_key);
- break;
-
- case GCRY_PK_ELG:
- err = gcry_sexp_build
- (&s_skey, NULL,
- "(protected-private-key(elg(p%m)(g%m)(y%m)"
- "(protected openpgp-native%S)))",
- skey[0], skey[1], skey[2], transfer_key);
- break;
-
-
- case GCRY_PK_RSA:
- err = gcry_sexp_build
- (&s_skey, NULL,
- "(protected-private-key(rsa(n%m)(e%m)"
- "(protected openpgp-native%S)))",
- skey[0], skey[1], transfer_key );
- break;
-
- case GCRY_PK_ECC:
- if (!curve)
- err = gpg_error (GPG_ERR_BAD_SECKEY);
- else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL)))
- {
- /* Do not store the OID as name but the real name and the
- EdDSA flag. */
- err = gcry_sexp_build
- (&s_skey, NULL,
- "(protected-private-key(ecc(curve%s)(flags eddsa)(q%m)"
- "(protected openpgp-native%S)))",
- "Ed25519", skey[0], transfer_key);
- }
- else
- err = gcry_sexp_build
- (&s_skey, NULL,
- "(protected-private-key(ecc(curve%s)(q%m)"
- "(protected openpgp-native%S)))",
- curve, skey[0], transfer_key);
- break;
-
- default:
- err = gpg_error (GPG_ERR_PUBKEY_ALGO);
- break;
- }
-
- if (!err)
- *r_key = s_skey;
- return err;
-}
-
-
-/* Hash the passphrase and set the key. */
-static gpg_error_t
-hash_passphrase_and_set_key (const char *passphrase,
- gcry_cipher_hd_t hd, int protect_algo,
- int s2k_mode, int s2k_algo,
- byte *s2k_salt, u32 s2k_count)
-{
- gpg_error_t err;
- unsigned char *key;
- size_t keylen;
-
- keylen = gcry_cipher_get_algo_keylen (protect_algo);
- if (!keylen)
- return gpg_error (GPG_ERR_INTERNAL);
-
- key = xtrymalloc_secure (keylen);
- if (!key)
- return gpg_error_from_syserror ();
-
- err = s2k_hash_passphrase (passphrase,
- s2k_algo, s2k_mode, s2k_salt, s2k_count,
- key, keylen);
- if (!err)
- err = gcry_cipher_setkey (hd, key, keylen);
-
- xfree (key);
- return err;
-}
-
-
-static u16
-checksum (const unsigned char *p, unsigned int n)
-{
- u16 a;
-
- for (a=0; n; n-- )
- a += *p++;
- return a;
-}
-
-
-/* Return the number of expected key parameters. */
-static void
-get_npkey_nskey (int pubkey_algo, size_t *npkey, size_t *nskey)
-{
- switch (pubkey_algo)
- {
- case GCRY_PK_RSA: *npkey = 2; *nskey = 6; break;
- case GCRY_PK_ELG: *npkey = 3; *nskey = 4; break;
- case GCRY_PK_ELG_E: *npkey = 3; *nskey = 4; break;
- case GCRY_PK_DSA: *npkey = 4; *nskey = 5; break;
- case GCRY_PK_ECC: *npkey = 1; *nskey = 2; break;
- default: *npkey = 0; *nskey = 0; break;
- }
-}
-
-
-/* Helper for do_unprotect. PUBKEY_ALOGO is the gcrypt algo number.
- On success R_NPKEY and R_NSKEY receive the number or parameters for
- the algorithm PUBKEY_ALGO and R_SKEYLEN the used length of
- SKEY. */
-static int
-prepare_unprotect (int pubkey_algo, gcry_mpi_t *skey, size_t skeysize,
- int s2k_mode,
- unsigned int *r_npkey, unsigned int *r_nskey,
- unsigned int *r_skeylen)
-{
- size_t npkey, nskey, skeylen;
- int i;
-
- /* Count the actual number of MPIs is in the array and set the
- remainder to NULL for easier processing later on. */
- for (skeylen = 0; skey[skeylen]; skeylen++)
- ;
- for (i=skeylen; i < skeysize; i++)
- skey[i] = NULL;
-
- /* Check some args. */
- if (s2k_mode == 1001)
- {
- /* Stub key. */
- log_info (_("secret key parts are not available\n"));
- return gpg_error (GPG_ERR_UNUSABLE_SECKEY);
- }
-
- if (gcry_pk_test_algo (pubkey_algo))
- {
- log_info (_("public key algorithm %d (%s) is not supported\n"),
- pubkey_algo, gcry_pk_algo_name (pubkey_algo));
- return gpg_error (GPG_ERR_PUBKEY_ALGO);
- }
-
- /* Get properties of the public key algorithm and do some
- consistency checks. Note that we need at least NPKEY+1 elements
- in the SKEY array. */
- get_npkey_nskey (pubkey_algo, &npkey, &nskey);
- if (!npkey || !nskey || npkey >= nskey)
- return gpg_error (GPG_ERR_INTERNAL);
- if (skeylen <= npkey)
- return gpg_error (GPG_ERR_MISSING_VALUE);
- if (nskey+1 >= skeysize)
- return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
-
- /* Check that the public key parameters are all available and not
- encrypted. */
- for (i=0; i < npkey; i++)
- {
- if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_USER1))
- return gpg_error (GPG_ERR_BAD_SECKEY);
- }
-
- if (r_npkey)
- *r_npkey = npkey;
- if (r_nskey)
- *r_nskey = nskey;
- if (r_skeylen)
- *r_skeylen = skeylen;
- return 0;
-}
-
-
-/* Note that this function modifies SKEY. SKEYSIZE is the allocated
- size of the array including the NULL item; this is used for a
- bounds check. On success a converted key is stored at R_KEY. */
-static int
-do_unprotect (const char *passphrase,
- int pkt_version, int pubkey_algo, int is_protected,
- const char *curve, gcry_mpi_t *skey, size_t skeysize,
- int protect_algo, void *protect_iv, size_t protect_ivlen,
- int s2k_mode, int s2k_algo, byte *s2k_salt, u32 s2k_count,
- u16 desired_csum, gcry_sexp_t *r_key)
-{
- gpg_error_t err;
- unsigned int npkey, nskey, skeylen;
- gcry_cipher_hd_t cipher_hd = NULL;
- u16 actual_csum;
- size_t nbytes;
- int i;
- gcry_mpi_t tmpmpi;
-
- *r_key = NULL;
-
- err = prepare_unprotect (pubkey_algo, skey, skeysize, s2k_mode,
- &npkey, &nskey, &skeylen);
- if (err)
- return err;
-
- /* Check whether SKEY is at all protected. If it is not protected
- merely verify the checksum. */
- if (!is_protected)
- {
- actual_csum = 0;
- for (i=npkey; i < nskey; i++)
- {
- if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_USER1))
- return gpg_error (GPG_ERR_BAD_SECKEY);
-
- if (gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE))
- {
- unsigned int nbits;
- const unsigned char *buffer;
- buffer = gcry_mpi_get_opaque (skey[i], &nbits);
- nbytes = (nbits+7)/8;
- actual_csum += checksum (buffer, nbytes);
- }
- else
- {
- unsigned char *buffer;
-
- err = gcry_mpi_aprint (GCRYMPI_FMT_PGP, &buffer, &nbytes,
- skey[i]);
- if (!err)
- actual_csum += checksum (buffer, nbytes);
- xfree (buffer);
- }
- if (err)
- return err;
- }
-
- if (actual_csum != desired_csum)
- return gpg_error (GPG_ERR_CHECKSUM);
-
- goto do_convert;
- }
-
-
- if (gcry_cipher_test_algo (protect_algo))
- {
- /* The algorithm numbers are Libgcrypt numbers but fortunately
- the OpenPGP algorithm numbers map one-to-one to the Libgcrypt
- numbers. */
- log_info (_("protection algorithm %d (%s) is not supported\n"),
- protect_algo, gnupg_cipher_algo_name (protect_algo));
- return gpg_error (GPG_ERR_CIPHER_ALGO);
- }
-
- if (gcry_md_test_algo (s2k_algo))
- {
- log_info (_("protection hash algorithm %d (%s) is not supported\n"),
- s2k_algo, gcry_md_algo_name (s2k_algo));
- return gpg_error (GPG_ERR_DIGEST_ALGO);
- }
-
- err = gcry_cipher_open (&cipher_hd, protect_algo,
- GCRY_CIPHER_MODE_CFB,
- (GCRY_CIPHER_SECURE
- | (protect_algo >= 100 ?
- 0 : GCRY_CIPHER_ENABLE_SYNC)));
- if (err)
- {
- log_error ("failed to open cipher_algo %d: %s\n",
- protect_algo, gpg_strerror (err));
- return err;
- }
-
- err = hash_passphrase_and_set_key (passphrase, cipher_hd, protect_algo,
- s2k_mode, s2k_algo, s2k_salt, s2k_count);
- if (err)
- {
- gcry_cipher_close (cipher_hd);
- return err;
- }
-
- gcry_cipher_setiv (cipher_hd, protect_iv, protect_ivlen);
-
- actual_csum = 0;
- if (pkt_version >= 4)
- {
- int ndata;
- unsigned int ndatabits;
- const unsigned char *p;
- unsigned char *data;
- u16 csum_pgp7 = 0;
-
- if (!gcry_mpi_get_flag (skey[npkey], GCRYMPI_FLAG_OPAQUE ))
- {
- gcry_cipher_close (cipher_hd);
- return gpg_error (GPG_ERR_BAD_SECKEY);
- }
- p = gcry_mpi_get_opaque (skey[npkey], &ndatabits);
- ndata = (ndatabits+7)/8;
-
- if (ndata > 1)
- csum_pgp7 = buf16_to_u16 (p+ndata-2);
- data = xtrymalloc_secure (ndata);
- if (!data)
- {
- err = gpg_error_from_syserror ();
- gcry_cipher_close (cipher_hd);
- return err;
- }
- gcry_cipher_decrypt (cipher_hd, data, ndata, p, ndata);
-
- p = data;
- if (is_protected == 2)
- {
- /* This is the new SHA1 checksum method to detect tampering
- with the key as used by the Klima/Rosa attack. */
- desired_csum = 0;
- actual_csum = 1; /* Default to bad checksum. */
-
- if (ndata < 20)
- log_error ("not enough bytes for SHA-1 checksum\n");
- else
- {
- gcry_md_hd_t h;
-
- if (gcry_md_open (&h, GCRY_MD_SHA1, 1))
- BUG(); /* Algo not available. */
- gcry_md_write (h, data, ndata - 20);
- gcry_md_final (h);
- if (!memcmp (gcry_md_read (h, GCRY_MD_SHA1), data+ndata-20, 20))
- actual_csum = 0; /* Digest does match. */
- gcry_md_close (h);
- }
- }
- else
- {
- /* Old 16 bit checksum method. */
- if (ndata < 2)
- {
- log_error ("not enough bytes for checksum\n");
- desired_csum = 0;
- actual_csum = 1; /* Mark checksum bad. */
- }
- else
- {
- desired_csum = buf16_to_u16 (data+ndata-2);
- actual_csum = checksum (data, ndata-2);
- if (desired_csum != actual_csum)
- {
- /* This is a PGP 7.0.0 workaround */
- desired_csum = csum_pgp7; /* Take the encrypted one. */
- }
- }
- }
-
- /* Better check it here. Otherwise the gcry_mpi_scan would fail
- because the length may have an arbitrary value. */
- if (desired_csum == actual_csum)
- {
- for (i=npkey; i < nskey; i++ )
- {
- if (gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_PGP, p, ndata, &nbytes))
- {
- /* Checksum was okay, but not correctly decrypted. */
- desired_csum = 0;
- actual_csum = 1; /* Mark checksum bad. */
- break;
- }
- gcry_mpi_release (skey[i]);
- skey[i] = tmpmpi;
- ndata -= nbytes;
- p += nbytes;
- }
- skey[i] = NULL;
- skeylen = i;
- assert (skeylen <= skeysize);
-
- /* Note: at this point NDATA should be 2 for a simple
- checksum or 20 for the sha1 digest. */
- }
- xfree(data);
- }
- else /* Packet version <= 3. */
- {
- unsigned char *buffer;
-
- for (i = npkey; i < nskey; i++)
- {
- const unsigned char *p;
- size_t ndata;
- unsigned int ndatabits;
-
- if (!skey[i] || !gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE))
- {
- gcry_cipher_close (cipher_hd);
- return gpg_error (GPG_ERR_BAD_SECKEY);
- }
- p = gcry_mpi_get_opaque (skey[i], &ndatabits);
- ndata = (ndatabits+7)/8;
-
- if (!(ndata >= 2) || !(ndata == (buf16_to_ushort (p) + 7)/8 + 2))
- {
- gcry_cipher_close (cipher_hd);
- return gpg_error (GPG_ERR_BAD_SECKEY);
- }
-
- buffer = xtrymalloc_secure (ndata);
- if (!buffer)
- {
- err = gpg_error_from_syserror ();
- gcry_cipher_close (cipher_hd);
- return err;
- }
-
- gcry_cipher_sync (cipher_hd);
- buffer[0] = p[0];
- buffer[1] = p[1];
- gcry_cipher_decrypt (cipher_hd, buffer+2, ndata-2, p+2, ndata-2);
- actual_csum += checksum (buffer, ndata);
- err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_PGP, buffer, ndata, &ndata);
- xfree (buffer);
- if (err)
- {
- /* Checksum was okay, but not correctly decrypted. */
- desired_csum = 0;
- actual_csum = 1; /* Mark checksum bad. */
- break;
- }
- gcry_mpi_release (skey[i]);
- skey[i] = tmpmpi;
- }
- }
- gcry_cipher_close (cipher_hd);
-
- /* Now let's see whether we have used the correct passphrase. */
- if (actual_csum != desired_csum)
- return gpg_error (GPG_ERR_BAD_PASSPHRASE);
-
- do_convert:
- if (nskey != skeylen)
- err = gpg_error (GPG_ERR_BAD_SECKEY);
- else
- err = convert_secret_key (r_key, pubkey_algo, skey, curve);
- if (err)
- return err;
-
- /* The checksum may fail, thus we also check the key itself. */
- err = gcry_pk_testkey (*r_key);
- if (err)
- {
- gcry_sexp_release (*r_key);
- *r_key = NULL;
- return gpg_error (GPG_ERR_BAD_PASSPHRASE);
- }
-
- return 0;
-}
-
-
-/* Callback function to try the unprotection from the passphrase query
- code. */
-static int
-try_do_unprotect_cb (struct pin_entry_info_s *pi)
-{
- gpg_error_t err;
- struct try_do_unprotect_arg_s *arg = pi->check_cb_arg;
-
- err = do_unprotect (pi->pin,
- arg->is_v4? 4:3,
- arg->pubkey_algo, arg->is_protected,
- arg->curve,
- arg->skey, arg->skeysize,
- arg->protect_algo, arg->iv, arg->ivlen,
- arg->s2k_mode, arg->s2k_algo,
- arg->s2k_salt, arg->s2k_count,
- arg->desired_csum, arg->r_key);
- /* SKEY may be modified now, thus we need to re-compute SKEYIDX. */
- for (arg->skeyidx = 0; (arg->skeyidx < arg->skeysize
- && arg->skey[arg->skeyidx]); arg->skeyidx++)
- ;
- return err;
-}
-
-
-/* See convert_from_openpgp for the core of the description. This
- function adds an optional PASSPHRASE argument and uses this to
- silently decrypt the key; CACHE_NONCE and R_PASSPHRASE must both be
- NULL in this mode. */
-static gpg_error_t
-convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
- unsigned char *grip, const char *prompt,
- const char *cache_nonce, const char *passphrase,
- unsigned char **r_key, char **r_passphrase)
-{
- gpg_error_t err;
- int unattended;
- int from_native;
- gcry_sexp_t top_list;
- gcry_sexp_t list = NULL;
- const char *value;
- size_t valuelen;
- char *string;
- int idx;
- int is_v4, is_protected;
- int pubkey_algo;
- int protect_algo = 0;
- char iv[16];
- int ivlen = 0;
- int s2k_mode = 0;
- int s2k_algo = 0;
- byte s2k_salt[8];
- u32 s2k_count = 0;
- size_t npkey, nskey;
- gcry_mpi_t skey[10]; /* We support up to 9 parameters. */
- char *curve = NULL;
- u16 desired_csum;
- int skeyidx = 0;
- gcry_sexp_t s_skey = NULL;
-
- *r_key = NULL;
- if (r_passphrase)
- *r_passphrase = NULL;
- unattended = !r_passphrase;
- from_native = (!cache_nonce && passphrase && !r_passphrase);
-
- top_list = gcry_sexp_find_token (s_pgp, "openpgp-private-key", 0);
- if (!top_list)
- goto bad_seckey;
-
- list = gcry_sexp_find_token (top_list, "version", 0);
- if (!list)
- goto bad_seckey;
- value = gcry_sexp_nth_data (list, 1, &valuelen);
- if (!value || valuelen != 1 || !(value[0] == '3' || value[0] == '4'))
- goto bad_seckey;
- is_v4 = (value[0] == '4');
-
- gcry_sexp_release (list);
- list = gcry_sexp_find_token (top_list, "protection", 0);
- if (!list)
- goto bad_seckey;
- value = gcry_sexp_nth_data (list, 1, &valuelen);
- if (!value)
- goto bad_seckey;
- if (valuelen == 4 && !memcmp (value, "sha1", 4))
- is_protected = 2;
- else if (valuelen == 3 && !memcmp (value, "sum", 3))
- is_protected = 1;
- else if (valuelen == 4 && !memcmp (value, "none", 4))
- is_protected = 0;
- else
- goto bad_seckey;
-
- if (is_protected)
- {
- string = gcry_sexp_nth_string (list, 2);
- if (!string)
- goto bad_seckey;
- protect_algo = gcry_cipher_map_name (string);
- xfree (string);
-
- value = gcry_sexp_nth_data (list, 3, &valuelen);
- if (!value || !valuelen || valuelen > sizeof iv)
- goto bad_seckey;
- memcpy (iv, value, valuelen);
- ivlen = valuelen;
-
- string = gcry_sexp_nth_string (list, 4);
- if (!string)
- goto bad_seckey;
- s2k_mode = strtol (string, NULL, 10);
- xfree (string);
-
- string = gcry_sexp_nth_string (list, 5);
- if (!string)
- goto bad_seckey;
- s2k_algo = gcry_md_map_name (string);
- xfree (string);
-
- value = gcry_sexp_nth_data (list, 6, &valuelen);
- if (!value || !valuelen || valuelen > sizeof s2k_salt)
- goto bad_seckey;
- memcpy (s2k_salt, value, valuelen);
-
- string = gcry_sexp_nth_string (list, 7);
- if (!string)
- goto bad_seckey;
- s2k_count = strtoul (string, NULL, 10);
- xfree (string);
- }
-
- gcry_sexp_release (list);
- list = gcry_sexp_find_token (top_list, "algo", 0);
- if (!list)
- goto bad_seckey;
- string = gcry_sexp_nth_string (list, 1);
- if (!string)
- goto bad_seckey;
- pubkey_algo = gcry_pk_map_name (string);
- xfree (string);
-
- get_npkey_nskey (pubkey_algo, &npkey, &nskey);
- if (!npkey || !nskey || npkey >= nskey)
- goto bad_seckey;
-
- if (npkey == 1) /* This is ECC */
- {
- gcry_sexp_release (list);
- list = gcry_sexp_find_token (top_list, "curve", 0);
- if (!list)
- goto bad_seckey;
- curve = gcry_sexp_nth_string (list, 1);
- if (!curve)
- goto bad_seckey;
- }
-
- gcry_sexp_release (list);
- list = gcry_sexp_find_token (top_list, "skey", 0);
- if (!list)
- goto bad_seckey;
- for (idx=0;;)
- {
- int is_enc;
-
- value = gcry_sexp_nth_data (list, ++idx, &valuelen);
- if (!value && skeyidx >= npkey)
- break; /* Ready. */
-
- /* Check for too many parameters. Note that depending on the
- protection mode and version number we may see less than NSKEY
- (but at least NPKEY+1) parameters. */
- if (idx >= 2*nskey)
- goto bad_seckey;
- if (skeyidx >= DIM (skey)-1)
- goto bad_seckey;
-
- if (!value || valuelen != 1 || !(value[0] == '_' || value[0] == 'e'))
- goto bad_seckey;
- is_enc = (value[0] == 'e');
- value = gcry_sexp_nth_data (list, ++idx, &valuelen);
- if (!value || !valuelen)
- goto bad_seckey;
- if (is_enc || curve)
- {
- /* Encrypted parameters and ECC parameters need or can be
- stored as opaque. */
- skey[skeyidx] = gcry_mpi_set_opaque_copy (NULL, value, valuelen*8);
- if (!skey[skeyidx])
- goto outofmem;
- if (is_enc)
- gcry_mpi_set_flag (skey[skeyidx], GCRYMPI_FLAG_USER1);
- }
- else
- {
- if (gcry_mpi_scan (skey + skeyidx, GCRYMPI_FMT_STD,
- value, valuelen, NULL))
- goto bad_seckey;
- }
- skeyidx++;
- }
- skey[skeyidx++] = NULL;
-
- gcry_sexp_release (list);
- list = gcry_sexp_find_token (top_list, "csum", 0);
- if (list)
- {
- string = gcry_sexp_nth_string (list, 1);
- if (!string)
- goto bad_seckey;
- desired_csum = strtoul (string, NULL, 10);
- xfree (string);
- }
- else
- desired_csum = 0;
-
-
- gcry_sexp_release (list); list = NULL;
- gcry_sexp_release (top_list); top_list = NULL;
-
-#if 0
- log_debug ("XXX is_v4=%d\n", is_v4);
- log_debug ("XXX pubkey_algo=%d\n", pubkey_algo);
- log_debug ("XXX is_protected=%d\n", is_protected);
- log_debug ("XXX protect_algo=%d\n", protect_algo);
- log_printhex ("XXX iv", iv, ivlen);
- log_debug ("XXX ivlen=%d\n", ivlen);
- log_debug ("XXX s2k_mode=%d\n", s2k_mode);
- log_debug ("XXX s2k_algo=%d\n", s2k_algo);
- log_printhex ("XXX s2k_salt", s2k_salt, sizeof s2k_salt);
- log_debug ("XXX s2k_count=%lu\n", (unsigned long)s2k_count);
- log_debug ("XXX curve='%s'\n", curve);
- for (idx=0; skey[idx]; idx++)
- gcry_log_debugmpi (gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_USER1)
- ? "skey(e)" : "skey(_)", skey[idx]);
-#endif /*0*/
-
- err = get_keygrip (pubkey_algo, curve, skey, grip);
- if (err)
- goto leave;
-
- if (!from_native && !agent_key_available (grip))
- {
- err = gpg_error (GPG_ERR_EEXIST);
- goto leave;
- }
-
- if (unattended && !from_native)
- {
- err = prepare_unprotect (pubkey_algo, skey, DIM(skey), s2k_mode,
- NULL, NULL, NULL);
- if (err)
- goto leave;
-
- err = convert_transfer_key (&s_skey, pubkey_algo, skey, curve, s_pgp);
- if (err)
- goto leave;
- }
- else
- {
- struct pin_entry_info_s *pi;
- struct try_do_unprotect_arg_s pi_arg;
-
- pi = xtrycalloc_secure (1, sizeof (*pi) + 100);
- if (!pi)
- return gpg_error_from_syserror ();
- pi->max_length = 100;
- pi->min_digits = 0; /* We want a real passphrase. */
- pi->max_digits = 16;
- pi->max_tries = 3;
- pi->check_cb = try_do_unprotect_cb;
- pi->check_cb_arg = &pi_arg;
- pi_arg.is_v4 = is_v4;
- pi_arg.is_protected = is_protected;
- pi_arg.pubkey_algo = pubkey_algo;
- pi_arg.curve = curve;
- pi_arg.protect_algo = protect_algo;
- pi_arg.iv = iv;
- pi_arg.ivlen = ivlen;
- pi_arg.s2k_mode = s2k_mode;
- pi_arg.s2k_algo = s2k_algo;
- pi_arg.s2k_salt = s2k_salt;
- pi_arg.s2k_count = s2k_count;
- pi_arg.desired_csum = desired_csum;
- pi_arg.skey = skey;
- pi_arg.skeysize = DIM (skey);
- pi_arg.skeyidx = skeyidx;
- pi_arg.r_key = &s_skey;
-
- err = gpg_error (GPG_ERR_BAD_PASSPHRASE);
- if (!is_protected)
- {
- err = try_do_unprotect_cb (pi);
- }
- else if (cache_nonce)
- {
- char *cache_value;
-
- cache_value = agent_get_cache (cache_nonce, CACHE_MODE_NONCE);
- if (cache_value)
- {
- if (strlen (cache_value) < pi->max_length)
- strcpy (pi->pin, cache_value);
- xfree (cache_value);
- }
- if (*pi->pin)
- err = try_do_unprotect_cb (pi);
- }
- else if (from_native)
- {
- if (strlen (passphrase) < pi->max_length)
- strcpy (pi->pin, passphrase);
- err = try_do_unprotect_cb (pi);
- }
- if (gpg_err_code (err) == GPG_ERR_BAD_PASSPHRASE && !from_native)
- err = agent_askpin (ctrl, prompt, NULL, NULL, pi, NULL, 0);
- skeyidx = pi_arg.skeyidx;
- if (!err && r_passphrase && is_protected)
- {
- *r_passphrase = xtrystrdup (pi->pin);
- if (!*r_passphrase)
- err = gpg_error_from_syserror ();
- }
- xfree (pi);
- if (err)
- goto leave;
- }
-
- /* Save some memory and get rid of the SKEY array now. */
- for (idx=0; idx < skeyidx; idx++)
- gcry_mpi_release (skey[idx]);
- skeyidx = 0;
-
- /* Note that the padding is not required - we use it only because
- that function allows us to create the result in secure memory. */
- err = make_canon_sexp_pad (s_skey, 1, r_key, NULL);
-
- leave:
- xfree (curve);
- gcry_sexp_release (s_skey);
- gcry_sexp_release (list);
- gcry_sexp_release (top_list);
- for (idx=0; idx < skeyidx; idx++)
- gcry_mpi_release (skey[idx]);
- if (err && r_passphrase)
- {
- xfree (*r_passphrase);
- *r_passphrase = NULL;
- }
- return err;
-
- bad_seckey:
- err = gpg_error (GPG_ERR_BAD_SECKEY);
- goto leave;
-
- outofmem:
- err = gpg_error (GPG_ERR_ENOMEM);
- goto leave;
-
-}
-
-
-/* Convert an OpenPGP transfer key into our internal format. Before
- asking for a passphrase we check whether the key already exists in
- our key storage. S_PGP is the OpenPGP key in transfer format. If
- CACHE_NONCE is given the passphrase will be looked up in the cache.
- On success R_KEY will receive a canonical encoded S-expression with
- the unprotected key in our internal format; the caller needs to
- release that memory. The passphrase used to decrypt the OpenPGP
- key will be returned at R_PASSPHRASE; the caller must release this
- passphrase. If R_PASSPHRASE is NULL the unattended conversion mode
- will be used which uses the openpgp-native protection format for
- the key. The keygrip will be stored at the 20 byte buffer pointed
- to by GRIP. On error NULL is stored at all return arguments. */
-gpg_error_t
-convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
- unsigned char *grip, const char *prompt,
- const char *cache_nonce,
- unsigned char **r_key, char **r_passphrase)
-{
- return convert_from_openpgp_main (ctrl, s_pgp, grip, prompt,
- cache_nonce, NULL,
- r_key, r_passphrase);
-}
-
-/* This function is called by agent_unprotect to re-protect an
- openpgp-native protected private-key into the standard private-key
- protection format. */
-gpg_error_t
-convert_from_openpgp_native (ctrl_t ctrl,
- gcry_sexp_t s_pgp, const char *passphrase,
- unsigned char **r_key)
-{
- gpg_error_t err;
- unsigned char grip[20];
-
- if (!passphrase)
- return gpg_error (GPG_ERR_INTERNAL);
-
- err = convert_from_openpgp_main (ctrl, s_pgp, grip, NULL,
- NULL, passphrase,
- r_key, NULL);
-
- /* On success try to re-write the key. */
- if (!err)
- {
- if (*passphrase)
- {
- unsigned char *protectedkey = NULL;
- size_t protectedkeylen;
-
- if (!agent_protect (*r_key, passphrase,
- &protectedkey, &protectedkeylen,
- ctrl->s2k_count))
- agent_write_private_key (grip, protectedkey, protectedkeylen, 1);
- xfree (protectedkey);
- }
- else
- {
- /* Empty passphrase: write key without protection. */
- agent_write_private_key (grip,
- *r_key,
- gcry_sexp_canon_len (*r_key, 0, NULL,NULL),
- 1);
- }
- }
-
- return err;
-}
-
-
-/* Given an ARRAY of mpis with the key parameters, protect the secret
- parameters in that array and replace them by one opaque encoded
- mpi. NPKEY is the number of public key parameters and NSKEY is
- the number of secret key parameters (including the public ones).
- On success the array will have NPKEY+1 elements. */
-static gpg_error_t
-apply_protection (gcry_mpi_t *array, int npkey, int nskey,
- const char *passphrase,
- int protect_algo, void *protect_iv, size_t protect_ivlen,
- int s2k_mode, int s2k_algo, byte *s2k_salt, u32 s2k_count)
-{
- gpg_error_t err;
- int i, j;
- gcry_cipher_hd_t cipherhd;
- unsigned char *bufarr[10];
- size_t narr[10];
- unsigned int nbits[10];
- int ndata;
- unsigned char *p, *data;
-
- assert (npkey < nskey);
- assert (nskey < DIM (bufarr));
-
- /* Collect only the secret key parameters into BUFARR et al and
- compute the required size of the data buffer. */
- ndata = 20; /* Space for the SHA-1 checksum. */
- for (i = npkey, j = 0; i < nskey; i++, j++ )
- {
- if (gcry_mpi_get_flag (array[i], GCRYMPI_FLAG_OPAQUE))
- {
- const unsigned char *s;
- unsigned int n;
-
- s = gcry_mpi_get_opaque (array[i], &n);
- if (!s)
- {
- s = "";
- n = 0;
- }
- /* Strip leading zero bits. */
- for (; n >= 8 && !*s; s++, n -= 8)
- ;
- if (n >= 8 && !(*s & 0x80))
- if (--n >= 7 && !(*s & 0x40))
- if (--n >= 6 && !(*s & 0x20))
- if (--n >= 5 && !(*s & 0x10))
- if (--n >= 4 && !(*s & 0x08))
- if (--n >= 3 && !(*s & 0x04))
- if (--n >= 2 && !(*s & 0x02))
- if (--n >= 1 && !(*s & 0x01))
- --n;
-
- nbits[j] = n;
- n = (n+7)/8;
- narr[j] = n;
- bufarr[j] = (gcry_is_secure (s)? xtrymalloc_secure (n?n:1)
- /* */ : xtrymalloc (n?n:1));
- if (!bufarr[j])
- {
- err = gpg_error_from_syserror ();
- for (i = 0; i < j; i++)
- xfree (bufarr[i]);
- return err;
- }
- memcpy (bufarr[j], s, n);
- }
- else
- {
- err = gcry_mpi_aprint (GCRYMPI_FMT_USG, bufarr+j, narr+j, array[i]);
- if (err)
- {
- for (i = 0; i < j; i++)
- xfree (bufarr[i]);
- return err;
- }
- nbits[j] = gcry_mpi_get_nbits (array[i]);
- }
- ndata += 2 + narr[j];
- }
-
- /* Allocate data buffer and stuff it with the secret key parameters. */
- data = xtrymalloc_secure (ndata);
- if (!data)
- {
- err = gpg_error_from_syserror ();
- for (i = 0; i < (nskey-npkey); i++ )
- xfree (bufarr[i]);
- return err;
- }
- p = data;
- for (i = 0; i < (nskey-npkey); i++ )
- {
- *p++ = nbits[i] >> 8 ;
- *p++ = nbits[i];
- memcpy (p, bufarr[i], narr[i]);
- p += narr[i];
- xfree (bufarr[i]);
- bufarr[i] = NULL;
- }
- assert (p == data + ndata - 20);
-
- /* Append a hash of the secret key parameters. */
- gcry_md_hash_buffer (GCRY_MD_SHA1, p, data, ndata - 20);
-
- /* Encrypt it. */
- err = gcry_cipher_open (&cipherhd, protect_algo,
- GCRY_CIPHER_MODE_CFB, GCRY_CIPHER_SECURE);
- if (!err)
- err = hash_passphrase_and_set_key (passphrase, cipherhd, protect_algo,
- s2k_mode, s2k_algo, s2k_salt, s2k_count);
- if (!err)
- err = gcry_cipher_setiv (cipherhd, protect_iv, protect_ivlen);
- if (!err)
- err = gcry_cipher_encrypt (cipherhd, data, ndata, NULL, 0);
- gcry_cipher_close (cipherhd);
- if (err)
- {
- xfree (data);
- return err;
- }
-
- /* Replace the secret key parameters in the array by one opaque value. */
- for (i = npkey; i < nskey; i++ )
- {
- gcry_mpi_release (array[i]);
- array[i] = NULL;
- }
- array[npkey] = gcry_mpi_set_opaque (NULL, data, ndata*8);
- return 0;
-}
-
-
-/*
- * Examining S_KEY in S-Expression and extract data.
- * When REQ_PRIVATE_KEY_DATA == 1, S_KEY's CAR should be 'private-key',
- * but it also allows shadowed or protected versions.
- * On success, it returns 0, otherwise error number.
- * R_ALGONAME is static string which is no need to free by caller.
- * R_NPKEY is pointer to number of public key data.
- * R_NSKEY is pointer to number of private key data.
- * R_ELEMS is static string which is no need to free by caller.
- * ARRAY contains public and private key data.
- * ARRAYSIZE is the allocated size of the array for cross-checking.
- * R_CURVE is pointer to S-Expression of the curve (can be NULL).
- * R_FLAGS is pointer to S-Expression of the flags (can be NULL).
- */
-gpg_error_t
-extract_private_key (gcry_sexp_t s_key, int req_private_key_data,
- const char **r_algoname, int *r_npkey, int *r_nskey,
- const char **r_elems,
- gcry_mpi_t *array, int arraysize,
- gcry_sexp_t *r_curve, gcry_sexp_t *r_flags)
-{
- gpg_error_t err;
- gcry_sexp_t list, l2;
- char *name;
- const char *algoname, *format;
- int npkey, nskey;
- gcry_sexp_t curve = NULL;
- gcry_sexp_t flags = NULL;
-
- *r_curve = NULL;
- *r_flags = NULL;
-
- if (!req_private_key_data)
- {
- list = gcry_sexp_find_token (s_key, "shadowed-private-key", 0 );
- if (!list)
- list = gcry_sexp_find_token (s_key, "protected-private-key", 0 );
- if (!list)
- list = gcry_sexp_find_token (s_key, "private-key", 0 );
- }
- else
- list = gcry_sexp_find_token (s_key, "private-key", 0);
-
- if (!list)
- {
- log_error ("invalid private key format\n");
- return gpg_error (GPG_ERR_BAD_SECKEY);
- }
-
- l2 = gcry_sexp_cadr (list);
- gcry_sexp_release (list);
- list = l2;
- name = gcry_sexp_nth_string (list, 0);
- if (!name)
- {
- gcry_sexp_release (list);
- return gpg_error (GPG_ERR_INV_OBJ); /* Invalid structure of object. */
- }
-
- if (arraysize < 7)
- BUG ();
-
- /* Map NAME to a name as used by Libgcrypt. We do not use the
- Libgcrypt function here because we need a lowercase name and
- require special treatment for some algorithms. */
- strlwr (name);
- if (!strcmp (name, "rsa"))
- {
- algoname = "rsa";
- format = "ned?p?q?u?";
- npkey = 2;
- nskey = 6;
- err = gcry_sexp_extract_param (list, NULL, format,
- array+0, array+1, array+2, array+3,
- array+4, array+5, NULL);
- }
- else if (!strcmp (name, "elg"))
- {
- algoname = "elg";
- format = "pgyx?";
- npkey = 3;
- nskey = 4;
- err = gcry_sexp_extract_param (list, NULL, format,
- array+0, array+1, array+2, array+3,
- NULL);
- }
- else if (!strcmp (name, "dsa"))
- {
- algoname = "dsa";
- format = "pqgyx?";
- npkey = 4;
- nskey = 5;
- err = gcry_sexp_extract_param (list, NULL, format,
- array+0, array+1, array+2, array+3,
- array+4, NULL);
- }
- else if (!strcmp (name, "ecc"))
- {
- algoname = "ecc";
- format = "/qd?";
- npkey = 1;
- nskey = 2;
- curve = gcry_sexp_find_token (list, "curve", 0);
- flags = gcry_sexp_find_token (list, "flags", 0);
- err = gcry_sexp_extract_param (list, NULL, format,
- array+0, array+1, NULL);
- if (flags)
- {
- gcry_sexp_t param = gcry_sexp_find_token (flags, "param", 0);
- if (param)
- {
- gcry_sexp_release (param);
- array[6] = array[0];
- array[7] = array[1];
- err = gcry_sexp_extract_param (list, NULL, "pabgnh?",
- array+0, array+1, array+2, array+3,
- array+4, array+5, NULL);
- if (array[5] == NULL)
- {
- array[5] = GCRYMPI_CONST_ONE;
- npkey += 6;
- nskey += 6;
- }
- format = "pabgnhqd?";
- }
- }
- }
- else if (!strcmp (name, "ecdsa"))
- {
- algoname = "ecdsa";
- format = "pabgnqd?";
- npkey = 6;
- nskey = 7;
- err = gcry_sexp_extract_param (list, NULL, format,
- array+0, array+1, array+2, array+3,
- array+4, array+5, array+6, NULL);
- }
- else if (!strcmp (name, "ecdh"))
- {
- algoname = "ecdh";
- format = "pabgnqd?";
- npkey = 6;
- nskey= 7;
- err = gcry_sexp_extract_param (list, NULL, format,
- array+0, array+1, array+2, array+3,
- array+4, array+5, array+6, NULL);
- }
- else
- {
- err = gpg_error (GPG_ERR_PUBKEY_ALGO);
- }
- xfree (name);
- gcry_sexp_release (list);
- if (err)
- {
- gcry_sexp_release (curve);
- gcry_sexp_release (flags);
- return err;
- }
- else
- {
- *r_algoname = algoname;
- if (r_elems)
- {
- if (format[0] == '/') /* It is opaque data qualifier, skip it. */
- *r_elems = format+1;
- else
- *r_elems = format;
- }
- *r_npkey = npkey;
- if (r_nskey)
- *r_nskey = nskey;
- *r_curve = curve;
- *r_flags = flags;
-
- return 0;
- }
-}
-
-/* Convert our key S_KEY into an OpenPGP key transfer format. On
- success a canonical encoded S-expression is stored at R_TRANSFERKEY
- and its length at R_TRANSFERKEYLEN; this S-expression is also
- padded to a multiple of 64 bits. */
-gpg_error_t
-convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
- unsigned char **r_transferkey, size_t *r_transferkeylen)
-{
- gpg_error_t err;
- const char *algoname;
- int npkey, nskey;
- gcry_mpi_t array[10];
- gcry_sexp_t curve = NULL;
- gcry_sexp_t flags = NULL;
- char protect_iv[16];
- char salt[8];
- unsigned long s2k_count;
- int i, j;
-
- (void)ctrl;
-
- *r_transferkey = NULL;
-
- for (i=0; i < DIM (array); i++)
- array[i] = NULL;
-
- err = extract_private_key (s_key, 1, &algoname, &npkey, &nskey, NULL,
- array, DIM (array), &curve, &flags);
- if (err)
- return err;
-
- gcry_create_nonce (protect_iv, sizeof protect_iv);
- gcry_create_nonce (salt, sizeof salt);
- /* We need to use the encoded S2k count. It is not possible to
- encode it after it has been used because the encoding procedure
- may round the value up. */
- s2k_count = get_standard_s2k_count_rfc4880 ();
- err = apply_protection (array, npkey, nskey, passphrase,
- GCRY_CIPHER_AES, protect_iv, sizeof protect_iv,
- 3, GCRY_MD_SHA1, salt, s2k_count);
- /* Turn it into the transfer key S-expression. Note that we always
- return a protected key. */
- if (!err)
- {
- char countbuf[35];
- membuf_t mbuf;
- void *format_args[10+2];
- gcry_sexp_t tmpkey;
- gcry_sexp_t tmpsexp = NULL;
-
- snprintf (countbuf, sizeof countbuf, "%lu", s2k_count);
-
- init_membuf (&mbuf, 50);
- put_membuf_str (&mbuf, "(skey");
- for (i=j=0; i < npkey; i++)
- {
- put_membuf_str (&mbuf, " _ %m");
- format_args[j++] = array + i;
- }
- put_membuf_str (&mbuf, " e %m");
- format_args[j++] = array + npkey;
- put_membuf_str (&mbuf, ")\n");
- put_membuf (&mbuf, "", 1);
-
- tmpkey = NULL;
- {
- char *format = get_membuf (&mbuf, NULL);
- if (!format)
- err = gpg_error_from_syserror ();
- else
- err = gcry_sexp_build_array (&tmpkey, NULL, format, format_args);
- xfree (format);
- }
- if (!err)
- err = gcry_sexp_build (&tmpsexp, NULL,
- "(openpgp-private-key\n"
- " (version 1:4)\n"
- " (algo %s)\n"
- " %S%S\n"
- " (protection sha1 aes %b 1:3 sha1 %b %s))\n",
- algoname,
- curve,
- tmpkey,
- (int)sizeof protect_iv, protect_iv,
- (int)sizeof salt, salt,
- countbuf);
- gcry_sexp_release (tmpkey);
- if (!err)
- err = make_canon_sexp_pad (tmpsexp, 0, r_transferkey, r_transferkeylen);
- gcry_sexp_release (tmpsexp);
- }
-
- for (i=0; i < DIM (array); i++)
- gcry_mpi_release (array[i]);
- gcry_sexp_release (curve);
- gcry_sexp_release (flags);
-
- return err;
-}
diff -Nru gnupg2-2.1.6~build1/agent/cvt-openpgp.h gnupg2-2.0.28/agent/cvt-openpgp.h
--- gnupg2-2.1.6~build1/agent/cvt-openpgp.h 2015-06-17 06:39:24.000000000 +0000
+++ gnupg2-2.0.28/agent/cvt-openpgp.h 1970-01-01 00:00:00.000000000 +0000
@@ -1,36 +0,0 @@
-/* cvt-openpgp.h - Convert an OpenPGP key to our internal format.
- * Copyright (C) 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 .
- */
-#ifndef GNUPG_AGENT_CVT_OPENPGP_H
-#define GNUPG_AGENT_CVT_OPENPGP_H
-
-gpg_error_t convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
- unsigned char *grip, const char *prompt,
- const char *cache_nonce,
- unsigned char **r_key, char **r_passphrase);
-gpg_error_t convert_from_openpgp_native (ctrl_t ctrl,
- gcry_sexp_t s_pgp,
- const char *passphrase,
- unsigned char **r_key);
-
-gpg_error_t convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key,
- const char *passphrase,
- unsigned char **r_transferkey,
- size_t *r_transferkeylen);
-
-#endif /*GNUPG_AGENT_CVT_OPENPGP_H*/
diff -Nru gnupg2-2.1.6~build1/agent/divert-scd.c gnupg2-2.0.28/agent/divert-scd.c
--- gnupg2-2.1.6~build1/agent/divert-scd.c 2015-06-30 19:23:20.000000000 +0000
+++ gnupg2-2.0.28/agent/divert-scd.c 2015-06-02 08:13:55.000000000 +0000
@@ -1,4 +1,4 @@
-/* divert-scd.c - divert operations to the scdaemon
+/* divert-scd.c - divert operations to the scdaemon
* Copyright (C) 2002, 2003, 2009 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
@@ -44,7 +44,7 @@
*r_kid = NULL;
- rc = parse_shadow_info (shadow_info, &want_sn, &want_kid, NULL);
+ rc = parse_shadow_info (shadow_info, &want_sn, &want_kid);
if (rc)
return rc;
@@ -89,9 +89,9 @@
"%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"),
+ ? _("Please insert the card with serial number")
+ : _("Please remove the current card and "
+ "insert the one with serial number"),
want_sn_displen, want_sn) < 0)
{
rc = out_of_core ();
@@ -99,10 +99,6 @@
else
{
rc = agent_get_confirmation (ctrl, desc, NULL, NULL, 0);
- if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK &&
- gpg_err_code (rc) == GPG_ERR_NO_PIN_ENTRY)
- rc = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
-
xfree (desc);
}
}
@@ -144,7 +140,7 @@
memcpy (frame+asnlen, digest, digestlen);
if (DBG_CRYPTO)
log_printhex ("encoded hash:", frame, asnlen+digestlen);
-
+
*r_val = frame;
*r_len = asnlen+digestlen;
return 0;
@@ -174,11 +170,11 @@
Example:
"|AN|Please enter the new security officer's PIN"
-
+
The text "Please ..." will get displayed and the flags 'A' and 'N'
are considered.
*/
-static int
+static int
getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
{
struct pin_entry_info_s *pi;
@@ -201,19 +197,19 @@
for (s=info+1; s < ends; s++)
{
if (*s == 'A')
- prompt = L_("Admin PIN");
+ prompt = _("Admin PIN");
else if (*s == 'P')
{
/* TRANSLATORS: A PUK is the Personal Unblocking Code
used to unblock a PIN. */
- prompt = L_("PUK");
+ prompt = _("PUK");
is_puk = 1;
}
else if (*s == 'N')
newpin = 1;
else if (*s == 'R')
{
- prompt = L_("Reset Code");
+ prompt = _("Reset Code");
resetcode = 1;
}
}
@@ -239,7 +235,7 @@
char *desc;
if ( asprintf (&desc,
- L_("%s%%0A%%0AUse the reader's pinpad for input."),
+ _("%s%%0A%%0AUse the reader's pinpad for input."),
info) < 0 )
rc = gpg_error_from_syserror ();
else
@@ -288,18 +284,18 @@
pi2->max_tries = 1;
rc = agent_askpin (ctrl,
(resetcode?
- L_("Repeat this Reset Code"):
+ _("Repeat this Reset Code"):
is_puk?
- L_("Repeat this PUK"):
- L_("Repeat this PIN")),
+ _("Repeat this PUK"):
+ _("Repeat this PIN")),
prompt, NULL, pi2, NULL, 0);
if (!rc && strcmp (pi->pin, pi2->pin))
{
- again_text = (resetcode?
- L_("Reset Code not correctly repeated; try again"):
+ again_text = (resetcode?
+ N_("Reset Code not correctly repeated; try again"):
is_puk?
- L_("PUK not correctly repeated; try again"):
- L_("PIN not correctly repeated; try again"));
+ N_("PUK not correctly repeated; try again"):
+ N_("PIN not correctly repeated; try again"));
xfree (pi2);
xfree (pi);
goto again;
@@ -311,10 +307,10 @@
{
char *desc;
if ( asprintf (&desc,
- L_("Please enter the PIN%s%s%s to unlock the card"),
- info? " (":"",
+ _("Please enter the PIN%s%s%s to unlock the card"),
+ info? " (`":"",
info? info:"",
- info? ")":"") < 0)
+ info? "')":"") < 0)
desc = NULL;
rc = agent_askpin (ctrl, desc?desc:info, prompt, NULL, pi, NULL, 0);
xfree (desc);
@@ -333,10 +329,9 @@
int
-divert_pksign (ctrl_t ctrl,
+divert_pksign (ctrl_t ctrl,
const unsigned char *digest, size_t digestlen, int algo,
- const unsigned char *shadow_info, unsigned char **r_sig,
- size_t *r_siglen)
+ const unsigned char *shadow_info, unsigned char **r_sig)
{
int rc;
char *kid;
@@ -352,7 +347,7 @@
int save = ctrl->use_auth_call;
ctrl->use_auth_call = 1;
rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl,
- algo, digest, digestlen, &sigval, &siglen);
+ digest, digestlen, &sigval, &siglen);
ctrl->use_auth_call = save;
}
else
@@ -364,16 +359,13 @@
if (!rc)
{
rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl,
- algo, data, ndata, &sigval, &siglen);
+ data, ndata, &sigval, &siglen);
xfree (data);
}
}
if (!rc)
- {
- *r_sig = sigval;
- *r_siglen = siglen;
- }
+ *r_sig = sigval;
xfree (kid);
@@ -383,13 +375,12 @@
/* Decrypt the the value given asn an S-expression in CIPHER using the
key identified by SHADOW_INFO and return the plaintext in an
- allocated buffer in R_BUF. The padding information is stored at
- R_PADDING with -1 for not known. */
-int
+ allocated buffer in R_BUF. */
+int
divert_pkdecrypt (ctrl_t ctrl,
const unsigned char *cipher,
const unsigned char *shadow_info,
- char **r_buf, size_t *r_len, int *r_padding)
+ char **r_buf, size_t *r_len)
{
int rc;
char *kid;
@@ -400,64 +391,34 @@
char *plaintext;
size_t plaintextlen;
- *r_padding = -1;
-
s = cipher;
if (*s != '(')
return gpg_error (GPG_ERR_INV_SEXP);
s++;
n = snext (&s);
if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
+ return gpg_error (GPG_ERR_INV_SEXP);
if (!smatch (&s, n, "enc-val"))
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
+ return gpg_error (GPG_ERR_UNKNOWN_SEXP);
if (*s != '(')
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
s++;
n = snext (&s);
if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- if (smatch (&s, n, "rsa"))
- {
- if (*s != '(')
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- if (!smatch (&s, n, "a"))
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- n = snext (&s);
- }
- else if (smatch (&s, n, "ecdh"))
- {
- if (*s != '(')
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- if (smatch (&s, n, "s"))
- {
- n = snext (&s);
- s += n;
- if (*s++ != ')')
- return gpg_error (GPG_ERR_INV_SEXP);
- if (*s++ != '(')
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- }
- if (!smatch (&s, n, "e"))
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- n = snext (&s);
- }
- else
- return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
-
+ return gpg_error (GPG_ERR_INV_SEXP);
+ if (!smatch (&s, n, "rsa"))
+ return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
+ if (*s != '(')
+ return gpg_error (GPG_ERR_UNKNOWN_SEXP);
+ s++;
+ n = snext (&s);
if (!n)
+ return gpg_error (GPG_ERR_INV_SEXP);
+ if (!smatch (&s, n, "a"))
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
+ n = snext (&s);
+ if (!n)
+ return gpg_error (GPG_ERR_UNKNOWN_SEXP);
ciphertext = s;
ciphertextlen = n;
@@ -467,7 +428,7 @@
rc = agent_card_pkdecrypt (ctrl, kid, getpin_cb, ctrl,
ciphertext, ciphertextlen,
- &plaintext, &plaintextlen, r_padding);
+ &plaintext, &plaintextlen);
if (!rc)
{
*r_buf = plaintext;
@@ -477,16 +438,14 @@
return rc;
}
-int
-divert_writekey (ctrl_t ctrl, int force, const char *serialno,
- const char *id, const char *keydata, size_t keydatalen)
-{
- return agent_card_writekey (ctrl, force, serialno, id, keydata, keydatalen,
- getpin_cb, ctrl);
-}
-int
+int
divert_generic_cmd (ctrl_t ctrl, const char *cmdline, void *assuan_context)
{
return agent_card_scd (ctrl, cmdline, getpin_cb, ctrl, assuan_context);
}
+
+
+
+
+
diff -Nru gnupg2-2.1.6~build1/agent/findkey.c gnupg2-2.0.28/agent/findkey.c
--- gnupg2-2.1.6~build1/agent/findkey.c 2015-06-30 19:31:36.000000000 +0000
+++ gnupg2-2.0.28/agent/findkey.c 2015-06-02 08:13:55.000000000 +0000
@@ -1,7 +1,6 @@
/* findkey.c - Locate the secret key
* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007,
* 2010, 2011 Free Software Foundation, Inc.
- * Copyright (C) 2014 Werner Koch
*
* This file is part of GnuPG.
*
@@ -30,7 +29,7 @@
#include
#include
#include
-#include /* (we use pth_sleep) */
+#include /* (we use pth_sleep) */
#include "agent.h"
#include "i18n.h"
@@ -47,7 +46,7 @@
const unsigned char *protected_key;
unsigned char *unprotected_key;
int change_required; /* Set by the callback to indicate that the
- user should change the passphrase. */
+ user should chnage the passphrase. */
};
@@ -59,47 +58,69 @@
const void *buffer, size_t length, int force)
{
char *fname;
- estream_t fp;
+ FILE *fp;
char hexgrip[40+4+1];
+ int fd;
bin2hex (grip, 20, hexgrip);
strcpy (hexgrip+40, ".key");
fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
- /* FIXME: Write to a temp file first so that write failures during
- key updates won't lead to a key loss. */
-
if (!force && !access (fname, F_OK))
{
- log_error ("secret key file '%s' already exists\n", fname);
+ log_error ("secret key file `%s' already exists\n", fname);
xfree (fname);
- return gpg_error (GPG_ERR_EEXIST);
+ return gpg_error (GPG_ERR_GENERAL);
+ }
+
+ /* In FORCE mode we would like to create FNAME but only if it does
+ not already exist. We cannot make this guarantee just using
+ POSIX (GNU provides the "x" opentype for fopen, however, this is
+ not portable). Thus, we use the more flexible open function and
+ then use fdopen to obtain a stream. */
+ fd = open (fname, force? (O_CREAT | O_TRUNC | O_WRONLY | O_BINARY)
+ : (O_CREAT | O_EXCL | O_WRONLY | O_BINARY),
+ S_IRUSR | S_IWUSR
+#ifndef HAVE_W32_SYSTEM
+ | S_IRGRP
+#endif
+ );
+ if (fd < 0)
+ fp = NULL;
+ else
+ {
+ fp = fdopen (fd, "wb");
+ if (!fp)
+ {
+ int save_e = errno;
+ close (fd);
+ errno = save_e;
+ }
}
- fp = es_fopen (fname, force? "wb,mode=-rw" : "wbx,mode=-rw");
if (!fp)
{
- gpg_error_t tmperr = gpg_error_from_syserror ();
- log_error ("can't create '%s': %s\n", fname, gpg_strerror (tmperr));
+ gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
+ log_error ("can't create `%s': %s\n", fname, strerror (errno));
xfree (fname);
return tmperr;
}
- if (es_fwrite (buffer, length, 1, fp) != 1)
+ if (fwrite (buffer, length, 1, fp) != 1)
{
- gpg_error_t tmperr = gpg_error_from_syserror ();
- log_error ("error writing '%s': %s\n", fname, gpg_strerror (tmperr));
- es_fclose (fp);
- gnupg_remove (fname);
+ gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
+ log_error ("error writing `%s': %s\n", fname, strerror (errno));
+ fclose (fp);
+ remove (fname);
xfree (fname);
return tmperr;
}
- if (es_fclose (fp))
+ if ( fclose (fp) )
{
- gpg_error_t tmperr = gpg_error_from_syserror ();
- log_error ("error closing '%s': %s\n", fname, gpg_strerror (tmperr));
- gnupg_remove (fname);
+ gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
+ log_error ("error closing `%s': %s\n", fname, strerror (errno));
+ remove (fname);
xfree (fname);
return tmperr;
}
@@ -109,13 +130,12 @@
}
-/* Callback function to try the unprotection from the passphrase query
+/* Callback function to try the unprotection from the passpharse query
code. */
static int
try_unprotect_cb (struct pin_entry_info_s *pi)
{
struct try_unprotect_arg_s *arg = pi->check_cb_arg;
- ctrl_t ctrl = arg->ctrl;
size_t dummy;
gpg_error_t err;
gnupg_isotime_t now, protected_at, tmptime;
@@ -124,18 +144,18 @@
assert (!arg->unprotected_key);
arg->change_required = 0;
- err = agent_unprotect (ctrl, arg->protected_key, pi->pin, protected_at,
+ err = agent_unprotect (arg->protected_key, pi->pin, protected_at,
&arg->unprotected_key, &dummy);
if (err)
return err;
- if (!opt.max_passphrase_days || ctrl->in_passwd)
+ if (!opt.max_passphrase_days || arg->ctrl->in_passwd)
return 0; /* No regular passphrase change required. */
if (!*protected_at)
{
/* No protection date known - must force passphrase change. */
- desc = xtrystrdup (L_("Note: This passphrase has never been changed.%0A"
- "Please change it now."));
+ desc = xtrystrdup (_("Note: This passphrase has never been changed.%0A"
+ "Please change it now."));
if (!desc)
return gpg_error_from_syserror ();
}
@@ -150,8 +170,8 @@
{
/* Passphrase "expired". */
desc = xtryasprintf
- (L_("This passphrase has not been changed%%0A"
- "since %.4s-%.2s-%.2s. Please change it now."),
+ (_("This passphrase has not been changed%%0A"
+ "since %.4s-%.2s-%.2s. Please change it now."),
protected_at, protected_at+4, protected_at+6);
if (!desc)
return gpg_error_from_syserror ();
@@ -163,20 +183,19 @@
/* Change required. */
if (opt.enforce_passphrase_constraints)
{
- err = agent_get_confirmation (ctrl, desc,
- L_("Change passphrase"), NULL, 0);
+ err = agent_get_confirmation (arg->ctrl, desc,
+ _("Change passphrase"), NULL, 0);
if (!err)
arg->change_required = 1;
}
else
{
- err = agent_get_confirmation (ctrl, desc,
- L_("Change passphrase"),
- L_("I'll change it later"), 0);
+ err = agent_get_confirmation (arg->ctrl, desc,
+ _("Change passphrase"),
+ _("I'll change it later"), 0);
if (!err)
arg->change_required = 1;
- else if (gpg_err_code (err) == GPG_ERR_CANCELED
- || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
+ else if (gpg_err_code (err) == GPG_ERR_CANCELED)
err = 0;
}
xfree (desc);
@@ -191,7 +210,6 @@
%% - Replaced by a single %
%c - Replaced by the content of COMMENT.
- %C - Same as %c but put into parentheses.
%F - Replaced by an ssh style fingerprint computed from KEY.
The functions returns 0 on success or an error code. On success a
@@ -243,20 +261,6 @@
out_len += comment_length;
break;
- case 'C': /* Comment. */
- if (!comment_length)
- ;
- else if (out)
- {
- *out++ = '(';
- memcpy (out, comment, comment_length);
- out += comment_length;
- *out++ = ')';
- }
- else
- out_len += comment_length + 2;
- break;
-
case 'F': /* SSH style fingerprint. */
if (!ssh_fpr && key)
ssh_get_fingerprint_string (key, &ssh_fpr);
@@ -314,16 +318,11 @@
should be the hex encoded keygrip of that key to be used with the
caching mechanism. DESC_TEXT may be set to override the default
description used for the pinentry. If LOOKUP_TTL is given this
- function is used to lookup the default ttl. If R_PASSPHRASE is not
- NULL, the function succeeded and the key was protected the used
- passphrase (entered or from the cache) is stored there; if not NULL
- will be stored. The caller needs to free the returned
- passphrase. */
+ function is used to lookup the default ttl. */
static int
-unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
+unprotect (ctrl_t ctrl, const char *desc_text,
unsigned char **keybuf, const unsigned char *grip,
- cache_mode_t cache_mode, lookup_ttl_t lookup_ttl,
- char **r_passphrase)
+ cache_mode_t cache_mode, lookup_ttl_t lookup_ttl)
{
struct pin_entry_info_s *pi;
struct try_unprotect_arg_s arg;
@@ -332,99 +331,29 @@
size_t resultlen;
char hexgrip[40+1];
- if (r_passphrase)
- *r_passphrase = NULL;
-
bin2hex (grip, 20, hexgrip);
- /* Initially try to get it using a cache nonce. */
- if (cache_nonce)
- {
- char *pw;
-
- pw = agent_get_cache (cache_nonce, CACHE_MODE_NONCE);
- if (pw)
- {
- rc = agent_unprotect (ctrl, *keybuf, pw, NULL, &result, &resultlen);
- if (!rc)
- {
- if (r_passphrase)
- *r_passphrase = pw;
- else
- xfree (pw);
- xfree (*keybuf);
- *keybuf = result;
- return 0;
- }
- xfree (pw);
- }
- }
-
/* First try to get it from the cache - if there is none or we can't
unprotect it, we fall back to ask the user */
if (cache_mode != CACHE_MODE_IGNORE)
{
- char *pw;
+ void *cache_marker;
+ const char *pw;
retry:
- pw = agent_get_cache (hexgrip, cache_mode);
+ pw = agent_get_cache (hexgrip, cache_mode, &cache_marker);
if (pw)
{
- rc = agent_unprotect (ctrl, *keybuf, pw, NULL, &result, &resultlen);
+ rc = agent_unprotect (*keybuf, pw, NULL, &result, &resultlen);
+ agent_unlock_cache_entry (&cache_marker);
if (!rc)
{
- if (cache_mode == CACHE_MODE_NORMAL)
- agent_store_cache_hit (hexgrip);
- if (r_passphrase)
- *r_passphrase = pw;
- else
- xfree (pw);
xfree (*keybuf);
*keybuf = result;
return 0;
}
- xfree (pw);
rc = 0;
}
- else if (cache_mode == CACHE_MODE_NORMAL)
- {
- /* The standard use of GPG keys is to have a signing and an
- encryption subkey. Commonly both use the same
- passphrase. We try to help the user to enter the
- passphrase only once by silently trying the last
- correctly entered passphrase. Checking one additional
- passphrase should be acceptable; despite the S2K
- introduced delays. The assumed workflow is:
-
- 1. Read encrypted message in a MUA and thus enter a
- passphrase for the encryption subkey.
-
- 2. Reply to that mail with an encrypted and signed
- mail, thus entering the passphrase for the signing
- subkey.
-
- We can often avoid the passphrase entry in the second
- step. We do this only in normal mode, so not to
- interfere with unrelated cache entries. */
- pw = agent_get_cache (NULL, cache_mode);
- if (pw)
- {
- rc = agent_unprotect (ctrl, *keybuf, pw, NULL,
- &result, &resultlen);
- if (!rc)
- {
- if (r_passphrase)
- *r_passphrase = pw;
- else
- xfree (pw);
- xfree (*keybuf);
- *keybuf = result;
- return 0;
- }
- xfree (pw);
- rc = 0;
- }
- }
/* If the pinentry is currently in use, we wait up to 60 seconds
for it to close and check the cache again. This solves a common
@@ -443,7 +372,7 @@
{
/* We need to give the other thread a chance to actually put
it into the cache. */
- npth_sleep (1);
+ pth_sleep (1);
goto retry;
}
/* Timeout - better call pinentry now the plain way. */
@@ -470,8 +399,6 @@
assert (arg.unprotected_key);
if (arg.change_required)
{
- /* The callback told as that the user should change their
- passphrase. Present the dialog to do. */
size_t canlen, erroff;
gcry_sexp_t s_skey;
@@ -488,7 +415,7 @@
xfree (pi);
return rc;
}
- rc = agent_protect_and_store (ctrl, s_skey, NULL);
+ rc = agent_protect_and_store (ctrl, s_skey);
gcry_sexp_release (s_skey);
if (rc)
{
@@ -501,14 +428,8 @@
}
}
else
- {
- /* Passphrase is fine. */
- agent_put_cache (hexgrip, cache_mode, pi->pin,
- lookup_ttl? lookup_ttl (hexgrip) : 0);
- agent_store_cache_hit (hexgrip);
- if (r_passphrase && *pi->pin)
- *r_passphrase = xtrystrdup (pi->pin);
- }
+ agent_put_cache (hexgrip, cache_mode, pi->pin,
+ lookup_ttl? lookup_ttl (hexgrip) : 0);
xfree (*keybuf);
*keybuf = arg.unprotected_key;
}
@@ -525,7 +446,7 @@
{
int rc;
char *fname;
- estream_t fp;
+ FILE *fp;
struct stat st;
unsigned char *buf;
size_t buflen, erroff;
@@ -538,46 +459,33 @@
strcpy (hexgrip+40, ".key");
fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
- fp = es_fopen (fname, "rb");
+ fp = fopen (fname, "rb");
if (!fp)
{
rc = gpg_error_from_syserror ();
if (gpg_err_code (rc) != GPG_ERR_ENOENT)
- log_error ("can't open '%s': %s\n", fname, strerror (errno));
+ log_error ("can't open `%s': %s\n", fname, strerror (errno));
xfree (fname);
return rc;
}
- if (fstat (es_fileno (fp), &st))
+ if (fstat (fileno(fp), &st))
{
rc = gpg_error_from_syserror ();
- log_error ("can't stat '%s': %s\n", fname, strerror (errno));
+ log_error ("can't stat `%s': %s\n", fname, strerror (errno));
xfree (fname);
- es_fclose (fp);
+ fclose (fp);
return rc;
}
buflen = st.st_size;
buf = xtrymalloc (buflen+1);
- if (!buf)
- {
- rc = gpg_error_from_syserror ();
- log_error ("error allocating %zu bytes for '%s': %s\n",
- buflen, fname, strerror (errno));
- xfree (fname);
- es_fclose (fp);
- xfree (buf);
- return rc;
-
- }
-
- if (es_fread (buf, buflen, 1, fp) != 1)
+ if (!buf || fread (buf, buflen, 1, fp) != 1)
{
rc = gpg_error_from_syserror ();
- log_error ("error reading %zu bytes from '%s': %s\n",
- buflen, fname, strerror (errno));
+ log_error ("error reading `%s': %s\n", fname, strerror (errno));
xfree (fname);
- es_fclose (fp);
+ fclose (fp);
xfree (buf);
return rc;
}
@@ -585,7 +493,7 @@
/* Convert the file into a gcrypt S-expression object. */
rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen);
xfree (fname);
- es_fclose (fp);
+ fclose (fp);
xfree (buf);
if (rc)
{
@@ -598,64 +506,35 @@
}
-/* Remove the key identified by GRIP from the private key directory. */
-static gpg_error_t
-remove_key_file (const unsigned char *grip)
-{
- gpg_error_t err = 0;
- char *fname;
- char hexgrip[40+4+1];
-
- bin2hex (grip, 20, hexgrip);
- strcpy (hexgrip+40, ".key");
- fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
- if (gnupg_remove (fname))
- err = gpg_error_from_syserror ();
- xfree (fname);
- return err;
-}
-
-
/* Return the secret key as an S-Exp in RESULT after locating it using
- the GRIP. If the operation shall be diverted to a token, an
- allocated S-expression with the shadow_info part from the file is
- stored at SHADOW_INFO; if not NULL will be stored at SHADOW_INFO.
+ the GRIP. Stores NULL at RESULT if the operation shall be diverted
+ to a token; in this case an allocated S-expression with the
+ shadow_info part from the file is stored at SHADOW_INFO.
CACHE_MODE defines now the cache shall be used. DESC_TEXT may be
set to present a custom description for the pinentry. LOOKUP_TTL
is an optional function to convey a TTL to the cache manager; we do
- not simply pass the TTL value because the value is only needed if
- an unprotect action was needed and looking up the TTL may have some
- overhead (e.g. scanning the sshcontrol file). If a CACHE_NONCE is
- given that cache item is first tried to get a passphrase. If
- R_PASSPHRASE is not NULL, the function succeeded and the key was
- protected the used passphrase (entered or from the cache) is stored
- there; if not NULL will be stored. The caller needs to free the
- returned passphrase. */
+ not simply pass the TTL value because the value is only needed if an
+ unprotect action was needed and looking up the TTL may have some
+ overhead (e.g. scanning the sshcontrol file). */
gpg_error_t
-agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
- const char *desc_text,
+agent_key_from_file (ctrl_t ctrl, const char *desc_text,
const unsigned char *grip, unsigned char **shadow_info,
cache_mode_t cache_mode, lookup_ttl_t lookup_ttl,
- gcry_sexp_t *result, char **r_passphrase)
+ gcry_sexp_t *result)
{
int rc;
unsigned char *buf;
size_t len, buflen, erroff;
gcry_sexp_t s_skey;
+ int got_shadow_info = 0;
*result = NULL;
if (shadow_info)
*shadow_info = NULL;
- if (r_passphrase)
- *r_passphrase = NULL;
rc = read_key_file (grip, &s_skey);
if (rc)
- {
- if (gpg_err_code (rc) == GPG_ERR_ENOENT)
- rc = gpg_error (GPG_ERR_NO_SECKEY);
- return rc;
- }
+ return rc;
/* For use with the protection functions we also need the key as an
canonical encoded S-expression in a buffer. Create this buffer
@@ -668,22 +547,6 @@
{
case PRIVATE_KEY_CLEAR:
break; /* no unprotection needed */
- case PRIVATE_KEY_OPENPGP_NONE:
- {
- unsigned char *buf_new;
- size_t buf_newlen;
-
- rc = agent_unprotect (ctrl, buf, "", NULL, &buf_new, &buf_newlen);
- if (rc)
- log_error ("failed to convert unprotected openpgp key: %s\n",
- gpg_strerror (rc));
- else
- {
- xfree (buf);
- buf = buf_new;
- }
- }
- break;
case PRIVATE_KEY_PROTECTED:
{
char *desc_text_final;
@@ -709,8 +572,8 @@
if (!rc)
{
- rc = unprotect (ctrl, cache_nonce, desc_text_final, &buf, grip,
- cache_mode, lookup_ttl, r_passphrase);
+ rc = unprotect (ctrl, desc_text_final, &buf, grip,
+ cache_mode, lookup_ttl);
if (rc)
log_error ("failed to unprotect the secret key: %s\n",
gpg_strerror (rc));
@@ -737,6 +600,7 @@
{
memcpy (*shadow_info, s, n);
rc = 0;
+ got_shadow_info = 1;
}
}
if (rc)
@@ -752,14 +616,9 @@
}
gcry_sexp_release (s_skey);
s_skey = NULL;
- if (rc)
+ if (rc || got_shadow_info)
{
xfree (buf);
- if (r_passphrase)
- {
- xfree (*r_passphrase);
- *r_passphrase = NULL;
- }
return rc;
}
@@ -771,11 +630,6 @@
{
log_error ("failed to build S-Exp (off=%u): %s\n",
(unsigned int)erroff, gpg_strerror (rc));
- if (r_passphrase)
- {
- xfree (*r_passphrase);
- *r_passphrase = NULL;
- }
return rc;
}
@@ -784,186 +638,6 @@
}
-/* Return the string name from the S-expression S_KEY as well as a
- string describing the names of the parameters. ALGONAMESIZE and
- ELEMSSIZE give the allocated size of the provided buffers. The
- buffers may be NULL if not required. If R_LIST is not NULL the top
- level list will be stored there; the caller needs to release it in
- this case. */
-static gpg_error_t
-key_parms_from_sexp (gcry_sexp_t s_key, gcry_sexp_t *r_list,
- char *r_algoname, size_t algonamesize,
- char *r_elems, size_t elemssize)
-{
- gcry_sexp_t list, l2;
- const char *name, *algoname, *elems;
- size_t n;
-
- if (r_list)
- *r_list = NULL;
-
- list = gcry_sexp_find_token (s_key, "shadowed-private-key", 0 );
- if (!list)
- list = gcry_sexp_find_token (s_key, "protected-private-key", 0 );
- if (!list)
- list = gcry_sexp_find_token (s_key, "private-key", 0 );
- if (!list)
- {
- log_error ("invalid private key format\n");
- return gpg_error (GPG_ERR_BAD_SECKEY);
- }
-
- l2 = gcry_sexp_cadr (list);
- gcry_sexp_release (list);
- list = l2;
- name = gcry_sexp_nth_data (list, 0, &n);
- if (n==3 && !memcmp (name, "rsa", 3))
- {
- algoname = "rsa";
- elems = "ne";
- }
- else if (n==3 && !memcmp (name, "dsa", 3))
- {
- algoname = "dsa";
- elems = "pqgy";
- }
- else if (n==3 && !memcmp (name, "ecc", 3))
- {
- algoname = "ecc";
- elems = "pabgnq";
- }
- else if (n==5 && !memcmp (name, "ecdsa", 5))
- {
- algoname = "ecdsa";
- elems = "pabgnq";
- }
- else if (n==4 && !memcmp (name, "ecdh", 4))
- {
- algoname = "ecdh";
- elems = "pabgnq";
- }
- else if (n==3 && !memcmp (name, "elg", 3))
- {
- algoname = "elg";
- elems = "pgy";
- }
- else
- {
- log_error ("unknown private key algorithm\n");
- gcry_sexp_release (list);
- return gpg_error (GPG_ERR_BAD_SECKEY);
- }
-
- if (r_algoname)
- {
- if (strlen (algoname) >= algonamesize)
- return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
- strcpy (r_algoname, algoname);
- }
- if (r_elems)
- {
- if (strlen (elems) >= elemssize)
- return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
- strcpy (r_elems, elems);
- }
-
- if (r_list)
- *r_list = list;
- else
- gcry_sexp_release (list);
-
- return 0;
-}
-
-
-/* Return true if KEYPARMS holds an EdDSA key. */
-static int
-is_eddsa (gcry_sexp_t keyparms)
-{
- int result = 0;
- gcry_sexp_t list;
- const char *s;
- size_t n;
- int i;
-
- list = gcry_sexp_find_token (keyparms, "flags", 0);
- for (i = list ? gcry_sexp_length (list)-1 : 0; i > 0; i--)
- {
- s = gcry_sexp_nth_data (list, i, &n);
- if (!s)
- continue; /* Not a data element. */
-
- if (n == 5 && !memcmp (s, "eddsa", 5))
- {
- result = 1;
- break;
- }
- }
- gcry_sexp_release (list);
- return result;
-}
-
-
-/* Return the public key algorithm number if S_KEY is a DSA style key.
- If it is not a DSA style key, return 0. */
-int
-agent_is_dsa_key (gcry_sexp_t s_key)
-{
- int result;
- gcry_sexp_t list;
- char algoname[6];
-
- if (!s_key)
- return 0;
-
- if (key_parms_from_sexp (s_key, &list, algoname, sizeof algoname, NULL, 0))
- return 0; /* Error - assume it is not an DSA key. */
-
- if (!strcmp (algoname, "dsa"))
- result = GCRY_PK_DSA;
- else if (!strcmp (algoname, "ecc"))
- {
- if (is_eddsa (list))
- result = 0;
- else
- result = GCRY_PK_ECDSA;
- }
- else if (!strcmp (algoname, "ecdsa"))
- result = GCRY_PK_ECDSA;
- else
- result = 0;
-
- gcry_sexp_release (list);
- return result;
-}
-
-
-/* Return true if S_KEY is an EdDSA key as used with curve Ed25519. */
-int
-agent_is_eddsa_key (gcry_sexp_t s_key)
-{
- int result;
- gcry_sexp_t list;
- char algoname[6];
-
- if (!s_key)
- return 0;
-
- if (key_parms_from_sexp (s_key, &list, algoname, sizeof algoname, NULL, 0))
- return 0; /* Error - assume it is not an EdDSA key. */
-
- if (!strcmp (algoname, "ecc") && is_eddsa (list))
- result = 1;
- else if (!strcmp (algoname, "eddsa")) /* backward compatibility. */
- result = 1;
- else
- result = 0;
-
- gcry_sexp_release (list);
- return result;
-}
-
-
/* Return the key for the keygrip GRIP. The result is stored at
RESULT. This function extracts the key from the private key
database and returns it as an S-expression object as it is. On
@@ -995,43 +669,110 @@
const unsigned char *grip,
gcry_sexp_t *result)
{
- gpg_error_t err;
- int i, idx;
+ int i, idx, rc;
gcry_sexp_t s_skey;
- const char *algoname, *elems;
- int npkey;
- gcry_mpi_t array[10];
- gcry_sexp_t curve = NULL;
- gcry_sexp_t flags = NULL;
+ const char *algoname;
gcry_sexp_t uri_sexp, comment_sexp;
const char *uri, *comment;
size_t uri_length, comment_length;
char *format, *p;
- void *args[2+7+2+2+1]; /* Size is 2 + max. # of elements + 2 for uri + 2
- for comment + end-of-list. */
+ void *args[4+2+2+1]; /* Size is max. # of elements + 2 for uri + 2
+ for comment + end-of-list. */
int argidx;
- gcry_sexp_t list = NULL;
+ gcry_sexp_t list, l2;
+ const char *name;
const char *s;
+ size_t n;
+ const char *elems;
+ gcry_mpi_t *array;
(void)ctrl;
*result = NULL;
- err = read_key_file (grip, &s_skey);
- if (err)
- return err;
+ rc = read_key_file (grip, &s_skey);
+ if (rc)
+ return rc;
- for (i=0; i < DIM (array); i++)
- array[i] = NULL;
+ list = gcry_sexp_find_token (s_skey, "shadowed-private-key", 0 );
+ if (!list)
+ list = gcry_sexp_find_token (s_skey, "protected-private-key", 0 );
+ if (!list)
+ list = gcry_sexp_find_token (s_skey, "private-key", 0 );
+ if (!list)
+ {
+ log_error ("invalid private key format\n");
+ gcry_sexp_release (s_skey);
+ return gpg_error (GPG_ERR_BAD_SECKEY);
+ }
- err = extract_private_key (s_skey, 0, &algoname, &npkey, NULL, &elems,
- array, DIM (array), &curve, &flags);
- if (err)
+ l2 = gcry_sexp_cadr (list);
+ gcry_sexp_release (list);
+ list = l2;
+ name = gcry_sexp_nth_data (list, 0, &n);
+ if (n==3 && !memcmp (name, "rsa", 3))
+ {
+ algoname = "rsa";
+ elems = "ne";
+ }
+ else if (n==3 && !memcmp (name, "dsa", 3))
+ {
+ algoname = "dsa";
+ elems = "pqgy";
+ }
+ else if (n==3 && !memcmp (name, "elg", 3))
+ {
+ algoname = "elg";
+ elems = "pgy";
+ }
+ else
+ {
+ log_error ("unknown private key algorithm\n");
+ gcry_sexp_release (list);
+ gcry_sexp_release (s_skey);
+ return gpg_error (GPG_ERR_BAD_SECKEY);
+ }
+
+ /* Allocate an array for the parameters and copy them out of the
+ secret key. FIXME: We should have a generic copy function. */
+ array = xtrycalloc (strlen(elems) + 1, sizeof *array);
+ if (!array)
{
+ rc = gpg_error_from_syserror ();
+ gcry_sexp_release (list);
gcry_sexp_release (s_skey);
- return err;
+ return rc;
}
+ for (idx=0, s=elems; *s; s++, idx++ )
+ {
+ l2 = gcry_sexp_find_token (list, s, 1);
+ if (!l2)
+ {
+ /* Required parameter not found. */
+ for (i=0; i 0; i--)
putc ('\xff', infp);
fflush (infp);
@@ -155,13 +150,13 @@
if (opt.enforce_passphrase_constraints)
{
- err = agent_show_message (ctrl, desc, L_("Enter new passphrase"));
+ err = agent_show_message (ctrl, desc, _("Enter new passphrase"));
if (!err)
err = gpg_error (GPG_ERR_CANCELED);
}
else
err = agent_get_confirmation (ctrl, desc,
- anyway_btn, L_("Enter new passphrase"), 0);
+ anyway_btn, _("Enter new passphrase"), 0);
return err;
}
@@ -169,155 +164,109 @@
static int
take_this_one_anyway (ctrl_t ctrl, const char *desc)
{
- return take_this_one_anyway2 (ctrl, desc, L_("Take this one anyway"));
+ return take_this_one_anyway2 (ctrl, desc, _("Take this one anyway"));
}
/* Check whether the passphrase PW is suitable. Returns 0 if the
passphrase is suitable and true if it is not and the user should be
- asked to provide a different one. If FAILED_CONSTRAINT is set, a
- message describing the problem is returned in
- *FAILED_CONSTRAINT. */
+ asked to provide a different one. If SILENT is set, no message are
+ displayed. */
int
-check_passphrase_constraints (ctrl_t ctrl, const char *pw,
- char **failed_constraint)
+check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent)
{
- gpg_error_t err = 0;
+ gpg_error_t err;
unsigned int minlen = opt.min_passphrase_len;
unsigned int minnonalpha = opt.min_passphrase_nonalpha;
- char *msg1 = NULL;
- char *msg2 = NULL;
- char *msg3 = NULL;
if (!pw)
pw = "";
- /* The first check is to warn about an empty passphrase. */
- if (!*pw)
- {
- const char *desc = (opt.enforce_passphrase_constraints?
- L_("You have not entered a passphrase!%0A"
- "An empty passphrase is not allowed.") :
- L_("You have not entered a passphrase - "
- "this is in general a bad idea!%0A"
- "Please confirm that you do not want to "
- "have any protection on your key."));
-
- err = 1;
- if (failed_constraint)
- {
- if (opt.enforce_passphrase_constraints)
- *failed_constraint = xstrdup (desc);
- else
- err = take_this_one_anyway2 (ctrl, desc,
- L_("Yes, protection is not needed"));
- }
-
- goto leave;
- }
-
- /* Now check the constraints and collect the error messages unless
- in in silent mode which returns immediately. */
if (utf8_charcount (pw) < minlen )
{
- if (!failed_constraint)
- {
- err = gpg_error (GPG_ERR_INV_PASSPHRASE);
- goto leave;
- }
+ char *desc;
+
+ if (silent)
+ return gpg_error (GPG_ERR_INV_PASSPHRASE);
- msg1 = xtryasprintf
- ( ngettext ("A passphrase should be at least %u character long.",
+ desc = xtryasprintf
+ ( ngettext ("Warning: You have entered an insecure passphrase.%%0A"
+ "A passphrase should be at least %u character long.",
+ "Warning: You have entered an insecure passphrase.%%0A"
"A passphrase should be at least %u characters long.",
minlen), minlen );
- if (!msg1)
- {
- err = gpg_error_from_syserror ();
- goto leave;
- }
+ if (!desc)
+ return gpg_error_from_syserror ();
+ err = take_this_one_anyway (ctrl, desc);
+ xfree (desc);
+ if (err)
+ return err;
}
if (nonalpha_count (pw) < minnonalpha )
{
- if (!failed_constraint)
- {
- err = gpg_error (GPG_ERR_INV_PASSPHRASE);
- goto leave;
- }
+ char *desc;
+
+ if (silent)
+ return gpg_error (GPG_ERR_INV_PASSPHRASE);
- msg2 = xtryasprintf
- ( ngettext ("A passphrase should contain at least %u digit or%%0A"
+ desc = xtryasprintf
+ ( ngettext ("Warning: You have entered an insecure passphrase.%%0A"
+ "A passphrase should contain at least %u digit or%%0A"
"special character.",
+ "Warning: You have entered an insecure passphrase.%%0A"
"A passphrase should contain at least %u digits or%%0A"
"special characters.",
minnonalpha), minnonalpha );
- if (!msg2)
- {
- err = gpg_error_from_syserror ();
- goto leave;
- }
+ if (!desc)
+ return gpg_error_from_syserror ();
+ err = take_this_one_anyway (ctrl, desc);
+ xfree (desc);
+ if (err)
+ return err;
}
- /* If configured check the passphrase against a list of known words
+ /* If configured check the passphrase against a list of know words
and pattern. The actual test is done by an external program.
The warning message is generic to give the user no hint on how to
circumvent this list. */
if (*pw && opt.check_passphrase_pattern &&
check_passphrase_pattern (ctrl, pw))
{
- if (!failed_constraint)
- {
- err = gpg_error (GPG_ERR_INV_PASSPHRASE);
- goto leave;
- }
+ const char *desc =
+ /* */ _("Warning: You have entered an insecure passphrase.%%0A"
+ "A passphrase may not be a known term or match%%0A"
+ "certain pattern.");
- msg3 = xtryasprintf
- (L_("A passphrase may not be a known term or match%%0A"
- "certain pattern."));
- if (!msg3)
- {
- err = gpg_error_from_syserror ();
- goto leave;
- }
+ if (silent)
+ return gpg_error (GPG_ERR_INV_PASSPHRASE);
+
+ err = take_this_one_anyway (ctrl, desc);
+ if (err)
+ return err;
}
- if (failed_constraint && (msg1 || msg2 || msg3))
+ /* The final check is to warn about an empty passphrase. */
+ if (!*pw)
{
- char *msg;
- size_t n;
+ const char *desc = (opt.enforce_passphrase_constraints?
+ _("You have not entered a passphrase!%0A"
+ "An empty passphrase is not allowed.") :
+ _("You have not entered a passphrase - "
+ "this is in general a bad idea!%0A"
+ "Please confirm that you do not want to "
+ "have any protection on your key."));
+
+ if (silent)
+ return gpg_error (GPG_ERR_INV_PASSPHRASE);
+
+ err = take_this_one_anyway2 (ctrl, desc,
+ _("Yes, protection is not needed"));
+ if (err)
+ return err;
+ }
- msg = strconcat
- (L_("Warning: You have entered an insecure passphrase."),
- "%0A%0A",
- msg1? msg1 : "", msg1? "%0A" : "",
- msg2? msg2 : "", msg2? "%0A" : "",
- msg3? msg3 : "", msg3? "%0A" : "",
- NULL);
- if (!msg)
- {
- err = gpg_error_from_syserror ();
- goto leave;
- }
- /* Strip a trailing "%0A". */
- n = strlen (msg);
- if (n > 3 && !strcmp (msg + n - 3, "%0A"))
- msg[n-3] = 0;
-
- err = 1;
- if (opt.enforce_passphrase_constraints)
- *failed_constraint = msg;
- else
- {
- err = take_this_one_anyway (ctrl, msg);
- xfree (msg);
- }
- }
-
- leave:
- xfree (msg1);
- xfree (msg2);
- xfree (msg3);
- return err;
+ return 0;
}
@@ -334,110 +283,15 @@
}
-/* Ask the user for a new passphrase using PROMPT. On success the
- function returns 0 and store the passphrase at R_PASSPHRASE; if the
- user opted not to use a passphrase NULL will be stored there. The
- user needs to free the returned string. In case of an error and
- error code is returned and NULL stored at R_PASSPHRASE. */
-gpg_error_t
-agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
- char **r_passphrase)
-{
- gpg_error_t err;
- const char *text1 = prompt;
- const char *text2 = L_("Please re-enter this passphrase");
- char *initial_errtext = NULL;
- struct pin_entry_info_s *pi, *pi2;
-
- *r_passphrase = NULL;
-
- if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
- {
- size_t size;
- size_t len = 100;
- unsigned char *buffer;
-
- err = pinentry_loopback(ctrl, "NEW_PASSPHRASE", &buffer, &size, len);
- if (!err)
- {
- if (size)
- {
- buffer[size] = 0;
- *r_passphrase = buffer;
- }
- else
- *r_passphrase = NULL;
- }
- return err;
- }
-
- pi = gcry_calloc_secure (2, sizeof (*pi) + 100);
- pi2 = pi + (sizeof *pi + 100);
- pi->max_length = 100;
- pi->max_tries = 3;
- pi->with_qualitybar = 1;
- pi->with_repeat = 1;
- pi2->max_length = 100;
- pi2->max_tries = 3;
- pi2->check_cb = reenter_compare_cb;
- pi2->check_cb_arg = pi->pin;
-
- next_try:
- err = agent_askpin (ctrl, text1, NULL, initial_errtext, pi, NULL, 0);
- xfree (initial_errtext);
- initial_errtext = NULL;
- if (!err)
- {
- if (check_passphrase_constraints (ctrl, pi->pin, &initial_errtext))
- {
- pi->failed_tries = 0;
- pi2->failed_tries = 0;
- goto next_try;
- }
- /* Unless the passphrase is empty or the pinentry told us that
- it already did the repetition check, ask to confirm it. */
- if (*pi->pin && !pi->repeat_okay)
- {
- err = agent_askpin (ctrl, text2, NULL, NULL, pi2, NULL, 0);
- if (err == -1)
- { /* The re-entered one did not match and the user did not
- hit cancel. */
- initial_errtext = xtrystrdup (L_("does not match - try again"));
- if (initial_errtext)
- goto next_try;
- err = gpg_error_from_syserror ();
- }
- }
- }
-
- if (!err && *pi->pin)
- {
- /* User wants a passphrase. */
- *r_passphrase = xtrystrdup (pi->pin);
- if (!*r_passphrase)
- err = gpg_error_from_syserror ();
- }
-
- xfree (initial_errtext);
- xfree (pi);
- return err;
-}
-
-
/* Generate a new keypair according to the parameters given in
- KEYPARAM. If CACHE_NONCE is given first try to lookup a passphrase
- using the cache nonce. If NO_PROTECTION is true the key will not
- be protected by a passphrase. If OVERRIDE_PASSPHRASE is true that
- passphrase will be used for the new key. */
+ KEYPARAM */
int
-agent_genkey (ctrl_t ctrl, const char *cache_nonce,
- const char *keyparam, size_t keyparamlen, int no_protection,
- const char *override_passphrase, int preset, membuf_t *outbuf)
+agent_genkey (ctrl_t ctrl, const char *keyparam, size_t keyparamlen,
+ membuf_t *outbuf)
{
gcry_sexp_t s_keyparam, s_key, s_private, s_public;
- char *passphrase_buffer = NULL;
- const char *passphrase;
+ struct pin_entry_info_s *pi, *pi2;
int rc;
size_t len;
char *buf;
@@ -450,35 +304,63 @@
}
/* Get the passphrase now, cause key generation may take a while. */
- if (override_passphrase)
- passphrase = override_passphrase;
- else if (no_protection || !cache_nonce)
- passphrase = NULL;
- else
- {
- passphrase_buffer = agent_get_cache (cache_nonce, CACHE_MODE_NONCE);
- passphrase = passphrase_buffer;
- }
-
- if (passphrase || no_protection)
- ;
- else
- {
- rc = agent_ask_new_passphrase (ctrl,
- L_("Please enter the passphrase to%0A"
- "protect your new key"),
- &passphrase_buffer);
- if (rc)
+ {
+ const char *text1 = _("Please enter the passphrase to%0A"
+ "protect your new key");
+ const char *text2 = _("Please re-enter this passphrase");
+ const char *initial_errtext = NULL;
+
+ pi = gcry_calloc_secure (2, sizeof (*pi) + 100);
+ pi2 = pi + (sizeof *pi + 100);
+ pi->max_length = 100;
+ pi->max_tries = 3;
+ pi->with_qualitybar = 1;
+ pi2->max_length = 100;
+ pi2->max_tries = 3;
+ pi2->check_cb = reenter_compare_cb;
+ pi2->check_cb_arg = pi->pin;
+
+ next_try:
+ rc = agent_askpin (ctrl, text1, NULL, initial_errtext, pi, NULL, 0);
+ initial_errtext = NULL;
+ if (!rc)
+ {
+ if (check_passphrase_constraints (ctrl, pi->pin, 0))
+ {
+ pi->failed_tries = 0;
+ pi2->failed_tries = 0;
+ goto next_try;
+ }
+ if (pi->pin && *pi->pin)
+ {
+ rc = agent_askpin (ctrl, text2, NULL, NULL, pi2, NULL, 0);
+ if (rc == -1)
+ { /* The re-entered one did not match and the user did not
+ hit cancel. */
+ initial_errtext = _("does not match - try again");
+ goto next_try;
+ }
+ }
+ }
+ if (rc)
+ {
+ xfree (pi);
return rc;
- passphrase = passphrase_buffer;
- }
+ }
+
+ if (!*pi->pin)
+ {
+ xfree (pi);
+ pi = NULL; /* User does not want a passphrase. */
+ }
+ }
rc = gcry_pk_genkey (&s_key, s_keyparam );
gcry_sexp_release (s_keyparam);
if (rc)
{
log_error ("key generation failed: %s\n", gpg_strerror (rc));
- xfree (passphrase_buffer);
+ xfree (pi);
return rc;
}
@@ -488,7 +370,7 @@
{
log_error ("key generation failed: invalid return value\n");
gcry_sexp_release (s_key);
- xfree (passphrase_buffer);
+ xfree (pi);
return gpg_error (GPG_ERR_INV_DATA);
}
s_public = gcry_sexp_find_token (s_key, "public-key", 0);
@@ -497,7 +379,7 @@
log_error ("key generation failed: invalid return value\n");
gcry_sexp_release (s_private);
gcry_sexp_release (s_key);
- xfree (passphrase_buffer);
+ xfree (pi);
return gpg_error (GPG_ERR_INV_DATA);
}
gcry_sexp_release (s_key); s_key = NULL;
@@ -505,35 +387,8 @@
/* store the secret key */
if (DBG_CRYPTO)
log_debug ("storing private key\n");
- rc = store_key (s_private, passphrase, 0, ctrl->s2k_count);
- if (!rc)
- {
- if (!cache_nonce)
- {
- char tmpbuf[12];
- gcry_create_nonce (tmpbuf, 12);
- cache_nonce = bin2hex (tmpbuf, 12, NULL);
- }
- if (cache_nonce
- && !no_protection
- && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
- passphrase, ctrl->cache_ttl_opt_preset))
- agent_write_status (ctrl, "CACHE_NONCE", cache_nonce, NULL);
- if (preset && !no_protection)
- {
- unsigned char grip[20];
- char hexgrip[40+1];
- if (gcry_pk_get_keygrip (s_private, grip))
- {
- bin2hex(grip, 20, hexgrip);
- rc = agent_put_cache (hexgrip, CACHE_MODE_ANY, passphrase,
- ctrl->cache_ttl_opt_preset);
- }
- }
- }
- xfree (passphrase_buffer);
- passphrase_buffer = NULL;
- passphrase = NULL;
+ rc = store_key (s_private, pi? pi->pin:NULL, 0);
+ xfree (pi); pi = NULL;
gcry_sexp_release (s_private);
if (rc)
{
@@ -565,41 +420,65 @@
-/* Apply a new passphrase to the key S_SKEY and store it. If
- PASSPHRASE_ADDR and *PASSPHRASE_ADDR are not NULL, use that
- passphrase. If PASSPHRASE_ADDR is not NULL store a newly entered
- passphrase at that address. */
-gpg_error_t
-agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
- char **passphrase_addr)
+/* Apply a new passpahrse to the key S_SKEY and store it. */
+int
+agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey)
{
- gpg_error_t err;
+ struct pin_entry_info_s *pi, *pi2;
+ int rc;
- if (passphrase_addr && *passphrase_addr)
- {
- /* Take an empty string as request not to protect the key. */
- err = store_key (s_skey, **passphrase_addr? *passphrase_addr:NULL, 1,
- ctrl->s2k_count);
- }
- else
- {
- char *pass = NULL;
+ {
+ const char *text1 = _("Please enter the new passphrase");
+ const char *text2 = _("Please re-enter this passphrase");
+ const char *initial_errtext = NULL;
+
+ pi = gcry_calloc_secure (2, sizeof (*pi) + 100);
+ pi2 = pi + (sizeof *pi + 100);
+ pi->max_length = 100;
+ pi->max_tries = 3;
+ pi->with_qualitybar = 1;
+ pi2->max_length = 100;
+ pi2->max_tries = 3;
+ pi2->check_cb = reenter_compare_cb;
+ pi2->check_cb_arg = pi->pin;
+
+ next_try:
+ rc = agent_askpin (ctrl, text1, NULL, initial_errtext, pi, NULL, 0);
+ initial_errtext = NULL;
+ if (!rc)
+ {
+ if (check_passphrase_constraints (ctrl, pi->pin, 0))
+ {
+ pi->failed_tries = 0;
+ pi2->failed_tries = 0;
+ goto next_try;
+ }
+ /* Unless the passphrase is empty, ask to confirm it. */
+ if (pi->pin && *pi->pin)
+ {
+ rc = agent_askpin (ctrl, text2, NULL, NULL, pi2, NULL, 0);
+ if (rc == -1)
+ { /* The re-entered one did not match and the user did not
+ hit cancel. */
+ initial_errtext = _("does not match - try again");
+ goto next_try;
+ }
+ }
+ }
+ if (rc)
+ {
+ xfree (pi);
+ return rc;
+ }
- if (passphrase_addr)
- {
- xfree (*passphrase_addr);
- *passphrase_addr = NULL;
- }
- err = agent_ask_new_passphrase (ctrl,
- L_("Please enter the new passphrase"),
- &pass);
- if (!err)
- err = store_key (s_skey, pass, 1, ctrl->s2k_count);
- if (!err && passphrase_addr)
- *passphrase_addr = pass;
- else
- xfree (pass);
- }
+ if (!*pi->pin)
+ {
+ xfree (pi);
+ pi = NULL; /* User does not want a passphrase. */
+ }
+ }
- return err;
+ rc = store_key (s_skey, pi? pi->pin:NULL, 1);
+ xfree (pi);
+ return rc;
}
diff -Nru gnupg2-2.1.6~build1/agent/gpg-agent.c gnupg2-2.0.28/agent/gpg-agent.c
--- gnupg2-2.1.6~build1/agent/gpg-agent.c 2015-07-01 12:14:32.000000000 +0000
+++ gnupg2-2.0.28/agent/gpg-agent.c 2015-06-02 08:13:55.000000000 +0000
@@ -1,6 +1,7 @@
/* gpg-agent.c - The GnuPG Agent
- * Copyright (C) 2000-2007, 2009-2010 Free Software Foundation, Inc.
- * Copyright (C) 2000-2014 Werner Koch
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005,
+ * 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2013 Werner Koch
*
* This file is part of GnuPG.
*
@@ -44,23 +45,21 @@
# include
#endif /*!HAVE_W32_SYSTEM*/
#include
-#ifdef HAVE_SIGNAL_H
-# include
-#endif
-#include
+#include
+#include
-#define GNUPG_COMMON_NEED_AFLOCAL
+#define JNLIB_NEED_LOG_LOGV
+#define JNLIB_NEED_AFLOCAL
#include "agent.h"
#include /* Malloc hooks and socket wrappers. */
#include "i18n.h"
+#include "mkdtemp.h" /* Gnulib replacement. */
#include "sysutils.h"
+#include "setenv.h"
#include "gc-opt-flags.h"
#include "exechelp.h"
-#include "asshelp.h"
-#include "openpgpdefs.h" /* for PUBKEY_ALGO_ECDSA, PUBKEY_ALGO_ECDH */
-#include "../common/init.h"
-
+#include "../common/estream.h"
enum cmd_and_opt_values
{ aNull = 0,
@@ -78,8 +77,6 @@
oDebugAll,
oDebugLevel,
oDebugWait,
- oDebugQuickRandom,
- oDebugPinentry,
oNoGreeting,
oNoOptions,
oHomedir,
@@ -111,150 +108,105 @@
oEnablePassphraseHistory,
oUseStandardSocket,
oNoUseStandardSocket,
- oExtraSocket,
- oBrowserSocket,
oFakedSystemTime,
oIgnoreCacheForSigning,
oAllowMarkTrusted,
oNoAllowMarkTrusted,
oAllowPresetPassphrase,
- oAllowLoopbackPinentry,
oNoAllowExternalCache,
- oAllowEmacsPinentry,
oKeepTTY,
oKeepDISPLAY,
oSSHSupport,
oPuttySupport,
oDisableScdaemon,
- oDisableCheckOwnSocket,
oWriteEnvFile
};
-#ifndef ENAMETOOLONG
-# define ENAMETOOLONG EINVAL
-#endif
-
static ARGPARSE_OPTS opts[] = {
- ARGPARSE_c (aGPGConfList, "gpgconf-list", "@"),
- ARGPARSE_c (aGPGConfTest, "gpgconf-test", "@"),
- ARGPARSE_c (aUseStandardSocketP, "use-standard-socket-p", "@"),
-
- ARGPARSE_group (301, N_("@Options:\n ")),
-
- ARGPARSE_s_n (oDaemon, "daemon", N_("run in daemon mode (background)")),
- ARGPARSE_s_n (oServer, "server", N_("run in server mode (foreground)")),
- ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
- ARGPARSE_s_n (oQuiet, "quiet", N_("be somewhat more quiet")),
- ARGPARSE_s_n (oSh, "sh", N_("sh-style command output")),
- ARGPARSE_s_n (oCsh, "csh", N_("csh-style command output")),
- ARGPARSE_s_s (oOptions, "options", N_("|FILE|read options from FILE")),
-
- ARGPARSE_s_s (oDebug, "debug", "@"),
- ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
- ARGPARSE_s_s (oDebugLevel, "debug-level", "@"),
- ARGPARSE_s_i (oDebugWait," debug-wait", "@"),
- ARGPARSE_s_n (oDebugQuickRandom, "debug-quick-random", "@"),
- ARGPARSE_s_n (oDebugPinentry, "debug-pinentry", "@"),
-
- ARGPARSE_s_n (oNoDetach, "no-detach", N_("do not detach from the console")),
- ARGPARSE_s_n (oNoGrab, "no-grab", N_("do not grab keyboard and mouse")),
- ARGPARSE_s_s (oLogFile, "log-file", N_("use a log file for the server")),
- ARGPARSE_s_s (oPinentryProgram, "pinentry-program",
- /* */ N_("|PGM|use PGM as the PIN-Entry program")),
- ARGPARSE_s_s (oPinentryTouchFile, "pinentry-touch-file", "@"),
- ARGPARSE_s_s (oScdaemonProgram, "scdaemon-program",
- /* */ N_("|PGM|use PGM as the SCdaemon program") ),
- ARGPARSE_s_n (oDisableScdaemon, "disable-scdaemon",
- /* */ N_("do not use the SCdaemon") ),
- ARGPARSE_s_n (oDisableCheckOwnSocket, "disable-check-own-socket", "@"),
-
- ARGPARSE_s_s (oExtraSocket, "extra-socket",
- /* */ N_("|NAME|accept some commands via NAME")),
-
- ARGPARSE_s_s (oBrowserSocket, "browser-socket", "@"),
-
- ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"),
-
- ARGPARSE_s_n (oBatch, "batch", "@"),
- ARGPARSE_s_s (oHomedir, "homedir", "@"),
-
- ARGPARSE_s_s (oDisplay, "display", "@"),
- ARGPARSE_s_s (oTTYname, "ttyname", "@"),
- ARGPARSE_s_s (oTTYtype, "ttytype", "@"),
- ARGPARSE_s_s (oLCctype, "lc-ctype", "@"),
- ARGPARSE_s_s (oLCmessages, "lc-messages", "@"),
- ARGPARSE_s_s (oXauthority, "xauthority", "@"),
- ARGPARSE_s_n (oKeepTTY, "keep-tty",
- /* */ N_("ignore requests to change the TTY")),
- ARGPARSE_s_n (oKeepDISPLAY, "keep-display",
- /* */ N_("ignore requests to change the X display")),
-
- ARGPARSE_s_u (oDefCacheTTL, "default-cache-ttl",
- N_("|N|expire cached PINs after N seconds")),
- ARGPARSE_s_u (oDefCacheTTLSSH, "default-cache-ttl-ssh", "@" ),
- ARGPARSE_s_u (oMaxCacheTTL, "max-cache-ttl", "@" ),
- ARGPARSE_s_u (oMaxCacheTTLSSH, "max-cache-ttl-ssh", "@" ),
-
- ARGPARSE_s_n (oEnforcePassphraseConstraints, "enforce-passphrase-constraints",
- /* */ "@"),
- ARGPARSE_s_u (oMinPassphraseLen, "min-passphrase-len", "@"),
- ARGPARSE_s_u (oMinPassphraseNonalpha, "min-passphrase-nonalpha", "@"),
- ARGPARSE_s_s (oCheckPassphrasePattern, "check-passphrase-pattern", "@"),
- ARGPARSE_s_u (oMaxPassphraseDays, "max-passphrase-days", "@"),
- ARGPARSE_s_n (oEnablePassphraseHistory, "enable-passphrase-history", "@"),
-
- ARGPARSE_s_n (oIgnoreCacheForSigning, "ignore-cache-for-signing",
- /* */ N_("do not use the PIN cache when signing")),
- ARGPARSE_s_n (oNoAllowExternalCache, "no-allow-external-cache",
- /* */ N_("disallow the use of an external password cache")),
- ARGPARSE_s_n (oNoAllowMarkTrusted, "no-allow-mark-trusted",
- /* */ N_("disallow clients to mark keys as \"trusted\"")),
- ARGPARSE_s_n (oAllowMarkTrusted, "allow-mark-trusted", "@"),
- ARGPARSE_s_n (oAllowPresetPassphrase, "allow-preset-passphrase",
- /* */ N_("allow presetting passphrase")),
- ARGPARSE_s_n (oAllowLoopbackPinentry, "allow-loopback-pinentry",
- N_("allow caller to override the pinentry")),
- ARGPARSE_s_n (oAllowEmacsPinentry, "allow-emacs-pinentry",
- /* */ N_("allow passphrase to be prompted through Emacs")),
-
- ARGPARSE_s_n (oSSHSupport, "enable-ssh-support", N_("enable ssh support")),
- ARGPARSE_s_n (oPuttySupport, "enable-putty-support",
+ { aGPGConfList, "gpgconf-list", 256, "@" },
+ { aGPGConfTest, "gpgconf-test", 256, "@" },
+ { aUseStandardSocketP, "use-standard-socket-p", 256, "@" },
+
+ { 301, NULL, 0, N_("@Options:\n ") },
+
+ { oDaemon, "daemon", 0, N_("run in daemon mode (background)") },
+ { oServer, "server", 0, N_("run in server mode (foreground)") },
+ { oVerbose, "verbose", 0, N_("verbose") },
+ { oQuiet, "quiet", 0, N_("be somewhat more quiet") },
+ { oSh, "sh", 0, N_("sh-style command output") },
+ { oCsh, "csh", 0, N_("csh-style command output") },
+ { oOptions, "options" , 2, N_("|FILE|read options from FILE")},
+ { oDebug, "debug" ,4|16, "@"},
+ { oDebugAll, "debug-all" ,0, "@"},
+ { oDebugLevel, "debug-level" ,2, "@"},
+ { oDebugWait,"debug-wait",1, "@"},
+ { oNoDetach, "no-detach" ,0, N_("do not detach from the console")},
+ { oNoGrab, "no-grab" ,0, N_("do not grab keyboard and mouse")},
+ { oLogFile, "log-file" ,2, N_("use a log file for the server")},
+ { oUseStandardSocket, "use-standard-socket", 0,
+ N_("use a standard location for the socket")},
+ { oNoUseStandardSocket, "no-use-standard-socket", 0, "@"},
+ { oPinentryProgram, "pinentry-program", 2 ,
+ N_("|PGM|use PGM as the PIN-Entry program") },
+ { oPinentryTouchFile, "pinentry-touch-file", 2 , "@" },
+ { oScdaemonProgram, "scdaemon-program", 2 ,
+ N_("|PGM|use PGM as the SCdaemon program") },
+ { oDisableScdaemon, "disable-scdaemon", 0, N_("do not use the SCdaemon") },
+ { oFakedSystemTime, "faked-system-time", 2, "@" }, /* (epoch time) */
+
+ { oBatch, "batch", 0, "@" },
+ { oHomedir, "homedir", 2, "@"},
+
+ { oDisplay, "display", 2, "@" },
+ { oTTYname, "ttyname", 2, "@" },
+ { oTTYtype, "ttytype", 2, "@" },
+ { oLCctype, "lc-ctype", 2, "@" },
+ { oLCmessages, "lc-messages", 2, "@" },
+ { oXauthority, "xauthority", 2, "@" },
+ { oKeepTTY, "keep-tty", 0, N_("ignore requests to change the TTY")},
+ { oKeepDISPLAY, "keep-display",
+ 0, N_("ignore requests to change the X display")},
+
+ { oDefCacheTTL, "default-cache-ttl", 4,
+ N_("|N|expire cached PINs after N seconds")},
+ { oDefCacheTTLSSH, "default-cache-ttl-ssh", 4, "@" },
+ { oMaxCacheTTL, "max-cache-ttl", 4, "@" },
+ { oMaxCacheTTLSSH, "max-cache-ttl-ssh", 4, "@" },
+
+ { oEnforcePassphraseConstraints, "enforce-passphrase-constraints", 0, "@"},
+ { oMinPassphraseLen, "min-passphrase-len", 4, "@" },
+ { oMinPassphraseNonalpha, "min-passphrase-nonalpha", 4, "@" },
+ { oCheckPassphrasePattern, "check-passphrase-pattern", 2, "@" },
+ { oMaxPassphraseDays, "max-passphrase-days", 4, "@" },
+ { oEnablePassphraseHistory, "enable-passphrase-history", 0, "@" },
+
+ { oIgnoreCacheForSigning, "ignore-cache-for-signing", 0,
+ N_("do not use the PIN cache when signing")},
+ { oNoAllowMarkTrusted, "no-allow-mark-trusted", 0,
+ N_("disallow clients to mark keys as \"trusted\"")},
+ { oAllowMarkTrusted, "allow-mark-trusted", 0, "@"},
+ { oAllowPresetPassphrase, "allow-preset-passphrase", 0,
+ N_("allow presetting passphrase")},
+ { oSSHSupport, "enable-ssh-support", 0, N_("enable ssh support") },
+ { oPuttySupport, "enable-putty-support", 0,
#ifdef HAVE_W32_SYSTEM
- /* */ N_("enable putty support")
+ N_("enable putty support")
#else
- /* */ "@"
+ "@"
#endif
- ),
-
- /* Dummy options for backward compatibility. */
- ARGPARSE_o_s (oWriteEnvFile, "write-env-file", "@"),
- ARGPARSE_s_n (oUseStandardSocket, "use-standard-socket", "@"),
- ARGPARSE_s_n (oNoUseStandardSocket, "no-use-standard-socket", "@"),
-
- {0} /* End of list */
+ },
+ { oNoAllowExternalCache, "no-allow-external-cache", 0,
+ N_("disallow the use of an external password cache") },
+ { oWriteEnvFile, "write-env-file", 2|8,
+ N_("|FILE|write environment settings also to FILE")},
+ {0}
};
-/* The list of supported debug flags. */
-static struct debug_flags_s debug_flags [] =
- {
- { DBG_COMMAND_VALUE, "command" },
- { DBG_MPI_VALUE , "mpi" },
- { DBG_CRYPTO_VALUE , "crypto" },
- { DBG_MEMORY_VALUE , "memory" },
- { DBG_CACHE_VALUE , "cache" },
- { DBG_MEMSTAT_VALUE, "memstat" },
- { DBG_HASHING_VALUE, "hashing" },
- { DBG_IPC_VALUE , "ipc" },
- { 77, NULL } /* 77 := Do not exit on "help" or "?". */
- };
-
-
-
#define DEFAULT_CACHE_TTL (10*60) /* 10 minutes */
#define DEFAULT_CACHE_TTL_SSH (30*60) /* 30 minutes */
#define MAX_CACHE_TTL (120*60) /* 2 hours */
@@ -265,24 +217,14 @@
/* The timer tick used for housekeeping stuff. For Windows we use a
longer period as the SetWaitableTimer seems to signal earlier than
- the 2 seconds. CHECK_OWN_SOCKET_INTERVAL defines how often we
- check our own socket in standard socket mode. If that value is 0
- we don't check at all. All values are in seconds. */
-#if defined(HAVE_W32CE_SYSTEM)
-# define TIMERTICK_INTERVAL (60)
-# define CHECK_OWN_SOCKET_INTERVAL (0) /* Never */
-#elif defined(HAVE_W32_SYSTEM)
-# define TIMERTICK_INTERVAL (4)
-# define CHECK_OWN_SOCKET_INTERVAL (60)
+ the 2 seconds. */
+#ifdef HAVE_W32_SYSTEM
+#define TIMERTICK_INTERVAL (4)
#else
-# define TIMERTICK_INTERVAL (2)
-# define CHECK_OWN_SOCKET_INTERVAL (60)
+#define TIMERTICK_INTERVAL (2) /* Seconds. */
#endif
-/* Flag indicating that the ssh-agent subsystem has been enabled. */
-static int ssh_support;
-
#ifdef HAVE_W32_SYSTEM
/* Flag indicating that support for Putty has been enabled. */
static int putty_support;
@@ -310,35 +252,18 @@
/* Counter for the currently running own socket checks. */
static int check_own_socket_running;
-/* Flags to indicate that check_own_socket shall not be called. */
-static int disable_check_own_socket;
-
/* It is possible that we are currently running under setuid permissions */
static int maybe_setuid = 1;
-/* Name of the communication socket used for native gpg-agent
- requests. The second variable is either NULL or a malloced string
- with the real socket name in case it has been redirected. */
+/* Name of the communication socket used for native gpg-agent requests. */
static char *socket_name;
-static char *redir_socket_name;
-
-/* Name of the optional extra socket used for native gpg-agent requests. */
-static char *socket_name_extra;
-static char *redir_socket_name_extra;
-
-/* Name of the optional browser socket used for native gpg-agent requests. */
-static char *socket_name_browser;
-static char *redir_socket_name_browser;
/* Name of the communication socket used for ssh-agent-emulation. */
static char *socket_name_ssh;
-static char *redir_socket_name_ssh;
/* We need to keep track of the server's nonces (these are dummies for
POSIX systems). */
static assuan_sock_nonce_t socket_nonce;
-static assuan_sock_nonce_t socket_nonce_extra;
-static assuan_sock_nonce_t socket_nonce_browser;
static assuan_sock_nonce_t socket_nonce_ssh;
@@ -365,17 +290,13 @@
watched. */
static pid_t parent_pid = (pid_t)(-1);
-/* Number of active connections. */
-static int active_connections;
-
/*
Local prototypes.
*/
-static char *create_socket_name (char *standard_name, int with_homedir);
-static gnupg_fd_t create_server_socket (char *name, int primary, int cygwin,
- char **r_redir_name,
+static char *create_socket_name (char *standard_name, char *template);
+static gnupg_fd_t create_server_socket (char *name, int is_ssh,
assuan_sock_nonce_t *nonce);
static void create_directories (void);
@@ -383,23 +304,36 @@
static void agent_deinit_default_ctrl (ctrl_t ctrl);
static void handle_connections (gnupg_fd_t listen_fd,
- gnupg_fd_t listen_fd_extra,
- gnupg_fd_t listen_fd_browser,
gnupg_fd_t listen_fd_ssh);
static void check_own_socket (void);
-static int check_for_running_agent (int silent);
+static int check_for_running_agent (int silent, int mode);
/* Pth wrapper function definitions. */
-ASSUAN_SYSTEM_NPTH_IMPL;
+ASSUAN_SYSTEM_PTH_IMPL;
+
+#if GCRYPT_VERSION_NUMBER < 0x010600
+GCRY_THREAD_OPTION_PTH_IMPL;
+#if GCRY_THREAD_OPTION_VERSION < 1
+static int fixed_gcry_pth_init (void)
+{
+ return pth_self ()? 0 : (pth_init () == FALSE) ? errno : 0;
+}
+#endif
+#endif /*GCRYPT_VERSION_NUMBER < 0x10600*/
+
+#ifndef PTH_HAVE_PTH_THREAD_ID
+static unsigned long pth_thread_id (void)
+{
+ return (unsigned long)pth_self ();
+}
+#endif
+
/*
Functions.
*/
-/* Allocate a string describing a library version by calling a GETFNC.
- This function is expected to be called only once. GETFNC is
- expected to have a semantic like gcry_check_version (). */
static char *
make_libversion (const char *libname, const char *(*getfnc)(const char*))
{
@@ -417,9 +351,7 @@
return result;
}
-/* Return strings describing this program. The case values are
- described in common/argparse.c:strusage. The values here override
- the default values given by strusage. */
+
static const char *
my_strusage (int level)
{
@@ -428,7 +360,7 @@
switch (level)
{
- case 11: p = "@GPG_AGENT@ (@GNUPG@)";
+ case 11: p = "gpg-agent (GnuPG)";
break;
case 13: p = VERSION; break;
case 17: p = PRINTABLE_OS_NAME; break;
@@ -444,10 +376,10 @@
break;
case 1:
- case 40: p = _("Usage: @GPG_AGENT@ [options] (-h for help)");
+ case 40: p = _("Usage: gpg-agent [options] (-h for help)");
break;
- case 41: p = _("Syntax: @GPG_AGENT@ [options] [command [args]]\n"
- "Secret key management for @GNUPG@\n");
+ case 41: p = _("Syntax: gpg-agent [options] [command [args]]\n"
+ "Secret key management for GnuPG\n");
break;
default: p = NULL;
@@ -474,11 +406,11 @@
else if (!strcmp (debug_level, "none") || (numok && numlvl < 1))
opt.debug = 0;
else if (!strcmp (debug_level, "basic") || (numok && numlvl <= 2))
- opt.debug = DBG_IPC_VALUE;
+ opt.debug = DBG_ASSUAN_VALUE;
else if (!strcmp (debug_level, "advanced") || (numok && numlvl <= 5))
- opt.debug = DBG_IPC_VALUE|DBG_COMMAND_VALUE;
+ opt.debug = DBG_ASSUAN_VALUE|DBG_COMMAND_VALUE;
else if (!strcmp (debug_level, "expert") || (numok && numlvl <= 8))
- opt.debug = (DBG_IPC_VALUE|DBG_COMMAND_VALUE
+ opt.debug = (DBG_ASSUAN_VALUE|DBG_COMMAND_VALUE
|DBG_CACHE_VALUE);
else if (!strcmp (debug_level, "guru") || numok)
{
@@ -492,7 +424,7 @@
}
else
{
- log_error (_("invalid debug-level '%s' given\n"), debug_level);
+ log_error (_("invalid debug-level `%s' given\n"), debug_level);
opt.debug = 0; /* Reset debugging, so that prior debug
statements won't have an undesired effect. */
}
@@ -509,23 +441,27 @@
gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
if (opt.debug)
- parse_debug_flag (NULL, &opt.debug, debug_flags);
+ log_info ("enabled debug flags:%s%s%s%s%s%s%s%s\n",
+ (opt.debug & DBG_COMMAND_VALUE)? " command":"",
+ (opt.debug & DBG_MPI_VALUE )? " mpi":"",
+ (opt.debug & DBG_CRYPTO_VALUE )? " crypto":"",
+ (opt.debug & DBG_MEMORY_VALUE )? " memory":"",
+ (opt.debug & DBG_CACHE_VALUE )? " cache":"",
+ (opt.debug & DBG_MEMSTAT_VALUE)? " memstat":"",
+ (opt.debug & DBG_HASHING_VALUE)? " hashing":"",
+ (opt.debug & DBG_ASSUAN_VALUE )? " assuan":"");
}
-/* Helper for cleanup to remove one socket with NAME. REDIR_NAME is
- the corresponding real name if the socket has been redirected. */
+/* Helper for cleanup to remove one socket with NAME. */
static void
-remove_socket (char *name, char *redir_name)
+remove_socket (char *name)
{
if (name && *name)
{
char *p;
- if (redir_name)
- name = redir_name;
-
- gnupg_remove (name);
+ remove (name);
p = strrchr (name, '/');
if (p)
{
@@ -537,24 +473,11 @@
}
}
-
-/* Cleanup code for this program. This is either called has an atexit
- handler or directly. */
static void
cleanup (void)
{
- static int done;
-
- if (done)
- return;
- done = 1;
- deinitialize_module_cache ();
- remove_socket (socket_name, redir_socket_name);
- if (opt.extra_socket > 1)
- remove_socket (socket_name_extra, redir_socket_name_extra);
- if (opt.browser_socket > 1)
- remove_socket (socket_name_browser, redir_socket_name_browser);
- remove_socket (socket_name_ssh, redir_socket_name_ssh);
+ remove_socket (socket_name);
+ remove_socket (socket_name_ssh);
}
@@ -573,7 +496,6 @@
opt.verbose = 0;
opt.debug = 0;
opt.no_grab = 0;
- opt.debug_pinentry = 0;
opt.pinentry_program = NULL;
opt.pinentry_touch_file = NULL;
opt.scdaemon_program = NULL;
@@ -589,10 +511,8 @@
opt.enable_passhrase_history = 0;
opt.ignore_cache_for_signing = 0;
opt.allow_mark_trusted = 1;
- opt.allow_external_cache = 1;
- opt.allow_emacs_pinentry = 0;
opt.disable_scdaemon = 0;
- disable_check_own_socket = 0;
+ opt.allow_external_cache = 1;
return 1;
}
@@ -601,12 +521,9 @@
case oQuiet: opt.quiet = 1; break;
case oVerbose: opt.verbose++; break;
- case oDebug:
- parse_debug_flag (pargs->r.ret_str, &opt.debug, debug_flags);
- break;
+ case oDebug: opt.debug |= pargs->r.ret_ulong; break;
case oDebugAll: opt.debug = ~0; break;
case oDebugLevel: debug_level = pargs->r.ret_str; break;
- case oDebugPinentry: opt.debug_pinentry = 1; break;
case oLogFile:
if (!reread)
@@ -615,6 +532,8 @@
|| strcmp (current_logfile, pargs->r.ret_str))
{
log_set_file (pargs->r.ret_str);
+ if (DBG_ASSUAN)
+ assuan_set_assuan_log_stream (log_get_stream ());
xfree (current_logfile);
current_logfile = xtrystrdup (pargs->r.ret_str);
}
@@ -626,7 +545,6 @@
case oPinentryTouchFile: opt.pinentry_touch_file = pargs->r.ret_str; break;
case oScdaemonProgram: opt.scdaemon_program = pargs->r.ret_str; break;
case oDisableScdaemon: opt.disable_scdaemon = 1; break;
- case oDisableCheckOwnSocket: disable_check_own_socket = 1; break;
case oDefCacheTTL: opt.def_cache_ttl = pargs->r.ret_ulong; break;
case oDefCacheTTLSSH: opt.def_cache_ttl_ssh = pargs->r.ret_ulong; break;
@@ -657,14 +575,9 @@
case oAllowPresetPassphrase: opt.allow_preset_passphrase = 1; break;
- case oAllowLoopbackPinentry: opt.allow_loopback_pinentry = 1; break;
-
case oNoAllowExternalCache: opt.allow_external_cache = 0;
break;
- case oAllowEmacsPinentry: opt.allow_emacs_pinentry = 1;
- break;
-
default:
return 0; /* not handled */
}
@@ -673,14 +586,6 @@
}
-/* Fixup some options after all have been processed. */
-static void
-finalize_rereadable_options (void)
-{
-}
-
-
-
/* The main entry point. */
int
main (int argc, char **argv )
@@ -694,6 +599,8 @@
unsigned configlineno;
int parse_debug = 0;
int default_config =1;
+ int greeting = 0;
+ int nogreeting = 0;
int pipe_server = 0;
int is_daemon = 0;
int nodetach = 0;
@@ -702,10 +609,9 @@
int debug_wait = 0;
int gpgconf_list = 0;
gpg_error_t err;
+ const char *env_file_name = NULL;
struct assuan_malloc_hooks malloc_hooks;
- early_system_init ();
-
/* Before we do anything else we save the list of currently open
file descriptors and the signal mask. This info is required to
do the exec call properly. */
@@ -721,13 +627,27 @@
/* Please note that we may running SUID(ROOT), so be very CAREFUL
when adding any stuff between here and the call to INIT_SECMEM()
somewhere after the option parsing */
- log_set_prefix (GPG_AGENT_NAME, GPGRT_LOG_WITH_PREFIX|GPGRT_LOG_WITH_PID);
+ log_set_prefix ("gpg-agent", JNLIB_LOG_WITH_PREFIX|JNLIB_LOG_WITH_PID);
/* Make sure that our subsystems are ready. */
i18n_init ();
- init_common_subsystems (&argc, &argv);
+ init_common_subsystems ();
+
+
+#if GCRYPT_VERSION_NUMBER < 0x010600
+ /* Libgcrypt < 1.6 requires us to register the threading model first.
+ Note that this will also do the pth_init. */
+#if GCRY_THREAD_OPTION_VERSION < 1
+ gcry_threads_pth.init = fixed_gcry_pth_init;
+#endif
+ err = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
+ if (err)
+ {
+ log_fatal ("can't register GNU Pth with Libgcrypt: %s\n",
+ gpg_strerror (err));
+ }
+#endif /*GCRYPT_VERSION_NUMBER < 0x010600*/
- npth_init ();
/* Check that the libraries are suitable. Do it here because
the option parsing may need services of the library. */
@@ -741,10 +661,10 @@
malloc_hooks.realloc = gcry_realloc;
malloc_hooks.free = gcry_free;
assuan_set_malloc_hooks (&malloc_hooks);
+ assuan_set_assuan_log_prefix (log_get_prefix (NULL));
assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
- assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
+ assuan_set_system_hooks (ASSUAN_SYSTEM_PTH);
assuan_sock_init ();
- setup_libassuan_logging (&opt.debug);
setup_libgcrypt_logging ();
gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
@@ -753,6 +673,10 @@
/* Set default options. */
parse_rereadable_options (NULL, 0); /* Reset them to default values. */
+#ifdef USE_STANDARD_SOCKET
+ opt.use_standard_socket = 1; /* Under Windows we always use a standard
+ socket. */
+#endif
shell = getenv ("SHELL");
if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
@@ -779,7 +703,7 @@
}
if (!err)
{
- s = gnupg_ttyname (0);
+ s = ttyname (0);
if (s)
err = session_env_setenv (opt.startup_env, "GPG_TTY", s);
}
@@ -816,11 +740,6 @@
default_config = 0; /* --no-options */
else if (pargs.r_opt == oHomedir)
opt.homedir = pargs.r.ret_str;
- else if (pargs.r_opt == oDebugQuickRandom)
- {
- gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
- }
-
}
/* Initialize the secure memory. */
@@ -832,8 +751,7 @@
*/
if (default_config)
- configname = make_filename (opt.homedir, GPG_AGENT_NAME EXTSEP_S "conf",
- NULL );
+ configname = make_filename (opt.homedir, "gpg-agent.conf", NULL );
argc = orig_argc;
argv = orig_argv;
@@ -850,7 +768,7 @@
if (default_config)
{
if( parse_debug )
- log_info (_("Note: no default option file '%s'\n"),
+ log_info (_("NOTE: no default option file `%s'\n"),
configname );
/* Save the default conf file name so that
reread_configuration is able to test whether the
@@ -861,7 +779,7 @@
}
else
{
- log_error (_("option file '%s': %s\n"),
+ log_error (_("option file `%s': %s\n"),
configname, strerror(errno) );
exit(2);
}
@@ -869,7 +787,7 @@
configname = NULL;
}
if (parse_debug && configname )
- log_info (_("reading options from '%s'\n"), configname );
+ log_info (_("reading options from `%s'\n"), configname );
default_config = 0;
}
@@ -895,7 +813,7 @@
goto next_pass;
}
break;
- case oNoGreeting: /* Dummy option. */ break;
+ case oNoGreeting: nogreeting = 1; break;
case oNoVerbose: opt.verbose = 0; break;
case oNoOptions: break; /* no-options */
case oHomedir: opt.homedir = pargs.r.ret_str; break;
@@ -911,14 +829,11 @@
case oTTYtype: default_ttytype = xstrdup (pargs.r.ret_str); break;
case oLCctype: default_lc_ctype = xstrdup (pargs.r.ret_str); break;
case oLCmessages: default_lc_messages = xstrdup (pargs.r.ret_str);
- break;
case oXauthority: default_xauthority = xstrdup (pargs.r.ret_str);
break;
- case oUseStandardSocket:
- case oNoUseStandardSocket:
- obsolete_option (configname, configlineno, "use-standard-socket");
- break;
+ case oUseStandardSocket: opt.use_standard_socket = 1; break;
+ case oNoUseStandardSocket: opt.use_standard_socket = 0; break;
case oFakedSystemTime:
{
@@ -932,31 +847,19 @@
case oKeepTTY: opt.keep_tty = 1; break;
case oKeepDISPLAY: opt.keep_display = 1; break;
- case oSSHSupport:
- ssh_support = 1;
- break;
+ case oSSHSupport: opt.ssh_support = 1; break;
case oPuttySupport:
# ifdef HAVE_W32_SYSTEM
putty_support = 1;
+ opt.ssh_support = 1;
# endif
break;
- case oExtraSocket:
- opt.extra_socket = 1; /* (1 = points into argv) */
- socket_name_extra = pargs.r.ret_str;
- break;
-
- case oBrowserSocket:
- opt.browser_socket = 1; /* (1 = points into argv) */
- socket_name_browser = pargs.r.ret_str;
- break;
-
- case oDebugQuickRandom:
- /* Only used by the first stage command line parser. */
- break;
-
case oWriteEnvFile:
- obsolete_option (configname, configlineno, "write-env-file");
+ if (pargs.r_type)
+ env_file_name = pargs.r.ret_str;
+ else
+ env_file_name = make_filename ("~/.gpg-agent-info", NULL);
break;
default : pargs.err = configfp? 1:2; break;
@@ -980,45 +883,21 @@
configname = NULL;
if (log_get_errorcount(0))
exit(2);
+ if (nogreeting )
+ greeting = 0;
- finalize_rereadable_options ();
-
- /* Turn the homedir into an absolute one. */
- opt.homedir = make_absfilename (opt.homedir, NULL);
-
- /* Print a warning if an argument looks like an option. */
- if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
+ if (greeting)
{
- int i;
-
- for (i=0; i < argc; i++)
- if (argv[i][0] == '-' && argv[i][1] == '-')
- log_info (_("Note: '%s' is not considered an option\n"), argv[i]);
- }
-
-#ifdef ENABLE_NLS
- /* gpg-agent usually does not output any messages because it runs in
- the background. For log files it is acceptable to have messages
- always encoded in utf-8. We switch here to utf-8, so that
- commands like --help still give native messages. It is far
- easier to switch only once instead of for every message and it
- actually helps when more then one thread is active (avoids an
- extra copy step). */
- bind_textdomain_codeset (PACKAGE_GT, "UTF-8");
+ fprintf (stderr, "%s %s; %s\n",
+ strusage(11), strusage(13), strusage(14) );
+ fprintf (stderr, "%s\n", strusage(15) );
+ }
+#ifdef IS_DEVELOPMENT_VERSION
+ /* We don't want to print it here because gpg-agent is useful of its
+ own and quite matured. */
+ /*log_info ("NOTE: this is a development version!\n");*/
#endif
- if (!pipe_server && !is_daemon && !gpgconf_list)
- {
- /* We have been called without any options and thus we merely
- check whether an agent is already running. We do this right
- here so that we don't clobber a logfile with this check but
- print the status directly to stderr. */
- opt.debug = 0;
- set_debug ();
- check_for_running_agent (0);
- agent_exit (0);
- }
-
set_debug ();
if (atexit (cleanup))
@@ -1028,7 +907,6 @@
exit (1);
}
- initialize_module_cache ();
initialize_module_call_pinentry ();
initialize_module_call_scd ();
initialize_module_trustlist ();
@@ -1045,30 +923,24 @@
}
if (gpgconf_list == 3)
- {
- /* We now use the standard socket always - return true for
- backward compatibility. */
- agent_exit (0);
- }
- else if (gpgconf_list == 2)
+ agent_exit (!opt.use_standard_socket);
+ if (gpgconf_list == 2)
agent_exit (0);
- else if (gpgconf_list)
+ if (gpgconf_list)
{
char *filename;
char *filename_esc;
/* List options and default values in the GPG Conf format. */
- filename = make_filename (opt.homedir, GPG_AGENT_NAME EXTSEP_S "conf",
- NULL );
+ filename = make_filename (opt.homedir, "gpg-agent.conf", NULL );
filename_esc = percent_escape (filename, NULL);
- es_printf ("%s-%s.conf:%lu:\"%s\n",
- GPGCONF_NAME, GPG_AGENT_NAME,
- GC_OPT_FLAG_DEFAULT, filename_esc);
+ printf ("gpgconf-gpg-agent.conf:%lu:\"%s\n",
+ GC_OPT_FLAG_DEFAULT, filename_esc);
xfree (filename);
xfree (filename_esc);
- es_printf ("verbose:%lu:\n"
+ printf ("verbose:%lu:\n"
"quiet:%lu:\n"
"debug-level:%lu:\"none:\n"
"log-file:%lu:\n",
@@ -1076,63 +948,83 @@
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME,
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME,
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME );
- es_printf ("default-cache-ttl:%lu:%d:\n",
+ printf ("default-cache-ttl:%lu:%d:\n",
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, DEFAULT_CACHE_TTL );
- es_printf ("default-cache-ttl-ssh:%lu:%d:\n",
+ printf ("default-cache-ttl-ssh:%lu:%d:\n",
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, DEFAULT_CACHE_TTL_SSH );
- es_printf ("max-cache-ttl:%lu:%d:\n",
+ printf ("max-cache-ttl:%lu:%d:\n",
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, MAX_CACHE_TTL );
- es_printf ("max-cache-ttl-ssh:%lu:%d:\n",
+ printf ("max-cache-ttl-ssh:%lu:%d:\n",
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, MAX_CACHE_TTL_SSH );
- es_printf ("enforce-passphrase-constraints:%lu:\n",
+ printf ("enforce-passphrase-constraints:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
- es_printf ("min-passphrase-len:%lu:%d:\n",
+ printf ("min-passphrase-len:%lu:%d:\n",
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, MIN_PASSPHRASE_LEN );
- es_printf ("min-passphrase-nonalpha:%lu:%d:\n",
+ printf ("min-passphrase-nonalpha:%lu:%d:\n",
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME,
MIN_PASSPHRASE_NONALPHA);
- es_printf ("check-passphrase-pattern:%lu:\n",
+ printf ("check-passphrase-pattern:%lu:\n",
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME);
- es_printf ("max-passphrase-days:%lu:%d:\n",
+ printf ("max-passphrase-days:%lu:%d:\n",
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME,
MAX_PASSPHRASE_DAYS);
- es_printf ("enable-passphrase-history:%lu:\n",
+ printf ("enable-passphrase-history:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
- es_printf ("no-grab:%lu:\n",
+ printf ("no-grab:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
- es_printf ("ignore-cache-for-signing:%lu:\n",
+ printf ("ignore-cache-for-signing:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
- es_printf ("no-allow-external-cache:%lu:\n",
+ printf ("no-allow-mark-trusted:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
- es_printf ("no-allow-mark-trusted:%lu:\n",
+ printf ("no-allow-external-cache:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
- es_printf ("disable-scdaemon:%lu:\n",
+ printf ("disable-scdaemon:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
- es_printf ("enable-ssh-support:%lu:\n", GC_OPT_FLAG_NONE);
#ifdef HAVE_W32_SYSTEM
- es_printf ("enable-putty-support:%lu:\n", GC_OPT_FLAG_NONE);
+ printf ("enable-putty-support:%lu:\n", GC_OPT_FLAG_NONE);
+#else
+ printf ("enable-ssh-support:%lu:\n", GC_OPT_FLAG_NONE);
#endif
- es_printf ("allow-loopback-pinentry:%lu:\n",
- GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
- es_printf ("allow-emacs-pinentry:%lu:\n",
- GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
agent_exit (0);
}
+ /* If this has been called without any options, we merely check
+ whether an agent is already running. We do this here so that we
+ don't clobber a logfile but print it directly to stderr. */
+ if (!pipe_server && !is_daemon)
+ {
+ log_set_prefix (NULL, JNLIB_LOG_WITH_PREFIX);
+ check_for_running_agent (0, 0);
+ agent_exit (0);
+ }
+
+#ifdef ENABLE_NLS
+ /* gpg-agent usually does not output any messages because it runs in
+ the background. For log files it is acceptable to have messages
+ always encoded in utf-8. We switch here to utf-8, so that
+ commands like --help still give native messages. It is far
+ easier to switch only once instead of for every message and it
+ actually helps when more then one thread is active (avoids an
+ extra copy step). */
+ bind_textdomain_codeset (PACKAGE_GT, "UTF-8");
+#endif
+
/* Now start with logging to a file if this is desired. */
if (logfile)
{
log_set_file (logfile);
- log_set_prefix (NULL, (GPGRT_LOG_WITH_PREFIX
- | GPGRT_LOG_WITH_TIME
- | GPGRT_LOG_WITH_PID));
+ log_set_prefix (NULL, (JNLIB_LOG_WITH_PREFIX
+ |JNLIB_LOG_WITH_TIME
+ |JNLIB_LOG_WITH_PID));
current_logfile = xstrdup (logfile);
}
+ if (DBG_ASSUAN)
+ assuan_set_assuan_log_stream (log_get_stream ());
/* Make sure that we have a default ttyname. */
- if (!default_ttyname && gnupg_ttyname (1))
- default_ttyname = xstrdup (gnupg_ttyname (1));
+ if (!default_ttyname && ttyname (1))
+ default_ttyname = xstrdup (ttyname (1));
if (!default_ttytype && getenv ("TERM"))
default_ttytype = xstrdup (getenv ("TERM"));
@@ -1167,9 +1059,7 @@
else
{ /* Regular server mode */
gnupg_fd_t fd;
- gnupg_fd_t fd_extra = GNUPG_INVALID_FD;
- gnupg_fd_t fd_browser = GNUPG_INVALID_FD;
- gnupg_fd_t fd_ssh = GNUPG_INVALID_FD;
+ gnupg_fd_t fd_ssh;
pid_t pid;
/* Remove the DISPLAY variable so that a pinentry does not
@@ -1180,44 +1070,22 @@
exec the program given as arguments). */
#ifndef HAVE_W32_SYSTEM
if (!opt.keep_display && !argc)
- gnupg_unsetenv ("DISPLAY");
+ unsetenv ("DISPLAY");
#endif
- /* Remove the INSIDE_EMACS variable so that a pinentry does not
- always try to interact with Emacs. The variable is set when
- a client requested this using an OPTION command. */
- gnupg_unsetenv ("INSIDE_EMACS");
/* Create the sockets. */
- socket_name = create_socket_name (GPG_AGENT_SOCK_NAME, 1);
- fd = create_server_socket (socket_name, 1, 0,
- &redir_socket_name, &socket_nonce);
-
- if (opt.extra_socket)
- {
- socket_name_extra = create_socket_name (socket_name_extra, 0);
- opt.extra_socket = 2; /* Indicate that it has been malloced. */
- fd_extra = create_server_socket (socket_name_extra, 0, 0,
- &redir_socket_name_extra,
- &socket_nonce_extra);
- }
-
- if (opt.browser_socket)
- {
- socket_name_browser = create_socket_name (socket_name_browser, 0);
- opt.browser_socket = 2; /* Indicate that it has been malloced. */
- fd_browser = create_server_socket (socket_name_browser, 0, 0,
- &redir_socket_name_browser,
- &socket_nonce_browser);
- }
-
- if (ssh_support)
- {
- socket_name_ssh = create_socket_name (GPG_AGENT_SSH_SOCK_NAME, 1);
- fd_ssh = create_server_socket (socket_name_ssh, 0, 1,
- &redir_socket_name_ssh,
- &socket_nonce_ssh);
- }
+ socket_name = create_socket_name
+ ("S.gpg-agent", "/tmp/gpg-XXXXXX/S.gpg-agent");
+ if (opt.ssh_support)
+ socket_name_ssh = create_socket_name
+ ("S.gpg-agent.ssh", "/tmp/gpg-XXXXXX/S.gpg-agent.ssh");
+
+ fd = create_server_socket (socket_name, 0, &socket_nonce);
+ if (opt.ssh_support)
+ fd_ssh = create_server_socket (socket_name_ssh, 1, &socket_nonce_ssh);
+ else
+ fd_ssh = GNUPG_INVALID_FD;
/* If we are going to exec a program in the parent, we record
the PID, so that the child may check whether the program is
@@ -1227,9 +1095,8 @@
fflush (NULL);
#ifdef HAVE_W32_SYSTEM
- (void)csh_style;
- (void)nodetach;
pid = getpid ();
+ printf ("set GPG_AGENT_INFO=%s;%lu;1\n", socket_name, (ulong)pid);
#else /*!HAVE_W32_SYSTEM*/
pid = fork ();
if (pid == (pid_t)-1)
@@ -1239,14 +1106,25 @@
}
else if (pid)
{ /* We are the parent */
- char *infostr_ssh_sock, *infostr_ssh_valid;
+ char *infostr, *infostr_ssh_sock, *infostr_ssh_pid;
/* Close the socket FD. */
close (fd);
- /* The signal mask might not be correct right now and thus
- we restore it. That is not strictly necessary but some
- programs falsely assume a cleared signal mask. */
+ /* Note that we used a standard fork so that Pth runs in
+ both the parent and the child. The pth_fork would
+ terminate Pth in the child but that is not the way we
+ want it. Thus we use a plain fork and terminate Pth here
+ in the parent. The pth_kill may or may not work reliable
+ but it should not harm to call it. Because Pth fiddles
+ with the signal mask the signal mask might not be correct
+ right now and thus we restore it. That is not strictly
+ necessary but some programs falsely assume a cleared
+ signal mask. es_pth_kill is a wrapper around pth_kill to
+ take care not to use any Pth functions in the estream
+ code after Pth has been killed. */
+ if ( !es_pth_kill () )
+ log_error ("pth_kill failed in forked process\n");
#ifdef HAVE_SIGPROCMASK
if (startup_signal_mask_valid)
@@ -1259,8 +1137,15 @@
log_info ("no saved signal mask\n");
#endif /*HAVE_SIGPROCMASK*/
- /* Create the SSH info string if enabled. */
- if (ssh_support)
+ /* Create the info string: :: */
+ if (asprintf (&infostr, "GPG_AGENT_INFO=%s:%lu:1",
+ socket_name, (ulong)pid ) < 0)
+ {
+ log_error ("out of core\n");
+ kill (pid, SIGTERM);
+ exit (1);
+ }
+ if (opt.ssh_support)
{
if (asprintf (&infostr_ssh_sock, "SSH_AUTH_SOCK=%s",
socket_name_ssh) < 0)
@@ -1269,8 +1154,8 @@
kill (pid, SIGTERM);
exit (1);
}
- if (asprintf (&infostr_ssh_valid, "gnupg_SSH_AUTH_SOCK_by=%lu",
- (unsigned long)getpid()) < 0)
+ if (asprintf (&infostr_ssh_pid, "SSH_AGENT_PID=%u",
+ pid) < 0)
{
log_error ("out of core\n");
kill (pid, SIGTERM);
@@ -1280,17 +1165,50 @@
*socket_name = 0; /* Don't let cleanup() remove the socket -
the child should do this from now on */
- if (opt.extra_socket)
- *socket_name_extra = 0;
- if (opt.browser_socket)
- *socket_name_browser = 0;
- if (ssh_support)
+ if (opt.ssh_support)
*socket_name_ssh = 0;
+ if (env_file_name)
+ {
+ FILE *fp;
+
+ fp = fopen (env_file_name, "w");
+ if (!fp)
+ log_error (_("error creating `%s': %s\n"),
+ env_file_name, strerror (errno));
+ else
+ {
+ fputs (infostr, fp);
+ putc ('\n', fp);
+ if (opt.ssh_support)
+ {
+ fputs (infostr_ssh_sock, fp);
+ putc ('\n', fp);
+ fputs (infostr_ssh_pid, fp);
+ putc ('\n', fp);
+ }
+ fclose (fp);
+ }
+ }
+
+
if (argc)
{ /* Run the program given on the commandline. */
- if (ssh_support && (putenv (infostr_ssh_sock)
- || putenv (infostr_ssh_valid)))
+ if (putenv (infostr))
+ {
+ log_error ("failed to set environment: %s\n",
+ strerror (errno) );
+ kill (pid, SIGTERM );
+ exit (1);
+ }
+ if (opt.ssh_support && putenv (infostr_ssh_sock))
+ {
+ log_error ("failed to set environment: %s\n",
+ strerror (errno) );
+ kill (pid, SIGTERM );
+ exit (1);
+ }
+ if (opt.ssh_support && putenv (infostr_ssh_pid))
{
log_error ("failed to set environment: %s\n",
strerror (errno) );
@@ -1316,24 +1234,30 @@
shell's eval to set it */
if (csh_style)
{
- if (ssh_support)
+ *strchr (infostr, '=') = ' ';
+ printf ("setenv %s;\n", infostr);
+ if (opt.ssh_support)
{
*strchr (infostr_ssh_sock, '=') = ' ';
- es_printf ("setenv %s;\n", infostr_ssh_sock);
+ printf ("setenv %s;\n", infostr_ssh_sock);
+ *strchr (infostr_ssh_pid, '=') = ' ';
+ printf ("setenv %s;\n", infostr_ssh_pid);
}
}
else
{
- if (ssh_support)
+ printf ( "%s; export GPG_AGENT_INFO;\n", infostr);
+ if (opt.ssh_support)
{
- es_printf ("%s; export SSH_AUTH_SOCK;\n",
- infostr_ssh_sock);
+ printf ("%s; export SSH_AUTH_SOCK;\n", infostr_ssh_sock);
+ printf ("%s; export SSH_AGENT_PID;\n", infostr_ssh_pid);
}
}
- if (ssh_support)
+ xfree (infostr);
+ if (opt.ssh_support)
{
xfree (infostr_ssh_sock);
- xfree (infostr_ssh_valid);
+ xfree (infostr_ssh_pid);
}
exit (0);
}
@@ -1358,7 +1282,7 @@
if ( ! close (i)
&& open ("/dev/null", i? O_WRONLY : O_RDONLY) == -1)
{
- log_error ("failed to open '%s': %s\n",
+ log_error ("failed to open `%s': %s\n",
"/dev/null", strerror (errno));
cleanup ();
exit (1);
@@ -1373,7 +1297,7 @@
}
log_get_prefix (&oldflags);
- log_set_prefix (NULL, oldflags | GPGRT_LOG_RUN_DETACHED);
+ log_set_prefix (NULL, oldflags | JNLIB_LOG_RUN_DETACHED);
opt.running_detached = 1;
}
@@ -1394,7 +1318,7 @@
#endif /*!HAVE_W32_SYSTEM*/
log_info ("%s %s started\n", strusage(11), strusage(13) );
- handle_connections (fd, fd_extra, fd_browser, fd_ssh);
+ handle_connections (fd, opt.ssh_support ? fd_ssh : GNUPG_INVALID_FD);
assuan_sock_close (fd);
}
@@ -1402,18 +1326,10 @@
}
-/* Exit entry point. This function should be called instead of a
- plain exit. */
void
agent_exit (int rc)
{
/*FIXME: update_random_seed_file();*/
-
- /* We run our cleanup handler because that may close cipher contexts
- stored in secure memory and thus this needs to be done before we
- explicitly terminate secure memory. */
- cleanup ();
-
#if 1
/* at this time a bit annoying */
if (opt.debug & DBG_MEMSTAT_VALUE)
@@ -1430,11 +1346,6 @@
}
-/* Each thread has its own local variables conveyed by a control
- structure usually identified by an argument named CTRL. This
- function is called immediately after allocating the control
- structure. Its purpose is to setup the default values for that
- structure. Note that some values may have already been set. */
static void
agent_init_default_ctrl (ctrl_t ctrl)
{
@@ -1457,12 +1368,9 @@
xfree (ctrl->lc_messages);
ctrl->lc_messages = default_lc_messages? xtrystrdup (default_lc_messages)
/**/ : NULL;
- ctrl->cache_ttl_opt_preset = CACHE_TTL_OPT_PRESET;
}
-/* Release all resources allocated by default in the control
- structure. This is the counterpart to agent_init_default_ctrl. */
static void
agent_deinit_default_ctrl (ctrl_t ctrl)
{
@@ -1475,39 +1383,6 @@
}
-/* Because the ssh protocol does not send us information about the
- current TTY setting, we use this function to use those from startup
- or those explictly set. This is also used for the restricted mode
- where we ignore requests to change the environment. */
-gpg_error_t
-agent_copy_startup_env (ctrl_t ctrl)
-{
- static const char *names[] =
- {"GPG_TTY", "DISPLAY", "TERM", "XAUTHORITY", "PINENTRY_USER_DATA", NULL};
- gpg_error_t err = 0;
- int idx;
- const char *value;
-
- for (idx=0; !err && names[idx]; idx++)
- if ((value = session_env_getenv (opt.startup_env, names[idx])))
- err = session_env_setenv (ctrl->session_env, names[idx], value);
-
- if (!err && !ctrl->lc_ctype && opt.startup_lc_ctype)
- if (!(ctrl->lc_ctype = xtrystrdup (opt.startup_lc_ctype)))
- err = gpg_error_from_syserror ();
-
- if (!err && !ctrl->lc_messages && opt.startup_lc_messages)
- if (!(ctrl->lc_messages = xtrystrdup (opt.startup_lc_messages)))
- err = gpg_error_from_syserror ();
-
- if (err)
- log_error ("error setting default session environment: %s\n",
- gpg_strerror (err));
-
- return err;
-}
-
-
/* Reread parts of the configuration. Note, that this function is
obviously not thread-safe and should only be called from the PTH
signal handler.
@@ -1531,7 +1406,7 @@
fp = fopen (config_filename, "r");
if (!fp)
{
- log_info (_("option file '%s': %s\n"),
+ log_info (_("option file `%s': %s\n"),
config_filename, strerror(errno) );
return;
}
@@ -1550,7 +1425,6 @@
parse_rereadable_options (&pargs, 1);
}
fclose (fp);
- finalize_rereadable_options ();
set_debug ();
}
@@ -1579,18 +1453,18 @@
/* Under W32, this function returns the handle of the scdaemon
notification event. Calling it the first time creates that
event. */
-#if defined(HAVE_W32_SYSTEM) && !defined(HAVE_W32CE_SYSTEM)
+#ifdef HAVE_W32_SYSTEM
void *
get_agent_scd_notify_event (void)
{
- static HANDLE the_event = INVALID_HANDLE_VALUE;
+ static HANDLE the_event;
- if (the_event == INVALID_HANDLE_VALUE)
+ if (!the_event)
{
HANDLE h, h2;
SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
- /* We need to use a manual reset event object due to the way our
+ /* We need to use manual reset evet object due to the way our
w32-pth wait function works: If we would use an automatic
reset event we are not able to figure out which handle has
been signaled because at the time we single out the signaled
@@ -1614,30 +1488,52 @@
}
}
+ log_debug ("returning notify handle %p\n", the_event);
return the_event;
}
-#endif /*HAVE_W32_SYSTEM && !HAVE_W32CE_SYSTEM*/
+#endif /*HAVE_W32_SYSTEM*/
-/* Create a name for the socket in the home directory as using
- STANDARD_NAME. We also check for valid characters as well as
- against a maximum allowed length for a unix domain socket is done.
- The function terminates the process in case of an error. Returns:
- Pointer to an allocated string with the absolute name of the socket
- used. */
+/* Create a name for the socket. With USE_STANDARD_SOCKET given as
+ true using STANDARD_NAME in the home directory or if given as
+ false from the mkdir type name TEMPLATE. In the latter case a
+ unique name in a unique new directory will be created. In both
+ cases check for valid characters as well as against a maximum
+ allowed length for a unix domain socket is done. The function
+ terminates the process in case of an error. Returns: Pointer to an
+ allocated string with the absolute name of the socket used. */
static char *
-create_socket_name (char *standard_name, int with_homedir)
+create_socket_name (char *standard_name, char *template)
{
- char *name;
+ char *name, *p;
- if (with_homedir)
+ if (opt.use_standard_socket)
name = make_filename (opt.homedir, standard_name, NULL);
else
- name = make_filename (standard_name, NULL);
+ {
+ name = xstrdup (template);
+ p = strrchr (name, '/');
+ if (!p)
+ BUG ();
+ *p = 0;
+ if (!mkdtemp (name))
+ {
+ log_error (_("can't create directory `%s': %s\n"),
+ name, strerror (errno));
+ agent_exit (2);
+ }
+ *p = '/';
+ }
+
if (strchr (name, PATHSEP_C))
{
- log_error (("'%s' are not allowed in the socket name\n"), PATHSEP_S);
+ log_error (("`%s' are not allowed in the socket name\n"), PATHSEP_S);
+ agent_exit (2);
+ }
+ if (strlen (name) + 1 >= DIMof (struct sockaddr_un, sun_path) )
+ {
+ log_error (_("name of socket too long\n"));
agent_exit (2);
}
return name;
@@ -1646,133 +1542,82 @@
/* Create a Unix domain socket with NAME. Returns the file descriptor
- or terminates the process in case of an error. Note that this
- function needs to be used for the regular socket first (indicated
- by PRIMARY) and only then for the extra and the ssh sockets. If
- the socket has been redirected the name of the real socket is
- stored as a malloced string at R_REDIR_NAME. If CYGWIN is set a
- Cygwin compatible socket is created (Windows only). */
+ or terminates the process in case of an error. Not that this
+ function needs to be used for the regular socket first and only
+ then for the ssh socket. */
static gnupg_fd_t
-create_server_socket (char *name, int primary, int cygwin,
- char **r_redir_name, assuan_sock_nonce_t *nonce)
+create_server_socket (char *name, int is_ssh, assuan_sock_nonce_t *nonce)
{
- struct sockaddr *addr;
- struct sockaddr_un *unaddr;
+ struct sockaddr_un *serv_addr;
socklen_t len;
gnupg_fd_t fd;
int rc;
- xfree (*r_redir_name);
- *r_redir_name = NULL;
-
fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0);
if (fd == ASSUAN_INVALID_FD)
{
log_error (_("can't create socket: %s\n"), strerror (errno));
- *name = 0; /* Inhibit removal of the socket by cleanup(). */
agent_exit (2);
}
-#if ASSUAN_VERSION_NUMBER >= 0x020300 /* >= 2.3.0 */
- if (cygwin)
- assuan_sock_set_flag (fd, "cygwin", 1);
-#else
- (void)cygwin;
-#endif
-
- unaddr = xmalloc (sizeof *unaddr);
- addr = (struct sockaddr*)unaddr;
-
-#if ASSUAN_VERSION_NUMBER >= 0x020104 /* >= 2.1.4 */
- {
- int redirected;
-
- if (assuan_sock_set_sockaddr_un (name, addr, &redirected))
- {
- if (errno == ENAMETOOLONG)
- log_error (_("socket name '%s' is too long\n"), name);
- else
- log_error ("error preparing socket '%s': %s\n",
- name, gpg_strerror (gpg_error_from_syserror ()));
- *name = 0; /* Inhibit removal of the socket by cleanup(). */
- agent_exit (2);
- }
- if (redirected)
- {
- *r_redir_name = xstrdup (unaddr->sun_path);
- if (opt.verbose)
- log_info ("redirecting socket '%s' to '%s'\n", name, *r_redir_name);
- }
- }
-#else /* Assuan < 2.1.4 */
- memset (unaddr, 0, sizeof *unaddr);
- unaddr->sun_family = AF_UNIX;
- if (strlen (name) + 1 >= sizeof (unaddr->sun_path))
+ serv_addr = xmalloc (sizeof (*serv_addr));
+ memset (serv_addr, 0, sizeof *serv_addr);
+ serv_addr->sun_family = AF_UNIX;
+ if (strlen (name) + 1 >= sizeof (serv_addr->sun_path))
{
- log_error (_("socket name '%s' is too long\n"), name);
- *name = 0; /* Inhibit removal of the socket by cleanup(). */
+ log_error (_("socket name `%s' is too long\n"), name);
agent_exit (2);
}
- strcpy (unaddr->sun_path, name);
-#endif /* Assuan < 2.1.4 */
-
- len = SUN_LEN (unaddr);
- rc = assuan_sock_bind (fd, addr, len);
-
- /* Our error code mapping on W32CE returns EEXIST thus we also test
- for this. */
- if (rc == -1
- && (errno == EADDRINUSE
-#ifdef HAVE_W32_SYSTEM
- || errno == EEXIST
-#endif
- ))
- {
- /* Check whether a gpg-agent is already running. We do this
- test only if this is the primary socket. For secondary
- sockets we assume that a test for gpg-agent has already been
- done and reuse the requested socket. Testing the ssh-socket
- is not possible because at this point, though we know the new
- Assuan socket, the Assuan server and thus the ssh-agent
- server is not yet operational; this would lead to a hang. */
- if (primary && !check_for_running_agent (1))
+ strcpy (serv_addr->sun_path, name);
+ len = SUN_LEN (serv_addr);
+ rc = assuan_sock_bind (fd, (struct sockaddr*) serv_addr, len);
+ if (opt.use_standard_socket && rc == -1 && errno == EADDRINUSE)
+ {
+ /* Check whether a gpg-agent is already running on the standard
+ socket. We do this test only if this is not the ssh socket.
+ For ssh we assume that a test for gpg-agent has already been
+ done and reuse the requested ssh socket. Testing the
+ ssh-socket is not possible because at this point, though we
+ know the new Assuan socket, the Assuan server and thus the
+ ssh-agent server is not yet operational. This would lead to
+ a hang. */
+ if (!is_ssh && !check_for_running_agent (1, 1))
{
- log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX);
- log_set_file (NULL);
log_error (_("a gpg-agent is already running - "
"not starting a new one\n"));
*name = 0; /* Inhibit removal of the socket by cleanup(). */
assuan_sock_close (fd);
agent_exit (2);
}
- gnupg_remove (unaddr->sun_path);
- rc = assuan_sock_bind (fd, addr, len);
+ remove (name);
+ rc = assuan_sock_bind (fd, (struct sockaddr*) serv_addr, len);
}
- if (rc != -1 && (rc=assuan_sock_get_nonce (addr, len, nonce)))
+ if (rc != -1
+ && (rc=assuan_sock_get_nonce ((struct sockaddr*)serv_addr, len, nonce)))
log_error (_("error getting nonce for the socket\n"));
if (rc == -1)
{
/* We use gpg_strerror here because it allows us to get strings
for some W32 socket error codes. */
- log_error (_("error binding socket to '%s': %s\n"),
- unaddr->sun_path,
- gpg_strerror (gpg_error_from_syserror ()));
+ log_error (_("error binding socket to `%s': %s\n"),
+ serv_addr->sun_path,
+ gpg_strerror (gpg_error_from_errno (errno)));
assuan_sock_close (fd);
- *name = 0; /* Inhibit removal of the socket by cleanup(). */
+ if (opt.use_standard_socket)
+ *name = 0; /* Inhibit removal of the socket by cleanup(). */
agent_exit (2);
}
if (listen (FD2INT(fd), 5 ) == -1)
{
log_error (_("listen() failed: %s\n"), strerror (errno));
- *name = 0; /* Inhibit removal of the socket by cleanup(). */
assuan_sock_close (fd);
agent_exit (2);
}
if (opt.verbose)
- log_info (_("listening on socket '%s'\n"), unaddr->sun_path);
+ log_info (_("listening on socket `%s'\n"), serv_addr->sun_path);
return fd;
}
@@ -1790,11 +1635,17 @@
fname = make_filename (home, GNUPG_PRIVATE_KEYS_DIR, NULL);
if (stat (fname, &statbuf) && errno == ENOENT)
{
- if (gnupg_mkdir (fname, "-rwx"))
- log_error (_("can't create directory '%s': %s\n"),
+#ifdef HAVE_W32_SYSTEM /*FIXME: Setup proper permissions. */
+ if (!CreateDirectory (fname, NULL))
+ log_error (_("can't create directory `%s': %s\n"),
+ fname, w32_strerror (-1) );
+#else
+ if (mkdir (fname, S_IRUSR|S_IWUSR|S_IXUSR ))
+ log_error (_("can't create directory `%s': %s\n"),
fname, strerror (errno) );
+#endif
else if (!opt.quiet)
- log_info (_("directory '%s' created\n"), fname);
+ log_info (_("directory `%s' created\n"), fname);
}
xfree (fname);
}
@@ -1829,23 +1680,29 @@
#endif
)
{
- if (gnupg_mkdir (home, "-rwx"))
- log_error (_("can't create directory '%s': %s\n"),
+#ifdef HAVE_W32_SYSTEM
+ if (!CreateDirectory (home, NULL))
+ log_error (_("can't create directory `%s': %s\n"),
+ home, w32_strerror (-1) );
+#else
+ if (mkdir (home, S_IRUSR|S_IWUSR|S_IXUSR ))
+ log_error (_("can't create directory `%s': %s\n"),
home, strerror (errno) );
+#endif
else
{
if (!opt.quiet)
- log_info (_("directory '%s' created\n"), home);
+ log_info (_("directory `%s' created\n"), home);
create_private_keys_directory (home);
}
}
}
else
- log_error (_("stat() failed for '%s': %s\n"), home, strerror (errno));
+ log_error (_("stat() failed for `%s': %s\n"), home, strerror (errno));
}
else if ( !S_ISDIR(statbuf.st_mode))
{
- log_error (_("can't use '%s' as home directory\n"), home);
+ log_error (_("can't use `%s' as home directory\n"), home);
}
else /* exists and is a directory. */
{
@@ -1877,22 +1734,23 @@
if (kill (parent_pid, 0))
{
shutdown_pending = 2;
- log_info ("parent process died - shutting down\n");
- log_info ("%s %s stopped\n", strusage(11), strusage(13) );
+ if (!opt.quiet)
+ {
+ log_info ("parent process died - shutting down\n");
+ log_info ("%s %s stopped\n", strusage(11), strusage(13) );
+ }
cleanup ();
agent_exit (0);
}
}
#endif /*HAVE_W32_SYSTEM*/
- /* Code to be run from time to time. */
-#if CHECK_OWN_SOCKET_INTERVAL > 0
- if (last_minute + CHECK_OWN_SOCKET_INTERVAL <= time (NULL))
+ /* Code to be run every minute. */
+ if (last_minute + 60 <= time (NULL))
{
check_own_socket ();
last_minute = time (NULL);
}
-#endif
}
@@ -1904,18 +1762,12 @@
{
log_info ("SIGHUP received - "
"re-reading configuration and flushing cache\n");
-
agent_flush_cache ();
reread_configuration ();
agent_reload_trustlist ();
- /* We flush the module name cache so that after installing a
- "pinentry" binary that one can be used in case the
- "pinentry-basic" fallback was in use. */
- gnupg_module_name_flush_some ();
}
-/* A helper function to handle SIGUSR2. */
static void
agent_sigusr2_action (void)
{
@@ -1926,9 +1778,6 @@
}
-#ifndef HAVE_W32_SYSTEM
-/* The signal handler for this program. It is expected to be run in
- its own trhead and not in the context of a signal handler. */
static void
handle_signal (int signo)
{
@@ -1941,9 +1790,7 @@
case SIGUSR1:
log_info ("SIGUSR1 received - printing internal information:\n");
- /* Fixme: We need to see how to integrate pth dumping into our
- logging system. */
- /* pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ()); */
+ pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ());
agent_query_dump_state ();
agent_scd_dump_state ();
break;
@@ -1956,8 +1803,8 @@
if (!shutdown_pending)
log_info ("SIGTERM received - shutting down ...\n");
else
- log_info ("SIGTERM received - still %i open connections\n",
- active_connections);
+ log_info ("SIGTERM received - still %ld running threads\n",
+ pth_ctrl( PTH_CTRL_GETTHREADS ));
shutdown_pending++;
if (shutdown_pending > 2)
{
@@ -1979,7 +1826,7 @@
log_info ("signal %d received - no action defined\n", signo);
}
}
-#endif
+
/* Check the nonce on a new connection. This is a NOP unless we we
are using our Unix domain socket emulation under Windows. */
@@ -2019,6 +1866,9 @@
if (msg != WM_COPYDATA)
{
+ /* pth_leave (); */
+ /* log_debug ("putty loop: received WM_%u\n", msg ); */
+ /* pth_enter (); */
return DefWindowProc (hwnd, msg, wparam, lparam);
}
@@ -2029,25 +1879,25 @@
if (!cds->cbData || mapfile[cds->cbData - 1])
return 0; /* Ignore empty and non-properly terminated strings. */
- if (DBG_IPC)
+ if (DBG_ASSUAN)
{
- npth_protect ();
+ pth_leave ();
log_debug ("ssh map file '%s'", mapfile);
- npth_unprotect ();
+ pth_enter ();
}
maphd = OpenFileMapping (FILE_MAP_ALL_ACCESS, FALSE, mapfile);
- if (DBG_IPC)
+ if (DBG_ASSUAN)
{
- npth_protect ();
+ pth_leave ();
log_debug ("ssh map handle %p\n", maphd);
- npth_unprotect ();
+ pth_enter ();
}
if (!maphd || maphd == INVALID_HANDLE_VALUE)
return 0;
- npth_protect ();
+ pth_leave ();
mysid = w32_get_user_sid ();
if (!mysid)
@@ -2066,7 +1916,7 @@
goto leave;
}
- if (DBG_IPC)
+ if (DBG_ASSUAN)
{
char *sidstr;
@@ -2087,7 +1937,7 @@
}
data = MapViewOfFile (maphd, FILE_MAP_ALL_ACCESS, 0, 0, 0);
- if (DBG_IPC)
+ if (DBG_ASSUAN)
log_debug ("ssh IPC buffer at %p\n", data);
if (!data)
goto leave;
@@ -2125,7 +1975,7 @@
xfree (mysid);
CloseHandle (maphd);
- npth_unprotect ();
+ pth_enter ();
return ret;
}
@@ -2145,18 +1995,18 @@
(void)arg;
if (opt.verbose)
- log_info ("putty message loop thread started\n");
+ log_info ("putty message loop thread 0x%lx started\n", pth_thread_id ());
- /* The message loop runs as thread independent from our nPth system.
- This also means that we need to make sure that we switch back to
+ /* The message loop runs as thread independet from out Pth system.
+ This also meand that we need to make sure that we switch back to
our system before calling any no-windows function. */
- npth_unprotect ();
+ pth_enter ();
/* First create a window to make sure that a message queue exists
for this thread. */
if (!RegisterClass (&wndwclass))
{
- npth_protect ();
+ pth_leave ();
log_error ("error registering Pageant window class");
return NULL;
}
@@ -2168,7 +2018,7 @@
NULL); /* lpParm */
if (!hwnd)
{
- npth_protect ();
+ pth_leave ();
log_error ("error creating Pageant window");
return NULL;
}
@@ -2179,28 +2029,34 @@
DispatchMessage(&msg);
}
- /* Back to nPth. */
- npth_protect ();
+ /* Back to Pth. */
+ pth_leave ();
if (opt.verbose)
- log_info ("putty message loop thread stopped\n");
+ log_info ("putty message loop thread 0x%lx stopped\n", pth_thread_id ());
return NULL;
}
#endif /*HAVE_W32_SYSTEM*/
+/* This is the standard connection thread's main function. */
static void *
-do_start_connection_thread (ctrl_t ctrl)
+start_connection_thread (void *arg)
{
+ ctrl_t ctrl = arg;
+
+ if (check_nonce (ctrl, &socket_nonce))
+ return NULL;
+
agent_init_default_ctrl (ctrl);
if (opt.verbose)
log_info (_("handler 0x%lx for fd %d started\n"),
- (unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
+ pth_thread_id (), FD2INT(ctrl->thread_startup.fd));
start_command_handler (ctrl, GNUPG_INVALID_FD, ctrl->thread_startup.fd);
if (opt.verbose)
log_info (_("handler 0x%lx for fd %d terminated\n"),
- (unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
+ pth_thread_id (), FD2INT(ctrl->thread_startup.fd));
agent_deinit_default_ctrl (ctrl);
xfree (ctrl);
@@ -2208,59 +2064,6 @@
}
-/* This is the standard connection thread's main function. */
-static void *
-start_connection_thread_std (void *arg)
-{
- ctrl_t ctrl = arg;
-
- if (check_nonce (ctrl, &socket_nonce))
- {
- log_error ("handler 0x%lx nonce check FAILED\n",
- (unsigned long) npth_self());
- return NULL;
- }
-
- return do_start_connection_thread (ctrl);
-}
-
-
-/* This is the extra socket connection thread's main function. */
-static void *
-start_connection_thread_extra (void *arg)
-{
- ctrl_t ctrl = arg;
-
- if (check_nonce (ctrl, &socket_nonce_extra))
- {
- log_error ("handler 0x%lx nonce check FAILED\n",
- (unsigned long) npth_self());
- return NULL;
- }
-
- ctrl->restricted = 1;
- return do_start_connection_thread (ctrl);
-}
-
-
-/* This is the browser socket connection thread's main function. */
-static void *
-start_connection_thread_browser (void *arg)
-{
- ctrl_t ctrl = arg;
-
- if (check_nonce (ctrl, &socket_nonce_browser))
- {
- log_error ("handler 0x%lx nonce check FAILED\n",
- (unsigned long) npth_self());
- return NULL;
- }
-
- ctrl->restricted = 2;
- return do_start_connection_thread (ctrl);
-}
-
-
/* This is the ssh connection thread's main function. */
static void *
start_connection_thread_ssh (void *arg)
@@ -2273,12 +2076,12 @@
agent_init_default_ctrl (ctrl);
if (opt.verbose)
log_info (_("ssh handler 0x%lx for fd %d started\n"),
- (unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
+ pth_thread_id (), FD2INT(ctrl->thread_startup.fd));
start_command_handler_ssh (ctrl, ctrl->thread_startup.fd);
if (opt.verbose)
log_info (_("ssh handler 0x%lx for fd %d terminated\n"),
- (unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
+ pth_thread_id (), FD2INT(ctrl->thread_startup.fd));
agent_deinit_default_ctrl (ctrl);
xfree (ctrl);
@@ -2289,62 +2092,61 @@
/* Connection handler loop. Wait for connection requests and spawn a
thread after accepting a connection. */
static void
-handle_connections (gnupg_fd_t listen_fd,
- gnupg_fd_t listen_fd_extra,
- gnupg_fd_t listen_fd_browser,
- gnupg_fd_t listen_fd_ssh)
+handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
{
- npth_attr_t tattr;
+ pth_attr_t tattr;
+ pth_event_t ev, time_ev;
+ sigset_t sigs;
+ int signo;
struct sockaddr_un paddr;
socklen_t plen;
fd_set fdset, read_fdset;
int ret;
gnupg_fd_t fd;
int nfd;
- int saved_errno;
- struct timespec abstime;
- struct timespec curtime;
- struct timespec timeout;
-#ifdef HAVE_W32_SYSTEM
- HANDLE events[2];
- unsigned int events_set;
-#endif
- struct {
- const char *name;
- void *(*func) (void *arg);
- gnupg_fd_t l_fd;
- } listentbl[] = {
- { "std", start_connection_thread_std },
- { "extra", start_connection_thread_extra },
- { "browser", start_connection_thread_browser },
- { "ssh", start_connection_thread_ssh }
- };
-
-
- ret = npth_attr_init(&tattr);
- if (ret)
- log_fatal ("error allocating thread attributes: %s\n",
- strerror (ret));
- npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
-#ifndef HAVE_W32_SYSTEM
- npth_sigev_init ();
- npth_sigev_add (SIGHUP);
- npth_sigev_add (SIGUSR1);
- npth_sigev_add (SIGUSR2);
- npth_sigev_add (SIGINT);
- npth_sigev_add (SIGTERM);
- npth_sigev_fini ();
+ tattr = pth_attr_new();
+ pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
+ pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
+
+#ifndef HAVE_W32_SYSTEM /* fixme */
+ /* Make sure that the signals we are going to handle are not blocked
+ and create an event object for them. We also set the default
+ action to ignore because we use an Pth event to get notified
+ about signals. This avoids that the default action is taken in
+ case soemthing goes wrong within Pth. The problem might also be
+ a Pth bug. */
+ sigemptyset (&sigs );
+ {
+ static const int mysigs[] = { SIGHUP, SIGUSR1, SIGUSR2, SIGINT, SIGTERM };
+ struct sigaction sa;
+ int i;
+
+ for (i=0; i < DIM (mysigs); i++)
+ {
+ sigemptyset (&sa.sa_mask);
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = 0;
+ sigaction (mysigs[i], &sa, NULL);
+
+ sigaddset (&sigs, mysigs[i]);
+ }
+ }
+
+ pth_sigmask (SIG_UNBLOCK, &sigs, NULL);
+ ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
#else
-# ifdef HAVE_W32CE_SYSTEM
+# ifdef PTH_EVENT_HANDLE
+ sigs = 0;
+ ev = pth_event (PTH_EVENT_HANDLE, get_agent_scd_notify_event ());
+ signo = 0;
+# else
/* Use a dummy event. */
sigs = 0;
ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
-# else
- events[0] = get_agent_scd_notify_event ();
- events[1] = INVALID_HANDLE_VALUE;
# endif
#endif
+ time_ev = NULL;
/* On Windows we need to fire up a separate thread to listen for
requests from Putty (an SSH client), so we can replace Putty's
@@ -2352,12 +2154,11 @@
#ifdef HAVE_W32_SYSTEM
if (putty_support)
{
- npth_t thread;
-
- ret = npth_create (&thread, &tattr, putty_message_thread, NULL);
- if (ret)
+ pth_attr_set (tattr, PTH_ATTR_NAME, "putty message loop");
+ if (!pth_spawn (tattr, putty_message_thread, NULL))
{
- log_error ("error spawning putty message loop: %s\n", strerror (ret));
+ log_error ("error spawning putty message loop: %s\n",
+ strerror (errno) );
}
}
#endif /*HAVE_W32_SYSTEM*/
@@ -2369,18 +2170,6 @@
FD_ZERO (&fdset);
FD_SET (FD2INT (listen_fd), &fdset);
nfd = FD2INT (listen_fd);
- if (listen_fd_extra != GNUPG_INVALID_FD)
- {
- FD_SET ( FD2INT(listen_fd_extra), &fdset);
- if (FD2INT (listen_fd_extra) > nfd)
- nfd = FD2INT (listen_fd_extra);
- }
- if (listen_fd_browser != GNUPG_INVALID_FD)
- {
- FD_SET ( FD2INT(listen_fd_browser), &fdset);
- if (FD2INT (listen_fd_browser) > nfd)
- nfd = FD2INT (listen_fd_browser);
- }
if (listen_fd_ssh != GNUPG_INVALID_FD)
{
FD_SET ( FD2INT(listen_fd_ssh), &fdset);
@@ -2388,20 +2177,15 @@
nfd = FD2INT (listen_fd_ssh);
}
- listentbl[0].l_fd = listen_fd;
- listentbl[1].l_fd = listen_fd_extra;
- listentbl[2].l_fd = listen_fd_browser;
- listentbl[3].l_fd = listen_fd_ssh;
-
- npth_clock_gettime (&abstime);
- abstime.tv_sec += TIMERTICK_INTERVAL;
-
for (;;)
{
+ /* Make sure that our signals are not blocked. */
+ pth_sigmask (SIG_UNBLOCK, &sigs, NULL);
+
/* Shutdown test. */
if (shutdown_pending)
{
- if (active_connections == 0)
+ if (pth_ctrl (PTH_CTRL_GETTHREADS) == 1)
break; /* ready */
/* Do not accept new connections but keep on running the
@@ -2409,107 +2193,176 @@
FD_ZERO (&fdset);
}
+ /* Create a timeout event if needed. To help with power saving
+ we syncronize the ticks to the next full second. */
+ if (!time_ev)
+ {
+ pth_time_t nexttick;
+
+ nexttick = pth_timeout (TIMERTICK_INTERVAL, 0);
+ if (nexttick.tv_usec > 10) /* Use a 10 usec threshhold. */
+ {
+ nexttick.tv_sec++;
+ nexttick.tv_usec = 0;
+ }
+ time_ev = pth_event (PTH_EVENT_TIME, nexttick);
+ }
+
/* POSIX says that fd_set should be implemented as a structure,
thus a simple assignment is fine to copy the entire set. */
read_fdset = fdset;
- npth_clock_gettime (&curtime);
- if (!(npth_timercmp (&curtime, &abstime, <)))
- {
- /* Timeout. */
- handle_tick ();
- npth_clock_gettime (&abstime);
- abstime.tv_sec += TIMERTICK_INTERVAL;
- }
- npth_timersub (&abstime, &curtime, &timeout);
-
-#ifndef HAVE_W32_SYSTEM
- ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
- npth_sigev_sigmask ());
- saved_errno = errno;
+ if (time_ev)
+ pth_event_concat (ev, time_ev, NULL);
+ ret = pth_select_ev (nfd+1, &read_fdset, NULL, NULL, NULL, ev);
+ if (time_ev)
+ pth_event_isolate (time_ev);
- {
- int signo;
- while (npth_sigev_get_pending (&signo))
- handle_signal (signo);
- }
+ if (ret == -1)
+ {
+ if (pth_event_occurred (ev)
+ || (time_ev && pth_event_occurred (time_ev)))
+ {
+ if (pth_event_occurred (ev))
+ {
+#if defined(HAVE_W32_SYSTEM) && defined(PTH_EVENT_HANDLE)
+ agent_sigusr2_action ();
#else
- ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
- events, &events_set);
- saved_errno = errno;
-
- /* This is valid even if npth_eselect returns an error. */
- if (events_set & 1)
- agent_sigusr2_action ();
+ handle_signal (signo);
#endif
-
- if (ret == -1 && saved_errno != EINTR)
- {
- log_error (_("npth_pselect failed: %s - waiting 1s\n"),
- strerror (saved_errno));
- npth_sleep (1);
+ }
+ if (time_ev && pth_event_occurred (time_ev))
+ {
+ pth_event_free (time_ev, PTH_FREE_ALL);
+ time_ev = NULL;
+ handle_tick ();
+ }
+ continue;
+ }
+ log_error (_("pth_select failed: %s - waiting 1s\n"),
+ strerror (errno));
+ pth_sleep (1);
continue;
}
- if (ret <= 0)
- /* Interrupt or timeout. Will be handled when calculating the
- next timeout. */
- continue;
- if (!shutdown_pending)
+ if (pth_event_occurred (ev))
+ {
+#if defined(HAVE_W32_SYSTEM) && defined(PTH_EVENT_HANDLE)
+ agent_sigusr2_action ();
+#else
+ handle_signal (signo);
+#endif
+ }
+
+ if (time_ev && pth_event_occurred (time_ev))
{
- int idx;
+ pth_event_free (time_ev, PTH_FREE_ALL);
+ time_ev = NULL;
+ handle_tick ();
+ }
+
+
+ /* We now might create new threads and because we don't want any
+ signals (as we are handling them here) to be delivered to a
+ new thread. Thus we need to block those signals. */
+ pth_sigmask (SIG_BLOCK, &sigs, NULL);
+
+ if (!shutdown_pending && FD_ISSET (FD2INT (listen_fd), &read_fdset))
+ {
ctrl_t ctrl;
- npth_t thread;
- for (idx=0; idx < DIM(listentbl); idx++)
+ plen = sizeof paddr;
+ fd = INT2FD (pth_accept (FD2INT(listen_fd),
+ (struct sockaddr *)&paddr, &plen));
+ if (fd == GNUPG_INVALID_FD)
+ {
+ log_error ("accept failed: %s\n", strerror (errno));
+ }
+ else if ( !(ctrl = xtrycalloc (1, sizeof *ctrl)) )
{
- if (listentbl[idx].l_fd == GNUPG_INVALID_FD)
- continue;
- if (!FD_ISSET (FD2INT (listentbl[idx].l_fd), &read_fdset))
- continue;
-
- plen = sizeof paddr;
- fd = INT2FD (npth_accept (FD2INT(listentbl[idx].l_fd),
- (struct sockaddr *)&paddr, &plen));
- if (fd == GNUPG_INVALID_FD)
- {
- log_error ("accept failed for %s: %s\n",
- listentbl[idx].name, strerror (errno));
- }
- else if ( !(ctrl = xtrycalloc (1, sizeof *ctrl)))
+ log_error ("error allocating connection control data: %s\n",
+ strerror (errno) );
+ assuan_sock_close (fd);
+ }
+ else if ( !(ctrl->session_env = session_env_new ()) )
+ {
+ log_error ("error allocating session environment block: %s\n",
+ strerror (errno) );
+ xfree (ctrl);
+ assuan_sock_close (fd);
+ }
+ else
+ {
+ char threadname[50];
+
+ snprintf (threadname, sizeof threadname-1,
+ "conn fd=%d (gpg)", FD2INT(fd));
+ threadname[sizeof threadname -1] = 0;
+ pth_attr_set (tattr, PTH_ATTR_NAME, threadname);
+ ctrl->thread_startup.fd = fd;
+ if (!pth_spawn (tattr, start_connection_thread, ctrl))
{
- log_error ("error allocating connection data for %s: %s\n",
- listentbl[idx].name, strerror (errno) );
+ log_error ("error spawning connection handler: %s\n",
+ strerror (errno) );
assuan_sock_close (fd);
- }
- else if ( !(ctrl->session_env = session_env_new ()))
- {
- log_error ("error allocating session env block for %s: %s\n",
- listentbl[idx].name, strerror (errno) );
xfree (ctrl);
- assuan_sock_close (fd);
}
- else
+ }
+ fd = GNUPG_INVALID_FD;
+ }
+
+ if (!shutdown_pending && listen_fd_ssh != GNUPG_INVALID_FD
+ && FD_ISSET ( FD2INT (listen_fd_ssh), &read_fdset))
+ {
+ ctrl_t ctrl;
+
+ plen = sizeof paddr;
+ fd = INT2FD(pth_accept (FD2INT(listen_fd_ssh),
+ (struct sockaddr *)&paddr, &plen));
+ if (fd == GNUPG_INVALID_FD)
+ {
+ log_error ("accept failed for ssh: %s\n", strerror (errno));
+ }
+ else if ( !(ctrl = xtrycalloc (1, sizeof *ctrl)) )
+ {
+ log_error ("error allocating connection control data: %s\n",
+ strerror (errno) );
+ assuan_sock_close (fd);
+ }
+ else if ( !(ctrl->session_env = session_env_new ()) )
+ {
+ log_error ("error allocating session environment block: %s\n",
+ strerror (errno) );
+ xfree (ctrl);
+ assuan_sock_close (fd);
+ }
+ else
+ {
+ char threadname[50];
+
+ agent_init_default_ctrl (ctrl);
+ snprintf (threadname, sizeof threadname-1,
+ "conn fd=%d (ssh)", FD2INT(fd));
+ threadname[sizeof threadname -1] = 0;
+ pth_attr_set (tattr, PTH_ATTR_NAME, threadname);
+ ctrl->thread_startup.fd = fd;
+ if (!pth_spawn (tattr, start_connection_thread_ssh, ctrl) )
{
- ctrl->thread_startup.fd = fd;
- ret = npth_create (&thread, &tattr,
- listentbl[idx].func, ctrl);
- if (ret)
- {
- log_error ("error spawning connection handler for %s:"
- " %s\n", listentbl[idx].name, strerror (ret));
- assuan_sock_close (fd);
- xfree (ctrl);
- }
+ log_error ("error spawning ssh connection handler: %s\n",
+ strerror (errno) );
+ assuan_sock_close (fd);
+ xfree (ctrl);
}
- fd = GNUPG_INVALID_FD;
}
- }
+ fd = GNUPG_INVALID_FD;
+ }
}
+ pth_event_free (ev, PTH_FREE_ALL);
+ if (time_ev)
+ pth_event_free (time_ev, PTH_FREE_ALL);
cleanup ();
log_info (_("%s %s stopped\n"), strusage(11), strusage(13));
- npth_attr_destroy (&tattr);
}
@@ -2595,58 +2448,104 @@
/* Check whether we are still listening on our own socket. In case
another gpg-agent process started after us has taken ownership of
- our socket, we would linger around without any real task. Thus we
+ our socket, we woul linger around without any real taks. Thus we
better check once in a while whether we are really needed. */
static void
check_own_socket (void)
{
char *sockname;
- npth_t thread;
- npth_attr_t tattr;
- int err;
+ pth_attr_t tattr;
- if (disable_check_own_socket)
- return;
+ if (!opt.use_standard_socket)
+ return; /* This check makes only sense in standard socket mode. */
if (check_own_socket_running || shutdown_pending)
return; /* Still running or already shutting down. */
- sockname = make_filename (opt.homedir, GPG_AGENT_SOCK_NAME, NULL);
+ sockname = make_filename (opt.homedir, "S.gpg-agent", NULL);
if (!sockname)
return; /* Out of memory. */
- err = npth_attr_init (&tattr);
- if (err)
- return;
- npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
- err = npth_create (&thread, &tattr, check_own_socket_thread, sockname);
- if (err)
- log_error ("error spawning check_own_socket_thread: %s\n", strerror (err));
- npth_attr_destroy (&tattr);
+ tattr = pth_attr_new();
+ pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
+ pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
+ pth_attr_set (tattr, PTH_ATTR_NAME, "check-own-socket");
+
+ if (!pth_spawn (tattr, check_own_socket_thread, sockname))
+ log_error ("error spawning check_own_socket_thread: %s\n",
+ strerror (errno) );
+ pth_attr_destroy (tattr);
}
/* Figure out whether an agent is available and running. Prints an
- error if not. If SILENT is true, no messages are printed.
- Returns 0 if the agent is running. */
+ error if not. If SILENT is true, no messages are printed. Usually
+ started with MODE 0. Returns 0 if the agent is running. */
static int
-check_for_running_agent (int silent)
+check_for_running_agent (int silent, int mode)
{
- gpg_error_t err;
- char *sockname;
+ int rc;
+ char *infostr, *p;
assuan_context_t ctx = NULL;
+ int prot, pid;
- sockname = make_filename (opt.homedir, GPG_AGENT_SOCK_NAME, NULL);
+ if (!mode)
+ {
+ infostr = getenv ("GPG_AGENT_INFO");
+ if (!infostr || !*infostr)
+ {
+ if (!check_for_running_agent (silent, 1))
+ return 0; /* Okay, its running on the standard socket. */
+ if (!silent)
+ log_error (_("no gpg-agent running in this session\n"));
+ return -1;
+ }
- err = assuan_new (&ctx);
- if (!err)
- err = assuan_socket_connect (ctx, sockname, (pid_t)(-1), 0);
- xfree (sockname);
- if (err)
+ infostr = xstrdup (infostr);
+ if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
+ {
+ xfree (infostr);
+ if (!check_for_running_agent (silent, 1))
+ return 0; /* Okay, its running on the standard socket. */
+ if (!silent)
+ log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
+ return -1;
+ }
+
+ *p++ = 0;
+ pid = atoi (p);
+ while (*p && *p != PATHSEP_C)
+ p++;
+ prot = *p? atoi (p+1) : 0;
+ if (prot != 1)
+ {
+ xfree (infostr);
+ if (!silent)
+ log_error (_("gpg-agent protocol version %d is not supported\n"),
+ prot);
+ if (!check_for_running_agent (silent, 1))
+ return 0; /* Okay, its running on the standard socket. */
+ return -1;
+ }
+ }
+ else /* MODE != 0 */
{
- if (!silent)
- log_error (_("no gpg-agent running in this session\n"));
+ infostr = make_filename (opt.homedir, "S.gpg-agent", NULL);
+ pid = (pid_t)(-1);
+ }
+
+ rc = assuan_new (&ctx);
+ if (! rc)
+ rc = assuan_socket_connect (ctx, infostr, pid, 0);
+ xfree (infostr);
+ if (rc)
+ {
+ if (!mode && !check_for_running_agent (silent, 1))
+ return 0; /* Okay, its running on the standard socket. */
+
+ if (!mode && !silent)
+ log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
if (ctx)
assuan_release (ctx);
diff -Nru gnupg2-2.1.6~build1/agent/learncard.c gnupg2-2.0.28/agent/learncard.c
--- gnupg2-2.1.6~build1/agent/learncard.c 2015-06-17 06:39:24.000000000 +0000
+++ gnupg2-2.0.28/agent/learncard.c 2015-06-02 08:13:55.000000000 +0000
@@ -32,7 +32,7 @@
/* Structures used by the callback mechanism to convey information
pertaining to key pairs. */
-struct keypair_info_s
+struct keypair_info_s
{
struct keypair_info_s *next;
int no_cert;
@@ -44,7 +44,7 @@
};
typedef struct keypair_info_s *KEYPAIR_INFO;
-struct kpinfo_cb_parm_s
+struct kpinfo_cb_parm_s
{
ctrl_t ctrl;
int error;
@@ -56,13 +56,13 @@
pertaining to certificates. */
struct certinfo_s {
struct certinfo_s *next;
- int type;
+ int type;
int done;
char id[1];
};
typedef struct certinfo_s *CERTINFO;
-struct certinfo_cb_parm_s
+struct certinfo_cb_parm_s
{
ctrl_t ctrl;
int error;
@@ -75,9 +75,9 @@
struct sinfo_s {
struct sinfo_s *next;
char *data; /* Points into keyword. */
- char keyword[1];
+ char keyword[1];
};
-typedef struct sinfo_s *SINFO;
+typedef struct sinfo_s *SINFO;
struct sinfo_cb_parm_s {
int error;
@@ -172,7 +172,7 @@
return;
}
*p = 0; /* ignore trailing stuff */
-
+
/* store it */
item->next = parm->info;
parm->info = item;
@@ -202,7 +202,7 @@
for (pend = p; *pend && !spacep (pend); pend++)
;
if (p == pend || !*p)
- {
+ {
parm->error = gpg_error (GPG_ERR_INV_RESPONSE);
return;
}
@@ -258,7 +258,7 @@
int rc;
char *derbuf;
size_t derbuflen;
-
+
rc = agent_card_readcert (ctrl, id, &derbuf, &derbuflen);
if (rc)
{
@@ -275,7 +275,7 @@
break;
}
if (opt.verbose || !*action)
- log_info ("error reading certificate '%s': %s%s\n",
+ log_info ("error reading certificate `%s': %s%s\n",
id? id:"?", gpg_strerror (rc), action);
return *action? 0 : rc;
@@ -296,10 +296,10 @@
return 0;
}
-/* Perform the learn operation. If ASSUAN_CONTEXT is not NULL and
- SEND is true all new certificates are send back via Assuan. */
+/* Perform the learn operation. If ASSUAN_CONTEXT is not NULL all new
+ certificates are send back via Assuan. */
int
-agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
+agent_handle_learn (ctrl_t ctrl, void *assuan_context)
{
int rc;
@@ -312,7 +312,7 @@
unsigned char grip[20];
char *p;
int i;
- static int certtype_list[] = {
+ static int certtype_list[] = {
111, /* Root CA */
101, /* trusted */
102, /* useful */
@@ -344,7 +344,7 @@
log_debug ("agent_card_learn failed: %s\n", gpg_strerror (rc));
goto leave;
}
-
+
log_info ("card has S/N: %s\n", serialno);
/* Pass on all the collected status information. */
@@ -368,8 +368,8 @@
if (opt.verbose)
log_info (" id: %s (type=%d)\n",
citem->id, citem->type);
-
- if (assuan_context && send)
+
+ if (assuan_context)
{
rc = send_cert_back (ctrl, citem->id, assuan_context);
if (rc)
@@ -378,7 +378,7 @@
}
}
}
-
+
for (item = parm.info; item; item = item->next)
{
unsigned char *pubkey, *shdkey;
@@ -398,10 +398,10 @@
for (p=item->hexgrip, i=0; i < 20; p += 2, i++)
grip[i] = xtoi_2 (p);
-
- if (!force && !agent_key_available (grip))
+
+ if (!agent_key_available (grip))
continue; /* The key is already available. */
-
+
/* Unknown key - store it. */
rc = agent_card_readkey (ctrl, item->id, &pubkey);
if (rc)
@@ -430,7 +430,7 @@
n = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
assert (n);
- rc = agent_write_private_key (grip, shdkey, n, force);
+ rc = agent_write_private_key (grip, shdkey, n, 0);
xfree (shdkey);
if (rc)
{
@@ -439,12 +439,12 @@
}
if (opt.verbose)
- log_info (" id: %s - shadow key created\n", item->id);
-
- if (assuan_context && send)
+ log_info ("stored\n");
+
+ if (assuan_context)
{
CERTINFO citem;
-
+
/* only send the certificate if we have not done so before */
for (citem = cparm.info; citem; citem = citem->next)
{
@@ -460,7 +460,7 @@
}
}
-
+
leave:
xfree (serialno);
release_keypair_info (parm.info);
@@ -468,3 +468,5 @@
release_sinfo (sparm.info);
return rc;
}
+
+
diff -Nru gnupg2-2.1.6~build1/agent/Makefile.am gnupg2-2.0.28/agent/Makefile.am
--- gnupg2-2.1.6~build1/agent/Makefile.am 2015-06-17 06:39:24.000000000 +0000
+++ gnupg2-2.0.28/agent/Makefile.am 2015-06-02 08:13:55.000000000 +0000
@@ -18,17 +18,12 @@
## Process this file with automake to produce Makefile.in
bin_PROGRAMS = gpg-agent
-libexec_PROGRAMS = gpg-protect-tool
-if !HAVE_W32CE_SYSTEM
-# fixme: Do no use simple-pwquery for preset-passphrase.
-libexec_PROGRAMS += gpg-preset-passphrase
-endif
+libexec_PROGRAMS = gpg-protect-tool gpg-preset-passphrase
noinst_PROGRAMS = $(TESTS)
EXTRA_DIST = ChangeLog-2011 gpg-agent-w32info.rc
-
-AM_CPPFLAGS = -I$(top_srcdir)/common
+AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/common -I$(top_srcdir)/intl
include $(top_srcdir)/am/cmacros.am
@@ -36,7 +31,7 @@
resource_objs += gpg-agent-w32info.o
endif
-AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS)
+AM_CFLAGS = $(GPG_ERROR_CFLAGS) $(LIBGCRYPT_CFLAGS)
gpg_agent_SOURCES = \
gpg-agent.c agent.h \
@@ -51,30 +46,24 @@
protect.c \
trustlist.c \
divert-scd.c \
- cvt-openpgp.c cvt-openpgp.h \
call-scd.c \
learncard.c
-common_libs = $(libcommon)
-commonpth_libs = $(libcommonpth)
-if HAVE_W32CE_SYSTEM
-pwquery_libs =
-else
+common_libs = $(libcommon) ../jnlib/libjnlib.a ../gl/libgnu.a
+commonpth_libs = $(libcommonpth) ../jnlib/libjnlib.a ../gl/libgnu.a
pwquery_libs = ../common/libsimple-pwquery.a
-endif
-gpg_agent_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS)
+gpg_agent_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) $(PTH_CFLAGS)
gpg_agent_LDADD = $(commonpth_libs) \
- $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \
+ $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(PTH_LIBS) \
$(GPG_ERROR_LIBS) $(LIBINTL) $(NETLIBS) $(LIBICONV) \
$(resource_objs)
-gpg_agent_LDFLAGS = $(extra_bin_ldflags)
-gpg_agent_DEPENDENCIES = $(resource_objs)
gpg_protect_tool_SOURCES = \
protect-tool.c \
- protect.c
+ protect.c \
+ minip12.c minip12.h
gpg_protect_tool_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS)
gpg_protect_tool_LDADD = $(common_libs) $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) \
@@ -100,8 +89,8 @@
#
TESTS = t-protect
-t_common_ldadd = $(common_libs) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
- $(LIBINTL) $(LIBICONV) $(NETLIBS)
+t_common_ldadd = $(common_libs) \
+ $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV)
t_protect_SOURCES = t-protect.c protect.c
t_protect_LDADD = $(t_common_ldadd)
diff -Nru gnupg2-2.1.6~build1/agent/Makefile.in gnupg2-2.0.28/agent/Makefile.in
--- gnupg2-2.1.6~build1/agent/Makefile.in 2015-07-01 12:17:03.000000000 +0000
+++ gnupg2-2.0.28/agent/Makefile.in 2015-06-02 12:34:27.000000000 +0000
@@ -114,57 +114,61 @@
build_triplet = @build@
host_triplet = @host@
bin_PROGRAMS = gpg-agent$(EXEEXT)
-libexec_PROGRAMS = gpg-protect-tool$(EXEEXT) $(am__EXEEXT_1)
-# fixme: Do no use simple-pwquery for preset-passphrase.
-@HAVE_W32CE_SYSTEM_FALSE@am__append_1 = gpg-preset-passphrase
-noinst_PROGRAMS = $(am__EXEEXT_2)
+libexec_PROGRAMS = gpg-protect-tool$(EXEEXT) \
+ gpg-preset-passphrase$(EXEEXT)
+noinst_PROGRAMS = $(am__EXEEXT_1)
DIST_COMMON = $(top_srcdir)/am/cmacros.am $(srcdir)/Makefile.in \
- $(srcdir)/Makefile.am $(top_srcdir)/build-aux/mkinstalldirs \
- $(top_srcdir)/build-aux/depcomp
-@HAVE_DOSISH_SYSTEM_FALSE@am__append_2 = -DGNUPG_BINDIR="\"$(bindir)\"" \
+ $(srcdir)/Makefile.am $(top_srcdir)/scripts/mkinstalldirs \
+ $(top_srcdir)/scripts/depcomp
+@HAVE_DOSISH_SYSTEM_FALSE@am__append_1 = -DGNUPG_BINDIR="\"$(bindir)\"" \
@HAVE_DOSISH_SYSTEM_FALSE@ -DGNUPG_LIBEXECDIR="\"$(libexecdir)\"" \
@HAVE_DOSISH_SYSTEM_FALSE@ -DGNUPG_LIBDIR="\"$(libdir)/@PACKAGE@\"" \
@HAVE_DOSISH_SYSTEM_FALSE@ -DGNUPG_DATADIR="\"$(datadir)/@PACKAGE@\"" \
-@HAVE_DOSISH_SYSTEM_FALSE@ -DGNUPG_SYSCONFDIR="\"$(sysconfdir)/@PACKAGE@\"" \
-@HAVE_DOSISH_SYSTEM_FALSE@ -DGNUPG_LOCALSTATEDIR="\"$(localstatedir)\""
+@HAVE_DOSISH_SYSTEM_FALSE@ -DGNUPG_SYSCONFDIR="\"$(sysconfdir)/@PACKAGE@\""
# If a specific protect tool program has been defined, pass its name
# to cc. Note that these macros should not be used directly but via
# the gnupg_module_name function.
-@GNUPG_AGENT_PGM_TRUE@am__append_3 = -DGNUPG_DEFAULT_AGENT="\"@GNUPG_AGENT_PGM@\""
-@GNUPG_PINENTRY_PGM_TRUE@am__append_4 = -DGNUPG_DEFAULT_PINENTRY="\"@GNUPG_PINENTRY_PGM@\""
-@GNUPG_SCDAEMON_PGM_TRUE@am__append_5 = -DGNUPG_DEFAULT_SCDAEMON="\"@GNUPG_SCDAEMON_PGM@\""
-@GNUPG_DIRMNGR_PGM_TRUE@am__append_6 = -DGNUPG_DEFAULT_DIRMNGR="\"@GNUPG_DIRMNGR_PGM@\""
-@GNUPG_PROTECT_TOOL_PGM_TRUE@am__append_7 = -DGNUPG_DEFAULT_PROTECT_TOOL="\"@GNUPG_PROTECT_TOOL_PGM@\""
-@GNUPG_DIRMNGR_LDAP_PGM_TRUE@am__append_8 = -DGNUPG_DEFAULT_DIRMNGR_LDAP="\"@GNUPG_DIRMNGR_LDAP_PGM@\""
-@HAVE_W32_SYSTEM_TRUE@am__append_9 = gpg-agent-w32info.o
+@GNUPG_AGENT_PGM_TRUE@am__append_2 = -DGNUPG_DEFAULT_AGENT="\"@GNUPG_AGENT_PGM@\""
+@GNUPG_PINENTRY_PGM_TRUE@am__append_3 = -DGNUPG_DEFAULT_PINENTRY="\"@GNUPG_PINENTRY_PGM@\""
+@GNUPG_SCDAEMON_PGM_TRUE@am__append_4 = -DGNUPG_DEFAULT_SCDAEMON="\"@GNUPG_SCDAEMON_PGM@\""
+@GNUPG_DIRMNGR_PGM_TRUE@am__append_5 = -DGNUPG_DEFAULT_DIRMNGR="\"@GNUPG_DIRMNGR_PGM@\""
+@GNUPG_PROTECT_TOOL_PGM_TRUE@am__append_6 = -DGNUPG_DEFAULT_PROTECT_TOOL="\"@GNUPG_PROTECT_TOOL_PGM@\""
+@HAVE_W32_SYSTEM_TRUE@am__append_7 = gpg-agent-w32info.o
TESTS = t-protect$(EXEEXT)
subdir = agent
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/autobuild.m4 \
- $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gettext.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/gl/m4/absolute-header.m4 \
+ $(top_srcdir)/gl/m4/alloca.m4 $(top_srcdir)/gl/m4/allocsa.m4 \
+ $(top_srcdir)/gl/m4/eealloc.m4 \
+ $(top_srcdir)/gl/m4/gnulib-comp.m4 \
+ $(top_srcdir)/gl/m4/gnulib-tool.m4 \
+ $(top_srcdir)/gl/m4/mkdtemp.m4 $(top_srcdir)/gl/m4/setenv.m4 \
+ $(top_srcdir)/gl/m4/stdint.m4 $(top_srcdir)/gl/m4/strpbrk.m4 \
+ $(top_srcdir)/gl/m4/unistd_h.m4 $(top_srcdir)/m4/autobuild.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/estream.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gnupg-pth.m4 \
$(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/iconv.m4 \
$(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/ksba.m4 \
$(top_srcdir)/m4/lcmessage.m4 $(top_srcdir)/m4/ldap.m4 \
$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libassuan.m4 \
- $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/nls.m4 \
- $(top_srcdir)/m4/npth.m4 $(top_srcdir)/m4/ntbtls.m4 \
+ $(top_srcdir)/m4/libcurl.m4 $(top_srcdir)/m4/libgcrypt.m4 \
+ $(top_srcdir)/m4/longdouble.m4 $(top_srcdir)/m4/nls.m4 \
$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
- $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/socklen.m4 \
- $(top_srcdir)/m4/sys_socket_h.m4 $(top_srcdir)/m4/tar-ustar.m4 \
+ $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/size_max.m4 \
+ $(top_srcdir)/m4/socklen.m4 $(top_srcdir)/m4/sys_socket_h.m4 \
+ $(top_srcdir)/m4/tar-ustar.m4 $(top_srcdir)/m4/xsize.m4 \
$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-mkinstalldirs = $(SHELL) $(top_srcdir)/build-aux/mkinstalldirs
+mkinstalldirs = $(SHELL) $(top_srcdir)/scripts/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libexecdir)"
-@HAVE_W32CE_SYSTEM_FALSE@am__EXEEXT_1 = \
-@HAVE_W32CE_SYSTEM_FALSE@ gpg-preset-passphrase$(EXEEXT)
-am__EXEEXT_2 = t-protect$(EXEEXT)
+am__EXEEXT_1 = t-protect$(EXEEXT)
PROGRAMS = $(bin_PROGRAMS) $(libexec_PROGRAMS) $(noinst_PROGRAMS)
am_gpg_agent_OBJECTS = gpg_agent-gpg-agent.$(OBJEXT) \
gpg_agent-command.$(OBJEXT) gpg_agent-command-ssh.$(OBJEXT) \
@@ -173,22 +177,24 @@
gpg_agent-pksign.$(OBJEXT) gpg_agent-pkdecrypt.$(OBJEXT) \
gpg_agent-genkey.$(OBJEXT) gpg_agent-protect.$(OBJEXT) \
gpg_agent-trustlist.$(OBJEXT) gpg_agent-divert-scd.$(OBJEXT) \
- gpg_agent-cvt-openpgp.$(OBJEXT) gpg_agent-call-scd.$(OBJEXT) \
- gpg_agent-learncard.$(OBJEXT)
+ gpg_agent-call-scd.$(OBJEXT) gpg_agent-learncard.$(OBJEXT)
gpg_agent_OBJECTS = $(am_gpg_agent_OBJECTS)
am__DEPENDENCIES_1 =
-gpg_agent_LINK = $(CCLD) $(gpg_agent_CFLAGS) $(CFLAGS) \
- $(gpg_agent_LDFLAGS) $(LDFLAGS) -o $@
+gpg_agent_DEPENDENCIES = $(commonpth_libs) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) $(resource_objs)
+gpg_agent_LINK = $(CCLD) $(gpg_agent_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
am_gpg_preset_passphrase_OBJECTS = preset-passphrase.$(OBJEXT)
gpg_preset_passphrase_OBJECTS = $(am_gpg_preset_passphrase_OBJECTS)
-@HAVE_W32CE_SYSTEM_FALSE@am__DEPENDENCIES_2 = \
-@HAVE_W32CE_SYSTEM_FALSE@ ../common/libsimple-pwquery.a
-gpg_preset_passphrase_DEPENDENCIES = $(am__DEPENDENCIES_2) \
- $(common_libs) $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+gpg_preset_passphrase_DEPENDENCIES = $(pwquery_libs) $(common_libs) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1)
am_gpg_protect_tool_OBJECTS = gpg_protect_tool-protect-tool.$(OBJEXT) \
- gpg_protect_tool-protect.$(OBJEXT)
+ gpg_protect_tool-protect.$(OBJEXT) \
+ gpg_protect_tool-minip12.$(OBJEXT)
gpg_protect_tool_OBJECTS = $(am_gpg_protect_tool_OBJECTS)
gpg_protect_tool_DEPENDENCIES = $(common_libs) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
@@ -198,10 +204,10 @@
$(AM_LDFLAGS) $(LDFLAGS) -o $@
am_t_protect_OBJECTS = t-protect.$(OBJEXT) protect.$(OBJEXT)
t_protect_OBJECTS = $(am_t_protect_OBJECTS)
-am__DEPENDENCIES_3 = $(common_libs) $(am__DEPENDENCIES_1) \
+am__DEPENDENCIES_2 = $(common_libs) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
-t_protect_DEPENDENCIES = $(am__DEPENDENCIES_3)
+ $(am__DEPENDENCIES_1)
+t_protect_DEPENDENCIES = $(am__DEPENDENCIES_2)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
@@ -215,7 +221,7 @@
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
-depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+depcomp = $(SHELL) $(top_srcdir)/scripts/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
AM_V_lt = $(am__v_lt_@AM_V@)
@@ -285,7 +291,11 @@
fi; \
}
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABSOLUTE_STDINT_H = @ABSOLUTE_STDINT_H@
ACLOCAL = @ACLOCAL@
+ADNSLIBS = @ADNSLIBS@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
@@ -293,12 +303,16 @@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
+BITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@
+BITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@
+BITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@
+BITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@
+BITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@
BUILD_FILEVERSION = @BUILD_FILEVERSION@
BUILD_HOSTNAME = @BUILD_HOSTNAME@
BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@
BUILD_REVISION = @BUILD_REVISION@
BUILD_TIMESTAMP = @BUILD_TIMESTAMP@
-BUILD_VERSION = @BUILD_VERSION@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CC_FOR_BUILD = @CC_FOR_BUILD@
@@ -314,25 +328,39 @@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
-ENCFS = @ENCFS@
EXEEXT = @EXEEXT@
-FUSERMOUNT = @FUSERMOUNT@
+FAQPROG = @FAQPROG@
GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
GMSGFMT = @GMSGFMT@
GMSGFMT_015 = @GMSGFMT_015@
GNUPG_AGENT_PGM = @GNUPG_AGENT_PGM@
-GNUPG_DIRMNGR_LDAP_PGM = @GNUPG_DIRMNGR_LDAP_PGM@
GNUPG_DIRMNGR_PGM = @GNUPG_DIRMNGR_PGM@
GNUPG_PINENTRY_PGM = @GNUPG_PINENTRY_PGM@
GNUPG_PROTECT_TOOL_PGM = @GNUPG_PROTECT_TOOL_PGM@
GNUPG_SCDAEMON_PGM = @GNUPG_SCDAEMON_PGM@
+GPGKEYS_CURL = @GPGKEYS_CURL@
+GPGKEYS_FINGER = @GPGKEYS_FINGER@
+GPGKEYS_HKP = @GPGKEYS_HKP@
+GPGKEYS_KDNS = @GPGKEYS_KDNS@
GPGKEYS_LDAP = @GPGKEYS_LDAP@
+GPGKEYS_MAILTO = @GPGKEYS_MAILTO@
GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@
GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@
GPG_ERROR_LIBS = @GPG_ERROR_LIBS@
GPG_ERROR_MT_CFLAGS = @GPG_ERROR_MT_CFLAGS@
GPG_ERROR_MT_LIBS = @GPG_ERROR_MT_LIBS@
GREP = @GREP@
+HAVE_INTTYPES_H = @HAVE_INTTYPES_H@
+HAVE_LONG_LONG_INT = @HAVE_LONG_LONG_INT@
+HAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@
+HAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@
+HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@
+HAVE_STDINT_H = @HAVE_STDINT_H@
+HAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@
+HAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@
+HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@
+HAVE_UNSIGNED_LONG_LONG_INT = @HAVE_UNSIGNED_LONG_LONG_INT@
+HAVE_WCHAR_H = @HAVE_WCHAR_H@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -343,18 +371,19 @@
KSBA_CFLAGS = @KSBA_CFLAGS@
KSBA_CONFIG = @KSBA_CONFIG@
KSBA_LIBS = @KSBA_LIBS@
-LBER_LIBS = @LBER_LIBS@
LDAPLIBS = @LDAPLIBS@
LDAP_CPPFLAGS = @LDAP_CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBASSUAN_CFLAGS = @LIBASSUAN_CFLAGS@
LIBASSUAN_CONFIG = @LIBASSUAN_CONFIG@
LIBASSUAN_LIBS = @LIBASSUAN_LIBS@
+LIBCURL = @LIBCURL@
+LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@
LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
-LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@
-LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@
+LIBGNU_LIBDEPS = @LIBGNU_LIBDEPS@
+LIBGNU_LTLIBDEPS = @LIBGNU_LTLIBDEPS@
LIBICONV = @LIBICONV@
LIBINTL = @LIBINTL@
LIBOBJS = @LIBOBJS@
@@ -373,12 +402,6 @@
MSGFMT_015 = @MSGFMT_015@
MSGMERGE = @MSGMERGE@
NETLIBS = @NETLIBS@
-NPTH_CFLAGS = @NPTH_CFLAGS@
-NPTH_CONFIG = @NPTH_CONFIG@
-NPTH_LIBS = @NPTH_LIBS@
-NTBTLS_CFLAGS = @NTBTLS_CFLAGS@
-NTBTLS_CONFIG = @NTBTLS_CONFIG@
-NTBTLS_LIBS = @NTBTLS_LIBS@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
@@ -390,28 +413,37 @@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PERL = @PERL@
-PKG_CONFIG = @PKG_CONFIG@
-PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
-PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POSUB = @POSUB@
+PTH_CFLAGS = @PTH_CFLAGS@
+PTH_CONFIG = @PTH_CONFIG@
+PTH_LIBS = @PTH_LIBS@
+PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@
RANLIB = @RANLIB@
+SED = @SED@
SENDMAIL = @SENDMAIL@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SHRED = @SHRED@
+SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@
+SIZE_T_SUFFIX = @SIZE_T_SUFFIX@
+STDINT_H = @STDINT_H@
STRIP = @STRIP@
SYSROOT = @SYSROOT@
SYS_SOCKET_H = @SYS_SOCKET_H@
TAR = @TAR@
+UNISTD_H = @UNISTD_H@
USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
W32SOCKLIBS = @W32SOCKLIBS@
+WCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@
WINDRES = @WINDRES@
+WINT_T_SUFFIX = @WINT_T_SUFFIX@
XGETTEXT = @XGETTEXT@
XGETTEXT_015 = @XGETTEXT_015@
XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
ZLIBS = @ZLIBS@
+_libcurl_config = @_libcurl_config@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
@@ -463,31 +495,16 @@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
EXTRA_DIST = ChangeLog-2011 gpg-agent-w32info.rc
-
-# NB: AM_CFLAGS may also be used by tools running on the build
-# platform to create source files.
-AM_CPPFLAGS = -I$(top_srcdir)/common -DLOCALEDIR=\"$(localedir)\" \
- $(am__append_2) $(am__append_3) $(am__append_4) \
- $(am__append_5) $(am__append_6) $(am__append_7) \
- $(am__append_8)
-@HAVE_W32CE_SYSTEM_FALSE@extra_sys_libs =
-
-# Under Windows we use LockFileEx. WindowsCE provides this only on
-# the WindowsMobile 6 platform and thus we need to use the coredll6
-# import library. We also want to use a stacksize of 256k instead of
-# the 2MB which is the default with cegcc. 256k is the largest stack
-# we use with pth.
-@HAVE_W32CE_SYSTEM_TRUE@extra_sys_libs = -lcoredll6
-@HAVE_W32CE_SYSTEM_FALSE@extra_bin_ldflags =
-@HAVE_W32CE_SYSTEM_TRUE@extra_bin_ldflags = -Wl,--stack=0x40000
-resource_objs = $(am__append_9)
+AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/common \
+ -I$(top_srcdir)/intl -DLOCALEDIR=\"$(localedir)\" \
+ $(am__append_1) $(am__append_2) $(am__append_3) \
+ $(am__append_4) $(am__append_5) $(am__append_6)
+resource_objs = $(am__append_7)
# Convenience macros
libcommon = ../common/libcommon.a
libcommonpth = ../common/libcommonpth.a
-libcommontls = ../common/libcommontls.a
-libcommontlsnpth = ../common/libcommontlsnpth.a
-AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS)
+AM_CFLAGS = $(GPG_ERROR_CFLAGS) $(LIBGCRYPT_CFLAGS)
gpg_agent_SOURCES = \
gpg-agent.c agent.h \
command.c command-ssh.c \
@@ -501,25 +518,22 @@
protect.c \
trustlist.c \
divert-scd.c \
- cvt-openpgp.c cvt-openpgp.h \
call-scd.c \
learncard.c
-common_libs = $(libcommon)
-commonpth_libs = $(libcommonpth)
-@HAVE_W32CE_SYSTEM_FALSE@pwquery_libs = ../common/libsimple-pwquery.a
-@HAVE_W32CE_SYSTEM_TRUE@pwquery_libs =
-gpg_agent_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS)
+common_libs = $(libcommon) ../jnlib/libjnlib.a ../gl/libgnu.a
+commonpth_libs = $(libcommonpth) ../jnlib/libjnlib.a ../gl/libgnu.a
+pwquery_libs = ../common/libsimple-pwquery.a
+gpg_agent_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) $(PTH_CFLAGS)
gpg_agent_LDADD = $(commonpth_libs) \
- $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \
+ $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(PTH_LIBS) \
$(GPG_ERROR_LIBS) $(LIBINTL) $(NETLIBS) $(LIBICONV) \
$(resource_objs)
-gpg_agent_LDFLAGS = $(extra_bin_ldflags)
-gpg_agent_DEPENDENCIES = $(resource_objs)
gpg_protect_tool_SOURCES = \
protect-tool.c \
- protect.c
+ protect.c \
+ minip12.c minip12.h
gpg_protect_tool_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS)
gpg_protect_tool_LDADD = $(common_libs) $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) \
@@ -534,8 +548,8 @@
$(pwquery_libs) $(common_libs) \
$(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) $(NETLIBS) $(LIBICONV)
-t_common_ldadd = $(common_libs) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
- $(LIBINTL) $(LIBICONV) $(NETLIBS)
+t_common_ldadd = $(common_libs) \
+ $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV)
t_protect_SOURCES = t-protect.c protect.c
t_protect_LDADD = $(t_common_ldadd)
@@ -689,7 +703,6 @@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpg_agent-call-scd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpg_agent-command-ssh.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpg_agent-command.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpg_agent-cvt-openpgp.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpg_agent-divert-scd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpg_agent-findkey.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpg_agent-genkey.Po@am__quote@
@@ -700,6 +713,7 @@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpg_agent-protect.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpg_agent-trans.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpg_agent-trustlist.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpg_protect_tool-minip12.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpg_protect_tool-protect-tool.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpg_protect_tool-protect.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/preset-passphrase.Po@am__quote@
@@ -902,20 +916,6 @@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpg_agent_CFLAGS) $(CFLAGS) -c -o gpg_agent-divert-scd.obj `if test -f 'divert-scd.c'; then $(CYGPATH_W) 'divert-scd.c'; else $(CYGPATH_W) '$(srcdir)/divert-scd.c'; fi`
-gpg_agent-cvt-openpgp.o: cvt-openpgp.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpg_agent_CFLAGS) $(CFLAGS) -MT gpg_agent-cvt-openpgp.o -MD -MP -MF $(DEPDIR)/gpg_agent-cvt-openpgp.Tpo -c -o gpg_agent-cvt-openpgp.o `test -f 'cvt-openpgp.c' || echo '$(srcdir)/'`cvt-openpgp.c
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpg_agent-cvt-openpgp.Tpo $(DEPDIR)/gpg_agent-cvt-openpgp.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cvt-openpgp.c' object='gpg_agent-cvt-openpgp.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpg_agent_CFLAGS) $(CFLAGS) -c -o gpg_agent-cvt-openpgp.o `test -f 'cvt-openpgp.c' || echo '$(srcdir)/'`cvt-openpgp.c
-
-gpg_agent-cvt-openpgp.obj: cvt-openpgp.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpg_agent_CFLAGS) $(CFLAGS) -MT gpg_agent-cvt-openpgp.obj -MD -MP -MF $(DEPDIR)/gpg_agent-cvt-openpgp.Tpo -c -o gpg_agent-cvt-openpgp.obj `if test -f 'cvt-openpgp.c'; then $(CYGPATH_W) 'cvt-openpgp.c'; else $(CYGPATH_W) '$(srcdir)/cvt-openpgp.c'; fi`
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpg_agent-cvt-openpgp.Tpo $(DEPDIR)/gpg_agent-cvt-openpgp.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cvt-openpgp.c' object='gpg_agent-cvt-openpgp.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpg_agent_CFLAGS) $(CFLAGS) -c -o gpg_agent-cvt-openpgp.obj `if test -f 'cvt-openpgp.c'; then $(CYGPATH_W) 'cvt-openpgp.c'; else $(CYGPATH_W) '$(srcdir)/cvt-openpgp.c'; fi`
-
gpg_agent-call-scd.o: call-scd.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpg_agent_CFLAGS) $(CFLAGS) -MT gpg_agent-call-scd.o -MD -MP -MF $(DEPDIR)/gpg_agent-call-scd.Tpo -c -o gpg_agent-call-scd.o `test -f 'call-scd.c' || echo '$(srcdir)/'`call-scd.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpg_agent-call-scd.Tpo $(DEPDIR)/gpg_agent-call-scd.Po
@@ -972,6 +972,20 @@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpg_protect_tool_CFLAGS) $(CFLAGS) -c -o gpg_protect_tool-protect.obj `if test -f 'protect.c'; then $(CYGPATH_W) 'protect.c'; else $(CYGPATH_W) '$(srcdir)/protect.c'; fi`
+gpg_protect_tool-minip12.o: minip12.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpg_protect_tool_CFLAGS) $(CFLAGS) -MT gpg_protect_tool-minip12.o -MD -MP -MF $(DEPDIR)/gpg_protect_tool-minip12.Tpo -c -o gpg_protect_tool-minip12.o `test -f 'minip12.c' || echo '$(srcdir)/'`minip12.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpg_protect_tool-minip12.Tpo $(DEPDIR)/gpg_protect_tool-minip12.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minip12.c' object='gpg_protect_tool-minip12.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpg_protect_tool_CFLAGS) $(CFLAGS) -c -o gpg_protect_tool-minip12.o `test -f 'minip12.c' || echo '$(srcdir)/'`minip12.c
+
+gpg_protect_tool-minip12.obj: minip12.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpg_protect_tool_CFLAGS) $(CFLAGS) -MT gpg_protect_tool-minip12.obj -MD -MP -MF $(DEPDIR)/gpg_protect_tool-minip12.Tpo -c -o gpg_protect_tool-minip12.obj `if test -f 'minip12.c'; then $(CYGPATH_W) 'minip12.c'; else $(CYGPATH_W) '$(srcdir)/minip12.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpg_protect_tool-minip12.Tpo $(DEPDIR)/gpg_protect_tool-minip12.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minip12.c' object='gpg_protect_tool-minip12.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpg_protect_tool_CFLAGS) $(CFLAGS) -c -o gpg_protect_tool-minip12.obj `if test -f 'minip12.c'; then $(CYGPATH_W) 'minip12.c'; else $(CYGPATH_W) '$(srcdir)/minip12.c'; fi`
+
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
diff -Nru gnupg2-2.1.6~build1/agent/minip12.c gnupg2-2.0.28/agent/minip12.c
--- gnupg2-2.1.6~build1/agent/minip12.c 1970-01-01 00:00:00.000000000 +0000
+++ gnupg2-2.0.28/agent/minip12.c 2015-06-02 08:13:55.000000000 +0000
@@ -0,0 +1,2362 @@
+/* minip12.c - A minimal pkcs-12 implementation.
+ * Copyright (C) 2002, 2003, 2004, 2006 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 .
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef TEST
+#include
+#include
+#endif
+
+#include "../jnlib/logging.h"
+#include "../jnlib/utf8conv.h"
+#include "minip12.h"
+
+#ifndef DIM
+#define DIM(v) (sizeof(v)/sizeof((v)[0]))
+#endif
+
+
+enum
+{
+ UNIVERSAL = 0,
+ APPLICATION = 1,
+ ASNCONTEXT = 2,
+ PRIVATE = 3
+};
+
+
+enum
+{
+ TAG_NONE = 0,
+ TAG_BOOLEAN = 1,
+ TAG_INTEGER = 2,
+ TAG_BIT_STRING = 3,
+ TAG_OCTET_STRING = 4,
+ TAG_NULL = 5,
+ TAG_OBJECT_ID = 6,
+ TAG_OBJECT_DESCRIPTOR = 7,
+ TAG_EXTERNAL = 8,
+ TAG_REAL = 9,
+ TAG_ENUMERATED = 10,
+ TAG_EMBEDDED_PDV = 11,
+ TAG_UTF8_STRING = 12,
+ TAG_REALTIVE_OID = 13,
+ TAG_SEQUENCE = 16,
+ TAG_SET = 17,
+ TAG_NUMERIC_STRING = 18,
+ TAG_PRINTABLE_STRING = 19,
+ TAG_TELETEX_STRING = 20,
+ TAG_VIDEOTEX_STRING = 21,
+ TAG_IA5_STRING = 22,
+ TAG_UTC_TIME = 23,
+ TAG_GENERALIZED_TIME = 24,
+ TAG_GRAPHIC_STRING = 25,
+ TAG_VISIBLE_STRING = 26,
+ TAG_GENERAL_STRING = 27,
+ TAG_UNIVERSAL_STRING = 28,
+ TAG_CHARACTER_STRING = 29,
+ TAG_BMP_STRING = 30
+};
+
+
+static unsigned char const oid_data[9] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 };
+static unsigned char const oid_encryptedData[9] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06 };
+static unsigned char const oid_pkcs_12_keyBag[11] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, 0x01 };
+static unsigned char const oid_pkcs_12_pkcs_8ShroudedKeyBag[11] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, 0x02 };
+static unsigned char const oid_pkcs_12_CertBag[11] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, 0x03 };
+static unsigned char const oid_pkcs_12_CrlBag[11] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, 0x04 };
+
+static unsigned char const oid_pbeWithSHAAnd3_KeyTripleDES_CBC[10] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x01, 0x03 };
+static unsigned char const oid_pbeWithSHAAnd40BitRC2_CBC[10] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x01, 0x06 };
+static unsigned char const oid_x509Certificate_for_pkcs_12[10] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x16, 0x01 };
+
+
+static unsigned char const oid_rsaEncryption[9] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
+
+
+static unsigned char const data_3desiter2048[30] = {
+ 0x30, 0x1C, 0x06, 0x0A, 0x2A, 0x86, 0x48, 0x86,
+ 0xF7, 0x0D, 0x01, 0x0C, 0x01, 0x03, 0x30, 0x0E,
+ 0x04, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0x02, 0x02, 0x08, 0x00 };
+#define DATA_3DESITER2048_SALT_OFF 18
+
+static unsigned char const data_rc2iter2048[30] = {
+ 0x30, 0x1C, 0x06, 0x0A, 0x2A, 0x86, 0x48, 0x86,
+ 0xF7, 0x0D, 0x01, 0x0C, 0x01, 0x06, 0x30, 0x0E,
+ 0x04, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0x02, 0x02, 0x08, 0x00 };
+#define DATA_RC2ITER2048_SALT_OFF 18
+
+static unsigned char const data_mactemplate[51] = {
+ 0x30, 0x31, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
+ 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04,
+ 0x14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0x08, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02,
+ 0x02, 0x08, 0x00 };
+#define DATA_MACTEMPLATE_MAC_OFF 17
+#define DATA_MACTEMPLATE_SALT_OFF 39
+
+static unsigned char const data_attrtemplate[106] = {
+ 0x31, 0x7c, 0x30, 0x55, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x14, 0x31,
+ 0x48, 0x1e, 0x46, 0x00, 0x47, 0x00, 0x6e, 0x00,
+ 0x75, 0x00, 0x50, 0x00, 0x47, 0x00, 0x20, 0x00,
+ 0x65, 0x00, 0x78, 0x00, 0x70, 0x00, 0x6f, 0x00,
+ 0x72, 0x00, 0x74, 0x00, 0x65, 0x00, 0x64, 0x00,
+ 0x20, 0x00, 0x63, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00,
+ 0x63, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x20, 0x00, 0x66, 0x00, 0x66, 0x00, 0x66, 0x00,
+ 0x66, 0x00, 0x66, 0x00, 0x66, 0x00, 0x66, 0x00,
+ 0x66, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x16,
+ 0x04, 0x14 }; /* Need to append SHA-1 digest. */
+#define DATA_ATTRTEMPLATE_KEYID_OFF 73
+
+struct buffer_s
+{
+ unsigned char *buffer;
+ size_t length;
+};
+
+
+struct tag_info
+{
+ int class;
+ int is_constructed;
+ unsigned long tag;
+ unsigned long length; /* length part of the TLV */
+ int nhdr;
+ int ndef; /* It is an indefinite length */
+};
+
+
+/* Parse the buffer at the address BUFFER which is of SIZE and return
+ the tag and the length part from the TLV triplet. Update BUFFER
+ and SIZE on success. Checks that the encoded length does not
+ exhaust the length of the provided buffer. */
+static int
+parse_tag (unsigned char const **buffer, size_t *size, struct tag_info *ti)
+{
+ int c;
+ unsigned long tag;
+ const unsigned char *buf = *buffer;
+ size_t length = *size;
+
+ ti->length = 0;
+ ti->ndef = 0;
+ ti->nhdr = 0;
+
+ /* Get the tag */
+ if (!length)
+ return -1; /* premature eof */
+ c = *buf++; length--;
+ ti->nhdr++;
+
+ ti->class = (c & 0xc0) >> 6;
+ ti->is_constructed = !!(c & 0x20);
+ tag = c & 0x1f;
+
+ if (tag == 0x1f)
+ {
+ tag = 0;
+ do
+ {
+ tag <<= 7;
+ if (!length)
+ return -1; /* premature eof */
+ c = *buf++; length--;
+ ti->nhdr++;
+ tag |= c & 0x7f;
+ }
+ while (c & 0x80);
+ }
+ ti->tag = tag;
+
+ /* Get the length */
+ if (!length)
+ return -1; /* prematureeof */
+ c = *buf++; length--;
+ ti->nhdr++;
+
+ if ( !(c & 0x80) )
+ ti->length = c;
+ else if (c == 0x80)
+ ti->ndef = 1;
+ else if (c == 0xff)
+ return -1; /* forbidden length value */
+ else
+ {
+ unsigned long len = 0;
+ int count = c & 0x7f;
+
+ for (; count; count--)
+ {
+ len <<= 8;
+ if (!length)
+ return -1; /* premature_eof */
+ c = *buf++; length--;
+ ti->nhdr++;
+ len |= c & 0xff;
+ }
+ ti->length = len;
+ }
+
+ if (ti->class == UNIVERSAL && !ti->tag)
+ ti->length = 0;
+
+ if (ti->length > length)
+ return -1; /* data larger than buffer. */
+
+ *buffer = buf;
+ *size = length;
+ return 0;
+}
+
+
+/* Given an ASN.1 chunk of a structure like:
+
+ 24 NDEF: OCTET STRING -- This is not passed to us
+ 04 1: OCTET STRING -- INPUT point s to here
+ : 30
+ 04 1: OCTET STRING
+ : 80
+ [...]
+ 04 2: OCTET STRING
+ : 00 00
+ : } -- This denotes a Null tag and are the last
+ -- two bytes in INPUT.
+
+ Create a new buffer with the content of that octet string. INPUT
+ is the orginal buffer with a length as stored at LENGTH. Returns
+ NULL on error or a new malloced buffer with the length of this new
+ buffer stored at LENGTH and the number of bytes parsed from input
+ are added to the value stored at INPUT_CONSUMED. INPUT_CONSUMED is
+ allowed to be passed as NULL if the caller is not interested in
+ this value. */
+static unsigned char *
+cram_octet_string (const unsigned char *input, size_t *length,
+ size_t *input_consumed)
+{
+ const unsigned char *s = input;
+ size_t n = *length;
+ unsigned char *output, *d;
+ struct tag_info ti;
+
+ /* Allocate output buf. We know that it won't be longer than the
+ input buffer. */
+ d = output = gcry_malloc (n);
+ if (!output)
+ goto bailout;
+
+ for (;;)
+ {
+ if (parse_tag (&s, &n, &ti))
+ goto bailout;
+ if (ti.class == UNIVERSAL && ti.tag == TAG_OCTET_STRING
+ && !ti.ndef && !ti.is_constructed)
+ {
+ memcpy (d, s, ti.length);
+ s += ti.length;
+ d += ti.length;
+ n -= ti.length;
+ }
+ else if (ti.class == UNIVERSAL && !ti.tag && !ti.is_constructed)
+ break; /* Ready */
+ else
+ goto bailout;
+ }
+
+
+ *length = d - output;
+ if (input_consumed)
+ *input_consumed += s - input;
+ return output;
+
+ bailout:
+ if (input_consumed)
+ *input_consumed += s - input;
+ gcry_free (output);
+ return NULL;
+}
+
+
+
+static int
+string_to_key (int id, char *salt, size_t saltlen, int iter, const char *pw,
+ int req_keylen, unsigned char *keybuf)
+{
+ int rc, i, j;
+ gcry_md_hd_t md;
+ gcry_mpi_t num_b1 = NULL;
+ int pwlen;
+ unsigned char hash[20], buf_b[64], buf_i[128], *p;
+ size_t cur_keylen;
+ size_t n;
+
+ cur_keylen = 0;
+ pwlen = strlen (pw);
+ if (pwlen > 63/2)
+ {
+ log_error ("password too long\n");
+ return -1;
+ }
+
+ if (saltlen < 8)
+ {
+ log_error ("salt too short\n");
+ return -1;
+ }
+
+ /* Store salt and password in BUF_I */
+ p = buf_i;
+ for(i=0; i < 64; i++)
+ *p++ = salt [i%saltlen];
+ for(i=j=0; i < 64; i += 2)
+ {
+ *p++ = 0;
+ *p++ = pw[j];
+ if (++j > pwlen) /* Note, that we include the trailing zero */
+ j = 0;
+ }
+
+ for (;;)
+ {
+ rc = gcry_md_open (&md, GCRY_MD_SHA1, 0);
+ if (rc)
+ {
+ log_error ( "gcry_md_open failed: %s\n", gpg_strerror (rc));
+ return rc;
+ }
+ for(i=0; i < 64; i++)
+ gcry_md_putc (md, id);
+ gcry_md_write (md, buf_i, 128);
+ memcpy (hash, gcry_md_read (md, 0), 20);
+ gcry_md_close (md);
+ for (i=1; i < iter; i++)
+ gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash, 20);
+
+ for (i=0; i < 20 && cur_keylen < req_keylen; i++)
+ keybuf[cur_keylen++] = hash[i];
+ if (cur_keylen == req_keylen)
+ {
+ gcry_mpi_release (num_b1);
+ return 0; /* ready */
+ }
+
+ /* need more bytes. */
+ for(i=0; i < 64; i++)
+ buf_b[i] = hash[i % 20];
+ rc = gcry_mpi_scan (&num_b1, GCRYMPI_FMT_USG, buf_b, 64, &n);
+ if (rc)
+ {
+ log_error ( "gcry_mpi_scan failed: %s\n", gpg_strerror (rc));
+ return -1;
+ }
+ gcry_mpi_add_ui (num_b1, num_b1, 1);
+ for (i=0; i < 128; i += 64)
+ {
+ gcry_mpi_t num_ij;
+
+ rc = gcry_mpi_scan (&num_ij, GCRYMPI_FMT_USG, buf_i + i, 64, &n);
+ if (rc)
+ {
+ log_error ( "gcry_mpi_scan failed: %s\n",
+ gpg_strerror (rc));
+ return -1;
+ }
+ gcry_mpi_add (num_ij, num_ij, num_b1);
+ gcry_mpi_clear_highbit (num_ij, 64*8);
+ rc = gcry_mpi_print (GCRYMPI_FMT_USG, buf_i + i, 64, &n, num_ij);
+ if (rc)
+ {
+ log_error ( "gcry_mpi_print failed: %s\n",
+ gpg_strerror (rc));
+ return -1;
+ }
+ gcry_mpi_release (num_ij);
+ }
+ }
+}
+
+
+static int
+set_key_iv (gcry_cipher_hd_t chd, char *salt, size_t saltlen, int iter,
+ const char *pw, int keybytes)
+{
+ unsigned char keybuf[24];
+ int rc;
+
+ assert (keybytes == 5 || keybytes == 24);
+ if (string_to_key (1, salt, saltlen, iter, pw, keybytes, keybuf))
+ return -1;
+ rc = gcry_cipher_setkey (chd, keybuf, keybytes);
+ if (rc)
+ {
+ log_error ( "gcry_cipher_setkey failed: %s\n", gpg_strerror (rc));
+ return -1;
+ }
+
+ if (string_to_key (2, salt, saltlen, iter, pw, 8, keybuf))
+ return -1;
+ rc = gcry_cipher_setiv (chd, keybuf, 8);
+ if (rc)
+ {
+ log_error ("gcry_cipher_setiv failed: %s\n", gpg_strerror (rc));
+ return -1;
+ }
+ return 0;
+}
+
+
+static void
+crypt_block (unsigned char *buffer, size_t length, char *salt, size_t saltlen,
+ int iter, const char *pw, int cipher_algo, int encrypt)
+{
+ gcry_cipher_hd_t chd;
+ int rc;
+
+ rc = gcry_cipher_open (&chd, cipher_algo, GCRY_CIPHER_MODE_CBC, 0);
+ if (rc)
+ {
+ log_error ( "gcry_cipher_open failed: %s\n", gpg_strerror(rc));
+ wipememory (buffer, length);
+ return;
+ }
+ if (set_key_iv (chd, salt, saltlen, iter, pw,
+ cipher_algo == GCRY_CIPHER_RFC2268_40? 5:24))
+ {
+ wipememory (buffer, length);
+ goto leave;
+ }
+
+ rc = encrypt? gcry_cipher_encrypt (chd, buffer, length, NULL, 0)
+ : gcry_cipher_decrypt (chd, buffer, length, NULL, 0);
+
+ if (rc)
+ {
+ wipememory (buffer, length);
+ log_error ( "en/de-crytion failed: %s\n", gpg_strerror (rc));
+ goto leave;
+ }
+
+ leave:
+ gcry_cipher_close (chd);
+}
+
+
+/* Decrypt a block of data and try several encodings of the key.
+ CIPHERTEXT is the encrypted data of size LENGTH bytes; PLAINTEXT is
+ a buffer of the same size to receive the decryption result. SALT,
+ SALTLEN, ITER and PW are the information required for decryption
+ and CIPHER_ALGO is the algorithm id to use. CHECK_FNC is a
+ function called with the plaintext and used to check whether the
+ decryption succeeded; i.e. that a correct passphrase has been
+ given. That function shall return true if the decryption has likely
+ succeeded. */
+static void
+decrypt_block (const void *ciphertext, unsigned char *plaintext, size_t length,
+ char *salt, size_t saltlen,
+ int iter, const char *pw, int cipher_algo,
+ int (*check_fnc) (const void *, size_t))
+{
+ static const char * const charsets[] = {
+ "", /* No conversion - use the UTF-8 passphrase direct. */
+ "ISO-8859-1",
+ "ISO-8859-15",
+ "ISO-8859-2",
+ "ISO-8859-3",
+ "ISO-8859-4",
+ "ISO-8859-5",
+ "ISO-8859-6",
+ "ISO-8859-7",
+ "ISO-8859-8",
+ "ISO-8859-9",
+ "KOI8-R",
+ "IBM437",
+ "IBM850",
+ "EUC-JP",
+ "BIG5",
+ NULL
+ };
+ int charsetidx = 0;
+ char *convertedpw = NULL; /* Malloced and converted password or NULL. */
+ size_t convertedpwsize = 0; /* Allocated length. */
+
+ for (charsetidx=0; charsets[charsetidx]; charsetidx++)
+ {
+ if (*charsets[charsetidx])
+ {
+ jnlib_iconv_t cd;
+ const char *inptr;
+ char *outptr;
+ size_t inbytes, outbytes;
+
+ if (!convertedpw)
+ {
+ /* We assume one byte encodings. Thus we can allocate
+ the buffer of the same size as the original
+ passphrase; the result will actually be shorter
+ then. */
+ convertedpwsize = strlen (pw) + 1;
+ convertedpw = gcry_malloc_secure (convertedpwsize);
+ if (!convertedpw)
+ {
+ log_info ("out of secure memory while"
+ " converting passphrase\n");
+ break; /* Give up. */
+ }
+ }
+
+ cd = jnlib_iconv_open (charsets[charsetidx], "utf-8");
+ if (cd == (jnlib_iconv_t)(-1))
+ continue;
+
+ inptr = pw;
+ inbytes = strlen (pw);
+ outptr = convertedpw;
+ outbytes = convertedpwsize - 1;
+ if ( jnlib_iconv (cd, (const char **)&inptr, &inbytes,
+ &outptr, &outbytes) == (size_t)-1)
+ {
+ jnlib_iconv_close (cd);
+ continue;
+ }
+ *outptr = 0;
+ jnlib_iconv_close (cd);
+ log_info ("decryption failed; trying charset `%s'\n",
+ charsets[charsetidx]);
+ }
+ memcpy (plaintext, ciphertext, length);
+ crypt_block (plaintext, length, salt, saltlen, iter,
+ convertedpw? convertedpw:pw, cipher_algo, 0);
+ if (check_fnc (plaintext, length))
+ break; /* Decryption succeeded. */
+ }
+ gcry_free (convertedpw);
+}
+
+
+/* Return true if the decryption of an bag_encrypted_data object has
+ likely succeeded. */
+static int
+bag_decrypted_data_p (const void *plaintext, size_t length)
+{
+ struct tag_info ti;
+ const unsigned char *p = plaintext;
+ size_t n = length;
+
+ /* { */
+ /* # warning debug code is enabled */
+ /* FILE *fp = fopen ("tmp-rc2-plain.der", "wb"); */
+ /* if (!fp || fwrite (p, n, 1, fp) != 1) */
+ /* exit (2); */
+ /* fclose (fp); */
+ /* } */
+
+ if (parse_tag (&p, &n, &ti))
+ return 0;
+ if (ti.class || ti.tag != TAG_SEQUENCE)
+ return 0;
+ if (parse_tag (&p, &n, &ti))
+ return 0;
+
+ return 1;
+}
+
+/* Note: If R_RESULT is passed as NULL, a key object as already be
+ processed and thus we need to skip it here. */
+static int
+parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
+ int startoffset, size_t *r_consumed, const char *pw,
+ void (*certcb)(void*, const unsigned char*, size_t),
+ void *certcbarg, gcry_mpi_t **r_result)
+{
+ struct tag_info ti;
+ const unsigned char *p = buffer;
+ const unsigned char *p_start = buffer;
+ size_t n = length;
+ const char *where;
+ char salt[20];
+ size_t saltlen;
+ unsigned int iter;
+ unsigned char *plain = NULL;
+ int bad_pass = 0;
+ unsigned char *cram_buffer = NULL;
+ size_t consumed = 0; /* Number of bytes consumed from the orginal buffer. */
+ int is_3des = 0;
+ gcry_mpi_t *result = NULL;
+ int result_count;
+
+ if (r_result)
+ *r_result = NULL;
+ where = "start";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class != ASNCONTEXT || ti.tag)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.tag != TAG_SEQUENCE)
+ goto bailout;
+
+ where = "bag.encryptedData.version";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.tag != TAG_INTEGER || ti.length != 1 || *p != 0)
+ goto bailout;
+ p++; n--;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.tag != TAG_SEQUENCE)
+ goto bailout;
+
+ where = "bag.encryptedData.data";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.tag != TAG_OBJECT_ID || ti.length != DIM(oid_data)
+ || memcmp (p, oid_data, DIM(oid_data)))
+ goto bailout;
+ p += DIM(oid_data);
+ n -= DIM(oid_data);
+
+ where = "bag.encryptedData.keyinfo";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (!ti.class && ti.tag == TAG_OBJECT_ID
+ && ti.length == DIM(oid_pbeWithSHAAnd40BitRC2_CBC)
+ && !memcmp (p, oid_pbeWithSHAAnd40BitRC2_CBC,
+ DIM(oid_pbeWithSHAAnd40BitRC2_CBC)))
+ {
+ p += DIM(oid_pbeWithSHAAnd40BitRC2_CBC);
+ n -= DIM(oid_pbeWithSHAAnd40BitRC2_CBC);
+ }
+ else if (!ti.class && ti.tag == TAG_OBJECT_ID
+ && ti.length == DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC)
+ && !memcmp (p, oid_pbeWithSHAAnd3_KeyTripleDES_CBC,
+ DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC)))
+ {
+ p += DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC);
+ n -= DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC);
+ is_3des = 1;
+ }
+ else
+ goto bailout;
+
+ where = "rc2or3des-params";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_OCTET_STRING
+ || ti.length < 8 || ti.length > 20 )
+ goto bailout;
+ saltlen = ti.length;
+ memcpy (salt, p, saltlen);
+ p += saltlen;
+ n -= saltlen;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_INTEGER || !ti.length )
+ goto bailout;
+ for (iter=0; ti.length; ti.length--)
+ {
+ iter <<= 8;
+ iter |= (*p++) & 0xff;
+ n--;
+ }
+
+ where = "rc2or3des-ciphertext";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+
+ consumed = p - p_start;
+ if (ti.class == ASNCONTEXT && ti.tag == 0 && ti.is_constructed && ti.ndef)
+ {
+ /* Mozilla exported certs now come with single byte chunks of
+ octect strings. (Mozilla Firefox 1.0.4). Arghh. */
+ where = "cram-rc2or3des-ciphertext";
+ cram_buffer = cram_octet_string ( p, &n, &consumed);
+ if (!cram_buffer)
+ goto bailout;
+ p = p_start = cram_buffer;
+ if (r_consumed)
+ *r_consumed = consumed;
+ r_consumed = NULL; /* Ugly hack to not update that value any further. */
+ ti.length = n;
+ }
+ else if (ti.class == ASNCONTEXT && ti.tag == 0 && ti.length )
+ ;
+ else
+ goto bailout;
+
+ log_info ("%lu bytes of %s encrypted text\n",ti.length,is_3des?"3DES":"RC2");
+
+ plain = gcry_malloc_secure (ti.length);
+ if (!plain)
+ {
+ log_error ("error allocating decryption buffer\n");
+ goto bailout;
+ }
+ decrypt_block (p, plain, ti.length, salt, saltlen, iter, pw,
+ is_3des? GCRY_CIPHER_3DES : GCRY_CIPHER_RFC2268_40,
+ bag_decrypted_data_p);
+ n = ti.length;
+ startoffset = 0;
+ p_start = p = plain;
+
+ where = "outer.outer.seq";
+ if (parse_tag (&p, &n, &ti))
+ {
+ bad_pass = 1;
+ goto bailout;
+ }
+ if (ti.class || ti.tag != TAG_SEQUENCE)
+ {
+ bad_pass = 1;
+ goto bailout;
+ }
+
+ if (parse_tag (&p, &n, &ti))
+ {
+ bad_pass = 1;
+ goto bailout;
+ }
+
+ /* Loop over all certificates inside the bag. */
+ while (n)
+ {
+ int iscrlbag = 0;
+ int iskeybag = 0;
+
+ where = "certbag.nextcert";
+ if (ti.class || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+
+ where = "certbag.objectidentifier";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_OBJECT_ID)
+ goto bailout;
+ if ( ti.length == DIM(oid_pkcs_12_CertBag)
+ && !memcmp (p, oid_pkcs_12_CertBag, DIM(oid_pkcs_12_CertBag)))
+ {
+ p += DIM(oid_pkcs_12_CertBag);
+ n -= DIM(oid_pkcs_12_CertBag);
+ }
+ else if ( ti.length == DIM(oid_pkcs_12_CrlBag)
+ && !memcmp (p, oid_pkcs_12_CrlBag, DIM(oid_pkcs_12_CrlBag)))
+ {
+ p += DIM(oid_pkcs_12_CrlBag);
+ n -= DIM(oid_pkcs_12_CrlBag);
+ iscrlbag = 1;
+ }
+ else if ( ti.length == DIM(oid_pkcs_12_keyBag)
+ && !memcmp (p, oid_pkcs_12_keyBag, DIM(oid_pkcs_12_keyBag)))
+ {
+ /* The TrustedMIME plugin for MS Outlook started to create
+ files with just one outer 3DES encrypted container and
+ inside the certificates as well as the key. */
+ p += DIM(oid_pkcs_12_keyBag);
+ n -= DIM(oid_pkcs_12_keyBag);
+ iskeybag = 1;
+ }
+ else
+ goto bailout;
+
+ where = "certbag.before.certheader";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class != ASNCONTEXT || ti.tag)
+ goto bailout;
+ if (iscrlbag)
+ {
+ log_info ("skipping unsupported crlBag\n");
+ p += ti.length;
+ n -= ti.length;
+ }
+ else if (iskeybag && (result || !r_result))
+ {
+ log_info ("one keyBag already processed; skipping this one\n");
+ p += ti.length;
+ n -= ti.length;
+ }
+ else if (iskeybag)
+ {
+ int len;
+
+ log_info ("processing simple keyBag\n");
+
+ /* Fixme: This code is duplicated from parse_bag_data. */
+ if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER
+ || ti.length != 1 || *p)
+ goto bailout;
+ p++; n--;
+ if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ len = ti.length;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (len < ti.nhdr)
+ goto bailout;
+ len -= ti.nhdr;
+ if (ti.class || ti.tag != TAG_OBJECT_ID
+ || ti.length != DIM(oid_rsaEncryption)
+ || memcmp (p, oid_rsaEncryption,
+ DIM(oid_rsaEncryption)))
+ goto bailout;
+ p += DIM (oid_rsaEncryption);
+ n -= DIM (oid_rsaEncryption);
+ if (len < ti.length)
+ goto bailout;
+ len -= ti.length;
+ if (n < len)
+ goto bailout;
+ p += len;
+ n -= len;
+ if ( parse_tag (&p, &n, &ti)
+ || ti.class || ti.tag != TAG_OCTET_STRING)
+ goto bailout;
+ if ( parse_tag (&p, &n, &ti)
+ || ti.class || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ len = ti.length;
+
+ result = gcry_calloc (10, sizeof *result);
+ if (!result)
+ {
+ log_error ( "error allocating result array\n");
+ goto bailout;
+ }
+ result_count = 0;
+
+ where = "reading.keybag.key-parameters";
+ for (result_count = 0; len && result_count < 9;)
+ {
+ if ( parse_tag (&p, &n, &ti)
+ || ti.class || ti.tag != TAG_INTEGER)
+ goto bailout;
+ if (len < ti.nhdr)
+ goto bailout;
+ len -= ti.nhdr;
+ if (len < ti.length)
+ goto bailout;
+ len -= ti.length;
+ if (!result_count && ti.length == 1 && !*p)
+ ; /* ignore the very first one if it is a 0 */
+ else
+ {
+ int rc;
+
+ rc = gcry_mpi_scan (result+result_count, GCRYMPI_FMT_USG, p,
+ ti.length, NULL);
+ if (rc)
+ {
+ log_error ("error parsing key parameter: %s\n",
+ gpg_strerror (rc));
+ goto bailout;
+ }
+ result_count++;
+ }
+ p += ti.length;
+ n -= ti.length;
+ }
+ if (len)
+ goto bailout;
+ }
+ else
+ {
+ log_info ("processing certBag\n");
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_OBJECT_ID
+ || ti.length != DIM(oid_x509Certificate_for_pkcs_12)
+ || memcmp (p, oid_x509Certificate_for_pkcs_12,
+ DIM(oid_x509Certificate_for_pkcs_12)))
+ goto bailout;
+ p += DIM(oid_x509Certificate_for_pkcs_12);
+ n -= DIM(oid_x509Certificate_for_pkcs_12);
+
+ where = "certbag.before.octetstring";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class != ASNCONTEXT || ti.tag)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_OCTET_STRING || ti.ndef)
+ goto bailout;
+
+ /* Return the certificate. */
+ if (certcb)
+ certcb (certcbarg, p, ti.length);
+
+ p += ti.length;
+ n -= ti.length;
+ }
+
+ /* Ugly hack to cope with the padding: Forget about the rest if
+ that is less or equal to the cipher's block length. We can
+ reasonable assume that all valid data will be longer than
+ just one block. */
+ if (n <= 8)
+ n = 0;
+
+ /* Skip the optional SET with the pkcs12 cert attributes. */
+ if (n)
+ {
+ where = "bag.attributes";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (!ti.class && ti.tag == TAG_SEQUENCE)
+ ; /* No attributes. */
+ else if (!ti.class && ti.tag == TAG_SET && !ti.ndef)
+ { /* The optional SET. */
+ p += ti.length;
+ n -= ti.length;
+ if (n <= 8)
+ n = 0;
+ if (n && parse_tag (&p, &n, &ti))
+ goto bailout;
+ }
+ else
+ goto bailout;
+ }
+ }
+
+ if (r_consumed)
+ *r_consumed = consumed;
+ gcry_free (plain);
+ gcry_free (cram_buffer);
+ if (r_result)
+ *r_result = result;
+ return 0;
+
+ bailout:
+ if (result)
+ {
+ int i;
+
+ for (i=0; result[i]; i++)
+ gcry_mpi_release (result[i]);
+ gcry_free (result);
+ }
+ if (r_consumed)
+ *r_consumed = consumed;
+ gcry_free (plain);
+ gcry_free (cram_buffer);
+ log_error ("encryptedData error at \"%s\", offset %u\n",
+ where, (unsigned int)((p - p_start)+startoffset));
+ if (bad_pass)
+ {
+ /* Note, that the following string might be used by other programs
+ to check for a bad passphrase; it should therefore not be
+ translated or changed. */
+ log_error ("possibly bad passphrase given\n");
+ }
+ return -1;
+}
+
+
+/* Return true if the decryption of a bag_data object has likely
+ succeeded. */
+static int
+bag_data_p (const void *plaintext, size_t length)
+{
+ struct tag_info ti;
+ const unsigned char *p = plaintext;
+ size_t n = length;
+
+/* { */
+/* # warning debug code is enabled */
+/* FILE *fp = fopen ("tmp-3des-plain-key.der", "wb"); */
+/* if (!fp || fwrite (p, n, 1, fp) != 1) */
+/* exit (2); */
+/* fclose (fp); */
+/* } */
+
+ if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
+ return 0;
+ if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER
+ || ti.length != 1 || *p)
+ return 0;
+
+ return 1;
+}
+
+
+static gcry_mpi_t *
+parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
+ size_t *r_consumed, const char *pw)
+{
+ int rc;
+ struct tag_info ti;
+ const unsigned char *p = buffer;
+ const unsigned char *p_start = buffer;
+ size_t n = length;
+ const char *where;
+ char salt[20];
+ size_t saltlen;
+ unsigned int iter;
+ int len;
+ unsigned char *plain = NULL;
+ gcry_mpi_t *result = NULL;
+ int result_count, i;
+ unsigned char *cram_buffer = NULL;
+ size_t consumed = 0; /* Number of bytes consumed from the orginal buffer. */
+
+ where = "start";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class != ASNCONTEXT || ti.tag)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_OCTET_STRING)
+ goto bailout;
+
+ consumed = p - p_start;
+ if (ti.is_constructed && ti.ndef)
+ {
+ /* Mozilla exported certs now come with single byte chunks of
+ octect strings. (Mozilla Firefox 1.0.4). Arghh. */
+ where = "cram-data.outersegs";
+ cram_buffer = cram_octet_string ( p, &n, &consumed);
+ if (!cram_buffer)
+ goto bailout;
+ p = p_start = cram_buffer;
+ if (r_consumed)
+ *r_consumed = consumed;
+ r_consumed = NULL; /* Ugly hack to not update that value any further. */
+ }
+
+
+ where = "data.outerseqs";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+
+ where = "data.objectidentifier";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_OBJECT_ID
+ || ti.length != DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag)
+ || memcmp (p, oid_pkcs_12_pkcs_8ShroudedKeyBag,
+ DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag)))
+ goto bailout;
+ p += DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag);
+ n -= DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag);
+
+ where = "shrouded,outerseqs";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class != ASNCONTEXT || ti.tag)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_OBJECT_ID
+ || ti.length != DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC)
+ || memcmp (p, oid_pbeWithSHAAnd3_KeyTripleDES_CBC,
+ DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC)))
+ goto bailout;
+ p += DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC);
+ n -= DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC);
+
+ where = "3des-params";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_OCTET_STRING
+ || ti.length < 8 || ti.length > 20)
+ goto bailout;
+ saltlen = ti.length;
+ memcpy (salt, p, saltlen);
+ p += saltlen;
+ n -= saltlen;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_INTEGER || !ti.length )
+ goto bailout;
+ for (iter=0; ti.length; ti.length--)
+ {
+ iter <<= 8;
+ iter |= (*p++) & 0xff;
+ n--;
+ }
+
+ where = "3des-ciphertext";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_OCTET_STRING || !ti.length )
+ goto bailout;
+
+ log_info ("%lu bytes of 3DES encrypted text\n", ti.length);
+
+ plain = gcry_malloc_secure (ti.length);
+ if (!plain)
+ {
+ log_error ("error allocating decryption buffer\n");
+ goto bailout;
+ }
+ consumed += p - p_start + ti.length;
+ decrypt_block (p, plain, ti.length, salt, saltlen, iter, pw,
+ GCRY_CIPHER_3DES,
+ bag_data_p);
+ n = ti.length;
+ startoffset = 0;
+ p_start = p = plain;
+
+ where = "decrypted-text";
+ if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER
+ || ti.length != 1 || *p)
+ goto bailout;
+ p++; n--;
+ if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ len = ti.length;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (len < ti.nhdr)
+ goto bailout;
+ len -= ti.nhdr;
+ if (ti.class || ti.tag != TAG_OBJECT_ID
+ || ti.length != DIM(oid_rsaEncryption)
+ || memcmp (p, oid_rsaEncryption,
+ DIM(oid_rsaEncryption)))
+ goto bailout;
+ p += DIM (oid_rsaEncryption);
+ n -= DIM (oid_rsaEncryption);
+ if (len < ti.length)
+ goto bailout;
+ len -= ti.length;
+ if (n < len)
+ goto bailout;
+ p += len;
+ n -= len;
+ if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_OCTET_STRING)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ len = ti.length;
+
+ result = gcry_calloc (10, sizeof *result);
+ if (!result)
+ {
+ log_error ( "error allocating result array\n");
+ goto bailout;
+ }
+ result_count = 0;
+
+ where = "reading.key-parameters";
+ for (result_count=0; len && result_count < 9;)
+ {
+ if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER)
+ goto bailout;
+ if (len < ti.nhdr)
+ goto bailout;
+ len -= ti.nhdr;
+ if (len < ti.length)
+ goto bailout;
+ len -= ti.length;
+ if (!result_count && ti.length == 1 && !*p)
+ ; /* ignore the very first one if it is a 0 */
+ else
+ {
+ rc = gcry_mpi_scan (result+result_count, GCRYMPI_FMT_USG, p,
+ ti.length, NULL);
+ if (rc)
+ {
+ log_error ("error parsing key parameter: %s\n",
+ gpg_strerror (rc));
+ goto bailout;
+ }
+ result_count++;
+ }
+ p += ti.length;
+ n -= ti.length;
+ }
+ if (len)
+ goto bailout;
+
+ gcry_free (cram_buffer);
+ if (r_consumed)
+ *r_consumed = consumed;
+ return result;
+
+ bailout:
+ gcry_free (plain);
+ if (result)
+ {
+ for (i=0; result[i]; i++)
+ gcry_mpi_release (result[i]);
+ gcry_free (result);
+ }
+ gcry_free (cram_buffer);
+ log_error ( "data error at \"%s\", offset %u\n",
+ where, (unsigned int)((p - buffer) + startoffset));
+ if (r_consumed)
+ *r_consumed = consumed;
+ return NULL;
+}
+
+
+/* Parse a PKCS12 object and return an array of MPI representing the
+ secret key parameters. This is a very limited implementation in
+ that it is only able to look for 3DES encoded encryptedData and
+ tries to extract the first private key object it finds. In case of
+ an error NULL is returned. CERTCB and CERRTCBARG are used to pass
+ X.509 certificates back to the caller. */
+gcry_mpi_t *
+p12_parse (const unsigned char *buffer, size_t length, const char *pw,
+ void (*certcb)(void*, const unsigned char*, size_t),
+ void *certcbarg)
+{
+ struct tag_info ti;
+ const unsigned char *p = buffer;
+ const unsigned char *p_start = buffer;
+ size_t n = length;
+ const char *where;
+ int bagseqlength, len;
+ int bagseqndef, lenndef;
+ gcry_mpi_t *result = NULL;
+ unsigned char *cram_buffer = NULL;
+
+ where = "pfx";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.tag != TAG_SEQUENCE)
+ goto bailout;
+
+ where = "pfxVersion";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.tag != TAG_INTEGER || ti.length != 1 || *p != 3)
+ goto bailout;
+ p++; n--;
+
+ where = "authSave";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.tag != TAG_OBJECT_ID || ti.length != DIM(oid_data)
+ || memcmp (p, oid_data, DIM(oid_data)))
+ goto bailout;
+ p += DIM(oid_data);
+ n -= DIM(oid_data);
+
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class != ASNCONTEXT || ti.tag)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class != UNIVERSAL || ti.tag != TAG_OCTET_STRING)
+ goto bailout;
+
+ if (ti.is_constructed && ti.ndef)
+ {
+ /* Mozilla exported certs now come with single byte chunks of
+ octect strings. (Mozilla Firefox 1.0.4). Arghh. */
+ where = "cram-bags";
+ cram_buffer = cram_octet_string ( p, &n, NULL);
+ if (!cram_buffer)
+ goto bailout;
+ p = p_start = cram_buffer;
+ }
+
+ where = "bags";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class != UNIVERSAL || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ bagseqndef = ti.ndef;
+ bagseqlength = ti.length;
+ while (bagseqlength || bagseqndef)
+ {
+/* log_debug ( "at offset %u\n", (p - p_start)); */
+ where = "bag-sequence";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (bagseqndef && ti.class == UNIVERSAL && !ti.tag && !ti.is_constructed)
+ break; /* Ready */
+ if (ti.class != UNIVERSAL || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+
+ if (!bagseqndef)
+ {
+ if (bagseqlength < ti.nhdr)
+ goto bailout;
+ bagseqlength -= ti.nhdr;
+ if (bagseqlength < ti.length)
+ goto bailout;
+ bagseqlength -= ti.length;
+ }
+ lenndef = ti.ndef;
+ len = ti.length;
+
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (lenndef)
+ len = ti.nhdr;
+ else
+ len -= ti.nhdr;
+
+ if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_encryptedData)
+ && !memcmp (p, oid_encryptedData, DIM(oid_encryptedData)))
+ {
+ size_t consumed = 0;
+
+ p += DIM(oid_encryptedData);
+ n -= DIM(oid_encryptedData);
+ if (!lenndef)
+ len -= DIM(oid_encryptedData);
+ where = "bag.encryptedData";
+ if (parse_bag_encrypted_data (p, n, (p - p_start), &consumed, pw,
+ certcb, certcbarg,
+ result? NULL : &result))
+ goto bailout;
+ if (lenndef)
+ len += consumed;
+ }
+ else if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_data)
+ && !memcmp (p, oid_data, DIM(oid_data)))
+ {
+ if (result)
+ {
+ log_info ("already got an key object, skipping this one\n");
+ p += ti.length;
+ n -= ti.length;
+ }
+ else
+ {
+ size_t consumed = 0;
+
+ p += DIM(oid_data);
+ n -= DIM(oid_data);
+ if (!lenndef)
+ len -= DIM(oid_data);
+ result = parse_bag_data (p, n, (p - p_start), &consumed, pw);
+ if (!result)
+ goto bailout;
+ if (lenndef)
+ len += consumed;
+ }
+ }
+ else
+ {
+ log_info ("unknown bag type - skipped\n");
+ p += ti.length;
+ n -= ti.length;
+ }
+
+ if (len < 0 || len > n)
+ goto bailout;
+ p += len;
+ n -= len;
+ if (lenndef)
+ {
+ /* Need to skip the Null Tag. */
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (!(ti.class == UNIVERSAL && !ti.tag && !ti.is_constructed))
+ goto bailout;
+ }
+ }
+
+ gcry_free (cram_buffer);
+ return result;
+ bailout:
+ log_error ("error at \"%s\", offset %u\n",
+ where, (unsigned int)(p - p_start));
+ if (result)
+ {
+ int i;
+
+ for (i=0; result[i]; i++)
+ gcry_mpi_release (result[i]);
+ gcry_free (result);
+ }
+ gcry_free (cram_buffer);
+ return NULL;
+}
+
+
+
+static size_t
+compute_tag_length (size_t n)
+{
+ int needed = 0;
+
+ if (n < 128)
+ needed += 2; /* tag and one length byte */
+ else if (n < 256)
+ needed += 3; /* tag, number of length bytes, 1 length byte */
+ else if (n < 65536)
+ needed += 4; /* tag, number of length bytes, 2 length bytes */
+ else
+ {
+ log_error ("object too larger to encode\n");
+ return 0;
+ }
+ return needed;
+}
+
+static unsigned char *
+store_tag_length (unsigned char *p, int tag, size_t n)
+{
+ if (tag == TAG_SEQUENCE)
+ tag |= 0x20; /* constructed */
+
+ *p++ = tag;
+ if (n < 128)
+ *p++ = n;
+ else if (n < 256)
+ {
+ *p++ = 0x81;
+ *p++ = n;
+ }
+ else if (n < 65536)
+ {
+ *p++ = 0x82;
+ *p++ = n >> 8;
+ *p++ = n;
+ }
+
+ return p;
+}
+
+
+/* Create the final PKCS-12 object from the sequences contained in
+ SEQLIST. PW is the password. That array is terminated with an NULL
+ object. */
+static unsigned char *
+create_final (struct buffer_s *sequences, const char *pw, size_t *r_length)
+{
+ int i;
+ size_t needed = 0;
+ size_t len[8], n;
+ unsigned char *macstart;
+ size_t maclen;
+ unsigned char *result, *p;
+ size_t resultlen;
+ char salt[8];
+ unsigned char keybuf[20];
+ gcry_md_hd_t md;
+ int rc;
+ int with_mac = 1;
+
+
+ /* 9 steps to create the pkcs#12 Krampf. */
+
+ /* 8. The MAC. */
+ /* We add this at step 0. */
+
+ /* 7. All the buffers. */
+ for (i=0; sequences[i].buffer; i++)
+ needed += sequences[i].length;
+
+ /* 6. This goes into a sequences. */
+ len[6] = needed;
+ n = compute_tag_length (needed);
+ needed += n;
+
+ /* 5. Encapsulate all in an octet string. */
+ len[5] = needed;
+ n = compute_tag_length (needed);
+ needed += n;
+
+ /* 4. And tag it with [0]. */
+ len[4] = needed;
+ n = compute_tag_length (needed);
+ needed += n;
+
+ /* 3. Prepend an data OID. */
+ needed += 2 + DIM (oid_data);
+
+ /* 2. Put all into a sequences. */
+ len[2] = needed;
+ n = compute_tag_length (needed);
+ needed += n;
+
+ /* 1. Prepend the version integer 3. */
+ needed += 3;
+
+ /* 0. And the final outer sequence. */
+ if (with_mac)
+ needed += DIM (data_mactemplate);
+ len[0] = needed;
+ n = compute_tag_length (needed);
+ needed += n;
+
+ /* Allocate a buffer. */
+ result = gcry_malloc (needed);
+ if (!result)
+ {
+ log_error ("error allocating buffer\n");
+ return NULL;
+ }
+ p = result;
+
+ /* 0. Store the very outer sequence. */
+ p = store_tag_length (p, TAG_SEQUENCE, len[0]);
+
+ /* 1. Store the version integer 3. */
+ *p++ = TAG_INTEGER;
+ *p++ = 1;
+ *p++ = 3;
+
+ /* 2. Store another sequence. */
+ p = store_tag_length (p, TAG_SEQUENCE, len[2]);
+
+ /* 3. Store the data OID. */
+ p = store_tag_length (p, TAG_OBJECT_ID, DIM (oid_data));
+ memcpy (p, oid_data, DIM (oid_data));
+ p += DIM (oid_data);
+
+ /* 4. Next comes a context tag. */
+ p = store_tag_length (p, 0xa0, len[4]);
+
+ /* 5. And an octet string. */
+ p = store_tag_length (p, TAG_OCTET_STRING, len[5]);
+
+ /* 6. And the inner sequence. */
+ macstart = p;
+ p = store_tag_length (p, TAG_SEQUENCE, len[6]);
+
+ /* 7. Append all the buffers. */
+ for (i=0; sequences[i].buffer; i++)
+ {
+ memcpy (p, sequences[i].buffer, sequences[i].length);
+ p += sequences[i].length;
+ }
+
+ if (with_mac)
+ {
+ /* Intermezzo to compute the MAC. */
+ maclen = p - macstart;
+ gcry_randomize (salt, 8, GCRY_STRONG_RANDOM);
+ if (string_to_key (3, salt, 8, 2048, pw, 20, keybuf))
+ {
+ gcry_free (result);
+ return NULL;
+ }
+ rc = gcry_md_open (&md, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
+ if (rc)
+ {
+ log_error ("gcry_md_open failed: %s\n", gpg_strerror (rc));
+ gcry_free (result);
+ return NULL;
+ }
+ rc = gcry_md_setkey (md, keybuf, 20);
+ if (rc)
+ {
+ log_error ("gcry_md_setkey failed: %s\n", gpg_strerror (rc));
+ gcry_md_close (md);
+ gcry_free (result);
+ return NULL;
+ }
+ gcry_md_write (md, macstart, maclen);
+
+ /* 8. Append the MAC template and fix it up. */
+ memcpy (p, data_mactemplate, DIM (data_mactemplate));
+ memcpy (p + DATA_MACTEMPLATE_SALT_OFF, salt, 8);
+ memcpy (p + DATA_MACTEMPLATE_MAC_OFF, gcry_md_read (md, 0), 20);
+ p += DIM (data_mactemplate);
+ gcry_md_close (md);
+ }
+
+ /* Ready. */
+ resultlen = p - result;
+ if (needed != resultlen)
+ log_debug ("length mismatch: %lu, %lu\n",
+ (unsigned long)needed, (unsigned long)resultlen);
+
+ *r_length = resultlen;
+ return result;
+}
+
+
+/* Build a DER encoded SEQUENCE with the key:
+
+ SEQUENCE {
+ INTEGER 0
+ SEQUENCE {
+ OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
+ NULL
+ }
+ OCTET STRING, encapsulates {
+ SEQUENCE {
+ INTEGER 0
+ INTEGER
+ INTEGER
+ INTEGER
+ INTEGER
+ INTEGER
+ INTEGER
+ INTEGER
+ INTEGER
+ }
+ }
+ }
+*/
+
+static unsigned char *
+build_key_sequence (gcry_mpi_t *kparms, size_t *r_length)
+{
+ int rc, i;
+ size_t needed, n;
+ unsigned char *plain, *p;
+ size_t plainlen;
+ size_t outseqlen, oidseqlen, octstrlen, inseqlen;
+
+ needed = 3; /* The version(?) integer of value 0. */
+ for (i=0; kparms[i]; i++)
+ {
+ n = 0;
+ rc = gcry_mpi_print (GCRYMPI_FMT_STD, NULL, 0, &n, kparms[i]);
+ if (rc)
+ {
+ log_error ("error formatting parameter: %s\n", gpg_strerror (rc));
+ return NULL;
+ }
+ needed += n;
+ n = compute_tag_length (n);
+ if (!n)
+ return NULL;
+ needed += n;
+ }
+ if (i != 8)
+ {
+ log_error ("invalid parameters for p12_build\n");
+ return NULL;
+ }
+ /* Now this all goes into a sequence. */
+ inseqlen = needed;
+ n = compute_tag_length (needed);
+ if (!n)
+ return NULL;
+ needed += n;
+ /* Encapsulate all into an octet string. */
+ octstrlen = needed;
+ n = compute_tag_length (needed);
+ if (!n)
+ return NULL;
+ needed += n;
+ /* Prepend the object identifier sequence. */
+ oidseqlen = 2 + DIM (oid_rsaEncryption) + 2;
+ needed += 2 + oidseqlen;
+ /* The version number. */
+ needed += 3;
+ /* And finally put the whole thing into a sequence. */
+ outseqlen = needed;
+ n = compute_tag_length (needed);
+ if (!n)
+ return NULL;
+ needed += n;
+
+ /* allocate 8 extra bytes for padding */
+ plain = gcry_malloc_secure (needed+8);
+ if (!plain)
+ {
+ log_error ("error allocating encryption buffer\n");
+ return NULL;
+ }
+
+ /* And now fill the plaintext buffer. */
+ p = plain;
+ p = store_tag_length (p, TAG_SEQUENCE, outseqlen);
+ /* Store version. */
+ *p++ = TAG_INTEGER;
+ *p++ = 1;
+ *p++ = 0;
+ /* Store object identifier sequence. */
+ p = store_tag_length (p, TAG_SEQUENCE, oidseqlen);
+ p = store_tag_length (p, TAG_OBJECT_ID, DIM (oid_rsaEncryption));
+ memcpy (p, oid_rsaEncryption, DIM (oid_rsaEncryption));
+ p += DIM (oid_rsaEncryption);
+ *p++ = TAG_NULL;
+ *p++ = 0;
+ /* Start with the octet string. */
+ p = store_tag_length (p, TAG_OCTET_STRING, octstrlen);
+ p = store_tag_length (p, TAG_SEQUENCE, inseqlen);
+ /* Store the key parameters. */
+ *p++ = TAG_INTEGER;
+ *p++ = 1;
+ *p++ = 0;
+ for (i=0; kparms[i]; i++)
+ {
+ n = 0;
+ rc = gcry_mpi_print (GCRYMPI_FMT_STD, NULL, 0, &n, kparms[i]);
+ if (rc)
+ {
+ log_error ("oops: error formatting parameter: %s\n",
+ gpg_strerror (rc));
+ gcry_free (plain);
+ return NULL;
+ }
+ p = store_tag_length (p, TAG_INTEGER, n);
+
+ n = plain + needed - p;
+ rc = gcry_mpi_print (GCRYMPI_FMT_STD, p, n, &n, kparms[i]);
+ if (rc)
+ {
+ log_error ("oops: error storing parameter: %s\n",
+ gpg_strerror (rc));
+ gcry_free (plain);
+ return NULL;
+ }
+ p += n;
+ }
+
+ plainlen = p - plain;
+ assert (needed == plainlen);
+ /* Append some pad characters; we already allocated extra space. */
+ n = 8 - plainlen % 8;
+ for (i=0; i < n; i++, plainlen++)
+ *p++ = n;
+
+ *r_length = plainlen;
+ return plain;
+}
+
+
+
+static unsigned char *
+build_key_bag (unsigned char *buffer, size_t buflen, char *salt,
+ const unsigned char *sha1hash, const char *keyidstr,
+ size_t *r_length)
+{
+ size_t len[11], needed;
+ unsigned char *p, *keybag;
+ size_t keybaglen;
+
+ /* Walk 11 steps down to collect the info: */
+
+ /* 10. The data goes into an octet string. */
+ needed = compute_tag_length (buflen);
+ needed += buflen;
+
+ /* 9. Prepend the algorithm identifier. */
+ needed += DIM (data_3desiter2048);
+
+ /* 8. Put a sequence around. */
+ len[8] = needed;
+ needed += compute_tag_length (needed);
+
+ /* 7. Prepend a [0] tag. */
+ len[7] = needed;
+ needed += compute_tag_length (needed);
+
+ /* 6b. The attributes which are appended at the end. */
+ if (sha1hash)
+ needed += DIM (data_attrtemplate) + 20;
+
+ /* 6. Prepend the shroudedKeyBag OID. */
+ needed += 2 + DIM (oid_pkcs_12_pkcs_8ShroudedKeyBag);
+
+ /* 5+4. Put all into two sequences. */
+ len[5] = needed;
+ needed += compute_tag_length ( needed);
+ len[4] = needed;
+ needed += compute_tag_length (needed);
+
+ /* 3. This all goes into an octet string. */
+ len[3] = needed;
+ needed += compute_tag_length (needed);
+
+ /* 2. Prepend another [0] tag. */
+ len[2] = needed;
+ needed += compute_tag_length (needed);
+
+ /* 1. Prepend the data OID. */
+ needed += 2 + DIM (oid_data);
+
+ /* 0. Prepend another sequence. */
+ len[0] = needed;
+ needed += compute_tag_length (needed);
+
+ /* Now that we have all length information, allocate a buffer. */
+ p = keybag = gcry_malloc (needed);
+ if (!keybag)
+ {
+ log_error ("error allocating buffer\n");
+ return NULL;
+ }
+
+ /* Walk 11 steps up to store the data. */
+
+ /* 0. Store the first sequence. */
+ p = store_tag_length (p, TAG_SEQUENCE, len[0]);
+
+ /* 1. Store the data OID. */
+ p = store_tag_length (p, TAG_OBJECT_ID, DIM (oid_data));
+ memcpy (p, oid_data, DIM (oid_data));
+ p += DIM (oid_data);
+
+ /* 2. Store a [0] tag. */
+ p = store_tag_length (p, 0xa0, len[2]);
+
+ /* 3. And an octet string. */
+ p = store_tag_length (p, TAG_OCTET_STRING, len[3]);
+
+ /* 4+5. Two sequences. */
+ p = store_tag_length (p, TAG_SEQUENCE, len[4]);
+ p = store_tag_length (p, TAG_SEQUENCE, len[5]);
+
+ /* 6. Store the shroudedKeyBag OID. */
+ p = store_tag_length (p, TAG_OBJECT_ID,
+ DIM (oid_pkcs_12_pkcs_8ShroudedKeyBag));
+ memcpy (p, oid_pkcs_12_pkcs_8ShroudedKeyBag,
+ DIM (oid_pkcs_12_pkcs_8ShroudedKeyBag));
+ p += DIM (oid_pkcs_12_pkcs_8ShroudedKeyBag);
+
+ /* 7. Store a [0] tag. */
+ p = store_tag_length (p, 0xa0, len[7]);
+
+ /* 8. Store a sequence. */
+ p = store_tag_length (p, TAG_SEQUENCE, len[8]);
+
+ /* 9. Now for the pre-encoded algorithm identifier and the salt. */
+ memcpy (p, data_3desiter2048, DIM (data_3desiter2048));
+ memcpy (p + DATA_3DESITER2048_SALT_OFF, salt, 8);
+ p += DIM (data_3desiter2048);
+
+ /* 10. And the octet string with the encrypted data. */
+ p = store_tag_length (p, TAG_OCTET_STRING, buflen);
+ memcpy (p, buffer, buflen);
+ p += buflen;
+
+ /* Append the attributes whose length we calculated at step 2b. */
+ if (sha1hash)
+ {
+ int i;
+
+ memcpy (p, data_attrtemplate, DIM (data_attrtemplate));
+ for (i=0; i < 8; i++)
+ p[DATA_ATTRTEMPLATE_KEYID_OFF+2*i+1] = keyidstr[i];
+ p += DIM (data_attrtemplate);
+ memcpy (p, sha1hash, 20);
+ p += 20;
+ }
+
+
+ keybaglen = p - keybag;
+ if (needed != keybaglen)
+ log_debug ("length mismatch: %lu, %lu\n",
+ (unsigned long)needed, (unsigned long)keybaglen);
+
+ *r_length = keybaglen;
+ return keybag;
+}
+
+
+static unsigned char *
+build_cert_bag (unsigned char *buffer, size_t buflen, char *salt,
+ size_t *r_length)
+{
+ size_t len[9], needed;
+ unsigned char *p, *certbag;
+ size_t certbaglen;
+
+ /* Walk 9 steps down to collect the info: */
+
+ /* 8. The data goes into an octet string. */
+ needed = compute_tag_length (buflen);
+ needed += buflen;
+
+ /* 7. The algorithm identifier. */
+ needed += DIM (data_rc2iter2048);
+
+ /* 6. The data OID. */
+ needed += 2 + DIM (oid_data);
+
+ /* 5. A sequence. */
+ len[5] = needed;
+ needed += compute_tag_length ( needed);
+
+ /* 4. An integer. */
+ needed += 3;
+
+ /* 3. A sequence. */
+ len[3] = needed;
+ needed += compute_tag_length (needed);
+
+ /* 2. A [0] tag. */
+ len[2] = needed;
+ needed += compute_tag_length (needed);
+
+ /* 1. The encryptedData OID. */
+ needed += 2 + DIM (oid_encryptedData);
+
+ /* 0. The first sequence. */
+ len[0] = needed;
+ needed += compute_tag_length (needed);
+
+ /* Now that we have all length information, allocate a buffer. */
+ p = certbag = gcry_malloc (needed);
+ if (!certbag)
+ {
+ log_error ("error allocating buffer\n");
+ return NULL;
+ }
+
+ /* Walk 9 steps up to store the data. */
+
+ /* 0. Store the first sequence. */
+ p = store_tag_length (p, TAG_SEQUENCE, len[0]);
+
+ /* 1. Store the encryptedData OID. */
+ p = store_tag_length (p, TAG_OBJECT_ID, DIM (oid_encryptedData));
+ memcpy (p, oid_encryptedData, DIM (oid_encryptedData));
+ p += DIM (oid_encryptedData);
+
+ /* 2. Store a [0] tag. */
+ p = store_tag_length (p, 0xa0, len[2]);
+
+ /* 3. Store a sequence. */
+ p = store_tag_length (p, TAG_SEQUENCE, len[3]);
+
+ /* 4. Store the integer 0. */
+ *p++ = TAG_INTEGER;
+ *p++ = 1;
+ *p++ = 0;
+
+ /* 5. Store a sequence. */
+ p = store_tag_length (p, TAG_SEQUENCE, len[5]);
+
+ /* 6. Store the data OID. */
+ p = store_tag_length (p, TAG_OBJECT_ID, DIM (oid_data));
+ memcpy (p, oid_data, DIM (oid_data));
+ p += DIM (oid_data);
+
+ /* 7. Now for the pre-encoded algorithm identifier and the salt. */
+ memcpy (p, data_rc2iter2048, DIM (data_rc2iter2048));
+ memcpy (p + DATA_RC2ITER2048_SALT_OFF, salt, 8);
+ p += DIM (data_rc2iter2048);
+
+ /* 8. And finally the [0] tag with the encrypted data. */
+ p = store_tag_length (p, 0x80, buflen);
+ memcpy (p, buffer, buflen);
+ p += buflen;
+ certbaglen = p - certbag;
+
+ if (needed != certbaglen)
+ log_debug ("length mismatch: %lu, %lu\n",
+ (unsigned long)needed, (unsigned long)certbaglen);
+
+ *r_length = certbaglen;
+ return certbag;
+}
+
+
+static unsigned char *
+build_cert_sequence (unsigned char *buffer, size_t buflen,
+ const unsigned char *sha1hash, const char *keyidstr,
+ size_t *r_length)
+{
+ size_t len[8], needed, n;
+ unsigned char *p, *certseq;
+ size_t certseqlen;
+ int i;
+
+ assert (strlen (keyidstr) == 8);
+
+ /* Walk 8 steps down to collect the info: */
+
+ /* 7. The data goes into an octet string. */
+ needed = compute_tag_length (buflen);
+ needed += buflen;
+
+ /* 6. A [0] tag. */
+ len[6] = needed;
+ needed += compute_tag_length (needed);
+
+ /* 5. An OID. */
+ needed += 2 + DIM (oid_x509Certificate_for_pkcs_12);
+
+ /* 4. A sequence. */
+ len[4] = needed;
+ needed += compute_tag_length (needed);
+
+ /* 3. A [0] tag. */
+ len[3] = needed;
+ needed += compute_tag_length (needed);
+
+ /* 2b. The attributes which are appended at the end. */
+ if (sha1hash)
+ needed += DIM (data_attrtemplate) + 20;
+
+ /* 2. An OID. */
+ needed += 2 + DIM (oid_pkcs_12_CertBag);
+
+ /* 1. A sequence. */
+ len[1] = needed;
+ needed += compute_tag_length (needed);
+
+ /* 0. The first sequence. */
+ len[0] = needed;
+ needed += compute_tag_length (needed);
+
+ /* Now that we have all length information, allocate a buffer. */
+ p = certseq = gcry_malloc (needed + 8 /*(for padding)*/);
+ if (!certseq)
+ {
+ log_error ("error allocating buffer\n");
+ return NULL;
+ }
+
+ /* Walk 8 steps up to store the data. */
+
+ /* 0. Store the first sequence. */
+ p = store_tag_length (p, TAG_SEQUENCE, len[0]);
+
+ /* 1. Store the second sequence. */
+ p = store_tag_length (p, TAG_SEQUENCE, len[1]);
+
+ /* 2. Store the pkcs12-cert-bag OID. */
+ p = store_tag_length (p, TAG_OBJECT_ID, DIM (oid_pkcs_12_CertBag));
+ memcpy (p, oid_pkcs_12_CertBag, DIM (oid_pkcs_12_CertBag));
+ p += DIM (oid_pkcs_12_CertBag);
+
+ /* 3. Store a [0] tag. */
+ p = store_tag_length (p, 0xa0, len[3]);
+
+ /* 4. Store a sequence. */
+ p = store_tag_length (p, TAG_SEQUENCE, len[4]);
+
+ /* 5. Store the x509Certificate OID. */
+ p = store_tag_length (p, TAG_OBJECT_ID,
+ DIM (oid_x509Certificate_for_pkcs_12));
+ memcpy (p, oid_x509Certificate_for_pkcs_12,
+ DIM (oid_x509Certificate_for_pkcs_12));
+ p += DIM (oid_x509Certificate_for_pkcs_12);
+
+ /* 6. Store a [0] tag. */
+ p = store_tag_length (p, 0xa0, len[6]);
+
+ /* 7. And the octet string with the actual certificate. */
+ p = store_tag_length (p, TAG_OCTET_STRING, buflen);
+ memcpy (p, buffer, buflen);
+ p += buflen;
+
+ /* Append the attributes whose length we calculated at step 2b. */
+ if (sha1hash)
+ {
+ memcpy (p, data_attrtemplate, DIM (data_attrtemplate));
+ for (i=0; i < 8; i++)
+ p[DATA_ATTRTEMPLATE_KEYID_OFF+2*i+1] = keyidstr[i];
+ p += DIM (data_attrtemplate);
+ memcpy (p, sha1hash, 20);
+ p += 20;
+ }
+
+ certseqlen = p - certseq;
+ if (needed != certseqlen)
+ log_debug ("length mismatch: %lu, %lu\n",
+ (unsigned long)needed, (unsigned long)certseqlen);
+
+ /* Append some pad characters; we already allocated extra space. */
+ n = 8 - certseqlen % 8;
+ for (i=0; i < n; i++, certseqlen++)
+ *p++ = n;
+
+ *r_length = certseqlen;
+ return certseq;
+}
+
+
+/* Expect the RSA key parameters in KPARMS and a password in PW.
+ Create a PKCS structure from it and return it as well as the length
+ in R_LENGTH; return NULL in case of an error. If CHARSET is not
+ NULL, re-encode PW to that character set. */
+unsigned char *
+p12_build (gcry_mpi_t *kparms, unsigned char *cert, size_t certlen,
+ const char *pw, const char *charset, size_t *r_length)
+{
+ unsigned char *buffer = NULL;
+ size_t n, buflen;
+ char salt[8];
+ struct buffer_s seqlist[3];
+ int seqlistidx = 0;
+ unsigned char sha1hash[20];
+ char keyidstr[8+1];
+ char *pwbuf = NULL;
+ size_t pwbufsize = 0;
+
+ n = buflen = 0; /* (avoid compiler warning). */
+ memset (sha1hash, 0, 20);
+ *keyidstr = 0;
+
+ if (charset && pw && *pw)
+ {
+ jnlib_iconv_t cd;
+ const char *inptr;
+ char *outptr;
+ size_t inbytes, outbytes;
+
+ /* We assume that the converted passphrase is at max 2 times
+ longer than its utf-8 encoding. */
+ pwbufsize = strlen (pw)*2 + 1;
+ pwbuf = gcry_malloc_secure (pwbufsize);
+ if (!pwbuf)
+ {
+ log_error ("out of secure memory while converting passphrase\n");
+ goto failure;
+ }
+
+ cd = jnlib_iconv_open (charset, "utf-8");
+ if (cd == (jnlib_iconv_t)(-1))
+ {
+ log_error ("can't convert passphrase to"
+ " requested charset `%s': %s\n",
+ charset, strerror (errno));
+ gcry_free (pwbuf);
+ pwbuf = NULL;
+ goto failure;
+ }
+
+ inptr = pw;
+ inbytes = strlen (pw);
+ outptr = pwbuf;
+ outbytes = pwbufsize - 1;
+ if ( jnlib_iconv (cd, (const char **)&inptr, &inbytes,
+ &outptr, &outbytes) == (size_t)-1)
+ {
+ log_error ("error converting passphrase to"
+ " requested charset `%s': %s\n",
+ charset, strerror (errno));
+ gcry_free (pwbuf);
+ pwbuf = NULL;
+ jnlib_iconv_close (cd);
+ goto failure;
+ }
+ *outptr = 0;
+ jnlib_iconv_close (cd);
+ pw = pwbuf;
+ }
+
+
+ if (cert && certlen)
+ {
+ /* Calculate the hash value we need for the bag attributes. */
+ gcry_md_hash_buffer (GCRY_MD_SHA1, sha1hash, cert, certlen);
+ sprintf (keyidstr, "%02x%02x%02x%02x",
+ sha1hash[16], sha1hash[17], sha1hash[18], sha1hash[19]);
+
+ /* Encode the certificate. */
+ buffer = build_cert_sequence (cert, certlen, sha1hash, keyidstr,
+ &buflen);
+ if (!buffer)
+ goto failure;
+
+ /* Encrypt it. */
+ gcry_randomize (salt, 8, GCRY_STRONG_RANDOM);
+ crypt_block (buffer, buflen, salt, 8, 2048, pw,
+ GCRY_CIPHER_RFC2268_40, 1);
+
+ /* Encode the encrypted stuff into a bag. */
+ seqlist[seqlistidx].buffer = build_cert_bag (buffer, buflen, salt, &n);
+ seqlist[seqlistidx].length = n;
+ gcry_free (buffer);
+ buffer = NULL;
+ if (!seqlist[seqlistidx].buffer)
+ goto failure;
+ seqlistidx++;
+ }
+
+
+ if (kparms)
+ {
+ /* Encode the key. */
+ buffer = build_key_sequence (kparms, &buflen);
+ if (!buffer)
+ goto failure;
+
+ /* Encrypt it. */
+ gcry_randomize (salt, 8, GCRY_STRONG_RANDOM);
+ crypt_block (buffer, buflen, salt, 8, 2048, pw, GCRY_CIPHER_3DES, 1);
+
+ /* Encode the encrypted stuff into a bag. */
+ if (cert && certlen)
+ seqlist[seqlistidx].buffer = build_key_bag (buffer, buflen, salt,
+ sha1hash, keyidstr, &n);
+ else
+ seqlist[seqlistidx].buffer = build_key_bag (buffer, buflen, salt,
+ NULL, NULL, &n);
+ seqlist[seqlistidx].length = n;
+ gcry_free (buffer);
+ buffer = NULL;
+ if (!seqlist[seqlistidx].buffer)
+ goto failure;
+ seqlistidx++;
+ }
+
+ seqlist[seqlistidx].buffer = NULL;
+ seqlist[seqlistidx].length = 0;
+
+ buffer = create_final (seqlist, pw, &buflen);
+
+ failure:
+ if (pwbuf)
+ {
+ wipememory (pwbuf, pwbufsize);
+ gcry_free (pwbuf);
+ }
+ for ( ; seqlistidx; seqlistidx--)
+ gcry_free (seqlist[seqlistidx].buffer);
+
+ *r_length = buffer? buflen : 0;
+ return buffer;
+}
+
+
+#ifdef TEST
+
+static void
+cert_cb (void *opaque, const unsigned char *cert, size_t certlen)
+{
+ printf ("got a certificate of %u bytes length\n", certlen);
+}
+
+int
+main (int argc, char **argv)
+{
+ FILE *fp;
+ struct stat st;
+ unsigned char *buf;
+ size_t buflen;
+ gcry_mpi_t *result;
+
+ if (argc != 3)
+ {
+ fprintf (stderr, "usage: testp12 file passphrase\n");
+ return 1;
+ }
+
+ gcry_control (GCRYCTL_DISABLE_SECMEM, NULL);
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, NULL);
+
+ fp = fopen (argv[1], "rb");
+ if (!fp)
+ {
+ fprintf (stderr, "can't open `%s': %s\n", argv[1], strerror (errno));
+ return 1;
+ }
+
+ if (fstat (fileno(fp), &st))
+ {
+ fprintf (stderr, "can't stat `%s': %s\n", argv[1], strerror (errno));
+ return 1;
+ }
+
+ buflen = st.st_size;
+ buf = gcry_malloc (buflen+1);
+ if (!buf || fread (buf, buflen, 1, fp) != 1)
+ {
+ fprintf (stderr, "error reading `%s': %s\n", argv[1], strerror (errno));
+ return 1;
+ }
+ fclose (fp);
+
+ result = p12_parse (buf, buflen, argv[2], cert_cb, NULL);
+ if (result)
+ {
+ int i, rc;
+ unsigned char *tmpbuf;
+
+ for (i=0; result[i]; i++)
+ {
+ rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, &tmpbuf,
+ NULL, result[i]);
+ if (rc)
+ printf ("%d: [error printing number: %s]\n",
+ i, gpg_strerror (rc));
+ else
+ {
+ printf ("%d: %s\n", i, tmpbuf);
+ gcry_free (tmpbuf);
+ }
+ }
+ }
+
+ return 0;
+
+}
+
+/*
+Local Variables:
+compile-command: "gcc -Wall -O0 -g -DTEST=1 -o minip12 minip12.c ../jnlib/libjnlib.a -L /usr/local/lib -lgcrypt -lgpg-error"
+End:
+*/
+#endif /* TEST */
diff -Nru gnupg2-2.1.6~build1/agent/minip12.h gnupg2-2.0.28/agent/minip12.h
--- gnupg2-2.1.6~build1/agent/minip12.h 1970-01-01 00:00:00.000000000 +0000
+++ gnupg2-2.0.28/agent/minip12.h 2015-06-02 08:13:55.000000000 +0000
@@ -0,0 +1,36 @@
+/* minip12.h - Global definitions for the minimal pkcs-12 implementation.
+ * Copyright (C) 2002, 2003 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 .
+ */
+
+#ifndef MINIP12_H
+#define MINIP12_H
+
+#include
+
+gcry_mpi_t *p12_parse (const unsigned char *buffer, size_t length,
+ const char *pw,
+ void (*certcb)(void*, const unsigned char*, size_t),
+ void *certcbarg);
+
+unsigned char *p12_build (gcry_mpi_t *kparms,
+ unsigned char *cert, size_t certlen,
+ const char *pw, const char *charset,
+ size_t *r_length);
+
+
+#endif /*MINIP12_H*/
diff -Nru gnupg2-2.1.6~build1/agent/pkdecrypt.c gnupg2-2.0.28/agent/pkdecrypt.c
--- gnupg2-2.1.6~build1/agent/pkdecrypt.c 2015-06-17 06:39:24.000000000 +0000
+++ gnupg2-2.0.28/agent/pkdecrypt.c 2015-06-02 08:13:55.000000000 +0000
@@ -32,12 +32,11 @@
/* DECRYPT the stuff in ciphertext which is expected to be a S-Exp.
Try to get the key from CTRL and write the decoded stuff back to
- OUTFP. The padding information is stored at R_PADDING with -1
- for not known. */
+ OUTFP. */
int
agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
const unsigned char *ciphertext, size_t ciphertextlen,
- membuf_t *outbuf, int *r_padding)
+ membuf_t *outbuf)
{
gcry_sexp_t s_skey = NULL, s_cipher = NULL, s_plain = NULL;
unsigned char *shadow_info = NULL;
@@ -45,8 +44,6 @@
char *buf = NULL;
size_t len;
- *r_padding = -1;
-
if (!ctrl->have_keygrip)
{
log_error ("speculative decryption not yet supported\n");
@@ -67,17 +64,19 @@
log_printhex ("keygrip:", ctrl->keygrip, 20);
log_printhex ("cipher: ", ciphertext, ciphertextlen);
}
- rc = agent_key_from_file (ctrl, NULL, desc_text,
+ rc = agent_key_from_file (ctrl, desc_text,
ctrl->keygrip, &shadow_info,
- CACHE_MODE_NORMAL, NULL, &s_skey, NULL);
+ CACHE_MODE_NORMAL, NULL, &s_skey);
if (rc)
{
- if (gpg_err_code (rc) != GPG_ERR_NO_SECKEY)
+ if (gpg_err_code (rc) == GPG_ERR_ENOENT)
+ rc = gpg_error (GPG_ERR_NO_SECKEY);
+ else
log_error ("failed to read the secret key\n");
goto leave;
}
- if (shadow_info)
+ if (!s_skey)
{ /* divert operation to the smartcard */
if (!gcry_sexp_canon_len (ciphertext, ciphertextlen, NULL, NULL))
@@ -86,17 +85,21 @@
goto leave;
}
- rc = divert_pkdecrypt (ctrl, ciphertext, shadow_info,
- &buf, &len, r_padding);
+ rc = divert_pkdecrypt (ctrl, ciphertext, shadow_info, &buf, &len );
if (rc)
{
log_error ("smartcard decryption failed: %s\n", gpg_strerror (rc));
goto leave;
}
- put_membuf_printf (outbuf, "(5:value%u:", (unsigned int)len);
- put_membuf (outbuf, buf, len);
- put_membuf (outbuf, ")", 2);
+ {
+ char tmpbuf[60];
+
+ sprintf (tmpbuf, "(5:value%u:", (unsigned int)len);
+ put_membuf (outbuf, tmpbuf, strlen (tmpbuf));
+ put_membuf (outbuf, buf, len);
+ put_membuf (outbuf, ")", 2);
+ }
}
else
{ /* No smartcard, but a private key */
@@ -133,7 +136,7 @@
put_membuf (outbuf, buf, len);
put_membuf (outbuf, ")", 2);
}
- }
+ }
leave:
@@ -144,3 +147,5 @@
xfree (shadow_info);
return rc;
}
+
+
diff -Nru gnupg2-2.1.6~build1/agent/pksign.c gnupg2-2.0.28/agent/pksign.c
--- gnupg2-2.1.6~build1/agent/pksign.c 2015-06-17 06:39:24.000000000 +0000
+++ gnupg2-2.0.28/agent/pksign.c 2015-06-02 08:13:55.000000000 +0000
@@ -1,6 +1,5 @@
/* pksign.c - public key signing (well, actually using a secret key)
- * Copyright (C) 2001-2004, 2010 Free Software Foundation, Inc.
- * Copyright (C) 2001-2004, 2010, 2013 Werner Koch
+ * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -29,7 +28,6 @@
#include
#include "agent.h"
-#include "i18n.h"
static int
@@ -44,13 +42,13 @@
const char *s;
char tmp[16+1];
int i;
-
+
s = gcry_md_algo_name (algo);
if (s && strlen (s) < 16)
{
for (i=0; i < strlen (s); i++)
tmp[i] = tolower (s[i]);
- tmp[i] = '\0';
+ tmp[i] = '\0';
}
rc = gcry_sexp_build (&hash, NULL,
@@ -60,168 +58,20 @@
else
{
gcry_mpi_t mpi;
-
+
rc = gcry_mpi_scan (&mpi, GCRYMPI_FMT_USG, md, mdlen, NULL);
- if (!rc)
+ if (! rc)
{
rc = gcry_sexp_build (&hash, NULL,
"(data (flags raw) (value %m))",
mpi);
gcry_mpi_release (mpi);
}
- else
- hash = NULL;
-
+
}
-
+
*r_hash = hash;
- return rc;
-}
-
-
-/* Return the number of bits of the Q parameter from the DSA key
- KEY. */
-static unsigned int
-get_dsa_qbits (gcry_sexp_t key)
-{
- gcry_sexp_t l1, l2;
- gcry_mpi_t q;
- unsigned int nbits;
-
- l1 = gcry_sexp_find_token (key, "private-key", 0);
- if (!l1)
- l1 = gcry_sexp_find_token (key, "protected-private-key", 0);
- if (!l1)
- l1 = gcry_sexp_find_token (key, "shadowed-private-key", 0);
- if (!l1)
- l1 = gcry_sexp_find_token (key, "public-key", 0);
- if (!l1)
- return 0; /* Does not contain a key object. */
- l2 = gcry_sexp_cadr (l1);
- gcry_sexp_release (l1);
- l1 = gcry_sexp_find_token (l2, "q", 1);
- gcry_sexp_release (l2);
- if (!l1)
- return 0; /* Invalid object. */
- q = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
- gcry_sexp_release (l1);
- if (!q)
- return 0; /* Missing value. */
- nbits = gcry_mpi_get_nbits (q);
- gcry_mpi_release (q);
-
- return nbits;
-}
-
-
-/* Return an appropriate hash algorithm to be used with RFC-6979 for a
- message digest of length MDLEN. Although a fallback of SHA-256 is
- used the current implementation in Libgcrypt will reject a hash
- algorithm which does not match the length of the message. */
-static const char *
-rfc6979_hash_algo_string (size_t mdlen)
-{
- switch (mdlen)
- {
- case 20: return "sha1";
- case 28: return "sha224";
- case 32: return "sha256";
- case 48: return "sha384";
- case 64: return "sha512";
- default: return "sha256";
- }
-}
-
-
-/* Encode a message digest for use with the EdDSA algorithm
- (i.e. curve Ed25519). */
-static gpg_error_t
-do_encode_eddsa (const byte *md, size_t mdlen, gcry_sexp_t *r_hash)
-{
- gpg_error_t err;
- gcry_sexp_t hash;
-
- *r_hash = NULL;
- err = gcry_sexp_build (&hash, NULL,
- "(data(flags eddsa)(hash-algo sha512)(value %b))",
- (int)mdlen, md);
- if (!err)
- *r_hash = hash;
- return err;
-}
-
-
-/* Encode a message digest for use with an DSA algorithm. */
-static gpg_error_t
-do_encode_dsa (const byte *md, size_t mdlen, int pkalgo, gcry_sexp_t pkey,
- gcry_sexp_t *r_hash)
-{
- gpg_error_t err;
- gcry_sexp_t hash;
- unsigned int qbits;
-
- *r_hash = NULL;
-
- if (pkalgo == GCRY_PK_ECDSA)
- qbits = gcry_pk_get_nbits (pkey);
- else if (pkalgo == GCRY_PK_DSA)
- qbits = get_dsa_qbits (pkey);
- else
- return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
-
- if (pkalgo == GCRY_PK_DSA && (qbits%8))
- {
- /* FIXME: We check the QBITS but print a message about the hash
- length. */
- log_error (_("DSA requires the hash length to be a"
- " multiple of 8 bits\n"));
- return gpg_error (GPG_ERR_INV_LENGTH);
- }
-
- /* Don't allow any Q smaller than 160 bits. We don't want someone
- to issue signatures from a key with a 16-bit Q or something like
- that, which would look correct but allow trivial forgeries. Yes,
- I know this rules out using MD5 with DSA. ;) */
- if (qbits < 160)
- {
- log_error (_("%s key uses an unsafe (%u bit) hash\n"),
- gcry_pk_algo_name (pkalgo), qbits);
- return gpg_error (GPG_ERR_INV_LENGTH);
- }
-
- /* Check if we're too short. Too long is safe as we'll
- * automatically left-truncate.
- *
- * This check would require the use of SHA512 with ECDSA 512. I
- * think this is overkill to fail in this case. Therefore, relax
- * the check, but only for ECDSA keys. We may need to adjust it
- * later for general case. (Note that the check is really a bug for
- * ECDSA 521 as the only hash that matches it is SHA 512, but 512 <
- * 521 ).
- */
- if (mdlen < ((pkalgo==GCRY_PK_ECDSA && qbits > 521) ? 512 : qbits)/8)
- {
- log_error (_("a %zu bit hash is not valid for a %u bit %s key\n"),
- mdlen*8,
- gcry_pk_get_nbits (pkey),
- gcry_pk_algo_name (pkalgo));
- /* FIXME: we need to check the requirements for ECDSA. */
- if (mdlen < 20 || pkalgo == GCRY_PK_DSA)
- return gpg_error (GPG_ERR_INV_LENGTH);
- }
-
- /* Truncate. */
- if (mdlen > qbits/8)
- mdlen = qbits/8;
-
- /* Create the S-expression. */
- err = gcry_sexp_build (&hash, NULL,
- "(data (flags rfc6979) (hash %s %b))",
- rfc6979_hash_algo_string (mdlen),
- (int)mdlen, md);
- if (!err)
- *r_hash = hash;
- return err;
+ return rc;
}
@@ -237,7 +87,7 @@
gcry_sexp_t hash;
unsigned char *frame;
size_t i, n, nframe;
-
+
nframe = (nbits+7) / 8;
if ( !mdlen || mdlen + 8 + 4 > nframe )
{
@@ -248,7 +98,7 @@
frame = xtrymalloc (nframe);
if (!frame)
return gpg_error_from_syserror ();
-
+
/* Assemble the pkcs#1 block type 1. */
n = 0;
frame[n++] = 0;
@@ -261,7 +111,7 @@
memcpy (frame+n, md, mdlen );
n += mdlen;
assert (n == nframe);
-
+
/* Create the S-expression. */
rc = gcry_sexp_build (&hash, NULL,
"(data (flags raw) (value %b))",
@@ -269,157 +119,56 @@
xfree (frame);
*r_hash = hash;
- return rc;
+ return rc;
}
/* SIGN whatever information we have accumulated in CTRL and return
the signature S-expression. LOOKUP is an optional function to
- provide a way for lower layers to ask for the caching TTL. If a
- CACHE_NONCE is given that cache item is first tried to get a
- passphrase. If OVERRIDEDATA is not NULL, OVERRIDEDATALEN bytes
- from this buffer are used instead of the data in CTRL. The
- override feature is required to allow the use of Ed25519 with ssh
- because Ed25519 dies the hashing itself. */
+ provide a way for lower layers to ask for the caching TTL. */
int
-agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
- const char *desc_text,
+agent_pksign_do (ctrl_t ctrl, const char *desc_text,
gcry_sexp_t *signature_sexp,
- cache_mode_t cache_mode, lookup_ttl_t lookup_ttl,
- const void *overridedata, size_t overridedatalen)
+ cache_mode_t cache_mode, lookup_ttl_t lookup_ttl)
{
gcry_sexp_t s_skey = NULL, s_sig = NULL;
unsigned char *shadow_info = NULL;
unsigned int rc = 0; /* FIXME: gpg-error? */
- const unsigned char *data;
- int datalen;
-
- if (overridedata)
- {
- data = overridedata;
- datalen = overridedatalen;
- }
- else
- {
- data = ctrl->digest.value;
- datalen = ctrl->digest.valuelen;
- }
- if (!ctrl->have_keygrip)
+ if (! ctrl->have_keygrip)
return gpg_error (GPG_ERR_NO_SECKEY);
- rc = agent_key_from_file (ctrl, cache_nonce, desc_text, ctrl->keygrip,
+ rc = agent_key_from_file (ctrl, desc_text, ctrl->keygrip,
&shadow_info, cache_mode, lookup_ttl,
- &s_skey, NULL);
+ &s_skey);
if (rc)
{
- if (gpg_err_code (rc) != GPG_ERR_NO_SECKEY)
- log_error ("failed to read the secret key\n");
+ log_error ("failed to read the secret key\n");
goto leave;
}
- if (shadow_info)
+ if (!s_skey)
{
/* Divert operation to the smartcard */
- size_t len;
- unsigned char *buf = NULL;
- int key_type;
- int is_RSA = 0;
- int is_ECDSA = 0;
- int is_EdDSA = 0;
- if (agent_is_eddsa_key (s_skey))
- is_EdDSA = 1;
- else
- {
- key_type = agent_is_dsa_key (s_skey);
- if (key_type == 0)
- is_RSA = 1;
- else if (key_type == GCRY_PK_ECDSA)
- is_ECDSA = 1;
- }
+ unsigned char *buf = NULL;
+ size_t len = 0;
- rc = divert_pksign (ctrl,
- data, datalen,
+ rc = divert_pksign (ctrl,
+ ctrl->digest.value,
+ ctrl->digest.valuelen,
ctrl->digest.algo,
- shadow_info, &buf, &len);
+ shadow_info, &buf);
if (rc)
{
log_error ("smartcard signing failed: %s\n", gpg_strerror (rc));
goto leave;
}
+ len = gcry_sexp_canon_len (buf, 0, NULL, NULL);
+ assert (len);
- if (is_RSA)
- {
- if (*buf & 0x80)
- {
- len++;
- buf = xtryrealloc (buf, len);
- if (!buf)
- goto leave;
-
- memmove (buf + 1, buf, len - 1);
- *buf = 0;
- }
-
- rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%b)))",
- (int)len, buf);
- }
- else if (is_EdDSA)
- {
- rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(eddsa(r%b)(s%b)))",
- (int)len/2, buf, (int)len/2, buf + len/2);
- }
- else if (is_ECDSA)
- {
- unsigned char *r_buf_allocated = NULL;
- unsigned char *s_buf_allocated = NULL;
- unsigned char *r_buf, *s_buf;
- int r_buflen, s_buflen;
-
- r_buflen = s_buflen = len/2;
-
- if (*buf & 0x80)
- {
- r_buflen++;
- r_buf_allocated = xtrymalloc (r_buflen);
- if (!r_buf_allocated)
- goto leave;
-
- r_buf = r_buf_allocated;
- memcpy (r_buf + 1, buf, len/2);
- *r_buf = 0;
- }
- else
- r_buf = buf;
-
- if (*(buf + len/2) & 0x80)
- {
- s_buflen++;
- s_buf_allocated = xtrymalloc (s_buflen);
- if (!s_buf_allocated)
- {
- xfree (r_buf_allocated);
- goto leave;
- }
-
- s_buf = s_buf_allocated;
- memcpy (s_buf + 1, buf + len/2, len/2);
- *s_buf = 0;
- }
- else
- s_buf = buf + len/2;
-
- rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(ecdsa(r%b)(s%b)))",
- r_buflen, r_buf,
- s_buflen, s_buf);
- xfree (r_buf_allocated);
- xfree (s_buf_allocated);
- }
- else
- rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
-
+ rc = gcry_sexp_sscan (&s_sig, NULL, (char*)buf, len);
xfree (buf);
if (rc)
{
@@ -431,23 +180,18 @@
else
{
/* No smartcard, but a private key */
+
gcry_sexp_t s_hash = NULL;
- int dsaalgo;
/* Put the hash into a sexp */
- if (agent_is_eddsa_key (s_skey))
- rc = do_encode_eddsa (data, datalen,
- &s_hash);
- else if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1)
- rc = do_encode_raw_pkcs1 (data, datalen,
+ if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1)
+ rc = do_encode_raw_pkcs1 (ctrl->digest.value,
+ ctrl->digest.valuelen,
gcry_pk_get_nbits (s_skey),
&s_hash);
- else if ( (dsaalgo = agent_is_dsa_key (s_skey)) )
- rc = do_encode_dsa (data, datalen,
- dsaalgo, s_skey,
- &s_hash);
else
- rc = do_encode_md (data, datalen,
+ rc = do_encode_md (ctrl->digest.value,
+ ctrl->digest.valuelen,
ctrl->digest.algo,
&s_hash,
ctrl->digest.raw_value);
@@ -456,8 +200,8 @@
if (DBG_CRYPTO)
{
- gcry_log_debugsxp ("skey", s_skey);
- gcry_log_debugsxp ("hash", s_hash);
+ log_debug ("skey: ");
+ gcry_sexp_dump (s_skey);
}
/* sign */
@@ -470,7 +214,10 @@
}
if (DBG_CRYPTO)
- gcry_log_debugsxp ("rslt", s_sig);
+ {
+ log_debug ("result: ");
+ gcry_sexp_dump (s_sig);
+ }
}
leave:
@@ -484,19 +231,17 @@
}
/* SIGN whatever information we have accumulated in CTRL and write it
- back to OUTFP. If a CACHE_NONCE is given that cache item is first
- tried to get a passphrase. */
+ back to OUTFP. */
int
-agent_pksign (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
- membuf_t *outbuf, cache_mode_t cache_mode)
+agent_pksign (ctrl_t ctrl, const char *desc_text,
+ membuf_t *outbuf, cache_mode_t cache_mode)
{
gcry_sexp_t s_sig = NULL;
char *buf = NULL;
size_t len = 0;
int rc = 0;
- rc = agent_pksign_do (ctrl, cache_nonce, desc_text, &s_sig, cache_mode, NULL,
- NULL, 0);
+ rc = agent_pksign_do (ctrl, desc_text, &s_sig, cache_mode, NULL);
if (rc)
goto leave;
diff -Nru gnupg2-2.1.6~build1/agent/preset-passphrase.c gnupg2-2.0.28/agent/preset-passphrase.c
--- gnupg2-2.1.6~build1/agent/preset-passphrase.c 2015-06-17 06:39:24.000000000 +0000
+++ gnupg2-2.0.28/agent/preset-passphrase.c 2015-06-02 08:13:55.000000000 +0000
@@ -44,11 +44,12 @@
# include /* To initialize the sockets. fixme */
#endif
+#define JNLIB_NEED_LOG_LOGV
#include "agent.h"
+#include "minip12.h"
#include "simple-pwquery.h"
#include "i18n.h"
#include "sysutils.h"
-#include "../common/init.h"
enum cmd_and_opt_values
@@ -89,7 +90,7 @@
const char *p;
switch (level)
{
- case 11: p = "gpg-preset-passphrase (@GNUPG@)";
+ case 11: p = "gpg-preset-passphrase (GnuPG)";
break;
case 13: p = VERSION; break;
case 17: p = PRINTABLE_OS_NAME; break;
@@ -211,13 +212,12 @@
int cmd = 0;
const char *keygrip = NULL;
- early_system_init ();
set_strusage (my_strusage);
log_set_prefix ("gpg-preset-passphrase", 1);
/* Make sure that our subsystems are ready. */
i18n_init ();
- init_common_subsystems (&argc, &argv);
+ init_common_subsystems ();
opt_homedir = default_homedir ();
@@ -248,7 +248,7 @@
/* Tell simple-pwquery about the the standard socket name. */
{
- char *tmp = make_filename (opt_homedir, GPG_AGENT_SOCK_NAME, NULL);
+ char *tmp = make_filename (opt_homedir, "S.gpg-agent", NULL);
simple_pw_set_socket (tmp);
xfree (tmp);
}
diff -Nru gnupg2-2.1.6~build1/agent/protect.c gnupg2-2.0.28/agent/protect.c
--- gnupg2-2.1.6~build1/agent/protect.c 2015-06-17 06:39:24.000000000 +0000
+++ gnupg2-2.0.28/agent/protect.c 2015-06-02 08:13:55.000000000 +0000
@@ -1,6 +1,6 @@
/* protect.c - Un/Protect a secret key
- * Copyright (C) 1998-2003, 2007, 2009, 2011 Free Software Foundation, Inc.
- * Copyright (C) 1998-2003, 2007, 2009, 2011, 2013-2015 Werner Koch
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002,
+ * 2003, 2007, 2009 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -38,21 +38,15 @@
#include "agent.h"
-#include "cvt-openpgp.h"
#include "sexp-parse.h"
-/* The protection mode for encryption. The supported modes for
- decryption are listed in agent_unprotect(). */
-#define PROT_CIPHER GCRY_CIPHER_AES128
+#define PROT_CIPHER GCRY_CIPHER_AES
#define PROT_CIPHER_STRING "aes"
#define PROT_CIPHER_KEYLEN (128/8)
-/* Decode an rfc4880 encoded S2K count. */
-#define S2K_DECODE_COUNT(_val) ((16ul + ((_val) & 15)) << (((_val) >> 4) + 6))
-
/* A table containing the information needed to create a protected
- private key. */
+ private key */
static struct {
const char *algo;
const char *parmlist;
@@ -86,18 +80,12 @@
const unsigned char *s2ksalt, unsigned long s2kcount,
unsigned char *key, size_t keylen);
-
-
/* Get the process time and store it in DATA. */
static void
calibrate_get_time (struct calibrate_time_s *data)
{
#ifdef HAVE_W32_SYSTEM
-# ifdef HAVE_W32CE_SYSTEM
- GetThreadTimes (GetCurrentThread (),
-# else
GetProcessTimes (GetCurrentProcess (),
-# endif
&data->creation_time, &data->exit_time,
&data->kernel_time, &data->user_time);
#else
@@ -180,7 +168,7 @@
if (opt.verbose)
{
ms = calibrate_s2k_count_one (count);
- log_info ("S2K calibration: %lu -> %lums\n", count, ms);
+ log_info ("S2K calibration: %lu iterations for %lums\n", count, ms);
}
return count;
@@ -202,45 +190,16 @@
}
-/* Same as get_standard_s2k_count but return the count in the encoding
- as described by rfc4880. */
-unsigned char
-get_standard_s2k_count_rfc4880 (void)
-{
- unsigned long iterations;
- unsigned int count;
- unsigned char result;
- unsigned char c=0;
-
- iterations = get_standard_s2k_count ();
- if (iterations >= 65011712)
- return 255;
-
- /* Need count to be in the range 16-31 */
- for (count=iterations>>6; count>=32; count>>=1)
- c++;
-
- result = (c<<4)|(count-16);
-
- if (S2K_DECODE_COUNT(result) < iterations)
- result++;
-
- return result;
-
-}
-
-/* Calculate the MIC for a private key or shared secret S-expression.
- SHA1HASH should point to a 20 byte buffer. This function is
- suitable for all algorithms. */
+/* Calculate the MIC for a private key S-Exp. SHA1HASH should point to
+ a 20 byte buffer. This function is suitable for any algorithms. */
static int
calculate_mic (const unsigned char *plainkey, unsigned char *sha1hash)
{
const unsigned char *hash_begin, *hash_end;
const unsigned char *s;
size_t n;
- int is_shared_secret;
s = plainkey;
if (*s != '(')
@@ -249,23 +208,16 @@
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
- if (smatch (&s, n, "private-key"))
- is_shared_secret = 0;
- else if (smatch (&s, n, "shared-secret"))
- is_shared_secret = 1;
- else
+ if (!smatch (&s, n, "private-key"))
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
if (*s != '(')
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
hash_begin = s;
- if (!is_shared_secret)
- {
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- s += n; /* Skip the algorithm name. */
- }
+ s++;
+ n = snext (&s);
+ if (!n)
+ return gpg_error (GPG_ERR_INV_SEXP);
+ s += n; /* skip over the algorithm name */
while (*s == '(')
{
@@ -316,8 +268,7 @@
static int
do_encryption (const unsigned char *protbegin, size_t protlen,
const char *passphrase, const unsigned char *sha1hash,
- unsigned char **result, size_t *resultlen,
- unsigned long s2k_count)
+ unsigned char **result, size_t *resultlen)
{
gcry_cipher_hd_t hd;
const char *modestr = "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc";
@@ -376,8 +327,7 @@
{
rc = hash_passphrase (passphrase, GCRY_MD_SHA1,
3, iv+2*blklen,
- s2k_count ? s2k_count : get_standard_s2k_count(),
- key, keylen);
+ get_standard_s2k_count (), key, keylen);
if (!rc)
rc = gcry_cipher_setkey (hd, key, keylen);
xfree (key);
@@ -420,8 +370,7 @@
{
char countbuf[35];
- snprintf (countbuf, sizeof countbuf, "%lu",
- s2k_count ? s2k_count : get_standard_s2k_count ());
+ snprintf (countbuf, sizeof countbuf, "%lu", get_standard_s2k_count ());
p = xtryasprintf
("(9:protected%d:%s((4:sha18:%n_8bytes_%u:%s)%d:%n%*s)%d:%n%*s)",
(int)strlen (modestr), modestr,
@@ -453,8 +402,7 @@
a valid S-Exp here. */
int
agent_protect (const unsigned char *plainkey, const char *passphrase,
- unsigned char **result, size_t *resultlen,
- unsigned long s2k_count)
+ unsigned char **result, size_t *resultlen)
{
int rc;
const char *parmlist;
@@ -471,9 +419,8 @@
int depth = 0;
unsigned char *p;
gcry_md_hd_t md;
- int have_curve = 0;
- /* Create an S-expression with the protected-at timestamp. */
+ /* Create an S-expression with the procted-at timestamp. */
memcpy (timestamp_exp, "(12:protected-at15:", 19);
gnupg_get_isotime (timestamp_exp+19);
timestamp_exp[19+15] = ')';
@@ -504,11 +451,6 @@
if (!protect_info[infidx].algo)
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
- /* The parser below is a complete mess: To make it robust for ECC
- use we should reorder the s-expression to include only what we
- really need and thus guarantee the right order for saving stuff.
- This should be done before calling this function and maybe with
- the help of the new gcry_sexp_extract_param. */
parmlist = protect_info[infidx].parmlist;
prot_from_idx = protect_info[infidx].prot_from;
prot_to_idx = protect_info[infidx].prot_to;
@@ -532,19 +474,10 @@
/* This is a private ECC key but the first parameter is
the name of the curve. We change the parameter list
here to the one we expect in this case. */
- have_curve = 1;
parmlist = "?qd";
prot_from_idx = 2;
prot_to_idx = 2;
}
- else if (n == 5 && !memcmp (s, "flags", 5)
- && i == 1 && have_curve)
- {
- /* "curve" followed by "flags": Change again. */
- parmlist = "??qd";
- prot_from_idx = 3;
- prot_to_idx = 3;
- }
else
return gpg_error (GPG_ERR_INV_SEXP);
}
@@ -565,7 +498,7 @@
depth--;
hash_end = s;
s++;
- /* Skip to the end of the S-expression. */
+ /* skip to the end of the S-exp */
assert (depth == 1);
rc = sskip (&s, &depth);
if (rc)
@@ -587,7 +520,7 @@
rc = do_encryption (prot_begin, prot_end - prot_begin + 1,
passphrase, hashvalue,
- &protected, &protectedlen, s2k_count);
+ &protected, &protectedlen);
if (rc)
return rc;
@@ -625,7 +558,6 @@
return 0;
}
-
/* Do the actual decryption and check the return list for consistency. */
static int
@@ -633,7 +565,6 @@
const char *passphrase,
const unsigned char *s2ksalt, unsigned long s2kcount,
const unsigned char *iv, size_t ivlen,
- int prot_cipher, int prot_cipher_keylen,
unsigned char **result)
{
int rc = 0;
@@ -642,11 +573,11 @@
unsigned char *outbuf;
size_t reallen;
- blklen = gcry_cipher_get_algo_blklen (prot_cipher);
+ blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER);
if (protectedlen < 4 || (protectedlen%blklen))
return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
- rc = gcry_cipher_open (&hd, prot_cipher, GCRY_CIPHER_MODE_CBC,
+ rc = gcry_cipher_open (&hd, PROT_CIPHER, GCRY_CIPHER_MODE_CBC,
GCRY_CIPHER_SECURE);
if (rc)
return rc;
@@ -659,16 +590,17 @@
if (!rc)
{
unsigned char *key;
+ size_t keylen = PROT_CIPHER_KEYLEN;
- key = gcry_malloc_secure (prot_cipher_keylen);
+ key = gcry_malloc_secure (keylen);
if (!key)
rc = out_of_core ();
else
{
rc = hash_passphrase (passphrase, GCRY_MD_SHA1,
- 3, s2ksalt, s2kcount, key, prot_cipher_keylen);
+ 3, s2ksalt, s2kcount, key, keylen);
if (!rc)
- rc = gcry_cipher_setkey (hd, key, prot_cipher_keylen);
+ rc = gcry_cipher_setkey (hd, key, keylen);
xfree (key);
}
}
@@ -854,22 +786,12 @@
/* Unprotect the key encoded in canonical format. We assume a valid
S-Exp here. If a protected-at item is available, its value will
- be stored at protected_at unless this is NULL. */
+ be stored at protocted_at unless this is NULL. */
int
-agent_unprotect (ctrl_t ctrl,
- const unsigned char *protectedkey, const char *passphrase,
+agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
gnupg_isotime_t protected_at,
unsigned char **result, size_t *resultlen)
{
- static struct {
- const char *name; /* Name of the protection method. */
- int algo; /* (A zero indicates the "openpgp-native" hack.) */
- int keylen; /* Used key length in bytes. */
- } algotable[] = {
- { "openpgp-s2k3-sha1-aes-cbc", GCRY_CIPHER_AES128, (128/8)},
- { "openpgp-s2k3-sha1-aes256-cbc", GCRY_CIPHER_AES256, (256/8)},
- { "openpgp-native", 0, 0 }
- };
int rc;
const unsigned char *s;
const unsigned char *protect_list;
@@ -879,9 +801,8 @@
const unsigned char *s2ksalt;
unsigned long s2kcount;
const unsigned char *iv;
- int prot_cipher, prot_cipher_keylen;
const unsigned char *prot_begin;
- unsigned char *cleartext;
+ unsigned char *cleartext = NULL; /* Just to avoid gcc warning. */
unsigned char *final;
size_t finallen;
size_t cutoff, cutlen;
@@ -970,40 +891,8 @@
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
-
- /* Lookup the protection algo. */
- prot_cipher = 0; /* (avoid gcc warning) */
- prot_cipher_keylen = 0; /* (avoid gcc warning) */
- for (i= 0; i < DIM (algotable); i++)
- if (smatch (&s, n, algotable[i].name))
- {
- prot_cipher = algotable[i].algo;
- prot_cipher_keylen = algotable[i].keylen;
- break;
- }
- if (i == DIM (algotable))
+ if (!smatch (&s, n, "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc"))
return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION);
-
- if (!prot_cipher) /* This is "openpgp-native". */
- {
- gcry_sexp_t s_prot_begin;
-
- rc = gcry_sexp_sscan (&s_prot_begin, NULL,
- prot_begin,
- gcry_sexp_canon_len (prot_begin, 0,NULL,NULL));
- if (rc)
- return rc;
-
- rc = convert_from_openpgp_native (ctrl, s_prot_begin, passphrase, &final);
- gcry_sexp_release (s_prot_begin);
- if (!rc)
- {
- *result = final;
- *resultlen = gcry_sexp_canon_len (final, 0, NULL, NULL);
- }
- return rc;
- }
-
if (*s != '(' || s[1] != '(')
return gpg_error (GPG_ERR_INV_SEXP);
s += 2;
@@ -1046,7 +935,7 @@
s++; /* skip list end */
n = snext (&s);
- if (n != 16) /* Wrong blocksize for IV (we support only 128 bit). */
+ if (n != 16) /* Wrong blocksize for IV (we support only aes-128). */
return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
iv = s;
s += n;
@@ -1057,10 +946,9 @@
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
- cleartext = NULL; /* Avoid cc warning. */
rc = do_decryption (s, n,
passphrase, s2ksalt, s2kcount,
- iv, 16, prot_cipher, prot_cipher_keylen,
+ iv, 16,
&cleartext);
if (rc)
return rc;
@@ -1084,7 +972,7 @@
xfree (final);
return rc;
}
- /* Now remove the part which is included in the MIC but should not
+ /* Now remove tha part which is included in the MIC but should not
go into the final thing. */
if (cutlen)
{
@@ -1101,16 +989,13 @@
PRIVATE_KEY_UNKNOWN if we can't figure out the type (this is the
value 0), PRIVATE_KEY_CLEAR for an unprotected private key.
PRIVATE_KEY_PROTECTED for an protected private key or
- PRIVATE_KEY_SHADOWED for a sub key where the secret parts are
- stored elsewhere. Finally PRIVATE_KEY_OPENPGP_NONE may be returned
- is the key is still in the openpgp-native format but without
- protection. */
+ PRIVATE_KEY_SHADOWED for a sub key where the secret parts are stored
+ elsewhere. */
int
agent_private_key_type (const unsigned char *privatekey)
{
const unsigned char *s;
size_t n;
- int i;
s = privatekey;
if (*s != '(')
@@ -1120,75 +1005,7 @@
if (!n)
return PRIVATE_KEY_UNKNOWN;
if (smatch (&s, n, "protected-private-key"))
- {
- /* We need to check whether this is openpgp-native protected
- with the protection method "none". In that case we return a
- different key type so that the caller knows that there is no
- need to ask for a passphrase. */
- if (*s != '(')
- return PRIVATE_KEY_PROTECTED; /* Unknown sexp - assume protected. */
- s++;
- n = snext (&s);
- if (!n)
- return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
- s += n; /* Skip over the algo */
-
- /* Find the (protected ...) list. */
- for (;;)
- {
- if (*s != '(')
- return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
- s++;
- n = snext (&s);
- if (!n)
- return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
- if (smatch (&s, n, "protected"))
- break;
- s += n;
- i = 1;
- if (sskip (&s, &i))
- return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
- }
- /* Found - Is this openpgp-native? */
- n = snext (&s);
- if (!n)
- return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
- if (smatch (&s, n, "openpgp-native")) /* Yes. */
- {
- if (*s != '(')
- return PRIVATE_KEY_UNKNOWN; /* Unknown sexp. */
- s++;
- n = snext (&s);
- if (!n)
- return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
- s += n; /* Skip over "openpgp-private-key". */
- /* Find the (protection ...) list. */
- for (;;)
- {
- if (*s != '(')
- return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
- s++;
- n = snext (&s);
- if (!n)
- return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
- if (smatch (&s, n, "protection"))
- break;
- s += n;
- i = 1;
- if (sskip (&s, &i))
- return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
- }
- /* Found - Is the mode "none"? */
- n = snext (&s);
- if (!n)
- return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
- log_debug ("openpgp-native protection '%.*s'\n", (int)n, s);
- if (smatch (&s, n, "none"))
- return PRIVATE_KEY_OPENPGP_NONE; /* Yes. */
- }
-
- return PRIVATE_KEY_PROTECTED;
- }
+ return PRIVATE_KEY_PROTECTED;
if (smatch (&s, n, "shadowed-private-key"))
return PRIVATE_KEY_SHADOWED;
if (smatch (&s, n, "private-key"))
@@ -1211,30 +1028,70 @@
unsigned long s2kcount,
unsigned char *key, size_t keylen)
{
- /* The key derive function does not support a zero length string for
- the passphrase in the S2K modes. Return a better suited error
- code than GPG_ERR_INV_DATA. */
- if (!passphrase || !*passphrase)
- return gpg_error (GPG_ERR_NO_PASSPHRASE);
- return gcry_kdf_derive (passphrase, strlen (passphrase),
- s2kmode == 3? GCRY_KDF_ITERSALTED_S2K :
- s2kmode == 1? GCRY_KDF_SALTED_S2K :
- s2kmode == 0? GCRY_KDF_SIMPLE_S2K : GCRY_KDF_NONE,
- hashalgo, s2ksalt, 8, s2kcount,
- keylen, key);
-}
+ int rc;
+ gcry_md_hd_t md;
+ int pass, i;
+ int used = 0;
+ int pwlen = strlen (passphrase);
+ if ( (s2kmode != 0 && s2kmode != 1 && s2kmode != 3)
+ || !hashalgo || !keylen || !key || !passphrase)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ if ((s2kmode == 1 ||s2kmode == 3) && !s2ksalt)
+ return gpg_error (GPG_ERR_INV_VALUE);
-gpg_error_t
-s2k_hash_passphrase (const char *passphrase, int hashalgo,
- int s2kmode,
- const unsigned char *s2ksalt,
- unsigned int s2kcount,
- unsigned char *key, size_t keylen)
-{
- return hash_passphrase (passphrase, hashalgo, s2kmode, s2ksalt,
- S2K_DECODE_COUNT (s2kcount),
- key, keylen);
+ rc = gcry_md_open (&md, hashalgo, GCRY_MD_FLAG_SECURE);
+ if (rc)
+ return rc;
+
+ for (pass=0; used < keylen; pass++)
+ {
+ if (pass)
+ {
+ gcry_md_reset (md);
+ for (i=0; i < pass; i++) /* preset the hash context */
+ gcry_md_putc (md, 0);
+ }
+
+ if (s2kmode == 1 || s2kmode == 3)
+ {
+ int len2 = pwlen + 8;
+ unsigned long count = len2;
+
+ if (s2kmode == 3)
+ {
+ count = s2kcount;
+ if (count < len2)
+ count = len2;
+ }
+
+ while (count > len2)
+ {
+ gcry_md_write (md, s2ksalt, 8);
+ gcry_md_write (md, passphrase, pwlen);
+ count -= len2;
+ }
+ if (count < 8)
+ gcry_md_write (md, s2ksalt, count);
+ else
+ {
+ gcry_md_write (md, s2ksalt, 8);
+ count -= 8;
+ gcry_md_write (md, passphrase, count);
+ }
+ }
+ else
+ gcry_md_write (md, passphrase, pwlen);
+
+ gcry_md_final (md);
+ i = gcry_md_get_algo_dlen (hashalgo);
+ if (i > keylen - used)
+ i = keylen - used;
+ memcpy (key+used, gcry_md_read (md, hashalgo), i);
+ used += i;
+ }
+ gcry_md_close(md);
+ return 0;
}
@@ -1430,7 +1287,7 @@
required, NULL may be passed for them. */
gpg_error_t
parse_shadow_info (const unsigned char *shadow_info,
- char **r_hexsn, char **r_idstr, int *r_pinlen)
+ char **r_hexsn, char **r_idstr)
{
const unsigned char *s;
size_t n;
@@ -1439,8 +1296,6 @@
*r_hexsn = NULL;
if (r_idstr)
*r_idstr = NULL;
- if (r_pinlen)
- *r_pinlen = 0;
s = shadow_info;
if (*s != '(')
@@ -1485,34 +1340,6 @@
(*r_idstr)[n] = 0;
}
- /* Parse the optional PINLEN. */
- n = snext (&s);
- if (!n)
- return 0;
-
- if (r_pinlen)
- {
- char *tmpstr = xtrymalloc (n+1);
- if (!tmpstr)
- {
- if (r_hexsn)
- {
- xfree (*r_hexsn);
- *r_hexsn = NULL;
- }
- if (r_idstr)
- {
- xfree (*r_idstr);
- *r_idstr = NULL;
- }
- return gpg_error_from_syserror ();
- }
- memcpy (tmpstr, s, n);
- tmpstr[n] = 0;
-
- *r_pinlen = (int)strtol (tmpstr, NULL, 10);
- xfree (tmpstr);
- }
-
return 0;
}
+
diff -Nru gnupg2-2.1.6~build1/agent/protect-tool.c gnupg2-2.0.28/agent/protect-tool.c
--- gnupg2-2.1.6~build1/agent/protect-tool.c 2015-06-17 06:39:24.000000000 +0000
+++ gnupg2-2.0.28/agent/protect-tool.c 2015-06-02 08:13:55.000000000 +0000
@@ -38,11 +38,13 @@
#include /* for setmode() */
#endif
+#define JNLIB_NEED_LOG_LOGV
#include "agent.h"
+#include "minip12.h"
#include "i18n.h"
#include "get-passphrase.h"
#include "sysutils.h"
-#include "../common/init.h"
+#include "estream.h"
enum cmd_and_opt_values
@@ -62,6 +64,9 @@
oS2Kcalibration,
oCanonical,
+ oP12Import,
+ oP12Export,
+ oP12Charset,
oStore,
oForce,
oHaveCert,
@@ -95,10 +100,14 @@
static const char *opt_passphrase;
static char *opt_prompt;
static int opt_status_msg;
+static const char *opt_p12_charset;
static const char *opt_agent_program;
+static session_env_t opt_session_env;
static char *get_passphrase (int promptno);
static void release_passphrase (char *pw);
+static int store_private_key (const unsigned char *grip,
+ const void *buffer, size_t length, int force);
static ARGPARSE_OPTS opts[] = {
@@ -109,6 +118,11 @@
ARGPARSE_c (oShadow, "shadow", "create a shadow entry for a public key"),
ARGPARSE_c (oShowShadowInfo, "show-shadow-info", "return the shadow info"),
ARGPARSE_c (oShowKeygrip, "show-keygrip", "show the \"keygrip\""),
+ ARGPARSE_c (oP12Import, "p12-import",
+ "import a pkcs#12 encoded private key"),
+ ARGPARSE_c (oP12Export, "p12-export",
+ "export a private key pkcs#12 encoded"),
+
ARGPARSE_c (oS2Kcalibration, "s2k-calibration", "@"),
ARGPARSE_group (301, N_("@\nOptions:\n ")),
@@ -118,6 +132,8 @@
ARGPARSE_s_n (oCanonical, "canonical", "write output in canonical format"),
ARGPARSE_s_s (oPassphrase, "passphrase", "|STRING|use passphrase STRING"),
+ ARGPARSE_s_s (oP12Charset,"p12-charset",
+ "|NAME|set charset for a new PKCS#12 passphrase to NAME"),
ARGPARSE_s_n (oHaveCert, "have-cert",
"certificate to export provided on STDIN"),
ARGPARSE_s_n (oStore, "store",
@@ -141,7 +157,7 @@
const char *p;
switch (level)
{
- case 11: p = "gpg-protect-tool (" GNUPG_NAME ")";
+ case 11: p = "gpg-protect-tool (GnuPG)";
break;
case 13: p = VERSION; break;
case 17: p = PRINTABLE_OS_NAME; break;
@@ -190,7 +206,7 @@
rc = gcry_sexp_sscan (&sexp, &erroff, buf, buflen);
if (rc)
{
- log_error ("invalid S-Expression in '%s' (off=%u): %s\n",
+ log_error ("invalid S-Expression in `%s' (off=%u): %s\n",
fname, (unsigned int)erroff, gpg_strerror (rc));
return NULL;
}
@@ -257,7 +273,7 @@
nread = fread (buf+buflen, 1, NCHUNK, fp);
if (nread < NCHUNK && ferror (fp))
{
- log_error ("error reading '[stdin]': %s\n", strerror (errno));
+ log_error ("error reading `[stdin]': %s\n", strerror (errno));
xfree (buf);
return NULL;
}
@@ -274,13 +290,13 @@
fp = fopen (fname, "rb");
if (!fp)
{
- log_error ("can't open '%s': %s\n", fname, strerror (errno));
+ log_error ("can't open `%s': %s\n", fname, strerror (errno));
return NULL;
}
if (fstat (fileno(fp), &st))
{
- log_error ("can't stat '%s': %s\n", fname, strerror (errno));
+ log_error ("can't stat `%s': %s\n", fname, strerror (errno));
fclose (fp);
return NULL;
}
@@ -289,7 +305,7 @@
buf = xmalloc (buflen+1);
if (fread (buf, buflen, 1, fp) != 1)
{
- log_error ("error reading '%s': %s\n", fname, strerror (errno));
+ log_error ("error reading `%s': %s\n", fname, strerror (errno));
fclose (fp);
xfree (buf);
return NULL;
@@ -333,7 +349,7 @@
return;
pw = get_passphrase (1);
- rc = agent_protect (key, pw, &result, &resultlen, 0);
+ rc = agent_protect (key, pw, &result, &resultlen);
release_passphrase (pw);
xfree (key);
if (rc)
@@ -371,7 +387,7 @@
if (!key)
return;
- rc = agent_unprotect (NULL, key, (pw=get_passphrase (1)),
+ rc = agent_unprotect (key, (pw=get_passphrase (1)),
protected_at, &result, &resultlen);
release_passphrase (pw);
xfree (key);
@@ -538,6 +554,463 @@
}
+static int
+rsa_key_check (struct rsa_secret_key_s *skey)
+{
+ int err = 0;
+ gcry_mpi_t t = gcry_mpi_snew (0);
+ gcry_mpi_t t1 = gcry_mpi_snew (0);
+ gcry_mpi_t t2 = gcry_mpi_snew (0);
+ gcry_mpi_t phi = gcry_mpi_snew (0);
+
+ /* check that n == p * q */
+ gcry_mpi_mul (t, skey->p, skey->q);
+ if (gcry_mpi_cmp( t, skey->n) )
+ {
+ log_error ("RSA oops: n != p * q\n");
+ err++;
+ }
+
+ /* check that p is less than q */
+ if (gcry_mpi_cmp (skey->p, skey->q) > 0)
+ {
+ gcry_mpi_t tmp;
+
+ log_info ("swapping secret primes\n");
+ tmp = gcry_mpi_copy (skey->p);
+ gcry_mpi_set (skey->p, skey->q);
+ gcry_mpi_set (skey->q, tmp);
+ gcry_mpi_release (tmp);
+ /* and must recompute u of course */
+ gcry_mpi_invm (skey->u, skey->p, skey->q);
+ }
+
+ /* check that e divides neither p-1 nor q-1 */
+ gcry_mpi_sub_ui (t, skey->p, 1 );
+ gcry_mpi_div (NULL, t, t, skey->e, 0);
+ if (!gcry_mpi_cmp_ui( t, 0) )
+ {
+ log_error ("RSA oops: e divides p-1\n");
+ err++;
+ }
+ gcry_mpi_sub_ui (t, skey->q, 1);
+ gcry_mpi_div (NULL, t, t, skey->e, 0);
+ if (!gcry_mpi_cmp_ui( t, 0))
+ {
+ log_info ( "RSA oops: e divides q-1\n" );
+ err++;
+ }
+
+ /* check that d is correct. */
+ gcry_mpi_sub_ui (t1, skey->p, 1);
+ gcry_mpi_sub_ui (t2, skey->q, 1);
+ gcry_mpi_mul (phi, t1, t2);
+ gcry_mpi_invm (t, skey->e, phi);
+ if (gcry_mpi_cmp (t, skey->d))
+ { /* no: try universal exponent. */
+ gcry_mpi_gcd (t, t1, t2);
+ gcry_mpi_div (t, NULL, phi, t, 0);
+ gcry_mpi_invm (t, skey->e, t);
+ if (gcry_mpi_cmp (t, skey->d))
+ {
+ log_error ("RSA oops: bad secret exponent\n");
+ err++;
+ }
+ }
+
+ /* check for correctness of u */
+ gcry_mpi_invm (t, skey->p, skey->q);
+ if (gcry_mpi_cmp (t, skey->u))
+ {
+ log_info ( "RSA oops: bad u parameter\n");
+ err++;
+ }
+
+ if (err)
+ log_info ("RSA secret key check failed\n");
+
+ gcry_mpi_release (t);
+ gcry_mpi_release (t1);
+ gcry_mpi_release (t2);
+ gcry_mpi_release (phi);
+
+ return err? -1:0;
+}
+
+
+/* A callback used by p12_parse to return a certificate. */
+static void
+import_p12_cert_cb (void *opaque, const unsigned char *cert, size_t certlen)
+{
+ struct b64state state;
+ gpg_error_t err, err2;
+
+ (void)opaque;
+
+ err = b64enc_start (&state, stdout, "CERTIFICATE");
+ if (!err)
+ err = b64enc_write (&state, cert, certlen);
+ err2 = b64enc_finish (&state);
+ if (!err)
+ err = err2;
+ if (err)
+ log_error ("error writing armored certificate: %s\n", gpg_strerror (err));
+}
+
+static void
+import_p12_file (const char *fname)
+{
+ char *buf;
+ unsigned char *result;
+ size_t buflen, resultlen, buf_off;
+ int i;
+ int rc;
+ gcry_mpi_t *kparms;
+ struct rsa_secret_key_s sk;
+ gcry_sexp_t s_key;
+ unsigned char *key;
+ unsigned char grip[20];
+ char *pw;
+
+ /* fixme: we should release some stuff on error */
+
+ buf = read_file (fname, &buflen);
+ if (!buf)
+ return;
+
+ /* GnuPG 2.0.4 accidently created binary P12 files with the string
+ "The passphrase is %s encoded.\n\n" prepended to the ASN.1 data.
+ We fix that here. */
+ if (buflen > 29 && !memcmp (buf, "The passphrase is ", 18))
+ {
+ for (buf_off=18; buf_off < buflen && buf[buf_off] != '\n'; buf_off++)
+ ;
+ buf_off++;
+ if (buf_off < buflen && buf[buf_off] == '\n')
+ buf_off++;
+ }
+ else
+ buf_off = 0;
+
+ kparms = p12_parse ((unsigned char*)buf+buf_off, buflen-buf_off,
+ (pw=get_passphrase (2)),
+ import_p12_cert_cb, NULL);
+ release_passphrase (pw);
+ xfree (buf);
+ if (!kparms)
+ {
+ log_error ("error parsing or decrypting the PKCS-12 file\n");
+ return;
+ }
+ for (i=0; kparms[i]; i++)
+ ;
+ if (i != 8)
+ {
+ log_error ("invalid structure of private key\n");
+ return;
+ }
+
+
+/* print_mpi (" n", kparms[0]); */
+/* print_mpi (" e", kparms[1]); */
+/* print_mpi (" d", kparms[2]); */
+/* print_mpi (" p", kparms[3]); */
+/* print_mpi (" q", kparms[4]); */
+/* print_mpi ("dmp1", kparms[5]); */
+/* print_mpi ("dmq1", kparms[6]); */
+/* print_mpi (" u", kparms[7]); */
+
+ sk.n = kparms[0];
+ sk.e = kparms[1];
+ sk.d = kparms[2];
+ sk.q = kparms[3];
+ sk.p = kparms[4];
+ sk.u = kparms[7];
+ if (rsa_key_check (&sk))
+ return;
+/* print_mpi (" n", sk.n); */
+/* print_mpi (" e", sk.e); */
+/* print_mpi (" d", sk.d); */
+/* print_mpi (" p", sk.p); */
+/* print_mpi (" q", sk.q); */
+/* print_mpi (" u", sk.u); */
+
+ /* Create an S-expresion from the parameters. */
+ rc = gcry_sexp_build (&s_key, NULL,
+ "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
+ sk.n, sk.e, sk.d, sk.p, sk.q, sk.u, NULL);
+ for (i=0; i < 8; i++)
+ gcry_mpi_release (kparms[i]);
+ gcry_free (kparms);
+ if (rc)
+ {
+ log_error ("failed to created S-expression from key: %s\n",
+ gpg_strerror (rc));
+ return;
+ }
+
+ /* Compute the keygrip. */
+ if (!gcry_pk_get_keygrip (s_key, grip))
+ {
+ log_error ("can't calculate keygrip\n");
+ return;
+ }
+ log_info ("keygrip: ");
+ for (i=0; i < 20; i++)
+ log_printf ("%02X", grip[i]);
+ log_printf ("\n");
+
+ /* Convert to canonical encoding. */
+ buflen = gcry_sexp_sprint (s_key, GCRYSEXP_FMT_CANON, NULL, 0);
+ assert (buflen);
+ key = gcry_xmalloc_secure (buflen);
+ buflen = gcry_sexp_sprint (s_key, GCRYSEXP_FMT_CANON, key, buflen);
+ assert (buflen);
+ gcry_sexp_release (s_key);
+
+ pw = get_passphrase (4);
+ rc = agent_protect (key, pw, &result, &resultlen);
+ release_passphrase (pw);
+ xfree (key);
+ if (rc)
+ {
+ log_error ("protecting the key failed: %s\n", gpg_strerror (rc));
+ return;
+ }
+
+ if (opt_armor)
+ {
+ char *p = make_advanced (result, resultlen);
+ xfree (result);
+ if (!p)
+ return;
+ result = (unsigned char*)p;
+ resultlen = strlen (p);
+ }
+
+ if (opt_store)
+ store_private_key (grip, result, resultlen, opt_force);
+ else
+ fwrite (result, resultlen, 1, stdout);
+
+ xfree (result);
+}
+
+
+
+static gcry_mpi_t *
+sexp_to_kparms (gcry_sexp_t sexp)
+{
+ gcry_sexp_t list, l2;
+ const char *name;
+ const char *s;
+ size_t n;
+ int i, idx;
+ const char *elems;
+ gcry_mpi_t *array;
+
+ list = gcry_sexp_find_token (sexp, "private-key", 0 );
+ if(!list)
+ return NULL;
+ l2 = gcry_sexp_cadr (list);
+ gcry_sexp_release (list);
+ list = l2;
+ name = gcry_sexp_nth_data (list, 0, &n);
+ if(!name || n != 3 || memcmp (name, "rsa", 3))
+ {
+ gcry_sexp_release (list);
+ return NULL;
+ }
+
+ /* Parameter names used with RSA. */
+ elems = "nedpqu";
+ array = xcalloc (strlen(elems) + 1, sizeof *array);
+ for (idx=0, s=elems; *s; s++, idx++ )
+ {
+ l2 = gcry_sexp_find_token (list, s, 1);
+ if (!l2)
+ {
+ for (i=0; i
#include
#include
-#include
+#include
#include "agent.h"
#include /* fixme: need a way to avoid assuan calls here */
#include "i18n.h"
+#include "estream.h"
/* A structure to store the information from the trust file. */
@@ -51,10 +51,11 @@
typedef struct trustitem_s trustitem_t;
/* Malloced table and its allocated size with all trust items. */
-static trustitem_t *trusttable;
-static size_t trusttablesize;
+static trustitem_t *trusttable;
+static size_t trusttablesize;
/* A mutex used to protect the table. */
-static npth_mutex_t trusttable_lock;
+static pth_mutex_t trusttable_lock;
+
static const char headerblurb[] =
@@ -81,13 +82,11 @@
initialize_module_trustlist (void)
{
static int initialized;
- int err;
if (!initialized)
{
- err = npth_mutex_init (&trusttable_lock, NULL);
- if (err)
- log_fatal ("failed to init mutex in %s: %s\n", __FILE__,strerror (err));
+ if (!pth_mutex_init (&trusttable_lock))
+ log_fatal ("error initializing mutex: %s\n", strerror (errno));
initialized = 1;
}
}
@@ -98,89 +97,69 @@
static void
lock_trusttable (void)
{
- int err;
-
- err = npth_mutex_lock (&trusttable_lock);
- if (err)
- log_fatal ("failed to acquire mutex in %s: %s\n", __FILE__, strerror (err));
+ if (!pth_mutex_acquire (&trusttable_lock, 0, NULL))
+ log_fatal ("failed to acquire mutex in %s\n", __FILE__);
}
-
static void
unlock_trusttable (void)
{
- int err;
-
- err = npth_mutex_unlock (&trusttable_lock);
- if (err)
- log_fatal ("failed to release mutex in %s: %s\n", __FILE__, strerror (err));
+ if (!pth_mutex_release (&trusttable_lock))
+ log_fatal ("failed to release mutex in %s\n", __FILE__);
}
-/* Clear the trusttable. The caller needs to make sure that the
- trusttable is locked. */
-static inline void
-clear_trusttable (void)
-{
- xfree (trusttable);
- trusttable = NULL;
- trusttablesize = 0;
-}
-
static gpg_error_t
read_one_trustfile (const char *fname, int allow_include,
- trustitem_t **addr_of_table,
+ trustitem_t **addr_of_table,
size_t *addr_of_tablesize,
int *addr_of_tableidx)
{
gpg_error_t err = 0;
- estream_t fp;
+ FILE *fp;
int n, c;
char *p, line[256];
trustitem_t *table, *ti;
int tableidx;
size_t tablesize;
int lnr = 0;
-
+
table = *addr_of_table;
tablesize = *addr_of_tablesize;
tableidx = *addr_of_tableidx;
- fp = es_fopen (fname, "r");
+ fp = fopen (fname, "r");
if (!fp)
{
err = gpg_error_from_syserror ();
- log_error (_("error opening '%s': %s\n"), fname, gpg_strerror (err));
+ log_error (_("error opening `%s': %s\n"), fname, gpg_strerror (err));
goto leave;
}
- while (es_fgets (line, DIM(line)-1, fp))
+ while (fgets (line, DIM(line)-1, fp))
{
lnr++;
-
- n = strlen (line);
- if (!n || line[n-1] != '\n')
+
+ if (!*line || line[strlen(line)-1] != '\n')
{
/* Eat until end of line. */
- while ( (c=es_getc (fp)) != EOF && c != '\n')
+ while ( (c=getc (fp)) != EOF && c != '\n')
;
err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG
: GPG_ERR_INCOMPLETE_LINE);
- log_error (_("file '%s', line %d: %s\n"),
+ log_error (_("file `%s', line %d: %s\n"),
fname, lnr, gpg_strerror (err));
continue;
}
- line[--n] = 0; /* Chop the LF. */
- if (n && line[n-1] == '\r')
- line[--n] = 0; /* Chop an optional CR. */
-
+ line[strlen(line)-1] = 0; /* Chop the LF. */
+
/* Allow for empty lines and spaces */
for (p=line; spacep (p); p++)
;
if (!*p || *p == '#')
continue;
-
+
if (!strncmp (p, "include-default", 15)
&& (!p[15] || spacep (p+15)))
{
@@ -189,7 +168,7 @@
if (!allow_include)
{
- log_error (_("statement \"%s\" ignored in '%s', line %d\n"),
+ log_error (_("statement \"%s\" ignored in `%s', line %d\n"),
"include-default", fname, lnr);
continue;
}
@@ -197,13 +176,13 @@
etcname = make_filename (gnupg_sysconfdir (), "trustlist.txt", NULL);
if ( !strcmp (etcname, fname) ) /* Same file. */
- log_info (_("statement \"%s\" ignored in '%s', line %d\n"),
+ log_info (_("statement \"%s\" ignored in `%s', line %d\n"),
"include-default", fname, lnr);
else if ( access (etcname, F_OK) && errno == ENOENT )
{
/* A non existent system trustlist is not an error.
Just print a note. */
- log_info (_("system trustlist '%s' not available\n"), etcname);
+ log_info (_("system trustlist `%s' not available\n"), etcname);
}
else
{
@@ -213,7 +192,7 @@
err = err2;
}
xfree (etcname);
-
+
continue;
}
@@ -221,7 +200,7 @@
{
trustitem_t *tmp;
size_t tmplen;
-
+
tmplen = tablesize + 20;
tmp = xtryrealloc (table, tmplen * sizeof *table);
if (!tmp)
@@ -247,14 +226,14 @@
n = hexcolon2bin (p, ti->fpr, 20);
if (n < 0)
{
- log_error (_("bad fingerprint in '%s', line %d\n"), fname, lnr);
- err = gpg_error (GPG_ERR_BAD_DATA);
+ log_error (_("bad fingerprint in `%s', line %d\n"), fname, lnr);
+ err = gpg_error (GPG_ERR_BAD_DATA);
continue;
}
p += n;
for (; spacep (p); p++)
;
-
+
/* Process the first flag which needs to be the first for
backward compatibility. */
if (!*p || *p == '*' )
@@ -272,14 +251,14 @@
}
else
{
- log_error (_("invalid keyflag in '%s', line %d\n"), fname, lnr);
+ log_error (_("invalid keyflag in `%s', line %d\n"), fname, lnr);
err = gpg_error (GPG_ERR_BAD_DATA);
continue;
}
p++;
if ( *p && !spacep (p) )
{
- log_error (_("invalid keyflag in '%s', line %d\n"), fname, lnr);
+ log_error (_("invalid keyflag in `%s', line %d\n"), fname, lnr);
err = gpg_error (GPG_ERR_BAD_DATA);
continue;
}
@@ -295,7 +274,7 @@
if (p[n] == '=')
{
log_error ("assigning a value to a flag is not yet supported; "
- "in '%s', line %d\n", fname, lnr);
+ "in `%s', line %d\n", fname, lnr);
err = gpg_error (GPG_ERR_BAD_DATA);
p++;
}
@@ -304,21 +283,22 @@
else if (n == 2 && !memcmp (p, "cm", 2))
ti->flags.cm = 1;
else
- log_error ("flag '%.*s' in '%s', line %d ignored\n",
+ log_error ("flag `%.*s' in `%s', line %d ignored\n",
n, p, fname, lnr);
p += n;
}
tableidx++;
}
- if ( !err && !es_feof (fp) )
+ if ( !err && !feof (fp) )
{
err = gpg_error_from_syserror ();
- log_error (_("error reading '%s', line %d: %s\n"),
+ log_error (_("error reading `%s', line %d: %s\n"),
fname, lnr, gpg_strerror (err));
}
leave:
- es_fclose (fp);
+ if (fp)
+ fclose (fp);
*addr_of_table = table;
*addr_of_tablesize = tablesize;
*addr_of_tableidx = tableidx;
@@ -326,8 +306,7 @@
}
-/* Read the trust files and update the global table on success. The
- trusttable is assumed to be locked. */
+/* Read the trust files and update the global table on success. */
static gpg_error_t
read_trustfiles (void)
{
@@ -352,7 +331,7 @@
else
{
err = gpg_error_from_syserror ();
- log_error (_("error opening '%s': %s\n"), fname, gpg_strerror (err));
+ log_error (_("error opening `%s': %s\n"), fname, gpg_strerror (err));
}
xfree (fname);
fname = make_filename (gnupg_sysconfdir (), "trustlist.txt", NULL);
@@ -368,7 +347,11 @@
if (gpg_err_code (err) == GPG_ERR_ENOENT)
{
/* Take a missing trustlist as an empty one. */
- clear_trusttable ();
+ lock_trusttable ();
+ xfree (trusttable);
+ trusttable = NULL;
+ trusttablesize = 0;
+ unlock_trusttable ();
err = 0;
}
return err;
@@ -383,23 +366,22 @@
return err;
}
- /* Replace the trusttable. */
+ lock_trusttable ();
xfree (trusttable);
trusttable = ti;
trusttablesize = tableidx;
+ unlock_trusttable ();
return 0;
}
+
/* Check whether the given fpr is in our trustdb. We expect FPR to be
- an all uppercase hexstring of 40 characters. If ALREADY_LOCKED is
- true the function assumes that the trusttable is already locked. */
-static gpg_error_t
-istrusted_internal (ctrl_t ctrl, const char *fpr, int *r_disabled,
- int already_locked)
+ an all uppercase hexstring of 40 characters. */
+gpg_error_t
+agent_istrusted (ctrl_t ctrl, const char *fpr, int *r_disabled)
{
gpg_error_t err;
- int locked = already_locked;
trustitem_t *ti;
size_t len;
unsigned char fprbin[20];
@@ -408,16 +390,7 @@
*r_disabled = 0;
if ( hexcolon2bin (fpr, fprbin, 20) < 0 )
- {
- err = gpg_error (GPG_ERR_INV_VALUE);
- goto leave;
- }
-
- if (!already_locked)
- {
- lock_trusttable ();
- locked = 1;
- }
+ return gpg_error (GPG_ERR_INV_VALUE);
if (!trusttable)
{
@@ -425,7 +398,7 @@
if (err)
{
log_error (_("error reading list of trusted root certificates\n"));
- goto leave;
+ return err;
}
}
@@ -437,48 +410,31 @@
if (ti->flags.disabled && r_disabled)
*r_disabled = 1;
- /* Print status messages only if we have not been called
- in a locked state. */
- if (already_locked)
- ;
- else if (ti->flags.relax)
+ if (ti->flags.relax)
{
- unlock_trusttable ();
- locked = 0;
- err = agent_write_status (ctrl, "TRUSTLISTFLAG", "relax", NULL);
+ err = agent_write_status (ctrl,
+ "TRUSTLISTFLAG", "relax",
+ NULL);
+ if (err)
+ return err;
}
else if (ti->flags.cm)
{
- unlock_trusttable ();
- locked = 0;
- err = agent_write_status (ctrl, "TRUSTLISTFLAG", "cm", NULL);
+ err = agent_write_status (ctrl,
+ "TRUSTLISTFLAG", "cm",
+ NULL);
+ if (err)
+ return err;
}
-
- if (!err)
- err = ti->flags.disabled? gpg_error (GPG_ERR_NOT_TRUSTED) : 0;
- goto leave;
+ return ti->flags.disabled? gpg_error (GPG_ERR_NOT_TRUSTED) : 0;
}
}
- err = gpg_error (GPG_ERR_NOT_TRUSTED);
-
- leave:
- if (locked && !already_locked)
- unlock_trusttable ();
- return err;
-}
-
-
-/* Check whether the given fpr is in our trustdb. We expect FPR to be
- an all uppercase hexstring of 40 characters. */
-gpg_error_t
-agent_istrusted (ctrl_t ctrl, const char *fpr, int *r_disabled)
-{
- return istrusted_internal (ctrl, fpr, r_disabled, 0);
+ return gpg_error (GPG_ERR_NOT_TRUSTED);
}
/* Write all trust entries to FP. */
-gpg_error_t
+gpg_error_t
agent_listtrusted (void *assuan_context)
{
trustitem_t *ti;
@@ -486,13 +442,11 @@
gpg_error_t err;
size_t len;
- lock_trusttable ();
if (!trusttable)
{
err = read_trustfiles ();
if (err)
{
- unlock_trusttable ();
log_error (_("error reading list of trusted root certificates\n"));
return err;
}
@@ -500,6 +454,9 @@
if (trusttable)
{
+ /* We need to lock the table because the scheduler may interrupt
+ assuan_send_data and an other thread may then re-read the table. */
+ lock_trusttable ();
for (ti=trusttable, len = trusttablesize; len; ti++, len--)
{
if (ti->flags.disabled)
@@ -512,9 +469,9 @@
assuan_send_data (assuan_context, key, 43);
assuan_send_data (assuan_context, NULL, 0); /* flush */
}
+ unlock_trusttable ();
}
- unlock_trusttable ();
return 0;
}
@@ -574,7 +531,7 @@
count++;
newname = xtrymalloc (strlen (name) + count*replstringlen + 1);
if (!newname)
- return NULL;
+ return NULL;
for (s=name+1, d=newname; *s; s++)
if (*s == '/')
d = stpcpy (d, replstring);
@@ -587,10 +544,10 @@
/* Insert the given fpr into our trustdb. We expect FPR to be an all
uppercase hexstring of 40 characters. FLAG is either 'P' or 'C'.
- This function does first check whether that key has already been
- put into the trustdb and returns success in this case. Before a
- FPR actually gets inserted, the user is asked by means of the
- Pinentry whether this is actual what he wants to do. */
+ This function does first check whether that key has already been put
+ into the trustdb and returns success in this case. Before a FPR
+ actually gets inserted, the user is asked by means of the Pinentry
+ whether this is actual want he wants to do. */
gpg_error_t
agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
{
@@ -613,7 +570,7 @@
{
xfree (fname);
return gpg_error (GPG_ERR_EPERM);
- }
+ }
xfree (fname);
if (!agent_istrusted (ctrl, fpr, &is_disabled))
@@ -621,7 +578,7 @@
return 0; /* We already got this fingerprint. Silently return
success. */
}
-
+
/* This feature must explicitly been enabled. */
if (!opt.allow_mark_trusted)
return gpg_error (GPG_ERR_NOT_SUPPORTED);
@@ -651,16 +608,16 @@
plain % sign, you need to encode it as "%%25". The
"%s" gets replaced by the name as stored in the
certificate. */
- L_("Do you ultimately trust%%0A"
- " \"%s\"%%0A"
- "to correctly certify user certificates?"),
+ _("Do you ultimately trust%%0A"
+ " \"%s\"%%0A"
+ "to correctly certify user certificates?"),
nameformatted);
if (!desc)
{
xfree (nameformatted);
return out_of_core ();
}
- err = agent_get_confirmation (ctrl, desc, L_("Yes"), L_("No"), 1);
+ err = agent_get_confirmation (ctrl, desc, _("Yes"), _("No"), 1);
xfree (desc);
if (!err)
yes_i_trust = 1;
@@ -671,7 +628,7 @@
xfree (nameformatted);
return err;
}
-
+
fprformatted = insert_colons (fpr);
if (!fprformatted)
@@ -684,7 +641,7 @@
fingerprint of course. */
if (yes_i_trust)
{
- desc = xtryasprintf
+ desc = xtryasprintf
(
/* TRANSLATORS: This prompt is shown by the Pinentry and has
one special property: A "%%0A" is used by Pinentry to
@@ -694,21 +651,21 @@
"%%25". The second "%s" gets replaced by a hexdecimal
fingerprint string whereas the first one receives the name
as stored in the certificate. */
- L_("Please verify that the certificate identified as:%%0A"
- " \"%s\"%%0A"
- "has the fingerprint:%%0A"
- " %s"), nameformatted, fprformatted);
+ _("Please verify that the certificate identified as:%%0A"
+ " \"%s\"%%0A"
+ "has the fingerprint:%%0A"
+ " %s"), nameformatted, fprformatted);
if (!desc)
{
xfree (fprformatted);
xfree (nameformatted);
return out_of_core ();
}
-
+
/* TRANSLATORS: "Correct" is the label of a button and intended
to be hit if the fingerprint matches the one of the CA. The
other button is "the default "Cancel" of the Pinentry. */
- err = agent_get_confirmation (ctrl, desc, L_("Correct"), L_("Wrong"), 1);
+ err = agent_get_confirmation (ctrl, desc, _("Correct"), _("Wrong"), 1);
xfree (desc);
if (gpg_err_code (err) == GPG_ERR_NOT_CONFIRMED)
yes_i_trust = 0;
@@ -724,23 +681,23 @@
/* Now check again to avoid duplicates. We take the lock to make
sure that nobody else plays with our file and force a reread. */
lock_trusttable ();
- clear_trusttable ();
- if (!istrusted_internal (ctrl, fpr, &is_disabled, 1) || is_disabled)
+ agent_reload_trustlist ();
+ if (!agent_istrusted (ctrl, fpr, &is_disabled) || is_disabled)
{
unlock_trusttable ();
xfree (fprformatted);
xfree (nameformatted);
- return is_disabled? gpg_error (GPG_ERR_NOT_TRUSTED) : 0;
+ return is_disabled? gpg_error (GPG_ERR_NOT_TRUSTED) : 0;
}
fname = make_filename (opt.homedir, "trustlist.txt", NULL);
if ( access (fname, F_OK) && errno == ENOENT)
{
- fp = es_fopen (fname, "wx,mode=-rw-r");
+ fp = es_fopen (fname, "wx");
if (!fp)
{
err = gpg_error_from_syserror ();
- log_error ("can't create '%s': %s\n", fname, gpg_strerror (err));
+ log_error ("can't create `%s': %s\n", fname, gpg_strerror (err));
xfree (fname);
unlock_trusttable ();
xfree (fprformatted);
@@ -750,11 +707,11 @@
es_fputs (headerblurb, fp);
es_fclose (fp);
}
- fp = es_fopen (fname, "a+,mode=-rw-r");
+ fp = es_fopen (fname, "a+");
if (!fp)
{
err = gpg_error_from_syserror ();
- log_error ("can't open '%s': %s\n", fname, gpg_strerror (err));
+ log_error ("can't open `%s': %s\n", fname, gpg_strerror (err));
xfree (fname);
unlock_trusttable ();
xfree (fprformatted);
@@ -778,17 +735,15 @@
flag == 'S'? " relax":"");
if (es_ferror (fp))
err = gpg_error_from_syserror ();
-
+
if (es_fclose (fp))
err = gpg_error_from_syserror ();
- clear_trusttable ();
+ agent_reload_trustlist ();
xfree (fname);
unlock_trusttable ();
xfree (fprformatted);
xfree (nameformatted);
- if (!err)
- bump_key_eventcounter ();
return err;
}
@@ -801,7 +756,9 @@
/* All we need to do is to delete the trusttable. At the next
access it will get re-read. */
lock_trusttable ();
- clear_trusttable ();
+ xfree (trusttable);
+ trusttable = NULL;
+ trusttablesize = 0;
unlock_trusttable ();
bump_key_eventcounter ();
}
diff -Nru gnupg2-2.1.6~build1/am/cmacros.am gnupg2-2.0.28/am/cmacros.am
--- gnupg2-2.1.6~build1/am/cmacros.am 2015-06-17 06:39:24.000000000 +0000
+++ gnupg2-2.0.28/am/cmacros.am 2015-06-02 08:13:55.000000000 +0000
@@ -18,8 +18,6 @@
localedir = $(datadir)/locale
-# NB: AM_CFLAGS may also be used by tools running on the build
-# platform to create source files.
AM_CPPFLAGS += -DLOCALEDIR=\"$(localedir)\"
if ! HAVE_DOSISH_SYSTEM
@@ -27,8 +25,7 @@
-DGNUPG_LIBEXECDIR="\"$(libexecdir)\"" \
-DGNUPG_LIBDIR="\"$(libdir)/@PACKAGE@\"" \
-DGNUPG_DATADIR="\"$(datadir)/@PACKAGE@\"" \
- -DGNUPG_SYSCONFDIR="\"$(sysconfdir)/@PACKAGE@\"" \
- -DGNUPG_LOCALSTATEDIR="\"$(localstatedir)\""
+ -DGNUPG_SYSCONFDIR="\"$(sysconfdir)/@PACKAGE@\""
endif
@@ -50,22 +47,6 @@
if GNUPG_PROTECT_TOOL_PGM
AM_CPPFLAGS += -DGNUPG_DEFAULT_PROTECT_TOOL="\"@GNUPG_PROTECT_TOOL_PGM@\""
endif
-if GNUPG_DIRMNGR_LDAP_PGM
-AM_CPPFLAGS += -DGNUPG_DEFAULT_DIRMNGR_LDAP="\"@GNUPG_DIRMNGR_LDAP_PGM@\""
-endif
-
-# Under Windows we use LockFileEx. WindowsCE provides this only on
-# the WindowsMobile 6 platform and thus we need to use the coredll6
-# import library. We also want to use a stacksize of 256k instead of
-# the 2MB which is the default with cegcc. 256k is the largest stack
-# we use with pth.
-if HAVE_W32CE_SYSTEM
-extra_sys_libs = -lcoredll6
-extra_bin_ldflags = -Wl,--stack=0x40000
-else
-extra_sys_libs =
-extra_bin_ldflags =
-endif
if HAVE_W32_SYSTEM
.rc.o:
@@ -77,5 +58,4 @@
# Convenience macros
libcommon = ../common/libcommon.a
libcommonpth = ../common/libcommonpth.a
-libcommontls = ../common/libcommontls.a
-libcommontlsnpth = ../common/libcommontlsnpth.a
+
diff -Nru gnupg2-2.1.6~build1/AUTHORS gnupg2-2.0.28/AUTHORS
--- gnupg2-2.1.6~build1/AUTHORS 2015-06-17 06:39:24.000000000 +0000
+++ gnupg2-2.0.28/AUTHORS 2015-06-02 08:13:55.000000000 +0000
@@ -1,7 +1,5 @@
Program: GnuPG
Homepage: https://www.gnupg.org
-Download: ftp://ftp.gnupg.org/gcrypt/gnupg/
-Repository: git://git.gnupg.org/gnupg.git
Maintainer: Werner Koch
Bug reports: http://bugs.gnupg.org
Security related bug reports:
@@ -12,37 +10,12 @@
2000-2013, indicating that every year in the range, inclusive, is a
copyrightable year that would otherwise be listed individually.
-List of Copyright holders
-=========================
-
- Copyright (C) 1997-2015 Werner Koch
- Copyright (C) 1994-2015 Free Software Foundation, Inc.
- Copyright (C) 2003-2013 g10 Code GmbH
- Copyright (C) 2002 Klarälvdalens Datakonsult AB
- Copyright (C) 1995-1997, 2000-2007 Ulrich Drepper
- Copyright (C) 1994 X Consortium
- Copyright (C) 1998 by The Internet Society.
- Copyright (C) 1998-2004 The OpenLDAP Foundation
- Copyright (C) 1998-2004 Kurt D. Zeilenga.
- Copyright (C) 1998-2004 Net Boolean Incorporated.
- Copyright (C) 2001-2004 IBM Corporation.
- Copyright (C) 1999-2003 Howard Y.H. Chu.
- Copyright (C) 1999-2003 Symas Corporation.
- Copyright (C) 1998-2003 Hallvard B. Furuseth.
- Copyright (C) 1992-1996 Regents of the University of Michigan.
-
-
Authors with a FSF copyright assignment
=======================================
Ales Nyakhaychyk Translations [be]
-Andrey Jivsov Assigns past and future changes for ECC.
- (g10/ecdh.c. other changes to support ECC)
-
-Ben Kibbey Assigns past and future changes.
-
Birger Langkjer Translations [da]
Maxim Britov Translations [ru]
@@ -125,6 +98,8 @@
Pedro Morais Translations [pt_PT]
+Petr Pisar Translations [cs]
+
Rémi Guyomarch Assigns past and future changes.
(g10/compress.c, g10/encr-data.c,
g10/free-packet.c, g10/mdfilter.c, g10/plaintext.c, util/iobuf.c)
@@ -154,45 +129,12 @@
Yuri Chornoivan, yurchor at ukr dot net: Translations [uk]
-Yutaka Niibe Assigns Past and Future Changes
- (scd/)
-
Authors with a DCO
==================
-Andre Heinecke
-2014-09-19:4525694.FcpLvWDUFT@esus:
-
-Andreas Schwier
-2014-07-22:53CED1D8.1010306@cardcontact.de:
-
-Christian Aistleitner
-2013-05-26:20130626112332.GA2228@quelltextlich.at:
-
-Damien Goutte-Gattat
-2015-01-17:54BA49AA.2040708@incenp.org:
-
-Daniel Kahn Gillmor
-2014-09-24:87oau6w9q7.fsf@alice.fifthhorseman.net:
-
-Hans of Guardian
-2013-06-26:D84473D7-F3F7-43D5-A9CE-16580B88D574@guardianproject.info:
-
-Jonas Borgström
-2013-08-29:521F1E7A.5080602@borgstrom.se:
-
-Joshua Rogers
-2014-12-22:5497FE75.7010503@internot.info:
-
-Kyle Butt
-2013-05-29:CAAODAYLbCtqOG6msLLL0UTdASKWT6u2ptxsgUQ1JpusBESBoNQ@mail.gmail.com:
-
-Stefan Tomanek
-2014-01-30:20140129234449.GY30808@zirkel.wertarbyte.de:
-
-Werner Koch
-2013-03-29:87620ahchj.fsf@vigenere.g10code.de:
+The list of authors who signed the Developer's Certificate of Origin
+is kept in the GIT master branch's copy of this file.
Other authors
@@ -202,6 +144,10 @@
2013-03-29; the need for copyright disclaimers for translations
already in December 2012.
+The files common/libestream.[ch] are maintained as a separate project
+by g10 Code GmbH. These files, as used here, are considered part of
+GnuPG.
+
The RPM specs file scripts/gnupg.spec has been contributed by
several people.
@@ -216,18 +162,31 @@
=========
GnuPG is distributed under the GNU General Public License, version 3
-or later.
-
-Note that some files are under a combination of the GNU Lesser General
-Public License, version 3 and the GNU General Public License, version
-2. A few other files carry the all permissive license note as found
-at the bottom of this file.
+or later. A few files are under the Lesser General Public License, a
+few other files carry the all permissive license note as found at the
+bottom of this file. Certain files in keyserver/ allow one specific
+exception:
+
+ In addition, as a special exception, the Free Software Foundation
+ gives permission to link the code of the keyserver helper tools:
+ gpgkeys_ldap, gpgkeys_curl and gpgkeys_hkp with the OpenSSL
+ project's "OpenSSL" library (or with modified versions of it that
+ use the same license as the "OpenSSL" library), and distribute the
+ linked executables. You must obey the GNU General Public License
+ in all respects for all of the code used other than "OpenSSL". If
+ you modify this file, you may extend this exception to your version
+ of the file, but you are not obligated to do so. If you do not
+ wish to do so, delete this exception statement from your version.
+Note that the gpgkeys_* binaries are currently installed under the
+name gpg2keys_*.
=========
- Copyright 1998-2013 Free Software Foundation, Inc.
- Copyright 1997-2014 Werner Koch
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ 2006, 2007, 2008, 2009, 2010, 2011,
+ 2012, 2013 Free Software Foundation, Inc.
+ Copyright 1997, 1998, 2013, 2014 Werner Koch
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without
@@ -236,3 +195,4 @@
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
diff -Nru gnupg2-2.1.6~build1/autogen.rc gnupg2-2.0.28/autogen.rc
--- gnupg2-2.1.6~build1/autogen.rc 2015-06-17 06:39:24.000000000 +0000
+++ gnupg2-2.0.28/autogen.rc 1970-01-01 00:00:00.000000000 +0000
@@ -1,45 +0,0 @@
-# autogen.sh configuration for GnuPG -*- sh -*-
-
-#version_parts=3
-
-case "$myhost:$myhostsub" in
- w32:ce)
- extraoptions="--enable-dirmngr-auto-start --disable-scdaemon "
- extraoptions="$extraoptions --disable-zip --enable-gpg2-is-gpg"
- ;;
- w32:)
- extraoptions="--enable-gpgtar"
- ;;
-esac
-
-case "$myhost" in
- w32)
- configure_opts="
- --with-gpg-error-prefix=@SYSROOT@
- --with-ksba-prefix=@SYSROOT@
- --with-libgcrypt-prefix=@SYSROOT@
- --with-libassuan-prefix=@SYSROOT@
- --with-zlib=@SYSROOT@
- --with-regex=@SYSROOT@
- --with-npth-prefix=@SYSROOT@
- --with-adns=@SYSROOT@
- --disable-g13
- "
- ;;
-
- amd64)
- configure_opts="
- --with-gpg-error-prefix=@SYSROOT@
- --with-ksba-prefix=@SYSROOT@
- --with-libgcrypt-prefix=@SYSROOT@
- --with-libassuan-prefix=@SYSROOT@
- --with-zlib=/usr/x86_64-linux-gnu/usr
- --with-pth-prefix=/usr/x86_64-linux-gnu/usr
- "
- ;;
-esac
-
-
-extra_aclocal_flags=""
-
-final_info="./configure --sysconfdir=/etc --enable-maintainer-mode && make"
diff -Nru gnupg2-2.1.6~build1/autogen.sh gnupg2-2.0.28/autogen.sh
--- gnupg2-2.1.6~build1/autogen.sh 2015-06-17 06:39:24.000000000 +0000
+++ gnupg2-2.0.28/autogen.sh 2015-06-02 08:13:55.000000000 +0000
@@ -1,6 +1,7 @@
#! /bin/sh
-# autogen.sh
-# Copyright (C) 2003, 2014 g10 Code GmbH
+# Run this to generate all the initial makefiles, etc.
+#
+# Copyright (C) 2003 g10 Code GmbH
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
@@ -9,13 +10,6 @@
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-#
-# This is a generic script to create the configure script and handle cross
-# build environments. It requires the presence of a autogen.rc file to
-# configure it for the respective package. It is maintained as part of
-# GnuPG and source copied by other packages.
-#
-# Version: 2014-06-06
configure_ac="configure.ac"
@@ -24,7 +18,7 @@
}
check_version () {
- if [ $(( `("$1" --version || echo "0") | cvtver` >= $2 )) = 1 ]; then
+ if [ `("$1" --version || echo "0") | cvtver` -ge "$2" ]; then
return 0
fi
echo "**Error**: "\`$1\'" not installed or too old." >&2
@@ -34,29 +28,6 @@
return 1
}
-fatal () {
- echo "autogen.sh:" "$*" >&2
- DIE=yes
-}
-
-info () {
- if [ -z "${SILENT}" ]; then
- echo "autogen.sh:" "$*" >&2
- fi
-}
-
-die_p () {
- if [ "$DIE" = "yes" ]; then
- echo "autogen.sh: Stop." >&2
- exit 1
- fi
-}
-
-replace_sysroot () {
- configure_opts=$(echo $configure_opts | sed "s#@SYSROOT@#${w32root}#g")
- extraoptions=$(echo $extraoptions | sed "s#@SYSROOT@#${w32root}#g")
-}
-
# Allow to override the default tool names
AUTOCONF=${AUTOCONF_PREFIX}${AUTOCONF:-autoconf}${AUTOCONF_SUFFIX}
AUTOHEADER=${AUTOCONF_PREFIX}${AUTOHEADER:-autoheader}${AUTOCONF_SUFFIX}
@@ -69,219 +40,29 @@
DIE=no
FORCE=
-SILENT=
-PRINT_HOST=no
-PRINT_BUILD=no
-tmp=$(dirname "$0")
-tsdir=$(cd "${tmp}"; pwd)
-version_parts=3
-
-if [ -n "${AUTOGEN_SH_SILENT}" ]; then
- SILENT=" --silent"
-fi
-if test x"$1" = x"--help"; then
- echo "usage: ./autogen.sh [--silent] [--force] [--build-TYPE] [ARGS]"
- exit 0
-fi
-if test x"$1" = x"--silent"; then
- SILENT=" --silent"
- shift
-fi
if test x"$1" = x"--force"; then
FORCE=" --force"
shift
fi
-if test x"$1" = x"--print-host"; then
- PRINT_HOST=yes
- shift
-fi
-if test x"$1" = x"--print-build"; then
- PRINT_BUILD=yes
- shift
-fi
-
-# Reject unsafe characters in $HOME, $tsdir and cwd. We consider spaces
-# as unsafe because it is too easy to get scripts wrong in this regard.
-am_lf='
-'
-case `pwd` in
- *[\;\\\"\#\$\&\'\`$am_lf\ \ ]*)
- fatal "unsafe working directory name" ;;
-esac
-case $tsdir in
- *[\;\\\"\#\$\&\'\`$am_lf\ \ ]*)
- fatal "unsafe source directory: \`$tsdir'" ;;
-esac
-case $HOME in
- *[\;\\\"\#\$\&\'\`$am_lf\ \ ]*)
- fatal "unsafe home directory: \`$HOME'" ;;
-esac
-die_p
-
-
-# List of variables sourced from autogen.rc. The strings '@SYSROOT@' in
-# these variables are replaced by the actual system root.
-configure_opts=
-extraoptions=
-# List of optional variables sourced from autogen.rc and ~/.gnupg-autogen.rc
-w32_toolprefixes=
-w32_extraoptions=
-w32ce_toolprefixes=
-w32ce_extraoptions=
-w64_toolprefixes=
-w64_extraoptions=
-amd64_toolprefixes=
-# End list of optional variables sourced from ~/.gnupg-autogen.rc
-# What follows are variables which are sourced but default to
-# environment variables or lacking them hardcoded values.
-#w32root=
-#w32ce_root=
-#w64root=
-#amd64root=
-
-# Convenience option to use certain configure options for some hosts.
-myhost=""
-myhostsub=""
-case "$1" in
- --find-version)
- myhost="find-version"
- SILENT=" --silent"
- shift
- ;;
- --build-w32)
- myhost="w32"
- shift
- ;;
- --build-w32ce)
- myhost="w32"
- myhostsub="ce"
- shift
- ;;
- --build-w64)
- myhost="w32"
- myhostsub="64"
- shift
- ;;
- --build-amd64)
- myhost="amd64"
- shift
- ;;
- --build*)
- fatal "**Error**: invalid build option $1"
- shift
- ;;
- *)
- ;;
-esac
-die_p
-
-
-# Source our configuration
-if [ -f "${tsdir}/autogen.rc" ]; then
- . "${tsdir}/autogen.rc"
-fi
-
-# Source optional site specific configuration
-if [ -f "$HOME/.gnupg-autogen.rc" ]; then
- info "sourcing extra definitions from $HOME/.gnupg-autogen.rc"
- . "$HOME/.gnupg-autogen.rc"
-fi
-
-
-# **** FIND VERSION ****
-# This is a helper for the configure.ac M4 magic
-# Called
-# ./autogen.sh --find-version PACKAGE MAJOR MINOR [MICRO]
-# returns a complete version string with automatic beta numbering.
-if [ "$myhost" = "find-version" ]; then
- package="$1"
- major="$2"
- minor="$3"
- micro="$4"
-
- case "$version_parts" in
- 2)
- matchstr1="$package-$major.[0-9]*"
- matchstr2="$package-$major-base"
- vers="$major.$minor"
- ;;
- *)
- matchstr1="$package-$major.$minor.[0-9]*"
- matchstr2="$package-$major.$minor-base"
- vers="$major.$minor.$micro"
- ;;
- esac
-
- beta=no
- if [ -d .git ]; then
- ingit=yes
- tmp=$(git describe --match "${matchstr1}" --long 2>/dev/null)
- if [ -n "$tmp" ]; then
- tmp=$(echo "$tmp"|awk -F- '$3!=0 && $3 !~ /^beta/ {print"-beta"$3}')
- else
- tmp=$(git describe --match "${matchstr2}" --long 2>/dev/null \
- | awk -F- '$4!=0{print"-beta"$4}')
- fi
- [ -n "$tmp" ] && beta=yes
- rev=$(git rev-parse --short HEAD | tr -d '\n\r')
- rvd=$((0x$(echo ${rev} | head -c 4)))
- else
- ingit=no
- beta=yes
- tmp="-unknown"
- rev="0000000"
- rvd="0"
+# ***** W32 build script *******
+# Used to cross-compile for Windows.
+if test "$1" = "--build-w32"; then
+ tmp=`dirname $0`
+ tsdir=`cd "$tmp"; pwd`
+ shift
+ if [ ! -f $tsdir/scripts/config.guess ]; then
+ echo "$tsdir/scripts/config.guess not found" >&2
+ exit 1
fi
+ build=`$tsdir/scripts/config.guess`
- echo "$package-$vers$tmp:$beta:$ingit:$vers$tmp:$vers:$tmp:$rev:$rvd:"
- exit 0
-fi
-# **** end FIND VERSION ****
-
-
-if [ ! -f "$tsdir/build-aux/config.guess" ]; then
- fatal "$tsdir/build-aux/config.guess not found"
- exit 1
-fi
-build=`$tsdir/build-aux/config.guess`
-if [ $PRINT_BUILD = yes ]; then
- echo "$build"
- exit 0
-fi
-
-
-
-# ******************
-# W32 build script
-# ******************
-if [ "$myhost" = "w32" ]; then
- case $myhostsub in
- ce)
- w32root="$w32ce_root"
- [ -z "$w32root" ] && w32root="$HOME/w32ce_root"
- toolprefixes="$w32ce_toolprefixes arm-mingw32ce"
- extraoptions="$extraoptions $w32ce_extraoptions"
- ;;
- 64)
- w32root="$w64root"
- [ -z "$w32root" ] && w32root="$HOME/w64root"
- toolprefixes="$w64_toolprefixes x86_64-w64-mingw32"
- extraoptions="$extraoptions $w64_extraoptions"
- ;;
- *)
- [ -z "$w32root" ] && w32root="$HOME/w32root"
- toolprefixes="$w32_toolprefixes i686-w64-mingw32 i586-mingw32msvc"
- toolprefixes="$toolprefixes i386-mingw32msvc mingw32"
- extraoptions="$extraoptions $w32_extraoptions"
- ;;
- esac
- info "Using $w32root as standard install directory"
- replace_sysroot
+ [ -z "$w32root" ] && w32root="$HOME/w32root"
+ echo "Using $w32root as standard install directory" >&2
# Locate the cross compiler
crossbindir=
- for host in $toolprefixes; do
+ for host in i686-w64-mingw32 i586-mingw32msvc i386-mingw32msvc mingw32; do
if ${host}-gcc --version >/dev/null 2>&1 ; then
crossbindir=/usr/${host}/bin
conf_CC="CC=${host}-gcc"
@@ -289,29 +70,32 @@
fi
done
if [ -z "$crossbindir" ]; then
- fatal "cross compiler kit not installed"
- if [ -z "$myhostsub" ]; then
- info "Under Debian GNU/Linux, you may install it using"
- info " apt-get install mingw32 mingw32-runtime mingw32-binutils"
- fi
- die_p
- fi
- if [ $PRINT_HOST = yes ]; then
- echo "$host"
- exit 0
+ echo "Cross compiler kit not installed" >&2
+ echo "Under Debian GNU/Linux, you may install it using" >&2
+ echo " apt-get install mingw32 mingw32-runtime mingw32-binutils" >&2
+ echo "Stop." >&2
+ exit 1
fi
if [ -f "$tsdir/config.log" ]; then
if ! head $tsdir/config.log | grep "$host" >/dev/null; then
- fatal "Please run a 'make distclean' first"
- die_p
+ echo "Please run a 'make distclean' first" >&2
+ exit 1
fi
fi
- $tsdir/configure --enable-maintainer-mode ${SILENT} \
- --prefix=${w32root} \
- --host=${host} --build=${build} SYSROOT=${w32root} \
- ${configure_opts} ${extraoptions} "$@"
+ $tsdir/configure --enable-maintainer-mode --prefix=${w32root} \
+ --host=${host} --build=${build} \
+ --enable-gpgtar \
+ --with-gpg-error-prefix=${w32root} \
+ --with-ksba-prefix=${w32root} \
+ --with-libgcrypt-prefix=${w32root} \
+ --with-libassuan-prefix=${w32root} \
+ --with-zlib=${w32root} \
+ --with-regex=${w32root} \
+ --with-pth-prefix=${w32root} \
+ --with-libiconv-prefix=${w32root} \
+ --with-adns=${w32root} "$@"
rc=$?
exit $rc
fi
@@ -319,16 +103,22 @@
# ***** AMD64 cross build script *******
# Used to cross-compile for AMD64 (for testing)
-if [ "$myhost" = "amd64" ]; then
- [ -z "$amd64root" ] && amd64root="$HOME/amd64root"
- info "Using $amd64root as standard install directory"
- replace_sysroot
+if test "$1" = "--build-amd64"; then
+ tmp=`dirname $0`
+ tsdir=`cd "$tmp"; pwd`
+ shift
+ if [ ! -f $tsdir/scripts/config.guess ]; then
+ echo "$tsdir/scripts/config.guess not found" >&2
+ exit 1
+ fi
+ build=`$tsdir/scripts/config.guess`
- toolprefixes="$amd64_toolprefixes x86_64-linux-gnu amd64-linux-gnu"
+ [ -z "$amd64root" ] && amd64root="$HOME/amd64root"
+ echo "Using $amd64root as standard install directory" >&2
# Locate the cross compiler
crossbindir=
- for host in $toolprefixes ; do
+ for host in x86_64-linux-gnu amd64-linux-gnu; do
if ${host}-gcc --version >/dev/null 2>&1 ; then
crossbindir=/usr/${host}/bin
conf_CC="CC=${host}-gcc"
@@ -340,10 +130,6 @@
echo "Stop." >&2
exit 1
fi
- if [ $PRINT_HOST = yes ]; then
- echo "$host"
- exit 0
- fi
if [ -f "$tsdir/config.log" ]; then
if ! head $tsdir/config.log | grep "$host" >/dev/null; then
@@ -352,10 +138,14 @@
fi
fi
- $tsdir/configure --enable-maintainer-mode ${SILENT} \
- --prefix=${amd64root} \
+ $tsdir/configure --enable-maintainer-mode --prefix=${amd64root} \
--host=${host} --build=${build} \
- ${configure_opts} ${extraoptions} "$@"
+ --with-gpg-error-prefix=${amd64root} \
+ --with-ksba-prefix=${amd64root} \
+ --with-libgcrypt-prefix=${amd64root} \
+ --with-libassuan-prefix=${amd64root} \
+ --with-zlib=/usr/x86_64-linux-gnu/usr \
+ --with-pth-prefix=/usr/x86_64-linux-gnu/usr
rc=$?
exit $rc
fi
@@ -375,15 +165,12 @@
}' ${configure_ac}`
automake_vers_num=`echo "$automake_vers" | cvtver`
-if [ -d "${tsdir}/po" ]; then
- gettext_vers=`sed -n '/^AM_GNU_GETTEXT_VERSION(/ {
+gettext_vers=`sed -n '/^AM_GNU_GETTEXT_VERSION(/ {
s/^.*\[\(.*\)])/\1/p
q
}' ${configure_ac}`
- gettext_vers_num=`echo "$gettext_vers" | cvtver`
-else
- gettext_vers="n/a"
-fi
+gettext_vers_num=`echo "$gettext_vers" | cvtver`
+
if [ -z "$autoconf_vers" -o -z "$automake_vers" -o -z "$gettext_vers" ]
then
@@ -398,71 +185,60 @@
if check_version $AUTOMAKE $automake_vers_num $automake_vers; then
check_version $ACLOCAL $automake_vers_num $autoconf_vers automake
fi
-if [ "$gettext_vers" != "n/a" ]; then
- if check_version $GETTEXT $gettext_vers_num $gettext_vers; then
- check_version $MSGMERGE $gettext_vers_num $gettext_vers gettext
- fi
+if check_version $GETTEXT $gettext_vers_num $gettext_vers; then
+ check_version $MSGMERGE $gettext_vers_num $gettext_vers gettext
fi
-if [ "$DIE" = "yes" ]; then
+if test "$DIE" = "yes"; then
cat <&2
*** Activating trailing whitespace git pre-commit hook. ***
For more information see this thread:
http://mail.gnome.org/archives/desktop-devel-list/2009-May/msg00084html
To deactivate this pre-commit hook again move .git/hooks/pre-commit
and .git/hooks/pre-commit.sample out of the way.
EOF
- $CP .git/hooks/pre-commit.sample .git/hooks/pre-commit
- chmod +x .git/hooks/pre-commit
+ cp .git/hooks/pre-commit.sample .git/hooks/pre-commit
+ chmod -c +x .git/hooks/pre-commit
fi
-
- if [ "$gettext_vers" != "n/a" ]; then
- tmp=$(git config --get filter.cleanpo.clean)
- if [ "$tmp" != \
- "awk '/^\"POT-Creation-Date:/&&!s{s=1;next};!/^#: /{print}'" ]
- then
- info "*** Adding GIT filter.cleanpo.clean configuration."
- git config --add filter.cleanpo.clean \
+ tmp=$(git config --get filter.cleanpo.clean)
+ if [ "$tmp" != "awk '/^\"POT-Creation-Date:/&&!s{s=1;next};!/^#: /{print}'" ]
+ then
+ echo "*** Adding GIT filter.cleanpo.clean configuration." >&2
+ git config --add filter.cleanpo.clean \
"awk '/^\"POT-Creation-Date:/&&!s{s=1;next};!/^#: /{print}'"
- fi
fi
- if [ -f build-aux/git-hooks/commit-msg -a ! -f .git/hooks/commit-msg ] ; then
- [ -z "${SILENT}" ] && cat <&2
*** Activating commit log message check hook. ***
EOF
- $CP build-aux/git-hooks/commit-msg .git/hooks/commit-msg
- chmod +x .git/hooks/commit-msg
+ cp scripts/git-hooks/commit-msg .git/hooks/commit-msg
+ chmod -c +x .git/hooks/commit-msg
fi
fi
-aclocal_flags="-I m4"
-if [ -n "${extra_aclocal_flags}" ]; then
- aclocal_flags="${aclocal_flags} ${extra_aclocal_flags}"
-fi
-if [ -n "${ACLOCAL_FLAGS}" ]; then
- aclocal_flags="${aclocal_flags} ${ACLOCAL_FLAGS}"
-fi
-info "Running $ACLOCAL ${aclocal_flags} ..."
-$ACLOCAL ${aclocal_flags}
-info "Running autoheader..."
+
+echo "Running aclocal -I m4 -I gl/m4 ${ACLOCAL_FLAGS:+$ACLOCAL_FLAGS }..."
+$ACLOCAL -I m4 -I gl/m4 $ACLOCAL_FLAGS
+echo "Running autoheader..."
$AUTOHEADER
-info "Running automake --gnu ..."
+echo "Running automake --gnu ..."
$AUTOMAKE --gnu;
-info "Running autoconf${FORCE} ..."
+echo "Running autoconf${FORCE} ..."
$AUTOCONF${FORCE}
-info "You may now run:${am_lf} ${final_info}"
+echo "You may now run:
+ ./configure --sysconfdir=/etc --enable-maintainer-mode --enable-symcryptrun --enable-mailto --enable-gpgtar && make
+"
diff -Nru gnupg2-2.1.6~build1/build-aux/ChangeLog-2011 gnupg2-2.0.28/build-aux/ChangeLog-2011
--- gnupg2-2.1.6~build1/build-aux/ChangeLog-2011 2015-06-17 06:39:24.000000000 +0000
+++ gnupg2-2.0.28/build-aux/ChangeLog-2011 1970-01-01 00:00:00.000000000 +0000
@@ -1,62 +0,0 @@
-2011-12-01 Werner Koch
-
- NB: ChangeLog files are no longer manually maintained. Starting
- on December 1st, 2011 we put change information only in the GIT
- commit log, and generate a top-level ChangeLog file from logs at
- "make dist". See doc/HACKING for details.
-
-2011-11-29 Werner Koch