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