c0a082bbaddff916e41c2bbdcf61858c7fda64e3
[gnupg.git] / g10 / keyedit.c
1 /* keyedit.c - keyedit stuff
2  *      Copyright (C) 1998 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_select_uid( KBNODE keyblock, int index );
52 static int menu_select_key( KBNODE keyblock, int index );
53 static int count_uids( KBNODE keyblock );
54 static int count_uids_with_flag( KBNODE keyblock, unsigned flag );
55 static int count_keys_with_flag( KBNODE keyblock, unsigned flag );
56 static int count_selected_uids( KBNODE keyblock );
57 static int count_selected_keys( KBNODE keyblock );
58
59 #define CONTROL_D ('D' - 'A' + 1)
60
61 #define NODFLG_BADSIG (1<<0)  /* bad signature */
62 #define NODFLG_NOKEY  (1<<1)  /* no public key */
63 #define NODFLG_SIGERR (1<<2)  /* other sig error */
64
65 #define NODFLG_MARK_A (1<<4)  /* temporary mark */
66
67 #define NODFLG_SELUID (1<<8)  /* indicate the selected userid */
68 #define NODFLG_SELKEY (1<<9)  /* indicate the selected key */
69
70
71 static int
72 get_keyblock_byname( KBNODE *keyblock, KBPOS *kbpos, const char *username )
73 {
74     int rc;
75
76     *keyblock = NULL;
77     /* search the userid */
78     rc = find_keyblock_byname( kbpos, username );
79     if( rc ) {
80         log_error(_("%s: user not found\n"), username );
81         return rc;
82     }
83
84     /* read the keyblock */
85     rc = read_keyblock( kbpos, keyblock );
86     if( rc )
87         log_error("%s: keyblock read problem: %s\n", username, g10_errstr(rc));
88     return rc;
89 }
90
91
92 /****************
93  * Check the keysigs and set the flags to indicate errors.
94  * Returns true if error found.
95  */
96 static int
97 check_all_keysigs( KBNODE keyblock, int only_selected )
98 {
99     KBNODE kbctx;
100     KBNODE node;
101     int rc;
102     int inv_sigs = 0;
103     int no_key = 0;
104     int oth_err = 0;
105     int has_selfsig = 0;
106     int mis_selfsig = 0;
107     int selected = !only_selected;
108     int anyuid = 0;
109
110     for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
111         if( node->pkt->pkttype == PKT_USER_ID ) {
112             PKT_user_id *uid = node->pkt->pkt.user_id;
113
114             if( only_selected )
115                 selected = (node->flag & NODFLG_SELUID);
116             if( selected ) {
117                 tty_printf("uid  ");
118                 tty_print_string( uid->name, uid->len );
119                 tty_printf("\n");
120                 if( anyuid && !has_selfsig )
121                     mis_selfsig++;
122                 has_selfsig = 0;
123                 anyuid = 1;
124             }
125         }
126         else if( selected && node->pkt->pkttype == PKT_SIGNATURE
127                  && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
128             PKT_signature *sig = node->pkt->pkt.signature;
129             int sigrc, selfsig;
130
131             switch( (rc = check_key_signature( keyblock, node, &selfsig)) ) {
132               case 0:
133                 node->flag &= ~(NODFLG_BADSIG|NODFLG_NOKEY|NODFLG_SIGERR);
134                 sigrc = '!';
135                 break;
136               case G10ERR_BAD_SIGN:
137                 node->flag = NODFLG_BADSIG;
138                 sigrc = '-';
139                 inv_sigs++;
140                 break;
141               case G10ERR_NO_PUBKEY:
142                 node->flag = NODFLG_NOKEY;
143                 sigrc = '?';
144                 no_key++;
145                 break;
146               default:
147                 node->flag = NODFLG_SIGERR;
148                 sigrc = '%';
149                 oth_err++;
150                 break;
151             }
152             if( sigrc != '?' ) {
153                 tty_printf("sig%c       %08lX %s   ",
154                         sigrc, sig->keyid[1], datestr_from_sig(sig));
155                 if( sigrc == '%' )
156                     tty_printf("[%s] ", g10_errstr(rc) );
157                 else if( sigrc == '?' )
158                     ;
159                 else if( selfsig ) {
160                     tty_printf( _("[self-signature]") );
161                     if( sigrc == '!' )
162                         has_selfsig = 1;
163                 }
164                 else {
165                     size_t n;
166                     char *p = get_user_id( sig->keyid, &n );
167                     tty_print_string( p, n > 40? 40 : n );
168                     m_free(p);
169                 }
170                 tty_printf("\n");
171                 /* fixme: Should we update the trustdb here */
172             }
173         }
174     }
175     if( !has_selfsig )
176         mis_selfsig++;
177     if( inv_sigs == 1 )
178         tty_printf(_("1 bad signature\n"), inv_sigs );
179     else if( inv_sigs )
180         tty_printf(_("%d bad signatures\n"), inv_sigs );
181     if( no_key == 1 )
182         tty_printf(_("1 signature not checked due to a missing key\n") );
183     else if( no_key )
184         tty_printf(_("%d signatures not checked due to missing keys\n"), no_key );
185     if( oth_err == 1 )
186         tty_printf(_("1 signature not checked due to an error\n") );
187     else if( oth_err )
188         tty_printf(_("%d signatures not checked due to errors\n"), oth_err );
189     if( mis_selfsig == 1 )
190         tty_printf(_("1 user id without valid self-signature detected\n"));
191     else if( mis_selfsig  )
192         tty_printf(_("%d user ids without valid self-signatures detected\n"),
193                                                                     mis_selfsig);
194
195     return inv_sigs || no_key || oth_err || mis_selfsig;
196 }
197
198
199
200 /****************
201  * Loop over all locusr and and sign the uids after asking.
202  * If no user id is marked, all user ids will be signed;
203  * if some user_ids are marked those will be signed.
204  *
205  * fixme: Add support for our proposed sign-all scheme
206  */
207 static int
208 sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified )
209 {
210     int rc = 0;
211     SK_LIST sk_list = NULL;
212     SK_LIST sk_rover = NULL;
213     KBNODE node, uidnode;
214     PKT_public_key *primary_pk;
215     int select_all = !count_selected_uids(keyblock);
216
217     /* build a list of all signators */
218     rc=build_sk_list( locusr, &sk_list, 0, 1 );
219     if( rc )
220         goto leave;
221
222     /* loop over all signaturs */
223     for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
224         u32 sk_keyid[2];
225         size_t n;
226         char *p;
227
228         keyid_from_sk( sk_rover->sk, sk_keyid );
229         /* set mark A for all selected user ids */
230         for( node=keyblock; node; node = node->next ) {
231             if( select_all || (node->flag & NODFLG_SELUID) )
232                 node->flag |= NODFLG_MARK_A;
233             else
234                 node->flag &= ~NODFLG_MARK_A;
235         }
236         /* reset mark for uids which are already signed */
237         uidnode = NULL;
238         for( node=keyblock; node; node = node->next ) {
239             if( node->pkt->pkttype == PKT_USER_ID ) {
240                 uidnode = (node->flag & NODFLG_MARK_A)? node : NULL;
241             }
242             else if( uidnode && node->pkt->pkttype == PKT_SIGNATURE
243                 && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
244                 if( sk_keyid[0] == node->pkt->pkt.signature->keyid[0]
245                     && sk_keyid[1] == node->pkt->pkt.signature->keyid[1] ) {
246                     tty_printf(_("Already signed by key %08lX\n"),
247                                                         (ulong)sk_keyid[1] );
248                     uidnode->flag &= ~NODFLG_MARK_A; /* remove mark */
249                 }
250             }
251         }
252         /* check whether any uids are left for signing */
253         if( !count_uids_with_flag(keyblock, NODFLG_MARK_A) ) {
254             tty_printf(_("Nothing to sign with key %08lX\n"),
255                                                   (ulong)sk_keyid[1] );
256             continue;
257         }
258         /* Ask whether we realy should sign these user id(s) */
259         tty_printf("\n");
260         show_key_with_all_names( keyblock, 1, 1, 0, 0 );
261         tty_printf("\n");
262         tty_printf(_(
263              "Are you really sure that you want to sign this key\n"
264              "with your key: \""));
265         p = get_user_id( sk_keyid, &n );
266         tty_print_string( p, n );
267         m_free(p); p = NULL;
268         tty_printf("\"\n\n");
269
270         if( !cpr_get_answer_is_yes(N_("sign_uid.okay"), _("Really sign? ")) )
271             continue;;
272         /* now we can sign the user ids */
273       reloop: /* (must use this, because we are modifing the list) */
274         primary_pk = NULL;
275         for( node=keyblock; node; node = node->next ) {
276             if( node->pkt->pkttype == PKT_PUBLIC_KEY )
277                 primary_pk = node->pkt->pkt.public_key;
278             else if( node->pkt->pkttype == PKT_USER_ID
279                      && (node->flag & NODFLG_MARK_A) ) {
280                 PACKET *pkt;
281                 PKT_signature *sig;
282
283                 assert( primary_pk );
284                 node->flag &= ~NODFLG_MARK_A;
285                 rc = make_keysig_packet( &sig, primary_pk,
286                                                node->pkt->pkt.user_id,
287                                                NULL,
288                                                sk_rover->sk,
289                                                0x10, 0, NULL, NULL );
290                 if( rc ) {
291                     log_error(_("signing failed: %s\n"), g10_errstr(rc));
292                     goto leave;
293                 }
294                 *ret_modified = 1; /* we changed the keyblock */
295
296                 pkt = m_alloc_clear( sizeof *pkt );
297                 pkt->pkttype = PKT_SIGNATURE;
298                 pkt->pkt.signature = sig;
299                 insert_kbnode( node, new_kbnode(pkt), PKT_SIGNATURE );
300                 goto reloop;
301             }
302         }
303     } /* end loop over signators */
304
305   leave:
306     release_sk_list( sk_list );
307     return rc;
308 }
309
310
311
312 /****************
313  * Change the passphrase of the primary and all secondary keys.
314  * We use only one passphrase for all keys.
315  */
316 static int
317 change_passphrase( KBNODE keyblock )
318 {
319     int rc = 0;
320     int changed=0;
321     KBNODE node;
322     PKT_secret_key *sk;
323     char *passphrase = NULL;
324
325     node = find_kbnode( keyblock, PKT_SECRET_KEY );
326     if( !node ) {
327         log_error("Oops; secret key not found anymore!\n");
328         goto leave;
329     }
330     sk = node->pkt->pkt.secret_key;
331
332     switch( is_secret_key_protected( sk ) ) {
333       case -1:
334         rc = G10ERR_PUBKEY_ALGO;
335         break;
336       case 0:
337         tty_printf(_("This key is not protected.\n"));
338         break;
339       default:
340         tty_printf(_("Key is protected.\n"));
341         rc = check_secret_key( sk, 0 );
342         if( !rc )
343             passphrase = get_last_passphrase();
344         break;
345     }
346
347     /* unprotect all subkeys (use the supplied passphrase or ask)*/
348     for(node=keyblock; !rc && node; node = node->next ) {
349         if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
350             PKT_secret_key *subsk = node->pkt->pkt.secret_key;
351             set_next_passphrase( passphrase );
352             rc = check_secret_key( subsk, 0 );
353         }
354     }
355
356     if( rc )
357         tty_printf(_("Can't edit this key: %s\n"), g10_errstr(rc));
358     else {
359         DEK *dek = NULL;
360         STRING2KEY *s2k = m_alloc_secure( sizeof *s2k );
361
362         tty_printf(_("Enter the new passphrase for this secret key.\n\n") );
363
364         set_next_passphrase( NULL );
365         for(;;) {
366             s2k->mode = 1;
367             s2k->hash_algo = DIGEST_ALGO_RMD160;
368             dek = passphrase_to_dek( NULL, CIPHER_ALGO_BLOWFISH, s2k, 2 );
369             if( !dek ) {
370                 tty_printf(_("passphrase not correctly repeated; try again.\n"));
371             }
372             else if( !dek->keylen ) {
373                 rc = 0;
374                 tty_printf(_( "You don't want a passphrase -"
375                             " this is probably a *bad* idea!\n\n"));
376                 if( cpr_get_answer_is_yes(N_("change_passwd.empty.okay"),
377                                _("Do you really want to do this? ")))
378                     changed++;
379                 break;
380             }
381             else { /* okay */
382                 sk->protect.algo = dek->algo;
383                 sk->protect.s2k = *s2k;
384                 rc = protect_secret_key( sk, dek );
385                 for(node=keyblock; !rc && node; node = node->next ) {
386                     if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
387                         PKT_secret_key *subsk = node->pkt->pkt.secret_key;
388                         subsk->protect.algo = dek->algo;
389                         subsk->protect.s2k = *s2k;
390                         rc = protect_secret_key( subsk, dek );
391                     }
392                 }
393                 if( rc )
394                     log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
395                 else
396                     changed++;
397                 break;
398             }
399         }
400         m_free(s2k);
401         m_free(dek);
402     }
403
404   leave:
405     m_free( passphrase );
406     set_next_passphrase( NULL );
407     return changed && !rc;
408 }
409
410
411
412
413 /****************
414  * Menu driven key editor
415  *
416  * Note: to keep track of some selection we use node->mark MARKBIT_xxxx.
417  */
418
419 void
420 keyedit_menu( const char *username, STRLIST locusr )
421 {
422     enum cmdids { cmdNONE = 0,
423            cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN,
424            cmdDEBUG, cmdSAVE, cmdADDUID, cmdDELUID, cmdADDKEY, cmdDELKEY,
425            cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF,
426            cmdNOP };
427     static struct { const char *name;
428                     enum cmdids id;
429                     int need_sk;
430                     const char *desc;
431                   } cmds[] = {
432         { N_("quit")    , cmdQUIT   , 0, N_("quit this menu") },
433         { N_("q")       , cmdQUIT   , 0, NULL   },
434         { N_("save")    , cmdSAVE   , 0, N_("save and quit") },
435         { N_("help")    , cmdHELP   , 0, N_("show this help") },
436         {    "?"        , cmdHELP   , 0, NULL   },
437         { N_("fpr")     , cmdFPR    , 0, N_("show fingerprint") },
438         { N_("list")    , cmdLIST   , 0, N_("list key and user ids") },
439         { N_("l")       , cmdLIST   , 0, NULL   },
440         { N_("uid")     , cmdSELUID , 0, N_("select user id N") },
441         { N_("key")     , cmdSELKEY , 0, N_("select secondary key N") },
442         { N_("check")   , cmdCHECK  , 0, N_("list signatures") },
443         { N_("c")       , cmdCHECK  , 0, NULL },
444         { N_("sign")    , cmdSIGN   , 0, N_("sign the key") },
445         { N_("s")       , cmdSIGN   , 0, NULL },
446         { N_("debug")   , cmdDEBUG  , 0, NULL },
447         { N_("adduid")  , cmdADDUID , 1, N_("add a user id") },
448         { N_("deluid")  , cmdDELUID , 0, N_("delete user id") },
449         { N_("addkey")  , cmdADDKEY , 1, N_("add a secondary key") },
450         { N_("delkey")  , cmdDELKEY , 0, N_("delete a secondary key") },
451         { N_("toggle")  , cmdTOGGLE , 1, N_("toggle between secret "
452                                             "and public key listing") },
453         { N_("t"     )  , cmdTOGGLE , 1, NULL },
454         { N_("pref")    , cmdPREF  , 0, N_("list preferences") },
455         { N_("passwd")  , cmdPASSWD , 1, N_("change the passphrase") },
456         { N_("trust")   , cmdTRUST , 0, N_("change the ownertrust") },
457
458     { NULL, cmdNONE } };
459     enum cmdids cmd;
460     int rc = 0;
461     KBNODE keyblock = NULL;
462     KBPOS keyblockpos;
463     KBNODE sec_keyblock = NULL;
464     KBPOS sec_keyblockpos;
465     KBNODE cur_keyblock;
466     char *answer = NULL;
467     int redisplay = 1;
468     int modified = 0;
469     int sec_modified = 0;
470     int toggle;
471
472
473     if( opt.batch ) {
474         log_error(_("can't do that in batchmode\n"));
475         goto leave;
476     }
477
478     /* first try to locate it as secret key */
479     rc = find_secret_keyblock_byname( &sec_keyblockpos, username );
480     if( !rc ) {
481         rc = read_keyblock( &sec_keyblockpos, &sec_keyblock );
482         if( rc ) {
483             log_error("%s: secret keyblock read problem: %s\n",
484                                             username, g10_errstr(rc));
485             goto leave;
486         }
487     }
488
489     /* and now get the public key */
490     rc = get_keyblock_byname( &keyblock, &keyblockpos, username );
491     if( rc )
492         goto leave;
493
494     if( sec_keyblock ) { /* check that they match */
495         /* FIXME: check that they both match */
496         tty_printf(_("Secret key is available.\n"));
497     }
498
499     toggle = 0;
500     cur_keyblock = keyblock;
501     for(;;) { /* main loop */
502         int i, arg_number;
503         char *p;
504
505         tty_printf("\n");
506         if( redisplay ) {
507             show_key_with_all_names( cur_keyblock, 0, 0, 1, 0 );
508             tty_printf("\n");
509             redisplay = 0;
510         }
511         m_free(answer);
512         answer = cpr_get(N_("keyedit.cmd"), _("Command> "));
513         cpr_kill_prompt();
514         trim_spaces(answer);
515
516         arg_number = 0;
517         if( !*answer )
518             cmd = cmdLIST;
519         else if( *answer == CONTROL_D )
520             cmd = cmdQUIT;
521         else if( isdigit( *answer ) ) {
522             cmd = cmdSELUID;
523             arg_number = atoi(answer);
524         }
525         else {
526             if( (p=strchr(answer,' ')) ) {
527                 *p++ = 0;
528                 trim_spaces(answer);
529                 trim_spaces(p);
530                 arg_number = atoi(p);
531             }
532
533             for(i=0; cmds[i].name; i++ )
534                 if( !stricmp( answer, cmds[i].name ) )
535                     break;
536             if( cmds[i].need_sk && !sec_keyblock ) {
537                 tty_printf(_("Need the secret key to to this.\n"));
538                 cmd = cmdNOP;
539             }
540             else
541                 cmd = cmds[i].id;
542         }
543         switch( cmd )  {
544           case cmdHELP:
545             for(i=0; cmds[i].name; i++ ) {
546                 if( cmds[i].need_sk && !sec_keyblock )
547                     ; /* skip if we do not have the secret key */
548                 else if( cmds[i].desc )
549                     tty_printf("%-10s %s\n", cmds[i].name, cmds[i].desc );
550             }
551             break;
552
553           case cmdQUIT:
554             if( !modified && !sec_modified )
555                 goto leave;
556             if( !cpr_get_answer_is_yes(N_("keyedit.save.okay"),
557                                         _("Save changes? ")) ) {
558                 if( cpr_enabled()
559                     || cpr_get_answer_is_yes(N_("keyedit.cancel.okay"),
560                                              _("Quit without saving? ")) )
561                     goto leave;
562                 break;
563             }
564             /* fall thru */
565           case cmdSAVE:
566             if( modified || sec_modified  ) {
567                 if( modified ) {
568                     rc = update_keyblock( &keyblockpos, keyblock );
569                     if( rc ) {
570                         log_error(_("update failed: %s\n"), g10_errstr(rc) );
571                         break;
572                     }
573                 }
574                 if( sec_modified ) {
575                     rc = update_keyblock( &sec_keyblockpos, sec_keyblock );
576                     if( rc ) {
577                         log_error(_("update secret failed: %s\n"),
578                                                             g10_errstr(rc) );
579                         break;
580                     }
581                 }
582                 /* FIXME: UPDATE/INVALIDATE trustdb !! */
583             }
584             else
585                 tty_printf(_("Key not changed so no update needed.\n"));
586             goto leave;
587
588           case cmdLIST:
589             redisplay = 1;
590             break;
591
592           case cmdFPR:
593             show_key_and_fingerprint( keyblock );
594             break;
595
596           case cmdSELUID:
597             if( menu_select_uid( cur_keyblock, arg_number ) )
598                 redisplay = 1;
599             break;
600
601           case cmdSELKEY:
602             if( menu_select_key( cur_keyblock, arg_number ) )
603                 redisplay = 1;
604             break;
605
606           case cmdCHECK:
607             /* we can only do this with the public key becuase the
608              * check functions can't cope with secret keys and it
609              * is questionable whether this would make sense at all */
610             check_all_keysigs( keyblock, count_selected_uids(keyblock) );
611             break;
612
613           case cmdSIGN: /* sign (only the public key) */
614             if( count_uids(keyblock) > 1 && !count_selected_uids(keyblock) ) {
615                 if( !cpr_get_answer_is_yes(N_("keyedit.sign_all.okay"),
616                                            _("Really sign all user ids? ")) ) {
617                     tty_printf(_("Hint: Select the user ids to sign\n"));
618                     break;
619                 }
620             }
621             sign_uids( keyblock, locusr, &modified );
622             break;
623
624           case cmdDEBUG:
625             dump_kbnode( cur_keyblock );
626             break;
627
628           case cmdTOGGLE:
629             toggle = !toggle;
630             cur_keyblock = toggle? sec_keyblock : keyblock;
631             redisplay = 1;
632             break;
633
634           case cmdADDUID:
635             if( menu_adduid( keyblock, sec_keyblock ) ) {
636                 redisplay = 1;
637                 sec_modified = modified = 1;
638             }
639             break;
640
641           case cmdDELUID: {
642                 int n1;
643
644                 if( !(n1=count_selected_uids(keyblock)) )
645                     tty_printf(_("You must select at least one user id.\n"));
646                 else if( count_uids(keyblock) - n1 < 1 )
647                     tty_printf(_("You can't delete the last user id!\n"));
648                 else if( cpr_get_answer_is_yes(
649                             N_("keyedit.remove.uid.okay"),
650                         n1 > 1? _("Really remove all selected user ids? ")
651                               : _("Really remove this user id? ")
652                        ) ) {
653                     menu_deluid( keyblock, sec_keyblock );
654                     redisplay = 1;
655                     modified = 1;
656                     if( sec_keyblock )
657                        sec_modified = 1;
658                 }
659             }
660             break;
661
662           case cmdADDKEY:
663             if( generate_subkeypair( keyblock, sec_keyblock ) ) {
664                 redisplay = 1;
665                 sec_modified = modified = 1;
666             }
667             break;
668
669
670           case cmdDELKEY: {
671                 int n1;
672
673                 if( !(n1=count_selected_keys( keyblock )) )
674                     tty_printf(_("You must select at least one key.\n"));
675                 else if( sec_keyblock && !cpr_get_answer_is_yes(
676                             N_("keyedit.remove.subkey.okay"),
677                        n1 > 1?
678                         _("Do you really want to delete the selected keys? "):
679                         _("Do you really want to delete this key? ")
680                        ))
681                     ;
682                 else {
683                     menu_delkey( keyblock, sec_keyblock );
684                     redisplay = 1;
685                     modified = 1;
686                     if( sec_keyblock )
687                        sec_modified = 1;
688                 }
689             }
690             break;
691
692           case cmdPASSWD:
693             if( change_passphrase( sec_keyblock ) )
694                 sec_modified = 1;
695             break;
696
697           case cmdTRUST:
698             show_key_with_all_names( keyblock, 0, 0, 1, 0 );
699             tty_printf("\n");
700             if( edit_ownertrust( find_kbnode( keyblock,
701                       PKT_PUBLIC_KEY )->pkt->pkt.public_key->local_id, 1 ) )
702                 redisplay = 1;
703             /* we don't need to set modified here, as the trustvalues
704              * are updated immediately */
705             break;
706
707           case cmdPREF:
708             show_key_with_all_names( keyblock, 0, 0, 0, 1 );
709             break;
710
711           case cmdNOP:
712             break;
713
714           default:
715             tty_printf("\n");
716             tty_printf(_("Invalid command  (try \"help\")\n"));
717             break;
718         }
719     } /* end main loop */
720
721   leave:
722     release_kbnode( keyblock );
723     release_kbnode( sec_keyblock );
724     m_free(answer);
725 }
726
727
728 /****************
729  * show preferences of a public keyblock.
730  */
731 static void
732 show_prefs( KBNODE keyblock, PKT_user_id *uid )
733 {
734     KBNODE node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
735     PKT_public_key *pk;
736     byte *p;
737     int i;
738     size_t n;
739     byte namehash[20];
740
741     if( !node )
742         return; /* is a secret keyblock */
743     pk = node->pkt->pkt.public_key;
744     if( !pk->local_id ) {
745         log_error("oops: no LID\n");
746         return;
747     }
748
749     rmd160_hash_buffer( namehash, uid->name, uid->len );
750
751     p = get_pref_data( pk->local_id, namehash, &n );
752     if( !p )
753         return;
754
755     tty_printf("    ");
756     for(i=0; i < n; i+=2 ) {
757         if( p[i] )
758             tty_printf( " %c%d", p[i] == PREFTYPE_SYM    ? 'S' :
759                                  p[i] == PREFTYPE_HASH   ? 'H' :
760                                  p[i] == PREFTYPE_COMPR  ? 'Z' : '?', p[i+1]);
761     }
762     tty_printf("\n");
763
764     m_free(p);
765 }
766
767
768 /****************
769  * Display the key a the user ids, if only_marked is true, do only
770  * so for user ids with mark A flag set and dont display the index number
771  */
772 static void
773 show_key_with_all_names( KBNODE keyblock, int only_marked,
774                          int with_fpr, int with_subkeys, int with_prefs )
775 {
776     KBNODE node;
777     int i;
778
779     /* the keys */
780     for( node = keyblock; node; node = node->next ) {
781         if( node->pkt->pkttype == PKT_PUBLIC_KEY
782             || (with_subkeys && node->pkt->pkttype == PKT_PUBLIC_SUBKEY) ) {
783             PKT_public_key *pk = node->pkt->pkt.public_key;
784             int otrust=0, trust=0;
785
786             if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
787                 /* do it here, so that debug messages don't clutter the
788                  * output */
789                 trust = query_trust_info(pk);
790                 otrust = get_ownertrust_info( pk->local_id );
791             }
792
793             tty_printf("%s%c %4u%c/%08lX  created: %s expires: %s",
794                           node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub",
795                           (node->flag & NODFLG_SELKEY)? '*':' ',
796                           nbits_from_pk( pk ),
797                           pubkey_letter( pk->pubkey_algo ),
798                           (ulong)keyid_from_pk(pk,NULL),
799                           datestr_from_pk(pk),
800                           expirestr_from_pk(pk) );
801             if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
802                 tty_printf(" trust: %c/%c", otrust, trust );
803                 if( with_fpr  )
804                     show_fingerprint( pk );
805             }
806             tty_printf("\n");
807         }
808         else if( node->pkt->pkttype == PKT_SECRET_KEY
809             || (with_subkeys && node->pkt->pkttype == PKT_SECRET_SUBKEY) ) {
810             PKT_secret_key *sk = node->pkt->pkt.secret_key;
811             tty_printf("%s%c %4u%c/%08lX  created: %s expires: %s\n",
812                           node->pkt->pkttype == PKT_SECRET_KEY? "sec":"sbb",
813                           (node->flag & NODFLG_SELKEY)? '*':' ',
814                           nbits_from_sk( sk ),
815                           pubkey_letter( sk->pubkey_algo ),
816                           (ulong)keyid_from_sk(sk,NULL),
817                           datestr_from_sk(sk),
818                           expirestr_from_sk(sk) );
819         }
820     }
821     /* the user ids */
822     i = 0;
823     for( node = keyblock; node; node = node->next ) {
824         if( node->pkt->pkttype == PKT_USER_ID ) {
825             PKT_user_id *uid = node->pkt->pkt.user_id;
826             ++i;
827             if( !only_marked || (only_marked && (node->flag & NODFLG_MARK_A))){
828                 if( only_marked )
829                    tty_printf("     ");
830                 else if( node->flag & NODFLG_SELUID )
831                    tty_printf("(%d)* ", i);
832                 else
833                    tty_printf("(%d)  ", i);
834                 tty_print_string( uid->name, uid->len );
835                 tty_printf("\n");
836                 if( with_prefs )
837                     show_prefs( keyblock, uid );
838             }
839         }
840     }
841 }
842
843 static void
844 show_key_and_fingerprint( KBNODE keyblock )
845 {
846     KBNODE node;
847     PKT_public_key *pk = NULL;
848
849     for( node = keyblock; node; node = node->next ) {
850         if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
851             pk = node->pkt->pkt.public_key;
852             tty_printf("pub  %4u%c/%08lX %s ",
853                           nbits_from_pk( pk ),
854                           pubkey_letter( pk->pubkey_algo ),
855                           (ulong)keyid_from_pk(pk,NULL),
856                           datestr_from_pk(pk) );
857         }
858         else if( node->pkt->pkttype == PKT_USER_ID ) {
859             PKT_user_id *uid = node->pkt->pkt.user_id;
860             tty_print_string( uid->name, uid->len );
861             break;
862         }
863     }
864     tty_printf("\n");
865     if( pk )
866         show_fingerprint( pk );
867 }
868
869
870 static void
871 show_fingerprint( PKT_public_key *pk )
872 {
873     byte *array, *p;
874     size_t i, n;
875
876     p = array = fingerprint_from_pk( pk, NULL, &n );
877     tty_printf("             Fingerprint:");
878     if( n == 20 ) {
879         for(i=0; i < n ; i++, i++, p += 2 ) {
880             if( i == 10 )
881                 tty_printf(" ");
882             tty_printf(" %02X%02X", *p, p[1] );
883         }
884     }
885     else {
886         for(i=0; i < n ; i++, p++ ) {
887             if( i && !(i%8) )
888                 tty_printf(" ");
889             tty_printf(" %02X", *p );
890         }
891     }
892     tty_printf("\n");
893     m_free(array);
894 }
895
896
897 /****************
898  * Ask for a new user id , do the selfsignature and put it into
899  * both keyblocks.
900  * Return true if there is a new user id
901  */
902 static int
903 menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock )
904 {
905     PKT_user_id *uid;
906     PKT_public_key *pk=NULL;
907     PKT_secret_key *sk=NULL;
908     PKT_signature *sig=NULL;
909     PACKET *pkt;
910     KBNODE node;
911     KBNODE pub_where=NULL, sec_where=NULL;
912     int rc;
913
914     uid = generate_user_id();
915     if( !uid )
916         return 0;
917
918     for( node = pub_keyblock; node; pub_where = node, node = node->next ) {
919         if( node->pkt->pkttype == PKT_PUBLIC_KEY )
920             pk = node->pkt->pkt.public_key;
921         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
922             break;
923     }
924     if( !node ) /* no subkey */
925         pub_where = NULL;
926     for( node = sec_keyblock; node; sec_where = node, node = node->next ) {
927         if( node->pkt->pkttype == PKT_SECRET_KEY )
928             sk = node->pkt->pkt.secret_key;
929         else if( node->pkt->pkttype == PKT_SECRET_SUBKEY )
930             break;
931     }
932     if( !node ) /* no subkey */
933         sec_where = NULL;
934     assert(pk && sk );
935
936     rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0,
937                              keygen_add_std_prefs, sk );
938     if( rc ) {
939         log_error("signing failed: %s\n", g10_errstr(rc) );
940         free_user_id(uid);
941         return 0;
942     }
943
944     /* insert/append to secret keyblock */
945     pkt = m_alloc_clear( sizeof *pkt );
946     pkt->pkttype = PKT_USER_ID;
947     pkt->pkt.user_id = copy_user_id(NULL, uid);
948     node = new_kbnode(pkt);
949     if( sec_where )
950         insert_kbnode( sec_where, node, 0 );
951     else
952         add_kbnode( sec_keyblock, node );
953     pkt = m_alloc_clear( sizeof *pkt );
954     pkt->pkttype = PKT_SIGNATURE;
955     pkt->pkt.signature = copy_signature(NULL, sig);
956     if( sec_where )
957         insert_kbnode( node, new_kbnode(pkt), 0 );
958     else
959         add_kbnode( sec_keyblock, new_kbnode(pkt) );
960     /* insert/append to public keyblock */
961     pkt = m_alloc_clear( sizeof *pkt );
962     pkt->pkttype = PKT_USER_ID;
963     pkt->pkt.user_id = uid;
964     node = new_kbnode(pkt);
965     if( pub_where )
966         insert_kbnode( pub_where, node, 0 );
967     else
968         add_kbnode( pub_keyblock, node );
969     pkt = m_alloc_clear( sizeof *pkt );
970     pkt->pkttype = PKT_SIGNATURE;
971     pkt->pkt.signature = copy_signature(NULL, sig);
972     if( pub_where )
973         insert_kbnode( node, new_kbnode(pkt), 0 );
974     else
975         add_kbnode( pub_keyblock, new_kbnode(pkt) );
976     return 1;
977 }
978
979
980 /****************
981  * Remove all selceted userids from the keyrings
982  */
983 static void
984 menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock )
985 {
986     KBNODE node;
987     int selected=0;
988
989     for( node = pub_keyblock; node; node = node->next ) {
990         if( node->pkt->pkttype == PKT_USER_ID ) {
991             selected = node->flag & NODFLG_SELUID;
992             if( selected ) {
993                 delete_kbnode( node );
994                 if( sec_keyblock ) {
995                     KBNODE snode;
996                     int s_selected = 0;
997                     PKT_user_id *uid = node->pkt->pkt.user_id;
998                     for( snode = sec_keyblock; snode; snode = snode->next ) {
999                         if( snode->pkt->pkttype == PKT_USER_ID ) {
1000                             PKT_user_id *suid = snode->pkt->pkt.user_id;
1001
1002                             s_selected =
1003                                 (uid->len == suid->len
1004                                  && !memcmp( uid->name, suid->name, uid->len));
1005                             if( s_selected )
1006                                 delete_kbnode( snode );
1007                         }
1008                         else if( s_selected
1009                                  && snode->pkt->pkttype == PKT_SIGNATURE )
1010                             delete_kbnode( snode );
1011                         else if( snode->pkt->pkttype == PKT_SECRET_SUBKEY )
1012                             s_selected = 0;
1013                     }
1014                 }
1015             }
1016         }
1017         else if( selected && node->pkt->pkttype == PKT_SIGNATURE )
1018             delete_kbnode( node );
1019         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
1020             selected = 0;
1021     }
1022     commit_kbnode( &pub_keyblock );
1023     if( sec_keyblock )
1024         commit_kbnode( &sec_keyblock );
1025 }
1026
1027
1028 /****************
1029  * Remove some of the secondary keys
1030  */
1031 static void
1032 menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
1033 {
1034     KBNODE node;
1035     int selected=0;
1036
1037     for( node = pub_keyblock; node; node = node->next ) {
1038         if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
1039             selected = node->flag & NODFLG_SELKEY;
1040             if( selected ) {
1041                 delete_kbnode( node );
1042                 if( sec_keyblock ) {
1043                     KBNODE snode;
1044                     int s_selected = 0;
1045                     u32 ki[2];
1046
1047                     keyid_from_pk( node->pkt->pkt.public_key, ki );
1048                     for( snode = sec_keyblock; snode; snode = snode->next ) {
1049                         if( snode->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1050                             u32 ki2[2];
1051
1052                             keyid_from_sk( snode->pkt->pkt.secret_key, ki2 );
1053                             s_selected = (ki[0] == ki2[0] && ki[1] == ki2[1]);
1054                             if( s_selected )
1055                                 delete_kbnode( snode );
1056                         }
1057                         else if( s_selected
1058                                  && snode->pkt->pkttype == PKT_SIGNATURE )
1059                             delete_kbnode( snode );
1060                         else
1061                             s_selected = 0;
1062                     }
1063                 }
1064             }
1065         }
1066         else if( selected && node->pkt->pkttype == PKT_SIGNATURE )
1067             delete_kbnode( node );
1068         else
1069             selected = 0;
1070     }
1071     commit_kbnode( &pub_keyblock );
1072     if( sec_keyblock )
1073         commit_kbnode( &sec_keyblock );
1074 }
1075
1076
1077 /****************
1078  * Select one user id or remove all selection if index is 0.
1079  * Returns: True if the selection changed;
1080  */
1081 static int
1082 menu_select_uid( KBNODE keyblock, int index )
1083 {
1084     KBNODE node;
1085     int i;
1086
1087     /* first check that the index is valid */
1088     if( index ) {
1089         for( i=0, node = keyblock; node; node = node->next ) {
1090             if( node->pkt->pkttype == PKT_USER_ID ) {
1091                 if( ++i == index )
1092                     break;
1093             }
1094         }
1095         if( !node ) {
1096             tty_printf(_("No user id with index %d\n"), index );
1097             return 0;
1098         }
1099     }
1100     else { /* reset all */
1101         for( i=0, node = keyblock; node; node = node->next ) {
1102             if( node->pkt->pkttype == PKT_USER_ID )
1103                 node->flag &= ~NODFLG_SELUID;
1104         }
1105         return 1;
1106     }
1107     /* and toggle the new index */
1108     for( i=0, node = keyblock; node; node = node->next ) {
1109         if( node->pkt->pkttype == PKT_USER_ID ) {
1110             if( ++i == index )
1111                 if( (node->flag & NODFLG_SELUID) )
1112                     node->flag &= ~NODFLG_SELUID;
1113                 else
1114                     node->flag |= NODFLG_SELUID;
1115         }
1116     }
1117
1118     return 1;
1119 }
1120
1121 /****************
1122  * Select secondary keys
1123  * Returns: True if the selection changed;
1124  */
1125 static int
1126 menu_select_key( KBNODE keyblock, int index )
1127 {
1128     KBNODE node;
1129     int i;
1130
1131     /* first check that the index is valid */
1132     if( index ) {
1133         for( i=0, node = keyblock; node; node = node->next ) {
1134             if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1135                 || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1136                 if( ++i == index )
1137                     break;
1138             }
1139         }
1140         if( !node ) {
1141             tty_printf(_("No secondary key with index %d\n"), index );
1142             return 0;
1143         }
1144     }
1145     else { /* reset all */
1146         for( i=0, node = keyblock; node; node = node->next ) {
1147             if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1148                 || node->pkt->pkttype == PKT_SECRET_SUBKEY )
1149                 node->flag &= ~NODFLG_SELKEY;
1150         }
1151         return 1;
1152     }
1153     /* and set the new index */
1154     for( i=0, node = keyblock; node; node = node->next ) {
1155         if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1156             || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1157             if( ++i == index )
1158                 if( (node->flag & NODFLG_SELKEY) )
1159                     node->flag &= ~NODFLG_SELKEY;
1160                 else
1161                     node->flag |= NODFLG_SELKEY;
1162         }
1163     }
1164
1165     return 1;
1166 }
1167
1168
1169 static int
1170 count_uids_with_flag( KBNODE keyblock, unsigned flag )
1171 {
1172     KBNODE node;
1173     int i=0;
1174
1175     for( node = keyblock; node; node = node->next )
1176         if( node->pkt->pkttype == PKT_USER_ID && (node->flag & flag) )
1177             i++;
1178     return i;
1179 }
1180
1181 static int
1182 count_keys_with_flag( KBNODE keyblock, unsigned flag )
1183 {
1184     KBNODE node;
1185     int i=0;
1186
1187     for( node = keyblock; node; node = node->next )
1188         if( ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1189               || node->pkt->pkttype == PKT_SECRET_SUBKEY)
1190             && (node->flag & flag) )
1191             i++;
1192     return i;
1193 }
1194
1195 static int
1196 count_uids( KBNODE keyblock )
1197 {
1198     KBNODE node;
1199     int i=0;
1200
1201     for( node = keyblock; node; node = node->next )
1202         if( node->pkt->pkttype == PKT_USER_ID )
1203             i++;
1204     return i;
1205 }
1206
1207
1208 /****************
1209  * Returns true if there is at least one selected user id
1210  */
1211 static int
1212 count_selected_uids( KBNODE keyblock )
1213 {
1214     return count_uids_with_flag( keyblock, NODFLG_SELUID);
1215 }
1216
1217 static int
1218 count_selected_keys( KBNODE keyblock )
1219 {
1220     return count_keys_with_flag( keyblock, NODFLG_SELKEY);
1221 }
1222