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