Release 1.9.0
[gpgme.git] / src / decrypt.c
1 /* decrypt.c - Decrypt function.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004 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 #include <assert.h>
29
30 #include "debug.h"
31 #include "gpgme.h"
32 #include "util.h"
33 #include "context.h"
34 #include "ops.h"
35
36
37 \f
38 typedef struct
39 {
40   struct _gpgme_op_decrypt_result result;
41
42   /* The error code from a FAILURE status line or 0.  */
43   gpg_error_t failure_code;
44
45   int okay;
46   int failed;
47
48   /* A pointer to the next pointer of the last recipient in the list.
49      This makes appending new invalid signers painless while
50      preserving the order.  */
51   gpgme_recipient_t *last_recipient_p;
52 } *op_data_t;
53
54
55 static void
56 release_op_data (void *hook)
57 {
58   op_data_t opd = (op_data_t) hook;
59   gpgme_recipient_t recipient = opd->result.recipients;
60
61   if (opd->result.unsupported_algorithm)
62     free (opd->result.unsupported_algorithm);
63
64   if (opd->result.file_name)
65     free (opd->result.file_name);
66
67   if (opd->result.session_key)
68     free (opd->result.session_key);
69
70   while (recipient)
71     {
72       gpgme_recipient_t next = recipient->next;
73       free (recipient);
74       recipient = next;
75     }
76 }
77
78
79 gpgme_decrypt_result_t
80 gpgme_op_decrypt_result (gpgme_ctx_t ctx)
81 {
82   void *hook;
83   op_data_t opd;
84   gpgme_error_t err;
85
86   TRACE_BEG (DEBUG_CTX, "gpgme_op_decrypt_result", ctx);
87
88   err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
89   opd = hook;
90   if (err || !opd)
91     {
92       TRACE_SUC0 ("result=(null)");
93       return NULL;
94     }
95
96   if (_gpgme_debug_trace ())
97     {
98       gpgme_recipient_t rcp;
99
100       if (opd->result.unsupported_algorithm)
101         {
102           TRACE_LOG1 ("result: unsupported_algorithm: %s",
103                       opd->result.unsupported_algorithm);
104         }
105       if (opd->result.wrong_key_usage)
106         {
107           TRACE_LOG ("result: wrong key usage");
108         }
109       rcp = opd->result.recipients;
110       while (rcp)
111         {
112           TRACE_LOG3 ("result: recipient: keyid=%s, pubkey_algo=%i, "
113                       "status=%s", rcp->keyid, rcp->pubkey_algo,
114                       gpg_strerror (rcp->status));
115           rcp = rcp->next;
116         }
117       if (opd->result.file_name)
118         {
119           TRACE_LOG1 ("result: original file name: %s", opd->result.file_name);
120         }
121     }
122
123   TRACE_SUC1 ("result=%p", &opd->result);
124   return &opd->result;
125 }
126
127 \f
128 static gpgme_error_t
129 parse_enc_to (char *args, gpgme_recipient_t *recp, gpgme_protocol_t protocol)
130 {
131   gpgme_recipient_t rec;
132   char *tail;
133   int i;
134
135   rec = malloc (sizeof (*rec));
136   if (!rec)
137     return gpg_error_from_syserror ();
138
139   rec->next = NULL;
140   rec->keyid = rec->_keyid;
141   rec->status = 0;
142
143   for (i = 0; i < sizeof (rec->_keyid) - 1; i++)
144     {
145       if (args[i] == '\0' || args[i] == ' ')
146         break;
147
148       rec->_keyid[i] = args[i];
149     }
150   rec->_keyid[i] = '\0';
151
152   args = &args[i];
153   if (*args != '\0' && *args != ' ')
154     {
155       free (rec);
156       return trace_gpg_error (GPG_ERR_INV_ENGINE);
157     }
158
159   while (*args == ' ')
160     args++;
161
162   if (*args)
163     {
164       gpg_err_set_errno (0);
165       rec->pubkey_algo = _gpgme_map_pk_algo (strtol (args, &tail, 0), protocol);
166       if (errno || args == tail || *tail != ' ')
167         {
168           /* The crypto backend does not behave.  */
169           free (rec);
170           return trace_gpg_error (GPG_ERR_INV_ENGINE);
171         }
172     }
173
174   /* FIXME: The key length is always 0 right now, so no need to parse
175      it.  */
176
177   *recp = rec;
178   return 0;
179 }
180
181
182 gpgme_error_t
183 _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
184                                char *args)
185 {
186   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
187   gpgme_error_t err;
188   void *hook;
189   op_data_t opd;
190
191   err = _gpgme_passphrase_status_handler (priv, code, args);
192   if (err)
193     return err;
194
195   err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
196   opd = hook;
197   if (err)
198     return err;
199
200   switch (code)
201     {
202     case GPGME_STATUS_FAILURE:
203       opd->failure_code = _gpgme_parse_failure (args);
204       break;
205
206     case GPGME_STATUS_EOF:
207       /* FIXME: These error values should probably be attributed to
208          the underlying crypto engine (as error source).  */
209       if (opd->failed)
210         return gpg_error (GPG_ERR_DECRYPT_FAILED);
211       else if (!opd->okay)
212         return gpg_error (GPG_ERR_NO_DATA);
213       else if (opd->failure_code)
214         return opd->failure_code;
215       break;
216
217     case GPGME_STATUS_DECRYPTION_INFO:
218       /* Fixme: Provide a way to return the used symmetric algorithm. */
219       break;
220
221     case GPGME_STATUS_DECRYPTION_OKAY:
222       opd->okay = 1;
223       break;
224
225     case GPGME_STATUS_DECRYPTION_FAILED:
226       opd->failed = 1;
227       break;
228
229     case GPGME_STATUS_ERROR:
230       /* Note that this is an informational status code which should
231          not lead to an error return unless it is something not
232          related to the backend.  */
233       {
234         const char d_alg[] = "decrypt.algorithm";
235         const char k_alg[] = "decrypt.keyusage";
236
237         if (!strncmp (args, d_alg, sizeof (d_alg) - 1))
238           {
239             args += sizeof (d_alg) - 1;
240             while (*args == ' ')
241               args++;
242
243             if (gpg_err_code (atoi (args)) == GPG_ERR_UNSUPPORTED_ALGORITHM)
244               {
245                 char *end;
246
247                 while (*args && *args != ' ')
248                   args++;
249                 while (*args == ' ')
250                   args++;
251
252                 end = strchr (args, ' ');
253                 if (end)
254                   *end = '\0';
255
256                 if (!(*args == '?' && *(args + 1) == '\0'))
257                   {
258                     opd->result.unsupported_algorithm = strdup (args);
259                     if (!opd->result.unsupported_algorithm)
260                       return gpg_error_from_syserror ();
261                   }
262               }
263           }
264         else if (!strncmp (args, k_alg, sizeof (k_alg) - 1))
265           {
266             args += sizeof (k_alg) - 1;
267             while (*args == ' ')
268               args++;
269
270             if (gpg_err_code (atoi (args)) == GPG_ERR_WRONG_KEY_USAGE)
271               opd->result.wrong_key_usage = 1;
272           }
273       }
274       break;
275
276     case GPGME_STATUS_ENC_TO:
277       err = parse_enc_to (args, opd->last_recipient_p, ctx->protocol);
278       if (err)
279         return err;
280
281       opd->last_recipient_p = &(*opd->last_recipient_p)->next;
282       break;
283
284     case GPGME_STATUS_SESSION_KEY:
285       if (opd->result.session_key)
286         free (opd->result.session_key);
287       opd->result.session_key = strdup(args);
288       break;
289
290     case GPGME_STATUS_NO_SECKEY:
291       {
292         gpgme_recipient_t rec = opd->result.recipients;
293
294         while (rec)
295           {
296             if (!strcmp (rec->keyid, args))
297               {
298                 rec->status = gpg_error (GPG_ERR_NO_SECKEY);
299                 break;
300               }
301             rec = rec->next;
302           }
303         /* FIXME: Is this ok?  */
304         if (!rec)
305           return trace_gpg_error (GPG_ERR_INV_ENGINE);
306       }
307       break;
308
309     case GPGME_STATUS_PLAINTEXT:
310       err = _gpgme_parse_plaintext (args, &opd->result.file_name);
311       if (err)
312         return err;
313       break;
314
315     case GPGME_STATUS_INQUIRE_MAXLEN:
316       if (ctx->status_cb && !ctx->full_status)
317         {
318           err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
319           if (err)
320             return err;
321         }
322       break;
323
324     default:
325       break;
326     }
327
328   return 0;
329 }
330
331
332 static gpgme_error_t
333 decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
334 {
335   gpgme_error_t err;
336
337   err = _gpgme_progress_status_handler (priv, code, args);
338   if (!err)
339     err = _gpgme_decrypt_status_handler (priv, code, args);
340   return err;
341 }
342
343
344 gpgme_error_t
345 _gpgme_op_decrypt_init_result (gpgme_ctx_t ctx)
346 {
347   gpgme_error_t err;
348   void *hook;
349   op_data_t opd;
350
351   err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook,
352                                sizeof (*opd), release_op_data);
353   opd = hook;
354   if (err)
355     return err;
356
357   opd->last_recipient_p = &opd->result.recipients;
358   return 0;
359 }
360
361
362 gpgme_error_t
363 _gpgme_decrypt_start (gpgme_ctx_t ctx, int synchronous,
364                       gpgme_decrypt_flags_t flags,
365                       gpgme_data_t cipher, gpgme_data_t plain)
366 {
367   gpgme_error_t err;
368
369   assert (!(flags & GPGME_DECRYPT_VERIFY));
370
371   err = _gpgme_op_reset (ctx, synchronous);
372   if (err)
373     return err;
374
375   err = _gpgme_op_decrypt_init_result (ctx);
376   if (err)
377     return err;
378
379   if (!cipher)
380     return gpg_error (GPG_ERR_NO_DATA);
381   if (!plain)
382     return gpg_error (GPG_ERR_INV_VALUE);
383
384   if (err)
385     return err;
386
387   if (ctx->passphrase_cb)
388     {
389       err = _gpgme_engine_set_command_handler
390         (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
391       if (err)
392         return err;
393     }
394
395   _gpgme_engine_set_status_handler (ctx->engine, decrypt_status_handler, ctx);
396
397   return _gpgme_engine_op_decrypt (ctx->engine,
398                                    flags,
399                                    cipher, plain,
400                                    ctx->export_session_keys,
401                                    ctx->override_session_key);
402 }
403
404
405 gpgme_error_t
406 gpgme_op_decrypt_start (gpgme_ctx_t ctx, gpgme_data_t cipher,
407                         gpgme_data_t plain)
408 {
409   gpgme_error_t err;
410
411   TRACE_BEG2 (DEBUG_CTX, "gpgme_op_decrypt_start", ctx,
412               "cipher=%p, plain=%p", cipher, plain);
413
414   if (!ctx)
415     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
416
417   err = _gpgme_decrypt_start (ctx, 0, 0, cipher, plain);
418   return TRACE_ERR (err);
419 }
420
421
422 /* Decrypt ciphertext CIPHER within CTX and store the resulting
423    plaintext in PLAIN.  */
424 gpgme_error_t
425 gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain)
426 {
427   gpgme_error_t err;
428
429   TRACE_BEG2 (DEBUG_CTX, "gpgme_op_decrypt", ctx,
430               "cipher=%p, plain=%p", cipher, plain);
431
432   if (!ctx)
433     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
434
435   err = _gpgme_decrypt_start (ctx, 1, 0, cipher, plain);
436   if (!err)
437     err = _gpgme_wait_one (ctx);
438   return TRACE_ERR (err);
439 }