From bbf86c6e592b62cd6ae0e74ac37822b69242a4aa Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 26 Apr 1999 15:53:01 +0000 Subject: [PATCH] See ChangeLog: Mon Apr 26 17:48:15 CEST 1999 Werner Koch --- NEWS | 3 + PROJECTS | 4 + TODO | 2 +- doc/gpg.1pod | 5 ++ doc/manual.sgml | 2 +- g10/ChangeLog | 14 +++- g10/build-packet.c | 12 ++- g10/compress.c | 4 +- g10/decrypt.c | 2 +- g10/encode.c | 192 +++++++++++++++++++++++++++++++++++++++++++++ g10/encr-data.c | 4 +- g10/free-packet.c | 20 ++--- g10/g10.c | 5 +- g10/keyedit.c | 184 +++++++++++++++++++++++++++++++++++++++++-- g10/mainproc.c | 102 ++++++++++++++++-------- g10/options.h | 1 + g10/packet.h | 12 +-- g10/parse-packet.c | 46 +++++++---- g10/revoke.c | 186 +++++++++++++++++++++++++++++++++++++++++++ g10/sig-check.c | 91 ++++++++++++++++++++- g10/sign.c | 2 +- g10/status.c | 3 + g10/status.h | 3 + g10/verify.c | 2 +- include/errors.h | 2 +- mpi/ChangeLog | 6 ++ mpi/Makefile.am | 3 +- mpi/mpi-inline.c | 36 +++++++++ mpi/mpi-inline.h | 13 +-- mpi/mpih-add.c | 88 --------------------- mpi/mpih-sub.c | 81 ------------------- util/errors.c | 1 + 32 files changed, 866 insertions(+), 265 deletions(-) create mode 100644 mpi/mpi-inline.c delete mode 100644 mpi/mpih-add.c delete mode 100644 mpi/mpih-sub.c diff --git a/NEWS b/NEWS index 073e82ec2..624973263 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,9 @@ * Merged gpgm and gpg into one binary. + * Add revsig command to the edit menu. It is now possible to + revoke signature. + Noteworthy changes in version 0.9.5 ----------------------------------- diff --git a/PROJECTS b/PROJECTS index c5c445893..a794148c3 100644 --- a/PROJECTS +++ b/PROJECTS @@ -47,3 +47,7 @@ * Keep a list of duplicate, faked or unwanted keyids. + * The current code has knowledge about the structure of a keyblock. + We should add an abstraction layer so that adding support for + different certificate structures will become easier. + diff --git a/TODO b/TODO index 2285a49ce..aa736aee2 100644 --- a/TODO +++ b/TODO @@ -8,7 +8,7 @@ * See why we always get this "Hmmm, public key not anymore available" - * print a warning when a revoked/expired secret key is used. + * print a warning when a revoked/expired _secret_ key is used. * remove more "Fixmes" diff --git a/doc/gpg.1pod b/doc/gpg.1pod index 42d4298bf..95f5c301f 100644 --- a/doc/gpg.1pod +++ b/doc/gpg.1pod @@ -473,6 +473,11 @@ B<--force-v3-sigs> on key material. This options forces v3 signatures for signatures on data. +B<--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). + B<--lock-once> Lock the file the first time a lock is requested and do not release the lock until the process diff --git a/doc/manual.sgml b/doc/manual.sgml index 2d02caae4..a604d5357 100644 --- a/doc/manual.sgml +++ b/doc/manual.sgml @@ -5,7 +5,7 @@ The GNU Privacy Guard Werner Koch -
wk@computer.org
+
wk@gnupg.org
diff --git a/g10/ChangeLog b/g10/ChangeLog index 90f7f9209..739677029 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,16 @@ +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 @@ -7,7 +20,6 @@ Sun Apr 18 20:48:15 CEST 1999 Werner Koch 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. diff --git a/g10/build-packet.c b/g10/build-packet.c index b3831eb32..285f115f4 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -728,9 +728,15 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig ) } iobuf_put(a, sig->digest_start[0] ); iobuf_put(a, sig->digest_start[1] ); - n = pubkey_get_nsig( sig->pubkey_algo ); - if( !n ) - write_fake_data( a, sig->data[0] ); + n = sig->pubkey_algo? pubkey_get_nsig( sig->pubkey_algo ) : 0; + if( !n ) { /* the MDC data */ + fputs("The MDC: ", stderr); + mpi_print(stderr, sig->data[0], 0 ); + fputs(" ", stderr); + mpi_print(stderr, sig->data[0], 1 ); + putc('\n', stderr); + mpi_write( a, sig->data[0] ); + } for(i=0; i < n; i++ ) mpi_write(a, sig->data[i] ); diff --git a/g10/compress.c b/g10/compress.c index accca02cc..5ad4a27de 100644 --- a/g10/compress.c +++ b/g10/compress.c @@ -256,7 +256,7 @@ compress_filter( void *opaque, int control, * Handle a compressed packet */ int -handle_compressed( PKT_compressed *cd, +handle_compressed( void *procctx, PKT_compressed *cd, int (*callback)(IOBUF, void *), void *passthru ) { compress_filter_context_t cfx; @@ -271,7 +271,7 @@ handle_compressed( PKT_compressed *cd, if( callback ) rc = callback(cd->buf, passthru ); else - rc = proc_packets(cd->buf); + rc = proc_packets(procctx, cd->buf); #if 0 iobuf_pop_filter( cd->buf, compress_filter, &cfx ); if( cd->len ) diff --git a/g10/decrypt.c b/g10/decrypt.c index 3d223eadd..df6b0a7c0 100644 --- a/g10/decrypt.c +++ b/g10/decrypt.c @@ -71,7 +71,7 @@ decrypt_message( const char *filename ) no_out = 1; opt.outfile = "-"; } - rc = proc_encryption_packets( fp ); + rc = proc_encryption_packets( NULL, fp ); if( no_out ) opt.outfile = NULL; iobuf_close(fp); diff --git a/g10/encode.c b/g10/encode.c index 825a4c98a..ba97299e2 100644 --- a/g10/encode.c +++ b/g10/encode.c @@ -39,6 +39,7 @@ static int encode_simple( const char *filename, int mode ); +static int encode_crypt_mdc( const char* fname, STRLIST remusr ); static int write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out ); @@ -215,6 +216,10 @@ encode_crypt( const char *filename, STRLIST remusr ) PK_LIST pk_list; int do_compress = opt.compress && !opt.rfc1991; + if( opt.force_mdc ) + return encode_crypt_mdc( filename, remusr ); + + memset( &cfx, 0, sizeof cfx); memset( &afx, 0, sizeof afx); memset( &zfx, 0, sizeof zfx); @@ -329,6 +334,193 @@ encode_crypt( const char *filename, STRLIST remusr ) } + +static int +encode_crypt_mdc( const char* fname, STRLIST remusr ) +{ + armor_filter_context_t afx; + compress_filter_context_t zfx; + md_filter_context_t mfx; + text_filter_context_t tfx; + encrypt_filter_context_t efx; + IOBUF inp = NULL, out = NULL; + PACKET pkt; + PKT_plaintext *pt = NULL; + u32 filesize; + int rc = 0; + PK_LIST pk_list = NULL; + int compr_algo = -1; /* unknown */ + + + memset( &afx, 0, sizeof afx); + memset( &zfx, 0, sizeof zfx); + memset( &mfx, 0, sizeof mfx); + memset( &tfx, 0, sizeof tfx); + memset( &efx, 0, sizeof efx); + init_packet( &pkt ); + + if( (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC )) ) + goto leave; + compr_algo = select_algo_from_prefs( pk_list, PREFTYPE_COMPR ); + + /* prepare iobufs */ + if( !(inp = iobuf_open(fname)) ) { + log_error("can't open %s: %s\n", fname? fname: "[stdin]", + strerror(errno) ); + rc = G10ERR_OPEN_FILE; + goto leave; + } + + if( (rc = open_outfile( fname, opt.armor? 1: 0, &out ))) + goto leave; + + /* prepare to calculate the MD over the input */ + mfx.md = md_open( DIGEST_ALGO_SHA1, 0 ); + iobuf_push_filter( inp, md_filter, &mfx ); + + if( opt.armor ) + iobuf_push_filter( out, armor_filter, &afx ); + efx.pk_list = pk_list; + /* fixme: set efx.cfx.datalen if known */ + iobuf_push_filter( out, encrypt_filter, &efx ); + + if( opt.compress ) { + if( !compr_algo ) + ; /* don't use compression */ + else { + if( compr_algo == 1 ) + zfx.algo = 1; + iobuf_push_filter( out, compress_filter, &zfx ); + } + } + + /* build a one pass packet */ + { + PKT_onepass_sig *ops; + + ops = m_alloc_clear( sizeof *ops ); + ops->sig_class = 0x00; + ops->digest_algo = DIGEST_ALGO_SHA1; + ops->pubkey_algo = 0; + ops->keyid[0] = 0; + ops->keyid[1] = 0; + ops->last = 1; + + init_packet(&pkt); + pkt.pkttype = PKT_ONEPASS_SIG; + pkt.pkt.onepass_sig = ops; + rc = build_packet( out, &pkt ); + free_packet( &pkt ); + if( rc ) { + log_error("build onepass_sig packet failed: %s\n", + g10_errstr(rc)); + goto leave; + } + } + + /* setup the inner packet */ + if( fname || opt.set_filename ) { + char *s = make_basename( opt.set_filename ? opt.set_filename : fname ); + pt = m_alloc( sizeof *pt + strlen(s) - 1 ); + pt->namelen = strlen(s); + memcpy(pt->name, s, pt->namelen ); + m_free(s); + } + else { /* no filename */ + pt = m_alloc( sizeof *pt - 1 ); + pt->namelen = 0; + } + if( fname ) { + if( !(filesize = iobuf_get_filelength(inp)) ) + log_info(_("WARNING: `%s' is an empty file\n"), fname ); + + /* because the text_filter modifies the length of the + * data, it is not possible to know the used length + * without a double read of the file - to avoid that + * we simple use partial length packets. + */ + if( opt.textmode ) + filesize = 0; + } + else + filesize = 0; /* stdin */ + pt->timestamp = make_timestamp(); + pt->mode = opt.textmode ? 't':'b'; + pt->len = filesize; + pt->new_ctb = !pt->len; + pt->buf = inp; + pkt.pkttype = PKT_PLAINTEXT; + pkt.pkt.plaintext = pt; + /*cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;*/ + if( (rc = build_packet( out, &pkt )) ) + log_error("build_packet(PLAINTEXT) failed: %s\n", g10_errstr(rc) ); + pt->buf = NULL; + + /* build the MDC faked signature packet */ + { + PKT_signature *sig; + MD_HANDLE md; + byte buf[6]; + size_t n; + + sig = m_alloc_clear( sizeof *sig ); + sig->version = 4; + sig->digest_algo = DIGEST_ALGO_SHA1; + md = md_copy( mfx.md ); + + md_putc( md, sig->version ); + md_putc( md, sig->sig_class ); + md_putc( md, sig->pubkey_algo ); + md_putc( md, sig->digest_algo ); + n = 6; + /* add some magic */ + buf[0] = sig->version; + buf[1] = 0xff; buf[2] = 0; buf[3] = 0; buf[4] = 0; buf[5] = 6; + md_write( md, buf, 6 ); + md_final( md ); + + /* pack the hash into data[0] */ + memcpy( sig->digest_start, md_read( md, DIGEST_ALGO_SHA1), 2 ); + sig->data[0] = mpi_alloc( (20+BYTES_PER_MPI_LIMB-1) + /BYTES_PER_MPI_LIMB ); + mpi_set_buffer( sig->data[0], md_read(md, DIGEST_ALGO_SHA1), + md_digest_length(DIGEST_ALGO_SHA1), 0 ); + + md_close( md ); + + if( !rc ) { /* and write it */ + init_packet(&pkt); + pkt.pkttype = PKT_SIGNATURE; + pkt.pkt.signature = sig; + rc = build_packet( out, &pkt ); + free_packet( &pkt ); + if( rc ) + log_error("build MDC packet failed: %s\n", g10_errstr(rc) ); + } + if( rc ) + goto leave; + } + + + leave: + if( rc ) + iobuf_cancel(out); + else + iobuf_close(out); + iobuf_close(inp); + md_close( mfx.md ); + release_pk_list( pk_list ); + return rc; +} + + + + + + + + + /**************** * Filter to do a complete public key encryption. */ diff --git a/g10/encr-data.c b/g10/encr-data.c index c18a397bd..5061622da 100644 --- a/g10/encr-data.c +++ b/g10/encr-data.c @@ -45,7 +45,7 @@ typedef struct { * Decrypt the data, specified by ED with the key DEK. */ int -decrypt_data( PKT_encrypted *ed, DEK *dek ) +decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek ) { decode_filter_ctx_t dfx; byte *p; @@ -105,7 +105,7 @@ decrypt_data( PKT_encrypted *ed, DEK *dek ) return G10ERR_BAD_KEY; } iobuf_push_filter( ed->buf, decode_filter, &dfx ); - proc_packets(ed->buf); + proc_packets( procctx, ed->buf); ed->buf = NULL; cipher_close(dfx.cipher_hd); return 0; diff --git a/g10/free-packet.c b/g10/free-packet.c index 78f81bd0a..e8a3a8af3 100644 --- a/g10/free-packet.c +++ b/g10/free-packet.c @@ -56,11 +56,9 @@ void free_seckey_enc( PKT_signature *sig ) { int n, i; - n = pubkey_get_nsig( sig->pubkey_algo ); - if( !n ) { - m_free(sig->data[0]); - sig->data[0] = NULL; - } + n = sig->pubkey_algo? pubkey_get_nsig( sig->pubkey_algo ) : 0; + if( !n ) + mpi_free(sig->data[0]); for(i=0; i < n; i++ ) mpi_free( sig->data[i] ); m_free(sig->hashed_data); @@ -168,13 +166,11 @@ copy_signature( PKT_signature *d, PKT_signature *s ) if( !d ) d = m_alloc(sizeof *d); memcpy( d, s, sizeof *d ); - n = pubkey_get_nsig( s->pubkey_algo ); + n = s->pubkey_algo? pubkey_get_nsig( s->pubkey_algo ) : 0; if( !n ) - d->data[0] = cp_fake_data(s->data[0]); - else { - for(i=0; i < n; i++ ) - d->data[i] = mpi_copy( s->data[i] ); - } + d->data[0] = mpi_copy(s->data[0]); + for(i=0; i < n; i++ ) + d->data[i] = mpi_copy( s->data[i] ); d->hashed_data = cp_data_block(s->hashed_data); d->unhashed_data = cp_data_block(s->unhashed_data); return d; @@ -434,7 +430,7 @@ cmp_signatures( PKT_signature *a, PKT_signature *b ) if( a->pubkey_algo != b->pubkey_algo ) return -1; - n = pubkey_get_nsig( a->pubkey_algo ); + n = a->pubkey_algo? pubkey_get_nsig( a->pubkey_algo ) : 0; if( !n ) return -1; /* can't compare due to unknown algorithm */ for(i=0; i < n; i++ ) { diff --git a/g10/g10.c b/g10/g10.c index 3ebcbe99f..ab6a28d2a 100644 --- a/g10/g10.c +++ b/g10/g10.c @@ -144,6 +144,7 @@ enum cmd_and_opt_values { aNull = 0, oComment, oThrowKeyid, oForceV3Sigs, + oForceMDC, oS2KMode, oS2KDigest, oS2KCipher, @@ -220,6 +221,7 @@ static ARGPARSE_OPTS opts[] = { { oVerbose, "verbose", 0, N_("verbose") }, { oQuiet, "quiet", 0, N_("be somewhat more quiet") }, { oForceV3Sigs, "force-v3-sigs", 0, N_("force v3 signatures") }, + { oForceMDC, "force-mdc", 0, N_("always use a MDC for encryption") }, { oDryRun, "dry-run", 0, N_("do not make any changes") }, { oBatch, "batch", 0, N_("batch mode: never ask")}, { oAnswerYes, "yes", 0, N_("assume yes on most questions")}, @@ -701,6 +703,7 @@ main( int argc, char **argv ) case oComment: opt.comment_string = pargs.r.ret_str; break; case oThrowKeyid: opt.throw_keyid = 1; break; case oForceV3Sigs: opt.force_v3_sigs = 1; break; + case oForceMDC: opt.force_mdc = 1; break; case oS2KMode: opt.s2k_mode = pargs.r.ret_int; break; case oS2KDigest: s2k_digest_string = m_strdup(pargs.r.ret_str); break; case oS2KCipher: s2k_cipher_string = m_strdup(pargs.r.ret_str); break; @@ -1240,7 +1243,7 @@ main( int argc, char **argv ) set_packet_list_mode(1); opt.list_packets=1; } - proc_packets( a ); + proc_packets(NULL, a ); iobuf_close(a); } break; diff --git a/g10/keyedit.c b/g10/keyedit.c index 7ae006a68..1ba92a2cd 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -1,5 +1,5 @@ /* keyedit.c - keyedit stuff - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -56,6 +56,7 @@ 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 ); #define CONTROL_D ('D' - 'A' + 1) @@ -67,6 +68,7 @@ static int count_selected_keys( KBNODE keyblock ); #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 { @@ -119,6 +121,8 @@ check_all_keysigs( KBNODE keyblock, int only_selected ) int anyuid = 0; for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) { + int is_rev = 0; + if( node->pkt->pkttype == PKT_USER_ID ) { PKT_user_id *uid = node->pkt->pkt.user_id; @@ -135,7 +139,8 @@ check_all_keysigs( KBNODE keyblock, int only_selected ) } } else if( selected && node->pkt->pkttype == PKT_SIGNATURE - && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) { + && (node->pkt->pkt.signature->sig_class&~3) == 0x10 + && (is_rev = node->pkt->pkt.signature->sig_class == 0x30) ) { PKT_signature *sig = node->pkt->pkt.signature; int sigrc, selfsig; @@ -161,14 +166,16 @@ check_all_keysigs( KBNODE keyblock, int only_selected ) break; } if( sigrc != '?' ) { - tty_printf("sig%c %08lX %s ", + 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( selfsig ) { - tty_printf( _("[self-signature]") ); + tty_printf( is_rev? _("[revocation]") + : _("[self-signature]") ); if( sigrc == '!' ) has_selfsig = 1; } @@ -278,6 +285,8 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, int local ) && (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 */ @@ -514,7 +523,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands ) { enum cmdids { cmdNONE = 0, cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN, - cmdLSIGN, + cmdLSIGN, cmdREVSIG, cmdDEBUG, cmdSAVE, cmdADDUID, cmdDELUID, cmdADDKEY, cmdDELKEY, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE, cmdNOP }; @@ -550,6 +559,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands ) { N_("pref") , cmdPREF , 0, N_("list preferences") }, { N_("passwd") , cmdPASSWD , 1, N_("change the passphrase") }, { N_("trust") , cmdTRUST , 0, N_("change the ownertrust") }, + { N_("revsig") , cmdREVSIG , 0, N_("revoke signatures") }, { NULL, cmdNONE } }; enum cmdids cmd; @@ -852,6 +862,13 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands ) case cmdNOP: break; + case cmdREVSIG: + if( menu_revsig( keyblock ) ) { + redisplay = 1; + modified = 1; + } + break; + default: tty_printf("\n"); tty_printf(_("Invalid command (try \"help\")\n")); @@ -1490,3 +1507,160 @@ 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_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_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_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), PKT_SIGNATURE ); + goto reloop; + } + + if( upd_trust ) + clear_trust_checked_flag( primary_pk ); + + return changed; +} + + diff --git a/g10/mainproc.c b/g10/mainproc.c index 5d33f4edc..528f520ac 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -1,5 +1,5 @@ /* mainproc.c - handle packets - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -42,8 +42,9 @@ /**************** * Structure to hold the context */ - -typedef struct { +typedef struct mainproc_context *CTX; +struct mainproc_context { + struct mainproc_context *anchor; PKT_public_key *last_pubkey; PKT_secret_key *last_seckey; PKT_user_id *last_user_id; @@ -59,7 +60,8 @@ typedef struct { IOBUF iobuf; /* used to get the filename etc. */ int trustletter; /* temp usage in list_node */ ulong local_id; /* ditto */ -} *CTX; + int is_encrypted; /* used to check the MDC */ +}; static int do_proc_packets( CTX c, IOBUF a ); @@ -226,7 +228,8 @@ proc_encrypted( CTX c, PACKET *pkt ) { int result = 0; - /*printf("dat: %sencrypted data\n", c->dek?"":"conventional ");*/ + /*log_debug("dat: %sencrypted data\n", c->dek?"":"conventional ");*/ + c->is_encrypted = 1; if( !c->dek && !c->last_was_session_key ) { /* assume this is old conventional encrypted data */ c->dek = passphrase_to_dek( NULL, @@ -236,7 +239,7 @@ proc_encrypted( CTX c, PACKET *pkt ) else if( !c->dek ) result = G10ERR_NO_SECKEY; if( !result ) - result = decrypt_data( pkt->pkt.encrypted, c->dek ); + result = decrypt_data( c, pkt->pkt.encrypted, c->dek ); m_free(c->dek); c->dek = NULL; if( result == -1 ) ; @@ -289,10 +292,13 @@ proc_plaintext( CTX c, PACKET *pkt ) * 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) + * Hmmm: There is one problem: The MDC also uses a keyid of 0 + * and a pubkey algo of 0 - the only difference is that the + * sig_class will be 0. */ if( n->pkt->pkt.onepass_sig->sig_class == 0x01 && !n->pkt->pkt.onepass_sig->keyid[0] - && !n->pkt->pkt.onepass_sig->keyid[1] ) + && !n->pkt->pkt.onepass_sig->keyid[1] ) clearsig = 1; } } @@ -321,14 +327,14 @@ proc_plaintext( CTX c, PACKET *pkt ) static int proc_compressed_cb( IOBUF a, void *info ) { - return proc_signature_packets( a, ((CTX)info)->signed_data, - ((CTX)info)->sigfilename ); + 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( a ); + return proc_encryption_packets( info, a ); } static void @@ -339,19 +345,26 @@ proc_compressed( CTX c, PACKET *pkt ) /*printf("zip: compressed data packet\n");*/ if( c->sigs_only ) - rc = handle_compressed( zd, proc_compressed_cb, c ); + rc = handle_compressed( c, zd, proc_compressed_cb, c ); else if( c->encrypt_only ) - rc = handle_compressed( zd, proc_encrypt_cb, c ); + rc = handle_compressed( c, zd, proc_encrypt_cb, c ); else - rc = handle_compressed( zd, NULL, NULL ); + 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; } - - +static int +is_encrypted( CTX c ) +{ + for( ; c; c = c->anchor ) { + if( c->is_encrypted ) + return 1; + } + return 0; +} /**************** * check the signature @@ -370,17 +383,9 @@ do_check_sig( CTX c, KBNODE node, int *is_selfsig ) sig = node->pkt->pkt.signature; algo = sig->digest_algo; - if( !algo ) - return G10ERR_PUBKEY_ALGO; if( (rc=check_digest_algo(algo)) ) return rc; - if( c->mfx.md ) { - m_check(c->mfx.md); - if( c->mfx.md->list ) - m_check( c->mfx.md->list ); - } - if( sig->sig_class == 0x00 ) { if( c->mfx.md ) md = md_copy( c->mfx.md ); @@ -411,7 +416,12 @@ do_check_sig( CTX c, KBNODE node, int *is_selfsig ) } else return G10ERR_SIG_CLASS; - rc = signature_check( sig, md ); + if( sig->pubkey_algo ) + rc = signature_check( sig, md ); + else if( !is_encrypted( c ) ) + rc = G10ERR_NOT_ENCRYPTED; + else + rc = mdc_kludge_check( sig, md ); md_close(md); return rc; @@ -697,19 +707,25 @@ list_node( CTX c, KBNODE node ) int -proc_packets( IOBUF a ) +proc_packets( void *anchor, IOBUF a ) { + int rc; CTX c = m_alloc_clear( sizeof *c ); - int rc = do_proc_packets( c, a ); + + c->anchor = anchor; + rc = do_proc_packets( c, a ); m_free( c ); return rc; } int -proc_signature_packets( IOBUF a, STRLIST signedfiles, const char *sigfilename ) +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; @@ -719,10 +735,12 @@ proc_signature_packets( IOBUF a, STRLIST signedfiles, const char *sigfilename ) } int -proc_encryption_packets( IOBUF a ) +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 ); @@ -845,23 +863,41 @@ check_sig_and_print( CTX c, KBNODE node ) PKT_signature *sig = node->pkt->pkt.signature; const char *astr, *tstr; int rc; + int mdc_hack = !sig->pubkey_algo; - if( opt.skip_verify ) { + if( opt.skip_verify && !mdc_hack ) { 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"), + if( !mdc_hack ) { + 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 ) { + if( mdc_hack ) { + if( !rc ) { + if( opt.verbose ) + log_info(_("encrypted message is valid\n")); + write_status( STATUS_GOODMDC ); + } + else if( rc == G10ERR_BAD_SIGN ) { + log_error(_("WARNING: encrypted message has been manipulated!\n")); + write_status( STATUS_BADMDC ); + } + else { + write_status( STATUS_ERRMDC ); + log_error(_("Can't check MDC: %s\n"), g10_errstr(rc) ); + } + } + else if( !rc || rc == G10ERR_BAD_SIGN ) { KBNODE un, keyblock; char *us; int count=0; diff --git a/g10/options.h b/g10/options.h index c01bbd2a6..4f5457a4a 100644 --- a/g10/options.h +++ b/g10/options.h @@ -44,6 +44,7 @@ struct { int list_packets; /* list-packets mode */ int def_cipher_algo; int force_v3_sigs; + int force_mdc; int def_digest_algo; int def_compress_algo; const char *def_secret_key; diff --git a/g10/packet.h b/g10/packet.h index 36115be5b..312668317 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -233,9 +233,10 @@ typedef enum { /*-- mainproc.c --*/ -int proc_packets( IOBUF a ); -int proc_signature_packets( IOBUF a, STRLIST signedfiles, const char *sigfile ); -int proc_encryption_packets( IOBUF a ); +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 --*/ @@ -301,6 +302,7 @@ int cmp_user_ids( PKT_user_id *a, PKT_user_id *b ); /*-- sig-check.c --*/ int signature_check( PKT_signature *sig, MD_HANDLE digest ); +int mdc_kludge_check( PKT_signature *sig, MD_HANDLE digest ); /*-- seckey-cert.c --*/ int is_secret_key_protected( PKT_secret_key *sk ); @@ -311,11 +313,11 @@ int protect_secret_key( PKT_secret_key *sk, DEK *dek ); int get_session_key( PKT_pubkey_enc *k, DEK *dek ); /*-- compress.c --*/ -int handle_compressed( PKT_compressed *cd, +int handle_compressed( void *ctx, PKT_compressed *cd, int (*callback)(IOBUF, void *), void *passthru ); /*-- encr-data.c --*/ -int decrypt_data( PKT_encrypted *ed, DEK *dek ); +int decrypt_data( void *ctx, PKT_encrypted *ed, DEK *dek ); int encrypt_data( PKT_encrypted *ed, DEK *dek ); /*-- plaintext.c --*/ diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 61a226a39..94bf0f38d 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -1024,7 +1024,7 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, sig->digest_start[0] = iobuf_get_noeof(inp); pktlen--; sig->digest_start[1] = iobuf_get_noeof(inp); pktlen--; - if( is_v4 ) { /*extract required information */ + if( is_v4 && sig->pubkey_algo ) { /*extract required information */ const byte *p; /* set sig->flags.unknown_critical if there is a @@ -1065,24 +1065,36 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, } } - ndata = pubkey_get_nsig(sig->pubkey_algo); - if( !ndata ) { - if( list_mode ) - printf("\tunknown algorithm %d\n", sig->pubkey_algo ); - unknown_pubkey_warning( sig->pubkey_algo ); - /* we store the plain material in data[0], so that we are able - * to write it back with build_packet() */ - sig->data[0] = read_rest(inp, &pktlen ); + if( !sig->pubkey_algo ) { + n = pktlen; + sig->data[0] = mpi_read(inp, &n, 0 ); + pktlen -=n; + if( list_mode ) { + printf("\tMDC data: "); + mpi_print(stdout, sig->data[0], mpi_print_mode ); + putchar('\n'); + } } else { - for( i=0; i < ndata; i++ ) { - n = pktlen; - sig->data[i] = mpi_read(inp, &n, 0 ); - pktlen -=n; - if( list_mode ) { - printf("\tdata: "); - mpi_print(stdout, sig->data[i], mpi_print_mode ); - putchar('\n'); + ndata = pubkey_get_nsig(sig->pubkey_algo); + if( !ndata ) { + if( list_mode ) + printf("\tunknown algorithm %d\n", sig->pubkey_algo ); + unknown_pubkey_warning( sig->pubkey_algo ); + /* we store the plain material in data[0], so that we are able + * to write it back with build_packet() */ + sig->data[0] = read_rest(inp, &pktlen ); + } + else { + for( i=0; i < ndata; i++ ) { + n = pktlen; + sig->data[i] = mpi_read(inp, &n, 0 ); + pktlen -=n; + if( list_mode ) { + printf("\tdata: "); + mpi_print(stdout, sig->data[i], mpi_print_mode ); + putchar('\n'); + } } } } diff --git a/g10/revoke.c b/g10/revoke.c index 6467b8482..d93c7a462 100644 --- a/g10/revoke.c +++ b/g10/revoke.c @@ -201,4 +201,190 @@ gen_revoke( const char *uname ) return rc; } +#if 0 /* The code is not complete but anyway, now we use */ + /* the edit menu to revoke signature */ +/**************** + * Return true if there is already a revocation signature for KEYID + * in KEYBLOCK at point node. + */ +static int +already_revoked( const KBNODE keyblock, const KBNODE node, u32 *keyid ) ) { +{ + const KBNODE n = find_prev_kbnode( keyblock, node, PKT_USER_ID ); + + for( ; n; n = n->next ) { + PKT_signature *sig; + if( n->pkt->pkttype == PKT_SIGNATURE + && (sig = node->pkt->pkt.signature)->sig_class == 0x30 + && sig->keyid[0] == keyid[0] + && sig->keyid[1] == keyid[1] ) + return 1; + } + else if( n->pkt->pkttype == PKT_USER_ID + break; + else if( n->pkt->pkttype == PKT_PUBLIC_SUBKEY + break; + } + return 0; +} + +/**************** + * Ask whether the signature should be revoked. If the user commits this, + * flag bit 0 is set. + */ +static void +ask_revoke_sig( KBNODE keyblock, KBNODE node, PKT_signature *sig ) ) { +{ + 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, 0 ); + 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 |= 1; + } +} + +/**************** + * Generate a signature revocation certificate for UNAME + */ +int +gen_sig_revoke( const char *uname ) +{ + int rc = 0; + armor_filter_context_t afx; + compress_filter_context_t zfx; + PACKET pkt; + IOBUF out = NULL; + KBNODE keyblock = NULL; + KBNODE node; + KBPOS kbpos; + int uidchg; + + if( opt.batch ) { + log_error(_("sorry, can't do this in batch mode\n")); + return G10ERR_GENERAL; + } + + + memset( &afx, 0, sizeof afx); + memset( &zfx, 0, sizeof zfx); + init_packet( &pkt ); + + + /* get the keyblock */ + rc = find_keyblock_byname( &kbpos, uname ); + if( rc ) { + log_error(_("public key for user `%s' not found\n"), uname ); + goto leave; + } + + /* read the keyblock */ + rc = read_keyblock( &kbpos, &keyblock ); + if( rc ) { + log_error(_("error reading the certificate: %s\n"), g10_errstr(rc) ); + goto leave; + } + + /* get the keyid from the keyblock */ + node = find_kbnode( keyblock, PKT_PUBLIC_KEY ); + if( !node ) { + log_error(_("Oops; public key lost!\n")); + rc = G10ERR_GENERAL; + goto leave; + } + + if( (rc = open_outfile( NULL, 0, &out )) ) + goto leave; + + if( opt.armor ) { + afx.what = 1; + iobuf_push_filter( out, armor_filter, &afx ); + } + + /* Now walk over all signatures which we did with one of + * our secret keys. Hmmm: Should we check for duplicate signatures */ + clear_kbnode_flags( flags ); + for( node = keyblock; node; node = node->next ) { + PKT_signature *sig; + if( node->pkt->pkttype == PKT_SIGNATURE + && ((sig = node->pkt->pkt.signature)->sig_class&~3) == 0x10 + && seckey_available( sig->keyid ) + && !already_revoked( keyblock, node, sig->keyid ) ) { ) { + ask_revoke_sig( keyblock, node, sig ) + } + else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY + break; + } + + + for( node = keyblock; node; node = node->next ) { { + if( (node->flag & 1) ) + break; + } + if( !node ) { + log_info(_("nothing to revoke\n")); + iobuf_cancel(out); + out = NULL; + goto leave; + } + + init_packet( &pkt ); + pkt.pkttype = PKT_PUBLIC_KEY; + pkt.pkt.public_key = keyblock->pkt->pkt.public_key; + rc = build_packet( out, &pkt ); + if( rc ) { + log_error(_("build_packet failed: %s\n"), g10_errstr(rc) ); + goto leave; + } + uidchg = 1; + for( node = keyblock; node; node = node->next ) { + if( node->pkt->pkttype == PKT_USER_ID ) + uidchg = 1; + if( !(node->flag & 1) ) + continue; + + if( uidchg ) { + /* create a user ID packet */ + ....... + uidchg = 0; + } + + /* create it */ + rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x30, 0, NULL, NULL); + if( rc ) { + log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc)); + goto leave; + } + init_packet( &pkt ); + pkt.pkttype = PKT_SIGNATURE; + pkt.pkt.signature = sig; + + rc = build_packet( out, &pkt ); + if( rc ) { + log_error(_("build_packet failed: %s\n"), g10_errstr(rc) ); + goto leave; + } + } + + leave: + release_kbnode( keyblock ); + if( !out ) + ; + else if( rc ) + iobuf_cancel(out); + else + iobuf_close(out); + return rc; +} +#endif /* unused code */ diff --git a/g10/sig-check.c b/g10/sig-check.c index 885a5b587..8b1f51c3d 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -45,7 +45,7 @@ static int do_check( PKT_public_key *pk, PKT_signature *sig, /**************** * Check the signature which is contained in SIG. - * The md5handle should be currently open, so that this function + * The MD_HANDLE should be currently open, so that this function * is able to append some data, before finalizing the digest. */ int @@ -54,7 +54,6 @@ signature_check( PKT_signature *sig, MD_HANDLE digest ) PKT_public_key *pk = m_alloc_clear( sizeof *pk ); int rc=0; - if( is_RSA(sig->pubkey_algo) ) write_status(STATUS_RSA_OR_IDEA); @@ -108,6 +107,94 @@ signature_check( PKT_signature *sig, MD_HANDLE digest ) } + +/**************** + * Check the MDC which is contained in SIG. + * The MD_HANDLE should be currently open, so that this function + * is able to append some data, before finalizing the digest. + */ +int +mdc_kludge_check( PKT_signature *sig, MD_HANDLE digest ) +{ + int rc=0; + + if( (rc=check_digest_algo(sig->digest_algo)) ) + return rc; + + /* make sure the digest algo is enabled (in case of a detached mdc??) */ + md_enable( digest, sig->digest_algo ); + + /* complete the digest */ + if( sig->version >= 4 ) + md_putc( digest, sig->version ); + md_putc( digest, sig->sig_class ); + if( sig->version < 4 ) { + u32 a = sig->timestamp; + md_putc( digest, (a >> 24) & 0xff ); + md_putc( digest, (a >> 16) & 0xff ); + md_putc( digest, (a >> 8) & 0xff ); + md_putc( digest, a & 0xff ); + } + else { + byte buf[6]; + size_t n; + md_putc( digest, sig->pubkey_algo ); + md_putc( digest, sig->digest_algo ); + if( sig->hashed_data ) { + n = (sig->hashed_data[0] << 8) | sig->hashed_data[1]; + md_write( digest, sig->hashed_data, n+2 ); + n += 6; + } + else + n = 6; + /* add some magic */ + buf[0] = sig->version; + buf[1] = 0xff; + buf[2] = n >> 24; + buf[3] = n >> 16; + buf[4] = n >> 8; + buf[5] = n; + md_write( digest, buf, 6 ); + } + md_final( digest ); + + rc = G10ERR_BAD_SIGN; + { const byte *s1 = md_read( digest, sig->digest_algo ); + int s1len = md_digest_length( sig->digest_algo ); + + log_hexdump( "MDC calculated", s1, s1len ); + + if( !sig->data[0] ) + log_debug("sig_data[0] is NULL\n"); + else { + unsigned s2len; + byte *s2; + s2 = mpi_get_buffer( sig->data[0], &s2len, NULL ); + log_hexdump( "MDC stored ", s2, s2len ); + + if( s2len != s1len ) + log_debug("MDC check: len differ: %d/%d\n", s1len, s2len); + else if( memcmp( s1, s2, s1len ) ) + log_debug("MDC check: hashs differ\n"); + else + rc = 0; + m_free(s2); + } + } + + if( !rc && sig->flags.unknown_critical ) { + log_info(_("assuming bad MDC due to an unknown critical bit\n")); + rc = G10ERR_BAD_SIGN; + } + sig->flags.checked = 1; + sig->flags.valid = !rc; + + /* FIXME: check that we are actually in an encrypted packet */ + + return rc; +} + + /**************** * This function gets called by pubkey_verify() if the algorithm needs it. */ diff --git a/g10/sign.c b/g10/sign.c index 8924adab8..8cf5be7f5 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -656,7 +656,7 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk, MD_HANDLE md; assert( (sigclass >= 0x10 && sigclass <= 0x13) - || sigclass == 0x20 || sigclass == 0x18 ); + || sigclass == 0x20 || sigclass == 0x18 || sigclass == 0x30 ); if( !digest_algo ) { switch( sk->pubkey_algo ) { case PUBKEY_ALGO_DSA: digest_algo = DIGEST_ALGO_SHA1; break; diff --git a/g10/status.c b/g10/status.c index 9af3c9a5f..a832ea713 100644 --- a/g10/status.c +++ b/g10/status.c @@ -109,6 +109,9 @@ write_status_text ( int no, const char *text) case STATUS_DECRYPTION_OKAY: s = "DECRYPTION_OKAY\n"; break; case STATUS_MISSING_PASSPHRASE: s = "MISSING_PASSPHRASE\n"; break; case STATUS_GOOD_PASSPHRASE : s = "GOOD_PASSPHRASE\n"; break; + case STATUS_GOODMDC : s = "GOODMDC\n"; break; + case STATUS_BADMDC : s = "BADMDC\n"; break; + case STATUS_ERRMDC : s = "ERRMDC\n"; break; default: s = "?\n"; break; } diff --git a/g10/status.h b/g10/status.h index 083d7ce41..d8e13b70e 100644 --- a/g10/status.h +++ b/g10/status.h @@ -60,6 +60,9 @@ #define STATUS_DECRYPTION_OKAY 30 #define STATUS_MISSING_PASSPHRASE 31 #define STATUS_GOOD_PASSPHRASE 32 +#define STATUS_GOODMDC 33 +#define STATUS_BADMDC 34 +#define STATUS_ERRMDC 35 /*-- status.c --*/ void set_status_fd ( int fd ); diff --git a/g10/verify.c b/g10/verify.c index 4c8ea0196..589b1b7bb 100644 --- a/g10/verify.c +++ b/g10/verify.c @@ -77,7 +77,7 @@ verify_signatures( int nfiles, char **files ) sl = NULL; for(i=1 ; i < nfiles; i++ ) add_to_strlist( &sl, files[i] ); - rc = proc_signature_packets( fp, sl, sigfile ); + rc = proc_signature_packets( NULL, fp, sl, sigfile ); free_strlist(sl); iobuf_close(fp); return rc; diff --git a/include/errors.h b/include/errors.h index 32d1ea55e..247951271 100644 --- a/include/errors.h +++ b/include/errors.h @@ -70,7 +70,7 @@ #define G10ERR_NETWORK 48 /* general network error */ #define G10ERR_UNKNOWN_HOST 49 #define G10ERR_SELFTEST_FAILED 50 - +#define G10ERR_NOT_ENCRYPTED 51 #ifndef HAVE_STRERROR char *strerror( int n ); diff --git a/mpi/ChangeLog b/mpi/ChangeLog index 95f0e4055..7d66b809b 100644 --- a/mpi/ChangeLog +++ b/mpi/ChangeLog @@ -1,3 +1,9 @@ +Mon Apr 26 17:48:15 CEST 1999 Werner Koch + + * mpih-add.c, mpih-sub.c: Removed + * mpi-inline.c: New. + * mpi-inline.h: Make it usable by mpi-inline.c. + Sun Apr 18 10:11:28 CEST 1999 Werner Koch * mpih-mul.c (mpihelp_mul_n): Fixed use of memory region. diff --git a/mpi/Makefile.am b/mpi/Makefile.am index 2f743093e..42acb55fe 100644 --- a/mpi/Makefile.am +++ b/mpi/Makefile.am @@ -22,6 +22,7 @@ libmpi_a_SOURCES = longlong.h \ mpi-gcd.c \ mpi-internal.h \ mpi-inline.h \ + mpi-inline.c \ mpi-inv.c \ mpi-mul.c \ mpi-pow.c \ @@ -29,8 +30,6 @@ libmpi_a_SOURCES = longlong.h \ mpi-scan.c \ mpicoder.c \ mpih-cmp.c \ - mpih-add.c \ - mpih-sub.c \ mpih-div.c \ mpih-mul.c \ mpiutil.c \ diff --git a/mpi/mpi-inline.c b/mpi/mpi-inline.c new file mode 100644 index 000000000..7a2e7a4fd --- /dev/null +++ b/mpi/mpi-inline.c @@ -0,0 +1,36 @@ +/* mpi-inline.c + * Copyright (C) 1999 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include +#include + +/* put the inline functions as real functions into the lib */ +#define G10_MPI_INLINE_DECL + +#include "mpi-internal.h" + +/* always include the header becuase it is only + * included by mpi-internal if __GCC__ is defined but we + * need it here in all cases and the above definition of + * of the macro allows us to do so + */ +#include "mpi-inline.h" + diff --git a/mpi/mpi-inline.h b/mpi/mpi-inline.h index 5dc6fc0a3..8c7cedb60 100644 --- a/mpi/mpi-inline.h +++ b/mpi/mpi-inline.h @@ -1,5 +1,5 @@ /* mpi-inline.h - Internal to the Multi Precision Integers - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999 Free Software Foundation, Inc. * Copyright (C) 1994, 1996 Free Software Foundation, Inc. * * This file is part of GnuPG. @@ -30,8 +30,11 @@ #ifndef G10_MPI_INLINE_H #define G10_MPI_INLINE_H +#ifndef G10_MPI_INLINE_DECL + #define G10_MPI_INLINE_DECL extern __inline__ +#endif -extern __inline__ mpi_limb_t +G10_MPI_INLINE_DECL mpi_limb_t mpihelp_add_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size, mpi_limb_t s2_limb) { @@ -61,7 +64,7 @@ mpihelp_add_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, -extern __inline__ mpi_limb_t +G10_MPI_INLINE_DECL mpi_limb_t mpihelp_add(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size, mpi_ptr_t s2_ptr, mpi_size_t s2_size) { @@ -77,7 +80,7 @@ mpihelp_add(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size, } -extern __inline__ mpi_limb_t +G10_MPI_INLINE_DECL mpi_limb_t mpihelp_sub_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size, mpi_limb_t s2_limb ) { @@ -107,7 +110,7 @@ mpihelp_sub_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, -extern __inline__ mpi_limb_t +G10_MPI_INLINE_DECL mpi_limb_t mpihelp_sub( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size, mpi_ptr_t s2_ptr, mpi_size_t s2_size) { diff --git a/mpi/mpih-add.c b/mpi/mpih-add.c deleted file mode 100644 index d6b0c3eb0..000000000 --- a/mpi/mpih-add.c +++ /dev/null @@ -1,88 +0,0 @@ -/* mpihelp-add.c - MPI helper functions - * Copyright (C) 1998 Free Software Foundation, Inc. - * Copyright (C) 1994, 1996 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 - * - * Note: This code is heavily based on the GNU MP Library. - * Actually it's the same code with only minor changes in the - * way the data is stored; this is to support the abstraction - * of an optional secure memory allocation which may be used - * to avoid revealing of sensitive data due to paging etc. - * The GNU MP Library itself is published under the LGPL; - * however I decided to publish this code under the plain GPL. - */ - -#include -#include -#include - -#include "mpi-internal.h" - -/**************** - * Add to S1_PTR with size S1_SIZE the limb S2_LIMB and - * store the result in RES_PTR. Return the carry - * S1_SIZE must be > 0. - */ -#ifndef __GNUC__ -/*_EXTERN_INLINE */ -mpi_limb_t -mpihelp_add_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, - mpi_size_t s1_size, mpi_limb_t s2_limb) -{ - mpi_limb_t x; - - x = *s1_ptr++; - s2_limb += x; - *res_ptr++ = s2_limb; - if( s2_limb < x ) { /* sum is less than the left operand: handle carry */ - while( --s1_size ) { - x = *s1_ptr++ + 1; /* add carry */ - *res_ptr++ = x; /* and store */ - if( x ) /* not 0 (no overflow): we can stop */ - goto leave; - } - return 1; /* return carry (size of s1 to small) */ - } - - leave: - if( res_ptr != s1_ptr ) { /* not the same variable */ - mpi_size_t i; /* copy the rest */ - for( i=0; i < s1_size-1; i++ ) - res_ptr[i] = s1_ptr[i]; - } - return 0; /* no carry */ -} - - - -/*_EXTERN_INLINE*/ -mpi_limb_t -mpihelp_add(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size, - mpi_ptr_t s2_ptr, mpi_size_t s2_size) -{ - mpi_limb_t cy = 0; - - if( s2_size ) - cy = mpihelp_add_n( res_ptr, s1_ptr, s2_ptr, s2_size ); - - if( s1_size - s2_size ) - cy = mpihelp_add_1( res_ptr + s2_size, s1_ptr + s2_size, - s1_size - s2_size, cy); - return cy; -} -#endif diff --git a/mpi/mpih-sub.c b/mpi/mpih-sub.c deleted file mode 100644 index 7bfcddeae..000000000 --- a/mpi/mpih-sub.c +++ /dev/null @@ -1,81 +0,0 @@ -/* mpihelp-sub.c - MPI helper functions - * Copyright (C) 1998 Free Software Foundation, Inc. - * Copyright (C) 1994, 1996 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 - * - * Note: This code is heavily based on the GNU MP Library. - * Actually it's the same code with only minor changes in the - * way the data is stored; this is to support the abstraction - * of an optional secure memory allocation which may be used - * to avoid revealing of sensitive data due to paging etc. - * The GNU MP Library itself is published under the LGPL; - * however I decided to publish this code under the plain GPL. - */ - -#include -#include -#include - -#include "mpi-internal.h" - -#ifndef __GNUC__ -mpi_limb_t -mpihelp_sub_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, - mpi_size_t s1_size, mpi_limb_t s2_limb ) -{ - mpi_limb_t x; - - x = *s1_ptr++; - s2_limb = x - s2_limb; - *res_ptr++ = s2_limb; - if( s2_limb > x ) { - while( --s1_size ) { - x = *s1_ptr++; - *res_ptr++ = x - 1; - if( x ) - goto leave; - } - return 1; - } - - leave: - if( res_ptr != s1_ptr ) { - mpi_size_t i; - for( i=0; i < s1_size-1; i++ ) - res_ptr[i] = s1_ptr[i]; - } - return 0; -} - - -mpi_limb_t -mpihelp_sub( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size, - mpi_ptr_t s2_ptr, mpi_size_t s2_size) -{ - mpi_limb_t cy = 0; - - if( s2_size ) - cy = mpihelp_sub_n(res_ptr, s1_ptr, s2_ptr, s2_size); - - if( s1_size - s2_size ) - cy = mpihelp_sub_1(res_ptr + s2_size, s1_ptr + s2_size, - s1_size - s2_size, cy); - return cy; -} -#endif - diff --git a/util/errors.c b/util/errors.c index 3e9dbcf79..0590f8ed8 100644 --- a/util/errors.c +++ b/util/errors.c @@ -99,6 +99,7 @@ g10_errstr( int err ) X(INVALID_URI ,N_("unsupported URI")) X(NETWORK ,N_("network error")) X(SELFTEST_FAILED,"selftest failed") + X(NOT_ENCRYPTED ,N_("not encrypted")) default: p = buf; sprintf(buf, "g10err=%d", err); break; } #undef X