1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00

This commit was manufactured by cvs2svn to create branch

'GNUPG-1-9-BRANCH'.
This commit is contained in:
Repo Admin 2002-10-19 07:55:27 +00:00
parent 8d76177f10
commit 82a17c9fb3
563 changed files with 0 additions and 267875 deletions

324
ABOUT-NLS
View File

@ -1,324 +0,0 @@
Notes on the Free Translation Project
*************************************
Free software is going international! The Free Translation Project
is a way to get maintainers of free software, translators, and users all
together, so that will gradually become able to speak many languages.
A few packages already provide translations for their messages.
If you found this `ABOUT-NLS' file inside a distribution, you may
assume that the distributed package does use GNU `gettext' internally,
itself available at your nearest GNU archive site. But you do _not_
need to install GNU `gettext' prior to configuring, installing or using
this package with messages translated.
Installers will find here some useful hints. These notes also
explain how users should proceed for getting the programs to use the
available translations. They tell how people wanting to contribute and
work at translations should 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.
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'.
INSTALL Matters
===============
Some packages are "localizable" when properly installed; the
programs they contain can be made to speak your own native language.
Most such packages use GNU `gettext'. Other packages have their own
ways to internationalization, predating GNU `gettext'.
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 GNU `gettext' own
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:
./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.
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 be not what is 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.
Internationalized packages have usually many `po/LL.po' files, where
LL gives an ISO 639 two-letter code identifying the language. Unless
translations have been forbidden at `configure' time by using the
`--disable-nls' switch, all available translations are installed
together with the package. However, the environment variable `LINGUAS'
may be set, prior to configuration, to limit the installed set.
`LINGUAS' should then contain a space separated list of two-letter
codes, stating which languages are allowed.
Using This Package
==================
As a user, if your language has been installed for this package, you
only have to set the `LANG' environment variable to the appropriate
`LL_CC' combination. Here `LL' is an ISO 639 two-letter language code,
and `CC' is an ISO 3166 two-letter country code. For example, let's
suppose that you speak German and live in Germany. At the shell
prompt, merely execute `setenv LANG de_DE' (in `csh'),
`export LANG; LANG=de_DE' (in `sh') or `export LANG=de_DE' (in `bash').
This can be done from your `.login' or `.profile' file, once and for
all.
You might think that the country code specification is redundant.
But in fact, some languages have dialects in different countries. For
example, `de_AT' is used for Austria, and `pt_BR' for Brazil. The
country code serves to distinguish the dialects.
Not all programs have translations for all languages. By default, an
English message is shown in place of a nonexistent translation. If you
understand other languages, you can set up a priority list of languages.
This is done through a different environment variable, called
`LANGUAGE'. GNU `gettext' gives preference to `LANGUAGE' over `LANG'
for the purpose of message handling, but you still need to have `LANG'
set to the primary language; this is required by other parts of the
system libraries. For example, some Swedish users who would rather
read translations in German than English for when Swedish is not
available, set `LANGUAGE' to `sv:de' while leaving `LANG' to `sv_SE'.
In the `LANGUAGE' environment variable, but not in the `LANG'
environment variable, `LL_CC' combinations can be abbreviated as `LL'
to denote the language's main dialect. For example, `de' is equivalent
to `de_DE' (German as spoken in Germany), and `pt' to `pt_PT'
(Portuguese as spoken in Portugal) in this context.
Translating Teams
=================
For the Free Translation Project to be a success, we need interested
people who like their own language and write it well, and who are also
able to synergize with other translators speaking the same language.
Each translation team has its own mailing list. The up-to-date list of
teams can be found at the Free Translation Project's homepage,
`http://www.iro.umontreal.ca/contrib/po/HTML/', in the "National teams"
area.
If you'd like to volunteer to _work_ at translating messages, you
should become a member of the translating team for your own language.
The subscribing address is _not_ the same as the list itself, it has
`-request' appended. For example, speakers of Swedish can send a
message to `sv-request@li.org', having this message body:
subscribe
Keep in mind that team members are expected to participate
_actively_ in translations, or at solving translational difficulties,
rather than merely lurking around. If your team does not exist yet and
you want to start one, or if you are unsure about what to do or how to
get started, please write to `translation@iro.umontreal.ca' to reach the
coordinator for all translator teams.
The English team is special. It works at improving and uniformizing
the terminology in use. Proven linguistic skill are praised more than
programming skill, here.
Available Packages
==================
Languages are not equally supported in all packages. The following
matrix shows the current state of internationalization, as of September
2001. 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 bg cs da de el en eo es et fi fr gl he hr id it ja
+----------------------------------------------------+
a2ps | [] [] [] |
bash | [] [] [] [] |
bfd | |
binutils | [] |
bison | [] [] [] [] [] |
clisp | [] [] [] [] |
cpio | [] [] [] [] [] |
diffutils | [] [] [] [] [] [] [] |
enscript | [] [] |
error | [] [] |
fetchmail | |
fileutils | [] [] [] [] [] [] [] [] |
findutils | [] [] [] [] [] [] [] [] |
flex | [] [] [] |
freetype | |
gas | |
gawk | [] [] |
gcal | |
gcc | |
gettext | [] [] [] [] [] [] [] [] [] [] |
gnupg | [] [] [] [] [] [] [] |
gprof | |
grep | [] [] [] [] [] [] [] [] |
hello | [] [] [] [] [] [] [] [] [] [] [] |
id-utils | [] [] [] |
indent | [] [] [] [] [] |
jpilot | [] |
kbd | |
ld | [] |
libc | [] [] [] [] [] [] [] [] |
lilypond | [] |
lynx | [] [] [] [] |
m4 | [] [] [] [] [] [] [] [] |
make | [] [] [] [] [] [] |
mysecretdiary | [] |
nano | [] [] [] |
opcodes | |
parted | [] [] [] |
ptx | [] [] [] [] [] [] [] |
python | |
recode | [] [] [] [] [] [] [] [] [] |
sed | [] [] [] [] [] [] [] [] [] [] [] [] |
sh-utils | [] [] [] [] [] [] [] [] [] [] |
sharutils | [] [] [] [] [] [] [] [] |
sketch | |
soundtracker | [] [] [] |
sp | |
tar | [] [] [] [] [] [] [] [] |
texinfo | [] [] [] [] [] [] |
textutils | [] [] [] [] [] [] [] [] |
util-linux | [] [] |
wdiff | [] [] [] |
wget | [] [] [] [] [] [] [] [] [] [] |
+----------------------------------------------------+
bg cs da de el en eo es et fi fr gl he hr id it ja
0 14 24 32 11 1 8 23 13 1 33 22 4 0 7 9 18
ko lv nb nl nn no pl pt pt_BR ru sk sl sv tr uk zh
+----------------------------------------------------+
a2ps | [] [] [] | 6
bash | | 4
bfd | | 0
binutils | | 1
bison | [] | 6
clisp | [] | 5
cpio | [] [] [] [] [] | 10
diffutils | [] [] [] [] | 11
enscript | [] [] [] | 5
error | [] [] | 4
fetchmail | | 0
fileutils | [] [] [] [] [] [] [] [] [] | 17
findutils | [] [] [] [] [] [] [] [] | 16
flex | [] [] [] | 6
freetype | | 0
gas | | 0
gawk | [] | 3
gcal | | 0
gcc | | 0
gettext | [] [] [] [] [] [] [] [] | 18
gnupg | [] [] [] | 10
gprof | | 0
grep | [] [] [] [] | 12
hello | [] [] [] [] [] [] [] [] [] [] [] | 22
id-utils | [] [] [] | 6
indent | [] [] [] [] [] [] [] | 12
jpilot | | 1
kbd | [] | 1
ld | | 1
libc | [] [] [] [] [] [] [] [] | 16
lilypond | [] [] | 3
lynx | [] [] [] [] | 8
m4 | [] [] [] [] | 12
make | [] [] [] [] [] [] | 12
mysecretdiary | | 1
nano | [] | 4
opcodes | [] | 1
parted | [] [] | 5
ptx | [] [] [] [] [] [] [] [] | 15
python | | 0
recode | [] [] [] [] | 13
sed | [] [] [] [] [] [] [] | 19
sh-utils | [] [] [] [] [] [] [] [] [] [] [] | 21
sharutils | [] [] [] | 11
sketch | | 0
soundtracker | | 3
sp | | 0
tar | [] [] [] [] [] [] [] | 15
texinfo | [] | 7
textutils | [] [] [] [] [] [] [] [] | 16
util-linux | [] [] | 4
wdiff | [] [] [] [] | 7
wget | [] [] [] [] [] [] [] | 17
+----------------------------------------------------+
33 teams ko lv nb nl nn no pl pt pt_BR ru sk sl sv tr uk zh
53 domains 9 1 6 20 0 6 17 1 13 25 10 11 23 21 2 2 387
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
used for implementing regional variants of languages, or language
dialects.
For a PO file in the matrix above to be effective, the package to
which it applies should also have been internationalized and
distributed as such by its maintainer. There might be an observable
lag between the mere existence a PO file and its wide availability in a
distribution.
If September 2001 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://www.iro.umontreal.ca/contrib/po/HTML/matrix.html'.
Using `gettext' in new packages
===============================
If you are writing a freely available program and want to
internationalize it you are welcome to use GNU `gettext' in your
package. Of course you have to respect the GNU Library General Public
License which covers the use of the GNU `gettext' library. This means
in particular that even non-free programs can use `libintl' as a shared
library, whereas only free software can use `libintl' as a static
library or use modified versions of `libintl'.
Once the sources are changed appropriately and the setup can handle
to use of `gettext' the only thing missing are the translations. The
Free Translation Project is also available for packages which are not
developed inside the GNU project. Therefore the information given above
applies also for every other Free Software Project. Contact
`translation@iro.umontreal.ca' to make the `.pot' files available to
the translation teams.

12
BUGS
View File

@ -1,12 +0,0 @@
Please see
http://www.gnupg.org/buglist.html
for a list of know bugs in GnuPG. We don't distribute this list anymore
with the package because a more current one with notes in which version
the bug is fixed can be found online.
For security related bugs, please contact <security@gnupg.org> which
directs mails only to the core developers. If you need to encrypt the
report you should use the public keys of the maintainer and of 2 or 3
other active developers (consult the ChangeLog and AUTHORS).

231
INSTALL
View File

@ -1,231 +0,0 @@
Copyright 1994, 1995, 1996, 1999, 2000, 2001 Free Software Foundation,
Inc.
This file is free documentation; the Free Software Foundation gives
unlimited permission to copy, distribute and modify it.
Basic Installation
==================
These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. (Caching is
disabled by default to prevent problems with accidental use of stale
cache files.)
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You only need
`configure.ac' if you want to change it or regenerate `configure' using
a newer version of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes awhile. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. Run `./configure --help'
for details on some of the pertinent environment variables.
You can give `configure' initial values for variables by setting
them in the environment. You can do that on the command line like this:
./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
If you have to use a `make' that does not support the `VPATH'
variable, you have to compile the package for one architecture at a
time in the source code directory. After you have installed the
package for one architecture, use `make distclean' before reconfiguring
for another architecture.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=PATH' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of host the package
will run on. Usually `configure' can figure that out, but if it prints
a message saying it cannot guess the host type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the host type.
If you are _building_ compiler tools for cross-compiling, you should
use the `--target=TYPE' option to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the host
platform (i.e., that on which the generated programs will eventually be
run) with `--host=TYPE'. In this case, you should also specify the
build platform with `--build=TYPE', because, in this case, it may not
be possible to guess the build platform (it sometimes involves
compiling and running simple test programs, and this can't be done if
the compiler is a cross compiler).
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
will cause the specified gcc to be used as the C compiler (unless it is
overridden in the site shell script).
`configure' Invocation
======================
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'
Print a summary of the options to `configure', and exit.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

46
NOTES
View File

@ -1,46 +0,0 @@
Checking ElGamal signatures is really slow and the reason for the long
running time on parts o my keyring. Because somekeys are also checked at startup, this is even worser. I should invalidate my self signature with algo 16 or 20.
SCO UnixWare/7.1.0 reported by Allan Clark <allanc@sco.com> for 0.9.8
Some other reported cpu-vendor-os strings:
hppa1.1-hp-hpux10.20
mips-sgi-irix6.2
sparc-sun-solaris5.4
sparc-sun-sunos4.1.2
i386-pc-sysv4.2 (USL Unixware v1.1.2)
powerpc-ibm-aix4.3.2.0 John Payne <jcapayne@att.com>
gpg 1.0.1 okay with MP-RAS 3.02.01 Edition 5 using gcc 2.95.2 and EGD
By <CSpeicher@eisi.com>
gpg 1.0.1 okay with 4.0.1 BSDI BSD/OS 4.0 i386
rndw32 tested on:
Windows 98 4.10.1998 mit einem AMD-K6-2-450
Michael Engels <angel@dalrin.de>)
Windows 95 4.00.950a
Windows NT 4.00.1381
tried to compile GnuPG on AIX 4.3 on a power CPU based machine. It
doesn't work out of the box but i found a way to do so:
PowerPC based machines:
CFLAGS="-g -O2 -mcpu=powerpc" ./configure --disable-asm --disable-dynload
+--enable-static-rnd=egd
Power1 and Power2 machines:
CFLAGS="-g -O2 -mcpu=power" ./configure --disable-asm --disable-dynload
+--enable-static-rnd=egd

102
OBUGS
View File

@ -1,102 +0,0 @@
List of fixed bugs
--------------------
(format: severity: [ *] to [***], no, first reported, by, version)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[ *] #1
pgp263in works fine even with a source file with CR,LF but GnuPG
and pgp263in has problems if the clearsign has been created by
pgp263ia. The reason for this problem is that pgp2 sometimes
converts CR,LF to CR,CR,LF and to fix for this it hashes both
versions. I was able to reproduce such a problem, that PGP263in
was not able to verify it's own signature.
FIX: 1999-05-19 (Most cases are now handled)
[***] #2 1999-02-21
Problem while importing or deleting public keys in 0.9.3 - 0.9.2
worked fine. Error message:
gpg:[stdin]: key A6A59DB9: secret key not found: public key not found
FIX: 1999-02-22 wk
[ *] #5
/home/jam/.gnupg/pubring.gpg: can't open gdbm file: Can't be writer
keyblock resource `/home/jam/.gnupg/pubring.gpg': file open error
OOPS in close enum_keyblocks - ignored
[gdbm is experimental and will be replaced by the new keybox code]
FIX: 1999-07-22 (Fixed the second error, there will be no fix for
the first one, because GDBM is to be replaced)
[ *] #7 1999-02-22 <dwpalmer@dwpalm.jf.intel.com> 0.9.3
Conventional encryption incompatibility:
$ gpg -c --cipher-algo cast5 --compress-algo 1 --no-comment secrets.txt
Creates a file that gpg can decrypt, but PGP 5.5 has problems with it.
PGP decrypts 6416k out of 6424k, then complains with "PGP Warning",
"The keyring contains a bad (corrupted) PGP packet". The resulting
file is missing information from the front.
FIX: 1999-02-26 temporary fix in encrypt_simple()
[ *] #8 1999-02-25 <kazu@iijlab.net> 0.9.3
%gpg --encrypt -r kazu@iijlab.net --batch foo
gpg: Warning: using insecure memory!
gpg: 11C23F61: no info to calculate a trust probability
This creates a symmetrically encrypted message WITHOUT a session key
encrypted with public cryptographic(i.e. foo.gpg). This is probably
FIX: 199-02-26 wk
[ **] #9 1999-02-25
Misalignment in md5.c#md5_write.
FIX: 1999-02-26 wk
[ **] #10 1999-03-01
Armor detection code is broken. Direct import of keyrings is not possible.
FIX: 1999-03-02 wk
[***] #11 1999-02-25
"cipher algo 10 not found".
FIX: 1999-02-25 wk
[ **] #12 1999-03-10
gpg --list-secret-keys --with-colon SEGVs
FIX: 1999-03-10
[ *] #13 1999-04-05
Trying to generate very large keys fails with a BUG in read_pool()
FIX: 1999-04-06
[ *] #14 1999-04-05 <anonymous>
If you use --s2k-cipher-algo twofish, the the program crashes with
a BUG at line 226 of passphrase.c.
FIX: 1999-04-06
[ **] #15 1999-04-05
Hash calculation for subkey bindings is not according to rfc2440 if
a 4 byte length header is used for the subkey.
FIX: 1999-04-06
[***] #16 1999-03-23 <jafo@tummy.com>
Verifying detached signatures with an empty file yields a rc of 0.
FIX: 1999-05-06
[ **] #17 1999-05-18 <Bodo_Moeller@public.uni-hamburg.de> 0.9.6
Import does not detect identical user IDs.
FIX: 1999-05-22
[ **] #19 1999-06-11
"trustdb transaction too large" with about 500 signatures on a key
FAEBD5FC.
FIX: 1999-07-12 (less memory requirement and increased the limit)
[ **] #20 1999-06-16 <jashley@yorktown.designlab.ukans.edu> 0.9.7
Using "addkey" in the edit menu with more than 1 subkey leads to
"out of secure memory" in some cases.
FIX: 1999-06-17 (Twofish uses too much memory and the memory
becomes fragmented - workaround is using CAST5 to protect passphrases)
[ *] #21 1999-06-17
Ctrl-D does not work correct for messages entered at the tty.
FIX: 1999-06-18 (Better EOF detection on terminals)

View File

@ -1,46 +0,0 @@
* Change the internal representation of keyid into a struct which
can also hold the localid and extend the localid to hold information
of the subkey number because two subkeys may have the same keyid.
* Add a way to override the current cipher/md implementations
by others (using extensions)
* Not GnuPG related: What about option completion in bash?
Can "--dump-options" be used for this or should we place the
options in an ELF note section?
* Split key support (n-out-of-m). Use our own protocol or figure out
how PGP does it.
* add an option to re-create a public key from a secret key; we
can do this in trustdb.c:verify_own_keys. (special tool?)
Hmmm, we better drop the duplication of the public part and just keep
the secrets in the "secring" - this has the additional that we can
put those secrets on a hardware token.
* write a tool to extract selected keys from a file.
* Change the buffering to a mbuf like scheme? See Michael's proposal.
* Keep a list of duplicate, faked or unwanted keyids.
* The current code has knowledge about the structure of a keyblock.
We should add an abstraction layer so that adding support for
different certificate structures will become easier.
* "Michael T. Babcock" <mbabcock@fibrespeed.net> suggested to write
an event log so that other software can display a key history or
alike with GnuPG results. This should be connected to the keyrings.
Copyright 1998, 1999, 2000, 2001 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
modifications, as long as this notice is preserved.
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.

275
THOUGHTS
View File

@ -1,275 +0,0 @@
How often have we to do a key lookup by mailaddress?.
can this be accomplished by an external program?
What about using S-Exp to describe the interface to the ciphers instead
of simply iterating over them. This way we can easy register a name which
can be used as the "hintstr" for --load-extension.
EGD
====
Oh, and on embedding egd into the gpg package: I think if you just unpack it
into, say, util/egd/* then you can put something like this into configure.in:
AC_CHECK_PROG(perl_present, perl, true, false)
if $perl_present; then
AC_PATH_PROG(PERL, perl)
(cd util/egd; $PERL Makefile.PL FULLPERL=$PERL INSTALLBIN=$sbindir)
fi
AM_CONDITIONAL(WITH_EGD, $perl_present)
and add util/egd to the top-level Makefile directory list inside a WITH_EGD
conditional.
* What shall we do if we have a valid subkey revocation certificate
but no subkey binding? Is this a valid but revoked key?
* use a mmaped file for secure memory if mlock does not work and
make sure that this file is always wiped out. Is this really
more secure than swapping out to the swap disk? I don't
believe so because if an attacker has access to the physical
box (and he needs this to look at the swap area) he can also
leave a Trojan horse which is far more easier than to analyze
memory dumps. Question: Is it possible that a Unix pages
an old (left over by some other process) swap page in for
another process - this should be considered a serious design
flow/bug.
Date: Mon, 4 Jan 1999 19:34:29 -0800 (PST)
From: Matthew Skala <mskala@ansuz.sooke.bc.ca>
- Signing with an expired key doesn't work by default, does work with a
special option.
- Verifying a signature that appears to have been made by an expired key
after its expiry date but is otherwise good reports the signature as BAD,
preferably with a message indicating that it's a key-expiry problem rather
than a cryptographically bad signature.
- Verifying a signature from a key that is now expired, where the
signature was made before the expiry date, reports the signature as
GOOD, possibly with a warning that the key has since expired.
- Encrypting to an expired key doesn't work by default, does work with a
special option.
- Decrypting always works, if you have the appropriate secret key and
passphrase.
==============================
[ "-->" indicates a comment by me (wk) ]
Hi Werner..
I was looking at some of the PROJECTS items in the recent gpg CVS and wanted
to comment on one of them:
* Add a way to override the current cipher/md implementations
by others (using extensions)
As you know I've been thinking about how to use a PalmPilot or an iButton in
some useful way in GPG. The two things that seem reasonable are:
1) keep the secret key in the device, only transferring it to the host
computer for the duration of the secret-key operation (sign or decrypt).
The key is never kept on disk, only in RAM. This removes the chance that
casual snooping on your office workstation will reveal your key (it
doesn't help against an active attack, but the attacker must leave a
tampered version of GPG around or otherwise get their code to run while
the key-storage device is attached to attack the key)
2) perform the secret-key operation on the device, so the secret key never
leaves the confines of that device. There are still attacks possible,
based upon talking to the device while it is connected and trying to
convince the device (and possibly the user) that it is the real GPG,
but in general this protects the key pretty strongly. Any individual
message is still vulnerable, but that's a tradeoff of the convenience of
composing that message on a full-sized screen+keyboard (plus the added
speed of encryption) vs. the security of writing the message on a
secure device.
I think there are a variety of ways of implementing these things, but a few
extension mechanisms in GPG should be enough to try various ways later on.
1) pass an argument string to loadable extension modules (maybe
gpg --load-extension foofish=arg1,arg2,arg3 ?)
--> could also be achived by S-Exps
2) allow multiple instances of the same extension module (presumably with
different arguments)
--> set an alias name when loading them
3) allow extension modules to use stdin/stdout/stderr as normal (probably
already in there), for giving feedback to the user, or possibly asking them
for a password of some sort
--> there should really be some kind of callback mechanism.
4) have an extension to provide secret keys:
It looks like most of the hooks for this are already in place, it just
needs an extension module which can register itself as a keyblock resource.
I'm thinking of a module for this that is given an external program name as
an argument. When the keyblock resource is asked to enumerate its keys, it
runs the external program (first with a "0" argument, then a "1", and so on
until the program reports that no more keys are available). The external
--> better use a cookie: This way we are also stateless but have a more
general interface.
program returns one (possibly armored) secret key block each time. The
program might have some kind of special protocol to talk to the storage
device. One thing that comes to mind is to simply include a random number
in the message sent over the serial port: the program would display this
number, the Pilot at the other end would display the number it receives, if
the user sees that both are the same they instruct the Pilot to release the
key, as basic protection against someone else asking for the key while it
is attached. More sophisticated schemes are possible depending upon how
much processing power and IO is available on the device. But the same
extension module should be able to handle as complex a scheme as one could
wish.
--> authenticate the session on startup, using DH and the mentioned
cookie/screen/keyboard authentication.
The current keyblock-resource interface would work fine, although it
might be more convenient if a resource could be asked for a key by id
instead of enumerating all of them and then searching through the resulting
list for a match. A module that provided public keys would have to work this
way (imagine a module that could automatically do an http fetch for a
particular key.. easily-added automatic key fetching). Without that ability
to fetch by id (which would require it to fall back to the other keyblock
resources if it failed), the user's device might be asked to release the
key even though some other secret key was the one needed.
--> Right.
5) have an extension to perform a secret-key operation without the actual
secret key material
--> Define a clear interface to do this and in the first step write
a daemon which does exactly this.
basically something to indicate that any decrypt or sign operations that
occur for a specific keyid should call the extension module instead. The
secret key would not be extracted (it wouldn't be available anyway). The
module is given the keyid and the MPI of the block it is supposed to sign
or decrypt.
The module could then run an external program to do the operation. I'm
imagining a Pilot program which receives the data, asks the user if it can go
along with the operation (after displaying a hash of the request, which is
also displayed by the extension module's program to make sure the Pilot is
being asked to do the right operation), performs the signature or decryption,
then returns the data. This protocol could be made arbitrarily complex, with
a D-H key to encrypt the link, and both sides signing requests to
authenticate one to the other (although this transforms the the problem of
getting your secret key off your office workstation into the problem of
your workstation holding a key tells your Pilot that it is allowed to perform
the secret key operation, and if someone gets a hold of that key they may
be able to trick your pilot [plugged in somewhere else] to do the same thing
for them).
This is basically red/black separation, with the Pilot or iButton having the
perimeter beyond which the red data doesn't pass. Better than the secret-key
storage device but requires a lot more power on the device (the new iButtons
with the exponentiator could do it, but it would take way too much code space
on the old ones, although they would be fine for just carrying the keys).
The signature code might need to be extended to verify the signature you just
made, since an active intruder pretending to the the Pilot wouldn't be able to
make a valid signature (but they might sign your message with a different key
just to be annoying).
Anyway, just wanted to share my thoughts on some possibilities. I've been
carrying this little Java iButton on my keyring for months now, looking for
something cool to do with it, and I think that secure storage for my GPG key
would be just the right application.
cheers,
-Brian
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v0.4.5 (GNU/Linux)
Comment: For info finger gcrypt@ftp.guug.de
iD8DBQE2c5oZkDmgv9E5zEwRArAwAKDWV5fpTtbGPiMPgl2Bpp0gvhbfQgCgzJuY
AmIQTk4s62/y2zMAHDdOzK0=
=jr7m
-----END PGP SIGNATURE-----
About a new Keyserver (discussion with Allan Clark <allanc@sco.com>):
=====================
Some ideas:
o the KS should verify signatures and only accept those
which are good.
o Keep a blacklist of known bad signatures to minimize
the time needed to check them
o Should be fast - I'm currently designing a new storage
system called keybox which takes advantage of the fact
that the keyID is highly random and can directly be
used as a hash value and this keyID is (for v4 keys)
part of the fingerprint: So it is possible to use the
fingerprint as key but do an lookup by the keyID.
o To be used as the "public keyring" in a LAN so that there
is no need to keep one on every machine.
o Allow more that one file for key storage.
o Use the HKS protocol and enhance it in a way that binary
keyrings can be transmitted. (I already wrote some
http server and client code which can be used for this)
And extend it to allow reuse of a connection.
o Keep a checksum (hash) of the entire keyblock so that a
client can easy check whether this keyblock has changed.
(keyblock = the entire key with all certificates etc.)
Transmitted in the HEAD info.
o Allow efficient propagation of new keys and revocation
certificates.
Probably more things but this keyserver is not a goal for the
1.0 release. Someone should be able to fix some of the limitations
of the existing key servers (I think they bail out on some rfc2440
packet formats).
DJGPP
=====
Don't use symlinks but try to do the preprocessing in the config-links script.
DJPGG has problems to distinguish betwen .s and .S becaus the FAT filesystem
is not case sensitive (Mark Elbrecht).
Well, it runs only on one architecture and therefor it might be possible
to add a special case for it, completely bypassing the symlink autselection
trick.
Special procmail addresses
==========================
* foo+bar@example.net: Try to match the address without the "+bar".
Should be done by the MUA, but maybe we can do this.
--> Yep. Another reason to utilize a directory service or something
else for keylookup.
Suggested things which I will not do:
=====================================
* Let take --help an option to select some topics.
Using grep is much easier
* Check if an object (a message, detached sign, public key, or whatever)
is signed by definite user, i.e. define user
(userid, or any other unique identification) on command line.
--> Use a script and --status-fd
Copyright 1998, 1999, 2000, 2001 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
modifications, as long as this notice is preserved.
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.

View File

@ -1,419 +0,0 @@
2002-09-25 Werner Koch <wk@gnupg.org>
* gpg-agent.c (handle_signal): Flush cache on SIGHUP.
* cache.c (agent_flush_cache): New.
* gpg-agent.c, agent.h: Add --keep-display and --keep-tty.
* query.c (start_pinentry): Implement them. The option passing
needs more thoughts.
2002-09-09 Werner Koch <wk@gnupg.org>
* gpg-agent.c (create_private_keys_directory)
(create_directories): New.
(main): Try to create a home directory.
2002-09-04 Neal H. Walfield <neal@g10code.de>
* gpg-agent.c (main): Use sigaction, not signal.
2002-09-03 Neal H. Walfield <neal@g10code.de>
* findkey.c: Include <fcntl.h>.
(agent_write_private_key): Prefer POSIX compatibity, open and
fdopen, over the simplicity of GNU extensions, fopen(file, "x").
2002-08-22 Werner Koch <wk@gnupg.org>
* query.c (agent_askpin): Provide the default desc text depending
on the pininfo. Do the basic PIN verification only when
min_digits is set.
2002-08-21 Werner Koch <wk@gnupg.org>
* query.c (agent_askpin): Hack to show the right default prompt.
(agent_get_passphrase): Ditto.
* trans.c: Removed and replaced all usages with standard _()
* divert-scd.c (getpin_cb): Pass a more descritive text to the
pinentry.
* Makefile.am: Renamed the binary protect-tool to gpg-protect-tool.
* protect-tool.c: Removed the note about internal use only.
* gpg-agent.c (main): New option --daemon so that the program is
not accidently started in the background.
2002-08-16 Werner Koch <wk@gnupg.org>
* call-scd.c (learn_status_cb): Handle CERTINFO status.
(agent_card_learn): Add args for certinfo cb.
* learncard.c (release_certinfo,certinfo_cb): New.
(send_cert_back): New. With factored out code from ..
(agent_handle_learn): here. Return certinfo stuff.
2002-07-26 Werner Koch <wk@gnupg.org>
* gpg-agent.c (main): New option --ignore-cache-for-signing.
* command.c (option_handler): New server option
use-cache-for-signing defaulting to true.
(cmd_pksign): handle global and per session option.
* findkey.c (agent_key_from_file, unprotect): New arg
ignore_cache. Changed all callers.
* pksign.c (agent_pksign): Likewise.
2002-06-29 Werner Koch <wk@gnupg.org>
* query.c (start_pinentry): Use GNUPG_DERAULT_PINENTRY.
* call-scd.c (start_scd): Use GNUPG_DEFAULT_SCDAEMON.
2002-06-28 Werner Koch <wk@gnupg.org>
* protect-tool.c (export_p12_file): New.
(main): New command --p12-export.
* minip12.c (create_final,p12_build,compute_tag_length): New.
(store_tag_length): New.
2002-06-27 Werner Koch <wk@gnupg.org>
* minip12.c (crypt_block): Renamed from decrypt_block, add arg to
allow encryption.
* Makefile.am (pkglib_PROGRAMS): Put protect-tool there.
* findkey.c (agent_write_private_key,agent_key_from_file)
(agent_key_available): Use GNUPG_PRIVATE_KEYS_DIR constant.
* gpg-agent.c (main): Use GNUPG_DEFAULT_HOMEDIR constant.
* protect-tool.c (store_private_key): New.
(import_p12_file): Store the new file if requested.
(main): New options --force and --store.
* gpg-agent.c (main): Set a global flag when running detached.
* query.c (start_pinentry): Pass the list of FD to keep in the
child when not running detached.
* call-scd.c (start_scd): Ditto.
2002-06-26 Werner Koch <wk@gnupg.org>
* command.c (cmd_istrusted, cmd_listtrusted, cmd_marktrusted)
(cmd_pksign, cmd_pkdecrypt, cmd_genkey, cmd_get_passphrase)
(cmd_learn): Print an error message for a failed operation.
* simple-pwquery.c, simple-pwquery.h: New.
* protect-tool. (get_passphrase): New, used to get a passphrase
from the agent if none was given on the command line.
2002-06-25 Werner Koch <wk@gnupg.org>
* protect-tool.c (rsa_key_check): New.
(import_p12_file): New.
(main): New command --p12-import.
* minip12.c, minip12.h: New.
2002-06-24 Werner Koch <wk@gnupg.org>
* protect-tool.c (read_file): New.
(read_key): Factored most code out to read_file.
2002-06-17 Werner Koch <wk@gnupg.org>
* agent.h: Add a callback function to the pin_entry_info structure.
* query.c (agent_askpin): Use the callback to check for a correct
PIN. Removed the start_err_text argument because it is not
anymore needed; changed callers.
* findkey.c (unprotect): Replace our own check loop by a callback.
(try_unprotect_cb): New.
* genkey.c (reenter_compare_cb): New.
(agent_genkey): Use this callback here. Fixed setting of the pi2
variable and a segv in case of an empty PIN.
* divert-scd.c (getpin_cb): Removed some unused stuff and
explained what we still have to change.
2002-06-12 Werner Koch <wk@gnupg.org>
* gpg-agent.c (main): New option --disable-pth.
2002-06-11 Werner Koch <wk@gnupg.org>
* protect-tool.c: Add command --show-keygrip
(show_keygrip): New.
2002-05-23 Werner Koch <wk@gnupg.org>
* call-scd.c: Seirialized all scdaeom access when using Pth.
* cache.c: Made the cache Pth-thread-safe.
(agent_unlock_cache_entry): New.
* findkey.c (unprotect): Unlock the returned cache value.
* command.c (cmd_get_passphrase): Ditto.
* gpg-agent.c (main): Register pth_read/write with Assuan.
2002-05-22 Werner Koch <wk@gnupg.org>
* query.c: Serialized all pinentry access when using Pth.
* gpg-agent.c (handle_signal,start_connection_thread)
(handle_connections): New
(main): Use the new Pth stuff to allow concurrent connections.
* command.c (start_command_handler): Add new arg FD so that the
fucntion can also be used for an already connected socket.
* Makefile.am: Link with Pth.
2002-05-14 Werner Koch <wk@gnupg.org>
* cache.c (housekeeping, agent_put_cache): Use our time() wrapper.
2002-04-26 Werner Koch <wk@gnupg.org>
* cache.c (agent_put_cache): Reinitialize the creation time and
the ttl when reusing a slot.
* call-scd.c (start_scd): Print debug messages only with debug
flags set.
* query.c (start_pinentry): Ditto.
2002-04-25 Marcus Brinkmann <marcus@g10code.de>
* agent.h (agent_get_confirmation): Replace paramter prompt with
two parameters ok and cancel.
* query.c (agent_get_confirmation): Likewise. Implement this.
* trustlist.c (agent_marktrusted): Fix invocation of
agent_get_confirmation.
* divert-scd.c (ask_for_card): Likewise.
2002-04-24 Marcus Brinkmann <marcus@g10code.de>
* agent.h (struct opt): Add members display, ttyname, ttytype,
lc_ctype, and lc_messages.
* gpg-agent.c (enum cmd_and_opt_values): Add oDisplay, oTTYname,
oTTYtype, oLCctype, and LCmessages.
(main): Handle these options.
* command.c (option_handler): New function.
(register_commands): Register option handler.
* query.c (start_pinentry): Pass the various display and tty
options to the pinentry.
2002-04-05 Werner Koch <wk@gnupg.org>
* protect-tool.c (show_file): New. Used as default action.
2002-03-28 Werner Koch <wk@gnupg.org>
* divert-scd.c (encode_md_for_card): Don't do the pkcs-1 padding,
the scdaemon should take care of it.
(ask_for_card): Hack to not display the trailing zero.
2002-03-11 Werner Koch <wk@gnupg.org>
* learncard.c (kpinfo_cb): Remove the content restrictions from
the keyID.
2002-03-06 Werner Koch <wk@gnupg.org>
* learncard.c: New.
* divert-scd.c (ask_for_card): The serial number is binary so
convert it to hex here.
* findkey.c (agent_write_private_key): New.
* genkey.c (store_key): And use it here.
* pkdecrypt.c (agent_pkdecrypt): Changed the way the diversion is done.
* divert-scd.c (divert_pkdecrypt): Changed interface and
implemented it.
2002-03-05 Werner Koch <wk@gnupg.org>
* call-scd.c (inq_needpin): New.
(agent_card_pksign): Add getpin_cb args.
(agent_card_pkdecrypt): New.
2002-03-04 Werner Koch <wk@gnupg.org>
* pksign.c (agent_pksign): Changed how the diversion is done.
* divert-scd.c (divert_pksign): Changed interface and implemented it.
(encode_md_for_card): New.
* call-scd.c (agent_card_pksign): New.
2002-02-28 Werner Koch <wk@gnupg.org>
* pksign.c (agent_pksign): Detect whether a Smartcard is to be
used and divert the operation in this case.
* pkdecrypt.c (agent_pkdecrypt): Likewise
* findkey.c (agent_key_from_file): Add optional arg shadow_info
and have it return information about a shadowed key.
* protect.c (agent_get_shadow_info): New.
* protect.c (snext,sskip,smatch): Moved to
* sexp-parse.h: new file.
* divert-scd.c: New.
2002-02-27 Werner Koch <wk@gnupg.org>
* protect.c (agent_shadow_key): New.
* command.c (cmd_learn): New command LEARN.
* gpg-agent.c: New option --scdaemon-program.
* call-scd.c (start_scd): New. Based on query.c
* query.c: Add 2 more arguments to all uses of assuan_transact.
2002-02-18 Werner Koch <wk@gnupg.org>
* findkey.c (unprotect): Show an error message for a bad passphrase.
* command.c (cmd_marktrusted): Implemented.
* trustlist.c (agent_marktrusted): New.
(open_list): Add APPEND arg.
* query.c (agent_get_confirmation): New.
2002-02-06 Werner Koch <wk@gnupg.org>
* cache.c (housekeeping): Fixed linking in the remove case.
2002-02-01 Werner Koch <wk@gnupg.org>
* gpg-agent.c: New option --default-cache-ttl.
* cache.c (agent_put_cache): Use it.
* cache.c: Add a few debug outputs.
* protect.c (agent_private_key_type): New.
* agent.h: Add PRIVATE_KEY_ enums.
* findkey.c (agent_key_from_file): Use it to decide whether we
have to unprotect a key.
(unprotect): Cache the passphrase.
* findkey.c (agent_key_from_file,agent_key_available): The key
files do now require a ".key" suffix to make a script's life
easier.
* genkey.c (store_key): Ditto.
2002-01-31 Werner Koch <wk@gnupg.org>
* genkey.c (store_key): Protect the key.
(agent_genkey): Ask for the passphrase.
* findkey.c (unprotect): Actually unprotect the key.
* query.c (agent_askpin): Add an optional start_err_text.
2002-01-30 Werner Koch <wk@gnupg.org>
* protect.c: New.
(hash_passphrase): Based on the GnuPG 1.0.6 version.
* protect-tool.c: New
2002-01-29 Werner Koch <wk@gnupg.org>
* findkey.c (agent_key_available): New.
* command.c (cmd_havekey): New.
(register_commands): And register new command.
2002-01-20 Werner Koch <wk@gnupg.org>
* command.c (cmd_get_passphrase): Remove the plus signs.
* query.c (start_pinentry): Send no-grab option to pinentry
* gpg-agent.c (main): Move variable grab as no_grab to agent.h.
2002-01-19 Werner Koch <wk@gnupg.org>
* gpg-agent.c (main): Disable core dumps.
* cache.c: New.
* command.c (cmd_get_passphrase): Use the cache.
(cmd_clear_passphrase): Ditto.
* gpg-agent.c: Removed unused cruft and implement the socket
based server.
(my_strusage): Take bug report address from configure.ac.
* command.c (start_command_handler): Add an argument to start as
regular server.
(start_command_handler): Enable Assuan logging.
2002-01-15 Werner Koch <wk@gnupg.org>
* trustlist.c: New.
* command.c (cmd_istrusted, cmd_listtrusted, cmd_marktrusted): New.
2002-01-07 Werner Koch <wk@gnupg.org>
* genkey.c: Store the secret part and return the public part.
2002-01-03 Werner Koch <wk@gnupg.org>
* command.c (cmd_get_passphrase): New.
(cmd_clear_passphrase): New.
* query.c (agent_get_passphrase): New.
2002-01-02 Werner Koch <wk@gnupg.org>
* genkey.c: New.
* command.c (cmd_genkey): New.
* command.c (rc_to_assuan_status): Removed and changed all callers
to use map_to_assuan_status.
2001-12-19 Werner Koch <wk@gnupg.org>
* keyformat.txt: New.
2001-12-19 Marcus Brinkmann <marcus@g10code.de>
* query.c (start_pinentry): Add new argument to assuan_pipe_connect.
2001-12-18 Werner Koch <wk@gnupg.org>
* Makefile.am: Use LIBGCRYPT macros
2001-12-14 Werner Koch <wk@gnupg.org>
* gpg-agent.c (main): New option --batch. New option --debug-wait
n, so that it is possible to attach gdb when used in server mode.
* query.c (agent_askpin): Don't ask in batch mode.
* command.c: Removed the conversion macros as they are now in
../common/util.h.
2001-12-14 Marcus Brinkmann <marcus@g10code.de>
* query.c (LINELENGTH): Removed.
(agent_askpin): Use ASSUAN_LINELENGTH, not LINELENGTH.
2001-11-19 Werner Koch <wk@gnupg.org>
* gpg-agent.c: Removed all GUI code, removed code for old
protocol. New code to use the Assuan protocol as a server and
also to communicate with a new ask-passphrase utility.
2000-11-22 Werner Koch <wk@gnupg.org>
* gpg-agent.c (main): csh support by Dan Winship, new options --sh
and --csh and set default by consulting $SHELL.
Mon Aug 21 17:59:17 CEST 2000 Werner Koch <wk@openit.de>
* gpg-agent.c (passphrase_dialog): Cleanup the window and added the
user supplied text to the window.
(main): Fixed segv in gtk_init when used without a command to start.
* gpg-agent.c: --flush option.
(req_flush): New.
(req_clear_passphrase): Implemented.
Fri Aug 18 14:27:14 CEST 2000 Werner Koch <wk@openit.de>
* gpg-agent.c: New.
* Makefile.am: New.
Copyright 2001, 2002 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
modifications, as long as this notice is preserved.
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.

View File

@ -1,62 +0,0 @@
# Copyright (C) 2001 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 2 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
## Process this file with automake to produce Makefile.in
localedir = $(datadir)/locale
INCLUDES = -I../intl -DLOCALEDIR=\"$(localedir)\"
bin_PROGRAMS = gpg-agent
pkglib_PROGRAMS = gpg-protect-tool
AM_CPPFLAGS = -I$(top_srcdir)/common $(LIBGCRYPT_CFLAGS) $(PTH_CFLAGS)
LDFLAGS = @LDFLAGS@
gpg_agent_SOURCES = \
gpg-agent.c agent.h \
command.c \
query.c \
cache.c \
trans.c \
findkey.c \
pksign.c \
pkdecrypt.c \
genkey.c \
protect.c \
trustlist.c \
divert-scd.c \
call-scd.c \
learncard.c \
sexp-parse.h
gpg_agent_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a \
../common/libcommon.a $(LIBGCRYPT_LIBS) $(PTH_LIBS)
gpg_protect_tool_SOURCES = \
protect-tool.c \
protect.c \
minip12.c minip12.h \
simple-pwquery.c simple-pwquery.h
gpg_protect_tool_LDADD = ../jnlib/libjnlib.a \
../common/libcommon.a $(LIBGCRYPT_LIBS)

View File

@ -1,197 +0,0 @@
/* agent.h - Global definitions for the agent
* Copyright (C) 2001 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef AGENT_H
#define AGENT_H
#include <gcrypt.h>
#include "../common/util.h"
#include "../common/errors.h"
#define MAX_DIGEST_LEN 24
/* A large struct name "opt" to keep global flags */
struct {
unsigned int debug; /* debug flags (DBG_foo_VALUE) */
int verbose; /* verbosity level */
int quiet; /* be as quiet as possible */
int dry_run; /* don't change any persistent data */
int batch; /* batch mode */
const char *homedir; /* configuration directory name */
const char *pinentry_program;
char *display;
char *ttyname;
char *ttytype;
char *lc_ctype;
char *lc_messages;
const char *scdaemon_program;
int no_grab; /* don't let the pinentry grab the keyboard */
unsigned long def_cache_ttl;
int running_detached; /* we are running detached from the tty. */
int ignore_cache_for_signing;
int keep_tty; /* don't switch the TTY (for pinentry) on request */
int keep_display; /* don't switch the DISPLAY (for pinentry) on request */
} opt;
#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 */
#define DBG_MEMORY_VALUE 32 /* debug memory allocation stuff */
#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_ASSUAN_VALUE 1024
#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_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
struct server_local_s;
struct server_control_s {
struct server_local_s *server_local;
struct {
int algo;
unsigned char value[MAX_DIGEST_LEN];
int valuelen;
} digest;
char keygrip[20];
int have_keygrip;
};
typedef struct server_control_s *CTRL;
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;
int failed_tries;
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 displaye a specific error */
size_t max_length; /* allocated length of the buffer */
char pin[1];
};
enum {
PRIVATE_KEY_UNKNOWN = 0,
PRIVATE_KEY_CLEAR = 1,
PRIVATE_KEY_PROTECTED = 2,
PRIVATE_KEY_SHADOWED = 3
};
/*-- gpg-agent.c --*/
void agent_exit (int rc); /* also implemented in other tools */
/*-- command.c --*/
void start_command_handler (int, int);
/*-- findkey.c --*/
int agent_write_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force);
GCRY_SEXP agent_key_from_file (const unsigned char *grip,
unsigned char **shadow_info, int ignore_cache);
int agent_key_available (const unsigned char *grip);
/*-- query.c --*/
int agent_askpin (const char *desc_text, struct pin_entry_info_s *pininfo);
int agent_get_passphrase (char **retpass,
const char *desc, const char *prompt,
const char *errtext);
int agent_get_confirmation (const char *desc, const char *ok,
const char *cancel);
/*-- cache.c --*/
void agent_flush_cache (void);
int agent_put_cache (const char *key, const char *data, int ttl);
const char *agent_get_cache (const char *key, void **cache_id);
void agent_unlock_cache_entry (void **cache_id);
/*-- pksign.c --*/
int agent_pksign (CTRL ctrl, FILE *outfp, int ignore_cache);
/*-- pkdecrypt.c --*/
int agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen,
FILE *outfp);
/*-- genkey.c --*/
int agent_genkey (CTRL ctrl,
const char *keyparam, size_t keyparmlen, FILE *outfp);
/*-- protect.c --*/
int agent_protect (const unsigned char *plainkey, const char *passphrase,
unsigned char **result, size_t *resultlen);
int agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
unsigned char **result, size_t *resultlen);
int agent_private_key_type (const unsigned char *privatekey);
int agent_shadow_key (const unsigned char *pubkey,
const unsigned char *shadow_info,
unsigned char **result);
int agent_get_shadow_info (const unsigned char *shadowkey,
unsigned char const **shadow_info);
/*-- trustlist.c --*/
int agent_istrusted (const char *fpr);
int agent_listtrusted (void *assuan_context);
int agent_marktrusted (const char *name, const char *fpr, int flag);
/*-- divert-scd.c --*/
int divert_pksign (const unsigned char *digest, size_t digestlen, int algo,
const unsigned char *shadow_info, unsigned char **r_sig);
int divert_pkdecrypt (const unsigned char *cipher,
const unsigned char *shadow_info,
char **r_buf, size_t *r_len);
/*-- call-scd.c --*/
int agent_card_learn (void (*kpinfo_cb)(void*, const char *),
void *kpinfo_cb_arg,
void (*certinfo_cb)(void*, const char *),
void *certinfo_cb_arg);
int agent_card_serialno (char **r_serialno);
int agent_card_pksign (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 agent_card_pkdecrypt (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 agent_card_readcert (const char *id, char **r_buf, size_t *r_buflen);
int agent_card_readkey (const char *id, unsigned char **r_buf);
/*-- learncard.c --*/
int agent_handle_learn (void *assuan_context);
#endif /*AGENT_H*/

View File

@ -1,314 +0,0 @@
/* cache.c - keep a cache of passphrases
* Copyright (C) 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include "agent.h"
struct secret_data_s {
int totallen; /* this includes the padding */
int datalen; /* actual data length */
char data[1];
};
typedef struct cache_item_s *ITEM;
struct cache_item_s {
ITEM next;
time_t created;
time_t accessed;
int ttl; /* max. lifetime given in seonds */
int lockcount;
struct secret_data_s *pw;
char key[1];
};
static ITEM thecache;
static void
release_data (struct secret_data_s *data)
{
xfree (data);
}
static struct secret_data_s *
new_data (const void *data, size_t length)
{
struct secret_data_s *d;
int total;
/* 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*/
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);
}
return d;
}
/* check whether there are items to expire */
static void
housekeeping (void)
{
ITEM r, rprev;
time_t current = gnupg_get_time ();
/* first expire the actual data */
for (r=thecache; r; r = r->next)
{
if (!r->lockcount && r->pw && r->accessed + r->ttl < current)
{
if (DBG_CACHE)
log_debug (" expired `%s' (%ds after last access)\n",
r->key, r->ttl);
release_data (r->pw);
r->pw = NULL;
r->accessed = current;
}
}
/* second, make sure that we also remove them based on the created stamp so
that the user has to enter it from time to time. We do this every hour */
for (r=thecache; r; r = r->next)
{
if (!r->lockcount && r->pw && r->created + 60*60 < current)
{
if (DBG_CACHE)
log_debug (" expired `%s' (1h after creation)\n", r->key);
release_data (r->pw);
r->pw = NULL;
r->accessed = current;
}
}
/* third, make sure that we don't have too many items in the list.
Expire old and unused entries after 30 minutes */
for (rprev=NULL, r=thecache; r; )
{
if (!r->pw && r->accessed + 60*30 < current)
{
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
{
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
{
rprev = r;
r = r->next;
}
}
}
void
agent_flush_cache (void)
{
ITEM r;
if (DBG_CACHE)
log_debug ("agent_flush_cache\n");
for (r=thecache; r; r = r->next)
{
if (!r->lockcount && r->pw)
{
if (DBG_CACHE)
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 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 */
int
agent_put_cache (const char *key, const char *data, int ttl)
{
ITEM r;
if (DBG_CACHE)
log_debug ("agent_put_cache `%s'\n", key);
housekeeping ();
if (ttl < 1)
ttl = opt.def_cache_ttl;
if (!ttl)
return 0;
for (r=thecache; r; r = r->next)
{
if (!r->lockcount && !strcmp (r->key, key))
break;
}
if (r)
{ /* replace */
if (r->pw)
{
release_data (r->pw);
r->pw = NULL;
}
if (data)
{
r->created = r->accessed = gnupg_get_time ();
r->ttl = ttl;
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)
{ /* simply insert */
r = xtrycalloc (1, sizeof *r + strlen (key));
if (!r)
log_error ("out of core while allocating new cache control\n");
else
{
strcpy (r->key, key);
r->created = r->accessed = gnupg_get_time ();
r->ttl = ttl;
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;
}
}
}
return 0;
}
/* Try to find an item in the cache */
const char *
agent_get_cache (const char *key, void **cache_id)
{
ITEM r;
if (DBG_CACHE)
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->lockcount && r->pw && !strcmp (r->key, key))
{
/* 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");
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;
}
void
agent_unlock_cache_entry (void **cache_id)
{
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;
}
}
}

View File

@ -1,592 +0,0 @@
/* call-scd.c - fork of the scdaemon to do SC operations
* Copyright (C) 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/* Fixme: For now we have serialized all access to the scdaemon which
make sense becuase the scdaemon can't handle concurrent connections
right now. We should however keep a list of connections and lock
just that connection - it migth make sense to implemtn parts of
this in Assuan.*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#ifdef USE_GNU_PTH
# include <pth.h>
#endif
#include "agent.h"
#include "../assuan/assuan.h"
#ifdef _POSIX_OPEN_MAX
#define MAX_OPEN_FDS _POSIX_OPEN_MAX
#else
#define MAX_OPEN_FDS 20
#endif
static ASSUAN_CONTEXT scd_ctx = NULL;
#ifdef USE_GNU_PTH
static pth_mutex_t scd_lock = PTH_MUTEX_INIT;
#endif
/* callback parameter for learn card */
struct learn_parm_s {
void (*kpinfo_cb)(void*, const char *);
void *kpinfo_cb_arg;
void (*certinfo_cb)(void*, const char *);
void *certinfo_cb_arg;
};
struct inq_needpin_s {
ASSUAN_CONTEXT ctx;
int (*getpin_cb)(void *, const char *, char*, size_t);
void *getpin_cb_arg;
};
struct membuf {
size_t len;
size_t size;
char *buf;
int out_of_core;
};
/* A simple implementation of a dynamic buffer. Use init_membuf() to
create a buffer, put_membuf to append bytes and get_membuf to
release and return the buffer. Allocation errors are detected but
only returned at the final get_membuf(), this helps not to clutter
the code with out of core checks. */
static void
init_membuf (struct membuf *mb, int initiallen)
{
mb->len = 0;
mb->size = initiallen;
mb->out_of_core = 0;
mb->buf = xtrymalloc (initiallen);
if (!mb->buf)
mb->out_of_core = 1;
}
static void
put_membuf (struct membuf *mb, const void *buf, size_t len)
{
if (mb->out_of_core)
return;
if (mb->len + len >= mb->size)
{
char *p;
mb->size += len + 1024;
p = xtryrealloc (mb->buf, mb->size);
if (!p)
{
mb->out_of_core = 1;
return;
}
mb->buf = p;
}
memcpy (mb->buf + mb->len, buf, len);
mb->len += len;
}
static void *
get_membuf (struct membuf *mb, size_t *len)
{
char *p;
if (mb->out_of_core)
{
xfree (mb->buf);
mb->buf = NULL;
return NULL;
}
p = mb->buf;
*len = mb->len;
mb->buf = NULL;
mb->out_of_core = 1; /* don't allow a reuse */
return p;
}
static int
unlock_scd (int rc)
{
#ifdef USE_GNU_PTH
if (!pth_mutex_release (&scd_lock))
{
log_error ("failed to release the SCD lock\n");
if (!rc)
rc = GNUPG_Internal_Error;
}
#endif
return rc;
}
/* Fork off the SCdaemon if this has not already been done */
static int
start_scd (void)
{
int rc;
const char *pgmname;
ASSUAN_CONTEXT ctx;
const char *argv[3];
int no_close_list[3];
int i;
#ifdef USE_GNU_PTH
if (!pth_mutex_acquire (&scd_lock, 0, NULL))
{
log_error ("failed to acquire the SCD lock\n");
return GNUPG_Internal_Error;
}
#endif
if (scd_ctx)
return 0; /* No need to serialize things because the agent is
expected to tun as a single-thread (or may be in
future using libpth) */
if (opt.verbose)
log_info ("no running SCdaemon - starting it\n");
if (fflush (NULL))
{
log_error ("error flushing pending output: %s\n", strerror (errno));
return unlock_scd (seterr (Write_Error));
}
if (!opt.scdaemon_program || !*opt.scdaemon_program)
opt.scdaemon_program = GNUPG_DEFAULT_SCDAEMON;
if ( !(pgmname = strrchr (opt.scdaemon_program, '/')))
pgmname = opt.scdaemon_program;
else
pgmname++;
argv[0] = pgmname;
argv[1] = "--server";
argv[2] = NULL;
i=0;
if (!opt.running_detached)
{
if (log_get_fd () != -1)
no_close_list[i++] = log_get_fd ();
no_close_list[i++] = fileno (stderr);
}
no_close_list[i] = -1;
/* connect to the pinentry and perform initial handshaking */
rc = assuan_pipe_connect (&ctx, opt.scdaemon_program, (char**)argv,
no_close_list);
if (rc)
{
log_error ("can't connect to the SCdaemon: %s\n",
assuan_strerror (rc));
return unlock_scd (seterr (No_Scdaemon));
}
scd_ctx = ctx;
if (DBG_ASSUAN)
log_debug ("connection to SCdaemon established\n");
return 0;
}
static AssuanError
learn_status_cb (void *opaque, const char *line)
{
struct learn_parm_s *parm = opaque;
const char *keyword = line;
int keywordlen;
for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
;
while (spacep (line))
line++;
if (keywordlen == 8 && !memcmp (keyword, "CERTINFO", keywordlen))
{
parm->certinfo_cb (parm->certinfo_cb_arg, line);
}
else if (keywordlen == 11 && !memcmp (keyword, "KEYPAIRINFO", keywordlen))
{
parm->kpinfo_cb (parm->kpinfo_cb_arg, line);
}
else if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
{
log_debug ("learn_status_cb: serialno `%s'\n", line);
}
else
log_debug ("learn_status_cb: ignoring `%.*s'\n", keywordlen, keyword);
return 0;
}
/* Perform the learn command and return a list of all private keys
stored on the card. */
int
agent_card_learn (void (*kpinfo_cb)(void*, const char *),
void *kpinfo_cb_arg,
void (*certinfo_cb)(void*, const char *),
void *certinfo_cb_arg)
{
int rc;
struct learn_parm_s parm;
rc = start_scd ();
if (rc)
return rc;
memset (&parm, 0, sizeof parm);
parm.kpinfo_cb = kpinfo_cb;
parm.kpinfo_cb_arg = kpinfo_cb_arg;
parm.certinfo_cb = certinfo_cb;
parm.certinfo_cb_arg = certinfo_cb_arg;
rc = assuan_transact (scd_ctx, "LEARN --force",
NULL, NULL, NULL, NULL,
learn_status_cb, &parm);
if (rc)
return unlock_scd (map_assuan_err (rc));
return unlock_scd (0);
}
static AssuanError
get_serialno_cb (void *opaque, const char *line)
{
char **serialno = opaque;
const char *keyword = line;
const char *s;
int keywordlen, n;
for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
;
while (spacep (line))
line++;
if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
{
if (*serialno)
return ASSUAN_Unexpected_Status;
for (n=0,s=line; hexdigitp (s); s++, n++)
;
if (!n || (n&1)|| !(spacep (s) || !*s) )
return ASSUAN_Invalid_Status;
*serialno = xtrymalloc (n+1);
if (!*serialno)
return ASSUAN_Out_Of_Core;
memcpy (*serialno, line, n);
(*serialno)[n] = 0;
}
return 0;
}
/* Return the serial number of the card or an appropriate error. The
serial number is returned as a hexstring. */
int
agent_card_serialno (char **r_serialno)
{
int rc;
char *serialno = NULL;
rc = start_scd ();
if (rc)
return rc;
/* Hmm, do we really need this reset - scddaemon should do this or
we can do this if we for some reason figure out that the
operation might have failed due to a missing RESET. Hmmm, I feel
this is really SCdaemon's duty */
rc = assuan_transact (scd_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return unlock_scd (map_assuan_err (rc));
rc = assuan_transact (scd_ctx, "SERIALNO",
NULL, NULL, NULL, NULL,
get_serialno_cb, &serialno);
if (rc)
{
xfree (serialno);
return unlock_scd (map_assuan_err (rc));
}
*r_serialno = serialno;
return unlock_scd (0);
}
static AssuanError
membuf_data_cb (void *opaque, const void *buffer, size_t length)
{
struct membuf *data = opaque;
if (buffer)
put_membuf (data, buffer, length);
return 0;
}
/* Handle the NEEDPIN inquiry. */
static AssuanError
inq_needpin (void *opaque, const char *line)
{
struct inq_needpin_s *parm = opaque;
char *pin;
size_t pinlen;
int rc;
if (!(!strncmp (line, "NEEDPIN", 7) && (line[7] == ' ' || !line[7])))
{
log_error ("unsupported inquiry `%s'\n", line);
return ASSUAN_Inquire_Unknown;
}
line += 7;
pinlen = 90;
pin = gcry_malloc_secure (pinlen);
if (!pin)
return ASSUAN_Out_Of_Core;
rc = parm->getpin_cb (parm->getpin_cb_arg, line, pin, pinlen);
if (rc)
rc = ASSUAN_Canceled;
if (!rc)
rc = assuan_send_data (parm->ctx, pin, pinlen);
xfree (pin);
return rc;
}
/* Create a signature using the current card */
int
agent_card_pksign (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 rc, i;
char *p, line[ASSUAN_LINELENGTH];
struct membuf data;
struct inq_needpin_s inqparm;
size_t len;
unsigned char *sigbuf;
size_t sigbuflen;
*r_buf = NULL;
rc = start_scd ();
if (rc)
return rc;
if (indatalen*2 + 50 > DIM(line))
return unlock_scd (seterr (General_Error));
sprintf (line, "SETDATA ");
p = line + strlen (line);
for (i=0; i < indatalen ; i++, p += 2 )
sprintf (p, "%02X", indata[i]);
rc = assuan_transact (scd_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return unlock_scd (map_assuan_err (rc));
init_membuf (&data, 1024);
inqparm.ctx = scd_ctx;
inqparm.getpin_cb = getpin_cb;
inqparm.getpin_cb_arg = getpin_cb_arg;
snprintf (line, DIM(line)-1, "PKSIGN %s", keyid);
line[DIM(line)-1] = 0;
rc = assuan_transact (scd_ctx, line,
membuf_data_cb, &data,
inq_needpin, &inqparm,
NULL, NULL);
if (rc)
{
xfree (get_membuf (&data, &len));
return unlock_scd (map_assuan_err (rc));
}
sigbuf = get_membuf (&data, &sigbuflen);
/* 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;
*r_buf = xtrymalloc (*r_buflen);
if (!*r_buf)
{
xfree (*r_buf);
return unlock_scd (GNUPG_Out_Of_Core);
}
p = stpcpy (*r_buf, "(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);
assert (gcry_sexp_canon_len (*r_buf, *r_buflen, NULL, NULL));
return unlock_scd (0);
}
/* Decipher INDATA using the current card. Note that the returned value is */
int
agent_card_pkdecrypt (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 rc, i;
char *p, line[ASSUAN_LINELENGTH];
struct membuf data;
struct inq_needpin_s inqparm;
size_t len;
*r_buf = NULL;
rc = start_scd ();
if (rc)
return rc;
/* FIXME: use secure memory where appropriate */
if (indatalen*2 + 50 > DIM(line))
return unlock_scd (seterr (General_Error));
sprintf (line, "SETDATA ");
p = line + strlen (line);
for (i=0; i < indatalen ; i++, p += 2 )
sprintf (p, "%02X", indata[i]);
rc = assuan_transact (scd_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return unlock_scd (map_assuan_err (rc));
init_membuf (&data, 1024);
inqparm.ctx = scd_ctx;
inqparm.getpin_cb = getpin_cb;
inqparm.getpin_cb_arg = getpin_cb_arg;
snprintf (line, DIM(line)-1, "PKDECRYPT %s", keyid);
line[DIM(line)-1] = 0;
rc = assuan_transact (scd_ctx, line,
membuf_data_cb, &data,
inq_needpin, &inqparm,
NULL, NULL);
if (rc)
{
xfree (get_membuf (&data, &len));
return unlock_scd (map_assuan_err (rc));
}
*r_buf = get_membuf (&data, r_buflen);
if (!*r_buf)
return unlock_scd (GNUPG_Out_Of_Core);
return unlock_scd (0);
}
/* Read a certificate with ID into R_BUF and R_BUFLEN. */
int
agent_card_readcert (const char *id, char **r_buf, size_t *r_buflen)
{
int rc;
char line[ASSUAN_LINELENGTH];
struct membuf data;
size_t len;
*r_buf = NULL;
rc = start_scd ();
if (rc)
return rc;
init_membuf (&data, 1024);
snprintf (line, DIM(line)-1, "READCERT %s", id);
line[DIM(line)-1] = 0;
rc = assuan_transact (scd_ctx, line,
membuf_data_cb, &data,
NULL, NULL,
NULL, NULL);
if (rc)
{
xfree (get_membuf (&data, &len));
return unlock_scd (map_assuan_err (rc));
}
*r_buf = get_membuf (&data, r_buflen);
if (!*r_buf)
return unlock_scd (GNUPG_Out_Of_Core);
return unlock_scd (0);
}
/* Read a key with ID and return it in an allocate buffer pointed to
by r_BUF as a valid S-expression. */
int
agent_card_readkey (const char *id, unsigned char **r_buf)
{
int rc;
char line[ASSUAN_LINELENGTH];
struct membuf data;
size_t len, buflen;
*r_buf = NULL;
rc = start_scd ();
if (rc)
return rc;
init_membuf (&data, 1024);
snprintf (line, DIM(line)-1, "READKEY %s", id);
line[DIM(line)-1] = 0;
rc = assuan_transact (scd_ctx, line,
membuf_data_cb, &data,
NULL, NULL,
NULL, NULL);
if (rc)
{
xfree (get_membuf (&data, &len));
return unlock_scd (map_assuan_err (rc));
}
*r_buf = get_membuf (&data, &buflen);
if (!*r_buf)
return unlock_scd (GNUPG_Out_Of_Core);
if (!gcry_sexp_canon_len (*r_buf, buflen, NULL, NULL))
{
xfree (*r_buf); *r_buf = NULL;
return unlock_scd (GNUPG_Invalid_Value);
}
return unlock_scd (0);
}

View File

@ -1,697 +0,0 @@
/* command.c - gpg-agent command handler
* Copyright (C) 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/* FIXME: we should not use the default assuan buffering but setup
some buffering in secure mempory to protect session keys etc. */
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include "agent.h"
#include "../assuan/assuan.h"
/* maximum allowed size of the inquired ciphertext */
#define MAXLEN_CIPHERTEXT 4096
/* maximum allowed size of the key parameters */
#define MAXLEN_KEYPARAM 1024
#define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
#if MAX_DIGEST_LEN < 20
#error MAX_DIGEST_LEN shorter than keygrip
#endif
/* Data used to associate an Assuan context with local server data */
struct server_local_s {
ASSUAN_CONTEXT assuan_ctx;
int message_fd;
int use_cache_for_signing;
};
static void
reset_notify (ASSUAN_CONTEXT ctx)
{
CTRL ctrl = assuan_get_pointer (ctx);
memset (ctrl->keygrip, 0, 20);
ctrl->have_keygrip = 0;
ctrl->digest.valuelen = 0;
}
/* Check whether the option NAME appears in LINE */
static int
has_option (const char *line, const char *name)
{
const char *s;
int n = strlen (name);
s = strstr (line, name);
return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
}
/* ISTRUSTED <hexstring_with_fingerprint>
Return OK when we have an entry with this fingerprint in our
trustlist */
static int
cmd_istrusted (ASSUAN_CONTEXT ctx, char *line)
{
int rc, n, i;
char *p;
char fpr[41];
/* parse the fingerprint value */
for (p=line,n=0; hexdigitp (p); p++, n++)
;
if (*p || !(n == 40 || n == 32))
return set_error (Parameter_Error, "invalid fingerprint");
i = 0;
if (n==32)
{
strcpy (fpr, "00000000");
i += 8;
}
for (p=line; i < 40; p++, i++)
fpr[i] = *p >= 'a'? (*p & 0xdf): *p;
fpr[i] = 0;
rc = agent_istrusted (fpr);
if (!rc)
return 0;
else if (rc == -1)
return ASSUAN_Not_Trusted;
else
{
log_error ("command is_trusted failed: %s\n", gnupg_strerror (rc));
return map_to_assuan_status (rc);
}
}
/* LISTTRUSTED
List all entries from the trustlist */
static int
cmd_listtrusted (ASSUAN_CONTEXT ctx, char *line)
{
int rc = agent_listtrusted (ctx);
if (rc)
log_error ("command listtrusted failed: %s\n", gnupg_strerror (rc));
return map_to_assuan_status (rc);
}
/* MARKTRUSTED <hexstring_with_fingerprint> <flag> <display_name>
Store a new key in into the trustlist*/
static int
cmd_marktrusted (ASSUAN_CONTEXT ctx, char *line)
{
int rc, n, i;
char *p;
char fpr[41];
int flag;
/* parse the fingerprint value */
for (p=line,n=0; hexdigitp (p); p++, n++)
;
if (!spacep (p) || !(n == 40 || n == 32))
return set_error (Parameter_Error, "invalid fingerprint");
i = 0;
if (n==32)
{
strcpy (fpr, "00000000");
i += 8;
}
for (p=line; i < 40; p++, i++)
fpr[i] = *p >= 'a'? (*p & 0xdf): *p;
fpr[i] = 0;
while (spacep (p))
p++;
flag = *p++;
if ( (flag != 'S' && flag != 'P') || !spacep (p) )
return set_error (Parameter_Error, "invalid flag - must be P or S");
while (spacep (p))
p++;
rc = agent_marktrusted (p, fpr, flag);
if (rc)
log_error ("command marktrusted failed: %s\n", gnupg_strerror (rc));
return map_to_assuan_status (rc);
}
/* HAVEKEY <hexstring_with_keygrip>
Return success when the secret key is available */
static int
cmd_havekey (ASSUAN_CONTEXT ctx, char *line)
{
int n;
char *p;
unsigned char buf[20];
/* parse the hash value */
for (p=line,n=0; hexdigitp (p); p++, n++)
;
if (*p)
return set_error (Parameter_Error, "invalid hexstring");
if ((n&1))
return set_error (Parameter_Error, "odd number of digits");
n /= 2;
if (n != 20)
return set_error (Parameter_Error, "invalid length of keygrip");
for (p=line, n=0; n < 20; p += 2, n++)
buf[n] = xtoi_2 (p);
if (agent_key_available (buf))
return ASSUAN_No_Secret_Key;
return 0;
}
/* SIGKEY <hexstring_with_keygrip>
SETKEY <hexstring_with_keygrip>
Set the key used for a sign or decrypt operation */
static int
cmd_sigkey (ASSUAN_CONTEXT ctx, char *line)
{
int n;
char *p;
CTRL ctrl = assuan_get_pointer (ctx);
unsigned char *buf;
/* parse the hash value */
for (p=line,n=0; hexdigitp (p); p++, n++)
;
if (*p)
return set_error (Parameter_Error, "invalid hexstring");
if ((n&1))
return set_error (Parameter_Error, "odd number of digits");
n /= 2;
if (n != 20)
return set_error (Parameter_Error, "invalid length of keygrip");
buf = ctrl->keygrip;
for (p=line, n=0; n < 20; p += 2, n++)
buf[n] = xtoi_2 (p);
ctrl->have_keygrip = 1;
return 0;
}
/* SETHASH <algonumber> <hexstring>
The client can use this command to tell the server about the data
(which usually is a hash) to be signed. */
static int
cmd_sethash (ASSUAN_CONTEXT ctx, char *line)
{
int n;
char *p;
CTRL ctrl = assuan_get_pointer (ctx);
unsigned char *buf;
char *endp;
int algo;
/* parse the algo number and check it */
algo = (int)strtoul (line, &endp, 10);
for (line = endp; *line == ' ' || *line == '\t'; line++)
;
if (!algo || gcry_md_test_algo (algo))
return set_error (Unsupported_Algorithm, NULL);
ctrl->digest.algo = algo;
/* parse the hash value */
for (p=line,n=0; hexdigitp (p); p++, n++)
;
if (*p)
return set_error (Parameter_Error, "invalid hexstring");
if ((n&1))
return set_error (Parameter_Error, "odd number of digits");
n /= 2;
if (n != 16 && n != 20 && n != 24 && n != 32)
return set_error (Parameter_Error, "unsupported length of hash");
if (n > MAX_DIGEST_LEN)
return set_error (Parameter_Error, "hash value to long");
buf = ctrl->digest.value;
ctrl->digest.valuelen = n;
for (p=line, n=0; n < ctrl->digest.valuelen; p += 2, n++)
buf[n] = xtoi_2 (p);
for (; n < ctrl->digest.valuelen; n++)
buf[n] = 0;
return 0;
}
/* PKSIGN <options>
Perform the actual sign operation. Neither input nor output are
sensitive to eavesdropping */
static int
cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
{
int rc;
int ignore_cache = 0;
CTRL ctrl = assuan_get_pointer (ctx);
if (opt.ignore_cache_for_signing)
ignore_cache = 1;
else if (!ctrl->server_local->use_cache_for_signing)
ignore_cache = 1;
rc = agent_pksign (ctrl, assuan_get_data_fp (ctx), ignore_cache);
if (rc)
log_error ("command pksign failed: %s\n", gnupg_strerror (rc));
return map_to_assuan_status (rc);
}
/* PKDECRYPT <options>
Perform the actual decrypt operation. Input is not
sensitive to eavesdropping */
static int
cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
{
int rc;
CTRL ctrl = assuan_get_pointer (ctx);
char *value;
size_t valuelen;
/* First inquire the data to decrypt */
rc = assuan_inquire (ctx, "CIPHERTEXT",
&value, &valuelen, MAXLEN_CIPHERTEXT);
if (rc)
return rc;
rc = agent_pkdecrypt (ctrl, value, valuelen, assuan_get_data_fp (ctx));
xfree (value);
if (rc)
log_error ("command pkdecrypt failed: %s\n", gnupg_strerror (rc));
return map_to_assuan_status (rc);
}
/* GENKEY
Generate a new key, store the secret part and return the public
part. Here is an example transaction:
C: GENKEY
S: INQUIRE KEYPARM
C: D (genkey (rsa (nbits 1024)))
C: END
S: D (public-key
S: D (rsa (n 326487324683264) (e 10001)))
S OK key created
*/
static int
cmd_genkey (ASSUAN_CONTEXT ctx, char *line)
{
CTRL ctrl = assuan_get_pointer (ctx);
int rc;
char *value;
size_t valuelen;
/* First inquire the parameters */
rc = assuan_inquire (ctx, "KEYPARAM", &value, &valuelen, MAXLEN_KEYPARAM);
if (rc)
return rc;
rc = agent_genkey (ctrl, value, valuelen, assuan_get_data_fp (ctx));
xfree (value);
if (rc)
log_error ("command genkey failed: %s\n", gnupg_strerror (rc));
return map_to_assuan_status (rc);
}
static void
plus_to_blank (char *s)
{
for (; *s; s++)
{
if (*s == '+')
*s = ' ';
}
}
/* GET_PASSPHRASE <cache_id> [<error_message> <prompt> <description>]
This function is usually used to ask for a passphrase to be used
for conventional encryption, but may also be used by programs which
need specal handling of passphrases. This command uses a syntax
which helps clients to use the agent with minimum effort. The
agent either returns with an error or with a OK followed by the hex
encoded passphrase. Note that the length of the strings is
implicitly limited by the maximum length of a command.
*/
static int
cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line)
{
int rc;
const char *pw;
char *response;
char *cacheid = NULL, *desc = NULL, *prompt = NULL, *errtext = NULL;
char *p;
void *cache_marker;
/* parse the stuff */
for (p=line; *p == ' '; p++)
;
cacheid = p;
p = strchr (cacheid, ' ');
if (p)
{
*p++ = 0;
while (*p == ' ')
p++;
errtext = p;
p = strchr (errtext, ' ');
if (p)
{
*p++ = 0;
while (*p == ' ')
p++;
prompt = p;
p = strchr (prompt, ' ');
if (p)
{
*p++ = 0;
while (*p == ' ')
p++;
desc = p;
p = strchr (desc, ' ');
if (p)
*p = 0; /* ignore garbage */
}
}
}
if (!cacheid || !*cacheid || strlen (cacheid) > 50)
return set_error (Parameter_Error, "invalid length of cacheID");
if (!desc)
return set_error (Parameter_Error, "no description given");
if (!strcmp (cacheid, "X"))
cacheid = NULL;
if (!strcmp (errtext, "X"))
errtext = NULL;
if (!strcmp (prompt, "X"))
prompt = NULL;
if (!strcmp (desc, "X"))
desc = NULL;
/* Note: we store the hexified versions in the cache. */
pw = cacheid ? agent_get_cache (cacheid, &cache_marker) : NULL;
if (pw)
{
assuan_begin_confidential (ctx);
rc = assuan_set_okay_line (ctx, pw);
agent_unlock_cache_entry (&cache_marker);
}
else
{
/* Note, that we only need to replace the + characters and
should leave the other escaping in place because the escaped
string is send verbatim to the pinentry which does the
unescaping (but not the + replacing) */
if (errtext)
plus_to_blank (errtext);
if (prompt)
plus_to_blank (prompt);
if (desc)
plus_to_blank (desc);
rc = agent_get_passphrase (&response, desc, prompt, errtext);
if (!rc)
{
if (cacheid)
agent_put_cache (cacheid, response, 0);
assuan_begin_confidential (ctx);
rc = assuan_set_okay_line (ctx, response);
xfree (response);
}
}
if (rc)
log_error ("command get_passphrase failed: %s\n", gnupg_strerror (rc));
return map_to_assuan_status (rc);
}
/* CLEAR_PASSPHRASE <cache_id>
may be used to invalidate the cache entry for a passphrase. The
function returns with OK even when there is no cached passphrase.
*/
static int
cmd_clear_passphrase (ASSUAN_CONTEXT ctx, char *line)
{
char *cacheid = NULL;
char *p;
/* parse the stuff */
for (p=line; *p == ' '; p++)
;
cacheid = p;
p = strchr (cacheid, ' ');
if (p)
*p = 0; /* ignore garbage */
if (!cacheid || !*cacheid || strlen (cacheid) > 50)
return set_error (Parameter_Error, "invalid length of cacheID");
agent_put_cache (cacheid, NULL, 0);
return 0;
}
/* LEARN [--send]
Learn something about the currently inserted smartcard. With
--send the new certificates are send back. */
static int
cmd_learn (ASSUAN_CONTEXT ctx, char *line)
{
int rc;
rc = agent_handle_learn (has_option (line, "--send")? ctx : NULL);
if (rc)
log_error ("command learn failed: %s\n", gnupg_strerror (rc));
return map_to_assuan_status (rc);
}
static int
option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
{
CTRL ctrl = assuan_get_pointer (ctx);
/* FIXME: We should not change opt. here. It is not a problem right
now but as soon as we are allowing concurrent connections we mess
things up */
if (!strcmp (key, "display"))
{
if (opt.display)
free (opt.display);
opt.display = strdup (value);
if (!opt.display)
return ASSUAN_Out_Of_Core;
}
else if (!strcmp (key, "ttyname"))
{
if (opt.ttyname)
free (opt.ttyname);
opt.ttyname = strdup (value);
if (!opt.ttyname)
return ASSUAN_Out_Of_Core;
}
else if (!strcmp (key, "ttytype"))
{
if (opt.ttytype)
free (opt.ttytype);
opt.ttytype = strdup (value);
if (!opt.ttytype)
return ASSUAN_Out_Of_Core;
}
else if (!strcmp (key, "lc-ctype"))
{
if (opt.lc_ctype)
free (opt.lc_ctype);
opt.lc_ctype = strdup (value);
if (!opt.lc_ctype)
return ASSUAN_Out_Of_Core;
}
else if (!strcmp (key, "lc-messages"))
{
if (opt.lc_messages)
free (opt.lc_messages);
opt.lc_messages = strdup (value);
if (!opt.lc_messages)
return ASSUAN_Out_Of_Core;
}
else if (!strcmp (key, "use-cache-for-signing"))
ctrl->server_local->use_cache_for_signing = *value? atoi (value) : 0;
else
return ASSUAN_Invalid_Option;
return 0;
}
/* Tell the assuan library about our commands */
static int
register_commands (ASSUAN_CONTEXT ctx)
{
static struct {
const char *name;
int cmd_id;
int (*handler)(ASSUAN_CONTEXT, char *line);
} table[] = {
{ "ISTRUSTED", 0, cmd_istrusted },
{ "HAVEKEY", 0, cmd_havekey },
{ "SIGKEY", 0, cmd_sigkey },
{ "SETKEY", 0, cmd_sigkey },
{ "SETHASH", 0, cmd_sethash },
{ "PKSIGN", 0, cmd_pksign },
{ "PKDECRYPT", 0, cmd_pkdecrypt },
{ "GENKEY", 0, cmd_genkey },
{ "GET_PASSPHRASE",0, cmd_get_passphrase },
{ "CLEAR_PASSPHRASE",0, cmd_clear_passphrase },
{ "LISTTRUSTED", 0, cmd_listtrusted },
{ "MARKTRUSTED", 0, cmd_marktrusted },
{ "LEARN", 0, cmd_learn },
{ "", ASSUAN_CMD_INPUT, NULL },
{ "", ASSUAN_CMD_OUTPUT, NULL },
{ NULL }
};
int i, j, rc;
for (i=j=0; table[i].name; i++)
{
rc = assuan_register_command (ctx,
table[i].cmd_id? table[i].cmd_id
: (ASSUAN_CMD_USER + j++),
table[i].name, table[i].handler);
if (rc)
return rc;
}
assuan_register_reset_notify (ctx, reset_notify);
assuan_register_option_handler (ctx, option_handler);
return 0;
}
/* Startup the server. If LISTEN_FD and FD is given as -1, this is a simple
piper server, otherwise it is a regular server */
void
start_command_handler (int listen_fd, int fd)
{
int rc;
ASSUAN_CONTEXT ctx;
struct server_control_s ctrl;
memset (&ctrl, 0, sizeof ctrl);
if (listen_fd == -1 && fd == -1)
{
int filedes[2];
filedes[0] = 0;
filedes[1] = 1;
rc = assuan_init_pipe_server (&ctx, filedes);
}
else if (listen_fd != -1)
{
rc = assuan_init_socket_server (&ctx, listen_fd);
}
else
{
rc = assuan_init_connected_socket_server (&ctx, fd);
}
if (rc)
{
log_error ("failed to initialize the server: %s\n",
assuan_strerror(rc));
agent_exit (2);
}
rc = register_commands (ctx);
if (rc)
{
log_error ("failed to register commands with Assuan: %s\n",
assuan_strerror(rc));
agent_exit (2);
}
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;
if (DBG_ASSUAN)
assuan_set_log_stream (ctx, log_get_stream ());
for (;;)
{
rc = assuan_accept (ctx);
if (rc == -1)
{
break;
}
else if (rc)
{
log_info ("Assuan accept problem: %s\n", assuan_strerror (rc));
break;
}
rc = assuan_process (ctx);
if (rc)
{
log_info ("Assuan processing failed: %s\n", assuan_strerror (rc));
continue;
}
}
assuan_deinit_server (ctx);
}

View File

@ -1,305 +0,0 @@
/* divert-scd.c - divert operations to the scdaemon
* Copyright (C) 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#include "agent.h"
#include "sexp-parse.h"
#include "i18n.h"
static int
ask_for_card (const unsigned char *shadow_info, char **r_kid)
{
int rc, i;
const unsigned char *s;
size_t n;
char *serialno;
int no_card = 0;
char *desc;
char *want_sn, *want_kid;
int want_sn_displen;
*r_kid = NULL;
s = shadow_info;
if (*s != '(')
return GNUPG_Invalid_Sexp;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
want_sn = xtrymalloc (n*2+1);
if (!want_sn)
return GNUPG_Out_Of_Core;
for (i=0; i < n; i++)
sprintf (want_sn+2*i, "%02X", s[i]);
s += n;
/* We assume that a 20 byte serial number is a standard one which
seems to have the property to have a zero in the last nibble. We
don't display this '0' because it may confuse the user */
want_sn_displen = strlen (want_sn);
if (want_sn_displen == 20 && want_sn[19] == '0')
want_sn_displen--;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
want_kid = xtrymalloc (n+1);
if (!want_kid)
{
xfree (want_sn);
return GNUPG_Out_Of_Core;
}
memcpy (want_kid, s, n);
want_kid[n] = 0;
for (;;)
{
rc = agent_card_serialno (&serialno);
if (!rc)
{
log_debug ("detected card with S/N %s\n", serialno);
i = strcmp (serialno, want_sn);
xfree (serialno);
serialno = NULL;
if (!i)
{
xfree (want_sn);
*r_kid = want_kid;
return 0; /* yes, we have the correct card */
}
}
else if (rc == GNUPG_Card_Not_Present)
{
log_debug ("no card present\n");
rc = 0;
no_card = 1;
}
else
{
log_error ("error accesing card: %s\n", gnupg_strerror (rc));
}
if (!rc)
{
if (asprintf (&desc,
"%s:%%0A%%0A"
" \"%.*s\"",
no_card? "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 = GNUPG_Out_Of_Core;
}
else
{
rc = agent_get_confirmation (desc, NULL, NULL);
free (desc);
}
}
if (rc)
{
xfree (want_sn);
xfree (want_kid);
return rc;
}
}
}
/* Put the DIGEST into an DER encoded comtainer and return it in R_VAL. */
static int
encode_md_for_card (const unsigned char *digest, size_t digestlen, int algo,
unsigned char **r_val, size_t *r_len)
{
byte *frame;
byte asn[100];
size_t asnlen;
asnlen = DIM(asn);
if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
{
log_error ("no object identifier for algo %d\n", algo);
return GNUPG_Internal_Error;
}
frame = xtrymalloc (asnlen + digestlen);
if (!frame)
return GNUPG_Out_Of_Core;
memcpy (frame, asn, asnlen);
memcpy (frame+asnlen, digest, digestlen);
if (DBG_CRYPTO)
log_printhex ("encoded hash:", frame, asnlen+digestlen);
*r_val = frame;
*r_len = asnlen+digestlen;
return 0;
}
/* Callback used to ask for the PIN which should be set into BUF. The
buf has been allocated by the caller and is of size MAXBUF which
includes the terminating null. The function should return an UTF-8
string with the passphrase, the buffer may optionally be padded
with arbitrary characters */
static int
getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
{
struct pin_entry_info_s *pi;
int rc;
char *desc;
assert (!opaque);
if (maxbuf < 2)
return GNUPG_Invalid_Value;
/* FIXME: keep PI and TRIES in OPAQUE. Frankly this is a whole
mess because we should call the card's verify function from the
pinentry check pin CB. */
pi = gcry_calloc_secure (1, sizeof (*pi) + 100);
pi->max_length = maxbuf-1;
pi->min_digits = 0; /* we want a real passphrase */
pi->max_digits = 8;
pi->max_tries = 3;
if ( asprintf (&desc, _("Please enter the PIN%s%s%s to unlock the card"),
info? " (`":"",
info? info:"",
info? "')":"") < 0)
desc = NULL;
rc = agent_askpin (desc?desc:info, pi);
free (desc);
if (!rc)
{
strncpy (buf, pi->pin, maxbuf-1);
buf[maxbuf-1] = 0;
}
xfree (pi);
return rc;
}
int
divert_pksign (const unsigned char *digest, size_t digestlen, int algo,
const unsigned char *shadow_info, unsigned char **r_sig)
{
int rc;
char *kid;
size_t siglen;
char *sigval;
unsigned char *data;
size_t ndata;
rc = ask_for_card (shadow_info, &kid);
if (rc)
return rc;
rc = encode_md_for_card (digest, digestlen, algo,
&data, &ndata);
if (rc)
return rc;
rc = agent_card_pksign (kid, getpin_cb, NULL,
data, ndata, &sigval, &siglen);
if (!rc)
*r_sig = sigval;
xfree (data);
xfree (kid);
return rc;
}
/* 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. */
int
divert_pkdecrypt (const unsigned char *cipher,
const unsigned char *shadow_info,
char **r_buf, size_t *r_len)
{
int rc;
char *kid;
const unsigned char *s;
size_t n;
const unsigned char *ciphertext;
size_t ciphertextlen;
char *plaintext;
size_t plaintextlen;
s = cipher;
if (*s != '(')
return GNUPG_Invalid_Sexp;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
if (!smatch (&s, n, "enc-val"))
return GNUPG_Unknown_Sexp;
if (*s != '(')
return GNUPG_Unknown_Sexp;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
if (!smatch (&s, n, "rsa"))
return GNUPG_Unsupported_Algorithm;
if (*s != '(')
return GNUPG_Unknown_Sexp;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
if (!smatch (&s, n, "a"))
return GNUPG_Unknown_Sexp;
n = snext (&s);
if (!n)
return GNUPG_Unknown_Sexp;
ciphertext = s;
ciphertextlen = n;
rc = ask_for_card (shadow_info, &kid);
if (rc)
return rc;
rc = agent_card_pkdecrypt (kid, getpin_cb, NULL,
ciphertext, ciphertextlen,
&plaintext, &plaintextlen);
if (!rc)
{
*r_buf = plaintext;
*r_len = plaintextlen;
}
xfree (kid);
return rc;
}

View File

@ -1,350 +0,0 @@
/* findkey.c - locate the secret key
* Copyright (C) 2001,02 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#include <assert.h>
#include "agent.h"
/* Helper to pass data to the check callback of the unprotect function. */
struct try_unprotect_arg_s {
const unsigned char *protected_key;
unsigned char *unprotected_key;
};
int
agent_write_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force)
{
int i;
char *fname;
FILE *fp;
char hexgrip[40+4+1];
for (i=0; i < 20; i++)
sprintf (hexgrip+2*i, "%02X", grip[i]);
strcpy (hexgrip+40, ".key");
fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
if (force)
fp = fopen (fname, "wb");
else
{
int fd;
if (!access (fname, F_OK))
{
log_error ("secret key file `%s' already exists\n", fname);
xfree (fname);
return seterr (General_Error);
}
/* 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.
The mode parameter to open is what fopen uses. It will be
combined with the process' umask automatically. */
fd = open (fname, O_CREAT | O_EXCL | O_RDWR,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (fd < 0)
fp = 0;
else
{
fp = fdopen (fd, "wb");
if (! fp)
close (fd);
}
}
if (!fp)
{
log_error ("can't create `%s': %s\n", fname, strerror (errno));
xfree (fname);
return seterr (File_Create_Error);
}
if (fwrite (buffer, length, 1, fp) != 1)
{
log_error ("error writing `%s': %s\n", fname, strerror (errno));
fclose (fp);
remove (fname);
xfree (fname);
return seterr (File_Create_Error);
}
if ( fclose (fp) )
{
log_error ("error closing `%s': %s\n", fname, strerror (errno));
remove (fname);
xfree (fname);
return seterr (File_Create_Error);
}
xfree (fname);
return 0;
}
/* 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;
size_t dummy;
assert (!arg->unprotected_key);
return agent_unprotect (arg->protected_key, pi->pin,
&arg->unprotected_key, &dummy);
}
/* Unprotect the canconical encoded S-expression key in KEYBUF. GRIP
should be the hex encoded keygrip of that key to be used with the
cahing mechanism. */
static int
unprotect (unsigned char **keybuf, const unsigned char *grip, int ignore_cache)
{
struct pin_entry_info_s *pi;
struct try_unprotect_arg_s arg;
int rc, i;
unsigned char *result;
size_t resultlen;
char hexgrip[40+1];
for (i=0; i < 20; i++)
sprintf (hexgrip+2*i, "%02X", grip[i]);
hexgrip[40] = 0;
/* 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 (!ignore_cache)
{
void *cache_marker;
const char *pw = agent_get_cache (hexgrip, &cache_marker);
if (pw)
{
rc = agent_unprotect (*keybuf, pw, &result, &resultlen);
agent_unlock_cache_entry (&cache_marker);
if (!rc)
{
xfree (*keybuf);
*keybuf = result;
return 0;
}
rc = 0;
}
}
pi = gcry_calloc_secure (1, sizeof (*pi) + 100);
pi->max_length = 100;
pi->min_digits = 0; /* we want a real passphrase */
pi->max_digits = 8;
pi->max_tries = 3;
pi->check_cb = try_unprotect_cb;
arg.protected_key = *keybuf;
arg.unprotected_key = NULL;
pi->check_cb_arg = &arg;
rc = agent_askpin (NULL, pi);
if (!rc)
{
assert (arg.unprotected_key);
agent_put_cache (hexgrip, pi->pin, 0);
xfree (*keybuf);
*keybuf = arg.unprotected_key;
}
xfree (pi);
return rc;
}
/* Return the secret key as an S-Exp after locating it using the grip.
Returns NULL if key is not available or the operation should be
diverted to a token. In the latter case shadow_info will point to
an allocated S-Expression with the shadow_info part from the file.
With IGNORE_CACHE passed as true the passphrase is not taken from
the cache.*/
GCRY_SEXP
agent_key_from_file (const unsigned char *grip, unsigned char **shadow_info,
int ignore_cache)
{
int i, rc;
char *fname;
FILE *fp;
struct stat st;
unsigned char *buf;
size_t len, buflen, erroff;
GCRY_SEXP s_skey;
char hexgrip[40+4+1];
if (shadow_info)
*shadow_info = NULL;
for (i=0; i < 20; i++)
sprintf (hexgrip+2*i, "%02X", grip[i]);
strcpy (hexgrip+40, ".key");
fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
fp = fopen (fname, "rb");
if (!fp)
{
log_error ("can't open `%s': %s\n", fname, strerror (errno));
xfree (fname);
return NULL;
}
if (fstat (fileno(fp), &st))
{
log_error ("can't stat `%s': %s\n", fname, strerror (errno));
xfree (fname);
fclose (fp);
return NULL;
}
buflen = st.st_size;
buf = xmalloc (buflen+1);
if (fread (buf, buflen, 1, fp) != 1)
{
log_error ("error reading `%s': %s\n", fname, strerror (errno));
xfree (fname);
fclose (fp);
xfree (buf);
return NULL;
}
rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
xfree (fname);
fclose (fp);
xfree (buf);
if (rc)
{
log_error ("failed to build S-Exp (off=%u): %s\n",
(unsigned int)erroff, gcry_strerror (rc));
return NULL;
}
len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
assert (len);
buf = xtrymalloc (len);
if (!buf)
{
gcry_sexp_release (s_skey);
return NULL;
}
len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, buf, len);
assert (len);
gcry_sexp_release (s_skey);
switch (agent_private_key_type (buf))
{
case PRIVATE_KEY_CLEAR:
break; /* no unprotection needed */
case PRIVATE_KEY_PROTECTED:
rc = unprotect (&buf, grip, ignore_cache);
if (rc)
log_error ("failed to unprotect the secret key: %s\n",
gnupg_strerror (rc));
break;
case PRIVATE_KEY_SHADOWED:
if (shadow_info)
{
const unsigned char *s;
size_t n;
rc = agent_get_shadow_info (buf, &s);
if (!rc)
{
n = gcry_sexp_canon_len (s, 0, NULL,NULL);
assert (n);
*shadow_info = xtrymalloc (n);
if (!*shadow_info)
rc = GNUPG_Out_Of_Core;
else
{
memcpy (*shadow_info, s, n);
rc = 0;
}
}
if (rc)
log_error ("get_shadow_info failed: %s\n", gnupg_strerror (rc));
}
rc = -1; /* ugly interface: we return an error but keep a value
in shadow_info. */
break;
default:
log_error ("invalid private key format\n");
rc = GNUPG_Bad_Secret_Key;
break;
}
if (rc)
{
xfree (buf);
return NULL;
}
/* arggg FIXME: does scan support secure memory? */
rc = gcry_sexp_sscan (&s_skey, &erroff,
buf, gcry_sexp_canon_len (buf, 0, NULL, NULL));
xfree (buf);
if (rc)
{
log_error ("failed to build S-Exp (off=%u): %s\n",
(unsigned int)erroff, gcry_strerror (rc));
return NULL;
}
return s_skey;
}
/* Return the secret key as an S-Exp after locating it using the grip.
Returns NULL if key is not available. 0 = key is available */
int
agent_key_available (const unsigned char *grip)
{
int i;
char *fname;
char hexgrip[40+4+1];
for (i=0; i < 20; i++)
sprintf (hexgrip+2*i, "%02X", grip[i]);
strcpy (hexgrip+40, ".key");
fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
i = !access (fname, R_OK)? 0 : -1;
xfree (fname);
return i;
}

View File

@ -1,200 +0,0 @@
/* pksign.c - Generate a keypair
* Copyright (C) 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "agent.h"
#include "i18n.h"
static int
store_key (GCRY_SEXP private, const char *passphrase)
{
int rc;
char *buf;
size_t len;
unsigned char grip[20];
if ( !gcry_pk_get_keygrip (private, grip) )
{
log_error ("can't calculate keygrip\n");
return seterr (General_Error);
}
len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, NULL, 0);
assert (len);
buf = gcry_malloc_secure (len);
if (!buf)
return seterr (Out_Of_Core);
len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, buf, len);
assert (len);
if (passphrase)
{
unsigned char *p;
rc = agent_protect (buf, passphrase, &p, &len);
if (rc)
{
xfree (buf);
return rc;
}
xfree (buf);
buf = p;
}
rc = agent_write_private_key (grip, buf, len, 0);
xfree (buf);
return rc;
}
/* Callback function to compare the first entered PIN with the one
currently beeing entered. */
static int
reenter_compare_cb (struct pin_entry_info_s *pi)
{
const char *pin1 = pi->check_cb_arg;
if (!strcmp (pin1, pi->pin))
return 0; /* okay */
pi->cb_errtext = _("does not match - try again");
return -1;
}
/* Generate a new keypair according to the parameters given in
KEYPARAM */
int
agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparamlen,
FILE *outfp)
{
GCRY_SEXP s_keyparam, s_key, s_private, s_public;
struct pin_entry_info_s *pi, *pi2;
int rc;
size_t len;
char *buf;
rc = gcry_sexp_sscan (&s_keyparam, NULL, keyparam, keyparamlen);
if (rc)
{
log_error ("failed to convert keyparam: %s\n", gcry_strerror (rc));
return seterr (Invalid_Data);
}
/* Get the passphrase now, cause key generation may take a while. */
{
const char *text1 = _("Please enter the passphrase to%0A"
"to protect your new key");
const char *text2 = _("Please re-enter this passphrase");
pi = gcry_calloc_secure (2, sizeof (*pi) + 100);
pi2 = pi + (sizeof *pi + 100);
pi->max_length = 100;
pi->max_tries = 3;
pi2->max_length = 100;
pi2->max_tries = 3;
pi2->check_cb = reenter_compare_cb;
pi2->check_cb_arg = pi->pin;
rc = agent_askpin (text1, pi);
if (!rc)
rc = agent_askpin (text2, pi2);
if (rc)
return rc;
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", gcry_strerror (rc));
xfree (pi);
return map_gcry_err (rc);
}
/* break out the parts */
s_private = gcry_sexp_find_token (s_key, "private-key", 0);
if (!s_private)
{
log_error ("key generation failed: invalid return value\n");
gcry_sexp_release (s_key);
xfree (pi);
return seterr (Invalid_Data);
}
s_public = gcry_sexp_find_token (s_key, "public-key", 0);
if (!s_public)
{
log_error ("key generation failed: invalid return value\n");
gcry_sexp_release (s_private);
gcry_sexp_release (s_key);
xfree (pi);
return seterr (Invalid_Data);
}
gcry_sexp_release (s_key); s_key = NULL;
/* store the secret key */
log_debug ("storing private key\n");
rc = store_key (s_private, pi? pi->pin:NULL);
xfree (pi); pi = NULL;
gcry_sexp_release (s_private);
if (rc)
{
gcry_sexp_release (s_public);
return rc;
}
/* return the public key */
log_debug ("returning public key\n");
len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, NULL, 0);
assert (len);
buf = xmalloc (len);
if (!buf)
{
gcry_sexp_release (s_private);
gcry_sexp_release (s_public);
return seterr (Out_Of_Core);
}
len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, buf, len);
assert (len);
if (fwrite (buf, len, 1, outfp) != 1)
{
log_error ("error writing public key: %s\n", strerror (errno));
gcry_sexp_release (s_private);
gcry_sexp_release (s_public);
xfree (buf);
return seterr (File_Create_Error);
}
gcry_sexp_release (s_public);
xfree (buf);
return 0;
}

View File

@ -1,916 +0,0 @@
/* gpg-agent.c - The GnuPG Agent
* Copyright (C) 2000, 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <time.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <signal.h>
#ifdef USE_GNU_PTH
# include <pth.h>
#endif
#include <gcrypt.h>
#define JNLIB_NEED_LOG_LOGV
#include "agent.h"
#include "../assuan/assuan.h" /* malloc hooks */
#include "i18n.h"
#include "sysutils.h"
enum cmd_and_opt_values
{ aNull = 0,
oCsh = 'c',
oQuiet = 'q',
oSh = 's',
oVerbose = 'v',
oNoVerbose = 500,
oOptions,
oDebug,
oDebugAll,
oDebugWait,
oNoGreeting,
oNoOptions,
oHomedir,
oNoDetach,
oNoGrab,
oLogFile,
oServer,
oDaemon,
oBatch,
oPinentryProgram,
oDisplay,
oTTYname,
oTTYtype,
oLCctype,
oLCmessages,
oScdaemonProgram,
oDefCacheTTL,
oDisablePth,
oIgnoreCacheForSigning,
oKeepTTY,
oKeepDISPLAY,
aTest };
static ARGPARSE_OPTS opts[] = {
{ 301, NULL, 0, N_("@Options:\n ") },
{ oServer, "server", 0, N_("run in server mode (foreground)") },
{ oDaemon, "daemon", 0, N_("run in daemon mode (background)") },
{ 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_("read options from file")},
{ oDebug, "debug" ,4|16, N_("set debugging flags")},
{ oDebugAll, "debug-all" ,0, N_("enable full debugging")},
{ 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")},
{ oDisablePth, "disable-pth", 0, N_("do not allow multiple connections")},
{ oPinentryProgram, "pinentry-program", 2 , "path to PIN Entry program" },
{ oDisplay, "display", 2, "set the display" },
{ oTTYname, "ttyname", 2, "set the tty terminal node name" },
{ oTTYtype, "ttytype", 2, "set the tty terminal type" },
{ oLCctype, "lc-ctype", 2, "set the tty LC_CTYPE value" },
{ oLCmessages, "lc-messages", 2, "set the tty LC_MESSAGES value" },
{ oScdaemonProgram, "scdaemon-program", 2 , "path to SCdaemon program" },
{ oDefCacheTTL, "default-cache-ttl", 4,
"|N|expire cached PINs after N seconds"},
{ oIgnoreCacheForSigning, "ignore-cache-for-signing", 0,
"do not use the PIN cache when signing"},
{ oKeepTTY, "keep-tty", 0, N_("ignore requests to change the TTY")},
{ oKeepDISPLAY, "keep-display",
0, N_("ignore requests to change the X display")},
{0}
};
static volatile int caught_fatal_sig = 0;
/* flag to indicate that a shutdown was requested */
static int shutdown_pending;
/* It is possible that we are currently running under setuid permissions */
static int maybe_setuid = 1;
/* Name of the communication socket */
static char socket_name[128];
static void create_directories (void);
#ifdef USE_GNU_PTH
static void handle_connections (int listen_fd);
#endif
static const char *
my_strusage (int level)
{
const char *p;
switch (level)
{
case 11: p = "gpg-agent (GnuPG)";
break;
case 13: p = VERSION; break;
case 17: p = PRINTABLE_OS_NAME; break;
case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
break;
case 1:
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");
break;
default: p = NULL;
}
return p;
}
static void
i18n_init (void)
{
#ifdef USE_SIMPLE_GETTEXT
set_gettext_file( PACKAGE );
#else
#ifdef ENABLE_NLS
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
#endif
#endif
}
/* Used by gcry for logging */
static void
my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
{
/* translate the log levels */
switch (level)
{
case GCRY_LOG_CONT: level = JNLIB_LOG_CONT; break;
case GCRY_LOG_INFO: level = JNLIB_LOG_INFO; break;
case GCRY_LOG_WARN: level = JNLIB_LOG_WARN; break;
case GCRY_LOG_ERROR:level = JNLIB_LOG_ERROR; break;
case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break;
case GCRY_LOG_BUG: level = JNLIB_LOG_BUG; break;
case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break;
default: level = JNLIB_LOG_ERROR; break;
}
log_logv (level, fmt, arg_ptr);
}
static void
cleanup (void)
{
if (*socket_name)
{
char *p;
remove (socket_name);
p = strrchr (socket_name, '/');
if (p)
{
*p = 0;
rmdir (socket_name);
*p = '/';
}
*socket_name = 0;
}
}
static RETSIGTYPE
cleanup_sh (int sig)
{
if (caught_fatal_sig)
raise (sig);
caught_fatal_sig = 1;
/* gcry_control( GCRYCTL_TERM_SECMEM );*/
cleanup ();
#ifndef HAVE_DOSISH_SYSTEM
{ /* reset action to default action and raise signal again */
struct sigaction nact;
nact.sa_handler = SIG_DFL;
sigemptyset( &nact.sa_mask );
nact.sa_flags = 0;
sigaction( sig, &nact, NULL);
}
#endif
raise( sig );
}
int
main (int argc, char **argv )
{
ARGPARSE_ARGS pargs;
int orig_argc;
int may_coredump;
char **orig_argv;
FILE *configfp = NULL;
char *configname = NULL;
const char *shell;
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;
int csh_style = 0;
char *logfile = NULL;
int debug_wait = 0;
int disable_pth = 0;
set_strusage (my_strusage);
gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
/* 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", 1|4);
i18n_init ();
/* check that the libraries are suitable. Do it here because
the option parsing may need services of the library */
if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
{
log_fatal( _("libgcrypt is too old (need %s, have %s)\n"),
NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
}
assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
#ifdef USE_GNU_PTH
assuan_set_io_func (pth_read, pth_write);
#endif
gcry_set_log_handler (my_gcry_logger, NULL);
gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
may_coredump = disable_core_dumps ();
shell = getenv ("SHELL");
if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
csh_style = 1;
opt.homedir = getenv("GNUPGHOME");
if (!opt.homedir || !*opt.homedir)
opt.homedir = GNUPG_DEFAULT_HOMEDIR;
opt.def_cache_ttl = 10*60; /* default to 10 minutes */
/* check whether we have a config file on the commandline */
orig_argc = argc;
orig_argv = argv;
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= 1|(1<<6); /* do not remove the args, ignore version */
while (arg_parse( &pargs, opts))
{
if (pargs.r_opt == oDebug || pargs.r_opt == oDebugAll)
parse_debug++;
else if (pargs.r_opt == oOptions)
{ /* yes there is one, so we do not try the default one, but
read the option file when it is encountered at the
commandline */
default_config = 0;
}
else if (pargs.r_opt == oNoOptions)
default_config = 0; /* --no-options */
else if (pargs.r_opt == oHomedir)
opt.homedir = pargs.r.ret_str;
}
/* initialize the secure memory. */
gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
maybe_setuid = 0;
/*
Now we are now working under our real uid
*/
if (default_config)
configname = make_filename (opt.homedir, "gpg-agent.conf", NULL );
argc = orig_argc;
argv = orig_argv;
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= 1; /* do not remove the args */
next_pass:
if (configname)
{
configlineno = 0;
configfp = fopen (configname, "r");
if (!configfp)
{
if (default_config)
{
if( parse_debug )
log_info (_("NOTE: no default option file `%s'\n"),
configname );
}
else
{
log_error (_("option file `%s': %s\n"),
configname, strerror(errno) );
exit(2);
}
xfree (configname);
configname = NULL;
}
if (parse_debug && configname )
log_info (_("reading options from `%s'\n"), configname );
default_config = 0;
}
while (optfile_parse( configfp, configname, &configlineno, &pargs, opts) )
{
switch (pargs.r_opt)
{
case oQuiet: opt.quiet = 1; break;
case oVerbose: opt.verbose++; break;
case oBatch: opt.batch=1; break;
case oDebug: opt.debug |= pargs.r.ret_ulong; break;
case oDebugAll: opt.debug = ~0; break;
case oDebugWait: debug_wait = pargs.r.ret_int; break;
case oOptions:
/* config files may not be nested (silently ignore them) */
if (!configfp)
{
xfree(configname);
configname = xstrdup(pargs.r.ret_str);
goto next_pass;
}
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;
case oNoDetach: nodetach = 1; break;
case oNoGrab: opt.no_grab = 1; break;
case oLogFile: logfile = pargs.r.ret_str; break;
case oCsh: csh_style = 1; break;
case oSh: csh_style = 0; break;
case oServer: pipe_server = 1; break;
case oDaemon: is_daemon = 1; break;
case oDisablePth: disable_pth = 1; break;
case oPinentryProgram: opt.pinentry_program = pargs.r.ret_str; break;
case oDisplay: opt.display = xstrdup (pargs.r.ret_str); break;
case oTTYname: opt.ttyname = xstrdup (pargs.r.ret_str); break;
case oTTYtype: opt.ttytype = xstrdup (pargs.r.ret_str); break;
case oLCctype: opt.lc_ctype = xstrdup (pargs.r.ret_str); break;
case oLCmessages: opt.lc_messages = xstrdup (pargs.r.ret_str); break;
case oScdaemonProgram: opt.scdaemon_program = pargs.r.ret_str; break;
case oDefCacheTTL: opt.def_cache_ttl = pargs.r.ret_ulong; break;
case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break;
case oKeepTTY: opt.keep_tty = 1; break;
case oKeepDISPLAY: opt.keep_display = 1; break;
default : pargs.err = configfp? 1:2; break;
}
}
if (configfp)
{
fclose( configfp );
configfp = NULL;
xfree(configname);
configname = NULL;
goto next_pass;
}
xfree (configname);
configname = NULL;
if (log_get_errorcount(0))
exit(2);
if (nogreeting )
greeting = 0;
if (greeting)
{
fprintf (stderr, "%s %s; %s\n",
strusage(11), strusage(13), strusage(14) );
fprintf (stderr, "%s\n", strusage(15) );
}
#ifdef IS_DEVELOPMENT_VERSION
log_info ("NOTE: this is a development version!\n");
#endif
if (atexit (cleanup))
{
log_error ("atexit failed\n");
cleanup ();
exit (1);
}
create_directories ();
if (debug_wait && pipe_server)
{
log_debug ("waiting for debugger - my pid is %u .....\n",
(unsigned int)getpid());
sleep (debug_wait);
log_debug ("... okay\n");
}
/* now start with logging to a file if this is desired */
if (logfile)
{
log_set_file (logfile);
log_set_prefix (NULL, 1|2|4);
}
if (pipe_server)
{ /* this is the simple pipe based server */
start_command_handler (-1, -1);
}
else if (!is_daemon)
{
log_info (_("please use the option `--daemon'"
" to run the program in the background\n"));
}
else
{ /* regular server mode */
int fd;
pid_t pid;
int len;
struct sockaddr_un serv_addr;
char *p;
*socket_name = 0;
snprintf (socket_name, DIM(socket_name)-1,
"/tmp/gpg-XXXXXX/S.gpg-agent");
socket_name[DIM(socket_name)-1] = 0;
p = strrchr (socket_name, '/');
if (!p)
BUG ();
*p = 0;;
if (!mkdtemp(socket_name))
{
log_error ("can't create directory `%s': %s\n",
socket_name, strerror(errno) );
exit (1);
}
*p = '/';
if (strchr (socket_name, ':') )
{
log_error ("colons are not allowed in the socket name\n");
exit (1);
}
if (strlen (socket_name)+1 >= sizeof serv_addr.sun_path )
{
log_error ("name of socket too long\n");
exit (1);
}
fd = socket (AF_UNIX, SOCK_STREAM, 0);
if (fd == -1)
{
log_error ("can't create socket: %s\n", strerror(errno) );
exit (1);
}
memset (&serv_addr, 0, sizeof serv_addr);
serv_addr.sun_family = AF_UNIX;
strcpy (serv_addr.sun_path, socket_name);
len = (offsetof (struct sockaddr_un, sun_path)
+ strlen(serv_addr.sun_path) + 1);
if (bind (fd, (struct sockaddr*)&serv_addr, len) == -1)
{
log_error ("error binding socket to `%s': %s\n",
serv_addr.sun_path, strerror (errno) );
close (fd);
exit (1);
}
if (listen (fd, 5 ) == -1)
{
log_error ("listen() failed: %s\n", strerror (errno));
close (fd);
exit (1);
}
if (opt.verbose)
log_info ("listening on socket `%s'\n", socket_name );
fflush (NULL);
pid = fork ();
if (pid == (pid_t)-1)
{
log_fatal ("fork failed: %s\n", strerror (errno) );
exit (1);
}
else if (pid)
{ /* we are the parent */
char *infostr;
close (fd);
/* create the info string: <name>:<pid>:<protocol_version> */
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);
}
*socket_name = 0; /* don't let cleanup() remove the socket -
the child should do this from now on */
if (argc)
{ /* run the program given on the commandline */
if (putenv (infostr))
{
log_error ("failed to set environment: %s\n",
strerror (errno) );
kill (pid, SIGTERM );
exit (1);
}
execvp (argv[0], argv);
log_error ("failed to run the command: %s\n", strerror (errno));
kill (pid, SIGTERM);
exit (1);
}
else
{
/* print the environment string, so that the caller can use
shell's eval to set it */
if (csh_style)
{
*strchr (infostr, '=') = ' ';
printf ( "setenv %s\n", infostr);
}
else
{
printf ( "%s; export GPG_AGENT_INFO;\n", infostr);
}
free (infostr);
exit (0);
}
/*NEVER REACHED*/
} /* end parent */
/* this is the child */
/* detach from tty and put process into a new session */
if (!nodetach )
{
int i;
/* close stdin, stdout and stderr unless it is the log stream */
for (i=0; i <= 2; i++)
{
if ( log_get_fd () != i)
close (i);
}
if (setsid() == -1)
{
log_error ("setsid() failed: %s\n", strerror(errno) );
cleanup ();
exit (1);
}
opt.running_detached = 1;
}
if (chdir("/"))
{
log_error ("chdir to / failed: %s\n", strerror (errno));
exit (1);
}
#ifdef USE_GNU_PTH
if (!disable_pth)
{
struct sigaction sa;
if (!pth_init ())
{
log_error ("failed to initialize the Pth library\n");
exit (1);
}
sa.sa_handler = SIG_IGN;
sigemptyset (&sa.sa_mask);
sa.sa_flags = 0;
sigaction (SIGPIPE, &sa, NULL);
handle_connections (fd);
}
else
#endif /*!USE_GNU_PTH*/
/* setup signals */
{
struct sigaction oact, nact;
nact.sa_handler = cleanup_sh;
sigemptyset (&nact.sa_mask);
nact.sa_flags = 0;
sigaction (SIGHUP, NULL, &oact);
if (oact.sa_handler != SIG_IGN)
sigaction (SIGHUP, &nact, NULL);
sigaction( SIGTERM, NULL, &oact );
if (oact.sa_handler != SIG_IGN)
sigaction (SIGTERM, &nact, NULL);
nact.sa_handler = SIG_IGN;
sigaction (SIGPIPE, &nact, NULL);
sigaction (SIGINT, &nact, NULL);
start_command_handler (fd, -1);
}
close (fd);
}
return 0;
}
void
agent_exit (int rc)
{
/*FIXME: update_random_seed_file();*/
#if 1
/* at this time a bit annoying */
if (opt.debug & DBG_MEMSTAT_VALUE)
{
gcry_control( GCRYCTL_DUMP_MEMORY_STATS );
gcry_control( GCRYCTL_DUMP_RANDOM_STATS );
}
if (opt.debug)
gcry_control (GCRYCTL_DUMP_SECMEM_STATS );
#endif
gcry_control (GCRYCTL_TERM_SECMEM );
rc = rc? rc : log_get_errorcount(0)? 2 : 0;
exit (rc);
}
static void
reread_configuration (void)
{
/* FIXME: Move parts of the option parsing to here. */
}
static void
create_private_keys_directory (const char *home)
{
char *fname;
struct stat statbuf;
fname = make_filename (home, GNUPG_PRIVATE_KEYS_DIR, NULL);
if (stat (fname, &statbuf) && errno == ENOENT)
{
if (mkdir (fname, S_IRUSR|S_IWUSR|S_IXUSR ))
log_error (_("can't create directory `%s': %s\n"),
fname, strerror(errno) );
else if (!opt.quiet)
log_info (_("directory `%s' created\n"), fname);
}
xfree (fname);
}
/* Create the directory only if the supplied directory name is the
same as the default one. This way we avoid to create arbitrary
directories when a non-default home directory is used. To cope
with HOME, we compare only the suffix if we see that the default
homedir does start with a tilde. We don't stop here in case of
problems because other functions will throw an error anyway.*/
static void
create_directories (void)
{
struct stat statbuf;
const char *defhome = GNUPG_DEFAULT_HOMEDIR;
char *home;
home = make_filename (opt.homedir, NULL);
if ( stat (home, &statbuf) )
{
if (errno == ENOENT)
{
if ( (*defhome == '~'
&& (strlen (home) >= strlen (defhome+1)
&& !strcmp (home + strlen(home)
- strlen (defhome+1), defhome+1)))
|| (*defhome != '~' && !strcmp (home, defhome) )
)
{
if (mkdir (home, S_IRUSR|S_IWUSR|S_IXUSR ))
log_error (_("can't create directory `%s': %s\n"),
home, strerror(errno) );
else
{
if (!opt.quiet)
log_info (_("directory `%s' created\n"), home);
create_private_keys_directory (home);
}
}
}
else
log_error ("error stat-ing `%s': %s\n", home, strerror (errno));
}
else if ( !S_ISDIR(statbuf.st_mode))
{
log_error ("can't use `%s' as home directory\n", home);
}
else /* exists and is a directory. */
{
create_private_keys_directory (home);
}
xfree (home);
}
#ifdef USE_GNU_PTH
static void
handle_signal (int signo)
{
switch (signo)
{
case SIGHUP:
log_info ("SIGHUP received - "
"re-reading configuration and flushing cache\n");
agent_flush_cache ();
reread_configuration ();
break;
case SIGUSR1:
if (opt.verbose < 5)
opt.verbose++;
log_info ("SIGUSR1 received - verbosity set to %d\n", opt.verbose);
break;
case SIGUSR2:
if (opt.verbose)
opt.verbose--;
log_info ("SIGUSR2 received - verbosity set to %d\n", opt.verbose );
break;
case SIGTERM:
if (!shutdown_pending)
log_info ("SIGTERM received - shutting down ...\n");
else
log_info ("SIGTERM received - still %ld running threads\n",
pth_ctrl( PTH_CTRL_GETTHREADS ));
shutdown_pending++;
if (shutdown_pending > 2)
{
log_info ("shutdown forced\n");
log_info ("%s %s stopped\n", strusage(11), strusage(13) );
cleanup ();
agent_exit (0);
}
break;
case SIGINT:
log_info ("SIGINT received - immediate shutdown\n");
log_info( "%s %s stopped\n", strusage(11), strusage(13));
cleanup ();
agent_exit (0);
break;
default:
log_info ("signal %d received - no action defined\n", signo);
}
}
static void *
start_connection_thread (void *arg)
{
int fd = (int)arg;
if (opt.verbose)
log_info ("handler for fd %d started\n", fd);
start_command_handler (-1, fd);
if (opt.verbose)
log_info ("handler for fd %d terminated\n", fd);
return NULL;
}
static void
handle_connections (int listen_fd)
{
pth_attr_t tattr;
pth_event_t ev;
sigset_t sigs;
int signo;
struct sockaddr_un paddr;
socklen_t plen = sizeof( paddr );
int fd;
tattr = pth_attr_new();
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 32*1024);
pth_attr_set (tattr, PTH_ATTR_NAME, "gpg-agent");
sigemptyset (&sigs );
sigaddset (&sigs, SIGHUP);
sigaddset (&sigs, SIGUSR1);
sigaddset (&sigs, SIGUSR2);
sigaddset (&sigs, SIGINT);
sigaddset (&sigs, SIGTERM);
ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
for (;;)
{
if (shutdown_pending)
{
if (pth_ctrl (PTH_CTRL_GETTHREADS) == 1)
break; /* ready */
/* Do not accept anymore connections and wait for existing
connections to terminate */
signo = 0;
pth_wait (ev);
if (pth_event_occurred (ev) && signo)
handle_signal (signo);
continue;
}
fd = pth_accept_ev (listen_fd, (struct sockaddr *)&paddr, &plen, ev);
if (fd == -1)
{
if (pth_event_occurred (ev))
{
handle_signal (signo);
continue;
}
log_error ("accept failed: %s - waiting 1s\n", strerror (errno));
pth_sleep(1);
continue;
}
if (!pth_spawn (tattr, start_connection_thread, (void*)fd))
{
log_error ("error spawning connection handler: %s\n",
strerror (errno) );
close (fd);
}
}
pth_event_free (ev, PTH_FREE_ALL);
cleanup ();
log_info ("%s %s stopped\n", strusage(11), strusage(13));
}
#endif /*USE_GNU_PTH*/

View File

@ -1,380 +0,0 @@
/* learncard.c - Handle the LEARN command
* Copyright (C) 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#include "agent.h"
#include "../assuan/assuan.h"
struct keypair_info_s {
struct keypair_info_s *next;
int no_cert;
char *id; /* points into grip */
char hexgrip[1];
};
typedef struct keypair_info_s *KEYPAIR_INFO;
struct kpinfo_cb_parm_s {
int error;
KEYPAIR_INFO info;
};
struct certinfo_s {
struct certinfo_s *next;
int type;
int done;
char id[1];
};
typedef struct certinfo_s *CERTINFO;
struct certinfo_cb_parm_s {
int error;
CERTINFO info;
};
static void
release_keypair_info (KEYPAIR_INFO info)
{
while (info)
{
KEYPAIR_INFO tmp = info->next;
xfree (info);
info = tmp;
}
}
static void
release_certinfo (CERTINFO info)
{
while (info)
{
CERTINFO tmp = info->next;
xfree (info);
info = tmp;
}
}
/* This callback is used by agent_card_leanr and passed the content of
all KEYPAIRINFO lines. It merely stores this data away */
static void
kpinfo_cb (void *opaque, const char *line)
{
struct kpinfo_cb_parm_s *parm = opaque;
KEYPAIR_INFO item;
char *p;
if (parm->error)
return; /* no need to gather data after an error coccured */
item = xtrycalloc (1, sizeof *item + strlen (line));
if (!item)
{
parm->error = GNUPG_Out_Of_Core;
return;
}
strcpy (item->hexgrip, line);
for (p = item->hexgrip; hexdigitp (p); p++)
;
if (p == item->hexgrip && *p == 'X' && spacep (p+1))
{
item->no_cert = 1;
p++;
}
else if ((p - item->hexgrip) != 40 || !spacep (p))
{ /* not a 20 byte hex keygrip or not followed by a space */
parm->error = GNUPG_Invalid_Response;
xfree (item);
return;
}
*p++ = 0;
while (spacep (p))
p++;
item->id = p;
while (*p && !spacep (p))
p++;
if (p == item->id)
{ /* invalid ID string */
parm->error = GNUPG_Invalid_Response;
xfree (item);
return;
}
*p = 0; /* ignore trailing stuff */
/* store it */
item->next = parm->info;
parm->info = item;
}
/* This callback is used by agent_card_leanr and passed the content of
all CERTINFO lines. It merely stores this data away */
static void
certinfo_cb (void *opaque, const char *line)
{
struct certinfo_cb_parm_s *parm = opaque;
CERTINFO item;
int type;
char *p, *pend;
if (parm->error)
return; /* no need to gather data after an error coccured */
type = strtol (line, &p, 10);
while (spacep (p))
p++;
for (pend = p; *pend && !spacep (pend); pend++)
;
if (p == pend || !*p)
{
parm->error = GNUPG_Invalid_Response;
return;
}
*pend = 0; /* ignore trailing stuff */
item = xtrycalloc (1, sizeof *item + strlen (p));
if (!item)
{
parm->error = GNUPG_Out_Of_Core;
return;
}
item->type = type;
strcpy (item->id, p);
/* store it */
item->next = parm->info;
parm->info = item;
}
/* Create an S-expression with the shadow info. */
static unsigned char *
make_shadow_info (const char *serialno, const char *idstring)
{
const char *s;
unsigned char *info, *p;
char numbuf[21];
int n;
for (s=serialno, n=0; *s && s[1]; s += 2)
n++;
info = p = xtrymalloc (1 + 21 + n
+ 21 + strlen (idstring) + 1 + 1);
*p++ = '(';
sprintf (numbuf, "%d:", n);
p = stpcpy (p, numbuf);
for (s=serialno; *s && s[1]; s += 2)
*p++ = xtoi_2 (s);
sprintf (numbuf, "%d:", strlen (idstring));
p = stpcpy (p, numbuf);
p = stpcpy (p, idstring);
*p++ = ')';
*p = 0;
return info;
}
static int
send_cert_back (const char *id, void *assuan_context)
{
int rc;
char *derbuf;
size_t derbuflen;
rc = agent_card_readcert (id, &derbuf, &derbuflen);
if (rc)
{
log_error ("error reading certificate: %s\n",
gnupg_strerror (rc));
return rc;
}
rc = assuan_send_data (assuan_context, derbuf, derbuflen);
xfree (derbuf);
if (!rc)
rc = assuan_send_data (assuan_context, NULL, 0);
if (!rc)
rc = assuan_write_line (assuan_context, "END");
if (rc)
{
log_error ("sending certificate failed: %s\n",
assuan_strerror (rc));
return map_assuan_err (rc);
}
return 0;
}
/* Perform the learn operation. If ASSUAN_CONTEXT is not NULL all new
certificates are send via Assuan */
int
agent_handle_learn (void *assuan_context)
{
int rc;
struct kpinfo_cb_parm_s parm;
struct certinfo_cb_parm_s cparm;
char *serialno = NULL;
KEYPAIR_INFO item;
unsigned char grip[20];
char *p;
int i;
static int certtype_list[] = {
101, /* trusted */
102, /* useful */
100, /* regular */
-1 /* end of list */
};
memset (&parm, 0, sizeof parm);
memset (&cparm, 0, sizeof cparm);
/* Check whether a card is present and get the serial number */
rc = agent_card_serialno (&serialno);
if (rc)
goto leave;
/* now gather all the availabe info */
rc = agent_card_learn (kpinfo_cb, &parm, certinfo_cb, &cparm);
if (!rc && (parm.error || cparm.error))
rc = parm.error? parm.error : cparm.error;
if (rc)
{
log_debug ("agent_card_learn failed: %s\n", gnupg_strerror (rc));
goto leave;
}
log_info ("card has S/N: %s\n", serialno);
/* Write out the certificates in a standard order. */
for (i=0; certtype_list[i] != -1; i++)
{
CERTINFO citem;
for (citem = cparm.info; citem; citem = citem->next)
{
if (certtype_list[i] != citem->type)
continue;
if (opt.verbose)
log_info (" id: %s (type=%d)\n",
citem->id, citem->type);
if (assuan_context)
{
rc = send_cert_back (citem->id, assuan_context);
if (rc)
goto leave;
citem->done = 1;
}
}
}
for (item = parm.info; item; item = item->next)
{
unsigned char *pubkey, *shdkey;
size_t n;
if (opt.verbose)
log_info (" id: %s (grip=%s)\n", item->id, item->hexgrip);
if (item->no_cert)
continue; /* no public key yet available */
for (p=item->hexgrip, i=0; i < 20; p += 2, i++)
grip[i] = xtoi_2 (p);
if (!agent_key_available (grip))
continue;
/* unknown - store it */
rc = agent_card_readkey (item->id, &pubkey);
if (rc)
{
log_debug ("agent_card_readkey failed: %s\n", gnupg_strerror (rc));
goto leave;
}
{
unsigned char *shadow_info = make_shadow_info (serialno, item->id);
if (!shadow_info)
{
rc = GNUPG_Out_Of_Core;
xfree (pubkey);
goto leave;
}
rc = agent_shadow_key (pubkey, shadow_info, &shdkey);
xfree (shadow_info);
}
xfree (pubkey);
if (rc)
{
log_error ("shadowing the key failed: %s\n", gnupg_strerror (rc));
goto leave;
}
n = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
assert (n);
rc = agent_write_private_key (grip, shdkey, n, 0);
xfree (shdkey);
if (rc)
{
log_error ("error writing key: %s\n", gnupg_strerror (rc));
goto leave;
}
if (opt.verbose)
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)
{
if (!strcmp (citem->id, item->id))
break;
}
if (!citem)
{
rc = send_cert_back (item->id, assuan_context);
if (rc)
goto leave;
}
}
}
leave:
xfree (serialno);
release_keypair_info (parm.info);
release_certinfo (cparm.info);
return rc;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,32 +0,0 @@
/* minip12.h - Global definitions for the minimal pkcs-12 implementation.
* Copyright (C) 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef MINIP12_H
#define MINIP12_H
#include <gcrypt.h>
GcryMPI *p12_parse (const unsigned char *buffer, size_t length,
const char *pw);
unsigned char *p12_build (GcryMPI *kparms, const char *pw, size_t *r_length);
#endif /*MINIP12_H*/

View File

@ -1,138 +0,0 @@
/* pkdecrypt.c - public key decryption (well, acually using a secret key)
* Copyright (C) 2001 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#include "agent.h"
/* 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. */
int
agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen,
FILE *outfp)
{
GCRY_SEXP s_skey = NULL, s_cipher = NULL, s_plain = NULL;
unsigned char *shadow_info = NULL;
int rc;
char *buf = NULL;
size_t len;
if (!ctrl->have_keygrip)
{
log_error ("speculative decryption not yet supported\n");
rc = seterr (No_Secret_Key);
goto leave;
}
rc = gcry_sexp_sscan (&s_cipher, NULL, ciphertext, ciphertextlen);
if (rc)
{
log_error ("failed to convert ciphertext: %s\n", gcry_strerror (rc));
rc = seterr (Invalid_Data);
goto leave;
}
if (DBG_CRYPTO)
{
log_printhex ("keygrip:", ctrl->keygrip, 20);
log_printhex ("cipher: ", ciphertext, ciphertextlen);
}
s_skey = agent_key_from_file (ctrl->keygrip, &shadow_info, 0);
if (!s_skey && !shadow_info)
{
log_error ("failed to read the secret key\n");
rc = seterr (No_Secret_Key);
goto leave;
}
if (!s_skey)
{ /* divert operation to the smartcard */
if (!gcry_sexp_canon_len (ciphertext, ciphertextlen, NULL, NULL))
{
rc = GNUPG_Invalid_Sexp;
goto leave;
}
rc = divert_pkdecrypt (ciphertext, shadow_info, &buf, &len );
if (rc)
{
log_error ("smartcard decryption failed: %s\n", gnupg_strerror (rc));
goto leave;
}
/* FIXME: don't use buffering and change the protocol to return
a complete S-expression and not just a part. */
fprintf (outfp, "%u:", (unsigned int)len);
fwrite (buf, 1, len, outfp);
putc (0, outfp);
}
else
{ /* no smartcard, but a private key */
if (DBG_CRYPTO)
{
log_debug ("skey: ");
gcry_sexp_dump (s_skey);
}
rc = gcry_pk_decrypt (&s_plain, s_cipher, s_skey);
if (rc)
{
log_error ("decryption failed: %s\n", gcry_strerror (rc));
rc = map_gcry_err (rc);
goto leave;
}
if (DBG_CRYPTO)
{
log_debug ("plain: ");
gcry_sexp_dump (s_plain);
}
len = gcry_sexp_sprint (s_plain, GCRYSEXP_FMT_CANON, NULL, 0);
assert (len);
buf = xmalloc (len);
len = gcry_sexp_sprint (s_plain, GCRYSEXP_FMT_CANON, buf, len);
assert (len);
/* FIXME: we must make sure that no buffering takes place or we are
in full control of the buffer memory (easy to do) - should go
into assuan. */
fwrite (buf, 1, len, outfp);
}
leave:
gcry_sexp_release (s_skey);
gcry_sexp_release (s_plain);
gcry_sexp_release (s_cipher);
xfree (buf);
xfree (shadow_info);
return rc;
}

View File

@ -1,183 +0,0 @@
/* pksign.c - public key signing (well, acually using a secret key)
* Copyright (C) 2001 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#include "agent.h"
static int
do_encode_md (const unsigned char *digest, size_t digestlen, int algo,
unsigned int nbits, GCRY_MPI *r_val)
{
int nframe = (nbits+7) / 8;
byte *frame;
int i, n;
byte asn[100];
size_t asnlen;
asnlen = DIM(asn);
if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
{
log_error ("no object identifier for algo %d\n", algo);
return GNUPG_Internal_Error;
}
if (digestlen + asnlen + 4 > nframe )
{
log_error ("can't encode a %d bit MD into a %d bits frame\n",
(int)(digestlen*8), (int)nbits);
return GNUPG_Internal_Error;
}
/* We encode the MD in this way:
*
* 0 1 PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes)
*
* PAD consists of FF bytes.
*/
frame = xtrymalloc (nframe);
if (!frame)
return GNUPG_Out_Of_Core;
n = 0;
frame[n++] = 0;
frame[n++] = 1; /* block type */
i = nframe - digestlen - asnlen -3 ;
assert ( i > 1 );
memset ( frame+n, 0xff, i ); n += i;
frame[n++] = 0;
memcpy ( frame+n, asn, asnlen ); n += asnlen;
memcpy ( frame+n, digest, digestlen ); n += digestlen;
assert ( n == nframe );
if (DBG_CRYPTO)
log_printhex ("encoded hash:", frame, nframe);
gcry_mpi_scan (r_val, GCRYMPI_FMT_USG, frame, &nframe);
xfree (frame);
return 0;
}
/* SIGN whatever information we have accumulated in CTRL and write it
back to OUTFP. */
int
agent_pksign (CTRL ctrl, FILE *outfp, int ignore_cache)
{
GCRY_SEXP s_skey = NULL, s_hash = NULL, s_sig = NULL;
GCRY_MPI frame = NULL;
unsigned char *shadow_info = NULL;
int rc;
char *buf = NULL;
size_t len;
if (!ctrl->have_keygrip)
return seterr (No_Secret_Key);
s_skey = agent_key_from_file (ctrl->keygrip, &shadow_info, ignore_cache);
if (!s_skey && !shadow_info)
{
log_error ("failed to read the secret key\n");
rc = seterr (No_Secret_Key);
goto leave;
}
if (!s_skey)
{ /* divert operation to the smartcard */
unsigned char *sigbuf;
rc = divert_pksign (ctrl->digest.value,
ctrl->digest.valuelen,
ctrl->digest.algo,
shadow_info, &sigbuf);
if (rc)
{
log_error ("smartcard signing failed: %s\n", gnupg_strerror (rc));
goto leave;
}
len = gcry_sexp_canon_len (sigbuf, 0, NULL, NULL);
assert (len);
buf = sigbuf;
}
else
{ /* no smartcard, but a private key */
/* put the hash into a sexp */
rc = do_encode_md (ctrl->digest.value,
ctrl->digest.valuelen,
ctrl->digest.algo,
gcry_pk_get_nbits (s_skey),
&frame);
if (rc)
goto leave;
if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
BUG ();
if (DBG_CRYPTO)
{
log_debug ("skey: ");
gcry_sexp_dump (s_skey);
}
/* sign */
rc = gcry_pk_sign (&s_sig, s_hash, s_skey);
if (rc)
{
log_error ("signing failed: %s\n", gcry_strerror (rc));
rc = map_gcry_err (rc);
goto leave;
}
if (DBG_CRYPTO)
{
log_debug ("result: ");
gcry_sexp_dump (s_sig);
}
len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, NULL, 0);
assert (len);
buf = xmalloc (len);
len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, buf, len);
assert (len);
}
/* FIXME: we must make sure that no buffering takes place or we are
in full control of the buffer memory (easy to do) - should go
into assuan. */
fwrite (buf, 1, len, outfp);
leave:
gcry_sexp_release (s_skey);
gcry_sexp_release (s_hash);
gcry_sexp_release (s_sig);
gcry_mpi_release (frame);
xfree (buf);
xfree (shadow_info);
return rc;
}

View File

@ -1,977 +0,0 @@
/* protect-tool.c - A tool to test the secret key protection
* Copyright (C) 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <sys/stat.h>
#include <unistd.h>
#include <gcrypt.h>
#define JNLIB_NEED_LOG_LOGV
#include "agent.h"
#include "minip12.h"
#include "simple-pwquery.h"
#include "i18n.h"
enum cmd_and_opt_values
{ aNull = 0,
oVerbose = 'v',
oArmor = 'a',
oPassphrase = 'P',
oProtect = 'p',
oUnprotect = 'u',
oNoVerbose = 500,
oShadow,
oShowShadowInfo,
oShowKeygrip,
oP12Import,
oP12Export,
oStore,
oForce,
aTest };
struct rsa_secret_key_s
{
MPI n; /* public modulus */
MPI e; /* public exponent */
MPI d; /* exponent */
MPI p; /* prime p. */
MPI q; /* prime q. */
MPI u; /* inverse of p mod q. */
};
static int opt_armor;
static int opt_store;
static int opt_force;
static const char *passphrase;
static const char *get_passphrase (void);
static int store_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force);
static ARGPARSE_OPTS opts[] = {
{ 301, NULL, 0, N_("@Options:\n ") },
{ oVerbose, "verbose", 0, "verbose" },
{ oArmor, "armor", 0, "write output in advanced format" },
{ oPassphrase, "passphrase", 2, "|STRING|use passphrase STRING" },
{ oProtect, "protect", 256, "protect a private key"},
{ oUnprotect, "unprotect", 256, "unprotect a private key"},
{ oShadow, "shadow", 256, "create a shadow entry for a priblic key"},
{ oShowShadowInfo, "show-shadow-info", 256, "return the shadow info"},
{ oShowKeygrip, "show-keygrip", 256, "show the \"keygrip\""},
{ oP12Import, "p12-import", 256, "import a PKCS-12 encoded private key"},
{ oP12Export, "p12-export", 256, "export a private key PKCS-12 encoded"},
{ oStore, "store", 0, "store the created key in the appropriate place"},
{ oForce, "force", 0, "force overwriting"},
{0}
};
static const char *
my_strusage (int level)
{
const char *p;
switch (level)
{
case 11: p = "gpg-protect-tool (GnuPG)";
break;
case 13: p = VERSION; break;
case 17: p = PRINTABLE_OS_NAME; break;
case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
break;
case 1:
case 40: p = _("Usage: gpg-protect-tool [options] (-h for help)\n");
break;
case 41: p = _("Syntax: gpg-protect-tool [options] [args]]\n"
"Secret key maintenance tool\n");
break;
default: p = NULL;
}
return p;
}
static void
i18n_init (void)
{
#ifdef USE_SIMPLE_GETTEXT
set_gettext_file( PACKAGE );
#else
#ifdef ENABLE_NLS
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
#endif
#endif
}
/* Used by gcry for logging */
static void
my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
{
/* translate the log levels */
switch (level)
{
case GCRY_LOG_CONT: level = JNLIB_LOG_CONT; break;
case GCRY_LOG_INFO: level = JNLIB_LOG_INFO; break;
case GCRY_LOG_WARN: level = JNLIB_LOG_WARN; break;
case GCRY_LOG_ERROR:level = JNLIB_LOG_ERROR; break;
case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break;
case GCRY_LOG_BUG: level = JNLIB_LOG_BUG; break;
case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break;
default: level = JNLIB_LOG_ERROR; break; }
log_logv (level, fmt, arg_ptr);
}
/* static void */
/* print_mpi (const char *text, GcryMPI a) */
/* { */
/* char *buf; */
/* void *bufaddr = &buf; */
/* int rc; */
/* rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a); */
/* if (rc) */
/* log_info ("%s: [error printing number: %s]\n", text, gcry_strerror (rc)); */
/* else */
/* { */
/* log_info ("%s: %s\n", text, buf); */
/* gcry_free (buf); */
/* } */
/* } */
static unsigned char *
make_canonical (const char *fname, const char *buf, size_t buflen)
{
int rc;
size_t erroff, len;
GCRY_SEXP sexp;
unsigned char *result;
rc = gcry_sexp_sscan (&sexp, &erroff, buf, buflen);
if (rc)
{
log_error ("invalid S-Expression in `%s' (off=%u): %s\n",
fname, (unsigned int)erroff, gcry_strerror (rc));
return NULL;
}
len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0);
assert (len);
result = xmalloc (len);
len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, result, len);
assert (len);
gcry_sexp_release (sexp);
return result;
}
static char *
make_advanced (const unsigned char *buf, size_t buflen)
{
int rc;
size_t erroff, len;
GCRY_SEXP sexp;
unsigned char *result;
rc = gcry_sexp_sscan (&sexp, &erroff, buf, buflen);
if (rc)
{
log_error ("invalid canonical S-Expression (off=%u): %s\n",
(unsigned int)erroff, gcry_strerror (rc));
return NULL;
}
len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
assert (len);
result = xmalloc (len);
len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, result, len);
assert (len);
gcry_sexp_release (sexp);
return result;
}
static char *
read_file (const char *fname, size_t *r_length)
{
FILE *fp;
struct stat st;
char *buf;
size_t buflen;
fp = fopen (fname, "rb");
if (!fp)
{
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));
fclose (fp);
return NULL;
}
buflen = st.st_size;
buf = xmalloc (buflen+1);
if (fread (buf, buflen, 1, fp) != 1)
{
log_error ("error reading `%s': %s\n", fname, strerror (errno));
fclose (fp);
xfree (buf);
return NULL;
}
fclose (fp);
*r_length = buflen;
return buf;
}
static unsigned char *
read_key (const char *fname)
{
char *buf;
size_t buflen;
unsigned char *key;
buf = read_file (fname, &buflen);
key = make_canonical (fname, buf, buflen);
xfree (buf);
return key;
}
static void
read_and_protect (const char *fname)
{
int rc;
unsigned char *key;
unsigned char *result;
size_t resultlen;
key = read_key (fname);
if (!key)
return;
rc = agent_protect (key, get_passphrase (), &result, &resultlen);
xfree (key);
if (rc)
{
log_error ("protecting the key failed: %s\n", gnupg_strerror (rc));
return;
}
if (opt_armor)
{
char *p = make_advanced (result, resultlen);
xfree (result);
if (!p)
return;
result = p;
resultlen = strlen (p);
}
fwrite (result, resultlen, 1, stdout);
xfree (result);
}
static void
read_and_unprotect (const char *fname)
{
int rc;
unsigned char *key;
unsigned char *result;
size_t resultlen;
key = read_key (fname);
if (!key)
return;
rc = agent_unprotect (key, get_passphrase (), &result, &resultlen);
xfree (key);
if (rc)
{
log_error ("unprotecting the key failed: %s\n", gnupg_strerror (rc));
return;
}
if (opt_armor)
{
char *p = make_advanced (result, resultlen);
xfree (result);
if (!p)
return;
result = p;
resultlen = strlen (p);
}
fwrite (result, resultlen, 1, stdout);
xfree (result);
}
static void
read_and_shadow (const char *fname)
{
int rc;
unsigned char *key;
unsigned char *result;
size_t resultlen;
key = read_key (fname);
if (!key)
return;
rc = agent_shadow_key (key, "(8:313233342:43)", &result);
xfree (key);
if (rc)
{
log_error ("shadowing the key failed: %s\n", gnupg_strerror (rc));
return;
}
resultlen = gcry_sexp_canon_len (result, 0, NULL,NULL);
assert (resultlen);
if (opt_armor)
{
char *p = make_advanced (result, resultlen);
xfree (result);
if (!p)
return;
result = p;
resultlen = strlen (p);
}
fwrite (result, resultlen, 1, stdout);
xfree (result);
}
static void
show_shadow_info (const char *fname)
{
int rc;
unsigned char *key;
const unsigned char *info;
size_t infolen;
key = read_key (fname);
if (!key)
return;
rc = agent_get_shadow_info (key, &info);
xfree (key);
if (rc)
{
log_error ("get_shadow_info failed: %s\n", gnupg_strerror (rc));
return;
}
infolen = gcry_sexp_canon_len (info, 0, NULL,NULL);
assert (infolen);
if (opt_armor)
{
char *p = make_advanced (info, infolen);
if (!p)
return;
fwrite (p, strlen (p), 1, stdout);
xfree (p);
}
else
fwrite (info, infolen, 1, stdout);
}
static void
show_file (const char *fname)
{
unsigned char *key;
size_t keylen;
char *p;
key = read_key (fname);
if (!key)
return;
keylen = gcry_sexp_canon_len (key, 0, NULL,NULL);
assert (keylen);
p = make_advanced (key, keylen);
xfree (key);
if (p)
{
fwrite (p, strlen (p), 1, stdout);
xfree (p);
}
}
static void
show_keygrip (const char *fname)
{
unsigned char *key;
GcrySexp private;
unsigned char grip[20];
int i;
key = read_key (fname);
if (!key)
return;
if (gcry_sexp_new (&private, key, 0, 0))
{
log_error ("gcry_sexp_new failed\n");
return;
}
xfree (key);
if (!gcry_pk_get_keygrip (private, grip))
{
log_error ("can't calculate keygrip\n");
return;
}
gcry_sexp_release (private);
for (i=0; i < 20; i++)
printf ("%02X", grip[i]);
putchar ('\n');
}
static int
rsa_key_check (struct rsa_secret_key_s *skey)
{
int err = 0;
MPI t = gcry_mpi_snew (0);
MPI t1 = gcry_mpi_snew (0);
MPI t2 = gcry_mpi_snew (0);
MPI 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)
{
GcryMPI 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;
}
static void
import_p12_file (const char *fname)
{
char *buf;
unsigned char *result;
size_t buflen, resultlen;
int i;
int rc;
GcryMPI *kparms;
struct rsa_secret_key_s sk;
GcrySexp s_key;
unsigned char *key;
unsigned char grip[20];
/* fixme: we should release some stuff on error */
buf = read_file (fname, &buflen);
if (!buf)
return;
kparms = p12_parse (buf, buflen, get_passphrase ());
xfree (buf);
if (!kparms)
{
log_error ("error parsing or decrypting the PKCS-1 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",
gcry_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);
rc = agent_protect (key, get_passphrase (), &result, &resultlen);
xfree (key);
if (rc)
{
log_error ("protecting the key failed: %s\n", gnupg_strerror (rc));
return;
}
if (opt_armor)
{
char *p = make_advanced (result, resultlen);
xfree (result);
if (!p)
return;
result = p;
resultlen = strlen (p);
}
if (opt_store)
store_private_key (grip, result, resultlen, opt_force);
else
fwrite (result, resultlen, 1, stdout);
xfree (result);
}
static GcryMPI *
sexp_to_kparms (GCRY_SEXP sexp)
{
GcrySexp list, l2;
const char *name;
const char *s;
size_t n;
int i, idx;
const char *elems;
GcryMPI *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;
}
/* Paramter 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<idx; i++)
gcry_mpi_release (array[i]);
xfree (array);
gcry_sexp_release (list);
return NULL; /* required parameter not found */
}
array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
gcry_sexp_release (l2);
if (!array[idx])
{
for (i=0; i<idx; i++)
gcry_mpi_release (array[i]);
xfree (array);
gcry_sexp_release (list);
return NULL; /* required parameter is invalid */
}
}
gcry_sexp_release (list);
return array;
}
static void
export_p12_file (const char *fname)
{
GcryMPI kparms[9], *kp;
unsigned char *key;
size_t keylen;
GcrySexp private;
struct rsa_secret_key_s sk;
int i;
key = read_key (fname);
if (!key)
return;
if (gcry_sexp_new (&private, key, 0, 0))
{
log_error ("gcry_sexp_new failed\n");
return;
}
xfree (key);
kp = sexp_to_kparms (private);
gcry_sexp_release (private);
if (!kp)
{
log_error ("error converting key parameters\n");
return;
}
sk.n = kp[0];
sk.e = kp[1];
sk.d = kp[2];
sk.p = kp[3];
sk.q = kp[4];
sk.u = kp[5];
xfree (kp);
kparms[0] = sk.n;
kparms[1] = sk.e;
kparms[2] = sk.d;
kparms[3] = sk.q;
kparms[4] = sk.p;
kparms[5] = gcry_mpi_snew (0); /* compute d mod (p-1) */
gcry_mpi_sub_ui (kparms[5], kparms[3], 1);
gcry_mpi_mod (kparms[5], sk.d, kparms[5]);
kparms[6] = gcry_mpi_snew (0); /* compute d mod (q-1) */
gcry_mpi_sub_ui (kparms[6], kparms[4], 1);
gcry_mpi_mod (kparms[6], sk.d, kparms[6]);
kparms[7] = sk.u;
kparms[8] = NULL;
key = p12_build (kparms, get_passphrase (), &keylen);
for (i=0; i < 8; i++)
gcry_mpi_release (kparms[i]);
if (!key)
return;
fwrite (key, keylen, 1, stdout);
xfree (key);
}
int
main (int argc, char **argv )
{
ARGPARSE_ARGS pargs;
int cmd = 0;
set_strusage (my_strusage);
gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
log_set_prefix ("gpg-protect-tool", 1);
i18n_init ();
if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
{
log_fatal( _("libgcrypt is too old (need %s, have %s)\n"),
NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
}
gcry_set_log_handler (my_gcry_logger, NULL);
gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= 1; /* do not remove the args */
while (arg_parse (&pargs, opts) )
{
switch (pargs.r_opt)
{
case oVerbose: opt.verbose++; break;
case oArmor: opt_armor=1; break;
case oProtect: cmd = oProtect; break;
case oUnprotect: cmd = oUnprotect; break;
case oShadow: cmd = oShadow; break;
case oShowShadowInfo: cmd = oShowShadowInfo; break;
case oShowKeygrip: cmd = oShowKeygrip; break;
case oP12Import: cmd = oP12Import; break;
case oP12Export: cmd = oP12Export; break;
case oPassphrase: passphrase = pargs.r.ret_str; break;
case oStore: opt_store = 1; break;
case oForce: opt_force = 1; break;
default : pargs.err = 2; break;
}
}
if (log_get_errorcount(0))
exit(2);
if (argc != 1)
usage (1);
if (cmd == oProtect)
read_and_protect (*argv);
else if (cmd == oUnprotect)
read_and_unprotect (*argv);
else if (cmd == oShadow)
read_and_shadow (*argv);
else if (cmd == oShowShadowInfo)
show_shadow_info (*argv);
else if (cmd == oShowKeygrip)
show_keygrip (*argv);
else if (cmd == oP12Import)
import_p12_file (*argv);
else if (cmd == oP12Export)
export_p12_file (*argv);
else
show_file (*argv);
agent_exit (0);
return 8; /*NOTREACHED*/
}
void
agent_exit (int rc)
{
rc = rc? rc : log_get_errorcount(0)? 2 : 0;
exit (rc);
}
/* Return the passphrase string and ask the agent if it has not been
set from the command line. */
static const char *
get_passphrase (void)
{
char *pw;
int err;
if (passphrase)
return passphrase;
pw = simple_pwquery (NULL,NULL,
_("Enter passphrase:"),
_("Please enter the passphrase or the PIN\n"
"needed to complete this operation."),
&err);
if (!pw)
{
if (err)
log_error ("error while asking for the passphrase\n");
else
log_info ("cancelled\n");
agent_exit (0);
}
passphrase = pw;
return passphrase;
}
static int
store_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force)
{
int i;
const char *homedir;
char *fname;
FILE *fp;
char hexgrip[40+4+1];
for (i=0; i < 20; i++)
sprintf (hexgrip+2*i, "%02X", grip[i]);
strcpy (hexgrip+40, ".key");
homedir = getenv("GNUPGHOME");
if (!homedir || !*homedir)
homedir = GNUPG_DEFAULT_HOMEDIR;
fname = make_filename (homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
if (force)
fp = fopen (fname, "wb");
else
{
if (!access (fname, F_OK))
{
log_error ("secret key file `%s' already exists\n", fname);
xfree (fname);
return -1;
}
fp = fopen (fname, "wbx"); /* FIXME: the x is a GNU extension - let
configure check whether this actually
works */
}
if (!fp)
{
log_error ("can't create `%s': %s\n", fname, strerror (errno));
xfree (fname);
return -1;
}
if (fwrite (buffer, length, 1, fp) != 1)
{
log_error ("error writing `%s': %s\n", fname, strerror (errno));
fclose (fp);
remove (fname);
xfree (fname);
return -1;
}
if ( fclose (fp) )
{
log_error ("error closing `%s': %s\n", fname, strerror (errno));
remove (fname);
xfree (fname);
return -1;
}
log_info ("secret key stored as `%s'\n", fname);
xfree (fname);
return 0;
}

View File

@ -1,967 +0,0 @@
/* protect.c - Un/Protect a secret key
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#include "agent.h"
#include "sexp-parse.h"
#define PROT_CIPHER GCRY_CIPHER_AES
#define PROT_CIPHER_STRING "aes"
#define PROT_CIPHER_KEYLEN (128/8)
/* A table containing the information needed to create a protected
private key */
static struct {
const char *algo;
const char *parmlist;
int prot_from, prot_to;
} protect_info[] = {
{ "rsa", "nedpqu", 2, 5 },
{ NULL }
};
static int
hash_passphrase (const char *passphrase, int hashalgo,
int s2kmode,
const unsigned char *s2ksalt, unsigned long s2kcount,
unsigned char *key, size_t keylen);
/* Calculate the MIC for a private key S-Exp. SHA1HASH should pint 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;
s = plainkey;
if (*s != '(')
return GNUPG_Invalid_Sexp;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
if (!smatch (&s, n, "private-key"))
return GNUPG_Unknown_Sexp;
if (*s != '(')
return GNUPG_Unknown_Sexp;
hash_begin = s;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
s += n; /* skip over the algorithm name */
while (*s == '(')
{
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
s += n;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
s += n;
if ( *s != ')' )
return GNUPG_Invalid_Sexp;
s++;
}
if (*s != ')')
return GNUPG_Invalid_Sexp;
s++;
hash_end = s;
gcry_md_hash_buffer (GCRY_MD_SHA1, sha1hash,
hash_begin, hash_end - hash_begin);
return 0;
}
/* Encrypt the parameter block starting at PROTBEGIN with length
PROTLEN using the utf8 encoded key PASSPHRASE and return the entire
encrypted block in RESULT or ereturn with an error code. SHA1HASH
is the 20 byte SHA-1 hash required for the integrity code.
The parameter block is expected to be an incomplete S-Expression of
the form (example in advanced format):
(d #046129F..[some bytes not shown]..81#)
(p #00e861b..[some bytes not shown]..f1#)
(q #00f7a7c..[some bytes not shown]..61#)
(u #304559a..[some bytes not shown]..9b#)
the returned block is the S-Expression:
(protected mode (parms) encrypted_octet_string)
*/
static int
do_encryption (const char *protbegin, size_t protlen,
const char *passphrase, const unsigned char *sha1hash,
unsigned char **result, size_t *resultlen)
{
GCRY_CIPHER_HD hd;
const char *modestr = "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc";
int blklen, enclen, outlen;
char *iv = NULL;
int rc = 0;
char *outbuf = NULL;
char *p;
int saltpos, ivpos, encpos;
hd = gcry_cipher_open (PROT_CIPHER, GCRY_CIPHER_MODE_CBC,
GCRY_CIPHER_SECURE);
if (!hd)
return map_gcry_err (gcry_errno());
/* We need to work on a copy of the data because this makes it
easier to add the trailer and the padding and more important we
have to prefix the text with 2 parenthesis, so we have to
allocate enough space for:
((<parameter_list>)(4:hash4:sha120:<hashvalue>)) + padding
We always append a full block of random bytes as padding but
encrypt only what is needed for a full blocksize */
blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER);
outlen = 2 + protlen + 2 + 6 + 6 + 23 + 2 + blklen;
enclen = outlen/blklen * blklen;
outbuf = gcry_malloc_secure (outlen);
if (!outbuf)
rc = GNUPG_Out_Of_Core;
if (!rc)
{
/* allocate random bytes to be used as IV, padding and s2k salt*/
iv = gcry_random_bytes (blklen*2+8, GCRY_WEAK_RANDOM);
if (!iv)
rc = GNUPG_Out_Of_Core;
else
rc = gcry_cipher_setiv (hd, iv, blklen);
}
if (!rc)
{
unsigned char *key;
size_t keylen = PROT_CIPHER_KEYLEN;
key = gcry_malloc_secure (keylen);
if (!key)
rc = GNUPG_Out_Of_Core;
else
{
rc = hash_passphrase (passphrase, GCRY_MD_SHA1,
3, iv+2*blklen, 96, key, keylen);
if (!rc)
rc = gcry_cipher_setkey (hd, key, keylen);
xfree (key);
}
}
if (!rc)
{
p = outbuf;
*p++ = '(';
*p++ = '(';
memcpy (p, protbegin, protlen);
p += protlen;
memcpy (p, ")(4:hash4:sha120:", 17);
p += 17;
memcpy (p, sha1hash, 20);
p += 20;
*p++ = ')';
*p++ = ')';
memcpy (p, iv+blklen, blklen);
p += blklen;
assert ( p - outbuf == outlen);
rc = gcry_cipher_encrypt (hd, outbuf, enclen, NULL, 0);
}
gcry_cipher_close (hd);
if (rc)
{
xfree (iv);
xfree (outbuf);
return rc;
}
/* Now allocate the buffer we want to return. This is
(protected openpgp-s2k3-sha1-aes-cbc
((sha1 salt no_of_iterations) 16byte_iv)
encrypted_octet_string)
in canoncical format of course. We use asprintf and %n modifier
and spaces as palceholders. */
asprintf (&p,
"(9:protected%d:%s((4:sha18:%n_8bytes_2:96)%d:%n%*s)%d:%n%*s)",
(int)strlen (modestr), modestr,
&saltpos,
blklen, &ivpos, blklen, "",
enclen, &encpos, enclen, "");
if (p)
{ /* asprintf does not use out malloc system */
char *psave = p;
p = xtrymalloc (strlen (psave)+1);
if (p)
strcpy (p, psave);
free (psave);
}
if (!p)
{
xfree (iv);
xfree (outbuf);
return GNUPG_Out_Of_Core;
}
*resultlen = strlen (p);
*result = p;
memcpy (p+saltpos, iv+2*blklen, 8);
memcpy (p+ivpos, iv, blklen);
memcpy (p+encpos, outbuf, enclen);
xfree (iv);
xfree (outbuf);
return 0;
}
/* Protect the key encoded in canonical format in plainkey. We assume
a valid S-Exp here. */
int
agent_protect (const unsigned char *plainkey, const char *passphrase,
unsigned char **result, size_t *resultlen)
{
int rc;
const unsigned char *s;
const unsigned char *hash_begin, *hash_end;
const unsigned char *prot_begin, *prot_end, *real_end;
size_t n;
int c, infidx, i;
unsigned char hashvalue[20];
unsigned char *protected;
size_t protectedlen;
int depth = 0;
unsigned char *p;
s = plainkey;
if (*s != '(')
return GNUPG_Invalid_Sexp;
depth++;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
if (!smatch (&s, n, "private-key"))
return GNUPG_Unknown_Sexp;
if (*s != '(')
return GNUPG_Unknown_Sexp;
depth++;
hash_begin = s;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
for (infidx=0; protect_info[infidx].algo
&& !smatch (&s, n, protect_info[infidx].algo); infidx++)
;
if (!protect_info[infidx].algo)
return GNUPG_Unsupported_Algorithm;
prot_begin = prot_end = NULL;
for (i=0; (c=protect_info[infidx].parmlist[i]); i++)
{
if (i == protect_info[infidx].prot_from)
prot_begin = s;
if (*s != '(')
return GNUPG_Invalid_Sexp;
depth++;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
if (n != 1 || c != *s)
return GNUPG_Invalid_Sexp;
s += n;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
s +=n; /* skip value */
if (*s != ')')
return GNUPG_Invalid_Sexp;
depth--;
if (i == protect_info[infidx].prot_to)
prot_end = s;
s++;
}
if (*s != ')' || !prot_begin || !prot_end )
return GNUPG_Invalid_Sexp;
depth--;
hash_end = s;
s++;
/* skip to the end of the S-exp */
assert (depth == 1);
rc = sskip (&s, &depth);
if (rc)
return rc;
assert (!depth);
real_end = s-1;
gcry_md_hash_buffer (GCRY_MD_SHA1, hashvalue,
hash_begin, hash_end - hash_begin + 1);
rc = do_encryption (prot_begin, prot_end - prot_begin + 1,
passphrase, hashvalue,
&protected, &protectedlen);
if (rc)
return rc;
/* Now create the protected version of the key. Note that the 10
extra bytes are for for the inserted "protected-" string (the
beginning of the plaintext reads: "((11:private-key(" ). */
*resultlen = (10
+ (prot_begin-plainkey)
+ protectedlen
+ (real_end-prot_end));
*result = p = xtrymalloc (*resultlen);
if (!p)
{
xfree (protected);
return GNUPG_Out_Of_Core;
}
memcpy (p, "(21:protected-", 14);
p += 14;
memcpy (p, plainkey+4, prot_begin - plainkey - 4);
p += prot_begin - plainkey - 4;
memcpy (p, protected, protectedlen);
p += protectedlen;
memcpy (p, prot_end+1, real_end - prot_end);
p += real_end - prot_end;
assert ( p - *result == *resultlen);
xfree (protected);
return 0;
}
/* Do the actual decryption and check the return list for consistency. */
static int
do_decryption (const unsigned char *protected, size_t protectedlen,
const char *passphrase,
const unsigned char *s2ksalt, unsigned long s2kcount,
const unsigned char *iv, size_t ivlen,
unsigned char **result)
{
int rc = 0;
int blklen;
GCRY_CIPHER_HD hd;
unsigned char *outbuf;
size_t reallen;
blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER);
if (protectedlen < 4 || (protectedlen%blklen))
return GNUPG_Corrupted_Protection;
hd = gcry_cipher_open (PROT_CIPHER, GCRY_CIPHER_MODE_CBC,
GCRY_CIPHER_SECURE);
if (!hd)
return map_gcry_err (gcry_errno());
outbuf = gcry_malloc_secure (protectedlen);
if (!outbuf)
rc = GNUPG_Out_Of_Core;
if (!rc)
rc = gcry_cipher_setiv (hd, iv, ivlen);
if (!rc)
{
unsigned char *key;
size_t keylen = PROT_CIPHER_KEYLEN;
key = gcry_malloc_secure (keylen);
if (!key)
rc = GNUPG_Out_Of_Core;
else
{
rc = hash_passphrase (passphrase, GCRY_MD_SHA1,
3, s2ksalt, s2kcount, key, keylen);
if (!rc)
rc = gcry_cipher_setkey (hd, key, keylen);
xfree (key);
}
}
if (!rc)
rc = gcry_cipher_decrypt (hd, outbuf, protectedlen,
protected, protectedlen);
gcry_cipher_close (hd);
if (rc)
{
xfree (outbuf);
return rc;
}
/* do a quick check first */
if (*outbuf != '(' && outbuf[1] != '(')
{
xfree (outbuf);
return GNUPG_Bad_Passphrase;
}
/* check that we have a consistent S-Exp */
reallen = gcry_sexp_canon_len (outbuf, protectedlen, NULL, NULL);
if (!reallen || (reallen + blklen < protectedlen) )
{
xfree (outbuf);
return GNUPG_Bad_Passphrase;
}
*result = outbuf;
return 0;
}
/* Merge the parameter list contained in CLEARTEXT with the original
protect lists PROTECTEDKEY by replacing the list at REPLACEPOS.
Return the new list in RESULT and the MIC value in the 20 byte
buffer SHA1HASH. */
static int
merge_lists (const unsigned char *protectedkey,
size_t replacepos,
const unsigned char *cleartext,
unsigned char *sha1hash, unsigned char **result)
{
size_t n, newlistlen;
unsigned char *newlist, *p;
const unsigned char *s;
const unsigned char *startpos, *endpos;
int i, rc;
if (replacepos < 26)
return GNUPG_Bug;
/* Estimate the required size of the resulting list. We have a large
safety margin of >20 bytes (MIC hash from CLEARTEXT and the
removed "protected-" */
newlistlen = gcry_sexp_canon_len (protectedkey, 0, NULL, NULL);
if (!newlistlen)
return GNUPG_Bug;
n = gcry_sexp_canon_len (cleartext, 0, NULL, NULL);
if (!n)
return GNUPG_Bug;
newlistlen += n;
newlist = gcry_malloc_secure (newlistlen);
if (!newlist)
return GNUPG_Out_Of_Core;
/* Copy the initial segment */
strcpy (newlist, "(11:private-key");
p = newlist + 15;
memcpy (p, protectedkey+15+10, replacepos-15-10);
p += replacepos-15-10;
/* copy the cleartext */
s = cleartext;
if (*s != '(' && s[1] != '(')
return GNUPG_Bug; /*we already checked this */
s += 2;
startpos = s;
while ( *s == '(' )
{
s++;
n = snext (&s);
if (!n)
goto invalid_sexp;
s += n;
n = snext (&s);
if (!n)
goto invalid_sexp;
s += n;
if ( *s != ')' )
goto invalid_sexp;
s++;
}
if ( *s != ')' )
goto invalid_sexp;
endpos = s;
s++;
/* short intermezzo: Get the MIC */
if (*s != '(')
goto invalid_sexp;
s++;
n = snext (&s);
if (!smatch (&s, n, "hash"))
goto invalid_sexp;
n = snext (&s);
if (!smatch (&s, n, "sha1"))
goto invalid_sexp;
n = snext (&s);
if (n != 20)
goto invalid_sexp;
memcpy (sha1hash, s, 20);
s += n;
if (*s != ')')
goto invalid_sexp;
/* end intermezzo */
/* append the parameter list */
memcpy (p, startpos, endpos - startpos);
p += endpos - startpos;
/* skip overt the protected list element in the original list */
s = protectedkey + replacepos;
assert (*s == '(');
s++;
i = 1;
rc = sskip (&s, &i);
if (rc)
goto failure;
startpos = s;
i = 2; /* we are inside this level */
rc = sskip (&s, &i);
if (rc)
goto failure;
assert (s[-1] == ')');
endpos = s; /* one behind the end of the list */
/* append the rest */
memcpy (p, startpos, endpos - startpos);
p += endpos - startpos;
/* ready */
*result = newlist;
return 0;
failure:
xfree (newlist);
return rc;
invalid_sexp:
xfree (newlist);
return GNUPG_Invalid_Sexp;
}
/* Unprotect the key encoded in canonical format. We assume a valid
S-Exp here. */
int
agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
unsigned char **result, size_t *resultlen)
{
int rc;
const unsigned char *s;
size_t n;
int infidx, i;
unsigned char sha1hash[20], sha1hash2[20];
const unsigned char *s2ksalt;
unsigned long s2kcount;
const unsigned char *iv;
const unsigned char *prot_begin;
unsigned char *cleartext;
unsigned char *final;
s = protectedkey;
if (*s != '(')
return GNUPG_Invalid_Sexp;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
if (!smatch (&s, n, "protected-private-key"))
return GNUPG_Unknown_Sexp;
if (*s != '(')
return GNUPG_Unknown_Sexp;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
for (infidx=0; protect_info[infidx].algo
&& !smatch (&s, n, protect_info[infidx].algo); infidx++)
;
if (!protect_info[infidx].algo)
return GNUPG_Unsupported_Algorithm;
/* now find the list with the protected information. Here is an
example for such a list:
(protected openpgp-s2k3-sha1-aes-cbc
((sha1 <salt> <count>) <Initialization_Vector>)
<encrypted_data>)
*/
for (;;)
{
if (*s != '(')
return GNUPG_Invalid_Sexp;
prot_begin = s;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
if (smatch (&s, n, "protected"))
break;
s += n;
i = 1;
rc = sskip (&s, &i);
if (rc)
return rc;
}
/* found */
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
if (!smatch (&s, n, "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc"))
return GNUPG_Unsupported_Protection;
if (*s != '(' || s[1] != '(')
return GNUPG_Invalid_Sexp;
s += 2;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
if (!smatch (&s, n, "sha1"))
return GNUPG_Unsupported_Protection;
n = snext (&s);
if (n != 8)
return GNUPG_Corrupted_Protection;
s2ksalt = s;
s += n;
n = snext (&s);
if (!n)
return GNUPG_Corrupted_Protection;
/* We expect a list close as next, so we can simply use strtoul()
here. We might want to check that we only have digits - but this
is nothing we should worry about */
if (s[n] != ')' )
return GNUPG_Invalid_Sexp;
s2kcount = strtoul (s, NULL, 10);
if (!s2kcount)
return GNUPG_Corrupted_Protection;
s += n;
s++; /* skip list end */
n = snext (&s);
if (n != 16) /* Wrong blocksize for IV (we support ony aes-128) */
return GNUPG_Corrupted_Protection;
iv = s;
s += n;
if (*s != ')' )
return GNUPG_Invalid_Sexp;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
rc = do_decryption (s, n,
passphrase, s2ksalt, s2kcount,
iv, 16,
&cleartext);
if (rc)
return rc;
rc = merge_lists (protectedkey, prot_begin-protectedkey, cleartext,
sha1hash, &final);
xfree (cleartext);
if (rc)
return rc;
rc = calculate_mic (final, sha1hash2);
if (!rc && memcmp (sha1hash, sha1hash2, 20))
rc = GNUPG_Corrupted_Protection;
if (rc)
{
xfree (final);
return rc;
}
*result = final;
*resultlen = gcry_sexp_canon_len (final, 0, NULL, NULL);
return 0;
}
/* Check the type of the private key, this is one of the constants:
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. */
int
agent_private_key_type (const unsigned char *privatekey)
{
const unsigned char *s;
size_t n;
s = privatekey;
if (*s != '(')
return PRIVATE_KEY_UNKNOWN;
s++;
n = snext (&s);
if (!n)
return PRIVATE_KEY_UNKNOWN;
if (smatch (&s, n, "protected-private-key"))
return PRIVATE_KEY_PROTECTED;
if (smatch (&s, n, "shadowed-private-key"))
return PRIVATE_KEY_SHADOWED;
if (smatch (&s, n, "private-key"))
return PRIVATE_KEY_CLEAR;
return PRIVATE_KEY_UNKNOWN;
}
/* Transform a passphrase into a suitable key of length KEYLEN and
store this key in the caller provided buffer KEY. The caller must
provide an HASHALGO, a valid S2KMODE (see rfc-2440) and depending on
that mode an S2KSALT of 8 random bytes and an S2KCOUNT (a suitable
value is 96).
Returns an error code on failure. */
static int
hash_passphrase (const char *passphrase, int hashalgo,
int s2kmode,
const unsigned char *s2ksalt,
unsigned long s2kcount,
unsigned char *key, size_t keylen)
{
GCRY_MD_HD md;
int pass, i;
int used = 0;
int pwlen = strlen (passphrase);
if ( (s2kmode != 0 && s2kmode != 1 && s2kmode != 3)
|| !hashalgo || !keylen || !key || !passphrase)
return GNUPG_Invalid_Value;
if ((s2kmode == 1 ||s2kmode == 3) && !s2ksalt)
return GNUPG_Invalid_Value;
md = gcry_md_open (hashalgo, GCRY_MD_FLAG_SECURE);
if (!md)
return map_gcry_err (gcry_errno());
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 = (16ul + (s2kcount & 15)) << ((s2kcount >> 4) + 6);
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;
}
/* Create a shadow key from a public key. We use the shadow protocol
"ti-v1" and insert the S-expressionn SHADOW_INFO. The resulting
S-expression is returned in an allocated buffer RESULT will point
to. The input parameters are expected to be valid canonilized
S-expressions */
int
agent_shadow_key (const unsigned char *pubkey,
const unsigned char *shadow_info,
unsigned char **result)
{
const unsigned char *s;
const unsigned char *point;
size_t n;
int depth = 0;
unsigned char *p;
size_t pubkey_len = gcry_sexp_canon_len (pubkey, 0, NULL,NULL);
size_t shadow_info_len = gcry_sexp_canon_len (shadow_info, 0, NULL,NULL);
if (!pubkey_len || !shadow_info_len)
return GNUPG_Invalid_Value;
s = pubkey;
if (*s != '(')
return GNUPG_Invalid_Sexp;
depth++;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
if (!smatch (&s, n, "public-key"))
return GNUPG_Unknown_Sexp;
if (*s != '(')
return GNUPG_Unknown_Sexp;
depth++;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
s += n; /* skip over the algorithm name */
while (*s != ')')
{
if (*s != '(')
return GNUPG_Invalid_Sexp;
depth++;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
s += n;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
s +=n; /* skip value */
if (*s != ')')
return GNUPG_Invalid_Sexp;
depth--;
s++;
}
point = s; /* insert right before the point */
depth--;
s++;
assert (depth == 1);
/* calculate required length by taking in account: the "shadowed-"
prefix, the "shadowed", "t1-v1" as well as some parenthesis */
n = 12 + pubkey_len + 1 + 3+8 + 2+5 + shadow_info_len + 1;
*result = p = xtrymalloc (n);
if (!p)
return GNUPG_Out_Of_Core;
p = stpcpy (p, "(20:shadowed-private-key");
/* (10:public-key ...)*/
memcpy (p, pubkey+14, point - (pubkey+14));
p += point - (pubkey+14);
p = stpcpy (p, "(8:shadowed5:t1-v1");
memcpy (p, shadow_info, shadow_info_len);
p += shadow_info_len;
*p++ = ')';
memcpy (p, point, pubkey_len - (point - pubkey));
p += pubkey_len - (point - pubkey);
return 0;
}
/* Parse a canonical encoded shadowed key and return a pointer to the
inner list with the shadow_info */
int
agent_get_shadow_info (const unsigned char *shadowkey,
unsigned char const **shadow_info)
{
const unsigned char *s;
size_t n;
int depth = 0;
s = shadowkey;
if (*s != '(')
return GNUPG_Invalid_Sexp;
depth++;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
if (!smatch (&s, n, "shadowed-private-key"))
return GNUPG_Unknown_Sexp;
if (*s != '(')
return GNUPG_Unknown_Sexp;
depth++;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
s += n; /* skip over the algorithm name */
for (;;)
{
if (*s == ')')
return GNUPG_Unknown_Sexp;
if (*s != '(')
return GNUPG_Invalid_Sexp;
depth++;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
if (smatch (&s, n, "shadowed"))
break;
s += n;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
s +=n; /* skip value */
if (*s != ')')
return GNUPG_Invalid_Sexp;
depth--;
s++;
}
/* found the shadowed list, s points to the protocol */
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
if (smatch (&s, n, "t1-v1"))
{
if (*s != '(')
return GNUPG_Invalid_Sexp;
*shadow_info = s;
}
else
return GNUPG_Unsupported_Protocol;
return 0;
}

View File

@ -1,460 +0,0 @@
/* query.c - fork of the pinentry to query stuff from the user
* Copyright (C) 2001 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#ifdef USE_GNU_PTH
# include <pth.h>
#endif
#include "agent.h"
#include "i18n.h"
#include "../assuan/assuan.h"
#ifdef _POSIX_OPEN_MAX
#define MAX_OPEN_FDS _POSIX_OPEN_MAX
#else
#define MAX_OPEN_FDS 20
#endif
static ASSUAN_CONTEXT entry_ctx = NULL;
#ifdef USE_GNU_PTH
static pth_mutex_t entry_lock = PTH_MUTEX_INIT;
#endif
/* data to be passed to our callbacks */
struct entry_parm_s {
int lines;
size_t size;
char *buffer;
};
static int
unlock_pinentry (int rc)
{
#ifdef USE_GNU_PTH
if (!pth_mutex_release (&entry_lock))
{
log_error ("failed to release the entry lock\n");
if (!rc)
rc = GNUPG_Internal_Error;
}
#endif
return rc;
}
/* Fork off the pin entry if this has not already been done. Note,
that this function must always be used to aquire the lock for the
pinentry - we will serialize _all_ pinentry calls.
*/
static int
start_pinentry (void)
{
int rc;
const char *pgmname;
ASSUAN_CONTEXT ctx;
const char *argv[5];
int no_close_list[3];
int i;
#ifdef USE_GNU_PTH
if (!pth_mutex_acquire (&entry_lock, 0, NULL))
{
log_error ("failed to acquire the entry lock\n");
return GNUPG_Internal_Error;
}
#endif
if (entry_ctx)
return 0;
if (opt.verbose)
log_info ("no running PIN Entry - starting it\n");
if (fflush (NULL))
{
log_error ("error flushing pending output: %s\n", strerror (errno));
return unlock_pinentry (seterr (Write_Error));
}
if (!opt.pinentry_program || !*opt.pinentry_program)
opt.pinentry_program = GNUPG_DEFAULT_PINENTRY;
if ( !(pgmname = strrchr (opt.pinentry_program, '/')))
pgmname = opt.pinentry_program;
else
pgmname++;
/* FIXME: We must do this thread specific */
argv[0] = pgmname;
if (opt.display && !opt.keep_display)
{
argv[1] = "--display";
argv[2] = opt.display;
argv[3] = NULL;
}
else
argv[1] = NULL;
i=0;
if (!opt.running_detached)
{
if (log_get_fd () != -1)
no_close_list[i++] = log_get_fd ();
no_close_list[i++] = fileno (stderr);
}
no_close_list[i] = -1;
/* connect to the pinentry and perform initial handshaking */
rc = assuan_pipe_connect (&ctx, opt.pinentry_program, (char**)argv,
no_close_list);
if (rc)
{
log_error ("can't connect to the PIN entry module: %s\n",
assuan_strerror (rc));
return unlock_pinentry (seterr (No_PIN_Entry));
}
entry_ctx = ctx;
if (DBG_ASSUAN)
log_debug ("connection to PIN entry established\n");
rc = assuan_transact (entry_ctx,
opt.no_grab? "OPTION no-grab":"OPTION grab",
NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return unlock_pinentry (map_assuan_err (rc));
if (opt.ttyname && !opt.keep_tty)
{
char *optstr;
if (asprintf (&optstr, "OPTION ttyname=%s", opt.ttyname) < 0 )
return unlock_pinentry (GNUPG_Out_Of_Core);
rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
NULL);
free (optstr);
if (rc)
return unlock_pinentry (map_assuan_err (rc));
}
if (opt.ttytype && !opt.keep_tty)
{
char *optstr;
if (asprintf (&optstr, "OPTION ttytype=%s", opt.ttytype) < 0 )
return unlock_pinentry (GNUPG_Out_Of_Core);
rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
NULL);
if (rc)
return unlock_pinentry (map_assuan_err (rc));
}
if (opt.lc_ctype)
{
char *optstr;
if (asprintf (&optstr, "OPTION lc-ctype=%s", opt.lc_ctype) < 0 )
return unlock_pinentry (GNUPG_Out_Of_Core);
rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
NULL);
if (rc)
return unlock_pinentry (map_assuan_err (rc));
}
if (opt.lc_messages)
{
char *optstr;
if (asprintf (&optstr, "OPTION lc-messages=%s", opt.lc_messages) < 0 )
return unlock_pinentry (GNUPG_Out_Of_Core);
rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
NULL);
if (rc)
return unlock_pinentry (map_assuan_err (rc));
}
return 0;
}
static AssuanError
getpin_cb (void *opaque, const void *buffer, size_t length)
{
struct entry_parm_s *parm = opaque;
if (!buffer)
return 0;
/* we expect the pin to fit on one line */
if (parm->lines || length >= parm->size)
return ASSUAN_Too_Much_Data;
/* fixme: we should make sure that the assuan buffer is allocated in
secure memory or read the response byte by byte */
memcpy (parm->buffer, buffer, length);
parm->buffer[length] = 0;
parm->lines++;
return 0;
}
static int
all_digitsp( const char *s)
{
for (; *s && *s >= '0' && *s <= '9'; s++)
;
return !*s;
}
/* 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. */
int
agent_askpin (const char *desc_text, struct pin_entry_info_s *pininfo)
{
int rc;
char line[ASSUAN_LINELENGTH];
struct entry_parm_s parm;
const char *errtext = NULL;
int is_pin = 0;
if (opt.batch)
return 0; /* fixme: we should return BAD PIN */
if (!pininfo || pininfo->max_length < 1)
return seterr (Invalid_Value);
if (!desc_text && pininfo->min_digits)
desc_text = _("Please enter your PIN, so that the secret key "
"can be unlocked for this session");
else if (!desc_text)
desc_text = _("Please enter your passphrase, so that the secret key "
"can be unlocked for this session");
is_pin = desc_text && strstr (desc_text, "PIN");
rc = start_pinentry ();
if (rc)
return rc;
snprintf (line, DIM(line)-1, "SETDESC %s", desc_text);
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return unlock_pinentry (map_assuan_err (rc));
rc = assuan_transact (entry_ctx,
is_pin? "SETPROMPT PIN:"
: "SETPROMPT Passphrase:",
NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return unlock_pinentry (map_assuan_err (rc));
for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
{
memset (&parm, 0, sizeof parm);
parm.size = pininfo->max_length;
parm.buffer = pininfo->pin;
if (errtext)
{
/* fixme: should we show the try count? It must be translated */
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, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return unlock_pinentry (map_assuan_err (rc));
errtext = NULL;
}
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
NULL, NULL, NULL, NULL);
if (rc == ASSUAN_Too_Much_Data)
errtext = is_pin? _("PIN too long")
: _("Passphrase too long");
else if (rc)
return unlock_pinentry (map_assuan_err (rc));
if (!errtext && pininfo->min_digits)
{
/* do some basic checks on the entered PIN. */
if (!all_digitsp (pininfo->pin))
errtext = _("Invalid characters in PIN");
else if (pininfo->max_digits
&& strlen (pininfo->pin) > pininfo->max_digits)
errtext = _("PIN too long");
else if (strlen (pininfo->pin) < pininfo->min_digits)
errtext = _("PIN too short");
}
if (!errtext && pininfo->check_cb)
{
/* More checks by utilizing the optional callback. */
pininfo->cb_errtext = NULL;
rc = pininfo->check_cb (pininfo);
if (rc == -1 && pininfo->cb_errtext)
errtext = pininfo->cb_errtext;
else if (rc == GNUPG_Bad_Passphrase || rc == GNUPG_Bad_PIN)
errtext = (is_pin? _("Bad PIN")
: _("Bad Passphrase"));
else if (rc)
return unlock_pinentry (map_assuan_err (rc));
}
if (!errtext)
return unlock_pinentry (0); /* okay, got a PIN or passphrase */
}
return unlock_pinentry (pininfo->min_digits? GNUPG_Bad_PIN
: GNUPG_Bad_Passphrase);
}
/* Ask for the passphrase using the supplied arguments. The
passphrase is returned in RETPASS as an hex encoded string to be
freed by the caller */
int
agent_get_passphrase (char **retpass, const char *desc, const char *prompt,
const char *errtext)
{
int rc;
char line[ASSUAN_LINELENGTH];
struct entry_parm_s parm;
unsigned char *p, *hexstring;
int i;
*retpass = NULL;
if (opt.batch)
return GNUPG_Bad_Passphrase;
rc = start_pinentry ();
if (rc)
return rc;
if (!prompt)
prompt = desc && strstr (desc, "PIN")? "PIN": _("Passphrase");
if (desc)
snprintf (line, DIM(line)-1, "SETDESC %s", desc);
else
snprintf (line, DIM(line)-1, "RESET");
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return unlock_pinentry (map_assuan_err (rc));
snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt);
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return unlock_pinentry (map_assuan_err (rc));
if (errtext)
{
snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return unlock_pinentry (map_assuan_err (rc));
}
memset (&parm, 0, sizeof parm);
parm.size = ASSUAN_LINELENGTH/2 - 5;
parm.buffer = gcry_malloc_secure (parm.size+10);
if (!parm.buffer)
return unlock_pinentry (seterr (Out_Of_Core));
assuan_begin_confidential (entry_ctx);
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL, NULL, NULL);
if (rc)
{
xfree (parm.buffer);
return unlock_pinentry (map_assuan_err (rc));
}
hexstring = gcry_malloc_secure (strlen (parm.buffer)*2+1);
if (!hexstring)
{
xfree (parm.buffer);
return unlock_pinentry (seterr (Out_Of_Core));
}
for (i=0, p=parm.buffer; *p; p++, i += 2)
sprintf (hexstring+i, "%02X", *p);
xfree (parm.buffer);
*retpass = hexstring;
return unlock_pinentry (0);
}
/* Pop up the PIN-entry, display the text and the prompt and ask the
user to confirm this. We return 0 for success, ie. the used
confirmed it, GNUPG_Not_Confirmed for what the text says or an
other error. */
int
agent_get_confirmation (const char *desc, const char *ok, const char *cancel)
{
int rc;
char line[ASSUAN_LINELENGTH];
rc = start_pinentry ();
if (rc)
return rc;
if (desc)
snprintf (line, DIM(line)-1, "SETDESC %s", desc);
else
snprintf (line, DIM(line)-1, "RESET");
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return unlock_pinentry (map_assuan_err (rc));
if (ok)
{
snprintf (line, DIM(line)-1, "SETOK %s", ok);
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return unlock_pinentry (map_assuan_err (rc));
}
if (cancel)
{
snprintf (line, DIM(line)-1, "SETCANCEL %s", cancel);
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return unlock_pinentry (map_assuan_err (rc));
}
rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
return unlock_pinentry (map_assuan_err (rc));
}

View File

@ -1,98 +0,0 @@
/* sexp-parse.h - S-Exp helper functions
* Copyright (C) 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef SEXP_PARSE_H
#define SEXP_PARSE_H
#include "../common/util.h"
/* Return the length of the next S-Exp part and update the pointer to
the first data byte. 0 is return on error */
static inline size_t
snext (unsigned char const **buf)
{
const unsigned char *s;
int n;
s = *buf;
for (n=0; *s && *s != ':' && digitp (s); s++)
n = n*10 + atoi_1 (s);
if (!n || *s != ':')
return 0; /* we don't allow empty lengths */
*buf = s+1;
return n;
}
/* Skip over the S-Expression BUF points to and update BUF to point to
the chacter right behind. DEPTH gives the initial number of open
lists and may be passed as a positive number to skip over the
remainder of an S-Expression if the current position is somewhere
in an S-Expression. The function may return an error code if it
encounters an impossible conditions */
static inline int
sskip (unsigned char const **buf, int *depth)
{
const unsigned char *s = *buf;
size_t n;
int d = *depth;
while (d > 0)
{
if (*s == '(')
{
d++;
s++;
}
else if (*s == ')')
{
d--;
s++;
}
else
{
if (!d)
return GNUPG_Invalid_Sexp;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
s += n;
}
}
*buf = s;
*depth = d;
return 0;
}
/* Check whether the the string at the address BUF points to matches
the token. Return true on match and update BUF to point behind the
token. */
static inline int
smatch (unsigned char const **buf, size_t buflen, const char *token)
{
size_t toklen = strlen (token);
if (buflen != toklen || memcmp (*buf, token, toklen))
return 0;
*buf += toklen;
return 1;
}
#endif /*SEXP_PARSE_H*/

View File

@ -1,485 +0,0 @@
/* simple-pwquery.c - A simple password query cleint for gpg-agent
* Copyright (C) 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/* This module is intended as a standalone client implementation to
gpg-agent's GET_PASSPHRASE command. In particular it does not use
the Assuan library and can only cope with an already running
gpg-agent. Some stuff is configurable in the header file. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#define SIMPLE_PWQUERY_IMPLEMENTATION 1
#include "simple-pwquery.h"
#if defined(SPWQ_USE_LOGGING) && !defined(HAVE_JNLIB_LOGGING)
# undef SPWQ_USE_LOGGING
#endif
#ifndef _
#define _(a) (a)
#endif
#if !defined (hexdigitp) && !defined (xtoi_2)
#define digitp(p) (*(p) >= '0' && *(p) <= '9')
#define hexdigitp(a) (digitp (a) \
|| (*(a) >= 'A' && *(a) <= 'F') \
|| (*(a) >= 'a' && *(a) <= 'f'))
#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
*(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
#endif
/* Write NBYTES of BUF to file descriptor FD. */
static int
writen (int fd, const void *buf, size_t nbytes)
{
size_t nleft = nbytes;
int nwritten;
while (nleft > 0)
{
nwritten = write( fd, buf, nleft );
if (nwritten < 0)
{
if (errno == EINTR)
nwritten = 0;
else {
#ifdef SPWQ_USE_LOGGING
log_error ("write failed: %s\n", strerror (errno));
#endif
return SPWQ_IO_ERROR;
}
}
nleft -= nwritten;
buf = (const char*)buf + nwritten;
}
return 0;
}
/* Read an entire line and return number of bytes read. */
static int
readline (int fd, char *buf, size_t buflen)
{
size_t nleft = buflen;
char *p;
int nread = 0;
while (nleft > 0)
{
int n = read (fd, buf, nleft);
if (n < 0)
{
if (errno == EINTR)
continue;
return -(SPWQ_IO_ERROR);
}
else if (!n)
{
return -(SPWQ_PROTOCOL_ERROR); /* incomplete line */
}
p = buf;
nleft -= n;
buf += n;
nread += n;
for (; n && *p != '\n'; n--, p++)
;
if (n)
{
break; /* at least one full line available - that's enough.
This function is just a simple implementation, so
it is okay to forget about pending bytes */
}
}
return nread;
}
/* Send an option to the agent */
static int
agent_send_option (int fd, const char *name, const char *value)
{
char buf[200];
int nread;
char *line;
int i;
line = spwq_malloc (7 + strlen (name) + 1 + strlen (value) + 2);
if (!line)
return SPWQ_OUT_OF_CORE;
strcpy (stpcpy (stpcpy (stpcpy (
stpcpy (line, "OPTION "), name), "="), value), "\n");
i = writen (fd, line, strlen (line));
spwq_free (line);
if (i)
return i;
/* get response */
nread = readline (fd, buf, DIM(buf)-1);
if (nread < 0)
return -nread;
if (nread < 3)
return SPWQ_PROTOCOL_ERROR;
if (buf[0] == 'O' && buf[1] == 'K' && (buf[2] == ' ' || buf[2] == '\n'))
return 0; /* okay */
return SPWQ_ERR_RESPONSE;
}
/* Send all available options to the agent. */
static int
agent_send_all_options (int fd)
{
char *dft_display = NULL;
char *dft_ttyname = NULL;
char *dft_ttytype = NULL;
int rc = 0;
dft_display = getenv ("DISPLAY");
if (dft_display)
{
if ((rc = agent_send_option (fd, "display", dft_display)))
return rc;
}
if (ttyname (1))
dft_ttyname = ttyname (1);
if (dft_ttyname)
{
if ((rc=agent_send_option (fd, "ttyname", dft_ttyname)))
return rc;
}
dft_ttytype = getenv ("TERM");
if (dft_ttyname && dft_ttytype)
{
if ((rc = agent_send_option (fd, "ttytype", dft_ttytype)))
return rc;
}
#if defined(HAVE_SETLOCALE)
{
char *old_lc = NULL;
char *dft_lc = NULL;
#if defined(LC_CTYPE)
old_lc = setlocale (LC_CTYPE, NULL);
if (old_lc)
{
char *p = spwq_malloc (strlen (old_lc)+1);
if (!p)
return SPWQ_OUT_OF_CORE;
strcpy (p, old_lc);
old_lc = p;
}
dft_lc = setlocale (LC_CTYPE, "");
if (dft_ttyname && dft_lc)
rc = agent_send_option (fd, "lc-ctype", dft_lc);
if (old_lc)
{
setlocale (LC_CTYPE, old_lc);
spwq_free (old_lc);
}
if (rc)
return rc;
#endif
#if defined(LC_MESSAGES)
old_lc = setlocale (LC_MESSAGES, NULL);
if (old_lc)
{
char *p = spwq_malloc (strlen (old_lc)+1);
if (!p)
return SPWQ_OUT_OF_CORE;
strcpy (p, old_lc);
old_lc = p;
}
dft_lc = setlocale (LC_MESSAGES, "");
if (dft_ttyname && dft_lc)
rc = agent_send_option (fd, "lc-messages", dft_lc);
if (old_lc)
{
setlocale (LC_MESSAGES, old_lc);
spwq_free (old_lc);
}
if (rc)
return rc;
#endif
}
#endif /*HAVE_SETLOCALE*/
return 0;
}
/* Try to open a connection to the agent, send all options and return
the file descriptor for the connection. Return -1 in case of
error. */
static int
agent_open (int *rfd)
{
int rc;
int fd;
char *infostr, *p;
struct sockaddr_un client_addr;
size_t len;
int prot;
char line[200];
int nread;
*rfd = -1;
infostr = getenv ( "GPG_AGENT_INFO" );
if ( !infostr )
{
#ifdef SPWQ_USE_LOGGING
log_error (_("gpg-agent is not available in this session\n"));
#endif
return SPWQ_NO_AGENT;
}
if ( !(p = strchr ( infostr, ':')) || p == infostr
|| (p-infostr)+1 >= sizeof client_addr.sun_path )
{
#ifdef SPWQ_USE_LOGGING
log_error ( _("malformed GPG_AGENT_INFO environment variable\n"));
#endif
return SPWQ_NO_AGENT;
}
*p++ = 0;
while (*p && *p != ':')
p++;
prot = *p? atoi (p+1) : 0;
if ( prot != 1)
{
#ifdef SPWQ_USE_LOGGING
log_error (_("gpg-agent protocol version %d is not supported\n"),prot);
#endif
return SPWQ_PROTOCOL_ERROR;
}
if( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1 )
{
#ifdef SPWQ_USE_LOGGING
log_error ("can't create socket: %s\n", strerror(errno) );
#endif
return SPWQ_SYS_ERROR;
}
memset (&client_addr, 0, sizeof client_addr);
client_addr.sun_family = AF_UNIX;
strcpy (client_addr.sun_path, infostr);
len = (offsetof (struct sockaddr_un, sun_path)
+ strlen(client_addr.sun_path) + 1);
if (connect (fd, (struct sockaddr*)&client_addr, len ) == -1)
{
#ifdef SPWQ_USE_LOGGING
log_error ( _("can't connect to `%s': %s\n"), infostr, strerror (errno));
#endif
close (fd );
return SPWQ_IO_ERROR;
}
nread = readline (fd, line, DIM(line));
if (nread < 3 || !(line[0] == 'O' && line[1] == 'K'
&& (line[2] == '\n' || line[2] == ' ')) )
{
#ifdef SPWQ_USE_LOGGING
log_error ( _("communication problem with gpg-agent\n"));
#endif
close (fd );
return SPWQ_PROTOCOL_ERROR;
}
rc = agent_send_all_options (fd);
if (rc)
{
#ifdef SPWQ_USE_LOGGING
log_error (_("problem setting the gpg-agent options\n"));
#endif
close (fd);
return rc;
}
*rfd = fd;
return 0;
}
/* Copy text to BUFFER and escape as required. Return a poiinter to
the end of the new buffer. NOte that BUFFER must be large enough
to keep the entire text; allocataing it 3 times the size of TEXT
is sufficient. */
static char *
copy_and_escape (char *buffer, const char *text)
{
int i;
char *p = buffer;
for (i=0; text[i]; i++)
{
if (text[i] < ' ' || text[i] == '+')
{
sprintf (p, "%%%02X", text[i]);
p += 3;
}
else if (text[i] == ' ')
*p++ = '+';
else
*p++ = text[i];
}
return p;
}
/* Ask the gpg-agent for a passphrase and present the user with a
DESCRIPTION, a PROMPT and optiaonlly with a TRYAGAIN extra text.
If a CACHEID is not NULL it is used to locate the passphrase in in
the cache and store it under this ID. If ERRORCODE is not NULL it
should point a variable receiving an errorcode; thsi errocode might
be 0 if the user canceled the operation. The function returns NULL
to indicate an error. */
char *
simple_pwquery (const char *cacheid,
const char *tryagain,
const char *prompt,
const char *description,
int *errorcode)
{
int fd = -1;
int nread;
char *result = NULL;
char *pw = NULL;
char *p;
int rc, i;
rc = agent_open (&fd);
if (rc)
goto leave;
if (!cacheid)
cacheid = "X";
if (!tryagain)
tryagain = "X";
if (!prompt)
prompt = "X";
if (!description)
description = "X";
{
char *line;
/* We allocate 3 times the needed space so that there is enough
space for escaping. */
line = spwq_malloc (15
+ 3*strlen (cacheid) + 1
+ 3*strlen (tryagain) + 1
+ 3*strlen (prompt) + 1
+ 3*strlen (description) + 1
+ 2);
if (!line)
{
rc = SPWQ_OUT_OF_CORE;
goto leave;
}
strcpy (line, "GET_PASSPHRASE ");
p = line+15;
p = copy_and_escape (p, cacheid);
*p++ = ' ';
p = copy_and_escape (p, tryagain);
*p++ = ' ';
p = copy_and_escape (p, prompt);
*p++ = ' ';
p = copy_and_escape (p, description);
*p++ = '\n';
rc = writen (fd, line, p - line);
spwq_free (line);
if (rc)
goto leave;
}
/* get response */
pw = spwq_secure_malloc (500);
nread = readline (fd, pw, 499);
if (nread < 0)
{
rc = -nread;
goto leave;
}
if (nread < 3)
{
rc = SPWQ_PROTOCOL_ERROR;
goto leave;
}
if (pw[0] == 'O' && pw[1] == 'K' && pw[2] == ' ')
{ /* we got a passphrase - convert it back from hex */
size_t pwlen = 0;
for (i=3; i < nread && hexdigitp (pw+i); i+=2)
pw[pwlen++] = xtoi_2 (pw+i);
pw[pwlen] = 0; /* make a C String */
result = pw;
pw = NULL;
}
else if (nread > 7 && !memcmp (pw, "ERR 111", 7)
&& (pw[7] == ' ' || pw[7] == '\n') )
{
#ifdef SPWQ_USE_LOGGING
log_info (_("canceled by user\n") );
#endif
*errorcode = 0; /* canceled */
}
else
{
#ifdef SPWQ_USE_LOGGING
log_error (_("problem with the agent\n"));
#endif
rc = SPWQ_ERR_RESPONSE;
}
leave:
if (errorcode)
*errorcode = rc;
if (fd != -1)
close (fd);
if (pw)
spwq_free (pw);
return result;
}

View File

@ -1,304 +0,0 @@
/* trustlist.c - Maintain the list of trusted keys
* Copyright (C) 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#include "agent.h"
#include "../assuan/assuan.h" /* fixme: need a way to avoid assuan
calls here */
static const char headerblurb[] =
"# This is the list of trusted keys. Comments like this one and empty\n"
"# lines are allowed but keep in mind that the entire file is integrity\n"
"# protected by the use of a MAC, so changing the file does not make\n"
"# much sense without the knowledge of the MAC key. Lines do have a\n"
"# length limit but this is not serious limitation as the format of the\n"
"# entries is fixed and checked by gpg-agent: A non-comment line starts\n"
"# with optional white spaces, followed by exactly 40 hex character,\n"
"# optioanlly followed by a flag character which my either be 'P', 'S'\n"
"# or '*'. Additional data delimited with by a white space is ignored.\n"
"\n";
static FILE *trustfp;
static int
open_list (int append)
{
char *fname;
fname = make_filename (opt.homedir, "trustlist.txt", NULL);
trustfp = fopen (fname, append? "a+":"r");
if (!trustfp && errno == ENOENT)
{
trustfp = fopen (fname, "wx");
if (!trustfp)
{
log_error ("can't create `%s': %s\n", fname, strerror (errno));
xfree (fname);
return seterr (File_Create_Error);
}
fputs (headerblurb, trustfp);
fclose (trustfp);
trustfp = fopen (fname, append? "a+":"r");
}
if (!trustfp)
{
log_error ("can't open `%s': %s\n", fname, strerror (errno));
xfree (fname);
return seterr (File_Open_Error);
}
/*FIXME: check the MAC */
return 0;
}
/* Read the trustlist and return entry by entry. KEY must point to a
buffer of at least 41 characters. KEYFLAG does return either 'P',
'S' or '*'.
Reading a valid entry return 0, EOF returns -1 any other error
returns the appropriate error code. */
static int
read_list (char *key, int *keyflag)
{
int rc;
int c, i;
char *p, line[256];
if (!trustfp)
{
rc = open_list (0);
if (rc)
return rc;
}
do
{
if (!fgets (line, DIM(line)-1, trustfp) )
{
if (feof (trustfp))
return -1;
return GNUPG_Read_Error;
}
if (!*line || line[strlen(line)-1] != '\n')
{
/* eat until end of line */
while ( (c=getc (trustfp)) != EOF && c != '\n')
;
return *line? GNUPG_Line_Too_Long: GNUPG_Incomplete_Line;
}
/* Allow for emty lines and spaces */
for (p=line; spacep (p); p++)
;
}
while (!*p || *p == '\n' || *p == '#');
for (i=0; hexdigitp (p+i) && i < 40; i++)
key[i] = p[i] >= 'a'? (p[i] & 0xdf): p[i];
key[i] = 0;
if (i!=40 || !(spacep (p+i) || p[i] == '\n'))
{
log_error ("invalid formatted fingerprint in trustlist\n");
return GNUPG_Bad_Data;
}
assert (p[i]);
if (p[i] == '\n')
*keyflag = '*';
else
{
i++;
if ( p[i] == 'P' || p[i] == 'p')
*keyflag = 'P';
else if ( p[i] == 'S' || p[i] == 's')
*keyflag = 'S';
else if ( p[i] == '*')
*keyflag = '*';
else
{
log_error ("invalid keyflag in trustlist\n");
return GNUPG_Bad_Data;
}
i++;
if ( !(spacep (p+i) || p[i] == '\n'))
{
log_error ("invalid keyflag in trustlist\n");
return GNUPG_Bad_Data;
}
}
return 0;
}
/* check whether the given fpr is in our trustdb. We expect FPR to be
an all uppercase hexstring of 40 characters. */
int
agent_istrusted (const char *fpr)
{
int rc;
static char key[41];
int keyflag;
if (trustfp)
rewind (trustfp);
while (!(rc=read_list (key, &keyflag)))
{
if (!strcmp (key, fpr))
return 0;
}
if (rc != -1)
{
/* error in the trustdb - close it to give the user a chance for
correction */
fclose (trustfp);
trustfp = NULL;
}
return rc;
}
/* write all trust entries to FP */
int
agent_listtrusted (void *assuan_context)
{
int rc;
static char key[51];
int keyflag;
if (trustfp)
rewind (trustfp);
while (!(rc=read_list (key, &keyflag)))
{
key[40] = ' ';
key[41] = keyflag;
key[42] = '\n';
assuan_send_data (assuan_context, key, 43);
assuan_send_data (assuan_context, NULL, 0); /* flush */
}
if (rc == -1)
rc = 0;
if (rc)
{
/* error in the trustdb - close it to give the user a chance for
correction */
fclose (trustfp);
trustfp = NULL;
}
return rc;
}
/* 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 alreay ben put
into the trustdb and returns success in this case. Before a FPR
actually gets inserted, the user is asked by means of the pin-entry
whether this is actual wants he want to do.
*/
int
agent_marktrusted (const char *name, const char *fpr, int flag)
{
int rc;
static char key[41];
int keyflag;
char *desc;
if (trustfp)
rewind (trustfp);
while (!(rc=read_list (key, &keyflag)))
{
if (!strcmp (key, fpr))
return 0;
}
fclose (trustfp);
trustfp = NULL;
if (rc != -1)
return rc; /* error in the trustdb */
/* insert a new one */
if (asprintf (&desc,
"Please verify that the certificate identified as:%%0A"
" \"%s\"%%0A"
"has the fingerprint:%%0A"
" %s", name, fpr) < 0 )
return GNUPG_Out_Of_Core;
rc = agent_get_confirmation (desc, "Correct", "No");
free (desc);
if (rc)
return rc;
if (asprintf (&desc,
"Do you ultimately trust%%0A"
" \"%s\"%%0A"
"to correctly certify user certificates?",
name) < 0 )
return GNUPG_Out_Of_Core;
rc = agent_get_confirmation (desc, "Yes", "No");
free (desc);
if (rc)
return rc;
/* now check again to avoid duplicates. Also open in append mode now */
rc = open_list (1);
if (rc)
return rc;
rewind (trustfp);
while (!(rc=read_list (key, &keyflag)))
{
if (!strcmp (key, fpr))
return 0;
}
if (rc != -1)
{
fclose (trustfp);
trustfp = NULL;
return rc; /* error in the trustdb */
}
rc = 0;
/* append the key */
fflush (trustfp);
fputs ("\n# ", trustfp);
print_sanitized_string (trustfp, name, 0);
fprintf (trustfp, "\n%s %c\n", fpr, flag);
if (ferror (trustfp))
rc = GNUPG_Write_Error;
/* close because we are in append mode */
if (fclose (trustfp))
rc = GNUPG_File_Error;
trustfp = NULL;
return rc;
}

View File

@ -1,250 +0,0 @@
2002-08-16 Werner Koch <wk@gnupg.org>
* assuan.h: Renamed Bad_Certificate_Path to Bad_Certificate_Chain.
2002-07-30 Werner Koch <wk@gnupg.org>
Changed the license from GPL to LGPL.
2002-07-23 Werner Koch <wk@gnupg.org>
* assuan-handler.c (_IO_cookie_io_functions_t): Define it here if
it does not exists.
2002-06-27 Werner Koch <wk@gnupg.org>
* assuan-pipe-connect.c (assuan_pipe_connect): No special handling
for the log_fd and stderr. Connect stderr to /dev/null if it
should not be retained.
2002-06-26 Werner Koch <wk@gnupg.org>
* assuan-buffer.c (assuan_write_line): Make sure we never
accidently print an extra LF.
2002-05-23 Werner Koch <wk@gnupg.org>
* assuan-util.c (assuan_set_io_func): New.
* assuan-buffer.c (writen, readline): Use the new functions
instead of pth.
* assuan-socket-server.c (accept_connection): Don't use the
pth_accept - using the assuan included accept code would be a bad
idea within Pth so we don't need a replacement function.
2002-05-22 Werner Koch <wk@gnupg.org>
* assuan-socket-server.c (assuan_init_connected_socket_server): New.
(accept_connection): Factored most code out to..
(accept_connection_bottom): .. new function.
2002-04-04 Werner Koch <wk@gnupg.org>
* assuan-buffer.c (my_log_prefix): New. Use it for all i/o debug
output.
2002-03-06 Werner Koch <wk@gnupg.org>
* assuan-client.c (_assuan_read_from_server): Detect END.
(assuan_transact): Pass it to the data callback.
2002-02-27 Werner Koch <wk@gnupg.org>
* assuan-client.c (assuan_transact): Add 2 more arguments to
support status lines. Passing NULL yields the old behaviour.
* assuan-handler.c (process_request): Flush data lines send
without using the data fp.
2002-02-14 Werner Koch <wk@gnupg.org>
* assuan-inquire.c (assuan_inquire): Check for a cancel command
and return ASSUAN_Canceled. Allow for non-data inquiry.
* assuan.h: Add a few token specific error codes.
2002-02-13 Werner Koch <wk@gnupg.org>
* assuan-defs.h (assuan_context_s): New var CLIENT_PID.
* assuan-pipe-server.c (_assuan_new_context): set default value.
* assuan-socket-server.c (accept_connection): get the actual pid.
2002-02-12 Werner Koch <wk@gnupg.org>
* assuan-buffer.c (writen,readline) [USE_GNU_PT]: Use pth_read/write.
* assuan-socket-server.c (accept_connection) [USE_GNU_PTH]: Ditto.
2002-02-01 Marcus Brinkmann <marcus@g10code.de>
* Makefile.am (MOSTLYCLEANFILES): New variable.
2002-01-23 Werner Koch <wk@gnupg.org>
* assuan-socket-connect.c (LOGERRORX): and removed typo.
2002-01-22 Marcus Brinkmann <marcus@g10code.de>
* assuan-socket-connect.c (LOGERRORX): Reverse arguments to fputs.
2002-01-21 Werner Koch <wk@gnupg.org>
* assuan-connect.c: Move all except assuan_get_pid to...
* assuan-pipe-connect.c: this.
(assuan_pipe_disconnect): Removed.
(do_finish, do_deinit): New
(assuan_pipe_connect): and set them into the context.
* assuan-socket-connect.c: New.
* assuan-util.c (_assuan_log_sanitized_string): New.
* assuan-pipe-server.c (assuan_init_pipe_server): Factored most
code out to ...
(_assuan_new_context): new func.
(_assuan_release_context): New
* assuan-connect.c (assuan_pipe_connect): Use the new functions.
2002-01-20 Werner Koch <wk@gnupg.org>
* assuan.h: Added Invalid Option error code.
* assuan-handler.c (std_handler_option): New.
(std_cmd_tbl): Add OPTION as standard command.
(assuan_register_option_handler): New.
(dispatch_command): Use case insensitive matching as a fallback.
(my_strcasecmp): New.
2002-01-19 Werner Koch <wk@gnupg.org>
* assuan-buffer.c (_assuan_read_line): Add output logging.
(assuan_write_line): Ditto.
(_assuan_cookie_write_data): Ditto.
(_assuan_cookie_write_flush): Ditto.
* assuan-util.c (_assuan_log_print_buffer): New.
(assuan_set_log_stream): New.
(assuan_begin_confidential): New.
(assuan_end_confidential): New.
* assuan-defs.h: Add a few handler variables.
* assuan-pipe-server.c (assuan_deinit_pipe_server): Removed.
(deinit_pipe_server): New.
(assuan_deinit_server): New. Changed all callers to use this.
* assuan-listen.c (assuan_accept): Use the accept handler.
* assuan-handler.c (process_request): Use the close Handler.
* assuan-socket-server.c: New.
2002-01-14 Werner Koch <wk@gnupg.org>
* assuan-client.c (_assuan_read_from_server): Skip spaces after
the keyword.
2002-01-03 Werner Koch <wk@gnupg.org>
* assuan-handler.c (assuan_set_okay_line): New.
(process_request): And use it here.
2002-01-02 Werner Koch <wk@gnupg.org>
* assuan-inquire.c (init_membuf,put_membuf,get_membuf): Apply a
hidden 0 behind the buffer so that the buffer can be used as a
string in certain contexts.
2001-12-14 Marcus Brinkmann <marcus@g10code.de>
* assuan-connect.c (assuan_pipe_connect): New argument
FD_CHILD_LIST. Don't close those fds.
* assuan.h: Likewise for prototype.
2001-12-14 Werner Koch <wk@gnupg.org>
* assuan-listen.c (assuan_close_input_fd): New.
(assuan_close_output_fd): New.
* assuan-handler.c (std_handler_reset): Always close them after a
reset command.
(std_handler_bye): Likewise.
2001-12-14 Marcus Brinkmann <marcus@g10code.de>
* assuan-buffer.c (_assuan_read_line): New variable ATTICLEN, use
it to save the length of the attic line.
Rediddle the code a bit to make it more clear what happens.
2001-12-14 Marcus Brinkmann <marcus@g10code.de>
* assuan-defs.h (LINELENGTH): Define as ASSUAN_LINELENGTH.
assuan.h: Define ASSUAN_LINELENGTH.
2001-12-13 Marcus Brinkmann <marcus@g10code.de>
* assuan-buffer.c (assuan_read_line): Fix order of execution to
get correct return values.
2001-12-13 Werner Koch <wk@gnupg.org>
* assuan-handler.c (assuan_get_active_fds): Fixed silly bug,
pretty obvious that nobody ever tested this function.
2001-12-12 Werner Koch <wk@gnupg.org>
* assuan-connect.c (assuan_pipe_connect): Implemented the inital
handshake.
* assuan-client.c (read_from_server): Renamed to
(_assuan_read_from_server): this and made external.
* assuan-listen.c (assuan_set_hello_line): New.
(assuan_accept): Use a custom hello line is available.
* assuan-buffer.c (assuan_read_line): New.
(assuan_pending_line): New.
(_assuan_write_line): Renamed to ..
(assuan_write_line): this, made public and changed all callers.
2001-12-04 Werner Koch <wk@gnupg.org>
* assuan-connect.c (assuan_pipe_connect): Add more error reporting.
* assuan-client.c: New.
* assuan-inquire.c: New.
* assuan-handler.c (process_request): Check for nested invocations.
2001-11-27 Werner Koch <wk@gnupg.org>
* assuan-handler.c (assuan_register_input_notify): New.
(assuan_register_output_notify): New.
2001-11-26 Werner Koch <wk@gnupg.org>
* assuan.h: Added more status codes.
2001-11-25 Werner Koch <wk@gnupg.org>
* assuan-handler.c (assuan_register_bye_notify)
(assuan_register_reset_notify)
(assuan_register_cancel_notify): New and call them from the
standard handlers.
(assuan_process): Moved bulk of function to ..
(process_request): .. new.
(assuan_process_next): One shot version of above.
(assuan_get_active_fds): New.
2001-11-24 Werner Koch <wk@gnupg.org>
* assuan-connect.c (assuan_get_pid): New.
* assuan-buffer.c (_assuan_read_line): Deal with reads of more
than a line.
* assuan-defs.h: Add space in the context for this.
***********************************************************
* Please note that Assuan is maintained as part of GnuPG. *
* You may find it source-copied in other packages. *
***********************************************************
Copyright 2001, 2002 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
modifications, as long as this notice is preserved.
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.

View File

@ -1,49 +0,0 @@
# Assuan Makefile
# Copyright (C) 2001, 2002 Free Software Foundation, Inc.
#
# This file is part of Assuan.
#
# Assuan is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of
# the License, or (at your option) any later version.
#
# Assuan 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser 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
## Process this file with automake to produce Makefile.in
EXTRA_DIST = mkerrors
INCLUDES = -I.. -I$(top_srcdir)/include
BUILT_SOURCES = assuan-errors.c
MOSTLYCLEANFILES = assuan-errors.c
noinst_LIBRARIES = libassuan.a
#libassuan_a_LDFLAGS =
libassuan_a_SOURCES = \
assuan.h \
assuan-defs.h \
assuan-util.c \
assuan-errors.c \
assuan-buffer.c \
assuan-handler.c \
assuan-inquire.c \
assuan-listen.c \
assuan-connect.c \
assuan-client.c \
assuan-pipe-server.c \
assuan-socket-server.c \
assuan-pipe-connect.c \
assuan-socket-connect.c
assuan-errors.c : assuan.h
$(srcdir)/mkerrors < $(srcdir)/assuan.h > assuan-errors.c

View File

@ -1,443 +0,0 @@
/* assuan-buffer.c - read and send data
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
#include <config.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>
#include "assuan-defs.h"
#ifdef HAVE_JNLIB_LOGGING
#include "../jnlib/logging.h"
#endif
static const char *
my_log_prefix (void)
{
#ifdef HAVE_JNLIB_LOGGING
return log_get_prefix (NULL);
#else
return "";
#endif
}
static int
writen ( int fd, const char *buffer, size_t length )
{
while (length)
{
int nwritten = _assuan_write_wrapper?
_assuan_write_wrapper (fd, buffer, length):
write (fd, buffer, length);
if (nwritten < 0)
{
if (errno == EINTR)
continue;
return -1; /* write error */
}
length -= nwritten;
buffer += nwritten;
}
return 0; /* okay */
}
/* read an entire line */
static int
readline (int fd, char *buf, size_t buflen, int *r_nread, int *eof)
{
size_t nleft = buflen;
char *p;
*eof = 0;
*r_nread = 0;
while (nleft > 0)
{
int n = _assuan_read_wrapper?
_assuan_read_wrapper (fd, buf, nleft):
read (fd, buf, nleft);
if (n < 0)
{
if (errno == EINTR)
continue;
return -1; /* read error */
}
else if (!n)
{
*eof = 1;
break; /* allow incomplete lines */
}
p = buf;
nleft -= n;
buf += n;
*r_nread += n;
for (; n && *p != '\n'; n--, p++)
;
if (n)
break; /* at least one full line available - that's enough for now */
}
return 0;
}
int
_assuan_read_line (ASSUAN_CONTEXT ctx)
{
char *line = ctx->inbound.line;
int n, nread, atticlen;
int rc;
if (ctx->inbound.eof)
return -1;
atticlen = ctx->inbound.attic.linelen;
if (atticlen)
{
memcpy (line, ctx->inbound.attic.line, atticlen);
ctx->inbound.attic.linelen = 0;
for (n=0; n < atticlen && line[n] != '\n'; n++)
;
if (n < atticlen)
{
rc = 0; /* found another line in the attic */
nread = atticlen;
atticlen = 0;
}
else
{ /* read the rest */
assert (atticlen < LINELENGTH);
rc = readline (ctx->inbound.fd, line + atticlen,
LINELENGTH - atticlen, &nread, &ctx->inbound.eof);
}
}
else
rc = readline (ctx->inbound.fd, line, LINELENGTH,
&nread, &ctx->inbound.eof);
if (rc)
{
if (ctx->log_fp)
fprintf (ctx->log_fp, "%s[%p] <- [Error: %s]\n",
my_log_prefix (), ctx, strerror (errno));
return ASSUAN_Read_Error;
}
if (!nread)
{
assert (ctx->inbound.eof);
if (ctx->log_fp)
fprintf (ctx->log_fp, "%s[%p] <- [EOF]\n", my_log_prefix (),ctx);
return -1;
}
ctx->inbound.attic.pending = 0;
nread += atticlen;
for (n=0; n < nread; n++)
{
if (line[n] == '\n')
{
if (n+1 < nread)
{
char *s, *d;
int i;
n++;
/* we have to copy the rest because the handlers are
allowed to modify the passed buffer */
for (d=ctx->inbound.attic.line, s=line+n, i=nread-n; i; i--)
{
if (*s=='\n')
ctx->inbound.attic.pending = 1;
*d++ = *s++;
}
ctx->inbound.attic.linelen = nread-n;
n--;
}
if (n && line[n-1] == '\r')
n--;
line[n] = 0;
ctx->inbound.linelen = n;
if (ctx->log_fp)
{
fprintf (ctx->log_fp, "%s[%p] <- ", my_log_prefix (), ctx);
if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp);
else
_assuan_log_print_buffer (ctx->log_fp,
ctx->inbound.line,
ctx->inbound.linelen);
putc ('\n', ctx->log_fp);
}
return 0;
}
}
if (ctx->log_fp)
fprintf (ctx->log_fp, "%s[%p] <- [Invalid line]\n", my_log_prefix (), ctx);
*line = 0;
ctx->inbound.linelen = 0;
return ctx->inbound.eof? ASSUAN_Line_Not_Terminated : ASSUAN_Line_Too_Long;
}
/* Read the next line from the client or server and return a pointer
to a buffer with holding that line. linelen returns the length of
the line. This buffer is valid until another read operation is
done on this buffer. The caller is allowed to modify this buffer.
He should only use the buffer if the function returns without an
error.
Returns: 0 on success or an assuan error code
See also: assuan_pending_line().
*/
AssuanError
assuan_read_line (ASSUAN_CONTEXT ctx, char **line, size_t *linelen)
{
AssuanError err;
if (!ctx)
return ASSUAN_Invalid_Value;
err = _assuan_read_line (ctx);
*line = ctx->inbound.line;
*linelen = ctx->inbound.linelen;
return err;
}
/* Return true when a full line is pending for a read, without the need
for actual IO */
int
assuan_pending_line (ASSUAN_CONTEXT ctx)
{
return ctx && ctx->inbound.attic.pending;
}
AssuanError
assuan_write_line (ASSUAN_CONTEXT ctx, const char *line )
{
int rc;
size_t len;
const char *s;
if (!ctx)
return ASSUAN_Invalid_Value;
/* Make sure that we never take a LF from the user - this might
violate the protocol. */
s = strchr (line, '\n');
len = s? (s-line) : strlen (line);
/* fixme: we should do some kind of line buffering. */
if (ctx->log_fp)
{
fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx);
if (s)
fputs ("[supplied line contained a LF]", ctx->log_fp);
if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp);
else
_assuan_log_print_buffer (ctx->log_fp, line, len);
putc ('\n', ctx->log_fp);
}
rc = writen (ctx->outbound.fd, line, len);
if (rc)
rc = ASSUAN_Write_Error;
if (!rc)
{
rc = writen (ctx->outbound.fd, "\n", 1);
if (rc)
rc = ASSUAN_Write_Error;
}
return rc;
}
/* Write out the data in buffer as datalines with line wrapping and
percent escaping. This fucntion is used for GNU's custom streams */
int
_assuan_cookie_write_data (void *cookie, const char *buffer, size_t size)
{
ASSUAN_CONTEXT ctx = cookie;
char *line;
size_t linelen;
if (ctx->outbound.data.error)
return 0;
line = ctx->outbound.data.line;
linelen = ctx->outbound.data.linelen;
line += linelen;
while (size)
{
/* insert data line header */
if (!linelen)
{
*line++ = 'D';
*line++ = ' ';
linelen += 2;
}
/* copy data, keep some space for the CRLF and to escape one character */
while (size && linelen < LINELENGTH-2-2)
{
if (*buffer == '%' || *buffer == '\r' || *buffer == '\n')
{
sprintf (line, "%%%02X", *(unsigned char*)buffer);
line += 3;
linelen += 3;
buffer++;
}
else
{
*line++ = *buffer++;
linelen++;
}
size--;
}
if (linelen >= LINELENGTH-2-2)
{
if (ctx->log_fp)
{
fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx);
if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp);
else
_assuan_log_print_buffer (ctx->log_fp,
ctx->outbound.data.line,
linelen);
putc ('\n', ctx->log_fp);
}
*line++ = '\n';
linelen++;
if (writen (ctx->outbound.fd, ctx->outbound.data.line, linelen))
{
ctx->outbound.data.error = ASSUAN_Write_Error;
return 0;
}
line = ctx->outbound.data.line;
linelen = 0;
}
}
ctx->outbound.data.linelen = linelen;
return 0;
}
/* Write out any buffered data
This fucntion is used for GNU's custom streams */
int
_assuan_cookie_write_flush (void *cookie)
{
ASSUAN_CONTEXT ctx = cookie;
char *line;
size_t linelen;
if (ctx->outbound.data.error)
return 0;
line = ctx->outbound.data.line;
linelen = ctx->outbound.data.linelen;
line += linelen;
if (linelen)
{
if (ctx->log_fp)
{
fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx);
if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp);
else
_assuan_log_print_buffer (ctx->log_fp,
ctx->outbound.data.line,
linelen);
putc ('\n', ctx->log_fp);
}
*line++ = '\n';
linelen++;
if (writen (ctx->outbound.fd, ctx->outbound.data.line, linelen))
{
ctx->outbound.data.error = ASSUAN_Write_Error;
return 0;
}
ctx->outbound.data.linelen = 0;
}
return 0;
}
/**
* assuan_send_data:
* @ctx: An assuan context
* @buffer: Data to send or NULL to flush
* @length: length of the data to send/
*
* This function may be used by the server or the client to send data
* lines. The data will be escaped as required by the Assuan protocol
* and may get buffered until a line is full. To force sending the
* data out @buffer may be passed as NULL (in which case @length must
* also be 0); however when used by a client this flush operation does
* also send the terminating "END" command to terminate the reponse on
* a INQUIRE response. However, when assuan_transact() is used, this
* function takes care of sending END itself.
*
* Return value: 0 on success or an error code
**/
AssuanError
assuan_send_data (ASSUAN_CONTEXT ctx, const void *buffer, size_t length)
{
if (!ctx)
return ASSUAN_Invalid_Value;
if (!buffer && length)
return ASSUAN_Invalid_Value;
if (!buffer)
{ /* flush what we have */
_assuan_cookie_write_flush (ctx);
if (ctx->outbound.data.error)
return ctx->outbound.data.error;
if (!ctx->is_server)
return assuan_write_line (ctx, "END");
}
else
{
_assuan_cookie_write_data (ctx, buffer, length);
if (ctx->outbound.data.error)
return ctx->outbound.data.error;
}
return 0;
}

View File

@ -1,225 +0,0 @@
/* assuan-client.c - client functions
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>
#include "assuan-defs.h"
#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
*(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
AssuanError
_assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off)
{
char *line;
int linelen;
AssuanError rc;
*okay = 0;
*off = 0;
do
{
rc = _assuan_read_line (ctx);
if (rc)
return rc;
line = ctx->inbound.line;
linelen = ctx->inbound.linelen;
}
while (*line == '#' || !linelen);
if (linelen >= 1
&& line[0] == 'D' && line[1] == ' ')
{
*okay = 2; /* data line */
*off = 2;
}
else if (linelen >= 1
&& line[0] == 'S'
&& (line[1] == '\0' || line[1] == ' '))
{
*okay = 4;
*off = 1;
while (line[*off] == ' ')
++*off;
}
else if (linelen >= 2
&& line[0] == 'O' && line[1] == 'K'
&& (line[2] == '\0' || line[2] == ' '))
{
*okay = 1;
*off = 2;
while (line[*off] == ' ')
++*off;
}
else if (linelen >= 3
&& line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
&& (line[3] == '\0' || line[3] == ' '))
{
*okay = 0;
*off = 3;
while (line[*off] == ' ')
++*off;
}
else if (linelen >= 7
&& line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
&& line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
&& line[6] == 'E'
&& (line[7] == '\0' || line[7] == ' '))
{
*okay = 3;
*off = 7;
while (line[*off] == ' ')
++*off;
}
else if (linelen >= 3
&& line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
&& (line[3] == '\0' || line[3] == ' '))
{
*okay = 5; /* end line */
*off = 3;
}
else
rc = ASSUAN_Invalid_Response;
return rc;
}
/**
* assuan_transact:
* @ctx: The Assuan context
* @command: Coimmand line to be send to server
* @data_cb: Callback function for data lines
* @data_cb_arg: first argument passed to @data_cb
* @inquire_cb: Callback function for a inquire response
* @inquire_cb_arg: first argument passed to @inquire_cb
* @status_cb: Callback function for a status response
* @status_cb_arg: first argument passed to @status_cb
*
* FIXME: Write documentation
*
* Return value: 0 on success or error code. The error code may be
* the one one returned by the server in error lines or from the
* callback functions.
**/
AssuanError
assuan_transact (ASSUAN_CONTEXT ctx,
const char *command,
AssuanError (*data_cb)(void *, const void *, size_t),
void *data_cb_arg,
AssuanError (*inquire_cb)(void*, const char *),
void *inquire_cb_arg,
AssuanError (*status_cb)(void*, const char *),
void *status_cb_arg)
{
int rc, okay, off;
unsigned char *line;
int linelen;
rc = assuan_write_line (ctx, command);
if (rc)
return rc;
again:
rc = _assuan_read_from_server (ctx, &okay, &off);
if (rc)
return rc; /* error reading from server */
line = ctx->inbound.line + off;
linelen = ctx->inbound.linelen - off;
if (!okay)
{
rc = atoi (line);
if (rc < 100)
rc = ASSUAN_Server_Fault;
}
else if (okay == 2)
{
if (!data_cb)
rc = ASSUAN_No_Data_Callback;
else
{
unsigned char *s, *d;
for (s=d=line; linelen; linelen--)
{
if (*s == '%' && linelen > 2)
{ /* handle escaping */
s++;
*d++ = xtoi_2 (s);
s += 2;
linelen -= 2;
}
else
*d++ = *s++;
}
*d = 0; /* add a hidden string terminator */
rc = data_cb (data_cb_arg, line, d - line);
if (!rc)
goto again;
}
}
else if (okay == 3)
{
if (!inquire_cb)
{
assuan_write_line (ctx, "END"); /* get out of inquire mode */
_assuan_read_from_server (ctx, &okay, &off); /* dummy read */
rc = ASSUAN_No_Inquire_Callback;
}
else
{
rc = inquire_cb (inquire_cb_arg, line);
if (!rc)
rc = assuan_send_data (ctx, NULL, 0); /* flush and send END */
if (!rc)
goto again;
}
}
else if (okay == 4)
{
if (status_cb)
rc = status_cb (status_cb_arg, line);
if (!rc)
goto again;
}
else if (okay == 5)
{
if (!data_cb)
rc = ASSUAN_No_Data_Callback;
else
{
rc = data_cb (data_cb_arg, NULL, 0);
if (!rc)
goto again;
}
}
return rc;
}

View File

@ -1,54 +0,0 @@
/* assuan-connect.c - Establish a connection (client)
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "assuan-defs.h"
/* Disconnect and release the context CTX. */
void
assuan_disconnect (ASSUAN_CONTEXT ctx)
{
if (ctx)
{
assuan_write_line (ctx, "BYE");
ctx->finish_handler (ctx);
ctx->deinit_handler (ctx);
ctx->deinit_handler = NULL;
_assuan_release_context (ctx);
}
}
pid_t
assuan_get_pid (ASSUAN_CONTEXT ctx)
{
return ctx ? ctx->pid : -1;
}

View File

@ -1,144 +0,0 @@
/* assuan-defs.c - Internal definitions to Assuan
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
#ifndef ASSUAN_DEFS_H
#define ASSUAN_DEFS_H
#include <sys/types.h>
#include "assuan.h"
#define LINELENGTH ASSUAN_LINELENGTH
struct cmdtbl_s {
const char *name;
int cmd_id;
int (*handler)(ASSUAN_CONTEXT, char *line);
};
struct assuan_context_s {
AssuanError err_no;
const char *err_str;
int os_errno; /* last system error number used with certain error codes*/
int confidential;
int is_server; /* set if this is context belongs to a server */
int in_inquire;
char *hello_line;
char *okay_line; /* see assan_set_okay_line() */
void *user_pointer; /* for assuan_[gs]et_pointer () */
FILE *log_fp;
struct {
int fd;
int eof;
char line[LINELENGTH];
int linelen; /* w/o CR, LF - might not be the same as
strlen(line) due to embedded nuls. However a nul
is always written at this pos */
struct {
char line[LINELENGTH];
int linelen ;
int pending; /* i.e. at least one line is available in the attic */
} attic;
} inbound;
struct {
int fd;
struct {
FILE *fp;
char line[LINELENGTH];
int linelen;
int error;
} data;
} outbound;
int pipe_mode; /* We are in pipe mode, i.e. we can handle just one
connection and must terminate then */
pid_t pid; /* In pipe mode, the pid of the child server process.
In socket mode, the pid of the server */
int listen_fd; /* The fd we are listening on (used by socket servers) */
int connected_fd; /* helper */
pid_t client_pid; /* for a socket server the PID of the client or -1
if not available */
void (*deinit_handler)(ASSUAN_CONTEXT);
int (*accept_handler)(ASSUAN_CONTEXT);
int (*finish_handler)(ASSUAN_CONTEXT);
struct cmdtbl_s *cmdtbl;
size_t cmdtbl_used; /* used entries */
size_t cmdtbl_size; /* allocated size of table */
void (*bye_notify_fnc)(ASSUAN_CONTEXT);
void (*reset_notify_fnc)(ASSUAN_CONTEXT);
void (*cancel_notify_fnc)(ASSUAN_CONTEXT);
int (*option_handler_fnc)(ASSUAN_CONTEXT,const char*, const char*);
void (*input_notify_fnc)(ASSUAN_CONTEXT, const char *);
void (*output_notify_fnc)(ASSUAN_CONTEXT, const char *);
int input_fd; /* set by INPUT command */
int output_fd; /* set by OUTPUT command */
};
/*-- assuan-pipe-server.c --*/
int _assuan_new_context (ASSUAN_CONTEXT *r_ctx);
void _assuan_release_context (ASSUAN_CONTEXT ctx);
/*-- assuan-handler.c --*/
int _assuan_register_std_commands (ASSUAN_CONTEXT ctx);
/*-- assuan-buffer.c --*/
int _assuan_read_line (ASSUAN_CONTEXT ctx);
int _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size);
int _assuan_cookie_write_flush (void *cookie);
/*-- assuan-client.c --*/
AssuanError _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off);
/*-- assuan-util.c --*/
extern ssize_t (*_assuan_read_wrapper)(int,void*,size_t);
extern ssize_t (*_assuan_write_wrapper)(int,const void*,size_t);
void *_assuan_malloc (size_t n);
void *_assuan_calloc (size_t n, size_t m);
void *_assuan_realloc (void *p, size_t n);
void _assuan_free (void *p);
#define xtrymalloc(a) _assuan_malloc ((a))
#define xtrycalloc(a,b) _assuan_calloc ((a),(b))
#define xtryrealloc(a,b) _assuan_realloc((a),(b))
#define xfree(a) _assuan_free ((a))
#define set_error(c,e,t) assuan_set_error ((c), ASSUAN_ ## e, (t))
void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length);
void _assuan_log_sanitized_string (const char *string);
#endif /*ASSUAN_DEFS_H*/

View File

@ -1,708 +0,0 @@
/* assuan-handler.c - dispatch commands
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "assuan-defs.h"
#define spacep(p) (*(p) == ' ' || *(p) == '\t')
#define digitp(a) ((a) >= '0' && (a) <= '9')
#if !HAVE_FOPENCOOKIE
/* Provide structure for our dummy replacement function. Usually this
is defined in ../common/util.h but assuan should be self
contained. */
/* Fixme: Remove fopencoookie :-(( */
typedef struct
{
ssize_t (*read)(void*,char*,size_t);
ssize_t (*write)(void*,const char*,size_t);
int (*seek)(void*,off_t*,int);
int (*close)(void*);
} _IO_cookie_io_functions_t;
typedef _IO_cookie_io_functions_t cookie_io_functions_t;
FILE *fopencookie (void *cookie, const char *opentype,
cookie_io_functions_t funclist);
#endif /*!HAVE_FOPENCOOKIE*/
static int
dummy_handler (ASSUAN_CONTEXT ctx, char *line)
{
return set_error (ctx, Server_Fault, "no handler registered");
}
static int
std_handler_nop (ASSUAN_CONTEXT ctx, char *line)
{
return 0; /* okay */
}
static int
std_handler_cancel (ASSUAN_CONTEXT ctx, char *line)
{
if (ctx->cancel_notify_fnc)
ctx->cancel_notify_fnc (ctx);
return set_error (ctx, Not_Implemented, NULL);
}
static int
std_handler_option (ASSUAN_CONTEXT ctx, char *line)
{
char *key, *value, *p;
for (key=line; spacep (key); key++)
;
if (!*key)
return set_error (ctx, Syntax_Error, "argument required");
if (*key == '=')
return set_error (ctx, Syntax_Error, "no option name given");
for (value=key; *value && !spacep (value) && *value != '='; value++)
;
if (*value)
{
if (spacep (value))
*value++ = 0; /* terminate key */
for (; spacep (value); value++)
;
if (*value == '=')
{
*value++ = 0; /* terminate key */
for (; spacep (value); value++)
;
if (!*value)
return set_error (ctx, Syntax_Error, "option argument expected");
}
if (*value)
{
for (p = value + strlen(value) - 1; p > value && spacep (p); p--)
;
if (p > value)
*++p = 0; /* strip trailing spaces */
}
}
if (*key == '-' && key[1] == '-' && key[2])
key += 2; /* the double dashes are optional */
if (*key == '-')
return set_error (ctx, Syntax_Error,
"option should not begin with one dash");
if (ctx->option_handler_fnc)
return ctx->option_handler_fnc (ctx, key, value);
return 0;
}
static int
std_handler_bye (ASSUAN_CONTEXT ctx, char *line)
{
if (ctx->bye_notify_fnc)
ctx->bye_notify_fnc (ctx);
assuan_close_input_fd (ctx);
assuan_close_output_fd (ctx);
return -1; /* pretty simple :-) */
}
static int
std_handler_auth (ASSUAN_CONTEXT ctx, char *line)
{
return set_error (ctx, Not_Implemented, NULL);
}
static int
std_handler_reset (ASSUAN_CONTEXT ctx, char *line)
{
if (ctx->reset_notify_fnc)
ctx->reset_notify_fnc (ctx);
assuan_close_input_fd (ctx);
assuan_close_output_fd (ctx);
return 0;
}
static int
std_handler_end (ASSUAN_CONTEXT ctx, char *line)
{
return set_error (ctx, Not_Implemented, NULL);
}
static int
parse_cmd_input_output (ASSUAN_CONTEXT ctx, char *line, int *rfd)
{
char *endp;
if (strncmp (line, "FD=", 3))
return set_error (ctx, Syntax_Error, "FD=<n> expected");
line += 3;
if (!digitp (*line))
return set_error (ctx, Syntax_Error, "number required");
*rfd = strtoul (line, &endp, 10);
/* remove that argument so that a notify handler won't see it */
memset (line, ' ', endp? (endp-line):strlen(line));
if (*rfd == ctx->inbound.fd)
return set_error (ctx, Parameter_Conflict, "fd same as inbound fd");
if (*rfd == ctx->outbound.fd)
return set_error (ctx, Parameter_Conflict, "fd same as outbound fd");
return 0;
}
/* Format is INPUT FD=<n> */
static int
std_handler_input (ASSUAN_CONTEXT ctx, char *line)
{
int rc, fd;
rc = parse_cmd_input_output (ctx, line, &fd);
if (rc)
return rc;
ctx->input_fd = fd;
if (ctx->input_notify_fnc)
ctx->input_notify_fnc (ctx, line);
return 0;
}
/* Format is OUTPUT FD=<n> */
static int
std_handler_output (ASSUAN_CONTEXT ctx, char *line)
{
int rc, fd;
rc = parse_cmd_input_output (ctx, line, &fd);
if (rc)
return rc;
ctx->output_fd = fd;
if (ctx->output_notify_fnc)
ctx->output_notify_fnc (ctx, line);
return 0;
}
/* This is a table with the standard commands and handler for them.
The table is used to initialize a new context and assuciate strings
and handlers with cmd_ids */
static struct {
const char *name;
int cmd_id;
int (*handler)(ASSUAN_CONTEXT, char *line);
int always; /* always initialize this command */
} std_cmd_table[] = {
{ "NOP", ASSUAN_CMD_NOP, std_handler_nop, 1 },
{ "CANCEL", ASSUAN_CMD_CANCEL, std_handler_cancel, 1 },
{ "OPTION", ASSUAN_CMD_OPTION, std_handler_option, 1 },
{ "BYE", ASSUAN_CMD_BYE, std_handler_bye, 1 },
{ "AUTH", ASSUAN_CMD_AUTH, std_handler_auth, 1 },
{ "RESET", ASSUAN_CMD_RESET, std_handler_reset, 1 },
{ "END", ASSUAN_CMD_END, std_handler_end, 1 },
{ "INPUT", ASSUAN_CMD_INPUT, std_handler_input },
{ "OUTPUT", ASSUAN_CMD_OUTPUT, std_handler_output },
{ "OPTION", ASSUAN_CMD_OPTION, std_handler_option, 1 },
{ NULL }
};
/**
* assuan_register_command:
* @ctx: the server context
* @cmd_id: An ID value for the command
* @cmd_name: A string with the command name
* @handler: The handler function to be called
*
* Register a handler to be used for a given command.
*
* The @cmd_name must be %NULL or an empty string for all @cmd_ids
* below %ASSUAN_CMD_USER because predefined values are used.
*
* Return value:
**/
int
assuan_register_command (ASSUAN_CONTEXT ctx,
int cmd_id, const char *cmd_name,
int (*handler)(ASSUAN_CONTEXT, char *))
{
int i;
if (cmd_name && !*cmd_name)
cmd_name = NULL;
if (cmd_id < ASSUAN_CMD_USER)
{
if (cmd_name)
return ASSUAN_Invalid_Value; /* must be NULL for these values*/
for (i=0; std_cmd_table[i].name; i++)
{
if (std_cmd_table[i].cmd_id == cmd_id)
{
cmd_name = std_cmd_table[i].name;
if (!handler)
handler = std_cmd_table[i].handler;
break;
}
}
if (!std_cmd_table[i].name)
return ASSUAN_Invalid_Value; /* not a pre-registered one */
}
if (!handler)
handler = dummy_handler;
if (!cmd_name)
return ASSUAN_Invalid_Value;
/* fprintf (stderr, "DBG-assuan: registering %d as `%s'\n", cmd_id, cmd_name); */
if (!ctx->cmdtbl)
{
ctx->cmdtbl_size = 50;
ctx->cmdtbl = xtrycalloc ( ctx->cmdtbl_size, sizeof *ctx->cmdtbl);
if (!ctx->cmdtbl)
return ASSUAN_Out_Of_Core;
ctx->cmdtbl_used = 0;
}
else if (ctx->cmdtbl_used >= ctx->cmdtbl_size)
{
struct cmdtbl_s *x;
x = xtryrealloc ( ctx->cmdtbl, (ctx->cmdtbl_size+10) * sizeof *x);
if (!x)
return ASSUAN_Out_Of_Core;
ctx->cmdtbl = x;
ctx->cmdtbl_size += 50;
}
ctx->cmdtbl[ctx->cmdtbl_used].name = cmd_name;
ctx->cmdtbl[ctx->cmdtbl_used].cmd_id = cmd_id;
ctx->cmdtbl[ctx->cmdtbl_used].handler = handler;
ctx->cmdtbl_used++;
return 0;
}
int
assuan_register_bye_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
{
if (!ctx)
return ASSUAN_Invalid_Value;
ctx->bye_notify_fnc = fnc;
return 0;
}
int
assuan_register_reset_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
{
if (!ctx)
return ASSUAN_Invalid_Value;
ctx->reset_notify_fnc = fnc;
return 0;
}
int
assuan_register_cancel_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
{
if (!ctx)
return ASSUAN_Invalid_Value;
ctx->cancel_notify_fnc = fnc;
return 0;
}
int
assuan_register_option_handler (ASSUAN_CONTEXT ctx,
int (*fnc)(ASSUAN_CONTEXT,
const char*, const char*))
{
if (!ctx)
return ASSUAN_Invalid_Value;
ctx->option_handler_fnc = fnc;
return 0;
}
int
assuan_register_input_notify (ASSUAN_CONTEXT ctx,
void (*fnc)(ASSUAN_CONTEXT, const char *))
{
if (!ctx)
return ASSUAN_Invalid_Value;
ctx->input_notify_fnc = fnc;
return 0;
}
int
assuan_register_output_notify (ASSUAN_CONTEXT ctx,
void (*fnc)(ASSUAN_CONTEXT, const char *))
{
if (!ctx)
return ASSUAN_Invalid_Value;
ctx->output_notify_fnc = fnc;
return 0;
}
/* Helper to register the standards commands */
int
_assuan_register_std_commands (ASSUAN_CONTEXT ctx)
{
int i, rc;
for (i=0; std_cmd_table[i].name; i++)
{
if (std_cmd_table[i].always)
{
rc = assuan_register_command (ctx, std_cmd_table[i].cmd_id,
NULL, NULL);
if (rc)
return rc;
}
}
return 0;
}
/* Process the special data lines. The "D " has already been removed
from the line. As all handlers this function may modify the line. */
static int
handle_data_line (ASSUAN_CONTEXT ctx, char *line, int linelen)
{
return set_error (ctx, Not_Implemented, NULL);
}
/* like ascii_strcasecmp but assume that B is already uppercase */
static int
my_strcasecmp (const char *a, const char *b)
{
if (a == b)
return 0;
for (; *a && *b; a++, b++)
{
if (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) != *b)
break;
}
return *a == *b? 0 : (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) - *b);
}
/* Parse the line, break out the command, find it in the command
table, remove leading and white spaces from the arguments, all the
handler with the argument line and return the error */
static int
dispatch_command (ASSUAN_CONTEXT ctx, char *line, int linelen)
{
char *p;
const char *s;
int shift, i;
if (*line == 'D' && line[1] == ' ') /* divert to special handler */
return handle_data_line (ctx, line+2, linelen-2);
for (p=line; *p && *p != ' ' && *p != '\t'; p++)
;
if (p==line)
return set_error (ctx, Invalid_Command, "leading white-space");
if (*p)
{ /* Skip over leading WS after the keyword */
*p++ = 0;
while ( *p == ' ' || *p == '\t')
p++;
}
shift = p - line;
for (i=0; (s=ctx->cmdtbl[i].name); i++)
{
if (!strcmp (line, s))
break;
}
if (!s)
{ /* and try case insensitive */
for (i=0; (s=ctx->cmdtbl[i].name); i++)
{
if (!my_strcasecmp (line, s))
break;
}
}
if (!s)
return set_error (ctx, Unknown_Command, NULL);
line += shift;
linelen -= shift;
/* fprintf (stderr, "DBG-assuan: processing %s `%s'\n", s, line); */
return ctx->cmdtbl[i].handler (ctx, line);
}
static int
process_request (ASSUAN_CONTEXT ctx)
{
int rc;
if (ctx->in_inquire)
return ASSUAN_Nested_Commands;
rc = _assuan_read_line (ctx);
if (rc)
return rc;
if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
return 0; /* comment line - ignore */
ctx->outbound.data.error = 0;
ctx->outbound.data.linelen = 0;
/* dispatch command and return reply */
rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);
/* check from data write errors */
if (ctx->outbound.data.fp)
{ /* Flush the data lines */
fclose (ctx->outbound.data.fp);
ctx->outbound.data.fp = NULL;
if (!rc && ctx->outbound.data.error)
rc = ctx->outbound.data.error;
}
else /* flush any data send w/o using the data fp */
{
assuan_send_data (ctx, NULL, 0);
if (!rc && ctx->outbound.data.error)
rc = ctx->outbound.data.error;
}
/* Error handling */
if (!rc)
{
rc = assuan_write_line (ctx, ctx->okay_line? ctx->okay_line : "OK");
}
else if (rc == -1)
{ /* No error checking because the peer may have already disconnect */
assuan_write_line (ctx, "OK closing connection");
ctx->finish_handler (ctx);
}
else
{
char errline[256];
if (rc < 100)
sprintf (errline, "ERR %d server fault (%.50s)",
ASSUAN_Server_Fault, assuan_strerror (rc));
else
{
const char *text = ctx->err_no == rc? ctx->err_str:NULL;
sprintf (errline, "ERR %d %.50s%s%.100s",
rc, assuan_strerror (rc), text? " - ":"", text?text:"");
}
rc = assuan_write_line (ctx, errline);
}
ctx->confidential = 0;
if (ctx->okay_line)
{
xfree (ctx->okay_line);
ctx->okay_line = NULL;
}
return rc;
}
/**
* assuan_process:
* @ctx: assuan context
*
* This fucntion is used to handle the assuan protocol after a
* connection has been established using assuan_accept(). This is the
* main protocol handler.
*
* Return value: 0 on success or an error code if the assuan operation
* failed. Note, that no error is returned for operational errors.
**/
int
assuan_process (ASSUAN_CONTEXT ctx)
{
int rc;
do {
rc = process_request (ctx);
} while (!rc);
if (rc == -1)
rc = 0;
return rc;
}
/**
* assuan_process_next:
* @ctx: Assuan context
*
* Same as assuan_process() but the user has to provide the outer
* loop. He should loop as long as the return code is zero and stop
* otherwise; -1 is regular end.
*
* See also: assuan_get_active_fds()
* Return value: -1 for end of server, 0 on success or an error code
**/
int
assuan_process_next (ASSUAN_CONTEXT ctx)
{
return process_request (ctx);
}
/**
* assuan_get_active_fds:
* @ctx: Assuan context
* @what: 0 for read fds, 1 for write fds
* @fdarray: Caller supplied array to store the FDs
* @fdarraysize: size of that array
*
* Return all active filedescriptors for the given context. This
* function can be used to select on the fds and call
* assuan_process_next() if there is an active one. The first fd in
* the array is the one used for the command connection.
*
* Note, that write FDs are not yet supported.
*
* Return value: number of FDs active and put into @fdarray or -1 on
* error which is most likely a too small fdarray.
**/
int
assuan_get_active_fds (ASSUAN_CONTEXT ctx, int what,
int *fdarray, int fdarraysize)
{
int n = 0;
if (!ctx || fdarraysize < 2 || what < 0 || what > 1)
return -1;
if (!what)
{
if (ctx->inbound.fd != -1)
fdarray[n++] = ctx->inbound.fd;
}
else
{
if (ctx->outbound.fd != -1)
fdarray[n++] = ctx->outbound.fd;
if (ctx->outbound.data.fp)
fdarray[n++] = fileno (ctx->outbound.data.fp);
}
return n;
}
/* Return a FP to be used for data output. The FILE pointer is valid
until the end of a handler. So a close is not needed. Assuan does
all the buffering needed to insert the status line as well as the
required line wappping and quoting for data lines.
We use GNU's custom streams here. There should be an alternative
implementaion for systems w/o a glibc, a simple implementation
could use a child process */
FILE *
assuan_get_data_fp (ASSUAN_CONTEXT ctx)
{
cookie_io_functions_t cookie_fnc;
if (ctx->outbound.data.fp)
return ctx->outbound.data.fp;
cookie_fnc.read = NULL;
cookie_fnc.write = _assuan_cookie_write_data;
cookie_fnc.seek = NULL;
cookie_fnc.close = _assuan_cookie_write_flush;
ctx->outbound.data.fp = fopencookie (ctx, "wb", cookie_fnc);
ctx->outbound.data.error = 0;
return ctx->outbound.data.fp;
}
/* Set the text used for the next OK reponse. This string is
automatically reset to NULL after the next command. */
AssuanError
assuan_set_okay_line (ASSUAN_CONTEXT ctx, const char *line)
{
if (!ctx)
return ASSUAN_Invalid_Value;
if (!line)
{
xfree (ctx->okay_line);
ctx->okay_line = NULL;
}
else
{
/* FIXME: we need to use gcry_is_secure() to test whether
we should allocate the entire line in secure memory */
char *buf = xtrymalloc (3+strlen(line)+1);
if (!buf)
return ASSUAN_Out_Of_Core;
strcpy (buf, "OK ");
strcpy (buf+3, line);
xfree (ctx->okay_line);
ctx->okay_line = buf;
}
return 0;
}
void
assuan_write_status (ASSUAN_CONTEXT ctx, const char *keyword, const char *text)
{
char buffer[256];
char *helpbuf;
size_t n;
if ( !ctx || !keyword)
return;
if (!text)
text = "";
n = 2 + strlen (keyword) + 1 + strlen (text) + 1;
if (n < sizeof (buffer))
{
strcpy (buffer, "S ");
strcat (buffer, keyword);
if (*text)
{
strcat (buffer, " ");
strcat (buffer, text);
}
assuan_write_line (ctx, buffer);
}
else if ( (helpbuf = xtrymalloc (n)) )
{
strcpy (helpbuf, "S ");
strcat (helpbuf, keyword);
if (*text)
{
strcat (helpbuf, " ");
strcat (helpbuf, text);
}
assuan_write_line (ctx, helpbuf);
xfree (helpbuf);
}
}

View File

@ -1,239 +0,0 @@
/* assuan-inquire.c - handle inquire stuff
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "assuan-defs.h"
#define digitp(a) ((a) >= '0' && (a) <= '9')
#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
*(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
struct membuf {
size_t len;
size_t size;
char *buf;
int out_of_core;
int too_large;
size_t maxlen;
};
/* A simple implemnation of a dynamic buffer. Use init_membuf() to
create a buffer, put_membuf to append bytes and get_membuf to
release and return the buffer. Allocation errors are detected but
only returned at the final get_membuf(), this helps not to clutter
the code with out of core checks. */
static void
init_membuf (struct membuf *mb, int initiallen, size_t maxlen)
{
mb->len = 0;
mb->size = initiallen;
mb->out_of_core = 0;
mb->too_large = 0;
mb->maxlen = maxlen;
/* we need to allocate one byte more for get_membuf */
mb->buf = xtrymalloc (initiallen+1);
if (!mb->buf)
mb->out_of_core = 1;
}
static void
put_membuf (struct membuf *mb, const void *buf, size_t len)
{
if (mb->out_of_core || mb->too_large)
return;
if (mb->maxlen && mb->len + len > mb->maxlen)
{
mb->too_large = 1;
return;
}
if (mb->len + len >= mb->size)
{
char *p;
mb->size += len + 1024;
/* we need to allocate one byte more for get_membuf */
p = xtryrealloc (mb->buf, mb->size+1);
if (!p)
{
mb->out_of_core = 1;
return;
}
mb->buf = p;
}
memcpy (mb->buf + mb->len, buf, len);
mb->len += len;
}
static void *
get_membuf (struct membuf *mb, size_t *len)
{
char *p;
if (mb->out_of_core || mb->too_large)
{
xfree (mb->buf);
mb->buf = NULL;
return NULL;
}
mb->buf[mb->len] = 0; /* there is enough space for the hidden eos */
p = mb->buf;
*len = mb->len;
mb->buf = NULL;
mb->out_of_core = 1; /* don't allow a reuse */
return p;
}
static void
free_membuf (struct membuf *mb)
{
xfree (mb->buf);
mb->buf = NULL;
}
/**
* assuan_inquire:
* @ctx: An assuan context
* @keyword: The keyword used for the inquire
* @r_buffer: Returns an allocated buffer
* @r_length: Returns the length of this buffer
* @maxlen: If not 0, the size limit of the inquired data.
*
* A Server may use this to Send an inquire. r_buffer, r_length and
* maxlen may all be NULL/0 to indicate that no real data is expected.
*
* Return value: 0 on success or an ASSUAN error code
**/
AssuanError
assuan_inquire (ASSUAN_CONTEXT ctx, const char *keyword,
char **r_buffer, size_t *r_length, size_t maxlen)
{
AssuanError rc;
struct membuf mb;
char cmdbuf[100];
unsigned char *line, *p;
int linelen;
int nodataexpected;
if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf)))
return ASSUAN_Invalid_Value;
nodataexpected = !r_buffer && !r_length && !maxlen;
if (!nodataexpected && (!r_buffer || !r_length))
return ASSUAN_Invalid_Value;
if (!ctx->is_server)
return ASSUAN_Not_A_Server;
if (ctx->in_inquire)
return ASSUAN_Nested_Commands;
ctx->in_inquire = 1;
if (nodataexpected)
memset (&mb, 0, sizeof mb); /* avoid compiler warnings */
else
init_membuf (&mb, maxlen? maxlen:1024, maxlen);
strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword);
rc = assuan_write_line (ctx, cmdbuf);
if (rc)
goto leave;
for (;;)
{
do
{
rc = _assuan_read_line (ctx);
if (rc)
goto leave;
line = ctx->inbound.line;
linelen = ctx->inbound.linelen;
}
while (*line == '#' || !linelen);
if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
&& (!line[3] || line[3] == ' '))
break; /* END command received*/
if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N')
{
rc = ASSUAN_Canceled;
goto leave;
}
if (line[0] != 'D' || line[1] != ' ' || nodataexpected)
{
rc = ASSUAN_Unexpected_Command;
goto leave;
}
if (linelen < 3)
continue;
line += 2;
linelen -= 2;
p = line;
while (linelen)
{
for (;linelen && *p != '%'; linelen--, p++)
;
put_membuf (&mb, line, p-line);
if (linelen > 2)
{ /* handle escaping */
unsigned char tmp[1];
p++;
*tmp = xtoi_2 (p);
p += 2;
linelen -= 3;
put_membuf (&mb, tmp, 1);
}
line = p;
}
if (mb.too_large)
{
rc = ASSUAN_Too_Much_Data;
goto leave;
}
}
if (!nodataexpected)
{
*r_buffer = get_membuf (&mb, r_length);
if (!*r_buffer)
rc = ASSUAN_Out_Of_Core;
}
leave:
if (!nodataexpected)
free_membuf (&mb);
ctx->in_inquire = 0;
return rc;
}

View File

@ -1,132 +0,0 @@
/* assuan-listen.c - Wait for a connection (server)
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "assuan-defs.h"
AssuanError
assuan_set_hello_line (ASSUAN_CONTEXT ctx, const char *line)
{
if (!ctx)
return ASSUAN_Invalid_Value;
if (!line)
{
xfree (ctx->hello_line);
ctx->hello_line = NULL;
}
else
{
char *buf = xtrymalloc (3+strlen(line)+1);
if (!buf)
return ASSUAN_Out_Of_Core;
strcpy (buf, "OK ");
strcpy (buf+3, line);
xfree (ctx->hello_line);
ctx->hello_line = buf;
}
return 0;
}
/**
* assuan_accept:
* @ctx: context
*
* Cancel any existing connectiion and wait for a connection from a
* client. The initial handshake is performed which may include an
* initial authentication or encryption negotiation.
*
* Return value: 0 on success or an error if the connection could for
* some reason not be established.
**/
AssuanError
assuan_accept (ASSUAN_CONTEXT ctx)
{
int rc;
if (!ctx)
return ASSUAN_Invalid_Value;
if (ctx->pipe_mode > 1)
return -1; /* second invocation for pipemode -> terminate */
ctx->finish_handler (ctx);
rc = ctx->accept_handler (ctx);
if (rc)
return rc;
/* send the hello */
rc = assuan_write_line (ctx, ctx->hello_line? ctx->hello_line
: "OK Your orders please");
if (rc)
return rc;
if (ctx->pipe_mode)
ctx->pipe_mode = 2;
return 0;
}
int
assuan_get_input_fd (ASSUAN_CONTEXT ctx)
{
return ctx? ctx->input_fd : -1;
}
int
assuan_get_output_fd (ASSUAN_CONTEXT ctx)
{
return ctx? ctx->output_fd : -1;
}
/* Close the fd descriptor set by the command INPUT FD=n. We handle
this fd inside assuan so that we can do some initial checks */
AssuanError
assuan_close_input_fd (ASSUAN_CONTEXT ctx)
{
if (!ctx || ctx->input_fd == -1)
return ASSUAN_Invalid_Value;
close (ctx->input_fd);
ctx->input_fd = -1;
return 0;
}
/* Close the fd descriptor set by the command OUTPUT FD=n. We handle
this fd inside assuan so that we can do some initial checks */
AssuanError
assuan_close_output_fd (ASSUAN_CONTEXT ctx)
{
if (!ctx || ctx->output_fd == -1)
return ASSUAN_Invalid_Value;
close (ctx->output_fd);
ctx->output_fd = -1;
return 0;
}

View File

@ -1,288 +0,0 @@
/* assuan-pipe-connect.c - Establish a pipe connection (client)
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "assuan-defs.h"
#ifdef _POSIX_OPEN_MAX
#define MAX_OPEN_FDS _POSIX_OPEN_MAX
#else
#define MAX_OPEN_FDS 20
#endif
#ifdef HAVE_JNLIB_LOGGING
#include "../jnlib/logging.h"
#define LOGERROR1(a,b) log_error ((a), (b))
#else
#define LOGERROR1(a,b) fprintf (stderr, (a), (b))
#endif
static int
writen ( int fd, const char *buffer, size_t length )
{
while (length)
{
int nwritten = write (fd, buffer, length);
if (nwritten < 0)
{
if (errno == EINTR)
continue;
return -1; /* write error */
}
length -= nwritten;
buffer += nwritten;
}
return 0; /* okay */
}
static int
do_finish (ASSUAN_CONTEXT ctx)
{
if (ctx->inbound.fd != -1)
{
close (ctx->inbound.fd);
ctx->inbound.fd = -1;
}
if (ctx->outbound.fd != -1)
{
close (ctx->outbound.fd);
ctx->outbound.fd = -1;
}
if (ctx->pid != -1)
{
waitpid (ctx->pid, NULL, 0); /* FIXME Check return value. */
ctx->pid = -1;
}
return 0;
}
static void
do_deinit (ASSUAN_CONTEXT ctx)
{
do_finish (ctx);
}
/* Connect to a server over a pipe, creating the assuan context and
returning it in CTX. The server filename is NAME, the argument
vector in ARGV. FD_CHILD_LIST is a -1 terminated list of file
descriptors not to close in the child. */
AssuanError
assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name, char *const argv[],
int *fd_child_list)
{
static int fixed_signals = 0;
AssuanError err;
int rp[2];
int wp[2];
if (!ctx || !name || !argv || !argv[0])
return ASSUAN_Invalid_Value;
if (!fixed_signals)
{
struct sigaction act;
sigaction (SIGPIPE, NULL, &act);
if (act.sa_handler == SIG_DFL)
{
act.sa_handler = SIG_IGN;
sigemptyset (&act.sa_mask);
act.sa_flags = 0;
sigaction (SIGPIPE, &act, NULL);
}
fixed_signals = 1;
/* FIXME: This is not MT safe */
}
if (pipe (rp) < 0)
return ASSUAN_General_Error;
if (pipe (wp) < 0)
{
close (rp[0]);
close (rp[1]);
return ASSUAN_General_Error;
}
err = _assuan_new_context (ctx);
if (err)
{
close (rp[0]);
close (rp[1]);
close (wp[0]);
close (wp[1]);
return err;
}
(*ctx)->pipe_mode = 1;
(*ctx)->inbound.fd = rp[0]; /* Our inbound is read end of read pipe. */
(*ctx)->outbound.fd = wp[1]; /* Our outbound is write end of write pipe. */
(*ctx)->deinit_handler = do_deinit;
(*ctx)->finish_handler = do_finish;
(*ctx)->pid = fork ();
if ((*ctx)->pid < 0)
{
close (rp[0]);
close (rp[1]);
close (wp[0]);
close (wp[1]);
_assuan_release_context (*ctx);
return ASSUAN_General_Error;
}
if ((*ctx)->pid == 0)
{
int i, n;
char errbuf[512];
int *fdp;
/* Close all files which will not be duped and are not in the
fd_child_list. */
n = sysconf (_SC_OPEN_MAX);
if (n < 0)
n = MAX_OPEN_FDS;
for (i=0; i < n; i++)
{
fdp = fd_child_list;
if (fdp)
{
while (*fdp != -1 && *fdp != i)
fdp++;
}
if (!(fdp && *fdp != -1)
&& i != rp[1] && i != wp[0])
close(i);
}
errno = 0;
/* Dup stderr to /dev/null unless it is in the list of FDs to be
passed to the child. */
fdp = fd_child_list;
if (fdp)
{
for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
;
}
if (!fdp || *fdp == -1)
{
int fd = open ("/dev/null", O_WRONLY);
if (fd == -1)
{
LOGERROR1 ("can't open `/dev/null': %s\n", strerror (errno));
_exit (4);
}
if (dup2 (fd, STDERR_FILENO) == -1)
{
LOGERROR1 ("dup2(dev/null, 2) failed: %s\n", strerror (errno));
_exit (4);
}
close (fd);
}
/* Dup handles and to stdin/stdout and exec. */
if (rp[1] != STDOUT_FILENO)
{
if (dup2 (rp[1], STDOUT_FILENO) == -1)
{
LOGERROR1 ("dup2 failed in child: %s\n", strerror (errno));
_exit (4);
}
close (rp[1]);
}
if (wp[0] != STDIN_FILENO)
{
if (dup2 (wp[0], STDIN_FILENO) == -1)
{
LOGERROR1 ("dup2 failed in child: %s\n", strerror (errno));
_exit (4);
}
close (wp[0]);
}
execv (name, argv);
/* oops - use the pipe to tell the parent about it */
snprintf (errbuf, sizeof(errbuf)-1, "ERR %d can't exec `%s': %.50s\n",
ASSUAN_Problem_Starting_Server, name, strerror (errno));
errbuf[sizeof(errbuf)-1] = 0;
writen (1, errbuf, strlen (errbuf));
_exit (4);
}
close (rp[1]);
close (wp[0]);
/* initial handshake */
{
int okay, off;
err = _assuan_read_from_server (*ctx, &okay, &off);
if (err)
{
LOGERROR1 ("can't connect server: %s\n", assuan_strerror (err));
}
else if (okay != 1)
{
LOGERROR1 ("can't connect server: `%s'\n", (*ctx)->inbound.line);
err = ASSUAN_Connect_Failed;
}
}
if (err)
{
assuan_disconnect (*ctx);
*ctx = NULL;
}
return err;
}

View File

@ -1,124 +0,0 @@
/* assuan-pipe-server.c - Assuan server working over a pipe
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include "assuan-defs.h"
static void
deinit_pipe_server (ASSUAN_CONTEXT ctx)
{
/* nothing to do for this simple server */
}
static int
accept_connection (ASSUAN_CONTEXT ctx)
{
/* This is a NOP for a pipe server */
return 0;
}
static int
finish_connection (ASSUAN_CONTEXT ctx)
{
/* This is a NOP for a pipe server */
return 0;
}
/* Create a new context. Note that the handlers are set up for a pipe
server/client - this way we don't need extra dummy functions */
int
_assuan_new_context (ASSUAN_CONTEXT *r_ctx)
{
ASSUAN_CONTEXT ctx;
int rc;
*r_ctx = NULL;
ctx = xtrycalloc (1, sizeof *ctx);
if (!ctx)
return ASSUAN_Out_Of_Core;
ctx->input_fd = -1;
ctx->output_fd = -1;
ctx->inbound.fd = -1;
ctx->outbound.fd = -1;
ctx->listen_fd = -1;
ctx->client_pid = (pid_t)-1;
/* use the pipe server handler as a default */
ctx->deinit_handler = deinit_pipe_server;
ctx->accept_handler = accept_connection;
ctx->finish_handler = finish_connection;
rc = _assuan_register_std_commands (ctx);
if (rc)
xfree (ctx);
else
*r_ctx = ctx;
return rc;
}
int
assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2])
{
int rc;
rc = _assuan_new_context (r_ctx);
if (!rc)
{
ASSUAN_CONTEXT ctx = *r_ctx;
ctx->is_server = 1;
ctx->inbound.fd = filedes[0];
ctx->outbound.fd = filedes[1];
ctx->pipe_mode = 1;
}
return rc;
}
void
_assuan_release_context (ASSUAN_CONTEXT ctx)
{
if (ctx)
{
xfree (ctx->hello_line);
xfree (ctx->okay_line);
xfree (ctx);
}
}
void
assuan_deinit_server (ASSUAN_CONTEXT ctx)
{
if (ctx)
{
/* We use this function pointer to avoid linking other server
when not needed but still allow for a generic deinit function */
ctx->deinit_handler (ctx);
ctx->deinit_handler = NULL;
_assuan_release_context (ctx);
}
}

View File

@ -1,150 +0,0 @@
/* assuan-socket-connect.c - Assuan socket based client
* Copyright (C) 2002 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
#include <config.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include "assuan-defs.h"
#ifdef HAVE_JNLIB_LOGGING
#include "../jnlib/logging.h"
#define LOGERROR(a) log_error ((a))
#define LOGERROR1(a,b) log_error ((a), (b))
#define LOGERROR2(a,b,c) log_error ((a), (b), (c))
#define LOGERRORX(a) log_printf ((a))
#else
#define LOGERROR(a) fprintf (stderr, (a))
#define LOGERROR1(a,b) fprintf (stderr, (a), (b))
#define LOGERROR2(a,b,c) fprintf (stderr, (a), (b), (c))
#define LOGERRORX(a) fputs ((a), stderr)
#endif
static int
do_finish (ASSUAN_CONTEXT ctx)
{
if (ctx->inbound.fd != -1)
{
close (ctx->inbound.fd);
}
ctx->inbound.fd = -1;
ctx->outbound.fd = -1;
return 0;
}
static void
do_deinit (ASSUAN_CONTEXT ctx)
{
do_finish (ctx);
}
/* Make a connection to the Unix domain socket NAME and return a new
Assuan context in CTX. SERVER_PID is currently not used but may
becode handy in future. */
AssuanError
assuan_socket_connect (ASSUAN_CONTEXT *r_ctx,
const char *name, pid_t server_pid)
{
AssuanError err;
ASSUAN_CONTEXT ctx;
int fd;
struct sockaddr_un srvr_addr;
size_t len;
if (!r_ctx || !name)
return ASSUAN_Invalid_Value;
*r_ctx = NULL;
/* we require that the name starts with a slash, so that we can
alter reuse this function for other socket types */
if (*name != '/')
return ASSUAN_Invalid_Value;
if (strlen (name)+1 >= sizeof srvr_addr.sun_path)
return ASSUAN_Invalid_Value;
err = _assuan_new_context (&ctx);
if (err)
return err;
ctx->pid = server_pid; /* save it in case we need it later */
ctx->deinit_handler = do_deinit;
ctx->finish_handler = do_finish;
fd = socket (AF_UNIX, SOCK_STREAM, 0);
if (fd == -1)
{
LOGERROR1 ("can't create socket: %s\n", strerror (errno));
_assuan_release_context (ctx);
return ASSUAN_General_Error;
}
memset (&srvr_addr, 0, sizeof srvr_addr );
srvr_addr.sun_family = AF_UNIX;
strcpy (srvr_addr.sun_path, name);
len = (offsetof (struct sockaddr_un, sun_path)
+ strlen (srvr_addr.sun_path) + 1);
if (connect (fd, (struct sockaddr*)&srvr_addr, len) == -1)
{
LOGERROR2 ("can't connect to `%s': %s\n", name, strerror (errno));
_assuan_release_context (ctx);
close (fd );
return ASSUAN_Connect_Failed;
}
ctx->inbound.fd = fd;
ctx->outbound.fd = fd;
/* initial handshake */
{
int okay, off;
err = _assuan_read_from_server (ctx, &okay, &off);
if (err)
{
LOGERROR1 ("can't connect server: %s\n", assuan_strerror (err));
}
else if (okay != 1)
{
LOGERROR ("can't connect server: `");
_assuan_log_sanitized_string (ctx->inbound.line);
LOGERRORX ("'\n");
err = ASSUAN_Connect_Failed;
}
}
if (err)
{
assuan_disconnect (ctx);
}
else
*r_ctx = ctx;
return 0;
}

View File

@ -1,169 +0,0 @@
/* assuan-socket-server.c - Assuan socket based server
* Copyright (C) 2002 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include "assuan-defs.h"
static int
accept_connection_bottom (ASSUAN_CONTEXT ctx)
{
int fd = ctx->connected_fd;
ctx->client_pid = (pid_t)-1;
#ifdef HAVE_SO_PEERCRED
{
struct ucred cr;
int cl = sizeof cr;
if ( !getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl) )
ctx->client_pid = cr.pid;
}
#endif
ctx->inbound.fd = fd;
ctx->inbound.eof = 0;
ctx->inbound.linelen = 0;
ctx->inbound.attic.linelen = 0;
ctx->inbound.attic.pending = 0;
ctx->outbound.fd = fd;
ctx->outbound.data.linelen = 0;
ctx->outbound.data.error = 0;
ctx->confidential = 0;
return 0;
}
static int
accept_connection (ASSUAN_CONTEXT ctx)
{
int fd;
struct sockaddr_un clnt_addr;
size_t len = sizeof clnt_addr;
ctx->client_pid = (pid_t)-1;
fd = accept (ctx->listen_fd, (struct sockaddr*)&clnt_addr, &len );
if (fd == -1)
{
ctx->os_errno = errno;
return ASSUAN_Accept_Failed;
}
ctx->connected_fd = fd;
return accept_connection_bottom (ctx);
}
static int
finish_connection (ASSUAN_CONTEXT ctx)
{
if (ctx->inbound.fd != -1)
{
close (ctx->inbound.fd);
}
ctx->inbound.fd = -1;
ctx->outbound.fd = -1;
return 0;
}
static void
deinit_socket_server (ASSUAN_CONTEXT ctx)
{
finish_connection (ctx);
}
/* Initialize a server for the socket LISTEN_FD which has already be
put into listen mode */
int
assuan_init_socket_server (ASSUAN_CONTEXT *r_ctx, int listen_fd)
{
ASSUAN_CONTEXT ctx;
int rc;
*r_ctx = NULL;
ctx = xtrycalloc (1, sizeof *ctx);
if (!ctx)
return ASSUAN_Out_Of_Core;
ctx->is_server = 1;
ctx->input_fd = -1;
ctx->output_fd = -1;
ctx->inbound.fd = -1;
ctx->outbound.fd = -1;
ctx->listen_fd = listen_fd;
ctx->connected_fd = -1;
ctx->deinit_handler = deinit_socket_server;
ctx->accept_handler = accept_connection;
ctx->finish_handler = finish_connection;
rc = _assuan_register_std_commands (ctx);
if (rc)
xfree (ctx);
else
*r_ctx = ctx;
return rc;
}
/* Initialize a server using the already accepted socket FD. */
int
assuan_init_connected_socket_server (ASSUAN_CONTEXT *r_ctx, int fd)
{
ASSUAN_CONTEXT ctx;
int rc;
*r_ctx = NULL;
ctx = xtrycalloc (1, sizeof *ctx);
if (!ctx)
return ASSUAN_Out_Of_Core;
ctx->is_server = 1;
ctx->pipe_mode = 1; /* we wan't a second accept to indicate EOF */
ctx->input_fd = -1;
ctx->output_fd = -1;
ctx->inbound.fd = -1;
ctx->outbound.fd = -1;
ctx->listen_fd = -1;
ctx->connected_fd = fd;
ctx->deinit_handler = deinit_socket_server;
ctx->accept_handler = accept_connection_bottom;
ctx->finish_handler = finish_connection;
rc = _assuan_register_std_commands (ctx);
if (rc)
xfree (ctx);
else
*r_ctx = ctx;
return rc;
}

View File

@ -1,210 +0,0 @@
/* assuan-util.c - Utility functions for Assuan
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "assuan-defs.h"
#ifdef HAVE_JNLIB_LOGGING
#include "../jnlib/logging.h"
#endif
ssize_t (*_assuan_read_wrapper)(int,void*,size_t) = NULL;
ssize_t (*_assuan_write_wrapper)(int,const void*,size_t) = NULL;
static void *(*alloc_func)(size_t n) = malloc;
static void *(*realloc_func)(void *p, size_t n) = realloc;
static void (*free_func)(void*) = free;
void
assuan_set_malloc_hooks ( void *(*new_alloc_func)(size_t n),
void *(*new_realloc_func)(void *p, size_t n),
void (*new_free_func)(void*) )
{
alloc_func = new_alloc_func;
realloc_func = new_realloc_func;
free_func = new_free_func;
}
void *
_assuan_malloc (size_t n)
{
return alloc_func (n);
}
void *
_assuan_realloc (void *a, size_t n)
{
return realloc_func (a, n);
}
void *
_assuan_calloc (size_t n, size_t m)
{
void *p = _assuan_malloc (n*m);
if (p)
memset (p, 0, n* m);
return p;
}
void
_assuan_free (void *p)
{
if (p)
free_func (p);
}
/* For use with Pth it is required to have special read and write
functions. We can't assume an ELF based system so we have to
explicitly set them if we are going to use Pth. */
void
assuan_set_io_func (ssize_t (*r)(int,void*,size_t),
ssize_t (*w)(int,const void*,size_t))
{
_assuan_read_wrapper = r;
_assuan_write_wrapper = w;
}
/* Store the error in the context so that the error sending function
can take out a descriptive text. Inside the assuan code, use the
macro set_error instead of this function. */
int
assuan_set_error (ASSUAN_CONTEXT ctx, int err, const char *text)
{
ctx->err_no = err;
ctx->err_str = text;
return err;
}
void
assuan_set_pointer (ASSUAN_CONTEXT ctx, void *pointer)
{
if (ctx)
ctx->user_pointer = pointer;
}
void *
assuan_get_pointer (ASSUAN_CONTEXT ctx)
{
return ctx? ctx->user_pointer : NULL;
}
void
assuan_set_log_stream (ASSUAN_CONTEXT ctx, FILE *fp)
{
if (ctx)
{
if (ctx->log_fp)
fflush (ctx->log_fp);
ctx->log_fp = fp;
}
}
void
assuan_begin_confidential (ASSUAN_CONTEXT ctx)
{
if (ctx)
{
ctx->confidential = 1;
}
}
void
assuan_end_confidential (ASSUAN_CONTEXT ctx)
{
if (ctx)
{
ctx->confidential = 0;
}
}
void
_assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length)
{
const unsigned char *s;
int n;
for (n=length,s=buffer; n; n--, s++)
{
if (*s < ' ' || (*s >= 0x7f && *s <= 0xa0))
break;
}
s = buffer;
if (!n && *s != '[')
fwrite (buffer, length, 1, fp);
else
{
putc ('[', fp);
for (n=0; n < length; n++, s++)
fprintf (fp, " %02x", *s);
putc (' ', fp);
putc (']', fp);
}
}
/* print a user supplied string after filtering out potential bad
characters*/
void
_assuan_log_sanitized_string (const char *string)
{
const unsigned char *s = string;
#ifdef HAVE_JNLIB_LOGGING
FILE *fp = log_get_stream ();
#else
FILE *fp = stderr;
#endif
for (; *s; s++)
{
if (*s < 0x20 || (*s >= 0x7f && *s <= 0xa0))
{
putc ('\\', fp);
if (*s == '\n')
putc ('n', fp);
else if (*s == '\r')
putc ('r', fp);
else if (*s == '\f')
putc ('f', fp);
else if (*s == '\v')
putc ('v', fp);
else if (*s == '\b')
putc ('b', fp);
else if (!*s)
putc ('0', fp);
else
fprintf (fp, "x%02x", *s );
}
else
putc (*s, fp);
}
}

View File

@ -1,234 +0,0 @@
/* assuan.c - Definitions for the Assuan protocol
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
#ifndef ASSUAN_H
#define ASSUAN_H
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h> /* for ssize_t */
#ifdef __cplusplus
extern "C" {
#if 0
}
#endif
#endif
typedef enum {
ASSUAN_No_Error = 0,
ASSUAN_General_Error = 1,
ASSUAN_Out_Of_Core = 2,
ASSUAN_Invalid_Value = 3,
ASSUAN_Timeout = 4,
ASSUAN_Read_Error = 5,
ASSUAN_Write_Error = 6,
ASSUAN_Problem_Starting_Server = 7,
ASSUAN_Not_A_Server = 8,
ASSUAN_Not_A_Client = 9,
ASSUAN_Nested_Commands = 10,
ASSUAN_Invalid_Response = 11,
ASSUAN_No_Data_Callback = 12,
ASSUAN_No_Inquire_Callback = 13,
ASSUAN_Connect_Failed = 14,
ASSUAN_Accept_Failed = 15,
/* error codes above 99 are meant as status codes */
ASSUAN_Not_Implemented = 100,
ASSUAN_Server_Fault = 101,
ASSUAN_Invalid_Command = 102,
ASSUAN_Unknown_Command = 103,
ASSUAN_Syntax_Error = 104,
ASSUAN_Parameter_Error = 105,
ASSUAN_Parameter_Conflict = 106,
ASSUAN_Line_Too_Long = 107,
ASSUAN_Line_Not_Terminated = 108,
ASSUAN_No_Input = 109,
ASSUAN_No_Output = 110,
ASSUAN_Canceled = 111,
ASSUAN_Unsupported_Algorithm = 112,
ASSUAN_Server_Resource_Problem = 113,
ASSUAN_Server_IO_Error = 114,
ASSUAN_Server_Bug = 115,
ASSUAN_No_Data_Available = 116,
ASSUAN_Invalid_Data = 117,
ASSUAN_Unexpected_Command = 118,
ASSUAN_Too_Much_Data = 119,
ASSUAN_Inquire_Unknown = 120,
ASSUAN_Inquire_Error = 121,
ASSUAN_Invalid_Option = 122,
ASSUAN_Invalid_Index = 123,
ASSUAN_Unexpected_Status = 124,
ASSUAN_Unexpected_Data = 125,
ASSUAN_Invalid_Status = 126,
ASSUAN_Not_Confirmed = 128,
ASSUAN_Bad_Certificate = 201,
ASSUAN_Bad_Certificate_Chain = 202,
ASSUAN_Missing_Certificate = 203,
ASSUAN_Bad_Signature = 204,
ASSUAN_No_Agent = 205,
ASSUAN_Agent_Error = 206,
ASSUAN_No_Public_Key = 207,
ASSUAN_No_Secret_Key = 208,
ASSUAN_Invalid_Name = 209,
ASSUAN_Cert_Revoked = 301,
ASSUAN_No_CRL_For_Cert = 302,
ASSUAN_CRL_Too_Old = 303,
ASSUAN_Not_Trusted = 304,
ASSUAN_Card_Error = 401,
ASSUAN_Invalid_Card = 402,
ASSUAN_No_PKCS15_App = 403,
ASSUAN_Card_Not_Present = 404,
ASSUAN_Invalid_Id = 405
} AssuanError;
/* This is a list of pre-registered ASSUAN commands */
typedef enum {
ASSUAN_CMD_NOP = 0,
ASSUAN_CMD_CANCEL, /* cancel the current request */
ASSUAN_CMD_BYE,
ASSUAN_CMD_AUTH,
ASSUAN_CMD_RESET,
ASSUAN_CMD_OPTION,
ASSUAN_CMD_DATA,
ASSUAN_CMD_END,
ASSUAN_CMD_INPUT,
ASSUAN_CMD_OUTPUT,
ASSUAN_CMD_USER = 256 /* Other commands should be used with this offset*/
} AssuanCommand;
#define ASSUAN_LINELENGTH 1002 /* 1000 + [CR,]LF */
struct assuan_context_s;
typedef struct assuan_context_s *ASSUAN_CONTEXT;
/*-- assuan-handler.c --*/
int assuan_register_command (ASSUAN_CONTEXT ctx,
int cmd_id, const char *cmd_string,
int (*handler)(ASSUAN_CONTEXT, char *));
int assuan_register_bye_notify (ASSUAN_CONTEXT ctx,
void (*fnc)(ASSUAN_CONTEXT));
int assuan_register_reset_notify (ASSUAN_CONTEXT ctx,
void (*fnc)(ASSUAN_CONTEXT));
int assuan_register_cancel_notify (ASSUAN_CONTEXT ctx,
void (*fnc)(ASSUAN_CONTEXT));
int assuan_register_input_notify (ASSUAN_CONTEXT ctx,
void (*fnc)(ASSUAN_CONTEXT, const char *));
int assuan_register_output_notify (ASSUAN_CONTEXT ctx,
void (*fnc)(ASSUAN_CONTEXT, const char *));
int assuan_register_option_handler (ASSUAN_CONTEXT ctx,
int (*fnc)(ASSUAN_CONTEXT,
const char*, const char*));
int assuan_process (ASSUAN_CONTEXT ctx);
int assuan_process_next (ASSUAN_CONTEXT ctx);
int assuan_get_active_fds (ASSUAN_CONTEXT ctx, int what,
int *fdarray, int fdarraysize);
FILE *assuan_get_data_fp (ASSUAN_CONTEXT ctx);
AssuanError assuan_set_okay_line (ASSUAN_CONTEXT ctx, const char *line);
void assuan_write_status (ASSUAN_CONTEXT ctx,
const char *keyword, const char *text);
/*-- assuan-listen.c --*/
AssuanError assuan_set_hello_line (ASSUAN_CONTEXT ctx, const char *line);
AssuanError assuan_accept (ASSUAN_CONTEXT ctx);
int assuan_get_input_fd (ASSUAN_CONTEXT ctx);
int assuan_get_output_fd (ASSUAN_CONTEXT ctx);
AssuanError assuan_close_input_fd (ASSUAN_CONTEXT ctx);
AssuanError assuan_close_output_fd (ASSUAN_CONTEXT ctx);
/*-- assuan-pipe-server.c --*/
int assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2]);
void assuan_deinit_server (ASSUAN_CONTEXT ctx);
/*-- assuan-socket-server.c --*/
int assuan_init_socket_server (ASSUAN_CONTEXT *r_ctx, int listen_fd);
int assuan_init_connected_socket_server (ASSUAN_CONTEXT *r_ctx, int fd);
/*-- assuan-pipe-connect.c --*/
AssuanError assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name,
char *const argv[], int *fd_child_list);
/*-- assuan-socket-connect.c --*/
AssuanError assuan_socket_connect (ASSUAN_CONTEXT *ctx, const char *name,
pid_t server_pid);
/*-- assuan-connect.c --*/
void assuan_disconnect (ASSUAN_CONTEXT ctx);
pid_t assuan_get_pid (ASSUAN_CONTEXT ctx);
/*-- assuan-client.c --*/
AssuanError
assuan_transact (ASSUAN_CONTEXT ctx,
const char *command,
AssuanError (*data_cb)(void *, const void *, size_t),
void *data_cb_arg,
AssuanError (*inquire_cb)(void*, const char *),
void *inquire_cb_arg,
AssuanError (*status_cb)(void*, const char *),
void *status_cb_arg);
/*-- assuan-inquire.c --*/
AssuanError assuan_inquire (ASSUAN_CONTEXT ctx, const char *keyword,
char **r_buffer, size_t *r_length, size_t maxlen);
/*-- assuan-buffer.c --*/
AssuanError assuan_read_line (ASSUAN_CONTEXT ctx,
char **line, size_t *linelen);
int assuan_pending_line (ASSUAN_CONTEXT ctx);
AssuanError assuan_write_line (ASSUAN_CONTEXT ctx, const char *line );
AssuanError assuan_send_data (ASSUAN_CONTEXT ctx,
const void *buffer, size_t length);
/*-- assuan-util.c --*/
void assuan_set_malloc_hooks ( void *(*new_alloc_func)(size_t n),
void *(*new_realloc_func)(void *p, size_t n),
void (*new_free_func)(void*) );
void assuan_set_io_func (ssize_t (*r)(int,void*,size_t),
ssize_t (*w)(int,const void*,size_t));
void assuan_set_log_stream (ASSUAN_CONTEXT ctx, FILE *fp);
int assuan_set_error (ASSUAN_CONTEXT ctx, int err, const char *text);
void assuan_set_pointer (ASSUAN_CONTEXT ctx, void *pointer);
void *assuan_get_pointer (ASSUAN_CONTEXT ctx);
void assuan_begin_confidential (ASSUAN_CONTEXT ctx);
void assuan_end_confidential (ASSUAN_CONTEXT ctx);
/*-- assuan-errors.c (built) --*/
const char *assuan_strerror (AssuanError err);
#ifdef __cplusplus
}
#endif
#endif /*ASSUAN_H*/

View File

@ -1,71 +0,0 @@
#!/bin/sh
# mkerrors - Extract error strings from assuan.h
# and create C source for assuan_strerror
# Copyright (C) 2001, 2002 Free Software Foundation, Inc.
#
# This file is part of Assuan.
#
# Assuan is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of
# the License, or (at your option) any later version.
#
# Assuan 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser 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
cat <<EOF
/* Generated automatically by mkerrors */
/* Do not edit! */
#include <stdio.h>
#include "assuan.h"
/**
* assuan_strerror:
* @err: Error code
*
* This function returns a textual representaion of the given
* errorcode. If this is an unknown value, a string with the value
* is returned (Beware: it is hold in a static buffer).
*
* Return value: String with the error description.
**/
const char *
assuan_strerror (AssuanError err)
{
const char *s;
static char buf[25];
switch (err)
{
EOF
awk '
/ASSUAN_No_Error/ { okay=1 }
!okay {next}
/}/ { exit 0 }
/ASSUAN_[A-Za-z_]*/ { print_code($1) }
function print_code( s )
{
printf " case %s: s=\"", s ;
gsub(/_/, " ", s );
printf "%s\"; break;\n", tolower(substr(s,8));
}
'
cat <<EOF
default: sprintf (buf, "ec=%d", err ); s=buf; break;
}
return s;
}
EOF

View File

@ -1,171 +0,0 @@
2002-05-10 Werner Koch <wk@gnupg.org>
* Makefile.am: Add gpg_dearmor to all targets where it is used.
Noted by Andreas Haumer.
2002-04-19 Werner Koch <wk@gnupg.org>
* signencrypt-dsa.test, sigs-dsa.test: Don't check with MD5 as
this is not valid with DSA signatures.
2001-12-22 Werner Koch <wk@gnupg.org>
* options.in: Add no-permission-warning.
2001-12-21 Werner Koch <wk@gnupg.org>
* Makefile.am (distclean-local): prefix mkdemodirs with srcdir
(DISTCLEANFILES): Add random_seed.
2001-12-19 Werner Koch <wk@gnupg.org>
* options.in: Remove load-extension tiger
* Makefile.am (./options): append it if there is such a module.
2001-10-23 Werner Koch <wk@gnupg.org>
* defs.inc, Makefile.am: Do not use $srcdir when invoking gpg.
Write the logfile to the current directory.
2001-09-28 Werner Koch <wk@gnupg.org>
* defs.inc: Write a log file for each test.
* run-gpg, run-gpgm, run-gpg.patterns: Removed. Replaced in all
tests by a simple macro from defs.inc.
* Makefile.am (CLEANFILES): Remove log files.
(./gpg_dearmor): create it and use it instead of the macro.
This is needed in multisig.test due to IFS tricks.
* armsignencrypt.test, signencrypt-dsa.test, signencrypt.test,
armencryptp.test, armencrypt.test, encryptp.test, seat.test,
encrypt-dsa.test, encrypt.test: Use --always-trust because the
test are not designed to check the validity.
2001-09-06 Werner Koch <wk@gnupg.org>
* genkey1024.test: Simplified by using a parameter file.
2001-05-30 Werner Koch <wk@gnupg.org>
* multisig.test (IFS): Reset IFS just before the test.
2001-04-30 Werner Koch <wk@gnupg.org>
* multisig.test: Add an set +x to avoid ksh problems
2001-04-28 Werner Koch <wk@gnupg.org>
* run-gpg.patterns: a v3 test key expired yesterday, suppress the
messages.
2001-03-27 Werner Koch <wk@gnupg.org>
* defs.inc: Removed creation of options file.
* options.in: New.
* Makefile.am: Create options file and fixed import of pubdemo.asc.
* run-gpg.patterns (gpg): Add some more patterns.
2001-03-20 Werner Koch <wk@gnupg.org>
* Makefile.am: Import the pubdemo.asc file
* sigs.test (hash_algo_list): s/tiger/tiger192/
2001-03-19 Werner Koch <wk@gnupg.org>
* mkdemodirs (GPGDEMO): Add --allow-secret-key-import to all gpg
invocations. Use echon -n instead of an argument with \c.
2001-02-12 Werner Koch <wk@gnupg.org>
* multisig.test: new
* Makefile.am (TESTS): Added.
2000-10-18 Werner Koch <wk@gnupg.org>
* conventional-mdc.test: Add Rijndael and fix for empty plain texts.
Thu Feb 10 17:39:44 CET 2000 Werner Koch <wk@gnupg.de>
* mkdemodirs: Fixed the --clean loop.
Thu Jan 13 19:31:58 CET 2000 Werner Koch <wk@gnupg.de>
* defs.inc (chdir): Removed becuase it is unsused an plain old sh
does not like this name. Reported by Alec Habig.
Tue Oct 26 20:02:23 1999 Werner Koch (wk@gnupg.org)
* Makefile.am (GPG_DEARMOR): New and use --no-options.
Tue Aug 31 17:20:44 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* defs.inc: set LC_ALL empty
Wed Aug 4 10:34:18 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* defs.inc (echo_n): New and used instead of /bin/echo "\c"
Sun Apr 18 10:11:28 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* mkdemodirs: New
* signdemokey: New.
* Makefile.am (distclean-local): New.
Wed Mar 17 13:09:03 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* mds.test: replaced the "echo -n"
Mon Mar 8 20:47:17 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* pubdemo.asc, secdemo.asc: New.
Fri Feb 19 15:49:15 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* genkey1024.test: Be really quiet.
1999-01-01 Geoff Keating <geoffk@ozemail.com.au>
* Makefile.am (CLEANFILES): Also delete trustdb and any leftover
lockfiles.
Fri Nov 27 15:30:24 CET 1998 Werner Koch <wk@isil.d.shuttle.de>
* clearsig.test: Some more test cases.
Sun Oct 25 18:19:35 1998 Werner Koch (wk@isil.d.shuttle.de)
* mds.test: Check whether TIGER is available.
* sigs.tesr: Ditto.
Wed Sep 23 12:25:07 1998 Werner Koch (wk@isil.d.shuttle.de)
* run-gpg.patterns: New (because Solaris fgrep does not like -f -).
Mon Aug 10 21:33:38 1998 Werner Koch (wk@(none))
* genkey1024.test: Ariel fixed this.
Wed Jul 8 10:43:47 1998 Werner Koch (wk@isil.d.shuttle.de)
* seat.test: New.
Mon May 18 15:40:02 1998 Werner Koch (wk@isil.d.shuttle.de)
* Makefile.am: Now uses mk-tdata to produce random test data.
* ChangeLog: New.
Copyright 1998, 1999, 2000, 2001 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
modifications, as long as this notice is preserved.
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.

View File

@ -1,107 +0,0 @@
# Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
# Process this file with automake to create Makefile.in
GPG_IMPORT = ../g10/gpg --homedir . --quiet --yes --import
TESTS = version.test mds.test \
decrypt.test decrypt-dsa.test \
sigs.test sigs-dsa.test \
encrypt.test encrypt-dsa.test \
seat.test clearsig.test encryptp.test detach.test \
armsigs.test armencrypt.test armencryptp.test \
signencrypt.test signencrypt-dsa.test \
armsignencrypt.test armdetach.test \
armdetachm.test detachm.test genkey1024.test \
conventional.test conventional-mdc.test \
multisig.test
TEST_FILES = pubring.asc secring.asc plain-1o.asc plain-2o.asc plain-3o.asc \
plain-1.asc plain-2.asc plain-3.asc plain-1-pgp.asc \
pubring.pkr.asc secring.skr.asc secdemo.asc pubdemo.asc options.in
DATA_FILES = data-500 data-9000 data-32000 data-80000 plain-large
EXTRA_DIST = defs.inc $(TESTS) $(TEST_FILES) \
mkdemodirs signdemokey
CLEANFILES = prepared.stamp x y yy z out err $(DATA_FILES) \
plain-1 plain-2 plain-3 trustdb.gpg *.lock .\#lk* \
*.test.log options gpg_dearmor \
pubring.gpg secring.gpg pubring.pkr secring.skr
DISTCLEANFILES = pubring.gpg~ random_seed
all-local: prepared.stamp
distclean-local:
$(srcdir)/mkdemodirs --clean
prepared.stamp: ./pubring.gpg ./secring.gpg ./plain-1 ./plain-2 ./plain-3 \
./pubring.pkr ./secring.skr ./options ./gpg_dearmor \
$(DATA_FILES)
$(GPG_IMPORT) $(srcdir)/pubdemo.asc
echo timestamp >./prepared.stamp
./options: $(srcdir)/options.in
cat $(srcdir)/options.in >./options
@set -e; if echo "@DYNAMIC_CIPHER_MODS@" |grep tiger >/dev/null ;then \
echo load-extension ../cipher/tiger >>./options; fi
./gpg_dearmor:
echo '#!/bin/sh' >./gpg_dearmor
echo "../g10/gpg --no-options --no-greeting \
--no-secmem-warning --batch --dearmor" >>./gpg_dearmor
chmod 755 ./gpg_dearmor
./pubring.gpg: $(srcdir)/pubring.asc $(srcdir)/pubdemo.asc ./gpg_dearmor
./gpg_dearmor > ./pubring.gpg < $(srcdir)/pubring.asc
./secring.gpg: $(srcdir)/secring.asc ./gpg_dearmor
./gpg_dearmor > ./secring.gpg < $(srcdir)/secring.asc
./pubring.pkr: $(srcdir)/pubring.pkr.asc ./gpg_dearmor
./gpg_dearmor > ./pubring.pkr < $(srcdir)/pubring.pkr.asc
./secring.skr: $(srcdir)/secring.skr.asc ./gpg_dearmor
./gpg_dearmor > ./secring.skr < $(srcdir)/secring.skr.asc
./plain-1: $(srcdir)/plain-1o.asc ./gpg_dearmor
./gpg_dearmor > ./plain-1 < $(srcdir)/plain-1o.asc
./plain-2: $(srcdir)/plain-2o.asc ./gpg_dearmor
./gpg_dearmor > ./plain-2 < $(srcdir)/plain-2o.asc
./plain-3: $(srcdir)/plain-3o.asc ./gpg_dearmor
./gpg_dearmor > ./plain-3 < $(srcdir)/plain-3o.asc
data-500:
../tools/mk-tdata 500 >data-500
data-9000:
../tools/mk-tdata 9000 >data-9000
data-32000:
../tools/mk-tdata 32000 >data-32000
data-80000:
../tools/mk-tdata 80000 >data-80000
plain-large:
cat $(srcdir)/../doc/HACKING \
$(srcdir)/../doc/DETAILS \
$(srcdir)/../doc/FAQ >plain-large

View File

@ -1,11 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
#info Checking armored detached signatures
for i in $plain_files $data_files ; do
echo "$usrpass1" | $GPG --passphrase-fd 0 -sab -o x --yes $i
$GPG -o /dev/null --yes x <$i || error "$i: bad signature"
done

View File

@ -1,9 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
#info Checking armored detached signatures of multiple files
i="$plain_files $data_files"
echo "$usrpass1" | $GPG --passphrase-fd 0 -sab -o x --yes $i
cat $i | $GPG -o /dev/null --yes x || error "$i: bad signature"

View File

@ -1,11 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
#info Checking armored encryption
for i in $plain_files $data_files ; do
$GPG --always-trust -ea -o x --yes -r "$usrname2" $i
$GPG -o y --yes x
cmp $i y || error "$i: mismatch"
done

View File

@ -1,12 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
#info Checking armored encryption with a pipe
for i in $plain_files $data_files ; do
$GPG --always-trust -ea --yes -r "$usrname2" < $i | tee x | $GPG -o y --yes
cmp $i y || error "$i: mismatch"
$GPG --yes < x > y
cmp $i y || error "$i: mismatch"
done

View File

@ -1,13 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
#info Checking armored signing and encryption
for i in $plain_files $data_files ; do
echo "$usrpass1" | $GPG --passphrase-fd 0 --always-trust \
-sae -o x --yes -r "$usrname2" $i
$GPG -o y --yes x
cmp $i y || error "$i: mismatch"
done

View File

@ -1,11 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
#info Checking armored signatures
for i in $plain_files $data_files ; do
echo "$usrpass1" | $GPG --passphrase-fd 0 -sa -o x --yes $i
$GPG -o y --yes x
cmp $i y || error "$i: mismatch"
done

View File

@ -1,42 +0,0 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: RIPEMD160
I promise to delivery 8 bottles of "Füchschen" to the first one who tells me
the plaintext of the following message or is able to forge the signature
on this file. Don't try to get my secret key, it does not exist any longer.
For those who don't know: Füchschen is a beer brewed here in Düsseldorf.
This promise is valid for 2 years from now (29.5.1998).
Good luck,
Werner
- -----BEGIN PGP MESSAGE-----
Version: GNUPG v0.2.19 (GNU/Linux)
Comment: This is an alpha version!
hQEOA+Pk8EXQYMj+FAP/V8XiybbbGVReNAKbknj9nqaHHVOjPdwBXyOBLRBEC5TiMhe/APmq
XN3esJ/MU97eN9lZMVBLIwG4/jqzT/g2ULd3rZtWwgcyV1cDehGVun8cp0CbsM6QH8lhItLo
fEqQ8u44q4ZO9drcswcA24Bn0j9dkX7sbyJTEtipj1LGjoUD/i5+e1sIQEWb5esA1WXIPWVS
b8e8d/JnH4acQbTFH+1mrE2PtGD18IbM2PdTilcC/l4KNKcyWfsuoJmwoG5x/ciQUhpqn/fW
WBjH99tbK8kIHSbgQ4FrMhS+I6Z3pH0EbViDC20f7TgZgGShVHUM/0BGcavVdd1vjUK4MZag
kwJwpwBNGRPSazs8NKyjiAQupIC+xbZG+Qcz67xmOWU92qmfr3h6wrk8JJGsPOynGExJFNKv
PwKckh3z7surZLhPeDMuZykGcEtFmJJbVBK+cIcAAA==
=o6Ev
- -----END PGP MESSAGE-----
-----BEGIN PGP SIGNATURE-----
Version: GNUPG v0.2.19 (GNU/Linux)
Comment: This is an alpha version!
iQEXAwUBNW6hBuPk8EXQYMj+FAN5GQP+NhSpe3WmGfWYYQSOM4CxlgNv+EmpDvvDBCmxyKT6
oVw+YD1b6q0XCkSx5u1b/ykwPbPS8VUxPqEKFBOtVWNQbCfmMRujUtPYWm8eomIHO3k7l0DF
H8nah5gdwvOheB5YMUfhtuKQRk8/d8QRrsoc44OmB7znkLvQEMMaHxrgb5AD/31/TocHnNj6
iC61cQrwTDSj2nLFWHn2yQ7uX5j9fBxCJgbQq6Aku17Z6LHDu6FfaMigS9l6s5VT2n4XuzFl
qV2GMe20HU5JgrprU1cTULtr1yc3KUctnI3tcGt4UoF0Rt/IcPDdPTIcWScmUd01v4x1zVV9
n6Qxh+yxRMwl+Oo+
=gI9G
-----END PGP SIGNATURE-----

View File

@ -1,103 +0,0 @@
#!/bin/sh
# Fixme: we should not only do a --verify but also the output.
. $srcdir/defs.inc || exit 3
# ======================================
# I can't compare the out because plain-3 has no LF as last charcater
# but the output has always one. I do not thinkl this is a bug, because
# it is clear text and not binary text.
# ======================================
for i in $plain_files plain-large ; do
echo "$usrpass1" | $GPG --passphrase-fd 0 -sat -o x --yes $i
$GPG --verify x
done
# ======================================
# and once more to check rfc1991
# ======================================
for i in $plain_files plain-large ; do
echo "$usrpass1" | $GPG --passphrase-fd 0 \
--rfc1991 --digest-algo md5 -sat -o x --yes $i
$GPG --verify x
done
# ======================================
# and one with long lines
# ======================================
cat >y <<EOF
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
EOF
echo "$usrpass1" | $GPG --passphrase-fd 0 --clearsign -o x --yes y
$GPG --verify x
# ======================================
# and one with only one long lines
# ======================================
cat >y <<EOF
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyx
EOF
echo "$usrpass1" | $GPG --passphrase-fd 0 --clearsign -o x --yes y
$GPG --verify x
# ======================================
# and one with an empty body
# ======================================
cat >y <<EOF
EOF
echo "$usrpass1" | $GPG --passphrase-fd 0 --clearsign -o x --yes y
$GPG --verify x
# ======================================
# and one with one empty line at the end
# ======================================
cat >y <<EOF
line 1
line 2
line 3
there is a blank line after this
EOF
echo "$usrpass1" | $GPG --passphrase-fd 0 --clearsign -o x --yes y
$GPG --verify x
# ======================================
# I think this file will be constructed wrong (gpg 0.9.3)
# but it should verify okay anyway.
# ======================================
echo "this is a sig test" >y
echo_n " " >>y
echo "$usrpass1" | $GPG --passphrase-fd 0 --clearsign -o x --yes y
$GPG --verify x
# ======================================
# check our special diff mode
# ======================================
cat >y <<EOF
--- mainproc.c Tue Jun 27 09:28:11 2000
+++ mainproc.c~ Thu Jun 8 22:50:25 2000
@@ -1190,16 +1190,13 @@
md_enable( c->mfx.md, n1->pkt->pkt.signature->digest_algo);
}
/* ask for file and hash it */
- if( c->sigs_only ) {
+ if( c->sigs_only )
rc = hash_datafiles( c->mfx.md, NULL,
c->signed_data, c->sigfilename,
n1? (n1->pkt->pkt.onepass_sig->sig_class == 0x01):0 );
EOF
echo "$usrpass1" | $GPG --passphrase-fd 0 \
--not-dash-escaped --clearsign -o x --yes y
$GPG --verify x

View File

@ -1,21 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
#info Checking conventional encryption
for i in 0 1 2 3 9 10 11 19 20 21 22 23 39 40 41 8192 32000 ; do
for ciph in 3des cast5 blowfish twofish rijndael; do
# *BSD's dd can't cope with a count of 0
if test "$i" = "0"; then
: >z
else
dd if=data-80000 of=z bs=1 count=$i 2>/dev/null
fi
echo "Hier spricht HAL" | $GPG --passphrase-fd 0 \
--force-mdc --cipher $ciph -c -o x --yes z
echo "Hier spricht HAL" | $GPG --passphrase-fd 0 \
-o y --yes x
cmp z y || error "$ciph/$i: mismatch"
done
done

View File

@ -1,24 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
# temp. hack cause the format for 128 bit blocksize messages may change
GNUPG_ENABLE_TWOFISH=1
export GNUPG_ENABLE_TWOFISH
#info Checking conventional encryption
for i in plain-2 data-32000 ; do
echo "Hier spricht HAL" | $GPG --passphrase-fd 0 -c -o x --yes $i
echo "Hier spricht HAL" | $GPG --passphrase-fd 0 -o y --yes x
cmp $i y || error "$i: mismatch"
done
for a in cast5 3des twofish; do
for i in plain-1 data-80000 ; do
echo "Hier spricht HAL" | $GPG --passphrase-fd 0 \
--cipher-algo $a -c -o x --yes $i
echo "Hier spricht HAL" | $GPG --passphrase-fd 0 -o y --yes x
cmp $i y || error "$i: ($a) mismatch"
done
done

View File

@ -1,10 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
#info Checking decryption of supplied DSA encrypted file
for i in "plain-1" ; do
$GPG $dsa_keyrings -o y --yes $srcdir/$i-pgp.asc
cmp $i y || error "$i: mismatch"
done

View File

@ -1,10 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
#info Checking decryption of supplied files
for i in $plain_files ; do
echo "$usrpass1" | $GPG --passphrase-fd 0 -o y --yes $srcdir/$i.asc
cmp $i y || error "$i: mismatch"
done

View File

@ -1,106 +0,0 @@
# definitions for the check scripts
#--------------------------------
#------ constants ---------------
#--------------------------------
# Note that usrpass1 is also used in Makefile.am
usrname1="one"
usrpass1="def"
usrname2="two"
usrpass2=""
usrname3="three"
usrpass3="abc"
dsa_usrname1="pgp5"
# we use the sub key because we do not yet have the logic to
# to derive the first encryption key from a keyblock (I guess)
dsa_usrname2="0xCB879DE9"
dsa_keyrings="--keyring ./pubring.pkr --secret-keyring ./secring.skr"
plain_files="plain-1 plain-2 plain-3"
data_files="data-500 data-9000 data-32000 data-80000"
exp_files=""
# The testscripts expect the original language
LANG=
LANGUAGE=
LC_ALL=
LC_MESSAGES=
#--------------------------------
#------ utility functions -------
#--------------------------------
fatal () {
echo "$pgmname: fatal:" $* >&2
exit 1;
}
error () {
echo "$pgmname:" $* >&2
exit 1
}
info () {
echo "$pgmname:" $* >&2
}
echo_n_init=no
echo_n () {
if test "$echo_n_init" = "no"; then
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
echo_n_n=
echo_n_c='
'
else
echo_n_n='-n'
echo_n_c=
fi
else
echo_n_n=
echo_n_c='\c'
fi
echo_n_init=yes
fi
echo $echo_n_n "${1}$echo_n_c"
}
#cleanup () {
# rm $cleanup_files 2>/dev/null || true
# echo "#empty" >./options
#}
#add_cleanup () {
# cleanup_files="$cleanup_files $*"
#}
have_hash_algo () {
if ../g10/gpg --homedir . --version | grep "Hash:.*$1" >/dev/null
then
true
else
false
fi
}
set -e
pgmname=`basename $0`
#trap cleanup SIGHUP SIGINT SIGQUIT
[ -z "$srcdir" ] && fatal "not called from make"
GPG="../g10/gpg --homedir . "
exec 2> ${pgmname}.log
:
# end

View File

@ -1,10 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
#info Checking detached signatures
for i in $plain_files $data_files ; do
echo "$usrpass1" | $GPG --passphrase-fd 0 -sb -o x --yes $i
$GPG -o /dev/null --yes x <$i || error "$i: bad signature"
done

View File

@ -1,9 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
#info Checking detached signatures of multiple files
i="$plain_files $data_files"
echo "$usrpass1" | $GPG --passphrase-fd 0 -sb -o x --yes $i
cat $i | $GPG -o /dev/null --yes x || error "$i: bad signature"

View File

@ -1,19 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
#info Checking encryption
for i in $plain_files $data_files ; do
$GPG $dsa_keyrings --always-trust -e -o x --yes -r "$dsa_usrname2" $i
$GPG $dsa_keyrings -o y --yes x
cmp $i y || error "$i: mismatch"
done
# and with cast
for i in $plain_files $data_files ; do
$GPG $dsa_keyrings --always-trust --cipher-algo cast5 -e \
-o x --yes -r "$dsa_usrname2" $i
$GPG $dsa_keyrings -o y --yes x
cmp $i y || error "$i: mismatch"
done

View File

@ -1,16 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
#info Checking encryption
for i in $plain_files $data_files ; do
$GPG --always-trust -e -o x --yes -r "$usrname2" $i
$GPG -o y --yes x
cmp $i y || error "$i: mismatch"
done
for i in $plain_files $data_files ; do
$GPG --always-trust -e -o x --yes -r "$usrname2" --cipher-algo cast5 $i
$GPG -o y --yes x
cmp $i y || error "$i: mismatch"
done

View File

@ -1,10 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
#info Checking encryption with a pipe
for i in $plain_files $data_files ; do
$GPG --always-trust -e --yes -r "$usrname2" <$i | $GPG --yes > y
cmp $i y || error "$i: mismatch"
done

View File

@ -1,26 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
../g10/gpg --quiet --batch --quick-random --homedir . --gen-key <<EOF
Key-Type: DSA
Key-Length: 1024
Subkey-Type: ELG-E
Subkey-Length: 1024
Name-Real: Harry H.
Name-Comment: test key
Name-Email: hh@@ddorf.de
Expire-Date: 1
Passphrase: abc
%commit
Key-Type: RSA
Key-Length: 1024
Key-Usage: sign,encrypt
Name-Real: Harry A.
Name-Comment: RSA test key
Name-Email: hh@@ddorf.de
Expire-Date: 2
Passphrase: abc
%commit
EOF

View File

@ -1,40 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
test_one () {
if [ "`grep $1 y | sed -e 's/.*=[ ]\(.*\)/\1/' -e 's/ //g'`" != "$2" ]; then
failed="$failed $1"
fi
}
failed=""
#info Checking message digests
cat /dev/null | $GPG -v --print-mds >y
test_one "MD5" "D41D8CD98F00B204E9800998ECF8427E"
test_one "SHA1" "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"
test_one "RMD160" "9C1185A5C5E9FC54612808977EE8F548B2258D31"
if have_hash_algo "TIGER"; then
test_one "TIGER" "24F0130C63AC933216166E76B1BB925FF373DE2D49584E7A"
else
echo "Hash algorithm TIGER/192 is not installed"
fi
[ "$failed" != "" ] && error "$failed failed for empty string"
echo_n "abcdefghijklmnopqrstuvwxyz" | $GPG --print-mds >y
test_one "MD5" "C3FCD3D76192E4007DFB496CCA67E13B"
test_one "SHA1" "32D10C7B8CF96570CA04CE37F2A19D84240D3A89"
test_one "RMD160" "F71C27109C692C1B56BBDCEB5B9D2865B3708DBC"
if have_hash_algo "TIGER"; then
test_one "TIGER" "307DE5EE72A414172A0355CCBF120404E9EE7BF32F60110B"
fi
[ "$failed" != "" ] && error "$failed failed for a..z"
exit 0

View File

@ -1,37 +0,0 @@
#!/bin/sh
set -e
GPG="../g10/gpg --batch --quiet --no-secmem-warning --allow-secret-key-import"
NAMES='Alpha Bravo Charlie Delta Echo Foxtrot Golf Hotel India
Juliet Kilo Lima Mike November Oscar Papa Quebec Romeo
Sierra Tango Uniform Victor Whisky XRay Yankee Zulu'
if [ "$1" = "--clean" ]; then
(for i in $NAMES; do
[ -d $i ] && rm -r $i
done) || true
exit 0
fi
$GPG --dearmor -o secdemo.gpg --yes ../checks/secdemo.asc
$GPG --dearmor -o pubdemo.gpg --yes ../checks/pubdemo.asc
[ -f ./tdb.tmp ] && rm ./tdb.tmp
GPGDEMO="$GPG --homedir . --trustdb-name ./tdb.tmp --no-default-keyring
--keyring pubdemo.gpg --secret-keyring secdemo.gpg"
echo -n "Creating:"
for name in $NAMES; do
echo -n " $name"
[ -d $name ] && rm -r $name
mkdir $name
$GPGDEMO --export-secret-key -o - $name > $name/Secret.gpg
$GPG --homedir $name --import $name/Secret.gpg
$GPGDEMO --export -o - $name > $name/Public.gpg
$GPG --homedir $name --import $name/Public.gpg
[ -f $name/pubring.gpg~ ] && rm $name/pubring.gpg~
done
echo "."
[ -f ./tdb.tmp ] && rm ./tdb.tmp
rm pubdemo.gpg secdemo.gpg

View File

@ -1,145 +0,0 @@
#!/bin/sh
# Check that gpg verifies only signatures where there is no ambiguity
# in the order of packets. Needs the Demo Keys Lima and Mike.
. $srcdir/defs.inc || exit 3
# (variable intialization was created using:
# for i in files; do echo "`echo $i | sed 's,[.-],_,g'`='"; \
# gpg --no-version --enarmor <$i | grep -v ^Comment:; echo "'" ; done
# )
sig_1ls1ls_valid='
-----BEGIN PGP ARMORED FILE-----
kA0DAAIRN8q1H7eRA/gBrCdiBXRleHQxOogq9EkgYW0gc29ycnksIEkgY2FuJ3Qg
ZG8gdGhhdAqIPwMFADqIKvQ3yrUft5ED+BEC2joAoJaSaXOZEtSZqQ780HIXG77e
8PB7AJ4wCprmaFTO0fBaTcXDuEOBdAWnOZANAwACETfKtR+3kQP4AawnYgV0ZXh0
MTqIKvRJIGFtIHNvcnJ5LCBJIGNhbid0IGRvIHRoYXQKiD8DBQA6iCr0N8q1H7eR
A/gRAto6AKCWkmlzmRLUmakO/NByFxu+3vDwewCeMAqa5mhUztHwWk3Fw7hDgXQF
pzk=
=8jSC
-----END PGP ARMORED FILE-----
'
sig_ls_valid='
-----BEGIN PGP ARMORED FILE-----
rCdiBXRleHQxOogrS0kgYW0gc29ycnksIEkgY2FuJ3QgZG8gdGhhdAqIPwMFADqI
K0s3yrUft5ED+BECLQMAn2jZUNOpB4OuurSQkc2TRfg6ek02AJ9+oJS0frQ+yUsT
QDUFTH2PvZRxjw==
=J+lb
-----END PGP ARMORED FILE-----
'
sig_sl_valid='
-----BEGIN PGP ARMORED FILE-----
iD8DBQA6iCtLN8q1H7eRA/gRAi0DAJ9o2VDTqQeDrrq0kJHNk0X4OnpNNgCffqCU
tH60PslLE0A1BUx9j72UcY+sJ2IFdGV4dDE6iCtLSSBhbSBzb3JyeSwgSSBjYW4n
dCBkbyB0aGF0Cg==
=N9MP
-----END PGP ARMORED FILE-----
'
sig_11lss_valid_but_is_not='
-----BEGIN PGP ARMORED FILE-----
kA0DAAIRN8q1H7eRA/gAkA0DAAIRN8q1H7eRA/gBrCdiBXRleHQxOogyXUkgYW0g
c29ycnksIEkgY2FuJ3QgZG8gdGhhdAqIPwMFADqIMl03yrUft5ED+BECwQAAnRXT
mXjVd385oD38W80XuheWKTGcAJ9pZ6/flaKDfw+SLido7xaUHuhp5Yg/AwUAOogy
XTfKtR+3kQP4EQLBAACgnN0IP+NztE0aAc/DZ17yHWR9diwAniN0P01WmbgZJoZB
Q341WRXKS/at
=Ekrs
-----END PGP ARMORED FILE-----
'
sig_11lss11lss_valid_but_is_not='
-----BEGIN PGP ARMORED FILE-----
kA0DAAIRN8q1H7eRA/gAkA0DAAIRN8q1H7eRA/gBrCdiBXRleHQxOogyXUkgYW0g
c29ycnksIEkgY2FuJ3QgZG8gdGhhdAqIPwMFADqIMl03yrUft5ED+BECwQAAnRXT
mXjVd385oD38W80XuheWKTGcAJ9pZ6/flaKDfw+SLido7xaUHuhp5Yg/AwUAOogy
XTfKtR+3kQP4EQLBAACgnN0IP+NztE0aAc/DZ17yHWR9diwAniN0P01WmbgZJoZB
Q341WRXKS/atkA0DAAIRN8q1H7eRA/gAkA0DAAIRN8q1H7eRA/gBrCdiBXRleHQx
OogyXUkgYW0gc29ycnksIEkgY2FuJ3QgZG8gdGhhdAqIPwMFADqIMl03yrUft5ED
+BECwQAAnRXTmXjVd385oD38W80XuheWKTGcAJ9pZ6/flaKDfw+SLido7xaUHuhp
5Yg/AwUAOogyXTfKtR+3kQP4EQLBAACgnN0IP+NztE0aAc/DZ17yHWR9diwAniN0
P01WmbgZJoZBQ341WRXKS/at
=P1Mu
-----END PGP ARMORED FILE-----
'
sig_ssl_valid_but_is_not='
-----BEGIN PGP ARMORED FILE-----
iD8DBQA6iCtLN8q1H7eRA/gRAi0DAJ9o2VDTqQeDrrq0kJHNk0X4OnpNNgCffqCU
tH60PslLE0A1BUx9j72UcY+IPwMFADqIK0s3yrUft5ED+BECLQMAn2jZUNOpB4Ou
urSQkc2TRfg6ek02AJ9+oJS0frQ+yUsTQDUFTH2PvZRxj6wnYgV0ZXh0MTqIK0tJ
IGFtIHNvcnJ5LCBJIGNhbid0IGRvIHRoYXQK
=Zven
-----END PGP ARMORED FILE-----
'
sig_1lsls_invalid='
-----BEGIN PGP ARMORED FILE-----
kA0DAAIRN8q1H7eRA/gBrCdiBXRleHQxOogq9EkgYW0gc29ycnksIEkgY2FuJ3Qg
ZG8gdGhhdAqIPwMFADqIKvQ3yrUft5ED+BEC2joAoJaSaXOZEtSZqQ780HIXG77e
8PB7AJ4wCprmaFTO0fBaTcXDuEOBdAWnOawnYgV0ZXh0MTqIK0tJIGFtIHNvcnJ5
LCBJIGNhbid0IGRvIHRoYXQKiD8DBQA6iCtLN8q1H7eRA/gRAi0DAJ9o2VDTqQeD
rrq0kJHNk0X4OnpNNgCffqCUtH60PslLE0A1BUx9j72UcY8=
=nkeu
-----END PGP ARMORED FILE-----
'
sig_lsls_invalid='
-----BEGIN PGP ARMORED FILE-----
rCdiBXRleHQxOogrS0kgYW0gc29ycnksIEkgY2FuJ3QgZG8gdGhhdAqIPwMFADqI
K0s3yrUft5ED+BECLQMAn2jZUNOpB4OuurSQkc2TRfg6ek02AJ9+oJS0frQ+yUsT
QDUFTH2PvZRxj6wnYgV0ZXh0MTqIK0tJIGFtIHNvcnJ5LCBJIGNhbid0IGRvIHRo
YXQKiD8DBQA6iCtLN8q1H7eRA/gRAi0DAJ9o2VDTqQeDrrq0kJHNk0X4OnpNNgCf
fqCUtH60PslLE0A1BUx9j72UcY8=
=BlZH
-----END PGP ARMORED FILE-----
'
sig_lss_invalid='
-----BEGIN PGP ARMORED FILE-----
rCdiBXRleHQxOogrS0kgYW0gc29ycnksIEkgY2FuJ3QgZG8gdGhhdAqIPwMFADqI
K0s3yrUft5ED+BECLQMAn2jZUNOpB4OuurSQkc2TRfg6ek02AJ9+oJS0frQ+yUsT
QDUFTH2PvZRxj4g/AwUAOogrSzfKtR+3kQP4EQItAwCfaNlQ06kHg666tJCRzZNF
+Dp6TTYAn36glLR+tD7JSxNANQVMfY+9lHGP
=jmt6
-----END PGP ARMORED FILE-----
'
sig_slsl_invalid='
-----BEGIN PGP ARMORED FILE-----
iD8DBQA6iCtLN8q1H7eRA/gRAi0DAJ9o2VDTqQeDrrq0kJHNk0X4OnpNNgCffqCU
tH60PslLE0A1BUx9j72UcY+sJ2IFdGV4dDE6iCtLSSBhbSBzb3JyeSwgSSBjYW4n
dCBkbyB0aGF0Cog/AwUAOogrSzfKtR+3kQP4EQItAwCfaNlQ06kHg666tJCRzZNF
+Dp6TTYAn36glLR+tD7JSxNANQVMfY+9lHGPrCdiBXRleHQxOogrS0kgYW0gc29y
cnksIEkgY2FuJ3QgZG8gdGhhdAo=
=phBF
-----END PGP ARMORED FILE-----
'
save_IFS="${IFS}"
IFS=""
for i in "$sig_1ls1ls_valid" "$sig_ls_valid" "$sig_sl_valid"; do
echo "$i" | ./gpg_dearmor >x
IFS="${save_IFS}"
$GPG --verify x 2>/dev/null || error "valid is invalid"
IFS=""
done
#for i in "$sig_11lss_valid_but_is_not" "$sig_11lss11lss_valid_but_is_not" \
# "$sig_ssl_valid_but_is_not"; do
# echo "$i" | $GPG --dearmor >x
# $GPG --verify <x 2>/dev/null || error "valid is invalid"
#done
# without the +e ksh seems to terminate the for loop
set +e
for i in "$sig_1lsls_invalid" "$sig_lsls_invalid" \
"$sig_lss_invalid" "$sig_slsl_invalid" ; do
echo "$i" | ./gpg_dearmor >x
IFS="${save_IFS}"
$GPG --verify <x 2>/dev/null && error "invalid is valid"
IFS=""
done
IFS="${save_IFS}"

View File

@ -1,6 +0,0 @@
no-greeting
no-secmem-warning
no-permission-warning
batch
emulate-md-encode-bug
no-auto-check-trustdb

View File

@ -1,14 +0,0 @@
Type Bits/KeyID Date User ID
pub 888/A50283F1 2001/11/08 pgp2.6.3-test-key
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: 2.6.3a
mQB8AzvqRosAAAEDeNMKLJMJQeGC2RG5Nec6R2mzC12N1wGLiYYJCsmSQd1Y8mht
A2Sc+4k/q5+l6GHtfqUR/RTCIIudAZUzrQVIMhHDKF+5de9lsE5QxQS1u43QGVCb
/9IYrOLOizYQ2pkBtD9LCrf7W2DccMEkpQKD8QAFE7QRcGdwMi42LjMtdGVzdC1r
ZXmJAIQDBRA76kaL3HDBJKUCg/EBAZMoA3Yqqdix6B2RAzywi9bKSLqwAFVL+MMw
W+BnYeBXF9u+bPpQvtyxgi0vx8F9r84B3HAhZNEjBWODF6vctIQhXhAhXIniDTSj
HNzQ/+nbWnebQn18XUV2SdM1PzMOblD+nISte7+WUfWzlD7YUJPkFPw=
=b498
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -1,18 +0,0 @@
Type Bits/KeyID Date User ID
sec 888/A50283F1 2001/11/08 pgp2.6.3-test-key
-----BEGIN PGP SECRET KEY BLOCK-----
Version: 2.6.3a
lQGdAzvqRosAAAEDeNMKLJMJQeGC2RG5Nec6R2mzC12N1wGLiYYJCsmSQd1Y8mht
A2Sc+4k/q5+l6GHtfqUR/RTCIIudAZUzrQVIMhHDKF+5de9lsE5QxQS1u43QGVCb
/9IYrOLOizYQ2pkBtD9LCrf7W2DccMEkpQKD8QAFEwADd0Kk5aeyFM3zbPgfikkE
7iFg9h2LG3nARmA4wAnCZaQ3CS5zRHCdXOf5KLkm6xFza1yMat4iWx6ULvuuNpIc
RmkHccyXYkRi3Hvacd5A9VCNw1UKtCdaCKgacsfplU0s1xYWGZd4J8Jg8boSfW5W
gwG8Dc9R20HHno8uD2vfr5rg8ElWvbFyJI/j4eCVAd+NYAGNvB8I3VP38IIYcavh
YYcGjrpxbGVRybsBvA9IJltpGaVulxwpeCp5NecCGgoAUsN4Ktf42Pg7HXDlQL6r
Xs/YggMztj4NzEgBHXAOLShdKKhDAbEByVSKXZD9A8J+RejXBl6VbuJmD/5qOvph
GAPKS3ahPDj8438HyD7yIDLYYVRKfxjWHLubc46Pgui0EXBncDIuNi4zLXRlc3Qt
a2V5
=l/aV
-----END PGP SECRET KEY BLOCK-----

View File

@ -1,29 +0,0 @@
This is an encrypted version of plain-1 for
the PGP test key 0xCB879DE9 using CAST.
-----BEGIN PGP MESSAGE-----
Version: PGPfreeware 5.0i for non-commercial use
MessageID: D0P6k4cfvaTDkyRQM+/MpOoQW6xT5Swm
qANQR1DBwA4DW3oC8MuHnekQAwDj3tkgY6XU+e1k9XOlSSzIPGenxgOZ8VSvuEUd
L+/1E9T2KJmH5CGyH4Hz6wIOLtFSd1A13yYRyHNhxD/nGgcjg6etZNVQnjPuRp5k
O4jYz2BCstkjz793ZjPzgXgdpt0C/0zmlQz8clT+/cswAj0t1famcz/Ai4gexfkI
pojmFHewdYs6FT0XbwxjaYUyw955KBEUwJ4uJ6VTR5ab4GxUmpHn/S7HfoWVPjXl
j7R8Xw/5bsrOCjA5hd2XcpE95lTHzcnB9Fr57OMFlFC/FSwUaDsArZ/V8sUJnD+l
aWyrDhzuiwVy2XSYiX55qCL3zuZsiElo6AS7ITkI8onL2FIFtC3L5LecPprNlE68
XJLxNZUSAel7OcnwqUNtM1lEK6bfYfiXr0BBEkg1Jfx/KucHMIara0CVEh+V0aGj
I8rKt3MS+T7KMYgJzf47ipTtf0Q3qZph28fRirn8gKBlEIRz62WU9Jjz/GrNqbuD
meixSq3JprnK2kDZ00oqSZVCjFEc6pQoZqZc0cGT6IDpYEsNghfeyCxzUB17QzJC
gisd5k0uSCIWO8lwbWInnDzmV8XTfG5o4u88S89ioGydxMlCcNNX2cNp/MH/chgk
iSI+BAZ6mVcKdH2x6NpFJDGcogIM9phsnUC8NkOUH2FtjnCxDJyKSfML4lrEIi3x
QCAFEx+dYq4xcT8AnEQcTJ4ppoUJwfbtqXxYh2TKSWSkXnNz6sp2AGlx/uc99CyB
BjurpFQzseceTbxfJySm3LMJ470jSmwXSl3byryfiwTVV7BYoKkYfpVaXK4VHVMS
bw15DEH8PqjkxRabokwhIpWsJ4ta+FCgaDYhdOvrBAztwm9edsYYiNdrwjn8zFzw
QpOqh7h0uCksU5/ULmadIAYgejPyGJM6lv2m7o0xay4TOqyRMzkdcu0WyR3PVFAE
iwk/uYIonNCJc3pFS8k4b3CYnSiso0z1ugJR5YcPoOuxrbdly1om4ZC0is+euQZN
kzSGwfbabKY3mvRWGTGpZil43BRMK7nzL6oN0f7Y+/DTRp4Vzc0NTyfV2QkU25Il
ARs4Cxa138Nw4fmfvenCvv2QL2Ks/HCM7lybhq2IvbRVRiOEgcPxvRtZ5VKrqbkM
rrzzqi2PxlVrinR2GAkNu75ef+FP/KWP4NFYvEMpDxqXNS7Ju1sfcyFaTnm9
=TpZW
-----END PGP MESSAGE-----

View File

@ -1,32 +0,0 @@
-----BEGIN PGP MESSAGE-----
Version: GNUPG v0.2.15a (Linux)
Comment: This is an alpha version!
0CIjY3JlYXRlZCBieSBHTlVQRyB2MC4yLjE1YSAoTGludXgpowJ4nAFBBb76hM4DPGu75p0m
bg8QAwCx58y5eWLvOyIPG+OzRE9RCA9ZAC+9/A7Zy0u6KfUx4FaGZEMaxECYVK7l4qOmsNG+
FQB25V+OX9P3nfJ9IFs+AlvhEzv6mBGuoyIErMsXe9XHVGCTV2mceKqmE959zH8DAL8a0GEo
fgtyvu8KC8GdJi4SgTvKXKC9cBdU14RSsk5G3KFYl+qCRP8fcoZ2AkZUf2+LOGk1c1h1eGF5
8C5EdFbCQNM+EUVTsYc4nOpMwGl4B2TQ6Jmn4LB+qVGgFzbZsKUEbhM0CbsTTbGimyGAWMEh
LAp7hFrR7hWaY3nmbMd3xUc3OIvOgF8TqbcnbyHKGUIgH9UiRshTFIVNGaWJbbemVk9zQi50
v6+unuYtQmaghBSZ/OPcFvThdfkLFQbSVsVJ21N/6mblUrHpv4TsEmeHSeBMdfhhdf2a0f03
7uHxITOSr53iSi3A5K9/7mvLznMrAJ/W7fMx37imdsvxNc3TZFbPoau5auqG4PJMGMqucFH1
6bOkq/jbAbNhaOhU1pLazYVjAL+iqW1wVDc4NTfqJjaf/gI4E+4WTjddAbUYtmuqEhx8UGwU
tW0B7gVNhKvMUE2EtTCtC5kCW6qridVOFx2W42xrrAEGyG84oHuMmsE0K9QB0OJBRLwFUzPS
4JVW+sdv26XkReiNKQeD5I5Vwu5oYY36MdQFdnGDmKhTwt6/+NLzyJ7bSPFhAKHwYkPoDCuI
nMVWUrrt6HsXY2cszTP403bbdp4vI0OIHCT7yBS2kRVygD2/N9E66O0vvOWEPKaHuZUIhJi5
pNFVrhBDUoYxRGbdcLq4RNYrexYBNdnD4IuhJfmnqJfv4HxSoyHy4llXY2AieNtOscBzA7nU
jHrvqykyFVmyLUGcG1w9a72xl2XG8cKvL2BNpMbt+Xv+8mxst85TrFTjmoPdGDAHcMzgr/ds
yKcw0yOgX2PumuAxQ8ND1BXxctS5R8ZQlsOQgY7StvnfSwKPLXXJ1Xdmo/pn8mncPrzbEl/X
d07bZZ1vzE6/NkGkLpHo3WKuiNTu9FtwuO6DsqzsM1yZ4AOiDMG4uIxQplPa/mv31eEkYY3/
9F5K3mzFh9phK3lKk0bdp29d8pO44A7tXt+yS5/QeDojykarAwAz2EvEA+F8dLvprJ4ku9Qv
T/2ubr8I+9pRwtA69BevNd80qKQr2q1Exi/Y5d2Lvcp6x6kSwXKO65rLYQ/2RlCOHzlkFNvn
r9RJ/H/c8COYhjFbTeVymgviRyGABdxeLEMOSFFRa4EQL0L7Kbu6obX2NLbuQA+UlQ3bFKMn
r2P5+6qxIIS6bgDxmb3xRnOCsVl8X4/Y14oOY0HbcBY3VmiXUqVG4zMaPChSFn5vGXaCH3uC
J9lETUeh+2q5L+nvoRW6wGax4smtNBIVKkCTDGnuaiYQ5L+24MJQzn5OXnkeoe09cNp4FR+s
SxaVfLyJW+TkMppd1v6rswSrCeh1zh+baamOmKOyS/RcwkRH+hoRECvVxQ7mm5QLm6Wyl22B
CFns6pzKQFeh9KgK4w+PgaNuiSI8UKqD/MJ4y3aylAfgX8izODd4grqYt/KrLgfFJ7mESDdP
3uL8PcX7iIhq47YRGPk0mDyCRNni6xC27xeaYy2pGeEr3NJ+nZceUsYZxBCvdoiejFxQ+Hog
dA9saADuqORjQuQEybej8Eq2LXeg62TvcSzBF4nbVATG2N9/U5PVtTx/hv26Ime8hmrsTA7M
2Wm+9xHoWHsZIyj5tkWdgChIZQ+4ZBi3w6f4M9yGmb4kf73bVkimI4d8r48=
=a0yS
-----END PGP MESSAGE-----

View File

@ -1,28 +0,0 @@
-----BEGIN PGP ARMORED FILE-----
Version: GNUPG v0.3.4 (GNU/Linux)
Comment: Get GNUPG from ftp://ftp.guug.de/pub/gcrypt/
Comment: Use "gpgm --dearmor" for unpacking
PCEtLSBEaWVzIGlzdCBTZWl0ZSAzLCBkb3J0IGlzdCBrZWluZSBTZWl0ZW56YWhsIGFuZ2Vn
ZWJlbiwKICAgICBvYmVuIHJlY2h0cyBpc3Qgd2llZGVyIGRlciBTdGVtcGVsIHZvbiBtZWlu
ZW0gT3BhIHp1IGZpbmRlbiAtLT4KCjxzZWN0MT5OYW1lIDxxPkdyb98tQmFydGxvZmY8Lz4K
CjxwPgpEZXIgTmFtZSA8cS9CYXJ0bG9mZi8gaXN0IHNjaHdlciB6dSBkZXV0ZW4uIE1hbiBo
YXQgdmllbGUgTXV0bWHfdW5nZW4KYW5nZXN0ZWxsdCwgdm9uIGRlbmVuIG1hbiBhYmVyIGJp
c2xhbmcga2VpbmUgZWluemlnZSBhbHMgdW5iZWRpbmd0CnJpY2h0aWcgZXJrbORyZW4ga2Fu
bi4KPGZvbnRpbmZvIHJlbT0ibWl0IExlZXJ6ZWljaGVuIGdlc2NocmllYmVuIj5Vcmt1bmRs
aWNoPC8+IHdpcmQgZGFzCkRvcmYgYmlzIHp1ciBSZWZvcm1hdGlvbiBzdGV0cyA8cS9CYXJ0
b3JmLyAoYW5ubyAxMjUzKSB1bmQKPHEvQmFyZG9yZi8gKDEzMDYsIDEzMTgsIDEzMjksIDE0
MjkpIGdlbmFubnQgdW5kIGRhc18gc293b2hsIEtsZWluLQp3aWUgR3Jv32JhcnRsb2ZmLiBF
cnN0IDE1ODYgaW0gQmlzY2hvZnNzdGVpbmVyIEp1cmlzZGlrdGlvbmFsYnVjaApoZWnfdCB1
bnNlciBEb3JmIDxxL0JhcnR0ZWxvZmYvIHVuZCBzbyBhdWNoIGluIGRlciDkbHRlc3RlbiBu
b2NoCnZvcmhhbmRlbmVuIEtpcmNoZW5yZWNobnVuZyB2b20gSmFocmUgMTY1MS4gTkFjaCBk
ZW0gSmFocmUgMTcwMCB3aXJkCmluIGRlbiBVcmt1bmRlbiBiZWdvbm5lbiwgZGVuIHZvbGxl
biBOYW1lbiA8cS9Hcm/fLUJhcnRsb2ZmLyB1bmQKPHEvS2xlaW4tQmFydGxvZmYvIHp1IHNj
aHJlaWJlbi4KLS0tLS0tLS0tLS0tLS0tLSBbd2VnZW4gZGFzaGVkIGVzY2FwZWQgdGV4dF0K
PHA+Ck5pbW10IG1hbiBhbiwgZGHfIGRpZSB1cmt1bmRsaWNoZSwg5Gx0ZXN0ZSBCZXplaWNo
bnVuZyBCYXJ0b3JmIGRpZQp1cnNwcvxuZ2xpY2hlIGlzdCB1bmQgbmljaHQgZGllIG11bmRh
cnRsaWNoZSBCYXJ0bG9mZiwgc28ga/ZubnRlIGRlcgpOYW1lIGd1dCBnZWRldXRldCB3ZXJk
ZW4gYWxzIERvcmYgYW4gZGVyIDxxL0JvcmRlLyBvZGVyIGFtIFJhbmRlCm9kZXIgYW4gZGVy
IEdyZW56ZSBlbnR3ZWRlciBkZXMgV2FsZGVzCg==
=m1k/
-----END PGP ARMORED FILE-----

View File

@ -1,41 +0,0 @@
-----BEGIN PGP MESSAGE-----
Version: GNUPG v0.2.15a (Linux)
Comment: This is an alpha version!
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
suFI5P95Yw==
=08za
-----END PGP MESSAGE-----

View File

@ -1,36 +0,0 @@
-----BEGIN PGP ARMORED FILE-----
Version: GNUPG v0.3.4 (GNU/Linux)
Comment: Get GNUPG from ftp://ftp.guug.de/pub/gcrypt/
Comment: Use "gpgm --dearmor" for unpacking
Cgo8c2VjdD5Wb3J3b3J0CjxwPgpEZXIgV2VydCBlaW5lciBPcnRzY2hyb25payBpc3Qgb2Zm
ZW5iYXIgdW5kIGJlZGFyZiBrZWluZXIgRXL2cnRlcnVuZy4KTWl0IEF1c2JydWNoIGRlcyBX
ZWx0a3JpZWdlc18sIGlubWl0dGVuIGRlciBnZXdhbHRpZ2VuIEdlc2NoZWhuaXNzZSwgZvxo
bHRlCmRlciBLbGVydXNfIHVuc2VyZXNfIEVpY2hzX2ZlbGRlc18gZGFzXyBtZWhyIHdpZSBm
cvxoZXIgdW5kIHNvCmVyc3Rhcmt0ZSBkYXNfIFN0cmViZW4sIGVpbmUgc29sY2hlIE9ydHNf
Z2VzY2hpY2h0ZSB6dSBzY2FoZmZlbiwgdW0KdW5zZXJlbiBOYWNoa29tbWVuIHp1IGJlcmlj
aHRlbiwgd2FzXyBhdWNoIGRpZSBrbGVpbnN0ZW4gRPZyZmVyIGluCmRlciBncm/fZW4gWmVp
dCBnZWxlaXN0ZXQsIGVybGVidCB1bmQgZXJsaXR0ZW4gaGFiZW4uCjxwPgpVbmQgc28gYmVn
YW5uIGF1Y2ggaWNoIGltIERlemVtYmVyIDE5MTQsIGRlbiA/Pz8/Pz8/Pz8KU3RvZmYsIHdv
IGltbWVyIGljaCBpaG4gYXVjaCBudXIgc28gc3DkcmxpY2ggZmluZGVuIGtvbm50ZSwgenUK
c2FtbWVsbiwgaWNoIGJlZnJhZ3RlIHp1buRjaHN0IGVtc2lnIGRpZSDkbHRlc3RlbiBMZXV0
ZSwKZHVyY2hmb3JzY2h0ZSBzb2Rhbm4gZGFzIGdhbnplIFBmYXJyYXJjaGl2LCBkYXMgU2No
dWx6ZW5hcmNoaXYKYmVpZGVyIFBmYXJyZPZyZmVyLCBkYXMgS29tbWlzc2FyaWF0c19hcmNo
aXYgenUgSGVpbGlnZW5zdGFkdCwKZW5kbGljaCBhdWNoIDE5MTYgZGFzIFN0YWF0c19hcmNo
aXYgenUgTWFnZGVidXJnLiBTZWxic3R2ZXJzdORuZGxpY2gKYXJiZWl0ZXRlIGljaCBhdWNo
IGRpZSBlaW5zY2hs5GdpZ2UgTGl0ZXJhdHVyIGR1cmNoLiBHYXIgdmllbGUgWmVpdAp1bmQg
TfxoZSBoYXQgZXNfIGdla29zdGV0IHVtIG5hY2ggbWVociBhbHMgOCBKYWhyZW4gZGllIE9y
dHNjaHJvbmlrIHZvbgpHcm/fYmFydGxvZmYgdW5kIHZvbSBGaWxpYWxkb3JmIFdpbGJpY2gg
Z2Vzb25kZXJ0IHp1IHNjaGFmZmVuLgo8cCB2c3BhY2U9IjJleCI+CjxiZj5Hcm/fYmFydGxv
ZmYsPC8+IGRlbiAyMy4gTeRyeiAxOTIzLgo8cCB2c3BhY2U9IjNleCIgYWxpZ249cmlnaHQ+
CjxiZi9OaWtvbGF1cyBH9nJpbmcsLyBQZmFycmVyLgo8L3A+Cgo8IS0tIEhpZXIgZm9sZ3Qg
ZWluIFN0ZW1wZWwgdm9uIG1laW5lbSBPcGE6CgkgIFJ1ZC4gS29jaAogICAgIEdyb99iYXJ0
bG9mZi9FaWNoc2ZlbGQKCUFuZ2VyIDE2MQotLT4KPCEtLSBGSVhNRTogaGllciBrb21tdCBl
aW5lbiBaaWVybGluaWUgLS0+Cgo8cCB2c3BhY2U9ZmlsbD4gPCEtLSBEZXIgUmVzdCBrYW0g
YW0gRW5kZSBkZXIgU2VpdGUgLS0+CjxwIGFsaWduPWNlbnRlcj4gTGl0ZXJhdHVyOiA8L3A+
CjEpIEpvaC4gV29sZjogUG9saXRpc2NoZSBHZXNjaGljaHRlIGRlcyBFaWNoc2YuIEf2dHQu
IDE3OTIgdW5kCkz2ZmZsZXIgMTkyMS4gMikgSy4gR2VzY2hpY2h0ZSwgV29sZiAxODE2IEf2
dHQuICAzKSBLbmllYjogR2VzY2guCmRlciBSZWYuIHUuIEdlZ2VucmVmPz8/Cgo8IS0tIEZJ
WE1FOiBEZXIgUmVzdCBmZWhsdCBub2NoIC0tPgoKCgoKCgoKCjwvc2VjdD4K
=9nnj
-----END PGP ARMORED FILE-----

View File

@ -1,13 +0,0 @@
-----BEGIN PGP MESSAGE-----
Version: GNUPG v0.2.15a (Linux)
Comment: This is an alpha version!
0CIjY3JlYXRlZCBieSBHTlVQRyB2MC4yLjE1YSAoTGludXgpowJ4nAEYAef+hM4DPGu75p0m
bg8QAwDAGvCZWrqo7Rt8DNg7tDI8ckhL1XfN0OZuy/tJjD8o1K1JuXPfCpAX2WI69PvlVhPC
RO9F2WaBTqyo/fY5XVSzNlfin9TMe56gFjhT3vhK0IgZ1gjBuowY4TktVq4cG/YC/0hX3u6L
7M9D0H0ye0YgRof82sRHKQBSeuFn5iHc6hSB7fFXsyDLqmEvclDV0exY1a3giTGwUX81fknR
EwzB2weemUnf1DQ8rGhw/dBiarOMjjWz0ypyfhWqV/U3RNZRIaRGjBtl0Qbr51KIvg3UnaGD
YX8DXWpV61kkRX+DsQ27tuQvW6V8lKcsElipIFXPhCpfdSnGGVjx69gGDSFEhMLcSy3s4i4X
MMVwiy8=
=MnS6
-----END PGP MESSAGE-----

View File

@ -1,10 +0,0 @@
Stored by G10, because diff/patch have problems with
files not having a trailing LF - and this one has none.
-----BEGIN PGP ARMORED FILE-----
Version: G10 v0.2.6a (Linux)
Comment: This is an alpha version!
RGllcyBpc3QgZWluZSBlaW5mYWNoZSBaZWlsZSBvaG5lIExGIGFtIEVuZGUu
=ZQ6m
-----END PGP ARMORED FILE-----

View File

@ -1,566 +0,0 @@
26 demo keys:
pub 1024D/68697734 1999-03-08 Alpha Test (demo key) <alpha@example.net>
uid Alice (demo key)
uid Alfa Test (demo key) <alfa@example.net>
sub 1024g/46A871F8 1999-03-08
pub 1024D/1AFDAB6C 1999-03-08 Charlie Test (demo key) <charlie@example.net>
sub 1024g/BC43DA60 1999-03-08
pub 1024D/FAEF6D1B 1999-03-08 Echo Test (demo key) <echo@example.net>
uid Eve (demo key)
uid Echelon (demo key)
sub 1024g/7272144D 1999-03-08
pub 1024D/8FC282E6 1999-03-08 Golf Test (demo key) <golf@example.net>
sub 1024g/9DCAD354 1999-03-08
pub 1024D/04259677 1999-03-08 India Test (demo key) <india@example.net>
sub 1024g/61F76C73 1999-03-08
pub 1024D/43C2D0C7 1999-03-08 Kilo Test (demo key) <kilo@example.net>
sub 1024g/9AF64D02 1999-03-08
pub 1024D/A9E3B0B2 1999-03-08 Bravo Test (demo key) <bravo@example.net>
uid Bob (demo key)
sub 1024g/E29BA37F 1999-03-08
pub 1024D/EB9DC9E6 1999-03-08 Delta Test (demo key) <delta@example.net>
sub 1024g/B0C45424 1999-03-08
pub 1024D/7372E243 1999-03-08 Foxtrot Test (demo key) <foxtrot@example.net>
sub 1024g/EE45198E 1999-03-08
pub 1024D/34C6E3F1 1999-03-08 Hotel Test (demo key) <hotel@example.net>
sub 1024g/D622AD0A 1999-03-08
pub 1024D/D2699313 1999-03-08 Juliet Test (demo key) <juliet@example.net>
sub 1024g/35F8F136 1999-03-08
pub 1024D/B79103F8 1999-03-08 Lima Test (demo key) <lima@example.net>
sub 1024g/FE56350C 1999-03-08
pub 1024D/BE5CF886 1999-03-08 Mike Test (demo key) <mike@example.net>
uid Mallory (demo key)
sub 1024g/4F31EAE8 1999-03-08
pub 1024D/30CEC684 1999-03-08 November Test (demo key) <november@example.net>
sub 1024g/8B70E472 1999-03-08
pub 1024D/6D9732AC 1999-03-08 Oscar Test (demo key) <oscar@example.net>
sub 1024g/2681619F 1999-03-08
pub 1024D/3FF13206 1999-03-08 Papa test (demo key) <papa@example.net>
sub 1024g/63330D9C 1999-03-08
pub 1024D/3C661C84 1999-03-08 Quebec Test (demo key) <quebec@example.net>
sub 1024g/A029ACF4 1999-03-08
pub 1024D/777FBED3 1999-03-08 Romeo Test (demo key) <romeo@example.net>
sub 1024g/11D102EA 1999-03-08
pub 1024D/A3AE3EA1 1999-03-08 Sierra Test (demo key) <sierra@example.net>
sub 1024g/0F1B50B4 1999-03-08
pub 1024D/85A81F38 1999-03-08 Tango Test (demo key) <tango@example.net>
sub 1024g/101C0402 1999-03-08
pub 1024D/653244D6 1999-03-08 Uniform Test (demo key) <uniform@example.net>
sub 1024g/5522BDB9 1999-03-08
pub 1024D/61F04784 1999-03-08 Victor Test (demo key) <victor@example.org>
sub 1024g/07287134 1999-03-08
pub 1024D/EC67DBDE 1999-03-08 Whisky Test (demo key) <whisky@example.net>
sub 1024g/FD6E27F6 1999-03-08
pub 1024D/567FB34A 1999-03-08 XRay Test (demo key) <xray@example.net>
sub 1024g/41E408BE 1999-03-08
pub 1024D/4B11B25F 1999-03-08 Yankee Test (demo key) <yankee@example.net>
sub 1024g/F7B080AD 1999-03-08
pub 1024D/54ACD246 1999-03-08 Zulu Test (demo key) <zulu@example.net>
sub 1024g/A172C881 1999-03-08
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v0.9.3 (GNU/Linux)
Comment: For info see http://www.gnupg.org
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
=1N8S
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -1,734 +0,0 @@
-----BEGIN PGP ARMORED FILE-----
Version: GnuPG v1.0.7 (GNU/Linux)
Comment: Use "gpg --dearmor" for unpacking
mM8DNUWBuARHEAMA8bSQw1VFSXbgZ+nNXhM9xeDD+OpKQU4hUaCKfuTtRHoY5QxT
Pz3DFWRlFewsA50Ou28jlPWxIKZaaGxMqbDtqyUsm6AEz/vRi5VKiVHf28XUkMry
QSTHvjwJFVb7+6WbAAMFAwDXZiawNtgYsjwVedv/xXdhTsrf0Tn/8HCj3S9N/MAT
0zCnXL0flYeqhqL/okuBcrwMA4amAIWGVW7ws7k7QgrfJoWG2SELxIT9MovMLvq5
Kh55J7H6Yn6uoFzIOX0A43HQIiNjcmVhdGVkIGJ5IEdOVVBHIHYwLjIuMTVhIChM
aW51eCm0KFRlc3Qgb25lIChwcD1kZWYpIDxvbmVAdGVzdC5ub3doZXJlLm5pbD6I
1wMFEzVFgbg8a7vmnSZuDxADD/4DAK0FELG1gICh/fxO5dXulV+S1CY9YPQwRxQN
7zYlixA7vedTCN9jutMC6fOlmMXqfivF2CMux3uz0oTJgjF/myh+jkcOsE+iUgcO
+fdMIn4oY53Pval5zuCcmqqbszP6mQMAqIYYNtE2BI6acRU8sqwIxx/GiVqELwzX
4QGp5N/4oURoZJ4Ybb8+6eEePI1vzIpLq9TO0ttQzDv9hO8WNyYEPVAoe9gOIoMY
Oh9E0W9Ru0wf4sh67KCrRvc7yrFTMwHtiN8DBRA1RYLMDvng6C5fpPQQAzlHAx4q
EZmAhoAtCfgQmlmqHIwcOa2xI/eOsqexT6eYMty8f/vsNznGhTh5gJ3PDDy8U/Lj
1KRJWPeDSZJ/6tZ/3DUd/x+KjPzVVnm1zlJSflR5AWLS7IQiyJzz7uo2dUiCs2nO
4rZcAyDaLbj/2aWwI92UQzKjWvcS49lWr2wp0QURUomqvNexKkHHDyIRhwspXwT9
glETyn+focZKRBJTv0QtxOMVQeGaUnIuAcsDgpZuZkXBcdXgPbmj39rN+nNUW1UI
0fKsnBl5cnSgiNcDBRA1RYLaZE80um0R1tMQAwq4Av9rzmMgXgDtJy+mauJJ5FUE
E5GY3bIul1MuIbaMv6T99uWgwD9q2HsV0z9/T552cOTJ/DIkSjdusZ6+PlY8jYDK
4xTYwcglPuMH5/EsKW8zZwcwYiqnGMbmY4F70SxZW2EC/1p760rM7MrNCDAWnEle
gTvEMvutfK+K3DOu+Ba+KxU3zfgWr4z6B74QV2TvHrF0Zgu9UpXOp0FghufA6Jev
CvYhzNDM4VJV24QaF3bt16JoHQyiS9jtYcMl4IzexeeO0JjXAzVFggEAABADINyO
1leIKxvoee6oi0zkI9SCJ6dSTEH7/kETqetNArjqClenO1K0AVd+MqMajl97bg5i
UYGam55PECkkozOlscDzDF9exWY6sey44dBREQhgXLVWE4GZ1G3sy85aD+sVHgxw
lz8AAwUDILAV8w6FL7PpgiedAOHslMtqf7sh1IeNSkCjRdqvMCKgKroSLQto9Wpr
XMUv3KHmTL7TpZNad+8xJUK7R5GHUTR1OIFQMJvTodG8RU6JOaGoeTqWgs61v00f
FgwY6sYO11ckmsfQIiNjcmVhdGVkIGJ5IEdOVVBHIHYwLjIuMTVhIChMaW51eCm0
J3Rlc3QgdHdvIChubyBwcCkgPHR3b0B0ZXN0Lm5vd2hlcmUubmlsPojfAwUTNUWC
AQ754OguX6T0EAOQsQMfXrBhe1g+hBCwQH94+08VqNGS/+Fs8s4FRmEP1Y0TuT6U
qf9QLHtfbPgKbJL1NwGgy6dn4TfWo2PRj0U8ai+YIIPZopl4hnrj+v1f94V/IbMd
3N77K0F0rJrHzL4egHi95BUVdgMgr00QAYcbbZItd/wIb2TNSu/DRlzEXezA3xRu
CIBnTdsrHMPc2B4lmCQsyx9/fmBlwrVLlaftBTvrOUa/yXf8hHwPv48avRwgClao
ChExhFMdEA9Df5ju4192VldJyJgPVz0Ze4jXAwUQNUWCsTxru+adJm4PEAOeIwMA
hzYyjVb5vlae3V3VO+5+Zsx4SVRB2NeCY74FIN5vXMoWJyt/UjmXC9CmI82PvVD3
F8RXKUZqZC9gXcGyDYyZ87oooYc9HbQ7lhyOWsv/0dWztX9UQQrHdScQ0TbZcC2a
AvwJF7WESAGhOGssVKWaUkXZJV1sCpyyEtkUP/UJtcGha/OpPlmG6vC9XW5ymtRk
0XhFkvG4dLopbRIZgAI0CmHSloKIL5Y4JzOfc5bccNCB/tiI+3Y1JIr3AYMqaSTj
oGOI1gMFEDVFgwJkTzS6bRHW0xAD83sC93MCuEN8MCJGTZX//I7QVsg5DJ9xJRdy
5Te6MNA1Ie1o7+EJZ1MqDVF/6+HkITqGWFOPD/GYPmgdP5QALfHW6z9YddHOHH6S
kt2fC2NWTip4e+/t8iAOR/ynwocPpyHkAwCHsxTXtRlaCbIt40/3d0LFPoN4JYBV
DM+pWfNgNAWUzgMEMua2P24g4P4NZnW3fsJuYQ6Ro7jqu6oolfFkxVOYd2/KrnH5
Mggu3D8q+gg68kzXTj62QW9vTBax5Ve0Kk+YzwM1RYJlAAAQAwCWZQsoNJJI8u1n
V+5VZaXZqZBn+uk3fp/my7l9YLQeV5S9U76Ogdw0la/YiWX2m8Aw+hO47pYswsyR
i2lu/FE/dr0o0CB53LB4EnFJPiBHrB8rm3wI142BQeJ9Dj5YU/MAAwYC/1gB0NoF
l2QhbYY83tuLg/UlIkM8CZtxtXR9vfQq0UgrVuDoeLx0/mlnWm8pmJsHR+0r8sL2
yjl7P0RQ+FJtiaMTVHihJyhXukCO1bPM3PX8L/QsmXFzWcfmavk11xpPNdAiI2Ny
ZWF0ZWQgYnkgR05VUEcgdjAuMi4xNWEgKExpbnV4KbQsdGVzdCB0aHJlZSAocHA9
YWJjKSA8dGhyZWVAdGVzdC5ub3doZXJlLm5pbD6I1wMFEzVFgmVkTzS6bRHW0xAD
VtEDAIWyFsZZgyT9wLmEsVbLcv2WNK/z7XweyDOV203Z3Po5lo75+c8bFkRPNcD/
0R/nD5wbyNPACFHxe7VUm+wLHZFq5Hw8TuAegqNq0ZlgeR/vLgs54m1eOi3jbDfy
ZMJASAL/XKRGnGu3oi6SjknKsKhFOprdn7DeMW0q7YP5WtRTnnrJjIhDl0c+mi82
Yj2OVEOLg3SaILBDZJd9muLPHQLAp95XsKZ0nHfBzlFFsr0V5BvWF4UV+U9JHxyD
uXLWyEDbiNcDBRA1RYK7PGu75p0mbg8QA3mwAvsHXEo6HotEGw0stskTnV/Dp32b
SJ8yRq2kOWfQAgaY1ZZWVRSPtHBDAJZJ/LpfWXPke90M3B72v0a9gAxOx5Vfevaa
XJAdp/ZjrVh1TE90LujbPVNeHt4a1dD0bQa9EbwC/1NTZMfb8LDHxYdsJdDdZxsx
fCDy2U7BWC1e3LLQCJOeNfSx76ICJBLq+HOpCgP2AodGgV9Rx01O3Fz8Gx3iVRgZ
bKnyS8perkS3AFayedGat/6reUI6KJtddro0SIeBxIjfAwUQNUWDEw754OguX6T0
EAPKMgMeL8YKAj4KvkJBWNxt1W+WTjF2YBj4pYmrWisXxgmRZWEwwyDHYecH1zE2
L12o82QGprbU8BW+GUXQVxbRt0rvlDqfGPN5HAgdjES7sK3qVZLsVeMcnhpjDDQk
pYkCIsWueCKKRwMfSiqZ1S3oBHIz3CVzbQkdMp6FbpSYXRR55CyzVdUZDb9ynXKx
QCk3Pmn0bTFsRWRFOlRe3oVpS2lM2EQFu5cWheypAt2y86ZuoevHPkcpsR0UXD12
9IzwOV3cstGm3jCAhdGMmJkBogQ2446eEQQAtmWxQ19MJiSPMiw2EHSImXgLhy5n
8h7Kl2ixlDGbVogL5/4TaXLcGoZsypuaF4px1L1JCzkNLPKzpbteZ4cOGs3N9K0z
9S7CJJ+czkTZxXYGAukSsoTnopv+t/v8hrXZ05uPZVX2gqsLBJgQhJF2nlgxqvon
tW/PSfPU+p/yarsAoKEJI1XlRhvgf0syevson3R1kFZHA/0Vw8i11+Plhxj9mnre
dV5SqI1hsLGZnPSzz2IcFP0XFDu3HtUEG9FxZVFRQYWNCUKTP7cv5DYvmhlhc4oG
0PhwFmZFLwPPlSAFZ3jfqfkh4RiMi01yqQGE6uOgML5ZWeQqb39Ngqf/ltWlcgNK
pwVjMniMV5kfRzoupccZ+XI2owP/VWbnzl1qgl5Ab8+Dst0ORW40ENP/rcvKw5/D
k2oj4uNRclJxIuizvqsgUtPRY52Y/vj5HEXF1vfUjcZhCUWOzLjR7ecCLxB9ozRD
ifZbM82RQQ27sLI1xyt+fpT2xhMuvcQj9uohGn8rCim0VyYRNQvrZPEpyvhputrI
r5iv+Wq0KUFscGhhIFRlc3QgKGRlbW8ga2V5KSA8YWxwaGFAZXhhbXBsZS5uZXQ+
iF0EExECABUFAjbjjp4DCwoDAxUDAgMWAgECF4AAEgkQLXJ8x2hpdzQHZUdQRwAB
ATl4AKCBLmRplv/8ZfSqep5IjqEAuaXvWwCgl6NEzT+/WewPTGcwZY+pLkycLv20
EEFsaWNlIChkZW1vIGtleSmIXQQTEQIAFQUCNuO2qwMLCgMDFQMCAxYCAQIXgAAS
CRAtcnzHaGl3NAdlR1BHAAEBJ4wAn0x5RWtqCjklzo93B143k4zBvLftAKCFbrlx
lNCUPVsGUir9AzxvP0A3gbQnQWxmYSBUZXN0IChkZW1vIGtleSkgPGFsZmFAZXhh
bXBsZS5uZXQ+iF0EExECABUFAjbjuFgDCwoDAxUDAgMWAgECF4AAEgkQLXJ8x2hp
dzQHZUdQRwABAbfCAKCT8Guo/lZuVYtzb7qPCWa4uDyfwwCfXam5miXQfBXSZx3x
oda1yt8vyXK5AQ0ENuOPDxAEAJyN1x9X9LsjfX2Z8O9s7BzMO9OoOxFtvZw+FA0B
uDs0WVYkq1GuZ9/XiO0K30zvtZnlb7NMvBfz7xbLeYx+vKzy5xkq18+LE5dU+HKK
dRQZKrrwgCsDy8tJRO447QsiLTksCDqPMaE32OCRBF5nKrG5vih7/cmEhf2CuAn+
2yM3AAMHA/0Z5eYysaLnAwPeqQ9vNvUyrCxUEmrvl4svG7zkkg3ZcgAbDpDQUmni
jt3gEBCoAzO3c41TU5wJaUNBEPGPWfKcTlmBEGJWjK50QQuA2diGncxIS5SDs+QV
af434a6/KFVQcCmV7K8/T2S8/nuGJ/rIlFL5XovW6A/S9mYEjh2pD4hOBBgRAgAG
BQI2448PABIJEC1yfMdoaXc0B2VHUEcAAQEgqQCfcDXmD8uNVdKg/C9vqI3JSndq
knsAnRxzVeHi/iJ73OCKtvFrHbV9GogqmQGiBDbjkGcRBAC/DCQungO2iJ7j9+9q
d2crjBU8K+AmQhs27JBkJqtAbC/xFqkHBsA1Pi8Zb6TLa/OCm2PbXFiM5x00wiEn
VKNzuGOzU8uHB6kwWtLj8+V7VOWOkSDEtnlTF6u0y9JOvs7GwDvqOM5C3QH7La+z
nNeAu1527Hj6l0XGSAzyvp+NkwCgnktU11VFpKSIdoplZBayN9OzT8sD/Awc/890
fiSMWYNGo4+n6IHxhjBBM9lL+DAe1RtCEtwUSWNrGsIxFnDRkMxvMpaT4GusG+DP
haTddrDBSyFiCLxKDBYgMbSO6wQ9g6zWEEh1ZMTMVU/akr81DOEColXn/f3Q4sRj
xI3hu2z8tjVewAPNTuWETQ6iHHoVqdpkK4aABACfbMrnfK6TujxSs91MfKBWfYxy
w9hjM6+VV8cJJdDXiheMKzWcrVecwgYYzukmNinO//BRmQcs1wdfi5UdfHLNFDig
w96SdyZpHx+79ghD3NqDmzYakoRIoDKcZAIrAjgfl5if6vIiA4c1LjhSdcVTBsSy
ic/mkk01EgztWKY0abQtQ2hhcmxpZSBUZXN0IChkZW1vIGtleSkgPGNoYXJsaWVA
ZXhhbXBsZS5uZXQ+iF0EExECABUFAjbjkGcDCwoDAxUDAgMWAgECF4AAEgkQQT9K
8xr9q2wHZUdQRwABAT5EAJ9fcDAXA+7n6av9/VJr9a/Sb1PnuACfVMEihQSsyol6
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
=Xw/z
-----END PGP ARMORED FILE-----

View File

@ -1,28 +0,0 @@
This is a test pubring generated by pgp 5 beta
Type Bits KeyID Created Expires Algorithm Use
sec+ 768 439F02CA 1998-03-17 ---------- DSS Sign and Encrypt
sub 768 CB879DE9 1998-03-17 ---------- Diffie-Hellman
uid pgp5 test <pgp5@dev.null>
-----BEGIN PGP ARMORED FILE-----
Version: GNUPG v0.2.13a (Linux)
Comment: This is an alpha version!
Comment: Use "gpgm --dearmor" for unpacking
mQFCBDUOrE4RAwDbbxWAbWsheUJprK6VryMTpwDiYwMfL+92nrHqSfPqlpMWgDTia8qnpRSXbyEm
Sppp/6/Ygp+N3n32Kznq7PjHXiuWLlZGvZMtzmvaMA17y0GY6oLBxS7rhASXIKa9hEUAoP+KBFly
qNMdsK8j+ZO0A8rnImGrAwC1ddDme5iZFkTEWHhrtU97sEu2GDkSQB8HdX8CoRcrOz/B2WliF6qf
BKhcZPFVBIhKNzjTfY7SEYAZk2zcsCm8elnwSLaGEzxKFNFBqKDNXP+a35spcqsHSGzDVw4VuKMD
AJNnAP6skpHlhVAmecLZT9eRzVoOq1ivUIntK2Mh47qsL74q6BBwz2sviPU2Y3pDlbb6Ed0qJAXv
dCT24hlfoGoXzkoDInkPJTJeL0gCnwmQPjvXFFd71Cvg5LaL4lIQLbABh7QZcGdwNSB0ZXN0IDxw
Z3A1QGRldi5udWxsPrABA4kASwQQEQIACwUCNQ6sTgQLAwECAAoJENY0E25DnwLKxIoAoPSyM/Mw
BogpyMU5YY+Sj74k3UIfAJ0RopQa8ciickDVzoSVPrGysrnOkLABZ7kAzQQ1DqxWEAMA/wVrlNsP
qTxWZbUiMrUN8MjTFR2xUhuTw3cdvRgiVPUT/q1l1+I3CpopVBx/XuAkg5sHB80zc6pZg652YFV3
dLoTceS7ridb5k23sHa2hZGCeTo6AdxIOy53giCPDP9FAAICAv9Oh5/OVxUqI+6hsp9ccOEhRA9N
8aJzYDPjvCQyhgej2P1kTsBZqWIx0/PiMvIt+qqhT2YfyD68mHIBztScAXZKTnjroUPKl0+bkX09
NbdyqojAkzhaCRKUzwnaHEfhi2WwAYeJAD8DBRg1DqxW1jQTbkOfAsoRAnaPAJ0Z/k6Y2ypgDhXo
qBLeW7Lq/AKYEACeLTod6Nt117DkqDz9epmIqwWOE1ewAWc=
=6BrN
-----END PGP ARMORED FILE-----

View File

@ -1,11 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
for i in $plain_files ; do
echo "$usrpass1" | $GPG --passphrase-fd 0 --always-trust -seat \
-r two -o x --yes $i
$GPG -o y --yes x
cmp $i y || error "$i: mismatch"
done

View File

@ -1,737 +0,0 @@
26 demo keys (passphrase is "abc"):
sec 1024D/68697734 1999-03-08 Alpha Test (demo key) <alpha@example.net>
uid Alice (demo key)
uid Alfa Test (demo key) <alfa@example.net>
ssb 1024g/46A871F8 1999-03-08
sec 1024D/1AFDAB6C 1999-03-08 Charlie Test (demo key) <charlie@example.net>
ssb 1024g/BC43DA60 1999-03-08
sec 1024D/FAEF6D1B 1999-03-08 Echo Test (demo key) <echo@example.net>
uid Eve (demo key)
uid Echelon (demo key)
ssb 1024g/7272144D 1999-03-08
sec 1024D/8FC282E6 1999-03-08 Golf Test (demo key) <golf@example.net>
ssb 1024g/9DCAD354 1999-03-08
sec 1024D/04259677 1999-03-08 India Test (demo key) <india@example.net>
ssb 1024g/61F76C73 1999-03-08
sec 1024D/43C2D0C7 1999-03-08 Kilo Test (demo key) <kilo@example.net>
ssb 1024g/9AF64D02 1999-03-08
sec 1024D/A9E3B0B2 1999-03-08 Bravo Test (demo key) <bravo@example.net>
uid Bob (demo key)
ssb 1024g/E29BA37F 1999-03-08
sec 1024D/EB9DC9E6 1999-03-08 Delta Test (demo key) <delta@example.net>
ssb 1024g/B0C45424 1999-03-08
sec 1024D/7372E243 1999-03-08 Foxtrot Test (demo key) <foxtrot@example.net>
ssb 1024g/EE45198E 1999-03-08
sec 1024D/34C6E3F1 1999-03-08 Hotel Test (demo key) <hotel@example.net>
ssb 1024g/D622AD0A 1999-03-08
sec 1024D/D2699313 1999-03-08 Juliet Test (demo key) <juliet@example.net>
ssb 1024g/35F8F136 1999-03-08
sec 1024D/B79103F8 1999-03-08 Lima Test (demo key) <lima@example.net>
ssb 1024g/FE56350C 1999-03-08
sec 1024D/BE5CF886 1999-03-08 Mike Test (demo key) <mike@example.net>
uid Mallory (demo key)
ssb 1024g/4F31EAE8 1999-03-08
sec 1024D/30CEC684 1999-03-08 November Test (demo key) <november@example.net>
ssb 1024g/8B70E472 1999-03-08
sec 1024D/6D9732AC 1999-03-08 Oscar Test (demo key) <oscar@example.net>
ssb 1024g/2681619F 1999-03-08
sec 1024D/3FF13206 1999-03-08 Papa test (demo key) <papa@example.net>
ssb 1024g/63330D9C 1999-03-08
sec 1024D/3C661C84 1999-03-08 Quebec Test (demo key) <quebec@example.net>
ssb 1024g/A029ACF4 1999-03-08
sec 1024D/777FBED3 1999-03-08 Romeo Test (demo key) <romeo@example.net>
ssb 1024g/11D102EA 1999-03-08
sec 1024D/A3AE3EA1 1999-03-08 Sierra Test (demo key) <sierra@example.net>
ssb 1024g/0F1B50B4 1999-03-08
sec 1024D/85A81F38 1999-03-08 Tango Test (demo key) <tango@example.net>
ssb 1024g/101C0402 1999-03-08
sec 1024D/653244D6 1999-03-08 Uniform Test (demo key) <uniform@example.net>
ssb 1024g/5522BDB9 1999-03-08
sec 1024D/61F04784 1999-03-08 Victor Test (demo key) <victor@example.org>
ssb 1024g/07287134 1999-03-08
sec 1024D/EC67DBDE 1999-03-08 Whisky Test (demo key) <whisky@example.net>
ssb 1024g/FD6E27F6 1999-03-08
sec 1024D/567FB34A 1999-03-08 XRay Test (demo key) <xray@example.net>
ssb 1024g/41E408BE 1999-03-08
sec 1024D/4B11B25F 1999-03-08 Yankee Test (demo key) <yankee@example.net>
ssb 1024g/F7B080AD 1999-03-08
sec 1024D/54ACD246 1999-03-08 Zulu Test (demo key) <zulu@example.net>
ssb 1024g/A172C881 1999-03-08
-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: GnuPG v0.9.3 (GNU/Linux)
Comment: For info see http://www.gnupg.org
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
=P9+G
-----END PGP PRIVATE KEY BLOCK-----

View File

@ -1,57 +0,0 @@
This is a test secret keyring simply stored by GNUPG so that
it is easier to make diff files.
sec 768G/9D266E0F 1998-04-28 Test one (pp=def) <one@test.nowhere.nil>
sec 800G/2E5FA4F4 1998-04-28 test two (no pp) <two@test.nowhere.nil>
sec 768G/6D11D6D3 1998-04-28 test three (pp=abc) <three@test.nowhere.nil>
-----BEGIN PGP ARMORED FILE-----
Version: GNUPG v0.2.19b (GNU/Linux)
Comment: This is an alpha version!
Comment: Use "gpgm --dearmor" for unpacking
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
tW5GlGnLFCLsPQ==
=VGBx
-----END PGP ARMORED FILE-----

View File

@ -1,27 +0,0 @@
This is a test secring generated by pgp 5 beta
Type Bits KeyID Created Expires Algorithm Use
sec+ 768 439F02CA 1998-03-17 ---------- DSS Sign and Encrypt
sub 768 CB879DE9 1998-03-17 ---------- Diffie-Hellman
uid pgp5 test <pgp5@dev.null>
There is no password on the key
-----BEGIN PGP ARMORED FILE-----
Version: GNUPG v0.2.13a (Linux)
Comment: This is an alpha version!
Comment: Use "gpgm --dearmor" for unpacking
lQFbBDUOrE4RAwDbbxWAbWsheUJprK6VryMTpwDiYwMfL+92nrHqSfPqlpMWgDTia8qnpRSXbyEm
Sppp/6/Ygp+N3n32Kznq7PjHXiuWLlZGvZMtzmvaMA17y0GY6oLBxS7rhASXIKa9hEUAoP+KBFly
qNMdsK8j+ZO0A8rnImGrAwC1ddDme5iZFkTEWHhrtU97sEu2GDkSQB8HdX8CoRcrOz/B2WliF6qf
BKhcZPFVBIhKNzjTfY7SEYAZk2zcsCm8elnwSLaGEzxKFNFBqKDNXP+a35spcqsHSGzDVw4VuKMD
AJNnAP6skpHlhVAmecLZT9eRzVoOq1ivUIntK2Mh47qsL74q6BBwz2sviPU2Y3pDlbb6Ed0qJAXv
dCT24hlfoGoXzkoDInkPJTJeL0gCnwmQPjvXFFd71Cvg5LaL4lIQLQAAn3GbgsWo+7E/hWakzstp
TXzI2kDIDIm0GXBncDUgdGVzdCA8cGdwNUBkZXYubnVsbD6dAO8ENQ6sVhADAP8Fa5TbD6k8VmW1
IjK1DfDI0xUdsVIbk8N3Hb0YIlT1E/6tZdfiNwqaKVQcf17gJIObBwfNM3OqWYOudmBVd3S6E3Hk
u64nW+ZNt7B2toWRgnk6OgHcSDsud4Igjwz/RQACAgL/ToefzlcVKiPuobKfXHDhIUQPTfGic2Az
47wkMoYHo9j9ZE7AWaliMdPz4jLyLfqqoU9mH8g+vJhyAc7UnAF2Sk5466FDypdPm5F9PTW3cqqI
wJM4WgkSlM8J2hxH4YtlAADlG+pxFXNFuDPmcq6jL6dug2ikZ7hcHLAy7DddSS8OAA==
=1UWo
-----END PGP ARMORED FILE-----

View File

@ -1,16 +0,0 @@
#!/bin/sh
set -e
if [ $# != 3 ]; then
echo "Usage: signdemokey name user_id user_id_no"
exit 1
fi
name="$1"
user_id="$2"
user_id_no="$3"
echo "abc" | ../g10/gpg --options ./options --homedir $name \
--sign-key --batch --yes --passphrase-fd 0 $user_id \
$user_id_no sign save

View File

@ -1,22 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
#info Checking signing and encryption for DSA
for i in $plain_files $data_files ; do
$GPG $dsa_keyrings --always-trust -se -o x --yes \
-u "$dsa_usrname1" -r "$dsa_usrname2" $i
$GPG $dsa_keyrings -o y --yes x
cmp $i y || error "$i: mismatch"
done
for da in ripemd160 sha1; do
for i in $plain_files; do
$GPG $dsa_keyrings --always-trust -se -o x --yes --digest-algo $da \
-u "$dsa_usrname1" -r "$dsa_usrname2" $i
$GPG $dsa_keyrings -o y --yes x
cmp $i y || error "$i: mismatch"
# process only the first one
break
done
done

View File

@ -1,13 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
#info Checking signing and encryption
for i in $plain_files $data_files ; do
echo "$usrpass1" | $GPG --passphrase-fd 0 --always-trust \
-se -o x --yes -r "$usrname2" $i
$GPG -o y --yes x
cmp $i y || error "$i: mismatch"
done

View File

@ -1,22 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
#info Checking DSA signatures (default digest algo)
for i in $plain_files $data_files; do
$GPG $dsa_keyrings -s -o x --yes -u $dsa_usrname1 $i
$GPG $dsa_keyrings -o y --yes x
cmp $i y || error "$i: mismatch"
done
for da in ripemd160 sha1; do
for i in $plain_files; do
$GPG $dsa_keyrings --digest-algo $da \
-s -o x --yes -u $dsa_usrname1 $i
$GPG $dsa_keyrings -o y --yes x
cmp $i y || error "$i: mismatch"
# process only the first one
break
done
done

View File

@ -1,26 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
#info Checking signatures
for i in $plain_files $data_files; do
echo "$usrpass1" | $GPG --passphrase-fd 0 -s -o x --yes $i
$GPG -o y --yes x
cmp $i y || error "$i: mismatch"
done
hash_algo_list="ripemd160 sha1 md5"
if have_hash_algo "TIGER192"; then
hash_algo_list="$hash_algo_list tiger192"
fi
for da in $hash_algo_list ; do
for i in $plain_files; do
echo "$usrpass1" | $GPG --passphrase-fd 0 --digest-algo $da \
-s -o x --yes $i
$GPG -o y --yes x
cmp $i y || error "$i: mismatch"
# process only the first one
break
done
done

View File

@ -1,9 +0,0 @@
#!/bin/sh
. $srcdir/defs.inc || exit 3
# print the GPG version
$GPG --version
#fixme: check that the output is correct

File diff suppressed because it is too large Load Diff

View File

@ -1,63 +0,0 @@
# Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
## Process this file with automake to produce Makefile.in
INCLUDES = -I.. -I$(top_srcdir)/include -I$(top_srcdir)/intl
noinst_LIBRARIES = libcipher.a
libcipher_a_SOURCES = cipher.c \
pubkey.c \
md.c \
dynload.c \
bithelp.h \
des.c \
twofish.c \
blowfish.c \
cast5.c \
rijndael.c \
elgamal.c \
elgamal.h \
rsa.c rsa.h \
primegen.c \
random.h \
random.c \
rand-internal.h \
rmd.h \
dsa.h \
dsa.c \
g10c.c \
smallprime.c \
algorithms.h \
rndlinux.c \
rndunix.c \
rndegd.c \
rndw32.c \
md5.c \
rmd160.c \
sha1.c \
tiger.c
EXTRA_libcipher_a_SOURCES = idea-stub.c
libcipher_a_DEPENDENCIES = @IDEA_O@
libcipher_a_LIBADD = @IDEA_O@
tiger.o: $(srcdir)/tiger.c
`echo $(COMPILE) -c $(srcdir)/tiger.c | sed -e 's/-O[2-9s]*/-O1/g' `

View File

@ -1,118 +0,0 @@
/* algorithms.h - prototypes for algorithm functions.
* Copyright (C) 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef GNUPG_ALGORITHMS_H
#define GNUPG_ALGORITHMS_H 1
const char *dynload_enum_module_names (int seq);
const char *
md5_get_info (int algo, size_t *contextsize,
byte **r_asnoid, int *r_asnlen, int *r_mdlen,
void (**r_init)( void *c ),
void (**r_write)( void *c, byte *buf, size_t nbytes ),
void (**r_final)( void *c ),
byte *(**r_read)( void *c )
);
const char *
rmd160_get_info (int algo, size_t *contextsize,
byte **r_asnoid, int *r_asnlen, int *r_mdlen,
void (**r_init)( void *c ),
void (**r_write)( void *c, byte *buf, size_t nbytes ),
void (**r_final)( void *c ),
byte *(**r_read)( void *c )
);
const char *
sha1_get_info (int algo, size_t *contextsize,
byte **r_asnoid, int *r_asnlen, int *r_mdlen,
void (**r_init)( void *c ),
void (**r_write)( void *c, byte *buf, size_t nbytes ),
void (**r_final)( void *c ),
byte *(**r_read)( void *c )
);
const char *
tiger_get_info (int algo, size_t *contextsize,
byte **r_asnoid, int *r_asnlen, int *r_mdlen,
void (**r_init)( void *c ),
void (**r_write)( void *c, byte *buf, size_t nbytes ),
void (**r_final)( void *c ),
byte *(**r_read)( void *c )
);
const char *
des_get_info( int algo, size_t *keylen,
size_t *blocksize, size_t *contextsize,
int (**setkeyf)( void *c, byte *key, unsigned keylen ),
void (**encryptf)( void *c, byte *outbuf, byte *inbuf ),
void (**decryptf)( void *c, byte *outbuf, byte *inbuf )
);
const char *
cast5_get_info( int algo, size_t *keylen,
size_t *blocksize, size_t *contextsize,
int (**setkeyf)( void *c, byte *key, unsigned keylen ),
void (**encryptf)( void *c, byte *outbuf, byte *inbuf ),
void (**decryptf)( void *c, byte *outbuf, byte *inbuf )
);
const char *
blowfish_get_info( int algo, size_t *keylen,
size_t *blocksize, size_t *contextsize,
int (**setkeyf)( void *c, byte *key, unsigned keylen ),
void (**encryptf)( void *c, byte *outbuf, byte *inbuf ),
void (**decryptf)( void *c, byte *outbuf, byte *inbuf )
);
const char *
twofish_get_info( int algo, size_t *keylen,
size_t *blocksize, size_t *contextsize,
int (**setkeyf)( void *c, byte *key, unsigned keylen ),
void (**encryptf)( void *c, byte *outbuf, byte *inbuf ),
void (**decryptf)( void *c, byte *outbuf, byte *inbuf )
);
/* this is just a kludge for the time we have not yet changed the cipher
* stuff to the scheme we use for random and digests */
const char *
rijndael_get_info( int algo, size_t *keylen,
size_t *blocksize, size_t *contextsize,
int (**setkeyf)( void *c, byte *key, unsigned keylen ),
void (**encryptf)( void *c, byte *outbuf, byte *inbuf ),
void (**decryptf)( void *c, byte *outbuf, byte *inbuf )
);
const char *
idea_get_info( int algo, size_t *keylen,
size_t *blocksize, size_t *contextsize,
int (**setkeyf)( void *c, byte *key, unsigned keylen ),
void (**encryptf)( void *c, byte *outbuf, byte *inbuf ),
void (**decryptf)( void *c, byte *outbuf, byte *inbuf )
);
#endif /*GNUPG_ALGORITHMS_H*/

View File

@ -1,41 +0,0 @@
/* bithelp.h - Some bit manipulation helpers
* Copyright (C) 1999 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef G10_BITHELP_H
#define G10_BITHELP_H
/****************
* Rotate a 32 bit integer by n bytes
*/
#if defined(__GNUC__) && defined(__i386__)
static inline u32
rol( u32 x, int n)
{
__asm__("roll %%cl,%0"
:"=r" (x)
:"0" (x),"c" (n));
return x;
}
#else
#define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) )
#endif
#endif /*G10_BITHELP_H*/

View File

@ -1,632 +0,0 @@
/* blowfish.c - Blowfish encryption
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* For a description of the algorithm, see:
* Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
* ISBN 0-471-11709-9. Pages 336 ff.
*/
/* Test values:
* key "abcdefghijklmnopqrstuvwxyz";
* plain "BLOWFISH"
* cipher 32 4E D0 FE F4 13 A2 03
*
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "types.h"
#include "errors.h"
#include "algorithms.h"
#define CIPHER_ALGO_BLOWFISH 4 /* blowfish 128 bit key */
#define BLOWFISH_BLOCKSIZE 8
#define BLOWFISH_ROUNDS 16
typedef struct {
u32 s0[256];
u32 s1[256];
u32 s2[256];
u32 s3[256];
u32 p[BLOWFISH_ROUNDS+2];
} BLOWFISH_context;
static int bf_setkey( BLOWFISH_context *c, byte *key, unsigned keylen );
static void encrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf );
static void decrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf );
/* precomputed S boxes */
static const u32 ks0[256] = {
0xD1310BA6,0x98DFB5AC,0x2FFD72DB,0xD01ADFB7,0xB8E1AFED,0x6A267E96,
0xBA7C9045,0xF12C7F99,0x24A19947,0xB3916CF7,0x0801F2E2,0x858EFC16,
0x636920D8,0x71574E69,0xA458FEA3,0xF4933D7E,0x0D95748F,0x728EB658,
0x718BCD58,0x82154AEE,0x7B54A41D,0xC25A59B5,0x9C30D539,0x2AF26013,
0xC5D1B023,0x286085F0,0xCA417918,0xB8DB38EF,0x8E79DCB0,0x603A180E,
0x6C9E0E8B,0xB01E8A3E,0xD71577C1,0xBD314B27,0x78AF2FDA,0x55605C60,
0xE65525F3,0xAA55AB94,0x57489862,0x63E81440,0x55CA396A,0x2AAB10B6,
0xB4CC5C34,0x1141E8CE,0xA15486AF,0x7C72E993,0xB3EE1411,0x636FBC2A,
0x2BA9C55D,0x741831F6,0xCE5C3E16,0x9B87931E,0xAFD6BA33,0x6C24CF5C,
0x7A325381,0x28958677,0x3B8F4898,0x6B4BB9AF,0xC4BFE81B,0x66282193,
0x61D809CC,0xFB21A991,0x487CAC60,0x5DEC8032,0xEF845D5D,0xE98575B1,
0xDC262302,0xEB651B88,0x23893E81,0xD396ACC5,0x0F6D6FF3,0x83F44239,
0x2E0B4482,0xA4842004,0x69C8F04A,0x9E1F9B5E,0x21C66842,0xF6E96C9A,
0x670C9C61,0xABD388F0,0x6A51A0D2,0xD8542F68,0x960FA728,0xAB5133A3,
0x6EEF0B6C,0x137A3BE4,0xBA3BF050,0x7EFB2A98,0xA1F1651D,0x39AF0176,
0x66CA593E,0x82430E88,0x8CEE8619,0x456F9FB4,0x7D84A5C3,0x3B8B5EBE,
0xE06F75D8,0x85C12073,0x401A449F,0x56C16AA6,0x4ED3AA62,0x363F7706,
0x1BFEDF72,0x429B023D,0x37D0D724,0xD00A1248,0xDB0FEAD3,0x49F1C09B,
0x075372C9,0x80991B7B,0x25D479D8,0xF6E8DEF7,0xE3FE501A,0xB6794C3B,
0x976CE0BD,0x04C006BA,0xC1A94FB6,0x409F60C4,0x5E5C9EC2,0x196A2463,
0x68FB6FAF,0x3E6C53B5,0x1339B2EB,0x3B52EC6F,0x6DFC511F,0x9B30952C,
0xCC814544,0xAF5EBD09,0xBEE3D004,0xDE334AFD,0x660F2807,0x192E4BB3,
0xC0CBA857,0x45C8740F,0xD20B5F39,0xB9D3FBDB,0x5579C0BD,0x1A60320A,
0xD6A100C6,0x402C7279,0x679F25FE,0xFB1FA3CC,0x8EA5E9F8,0xDB3222F8,
0x3C7516DF,0xFD616B15,0x2F501EC8,0xAD0552AB,0x323DB5FA,0xFD238760,
0x53317B48,0x3E00DF82,0x9E5C57BB,0xCA6F8CA0,0x1A87562E,0xDF1769DB,
0xD542A8F6,0x287EFFC3,0xAC6732C6,0x8C4F5573,0x695B27B0,0xBBCA58C8,
0xE1FFA35D,0xB8F011A0,0x10FA3D98,0xFD2183B8,0x4AFCB56C,0x2DD1D35B,
0x9A53E479,0xB6F84565,0xD28E49BC,0x4BFB9790,0xE1DDF2DA,0xA4CB7E33,
0x62FB1341,0xCEE4C6E8,0xEF20CADA,0x36774C01,0xD07E9EFE,0x2BF11FB4,
0x95DBDA4D,0xAE909198,0xEAAD8E71,0x6B93D5A0,0xD08ED1D0,0xAFC725E0,
0x8E3C5B2F,0x8E7594B7,0x8FF6E2FB,0xF2122B64,0x8888B812,0x900DF01C,
0x4FAD5EA0,0x688FC31C,0xD1CFF191,0xB3A8C1AD,0x2F2F2218,0xBE0E1777,
0xEA752DFE,0x8B021FA1,0xE5A0CC0F,0xB56F74E8,0x18ACF3D6,0xCE89E299,
0xB4A84FE0,0xFD13E0B7,0x7CC43B81,0xD2ADA8D9,0x165FA266,0x80957705,
0x93CC7314,0x211A1477,0xE6AD2065,0x77B5FA86,0xC75442F5,0xFB9D35CF,
0xEBCDAF0C,0x7B3E89A0,0xD6411BD3,0xAE1E7E49,0x00250E2D,0x2071B35E,
0x226800BB,0x57B8E0AF,0x2464369B,0xF009B91E,0x5563911D,0x59DFA6AA,
0x78C14389,0xD95A537F,0x207D5BA2,0x02E5B9C5,0x83260376,0x6295CFA9,
0x11C81968,0x4E734A41,0xB3472DCA,0x7B14A94A,0x1B510052,0x9A532915,
0xD60F573F,0xBC9BC6E4,0x2B60A476,0x81E67400,0x08BA6FB5,0x571BE91F,
0xF296EC6B,0x2A0DD915,0xB6636521,0xE7B9F9B6,0xFF34052E,0xC5855664,
0x53B02D5D,0xA99F8FA1,0x08BA4799,0x6E85076A };
static const u32 ks1[256] = {
0x4B7A70E9,0xB5B32944,0xDB75092E,0xC4192623,0xAD6EA6B0,0x49A7DF7D,
0x9CEE60B8,0x8FEDB266,0xECAA8C71,0x699A17FF,0x5664526C,0xC2B19EE1,
0x193602A5,0x75094C29,0xA0591340,0xE4183A3E,0x3F54989A,0x5B429D65,
0x6B8FE4D6,0x99F73FD6,0xA1D29C07,0xEFE830F5,0x4D2D38E6,0xF0255DC1,
0x4CDD2086,0x8470EB26,0x6382E9C6,0x021ECC5E,0x09686B3F,0x3EBAEFC9,
0x3C971814,0x6B6A70A1,0x687F3584,0x52A0E286,0xB79C5305,0xAA500737,
0x3E07841C,0x7FDEAE5C,0x8E7D44EC,0x5716F2B8,0xB03ADA37,0xF0500C0D,
0xF01C1F04,0x0200B3FF,0xAE0CF51A,0x3CB574B2,0x25837A58,0xDC0921BD,
0xD19113F9,0x7CA92FF6,0x94324773,0x22F54701,0x3AE5E581,0x37C2DADC,
0xC8B57634,0x9AF3DDA7,0xA9446146,0x0FD0030E,0xECC8C73E,0xA4751E41,
0xE238CD99,0x3BEA0E2F,0x3280BBA1,0x183EB331,0x4E548B38,0x4F6DB908,
0x6F420D03,0xF60A04BF,0x2CB81290,0x24977C79,0x5679B072,0xBCAF89AF,
0xDE9A771F,0xD9930810,0xB38BAE12,0xDCCF3F2E,0x5512721F,0x2E6B7124,
0x501ADDE6,0x9F84CD87,0x7A584718,0x7408DA17,0xBC9F9ABC,0xE94B7D8C,
0xEC7AEC3A,0xDB851DFA,0x63094366,0xC464C3D2,0xEF1C1847,0x3215D908,
0xDD433B37,0x24C2BA16,0x12A14D43,0x2A65C451,0x50940002,0x133AE4DD,
0x71DFF89E,0x10314E55,0x81AC77D6,0x5F11199B,0x043556F1,0xD7A3C76B,
0x3C11183B,0x5924A509,0xF28FE6ED,0x97F1FBFA,0x9EBABF2C,0x1E153C6E,
0x86E34570,0xEAE96FB1,0x860E5E0A,0x5A3E2AB3,0x771FE71C,0x4E3D06FA,
0x2965DCB9,0x99E71D0F,0x803E89D6,0x5266C825,0x2E4CC978,0x9C10B36A,
0xC6150EBA,0x94E2EA78,0xA5FC3C53,0x1E0A2DF4,0xF2F74EA7,0x361D2B3D,
0x1939260F,0x19C27960,0x5223A708,0xF71312B6,0xEBADFE6E,0xEAC31F66,
0xE3BC4595,0xA67BC883,0xB17F37D1,0x018CFF28,0xC332DDEF,0xBE6C5AA5,
0x65582185,0x68AB9802,0xEECEA50F,0xDB2F953B,0x2AEF7DAD,0x5B6E2F84,
0x1521B628,0x29076170,0xECDD4775,0x619F1510,0x13CCA830,0xEB61BD96,
0x0334FE1E,0xAA0363CF,0xB5735C90,0x4C70A239,0xD59E9E0B,0xCBAADE14,
0xEECC86BC,0x60622CA7,0x9CAB5CAB,0xB2F3846E,0x648B1EAF,0x19BDF0CA,
0xA02369B9,0x655ABB50,0x40685A32,0x3C2AB4B3,0x319EE9D5,0xC021B8F7,
0x9B540B19,0x875FA099,0x95F7997E,0x623D7DA8,0xF837889A,0x97E32D77,
0x11ED935F,0x16681281,0x0E358829,0xC7E61FD6,0x96DEDFA1,0x7858BA99,
0x57F584A5,0x1B227263,0x9B83C3FF,0x1AC24696,0xCDB30AEB,0x532E3054,
0x8FD948E4,0x6DBC3128,0x58EBF2EF,0x34C6FFEA,0xFE28ED61,0xEE7C3C73,
0x5D4A14D9,0xE864B7E3,0x42105D14,0x203E13E0,0x45EEE2B6,0xA3AAABEA,
0xDB6C4F15,0xFACB4FD0,0xC742F442,0xEF6ABBB5,0x654F3B1D,0x41CD2105,
0xD81E799E,0x86854DC7,0xE44B476A,0x3D816250,0xCF62A1F2,0x5B8D2646,
0xFC8883A0,0xC1C7B6A3,0x7F1524C3,0x69CB7492,0x47848A0B,0x5692B285,
0x095BBF00,0xAD19489D,0x1462B174,0x23820E00,0x58428D2A,0x0C55F5EA,
0x1DADF43E,0x233F7061,0x3372F092,0x8D937E41,0xD65FECF1,0x6C223BDB,
0x7CDE3759,0xCBEE7460,0x4085F2A7,0xCE77326E,0xA6078084,0x19F8509E,
0xE8EFD855,0x61D99735,0xA969A7AA,0xC50C06C2,0x5A04ABFC,0x800BCADC,
0x9E447A2E,0xC3453484,0xFDD56705,0x0E1E9EC9,0xDB73DBD3,0x105588CD,
0x675FDA79,0xE3674340,0xC5C43465,0x713E38D8,0x3D28F89E,0xF16DFF20,
0x153E21E7,0x8FB03D4A,0xE6E39F2B,0xDB83ADF7 };
static const u32 ks2[256] = {
0xE93D5A68,0x948140F7,0xF64C261C,0x94692934,0x411520F7,0x7602D4F7,
0xBCF46B2E,0xD4A20068,0xD4082471,0x3320F46A,0x43B7D4B7,0x500061AF,
0x1E39F62E,0x97244546,0x14214F74,0xBF8B8840,0x4D95FC1D,0x96B591AF,
0x70F4DDD3,0x66A02F45,0xBFBC09EC,0x03BD9785,0x7FAC6DD0,0x31CB8504,
0x96EB27B3,0x55FD3941,0xDA2547E6,0xABCA0A9A,0x28507825,0x530429F4,
0x0A2C86DA,0xE9B66DFB,0x68DC1462,0xD7486900,0x680EC0A4,0x27A18DEE,
0x4F3FFEA2,0xE887AD8C,0xB58CE006,0x7AF4D6B6,0xAACE1E7C,0xD3375FEC,
0xCE78A399,0x406B2A42,0x20FE9E35,0xD9F385B9,0xEE39D7AB,0x3B124E8B,
0x1DC9FAF7,0x4B6D1856,0x26A36631,0xEAE397B2,0x3A6EFA74,0xDD5B4332,
0x6841E7F7,0xCA7820FB,0xFB0AF54E,0xD8FEB397,0x454056AC,0xBA489527,
0x55533A3A,0x20838D87,0xFE6BA9B7,0xD096954B,0x55A867BC,0xA1159A58,
0xCCA92963,0x99E1DB33,0xA62A4A56,0x3F3125F9,0x5EF47E1C,0x9029317C,
0xFDF8E802,0x04272F70,0x80BB155C,0x05282CE3,0x95C11548,0xE4C66D22,
0x48C1133F,0xC70F86DC,0x07F9C9EE,0x41041F0F,0x404779A4,0x5D886E17,
0x325F51EB,0xD59BC0D1,0xF2BCC18F,0x41113564,0x257B7834,0x602A9C60,
0xDFF8E8A3,0x1F636C1B,0x0E12B4C2,0x02E1329E,0xAF664FD1,0xCAD18115,
0x6B2395E0,0x333E92E1,0x3B240B62,0xEEBEB922,0x85B2A20E,0xE6BA0D99,
0xDE720C8C,0x2DA2F728,0xD0127845,0x95B794FD,0x647D0862,0xE7CCF5F0,
0x5449A36F,0x877D48FA,0xC39DFD27,0xF33E8D1E,0x0A476341,0x992EFF74,
0x3A6F6EAB,0xF4F8FD37,0xA812DC60,0xA1EBDDF8,0x991BE14C,0xDB6E6B0D,
0xC67B5510,0x6D672C37,0x2765D43B,0xDCD0E804,0xF1290DC7,0xCC00FFA3,
0xB5390F92,0x690FED0B,0x667B9FFB,0xCEDB7D9C,0xA091CF0B,0xD9155EA3,
0xBB132F88,0x515BAD24,0x7B9479BF,0x763BD6EB,0x37392EB3,0xCC115979,
0x8026E297,0xF42E312D,0x6842ADA7,0xC66A2B3B,0x12754CCC,0x782EF11C,
0x6A124237,0xB79251E7,0x06A1BBE6,0x4BFB6350,0x1A6B1018,0x11CAEDFA,
0x3D25BDD8,0xE2E1C3C9,0x44421659,0x0A121386,0xD90CEC6E,0xD5ABEA2A,
0x64AF674E,0xDA86A85F,0xBEBFE988,0x64E4C3FE,0x9DBC8057,0xF0F7C086,
0x60787BF8,0x6003604D,0xD1FD8346,0xF6381FB0,0x7745AE04,0xD736FCCC,
0x83426B33,0xF01EAB71,0xB0804187,0x3C005E5F,0x77A057BE,0xBDE8AE24,
0x55464299,0xBF582E61,0x4E58F48F,0xF2DDFDA2,0xF474EF38,0x8789BDC2,
0x5366F9C3,0xC8B38E74,0xB475F255,0x46FCD9B9,0x7AEB2661,0x8B1DDF84,
0x846A0E79,0x915F95E2,0x466E598E,0x20B45770,0x8CD55591,0xC902DE4C,
0xB90BACE1,0xBB8205D0,0x11A86248,0x7574A99E,0xB77F19B6,0xE0A9DC09,
0x662D09A1,0xC4324633,0xE85A1F02,0x09F0BE8C,0x4A99A025,0x1D6EFE10,
0x1AB93D1D,0x0BA5A4DF,0xA186F20F,0x2868F169,0xDCB7DA83,0x573906FE,
0xA1E2CE9B,0x4FCD7F52,0x50115E01,0xA70683FA,0xA002B5C4,0x0DE6D027,
0x9AF88C27,0x773F8641,0xC3604C06,0x61A806B5,0xF0177A28,0xC0F586E0,
0x006058AA,0x30DC7D62,0x11E69ED7,0x2338EA63,0x53C2DD94,0xC2C21634,
0xBBCBEE56,0x90BCB6DE,0xEBFC7DA1,0xCE591D76,0x6F05E409,0x4B7C0188,
0x39720A3D,0x7C927C24,0x86E3725F,0x724D9DB9,0x1AC15BB4,0xD39EB8FC,
0xED545578,0x08FCA5B5,0xD83D7CD3,0x4DAD0FC4,0x1E50EF5E,0xB161E6F8,
0xA28514D9,0x6C51133C,0x6FD5C7E7,0x56E14EC4,0x362ABFCE,0xDDC6C837,
0xD79A3234,0x92638212,0x670EFA8E,0x406000E0 };
static const u32 ks3[256] = {
0x3A39CE37,0xD3FAF5CF,0xABC27737,0x5AC52D1B,0x5CB0679E,0x4FA33742,
0xD3822740,0x99BC9BBE,0xD5118E9D,0xBF0F7315,0xD62D1C7E,0xC700C47B,
0xB78C1B6B,0x21A19045,0xB26EB1BE,0x6A366EB4,0x5748AB2F,0xBC946E79,
0xC6A376D2,0x6549C2C8,0x530FF8EE,0x468DDE7D,0xD5730A1D,0x4CD04DC6,
0x2939BBDB,0xA9BA4650,0xAC9526E8,0xBE5EE304,0xA1FAD5F0,0x6A2D519A,
0x63EF8CE2,0x9A86EE22,0xC089C2B8,0x43242EF6,0xA51E03AA,0x9CF2D0A4,
0x83C061BA,0x9BE96A4D,0x8FE51550,0xBA645BD6,0x2826A2F9,0xA73A3AE1,
0x4BA99586,0xEF5562E9,0xC72FEFD3,0xF752F7DA,0x3F046F69,0x77FA0A59,
0x80E4A915,0x87B08601,0x9B09E6AD,0x3B3EE593,0xE990FD5A,0x9E34D797,
0x2CF0B7D9,0x022B8B51,0x96D5AC3A,0x017DA67D,0xD1CF3ED6,0x7C7D2D28,
0x1F9F25CF,0xADF2B89B,0x5AD6B472,0x5A88F54C,0xE029AC71,0xE019A5E6,
0x47B0ACFD,0xED93FA9B,0xE8D3C48D,0x283B57CC,0xF8D56629,0x79132E28,
0x785F0191,0xED756055,0xF7960E44,0xE3D35E8C,0x15056DD4,0x88F46DBA,
0x03A16125,0x0564F0BD,0xC3EB9E15,0x3C9057A2,0x97271AEC,0xA93A072A,
0x1B3F6D9B,0x1E6321F5,0xF59C66FB,0x26DCF319,0x7533D928,0xB155FDF5,
0x03563482,0x8ABA3CBB,0x28517711,0xC20AD9F8,0xABCC5167,0xCCAD925F,
0x4DE81751,0x3830DC8E,0x379D5862,0x9320F991,0xEA7A90C2,0xFB3E7BCE,
0x5121CE64,0x774FBE32,0xA8B6E37E,0xC3293D46,0x48DE5369,0x6413E680,
0xA2AE0810,0xDD6DB224,0x69852DFD,0x09072166,0xB39A460A,0x6445C0DD,
0x586CDECF,0x1C20C8AE,0x5BBEF7DD,0x1B588D40,0xCCD2017F,0x6BB4E3BB,
0xDDA26A7E,0x3A59FF45,0x3E350A44,0xBCB4CDD5,0x72EACEA8,0xFA6484BB,
0x8D6612AE,0xBF3C6F47,0xD29BE463,0x542F5D9E,0xAEC2771B,0xF64E6370,
0x740E0D8D,0xE75B1357,0xF8721671,0xAF537D5D,0x4040CB08,0x4EB4E2CC,
0x34D2466A,0x0115AF84,0xE1B00428,0x95983A1D,0x06B89FB4,0xCE6EA048,
0x6F3F3B82,0x3520AB82,0x011A1D4B,0x277227F8,0x611560B1,0xE7933FDC,
0xBB3A792B,0x344525BD,0xA08839E1,0x51CE794B,0x2F32C9B7,0xA01FBAC9,
0xE01CC87E,0xBCC7D1F6,0xCF0111C3,0xA1E8AAC7,0x1A908749,0xD44FBD9A,
0xD0DADECB,0xD50ADA38,0x0339C32A,0xC6913667,0x8DF9317C,0xE0B12B4F,
0xF79E59B7,0x43F5BB3A,0xF2D519FF,0x27D9459C,0xBF97222C,0x15E6FC2A,
0x0F91FC71,0x9B941525,0xFAE59361,0xCEB69CEB,0xC2A86459,0x12BAA8D1,
0xB6C1075E,0xE3056A0C,0x10D25065,0xCB03A442,0xE0EC6E0E,0x1698DB3B,
0x4C98A0BE,0x3278E964,0x9F1F9532,0xE0D392DF,0xD3A0342B,0x8971F21E,
0x1B0A7441,0x4BA3348C,0xC5BE7120,0xC37632D8,0xDF359F8D,0x9B992F2E,
0xE60B6F47,0x0FE3F11D,0xE54CDA54,0x1EDAD891,0xCE6279CF,0xCD3E7E6F,
0x1618B166,0xFD2C1D05,0x848FD2C5,0xF6FB2299,0xF523F357,0xA6327623,
0x93A83531,0x56CCCD02,0xACF08162,0x5A75EBB5,0x6E163697,0x88D273CC,
0xDE966292,0x81B949D0,0x4C50901B,0x71C65614,0xE6C6C7BD,0x327A140A,
0x45E1D006,0xC3F27B9A,0xC9AA53FD,0x62A80F00,0xBB25BFE2,0x35BDD2F6,
0x71126905,0xB2040222,0xB6CBCF7C,0xCD769C2B,0x53113EC0,0x1640E3D3,
0x38ABBD60,0x2547ADF0,0xBA38209C,0xF746CE76,0x77AFA1C5,0x20756060,
0x85CBFE4E,0x8AE88DD8,0x7AAAF9B0,0x4CF9AA7E,0x1948C25C,0x02FB8A8C,
0x01C36AE4,0xD6EBE1F9,0x90D4F869,0xA65CDEA0,0x3F09252D,0xC208E69F,
0xB74E6132,0xCE77E25B,0x578FDFE3,0x3AC372E6 };
static const u32 ps[BLOWFISH_ROUNDS+2] = {
0x243F6A88,0x85A308D3,0x13198A2E,0x03707344,0xA4093822,0x299F31D0,
0x082EFA98,0xEC4E6C89,0x452821E6,0x38D01377,0xBE5466CF,0x34E90C6C,
0xC0AC29B7,0xC97C50DD,0x3F84D5B5,0xB5470917,0x9216D5D9,0x8979FB1B };
#if BLOWFISH_ROUNDS != 16
static inline u32
function_F( BLOWFISH_context *bc, u32 x )
{
u16 a, b, c, d;
#ifdef BIG_ENDIAN_HOST
a = ((byte*)&x)[0];
b = ((byte*)&x)[1];
c = ((byte*)&x)[2];
d = ((byte*)&x)[3];
#else
a = ((byte*)&x)[3];
b = ((byte*)&x)[2];
c = ((byte*)&x)[1];
d = ((byte*)&x)[0];
#endif
return ((bc->s0[a] + bc->s1[b]) ^ bc->s2[c] ) + bc->s3[d];
}
#endif
#ifdef BIG_ENDIAN_HOST
#define F(x) ((( s0[((byte*)&x)[0]] + s1[((byte*)&x)[1]]) \
^ s2[((byte*)&x)[2]]) + s3[((byte*)&x)[3]] )
#else
#define F(x) ((( s0[((byte*)&x)[3]] + s1[((byte*)&x)[2]]) \
^ s2[((byte*)&x)[1]]) + s3[((byte*)&x)[0]] )
#endif
#define R(l,r,i) do { l ^= p[i]; r ^= F(l); } while(0)
static void
burn_stack (int bytes)
{
char buf[64];
memset (buf, 0, sizeof buf);
bytes -= sizeof buf;
if (bytes > 0)
burn_stack (bytes);
}
static void
do_encrypt( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
{
#if BLOWFISH_ROUNDS == 16
u32 xl, xr, *s0, *s1, *s2, *s3, *p;
xl = *ret_xl;
xr = *ret_xr;
p = bc->p;
s0 = bc->s0;
s1 = bc->s1;
s2 = bc->s2;
s3 = bc->s3;
R( xl, xr, 0);
R( xr, xl, 1);
R( xl, xr, 2);
R( xr, xl, 3);
R( xl, xr, 4);
R( xr, xl, 5);
R( xl, xr, 6);
R( xr, xl, 7);
R( xl, xr, 8);
R( xr, xl, 9);
R( xl, xr, 10);
R( xr, xl, 11);
R( xl, xr, 12);
R( xr, xl, 13);
R( xl, xr, 14);
R( xr, xl, 15);
xl ^= p[BLOWFISH_ROUNDS];
xr ^= p[BLOWFISH_ROUNDS+1];
*ret_xl = xr;
*ret_xr = xl;
#else
u32 xl, xr, temp, *p;
int i;
xl = *ret_xl;
xr = *ret_xr;
p = bc->p;
for(i=0; i < BLOWFISH_ROUNDS; i++ ) {
xl ^= p[i];
xr ^= function_F(bc, xl);
temp = xl;
xl = xr;
xr = temp;
}
temp = xl;
xl = xr;
xr = temp;
xr ^= p[BLOWFISH_ROUNDS];
xl ^= p[BLOWFISH_ROUNDS+1];
*ret_xl = xl;
*ret_xr = xr;
#endif
}
static void
decrypt( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
{
#if BLOWFISH_ROUNDS == 16
u32 xl, xr, *s0, *s1, *s2, *s3, *p;
xl = *ret_xl;
xr = *ret_xr;
p = bc->p;
s0 = bc->s0;
s1 = bc->s1;
s2 = bc->s2;
s3 = bc->s3;
R( xl, xr, 17);
R( xr, xl, 16);
R( xl, xr, 15);
R( xr, xl, 14);
R( xl, xr, 13);
R( xr, xl, 12);
R( xl, xr, 11);
R( xr, xl, 10);
R( xl, xr, 9);
R( xr, xl, 8);
R( xl, xr, 7);
R( xr, xl, 6);
R( xl, xr, 5);
R( xr, xl, 4);
R( xl, xr, 3);
R( xr, xl, 2);
xl ^= p[1];
xr ^= p[0];
*ret_xl = xr;
*ret_xr = xl;
#else
u32 xl, xr, temp, *p;
int i;
xl = *ret_xl;
xr = *ret_xr;
p = bc->p;
for(i=BLOWFISH_ROUNDS+1; i > 1; i-- ) {
xl ^= p[i];
xr ^= function_F(bc, xl);
temp = xl;
xl = xr;
xr = temp;
}
temp = xl;
xl = xr;
xr = temp;
xr ^= p[1];
xl ^= p[0];
*ret_xl = xl;
*ret_xr = xr;
#endif
}
#undef F
#undef R
static void
do_encrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf )
{
u32 d1, d2;
d1 = inbuf[0] << 24 | inbuf[1] << 16 | inbuf[2] << 8 | inbuf[3];
d2 = inbuf[4] << 24 | inbuf[5] << 16 | inbuf[6] << 8 | inbuf[7];
do_encrypt( bc, &d1, &d2 );
outbuf[0] = (d1 >> 24) & 0xff;
outbuf[1] = (d1 >> 16) & 0xff;
outbuf[2] = (d1 >> 8) & 0xff;
outbuf[3] = d1 & 0xff;
outbuf[4] = (d2 >> 24) & 0xff;
outbuf[5] = (d2 >> 16) & 0xff;
outbuf[6] = (d2 >> 8) & 0xff;
outbuf[7] = d2 & 0xff;
}
static void
encrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf )
{
do_encrypt_block (bc, outbuf, inbuf);
burn_stack (64);
}
static void
do_decrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf )
{
u32 d1, d2;
d1 = inbuf[0] << 24 | inbuf[1] << 16 | inbuf[2] << 8 | inbuf[3];
d2 = inbuf[4] << 24 | inbuf[5] << 16 | inbuf[6] << 8 | inbuf[7];
decrypt( bc, &d1, &d2 );
outbuf[0] = (d1 >> 24) & 0xff;
outbuf[1] = (d1 >> 16) & 0xff;
outbuf[2] = (d1 >> 8) & 0xff;
outbuf[3] = d1 & 0xff;
outbuf[4] = (d2 >> 24) & 0xff;
outbuf[5] = (d2 >> 16) & 0xff;
outbuf[6] = (d2 >> 8) & 0xff;
outbuf[7] = d2 & 0xff;
}
static void
decrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf )
{
do_decrypt_block (bc, outbuf, inbuf);
burn_stack (64);
}
static const char*
selftest(void)
{
BLOWFISH_context c;
byte plain[] = "BLOWFISH";
byte buffer[8];
byte plain3[] = { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 };
byte key3[] = { 0x41, 0x79, 0x6E, 0xA0, 0x52, 0x61, 0x6E, 0xE4 };
byte cipher3[] = { 0xE1, 0x13, 0xF4, 0x10, 0x2C, 0xFC, 0xCE, 0x43 };
bf_setkey( &c, "abcdefghijklmnopqrstuvwxyz", 26 );
encrypt_block( &c, buffer, plain );
if( memcmp( buffer, "\x32\x4E\xD0\xFE\xF4\x13\xA2\x03", 8 ) )
return "Blowfish selftest failed (1).";
decrypt_block( &c, buffer, buffer );
if( memcmp( buffer, plain, 8 ) )
return "Blowfish selftest failed (2).";
bf_setkey( &c, key3, 8 );
encrypt_block( &c, buffer, plain3 );
if( memcmp( buffer, cipher3, 8 ) )
return "Blowfish selftest failed (3).";
decrypt_block( &c, buffer, buffer );
if( memcmp( buffer, plain3, 8 ) )
return "Blowfish selftest failed (4).";
return NULL;
}
#ifdef __riscos__
/* need to switch off CSE optimisation for Norcroft C (Acorn/Pace) */
#pragma no_optimise_cse
#endif /* __riscos__ */
static int
do_bf_setkey( BLOWFISH_context *c, byte *key, unsigned keylen )
{
int i, j;
u32 data, datal, datar;
static int initialized;
static const char *selftest_failed;
if( !initialized ) {
initialized = 1;
selftest_failed = selftest();
if( selftest_failed )
fprintf(stderr,"%s\n", selftest_failed );
}
if( selftest_failed )
return G10ERR_SELFTEST_FAILED;
for(i=0; i < BLOWFISH_ROUNDS+2; i++ )
c->p[i] = ps[i];
for(i=0; i < 256; i++ ) {
c->s0[i] = ks0[i];
c->s1[i] = ks1[i];
c->s2[i] = ks2[i];
c->s3[i] = ks3[i];
}
for(i=j=0; i < BLOWFISH_ROUNDS+2; i++ ) {
#ifdef BIG_ENDIAN_HOST
((byte*)&data)[0] = key[j];
((byte*)&data)[1] = key[(j+1)%keylen];
((byte*)&data)[2] = key[(j+2)%keylen];
((byte*)&data)[3] = key[(j+3)%keylen];
#else
((byte*)&data)[3] = key[j];
((byte*)&data)[2] = key[(j+1)%keylen];
((byte*)&data)[1] = key[(j+2)%keylen];
((byte*)&data)[0] = key[(j+3)%keylen];
#endif
c->p[i] ^= data;
j = (j+4) % keylen;
}
datal = datar = 0;
for(i=0; i < BLOWFISH_ROUNDS+2; i += 2 ) {
do_encrypt( c, &datal, &datar );
c->p[i] = datal;
c->p[i+1] = datar;
}
for(i=0; i < 256; i += 2 ) {
do_encrypt( c, &datal, &datar );
c->s0[i] = datal;
c->s0[i+1] = datar;
}
for(i=0; i < 256; i += 2 ) {
do_encrypt( c, &datal, &datar );
c->s1[i] = datal;
c->s1[i+1] = datar;
}
for(i=0; i < 256; i += 2 ) {
do_encrypt( c, &datal, &datar );
c->s2[i] = datal;
c->s2[i+1] = datar;
}
for(i=0; i < 256; i += 2 ) {
do_encrypt( c, &datal, &datar );
c->s3[i] = datal;
c->s3[i+1] = datar;
}
/* Check for weak key. A weak key is a key in which a value in */
/* the P-array (here c) occurs more than once per table. */
for(i=0; i < 255; i++ ) {
for( j=i+1; j < 256; j++) {
if( (c->s0[i] == c->s0[j]) || (c->s1[i] == c->s1[j]) ||
(c->s2[i] == c->s2[j]) || (c->s3[i] == c->s3[j]) )
return G10ERR_WEAK_KEY;
}
}
return 0;
}
#ifdef __riscos__
#pragma optimise_cse
#endif /* __riscos__ */
static int
bf_setkey( BLOWFISH_context *c, byte *key, unsigned keylen )
{
int rc = do_bf_setkey (c, key, keylen);
burn_stack (64);
return rc;
}
/****************
* Return some information about the algorithm. We need algo here to
* distinguish different flavors of the algorithm.
* Returns: A pointer to string describing the algorithm or NULL if
* the ALGO is invalid.
*/
const char *
blowfish_get_info( int algo, size_t *keylen,
size_t *blocksize, size_t *contextsize,
int (**r_setkey)( void *c, byte *key, unsigned keylen ),
void (**r_encrypt)( void *c, byte *outbuf, byte *inbuf ),
void (**r_decrypt)( void *c, byte *outbuf, byte *inbuf )
)
{
*keylen = 128;
*blocksize = BLOWFISH_BLOCKSIZE;
*contextsize = sizeof(BLOWFISH_context);
*(int (**)(BLOWFISH_context*, byte*, unsigned))r_setkey
= bf_setkey;
*(void (**)(BLOWFISH_context*, byte*, byte*))r_encrypt
= encrypt_block;
*(void (**)(BLOWFISH_context*, byte*, byte*))r_decrypt
= decrypt_block;
if( algo == CIPHER_ALGO_BLOWFISH )
return "BLOWFISH";
return NULL;
}

View File

@ -1,654 +0,0 @@
/* cast5.c - CAST5 cipher (RFC2144)
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/* Test vectors:
*
* 128-bit key = 01 23 45 67 12 34 56 78 23 45 67 89 34 56 78 9A
* plaintext = 01 23 45 67 89 AB CD EF
* ciphertext = 23 8B 4F E5 84 7E 44 B2
*
* 80-bit key = 01 23 45 67 12 34 56 78 23 45
* = 01 23 45 67 12 34 56 78 23 45 00 00 00 00 00 00
* plaintext = 01 23 45 67 89 AB CD EF
* ciphertext = EB 6A 71 1A 2C 02 27 1B
*
* 40-bit key = 01 23 45 67 12
* = 01 23 45 67 12 00 00 00 00 00 00 00 00 00 00 00
* plaintext = 01 23 45 67 89 AB CD EF
* ciphertext = 7A C8 16 D1 6E 9B 30 2E
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "errors.h"
#include "algorithms.h"
#define CIPHER_ALGO_CAST5 3
#define CAST5_BLOCKSIZE 8
typedef struct {
u32 Km[16];
byte Kr[16];
} CAST5_context;
static int cast_setkey( CAST5_context *c, byte *key, unsigned keylen );
static void encrypt_block( CAST5_context *bc, byte *outbuf, byte *inbuf );
static void decrypt_block( CAST5_context *bc, byte *outbuf, byte *inbuf );
static const u32 s1[256] = {
0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf
};
static const u32 s2[256] = {
0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1
};
static const u32 s3[256] = {
0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783
};
static const u32 s4[256] = {
0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2
};
static const u32 s5[256] = {
0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4
};
static const u32 s6[256] = {
0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f
};
static const u32 s7[256] = {
0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3
};
static const u32 s8[256] = {
0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e
};
#if defined(__GNUC__) && defined(__i386__)
static inline u32
rol(int n, u32 x)
{
__asm__("roll %%cl,%0"
:"=r" (x)
:"0" (x),"c" (n));
return x;
}
#else
#define rol(n,x) ( ((x) << (n)) | ((x) >> (32-(n))) )
#endif
#define F1(D,m,r) ( (I = ((m) + (D))), (I=rol((r),I)), \
(((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff]) )
#define F2(D,m,r) ( (I = ((m) ^ (D))), (I=rol((r),I)), \
(((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff]) )
#define F3(D,m,r) ( (I = ((m) - (D))), (I=rol((r),I)), \
(((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff]) )
static void
burn_stack (int bytes)
{
char buf[64];
memset (buf, 0, sizeof buf);
bytes -= sizeof buf;
if (bytes > 0)
burn_stack (bytes);
}
static void
do_encrypt_block( CAST5_context *c, byte *outbuf, byte *inbuf )
{
u32 l, r, t;
u32 I; /* used by the Fx macros */
u32 *Km;
byte *Kr;
Km = c->Km;
Kr = c->Kr;
/* (L0,R0) <-- (m1...m64). (Split the plaintext into left and
* right 32-bit halves L0 = m1...m32 and R0 = m33...m64.)
*/
l = inbuf[0] << 24 | inbuf[1] << 16 | inbuf[2] << 8 | inbuf[3];
r = inbuf[4] << 24 | inbuf[5] << 16 | inbuf[6] << 8 | inbuf[7];
/* (16 rounds) for i from 1 to 16, compute Li and Ri as follows:
* Li = Ri-1;
* Ri = Li-1 ^ f(Ri-1,Kmi,Kri), where f is defined in Section 2.2
* Rounds 1, 4, 7, 10, 13, and 16 use f function Type 1.
* Rounds 2, 5, 8, 11, and 14 use f function Type 2.
* Rounds 3, 6, 9, 12, and 15 use f function Type 3.
*/
t = l; l = r; r = t ^ F1(r, Km[ 0], Kr[ 0]);
t = l; l = r; r = t ^ F2(r, Km[ 1], Kr[ 1]);
t = l; l = r; r = t ^ F3(r, Km[ 2], Kr[ 2]);
t = l; l = r; r = t ^ F1(r, Km[ 3], Kr[ 3]);
t = l; l = r; r = t ^ F2(r, Km[ 4], Kr[ 4]);
t = l; l = r; r = t ^ F3(r, Km[ 5], Kr[ 5]);
t = l; l = r; r = t ^ F1(r, Km[ 6], Kr[ 6]);
t = l; l = r; r = t ^ F2(r, Km[ 7], Kr[ 7]);
t = l; l = r; r = t ^ F3(r, Km[ 8], Kr[ 8]);
t = l; l = r; r = t ^ F1(r, Km[ 9], Kr[ 9]);
t = l; l = r; r = t ^ F2(r, Km[10], Kr[10]);
t = l; l = r; r = t ^ F3(r, Km[11], Kr[11]);
t = l; l = r; r = t ^ F1(r, Km[12], Kr[12]);
t = l; l = r; r = t ^ F2(r, Km[13], Kr[13]);
t = l; l = r; r = t ^ F3(r, Km[14], Kr[14]);
t = l; l = r; r = t ^ F1(r, Km[15], Kr[15]);
/* c1...c64 <-- (R16,L16). (Exchange final blocks L16, R16 and
* concatenate to form the ciphertext.) */
outbuf[0] = (r >> 24) & 0xff;
outbuf[1] = (r >> 16) & 0xff;
outbuf[2] = (r >> 8) & 0xff;
outbuf[3] = r & 0xff;
outbuf[4] = (l >> 24) & 0xff;
outbuf[5] = (l >> 16) & 0xff;
outbuf[6] = (l >> 8) & 0xff;
outbuf[7] = l & 0xff;
}
static void
encrypt_block( CAST5_context *c, byte *outbuf, byte *inbuf )
{
do_encrypt_block (c, outbuf, inbuf);
burn_stack (20+4*sizeof(void*));
}
static void
do_decrypt_block (CAST5_context *c, byte *outbuf, byte *inbuf )
{
u32 l, r, t;
u32 I;
u32 *Km;
byte *Kr;
Km = c->Km;
Kr = c->Kr;
l = inbuf[0] << 24 | inbuf[1] << 16 | inbuf[2] << 8 | inbuf[3];
r = inbuf[4] << 24 | inbuf[5] << 16 | inbuf[6] << 8 | inbuf[7];
t = l; l = r; r = t ^ F1(r, Km[15], Kr[15]);
t = l; l = r; r = t ^ F3(r, Km[14], Kr[14]);
t = l; l = r; r = t ^ F2(r, Km[13], Kr[13]);
t = l; l = r; r = t ^ F1(r, Km[12], Kr[12]);
t = l; l = r; r = t ^ F3(r, Km[11], Kr[11]);
t = l; l = r; r = t ^ F2(r, Km[10], Kr[10]);
t = l; l = r; r = t ^ F1(r, Km[ 9], Kr[ 9]);
t = l; l = r; r = t ^ F3(r, Km[ 8], Kr[ 8]);
t = l; l = r; r = t ^ F2(r, Km[ 7], Kr[ 7]);
t = l; l = r; r = t ^ F1(r, Km[ 6], Kr[ 6]);
t = l; l = r; r = t ^ F3(r, Km[ 5], Kr[ 5]);
t = l; l = r; r = t ^ F2(r, Km[ 4], Kr[ 4]);
t = l; l = r; r = t ^ F1(r, Km[ 3], Kr[ 3]);
t = l; l = r; r = t ^ F3(r, Km[ 2], Kr[ 2]);
t = l; l = r; r = t ^ F2(r, Km[ 1], Kr[ 1]);
t = l; l = r; r = t ^ F1(r, Km[ 0], Kr[ 0]);
outbuf[0] = (r >> 24) & 0xff;
outbuf[1] = (r >> 16) & 0xff;
outbuf[2] = (r >> 8) & 0xff;
outbuf[3] = r & 0xff;
outbuf[4] = (l >> 24) & 0xff;
outbuf[5] = (l >> 16) & 0xff;
outbuf[6] = (l >> 8) & 0xff;
outbuf[7] = l & 0xff;
}
static void
decrypt_block( CAST5_context *c, byte *outbuf, byte *inbuf )
{
do_decrypt_block (c, outbuf, inbuf);
burn_stack (20+4*sizeof(void*));
}
static const char*
selftest(void)
{
CAST5_context c;
byte key[16] = { 0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78,
0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A };
byte plain[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };
byte cipher[8]= { 0x23, 0x8B, 0x4F, 0xE5, 0x84, 0x7E, 0x44, 0xB2 };
byte buffer[8];
cast_setkey( &c, key, 16 );
encrypt_block( &c, buffer, plain );
if( memcmp( buffer, cipher, 8 ) )
return "1";
decrypt_block( &c, buffer, buffer );
if( memcmp( buffer, plain, 8 ) )
return "2";
#if 0 /* full maintenance test */
{
int i;
byte a0[16] = { 0x01,0x23,0x45,0x67,0x12,0x34,0x56,0x78,
0x23,0x45,0x67,0x89,0x34,0x56,0x78,0x9A };
byte b0[16] = { 0x01,0x23,0x45,0x67,0x12,0x34,0x56,0x78,
0x23,0x45,0x67,0x89,0x34,0x56,0x78,0x9A };
byte a1[16] = { 0xEE,0xA9,0xD0,0xA2,0x49,0xFD,0x3B,0xA6,
0xB3,0x43,0x6F,0xB8,0x9D,0x6D,0xCA,0x92 };
byte b1[16] = { 0xB2,0xC9,0x5E,0xB0,0x0C,0x31,0xAD,0x71,
0x80,0xAC,0x05,0xB8,0xE8,0x3D,0x69,0x6E };
for(i=0; i < 1000000; i++ ) {
cast_setkey( &c, b0, 16 );
encrypt_block( &c, a0, a0 );
encrypt_block( &c, a0+8, a0+8 );
cast_setkey( &c, a0, 16 );
encrypt_block( &c, b0, b0 );
encrypt_block( &c, b0+8, b0+8 );
}
if( memcmp( a0, a1, 16 ) || memcmp( b0, b1, 16 ) )
return "3";
}
#endif
return NULL;
}
static void
key_schedule( u32 *x, u32 *z, u32 *k )
{
#define xi(i) ((x[(i)/4] >> (8*(3-((i)%4)))) & 0xff)
#define zi(i) ((z[(i)/4] >> (8*(3-((i)%4)))) & 0xff)
z[0] = x[0] ^ s5[xi(13)]^s6[xi(15)]^s7[xi(12)]^s8[xi(14)]^s7[xi( 8)];
z[1] = x[2] ^ s5[zi( 0)]^s6[zi( 2)]^s7[zi( 1)]^s8[zi( 3)]^s8[xi(10)];
z[2] = x[3] ^ s5[zi( 7)]^s6[zi( 6)]^s7[zi( 5)]^s8[zi( 4)]^s5[xi( 9)];
z[3] = x[1] ^ s5[zi(10)]^s6[zi( 9)]^s7[zi(11)]^s8[zi( 8)]^s6[xi(11)];
k[0] = s5[zi( 8)]^s6[zi( 9)]^s7[zi( 7)]^s8[zi( 6)]^s5[zi( 2)];
k[1] = s5[zi(10)]^s6[zi(11)]^s7[zi( 5)]^s8[zi( 4)]^s6[zi( 6)];
k[2] = s5[zi(12)]^s6[zi(13)]^s7[zi( 3)]^s8[zi( 2)]^s7[zi( 9)];
k[3] = s5[zi(14)]^s6[zi(15)]^s7[zi( 1)]^s8[zi( 0)]^s8[zi(12)];
x[0] = z[2] ^ s5[zi( 5)]^s6[zi( 7)]^s7[zi( 4)]^s8[zi( 6)]^s7[zi( 0)];
x[1] = z[0] ^ s5[xi( 0)]^s6[xi( 2)]^s7[xi( 1)]^s8[xi( 3)]^s8[zi( 2)];
x[2] = z[1] ^ s5[xi( 7)]^s6[xi( 6)]^s7[xi( 5)]^s8[xi( 4)]^s5[zi( 1)];
x[3] = z[3] ^ s5[xi(10)]^s6[xi( 9)]^s7[xi(11)]^s8[xi( 8)]^s6[zi( 3)];
k[4] = s5[xi( 3)]^s6[xi( 2)]^s7[xi(12)]^s8[xi(13)]^s5[xi( 8)];
k[5] = s5[xi( 1)]^s6[xi( 0)]^s7[xi(14)]^s8[xi(15)]^s6[xi(13)];
k[6] = s5[xi( 7)]^s6[xi( 6)]^s7[xi( 8)]^s8[xi( 9)]^s7[xi( 3)];
k[7] = s5[xi( 5)]^s6[xi( 4)]^s7[xi(10)]^s8[xi(11)]^s8[xi( 7)];
z[0] = x[0] ^ s5[xi(13)]^s6[xi(15)]^s7[xi(12)]^s8[xi(14)]^s7[xi( 8)];
z[1] = x[2] ^ s5[zi( 0)]^s6[zi( 2)]^s7[zi( 1)]^s8[zi( 3)]^s8[xi(10)];
z[2] = x[3] ^ s5[zi( 7)]^s6[zi( 6)]^s7[zi( 5)]^s8[zi( 4)]^s5[xi( 9)];
z[3] = x[1] ^ s5[zi(10)]^s6[zi( 9)]^s7[zi(11)]^s8[zi( 8)]^s6[xi(11)];
k[8] = s5[zi( 3)]^s6[zi( 2)]^s7[zi(12)]^s8[zi(13)]^s5[zi( 9)];
k[9] = s5[zi( 1)]^s6[zi( 0)]^s7[zi(14)]^s8[zi(15)]^s6[zi(12)];
k[10]= s5[zi( 7)]^s6[zi( 6)]^s7[zi( 8)]^s8[zi( 9)]^s7[zi( 2)];
k[11]= s5[zi( 5)]^s6[zi( 4)]^s7[zi(10)]^s8[zi(11)]^s8[zi( 6)];
x[0] = z[2] ^ s5[zi( 5)]^s6[zi( 7)]^s7[zi( 4)]^s8[zi( 6)]^s7[zi( 0)];
x[1] = z[0] ^ s5[xi( 0)]^s6[xi( 2)]^s7[xi( 1)]^s8[xi( 3)]^s8[zi( 2)];
x[2] = z[1] ^ s5[xi( 7)]^s6[xi( 6)]^s7[xi( 5)]^s8[xi( 4)]^s5[zi( 1)];
x[3] = z[3] ^ s5[xi(10)]^s6[xi( 9)]^s7[xi(11)]^s8[xi( 8)]^s6[zi( 3)];
k[12]= s5[xi( 8)]^s6[xi( 9)]^s7[xi( 7)]^s8[xi( 6)]^s5[xi( 3)];
k[13]= s5[xi(10)]^s6[xi(11)]^s7[xi( 5)]^s8[xi( 4)]^s6[xi( 7)];
k[14]= s5[xi(12)]^s6[xi(13)]^s7[xi( 3)]^s8[xi( 2)]^s7[xi( 8)];
k[15]= s5[xi(14)]^s6[xi(15)]^s7[xi( 1)]^s8[xi( 0)]^s8[xi(13)];
#undef xi
#undef zi
}
static int
do_cast_setkey( CAST5_context *c, byte *key, unsigned keylen )
{
static int initialized;
static const char* selftest_failed;
int i;
u32 x[4];
u32 z[4];
u32 k[16];
if( !initialized ) {
initialized = 1;
selftest_failed = selftest();
if( selftest_failed )
fprintf(stderr,"CAST5 selftest failed (%s).\n", selftest_failed );
}
if( selftest_failed )
return G10ERR_SELFTEST_FAILED;
if( keylen != 16 )
return G10ERR_WRONG_KEYLEN;
x[0] = key[0] << 24 | key[1] << 16 | key[2] << 8 | key[3];
x[1] = key[4] << 24 | key[5] << 16 | key[6] << 8 | key[7];
x[2] = key[8] << 24 | key[9] << 16 | key[10] << 8 | key[11];
x[3] = key[12] << 24 | key[13] << 16 | key[14] << 8 | key[15];
key_schedule( x, z, k );
for(i=0; i < 16; i++ )
c->Km[i] = k[i];
key_schedule( x, z, k );
for(i=0; i < 16; i++ )
c->Kr[i] = k[i] & 0x1f;
memset(&x,0, sizeof x);
memset(&z,0, sizeof z);
memset(&k,0, sizeof k);
#undef xi
#undef zi
return 0;
}
static int
cast_setkey( CAST5_context *c, byte *key, unsigned keylen )
{
int rc = do_cast_setkey (c, key, keylen);
burn_stack (96+7*sizeof(void*));
return rc;
}
/****************
* Return some information about the algorithm. We need algo here to
* distinguish different flavors of the algorithm.
* Returns: A pointer to string describing the algorithm or NULL if
* the ALGO is invalid.
*/
const char *
cast5_get_info( int algo, size_t *keylen,
size_t *blocksize, size_t *contextsize,
int (**r_setkey)( void *c, byte *key, unsigned keylen ),
void (**r_encrypt)( void *c, byte *outbuf, byte *inbuf ),
void (**r_decrypt)( void *c, byte *outbuf, byte *inbuf )
)
{
*keylen = 128;
*blocksize = CAST5_BLOCKSIZE;
*contextsize = sizeof(CAST5_context);
*(int (**)(CAST5_context*, byte*, unsigned))r_setkey
= cast_setkey;
*(void (**)(CAST5_context*, byte*, byte*))r_encrypt
= encrypt_block;
*(void (**)(CAST5_context*, byte*, byte*))r_decrypt
= decrypt_block;
if( algo == CIPHER_ALGO_CAST5 )
return "CAST5";
return NULL;
}

View File

@ -1,678 +0,0 @@
/* cipher.c - cipher dispatcher
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "util.h"
#include "errors.h"
#include "cipher.h"
#include "algorithms.h"
/* We have support for a DUMMY encryption cipher which comes handy to
debug MDCs and similar things. Because this is a bit dangerous it
is not enabled. */
/*#define ALLOW_DUMMY 1 */
#define MAX_BLOCKSIZE 16
#define TABLE_SIZE 14
struct cipher_table_s {
const char *name;
int algo;
size_t blocksize;
size_t keylen;
size_t contextsize; /* allocate this amount of context */
int (*setkey)( void *c, byte *key, unsigned keylen );
void (*encrypt)( void *c, byte *outbuf, byte *inbuf );
void (*decrypt)( void *c, byte *outbuf, byte *inbuf );
};
static struct cipher_table_s cipher_table[TABLE_SIZE];
static int disabled_algos[TABLE_SIZE];
struct cipher_handle_s {
int algo;
int mode;
size_t blocksize;
byte iv[MAX_BLOCKSIZE]; /* (this should be ulong aligned) */
byte lastiv[MAX_BLOCKSIZE];
int unused; /* in IV */
int (*setkey)( void *c, byte *key, unsigned keylen );
void (*encrypt)( void *c, byte *outbuf, byte *inbuf );
void (*decrypt)( void *c, byte *outbuf, byte *inbuf );
PROPERLY_ALIGNED_TYPE context;
};
#ifdef ALLOW_DUMMY
static int
dummy_setkey( void *c, byte *key, unsigned keylen ) { return 0; }
static void
dummy_encrypt_block( void *c, byte *outbuf, byte *inbuf ) { BUG(); }
static void
dummy_decrypt_block( void *c, byte *outbuf, byte *inbuf ) { BUG(); }
#ifdef __GNUC__
# warning DUMMY cipher module is enabled
#endif
#endif
/****************
* Put the static entries into the table.
*/
static void
setup_cipher_table(void)
{
int i;
i = 0;
cipher_table[i].algo = CIPHER_ALGO_RIJNDAEL;
cipher_table[i].name = rijndael_get_info( cipher_table[i].algo,
&cipher_table[i].keylen,
&cipher_table[i].blocksize,
&cipher_table[i].contextsize,
&cipher_table[i].setkey,
&cipher_table[i].encrypt,
&cipher_table[i].decrypt );
if( !cipher_table[i].name )
BUG();
i++;
cipher_table[i].algo = CIPHER_ALGO_RIJNDAEL192;
cipher_table[i].name = rijndael_get_info( cipher_table[i].algo,
&cipher_table[i].keylen,
&cipher_table[i].blocksize,
&cipher_table[i].contextsize,
&cipher_table[i].setkey,
&cipher_table[i].encrypt,
&cipher_table[i].decrypt );
if( !cipher_table[i].name )
BUG();
i++;
cipher_table[i].algo = CIPHER_ALGO_RIJNDAEL256;
cipher_table[i].name = rijndael_get_info( cipher_table[i].algo,
&cipher_table[i].keylen,
&cipher_table[i].blocksize,
&cipher_table[i].contextsize,
&cipher_table[i].setkey,
&cipher_table[i].encrypt,
&cipher_table[i].decrypt );
if( !cipher_table[i].name )
BUG();
i++;
cipher_table[i].algo = CIPHER_ALGO_TWOFISH;
cipher_table[i].name = twofish_get_info( cipher_table[i].algo,
&cipher_table[i].keylen,
&cipher_table[i].blocksize,
&cipher_table[i].contextsize,
&cipher_table[i].setkey,
&cipher_table[i].encrypt,
&cipher_table[i].decrypt );
if( !cipher_table[i].name )
BUG();
i++;
cipher_table[i].algo = CIPHER_ALGO_BLOWFISH;
cipher_table[i].name = blowfish_get_info( cipher_table[i].algo,
&cipher_table[i].keylen,
&cipher_table[i].blocksize,
&cipher_table[i].contextsize,
&cipher_table[i].setkey,
&cipher_table[i].encrypt,
&cipher_table[i].decrypt );
if( !cipher_table[i].name )
BUG();
i++;
cipher_table[i].algo = CIPHER_ALGO_CAST5;
cipher_table[i].name = cast5_get_info( cipher_table[i].algo,
&cipher_table[i].keylen,
&cipher_table[i].blocksize,
&cipher_table[i].contextsize,
&cipher_table[i].setkey,
&cipher_table[i].encrypt,
&cipher_table[i].decrypt );
if( !cipher_table[i].name )
BUG();
i++;
cipher_table[i].algo = CIPHER_ALGO_3DES;
cipher_table[i].name = des_get_info( cipher_table[i].algo,
&cipher_table[i].keylen,
&cipher_table[i].blocksize,
&cipher_table[i].contextsize,
&cipher_table[i].setkey,
&cipher_table[i].encrypt,
&cipher_table[i].decrypt );
if( !cipher_table[i].name )
BUG();
i++;
cipher_table[i].algo = CIPHER_ALGO_IDEA;
cipher_table[i].name = idea_get_info( cipher_table[i].algo,
&cipher_table[i].keylen,
&cipher_table[i].blocksize,
&cipher_table[i].contextsize,
&cipher_table[i].setkey,
&cipher_table[i].encrypt,
&cipher_table[i].decrypt );
if (cipher_table[i].name)
i++; /* Note that IDEA is usually not available. */
#ifdef ALLOW_DUMMY
cipher_table[i].algo = CIPHER_ALGO_DUMMY;
cipher_table[i].name = "DUMMY";
cipher_table[i].blocksize = 8;
cipher_table[i].keylen = 128;
cipher_table[i].contextsize = 0;
cipher_table[i].setkey = dummy_setkey;
cipher_table[i].encrypt = dummy_encrypt_block;
cipher_table[i].decrypt = dummy_decrypt_block;
i++;
#endif
for( ; i < TABLE_SIZE; i++ )
cipher_table[i].name = NULL;
}
/****************
* Try to load all modules and return true if new modules are available
*/
static int
load_cipher_modules(void)
{
static int initialized = 0;
if (!initialized )
{
setup_cipher_table(); /* load static modules on the first call */
initialized = 1;
return 1;
}
return 0;
}
/****************
* Map a string to the cipher algo
*/
int
string_to_cipher_algo( const char *string )
{
int i;
const char *s;
/* kludge to alias RIJNDAEL to AES */
if ( *string == 'R' || *string == 'r')
{
if (!ascii_strcasecmp (string, "RIJNDAEL"))
string = "AES";
else if (!ascii_strcasecmp (string, "RIJNDAEL192"))
string = "AES192";
else if (!ascii_strcasecmp (string, "RIJNDAEL256"))
string = "AES256";
}
do
{
for(i=0; (s=cipher_table[i].name); i++ )
{
if( !ascii_strcasecmp( s, string ) )
return cipher_table[i].algo;
}
} while( load_cipher_modules() );
return 0;
}
/****************
* Map a cipher algo to a string
*/
const char *
cipher_algo_to_string( int algo )
{
int i;
do {
for(i=0; cipher_table[i].name; i++ )
if( cipher_table[i].algo == algo )
return cipher_table[i].name;
} while( load_cipher_modules() );
return NULL;
}
void
disable_cipher_algo( int algo )
{
int i;
for(i=0; i < DIM(disabled_algos); i++ ) {
if( !disabled_algos[i] || disabled_algos[i] == algo ) {
disabled_algos[i] = algo;
return;
}
}
/* fixme: we should use a linked list */
log_fatal("can't disable cipher algo %d: table full\n", algo );
}
/****************
* Return 0 if the cipher algo is available
*/
int
check_cipher_algo( int algo )
{
int i;
do {
for(i=0; cipher_table[i].name; i++ )
if( cipher_table[i].algo == algo ) {
for(i=0; i < DIM(disabled_algos); i++ ) {
if( disabled_algos[i] == algo )
return G10ERR_CIPHER_ALGO;
}
return 0; /* okay */
}
} while( load_cipher_modules() );
return G10ERR_CIPHER_ALGO;
}
unsigned
cipher_get_keylen( int algo )
{
int i;
unsigned len = 0;
do {
for(i=0; cipher_table[i].name; i++ ) {
if( cipher_table[i].algo == algo ) {
len = cipher_table[i].keylen;
if( !len )
log_bug("cipher %d w/o key length\n", algo );
return len;
}
}
} while( load_cipher_modules() );
log_bug("cipher %d not found\n", algo );
return 0;
}
unsigned
cipher_get_blocksize( int algo )
{
int i;
unsigned len = 0;
do {
for(i=0; cipher_table[i].name; i++ ) {
if( cipher_table[i].algo == algo ) {
len = cipher_table[i].blocksize;
if( !len )
log_bug("cipher %d w/o blocksize\n", algo );
return len;
}
}
} while( load_cipher_modules() );
log_bug("cipher %d not found\n", algo );
return 0;
}
/****************
* Open a cipher handle for use with algorithm ALGO, in mode MODE
* and put it into secure memory if SECURE is true.
*/
CIPHER_HANDLE
cipher_open( int algo, int mode, int secure )
{
CIPHER_HANDLE hd;
int i;
fast_random_poll();
do {
for(i=0; cipher_table[i].name; i++ )
if( cipher_table[i].algo == algo )
break;
} while( !cipher_table[i].name && load_cipher_modules() );
if( !cipher_table[i].name ) {
log_fatal("cipher_open: algorithm %d not available\n", algo );
return NULL;
}
/* ? perform selftest here and mark this with a flag in cipher_table ? */
hd = secure ? m_alloc_secure_clear( sizeof *hd
+ cipher_table[i].contextsize
- sizeof(PROPERLY_ALIGNED_TYPE) )
: m_alloc_clear( sizeof *hd + cipher_table[i].contextsize
- sizeof(PROPERLY_ALIGNED_TYPE) );
hd->algo = algo;
hd->blocksize = cipher_table[i].blocksize;
hd->setkey = cipher_table[i].setkey;
hd->encrypt = cipher_table[i].encrypt;
hd->decrypt = cipher_table[i].decrypt;
if( mode == CIPHER_MODE_AUTO_CFB ) {
if( algo >= 100 )
hd->mode = CIPHER_MODE_CFB;
else
hd->mode = CIPHER_MODE_PHILS_CFB;
}
else
hd->mode = mode;
#ifdef ALLOW_DUMMY
if( algo == CIPHER_ALGO_DUMMY )
hd->mode = CIPHER_MODE_DUMMY;
#endif
return hd;
}
void
cipher_close( CIPHER_HANDLE c )
{
m_free(c);
}
int
cipher_setkey( CIPHER_HANDLE c, byte *key, unsigned keylen )
{
return (*c->setkey)( &c->context.c, key, keylen );
}
void
cipher_setiv( CIPHER_HANDLE c, const byte *iv, unsigned ivlen )
{
memset( c->iv, 0, c->blocksize );
if( iv ) {
if( ivlen != c->blocksize )
log_info("WARNING: cipher_setiv: ivlen=%u blklen=%u\n",
ivlen, (unsigned)c->blocksize );
if( ivlen > c->blocksize )
ivlen = c->blocksize;
memcpy( c->iv, iv, ivlen );
}
c->unused = 0;
}
static void
do_ecb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks )
{
unsigned n;
for(n=0; n < nblocks; n++ ) {
(*c->encrypt)( &c->context.c, outbuf, inbuf );
inbuf += c->blocksize;
outbuf += c->blocksize;
}
}
static void
do_ecb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks )
{
unsigned n;
for(n=0; n < nblocks; n++ ) {
(*c->decrypt)( &c->context.c, outbuf, inbuf );
inbuf += c->blocksize;
outbuf += c->blocksize;
}
}
static void
do_cbc_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks )
{
unsigned int n;
byte *ivp;
int i;
size_t blocksize = c->blocksize;
for(n=0; n < nblocks; n++ ) {
/* fixme: the xor should works on words and not on
* bytes. Maybe it is a good idea to enhance the cipher backend
* API to allow for CBC handling in the backend */
for(ivp=c->iv,i=0; i < blocksize; i++ )
outbuf[i] = inbuf[i] ^ *ivp++;
(*c->encrypt)( &c->context.c, outbuf, outbuf );
memcpy(c->iv, outbuf, blocksize );
inbuf += c->blocksize;
outbuf += c->blocksize;
}
}
static void
do_cbc_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks )
{
unsigned int n;
byte *ivp;
int i;
size_t blocksize = c->blocksize;
for(n=0; n < nblocks; n++ ) {
/* because outbuf and inbuf might be the same, we have
* to save the original ciphertext block. We use lastiv
* for this here because it is not used otherwise */
memcpy(c->lastiv, inbuf, blocksize );
(*c->decrypt)( &c->context.c, outbuf, inbuf );
for(ivp=c->iv,i=0; i < blocksize; i++ )
outbuf[i] ^= *ivp++;
memcpy(c->iv, c->lastiv, blocksize );
inbuf += c->blocksize;
outbuf += c->blocksize;
}
}
static void
do_cfb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
{
byte *ivp;
size_t blocksize = c->blocksize;
if( nbytes <= c->unused ) {
/* short enough to be encoded by the remaining XOR mask */
/* XOR the input with the IV and store input into IV */
for(ivp=c->iv+c->blocksize - c->unused; nbytes; nbytes--, c->unused-- )
*outbuf++ = (*ivp++ ^= *inbuf++);
return;
}
if( c->unused ) {
/* XOR the input with the IV and store input into IV */
nbytes -= c->unused;
for(ivp=c->iv+blocksize - c->unused; c->unused; c->unused-- )
*outbuf++ = (*ivp++ ^= *inbuf++);
}
/* now we can process complete blocks */
while( nbytes >= blocksize ) {
int i;
/* encrypt the IV (and save the current one) */
memcpy( c->lastiv, c->iv, blocksize );
(*c->encrypt)( &c->context.c, c->iv, c->iv );
/* XOR the input with the IV and store input into IV */
for(ivp=c->iv,i=0; i < blocksize; i++ )
*outbuf++ = (*ivp++ ^= *inbuf++);
nbytes -= blocksize;
}
if( nbytes ) { /* process the remaining bytes */
/* encrypt the IV (and save the current one) */
memcpy( c->lastiv, c->iv, blocksize );
(*c->encrypt)( &c->context.c, c->iv, c->iv );
c->unused = blocksize;
/* and apply the xor */
c->unused -= nbytes;
for(ivp=c->iv; nbytes; nbytes-- )
*outbuf++ = (*ivp++ ^= *inbuf++);
}
}
static void
do_cfb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
{
byte *ivp;
ulong temp;
size_t blocksize = c->blocksize;
if( nbytes <= c->unused ) {
/* short enough to be encoded by the remaining XOR mask */
/* XOR the input with the IV and store input into IV */
for(ivp=c->iv+blocksize - c->unused; nbytes; nbytes--,c->unused--){
temp = *inbuf++;
*outbuf++ = *ivp ^ temp;
*ivp++ = temp;
}
return;
}
if( c->unused ) {
/* XOR the input with the IV and store input into IV */
nbytes -= c->unused;
for(ivp=c->iv+blocksize - c->unused; c->unused; c->unused-- ) {
temp = *inbuf++;
*outbuf++ = *ivp ^ temp;
*ivp++ = temp;
}
}
/* now we can process complete blocks */
while( nbytes >= blocksize ) {
int i;
/* encrypt the IV (and save the current one) */
memcpy( c->lastiv, c->iv, blocksize );
(*c->encrypt)( &c->context.c, c->iv, c->iv );
/* XOR the input with the IV and store input into IV */
for(ivp=c->iv,i=0; i < blocksize; i++ ) {
temp = *inbuf++;
*outbuf++ = *ivp ^ temp;
*ivp++ = temp;
}
nbytes -= blocksize;
}
if( nbytes ) { /* process the remaining bytes */
/* encrypt the IV (and save the current one) */
memcpy( c->lastiv, c->iv, blocksize );
(*c->encrypt)( &c->context.c, c->iv, c->iv );
c->unused = blocksize;
/* and apply the xor */
c->unused -= nbytes;
for(ivp=c->iv; nbytes; nbytes-- ) {
temp = *inbuf++;
*outbuf++ = *ivp ^ temp;
*ivp++ = temp;
}
}
}
/****************
* Encrypt INBUF to OUTBUF with the mode selected at open.
* inbuf and outbuf may overlap or be the same.
* Depending on the mode some some contraints apply to NBYTES.
*/
void
cipher_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
{
switch( c->mode ) {
case CIPHER_MODE_ECB:
assert(!(nbytes%c->blocksize));
do_ecb_encrypt(c, outbuf, inbuf, nbytes/c->blocksize );
break;
case CIPHER_MODE_CBC:
assert(!(nbytes%c->blocksize));
do_cbc_encrypt(c, outbuf, inbuf, nbytes/c->blocksize );
break;
case CIPHER_MODE_CFB:
case CIPHER_MODE_PHILS_CFB:
do_cfb_encrypt(c, outbuf, inbuf, nbytes );
break;
#ifdef ALLOW_DUMMY
case CIPHER_MODE_DUMMY:
if( inbuf != outbuf )
memmove( outbuf, inbuf, nbytes );
break;
#endif
default: log_fatal("cipher_encrypt: invalid mode %d\n", c->mode );
}
}
/****************
* Decrypt INBUF to OUTBUF with the mode selected at open.
* inbuf and outbuf may overlap or be the same.
* Depending on the mode some some contraints apply to NBYTES.
*/
void
cipher_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes )
{
switch( c->mode ) {
case CIPHER_MODE_ECB:
assert(!(nbytes%c->blocksize));
do_ecb_decrypt(c, outbuf, inbuf, nbytes/c->blocksize );
break;
case CIPHER_MODE_CBC:
assert(!(nbytes%c->blocksize));
do_cbc_decrypt(c, outbuf, inbuf, nbytes/c->blocksize );
break;
case CIPHER_MODE_CFB:
case CIPHER_MODE_PHILS_CFB:
do_cfb_decrypt(c, outbuf, inbuf, nbytes );
break;
#ifdef ALLOW_DUMMY
case CIPHER_MODE_DUMMY:
if( inbuf != outbuf )
memmove( outbuf, inbuf, nbytes );
break;
#endif
default: log_fatal("cipher_decrypt: invalid mode %d\n", c->mode );
}
}
/****************
* Used for PGP's somewhat strange CFB mode. Only works if
* the handle is in PHILS_CFB mode
*/
void
cipher_sync( CIPHER_HANDLE c )
{
if( c->mode == CIPHER_MODE_PHILS_CFB && c->unused ) {
memmove(c->iv + c->unused, c->iv, c->blocksize - c->unused );
memcpy(c->iv, c->lastiv + c->blocksize - c->unused, c->unused);
c->unused = 0;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,483 +0,0 @@
/* dsa.c - DSA signature algorithm
* Copyright (C) 1998, 1999, 2000 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "util.h"
#include "mpi.h"
#include "cipher.h"
#include "dsa.h"
typedef struct {
MPI p; /* prime */
MPI q; /* group order */
MPI g; /* group generator */
MPI y; /* g^x mod p */
} DSA_public_key;
typedef struct {
MPI p; /* prime */
MPI q; /* group order */
MPI g; /* group generator */
MPI y; /* g^x mod p */
MPI x; /* secret exponent */
} DSA_secret_key;
static MPI gen_k( MPI q );
static void test_keys( DSA_secret_key *sk, unsigned qbits );
static int check_secret_key( DSA_secret_key *sk );
static void generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors );
static void sign(MPI r, MPI s, MPI input, DSA_secret_key *skey);
static int verify(MPI r, MPI s, MPI input, DSA_public_key *pkey);
static void (*progress_cb) ( void *, int );
static void *progress_cb_data;
void
register_pk_dsa_progress ( void (*cb)( void *, int), void *cb_data )
{
progress_cb = cb;
progress_cb_data = cb_data;
}
static void
progress( int c )
{
if ( progress_cb )
progress_cb ( progress_cb_data, c );
else
fputc( c, stderr );
}
/****************
* Generate a random secret exponent k less than q
*/
static MPI
gen_k( MPI q )
{
MPI k = mpi_alloc_secure( mpi_get_nlimbs(q) );
unsigned int nbits = mpi_get_nbits(q);
unsigned int nbytes = (nbits+7)/8;
char *rndbuf = NULL;
if( DBG_CIPHER )
log_debug("choosing a random k ");
for(;;) {
if( DBG_CIPHER )
progress('.');
if( !rndbuf || nbits < 32 ) {
m_free(rndbuf);
rndbuf = get_random_bits( nbits, 1, 1 );
}
else { /* change only some of the higher bits */
/* we could imporove this by directly requesting more memory
* at the first call to get_random_bits() and use this the here
* maybe it is easier to do this directly in random.c */
char *pp = get_random_bits( 32, 1, 1 );
memcpy( rndbuf,pp, 4 );
m_free(pp);
}
mpi_set_buffer( k, rndbuf, nbytes, 0 );
if( mpi_test_bit( k, nbits-1 ) )
mpi_set_highbit( k, nbits-1 );
else {
mpi_set_highbit( k, nbits-1 );
mpi_clear_bit( k, nbits-1 );
}
if( !(mpi_cmp( k, q ) < 0) ) { /* check: k < q */
if( DBG_CIPHER )
progress('+');
continue; /* no */
}
if( !(mpi_cmp_ui( k, 0 ) > 0) ) { /* check: k > 0 */
if( DBG_CIPHER )
progress('-');
continue; /* no */
}
break; /* okay */
}
m_free(rndbuf);
if( DBG_CIPHER )
progress('\n');
return k;
}
static void
test_keys( DSA_secret_key *sk, unsigned qbits )
{
DSA_public_key pk;
MPI test = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
MPI out1_a = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
MPI out1_b = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
pk.p = sk->p;
pk.q = sk->q;
pk.g = sk->g;
pk.y = sk->y;
/*mpi_set_bytes( test, qbits, get_random_byte, 0 );*/
{ char *p = get_random_bits( qbits, 0, 0 );
mpi_set_buffer( test, p, (qbits+7)/8, 0 );
m_free(p);
}
sign( out1_a, out1_b, test, sk );
if( !verify( out1_a, out1_b, test, &pk ) )
log_fatal("DSA:: sign, verify failed\n");
mpi_free( test );
mpi_free( out1_a );
mpi_free( out1_b );
}
/****************
* Generate a DSA key pair with a key of size NBITS
* Returns: 2 structures filled with all needed values
* and an array with the n-1 factors of (p-1)
*/
static void
generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors )
{
MPI p; /* the prime */
MPI q; /* the 160 bit prime factor */
MPI g; /* the generator */
MPI y; /* g^x mod p */
MPI x; /* the secret exponent */
MPI h, e; /* helper */
unsigned qbits;
byte *rndbuf;
assert( nbits >= 512 && nbits <= 1024 );
qbits = 160;
p = generate_elg_prime( 1, nbits, qbits, NULL, ret_factors );
/* get q out of factors */
q = mpi_copy((*ret_factors)[0]);
if( mpi_get_nbits(q) != qbits )
BUG();
/* find a generator g (h and e are helpers)*/
/* e = (p-1)/q */
e = mpi_alloc( mpi_get_nlimbs(p) );
mpi_sub_ui( e, p, 1 );
mpi_fdiv_q( e, e, q );
g = mpi_alloc( mpi_get_nlimbs(p) );
h = mpi_alloc_set_ui( 1 ); /* we start with 2 */
do {
mpi_add_ui( h, h, 1 );
/* g = h^e mod p */
mpi_powm( g, h, e, p );
} while( !mpi_cmp_ui( g, 1 ) ); /* continue until g != 1 */
/* select a random number which has these properties:
* 0 < x < q-1
* This must be a very good random number because this
* is the secret part. */
if( DBG_CIPHER )
log_debug("choosing a random x ");
assert( qbits >= 160 );
x = mpi_alloc_secure( mpi_get_nlimbs(q) );
mpi_sub_ui( h, q, 1 ); /* put q-1 into h */
rndbuf = NULL;
do {
if( DBG_CIPHER )
progress('.');
if( !rndbuf )
rndbuf = get_random_bits( qbits, 2, 1 );
else { /* change only some of the higher bits (= 2 bytes)*/
char *r = get_random_bits( 16, 2, 1 );
memcpy(rndbuf, r, 16/8 );
m_free(r);
}
mpi_set_buffer( x, rndbuf, (qbits+7)/8, 0 );
mpi_clear_highbit( x, qbits+1 );
} while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, h )<0 ) );
m_free(rndbuf);
mpi_free( e );
mpi_free( h );
/* y = g^x mod p */
y = mpi_alloc( mpi_get_nlimbs(p) );
mpi_powm( y, g, x, p );
if( DBG_CIPHER ) {
progress('\n');
log_mpidump("dsa p= ", p );
log_mpidump("dsa q= ", q );
log_mpidump("dsa g= ", g );
log_mpidump("dsa y= ", y );
log_mpidump("dsa x= ", x );
}
/* copy the stuff to the key structures */
sk->p = p;
sk->q = q;
sk->g = g;
sk->y = y;
sk->x = x;
/* now we can test our keys (this should never fail!) */
test_keys( sk, qbits );
}
/****************
* Test whether the secret key is valid.
* Returns: if this is a valid key.
*/
static int
check_secret_key( DSA_secret_key *sk )
{
int rc;
MPI y = mpi_alloc( mpi_get_nlimbs(sk->y) );
mpi_powm( y, sk->g, sk->x, sk->p );
rc = !mpi_cmp( y, sk->y );
mpi_free( y );
return rc;
}
/****************
* Make a DSA signature from HASH and put it into r and s.
*
* Without generating the k this function runs in
* about 26ms on a 300 Mhz Mobile Pentium
*/
static void
sign(MPI r, MPI s, MPI hash, DSA_secret_key *skey )
{
MPI k;
MPI kinv;
MPI tmp;
/* select a random k with 0 < k < q */
k = gen_k( skey->q );
/* r = (a^k mod p) mod q */
mpi_powm( r, skey->g, k, skey->p );
mpi_fdiv_r( r, r, skey->q );
/* kinv = k^(-1) mod q */
kinv = mpi_alloc( mpi_get_nlimbs(k) );
mpi_invm(kinv, k, skey->q );
/* s = (kinv * ( hash + x * r)) mod q */
tmp = mpi_alloc( mpi_get_nlimbs(skey->p) );
mpi_mul( tmp, skey->x, r );
mpi_add( tmp, tmp, hash );
mpi_mulm( s , kinv, tmp, skey->q );
mpi_free(k);
mpi_free(kinv);
mpi_free(tmp);
}
/****************
* Returns true if the signature composed from R and S is valid.
*
* Without the checks this function runs in
* about 31ms on a 300 Mhz Mobile Pentium
*/
static int
verify(MPI r, MPI s, MPI hash, DSA_public_key *pkey )
{
int rc;
MPI w, u1, u2, v;
MPI base[3];
MPI exp[3];
if( !(mpi_cmp_ui( r, 0 ) > 0 && mpi_cmp( r, pkey->q ) < 0) )
return 0; /* assertion 0 < r < q failed */
if( !(mpi_cmp_ui( s, 0 ) > 0 && mpi_cmp( s, pkey->q ) < 0) )
return 0; /* assertion 0 < s < q failed */
w = mpi_alloc( mpi_get_nlimbs(pkey->q) );
u1 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
u2 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
v = mpi_alloc( mpi_get_nlimbs(pkey->p) );
/* w = s^(-1) mod q */
mpi_invm( w, s, pkey->q );
/* u1 = (hash * w) mod q */
mpi_mulm( u1, hash, w, pkey->q );
/* u2 = r * w mod q */
mpi_mulm( u2, r, w, pkey->q );
/* v = g^u1 * y^u2 mod p mod q */
base[0] = pkey->g; exp[0] = u1;
base[1] = pkey->y; exp[1] = u2;
base[2] = NULL; exp[2] = NULL;
mpi_mulpowm( v, base, exp, pkey->p );
mpi_fdiv_r( v, v, pkey->q );
rc = !mpi_cmp( v, r );
mpi_free(w);
mpi_free(u1);
mpi_free(u2);
mpi_free(v);
return rc;
}
/*********************************************
************** interface ******************
*********************************************/
int
dsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
{
DSA_secret_key sk;
if( algo != PUBKEY_ALGO_DSA )
return G10ERR_PUBKEY_ALGO;
generate( &sk, nbits, retfactors );
skey[0] = sk.p;
skey[1] = sk.q;
skey[2] = sk.g;
skey[3] = sk.y;
skey[4] = sk.x;
return 0;
}
int
dsa_check_secret_key( int algo, MPI *skey )
{
DSA_secret_key sk;
if( algo != PUBKEY_ALGO_DSA )
return G10ERR_PUBKEY_ALGO;
if( !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] )
return G10ERR_BAD_MPI;
sk.p = skey[0];
sk.q = skey[1];
sk.g = skey[2];
sk.y = skey[3];
sk.x = skey[4];
if( !check_secret_key( &sk ) )
return G10ERR_BAD_SECKEY;
return 0;
}
int
dsa_sign( int algo, MPI *resarr, MPI data, MPI *skey )
{
DSA_secret_key sk;
if( algo != PUBKEY_ALGO_DSA )
return G10ERR_PUBKEY_ALGO;
if( !data || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] )
return G10ERR_BAD_MPI;
sk.p = skey[0];
sk.q = skey[1];
sk.g = skey[2];
sk.y = skey[3];
sk.x = skey[4];
resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
sign( resarr[0], resarr[1], data, &sk );
return 0;
}
int
dsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
int (*cmp)(void *, MPI), void *opaquev )
{
DSA_public_key pk;
if( algo != PUBKEY_ALGO_DSA )
return G10ERR_PUBKEY_ALGO;
if( !data[0] || !data[1] || !hash
|| !pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] )
return G10ERR_BAD_MPI;
pk.p = pkey[0];
pk.q = pkey[1];
pk.g = pkey[2];
pk.y = pkey[3];
if( !verify( data[0], data[1], hash, &pk ) )
return G10ERR_BAD_SIGN;
return 0;
}
unsigned
dsa_get_nbits( int algo, MPI *pkey )
{
if( algo != PUBKEY_ALGO_DSA )
return 0;
return mpi_get_nbits( pkey[0] );
}
/****************
* Return some information about the algorithm. We need algo here to
* distinguish different flavors of the algorithm.
* Returns: A pointer to string describing the algorithm or NULL if
* the ALGO is invalid.
* Usage: Bit 0 set : allows signing
* 1 set : allows encryption
*/
const char *
dsa_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig,
int *use )
{
*npkey = 4;
*nskey = 5;
*nenc = 0;
*nsig = 2;
switch( algo ) {
case PUBKEY_ALGO_DSA: *use = PUBKEY_USAGE_SIG; return "DSA";
default: *use = 0; return NULL;
}
}

Some files were not shown because too many files have changed in this diff Show More