1 /* decrypt.c - Decrypt function.
2 Copyright (C) 2000 Werner Koch (dd9jn)
3 Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH
5 This file is part of GPGME.
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.
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.
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
34 #include "extra-stati.h"
40 struct _gpgme_op_decrypt_result result;
45 /* A pointer to the next pointer of the last recipient in the list.
46 This makes appending new invalid signers painless while
47 preserving the order. */
48 gpgme_recipient_t *last_recipient_p;
53 release_op_data (void *hook)
55 op_data_t opd = (op_data_t) hook;
56 gpgme_recipient_t recipient = opd->result.recipients;
58 if (opd->result.unsupported_algorithm)
59 free (opd->result.unsupported_algorithm);
61 if (opd->result.file_name)
62 free (opd->result.file_name);
66 gpgme_recipient_t next = recipient->next;
73 gpgme_decrypt_result_t
74 gpgme_op_decrypt_result (gpgme_ctx_t ctx)
80 TRACE_BEG (DEBUG_CTX, "gpgme_op_decrypt_result", ctx);
82 err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
86 TRACE_SUC0 ("result=(null)");
90 if (_gpgme_debug_trace ())
92 gpgme_recipient_t rcp;
94 if (opd->result.unsupported_algorithm)
96 TRACE_LOG1 ("result: unsupported_algorithm: %s",
97 opd->result.unsupported_algorithm);
99 if (opd->result.wrong_key_usage)
101 TRACE_LOG ("result: wrong key usage");
103 rcp = opd->result.recipients;
106 TRACE_LOG3 ("result: recipient: keyid=%s, pubkey_algo=%i, "
107 "status=%s", rcp->keyid, rcp->pubkey_algo,
108 gpg_strerror (rcp->status));
111 if (opd->result.file_name)
113 TRACE_LOG1 ("result: original file name: %s", opd->result.file_name);
117 TRACE_SUC1 ("result=%p", &opd->result);
123 parse_enc_to (char *args, gpgme_recipient_t *recp)
125 gpgme_recipient_t rec;
129 rec = malloc (sizeof (*rec));
131 return gpg_error_from_syserror ();
134 rec->keyid = rec->_keyid;
137 for (i = 0; i < sizeof (rec->_keyid) - 1; i++)
139 if (args[i] == '\0' || args[i] == ' ')
142 rec->_keyid[i] = args[i];
144 rec->_keyid[i] = '\0';
147 if (*args != '\0' && *args != ' ')
150 return gpg_error (GPG_ERR_INV_ENGINE);
158 gpg_err_set_errno (0);
159 rec->pubkey_algo = strtol (args, &tail, 0);
160 if (errno || args == tail || *tail != ' ')
162 /* The crypto backend does not behave. */
164 return gpg_error (GPG_ERR_INV_ENGINE);
168 /* FIXME: The key length is always 0 right now, so no need to parse
177 _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
180 gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
185 err = _gpgme_passphrase_status_handler (priv, code, args);
189 err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
196 case GPGME_STATUS_EOF:
197 /* FIXME: These error values should probably be attributed to
198 the underlying crypto engine (as error source). */
200 return gpg_error (GPG_ERR_DECRYPT_FAILED);
202 return gpg_error (GPG_ERR_NO_DATA);
205 case GPGME_STATUS_DECRYPTION_INFO:
206 /* Fixme: Provide a way to return the used symmetric algorithm. */
209 case GPGME_STATUS_DECRYPTION_OKAY:
213 case GPGME_STATUS_DECRYPTION_FAILED:
217 case GPGME_STATUS_ERROR:
218 /* Note that this is an informational status code which should
219 not lead to an error return unless it is something not
220 related to the backend. */
222 const char d_alg[] = "decrypt.algorithm";
223 const char k_alg[] = "decrypt.keyusage";
225 if (!strncmp (args, d_alg, sizeof (d_alg) - 1))
227 args += sizeof (d_alg) - 1;
231 if (gpg_err_code (atoi (args)) == GPG_ERR_UNSUPPORTED_ALGORITHM)
235 while (*args && *args != ' ')
240 end = strchr (args, ' ');
244 if (!(*args == '?' && *(args + 1) == '\0'))
246 opd->result.unsupported_algorithm = strdup (args);
247 if (!opd->result.unsupported_algorithm)
248 return gpg_error_from_syserror ();
252 else if (!strncmp (args, k_alg, sizeof (k_alg) - 1))
254 args += sizeof (k_alg) - 1;
258 if (gpg_err_code (atoi (args)) == GPG_ERR_WRONG_KEY_USAGE)
259 opd->result.wrong_key_usage = 1;
264 case GPGME_STATUS_ENC_TO:
265 err = parse_enc_to (args, opd->last_recipient_p);
269 opd->last_recipient_p = &(*opd->last_recipient_p)->next;
272 case GPGME_STATUS_NO_SECKEY:
274 gpgme_recipient_t rec = opd->result.recipients;
278 if (!strcmp (rec->keyid, args))
280 rec->status = gpg_error (GPG_ERR_NO_SECKEY);
285 /* FIXME: Is this ok? */
287 return gpg_error (GPG_ERR_INV_ENGINE);
291 case GPGME_STATUS_PLAINTEXT:
292 err = _gpgme_parse_plaintext (args, &opd->result.file_name);
305 decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
309 err = _gpgme_progress_status_handler (priv, code, args);
311 err = _gpgme_decrypt_status_handler (priv, code, args);
317 _gpgme_op_decrypt_init_result (gpgme_ctx_t ctx)
323 err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook,
324 sizeof (*opd), release_op_data);
329 opd->last_recipient_p = &opd->result.recipients;
335 decrypt_start (gpgme_ctx_t ctx, int synchronous,
336 gpgme_data_t cipher, gpgme_data_t plain)
340 err = _gpgme_op_reset (ctx, synchronous);
344 err = _gpgme_op_decrypt_init_result (ctx);
349 return gpg_error (GPG_ERR_NO_DATA);
351 return gpg_error (GPG_ERR_INV_VALUE);
356 if (ctx->passphrase_cb)
358 err = _gpgme_engine_set_command_handler
359 (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
364 _gpgme_engine_set_status_handler (ctx->engine, decrypt_status_handler, ctx);
366 return _gpgme_engine_op_decrypt (ctx->engine, cipher, plain);
371 gpgme_op_decrypt_start (gpgme_ctx_t ctx, gpgme_data_t cipher,
376 TRACE_BEG2 (DEBUG_CTX, "gpgme_op_decrypt_start", ctx,
377 "cipher=%p, plain=%p", cipher, plain);
380 return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
382 err = decrypt_start (ctx, 0, cipher, plain);
383 return TRACE_ERR (err);
387 /* Decrypt ciphertext CIPHER within CTX and store the resulting
388 plaintext in PLAIN. */
390 gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain)
394 TRACE_BEG2 (DEBUG_CTX, "gpgme_op_decrypt", ctx,
395 "cipher=%p, plain=%p", cipher, plain);
398 return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
400 err = decrypt_start (ctx, 1, cipher, plain);
402 err = _gpgme_wait_one (ctx);
403 return TRACE_ERR (err);