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