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

Contents of /trunk/MyGPGME/verify.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show annotations)
Mon Jan 31 11:02:21 2005 UTC (20 years, 1 month ago) by twoaday
File MIME type: text/plain
File size: 22170 byte(s)
WinPT initial checkin.


1 /* verify.c - signature verification
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 safe_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 <ctype.h>
26 #include <assert.h>
27
28 #include "util.h"
29 #include "context.h"
30 #include "ops.h"
31 #include "gpgme.h"
32
33 struct verify_result_s {
34 struct verify_result_s * next;
35 gpgme_sigstat_t status;
36 gpgme_data_t notation; /* we store an XML fragment here */
37 int collecting; /* private to finish_sig() */
38 int notation_in_data; /* private to add_notation() */
39 char fpr[41]; /* fingerprint of a good signature or keyid of a bad one*/
40 ulong timestamp; /* signature creation time */
41 ulong exptime; /* signature expiration time */
42 unsigned expired:1;
43 int trust;
44 int key_algo;
45 int md_algo;
46 int sig_class;
47 char * user_id;
48 char * policy_url;
49 char * key_server;
50 char * file_name;
51 };
52
53
54 void
55 _gpgme_release_verify_result(_verify_result_t res)
56 {
57 while (res) {
58 _verify_result_t r2 = res->next;
59 gpgme_data_release (res->notation);
60 safe_free (res->user_id);
61 safe_free (res->policy_url );
62 safe_free (res->file_name);
63 safe_free (res->key_server);
64 safe_free (res);
65 res = r2;
66 }
67 } /* _gpgme_release_verify_result */
68
69
70 /*
71 * finish a pending signature info collection and prepare for a new
72 * signature info collection
73 */
74 static void
75 finish_sig( gpgme_ctx_t ctx, int stop )
76 {
77 if( stop )
78 return; /* nothing to do */
79
80 if( ctx->result.verify->collecting ) {
81 _verify_result_t res2;
82
83 ctx->result.verify->collecting = 0;
84 /* create a new result structure */
85 res2 = calloc ( 1, sizeof *res2 );
86 if( !res2 ) {
87 ctx->out_of_core = 1;
88 return;
89 }
90 res2->next = ctx->result.verify;
91 ctx->result.verify = res2;
92 }
93
94 ctx->result.verify->collecting = 1;
95 } /* finish_sig */
96
97
98 static char *
99 read_val( const char * args, int *ret_i )
100 {
101 static char buf[32];
102 int i = *ret_i, pos = 0;
103
104 for( ; args[i] && args[i] != ' '; i++ )
105 buf[pos++] = args[i];
106 buf[pos] = '\0';
107 *ret_i = ++i;
108 return buf;
109 } /* read_val */
110
111
112 static int
113 read_int_val( const char * args, int *ret_i )
114 {
115 char * p = read_val( args, ret_i );
116 return atol( p );
117 } /* read_int_val */
118
119
120 static unsigned
121 read_unsigned_val( const char * args, int *ret_i )
122 {
123 char * p = read_val( args, ret_i );
124 return strtoul( p, NULL, 10 );
125 } /* read_unsigned_val */
126
127
128 static void
129 verify_status_handler( gpgme_ctx_t ctx, gpg_status_code_t code, char * args )
130 {
131 gpgme_data_t in;
132 char * p;
133 int i, j, rc = 0;
134
135 if( ctx->out_of_core )
136 return;
137 if( ctx->result_type == RESULT_TYPE_NONE ) {
138 assert ( !ctx->result.verify );
139 ctx->result.verify = calloc( 1, sizeof *ctx->result.verify );
140 if( !ctx->result.verify ) {
141 ctx->out_of_core = 1;
142 return;
143 }
144 ctx->result_type = RESULT_TYPE_VERIFY;
145 }
146 assert( ctx->result_type == RESULT_TYPE_VERIFY );
147
148 if( code == STATUS_GOODSIG
149 || code == STATUS_REVKEYSIG
150 || code == STATUS_EXPKEYSIG
151 || code == STATUS_BADSIG
152 || code == STATUS_ERRSIG ) {
153 finish_sig( ctx, 0 );
154 if( ctx->out_of_core )
155 return;
156 }
157
158 _gpgme_sigtrust_status_handler (code, args, &ctx->result.verify->trust);
159
160 switch( code ) {
161 case STATUS_FILE_START:
162 if( *args++ == '1' ) {
163 args++;
164 p = ctx->result.verify->file_name = strdup( args );
165 if( !p ) {
166 ctx->out_of_core = 1;
167 return;
168 }
169 }
170 break;
171
172 case STATUS_FILE_DONE:
173 break;
174
175 case STATUS_GOODSIG: /* use it to get the user-id */
176 ctx->result.verify->status = GPGME_SIG_STAT_GOOD;
177 i = 0;
178 while( args[i] && args[i] == ' ' ) /* skip keyid */
179 i++;
180 while( args[i] && args[i] != ' ' )
181 i++;
182 ctx->result.verify->user_id = p = calloc( 1, strlen( args+i ) + 2 );
183 if( !p ) {
184 ctx->out_of_core = 1;
185 return;
186 }
187 j = 0;
188 while( args[i] )
189 p[j++] = args[i++];
190 p[j++] = '\0';
191 break;
192
193 case STATUS_BADSIG:
194 ctx->result.verify->status = GPGME_SIG_STAT_BAD;
195 p = ctx->result.verify->fpr; /* store the keyID in the fpr field */
196 for( i = 0; i < DIM(ctx->result.verify->fpr)
197 && args[i] && args[i] != ' ' ; i++ )
198 *p++ = args[i];
199 *p = '\0';
200 p = ctx->result.verify->user_id = calloc( 1, strlen( args+i ) + 2 );
201 if( !p ) {
202 ctx->out_of_core = 1;
203 return;
204 }
205 j = 0;
206 while( args[i] )
207 p[j++] = args[i++];
208 p[j++] = '\0';
209 break;
210
211 case STATUS_EXPKEYSIG:
212 case STATUS_REVKEYSIG:
213 if( code == STATUS_EXPKEYSIG )
214 ctx->result.verify->status = GPGME_SIG_STAT_E_GOOD;
215 else if( code == STATUS_REVKEYSIG )
216 ctx->result.verify->status = GPGME_SIG_STAT_R_GOOD;
217 for( i=0, p=ctx->result.verify->fpr;
218 args[i] && args[i] != ' '; i++ )
219 *p++ = args[i];
220 *p = '\0';
221 p = ctx->result.verify->user_id = calloc( 1, strlen( args+i ) + 2 );
222 if( !p ) {
223 ctx->out_of_core = 1;
224 return;
225 }
226 j=0;
227 while( args[i] )
228 p[j++] = args[i++];
229 p[j++] = '\0';
230 break;
231
232 case STATUS_VALIDSIG:
233 p = ctx->result.verify->fpr;
234 for( i = 0; i < DIM(ctx->result.verify->fpr)
235 && args[i] && args[i] != ' ' ; i++ )
236 *p++ = args[i];
237 *p = 0;
238 /* skip the formatted date */
239 while( args[i] && args[i] == ' ')
240 i++;
241 while( args[i] && args[i] != ' ')
242 i++;
243 /* and get the timestamp */
244 ctx->result.verify->timestamp = strtoul( args+i, NULL, 10 );
245 /* and the expire timestamp */
246 while( args[i] && args[i] == ' ' )
247 i++;
248 while( args[i] && args[i] != ' ' )
249 i++;
250 ctx->result.verify->exptime = strtoul( args+i, NULL, 10 );
251 break;
252
253 case STATUS_ERRSIG:
254 ctx->result.verify->status = GPGME_SIG_STAT_ERROR;
255 p = ctx->result.verify->fpr;
256 for( i = 0; i < DIM(ctx->result.verify->fpr )
257 && args[i] && args[i] != ' ' ; i++ )
258 *p++ = args[i];
259 *p = 0;
260 i++;
261 ctx->result.verify->key_algo = read_int_val( args, &i );
262 ctx->result.verify->md_algo = read_int_val( args, &i );
263 ctx->result.verify->sig_class = read_int_val( args, &i );
264 ctx->result.verify->timestamp = read_unsigned_val( args, &i );
265 rc = read_int_val( args, &i );
266 if( rc == 9 )
267 ctx->result.verify->status = GPGME_SIG_STAT_NOKEY;
268 break;
269
270 case STATUS_EXPSIG:
271 ctx->result.verify->expired = 1;
272 break;
273
274 case STATUS_NO_PUBKEY:
275 ctx->result.verify->status = GPGME_SIG_STAT_NOKEY;
276 break;
277
278 case STATUS_NOTATION_NAME:
279 if( !ctx->result.verify->notation )
280 gpgme_data_new( &ctx->result.verify->notation );
281 in = ctx->result.verify->notation;
282 gpgme_data_write( in, args, strlen( args ) );
283 gpgme_data_write( in, "=", 1 );
284 break;
285
286 case STATUS_NOTATION_DATA:
287 in = ctx->result.verify->notation;
288 for( i = 0; args[i] && in; i++ ) {
289 if( args[i] == '%' ) {
290 gpgme_data_putc( in, ' ' );
291 i += 2;
292 }
293 else
294 gpgme_data_putc( in, args[i] );
295 }
296 break;
297
298 case STATUS_SIG_SUBPACKET:
299 i=0;
300 read_int_val (args, &i);
301 read_int_val (args, &i);
302 j = read_int_val (args, &i);
303 p = ctx->result.verify->key_server = calloc (1, j+1);
304 if (!p) {
305 ctx->out_of_core = 1;
306 break;
307 }
308 memcpy (p, args+i, j);
309 break;
310
311 case STATUS_POLICY_URL:
312 p = ctx->result.verify->policy_url = strdup (args);
313 if (!p)
314 ctx->out_of_core = 1;
315 break;
316
317 case STATUS_EOF:
318 finish_sig( ctx, 1 );
319 break;
320 }
321 } /* verify_status_handler */
322
323
324 static const char *
325 verify_command_handler( void *opaque, gpg_status_code_t code, const char *key )
326 {
327 gpgme_ctx_t ctx = opaque;
328
329 if( !code || !key )
330 return NULL;
331
332 if( code == STATUS_GET_LINE && !strcmp( key, "detached_signature.filename" ) )
333 return ctx->tmp_id;
334
335 return NULL;
336 } /* verify_command_handler */
337
338
339 static long
340 verify_get_sig_date( gpgme_data_t sig )
341 {
342 gpgme_ctx_t ctx;
343 gpgme_data_t out;
344 gpgme_error_t rc;
345 const char * s;
346 char buf[128], tbuf[32];
347 size_t nread = 0, i = 0;
348 long timestamp = 0;
349
350 rc = gpgme_new( &ctx );
351 if( rc )
352 return 0;
353 gpgme_data_rewind( sig );
354 gpgme_data_read( sig, buf, 40, &nread );
355
356 _gpgme_gpg_new( &ctx->gpg );
357 _gpgme_gpg_add_arg( ctx->gpg, "--list-packets" );
358 gpgme_data_new( &out );
359 _gpgme_data_set_mode( out, GPGME_DATA_MODE_IN );
360
361 _gpgme_gpg_add_arg( ctx->gpg, "--output" );
362 _gpgme_gpg_add_arg( ctx->gpg, "-" );
363 _gpgme_gpg_add_data( ctx->gpg, out, 1 );
364 _gpgme_gpg_add_arg( ctx->gpg, "--" );
365 _gpgme_gpg_add_data( ctx->gpg, sig, 0 );
366
367 rc = _gpgme_gpg_spawn( ctx->gpg, ctx );
368 if( !rc ) {
369 gpgme_wait( ctx, 1 );
370 nread = gpgme_data_readline( out, buf, sizeof buf-1 );
371 if( !nread )
372 goto end;
373 nread = gpgme_data_readline( out, buf, sizeof buf -1 );
374 if( !nread )
375 goto end;
376 s = buf;
377 while( s && (*s == ' ' || * s == '\t') )
378 s++;
379 if( strstr( s, "version" ) && strlen( s ) > 20 ) {
380 s += 19;
381 while( isdigit( *s ) ) {
382 tbuf[i++] = *s;
383 s++;
384 }
385 tbuf[i++] = '\0';
386 timestamp = atol( tbuf );
387 }
388 }
389
390 end:
391 gpgme_data_release( out );
392 gpgme_release( ctx );
393 return timestamp;
394 }
395
396
397 static gpgme_error_t
398 verify_start (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t text)
399 {
400 gpgme_error_t rc = 0;
401
402 fail_on_pending_request( ctx );
403 ctx->pending = 1;
404
405 _gpgme_release_result( ctx );
406 ctx->out_of_core = 0;
407
408 _gpgme_gpg_release( &ctx->gpg );
409 rc = _gpgme_gpg_new ( &ctx->gpg );
410 if( rc )
411 goto leave;
412
413 if( ctx->use_logging )
414 _gpgme_gpg_set_logging_handler( ctx->gpg, ctx );
415 _gpgme_gpg_set_status_handler( ctx->gpg, verify_status_handler, ctx );
416
417 /* build the commandline */
418 _gpgme_gpg_add_arg ( ctx->gpg, "--verify" );
419 /* Check the supplied data */
420 if( gpgme_data_get_type( sig ) == GPGME_DATA_TYPE_NONE ) {
421 rc = mk_error( No_Data );
422 goto leave;
423 }
424 if( text && gpgme_data_get_type( text ) == GPGME_DATA_TYPE_NONE ) {
425 rc = mk_error( No_Data );
426 goto leave;
427 }
428 _gpgme_data_set_mode( sig, GPGME_DATA_MODE_OUT );
429 if (text) /* detached signature */
430 _gpgme_data_set_mode (text, GPGME_DATA_MODE_OUT);
431 /* Tell the gpg object about the data */
432 _gpgme_gpg_add_arg (ctx->gpg, "--");
433 _gpgme_gpg_add_data (ctx->gpg, sig, -1);
434 if (text) {
435 _gpgme_gpg_add_arg (ctx->gpg, "-");
436 _gpgme_gpg_add_data (ctx->gpg, text, 0);
437 }
438
439 /* and kick off the process */
440 rc = _gpgme_gpg_spawn (ctx->gpg, ctx);
441
442 leave:
443 if( rc ) {
444 ctx->pending = 0;
445 _gpgme_gpg_release( &ctx->gpg );
446 }
447
448 return rc;
449 } /* verify_start */
450
451
452 static gpgme_error_t
453 file_verify_start( gpgme_ctx_t ctx, gpgme_sigmode_t sigmode ,
454 const char ** sigfile, size_t nfiles, const char * datfile )
455 {
456 gpgme_error_t rc = 0;
457
458 fail_on_pending_request( ctx );
459 ctx->pending = 1;
460
461 _gpgme_gpg_release( &ctx->gpg );
462 rc = _gpgme_gpg_new( &ctx->gpg );
463 if( rc ) {
464 _gpgme_gpg_release( &ctx->gpg );
465 return rc;
466 }
467
468 _gpgme_gpg_set_status_handler( ctx->gpg, verify_status_handler, ctx );
469 _gpgme_gpg_set_command_handler( ctx->gpg, verify_command_handler, ctx );
470
471 _gpgme_gpg_add_arg( ctx->gpg, "--yes" );
472 if( ctx->pipemode || nfiles > 1 )
473 _gpgme_gpg_add_arg( ctx->gpg, "--verify-files" );
474 else if( sigmode != GPGME_SIG_MODE_DETACH )
475 _gpgme_gpg_add_arg( ctx->gpg, "--verify" );
476 else {
477 ctx->tmp_id = strdup( datfile );
478 if( !ctx->tmp_id ) {
479 ctx->out_of_core = 1;
480 return mk_error( Out_Of_Core );
481 }
482 }
483
484 while( nfiles-- )
485 _gpgme_gpg_add_arg( ctx->gpg, *sigfile++ );
486
487 rc = _gpgme_gpg_spawn( ctx->gpg, ctx );
488 if( rc ) {
489 ctx->pending = 0;
490 _gpgme_gpg_release( &ctx->gpg );
491 }
492
493 return rc;
494 } /* gpgme_file_verify_start */
495
496
497 /*
498 * Figure out a common status value for all signatures
499 */
500 static gpgme_sigstat_t
501 intersect_stati( _verify_result_t res )
502 {
503 gpgme_sigstat_t status = res->status;
504
505 for( res = res->next; res; res = res->next ) {
506 if( status != res->status )
507 return GPGME_SIG_STAT_DIFF;
508 }
509
510 return status;
511 } /* intersect_stati */
512
513
514 static char*
515 get_sig_userid( gpgme_ctx_t ctx, int idx )
516 {
517 _verify_result_t res;
518
519 if( !ctx )
520 return NULL;
521 for( res = ctx->result.verify; res && idx>0; res = res->next, idx-- )
522 ;
523 if( !res )
524 return NULL;
525 return res->user_id? strdup( res->user_id ) : NULL;
526 } /* get_sig_userid */
527
528
529 static gpgme_error_t
530 read_sig_results( gpgme_ctx_t ctx, gpgme_sig_t * r_sigctx )
531 {
532 gpgme_sig_t root = NULL, node;
533 gpgme_error_t err;
534 size_t i, n;
535
536 gpgme_get_sig_ctx( ctx, -1, &n, NULL );
537 for( i = 0; i < n; i++ ) {
538 err = gpgme_get_sig_ctx( ctx, i, NULL, &node );
539 if( !err ) {
540 if( node->sigstat != GPGME_SIG_STAT_NOKEY )
541 err = gpgme_get_sig_key( ctx, i, &node->key );
542 }
543 if( !root )
544 root = node;
545 else {
546 gpgme_sig_t s;
547 for( s = root; s->next; s = s->next )
548 ;
549 s->next = node;
550 }
551 }
552 *r_sigctx = root;
553 return err;
554 } /* read_sig_results */
555
556
557 /**
558 * gpgme_op_verify:
559 * @c: the context
560 * @sig: the signature data
561 * @text: the signed text
562 *
563 * Perform a signature check on the signature given in @sig. Currently it is
564 * assumed that this is a detached signature for the material given in @text.
565 * The result of this operation is returned via gpgme_get_sig_ctx ().
566 *
567 * Return value: 0 on success or an errorcode if something not related to
568 * the signature itself did go wrong.
569 **/
570 gpgme_error_t
571 gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t text)
572 {
573 gpgme_error_t rc;
574
575 gpgme_data_release (ctx->notation);
576 ctx->notation = NULL;
577
578 rc = verify_start( ctx, sig, text );
579 if( !rc ) {
580 gpgme_wait( ctx, 1 );
581 if( ctx->result_type != RESULT_TYPE_VERIFY )
582 rc = mk_error( General_Error );
583 else if ( ctx->out_of_core )
584 rc = mk_error( Out_Of_Core );
585 else {
586 assert ( ctx->result.verify );
587 if( ctx->result.verify->notation ) {
588 gpgme_data_t dh = ctx->result.verify->notation;
589 ctx->notation = dh;
590 ctx->result.verify->notation = NULL;
591 }
592 if( intersect_stati( ctx->result.verify ) == GPGME_SIG_STAT_BAD )
593 ctx->result.verify->timestamp = verify_get_sig_date( sig );
594 }
595 ctx->pending = 0;
596 }
597
598 return rc;
599 } /* gpgme_op_verify */
600
601
602 gpgme_error_t
603 gpgme_op_file_verify( gpgme_ctx_t ctx, gpgme_sigmode_t sigmode,
604 gpgme_sig_t * r_sigctx,
605 const char * sigfile, const char * datfile )
606
607 {
608 const char * s[1];
609 gpgme_error_t rc = 0;
610
611 s[0] = sigfile;
612 rc = file_verify_start( ctx, sigmode, s, 1, datfile );
613 if( !rc ) {
614 gpgme_wait( ctx, 1 );
615 ctx->pending = 0;
616 if( ctx->result_type != RESULT_TYPE_VERIFY )
617 rc = mk_error( General_Error );
618 else if( ctx->out_of_core )
619 rc = mk_error( Out_Of_Core );
620 else {
621 assert( ctx->result.verify );
622 if( ctx->result.verify->notation ) {
623 gpgme_data_t dh = ctx->result.verify->notation;
624 ctx->notation = dh;
625 ctx->result.verify->notation = NULL;
626 }
627 if( intersect_stati( ctx->result.verify ) == GPGME_SIG_STAT_BAD ) {
628 gpgme_data_t sig;
629 rc = gpgme_data_new_from_file (&sig, sigfile);
630 if( !rc ) {
631 ctx->result.verify->timestamp = verify_get_sig_date( sig );
632 gpgme_data_release( sig );
633 }
634 }
635 rc = read_sig_results( ctx, r_sigctx );
636 }
637 }
638
639 return rc;
640 } /* gpgme_op_file_verify */
641
642
643 gpgme_error_t
644 gpgme_op_files_verify( gpgme_ctx_t ctx, const char ** files, size_t nfiles,
645 gpgme_sig_t * ret_sig )
646 {
647 gpgme_error_t rc;
648
649 rc = file_verify_start( ctx, 0, files, nfiles, NULL );
650 if( !rc ) {
651 gpgme_wait( ctx, 1 );
652 ctx->pending = 0;
653 if( ctx->result_type != RESULT_TYPE_VERIFY )
654 rc = mk_error( General_Error );
655 else if( ctx->out_of_core )
656 rc = mk_error( Out_Of_Core );
657 else
658 read_sig_results( ctx, ret_sig );
659 }
660 return rc;
661 }
662
663
664 /**
665 * gpgme_get_sig_ctx:
666 * @ctx: Context
667 * @idx: Index of the signature starting at 0
668 * @r_stat: Returns the status
669 * @r_created: Returns the creation timestamp
670 *
671 * Return information about an already verified signatures.
672 *
673 * Return value: The fingerprint or NULL in case of an problem or
674 * when there are no more signatures.
675 **/
676 gpgme_error_t
677 gpgme_get_sig_ctx (gpgme_ctx_t ctx, int idx, size_t * r_ncount,
678 gpgme_sig_t * r_sig )
679 {
680 _verify_result_t res;
681 gpgme_sig_t sig;
682 gpgme_error_t err;
683 int idx_old = idx;
684
685 if( idx == -1 && !r_sig && r_ncount ) {
686 size_t n = 0;
687 for( res = ctx->result.verify; res; res = res->next )
688 n++;
689 *r_ncount = n;
690 }
691
692 if (!r_sig)
693 return mk_error (Invalid_Value);
694 if (!ctx || ctx->pending || ctx->result_type != RESULT_TYPE_VERIFY)
695 return mk_error (General_Error); /* No results yet or verification error */
696
697 for (res = ctx->result.verify; res && idx > 0 ; res = res->next, idx--)
698 ;
699 if (!res)
700 return mk_error (Invalid_Value); /* No more signatures */
701
702 *r_sig = NULL;
703 err = gpgme_sig_new (&sig);
704 if (err)
705 return err;
706
707 sig->flags.expired = res->expired;
708 sig->sigstat = res->status;
709 sig->created = res->timestamp;
710 sig->expired = res->exptime;
711 strcpy( sig->id, res->fpr );
712 sig->notation = gpgme_get_notation( ctx );
713 sig->trust = res->trust;
714 sig->key_algo = res->key_algo;
715 sig->md_algo = res->md_algo;
716 sig->class = res->sig_class;
717 sig->user_id = get_sig_userid( ctx, idx_old );
718 sig->policy_url = res->policy_url? strdup (res->policy_url) : NULL;
719 sig->file_name = res->file_name? strdup (res->file_name) : NULL;
720 sig->key_server = res->key_server? strdup (res->key_server) : NULL;
721 *r_sig = sig;
722 return 0;
723 } /* gpgme_get_sig_ctx */
724
725
726 /**
727 * gpgme_get_sig_key:
728 * @c: context
729 * @idx: Index of the signature starting at 0
730 * @r_key: Returns the key object
731 *
732 * Return a key object which was used to check the signature.
733 *
734 * Return value: An Errorcode or 0 for success. GPGME_EOF is returned to
735 * indicate that there are no more signatures.
736 **/
737 gpgme_error_t
738 gpgme_get_sig_key( gpgme_ctx_t ctx, int idx, gpgme_key_t * r_key )
739 {
740 _verify_result_t res;
741 gpgme_ctx_t listctx = NULL;
742 gpgme_error_t err;
743
744 if( !ctx || !r_key )
745 return mk_error( Invalid_Value );
746 if( ctx->pending || ctx->result_type != RESULT_TYPE_VERIFY )
747 return mk_error( Busy );
748
749 for( res = ctx->result.verify; res && idx>0 ; res = res->next, idx-- )
750 ;
751 if( !res )
752 return mk_error( EOF );
753
754 if( strlen( res->fpr ) < 16 ) /* we have at least an key ID */
755 return mk_error( Invalid_Key );
756
757 if( ctx->key_lookup )
758 err = gpgme_keycache_find_key( ctx->key_lookup, res->fpr, 0, r_key );
759 else {
760 err = gpgme_new( &listctx );
761 if( !err ) {
762 gpgme_control( listctx, GPGME_CTRL_LISTMODE, listctx->keylist_mode );
763 err = gpgme_op_keylist_start( listctx, res->fpr, 0 );
764 }
765 if( !err )
766 err = gpgme_op_keylist_next( listctx, r_key );
767 gpgme_release( listctx );
768 }
769
770 return err;
771 } /* gpgme_get_sig_key */
772
773
774 gpgme_error_t
775 gpgme_op_clip_verify (gpgme_keycache_t cache, gpgme_sig_t * r_sigctx)
776 {
777 gpgme_error_t err;
778 gpgme_data_t sig = NULL;
779 gpgme_ctx_t ctx = NULL;
780
781
782 err = gpgme_new (&ctx);
783 if (!err) {
784 if (cache)
785 gpgme_set_cache_ctx (ctx, cache);
786 }
787 if (!err)
788 err = gpgme_data_new_from_clipboard (&sig);
789 if (!err)
790 err = gpgme_op_verify (ctx, sig, NULL);
791 if (!err)
792 err = read_sig_results (ctx, r_sigctx);
793 gpgme_data_release (sig);
794 gpgme_release (ctx);
795
796 return err;
797 } /* gpgme_op_clip_verify */
798
799
800 gpgme_error_t
801 gpgme_op_clip_verify_detached( gpgme_keycache_t cache, gpgme_sig_t * r_sigctx,
802 const char * data, size_t len )
803 {
804 gpgme_error_t err;
805 gpgme_data_t sig = NULL;
806 gpgme_data_t text = NULL;
807 gpgme_ctx_t ctx = NULL;
808
809 err = gpgme_new( &ctx );
810 if( !err )
811 err = gpgme_data_new_from_mem( &text, data, len, 1 );
812 if( !err )
813 if( !err && cache )
814 gpgme_set_cache_ctx( ctx, cache );
815 if( !err )
816 err = gpgme_data_new_from_clipboard (&sig);
817 if( !err )
818 err = gpgme_op_verify( ctx, sig, text );
819 if( !err )
820 err = read_sig_results( ctx, r_sigctx );
821
822 gpgme_data_release( sig );
823 gpgme_data_release( text );
824 gpgme_release( ctx );
825
826 return err;
827 } /* gpgme_op_clip_verify_detached */

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26