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 #ifndef CRYPTODEBUGGING
34 #define CRYPTODEBUGGING (0)
39 #define MESSAGE LogBabblePrintf
41 #define MESSAGE while (0) LogBabblePrintf
44 /* Command-line options for specifying and controlling extra keys. */
45 static StringArrayOption
ExtraKeyOption ('K', "pubkey",
46 "URL or absolute path of extra public key file (RFC4880 format)");
48 static StringArrayOption
SexprExtraKeyOption ('S', "sexpr-pubkey",
49 "Extra DSA public key in s-expr format");
51 static BoolOption
UntrustedKeysOption (false, 'u', "untrusted-keys",
52 "Use untrusted saved extra keys");
53 static BoolOption
KeepUntrustedKeysOption (false, 'U', "keep-untrusted-keys",
54 "Use untrusted keys and retain all");
55 static BoolOption
EnableOldKeysOption (false, '\0', "old-keys",
56 "Enable old cygwin.com keys",
57 BoolOption::BoolOptionType::pairedAble
);
59 /* Embedded public half of Cygwin signing key. */
60 static const char *cygwin_pubkey_sexpr
=
61 #include "cyg-pubkey.h"
64 static const char *cygwin_old_pubkey_sexpr
=
65 #include "cyg-old-pubkey.h"
68 /* S-expr template for DSA pubkey. */
69 static const char *dsa_pubkey_templ
= "(public-key (dsa (p %m) (q %m) (g %m) (y %m)))";
71 /* S-expr template for RSA pubkey. */
72 static const char *rsa_pubkey_templ
= "(public-key (rsa (n %m) (e %m)))";
74 /* S-expr template for DSA signature. */
75 static const char *dsa_sig_templ
= "(sig-val (dsa (r %m) (s %m)))";
77 /* S-expr template for RSA signature. */
78 static const char *rsa_sig_templ
= "(sig-val (rsa (s %m)))";
80 /* S-expr template for DSA data block to be signed. */
81 static const char *dsa_data_hash_templ
= "(data (flags raw) (hash %s %b))";
83 /* S-expr template for RSA data block to be signed. */
84 static const char *rsa_data_hash_templ
= "(data (flags pkcs1) (hash %s %b))";
86 /* Information on a key to try */
89 key_info(std::string _name
, bool _builtin
, gcry_sexp_t _key
, bool _owned
=true) :
90 name(_name
), builtin(_builtin
), key(_key
), owned(_owned
)
95 bool builtin
; // if true, we don't need to retain this key with add_key_from_sexpr()
97 bool owned
; // if true, we own this key and should use gcry_sexp_release() on it
100 /* User context data for sig packet walk. */
103 /* MPI values of sig components. */
104 gcry_mpi_t dsa_mpi_r
, dsa_mpi_s
;
105 gcry_mpi_t rsa_mpi_s
;
111 io_stream
*sign_data
;
113 /* Auxiliary data. */
118 /* Converted algo code. */
122 std::vector
<struct key_info
> *keys_to_try
;
128 /* User context data for key packet walk. */
131 std::vector
<gcry_sexp_t
> keys
;
134 /* Callback hook for walking packets in gpg key file. Extracts
135 the key coefficients from any public key packets encountered and
136 converts them into s-expr pubkey format, returning the public
137 keys thus found to the caller in a vector in the userdata context. */
139 pkt_cb_resp
key_file_walker (struct packet_walker
*wlk
, unsigned char tag
,
140 size_t packetsize
, size_t hdrpos
)
142 struct key_data
*kdat
= (struct key_data
*)(wlk
->userdata
);
144 MESSAGE ("key packet %d size %d at offs $%04x kdat $%08x\n", tag
,
145 packetsize
, hdrpos
, kdat
);
147 if (tag
!= RFC4880_PT_PUBLIC_KEY
)
150 // So, get the data out. Version is first. In case of any errors during
151 // parsing, we just discard the key and continue, hoping to find a good one.
152 char ver
= pkt_getch (wlk
->pfile
);
155 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, ver
, "unsupported key version.");
159 // Only V4 accepted. Discard creation time.
160 if (pkt_getdword (wlk
->pfile
) == -1)
162 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, -1, "missing creation time.");
166 char pkalg
= pkt_getch (wlk
->pfile
);
167 if ((pkalg
!= RFC4880_PK_DSA
) && (pkalg
!= RFC4880_PK_RSA
))
169 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, pkalg
, "unsupported key alg.");
173 // Next, the key coefficient MPIs should be present. Read them out, convert
174 // to an s-expr and add that to the list of keys.
178 if (pkalg
== RFC4880_PK_DSA
)
180 gcry_mpi_t p
, q
, g
, y
;
183 if ((pkt_get_mpi (&p
, wlk
->pfile
) >= 0)
184 && (pkt_get_mpi (&q
, wlk
->pfile
) >= 0)
185 && (pkt_get_mpi (&g
, wlk
->pfile
) >= 0)
186 && (pkt_get_mpi (&y
, wlk
->pfile
) >= 0))
188 gcry_error_t rv
= gcry_sexp_build (&new_key
, &erroff
, dsa_pubkey_templ
, p
, q
, g
, y
);
189 if (rv
!= GPG_ERR_NO_ERROR
)
191 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, rv
, "while creating sig s-expr.");
196 // Release temps and continue.
198 gcry_mpi_release (p
);
200 gcry_mpi_release (q
);
202 gcry_mpi_release (g
);
204 gcry_mpi_release (y
);
206 else if (pkalg
== RFC4880_PK_RSA
)
211 if ((pkt_get_mpi (&n
, wlk
->pfile
) >= 0)
212 && (pkt_get_mpi (&e
, wlk
->pfile
) >= 0))
214 gcry_error_t rv
= gcry_sexp_build (&new_key
, &erroff
, rsa_pubkey_templ
, n
, e
);
215 if (rv
!= GPG_ERR_NO_ERROR
)
217 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, rv
, "while creating sig s-expr.");
223 gcry_mpi_release (n
);
225 gcry_mpi_release (e
);
230 char sexprbuf
[GPG_KEY_SEXPR_BUF_SIZE
];
231 erroff
= gcry_sexp_sprint (new_key
, GCRYSEXP_FMT_ADVANCED
, sexprbuf
,
232 GPG_KEY_SEXPR_BUF_SIZE
);
233 LogBabblePrintf ("key:%d\n'%s'", erroff
, sexprbuf
);
234 #endif /* CRYPTODEBUGGING */
236 // Return it to caller in the vector.
237 kdat
->keys
.push_back (new_key
);
242 /* Does what its name suggests: feeds a chosen amount of the data found
243 at the current seek position in an io_stream into the message digest
244 context passed in, using reasonably-sized chunks for efficiency. */
246 shovel_stream_data_into_md (io_stream
*stream
, size_t nbytes
, gcry_md_hd_t md
)
248 const size_t TMPBUFSZ
= 1024;
249 unsigned char tmpbuf
[TMPBUFSZ
];
250 size_t this_time
, total
= 0;
252 MESSAGE ("shovel %d bytes at pos $%08x\n", nbytes
, stream
->tell ());
255 this_time
= (nbytes
> TMPBUFSZ
) ? TMPBUFSZ
: nbytes
;
256 actual
= stream
->read (tmpbuf
, this_time
);
259 gcry_md_write (md
, tmpbuf
, actual
);
262 if (actual
!= (ssize_t
)this_time
)
268 /* Canonicalise an s-expr by converting LFs to spaces so that
269 it's all on one line and folding multiple spaces as we go. */
271 fold_lfs_and_spaces (char *buf
, size_t n
)
273 char *ptr1
= buf
, *ptr2
= buf
;
282 while (n
&& ((*ptr1
== ' ') || (*ptr1
== 0x0a)))
291 /* Size and allocate a temp buffer to print a representation
292 of a public key s-expr into, then add that to the extra keys
293 setting so it persists for the next run. */
295 add_key_from_sexpr (gcry_sexp_t key
)
297 size_t n
= gcry_sexp_sprint (key
, GCRYSEXP_FMT_ADVANCED
, 0, ~0);
298 char *sexprbuf
= new char[n
];
299 n
= gcry_sexp_sprint (key
, GCRYSEXP_FMT_ADVANCED
, sexprbuf
, n
);
300 // +1 because we want to include the nul-terminator.
301 n
= fold_lfs_and_spaces (sexprbuf
, n
+ 1);
302 ExtraKeysSetting::instance().add_key (sexprbuf
);
303 MESSAGE ("keep:%d\n'%s'", n
, sexprbuf
);
308 verify_sig(struct sig_data
*sigdat
, HWND owner
)
313 /* sig coefficients in s-expr format. */
316 /* signature hash data in s-expr format. */
319 /* Build everything into s-exprs, and call the libgcrypt verification
322 if (sigdat
->pk_alg
== RFC4880_PK_DSA
)
324 rv
= gcry_sexp_build (&sig
, &n
, dsa_sig_templ
, sigdat
->dsa_mpi_r
,
326 if (rv
!= GPG_ERR_NO_ERROR
)
328 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "while creating sig s-expr.");
332 rv
= gcry_sexp_build (&hash
, &n
, dsa_data_hash_templ
,
333 gcry_md_algo_name(sigdat
->algo
),
334 gcry_md_get_algo_dlen (sigdat
->algo
),
335 gcry_md_read (sigdat
->md
, 0));
336 if (rv
!= GPG_ERR_NO_ERROR
)
338 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "while creating hash s-expr.");
342 else if (sigdat
->pk_alg
== RFC4880_PK_RSA
)
344 rv
= gcry_sexp_build (&sig
, &n
, rsa_sig_templ
, sigdat
->rsa_mpi_s
);
345 if (rv
!= GPG_ERR_NO_ERROR
)
347 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "while creating sig s-expr.");
351 rv
= gcry_sexp_build (&hash
, &n
, rsa_data_hash_templ
,
352 gcry_md_algo_name(sigdat
->algo
),
353 gcry_md_get_algo_dlen (sigdat
->algo
),
354 gcry_md_read (sigdat
->md
, 0));
355 if (rv
!= GPG_ERR_NO_ERROR
)
357 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "while creating hash s-expr.");
363 char sexprbuf
[GPG_KEY_SEXPR_BUF_SIZE
];
364 n
= gcry_sexp_sprint (sig
, GCRYSEXP_FMT_ADVANCED
, sexprbuf
,
365 GPG_KEY_SEXPR_BUF_SIZE
);
366 LogBabblePrintf ("sig:%d\n'%s'", n
, sexprbuf
);
367 n
= gcry_sexp_sprint (hash
, GCRYSEXP_FMT_ADVANCED
, sexprbuf
,
368 GPG_KEY_SEXPR_BUF_SIZE
);
369 LogBabblePrintf ("hash:%d\n'%s'", n
, sexprbuf
);
370 #endif /* CRYPTODEBUGGING */
372 // Well, we're actually there!
373 // Try it against each key in turn
375 std::vector
<key_info
>::iterator it
;
376 for (it
= sigdat
->keys_to_try
->begin ();
377 it
< sigdat
->keys_to_try
->end ();
380 rv
= gcry_pk_verify (sig
, hash
, it
->key
);
382 LogBabblePrintf("signature: tried key %s, returned 0x%08x %s\n",
383 it
->name
.c_str(), rv
, gcry_strerror(rv
));
385 if (rv
!= GPG_ERR_NO_ERROR
)
387 // Found it! This key gets kept!
389 add_key_from_sexpr (it
->key
);
393 gcry_sexp_release (sig
);
394 gcry_sexp_release (hash
);
397 return (rv
== GPG_ERR_NO_ERROR
);
400 /* Do-nothing stubs called by the sig file walker to
401 walk over the embedded subpackets. In the event, we don't
402 actually need to do this as we aren't inspecting them. */
404 pkt_cb_resp
hashed_subpkt_walker (struct packet_walker
*wlk
, unsigned char tag
,
405 size_t packetsize
, size_t hdrpos
)
411 pkt_cb_resp
unhashed_subpkt_walker (struct packet_walker
*wlk
, unsigned char tag
,
412 size_t packetsize
, size_t hdrpos
)
417 /* Callback to parse the packets found in the setup.ini/setup.bz2
418 signature file. We have to parse the header to get the hash type
419 and other details. Once we have that we can create a message
420 digest context and start pumping data through it; first the ini
421 file itself, then the portion of the packet itself that is
422 covered by the hash. */
424 pkt_cb_resp
sig_file_walker (struct packet_walker
*wlk
, unsigned char tag
,
425 size_t packetsize
, size_t hdrpos
)
427 struct sig_data
*sigdat
= (struct sig_data
*)(wlk
->userdata
);
429 if (tag
!= RFC4880_PT_SIGNATURE
)
432 // To add the trailers later, we hang on to the current pos.
433 size_t v34hdrofs
= wlk
->pfile
->tell ();
435 // So, get the data out. Version is first.
436 char ver
= pkt_getch (wlk
->pfile
);
437 if ((ver
< 3) || (ver
> 4))
439 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, ver
, "unsupported sig version.");
443 // Only V3 and V4 accepted.
446 sigdat
->sig_type
= pkt_getch (wlk
->pfile
);
447 sigdat
->pk_alg
= pkt_getch (wlk
->pfile
);
448 sigdat
->hash_alg
= pkt_getch (wlk
->pfile
);
452 int hmsize
= pkt_getch (wlk
->pfile
);
453 if (hmsize
!= RFC4880_SIGV3_HASHED_SIZE
)
455 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, hmsize
, "wrong hashed material size.");
458 v34hdrofs
= wlk
->pfile
->tell ();
459 if ((pkt_getch (wlk
->pfile
) < 0) || (pkt_getdword (wlk
->pfile
) == -1))
461 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, hmsize
, "wrong hashed material size.");
464 if ((pkt_getdword (wlk
->pfile
) == -1) || (pkt_getdword (wlk
->pfile
) == -1))
466 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, -1, "missing signer ID.");
470 sigdat
->sig_type
= 0;
471 sigdat
->pk_alg
= pkt_getch (wlk
->pfile
);
472 sigdat
->hash_alg
= pkt_getch (wlk
->pfile
);
475 LogBabblePrintf("signature: sig_type %d, pk_alg %d, hash_alg %d\n",
476 sigdat
->sig_type
, sigdat
->pk_alg
, sigdat
->hash_alg
);
478 // We only handle binary file signatures
479 if (sigdat
->sig_type
!= RFC4880_ST_BINARY
)
481 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, sigdat
->sig_type
, "unsupported sig type.");
485 // We only handle RSA and DSA keys
486 if ((sigdat
->pk_alg
!= RFC4880_PK_DSA
) && (sigdat
->pk_alg
!= RFC4880_PK_RSA
))
488 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, sigdat
->pk_alg
, "unsupported pk alg.");
492 // Start to hash all the data. Figure out what hash to use.
493 sigdat
->algo
= pkt_convert_hashcode (sigdat
->hash_alg
);
494 if (sigdat
->algo
== GCRY_MD_NONE
)
496 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, sigdat
->hash_alg
, "unconvertible hash.");
500 // Now we know hash algo, we can create md context.
502 gcry_error_t rv
= gcry_md_open (&sigdat
->md
, sigdat
->algo
, 0);
503 if (rv
!= GPG_ERR_NO_ERROR
)
505 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, rv
, "while initialising message digest.");
509 // Add all the sig_file data into the hash.
510 sigdat
->sign_data
->seek (0, IO_SEEK_SET
);
511 size_t nbytes
= sigdat
->sign_data
->get_size ();
512 if (nbytes
!= shovel_stream_data_into_md (sigdat
->sign_data
, nbytes
, sigdat
->md
))
514 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, sigdat
->hash_alg
, "internal buffer error.");
517 sigdat
->sign_data
->seek (0, IO_SEEK_SET
);
519 // V4 now has some hashed subpackets
520 int hashed_subpkt_size
= (ver
== 4) ? pkt_getword (wlk
->pfile
) : 0;
521 if (hashed_subpkt_size
)
522 pkt_walk_subpackets (wlk
->pfile
, hashed_subpkt_walker
, wlk
->owner
,
523 wlk
->pfile
->tell (), hashed_subpkt_size
, wlk
->userdata
);
525 // V4 now has some unhashed subpackets
526 int unhashed_subpkt_size
= (ver
== 4) ? pkt_getword (wlk
->pfile
) : 0;
527 if (unhashed_subpkt_size
)
528 pkt_walk_subpackets (wlk
->pfile
, unhashed_subpkt_walker
, wlk
->owner
,
529 wlk
->pfile
->tell (), unhashed_subpkt_size
, wlk
->userdata
);
531 // Both formats now have 16 bits of the hash value.
532 int hash_first
= pkt_getword (wlk
->pfile
);
534 MESSAGE ("signature: hash leftmost 2 bytes 0x%04x\n", hash_first
);
536 /* Algorithm-Specific Fields for signatures:
542 DSA signatures MUST use hashes that are equal in size to the number of
543 bits of q, the group generated by the DSA key's generator value.
546 - MPI of RSA value m^d mod n (aka s)
548 sigdat
->dsa_mpi_r
= sigdat
->dsa_mpi_s
= 0;
549 sigdat
->rsa_mpi_s
= 0;
551 if (sigdat
->pk_alg
== RFC4880_PK_DSA
)
553 if ((pkt_get_mpi (&sigdat
->dsa_mpi_r
, wlk
->pfile
) < 0)
554 || (pkt_get_mpi (&sigdat
->dsa_mpi_s
, wlk
->pfile
) < 0))
556 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, "unpacking mpi.");
560 else if (sigdat
->pk_alg
== RFC4880_PK_RSA
)
562 if (pkt_get_mpi (&sigdat
->rsa_mpi_s
, wlk
->pfile
) < 0)
564 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, "unpacking mpi.");
569 MESSAGE ("Read sig packets succesfully!\n");
571 // Now we got all the data out ok, rewind and hash the first trailer.
572 wlk
->pfile
->seek (v34hdrofs
, IO_SEEK_SET
);
573 nbytes
= (ver
== 4) ? (RFC4880_SIGV4_HASHED_OVERHEAD
+ hashed_subpkt_size
)
574 : (RFC4880_SIGV3_HASHED_SIZE
);
575 if (nbytes
!= shovel_stream_data_into_md (wlk
->pfile
, nbytes
, sigdat
->md
))
577 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, sigdat
->hash_alg
, "internal buffer error 2.");
583 // And now the synthetic final trailer.
584 gcry_md_putc (sigdat
->md
, 4);
585 gcry_md_putc (sigdat
->md
, 0xff);
586 gcry_md_putc (sigdat
->md
, (nbytes
>> 24) & 0xff);
587 gcry_md_putc (sigdat
->md
, (nbytes
>> 16) & 0xff);
588 gcry_md_putc (sigdat
->md
, (nbytes
>> 8) & 0xff);
589 gcry_md_putc (sigdat
->md
, nbytes
& 0xff);
593 gcry_md_final (sigdat
->md
);
594 MESSAGE("digest length is %d\n",gcry_md_get_algo_dlen (sigdat
->algo
));
596 // we have hashed all the data, and found the sig coefficients.
597 // heck this signature
598 if (verify_sig (sigdat
, wlk
->owner
))
599 sigdat
->valid
= true;
603 gcry_md_close (sigdat
->md
);
605 // discard sig coefffcients
606 if (sigdat
->dsa_mpi_r
)
607 gcry_mpi_release (sigdat
->dsa_mpi_r
);
608 if (sigdat
->dsa_mpi_s
)
609 gcry_mpi_release (sigdat
->dsa_mpi_s
);
610 if (sigdat
->rsa_mpi_s
)
611 gcry_mpi_release (sigdat
->rsa_mpi_s
);
613 // we can stop immediately if we found a good signature
614 return sigdat
->valid
? pktHALT
: pktCONTINUE
;
619 gcrypt_log_adaptor(void *priv
, int level
, const char *fmt
, va_list args
)
621 static std::string collected
;
623 char buf
[GPG_KEY_SEXPR_BUF_SIZE
];
624 vsnprintf (buf
, GPG_KEY_SEXPR_BUF_SIZE
, fmt
, args
);
631 if (collected
.length() == 0)
633 collected
= "gcrypt: ";
636 end
= strchr(start
, '\n');
644 if (level
== GCRY_LOG_DEBUG
)
645 Log (LOG_BABBLE
) << collected
<< endLog
;
647 Log (LOG_PLAIN
) << collected
<< endLog
;
657 /* Verify the signature on an ini file. Takes care of all key-handling. */
659 verify_ini_file_sig (io_stream
*ini_file
, io_stream
*ini_sig_file
, HWND owner
)
661 /* Data returned from packet walker. */
662 struct sig_data sigdat
;
664 /* Vector of keys to use. */
665 std::vector
<struct key_info
> keys_to_try
;
667 /* Overall status of signature. */
670 // Temps for intermediate processing.
674 /* Initialise the library. */
675 static bool gcrypt_init
= false;
679 gcry_set_log_handler (gcrypt_log_adaptor
, NULL
);
681 gcry_check_version (NULL
);
683 if ((rv
= gcry_control (GCRYCTL_SELFTEST
)) != GPG_ERR_NO_ERROR
)
684 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "libgcrypt selftest failed");
687 gcry_control (GCRYCTL_SET_DEBUG_FLAGS
, 1);
692 /* So first build the built-in key. */
693 gcry_sexp_t cygwin_key
;
694 rv
= gcry_sexp_new (&cygwin_key
, cygwin_pubkey_sexpr
, strlen (cygwin_pubkey_sexpr
), 1);
695 if (rv
!= GPG_ERR_NO_ERROR
)
697 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "while creating pubkey s-expr.");
701 keys_to_try
.push_back (key_info("cygwin", true, cygwin_key
));
705 char sexprbuf
[GPG_KEY_SEXPR_BUF_SIZE
];
706 n
= gcry_sexp_sprint (cygwin_key
, GCRYSEXP_FMT_ADVANCED
, sexprbuf
, GPG_KEY_SEXPR_BUF_SIZE
);
707 LogBabblePrintf ("key:%d\n'%s'", n
, sexprbuf
);
708 #endif /* CRYPTODEBUGGING */
710 /* If not disabled, also try the old built-in key */
711 gcry_sexp_t cygwin_old_key
;
712 if (EnableOldKeysOption
)
714 rv
= gcry_sexp_new (&cygwin_old_key
, cygwin_old_pubkey_sexpr
, strlen (cygwin_old_pubkey_sexpr
), 1);
715 if (rv
!= GPG_ERR_NO_ERROR
)
717 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "while creating old pubkey s-expr.");
721 keys_to_try
.push_back (key_info ("cygwin-old", TRUE
, cygwin_old_key
));
724 /* Vector of cached extra keys from last run. */
725 static std::vector
<gcry_sexp_t
> input_keys
;
727 /* Next we should extract the keys from the extrakeys user
728 setting, and flush it; we'll only return them to it if they
729 get used. OTOH, should we do this at all? The user settings
730 file isn't heavily protected. So we only trust the extra
731 keys if we're told to by the user. We still read them in
732 and write them back out, which canonicalises and eliminates
733 any duplicates or garbage lines that may have crept in. */
734 static bool input_keys_read
= false;
735 if (!input_keys_read
)
737 // We only want to do this once, first time through:
738 input_keys_read
= true;
739 // Copy all valid keys from ExtraKeysSetting into a
740 // static vector where we can keep them throughout the
741 // remainder of the run.
742 for (size_t i
= 0; i
< ExtraKeysSetting::instance().num_keys (); i
++)
744 const char *keystring
= ExtraKeysSetting::instance().get_key (i
, &n
);
746 rv
= gcry_sexp_new (&newkey
, keystring
, n
, 1);
747 if (rv
== GPG_ERR_NO_ERROR
)
748 input_keys
.push_back (newkey
);
751 // Now flush out the ExtraKeysSetting; from here on it
752 // will build up a list of the keys we want to retain.
753 ExtraKeysSetting::instance().flush ();
755 // Which, if we aren't using them, means all the ones
757 if (KeepUntrustedKeysOption
|| !UntrustedKeysOption
)
759 std::vector
<gcry_sexp_t
>::iterator it
;
760 for (it
= input_keys
.begin (); it
< input_keys
.end (); ++it
)
761 add_key_from_sexpr (*it
);
765 // We only use the untrusted keys if told to.
766 if (KeepUntrustedKeysOption
|| UntrustedKeysOption
)
767 for (std::vector
<gcry_sexp_t
>::const_iterator it
= input_keys
.begin ();
768 it
< input_keys
.end ();
771 keys_to_try
.push_back (key_info ("saved key", false, *it
, false));
774 /* Next, there may have been command-line options. */
775 std::vector
<std::string
> SexprExtraKeyStrings
= SexprExtraKeyOption
;
776 for (std::vector
<std::string
>::const_iterator it
777 = SexprExtraKeyStrings
.begin ();
778 it
!= SexprExtraKeyStrings
.end (); ++it
)
780 MESSAGE ("key str is '%s'\n", it
->c_str ());
781 gcry_sexp_t dsa_key2
= 0;
782 rv
= gcry_sexp_new (&dsa_key2
, it
->c_str (), it
->size (), 1);
783 if (rv
== GPG_ERR_NO_ERROR
)
785 // We probably want to add it to the extra keys setting
786 // if KeepUntrustedKeysOption is supplied.
787 if (KeepUntrustedKeysOption
)
788 add_key_from_sexpr (dsa_key2
);
790 n
= gcry_sexp_sprint (dsa_key2
, GCRYSEXP_FMT_ADVANCED
, sexprbuf
,
791 GPG_KEY_SEXPR_BUF_SIZE
);
792 // +1 because we want to include the nul-terminator.
793 n
= fold_lfs_and_spaces (sexprbuf
, n
+ 1);
794 ExtraKeysSetting::instance().add_key (sexprbuf
);
795 LogBabblePrintf ("key2:%d\n'%s'", n
, sexprbuf
);
796 #endif /* CRYPTODEBUGGING */
797 keys_to_try
.push_back (key_info ("from command-line option --sexpr-pubkey", false, dsa_key2
));
801 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "invalid command-line pubkey s-expr.");
805 /* Also, we may have to read a key(s) file. */
806 std::vector
<std::string
> ExtraKeysFiles
= ExtraKeyOption
;
807 for (std::vector
<std::string
>::const_iterator it
808 = ExtraKeysFiles
.begin ();
809 it
!= ExtraKeysFiles
.end (); ++it
)
811 io_stream
*keys
= get_url_to_membuf (*it
, owner
);
814 struct key_data kdat
;
815 pkt_walk_packets (keys
, key_file_walker
, owner
, 0, keys
->get_size (), &kdat
);
816 // We now have a vector of (some/any?) keys returned from
817 // the walker; add them to the list to try.
818 while (!kdat
.keys
.empty ())
820 // We probably want to add it to the extra keys setting
821 // if KeepUntrustedKeysOption is supplied.
822 if (KeepUntrustedKeysOption
)
823 add_key_from_sexpr (kdat
.keys
.back ());
825 n
= gcry_sexp_sprint (kdat
.keys
.back (), GCRYSEXP_FMT_ADVANCED
,
826 sexprbuf
, GPG_KEY_SEXPR_BUF_SIZE
);
827 // +1 because we want to include the nul-terminator.
828 n
= fold_lfs_and_spaces (sexprbuf
, n
+ 1);
829 ExtraKeysSetting::instance().add_key (sexprbuf
);
830 LogBabblePrintf ("key3:%d\n'%s'", n
, sexprbuf
);
831 #endif /* CRYPTODEBUGGING */
832 keys_to_try
.push_back (key_info ("from command-line option --pubkey", false, kdat
.keys
.back ()));
833 kdat
.keys
.pop_back ();
838 // We pass in a pointer to the ini file in the user context data,
839 // which the packet walker callback uses to create a new hash
840 // context preloaded with all the signature-covered data.
841 sigdat
.valid
= false;
842 sigdat
.sign_data
= ini_file
;
843 sigdat
.keys_to_try
= &keys_to_try
;
845 pkt_walk_packets (ini_sig_file
, sig_file_walker
, owner
, 0,
846 ini_sig_file
->get_size (), &sigdat
);
848 sig_ok
= sigdat
.valid
;
850 while (keys_to_try
.size ())
852 if (keys_to_try
.back ().owned
)
853 gcry_sexp_release (keys_to_try
.back ().key
);
854 keys_to_try
.pop_back ();