qt: Handle diagnostic audit log for CMS
[gpgme.git] / src / sign.c
1 /* sign.c - Signing function.
2  * Copyright (C) 2000 Werner Koch (dd9jn)
3  * Copyright (C) 2001, 2002, 2003, 2004, 2007 g10 Code GmbH
4  *
5  * This file is part of GPGME.
6  *
7  * GPGME is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * GPGME is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, see <https://gnu.org/licenses/>.
19  * SPDX-License-Identifier: LGPL-2.1-or-later
20  */
21
22 #if HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28
29 /* Suppress warning for accessing deprecated member "class".  */
30 #define _GPGME_IN_GPGME 1
31 #include "gpgme.h"
32 #include "context.h"
33 #include "ops.h"
34 #include "util.h"
35 #include "debug.h"
36
37 \f
38 typedef struct
39 {
40   struct _gpgme_op_sign_result result;
41
42   /* The error code from a FAILURE status line or 0.  */
43   gpg_error_t failure_code;
44
45   /* The fingerprint from the last KEY_CONSIDERED status line.  */
46   char *kc_fpr;
47
48   /* The flags from the last KEY_CONSIDERED status line.  */
49   unsigned int kc_flags;
50
51   /* A pointer to the next pointer of the last invalid signer in
52      the list.  This makes appending new invalid signers painless
53      while preserving the order.  */
54   gpgme_invalid_key_t *last_signer_p;
55
56   /* Likewise for signature information.  */
57   gpgme_new_signature_t *last_sig_p;
58
59   /* Flags used while processing the status lines.  */
60   unsigned int ignore_inv_recp:1;
61   unsigned int inv_sgnr_seen:1;
62   unsigned int sig_created_seen:1;
63 } *op_data_t;
64
65
66 static void
67 release_signatures (gpgme_new_signature_t sig)
68 {
69   while (sig)
70     {
71       gpgme_new_signature_t next = sig->next;
72       free (sig->fpr);
73       free (sig);
74       sig = next;
75     }
76 }
77
78
79 static void
80 release_op_data (void *hook)
81 {
82   op_data_t opd = (op_data_t) hook;
83   gpgme_invalid_key_t invalid_signer = opd->result.invalid_signers;
84
85   while (invalid_signer)
86     {
87       gpgme_invalid_key_t next = invalid_signer->next;
88       if (invalid_signer->fpr)
89         free (invalid_signer->fpr);
90       free (invalid_signer);
91       invalid_signer = next;
92     }
93
94   release_signatures (opd->result.signatures);
95   free (opd->kc_fpr);
96 }
97
98
99 gpgme_sign_result_t
100 gpgme_op_sign_result (gpgme_ctx_t ctx)
101 {
102   void *hook;
103   op_data_t opd;
104   gpgme_error_t err;
105   gpgme_invalid_key_t inv_key, key;
106   gpgme_new_signature_t sig;
107   unsigned int inv_signers = 0;
108   unsigned int signatures = 0;
109
110   TRACE_BEG (DEBUG_CTX, "gpgme_op_sign_result", ctx, "");
111
112   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, -1, NULL);
113   opd = hook;
114   if (err || !opd)
115     {
116       TRACE_SUC ("result=(null)");
117       return NULL;
118     }
119
120   for (inv_key = opd->result.invalid_signers; inv_key; inv_key = inv_key->next)
121     inv_signers++;
122   for (sig = opd->result.signatures; sig; sig = sig->next)
123     signatures++;
124
125   if (gpgme_signers_count (ctx)
126       && signatures + inv_signers != gpgme_signers_count (ctx))
127     {
128       /* In this case at least one signatures was not created perhaps
129          due to a bad passphrase etc.  Thus the entire message is
130          broken and should not be used.  We add the already created
131          signatures to the invalid signers list and thus this case can
132          be detected.  */
133       TRACE_LOG  ("result: invalid signers: %u, signatures: %u, count: %u",
134                   inv_signers, signatures, gpgme_signers_count (ctx));
135
136       for (sig = opd->result.signatures; sig; sig = sig->next)
137         {
138           key = calloc (1, sizeof *key);
139           if (!key)
140             {
141               TRACE_SUC ("out of core; result=(null)");
142               return NULL;
143             }
144           if (sig->fpr)
145             {
146               key->fpr = strdup (sig->fpr);
147               if (!key->fpr)
148                 {
149                   free (key);
150                   TRACE_SUC ("out of core; result=(null)");
151                   return NULL;
152                 }
153             }
154           key->reason = GPG_ERR_GENERAL;
155
156           inv_key = opd->result.invalid_signers;
157           if (inv_key)
158             {
159               for (; inv_key->next; inv_key = inv_key->next)
160                 ;
161               inv_key->next = key;
162             }
163           else
164             opd->result.invalid_signers = key;
165         }
166
167       release_signatures (opd->result.signatures);
168       opd->result.signatures = NULL;
169     }
170
171   if (_gpgme_debug_trace())
172     {
173       TRACE_LOG  ("result: invalid signers: %i, signatures: %i",
174                   inv_signers, signatures);
175       for (inv_key=opd->result.invalid_signers; inv_key; inv_key=inv_key->next)
176         {
177           TRACE_LOG  ("result: invalid signer: fpr=%s, reason=%s <%s>",
178                       inv_key->fpr, gpgme_strerror (inv_key->reason),
179                       gpgme_strsource (inv_key->reason));
180         }
181       for (sig = opd->result.signatures; sig; sig = sig->next)
182         {
183           TRACE_LOG  ("result: signature: type=%i, pubkey_algo=%i, "
184                       "hash_algo=%i, timestamp=%li, fpr=%s, sig_class=%i",
185                       sig->type, sig->pubkey_algo, sig->hash_algo,
186                       sig->timestamp, sig->fpr, sig->sig_class);
187         }
188    }
189
190   TRACE_SUC ("result=%p", &opd->result);
191   return &opd->result;
192 }
193
194
195 \f
196 static gpgme_error_t
197 parse_sig_created (char *args, gpgme_new_signature_t *sigp,
198                    gpgme_protocol_t protocol)
199 {
200   gpgme_new_signature_t sig;
201   char *tail;
202
203   sig = malloc (sizeof (*sig));
204   if (!sig)
205     return gpg_error_from_syserror ();
206
207   sig->next = NULL;
208   switch (*args)
209     {
210     case 'S':
211       sig->type = GPGME_SIG_MODE_NORMAL;
212       break;
213
214     case 'D':
215       sig->type = GPGME_SIG_MODE_DETACH;
216       break;
217
218     case 'C':
219       sig->type = GPGME_SIG_MODE_CLEAR;
220       break;
221
222     default:
223       /* The backend engine is not behaving.  */
224       free (sig);
225       return trace_gpg_error (GPG_ERR_INV_ENGINE);
226     }
227
228   args++;
229   if (*args != ' ')
230     {
231       free (sig);
232       return trace_gpg_error (GPG_ERR_INV_ENGINE);
233     }
234
235   gpg_err_set_errno (0);
236   sig->pubkey_algo = _gpgme_map_pk_algo (strtol (args, &tail, 0), protocol);
237   if (errno || args == tail || *tail != ' ')
238     {
239       /* The crypto backend does not behave.  */
240       free (sig);
241       return trace_gpg_error (GPG_ERR_INV_ENGINE);
242     }
243   args = tail;
244
245   sig->hash_algo = strtol (args, &tail, 0);
246   if (errno || args == tail || *tail != ' ')
247     {
248       /* The crypto backend does not behave.  */
249       free (sig);
250       return trace_gpg_error (GPG_ERR_INV_ENGINE);
251     }
252   args = tail;
253
254   sig->sig_class = strtol (args, &tail, 0);
255   sig->class = sig->sig_class;
256   sig->_obsolete_class = sig->sig_class;
257   if (errno || args == tail || *tail != ' ')
258     {
259       /* The crypto backend does not behave.  */
260       free (sig);
261       return trace_gpg_error (GPG_ERR_INV_ENGINE);
262     }
263   args = tail;
264
265   sig->timestamp = _gpgme_parse_timestamp (args, &tail);
266   if (sig->timestamp == -1 || args == tail || *tail != ' ')
267     {
268       /* The crypto backend does not behave.  */
269       free (sig);
270       return trace_gpg_error (GPG_ERR_INV_ENGINE);
271     }
272   args = tail;
273   while (*args == ' ')
274     args++;
275
276   if (!*args)
277     {
278       /* The crypto backend does not behave.  */
279       free (sig);
280       return trace_gpg_error (GPG_ERR_INV_ENGINE);
281     }
282
283   tail = strchr (args, ' ');
284   if (tail)
285     *tail = '\0';
286
287   sig->fpr = strdup (args);
288   if (!sig->fpr)
289     {
290       free (sig);
291       return gpg_error_from_syserror ();
292     }
293   *sigp = sig;
294   return 0;
295 }
296
297
298 gpgme_error_t
299 _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
300 {
301   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
302   gpgme_error_t err;
303   void *hook;
304   op_data_t opd;
305
306   err = _gpgme_passphrase_status_handler (priv, code, args);
307   if (err)
308     return err;
309
310   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, -1, NULL);
311   opd = hook;
312   if (err)
313     return err;
314
315   switch (code)
316     {
317     case GPGME_STATUS_SIG_CREATED:
318       opd->sig_created_seen = 1;
319       err = parse_sig_created (args, opd->last_sig_p, ctx->protocol);
320       if (err)
321         return err;
322
323       opd->last_sig_p = &(*opd->last_sig_p)->next;
324       break;
325
326     case GPGME_STATUS_KEY_CONSIDERED:
327       /* This is emitted during gpg's key lookup to give information
328        * about the lookup results.  We store the last one so it can be
329        * used in connection with INV_RECP.  */
330       free (opd->kc_fpr);
331       opd->kc_fpr = NULL;
332       err = _gpgme_parse_key_considered (args, &opd->kc_fpr, &opd->kc_flags);
333       if (err)
334         return err;
335       break;
336
337     case GPGME_STATUS_INV_RECP:
338       if (opd->inv_sgnr_seen && opd->ignore_inv_recp)
339         break;
340       /* FALLTHROUGH */
341     case GPGME_STATUS_INV_SGNR:
342       if (code == GPGME_STATUS_INV_SGNR)
343         opd->inv_sgnr_seen = 1;
344       free (opd->kc_fpr);
345       opd->kc_fpr = NULL;
346       err = _gpgme_parse_inv_recp (args, 1, opd->kc_fpr, opd->kc_flags,
347                                    opd->last_signer_p);
348       if (err)
349         return err;
350
351       opd->last_signer_p = &(*opd->last_signer_p)->next;
352       free (opd->kc_fpr);
353       opd->kc_fpr = NULL;
354       break;
355
356     case GPGME_STATUS_FAILURE:
357       opd->failure_code = _gpgme_parse_failure (args);
358       break;
359
360     case GPGME_STATUS_EOF:
361       /* The UI server does not send information about the created
362          signature.  This is irrelevant for this protocol and thus we
363          should not check for that.  */
364       if (opd->result.invalid_signers)
365         err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
366       else if (!opd->sig_created_seen
367                && ctx->protocol != GPGME_PROTOCOL_UISERVER)
368         err = opd->failure_code? opd->failure_code:gpg_error (GPG_ERR_GENERAL);
369       break;
370
371     case GPGME_STATUS_INQUIRE_MAXLEN:
372       if (ctx->status_cb && !ctx->full_status)
373         err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
374       break;
375
376     default:
377       break;
378     }
379   return err;
380 }
381
382
383 static gpgme_error_t
384 sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
385 {
386   gpgme_error_t err;
387
388   err = _gpgme_progress_status_handler (priv, code, args);
389   if (!err)
390     err = _gpgme_sign_status_handler (priv, code, args);
391   return err;
392 }
393
394
395 static gpgme_error_t
396 sign_init_result (gpgme_ctx_t ctx, int ignore_inv_recp)
397 {
398   gpgme_error_t err;
399   void *hook;
400   op_data_t opd;
401
402   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook,
403                                sizeof (*opd), release_op_data);
404   opd = hook;
405   if (err)
406     return err;
407   opd->failure_code = 0;
408   opd->last_signer_p = &opd->result.invalid_signers;
409   opd->last_sig_p = &opd->result.signatures;
410   opd->ignore_inv_recp = !!ignore_inv_recp;
411   opd->inv_sgnr_seen = 0;
412   opd->sig_created_seen = 0;
413   return 0;
414 }
415
416 gpgme_error_t
417 _gpgme_op_sign_init_result (gpgme_ctx_t ctx)
418 {
419   return sign_init_result (ctx, 0);
420 }
421
422
423 static gpgme_error_t
424 sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t plain,
425             gpgme_data_t sig, gpgme_sig_mode_t mode)
426 {
427   gpgme_error_t err;
428
429   err = _gpgme_op_reset (ctx, synchronous);
430   if (err)
431     return err;
432
433   /* If we are using the CMS protocol, we ignore the INV_RECP status
434      code if a newer GPGSM is in use.  GPGMS does not support combined
435      sign+encrypt and thus this can't harm.  */
436   err = sign_init_result (ctx, (ctx->protocol == GPGME_PROTOCOL_CMS));
437   if (err)
438     return err;
439
440   if (mode != GPGME_SIG_MODE_NORMAL && mode != GPGME_SIG_MODE_DETACH
441       && mode != GPGME_SIG_MODE_CLEAR)
442     return gpg_error (GPG_ERR_INV_VALUE);
443
444   if (!plain)
445     return gpg_error (GPG_ERR_NO_DATA);
446   if (!sig)
447     return gpg_error (GPG_ERR_INV_VALUE);
448
449   if (ctx->passphrase_cb)
450     {
451       err = _gpgme_engine_set_command_handler
452         (ctx->engine, _gpgme_passphrase_command_handler, ctx);
453       if (err)
454         return err;
455     }
456
457   _gpgme_engine_set_status_handler (ctx->engine, sign_status_handler,
458                                     ctx);
459
460   return _gpgme_engine_op_sign (ctx->engine, plain, sig, mode, ctx->use_armor,
461                                 ctx->use_textmode, ctx->include_certs,
462                                 ctx /* FIXME */);
463 }
464
465
466 /* Sign the plaintext PLAIN and store the signature in SIG.  */
467 gpgme_error_t
468 gpgme_op_sign_start (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
469                      gpgme_sig_mode_t mode)
470 {
471   gpg_error_t err;
472   TRACE_BEG  (DEBUG_CTX, "gpgme_op_sign_start", ctx,
473               "plain=%p, sig=%p, mode=%i", plain, sig, mode);
474
475   if (!ctx)
476     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
477
478   err = sign_start (ctx, 0, plain, sig, mode);
479   return TRACE_ERR (err);
480 }
481
482
483 /* Sign the plaintext PLAIN and store the signature in SIG.  */
484 gpgme_error_t
485 gpgme_op_sign (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
486                gpgme_sig_mode_t mode)
487 {
488   gpgme_error_t err;
489
490   TRACE_BEG  (DEBUG_CTX, "gpgme_op_sign", ctx,
491               "plain=%p, sig=%p, mode=%i", plain, sig, mode);
492
493   if (!ctx)
494     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
495
496   err = sign_start (ctx, 1, plain, sig, mode);
497   if (!err)
498     err = _gpgme_wait_one (ctx);
499   return TRACE_ERR (err);
500 }