indent: Always use "_(" and not "_ (" to mark translatable strings.
[gnupg.git] / sm / verify.c
1 /* verify.c - Verify a messages signature
2  * Copyright (C) 2001, 2002, 2003, 2007,
3  *               2010 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 <unistd.h>
27 #include <time.h>
28 #include <assert.h>
29
30 #include "gpgsm.h"
31 #include <gcrypt.h>
32 #include <ksba.h>
33
34 #include "keydb.h"
35 #include "../common/i18n.h"
36 #include "../common/compliance.h"
37
38 static char *
39 strtimestamp_r (ksba_isotime_t atime)
40 {
41   char *buffer = xmalloc (15);
42
43   if (!atime || !*atime)
44     strcpy (buffer, "none");
45   else
46     sprintf (buffer, "%.4s-%.2s-%.2s", atime, atime+4, atime+6);
47   return buffer;
48 }
49
50
51
52 /* Hash the data for a detached signature.  Returns 0 on success.  */
53 static gpg_error_t
54 hash_data (int fd, gcry_md_hd_t md)
55 {
56   gpg_error_t err = 0;
57   estream_t fp;
58   char buffer[4096];
59   int nread;
60
61   fp = es_fdopen_nc (fd, "rb");
62   if (!fp)
63     {
64       err = gpg_error_from_syserror ();
65       log_error ("fdopen(%d) failed: %s\n", fd, gpg_strerror (err));
66       return err;
67     }
68
69   do
70     {
71       nread = es_fread (buffer, 1, DIM(buffer), fp);
72       gcry_md_write (md, buffer, nread);
73     }
74   while (nread);
75   if (es_ferror (fp))
76     {
77       err = gpg_error_from_syserror ();
78       log_error ("read error on fd %d: %s\n", fd, gpg_strerror (err));
79     }
80   es_fclose (fp);
81   return err;
82 }
83
84
85
86 \f
87 /* Perform a verify operation.  To verify detached signatures, DATA_FD
88    must be different than -1.  With OUT_FP given and a non-detached
89    signature, the signed material is written to that stream.  */
90 int
91 gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
92 {
93   int i, rc;
94   gnupg_ksba_io_t b64reader = NULL;
95   gnupg_ksba_io_t b64writer = NULL;
96   ksba_reader_t reader;
97   ksba_writer_t writer = NULL;
98   ksba_cms_t cms = NULL;
99   ksba_stop_reason_t stopreason;
100   ksba_cert_t cert;
101   KEYDB_HANDLE kh;
102   gcry_md_hd_t data_md = NULL;
103   int signer;
104   const char *algoid;
105   int algo;
106   int is_detached;
107   estream_t in_fp = NULL;
108   char *p;
109
110   audit_set_type (ctrl->audit, AUDIT_TYPE_VERIFY);
111
112   kh = keydb_new ();
113   if (!kh)
114     {
115       log_error (_("failed to allocate keyDB handle\n"));
116       rc = gpg_error (GPG_ERR_GENERAL);
117       goto leave;
118     }
119
120
121   in_fp = es_fdopen_nc (in_fd, "rb");
122   if (!in_fp)
123     {
124       rc = gpg_error_from_syserror ();
125       log_error ("fdopen() failed: %s\n", strerror (errno));
126       goto leave;
127     }
128
129   rc = gnupg_ksba_create_reader
130     (&b64reader, ((ctrl->is_pem? GNUPG_KSBA_IO_PEM : 0)
131                   | (ctrl->is_base64? GNUPG_KSBA_IO_BASE64 : 0)
132                   | (ctrl->autodetect_encoding? GNUPG_KSBA_IO_AUTODETECT : 0)),
133      in_fp, &reader);
134   if (rc)
135     {
136       log_error ("can't create reader: %s\n", gpg_strerror (rc));
137       goto leave;
138     }
139
140   if (out_fp)
141     {
142       rc = gnupg_ksba_create_writer
143         (&b64writer, ((ctrl->create_pem? GNUPG_KSBA_IO_PEM : 0)
144                       | (ctrl->create_base64? GNUPG_KSBA_IO_BASE64 : 0)),
145          ctrl->pem_name, out_fp, &writer);
146       if (rc)
147         {
148           log_error ("can't create writer: %s\n", gpg_strerror (rc));
149           goto leave;
150         }
151     }
152
153   rc = ksba_cms_new (&cms);
154   if (rc)
155     goto leave;
156
157   rc = ksba_cms_set_reader_writer (cms, reader, writer);
158   if (rc)
159     {
160       log_error ("ksba_cms_set_reader_writer failed: %s\n",
161                  gpg_strerror (rc));
162       goto leave;
163     }
164
165   rc = gcry_md_open (&data_md, 0, 0);
166   if (rc)
167     {
168       log_error ("md_open failed: %s\n", gpg_strerror (rc));
169       goto leave;
170     }
171   if (DBG_HASHING)
172     gcry_md_debug (data_md, "vrfy.data");
173
174   audit_log (ctrl->audit, AUDIT_SETUP_READY);
175
176   is_detached = 0;
177   do
178     {
179       rc = ksba_cms_parse (cms, &stopreason);
180       if (rc)
181         {
182           log_error ("ksba_cms_parse failed: %s\n", gpg_strerror (rc));
183           goto leave;
184         }
185
186       if (stopreason == KSBA_SR_NEED_HASH)
187         {
188           is_detached = 1;
189           audit_log (ctrl->audit, AUDIT_DETACHED_SIGNATURE);
190           if (opt.verbose)
191             log_info ("detached signature\n");
192         }
193
194       if (stopreason == KSBA_SR_NEED_HASH
195           || stopreason == KSBA_SR_BEGIN_DATA)
196         {
197           audit_log (ctrl->audit, AUDIT_GOT_DATA);
198
199           /* We are now able to enable the hash algorithms */
200           for (i=0; (algoid=ksba_cms_get_digest_algo_list (cms, i)); i++)
201             {
202               algo = gcry_md_map_name (algoid);
203               if (!algo)
204                 {
205                   log_error ("unknown hash algorithm '%s'\n",
206                              algoid? algoid:"?");
207                   if (algoid
208                       && (  !strcmp (algoid, "1.2.840.113549.1.1.2")
209                           ||!strcmp (algoid, "1.2.840.113549.2.2")))
210                     log_info (_("(this is the MD2 algorithm)\n"));
211                   audit_log_s (ctrl->audit, AUDIT_BAD_DATA_HASH_ALGO, algoid);
212                 }
213               else
214                 {
215                   if (DBG_X509)
216                     log_debug ("enabling hash algorithm %d (%s)\n",
217                                algo, algoid? algoid:"");
218                   gcry_md_enable (data_md, algo);
219                   audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO, algo);
220                 }
221             }
222           if (opt.extra_digest_algo)
223             {
224               if (DBG_X509)
225                 log_debug ("enabling extra hash algorithm %d\n",
226                            opt.extra_digest_algo);
227               gcry_md_enable (data_md, opt.extra_digest_algo);
228               audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO,
229                            opt.extra_digest_algo);
230             }
231           if (is_detached)
232             {
233               if (data_fd == -1)
234                 {
235                   log_info ("detached signature w/o data "
236                             "- assuming certs-only\n");
237                   audit_log (ctrl->audit, AUDIT_CERT_ONLY_SIG);
238                 }
239               else
240                 audit_log_ok (ctrl->audit, AUDIT_DATA_HASHING,
241                               hash_data (data_fd, data_md));
242             }
243           else
244             {
245               ksba_cms_set_hash_function (cms, HASH_FNC, data_md);
246             }
247         }
248       else if (stopreason == KSBA_SR_END_DATA)
249         { /* The data bas been hashed */
250           audit_log_ok (ctrl->audit, AUDIT_DATA_HASHING, 0);
251         }
252     }
253   while (stopreason != KSBA_SR_READY);
254
255   if (b64writer)
256     {
257       rc = gnupg_ksba_finish_writer (b64writer);
258       if (rc)
259         {
260           log_error ("write failed: %s\n", gpg_strerror (rc));
261           audit_log_ok (ctrl->audit, AUDIT_WRITE_ERROR, rc);
262           goto leave;
263         }
264     }
265
266   if (data_fd != -1 && !is_detached)
267     {
268       log_error ("data given for a non-detached signature\n");
269       rc = gpg_error (GPG_ERR_CONFLICT);
270       audit_log (ctrl->audit, AUDIT_USAGE_ERROR);
271       goto leave;
272     }
273
274   for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
275     {
276       /* Fixme: it might be better to check the validity of the
277          certificate first before entering it into the DB.  This way
278          we would avoid cluttering the DB with invalid
279          certificates. */
280       audit_log_cert (ctrl->audit, AUDIT_SAVE_CERT, cert,
281                       keydb_store_cert (ctrl, cert, 0, NULL));
282       ksba_cert_release (cert);
283     }
284
285   cert = NULL;
286   for (signer=0; ; signer++)
287     {
288       char *issuer = NULL;
289       ksba_sexp_t sigval = NULL;
290       ksba_isotime_t sigtime, keyexptime;
291       ksba_sexp_t serial;
292       char *msgdigest = NULL;
293       size_t msgdigestlen;
294       char *ctattr;
295       int sigval_hash_algo;
296       int info_pkalgo;
297       unsigned int verifyflags;
298
299       rc = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial);
300       if (!signer && gpg_err_code (rc) == GPG_ERR_NO_DATA
301           && data_fd == -1 && is_detached)
302         {
303           log_info ("certs-only message accepted\n");
304           rc = 0;
305           break;
306         }
307       if (rc)
308         {
309           if (signer && rc == -1)
310             rc = 0;
311           break;
312         }
313
314       gpgsm_status (ctrl, STATUS_NEWSIG, NULL);
315       audit_log_i (ctrl->audit, AUDIT_NEW_SIG, signer);
316
317       if (DBG_X509)
318         {
319           log_debug ("signer %d - issuer: '%s'\n",
320                      signer, issuer? issuer:"[NONE]");
321           log_debug ("signer %d - serial: ", signer);
322           gpgsm_dump_serial (serial);
323           log_printf ("\n");
324         }
325       if (ctrl->audit)
326         {
327           char *tmpstr = gpgsm_format_sn_issuer (serial, issuer);
328           audit_log_s (ctrl->audit, AUDIT_SIG_NAME, tmpstr);
329           xfree (tmpstr);
330         }
331
332       rc = ksba_cms_get_signing_time (cms, signer, sigtime);
333       if (gpg_err_code (rc) == GPG_ERR_NO_DATA)
334         *sigtime = 0;
335       else if (rc)
336         {
337           log_error ("error getting signing time: %s\n", gpg_strerror (rc));
338           *sigtime = 0; /* (we can't encode an error in the time string.) */
339         }
340
341       rc = ksba_cms_get_message_digest (cms, signer,
342                                         &msgdigest, &msgdigestlen);
343       if (!rc)
344         {
345           algoid = ksba_cms_get_digest_algo (cms, signer);
346           algo = gcry_md_map_name (algoid);
347           if (DBG_X509)
348             log_debug ("signer %d - digest algo: %d\n", signer, algo);
349           if (! gcry_md_is_enabled (data_md, algo))
350             {
351               log_error ("digest algo %d (%s) has not been enabled\n",
352                          algo, algoid?algoid:"");
353               audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "unsupported");
354               goto next_signer;
355             }
356         }
357       else if (gpg_err_code (rc) == GPG_ERR_NO_DATA)
358         {
359           assert (!msgdigest);
360           rc = 0;
361           algoid = NULL;
362           algo = 0;
363         }
364       else /* real error */
365         {
366           audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "error");
367           break;
368         }
369
370       rc = ksba_cms_get_sigattr_oids (cms, signer,
371                                       "1.2.840.113549.1.9.3", &ctattr);
372       if (!rc)
373         {
374           const char *s;
375
376           if (DBG_X509)
377             log_debug ("signer %d - content-type attribute: %s",
378                        signer, ctattr);
379
380           s = ksba_cms_get_content_oid (cms, 1);
381           if (!s || strcmp (ctattr, s))
382             {
383               log_error ("content-type attribute does not match "
384                          "actual content-type\n");
385               ksba_free (ctattr);
386               ctattr = NULL;
387               audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
388               goto next_signer;
389             }
390           ksba_free (ctattr);
391           ctattr = NULL;
392         }
393       else if (rc != -1)
394         {
395           log_error ("error getting content-type attribute: %s\n",
396                      gpg_strerror (rc));
397           audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
398           goto next_signer;
399         }
400       rc = 0;
401
402
403       sigval = ksba_cms_get_sig_val (cms, signer);
404       if (!sigval)
405         {
406           log_error ("no signature value available\n");
407           audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
408           goto next_signer;
409         }
410       sigval_hash_algo = hash_algo_from_sigval (sigval);
411       if (DBG_X509)
412         {
413           log_debug ("signer %d - signature available (sigval hash=%d)",
414                      signer, sigval_hash_algo);
415 /*           log_printhex ("sigval    ", sigval, */
416 /*                         gcry_sexp_canon_len (sigval, 0, NULL, NULL)); */
417         }
418       if (!sigval_hash_algo)
419         sigval_hash_algo = algo; /* Fallback used e.g. with old libksba. */
420
421       /* Find the certificate of the signer */
422       keydb_search_reset (kh);
423       rc = keydb_search_issuer_sn (ctrl, kh, issuer, serial);
424       if (rc)
425         {
426           if (rc == -1)
427             {
428               log_error ("certificate not found\n");
429               rc = gpg_error (GPG_ERR_NO_PUBKEY);
430             }
431           else
432             log_error ("failed to find the certificate: %s\n",
433                        gpg_strerror(rc));
434           {
435             char numbuf[50];
436             sprintf (numbuf, "%d", rc);
437
438             gpgsm_status2 (ctrl, STATUS_ERROR, "verify.findkey",
439                            numbuf, NULL);
440           }
441           audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "no-cert");
442           goto next_signer;
443         }
444
445       rc = keydb_get_cert (kh, &cert);
446       if (rc)
447         {
448           log_error ("failed to get cert: %s\n", gpg_strerror (rc));
449           audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "error");
450           goto next_signer;
451         }
452
453       /* Check compliance.  */
454       {
455         unsigned int nbits;
456         int pk_algo = gpgsm_get_key_algo_info (cert, &nbits);
457
458         if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
459                                    pk_algo, NULL, nbits, NULL))
460           {
461             log_error ("certificate ID 0x%08lX not suitable for "
462                        "verification while in %s mode\n",
463                        gpgsm_get_short_fingerprint (cert, NULL),
464                        gnupg_compliance_option_string (opt.compliance));
465             goto next_signer;
466           }
467
468         if (! gnupg_digest_is_allowed (opt.compliance, 0, sigval_hash_algo))
469           {
470             log_error (_("you may not use digest algorithm '%s'"
471                          " while in %s mode\n"),
472                        gcry_md_algo_name (sigval_hash_algo),
473                        gnupg_compliance_option_string (opt.compliance));
474             goto next_signer;
475           }
476
477         /* Check compliance with CO_DE_VS.  */
478         if (gnupg_pk_is_compliant (CO_DE_VS, pk_algo, NULL, nbits, NULL)
479             && gnupg_digest_is_compliant (CO_DE_VS, sigval_hash_algo))
480           gpgsm_status (ctrl, STATUS_VERIFICATION_COMPLIANCE_MODE,
481                         gnupg_status_compliance_flag (CO_DE_VS));
482       }
483
484       log_info (_("Signature made "));
485       if (*sigtime)
486         dump_isotime (sigtime);
487       else
488         log_printf (_("[date not given]"));
489       log_printf (_(" using certificate ID 0x%08lX\n"),
490                   gpgsm_get_short_fingerprint (cert, NULL));
491
492       audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO, algo);
493
494       if (msgdigest)
495         { /* Signed attributes are available. */
496           gcry_md_hd_t md;
497           unsigned char *s;
498
499           /* Check that the message digest in the signed attributes
500              matches the one we calculated on the data.  */
501           s = gcry_md_read (data_md, algo);
502           if ( !s || !msgdigestlen
503                || gcry_md_get_algo_dlen (algo) != msgdigestlen
504                || memcmp (s, msgdigest, msgdigestlen) )
505             {
506               char *fpr;
507
508               log_error (_("invalid signature: message digest attribute "
509                            "does not match computed one\n"));
510               if (DBG_X509)
511                 {
512                   if (msgdigest)
513                     log_printhex ("message:  ", msgdigest, msgdigestlen);
514                   if (s)
515                     log_printhex ("computed: ",
516                                   s, gcry_md_get_algo_dlen (algo));
517                 }
518               fpr = gpgsm_fpr_and_name_for_status (cert);
519               gpgsm_status (ctrl, STATUS_BADSIG, fpr);
520               xfree (fpr);
521               audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
522               goto next_signer;
523             }
524
525           audit_log_i (ctrl->audit, AUDIT_ATTR_HASH_ALGO, sigval_hash_algo);
526           rc = gcry_md_open (&md, sigval_hash_algo, 0);
527           if (rc)
528             {
529               log_error ("md_open failed: %s\n", gpg_strerror (rc));
530               audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "error");
531               goto next_signer;
532             }
533           if (DBG_HASHING)
534             gcry_md_debug (md, "vrfy.attr");
535
536           ksba_cms_set_hash_function (cms, HASH_FNC, md);
537           rc = ksba_cms_hash_signed_attrs (cms, signer);
538           if (rc)
539             {
540               log_error ("hashing signed attrs failed: %s\n",
541                          gpg_strerror (rc));
542               gcry_md_close (md);
543               audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "error");
544               goto next_signer;
545             }
546           rc = gpgsm_check_cms_signature (cert, sigval, md,
547                                           sigval_hash_algo, &info_pkalgo);
548           gcry_md_close (md);
549         }
550       else
551         {
552           rc = gpgsm_check_cms_signature (cert, sigval, data_md,
553                                           algo, &info_pkalgo);
554         }
555
556       if (rc)
557         {
558           char *fpr;
559
560           log_error ("invalid signature: %s\n", gpg_strerror (rc));
561           fpr = gpgsm_fpr_and_name_for_status (cert);
562           gpgsm_status (ctrl, STATUS_BADSIG, fpr);
563           xfree (fpr);
564           audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
565           goto next_signer;
566         }
567       rc = gpgsm_cert_use_verify_p (cert); /*(this displays an info message)*/
568       if (rc)
569         {
570           gpgsm_status_with_err_code (ctrl, STATUS_ERROR, "verify.keyusage",
571                                       gpg_err_code (rc));
572           rc = 0;
573         }
574
575       if (DBG_X509)
576         log_debug ("signature okay - checking certs\n");
577       audit_log (ctrl->audit, AUDIT_VALIDATE_CHAIN);
578       rc = gpgsm_validate_chain (ctrl, cert,
579                                  *sigtime? sigtime : "19700101T000000",
580                                  keyexptime, 0,
581                                  NULL, 0, &verifyflags);
582       {
583         char *fpr, *buf, *tstr;
584
585         fpr = gpgsm_fpr_and_name_for_status (cert);
586         if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED)
587           {
588             gpgsm_status (ctrl, STATUS_EXPKEYSIG, fpr);
589             rc = 0;
590           }
591         else
592           gpgsm_status (ctrl, STATUS_GOODSIG, fpr);
593
594         xfree (fpr);
595
596         fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
597         tstr = strtimestamp_r (sigtime);
598         buf = xasprintf ("%s %s %s %s 0 0 %d %d 00", fpr, tstr,
599                          *sigtime? sigtime : "0",
600                          *keyexptime? keyexptime : "0",
601                          info_pkalgo, algo);
602         xfree (tstr);
603         xfree (fpr);
604         gpgsm_status (ctrl, STATUS_VALIDSIG, buf);
605         xfree (buf);
606       }
607
608       audit_log_ok (ctrl->audit, AUDIT_CHAIN_STATUS, rc);
609       if (rc) /* of validate_chain */
610         {
611           log_error ("invalid certification chain: %s\n", gpg_strerror (rc));
612           if (gpg_err_code (rc) == GPG_ERR_BAD_CERT_CHAIN
613               || gpg_err_code (rc) == GPG_ERR_BAD_CERT
614               || gpg_err_code (rc) == GPG_ERR_BAD_CA_CERT
615               || gpg_err_code (rc) == GPG_ERR_CERT_REVOKED)
616             gpgsm_status_with_err_code (ctrl, STATUS_TRUST_NEVER, NULL,
617                                         gpg_err_code (rc));
618           else
619             gpgsm_status_with_err_code (ctrl, STATUS_TRUST_UNDEFINED, NULL,
620                                         gpg_err_code (rc));
621           audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
622           goto next_signer;
623         }
624
625       audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "good");
626
627       for (i=0; (p = ksba_cert_get_subject (cert, i)); i++)
628         {
629           log_info (!i? _("Good signature from")
630                       : _("                aka"));
631           log_printf (" \"");
632           gpgsm_es_print_name (log_get_stream (), p);
633           log_printf ("\"\n");
634           ksba_free (p);
635         }
636
637       /* Print a note if this is a qualified signature.  */
638       {
639         size_t qualbuflen;
640         char qualbuffer[1];
641
642         rc = ksba_cert_get_user_data (cert, "is_qualified", &qualbuffer,
643                                       sizeof (qualbuffer), &qualbuflen);
644         if (!rc && qualbuflen)
645           {
646             if (*qualbuffer)
647               {
648                 log_info (_("This is a qualified signature\n"));
649                 if (!opt.qualsig_approval)
650                   log_info
651                     (_("Note, that this software is not officially approved "
652                        "to create or verify such signatures.\n"));
653               }
654           }
655         else if (gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
656           log_error ("get_user_data(is_qualified) failed: %s\n",
657                      gpg_strerror (rc));
658       }
659
660       gpgsm_status (ctrl, STATUS_TRUST_FULLY,
661                     (verifyflags & VALIDATE_FLAG_STEED)?
662                     "0 steed":
663                     (verifyflags & VALIDATE_FLAG_CHAIN_MODEL)?
664                     "0 chain": "0 shell");
665
666     next_signer:
667       rc = 0;
668       xfree (issuer);
669       xfree (serial);
670       xfree (sigval);
671       xfree (msgdigest);
672       ksba_cert_release (cert);
673       cert = NULL;
674     }
675   rc = 0;
676
677  leave:
678   ksba_cms_release (cms);
679   gnupg_ksba_destroy_reader (b64reader);
680   gnupg_ksba_destroy_writer (b64writer);
681   keydb_release (kh);
682   gcry_md_close (data_md);
683   es_fclose (in_fp);
684
685   if (rc)
686     {
687       char numbuf[50];
688       sprintf (numbuf, "%d", rc );
689       gpgsm_status2 (ctrl, STATUS_ERROR, "verify.leave",
690                      numbuf, NULL);
691     }
692
693   return rc;
694 }