See ChangeLog: Sat May 22 22:47:26 CEST 1999 Werner Koch
[gnupg.git] / g10 / keyedit.c
1 /* keyedit.c - keyedit stuff
2  *      Copyright (C) 1998, 1999 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27 #include <ctype.h>
28
29 #include "options.h"
30 #include "packet.h"
31 #include "errors.h"
32 #include "iobuf.h"
33 #include "keydb.h"
34 #include "memory.h"
35 #include "util.h"
36 #include "main.h"
37 #include "trustdb.h"
38 #include "filter.h"
39 #include "ttyio.h"
40 #include "status.h"
41 #include "i18n.h"
42
43 static void show_prefs( KBNODE keyblock, PKT_user_id *uid );
44 static void show_key_with_all_names( KBNODE keyblock,
45             int only_marked, int with_fpr, int with_subkeys, int with_prefs );
46 static void show_key_and_fingerprint( KBNODE keyblock );
47 static void show_fingerprint( PKT_public_key *pk );
48 static int menu_adduid( KBNODE keyblock, KBNODE sec_keyblock );
49 static void menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock );
50 static void menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock );
51 static int menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock );
52 static int menu_select_uid( KBNODE keyblock, int idx );
53 static int menu_select_key( KBNODE keyblock, int idx );
54 static int count_uids( KBNODE keyblock );
55 static int count_uids_with_flag( KBNODE keyblock, unsigned flag );
56 static int count_keys_with_flag( KBNODE keyblock, unsigned flag );
57 static int count_selected_uids( KBNODE keyblock );
58 static int count_selected_keys( KBNODE keyblock );
59 static int menu_revsig( KBNODE keyblock );
60 static int menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock );
61
62 #define CONTROL_D ('D' - 'A' + 1)
63
64 #define NODFLG_BADSIG (1<<0)  /* bad signature */
65 #define NODFLG_NOKEY  (1<<1)  /* no public key */
66 #define NODFLG_SIGERR (1<<2)  /* other sig error */
67
68 #define NODFLG_MARK_A (1<<4)  /* temporary mark */
69
70 #define NODFLG_SELUID (1<<8)  /* indicate the selected userid */
71 #define NODFLG_SELKEY (1<<9)  /* indicate the selected key */
72 #define NODFLG_SELSIG (1<<10) /* indicate a selected signature */
73
74
75 struct sign_uid_attrib {
76     int non_exportable;
77 };
78
79
80
81
82 static int
83 get_keyblock_byname( KBNODE *keyblock, KBPOS *kbpos, const char *username )
84 {
85     int rc;
86
87     *keyblock = NULL;
88     /* search the userid */
89     rc = find_keyblock_byname( kbpos, username );
90     if( rc ) {
91         log_error(_("%s: user not found\n"), username );
92         return rc;
93     }
94
95     /* read the keyblock */
96     rc = read_keyblock( kbpos, keyblock );
97     if( rc )
98         log_error("%s: keyblock read problem: %s\n", username, g10_errstr(rc));
99     else
100         merge_keys_and_selfsig( *keyblock );
101
102     return rc;
103 }
104
105
106 /****************
107  * Check the keysigs and set the flags to indicate errors.
108  * Returns true if error found.
109  */
110 static int
111 check_all_keysigs( KBNODE keyblock, int only_selected )
112 {
113     KBNODE kbctx;
114     KBNODE node;
115     int rc;
116     int inv_sigs = 0;
117     int no_key = 0;
118     int oth_err = 0;
119     int has_selfsig = 0;
120     int mis_selfsig = 0;
121     int selected = !only_selected;
122     int anyuid = 0;
123
124     for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
125         if( node->pkt->pkttype == PKT_USER_ID ) {
126             PKT_user_id *uid = node->pkt->pkt.user_id;
127
128             if( only_selected )
129                 selected = (node->flag & NODFLG_SELUID);
130             if( selected ) {
131                 tty_printf("uid  ");
132                 tty_print_string( uid->name, uid->len );
133                 tty_printf("\n");
134                 if( anyuid && !has_selfsig )
135                     mis_selfsig++;
136                 has_selfsig = 0;
137                 anyuid = 1;
138             }
139         }
140         else if( selected && node->pkt->pkttype == PKT_SIGNATURE
141                  && ( (node->pkt->pkt.signature->sig_class&~3) == 0x10
142                      || node->pkt->pkt.signature->sig_class == 0x30 )  ) {
143             PKT_signature *sig = node->pkt->pkt.signature;
144             int sigrc, selfsig;
145             int is_rev = sig->sig_class == 0x30;
146
147             switch( (rc = check_key_signature( keyblock, node, &selfsig)) ) {
148               case 0:
149                 node->flag &= ~(NODFLG_BADSIG|NODFLG_NOKEY|NODFLG_SIGERR);
150                 sigrc = '!';
151                 break;
152               case G10ERR_BAD_SIGN:
153                 node->flag = NODFLG_BADSIG;
154                 sigrc = '-';
155                 inv_sigs++;
156                 break;
157               case G10ERR_NO_PUBKEY:
158                 node->flag = NODFLG_NOKEY;
159                 sigrc = '?';
160                 no_key++;
161                 break;
162               default:
163                 node->flag = NODFLG_SIGERR;
164                 sigrc = '%';
165                 oth_err++;
166                 break;
167             }
168             if( sigrc != '?' ) {
169                 tty_printf("%s%c       %08lX %s   ",
170                         is_rev? "rev":"sig",
171                         sigrc, sig->keyid[1], datestr_from_sig(sig));
172                 if( sigrc == '%' )
173                     tty_printf("[%s] ", g10_errstr(rc) );
174                 else if( sigrc == '?' )
175                     ;
176                 else if( selfsig ) {
177                     tty_printf( is_rev? _("[revocation]")
178                                       : _("[self-signature]") );
179                     if( sigrc == '!' )
180                         has_selfsig = 1;
181                 }
182                 else {
183                     size_t n;
184                     char *p = get_user_id( sig->keyid, &n );
185                     tty_print_string( p, n > 40? 40 : n );
186                     m_free(p);
187                 }
188                 tty_printf("\n");
189                 /* fixme: Should we update the trustdb here */
190             }
191         }
192     }
193     if( !has_selfsig )
194         mis_selfsig++;
195     if( inv_sigs == 1 )
196         tty_printf(_("1 bad signature\n"), inv_sigs );
197     else if( inv_sigs )
198         tty_printf(_("%d bad signatures\n"), inv_sigs );
199     if( no_key == 1 )
200         tty_printf(_("1 signature not checked due to a missing key\n") );
201     else if( no_key )
202         tty_printf(_("%d signatures not checked due to missing keys\n"), no_key );
203     if( oth_err == 1 )
204         tty_printf(_("1 signature not checked due to an error\n") );
205     else if( oth_err )
206         tty_printf(_("%d signatures not checked due to errors\n"), oth_err );
207     if( mis_selfsig == 1 )
208         tty_printf(_("1 user id without valid self-signature detected\n"));
209     else if( mis_selfsig  )
210         tty_printf(_("%d user ids without valid self-signatures detected\n"),
211                                                                     mis_selfsig);
212
213     return inv_sigs || no_key || oth_err || mis_selfsig;
214 }
215
216
217
218
219 int
220 sign_uid_mk_attrib( PKT_signature *sig, void *opaque )
221 {
222     struct sign_uid_attrib *attrib = opaque;
223     byte buf[8];
224
225     if( attrib->non_exportable ) {
226         buf[0] = 0; /* not exportable */
227         build_sig_subpkt( sig, SIGSUBPKT_EXPORTABLE, buf, 1 );
228     }
229
230     return 0;
231 }
232
233
234
235 /****************
236  * Loop over all locusr and and sign the uids after asking.
237  * If no user id is marked, all user ids will be signed;
238  * if some user_ids are marked those will be signed.
239  */
240 static int
241 sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, int local )
242 {
243     int rc = 0;
244     SK_LIST sk_list = NULL;
245     SK_LIST sk_rover = NULL;
246     PKT_secret_key *sk = NULL;
247     KBNODE node, uidnode;
248     PKT_public_key *primary_pk=NULL;
249     int select_all = !count_selected_uids(keyblock);
250     int upd_trust = 0;
251
252     /* build a list of all signators */
253     rc=build_sk_list( locusr, &sk_list, 0, 1 );
254     if( rc )
255         goto leave;
256
257     /* loop over all signaturs */
258     for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
259         u32 sk_keyid[2];
260         size_t n;
261         char *p;
262
263         /* we have to use a copy of the sk, because make_keysig_packet
264          * may remove the protection from sk and if we did other
265          * changes to the secret key, we would save the unprotected
266          * version */
267         if( sk )
268             free_secret_key(sk);
269         sk = copy_secret_key( NULL, sk_rover->sk );
270         keyid_from_sk( sk, sk_keyid );
271         /* set mark A for all selected user ids */
272         for( node=keyblock; node; node = node->next ) {
273             if( select_all || (node->flag & NODFLG_SELUID) )
274                 node->flag |= NODFLG_MARK_A;
275             else
276                 node->flag &= ~NODFLG_MARK_A;
277         }
278         /* reset mark for uids which are already signed */
279         uidnode = NULL;
280         for( node=keyblock; node; node = node->next ) {
281             if( node->pkt->pkttype == PKT_USER_ID ) {
282                 uidnode = (node->flag & NODFLG_MARK_A)? node : NULL;
283             }
284             else if( uidnode && node->pkt->pkttype == PKT_SIGNATURE
285                 && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
286                 if( sk_keyid[0] == node->pkt->pkt.signature->keyid[0]
287                     && sk_keyid[1] == node->pkt->pkt.signature->keyid[1] ) {
288                     /* Fixme: see whether there is a revocation in which
289                      * case we should allow to sign it again. */
290                     tty_printf(_("Already signed by key %08lX\n"),
291                                                         (ulong)sk_keyid[1] );
292                     uidnode->flag &= ~NODFLG_MARK_A; /* remove mark */
293                 }
294             }
295         }
296         /* check whether any uids are left for signing */
297         if( !count_uids_with_flag(keyblock, NODFLG_MARK_A) ) {
298             tty_printf(_("Nothing to sign with key %08lX\n"),
299                                                   (ulong)sk_keyid[1] );
300             continue;
301         }
302         /* Ask whether we really should sign these user id(s) */
303         tty_printf("\n");
304         show_key_with_all_names( keyblock, 1, 1, 0, 0 );
305         tty_printf("\n");
306         tty_printf(_(
307              "Are you really sure that you want to sign this key\n"
308              "with your key: \""));
309         p = get_user_id( sk_keyid, &n );
310         tty_print_string( p, n );
311         m_free(p); p = NULL;
312         tty_printf("\"\n\n");
313
314         if( local )
315             tty_printf(
316                   _("The signature will be marked as non-exportable.\n\n"));
317
318
319         if( opt.batch && opt.answer_yes )
320             ;
321         else if( !cpr_get_answer_is_yes("sign_uid.okay", _("Really sign? ")) )
322             continue;
323         /* now we can sign the user ids */
324       reloop: /* (must use this, because we are modifing the list) */
325         primary_pk = NULL;
326         for( node=keyblock; node; node = node->next ) {
327             if( node->pkt->pkttype == PKT_PUBLIC_KEY )
328                 primary_pk = node->pkt->pkt.public_key;
329             else if( node->pkt->pkttype == PKT_USER_ID
330                      && (node->flag & NODFLG_MARK_A) ) {
331                 PACKET *pkt;
332                 PKT_signature *sig;
333                 struct sign_uid_attrib attrib;
334
335                 assert( primary_pk );
336                 memset( &attrib, 0, sizeof attrib );
337                 attrib.non_exportable = local;
338                 node->flag &= ~NODFLG_MARK_A;
339                 rc = make_keysig_packet( &sig, primary_pk,
340                                                node->pkt->pkt.user_id,
341                                                NULL,
342                                                sk,
343                                                0x10, 0,
344                                                sign_uid_mk_attrib,
345                                                &attrib );
346                 if( rc ) {
347                     log_error(_("signing failed: %s\n"), g10_errstr(rc));
348                     goto leave;
349                 }
350                 *ret_modified = 1; /* we changed the keyblock */
351                 upd_trust = 1;
352
353                 pkt = m_alloc_clear( sizeof *pkt );
354                 pkt->pkttype = PKT_SIGNATURE;
355                 pkt->pkt.signature = sig;
356                 insert_kbnode( node, new_kbnode(pkt), PKT_SIGNATURE );
357                 goto reloop;
358             }
359         }
360     } /* end loop over signators */
361     if( upd_trust && primary_pk ) {
362         rc = clear_trust_checked_flag( primary_pk );
363     }
364
365
366   leave:
367     release_sk_list( sk_list );
368     if( sk )
369         free_secret_key(sk);
370     return rc;
371 }
372
373
374
375 /****************
376  * Change the passphrase of the primary and all secondary keys.
377  * We use only one passphrase for all keys.
378  */
379 static int
380 change_passphrase( KBNODE keyblock )
381 {
382     int rc = 0;
383     int changed=0;
384     KBNODE node;
385     PKT_secret_key *sk;
386     char *passphrase = NULL;
387
388     node = find_kbnode( keyblock, PKT_SECRET_KEY );
389     if( !node ) {
390         log_error("Oops; secret key not found anymore!\n");
391         goto leave;
392     }
393     sk = node->pkt->pkt.secret_key;
394
395     switch( is_secret_key_protected( sk ) ) {
396       case -1:
397         rc = G10ERR_PUBKEY_ALGO;
398         break;
399       case 0:
400         tty_printf(_("This key is not protected.\n"));
401         break;
402       default:
403         tty_printf(_("Key is protected.\n"));
404         rc = check_secret_key( sk, 0 );
405         if( !rc )
406             passphrase = get_last_passphrase();
407         break;
408     }
409
410     /* unprotect all subkeys (use the supplied passphrase or ask)*/
411     for(node=keyblock; !rc && node; node = node->next ) {
412         if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
413             PKT_secret_key *subsk = node->pkt->pkt.secret_key;
414             set_next_passphrase( passphrase );
415             rc = check_secret_key( subsk, 0 );
416         }
417     }
418
419     if( rc )
420         tty_printf(_("Can't edit this key: %s\n"), g10_errstr(rc));
421     else {
422         DEK *dek = NULL;
423         STRING2KEY *s2k = m_alloc_secure( sizeof *s2k );
424
425         tty_printf(_("Enter the new passphrase for this secret key.\n\n") );
426
427         set_next_passphrase( NULL );
428         for(;;) {
429             s2k->mode = opt.s2k_mode;
430             s2k->hash_algo = opt.s2k_digest_algo;
431             dek = passphrase_to_dek( NULL, opt.s2k_cipher_algo, s2k, 2 );
432             if( !dek ) {
433                 tty_printf(_("passphrase not correctly repeated; try again.\n"));
434             }
435             else if( !dek->keylen ) {
436                 rc = 0;
437                 tty_printf(_( "You don't want a passphrase -"
438                             " this is probably a *bad* idea!\n\n"));
439                 if( cpr_get_answer_is_yes("change_passwd.empty.okay",
440                                _("Do you really want to do this? ")))
441                     changed++;
442                 break;
443             }
444             else { /* okay */
445                 sk->protect.algo = dek->algo;
446                 sk->protect.s2k = *s2k;
447                 rc = protect_secret_key( sk, dek );
448                 for(node=keyblock; !rc && node; node = node->next ) {
449                     if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
450                         PKT_secret_key *subsk = node->pkt->pkt.secret_key;
451                         subsk->protect.algo = dek->algo;
452                         subsk->protect.s2k = *s2k;
453                         rc = protect_secret_key( subsk, dek );
454                     }
455                 }
456                 if( rc )
457                     log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
458                 else
459                     changed++;
460                 break;
461             }
462         }
463         m_free(s2k);
464         m_free(dek);
465     }
466
467   leave:
468     m_free( passphrase );
469     set_next_passphrase( NULL );
470     return changed && !rc;
471 }
472
473
474 /****************
475  * There are some keys out (due to a bug in gnupg), where the sequence
476  * of the packets is wrong.  This function fixes that.
477  * Returns: true if the keyblock has been fixed.
478  *
479  * Note:  This function does not work if there is more than one user ID.
480  */
481 static int
482 fix_keyblock( KBNODE keyblock )
483 {
484     KBNODE node, last, subkey;
485     int fixed=0;
486
487     /* locate key signatures of class 0x10..0x13 behind sub key packets */
488     for( subkey=last=NULL, node = keyblock; node;
489                                             last=node, node = node->next ) {
490         switch( node->pkt->pkttype ) {
491           case PKT_PUBLIC_SUBKEY:
492           case PKT_SECRET_SUBKEY:
493             if( !subkey )
494                 subkey = last; /* actually it is the one before the subkey */
495             break;
496           case PKT_SIGNATURE:
497             if( subkey ) {
498                 PKT_signature *sig = node->pkt->pkt.signature;
499                 if( sig->sig_class >= 0x10 && sig->sig_class <= 0x13 ) {
500                     log_info(_(
501                         "moving a key signature to the correct place\n"));
502                     last->next = node->next;
503                     node->next = subkey->next;
504                     subkey->next = node;
505                     node = last;
506                     fixed=1;
507                 }
508             }
509             break;
510           default: break;
511         }
512     }
513
514     return fixed;
515 }
516
517 /****************
518  * Menu driven key editor
519  *
520  * Note: to keep track of some selection we use node->mark MARKBIT_xxxx.
521  */
522
523 void
524 keyedit_menu( const char *username, STRLIST locusr, STRLIST commands )
525 {
526     enum cmdids { cmdNONE = 0,
527            cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN,
528            cmdLSIGN, cmdREVSIG, cmdREVKEY,
529            cmdDEBUG, cmdSAVE, cmdADDUID, cmdDELUID, cmdADDKEY, cmdDELKEY,
530            cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE,
531            cmdNOP };
532     static struct { const char *name;
533                     enum cmdids id;
534                     int need_sk;
535                     const char *desc;
536                   } cmds[] = {
537         { N_("quit")    , cmdQUIT   , 0, N_("quit this menu") },
538         { N_("q")       , cmdQUIT   , 0, NULL   },
539         { N_("save")    , cmdSAVE   , 0, N_("save and quit") },
540         { N_("help")    , cmdHELP   , 0, N_("show this help") },
541         {    "?"        , cmdHELP   , 0, NULL   },
542         { N_("fpr")     , cmdFPR    , 0, N_("show fingerprint") },
543         { N_("list")    , cmdLIST   , 0, N_("list key and user ids") },
544         { N_("l")       , cmdLIST   , 0, NULL   },
545         { N_("uid")     , cmdSELUID , 0, N_("select user id N") },
546         { N_("key")     , cmdSELKEY , 0, N_("select secondary key N") },
547         { N_("check")   , cmdCHECK  , 0, N_("list signatures") },
548         { N_("c")       , cmdCHECK  , 0, NULL },
549         { N_("sign")    , cmdSIGN   , 0, N_("sign the key") },
550         { N_("s")       , cmdSIGN   , 0, NULL },
551         { N_("lsign")   , cmdLSIGN  , 0, N_("sign the key locally") },
552         { N_("debug")   , cmdDEBUG  , 0, NULL },
553         { N_("adduid")  , cmdADDUID , 1, N_("add a user id") },
554         { N_("deluid")  , cmdDELUID , 0, N_("delete user id") },
555         { N_("addkey")  , cmdADDKEY , 1, N_("add a secondary key") },
556         { N_("delkey")  , cmdDELKEY , 0, N_("delete a secondary key") },
557         { N_("expire")  , cmdEXPIRE , 1, N_("change the expire date") },
558         { N_("toggle")  , cmdTOGGLE , 1, N_("toggle between secret "
559                                             "and public key listing") },
560         { N_("t"     )  , cmdTOGGLE , 1, NULL },
561         { N_("pref")    , cmdPREF  , 0, N_("list preferences") },
562         { N_("passwd")  , cmdPASSWD , 1, N_("change the passphrase") },
563         { N_("trust")   , cmdTRUST , 0, N_("change the ownertrust") },
564         { N_("revsig")  , cmdREVSIG , 0, N_("revoke signatures") },
565         { N_("revkey")  , cmdREVKEY , 1, N_("revoke a secondary key") },
566
567     { NULL, cmdNONE } };
568     enum cmdids cmd;
569     int rc = 0;
570     KBNODE keyblock = NULL;
571     KBPOS keyblockpos;
572     KBNODE sec_keyblock = NULL;
573     KBPOS sec_keyblockpos;
574     KBNODE cur_keyblock;
575     char *answer = NULL;
576     int redisplay = 1;
577     int modified = 0;
578     int sec_modified = 0;
579     int toggle;
580     int have_commands = !!commands;
581
582
583     if( opt.batch && !have_commands ) {
584         log_error(_("can't do that in batchmode\n"));
585         goto leave;
586     }
587
588     /* first try to locate it as secret key */
589     rc = find_secret_keyblock_byname( &sec_keyblockpos, username );
590     if( !rc ) {
591         rc = read_keyblock( &sec_keyblockpos, &sec_keyblock );
592         if( rc ) {
593             log_error("%s: secret keyblock read problem: %s\n",
594                                             username, g10_errstr(rc));
595             goto leave;
596         }
597         merge_keys_and_selfsig( sec_keyblock );
598         if( fix_keyblock( sec_keyblock ) )
599             sec_modified++;
600     }
601
602     /* and now get the public key */
603     rc = get_keyblock_byname( &keyblock, &keyblockpos, username );
604     if( rc )
605         goto leave;
606     if( fix_keyblock( keyblock ) )
607         modified++;
608     if( collapse_uids( &keyblock ) )
609         modified++;
610
611     if( sec_keyblock ) { /* check that they match */
612         /* FIXME: check that they both match */
613         tty_printf(_("Secret key is available.\n"));
614     }
615
616     toggle = 0;
617     cur_keyblock = keyblock;
618     for(;;) { /* main loop */
619         int i, arg_number;
620         char *p;
621
622         tty_printf("\n");
623         if( redisplay ) {
624             show_key_with_all_names( cur_keyblock, 0, 0, 1, 0 );
625             tty_printf("\n");
626             redisplay = 0;
627         }
628         do {
629             m_free(answer);
630             if( have_commands ) {
631                 if( commands ) {
632                     answer = m_strdup( commands->d );
633                     commands = commands->next;
634                 }
635                 else if( opt.batch ) {
636                     answer = m_strdup("quit");
637                 }
638                 else
639                     have_commands = 0;
640             }
641             if( !have_commands ) {
642                 answer = cpr_get("keyedit.cmd", _("Command> "));
643                 cpr_kill_prompt();
644             }
645             trim_spaces(answer);
646         } while( *answer == '#' );
647
648         arg_number = 0;
649         if( !*answer )
650             cmd = cmdLIST;
651         else if( *answer == CONTROL_D )
652             cmd = cmdQUIT;
653         else if( isdigit( *answer ) ) {
654             cmd = cmdSELUID;
655             arg_number = atoi(answer);
656         }
657         else {
658             if( (p=strchr(answer,' ')) ) {
659                 *p++ = 0;
660                 trim_spaces(answer);
661                 trim_spaces(p);
662                 arg_number = atoi(p);
663             }
664
665             for(i=0; cmds[i].name; i++ )
666                 if( !stricmp( answer, cmds[i].name ) )
667                     break;
668             if( cmds[i].need_sk && !sec_keyblock ) {
669                 tty_printf(_("Need the secret key to do this.\n"));
670                 cmd = cmdNOP;
671             }
672             else
673                 cmd = cmds[i].id;
674         }
675         switch( cmd )  {
676           case cmdHELP:
677             for(i=0; cmds[i].name; i++ ) {
678                 if( cmds[i].need_sk && !sec_keyblock )
679                     ; /* skip if we do not have the secret key */
680                 else if( cmds[i].desc )
681                     tty_printf("%-10s %s\n", cmds[i].name, _(cmds[i].desc) );
682             }
683             break;
684
685           case cmdQUIT:
686             if( have_commands )
687                 goto leave;
688             if( !modified && !sec_modified )
689                 goto leave;
690             if( !cpr_get_answer_is_yes("keyedit.save.okay",
691                                         _("Save changes? ")) ) {
692                 if( cpr_enabled()
693                     || cpr_get_answer_is_yes("keyedit.cancel.okay",
694                                              _("Quit without saving? ")) )
695                     goto leave;
696                 break;
697             }
698             /* fall thru */
699           case cmdSAVE:
700             if( modified || sec_modified  ) {
701                 if( modified ) {
702                     rc = update_keyblock( &keyblockpos, keyblock );
703                     if( rc ) {
704                         log_error(_("update failed: %s\n"), g10_errstr(rc) );
705                         break;
706                     }
707                 }
708                 if( sec_modified ) {
709                     rc = update_keyblock( &sec_keyblockpos, sec_keyblock );
710                     if( rc ) {
711                         log_error(_("update secret failed: %s\n"),
712                                                             g10_errstr(rc) );
713                         break;
714                     }
715                 }
716             }
717             else
718                 tty_printf(_("Key not changed so no update needed.\n"));
719             rc = update_trust_record( keyblock, 0, NULL );
720             if( rc )
721                 log_error(_("update of trustdb failed: %s\n"),
722                             g10_errstr(rc) );
723             goto leave;
724
725           case cmdLIST:
726             redisplay = 1;
727             break;
728
729           case cmdFPR:
730             show_key_and_fingerprint( keyblock );
731             break;
732
733           case cmdSELUID:
734             if( menu_select_uid( cur_keyblock, arg_number ) )
735                 redisplay = 1;
736             break;
737
738           case cmdSELKEY:
739             if( menu_select_key( cur_keyblock, arg_number ) )
740                 redisplay = 1;
741             break;
742
743           case cmdCHECK:
744             /* we can only do this with the public key becuase the
745              * check functions can't cope with secret keys and it
746              * is questionable whether this would make sense at all */
747             check_all_keysigs( keyblock, count_selected_uids(keyblock) );
748             break;
749
750           case cmdSIGN: /* sign (only the public key) */
751           case cmdLSIGN: /* sign (only the public key) */
752             if( count_uids(keyblock) > 1 && !count_selected_uids(keyblock) ) {
753                 if( !cpr_get_answer_is_yes("keyedit.sign_all.okay",
754                                            _("Really sign all user ids? ")) ) {
755                     tty_printf(_("Hint: Select the user ids to sign\n"));
756                     break;
757                 }
758             }
759             sign_uids( keyblock, locusr, &modified, cmd == cmdLSIGN );
760             break;
761
762           case cmdDEBUG:
763             dump_kbnode( cur_keyblock );
764             break;
765
766           case cmdTOGGLE:
767             toggle = !toggle;
768             cur_keyblock = toggle? sec_keyblock : keyblock;
769             redisplay = 1;
770             break;
771
772           case cmdADDUID:
773             if( menu_adduid( keyblock, sec_keyblock ) ) {
774                 redisplay = 1;
775                 sec_modified = modified = 1;
776                 /* must update the trustdb already here, so that preferences
777                  * get listed correctly */
778                 rc = update_trust_record( keyblock, 0, NULL );
779                 if( rc ) {
780                     log_error(_("update of trustdb failed: %s\n"),
781                                 g10_errstr(rc) );
782                     rc = 0;
783                 }
784             }
785             break;
786
787           case cmdDELUID: {
788                 int n1;
789
790                 if( !(n1=count_selected_uids(keyblock)) )
791                     tty_printf(_("You must select at least one user id.\n"));
792                 else if( count_uids(keyblock) - n1 < 1 )
793                     tty_printf(_("You can't delete the last user id!\n"));
794                 else if( cpr_get_answer_is_yes(
795                             "keyedit.remove.uid.okay",
796                         n1 > 1? _("Really remove all selected user ids? ")
797                               : _("Really remove this user id? ")
798                        ) ) {
799                     menu_deluid( keyblock, sec_keyblock );
800                     redisplay = 1;
801                     modified = 1;
802                     if( sec_keyblock )
803                        sec_modified = 1;
804                 }
805             }
806             break;
807
808           case cmdADDKEY:
809             if( generate_subkeypair( keyblock, sec_keyblock ) ) {
810                 redisplay = 1;
811                 sec_modified = modified = 1;
812             }
813             break;
814
815
816           case cmdDELKEY: {
817                 int n1;
818
819                 if( !(n1=count_selected_keys( keyblock )) )
820                     tty_printf(_("You must select at least one key.\n"));
821                 else if( sec_keyblock && !cpr_get_answer_is_yes(
822                             "keyedit.remove.subkey.okay",
823                        n1 > 1?
824                         _("Do you really want to delete the selected keys? "):
825                         _("Do you really want to delete this key? ")
826                        ))
827                     ;
828                 else {
829                     menu_delkey( keyblock, sec_keyblock );
830                     redisplay = 1;
831                     modified = 1;
832                     if( sec_keyblock )
833                        sec_modified = 1;
834                 }
835             }
836             break;
837
838           case cmdREVKEY: {
839                 int n1;
840
841                 if( !(n1=count_selected_keys( keyblock )) )
842                     tty_printf(_("You must select at least one key.\n"));
843                 else if( sec_keyblock && !cpr_get_answer_is_yes(
844                             "keyedit.revoke.subkey.okay",
845                        n1 > 1?
846                         _("Do you really want to revoke the selected keys? "):
847                         _("Do you really want to revoke this key? ")
848                        ))
849                     ;
850                 else {
851                     if( menu_revkey( keyblock, sec_keyblock ) ) {
852                         modified = 1;
853                         /*sec_modified = 1;*/
854                     }
855                     redisplay = 1;
856                 }
857             }
858             break;
859
860           case cmdEXPIRE:
861             if( menu_expire( keyblock, sec_keyblock ) ) {
862                 merge_keys_and_selfsig( sec_keyblock );
863                 merge_keys_and_selfsig( keyblock );
864                 sec_modified = 1;
865                 modified = 1;
866                 redisplay = 1;
867             }
868             break;
869
870           case cmdPASSWD:
871             if( change_passphrase( sec_keyblock ) )
872                 sec_modified = 1;
873             break;
874
875           case cmdTRUST:
876             show_key_with_all_names( keyblock, 0, 0, 1, 0 );
877             tty_printf("\n");
878             if( edit_ownertrust( find_kbnode( keyblock,
879                       PKT_PUBLIC_KEY )->pkt->pkt.public_key->local_id, 1 ) )
880                 redisplay = 1;
881             /* we don't need to set modified here, as the trustvalues
882              * are updated immediately */
883             break;
884
885           case cmdPREF:
886             show_key_with_all_names( keyblock, 0, 0, 0, 1 );
887             break;
888
889           case cmdNOP:
890             break;
891
892           case cmdREVSIG:
893             if( menu_revsig( keyblock ) ) {
894                 redisplay = 1;
895                 modified = 1;
896             }
897             break;
898
899           default:
900             tty_printf("\n");
901             tty_printf(_("Invalid command  (try \"help\")\n"));
902             break;
903         }
904     } /* end main loop */
905
906   leave:
907     release_kbnode( keyblock );
908     release_kbnode( sec_keyblock );
909     m_free(answer);
910 }
911
912
913 /****************
914  * show preferences of a public keyblock.
915  */
916 static void
917 show_prefs( KBNODE keyblock, PKT_user_id *uid )
918 {
919     KBNODE node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
920     PKT_public_key *pk;
921     byte *p;
922     int i;
923     size_t n;
924     byte namehash[20];
925
926     if( !node )
927         return; /* is a secret keyblock */
928     pk = node->pkt->pkt.public_key;
929     if( !pk->local_id ) {
930         log_error("oops: no LID\n");
931         return;
932     }
933
934     rmd160_hash_buffer( namehash, uid->name, uid->len );
935
936     p = get_pref_data( pk->local_id, namehash, &n );
937     if( !p )
938         return;
939
940     tty_printf("    ");
941     for(i=0; i < n; i+=2 ) {
942         if( p[i] )
943             tty_printf( " %c%d", p[i] == PREFTYPE_SYM    ? 'S' :
944                                  p[i] == PREFTYPE_HASH   ? 'H' :
945                                  p[i] == PREFTYPE_COMPR  ? 'Z' : '?', p[i+1]);
946     }
947     tty_printf("\n");
948
949     m_free(p);
950 }
951
952
953 /****************
954  * Display the key a the user ids, if only_marked is true, do only
955  * so for user ids with mark A flag set and dont display the index number
956  */
957 static void
958 show_key_with_all_names( KBNODE keyblock, int only_marked,
959                          int with_fpr, int with_subkeys, int with_prefs )
960 {
961     KBNODE node;
962     int i, rc;
963
964     /* the keys */
965     for( node = keyblock; node; node = node->next ) {
966         if( node->pkt->pkttype == PKT_PUBLIC_KEY
967             || (with_subkeys && node->pkt->pkttype == PKT_PUBLIC_SUBKEY) ) {
968             PKT_public_key *pk = node->pkt->pkt.public_key;
969             int otrust=0, trust=0;
970
971             if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
972                 /* do it here, so that debug messages don't clutter the
973                  * output */
974                 trust = query_trust_info(pk, NULL);
975                 otrust = get_ownertrust_info( pk->local_id );
976             }
977
978             tty_printf("%s%c %4u%c/%08lX  created: %s expires: %s",
979                           node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub",
980                           (node->flag & NODFLG_SELKEY)? '*':' ',
981                           nbits_from_pk( pk ),
982                           pubkey_letter( pk->pubkey_algo ),
983                           (ulong)keyid_from_pk(pk,NULL),
984                           datestr_from_pk(pk),
985                           expirestr_from_pk(pk) );
986             if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
987                 tty_printf(" trust: %c/%c", otrust, trust );
988                 if( with_fpr  ) {
989                     tty_printf("\n");
990                     show_fingerprint( pk );
991                 }
992             }
993             tty_printf("\n");
994         }
995         else if( node->pkt->pkttype == PKT_SECRET_KEY
996             || (with_subkeys && node->pkt->pkttype == PKT_SECRET_SUBKEY) ) {
997             PKT_secret_key *sk = node->pkt->pkt.secret_key;
998             tty_printf("%s%c %4u%c/%08lX  created: %s expires: %s\n",
999                           node->pkt->pkttype == PKT_SECRET_KEY? "sec":"sbb",
1000                           (node->flag & NODFLG_SELKEY)? '*':' ',
1001                           nbits_from_sk( sk ),
1002                           pubkey_letter( sk->pubkey_algo ),
1003                           (ulong)keyid_from_sk(sk,NULL),
1004                           datestr_from_sk(sk),
1005                           expirestr_from_sk(sk) );
1006         }
1007         else if( with_subkeys && node->pkt->pkttype == PKT_SIGNATURE
1008                  && node->pkt->pkt.signature->sig_class == 0x28       ) {
1009             PKT_signature *sig = node->pkt->pkt.signature;
1010
1011             rc = check_key_signature( keyblock, node, NULL );
1012             if( !rc )
1013                 tty_printf( "rev! subkey has been revoked: %s\n",
1014                             datestr_from_sig( sig ) );
1015             else if( rc == G10ERR_BAD_SIGN )
1016                 tty_printf( "rev- faked revocation found\n" );
1017             else if( rc )
1018                 tty_printf( "rev? problem checking revocation: %s\n",
1019                                                          g10_errstr(rc) );
1020         }
1021     }
1022     /* the user ids */
1023     i = 0;
1024     for( node = keyblock; node; node = node->next ) {
1025         if( node->pkt->pkttype == PKT_USER_ID ) {
1026             PKT_user_id *uid = node->pkt->pkt.user_id;
1027             ++i;
1028             if( !only_marked || (only_marked && (node->flag & NODFLG_MARK_A))){
1029                 if( only_marked )
1030                    tty_printf("     ");
1031                 else if( node->flag & NODFLG_SELUID )
1032                    tty_printf("(%d)* ", i);
1033                 else
1034                    tty_printf("(%d)  ", i);
1035                 tty_print_string( uid->name, uid->len );
1036                 tty_printf("\n");
1037                 if( with_prefs )
1038                     show_prefs( keyblock, uid );
1039             }
1040         }
1041     }
1042 }
1043
1044 static void
1045 show_key_and_fingerprint( KBNODE keyblock )
1046 {
1047     KBNODE node;
1048     PKT_public_key *pk = NULL;
1049
1050     for( node = keyblock; node; node = node->next ) {
1051         if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
1052             pk = node->pkt->pkt.public_key;
1053             tty_printf("pub  %4u%c/%08lX %s ",
1054                           nbits_from_pk( pk ),
1055                           pubkey_letter( pk->pubkey_algo ),
1056                           (ulong)keyid_from_pk(pk,NULL),
1057                           datestr_from_pk(pk) );
1058         }
1059         else if( node->pkt->pkttype == PKT_USER_ID ) {
1060             PKT_user_id *uid = node->pkt->pkt.user_id;
1061             tty_print_string( uid->name, uid->len );
1062             break;
1063         }
1064     }
1065     tty_printf("\n");
1066     if( pk )
1067         show_fingerprint( pk );
1068 }
1069
1070
1071 static void
1072 show_fingerprint( PKT_public_key *pk )
1073 {
1074     byte array[MAX_FINGERPRINT_LEN], *p;
1075     size_t i, n;
1076
1077     fingerprint_from_pk( pk, array, &n );
1078     p = array;
1079     tty_printf("             Fingerprint:");
1080     if( n == 20 ) {
1081         for(i=0; i < n ; i++, i++, p += 2 ) {
1082             if( i == 10 )
1083                 tty_printf(" ");
1084             tty_printf(" %02X%02X", *p, p[1] );
1085         }
1086     }
1087     else {
1088         for(i=0; i < n ; i++, p++ ) {
1089             if( i && !(i%8) )
1090                 tty_printf(" ");
1091             tty_printf(" %02X", *p );
1092         }
1093     }
1094     tty_printf("\n");
1095 }
1096
1097
1098 /****************
1099  * Ask for a new user id , do the selfsignature and put it into
1100  * both keyblocks.
1101  * Return true if there is a new user id
1102  */
1103 static int
1104 menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock )
1105 {
1106     PKT_user_id *uid;
1107     PKT_public_key *pk=NULL;
1108     PKT_secret_key *sk=NULL;
1109     PKT_signature *sig=NULL;
1110     PACKET *pkt;
1111     KBNODE node;
1112     KBNODE pub_where=NULL, sec_where=NULL;
1113     int rc;
1114
1115     uid = generate_user_id();
1116     if( !uid )
1117         return 0;
1118
1119     for( node = pub_keyblock; node; pub_where = node, node = node->next ) {
1120         if( node->pkt->pkttype == PKT_PUBLIC_KEY )
1121             pk = node->pkt->pkt.public_key;
1122         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
1123             break;
1124     }
1125     if( !node ) /* no subkey */
1126         pub_where = NULL;
1127     for( node = sec_keyblock; node; sec_where = node, node = node->next ) {
1128         if( node->pkt->pkttype == PKT_SECRET_KEY )
1129             sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
1130         else if( node->pkt->pkttype == PKT_SECRET_SUBKEY )
1131             break;
1132     }
1133     if( !node ) /* no subkey */
1134         sec_where = NULL;
1135     assert(pk && sk );
1136
1137     rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0,
1138                              keygen_add_std_prefs, pk );
1139     free_secret_key( sk );
1140     if( rc ) {
1141         log_error("signing failed: %s\n", g10_errstr(rc) );
1142         free_user_id(uid);
1143         return 0;
1144     }
1145
1146     /* insert/append to secret keyblock */
1147     pkt = m_alloc_clear( sizeof *pkt );
1148     pkt->pkttype = PKT_USER_ID;
1149     pkt->pkt.user_id = copy_user_id(NULL, uid);
1150     node = new_kbnode(pkt);
1151     if( sec_where )
1152         insert_kbnode( sec_where, node, 0 );
1153     else
1154         add_kbnode( sec_keyblock, node );
1155     pkt = m_alloc_clear( sizeof *pkt );
1156     pkt->pkttype = PKT_SIGNATURE;
1157     pkt->pkt.signature = copy_signature(NULL, sig);
1158     if( sec_where )
1159         insert_kbnode( node, new_kbnode(pkt), 0 );
1160     else
1161         add_kbnode( sec_keyblock, new_kbnode(pkt) );
1162     /* insert/append to public keyblock */
1163     pkt = m_alloc_clear( sizeof *pkt );
1164     pkt->pkttype = PKT_USER_ID;
1165     pkt->pkt.user_id = uid;
1166     node = new_kbnode(pkt);
1167     if( pub_where )
1168         insert_kbnode( pub_where, node, 0 );
1169     else
1170         add_kbnode( pub_keyblock, node );
1171     pkt = m_alloc_clear( sizeof *pkt );
1172     pkt->pkttype = PKT_SIGNATURE;
1173     pkt->pkt.signature = copy_signature(NULL, sig);
1174     if( pub_where )
1175         insert_kbnode( node, new_kbnode(pkt), 0 );
1176     else
1177         add_kbnode( pub_keyblock, new_kbnode(pkt) );
1178     return 1;
1179 }
1180
1181
1182 /****************
1183  * Remove all selceted userids from the keyrings
1184  */
1185 static void
1186 menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock )
1187 {
1188     KBNODE node;
1189     int selected=0;
1190
1191     for( node = pub_keyblock; node; node = node->next ) {
1192         if( node->pkt->pkttype == PKT_USER_ID ) {
1193             selected = node->flag & NODFLG_SELUID;
1194             if( selected ) {
1195                 delete_kbnode( node );
1196                 if( sec_keyblock ) {
1197                     KBNODE snode;
1198                     int s_selected = 0;
1199                     PKT_user_id *uid = node->pkt->pkt.user_id;
1200                     for( snode = sec_keyblock; snode; snode = snode->next ) {
1201                         if( snode->pkt->pkttype == PKT_USER_ID ) {
1202                             PKT_user_id *suid = snode->pkt->pkt.user_id;
1203
1204                             s_selected =
1205                                 (uid->len == suid->len
1206                                  && !memcmp( uid->name, suid->name, uid->len));
1207                             if( s_selected )
1208                                 delete_kbnode( snode );
1209                         }
1210                         else if( s_selected
1211                                  && snode->pkt->pkttype == PKT_SIGNATURE )
1212                             delete_kbnode( snode );
1213                         else if( snode->pkt->pkttype == PKT_SECRET_SUBKEY )
1214                             s_selected = 0;
1215                     }
1216                 }
1217             }
1218         }
1219         else if( selected && node->pkt->pkttype == PKT_SIGNATURE )
1220             delete_kbnode( node );
1221         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
1222             selected = 0;
1223     }
1224     commit_kbnode( &pub_keyblock );
1225     if( sec_keyblock )
1226         commit_kbnode( &sec_keyblock );
1227 }
1228
1229
1230 /****************
1231  * Remove some of the secondary keys
1232  */
1233 static void
1234 menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
1235 {
1236     KBNODE node;
1237     int selected=0;
1238
1239     for( node = pub_keyblock; node; node = node->next ) {
1240         if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
1241             selected = node->flag & NODFLG_SELKEY;
1242             if( selected ) {
1243                 delete_kbnode( node );
1244                 if( sec_keyblock ) {
1245                     KBNODE snode;
1246                     int s_selected = 0;
1247                     u32 ki[2];
1248
1249                     keyid_from_pk( node->pkt->pkt.public_key, ki );
1250                     for( snode = sec_keyblock; snode; snode = snode->next ) {
1251                         if( snode->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1252                             u32 ki2[2];
1253
1254                             keyid_from_sk( snode->pkt->pkt.secret_key, ki2 );
1255                             s_selected = (ki[0] == ki2[0] && ki[1] == ki2[1]);
1256                             if( s_selected )
1257                                 delete_kbnode( snode );
1258                         }
1259                         else if( s_selected
1260                                  && snode->pkt->pkttype == PKT_SIGNATURE )
1261                             delete_kbnode( snode );
1262                         else
1263                             s_selected = 0;
1264                     }
1265                 }
1266             }
1267         }
1268         else if( selected && node->pkt->pkttype == PKT_SIGNATURE )
1269             delete_kbnode( node );
1270         else
1271             selected = 0;
1272     }
1273     commit_kbnode( &pub_keyblock );
1274     if( sec_keyblock )
1275         commit_kbnode( &sec_keyblock );
1276 }
1277
1278
1279
1280 static int
1281 menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
1282 {
1283     int n1, signumber, rc;
1284     u32 expiredate;
1285     int mainkey=0;
1286     PKT_secret_key *sk;    /* copy of the main sk */
1287     PKT_public_key *main_pk, *sub_pk;
1288     PKT_user_id *uid;
1289     KBNODE node;
1290     u32 keyid[2];
1291
1292     if( count_selected_keys( sec_keyblock ) ) {
1293         tty_printf(_("Please remove selections from the secret keys.\n"));
1294         return 0;
1295     }
1296
1297     n1 = count_selected_keys( pub_keyblock );
1298     if( n1 > 1 ) {
1299         tty_printf(_("Please select at most one secondary key.\n"));
1300         return 0;
1301     }
1302     else if( n1 )
1303         tty_printf(_("Changing exiration time for a secondary key.\n"));
1304     else {
1305         tty_printf(_("Changing exiration time for the primary key.\n"));
1306         mainkey=1;
1307     }
1308
1309     expiredate = ask_expiredate();
1310     node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
1311     sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
1312
1313     /* Now we can actually change the self signature(s) */
1314     main_pk = sub_pk = NULL;
1315     uid = NULL;
1316     signumber = 0;
1317     for( node=pub_keyblock; node; node = node->next ) {
1318         if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
1319             main_pk = node->pkt->pkt.public_key;
1320             keyid_from_pk( main_pk, keyid );
1321             main_pk->expiredate = expiredate;
1322         }
1323         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1324                  && (node->flag & NODFLG_SELKEY ) ) {
1325             sub_pk = node->pkt->pkt.public_key;
1326             sub_pk->expiredate = expiredate;
1327         }
1328         else if( node->pkt->pkttype == PKT_USER_ID )
1329             uid = node->pkt->pkt.user_id;
1330         else if( main_pk && node->pkt->pkttype == PKT_SIGNATURE ) {
1331             PKT_signature *sig = node->pkt->pkt.signature;
1332             if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
1333                 && (    (mainkey && uid && (sig->sig_class&~3) == 0x10)
1334                      || (!mainkey && sig->sig_class == 0x18)  ) ) {
1335                 /* this is a selfsignature which is to be replaced */
1336                 PKT_signature *newsig;
1337                 PACKET *newpkt;
1338                 KBNODE sn;
1339                 int signumber2 = 0;
1340
1341                 signumber++;
1342
1343                 if( (mainkey && main_pk->version < 4)
1344                     || (!mainkey && sub_pk->version < 4 ) ) {
1345                     log_info(_(
1346                         "You can't change the expiration date of a v3 key\n"));
1347                     free_secret_key( sk );
1348                     return 0;
1349                 }
1350
1351                 /* find the corresponding secret self-signature */
1352                 for( sn=sec_keyblock; sn; sn = sn->next ) {
1353                     if( sn->pkt->pkttype == PKT_SIGNATURE ) {
1354                         PKT_signature *b = sn->pkt->pkt.signature;
1355                         if( keyid[0] == b->keyid[0] && keyid[1] == b->keyid[1]
1356                             && sig->sig_class == b->sig_class
1357                             && ++signumber2 == signumber )
1358                             break;
1359                     }
1360                 }
1361                 if( !sn )
1362                     log_info(_("No corresponding signature in secret ring\n"));
1363
1364                 /* create new self signature */
1365                 if( mainkey )
1366                     rc = make_keysig_packet( &newsig, main_pk, uid, NULL,
1367                                              sk, 0x13, 0,
1368                                              keygen_add_std_prefs, main_pk );
1369                 else
1370                     rc = make_keysig_packet( &newsig, main_pk, NULL, sub_pk,
1371                                              sk, 0x18, 0,
1372                                              keygen_add_key_expire, sub_pk );
1373                 if( rc ) {
1374                     log_error("make_keysig_packet failed: %s\n",
1375                                                     g10_errstr(rc));
1376                     free_secret_key( sk );
1377                     return 0;
1378                 }
1379                 /* replace the packet */
1380                 newpkt = m_alloc_clear( sizeof *newpkt );
1381                 newpkt->pkttype = PKT_SIGNATURE;
1382                 newpkt->pkt.signature = newsig;
1383                 free_packet( node->pkt );
1384                 m_free( node->pkt );
1385                 node->pkt = newpkt;
1386                 if( sn ) {
1387                     newpkt = m_alloc_clear( sizeof *newpkt );
1388                     newpkt->pkttype = PKT_SIGNATURE;
1389                     newpkt->pkt.signature = copy_signature( NULL, newsig );
1390                     free_packet( sn->pkt );
1391                     m_free( sn->pkt );
1392                     sn->pkt = newpkt;
1393                 }
1394             }
1395         }
1396     }
1397
1398     free_secret_key( sk );
1399     return 1;
1400 }
1401
1402
1403 /****************
1404  * Select one user id or remove all selection if index is 0.
1405  * Returns: True if the selection changed;
1406  */
1407 static int
1408 menu_select_uid( KBNODE keyblock, int idx )
1409 {
1410     KBNODE node;
1411     int i;
1412
1413     /* first check that the index is valid */
1414     if( idx ) {
1415         for( i=0, node = keyblock; node; node = node->next ) {
1416             if( node->pkt->pkttype == PKT_USER_ID ) {
1417                 if( ++i == idx )
1418                     break;
1419             }
1420         }
1421         if( !node ) {
1422             tty_printf(_("No user id with index %d\n"), idx );
1423             return 0;
1424         }
1425     }
1426     else { /* reset all */
1427         for( i=0, node = keyblock; node; node = node->next ) {
1428             if( node->pkt->pkttype == PKT_USER_ID )
1429                 node->flag &= ~NODFLG_SELUID;
1430         }
1431         return 1;
1432     }
1433     /* and toggle the new index */
1434     for( i=0, node = keyblock; node; node = node->next ) {
1435         if( node->pkt->pkttype == PKT_USER_ID ) {
1436             if( ++i == idx ) {
1437                 if( (node->flag & NODFLG_SELUID) )
1438                     node->flag &= ~NODFLG_SELUID;
1439                 else
1440                     node->flag |= NODFLG_SELUID;
1441             }
1442         }
1443     }
1444
1445     return 1;
1446 }
1447
1448 /****************
1449  * Select secondary keys
1450  * Returns: True if the selection changed;
1451  */
1452 static int
1453 menu_select_key( KBNODE keyblock, int idx )
1454 {
1455     KBNODE node;
1456     int i;
1457
1458     /* first check that the index is valid */
1459     if( idx ) {
1460         for( i=0, node = keyblock; node; node = node->next ) {
1461             if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1462                 || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1463                 if( ++i == idx )
1464                     break;
1465             }
1466         }
1467         if( !node ) {
1468             tty_printf(_("No secondary key with index %d\n"), idx );
1469             return 0;
1470         }
1471     }
1472     else { /* reset all */
1473         for( i=0, node = keyblock; node; node = node->next ) {
1474             if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1475                 || node->pkt->pkttype == PKT_SECRET_SUBKEY )
1476                 node->flag &= ~NODFLG_SELKEY;
1477         }
1478         return 1;
1479     }
1480     /* and set the new index */
1481     for( i=0, node = keyblock; node; node = node->next ) {
1482         if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1483             || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1484             if( ++i == idx ) {
1485                 if( (node->flag & NODFLG_SELKEY) )
1486                     node->flag &= ~NODFLG_SELKEY;
1487                 else
1488                     node->flag |= NODFLG_SELKEY;
1489             }
1490         }
1491     }
1492
1493     return 1;
1494 }
1495
1496
1497 static int
1498 count_uids_with_flag( KBNODE keyblock, unsigned flag )
1499 {
1500     KBNODE node;
1501     int i=0;
1502
1503     for( node = keyblock; node; node = node->next )
1504         if( node->pkt->pkttype == PKT_USER_ID && (node->flag & flag) )
1505             i++;
1506     return i;
1507 }
1508
1509 static int
1510 count_keys_with_flag( KBNODE keyblock, unsigned flag )
1511 {
1512     KBNODE node;
1513     int i=0;
1514
1515     for( node = keyblock; node; node = node->next )
1516         if( ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1517               || node->pkt->pkttype == PKT_SECRET_SUBKEY)
1518             && (node->flag & flag) )
1519             i++;
1520     return i;
1521 }
1522
1523 static int
1524 count_uids( KBNODE keyblock )
1525 {
1526     KBNODE node;
1527     int i=0;
1528
1529     for( node = keyblock; node; node = node->next )
1530         if( node->pkt->pkttype == PKT_USER_ID )
1531             i++;
1532     return i;
1533 }
1534
1535
1536 /****************
1537  * Returns true if there is at least one selected user id
1538  */
1539 static int
1540 count_selected_uids( KBNODE keyblock )
1541 {
1542     return count_uids_with_flag( keyblock, NODFLG_SELUID);
1543 }
1544
1545 static int
1546 count_selected_keys( KBNODE keyblock )
1547 {
1548     return count_keys_with_flag( keyblock, NODFLG_SELKEY);
1549 }
1550
1551 /*
1552  * Ask whether the signature should be revoked.  If the user commits this,
1553  * flag bit MARK_A is set on the signature and the user ID.
1554  */
1555 static void
1556 ask_revoke_sig( KBNODE keyblock, KBNODE node )
1557 {
1558     PKT_signature *sig = node->pkt->pkt.signature;
1559     KBNODE unode = find_prev_kbnode( keyblock, node, PKT_USER_ID );
1560
1561     if( !unode ) {
1562         log_error("Oops: no user ID for signature\n");
1563         return;
1564     }
1565
1566     tty_printf(_("user ID: \""));
1567     tty_print_string( unode->pkt->pkt.user_id->name,
1568                       unode->pkt->pkt.user_id->len );
1569     tty_printf(_("\"\nsigned with your key %08lX at %s\n"),
1570                 sig->keyid[1], datestr_from_sig(sig) );
1571
1572     if( cpr_get_answer_is_yes("ask_revoke_sig.one",
1573          _("Create a revocation certificate for this signature? (y/N)")) ) {
1574         node->flag |= NODFLG_MARK_A;
1575         unode->flag |= NODFLG_MARK_A;
1576     }
1577 }
1578
1579 /****************
1580  * Display all user ids of the current public key together with signatures
1581  * done by one of our keys.  Then walk over all this sigs and ask the user
1582  * whether he wants to revoke this signature.
1583  * Return: True when the keyblock has changed.
1584  */
1585 static int
1586 menu_revsig( KBNODE keyblock )
1587 {
1588     PKT_signature *sig;
1589     PKT_public_key *primary_pk;
1590     KBNODE node;
1591     int changed = 0;
1592     int upd_trust = 0;
1593     int rc, any;
1594
1595     /* FIXME: detect duplicates here  */
1596     tty_printf("You have signed these user IDs:\n");
1597     for( node = keyblock; node; node = node->next ) {
1598         node->flag &= ~(NODFLG_SELSIG | NODFLG_MARK_A);
1599         if( node->pkt->pkttype == PKT_USER_ID ) {
1600             PKT_user_id *uid = node->pkt->pkt.user_id;
1601             /* Hmmm: Should we show only UIDs with a signature? */
1602             tty_printf("     ");
1603             tty_print_string( uid->name, uid->len );
1604             tty_printf("\n");
1605         }
1606         else if( node->pkt->pkttype == PKT_SIGNATURE
1607                 && ((sig = node->pkt->pkt.signature),
1608                      !seckey_available( sig->keyid )  ) ) {
1609             if( (sig->sig_class&~3) == 0x10 ) {
1610                 tty_printf("   signed by %08lX at %s\n",
1611                             sig->keyid[1], datestr_from_sig(sig) );
1612                 node->flag |= NODFLG_SELSIG;
1613             }
1614             else if( sig->sig_class == 0x30 ) {
1615                 tty_printf("   revoked by %08lX at %s\n",
1616                             sig->keyid[1], datestr_from_sig(sig) );
1617             }
1618         }
1619     }
1620
1621     /* ask */
1622     for( node = keyblock; node; node = node->next ) {
1623         if( !(node->flag & NODFLG_SELSIG) )
1624             continue;
1625         ask_revoke_sig( keyblock, node );
1626     }
1627
1628     /* present selected */
1629     any = 0;
1630     for( node = keyblock; node; node = node->next ) {
1631         if( !(node->flag & NODFLG_MARK_A) )
1632             continue;
1633         if( !any ) {
1634             any = 1;
1635             tty_printf("You are about to revoke these signatures:\n");
1636         }
1637         if( node->pkt->pkttype == PKT_USER_ID ) {
1638             PKT_user_id *uid = node->pkt->pkt.user_id;
1639             tty_printf("     ");
1640             tty_print_string( uid->name, uid->len );
1641             tty_printf("\n");
1642         }
1643         else if( node->pkt->pkttype == PKT_SIGNATURE ) {
1644             sig = node->pkt->pkt.signature;
1645             tty_printf("   signed by %08lX at %s\n",
1646                             sig->keyid[1], datestr_from_sig(sig) );
1647         }
1648     }
1649     if( !any )
1650         return 0; /* none selected */
1651
1652     if( !cpr_get_answer_is_yes("ask_revoke_sig.okay",
1653          _("Really create the revocation certificates? (y/N)")) )
1654         return 0; /* forget it */
1655
1656
1657     /* now we can sign the user ids */
1658   reloop: /* (must use this, because we are modifing the list) */
1659     primary_pk = keyblock->pkt->pkt.public_key;
1660     for( node=keyblock; node; node = node->next ) {
1661         KBNODE unode;
1662         PACKET *pkt;
1663         struct sign_uid_attrib attrib;
1664         PKT_secret_key *sk;
1665
1666         if( !(node->flag & NODFLG_MARK_A)
1667             || node->pkt->pkttype != PKT_SIGNATURE )
1668             continue;
1669         unode = find_prev_kbnode( keyblock, node, PKT_USER_ID );
1670         assert( unode ); /* we already checked this */
1671
1672         memset( &attrib, 0, sizeof attrib );
1673         node->flag &= ~NODFLG_MARK_A;
1674         sk = m_alloc_secure_clear( sizeof *sk );
1675         if( get_seckey( sk, node->pkt->pkt.signature->keyid ) ) {
1676             log_info(_("no secret key\n"));
1677             continue;
1678         }
1679         rc = make_keysig_packet( &sig, primary_pk,
1680                                        unode->pkt->pkt.user_id,
1681                                        NULL,
1682                                        sk,
1683                                        0x30, 0,
1684                                        sign_uid_mk_attrib,
1685                                        &attrib );
1686         free_secret_key(sk);
1687         if( rc ) {
1688             log_error(_("signing failed: %s\n"), g10_errstr(rc));
1689             return changed;
1690         }
1691         changed = 1; /* we changed the keyblock */
1692         upd_trust = 1;
1693
1694         pkt = m_alloc_clear( sizeof *pkt );
1695         pkt->pkttype = PKT_SIGNATURE;
1696         pkt->pkt.signature = sig;
1697         insert_kbnode( unode, new_kbnode(pkt), 0 );
1698         goto reloop;
1699     }
1700
1701     if( upd_trust )
1702         clear_trust_checked_flag( primary_pk );
1703
1704     return changed;
1705 }
1706
1707 /****************
1708  * Revoke some of the secondary keys.
1709  * Hmmm: Should we add a revocation to the secret keyring too?
1710  *       Does its all make sense to duplicate most of the information?
1711  */
1712 static int
1713 menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
1714 {
1715     PKT_public_key *mainpk;
1716     KBNODE node;
1717     int changed = 0;
1718     int upd_trust = 0;
1719     int rc;
1720
1721   reloop: /* (better this way because we are modifing the keyring) */
1722     mainpk = pub_keyblock->pkt->pkt.public_key;
1723     for( node = pub_keyblock; node; node = node->next ) {
1724         if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1725             && (node->flag & NODFLG_SELKEY) ) {
1726             PACKET *pkt;
1727             PKT_signature *sig;
1728             PKT_secret_key *sk;
1729             PKT_public_key *subpk = node->pkt->pkt.public_key;
1730
1731             node->flag &= ~NODFLG_SELKEY;
1732             sk = copy_secret_key( NULL, sec_keyblock->pkt->pkt.secret_key );
1733             rc = make_keysig_packet( &sig, mainpk, NULL, subpk, sk, 0x28, 0,
1734                                      NULL, NULL );
1735             free_secret_key(sk);
1736             if( rc ) {
1737                 log_error(_("signing failed: %s\n"), g10_errstr(rc));
1738                 return changed;
1739             }
1740             changed = 1; /* we changed the keyblock */
1741             upd_trust = 1;
1742
1743             pkt = m_alloc_clear( sizeof *pkt );
1744             pkt->pkttype = PKT_SIGNATURE;
1745             pkt->pkt.signature = sig;
1746             insert_kbnode( node, new_kbnode(pkt), 0 );
1747             goto reloop;
1748         }
1749     }
1750     commit_kbnode( &pub_keyblock );
1751     /*commit_kbnode( &sec_keyblock );*/
1752
1753     if( upd_trust )
1754         clear_trust_checked_flag( mainpk );
1755
1756     return changed;
1757 }
1758
1759