diff --git a/NEWS b/NEWS index 7e5ca2ce6..cbcd5d43a 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ Noteworthy changes in the current test release ---------------------------------------------- + * The user is now asked for the reason of revocation as required + by the new OpenPGP draft. + * There is a ~/.gnupg/random_seed file now which saves the state of the internal RNG and increases system performance somewhat. This way the full entropy source is only used in diff --git a/TODO b/TODO index 727c721b8..23a23783d 100644 --- a/TODO +++ b/TODO @@ -4,7 +4,7 @@ * --delete-secret-key should work even when the public key is not there. - * Add reason for revocation which is going to be a SHOULD + * Print the reason for revocation at certain places. * at least an option to prefer DSA keys over RSA when selecting the key to use. Depending on creatin time would be nice too. I thing this is diff --git a/g10/ChangeLog b/g10/ChangeLog index 2676d3215..7de3dddd1 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,21 @@ +Thu Feb 17 13:39:32 CET 2000 Werner Koch + + * revoke.c: Removed a bunch of commented code. + + * packet.h (SIGSUBPKT_REVOC_REASON): New. + * build-packet.c (build_sig_subpkt): Support new sub packet. + * parse-packet.c (parse_one_sig_subpkt): Ditto. + (dump_sig_subpkt): Ditto. + * revoke.c (ask_revocation_reason): New. + (release_revocation_reason_info): New. + (revocation_reason_build_cb): New. + (gen_revoke): Ask for reason. + * main.h (struct revocation_reason_info): Add declaration. + * keyedit.c (menu_revsig): Add support for revocation reason. + (menu_revkey): Ditto. + (sign_uid_mk_attrib): Renamed to ... + (sign_mk_attrib): ... this, made static and add support for reasons. + Tue Feb 15 08:48:13 CET 2000 Werner Koch * build-packet.c (build_packet): Fixed fixing of old comment packets. diff --git a/g10/build-packet.c b/g10/build-packet.c index 78c594db8..204611bcd 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -646,7 +646,6 @@ void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type, const byte *buffer, size_t buflen ) { - byte *data; size_t hlen, dlen, nlen; int found=0; @@ -682,6 +681,7 @@ build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type, case SIGSUBPKT_KEY_EXPIRE: case SIGSUBPKT_NOTATION: case SIGSUBPKT_POLICY: + case SIGSUBPKT_REVOC_REASON: hashed = 1; break; default: hashed = 0; break; } diff --git a/g10/helptext.c b/g10/helptext.c index e42902512..cda881fbd 100644 --- a/g10/helptext.c +++ b/g10/helptext.c @@ -224,6 +224,29 @@ static struct helptexts { const char *key; const char *help; } helptexts[] = { "file (which is shown in brackets) will be used." )}, +/* revoke.c (ask_revocation_reason) */ +{ "ask_revocation_reason.code", N_( + "You should specify a reason for the certification. Depending on the\n" + "context you have the ability to choose from this list:\n" + " \"Key has been compromised\"\n" + " Use this if you have a reason to believe that unauthorized persons\n" + " got access to your secret key.\n" + " \"Key is superseded\"\n" + " Use this if you have replaced this key with a newer one.\n" + " \"Key is no longer used\"\n" + " Use this if you have retired this key.\n" + " \"User ID is non longer valid\"\n" + " Use this to state that the user ID should not longer be used;\n" + " this is normally used to mark an email address invalid.\n" +)}, + +/* revoke.c (ask_revocation_reason) */ +{ "ask_revocation_reason.text", N_( + "If you like, you can enter a text describing why you issue this\n" + "revocation certificate. Please keep this text consis.\n" + "An empty line ends the text.\n" +)}, + /* end of list */ { NULL, NULL } }; diff --git a/g10/keyedit.c b/g10/keyedit.c index a56f55c4e..affe3b49b 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -74,8 +74,9 @@ static int enable_disable_key( KBNODE keyblock, int disable ); #define NODFLG_SELSIG (1<<10) /* indicate a selected signature */ -struct sign_uid_attrib { +struct sign_attrib { int non_exportable; + struct revocation_reason_info *reason; }; @@ -239,16 +240,18 @@ check_all_keysigs( KBNODE keyblock, int only_selected ) -int -sign_uid_mk_attrib( PKT_signature *sig, void *opaque ) +static int +sign_mk_attrib( PKT_signature *sig, void *opaque ) { - struct sign_uid_attrib *attrib = opaque; + struct sign_attrib *attrib = opaque; byte buf[8]; if( attrib->non_exportable ) { buf[0] = 0; /* not exportable */ build_sig_subpkt( sig, SIGSUBPKT_EXPORTABLE, buf, 1 ); } + if( attrib->reason ) + revocation_reason_build_cb( sig, attrib->reason ); return 0; } @@ -353,7 +356,7 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, int local ) && (node->flag & NODFLG_MARK_A) ) { PACKET *pkt; PKT_signature *sig; - struct sign_uid_attrib attrib; + struct sign_attrib attrib; assert( primary_pk ); memset( &attrib, 0, sizeof attrib ); @@ -364,7 +367,7 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, int local ) NULL, sk, 0x10, 0, - sign_uid_mk_attrib, + sign_mk_attrib, &attrib ); if( rc ) { log_error(_("signing failed: %s\n"), g10_errstr(rc)); @@ -1752,6 +1755,7 @@ menu_revsig( KBNODE keyblock ) int changed = 0; int upd_trust = 0; int rc, any; + struct revocation_reason_info *reason = NULL; /* FIXME: detect duplicates here */ tty_printf(_("You have signed these user IDs:\n")); @@ -1814,6 +1818,10 @@ menu_revsig( KBNODE keyblock ) _("Really create the revocation certificates? (y/N)")) ) return 0; /* forget it */ + reason = ask_revocation_reason( 0, 1, 0 ); + if( !reason ) { /* user decided to cancel */ + return 0; + } /* now we can sign the user ids */ reloop: /* (must use this, because we are modifing the list) */ @@ -1821,7 +1829,7 @@ menu_revsig( KBNODE keyblock ) for( node=keyblock; node; node = node->next ) { KBNODE unode; PACKET *pkt; - struct sign_uid_attrib attrib; + struct sign_attrib attrib; PKT_secret_key *sk; if( !(node->flag & NODFLG_MARK_A) @@ -1831,6 +1839,8 @@ menu_revsig( KBNODE keyblock ) assert( unode ); /* we already checked this */ memset( &attrib, 0, sizeof attrib ); + attrib.reason = reason; + node->flag &= ~NODFLG_MARK_A; sk = m_alloc_secure_clear( sizeof *sk ); if( get_seckey( sk, node->pkt->pkt.signature->keyid ) ) { @@ -1842,11 +1852,12 @@ menu_revsig( KBNODE keyblock ) NULL, sk, 0x30, 0, - sign_uid_mk_attrib, + sign_mk_attrib, &attrib ); free_secret_key(sk); if( rc ) { log_error(_("signing failed: %s\n"), g10_errstr(rc)); + release_revocation_reason_info( reason ); return changed; } changed = 1; /* we changed the keyblock */ @@ -1861,7 +1872,7 @@ menu_revsig( KBNODE keyblock ) if( upd_trust ) clear_trust_checked_flag( primary_pk ); - + release_revocation_reason_info( reason ); return changed; } @@ -1878,6 +1889,13 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock ) int changed = 0; int upd_trust = 0; int rc; + struct revocation_reason_info *reason = NULL; + + reason = ask_revocation_reason( 1, 0, 0 ); + if( !reason ) { /* user decided to cancel */ + return 0; + } + reloop: /* (better this way because we are modifing the keyring) */ mainpk = pub_keyblock->pkt->pkt.public_key; @@ -1888,14 +1906,20 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock ) PKT_signature *sig; PKT_secret_key *sk; PKT_public_key *subpk = node->pkt->pkt.public_key; + struct sign_attrib attrib; + + memset( &attrib, 0, sizeof attrib ); + attrib.reason = reason; 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 ); + sign_mk_attrib, + &attrib ); free_secret_key(sk); if( rc ) { log_error(_("signing failed: %s\n"), g10_errstr(rc)); + release_revocation_reason_info( reason ); return changed; } changed = 1; /* we changed the keyblock */ @@ -1914,6 +1938,7 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock ) if( upd_trust ) clear_trust_checked_flag( mainpk ); + release_revocation_reason_info( reason ); return changed; } diff --git a/g10/main.h b/g10/main.h index e578c9cf7..9a4969415 100644 --- a/g10/main.h +++ b/g10/main.h @@ -131,7 +131,12 @@ int dearmor_file( const char *fname ); int enarmor_file( const char *fname ); /*-- revoke.c --*/ +struct revocation_reason_info; int gen_revoke( const char *uname ); +int revocation_reason_build_cb( PKT_signature *sig, void *opaque ); +struct revocation_reason_info * + ask_revocation_reason( int key_rev, int cert_rev, int hint ); +void release_revocation_reason_info( struct revocation_reason_info *reason ); /*-- keylist.c --*/ void public_key_list( STRLIST list ); diff --git a/g10/packet.h b/g10/packet.h index 3a05f0d52..41782dcc3 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -239,6 +239,7 @@ typedef enum { SIGSUBPKT_POLICY =26, /* policy URL */ SIGSUBPKT_KEY_FLAGS =27, /* key flags */ SIGSUBPKT_SIGNERS_UID =28, /* signer's user id */ + SIGSUBPKT_REVOC_REASON =29, /* reason for revocation */ SIGSUBPKT_PRIV_ADD_SIG =101,/* signatur is also valid for this uid */ SIGSUBPKT_FLAG_CRITICAL=128 diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 93dc094db..8b12216cc 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -811,6 +811,13 @@ dump_sig_subpkt( int hashed, int type, int critical, case SIGSUBPKT_SIGNERS_UID: p = "signer's user ID"; break; + case SIGSUBPKT_REVOC_REASON: + if( length ) { + printf("revocation reason 0x%02x (", *buffer ); + print_string( stdout, buffer+1, length-1, ')' ); + p = ")"; + } + break; case SIGSUBPKT_PRIV_ADD_SIG: p = "signs additional user ID"; break; @@ -848,6 +855,10 @@ parse_one_sig_subpkt( const byte *buffer, size_t n, int type ) if( n < 8 ) /* minimum length needed */ break; return 0; + case SIGSUBPKT_REVOC_REASON: + if( !n ) + break; + return 0; case SIGSUBPKT_PREF_SYM: case SIGSUBPKT_PREF_HASH: case SIGSUBPKT_PREF_COMPR: @@ -885,7 +896,7 @@ can_handle_critical( const byte *buffer, size_t n, int type ) case SIGSUBPKT_PREF_COMPR: return 1; - case SIGSUBPKT_POLICY: /* Is enough to show the policy? */ + case SIGSUBPKT_POLICY: /* Is it enough to show the policy? */ default: return 0; } diff --git a/g10/revoke.c b/g10/revoke.c index cc89409e2..3683c3006 100644 --- a/g10/revoke.c +++ b/g10/revoke.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "options.h" #include "packet.h" @@ -37,6 +38,38 @@ #include "i18n.h" +struct revocation_reason_info { + int code; + char *desc; +}; + + +int +revocation_reason_build_cb( PKT_signature *sig, void *opaque ) +{ + struct revocation_reason_info *reason = opaque; + char *ud = NULL; + byte *buffer; + size_t buflen = 1; + + if( reason->desc ) { + ud = native_to_utf8( reason->desc ); + buflen += strlen(ud); + } + buffer = m_alloc( buflen ); + *buffer = reason->code; + if( ud ) { + memcpy(buffer+1, ud, strlen(ud) ); + m_free( ud ); + } + + build_sig_subpkt( sig, SIGSUBPKT_REVOC_REASON, buffer, buflen ); + m_free( buffer ); + return 0; +} + + + /**************** * Generate a revocation certificate for UNAME */ @@ -55,6 +88,7 @@ gen_revoke( const char *uname ) KBNODE keyblock = NULL; KBNODE node; KBPOS kbpos; + struct revocation_reason_info *reason = NULL; if( opt.batch ) { log_error(_("sorry, can't do this in batch mode\n")); @@ -62,19 +96,6 @@ gen_revoke( const char *uname ) } - /* FIXME: ask for the reason of revocation - 0x00 - No reason specified (key revocations or cert revocations) - Does not make sense! - - 0x01 - Key is superceded (key revocations) - 0x02 - Key material has been compromised (key revocations) - 0x03 - Key is no longer used (key revocations) - 0x20 - User id information is no longer valid (cert revocations) - - Following the revocation code is a string of octets which gives - information about the reason for revocation in human-readable form - */ - memset( &afx, 0, sizeof afx); memset( &zfx, 0, sizeof zfx); init_packet( &pkt ); @@ -136,6 +157,13 @@ gen_revoke( const char *uname ) goto leave; } + /* get the reason for the revocation */ + reason = ask_revocation_reason( 1, 0, 1 ); + if( !reason ) { /* user decided to cancel */ + rc = 0; + goto leave; + } + switch( is_secret_key_protected( sk ) ) { case -1: log_error(_("unknown protection algorithm\n")); @@ -163,7 +191,9 @@ gen_revoke( const char *uname ) iobuf_push_filter( out, armor_filter, &afx ); /* create it */ - rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0, NULL, NULL); + rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0, + revocation_reason_build_cb, + reason ); if( rc ) { log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc)); goto leave; @@ -198,193 +228,127 @@ gen_revoke( const char *uname ) iobuf_cancel(out); else iobuf_close(out); + release_revocation_reason_info( reason ); 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; + +struct revocation_reason_info * +ask_revocation_reason( int key_rev, int cert_rev, int hint ) +{ + int code; + char *description = NULL; + struct revocation_reason_info *reason; + const char *text_1 = _("Key has been compromised"); + const char *text_2 = _("Key is superseded"); + const char *text_3 = _("Key is no longer used"); + const char *text_4 = _("User ID is non longer valid"); + const char *code_text = NULL; + + do { + m_free(description); + description = NULL; + + tty_printf(_("Please select the reason for the revocation:\n")); + if( key_rev ) + tty_printf(" 1 = %s\n", text_1 ); + if( key_rev ) + tty_printf(" 2 = %s\n", text_2 ); + if( key_rev ) + tty_printf(" 3 = %s\n", text_3 ); + if( cert_rev ) + tty_printf(" 4 = %s\n", text_4 ); + tty_printf( " 0 = %s\n", _("Cancel") ); + if( hint ) + tty_printf(_("(Probably you want to select %d here)\n"), hint ); + + for(code = 0; !code;) { + int n; + char *answer = cpr_get("ask_revocation_reason.code", + _("Your decision? ")); + trim_spaces( answer ); + cpr_kill_prompt(); + if( *answer == 'q' || *answer == 'Q' ) + n = 0; + else if( !isdigit( *answer ) ) + n = -1; + else if( hint && !*answer ) + n = hint; + else + n = atoi(answer); + m_free(answer); + if( !n ) + return NULL; /* cancel */ + else if( key_rev && n == 1 ) { + code = 0x02; /* key has been compromised */ + code_text = text_1; + } + else if( key_rev && n == 2 ) { + code = 0x01; /* key is superseded */ + code_text = text_2; + } + else if( key_rev && n == 3 ) { + code = 0x03; /* key is no longer used */ + code_text = text_3; + } + else if( cert_rev && n == 4 ) { + code = 0x20; /* uid is non longer valid */ + code_text = text_4; + } + else + tty_printf(_("Invalid selection.\n")); } - else if( n->pkt->pkttype == PKT_USER_ID - break; - else if( n->pkt->pkttype == PKT_PUBLIC_SUBKEY - break; - } - return 0; + + tty_printf(_("Enter an optional description; " + "end it with an empty line:\n") ); + for(;;) { + char *answer = cpr_get("ask_revocation_reason.text", "> " ); + trim_trailing_ws( answer, strlen(answer) ); + cpr_kill_prompt(); + if( !*answer ) { + m_free(answer); + break; + } + + { + char *p = make_printable_string( answer, strlen(answer), 0 ); + m_free(answer); + answer = p; + } + + if( !description ) + description = m_strdup(answer); + else { + char *p = m_alloc( strlen(description) + strlen(answer) + 2 ); + strcpy(stpcpy(stpcpy( p, description),"\n"),answer); + m_free(description); + description = p; + } + m_free(answer); + } + + tty_printf(_("Reason for revocation: %s\n"), code_text ); + if( !description ) + tty_printf(_("(No description given)\n") ); + else + tty_printf("%s\n", description ); + + } while( !cpr_get_answer_is_yes("ask_revocation_reason.okay", + _("Is this okay? ")) ); + + reason = m_alloc( sizeof *reason ); + reason->code = code; + reason->desc = description; + return reason; } -/**************** - * 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 ) ) { +void +release_revocation_reason_info( struct revocation_reason_info *reason ) { - 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_utf8_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; + if( reason ) { + m_free( reason->desc ); + m_free( reason ); } } -/**************** - * 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 */ -