]> cygwin.com Git - cygwin-apps/setup.git/blob - crypto.cc
Use solver to check for problems and produce a list of package transactions
[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 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <vector>
20 #include "io_stream.h"
21 #include "crypto.h"
22 #include "compress.h"
23 #include "gcrypt.h"
24 #include "msg.h"
25 #include "LogSingleton.h"
26 #include "resource.h"
27 #include "getopt++/StringArrayOption.h"
28 #include "getopt++/BoolOption.h"
29 #include "KeysSetting.h"
30 #include "gpg-packet.h"
31 #include "geturl.h"
32
33 #define CRYPTODEBUGGING (0)
34
35 #if CRYPTODEBUGGING
36 #define ERRKIND __asm__ __volatile__ (".byte 0xcc"); note
37 #define MESSAGE LogBabblePrintf
38 #else /* !CRYPTODEBUGGING */
39 #define ERRKIND note
40 #define MESSAGE while (0) LogBabblePrintf
41 #endif /* CRYPTODEBUGGING */
42
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)");
46
47 static StringArrayOption SexprExtraKeyOption ('S', "sexpr-pubkey",
48 "Extra public key in s-expr format");
49
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");
54
55 /* Embedded public half of Cygwin DSA signing key. */
56 static const char *cygwin_pubkey_sexpr =
57 #include "cyg-pubkey.h"
58 ;
59
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)))";
62
63 /* S-expr template for DSA signature. */
64 static const char *dsa_sig_templ = "(sig-val (dsa (r %m) (s %m)))";
65
66 /* S-expr template for data block to be signed. */
67 static const char *data_hash_templ = "(data (flags raw) (value %m))";
68
69 /* User context data for sig packet walk. */
70 struct sig_data
71 {
72 /* MPI values of sig components. */
73 gcry_mpi_t dsa_mpi_r, dsa_mpi_s;
74
75 /* Hash context. */
76 gcry_md_hd_t md;
77
78 /* Main data. */
79 io_stream *sign_data;
80
81 /* Auxiliary data. */
82 int sig_type;
83 int pk_alg;
84 int hash_alg;
85
86 /* Converted algo code. */
87 int algo;
88
89 /* Final status. */
90 bool complete;
91 };
92
93 /* User context data for key packet walk. */
94 struct key_data
95 {
96 std::vector<gcry_sexp_t> keys;
97 };
98
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. */
103 static enum
104 pkt_cb_resp key_file_walker (struct packet_walker *wlk, unsigned char tag,
105 size_t packetsize, size_t hdrpos)
106 {
107 struct key_data *kdat = (struct key_data *)(wlk->userdata);
108
109 MESSAGE ("key packet %d size %d at offs $%04x kdat $%08x\n", tag,
110 packetsize, hdrpos, kdat);
111
112 if (tag != RFC4880_PT_PUBLIC_KEY)
113 return pktCONTINUE;
114
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);
118 if (ver != 4)
119 {
120 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, ver, "unsupported key version.");
121 return pktCONTINUE;
122 }
123
124 // Only V4 accepted. Discard creation time.
125 if (pkt_getdword (wlk->pfile) == -1)
126 {
127 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, -1, "missing creation time.");
128 return pktCONTINUE;
129 }
130
131 char pkalg = pkt_getch (wlk->pfile);
132 if (pkalg != RFC4880_PK_DSA)
133 {
134 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, pkalg, "unsupported key alg.");
135 return pktCONTINUE;
136 }
137
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;
141 p = q = g = y = 0;
142
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))
147 {
148 // Convert to s-expr.
149 gcry_sexp_t new_key;
150 size_t n;
151
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)
154 {
155 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, rv, "while creating sig s-expr.");
156 return pktCONTINUE;
157 }
158
159 #if CRYPTODEBUGGING
160 // Debugging
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 */
166
167 // Return it to caller in the vector.
168 kdat->keys.push_back (new_key);
169 }
170
171 // Release temps and continue.
172 if (p)
173 gcry_mpi_release (p);
174 if (q)
175 gcry_mpi_release (q);
176 if (g)
177 gcry_mpi_release (g);
178 if (y)
179 gcry_mpi_release (y);
180
181 return pktCONTINUE;
182 }
183
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. */
187 static size_t
188 shovel_stream_data_into_md (io_stream *stream, size_t nbytes, gcry_md_hd_t md)
189 {
190 const size_t TMPBUFSZ = 1024;
191 unsigned char tmpbuf[TMPBUFSZ];
192 size_t this_time, total = 0;
193 ssize_t actual;
194 MESSAGE ("shovel %d bytes at pos $%08x\n", nbytes, stream->tell ());
195 while (nbytes)
196 {
197 this_time = (nbytes > TMPBUFSZ) ? TMPBUFSZ : nbytes;
198 actual = stream->read (tmpbuf, this_time);
199 if (actual <= 0)
200 break;
201 gcry_md_write (md, tmpbuf, actual);
202 total += actual;
203 nbytes -= actual;
204 if (actual != (ssize_t)this_time)
205 break;
206 }
207 return total;
208 }
209
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. */
212 static size_t
213 fold_lfs_and_spaces (char *buf, size_t n)
214 {
215 char *ptr1 = buf, *ptr2 = buf;
216
217 while (n--)
218 {
219 char ch = *ptr1++;
220 if (ch == 0x0a)
221 ch = ' ';
222 *ptr2++ = ch;
223 if (ch == 0x20)
224 while (n && ((*ptr1 == ' ') || (*ptr1 == 0x0a)))
225 {
226 --n;
227 ++ptr1;
228 }
229 }
230 return ptr2 - buf;
231 }
232
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. */
236 static enum
237 pkt_cb_resp hashed_subpkt_walker (struct packet_walker *wlk, unsigned char tag,
238 size_t packetsize, size_t hdrpos)
239 {
240 return pktCONTINUE;
241 }
242
243 static enum
244 pkt_cb_resp unhashed_subpkt_walker (struct packet_walker *wlk, unsigned char tag,
245 size_t packetsize, size_t hdrpos)
246 {
247 return pktCONTINUE;
248 }
249
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. */
256 static enum
257 pkt_cb_resp sig_file_walker (struct packet_walker *wlk, unsigned char tag,
258 size_t packetsize, size_t hdrpos)
259 {
260 struct sig_data *sigdat = (struct sig_data *)(wlk->userdata);
261 sigdat->complete = false;
262
263 if (tag != RFC4880_PT_SIGNATURE)
264 return pktCONTINUE;
265
266 // To add the trailers later, we hang on to the current pos.
267 size_t v34hdrofs = wlk->pfile->tell ();
268
269 // So, get the data out. Version is first.
270 char ver = pkt_getch (wlk->pfile);
271 if ((ver < 3) || (ver > 4))
272 {
273 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, ver, "unsupported sig version.");
274 return pktHALT;
275 }
276
277 // Only V3 and V4 accepted.
278 if (ver == 4)
279 {
280 sigdat->sig_type = pkt_getch (wlk->pfile);
281 sigdat->pk_alg = pkt_getch (wlk->pfile);
282 sigdat->hash_alg = pkt_getch (wlk->pfile);
283 }
284 else
285 {
286 int hmsize = pkt_getch (wlk->pfile);
287 if (hmsize != RFC4880_SIGV3_HASHED_SIZE)
288 {
289 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, hmsize, "wrong hashed material size.");
290 return pktHALT;
291 }
292 v34hdrofs = wlk->pfile->tell ();
293 if ((pkt_getch (wlk->pfile) < 0) || (pkt_getdword (wlk->pfile) == -1))
294 {
295 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, hmsize, "wrong hashed material size.");
296 return pktHALT;
297 }
298 if ((pkt_getdword (wlk->pfile) == -1) || (pkt_getdword (wlk->pfile) == -1))
299 {
300 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, -1, "missing signer ID.");
301 return pktHALT;
302 }
303
304 sigdat->sig_type = 0;
305 sigdat->pk_alg = pkt_getch (wlk->pfile);
306 sigdat->hash_alg = pkt_getch (wlk->pfile);
307 }
308
309 MESSAGE ("sig type %d, pk_alg %d, hash_alg %d\n", sigdat->sig_type,
310 sigdat->pk_alg, sigdat->hash_alg);
311
312 // We only handle binary file signatures
313 if (sigdat->sig_type != RFC4880_ST_BINARY)
314 {
315 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, sigdat->sig_type, "unsupported sig type.");
316 return pktHALT;
317 }
318 // And we only speak DSA.
319 if (sigdat->pk_alg != RFC4880_PK_DSA)
320 {
321 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, sigdat->pk_alg, "unsupported pk alg.");
322 return pktHALT;
323 }
324
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)
328 {
329 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, sigdat->hash_alg, "unconvertible hash.");
330 return pktHALT;
331 }
332
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)
336 {
337 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, rv, "while initialising message digest.");
338 return pktHALT;
339 }
340
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))
345 {
346 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, sigdat->hash_alg, "internal buffer error.");
347 return pktHALT;
348 }
349 sigdat->sign_data->seek (0, IO_SEEK_SET);
350
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);
356
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);
362
363 // Both formats now have 16 bits of the hash value.
364 int hash_first = pkt_getword (wlk->pfile);
365
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);
368
369 /* Algorithm-Specific Fields for DSA signatures:
370
371 - MPI of DSA value r.
372
373 - MPI of DSA value s.
374
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. */
377
378 if ((pkt_get_mpi (&sigdat->dsa_mpi_r, wlk->pfile) < 0)
379 || (pkt_get_mpi (&sigdat->dsa_mpi_s, wlk->pfile) < 0))
380 {
381 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, "unpacking mpi.");
382 return pktHALT;
383 }
384
385 MESSAGE ("Read sig packets succesfully!\n");
386
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))
392 {
393 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, sigdat->hash_alg, "internal buffer error 2.");
394 return pktHALT;
395 }
396
397 if (ver == 4)
398 {
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);
406 }
407
408 // Hooray, succeeded!
409 sigdat->complete = true;
410
411 return pktHALT;
412 }
413
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. */
417 void
418 add_key_from_sexpr (gcry_sexp_t key)
419 {
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);
427 delete [] sexprbuf;
428 }
429
430 /* Verify the signature on an ini file. Takes care of all key-handling. */
431 bool
432 verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, HWND owner)
433 {
434 /* DSA public key in s-expr format. */
435 gcry_sexp_t dsa_key;
436
437 /* Data returned from packet walker. */
438 struct sig_data sigdat;
439
440 /* Vector of extra keys to use. */
441 std::vector<gcry_sexp_t> keys_to_try;
442
443 /* Vector of cached extra keys from last run. */
444 static std::vector<gcry_sexp_t> input_keys;
445
446 /* Overall status of signature. */
447 bool sig_ok = false;
448
449 // Temps for intermediate processing.
450 gcry_error_t rv;
451 size_t n;
452
453 /* Initialise the library. */
454 gcry_check_version (NULL);
455
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)
459 {
460 ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "while creating pubkey s-expr.");
461 }
462
463 #if CRYPTODEBUGGING
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 */
468
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)
478 {
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++)
485 {
486 const char *keystring = ExtraKeysSetting::instance().get_key (i, &n);
487 gcry_sexp_t newkey;
488 rv = gcry_sexp_new (&newkey, keystring, n, 1);
489 if (rv == GPG_ERR_NO_ERROR)
490 input_keys.push_back (newkey);
491 }
492
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 ();
496
497 // Which, if we aren't using them, means all the ones
498 // we just read.
499 if (KeepUntrustedKeysOption || !UntrustedKeysOption)
500 {
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);
504 }
505 }
506
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)
512 {
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)
517 {
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);
522 #if CRYPTODEBUGGING
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);
531 }
532 else
533 {
534 ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "invalid command-line pubkey s-expr.");
535 }
536 }
537
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)
543 {
544 io_stream *keys = get_url_to_membuf (*it, owner);
545 if (keys)
546 {
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 ())
552 {
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 ());
557 #if CRYPTODEBUGGING
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 ();
567 }
568 }
569 }
570
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;
577 sigdat.md = 0;
578 pkt_walk_packets (ini_sig_file, sig_file_walker, owner, 0,
579 ini_sig_file->get_size (), &sigdat);
580 if (sigdat.complete)
581 {
582 /* DSA sig coefficients in s-expr format. */
583 gcry_sexp_t dsa_sig;
584
585 /* DSA signature hash data in s-expr format. */
586 gcry_sexp_t dsa_hash;
587
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. */
591
592 rv = gcry_sexp_build (&dsa_sig, &n, dsa_sig_templ, sigdat.dsa_mpi_r,
593 sigdat.dsa_mpi_s);
594 if (rv != GPG_ERR_NO_ERROR)
595 {
596 ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "while creating sig s-expr.");
597 return false;
598 }
599
600 gcry_md_final (sigdat.md);
601
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)
608 {
609 ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "while creating hash MPI.");
610 return false;
611 }
612
613 rv = gcry_sexp_build (&dsa_hash, &n, data_hash_templ, dsa_mpi_hash);
614 if (rv != GPG_ERR_NO_ERROR)
615 {
616 ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "while creating hash s-expr.");
617 return false;
618 }
619
620 #if CRYPTODEBUGGING
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 */
628
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)
633 {
634 std::vector<gcry_sexp_t>::iterator it;
635 for (it = keys_to_try.begin (); it < keys_to_try.end (); ++it)
636 {
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)
640 continue;
641 // Found it! This key gets kept!
642 add_key_from_sexpr (*it);
643 break;
644 }
645
646 // We only use the untrusted keys if told to.
647 it = ((rv != GPG_ERR_NO_ERROR)
648 && (KeepUntrustedKeysOption || UntrustedKeysOption))
649 ? input_keys.begin ()
650 : input_keys.end ();
651 for ( ; it < input_keys.end (); ++it)
652 {
653 MESSAGE ("Testing an input key\n");
654 rv = gcry_pk_verify (dsa_sig, dsa_hash, *it);
655 if (rv != GPG_ERR_NO_ERROR)
656 continue;
657 // Found it! This key gets kept!
658 add_key_from_sexpr (*it);
659 break;
660 }
661 }
662
663 sig_ok = (rv == GPG_ERR_NO_ERROR);
664
665 #if CRYPTODEBUGGING
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 */
672
673 gcry_mpi_release (dsa_mpi_hash);
674 gcry_sexp_release (dsa_sig);
675 gcry_sexp_release (dsa_hash);
676 }
677
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);
684 if (sigdat.md)
685 gcry_md_close (sigdat.md);
686 while (keys_to_try.size ())
687 {
688 gcry_sexp_release (keys_to_try.back ());
689 keys_to_try.pop_back ();
690 }
691
692 return sig_ok;
693 }
694
This page took 0.066334 seconds and 5 git commands to generate.