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