]> cygwin.com Git - cygwin-apps/setup.git/blob - crypto.cc
* prereq.cc (PrereqChecker::getUnmetString): Improve dependency list
[cygwin-apps/setup.git] / crypto.cc
1 /*
2 * Copyright (c) 2008, Dave Korn.
3 *
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.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by Dave Korn <dave.korn.cygwin@gmail.com>
13 *
14 */
15
16 #if 0
17 static const char *cvsid =
18 "\n%%% $Id$\n";
19 #endif
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <vector>
25 #include "io_stream.h"
26 #include "crypto.h"
27 #include "compress.h"
28 #include "gcrypt.h"
29 #include "msg.h"
30 #include "resource.h"
31 #include "getopt++/StringOption.h"
32 #include "getopt++/BoolOption.h"
33 #include "KeysSetting.h"
34 #include "gpg-packet.h"
35 #include "geturl.h"
36
37 #define CRYPTODEBUGGING (0)
38
39 #if CRYPTODEBUGGING
40 #define ERRKIND __asm__ __volatile__ (".byte 0xcc"); note
41 #define MESSAGE msg
42 #else /* !CRYPTODEBUGGING */
43 #define ERRKIND note
44 #define MESSAGE while (0) msg
45 #endif /* CRYPTODEBUGGING */
46
47 /* Command-line options for specifying and controlling extra keys. */
48 static StringOption ExtraKeyOption ("", 'K', "pubkey",
49 "Path to extra public key file (gpg format)", true);
50
51 static StringOption SexprExtraKeyOption ("", 'S', "sexpr-pubkey",
52 "Extra public key in s-expr format", true);
53
54 static BoolOption UntrustedKeysOption (false, 'u', "untrusted-keys",
55 "Use untrusted keys from last-extrakeys");
56 static BoolOption KeepUntrustedKeysOption (false, 'U', "keep-untrusted-keys",
57 "Use untrusted keys and retain all");
58
59 /* Embedded public half of Cygwin DSA signing key. */
60 static const char *cygwin_pubkey_sexpr =
61 #include "cyg-pubkey.h"
62 ;
63
64 /* S-expr template for DSA pubkey. */
65 static const char *dsa_pubkey_templ = "(public-key (dsa (p %m) (q %m) (g %m) (y %m)))";
66
67 /* S-expr template for DSA signature. */
68 static const char *dsa_sig_templ = "(sig-val (dsa (r %m) (s %m)))";
69
70 /* S-expr template for data block to be signed. */
71 static const char *data_hash_templ = "(data (flags raw) (value %m))";
72
73 /* User context data for sig packet walk. */
74 struct sig_data
75 {
76 /* MPI values of sig components. */
77 gcry_mpi_t dsa_mpi_r, dsa_mpi_s;
78
79 /* Hash context. */
80 gcry_md_hd_t md;
81
82 /* Main data. */
83 io_stream *sign_data;
84
85 /* Auxiliary data. */
86 int sig_type;
87 int pk_alg;
88 int hash_alg;
89
90 /* Converted algo code. */
91 int algo;
92
93 /* Final status. */
94 bool complete;
95 };
96
97 /* User context data for key packet walk. */
98 struct key_data
99 {
100 std::vector<gcry_sexp_t> keys;
101 };
102
103 /* Callback hook for walking packets in gpg key file. Extracts
104 the DSA coefficients from any public key packets encountered and
105 converts them into s-expr pubkey format, returning the public
106 keys thus found to the caller in a vector in the userdata context. */
107 static enum
108 pkt_cb_resp key_file_walker (struct packet_walker *wlk, unsigned char tag,
109 size_t packetsize, size_t hdrpos)
110 {
111 struct key_data *kdat = (struct key_data *)(wlk->userdata);
112
113 MESSAGE ("key packet %d size %d at offs $%04x kdat $%08x\n", tag,
114 packetsize, hdrpos, kdat);
115
116 if (tag != RFC4880_PT_PUBLIC_KEY)
117 return pktCONTINUE;
118
119 // So, get the data out. Version is first. In case of any errors during
120 // parsing, we just discard the key and continue, hoping to find a good one.
121 char ver = pkt_getch (wlk->pfile);
122 if (ver != 4)
123 {
124 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, ver, "unsupported key version.");
125 return pktCONTINUE;
126 }
127
128 // Only V4 accepted. Discard creation time.
129 if (pkt_getdword (wlk->pfile) == -1)
130 {
131 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, -1, "missing creation time.");
132 return pktCONTINUE;
133 }
134
135 char pkalg = pkt_getch (wlk->pfile);
136 if (pkalg != RFC4880_PK_DSA)
137 {
138 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, pkalg, "unsupported key alg.");
139 return pktCONTINUE;
140 }
141
142 // Next, the four MPIs should be present. Read them out,
143 // convert to an s-expr and add that to the list.
144 gcry_mpi_t p, q, g, y;
145 p = q = g = y = 0;
146
147 if ((pkt_get_mpi (&p, wlk->pfile) >= 0)
148 && (pkt_get_mpi (&q, wlk->pfile) >= 0)
149 && (pkt_get_mpi (&g, wlk->pfile) >= 0)
150 && (pkt_get_mpi (&y, wlk->pfile) >= 0))
151 {
152 // Convert to s-expr.
153 gcry_sexp_t new_key;
154 size_t n;
155
156 gcry_error_t rv = gcry_sexp_build (&new_key, &n, dsa_pubkey_templ, p, q, g, y);
157 if (rv != GPG_ERR_NO_ERROR)
158 {
159 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, rv, "while creating sig s-expr.");
160 return pktCONTINUE;
161 }
162
163 #if CRYPTODEBUGGING
164 // Debugging
165 char sexprbuf[GPG_KEY_SEXPR_BUF_SIZE];
166 n = gcry_sexp_sprint (new_key, GCRYSEXP_FMT_ADVANCED, sexprbuf,
167 GPG_KEY_SEXPR_BUF_SIZE);
168 msg ("key:%d\n'%s'", n, sexprbuf);
169 #endif /* CRYPTODEBUGGING */
170
171 // Return it to caller in the vector.
172 kdat->keys.push_back (new_key);
173 }
174
175 // Release temps and continue.
176 if (p)
177 gcry_mpi_release (p);
178 if (q)
179 gcry_mpi_release (q);
180 if (g)
181 gcry_mpi_release (g);
182 if (y)
183 gcry_mpi_release (y);
184
185 return pktCONTINUE;
186 }
187
188 /* Does what its name suggests: feeds a chosen amount of the data found
189 at the current seek position in an io_stream into the message digest
190 context passed in, using reasonably-sized chunks for efficiency. */
191 static size_t
192 shovel_stream_data_into_md (io_stream *stream, size_t nbytes, gcry_md_hd_t md)
193 {
194 const size_t TMPBUFSZ = 1024;
195 unsigned char tmpbuf[TMPBUFSZ];
196 size_t this_time, total = 0;
197 ssize_t actual;
198 MESSAGE ("shovel %d bytes at pos $%08x\n", nbytes, stream->tell ());
199 while (nbytes)
200 {
201 this_time = (nbytes > TMPBUFSZ) ? TMPBUFSZ : nbytes;
202 actual = stream->read (tmpbuf, this_time);
203 if (actual <= 0)
204 break;
205 gcry_md_write (md, tmpbuf, actual);
206 total += actual;
207 nbytes -= actual;
208 if (actual != (ssize_t)this_time)
209 break;
210 }
211 return total;
212 }
213
214 /* Canonicalise an s-expr by converting LFs to spaces so that
215 it's all on one line and folding multiple spaces as we go. */
216 static size_t
217 fold_lfs_and_spaces (char *buf, size_t n)
218 {
219 char *ptr1 = buf, *ptr2 = buf;
220
221 while (n--)
222 {
223 char ch = *ptr1++;
224 if (ch == 0x0a)
225 ch = ' ';
226 *ptr2++ = ch;
227 if (ch == 0x20)
228 while (n && ((*ptr1 == ' ') || (*ptr1 == 0x0a)))
229 {
230 --n;
231 ++ptr1;
232 }
233 }
234 return ptr2 - buf;
235 }
236
237 /* Do-nothing stubs called by the sig file walker to
238 walk over the embedded subpackets. In the event, we don't
239 actually need to do this as we aren't inspecting them. */
240 static enum
241 pkt_cb_resp hashed_subpkt_walker (struct packet_walker *wlk, unsigned char tag,
242 size_t packetsize, size_t hdrpos)
243 {
244 return pktCONTINUE;
245 }
246
247 static enum
248 pkt_cb_resp unhashed_subpkt_walker (struct packet_walker *wlk, unsigned char tag,
249 size_t packetsize, size_t hdrpos)
250 {
251 return pktCONTINUE;
252 }
253
254 /* Callback to parse the packets found in the setup.ini/setup.bz2
255 signature file. We have to parse the header to get the hash type
256 and other details. Once we have that we can create a message
257 digest context and start pumping data through it; first the ini
258 file itself, then the portion of the packet itself that is
259 covered by the hash. */
260 static enum
261 pkt_cb_resp sig_file_walker (struct packet_walker *wlk, unsigned char tag,
262 size_t packetsize, size_t hdrpos)
263 {
264 struct sig_data *sigdat = (struct sig_data *)(wlk->userdata);
265 sigdat->complete = false;
266
267 if (tag != RFC4880_PT_SIGNATURE)
268 return pktCONTINUE;
269
270 // To add the trailers later, we hang on to the current pos.
271 size_t v34hdrofs = wlk->pfile->tell ();
272
273 // So, get the data out. Version is first.
274 char ver = pkt_getch (wlk->pfile);
275 if ((ver < 3) || (ver > 4))
276 {
277 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, ver, "unsupported sig version.");
278 return pktHALT;
279 }
280
281 // Only V3 and V4 accepted.
282 if (ver == 4)
283 {
284 sigdat->sig_type = pkt_getch (wlk->pfile);
285 sigdat->pk_alg = pkt_getch (wlk->pfile);
286 sigdat->hash_alg = pkt_getch (wlk->pfile);
287 }
288 else
289 {
290 int hmsize = pkt_getch (wlk->pfile);
291 if (hmsize != RFC4880_SIGV3_HASHED_SIZE)
292 {
293 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, hmsize, "wrong hashed material size.");
294 return pktHALT;
295 }
296 v34hdrofs = wlk->pfile->tell ();
297 if ((pkt_getch (wlk->pfile) < 0) || (pkt_getdword (wlk->pfile) == -1))
298 {
299 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, hmsize, "wrong hashed material size.");
300 return pktHALT;
301 }
302 if ((pkt_getdword (wlk->pfile) == -1) || (pkt_getdword (wlk->pfile) == -1))
303 {
304 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, -1, "missing signer ID.");
305 return pktHALT;
306 }
307
308 sigdat->sig_type = 0;
309 sigdat->pk_alg = pkt_getch (wlk->pfile);
310 sigdat->hash_alg = pkt_getch (wlk->pfile);
311 }
312
313 MESSAGE ("sig type %d, pk_alg %d, hash_alg %d\n", sigdat->sig_type,
314 sigdat->pk_alg, sigdat->hash_alg);
315
316 // We only handle binary file signatures
317 if (sigdat->sig_type != RFC4880_ST_BINARY)
318 {
319 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, sigdat->sig_type, "unsupported sig type.");
320 return pktHALT;
321 }
322 // And we only speak DSA.
323 if (sigdat->pk_alg != RFC4880_PK_DSA)
324 {
325 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, sigdat->pk_alg, "unsupported pk alg.");
326 return pktHALT;
327 }
328
329 // Start to hash all the data. Figure out what hash to use.
330 sigdat->algo = pkt_convert_hashcode (sigdat->hash_alg);
331 if (sigdat->algo == GCRY_MD_NONE)
332 {
333 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, sigdat->hash_alg, "unconvertible hash.");
334 return pktHALT;
335 }
336
337 // Now we know hash algo, we can create md context.
338 gcry_error_t rv = gcry_md_open (&sigdat->md, sigdat->algo, 0);
339 if (rv != GPG_ERR_NO_ERROR)
340 {
341 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, rv, "while initialising message digest.");
342 return pktHALT;
343 }
344
345 // Add all the sig_file data into the hash.
346 sigdat->sign_data->seek (0, IO_SEEK_SET);
347 size_t nbytes = sigdat->sign_data->get_size ();
348 if (nbytes != shovel_stream_data_into_md (sigdat->sign_data, nbytes, sigdat->md))
349 {
350 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, sigdat->hash_alg, "internal buffer error.");
351 return pktHALT;
352 }
353 sigdat->sign_data->seek (0, IO_SEEK_SET);
354
355 // V4 now has some hashed subpackets
356 int hashed_subpkt_size = (ver == 4) ? pkt_getword (wlk->pfile) : 0;
357 if (hashed_subpkt_size)
358 pkt_walk_subpackets (wlk->pfile, hashed_subpkt_walker, wlk->owner,
359 wlk->pfile->tell (), hashed_subpkt_size, wlk->userdata);
360
361 // V4 now has some unhashed subpackets
362 int unhashed_subpkt_size = (ver == 4) ? pkt_getword (wlk->pfile) : 0;
363 if (unhashed_subpkt_size)
364 pkt_walk_subpackets (wlk->pfile, unhashed_subpkt_walker, wlk->owner,
365 wlk->pfile->tell (), unhashed_subpkt_size, wlk->userdata);
366
367 // Both formats now have 16 bits of the hash value.
368 int hash_first = pkt_getword (wlk->pfile);
369
370 MESSAGE ("sig type %d, pk_alg %d, hash_alg %d - first $%04x\n", sigdat->sig_type,
371 sigdat->pk_alg, sigdat->hash_alg, hash_first);
372
373 /* Algorithm-Specific Fields for DSA signatures:
374
375 - MPI of DSA value r.
376
377 - MPI of DSA value s.
378
379 DSA signatures MUST use hashes that are equal in size to the number
380 of bits of q, the group generated by the DSA key's generator value. */
381
382 if ((pkt_get_mpi (&sigdat->dsa_mpi_r, wlk->pfile) < 0)
383 || (pkt_get_mpi (&sigdat->dsa_mpi_s, wlk->pfile) < 0))
384 {
385 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, "unpacking mpi.");
386 return pktHALT;
387 }
388
389 MESSAGE ("Read sig packets succesfully!\n");
390
391 // Now we got all the data out ok, rewind and hash the first trailer.
392 wlk->pfile->seek (v34hdrofs, IO_SEEK_SET);
393 nbytes = (ver == 4) ? (RFC4880_SIGV4_HASHED_OVERHEAD + hashed_subpkt_size)
394 : (RFC4880_SIGV3_HASHED_SIZE);
395 if (nbytes != shovel_stream_data_into_md (wlk->pfile, nbytes, sigdat->md))
396 {
397 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, sigdat->hash_alg, "internal buffer error 2.");
398 return pktHALT;
399 }
400
401 if (ver == 4)
402 {
403 // And now the synthetic final trailer.
404 gcry_md_putc (sigdat->md, 4);
405 gcry_md_putc (sigdat->md, 0xff);
406 gcry_md_putc (sigdat->md, (nbytes >> 24) & 0xff);
407 gcry_md_putc (sigdat->md, (nbytes >> 16) & 0xff);
408 gcry_md_putc (sigdat->md, (nbytes >> 8) & 0xff);
409 gcry_md_putc (sigdat->md, nbytes & 0xff);
410 }
411
412 // Hooray, succeeded!
413 sigdat->complete = true;
414
415 return pktHALT;
416 }
417
418 /* Size and allocate a temp buffer to print a representation
419 of a public key s-expr into, then add that to the extra keys
420 setting so it persists for the next run. */
421 void
422 add_key_from_sexpr (gcry_sexp_t key)
423 {
424 size_t n = gcry_sexp_sprint (key, GCRYSEXP_FMT_ADVANCED, 0, ~0);
425 char *sexprbuf = new char[n];
426 n = gcry_sexp_sprint (key, GCRYSEXP_FMT_ADVANCED, sexprbuf, n);
427 // +1 because we want to include the nul-terminator.
428 n = fold_lfs_and_spaces (sexprbuf, n + 1);
429 ExtraKeysSetting::instance().add_key (sexprbuf);
430 MESSAGE ("keep:%d\n'%s'", n, sexprbuf);
431 delete [] sexprbuf;
432 }
433
434 /* Verify the signature on an ini file. Takes care of all key-handling. */
435 bool
436 verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, HWND owner)
437 {
438 /* DSA public key in s-expr format. */
439 gcry_sexp_t dsa_key;
440
441 /* Data returned from packet walker. */
442 struct sig_data sigdat;
443
444 /* Vector of extra keys to use. */
445 std::vector<gcry_sexp_t> keys_to_try;
446
447 /* Vector of cached extra keys from last run. */
448 static std::vector<gcry_sexp_t> input_keys;
449
450 /* Overall status of signature. */
451 bool sig_ok = false;
452
453 // Temps for intermediate processing.
454 gcry_error_t rv;
455 size_t n;
456
457 /* Initialise the library. */
458 gcry_check_version (NULL);
459
460 /* So first build the built-in key. */
461 rv = gcry_sexp_new (&dsa_key, cygwin_pubkey_sexpr, strlen (cygwin_pubkey_sexpr), 1);
462 if (rv != GPG_ERR_NO_ERROR)
463 {
464 ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "while creating pubkey s-expr.");
465 }
466
467 #if CRYPTODEBUGGING
468 char sexprbuf[GPG_KEY_SEXPR_BUF_SIZE];
469 n = gcry_sexp_sprint (dsa_key, GCRYSEXP_FMT_ADVANCED, sexprbuf, GPG_KEY_SEXPR_BUF_SIZE);
470 msg ("key:%d\n'%s'", n, sexprbuf);
471 #endif /* CRYPTODEBUGGING */
472
473 /* Next we should extract the keys from the last-extrakeys
474 file, and flush it; we'll only return them to it if they
475 get used. OTOH, should we do this at all? The extrakeys
476 file isn't heavily protected. So we only trust the extra
477 keys if we're told to by the user. We still read them in
478 and write them back out, which canonicalises and eliminates
479 any duplicates or garbage lines that may have crept in. */
480 static bool input_keys_read = false;
481 if (!input_keys_read)
482 {
483 // We only want to do this once, first time through:
484 input_keys_read = true;
485 // Copy all valid keys from ExtraKeysSetting into a
486 // static vector where we can keep them throughout the
487 // remainder of the run.
488 for (size_t i = 0; i < ExtraKeysSetting::instance().num_keys (); i++)
489 {
490 const char *keystring = ExtraKeysSetting::instance().get_key (i, &n);
491 gcry_sexp_t newkey;
492 rv = gcry_sexp_new (&newkey, keystring, n, 1);
493 if (rv == GPG_ERR_NO_ERROR)
494 input_keys.push_back (newkey);
495 }
496
497 // Now flush out the ExtraKeysSetting; from here on it
498 // will build up a list of the keys we want to retain.
499 ExtraKeysSetting::instance().flush ();
500
501 // Which, if we aren't using them, means all the ones
502 // we just read.
503 if (KeepUntrustedKeysOption || !UntrustedKeysOption)
504 {
505 std::vector<gcry_sexp_t>::iterator it;
506 for (it = input_keys.begin (); it < input_keys.end (); ++it)
507 add_key_from_sexpr (*it);
508 }
509 }
510
511 /* Next, there may have been command-line options. */
512 std::string SexprExtraKeyString = SexprExtraKeyOption;
513 MESSAGE ("key str is '%s'\n", SexprExtraKeyString.c_str ());
514 if (SexprExtraKeyString.size ())
515 {
516 gcry_sexp_t dsa_key2 = 0;
517 rv = gcry_sexp_new (&dsa_key2, SexprExtraKeyString.c_str (),
518 SexprExtraKeyString.size (), 1);
519 if (rv == GPG_ERR_NO_ERROR)
520 {
521 // We probably want to add it to the extra keys setting
522 // if KeepUntrustedKeysOption is supplied.
523 if (KeepUntrustedKeysOption)
524 add_key_from_sexpr (dsa_key2);
525 #if CRYPTODEBUGGING
526 n = gcry_sexp_sprint (dsa_key2, GCRYSEXP_FMT_ADVANCED, sexprbuf,
527 GPG_KEY_SEXPR_BUF_SIZE);
528 // +1 because we want to include the nul-terminator.
529 n = fold_lfs_and_spaces (sexprbuf, n + 1);
530 ExtraKeysSetting::instance().add_key (sexprbuf);
531 msg ("key2:%d\n'%s'", n, sexprbuf);
532 #endif /* CRYPTODEBUGGING */
533 keys_to_try.push_back (dsa_key2);
534 }
535 else
536 {
537 ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "invalid command-line pubkey s-expr.");
538 }
539 }
540
541 /* Also, we may have to read a key(s) file. */
542 std::string ExtraKeysFile = ExtraKeyOption;
543 if (ExtraKeysFile.size ())
544 {
545 io_stream *keys = get_url_to_membuf (ExtraKeysFile, owner);
546 if (keys)
547 {
548 struct key_data kdat;
549 pkt_walk_packets (keys, key_file_walker, owner, 0, keys->get_size (), &kdat);
550 // We now have a vector of (some/any?) keys returned from
551 // the walker; add them to the list to try.
552 while (!kdat.keys.empty ())
553 {
554 // We probably want to add it to the extra keys setting
555 // if KeepUntrustedKeysOption is supplied.
556 if (KeepUntrustedKeysOption)
557 add_key_from_sexpr (kdat.keys.back ());
558 #if CRYPTODEBUGGING
559 n = gcry_sexp_sprint (kdat.keys.back (), GCRYSEXP_FMT_ADVANCED,
560 sexprbuf, GPG_KEY_SEXPR_BUF_SIZE);
561 // +1 because we want to include the nul-terminator.
562 n = fold_lfs_and_spaces (sexprbuf, n + 1);
563 ExtraKeysSetting::instance().add_key (sexprbuf);
564 msg ("key3:%d\n'%s'", n, sexprbuf);
565 #endif /* CRYPTODEBUGGING */
566 keys_to_try.push_back (kdat.keys.back ());
567 kdat.keys.pop_back ();
568 }
569 }
570 }
571
572 // We pass in a pointer to the ini file in the user context data,
573 // which the packet walker callback uses to create a new hash
574 // context preloaded with all the signature-covered data.
575 sigdat.complete = false;
576 sigdat.sign_data = ini_file;
577 sigdat.dsa_mpi_r = sigdat.dsa_mpi_s = 0;
578 sigdat.md = 0;
579 pkt_walk_packets (ini_sig_file, sig_file_walker, owner, 0,
580 ini_sig_file->get_size (), &sigdat);
581 if (sigdat.complete)
582 {
583 /* DSA sig coefficients in s-expr format. */
584 gcry_sexp_t dsa_sig;
585
586 /* DSA signature hash data in s-expr format. */
587 gcry_sexp_t dsa_hash;
588
589 /* So, we have hashed all the data, and found the sig coefficients.
590 Next stages are to finalise the hash, build everything into
591 s-exprs, and call the libgcrypt verification routine. */
592
593 rv = gcry_sexp_build (&dsa_sig, &n, dsa_sig_templ, sigdat.dsa_mpi_r,
594 sigdat.dsa_mpi_s);
595 if (rv != GPG_ERR_NO_ERROR)
596 {
597 ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "while creating sig s-expr.");
598 return false;
599 }
600
601 gcry_md_final (sigdat.md);
602
603 // Make a temp mpi from the hash output, then an s-expr from that.
604 gcry_mpi_t dsa_mpi_hash = 0;
605 unsigned char *tmpbuf = gcry_md_read (sigdat.md, 0);
606 size_t dlen = gcry_md_get_algo_dlen (sigdat.algo);
607 rv = gcry_mpi_scan (&dsa_mpi_hash, GCRYMPI_FMT_USG, tmpbuf, dlen, 0UL);
608 if (rv != GPG_ERR_NO_ERROR)
609 {
610 ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "while creating hash MPI.");
611 return false;
612 }
613
614 rv = gcry_sexp_build (&dsa_hash, &n, data_hash_templ, dsa_mpi_hash);
615 if (rv != GPG_ERR_NO_ERROR)
616 {
617 ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "while creating hash s-expr.");
618 return false;
619 }
620
621 #if CRYPTODEBUGGING
622 n = gcry_sexp_sprint (dsa_sig, GCRYSEXP_FMT_ADVANCED, sexprbuf,
623 GPG_KEY_SEXPR_BUF_SIZE);
624 msg ("sig:%d\n'%s'", n, sexprbuf);
625 n = gcry_sexp_sprint (dsa_hash, GCRYSEXP_FMT_ADVANCED, sexprbuf,
626 GPG_KEY_SEXPR_BUF_SIZE);
627 msg ("hash:%d\n'%s'", n, sexprbuf);
628 #endif /* CRYPTODEBUGGING */
629
630 // Well, we're actually there! Try it against the main key.
631 rv = gcry_pk_verify (dsa_sig, dsa_hash, dsa_key);
632 // If not that, try any supplied on the commandline.
633 if (rv != GPG_ERR_NO_ERROR)
634 {
635 std::vector<gcry_sexp_t>::iterator it;
636 for (it = keys_to_try.begin (); it < keys_to_try.end (); ++it)
637 {
638 MESSAGE ("Testing a key to try\n");
639 rv = gcry_pk_verify (dsa_sig, dsa_hash, *it);
640 if (rv != GPG_ERR_NO_ERROR)
641 continue;
642 // Found it! This key gets kept!
643 add_key_from_sexpr (*it);
644 break;
645 }
646
647 // We only use the untrusted keys if told to.
648 it = ((rv != GPG_ERR_NO_ERROR)
649 && (KeepUntrustedKeysOption || UntrustedKeysOption))
650 ? input_keys.begin ()
651 : input_keys.end ();
652 for ( ; it < input_keys.end (); ++it)
653 {
654 MESSAGE ("Testing an input key\n");
655 rv = gcry_pk_verify (dsa_sig, dsa_hash, *it);
656 if (rv != GPG_ERR_NO_ERROR)
657 continue;
658 // Found it! This key gets kept!
659 add_key_from_sexpr (*it);
660 break;
661 }
662 }
663
664 sig_ok = (rv == GPG_ERR_NO_ERROR);
665
666 #if CRYPTODEBUGGING
667 gcry_err_code_t code;
668 gcry_err_source_t src;
669 code = gcry_err_code (rv);
670 src = gcry_err_source (rv);
671 msg ("Well, pk verify returned $%08x - code %d src %d\n", rv, code, src);
672 #endif /* CRYPTODEBUGGING */
673
674 gcry_mpi_release (dsa_mpi_hash);
675 gcry_sexp_release (dsa_sig);
676 gcry_sexp_release (dsa_hash);
677 }
678
679 // Discard the temp data then.
680 gcry_sexp_release (dsa_key);
681 if (sigdat.dsa_mpi_r)
682 gcry_mpi_release (sigdat.dsa_mpi_r);
683 if (sigdat.dsa_mpi_s)
684 gcry_mpi_release (sigdat.dsa_mpi_s);
685 if (sigdat.md)
686 gcry_md_close (sigdat.md);
687 while (keys_to_try.size ())
688 {
689 gcry_sexp_release (keys_to_try.back ());
690 keys_to_try.pop_back ();
691 }
692
693 return sig_ok;
694 }
695
This page took 0.067184 seconds and 5 git commands to generate.