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

Contents of /trunk/MyGPGME/sign.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (show 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 /* 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 int i;
213
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
237 for (i=0; (key = gpgme_signers_enum (ctx, i)); i++) {
238 const char * s;
239 s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEYID, NULL, 0);
240 if (!s)
241 continue;
242 _gpgme_gpg_add_arg (ctx->gpg, "-u");
243 _gpgme_gpg_add_arg_concat (ctx->gpg, s, "!");
244 if (signenc) {
245 _gpgme_gpg_add_arg (ctx->gpg, "--encrypt-to");
246 _gpgme_gpg_add_arg (ctx->gpg, s);
247 }
248 gpgme_key_unref (key);
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 gpgme_key_t key;
305 int rc = 0;
306 int i;
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 const char *s;
351 s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEYID, NULL, 0);
352 if (s) {
353 _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 err = mk_error( Internal_GPG_Problem );
416 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 gpgme_op_file_sign (gpgme_ctx_t ctx, gpgme_sigmode_t mode,
465 const char * input, const char * output)
466 {
467 gpgme_error_t err;
468
469 err = file_sign_start (ctx, 0, mode, NULL, input, output);
470 if (!err) {
471 gpgme_wait (ctx, 1);
472 ctx->pending = 0;
473 err = get_sign_result (ctx);
474 }
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