2009-06-22 Marcus Brinkmann <marcus@g10code.de>
[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 } *op_data_t;
50
51
52 static void
53 release_op_data (void *hook)
54 {
55   op_data_t opd = (op_data_t) hook;
56   gpgme_invalid_key_t invalid_signer = opd->result.invalid_signers;
57   gpgme_new_signature_t sig = opd->result.signatures;
58
59   while (invalid_signer)
60     {
61       gpgme_invalid_key_t next = invalid_signer->next;
62       if (invalid_signer->fpr)
63         free (invalid_signer->fpr);
64       free (invalid_signer);
65       invalid_signer = next;
66     }
67
68   while (sig)
69     {
70       gpgme_new_signature_t next = sig->next;
71       free (sig->fpr);
72       free (sig);
73       sig = next;
74     }
75 }
76
77
78 gpgme_sign_result_t
79 gpgme_op_sign_result (gpgme_ctx_t ctx)
80 {
81   void *hook;
82   op_data_t opd;
83   gpgme_error_t err;
84
85   TRACE_BEG (DEBUG_CTX, "gpgme_op_sign_result", ctx);
86
87   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, -1, NULL);
88   opd = hook;
89   if (err || !opd)
90     {
91       TRACE_SUC0 ("result=(null)");
92       return NULL;
93     }
94
95   if (_gpgme_debug_trace ())
96     {
97       gpgme_invalid_key_t inv_key = opd->result.invalid_signers;
98       gpgme_new_signature_t sig = opd->result.signatures;
99       int inv_signers = 0;
100       int signatures = 0;
101
102       while (inv_key)
103         {
104           inv_signers++;
105           inv_key = inv_key->next;
106         }
107       while (sig)
108         {
109           signatures++;
110           sig = sig->next;
111         }
112
113       TRACE_LOG2 ("result: invalid signers: %i, signatures: %i",
114                   inv_signers, signatures);
115       inv_key = opd->result.invalid_signers;
116       while (inv_key)
117         {
118           TRACE_LOG3 ("result: invalid signer: fpr=%s, reason=%s <%s>",
119                       inv_key->fpr, gpgme_strerror (inv_key->reason),
120                       gpgme_strsource (inv_key->reason));
121           inv_key = inv_key->next;
122         }
123       sig = opd->result.signatures;
124       while (sig)
125         {
126           TRACE_LOG6 ("result: signature: type=%i, pubkey_algo=%i, "
127                       "hash_algo=%i, timestamp=%li, fpr=%s, sig_class=%i",
128                       sig->type, sig->pubkey_algo, sig->hash_algo,
129                       sig->timestamp, sig->fpr, sig->sig_class);
130           sig = sig->next;
131         }
132     }
133
134   TRACE_SUC1 ("result=%p", &opd->result);
135   return &opd->result;
136 }
137
138 \f
139 static gpgme_error_t
140 parse_sig_created (char *args, gpgme_new_signature_t *sigp)
141 {
142   gpgme_new_signature_t sig;
143   char *tail;
144
145   sig = malloc (sizeof (*sig));
146   if (!sig)
147     return gpg_error_from_errno (errno);
148
149   sig->next = NULL;
150   switch (*args)
151     {
152     case 'S':
153       sig->type = GPGME_SIG_MODE_NORMAL;
154       break;
155
156     case 'D':
157       sig->type = GPGME_SIG_MODE_DETACH;
158       break;
159
160     case 'C':
161       sig->type = GPGME_SIG_MODE_CLEAR;
162       break;
163
164     default:
165       /* The backend engine is not behaving.  */
166       free (sig);
167       return gpg_error (GPG_ERR_INV_ENGINE);
168     }
169
170   args++;
171   if (*args != ' ')
172     {
173       free (sig);
174       return gpg_error (GPG_ERR_INV_ENGINE);
175     }
176
177   errno = 0;
178   sig->pubkey_algo = strtol (args, &tail, 0);
179   if (errno || args == tail || *tail != ' ')
180     {
181       /* The crypto backend does not behave.  */
182       free (sig);
183       return gpg_error (GPG_ERR_INV_ENGINE);
184     }
185   args = tail;
186
187   sig->hash_algo = strtol (args, &tail, 0);
188   if (errno || args == tail || *tail != ' ')
189     {
190       /* The crypto backend does not behave.  */
191       free (sig);
192       return gpg_error (GPG_ERR_INV_ENGINE);
193     }
194   args = tail;
195
196   sig->sig_class = strtol (args, &tail, 0);
197   sig->class = sig->sig_class;
198   sig->_obsolete_class = sig->sig_class;
199   if (errno || args == tail || *tail != ' ')
200     {
201       /* The crypto backend does not behave.  */
202       free (sig);
203       return gpg_error (GPG_ERR_INV_ENGINE);
204     }
205   args = tail;
206
207   sig->timestamp = _gpgme_parse_timestamp (args, &tail);
208   if (sig->timestamp == -1 || args == tail || *tail != ' ')
209     {
210       /* The crypto backend does not behave.  */
211       free (sig);
212       return gpg_error (GPG_ERR_INV_ENGINE);
213     }
214   args = tail;
215   while (*args == ' ')
216     args++;
217
218   if (!*args)
219     {
220       /* The crypto backend does not behave.  */
221       free (sig);
222       return gpg_error (GPG_ERR_INV_ENGINE);
223     }
224
225   tail = strchr (args, ' ');
226   if (tail)
227     *tail = '\0';
228
229   sig->fpr = strdup (args);
230   if (!sig->fpr)
231     {
232       int saved_errno = errno;
233       free (sig);
234       return gpg_error_from_errno (saved_errno);
235     }
236   *sigp = sig;
237   return 0;
238 }
239
240
241 gpgme_error_t
242 _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
243 {
244   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
245   gpgme_error_t err;
246   void *hook;
247   op_data_t opd;
248
249   err = _gpgme_passphrase_status_handler (priv, code, args);
250   if (err)
251     return err;
252
253   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, -1, NULL);
254   opd = hook;
255   if (err)
256     return err;
257
258   switch (code)
259     {
260     case GPGME_STATUS_SIG_CREATED:
261       err = parse_sig_created (args, opd->last_sig_p);
262       if (err)
263         return err;
264
265       opd->last_sig_p = &(*opd->last_sig_p)->next;
266       break;
267
268     case GPGME_STATUS_INV_RECP:
269       err = _gpgme_parse_inv_recp (args, opd->last_signer_p);
270       if (err)
271         return err;
272
273       opd->last_signer_p = &(*opd->last_signer_p)->next;
274       break;
275
276     case GPGME_STATUS_EOF:
277       if (opd->result.invalid_signers)
278         return gpg_error (GPG_ERR_UNUSABLE_SECKEY);
279       break;
280
281     default:
282       break;
283     }
284   return err;
285 }
286
287
288 static gpgme_error_t
289 sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
290 {
291   gpgme_error_t err;
292
293   err = _gpgme_progress_status_handler (priv, code, args);
294   if (!err)
295     err = _gpgme_sign_status_handler (priv, code, args);
296   return err;
297 }
298
299
300 gpgme_error_t
301 _gpgme_op_sign_init_result (gpgme_ctx_t ctx)
302 {
303   gpgme_error_t err;
304   void *hook;
305   op_data_t opd;
306
307   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook,
308                                sizeof (*opd), release_op_data);
309   opd = hook;
310   if (err)
311     return err;
312   opd->last_signer_p = &opd->result.invalid_signers;
313   opd->last_sig_p = &opd->result.signatures;
314   return 0;
315 }
316
317
318 static gpgme_error_t
319 sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t plain,
320             gpgme_data_t sig, gpgme_sig_mode_t mode)
321 {
322   gpgme_error_t err;
323
324   err = _gpgme_op_reset (ctx, synchronous);
325   if (err)
326     return err;
327
328   err = _gpgme_op_sign_init_result (ctx);
329   if (err)
330     return err;
331
332   if (mode != GPGME_SIG_MODE_NORMAL && mode != GPGME_SIG_MODE_DETACH
333       && mode != GPGME_SIG_MODE_CLEAR)
334     return gpg_error (GPG_ERR_INV_VALUE);
335
336   if (!plain)
337     return gpg_error (GPG_ERR_NO_DATA);
338   if (!sig)
339     return gpg_error (GPG_ERR_INV_VALUE);
340
341   if (ctx->passphrase_cb)
342     {
343       err = _gpgme_engine_set_command_handler
344         (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
345       if (err)
346         return err;
347     }
348
349   _gpgme_engine_set_status_handler (ctx->engine, sign_status_handler,
350                                     ctx);
351
352   return _gpgme_engine_op_sign (ctx->engine, plain, sig, mode, ctx->use_armor,
353                                 ctx->use_textmode, ctx->include_certs,
354                                 ctx /* FIXME */);
355 }
356
357
358 /* Sign the plaintext PLAIN and store the signature in SIG.  */
359 gpgme_error_t
360 gpgme_op_sign_start (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
361                      gpgme_sig_mode_t mode)
362 {
363   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_sign_start", ctx,
364               "plain=%p, sig=%p, mode=%i", plain, sig, mode);
365   return TRACE_ERR (sign_start (ctx, 0, plain, sig, mode));
366 }
367
368
369 /* Sign the plaintext PLAIN and store the signature in SIG.  */
370 gpgme_error_t
371 gpgme_op_sign (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
372                gpgme_sig_mode_t mode)
373 {
374   gpgme_error_t err;
375
376   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_sign_start", ctx,
377               "plain=%p, sig=%p, mode=%i", plain, sig, mode);
378   err = sign_start (ctx, 1, plain, sig, mode);
379   if (!err)
380     err = _gpgme_wait_one (ctx);
381   return TRACE_ERR (err);
382 }