2 * Copyright (c) 2008, Dave Korn.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * A copy of the GNU General Public License can be found at
12 * Written by Dave Korn <dave.korn.cygwin@gmail.com>
20 #include "io_stream.h"
25 #include "LogSingleton.h"
27 #include "getopt++/StringArrayOption.h"
28 #include "getopt++/BoolOption.h"
29 #include "KeysSetting.h"
30 #include "gpg-packet.h"
33 #define CRYPTODEBUGGING (0)
36 #define ERRKIND __asm__ __volatile__ (".byte 0xcc"); note
37 #define MESSAGE LogBabblePrintf
38 #else /* !CRYPTODEBUGGING */
40 #define MESSAGE while (0) LogBabblePrintf
41 #endif /* CRYPTODEBUGGING */
43 /* Command-line options for specifying and controlling extra keys. */
44 static StringArrayOption
ExtraKeyOption ('K', "pubkey",
45 "URL of extra public key file (gpg format)");
47 static StringArrayOption
SexprExtraKeyOption ('S', "sexpr-pubkey",
48 "Extra public key in s-expr format");
50 static BoolOption
UntrustedKeysOption (false, 'u', "untrusted-keys",
51 "Use untrusted saved extra keys");
52 static BoolOption
KeepUntrustedKeysOption (false, 'U', "keep-untrusted-keys",
53 "Use untrusted keys and retain all");
55 /* Embedded public half of Cygwin DSA signing key. */
56 static const char *cygwin_pubkey_sexpr
=
57 #include "cyg-pubkey.h"
60 /* S-expr template for DSA pubkey. */
61 static const char *dsa_pubkey_templ
= "(public-key (dsa (p %m) (q %m) (g %m) (y %m)))";
63 /* S-expr template for DSA signature. */
64 static const char *dsa_sig_templ
= "(sig-val (dsa (r %m) (s %m)))";
66 /* S-expr template for data block to be signed. */
67 static const char *data_hash_templ
= "(data (flags raw) (value %m))";
69 /* User context data for sig packet walk. */
72 /* MPI values of sig components. */
73 gcry_mpi_t dsa_mpi_r
, dsa_mpi_s
;
86 /* Converted algo code. */
93 /* User context data for key packet walk. */
96 std::vector
<gcry_sexp_t
> keys
;
99 /* Callback hook for walking packets in gpg key file. Extracts
100 the DSA coefficients from any public key packets encountered and
101 converts them into s-expr pubkey format, returning the public
102 keys thus found to the caller in a vector in the userdata context. */
104 pkt_cb_resp
key_file_walker (struct packet_walker
*wlk
, unsigned char tag
,
105 size_t packetsize
, size_t hdrpos
)
107 struct key_data
*kdat
= (struct key_data
*)(wlk
->userdata
);
109 MESSAGE ("key packet %d size %d at offs $%04x kdat $%08x\n", tag
,
110 packetsize
, hdrpos
, kdat
);
112 if (tag
!= RFC4880_PT_PUBLIC_KEY
)
115 // So, get the data out. Version is first. In case of any errors during
116 // parsing, we just discard the key and continue, hoping to find a good one.
117 char ver
= pkt_getch (wlk
->pfile
);
120 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, ver
, "unsupported key version.");
124 // Only V4 accepted. Discard creation time.
125 if (pkt_getdword (wlk
->pfile
) == -1)
127 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, -1, "missing creation time.");
131 char pkalg
= pkt_getch (wlk
->pfile
);
132 if (pkalg
!= RFC4880_PK_DSA
)
134 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, pkalg
, "unsupported key alg.");
138 // Next, the four MPIs should be present. Read them out,
139 // convert to an s-expr and add that to the list.
140 gcry_mpi_t p
, q
, g
, y
;
143 if ((pkt_get_mpi (&p
, wlk
->pfile
) >= 0)
144 && (pkt_get_mpi (&q
, wlk
->pfile
) >= 0)
145 && (pkt_get_mpi (&g
, wlk
->pfile
) >= 0)
146 && (pkt_get_mpi (&y
, wlk
->pfile
) >= 0))
148 // Convert to s-expr.
152 gcry_error_t rv
= gcry_sexp_build (&new_key
, &n
, dsa_pubkey_templ
, p
, q
, g
, y
);
153 if (rv
!= GPG_ERR_NO_ERROR
)
155 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, rv
, "while creating sig s-expr.");
161 char sexprbuf
[GPG_KEY_SEXPR_BUF_SIZE
];
162 n
= gcry_sexp_sprint (new_key
, GCRYSEXP_FMT_ADVANCED
, sexprbuf
,
163 GPG_KEY_SEXPR_BUF_SIZE
);
164 msg ("key:%d\n'%s'", n
, sexprbuf
);
165 #endif /* CRYPTODEBUGGING */
167 // Return it to caller in the vector.
168 kdat
->keys
.push_back (new_key
);
171 // Release temps and continue.
173 gcry_mpi_release (p
);
175 gcry_mpi_release (q
);
177 gcry_mpi_release (g
);
179 gcry_mpi_release (y
);
184 /* Does what its name suggests: feeds a chosen amount of the data found
185 at the current seek position in an io_stream into the message digest
186 context passed in, using reasonably-sized chunks for efficiency. */
188 shovel_stream_data_into_md (io_stream
*stream
, size_t nbytes
, gcry_md_hd_t md
)
190 const size_t TMPBUFSZ
= 1024;
191 unsigned char tmpbuf
[TMPBUFSZ
];
192 size_t this_time
, total
= 0;
194 MESSAGE ("shovel %d bytes at pos $%08x\n", nbytes
, stream
->tell ());
197 this_time
= (nbytes
> TMPBUFSZ
) ? TMPBUFSZ
: nbytes
;
198 actual
= stream
->read (tmpbuf
, this_time
);
201 gcry_md_write (md
, tmpbuf
, actual
);
204 if (actual
!= (ssize_t
)this_time
)
210 /* Canonicalise an s-expr by converting LFs to spaces so that
211 it's all on one line and folding multiple spaces as we go. */
213 fold_lfs_and_spaces (char *buf
, size_t n
)
215 char *ptr1
= buf
, *ptr2
= buf
;
224 while (n
&& ((*ptr1
== ' ') || (*ptr1
== 0x0a)))
233 /* Do-nothing stubs called by the sig file walker to
234 walk over the embedded subpackets. In the event, we don't
235 actually need to do this as we aren't inspecting them. */
237 pkt_cb_resp
hashed_subpkt_walker (struct packet_walker
*wlk
, unsigned char tag
,
238 size_t packetsize
, size_t hdrpos
)
244 pkt_cb_resp
unhashed_subpkt_walker (struct packet_walker
*wlk
, unsigned char tag
,
245 size_t packetsize
, size_t hdrpos
)
250 /* Callback to parse the packets found in the setup.ini/setup.bz2
251 signature file. We have to parse the header to get the hash type
252 and other details. Once we have that we can create a message
253 digest context and start pumping data through it; first the ini
254 file itself, then the portion of the packet itself that is
255 covered by the hash. */
257 pkt_cb_resp
sig_file_walker (struct packet_walker
*wlk
, unsigned char tag
,
258 size_t packetsize
, size_t hdrpos
)
260 struct sig_data
*sigdat
= (struct sig_data
*)(wlk
->userdata
);
261 sigdat
->complete
= false;
263 if (tag
!= RFC4880_PT_SIGNATURE
)
266 // To add the trailers later, we hang on to the current pos.
267 size_t v34hdrofs
= wlk
->pfile
->tell ();
269 // So, get the data out. Version is first.
270 char ver
= pkt_getch (wlk
->pfile
);
271 if ((ver
< 3) || (ver
> 4))
273 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, ver
, "unsupported sig version.");
277 // Only V3 and V4 accepted.
280 sigdat
->sig_type
= pkt_getch (wlk
->pfile
);
281 sigdat
->pk_alg
= pkt_getch (wlk
->pfile
);
282 sigdat
->hash_alg
= pkt_getch (wlk
->pfile
);
286 int hmsize
= pkt_getch (wlk
->pfile
);
287 if (hmsize
!= RFC4880_SIGV3_HASHED_SIZE
)
289 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, hmsize
, "wrong hashed material size.");
292 v34hdrofs
= wlk
->pfile
->tell ();
293 if ((pkt_getch (wlk
->pfile
) < 0) || (pkt_getdword (wlk
->pfile
) == -1))
295 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, hmsize
, "wrong hashed material size.");
298 if ((pkt_getdword (wlk
->pfile
) == -1) || (pkt_getdword (wlk
->pfile
) == -1))
300 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, -1, "missing signer ID.");
304 sigdat
->sig_type
= 0;
305 sigdat
->pk_alg
= pkt_getch (wlk
->pfile
);
306 sigdat
->hash_alg
= pkt_getch (wlk
->pfile
);
309 MESSAGE ("sig type %d, pk_alg %d, hash_alg %d\n", sigdat
->sig_type
,
310 sigdat
->pk_alg
, sigdat
->hash_alg
);
312 // We only handle binary file signatures
313 if (sigdat
->sig_type
!= RFC4880_ST_BINARY
)
315 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, sigdat
->sig_type
, "unsupported sig type.");
318 // And we only speak DSA.
319 if (sigdat
->pk_alg
!= RFC4880_PK_DSA
)
321 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, sigdat
->pk_alg
, "unsupported pk alg.");
325 // Start to hash all the data. Figure out what hash to use.
326 sigdat
->algo
= pkt_convert_hashcode (sigdat
->hash_alg
);
327 if (sigdat
->algo
== GCRY_MD_NONE
)
329 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, sigdat
->hash_alg
, "unconvertible hash.");
333 // Now we know hash algo, we can create md context.
334 gcry_error_t rv
= gcry_md_open (&sigdat
->md
, sigdat
->algo
, 0);
335 if (rv
!= GPG_ERR_NO_ERROR
)
337 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, rv
, "while initialising message digest.");
341 // Add all the sig_file data into the hash.
342 sigdat
->sign_data
->seek (0, IO_SEEK_SET
);
343 size_t nbytes
= sigdat
->sign_data
->get_size ();
344 if (nbytes
!= shovel_stream_data_into_md (sigdat
->sign_data
, nbytes
, sigdat
->md
))
346 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, sigdat
->hash_alg
, "internal buffer error.");
349 sigdat
->sign_data
->seek (0, IO_SEEK_SET
);
351 // V4 now has some hashed subpackets
352 int hashed_subpkt_size
= (ver
== 4) ? pkt_getword (wlk
->pfile
) : 0;
353 if (hashed_subpkt_size
)
354 pkt_walk_subpackets (wlk
->pfile
, hashed_subpkt_walker
, wlk
->owner
,
355 wlk
->pfile
->tell (), hashed_subpkt_size
, wlk
->userdata
);
357 // V4 now has some unhashed subpackets
358 int unhashed_subpkt_size
= (ver
== 4) ? pkt_getword (wlk
->pfile
) : 0;
359 if (unhashed_subpkt_size
)
360 pkt_walk_subpackets (wlk
->pfile
, unhashed_subpkt_walker
, wlk
->owner
,
361 wlk
->pfile
->tell (), unhashed_subpkt_size
, wlk
->userdata
);
363 // Both formats now have 16 bits of the hash value.
364 int hash_first
= pkt_getword (wlk
->pfile
);
366 MESSAGE ("sig type %d, pk_alg %d, hash_alg %d - first $%04x\n", sigdat
->sig_type
,
367 sigdat
->pk_alg
, sigdat
->hash_alg
, hash_first
);
369 /* Algorithm-Specific Fields for DSA signatures:
371 - MPI of DSA value r.
373 - MPI of DSA value s.
375 DSA signatures MUST use hashes that are equal in size to the number
376 of bits of q, the group generated by the DSA key's generator value. */
378 if ((pkt_get_mpi (&sigdat
->dsa_mpi_r
, wlk
->pfile
) < 0)
379 || (pkt_get_mpi (&sigdat
->dsa_mpi_s
, wlk
->pfile
) < 0))
381 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, "unpacking mpi.");
385 MESSAGE ("Read sig packets succesfully!\n");
387 // Now we got all the data out ok, rewind and hash the first trailer.
388 wlk
->pfile
->seek (v34hdrofs
, IO_SEEK_SET
);
389 nbytes
= (ver
== 4) ? (RFC4880_SIGV4_HASHED_OVERHEAD
+ hashed_subpkt_size
)
390 : (RFC4880_SIGV3_HASHED_SIZE
);
391 if (nbytes
!= shovel_stream_data_into_md (wlk
->pfile
, nbytes
, sigdat
->md
))
393 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, sigdat
->hash_alg
, "internal buffer error 2.");
399 // And now the synthetic final trailer.
400 gcry_md_putc (sigdat
->md
, 4);
401 gcry_md_putc (sigdat
->md
, 0xff);
402 gcry_md_putc (sigdat
->md
, (nbytes
>> 24) & 0xff);
403 gcry_md_putc (sigdat
->md
, (nbytes
>> 16) & 0xff);
404 gcry_md_putc (sigdat
->md
, (nbytes
>> 8) & 0xff);
405 gcry_md_putc (sigdat
->md
, nbytes
& 0xff);
408 // Hooray, succeeded!
409 sigdat
->complete
= true;
414 /* Size and allocate a temp buffer to print a representation
415 of a public key s-expr into, then add that to the extra keys
416 setting so it persists for the next run. */
418 add_key_from_sexpr (gcry_sexp_t key
)
420 size_t n
= gcry_sexp_sprint (key
, GCRYSEXP_FMT_ADVANCED
, 0, ~0);
421 char *sexprbuf
= new char[n
];
422 n
= gcry_sexp_sprint (key
, GCRYSEXP_FMT_ADVANCED
, sexprbuf
, n
);
423 // +1 because we want to include the nul-terminator.
424 n
= fold_lfs_and_spaces (sexprbuf
, n
+ 1);
425 ExtraKeysSetting::instance().add_key (sexprbuf
);
426 MESSAGE ("keep:%d\n'%s'", n
, sexprbuf
);
430 /* Verify the signature on an ini file. Takes care of all key-handling. */
432 verify_ini_file_sig (io_stream
*ini_file
, io_stream
*ini_sig_file
, HWND owner
)
434 /* DSA public key in s-expr format. */
437 /* Data returned from packet walker. */
438 struct sig_data sigdat
;
440 /* Vector of extra keys to use. */
441 std::vector
<gcry_sexp_t
> keys_to_try
;
443 /* Vector of cached extra keys from last run. */
444 static std::vector
<gcry_sexp_t
> input_keys
;
446 /* Overall status of signature. */
449 // Temps for intermediate processing.
453 /* Initialise the library. */
454 gcry_check_version (NULL
);
456 /* So first build the built-in key. */
457 rv
= gcry_sexp_new (&dsa_key
, cygwin_pubkey_sexpr
, strlen (cygwin_pubkey_sexpr
), 1);
458 if (rv
!= GPG_ERR_NO_ERROR
)
460 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "while creating pubkey s-expr.");
464 char sexprbuf
[GPG_KEY_SEXPR_BUF_SIZE
];
465 n
= gcry_sexp_sprint (dsa_key
, GCRYSEXP_FMT_ADVANCED
, sexprbuf
, GPG_KEY_SEXPR_BUF_SIZE
);
466 msg ("key:%d\n'%s'", n
, sexprbuf
);
467 #endif /* CRYPTODEBUGGING */
469 /* Next we should extract the keys from the extrakeys user
470 setting, and flush it; we'll only return them to it if they
471 get used. OTOH, should we do this at all? The user settings
472 file isn't heavily protected. So we only trust the extra
473 keys if we're told to by the user. We still read them in
474 and write them back out, which canonicalises and eliminates
475 any duplicates or garbage lines that may have crept in. */
476 static bool input_keys_read
= false;
477 if (!input_keys_read
)
479 // We only want to do this once, first time through:
480 input_keys_read
= true;
481 // Copy all valid keys from ExtraKeysSetting into a
482 // static vector where we can keep them throughout the
483 // remainder of the run.
484 for (size_t i
= 0; i
< ExtraKeysSetting::instance().num_keys (); i
++)
486 const char *keystring
= ExtraKeysSetting::instance().get_key (i
, &n
);
488 rv
= gcry_sexp_new (&newkey
, keystring
, n
, 1);
489 if (rv
== GPG_ERR_NO_ERROR
)
490 input_keys
.push_back (newkey
);
493 // Now flush out the ExtraKeysSetting; from here on it
494 // will build up a list of the keys we want to retain.
495 ExtraKeysSetting::instance().flush ();
497 // Which, if we aren't using them, means all the ones
499 if (KeepUntrustedKeysOption
|| !UntrustedKeysOption
)
501 std::vector
<gcry_sexp_t
>::iterator it
;
502 for (it
= input_keys
.begin (); it
< input_keys
.end (); ++it
)
503 add_key_from_sexpr (*it
);
507 /* Next, there may have been command-line options. */
508 std::vector
<std::string
> SexprExtraKeyStrings
= SexprExtraKeyOption
;
509 for (std::vector
<std::string
>::const_iterator it
510 = SexprExtraKeyStrings
.begin ();
511 it
!= SexprExtraKeyStrings
.end (); ++it
)
513 MESSAGE ("key str is '%s'\n", it
->c_str ());
514 gcry_sexp_t dsa_key2
= 0;
515 rv
= gcry_sexp_new (&dsa_key2
, it
->c_str (), it
->size (), 1);
516 if (rv
== GPG_ERR_NO_ERROR
)
518 // We probably want to add it to the extra keys setting
519 // if KeepUntrustedKeysOption is supplied.
520 if (KeepUntrustedKeysOption
)
521 add_key_from_sexpr (dsa_key2
);
523 n
= gcry_sexp_sprint (dsa_key2
, GCRYSEXP_FMT_ADVANCED
, sexprbuf
,
524 GPG_KEY_SEXPR_BUF_SIZE
);
525 // +1 because we want to include the nul-terminator.
526 n
= fold_lfs_and_spaces (sexprbuf
, n
+ 1);
527 ExtraKeysSetting::instance().add_key (sexprbuf
);
528 msg ("key2:%d\n'%s'", n
, sexprbuf
);
529 #endif /* CRYPTODEBUGGING */
530 keys_to_try
.push_back (dsa_key2
);
534 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "invalid command-line pubkey s-expr.");
538 /* Also, we may have to read a key(s) file. */
539 std::vector
<std::string
> ExtraKeysFiles
= ExtraKeyOption
;
540 for (std::vector
<std::string
>::const_iterator it
541 = ExtraKeysFiles
.begin ();
542 it
!= ExtraKeysFiles
.end (); ++it
)
544 io_stream
*keys
= get_url_to_membuf (*it
, owner
);
547 struct key_data kdat
;
548 pkt_walk_packets (keys
, key_file_walker
, owner
, 0, keys
->get_size (), &kdat
);
549 // We now have a vector of (some/any?) keys returned from
550 // the walker; add them to the list to try.
551 while (!kdat
.keys
.empty ())
553 // We probably want to add it to the extra keys setting
554 // if KeepUntrustedKeysOption is supplied.
555 if (KeepUntrustedKeysOption
)
556 add_key_from_sexpr (kdat
.keys
.back ());
558 n
= gcry_sexp_sprint (kdat
.keys
.back (), GCRYSEXP_FMT_ADVANCED
,
559 sexprbuf
, GPG_KEY_SEXPR_BUF_SIZE
);
560 // +1 because we want to include the nul-terminator.
561 n
= fold_lfs_and_spaces (sexprbuf
, n
+ 1);
562 ExtraKeysSetting::instance().add_key (sexprbuf
);
563 msg ("key3:%d\n'%s'", n
, sexprbuf
);
564 #endif /* CRYPTODEBUGGING */
565 keys_to_try
.push_back (kdat
.keys
.back ());
566 kdat
.keys
.pop_back ();
571 // We pass in a pointer to the ini file in the user context data,
572 // which the packet walker callback uses to create a new hash
573 // context preloaded with all the signature-covered data.
574 sigdat
.complete
= false;
575 sigdat
.sign_data
= ini_file
;
576 sigdat
.dsa_mpi_r
= sigdat
.dsa_mpi_s
= 0;
578 pkt_walk_packets (ini_sig_file
, sig_file_walker
, owner
, 0,
579 ini_sig_file
->get_size (), &sigdat
);
582 /* DSA sig coefficients in s-expr format. */
585 /* DSA signature hash data in s-expr format. */
586 gcry_sexp_t dsa_hash
;
588 /* So, we have hashed all the data, and found the sig coefficients.
589 Next stages are to finalise the hash, build everything into
590 s-exprs, and call the libgcrypt verification routine. */
592 rv
= gcry_sexp_build (&dsa_sig
, &n
, dsa_sig_templ
, sigdat
.dsa_mpi_r
,
594 if (rv
!= GPG_ERR_NO_ERROR
)
596 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "while creating sig s-expr.");
600 gcry_md_final (sigdat
.md
);
602 // Make a temp mpi from the hash output, then an s-expr from that.
603 gcry_mpi_t dsa_mpi_hash
= 0;
604 unsigned char *tmpbuf
= gcry_md_read (sigdat
.md
, 0);
605 size_t dlen
= gcry_md_get_algo_dlen (sigdat
.algo
);
606 rv
= gcry_mpi_scan (&dsa_mpi_hash
, GCRYMPI_FMT_USG
, tmpbuf
, dlen
, 0UL);
607 if (rv
!= GPG_ERR_NO_ERROR
)
609 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "while creating hash MPI.");
613 rv
= gcry_sexp_build (&dsa_hash
, &n
, data_hash_templ
, dsa_mpi_hash
);
614 if (rv
!= GPG_ERR_NO_ERROR
)
616 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "while creating hash s-expr.");
621 n
= gcry_sexp_sprint (dsa_sig
, GCRYSEXP_FMT_ADVANCED
, sexprbuf
,
622 GPG_KEY_SEXPR_BUF_SIZE
);
623 msg ("sig:%d\n'%s'", n
, sexprbuf
);
624 n
= gcry_sexp_sprint (dsa_hash
, GCRYSEXP_FMT_ADVANCED
, sexprbuf
,
625 GPG_KEY_SEXPR_BUF_SIZE
);
626 msg ("hash:%d\n'%s'", n
, sexprbuf
);
627 #endif /* CRYPTODEBUGGING */
629 // Well, we're actually there! Try it against the main key.
630 rv
= gcry_pk_verify (dsa_sig
, dsa_hash
, dsa_key
);
631 // If not that, try any supplied on the commandline.
632 if (rv
!= GPG_ERR_NO_ERROR
)
634 std::vector
<gcry_sexp_t
>::iterator it
;
635 for (it
= keys_to_try
.begin (); it
< keys_to_try
.end (); ++it
)
637 MESSAGE ("Testing a key to try\n");
638 rv
= gcry_pk_verify (dsa_sig
, dsa_hash
, *it
);
639 if (rv
!= GPG_ERR_NO_ERROR
)
641 // Found it! This key gets kept!
642 add_key_from_sexpr (*it
);
646 // We only use the untrusted keys if told to.
647 it
= ((rv
!= GPG_ERR_NO_ERROR
)
648 && (KeepUntrustedKeysOption
|| UntrustedKeysOption
))
649 ? input_keys
.begin ()
651 for ( ; it
< input_keys
.end (); ++it
)
653 MESSAGE ("Testing an input key\n");
654 rv
= gcry_pk_verify (dsa_sig
, dsa_hash
, *it
);
655 if (rv
!= GPG_ERR_NO_ERROR
)
657 // Found it! This key gets kept!
658 add_key_from_sexpr (*it
);
663 sig_ok
= (rv
== GPG_ERR_NO_ERROR
);
666 gcry_err_code_t code
;
667 gcry_err_source_t src
;
668 code
= gcry_err_code (rv
);
669 src
= gcry_err_source (rv
);
670 msg ("Well, pk verify returned $%08x - code %d src %d\n", rv
, code
, src
);
671 #endif /* CRYPTODEBUGGING */
673 gcry_mpi_release (dsa_mpi_hash
);
674 gcry_sexp_release (dsa_sig
);
675 gcry_sexp_release (dsa_hash
);
678 // Discard the temp data then.
679 gcry_sexp_release (dsa_key
);
680 if (sigdat
.dsa_mpi_r
)
681 gcry_mpi_release (sigdat
.dsa_mpi_r
);
682 if (sigdat
.dsa_mpi_s
)
683 gcry_mpi_release (sigdat
.dsa_mpi_s
);
685 gcry_md_close (sigdat
.md
);
686 while (keys_to_try
.size ())
688 gcry_sexp_release (keys_to_try
.back ());
689 keys_to_try
.pop_back ();