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
39 struct _gpgme_op_decrypt_result result;
41 /* The error code from a FAILURE status line or 0. */
42 gpg_error_t failure_code;
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;
55 release_op_data (void *hook)
57 op_data_t opd = (op_data_t) hook;
58 gpgme_recipient_t recipient = opd->result.recipients;
60 if (opd->result.unsupported_algorithm)
61 free (opd->result.unsupported_algorithm);
63 if (opd->result.file_name)
64 free (opd->result.file_name);
66 if (opd->result.session_key)
67 free (opd->result.session_key);
71 gpgme_recipient_t next = recipient->next;
78 gpgme_decrypt_result_t
79 gpgme_op_decrypt_result (gpgme_ctx_t ctx)
85 TRACE_BEG (DEBUG_CTX, "gpgme_op_decrypt_result", ctx);
87 err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
91 TRACE_SUC0 ("result=(null)");
95 if (_gpgme_debug_trace ())
97 gpgme_recipient_t rcp;
99 if (opd->result.unsupported_algorithm)
101 TRACE_LOG1 ("result: unsupported_algorithm: %s",
102 opd->result.unsupported_algorithm);
104 if (opd->result.wrong_key_usage)
106 TRACE_LOG ("result: wrong key usage");
108 rcp = opd->result.recipients;
111 TRACE_LOG3 ("result: recipient: keyid=%s, pubkey_algo=%i, "
112 "status=%s", rcp->keyid, rcp->pubkey_algo,
113 gpg_strerror (rcp->status));
116 if (opd->result.file_name)
118 TRACE_LOG1 ("result: original file name: %s", opd->result.file_name);
122 TRACE_SUC1 ("result=%p", &opd->result);
128 parse_enc_to (char *args, gpgme_recipient_t *recp, gpgme_protocol_t protocol)
130 gpgme_recipient_t rec;
134 rec = malloc (sizeof (*rec));
136 return gpg_error_from_syserror ();
139 rec->keyid = rec->_keyid;
142 for (i = 0; i < sizeof (rec->_keyid) - 1; i++)
144 if (args[i] == '\0' || args[i] == ' ')
147 rec->_keyid[i] = args[i];
149 rec->_keyid[i] = '\0';
152 if (*args != '\0' && *args != ' ')
155 return trace_gpg_error (GPG_ERR_INV_ENGINE);
163 gpg_err_set_errno (0);
164 rec->pubkey_algo = _gpgme_map_pk_algo (strtol (args, &tail, 0), protocol);
165 if (errno || args == tail || *tail != ' ')
167 /* The crypto backend does not behave. */
169 return trace_gpg_error (GPG_ERR_INV_ENGINE);
173 /* FIXME: The key length is always 0 right now, so no need to parse
182 _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
185 gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
190 err = _gpgme_passphrase_status_handler (priv, code, args);
194 err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
201 case GPGME_STATUS_FAILURE:
202 opd->failure_code = _gpgme_parse_failure (args);
205 case GPGME_STATUS_EOF:
206 /* FIXME: These error values should probably be attributed to
207 the underlying crypto engine (as error source). */
209 return gpg_error (GPG_ERR_DECRYPT_FAILED);
211 return gpg_error (GPG_ERR_NO_DATA);
212 else if (opd->failure_code)
213 return opd->failure_code;
216 case GPGME_STATUS_DECRYPTION_INFO:
217 /* Fixme: Provide a way to return the used symmetric algorithm. */
220 case GPGME_STATUS_DECRYPTION_OKAY:
224 case GPGME_STATUS_DECRYPTION_FAILED:
228 case GPGME_STATUS_ERROR:
229 /* Note that this is an informational status code which should
230 not lead to an error return unless it is something not
231 related to the backend. */
233 const char d_alg[] = "decrypt.algorithm";
234 const char k_alg[] = "decrypt.keyusage";
236 if (!strncmp (args, d_alg, sizeof (d_alg) - 1))
238 args += sizeof (d_alg) - 1;
242 if (gpg_err_code (atoi (args)) == GPG_ERR_UNSUPPORTED_ALGORITHM)
246 while (*args && *args != ' ')
251 end = strchr (args, ' ');
255 if (!(*args == '?' && *(args + 1) == '\0'))
257 opd->result.unsupported_algorithm = strdup (args);
258 if (!opd->result.unsupported_algorithm)
259 return gpg_error_from_syserror ();
263 else if (!strncmp (args, k_alg, sizeof (k_alg) - 1))
265 args += sizeof (k_alg) - 1;
269 if (gpg_err_code (atoi (args)) == GPG_ERR_WRONG_KEY_USAGE)
270 opd->result.wrong_key_usage = 1;
275 case GPGME_STATUS_ENC_TO:
276 err = parse_enc_to (args, opd->last_recipient_p, ctx->protocol);
280 opd->last_recipient_p = &(*opd->last_recipient_p)->next;
283 case GPGME_STATUS_SESSION_KEY:
284 if (opd->result.session_key)
285 free (opd->result.session_key);
286 opd->result.session_key = strdup(args);
289 case GPGME_STATUS_NO_SECKEY:
291 gpgme_recipient_t rec = opd->result.recipients;
295 if (!strcmp (rec->keyid, args))
297 rec->status = gpg_error (GPG_ERR_NO_SECKEY);
302 /* FIXME: Is this ok? */
304 return trace_gpg_error (GPG_ERR_INV_ENGINE);
308 case GPGME_STATUS_PLAINTEXT:
309 err = _gpgme_parse_plaintext (args, &opd->result.file_name);
314 case GPGME_STATUS_INQUIRE_MAXLEN:
315 if (ctx->status_cb && !ctx->full_status)
317 err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
332 decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
336 err = _gpgme_progress_status_handler (priv, code, args);
338 err = _gpgme_decrypt_status_handler (priv, code, args);
344 _gpgme_op_decrypt_init_result (gpgme_ctx_t ctx)
350 err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook,
351 sizeof (*opd), release_op_data);
356 opd->last_recipient_p = &opd->result.recipients;
362 decrypt_start (gpgme_ctx_t ctx, int synchronous,
363 gpgme_data_t cipher, gpgme_data_t plain)
367 err = _gpgme_op_reset (ctx, synchronous);
371 err = _gpgme_op_decrypt_init_result (ctx);
376 return gpg_error (GPG_ERR_NO_DATA);
378 return gpg_error (GPG_ERR_INV_VALUE);
383 if (ctx->passphrase_cb)
385 err = _gpgme_engine_set_command_handler
386 (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
391 _gpgme_engine_set_status_handler (ctx->engine, decrypt_status_handler, ctx);
393 return _gpgme_engine_op_decrypt (ctx->engine, cipher, plain,
394 ctx->export_session_keys,
395 ctx->override_session_key);
400 gpgme_op_decrypt_start (gpgme_ctx_t ctx, gpgme_data_t cipher,
405 TRACE_BEG2 (DEBUG_CTX, "gpgme_op_decrypt_start", ctx,
406 "cipher=%p, plain=%p", cipher, plain);
409 return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
411 err = decrypt_start (ctx, 0, cipher, plain);
412 return TRACE_ERR (err);
416 /* Decrypt ciphertext CIPHER within CTX and store the resulting
417 plaintext in PLAIN. */
419 gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain)
423 TRACE_BEG2 (DEBUG_CTX, "gpgme_op_decrypt", ctx,
424 "cipher=%p, plain=%p", cipher, plain);
427 return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
429 err = decrypt_start (ctx, 1, cipher, plain);
431 err = _gpgme_wait_one (ctx);
432 return TRACE_ERR (err);