e91079910d835e7821db777bbbc8da0b9f8df11c
[gpgme.git] / src / sign.c
1 /* sign.c - Signing function.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004, 2007 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 /* Suppress warning for accessing deprecated member "class".  */
30 #define _GPGME_IN_GPGME 1
31 #include "gpgme.h"
32 #include "context.h"
33 #include "ops.h"
34 #include "util.h"
35 #include "debug.h"
36
37 \f
38 typedef struct
39 {
40   struct _gpgme_op_sign_result result;
41
42   /* A pointer to the next pointer of the last invalid signer in
43      the list.  This makes appending new invalid signers painless
44      while preserving the order.  */
45   gpgme_invalid_key_t *last_signer_p;
46
47   /* Likewise for signature information.  */
48   gpgme_new_signature_t *last_sig_p;
49
50   /* Flags used while processing the status lines.  */
51   unsigned int ignore_inv_recp:1;
52   unsigned int inv_sgnr_seen:1;
53   unsigned int sig_created_seen:1;
54 } *op_data_t;
55
56
57 static void
58 release_op_data (void *hook)
59 {
60   op_data_t opd = (op_data_t) hook;
61   gpgme_invalid_key_t invalid_signer = opd->result.invalid_signers;
62   gpgme_new_signature_t sig = opd->result.signatures;
63
64   while (invalid_signer)
65     {
66       gpgme_invalid_key_t next = invalid_signer->next;
67       if (invalid_signer->fpr)
68         free (invalid_signer->fpr);
69       free (invalid_signer);
70       invalid_signer = next;
71     }
72
73   while (sig)
74     {
75       gpgme_new_signature_t next = sig->next;
76       free (sig->fpr);
77       free (sig);
78       sig = next;
79     }
80 }
81
82
83 gpgme_sign_result_t
84 gpgme_op_sign_result (gpgme_ctx_t ctx)
85 {
86   void *hook;
87   op_data_t opd;
88   gpgme_error_t err;
89
90   TRACE_BEG (DEBUG_CTX, "gpgme_op_sign_result", ctx);
91
92   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, -1, NULL);
93   opd = hook;
94   if (err || !opd)
95     {
96       TRACE_SUC0 ("result=(null)");
97       return NULL;
98     }
99
100   if (_gpgme_debug_trace ())
101     {
102       gpgme_invalid_key_t inv_key = opd->result.invalid_signers;
103       gpgme_new_signature_t sig = opd->result.signatures;
104       int inv_signers = 0;
105       int signatures = 0;
106
107       while (inv_key)
108         {
109           inv_signers++;
110           inv_key = inv_key->next;
111         }
112       while (sig)
113         {
114           signatures++;
115           sig = sig->next;
116         }
117
118       TRACE_LOG2 ("result: invalid signers: %i, signatures: %i",
119                   inv_signers, signatures);
120       inv_key = opd->result.invalid_signers;
121       while (inv_key)
122         {
123           TRACE_LOG3 ("result: invalid signer: fpr=%s, reason=%s <%s>",
124                       inv_key->fpr, gpgme_strerror (inv_key->reason),
125                       gpgme_strsource (inv_key->reason));
126           inv_key = inv_key->next;
127         }
128       sig = opd->result.signatures;
129       while (sig)
130         {
131           TRACE_LOG6 ("result: signature: type=%i, pubkey_algo=%i, "
132                       "hash_algo=%i, timestamp=%li, fpr=%s, sig_class=%i",
133                       sig->type, sig->pubkey_algo, sig->hash_algo,
134                       sig->timestamp, sig->fpr, sig->sig_class);
135           sig = sig->next;
136         }
137     }
138
139   TRACE_SUC1 ("result=%p", &opd->result);
140   return &opd->result;
141 }
142
143 \f
144 static gpgme_error_t
145 parse_sig_created (char *args, gpgme_new_signature_t *sigp)
146 {
147   gpgme_new_signature_t sig;
148   char *tail;
149
150   sig = malloc (sizeof (*sig));
151   if (!sig)
152     return gpg_error_from_syserror ();
153
154   sig->next = NULL;
155   switch (*args)
156     {
157     case 'S':
158       sig->type = GPGME_SIG_MODE_NORMAL;
159       break;
160
161     case 'D':
162       sig->type = GPGME_SIG_MODE_DETACH;
163       break;
164
165     case 'C':
166       sig->type = GPGME_SIG_MODE_CLEAR;
167       break;
168
169     default:
170       /* The backend engine is not behaving.  */
171       free (sig);
172       return trace_gpg_error (GPG_ERR_INV_ENGINE);
173     }
174
175   args++;
176   if (*args != ' ')
177     {
178       free (sig);
179       return trace_gpg_error (GPG_ERR_INV_ENGINE);
180     }
181
182   gpg_err_set_errno (0);
183   sig->pubkey_algo = strtol (args, &tail, 0);
184   if (errno || args == tail || *tail != ' ')
185     {
186       /* The crypto backend does not behave.  */
187       free (sig);
188       return trace_gpg_error (GPG_ERR_INV_ENGINE);
189     }
190   args = tail;
191
192   sig->hash_algo = strtol (args, &tail, 0);
193   if (errno || args == tail || *tail != ' ')
194     {
195       /* The crypto backend does not behave.  */
196       free (sig);
197       return trace_gpg_error (GPG_ERR_INV_ENGINE);
198     }
199   args = tail;
200
201   sig->sig_class = strtol (args, &tail, 0);
202   sig->class = sig->sig_class;
203   sig->_obsolete_class = sig->sig_class;
204   if (errno || args == tail || *tail != ' ')
205     {
206       /* The crypto backend does not behave.  */
207       free (sig);
208       return trace_gpg_error (GPG_ERR_INV_ENGINE);
209     }
210   args = tail;
211
212   sig->timestamp = _gpgme_parse_timestamp (args, &tail);
213   if (sig->timestamp == -1 || args == tail || *tail != ' ')
214     {
215       /* The crypto backend does not behave.  */
216       free (sig);
217       return trace_gpg_error (GPG_ERR_INV_ENGINE);
218     }
219   args = tail;
220   while (*args == ' ')
221     args++;
222
223   if (!*args)
224     {
225       /* The crypto backend does not behave.  */
226       free (sig);
227       return trace_gpg_error (GPG_ERR_INV_ENGINE);
228     }
229
230   tail = strchr (args, ' ');
231   if (tail)
232     *tail = '\0';
233
234   sig->fpr = strdup (args);
235   if (!sig->fpr)
236     {
237       free (sig);
238       return gpg_error_from_syserror ();
239     }
240   *sigp = sig;
241   return 0;
242 }
243
244
245 gpgme_error_t
246 _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
247 {
248   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
249   gpgme_error_t err;
250   void *hook;
251   op_data_t opd;
252
253   err = _gpgme_passphrase_status_handler (priv, code, args);
254   if (err)
255     return err;
256
257   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, -1, NULL);
258   opd = hook;
259   if (err)
260     return err;
261
262   switch (code)
263     {
264     case GPGME_STATUS_SIG_CREATED:
265       opd->sig_created_seen = 1;
266       err = parse_sig_created (args, opd->last_sig_p);
267       if (err)
268         return err;
269
270       opd->last_sig_p = &(*opd->last_sig_p)->next;
271       break;
272
273     case GPGME_STATUS_INV_RECP:
274       if (opd->inv_sgnr_seen && opd->ignore_inv_recp)
275         break;
276       /* FALLTROUGH */
277     case GPGME_STATUS_INV_SGNR:
278       if (code == GPGME_STATUS_INV_SGNR)
279         opd->inv_sgnr_seen = 1;
280       err = _gpgme_parse_inv_recp (args, opd->last_signer_p);
281       if (err)
282         return err;
283
284       opd->last_signer_p = &(*opd->last_signer_p)->next;
285       break;
286
287     case GPGME_STATUS_EOF:
288       /* The UI server does not send information about the created
289          signature.  This is irrelevant for this protocol and thus we
290          should not check for that.  */
291       if (opd->result.invalid_signers)
292         err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
293       else if (!opd->sig_created_seen
294                && ctx->protocol != GPGME_PROTOCOL_UISERVER)
295         err = gpg_error (GPG_ERR_GENERAL);
296       break;
297
298     default:
299       break;
300     }
301   return err;
302 }
303
304
305 static gpgme_error_t
306 sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
307 {
308   gpgme_error_t err;
309
310   err = _gpgme_progress_status_handler (priv, code, args);
311   if (!err)
312     err = _gpgme_sign_status_handler (priv, code, args);
313   return err;
314 }
315
316
317 static gpgme_error_t
318 sign_init_result (gpgme_ctx_t ctx, int ignore_inv_recp)
319 {
320   gpgme_error_t err;
321   void *hook;
322   op_data_t opd;
323
324   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook,
325                                sizeof (*opd), release_op_data);
326   opd = hook;
327   if (err)
328     return err;
329   opd->last_signer_p = &opd->result.invalid_signers;
330   opd->last_sig_p = &opd->result.signatures;
331   opd->ignore_inv_recp = !!ignore_inv_recp;
332   opd->inv_sgnr_seen = 0;
333   opd->sig_created_seen = 0;
334   return 0;
335 }
336
337 gpgme_error_t
338 _gpgme_op_sign_init_result (gpgme_ctx_t ctx)
339 {
340   return sign_init_result (ctx, 0);
341 }
342
343
344 static gpgme_error_t
345 sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t plain,
346             gpgme_data_t sig, gpgme_sig_mode_t mode)
347 {
348   gpgme_error_t err;
349
350   err = _gpgme_op_reset (ctx, synchronous);
351   if (err)
352     return err;
353
354   /* If we are using the CMS protocol, we ignore the INV_RECP status
355      code if a newer GPGSM is in use.  GPGMS does not support combined
356      sign+encrypt and thus this can't harm.  */
357   err = sign_init_result (ctx, (ctx->protocol == GPGME_PROTOCOL_CMS));
358   if (err)
359     return err;
360
361   if (mode != GPGME_SIG_MODE_NORMAL && mode != GPGME_SIG_MODE_DETACH
362       && mode != GPGME_SIG_MODE_CLEAR)
363     return gpg_error (GPG_ERR_INV_VALUE);
364
365   if (!plain)
366     return gpg_error (GPG_ERR_NO_DATA);
367   if (!sig)
368     return gpg_error (GPG_ERR_INV_VALUE);
369
370   if (ctx->passphrase_cb)
371     {
372       err = _gpgme_engine_set_command_handler
373         (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
374       if (err)
375         return err;
376     }
377
378   _gpgme_engine_set_status_handler (ctx->engine, sign_status_handler,
379                                     ctx);
380
381   return _gpgme_engine_op_sign (ctx->engine, plain, sig, mode, ctx->use_armor,
382                                 ctx->use_textmode, ctx->include_certs,
383                                 ctx /* FIXME */);
384 }
385
386
387 /* Sign the plaintext PLAIN and store the signature in SIG.  */
388 gpgme_error_t
389 gpgme_op_sign_start (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
390                      gpgme_sig_mode_t mode)
391 {
392   gpg_error_t err;
393   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_sign_start", ctx,
394               "plain=%p, sig=%p, mode=%i", plain, sig, mode);
395
396   if (!ctx)
397     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
398
399   err = sign_start (ctx, 0, plain, sig, mode);
400   return TRACE_ERR (err);
401 }
402
403
404 /* Sign the plaintext PLAIN and store the signature in SIG.  */
405 gpgme_error_t
406 gpgme_op_sign (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
407                gpgme_sig_mode_t mode)
408 {
409   gpgme_error_t err;
410
411   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_sign", ctx,
412               "plain=%p, sig=%p, mode=%i", plain, sig, mode);
413
414   if (!ctx)
415     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
416
417   err = sign_start (ctx, 1, plain, sig, mode);
418   if (!err)
419     err = _gpgme_wait_one (ctx);
420   return TRACE_ERR (err);
421 }