LCOV - code coverage report
Current view: top level - g10 - revoke.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 63 392 16.1 %
Date: 2015-11-05 17:10:59 Functions: 3 8 37.5 %

          Line data    Source code
       1             : /* revoke.c - Create recovation certificates.
       2             :  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
       3             :  *               2004 Free Software Foundation, Inc.
       4             :  *
       5             :  * This file is part of GnuPG.
       6             :  *
       7             :  * GnuPG is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU General Public License as published by
       9             :  * the Free Software Foundation; either version 3 of the License, or
      10             :  * (at your option) any later version.
      11             :  *
      12             :  * GnuPG is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :  * GNU General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License
      18             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      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 "gpg.h"
      30             : #include "options.h"
      31             : #include "packet.h"
      32             : #include "status.h"
      33             : #include "keydb.h"
      34             : #include "util.h"
      35             : #include "main.h"
      36             : #include "ttyio.h"
      37             : #include "status.h"
      38             : #include "i18n.h"
      39             : #include "call-agent.h"
      40             : 
      41             : struct revocation_reason_info {
      42             :     int code;
      43             :     char *desc;
      44             : };
      45             : 
      46             : 
      47             : int
      48           2 : revocation_reason_build_cb( PKT_signature *sig, void *opaque )
      49             : {
      50           2 :     struct revocation_reason_info *reason = opaque;
      51           2 :     char *ud = NULL;
      52             :     byte *buffer;
      53           2 :     size_t buflen = 1;
      54             : 
      55           2 :     if(!reason)
      56           0 :       return 0;
      57             : 
      58           2 :     if( reason->desc ) {
      59           0 :         ud = native_to_utf8( reason->desc );
      60           0 :         buflen += strlen(ud);
      61             :     }
      62           2 :     buffer = xmalloc( buflen );
      63           2 :     *buffer = reason->code;
      64           2 :     if( ud ) {
      65           0 :         memcpy(buffer+1, ud, strlen(ud) );
      66           0 :         xfree( ud );
      67             :     }
      68             : 
      69           2 :     build_sig_subpkt( sig, SIGSUBPKT_REVOC_REASON, buffer, buflen );
      70           2 :     xfree( buffer );
      71           2 :     return 0;
      72             : }
      73             : 
      74             : /* Outputs a minimal pk (as defined by 2440) from a keyblock.  A
      75             :    minimal pk consists of the public key packet and a user ID.  We try
      76             :    and pick a user ID that has a uid signature, and include it if
      77             :    possible. */
      78             : static int
      79           0 : export_minimal_pk(IOBUF out,KBNODE keyblock,
      80             :                   PKT_signature *revsig,PKT_signature *revkey)
      81             : {
      82             :   KBNODE node;
      83             :   PACKET pkt;
      84           0 :   PKT_user_id *uid=NULL;
      85           0 :   PKT_signature *selfsig=NULL;
      86             :   u32 keyid[2];
      87             :   int rc;
      88             : 
      89           0 :   node=find_kbnode(keyblock,PKT_PUBLIC_KEY);
      90           0 :   if(!node)
      91             :     {
      92           0 :       log_error("key incomplete\n");
      93           0 :       return GPG_ERR_GENERAL;
      94             :     }
      95             : 
      96           0 :   keyid_from_pk(node->pkt->pkt.public_key,keyid);
      97             : 
      98           0 :   pkt=*node->pkt;
      99           0 :   rc=build_packet(out,&pkt);
     100           0 :   if(rc)
     101             :     {
     102           0 :       log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
     103           0 :       return rc;
     104             :     }
     105             : 
     106           0 :   init_packet(&pkt);
     107           0 :   pkt.pkttype=PKT_SIGNATURE;
     108             : 
     109             :   /* the revocation itself, if any.  2440 likes this to come first. */
     110           0 :   if(revsig)
     111             :     {
     112           0 :       pkt.pkt.signature=revsig;
     113           0 :       rc=build_packet(out,&pkt);
     114           0 :       if(rc)
     115             :         {
     116           0 :           log_error("build_packet failed: %s\n", gpg_strerror (rc) );
     117           0 :           return rc;
     118             :         }
     119             :     }
     120             : 
     121             :   /* If a revkey in a 1F sig is present, include it too */
     122           0 :   if(revkey)
     123             :     {
     124           0 :       pkt.pkt.signature=revkey;
     125           0 :       rc=build_packet(out,&pkt);
     126           0 :       if(rc)
     127             :         {
     128           0 :           log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
     129           0 :           return rc;
     130             :         }
     131             :     }
     132             : 
     133           0 :   while(!selfsig)
     134             :     {
     135             :       KBNODE signode;
     136             : 
     137           0 :       node=find_next_kbnode(node,PKT_USER_ID);
     138           0 :       if(!node)
     139             :         {
     140             :           /* We're out of user IDs - none were self-signed. */
     141           0 :           if(uid)
     142           0 :             break;
     143             :           else
     144             :             {
     145           0 :               log_error(_("key %s has no user IDs\n"),keystr(keyid));
     146           0 :               return GPG_ERR_GENERAL;
     147             :             }
     148             :         }
     149             : 
     150           0 :       if(node->pkt->pkt.user_id->attrib_data)
     151           0 :         continue;
     152             : 
     153           0 :       uid=node->pkt->pkt.user_id;
     154           0 :       signode=node;
     155             : 
     156           0 :       while((signode=find_next_kbnode(signode,PKT_SIGNATURE)))
     157             :         {
     158           0 :           if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
     159           0 :              keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
     160           0 :              IS_UID_SIG(signode->pkt->pkt.signature))
     161             :             {
     162           0 :               selfsig=signode->pkt->pkt.signature;
     163           0 :               break;
     164             :             }
     165             :         }
     166             :     }
     167             : 
     168           0 :   pkt.pkttype=PKT_USER_ID;
     169           0 :   pkt.pkt.user_id=uid;
     170             : 
     171           0 :   rc=build_packet(out,&pkt);
     172           0 :   if(rc)
     173             :     {
     174           0 :       log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
     175           0 :       return rc;
     176             :     }
     177             : 
     178           0 :   if(selfsig)
     179             :     {
     180           0 :       pkt.pkttype=PKT_SIGNATURE;
     181           0 :       pkt.pkt.signature=selfsig;
     182             : 
     183           0 :       rc=build_packet(out,&pkt);
     184           0 :       if(rc)
     185             :         {
     186           0 :           log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
     187           0 :           return rc;
     188             :         }
     189             :     }
     190             : 
     191           0 :   return 0;
     192             : }
     193             : 
     194             : /****************
     195             :  * Generate a revocation certificate for UNAME via a designated revoker
     196             :  */
     197             : int
     198           0 : gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr)
     199             : {
     200           0 :     int rc = 0;
     201             :     armor_filter_context_t *afx;
     202           0 :     PKT_public_key *pk = NULL;
     203           0 :     PKT_public_key *pk2 = NULL;
     204           0 :     PKT_signature *sig = NULL;
     205           0 :     IOBUF out = NULL;
     206           0 :     struct revocation_reason_info *reason = NULL;
     207             :     KEYDB_HANDLE kdbhd;
     208             :     KEYDB_SEARCH_DESC desc;
     209           0 :     KBNODE keyblock=NULL,node;
     210             :     u32 keyid[2];
     211           0 :     int i,any=0;
     212           0 :     SK_LIST sk_list=NULL;
     213             : 
     214           0 :     if( opt.batch )
     215             :       {
     216           0 :         log_error(_("can't do this in batch mode\n"));
     217           0 :         return GPG_ERR_GENERAL;
     218             :       }
     219             : 
     220           0 :     afx = new_armor_context ();
     221             : 
     222           0 :     kdbhd = keydb_new ();
     223           0 :     rc = classify_user_id (uname, &desc, 1);
     224           0 :     if (!rc)
     225           0 :       rc = keydb_search (kdbhd, &desc, 1, NULL);
     226           0 :     if (rc) {
     227           0 :         log_error (_("key \"%s\" not found: %s\n"),uname, gpg_strerror (rc));
     228           0 :         goto leave;
     229             :     }
     230             : 
     231           0 :     rc = keydb_get_keyblock (kdbhd, &keyblock );
     232           0 :     if( rc ) {
     233           0 :         log_error (_("error reading keyblock: %s\n"), gpg_strerror (rc) );
     234           0 :         goto leave;
     235             :     }
     236             : 
     237             :     /* To parse the revkeys */
     238           0 :     merge_keys_and_selfsig(keyblock);
     239             : 
     240             :     /* get the key from the keyblock */
     241           0 :     node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
     242           0 :     if( !node )
     243           0 :       BUG ();
     244             : 
     245           0 :     pk=node->pkt->pkt.public_key;
     246             : 
     247           0 :     keyid_from_pk(pk,keyid);
     248             : 
     249           0 :     if(locusr)
     250             :       {
     251           0 :         rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_CERT);
     252           0 :         if(rc)
     253           0 :           goto leave;
     254             :       }
     255             : 
     256             :     /* Are we a designated revoker for this key? */
     257             : 
     258           0 :     if(!pk->revkey && pk->numrevkeys)
     259           0 :       BUG();
     260             : 
     261           0 :     for(i=0;i<pk->numrevkeys;i++)
     262             :       {
     263             :         SK_LIST list;
     264             : 
     265           0 :         free_public_key (pk2);
     266           0 :         pk2 = NULL;
     267             : 
     268           0 :         if(sk_list)
     269             :           {
     270           0 :             for(list=sk_list;list;list=list->next)
     271             :               {
     272             :                 byte fpr[MAX_FINGERPRINT_LEN];
     273             :                 size_t fprlen;
     274             : 
     275           0 :                 fingerprint_from_pk (list->pk, fpr, &fprlen);
     276             : 
     277             :                 /* Don't get involved with keys that don't have 160
     278             :                    bit fingerprints */
     279           0 :                 if(fprlen!=20)
     280           0 :                   continue;
     281             : 
     282           0 :                 if(memcmp(fpr,pk->revkey[i].fpr,20)==0)
     283           0 :                   break;
     284             :               }
     285             : 
     286           0 :             if (list)
     287           0 :               pk2 = copy_public_key (NULL, list->pk);
     288             :             else
     289           0 :               continue;
     290             :           }
     291             :         else
     292             :           {
     293           0 :             pk2 = xmalloc_clear (sizeof *pk2);
     294           0 :             rc = get_pubkey_byfprint (pk2, NULL,
     295           0 :                                       pk->revkey[i].fpr, MAX_FINGERPRINT_LEN);
     296             :           }
     297             : 
     298             :         /* We have the revocation key.  */
     299           0 :         if(!rc)
     300             :           {
     301           0 :             PKT_signature *revkey = NULL;
     302             : 
     303           0 :             any = 1;
     304             : 
     305           0 :             print_pubkey_info (NULL, pk);
     306           0 :             tty_printf ("\n");
     307             : 
     308           0 :             tty_printf (_("To be revoked by:\n"));
     309           0 :             print_seckey_info (pk2);
     310             : 
     311           0 :             if(pk->revkey[i].class&0x40)
     312           0 :               tty_printf(_("(This is a sensitive revocation key)\n"));
     313           0 :             tty_printf("\n");
     314             : 
     315           0 :             rc = agent_probe_secret_key (ctrl, pk2);
     316           0 :             if (rc)
     317             :               {
     318           0 :                 tty_printf (_("Secret key is not available.\n"));
     319           0 :                 continue;
     320             :               }
     321             : 
     322           0 :             if( !cpr_get_answer_is_yes("gen_desig_revoke.okay",
     323           0 :          _("Create a designated revocation certificate for this key? (y/N) ")))
     324           0 :               continue;
     325             : 
     326             :             /* get the reason for the revocation (this is always v4) */
     327           0 :             reason = ask_revocation_reason( 1, 0, 1 );
     328           0 :             if( !reason )
     329           0 :               continue;
     330             : 
     331           0 :             if( !opt.armor )
     332           0 :               tty_printf(_("ASCII armored output forced.\n"));
     333             : 
     334           0 :             if( (rc = open_outfile (-1, NULL, 0, 1, &out )) )
     335           0 :               goto leave;
     336             : 
     337           0 :             afx->what = 1;
     338           0 :             afx->hdrlines = "Comment: A designated revocation certificate"
     339             :               " should follow\n";
     340           0 :             push_armor_filter (afx, out);
     341             : 
     342             :             /* create it */
     343           0 :             rc = make_keysig_packet( &sig, pk, NULL, NULL, pk2, 0x20, 0,
     344             :                                      0, 0,
     345             :                                      revocation_reason_build_cb, reason,
     346             :                                      NULL);
     347           0 :             if( rc ) {
     348           0 :               log_error(_("make_keysig_packet failed: %s\n"), gpg_strerror (rc));
     349           0 :               goto leave;
     350             :             }
     351             : 
     352             :             /* Spit out a minimal pk as well, since otherwise there is
     353             :                no way to know which key to attach this revocation to.
     354             :                Also include the direct key signature that contains
     355             :                this revocation key.  We're allowed to include
     356             :                sensitive revocation keys along with a revocation, as
     357             :                this may be the only time the recipient has seen it.
     358             :                Note that this means that if we have multiple different
     359             :                sensitive revocation keys in a given direct key
     360             :                signature, we're going to include them all here.  This
     361             :                is annoying, but the good outweighs the bad, since
     362             :                without including this a sensitive revoker can't really
     363             :                do their job.  People should not include multiple
     364             :                sensitive revocation keys in one signature: 2440 says
     365             :                "Note that it may be appropriate to isolate this
     366             :                subpacket within a separate signature so that it is not
     367             :                combined with other subpackets that need to be
     368             :                exported." -dms */
     369             : 
     370           0 :             while(!revkey)
     371             :               {
     372             :                 KBNODE signode;
     373             : 
     374           0 :                 signode=find_next_kbnode(node,PKT_SIGNATURE);
     375           0 :                 if(!signode)
     376           0 :                   break;
     377             : 
     378           0 :                 node=signode;
     379             : 
     380           0 :                 if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
     381           0 :                    keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
     382           0 :                    IS_KEY_SIG(signode->pkt->pkt.signature))
     383             :                   {
     384             :                     int j;
     385             : 
     386           0 :                     for(j=0;j<signode->pkt->pkt.signature->numrevkeys;j++)
     387             :                       {
     388           0 :                         if(pk->revkey[i].class==
     389           0 :                            signode->pkt->pkt.signature->revkey[j].class &&
     390           0 :                            pk->revkey[i].algid==
     391           0 :                            signode->pkt->pkt.signature->revkey[j].algid &&
     392           0 :                            memcmp(pk->revkey[i].fpr,
     393           0 :                                   signode->pkt->pkt.signature->revkey[j].fpr,
     394             :                                   MAX_FINGERPRINT_LEN)==0)
     395             :                           {
     396           0 :                             revkey=signode->pkt->pkt.signature;
     397           0 :                             break;
     398             :                           }
     399             :                       }
     400             :                   }
     401             :               }
     402             : 
     403           0 :             if(!revkey)
     404           0 :               BUG();
     405             : 
     406           0 :             rc=export_minimal_pk(out,keyblock,sig,revkey);
     407           0 :             if(rc)
     408           0 :               goto leave;
     409             : 
     410             :             /* and issue a usage notice */
     411           0 :             tty_printf(_("Revocation certificate created.\n"));
     412           0 :             break;
     413             :           }
     414             :       }
     415             : 
     416           0 :     if(!any)
     417           0 :       log_error(_("no revocation keys found for \"%s\"\n"),uname);
     418             : 
     419             :   leave:
     420           0 :     free_public_key (pk);
     421           0 :     free_public_key (pk2);
     422           0 :     if( sig )
     423           0 :         free_seckey_enc( sig );
     424             : 
     425           0 :     release_sk_list(sk_list);
     426             : 
     427           0 :     if( rc )
     428           0 :         iobuf_cancel(out);
     429             :     else
     430           0 :         iobuf_close(out);
     431           0 :     release_revocation_reason_info( reason );
     432           0 :     release_armor_context (afx);
     433           0 :     return rc;
     434             : }
     435             : 
     436             : 
     437             : /* Common core to create the revocation. FILENAME may be NULL to write
     438             :    to stdout or the filename given by --output.  REASON describes the
     439             :    revocation reason.  PSK is the public primary key - we expect that
     440             :    a corresponding secret key is available.  KEYBLOCK is the entire
     441             :    KEYBLOCK which is used in PGP mode to write a a minimal key and not
     442             :    just the naked revocation signature; it may be NULL.  If LEADINTEXT
     443             :    is not NULL, it is written right before the (armored) output.*/
     444             : static int
     445           2 : create_revocation (const char *filename,
     446             :                    struct revocation_reason_info *reason,
     447             :                    PKT_public_key *psk,
     448             :                    kbnode_t keyblock,
     449             :                    const char *leadintext, int suffix,
     450             :                    const char *cache_nonce)
     451             : {
     452             :   int rc;
     453           2 :   iobuf_t out = NULL;
     454             :   armor_filter_context_t *afx;
     455           2 :   PKT_signature *sig = NULL;
     456             :   PACKET pkt;
     457             : 
     458           2 :   afx = new_armor_context ();
     459             : 
     460           2 :   if ((rc = open_outfile (-1, filename, suffix, 1, &out)))
     461           0 :     goto leave;
     462             : 
     463           2 :   if (leadintext )
     464           2 :     iobuf_writestr (out, leadintext);
     465             : 
     466           2 :   afx->what = 1;
     467           2 :   afx->hdrlines = "Comment: This is a revocation certificate\n";
     468           2 :   push_armor_filter (afx, out);
     469             : 
     470           2 :   rc = make_keysig_packet (&sig, psk, NULL, NULL, psk, 0x20, 0,
     471             :                            0, 0,
     472             :                            revocation_reason_build_cb, reason, cache_nonce);
     473           2 :   if (rc)
     474             :     {
     475           0 :       log_error (_("make_keysig_packet failed: %s\n"), gpg_strerror (rc));
     476           0 :       goto leave;
     477             :     }
     478             : 
     479           2 :   if (keyblock && (PGP6 || PGP7 || PGP8))
     480             :     {
     481             :       /* Use a minimal pk for PGPx mode, since PGP can't import bare
     482             :          revocation certificates. */
     483           0 :       rc = export_minimal_pk (out, keyblock, sig, NULL);
     484           0 :       if (rc)
     485           0 :         goto leave;
     486             :     }
     487             :   else
     488             :     {
     489           2 :       init_packet (&pkt);
     490           2 :       pkt.pkttype = PKT_SIGNATURE;
     491           2 :       pkt.pkt.signature = sig;
     492             : 
     493           2 :       rc = build_packet (out, &pkt);
     494           2 :       if (rc)
     495             :         {
     496           0 :           log_error (_("build_packet failed: %s\n"), gpg_strerror (rc));
     497           0 :           goto leave;
     498             :         }
     499             :     }
     500             : 
     501             :  leave:
     502           2 :   if (sig)
     503           2 :     free_seckey_enc (sig);
     504           2 :   if (rc)
     505           0 :     iobuf_cancel (out);
     506             :   else
     507           2 :     iobuf_close (out);
     508           2 :   release_armor_context (afx);
     509           2 :   return rc;
     510             : }
     511             : 
     512             : 
     513             : /* This function is used to generate a standard revocation certificate
     514             :    by gpg's interactive key generation function.  The certificate is
     515             :    stored at a dedicated place in a slightly modified form to avoid an
     516             :    accidental import.  PSK is the primary key; a corresponding secret
     517             :    key must be available.  CACHE_NONCE is optional but can be used to
     518             :    help gpg-agent to avoid an extra passphrase prompt. */
     519             : int
     520           2 : gen_standard_revoke (PKT_public_key *psk, const char *cache_nonce)
     521             : {
     522             :   int rc;
     523             :   estream_t memfp;
     524             :   struct revocation_reason_info reason;
     525             :   char *dir, *tmpstr, *fname;
     526             :   void *leadin;
     527             :   size_t len;
     528             :   u32 keyid[2];
     529             :   char pkstrbuf[PUBKEY_STRING_SIZE];
     530             :   char *orig_codeset;
     531             : 
     532           2 :   dir = get_openpgp_revocdir (opt.homedir);
     533           2 :   tmpstr = hexfingerprint (psk);
     534           2 :   fname = xstrconcat (dir, DIRSEP_S, tmpstr, NULL);
     535           2 :   xfree (tmpstr);
     536           2 :   xfree (dir);
     537             : 
     538           2 :   keyid_from_pk (psk, keyid);
     539             : 
     540           2 :   memfp = es_fopenmem (0, "r+");
     541           2 :   if (!memfp)
     542           0 :     log_fatal ("error creating memory stream\n");
     543             : 
     544           2 :   orig_codeset = i18n_switchto_utf8 ();
     545             : 
     546           2 :   es_fprintf (memfp, "%s\n\n",
     547             :               _("This is a revocation certificate for the OpenPGP key:"));
     548             : 
     549           2 :   es_fprintf (memfp, "pub  %s/%s %s\n",
     550             :               pubkey_string (psk, pkstrbuf, sizeof pkstrbuf),
     551             :               keystr (keyid),
     552             :               datestr_from_pk (psk));
     553             : 
     554           2 :   print_fingerprint (memfp, psk, 3);
     555             : 
     556           2 :   tmpstr = get_user_id (keyid, &len);
     557           4 :   es_fprintf (memfp, "uid%*s%.*s\n\n",
     558           2 :               (int)keystrlen () + 10, "",
     559             :               (int)len, tmpstr);
     560           2 :   xfree (tmpstr);
     561             : 
     562           2 :   es_fprintf (memfp, "%s\n\n%s\n\n:",
     563             :      _("Use it to revoke this key in case of a compromise or loss of\n"
     564             :        "the secret key.  However, if the secret key is still accessible,\n"
     565             :        "it is better to generate a new revocation certificate and give\n"
     566             :        "a reason for the revocation."),
     567             :      _("To avoid an accidental use of this file, a colon has been inserted\n"
     568             :        "before the 5 dashes below.  Remove this colon with a text editor\n"
     569             :        "before making use of this revocation certificate."));
     570             : 
     571           2 :   es_putc (0, memfp);
     572             : 
     573           2 :   i18n_switchback (orig_codeset);
     574             : 
     575           2 :   if (es_fclose_snatch (memfp, &leadin, NULL))
     576           0 :     log_fatal ("error snatching memory stream\n");
     577             : 
     578           2 :   reason.code = 0x00; /* No particular reason.  */
     579           2 :   reason.desc = NULL;
     580           2 :   rc = create_revocation (fname, &reason, psk, NULL, leadin, 3, cache_nonce);
     581           2 :   xfree (leadin);
     582           2 :   xfree (fname);
     583             : 
     584           2 :   return rc;
     585             : }
     586             : 
     587             : 
     588             : 
     589             : /****************
     590             :  * Generate a revocation certificate for UNAME
     591             :  */
     592             : int
     593           0 : gen_revoke (const char *uname)
     594             : {
     595           0 :   int rc = 0;
     596             :   PKT_public_key *psk;
     597             :   u32 keyid[2];
     598           0 :   kbnode_t keyblock = NULL;
     599             :   kbnode_t node;
     600             :   KEYDB_HANDLE kdbhd;
     601           0 :   struct revocation_reason_info *reason = NULL;
     602             :   KEYDB_SEARCH_DESC desc;
     603             : 
     604           0 :   if( opt.batch )
     605             :     {
     606           0 :       log_error(_("can't do this in batch mode\n"));
     607           0 :       return GPG_ERR_GENERAL;
     608             :     }
     609             : 
     610             :   /* Search the userid; we don't want the whole getkey stuff here.  */
     611           0 :   kdbhd = keydb_new ();
     612           0 :   rc = classify_user_id (uname, &desc, 1);
     613           0 :   if (!rc)
     614           0 :     rc = keydb_search (kdbhd, &desc, 1, NULL);
     615           0 :   if (rc)
     616             :     {
     617           0 :       log_error (_("secret key \"%s\" not found: %s\n"),
     618             :                  uname, gpg_strerror (rc));
     619           0 :       goto leave;
     620             :     }
     621             : 
     622           0 :   rc = keydb_get_keyblock (kdbhd, &keyblock );
     623           0 :   if (rc)
     624             :     {
     625           0 :       log_error (_("error reading keyblock: %s\n"), gpg_strerror (rc) );
     626           0 :       goto leave;
     627             :     }
     628             : 
     629             :   /* Get the keyid from the keyblock.  */
     630           0 :   node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
     631           0 :   if (!node)
     632           0 :     BUG ();
     633             : 
     634           0 :   psk = node->pkt->pkt.public_key;
     635           0 :   rc = agent_probe_secret_key (NULL, psk);
     636           0 :   if (rc)
     637             :     {
     638           0 :       log_error (_("secret key \"%s\" not found: %s\n"),
     639             :                  uname, gpg_strerror (rc));
     640           0 :       goto leave;
     641             :     }
     642             : 
     643           0 :   keyid_from_pk (psk, keyid );
     644           0 :   print_seckey_info (psk);
     645             : 
     646           0 :   tty_printf("\n");
     647           0 :   if (!cpr_get_answer_is_yes ("gen_revoke.okay",
     648           0 :                 _("Create a revocation certificate for this key? (y/N) ")))
     649             :     {
     650           0 :       rc = 0;
     651           0 :       goto leave;
     652             :     }
     653             : 
     654             :   /* Get the reason for the revocation.  */
     655           0 :   reason = ask_revocation_reason (1, 0, 1);
     656           0 :   if (!reason)
     657             :     {
     658             :       /* User decided to cancel.  */
     659           0 :       rc = 0;
     660           0 :       goto leave;
     661             :     }
     662             : 
     663           0 :   if (!opt.armor)
     664           0 :     tty_printf (_("ASCII armored output forced.\n"));
     665             : 
     666           0 :   rc = create_revocation (NULL, reason, psk, keyblock, NULL, 0, NULL);
     667           0 :   if (rc)
     668           0 :     goto leave;
     669             : 
     670             :   /* and issue a usage notice */
     671           0 :   tty_printf (_(
     672             : "Revocation certificate created.\n\n"
     673             : "Please move it to a medium which you can hide away; if Mallory gets\n"
     674             : "access to this certificate he can use it to make your key unusable.\n"
     675             : "It is smart to print this certificate and store it away, just in case\n"
     676             : "your media become unreadable.  But have some caution:  The print system of\n"
     677             : "your machine might store the data and make it available to others!\n"));
     678             : 
     679             :  leave:
     680           0 :   release_kbnode (keyblock);
     681           0 :   keydb_release (kdbhd);
     682           0 :   release_revocation_reason_info( reason );
     683           0 :   return rc;
     684             : }
     685             : 
     686             : 
     687             : 
     688             : struct revocation_reason_info *
     689           0 : ask_revocation_reason( int key_rev, int cert_rev, int hint )
     690             : {
     691           0 :     int code=-1;
     692           0 :     char *description = NULL;
     693             :     struct revocation_reason_info *reason;
     694           0 :     const char *text_0 = _("No reason specified");
     695           0 :     const char *text_1 = _("Key has been compromised");
     696           0 :     const char *text_2 = _("Key is superseded");
     697           0 :     const char *text_3 = _("Key is no longer used");
     698           0 :     const char *text_4 = _("User ID is no longer valid");
     699           0 :     const char *code_text = NULL;
     700             : 
     701             :     do {
     702           0 :         code=-1;
     703           0 :         xfree(description);
     704           0 :         description = NULL;
     705             : 
     706           0 :         tty_printf(_("Please select the reason for the revocation:\n"));
     707           0 :         tty_printf(    "  0 = %s\n", text_0 );
     708           0 :         if( key_rev )
     709           0 :             tty_printf("  1 = %s\n", text_1 );
     710           0 :         if( key_rev )
     711           0 :             tty_printf("  2 = %s\n", text_2 );
     712           0 :         if( key_rev )
     713           0 :             tty_printf("  3 = %s\n", text_3 );
     714           0 :         if( cert_rev )
     715           0 :             tty_printf("  4 = %s\n", text_4 );
     716           0 :         tty_printf(    "  Q = %s\n", _("Cancel") );
     717           0 :         if( hint )
     718           0 :             tty_printf(_("(Probably you want to select %d here)\n"), hint );
     719             : 
     720           0 :         while(code==-1) {
     721             :             int n;
     722           0 :             char *answer = cpr_get("ask_revocation_reason.code",
     723           0 :                                                 _("Your decision? "));
     724           0 :             trim_spaces( answer );
     725           0 :             cpr_kill_prompt();
     726           0 :             if( *answer == 'q' || *answer == 'Q')
     727           0 :               return NULL; /* cancel */
     728           0 :             if( hint && !*answer )
     729           0 :                 n = hint;
     730           0 :             else if(!digitp( answer ) )
     731           0 :                 n = -1;
     732             :             else
     733           0 :                 n = atoi(answer);
     734           0 :             xfree(answer);
     735           0 :             if( n == 0 ) {
     736           0 :                 code = 0x00; /* no particular reason */
     737           0 :                 code_text = text_0;
     738             :             }
     739           0 :             else if( key_rev && n == 1 ) {
     740           0 :                 code = 0x02; /* key has been compromised */
     741           0 :                 code_text = text_1;
     742             :             }
     743           0 :             else if( key_rev && n == 2 ) {
     744           0 :                 code = 0x01; /* key is superseded */
     745           0 :                 code_text = text_2;
     746             :             }
     747           0 :             else if( key_rev && n == 3 ) {
     748           0 :                 code = 0x03; /* key is no longer used */
     749           0 :                 code_text = text_3;
     750             :             }
     751           0 :             else if( cert_rev && n == 4 ) {
     752           0 :                 code = 0x20; /* uid is no longer valid */
     753           0 :                 code_text = text_4;
     754             :             }
     755             :             else
     756           0 :                 tty_printf(_("Invalid selection.\n"));
     757             :         }
     758             : 
     759           0 :         tty_printf(_("Enter an optional description; "
     760             :                      "end it with an empty line:\n") );
     761             :         for(;;) {
     762           0 :             char *answer = cpr_get("ask_revocation_reason.text", "> " );
     763           0 :             trim_trailing_ws( answer, strlen(answer) );
     764           0 :             cpr_kill_prompt();
     765           0 :             if( !*answer ) {
     766           0 :                 xfree(answer);
     767           0 :                 break;
     768             :             }
     769             : 
     770             :             {
     771           0 :                 char *p = make_printable_string( answer, strlen(answer), 0 );
     772           0 :                 xfree(answer);
     773           0 :                 answer = p;
     774             :             }
     775             : 
     776           0 :             if( !description )
     777           0 :                 description = xstrdup(answer);
     778             :             else {
     779           0 :                 char *p = xmalloc( strlen(description) + strlen(answer) + 2 );
     780           0 :                 strcpy(stpcpy(stpcpy( p, description),"\n"),answer);
     781           0 :                 xfree(description);
     782           0 :                 description = p;
     783             :             }
     784           0 :             xfree(answer);
     785           0 :         }
     786             : 
     787           0 :         tty_printf(_("Reason for revocation: %s\n"), code_text );
     788           0 :         if( !description )
     789           0 :             tty_printf(_("(No description given)\n") );
     790             :         else
     791           0 :             tty_printf("%s\n", description );
     792             : 
     793           0 :     } while( !cpr_get_answer_is_yes("ask_revocation_reason.okay",
     794           0 :                                             _("Is this okay? (y/N) "))  );
     795             : 
     796           0 :     reason = xmalloc( sizeof *reason );
     797           0 :     reason->code = code;
     798           0 :     reason->desc = description;
     799           0 :     return reason;
     800             : }
     801             : 
     802             : void
     803           0 : release_revocation_reason_info( struct revocation_reason_info *reason )
     804             : {
     805           0 :     if( reason ) {
     806           0 :         xfree( reason->desc );
     807           0 :         xfree( reason );
     808             :     }
     809           0 : }

Generated by: LCOV version 1.11