diff --git a/NEWS b/NEWS index ba17e9688..41d9b4fd6 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,7 @@ + * added option "--status-fd": see g10/OPTIONS + + * We have secure memeory on systems which support mlock(). It is not complete yet, because we do not have signal handler which does a cleanup in very case. diff --git a/g10/Makefile.am b/g10/Makefile.am index 154ffe689..e83e63ad2 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -43,6 +43,8 @@ g10_SOURCES = g10.c \ import.c \ export.c \ comment.c \ + status.c \ + status.h \ sig-check.c diff --git a/g10/Makefile.in b/g10/Makefile.in index a11c89aba..d8b06727a 100644 --- a/g10/Makefile.in +++ b/g10/Makefile.in @@ -81,6 +81,8 @@ g10_SOURCES = g10.c \ import.c \ export.c \ comment.c \ + status.c \ + status.h \ sig-check.c LDADD = -L ../cipher -L ../mpi -L ../util \ @@ -107,7 +109,7 @@ free-packet.o getkey.o pkclist.o skclist.o ringedit.o kbnode.o keygen.o \ mainproc.o armor.o mdfilter.o textfilter.o cipher.o elg.o rsa.o \ openfile.o keyid.o trustdb.o parse-packet.o passphrase.o plaintext.o \ pubkey-enc.o seckey-cert.o seskey.o sign.o import.o export.o comment.o \ -sig-check.o +status.o sig-check.o EXTRA_g10_SOURCES = g10_LDADD = $(LDADD) DIST_COMMON = Makefile.am Makefile.in @@ -137,7 +139,8 @@ $(srcdir)/.deps/pubkey-enc.P $(srcdir)/.deps/ringedit.P \ $(srcdir)/.deps/rsa.P $(srcdir)/.deps/seckey-cert.P \ $(srcdir)/.deps/seskey.P $(srcdir)/.deps/sig-check.P \ $(srcdir)/.deps/sign.P $(srcdir)/.deps/skclist.P \ -$(srcdir)/.deps/textfilter.P $(srcdir)/.deps/trustdb.P +$(srcdir)/.deps/status.P $(srcdir)/.deps/textfilter.P \ +$(srcdir)/.deps/trustdb.P SOURCES = $(g10_SOURCES) OBJECTS = $(g10_OBJECTS) diff --git a/g10/OPTIONS b/g10/OPTIONS index ed91fcf50..4f21a9e21 100644 --- a/g10/OPTIONS +++ b/g10/OPTIONS @@ -192,6 +192,13 @@ remote-user secret-keyring filename # add filename to the list of secret keyrings +status-fd n +# Write status informations to this file descriptor. If this option +# is not used, no status information is writte. This option is for the +# sake of a calling programm (e.g. a MUA) to ease up parsing of output +# and providing a defined set of status messages. +# FIXME: use a format ala "100 Blabla"? + verbose # Give more informations suring processing. If used 2 times, the input data # is listed in detail. diff --git a/g10/free-packet.c b/g10/free-packet.c index e2efa5a66..949af1099 100644 --- a/g10/free-packet.c +++ b/g10/free-packet.c @@ -56,6 +56,25 @@ free_seckey_enc( PKT_signature *enc ) m_free(enc); } + +/**************** + * Return the digest algorith from the signature packet. + * We need this function because the digeste algo depends on the + * used pubkey algorithm. + */ +int +digest_algo_from_sig( PKT_signature *sig ) +{ + switch( sig->pubkey_algo ) { + case PUBKEY_ALGO_ELGAMAL: return sig->d.elg.digest_algo; + case PUBKEY_ALGO_RSA: return sig->d.rsa.digest_algo; + default: return 0; + } +} + + + + void release_public_cert_parts( PKT_public_cert *cert ) { diff --git a/g10/g10.c b/g10/g10.c index cab9dc371..9b593e027 100644 --- a/g10/g10.c +++ b/g10/g10.c @@ -38,6 +38,7 @@ #include "trustdb.h" #include "ttyio.h" #include "i18n.h" +#include "status.h" enum cmd_values { aNull = 0, @@ -187,7 +188,7 @@ main( int argc, char **argv ) { 'k', NULL , 0, N_("list keys")}, { 510, "debug" ,4|16, N_("set debugging flags")}, { 511, "debug-all" ,0, N_("enable full debugging")}, - /* { 512 unused */ + { 512, "status-fd" ,1, N_("write status info to this fd") }, { 513, "gen-prime" , 0, "\r" }, { 514, "test" , 0, "\r" }, { 515, "fingerprint", 0, N_("show the fingerprints")}, @@ -329,7 +330,7 @@ main( int argc, char **argv ) case 509: add_keyring(pargs.r.ret_str); nrings++; break; case 510: opt.debug |= pargs.r.ret_ulong; break; case 511: opt.debug = ~0; break; - /* case 512: */ + case 512: set_status_fd( pargs.r.ret_int ); break; case 513: set_cmd( &cmd, aPrimegen); break; case 514: set_cmd( &cmd, aTest); break; case 515: opt.fingerprint = 1; break; @@ -401,6 +402,7 @@ main( int argc, char **argv ) if( errors ) g10_exit(2); + write_status( STATUS_ENTER ); set_debug(); if( cmd == aKMode || cmd == aKModeC ) { /* kludge to be compatible to pgp */ @@ -685,7 +687,9 @@ g10_exit( int rc ) if( opt.verbose ) secmem_dump_stats(); secmem_term(); - exit( rc? rc : log_get_errorcount(0)? 2:0 ); + rc = rc? rc : log_get_errorcount(0)? 2:0; + write_status( STATUS_LEAVE ); + exit(rc ); } diff --git a/g10/mainproc.c b/g10/mainproc.c index 35a44939b..607d7125a 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -33,6 +33,7 @@ #include "filter.h" #include "cipher.h" #include "main.h" +#include "status.h" /**************** @@ -46,7 +47,7 @@ typedef struct { md_filter_context_t mfx; DEK *dek; int last_was_pubkey_enc; - KBNODE cert; /* the current certificate */ + KBNODE cert; /* the current certificate / or signature */ int have_data; IOBUF iobuf; /* used to get the filename etc. */ } *CTX; @@ -74,7 +75,6 @@ add_onepass_sig( CTX c, PACKET *pkt ) KBNODE node; if( c->cert ) { /* add another packet */ - if( c->cert->pkt->pkttype != PKT_ONEPASS_SIG ) { log_error("add_onepass_sig: another packet is in the way\n"); release_cert( c ); @@ -143,29 +143,36 @@ add_signature( CTX c, PACKET *pkt ) { KBNODE node, n1, n2; - if( !c->cert ) { - /* orphaned signature (no certificate) - * this is the first signature for a following datafile - */ - return 0; + if( pkt->pkttype == PKT_SIGNATURE && !c->cert ) { + /* This is the first signature for a following datafile. + * G10 does not write such packets, instead it always uses + * onepass-sig packets. The drawback of PGP's method + * of writing prepending the signtaure to the data is, + * that it is not possible to make a signature from data + * read from stdin. But we are able to read these stuff. */ + node = new_kbnode( pkt ); + node->next = c->cert; + c->cert = node; + return 1; } - assert( c->cert->pkt ); - if( c->cert->pkt->pkttype == PKT_ONEPASS_SIG ) { + else if( !c->cert ) + return 0; + else if( !c->cert->pkt ) + BUG(); + else if( c->cert->pkt->pkttype == PKT_ONEPASS_SIG ) { /* The root is a onepass signature, so we are signing data * The childs direct under the root are the signatures - * (there is no need to keep the correct sequence of packets) - */ + * (there is no need to keep the correct sequence of packets) */ node = new_kbnode( pkt ); node->next = c->cert->child; c->cert->child = node; return 1; } - - - if( !c->cert->child ) { + else if( !c->cert->child ) { log_error("orphaned signature (no userid)\n" ); return 0; } + /* goto the last user id */ for(n1=c->cert->child; n1->next; n1 = n1->next ) ; @@ -564,6 +571,38 @@ print_keyid( FILE *fp, u32 *keyid ) m_free(p); } + + +static int +check_sig_and_print( CTX c, KBNODE node ) +{ + PKT_signature *sig = node->pkt->pkt.signature; + int rc; + + rc = do_check_sig(c, node ); + if( !rc ) { + write_status( STATUS_GOODSIG ); + log_info("Good signature from "); + print_keyid( stderr, sig->keyid ); + putc('\n', stderr); + } + else if( rc == G10ERR_BAD_SIGN ) { + write_status( STATUS_BADSIG ); + log_error("BAD signature from "); + print_keyid( stderr, sig->keyid ); + putc('\n', stderr); + if( opt.batch ) + g10_exit(1); + } + else { + write_status( STATUS_ERRSIG ); + log_error("Can't check signature made by %08lX: %s\n", + sig->keyid[1], g10_errstr(rc) ); + } + return rc; +} + + /**************** * Process the tree which starts at node */ @@ -588,9 +627,13 @@ proc_tree( CTX c, KBNODE node ) else { /* check all signatures */ if( !c->have_data ) { free_md_filter_context( &c->mfx ); - /* fixme: take the digest algo to use from the - * onepass_sig packet (if we have these) */ - c->mfx.md = md_open(DIGEST_ALGO_RMD160, 0); + /* prepare to create all requested message digests */ + c->mfx.md = md_open(0, 0); + for(n1=node->child; n1; n1 = n1->next ) { + md_enable( c->mfx.md, + digest_algo_from_sig(n1->pkt->pkt.signature)); + } + /* ask for file and hash it */ rc = ask_for_detached_datafile( &c->mfx, iobuf_get_fname(c->iobuf)); if( rc ) { @@ -599,30 +642,26 @@ proc_tree( CTX c, KBNODE node ) } } - for(n1=node->child; n1; n1 = n1->next ) { - PKT_signature *sig = n1->pkt->pkt.signature; - - rc = do_check_sig(c, n1 ); - if( !rc ) { - log_info("Good signature from "); - print_keyid( stderr, sig->keyid ); - putc('\n', stderr); - } - else if( rc == G10ERR_BAD_SIGN ) { - log_error("BAD signature from "); - print_keyid( stderr, sig->keyid ); - putc('\n', stderr); - if( opt.batch ) - g10_exit(1); - } - else - log_error("Can't check signature made by %08lX: %s\n", - sig->keyid[1], g10_errstr(rc) ); - } + for(n1=node->child; n1; n1 = n1->next ) + check_sig_and_print( c, n1 ); } } else if( node->pkt->pkttype == PKT_SIGNATURE ) { + PKT_signature *sig = node->pkt->pkt.signature; + log_info("proc_tree: old style signature\n"); + if( !c->have_data ) { + free_md_filter_context( &c->mfx ); + c->mfx.md = md_open(digest_algo_from_sig(sig), 0); + rc = ask_for_detached_datafile( &c->mfx, + iobuf_get_fname(c->iobuf)); + if( rc ) { + log_error("can't hash datafile: %s\n", g10_errstr(rc)); + return; + } + } + + check_sig_and_print( c, node ); } else log_error("proc_tree: invalid root packet\n"); diff --git a/g10/packet.h b/g10/packet.h index 285695213..8d3018d58 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -230,6 +230,7 @@ void hash_public_cert( MD_HANDLE md, PKT_public_cert *pkc ); /*-- free-packet.c --*/ 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_cert_parts( PKT_public_cert *cert ); void free_public_cert( PKT_public_cert *cert ); void release_secret_cert_parts( PKT_secret_cert *cert ); diff --git a/g10/status.c b/g10/status.c new file mode 100644 index 000000000..6c660b7ee --- /dev/null +++ b/g10/status.c @@ -0,0 +1,57 @@ +/* status.c + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 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. + * + * G10 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 "status.h" + +static int fd = -1; + +void +set_status_fd( int newfd ) +{ + fd = newfd; +} + + +void +write_status( int no ) +{ + const char *s; + + if( fd == -1 ) + return; /* not enabled */ + + switch( no ) { + case STATUS_ENTER : s = "ENTER\n"; break; + case STATUS_LEAVE : s = "LEAVE\n"; break; + case STATUS_ABORT : s = "ABORT\n"; break; + case STATUS_GOODSIG: s = "GOODSIG\n"; break; + case STATUS_BADSIG : s = "BADSIG\n"; break; + case STATUS_ERRSIG : s = "ERRSIG\n"; break; + default: s = "?\n"; break; + } + + write( fd, s, strlen(s) ); + +} + diff --git a/g10/status.h b/g10/status.h new file mode 100644 index 000000000..55eef32bb --- /dev/null +++ b/g10/status.h @@ -0,0 +1,41 @@ +/* status.h + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 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. + * + * G10 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_STATUS_H +#define G10_STATUS_H + + +#define STATUS_ENTER 1 +#define STATUS_LEAVE 2 +#define STATUS_ABORT 3 + +#define STATUS_GOODSIG 4 +#define STATUS_BADSIG 5 +#define STATUS_ERRSIG 6 + + + + + +/*-- status.c --*/ +void set_status_fd( int fd ); +void write_status( int no ); + + +#endif /*G10_STATUS_H*/ diff --git a/mpi/mpicoder.c b/mpi/mpicoder.c index 75583996d..b371fa64a 100644 --- a/mpi/mpicoder.c +++ b/mpi/mpicoder.c @@ -244,14 +244,21 @@ mpi_print( FILE *fp, MPI a, int mode ) u32 mpi_get_keyid( MPI a, u32 *keyid ) { -#if BYTES_PER_MPI_LIMB != 4 - #error Make this function work with other LIMB sizes -#endif +#if BYTES_PER_MPI_LIMB == 4 if( keyid ) { keyid[0] = a->nlimbs >= 2? a->d[1] : 0; keyid[1] = a->nlimbs >= 1? a->d[0] : 0; } return a->nlimbs >= 1? a->d[0] : 0; +#elif BYTES_PER_MPI_LIMB == 8 + if( keyid ) { + keyid[0] = a->nlimbs? (u32)(a->d[0] >> 32) : 0; + keyid[1] = a->nlimbs? (u32)(a->d[0] & 0xffffffff) : 0; + } + return a->nlimbs? (u32)(a->d[0] & 0xffffffff) : 0; +#else + #error Make this function work with other LIMB sizes +#endif }