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