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