c66f06a0f695fb9539209bb86ebcfc37d410894a
[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_errno (errno);
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   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       if (opd->result.invalid_signers)
290         err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
291       else if (!opd->sig_created_seen)
292         err = gpg_error (GPG_ERR_GENERAL);
293       break;
294
295     default:
296       break;
297     }
298   return err;
299 }
300
301
302 static gpgme_error_t
303 sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
304 {
305   gpgme_error_t err;
306
307   err = _gpgme_progress_status_handler (priv, code, args);
308   if (!err)
309     err = _gpgme_sign_status_handler (priv, code, args);
310   return err;
311 }
312
313
314 static gpgme_error_t
315 sign_init_result (gpgme_ctx_t ctx, int ignore_inv_recp)
316 {
317   gpgme_error_t err;
318   void *hook;
319   op_data_t opd;
320
321   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook,
322                                sizeof (*opd), release_op_data);
323   opd = hook;
324   if (err)
325     return err;
326   opd->last_signer_p = &opd->result.invalid_signers;
327   opd->last_sig_p = &opd->result.signatures;
328   opd->ignore_inv_recp = !!ignore_inv_recp;
329   opd->inv_sgnr_seen = 0;
330   opd->sig_created_seen = 0;
331   return 0;
332 }
333
334 gpgme_error_t
335 _gpgme_op_sign_init_result (gpgme_ctx_t ctx)
336 {
337   return sign_init_result (ctx, 0);
338 }
339
340
341 static gpgme_error_t
342 sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t plain,
343             gpgme_data_t sig, gpgme_sig_mode_t mode)
344 {
345   gpgme_error_t err;
346
347   err = _gpgme_op_reset (ctx, synchronous);
348   if (err)
349     return err;
350
351   /* If we are using the CMS protocol, we ignore the INV_RECP status
352      code if a newer GPGSM is in use.  GPGMS does not support combined
353      sign+encrypt and thus this can't harm.  */
354   err = sign_init_result (ctx, (ctx->protocol == GPGME_PROTOCOL_CMS));
355   if (err)
356     return err;
357
358   if (mode != GPGME_SIG_MODE_NORMAL && mode != GPGME_SIG_MODE_DETACH
359       && mode != GPGME_SIG_MODE_CLEAR)
360     return gpg_error (GPG_ERR_INV_VALUE);
361
362   if (!plain)
363     return gpg_error (GPG_ERR_NO_DATA);
364   if (!sig)
365     return gpg_error (GPG_ERR_INV_VALUE);
366
367   if (ctx->passphrase_cb)
368     {
369       err = _gpgme_engine_set_command_handler
370         (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
371       if (err)
372         return err;
373     }
374
375   _gpgme_engine_set_status_handler (ctx->engine, sign_status_handler,
376                                     ctx);
377
378   return _gpgme_engine_op_sign (ctx->engine, plain, sig, mode, ctx->use_armor,
379                                 ctx->use_textmode, ctx->include_certs,
380                                 ctx /* FIXME */);
381 }
382
383
384 /* Sign the plaintext PLAIN and store the signature in SIG.  */
385 gpgme_error_t
386 gpgme_op_sign_start (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
387                      gpgme_sig_mode_t mode)
388 {
389   gpg_error_t err;
390   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_sign_start", ctx,
391               "plain=%p, sig=%p, mode=%i", plain, sig, mode);
392   err = sign_start (ctx, 0, plain, sig, mode);
393   return TRACE_ERR (err);
394 }
395
396
397 /* Sign the plaintext PLAIN and store the signature in SIG.  */
398 gpgme_error_t
399 gpgme_op_sign (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
400                gpgme_sig_mode_t mode)
401 {
402   gpgme_error_t err;
403
404   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_sign", ctx,
405               "plain=%p, sig=%p, mode=%i", plain, sig, mode);
406   err = sign_start (ctx, 1, plain, sig, mode);
407   if (!err)
408     err = _gpgme_wait_one (ctx);
409   return TRACE_ERR (err);
410 }