See ChangeLog: Thu May 6 14:18:17 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 fixed.
478  */
479 static int
480 fix_keyblock( KBNODE keyblock )
481 {
482     KBNODE node, last, subkey;
483     int fixed=0;
484
485     /* locate key signatures of class 0x10..0x13 behind sub key packets */
486     for( subkey=last=NULL, node = keyblock; node;
487                                             last=node, node = node->next ) {
488         switch( node->pkt->pkttype ) {
489           case PKT_PUBLIC_SUBKEY:
490           case PKT_SECRET_SUBKEY:
491             if( !subkey )
492                 subkey = last; /* actually it is the one before the subkey */
493             break;
494           case PKT_SIGNATURE:
495             if( subkey ) {
496                 PKT_signature *sig = node->pkt->pkt.signature;
497                 if( sig->sig_class >= 0x10 && sig->sig_class <= 0x13 ) {
498                     log_info(_(
499                         "moving a key signature to the correct place\n"));
500                     last->next = node->next;
501                     node->next = subkey->next;
502                     subkey->next = node;
503                     node = last;
504                     fixed=1;
505                 }
506             }
507             break;
508           default: break;
509         }
510     }
511
512     return fixed;
513 }
514
515 /****************
516  * Menu driven key editor
517  *
518  * Note: to keep track of some selection we use node->mark MARKBIT_xxxx.
519  */
520
521 void
522 keyedit_menu( const char *username, STRLIST locusr, STRLIST commands )
523 {
524     enum cmdids { cmdNONE = 0,
525            cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN,
526            cmdLSIGN, cmdREVSIG, cmdREVKEY,
527            cmdDEBUG, cmdSAVE, cmdADDUID, cmdDELUID, cmdADDKEY, cmdDELKEY,
528            cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE,
529            cmdNOP };
530     static struct { const char *name;
531                     enum cmdids id;
532                     int need_sk;
533                     const char *desc;
534                   } cmds[] = {
535         { N_("quit")    , cmdQUIT   , 0, N_("quit this menu") },
536         { N_("q")       , cmdQUIT   , 0, NULL   },
537         { N_("save")    , cmdSAVE   , 0, N_("save and quit") },
538         { N_("help")    , cmdHELP   , 0, N_("show this help") },
539         {    "?"        , cmdHELP   , 0, NULL   },
540         { N_("fpr")     , cmdFPR    , 0, N_("show fingerprint") },
541         { N_("list")    , cmdLIST   , 0, N_("list key and user ids") },
542         { N_("l")       , cmdLIST   , 0, NULL   },
543         { N_("uid")     , cmdSELUID , 0, N_("select user id N") },
544         { N_("key")     , cmdSELKEY , 0, N_("select secondary key N") },
545         { N_("check")   , cmdCHECK  , 0, N_("list signatures") },
546         { N_("c")       , cmdCHECK  , 0, NULL },
547         { N_("sign")    , cmdSIGN   , 0, N_("sign the key") },
548         { N_("s")       , cmdSIGN   , 0, NULL },
549         { N_("lsign")   , cmdLSIGN  , 0, N_("sign the key locally") },
550         { N_("debug")   , cmdDEBUG  , 0, NULL },
551         { N_("adduid")  , cmdADDUID , 1, N_("add a user id") },
552         { N_("deluid")  , cmdDELUID , 0, N_("delete user id") },
553         { N_("addkey")  , cmdADDKEY , 1, N_("add a secondary key") },
554         { N_("delkey")  , cmdDELKEY , 0, N_("delete a secondary key") },
555         { N_("expire")  , cmdEXPIRE , 1, N_("change the expire date") },
556         { N_("toggle")  , cmdTOGGLE , 1, N_("toggle between secret "
557                                             "and public key listing") },
558         { N_("t"     )  , cmdTOGGLE , 1, NULL },
559         { N_("pref")    , cmdPREF  , 0, N_("list preferences") },
560         { N_("passwd")  , cmdPASSWD , 1, N_("change the passphrase") },
561         { N_("trust")   , cmdTRUST , 0, N_("change the ownertrust") },
562         { N_("revsig")  , cmdREVSIG , 0, N_("revoke signatures") },
563         { N_("revkey")  , cmdREVKEY , 1, N_("revoke a secondary key") },
564
565     { NULL, cmdNONE } };
566     enum cmdids cmd;
567     int rc = 0;
568     KBNODE keyblock = NULL;
569     KBPOS keyblockpos;
570     KBNODE sec_keyblock = NULL;
571     KBPOS sec_keyblockpos;
572     KBNODE cur_keyblock;
573     char *answer = NULL;
574     int redisplay = 1;
575     int modified = 0;
576     int sec_modified = 0;
577     int toggle;
578     int have_commands = !!commands;
579
580
581     if( opt.batch && !have_commands ) {
582         log_error(_("can't do that in batchmode\n"));
583         goto leave;
584     }
585
586     /* first try to locate it as secret key */
587     rc = find_secret_keyblock_byname( &sec_keyblockpos, username );
588     if( !rc ) {
589         rc = read_keyblock( &sec_keyblockpos, &sec_keyblock );
590         if( rc ) {
591             log_error("%s: secret keyblock read problem: %s\n",
592                                             username, g10_errstr(rc));
593             goto leave;
594         }
595         merge_keys_and_selfsig( sec_keyblock );
596         if( fix_keyblock( sec_keyblock ) )
597             sec_modified++;
598     }
599
600     /* and now get the public key */
601     rc = get_keyblock_byname( &keyblock, &keyblockpos, username );
602     if( rc )
603         goto leave;
604     if( fix_keyblock( keyblock ) )
605         modified++;
606
607     if( sec_keyblock ) { /* check that they match */
608         /* FIXME: check that they both match */
609         tty_printf(_("Secret key is available.\n"));
610     }
611
612     toggle = 0;
613     cur_keyblock = keyblock;
614     for(;;) { /* main loop */
615         int i, arg_number;
616         char *p;
617
618         tty_printf("\n");
619         if( redisplay ) {
620             show_key_with_all_names( cur_keyblock, 0, 0, 1, 0 );
621             tty_printf("\n");
622             redisplay = 0;
623         }
624         do {
625             m_free(answer);
626             if( have_commands ) {
627                 if( commands ) {
628                     answer = m_strdup( commands->d );
629                     commands = commands->next;
630                 }
631                 else if( opt.batch ) {
632                     answer = m_strdup("quit");
633                 }
634                 else
635                     have_commands = 0;
636             }
637             if( !have_commands ) {
638                 answer = cpr_get("keyedit.cmd", _("Command> "));
639                 cpr_kill_prompt();
640             }
641             trim_spaces(answer);
642         } while( *answer == '#' );
643
644         arg_number = 0;
645         if( !*answer )
646             cmd = cmdLIST;
647         else if( *answer == CONTROL_D )
648             cmd = cmdQUIT;
649         else if( isdigit( *answer ) ) {
650             cmd = cmdSELUID;
651             arg_number = atoi(answer);
652         }
653         else {
654             if( (p=strchr(answer,' ')) ) {
655                 *p++ = 0;
656                 trim_spaces(answer);
657                 trim_spaces(p);
658                 arg_number = atoi(p);
659             }
660
661             for(i=0; cmds[i].name; i++ )
662                 if( !stricmp( answer, cmds[i].name ) )
663                     break;
664             if( cmds[i].need_sk && !sec_keyblock ) {
665                 tty_printf(_("Need the secret key to do this.\n"));
666                 cmd = cmdNOP;
667             }
668             else
669                 cmd = cmds[i].id;
670         }
671         switch( cmd )  {
672           case cmdHELP:
673             for(i=0; cmds[i].name; i++ ) {
674                 if( cmds[i].need_sk && !sec_keyblock )
675                     ; /* skip if we do not have the secret key */
676                 else if( cmds[i].desc )
677                     tty_printf("%-10s %s\n", cmds[i].name, _(cmds[i].desc) );
678             }
679             break;
680
681           case cmdQUIT:
682             if( have_commands )
683                 goto leave;
684             if( !modified && !sec_modified )
685                 goto leave;
686             if( !cpr_get_answer_is_yes("keyedit.save.okay",
687                                         _("Save changes? ")) ) {
688                 if( cpr_enabled()
689                     || cpr_get_answer_is_yes("keyedit.cancel.okay",
690                                              _("Quit without saving? ")) )
691                     goto leave;
692                 break;
693             }
694             /* fall thru */
695           case cmdSAVE:
696             if( modified || sec_modified  ) {
697                 if( modified ) {
698                     rc = update_keyblock( &keyblockpos, keyblock );
699                     if( rc ) {
700                         log_error(_("update failed: %s\n"), g10_errstr(rc) );
701                         break;
702                     }
703                 }
704                 if( sec_modified ) {
705                     rc = update_keyblock( &sec_keyblockpos, sec_keyblock );
706                     if( rc ) {
707                         log_error(_("update secret failed: %s\n"),
708                                                             g10_errstr(rc) );
709                         break;
710                     }
711                 }
712             }
713             else
714                 tty_printf(_("Key not changed so no update needed.\n"));
715             rc = update_trust_record( keyblock, 0, NULL );
716             if( rc )
717                 log_error(_("update of trustdb failed: %s\n"),
718                             g10_errstr(rc) );
719             goto leave;
720
721           case cmdLIST:
722             redisplay = 1;
723             break;
724
725           case cmdFPR:
726             show_key_and_fingerprint( keyblock );
727             break;
728
729           case cmdSELUID:
730             if( menu_select_uid( cur_keyblock, arg_number ) )
731                 redisplay = 1;
732             break;
733
734           case cmdSELKEY:
735             if( menu_select_key( cur_keyblock, arg_number ) )
736                 redisplay = 1;
737             break;
738
739           case cmdCHECK:
740             /* we can only do this with the public key becuase the
741              * check functions can't cope with secret keys and it
742              * is questionable whether this would make sense at all */
743             check_all_keysigs( keyblock, count_selected_uids(keyblock) );
744             break;
745
746           case cmdSIGN: /* sign (only the public key) */
747           case cmdLSIGN: /* sign (only the public key) */
748             if( count_uids(keyblock) > 1 && !count_selected_uids(keyblock) ) {
749                 if( !cpr_get_answer_is_yes("keyedit.sign_all.okay",
750                                            _("Really sign all user ids? ")) ) {
751                     tty_printf(_("Hint: Select the user ids to sign\n"));
752                     break;
753                 }
754             }
755             sign_uids( keyblock, locusr, &modified, cmd == cmdLSIGN );
756             break;
757
758           case cmdDEBUG:
759             dump_kbnode( cur_keyblock );
760             break;
761
762           case cmdTOGGLE:
763             toggle = !toggle;
764             cur_keyblock = toggle? sec_keyblock : keyblock;
765             redisplay = 1;
766             break;
767
768           case cmdADDUID:
769             if( menu_adduid( keyblock, sec_keyblock ) ) {
770                 redisplay = 1;
771                 sec_modified = modified = 1;
772                 /* must update the trustdb already here, so that preferences
773                  * get listed correctly */
774                 rc = update_trust_record( keyblock, 0, NULL );
775                 if( rc ) {
776                     log_error(_("update of trustdb failed: %s\n"),
777                                 g10_errstr(rc) );
778                     rc = 0;
779                 }
780             }
781             break;
782
783           case cmdDELUID: {
784                 int n1;
785
786                 if( !(n1=count_selected_uids(keyblock)) )
787                     tty_printf(_("You must select at least one user id.\n"));
788                 else if( count_uids(keyblock) - n1 < 1 )
789                     tty_printf(_("You can't delete the last user id!\n"));
790                 else if( cpr_get_answer_is_yes(
791                             "keyedit.remove.uid.okay",
792                         n1 > 1? _("Really remove all selected user ids? ")
793                               : _("Really remove this user id? ")
794                        ) ) {
795                     menu_deluid( keyblock, sec_keyblock );
796                     redisplay = 1;
797                     modified = 1;
798                     if( sec_keyblock )
799                        sec_modified = 1;
800                 }
801             }
802             break;
803
804           case cmdADDKEY:
805             if( generate_subkeypair( keyblock, sec_keyblock ) ) {
806                 redisplay = 1;
807                 sec_modified = modified = 1;
808             }
809             break;
810
811
812           case cmdDELKEY: {
813                 int n1;
814
815                 if( !(n1=count_selected_keys( keyblock )) )
816                     tty_printf(_("You must select at least one key.\n"));
817                 else if( sec_keyblock && !cpr_get_answer_is_yes(
818                             "keyedit.remove.subkey.okay",
819                        n1 > 1?
820                         _("Do you really want to delete the selected keys? "):
821                         _("Do you really want to delete this key? ")
822                        ))
823                     ;
824                 else {
825                     menu_delkey( keyblock, sec_keyblock );
826                     redisplay = 1;
827                     modified = 1;
828                     if( sec_keyblock )
829                        sec_modified = 1;
830                 }
831             }
832             break;
833
834           case cmdREVKEY: {
835                 int n1;
836
837                 if( !(n1=count_selected_keys( keyblock )) )
838                     tty_printf(_("You must select at least one key.\n"));
839                 else if( sec_keyblock && !cpr_get_answer_is_yes(
840                             "keyedit.revoke.subkey.okay",
841                        n1 > 1?
842                         _("Do you really want to revoke the selected keys? "):
843                         _("Do you really want to revoke this key? ")
844                        ))
845                     ;
846                 else {
847                     if( menu_revkey( keyblock, sec_keyblock ) ) {
848                         modified = 1;
849                         /*sec_modified = 1;*/
850                     }
851                     redisplay = 1;
852                 }
853             }
854             break;
855
856           case cmdEXPIRE:
857             if( menu_expire( keyblock, sec_keyblock ) ) {
858                 merge_keys_and_selfsig( sec_keyblock );
859                 merge_keys_and_selfsig( keyblock );
860                 sec_modified = 1;
861                 modified = 1;
862                 redisplay = 1;
863             }
864             break;
865
866           case cmdPASSWD:
867             if( change_passphrase( sec_keyblock ) )
868                 sec_modified = 1;
869             break;
870
871           case cmdTRUST:
872             show_key_with_all_names( keyblock, 0, 0, 1, 0 );
873             tty_printf("\n");
874             if( edit_ownertrust( find_kbnode( keyblock,
875                       PKT_PUBLIC_KEY )->pkt->pkt.public_key->local_id, 1 ) )
876                 redisplay = 1;
877             /* we don't need to set modified here, as the trustvalues
878              * are updated immediately */
879             break;
880
881           case cmdPREF:
882             show_key_with_all_names( keyblock, 0, 0, 0, 1 );
883             break;
884
885           case cmdNOP:
886             break;
887
888           case cmdREVSIG:
889             if( menu_revsig( keyblock ) ) {
890                 redisplay = 1;
891                 modified = 1;
892             }
893             break;
894
895           default:
896             tty_printf("\n");
897             tty_printf(_("Invalid command  (try \"help\")\n"));
898             break;
899         }
900     } /* end main loop */
901
902   leave:
903     release_kbnode( keyblock );
904     release_kbnode( sec_keyblock );
905     m_free(answer);
906 }
907
908
909 /****************
910  * show preferences of a public keyblock.
911  */
912 static void
913 show_prefs( KBNODE keyblock, PKT_user_id *uid )
914 {
915     KBNODE node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
916     PKT_public_key *pk;
917     byte *p;
918     int i;
919     size_t n;
920     byte namehash[20];
921
922     if( !node )
923         return; /* is a secret keyblock */
924     pk = node->pkt->pkt.public_key;
925     if( !pk->local_id ) {
926         log_error("oops: no LID\n");
927         return;
928     }
929
930     rmd160_hash_buffer( namehash, uid->name, uid->len );
931
932     p = get_pref_data( pk->local_id, namehash, &n );
933     if( !p )
934         return;
935
936     tty_printf("    ");
937     for(i=0; i < n; i+=2 ) {
938         if( p[i] )
939             tty_printf( " %c%d", p[i] == PREFTYPE_SYM    ? 'S' :
940                                  p[i] == PREFTYPE_HASH   ? 'H' :
941                                  p[i] == PREFTYPE_COMPR  ? 'Z' : '?', p[i+1]);
942     }
943     tty_printf("\n");
944
945     m_free(p);
946 }
947
948
949 /****************
950  * Display the key a the user ids, if only_marked is true, do only
951  * so for user ids with mark A flag set and dont display the index number
952  */
953 static void
954 show_key_with_all_names( KBNODE keyblock, int only_marked,
955                          int with_fpr, int with_subkeys, int with_prefs )
956 {
957     KBNODE node;
958     int i, rc;
959
960     /* the keys */
961     for( node = keyblock; node; node = node->next ) {
962         if( node->pkt->pkttype == PKT_PUBLIC_KEY
963             || (with_subkeys && node->pkt->pkttype == PKT_PUBLIC_SUBKEY) ) {
964             PKT_public_key *pk = node->pkt->pkt.public_key;
965             int otrust=0, trust=0;
966
967             if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
968                 /* do it here, so that debug messages don't clutter the
969                  * output */
970                 trust = query_trust_info(pk, NULL);
971                 otrust = get_ownertrust_info( pk->local_id );
972             }
973
974             tty_printf("%s%c %4u%c/%08lX  created: %s expires: %s",
975                           node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub",
976                           (node->flag & NODFLG_SELKEY)? '*':' ',
977                           nbits_from_pk( pk ),
978                           pubkey_letter( pk->pubkey_algo ),
979                           (ulong)keyid_from_pk(pk,NULL),
980                           datestr_from_pk(pk),
981                           expirestr_from_pk(pk) );
982             if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
983                 tty_printf(" trust: %c/%c", otrust, trust );
984                 if( with_fpr  ) {
985                     tty_printf("\n");
986                     show_fingerprint( pk );
987                 }
988             }
989             tty_printf("\n");
990         }
991         else if( node->pkt->pkttype == PKT_SECRET_KEY
992             || (with_subkeys && node->pkt->pkttype == PKT_SECRET_SUBKEY) ) {
993             PKT_secret_key *sk = node->pkt->pkt.secret_key;
994             tty_printf("%s%c %4u%c/%08lX  created: %s expires: %s\n",
995                           node->pkt->pkttype == PKT_SECRET_KEY? "sec":"sbb",
996                           (node->flag & NODFLG_SELKEY)? '*':' ',
997                           nbits_from_sk( sk ),
998                           pubkey_letter( sk->pubkey_algo ),
999                           (ulong)keyid_from_sk(sk,NULL),
1000                           datestr_from_sk(sk),
1001                           expirestr_from_sk(sk) );
1002         }
1003         else if( with_subkeys && node->pkt->pkttype == PKT_SIGNATURE
1004                  && node->pkt->pkt.signature->sig_class == 0x28       ) {
1005             PKT_signature *sig = node->pkt->pkt.signature;
1006
1007             rc = check_key_signature( keyblock, node, NULL );
1008             if( !rc )
1009                 tty_printf( "rev! subkey has been revoked: %s\n",
1010                             datestr_from_sig( sig ) );
1011             else if( rc == G10ERR_BAD_SIGN )
1012                 tty_printf( "rev- faked revocation found\n" );
1013             else if( rc )
1014                 tty_printf( "rev? problem checking revocation: %s\n",
1015                                                          g10_errstr(rc) );
1016         }
1017     }
1018     /* the user ids */
1019     i = 0;
1020     for( node = keyblock; node; node = node->next ) {
1021         if( node->pkt->pkttype == PKT_USER_ID ) {
1022             PKT_user_id *uid = node->pkt->pkt.user_id;
1023             ++i;
1024             if( !only_marked || (only_marked && (node->flag & NODFLG_MARK_A))){
1025                 if( only_marked )
1026                    tty_printf("     ");
1027                 else if( node->flag & NODFLG_SELUID )
1028                    tty_printf("(%d)* ", i);
1029                 else
1030                    tty_printf("(%d)  ", i);
1031                 tty_print_string( uid->name, uid->len );
1032                 tty_printf("\n");
1033                 if( with_prefs )
1034                     show_prefs( keyblock, uid );
1035             }
1036         }
1037     }
1038 }
1039
1040 static void
1041 show_key_and_fingerprint( KBNODE keyblock )
1042 {
1043     KBNODE node;
1044     PKT_public_key *pk = NULL;
1045
1046     for( node = keyblock; node; node = node->next ) {
1047         if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
1048             pk = node->pkt->pkt.public_key;
1049             tty_printf("pub  %4u%c/%08lX %s ",
1050                           nbits_from_pk( pk ),
1051                           pubkey_letter( pk->pubkey_algo ),
1052                           (ulong)keyid_from_pk(pk,NULL),
1053                           datestr_from_pk(pk) );
1054         }
1055         else if( node->pkt->pkttype == PKT_USER_ID ) {
1056             PKT_user_id *uid = node->pkt->pkt.user_id;
1057             tty_print_string( uid->name, uid->len );
1058             break;
1059         }
1060     }
1061     tty_printf("\n");
1062     if( pk )
1063         show_fingerprint( pk );
1064 }
1065
1066
1067 static void
1068 show_fingerprint( PKT_public_key *pk )
1069 {
1070     byte array[MAX_FINGERPRINT_LEN], *p;
1071     size_t i, n;
1072
1073     fingerprint_from_pk( pk, array, &n );
1074     p = array;
1075     tty_printf("             Fingerprint:");
1076     if( n == 20 ) {
1077         for(i=0; i < n ; i++, i++, p += 2 ) {
1078             if( i == 10 )
1079                 tty_printf(" ");
1080             tty_printf(" %02X%02X", *p, p[1] );
1081         }
1082     }
1083     else {
1084         for(i=0; i < n ; i++, p++ ) {
1085             if( i && !(i%8) )
1086                 tty_printf(" ");
1087             tty_printf(" %02X", *p );
1088         }
1089     }
1090     tty_printf("\n");
1091 }
1092
1093
1094 /****************
1095  * Ask for a new user id , do the selfsignature and put it into
1096  * both keyblocks.
1097  * Return true if there is a new user id
1098  */
1099 static int
1100 menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock )
1101 {
1102     PKT_user_id *uid;
1103     PKT_public_key *pk=NULL;
1104     PKT_secret_key *sk=NULL;
1105     PKT_signature *sig=NULL;
1106     PACKET *pkt;
1107     KBNODE node;
1108     KBNODE pub_where=NULL, sec_where=NULL;
1109     int rc;
1110
1111     uid = generate_user_id();
1112     if( !uid )
1113         return 0;
1114
1115     for( node = pub_keyblock; node; pub_where = node, node = node->next ) {
1116         if( node->pkt->pkttype == PKT_PUBLIC_KEY )
1117             pk = node->pkt->pkt.public_key;
1118         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
1119             break;
1120     }
1121     if( !node ) /* no subkey */
1122         pub_where = NULL;
1123     for( node = sec_keyblock; node; sec_where = node, node = node->next ) {
1124         if( node->pkt->pkttype == PKT_SECRET_KEY )
1125             sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
1126         else if( node->pkt->pkttype == PKT_SECRET_SUBKEY )
1127             break;
1128     }
1129     if( !node ) /* no subkey */
1130         sec_where = NULL;
1131     assert(pk && sk );
1132
1133     rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0,
1134                              keygen_add_std_prefs, pk );
1135     free_secret_key( sk );
1136     if( rc ) {
1137         log_error("signing failed: %s\n", g10_errstr(rc) );
1138         free_user_id(uid);
1139         return 0;
1140     }
1141
1142     /* insert/append to secret keyblock */
1143     pkt = m_alloc_clear( sizeof *pkt );
1144     pkt->pkttype = PKT_USER_ID;
1145     pkt->pkt.user_id = copy_user_id(NULL, uid);
1146     node = new_kbnode(pkt);
1147     if( sec_where )
1148         insert_kbnode( sec_where, node, 0 );
1149     else
1150         add_kbnode( sec_keyblock, node );
1151     pkt = m_alloc_clear( sizeof *pkt );
1152     pkt->pkttype = PKT_SIGNATURE;
1153     pkt->pkt.signature = copy_signature(NULL, sig);
1154     if( sec_where )
1155         insert_kbnode( node, new_kbnode(pkt), 0 );
1156     else
1157         add_kbnode( sec_keyblock, new_kbnode(pkt) );
1158     /* insert/append to public keyblock */
1159     pkt = m_alloc_clear( sizeof *pkt );
1160     pkt->pkttype = PKT_USER_ID;
1161     pkt->pkt.user_id = uid;
1162     node = new_kbnode(pkt);
1163     if( pub_where )
1164         insert_kbnode( pub_where, node, 0 );
1165     else
1166         add_kbnode( pub_keyblock, node );
1167     pkt = m_alloc_clear( sizeof *pkt );
1168     pkt->pkttype = PKT_SIGNATURE;
1169     pkt->pkt.signature = copy_signature(NULL, sig);
1170     if( pub_where )
1171         insert_kbnode( node, new_kbnode(pkt), 0 );
1172     else
1173         add_kbnode( pub_keyblock, new_kbnode(pkt) );
1174     return 1;
1175 }
1176
1177
1178 /****************
1179  * Remove all selceted userids from the keyrings
1180  */
1181 static void
1182 menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock )
1183 {
1184     KBNODE node;
1185     int selected=0;
1186
1187     for( node = pub_keyblock; node; node = node->next ) {
1188         if( node->pkt->pkttype == PKT_USER_ID ) {
1189             selected = node->flag & NODFLG_SELUID;
1190             if( selected ) {
1191                 delete_kbnode( node );
1192                 if( sec_keyblock ) {
1193                     KBNODE snode;
1194                     int s_selected = 0;
1195                     PKT_user_id *uid = node->pkt->pkt.user_id;
1196                     for( snode = sec_keyblock; snode; snode = snode->next ) {
1197                         if( snode->pkt->pkttype == PKT_USER_ID ) {
1198                             PKT_user_id *suid = snode->pkt->pkt.user_id;
1199
1200                             s_selected =
1201                                 (uid->len == suid->len
1202                                  && !memcmp( uid->name, suid->name, uid->len));
1203                             if( s_selected )
1204                                 delete_kbnode( snode );
1205                         }
1206                         else if( s_selected
1207                                  && snode->pkt->pkttype == PKT_SIGNATURE )
1208                             delete_kbnode( snode );
1209                         else if( snode->pkt->pkttype == PKT_SECRET_SUBKEY )
1210                             s_selected = 0;
1211                     }
1212                 }
1213             }
1214         }
1215         else if( selected && node->pkt->pkttype == PKT_SIGNATURE )
1216             delete_kbnode( node );
1217         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
1218             selected = 0;
1219     }
1220     commit_kbnode( &pub_keyblock );
1221     if( sec_keyblock )
1222         commit_kbnode( &sec_keyblock );
1223 }
1224
1225
1226 /****************
1227  * Remove some of the secondary keys
1228  */
1229 static void
1230 menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
1231 {
1232     KBNODE node;
1233     int selected=0;
1234
1235     for( node = pub_keyblock; node; node = node->next ) {
1236         if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
1237             selected = node->flag & NODFLG_SELKEY;
1238             if( selected ) {
1239                 delete_kbnode( node );
1240                 if( sec_keyblock ) {
1241                     KBNODE snode;
1242                     int s_selected = 0;
1243                     u32 ki[2];
1244
1245                     keyid_from_pk( node->pkt->pkt.public_key, ki );
1246                     for( snode = sec_keyblock; snode; snode = snode->next ) {
1247                         if( snode->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1248                             u32 ki2[2];
1249
1250                             keyid_from_sk( snode->pkt->pkt.secret_key, ki2 );
1251                             s_selected = (ki[0] == ki2[0] && ki[1] == ki2[1]);
1252                             if( s_selected )
1253                                 delete_kbnode( snode );
1254                         }
1255                         else if( s_selected
1256                                  && snode->pkt->pkttype == PKT_SIGNATURE )
1257                             delete_kbnode( snode );
1258                         else
1259                             s_selected = 0;
1260                     }
1261                 }
1262             }
1263         }
1264         else if( selected && node->pkt->pkttype == PKT_SIGNATURE )
1265             delete_kbnode( node );
1266         else
1267             selected = 0;
1268     }
1269     commit_kbnode( &pub_keyblock );
1270     if( sec_keyblock )
1271         commit_kbnode( &sec_keyblock );
1272 }
1273
1274
1275
1276 static int
1277 menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
1278 {
1279     int n1, signumber, rc;
1280     u32 expiredate;
1281     int mainkey=0;
1282     PKT_secret_key *sk;    /* copy of the main sk */
1283     PKT_public_key *main_pk, *sub_pk;
1284     PKT_user_id *uid;
1285     KBNODE node;
1286     u32 keyid[2];
1287
1288     if( count_selected_keys( sec_keyblock ) ) {
1289         tty_printf(_("Please remove selections from the secret keys.\n"));
1290         return 0;
1291     }
1292
1293     n1 = count_selected_keys( pub_keyblock );
1294     if( n1 > 1 ) {
1295         tty_printf(_("Please select at most one secondary key.\n"));
1296         return 0;
1297     }
1298     else if( n1 )
1299         tty_printf(_("Changing exiration time for a secondary key.\n"));
1300     else {
1301         tty_printf(_("Changing exiration time for the primary key.\n"));
1302         mainkey=1;
1303     }
1304
1305     expiredate = ask_expiredate();
1306     node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
1307     sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
1308
1309     /* Now we can actually change the self signature(s) */
1310     main_pk = sub_pk = NULL;
1311     uid = NULL;
1312     signumber = 0;
1313     for( node=pub_keyblock; node; node = node->next ) {
1314         if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
1315             main_pk = node->pkt->pkt.public_key;
1316             keyid_from_pk( main_pk, keyid );
1317             main_pk->expiredate = expiredate;
1318         }
1319         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1320                  && (node->flag & NODFLG_SELKEY ) ) {
1321             sub_pk = node->pkt->pkt.public_key;
1322             sub_pk->expiredate = expiredate;
1323         }
1324         else if( node->pkt->pkttype == PKT_USER_ID )
1325             uid = node->pkt->pkt.user_id;
1326         else if( main_pk && node->pkt->pkttype == PKT_SIGNATURE ) {
1327             PKT_signature *sig = node->pkt->pkt.signature;
1328             if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
1329                 && (    (mainkey && uid && (sig->sig_class&~3) == 0x10)
1330                      || (!mainkey && sig->sig_class == 0x18)  ) ) {
1331                 /* this is a selfsignature which is to be replaced */
1332                 PKT_signature *newsig;
1333                 PACKET *newpkt;
1334                 KBNODE sn;
1335                 int signumber2 = 0;
1336
1337                 signumber++;
1338
1339                 if( (mainkey && main_pk->version < 4)
1340                     || (!mainkey && sub_pk->version < 4 ) ) {
1341                     log_info(_(
1342                         "You can't change the expiration date of a v3 key\n"));
1343                     free_secret_key( sk );
1344                     return 0;
1345                 }
1346
1347                 /* find the corresponding secret self-signature */
1348                 for( sn=sec_keyblock; sn; sn = sn->next ) {
1349                     if( sn->pkt->pkttype == PKT_SIGNATURE ) {
1350                         PKT_signature *b = sn->pkt->pkt.signature;
1351                         if( keyid[0] == b->keyid[0] && keyid[1] == b->keyid[1]
1352                             && sig->sig_class == b->sig_class
1353                             && ++signumber2 == signumber )
1354                             break;
1355                     }
1356                 }
1357                 if( !sn )
1358                     log_info(_("No corresponding signature in secret ring\n"));
1359
1360                 /* create new self signature */
1361                 if( mainkey )
1362                     rc = make_keysig_packet( &newsig, main_pk, uid, NULL,
1363                                              sk, 0x13, 0,
1364                                              keygen_add_std_prefs, main_pk );
1365                 else
1366                     rc = make_keysig_packet( &newsig, main_pk, NULL, sub_pk,
1367                                              sk, 0x18, 0,
1368                                              keygen_add_key_expire, sub_pk );
1369                 if( rc ) {
1370                     log_error("make_keysig_packet failed: %s\n",
1371                                                     g10_errstr(rc));
1372                     free_secret_key( sk );
1373                     return 0;
1374                 }
1375                 /* replace the packet */
1376                 newpkt = m_alloc_clear( sizeof *newpkt );
1377                 newpkt->pkttype = PKT_SIGNATURE;
1378                 newpkt->pkt.signature = newsig;
1379                 free_packet( node->pkt );
1380                 m_free( node->pkt );
1381                 node->pkt = newpkt;
1382                 if( sn ) {
1383                     newpkt = m_alloc_clear( sizeof *newpkt );
1384                     newpkt->pkttype = PKT_SIGNATURE;
1385                     newpkt->pkt.signature = copy_signature( NULL, newsig );
1386                     free_packet( sn->pkt );
1387                     m_free( sn->pkt );
1388                     sn->pkt = newpkt;
1389                 }
1390             }
1391         }
1392     }
1393
1394     free_secret_key( sk );
1395     return 1;
1396 }
1397
1398
1399 /****************
1400  * Select one user id or remove all selection if index is 0.
1401  * Returns: True if the selection changed;
1402  */
1403 static int
1404 menu_select_uid( KBNODE keyblock, int idx )
1405 {
1406     KBNODE node;
1407     int i;
1408
1409     /* first check that the index is valid */
1410     if( idx ) {
1411         for( i=0, node = keyblock; node; node = node->next ) {
1412             if( node->pkt->pkttype == PKT_USER_ID ) {
1413                 if( ++i == idx )
1414                     break;
1415             }
1416         }
1417         if( !node ) {
1418             tty_printf(_("No user id with index %d\n"), idx );
1419             return 0;
1420         }
1421     }
1422     else { /* reset all */
1423         for( i=0, node = keyblock; node; node = node->next ) {
1424             if( node->pkt->pkttype == PKT_USER_ID )
1425                 node->flag &= ~NODFLG_SELUID;
1426         }
1427         return 1;
1428     }
1429     /* and toggle the new index */
1430     for( i=0, node = keyblock; node; node = node->next ) {
1431         if( node->pkt->pkttype == PKT_USER_ID ) {
1432             if( ++i == idx ) {
1433                 if( (node->flag & NODFLG_SELUID) )
1434                     node->flag &= ~NODFLG_SELUID;
1435                 else
1436                     node->flag |= NODFLG_SELUID;
1437             }
1438         }
1439     }
1440
1441     return 1;
1442 }
1443
1444 /****************
1445  * Select secondary keys
1446  * Returns: True if the selection changed;
1447  */
1448 static int
1449 menu_select_key( KBNODE keyblock, int idx )
1450 {
1451     KBNODE node;
1452     int i;
1453
1454     /* first check that the index is valid */
1455     if( idx ) {
1456         for( i=0, node = keyblock; node; node = node->next ) {
1457             if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1458                 || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1459                 if( ++i == idx )
1460                     break;
1461             }
1462         }
1463         if( !node ) {
1464             tty_printf(_("No secondary key with index %d\n"), idx );
1465             return 0;
1466         }
1467     }
1468     else { /* reset all */
1469         for( i=0, node = keyblock; node; node = node->next ) {
1470             if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1471                 || node->pkt->pkttype == PKT_SECRET_SUBKEY )
1472                 node->flag &= ~NODFLG_SELKEY;
1473         }
1474         return 1;
1475     }
1476     /* and set the new index */
1477     for( i=0, node = keyblock; node; node = node->next ) {
1478         if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1479             || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1480             if( ++i == idx ) {
1481                 if( (node->flag & NODFLG_SELKEY) )
1482                     node->flag &= ~NODFLG_SELKEY;
1483                 else
1484                     node->flag |= NODFLG_SELKEY;
1485             }
1486         }
1487     }
1488
1489     return 1;
1490 }
1491
1492
1493 static int
1494 count_uids_with_flag( KBNODE keyblock, unsigned flag )
1495 {
1496     KBNODE node;
1497     int i=0;
1498
1499     for( node = keyblock; node; node = node->next )
1500         if( node->pkt->pkttype == PKT_USER_ID && (node->flag & flag) )
1501             i++;
1502     return i;
1503 }
1504
1505 static int
1506 count_keys_with_flag( KBNODE keyblock, unsigned flag )
1507 {
1508     KBNODE node;
1509     int i=0;
1510
1511     for( node = keyblock; node; node = node->next )
1512         if( ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1513               || node->pkt->pkttype == PKT_SECRET_SUBKEY)
1514             && (node->flag & flag) )
1515             i++;
1516     return i;
1517 }
1518
1519 static int
1520 count_uids( KBNODE keyblock )
1521 {
1522     KBNODE node;
1523     int i=0;
1524
1525     for( node = keyblock; node; node = node->next )
1526         if( node->pkt->pkttype == PKT_USER_ID )
1527             i++;
1528     return i;
1529 }
1530
1531
1532 /****************
1533  * Returns true if there is at least one selected user id
1534  */
1535 static int
1536 count_selected_uids( KBNODE keyblock )
1537 {
1538     return count_uids_with_flag( keyblock, NODFLG_SELUID);
1539 }
1540
1541 static int
1542 count_selected_keys( KBNODE keyblock )
1543 {
1544     return count_keys_with_flag( keyblock, NODFLG_SELKEY);
1545 }
1546
1547 /*
1548  * Ask whether the signature should be revoked.  If the user commits this,
1549  * flag bit MARK_A is set on the signature and the user ID.
1550  */
1551 static void
1552 ask_revoke_sig( KBNODE keyblock, KBNODE node )
1553 {
1554     PKT_signature *sig = node->pkt->pkt.signature;
1555     KBNODE unode = find_prev_kbnode( keyblock, node, PKT_USER_ID );
1556
1557     if( !unode ) {
1558         log_error("Oops: no user ID for signature\n");
1559         return;
1560     }
1561
1562     tty_printf(_("user ID: \""));
1563     tty_print_string( unode->pkt->pkt.user_id->name,
1564                       unode->pkt->pkt.user_id->len );
1565     tty_printf(_("\"\nsigned with your key %08lX at %s\n"),
1566                 sig->keyid[1], datestr_from_sig(sig) );
1567
1568     if( cpr_get_answer_is_yes("ask_revoke_sig.one",
1569          _("Create a revocation certificate for this signature? (y/N)")) ) {
1570         node->flag |= NODFLG_MARK_A;
1571         unode->flag |= NODFLG_MARK_A;
1572     }
1573 }
1574
1575 /****************
1576  * Display all user ids of the current public key together with signatures
1577  * done by one of our keys.  Then walk over all this sigs and ask the user
1578  * whether he wants to revoke this signature.
1579  * Return: True when the keyblock has changed.
1580  */
1581 static int
1582 menu_revsig( KBNODE keyblock )
1583 {
1584     PKT_signature *sig;
1585     PKT_public_key *primary_pk;
1586     KBNODE node;
1587     int changed = 0;
1588     int upd_trust = 0;
1589     int rc, any;
1590
1591     /* FIXME: detect duplicates here  */
1592     tty_printf("You have signed these user IDs:\n");
1593     for( node = keyblock; node; node = node->next ) {
1594         node->flag &= ~(NODFLG_SELSIG | NODFLG_MARK_A);
1595         if( node->pkt->pkttype == PKT_USER_ID ) {
1596             PKT_user_id *uid = node->pkt->pkt.user_id;
1597             /* Hmmm: Should we show only UIDs with a signature? */
1598             tty_printf("     ");
1599             tty_print_string( uid->name, uid->len );
1600             tty_printf("\n");
1601         }
1602         else if( node->pkt->pkttype == PKT_SIGNATURE
1603                 && ((sig = node->pkt->pkt.signature),
1604                      !seckey_available( sig->keyid )  ) ) {
1605             if( (sig->sig_class&~3) == 0x10 ) {
1606                 tty_printf("   signed by %08lX at %s\n",
1607                             sig->keyid[1], datestr_from_sig(sig) );
1608                 node->flag |= NODFLG_SELSIG;
1609             }
1610             else if( sig->sig_class == 0x30 ) {
1611                 tty_printf("   revoked by %08lX at %s\n",
1612                             sig->keyid[1], datestr_from_sig(sig) );
1613             }
1614         }
1615     }
1616
1617     /* ask */
1618     for( node = keyblock; node; node = node->next ) {
1619         if( !(node->flag & NODFLG_SELSIG) )
1620             continue;
1621         ask_revoke_sig( keyblock, node );
1622     }
1623
1624     /* present selected */
1625     any = 0;
1626     for( node = keyblock; node; node = node->next ) {
1627         if( !(node->flag & NODFLG_MARK_A) )
1628             continue;
1629         if( !any ) {
1630             any = 1;
1631             tty_printf("You are about to revoke these signatures:\n");
1632         }
1633         if( node->pkt->pkttype == PKT_USER_ID ) {
1634             PKT_user_id *uid = node->pkt->pkt.user_id;
1635             tty_printf("     ");
1636             tty_print_string( uid->name, uid->len );
1637             tty_printf("\n");
1638         }
1639         else if( node->pkt->pkttype == PKT_SIGNATURE ) {
1640             sig = node->pkt->pkt.signature;
1641             tty_printf("   signed by %08lX at %s\n",
1642                             sig->keyid[1], datestr_from_sig(sig) );
1643         }
1644     }
1645     if( !any )
1646         return 0; /* none selected */
1647
1648     if( !cpr_get_answer_is_yes("ask_revoke_sig.okay",
1649          _("Really create the revocation certificates? (y/N)")) )
1650         return 0; /* forget it */
1651
1652
1653     /* now we can sign the user ids */
1654   reloop: /* (must use this, because we are modifing the list) */
1655     primary_pk = keyblock->pkt->pkt.public_key;
1656     for( node=keyblock; node; node = node->next ) {
1657         KBNODE unode;
1658         PACKET *pkt;
1659         struct sign_uid_attrib attrib;
1660         PKT_secret_key *sk;
1661
1662         if( !(node->flag & NODFLG_MARK_A)
1663             || node->pkt->pkttype != PKT_SIGNATURE )
1664             continue;
1665         unode = find_prev_kbnode( keyblock, node, PKT_USER_ID );
1666         assert( unode ); /* we already checked this */
1667
1668         memset( &attrib, 0, sizeof attrib );
1669         node->flag &= ~NODFLG_MARK_A;
1670         sk = m_alloc_secure_clear( sizeof *sk );
1671         if( get_seckey( sk, node->pkt->pkt.signature->keyid ) ) {
1672             log_info(_("no secret key\n"));
1673             continue;
1674         }
1675         rc = make_keysig_packet( &sig, primary_pk,
1676                                        unode->pkt->pkt.user_id,
1677                                        NULL,
1678                                        sk,
1679                                        0x30, 0,
1680                                        sign_uid_mk_attrib,
1681                                        &attrib );
1682         free_secret_key(sk);
1683         if( rc ) {
1684             log_error(_("signing failed: %s\n"), g10_errstr(rc));
1685             return changed;
1686         }
1687         changed = 1; /* we changed the keyblock */
1688         upd_trust = 1;
1689
1690         pkt = m_alloc_clear( sizeof *pkt );
1691         pkt->pkttype = PKT_SIGNATURE;
1692         pkt->pkt.signature = sig;
1693         insert_kbnode( unode, new_kbnode(pkt), 0 );
1694         goto reloop;
1695     }
1696
1697     if( upd_trust )
1698         clear_trust_checked_flag( primary_pk );
1699
1700     return changed;
1701 }
1702
1703 /****************
1704  * Revoke some of the secondary keys.
1705  * Hmmm: Should we add a revocation to the secret keyring too?
1706  *       Does its all make sense to duplicate most of the information?
1707  */
1708 static int
1709 menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
1710 {
1711     PKT_public_key *mainpk;
1712     KBNODE node;
1713     int changed = 0;
1714     int upd_trust = 0;
1715     int rc;
1716
1717   reloop: /* (better this way because we are modifing the keyring) */
1718     mainpk = pub_keyblock->pkt->pkt.public_key;
1719     for( node = pub_keyblock; node; node = node->next ) {
1720         if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1721             && (node->flag & NODFLG_SELKEY) ) {
1722             PACKET *pkt;
1723             PKT_signature *sig;
1724             PKT_secret_key *sk;
1725             PKT_public_key *subpk = node->pkt->pkt.public_key;
1726
1727             node->flag &= ~NODFLG_SELKEY;
1728             sk = copy_secret_key( NULL, sec_keyblock->pkt->pkt.secret_key );
1729             rc = make_keysig_packet( &sig, mainpk, NULL, subpk, sk, 0x28, 0,
1730                                      NULL, NULL );
1731             free_secret_key(sk);
1732             if( rc ) {
1733                 log_error(_("signing failed: %s\n"), g10_errstr(rc));
1734                 return changed;
1735             }
1736             changed = 1; /* we changed the keyblock */
1737             upd_trust = 1;
1738
1739             pkt = m_alloc_clear( sizeof *pkt );
1740             pkt->pkttype = PKT_SIGNATURE;
1741             pkt->pkt.signature = sig;
1742             insert_kbnode( node, new_kbnode(pkt), 0 );
1743             goto reloop;
1744         }
1745     }
1746     commit_kbnode( &pub_keyblock );
1747     /*commit_kbnode( &sec_keyblock );*/
1748
1749     if( upd_trust )
1750         clear_trust_checked_flag( mainpk );
1751
1752     return changed;
1753 }
1754
1755