/[winpt]/trunk/MyGPGME/sign.c
ViewVC logotype

Annotation of /trunk/MyGPGME/sign.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (hide annotations)
Mon Apr 4 07:01:43 2005 UTC (19 years, 10 months ago) by twoaday
File MIME type: text/plain
File size: 15941 byte(s)
2005-03-22  Timo Schulz  <twoaday@freakmail.de>
                                                                                
        * editcard.c: Support new status-fd entries SC_OP_SUCCESS
        and SC_OP_FAILURE.
        * editkey.c (cmd_addrev_handler): Check if context != NULL.
        * import.c (import_command_handler): Wrong function signature.
        Noted by Kurt Fitzner.
        * types.h: Fixed encrypt_result_s. Noted by Kurt.
        * gpgme.h (gpgme_editkey_addrev_set): Changed return type.
        Kudos to Kurt.
        * key.c: Removed some unreachable code. By Kurt.
                                                                                


1 twoaday 2 /* sign.c - signing functions
2     * Copyright (C) 2000 Werner Koch (dd9jn)
3     * Copyright (C) 2001-2004 Timo Schulz
4     *
5     * This file is part of MyGPGME.
6     *
7     * MyGPGME is free software; you can redistribute it and/or modify
8     * it 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     * MyGPGME is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20     */
21    
22     #include <stdio.h>
23     #include <stdlib.h>
24     #include <string.h>
25     #include <assert.h>
26    
27     #include "util.h"
28     #include "context.h"
29     #include "ops.h"
30     #include "status-table.h"
31    
32     struct sign_result_s {
33     void * last_pw_handle;
34     char * userid_hint;
35     char * passphrase_info;
36     char cardno[32+1];
37     int bad_passphrase;
38     int idea_cipher;
39     int no_passphrase;
40     int okay;
41     };
42    
43    
44     void
45     _gpgme_release_sign_result( _sign_result_t res )
46     {
47     if( res ) {
48     safe_free( res->userid_hint );
49     safe_free( res->passphrase_info );
50     safe_free( res );
51     }
52     }
53    
54    
55     static void
56     sign_status_handler( gpgme_ctx_t ctx, gpg_status_code_t code, char *args )
57     {
58     char * p;
59     int i=0;
60    
61     if( ctx->out_of_core )
62     return;
63     if( ctx->result_type == RESULT_TYPE_NONE ) {
64     assert( !ctx->result.sign );
65     ctx->result.sign = calloc( 1, sizeof *ctx->result.sign );
66     if( !ctx->result.sign ) {
67     ctx->out_of_core = 1;
68     return;
69     }
70     ctx->result_type = RESULT_TYPE_SIGN;
71     }
72     assert( ctx->result_type == RESULT_TYPE_SIGN );
73    
74     switch( code ) {
75     case STATUS_EOF:
76     break;
77    
78     case STATUS_USERID_HINT:
79     safe_free( ctx->result.sign->userid_hint );
80     ctx->result.sign->userid_hint = strdup( args );
81     if( !ctx->result.sign ) {
82     ctx->out_of_core = 1;
83     return;
84     }
85     break;
86    
87     case STATUS_BAD_PASSPHRASE:
88     DEBUG0( "Bad passphrase - once again please\n" );
89     ctx->result.sign->bad_passphrase++;
90     break;
91    
92     case STATUS_GOOD_PASSPHRASE:
93     ctx->result.sign->bad_passphrase = 0;
94     break;
95    
96     case STATUS_RSA_OR_IDEA:
97     ctx->result.sign->idea_cipher = 1;
98     break;
99    
100     case STATUS_NEED_PASSPHRASE:
101     case STATUS_NEED_PASSPHRASE_SYM:
102     safe_free( ctx->result.sign->passphrase_info );
103     ctx->result.sign->passphrase_info = strdup( args );
104     if( !ctx->result.sign->passphrase_info ) {
105     ctx->out_of_core = 1;
106     return;
107     }
108     break;
109    
110     case STATUS_MISSING_PASSPHRASE:
111     DEBUG0( "missing passphrase - stop\n" );
112     ctx->result.sign->no_passphrase = 1;
113     break;
114    
115     case STATUS_SIG_CREATED:
116     ctx->result.sign->okay = 1;
117     break;
118    
119     case STATUS_PROGRESS:
120     if( ctx->cb.progress )
121     _gpgme_progress_handler( ctx, args );
122     break;
123    
124     case STATUS_CARDCTRL:
125     if( args[i++] != '3' )
126     break;
127     i++;
128     p = ctx->result.sign->cardno;
129     for( ; i-1 < DIM(ctx->result.sign->cardno) && args[i]; i++ )
130     *p++ = args[i];
131     *p = 0;
132     break;
133    
134     default:
135     break;
136     }
137     }
138    
139    
140     static const char *
141     command_handler( void *opaque, gpg_status_code_t code, const char *key )
142     {
143     gpgme_ctx_t c = opaque;
144    
145     if( c->result_type == RESULT_TYPE_NONE ) {
146     assert( !c->result.sign );
147     c->result.sign = calloc( 1, sizeof *c->result.sign );
148     if( !c->result.sign ) {
149     c->out_of_core = 1;
150     return NULL;
151     }
152     c->result_type = RESULT_TYPE_SIGN;
153     }
154    
155     if( !code ) {
156     /* We have been called for cleanup */
157     if( c->cb.passphrase ) {
158     c->cb.passphrase( c->cb.passphrase_value, 0,
159     &c->result.sign->last_pw_handle );
160     }
161     return NULL;
162     }
163    
164     if( !key || !c->cb.passphrase )
165     return NULL;
166    
167     if( code == STATUS_GET_HIDDEN
168     && (!strcmp( key, "passphrase.enter" )
169     || !strcmp( key, "passphrase.pin.ask" )) ) {
170     const char * userid_hint = c->result.sign->userid_hint;
171     const char * passphrase_info = c->result.sign->passphrase_info;
172     const char * cardno = c->result.sign->cardno;
173     int bad_passphrase = c->result.sign->bad_passphrase;
174     int is_card=0;
175     char * buf;
176     const char * s;
177    
178     c->result.sign->bad_passphrase = 0;
179     is_card = !strcmp( key, "passphrase.pin.ask" );
180     if( !userid_hint )
181     userid_hint = "[User ID hint missing]";
182     if( !passphrase_info )
183     passphrase_info = "[passphrase info missing]";
184     buf = malloc( 20 + strlen( userid_hint )
185     + strlen( passphrase_info ) + 3 );
186     if( !buf ) {
187     c->out_of_core = 1;
188     return NULL;
189     }
190     sprintf( buf, "%s\n%s\n%s",
191     bad_passphrase? "TRY_AGAIN":"ENTER_PASSPHRASE",
192     userid_hint, passphrase_info );
193    
194     s = c->cb.passphrase( c->cb.passphrase_value,
195     is_card? cardno : buf,
196     &c->result.sign->last_pw_handle );
197     safe_free( buf );
198     return s;
199     }
200    
201     return NULL;
202     }
203    
204    
205     static gpgme_error_t
206     file_sign_start (gpgme_ctx_t ctx, int signenc, int sigmode,
207     gpgme_recipients_t recp,
208     const char * input, const char * output)
209     {
210     gpgme_error_t rc = 0;
211     gpgme_key_t key;
212    
213     fail_on_pending_request (ctx);
214     ctx->pending = 1;
215    
216     _gpgme_gpg_release (&ctx->gpg);
217     rc = _gpgme_gpg_new (&ctx->gpg);
218     if( rc )
219     return rc;
220    
221     if( ctx->use_logging )
222     _gpgme_gpg_set_logging_handler( ctx->gpg, ctx );
223     _gpgme_gpg_set_status_handler( ctx->gpg, sign_status_handler, ctx );
224     if( !ctx->use_pass_fd )
225     _gpgme_gpg_set_command_handler( ctx->gpg, command_handler, ctx );
226     else {
227     rc = _gpgme_add_passphrase( ctx );
228     if( rc ) {
229     _gpgme_gpg_release( &ctx->gpg );
230     return rc;
231     }
232     }
233    
234     _gpgme_gpg_add_arg (ctx->gpg, "--yes");
235     key = gpgme_signers_enum (ctx, 0);
236     if (key)
237     {
238     const char * s;
239     s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEYID, NULL, 0);
240     if (!s)
241     return mk_error (Invalid_Value);
242     _gpgme_gpg_add_arg (ctx->gpg, "-u");
243     _gpgme_gpg_add_arg_concat (ctx->gpg, s, "!");
244     if (signenc)
245     {
246     _gpgme_gpg_add_arg (ctx->gpg, "--encrypt-to");
247     _gpgme_gpg_add_arg (ctx->gpg, s);
248     }
249     }
250     if( ctx->use_armor )
251     _gpgme_gpg_add_arg( ctx->gpg, "--armor" );
252     if( ctx->cb.progress )
253     _gpgme_gpg_add_arg( ctx->gpg, "--enable-progress-filter" );
254     if( output && *output ) {
255     _gpgme_gpg_add_arg( ctx->gpg, "--output" );
256     _gpgme_gpg_add_arg( ctx->gpg, output );
257     }
258     else
259     _gpgme_gpg_add_arg( ctx->gpg, "--no-mangle-dos-filenames" );
260     if( signenc ) {
261     if (sigmode != GPGME_SIG_MODE_NORMAL)
262     return mk_error (Invalid_Value);
263     if (!recp)
264     return mk_error (No_Recipients);
265     if (ctx->force_trust || _gpgme_recipients_all_valid (recp))
266     _gpgme_gpg_add_arg (ctx->gpg, "--always-trust");
267     _gpgme_gpg_add_arg (ctx->gpg, "--encrypt");
268     _gpgme_append_gpg_args_from_recipients (recp, ctx->gpg);
269     }
270     if (ctx->cb.progress)
271     _gpgme_gpg_add_arg (ctx->gpg, "--enable-progress-filter");
272    
273     switch( sigmode ) {
274     case GPGME_SIG_MODE_NORMAL:
275     _gpgme_gpg_add_arg( ctx->gpg, "--sign" );
276     break;
277     case GPGME_SIG_MODE_DETACH:
278     _gpgme_gpg_add_arg( ctx->gpg, "--detach-sign" );
279     break;
280     case GPGME_SIG_MODE_CLEAR:
281     _gpgme_gpg_add_arg( ctx->gpg, "--clearsign" );
282     if( ctx->use_textmode )
283     _gpgme_gpg_add_arg( ctx->gpg, "--textmode" );
284     break;
285     default:
286     _gpgme_gpg_add_arg( ctx->gpg, "--sign" );
287     break;
288     }
289    
290     _gpgme_gpg_add_arg( ctx->gpg, input );
291     rc = _gpgme_gpg_spawn( ctx->gpg, ctx );
292     if( rc ) {
293     ctx->pending = 0;
294     _gpgme_gpg_release( &ctx->gpg );
295     }
296    
297     return rc;
298     } /* file_sign_start */
299    
300    
301     static gpgme_error_t
302     sign_start( gpgme_ctx_t ctx, gpgme_data_t in, gpgme_data_t out, gpgme_sigmode_t mode )
303     {
304     int rc = 0;
305     int i;
306     gpgme_key_t key;
307    
308     fail_on_pending_request( ctx );
309     ctx->pending = 1;
310    
311     _gpgme_release_result( ctx );
312     ctx->out_of_core = 0;
313    
314     if( mode != GPGME_SIG_MODE_NORMAL
315     && mode != GPGME_SIG_MODE_DETACH
316     && mode != GPGME_SIG_MODE_CLEAR )
317     return mk_error( Invalid_Value );
318    
319     /* create a process object */
320     _gpgme_gpg_release( &ctx->gpg );
321     rc = _gpgme_gpg_new( &ctx->gpg );
322     if( rc )
323     goto leave;
324    
325     _gpgme_gpg_set_status_handler( ctx->gpg, sign_status_handler, ctx );
326     if( ctx->cb.passphrase ) {
327     rc = _gpgme_gpg_set_command_handler( ctx->gpg, command_handler, ctx );
328     if( rc )
329     goto leave;
330     }
331     else if( ctx->passphrase_value ) {
332     rc = _gpgme_add_passphrase( ctx );
333     if( rc )
334     goto leave;
335     }
336    
337     /* build the commandline */
338     if( mode == GPGME_SIG_MODE_CLEAR )
339     _gpgme_gpg_add_arg ( ctx->gpg, "--clearsign" );
340     else {
341     _gpgme_gpg_add_arg ( ctx->gpg, "--sign" );
342     if( mode == GPGME_SIG_MODE_DETACH )
343     _gpgme_gpg_add_arg ( ctx->gpg, "--detach" );
344     if( ctx->use_armor )
345     _gpgme_gpg_add_arg ( ctx->gpg, "--armor" );
346     if( ctx->use_textmode)
347     _gpgme_gpg_add_arg (ctx->gpg, "--textmode");
348     }
349     for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
350     {
351     const char *s;
352     s = gpgme_key_get_string_attr( key, GPGME_ATTR_KEYID, NULL, 0);
353     if (s)
354     {
355     _gpgme_gpg_add_arg (ctx->gpg, "-u");
356     _gpgme_gpg_add_arg_concat (ctx->gpg, s, "!");
357     }
358     gpgme_key_unref (key);
359     }
360    
361     /* Check the supplied data */
362     if( gpgme_data_get_type( in ) == GPGME_DATA_TYPE_NONE ) {
363     rc = mk_error( No_Data );
364     goto leave;
365     }
366     _gpgme_data_set_mode(in, GPGME_DATA_MODE_OUT );
367     if( !out || gpgme_data_get_type( out ) != GPGME_DATA_TYPE_NONE ) {
368     rc = mk_error( Invalid_Value );
369     goto leave;
370     }
371     _gpgme_data_set_mode( out, GPGME_DATA_MODE_IN );
372    
373     if( ctx->use_tmpfiles ) {
374     _gpgme_gpg_add_arg( ctx->gpg, "--output" );
375     _gpgme_gpg_add_arg( ctx->gpg, _gpgme_get_tmpfile( 0 ) );
376     _gpgme_data_write_to_tmpfile( in );
377     _gpgme_gpg_add_arg( ctx->gpg, _gpgme_get_tmpfile( 1 ) );
378     }
379     else {
380     /* Tell the gpg object about the data */
381     _gpgme_gpg_add_data( ctx->gpg, in, 0 );
382     _gpgme_gpg_add_data( ctx->gpg, out, 1 );
383     }
384    
385     /* and kick off the process */
386     rc = _gpgme_gpg_spawn( ctx->gpg, ctx );
387    
388     leave:
389     if( rc ) {
390     ctx->pending = 0;
391     _gpgme_gpg_release( &ctx->gpg );
392     }
393     return rc;
394     }
395    
396    
397     static gpgme_error_t
398     get_sign_result( gpgme_ctx_t ctx )
399     {
400     struct sign_result_s * res;
401     gpgme_error_t err = 0;
402    
403     if( ctx->result_type != RESULT_TYPE_SIGN )
404     err = mk_error( General_Error );
405     else if( ctx->out_of_core )
406     err = mk_error( Out_Of_Core );
407     else {
408     assert ( ctx->result.sign );
409     res = ctx->result.sign;
410     if( res->no_passphrase )
411     err = mk_error( No_Passphrase );
412     else if( res->bad_passphrase )
413     err = mk_error( Bad_Passphrase );
414     else if( res->idea_cipher )
415     err = mk_error( Cipher_IDEA );
416     else if( gpgme_get_process_rc( ctx ) )
417 twoaday 7 err = mk_error( Internal_GPG_Problem );
418 twoaday 2 else if( !res->okay )
419     err = mk_error( Signing_Failed );
420     }
421     return err;
422     } /* get_sign_result */
423    
424    
425     /**
426     * gpgme_op_sign:
427     * @c: The context
428     * @in: Data to be signed
429     * @out: Detached signature
430     * @mode: Signature creation mode
431     *
432     * Create a detached signature for @in and write it to @out.
433     * The data will be signed using either the default key or the ones
434     * defined through @c.
435     * The defined modes for signature create are:
436     * <literal>
437     * GPGME_SIG_MODE_NORMAL (or 0)
438     * GPGME_SIG_MODE_DETACH
439     * GPGME_SIG_MODE_CLEAR
440     * </literal>
441     * Note that the settings done by gpgme_set_armor() and gpgme_set_textmode()
442     * are ignore for @mode GPGME_SIG_MODE_CLEAR.
443     *
444     * Return value: 0 on success or an error code.
445     **/
446     gpgme_error_t
447     gpgme_op_sign( gpgme_ctx_t ctx, gpgme_data_t in, gpgme_data_t out, gpgme_sigmode_t mode )
448     {
449     gpgme_error_t err;
450    
451     err = sign_start( ctx, in, out, mode );
452     if ( !err ) {
453     gpgme_wait( ctx, 1 );
454     ctx->pending = 0;
455     if( ctx->use_tmpfiles ) {
456     _gpgme_data_read_from_tmpfile( out );
457     _gpgme_del_tmpfiles( ctx->wipe_fnc );
458     }
459     err = get_sign_result( ctx );
460     }
461     return err;
462     } /* gpgme_op_sign */
463    
464    
465     gpgme_error_t
466     gpgme_op_file_sign( gpgme_ctx_t ctx, gpgme_sigmode_t mode,
467     const char * input, const char * output )
468     {
469     gpgme_error_t err;
470    
471     err = file_sign_start( ctx, 0, mode, NULL, input, output );
472     if( !err ) {
473     gpgme_wait( ctx, 1 );
474     ctx->pending = 0;
475     err = get_sign_result( ctx );
476     }
477     return err;
478     } /* gpgme_file_sign */
479    
480    
481     gpgme_error_t
482     gpgme_op_files_sign( gpgme_ctx_t ctx, gpgme_sigmode_t mode,
483     const char ** files, size_t nfiles )
484     {
485     gpgme_error_t err;
486     size_t i;
487    
488     for( i=0; i < nfiles; i++ ) {
489     err = gpgme_op_file_sign( ctx, mode, files[i], NULL );
490     if( err )
491     break;
492     }
493     return err;
494     } /* gpgme_op_files_sign */
495    
496    
497     gpgme_error_t
498     gpgme_op_file_sign_encrypt( gpgme_ctx_t ctx, gpgme_recipients_t recp,
499     const char * input, const char * output )
500     {
501     gpgme_error_t err;
502    
503     err = file_sign_start( ctx, 1, GPGME_SIG_MODE_NORMAL, recp, input, output );
504     if( !err ) {
505     gpgme_wait( ctx, 1 );
506     ctx->pending = 0;
507     err = get_sign_result( ctx );
508     }
509     return err;
510     } /* gpgme_op_file_sign_encrypt */
511    
512    
513     gpgme_error_t
514     gpgme_op_files_sign_encrypt( gpgme_ctx_t ctx, gpgme_recipients_t recp,
515     const char ** files, size_t nfiles )
516     {
517     gpgme_error_t err;
518     size_t i;
519    
520     for( i=0; i < nfiles; i++ ) {
521     err = gpgme_op_file_sign_encrypt( ctx, recp, files[i], NULL );
522     if( err )
523     break;
524     }
525     return err;
526     } /* gpgme_op_files_sign_encrypt */
527    
528    
529     gpgme_error_t
530     gpgme_op_clip_sign( gpgme_ctx_t ctx, gpgme_sigmode_t mode,
531     const char * keyid, int wraplen )
532     {
533     gpgme_error_t err;
534     gpgme_data_t plain = NULL;
535     gpgme_data_t sig = NULL;
536     gpgme_key_t key = NULL;
537    
538     if (!keyid)
539     return mk_error (General_Error);
540    
541     gpgme_control (ctx, GPGME_CTRL_ARMOR, 1);
542     err = gpgme_data_new_from_clipboard (&plain);
543     if (err)
544     return err;
545     if (wraplen)
546     gpgme_data_wrap_lines (&plain, wraplen);
547     gpgme_data_write (plain, "\r\n", 1);
548    
549     key = _gpgme_key_new_fromkeyid (keyid);
550     if (!key) {
551     gpgme_data_release (sig);
552     return mk_error (General_Error);
553     }
554    
555     err = gpgme_data_new (&sig);
556     if (!err)
557     err = gpgme_signers_add (ctx, key);
558     if (!err)
559     err = gpgme_op_sign (ctx, plain, sig, mode);
560     if (!err) {
561     gpgme_data_change_version (&sig);
562     gpgme_data_release_and_set_clipboard (sig);
563     }
564    
565     gpgme_data_release (plain);
566     gpgme_key_release (key);
567     return err;
568     } /* gpgme_op_clip_sign */

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26