cpp: Add wrapper for gpgme_set_global_flag
[gpgme.git] / tests / run-verify.c
1 /* run-verify.c  - Helper to perform a verify operation
2  * Copyright (C) 2009 g10 Code GmbH
3  *
4  * This file is part of GPGME.
5  *
6  * GPGME is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * GPGME is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <https://gnu.org/licenses/>.
18  * SPDX-License-Identifier: LGPL-2.1-or-later
19  */
20
21 /* We need to include config.h so that we know whether we are building
22    with large file system (LFS) support. */
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <time.h>
31
32 #include <gpgme.h>
33
34 #define PGM "run-verify"
35
36 #include "run-support.h"
37
38
39 static int verbose;
40
41
42 static const char *
43 isotimestr (unsigned long value)
44 {
45   time_t t;
46   static char buffer[25+5];
47   struct tm *tp;
48
49   if (!value)
50     return "none";
51   t = value;
52
53   tp = gmtime (&t);
54   snprintf (buffer, sizeof buffer, "%04d-%02d-%02d %02d:%02d:%02d",
55             1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
56             tp->tm_hour, tp->tm_min, tp->tm_sec);
57   return buffer;
58 }
59
60
61 static gpg_error_t
62 status_cb (void *opaque, const char *keyword, const char *value)
63 {
64   (void)opaque;
65   fprintf (stderr, "status_cb: %s %s\n", keyword, value);
66   return 0;
67 }
68
69
70 static void
71 print_summary (gpgme_sigsum_t summary)
72 {
73   if ( (summary & GPGME_SIGSUM_VALID      ))
74     fputs (" valid", stdout);
75   if ( (summary & GPGME_SIGSUM_GREEN      ))
76     fputs (" green", stdout);
77   if ( (summary & GPGME_SIGSUM_RED        ))
78     fputs (" red", stdout);
79   if ( (summary & GPGME_SIGSUM_KEY_REVOKED))
80     fputs (" revoked", stdout);
81   if ( (summary & GPGME_SIGSUM_KEY_EXPIRED))
82     fputs (" key-expired", stdout);
83   if ( (summary & GPGME_SIGSUM_SIG_EXPIRED))
84     fputs (" sig-expired", stdout);
85   if ( (summary & GPGME_SIGSUM_KEY_MISSING))
86     fputs (" key-missing", stdout);
87   if ( (summary & GPGME_SIGSUM_CRL_MISSING))
88     fputs (" crl-missing", stdout);
89   if ( (summary & GPGME_SIGSUM_CRL_TOO_OLD))
90     fputs (" crl-too-old", stdout);
91   if ( (summary & GPGME_SIGSUM_BAD_POLICY ))
92     fputs (" bad-policy", stdout);
93   if ( (summary & GPGME_SIGSUM_SYS_ERROR  ))
94     fputs (" sys-error", stdout);
95 }
96
97 static void
98 print_validity (gpgme_validity_t val)
99 {
100   const char *s = NULL;
101
102   switch (val)
103     {
104     case GPGME_VALIDITY_UNKNOWN:  s = "unknown"; break;
105     case GPGME_VALIDITY_UNDEFINED:s = "undefined"; break;
106     case GPGME_VALIDITY_NEVER:    s = "never"; break;
107     case GPGME_VALIDITY_MARGINAL: s = "marginal"; break;
108     case GPGME_VALIDITY_FULL:     s = "full"; break;
109     case GPGME_VALIDITY_ULTIMATE: s = "ultimate"; break;
110     }
111   if (s)
112     fputs (s, stdout);
113   else
114     printf ("[bad validity value %u]", (unsigned int)val);
115 }
116
117
118 static void
119 print_description (const char *text, int indent)
120 {
121   for (; *text; text++)
122     {
123       putchar (*text);
124       if (*text == '\n')
125         printf ("%*s", indent, "");
126     }
127   putchar ('\n');
128 }
129
130
131 static void
132 print_result (gpgme_verify_result_t result)
133 {
134   gpgme_signature_t sig;
135   gpgme_sig_notation_t nt;
136   gpgme_user_id_t uid;
137   gpgme_tofu_info_t ti;
138   int count = 0;
139
140   printf ("Original file name .: %s\n", nonnull(result->file_name));
141   printf ("MIME flag ..........: %s\n", result->is_mime? "yes":"no");
142   for (sig = result->signatures; sig; sig = sig->next)
143     {
144       printf ("Signature ...: %d\n", count++);
145       printf ("  status ....: %s\n", gpgme_strerror (sig->status));
146       printf ("  summary ...:"); print_summary (sig->summary); putchar ('\n');
147       printf ("  fingerprint: %s\n", nonnull (sig->fpr));
148       printf ("  created ...: %lu\n", sig->timestamp);
149       printf ("  expires ...: %lu\n", sig->exp_timestamp);
150       printf ("  validity ..: ");
151       print_validity (sig->validity); putchar ('\n');
152       printf ("  val.reason : %s\n", gpgme_strerror (sig->status));
153       printf ("  pubkey algo: %d (%s)\n", sig->pubkey_algo,
154               nonnull(gpgme_pubkey_algo_name (sig->pubkey_algo)));
155       printf ("  digest algo: %d (%s)\n", sig->hash_algo,
156               nonnull(gpgme_hash_algo_name (sig->hash_algo)));
157       printf ("  pka address: %s\n", nonnull (sig->pka_address));
158       printf ("  pka trust .: %s\n",
159               sig->pka_trust == 0? "n/a" :
160               sig->pka_trust == 1? "bad" :
161               sig->pka_trust == 2? "okay": "RFU");
162       printf ("  other flags:%s%s%s\n",
163               sig->wrong_key_usage? " wrong-key-usage":"",
164               sig->chain_model? " chain-model":"",
165               sig->is_de_vs? " de-vs":""
166               );
167       for (nt = sig->notations; nt; nt = nt->next)
168         {
169           if (nt->name)
170             {
171               printf ("  notation ..: '%s'\n", nt->name);
172               if (strlen (nt->name) != nt->name_len)
173                 printf ("    warning .: name larger (%d)\n", nt->name_len);
174               printf ("    flags ...:%s%s (0x%02x)\n",
175                       nt->critical? " critical":"",
176                       nt->human_readable? " human":"",
177                       nt->flags);
178               if (nt->value)
179                 printf ("    value ...: '%s'\n", nt->value);
180             }
181           else
182             {
183               printf ("  policy ....: '%s'\n", nt->value);
184             }
185           if ((nt->value?strlen (nt->value):0) != nt->value_len)
186             printf ("    warning .: value larger (%d)\n", nt->value_len);
187         }
188       if (sig->key)
189         {
190           printf ("  primary fpr: %s\n", nonnull (sig->key->fpr));
191           for (uid = sig->key->uids; uid; uid = uid->next)
192             {
193               printf ("  tofu addr .: %s\n", nonnull (uid->address));
194               ti = uid->tofu;
195               if (!ti)
196                 continue;
197               printf ("    validity : %u (%s)\n", ti->validity,
198                       ti->validity == 0? "conflict" :
199                       ti->validity == 1? "no history" :
200                       ti->validity == 2? "little history" :
201                       ti->validity == 3? "enough history" :
202                       ti->validity == 4? "lot of history" : "?");
203               printf ("    policy ..: %u (%s)\n", ti->policy,
204                       ti->policy == GPGME_TOFU_POLICY_NONE? "none" :
205                       ti->policy == GPGME_TOFU_POLICY_AUTO? "auto" :
206                       ti->policy == GPGME_TOFU_POLICY_GOOD? "good" :
207                       ti->policy == GPGME_TOFU_POLICY_UNKNOWN? "unknown" :
208                       ti->policy == GPGME_TOFU_POLICY_BAD? "bad" :
209                       ti->policy == GPGME_TOFU_POLICY_ASK? "ask" : "?");
210               printf ("    signcount: %hu\n", ti->signcount);
211               printf ("      first..: %s\n", isotimestr (ti->signfirst));
212               printf ("      last ..: %s\n", isotimestr (ti->signlast));
213               printf ("    encrcount: %hu\n", ti->encrcount);
214               printf ("      first..: %s\n", isotimestr (ti->encrfirst));
215               printf ("      last ..: %s\n", isotimestr (ti->encrlast));
216               printf ("    desc ....: ");
217               print_description (nonnull (ti->description), 15);
218             }
219         }
220     }
221 }
222
223
224
225 static int
226 show_usage (int ex)
227 {
228   fputs ("usage: " PGM " [options] [DETACHEDSIGFILE] FILE\n\n"
229          "Options:\n"
230          "  --verbose        run in verbose mode\n"
231          "  --status         print status lines from the backend\n"
232          "  --openpgp        use the OpenPGP protocol (default)\n"
233          "  --cms            use the CMS protocol\n"
234          "  --sender MBOX    use MBOX as sender address\n"
235          "  --repeat N       repeat the operation N times\n"
236          "  --auto-key-retrieve\n"
237          , stderr);
238   exit (ex);
239 }
240
241
242 int
243 main (int argc, char **argv)
244 {
245   int last_argc = -1;
246   const char *s;
247   gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
248   int print_status = 0;
249   const char *sender = NULL;
250   int auto_key_retrieve = 0;
251   int repeats = 1;
252
253   if (argc)
254     { argc--; argv++; }
255
256   while (argc && last_argc != argc )
257     {
258       last_argc = argc;
259       if (!strcmp (*argv, "--"))
260         {
261           argc--; argv++;
262           break;
263         }
264       else if (!strcmp (*argv, "--help"))
265         show_usage (0);
266       else if (!strcmp (*argv, "--verbose"))
267         {
268           verbose = 1;
269           argc--; argv++;
270         }
271       else if (!strcmp (*argv, "--status"))
272         {
273           print_status = 1;
274           argc--; argv++;
275         }
276       else if (!strcmp (*argv, "--openpgp"))
277         {
278           protocol = GPGME_PROTOCOL_OpenPGP;
279           argc--; argv++;
280         }
281       else if (!strcmp (*argv, "--cms"))
282         {
283           protocol = GPGME_PROTOCOL_CMS;
284           argc--; argv++;
285         }
286       else if (!strcmp (*argv, "--sender"))
287         {
288           argc--; argv++;
289           if (!argc)
290             show_usage (1);
291           sender = *argv;
292           argc--; argv++;
293         }
294       else if (!strcmp (*argv, "--repeat"))
295         {
296             argc--; argv++;
297             if (!argc)
298                 show_usage (1);
299             repeats = atoi (*argv);
300             argc--; argv++;
301         }
302       else if (!strcmp (*argv, "--auto-key-retrieve"))
303         {
304           auto_key_retrieve = 1;
305           argc--; argv++;
306         }
307
308       else if (!strncmp (*argv, "--", 2))
309         show_usage (1);
310
311     }
312
313   if (argc < 1 || argc > 2)
314     show_usage (1);
315
316   init_gpgme (protocol);
317
318   for (int i = 0; i < repeats; i++)
319     {
320       gpgme_error_t err;
321       gpgme_ctx_t ctx;
322       FILE *fp_sig = NULL;
323       gpgme_data_t sig = NULL;
324       FILE *fp_msg = NULL;
325       gpgme_data_t msg = NULL;
326       gpgme_verify_result_t result;
327
328       if (repeats > 1)
329         {
330           printf ("Repeat: %i\n", i);
331         }
332
333       fp_sig = fopen (argv[0], "rb");
334       if (!fp_sig)
335         {
336           err = gpgme_error_from_syserror ();
337           fprintf (stderr, PGM ": can't open `%s': %s\n",
338                    argv[0], gpgme_strerror (err));
339           exit (1);
340         }
341       if (argc > 1)
342         {
343           fp_msg = fopen (argv[1], "rb");
344           if (!fp_msg)
345             {
346               err = gpgme_error_from_syserror ();
347               fprintf (stderr, PGM ": can't open `%s': %s\n",
348                        argv[1], gpgme_strerror (err));
349               exit (1);
350             }
351         }
352
353       err = gpgme_new (&ctx);
354       fail_if_err (err);
355       gpgme_set_protocol (ctx, protocol);
356       if (print_status)
357         {
358           gpgme_set_status_cb (ctx, status_cb, NULL);
359           gpgme_set_ctx_flag (ctx, "full-status", "1");
360         }
361       /* gpgme_set_ctx_flag (ctx, "raw-description", "1"); */
362
363       if (auto_key_retrieve)
364         {
365           gpgme_set_ctx_flag (ctx, "auto-key-retrieve", "1");
366           s = gpgme_get_ctx_flag (ctx, "auto-key-retrieve");
367           if (!s || strcmp (s, "1"))
368             {
369               fprintf (stderr, PGM ": gpgme_get_ctx_flag failed for '%s'\n",
370                        "auto-key-retrieve");
371               exit (1);
372             }
373         }
374
375       if (sender)
376         {
377           err = gpgme_set_sender (ctx, sender);
378           fail_if_err (err);
379         }
380
381       err = gpgme_data_new_from_stream (&sig, fp_sig);
382       if (err)
383         {
384           fprintf (stderr, PGM ": error allocating data object: %s\n",
385                    gpgme_strerror (err));
386           exit (1);
387         }
388       if (fp_msg)
389         {
390           err = gpgme_data_new_from_stream (&msg, fp_msg);
391           if (err)
392             {
393               fprintf (stderr, PGM ": error allocating data object: %s\n",
394                        gpgme_strerror (err));
395               exit (1);
396             }
397         }
398
399       err = gpgme_op_verify (ctx, sig, msg, NULL);
400       result = gpgme_op_verify_result (ctx);
401       if (result)
402         print_result (result);
403       if (err)
404         {
405           fprintf (stderr, PGM ": verify failed: %s\n", gpgme_strerror (err));
406           exit (1);
407         }
408
409       gpgme_data_release (msg);
410       gpgme_data_release (sig);
411
412       gpgme_release (ctx);
413
414       if (fp_msg)
415         fclose (fp_msg);
416       if (fp_sig)
417         fclose (fp_sig);
418     }
419   return 0;
420 }