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