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