diff --git a/BUGS b/BUGS index 43998969a..087fde475 100644 --- a/BUGS +++ b/BUGS @@ -1,47 +1,47 @@ List of some known bugs ------------------------- This following list contains those bugs which we are aware of. Please make sure that bugs you report are not listed here. If you can fix one of these bugs/limitations we will certainly be glad to receive a patch. (Please note that we need a disclaimer if a patch is longer than about 10 lines; but it may help anyway to show us where we have to fix it. Do an "info standards" to find out why a disclaimer is needed for GNU.) Format: severity: [ *] to [***], no, first reported, by, version. Bugs which are marked with "FIX: yyyy-mm-dd" are fixed in the CVS and after about half a day in the rsync snapshots. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [ *] #3 --list-packets should continue even w/o a passphrase (or in batch mode). Maybe we have to move it to a separate program?? [ *] #4 1999-01-13 0.9.1 v3 key 'expiration date' problem: 1. generate a key, set expiration date 2. 3. edit a v3 secret key, try to set expiration date - output: "You can't change... 4. save 5. key has expiration date from 1. and gpg reports that pubkey and seckey differ. The for loop the exp.date is set before v3 detection? [is this bug still alive? - can someone please check it] [ **] #6 1999-02-22 0.9.3 - Buserror on IRIX 6.4: Crash while doing a keygen. I think while creating - the prime. Other buserrors are reported when doing a "gpg README" + Bus error on IRIX 6.4: Crash while doing a keygen. I think while creating + the prime. Other bus errors are reported when doing a "gpg README" on sparc-solaris2.6. --> Solaris fixed. --> IRIX bug still there but someone should test this again! [ *] #18 1999-05-27 0.9.7 rndunix hangs on hp/ux. The problem is related to my_plcose which is not always called. (I suggest to use EGD instead of rndunix.) [ *] #22 1999-07-22 Solaris make has problems with the generated POTFILES - seems to be a gettext bug. Use GNU gmake as a workaround. Next #23 diff --git a/ChangeLog b/ChangeLog index 760f312dc..a7f2d7648 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,339 +1,345 @@ +Tue Aug 31 17:20:44 CEST 1999 Werner Koch + + + * configure.in: Minor changes to the OS/2 and Mingw32 system labels. + Add a printable name for Hurd. + Mon Aug 30 20:38:33 CEST 1999 Werner Koch * configure.in: Some support for DJGPP (Mark Elbrecht) Wed Aug 4 10:34:46 CEST 1999 Werner Koch * VERSION: Set to 0.9.10. Mon Jul 26 09:34:46 CEST 1999 Werner Koch * acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): remove init of ac_cv_... * Makefile.am (DISCLEANFILES): New Fri Jul 23 13:53:03 CEST 1999 Werner Koch * VERSION: Set to 0.9.9. * configure.in: Print a notice when rndunix is used. Thu Jul 15 10:15:35 CEST 1999 Werner Koch * acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): Fixed last modification. Wed Jul 7 13:08:40 CEST 1999 Werner Koch * Makefile.am: Support for libtool. * configure.in: Ditto. Tue Jun 29 21:44:25 CEST 1999 Werner Koch * configure.in (use_local_zlib): The lost dollar is back. * acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): Add EMX case. * configure.in: Another variant of the MX vendor string * configure.in (--with-capabilities): Some test code (Remi). Sat Jun 26 12:15:59 CEST 1999 Werner Koch * acinclude.m4 (GNUPG_CHECK_RDYNAMIC): Support for HPUX and IRIX. * configure.in (HAVE_DL_SHL_LOAD): New for HPUX (Dave Dykstra). * VERSION: Now 0.9.8 Wed Jun 16 20:16:21 CEST 1999 Werner Koch * configure.in: Add test for docbook-to-man Tue Jun 15 12:21:08 CEST 1999 Werner Koch * acinclude.m4 (GNUPG_SYS_NM_PARSE): Support for {net,free}bsd, Thu Jun 10 14:18:23 CEST 1999 Werner Koch * configure.in (ZLIB,GDBM): Check both, header and lib. Sat Jun 5 15:30:33 CEST 1999 Werner Koch * pkclist.c (key_present_in_pk_list): New (Michael). Tue May 25 19:50:32 CEST 1999 Werner Koch * configure.in (IS_DEVELOPMENT_VERSION): Fixed detection. Sun May 23 14:20:22 CEST 1999 Werner Koch * acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): assume yes when cross-compiling. Mon May 17 21:54:43 CEST 1999 Werner Koch * configure.in (socket): Fix for Unisys by Katsuhiro Kondou. Sat May 8 19:28:08 CEST 1999 Werner Koch * NEWS: Add a marker line which I forgot to do for 0.9.6. Thu May 6 14:18:17 CEST 1999 Werner Koch * README: Minor updates * VERSION: Now 0.9.6 Thu Apr 8 09:35:53 CEST 1999 Werner Koch * acinclude.m4 (GNUPG_CHECK_RDYNAMIC): Fix for amiga-openbsd (Peter Reich) (GNUPG_PROG_NM): Ditto Wed Apr 7 20:51:39 CEST 1999 Werner Koch * Makefile.am (g10defs.h): Removed. * configure.in (AC_OUTPUT_COMMANDS): Create g10defs.h Sat Mar 20 12:55:33 CET 1999 Werner Koch * VERSION: Now 0.9.5 Sun Mar 14 19:34:36 CET 1999 Werner Koch * acinclude.m4 (AM_SYS_SYMBOL_UNDERSCORE): Removed because it is now in the latest libtool. Thu Mar 11 16:39:46 CET 1999 Werner Koch * configure.in: Removed the need for libtool Mon Mar 8 20:47:17 CET 1999 Werner Koch * configure.in (DLSYM_NEEDS_UNDERSCORE): Replaced. * acinclude.in (AM_SYS_SYMBOL_UNDERSCORE): New. * VERSION: Now 0.9.4 Sun Feb 28 19:11:00 CET 1999 Werner Koch * configure.in (dld): Test disabled. Fri Feb 26 17:55:41 CET 1999 Werner Koch * encode.c (encode_simple): temporary fix. Wed Feb 24 11:07:27 CET 1999 Werner Koch * configure.in: New option --enable-static-rnd. Mon Feb 22 20:04:00 CET 1999 Werner Koch * BUGS: Now we assign bug numbers. * OBUGS: New to keep rack o fixed bugs (CVS only) Fri Feb 19 18:01:54 CET 1999 Werner Koch * VERSION: Released 0.9.3 Fri Feb 19 15:49:15 CET 1999 Werner Koch * acinclude.m4: Removed gettext macros. Tue Feb 16 14:10:02 CET 1999 Werner Koch * configure.in (socket): Check for -lsocket and -lnsl. (osf4): Disable all warnings for DEC's cc. (-Wall): Add more warning options for gcc Sat Feb 13 12:04:43 CET 1999 Werner Koch * configure.in: Changed detection of compiler flags. * intl/ : Removed directory Wed Feb 10 17:15:39 CET 1999 Werner Koch * acinclude.m4 (GNUPG_CHECK_RDYNAMIC): Fix for freebsd 2.2 * configure.in: a lot of changes to allow selection of modules. Add support for OS/2. * acinclude.m4: add some more caching * README: Spelling and grammar corrections (John A. Martin) * INSTALL: Ditto. Wed Jan 20 21:40:21 CET 1999 Werner Koch * configure.in: --enable-m-guard is now default Wed Jan 13 12:49:36 CET 1999 Werner Koch * INSTALL: Applied new information how to build rpms by Fabio Coatti * Makefile.in (gnupg.spec): Changed the names. Tue Jan 12 11:17:18 CET 1999 Werner Koch * config.links (m68k-atari-mint): New Tue Jan 12 09:17:19 CET 1999 Gaël Quéri * all: Fixed typos all over the place Sat Jan 9 16:02:23 CET 1999 Werner Koch * configure.in: Add a way to statically link rndunix Sun Jan 3 15:28:44 CET 1999 Werner Koch * acinclude.m4 (GNUPG_CHECK_RDYNAMIC): New. * configure.in (DYNLOAD_CFLAGS): Use result from CHECK_RDYNAMIC Wed Dec 23 13:18:14 CET 1998 Werner Koch * README: Replaced the command overview with a short intro. Sat Dec 12 18:40:32 CET 1998 Werner Koch * configure.in: Add check for dlopen in libc (Greg Troxel) and a new define * acconfig.h (DLSYM_NEEDS_UNDERSCORE): New. Thu Dec 10 20:15:36 CET 1998 Werner Koch * acinclude.m (GNUPG_CHECK_PIC): New * configure.in, acinclude.m4: Renamed all WK_ to GNUPG_ Tue Dec 8 15:09:29 CET 1998 Werner Koch * VERSION: Set to 0.4.5 Wed Nov 25 12:38:29 1998 Werner Koch (wk@isil.d.shuttle.de) * configure.in (USE_RNDLINUX): New. Fri Nov 20 19:34:57 1998 Werner Koch (wk@isil.d.shuttle.de) * VERSION: Released 0.4.4 * configure.in (try_asm_modules): For option --disable-asm Tue Nov 10 19:32:40 1998 Werner Koch (wk@isil.d.shuttle.de) * configure.in (MPI_SFLAGS): New. Tue Nov 10 13:44:53 1998 Werner Koch (wk@isil.d.shuttle.de) * ABOUT-NLS: New * configure.in (AC_REVISION): New. Sun Nov 8 18:20:35 1998 Werner Koch (wk@isil.d.shuttle.de) * VERSION: Set to 0.4.3 Sun Oct 25 19:49:37 1998 Werner Koch (wk@isil.d.shuttle.de) * Makefile.am (g10defs.h): New macro GNUPG_DATADIR. Wed Oct 21 17:24:24 1998 Werner Koch (wk@isil.d.shuttle.de) * configure.in: Removed gettext kludge * acinclude.m4: Add patched AM_WITH_NKS macro Tue Oct 20 19:03:36 1998 Werner Koch (wk@isil.d.shuttle.de) * configure.in: Kludge to make AM_GNU_GETTEXT work, changed some macors to more modern versions. Also changeg the all makefiles to remove duplicate ../intl. * acinclude.m4: Removed the gettext stuff, as this already comes with automake now. Wed Oct 14 12:11:34 1998 Werner Koch (wk@isil.d.shuttle.de) * configure.in (NAME_OF_DEV_RANDOM): New. (DYNLINK_MOD_CFLAGS): New. Thu Oct 8 10:55:15 1998 Werner Koch (wk@isil.d.shuttle.de) * Makefile.am (g10defs.h): creates include file * acconfig.h: now includes g10defs.h * configure.in: Removed G10_LOCALEDIR and GNUPG_LIB Thu Sep 17 18:49:40 1998 Werner Koch (wk@(none)) * Makefile.am (dist-hook): Now creates RPM file. * scripts/gnupg.spec: New template file for RPMs Thu Jul 30 19:17:07 1998 Werner Koch (wk@(none)) * acinclude.h (WK_CHECK_IPC): New * configure.in : Add checks for SysV IPC Thu Jun 25 11:18:49 1998 Werner Koch (wk@isil.d.shuttle.de) * configure.in (--disable-dynload): New. Wed Jun 10 07:48:59 1998 Werner Koch,mobil,,, (wk@tobold) * configure.in (GNUPG_LIBDIR): New. Mon May 25 19:10:59 1998 Werner Koch (wk@isil.d.shuttle.de) * rand-unix.c (fast_random_poll): fixed syntax bug. Mon May 11 10:21:31 1998 Werner Koch (wk@isil.d.shuttle.de) * configure.in (PRINTABLE_OS_NAME): Linux is now GNU/Linux Tue Apr 14 19:08:05 1998 Werner Koch (wk@isil.d.shuttle.de) * [all files]: Applied Matthew Skala's typo and grammar fixes. Wed Mar 4 10:32:40 1998 Werner Koch (wk@isil.d.shuttle.de) * configure.in (getrusage,gettimeofday): New tests. Fri Feb 27 13:14:17 1998 Werner Koch (wk@isil.d.shuttle.de) * configure.in (--disable-m-guard): New. Thu Feb 26 17:09:27 1998 Werner Koch (wk@isil.d.shuttle.de) * configure.in, acinclude.m4, intl/, po/: New macros taken from GNOME, switched to automake 1.2f Thu Feb 26 09:05:46 1998 Werner Koch (wk@isil.d.shuttle.de) * configure.in (doc/Makefile): New Thu Feb 26 07:40:47 1998 Werner Koch (wk@isil.d.shuttle.de) * configure.in: Changed gettext stuff Wed Feb 25 11:44:10 1998 Werner Koch (wk@isil.d.shuttle.de) * checks/*test : restructured the directory. Tue Feb 24 15:59:12 1998 Werner Koch (wk@isil.d.shuttle.de) * configure.in: Changed the name of the package to GNUPG and chnaged several other names too. Wed Feb 18 17:36:45 1998 Werner Koch (wk@isil.d.shuttle.de) * Makefile.am (checks): New. Sat Feb 14 15:37:55 1998 Werner Koch (wk@isil.d.shuttle.de) * configure.in (mpi_config_done): Removed asm links caching. Sat Feb 14 14:02:20 1998 Werner Koch (wk@isil.d.shuttle.de) * configure.in (PRINTABLE_OS_NAME): New. * acconfig.h: Likewise. Fri Feb 13 19:43:41 1998 Werner Koch (wk@isil.d.shuttle.de) * configure.in : Fixed zlib stuff * Makefile.am: Likewise diff --git a/NEWS b/NEWS index ac834a1af..9a331119e 100644 --- a/NEWS +++ b/NEWS @@ -1,777 +1,786 @@ +Noteworthy changes in version 0.9.xx +------------------------------------ + + * UTF-8 strings are now correctly printed (if --charset is set correctly). + Output of --with-colons is remains C-style escaped UTF8. + + * Workaround for a problem with PGP 5 detached signature in textmode. + + Noteworthy changes in version 0.9.10 ------------------------------------ * Some strange new options to help pgpgpg * Cleaned up the dox a bit. Noteworthy changes in version 0.9.9 ----------------------------------- * New options --[no-]utf8-strings. * New edit-menu commands "enable" and "disable" for entire keys. * You will be asked for a filename if gpg cannot deduce one. * Changes to support libtool which is needed for the development of libgcrypt. * New script tools/lspgpot to help transferring assigned trustvalues from PGP to GnuPG. * New commands --lsign-key and made --sign-key a shortcut for --edit and sign. * New options (#122--126 ;-) --[no-]default-recipient[-self], --disable-{cipher,pubkey}-algo. See the man page. * Enhanced info output in case of multiple recipients and fixed exit code. * New option --allow-non-selfsigned-uid to work around a problem with the German IN way of separating signing and encryption keys. Noteworthy changes in version 0.9.8 ----------------------------------- * New subcommand "delsig" in the edit menu. * The name of the output file is not anymore the one which is embedded in the processed message, but the used filename with the extension stripped. To revert to the old behaviour you can use the option --use-embedded-filename. * Another hack to cope with pgp2 generated detached signatures. * latin-2 character set works (--charset=iso-8859-2). * New option --with-key-data to list the public key parameters. New option -N to insert notations and a --set-policy-url. A couple of other options to allow reseting of options. * Better support for HPUX. Noteworthy changes in version 0.9.7 ----------------------------------- * Add some work arounds for a bugs in pgp 2 which led to bad signatures - when used with canoncial texts in some cases. + when used with canonical texts in some cases. * Enhanced some status outputs. Noteworthy changes in version 0.9.6 ----------------------------------- * Twofish is now statically linked by default. The experimental 128 bit version is now disabled. Full support will be available as soon as the OpenPGP WG has decided on an interpretation of rfc2440. * Dropped support for the ancient Blowfish160 which is not OpenPGP. * Merged gpgm and gpg into one binary. * Add "revsig" and "revkey" commands to the edit menu. It is now possible to revoke signature and subkeys. Noteworthy changes in version 0.9.5 ----------------------------------- * New command "lsign" in the keyedit menu to create non-exportable signatures. Removed --trusted-keys option. * A bunch of changes to the key validation code. * --list-trust-path now has an optional --with-colons format. * New command --recv-keys to import keys from an keyserver. Noteworthy changes in version 0.9.4 ----------------------------------- * New configure option --enable-static-rnd=[egd|linux|unix|none] to select a random gathering module for static linking. * The original text is now verbatim copied to a cleartext signed message. * Bugfixes but there are still a couple of bugs. Noteworthy changes in version 0.9.3 ----------------------------------- * Changed the internal design of getkey which now allows a efficient lookup of multiple keys and add a word match mode. * New options --[no-]encrypt-to. * Some changes to the configure stuff. Switched to automake 1.4. Removed intl/ from CVS, autogen.sh now uses gettextize. * Preferences now include Twofish. Removed preference to Blowfish with a special hack to suppress the "not listed in preferences" warning; this is to allow us to switch completely to Twofish in the near future. * Changed the locking stuff. * Print all user ids of a good signature. Noteworthy changes in version 0.9.2 ----------------------------------- * add some additional time warp checks. * Option --keyserver and command --send-keys to utilize HKP servers. * Upgraded to zlib 1.1.3 and fixed an inflate bug * More cleanup on the cleartext signatures. Noteworthy changes in version 0.9.1 ----------------------------------- * Polish language support. * When querying the passphrase, the key ID of the primary key is displayed along with the one of the used secondary key. * Fixed a bug occurring when decrypting pgp 5 encrypted messages, fixed an infinite loop bug in the 3DES code and in the code which looks for trusted signatures. * Fixed a bug in the mpi library which caused signatures not to compare okay. * Rewrote the handling of cleartext signatures; the code is now better maintainable (I hope so). * New status output VALIDSIG only for valid signatures together with the fingerprint of the signer's key. Noteworthy changes in version 0.9.0 ----------------------------------- * --export does now only exports rfc2440 compatible keys; the old behaviour is available with --export-all. Generation of v3 ElGamal (sign and encrypt) keys is not longer supported. * Fixed the uncompress bug. * Rewrote the rndunix module. There are two environment variables used for debugging now: GNUPG_RNDUNIX_DBG give the file to write debugging information (use "-" for stdout) and if GNUPG_RNDUNIX_DBGALL is set, all programs which are only tried are also printed. * New option --escape-from-lines to "dash-escape" "From " lines to prevent mailers to change them to ">From ". This is not enabled by default because it is not in compliance with rfc2440 - however, you should turn it on. Noteworthy changes in version 0.4.5 ----------------------------------- * The keyrings and the trustdb is now locked, so that other GnuPG processes won't damage these files. You may want to put the option --lock-once into your options file. * The latest self-signatures are now used; this enables --import to see updated preferences etc. * Import of subkeys should now work. * Random gathering modules may now be loaded as extensions. Add such a module for most Unices but it is very experimental! * Brazilian language support. Noteworthy changes in version 0.4.4 ----------------------------------- * Fixed the way the key expiration time is stored. If you have an expiration time on your key you should fix it with --edit-key and the command "expire". I apologize for this inconvenience. * Add option --charset to support "koi8-r" encoding of user ids. (Not yet tested). * Preferences should now work again. You should run "gpgm --check-trustdb \*" to rebuild all preferences. * Checking of certificates should now work but this needs a lot of testing. Key validation values are now cached in the trustdb; they should be recalculated as needed, but you may use --check-trustdb or --update-trustdb to do this. * Spanish translation by Urko Lusa. * Patch files are from now on signed. See the man page for the new option --not-dash-escaped. * New syntax: --edit-key [] If you run it without --batch the commands are executed and then you are put into normal mode unless you use "quit" or "save" as one of the commands. When in batch mode, the program quits after the last command, so you have to use "save" if you did some changes. It does not yet work completely, but may be used to list so the keys etc. Noteworthy changes in version 0.4.3 ----------------------------------- * Fixed the gettext configure bug. * Kludge for RSA keys: keyid and length of a RSA key are correctly reported, but you get an error if you try to use this key (If you do not have the non-US version). * Experimental support for keyrings stored in a GDBM database. This is *much* faster than a standard keyring. You will notice that the import gets slower with time; the reason is that all new keys are used to verify signatures of previous inserted keys. Use "--keyring gnupg-gdbm:". This is not (yet) supported for secret keys. * A Russian language file in the distribution (alternatives are in the contrib directory of the FTP servers) * commandline option processing now works as expected for GNU programs with the exception that you can't mix options and normal arguments. * Now --list-key lists all matching keys. This is needed in some other places too. Noteworthy changes in version 0.4.2 ----------------------------------- * This is only a snapshot: There are still a few bugs. * Fixed this huge memory leak. * Redesigned the trust database: You should run "gpgm --check-trustdb". New command --update-trustdb, which adds new key from the public keyring into your trustdb * Fixed a bug in the armor code, leading to invalid packet errors. (a workaround for this was to use --no-armor). The shorten line length (64 instead of 72) fixes a problem with pgp5 and keyservers. * comment packets are not anymore generated. "--export" filters them out. One Exception: The comment packets in a secret keyring are still used because they carry the factorization of the public prime product. * --import now only looks for KEYBLOCK headers, so you can now simply remove the "- " in front of such a header if someone accidently signed such a message or the keyblock is part of a cleartext signed message. * --with-colons now lists the key expiration time and not anymore the valid period. * Some keyblocks created with old releases have a wrong sequence of packets, so that the keyservers don't accept these keys. Simply using "--edit-key" fixes the problem. * New option --force-v3-sigs to generate signed messages which are compatible to PGP 5. * Add some code to support DLD (for non ELF systems) - but this is not tested because my BSD box is currently broken. * New command "expire" in the edit-key menu. Noteworthy changes in version 0.4.1 ----------------------------------- * A secondary key is used when the primary key is specified but cannot be used for the operation (if it is a sign-only key). * GNUPG can now handle concatenated armored messages: There is still a bug if different kinds of messages are mixed. * Iterated+Salted passphrases now work. If want to be sure that PGP5 is able to handle them you may want to use the options "--s2k-mode 3 --s2k-cipher-algo cast5 --s2k-digest-algo sha1" when changing a passphrase. * doc/OpenPGP talks about OpenPGP compliance, doc/HACKING gives a few hints about the internal structure. * Checked gnupg against the August 1998 draft (07) and I believe it is in compliance with this document (except for one point). * Fixed some bugs in the import merging code and rewrote some code for the trustdb. Noteworthy changes in version 0.4.0 ----------------------------------- * Triple DES is now supported. Michael Roth did this piece of needed work. We have now all the coded needed to be OpenPGP compliant. * Added a simple rpm spec file (see INSTALL). * detached and armored signatures are now using "PGP SIGNATURE", except when --rfc1991 is used. * All times which are not in the yyy-mm-dd format are now printed in local time. Noteworthy changes in version 0.3.5 ----------------------------------- * New option --throw-keyid to create anonymous enciphered messages. If gpg detects such a message it tires all available secret keys in turn so decode it. This is a gnupg extension and not in OpenPGP but it has been discussed there and afaik some products use this scheme too (Suggested by Nimrod Zimmerman). * Fixed a bug with 5 byte length headers. * --delete-[secret-]key is now also available in gpgm. * cleartext signatures are not anymore converted to LF only. * Fixed a trustdb problem. Run "gpgm --check-trustdb" to fix old trust dbs. * Building in another directory should now work. * Weak key detection mechanism (Niklas Hernaeus). Noteworthy changes in version 0.3.4 ----------------------------------- * New options --comment and --set-filename; see g10/OPTIONS * yes/no, y/n localized. * Fixed some bugs. Noteworthy changes in version 0.3.3 ----------------------------------- * IMPORTANT: I found yet another bug in the way the secret keys are encrypted - I did it the way pgp 2.x did it, but OpenPGP and pgp 5.x specify another (in some aspects simpler) method. To convert your secret keys you have to do this: 1. Build the new release but don't install it and keep a copy of the old program. 2. Disable the network, make sure that you are the only user, be sure that there are no Trojan horses etc .... 3. Use your old gpg (version 0.3.[12]) and set the passphrases of ALL your secret keys to empty! (gpg --change-passphrase your-user-id). 4. Save your ownertrusts (see the next point) 5. rm ~/.gnupg/trustdb.gpg 6. install the new version of gpg (0.3.3) 7. For every secret key call "gpg --edit-key your-user-id", enter "passwd" at the prompt, follow the instructions and change your password back, enter "save" to store it. 8. Restore the ownertrust (see next point). * The format of the trust database has changed; you must delete the old one, so gnupg can create a new one. IMPORTANT: Use version 0.3.[12] to save your assigned ownertrusts ("gpgm --list-ownertrust >saved-trust"); then build this new version and restore the ownertrust with this new version ("gpgm --import-ownertrust saved-trust"). Please note that --list-ownertrust has been renamed to --export-ownertrust in this release and it does now only export defined ownertrusts. * The command --edit-key now provides a commandline driven menu which can be used for various tasks. --sign-key is only an an alias to --edit-key and maybe removed in future: use the command "sign" of this new menu - you can select which user ids you want to sign. * Alternate user ids can now be created an signed. * Owner trust values can now be changed with --edit-key (trust) * GNUPG can now run as a coprocess; this enables sophisticated frontends. tools/shmtest.c is a simple sample implementation. This needs some more work: all tty_xxx() are to be replaced by cpr_xxx() and some changes in the display logics is needed. * Removed options --gen-prime and --gen-random. * Removed option --add-key; use --edit-key instead. * Removed option --change-passphrase; use --edit-key instead. * Signatures are now checked even if the output file could not be created. Command "--verify" tries to find the detached data. * gpg now disables core dumps. * compress and symmetric cipher preferences are now used. Because there is no 3DES yet, this is replaced by Blowfish. * We have added the Twofish as an experimental cipher algorithm. Many thanks to Matthew Skala for doing this work. Twofish is the AES submission from Schneier et al.; see "www.counterpane.com/twofish.html" for more information. * Started with a help system: If you enter a question mark at some prompt; you should get a specific help for this prompt. * There is no more backup copy of the secret keyring. * A lot of new bugs. I think this release is not as stable as the previous one. Noteworthy changes in version 0.3.2 ----------------------------------- * Fixed some bugs when using --textmode (-seat) * Now displays the trust status of a positive verified message. * Keyrings are now scanned in the sequence they are added with --[secret-]keyring. Note that the default keyring is implicitly added as the very first one unless --no-default-keyring is used. * Fixed setuid and dlopen bug. Noteworthy changes in version 0.3.1 ----------------------------------- * Partial headers are now written in the OpenPGP format if a key in a v4 packet is used. * Removed some unused options, removed the gnupg.sig stuff. * Key lookup by name now returns a key which can be used for the desired action. * New options --list-ownertrust (gpgm) to make a backup copy of the ownertrust values you assigned. * clear signature headers are now in compliance with OpenPGP. Noteworthy changes in version 0.3.0 ----------------------------------- * New option --emulate-checksum-bug. If your passphrase does not work anymore, use this option and --change-passphrase to rewrite your passphrase. * More complete v4 key support: Preferences and expiration time is set into the self signature. * Key generation defaults to DSA/ElGamal keys, so that new keys are interoperable with pgp5 * DSA key generation is faster and key generation does not anymore remove entropy from the random generator (the primes are public parameters, so there is really no need for a cryptographic secure prime number generator which we had used). * A complete new structure for representing the key parameters. * Removed most public key knowledge into the cipher library. * Support for dynamic loading of new algorithms. * Moved tiger to an extension module. Noteworthy changes in version 0.2.19 ------------------------------------ * Replaced /dev/urandom in checks with new tool mk-tdata. * Some assembler file cleanups; some more functions for the Alpha. * Tiger has now the OpenPGP assigned number 6. Because the OID has changed, old signatures using this algorithm can't be verified. * gnupg now encrypts the compressed packed and not any longer in the reverse order; anyway it can decrypt both versions. Thanks to Tom for telling me this (not security related) bug. * --add-key works and you are now able to generate subkeys. * It is now possible to generate ElGamal keys in v4 packets to create valid OpenPGP keys. * Some new features for better integration into MUAs. Noteworthy changes in version 0.2.18 ------------------------------------ * Splitted cipher/random.c, add new option "--disable-dev-random" to configure to support the development of a random source for other systems. Prepared sourcefiles rand-unix.c, rand-w32.c and rand-dummy.c (which is used to allow compilation on systems without a random source). * Fixed a small bug in the key generation (it was possible that 48 bits of a key were not taken from the random pool) * Add key generation for DSA and v4 signatures. * Add a function trap_unaligned(), so that a SIGBUS is issued on Alphas and not the slow emulation code is used. And success: rmd160 raised a SIGBUS. * Enhanced the formatting facility of argparse and changed the use of \r,\v to @ because gettext does not like it. * New option "--compress-algo 1" to allow the creation of compressed messages which are readable by PGP and "--print-md" (gpgm) to make speed measurement easier. Noteworthy changes in version 0.2.17 ------------------------------------ * Comment packets are now of private type 61. * Passphrase code still used a 160 bit blowfish key, added a silly workaround. Please change your passphrase again - sorry. * Conventional encryption now uses a type 3 packet to describe the used algorithms. * The new algorithm number for Blowfish is 20, 16 is still used for encryption only; for signing it is only used when it is in a v3 packet, so that GNUPG keys are still valid. Noteworthy changes in version 0.2.16 ------------------------------------ * Add experimental support for the TIGER/192 message digest algorithm. (But there is only a dummy ASN OID). * Standard cipher is now Blowfish with 128 bit key in OpenPGP's CFB mode. I renamed the old cipher to Blowfish160. Because the OpenPGP group refused to assign me a number for Blowfish160, I have to drop support for this in the future. You should use "--change-passphrase" to recode your current passphrase with 128 bit Blowfish. Noteworthy changes in version 0.2.15 ------------------------------------ * Fixed a bug with the old checksum calculation for secret keys. If you run the program without --batch, a warning does inform you if your secret key needs to be converted; simply use --change-passphrase to recalculate the checksum. Please do this soon, as the compatible mode will be removed sometime in the future. * CAST5 works (using the PGP's special CFB mode). * Again somewhat more PGP 5 compatible. * Some new test cases Noteworthy changes in version 0.2.14 ------------------------------------ * Changed the internal handling of keyrings. * Add support to list PGP 5 keyrings with subkeys * Timestamps of signatures are now verified. * A expiration time can now be specified during key generation. * Some speedups for Blowfish and SHA-1, rewrote SHA-1 transform. Reduced the amount of random bytes needed for key generation in some cases. Noteworthy changes in version 0.2.13 ------------------------------------ * Verify of DSA signatures works. * Re-implemented the slower random number generator. Noteworthy changes in version 0.2.12 ------------------------------------ * --delete-key checks that there is no secret key. The new option --delete-secret-key maybe used to delete a secret key. * "-kv" now works as expected. Options "--list-{keys,sigs]" and "--check-sigs" are now working. * New options "--verify" and "--decrypt" to better support integration into MUAs (partly done for Mutt). * New option "--with-colons" to make parsing of key lists easier. Noteworthy changes in version 0.2.11 ------------------------------------ * GPG now asks for a recipient's name if option "-r" is not used. * If there is no good trust path, the program asks whether to use the public keys anyway. * "--delete-key" works for public keys. What semantics shall I use when there is a secret key too? Delete the secret key or leave him and auto-regenerate the public key, next time the secret key is used? Noteworthy changes in version 0.2.10 ------------------------------------ * Code for the alpha is much faster (about 20 times); the data was misaligned and the kernel traps this, so nearly all time was used by system to trap the misalignments and to write syslog messages. Shame on me and thanks to Ralph for pointing me at this while drinking some beer yesterday. * Changed some configure options and add an option --disable-m-guard to remove the memory checking code and to compile everything with optimization on. * New environment variable GNUPGHOME, which can be used to set another homedir than ~/.gnupg. Changed default homedir for Windoze version to c:/gnupg. * Fixed detached signatures; detached PGP signatures caused a SEGV. * The Windoze version works (as usual w/o a strong RNG). Noteworthy changes in version 0.2.9 ----------------------------------- * Fixed FreeBSD bug. * Added a simple man page. * Switched to automake1.2f and a newer gettext. Noteworthy changes in version 0.2.8 ----------------------------------- * Changed the name to GNUPG, the binaries are called gpg and gpgm. You must rename rename the directory "~/.g10" to ~/.gnupg/, rename {pub,sec}ring.g10 to {pub,sec}ring.gpg, trustdb.g10 to trustdb.gpg and g10.sig to gnupg.sig. * New or changed passphrases are now salted. Noteworthy changes in version 0.2.7 ----------------------------------- * New command "gen-revoke" to create a key revocation certificate. * New option "homedir" to set the homedir (which defaults to "~/.g10"). This directory is created if it does not exists (only the last part of the name and not the complete hierarchy) * Command "import" works. (Try: "finger gcrypt@ftp.guug.de|g10 --import") * New commands "dearmor/enarmor" for g10maint. These are mainly used for internal test purposes. * Option --version now conforming to the GNU standards and lists the available ciphers, message digests and public key algorithms. * Assembler code for m68k (not tested). * "make check" works. Noteworthy changes in version 0.2.6 ----------------------------------- * Option "--export" works. Noteworthy changes in version 0.2.5 ----------------------------------- * Added zlib for systems which don't have it. Use "./configure --with-zlib" to link with the static version. * Generalized some more functions and rewrote the encoding of message digests into MPIs. * Enhanced the checkit script Noteworthy changes in version 0.2.4 ----------------------------------- * nearly doubled the speed of the ElGamal signature verification. * backup copies of keyrings are created. * assembler stuff for Pentium; gives about 15% better performance. * fixed a lot of bugs. Noteworthy changes in version 0.2.3 ----------------------------------- * Found a bug in the calculation of ELG fingerprints. This is now fixed, but all existing fingerprints and keyids for ELG keys are not any more valid. * armor should now work; including clear signed text. * moved some options to the new program g10maint * It's now 64 bit clean and runs fine on an alpha--linux. * Key generation is much faster now. I fixed this by using not so strong random number for the primes (this was a bug because the ElGamal primes are public parameters and it does not make sense to generate them from strong random). The real secret is the x value which is still generated from strong (okay: /dev/random) random bits. * added option "--status-fd": see g10/OPTIONS * We have secure memory on systems which support mlock(). It is not complete yet, because we do not have signal handler which does a cleanup in very case. We should also check the ulimit for the user in the case that the admin does not have set a limit on locked pages. * started with internationalization support. * The logic to handle the web of trust is now implemented. It is has some bugs; but I'm going to change the algorithm anyway. It works by calculating the trustlevel on the fly. It may ask you to provide trust parameters if the calculated trust probability is too low. I will write a paper which discusses this new approach. * a couple of changes to the configure script. * New option "--quick-random" which uses a much quicker random number generator. Keys generated while this option is in effect are flags with "INSECURE!" in the user-id. This is a development only option. * Read support for new version packets (OpenPGP). * Comment packets are now of correct OpenPGP type 16. Old comment packets written by G10 are detected because they always start with a hash which is an invalid version byte. * The string "(INSECURE!)" is appended to a new user-id if this is generated on a system without a good random number generator. diff --git a/README b/README index 3c015a154..5d934b2f8 100644 --- a/README +++ b/README @@ -1,528 +1,528 @@ -----BEGIN PGP SIGNED MESSAGE----- GnuPG - The GNU Privacy Guard ------------------------------- Version 0.9.10 GnuPG is now in Beta test and you should report all bugs to the mailing list (see below). The 0.9.x versions are released mainly to fix all remaining serious bugs. As soon as version 1.0 is out, development will continue with a 1.1 series and bug fixes for the 1.0 version as needed. GnuPG works best on GNU/Linux or *BSD. Other Unices are also supported but are not as well tested as the Free Unices. See the file COPYING for copyright and warranty information. GnuPG is in compliance with RFC2440 (OpenPGP), see doc/OpenPGP for details. Because GnuPG does not use use any patented algorithm it cannot be compatible with PGP2 versions. PGP 2.x uses only IDEA (which is patented worldwide) and RSA (which is patented in the United States until Sep 20, 2000). The default algorithms are DSA and ElGamal. ElGamal for signing is still available, but because of the larger size of such signatures it is deprecated (Please note that the GnuPG implementation of ElGamal signatures is *not* insecure). Symmetric algorithms are: 3DES, Blowfish, CAST5 and Twofish (GnuPG does not yet create Twofish encrypted messages because there no agreement - in the OpenPG WG on how to use it together with a MDC algorithm) + in the OpenPGP WG on how to use it together with a MDC algorithm) Digest algorithms available are MD5, RIPEMD160, SHA1, and TIGER/192. Installation ------------ Please read the file INSTALL! Here is a quick summary: 1) Check that you have unmodified sources. The below on how to do this. Don't skip it - this is an important step! 2) Unpack the TAR. With GNU tar you can do it this way: "tar xzvf gnupg-x.y.z.tar.gz" 3) "cd gnupg-x.y.z" 4) "./configure" 5) "make" 6) "make install" 7) You end up with a "gpg" binary in /usr/local/bin. Note: Because some old programs rely on the existence of a binary named "gpgm"; you should install a symbolic link from gpgm to gpg: "cd /usr/local/bin; ln -s gpg gpgm" 8) To avoid swapping out of sensitive data, you can install "gpg" as suid root. If you don't do so, you may want to add the option "no-secmem-warning" to ~/.gnupg/options How to Verify the Source ------------------------ In order to check that the version of GnuPG which you are going to install is an original and unmodified one, you can do it in one of the following ways: a) If you already have a trusted Version of GnuPG installed, you can simply check the supplied signature: $ gpg --verify gnupg-x.y.z.tar.gz.asc This checks that the detached signature gnupg-x.y.z.tar.gz.asc is indeed a a signature of gnupg-x.y.z.tar.gz. The key used to create this signature is: "pub 1024D/57548DCD 1998-07-07 Werner Koch (gnupg sig) " If you do not have this key, you can get it from the source in the file g10/pubring.asc (use "gpg --import g10/pubring.gpg" to add it to the keyring) or from any keyserver. You have to make sure that this is really the key and not a faked one. You can do this by comparing the output of: $ gpg --fingerprint 0x57548DCD with the elsewhere published fingerprint, or - if you are able to _positively_ verify the signature of this README file - with this fingerprint: "6BD9 050F D8FC 941B 4341 2DCC 68B7 AB89 5754 8DCD" Please note, that you have to use an old version of GnuPG to do all this stuff. *Never* use the version which you are going to check! b) If you have a trusted Version of PGP 2 or 5 installed, you can check the supplied PGP 2 signature: $ pgp gnupg-x.y.z.tar.gz.sig gnupg-x.y.z.tar.gz This checks that the detached signature gnupg-x.y.z.tar.gz.sig is indeed a a signature of gnupg-x.y.z.tar.gz. Please note, that this signature has been created with a RSA signature and you probably can't use this method (due to legal reasons) when you are in the U.S. The key used to create this signature is the same as the one used to sign this README file. It should be available at the keyservers and is also included in the source of GnuPG in g10/pubring.asc. "pub 768R/0C9857A5 1995-09-30 Werner Koch " - The finperprint of this key is published in printed form in the + The fingerprint of this key is published in printed form in the "Global Trust Register for 1998", ISBN 0-9532397-0-5. c) If you don't have any of the above programs, you have to verify the MD5 checksum: $ md5sum gnupg-x.y.z.tar.gz.sig This should yield an output similar to this: fd9351b26b3189c1d577f0970f9dcadc gnupg-x.y.z.tar.gz Now check that this checksum is _exactly_ the same as the one - published via the anouncement list and probably via Usenet. + published via the announcement list and probably via Usenet. Introduction ------------ This is a brief overview how to use GnuPG - it is strongly suggested that you read the manual^H^H^H more information about the use of cryptography. GnuPG is only a tool, secure results require that YOU KNOW WHAT YOU ARE DOING. If you already have a DSA key from PGP 5 (they call them DH/ElGamal) you can simply copy the pgp keyrings over the GnuPG keyrings after running gpg once to create the correct directory. The normal way to create a key is gpg --gen-key This asks some questions and then starts key generation. To create good random numbers for the key parameters, GnuPG needs to gather enough noise (entropy) from your system. If you see no progress during key generation you should start some other activities such as mouse moves or hitting on the CTRL and SHIFT keys. Generate a key ONLY on a machine where you have direct physical access - don't do it over the network or on a machine used also by others - especially if you have no access to the root account. When you are asked for a passphrase use a good one which you can easy remember. Don't make the passphrase too long because you have to type it for every decryption or signing; but, - AND THIS IS VERY IMPORTANT - use a good one that is not easily to guess because the security of the whole system relies on your secret key and the passphrase that protects it when someone gains access to your secret keyring. A good way to select a passphrase is to figure out a short nonsense sentence which makes some sense for you and modify it by inserting extra spaces, non-letters and changing the case of some characters - this is really easy to remember especially if you associate some pictures with it. Next, you should create a revocation certificate in case someone gets knowledge of your secret key or you forgot your passphrase gpg --gen-revoke your_user_id Run this command and store the revocation certificate away. The output is always ASCII armored, so that you can print it and (hopefully never) re-create it if your electronic media fails. Now you can use your key to create digital signatures gpg -s file This creates a file "file.gpg" which is compressed and has a signature attached. gpg -sa file Same as above, but creates a file "file.asc" which is ASCII armored and and ready for sending by mail. It is better to use your mailers features to create signatures (The mailer uses GnuPG to do this) because the mailer has the ability to MIME encode such signatures - but this is not a security issue. gpg -s -o out file Creates a signature of "file", but writes the output to the file "out". Everyone who knows your public key (you can and should publish your key by putting it on a key server, a web page or in your .plan file) is now able to check whether you really signed this text gpg --verify file GnuPG now checks whether the signature is valid and prints an appropriate message. If the signature is good, you know at least that the person (or machine) has access to the secret key which corresponds to the published public key. If you run gpg without an option it will verify the signature and create a new file that is identical to the original. gpg can also run as a filter, so that you can pipe data to verify trough it cat signed-file | gpg | wc -l which will check the signature of signed-file and then display the number of lines in the original file. To send a message encrypted to someone you can use gpg -e -r heine file This encrypts "file" with the public key of the user "heine" and writes it to "file.gpg" echo "hello" | gpg -ea -r heine | mail heine Ditto, but encrypts "hello\n" and mails it as ASCII armored message to the user with the mail address heine. gpg -se -r heine file This encrypts "file" with the public key of "heine" and writes it to "file.gpg" after signing it with your user id. gpg -se -r heine -u Suttner file Ditto, but sign the file with your alternative user id "Suttner" GnuPG has some options to help you publish public keys. This is called "exporting" a key, thus gpg --export >all-my-keys exports all the keys in the keyring and writes them (in a binary format) to "all-my-keys". You may then mail "all-my-keys" as an MIME attachment to someone else or put it on an FTP server. To export only some user IDs, you give them as arguments on the command line. To mail a public key or put it on a web page you have to create the key in ASCII armored format gpg --export --armor | mail panther@tiger.int This will send all your public keys to your friend panther. If you have received a key from someone else you can put it into your public keyring. This is called "importing" gpg --import [filenames] New keys are appended to your keyring and already existing keys are updated. Note that GnuPG does not import keys that are not self-signed. Because anyone can claim that a public key belongs to her we must have some way to check that a public key really belongs to the owner. This can be achieved by comparing the key during a phone call. Sure, it is not very easy to compare a binary file by reading the complete hex dump of the file - GnuPG (and nearly every other program used for management of cryptographic keys) provides other solutions. gpg --fingerprint prints the so called "fingerprint" of the given username which is a sequence of hex bytes (which you may have noticed in mail sigs or on business cards) that uniquely identifies the public key - different keys will always have different fingerprints. It is easy to compare fingerprints by phone and I suggest that you print your fingerprint on the back of your business card. To see the fingerprints of the secondary keys, you can give the command twice; but this is normally not needed. If you don't know the owner of the public key you are in trouble. Suppose however that friend of yours knows someone who knows someone who has met the owner of the public key at some computer conference. Suppose that all the people between you and the public key holder may now act as introducers to you. Introducers signing keys thereby certify that they know the owner of the keys they sign. If you then trust all the introducers to have correctly signed other keys, you can be be sure that the other key really belongs to the one who claims to own it.. There are 2 steps to validate a key: 1. First check that there is a complete chain of signed keys from the public key you want to use and your key and verify each signature. 2. Make sure that you have full trust in the certificates of all the introduces between the public key holder and you. Step 2 is the more complicated part because there is no easy way for a computer to decide who is trustworthy and who is not. GnuPG leaves this decision to you and will ask you for a trust value (here also referenced as the owner-trust of a key) for every key needed to check the chain of certificates. You may choose from: a) "I don't know" - then it is not possible to use any of the chains of certificates, in which this key is used as an introducer, to validate the target key. Use this if you don't know the introducer. b) "I do not trust" - Use this if you know that the introducer does not do a good job in certifying other keys. The effect is the same as with a) but for a) you may later want to change the value because you got new information about this introducer. c) "I trust marginally" - Use this if you assume that the introducer knows what he is doing. Together with some other marginally trusted keys, GnuPG validates the target key then as good. d) "I fully trust" - Use this if you really know that this introducer does a good job when certifying other keys. If all the introducer are of this trust value, GnuPG normally needs only one chain of signatures to validate a target key okay. (But this may be adjusted with the help of some options). This information is confidential because it gives your personal opinion on the trustworthiness of someone else. Therefore this data is not stored in the keyring but in the "trustdb" (~/.gnupg/trustdb.gpg). Do not assign a high trust value just because the introducer is a friend of yours - decide how well she understands the implications of key signatures and you may want to tell her more about public key cryptography so you can later change the trust value you assigned. Okay, here is how GnuPG helps you with key management. Most stuff is done with the --edit-key command gpg --edit-key GnuPG displays some information about the key and then prompts for a command (enter "help" to see a list of commands and see the man page for a more detailed explanation). To sign a key you select the user ID you want to sign by entering the number that is displayed in the leftmost column (or do nothing if the key has only one user ID) and then enter the command "sign" and follow all the prompts. When you are ready, give the command "save" (or use "quit" to cancel your actions). If you want to sign the key with another of your user IDs, you must give an "-u" option on the command line together with the "--edit-key". Normally you want to sign only one user ID because GnuPG uses only one and this keeps the public key certificate small. Because such key signatures are very important you should make sure that the signatories of your key sign a user ID which is very likely to stay for a long time - choose one with an email address you have full control of or do not enter an email address at all. In future GnuPG will have a way to tell which user ID is the one with an email address you prefer - because you have no signatures on this email address it is easy to change this address. Remember, your signatories sign your public key (the primary one) together with one of your user IDs - so it is not possible to change the user ID later without voiding all the signatures. Tip: If you hear about a key signing party on a computer conference join it because this is a very convenient way to get your key certified (But remember that signatures have nothing to to with the trust you assign to a key). 8 Ways to Specify a User ID -------------------------- There are several ways to specify a user ID, here are some examples. * Only by the short keyid (prepend a zero if it begins with A..F): "234567C4" "0F34E556E" "01347A56A" "0xAB123456 * By a complete keyid: "234AABBCC34567C4" "0F323456784E56EAB" "01AB3FED1347A5612" "0x234AABBCC34567C4" * By a fingerprint: "1234343434343434C434343434343434" "123434343434343C3434343434343734349A3434" "0E12343434343434343434EAB3484343434343434" The first one is MD5 the others are ripemd160 or sha1. * By an exact string: "=Heinrich Heine " * By an email address: "" * By word match "+Heinrich Heine duesseldorf" - All words must match excatly (not case sensitive) and appear in + All words must match exactly (not case sensitive) and appear in any order in the user ID. Words are any sequences of letters, digits, the underscore and characters with bit 7 set. * By the Local ID (from the trust DB): "#34" This may be used by a MUA to specify an exact key after selecting a key from GnuPG (by using a special option or an extra utility) * Or by the usual substring: "Heine" "*Heine" The '*' indicates substring search explicitly. Batch mode ---------- If you use the option "--batch", GnuPG runs in non-interactive mode and never prompts for input data. This does not even allow entering the passphrase. Until we have a better solution (something like ssh-agent), - you can use the option "--passphrase-fd n", which works like PGPs + you can use the option "--passphrase-fd n", which works like PGP's PGPPASSFD. Batch mode also causes GnuPG to terminate as soon as a BAD signature is detected. Exit status ----------- GnuPG returns with an exit status of 1 if in batch mode and a bad signature has been detected or 2 or higher for all other errors. You should parse stderr or, better, the output of the fd specified with --status-fd to get detailed information about the errors. Esoteric commands ----------------- gpg --list-packets datafile Use this to list the contents of a data file. If the file is encrypted you are asked for the passphrase, so that GnuPG is able to look at the inner structure of a encrypted packet. This command should list all kinds of rfc2440 messages. gpg --list-trustdb List the contents of the trust DB in a human readable format gpg --list-trustdb List the tree of certificates for the given usernames gpg --list-trust-path username List the possible trust paths for the given username. The length of such a trust path is limited by the option --max-cert-depth which defaults to 5. For more options/commands see the man page or use "gpg --help". Other Notes ----------- The primary FTP site is "ftp://ftp.gnupg.org/pub/gcrypt/" The primary WWW page is "http://www.gnupg.org" See http://www.gnupg.org/mirrors.html for a list of FTP mirrors and use them if possible. We have some mailing lists dedicated to GnuPG: gnupg-announce@gnupg.org For important announcements like new versions and such stuff. This is a moderated list and has very low traffic. gnupg-users@gnupg.org For general user discussion and help. gnupg-devel@gnupg.org GnuPG developers main forum. You subscribe to one of the list by sending mail with a subject of "subscribe" to x-request@gnupg.org, where x is the name of the mailing list (gnupg-announce, gnupg-users, etc.). An archive of the mailing lists is available at http://lists.gnupg.org . The gnupg.org domain is hosted in Germany to avoid possible legal problems (technical advices may count as a violation of ITAR). Please direct bug reports to or post them direct to the mailing list . Please direct questions about GnuPG to the users mailing list or one of the pgp newsgroups and give me more time to improve GnuPG. Commercial support for GnuPG is also available; please see the GNU service directory or search other resources. Have fun and remember: Echelon is looking at you kid. - -----END PGP SIGNATURE----- -----BEGIN PGP SIGNATURE----- Version: GnuPG v0.9.9 (GNU/Linux) Comment: For info see http://www.gnupg.org iQB1AwUBN6figR0Z9MEMmFelAQHydwL+LuKC3W6kRkm0clwab3v8I7zlX0bagxzA RStlHXdO6ln1Mo3s3nBuCfrS6LogiUgNRFhNJQ5+rjrTydz00nzcorbyTalqvMlq Gnsu9Pd/pTPzvk6kP79yDdoBxfaQGcgw =W8uz -----END PGP SIGNATURE----- diff --git a/THOUGHTS b/THOUGHTS index b073b5ff2..1ff9e92f1 100644 --- a/THOUGHTS +++ b/THOUGHTS @@ -1,237 +1,237 @@ 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 + 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 - 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. -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 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 ?) 2) allow multiple instances of the same extension module (presumably with different arguments) 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 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 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. 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. 5) have an extension to perform a secret-key operation without the actual secret key material 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 ): ===================== 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 currently designing a new storage system called keybox which takes advantage of the fact that the keyID is highly random and can be 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). 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. Suggested things which I will not do: ===================================== * Let take --help an option to select some topics. Using grep is much easier diff --git a/TODO b/TODO index dfb71b4fe..d05abb406 100644 --- a/TODO +++ b/TODO @@ -1,59 +1,54 @@ - * use-emmbeded-filename ist nicht dokumentiert. - - * --disable-asm should still assemble _udiv_qrnnd when needed - - * Skip RO keyrings when importing a key. - - * help the translaters to catch changes made to helptext.c - and tell that, that they have to translate those strings. - Scheduled for 1.1 ----------------- * With option -i prompt before adding a key to the keyring and show some info what we are about to add. * Speed up calculation of key validation. * Allow a replacement for the progress functions in ./cipher * add an option to use an OpenPGP packet as input (and don't build a literal data packet) * print a warning when a revoked/expired _secret_ key is used. + * --disable-asm should still assemble _udiv_qrnnd when needed + + * Skip RO keyrings when importing a key. + Nice to have ------------ - * Offcial test vectors for 3DES-EDE3 + * Official test vectors for 3DES-EDE3 * use DEL and ^H for erasing the previous character (util/ttyio.c). or better readline. * Print a warning if the directory mode is wrong. * replace the keyserver stuff either by a call to a specialized utility and SOCKSify this utility. * Do a real fix for bug #7 or document that it is a PGP 5 error. * preferences of hash algorithms are not yet used. * Replace the SIGUSR1 stuff by semaphores to avoid loss of a signal. or use POSIX.4 realtime signals. Overhaul the interface and the test program. Use it with the test suite? * add test cases for invalid data (scrambled armor or other random data) * add checking of armor trailers * Burn the buffers used by fopen(), or use read(2). Does this really make sense? And while we are at it: implement a secure deletion stuff? * the pubkey encrypt functions should do some sanity checks. * dynload: implement the hint stuff. * "gpg filename.tar.gz.asc" should work like --verify (-sab). * for messages created with "-t", it might make sense to append the verification status of the message to the output (i.e. write something to the --output file and not only to stderr. * configure option where to find zlib - * Check the beginning of file to detect already compresssed files (gzip, + * Check the beginning of file to detect already compressed files (gzip, bzip2, xdelta and some picture formats) * Display more validity information about the user IDs at certain places. We need a more general function to extract such kind of info from the trustdb. * Evaluate whether it make sense to replace the namehashs either by using the user ID directly or by using pointers into the trustdb. * --gen-prime may trigger a log_bug; should be a log_fatal. diff --git a/checks/ChangeLog b/checks/ChangeLog index d5520589e..8e043bf71 100644 --- a/checks/ChangeLog +++ b/checks/ChangeLog @@ -1,55 +1,60 @@ +Tue Aug 31 17:20:44 CEST 1999 Werner Koch + + + * defs.inc: set LC_ALL empty + Wed Aug 4 10:34:18 CEST 1999 Werner Koch * defs.inc (echo_n): New and used instead of /bin/echo "\c" Sun Apr 18 10:11:28 CEST 1999 Werner Koch * mkdemodirs: New * signdemokey: New. * Makefile.am (distclean-local): New. Wed Mar 17 13:09:03 CET 1999 Werner Koch * mds.test: replaced the "echo -n" Mon Mar 8 20:47:17 CET 1999 Werner Koch * pubdemo.asc, secdemo.asc: New. Fri Feb 19 15:49:15 CET 1999 Werner Koch * genkey1024.test: Be really quiet. 1999-01-01 Geoff Keating * Makefile.am (CLEANFILES): Also delete trustdb and any leftover lockfiles. Fri Nov 27 15:30:24 CET 1998 Werner Koch * 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. diff --git a/checks/defs.inc b/checks/defs.inc index 058a23370..d5fdc8af7 100755 --- a/checks/defs.inc +++ b/checks/defs.inc @@ -1,108 +1,109 @@ # 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= #-------------------------------- #------ utility functions ------- #-------------------------------- fatal () { echo "$pgmname: fatal:" $* >&2 exit 1; } error () { echo "$pgmname:" $* >&2 exit 1 } info () { echo "$pgmname:" $* >&2 } chdir () { cd $1 || fatal "cannot cd to $1" } 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" cat <./options no-greeting no-secmem-warning load-extension ../cipher/tiger batch EOF diff --git a/configure.in b/configure.in index eee8c76d6..e72e7be4d 100644 --- a/configure.in +++ b/configure.in @@ -1,711 +1,715 @@ dnl dnl Configure template for GNUPG dnl dnl (Process this file with autoconf to produce a configure script.) AC_REVISION($Revision$)dnl dnl Must reset CDPATH so that bash's cd does not print to stdout CDPATH= AC_PREREQ(2.13) AC_INIT(g10/g10.c) AC_CONFIG_AUX_DIR(scripts) AM_CONFIG_HEADER(config.h) VERSION=`cat $srcdir/VERSION` PACKAGE=gnupg ALL_LINGUAS="de es_ES fr it pl pt_BR ru" static_modules="sha1 md5 rmd160" AC_SUBST(VERSION) AC_SUBST(PACKAGE) AC_DEFINE_UNQUOTED(VERSION, "$VERSION") AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE") MODULES_IN_CIPHER=`awk '/# MODULES: / { for(i=3;i<=NF;i++) print $i}' \ $srcdir/cipher/Makefile.am` dnl dnl Check for random module options dnl dnl Fixme: get the list of available modules from MODULES_IN_CIPHER dnl and check against this list AC_MSG_CHECKING([which static random module to use]) AC_ARG_ENABLE(static-rnd, [ --enable-static-rnd=[egd|unix|linux|none] ], [use_static_rnd=$enableval], [use_static_rnd=default] ) if test "$use_static_rnd" = no; then use_static_rnd=default fi case "$use_static_rnd" in egd | linux | unix | none | default ) AC_MSG_RESULT($use_static_rnd) ;; * ) AC_MSG_RESULT(invalid argument) AC_MSG_ERROR(there is no random module rnd$use_static_rnd) ;; esac dnl dnl See whether the user wants to disable checking for /dev/random AC_MSG_CHECKING([whether use of /dev/random is requested]) AC_ARG_ENABLE(dev-random, [ --disable-dev-random disable the use of dev random], try_dev_random=$enableval, try_dev_random=yes) AC_MSG_RESULT($try_dev_random) dnl dnl Check other options dnl AC_MSG_CHECKING([whether use of extensions is requested]) AC_ARG_ENABLE(dynload, [ --disable-dynload disable use of extensions], try_dynload=$enableval, try_dynload=yes) AC_MSG_RESULT($try_dynload) AC_MSG_CHECKING([whether assembler modules are requested]) AC_ARG_ENABLE(asm, [ --disable-asm do not use assembler modules], try_asm_modules=$enableval, try_asm_modules=yes) AC_MSG_RESULT($try_asm_modules) AC_MSG_CHECKING([whether memory debugging is requested]) AC_ARG_ENABLE(m-debug, [ --enable-m-debug enable debugging of memory allocation], use_m_debug=$enableval, use_m_debug=no) AC_MSG_RESULT($use_m_debug) if test "$use_m_debug" = yes; then AC_DEFINE(M_DEBUG) use_m_guard=yes else AC_MSG_CHECKING([whether memory guard is requested]) AC_ARG_ENABLE(m-guard, [ --enable-m-guard enable memory guard facility], use_m_guard=$enableval, use_m_guard=no) AC_MSG_RESULT($use_m_guard) fi if test "$use_m_guard" = yes ; then AC_DEFINE(M_GUARD) fi AC_MSG_CHECKING([whether included zlib is requested]) AC_ARG_WITH(included-zlib, [ --with-included-zlib use the zlib code included here], [g10_force_zlib=yes], [g10_force_zlib=no] ) AC_MSG_RESULT($g10_force_zlib) dnl dnl Check wether we want to compile libgcrypt dnl AC_MSG_CHECKING([whether compilation of libgcrypt is requested]) AC_ARG_ENABLE(libgcrypt, [ --enable-libgcrypt compile the libgcrypt [default=no]], [compile_libgcrypt="$enableval"],[compile_libgcrypt=no]) AC_MSG_RESULT($compile_libgcrypt) if test x$compile_libgcrypt = xyes ; then if test -f $srcdir/gcrypt/gcrypt.h; then : else compile_libgcrypt=no AC_MSG_WARN([[ *** *** LIBGCRYPT is not yet ready for public testing. *** Maybe you have more luck with the next release of GnuPG *** Watch the gnupg-announce mailing list or the webpage. ***]]) fi fi AM_CONDITIONAL(COMPILE_LIBGCRYPT, test x$compile_libgcrypt = xyes) dnl dnl Check whether we want to use Linux capabilities dnl AC_MSG_CHECKING([whether use of capabilities is requested]) AC_ARG_WITH(capabilities, [ --with-capabilities use linux capabilities [default=no]], [use_capabilities="$withval"],[use_capabilities=no]) AC_MSG_RESULT($use_capabilities) AM_MAINTAINER_MODE dnl Checks for programs. AC_CANONICAL_SYSTEM AC_ARG_PROGRAM AC_PROG_MAKE_SET AM_SANITY_CHECK missing_dir=`cd $ac_aux_dir && pwd` AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) dnl AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) AC_PROG_CC AC_PROG_CPP AC_ISC_POSIX AC_PROG_INSTALL AC_PROG_AWK AC_CHECK_PROG(DOCBOOK_TO_MAN, docbook-to-man, yes, no) AM_CONDITIONAL(HAVE_DOCBOOK_TO_MAN, test "$ac_cv_prog_DOCBOOK_TO_MAN" = yes) dnl dnl Build shared libraries only when compilation of libgcrypt dnl has been requested dnl AM_DISABLE_SHARED enable_shared="$compile_libgcrypt" AM_PROG_LIBTOOL MPI_OPT_FLAGS="" if test "$GCC" = yes; then CFLAGS="$CFLAGS -Wall -Wcast-align -Wshadow -Wstrict-prototypes" fi try_gettext=yes try_gdbm=yes case "${target}" in - i386--mingw32) + *-*-mingw32) # special stuff for Windoze NT cross_compiling=yes - CC="i386--mingw32-gcc" - CPP="i386--mingw32-gcc -E" - RANLIB="i386--mingw32-ranlib" + CC="${target}-gcc" + CPP="${target}-gcc -E" + RANLIB="${target}-ranlib" ac_cv_have_dev_random=no AC_DEFINE(USE_ONLY_8DOT3) AC_DEFINE(HAVE_DRIVE_LETTERS) AC_DEFINE(HAVE_DOSISH_SYSTEM) try_gettext="no" try_gdbm="no" ;; - i386-emx-os2 | i[3456]86-pc-os2*emx ) + i?86-emx-os2 | i?86-*-os2*emx ) # OS/2 with the EMX environment ac_cv_have_dev_random=no AC_DEFINE(HAVE_DRIVE_LETTERS) AC_DEFINE(HAVE_DOSISH_SYSTEM) try_gettext="no" try_gdbm="no" ;; - i*86-*-msdosdjgpp*) + i?86-*-msdosdjgpp*) # DOS with the DJGPP environment ac_cv_have_dev_random=no AC_DEFINE(HAVE_DRIVE_LETTERS) AC_DEFINE(HAVE_DOSISH_SYSTEM) try_gettext="no" try_gdbm="no" ;; *-*-hpux*) if test -z "$GCC" ; then CFLAGS="$CFLAGS -Ae -D_HPUX_SOURCE" fi ;; *-dec-osf4*) if test -z "$GCC" ; then # Suppress all warnings # to get rid of the unsigned/signed char mismatch warnings. CFLAGS="$CFLAGS -w" fi ;; m68k-atari-mint) ;; *) ;; esac AC_SUBST(MPI_OPT_FLAGS) GNUPG_SYS_SYMBOL_UNDERSCORE GNUPG_CHECK_PIC GNUPG_CHECK_RDYNAMIC if test "$NO_PIC" = yes; then try_dynload=no fi case "${target}" in - i386--mingw32) + *-*-mingw32) PRINTABLE_OS_NAME="MingW32" ;; - i386-emx-os2 | i[3456]86-pc-os2*emx ) + i?86-emx-os2 | i?86-*-os2*emx ) PRINTABLE_OS_NAME="OS/2" ;; + i?86-*-msdosdjgpp*) + PRINTABLE_OS_NAME="MSDOS/DJGPP" + try_dynload=no + ;; *-linux*) PRINTABLE_OS_NAME="GNU/Linux" ;; - i*86-*-msdosdjgpp*) - PRINTABLE_OS_NAME="MSDOS/DJGPP" - try_dynload=no +dnl let that after linux to avoid gnu-linux problems + *-gnu*) + PRINTABLE_OS_NAME="GNU/Hurd" ;; *) PRINTABLE_OS_NAME=`uname -s || echo "Unknown"` ;; esac AC_DEFINE_UNQUOTED(PRINTABLE_OS_NAME, "$PRINTABLE_OS_NAME") dnl Fixme: Are these the best flags for OpenBSD???? dnl (I have removed the -lc from * ...CFLAGS for test purposes.) case "${target}" in *-openbsd*) NAME_OF_DEV_RANDOM="/dev/srandom" NAME_OF_DEV_URANDOM="/dev/urandom" DYNLINK_MOD_CFLAGS="-shared -rdynamic -fpic -Wl,-Bshareable -Wl,-x" ;; *) NAME_OF_DEV_RANDOM="/dev/random" NAME_OF_DEV_URANDOM="/dev/urandom" DYNLINK_MOD_CFLAGS="-shared $CFLAGS_PIC" ;; esac AC_DEFINE_UNQUOTED(NAME_OF_DEV_RANDOM, "$NAME_OF_DEV_RANDOM") AC_DEFINE_UNQUOTED(NAME_OF_DEV_URANDOM, "$NAME_OF_DEV_URANDOM") AC_SUBST(MPI_OPT_FLAGS) dnl Checks for libraries. if test "$try_gettext" = yes; then AM_GNU_GETTEXT else USE_NLS=no USE_INCLUDED_LIBINTL=no AC_SUBST(USE_NLS) AC_SUBST(USE_INCLUDED_LIBINTL) fi dnl dnl There are lot of misconfigured systems. We include dnl gdbm support only if the lib and the header is installed. dnl if test "$try_gdbm" = yes; then AC_CHECK_HEADERS(gdbm.h) if test "$ac_cv_header_gdbm_h" = yes ; then AC_CHECK_LIB(gdbm,gdbm_firstkey) fi fi dnl Solaris needs -lsocket and -lnsl. Unisys system includes dnl gethostbyname in libsocket but needs libnsl for socket. AC_CHECK_LIB(nsl, gethostbyname) AC_CHECK_LIB(socket, socket, ac_need_libsocket=1, ac_try_nsl=1) if test x$ac_need_libsocket = x1; then LIBS="$LIBS -lsocket" fi if test x$ac_try_nsl = x1; then AC_CHECK_LIB(nsl, gethostbyname, ac_need_libnsl=1) if test x$ac_need_libnsl = x1 then LIBS="$LIBS -lnsl" fi fi if test "$try_dynload" = yes ; then AC_CHECK_LIB(dl,dlopen) if test "$ac_cv_lib_dl_dlopen" = "yes"; then AC_DEFINE(USE_DYNAMIC_LINKING) AC_DEFINE(HAVE_DL_DLOPEN) DYNLINK_LDFLAGS="$CFLAGS_RDYNAMIC" use_gnupg_extensions=yes else AC_CHECK_LIB(c,dlopen) if test "$ac_cv_lib_c_dlopen" = "yes"; then AC_DEFINE(USE_DYNAMIC_LINKING) AC_DEFINE(HAVE_DL_DLOPEN) DYNLINK_LDFLAGS="$CFLAGS_RDYNAMIC" use_gnupg_extensions=yes else AC_CHECK_LIB(dld,shl_load) if test "$ac_cv_lib_dld_shl_load" = "yes"; then AC_DEFINE(USE_DYNAMIC_LINKING) AC_DEFINE(HAVE_DL_SHL_LOAD) DYNLINK_LDFLAGS="$CFLAGS_RDYNAMIC" use_gnupg_extensions=yes dnl ----------------- dnl DLD is not ready for use. So I better disable this test dnl dnl AC_CHECK_LIB(dld,dld_link) dnl if test "$ac_cv_lib_dld_dld_link" = "yes"; then dnl AC_DEFINE(USE_DYNAMIC_LINKING) dnl AC_DEFINE(HAVE_DLD_DLD_LINK) dnl DYNLINK_LDFLAGS="$CFLAGS_RDYNAMIC" dnl use_gnupg_extensions=yes dnl --------------- fi fi fi else AC_MSG_CHECKING(for dynamic loading) DYNLINK_LDFLAGS= DYNLINK_MOD_CFLAGS= use_gnupg_extensions=no AC_MSG_RESULT(has been disabled) fi AM_CONDITIONAL(ENABLE_GNUPG_EXTENSIONS, test "$use_gnupg_extensions" = yes ) AC_SUBST(DYNLINK_LDFLAGS) AC_SUBST(DYNLINK_MOD_CFLAGS) dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS(unistd.h langinfo.h) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_C_INLINE AC_TYPE_SIZE_T AC_TYPE_SIGNAL AC_DECL_SYS_SIGLIST GNUPG_CHECK_ENDIAN GNUPG_CHECK_TYPEDEF(byte, HAVE_BYTE_TYPEDEF) GNUPG_CHECK_TYPEDEF(ushort, HAVE_USHORT_TYPEDEF) GNUPG_CHECK_TYPEDEF(ulong, HAVE_ULONG_TYPEDEF) GNUPG_CHECK_TYPEDEF(u16, HAVE_U16_TYPEDEF) GNUPG_CHECK_TYPEDEF(u32, HAVE_U32_TYPEDEF) AC_CHECK_SIZEOF(unsigned short, 2) AC_CHECK_SIZEOF(unsigned int, 4) AC_CHECK_SIZEOF(unsigned long, 4) if test "$ac_cv_sizeof_unsigned_short" = "0" \ || test "$ac_cv_sizeof_unsigned_int" = "0" \ || test "$ac_cv_sizeof_unsigned_long" = "0"; then AC_MSG_WARN([Hmmm, something is wrong with the sizes - using defaults]); fi dnl Checks for library functions. AC_FUNC_VPRINTF AC_CHECK_FUNCS(strerror stpcpy strlwr stricmp tcgetattr rand strtoul mmap) AC_CHECK_FUNCS(memmove gettimeofday getrusage gethrtime setrlimit) AC_CHECK_FUNCS(memicmp atexit raise getpagesize strftime nl_langinfo) GNUPG_CHECK_MLOCK dnl dnl Check whether we can use Linux capabilities as requested dnl if test "$use_capabilities" = "yes" ; then use_capabilities=no AC_CHECK_HEADERS(sys/capability.h) if test "$ac_cv_header_sys_capability_h" = "yes" ; then AC_CHECK_LIB(cap, cap_init, ac_need_libcap=1) if test "$ac_cv_lib_cap_cap_init" = "yes"; then AC_DEFINE(USE_CAPABILITIES) use_capabilities=yes fi fi if test "$use_capabilities" = "no" ; then AC_MSG_WARN([[ *** *** The use of capabilities on this system is not possible. *** You need a recent Linux kernel and some patches: *** fcaps-2.2.9-990610.patch (kernel patch for 2.2.9) *** fcap-module-990613.tar.gz (kernel module) *** libcap-1.92.tar.gz (user mode library and utilities) *** And you have to configure the kernel with CONFIG_VFS_CAP_PLUGIN *** set (filesystems menu). Be warned: This code is *really* ALPHA. ***]]) fi fi GNUPG_CHECK_IPC if test "$ac_cv_header_sys_shm_h" = "yes"; then AC_DEFINE(USE_SHM_COPROCESSING) fi dnl dnl check whether we have a random device dnl if test "$try_dev_random" = yes ; then AC_CACHE_CHECK(for random device, ac_cv_have_dev_random, [if test -c "$NAME_OF_DEV_RANDOM" && test -c "$NAME_OF_DEV_URANDOM" ; then ac_cv_have_dev_random=yes; else ac_cv_have_dev_random=no; fi]) if test "$ac_cv_have_dev_random" = yes; then AC_DEFINE(HAVE_DEV_RANDOM) fi else AC_MSG_CHECKING(for random device) ac_cv_have_dev_random=no AC_MSG_RESULT(has been disabled) fi dnl dnl and whether this device supports ioctl dnl (Note, that we should do a real test here) dnl if test "$ac_cv_have_dev_random" = yes ; then AC_CHECK_HEADERS(linux/random.h) AC_CACHE_CHECK(for random device ioctl, ac_cv_have_dev_random_ioctl, [ if test "$ac_cv_header_linux_random_h" = yes ; then ac_cv_have_dev_random_ioctl=yes; else ac_cv_have_dev_random_ioctl=no; fi ]) if test "$ac_cv_have_dev_random_ioctl" = yes; then AC_DEFINE(HAVE_DEV_RANDOM_IOCTL) fi fi dnl dnl Figure out the default linkage mode for cipher modules dnl dnl (We always need a static rmd160) print_egd_notice=no static_modules="$static_modules rmd160" if test "$use_static_rnd" = default; then if test "$ac_cv_have_dev_random" = yes; then static_modules="$static_modules rndlinux" else case "${target}" in - i386--mingw32) + *-*-mingw32) static_modules="$static_modules rndw32" ;; - i386-emx-os2|i[3456]86-pc-os2*emx) + i?86-emx-os2|i?86-*-os2*emx) static_modules="$static_modules rndos2" ;; m68k-atari-mint) static_modules="$static_modules rndatari" ;; - i*86-*-msdosdjgpp*) + i?86-*-msdosdjgpp*) static_modules="$static_modules" ;; *) static_modules="$static_modules rndunix" print_egd_notice=yes ;; esac fi else if test "$use_static_rnd" = none; then : else static_modules="$static_modules rnd$use_static_rnd" if test "$use_static_rnd" = "unix"; then print_egd_notice=yes fi fi fi if test "$print_egd_notice" = "yes"; then AC_MSG_WARN([[ *** *** The performance of the UNIX random gatherer module is not very good *** and it does not keep the entropy pool over multiple invocations of *** GnuPG. The suggested way to overcome this problem is to use the *** *** Entropy Gathering Daemon (EGD) *** *** which provides a entropy source for the whole system. It is written *** in Perl and available at the GnuPG FTP servers. For more information *** consult the GnuPG webpages: *** -*** http://www.gnupg.org/donwload.html#egd +*** http://www.gnupg.org/download.html#egd *** *** You may want to run ./configure with --enable-static-rnd=none to be *** able to load the EGD client code dynamically; this way you can choose *** between RNDUNIX and RNDEGD without recompilation. ***]]) fi dnl dnl Parse the modules list and build the list dnl of static and dymically linked modules dnl STATIC_CIPHER_NAMES="" STATIC_CIPHER_OBJS="" DYNAMIC_CIPHER_MODS="" GNUPG_MSG_PRINT([dynamically linked cipher modules:]) for name in $MODULES_IN_CIPHER; do x="no" for i in $static_modules; do if test "$name" = "$i" ; then x="yes" fi done; if test $x = yes; then STATIC_CIPHER_NAMES="$STATIC_CIPHER_NAMES $name" STATIC_CIPHER_OBJS="$STATIC_CIPHER_OBJS $name.lo" else DYNAMIC_CIPHER_MODS="$DYNAMIC_CIPHER_MODS $name" GNUPG_MSG_PRINT([$name]) fi done AC_MSG_RESULT() AC_SUBST(STATIC_CIPHER_OBJS) AC_SUBST(STATIC_CIPHER_NAMES) AC_SUBST(DYNAMIC_CIPHER_MODS) dnl dnl And build the constructor file dnl test -d cipher || mkdir cipher cat <cipher/construct.c /* automatically generated by configure - do not edit */ G10EOF GNUPG_MSG_PRINT([statically linked cipher modules:]) for name in $STATIC_CIPHER_NAMES; do echo "void ${name}_constructor(void);" >>cipher/construct.c GNUPG_MSG_PRINT([$name]) done AC_MSG_RESULT() cat <>cipher/construct.c void cipher_modules_constructor(void) { static int done = 0; if( done ) return; done = 1; G10EOF for name in $STATIC_CIPHER_NAMES; do echo " ${name}_constructor();" >>cipher/construct.c done echo '}' >>cipher/construct.c dnl dnl Figure how to link the cipher modules dnl AC_SUBST(STATIC_CIPHER_OBJS) AC_SUBST(DYNAMIC_CIPHER_MODS) dnl setup assembler stuff AC_MSG_CHECKING(for mpi assembler functions) if test -f $srcdir/mpi/config.links ; then . $srcdir/mpi/config.links GNUPG_LINK_FILES($mpi_ln_src, $mpi_ln_dst) ac_cv_mpi_extra_asm_modules="$mpi_extra_modules" ac_cv_mpi_sflags="$mpi_sflags" ac_cv_mpi_config_done="yes" AC_MSG_RESULT(done) else AC_MSG_RESULT(failed) AC_MSG_ERROR([mpi/config.links missing!]) fi MPI_EXTRA_ASM_OBJS="" if test "$ac_cv_mpi_extra_asm_modules" != ""; then GNUPG_MSG_PRINT([mpi extra asm functions:]) for i in $ac_cv_mpi_extra_asm_modules; do GNUPG_MSG_PRINT([$i]) MPI_EXTRA_ASM_OBJS="$MPI_EXTRA_ASM_OBJS $i.lo" done AC_MSG_RESULT() fi AC_SUBST(MPI_EXTRA_ASM_OBJS) MPI_SFLAGS="$ac_cv_mpi_sflags" AC_SUBST(MPI_SFLAGS) dnl Do we have zlib? Must do it here because Solaris failed dnl when compiling a conftest (due to the "-lz" from LIBS). use_local_zlib=yes if test "$g10_force_zlib" = "yes"; then : else AC_CHECK_HEADERS(zlib.h) if test "$ac_cv_header_zlib_h" = yes ; then AC_CHECK_LIB(z,deflateInit2_,use_local_zlib=no,:) fi fi if test "$use_local_zlib" = yes ; then AM_CONDITIONAL(ENABLE_LOCAL_ZLIB, true) GNUPG_LINK_FILES(zlib/zlib.h, zlib.h ) GNUPG_LINK_FILES(zlib/zconf.h, zconf.h ) ZLIBS="../zlib/libzlib.a" else AM_CONDITIONAL(ENABLE_LOCAL_ZLIB, false) ZLIBS= LIBS="-lz $LIBS" fi AC_SUBST(ZLIBS) changequote(,)dnl tmp_pat='[a-zA-Z]' changequote([,])dnl if echo "$VERSION" | grep $tmp_pat >/dev/null ; then AC_DEFINE(IS_DEVELOPMENT_VERSION) fi GNUPG_DO_LINK_FILES AC_OUTPUT_COMMANDS([ cat >g10defs.tmp </dev/null; then echo "g10defs.h is unchanged" rm -f g10defs.tmp else rm -f g10defs.h mv g10defs.tmp g10defs.h echo "g10defs.h created" fi ],[ prefix=$prefix exec_prefix=$exec_prefix libdir=$libdir datadir=$datadir DATADIRNAME=$DATADIRNAME ]) AC_OUTPUT([ Makefile intl/Makefile po/Makefile.in util/Makefile mpi/Makefile cipher/Makefile g10/Makefile doc/Makefile tools/Makefile zlib/Makefile checks/Makefile gcrypt/Makefile ]) dnl *-*wedit:notab*-* Please keep this as the last line. diff --git a/doc/DETAILS b/doc/DETAILS index 67ca23c16..7c1e11edf 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -1,598 +1,598 @@ Format of "---with-colons" listings =================================== sec::1024:17:6C7EE1B8621CC013:1998-07-07:0:::Werner Koch : ssb::1536:20:5CE086B5B5A18FF4:1998-07-07:0::: 1. Field: Type of record pub = public key sub = subkey (secondary key) sec = secret key ssb = secret subkey (secondary key) uid = user id (only field 10 is used). fpr = fingerprint: (fingerprint is in field 10) pkd = public key data (special field format, see below) 2. Field: A letter describing the calculated trust. This is a single letter, but be prepared that additional information may follow in some future versions. (not used for secret keys) o = Unknown (this key is new to the system) d = The key has been disabled r = The key has been revoked e = The key has expired q = Undefined (no value assigned) n = Don't trust this key at all m = There is marginal trust in this key f = The key is full trusted. u = The key is ultimately trusted; this is only used for keys for which the secret key is also available. 3. Field: length of key in bits. 4. Field: Algorithm: 1 = RSA 16 = ElGamal (encrypt only) 17 = DSA (sometimes called DH, sign only) 20 = ElGamal (sign and encrypt) (for other id's see include/cipher.h) 5. Field: KeyID 6. Field: Creation Date (in UTC) 7. Field: Key expiration date or empty if none. 8. Field: Local ID: record number of the dir record in the trustdb. This value is only valid as long as the trustdb is not deleted. You can use "# as the user id when specifying a key. This is needed because keyids may not be unique - a program may use this number to access keys later. 9. Field: Ownertrust (primary public keys only) This is a single letter, but be prepared that additional information may follow in some future versions. 10. Field: User-ID. The value is quoted like a C string to avoid control characters (the colon is quoted "\x3a"). More fields may be added later. If field 1 has the tag "pkd", a listing looks like this: pkd:0:1024:B665B1435F4C2 .... FF26ABB: ! ! !-- the value - ! !------ for infomation number of bits in the value + ! !------ for information number of bits in the value !--------- index (eg. DSA goes from 0 to 3: p,q,g,y) Format of the "--status-fd" output ================================== Every line is prefixed with "[GNUPG:] ", followed by a keyword with the type of the status line and a some arguments depending on the type (maybe none); an application should always be prepared to see more arguments in future versions. GOODSIG The signature with the keyid is good. BADSIG The signature with the keyid has not been verified okay. ERRSIG \ It was not possible to check the signature. This may be caused by a missing public key or an unsupported algorithm. A RC of 4 indicates unknown algorithm, a 9 indicates a missing public key. The other fields give more information about this signature. sig_class is a 2 byte hex-value. VALIDSIG The signature with the keyid is good. This is the same as GOODSIG but has the fingerprint as the argument. Both status lines ere emitted for a good signature. sig-timestamp is the signature creation time in seconds after the epoch. SIG_ID This is emitted only for signatures of class 0 or 1 which have been verified okay. The string is a signature id and may be used in applications to detect replay attacks of signed messages. Note that only DLP algorithms give unique ids - others may yield duplicated ones when they have been created in the same second. ENC_TO The message is encrypted to this keyid. keytype is the numerical value of the public key algorithm, - kenlength is the length of the key or 0 if it is not known + keylength is the length of the key or 0 if it is not known (which is currently always the case). NODATA No data has been found. Codes for what are: 1 - No armored data. 2 - Expected a packet but did not found one. 3 - Invalid packet found, this may indicate a non OpenPGP message. You may see more than one of these status lines. TRUST_UNDEFINED TRUST_NEVER TRUST_MARGINAL TRUST_FULLY TRUST_ULTIMATE For good signatures one of these status lines are emitted to indicate how trustworthy the signature is. No arguments yet. SIGEXPIRED The signature key has expired. No arguments yet. KEYREVOKED The used key has been revoked by his owner. No arguments yet. BADARMOR The ASCII armor is corrupted. No arguments yet. RSA_OR_IDEA The RSA or IDEA algorithms has been used in the data. A program might want to fallback to another program to handle the data if GnuPG failed. SHM_INFO SHM_GET SHM_GET_BOOL SHM_GET_HIDDEN NEED_PASSPHRASE Issued whenever a passphrase is needed. keytype is the numerical value of the public key algorithm or 0 if this is not applicable, keylength is the length of the key or 0 if it is not known (this is currently always the case). NEED_PASSPHRASE_SYM Issued whenever a passphrase for symmetric encryption is needed. MISSING_PASSPHRASE No passphrase was supplied. An application which encounters this message may want to stop parsing immediately because the next message will probably be a BAD_PASSPHRASE. However, if the application - is a wrapper around the key edit menu functionalty it might not + is a wrapper around the key edit menu functionality it might not make sense to stop parsing but simply ignoring the following PAD_PASSPHRASE. BAD_PASSPHRASE The supplied passphrase was wrong or not given. In the latter case you may have seen a MISSING_PASSPHRASE. GOOD_PASSPHRASE The supplied passphrase was good and the secret key material is therefore usable. DECRYPTION_FAILED The symmetric decryption failed - one reason could be a wrong passphrase for a symmetrical encrypted message. DECRYPTION_OKAY The decryption process succeeded. This means, that either the correct secret key has been used or the correct passphrase for a conventional encrypted message was given. The program - itself may return an errorcode becuase it may not be possible to + itself may return an errorcode because it may not be possible to verify a signature for some reasons. NO_PUBKEY NO_SECKEY The key is not available IMPORTED The keyid and name of the signature just imported IMPORTED_RES Final statistics on import process (this is one long line) Key generation ============== Key generation shows progress by printing different characters to stderr: "." Last 10 Miller-Rabin tests failed "+" Miller-Rabin test succeeded "!" Reloading the pool with fresh prime numbers "^" Checking a new value for the generator "<" Size of one factor decreased ">" Size of one factor increased The prime number for ElGamal is generated this way: 1) Make a prime number q of 160, 200, 240 bits (depending on the keysize) 2) Select the length of the other prime factors to be at least the size of q and calculate the number of prime factors needed 3) Make a pool of prime numbers, each of the length determined in step 2 4) Get a new permutation out of the pool or continue with step 3 if we have tested all permutations. 5) Calculate a candidate prime p = 2 * q * p[1] * ... * p[n] + 1 6) Check that this prime has the correct length (this may change q if it seems not to be possible to make a prime of the desired length) 7) Check whether this is a prime using trial divisions and the Miller-Rabin test. 8) Continue with step 4 if we did not find a prime in step 7. 9) Find a generator for that prime. This algorithm is based on Lim and Lee's suggestion from the Crypto '97 proceedings p. 260. Layout of the TrustDB ===================== The TrustDB is built from fixed length records, where the first byte describes the record type. All numeric values are stored in network byte order. The length of each record is 40 bytes. The first record of the DB is always of type 1 and this is the only record of this type. Record type 0: -------------- Unused record, can be reused for any purpose. Record type 1: -------------- Version information for this TrustDB. This is always the first record of the DB and the only one with type 1. 1 byte value 1 3 bytes 'gpg' magic value 1 byte Version of the TrustDB (2) 1 byte marginals needed 1 byte completes needed 1 byte max_cert_depth The three items are used to check whether the cached validity value from the dir record can be used. 1 u32 locked flags 1 u32 timestamp of trustdb creation 1 u32 timestamp of last modification which may affect the validity of keys in the trustdb. This value is checked against the validity timestamp in the dir records. 1 u32 timestamp of last validation (Used to keep track of the time, when this TrustDB was checked against the pubring) 1 u32 record number of keyhashtable 1 u32 first free record 1 u32 record number of shadow directory hash table It does not make sense to combine this table with the key table because the keyid is not in every case a part of the fingerprint. 4 bytes reserved for version extension record Record type 2: (directory record) -------------- Informations about a public key certificate. These are static values which are never changed without user interaction. 1 byte value 2 1 byte reserved 1 u32 LID . (This is simply the record number of this record.) 1 u32 List of key-records (the first one is the primary key) 1 u32 List of uid-records 1 u32 cache record 1 byte ownertrust 1 byte dirflag 1 byte maximum validity of all the user ids 1 u32 time of last validity check. 1 u32 Must check when this time has been reached. (0 = no check required) Record type 3: (key record) -------------- Informations about a primary public key. (This is mainly used to lookup a trust record) 1 byte value 3 1 byte reserved 1 u32 LID 1 u32 next - next key record 7 bytes reserved 1 byte keyflags 1 byte pubkey algorithm 1 byte length of the fingerprint (in bytes) 20 bytes fingerprint of the public key (This is the value we use to identify a key) Record type 4: (uid record) -------------- Informations about a userid We do not store the userid but the hash value of the userid because that is sufficient. 1 byte value 4 1 byte reserved 1 u32 LID points to the directory record. 1 u32 next next userid 1 u32 pointer to preference record 1 u32 siglist list of valid signatures 1 byte uidflags 1 byte validity of the key calculated over this user id 20 bytes ripemd160 hash of the username. Record type 5: (pref record) -------------- Informations about preferences 1 byte value 5 1 byte reserved 1 u32 LID; points to the directory record (and not to the uid record!). (or 0 for standard preference record) 1 u32 next 30 byte preference data Record type 6 (sigrec) ------------- Used to keep track of key signatures. Self-signatures are not stored. If a public key is not in the DB, the signature points to a shadow dir record, which in turn has a list of records which might be interested in this key (and the signature record here is one). 1 byte value 6 1 byte reserved 1 u32 LID points back to the dir record 1 u32 next next sigrec of this uid or 0 to indicate the last sigrec. 6 times 1 u32 Local_id of signators dir or shadow dir record 1 byte Flag: Bit 0 = checked: Bit 1 is valid (we have a real directory record for this) 1 = valid is set (but my be revoked) Record type 8: (shadow directory record) -------------- This record is used to reserved a LID for a public key. We need this to create the sig records of other keys, even if we do not yet have the public key of the signature. This record (the record number to be more precise) will be reused as the dir record when we import the real public key. 1 byte value 8 1 byte reserved 1 u32 LID (This is simply the record number of this record.) 2 u32 keyid 1 byte pubkey algorithm 3 byte reserved 1 u32 hintlist A list of records which have references to this key. This is used for fast access to signature records which are not yet checked. Note, that this is only a hint and the actual records may not anymore hold signature records for that key but that the code cares about this. 18 byte reserved Record Type 10 (hash table) -------------- Due to the fact that we use fingerprints to lookup keys, we can implement quick access by some simple hash methods, and avoid the overhead of gdbm. A property of fingerprints is that they can be used directly as hash values. (They can be considered as strong random numbers.) What we use is a dynamic multilevel architecture, which combines hashtables, record lists, and linked lists. This record is a hashtable of 256 entries; a special property is that all these records are stored consecutively to make one big table. The hash value is simple the 1st, 2nd, ... byte of the fingerprint (depending on the indirection level). When used to hash shadow directory records, a different table is used and indexed by the keyid. 1 byte value 10 1 byte reserved n u32 recnum; n depends on the record length: n = (reclen-2)/4 which yields 9 for the current record length of 40 bytes. the total number of such record which makes up the table is: m = (256+n-1) / n which is 29 for a record length of 40. To look up a key we use the first byte of the fingerprint to get the recnum from this hashtable and look up the addressed record: - If this record is another hashtable, we use 2nd byte to index this hash table and so on. - if this record is a hashlist, we walk all entries until we found one a matching one. - if this record is a key record, we compare the fingerprint and to decide whether it is the requested key; Record type 11 (hash list) -------------- see hash table for an explanation. This is also used for other purposes. 1 byte value 11 1 byte reserved 1 u32 next next hash list record n times n = (reclen-5)/5 1 u32 recnum For the current record length of 40, n is 7 Record type 254 (free record) --------------- All these records form a linked list of unused records. 1 byte value 254 1 byte reserved (0) 1 u32 next_free Packet Headers =============== GNUPG uses PGP 2 packet headers and also understands OpenPGP packet header. There is one enhancement used with the old style packet headers: CTB bits 10, the "packet-length length bits", have values listed in the following table: 00 - 1-byte packet-length field 01 - 2-byte packet-length field 10 - 4-byte packet-length field 11 - no packet length supplied, unknown packet length As indicated in this table, depending on the packet-length length bits, the remaining 1, 2, 4, or 0 bytes of the packet structure field are a "packet-length field". The packet-length field is a whole number field. The value of the packet-length field is defined to be the value of the whole number field. A value of 11 is currently used in one place: on compressed data. That is, a compressed data block currently looks like , where , binary 10 1000 11, is an indefinite-length packet. The proper interpretation is "until the end of the enclosing structure", although it should never appear outermost (where the enclosing structure is a file). + This will be changed with another version, where the new meaning of + the value 11 (see below) will also take place. + + A value of 11 for other packets enables a special length encoding, + which is used in case, where the length of the following packet can + not be determined prior to writing the packet; especially this will + be used if large amounts of data are processed in filter mode. + + It works like this: After the CTB (with a length field of 11) a + marker field is used, which gives the length of the following datablock. + This is a simple 2 byte field (MSB first) containing the amount of data + following this field, not including this length field. After this datablock + another length field follows, which gives the size of the next datablock. + A value of 0 indicates the end of the packet. The maximum size of a + data block is limited to 65534, thereby reserving a value of 0xffff for + future extensions. These length markers must be inserted into the data + stream just before writing the data out. + + This 2 byte filed is large enough, because the application must buffer + this amount of data to prepend the length marker before writing it out. + Data block sizes larger than about 32k doesn't make any sense. Note + that this may also be used for compressed data streams, but we must use + another packet version to tell the application that it can not assume, + that this is the last packet. Usage of gdbm files for keyrings ================================ The key to store the keyblock is it's fingerprint, other records are used for secondary keys. fingerprints are always 20 bytes where 16 bit fingerprints are appended with zero. The first byte of the key gives some information on the type of the key. 1 = key is a 20 bit fingerprint (16 bytes fpr are padded with zeroes) data is the keyblock 2 = key is the complete 8 byte keyid data is a list of 20 byte fingerprints 3 = key is the short 4 byte keyid data is a list of 20 byte fingerprints 4 = key is the email address data is a list of 20 byte fingerprints Data is prepended with a type byte: 1 = keyblock 2 = list of 20 byte padded fingerprints 3 = list of list fingerprints (but how to we key them?) Other Notes =========== * For packet version 3 we calculate the keyids this way: RSA := low 64 bits of n ELGAMAL := build a v3 pubkey packet (with CTB 0x99) and calculate a rmd160 hash value from it. This is used as the fingerprint and the low 64 bits are the keyid. * Revocation certificates consist only of the signature packet; "import" knows how to handle this. The rationale behind it is to keep them small. Keyserver Message Format ========================= The keyserver may be contacted by a Unix Domain socket or via TCP. The format of a request is: ==== command-tag "Content-length:" digits CRLF ======= Where command-tag is NOOP GET PUT DELETE The format of a response is: ====== "GNUPG/1.0" status-code status-text "Content-length:" digits CRLF ============ followed by bytes of data Status codes are: o 1xx: Informational - Request received, continuing process o 2xx: Success - The action was successfully received, understood, and accepted o 4xx: Client Error - The request contains bad syntax or cannot be fulfilled o 5xx: Server Error - The server failed to fulfill an apparently valid request Documentation on HKP (the http keyserver protocol): A minimalistic HTTP server on port 11371 recognizes a GET for /pks/lookup. The standard http URL encoded query parameters are this (always key=value): - op=index (like pgp -kv), op=vindex (like pgp -kvv) and op=get (like pgp -kxa) - search=. This is a list of words that must occur in the key. The words are delimited with space, points, @ and so on. The delimiters are not searched for and the order of the words doesn't matter (but see next option). -- exact=on. This switch tells the hkp server to only report exact mathing +- exact=on. This switch tells the hkp server to only report exact matching keys back. In this case the order and the "delimiters" are important. - fingerprint=on. Also reports the fingerprints when used with 'index' or 'vindex' The keyserver also recognizes http-POSTs to /pks/add. Use this to upload keys. A better way to to this would be a request like: /pks/lookup/?op= -this can be implemented using Hurd's translater mechanism. -However, I think the whole key server stuff has to be re-thougth; +this can be implemented using Hurd's translator mechanism. +However, I think the whole key server stuff has to be re-thought; I have some ideas and probably create a white paper. diff --git a/doc/FAQ b/doc/FAQ index c879f93aa..aa8e0c4d7 100644 --- a/doc/FAQ +++ b/doc/FAQ @@ -1,344 +1,344 @@ GNU Privacy Guard -- Frequently Asked Questions ================================================= This FAQ is partly compiled from messages of the developers mailing list. Many thanks to Kirk Fort, Brian Warner, ... Q: How does this whole thing work? A: To generate a secret/public keypair, run gpg --gen-key and choose the default values. Data that is encrypted with a public key can only be decrypted by the matching secret key. The secret key is protected by a password, the public key is not. So to send your friend a message, you would encrypt your message with his public key, and he would only be able to decrypt it by having the secret key and putting in the password to use his secret key. GnuPG is also useful for signing things. Things that are encrypted with the secret key can be decrypted with the public key. To sign something, a hash is taken of the data, and then the hash is in some form encoded with the secret key. If someone has your public key, they can verify that it is from you and that it hasn't changed by checking the encoded form of the hash with the public key. A keyring is just a large file that stores keys. You have a public keyring where you store yours and your friend's public keys. You have a secret keyring that you keep your secret key on, and be very careful with this secret keyring: Never ever give anyone else access to it and use a *good* passphrase to protect the data in it. You can 'conventionally' encrypt something by using the option 'gpg -c'. It is encrypted using a passphrase, and does not use public and secret keys. If the person you send the data to knows that passphrase, they can decrypt it. This is usually most useful for encrypting things to yourself, although you can encrypt things to your own public key in the same way. It should be used for communication with partners you know and where it is easy to exchange the passphrases (e.g. with your boy friend or your wife). The advantage is that you can change the passphrase from time to time and decrease the risk, that many old messages may be decrypted by people who accidently got your passphrase. You can add and copy keys to and from your keyring with the 'gpg --import' and 'gpg --export' option. 'gpg --export-secret-keys' will export secret keys. This is normally not useful, but you can generate the key on one machine then move it to another machine. Keys can be signed under the 'gpg --edit-key' option. When you sign a key, you are saying that you are certain that the key belongs to the person it says it comes from. You should be very sure that is really that person: You should verify the key fingerprint gpg --fingerprint user-id over phone (if you really know the voice of the other person) or at a key signing party (which are often held at computer conferences) or at a meeting of your local GNU/Linux User Group. Hmm, what else. You may use the option "-o filename" to force output to this filename (use "-" to force output to stdout). "-r" just lets you specify the recipient (which public key you encrypt with) on the command line instead of typing it interactively. Oh yeah, this is important. By default all data is encrypted in some weird binary format. If you want to have things appear in ASCII text that is readable, just add the '-a' option. But the preferred method is to use a MIME aware mail reader (Mutt, Pine and many more). There is a small security glitch in the OpenPGP (and therefore GnuPG) system; to avoid this you should always sign and encrypt a message instead of only encrypting it. Q: What is the recommended key size? A: 1024 bit for DSA signatures; even for plain ElGamal signatures this is sufficient as the size of the hash is probably the weakest link if the keysize is larger than 1024 bits. Encryption keys may have greater sizes, but you should than check the fingerprint of this key: "gpg --fingerprint --fingerprint ". Q: Why are some signatures with an ELG-E key valid? A: These are ElGamal Key generated by GnuPG in v3 (rfc1991) packets. The OpenPGP draft later changed the algorithm identifier for ElGamal keys which are usable for signatures and encryption from 16 to 20. GnuPG now uses 20 when it generates new ElGamal keys but still accept 16 (which is according to OpenPGP "encryption only") if this key is in a v3 packet. GnuPG is the only program which had used these v3 ElGamal keys - so this assumption is quite safe. Q: Why is PGP 5.x not able to encrypt messages with some keys? A: PGP Inc refuses to accept ElGamal keys of type 20 even for encryption. They only support type 16 (which is identical at least for decryption). To be more inter-operable, GnuPG (starting with version 0.3.3) now also uses type 16 for the ElGamal subkey which is created if the default key algorithm is chosen. You may add an type 16 ElGamal key to your public key which is easy as your key signatures are still valid. Q: Why is PGP 5.x not able to verify my messages? A: PGP 5.x does not accept V4 signatures for data material but OpenPGP requires generation of V4 signatures for all kind of data. Use the option "--force-v3-sigs" to generate V3 signatures for data. Q: I can't delete an user id because it is already deleted on my public keyring? A: Because you can only select from the public key ring, there is no direct way to do this. However it is not very complicated to do it anyway. Create a new user id with exactly the same name and you will see that there are now two identical user ids on the secret ring. Now select this user id and delete it. Both user ids will be removed from the secret ring. Q: How can I encrypt a message so that pgp 2.x is able to decrypt it? A: You can't do that because pgp 2.x normally uses IDEA which is not supported by GnuPG because it is patented, but if you have a modified version of PGP you can try this: gpg --rfc1991 --cipher-algo 3des ... Please don't pipe the data to encrypt to gpg but give it as a filename; other wise, pgp 2 will not be able to handle it. Q: How can I conventional encrypt a message, so that PGP can decrypt it? A: You can't do this for PGP 2. For PGP 5 you should use this: gpg -c --cipher-algo 3des --compress-algo 1 myfile You may replace "3des" by "cast5". "blowfish" does not work with all versions of pgp5. You may also want to put compress-algo 1 into your ~/.gnupg/options file - this does not affect normal gnupg operation. Q: Why does it sometimes take so long to create keys? A: The problem here is that we need a lot of random bytes and for that we (on Linux the /dev/random device) must collect some random data. It is really not easy to fill the Linux internal entropy buffer; I talked to Ted Ts'o and he commented that the best way to fill the buffer is to play with your keyboard. Good security has it's price. What I do is to hit several times on the shift, control, alternate, and capslock keys, because these keys do not produce output to the screen. This way you get your keys really fast (it's the same thing pgp2 does). Another problem might be another program which eats up your random bytes (a program (look at your daemons) that reads from /dev/[u]random). Q: And it really takes long when I work on a remote system. Why? A: Don't do this at all! You should never create keys or even use GnuPG on a remote system because you normally have no physical control over your secret keyring (which is in most cases vulnerable to advanced dictionary attacks) - I strongly encourage everyone to only create keys on a local computer (a disconnected laptop is probably the best choice) and if you need it on your connected box (I know: We all do this) be sure to have a strong password for your account and for your secret key and that you can trust your system administrator. When I check GnuPG on a remote system via ssh (I have no Alpha here ;-) I have the same problem. It takes a *very* long time to create the keys, so I use a special option, --quick-random, to generate insecure keys which are only good for some tests. Q: How does the whole trust thing work? A: It works more or less like PGP. The difference is that the trust is computed at the time it is needed. This is one of the reasons for the trustdb which holds a list of valid key signatures. If you are not running in batch mode you will be asked to assign a trust parameter (ownertrust) to a key. You can see the validity (calculated trust value) using this command. gpg --list-keys --with-colons If the first field is "pub" or "uid", the second field shows you the trust: o = Unknown (this key is new to the system) e = The key has expired q = Undefined (no value assigned) n = Don't trust this key at all m = There is marginal trust in this key f = The key is full trusted. u = The key is ultimately trusted; this is only used for keys for which the secret key is also available. r = The key has been revoked d = The key has been disabled The value in the "pub" record is the best one of all "uid" records. You can get a list of the assigned trust values (how much you trust the owner to correctly sign another person's key) gpg --list-ownertrust The first field is the fingerprint of the primary key, the second field is the assigned value: - = No Ownertrust value yet assigned. n = Never trust this keyholder to correctly verify others signatures. m = Have marginal trust in the keyholders capability to sign other keys. f = Assume that the key holder really knows how to sign keys. u = No need to trust ourself because we have the secret key. Keep these values confidential because they express your opinions about others. PGP stores this information with the keyring thus it is not a good idea to publish a PGP keyring instead of exporting the keyring. gnupg stores the trust in the trust-DB so it is okay to give a gpg keyring away (but we have a --export command too). Q: What is the difference between options and commands? A: If you do a "gpg --help", you will get two separate lists. The first is a list of commands. The second is a list of options. Whenever you run GPG, you *must* pick exactly one command (**with one exception, see below). You *may* pick one or more options. The command should, just by convention, come at the end of the argument list, after all the options. If the command takes a file (all the basic ones do), the filename comes at the very end. So the basic way to run gpg is: gpg [--option something] [--option2] [--option3 something] --command file Some options take arguments, for example the --output option (which can be abbreviated -o) is an option that takes a filename. The option's argument must follow immediately after the option itself, otherwise gpg doesn't know which option the argument is supposed to go with. As an option, --output and its filename must come before the command. The --remote-user (-r) option takes a name or keyid to encrypt the message to, which must come right after the -r argument. The --encrypt (or -e) command comes after all the options followed by the file you wish to encrypt. So use gpg -r alice -o secret.txt -e test.txt If you write the options out in full, it is easier to read gpg --remote-user alice --output secret.txt --encrypt test.txt If you're saving it in a file called ".txt" then you'd probably expect to see ASCII-armored text in there, so you need to add the --armor (-a) option, which doesn't take any arguments. gpg --armor --remote-user alice --output secret.txt --encrypt test.txt If you imagine square brackets around the optional parts, it becomes a bit clearer: gpg [--armor] [--remote-user alice] [--output secret.txt] --encrypt test.txt The optional parts can be rearranged any way you want. gpg --output secret.txt --remote-user alice --armor --encrypt test.txt If your filename begins with a hyphen (e.g. "-a.txt"), gnupg assumes this is an option and may complain. To avoid this you have either to use "./-a.txt" or stop the option and command processing with two hyphens: "-- -a.txt". ** the exception: signing and encrypting at the same time. Use gpg [--options] --sign --encrypt foo.txt Q: What kind of output is this: "key C26EE891.298, uid 09FB: ...."? A: This is the internal representation of an user id in the trustdb. "C26EE891" is the keyid, "298" is the local id (a record number in the trustdb) and "09FB" is the last two bytes of a ripe-md-160 hash of the user id for this key. Q: What is trust, validity and ownertrust? A: "ownertrust" is used instead of "trust" to make clear that this is the value you have assigned to a key to express how much you trust the owner of this key to correctly sign (and so introduce) other keys. "validity", or calculated trust, is a value which says how much GnuPG thinks a key is valid (that it really belongs to the one who claims to be the owner of the key). For more see the chapter "The Web of Trust" in the Manual [gpg: Oops: Internal error: manual not found - sorry] Q: How do I interpret some of the informational outputs? A: While checking the validity of a key, GnuPG sometimes prints some information which is prefixed with information about the checked item. "key 12345678.3456" This is about the key with key ID 12345678 and the internal number 3456, which is the record number of the so called directory record in the trustdb. "uid 12345678.3456/ACDE" This is about the user ID for the same key. To identify the user ID the last two bytes of a ripe-md-160 over the user ID ring is printed. "sig 12345678.3456/ACDE/9A8B7C6D" This is about the signature with key ID 9A8B7C6D for the above key and user ID, if it is a signature which is direct on a key, the user ID part is empty (..//..). Q: How do I sign a patch file? A: Use "gpg --clearsign --not-dash-escaped ...". The problem with --clearsign is that all lines starting with a dash are quoted with "- "; obviously diff produces many of lines starting with a dash and these are then quoted and that is not good for patch ;-). To use a patch file without removing the cleartext signature, the special option --not-dash-escaped may be used to suppress generation of these escape sequences. You should not mail such a patch because spaces and line endings are also subject to the signature and a mailer may not preserve these. If you want to mail a file you can simply sign it using your MUA. Q: Where is the "encrypt-to-self" option? A: Use "--encrypt-to your_keyid". You can use more than one of these options. To temporary override the use of this additional keys, you can use the option "--no-encrypt-to". Q: How can I get rid of the Version and Comment headers in armored messages? A: Use "--no-version --comment ''". Note that the left over blank line is required by the protocol. Q: What does the "You are using the xxxx character set." mean? A: This note is printed when UTF8 mapping has to be done. Make sure that the displayed charset is the one you have activated on your system "iso-8859-1" is the most used one, so this is the default. You can change the charset with the option "--charset". It is important that - you active characterset matches the one displayed - if not, restrict + you active character set matches the one displayed - if not, restrict yourself to plain 7 bit ASCII and no mapping has to be done. Q: How do I transfer owner trust values from PGP to GnuPG? A: There is a script in the tools directory to help you: After you have imported the PGP keyring you can give this command: $ lspgpot pgpkeyring | gpg --import-ownertrust diff --git a/doc/HACKING b/doc/HACKING index bc06a7064..6f4c9ffd8 100644 --- a/doc/HACKING +++ b/doc/HACKING @@ -1,232 +1,232 @@ A Hacker's Guide to GNUPG ================================ (Some notes on GNUPG internals.) ===> Under construction <======= CVS Access ========== Anonymous read-only CVS access is available: cvs -z6 -d :pserver:anonymous@ftp.guug.de:/home/koch/cvs login use the password "anonymous". To check out the the complete archive use: cvs -z6 -d :pserver:anonymous@ftp.guug.de:/home/koch/cvs checkout gnupg This service is provided to help you in hunting bugs and not to deliver stable snapshots; it may happen that it even does not compile, so please don't complain. CVS may put a high load on a server, so please don't poll poll for new updates but wait for an announcement; to receive this you may want to subscribe to: gnupg-commit-watchers@gnupg.org by sending a mail with subject "subscribe" to gnupg-commit-watchers-request@gnupg.org You must run scripts/autogen.sh before doing the ./configure, as this creates some needed while which are not in the CVS. autogen.sh should checks that you have all required tools installed. RSYNC access ============ The FTP archive is also available by anonymous rsync. A daily snapshot of the CVS head revision is also available. See rsync(1) and try "rsync ftp.gnupg.org::" to see available resources. Special Tools ============= -Documention is based on the docbook DTD. Actually we have only the +Documentation is based on the docbook DTD. Actually we have only the man page for now. To build a man page you need the docbook-to-man tool and all the other thinks needed for SGML processing. Debian comes with the docbook tools and you only need this docbook-to-man script which is comes with gtk-doc or download it from ftp.openit.de:/pub/devel/sgml. If you don't have it everything should still work fine but you will have only a dummy man page. RFCs ==== 1423 Privacy Enhancement for Internet Electronic Mail: Part III: Algorithms, Modes, and Identifiers. 1489 Registration of a Cyrillic Character Set. 1750 Randomness Recommendations for Security. 1991 PGP Message Exchange Formats. 2015 MIME Security with Pretty Good Privacy (PGP). 2144 The CAST-128 Encryption Algorithm. 2279 UTF-8, a transformation format of ISO 10646. 2440 OpenPGP. Debug Flags ----------- Use the option "--debug n" to output debug information. This option can be used multiple times, all values are ORed; n maybe prefixed with 0x to use hex-values. value used for ----- ---------------------------------------------- 1 packet reading/writing 2 MPI details 4 ciphers and primes (may reveal sensitive data) 8 iobuf filter functions 16 iobuf stuff 32 memory allocation stuff 64 caching 128 show memory statistics at exit 256 trust verification stuff Directory Layout ---------------- ./ Readme, configure ./scripts Scripts needed by configure and others ./doc Documentation ./util General purpose utility function ./mpi Multi precision integer library ./cipher Cryptographic functions ./g10 GnuPG application ./tools Some helper and demo programs ./keybox The keybox library (under construction) ./gcrypt Stuff needed to build libgcrypt (under construction) Memory allocation ----------------- Use only the functions: m_alloc() m_alloc_clear() m_strdup() m_free() If you want to store a passphrase or some other sensitive data you may want to use m_alloc_secure() instead of m_alloc(), as this puts the data into a memory region which is protected from swapping (on some platforms). m_free() works for both. This functions will not return if there is not enough memory available. Logging ------- Option parsing --------------- GNUPG does not use getopt or GNU getopt but functions of it's own. See util/argparse.c for details. The advantage of these functions is that it is more easy to display and maintain the help texts for the options. The same option table is also used to parse resource files. What is an IOBUF ---------------- This is the data structure used for most I/O of gnupg. It is similar to System V Streams but much simpler. Because OpenPGP messages are nested in different ways; the use of such a system has big advantages. Here is an example, how it works: If the parser sees a packet header with a partial length, it pushes the block_filter onto the IOBUF to handle these partial length packets: from now on you don't have to worry about this. When it sees a compressed packet it pushes the uncompress filter and the next read byte is one which has already been uncompressed by this filter. Same goes for enciphered packet, plaintext packets and so on. The file g10/encode.c might be a good staring point to see how it is used - actually this is the other way: constructing messages using pushed filters but it may be easier to understand. How to use the message digest functions --------------------------------------- cipher/md.c implements an interface to hash (message digest functions). a) If you have a common part of data and some variable parts and you need to hash of the concatenated parts, you can use this: md = md_open(...) md_write( md, common_part ) md1 = md_copy( md ) md_write(md1, part1) md_final(md1); digest1 = md_read(md1) md2 = md_copy( md ) md_write(md2, part2) md_final(md2); digest2 = md_read(md2) An example are key signatures; the key packet is the common part and the user-id packets are the variable parts. b) If you need a running digest you should use this: md = md_open(...) md_write( md, part1 ) digest_of_part1 = md_digest( md ); md_write( md, part2 ) digest_of_part1_cat_part2 = md_digest( md ); .... Both methods may be combined. [Please see the source for the real syntax] How to use the cipher functions ------------------------------- cipher/cipher.c implements the interface to symmetric encryption functions. As usual you have a function to open a cipher (which returns a handle to be used with all other functions), some functions to set the key and other stuff and -a encrypt and decrypt function which does the real work. YOu probably know +a encrypt and decrypt function which does the real work. You probably know how to work with files - so it should really be easy to work with these functions. Here is an example: CIPHER_HANDLE hd; hd = cipher_open( CIPHER_ALGO_TWOFISH, CIPHER_MODE_CFB, 0 ); if( !hd ) - oops( use other funtion to check for the real error ); + oops( use other function to check for the real error ); rc = cipher_setkey( hd, key256bit, 32 ) ) if( rc ) oops( weak key or something like this ); cipher_setiv( hd, some_IV_or_NULL_for_all_zeroes ); cipher_encrypt( hd, plain, cipher, size ); cipher_close( hd ); How to use the public key functions ----------------------------------- cipher/pubkey.c implements the interface to asymmetric encryption and signature functions. This is basically the same as with the symmetric counterparts, but due to their nature it is a little bit more complicated. [Give an example] diff --git a/doc/OpenPGP b/doc/OpenPGP index a32da4723..148032ad9 100644 --- a/doc/OpenPGP +++ b/doc/OpenPGP @@ -1,103 +1,103 @@ GnuPG and OpenPGP ================= See RFC2440 for a description of OpenPGP. I have an annotated version of this RFC online: http://www.gnupg.org/rfc2440.html Compatibility Notes =================== GnuPG (>0.4.5) is in compliance with RFC2440 despite these exceptions: * (9.1) states that RSA SHOULD be implemented. This is not done (except with an extension, usable outside the U.S.) due to patent problems. * (9.2) states that IDEA SHOULD be implemented. This is not done due to patent problems. All MAY features are implemented with this exception: * multi-part armored messages are not supported. MIME should be used instead. Most of the OPTIONAL stuff is implemented. There are a couple of options which can be used to override some RFC requirements. This is always mentioned with the description of that options. A special format of partial packet length exists for v3 packets which can be considered to be in compliance with RFC1991; this format is only created if a special option is active. Some Notes on OpenPGP / PGP Compatibility: ========================================== * PGP 5.x does not accept V4 signatures for anything other than key material. The GnuPG option --force-v3-sigs mimics this - behaviour. + behavior. * PGP 5.x does not recognize the "five-octet" lengths in new-format headers or in signature subpacket lengths. * PGP 5.0 rejects an encrypted session key if the keylength differs from the S2K symmetric algorithm. This is a bug in its validation function. * PGP 5.0 does not handle multiple one-pass signature headers and trailers. Signing one will compress the one-pass signed literal and prefix a V3 signature instead of doing a nested one-pass signature. * When exporting a private key, PGP 2.x generates the header "BEGIN PGP SECRET KEY BLOCK" instead of "BEGIN PGP PRIVATE KEY BLOCK". All previous versions ignore the implied data type, and look directly at the packet data type. * In a clear-signed signature, PGP 5.0 will figure out the correct hash algorithm if there is no "Hash:" header, but it will reject a mismatch between the header and the actual algorithm used. The "standard" (i.e. Zimmermann/Finney/et al.) version of PGP 2.x rejects the "Hash:" header and assumes MD5. There are a number of enhanced variants of PGP 2.6.x that have been modified for SHA-1 signatures. * PGP 5.0 can read an RSA key in V4 format, but can only recognize it with a V3 keyid, and can properly use only a V3 format RSA key. * Neither PGP 5.x nor PGP 6.0 recognize ElGamal Encrypt and Sign keys. They only handle ElGamal Encrypt-only keys. Parts of this document are taken from: ====================================== OpenPGP Message Format draft-ietf-openpgp-formats-07.txt Copyright 1998 by The Internet Society. All Rights Reserved. This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the Internet Society or other Internet organizations, except as needed for the purpose of developing Internet standards in which case the procedures for copyrights defined in the Internet Standards process must be followed, or as required to translate it into languages other than English. The limited permissions granted above are perpetual and will not be revoked by the Internet Society or its successors or assigns. diff --git a/doc/gpg.sgml b/doc/gpg.sgml index b4f0873cb..a5595400f 100644 --- a/doc/gpg.sgml +++ b/doc/gpg.sgml @@ -1,1371 +1,1378 @@ directory"> file"> &ParmFile;"> files"> &ParmFiles;"> names"> &ParmNames;"> name"> &ParmName;"> key IDs"> n"> flags"> string"> value"> name=value"> ]> gpg 1 GNU Tools encryption and signing tool gpg --homedir --options command DESCRIPTION COMMANDS -s, --sign Make a signature. This command may be combined with --encrypt. --clearsign Make a clear text signature. -b, --detach-sign Make a detached signature. -e, --encrypt Encrypt data. This option may be combined with --sign. -c, --symmetric Encrypt with symmetric cipher only This command asks for a passphrase. --store Store only (make a simple RFC1991 packet). --decrypt &OptParmFile; Decrypt &ParmFile; (or stdin if no file is specified) and write it to stdout (or the file specified with --output). If the decrypted file is signed, the signature is also verified. This command differs from the default operation, as it never writes to the filename which is included in the file and it rejects files which don't begin with an encrypted message. --verify Assume that --list-keys &OptParmNames; --list-public-keys &OptParmNames; List all keys from the public keyrings, or just the ones given on the command line. --list-secret-keys &OptParmNames; List all keys from the secret keyrings, or just the ones given on the command line. --list-sigs &OptParmNames; Same as --list-keys, but the signatures are listed too. --check-sigs &OptParmNames; Same as --list-sigs, but the signatures are verified. --fingerprint &OptParmNames; List all keys with their fingerprints. This is the same output as --list-keys but with the additional output of a line with the fingerprint. May also be combined with --list-sigs or --check-sigs. If this command is given twice, the fingerprints of all secondary keys are listed too. --list-packets List only the sequence of packets. This is mainly useful for debugging. --gen-key Generate a new key pair. This command can only be used interactive. --edit-key &ParmName; Present a menu which enables you to do all key related tasks: sign Make a signature on key of user &ParmName; If the key is not yet signed by the default user (or the users given with -u), the program displays the information of the key again, together with its fingerprint and asks whether it should be signed. This question is repeated for all users specified with -u. lsign Same as --sign but the signature is marked as non-exportbale and will therefore never be used by others. This may be used to make keys valid only in the local environment. revsig Revoke a signature. GnuPG asks for every every signature which has been done by one of the secret keys, whether a revocation certificate should be generated. trust Change the owner trust value. This updates the trust-db immediately and no save is required. disable enable Disable or enable an entire key. A disabled key can normally not be used for encryption. adduid Create an alternate user id. deluid Delete an user id. addkey Add a subkey to this key. delkey Remove a subkey. revkey Revoke a subkey. expire Change the key expiration time. If a key is selected, the time of this key will be changed. With no selection the key expiration of the primary key is changed. passwd Change the passphrase of the secret key. uid &ParmN; Toggle selection of user id with index &ParmN;. Use 0 to deselect all. key &ParmN; Toggle selection of subkey with index &ParmN;. Use 0 to deselect all. check Check all selected user ids. pref List preferences. toggle Toggle between public and secret key listing. save Save all changes to the key rings and quit. quit Quit the program without updating the key rings. The listing shows you the key with its secondary keys and all user ids. Selected keys or user ids are indicated by an asterisk. The trust value is displayed with the primary key: the first is the assigned owner trust and the second is the calculated trust value. Letters are used for the values: -No ownertrust assigned / not yet calculated. eTrust calculation has failed. qNot enough information for calculation. nNever trust this key. mMarginally trusted. fFully trusted. uUltimately trusted. --sign-key &ParmName; Sign a public key with you secret key. This is a shortcut version of the subcommand "sign" from --edit. --lsign-key &ParmName; Sign a public key with you secret key but mark it as non-exportable. This is a shortcut version of the subcommand "lsign" from --edit. --delete-key &ParmName; Remove key from the public keyring --delete-secret-key &ParmName; Remove key from the secret and public keyring --gen-revoke Generate a revocation certificate for the complete key. To revoke a subkey or a signature, use the --edit command. --export &OptParmNames; Either export all keys from all keyrings (default keyrings and those registered via option --keyring), or if at least one name is given, those of the given name. The new keyring is written to stdout or to the file given with option "output". Use together with --armor to mail those keys. --send-keys &OptParmNames; Same as --export but sends the keys to a keyserver. Option --keyserver must be used to give the name of this keyserver. Don't send your complete keyring to a keyserver - select only those keys which are new or changed by you. --export-all &OptParmNames; Same as --export, but does also export keys which are not compatible to OpenPGP. --export-secret-keys &OptParmNames; Same as --export, but does export the secret keys. This is normally not very useful and a security risk. --import &OptParmFiles; --fast-import &OptParmFiles; Import/merge keys. This adds the given keys to the keyring. The fast version does not build the trustdb; this can be done at any time with the command --update-trustdb. --recv-keys &ParmKeyIDs; Import the keys with the given key IDs from a HKP keyserver. Option --keyserver must be used to give the name of this keyserver. --export-ownertrust List the assigned ownertrust values in ASCII format for backup purposes --import-ownertrust &OptParmFiles; Update the trustdb with the ownertrust values stored in &ParmFiles; (or stdin if not given); existing values will be overwritten. --print-md algo &OptParmFiles; -Print message digest og algorithm ALGO for all given files of stdin. +Print message digest of algorithm ALGO for all given files of stdin. If "*" is used for the algorithm, digests for all available algorithms are printed. --gen-random 0|1|2 count Emit COUNT random bytes of the given quality level. If count is not given -or zero, an endless sequenece of random bytes will be emitted. -PLEASE, don't use this command unless you know waht you are doing, it may +or zero, an endless sequence of random bytes will be emitted. +PLEASE, don't use this command unless you know what you are doing, it may remove precious entropy from the system! --gen-prime mode bits qbits Use the source, Luke :-). The output format is still subject to change. --version Print version information along with a list of supported algorithms. --warranty Print warranty information. -h, --help Print usage information. This is a really long list even it does list not all options. OPTIONS Long options can be put in an options file (default "~/.gnupg/options"). Do not write the 2 dashes, but simply the name of the option and any required arguments. Lines with a hash as the first non-white-space character are ignored. Commands may be put in this file too, but that does not make sense. -a, --armor Create ASCII armored output. -o, --output &ParmFile; Write output to &ParmFile;. -u, --local-user &ParmName; Use &ParmName as the user ID to sign. This option is silently ignored for the list commands, so that it can be used in an options file. --default-key &ParmName; Use &ParmName; as default user ID for signatures. If this is not used the default user ID is the first user ID found in the secret keyring. -r, --recipient &ParmName; Encrypt for user id &ParmName;. If this option is not specified, GnuPG asks for the user-id unless --default-recipient is given --default-recipient &ParmName; Use &ParmName; as default recipient if option --recipient is not used and don't ask if this is a valid one. &ParmName; must be a non empty. --default-recipient-self Use the default key as default recipient if option --recipient is not used and don't ask if this is a valid one. The default key is the first one from the secret keyring or the one set with --default-key. --no-default-recipient Reset --default-recipient and --default-recipient-self. --encrypt-to &ParmName; Same as --recipient but this one is intended for in the options file and may be used together with an own user-id as an "encrypt-to-self". These keys are only used when there are other recipients given either by use of --recipient or by the asked user id. No trust checking is performed for these user ids and even disabled keys can be used. --no-encrypt-to Disable the use of all --encrypt-to keys. -v, --verbose Give more information during processing. If used twice, the input data is listed in detail. -q, --quiet Try to be as quiet as possible. -z &ParmN; Set compression level to &ParmN;. A value of 0 for &ParmN; disables compression. Default is to use the default compression level of zlib (normally 6). -t, --textmode Use canonical text mode. If -t (but not --textmode) is used together with armoring and signing, this enables clearsigned messages. This kludge is needed for PGP compatibility; normally you would use --sign or --clearsign to selected the type of the signature. -n, --dry-run Don't make any changes (this is not completely implemented). -i, --interactive Prompt before overwriting any files. --batch Use batch mode. Never ask, do not allow interactive commands. --no-batch Disable batch mode. This may be of use if --batch is enabled from an options file. --yes Assume "yes" on most questions. --no Assume "no" on most questions. --always-trust Skip key validation and assume that used keys are always fully trusted. You won't use this unless you have installed some external validation scheme. --keyserver &ParmName; Use &ParmName to lookup keys which are not yet in your keyring. This is only done while verifying messages with signatures. The option is also required for the command --send-keys to specify the keyserver to where the keys should be send. All keyservers synchronize with each other - so there is no need to send keys to more than one server. Using the command "host -l pgp.net | grep wwwkeys" gives you a list of keyservers. Because there is load balancing using round-robin DNS you may notice that you get different key servers. --keyring &ParmFile; Add &ParmFile to the list of keyrings. If &ParmFile begins with a tilde and a slash, these are replaced by the HOME directory. If the filename does not contain a slash, it is assumed to be in the home-directory ("~/.gnupg" if --homedir is not used). The filename may be prefixed with a scheme: "gnupg-ring:" is the default one. "gnupg-gdbm:" may be used for a GDBM ring. It might make sense to use it together with --no-default-keyring. --secret-keyring &ParmFile; Same as --keyring but for the secret keyrings. --homedir &ParmDir; Set the name of the home directory to &ParmDir; If this option is not used it defaults to "~/.gnupg". It does not make sense to use this in a options file. This also overrides the environment variable "GNUPGHOME". --charset &ParmName; Set the name of the native character set. This is used to convert some strings to proper UTF-8 encoding. Valid values for &ParmName; are: iso-8859-1This is the default Latin 1 set. iso-8859-2The Latin 2 set. koi8-rThe usual Russian set (rfc1489). --utf8-strings --no-utf8-strings Assume that the arguments are already given as UTF8 strings. The default (--no-utf8-strings) is to assume that arguments are encoded in the character set as specified by --charset. These options effects all following arguments. Both options may used multiple times. --options &ParmFile; Read options from &ParmFile; and do not try to read them from the default options file in the homedir (see --homedir). This option is ignored if used in an options file. --no-options Shortcut for "--options /dev/null". This option is detected before an attempt to open an option file. --load-extension &ParmName; Load an extension module. If &ParmName; does not contain a slash it is searched in "/usr/local/lib/gnupg" See the manual for more information about extensions. --debug &ParmFlags; Set debugging flags. All flags are or-ed and &ParmFlags; may be given in C syntax (e.g. 0x0042). --debug-all Set all useful debugging flags. --status-fd &ParmN; Write special status strings to the file descriptor &ParmN;. See the file DETAILS in the documentation for a listing of them. --logger-fd &ParmN; Write log output to file descriptor &ParmN; and not to stderr. --no-comment Do not write comment packets. This option affects only the generation of secret keys. Output of option packets is disabled since version 0.4.2. --comment &ParmString; Use &ParmString; as comment string in clear text signatures. --default-comment Force to write the standard comment string in clear text signatures. Use this to overwrite a --comment from a config file. --no-version Omit the version string in clear text signatures. --emit-version Force to write the version string in clear text signatures. Use this to overwrite a previous --no-version from a config file. -N, --notation-data &ParmNameValue; Put the name value pair into the signature as notation data. &ParmName; must consists only of alphanumeric characters, digits or the underscore; the first character must not be a digit. &ParmValue; may be any printable string; it will encoded in UTF8, so sou should have check that your --charset is set right. If you prefix &ParmName; with an exclamation mark, the notation data will be flagged as critical (rfc2440:5.2.3.15). --set-policy-url &ParmString; Use &ParmString; as Policy URL for signatures (rfc2440:5.2.3.19). If you prefix it with an exclamation mark, the policy URL packet will be flagged as critical. --set-filename &ParmString; Use &ParmString; as the name of file which is stored in messages. + +--use-embedded-filename + +Try to create a file with a name as embedded in the data. +This can be a dangerous option as it allows to overwrite files. + + --completes-needed &ParmN; Number of completely trusted users to introduce a new key signer (defaults to 1). --marginals-needed &ParmN; Number of marginally trusted users to introduce a new key signer (defaults to 3) --max-cert-depth &ParmN; Maximum depth of a certification chain (default is 5). --cipher-algo &ParmName; Use &ParmName; as cipher algorithm. Running the program with the command --version yields a list of supported algorithms. If this is not used the cipher algorithm is selected from the preferences stored with the key. --digest-algo &ParmName; Use &ParmName; as message digest algorithm. Running the program with the command --version yields a list of supported algorithms. Please note that using this option may violate the OpenPGP requirement, that a 160 bit hash is to be used for DSA. --s2k-cipher-algo &ParmName; Use &ParmName; as the cipher algorithm used to protect secret keys. The default cipher is BLOWFISH. This cipher is also used for conventional encryption if --cipher-algo is not given. --s2k-digest-algo &ParmName; Use &ParmName; as the digest algorithm used to mangle the passphrases. The default algorithm is RIPE-MD-160. This digest algorithm is also used for conventional encryption if --digest-algo is not given. --s2k-mode &ParmN; Selects how passphrases are mangled. If &ParmN; is 0 a plain passphrase (which is not recommended) will be used, a 1 (default) adds a salt to the passphrase and a 3 iterates the whole process a couple of times. Unless --rfc1991 is used, this mode is also used for conventional encryption. --compress-algo &ParmN; Use compress algorithm &ParmN;. Default is 2 which is RFC1950 compression. You may use 1 to use the old zlib version which is used by PGP. The default algorithm may give better results because the window size is not limited to 8K. If this is not used the OpenPGP behavior is used, i.e. the compression algorithm is selected from the preferences; note, that this can't be done if you do not encrypt the data. --disable-cipher-algo &ParmName; Never allow the use of &ParmName; as cipher algorithm. The given name will not be checked so that a later loaded algorithm will still get disabled. --disable-pubkey-algo &ParmName; Never allow the use of &ParmName; as public key algorithm. The given name will not be checked so that a later loaded algorithm will still get disabled. --throw-keyid Do not put the keyid into encrypted packets. This option hides the receiver of the message and is a countermeasure against traffic analysis. It may slow down the decryption process because all available secret keys are tried. --not-dash-escaped This option changes the behavior of cleartext signatures so that they can be used for patch files. You should not send such an armored file via email because all spaces and line endings are hashed too. You can not use this option for data which has 5 dashes at the beginning of a line, patch files don't have this. A special armor header line tells GnuPG about this cleartext signature option. --escape-from-lines Because some mailers change lines starting with "From " to "<From " it is good to handle such lines in a special way when creating cleartext signatures. All other PGP versions do it this way too. This option is not enabled by default because it would violate rfc2440. --passphrase-fd &ParmN; Read the passphrase from file descriptor &ParmN;. If you use 0 for &ParmN;, the passphrase will be read from stdin. This can only be used if only one passphrase is supplied. Don't use this option if you can avoid it. --rfc1991 Try to be more RFC1991 (PGP 2.x) compliant. --openpgp Reset all packet, cipher and digest options to OpenPGP behavior. Use this option to reset all previous options like --rfc1991, --force-v3-sigs, --s2k-*, --cipher-algo, --digest-algo and --compress-algo to OpenPGP compliant values. --force-v3-sigs OpenPGP states that an implementation should generate v4 signatures but PGP 5.x recognizes v4 signatures only on key material. This options forces v3 signatures for signatures on data. --force-mdc Force the use of encryption with appended manipulation code. This is always used with the newer cipher (those with a blocksize greater than 64 bit). This option might not be implemented yet. --allow-non-selfsigned-uid Allow the import of keys with user IDs which are not self-signed. -This is only allows the import - key validation will fail und you +This is only allows the import - key validation will fail and you have to check the validity of the key my other means. This hack is needed for some German keys generated with pgp 2.6.3in. You should really avoid using it, because OpenPGP has better mechanics to do separate signing and encryption keys. --lock-once Lock the databases the first time a lock is requested and do not release the lock until the process terminates. --lock-multiple Release the locks every time a lock is no longer needed. Use this to override a previous --lock-once from a config file. --no-verbose Reset verbose level to 0. --no-greeting Suppress the initial copyright message but do not enter batch mode. --no-secmem-warning Suppress the warning about "using insecure memory". --no-armor Assume the input data is not in ASCII armored format. --no-default-keyring Do not add the default keyrings to the list of keyrings. --skip-verify Skip the signature verification step. This may be used to make the decryption faster if the signature verification is not needed. --with-colons Print key listings delimited by colons. --with-key-data Print key listings delimited by colons and print the public key data. --with-fingerprint Same as the command --fingerprint but changes only the format of the output and may be used together with another command. --no-literal This is not for normal use. Use the source to see for what it might be useful. --set-filesize This is not for normal use. Use the source to see for what it might be useful. RETURN VALUE The program returns 0 if everything was fine, 1 if at least a signature was bad, and other error codes for fatal errors. EXAMPLES gpg -se -r sign and encrypt for user Bob gpg --clearsign &ParmFile; make a clear text signature gpg -sb &ParmFile; make a detached signature gpg --list-keys show keys gpg --fingerprint show fingerprint gpg --verify gpg --verify Verify the signature of the file but do not output the data. The second form is used for detached signatures, where ENVIRONMENT HOME Used to locate the default home directory. GNUPGHOME If set directory used instead of "~/.gnupg". FILES ~/.gnupg/secring.gpg The secret keyring ~/.gnupg/secring.gpg.lock and the lock file ~/.gnupg/pubring.gpg The public keyring ~/.gnupg/pubring.gpg.lock and the lock file ~/.gnupg/trustdb.gpg The trust database ~/.gnupg/trustdb.gpg.lock and the lock file ~/.gnupg/options May contain options /usr[/local]/share/gnupg/options.skel Skeleton options file /usr[/local]/lib/gnupg/ Default location for extensions WARNINGS Use a *good* password for your user account and a *good* passphrase to protect your secret key. This passphrase is the weakest part of the whole system. Programs to do dictionary attacks on your secret keyring are very easy to write and so you should protect your "~/.gnupg/" directory very well. Keep in mind that, if this program is used over a network (telnet), it is *very* easy to spy out your passphrase! BUGS On many systems this program should be installed as setuid(root). This is necessary to lock memory pages. Locking memory pages prevents the operating system from writing memory pages to disk. If you get no warning message about insecure memory your operating system supports locking without being root. The program drops root privileges as soon as locked memory is allocated. diff --git a/g10/ChangeLog b/g10/ChangeLog index 329b3a7b1..dec722de9 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,2281 +1,2293 @@ +Tue Aug 31 17:20:44 CEST 1999 Werner Koch + + + * plaintext.c (do_hash): Hash CR,LF for a single CR. + (ask_for_detached_datafile): Changed arguments to be closer to + those of hash_datafiles and cleanup the code a bit. + * mainproc.c (proc_tree): Workaround for pgp5 textmode detached + signatures. Changed behavior of asking for data file to be the same + as with provided data files. + + * keylist.c (list_keyblock): Use UTF8 print functions. + Mon Aug 30 20:38:33 CEST 1999 Werner Koch * import.c (chk_self_sigs): some s/log_error/log_info/ so that gpg does not return an error if a key has some invalid packets. * helptext.c: Fixed some typos and changed the way the translation works. The english text is now the keyword for gettext and not anymore the keyword supplied to the function. Done after some discussion with Walter who thinks this is much easier for the translators. * misc.c (disable_core_dumps): Don't do it for DOSish systems. * signal.c (signal_name): Bounds check on signum. Wed Aug 4 10:34:18 CEST 1999 Werner Koch * pubring.asc: Updated. * pkclist.c (do_we_trust_pre,check_signatures_trust): Do not print the warning about --always_trust when --quiet is used. * pkclist.c (fpr_info): New and called at several places. * parse-packet.c (dump_sig_subpkt): List revocation key contents. Mon Jul 26 09:34:46 CEST 1999 Werner Koch * pkclist.c (build_pk_list): Fixed typo in format string. * trustdb.c (create_shadow_dir): Don't translate the error string. * g10.c (main): Fixed spelling of user-id. * getkey.c (find_by_name_pk,find_by_name_sk, find_by_keyid,find_by_keyid_sk): Ditto and translate it. * import.c (mark_non_selfsigned_uids_valid,delete_inv_parts): Ditto. Mon Jul 26 01:01:39 CEST 1999 Michael Roth * g10.c, options.h: New options --no-literal and --set-filesize * encode.c (encode_simple, encode_crypt): Support for the options --no-literal and --set-filesize. * sign.c (sign_file): ditto. Fri Jul 23 13:53:03 CEST 1999 Werner Koch * ringedit.c (enum_keyblocks): Removed annoying error message in cases when we have no keyring at all to enum. * getkey.c (classify_user_id): Rewrote to relax the recognition of keyIDs and fingerprints (Michael). * mainproc.c (check_sig_and_print): Print status NO_PUBKEY. (print_failed_pkenc): Print status NO_SECKEY. * import.c (mark_non_selfsigned_uids_valid): New. * g10.c: New option --allow-non-selfsigned-uid. * pkclist.c (print_fpr): New. (do_we_trust_pre): Print the fpr before asking whether to use the key anyway. (do_edit_ownertrust): Likewise. Thu Jul 22 20:03:03 CEST 1999 Werner Koch * ringedit.c (enum_keyblocks): Removed annoying error message in cases when we have no keyring at all to enum. * getkey.c (classify_user_id): Rewrote to relax the recognition of keyIDs and fingerprints (Michael). * mainproc.c (check_sig_and_print): Print status NO_PUBKEY. (print_failed_pkenc): Print status NO_SECKEY. * import.c (mark_non_selfsigned_uids_valid): New. * g10.c: New option --allow-non-selfsigned-uid. Thu Jul 15 10:15:35 CEST 1999 Werner Koch * g10.c: New options --disable-{cipher,pubkey}-algo. Wed Jul 14 19:42:08 CEST 1999 Werner Koch * status.h (STATUS_IMPORTED): New. * import.c (import): Print some status information (Holger Schurig). * g10.c (main): Make --no-greeting work again. Add a warning when --force-mds is used. Tue Jul 13 17:39:25 CEST 1999 Werner Koch * pkclist.c (do_edit_ownertrust): Changed the way help works. (build_pk_list): Implemented default recipient stuff. * g10.c: New options --default-recipient[-self] (main): Suppress greeting in most cases, entering a passphrase or a missing value is not considered to be interactive use. Merged --print-md and --print-mds; the latter is now obsolete. Changed the way --gen-random works and documented it. Changed the way --gen-prime works and add a man entry. * g10.c (MAINTAINER_OPTIONS): Removed. Mon Jul 12 18:45:57 CEST 1999 Werner Koch * keyedit.c (keyedit_menu): Add arg sign_mode and changed callers * g10.c (main): New command --lsign-key. Mon Jul 12 14:55:34 CEST 1999 Werner Koch * mainproc.c (kidlist_item): New. (release_list): Release failed pk-enc-list. (print_failed_pkenc): New (proc_encrypted): Print info about failed PK enc. * openfile.c (make_outfile_name): s/error/info/ * passphrase.c (passphrase_to_dek): Return an empty passphrase when in batch mode and don't make the warning message fatal * seckey-cert.c (check_secret_key): Try only once when in batch mode. * g10.c (make_username): New. Thu Jul 8 16:21:27 CEST 1999 Werner Koch * packet.h (PKT_ring_trust): New * parse-packet.c (parse_trust): Store trust value * build-packet (build_packet): Ignore ring trust packets. * mainproc.c (add_ring_trust): New. (list_node): Print "rtv" records. * g10.c: New option --with-fingerprint. * trustdb.c (verify_own_keys): Don't insert if we are dry running (check_trust): Ditto. Wed Jul 7 13:08:40 CEST 1999 Werner Koch * Makefile.am: Support for libtool. * keygen.c (ask_expire_interval): Hack to allow for an expire date. * trustdb.c (do_update_trust_record,update_trust_record): Splitted. (check_trust_record): New. (check_trust,build_cert_tree): Check the dir record as needed. (upd_pref_record): Removed. (make_pref_record): New. (propagate_validity): Stop as soon as we have enough validity. * tbdio.c (MAX_CACHE_ENTRIES_HARD): Increased the limit. Fri Jul 2 11:45:54 CEST 1999 Werner Koch * g10.c (g10_exit): Dump random stats. * sig-check.c (check_key_signature,check_key_signature2): Enhanced version and wrapper for old function. (do_signature_check,signature_check): Ditto. Thu Jul 1 12:47:31 CEST 1999 Werner Koch * keyedit.c (show_key_with_all_names): Print a notice for disabled keys. (enable_disable_keys): Add functionality * pkclist.c (edit_ownertrust): preserve disabled state. (build_pk_list): Skip disabled keys. * trustdb.c (upd_one_ownertrust): Ditto. (build_cert_tree): Mask the ownertrust. (trust_letter): Mask the value. (do_check): Take disabled flag into account. * passphrase.c (passphrase_to_dek): Add a pubkey_algo arg and changed all callers. * g10.c (utf8_strings): 2 new options. * trustdb.c (insert_trust_record_by_pk): New, replaces the next one. (insert_trust_record): Now takes a keyblock as arg. Changed all callers to use the appropritae function. * openfile.c (ask_outfile_name): New. * plaintext.c (handle_plaintext): Ask for filename if there is no valid syntax. Don't use fname varbatim but filter it. Tue Jun 29 21:44:25 CEST 1999 Werner Koch * trustdb.h (TRUST_FLAG_DISABLED): New. * status.c (USE_CAPABILITIES): Capabilities support (Remi). * tdbio.c : Added new fields to the DIR record. (tdbio_write_record): Fixed the update of the hash tables. (tdbio_delete_record): Drop the record from the hash tables. (drop_from_hashtbl): New. * status.c (cpr_get): Special online help mode. * helptext.c ("keyedit.cmd"): Removed. * keyedit.c (keyedit_menu): Use only help system. (enable_disable_key): New bit doies not yet work. Sat Jun 26 12:15:59 CEST 1999 Werner Koch * dearmor.c (enarmor_file): Fixed comment string. * tdbdump.c (export_ownertrust): Text fix. * tbio.c (tdbio_invalid): Ditto. * parse-packet.c (parse_key): Made temp buffer larger. * Makefile.am (install-data-local): Add missing backslashes Tue Jun 15 12:21:08 CEST 1999 Werner Koch * g10.c (main): Made iterated+salted the default S2K method. * Makefile.am (install-data-local): Use DESTDIR. * passphrase.c (passphrase_to_dek): Emit missing-passphrase while in batchmode. * parse-packet.c (parse_pubkeyenc): Fixed a SEGV. Mon Jun 14 21:18:54 CEST 1999 Michael Roth * g10.c: New options --openpgp, --no-tty, --emit-version, --default-comment and --lock-multiple Thu Jun 10 14:18:23 CEST 1999 Werner Koch * free-packet.c (free_encrypted): Fixed EOF case (Remi). (free_plaintext): Ditto. * helptext.c (keyedit.delsig.unknown): New (Remi). * keyedit.c (print_and_check_one_sig): Add arg print_without_key and changed all callers to make use of it (Remi): Tue Jun 8 13:36:25 CEST 1999 Werner Koch * keylist.c (print_key_data): New and called elsewhere. * g10.c: New option --with-key-data Wed Jun 2 14:17:19 CEST 1999 Werner Koch * mainproc.c (proc_tree): Yet another bad hack to cope with broken pgp2 created detached messages in textmode. Tue Jun 1 16:01:46 CEST 1999 Werner Koch * openfile.c (make_outfile_name): New. * plaintext.c (handle_plaintext): Outputfile is now the inputfile without the suffix. * g10.c: New option --use-embedded-filename Mon May 31 19:41:10 CEST 1999 Werner Koch * g10.c (main): Fix for SHM init (Michael). * compress.c, encr-data.c, mdfilter.c, plaintext.c, free-packet.c: Speed patches (Rémi). Thu May 27 09:40:55 CEST 1999 Werner Koch * status.c (cpr_get_answer_yes_no_quit): New. * keyedit.c (menu_delsig): New. (check_all_keysigs): Splitted. (print_and_check_one_sig): New. Wed May 26 14:36:29 CEST 1999 Werner Koch * build-packet.c (build_sig_subpkt): Support large packets. * parse-packet.c (enum_sig_subpkt): Replaces parse_sig_subpkt. * mainproc.c (print_notation_data): Print all notation packets. * g10.c (add_notation_data): Add a way to specify the critical flag. (main): Add option --set-policy-url. (check_policy_url): Basic checks. * sign.c (mk_notation_and_policy): Replaces mk_notation. * parse-packet.c (can_handle_critical): Moved decision whether we can handle critical subpacket to an extra function. Tue May 25 19:50:32 CEST 1999 Werner Koch * sign.c (sign_file): Always use compression algo 1 for signed onyl file becuase we can´ be sure the the verifier supports other algorithms. * build-packet.c (build_sig_subpkt): Support for notation data. * sign.c (sign_file,clearsign_file,make_keysig_packet): Ditto. (mk_notation): New. * g10.c (add_notation_data): New and add option -N * mainproc.c (print_notation_data): New. (check_sig_and_print): Print any notation data of the signed text. Sun May 23 14:20:22 CEST 1999 Werner Koch * pkclist.c (check_signatures_trust): Print a warning and return immediateley if opt.always_trust is true. * g10.c (main): Corrected handling of no-default-keyring * pkclist.c (algo_available): Disable Twofish until we have settled how to do the MDC. * hkp.c: Disable everything for mingw32 Sat May 22 22:47:26 CEST 1999 Werner Koch * mainproc.c (check_sig_and_print): Add sig creation time to the VALIDSIG status output. Add more info to the ERRSIG output. * sig-check.c (signature_check): Add sig time after epoch to SIG_ID. * import.c (import_one): Merge duplicate user IDs. (collapse_uids): New. * kbnode.c (move_kbnode): New. (remove_kbnode): New. * keyedit.c (keyedit_menu): Call collapse_uids. * g10.c: new option --logger-fd. * import.c: s/log_*_f/log_*/ Thu May 20 14:04:08 CEST 1999 Werner Koch * misc.c (pull_in_libs): do the volatile only for gcc * sig-check (signature_check): Emit SIG_iD only for classes 0 and 1. * armor.c (armor_filter): Add detection of PGP2 created clearsigs. (fake_packet): A tab is not a WS for pgp2 - handle this. * textfilter.c (len_without_trailing_chars): New. (copy_clearsig_text): Add pgp2mode arg. * sign.c (clearsign_file): pass old_style to the above fnc. Wed May 19 16:04:30 CEST 1999 Werner Koch * g10.c: New option --interactive. * mainproc.c (proc_plaintext): Add workaround for pgp2 bug (do_check_sig): Ditto. (proc_tree): Ditto. * plaintext.c (do_hash): Ditto. (hash_datafiles): Ditto, add an arg, changed all callers. * mdfilter.c (md_filter): Add support for the alternate hash context. Mon May 17 21:54:43 CEST 1999 Werner Koch * parse-packet.c (parse_encrypted): Support for PKT_ENCRYPTED_MDC. * build-packet.c (do_encrypted_mdc): Ditto. * cipher.c (write_header): Add mdc hashing. (cipher_filter): write out the hash. * mainproc.c (do_proc_packets): Add PKT_ENCRYPTED_MDC. * encr-data.c (decrypt_data): Add mdc hashing. (mdc_decode_filter): New. * parse-packet.c (parse_sig_subpkt): Fixed stupid bug for subpkt length calculation (parse_signature): Fixed even more stupid bug. Sat May 8 19:28:08 CEST 1999 Werner Koch * build-packet.c (do_signature): Removed MDC hack. * encode.c (encode_crypt_mdc): Removed. * mainproc.c (do_check_sig): Removed MDC hack. (check_sig_and_print): Ditto. * parse-packet.c (parse_signature): Ditto. * sig-check.c (mdc_kludge_check): Ditto. * free-packte.c (copy_signature, free_seckey_enc): Ditto. * parse-packet.c (parse_signature,parse_key): Store data of unknown algorithms with mpi_set_opaque inseatd of the old faked data stuff. (read_rest): Removed. (read_rest2): Renamed to read_rest * build-packet.c (write_fake_data): Use mpi_get_opaque. * free-packet.c (cp_fake_data): Removed and cahnged all callers to use mpi_copy. (free_pubkey_enc,free_seckey_enc,release_public_key_parts, release_secret_key_parts): Use mpi_free for opaque data. Thu May 6 14:18:17 CEST 1999 Werner Koch * trustdb.c (check_trust): Check for revoked subkeys. * pkclist.c (do_we_trust): Handled revoked subkeys. (do_we_trust_pre): Ditto. (check_signatures_trust): Ditto. * build-packet.c (hash_public_key): Fix for ancient g10 keys. * mainproc.c (do_proc_packets): Return EOF if no data has been read. * g10.c (main): Catch errors for default operation. Thu Apr 29 12:29:22 CEST 1999 Werner Koch * sign.c (sign_file): Fixed hashing in case of no subpackets. (clearsign_file): Ditto. (make_keysig_packet): Ditto. Wed Apr 28 13:03:03 CEST 1999 Werner Koch * keyedit.c (keyedit_menu): Add new command revkey. * (menu_revkey): New. Mon Apr 26 17:48:15 CEST 1999 Werner Koch * parse-packet.c (parse_signature): Add the MDC hack. * build-packet.c (do_signature): Ditto. * free-packet.c (free_seckey_enc,copy_signature,cmp_signatures): Ditto. * mainproc.c (do_check_sig): Ditto. * sig-check.c (mdc_kludge_check): New. * encode.c (encrypt_mdc_file): New. * keyedit.c (check_all_keysigs): List revocations. * (menu_revsig): New. * sign (make_keysig_packet): Support for class 0x30. Sun Apr 18 20:48:15 CEST 1999 Werner Koch * pkclist.c (select_algo_from_prefs): Fixed the case that one key has no preferences (Remi Guyomarch). keylist.c (list_keyblock): ulti_hack to propagate trust to all uids. Sun Apr 18 10:11:28 CEST 1999 Werner Koch * seckey-cert.c (do_check): Use real IV instead of a 0 one, so that it works even if the length of the IV doesn't match the blocksize. Removed the save_iv stuff. (protect_secret_key): Likewise. Create the IV here. * packet.h (PKT_secret_key): Increased size of IV field and add a ivlen field. * parse-packet.c (parse_key): Use the len protect.ivlen. * build-packet.c (do_secret_key). Ditto. * getkey.c (key_byname): Close keyblocks. * Makefile.am (gpgm): Removed this * g10.c: Merged gpg and gpgm * import.c (import): Utilize option quiet. * tdbio.c (tdbio_set_dbname): Ditto. * ringedit.c (add_keyblock_resource,keyring_copy): Ditto. * keyedit.c (sign_uids): Add some batch support. * g10.c (main): add call to tty_batchmode. Fri Apr 9 12:26:25 CEST 1999 Werner Koch * status.c (write_status_text): Some more status codes. * passphrase_to_dek (passphrase_to_dek): add a status code. * seckey_cert.c (check_secret_key): Likewise. * encr-data.c (decrypt_data): Reverse the last changes * cipher.c (write_header): Ditto. * parse-packet.c (parse_key): Dropped kludge for ancient blowfish mode. Thu Apr 8 09:35:53 CEST 1999 Werner Koch * mainproc.c (proc_encrypted): Add a new status output * passphrase.c (passphrase_to_dek): Ditto. * status.h status.c: Add new status tokens. Wed Apr 7 20:51:39 CEST 1999 Werner Koch * encr-data.c (decrypt_data): Fixes for 128 bit blocksize * cipher.c (write_header): Ditto. * seckey-cert.c (do_check): Ditto. (protect_secret_key). Ditto. * misc.c (print_cipher_algo_note): Twofish is now a standard algo. * keygen.c (do_create): Fixed spelling (Gaël Quéri) (ask_keysize): Only allow keysizes up to 4096 * ringedit.c (add_keyblock_resource): chmod newly created secrings. * import.c (delete_inv_parts): Fixed accidently deleted subkeys. Tue Apr 6 19:58:12 CEST 1999 Werner Koch * armor.c: Removed duped include (John Bley) * mainproc.c: Ditto. * build-packet.c (hash_public_key): Fixed hashing of the header. * import.c (delete_inv_parts): Allow import of own non-exportable sigs. Sat Mar 20 13:59:47 CET 1999 Werner Koch * armor.c (fake_packet): Fix for not not-dash-escaped Sat Mar 20 11:44:21 CET 1999 Werner Koch * g10.c (main): Added command --recv-keys * hkp.c (hkp_import): New. Wed Mar 17 13:09:03 CET 1999 Werner Koch * trustdb.c (check_trust): add new arg add_fnc and changed all callers. (do_check): Ditto. (verify_key): Ditto. (propagate_validity): Use the new add_fnc arg. (print_user_id): Add the FILE arg. (propagate_ownertrust): New. * pkclist.c (add_ownertrust_cb): New and changed the add_ownertrust logic. * getkey.c (get_keyblock_bylid): New. * trustdb.c (print_uid_from_keyblock): New. (dump_tn_tree_with_colons): New. (list_trust_path): Add colon print mode. * trustdb.c (insert_trust_record): Always use the primary key. * encode.c (encode_simple): Added text_mode filter (Rémi Guyomarch) (encode_crypt): Ditto. * mainproc.c (proc_pubkey_enc): Added status ENC_TO. * armor.c (armor_filter): Added status NODATA. * passphrase.c (passphrase_to_dek): Always print NEED_PASSPHRASE * seckey_cert.c (check_secret_key): Added BAD_PASS status. * g10.c (main): Set g10_opt_homedir. Sun Mar 14 19:34:36 CET 1999 Werner Koch * keygen.c (do_create): Changed wording of the note (Hugh Daniel) Thu Mar 11 16:39:46 CET 1999 Werner Koch * tdbdump.c: New * trustdb.c (walk_sigrecs,do_list_sigs,list_sigs, list_records,list_trustdb,export_ownertrust,import_ownertrust): Moved to tdbdump.c (init_trustdb): renamed to setup_trustdb. Changed all callers. (do_init_trustdb): renamed to init_trustdb(). * trustdb.c (die_invalid_db): replaced by tdbio_invalid. * tdbio.c (tdbio_invalid): New. * import.c (delete_inv_parts): Skip non exportable signatures. * keyedit.c (sign_uid_mk_attrib): New. (sign_uids): Add the local argument. (keyedit_menu): New "lsign" command. * trustdb.c (register_trusted_key): Removed this and all related stuff. * g10.c (oTrustedKey): Removed option. * tdbio.h (dir.valcheck): New trustdb field. * tdbio.c: Add support for this field (tdbio_read_modify_stamp): New. (tdbio_write_modify_stamp): New. * trustdb.c (do_check): Check against this field. Removed cache update. (verify_key): Add cache update. (upd_uid_record): Some functional changes. (upd_cert_record): Ditto Wed Mar 10 11:26:18 CET 1999 Werner Koch * keylist.c (list_keyblock): Fixed segv in uid. Print 'u' as validity of sks. Mon Mar 8 20:47:17 CET 1999 Werner Koch * getkey.c (classify_user_id): Add new mode 12 (#). * seckey-cert.c (check_secret_key): replaced error by info. * trustdb.c (query_trust_info): Add another arg, changed all callers. (check_trust): Ditto. (do_check): Ditto. (verify_key): Handle namehash. * keylist.c (list_keyblock): print trust info for user ids. * sig-check.c (signature_check): Add sig-created to status output. Tue Mar 2 16:44:57 CET 1999 Werner Koch * textfilter.c (copy_clearsig_text): New. (clearsign): Removed. * sign.c (clearsign_file): does not use textfiler anymore. * keygen.c (ask_user_id): print a note about the used charset. Tue Mar 2 10:38:42 CET 1999 Werner Koch * sig-check.c (signature_check): sig-id now works for all algos. * armor.c (armor_filter): Fixed armor bypassing. Sun Feb 28 19:11:00 CET 1999 Werner Koch * keygen.c (ask_user_id): Don't change the case of email addresses. (has_invalid_email_chars): Adjusted. * keylist.c (list_one): Really list serect keys (Remi Guyomarch) * keyedit.c (menu_select_uid): Add some braces to make egcs happy. (menu_select_key): Ditto. * mainproc.c (do_proc_packets): List sym-enc packets (Remi Guyomarch) Fri Feb 26 17:55:41 CET 1999 Werner Koch * pkclist.c (build_pk_list): Return error if there are no recipients. * sig-check.c (signature_check): New signature id feature. * armor.c (make_radic64_string): New. * mainproc.c (proc_pubkey_enc): early check for seckey availability. * pkclist.c (do_we_trust_pre): print user id before asking. * ringedit.c (add_keyblock_resource,get_keyblock_handle): Cleaner handling of default resource. Thu Feb 25 18:47:39 CET 1999 Werner Koch * pkclist.c (algo_available): New. (select_algo_from_prefs): Check whether algo is available. * ringedit.c (keyring_copy): Take care of opt.dry_run. (do_gdbm_store): Ditto. * openfile.c (open_outfile). Ditto. (copy_options_file): Ditto. * trustdb.c (update_trustdb): Ditto. (clear_trust_checked_flag): Ditto. (update_trust_record): Ditto. (insert_trust_record): Ditto. Wed Feb 24 11:07:27 CET 1999 Werner Koch * keylist.c (secret_key_list): Now really list the secret key. * trustdb.c (do_init_trustdb): New. Init is now deferred. Mon Feb 22 20:04:00 CET 1999 Werner Koch * getkey.c (lookup_sk): Return G10ERR_NO_SECKEY and not x_PUBKEY. Fri Feb 19 15:49:15 CET 1999 Werner Koch * pkclist.c (select_algo_from_prefs): retrieve LID if not there. * armor.c (fake_packet): Replaced ugly lineending handling. * g10.c (oNoEncryptTo): New. * pkclist.c (build_pk_list): Implemented this option. * g10.c (main): Greeting is now printed to stderr and not to tty. Use add_to_strlist() instead of direct coding. * import.c (import): Use iobuf_push_filter2. * mainproc.c (check_sig_and_print): Print all user ids for good signatures. * getkey.c (get_pubkeyblock): New. * import.c (chk_self_sigs): Fixed SEGV for unbounded class 0x18 keys. (delete_inv_parts): Delete special marked packets. Tue Feb 16 14:10:02 CET 1999 Werner Koch * g10.c (main): New option --encrypt-to * pkclist.c (build_pk_list): Implemented encrypt-to. * parse-packet.c (parse_user_id): Removed the hack to work with utf-8 strings. * g10.c (main): Install lockfile cleanup handler. * tdbio.c (cleanup): Removed: this is now handled by dotlock. Sat Feb 13 14:13:04 CET 1999 Werner Koch * tdbio.c (tdbio_set_dbname): Init lockhandle for a new trustdb Wed Feb 10 17:15:39 CET 1999 Werner Koch * g10.c (main): check for development version now in configure * tdbio.c (tdbio_write_record): Add uid.validity (tdbio_read_record) : Ditto. (tdbio_dump_record) : Ditto. * keygen.c (keygen_add_std_prefs): Replaced Blowfish by Twofish, removed MD5 and Tiger. * pubkey-enc.c (get_it): Suppress warning about missing Blowfish in preferences in certain cases. * ringedit.c (lock_rentry,unlock_rentry): New. * getkey.c (key_byname): Pass ret_kb down to lookup_xx. * armor.c (armor_filter): No output of of empty comment lines. Add option --no-version to suppress the output of the version string. * getkey.c: Release the getkey context for auto context variables. Sun Jan 24 18:16:26 CET 1999 Werner Koch * getkey.c: Changed the internal design to allow simultaneous lookup of multible user ids (get_pubkey_bynames): New. (get_seckey_bynames): New. (get_seckey_next): New. (get_seckey_end): New. * keylist.c (list_one): Use the new functions. * keylist.c (list_keyblock): add a newline for normal listings. * g10.c (--recipient): New option name to replace --remote-user Wed Jan 20 18:59:49 CET 1999 Werner Koch * textfilter.c: Mostly rewritten * plaintext.c (handle_plaintext): Use now text_filter semantics. Tue Jan 19 19:34:58 CET 1999 Werner Koch * export.c (export_pubkeys_stream): New. (do_export_stream): New. * g10.c (aSendKeys): New command. * hkp.c (hkp_export): New. * compress.c (do_uncompress): Hack for algo 1 and 1.1.3 Sun Jan 17 11:04:33 CET 1999 Werner Koch * textfilter.c (text_filter): Now uses iobuf_read_line(). (read_line): Removed. * armor.c (trim_trailing_spaces): Removed and replaced by trim_trailing_ws from libutil Sat Jan 16 12:03:27 CET 1999 Werner Koch * hkp.c (hkp_ask_import): Use only the short keyid Sat Jan 16 09:27:30 CET 1999 Werner Koch * import.c (import_key_stream): New (import): New, moved most of import_keys here. * g10.c: New option --keyserver * mainproc.c (check_sig_and_print): Hook to import a pubkey. * pref.c pref.h : Removed * hkp.c hkp.h: New Wed Jan 13 14:10:15 CET 1999 Werner Koch * armor.c (radix64_read): Print an error if a bad armor was detected. Wed Jan 13 12:49:36 CET 1999 Werner Koch * armor.c (radix64_read): Now handles malformed armors produced by some buggy MUAs. Tue Jan 12 11:17:18 CET 1999 Werner Koch * ringedit.c (find_keyblock_bysk): New. * skc_list.c (is_insecure): New. (build_sk_list): usage check for insecure keys. * import.c (chk_self_sigs): Add handling for subkeys. (delete_inv_parts): Skip unsigned subkeys * sig-check.c (do_check): Print info if the signature is older than the key. * keygen.c (generate_subkeypair): Fail on time warp. * sign.c (do_sign): Ditto. Sun Jan 10 15:10:02 CET 1999 Werner Koch * armor.c (fake_packet): Fixed not-dash-escaped bug. Sat Jan 9 16:02:23 CET 1999 Werner Koch * sig-check.c (do_check): Output time diff on error * status.c (STATUS_VALIDSIG): New. (is_status_enabled): New. * mainproc.c (check_sig_and_print): Issue that status message. * plaintext.c (special_md_putc): Removed * armor.c (armor_filter): print error for truncated lines. * free-packet.c (free_encrypted): Revomed call to set_block_mode. (free_plaintext): Ditto. Thu Jan 7 18:00:58 CET 1999 Werner Koch * pkclist.c (add_ownertrust): Fixed return value. * encr-data.c (decrypt_data): Disabled iobuf_set_limit and iobuf_pop_filter stuff. * compress.c (handle_compressed): Disabled iobuf_pop_filter. * packet.h (PKT_secret_key): Add is_primary flag. * parse-packet.c (parse_key): Set this flag. * passphrase.c (passphrase_to_dek): Kludge to print the primary keyid - changed the API: keyid must now hold 2 keyids. * getkey.c (get_primary_seckey): New. * seckey-cert.c (do_check): pass primary keyid to passphrase query * tbdio.c (open_db): removed the atexit (tdbio_set_dbname): and moved it to here. * armor.c: Rewrote large parts. Tue Dec 29 19:55:38 CET 1998 Werner Koch * revoke.c (gen_revoke): Removed compression. * pkclist.c (do_we_trust_pre): special check for revoked keys * trustdb.c (update_trust_record): Fixed revoke flag. Tue Dec 29 14:41:47 CET 1998 Werner Koch * misc.c (disable_core_dumps): Check for EINVAL (Atari) * getkey (merge_one_pk_and_selfsig): Fixed search of expiredate. (merge_keys_and_selfsig): Ditto. * free-packet.c (cmp_public_keys): cmp expire only for v3 packets (cmp_secret_keys): Ditto. (cmp_public_secret_key): Ditto. Wed Dec 23 17:12:24 CET 1998 Werner Koch * armor.c (find_header): Reset not_dashed at every header Wed Dec 23 13:18:14 CET 1998 Werner Koch * pkclist.c (add_ownertrust): Refresh validity values. * trustdb.c (enum_cert_paths_print): New arg refresh. * ringedit.c: Fixed problems fix keyrings * parse-packet.c (dbg_parse_packet): New debug functions. * getkey.c (getkey_disable_caches): New. * import.c (import_keys): Disable caches. Thu Dec 17 18:31:15 CET 1998 Werner Koch * misc.c (trap_unaligned): Only for glibc 1 * sign.c (write_dash_escaped): Now escapes "From " lines * g10.c: New option --escape-from-lines * trustdb.c (sort_tsl_list): New (list_trust_path): Now prints sorted list. (enum_cert_paths): Likewise. (enum_cert_paths_print): New. (print_paths): New printing format. * pkclist.c (add_ownertrust): New arg quit. (edit_ownertrust): New quit selection and does not query the recipients ownertrust anymore. (add_ownertrust): Print the ceritficate path. Mon Dec 14 21:18:49 CET 1998 Werner Koch * parse-packet.c (parse_signature): Now checks for critical bit (parse_sig_subpkt): Splitted. (parse_one_sig_subpkt): New. * sig-check.c (do_check): handle critical bit. Sun Dec 13 14:10:56 CET 1998 Werner Koch * pcklist.c (select_algo_from_prefs): Preferences should now work (lost the != ? ) Thu Dec 10 20:15:36 CET 1998 Werner Koch * ringedit.c (gdbm_store): Fix for inserts * g10.c (main): New option --export-all * export.c (export_pubkeys): New arg. (do_export): Now may skip old keys. * status.c: Minor patches for Sun's cc * keygen.c (ask_algo): Disabled v3 ElGamal choice, rearranged the numbers. Add a warning question when a sign+encrypt key is selected. * g10.c (do_not_use_RSA): Removed. * misc.c (print_pubkey_algo_note): New as replacement for the do_not_use_RSA() and chnaged all callers. (print_cipher_algo_note): New. (print_hash_algo_note): New. * cipher.c (write_header): Add a call to print_cipher_algo_note. * seckey-cert.c (protect_secret_key): Ditto * sign.c (do_sign): Add a call to print_digest_algo_note. * getkey.c (get_long_user_id_string): New. * mainproc.c (check_sig_and_print): Changed the format of the status output. * encrypt.c (write_pubkey_enc_from_list): print used symmetric cipher. * pkclist.c (do_we_trust): Changed a message. Wed Dec 9 13:41:06 CET 1998 Werner Koch * misc.c (trap_unaligned) [ALPHA]: Only if UAC_SIGBUS is defined. * sign.c (write_dash_escaped): Add the forgotten patch by Brian Moore. * compress.c (do_uncompress): Fixed the inflating bug. Tue Dec 8 13:15:16 CET 1998 Werner Koch * trustdb.c (upd_uid_record): Now uses the newest self-signature (insert_trust_record): Now calls update with recheck set to true. (register_trusted_key): New. (verify_own_keys): Enhanced by list of trusted keys. * g10.c (main): Print a warning when a devel version is used. (main): New option --trusted-key * import.c (merge_blocks): Fixed merging of new user ids and added merging of subkeys. (append_uid): Ditto. (merge_keysig): New. (append_key): New. * getkey.c (merge_one_pk_and_selfsig): Get the expiration time from the newest self-signature. (merge_keys_and_selfsig): Ditto. * free-packet.c (cmp_secret_key): New. Fri Nov 27 21:37:41 CET 1998 Werner Koch * g10.c: New option --lock-once * tdbio.c (open_db): Add an atexit (cleanup): New. (tdbio_sync): Add locking. (tdbio_end_transaction): Ditto. (put_record_into_cache): Ditto. * ringedit.c (keyring_copy): Ditto. (cleanup): New. (add_keyblock_resource): Add an atexit. Fri Nov 27 15:30:24 CET 1998 Werner Koch * armor.c (find_header): Another fix for clearsigs. Fri Nov 27 12:39:29 CET 1998 Werner Koch * status.c (display_help): Removed. * helptext.c: New and removed the N_() from all cpr_gets. Fri Nov 20 16:54:52 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (main): New option --not-dash-escaped * sign.c (write_dashed_escaped): Ditto. * armor.c (find_header): Support for NotDashEscaped header. * getkey.c: print "disabled cache.." only if verbose is used. Thu Nov 19 07:17:31 1998 Werner Koch * parse-packet.c (dump_sig_subpkt): Fixed expire listing * getkey.c (merge_keys_and_selfsig): Fixed expire calculation. (merge_one_pk_and_selfsig): Ditto. * keyedit.c (menu_expire). Ditto. * keygen.c (keygen_add_key_expire): Ditto. (ask_expire_interval): New and changed all local function to use this instead. (keygen_add_key_expire): Opaque should now be a public key; changed all callers. * parse.packet.c (parse): use skip_rest to skip packets. * keyedit.c (keyedit_menu): New arg for cmdline cmds. Wed Nov 18 20:33:50 1998 Werner Koch (wk@isil.d.shuttle.de) * trustdb.c (check_trustdb): Now rechecks all gived userids. (collect_paths): Some fixes. (upd_pref_records): Skips empty items, evaluate all items. * parse-packet.c (dump_sig_subpkt): Better listing of prefs. (skip_packet): Now knows about marker packet * g10.c: removed cmd "--edit-sig". * pubring.asc: Updated. Sat Nov 14 14:01:29 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (main): Changed syntax of --list-trust-path * trustdb.c (list_trust_path): Replaced max_depth by opt.max_cert_depth Fri Nov 13 07:39:58 1998 Werner Koch * trustdb.c (collect_paths): Removed a warning message. (enum_trust_web): Removed. (enum_cert_paths): New. * pkclist.c (add_ownertrust): Changed to use enum_cert_paths. (edit_ownertrust): Now list ceritficates on request. (show_paths): New. Wed Nov 11 18:05:44 1998 Werner Koch * g10.c (main): New option --max-cert-depth * tdbio.h: add new fields to ver and dir record. * tdbio.c: read/write/dump of these fields. (tdbio_db_matches_options): New. * trustdb.c: replaced MAC_CERT_DEPTH by opt.max_cert_depth. (do_check): cache validity and changed other functions to reset the cached value. * keylist.c (list_one): Now lists the ownertrust. * mainproc.c (list_node): Ditto. Tue Nov 10 10:08:59 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (g10_exit): Now looks at the new g10_errors_seen. * mainproc.c (check_sig_and_print): Sets g10_errors_seen. * *.c : i18n many more strings. * ringedit.c (locate_keyblock_by_keyid): Add HAVE_LIBGDBM (locate_keyblock_by_fpr): Ditto. * g10.c (main): removed unsused "int errors". (main): Add new option --charset. * g10.c (main): special message for the unix newbie. Mon Nov 9 07:17:42 1998 Werner Koch * getkey.c (finish_lookup): Kludge to prefere algo 16. * trustdb.c (new_lid_table): Clear cached item. * status.c (cpr_get_utf8): New. * pkclist.c (build_pk_list): Uses this. Sun Nov 8 17:20:39 1998 Werner Koch (wk@isil.d.shuttle.de) * mainproc.c (check_sig_and_print): Why did I use strlen()-1 in the printf? - This truncated the TZ. Sat Nov 7 15:57:28 1998 me,,, (wk@tobold) * getkey.c (lookup): Changes to support a read_next. (get_pubkey): Fixed a memory leak. * keylist.c (list_one): Now lists all matching user IDs. Tue Nov 3 16:19:21 1998 Werner Koch (wk@isil.d.shuttle.de) * keygen.c (ask_user_id): Now converted to UTF-8 * g10.c (main): Kludge for pgp clearsigs and textmode. Fri Oct 30 16:40:39 1998 me,,, (wk@tobold) * signal.c (block_all_signals): New. (unblock_all_signals): New * tdbio.c (tdbio_end_transaction): Now blocks all signals. * trustdb.c (new_lid_table): Changed the representation of the former local_lid_info stuff. * trustdb.c (update_trust_record): Reorganized the whole thing. * sig-check.c (check_key_signature): Now handles class 0x28 Wed Oct 28 18:56:33 1998 me,,, (wk@tobold) * export.c (do_export): Takes care of the exportable sig flag. Tue Oct 27 14:53:04 1998 Werner Koch (wk@isil.d.shuttle.de) * trustdb.c (update_trust_record): New "fast" parameter. Sun Oct 25 19:32:05 1998 Werner Koch (wk@isil.d.shuttle.de) * openfile.c (copy_options_File): New. * ringedit.c (add_keyblock_resource): Creates options file * tdbio.c (tdbio_set_dbname): Ditto. Sat Oct 24 14:10:53 1998 brian moore * mainproc.c (proc_pubkey_enc): Don't release the DEK (do_proc_packets): Ditto. Fri Oct 23 06:49:38 1998 me,,, (wk@tobold) * keyedit.c (keyedit_menu): Comments are now allowed * trustdb.c: Rewrote large parts. Thu Oct 22 15:56:45 1998 Michael Roth (mroth@nessie.de) * encode.c: (encode_simple): Only the plain filename without a given directory is stored in generated packets. (encode_crypt): Ditto. * sign.c: (sign_file) Ditto. Thu Oct 22 10:53:41 1998 Werner Koch (wk@isil.d.shuttle.de) * trustdb.c (update_trust_record): Add new optional arg. * import.c (import_keys): Add statistics output * trustdb.c (update_trustdb): Ditto. (insert_trustdb): Ditto. * tdbio.c (tdbio_begin_transaction): New. (tdbio_end_transaction): New. (tdbio_cancel_transaction): New. * g10.c (main): New option --quit. * trustdb.c (check_hint_sig): No tests for user-id w/o sig. This caused an assert while checking the sigs. * trustdb.c (upd_sig_record): Splitted into several functions. * import.c (import_keys): New arg "fast". * g10.c (main): New command --fast-import. Wed Oct 21 18:19:36 1998 Michael Roth * ringedit.c (add_keyblock_resource): Directory is now created. * tdbio.c (tdbio_set_dbname): New info message. Wed Oct 21 11:52:04 1998 Werner Koch (wk@isil.d.shuttle.de) * trustdb.c (update_trustdb): released keyblock in loop. * keylist.c (list_block): New. (list_all): Changed to use list_block. * trustdb.c: Completed support for GDBM * sign.c (only_old_style): Changed the way force_v3 is handled (sign_file): Ditto. (clearsign_file): Ditto. * keygen.c (has_invalid_email_chars): Splitted into mailbox and host part. * keylist.c (list_one): Add a merge_keys_and_selfsig. * mainproc.c (proc_tree): Ditto. Sun Oct 18 11:49:03 1998 Werner Koch (wk@isil.d.shuttle.de) * sign.c (only_old_style): Add option force_v3_sigs (sign_file): Fixed a bug in sig->version (clearsign_file): Ditto. * parse-packet.c (dump_sig_subpkt): New * keyedit.c (menu_expire): New. * free-packet.c (cmp_signatures): New Sat Oct 17 10:22:39 1998 Werner Koch (wk@isil.d.shuttle.de) * armor.c: changed output line length from 72 to 64. * keyedit.c (fix_keyblock): New. Fri Oct 16 10:24:47 1998 Werner Koch (wk@isil.d.shuttle.de) * trustdb.c: Rewrote most. * tdbio.c: Add cache and generalized hash tables. * options.h (ENABLE_COMMENT_PACKETS): New but undef'ed. * encode.c, sign.c, keygen.c: Disabled comment packets. * export.c (do_export): Comment packets are never exported, except for those in the secret keyring. * g10.c (main): Removed option do-no-export-rsa; should be be replaced by a secpial tool. * export.c (do_export): Removed the code for the above option. * armor.c (find_header): Support for new only_keyblocks. * import.c (import_keys): Only looks for keyblock armors. * packet.h: replaced valid_days by expiredate and changed all users. * build-packet.c (do_public_key): calculates valid-days (do_secret_key): Ditto. * parse-packet.c (parse_key): expiredate is calucated from the valid_period in v3 packets. * keyid.c (do_fingerprint_md): calculates valid_dates. * keygen.c (add_key_expire): fixed key expiration time for v4 packets. * armor.c (find_header): A LF in the first 28 bytes was skipped for non-armored data. Thu Oct 8 11:35:51 1998 Werner Koch (wk@isil.d.shuttle.de) * armor.c (is_armored): Add test on old comment packets. * tdbio.c (tdbio_search_dir_bypk): fixed memory leak. * getkey.c: Changed the caching algorithms. Wed Oct 7 19:33:28 1998 Werner Koch (wk@isil.d.shuttle.de) * kbnodes.c (unused_nodes): New. Wed Oct 7 11:15:36 1998 Werner Koch (wk@isil.d.shuttle.de) * keyedit.c (sign_uids): Fixed a problem with SK which could caused a save of an unprotected key. (menu_adduid): Ditto. * keyedit.c (keyedit_menu): Prefs are now correctly listed for new user ids. * trustdb.c (update_trust_record): New. (insert_trust_record): Now makes use of update_trust_record. Tue Oct 6 16:18:03 1998 Werner Koch (wk@isil.d.shuttle.de) * trustdb.c (read_record): replaces most of the tdbio_read_records. (write_record): Ditto. Sat Oct 3 11:01:21 1998 Werner Koch (wk@isil.d.shuttle.de) * keygen.c (ask_alogo): enable ElGamal enc-only only for addmode. Wed Sep 30 10:15:33 1998 Werner Koch (wk@isil.d.shuttle.de) * import.c (import_one): Fixed update of wrong keyblock. Tue Sep 29 08:32:08 1998 me,,, (wk@tobold) * mainproc.c (proc_plaintext): Display note for special filename. * plaintext.c (handle_plaintext): Suppress output of special file. Mon Sep 28 12:57:12 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (verify_own_keys): Add warning if a key is not protected. * passphrase (hash_passphrase): Fixed iterated+salted mode and setup for keysizes > hashsize. * g10.c (main): New options: --s2k-{cipher,digest,mode}. Fri Sep 25 09:34:23 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c: Chnaged some help texts. Tue Sep 22 19:34:39 1998 Werner Koch (wk@isil.d.shuttle.de) * passphrase.c (read_passphrase_from_fd): fixed bug for long passphrases. Mon Sep 21 11:28:05 1998 Werner Koch (wk@(none)) * getkey.c (lookup): Add code to use the sub key if the primary one does not match the usage. * armor.c (armor_filter): New error message: no valid data found. (radix64_read): Changes to support multiple messages. (i18n.h): New. * mainproc.c (add_onepass_sig): bug fix. Mon Sep 21 08:03:16 1998 Werner Koch (wk@isil.d.shuttle.de) * pkclist.c (do_we_trust): Add keyid to most messages. * passphrase.c (read_passphrase_from_fd): New. (have_static_passphrase): New (get_passphrase_fd): Removed. (set_passphrase_fd): Removed. * g10.c (main): passphrase is now read here. * keyedit.c (keyedit_menu): "help" texts should now translate fine. Mon Sep 21 06:40:02 1998 Werner Koch (wk@isil.d.shuttle.de) * encode.c (encode_simple): Now disables compression when --rfc1991 is used. (encode_crypt): Ditto. Fri Sep 18 16:50:32 1998 Werner Koch (wk@isil.d.shuttle.de) * getkey.c (merge_key_and_selfsig): New. Fri Sep 18 10:20:11 1998 Werner Koch (wk@isil.d.shuttle.de) * pkclist.c (select_algo_from_prefs): Removed 3DES kludge. * seskey.c (make_session_key): Fixed SERIOUS bug introduced by adding the weak key detection code. * sign.c (sign_file): Changed aremor header in certain cases. Tue Sep 15 17:52:55 1998 Werner Koch (wk@isil.d.shuttle.de) * mainproc.c (check_sig_and_print): Replaced ascime by asctimestamp. Mon Sep 14 11:40:52 1998 Werner Koch (wk@isil.d.shuttle.de) * seskey.c (make_session_key): Now detects weak keys. * trustdb (clear_trust_checked_flag): New. * plaintext.c (handle_plaintext): Does no anymore suppress CR from cleartext signed messages. Sun Sep 13 12:54:29 1998 Werner Koch (wk@isil.d.shuttle.de) * trustdb.c (insert_trust_record): Fixed a stupid bug in the free liunked list loops. Sat Sep 12 15:49:16 1998 Werner Koch (wk@isil.d.shuttle.de) * status.c (remove_shmid): New. (init_shm_comprocess): Now sets permission to the real uid. Wed Sep 9 11:15:03 1998 Werner Koch (wk@isil.d.shuttle.de) * packet.h (PKT_pubkey_enc): New flah throw_keyid, and add logic to implement it. * g10.c (main): New Option --throw-keyid * getkey.c (enum_secret_keys): Add new ar and changed all callers. Tue Sep 8 20:04:09 1998 Werner Koch (wk@isil.d.shuttle.de) * delkey.c (delete_key): Moved from keyedit.c. Mon Sep 7 16:37:52 1998 Werner Koch (wk@isil.d.shuttle.de) * build-packet.c (calc_length_header): New arg new_ctb to correctly calculate the length of new style packets. * armor.c (is_armored): Checks for symkey_enc packets. * pkclist.c (select_algo_from_prefs): 3DEs substitute is now CAST5. Tue Aug 11 17:54:50 1998 Werner Koch (wk@isil.d.shuttle.de) * build-packet.c (do_secret_key): Fixed handling of old keys. * getkey.c (compare_name): Fixed exact and email matching * openfile.c (open_outfile): Changed arguments and all callers. Tue Aug 11 09:14:35 1998 Werner Koch (wk@isil.d.shuttle.de) * encode.c (encode_simple): Applied option set-filename and comment. (encode_crypt): Ditto. * sign.c (sign_file): Ditto. * armor.c (armor_filter): Applied option comment. * encode.c (encode_crypt): Moved init_packet to the begin. (encode_simple): add an init_packet(). * comment (write_comment): Now enforces a hash sign as the 1st byte. * import.c (import_one): Add explanation for "no user ids". * compress.c (do_uncompress): Applied Brian Warner's patch to support zlib 1.1.3 etc. * trustdb.c (check_trust): Fixed a problem after inserting new keys. * getkey (lookup): do not return the primary key if usage is given (lookup_sk): Ditto and take usage into account. * status.c (cpr_get_answer_is_yes): add display_help. Mon Aug 10 10:11:28 1998 Werner Koch (wk@isil.d.shuttle.de) * getkey.c (lookup_sk): Now always returns the primary if arg primary is true. (lookup): Likewise. (get_pubkey_byname): Now returns the primary key (get_seckey_byname): Ditto. Mon Aug 10 08:34:03 1998 Werner Koch (wk@isil.d.shuttle.de) * keyid.c (pubkey_letter): ELG_E is now a small g. Sat Aug 8 17:26:12 1998 Werner Koch (wk@isil.d.shuttle.de) * openfile (overwrite_filep): Changed semantics and all callers. Sat Aug 8 12:17:07 1998 Werner Koch (wk@isil.d.shuttle.de) * status.c (display_help): New. Thu Aug 6 16:30:41 1998 Werner Koch,mobil,,, (wk@tobold) * seskey.c (encode_session_key): Now uses get_random_bits(). Thu Aug 6 07:34:56 1998 Werner Koch,mobil,,, (wk@tobold) * ringedit.c (keyring_copy): No more backupfiles for secret keyrings and add additional warning in case of a failed secret keyring operation. Wed Aug 5 11:54:37 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (check_opts): Moved to main. Changed def_cipher_algo semantics and chnaged all users. * pubkey-enc.c (get_sssion_key): New informational output about preferences. * parse-packet.c (parse_symkeyenc): Fixed salted+iterated S2K (parse_key): Ditto. * build-packet.c (do_secret_key): Ditto. (do_symkey_enc): Ditto. Tue Aug 4 08:59:10 1998 Werner Koch (wk@isil.d.shuttle.de) * getkey.c (enum_secret_keys): Now returns only primary keys. * getkey (lookup): Now sets the new namehash field. * parse-packet.c (parse_sig_subpkt2): New. * sign.c (sign_file): one-pass sigs are now emiited reverse. Preference data is considered when selecting the compress algo. Wed Jul 29 12:53:03 1998 Werner Koch (wk@isil.d.shuttle.de) * free-packet.c (copy_signature): New. * keygen.c (generate_subkeypair): rewritten * g10.c (aKeyadd): Removed option --add-key Mon Jul 27 10:37:28 1998 Werner Koch (wk@isil.d.shuttle.de) * seckey-cert.c (do_check): Additional check on cipher blocksize. (protect_secret_key): Ditto. * encr-data.c: Support for other blocksizes. * cipher.c (write_header): Ditto. Fri Jul 24 16:47:59 1998 Werner Koch (wk@isil.d.shuttle.de) * kbnode.c (insert_kbnode): Changed semantics and all callers. * keyedit.c : More or less a complete rewrite Wed Jul 22 17:10:04 1998 Werner Koch (wk@isil.d.shuttle.de) * build-packet.c (write_sign_packet_header): New. Tue Jul 21 14:37:09 1998 Werner Koch (wk@isil.d.shuttle.de) * import.c (import_one): Now creates a trustdb record. * g10.c (main): New command --check-trustdb Mon Jul 20 11:15:07 1998 Werner Koch (wk@isil.d.shuttle.de) * genkey.c (generate_keypair): Default key is now DSA with encryption only ElGamal subkey. Thu Jul 16 10:58:33 1998 Werner Koch (wk@isil.d.shuttle.de) * keyid.c (keyid_from_fingerprint): New. * getkey.c (get_pubkey_byfprint): New. Tue Jul 14 18:09:51 1998 Werner Koch (wk@isil.d.shuttle.de) * keyid.c (fingerprint_from_pk): Add argument and changed all callers. (fingerprint_from_sk): Ditto. Tue Jul 14 10:10:03 1998 Werner Koch (wk@isil.d.shuttle.de) * plaintext.c (handle_plaintext): Now returns create error if the file could not be created or the user responded not to overwrite the file. * mainproc.c (proc_plaintext): Tries again if the file could not be created to check the signature without output. * misc.c (disable_core_dumps): New. * g10.c (main): disable coredumps for gpg * g10.c (MAINTAINER_OPTIONS): New to disable some options Mon Jul 13 16:47:54 1998 Werner Koch (wk@isil.d.shuttle.de) * plaintext.c (hash_datafiles): New arg for better support of detached sigs. Changed all callers. * mainproc.c (proc_signature_packets): Ditto. * g10.c (main): New option "compress-sigs" * sig.c (sign_file): detached signatures are not anymore compressed unless the option --compress-sigs is used. Thu Jul 9 19:54:54 1998 Werner Koch (wk@isil.d.shuttle.de) * armor.c: Fixes to allow zero length cleartext signatures Thu Jul 9 14:52:47 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (build_list): Now drops setuid. (main): Changed the way keyrings and algorithms are registered . Wed Jul 8 14:17:30 1998 Werner Koch (wk@isil.d.shuttle.de) * packet.h (PKT_public_key): Add field keyid. * parse-packet.c (parse_key): Reset the above field. * keyid.c (keyid_from_pk): Use above field as cache. * tdbio.c, tdbio.h: New * trustdb.c: Moved some functions to tdbio.c. (print_keyid): New. * pkclist.c (check_signatures_trust): New. Wed Jul 8 10:45:28 1998 Werner Koch (wk@isil.d.shuttle.de) * plaintext.c (special_md_putc): New. (handle_plaintext): add clearsig argument * mainproc.c (proc_plaintext): detection of clearsig * sign.c (write_dased_escaped): Changed clearsig format Tue Jul 7 18:56:19 1998 Werner Koch (wk@isil.d.shuttle.de) * armor.c (find_header): Now makes sure that there is only one empty line for clearsigs, as this is what OP now says. Mon Jul 6 13:09:07 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (main): New option default-secret-key * getkey.c (get_seckey_byname): support for this option. Mon Jul 6 09:03:49 1998 Werner Koch (wk@isil.d.shuttle.de) * getkey.c (add_keyring): Keyrings are now added to end of the list of keyrings. The first added keyringwill be created. (add_secret_keyring): Likewise. * ringedit.c (add_keyblock_resource): Files are created here. * g10.c (aNOP): Removed * getkey.c (lookup): Add checking of usage for name lookups * packet.h (pubkey_usage): Add a field which may be used to store usage capabilities. * pkclist.c (build_pk_list): getkey now called with usage arg. * skclist.c (build_sk_list): Ditto. * sign.c (clearsign_file): Fixed "Hash:" headers Sat Jul 4 13:33:31 1998 Werner Koch (wk@isil.d.shuttle.de) * trustdb.c (list_ownertrust): New. * g10.c (aListOwnerTrust): New. * g10.c (def_pubkey_algo): Removed. * trustdb.c (verify_private_data): Removed and also the call to it. (sign_private_data): Removed. Fri Jul 3 13:26:10 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (aEditKey): was aEditSig. Changed usage msg. * keyedit.c: Done some i18n stuff. * g10.c (do_not_use_RSA): New. * sign.c (do_sign): Add call to above function. * encode.c (write_pubkey_enc_from_list): Ditto. Thu Jul 2 21:01:25 1998 Werner Koch (wk@isil.d.shuttle.de) * parse-packet.c: Now is able sto store data of unknown algorithms. * free-packet.c: Support for this. * build-packet.c: Can write data of packet with unknown algos. Thu Jul 2 11:46:36 1998 Werner Koch (wk@isil.d.shuttle.de) * parse-packet.c (parse): fixed 4 byte length header Wed Jul 1 12:36:55 1998 Werner Koch (wk@isil.d.shuttle.de) * packet.h (new_ctb): New field for some packets * build-packet.c (build_packet): Support for new_ctb * parse-packet.c (parse): Ditto. Mon Jun 29 12:54:45 1998 Werner Koch (wk@isil.d.shuttle.de) * packet.h: changed all "_cert" to "_key", "subcert" to "subkey". * free-packet.c (free_packet): Removed memory leak for subkeys. Sun Jun 28 18:32:27 1998 Werner Koch (wk@isil.d.shuttle.de) * import.c (import_keys): Renamed from import_pubkeys. (import_secret_one): New. * g10.c (aExportSecret): New. * export.c (export_seckeys): New. * parse-packet.c (parse_certificate): Cleaned up. (parse_packet): Trust packets are now considered as unknown. (parse_pubkey_warning): New. Fri Jun 26 10:37:35 1998 Werner Koch (wk@isil.d.shuttle.de) * keygen.c (has_invalid_email_chars): New. Wed Jun 24 16:40:22 1998 Werner Koch (wk@isil.d.shuttle.de) * armor.c (armor_filter): Now creates valid onepass_sig packets with all detected hash algorithms. * mainproc.c (proc_plaintext): Now uses the hash algos as specified in the onepass_sig packets (if there are any) Mon Jun 22 11:54:08 1998 Werner Koch (wk@isil.d.shuttle.de) * plaintext.c (handle_plaintext): add arg to disable outout * mainproc.c (proc_plaintext): disable output when in sigs_only mode. Thu Jun 18 13:17:27 1998 Werner Koch (wk@isil.d.shuttle.de) * keygen.c: Removed all rsa packet stuff, chnaged defaults for key generation. Sun Jun 14 21:28:31 1998 Werner Koch (wk@isil.d.shuttle.de) * misc.c (checksum_u16): Fixed a stupid bug which caused a wrong checksum calculation for the secret key protection and add a backward compatibility option. * g10.c (main): Add option --emulate-checksum-bug. Thu Jun 11 13:26:44 1998 Werner Koch (wk@isil.d.shuttle.de) * packet.h: Major changes to the structure of public key material which is now stored in an array and not anaymore in a union of algorithm specific structures. These is needed to make the system more extendable and makes a lot of stuff much simpler. Changed all over the system. * dsa.c, rsa.c, elg.c: Removed. Wed Jun 10 07:22:02 1998 Werner Koch,mobil,,, (wk@tobold) * g10.c ("load-extension"): New option. Mon Jun 8 22:23:37 1998 Werner Koch (wk@isil.d.shuttle.de) * seckey-cert.c (do_check): Removed cipher constants (protect_secret_key): Ditto. Fri May 29 10:00:28 1998 Werner Koch (wk@isil.d.shuttle.de) * trustdb.c (query_trust_info): New. * keylist.c (list_one): Add output of trust info * mainproc (list_node): ditto. * g10.c (main): full trustdb init if -with-colons and any of the key list modes. Thu May 28 10:34:42 1998 Werner Koch (wk@isil.d.shuttle.de) * status.c (STATUS_RSA_OR_IDEA): New. * sig-check.c (check_signature): Output special status message. * pubkey-enc.c (get_session_key): Ditto. * mainproc.c (check_sig_and_print): Changed format of output. * passpharse.c (passphrase_to_dek): Likewise. Wed May 27 13:46:48 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (aListSecretKeys): New option --list-secret-keys * keylist.c (std_key_list): Renamed to public_key_list. (secret_key_list): New (list_one, list_all): Add support for secret keys. * getkey.c (get_secret_keyring): New. * mainproc.c (list_node): Add option --with-colons for secret keys * sig-check.c (check_key_signature): detection of selfsigs * mainproc.c (list_node): fixed listing. * g10.c (aListSecretKeys): New option --always-trust * pkclist.c (do_we_trust): Override per option added * status.c (write_status_text): Add a prefix to every output line. Wed May 27 07:49:21 1998 Werner Koch (wk@isil.d.shuttle.de) * g10 (--compress-keys): New. * options.h (compress_keys): New. * export.c (export_pubkeys): Only compresses with the new option. Tue May 26 11:24:33 1998 Werner Koch (wk@isil.d.shuttle.de) * passphrase.c (get_last_passphrase): New (set_next_passphrase): New. (passphrase_to_dek): add support for the above functions. * keyedit.c (make_keysig_packet): Add sigclass 0x18, changed all callers due to a new argument. * keygen.c (write_keybinding): New (generate_subkeypair): Add functionality (ask_algo, ask_keysize, ask_valid_days): Broke out of generate_keypair (ask_user_id, ask_passphrase): Ditto. Thu May 21 11:26:13 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c,gpgd.c (main): Does now return an int, so that egcs does not complain. * armor.c (fake_packet): Removed erro message and add a noticed that this part should be fixed. * sign.c (sign_file): Compression now comes in front of encryption. * encode.c (encode_simple): Ditto. (encode_crypt): Ditto. Tue May 19 16:18:19 1998 Werner Koch (wk@isil.d.shuttle.de) * armor.c (fake_packet): Changed assertion to log_error Sat May 16 16:02:06 1998 Werner Koch (wk@isil.d.shuttle.de) * build-packet.c (build_packet): Add SUBKEY packets. Fri May 15 17:57:23 1998 Werner Koch (wk@isil.d.shuttle.de) * sign.c (hash_for): New and used in all places here. * main.h (DEFAULT_): new macros. * g10.c (opt.def_digest_algo): Now set to 0 * compress.c (init_compress): Add support for algo 1 * options.h (def_compress_algo): New * g10.c (main): New option --compress-algo Fri May 15 13:23:59 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (print_mds): New feature to print only one hash, chnaged formatting. Thu May 14 15:36:24 1998 Werner Koch (wk@isil.d.shuttle.de) * misc.c (trap_unaligned) [__alpha__]: New * g10.c (trap_unaligned): Add call to this to track down SIGBUS on Alphas (to avoid the slow emulation code). Wed May 13 11:48:27 1998 Werner Koch (wk@isil.d.shuttle.de) * build-packet.c (do_signature): Support for v4 pakets. * keyedit.c (make_keysig_packet): Ditto. * build-packet.c (build_sig_subpkt_from_sig): New. (build_sig_subpkt): New. * elg.c (g10_elg_sign): removed keyid_from_skc. * dsa.c (g10_dsa_sign): Ditto. * rsa.c (g10_rsa_sign): Ditto. * keyedit.c (make_keysig_packet): Add call to keyid_from_skc * sign.c (clearsign_file): Support for v4 signatures. (sign_file): Ditto. Wed May 6 09:31:24 1998 Werner Koch (wk@isil.d.shuttle.de) * parse-packet.c (do_parse): add support for 5 byte length leader. (parse_subpkt): Ditto. * build-packet.c (write_new_header): Ditto. * packet.h (SIGSUBPKT_): New constants. * parse-packet.c (parse_sig_subpkt): Changed name, made global, and arg to return packet length, chnaged all callers Tue May 5 22:11:59 1998 Werner Koch (wk@isil.d.shuttle.de) * keygen.c (gen_dsa): New. * build_packet.c (do_secret_cert): Support for DSA Mon May 4 19:01:25 1998 Werner Koch (wk@isil.d.shuttle.de) * compress.c: doubled buffer sizes * parse-packet.c (do_plaintext): now uses iobuf_read/write. Mon May 4 09:35:53 1998 Werner Koch (wk@isil.d.shuttle.de) * seskey.c (encode_md_value): Add optional argument hash_algo, changed all callers. * passphrase.c (make_dek_from_passphrase): Removed * (get_passhrase_hash): Changed name to passphrase_to_dek, add arg, changed all callers. * all: Introduced the new ELG identifier and added support for the encryption only one (which is okay to use by GNUPG for signatures). Sun May 3 17:50:26 1998 Werner Koch (wk@isil.d.shuttle.de) * packet.h (PKT_OLD_COMMENT): New name for type 16. * parse-packet.c (parse_comment): Now uses type 61 Fri May 1 12:44:39 1998 Werner Koch,mobil,,, (wk@tobold) * packet.h (count): Chnaged s2k count from byte to u32. * seckey-cert.c (do_check): Changed s2k algo 3 to 4, changed reading of count. * build-packet.c (do_secret_cert): ditto. * parse-packet.c (parse_certificate): ditto. * parse-packet.c (parse_symkeyenc): New. * build-packet.c (do_symkey_enc): New. Thu Apr 30 16:33:34 1998 Werner Koch (wk@isil.d.shuttle.de) * sign.c (clearsign_file): Fixed "Hash: " armor line. Tue Apr 28 14:27:42 1998 Werner Koch (wk@isil.d.shuttle.de) * parse-packet.c (parse_subpkt): Some new types. Mon Apr 27 12:53:59 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (main): Add option --skip-verify. * mainproc.c (check_sig_and_print): Ditto. * g10.c (print_mds): Add output for Tiger. * sign.c (sign_file): Now uses partial length headers if used in canonical textmode (kludge to fix a bug). * parse-packet.c (parse_certificate): Changed BLOWFISH id. * pubkey-enc.c (get_session_key): Ditto. * seskey.c (make_session_key): Ditto. * seckey-cert.c (protect_secret_key,do_check): Add BLOWFISH160. Fri Apr 24 17:38:48 1998 Werner Koch,mobil,,, (wk@tobold) * sig-check.c (check_key_signature): Add sig-class 0x14..0x17 * keyedit.c (sign-key): Some changes to start with support of the above new sig-classes. Wed Apr 22 09:01:57 1998 Werner Koch,mobil,,, (wk@tobold) * getkey.c (compare_name): add email matching Tue Apr 21 16:17:12 1998 Werner Koch,mobil,,, (wk@tobold) * armor.c (armor_filter): fixed missing last LF before CSUM. Thu Apr 9 11:35:22 1998 Werner Koch (wk@isil.d.shuttle.de) * seckey-cert.c (do_check): New; combines all the check functions into one. * sign.c: removed all key management functions * keyedit.c: New. Thu Apr 9 09:49:36 1998 Werner Koch (wk@isil.d.shuttle.de) * import.c (chk_self_sigs): Changed an error message. Wed Apr 8 16:19:39 1998 Werner Koch (wk@isil.d.shuttle.de) * packet.h: packet structs now uses structs from the pubkey, removed all copy operations from packet to pubkey structs. Wed Apr 8 13:40:33 1998 Werner Koch (wk@isil.d.shuttle.de) * trustdb.c (verify_own_certs): Fixed "public key not found". * getkey.c (key_byname): New, combines public and secret key search. * pkclist.c (build_pkc_list): Add new arg usage, changed all callers. * skclist.c (build_skc_list): Likewise. * ringedit.c (find_keyblock, keyring_search2): Removed. Wed Apr 8 09:47:21 1998 Werner Koch (wk@isil.d.shuttle.de) * sig-check.c (do_check): Applied small fix from Ulf Möller. Tue Apr 7 19:28:07 1998 Werner Koch (wk@isil.d.shuttle.de) * cipher.c, encr-data.c, seckey-cert.c: Now uses cipher_xxxx functions instead of blowfish_xxx or cast_xxx Tue Apr 7 11:04:02 1998 Werner Koch (wk@isil.d.shuttle.de) * Makefile.am (g10maint.o): Changed the way it is created. Mon Apr 6 11:17:08 1998 Werner Koch (wk@isil.d.shuttle.de) * misc.c: New. * keygen.c (checksum,checksum_u16,checksum_mpi): Moved to misc.c * seckey-cert.c: Kludge for wrong ELG checksum implementation. Sat Apr 4 20:07:01 1998 Werner Koch (wk@isil.d.shuttle.de) * cipher.c (cipher_filter): Support for CAST5 * encr-data.c (decode_filter): Ditto. (decrypt_data): Ditto. * seskey.c (make_session_key): Ditto. * seckey-cert.c (check_elg, check_dsa): Ditto, (protect_secret_key): Ditto. * pubkey-enc.c (get_session_key): Ditto. * passphrase.c (hash_passphrase): Ditto. Thu Apr 2 20:22:35 1998 Werner Koch (wk@isil.d.shuttle.de) * gpgd.c: New Thu Apr 2 10:38:16 1998 Werner Koch (wk@isil.d.shuttle.de) * keygen.c (generate_keypair): Add valid_days stuff. * trustdb.c (check_trust): Add check for valid_days. Wed Apr 1 16:15:58 1998 Werner Koch (wk@isil.d.shuttle.de) * keygen.c (generate_keypair): Addional question whether the selected large keysize is really needed. Wed Apr 1 15:56:33 1998 Werner Koch (wk@isil.d.shuttle.de) * seckey-cert.c (protect_secret_key): merged protect_xxx to here. Wed Apr 1 10:34:46 1998 Werner Koch (wk@isil.d.shuttle.de) * Makefile.am (g10maint.c): Changed creation rule, so that it works on FreeBSD (missing CFLAGS). * parse-packet.c (parse_subkey): Removed. Thu Mar 19 15:22:36 1998 Werner Koch (wk@isil.d.shuttle.de) * ringedit.c (keyring_enum): Fixed problem with reading too many packets. Add support to read secret keyrings. * getkey.c (scan_keyring): Removed (lookup): New to replace scan_keyring. (scan_secret_keyring): Removed. (lookup_skc): New. Wed Mar 18 11:47:34 1998 Werner Koch (wk@isil.d.shuttle.de) * ringedit.c (enum_keyblocks): New read mode 11. * keyid.c (elg_fingerprint_md): New and changed all other functions to call this if the packet version is 4 or above. Tue Mar 17 20:46:16 1998 Werner Koch (wk@isil.d.shuttle.de) * parse-packet.c (parse_certificate): Add listing support for subkeys. Tue Mar 17 20:32:22 1998 Werner Koch (wk@isil.d.shuttle.de) * armor.c (is_armored): Allow marker packet. Thu Mar 12 13:36:49 1998 Werner Koch (wk@isil.d.shuttle.de) * trustdb.c (check_trust): Checks timestamp of pubkey. * sig-check. (do_check): Compares timestamps. Tue Mar 10 17:01:56 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (main): Add call to init_signals. * signal.c: New. Mon Mar 9 12:43:42 1998 Werner Koch (wk@isil.d.shuttle.de) * dsa.c: New * packet.h, free-packet.c, parse-packet.c : Add support for DSA * sig-check.c, getkey.c, keyid.c, ringedit.c: Ditto. * seckey-cert.c: Ditto. * packet.h : Moved .digest_algo of signature packets to outer structure. Changed all references Sun Mar 8 13:06:42 1998 Werner Koch (wk@isil.d.shuttle.de) * openfile.c : Support for stdout filename "-". * mainproc.c (check_sig_and_print): Enhanced status output: * status.c (write_status_text): New. Fri Mar 6 16:10:54 1998 Werner Koch (wk@isil.d.shuttle.de) * kbnode.c (clone_kbnode): Fixed private_flag. * mainproc.c (list_node): Output of string "Revoked" as user-id. Fri Mar 6 14:26:39 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (main): Add userids to "-kv" and cleaned up this stuff. Fri Mar 6 12:45:58 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (main): Changed semantics of the list-... commands and added a new one. Removed option "-d" * decrypt.c: New. * trustdb.c (init_trustdb): Autocreate directory only if it ends in "/.gnupg". Thu Mar 5 12:12:11 1998 Werner Koch (wk@isil.d.shuttle.de) * mainproc.c (do_proc_packets): New. Common part of proc_packet. (proc_signature_packets): special version to handle signature data. * verify.c: New. * g10.c (aVerify): New. * plaintext.c (hash_datafiles): New. * compress.c (handle_compressed): Add callback arg, changed caller. Thu Mar 5 10:20:06 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c: Is nom the common source for gpg and gpgm * g10maint.c: Removed * Makefile.am: Add rule to build g10maint.c Thu Mar 5 08:43:59 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (main): Changed the way clear text sigs are faked. Wed Mar 4 19:47:37 1998 Werner Koch (wk@isil.d.shuttle.de) * g10maint.c (aMuttKeyList): New * keylist.c: New. Wed Mar 4 17:20:33 1998 Werner Koch (wk@isil.d.shuttle.de) * getkey.c (get_pubkey_byname): Kludge to allow 0x prefix. Tue Mar 3 13:46:55 1998 Werner Koch (wk@isil.d.shuttle.de) * g10maint.c (main): New option --gen-random. Tue Mar 3 09:50:08 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (aDeleteSecretKey): New. (aEditSig): Add option "--edit-key" as synonym for "--edit-sig". (aDeleteSecretKey): New. * getkey.c (seckey_available): New. * sign.c (delete_key): Enhanced to delete secret keys, changed all callers. Mon Mar 2 21:23:48 1998 Werner Koch (wk@isil.d.shuttle.de) * pkc_list.c (build_pkc_list): Add interactive input of user ID. Mon Mar 2 20:54:05 1998 Werner Koch (wk@isil.d.shuttle.de) * pkclist.c (do_we_trust_pre): New. (add_ownertrust): Add message. * trustdb.c (enum_trust_web): Quick fix. Mon Mar 2 13:50:53 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (main): New action aDeleteKey * sign.c (delete_key): New. Sun Mar 1 16:38:58 1998 Werner Koch (wk@isil.d.shuttle.de) * trustdb.c (do_check): No returns TRUST_UNDEFINED instead of eof error. Fri Feb 27 18:14:03 1998 Werner Koch (wk@isil.d.shuttle.de) * armor.c (find_header): Removed trailing CR on headers. Fri Feb 27 18:02:48 1998 Werner Koch (wk@isil.d.shuttle.de) * ringedit.c (keyring_search) [MINGW32]: Open and close file here because rename does not work on open files. Chnaged callers. Fri Feb 27 16:43:11 1998 Werner Koch (wk@isil.d.shuttle.de) * sig-check.c (do_check): Add an md_enable. * mainproc.c (do_check_sig): Use md_open in case of detached sig (proc_tree): Take detached sigs into account. Fri Feb 27 15:22:46 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (main): Make use of GNUPGHOME envvar. * g10main.c (main): Ditto. Wed Feb 25 11:40:04 1998 Werner Koch (wk@isil.d.shuttle.de) * plaintext.c (ask_for_detached_datafile): add opt.verbose to info output. * openfile.c (open_sigfile): Try also name ending in ".asc" Wed Feb 25 08:41:00 1998 Werner Koch (wk@isil.d.shuttle.de) * keygen.c (generate_keypair): Fixed memory overflow. Tue Feb 24 15:51:55 1998 Werner Koch (wk@isil.d.shuttle.de) * parse-packet.c (parse_certificate): Support for S2K. * build-packet.c (do_secret_cert): Ditto. * keygen.c (gen_elg): Ditto. * seckey-cert.c (check_elg): Ditto (protect_elg): Ditto. * sign.c (chnage_passphrase): Ditto. * passphrase.c (get_passphrase_hash): Support for a salt and changed all callers. (make_dek_from_passphrase): Ditto. Tue Feb 24 12:30:56 1998 Werner Koch (wk@isil.d.shuttle.de) * build-packet.c (hash_public_cert): Disabled debug output. Fri Feb 20 17:22:28 1998 Werner Koch (wk@isil.d.shuttle.de) * trustdb.c (init_trustdb) [MINGW32]: Removed 2nd mkdir arg. (keyring_copy) [MINGW32]: Add a remove prior to the renames. Wed Feb 18 18:39:02 1998 Werner Koch (wk@isil.d.shuttle.de) * Makefile.am (OMIT_DEPENDENCIES): New. * rsa.c: Replaced log_bug by BUG. Wed Feb 18 13:35:58 1998 Werner Koch (wk@isil.d.shuttle.de) * mainproc.c (do_check_sig): Now uses hash_public_cert. * parse-packet.c (parse_certificate): Removed hashing. * packet.h (public_cert): Removed hash variable. * free-packet.c (copy_public_cert, free_public_cert): Likewise. * sig-check.c (check_key_signatures): Changed semantics. Wed Feb 18 12:11:28 1998 Werner Koch (wk@isil.d.shuttle.de) * trustdb.c (do_check): Add handling for revocation certificates. (build_sigrecs): Ditto. (check_sigs): Ditto. Wed Feb 18 09:31:04 1998 Werner Koch (wk@isil.d.shuttle.de) * armor.c (armor_filter): Add afx->hdrlines. * revoke.c (gen_revoke): Add comment line. * dearmor.c (enarmor_file): Ditto. * sig-check.c (check_key_signature): Add handling for class 0x20. * mainproc.c : Ditto. Tue Feb 17 21:24:17 1998 Werner Koch (wk@isil.d.shuttle.de) * armor.c : Add header lines "...ARMORED FILE .." * dearmor.c (enarmor_file): New. * g10maint.c (main): New option "--enarmor" Tue Feb 17 19:03:33 1998 Werner Koch (wk@isil.d.shuttle.de) * mainproc.c : Changed a lot, because the packets are now stored a simple linlked list and not anymore in a complicatd tree structure. Tue Feb 17 10:14:48 1998 Werner Koch (wk@isil.d.shuttle.de) * free_packet.c (cmp_public_certs): New. (cmp_user_ids): New. * kbnode.c (clone_kbnode): New. (release_kbnode): Add clone support. * ringedit.c (find_keyblock_bypkc): New. * sign.c (remove_keysigs): Self signatures are now skipped, changed arguments and all callers. * import.c : Add functionality. Tue Feb 17 09:31:40 1998 Werner Koch (wk@isil.d.shuttle.de) * options.h (homedir): New option. * g10.c, g10maint.c, getkey.c, keygen.c, trustdb.c (opt.homedir): New. * trustdb.c (init_trustdb): mkdir for hoem directory (sign_private_data): Renamed "sig" to "g10.sig" Mon Feb 16 20:02:03 1998 Werner Koch (wk@isil.d.shuttle.de) * kbnode.c (commit_kbnode): New. (delete_kbnode): removed unused first arg. Changed all Callers. * ringedit.c (keyblock_resource_name): New. (get_keyblock_handle): NULL for filename returns default resource. Mon Feb 16 19:38:48 1998 Werner Koch (wk@isil.d.shuttle.de) * sig-check.s (check_key_signature): Now uses the supplied public key to check the signature and not any more the one from the getkey.c (do_check): New. (check_signature): Most work moved to do_check. Mon Feb 16 14:48:57 1998 Werner Koch (wk@isil.d.shuttle.de) * armor.c (find_header): Fixed another bug. Mon Feb 16 12:18:34 1998 Werner Koch (wk@isil.d.shuttle.de) * getkey.c (scan_keyring): Add handling of compressed keyrings. Mon Feb 16 10:44:51 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c, g10maint.c (strusage): Rewrote. (build_list): New Mon Feb 16 08:58:41 1998 Werner Koch (wk@isil.d.shuttle.de) * armor.c (use_armor): New. Sat Feb 14 14:30:57 1998 Werner Koch (wk@isil.d.shuttle.de) * mainproc.c (proc_tree): Sigclass fix. Sat Feb 14 14:16:33 1998 Werner Koch (wk@isil.d.shuttle.de) * armor.c (armor_filter): Changed version and comment string. * encode.c, sign.c, keygen.c: Changed all comment packet strings. Sat Feb 14 12:39:24 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (aGenRevoke): New command. * revoke.c: New. * sign.c (make_keysig_packet): Add support for sigclass 0x20. Fri Feb 13 20:18:14 1998 Werner Koch (wk@isil.d.shuttle.de) * ringedit.c (enum_keyblocks, keyring_enum): New. Fri Feb 13 19:33:40 1998 Werner Koch (wk@isil.d.shuttle.de) * export.c: Add functionality. * keygen.c (generate_keypair): Moved the leading comment behind the key packet. * kbnode.c (walk_kbnode): Fixed. * g10.c (main): listing armored keys now work. Fri Feb 13 16:17:43 1998 Werner Koch (wk@isil.d.shuttle.de) * parse-packet.c (parse_publickey, parse_signature): Fixed calls to mpi_read used for ELG b. Fri Feb 13 15:13:23 1998 Werner Koch (wk@isil.d.shuttle.de) * g10.c (main): changed formatting of help output. Thu Feb 12 22:24:42 1998 Werner Koch (wk@frodo) * pubkey-enc.c (get_session_key): rewritten diff --git a/g10/helptext.c b/g10/helptext.c index d34a3a9ac..e6957da3b 100644 --- a/g10/helptext.c +++ b/g10/helptext.c @@ -1,252 +1,252 @@ /* helptext.c - English help texts * Copyright (C) 1998 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 #include #include #include #include "util.h" #include "ttyio.h" #include "main.h" #include "i18n.h" /**************** * These helptexts are used for the "online" help feature. We use * a key consisting of words and dots. Because the lookup is only * done in an interactive mode on a user request (when she enters a "?" * as response to a prompt) we can use a simple search through the list. * * Mini glossary: * * "user ID", "trustdb", "NOTE" and "WARNING". */ static struct helptexts { const char *key; const char *help; } helptexts[] = { /* begin of list */ { "edit_ownertrust.value", N_( "It's up to you to assign a value here; this value will never be exported\n" "to any 3rd party. We need it to implement the web-of-trust; it has nothing\n" "to do with the (implicitly created) web-of-certificates." )}, { "revoked_key.override", N_( "If you want to use this revoked key anyway, answer \"yes\"." )}, { "untrusted_key.override", N_( "If you want to use this untrusted key anyway, answer \"yes\"." )}, { "pklist.user_id.enter", N_( "Enter the user id of the addressee to whom you want to send the message." )}, { "keygen.algo", N_( "Select the algorithm to use.\n" "\n" "DSA (aka DSS) is the digital signature algorithm which can only be used\n" "for signatures. This is the suggested algorithm because verification of\n" "DSA signatures are much faster than those of ElGamal.\n" "\n" "ElGamal is an algorithm which can be used for signatures and encryption.\n" "OpenPGP distinguishs between two flavors of this algorithms: an encrypt only\n" "and a sign+encrypt; actually it is the same, but some parameters must be\n" "selected in a special way to create a safe key for signatures: this program\n" "does this but other OpenPGP implementations are not required to understand\n" "the signature+encryption flavor.\n" "\n" "The first (primary) key must always be a key which is capable of signing;\n" "this is the reason why the encryption only ElGamal key is not available in\n" "this menu." )}, { "keygen.algo.elg_se", N_( "Although these keys are defined in RFC2440 they are not suggested\n" "because they are not supported by all programs and signatures created\n" "with them are quite large and very slow to verify." )}, { "keygen.size", N_( "Enter the size of the key" )}, { "keygen.size.huge.okay", N_( "Answer \"yes\" or \"no\"" )}, { "keygen.size.large.okay", N_( "Answer \"yes\" or \"no\"" )}, { "keygen.valid", N_( - "Enter the required value as shown in the pronpt.\n" + "Enter the required value as shown in the prompt.\n" "It is possible to enter a ISO date (YYYY-MM-DD) but you won't\n" "get a good error response - instead the system tries to interpret\n" "the given value as an interval." )}, { "keygen.valid.okay", N_( "Answer \"yes\" or \"no\"" )}, { "keygen.name", N_( "Enter the name of the key holder" )}, { "keygen.email", N_( "please enter an optional but highly suggested email address" )}, { "keygen.comment", N_( "Please enter an optional comment" )}, { "keygen.userid.cmd", N_( "" "N to change the name.\n" "C to change the comment.\n" "E to change the email address.\n" "O to continue with key generation.\n" "Q to to quit the key generation." )}, { "keygen.sub.okay", N_( "Answer \"yes\" (or just \"y\") if it is okay to generate the sub key." )}, { "sign_uid.okay", N_( "Answer \"yes\" or \"no\"" )}, { "change_passwd.empty.okay", N_( "Answer \"yes\" or \"no\"" )}, { "keyedit.save.okay", N_( "Answer \"yes\" or \"no\"" )}, { "keyedit.cancel.okay", N_( "Answer \"yes\" or \"no\"" )}, { "keyedit.sign_all.okay", N_( "Answer \"yes\" is you want to sign ALL the user IDs" )}, { "keyedit.remove.uid.okay", N_( "Answer \"yes\" if you really want to delete this user ID.\n" "All certificates are then also lost!" )}, { "keyedit.remove.subkey.okay", N_( "Answer \"yes\" if it is okay to delete the subkey" )}, { "keyedit.delsig.valid", N_( "This is a valid signature on the key; you normally don't want\n" - "to delete this signature may be important to establish a trust\n" - "connection to the key or another key certified by this key." + "to delete this signature because it may be important to establish a\n" + "trust connection to the key or another key certified by this key." )}, { "keyedit.delsig.unknown", N_( "This signature can't be checked because you don't have the\n" "corresponding key. You should postpone its deletion until you\n" "know which key was used because this signing key might establish" "a trust connection through another already certified key." )}, { "keyedit.delsig.invalid", N_( "The signature is not valid. It does make sense to remove it from\n" "your keyring." )}, { "keyedit.delsig.selfsig", N_( "This is a signature which binds the user ID to the key. It is\n" "usually not a good idea to remove such a signature. Actually\n" "GnuPG might not be able to use this key anymore. So do this\n" "only if this self-signature is for some reason not valid and\n" "a second one is available." )}, { "passphrase.enter", N_( "" "Please enter the passhrase; this is a secret sentence \n" " Blurb, blurb,.... " )}, { "passphrase.repeat", N_( "Please repeat the last passphrase, so you are sure what you typed in." )}, { "detached_signature.filename", N_( "Give the name fo the file to which the signature applies" )}, /* openfile.c (overwrite_filep) */ { "openfile.overwrite.okay", N_( "Answer \"yes\" if it is okay to overwrite the file" )}, /* openfile.c (ask_outfile_name) */ { "openfile.askoutname", N_( "Please enter a new filename. If you just hit RETURN the default\n" "file (which is shown in brackets) will be used." )}, /* end of list */ { NULL, NULL } }; void display_online_help( const char *keyword ) { tty_kill_prompt(); if( !keyword ) tty_printf(_("No help available") ); else { const char *p; int i; for(i=0; (p=helptexts[i].key) && strcmp( p, keyword ); i++ ) ; if( !p || !*helptexts[i].help ) tty_printf(_("No help available for `%s'"), keyword ); else tty_printf("%s", _(helptexts[i].help) ); } tty_printf("\n"); } diff --git a/g10/keyedit.c b/g10/keyedit.c index db5c0050f..d54e90d6c 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -1,1923 +1,1923 @@ /* keyedit.c - keyedit stuff * Copyright (C) 1998, 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 */ #include #include #include #include #include #include #include #include "options.h" #include "packet.h" #include "errors.h" #include "iobuf.h" #include "keydb.h" #include "memory.h" #include "util.h" #include "main.h" #include "trustdb.h" #include "filter.h" #include "ttyio.h" #include "status.h" #include "i18n.h" static void show_prefs( KBNODE keyblock, PKT_user_id *uid ); static void show_key_with_all_names( KBNODE keyblock, int only_marked, int with_fpr, int with_subkeys, int with_prefs ); static void show_key_and_fingerprint( KBNODE keyblock ); static void show_fingerprint( PKT_public_key *pk ); static int menu_adduid( KBNODE keyblock, KBNODE sec_keyblock ); static void menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock ); static int menu_delsig( KBNODE pub_keyblock ); static void menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock ); static int menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock ); static int menu_select_uid( KBNODE keyblock, int idx ); static int menu_select_key( KBNODE keyblock, int idx ); static int count_uids( KBNODE keyblock ); static int count_uids_with_flag( KBNODE keyblock, unsigned flag ); static int count_keys_with_flag( KBNODE keyblock, unsigned flag ); static int count_selected_uids( KBNODE keyblock ); static int count_selected_keys( KBNODE keyblock ); static int menu_revsig( KBNODE keyblock ); static int menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock ); static int enable_disable_key( KBNODE keyblock, int disable ); #define CONTROL_D ('D' - 'A' + 1) #define NODFLG_BADSIG (1<<0) /* bad signature */ #define NODFLG_NOKEY (1<<1) /* no public key */ #define NODFLG_SIGERR (1<<2) /* other sig error */ #define NODFLG_MARK_A (1<<4) /* temporary mark */ #define NODFLG_SELUID (1<<8) /* indicate the selected userid */ #define NODFLG_SELKEY (1<<9) /* indicate the selected key */ #define NODFLG_SELSIG (1<<10) /* indicate a selected signature */ struct sign_uid_attrib { int non_exportable; }; static int get_keyblock_byname( KBNODE *keyblock, KBPOS *kbpos, const char *username ) { int rc; *keyblock = NULL; /* search the userid */ rc = find_keyblock_byname( kbpos, username ); if( rc ) { log_error(_("%s: user not found\n"), username ); return rc; } /* read the keyblock */ rc = read_keyblock( kbpos, keyblock ); if( rc ) log_error("%s: keyblock read problem: %s\n", username, g10_errstr(rc)); else merge_keys_and_selfsig( *keyblock ); return rc; } /**************** * Print information about a signature, chek it and return true * if the signature is okay. NODE must be a signature packet. */ static int print_and_check_one_sig( KBNODE keyblock, KBNODE node, int *inv_sigs, int *no_key, int *oth_err, int *is_selfsig, int print_without_key ) { PKT_signature *sig = node->pkt->pkt.signature; int rc, sigrc; int is_rev = sig->sig_class == 0x30; switch( (rc = check_key_signature( keyblock, node, is_selfsig)) ) { case 0: node->flag &= ~(NODFLG_BADSIG|NODFLG_NOKEY|NODFLG_SIGERR); sigrc = '!'; break; case G10ERR_BAD_SIGN: node->flag = NODFLG_BADSIG; sigrc = '-'; if( inv_sigs ) ++*inv_sigs; break; case G10ERR_NO_PUBKEY: node->flag = NODFLG_NOKEY; sigrc = '?'; if( no_key ) ++*no_key; break; default: node->flag = NODFLG_SIGERR; sigrc = '%'; if( oth_err ) ++*oth_err; break; } if( sigrc != '?' || print_without_key ) { tty_printf("%s%c %08lX %s ", is_rev? "rev":"sig", sigrc, sig->keyid[1], datestr_from_sig(sig)); if( sigrc == '%' ) tty_printf("[%s] ", g10_errstr(rc) ); else if( sigrc == '?' ) ; else if( *is_selfsig ) { tty_printf( is_rev? _("[revocation]") : _("[self-signature]") ); } else { size_t n; char *p = get_user_id( sig->keyid, &n ); - tty_print_string( p, n > 40? 40 : n ); + tty_print_utf8_string( p, n > 40? 40 : n ); m_free(p); } tty_printf("\n"); } return (sigrc == '!'); } /**************** * Check the keysigs and set the flags to indicate errors. * Returns true if error found. */ static int check_all_keysigs( KBNODE keyblock, int only_selected ) { KBNODE kbctx; KBNODE node; int inv_sigs = 0; int no_key = 0; int oth_err = 0; int has_selfsig = 0; int mis_selfsig = 0; int selected = !only_selected; int anyuid = 0; for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) { if( node->pkt->pkttype == PKT_USER_ID ) { PKT_user_id *uid = node->pkt->pkt.user_id; if( only_selected ) selected = (node->flag & NODFLG_SELUID); if( selected ) { tty_printf("uid "); - tty_print_string( uid->name, uid->len ); + tty_print_utf8_string( uid->name, uid->len ); tty_printf("\n"); if( anyuid && !has_selfsig ) mis_selfsig++; has_selfsig = 0; anyuid = 1; } } else if( selected && node->pkt->pkttype == PKT_SIGNATURE && ( (node->pkt->pkt.signature->sig_class&~3) == 0x10 || node->pkt->pkt.signature->sig_class == 0x30 ) ) { int selfsig; if( print_and_check_one_sig( keyblock, node, &inv_sigs, &no_key, &oth_err, &selfsig, 0 ) ) { if( selfsig ) has_selfsig = 1; } /* Hmmm: should we update the trustdb here? */ } } if( !has_selfsig ) mis_selfsig++; if( inv_sigs == 1 ) tty_printf(_("1 bad signature\n"), inv_sigs ); else if( inv_sigs ) tty_printf(_("%d bad signatures\n"), inv_sigs ); if( no_key == 1 ) tty_printf(_("1 signature not checked due to a missing key\n") ); else if( no_key ) tty_printf(_("%d signatures not checked due to missing keys\n"), no_key ); if( oth_err == 1 ) tty_printf(_("1 signature not checked due to an error\n") ); else if( oth_err ) tty_printf(_("%d signatures not checked due to errors\n"), oth_err ); if( mis_selfsig == 1 ) tty_printf(_("1 user id without valid self-signature detected\n")); else if( mis_selfsig ) tty_printf(_("%d user ids without valid self-signatures detected\n"), mis_selfsig); return inv_sigs || no_key || oth_err || mis_selfsig; } int sign_uid_mk_attrib( PKT_signature *sig, void *opaque ) { struct sign_uid_attrib *attrib = opaque; byte buf[8]; if( attrib->non_exportable ) { buf[0] = 0; /* not exportable */ build_sig_subpkt( sig, SIGSUBPKT_EXPORTABLE, buf, 1 ); } return 0; } /**************** * Loop over all locusr and and sign the uids after asking. * If no user id is marked, all user ids will be signed; * if some user_ids are marked those will be signed. */ static int sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, int local ) { int rc = 0; SK_LIST sk_list = NULL; SK_LIST sk_rover = NULL; PKT_secret_key *sk = NULL; KBNODE node, uidnode; PKT_public_key *primary_pk=NULL; int select_all = !count_selected_uids(keyblock); int upd_trust = 0; /* build a list of all signators */ rc=build_sk_list( locusr, &sk_list, 0, 1 ); if( rc ) goto leave; /* loop over all signaturs */ for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) { u32 sk_keyid[2]; size_t n; char *p; /* we have to use a copy of the sk, because make_keysig_packet * may remove the protection from sk and if we did other * changes to the secret key, we would save the unprotected * version */ if( sk ) free_secret_key(sk); sk = copy_secret_key( NULL, sk_rover->sk ); keyid_from_sk( sk, sk_keyid ); /* set mark A for all selected user ids */ for( node=keyblock; node; node = node->next ) { if( select_all || (node->flag & NODFLG_SELUID) ) node->flag |= NODFLG_MARK_A; else node->flag &= ~NODFLG_MARK_A; } /* reset mark for uids which are already signed */ uidnode = NULL; for( node=keyblock; node; node = node->next ) { if( node->pkt->pkttype == PKT_USER_ID ) { uidnode = (node->flag & NODFLG_MARK_A)? node : NULL; } else if( uidnode && node->pkt->pkttype == PKT_SIGNATURE && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) { if( sk_keyid[0] == node->pkt->pkt.signature->keyid[0] && sk_keyid[1] == node->pkt->pkt.signature->keyid[1] ) { /* Fixme: see whether there is a revocation in which * case we should allow to sign it again. */ tty_printf(_("Already signed by key %08lX\n"), (ulong)sk_keyid[1] ); uidnode->flag &= ~NODFLG_MARK_A; /* remove mark */ } } } /* check whether any uids are left for signing */ if( !count_uids_with_flag(keyblock, NODFLG_MARK_A) ) { tty_printf(_("Nothing to sign with key %08lX\n"), (ulong)sk_keyid[1] ); continue; } /* Ask whether we really should sign these user id(s) */ tty_printf("\n"); show_key_with_all_names( keyblock, 1, 1, 0, 0 ); tty_printf("\n"); tty_printf(_( "Are you really sure that you want to sign this key\n" "with your key: \"")); p = get_user_id( sk_keyid, &n ); - tty_print_string( p, n ); + tty_print_utf8_string( p, n ); m_free(p); p = NULL; tty_printf("\"\n\n"); if( local ) tty_printf( _("The signature will be marked as non-exportable.\n\n")); if( opt.batch && opt.answer_yes ) ; else if( !cpr_get_answer_is_yes("sign_uid.okay", _("Really sign? ")) ) continue; /* now we can sign the user ids */ reloop: /* (must use this, because we are modifing the list) */ primary_pk = NULL; for( node=keyblock; node; node = node->next ) { if( node->pkt->pkttype == PKT_PUBLIC_KEY ) primary_pk = node->pkt->pkt.public_key; else if( node->pkt->pkttype == PKT_USER_ID && (node->flag & NODFLG_MARK_A) ) { PACKET *pkt; PKT_signature *sig; struct sign_uid_attrib attrib; assert( primary_pk ); memset( &attrib, 0, sizeof attrib ); attrib.non_exportable = local; node->flag &= ~NODFLG_MARK_A; rc = make_keysig_packet( &sig, primary_pk, node->pkt->pkt.user_id, NULL, sk, 0x10, 0, sign_uid_mk_attrib, &attrib ); if( rc ) { log_error(_("signing failed: %s\n"), g10_errstr(rc)); goto leave; } *ret_modified = 1; /* we changed the keyblock */ upd_trust = 1; pkt = m_alloc_clear( sizeof *pkt ); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; insert_kbnode( node, new_kbnode(pkt), PKT_SIGNATURE ); goto reloop; } } } /* end loop over signators */ if( upd_trust && primary_pk ) { rc = clear_trust_checked_flag( primary_pk ); } leave: release_sk_list( sk_list ); if( sk ) free_secret_key(sk); return rc; } /**************** * Change the passphrase of the primary and all secondary keys. * We use only one passphrase for all keys. */ static int change_passphrase( KBNODE keyblock ) { int rc = 0; int changed=0; KBNODE node; PKT_secret_key *sk; char *passphrase = NULL; node = find_kbnode( keyblock, PKT_SECRET_KEY ); if( !node ) { log_error("Oops; secret key not found anymore!\n"); goto leave; } sk = node->pkt->pkt.secret_key; switch( is_secret_key_protected( sk ) ) { case -1: rc = G10ERR_PUBKEY_ALGO; break; case 0: tty_printf(_("This key is not protected.\n")); break; default: tty_printf(_("Key is protected.\n")); rc = check_secret_key( sk, 0 ); if( !rc ) passphrase = get_last_passphrase(); break; } /* unprotect all subkeys (use the supplied passphrase or ask)*/ for(node=keyblock; !rc && node; node = node->next ) { if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) { PKT_secret_key *subsk = node->pkt->pkt.secret_key; set_next_passphrase( passphrase ); rc = check_secret_key( subsk, 0 ); } } if( rc ) tty_printf(_("Can't edit this key: %s\n"), g10_errstr(rc)); else { DEK *dek = NULL; STRING2KEY *s2k = m_alloc_secure( sizeof *s2k ); tty_printf(_("Enter the new passphrase for this secret key.\n\n") ); set_next_passphrase( NULL ); for(;;) { s2k->mode = opt.s2k_mode; s2k->hash_algo = opt.s2k_digest_algo; dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2 ); if( !dek ) { tty_printf(_("passphrase not correctly repeated; try again.\n")); } else if( !dek->keylen ) { rc = 0; tty_printf(_( "You don't want a passphrase -" " this is probably a *bad* idea!\n\n")); if( cpr_get_answer_is_yes("change_passwd.empty.okay", _("Do you really want to do this? "))) changed++; break; } else { /* okay */ sk->protect.algo = dek->algo; sk->protect.s2k = *s2k; rc = protect_secret_key( sk, dek ); for(node=keyblock; !rc && node; node = node->next ) { if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) { PKT_secret_key *subsk = node->pkt->pkt.secret_key; subsk->protect.algo = dek->algo; subsk->protect.s2k = *s2k; rc = protect_secret_key( subsk, dek ); } } if( rc ) log_error("protect_secret_key failed: %s\n", g10_errstr(rc) ); else changed++; break; } } m_free(s2k); m_free(dek); } leave: m_free( passphrase ); set_next_passphrase( NULL ); return changed && !rc; } /**************** * There are some keys out (due to a bug in gnupg), where the sequence * of the packets is wrong. This function fixes that. * Returns: true if the keyblock has been fixed. * * Note: This function does not work if there is more than one user ID. */ static int fix_keyblock( KBNODE keyblock ) { KBNODE node, last, subkey; int fixed=0; /* locate key signatures of class 0x10..0x13 behind sub key packets */ for( subkey=last=NULL, node = keyblock; node; last=node, node = node->next ) { switch( node->pkt->pkttype ) { case PKT_PUBLIC_SUBKEY: case PKT_SECRET_SUBKEY: if( !subkey ) subkey = last; /* actually it is the one before the subkey */ break; case PKT_SIGNATURE: if( subkey ) { PKT_signature *sig = node->pkt->pkt.signature; if( sig->sig_class >= 0x10 && sig->sig_class <= 0x13 ) { log_info(_( "moving a key signature to the correct place\n")); last->next = node->next; node->next = subkey->next; subkey->next = node; node = last; fixed=1; } } break; default: break; } } return fixed; } /**************** * Menu driven key editor. If sign_mode is true semi-automatical signing * will be performed. commands are ignore in this case * * Note: to keep track of some selection we use node->mark MARKBIT_xxxx. */ void keyedit_menu( const char *username, STRLIST locusr, STRLIST commands, int sign_mode ) { enum cmdids { cmdNONE = 0, cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN, cmdLSIGN, cmdREVSIG, cmdREVKEY, cmdDELSIG, cmdDEBUG, cmdSAVE, cmdADDUID, cmdDELUID, cmdADDKEY, cmdDELKEY, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE, cmdENABLEKEY, cmdDISABLEKEY, cmdINVCMD, cmdNOP }; static struct { const char *name; enum cmdids id; int need_sk; int signmode; const char *desc; } cmds[] = { { N_("quit") , cmdQUIT , 0,1, N_("quit this menu") }, { N_("q") , cmdQUIT , 0,1, NULL }, { N_("save") , cmdSAVE , 0,1, N_("save and quit") }, { N_("help") , cmdHELP , 0,1, N_("show this help") }, { "?" , cmdHELP , 0,1, NULL }, { N_("fpr") , cmdFPR , 0,1, N_("show fingerprint") }, { N_("list") , cmdLIST , 0,1, N_("list key and user ids") }, { N_("l") , cmdLIST , 0,1, NULL }, { N_("uid") , cmdSELUID , 0,1, N_("select user id N") }, { N_("key") , cmdSELKEY , 0,0, N_("select secondary key N") }, { N_("check") , cmdCHECK , 0,1, N_("list signatures") }, { N_("c") , cmdCHECK , 0,1, NULL }, { N_("sign") , cmdSIGN , 0,1, N_("sign the key") }, { N_("s") , cmdSIGN , 0,1, NULL }, { N_("lsign") , cmdLSIGN , 0,1, N_("sign the key locally") }, { N_("debug") , cmdDEBUG , 0,0, NULL }, { N_("adduid") , cmdADDUID , 1,0, N_("add a user id") }, { N_("deluid") , cmdDELUID , 0,0, N_("delete user id") }, { N_("addkey") , cmdADDKEY , 1,0, N_("add a secondary key") }, { N_("delkey") , cmdDELKEY , 0,0, N_("delete a secondary key") }, { N_("delsig") , cmdDELSIG , 0,0, N_("delete signatures") }, { N_("expire") , cmdEXPIRE , 1,0, N_("change the expire date") }, { N_("toggle") , cmdTOGGLE , 1,0, N_("toggle between secret " "and public key listing") }, { N_("t" ) , cmdTOGGLE , 1,0, NULL }, { N_("pref") , cmdPREF , 0,0, N_("list preferences") }, { N_("passwd") , cmdPASSWD , 1,0, N_("change the passphrase") }, { N_("trust") , cmdTRUST , 0,0, N_("change the ownertrust") }, { N_("revsig") , cmdREVSIG , 0,0, N_("revoke signatures") }, { N_("revkey") , cmdREVKEY , 1,0, N_("revoke a secondary key") }, { N_("disable") , cmdDISABLEKEY, 0,0, N_("disable a key") }, { N_("enable") , cmdENABLEKEY , 0,0, N_("enable a key") }, { NULL, cmdNONE } }; enum cmdids cmd = 0; int rc = 0; KBNODE keyblock = NULL; KBPOS keyblockpos; KBNODE sec_keyblock = NULL; KBPOS sec_keyblockpos; KBNODE cur_keyblock; char *answer = NULL; int redisplay = 1; int modified = 0; int sec_modified = 0; int toggle; int have_commands = !!commands; if( opt.batch && !have_commands ) { log_error(_("can't do that in batchmode\n")); goto leave; } if( sign_mode ) { commands = NULL; append_to_strlist( &commands, sign_mode == 1? "sign":"lsign" ); have_commands = 1; } if( !sign_mode ) { /* first try to locate it as secret key */ rc = find_secret_keyblock_byname( &sec_keyblockpos, username ); if( !rc ) { rc = read_keyblock( &sec_keyblockpos, &sec_keyblock ); if( rc ) { log_error("%s: secret keyblock read problem: %s\n", username, g10_errstr(rc)); goto leave; } merge_keys_and_selfsig( sec_keyblock ); if( fix_keyblock( sec_keyblock ) ) sec_modified++; } } /* and now get the public key */ rc = get_keyblock_byname( &keyblock, &keyblockpos, username ); if( rc ) goto leave; if( fix_keyblock( keyblock ) ) modified++; if( collapse_uids( &keyblock ) ) modified++; if( sec_keyblock ) { /* check that they match */ /* fixme: check that they both match */ tty_printf(_("Secret key is available.\n")); } toggle = 0; cur_keyblock = keyblock; for(;;) { /* main loop */ int i, arg_number; char *p; tty_printf("\n"); if( redisplay ) { show_key_with_all_names( cur_keyblock, 0, 0, 1, 0 ); tty_printf("\n"); redisplay = 0; } do { m_free(answer); if( have_commands ) { if( commands ) { answer = m_strdup( commands->d ); commands = commands->next; } else if( opt.batch ) { answer = m_strdup("quit"); } else have_commands = 0; } if( !have_commands ) { answer = cpr_get("", _("Command> ")); cpr_kill_prompt(); } trim_spaces(answer); } while( *answer == '#' ); arg_number = 0; /* Yes, here is the init which egcc complains about*/ if( !*answer ) cmd = cmdLIST; else if( *answer == CONTROL_D ) cmd = cmdQUIT; else if( isdigit( *answer ) ) { cmd = cmdSELUID; arg_number = atoi(answer); } else { if( (p=strchr(answer,' ')) ) { *p++ = 0; trim_spaces(answer); trim_spaces(p); arg_number = atoi(p); } for(i=0; cmds[i].name; i++ ) { if( !stricmp( answer, cmds[i].name ) ) break; } if( sign_mode && !cmds[i].signmode ) cmd = cmdINVCMD; else if( cmds[i].need_sk && !sec_keyblock ) { tty_printf(_("Need the secret key to do this.\n")); cmd = cmdNOP; } else cmd = cmds[i].id; } switch( cmd ) { case cmdHELP: for(i=0; cmds[i].name; i++ ) { if( sign_mode && !cmds[i].signmode ) ; else if( cmds[i].need_sk && !sec_keyblock ) ; /* skip if we do not have the secret key */ else if( cmds[i].desc ) tty_printf("%-10s %s\n", cmds[i].name, _(cmds[i].desc) ); } break; case cmdLIST: redisplay = 1; break; case cmdFPR: show_key_and_fingerprint( keyblock ); break; case cmdSELUID: if( menu_select_uid( cur_keyblock, arg_number ) ) redisplay = 1; break; case cmdSELKEY: if( menu_select_key( cur_keyblock, arg_number ) ) redisplay = 1; break; case cmdCHECK: /* we can only do this with the public key becuase the * check functions can't cope with secret keys and it * is questionable whether this would make sense at all */ check_all_keysigs( keyblock, count_selected_uids(keyblock) ); break; case cmdSIGN: /* sign (only the public key) */ case cmdLSIGN: /* sign (only the public key) */ if( count_uids(keyblock) > 1 && !count_selected_uids(keyblock) ) { if( !cpr_get_answer_is_yes("keyedit.sign_all.okay", _("Really sign all user ids? ")) ) { tty_printf(_("Hint: Select the user ids to sign\n")); break; } } if( !sign_uids( keyblock, locusr, &modified, cmd == cmdLSIGN ) && sign_mode ) goto do_cmd_save; break; case cmdDEBUG: dump_kbnode( cur_keyblock ); break; case cmdTOGGLE: toggle = !toggle; cur_keyblock = toggle? sec_keyblock : keyblock; redisplay = 1; break; case cmdADDUID: if( menu_adduid( keyblock, sec_keyblock ) ) { redisplay = 1; sec_modified = modified = 1; /* must update the trustdb already here, so that preferences * get listed correctly */ rc = update_trust_record( keyblock, 0, NULL ); if( rc ) { log_error(_("update of trustdb failed: %s\n"), g10_errstr(rc) ); rc = 0; } } break; case cmdDELUID: { int n1; if( !(n1=count_selected_uids(keyblock)) ) tty_printf(_("You must select at least one user id.\n")); else if( count_uids(keyblock) - n1 < 1 ) tty_printf(_("You can't delete the last user id!\n")); else if( cpr_get_answer_is_yes( "keyedit.remove.uid.okay", n1 > 1? _("Really remove all selected user ids? ") : _("Really remove this user id? ") ) ) { menu_deluid( keyblock, sec_keyblock ); redisplay = 1; modified = 1; if( sec_keyblock ) sec_modified = 1; } } break; case cmdDELSIG: { int n1; if( !(n1=count_selected_uids(keyblock)) ) tty_printf(_("You must select at least one user id.\n")); else if( menu_delsig( keyblock ) ) { /* no redisplay here, because it may scroll away some * status output of delsig */ modified = 1; } } break; case cmdADDKEY: if( generate_subkeypair( keyblock, sec_keyblock ) ) { redisplay = 1; sec_modified = modified = 1; } break; case cmdDELKEY: { int n1; if( !(n1=count_selected_keys( keyblock )) ) tty_printf(_("You must select at least one key.\n")); else if( sec_keyblock && !cpr_get_answer_is_yes( "keyedit.remove.subkey.okay", n1 > 1? _("Do you really want to delete the selected keys? "): _("Do you really want to delete this key? ") )) ; else { menu_delkey( keyblock, sec_keyblock ); redisplay = 1; modified = 1; if( sec_keyblock ) sec_modified = 1; } } break; case cmdREVKEY: { int n1; if( !(n1=count_selected_keys( keyblock )) ) tty_printf(_("You must select at least one key.\n")); else if( sec_keyblock && !cpr_get_answer_is_yes( "keyedit.revoke.subkey.okay", n1 > 1? _("Do you really want to revoke the selected keys? "): _("Do you really want to revoke this key? ") )) ; else { if( menu_revkey( keyblock, sec_keyblock ) ) { modified = 1; /*sec_modified = 1;*/ } redisplay = 1; } } break; case cmdEXPIRE: if( menu_expire( keyblock, sec_keyblock ) ) { merge_keys_and_selfsig( sec_keyblock ); merge_keys_and_selfsig( keyblock ); sec_modified = 1; modified = 1; redisplay = 1; } break; case cmdPASSWD: if( change_passphrase( sec_keyblock ) ) sec_modified = 1; break; case cmdTRUST: show_key_with_all_names( keyblock, 0, 0, 1, 0 ); tty_printf("\n"); if( edit_ownertrust( find_kbnode( keyblock, PKT_PUBLIC_KEY )->pkt->pkt.public_key->local_id, 1 ) ) redisplay = 1; /* we don't need to set modified here, as the trustvalues * are updated immediately */ break; case cmdPREF: show_key_with_all_names( keyblock, 0, 0, 0, 1 ); break; case cmdNOP: break; case cmdREVSIG: if( menu_revsig( keyblock ) ) { redisplay = 1; modified = 1; } break; case cmdENABLEKEY: case cmdDISABLEKEY: if( enable_disable_key( keyblock, cmd == cmdDISABLEKEY ) ) { redisplay = 1; modified = 1; } break; case cmdQUIT: if( have_commands ) goto leave; if( !modified && !sec_modified ) goto leave; if( !cpr_get_answer_is_yes("keyedit.save.okay", _("Save changes? ")) ) { if( cpr_enabled() || cpr_get_answer_is_yes("keyedit.cancel.okay", _("Quit without saving? ")) ) goto leave; break; } /* fall thru */ case cmdSAVE: do_cmd_save: if( modified || sec_modified ) { if( modified ) { rc = update_keyblock( &keyblockpos, keyblock ); if( rc ) { log_error(_("update failed: %s\n"), g10_errstr(rc) ); break; } } if( sec_modified ) { rc = update_keyblock( &sec_keyblockpos, sec_keyblock ); if( rc ) { log_error(_("update secret failed: %s\n"), g10_errstr(rc) ); break; } } } else tty_printf(_("Key not changed so no update needed.\n")); /* TODO: we should keep track whether we have changed * something relevant to the trustdb */ if( !modified && sign_mode ) rc = 0; /* we can skip at least in this case */ else rc = update_trust_record( keyblock, 0, NULL ); if( rc ) log_error(_("update of trustdb failed: %s\n"), g10_errstr(rc) ); goto leave; case cmdINVCMD: default: tty_printf("\n"); tty_printf(_("Invalid command (try \"help\")\n")); break; } } /* end main loop */ leave: release_kbnode( keyblock ); release_kbnode( sec_keyblock ); m_free(answer); } /**************** * show preferences of a public keyblock. */ static void show_prefs( KBNODE keyblock, PKT_user_id *uid ) { KBNODE node = find_kbnode( keyblock, PKT_PUBLIC_KEY ); PKT_public_key *pk; byte *p; int i; size_t n; byte namehash[20]; if( !node ) return; /* is a secret keyblock */ pk = node->pkt->pkt.public_key; if( !pk->local_id ) { log_error("oops: no LID\n"); return; } rmd160_hash_buffer( namehash, uid->name, uid->len ); p = get_pref_data( pk->local_id, namehash, &n ); if( !p ) return; tty_printf(" "); for(i=0; i < n; i+=2 ) { if( p[i] ) tty_printf( " %c%d", p[i] == PREFTYPE_SYM ? 'S' : p[i] == PREFTYPE_HASH ? 'H' : p[i] == PREFTYPE_COMPR ? 'Z' : '?', p[i+1]); } tty_printf("\n"); m_free(p); } /**************** * Display the key a the user ids, if only_marked is true, do only * so for user ids with mark A flag set and dont display the index number */ static void show_key_with_all_names( KBNODE keyblock, int only_marked, int with_fpr, int with_subkeys, int with_prefs ) { KBNODE node; int i, rc; /* the keys */ for( node = keyblock; node; node = node->next ) { if( node->pkt->pkttype == PKT_PUBLIC_KEY || (with_subkeys && node->pkt->pkttype == PKT_PUBLIC_SUBKEY) ) { PKT_public_key *pk = node->pkt->pkt.public_key; int otrust=0, trust=0; if( node->pkt->pkttype == PKT_PUBLIC_KEY ) { /* do it here, so that debug messages don't clutter the * output */ trust = query_trust_info(pk, NULL); otrust = get_ownertrust_info( pk->local_id ); } tty_printf("%s%c %4u%c/%08lX created: %s expires: %s", node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub", (node->flag & NODFLG_SELKEY)? '*':' ', nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ), (ulong)keyid_from_pk(pk,NULL), datestr_from_pk(pk), expirestr_from_pk(pk) ); if( node->pkt->pkttype == PKT_PUBLIC_KEY ) { tty_printf(" trust: %c/%c", otrust, trust ); if( node->pkt->pkttype == PKT_PUBLIC_KEY && (get_ownertrust( pk->local_id )&TRUST_FLAG_DISABLED)) { tty_printf("\n*** "); tty_printf(_("This key has been disabled")); } if( with_fpr ) { tty_printf("\n"); show_fingerprint( pk ); } } tty_printf("\n"); } else if( node->pkt->pkttype == PKT_SECRET_KEY || (with_subkeys && node->pkt->pkttype == PKT_SECRET_SUBKEY) ) { PKT_secret_key *sk = node->pkt->pkt.secret_key; tty_printf("%s%c %4u%c/%08lX created: %s expires: %s\n", node->pkt->pkttype == PKT_SECRET_KEY? "sec":"sbb", (node->flag & NODFLG_SELKEY)? '*':' ', nbits_from_sk( sk ), pubkey_letter( sk->pubkey_algo ), (ulong)keyid_from_sk(sk,NULL), datestr_from_sk(sk), expirestr_from_sk(sk) ); } else if( with_subkeys && node->pkt->pkttype == PKT_SIGNATURE && node->pkt->pkt.signature->sig_class == 0x28 ) { PKT_signature *sig = node->pkt->pkt.signature; rc = check_key_signature( keyblock, node, NULL ); if( !rc ) tty_printf( "rev! subkey has been revoked: %s\n", datestr_from_sig( sig ) ); else if( rc == G10ERR_BAD_SIGN ) tty_printf( "rev- faked revocation found\n" ); else if( rc ) tty_printf( "rev? problem checking revocation: %s\n", g10_errstr(rc) ); } } /* the user ids */ i = 0; for( node = keyblock; node; node = node->next ) { if( node->pkt->pkttype == PKT_USER_ID ) { PKT_user_id *uid = node->pkt->pkt.user_id; ++i; if( !only_marked || (only_marked && (node->flag & NODFLG_MARK_A))){ if( only_marked ) tty_printf(" "); else if( node->flag & NODFLG_SELUID ) tty_printf("(%d)* ", i); else tty_printf("(%d) ", i); - tty_print_string( uid->name, uid->len ); + tty_print_utf8_string( uid->name, uid->len ); tty_printf("\n"); if( with_prefs ) show_prefs( keyblock, uid ); } } } } static void show_key_and_fingerprint( KBNODE keyblock ) { KBNODE node; PKT_public_key *pk = NULL; for( node = keyblock; node; node = node->next ) { if( node->pkt->pkttype == PKT_PUBLIC_KEY ) { pk = node->pkt->pkt.public_key; tty_printf("pub %4u%c/%08lX %s ", nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ), (ulong)keyid_from_pk(pk,NULL), datestr_from_pk(pk) ); } else if( node->pkt->pkttype == PKT_USER_ID ) { PKT_user_id *uid = node->pkt->pkt.user_id; - tty_print_string( uid->name, uid->len ); + tty_print_utf8_string( uid->name, uid->len ); break; } } tty_printf("\n"); if( pk ) show_fingerprint( pk ); } static void show_fingerprint( PKT_public_key *pk ) { byte array[MAX_FINGERPRINT_LEN], *p; size_t i, n; fingerprint_from_pk( pk, array, &n ); p = array; tty_printf(" Fingerprint:"); if( n == 20 ) { for(i=0; i < n ; i++, i++, p += 2 ) { if( i == 10 ) tty_printf(" "); tty_printf(" %02X%02X", *p, p[1] ); } } else { for(i=0; i < n ; i++, p++ ) { if( i && !(i%8) ) tty_printf(" "); tty_printf(" %02X", *p ); } } tty_printf("\n"); } /**************** * Ask for a new user id , do the selfsignature and put it into * both keyblocks. * Return true if there is a new user id */ static int menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock ) { PKT_user_id *uid; PKT_public_key *pk=NULL; PKT_secret_key *sk=NULL; PKT_signature *sig=NULL; PACKET *pkt; KBNODE node; KBNODE pub_where=NULL, sec_where=NULL; int rc; uid = generate_user_id(); if( !uid ) return 0; for( node = pub_keyblock; node; pub_where = node, node = node->next ) { if( node->pkt->pkttype == PKT_PUBLIC_KEY ) pk = node->pkt->pkt.public_key; else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) break; } if( !node ) /* no subkey */ pub_where = NULL; for( node = sec_keyblock; node; sec_where = node, node = node->next ) { if( node->pkt->pkttype == PKT_SECRET_KEY ) sk = copy_secret_key( NULL, node->pkt->pkt.secret_key); else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) break; } if( !node ) /* no subkey */ sec_where = NULL; assert(pk && sk ); rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0, keygen_add_std_prefs, pk ); free_secret_key( sk ); if( rc ) { log_error("signing failed: %s\n", g10_errstr(rc) ); free_user_id(uid); return 0; } /* insert/append to secret keyblock */ pkt = m_alloc_clear( sizeof *pkt ); pkt->pkttype = PKT_USER_ID; pkt->pkt.user_id = copy_user_id(NULL, uid); node = new_kbnode(pkt); if( sec_where ) insert_kbnode( sec_where, node, 0 ); else add_kbnode( sec_keyblock, node ); pkt = m_alloc_clear( sizeof *pkt ); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = copy_signature(NULL, sig); if( sec_where ) insert_kbnode( node, new_kbnode(pkt), 0 ); else add_kbnode( sec_keyblock, new_kbnode(pkt) ); /* insert/append to public keyblock */ pkt = m_alloc_clear( sizeof *pkt ); pkt->pkttype = PKT_USER_ID; pkt->pkt.user_id = uid; node = new_kbnode(pkt); if( pub_where ) insert_kbnode( pub_where, node, 0 ); else add_kbnode( pub_keyblock, node ); pkt = m_alloc_clear( sizeof *pkt ); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = copy_signature(NULL, sig); if( pub_where ) insert_kbnode( node, new_kbnode(pkt), 0 ); else add_kbnode( pub_keyblock, new_kbnode(pkt) ); return 1; } /**************** * Remove all selceted userids from the keyrings */ static void menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock ) { KBNODE node; int selected=0; for( node = pub_keyblock; node; node = node->next ) { if( node->pkt->pkttype == PKT_USER_ID ) { selected = node->flag & NODFLG_SELUID; if( selected ) { delete_kbnode( node ); if( sec_keyblock ) { KBNODE snode; int s_selected = 0; PKT_user_id *uid = node->pkt->pkt.user_id; for( snode = sec_keyblock; snode; snode = snode->next ) { if( snode->pkt->pkttype == PKT_USER_ID ) { PKT_user_id *suid = snode->pkt->pkt.user_id; s_selected = (uid->len == suid->len && !memcmp( uid->name, suid->name, uid->len)); if( s_selected ) delete_kbnode( snode ); } else if( s_selected && snode->pkt->pkttype == PKT_SIGNATURE ) delete_kbnode( snode ); else if( snode->pkt->pkttype == PKT_SECRET_SUBKEY ) s_selected = 0; } } } } else if( selected && node->pkt->pkttype == PKT_SIGNATURE ) delete_kbnode( node ); else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) selected = 0; } commit_kbnode( &pub_keyblock ); if( sec_keyblock ) commit_kbnode( &sec_keyblock ); } static int menu_delsig( KBNODE pub_keyblock ) { KBNODE node; PKT_user_id *uid = NULL; int changed=0; for( node = pub_keyblock; node; node = node->next ) { if( node->pkt->pkttype == PKT_USER_ID ) { uid = (node->flag & NODFLG_SELUID)? node->pkt->pkt.user_id : NULL; } else if( uid && node->pkt->pkttype == PKT_SIGNATURE ) { int okay, valid, selfsig, inv_sig, no_key, other_err; tty_printf("uid "); - tty_print_string( uid->name, uid->len ); + tty_print_utf8_string( uid->name, uid->len ); tty_printf("\n"); okay = inv_sig = no_key = other_err = 0; valid = print_and_check_one_sig( pub_keyblock, node, &inv_sig, &no_key, &other_err, &selfsig, 1 ); if( valid ) okay = cpr_get_answer_yes_no_quit( "keyedit.delsig.valid", _("Delete this good signature? (y/N/q)")); else if( inv_sig || other_err ) okay = cpr_get_answer_yes_no_quit( "keyedit.delsig.invalid", _("Delete this invalid signature? (y/N/q)")); else if( no_key ) okay = cpr_get_answer_yes_no_quit( "keyedit.delsig.unknown", _("Delete this unknown signature? (y/N/q)")); if( okay == -1 ) break; if( okay && selfsig && !cpr_get_answer_is_yes( "keyedit.delsig.selfsig", _("Really delete this self-signature? (y/N)") )) okay = 0; if( okay ) { delete_kbnode( node ); changed++; } } else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) uid = NULL; } if( changed ) { commit_kbnode( &pub_keyblock ); tty_printf( changed == 1? _("Deleted %d signature.\n") : _("Deleted %d signatures.\n"), changed ); } else tty_printf( _("Nothing deleted.\n") ); return changed; } /**************** * Remove some of the secondary keys */ static void menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock ) { KBNODE node; int selected=0; for( node = pub_keyblock; node; node = node->next ) { if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { selected = node->flag & NODFLG_SELKEY; if( selected ) { delete_kbnode( node ); if( sec_keyblock ) { KBNODE snode; int s_selected = 0; u32 ki[2]; keyid_from_pk( node->pkt->pkt.public_key, ki ); for( snode = sec_keyblock; snode; snode = snode->next ) { if( snode->pkt->pkttype == PKT_SECRET_SUBKEY ) { u32 ki2[2]; keyid_from_sk( snode->pkt->pkt.secret_key, ki2 ); s_selected = (ki[0] == ki2[0] && ki[1] == ki2[1]); if( s_selected ) delete_kbnode( snode ); } else if( s_selected && snode->pkt->pkttype == PKT_SIGNATURE ) delete_kbnode( snode ); else s_selected = 0; } } } } else if( selected && node->pkt->pkttype == PKT_SIGNATURE ) delete_kbnode( node ); else selected = 0; } commit_kbnode( &pub_keyblock ); if( sec_keyblock ) commit_kbnode( &sec_keyblock ); } static int menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock ) { int n1, signumber, rc; u32 expiredate; int mainkey=0; PKT_secret_key *sk; /* copy of the main sk */ PKT_public_key *main_pk, *sub_pk; PKT_user_id *uid; KBNODE node; u32 keyid[2]; if( count_selected_keys( sec_keyblock ) ) { tty_printf(_("Please remove selections from the secret keys.\n")); return 0; } n1 = count_selected_keys( pub_keyblock ); if( n1 > 1 ) { tty_printf(_("Please select at most one secondary key.\n")); return 0; } else if( n1 ) tty_printf(_("Changing expiration time for a secondary key.\n")); else { tty_printf(_("Changing expiration time for the primary key.\n")); mainkey=1; } expiredate = ask_expiredate(); node = find_kbnode( sec_keyblock, PKT_SECRET_KEY ); sk = copy_secret_key( NULL, node->pkt->pkt.secret_key); /* Now we can actually change the self signature(s) */ main_pk = sub_pk = NULL; uid = NULL; signumber = 0; for( node=pub_keyblock; node; node = node->next ) { if( node->pkt->pkttype == PKT_PUBLIC_KEY ) { main_pk = node->pkt->pkt.public_key; keyid_from_pk( main_pk, keyid ); main_pk->expiredate = expiredate; } else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY && (node->flag & NODFLG_SELKEY ) ) { sub_pk = node->pkt->pkt.public_key; sub_pk->expiredate = expiredate; } else if( node->pkt->pkttype == PKT_USER_ID ) uid = node->pkt->pkt.user_id; else if( main_pk && node->pkt->pkttype == PKT_SIGNATURE ) { PKT_signature *sig = node->pkt->pkt.signature; if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] && ( (mainkey && uid && (sig->sig_class&~3) == 0x10) || (!mainkey && sig->sig_class == 0x18) ) ) { /* this is a selfsignature which is to be replaced */ PKT_signature *newsig; PACKET *newpkt; KBNODE sn; int signumber2 = 0; signumber++; if( (mainkey && main_pk->version < 4) || (!mainkey && sub_pk->version < 4 ) ) { log_info(_( "You can't change the expiration date of a v3 key\n")); free_secret_key( sk ); return 0; } /* find the corresponding secret self-signature */ for( sn=sec_keyblock; sn; sn = sn->next ) { if( sn->pkt->pkttype == PKT_SIGNATURE ) { PKT_signature *b = sn->pkt->pkt.signature; if( keyid[0] == b->keyid[0] && keyid[1] == b->keyid[1] && sig->sig_class == b->sig_class && ++signumber2 == signumber ) break; } } if( !sn ) log_info(_("No corresponding signature in secret ring\n")); /* create new self signature */ if( mainkey ) rc = make_keysig_packet( &newsig, main_pk, uid, NULL, sk, 0x13, 0, keygen_add_std_prefs, main_pk ); else rc = make_keysig_packet( &newsig, main_pk, NULL, sub_pk, sk, 0x18, 0, keygen_add_key_expire, sub_pk ); if( rc ) { log_error("make_keysig_packet failed: %s\n", g10_errstr(rc)); free_secret_key( sk ); return 0; } /* replace the packet */ newpkt = m_alloc_clear( sizeof *newpkt ); newpkt->pkttype = PKT_SIGNATURE; newpkt->pkt.signature = newsig; free_packet( node->pkt ); m_free( node->pkt ); node->pkt = newpkt; if( sn ) { newpkt = m_alloc_clear( sizeof *newpkt ); newpkt->pkttype = PKT_SIGNATURE; newpkt->pkt.signature = copy_signature( NULL, newsig ); free_packet( sn->pkt ); m_free( sn->pkt ); sn->pkt = newpkt; } } } } free_secret_key( sk ); return 1; } /**************** * Select one user id or remove all selection if index is 0. * Returns: True if the selection changed; */ static int menu_select_uid( KBNODE keyblock, int idx ) { KBNODE node; int i; /* first check that the index is valid */ if( idx ) { for( i=0, node = keyblock; node; node = node->next ) { if( node->pkt->pkttype == PKT_USER_ID ) { if( ++i == idx ) break; } } if( !node ) { tty_printf(_("No user id with index %d\n"), idx ); return 0; } } else { /* reset all */ for( i=0, node = keyblock; node; node = node->next ) { if( node->pkt->pkttype == PKT_USER_ID ) node->flag &= ~NODFLG_SELUID; } return 1; } /* and toggle the new index */ for( i=0, node = keyblock; node; node = node->next ) { if( node->pkt->pkttype == PKT_USER_ID ) { if( ++i == idx ) { if( (node->flag & NODFLG_SELUID) ) node->flag &= ~NODFLG_SELUID; else node->flag |= NODFLG_SELUID; } } } return 1; } /**************** * Select secondary keys * Returns: True if the selection changed; */ static int menu_select_key( KBNODE keyblock, int idx ) { KBNODE node; int i; /* first check that the index is valid */ if( idx ) { for( i=0, node = keyblock; node; node = node->next ) { if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY ) { if( ++i == idx ) break; } } if( !node ) { tty_printf(_("No secondary key with index %d\n"), idx ); return 0; } } else { /* reset all */ for( i=0, node = keyblock; node; node = node->next ) { if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY ) node->flag &= ~NODFLG_SELKEY; } return 1; } /* and set the new index */ for( i=0, node = keyblock; node; node = node->next ) { if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY ) { if( ++i == idx ) { if( (node->flag & NODFLG_SELKEY) ) node->flag &= ~NODFLG_SELKEY; else node->flag |= NODFLG_SELKEY; } } } return 1; } static int count_uids_with_flag( KBNODE keyblock, unsigned flag ) { KBNODE node; int i=0; for( node = keyblock; node; node = node->next ) if( node->pkt->pkttype == PKT_USER_ID && (node->flag & flag) ) i++; return i; } static int count_keys_with_flag( KBNODE keyblock, unsigned flag ) { KBNODE node; int i=0; for( node = keyblock; node; node = node->next ) if( ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) && (node->flag & flag) ) i++; return i; } static int count_uids( KBNODE keyblock ) { KBNODE node; int i=0; for( node = keyblock; node; node = node->next ) if( node->pkt->pkttype == PKT_USER_ID ) i++; return i; } /**************** * Returns true if there is at least one selected user id */ static int count_selected_uids( KBNODE keyblock ) { return count_uids_with_flag( keyblock, NODFLG_SELUID); } static int count_selected_keys( KBNODE keyblock ) { return count_keys_with_flag( keyblock, NODFLG_SELKEY); } /* * Ask whether the signature should be revoked. If the user commits this, * flag bit MARK_A is set on the signature and the user ID. */ static void ask_revoke_sig( KBNODE keyblock, KBNODE node ) { PKT_signature *sig = node->pkt->pkt.signature; KBNODE unode = find_prev_kbnode( keyblock, node, PKT_USER_ID ); if( !unode ) { log_error("Oops: no user ID for signature\n"); return; } tty_printf(_("user ID: \"")); - tty_print_string( unode->pkt->pkt.user_id->name, - unode->pkt->pkt.user_id->len ); + tty_print_utf8_string( unode->pkt->pkt.user_id->name, + unode->pkt->pkt.user_id->len ); tty_printf(_("\"\nsigned with your key %08lX at %s\n"), sig->keyid[1], datestr_from_sig(sig) ); if( cpr_get_answer_is_yes("ask_revoke_sig.one", _("Create a revocation certificate for this signature? (y/N)")) ) { node->flag |= NODFLG_MARK_A; unode->flag |= NODFLG_MARK_A; } } /**************** * Display all user ids of the current public key together with signatures * done by one of our keys. Then walk over all this sigs and ask the user * whether he wants to revoke this signature. * Return: True when the keyblock has changed. */ static int menu_revsig( KBNODE keyblock ) { PKT_signature *sig; PKT_public_key *primary_pk; KBNODE node; int changed = 0; int upd_trust = 0; int rc, any; /* FIXME: detect duplicates here */ tty_printf("You have signed these user IDs:\n"); for( node = keyblock; node; node = node->next ) { node->flag &= ~(NODFLG_SELSIG | NODFLG_MARK_A); if( node->pkt->pkttype == PKT_USER_ID ) { PKT_user_id *uid = node->pkt->pkt.user_id; /* Hmmm: Should we show only UIDs with a signature? */ tty_printf(" "); - tty_print_string( uid->name, uid->len ); + tty_print_utf8_string( uid->name, uid->len ); tty_printf("\n"); } else if( node->pkt->pkttype == PKT_SIGNATURE && ((sig = node->pkt->pkt.signature), !seckey_available( sig->keyid ) ) ) { if( (sig->sig_class&~3) == 0x10 ) { tty_printf(" signed by %08lX at %s\n", sig->keyid[1], datestr_from_sig(sig) ); node->flag |= NODFLG_SELSIG; } else if( sig->sig_class == 0x30 ) { tty_printf(" revoked by %08lX at %s\n", sig->keyid[1], datestr_from_sig(sig) ); } } } /* ask */ for( node = keyblock; node; node = node->next ) { if( !(node->flag & NODFLG_SELSIG) ) continue; ask_revoke_sig( keyblock, node ); } /* present selected */ any = 0; for( node = keyblock; node; node = node->next ) { if( !(node->flag & NODFLG_MARK_A) ) continue; if( !any ) { any = 1; tty_printf("You are about to revoke these signatures:\n"); } if( node->pkt->pkttype == PKT_USER_ID ) { PKT_user_id *uid = node->pkt->pkt.user_id; tty_printf(" "); - tty_print_string( uid->name, uid->len ); + tty_print_utf8_string( uid->name, uid->len ); tty_printf("\n"); } else if( node->pkt->pkttype == PKT_SIGNATURE ) { sig = node->pkt->pkt.signature; tty_printf(" signed by %08lX at %s\n", sig->keyid[1], datestr_from_sig(sig) ); } } if( !any ) return 0; /* none selected */ if( !cpr_get_answer_is_yes("ask_revoke_sig.okay", _("Really create the revocation certificates? (y/N)")) ) return 0; /* forget it */ /* now we can sign the user ids */ reloop: /* (must use this, because we are modifing the list) */ primary_pk = keyblock->pkt->pkt.public_key; for( node=keyblock; node; node = node->next ) { KBNODE unode; PACKET *pkt; struct sign_uid_attrib attrib; PKT_secret_key *sk; if( !(node->flag & NODFLG_MARK_A) || node->pkt->pkttype != PKT_SIGNATURE ) continue; unode = find_prev_kbnode( keyblock, node, PKT_USER_ID ); assert( unode ); /* we already checked this */ memset( &attrib, 0, sizeof attrib ); node->flag &= ~NODFLG_MARK_A; sk = m_alloc_secure_clear( sizeof *sk ); if( get_seckey( sk, node->pkt->pkt.signature->keyid ) ) { log_info(_("no secret key\n")); continue; } rc = make_keysig_packet( &sig, primary_pk, unode->pkt->pkt.user_id, NULL, sk, 0x30, 0, sign_uid_mk_attrib, &attrib ); free_secret_key(sk); if( rc ) { log_error(_("signing failed: %s\n"), g10_errstr(rc)); return changed; } changed = 1; /* we changed the keyblock */ upd_trust = 1; pkt = m_alloc_clear( sizeof *pkt ); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; insert_kbnode( unode, new_kbnode(pkt), 0 ); goto reloop; } if( upd_trust ) clear_trust_checked_flag( primary_pk ); return changed; } /**************** * Revoke some of the secondary keys. * Hmmm: Should we add a revocation to the secret keyring too? * Does its all make sense to duplicate most of the information? */ static int menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock ) { PKT_public_key *mainpk; KBNODE node; int changed = 0; int upd_trust = 0; int rc; reloop: /* (better this way because we are modifing the keyring) */ mainpk = pub_keyblock->pkt->pkt.public_key; for( node = pub_keyblock; node; node = node->next ) { if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY && (node->flag & NODFLG_SELKEY) ) { PACKET *pkt; PKT_signature *sig; PKT_secret_key *sk; PKT_public_key *subpk = node->pkt->pkt.public_key; node->flag &= ~NODFLG_SELKEY; sk = copy_secret_key( NULL, sec_keyblock->pkt->pkt.secret_key ); rc = make_keysig_packet( &sig, mainpk, NULL, subpk, sk, 0x28, 0, NULL, NULL ); free_secret_key(sk); if( rc ) { log_error(_("signing failed: %s\n"), g10_errstr(rc)); return changed; } changed = 1; /* we changed the keyblock */ upd_trust = 1; pkt = m_alloc_clear( sizeof *pkt ); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; insert_kbnode( node, new_kbnode(pkt), 0 ); goto reloop; } } commit_kbnode( &pub_keyblock ); /*commit_kbnode( &sec_keyblock );*/ if( upd_trust ) clear_trust_checked_flag( mainpk ); return changed; } static int enable_disable_key( KBNODE keyblock, int disable ) { ulong lid = find_kbnode( keyblock, PKT_PUBLIC_KEY ) ->pkt->pkt.public_key->local_id; unsigned int trust, newtrust; /* Note: Because the keys have beed displayed, we have * ensured that local_id has been set */ trust = newtrust = get_ownertrust( lid ); newtrust &= ~TRUST_FLAG_DISABLED; if( disable ) newtrust |= TRUST_FLAG_DISABLED; if( trust == newtrust ) return 0; /* already in that state */ if( !update_ownertrust( lid, newtrust ) ) return 1; return 0; } diff --git a/g10/keylist.c b/g10/keylist.c index 02a265394..91a13afaf 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -1,459 +1,467 @@ /* keylist.c * Copyright (C) 1998 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 #include #include #include #include #include #include "options.h" #include "packet.h" #include "errors.h" #include "keydb.h" #include "memory.h" #include "util.h" #include "trustdb.h" #include "main.h" #include "i18n.h" static void list_all(int); static void list_one( STRLIST names, int secret); static void list_keyblock( KBNODE keyblock, int secret ); static void fingerprint( PKT_public_key *pk, PKT_secret_key *sk ); /**************** * List the keys * If NNAMES is 0; all available keys are listed */ void public_key_list( int nnames, char **names ) { if( !nnames ) list_all(0); else { /* List by user id */ STRLIST list = NULL; for( ; nnames ; nnames--, names++ ) add_to_strlist( &list, *names ); list_one( list, 0 ); free_strlist( list ); } } void secret_key_list( int nnames, char **names ) { if( !nnames ) list_all(1); else { /* List by user id */ STRLIST list = NULL; for( ; nnames ; nnames--, names++ ) add_to_strlist( &list, *names ); list_one( list, 1 ); free_strlist( list ); } } static void list_all( int secret ) { KBPOS kbpos; KBNODE keyblock = NULL; int rc=0; int lastresno; rc = enum_keyblocks( secret? 5:0, &kbpos, &keyblock ); if( rc ) { if( rc != -1 ) log_error("enum_keyblocks(open) failed: %s\n", g10_errstr(rc) ); goto leave; } lastresno = -1; while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) { if( lastresno != kbpos.resno ) { const char *s = keyblock_resource_name( &kbpos ); int i; lastresno = kbpos.resno; printf("%s\n", s ); for(i=strlen(s); i; i-- ) putchar('-'); putchar('\n'); } merge_keys_and_selfsig( keyblock ); list_keyblock( keyblock, secret ); release_kbnode( keyblock ); keyblock = NULL; } if( rc && rc != -1 ) log_error("enum_keyblocks(read) failed: %s\n", g10_errstr(rc)); leave: enum_keyblocks( 2, &kbpos, &keyblock ); /* close */ release_kbnode( keyblock ); } static void list_one( STRLIST names, int secret ) { int rc = 0; KBNODE keyblock = NULL; GETKEY_CTX ctx; if( secret ) { rc = get_seckey_bynames( &ctx, NULL, names, &keyblock ); if( rc ) { log_error("error reading key: %s\n", g10_errstr(rc) ); get_seckey_end( ctx ); return; } do { merge_keys_and_selfsig( keyblock ); list_keyblock( keyblock, 1 ); release_kbnode( keyblock ); } while( !get_seckey_next( ctx, NULL, &keyblock ) ); get_seckey_end( ctx ); } else { rc = get_pubkey_bynames( &ctx, NULL, names, &keyblock ); if( rc ) { log_error("error reading key: %s\n", g10_errstr(rc) ); get_pubkey_end( ctx ); return; } do { list_keyblock( keyblock, 0 ); release_kbnode( keyblock ); } while( !get_pubkey_next( ctx, NULL, &keyblock ) ); get_pubkey_end( ctx ); } } static void print_key_data( PKT_public_key *pk, u32 *keyid ) { int n = pubkey_get_npkey( pk->pubkey_algo ); int i; for(i=0; i < n; i++ ) { printf("pkd:%d:%u:", i, mpi_get_nbits( pk->pkey[i] ) ); mpi_print(stdout, pk->pkey[i], 1 ); putchar(':'); putchar('\n'); } } static void list_keyblock( KBNODE keyblock, int secret ) { int rc = 0; KBNODE kbctx; KBNODE node; PKT_public_key *pk; PKT_secret_key *sk; u32 keyid[2]; int any=0; int trustletter = 0; int ulti_hack = 0; /* get the keyid from the keyblock */ node = find_kbnode( keyblock, secret? PKT_SECRET_KEY : PKT_PUBLIC_KEY ); if( !node ) { log_error("Oops; key lost!\n"); dump_kbnode( keyblock ); return; } if( secret ) { pk = NULL; sk = node->pkt->pkt.secret_key; keyid_from_sk( sk, keyid ); if( opt.with_colons ) printf("sec:u:%u:%d:%08lX%08lX:%s:%s:::", nbits_from_sk( sk ), sk->pubkey_algo, (ulong)keyid[0],(ulong)keyid[1], datestr_from_sk( sk ), sk->expiredate? strtimestamp(sk->expiredate):"" /* fixme: add LID here */ ); else printf("sec %4u%c/%08lX %s ", nbits_from_sk( sk ), pubkey_letter( sk->pubkey_algo ), (ulong)keyid[1], datestr_from_sk( sk ) ); } else { pk = node->pkt->pkt.public_key; sk = NULL; keyid_from_pk( pk, keyid ); if( opt.with_colons ) { trustletter = query_trust_info( pk, NULL ); if( trustletter == 'u' ) ulti_hack = 1; printf("pub:%c:%u:%d:%08lX%08lX:%s:%s:", trustletter, nbits_from_pk( pk ), pk->pubkey_algo, (ulong)keyid[0],(ulong)keyid[1], datestr_from_pk( pk ), pk->expiredate? strtimestamp(pk->expiredate):"" ); if( pk->local_id ) printf("%lu", pk->local_id ); putchar(':'); if( pk->local_id ) putchar( get_ownertrust_info( pk->local_id ) ); putchar(':'); } else printf("pub %4u%c/%08lX %s ", nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ), (ulong)keyid[1], datestr_from_pk( pk ) ); } for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) { if( node->pkt->pkttype == PKT_USER_ID ) { if( any ) { if( opt.with_colons ) { byte namehash[20]; if( pk && !ulti_hack ) { rmd160_hash_buffer( namehash, node->pkt->pkt.user_id->name, node->pkt->pkt.user_id->len ); trustletter = query_trust_info( pk, namehash ); } else trustletter = 'u'; printf("uid:%c::::::::", trustletter); } else printf("uid%*s", 28, ""); } - print_string( stdout, node->pkt->pkt.user_id->name, - node->pkt->pkt.user_id->len, opt.with_colons ); - if( opt.with_colons ) + if( opt.with_colons ) { + print_string( stdout, node->pkt->pkt.user_id->name, + node->pkt->pkt.user_id->len, ':' ); putchar(':'); + } + else + print_utf8_string( stdout, node->pkt->pkt.user_id->name, + node->pkt->pkt.user_id->len ); + putchar('\n'); if( !any ) { if( opt.fingerprint ) fingerprint( pk, sk ); if( opt.with_key_data ) print_key_data( pk, keyid ); any = 1; } } else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { u32 keyid2[2]; PKT_public_key *pk2 = node->pkt->pkt.public_key; if( !any ) { putchar('\n'); if( opt.fingerprint ) fingerprint( pk, sk ); /* of the main key */ any = 1; } keyid_from_pk( pk2, keyid2 ); if( opt.with_colons ) { printf("sub:%c:%u:%d:%08lX%08lX:%s:%s:", trustletter, nbits_from_pk( pk2 ), pk2->pubkey_algo, (ulong)keyid2[0],(ulong)keyid2[1], datestr_from_pk( pk2 ), pk2->expiredate? strtimestamp(pk2->expiredate):"" /* fixme: add LID and ownertrust here */ ); if( pk->local_id ) /* use the local_id of the main key??? */ printf("%lu", pk->local_id ); putchar(':'); putchar(':'); putchar('\n'); } else printf("sub %4u%c/%08lX %s\n", nbits_from_pk( pk2 ), pubkey_letter( pk2->pubkey_algo ), (ulong)keyid2[1], datestr_from_pk( pk2 ) ); if( opt.fingerprint > 1 ) fingerprint( pk2, NULL ); if( opt.with_key_data ) print_key_data( pk2, keyid2 ); } else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) { u32 keyid2[2]; PKT_secret_key *sk2 = node->pkt->pkt.secret_key; if( !any ) { putchar('\n'); if( opt.fingerprint ) fingerprint( pk, sk ); /* of the main key */ any = 1; } keyid_from_sk( sk2, keyid2 ); if( opt.with_colons ) printf("ssb::%u:%d:%08lX%08lX:%s:%s:::\n", nbits_from_sk( sk2 ), sk2->pubkey_algo, (ulong)keyid2[0],(ulong)keyid2[1], datestr_from_sk( sk2 ), sk2->expiredate? strtimestamp(sk2->expiredate):"" /* fixme: add LID */ ); else printf("ssb %4u%c/%08lX %s\n", nbits_from_sk( sk2 ), pubkey_letter( sk2->pubkey_algo ), (ulong)keyid2[1], datestr_from_sk( sk2 ) ); if( opt.fingerprint > 1 ) fingerprint( NULL, sk2 ); } else if( opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE ) { PKT_signature *sig = node->pkt->pkt.signature; int sigrc; if( !any ) { /* no user id, (maybe a revocation follows)*/ if( sig->sig_class == 0x20 ) puts("[revoked]"); else if( sig->sig_class == 0x18 ) puts("[key binding]"); else if( sig->sig_class == 0x28 ) puts("[subkey revoked]"); else putchar('\n'); if( opt.fingerprint ) fingerprint( pk, sk ); any=1; } if( sig->sig_class == 0x20 || sig->sig_class == 0x28 || sig->sig_class == 0x30 ) fputs("rev", stdout); else if( (sig->sig_class&~3) == 0x10 ) fputs("sig", stdout); else if( sig->sig_class == 0x18 ) fputs("sig", stdout); else { if( opt.with_colons ) printf("sig::::::::::%02x:\n",sig->sig_class ); else printf("sig " "[unexpected signature class 0x%02x]\n",sig->sig_class ); continue; } if( opt.check_sigs ) { fflush(stdout); rc = check_key_signature( keyblock, node, NULL ); switch( rc ) { case 0: sigrc = '!'; break; case G10ERR_BAD_SIGN: sigrc = '-'; break; case G10ERR_NO_PUBKEY: sigrc = '?'; break; default: sigrc = '%'; break; } } else { rc = 0; sigrc = ' '; } if( opt.with_colons ) { putchar(':'); if( sigrc != ' ' ) putchar(sigrc); printf(":::%08lX%08lX:%s::::", (ulong)sig->keyid[0], (ulong)sig->keyid[1], datestr_from_sig(sig)); } else printf("%c %08lX %s ", sigrc, (ulong)sig->keyid[1], datestr_from_sig(sig)); if( sigrc == '%' ) printf("[%s] ", g10_errstr(rc) ); else if( sigrc == '?' ) ; else { size_t n; char *p = get_user_id( sig->keyid, &n ); - print_string( stdout, p, n, opt.with_colons ); + if( opt.with_colons ) + print_string( stdout, p, n, ':' ); + else + print_utf8_string( stdout, p, n ); m_free(p); } if( opt.with_colons ) printf(":%02x:", sig->sig_class ); putchar('\n'); /* FIXME: check or list other sigs here (subpkt PRIV_ADD_SIG)*/ } } if( !any ) {/* oops, no user id */ if( opt.with_colons ) putchar(':'); putchar('\n'); } else if( !opt.with_colons ) putchar('\n'); /* separator line */ } static void fingerprint( PKT_public_key *pk, PKT_secret_key *sk ) { byte *array, *p; size_t i, n; p = array = pk? fingerprint_from_pk( pk, NULL, &n ) : fingerprint_from_sk( sk, NULL, &n ); if( opt.with_colons ) { printf("fpr:::::::::"); for(i=0; i < n ; i++, p++ ) printf("%02X", *p ); putchar(':'); } else { printf(" Key fingerprint ="); if( n == 20 ) { for(i=0; i < n ; i++, i++, p += 2 ) { if( i == 10 ) putchar(' '); printf(" %02X%02X", *p, p[1] ); } } else { for(i=0; i < n ; i++, p++ ) { if( i && !(i%8) ) putchar(' '); printf(" %02X", *p ); } } } putchar('\n'); m_free(array); } diff --git a/g10/mainproc.c b/g10/mainproc.c index 99713f9a4..033157269 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -1,1219 +1,1222 @@ /* maPPPPinproc.c - handle packets * Copyright (C) 1998, 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 */ #include #include #include #include #include #include #include "packet.h" #include "iobuf.h" #include "memory.h" #include "options.h" #include "util.h" #include "cipher.h" #include "keydb.h" #include "filter.h" #include "main.h" #include "status.h" #include "i18n.h" #include "trustdb.h" #include "hkp.h" struct kidlist_item { struct kidlist_item *next; u32 kid[2]; int pubkey_algo; int reason; }; /**************** * Structure to hold the context */ typedef struct mainproc_context *CTX; struct mainproc_context { struct mainproc_context *anchor; /* may be useful in the future */ PKT_public_key *last_pubkey; PKT_secret_key *last_seckey; PKT_user_id *last_user_id; md_filter_context_t mfx; int sigs_only; /* process only signatures and reject all other stuff */ int encrypt_only; /* process only encrytion messages */ STRLIST signed_data; const char *sigfilename; DEK *dek; int last_was_session_key; KBNODE list; /* the current list of packets */ int have_data; IOBUF iobuf; /* used to get the filename etc. */ int trustletter; /* temp usage in list_node */ ulong local_id; /* ditto */ struct kidlist_item *failed_pkenc; /* list of packets for which we do not have a secret key */ }; static int do_proc_packets( CTX c, IOBUF a ); static void list_node( CTX c, KBNODE node ); static void proc_tree( CTX c, KBNODE node ); static void release_list( CTX c ) { if( !c->list ) return; proc_tree(c, c->list ); release_kbnode( c->list ); while( c->failed_pkenc ) { struct kidlist_item *tmp = c->failed_pkenc->next; m_free( c->failed_pkenc ); c->failed_pkenc = tmp; } c->failed_pkenc = NULL; c->list = NULL; } static int add_onepass_sig( CTX c, PACKET *pkt ) { KBNODE node; if( c->list ) { /* add another packet */ if( c->list->pkt->pkttype != PKT_ONEPASS_SIG ) { log_error("add_onepass_sig: another packet is in the way\n"); release_list( c ); c->list = new_kbnode( pkt ); } else add_kbnode( c->list, new_kbnode( pkt )); } else /* insert the first one */ c->list = node = new_kbnode( pkt ); return 1; } static int add_user_id( CTX c, PACKET *pkt ) { if( !c->list ) { log_error("orphaned user id\n" ); return 0; } add_kbnode( c->list, new_kbnode( pkt ) ); return 1; } static int add_subkey( CTX c, PACKET *pkt ) { if( !c->list ) { log_error("subkey w/o mainkey\n" ); return 0; } add_kbnode( c->list, new_kbnode( pkt ) ); return 1; } static int add_ring_trust( CTX c, PACKET *pkt ) { if( !c->list ) { log_error("ring trust w/o key\n" ); return 0; } add_kbnode( c->list, new_kbnode( pkt ) ); return 1; } static int add_signature( CTX c, PACKET *pkt ) { KBNODE node; if( pkt->pkttype == PKT_SIGNATURE && !c->list ) { /* This is the first signature for the following datafile. * G10 does not write such packets; instead it always uses * onepass-sig packets. The drawback of PGP's method * of prepending the signature to the data is * that it is not possible to make a signature from data read * from stdin. (G10 is able to read PGP stuff anyway.) */ node = new_kbnode( pkt ); c->list = node; return 1; } else if( !c->list ) return 0; /* oops (invalid packet sequence)*/ else if( !c->list->pkt ) BUG(); /* so nicht */ /* add a new signature node id at the end */ node = new_kbnode( pkt ); add_kbnode( c->list, node ); return 1; } static void proc_symkey_enc( CTX c, PACKET *pkt ) { PKT_symkey_enc *enc; enc = pkt->pkt.symkey_enc; if( enc->seskeylen ) log_error( "symkey_enc packet with session keys are not supported!\n"); else { c->last_was_session_key = 2; c->dek = passphrase_to_dek( NULL, 0, enc->cipher_algo, &enc->s2k, 0 ); } free_packet(pkt); } static void proc_pubkey_enc( CTX c, PACKET *pkt ) { PKT_pubkey_enc *enc; int result = 0; /* check whether the secret key is available and store in this case */ c->last_was_session_key = 1; enc = pkt->pkt.pubkey_enc; /*printf("enc: encrypted by a pubkey with keyid %08lX\n", enc->keyid[1] );*/ /* Hmmm: why do I have this algo check here - anyway there is * function to check it. */ if( opt.verbose ) log_info(_("public key is %08lX\n"), (ulong)enc->keyid[1] ); if( is_status_enabled() ) { char buf[50]; sprintf(buf, "%08lX%08lX %d 0", (ulong)enc->keyid[0], (ulong)enc->keyid[1], enc->pubkey_algo ); write_status_text( STATUS_ENC_TO, buf ); } if( is_ELGAMAL(enc->pubkey_algo) || enc->pubkey_algo == PUBKEY_ALGO_DSA || is_RSA(enc->pubkey_algo) ) { if ( !c->dek && ((!enc->keyid[0] && !enc->keyid[1]) || !seckey_available( enc->keyid )) ) { c->dek = m_alloc_secure( sizeof *c->dek ); if( (result = get_session_key( enc, c->dek )) ) { /* error: delete the DEK */ m_free(c->dek); c->dek = NULL; } } else result = G10ERR_NO_SECKEY; } else result = G10ERR_PUBKEY_ALGO; if( result == -1 ) ; else if( !result ) { if( opt.verbose > 1 ) log_info( _("public key encrypted data: good DEK\n") ); } else { /* store it for later display */ struct kidlist_item *x = m_alloc( sizeof *x ); x->kid[0] = enc->keyid[0]; x->kid[1] = enc->keyid[1]; x->pubkey_algo = enc->pubkey_algo; x->reason = result; x->next = c->failed_pkenc; c->failed_pkenc = x; } free_packet(pkt); } /**************** * Print the list of public key encrypted packets which we could * not decrypt. */ static void print_failed_pkenc( struct kidlist_item *list ) { for( ; list; list = list->next ) { PKT_public_key *pk = m_alloc_clear( sizeof *pk ); const char *algstr = pubkey_algo_to_string( list->pubkey_algo ); pk->pubkey_algo = list->pubkey_algo; if( !get_pubkey( pk, list->kid ) ) { size_t n; char *p; log_info( _("encrypted with %u-bit %s key, ID %08lX, created %s\n"), nbits_from_pk( pk ), algstr, (ulong)list->kid[1], strtimestamp(pk->timestamp) ); fputs(" \"", log_stream() ); p = get_user_id( list->kid, &n ); print_string( log_stream(), p, n, '"' ); m_free(p); fputs("\"\n", log_stream() ); } else { log_info(_("encrypted with %s key, ID %08lX\n"), algstr, (ulong) list->kid[1] ); } free_public_key( pk ); if( list->reason == G10ERR_NO_SECKEY ) { log_info(_("no secret key for decryption available\n")); if( is_status_enabled() ) { char buf[20]; sprintf(buf,"%08lX%08lX", (ulong)list->kid[0], (ulong)list->kid[1] ); write_status_text( STATUS_NO_SECKEY, buf ); } } else log_error(_("public key decryption failed: %s\n"), g10_errstr(list->reason)); } } static void proc_encrypted( CTX c, PACKET *pkt ) { int result = 0; print_failed_pkenc( c->failed_pkenc ); /*log_debug("dat: %sencrypted data\n", c->dek?"":"conventional ");*/ if( !c->dek && !c->last_was_session_key ) { /* assume this is old conventional encrypted data */ c->dek = passphrase_to_dek( NULL, 0, opt.def_cipher_algo ? opt.def_cipher_algo : DEFAULT_CIPHER_ALGO, NULL, 0 ); } else if( !c->dek ) result = G10ERR_NO_SECKEY; if( !result ) result = decrypt_data( c, pkt->pkt.encrypted, c->dek ); m_free(c->dek); c->dek = NULL; if( result == -1 ) ; else if( !result ) { write_status( STATUS_DECRYPTION_OKAY ); if( opt.verbose > 1 ) log_info(_("decryption okay\n")); if( pkt->pkt.encrypted->mdc_method ) write_status( STATUS_GOODMDC ); } else if( result == G10ERR_BAD_SIGN ) { log_error(_("WARNING: encrypted message has been manipulated!\n")); write_status( STATUS_BADMDC ); } else { write_status( STATUS_DECRYPTION_FAILED ); log_error(_("decryption failed: %s\n"), g10_errstr(result)); /* Hmmm: does this work when we have encrypted using a multiple * ways to specify the session key (symmmetric and PK)*/ } free_packet(pkt); c->last_was_session_key = 0; } static void proc_plaintext( CTX c, PACKET *pkt ) { PKT_plaintext *pt = pkt->pkt.plaintext; int any, clearsig, only_md5, rc; KBNODE n; if( pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8 ) ) log_info(_("NOTE: sender requested \"for-your-eyes-only\"\n")); else if( opt.verbose ) log_info(_("original file name='%.*s'\n"), pt->namelen, pt->name); free_md_filter_context( &c->mfx ); c->mfx.md = md_open( 0, 0); /* fixme: we may need to push the textfilter if we have sigclass 1 * and no armoring - Not yet tested * Hmmm, why don't we need it at all if we have sigclass 1 * Should we assume that plaintext in mode 't' has always sigclass 1?? * See: Russ Allbery's mail 1999-02-09 */ any = clearsig = only_md5 = 0; for(n=c->list; n; n = n->next ) { if( n->pkt->pkttype == PKT_ONEPASS_SIG ) { if( n->pkt->pkt.onepass_sig->digest_algo ) { md_enable( c->mfx.md, n->pkt->pkt.onepass_sig->digest_algo ); if( !any && n->pkt->pkt.onepass_sig->digest_algo == DIGEST_ALGO_MD5 ) only_md5 = 1; else only_md5 = 0; any = 1; } if( n->pkt->pkt.onepass_sig->sig_class != 0x01 ) only_md5 = 0; /* Check whether this is a cleartext signature. We assume that * we have one if the sig_class is 1 and the keyid is 0, that * are the faked packets produced by armor.c. There is a * possibility that this fails, but there is no other easy way * to do it. (We could use a special packet type to indicate * this, but this may also be faked - it simply can't be verified * and is _no_ security issue) */ if( n->pkt->pkt.onepass_sig->sig_class == 0x01 && !n->pkt->pkt.onepass_sig->keyid[0] && !n->pkt->pkt.onepass_sig->keyid[1] ) clearsig = 1; } } if( !any ) { /* no onepass sig packet: enable all standard algos */ md_enable( c->mfx.md, DIGEST_ALGO_RMD160 ); md_enable( c->mfx.md, DIGEST_ALGO_SHA1 ); md_enable( c->mfx.md, DIGEST_ALGO_MD5 ); } if( only_md5 ) { /* This is a kludge to work around a bug in pgp2. It does only * catch those mails which are armored. To catch the non-armored * pgp mails we could see whether there is the signature packet * in front of the plaintext. If someone needs this, send me a patch. */ c->mfx.md2 = md_open( DIGEST_ALGO_MD5, 0); } #if 0 #warning md_start_debug is enabled md_start_debug( c->mfx.md, "verify" ); #endif rc = handle_plaintext( pt, &c->mfx, c->sigs_only, clearsig ); if( rc == G10ERR_CREATE_FILE && !c->sigs_only) { /* can't write output but we hash it anyway to * check the signature */ rc = handle_plaintext( pt, &c->mfx, 1, clearsig ); } if( rc ) log_error( "handle plaintext failed: %s\n", g10_errstr(rc)); free_packet(pkt); c->last_was_session_key = 0; } static int proc_compressed_cb( IOBUF a, void *info ) { return proc_signature_packets( info, a, ((CTX)info)->signed_data, ((CTX)info)->sigfilename ); } static int proc_encrypt_cb( IOBUF a, void *info ) { return proc_encryption_packets( info, a ); } static void proc_compressed( CTX c, PACKET *pkt ) { PKT_compressed *zd = pkt->pkt.compressed; int rc; /*printf("zip: compressed data packet\n");*/ if( c->sigs_only ) rc = handle_compressed( c, zd, proc_compressed_cb, c ); else if( c->encrypt_only ) rc = handle_compressed( c, zd, proc_encrypt_cb, c ); else rc = handle_compressed( c, zd, NULL, NULL ); if( rc ) log_error("uncompressing failed: %s\n", g10_errstr(rc)); free_packet(pkt); c->last_was_session_key = 0; } /**************** * check the signature * Returns: 0 = valid signature or an error code */ static int do_check_sig( CTX c, KBNODE node, int *is_selfsig ) { PKT_signature *sig; MD_HANDLE md = NULL, md2 = NULL; int algo, rc; assert( node->pkt->pkttype == PKT_SIGNATURE ); if( is_selfsig ) *is_selfsig = 0; sig = node->pkt->pkt.signature; algo = sig->digest_algo; if( (rc=check_digest_algo(algo)) ) return rc; if( sig->sig_class == 0x00 ) { if( c->mfx.md ) md = md_copy( c->mfx.md ); else /* detached signature */ md = md_open( 0, 0 ); /* signature_check() will enable the md*/ } else if( sig->sig_class == 0x01 ) { /* how do we know that we have to hash the (already hashed) text * in canonical mode ??? (calculating both modes???) */ if( c->mfx.md ) { md = md_copy( c->mfx.md ); if( c->mfx.md2 ) md2 = md_copy( c->mfx.md2 ); } else { /* detached signature */ log_debug("Do we really need this here?"); md = md_open( 0, 0 ); /* signature_check() will enable the md*/ md2 = md_open( 0, 0 ); } } else if( (sig->sig_class&~3) == 0x10 || sig->sig_class == 0x18 || sig->sig_class == 0x20 || sig->sig_class == 0x30 ) { /* classes 0x10..0x17,0x20,0x30 */ if( c->list->pkt->pkttype == PKT_PUBLIC_KEY || c->list->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { return check_key_signature( c->list, node, is_selfsig ); } else { log_error("invalid root packet for sigclass %02x\n", sig->sig_class); return G10ERR_SIG_CLASS; } } else return G10ERR_SIG_CLASS; rc = signature_check( sig, md ); if( rc == G10ERR_BAD_SIGN && md2 ) rc = signature_check( sig, md2 ); md_close(md); md_close(md2); return rc; } static void print_userid( PACKET *pkt ) { if( !pkt ) BUG(); if( pkt->pkttype != PKT_USER_ID ) { printf("ERROR: unexpected packet type %d", pkt->pkttype ); return; } print_string( stdout, pkt->pkt.user_id->name, pkt->pkt.user_id->len, opt.with_colons ); } static void print_fingerprint( PKT_public_key *pk, PKT_secret_key *sk ) { byte array[MAX_FINGERPRINT_LEN], *p; size_t i, n; if( sk ) fingerprint_from_sk( sk, array, &n ); else fingerprint_from_pk( pk, array, &n ); p = array; if( opt.with_colons ) { printf("fpr:::::::::"); for(i=0; i < n ; i++, p++ ) printf("%02X", *p ); putchar(':'); } else { printf(" Key fingerprint ="); if( n == 20 ) { for(i=0; i < n ; i++, i++, p += 2 ) { if( i == 10 ) putchar(' '); printf(" %02X%02X", *p, p[1] ); } } else { for(i=0; i < n ; i++, p++ ) { if( i && !(i%8) ) putchar(' '); printf(" %02X", *p ); } } } putchar('\n'); } static void print_notation_data( PKT_signature *sig ) { size_t n, n1, n2; const byte *p; int seq = 0; while( (p = enum_sig_subpkt( sig->hashed_data, SIGSUBPKT_NOTATION, &n, &seq )) ) { if( n < 8 ) { log_info(_("WARNING: invalid notation data found\n")); return; } if( !(*p & 0x80) ) return; /* not human readable */ n1 = (p[4] << 8) | p[5]; n2 = (p[6] << 8) | p[7]; p += 8; if( 8+n1+n2 != n ) { log_info(_("WARNING: invalid notation data found\n")); return; } log_info(_("Notation: ") ); print_string( log_stream(), p, n1, 0 ); putc( '=', log_stream() ); print_string( log_stream(), p+n1, n2, 0 ); putc( '\n', log_stream() ); } if( (p = parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_POLICY, &n ) )) { log_info(_("Policy: ") ); print_string( log_stream(), p, n, 0 ); putc( '\n', log_stream() ); } /* Now check wheter the key of this signature has some * notation data */ /* TODO */ } /**************** * List the certificate in a user friendly way */ static void list_node( CTX c, KBNODE node ) { int any=0; int mainkey; if( !node ) ; else if( (mainkey = (node->pkt->pkttype == PKT_PUBLIC_KEY) ) || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { PKT_public_key *pk = node->pkt->pkt.public_key; if( opt.with_colons ) { u32 keyid[2]; keyid_from_pk( pk, keyid ); if( mainkey ) { c->local_id = pk->local_id; c->trustletter = query_trust_info( pk, NULL ); } printf("%s:%c:%u:%d:%08lX%08lX:%s:%s:", mainkey? "pub":"sub", c->trustletter, nbits_from_pk( pk ), pk->pubkey_algo, (ulong)keyid[0],(ulong)keyid[1], datestr_from_pk( pk ), pk->expiredate? strtimestamp(pk->expiredate):"" ); if( c->local_id ) printf("%lu", c->local_id ); putchar(':'); if( c->local_id ) putchar( get_ownertrust_info( c->local_id ) ); putchar(':'); if( node->next && node->next->pkt->pkttype == PKT_RING_TRUST) { putchar('\n'); any=1; if( opt.fingerprint ) print_fingerprint( pk, NULL ); printf("rtv:1:%u:\n", node->next->pkt->pkt.ring_trust->trustval ); } } else printf("%s %4u%c/%08lX %s ", mainkey? "pub":"sub", nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ), (ulong)keyid_from_pk( pk, NULL ), datestr_from_pk( pk ) ); if( mainkey ) { /* and now list all userids with their signatures */ for( node = node->next; node; node = node->next ) { if( node->pkt->pkttype == PKT_SIGNATURE ) { if( !any ) { if( node->pkt->pkt.signature->sig_class == 0x20 ) puts("[revoked]"); else putchar('\n'); any = 1; } list_node(c, node ); } else if( node->pkt->pkttype == PKT_USER_ID ) { if( any ) { if( opt.with_colons ) printf("uid:::::::::"); else printf( "uid%*s", 28, "" ); } print_userid( node->pkt ); if( opt.with_colons ) putchar(':'); putchar('\n'); if( opt.fingerprint && !any ) print_fingerprint( pk, NULL ); if( node->next && node->next->pkt->pkttype == PKT_RING_TRUST ) { printf("rtv:2:%u:\n", node->next->pkt->pkt.ring_trust->trustval ); } any=1; } else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { if( !any ) { putchar('\n'); any = 1; } list_node(c, node ); } } } if( !any ) putchar('\n'); if( !mainkey && opt.fingerprint > 1 ) print_fingerprint( pk, NULL ); } else if( (mainkey = (node->pkt->pkttype == PKT_SECRET_KEY) ) || node->pkt->pkttype == PKT_SECRET_SUBKEY ) { PKT_secret_key *sk = node->pkt->pkt.secret_key; if( opt.with_colons ) { u32 keyid[2]; keyid_from_sk( sk, keyid ); printf("%s::%u:%d:%08lX%08lX:%s:%s:::", mainkey? "sec":"ssb", nbits_from_sk( sk ), sk->pubkey_algo, (ulong)keyid[0],(ulong)keyid[1], datestr_from_sk( sk ), sk->expiredate? strtimestamp(sk->expiredate):"" /* fixme: add LID */ ); } else printf("%s %4u%c/%08lX %s ", mainkey? "sec":"ssb", nbits_from_sk( sk ), pubkey_letter( sk->pubkey_algo ), (ulong)keyid_from_sk( sk, NULL ), datestr_from_sk( sk ) ); if( mainkey ) { /* and now list all userids with their signatures */ for( node = node->next; node; node = node->next ) { if( node->pkt->pkttype == PKT_SIGNATURE ) { if( !any ) { if( node->pkt->pkt.signature->sig_class == 0x20 ) puts("[revoked]"); else putchar('\n'); any = 1; } list_node(c, node ); } else if( node->pkt->pkttype == PKT_USER_ID ) { if( any ) { if( opt.with_colons ) printf("uid:::::::::"); else printf( "uid%*s", 28, "" ); } print_userid( node->pkt ); if( opt.with_colons ) putchar(':'); putchar('\n'); if( opt.fingerprint && !any ) print_fingerprint( NULL, sk ); any=1; } else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) { if( !any ) { putchar('\n'); any = 1; } list_node(c, node ); } } } if( !any ) putchar('\n'); if( !mainkey && opt.fingerprint > 1 ) print_fingerprint( NULL, sk ); } else if( node->pkt->pkttype == PKT_SIGNATURE ) { PKT_signature *sig = node->pkt->pkt.signature; int is_selfsig = 0; int rc2=0; size_t n; char *p; int sigrc = ' '; if( !opt.list_sigs ) return; if( sig->sig_class == 0x20 || sig->sig_class == 0x30 ) fputs("rev", stdout); else fputs("sig", stdout); if( opt.check_sigs ) { fflush(stdout); switch( (rc2=do_check_sig( c, node, &is_selfsig )) ) { case 0: sigrc = '!'; break; case G10ERR_BAD_SIGN: sigrc = '-'; break; case G10ERR_NO_PUBKEY: sigrc = '?'; break; default: sigrc = '%'; break; } } else { /* check whether this is a self signature */ u32 keyid[2]; if( c->list->pkt->pkttype == PKT_PUBLIC_KEY || c->list->pkt->pkttype == PKT_SECRET_KEY ) { if( c->list->pkt->pkttype == PKT_PUBLIC_KEY ) keyid_from_pk( c->list->pkt->pkt.public_key, keyid ); else keyid_from_sk( c->list->pkt->pkt.secret_key, keyid ); if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] ) is_selfsig = 1; } } if( opt.with_colons ) { putchar(':'); if( sigrc != ' ' ) putchar(sigrc); printf(":::%08lX%08lX:%s::::", (ulong)sig->keyid[0], (ulong)sig->keyid[1], datestr_from_sig(sig)); } else printf("%c %08lX %s ", sigrc, (ulong)sig->keyid[1], datestr_from_sig(sig)); if( sigrc == '%' ) printf("[%s] ", g10_errstr(rc2) ); else if( sigrc == '?' ) ; else if( is_selfsig ) { if( opt.with_colons ) putchar(':'); fputs( sig->sig_class == 0x18? "[keybind]":"[selfsig]", stdout); if( opt.with_colons ) putchar(':'); } else { p = get_user_id( sig->keyid, &n ); print_string( stdout, p, n, opt.with_colons ); m_free(p); } if( opt.with_colons ) printf(":%02x:", sig->sig_class ); putchar('\n'); } else log_error("invalid node with packet of type %d\n", node->pkt->pkttype); } int proc_packets( void *anchor, IOBUF a ) { int rc; CTX c = m_alloc_clear( sizeof *c ); c->anchor = anchor; rc = do_proc_packets( c, a ); m_free( c ); return rc; } int proc_signature_packets( void *anchor, IOBUF a, STRLIST signedfiles, const char *sigfilename ) { CTX c = m_alloc_clear( sizeof *c ); int rc; c->anchor = anchor; c->sigs_only = 1; c->signed_data = signedfiles; c->sigfilename = sigfilename; rc = do_proc_packets( c, a ); m_free( c ); return rc; } int proc_encryption_packets( void *anchor, IOBUF a ) { CTX c = m_alloc_clear( sizeof *c ); int rc; c->anchor = anchor; c->encrypt_only = 1; rc = do_proc_packets( c, a ); m_free( c ); return rc; } int do_proc_packets( CTX c, IOBUF a ) { PACKET *pkt = m_alloc( sizeof *pkt ); int rc=0; int any_data=0; int newpkt; c->iobuf = a; init_packet(pkt); while( (rc=parse_packet(a, pkt)) != -1 ) { any_data = 1; if( rc ) { free_packet(pkt); if( rc == G10ERR_INVALID_PACKET ) break; continue; } newpkt = -1; if( opt.list_packets ) { switch( pkt->pkttype ) { case PKT_PUBKEY_ENC: proc_pubkey_enc( c, pkt ); break; case PKT_SYMKEY_ENC: proc_symkey_enc( c, pkt ); break; case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: proc_encrypted( c, pkt ); break; case PKT_COMPRESSED: proc_compressed( c, pkt ); break; default: newpkt = 0; break; } } else if( c->sigs_only ) { switch( pkt->pkttype ) { case PKT_PUBLIC_KEY: case PKT_SECRET_KEY: case PKT_USER_ID: case PKT_SYMKEY_ENC: case PKT_PUBKEY_ENC: case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: rc = G10ERR_UNEXPECTED; goto leave; case PKT_SIGNATURE: newpkt = add_signature( c, pkt ); break; case PKT_PLAINTEXT: proc_plaintext( c, pkt ); break; case PKT_COMPRESSED: proc_compressed( c, pkt ); break; case PKT_ONEPASS_SIG: newpkt = add_onepass_sig( c, pkt ); break; default: newpkt = 0; break; } } else if( c->encrypt_only ) { switch( pkt->pkttype ) { case PKT_PUBLIC_KEY: case PKT_SECRET_KEY: case PKT_USER_ID: rc = G10ERR_UNEXPECTED; goto leave; case PKT_SIGNATURE: newpkt = add_signature( c, pkt ); break; case PKT_SYMKEY_ENC: proc_symkey_enc( c, pkt ); break; case PKT_PUBKEY_ENC: proc_pubkey_enc( c, pkt ); break; case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: proc_encrypted( c, pkt ); break; case PKT_PLAINTEXT: proc_plaintext( c, pkt ); break; case PKT_COMPRESSED: proc_compressed( c, pkt ); break; case PKT_ONEPASS_SIG: newpkt = add_onepass_sig( c, pkt ); break; default: newpkt = 0; break; } } else { switch( pkt->pkttype ) { case PKT_PUBLIC_KEY: case PKT_SECRET_KEY: release_list( c ); c->list = new_kbnode( pkt ); newpkt = 1; break; case PKT_PUBLIC_SUBKEY: case PKT_SECRET_SUBKEY: newpkt = add_subkey( c, pkt ); break; case PKT_USER_ID: newpkt = add_user_id( c, pkt ); break; case PKT_SIGNATURE: newpkt = add_signature( c, pkt ); break; case PKT_PUBKEY_ENC: proc_pubkey_enc( c, pkt ); break; case PKT_SYMKEY_ENC: proc_symkey_enc( c, pkt ); break; case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: proc_encrypted( c, pkt ); break; case PKT_PLAINTEXT: proc_plaintext( c, pkt ); break; case PKT_COMPRESSED: proc_compressed( c, pkt ); break; case PKT_ONEPASS_SIG: newpkt = add_onepass_sig( c, pkt ); break; case PKT_RING_TRUST: newpkt = add_ring_trust( c, pkt ); break; default: newpkt = 0; break; } } if( pkt->pkttype != PKT_SIGNATURE ) c->have_data = pkt->pkttype == PKT_PLAINTEXT; if( newpkt == -1 ) ; else if( newpkt ) { pkt = m_alloc( sizeof *pkt ); init_packet(pkt); } else free_packet(pkt); } if( rc == G10ERR_INVALID_PACKET ) write_status_text( STATUS_NODATA, "3" ); if( any_data ) rc = 0; else if( rc == -1 ) write_status_text( STATUS_NODATA, "2" ); leave: release_list( c ); m_free(c->dek); free_packet( pkt ); m_free( pkt ); free_md_filter_context( &c->mfx ); return rc; } static int check_sig_and_print( CTX c, KBNODE node ) { PKT_signature *sig = node->pkt->pkt.signature; const char *astr, *tstr; int rc; if( opt.skip_verify ) { log_info(_("signature verification suppressed\n")); return 0; } tstr = asctimestamp(sig->timestamp); astr = pubkey_algo_to_string( sig->pubkey_algo ); log_info(_("Signature made %.*s using %s key ID %08lX\n"), (int)strlen(tstr), tstr, astr? astr: "?", (ulong)sig->keyid[1] ); rc = do_check_sig(c, node, NULL ); if( rc == G10ERR_NO_PUBKEY && opt.keyserver_name ) { if( !hkp_ask_import( sig->keyid ) ) rc = do_check_sig(c, node, NULL ); } if( !rc || rc == G10ERR_BAD_SIGN ) { KBNODE un, keyblock; char *us; int count=0; keyblock = get_pubkeyblock( sig->keyid ); us = get_long_user_id_string( sig->keyid ); write_status_text( rc? STATUS_BADSIG : STATUS_GOODSIG, us ); m_free(us); /* fixme: list only user ids which are valid and add information * about the trustworthiness of each user id, sort them. * Integrate this with check_signatures_trust(). */ for( un=keyblock; un; un = un->next ) { if( un->pkt->pkttype != PKT_USER_ID ) continue; if( !count++ ) log_info(rc? _("BAD signature from \"") : _("Good signature from \"")); else log_info( _(" aka \"")); print_string( log_stream(), un->pkt->pkt.user_id->name, un->pkt->pkt.user_id->len, '\"' ); fputs("\"\n", log_stream() ); if( rc ) break; /* print only one id in this case */ } if( !count ) { /* just in case that we have no userid */ log_info(rc? _("BAD signature from \"") : _("Good signature from \"")); fputs("[?]\"\n", log_stream() ); } release_kbnode( keyblock ); if( !rc ) print_notation_data( sig ); if( !rc && is_status_enabled() ) { /* print a status response with the fingerprint */ PKT_public_key *pk = m_alloc_clear( sizeof *pk ); if( !get_pubkey( pk, sig->keyid ) ) { byte array[MAX_FINGERPRINT_LEN], *p; char buf[MAX_FINGERPRINT_LEN*2+61]; size_t i, n; fingerprint_from_pk( pk, array, &n ); p = array; for(i=0; i < n ; i++, p++ ) sprintf(buf+2*i, "%02X", *p ); sprintf(buf+strlen(buf), " %s %lu", strtimestamp( sig->timestamp ), (ulong)sig->timestamp ); write_status_text( STATUS_VALIDSIG, buf ); } free_public_key( pk ); } if( !rc ) rc = check_signatures_trust( sig ); if( rc ) g10_errors_seen = 1; if( opt.batch && rc ) g10_exit(1); } else { char buf[50]; sprintf(buf, "%08lX%08lX %d %d %02x %lu %d", (ulong)sig->keyid[0], (ulong)sig->keyid[1], sig->pubkey_algo, sig->digest_algo, sig->sig_class, (ulong)sig->timestamp, rc ); write_status_text( STATUS_ERRSIG, buf ); if( rc == G10ERR_NO_PUBKEY ) { buf[16] = 0; write_status_text( STATUS_NO_PUBKEY, buf ); } log_error(_("Can't check signature: %s\n"), g10_errstr(rc) ); } return rc; } /**************** * Process the tree which starts at node */ static void proc_tree( CTX c, KBNODE node ) { KBNODE n1; int rc; if( opt.list_packets ) return; c->local_id = 0; c->trustletter = ' '; if( node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { merge_keys_and_selfsig( node ); list_node( c, node ); } else if( node->pkt->pkttype == PKT_SECRET_KEY ) { merge_keys_and_selfsig( node ); list_node( c, node ); } else if( node->pkt->pkttype == PKT_ONEPASS_SIG ) { /* check all signatures */ if( !c->have_data ) { free_md_filter_context( &c->mfx ); /* prepare to create all requested message digests */ c->mfx.md = md_open(0, 0); /* fixme: why looking for the signature packet and not 1passpacket*/ for( n1 = node; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )); ) { md_enable( c->mfx.md, n1->pkt->pkt.signature->digest_algo); } /* ask for file and hash it */ 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 ); else - rc = ask_for_detached_datafile( &c->mfx, - iobuf_get_fname(c->iobuf)); + rc = ask_for_detached_datafile( c->mfx.md, c->mfx.md2, + iobuf_get_fname(c->iobuf), 0 ); if( rc ) { log_error("can't hash datafile: %s\n", g10_errstr(rc)); return; } } for( n1 = node; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )); ) check_sig_and_print( c, n1 ); } else if( node->pkt->pkttype == PKT_SIGNATURE ) { PKT_signature *sig = node->pkt->pkt.signature; if( !c->have_data ) { + /* detached signature */ free_md_filter_context( &c->mfx ); c->mfx.md = md_open(sig->digest_algo, 0); if( sig->digest_algo == DIGEST_ALGO_MD5 && is_RSA( sig->pubkey_algo ) ) { /* enable a workaround for a pgp2 bug */ c->mfx.md2 = md_open( DIGEST_ALGO_MD5, 0 ); } - #if 0 - #warning md_start_debug enabled - md_start_debug( c->mfx.md, "det1" ); - if( c->mfx.md2 ) - md_start_debug( c->mfx.md2, "det2" ); - #endif + else if( sig->digest_algo == DIGEST_ALGO_SHA1 + && sig->pubkey_algo == PUBKEY_ALGO_DSA + && sig->sig_class == 0x01 ) { + /* enable the workaround also for pgp5 when the detached + * signature has been created in textmode */ + c->mfx.md2 = md_open( sig->digest_algo, 0 ); + } /* Here we have another hack to work around a pgp 2 bug * It works by not using the textmode for detached signatures; - * this will let the first signazure check (on md) fail + * this will let the first signature check (on md) fail * but the second one (on md2) which adds an extra CR should * then produce the "correct" hash. This is very, very ugly * hack but it may help in some cases (and break others) */ if( c->sigs_only ) rc = hash_datafiles( c->mfx.md, c->mfx.md2, c->signed_data, c->sigfilename, - c->mfx.md2? 0 :(sig->sig_class == 0x01) ); + c->mfx.md2? 0 :(sig->sig_class == 0x01) ); else - rc = ask_for_detached_datafile( &c->mfx, - iobuf_get_fname(c->iobuf)); + rc = ask_for_detached_datafile( c->mfx.md, c->mfx.md2, + iobuf_get_fname(c->iobuf), + c->mfx.md2? 0 :(sig->sig_class == 0x01) ); if( rc ) { log_error("can't hash datafile: %s\n", g10_errstr(rc)); return; } } else log_info(_("old style (PGP 2.x) signature\n")); check_sig_and_print( c, node ); } else log_error(_("invalid root packet detected in proc_tree()\n")); } diff --git a/g10/packet.h b/g10/packet.h index 91253ebe2..50ea65b3f 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -1,353 +1,354 @@ /* packet.h - packet read/write stuff * Copyright (C) 1998 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_PACKET_H #define G10_PACKET_H #include "types.h" #include "iobuf.h" #include "mpi.h" #include "cipher.h" #include "filter.h" #define DEBUG_PARSE_PACKET 1 typedef enum { PKT_NONE =0, PKT_PUBKEY_ENC =1, /* public key encrypted packet */ PKT_SIGNATURE =2, /* secret key encrypted packet */ PKT_SYMKEY_ENC =3, /* session key packet (OpenPGP)*/ PKT_ONEPASS_SIG =4, /* one pass sig packet (OpenPGP)*/ PKT_SECRET_KEY =5, /* secret key */ PKT_PUBLIC_KEY =6, /* public key */ PKT_SECRET_SUBKEY =7, /* secret subkey (OpenPGP) */ PKT_COMPRESSED =8, /* compressed data packet */ PKT_ENCRYPTED =9, /* conventional encrypted data */ PKT_MARKER =10, /* marker packet (OpenPGP) */ PKT_PLAINTEXT =11, /* plaintext data with filename and mode */ PKT_RING_TRUST =12, /* keyring trust packet */ PKT_USER_ID =13, /* user id packet */ PKT_PUBLIC_SUBKEY =14, /* public subkey (OpenPGP) */ PKT_OLD_COMMENT =16, /* comment packet from an OpenPGP draft */ PKT_COMMENT =61, /* new comment packet (private) */ PKT_ENCRYPTED_MDC =62, /* test: encrypted data with MDC */ } pkttype_t; typedef struct packet_struct PACKET; typedef struct { byte mode; byte hash_algo; byte salt[8]; u32 count; } STRING2KEY; typedef struct { byte version; byte cipher_algo; /* cipher algorithm used */ STRING2KEY s2k; byte seskeylen; /* keylength in byte or 0 for no seskey */ byte seskey[1]; } PKT_symkey_enc; typedef struct { u32 keyid[2]; /* 64 bit keyid */ byte version; byte pubkey_algo; /* algorithm used for public key scheme */ byte throw_keyid; MPI data[PUBKEY_MAX_NENC]; } PKT_pubkey_enc; typedef struct { u32 keyid[2]; /* 64 bit keyid */ byte sig_class; /* sig classification */ byte digest_algo; /* algorithm used for digest */ byte pubkey_algo; /* algorithm used for public key scheme */ byte last; /* a stupid flag */ } PKT_onepass_sig; typedef struct { ulong local_id; /* internal use, valid if > 0 */ struct { unsigned checked:1; /* signature has been checked */ unsigned valid:1; /* signature is good (if checked is set) */ unsigned unknown_critical:1; } flags; u32 keyid[2]; /* 64 bit keyid */ u32 timestamp; /* signature made */ byte version; byte sig_class; /* sig classification, append for MD calculation*/ byte pubkey_algo; /* algorithm used for public key scheme */ /* (PUBKEY_ALGO_xxx) */ byte digest_algo; /* algorithm used for digest (DIGEST_ALGO_xxxx) */ byte *hashed_data; /* all subpackets with hashed data (v4 only) */ byte *unhashed_data; /* ditto for unhashed data */ byte digest_start[2]; /* first 2 bytes of the digest */ MPI data[PUBKEY_MAX_NSIG]; } PKT_signature; /**************** * Note about the pkey/skey elements: We assume that the secret keys * has the same elemts as the public key at the begin of the array, so * that npkey < nskey and it is possible to compare the secret and * public keys by comparing the first npkey elements of pkey againts skey. */ typedef struct { u32 timestamp; /* key made */ u32 expiredate; /* expires at this date or 0 if not at all */ byte hdrbytes; /* number of header bytes */ byte version; byte pubkey_algo; /* algorithm used for public key scheme */ byte pubkey_usage; /* for now only used to pass it to getkey() */ ulong local_id; /* internal use, valid if > 0 */ u32 keyid[2]; /* calculated by keyid_from_pk() */ byte *namehash; /* if != NULL: found by this name */ MPI pkey[PUBKEY_MAX_NPKEY]; } PKT_public_key; typedef struct { u32 timestamp; /* key made */ u32 expiredate; /* expires at this date or 0 if not at all */ byte hdrbytes; /* number of header bytes */ byte version; byte pubkey_algo; /* algorithm used for public key scheme */ byte pubkey_usage; byte is_primary; byte is_protected; /* The secret info is protected and must */ /* be decrypted before use, the protected */ /* MPIs are simply (void*) pointers to memory */ /* and should never be passed to a mpi_xxx() */ struct { byte algo; /* cipher used to protect the secret information*/ STRING2KEY s2k; byte ivlen; /* used length of the iv */ byte iv[16]; /* initialization vector for CFB mode */ } protect; MPI skey[PUBKEY_MAX_NSKEY]; u16 csum; /* checksum */ } PKT_secret_key; typedef struct { int len; /* length of data */ char data[1]; } PKT_comment; typedef struct { int len; /* length of the name */ char name[1]; } PKT_user_id; typedef struct { u32 len; /* reserved */ byte new_ctb; byte algorithm; IOBUF buf; /* IOBUF reference */ } PKT_compressed; typedef struct { u32 len; /* length of encrypted data */ byte new_ctb; /* uses a new CTB */ byte mdc_method; /* test: > 0: this is is an encrypted_mdc packet */ IOBUF buf; /* IOBUF reference */ } PKT_encrypted; typedef struct { unsigned int trustval; } PKT_ring_trust; typedef struct { u32 len; /* length of encrypted data */ IOBUF buf; /* IOBUF reference */ byte new_ctb; int mode; u32 timestamp; int namelen; char name[1]; } PKT_plaintext; /* combine all packets into a union */ struct packet_struct { pkttype_t pkttype; union { void *generic; PKT_symkey_enc *symkey_enc; /* PKT_SYMKEY_ENC */ PKT_pubkey_enc *pubkey_enc; /* PKT_PUBKEY_ENC */ PKT_onepass_sig *onepass_sig; /* PKT_ONEPASS_SIG */ PKT_signature *signature; /* PKT_SIGNATURE */ PKT_public_key *public_key; /* PKT_PUBLIC_[SUB)KEY */ PKT_secret_key *secret_key; /* PKT_SECRET_[SUB]KEY */ PKT_comment *comment; /* PKT_COMMENT */ PKT_user_id *user_id; /* PKT_USER_ID */ PKT_compressed *compressed; /* PKT_COMPRESSED */ PKT_encrypted *encrypted; /* PKT_ENCRYPTED[_MDC] */ PKT_ring_trust *ring_trust; /* PKT_RING_TRUST */ PKT_plaintext *plaintext; /* PKT_PLAINTEXT */ } pkt; }; #define init_packet(a) do { (a)->pkttype = 0; \ (a)->pkt.generic = NULL; \ } while(0) typedef enum { SIGSUBPKT_TEST_CRITICAL=-3, SIGSUBPKT_LIST_UNHASHED=-2, SIGSUBPKT_LIST_HASHED =-1, SIGSUBPKT_NONE = 0, SIGSUBPKT_SIG_CREATED = 2, /* signature creation time */ SIGSUBPKT_SIG_EXPIRE = 3, /* signature expiration time */ SIGSUBPKT_EXPORTABLE = 4, /* exportable */ SIGSUBPKT_TRUST = 5, /* trust signature */ SIGSUBPKT_REGEXP = 6, /* regular expression */ SIGSUBPKT_REVOCABLE = 7, /* revocable */ SIGSUBPKT_KEY_EXPIRE = 9, /* key expiration time */ SIGSUBPKT_ARR =10, /* additional recipient request */ SIGSUBPKT_PREF_SYM =11, /* preferred symmetric algorithms */ SIGSUBPKT_REV_KEY =12, /* revocation key */ SIGSUBPKT_ISSUER =16, /* issuer key ID */ SIGSUBPKT_NOTATION =20, /* notation data */ SIGSUBPKT_PREF_HASH =21, /* preferred hash algorithms */ SIGSUBPKT_PREF_COMPR =22, /* preferred compression algorithms */ SIGSUBPKT_KS_FLAGS =23, /* key server preferences */ SIGSUBPKT_PREF_KS =24, /* preferred key server */ SIGSUBPKT_PRIMARY_UID =25, /* primary user id */ SIGSUBPKT_POLICY =26, /* policy URL */ SIGSUBPKT_KEY_FLAGS =27, /* key flags */ SIGSUBPKT_SIGNERS_UID =28, /* signer's user id */ SIGSUBPKT_PRIV_ADD_SIG =101,/* signatur is also valid for this uid */ SIGSUBPKT_FLAG_CRITICAL=128 } sigsubpkttype_t; /*-- mainproc.c --*/ int proc_packets( void *ctx, IOBUF a ); int proc_signature_packets( void *ctx, IOBUF a, STRLIST signedfiles, const char *sigfile ); int proc_encryption_packets( void *ctx, IOBUF a ); int list_packets( IOBUF a ); /*-- parse-packet.c --*/ int set_packet_list_mode( int mode ); #if DEBUG_PARSE_PACKET int dbg_search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos, const char* file, int lineno ); int dbg_parse_packet( IOBUF inp, PACKET *ret_pkt, const char* file, int lineno ); int dbg_copy_all_packets( IOBUF inp, IOBUF out, const char* file, int lineno ); int dbg_copy_some_packets( IOBUF inp, IOBUF out, ulong stopoff, const char* file, int lineno ); int dbg_skip_some_packets( IOBUF inp, unsigned n, const char* file, int lineno ); #define search_packet( a,b,c,d ) dbg_search_packet( (a), (b), (c), (d), __FILE__, __LINE__ ) #define parse_packet( a, b ) dbg_parse_packet( (a), (b), __FILE__, __LINE__ ) #define copy_all_packets( a,b ) dbg_copy_all_packets((a),(b), __FILE__, __LINE__ ) #define copy_some_packets( a,b,c ) dbg_copy_some_packets((a),(b),(c), __FILE__, __LINE__ ) #define skip_some_packets( a,b ) dbg_skip_some_packets((a),(b), __FILE__, __LINE__ ) #else int search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos ); int parse_packet( IOBUF inp, PACKET *ret_pkt); int copy_all_packets( IOBUF inp, IOBUF out ); int copy_some_packets( IOBUF inp, IOBUF out, ulong stopoff ); int skip_some_packets( IOBUF inp, unsigned n ); #endif const byte *enum_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, size_t *ret_n, int *start ); const byte *parse_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, size_t *ret_n ); const byte *parse_sig_subpkt2( PKT_signature *sig, sigsubpkttype_t reqtype, size_t *ret_n ); /*-- build-packet.c --*/ int build_packet( IOBUF inp, PACKET *pkt ); u32 calc_packet_length( PACKET *pkt ); void hash_public_key( MD_HANDLE md, PKT_public_key *pk ); void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type, const byte *buffer, size_t buflen ); void build_sig_subpkt_from_sig( PKT_signature *sig ); /*-- free-packet.c --*/ void free_symkey_enc( PKT_symkey_enc *enc ); void free_pubkey_enc( PKT_pubkey_enc *enc ); void free_seckey_enc( PKT_signature *enc ); int digest_algo_from_sig( PKT_signature *sig ); void release_public_key_parts( PKT_public_key *pk ); void free_public_key( PKT_public_key *key ); void release_secret_key_parts( PKT_secret_key *sk ); void free_secret_key( PKT_secret_key *sk ); void free_user_id( PKT_user_id *uid ); void free_comment( PKT_comment *rem ); void free_packet( PACKET *pkt ); PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s ); PKT_public_key *copy_public_key_new_namehash( PKT_public_key *d, PKT_public_key *s, const byte *namehash ); PKT_secret_key *copy_secret_key( PKT_secret_key *d, PKT_secret_key *s ); PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s ); PKT_user_id *copy_user_id( PKT_user_id *d, PKT_user_id *s ); int cmp_public_keys( PKT_public_key *a, PKT_public_key *b ); int cmp_secret_keys( PKT_secret_key *a, PKT_secret_key *b ); int cmp_signatures( PKT_signature *a, PKT_signature *b ); int cmp_public_secret_key( PKT_public_key *pk, PKT_secret_key *sk ); int cmp_user_ids( PKT_user_id *a, PKT_user_id *b ); /*-- sig-check.c --*/ int signature_check( PKT_signature *sig, MD_HANDLE digest ); /*-- seckey-cert.c --*/ int is_secret_key_protected( PKT_secret_key *sk ); int check_secret_key( PKT_secret_key *sk, int retries ); int protect_secret_key( PKT_secret_key *sk, DEK *dek ); /*-- pubkey-enc.c --*/ int get_session_key( PKT_pubkey_enc *k, DEK *dek ); /*-- compress.c --*/ int handle_compressed( void *ctx, PKT_compressed *cd, int (*callback)(IOBUF, void *), void *passthru ); /*-- encr-data.c --*/ int decrypt_data( void *ctx, PKT_encrypted *ed, DEK *dek ); int encrypt_data( PKT_encrypted *ed, DEK *dek ); /*-- plaintext.c --*/ int handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx, int nooutput, int clearsig ); -int ask_for_detached_datafile( md_filter_context_t *mfx, const char *inname ); +int ask_for_detached_datafile( MD_HANDLE md, MD_HANDLE md2, + const char *inname, int textmode ); /*-- comment.c --*/ int write_comment( IOBUF out, const char *s ); /*-- sign.c --*/ int make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk, PKT_user_id *uid, PKT_public_key *subpk, PKT_secret_key *sk, int sigclass, int digest_algo, int (*mksubpkt)(PKT_signature *, void *), void *opaque ); /*-- keygen.c --*/ PKT_user_id *generate_user_id(void); #endif /*G10_PACKET_H*/ diff --git a/g10/plaintext.c b/g10/plaintext.c index 878bdc46b..7411a4b16 100644 --- a/g10/plaintext.c +++ b/g10/plaintext.c @@ -1,375 +1,386 @@ /* plaintext.c - process an plaintext packet * Copyright (C) 1998, 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 */ #include #include #include #include #include #include #include "util.h" #include "memory.h" #include "options.h" #include "packet.h" #include "ttyio.h" #include "filter.h" #include "main.h" #include "status.h" #include "i18n.h" /**************** * Handle a plaintext packet. If MFX is not NULL, update the MDs * Note: we should use the filter stuff here, but we have to add some * easy mimic to set a read limit, so we calculate only the * bytes from the plaintext. */ int handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx, int nooutput, int clearsig ) { char *fname = NULL; FILE *fp = NULL; int rc = 0; int c; int convert = pt->mode == 't'; /* create the filename as C string */ if( nooutput ) ; else if( opt.outfile ) { fname = m_alloc( strlen( opt.outfile ) + 1); strcpy(fname, opt.outfile ); } else if( pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8 ) ) { log_info(_("data not saved; use option \"--output\" to save it\n")); nooutput = 1; } else if( !opt.use_embedded_filename ) { fname = make_outfile_name( iobuf_get_real_fname(pt->buf) ); if( !fname ) fname = ask_outfile_name( pt->name, pt->namelen ); if( !fname ) { rc = G10ERR_CREATE_FILE; goto leave; } } else { fname = make_printable_string( pt->name, pt->namelen, 0 ); } if( nooutput ) ; else if( !*fname || (*fname=='-' && !fname[1])) { /* no filename or "-" given; write to stdout */ fp = stdout; } else if( !overwrite_filep( fname ) ) { rc = G10ERR_CREATE_FILE; goto leave; } if( fp || nooutput ) ; else if( !(fp = fopen(fname,"wb")) ) { log_error("Error creating `%s': %s\n", fname, strerror(errno) ); rc = G10ERR_CREATE_FILE; goto leave; } if( pt->len ) { assert( !clearsig ); if( convert ) { /* text mode */ for( ; pt->len; pt->len-- ) { if( (c = iobuf_get(pt->buf)) == -1 ) { log_error("Problem reading source (%u bytes remaining)\n", (unsigned)pt->len); rc = G10ERR_READ_FILE; goto leave; } if( mfx->md ) md_putc(mfx->md, c ); if( c == '\r' ) continue; /* fixme: this hack might be too simple */ if( fp ) { if( putc( c, fp ) == EOF ) { log_error("Error writing to `%s': %s\n", fname, strerror(errno) ); rc = G10ERR_WRITE_FILE; goto leave; } } } } else { /* binary mode */ byte *buffer = m_alloc( 32768 ); while( pt->len ) { int len = pt->len > 32768 ? 32768 : pt->len; len = iobuf_read( pt->buf, buffer, len ); if( len == -1 ) { log_error("Problem reading source (%u bytes remaining)\n", (unsigned)pt->len); rc = G10ERR_READ_FILE; m_free( buffer ); goto leave; } if( mfx->md ) md_write( mfx->md, buffer, len ); if( fp ) { if( fwrite( buffer, 1, len, fp ) != len ) { log_error("Error writing to `%s': %s\n", fname, strerror(errno) ); rc = G10ERR_WRITE_FILE; m_free( buffer ); goto leave; } } pt->len -= len; } m_free( buffer ); } } else if( !clearsig ) { if( convert ) { /* text mode */ while( (c = iobuf_get(pt->buf)) != -1 ) { if( mfx->md ) md_putc(mfx->md, c ); if( convert && c == '\r' ) continue; /* fixme: this hack might be too simple */ if( fp ) { if( putc( c, fp ) == EOF ) { log_error("Error writing to `%s': %s\n", fname, strerror(errno) ); rc = G10ERR_WRITE_FILE; goto leave; } } } } else { /* binary mode */ byte *buffer = m_alloc( 32768 ); for( ;; ) { int len = iobuf_read( pt->buf, buffer, 32768 ); if( len == -1 ) break; if( mfx->md ) md_write( mfx->md, buffer, len ); if( fp ) { if( fwrite( buffer, 1, len, fp ) != len ) { log_error("Error writing to `%s': %s\n", fname, strerror(errno) ); rc = G10ERR_WRITE_FILE; m_free( buffer ); goto leave; } } } m_free( buffer ); } pt->buf = NULL; } else { /* clear text signature - don't hash the last cr,lf */ int state = 0; while( (c = iobuf_get(pt->buf)) != -1 ) { if( fp ) { if( putc( c, fp ) == EOF ) { log_error("Error writing to `%s': %s\n", fname, strerror(errno) ); rc = G10ERR_WRITE_FILE; goto leave; } } if( !mfx->md ) continue; if( state == 2 ) { md_putc(mfx->md, '\r' ); md_putc(mfx->md, '\n' ); state = 0; } if( !state ) { if( c == '\r' ) state = 1; else md_putc(mfx->md, c ); } else if( state == 1 ) { if( c == '\n' ) state = 2; else { md_putc(mfx->md, '\r' ); if( c == '\r' ) state = 1; else { state = 0; md_putc(mfx->md, c ); } } } } pt->buf = NULL; } if( fp && fp != stdout && fclose(fp) ) { log_error("Error closing `%s': %s\n", fname, strerror(errno) ); fp = NULL; rc = G10ERR_WRITE_FILE; goto leave; } fp = NULL; leave: if( fp && fp != stdout ) fclose(fp); m_free(fname); return rc; } /**************** * Ask for the detached datafile and calculate the digest from it. * INFILE is the name of the input file. */ int -ask_for_detached_datafile( md_filter_context_t *mfx, const char *inname ) +ask_for_detached_datafile( MD_HANDLE md, MD_HANDLE md2, + const char *inname, int textmode ) { char *answer = NULL; IOBUF fp; int rc = 0; int c; fp = open_sigfile( inname ); /* open default file */ if( !fp && !opt.batch ) { int any=0; tty_printf("Detached signature.\n"); do { m_free(answer); answer = cpr_get("detached_signature.filename", _("Please enter name of data file: ")); cpr_kill_prompt(); if( any && !*answer ) { rc = G10ERR_READ_FILE; goto leave; } fp = iobuf_open(answer); if( !fp && errno == ENOENT ) { tty_printf("No such file, try again or hit enter to quit.\n"); any++; } else if( !fp ) { log_error("can't open `%s': %s\n", answer, strerror(errno) ); rc = G10ERR_READ_FILE; goto leave; } } while( !fp ); } if( !fp ) { if( opt.verbose ) log_info(_("reading stdin ...\n")); - while( (c = getchar()) != EOF ) { - if( mfx->md ) - md_putc(mfx->md, c ); - } - } - else { - while( (c = iobuf_get(fp)) != -1 ) { - if( mfx->md ) - md_putc(mfx->md, c ); - } - iobuf_close(fp); + fp = iobuf_open( NULL ); + assert(fp); } + do_hash( md, md2, fp, textmode ); + iobuf_close(fp); + leave: m_free(answer); return rc; } static void do_hash( MD_HANDLE md, MD_HANDLE md2, IOBUF fp, int textmode ) { text_filter_context_t tfx; int c; if( textmode ) { memset( &tfx, 0, sizeof tfx); iobuf_push_filter( fp, text_filter, &tfx ); } if( md2 ) { /* work around a strange behaviour in pgp2 */ + /* It seems that at least PGP5 converts a single CR to a CR,LF too */ + int lc = -1; while( (c = iobuf_get(fp)) != -1 ) { - if( c == '\n' ) - md_putc(md2, '\r' ); - md_putc(md, c ); - md_putc(md2, c ); + if( c == '\n' && lc == '\r' ) + md_putc(md2, c); + else if( c == '\n' ) { + md_putc(md2, '\r'); + md_putc(md2, c); + } + else if( c != '\n' && lc == '\r' ) { + md_putc(md2, '\n'); + md_putc(md2, c); + } + else + md_putc(md2, c); + + if( md ) + md_putc(md, c ); + lc = c; } } else { - while( (c = iobuf_get(fp)) != -1 ) - md_putc(md, c ); + while( (c = iobuf_get(fp)) != -1 ) { + if( md ) + md_putc(md, c ); + } } } /**************** * Hash the given files and append the hash to hash context md. * If FILES is NULL, hash stdin. */ int hash_datafiles( MD_HANDLE md, MD_HANDLE md2, STRLIST files, const char *sigfilename, int textmode ) { IOBUF fp; STRLIST sl=NULL; if( !files ) { /* check whether we can open the signed material */ fp = open_sigfile( sigfilename ); if( fp ) { do_hash( md, md2, fp, textmode ); iobuf_close(fp); return 0; } /* no we can't (no sigfile) - read signed stuff from stdin */ add_to_strlist( &sl, "-"); } else sl = files; for( ; sl; sl = sl->next ) { fp = iobuf_open( sl->d ); if( !fp ) { log_error(_("can't open signed data `%s'\n"), print_fname_stdin(sl->d)); if( !files ) free_strlist(sl); return G10ERR_OPEN_FILE; } do_hash( md, md2, fp, textmode ); iobuf_close(fp); } if( !files ) free_strlist(sl); return 0; } diff --git a/include/ttyio.h b/include/ttyio.h index 24eedebaa..7992d85e8 100644 --- a/include/ttyio.h +++ b/include/ttyio.h @@ -1,33 +1,34 @@ /* ttyio.h * Copyright (C) 1998, 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_TTYIO_H #define G10_TTYIO_H int tty_batchmode( int onoff ); void tty_printf( const char *fmt, ... ); void tty_print_string( byte *p, size_t n ); +void tty_print_utf8_string( byte *p, size_t n ); char *tty_get( const char *prompt ); char *tty_get_hidden( const char *prompt ); void tty_kill_prompt(void); int tty_get_answer_is_yes( const char *prompt ); int tty_no_terminal(int onoff); #endif /*G10_TTYIO_H*/ diff --git a/include/util.h b/include/util.h index 6feab3211..8eec982cc 100644 --- a/include/util.h +++ b/include/util.h @@ -1,217 +1,218 @@ /* util.h * Copyright (C) 1998 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_UTIL_H #define G10_UTIL_H #include "types.h" #include "errors.h" #include "types.h" #include "mpi.h" typedef struct { int *argc; /* pointer to argc (value subject to change) */ char ***argv; /* pointer to argv (value subject to change) */ unsigned flags; /* Global flags (DO NOT CHANGE) */ int err; /* print error about last option */ /* 1 = warning, 2 = abort */ int r_opt; /* return option */ int r_type; /* type of return value (0 = no argument found)*/ union { int ret_int; long ret_long; ulong ret_ulong; char *ret_str; } r; /* Return values */ struct { int idx; int inarg; int stopped; const char *last; void *aliases; const void *cur_alias; } internal; /* DO NOT CHANGE */ } ARGPARSE_ARGS; typedef struct { int short_opt; const char *long_opt; unsigned flags; const char *description; /* optional option description */ } ARGPARSE_OPTS; /*-- logger.c --*/ void log_set_logfile( const char *name, int fd ); FILE *log_stream(void); void g10_log_print_prefix(const char *text); void log_set_name( const char *name ); const char *log_get_name(void); void log_set_pid( int pid ); int log_get_errorcount( int clear ); void g10_log_hexdump( const char *text, const char *buf, size_t len ); #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) void g10_log_bug( const char *fmt, ... ) __attribute__ ((noreturn, format (printf,1,2))); void g10_log_bug0( const char *, int, const char * ) __attribute__ ((noreturn)); void g10_log_fatal( const char *fmt, ... ) __attribute__ ((noreturn, format (printf,1,2))); void g10_log_error( const char *fmt, ... ) __attribute__ ((format (printf,1,2))); void g10_log_info( const char *fmt, ... ) __attribute__ ((format (printf,1,2))); void g10_log_debug( const char *fmt, ... ) __attribute__ ((format (printf,1,2))); void g10_log_fatal_f( const char *fname, const char *fmt, ... ) __attribute__ ((noreturn, format (printf,2,3))); void g10_log_error_f( const char *fname, const char *fmt, ... ) __attribute__ ((format (printf,2,3))); void g10_log_info_f( const char *fname, const char *fmt, ... ) __attribute__ ((format (printf,2,3))); void g10_log_debug_f( const char *fname, const char *fmt, ... ) __attribute__ ((format (printf,2,3))); #define BUG() g10_log_bug0( __FILE__ , __LINE__, __FUNCTION__ ) #else void g10_log_bug( const char *fmt, ... ); void g10_log_bug0( const char *, int ); void g10_log_fatal( const char *fmt, ... ); void g10_log_error( const char *fmt, ... ); void g10_log_info( const char *fmt, ... ); void g10_log_debug( const char *fmt, ... ); void g10_log_fatal_f( const char *fname, const char *fmt, ... ); void g10_log_error_f( const char *fname, const char *fmt, ... ); void g10_log_info_f( const char *fname, const char *fmt, ... ); void g10_log_debug_f( const char *fname, const char *fmt, ... ); #define BUG() g10_log_bug0( __FILE__ , __LINE__ ) #endif #define log_hexdump g10_log_hexdump #define log_bug g10_log_bug #define log_bug0 g10_log_bug0 #define log_fatal g10_log_fatal #define log_error g10_log_error #define log_info g10_log_info #define log_debug g10_log_debug #define log_fatal_f g10_log_fatal_f #define log_error_f g10_log_error_f #define log_info_f g10_log_info_f #define log_debug_f g10_log_debug_f /*-- errors.c --*/ const char * g10_errstr( int no ); /*-- argparse.c --*/ int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts); int optfile_parse( FILE *fp, const char *filename, unsigned *lineno, ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts); void usage( int level ); const char *default_strusage( int level ); /*-- (main program) --*/ const char *strusage( int level ); /*-- dotlock.c --*/ struct dotlock_handle; typedef struct dotlock_handle *DOTLOCK; DOTLOCK create_dotlock( const char *file_to_lock ); int make_dotlock( DOTLOCK h, long timeout ); int release_dotlock( DOTLOCK h ); /*-- fileutil.c --*/ char * make_basename(const char *filepath); char * make_dirname(const char *filepath); char *make_filename( const char *first_part, ... ); int compare_filenames( const char *a, const char *b ); const char *print_fname_stdin( const char *s ); const char *print_fname_stdout( const char *s ); /*-- miscutil.c --*/ u32 make_timestamp(void); u32 scan_isodatestr( const char *string ); u32 add_days_to_timestamp( u32 stamp, u16 days ); const char *strtimevalue( u32 stamp ); const char *strtimestamp( u32 stamp ); /* GMT */ const char *asctimestamp( u32 stamp ); /* localized */ void print_string( FILE *fp, const byte *p, size_t n, int delim ); +void print_utf8_string( FILE *fp, const byte *p, size_t n ); char *make_printable_string( const byte *p, size_t n, int delim ); int answer_is_yes( const char *s ); int answer_is_yes_no_quit( const char *s ); /*-- strgutil.c --*/ void free_strlist( STRLIST sl ); #define FREE_STRLIST(a) do { free_strlist((a)); (a) = NULL ; } while(0) STRLIST add_to_strlist( STRLIST *list, const char *string ); STRLIST add_to_strlist2( STRLIST *list, const char *string, int is_utf8 ); STRLIST append_to_strlist( STRLIST *list, const char *string ); STRLIST append_to_strlist2( STRLIST *list, const char *string, int is_utf8 ); STRLIST strlist_prev( STRLIST head, STRLIST node ); STRLIST strlist_last( STRLIST node ); const char *memistr( const char *buf, size_t buflen, const char *sub ); char *mem2str( char *, const void *, size_t); char *trim_spaces( char *string ); unsigned trim_trailing_chars( byte *line, unsigned len, const char *trimchars); unsigned trim_trailing_ws( byte *line, unsigned len ); int string_count_chr( const char *string, int c ); int set_native_charset( const char *newset ); const char* get_native_charset(void); char *native_to_utf8( const char *string ); -char *utf8_to_native( const char *string ); +char *utf8_to_native( const char *string, size_t length ); int check_utf8_string( const char *string ); #ifndef HAVE_MEMICMP int memicmp( const char *a, const char *b, size_t n ); #endif #ifndef HAVE_STPCPY char *stpcpy(char *a,const char *b); #endif #ifndef HAVE_STRLWR char *strlwr(char *a); #endif #ifndef HAVE_STRTOUL #define strtoul(a,b,c) ((unsigned long)strtol((a),(b),(c))) #endif #ifndef HAVE_MEMMOVE #define memmove(d, s, n) bcopy((s), (d), (n)) #endif #ifndef HAVE_STRICMP #define stricmp(a,b) strcasecmp( (a), (b) ) #endif /**** other missing stuff ****/ #ifndef HAVE_ATEXIT /* For SunOS */ #define atexit(a) (on_exit((a),0)) #endif #ifndef HAVE_RAISE #define raise(a) kill(getpid(), (a)) #endif /******** some macros ************/ #ifndef STR #define STR(v) #v #endif #define STR2(v) STR(v) #define DIM(v) (sizeof(v)/sizeof((v)[0])) #define DIMof(type,member) DIM(((type *)0)->member) #endif /*G10_UTIL_H*/ diff --git a/util/ChangeLog b/util/ChangeLog index 95b06019a..a451e4a9a 100644 --- a/util/ChangeLog +++ b/util/ChangeLog @@ -1,424 +1,435 @@ +Tue Aug 31 17:20:44 CEST 1999 Werner Koch + + + * strgutil (utf8_to_native): Implemented. + (check_utf8_string): Removed. + + * miscutil.c (make_printable_string): Fixed possible buffer overflow. + (print_utf8_string): New. + + * ttyio.c (tty_print_utf8_string): New. + Mon Aug 30 20:38:33 CEST 1999 Werner Koch * secmem.c (pool_okay): declared volatile. * miscutil.c (answer_is_yes): Always check for plain "yes". (answer_is_yes_no_quit): Likewise. * dotlock.c (create_dotlock): Fixed segv during cleanup. Mon Jul 12 14:55:34 CEST 1999 Werner Koch * argparse.c (initialize): Init ret_xxx. (optfile_parse): Remove quotes from arguments. Wed Jul 7 13:08:40 CEST 1999 Werner Koch * memory.c (membug): Use if either M_DEBUG or M_GUARD is used. * miscutil.c (scan_isodatestr): New. * logger.c (g10_log_mpidump): Moved to ../mpi/mpicoder.c (g10_log_print_prefix): Renamed from print_prefix and made global. * Makefile.am: Support for libtool. Thu Jul 1 12:47:31 CEST 1999 Werner Koch * miscutil.c (make_printable_string): New. * strgutil.c (add_to_strlist2,append_to_strlist2): New. Tue Jun 29 21:44:25 CEST 1999 Werner Koch * secmem.c (USE_CAPABILITIES): Capabilities support (Remi). Sat Jun 26 12:15:59 CEST 1999 Werner Koch * dotlock.c (create_dotlock): s/uts/utsbuf/ cause there an Amdahl system with the name UTS (Dave Dykstra). * secmem.c (DEFAULT_POOLSIZE): Doubled the size. Fri Jun 18 00:18:02 CEST 1999 Michael Roth * iobuf.c: file_filter() Detection of EOF on terminals improved/fixed (see Bug #21). Mon Jun 14 21:18:54 CEST 1999 Michael Roth * ttyio.c: tty_no_terminal() new. Sat Jun 5 15:30:33 CEST 1999 Werner Koch * strgutil.c (set_native_charset): Support Latin-2 Tue Jun 1 16:01:46 CEST 1999 Werner Koch * iobuf.c (iobuf_get_real_fname): Made global and now keep a copy of the name in the iobuf struct. Mon May 31 19:41:10 CEST 1999 Werner Koch * iobuf.c (file_filter,block_filter): Speed patches (Rémi). Thu May 27 09:40:55 CEST 1999 Werner Koch * miscutil.c (answer_is_yes_no_quit): New. Sun May 23 14:20:22 CEST 1999 Werner Koch * dotlock.c: Tweaked to make it compile under mingw32 * http.c: Disabled for mingw32. Sat May 22 22:47:26 CEST 1999 Werner Koch * logger.c (log_set_logfile): New. Thu May 20 14:04:08 CEST 1999 Werner Koch * memory.c (membug): Nanu, there was a const instead of a static. * strgutil.c (trim_trailing_chars): New. Mon May 17 21:54:43 CEST 1999 Werner Koch * logger.c (g10_log_hexdump): Made 2nd arg a const. Wed Apr 28 13:03:03 CEST 1999 Werner Koch * miscutil.c (asctimestamp): Use nl_langinfo (Gaël Quéri). Sun Apr 18 10:11:28 CEST 1999 Werner Koch * argparse.c (store_alias): Disabled becuase it is not used. * ttyio.c (tty_batchmode): New Sat Mar 20 11:44:21 CET 1999 Werner Koch * http.c: Swapped to includes. Tue Mar 2 16:44:57 CET 1999 Werner Koch * strgutil.c (get_native_charset): New. Fri Feb 26 17:55:41 CET 1999 Werner Koch * secmem.c (memblock_struct): Force align (Rémi Guyomarch) Wed Feb 24 11:07:27 CET 1999 Werner Koch * iobuf.c (block_filter): Fixed the oscillating partial packet chunks. Fri Feb 19 15:49:15 CET 1999 Werner Koch * iobuf.c (iobuf_push_filter2): New to allow transer of context ownership to the iobuf. Released the context where needed. Tue Feb 16 14:10:02 CET 1999 Werner Koch * strgutil.c (add_to_strglist): Clear the new flags field (append_to_strglist): Ditto. * dotlock.c (read_lockfile): terminate pidstr (Michael). Wed Feb 10 17:15:39 CET 1999 Werner Koch * dotlock.c (remove_lockfiles): Add cleanup function. (make_dotlock): Add deadlock check. * secmem.c (secmem_malloc): Changed error message. Wed Jan 20 21:40:21 CET 1999 Werner Koch * http.c (http_wait_response): Moved the shutdown behind the dup Wed Jan 20 18:59:49 CET 1999 Werner Koch * http.c (send_request): Removed double LF Tue Jan 19 19:34:58 CET 1999 Werner Koch * * iobuf.c (iobuf_push_filter): Allow filters for temp streams (iobuf_write_temp): Ditto. (iobuf_flush_temp): New. (iobuf_unget_and_close_temp): Removed. * http.c (close_http_document): Renamed to http_close(). (open_http_document): Renamed to http_open_document(). (http_open): New. (http_start_data): New. (http_wait_response): New. Sun Jan 17 11:04:33 CET 1999 Werner Koch * strgutil.c (trim_trailing_ws): New. Sat Jan 16 12:03:27 CET 1999 Werner Koch * http.c (connect_server): Fixed stupid bug. Sat Jan 16 09:27:30 CET 1999 Werner Koch * http.c: New Wed Jan 13 14:10:15 CET 1999 Werner Koch * iobuf.c (iobuf_fdopen): New. Sat Jan 9 16:02:23 CET 1999 Werner Koch * secmem.c (lock_pool): add another check that setuid() worked. (secmem_init): Ditto. Thu Jan 7 18:00:58 CET 1999 Werner Koch * iobuf.c (iobuf_clear_eof): Removed. (underflow): Changed the eof handling. (iobuf_pop_filter): Made static and renamed to pop_filter. * iobuf.c (iobuf_read_line): New. Sun Jan 3 15:28:44 CET 1999 Werner Koch * dotlock.c (make_dotlock): print another informal message. (make_dotlock): Removed the cpp checks. Tue Dec 29 14:41:47 CET 1998 Werner Koch * secmem.c: Moved unistd.h out of the #ifdef * dotlock.c (make_dotlock): Sun has no SYS_NMLN * iobuf.c (iobuf_unget_and_close_temp): Reset .start Sat Dec 12 18:40:32 CET 1998 Werner Koch * argparse.c (arg_pars): fixed opts[i] with negative index. Fri Nov 27 21:37:41 CET 1998 Werner Koch * dotlock.c: Implemented Wed Nov 25 11:30:07 1998 Werner Koch (wk@isil.d.shuttle.de) * iobuf.c (iobuf_pop_filter): Fixed sigsegv after error. Thu Nov 19 07:09:55 1998 Werner Koch * miscutil.c (strtimevalue): New. Tue Nov 10 10:01:53 1998 Werner Koch (wk@isil.d.shuttle.de) * strgutil.c (set_native_charset): New. (native_to_utf8): Now handles koi8-r. Tue Nov 3 16:17:56 1998 Werner Koch (wk@isil.d.shuttle.de) * strgutil.c (native_to_utf8): New. (utf8_to_native): New, but only as a stub. * argparse.c (optfile_parse): Trimmed spaces from args. Wed Oct 28 08:01:49 1998 me,,, (wk@tobold) * argparse.c (find_long_option): New. (arg_parse): option=value is now allowed. Add a new internal option "--dump-options". Thu Oct 22 16:25:49 1998 Michael Roth (mroth@nessie.de) * fileutil.c (make_basename): New. (make_dirname): New. Wed Oct 21 12:20:29 1998 Werner Koch (wk@isil.d.shuttle.de) * util.c (iobuf_flush): autoincreasing of a temp. iobuf (iobuf_temp_with_content): New. Tue Oct 13 12:40:13 1998 Werner Koch (wk@isil.d.shuttle.de) * util.c (.nofast): set this variable Wed Oct 7 19:27:50 1998 Werner Koch (wk@isil.d.shuttle.de) * memory.c (m_print_stats): New. Tue Oct 6 09:53:56 1998 Werner Koch (wk@isil.d.shuttle.de) * strgutil.c (memicmp): Add HAVE_MEMICMP. Mon Sep 21 19:45:01 1998 Werner Koch (wk@(none)) * secmem.c: New flags to allow suspend/resume of warnings. Fri Sep 18 16:25:47 1998 Werner Koch (wk@(none)) * secmem.c (lock_pool): Kludge for broken mlock on HPUX 10.20 Tue Sep 15 17:52:21 1998 Werner Koch (wk@(none)) * miscutil.c (asctimestamp): New. Mon Sep 14 09:38:18 1998 Werner Koch (wk@(none)) * secmem.c (init_pool): Now mmaps /dev/zero if we do not have MAP_ANON. Wed Sep 9 13:52:28 1998 Werner Koch (wk@(none)) * ttyio.c (do_get): Ctrl-D is now a valid but special character Mon Sep 7 13:52:41 1998 Werner Koch (wk@(none)) * iobuf.c (get_real_fname): New and changed file_filter datastructures and their initialization. Tue Aug 11 15:12:35 1998 Werner Koch (wk@(none)) * miscutil.c (answer_is_yes): i18ned Sat Aug 8 18:35:00 1998 Werner Koch (wk@(none)) * ttyio.c (cleanup): New. Mon Aug 3 17:06:00 1998 Werner Koch (wk@(none)) * secmem.c (MAP_ANON): Add a macro test Wed Jul 29 14:53:34 1998 Werner Koch (wk@(none)) * ttyio.c (tty_get_answer_is_yes): New. Tue Jul 21 10:35:48 1998 Werner Koch (wk@(none)) * argparse.c: New option flag to distinguish options and commands. Sat Jul 18 19:49:30 1998 Werner Koch (wk@(none)) * argparse.c (arg_parse): Added -? as alias for -h Thu Jul 9 14:47:20 1998 Werner Koch (wk@isil.d.shuttle.de) * secmem.c (secmem_init): Drops setuid if called with 0. Tue Jul 7 11:49:25 1998 Werner Koch (wk@isil.d.shuttle.de) * logger.c (log_set_filename): New. Mon Jul 6 09:03:49 1998 Werner Koch (wk@isil.d.shuttle.de) * strgutil.c (append_to_strlist): New. Thu Jul 2 15:55:44 1998 Werner Koch (wk@isil.d.shuttle.de) * iobuf.c (block_filter): Add writing of OP partial length headers. Fri Jun 26 10:38:35 1998 Werner Koch (wk@isil.d.shuttle.de) * ttyio.c (do_get): all iso8859-1 characters are now allowed. Thu Jun 25 15:57:21 1998 Werner Koch (wk@isil.d.shuttle.de) * secmem.c (lock_pool): Removed left over test code. Wed Jun 10 07:39:41 1998 Werner Koch,mobil,,, (wk@tobold) * fileutil.c (compare_filenames): New. * argparse.c (arg_parse): New flag bit 6 to ignore --version Thu May 14 16:45:13 1998 Werner Koch (wk@isil.d.shuttle.de) * argparse.c (show_help): Add some formatting stuff Fri May 8 17:06:49 1998 Werner Koch (wk@isil.d.shuttle.de) * errors.c (strerror): New if !HAVE_STRERROR Mon May 4 19:48:03 1998 Werner Koch (wk@isil.d.shuttle.de) * iobuf.c (iobuf_read): Code is now faster. * (iobuf_write): ditto. Mon Apr 27 11:01:32 1998 Werner Koch (wk@isil.d.shuttle.de) * strgutil.c (memicmp): New. Thu Mar 19 11:29:03 1998 Werner Koch (wk@isil.d.shuttle.de) * strgutil.c (memistr): Add const to return and first arg. Sat Mar 7 11:54:35 1998 Werner Koch (wk@isil.d.shuttle.de) * miscutil.c (print_string): New arg delim; changed all callers. Thu Mar 5 12:19:30 1998 Werner Koch (wk@isil.d.shuttle.de) * errors.c: New strings. Thu Mar 5 12:06:31 1998 Werner Koch (wk@isil.d.shuttle.de) * iobuf.c (iobuf_open): A name of "-" now opens stdin. * fileutil.c (print_fname_stdout, print_fname_stdin): New. Fri Feb 27 10:20:03 1998 Werner Koch (wk@isil.d.shuttle.de) * memory.c (m_is_secure): Removed. * secmem.c (m_is_secure): Moved to here. * secmem.c (secmem_realloc): New. * memory.c (M_GUARD,EXTRA_ALIGN): New (all functions). Thu Feb 26 14:36:51 1998 Werner Koch (wk@isil.d.shuttle.de) * secmem.c (lock_pool): No error if EAGAIN is returned instead of EPERM. Fri Feb 20 17:43:05 1998 Werner Koch (wk@isil.d.shuttle.de) * ttyio.c [MINGW32]: Add support for mingw32. Tue Feb 17 19:43:44 1998 Werner Koch (wk@isil.d.shuttle.de) * memory.c (dump_table_at_exit): New. Mon Feb 16 10:07:28 1998 Werner Koch (wk@isil.d.shuttle.de) * argparse.c (show_version, show_help, default_strusage): Changed according to GNU standards. Mon Feb 16 08:58:25 1998 Werner Koch (wk@isil.d.shuttle.de) * iobuf.c (iobuf_peek): New Fri Feb 13 19:34:59 1998 Werner Koch (wk@isil.d.shuttle.de) * iobuf.c (iobuf_seek): Set counters to new offset. Fri Feb 13 17:13:04 1998 Werner Koch (wk@isil.d.shuttle.de) * logger.c (log_set_name, log_get_name): New. (print_prefix, pgm_name): New, changed all function to make use it. (log_mpidump): Removed the "DBG" prefix. (log_hexdump): Ditto. * logger.c (printstr): Removed. Fri Feb 13 15:14:13 1998 Werner Koch (wk@isil.d.shuttle.de) * argparse.c (show_help): New '\v' kludge. diff --git a/util/miscutil.c b/util/miscutil.c index 2b95d97d6..eb72415bb 100644 --- a/util/miscutil.c +++ b/util/miscutil.c @@ -1,313 +1,336 @@ /* miscutil.c - miscellaneous utilities * Copyright (C) 1998, 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 */ #include #include #include #include #include #include #ifdef HAVE_LANGINFO_H #include #endif #include "types.h" #include "util.h" #include "i18n.h" /**************** * I know that the OpenPGP protocol has a Y2106 problem ;-) */ u32 make_timestamp() { return time(NULL); } /**************** * Scan a date string and return a timestamp. * The only supported format is "yyyy-mm-dd" * Returns 0 for an invalid date. */ u32 scan_isodatestr( const char *string ) { int year, month, day; struct tm tmbuf; time_t stamp; int i; if( strlen(string) != 10 || string[4] != '-' || string[7] != '-' ) return 0; for( i=0; i < 4; i++ ) if( !isdigit(string[i]) ) return 0; if( !isdigit(string[5]) || !isdigit(string[6]) ) return 0; if( !isdigit(string[8]) || !isdigit(string[9]) ) return 0; year = atoi(string); month = atoi(string+5); day = atoi(string+8); /* some basic checks */ if( year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ) return 0; memset( &tmbuf, 0, sizeof tmbuf ); tmbuf.tm_mday = day; tmbuf.tm_mon = month-1; tmbuf.tm_year = year - 1900; tmbuf.tm_isdst = -1; stamp = mktime( &tmbuf ); if( stamp == (time_t)-1 ) return 0; return stamp; } u32 add_days_to_timestamp( u32 stamp, u16 days ) { return stamp + days*86400L; } /**************** * Return a string with a time value in the form: x Y, n D, n H */ const char * strtimevalue( u32 value ) { static char buffer[30]; unsigned int years, days, hours, minutes; value /= 60; minutes = value % 60; value /= 60; hours = value % 24; value /= 24; days = value % 365; value /= 365; years = value; sprintf(buffer,"%uy%ud%uh%um", years, days, hours, minutes ); if( years ) return buffer; if( days ) return strchr( buffer, 'y' ) + 1; return strchr( buffer, 'd' ) + 1; } /**************** * Note: this function returns GMT */ const char * strtimestamp( u32 stamp ) { static char buffer[11+5]; struct tm *tp; time_t atime = stamp; tp = gmtime( &atime ); sprintf(buffer,"%04d-%02d-%02d", 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday ); return buffer; } /**************** * Note: this function returns local time */ const char * asctimestamp( u32 stamp ) { static char buffer[50]; #if defined (HAVE_STRFTIME) && defined (HAVE_NL_LANGINFO) static char fmt[50]; #endif struct tm *tp; time_t atime = stamp; tp = localtime( &atime ); #ifdef HAVE_STRFTIME #if defined(HAVE_NL_LANGINFO) mem2str( fmt, nl_langinfo(D_T_FMT), DIM(fmt) ); if( strstr( fmt, "%Z" ) == NULL ) strcat( fmt, " %Z"); strftime( buffer, DIM(buffer)-1, fmt, tp ); #else /* fixme: we should check whether the locale appends a " %Z" * These locales from glibc don't put the " %Z": * fi_FI hr_HR ja_JP lt_LT lv_LV POSIX ru_RU ru_SU sv_FI sv_SE zh_CN */ strftime( buffer, DIM(buffer)-1, "%c %Z", tp ); #endif buffer[DIM(buffer)-1] = 0; #else mem2str( buffer, asctime(tp), DIM(buffer) ); #endif return buffer; } /**************** * Print a string to FP, but filter all control characters out. */ void print_string( FILE *fp, const byte *p, size_t n, int delim ) { for( ; n; n--, p++ ) if( iscntrl( *p ) || *p == delim ) { putc('\\', fp); if( *p == '\n' ) putc('n', fp); else if( *p == '\r' ) putc('r', fp); else if( *p == '\f' ) putc('f', fp); else if( *p == '\v' ) putc('v', fp); else if( *p == '\b' ) putc('b', fp); else if( !*p ) putc('0', fp); else fprintf(fp, "x%02x", *p ); } else putc(*p, fp); } +/**************** + * Print an UTF8 string to FP and filter all control characters out. + */ +void +print_utf8_string( FILE *fp, const byte *p, size_t n ) +{ + size_t i; + char *buf; + + /* we can handle plain ascii simpler, so check for it first */ + for(i=0; i < n; i++ ) { + if( p[i] & 0x80 ) + break; + } + if( i < n ) { + buf = utf8_to_native( p, n ); + fputs( buf, fp ); + m_free( buf ); + } + else + print_string( fp, p, n, 0 ); +} + /**************** * This function returns a string which is suitable for printing * Caller must release it with m_free() */ char * make_printable_string( const byte *p, size_t n, int delim ) { size_t save_n, buflen; const byte *save_p; char *buffer, *d; /* first count length */ for(save_n = n, save_p = p, buflen=1 ; n; n--, p++ ) { if( iscntrl( *p ) || *p == delim ) { if( *p=='\n' || *p=='\r' || *p=='\f' || *p=='\v' || *p=='\b' || !*p ) buflen += 2; else - buflen += 3; + buflen += 4; } else buflen++; } p = save_p; n = save_n; /* and now make the string */ d = buffer = m_alloc( buflen ); for( ; n; n--, p++ ) { if( iscntrl( *p ) || *p == delim ) { *d++ = '\\'; if( *p == '\n' ) *d++ = 'n'; else if( *p == '\r' ) *d++ = 'r'; else if( *p == '\f' ) *d++ = 'f'; else if( *p == '\v' ) *d++ = 'v'; else if( *p == '\b' ) *d++ = 'b'; else if( !*p ) *d++ = '0'; else { sprintf(d, "x%02x", *p ); d += 2; } } else *d++ = *p; } *d = 0; return buffer; } int answer_is_yes( const char *s ) { char *long_yes = _("yes"); char *short_yes = _("yY"); char *long_no = _("no"); char *short_no = _("nN"); if( !stricmp(s, long_yes ) ) return 1; if( strchr( short_yes, *s ) && !s[1] ) return 1; /* test for no strings to catch ambiguities for the next test */ if( !stricmp(s, long_no ) ) return 0; if( strchr( short_no, *s ) && !s[1] ) return 0; /* test for the english version (for those who are used to type yes) */ if( !stricmp(s, "yes" ) ) return 1; if( strchr( "yY", *s ) && !s[1] ) return 1; return 0; } /**************** * Return 1 for yes, -1 for quit, or 0 for no */ int answer_is_yes_no_quit( const char *s ) { char *long_yes = _("yes"); char *long_no = _("no"); char *long_quit = _("quit"); char *short_yes = _("yY"); char *short_no = _("nN"); char *short_quit = _("qQ"); if( !stricmp(s, long_yes ) ) return 1; if( !stricmp(s, long_no ) ) return 0; if( !stricmp(s, long_quit ) ) return -1; if( strchr( short_yes, *s ) && !s[1] ) return 1; if( strchr( short_no, *s ) && !s[1] ) return 0; if( strchr( short_quit, *s ) && !s[1] ) return -1; if( !stricmp(s, "yes" ) ) return 1; if( !stricmp(s, "quit" ) ) return -1; if( strchr( "yY", *s ) && !s[1] ) return 1; if( strchr( "qQ", *s ) && !s[1] ) return -1; return 0; } diff --git a/util/strgutil.c b/util/strgutil.c index 87eaad423..9ab63a047 100644 --- a/util/strgutil.c +++ b/util/strgutil.c @@ -1,492 +1,576 @@ /* strgutil.c - string utilities * Copyright (C) 1998 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 #include #include #include #include "types.h" #include "util.h" #include "memory.h" static ushort koi8_unicode[128] = { 0x2500,0x2502,0x250c,0x2510,0x2514,0x2518,0x251c,0x2524, 0x252c,0x2534,0x253c,0x2580,0x2584,0x2588,0x258c,0x2590, 0x2591,0x2592,0x2593,0x2320,0x25a0,0x2219,0x221a,0x2248, 0x2264,0x2265,0x00a0,0x2321,0x00b0,0x00b2,0x00b7,0x00f7, 0x2550,0x2551,0x2552,0x0451,0x2553,0x2554,0x2555,0x2556, 0x2557,0x2558,0x2559,0x255a,0x255b,0x255c,0x255d,0x255e, 0x255f,0x2560,0x2561,0x0401,0x2562,0x2563,0x2564,0x2565, 0x2566,0x2567,0x2568,0x2569,0x256a,0x256b,0x256c,0x00a9, 0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433, 0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e, 0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432, 0x044c,0x044b,0x0437,0x0448,0x044d,0x0449,0x0447,0x044a, 0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413, 0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e, 0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412, 0x042c,0x042b,0x0417,0x0428,0x042d,0x0429,0x0427,0x042a }; static ushort latin2_unicode[128] = { 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087, 0x0088,0x0089,0x008A,0x008B,0x008C,0x008D,0x008E,0x008F, 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097, 0x0098,0x0099,0x009A,0x009B,0x009C,0x009D,0x009E,0x009F, 0x00A0,0x0104,0x02D8,0x0141,0x00A4,0x013D,0x015A,0x00A7, 0x00A8,0x0160,0x015E,0x0164,0x0179,0x00AD,0x017D,0x017B, 0x00B0,0x0105,0x02DB,0x0142,0x00B4,0x013E,0x015B,0x02C7, 0x00B8,0x0161,0x015F,0x0165,0x017A,0x02DD,0x017E,0x017C, 0x0154,0x00C1,0x00C2,0x0102,0x00C4,0x0139,0x0106,0x00C7, 0x010C,0x00C9,0x0118,0x00CB,0x011A,0x00CD,0x00CE,0x010E, 0x0110,0x0143,0x0147,0x00D3,0x00D4,0x0150,0x00D6,0x00D7, 0x0158,0x016E,0x00DA,0x0170,0x00DC,0x00DD,0x0162,0x00DF, 0x0155,0x00E1,0x00E2,0x0103,0x00E4,0x013A,0x0107,0x00E7, 0x010D,0x00E9,0x0119,0x00EB,0x011B,0x00ED,0x00EE,0x010F, 0x0111,0x0144,0x0148,0x00F3,0x00F4,0x0151,0x00F6,0x00F7, 0x0159,0x016F,0x00FA,0x0171,0x00FC,0x00FD,0x0163,0x02D9 }; static const char *active_charset_name = "iso-8859-1"; static ushort *active_charset = NULL; void free_strlist( STRLIST sl ) { STRLIST sl2; for(; sl; sl = sl2 ) { sl2 = sl->next; m_free(sl); } } STRLIST add_to_strlist( STRLIST *list, const char *string ) { STRLIST sl; sl = m_alloc( sizeof *sl + strlen(string)); sl->flags = 0; strcpy(sl->d, string); sl->next = *list; *list = sl; return sl; } /**************** * ame as add_to_strlist() but if is_utf8 is *not* set a conversion * to UTF8 is done */ STRLIST add_to_strlist2( STRLIST *list, const char *string, int is_utf8 ) { STRLIST sl; if( is_utf8 ) sl = add_to_strlist( list, string ); else { char *p = native_to_utf8( string ); sl = add_to_strlist( list, p ); m_free( p ); } return sl; } STRLIST append_to_strlist( STRLIST *list, const char *string ) { STRLIST r, sl; sl = m_alloc( sizeof *sl + strlen(string)); sl->flags = 0; strcpy(sl->d, string); sl->next = NULL; if( !*list ) *list = sl; else { for( r = *list; r->next; r = r->next ) ; r->next = sl; } return sl; } STRLIST append_to_strlist2( STRLIST *list, const char *string, int is_utf8 ) { STRLIST sl; if( is_utf8 ) sl = append_to_strlist( list, string ); else { char *p = native_to_utf8( string ); sl = append_to_strlist( list, p ); m_free( p ); } return sl; } STRLIST strlist_prev( STRLIST head, STRLIST node ) { STRLIST n; for(n=NULL; head && head != node; head = head->next ) n = head; return n; } STRLIST strlist_last( STRLIST node ) { if( node ) for( ; node->next ; node = node->next ) ; return node; } /**************** * look for the substring SUB in buffer and return a pointer to that * substring in BUF or NULL if not found. * Comparison is case-insensitive. */ const char * memistr( const char *buf, size_t buflen, const char *sub ) { const byte *t, *s ; size_t n; for( t=buf, n=buflen, s=sub ; n ; t++, n-- ) if( toupper(*t) == toupper(*s) ) { for( buf=t++, buflen = n--, s++; n && toupper(*t) == toupper(*s); t++, s++, n-- ) ; if( !*s ) return buf; t = buf; n = buflen; s = sub ; } return NULL ; } /**************** * Wie strncpy(), aber es werden maximal n-1 zeichen kopiert und ein * '\0' angehängt. Ist n = 0, so geschieht nichts, ist Destination * gleich NULL, so wird via m_alloc Speicher besorgt, ist dann nicht * genügend Speicher vorhanden, so bricht die funktion ab. */ char * mem2str( char *dest , const void *src , size_t n ) { char *d; const char *s; if( n ) { if( !dest ) dest = m_alloc( n ) ; d = dest; s = src ; for(n--; n && *s; n-- ) *d++ = *s++; *d = '\0' ; } return dest ; } /**************** * remove leading and trailing white spaces */ char * trim_spaces( char *str ) { char *string, *p, *mark; string = str; /* find first non space character */ for( p=string; *p && isspace( *(byte*)p ) ; p++ ) ; /* move characters */ for( (mark = NULL); (*string = *p); string++, p++ ) if( isspace( *(byte*)p ) ) { if( !mark ) mark = string ; } else mark = NULL ; if( mark ) *mark = '\0' ; /* remove trailing spaces */ return str ; } unsigned trim_trailing_chars( byte *line, unsigned len, const char *trimchars ) { byte *p, *mark; unsigned n; for(mark=NULL, p=line, n=0; n < len; n++, p++ ) { if( strchr(trimchars, *p ) ) { if( !mark ) mark = p; } else mark = NULL; } if( mark ) { *mark = 0; return mark - line; } return len; } /**************** * remove trailing white spaces and return the length of the buffer */ unsigned trim_trailing_ws( byte *line, unsigned len ) { return trim_trailing_chars( line, len, " \t\r\n" ); } int string_count_chr( const char *string, int c ) { int count; for(count=0; *string; string++ ) if( *string == c ) count++; return count; } int set_native_charset( const char *newset ) { if( !stricmp( newset, "iso-8859-1" ) ) { active_charset_name = "iso-8859-1"; active_charset = NULL; } else if( !stricmp( newset, "iso-8859-2" ) ) { active_charset_name = "iso-8859-2"; active_charset = latin2_unicode; } else if( !stricmp( newset, "koi8-r" ) ) { active_charset_name = "koi8-r"; active_charset = koi8_unicode; } else return G10ERR_GENERAL; return 0; } const char* get_native_charset() { return active_charset_name; } /**************** * Convert string, which is in native encoding to UTF8 and return the * new allocated UTF8 string. */ char * native_to_utf8( const char *string ) { const byte *s; char *buffer; byte *p; size_t length=0; if( active_charset ) { for(s=string; *s; s++ ) { length++; if( *s & 0x80 ) length += 2; /* we may need 3 bytes */ } buffer = m_alloc( length + 1 ); for(p=buffer, s=string; *s; s++ ) { if( *s & 0x80 ) { ushort val = active_charset[ *s & 0x7f ]; if( val < 0x0800 ) { *p++ = 0xc0 | ( (val >> 6) & 0x1f ); *p++ = 0x80 | ( val & 0x3f ); } else { *p++ = 0xe0 | ( (val >> 12) & 0x0f ); *p++ = 0x80 | ( (val >> 6) & 0x3f ); *p++ = 0x80 | ( val & 0x3f ); } } else *p++ = *s; } *p = 0; } else { for(s=string; *s; s++ ) { length++; if( *s & 0x80 ) length++; } buffer = m_alloc( length + 1 ); for(p=buffer, s=string; *s; s++ ) { if( *s & 0x80 ) { *p++ = 0xc0 | ((*s >> 6) & 3); *p++ = 0x80 | ( *s & 0x3f ); } else *p++ = *s; } *p = 0; } return buffer; } /**************** - * Convert string, which is in UTF8 to native encoding. Replace - * illegal encodings by some "\xnn". + * Convert string, which is in UTF8 to native encoding. + * illegal encodings by some "\xnn" and quote all control characters */ char * -utf8_to_native( const char *string ) +utf8_to_native( const char *string, size_t length ) { - #if 0 + int nleft; + int i; + byte encbuf[7]; + int encidx; const byte *s; size_t n; - byte *buffer, *p; - - /* quick check whether we actually have characters with bit 8 set */ - for( s=string; *s; s++ ) - if( *s & 0x80 ) - break; - if( !*s ) /* that is easy */ - return m_strdup(string); - - /* count the extended utf-8 characters */ - 110x xxxx - 1110 xxxx - 1111 0xxx - for( n=1, s=string; *s; s++ ) { - if( !(*s & 0x80) ) - n++; - else if( (*s & 0xe0) == 0xc0 ) - n += 2; - else if( (*s & 0xf0) == 0xe0 ) - n += 3; - else if( (*s & 0xf8) == 0xf0 ) - n += 4; - else - n++; /* invalid encoding */ - } + byte *buffer = NULL, *p = NULL; + unsigned long val = 0; + size_t slen; + int resync = 0; + + /* 1. pass (p==NULL): count the extended utf-8 characters */ + /* 2. pass (p!=NULL): create string */ + for( ;; ) { + for( slen=length, nleft=encidx=0, n=0, s=string; slen; s++, slen-- ) { + if( resync ) { + if( !(*s < 128 || (*s >= 0xc0 && *s <= 0xfd)) ) { + /* still invalid */ + if( p ) { + sprintf(p, "\\x%02x", *s ); + p += 4; + } + n += 4; + continue; + } + resync = 0; + } + if( !nleft ) { + if( !(*s & 0x80) ) { /* plain ascii */ + if( iscntrl( *s ) ) { + n++; + if( p ) + *p++ = '\\'; + switch( *s ) { + case '\n': n++; if( p ) *p++ = 'n'; break; + case '\r': n++; if( p ) *p++ = 'r'; break; + case '\f': n++; if( p ) *p++ = 'f'; break; + case '\v': n++; if( p ) *p++ = 'v'; break; + case '\b': n++; if( p ) *p++ = 'b'; break; + case 0 : n++; if( p ) *p++ = '0'; break; + default: n += 3; + sprintf( p, "x%02x", *s ); + p += 3; + break; + } + } + else { + if( p ) *p++ = *s; + n++; + } + } + else if( (*s & 0xe0) == 0xc0 ) { /* 110x xxxx */ + val = *s & 0x1f; + nleft = 1; + encbuf[encidx=0] = *s; + } + else if( (*s & 0xf0) == 0xe0 ) { /* 1110 xxxx */ + val = *s & 0x0f; + nleft = 2; + encbuf[encidx=0] = *s; + } + else if( (*s & 0xf8) == 0xf0 ) { /* 1111 0xxx */ + val = *s & 0x07; + nleft = 3; + encbuf[encidx=0] = *s; + } + else if( (*s & 0xfc) == 0xf8 ) { /* 1111 10xx */ + val = *s & 0x03; + nleft = 4; + encbuf[encidx=0] = *s; + } + else if( (*s & 0xfe) == 0xfc ) { /* 1111 110x */ + val = *s & 0x01; + nleft = 5; + encbuf[encidx=0] = *s; + } + else { /* invalid encoding: print as \xnn */ + if( p ) { + sprintf(p, "\\x%02x", *s ); + p += 4; + } + n += 4; + resync = 1; + } + } + else if( *s < 0x80 || *s >= 0xc0 ) { /* invalid */ + if( p ) { + sprintf(p, "\\x%02x", *s ); + p += 4; + } + n += 4; + nleft = 0; + resync = 1; + } + else { + encbuf[++encidx] = *s; + val <<= 6; + val |= *s & 0x3f; + if( !--nleft ) { /* ready */ + if( active_charset ) { /* table lookup */ + for(i=0; i < 128; i++ ) { + if( active_charset[i] == val ) + break; + } + if( i < 128 ) { /* we can print this one */ + if( p ) *p++ = i+128; + n++; + } + else { /* we do not have a translation: print utf8 */ + if( p ) { + for(i=0; i < encidx; i++ ) { + sprintf(p, "\\x%02x", encbuf[i] ); + p += 4; + } + } + n += encidx*4; + } + } + else { /* native set */ + if( val >= 0x80 && val < 256 ) { + n++; /* we can simply print this character */ + if( p ) *p++ = val; + } + else { /* we do not have a translation: print utf8 */ + if( p ) { + for(i=0; i < encidx; i++ ) { + sprintf(p, "\\x%02x", encbuf[i] ); + p += 4; + } + } + n += encidx*4; + } + } - buffer = p = m_alloc( n ); - for( s=string; *s; ) { - if( !(*s & 0x80) ) - *p++ = *s++; - else if( (*s & 0xe0) == 0xc0 ) { - u32 val; - if( (s[1] & 0xc0) != 0x80 ) - ; - val = (*s << 6) | (s[1] & 0x3f); + } + + } + } + if( !buffer ) { /* allocate the buffer after the first pass */ + buffer = p = m_alloc( n + 1 ); + } + else { + *p = 0; /* make a string */ + return buffer; } - else if( (*s & 0xf0) == 0xe0 ) - n += 3; - else if( (*s & 0xf8) == 0xf0 ) - n += 4; - else - n++; /* invalid encoding */ } - #endif - return m_strdup(string); - } -/**************** - * check whether string is a valid UTF8 string. - * Returns 0 = Okay - * 1 = Too short - * 2 = invalid encoding - */ -int -check_utf8_string( const char *string ) -{ - /*fixme */ - return 0; -} - /********************************************* ********** missing string functions ********* *********************************************/ #ifndef HAVE_STPCPY char * stpcpy(char *a,const char *b) { while( *b ) *a++ = *b++; *a = 0; return (char*)a; } #endif #ifndef HAVE_STRLWR char * strlwr(char *s) { char *p; for(p=s; *p; p++ ) *p = tolower(*p); return s; } #endif /**************** * mingw32/cpd has a memicmp() */ #ifndef HAVE_MEMICMP int memicmp( const char *a, const char *b, size_t n ) { for( ; n; n--, a++, b++ ) if( *a != *b && toupper(*(const byte*)a) != toupper(*(const byte*)b) ) return *(const byte *)a - *(const byte*)b; return 0; } #endif diff --git a/util/ttyio.c b/util/ttyio.c index 3f5eb7900..74f6ce0f6 100644 --- a/util/ttyio.c +++ b/util/ttyio.c @@ -1,408 +1,431 @@ /* ttyio.c - tty i/O functions * Copyright (C) 1998 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 #include #include #include #include #include #ifdef HAVE_TCGETATTR #include #endif #ifdef __MINGW32__ /* use the odd Win32 functions */ #include #ifdef HAVE_TCGETATTR #error mingw32 and termios #endif #endif #include #include #include "util.h" #include "memory.h" #include "ttyio.h" #define CONTROL_D ('D' - 'A' + 1) #ifdef __MINGW32__ /* use the odd Win32 functions */ static struct { HANDLE in, out; } con; #define DEF_INPMODE (ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT \ |ENABLE_PROCESSED_INPUT ) #define HID_INPMODE (ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT ) #define DEF_OUTMODE (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT) #else /* yeah, we have a real OS */ static FILE *ttyfp = NULL; #endif static int initialized; static int last_prompt_len; static int batchmode; static int no_terminal; #ifdef HAVE_TCGETATTR static struct termios termsave; static int restore_termios; #endif #ifdef HAVE_TCGETATTR static void cleanup(void) { if( restore_termios ) { restore_termios = 0; /* do it prios in case it is interrupted again */ if( tcsetattr(fileno(ttyfp), TCSAFLUSH, &termsave) ) log_error("tcsetattr() failed: %s\n", strerror(errno) ); } } #endif static void init_ttyfp(void) { if( initialized ) return; #if defined(__MINGW32__) { SECURITY_ATTRIBUTES sa; memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; con.out = CreateFileA( "CONOUT$", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, 0 ); if( con.out == INVALID_HANDLE_VALUE ) log_fatal("open(CONOUT$) failed: rc=%d", (int)GetLastError() ); memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; con.in = CreateFileA( "CONIN$", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, 0 ); if( con.in == INVALID_HANDLE_VALUE ) log_fatal("open(CONIN$) failed: rc=%d", (int)GetLastError() ); } SetConsoleMode(con.in, DEF_INPMODE ); SetConsoleMode(con.out, DEF_OUTMODE ); #elif defined(__EMX__) ttyfp = stdout; /* Fixme: replace by the real functions: see wklib */ #else ttyfp = batchmode? stderr : fopen("/dev/tty", "r+"); if( !ttyfp ) { log_error("cannot open /dev/tty: %s\n", strerror(errno) ); exit(2); } #endif #ifdef HAVE_TCGETATTR atexit( cleanup ); #endif initialized = 1; } int tty_batchmode( int onoff ) { int old = batchmode; if( onoff != -1 ) batchmode = onoff; return old; } int tty_no_terminal(int onoff) { int old = no_terminal; no_terminal = onoff ? 1 : 0; return old; } void tty_printf( const char *fmt, ... ) { va_list arg_ptr; if (no_terminal) return; if( !initialized ) init_ttyfp(); va_start( arg_ptr, fmt ) ; #ifdef __MINGW32__ { static char *buf; static size_t bufsize; int n; DWORD nwritten; #if 0 /* the dox say, that there is a snprintf, but I didn't found * it, so we use a static buffer for now */ do { if( n == -1 || !buf ) { m_free(buf); bufsize += 200; /* better check the new size; (we use M$ functions) */ if( bufsize > 50000 ) log_bug("vsnprintf probably failed\n"); buf = m_alloc( bufsize ); } n = _vsnprintf(buf, bufsize-1, fmt, arg_ptr); } while( n == -1 ); #else if( !buf ) { bufsize += 1000; buf = m_alloc( bufsize ); } n = vsprintf(buf, fmt, arg_ptr); if( n == -1 ) log_bug("vsprintf() failed\n"); #endif if( !WriteConsoleA( con.out, buf, n, &nwritten, NULL ) ) log_fatal("WriteConsole failed: rc=%d", (int)GetLastError() ); if( n != nwritten ) log_fatal("WriteConsole failed: %d != %ld\n", n, nwritten ); last_prompt_len += n; } #else last_prompt_len += vfprintf(ttyfp,fmt,arg_ptr) ; fflush(ttyfp); #endif va_end(arg_ptr); } /**************** * Print a string, but filter all control characters out. */ void tty_print_string( byte *p, size_t n ) { if (no_terminal) return; if( !initialized ) init_ttyfp(); #ifdef __MINGW32__ /* not so effective, change it if you want */ for( ; n; n--, p++ ) if( iscntrl( *p ) ) { if( *p == '\n' ) tty_printf("\\n"); else if( !*p ) tty_printf("\\0"); else tty_printf("\\x%02x", *p); } else tty_printf("%c", *p); #else for( ; n; n--, p++ ) if( iscntrl( *p ) ) { putc('\\', ttyfp); if( *p == '\n' ) putc('n', ttyfp); else if( !*p ) putc('0', ttyfp); else fprintf(ttyfp, "x%02x", *p ); } else putc(*p, ttyfp); #endif } +void +tty_print_utf8_string( byte *p, size_t n ) +{ + size_t i; + char *buf; + + if (no_terminal) + return; + + /* we can handle plain ascii simpler, so check for it first */ + for(i=0; i < n; i++ ) { + if( p[i] & 0x80 ) + break; + } + if( i < n ) { + buf = utf8_to_native( p, n ); + tty_printf("%s", buf ); + m_free( buf ); + } + else + tty_print_string( p, n ); +} + static char * do_get( const char *prompt, int hidden ) { char *buf; byte cbuf[1]; int c, n, i; if( batchmode ) { log_error("Sorry, we are in batchmode - can't get input\n"); exit(2); } if (no_terminal) { log_error("Sorry, no terminal at all requested - can't get input\n"); exit(2); } if( !initialized ) init_ttyfp(); last_prompt_len = 0; tty_printf( prompt ); buf = m_alloc(n=50); i = 0; #if __MINGW32__ /* windoze version */ if( hidden ) SetConsoleMode(con.in, HID_INPMODE ); for(;;) { DWORD nread; if( !ReadConsoleA( con.in, cbuf, 1, &nread, NULL ) ) log_fatal("ReadConsole failed: rc=%d", (int)GetLastError() ); if( !nread ) continue; if( *cbuf == '\n' ) break; if( !hidden ) last_prompt_len++; c = *cbuf; if( c == '\t' ) c = ' '; else if( c > 0xa0 ) ; /* we don't allow 0xa0, as this is a protected blank which may * confuse the user */ else if( iscntrl(c) ) continue; if( !(i < n-1) ) { n += 50; buf = m_realloc( buf, n ); } buf[i++] = c; } if( hidden ) SetConsoleMode(con.in, DEF_INPMODE ); #else /* unix version */ if( hidden ) { #ifdef HAVE_TCGETATTR struct termios term; if( tcgetattr(fileno(ttyfp), &termsave) ) log_fatal("tcgetattr() failed: %s\n", strerror(errno) ); restore_termios = 1; term = termsave; term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); if( tcsetattr( fileno(ttyfp), TCSAFLUSH, &term ) ) log_fatal("tcsetattr() failed: %s\n", strerror(errno) ); #endif } /* fixme: How can we avoid that the \n is echoed w/o disabling * canonical mode - w/o this kill_prompt can't work */ while( read(fileno(ttyfp), cbuf, 1) == 1 && *cbuf != '\n' ) { if( !hidden ) last_prompt_len++; c = *cbuf; if( c == CONTROL_D ) log_info("control d found\n"); if( c == '\t' ) c = ' '; else if( c > 0xa0 ) ; /* we don't allow 0xa0, as this is a protected blank which may * confuse the user */ else if( iscntrl(c) ) continue; if( !(i < n-1) ) { n += 50; buf = m_realloc( buf, n ); } buf[i++] = c; } if( *cbuf != '\n' ) { buf[0] = CONTROL_D; i = 1; } if( hidden ) { #ifdef HAVE_TCGETATTR if( tcsetattr(fileno(ttyfp), TCSAFLUSH, &termsave) ) log_error("tcsetattr() failed: %s\n", strerror(errno) ); restore_termios = 0; #endif } #endif /* end unix version */ buf[i] = 0; return buf; } char * tty_get( const char *prompt ) { return do_get( prompt, 0 ); } char * tty_get_hidden( const char *prompt ) { return do_get( prompt, 1 ); } void tty_kill_prompt() { if ( no_terminal ) return; if( !initialized ) init_ttyfp(); if( batchmode ) last_prompt_len = 0; if( !last_prompt_len ) return; #if __MINGW32__ tty_printf("\r%*s\r", last_prompt_len, ""); #else { int i; putc('\r', ttyfp); for(i=0; i < last_prompt_len; i ++ ) putc(' ', ttyfp); putc('\r', ttyfp); fflush(ttyfp); } #endif last_prompt_len = 0; } int tty_get_answer_is_yes( const char *prompt ) { int yes; char *p = tty_get( prompt ); tty_kill_prompt(); yes = answer_is_yes(p); m_free(p); return yes; }