2015-01-08 18:37:20 +01:00
|
|
|
/*
|
|
|
|
This file is part of TALER
|
2020-01-19 19:21:58 +01:00
|
|
|
Copyright (C) 2014, 2015, 2016 Taler Systems SA
|
2015-01-08 18:37:20 +01:00
|
|
|
|
|
|
|
TALER is free software; you can redistribute it and/or modify it under the
|
|
|
|
terms of the GNU General Public License as published by the Free Software
|
|
|
|
Foundation; either version 3, or (at your option) any later version.
|
|
|
|
|
|
|
|
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
|
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
2016-07-07 17:55:25 +02:00
|
|
|
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
2015-01-08 18:37:20 +01:00
|
|
|
*/
|
|
|
|
/**
|
2016-03-01 15:35:04 +01:00
|
|
|
* @file taler-exchange-keycheck.c
|
|
|
|
* @brief Check exchange keys for validity. Reads the signing and denomination
|
|
|
|
* keys from the exchange directory and checks to make sure they are
|
2015-03-15 21:10:05 +01:00
|
|
|
* well-formed. This is purely a diagnostic tool.
|
2015-01-08 18:37:20 +01:00
|
|
|
* @author Florian Dold
|
|
|
|
* @author Benedikt Mueller
|
2015-03-15 21:10:05 +01:00
|
|
|
* @author Christian Grothoff
|
2015-01-08 18:37:20 +01:00
|
|
|
*/
|
|
|
|
#include <platform.h>
|
|
|
|
#include <gnunet/gnunet_util_lib.h>
|
2016-03-01 15:35:04 +01:00
|
|
|
#include "taler_exchangedb_lib.h"
|
2015-01-08 18:37:20 +01:00
|
|
|
|
2015-03-15 21:10:05 +01:00
|
|
|
/**
|
2016-03-01 15:35:04 +01:00
|
|
|
* Exchange directory with the keys.
|
2015-03-15 21:10:05 +01:00
|
|
|
*/
|
2016-03-01 15:35:04 +01:00
|
|
|
static char *exchange_directory;
|
2015-03-15 16:52:19 +01:00
|
|
|
|
2015-03-15 21:10:05 +01:00
|
|
|
/**
|
|
|
|
* Our configuration.
|
|
|
|
*/
|
2016-04-16 13:57:22 +02:00
|
|
|
static const struct GNUNET_CONFIGURATION_Handle *kcfg;
|
2015-01-08 18:37:20 +01:00
|
|
|
|
2016-04-16 13:57:22 +02:00
|
|
|
/**
|
|
|
|
* Return value from main().
|
|
|
|
*/
|
|
|
|
static int global_ret;
|
2015-01-08 18:37:20 +01:00
|
|
|
|
2020-03-18 13:58:40 +01:00
|
|
|
/**
|
|
|
|
* Option -i used to print full denomination key hashes for
|
|
|
|
* denominations of certain amounts.
|
|
|
|
*/
|
|
|
|
static struct TALER_Amount print_dk_amount;
|
|
|
|
|
2016-04-16 19:53:01 +02:00
|
|
|
|
2015-03-15 21:10:05 +01:00
|
|
|
/**
|
|
|
|
* Function called on each signing key.
|
|
|
|
*
|
|
|
|
* @param cls closure (NULL)
|
|
|
|
* @param filename name of the file the key came from
|
|
|
|
* @param ski the sign key
|
|
|
|
* @return #GNUNET_OK to continue to iterate,
|
|
|
|
* #GNUNET_NO to stop iteration with no error,
|
|
|
|
* #GNUNET_SYSERR to abort iteration with error!
|
|
|
|
*/
|
2015-01-08 18:37:20 +01:00
|
|
|
static int
|
2015-03-15 16:52:19 +01:00
|
|
|
signkeys_iter (void *cls,
|
|
|
|
const char *filename,
|
2016-03-01 15:35:04 +01:00
|
|
|
const struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP *ski)
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
2019-11-01 14:34:34 +01:00
|
|
|
(void) cls;
|
2015-03-15 21:10:05 +01:00
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
|
|
|
"Iterating over key `%s' for start time %s\n",
|
|
|
|
filename,
|
|
|
|
GNUNET_STRINGS_absolute_time_to_string
|
2019-08-25 16:18:24 +02:00
|
|
|
(GNUNET_TIME_absolute_ntoh (ski->issue.start)));
|
2015-01-08 18:37:20 +01:00
|
|
|
|
2015-01-09 18:18:59 +01:00
|
|
|
if (ntohl (ski->issue.purpose.size) !=
|
2018-10-27 18:39:12 +02:00
|
|
|
(sizeof (struct TALER_ExchangeSigningKeyValidityPS)))
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
2015-03-15 21:10:05 +01:00
|
|
|
fprintf (stderr,
|
|
|
|
"Signing key `%s' has invalid purpose size\n",
|
|
|
|
filename);
|
2015-01-08 18:37:20 +01:00
|
|
|
return GNUNET_SYSERR;
|
|
|
|
}
|
2019-08-25 16:18:24 +02:00
|
|
|
if ( (0 != GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us
|
|
|
|
% 1000000) ||
|
|
|
|
(0 != GNUNET_TIME_absolute_ntoh (ski->issue.expire).abs_value_us
|
|
|
|
% 1000000) ||
|
|
|
|
(0 != GNUNET_TIME_absolute_ntoh (ski->issue.end).abs_value_us
|
|
|
|
% 1000000) )
|
2015-06-20 22:22:59 +02:00
|
|
|
{
|
|
|
|
fprintf (stderr,
|
|
|
|
"Timestamps are not multiples of a round second\n");
|
|
|
|
return GNUNET_SYSERR;
|
|
|
|
}
|
|
|
|
|
2015-03-15 21:10:05 +01:00
|
|
|
if (GNUNET_OK !=
|
2015-03-28 14:22:21 +01:00
|
|
|
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY,
|
2015-03-15 21:10:05 +01:00
|
|
|
&ski->issue.purpose,
|
2018-10-27 18:39:12 +02:00
|
|
|
&ski->master_sig.eddsa_signature,
|
2015-03-27 19:58:40 +01:00
|
|
|
&ski->issue.master_public_key.eddsa_pub))
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
2015-03-15 21:10:05 +01:00
|
|
|
fprintf (stderr,
|
|
|
|
"Signing key `%s' has invalid signature\n",
|
|
|
|
filename);
|
2015-01-08 18:37:20 +01:00
|
|
|
return GNUNET_SYSERR;
|
|
|
|
}
|
2020-03-07 12:58:40 +01:00
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
|
|
|
"Signing key `%s' valid\n",
|
|
|
|
filename);
|
2015-01-08 18:37:20 +01:00
|
|
|
return GNUNET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-15 21:10:05 +01:00
|
|
|
/**
|
|
|
|
* Check signing keys.
|
|
|
|
*
|
|
|
|
* @return #GNUNET_OK if the keys are OK
|
|
|
|
* #GNUNET_NO if not
|
|
|
|
*/
|
2015-01-08 18:37:20 +01:00
|
|
|
static int
|
2016-03-01 15:35:04 +01:00
|
|
|
exchange_signkeys_check ()
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
2016-03-01 15:35:04 +01:00
|
|
|
if (0 > TALER_EXCHANGEDB_signing_keys_iterate (exchange_directory,
|
2016-04-10 17:10:20 +02:00
|
|
|
&signkeys_iter,
|
|
|
|
NULL))
|
2015-01-08 18:37:20 +01:00
|
|
|
return GNUNET_NO;
|
|
|
|
return GNUNET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-15 21:10:05 +01:00
|
|
|
/**
|
|
|
|
* Function called on each denomination key.
|
|
|
|
*
|
|
|
|
* @param cls closure (NULL)
|
|
|
|
* @param dki the denomination key
|
|
|
|
* @param alias coin alias
|
|
|
|
* @return #GNUNET_OK to continue to iterate,
|
|
|
|
* #GNUNET_NO to stop iteration with no error,
|
|
|
|
* #GNUNET_SYSERR to abort iteration with error!
|
|
|
|
*/
|
2015-01-09 18:18:59 +01:00
|
|
|
static int
|
|
|
|
denomkeys_iter (void *cls,
|
|
|
|
const char *alias,
|
2019-08-25 16:18:24 +02:00
|
|
|
const struct
|
2020-03-04 11:51:00 +01:00
|
|
|
TALER_EXCHANGEDB_DenominationKey *dki)
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
2015-03-15 21:10:05 +01:00
|
|
|
struct GNUNET_HashCode hc;
|
2020-03-18 13:58:40 +01:00
|
|
|
struct TALER_Amount value;
|
2015-01-08 18:37:20 +01:00
|
|
|
|
2019-11-01 14:34:34 +01:00
|
|
|
(void) cls;
|
2015-07-06 10:16:49 +02:00
|
|
|
if (ntohl (dki->issue.properties.purpose.size) !=
|
|
|
|
sizeof (struct TALER_DenominationKeyValidityPS))
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
2015-03-15 21:10:05 +01:00
|
|
|
fprintf (stderr,
|
|
|
|
"Denomination key for `%s' has invalid purpose size\n",
|
|
|
|
alias);
|
2015-01-08 18:37:20 +01:00
|
|
|
return GNUNET_SYSERR;
|
|
|
|
}
|
|
|
|
|
2019-08-25 16:18:24 +02:00
|
|
|
if ( (0 != GNUNET_TIME_absolute_ntoh (
|
|
|
|
dki->issue.properties.start).abs_value_us % 1000000) ||
|
|
|
|
(0 != GNUNET_TIME_absolute_ntoh (
|
|
|
|
dki->issue.properties.expire_withdraw).abs_value_us % 1000000) ||
|
|
|
|
(0 != GNUNET_TIME_absolute_ntoh (
|
|
|
|
dki->issue.properties.expire_legal).abs_value_us % 1000000) ||
|
|
|
|
(0 != GNUNET_TIME_absolute_ntoh (
|
|
|
|
dki->issue.properties.expire_deposit).abs_value_us % 1000000) )
|
2015-06-20 22:22:59 +02:00
|
|
|
{
|
|
|
|
fprintf (stderr,
|
|
|
|
"Timestamps are not multiples of a round second\n");
|
|
|
|
return GNUNET_SYSERR;
|
|
|
|
}
|
|
|
|
|
2015-01-09 18:18:59 +01:00
|
|
|
if (GNUNET_OK !=
|
2019-08-25 16:18:24 +02:00
|
|
|
GNUNET_CRYPTO_eddsa_verify (
|
|
|
|
TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY,
|
|
|
|
&dki->issue.properties.purpose,
|
|
|
|
&dki->issue.signature.eddsa_signature,
|
|
|
|
&dki->issue.properties.master.eddsa_pub))
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
2015-03-15 21:10:05 +01:00
|
|
|
fprintf (stderr,
|
|
|
|
"Denomination key for `%s' has invalid signature\n",
|
|
|
|
alias);
|
2015-01-08 18:37:20 +01:00
|
|
|
return GNUNET_SYSERR;
|
|
|
|
}
|
2015-03-22 22:14:30 +01:00
|
|
|
GNUNET_CRYPTO_rsa_public_key_hash (dki->denom_pub.rsa_public_key,
|
2015-03-15 21:10:05 +01:00
|
|
|
&hc);
|
2019-04-17 20:13:14 +02:00
|
|
|
if (0 != GNUNET_memcmp (&hc,
|
|
|
|
&dki->issue.properties.denom_hash))
|
2015-03-15 21:10:05 +01:00
|
|
|
{
|
|
|
|
fprintf (stderr,
|
|
|
|
"Public key for `%s' does not match signature\n",
|
|
|
|
alias);
|
|
|
|
return GNUNET_SYSERR;
|
|
|
|
}
|
2020-03-07 12:58:40 +01:00
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
|
|
|
"Denomination key `%s' (%s) is valid\n",
|
|
|
|
alias,
|
|
|
|
GNUNET_h2s (&hc));
|
2020-03-18 13:58:40 +01:00
|
|
|
TALER_amount_ntoh (&value,
|
|
|
|
&dki->issue.properties.value);
|
|
|
|
if ( (GNUNET_OK ==
|
|
|
|
TALER_amount_cmp_currency (&print_dk_amount,
|
|
|
|
&value)) &&
|
|
|
|
(0 ==
|
|
|
|
TALER_amount_cmp (&print_dk_amount,
|
|
|
|
&value)) )
|
|
|
|
{
|
|
|
|
char *dh;
|
|
|
|
struct GNUNET_TIME_Absolute start;
|
|
|
|
|
|
|
|
start = GNUNET_TIME_absolute_ntoh (dki->issue.properties.start);
|
|
|
|
dh = GNUNET_STRINGS_data_to_string_alloc (&dki->issue.properties.denom_hash,
|
|
|
|
sizeof (struct GNUNET_HashCode));
|
|
|
|
/* output start time first for easy numeric sorting, then
|
|
|
|
the denomination hash, and finally the human-readable start time */
|
|
|
|
printf ("%020llu %s %s\n",
|
|
|
|
(unsigned long long) start.abs_value_us,
|
|
|
|
dh,
|
|
|
|
GNUNET_STRINGS_absolute_time_to_string (start));
|
|
|
|
GNUNET_free (dh);
|
|
|
|
}
|
2015-01-08 18:37:20 +01:00
|
|
|
return GNUNET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-15 21:10:05 +01:00
|
|
|
/**
|
|
|
|
* Check denomination keys.
|
|
|
|
*
|
|
|
|
* @return #GNUNET_OK if the keys are OK
|
|
|
|
* #GNUNET_NO if not
|
|
|
|
*/
|
2015-01-08 18:37:20 +01:00
|
|
|
static int
|
2016-03-01 15:35:04 +01:00
|
|
|
exchange_denomkeys_check ()
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
2017-04-07 22:37:00 +02:00
|
|
|
struct TALER_MasterPublicKeyP master_public_key_from_cfg;
|
|
|
|
|
|
|
|
if (GNUNET_OK !=
|
|
|
|
GNUNET_CONFIGURATION_get_data (kcfg,
|
|
|
|
"exchange",
|
|
|
|
"master_public_key",
|
|
|
|
&master_public_key_from_cfg,
|
2019-08-25 16:18:24 +02:00
|
|
|
sizeof (struct
|
|
|
|
GNUNET_CRYPTO_EddsaPublicKey)))
|
2017-04-07 22:37:00 +02:00
|
|
|
{
|
|
|
|
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"exchange",
|
|
|
|
"master_public_key");
|
|
|
|
return GNUNET_NO;
|
|
|
|
}
|
2016-03-01 15:35:04 +01:00
|
|
|
if (0 > TALER_EXCHANGEDB_denomination_keys_iterate (exchange_directory,
|
2016-04-10 17:10:20 +02:00
|
|
|
&denomkeys_iter,
|
|
|
|
NULL))
|
2015-01-08 18:37:20 +01:00
|
|
|
return GNUNET_NO;
|
|
|
|
return GNUNET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-16 13:57:22 +02:00
|
|
|
/**
|
|
|
|
* Main function that will be run.
|
|
|
|
*
|
|
|
|
* @param cls closure
|
|
|
|
* @param args remaining command-line arguments
|
|
|
|
* @param cfgfile name of the configuration file used (for saving, can be NULL!)
|
|
|
|
* @param cfg configuration
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
run (void *cls,
|
|
|
|
char *const *args,
|
|
|
|
const char *cfgfile,
|
|
|
|
const struct GNUNET_CONFIGURATION_Handle *cfg)
|
|
|
|
{
|
2019-11-01 14:34:34 +01:00
|
|
|
(void) cls;
|
|
|
|
(void) args;
|
|
|
|
(void) cfgfile;
|
2016-04-16 13:57:22 +02:00
|
|
|
kcfg = cfg;
|
|
|
|
if (GNUNET_OK !=
|
|
|
|
GNUNET_CONFIGURATION_get_value_filename (kcfg,
|
|
|
|
"exchange",
|
|
|
|
"KEYDIR",
|
|
|
|
&exchange_directory))
|
|
|
|
{
|
|
|
|
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"exchange",
|
|
|
|
"KEYDIR");
|
|
|
|
global_ret = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( (GNUNET_OK != exchange_signkeys_check ()) ||
|
|
|
|
(GNUNET_OK != exchange_denomkeys_check ()) )
|
|
|
|
{
|
|
|
|
global_ret = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-08 18:37:20 +01:00
|
|
|
/**
|
|
|
|
* The main function of the keyup tool
|
|
|
|
*
|
|
|
|
* @param argc number of arguments from the command line
|
|
|
|
* @param argv command line arguments
|
|
|
|
* @return 0 ok, 1 on error
|
|
|
|
*/
|
|
|
|
int
|
2020-03-07 12:58:40 +01:00
|
|
|
main (int argc,
|
|
|
|
char *const *argv)
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
2016-04-10 17:10:20 +02:00
|
|
|
const struct GNUNET_GETOPT_CommandLineOption options[] = {
|
2020-03-18 13:58:40 +01:00
|
|
|
TALER_getopt_get_amount ('i',
|
|
|
|
"denomination-info-hash",
|
|
|
|
"AMOUNT",
|
|
|
|
"print full denomination hashes of all denominations with the given AMOUNT value",
|
|
|
|
&print_dk_amount),
|
2015-01-08 18:37:20 +01:00
|
|
|
GNUNET_GETOPT_OPTION_END
|
|
|
|
};
|
|
|
|
|
2020-03-07 12:58:40 +01:00
|
|
|
/* force linker to link against libtalerutil; if we do
|
|
|
|
not do this, the linker may "optimize" libtalerutil
|
|
|
|
away and skip #TALER_OS_init(), which we do need */
|
|
|
|
(void) TALER_project_data_default ();
|
2015-03-15 21:10:05 +01:00
|
|
|
GNUNET_assert (GNUNET_OK ==
|
2016-03-01 15:35:04 +01:00
|
|
|
GNUNET_log_setup ("taler-exchange-keycheck",
|
2015-03-15 21:10:05 +01:00
|
|
|
"WARNING",
|
|
|
|
NULL));
|
2016-04-10 17:10:20 +02:00
|
|
|
if (GNUNET_OK !=
|
2016-04-16 13:57:22 +02:00
|
|
|
GNUNET_PROGRAM_run (argc, argv,
|
|
|
|
"taler-exchange-keycheck",
|
2019-08-25 16:18:24 +02:00
|
|
|
"Check keys of the exchange for validity",
|
|
|
|
options,
|
|
|
|
&run, NULL))
|
2015-01-08 18:37:20 +01:00
|
|
|
return 1;
|
2016-04-16 13:57:22 +02:00
|
|
|
return global_ret;
|
2016-04-10 17:10:20 +02:00
|
|
|
|
2015-01-08 18:37:20 +01:00
|
|
|
}
|
2015-03-15 21:10:05 +01:00
|
|
|
|
2019-10-31 12:59:50 +01:00
|
|
|
|
2016-03-01 15:35:04 +01:00
|
|
|
/* end of taler-exchange-keycheck.c */
|