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
38 struct _gpgme_op_decrypt_result result;
43 /* A pointer to the next pointer of the last recipient in the list.
44 This makes appending new invalid signers painless while
45 preserving the order. */
46 gpgme_recipient_t *last_recipient_p;
51 release_op_data (void *hook)
53 op_data_t opd = (op_data_t) hook;
54 gpgme_recipient_t recipient = opd->result.recipients;
56 if (opd->result.unsupported_algorithm)
57 free (opd->result.unsupported_algorithm);
59 if (opd->result.file_name)
60 free (opd->result.file_name);
64 gpgme_recipient_t next = recipient->next;
71 gpgme_decrypt_result_t
72 gpgme_op_decrypt_result (gpgme_ctx_t ctx)
78 TRACE_BEG (DEBUG_CTX, "gpgme_op_decrypt_result", ctx);
80 err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
84 TRACE_SUC0 ("result=(null)");
88 if (_gpgme_debug_trace ())
90 gpgme_recipient_t rcp;
92 if (opd->result.unsupported_algorithm)
94 TRACE_LOG1 ("result: unsupported_algorithm: %s",
95 opd->result.unsupported_algorithm);
97 if (opd->result.wrong_key_usage)
99 TRACE_LOG ("result: wrong key usage");
101 rcp = opd->result.recipients;
104 TRACE_LOG3 ("result: recipient: keyid=%s, pubkey_algo=%i, "
105 "status=%s", rcp->keyid, rcp->pubkey_algo,
106 gpg_strerror (rcp->status));
109 if (opd->result.file_name)
111 TRACE_LOG1 ("result: original file name: %s", opd->result.file_name);
115 TRACE_SUC1 ("result=%p", &opd->result);
121 parse_enc_to (char *args, gpgme_recipient_t *recp)
123 gpgme_recipient_t rec;
127 rec = malloc (sizeof (*rec));
129 return gpg_error_from_syserror ();
132 rec->keyid = rec->_keyid;
135 for (i = 0; i < sizeof (rec->_keyid) - 1; i++)
137 if (args[i] == '\0' || args[i] == ' ')
140 rec->_keyid[i] = args[i];
142 rec->_keyid[i] = '\0';
145 if (*args != '\0' && *args != ' ')
148 return gpg_error (GPG_ERR_INV_ENGINE);
156 gpg_err_set_errno (0);
157 rec->pubkey_algo = strtol (args, &tail, 0);
158 if (errno || args == tail || *tail != ' ')
160 /* The crypto backend does not behave. */
162 return gpg_error (GPG_ERR_INV_ENGINE);
166 /* FIXME: The key length is always 0 right now, so no need to parse
175 _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
178 gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
183 err = _gpgme_passphrase_status_handler (priv, code, args);
187 err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
194 case GPGME_STATUS_EOF:
195 /* FIXME: These error values should probably be attributed to
196 the underlying crypto engine (as error source). */
198 return gpg_error (GPG_ERR_DECRYPT_FAILED);
200 return gpg_error (GPG_ERR_NO_DATA);
203 case GPGME_STATUS_DECRYPTION_OKAY:
207 case GPGME_STATUS_DECRYPTION_FAILED:
211 case GPGME_STATUS_ERROR:
212 /* Note that this is an informational status code which should
213 not lead to an error return unless it is something not
214 related to the backend. */
216 const char d_alg[] = "decrypt.algorithm";
217 const char k_alg[] = "decrypt.keyusage";
219 if (!strncmp (args, d_alg, sizeof (d_alg) - 1))
221 args += sizeof (d_alg) - 1;
225 if (gpg_err_code (atoi (args)) == GPG_ERR_UNSUPPORTED_ALGORITHM)
229 while (*args && *args != ' ')
234 end = strchr (args, ' ');
238 if (!(*args == '?' && *(args + 1) == '\0'))
240 opd->result.unsupported_algorithm = strdup (args);
241 if (!opd->result.unsupported_algorithm)
242 return gpg_error_from_syserror ();
246 else if (!strncmp (args, k_alg, sizeof (k_alg) - 1))
248 args += sizeof (k_alg) - 1;
252 if (gpg_err_code (atoi (args)) == GPG_ERR_WRONG_KEY_USAGE)
253 opd->result.wrong_key_usage = 1;
258 case GPGME_STATUS_ENC_TO:
259 err = parse_enc_to (args, opd->last_recipient_p);
263 opd->last_recipient_p = &(*opd->last_recipient_p)->next;
266 case GPGME_STATUS_NO_SECKEY:
268 gpgme_recipient_t rec = opd->result.recipients;
272 if (!strcmp (rec->keyid, args))
274 rec->status = gpg_error (GPG_ERR_NO_SECKEY);
279 /* FIXME: Is this ok? */
281 return gpg_error (GPG_ERR_INV_ENGINE);
285 case GPGME_STATUS_PLAINTEXT:
286 err = _gpgme_parse_plaintext (args, &opd->result.file_name);
299 decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
303 err = _gpgme_progress_status_handler (priv, code, args);
305 err = _gpgme_decrypt_status_handler (priv, code, args);
311 _gpgme_op_decrypt_init_result (gpgme_ctx_t ctx)
317 err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook,
318 sizeof (*opd), release_op_data);
323 opd->last_recipient_p = &opd->result.recipients;
329 decrypt_start (gpgme_ctx_t ctx, int synchronous,
330 gpgme_data_t cipher, gpgme_data_t plain)
334 err = _gpgme_op_reset (ctx, synchronous);
338 err = _gpgme_op_decrypt_init_result (ctx);
343 return gpg_error (GPG_ERR_NO_DATA);
345 return gpg_error (GPG_ERR_INV_VALUE);
350 if (ctx->passphrase_cb)
352 err = _gpgme_engine_set_command_handler
353 (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
358 _gpgme_engine_set_status_handler (ctx->engine, decrypt_status_handler, ctx);
360 return _gpgme_engine_op_decrypt (ctx->engine, cipher, plain);
365 gpgme_op_decrypt_start (gpgme_ctx_t ctx, gpgme_data_t cipher,
370 TRACE_BEG2 (DEBUG_CTX, "gpgme_op_decrypt_start", ctx,
371 "cipher=%p, plain=%p", cipher, plain);
372 err = decrypt_start (ctx, 0, cipher, plain);
373 return TRACE_ERR (err);
377 /* Decrypt ciphertext CIPHER within CTX and store the resulting
378 plaintext in PLAIN. */
380 gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain)
384 TRACE_BEG2 (DEBUG_CTX, "gpgme_op_decrypt", ctx,
385 "cipher=%p, plain=%p", cipher, plain);
386 err = decrypt_start (ctx, 1, cipher, plain);
388 err = _gpgme_wait_one (ctx);
389 return TRACE_ERR (err);