15092049a4f89cbfa8bc25e785999ac64767cebe
[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 gpg_error (GPG_ERR_INV_ENGINE);
173     }
174
175   args++;
176   if (*args != ' ')
177     {
178       free (sig);
179       return 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 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 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 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 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 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       int saved_errno = errno;
238       free (sig);
239       return gpg_error_from_errno (saved_errno);
240     }
241   *sigp = sig;
242   return 0;
243 }
244
245
246 gpgme_error_t
247 _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
248 {
249   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
250   gpgme_error_t err;
251   void *hook;
252   op_data_t opd;
253
254   err = _gpgme_passphrase_status_handler (priv, code, args);
255   if (err)
256     return err;
257
258   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, -1, NULL);
259   opd = hook;
260   if (err)
261     return err;
262
263   switch (code)
264     {
265     case GPGME_STATUS_SIG_CREATED:
266       opd->sig_created_seen = 1;
267       err = parse_sig_created (args, opd->last_sig_p);
268       if (err)
269         return err;
270
271       opd->last_sig_p = &(*opd->last_sig_p)->next;
272       break;
273
274     case GPGME_STATUS_INV_RECP:
275       if (opd->inv_sgnr_seen && opd->ignore_inv_recp)
276         break;
277       /* FALLTROUGH */
278     case GPGME_STATUS_INV_SGNR:
279       if (code == GPGME_STATUS_INV_SGNR)
280         opd->inv_sgnr_seen = 1;
281       err = _gpgme_parse_inv_recp (args, opd->last_signer_p);
282       if (err)
283         return err;
284
285       opd->last_signer_p = &(*opd->last_signer_p)->next;
286       break;
287
288     case GPGME_STATUS_EOF:
289       /* The UI server does not send information about the created
290          signature.  This is irrelevant for this protocol and thus we
291          should not check for that.  */
292       if (opd->result.invalid_signers)
293         err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
294       else if (!opd->sig_created_seen
295                && ctx->protocol != GPGME_PROTOCOL_UISERVER)
296         err = gpg_error (GPG_ERR_GENERAL);
297       break;
298
299     default:
300       break;
301     }
302   return err;
303 }
304
305
306 static gpgme_error_t
307 sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
308 {
309   gpgme_error_t err;
310
311   err = _gpgme_progress_status_handler (priv, code, args);
312   if (!err)
313     err = _gpgme_sign_status_handler (priv, code, args);
314   return err;
315 }
316
317
318 static gpgme_error_t
319 sign_init_result (gpgme_ctx_t ctx, int ignore_inv_recp)
320 {
321   gpgme_error_t err;
322   void *hook;
323   op_data_t opd;
324
325   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook,
326                                sizeof (*opd), release_op_data);
327   opd = hook;
328   if (err)
329     return err;
330   opd->last_signer_p = &opd->result.invalid_signers;
331   opd->last_sig_p = &opd->result.signatures;
332   opd->ignore_inv_recp = !!ignore_inv_recp;
333   opd->inv_sgnr_seen = 0;
334   opd->sig_created_seen = 0;
335   return 0;
336 }
337
338 gpgme_error_t
339 _gpgme_op_sign_init_result (gpgme_ctx_t ctx)
340 {
341   return sign_init_result (ctx, 0);
342 }
343
344
345 static gpgme_error_t
346 sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t plain,
347             gpgme_data_t sig, gpgme_sig_mode_t mode)
348 {
349   gpgme_error_t err;
350
351   err = _gpgme_op_reset (ctx, synchronous);
352   if (err)
353     return err;
354
355   /* If we are using the CMS protocol, we ignore the INV_RECP status
356      code if a newer GPGSM is in use.  GPGMS does not support combined
357      sign+encrypt and thus this can't harm.  */
358   err = sign_init_result (ctx, (ctx->protocol == GPGME_PROTOCOL_CMS));
359   if (err)
360     return err;
361
362   if (mode != GPGME_SIG_MODE_NORMAL && mode != GPGME_SIG_MODE_DETACH
363       && mode != GPGME_SIG_MODE_CLEAR)
364     return gpg_error (GPG_ERR_INV_VALUE);
365
366   if (!plain)
367     return gpg_error (GPG_ERR_NO_DATA);
368   if (!sig)
369     return gpg_error (GPG_ERR_INV_VALUE);
370
371   if (ctx->passphrase_cb)
372     {
373       err = _gpgme_engine_set_command_handler
374         (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
375       if (err)
376         return err;
377     }
378
379   _gpgme_engine_set_status_handler (ctx->engine, sign_status_handler,
380                                     ctx);
381
382   return _gpgme_engine_op_sign (ctx->engine, plain, sig, mode, ctx->use_armor,
383                                 ctx->use_textmode, ctx->include_certs,
384                                 ctx /* FIXME */);
385 }
386
387
388 /* Sign the plaintext PLAIN and store the signature in SIG.  */
389 gpgme_error_t
390 gpgme_op_sign_start (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
391                      gpgme_sig_mode_t mode)
392 {
393   gpg_error_t err;
394   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_sign_start", ctx,
395               "plain=%p, sig=%p, mode=%i", plain, sig, mode);
396
397   if (!ctx)
398     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
399
400   err = sign_start (ctx, 0, plain, sig, mode);
401   return TRACE_ERR (err);
402 }
403
404
405 /* Sign the plaintext PLAIN and store the signature in SIG.  */
406 gpgme_error_t
407 gpgme_op_sign (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
408                gpgme_sig_mode_t mode)
409 {
410   gpgme_error_t err;
411
412   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_sign", ctx,
413               "plain=%p, sig=%p, mode=%i", plain, sig, mode);
414
415   if (!ctx)
416     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
417
418   err = sign_start (ctx, 1, plain, sig, mode);
419   if (!err)
420     err = _gpgme_wait_one (ctx);
421   return TRACE_ERR (err);
422 }