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", IDS_HELPTEXT_PUBKEY
);
46 static StringArrayOption
SexprExtraKeyOption ('S', "sexpr-pubkey", IDS_HELPTEXT_SEXPR_PUBKEY
);
47 static BoolOption
UntrustedKeysOption (false, 'u', "untrusted-keys", IDS_HELPTEXT_UNTRUSTED_KEYS
);
48 static BoolOption
KeepUntrustedKeysOption (false, 'U', "keep-untrusted-keys", IDS_HELPTEXT_KEEP_UNTRUSTED_KEYS
);
49 static BoolOption
EnableOldKeysOption (false, '\0', "old-keys", IDS_HELPTEXT_OLD_KEYS
,
50 BoolOption::BoolOptionType::pairedAble
);
52 /* Embedded public half of Cygwin signing key. */
53 static const char *cygwin_pubkey_sexpr
=
54 #include "cyg-pubkey.h"
57 static const char *cygwin_old_pubkey_sexpr
=
58 #include "cyg-old-pubkey.h"
61 /* S-expr template for DSA pubkey. */
62 static const char *dsa_pubkey_templ
= "(public-key (dsa (p %m) (q %m) (g %m) (y %m)))";
64 /* S-expr template for RSA pubkey. */
65 static const char *rsa_pubkey_templ
= "(public-key (rsa (n %m) (e %m)))";
67 /* S-expr template for DSA signature. */
68 static const char *dsa_sig_templ
= "(sig-val (dsa (r %m) (s %m)))";
70 /* S-expr template for RSA signature. */
71 static const char *rsa_sig_templ
= "(sig-val (rsa (s %m)))";
73 /* S-expr template for DSA data block to be signed. */
74 static const char *dsa_data_hash_templ
= "(data (flags raw) (hash %s %b))";
76 /* S-expr template for RSA data block to be signed. */
77 static const char *rsa_data_hash_templ
= "(data (flags pkcs1) (hash %s %b))";
79 /* Information on a key to try */
82 key_info(std::string _name
, bool _builtin
, gcry_sexp_t _key
, bool _owned
=true) :
83 name(_name
), builtin(_builtin
), key(_key
), owned(_owned
)
88 bool builtin
; // if true, we don't need to retain this key with add_key_from_sexpr()
90 bool owned
; // if true, we own this key and should use gcry_sexp_release() on it
93 /* User context data for sig packet walk. */
96 /* MPI values of sig components. */
97 gcry_mpi_t dsa_mpi_r
, dsa_mpi_s
;
104 io_stream
*sign_data
;
106 /* Auxiliary data. */
111 /* Converted algo code. */
115 std::vector
<struct key_info
> *keys_to_try
;
121 /* User context data for key packet walk. */
124 std::vector
<gcry_sexp_t
> keys
;
127 /* Callback hook for walking packets in gpg key file. Extracts
128 the key coefficients from any public key packets encountered and
129 converts them into s-expr pubkey format, returning the public
130 keys thus found to the caller in a vector in the userdata context. */
132 pkt_cb_resp
key_file_walker (struct packet_walker
*wlk
, unsigned char tag
,
133 size_t packetsize
, size_t hdrpos
)
135 struct key_data
*kdat
= (struct key_data
*)(wlk
->userdata
);
137 MESSAGE ("key packet %d size %d at offs $%04x kdat $%08x\n", tag
,
138 packetsize
, hdrpos
, kdat
);
140 if (tag
!= RFC4880_PT_PUBLIC_KEY
)
143 // So, get the data out. Version is first. In case of any errors during
144 // parsing, we just discard the key and continue, hoping to find a good one.
145 char ver
= pkt_getch (wlk
->pfile
);
148 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, ver
, "unsupported key version.");
152 // Only V4 accepted. Discard creation time.
153 if (pkt_getdword (wlk
->pfile
) == -1)
155 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, -1, "missing creation time.");
159 char pkalg
= pkt_getch (wlk
->pfile
);
160 if ((pkalg
!= RFC4880_PK_DSA
) && (pkalg
!= RFC4880_PK_RSA
))
162 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, pkalg
, "unsupported key alg.");
166 // Next, the key coefficient MPIs should be present. Read them out, convert
167 // to an s-expr and add that to the list of keys.
171 if (pkalg
== RFC4880_PK_DSA
)
173 gcry_mpi_t p
, q
, g
, y
;
176 if ((pkt_get_mpi (&p
, wlk
->pfile
) >= 0)
177 && (pkt_get_mpi (&q
, wlk
->pfile
) >= 0)
178 && (pkt_get_mpi (&g
, wlk
->pfile
) >= 0)
179 && (pkt_get_mpi (&y
, wlk
->pfile
) >= 0))
181 gcry_error_t rv
= gcry_sexp_build (&new_key
, &erroff
, dsa_pubkey_templ
, p
, q
, g
, y
);
182 if (rv
!= GPG_ERR_NO_ERROR
)
184 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, rv
, "while creating sig s-expr.");
189 // Release temps and continue.
191 gcry_mpi_release (p
);
193 gcry_mpi_release (q
);
195 gcry_mpi_release (g
);
197 gcry_mpi_release (y
);
199 else if (pkalg
== RFC4880_PK_RSA
)
204 if ((pkt_get_mpi (&n
, wlk
->pfile
) >= 0)
205 && (pkt_get_mpi (&e
, wlk
->pfile
) >= 0))
207 gcry_error_t rv
= gcry_sexp_build (&new_key
, &erroff
, rsa_pubkey_templ
, n
, e
);
208 if (rv
!= GPG_ERR_NO_ERROR
)
210 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, rv
, "while creating sig s-expr.");
216 gcry_mpi_release (n
);
218 gcry_mpi_release (e
);
223 char sexprbuf
[GPG_KEY_SEXPR_BUF_SIZE
];
224 erroff
= gcry_sexp_sprint (new_key
, GCRYSEXP_FMT_ADVANCED
, sexprbuf
,
225 GPG_KEY_SEXPR_BUF_SIZE
);
226 LogBabblePrintf ("key:%d\n'%s'", erroff
, sexprbuf
);
227 #endif /* CRYPTODEBUGGING */
229 // Return it to caller in the vector.
230 kdat
->keys
.push_back (new_key
);
235 /* Does what its name suggests: feeds a chosen amount of the data found
236 at the current seek position in an io_stream into the message digest
237 context passed in, using reasonably-sized chunks for efficiency. */
239 shovel_stream_data_into_md (io_stream
*stream
, size_t nbytes
, gcry_md_hd_t md
)
241 const size_t TMPBUFSZ
= 1024;
242 unsigned char tmpbuf
[TMPBUFSZ
];
243 size_t this_time
, total
= 0;
245 MESSAGE ("shovel %d bytes at pos $%08x\n", nbytes
, stream
->tell ());
248 this_time
= (nbytes
> TMPBUFSZ
) ? TMPBUFSZ
: nbytes
;
249 actual
= stream
->read (tmpbuf
, this_time
);
252 gcry_md_write (md
, tmpbuf
, actual
);
255 if (actual
!= (ssize_t
)this_time
)
261 /* Canonicalise an s-expr by converting LFs to spaces so that
262 it's all on one line and folding multiple spaces as we go. */
264 fold_lfs_and_spaces (char *buf
, size_t n
)
266 char *ptr1
= buf
, *ptr2
= buf
;
275 while (n
&& ((*ptr1
== ' ') || (*ptr1
== 0x0a)))
284 /* Size and allocate a temp buffer to print a representation
285 of a public key s-expr into, then add that to the extra keys
286 setting so it persists for the next run. */
288 add_key_from_sexpr (gcry_sexp_t key
)
290 size_t n
= gcry_sexp_sprint (key
, GCRYSEXP_FMT_ADVANCED
, 0, ~0);
291 char *sexprbuf
= new char[n
];
292 n
= gcry_sexp_sprint (key
, GCRYSEXP_FMT_ADVANCED
, sexprbuf
, n
);
293 // +1 because we want to include the nul-terminator.
294 n
= fold_lfs_and_spaces (sexprbuf
, n
+ 1);
295 ExtraKeysSetting::instance().add_key (sexprbuf
);
296 MESSAGE ("keep:%d\n'%s'", n
, sexprbuf
);
301 verify_sig(struct sig_data
*sigdat
, HWND owner
)
306 /* sig coefficients in s-expr format. */
309 /* signature hash data in s-expr format. */
312 /* Build everything into s-exprs, and call the libgcrypt verification
315 if (sigdat
->pk_alg
== RFC4880_PK_DSA
)
317 rv
= gcry_sexp_build (&sig
, &n
, dsa_sig_templ
, sigdat
->dsa_mpi_r
,
319 if (rv
!= GPG_ERR_NO_ERROR
)
321 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "while creating sig s-expr.");
325 rv
= gcry_sexp_build (&hash
, &n
, dsa_data_hash_templ
,
326 gcry_md_algo_name(sigdat
->algo
),
327 gcry_md_get_algo_dlen (sigdat
->algo
),
328 gcry_md_read (sigdat
->md
, 0));
329 if (rv
!= GPG_ERR_NO_ERROR
)
331 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "while creating hash s-expr.");
335 else if (sigdat
->pk_alg
== RFC4880_PK_RSA
)
337 rv
= gcry_sexp_build (&sig
, &n
, rsa_sig_templ
, sigdat
->rsa_mpi_s
);
338 if (rv
!= GPG_ERR_NO_ERROR
)
340 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "while creating sig s-expr.");
344 rv
= gcry_sexp_build (&hash
, &n
, rsa_data_hash_templ
,
345 gcry_md_algo_name(sigdat
->algo
),
346 gcry_md_get_algo_dlen (sigdat
->algo
),
347 gcry_md_read (sigdat
->md
, 0));
348 if (rv
!= GPG_ERR_NO_ERROR
)
350 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "while creating hash s-expr.");
356 char sexprbuf
[GPG_KEY_SEXPR_BUF_SIZE
];
357 n
= gcry_sexp_sprint (sig
, GCRYSEXP_FMT_ADVANCED
, sexprbuf
,
358 GPG_KEY_SEXPR_BUF_SIZE
);
359 LogBabblePrintf ("sig:%d\n'%s'", n
, sexprbuf
);
360 n
= gcry_sexp_sprint (hash
, GCRYSEXP_FMT_ADVANCED
, sexprbuf
,
361 GPG_KEY_SEXPR_BUF_SIZE
);
362 LogBabblePrintf ("hash:%d\n'%s'", n
, sexprbuf
);
363 #endif /* CRYPTODEBUGGING */
365 // Well, we're actually there!
366 // Try it against each key in turn
368 std::vector
<key_info
>::iterator it
;
369 for (it
= sigdat
->keys_to_try
->begin ();
370 it
< sigdat
->keys_to_try
->end ();
373 rv
= gcry_pk_verify (sig
, hash
, it
->key
);
375 LogBabblePrintf("signature: tried key %s, returned 0x%08x %s\n",
376 it
->name
.c_str(), rv
, gcry_strerror(rv
));
378 if (rv
!= GPG_ERR_NO_ERROR
)
380 // Found it! This key gets kept!
382 add_key_from_sexpr (it
->key
);
386 gcry_sexp_release (sig
);
387 gcry_sexp_release (hash
);
390 return (rv
== GPG_ERR_NO_ERROR
);
393 /* Do-nothing stubs called by the sig file walker to
394 walk over the embedded subpackets. In the event, we don't
395 actually need to do this as we aren't inspecting them. */
397 pkt_cb_resp
hashed_subpkt_walker (struct packet_walker
*wlk
, unsigned char tag
,
398 size_t packetsize
, size_t hdrpos
)
404 pkt_cb_resp
unhashed_subpkt_walker (struct packet_walker
*wlk
, unsigned char tag
,
405 size_t packetsize
, size_t hdrpos
)
410 /* Callback to parse the packets found in the setup.ini/setup.bz2
411 signature file. We have to parse the header to get the hash type
412 and other details. Once we have that we can create a message
413 digest context and start pumping data through it; first the ini
414 file itself, then the portion of the packet itself that is
415 covered by the hash. */
417 pkt_cb_resp
sig_file_walker (struct packet_walker
*wlk
, unsigned char tag
,
418 size_t packetsize
, size_t hdrpos
)
420 struct sig_data
*sigdat
= (struct sig_data
*)(wlk
->userdata
);
422 if (tag
!= RFC4880_PT_SIGNATURE
)
425 // To add the trailers later, we hang on to the current pos.
426 size_t v34hdrofs
= wlk
->pfile
->tell ();
428 // So, get the data out. Version is first.
429 char ver
= pkt_getch (wlk
->pfile
);
430 if ((ver
< 3) || (ver
> 4))
432 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, ver
, "unsupported sig version.");
436 // Only V3 and V4 accepted.
439 sigdat
->sig_type
= pkt_getch (wlk
->pfile
);
440 sigdat
->pk_alg
= pkt_getch (wlk
->pfile
);
441 sigdat
->hash_alg
= pkt_getch (wlk
->pfile
);
445 int hmsize
= pkt_getch (wlk
->pfile
);
446 if (hmsize
!= RFC4880_SIGV3_HASHED_SIZE
)
448 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, hmsize
, "wrong hashed material size.");
451 v34hdrofs
= wlk
->pfile
->tell ();
452 if ((pkt_getch (wlk
->pfile
) < 0) || (pkt_getdword (wlk
->pfile
) == -1))
454 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, hmsize
, "wrong hashed material size.");
457 if ((pkt_getdword (wlk
->pfile
) == -1) || (pkt_getdword (wlk
->pfile
) == -1))
459 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, -1, "missing signer ID.");
463 sigdat
->sig_type
= 0;
464 sigdat
->pk_alg
= pkt_getch (wlk
->pfile
);
465 sigdat
->hash_alg
= pkt_getch (wlk
->pfile
);
468 LogBabblePrintf("signature: sig_type %d, pk_alg %d, hash_alg %d\n",
469 sigdat
->sig_type
, sigdat
->pk_alg
, sigdat
->hash_alg
);
471 // We only handle binary file signatures
472 if (sigdat
->sig_type
!= RFC4880_ST_BINARY
)
474 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, sigdat
->sig_type
, "unsupported sig type.");
478 // We only handle RSA and DSA keys
479 if ((sigdat
->pk_alg
!= RFC4880_PK_DSA
) && (sigdat
->pk_alg
!= RFC4880_PK_RSA
))
481 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, sigdat
->pk_alg
, "unsupported pk alg.");
485 // Start to hash all the data. Figure out what hash to use.
486 sigdat
->algo
= pkt_convert_hashcode (sigdat
->hash_alg
);
487 if (sigdat
->algo
== GCRY_MD_NONE
)
489 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, sigdat
->hash_alg
, "unconvertible hash.");
493 // Now we know hash algo, we can create md context.
495 gcry_error_t rv
= gcry_md_open (&sigdat
->md
, sigdat
->algo
, 0);
496 if (rv
!= GPG_ERR_NO_ERROR
)
498 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, rv
, "while initialising message digest.");
502 // Add all the sig_file data into the hash.
503 sigdat
->sign_data
->seek (0, IO_SEEK_SET
);
504 size_t nbytes
= sigdat
->sign_data
->get_size ();
505 if (nbytes
!= shovel_stream_data_into_md (sigdat
->sign_data
, nbytes
, sigdat
->md
))
507 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, sigdat
->hash_alg
, "internal buffer error.");
510 sigdat
->sign_data
->seek (0, IO_SEEK_SET
);
512 // V4 now has some hashed subpackets
513 int hashed_subpkt_size
= (ver
== 4) ? pkt_getword (wlk
->pfile
) : 0;
514 if (hashed_subpkt_size
)
515 pkt_walk_subpackets (wlk
->pfile
, hashed_subpkt_walker
, wlk
->owner
,
516 wlk
->pfile
->tell (), hashed_subpkt_size
, wlk
->userdata
);
518 // V4 now has some unhashed subpackets
519 int unhashed_subpkt_size
= (ver
== 4) ? pkt_getword (wlk
->pfile
) : 0;
520 if (unhashed_subpkt_size
)
521 pkt_walk_subpackets (wlk
->pfile
, unhashed_subpkt_walker
, wlk
->owner
,
522 wlk
->pfile
->tell (), unhashed_subpkt_size
, wlk
->userdata
);
524 // Both formats now have 16 bits of the hash value.
525 int hash_first
= pkt_getword (wlk
->pfile
);
527 MESSAGE ("signature: hash leftmost 2 bytes 0x%04x\n", hash_first
);
529 /* Algorithm-Specific Fields for signatures:
535 DSA signatures MUST use hashes that are equal in size to the number of
536 bits of q, the group generated by the DSA key's generator value.
539 - MPI of RSA value m^d mod n (aka s)
541 sigdat
->dsa_mpi_r
= sigdat
->dsa_mpi_s
= 0;
542 sigdat
->rsa_mpi_s
= 0;
544 if (sigdat
->pk_alg
== RFC4880_PK_DSA
)
546 if ((pkt_get_mpi (&sigdat
->dsa_mpi_r
, wlk
->pfile
) < 0)
547 || (pkt_get_mpi (&sigdat
->dsa_mpi_s
, wlk
->pfile
) < 0))
549 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, "unpacking mpi.");
553 else if (sigdat
->pk_alg
== RFC4880_PK_RSA
)
555 if (pkt_get_mpi (&sigdat
->rsa_mpi_s
, wlk
->pfile
) < 0)
557 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, "unpacking mpi.");
562 MESSAGE ("Read sig packets succesfully!\n");
564 // Now we got all the data out ok, rewind and hash the first trailer.
565 wlk
->pfile
->seek (v34hdrofs
, IO_SEEK_SET
);
566 nbytes
= (ver
== 4) ? (RFC4880_SIGV4_HASHED_OVERHEAD
+ hashed_subpkt_size
)
567 : (RFC4880_SIGV3_HASHED_SIZE
);
568 if (nbytes
!= shovel_stream_data_into_md (wlk
->pfile
, nbytes
, sigdat
->md
))
570 ERRKIND (wlk
->owner
, IDS_CRYPTO_ERROR
, sigdat
->hash_alg
, "internal buffer error 2.");
576 // And now the synthetic final trailer.
577 gcry_md_putc (sigdat
->md
, 4);
578 gcry_md_putc (sigdat
->md
, 0xff);
579 gcry_md_putc (sigdat
->md
, (nbytes
>> 24) & 0xff);
580 gcry_md_putc (sigdat
->md
, (nbytes
>> 16) & 0xff);
581 gcry_md_putc (sigdat
->md
, (nbytes
>> 8) & 0xff);
582 gcry_md_putc (sigdat
->md
, nbytes
& 0xff);
586 gcry_md_final (sigdat
->md
);
587 MESSAGE("digest length is %d\n",gcry_md_get_algo_dlen (sigdat
->algo
));
589 // we have hashed all the data, and found the sig coefficients.
590 // heck this signature
591 if (verify_sig (sigdat
, wlk
->owner
))
592 sigdat
->valid
= true;
596 gcry_md_close (sigdat
->md
);
598 // discard sig coefffcients
599 if (sigdat
->dsa_mpi_r
)
600 gcry_mpi_release (sigdat
->dsa_mpi_r
);
601 if (sigdat
->dsa_mpi_s
)
602 gcry_mpi_release (sigdat
->dsa_mpi_s
);
603 if (sigdat
->rsa_mpi_s
)
604 gcry_mpi_release (sigdat
->rsa_mpi_s
);
606 // we can stop immediately if we found a good signature
607 return sigdat
->valid
? pktHALT
: pktCONTINUE
;
612 gcrypt_log_adaptor(void *priv
, int level
, const char *fmt
, va_list args
)
614 static std::string collected
;
616 char buf
[GPG_KEY_SEXPR_BUF_SIZE
];
617 vsnprintf (buf
, GPG_KEY_SEXPR_BUF_SIZE
, fmt
, args
);
624 if (collected
.length() == 0)
626 collected
= "gcrypt: ";
629 end
= strchr(start
, '\n');
637 if (level
== GCRY_LOG_DEBUG
)
638 Log (LOG_BABBLE
) << collected
<< endLog
;
640 Log (LOG_PLAIN
) << collected
<< endLog
;
650 /* Verify the signature on an ini file. Takes care of all key-handling. */
652 verify_ini_file_sig (io_stream
*ini_file
, io_stream
*ini_sig_file
, HWND owner
)
654 /* Data returned from packet walker. */
655 struct sig_data sigdat
;
657 /* Vector of keys to use. */
658 std::vector
<struct key_info
> keys_to_try
;
660 /* Overall status of signature. */
663 // Temps for intermediate processing.
667 /* Initialise the library. */
668 static bool gcrypt_init
= false;
672 gcry_set_log_handler (gcrypt_log_adaptor
, NULL
);
674 gcry_check_version (NULL
);
676 if ((rv
= gcry_control (GCRYCTL_SELFTEST
)) != GPG_ERR_NO_ERROR
)
677 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "libgcrypt selftest failed");
680 gcry_control (GCRYCTL_SET_DEBUG_FLAGS
, 1);
685 /* So first build the built-in key. */
686 gcry_sexp_t cygwin_key
;
687 rv
= gcry_sexp_new (&cygwin_key
, cygwin_pubkey_sexpr
, strlen (cygwin_pubkey_sexpr
), 1);
688 if (rv
!= GPG_ERR_NO_ERROR
)
690 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "while creating pubkey s-expr.");
694 keys_to_try
.push_back (key_info("cygwin", true, cygwin_key
));
698 char sexprbuf
[GPG_KEY_SEXPR_BUF_SIZE
];
699 n
= gcry_sexp_sprint (cygwin_key
, GCRYSEXP_FMT_ADVANCED
, sexprbuf
, GPG_KEY_SEXPR_BUF_SIZE
);
700 LogBabblePrintf ("key:%d\n'%s'", n
, sexprbuf
);
701 #endif /* CRYPTODEBUGGING */
703 /* If not disabled, also try the old built-in key */
704 gcry_sexp_t cygwin_old_key
;
705 if (EnableOldKeysOption
)
707 rv
= gcry_sexp_new (&cygwin_old_key
, cygwin_old_pubkey_sexpr
, strlen (cygwin_old_pubkey_sexpr
), 1);
708 if (rv
!= GPG_ERR_NO_ERROR
)
710 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "while creating old pubkey s-expr.");
714 keys_to_try
.push_back (key_info ("cygwin-old", TRUE
, cygwin_old_key
));
717 /* Vector of cached extra keys from last run. */
718 static std::vector
<gcry_sexp_t
> input_keys
;
720 /* Next we should extract the keys from the extrakeys user
721 setting, and flush it; we'll only return them to it if they
722 get used. OTOH, should we do this at all? The user settings
723 file isn't heavily protected. So we only trust the extra
724 keys if we're told to by the user. We still read them in
725 and write them back out, which canonicalises and eliminates
726 any duplicates or garbage lines that may have crept in. */
727 static bool input_keys_read
= false;
728 if (!input_keys_read
)
730 // We only want to do this once, first time through:
731 input_keys_read
= true;
732 // Copy all valid keys from ExtraKeysSetting into a
733 // static vector where we can keep them throughout the
734 // remainder of the run.
735 for (size_t i
= 0; i
< ExtraKeysSetting::instance().num_keys (); i
++)
737 const char *keystring
= ExtraKeysSetting::instance().get_key (i
, &n
);
739 rv
= gcry_sexp_new (&newkey
, keystring
, n
, 1);
740 if (rv
== GPG_ERR_NO_ERROR
)
741 input_keys
.push_back (newkey
);
744 // Now flush out the ExtraKeysSetting; from here on it
745 // will build up a list of the keys we want to retain.
746 ExtraKeysSetting::instance().flush ();
748 // Which, if we aren't using them, means all the ones
750 if (KeepUntrustedKeysOption
|| !UntrustedKeysOption
)
752 std::vector
<gcry_sexp_t
>::iterator it
;
753 for (it
= input_keys
.begin (); it
< input_keys
.end (); ++it
)
754 add_key_from_sexpr (*it
);
758 // We only use the untrusted keys if told to.
759 if (KeepUntrustedKeysOption
|| UntrustedKeysOption
)
760 for (std::vector
<gcry_sexp_t
>::const_iterator it
= input_keys
.begin ();
761 it
< input_keys
.end ();
764 keys_to_try
.push_back (key_info ("saved key", false, *it
, false));
767 /* Next, there may have been command-line options. */
768 std::vector
<std::string
> SexprExtraKeyStrings
= SexprExtraKeyOption
;
769 for (std::vector
<std::string
>::const_iterator it
770 = SexprExtraKeyStrings
.begin ();
771 it
!= SexprExtraKeyStrings
.end (); ++it
)
773 MESSAGE ("key str is '%s'\n", it
->c_str ());
774 gcry_sexp_t dsa_key2
= 0;
775 rv
= gcry_sexp_new (&dsa_key2
, it
->c_str (), it
->size (), 1);
776 if (rv
== GPG_ERR_NO_ERROR
)
778 // We probably want to add it to the extra keys setting
779 // if KeepUntrustedKeysOption is supplied.
780 if (KeepUntrustedKeysOption
)
781 add_key_from_sexpr (dsa_key2
);
783 n
= gcry_sexp_sprint (dsa_key2
, GCRYSEXP_FMT_ADVANCED
, sexprbuf
,
784 GPG_KEY_SEXPR_BUF_SIZE
);
785 // +1 because we want to include the nul-terminator.
786 n
= fold_lfs_and_spaces (sexprbuf
, n
+ 1);
787 ExtraKeysSetting::instance().add_key (sexprbuf
);
788 LogBabblePrintf ("key2:%d\n'%s'", n
, sexprbuf
);
789 #endif /* CRYPTODEBUGGING */
790 keys_to_try
.push_back (key_info ("from command-line option --sexpr-pubkey", false, dsa_key2
));
794 ERRKIND (owner
, IDS_CRYPTO_ERROR
, rv
, "invalid command-line pubkey s-expr.");
798 /* Also, we may have to read a key(s) file. */
799 std::vector
<std::string
> ExtraKeysFiles
= ExtraKeyOption
;
800 for (std::vector
<std::string
>::const_iterator it
801 = ExtraKeysFiles
.begin ();
802 it
!= ExtraKeysFiles
.end (); ++it
)
804 io_stream
*keys
= get_url_to_membuf (*it
, owner
);
807 struct key_data kdat
;
808 pkt_walk_packets (keys
, key_file_walker
, owner
, 0, keys
->get_size (), &kdat
);
809 // We now have a vector of (some/any?) keys returned from
810 // the walker; add them to the list to try.
811 while (!kdat
.keys
.empty ())
813 // We probably want to add it to the extra keys setting
814 // if KeepUntrustedKeysOption is supplied.
815 if (KeepUntrustedKeysOption
)
816 add_key_from_sexpr (kdat
.keys
.back ());
818 n
= gcry_sexp_sprint (kdat
.keys
.back (), GCRYSEXP_FMT_ADVANCED
,
819 sexprbuf
, GPG_KEY_SEXPR_BUF_SIZE
);
820 // +1 because we want to include the nul-terminator.
821 n
= fold_lfs_and_spaces (sexprbuf
, n
+ 1);
822 ExtraKeysSetting::instance().add_key (sexprbuf
);
823 LogBabblePrintf ("key3:%d\n'%s'", n
, sexprbuf
);
824 #endif /* CRYPTODEBUGGING */
825 keys_to_try
.push_back (key_info ("from command-line option --pubkey", false, kdat
.keys
.back ()));
826 kdat
.keys
.pop_back ();
831 // We pass in a pointer to the ini file in the user context data,
832 // which the packet walker callback uses to create a new hash
833 // context preloaded with all the signature-covered data.
834 sigdat
.valid
= false;
835 sigdat
.sign_data
= ini_file
;
836 sigdat
.keys_to_try
= &keys_to_try
;
838 pkt_walk_packets (ini_sig_file
, sig_file_walker
, owner
, 0,
839 ini_sig_file
->get_size (), &sigdat
);
841 sig_ok
= sigdat
.valid
;
843 while (keys_to_try
.size ())
845 if (keys_to_try
.back ().owned
)
846 gcry_sexp_release (keys_to_try
.back ().key
);
847 keys_to_try
.pop_back ();