c235be4adbac371a06636ada6cd83fb376418766
[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 } *op_data_t;
42
43
44 static void
45 release_op_data (void *hook)
46 {
47   op_data_t opd = (op_data_t) hook;
48
49   if (opd->result.unsupported_algorithm)
50     free (opd->result.unsupported_algorithm);
51 }
52
53
54 gpgme_decrypt_result_t
55 gpgme_op_decrypt_result (gpgme_ctx_t ctx)
56 {
57   void *hook;
58   op_data_t opd;
59   gpgme_error_t err;
60
61   err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
62   opd = hook;
63   if (err || !opd)
64     return NULL;
65
66   return &opd->result;
67 }
68
69 \f
70 gpgme_error_t
71 _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
72                                char *args)
73 {
74   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
75   gpgme_error_t err;
76   void *hook;
77   op_data_t opd;
78
79   err = _gpgme_passphrase_status_handler (priv, code, args);
80   if (err)
81     return err;
82
83   err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
84   opd = hook;
85   if (err)
86     return err;
87
88   switch (code)
89     {
90     case GPGME_STATUS_EOF:
91       /* FIXME: These error values should probably be attributed to
92          the underlying crypto engine (as error source).  */
93       if (opd->failed)
94         return gpg_error (GPG_ERR_DECRYPT_FAILED);
95       else if (!opd->okay)
96         return gpg_error (GPG_ERR_NO_DATA);
97       break;
98
99     case GPGME_STATUS_DECRYPTION_OKAY:
100       opd->okay = 1;
101       break;
102
103     case GPGME_STATUS_DECRYPTION_FAILED:
104       opd->failed = 1;
105       break;
106
107     case GPGME_STATUS_ERROR:
108       /* Note that this is an informational status code which should
109          not lead to an error return unless it is something not
110          related to the backend.  */
111       {
112         const char d_alg[] = "decrypt.algorithm";
113         const char u_alg[] = "Unsupported_Algorithm";
114         const char k_alg[] = "decrypt.keyusage";
115
116         if (!strncmp (args, d_alg, sizeof (d_alg) - 1))
117           {
118             args += sizeof (d_alg) - 1;
119             while (*args == ' ')
120               args++;
121
122             if (!strncmp (args, u_alg, sizeof (u_alg) - 1))
123               {
124                 char *end;
125
126                 args += sizeof (u_alg) - 1;
127                 while (*args == ' ')
128                   args++;
129
130                 end = strchr (args, ' ');
131                 if (end)
132                   *end = '\0';
133
134                 if (!(*args == '?' && *(args + 1) == '\0'))
135                   {
136                     opd->result.unsupported_algorithm = strdup (args);
137                     if (!opd->result.unsupported_algorithm)
138                       return gpg_error_from_errno (errno);
139                   }
140               }
141           }
142         else if (!strncmp (args, k_alg, sizeof (k_alg) - 1))
143           {
144             args += sizeof (k_alg) - 1;
145             while (*args == ' ')
146               args++;
147
148             err = _gpgme_map_gnupg_error (args);
149             if (gpg_err_code (err) == GPG_ERR_WRONG_KEY_USAGE)
150               opd->result.wrong_key_usage = 1;
151           }
152       }
153       break;
154         
155     default:
156       break;
157     }
158
159   return 0;
160 }
161
162
163 static gpgme_error_t
164 decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
165 {
166   gpgme_error_t err;
167
168   err = _gpgme_progress_status_handler (priv, code, args);
169   if (!err)
170     err = _gpgme_decrypt_status_handler (priv, code, args);
171   return err;
172 }
173
174
175 gpgme_error_t
176 _gpgme_op_decrypt_init_result (gpgme_ctx_t ctx)
177 {
178   void *hook;
179   op_data_t opd;
180
181   return _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook,
182                                 sizeof (*opd), release_op_data);
183 }
184
185
186 static gpgme_error_t
187 decrypt_start (gpgme_ctx_t ctx, int synchronous,
188                       gpgme_data_t cipher, gpgme_data_t plain)
189 {
190   gpgme_error_t err;
191
192   err = _gpgme_op_reset (ctx, synchronous);
193   if (err)
194     return err;
195
196   err = _gpgme_op_decrypt_init_result (ctx);
197   if (err)
198     return err;
199
200   if (!cipher)
201     return gpg_error (GPG_ERR_NO_DATA);
202   if (!plain)
203     return gpg_error (GPG_ERR_INV_VALUE);
204
205   if (err)
206     return err;
207
208   if (ctx->passphrase_cb)
209     {
210       err = _gpgme_engine_set_command_handler
211         (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
212       if (err)
213         return err;
214     }
215
216   _gpgme_engine_set_status_handler (ctx->engine, decrypt_status_handler, ctx);
217
218   return _gpgme_engine_op_decrypt (ctx->engine, cipher, plain);
219 }
220
221
222 gpgme_error_t
223 gpgme_op_decrypt_start (gpgme_ctx_t ctx, gpgme_data_t cipher,
224                         gpgme_data_t plain)
225 {
226   return decrypt_start (ctx, 0, cipher, plain);
227 }
228
229
230 /* Decrypt ciphertext CIPHER within CTX and store the resulting
231    plaintext in PLAIN.  */
232 gpgme_error_t
233 gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain)
234 {
235   gpgme_error_t err = decrypt_start (ctx, 1, cipher, plain);
236   if (!err)
237     err = _gpgme_wait_one (ctx);
238   return err;
239 }