Line data Source code
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 :
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 38 : release_op_data (void *hook)
56 : {
57 38 : op_data_t opd = (op_data_t) hook;
58 38 : gpgme_recipient_t recipient = opd->result.recipients;
59 :
60 38 : if (opd->result.unsupported_algorithm)
61 0 : free (opd->result.unsupported_algorithm);
62 :
63 38 : if (opd->result.file_name)
64 6 : free (opd->result.file_name);
65 :
66 108 : while (recipient)
67 : {
68 32 : gpgme_recipient_t next = recipient->next;
69 32 : free (recipient);
70 32 : recipient = next;
71 : }
72 38 : }
73 :
74 :
75 : gpgme_decrypt_result_t
76 35 : gpgme_op_decrypt_result (gpgme_ctx_t ctx)
77 : {
78 : void *hook;
79 : op_data_t opd;
80 : gpgme_error_t err;
81 :
82 35 : TRACE_BEG (DEBUG_CTX, "gpgme_op_decrypt_result", ctx);
83 :
84 35 : err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
85 35 : opd = hook;
86 35 : if (err || !opd)
87 : {
88 0 : TRACE_SUC0 ("result=(null)");
89 0 : return NULL;
90 : }
91 :
92 : if (_gpgme_debug_trace ())
93 : {
94 : gpgme_recipient_t rcp;
95 :
96 35 : if (opd->result.unsupported_algorithm)
97 : {
98 0 : TRACE_LOG1 ("result: unsupported_algorithm: %s",
99 : opd->result.unsupported_algorithm);
100 : }
101 35 : if (opd->result.wrong_key_usage)
102 : {
103 0 : TRACE_LOG ("result: wrong key usage");
104 : }
105 35 : rcp = opd->result.recipients;
106 102 : while (rcp)
107 : {
108 32 : TRACE_LOG3 ("result: recipient: keyid=%s, pubkey_algo=%i, "
109 : "status=%s", rcp->keyid, rcp->pubkey_algo,
110 : gpg_strerror (rcp->status));
111 32 : rcp = rcp->next;
112 : }
113 35 : if (opd->result.file_name)
114 : {
115 6 : TRACE_LOG1 ("result: original file name: %s", opd->result.file_name);
116 : }
117 : }
118 :
119 35 : TRACE_SUC1 ("result=%p", &opd->result);
120 35 : return &opd->result;
121 : }
122 :
123 :
124 : static gpgme_error_t
125 30 : 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 30 : rec = malloc (sizeof (*rec));
132 30 : if (!rec)
133 0 : return gpg_error_from_syserror ();
134 :
135 30 : rec->next = NULL;
136 30 : rec->keyid = rec->_keyid;
137 30 : rec->status = 0;
138 :
139 510 : for (i = 0; i < sizeof (rec->_keyid) - 1; i++)
140 : {
141 480 : if (args[i] == '\0' || args[i] == ' ')
142 : break;
143 :
144 480 : rec->_keyid[i] = args[i];
145 : }
146 30 : rec->_keyid[i] = '\0';
147 :
148 30 : args = &args[i];
149 30 : if (*args != '\0' && *args != ' ')
150 : {
151 0 : free (rec);
152 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
153 : }
154 :
155 90 : while (*args == ' ')
156 30 : args++;
157 :
158 30 : if (*args)
159 : {
160 30 : gpg_err_set_errno (0);
161 30 : rec->pubkey_algo = _gpgme_map_pk_algo (strtol (args, &tail, 0), protocol);
162 30 : if (errno || args == tail || *tail != ' ')
163 : {
164 : /* The crypto backend does not behave. */
165 0 : free (rec);
166 0 : 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 30 : *recp = rec;
174 30 : return 0;
175 : }
176 :
177 :
178 : gpgme_error_t
179 542 : _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
180 : char *args)
181 : {
182 542 : gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
183 : gpgme_error_t err;
184 : void *hook;
185 : op_data_t opd;
186 :
187 542 : err = _gpgme_passphrase_status_handler (priv, code, args);
188 541 : if (err)
189 0 : return err;
190 :
191 541 : err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
192 541 : opd = hook;
193 541 : if (err)
194 0 : return err;
195 :
196 541 : switch (code)
197 : {
198 : case GPGME_STATUS_FAILURE:
199 0 : opd->failure_code = _gpgme_parse_failure (args);
200 0 : 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 38 : if (opd->failed)
206 0 : return gpg_error (GPG_ERR_DECRYPT_FAILED);
207 38 : else if (!opd->okay)
208 0 : return gpg_error (GPG_ERR_NO_DATA);
209 38 : else if (opd->failure_code)
210 0 : return opd->failure_code;
211 38 : break;
212 :
213 : case GPGME_STATUS_DECRYPTION_INFO:
214 : /* Fixme: Provide a way to return the used symmetric algorithm. */
215 36 : break;
216 :
217 : case GPGME_STATUS_DECRYPTION_OKAY:
218 39 : opd->okay = 1;
219 39 : break;
220 :
221 : case GPGME_STATUS_DECRYPTION_FAILED:
222 0 : opd->failed = 1;
223 0 : 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 0 : const char d_alg[] = "decrypt.algorithm";
231 0 : const char k_alg[] = "decrypt.keyusage";
232 :
233 0 : if (!strncmp (args, d_alg, sizeof (d_alg) - 1))
234 : {
235 0 : args += sizeof (d_alg) - 1;
236 0 : while (*args == ' ')
237 0 : args++;
238 :
239 0 : if (gpg_err_code (atoi (args)) == GPG_ERR_UNSUPPORTED_ALGORITHM)
240 : {
241 : char *end;
242 :
243 0 : while (*args && *args != ' ')
244 0 : args++;
245 0 : while (*args == ' ')
246 0 : args++;
247 :
248 0 : end = strchr (args, ' ');
249 0 : if (end)
250 0 : *end = '\0';
251 :
252 0 : if (!(*args == '?' && *(args + 1) == '\0'))
253 : {
254 0 : opd->result.unsupported_algorithm = strdup (args);
255 0 : if (!opd->result.unsupported_algorithm)
256 0 : return gpg_error_from_syserror ();
257 : }
258 : }
259 : }
260 0 : else if (!strncmp (args, k_alg, sizeof (k_alg) - 1))
261 : {
262 0 : args += sizeof (k_alg) - 1;
263 0 : while (*args == ' ')
264 0 : args++;
265 :
266 0 : if (gpg_err_code (atoi (args)) == GPG_ERR_WRONG_KEY_USAGE)
267 0 : opd->result.wrong_key_usage = 1;
268 : }
269 : }
270 0 : break;
271 :
272 : case GPGME_STATUS_ENC_TO:
273 30 : err = parse_enc_to (args, opd->last_recipient_p, ctx->protocol);
274 30 : if (err)
275 0 : return err;
276 :
277 30 : opd->last_recipient_p = &(*opd->last_recipient_p)->next;
278 30 : break;
279 :
280 : case GPGME_STATUS_NO_SECKEY:
281 : {
282 1 : gpgme_recipient_t rec = opd->result.recipients;
283 :
284 2 : while (rec)
285 : {
286 1 : if (!strcmp (rec->keyid, args))
287 : {
288 1 : rec->status = gpg_error (GPG_ERR_NO_SECKEY);
289 1 : break;
290 : }
291 0 : rec = rec->next;
292 : }
293 : /* FIXME: Is this ok? */
294 1 : if (!rec)
295 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
296 : }
297 1 : break;
298 :
299 : case GPGME_STATUS_PLAINTEXT:
300 36 : err = _gpgme_parse_plaintext (args, &opd->result.file_name);
301 36 : if (err)
302 0 : return err;
303 36 : break;
304 :
305 : case GPGME_STATUS_INQUIRE_MAXLEN:
306 7 : if (ctx->status_cb && !ctx->full_status)
307 : {
308 0 : err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
309 0 : if (err)
310 0 : return err;
311 : }
312 7 : break;
313 :
314 : default:
315 354 : break;
316 : }
317 :
318 541 : return 0;
319 : }
320 :
321 :
322 : static gpgme_error_t
323 420 : decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
324 : {
325 : gpgme_error_t err;
326 :
327 420 : err = _gpgme_progress_status_handler (priv, code, args);
328 420 : if (!err)
329 420 : err = _gpgme_decrypt_status_handler (priv, code, args);
330 419 : return err;
331 : }
332 :
333 :
334 : gpgme_error_t
335 37 : _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 37 : err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook,
342 : sizeof (*opd), release_op_data);
343 37 : opd = hook;
344 37 : if (err)
345 0 : return err;
346 :
347 37 : opd->last_recipient_p = &opd->result.recipients;
348 37 : return 0;
349 : }
350 :
351 :
352 : static gpgme_error_t
353 30 : 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 30 : err = _gpgme_op_reset (ctx, synchronous);
359 30 : if (err)
360 0 : return err;
361 :
362 30 : err = _gpgme_op_decrypt_init_result (ctx);
363 30 : if (err)
364 0 : return err;
365 :
366 30 : if (!cipher)
367 0 : return gpg_error (GPG_ERR_NO_DATA);
368 30 : if (!plain)
369 0 : return gpg_error (GPG_ERR_INV_VALUE);
370 :
371 30 : if (err)
372 0 : return err;
373 :
374 30 : if (ctx->passphrase_cb)
375 : {
376 27 : err = _gpgme_engine_set_command_handler
377 : (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
378 27 : if (err)
379 0 : return err;
380 : }
381 :
382 30 : _gpgme_engine_set_status_handler (ctx->engine, decrypt_status_handler, ctx);
383 :
384 30 : return _gpgme_engine_op_decrypt (ctx->engine, cipher, plain);
385 : }
386 :
387 :
388 : gpgme_error_t
389 0 : 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 0 : TRACE_BEG2 (DEBUG_CTX, "gpgme_op_decrypt_start", ctx,
395 : "cipher=%p, plain=%p", cipher, plain);
396 :
397 0 : if (!ctx)
398 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
399 :
400 0 : err = decrypt_start (ctx, 0, cipher, plain);
401 0 : 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 30 : gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain)
409 : {
410 : gpgme_error_t err;
411 :
412 30 : TRACE_BEG2 (DEBUG_CTX, "gpgme_op_decrypt", ctx,
413 : "cipher=%p, plain=%p", cipher, plain);
414 :
415 30 : if (!ctx)
416 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
417 :
418 30 : err = decrypt_start (ctx, 1, cipher, plain);
419 29 : if (!err)
420 29 : err = _gpgme_wait_one (ctx);
421 31 : return TRACE_ERR (err);
422 : }
|