e42eb6bfe529bac3bbcb437539568ec89f8fecbf
[platform/upstream/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          "  --auto-key-import\n"
238          , stderr);
239   exit (ex);
240 }
241
242
243 int
244 main (int argc, char **argv)
245 {
246   int last_argc = -1;
247   const char *s;
248   gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
249   int print_status = 0;
250   const char *sender = NULL;
251   int auto_key_retrieve = 0;
252   int auto_key_import = 0;
253   int repeats = 1;
254
255   if (argc)
256     { argc--; argv++; }
257
258   while (argc && last_argc != argc )
259     {
260       last_argc = argc;
261       if (!strcmp (*argv, "--"))
262         {
263           argc--; argv++;
264           break;
265         }
266       else if (!strcmp (*argv, "--help"))
267         show_usage (0);
268       else if (!strcmp (*argv, "--verbose"))
269         {
270           verbose = 1;
271           argc--; argv++;
272         }
273       else if (!strcmp (*argv, "--status"))
274         {
275           print_status = 1;
276           argc--; argv++;
277         }
278       else if (!strcmp (*argv, "--openpgp"))
279         {
280           protocol = GPGME_PROTOCOL_OpenPGP;
281           argc--; argv++;
282         }
283       else if (!strcmp (*argv, "--cms"))
284         {
285           protocol = GPGME_PROTOCOL_CMS;
286           argc--; argv++;
287         }
288       else if (!strcmp (*argv, "--sender"))
289         {
290           argc--; argv++;
291           if (!argc)
292             show_usage (1);
293           sender = *argv;
294           argc--; argv++;
295         }
296       else if (!strcmp (*argv, "--repeat"))
297         {
298             argc--; argv++;
299             if (!argc)
300                 show_usage (1);
301             repeats = atoi (*argv);
302             argc--; argv++;
303         }
304       else if (!strcmp (*argv, "--auto-key-retrieve"))
305         {
306           auto_key_retrieve = 1;
307           argc--; argv++;
308         }
309       else if (!strcmp (*argv, "--auto-key-import"))
310         {
311           auto_key_import = 1;
312           argc--; argv++;
313         }
314       else if (!strncmp (*argv, "--", 2))
315         show_usage (1);
316
317     }
318
319   if (argc < 1 || argc > 2)
320     show_usage (1);
321
322   init_gpgme (protocol);
323
324   for (int i = 0; i < repeats; i++)
325     {
326       gpgme_error_t err;
327       gpgme_ctx_t ctx;
328       FILE *fp_sig = NULL;
329       gpgme_data_t sig = NULL;
330       FILE *fp_msg = NULL;
331       gpgme_data_t msg = NULL;
332       gpgme_verify_result_t result;
333
334       if (repeats > 1)
335         {
336           printf ("Repeat: %i\n", i);
337         }
338
339       fp_sig = fopen (argv[0], "rb");
340       if (!fp_sig)
341         {
342           err = gpgme_error_from_syserror ();
343           fprintf (stderr, PGM ": can't open `%s': %s\n",
344                    argv[0], gpgme_strerror (err));
345           exit (1);
346         }
347       if (argc > 1)
348         {
349           fp_msg = fopen (argv[1], "rb");
350           if (!fp_msg)
351             {
352               err = gpgme_error_from_syserror ();
353               fprintf (stderr, PGM ": can't open `%s': %s\n",
354                        argv[1], gpgme_strerror (err));
355               exit (1);
356             }
357         }
358
359       err = gpgme_new (&ctx);
360       fail_if_err (err);
361       gpgme_set_protocol (ctx, protocol);
362       if (print_status)
363         {
364           gpgme_set_status_cb (ctx, status_cb, NULL);
365           gpgme_set_ctx_flag (ctx, "full-status", "1");
366         }
367       /* gpgme_set_ctx_flag (ctx, "raw-description", "1"); */
368
369       if (auto_key_retrieve)
370         {
371           gpgme_set_ctx_flag (ctx, "auto-key-retrieve", "1");
372           s = gpgme_get_ctx_flag (ctx, "auto-key-retrieve");
373           if (!s || strcmp (s, "1"))
374             {
375               fprintf (stderr, PGM ": gpgme_get_ctx_flag failed for '%s'\n",
376                        "auto-key-retrieve");
377               exit (1);
378             }
379         }
380
381       if (auto_key_import)
382         {
383           gpgme_set_ctx_flag (ctx, "auto-key-import", "1");
384           s = gpgme_get_ctx_flag (ctx, "auto-key-import");
385           if (!s || strcmp (s, "1"))
386             {
387               fprintf (stderr, PGM ": gpgme_get_ctx_flag failed for '%s'\n",
388                        "auto-key-import");
389               exit (1);
390             }
391         }
392
393       if (sender)
394         {
395           err = gpgme_set_sender (ctx, sender);
396           fail_if_err (err);
397         }
398
399       err = gpgme_data_new_from_stream (&sig, fp_sig);
400       if (err)
401         {
402           fprintf (stderr, PGM ": error allocating data object: %s\n",
403                    gpgme_strerror (err));
404           exit (1);
405         }
406       if (fp_msg)
407         {
408           err = gpgme_data_new_from_stream (&msg, fp_msg);
409           if (err)
410             {
411               fprintf (stderr, PGM ": error allocating data object: %s\n",
412                        gpgme_strerror (err));
413               exit (1);
414             }
415         }
416
417       err = gpgme_op_verify (ctx, sig, msg, NULL);
418       result = gpgme_op_verify_result (ctx);
419       if (result)
420         print_result (result);
421       if (err)
422         {
423           fprintf (stderr, PGM ": verify failed: %s\n", gpgme_strerror (err));
424           exit (1);
425         }
426
427       gpgme_data_release (msg);
428       gpgme_data_release (sig);
429
430       gpgme_release (ctx);
431
432       if (fp_msg)
433         fclose (fp_msg);
434       if (fp_sig)
435         fclose (fp_sig);
436     }
437   return 0;
438 }