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

Annotation of /trunk/MyGPGME/sign.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (hide annotations)
Fri Sep 30 10:10:16 2005 UTC (19 years, 5 months ago) by twoaday
File MIME type: text/plain
File size: 15936 byte(s)
Almost finished phase 1 of the WinPT GPGME port.
Still need more cleanup, comments and tests.


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 twoaday 23 int i;
213 twoaday 2
214     fail_on_pending_request (ctx);
215     ctx->pending = 1;
216    
217     _gpgme_gpg_release (&ctx->gpg);
218     rc = _gpgme_gpg_new (&ctx->gpg);
219     if( rc )
220     return rc;
221    
222     if( ctx->use_logging )
223     _gpgme_gpg_set_logging_handler( ctx->gpg, ctx );
224     _gpgme_gpg_set_status_handler( ctx->gpg, sign_status_handler, ctx );
225     if( !ctx->use_pass_fd )
226     _gpgme_gpg_set_command_handler( ctx->gpg, command_handler, ctx );
227     else {
228     rc = _gpgme_add_passphrase( ctx );
229     if( rc ) {
230     _gpgme_gpg_release( &ctx->gpg );
231     return rc;
232     }
233     }
234    
235     _gpgme_gpg_add_arg (ctx->gpg, "--yes");
236 twoaday 23
237     for (i=0; (key = gpgme_signers_enum (ctx, i)); i++) {
238 twoaday 2 const char * s;
239     s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEYID, NULL, 0);
240     if (!s)
241 twoaday 23 continue;
242     _gpgme_gpg_add_arg (ctx->gpg, "-u");
243 twoaday 2 _gpgme_gpg_add_arg_concat (ctx->gpg, s, "!");
244 twoaday 23 if (signenc) {
245 twoaday 2 _gpgme_gpg_add_arg (ctx->gpg, "--encrypt-to");
246 twoaday 23 _gpgme_gpg_add_arg (ctx->gpg, s);
247 twoaday 2 }
248 twoaday 23 gpgme_key_unref (key);
249 twoaday 2 }
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 twoaday 23 sign_start (gpgme_ctx_t ctx, gpgme_data_t in, gpgme_data_t out, gpgme_sigmode_t mode)
303 twoaday 2 {
304 twoaday 23 gpgme_key_t key;
305 twoaday 2 int rc = 0;
306 twoaday 23 int i;
307 twoaday 2
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 twoaday 23 for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++) {
350 twoaday 2 const char *s;
351 twoaday 23 s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEYID, NULL, 0);
352     if (s) {
353 twoaday 2 _gpgme_gpg_add_arg (ctx->gpg, "-u");
354     _gpgme_gpg_add_arg_concat (ctx->gpg, s, "!");
355     }
356     gpgme_key_unref (key);
357     }
358    
359     /* Check the supplied data */
360     if( gpgme_data_get_type( in ) == GPGME_DATA_TYPE_NONE ) {
361     rc = mk_error( No_Data );
362     goto leave;
363     }
364     _gpgme_data_set_mode(in, GPGME_DATA_MODE_OUT );
365     if( !out || gpgme_data_get_type( out ) != GPGME_DATA_TYPE_NONE ) {
366     rc = mk_error( Invalid_Value );
367     goto leave;
368     }
369     _gpgme_data_set_mode( out, GPGME_DATA_MODE_IN );
370    
371     if( ctx->use_tmpfiles ) {
372     _gpgme_gpg_add_arg( ctx->gpg, "--output" );
373     _gpgme_gpg_add_arg( ctx->gpg, _gpgme_get_tmpfile( 0 ) );
374     _gpgme_data_write_to_tmpfile( in );
375     _gpgme_gpg_add_arg( ctx->gpg, _gpgme_get_tmpfile( 1 ) );
376     }
377     else {
378     /* Tell the gpg object about the data */
379     _gpgme_gpg_add_data( ctx->gpg, in, 0 );
380     _gpgme_gpg_add_data( ctx->gpg, out, 1 );
381     }
382    
383     /* and kick off the process */
384     rc = _gpgme_gpg_spawn( ctx->gpg, ctx );
385    
386     leave:
387     if( rc ) {
388     ctx->pending = 0;
389     _gpgme_gpg_release( &ctx->gpg );
390     }
391     return rc;
392     }
393    
394    
395     static gpgme_error_t
396     get_sign_result( gpgme_ctx_t ctx )
397     {
398     struct sign_result_s * res;
399     gpgme_error_t err = 0;
400    
401     if( ctx->result_type != RESULT_TYPE_SIGN )
402     err = mk_error( General_Error );
403     else if( ctx->out_of_core )
404     err = mk_error( Out_Of_Core );
405     else {
406     assert ( ctx->result.sign );
407     res = ctx->result.sign;
408     if( res->no_passphrase )
409     err = mk_error( No_Passphrase );
410     else if( res->bad_passphrase )
411     err = mk_error( Bad_Passphrase );
412     else if( res->idea_cipher )
413     err = mk_error( Cipher_IDEA );
414     else if( gpgme_get_process_rc( ctx ) )
415 twoaday 7 err = mk_error( Internal_GPG_Problem );
416 twoaday 2 else if( !res->okay )
417     err = mk_error( Signing_Failed );
418     }
419     return err;
420     } /* get_sign_result */
421    
422    
423     /**
424     * gpgme_op_sign:
425     * @c: The context
426     * @in: Data to be signed
427     * @out: Detached signature
428     * @mode: Signature creation mode
429     *
430     * Create a detached signature for @in and write it to @out.
431     * The data will be signed using either the default key or the ones
432     * defined through @c.
433     * The defined modes for signature create are:
434     * <literal>
435     * GPGME_SIG_MODE_NORMAL (or 0)
436     * GPGME_SIG_MODE_DETACH
437     * GPGME_SIG_MODE_CLEAR
438     * </literal>
439     * Note that the settings done by gpgme_set_armor() and gpgme_set_textmode()
440     * are ignore for @mode GPGME_SIG_MODE_CLEAR.
441     *
442     * Return value: 0 on success or an error code.
443     **/
444     gpgme_error_t
445     gpgme_op_sign( gpgme_ctx_t ctx, gpgme_data_t in, gpgme_data_t out, gpgme_sigmode_t mode )
446     {
447     gpgme_error_t err;
448    
449     err = sign_start( ctx, in, out, mode );
450     if ( !err ) {
451     gpgme_wait( ctx, 1 );
452     ctx->pending = 0;
453     if( ctx->use_tmpfiles ) {
454     _gpgme_data_read_from_tmpfile( out );
455     _gpgme_del_tmpfiles( ctx->wipe_fnc );
456     }
457     err = get_sign_result( ctx );
458     }
459     return err;
460     } /* gpgme_op_sign */
461    
462    
463     gpgme_error_t
464 twoaday 23 gpgme_op_file_sign (gpgme_ctx_t ctx, gpgme_sigmode_t mode,
465     const char * input, const char * output)
466 twoaday 2 {
467     gpgme_error_t err;
468    
469 twoaday 23 err = file_sign_start (ctx, 0, mode, NULL, input, output);
470     if (!err) {
471     gpgme_wait (ctx, 1);
472 twoaday 2 ctx->pending = 0;
473 twoaday 23 err = get_sign_result (ctx);
474 twoaday 2 }
475     return err;
476     } /* gpgme_file_sign */
477    
478    
479     gpgme_error_t
480     gpgme_op_files_sign( gpgme_ctx_t ctx, gpgme_sigmode_t mode,
481     const char ** files, size_t nfiles )
482     {
483     gpgme_error_t err;
484     size_t i;
485    
486     for( i=0; i < nfiles; i++ ) {
487     err = gpgme_op_file_sign( ctx, mode, files[i], NULL );
488     if( err )
489     break;
490     }
491     return err;
492     } /* gpgme_op_files_sign */
493    
494    
495     gpgme_error_t
496     gpgme_op_file_sign_encrypt( gpgme_ctx_t ctx, gpgme_recipients_t recp,
497     const char * input, const char * output )
498     {
499     gpgme_error_t err;
500    
501     err = file_sign_start( ctx, 1, GPGME_SIG_MODE_NORMAL, recp, input, output );
502     if( !err ) {
503     gpgme_wait( ctx, 1 );
504     ctx->pending = 0;
505     err = get_sign_result( ctx );
506     }
507     return err;
508     } /* gpgme_op_file_sign_encrypt */
509    
510    
511     gpgme_error_t
512     gpgme_op_files_sign_encrypt( gpgme_ctx_t ctx, gpgme_recipients_t recp,
513     const char ** files, size_t nfiles )
514     {
515     gpgme_error_t err;
516     size_t i;
517    
518     for( i=0; i < nfiles; i++ ) {
519     err = gpgme_op_file_sign_encrypt( ctx, recp, files[i], NULL );
520     if( err )
521     break;
522     }
523     return err;
524     } /* gpgme_op_files_sign_encrypt */
525    
526    
527     gpgme_error_t
528     gpgme_op_clip_sign( gpgme_ctx_t ctx, gpgme_sigmode_t mode,
529     const char * keyid, int wraplen )
530     {
531     gpgme_error_t err;
532     gpgme_data_t plain = NULL;
533     gpgme_data_t sig = NULL;
534     gpgme_key_t key = NULL;
535    
536     if (!keyid)
537     return mk_error (General_Error);
538    
539     gpgme_control (ctx, GPGME_CTRL_ARMOR, 1);
540     err = gpgme_data_new_from_clipboard (&plain);
541     if (err)
542     return err;
543     if (wraplen)
544     gpgme_data_wrap_lines (&plain, wraplen);
545     gpgme_data_write (plain, "\r\n", 1);
546    
547     key = _gpgme_key_new_fromkeyid (keyid);
548     if (!key) {
549     gpgme_data_release (sig);
550     return mk_error (General_Error);
551     }
552    
553     err = gpgme_data_new (&sig);
554     if (!err)
555     err = gpgme_signers_add (ctx, key);
556     if (!err)
557     err = gpgme_op_sign (ctx, plain, sig, mode);
558     if (!err) {
559     gpgme_data_change_version (&sig);
560     gpgme_data_release_and_set_clipboard (sig);
561     }
562    
563     gpgme_data_release (plain);
564     gpgme_key_release (key);
565     return err;
566     } /* gpgme_op_clip_sign */

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26