Improve error return by checking the FAILURE status.
[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, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20    02111-1307, USA.  */
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   /* A pointer to the next pointer of the last invalid signer in
46      the list.  This makes appending new invalid signers painless
47      while preserving the order.  */
48   gpgme_invalid_key_t *last_signer_p;
49
50   /* Likewise for signature information.  */
51   gpgme_new_signature_t *last_sig_p;
52
53   /* Flags used while processing the status lines.  */
54   unsigned int ignore_inv_recp:1;
55   unsigned int inv_sgnr_seen:1;
56   unsigned int sig_created_seen:1;
57 } *op_data_t;
58
59
60 static void
61 release_signatures (gpgme_new_signature_t sig)
62 {
63   while (sig)
64     {
65       gpgme_new_signature_t next = sig->next;
66       free (sig->fpr);
67       free (sig);
68       sig = next;
69     }
70 }
71
72
73 static void
74 release_op_data (void *hook)
75 {
76   op_data_t opd = (op_data_t) hook;
77   gpgme_invalid_key_t invalid_signer = opd->result.invalid_signers;
78
79   while (invalid_signer)
80     {
81       gpgme_invalid_key_t next = invalid_signer->next;
82       if (invalid_signer->fpr)
83         free (invalid_signer->fpr);
84       free (invalid_signer);
85       invalid_signer = next;
86     }
87
88   release_signatures (opd->result.signatures);
89 }
90
91
92 gpgme_sign_result_t
93 gpgme_op_sign_result (gpgme_ctx_t ctx)
94 {
95   void *hook;
96   op_data_t opd;
97   gpgme_error_t err;
98   gpgme_invalid_key_t inv_key, key;
99   gpgme_new_signature_t sig;
100   unsigned int inv_signers = 0;
101   unsigned int signatures = 0;
102
103   TRACE_BEG (DEBUG_CTX, "gpgme_op_sign_result", ctx);
104
105   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, -1, NULL);
106   opd = hook;
107   if (err || !opd)
108     {
109       TRACE_SUC0 ("result=(null)");
110       return NULL;
111     }
112
113   for (inv_key = opd->result.invalid_signers; inv_key; inv_key = inv_key->next)
114     inv_signers++;
115   for (sig = opd->result.signatures; sig; sig = sig->next)
116     signatures++;
117
118   if (gpgme_signers_count (ctx)
119       && signatures + inv_signers != gpgme_signers_count (ctx))
120     {
121       /* In this case at least one signatures was not created perhaps
122          due to a bad passphrase etc.  Thus the entire message is
123          broken and should not be used.  We add the already created
124          signatures to the invalid signers list and thus this case can
125          be detected.  */
126       TRACE_LOG3 ("result: invalid signers: %u, signatures: %u, count: %u",
127                   inv_signers, signatures, gpgme_signers_count (ctx));
128
129       for (sig = opd->result.signatures; sig; sig = sig->next)
130         {
131           key = calloc (1, sizeof *key);
132           if (!key)
133             {
134               TRACE_SUC0 ("out of core; result=(null)");
135               return NULL;
136             }
137           if (sig->fpr)
138             {
139               key->fpr = strdup (sig->fpr);
140               if (!key->fpr)
141                 {
142                   free (key);
143                   TRACE_SUC0 ("out of core; result=(null)");
144                   return NULL;
145                 }
146             }
147           key->reason = GPG_ERR_GENERAL;
148
149           inv_key = opd->result.invalid_signers;
150           if (inv_key)
151             {
152               for (; inv_key->next; inv_key = inv_key->next)
153                 ;
154               inv_key->next = key;
155             }
156           else
157             opd->result.invalid_signers = key;
158         }
159
160       release_signatures (opd->result.signatures);
161       opd->result.signatures = NULL;
162     }
163
164   if (_gpgme_debug_trace())
165     {
166       TRACE_LOG2 ("result: invalid signers: %i, signatures: %i",
167                   inv_signers, signatures);
168       for (inv_key=opd->result.invalid_signers; inv_key; inv_key=inv_key->next)
169         {
170           TRACE_LOG3 ("result: invalid signer: fpr=%s, reason=%s <%s>",
171                       inv_key->fpr, gpgme_strerror (inv_key->reason),
172                       gpgme_strsource (inv_key->reason));
173         }
174       for (sig = opd->result.signatures; sig; sig = sig->next)
175         {
176           TRACE_LOG6 ("result: signature: type=%i, pubkey_algo=%i, "
177                       "hash_algo=%i, timestamp=%li, fpr=%s, sig_class=%i",
178                       sig->type, sig->pubkey_algo, sig->hash_algo,
179                       sig->timestamp, sig->fpr, sig->sig_class);
180         }
181    }
182
183   TRACE_SUC1 ("result=%p", &opd->result);
184   return &opd->result;
185 }
186
187
188 \f
189 static gpgme_error_t
190 parse_sig_created (char *args, gpgme_new_signature_t *sigp,
191                    gpgme_protocol_t protocol)
192 {
193   gpgme_new_signature_t sig;
194   char *tail;
195
196   sig = malloc (sizeof (*sig));
197   if (!sig)
198     return gpg_error_from_syserror ();
199
200   sig->next = NULL;
201   switch (*args)
202     {
203     case 'S':
204       sig->type = GPGME_SIG_MODE_NORMAL;
205       break;
206
207     case 'D':
208       sig->type = GPGME_SIG_MODE_DETACH;
209       break;
210
211     case 'C':
212       sig->type = GPGME_SIG_MODE_CLEAR;
213       break;
214
215     default:
216       /* The backend engine is not behaving.  */
217       free (sig);
218       return trace_gpg_error (GPG_ERR_INV_ENGINE);
219     }
220
221   args++;
222   if (*args != ' ')
223     {
224       free (sig);
225       return trace_gpg_error (GPG_ERR_INV_ENGINE);
226     }
227
228   gpg_err_set_errno (0);
229   sig->pubkey_algo = _gpgme_map_pk_algo (strtol (args, &tail, 0), protocol);
230   if (errno || args == tail || *tail != ' ')
231     {
232       /* The crypto backend does not behave.  */
233       free (sig);
234       return trace_gpg_error (GPG_ERR_INV_ENGINE);
235     }
236   args = tail;
237
238   sig->hash_algo = strtol (args, &tail, 0);
239   if (errno || args == tail || *tail != ' ')
240     {
241       /* The crypto backend does not behave.  */
242       free (sig);
243       return trace_gpg_error (GPG_ERR_INV_ENGINE);
244     }
245   args = tail;
246
247   sig->sig_class = strtol (args, &tail, 0);
248   sig->class = sig->sig_class;
249   sig->_obsolete_class = sig->sig_class;
250   if (errno || args == tail || *tail != ' ')
251     {
252       /* The crypto backend does not behave.  */
253       free (sig);
254       return trace_gpg_error (GPG_ERR_INV_ENGINE);
255     }
256   args = tail;
257
258   sig->timestamp = _gpgme_parse_timestamp (args, &tail);
259   if (sig->timestamp == -1 || args == tail || *tail != ' ')
260     {
261       /* The crypto backend does not behave.  */
262       free (sig);
263       return trace_gpg_error (GPG_ERR_INV_ENGINE);
264     }
265   args = tail;
266   while (*args == ' ')
267     args++;
268
269   if (!*args)
270     {
271       /* The crypto backend does not behave.  */
272       free (sig);
273       return trace_gpg_error (GPG_ERR_INV_ENGINE);
274     }
275
276   tail = strchr (args, ' ');
277   if (tail)
278     *tail = '\0';
279
280   sig->fpr = strdup (args);
281   if (!sig->fpr)
282     {
283       free (sig);
284       return gpg_error_from_syserror ();
285     }
286   *sigp = sig;
287   return 0;
288 }
289
290
291 gpgme_error_t
292 _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
293 {
294   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
295   gpgme_error_t err;
296   void *hook;
297   op_data_t opd;
298
299   err = _gpgme_passphrase_status_handler (priv, code, args);
300   if (err)
301     return err;
302
303   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, -1, NULL);
304   opd = hook;
305   if (err)
306     return err;
307
308   switch (code)
309     {
310     case GPGME_STATUS_SIG_CREATED:
311       opd->sig_created_seen = 1;
312       err = parse_sig_created (args, opd->last_sig_p, ctx->protocol);
313       if (err)
314         return err;
315
316       opd->last_sig_p = &(*opd->last_sig_p)->next;
317       break;
318
319     case GPGME_STATUS_INV_RECP:
320       if (opd->inv_sgnr_seen && opd->ignore_inv_recp)
321         break;
322       /* FALLTROUGH */
323     case GPGME_STATUS_INV_SGNR:
324       if (code == GPGME_STATUS_INV_SGNR)
325         opd->inv_sgnr_seen = 1;
326       err = _gpgme_parse_inv_recp (args, opd->last_signer_p);
327       if (err)
328         return err;
329
330       opd->last_signer_p = &(*opd->last_signer_p)->next;
331       break;
332
333     case GPGME_STATUS_FAILURE:
334       opd->failure_code = _gpgme_parse_failure (args);
335       break;
336
337     case GPGME_STATUS_EOF:
338       /* The UI server does not send information about the created
339          signature.  This is irrelevant for this protocol and thus we
340          should not check for that.  */
341       if (opd->result.invalid_signers)
342         err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
343       else if (!opd->sig_created_seen
344                && ctx->protocol != GPGME_PROTOCOL_UISERVER)
345         err = opd->failure_code? opd->failure_code:gpg_error (GPG_ERR_GENERAL);
346       break;
347
348     case GPGME_STATUS_INQUIRE_MAXLEN:
349       if (ctx->status_cb)
350         err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
351       break;
352
353     default:
354       break;
355     }
356   return err;
357 }
358
359
360 static gpgme_error_t
361 sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
362 {
363   gpgme_error_t err;
364
365   err = _gpgme_progress_status_handler (priv, code, args);
366   if (!err)
367     err = _gpgme_sign_status_handler (priv, code, args);
368   return err;
369 }
370
371
372 static gpgme_error_t
373 sign_init_result (gpgme_ctx_t ctx, int ignore_inv_recp)
374 {
375   gpgme_error_t err;
376   void *hook;
377   op_data_t opd;
378
379   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook,
380                                sizeof (*opd), release_op_data);
381   opd = hook;
382   if (err)
383     return err;
384   opd->failure_code = 0;
385   opd->last_signer_p = &opd->result.invalid_signers;
386   opd->last_sig_p = &opd->result.signatures;
387   opd->ignore_inv_recp = !!ignore_inv_recp;
388   opd->inv_sgnr_seen = 0;
389   opd->sig_created_seen = 0;
390   return 0;
391 }
392
393 gpgme_error_t
394 _gpgme_op_sign_init_result (gpgme_ctx_t ctx)
395 {
396   return sign_init_result (ctx, 0);
397 }
398
399
400 static gpgme_error_t
401 sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t plain,
402             gpgme_data_t sig, gpgme_sig_mode_t mode)
403 {
404   gpgme_error_t err;
405
406   err = _gpgme_op_reset (ctx, synchronous);
407   if (err)
408     return err;
409
410   /* If we are using the CMS protocol, we ignore the INV_RECP status
411      code if a newer GPGSM is in use.  GPGMS does not support combined
412      sign+encrypt and thus this can't harm.  */
413   err = sign_init_result (ctx, (ctx->protocol == GPGME_PROTOCOL_CMS));
414   if (err)
415     return err;
416
417   if (mode != GPGME_SIG_MODE_NORMAL && mode != GPGME_SIG_MODE_DETACH
418       && mode != GPGME_SIG_MODE_CLEAR)
419     return gpg_error (GPG_ERR_INV_VALUE);
420
421   if (!plain)
422     return gpg_error (GPG_ERR_NO_DATA);
423   if (!sig)
424     return gpg_error (GPG_ERR_INV_VALUE);
425
426   if (ctx->passphrase_cb)
427     {
428       err = _gpgme_engine_set_command_handler
429         (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
430       if (err)
431         return err;
432     }
433
434   _gpgme_engine_set_status_handler (ctx->engine, sign_status_handler,
435                                     ctx);
436
437   return _gpgme_engine_op_sign (ctx->engine, plain, sig, mode, ctx->use_armor,
438                                 ctx->use_textmode, ctx->include_certs,
439                                 ctx /* FIXME */);
440 }
441
442
443 /* Sign the plaintext PLAIN and store the signature in SIG.  */
444 gpgme_error_t
445 gpgme_op_sign_start (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
446                      gpgme_sig_mode_t mode)
447 {
448   gpg_error_t err;
449   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_sign_start", ctx,
450               "plain=%p, sig=%p, mode=%i", plain, sig, mode);
451
452   if (!ctx)
453     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
454
455   err = sign_start (ctx, 0, plain, sig, mode);
456   return TRACE_ERR (err);
457 }
458
459
460 /* Sign the plaintext PLAIN and store the signature in SIG.  */
461 gpgme_error_t
462 gpgme_op_sign (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
463                gpgme_sig_mode_t mode)
464 {
465   gpgme_error_t err;
466
467   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_sign", ctx,
468               "plain=%p, sig=%p, mode=%i", plain, sig, mode);
469
470   if (!ctx)
471     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
472
473   err = sign_start (ctx, 1, plain, sig, mode);
474   if (!err)
475     err = _gpgme_wait_one (ctx);
476   return TRACE_ERR (err);
477 }