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 25 : release_op_data (void *hook)
56 : {
57 25 : op_data_t opd = (op_data_t) hook;
58 25 : gpgme_recipient_t recipient = opd->result.recipients;
59 :
60 25 : if (opd->result.unsupported_algorithm)
61 0 : free (opd->result.unsupported_algorithm);
62 :
63 25 : if (opd->result.file_name)
64 2 : free (opd->result.file_name);
65 :
66 74 : while (recipient)
67 : {
68 24 : gpgme_recipient_t next = recipient->next;
69 24 : free (recipient);
70 24 : recipient = next;
71 : }
72 25 : }
73 :
74 :
75 : gpgme_decrypt_result_t
76 24 : gpgme_op_decrypt_result (gpgme_ctx_t ctx)
77 : {
78 : void *hook;
79 : op_data_t opd;
80 : gpgme_error_t err;
81 :
82 24 : TRACE_BEG (DEBUG_CTX, "gpgme_op_decrypt_result", ctx);
83 :
84 24 : err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
85 24 : opd = hook;
86 24 : 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 24 : if (opd->result.unsupported_algorithm)
97 : {
98 0 : TRACE_LOG1 ("result: unsupported_algorithm: %s",
99 : opd->result.unsupported_algorithm);
100 : }
101 24 : if (opd->result.wrong_key_usage)
102 : {
103 0 : TRACE_LOG ("result: wrong key usage");
104 : }
105 24 : rcp = opd->result.recipients;
106 72 : while (rcp)
107 : {
108 24 : TRACE_LOG3 ("result: recipient: keyid=%s, pubkey_algo=%i, "
109 : "status=%s", rcp->keyid, rcp->pubkey_algo,
110 : gpg_strerror (rcp->status));
111 24 : rcp = rcp->next;
112 : }
113 24 : if (opd->result.file_name)
114 : {
115 2 : TRACE_LOG1 ("result: original file name: %s", opd->result.file_name);
116 : }
117 : }
118 :
119 24 : TRACE_SUC1 ("result=%p", &opd->result);
120 24 : return &opd->result;
121 : }
122 :
123 :
124 : static gpgme_error_t
125 24 : 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 24 : rec = malloc (sizeof (*rec));
132 24 : if (!rec)
133 0 : return gpg_error_from_syserror ();
134 :
135 24 : rec->next = NULL;
136 24 : rec->keyid = rec->_keyid;
137 24 : rec->status = 0;
138 :
139 408 : for (i = 0; i < sizeof (rec->_keyid) - 1; i++)
140 : {
141 384 : if (args[i] == '\0' || args[i] == ' ')
142 : break;
143 :
144 384 : rec->_keyid[i] = args[i];
145 : }
146 24 : rec->_keyid[i] = '\0';
147 :
148 24 : args = &args[i];
149 24 : if (*args != '\0' && *args != ' ')
150 : {
151 0 : free (rec);
152 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
153 : }
154 :
155 72 : while (*args == ' ')
156 24 : args++;
157 :
158 24 : if (*args)
159 : {
160 24 : gpg_err_set_errno (0);
161 24 : rec->pubkey_algo = _gpgme_map_pk_algo (strtol (args, &tail, 0), protocol);
162 24 : 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 24 : *recp = rec;
174 24 : return 0;
175 : }
176 :
177 :
178 : gpgme_error_t
179 276 : _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
180 : char *args)
181 : {
182 276 : gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
183 : gpgme_error_t err;
184 : void *hook;
185 : op_data_t opd;
186 :
187 276 : err = _gpgme_passphrase_status_handler (priv, code, args);
188 276 : if (err)
189 0 : return err;
190 :
191 276 : err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
192 276 : opd = hook;
193 276 : if (err)
194 0 : return err;
195 :
196 276 : 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 25 : if (opd->failed)
206 0 : return gpg_error (GPG_ERR_DECRYPT_FAILED);
207 25 : else if (!opd->okay)
208 0 : return gpg_error (GPG_ERR_NO_DATA);
209 25 : else if (opd->failure_code)
210 0 : return opd->failure_code;
211 25 : break;
212 :
213 : case GPGME_STATUS_DECRYPTION_INFO:
214 : /* Fixme: Provide a way to return the used symmetric algorithm. */
215 24 : break;
216 :
217 : case GPGME_STATUS_DECRYPTION_OKAY:
218 25 : opd->okay = 1;
219 25 : 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 24 : err = parse_enc_to (args, opd->last_recipient_p, ctx->protocol);
274 24 : if (err)
275 0 : return err;
276 :
277 24 : opd->last_recipient_p = &(*opd->last_recipient_p)->next;
278 24 : break;
279 :
280 : case GPGME_STATUS_NO_SECKEY:
281 : {
282 0 : gpgme_recipient_t rec = opd->result.recipients;
283 :
284 0 : while (rec)
285 : {
286 0 : if (!strcmp (rec->keyid, args))
287 : {
288 0 : rec->status = gpg_error (GPG_ERR_NO_SECKEY);
289 0 : break;
290 : }
291 0 : rec = rec->next;
292 : }
293 : /* FIXME: Is this ok? */
294 0 : if (!rec)
295 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
296 : }
297 0 : break;
298 :
299 : case GPGME_STATUS_PLAINTEXT:
300 24 : err = _gpgme_parse_plaintext (args, &opd->result.file_name);
301 24 : if (err)
302 0 : return err;
303 24 : break;
304 :
305 : case GPGME_STATUS_INQUIRE_MAXLEN:
306 0 : if (ctx->status_cb)
307 : {
308 0 : err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
309 0 : if (err)
310 0 : return err;
311 : }
312 0 : break;
313 :
314 : default:
315 154 : break;
316 : }
317 :
318 276 : return 0;
319 : }
320 :
321 :
322 : static gpgme_error_t
323 260 : decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
324 : {
325 : gpgme_error_t err;
326 :
327 260 : err = _gpgme_progress_status_handler (priv, code, args);
328 260 : if (!err)
329 260 : err = _gpgme_decrypt_status_handler (priv, code, args);
330 260 : return err;
331 : }
332 :
333 :
334 : gpgme_error_t
335 25 : _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 25 : err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook,
342 : sizeof (*opd), release_op_data);
343 25 : opd = hook;
344 25 : if (err)
345 0 : return err;
346 :
347 25 : opd->last_recipient_p = &opd->result.recipients;
348 25 : return 0;
349 : }
350 :
351 :
352 : static gpgme_error_t
353 24 : 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 24 : err = _gpgme_op_reset (ctx, synchronous);
359 24 : if (err)
360 0 : return err;
361 :
362 24 : err = _gpgme_op_decrypt_init_result (ctx);
363 24 : if (err)
364 0 : return err;
365 :
366 24 : if (!cipher)
367 0 : return gpg_error (GPG_ERR_NO_DATA);
368 24 : if (!plain)
369 0 : return gpg_error (GPG_ERR_INV_VALUE);
370 :
371 24 : if (err)
372 0 : return err;
373 :
374 24 : if (ctx->passphrase_cb)
375 : {
376 23 : err = _gpgme_engine_set_command_handler
377 : (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
378 23 : if (err)
379 0 : return err;
380 : }
381 :
382 24 : _gpgme_engine_set_status_handler (ctx->engine, decrypt_status_handler, ctx);
383 :
384 24 : 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 24 : gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain)
409 : {
410 : gpgme_error_t err;
411 :
412 24 : TRACE_BEG2 (DEBUG_CTX, "gpgme_op_decrypt", ctx,
413 : "cipher=%p, plain=%p", cipher, plain);
414 :
415 24 : if (!ctx)
416 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
417 :
418 24 : err = decrypt_start (ctx, 1, cipher, plain);
419 24 : if (!err)
420 24 : err = _gpgme_wait_one (ctx);
421 24 : return TRACE_ERR (err);
422 : }
|