LCOV - code coverage report
Current view: top level - g10 - revoke.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 79 430 18.4 %
Date: 2016-11-29 15:00:56 Functions: 5 9 55.6 %

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

Generated by: LCOV version 1.11