json: Add command "decrypt" to gpgme-json.
[gpgme.git] / src / encrypt.c
1 /* encrypt.c - Encrypt 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 "gpgme.h"
30 #include "debug.h"
31 #include "context.h"
32 #include "ops.h"
33
34 \f
35 typedef struct
36 {
37   struct _gpgme_op_encrypt_result result;
38
39   /* The error code from a FAILURE status line or 0.  */
40   gpg_error_t failure_code;
41
42   /* The fingerprint from the last KEY_CONSIDERED status line.  */
43   char *kc_fpr;
44
45   /* The flags from the last KEY_CONSIDERED status line.  */
46   unsigned int kc_flags;
47
48   /* A pointer to the next pointer of the last invalid recipient in
49      the list.  This makes appending new invalid recipients painless
50      while preserving the order.  */
51   gpgme_invalid_key_t *lastp;
52 } *op_data_t;
53
54
55 static void
56 release_op_data (void *hook)
57 {
58   op_data_t opd = (op_data_t) hook;
59   gpgme_invalid_key_t invalid_recipient = opd->result.invalid_recipients;
60
61   while (invalid_recipient)
62     {
63       gpgme_invalid_key_t next = invalid_recipient->next;
64       if (invalid_recipient->fpr)
65         free (invalid_recipient->fpr);
66       free (invalid_recipient);
67       invalid_recipient = next;
68     }
69
70   free (opd->kc_fpr);
71 }
72
73
74 gpgme_encrypt_result_t
75 gpgme_op_encrypt_result (gpgme_ctx_t ctx)
76 {
77   void *hook;
78   op_data_t opd;
79   gpgme_error_t err;
80
81   TRACE_BEG (DEBUG_CTX, "gpgme_op_encrypt_result", ctx);
82
83   err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, &hook, -1, NULL);
84   opd = hook;
85
86   if (err || !opd)
87     {
88       TRACE_SUC0 ("result=(null)");
89       return NULL;
90     }
91
92   if (_gpgme_debug_trace ())
93     {
94       gpgme_invalid_key_t invkeys = opd->result.invalid_recipients;
95       int i = 0;
96
97       while (invkeys)
98         {
99           TRACE_LOG3 ("invalid_recipients[%i] = %s (%s)",
100                       i, invkeys->fpr ? invkeys->fpr : "(null)",
101                       gpg_strerror (invkeys->reason));
102           invkeys = invkeys->next;
103           i++;
104         }
105     }
106
107   TRACE_SUC1 ("result=%p", &opd->result);
108   return &opd->result;
109 }
110
111 \f
112 gpgme_error_t
113 _gpgme_encrypt_status_handler (void *priv, gpgme_status_code_t code,
114                                char *args)
115 {
116   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
117   gpgme_error_t err;
118   void *hook;
119   op_data_t opd;
120
121   err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, &hook, -1, NULL);
122   opd = hook;
123   if (err)
124     return err;
125
126   switch (code)
127     {
128     case GPGME_STATUS_FAILURE:
129       opd->failure_code = _gpgme_parse_failure (args);
130       break;
131
132     case GPGME_STATUS_EOF:
133       if (opd->result.invalid_recipients)
134         return gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
135       if (opd->failure_code)
136         return opd->failure_code;
137       break;
138
139     case GPGME_STATUS_KEY_CONSIDERED:
140       /* This is emitted during gpg's key lookup to give information
141        * about the lookup results.  We store the last one so it can be
142        * used in connection with INV_RECP.  */
143       free (opd->kc_fpr);
144       opd->kc_fpr = NULL;
145       err = _gpgme_parse_key_considered (args, &opd->kc_fpr, &opd->kc_flags);
146       if (err)
147         return err;
148       break;
149
150     case GPGME_STATUS_INV_RECP:
151       err = _gpgme_parse_inv_recp (args, 0, opd->kc_fpr, opd->kc_flags,
152                                    opd->lastp);
153       if (err)
154         return err;
155
156       opd->lastp = &(*opd->lastp)->next;
157       free (opd->kc_fpr);
158       opd->kc_fpr = NULL;
159       break;
160
161     case GPGME_STATUS_NO_RECP:
162       /* Should not happen, because we require at least one recipient.  */
163       return gpg_error (GPG_ERR_GENERAL);
164
165     default:
166       break;
167     }
168   return 0;
169 }
170
171
172 static gpgme_error_t
173 encrypt_sym_status_handler (void *priv, gpgme_status_code_t code, char *args)
174 {
175   gpgme_error_t err;
176
177   err = _gpgme_progress_status_handler (priv, code, args);
178   if (!err)
179     err = _gpgme_passphrase_status_handler (priv, code, args);
180   return err;
181 }
182
183
184 static gpgme_error_t
185 encrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
186 {
187   gpgme_error_t err;
188
189   err = _gpgme_progress_status_handler (priv, code, args);
190   if (!err)
191     err = _gpgme_encrypt_status_handler (priv, code, args);
192
193   return err;
194 }
195
196
197 gpgme_error_t
198 _gpgme_op_encrypt_init_result (gpgme_ctx_t ctx)
199 {
200   gpgme_error_t err;
201   void *hook;
202   op_data_t opd;
203
204   err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, &hook, sizeof (*opd),
205                                release_op_data);
206   opd = hook;
207   if (err)
208     return err;
209
210   opd->lastp = &opd->result.invalid_recipients;
211   return 0;
212 }
213
214
215 static gpgme_error_t
216 encrypt_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
217                const char *recpstring,
218                gpgme_encrypt_flags_t flags,
219                gpgme_data_t plain, gpgme_data_t cipher)
220 {
221   gpgme_error_t err;
222   int symmetric = 0;
223
224   err = _gpgme_op_reset (ctx, synchronous);
225   if (err)
226     return err;
227
228   err = _gpgme_op_encrypt_init_result (ctx);
229   if (err)
230     return err;
231
232   symmetric = (!recp && !recpstring) || (flags & GPGME_ENCRYPT_SYMMETRIC);
233
234   if (!plain)
235     return gpg_error (GPG_ERR_NO_DATA);
236   if (!cipher)
237     return gpg_error (GPG_ERR_INV_VALUE);
238   if (recp && !*recp)
239     return gpg_error (GPG_ERR_INV_VALUE);
240
241   if (symmetric && ctx->passphrase_cb)
242     {
243       /* Symmetric encryption requires a passphrase.  */
244       err = _gpgme_engine_set_command_handler
245         (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
246       if (err)
247         return err;
248     }
249
250   _gpgme_engine_set_status_handler (ctx->engine,
251                                     symmetric
252                                     ? encrypt_sym_status_handler
253                                     : encrypt_status_handler,
254                                     ctx);
255
256   return _gpgme_engine_op_encrypt (ctx->engine, recp, recpstring,
257                                    flags, plain, cipher, ctx->use_armor);
258 }
259
260
261 /* Old version of gpgme_op_encrypt_ext without RECPSTRING.  */
262 gpgme_error_t
263 gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[],
264                   gpgme_encrypt_flags_t flags,
265                   gpgme_data_t plain, gpgme_data_t cipher)
266 {
267   return gpgme_op_encrypt_ext (ctx, recp, NULL, flags, plain, cipher);
268 }
269
270
271 /* Old version of gpgme_op_encrypt_ext_start without RECPSTRING.  */
272 gpgme_error_t
273 gpgme_op_encrypt_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
274                         gpgme_encrypt_flags_t flags,
275                         gpgme_data_t plain, gpgme_data_t cipher)
276 {
277   return gpgme_op_encrypt_ext_start (ctx, recp, NULL, flags, plain, cipher);
278 }
279
280
281 /* Encrypt plaintext PLAIN within CTX for the recipients RECP and
282  * store the resulting ciphertext in CIPHER.  RECPSTRING can be used
283  * instead of the RECP array to directly specify recipients as LF
284  * delimited strings; these may be any kind of recipient specification
285  * patterns as supported by the backend.  */
286 gpgme_error_t
287 gpgme_op_encrypt_ext (gpgme_ctx_t ctx, gpgme_key_t recp[],
288                       const char *recpstring,
289                       gpgme_encrypt_flags_t flags,
290                       gpgme_data_t plain, gpgme_data_t cipher)
291 {
292   gpgme_error_t err;
293
294   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt", ctx,
295               "flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher);
296
297   if (!ctx)
298     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
299
300   if (_gpgme_debug_trace () && (recp || recpstring))
301     {
302       if (recp)
303         {
304           int i = 0;
305
306           while (recp[i])
307             {
308               TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
309                       (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
310                           recp[i]->subkeys->fpr : "invalid");
311               i++;
312             }
313         }
314       else
315         {
316           TRACE_LOG1 ("recipients = '%s'", recpstring);
317         }
318     }
319
320   err = encrypt_start (ctx, 1, recp, recpstring, flags, plain, cipher);
321   if (!err)
322     err = _gpgme_wait_one (ctx);
323   return TRACE_ERR (err);
324 }
325
326
327 gpgme_error_t
328 gpgme_op_encrypt_ext_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
329                             const char *recpstring,
330                             gpgme_encrypt_flags_t flags,
331                             gpgme_data_t plain, gpgme_data_t cipher)
332 {
333   gpgme_error_t err;
334
335   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_start", ctx,
336               "flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher);
337
338   if (!ctx)
339     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
340
341   if (_gpgme_debug_trace () && (recp || recpstring))
342     {
343       if (recp)
344         {
345           int i = 0;
346
347           while (recp[i])
348             {
349               TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
350                           (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
351                           recp[i]->subkeys->fpr : "invalid");
352               i++;
353             }
354         }
355       else
356         {
357           TRACE_LOG1 ("recipients = '%s'", recpstring);
358         }
359     }
360
361   err = encrypt_start (ctx, 0, recp, recpstring, flags, plain, cipher);
362   return TRACE_ERR (err);
363 }