doc/
[gpgme.git] / gpgme / 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 "gpgme.h"
30 #include "util.h"
31 #include "context.h"
32 #include "ops.h"
33
34 \f
35 typedef struct
36 {
37   struct _gpgme_op_decrypt_result result;
38
39   int okay;
40   int failed;
41   
42   /* A pointer to the next pointer of the last recipient in the list.
43      This makes appending new invalid signers painless while
44      preserving the order.  */
45   gpgme_recipient_t *last_recipient_p;
46 } *op_data_t;
47
48
49 static void
50 release_op_data (void *hook)
51 {
52   op_data_t opd = (op_data_t) hook;
53
54   if (opd->result.unsupported_algorithm)
55     free (opd->result.unsupported_algorithm);
56 }
57
58
59 gpgme_decrypt_result_t
60 gpgme_op_decrypt_result (gpgme_ctx_t ctx)
61 {
62   void *hook;
63   op_data_t opd;
64   gpgme_error_t err;
65
66   err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
67   opd = hook;
68   if (err || !opd)
69     return NULL;
70
71   return &opd->result;
72 }
73
74 \f
75 static gpgme_error_t
76 parse_enc_to (char *args, gpgme_recipient_t *recp)
77 {
78   gpgme_recipient_t rec;
79   char *tail;
80   int i;
81
82   rec = malloc (sizeof (*rec));
83   if (!rec)
84     return gpg_error_from_errno (errno);
85
86   rec->next = NULL;
87   rec->keyid = rec->_keyid;
88   rec->status = 0;
89
90   for (i = 0; i < sizeof (rec->_keyid) - 1; i++)
91     {
92       if (args[i] == '\0' || args[i] == ' ')
93         break;
94
95       rec->_keyid[i] = args[i];
96     }
97   rec->_keyid[i] = '\0';
98
99   args = &args[i];
100   if (*args != '\0' && *args != ' ')
101     {
102       free (rec);
103       return gpg_error (GPG_ERR_INV_ENGINE);
104     }
105
106   while (*args == ' ')
107     args++;
108
109   if (*args)
110     {
111       errno = 0;
112       rec->pubkey_algo = strtol (args, &tail, 0);
113       if (errno || args == tail || *tail != ' ')
114         {
115           /* The crypto backend does not behave.  */
116           free (rec);
117           return gpg_error (GPG_ERR_INV_ENGINE);
118         }
119     }
120
121   /* FIXME: The key length is always 0 right now, so no need to parse
122      it.  */
123
124   *recp = rec;
125   return 0;
126 }
127
128
129 gpgme_error_t
130 _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
131                                char *args)
132 {
133   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
134   gpgme_error_t err;
135   void *hook;
136   op_data_t opd;
137
138   err = _gpgme_passphrase_status_handler (priv, code, args);
139   if (err)
140     return err;
141
142   err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
143   opd = hook;
144   if (err)
145     return err;
146
147   switch (code)
148     {
149     case GPGME_STATUS_EOF:
150       /* FIXME: These error values should probably be attributed to
151          the underlying crypto engine (as error source).  */
152       if (opd->failed)
153         return gpg_error (GPG_ERR_DECRYPT_FAILED);
154       else if (!opd->okay)
155         return gpg_error (GPG_ERR_NO_DATA);
156       break;
157
158     case GPGME_STATUS_DECRYPTION_OKAY:
159       opd->okay = 1;
160       break;
161
162     case GPGME_STATUS_DECRYPTION_FAILED:
163       opd->failed = 1;
164       break;
165
166     case GPGME_STATUS_ERROR:
167       /* Note that this is an informational status code which should
168          not lead to an error return unless it is something not
169          related to the backend.  */
170       {
171         const char d_alg[] = "decrypt.algorithm";
172         const char u_alg[] = "Unsupported_Algorithm";
173         const char k_alg[] = "decrypt.keyusage";
174
175         if (!strncmp (args, d_alg, sizeof (d_alg) - 1))
176           {
177             args += sizeof (d_alg) - 1;
178             while (*args == ' ')
179               args++;
180
181             if (!strncmp (args, u_alg, sizeof (u_alg) - 1))
182               {
183                 char *end;
184
185                 args += sizeof (u_alg) - 1;
186                 while (*args == ' ')
187                   args++;
188
189                 end = strchr (args, ' ');
190                 if (end)
191                   *end = '\0';
192
193                 if (!(*args == '?' && *(args + 1) == '\0'))
194                   {
195                     opd->result.unsupported_algorithm = strdup (args);
196                     if (!opd->result.unsupported_algorithm)
197                       return gpg_error_from_errno (errno);
198                   }
199               }
200           }
201         else if (!strncmp (args, k_alg, sizeof (k_alg) - 1))
202           {
203             args += sizeof (k_alg) - 1;
204             while (*args == ' ')
205               args++;
206
207             err = _gpgme_map_gnupg_error (args);
208             if (gpg_err_code (err) == GPG_ERR_WRONG_KEY_USAGE)
209               opd->result.wrong_key_usage = 1;
210           }
211       }
212       break;
213
214     case GPGME_STATUS_ENC_TO:
215       err = parse_enc_to (args, opd->last_recipient_p);
216       if (err)
217         return err;
218
219       opd->last_recipient_p = &(*opd->last_recipient_p)->next;
220       break;
221
222     case GPGME_STATUS_NO_SECKEY:
223       {
224         gpgme_recipient_t rec = opd->result.recipients;
225
226         while (rec)
227           {
228             if (!strcmp (rec->keyid, args))
229               {
230                 rec->status = gpg_error (GPG_ERR_NO_SECKEY);
231                 break;
232               }
233           }
234         /* FIXME: Is this ok?  */
235         if (!rec)
236           return gpg_error (GPG_ERR_INV_ENGINE);
237       }
238       break;
239
240     default:
241       break;
242     }
243
244   return 0;
245 }
246
247
248 static gpgme_error_t
249 decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
250 {
251   gpgme_error_t err;
252
253   err = _gpgme_progress_status_handler (priv, code, args);
254   if (!err)
255     err = _gpgme_decrypt_status_handler (priv, code, args);
256   return err;
257 }
258
259
260 gpgme_error_t
261 _gpgme_op_decrypt_init_result (gpgme_ctx_t ctx)
262 {
263   gpgme_error_t err;
264   void *hook;
265   op_data_t opd;
266
267   err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook,
268                                sizeof (*opd), release_op_data);
269   opd = hook;
270   if (err)
271     return err;
272
273   opd->last_recipient_p = &opd->result.recipients;
274   return 0;
275 }
276
277
278 static gpgme_error_t
279 decrypt_start (gpgme_ctx_t ctx, int synchronous,
280                       gpgme_data_t cipher, gpgme_data_t plain)
281 {
282   gpgme_error_t err;
283
284   err = _gpgme_op_reset (ctx, synchronous);
285   if (err)
286     return err;
287
288   err = _gpgme_op_decrypt_init_result (ctx);
289   if (err)
290     return err;
291
292   if (!cipher)
293     return gpg_error (GPG_ERR_NO_DATA);
294   if (!plain)
295     return gpg_error (GPG_ERR_INV_VALUE);
296
297   if (err)
298     return err;
299
300   if (ctx->passphrase_cb)
301     {
302       err = _gpgme_engine_set_command_handler
303         (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
304       if (err)
305         return err;
306     }
307
308   _gpgme_engine_set_status_handler (ctx->engine, decrypt_status_handler, ctx);
309
310   return _gpgme_engine_op_decrypt (ctx->engine, cipher, plain);
311 }
312
313
314 gpgme_error_t
315 gpgme_op_decrypt_start (gpgme_ctx_t ctx, gpgme_data_t cipher,
316                         gpgme_data_t plain)
317 {
318   return decrypt_start (ctx, 0, cipher, plain);
319 }
320
321
322 /* Decrypt ciphertext CIPHER within CTX and store the resulting
323    plaintext in PLAIN.  */
324 gpgme_error_t
325 gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain)
326 {
327   gpgme_error_t err = decrypt_start (ctx, 1, cipher, plain);
328   if (!err)
329     err = _gpgme_wait_one (ctx);
330   return err;
331 }