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