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