Line data Source code
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 :
38 : typedef struct
39 : {
40 : struct _gpgme_op_sign_result result;
41 :
42 : /* The error code from a FAILURE status line or 0. */
43 : gpg_error_t failure_code;
44 :
45 : /* A pointer to the next pointer of the last invalid signer in
46 : the list. This makes appending new invalid signers painless
47 : while preserving the order. */
48 : gpgme_invalid_key_t *last_signer_p;
49 :
50 : /* Likewise for signature information. */
51 : gpgme_new_signature_t *last_sig_p;
52 :
53 : /* Flags used while processing the status lines. */
54 : unsigned int ignore_inv_recp:1;
55 : unsigned int inv_sgnr_seen:1;
56 : unsigned int sig_created_seen:1;
57 : } *op_data_t;
58 :
59 :
60 : static void
61 11 : release_signatures (gpgme_new_signature_t sig)
62 : {
63 36 : while (sig)
64 : {
65 14 : gpgme_new_signature_t next = sig->next;
66 14 : free (sig->fpr);
67 14 : free (sig);
68 14 : sig = next;
69 : }
70 11 : }
71 :
72 :
73 : static void
74 11 : release_op_data (void *hook)
75 : {
76 11 : op_data_t opd = (op_data_t) hook;
77 11 : gpgme_invalid_key_t invalid_signer = opd->result.invalid_signers;
78 :
79 22 : while (invalid_signer)
80 : {
81 0 : gpgme_invalid_key_t next = invalid_signer->next;
82 0 : if (invalid_signer->fpr)
83 0 : free (invalid_signer->fpr);
84 0 : free (invalid_signer);
85 0 : invalid_signer = next;
86 : }
87 :
88 11 : release_signatures (opd->result.signatures);
89 11 : }
90 :
91 :
92 : gpgme_sign_result_t
93 10 : gpgme_op_sign_result (gpgme_ctx_t ctx)
94 : {
95 : void *hook;
96 : op_data_t opd;
97 : gpgme_error_t err;
98 : gpgme_invalid_key_t inv_key, key;
99 : gpgme_new_signature_t sig;
100 10 : unsigned int inv_signers = 0;
101 10 : unsigned int signatures = 0;
102 :
103 10 : TRACE_BEG (DEBUG_CTX, "gpgme_op_sign_result", ctx);
104 :
105 10 : err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, -1, NULL);
106 10 : opd = hook;
107 10 : if (err || !opd)
108 : {
109 0 : TRACE_SUC0 ("result=(null)");
110 0 : return NULL;
111 : }
112 :
113 10 : for (inv_key = opd->result.invalid_signers; inv_key; inv_key = inv_key->next)
114 0 : inv_signers++;
115 23 : for (sig = opd->result.signatures; sig; sig = sig->next)
116 13 : signatures++;
117 :
118 10 : if (gpgme_signers_count (ctx)
119 3 : && signatures + inv_signers != gpgme_signers_count (ctx))
120 : {
121 : /* In this case at least one signatures was not created perhaps
122 : due to a bad passphrase etc. Thus the entire message is
123 : broken and should not be used. We add the already created
124 : signatures to the invalid signers list and thus this case can
125 : be detected. */
126 0 : TRACE_LOG3 ("result: invalid signers: %u, signatures: %u, count: %u",
127 : inv_signers, signatures, gpgme_signers_count (ctx));
128 :
129 0 : for (sig = opd->result.signatures; sig; sig = sig->next)
130 : {
131 0 : key = calloc (1, sizeof *key);
132 0 : if (!key)
133 : {
134 0 : TRACE_SUC0 ("out of core; result=(null)");
135 0 : return NULL;
136 : }
137 0 : if (sig->fpr)
138 : {
139 0 : key->fpr = strdup (sig->fpr);
140 0 : if (!key->fpr)
141 : {
142 0 : free (key);
143 0 : TRACE_SUC0 ("out of core; result=(null)");
144 0 : return NULL;
145 : }
146 : }
147 0 : key->reason = GPG_ERR_GENERAL;
148 :
149 0 : inv_key = opd->result.invalid_signers;
150 0 : if (inv_key)
151 : {
152 0 : for (; inv_key->next; inv_key = inv_key->next)
153 : ;
154 0 : inv_key->next = key;
155 : }
156 : else
157 0 : opd->result.invalid_signers = key;
158 : }
159 :
160 0 : release_signatures (opd->result.signatures);
161 0 : opd->result.signatures = NULL;
162 : }
163 :
164 : if (_gpgme_debug_trace())
165 : {
166 10 : TRACE_LOG2 ("result: invalid signers: %i, signatures: %i",
167 : inv_signers, signatures);
168 10 : for (inv_key=opd->result.invalid_signers; inv_key; inv_key=inv_key->next)
169 : {
170 0 : TRACE_LOG3 ("result: invalid signer: fpr=%s, reason=%s <%s>",
171 : inv_key->fpr, gpgme_strerror (inv_key->reason),
172 : gpgme_strsource (inv_key->reason));
173 : }
174 23 : for (sig = opd->result.signatures; sig; sig = sig->next)
175 : {
176 13 : TRACE_LOG6 ("result: signature: type=%i, pubkey_algo=%i, "
177 : "hash_algo=%i, timestamp=%li, fpr=%s, sig_class=%i",
178 : sig->type, sig->pubkey_algo, sig->hash_algo,
179 : sig->timestamp, sig->fpr, sig->sig_class);
180 : }
181 : }
182 :
183 10 : TRACE_SUC1 ("result=%p", &opd->result);
184 10 : return &opd->result;
185 : }
186 :
187 :
188 :
189 : static gpgme_error_t
190 14 : parse_sig_created (char *args, gpgme_new_signature_t *sigp,
191 : gpgme_protocol_t protocol)
192 : {
193 : gpgme_new_signature_t sig;
194 : char *tail;
195 :
196 14 : sig = malloc (sizeof (*sig));
197 14 : if (!sig)
198 0 : return gpg_error_from_syserror ();
199 :
200 14 : sig->next = NULL;
201 14 : switch (*args)
202 : {
203 : case 'S':
204 7 : sig->type = GPGME_SIG_MODE_NORMAL;
205 7 : break;
206 :
207 : case 'D':
208 4 : sig->type = GPGME_SIG_MODE_DETACH;
209 4 : break;
210 :
211 : case 'C':
212 3 : sig->type = GPGME_SIG_MODE_CLEAR;
213 3 : break;
214 :
215 : default:
216 : /* The backend engine is not behaving. */
217 0 : free (sig);
218 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
219 : }
220 :
221 14 : args++;
222 14 : if (*args != ' ')
223 : {
224 0 : free (sig);
225 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
226 : }
227 :
228 14 : gpg_err_set_errno (0);
229 14 : sig->pubkey_algo = _gpgme_map_pk_algo (strtol (args, &tail, 0), protocol);
230 14 : if (errno || args == tail || *tail != ' ')
231 : {
232 : /* The crypto backend does not behave. */
233 0 : free (sig);
234 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
235 : }
236 14 : args = tail;
237 :
238 14 : sig->hash_algo = strtol (args, &tail, 0);
239 14 : if (errno || args == tail || *tail != ' ')
240 : {
241 : /* The crypto backend does not behave. */
242 0 : free (sig);
243 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
244 : }
245 14 : args = tail;
246 :
247 14 : sig->sig_class = strtol (args, &tail, 0);
248 14 : sig->class = sig->sig_class;
249 14 : sig->_obsolete_class = sig->sig_class;
250 14 : if (errno || args == tail || *tail != ' ')
251 : {
252 : /* The crypto backend does not behave. */
253 0 : free (sig);
254 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
255 : }
256 14 : args = tail;
257 :
258 14 : sig->timestamp = _gpgme_parse_timestamp (args, &tail);
259 14 : if (sig->timestamp == -1 || args == tail || *tail != ' ')
260 : {
261 : /* The crypto backend does not behave. */
262 0 : free (sig);
263 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
264 : }
265 14 : args = tail;
266 42 : while (*args == ' ')
267 14 : args++;
268 :
269 14 : if (!*args)
270 : {
271 : /* The crypto backend does not behave. */
272 0 : free (sig);
273 0 : return trace_gpg_error (GPG_ERR_INV_ENGINE);
274 : }
275 :
276 14 : tail = strchr (args, ' ');
277 14 : if (tail)
278 0 : *tail = '\0';
279 :
280 14 : sig->fpr = strdup (args);
281 14 : if (!sig->fpr)
282 : {
283 0 : free (sig);
284 0 : return gpg_error_from_syserror ();
285 : }
286 14 : *sigp = sig;
287 14 : return 0;
288 : }
289 :
290 :
291 : gpgme_error_t
292 61 : _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
293 : {
294 61 : gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
295 : gpgme_error_t err;
296 : void *hook;
297 : op_data_t opd;
298 :
299 61 : err = _gpgme_passphrase_status_handler (priv, code, args);
300 61 : if (err)
301 0 : return err;
302 :
303 61 : err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, -1, NULL);
304 61 : opd = hook;
305 61 : if (err)
306 0 : return err;
307 :
308 61 : switch (code)
309 : {
310 : case GPGME_STATUS_SIG_CREATED:
311 14 : opd->sig_created_seen = 1;
312 14 : err = parse_sig_created (args, opd->last_sig_p, ctx->protocol);
313 14 : if (err)
314 0 : return err;
315 :
316 14 : opd->last_sig_p = &(*opd->last_sig_p)->next;
317 14 : break;
318 :
319 : case GPGME_STATUS_INV_RECP:
320 0 : if (opd->inv_sgnr_seen && opd->ignore_inv_recp)
321 0 : break;
322 : /* FALLTROUGH */
323 : case GPGME_STATUS_INV_SGNR:
324 0 : if (code == GPGME_STATUS_INV_SGNR)
325 0 : opd->inv_sgnr_seen = 1;
326 0 : err = _gpgme_parse_inv_recp (args, opd->last_signer_p);
327 0 : if (err)
328 0 : return err;
329 :
330 0 : opd->last_signer_p = &(*opd->last_signer_p)->next;
331 0 : break;
332 :
333 : case GPGME_STATUS_FAILURE:
334 0 : opd->failure_code = _gpgme_parse_failure (args);
335 0 : break;
336 :
337 : case GPGME_STATUS_EOF:
338 : /* The UI server does not send information about the created
339 : signature. This is irrelevant for this protocol and thus we
340 : should not check for that. */
341 11 : if (opd->result.invalid_signers)
342 0 : err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
343 11 : else if (!opd->sig_created_seen
344 0 : && ctx->protocol != GPGME_PROTOCOL_UISERVER)
345 0 : err = opd->failure_code? opd->failure_code:gpg_error (GPG_ERR_GENERAL);
346 11 : break;
347 :
348 : case GPGME_STATUS_INQUIRE_MAXLEN:
349 0 : if (ctx->status_cb)
350 0 : err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
351 0 : break;
352 :
353 : default:
354 36 : break;
355 : }
356 61 : return err;
357 : }
358 :
359 :
360 : static gpgme_error_t
361 43 : sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
362 : {
363 : gpgme_error_t err;
364 :
365 43 : err = _gpgme_progress_status_handler (priv, code, args);
366 43 : if (!err)
367 43 : err = _gpgme_sign_status_handler (priv, code, args);
368 43 : return err;
369 : }
370 :
371 :
372 : static gpgme_error_t
373 11 : sign_init_result (gpgme_ctx_t ctx, int ignore_inv_recp)
374 : {
375 : gpgme_error_t err;
376 : void *hook;
377 : op_data_t opd;
378 :
379 11 : err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook,
380 : sizeof (*opd), release_op_data);
381 11 : opd = hook;
382 11 : if (err)
383 0 : return err;
384 11 : opd->failure_code = 0;
385 11 : opd->last_signer_p = &opd->result.invalid_signers;
386 11 : opd->last_sig_p = &opd->result.signatures;
387 11 : opd->ignore_inv_recp = !!ignore_inv_recp;
388 11 : opd->inv_sgnr_seen = 0;
389 11 : opd->sig_created_seen = 0;
390 11 : return 0;
391 : }
392 :
393 : gpgme_error_t
394 2 : _gpgme_op_sign_init_result (gpgme_ctx_t ctx)
395 : {
396 2 : return sign_init_result (ctx, 0);
397 : }
398 :
399 :
400 : static gpgme_error_t
401 9 : sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t plain,
402 : gpgme_data_t sig, gpgme_sig_mode_t mode)
403 : {
404 : gpgme_error_t err;
405 :
406 9 : err = _gpgme_op_reset (ctx, synchronous);
407 9 : if (err)
408 0 : return err;
409 :
410 : /* If we are using the CMS protocol, we ignore the INV_RECP status
411 : code if a newer GPGSM is in use. GPGMS does not support combined
412 : sign+encrypt and thus this can't harm. */
413 9 : err = sign_init_result (ctx, (ctx->protocol == GPGME_PROTOCOL_CMS));
414 9 : if (err)
415 0 : return err;
416 :
417 9 : if (mode != GPGME_SIG_MODE_NORMAL && mode != GPGME_SIG_MODE_DETACH
418 2 : && mode != GPGME_SIG_MODE_CLEAR)
419 0 : return gpg_error (GPG_ERR_INV_VALUE);
420 :
421 9 : if (!plain)
422 0 : return gpg_error (GPG_ERR_NO_DATA);
423 9 : if (!sig)
424 0 : return gpg_error (GPG_ERR_INV_VALUE);
425 :
426 9 : if (ctx->passphrase_cb)
427 : {
428 7 : err = _gpgme_engine_set_command_handler
429 : (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
430 7 : if (err)
431 0 : return err;
432 : }
433 :
434 9 : _gpgme_engine_set_status_handler (ctx->engine, sign_status_handler,
435 : ctx);
436 :
437 18 : return _gpgme_engine_op_sign (ctx->engine, plain, sig, mode, ctx->use_armor,
438 18 : ctx->use_textmode, ctx->include_certs,
439 : ctx /* FIXME */);
440 : }
441 :
442 :
443 : /* Sign the plaintext PLAIN and store the signature in SIG. */
444 : gpgme_error_t
445 0 : gpgme_op_sign_start (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
446 : gpgme_sig_mode_t mode)
447 : {
448 : gpg_error_t err;
449 0 : TRACE_BEG3 (DEBUG_CTX, "gpgme_op_sign_start", ctx,
450 : "plain=%p, sig=%p, mode=%i", plain, sig, mode);
451 :
452 0 : if (!ctx)
453 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
454 :
455 0 : err = sign_start (ctx, 0, plain, sig, mode);
456 0 : return TRACE_ERR (err);
457 : }
458 :
459 :
460 : /* Sign the plaintext PLAIN and store the signature in SIG. */
461 : gpgme_error_t
462 9 : gpgme_op_sign (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
463 : gpgme_sig_mode_t mode)
464 : {
465 : gpgme_error_t err;
466 :
467 9 : TRACE_BEG3 (DEBUG_CTX, "gpgme_op_sign", ctx,
468 : "plain=%p, sig=%p, mode=%i", plain, sig, mode);
469 :
470 9 : if (!ctx)
471 0 : return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
472 :
473 9 : err = sign_start (ctx, 1, plain, sig, mode);
474 9 : if (!err)
475 9 : err = _gpgme_wait_one (ctx);
476 9 : return TRACE_ERR (err);
477 : }
|