LCOV - code coverage report
Current view: top level - exchange-tools - taler-exchange-keyup.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 297 407 73.0 %
Date: 2017-09-17 17:24:28 Functions: 18 18 100.0 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2017 GNUnet e.V.
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU General Public License as published by the Free Software
       7             :   Foundation; either version 3, or (at your option) any later version.
       8             : 
       9             :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10             :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11             :   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU General Public License along with
      14             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : /**
      17             :  * @file taler-exchange-keyup.c
      18             :  * @brief Update the exchange's keys for coins and signatures,
      19             :  *        using the exchange's offline master key.
      20             :  * @author Florian Dold
      21             :  * @author Benedikt Mueller
      22             :  * @author Christian Grothoff
      23             :  */
      24             : #include <platform.h>
      25             : #include "taler_exchangedb_lib.h"
      26             : #include "taler_wire_lib.h"
      27             : 
      28             : /**
      29             :  * When generating filenames from a cryptographic hash, we do not use
      30             :  * all 512 bits but cut off after this number of characters (in
      31             :  * base32-encoding).  Base32 is 5 bit per character, and given that we
      32             :  * have very few coin types we hash, at 100 bits the chance of
      33             :  * collision (by accident over tiny set -- birthday paradox does not
      34             :  * apply here!) is negligible.
      35             :  */
      36             : #define HASH_CUTOFF 20
      37             : 
      38             : 
      39             : GNUNET_NETWORK_STRUCT_BEGIN
      40             : 
      41             : /**
      42             :  * Struct with all of the key information for a kind of coin.  Hashed
      43             :  * to generate a unique directory name per coin type.
      44             :  */
      45             : struct CoinTypeNBOP
      46             : {
      47             :   /**
      48             :    * How long are the signatures legally valid?
      49             :    */
      50             :   struct GNUNET_TIME_RelativeNBO duration_legal;
      51             : 
      52             :   /**
      53             :    * How long can the coin be spend?
      54             :    */
      55             :   struct GNUNET_TIME_RelativeNBO duration_spend;
      56             : 
      57             :   /**
      58             :    * How long can the coin be withdrawn (generated)?
      59             :    */
      60             :   struct GNUNET_TIME_RelativeNBO duration_withdraw;
      61             : 
      62             :   /**
      63             :    * What is the value of the coin?
      64             :    */
      65             :   struct TALER_AmountNBO value;
      66             : 
      67             :   /**
      68             :    * What is the fee charged for withdrawl?
      69             :    */
      70             :   struct TALER_AmountNBO fee_withdraw;
      71             : 
      72             :   /**
      73             :    * What is the fee charged for deposits?
      74             :    */
      75             :   struct TALER_AmountNBO fee_deposit;
      76             : 
      77             :   /**
      78             :    * What is the fee charged for melting?
      79             :    */
      80             :   struct TALER_AmountNBO fee_refresh;
      81             : 
      82             :   /**
      83             :    * What is the fee charged for refunds?
      84             :    */
      85             :   struct TALER_AmountNBO fee_refund;
      86             : 
      87             :   /**
      88             :    * Key size in NBO.
      89             :    */
      90             :   uint32_t rsa_keysize;
      91             : };
      92             : 
      93             : GNUNET_NETWORK_STRUCT_END
      94             : 
      95             : /**
      96             :  * Set of all of the parameters that chracterize a coin.
      97             :  */
      98             : struct CoinTypeParams
      99             : {
     100             : 
     101             :   /**
     102             :    * How long are the signatures legally valid?  Should be
     103             :    * significantly larger than @e duration_spend (i.e. years).
     104             :    */
     105             :   struct GNUNET_TIME_Relative duration_legal;
     106             : 
     107             : 
     108             :   /**
     109             :    * How long can the coin be spend?  Should be significantly
     110             :    * larger than @e duration_withdraw (i.e. years).
     111             :    */
     112             :   struct GNUNET_TIME_Relative duration_spend;
     113             : 
     114             :   /**
     115             :    * How long can the coin be withdrawn (generated)?  Should be small
     116             :    * enough to limit how many coins will be signed into existence with
     117             :    * the same key, but large enough to still provide a reasonable
     118             :    * anonymity set.
     119             :    */
     120             :   struct GNUNET_TIME_Relative duration_withdraw;
     121             : 
     122             :   /**
     123             :    * How much should coin creation (@e duration_withdraw) duration
     124             :    * overlap with the next coin?  Basically, the starting time of two
     125             :    * coins is always @e duration_withdraw - @e duration_overlap apart.
     126             :    */
     127             :   struct GNUNET_TIME_Relative duration_overlap;
     128             : 
     129             :   /**
     130             :    * What is the value of the coin?
     131             :    */
     132             :   struct TALER_Amount value;
     133             : 
     134             :   /**
     135             :    * What is the fee charged for withdrawl?
     136             :    */
     137             :   struct TALER_Amount fee_withdraw;
     138             : 
     139             :   /**
     140             :    * What is the fee charged for deposits?
     141             :    */
     142             :   struct TALER_Amount fee_deposit;
     143             : 
     144             :   /**
     145             :    * What is the fee charged for melting?
     146             :    */
     147             :   struct TALER_Amount fee_refresh;
     148             : 
     149             :   /**
     150             :    * What is the fee charged for refunds?
     151             :    */
     152             :   struct TALER_Amount fee_refund;
     153             : 
     154             :   /**
     155             :    * Time at which this coin is supposed to become valid.
     156             :    */
     157             :   struct GNUNET_TIME_Absolute anchor;
     158             : 
     159             :   /**
     160             :    * Length of the RSA key in bits.
     161             :    */
     162             :   uint32_t rsa_keysize;
     163             : };
     164             : 
     165             : 
     166             : /**
     167             :  * Filename of the master private key.
     168             :  */
     169             : static char *masterkeyfile;
     170             : 
     171             : /**
     172             :  * Filename where to write denomination key signing
     173             :  * requests for the auditor (optional, can be NULL).
     174             :  */
     175             : static char *auditorrequestfile;
     176             : 
     177             : /**
     178             :  * Handle for writing the output for the auditor.
     179             :  */
     180             : static FILE *auditor_output_file;
     181             : 
     182             : /**
     183             :  * Director of the exchange, containing the keys.
     184             :  */
     185             : static char *exchange_directory;
     186             : 
     187             : /**
     188             :  * Directory where we should write the wire transfer fee structure.
     189             :  */
     190             : static char *feedir;
     191             : 
     192             : /**
     193             :  * Handle to the exchange's configuration
     194             :  */
     195             : static const struct GNUNET_CONFIGURATION_Handle *kcfg;
     196             : 
     197             : /**
     198             :  * Time when the key update is executed.  Either the actual current time, or a
     199             :  * pretended time.
     200             :  */
     201             : static struct GNUNET_TIME_Absolute now;
     202             : 
     203             : /**
     204             :  * Master private key of the exchange.
     205             :  */
     206             : static struct TALER_MasterPrivateKeyP master_priv;
     207             : 
     208             : /**
     209             :  * Master public key of the exchange.
     210             :  */
     211             : static struct TALER_MasterPublicKeyP master_public_key;
     212             : 
     213             : /**
     214             :  * Until what time do we provide keys?
     215             :  */
     216             : static struct GNUNET_TIME_Absolute lookahead_sign_stamp;
     217             : 
     218             : /**
     219             :  * Largest duration for spending of any key.
     220             :  */
     221             : static struct GNUNET_TIME_Relative max_duration_spend;
     222             : 
     223             : /**
     224             :  * Revoke denomination key identified by this hash (if non-zero).
     225             :  */
     226             : static struct GNUNET_HashCode revoke_dkh;
     227             : 
     228             : /**
     229             :  * Return value from main().
     230             :  */
     231             : static int global_ret;
     232             : 
     233             : 
     234             : /**
     235             :  * Hash the data defining the coin type.  Exclude information that may
     236             :  * not be the same for all instances of the coin type (i.e. the
     237             :  * anchor, overlap).
     238             :  *
     239             :  * @param p coin parameters to convert to a hash
     240             :  * @param[out] hash set to the hash matching @a p
     241             :  */
     242             : static void
     243         156 : hash_coin_type (const struct CoinTypeParams *p,
     244             :                 struct GNUNET_HashCode *hash)
     245             : {
     246             :   struct CoinTypeNBOP p_nbo;
     247             : 
     248         156 :   memset (&p_nbo,
     249             :           0,
     250             :           sizeof (struct CoinTypeNBOP));
     251         156 :   p_nbo.duration_spend = GNUNET_TIME_relative_hton (p->duration_spend);
     252         156 :   p_nbo.duration_legal = GNUNET_TIME_relative_hton (p->duration_legal);
     253         156 :   p_nbo.duration_withdraw = GNUNET_TIME_relative_hton (p->duration_withdraw);
     254         156 :   TALER_amount_hton (&p_nbo.value,
     255             :                      &p->value);
     256         156 :   TALER_amount_hton (&p_nbo.fee_withdraw,
     257             :                      &p->fee_withdraw);
     258         156 :   TALER_amount_hton (&p_nbo.fee_deposit,
     259             :                      &p->fee_deposit);
     260         156 :   TALER_amount_hton (&p_nbo.fee_refresh,
     261             :                      &p->fee_refresh);
     262         156 :   TALER_amount_hton (&p_nbo.fee_refund,
     263             :                      &p->fee_refund);
     264         156 :   p_nbo.rsa_keysize = htonl (p->rsa_keysize);
     265         156 :   GNUNET_CRYPTO_hash (&p_nbo,
     266             :                       sizeof (struct CoinTypeNBOP),
     267             :                       hash);
     268         156 : }
     269             : 
     270             : 
     271             : /**
     272             :  * Obtain the name of the directory we should use to store coins of
     273             :  * the given type.  The directory name has the format
     274             :  * "$EXCHANGEDIR/$VALUE/$HASH/" where "$VALUE" represents the value of the
     275             :  * coin and "$HASH" encodes all of the coin's parameters, generating a
     276             :  * unique string for each type of coin.  Note that the "$HASH"
     277             :  * includes neither the absolute creation time nor the key of the
     278             :  * coin, thus the files in the subdirectory really just refer to the
     279             :  * same type of coins, not the same coin.
     280             :  *
     281             :  * @param p coin parameters to convert to a directory name
     282             :  * @return directory name (valid until next call to this function)
     283             :  */
     284             : static const char *
     285         156 : get_cointype_dir (const struct CoinTypeParams *p)
     286             : {
     287             :   static char dir[4096];
     288             :   struct GNUNET_HashCode hash;
     289             :   char *hash_str;
     290             :   char *val_str;
     291             :   size_t i;
     292             : 
     293         156 :   hash_coin_type (p, &hash);
     294         156 :   hash_str = GNUNET_STRINGS_data_to_string_alloc (&hash,
     295             :                                                   sizeof (struct GNUNET_HashCode));
     296         156 :   GNUNET_assert (NULL != hash_str);
     297         156 :   GNUNET_assert (HASH_CUTOFF <= strlen (hash_str) + 1);
     298         156 :   hash_str[HASH_CUTOFF] = 0;
     299             : 
     300         156 :   val_str = TALER_amount_to_string (&p->value);
     301        1201 :   for (i = 0; i < strlen (val_str); i++)
     302        1934 :     if ( (':' == val_str[i]) ||
     303         889 :          ('.' == val_str[i]) )
     304         256 :       val_str[i] = '_';
     305             : 
     306         156 :   GNUNET_snprintf (dir,
     307             :                    sizeof (dir),
     308             :                    "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS DIR_SEPARATOR_STR "%s-%s",
     309             :                    exchange_directory,
     310             :                    val_str,
     311             :                    hash_str);
     312         156 :   GNUNET_free (hash_str);
     313         156 :   GNUNET_free (val_str);
     314         156 :   return dir;
     315             : }
     316             : 
     317             : 
     318             : /**
     319             :  * Obtain the name of the file we would use to store the key
     320             :  * information for a coin of the given type @a p and validity
     321             :  * start time @a start
     322             :  *
     323             :  * @param p parameters for the coin
     324             :  * @param start when would the coin begin to be issued
     325             :  * @return name of the file to use for this coin
     326             :  *         (valid until next call to this function)
     327             :  */
     328             : static const char *
     329         112 : get_cointype_file (const struct CoinTypeParams *p,
     330             :                    struct GNUNET_TIME_Absolute start)
     331             : {
     332             :   static char filename[4096];
     333             :   const char *dir;
     334             : 
     335         112 :   dir = get_cointype_dir (p);
     336         112 :   GNUNET_snprintf (filename,
     337             :                    sizeof (filename),
     338             :                    "%s" DIR_SEPARATOR_STR "%llu",
     339             :                    dir,
     340         112 :                    (unsigned long long) start.abs_value_us);
     341         112 :   return filename;
     342             : }
     343             : 
     344             : 
     345             : /**
     346             :  * Get the latest key file from a past run of the key generation
     347             :  * tool.  Used to calculate the starting time for the keys we
     348             :  * generate during this invocation.  This function is used to
     349             :  * handle both signing keys and coin keys, as in both cases
     350             :  * the filenames correspond to the timestamps we need.
     351             :  *
     352             :  * @param cls closure, a `struct GNUNET_TIME_Absolute *`, updated
     353             :  *                     to contain the highest timestamp (below #now)
     354             :  *                     that was found
     355             :  * @param filename complete filename (absolute path)
     356             :  * @return #GNUNET_OK (to continue to iterate)
     357             :  */
     358             : static int
     359          36 : get_anchor_iter (void *cls,
     360             :                  const char *filename)
     361             : {
     362          36 :   struct GNUNET_TIME_Absolute *anchor = cls;
     363             :   struct GNUNET_TIME_Absolute stamp;
     364             :   const char *base;
     365          36 :   char *end = NULL;
     366             : 
     367          36 :   base = GNUNET_STRINGS_get_short_name (filename);
     368          36 :   stamp.abs_value_us = strtoll (base,
     369             :                                 &end,
     370             :                                 10);
     371          36 :   if ((NULL == end) || (0 != *end))
     372             :   {
     373           1 :     fprintf(stderr,
     374             :             "Ignoring unexpected file `%s'.\n",
     375             :             filename);
     376           1 :     return GNUNET_OK;
     377             :   }
     378          35 :   *anchor = GNUNET_TIME_absolute_max (stamp,
     379             :                                       *anchor);
     380          35 :   return GNUNET_OK;
     381             : }
     382             : 
     383             : 
     384             : /**
     385             :  * Get the timestamp where the first new key should be generated.
     386             :  * Relies on correctly named key files (as we do not parse them,
     387             :  * but just look at the filenames to "guess" at their contents).
     388             :  *
     389             :  * @param dir directory that should contain the existing keys
     390             :  * @param duration how long is one key valid (for signing)?
     391             :  * @param overlap what's the overlap between the keys validity period?
     392             :  * @param[out] anchor the timestamp where the first new key should be generated
     393             :  */
     394             : static void
     395          30 : get_anchor (const char *dir,
     396             :             struct GNUNET_TIME_Relative duration,
     397             :             struct GNUNET_TIME_Relative overlap,
     398             :             struct GNUNET_TIME_Absolute *anchor)
     399             : {
     400          30 :   GNUNET_assert (0 == duration.rel_value_us % 1000000);
     401          30 :   GNUNET_assert (0 == overlap.rel_value_us % 1000000);
     402          30 :   if (GNUNET_YES !=
     403          30 :       GNUNET_DISK_directory_test (dir,
     404             :                                   GNUNET_YES))
     405             :   {
     406          10 :     *anchor = now;
     407          10 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     408             :                 "No existing keys found, starting with fresh key set.\n");
     409          10 :     return;
     410             :   }
     411          20 :   *anchor = GNUNET_TIME_UNIT_ZERO_ABS;
     412          20 :   if (-1 ==
     413          20 :       GNUNET_DISK_directory_scan (dir,
     414             :                                   &get_anchor_iter,
     415             :                                   anchor))
     416             :   {
     417           0 :     *anchor = now;
     418           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     419             :                 "No existing keys found, starting with fresh key set.\n");
     420           0 :     return;
     421             :   }
     422             : 
     423          40 :   if ((GNUNET_TIME_absolute_add (*anchor,
     424          20 :                                  duration)).abs_value_us < now.abs_value_us)
     425             :   {
     426           3 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     427             :                 "Existing keys are way too old, starting with fresh key set.\n");
     428           3 :     *anchor = now;
     429             :   }
     430          17 :   else if (anchor->abs_value_us != now.abs_value_us)
     431             :   {
     432             :     /* Real starting time is the last start time + duration - overlap */
     433          17 :     *anchor = GNUNET_TIME_absolute_add (*anchor,
     434             :                                         duration);
     435          17 :     *anchor = GNUNET_TIME_absolute_subtract (*anchor,
     436             :                                              overlap);
     437             :   }
     438             :   /* anchor is now the stamp where we need to create a new key */
     439             : }
     440             : 
     441             : 
     442             : /**
     443             :  * Create a exchange signing key (for signing exchange messages, not for coins)
     444             :  * and assert its correctness by signing it with the master key.
     445             :  *
     446             :  * @param start start time of the validity period for the key
     447             :  * @param duration how long should the key be valid
     448             :  * @param end when do all signatures by this key expire
     449             :  * @param[out] pi set to the signing key information
     450             :  */
     451             : static void
     452          11 : create_signkey_issue_priv (struct GNUNET_TIME_Absolute start,
     453             :                            struct GNUNET_TIME_Relative duration,
     454             :                            struct GNUNET_TIME_Absolute end,
     455             :                            struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP *pi)
     456             : {
     457             :   struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
     458          11 :   struct TALER_ExchangeSigningKeyValidityPS *issue = &pi->issue;
     459             : 
     460          11 :   priv = GNUNET_CRYPTO_eddsa_key_create ();
     461          11 :   pi->signkey_priv.eddsa_priv = *priv;
     462          11 :   GNUNET_free (priv);
     463          11 :   issue->master_public_key = master_public_key;
     464          11 :   issue->start = GNUNET_TIME_absolute_hton (start);
     465          11 :   issue->expire = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (start,
     466             :                                                                        duration));
     467          11 :   issue->end = GNUNET_TIME_absolute_hton (end);
     468          11 :   GNUNET_CRYPTO_eddsa_key_get_public (&pi->signkey_priv.eddsa_priv,
     469             :                                       &issue->signkey_pub.eddsa_pub);
     470          11 :   issue->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY);
     471          11 :   issue->purpose.size = htonl (sizeof (struct TALER_ExchangeSigningKeyValidityPS) -
     472             :                                offsetof (struct TALER_ExchangeSigningKeyValidityPS,
     473             :                                          purpose));
     474             : 
     475          11 :   GNUNET_assert (GNUNET_OK ==
     476             :                  GNUNET_CRYPTO_eddsa_sign (&master_priv.eddsa_priv,
     477             :                                            &issue->purpose,
     478             :                                            &issue->signature.eddsa_signature));
     479          11 : }
     480             : 
     481             : 
     482             : /**
     483             :  * Generate signing keys starting from the last key found to
     484             :  * the lookahead time.
     485             :  *
     486             :  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
     487             :  */
     488             : static int
     489           8 : exchange_keys_update_signkeys ()
     490             : {
     491             :   struct GNUNET_TIME_Relative signkey_duration;
     492             :   struct GNUNET_TIME_Relative legal_duration;
     493             :   struct GNUNET_TIME_Absolute anchor;
     494             :   char *signkey_dir;
     495             : 
     496           8 :   if (GNUNET_OK !=
     497           8 :       GNUNET_CONFIGURATION_get_value_time (kcfg,
     498             :                                            "exchange_keys",
     499             :                                            "signkey_duration",
     500             :                                            &signkey_duration))
     501             :   {
     502           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     503             :                                "exchange_keys",
     504             :                                "signkey_duration");
     505           0 :     return GNUNET_SYSERR;
     506             :   }
     507           8 :   if (GNUNET_OK !=
     508           8 :       GNUNET_CONFIGURATION_get_value_time (kcfg,
     509             :                                            "exchange_keys",
     510             :                                            "legal_duration",
     511             :                                            &legal_duration))
     512             :   {
     513           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     514             :                                "exchange_keys",
     515             :                                "legal_duration",
     516             :                                "fails to specify valid timeframe");
     517           0 :     return GNUNET_SYSERR;
     518             :   }
     519           8 :   if (signkey_duration.rel_value_us > legal_duration.rel_value_us)
     520             :   {
     521           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     522             :                                "exchange_keys",
     523             :                                "legal_duration",
     524             :                                "must be longer than signkey_duration");
     525           0 :     return GNUNET_SYSERR;
     526             :   }
     527           8 :   GNUNET_TIME_round_rel (&signkey_duration);
     528           8 :   GNUNET_asprintf (&signkey_dir,
     529             :                    "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_SIGNING_KEYS,
     530             :                    exchange_directory);
     531             :   /* make sure the directory exists */
     532           8 :   if (GNUNET_OK !=
     533           8 :       GNUNET_DISK_directory_create (signkey_dir))
     534             :   {
     535           0 :     fprintf (stderr,
     536             :              "Failed to create signing key directory\n");
     537           0 :     GNUNET_free (signkey_dir);
     538           0 :     return GNUNET_SYSERR;
     539             :   }
     540             : 
     541           8 :   get_anchor (signkey_dir,
     542             :               signkey_duration,
     543             :               GNUNET_TIME_UNIT_ZERO /* no overlap for signing keys */,
     544             :               &anchor);
     545           8 :   GNUNET_free (signkey_dir);
     546             : 
     547          27 :   while (anchor.abs_value_us < lookahead_sign_stamp.abs_value_us)
     548             :   {
     549             :     struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP signkey_issue;
     550             :     struct GNUNET_TIME_Absolute end;
     551             : 
     552          11 :     end = GNUNET_TIME_absolute_add (anchor,
     553             :                                     legal_duration);
     554          11 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     555             :                 "Generating signing key for %s.\n",
     556             :                 GNUNET_STRINGS_absolute_time_to_string (anchor));
     557          11 :     create_signkey_issue_priv (anchor,
     558             :                                signkey_duration,
     559             :                                end,
     560             :                                &signkey_issue);
     561          11 :     if (GNUNET_OK !=
     562          11 :         TALER_EXCHANGEDB_signing_key_write (exchange_directory,
     563             :                                             anchor,
     564             :                                             &signkey_issue))
     565           0 :       return GNUNET_SYSERR;
     566          11 :     anchor = GNUNET_TIME_absolute_add (anchor,
     567             :                                        signkey_duration);
     568             :   }
     569           8 :   return GNUNET_OK;
     570             : }
     571             : 
     572             : 
     573             : /**
     574             :  * Parse configuration for coin type parameters.  Also determines
     575             :  * our anchor by looking at the existing coins of the same type.
     576             :  *
     577             :  * @param ct section in the configuration file giving the coin type parameters
     578             :  * @param[out] params set to the coin parameters from the configuration
     579             :  * @return #GNUNET_OK on success, #GNUNET_SYSERR if the configuration is invalid
     580             :  */
     581             : static int
     582          22 : get_cointype_params (const char *ct,
     583             :                      struct CoinTypeParams *params)
     584             : {
     585             :   const char *dir;
     586             :   unsigned long long rsa_keysize;
     587             : 
     588          22 :   if (GNUNET_OK !=
     589          22 :       GNUNET_CONFIGURATION_get_value_time (kcfg,
     590             :                                            ct,
     591             :                                            "duration_withdraw",
     592             :                                            &params->duration_withdraw))
     593             :   {
     594           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     595             :                                ct,
     596             :                                "duration_withdraw");
     597           0 :     return GNUNET_SYSERR;
     598             :   }
     599          22 :   GNUNET_TIME_round_rel (&params->duration_withdraw);
     600          22 :   if (GNUNET_OK !=
     601          22 :       GNUNET_CONFIGURATION_get_value_time (kcfg,
     602             :                                            ct,
     603             :                                            "duration_spend",
     604             :                                            &params->duration_spend))
     605             :   {
     606           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     607             :                                ct,
     608             :                                "duration_spend");
     609           0 :     return GNUNET_SYSERR;
     610             :   }
     611          22 :   GNUNET_TIME_round_rel (&params->duration_spend);
     612          22 :   max_duration_spend = GNUNET_TIME_relative_max (max_duration_spend,
     613             :                                                  params->duration_spend);
     614          22 :   if (GNUNET_OK !=
     615          22 :       GNUNET_CONFIGURATION_get_value_time (kcfg,
     616             :                                            ct,
     617             :                                            "duration_legal",
     618             :                                            &params->duration_legal))
     619             :   {
     620           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     621             :                                ct,
     622             :                                "duration_legal");
     623           0 :     return GNUNET_SYSERR;
     624             :   }
     625          22 :   GNUNET_TIME_round_rel (&params->duration_legal);
     626          22 :   if (GNUNET_OK !=
     627          22 :       GNUNET_CONFIGURATION_get_value_time (kcfg,
     628             :                                            ct,
     629             :                                            "duration_overlap",
     630             :                                            &params->duration_overlap))
     631             :   {
     632           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     633             :                                ct,
     634             :                                "exchange_denom_duration_overlap");
     635           0 :     return GNUNET_SYSERR;
     636             :   }
     637          22 :   GNUNET_TIME_round_rel (&params->duration_overlap);
     638          22 :   if (GNUNET_OK !=
     639          22 :       GNUNET_CONFIGURATION_get_value_number (kcfg,
     640             :                                              ct,
     641             :                                              "rsa_keysize",
     642             :                                              &rsa_keysize))
     643             :   {
     644           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     645             :                                ct,
     646             :                                "rsa_keysize");
     647           0 :     return GNUNET_SYSERR;
     648             :   }
     649          44 :   if ( (rsa_keysize > 4 * 2048) ||
     650          22 :        (rsa_keysize < 1024) )
     651             :   {
     652           0 :     fprintf (stderr,
     653             :              "Given RSA keysize %llu outside of permitted range\n",
     654             :              rsa_keysize);
     655           0 :     return GNUNET_SYSERR;
     656             :   }
     657          22 :   params->rsa_keysize = (unsigned int) rsa_keysize;
     658          22 :   if (GNUNET_OK !=
     659          22 :       TALER_config_get_denom (kcfg,
     660             :                               ct,
     661             :                               "value",
     662             :                               &params->value))
     663             :   {
     664           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     665             :                                ct,
     666             :                                "value");
     667           0 :     return GNUNET_SYSERR;
     668             :   }
     669          22 :   if (GNUNET_OK !=
     670          22 :       TALER_config_get_denom (kcfg,
     671             :                               ct,
     672             :                               "fee_withdraw",
     673             :                               &params->fee_withdraw))
     674             :   {
     675           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     676             :                                ct,
     677             :                                "fee_withdraw");
     678           0 :     return GNUNET_SYSERR;
     679             :   }
     680          22 :   if (GNUNET_OK !=
     681          22 :       TALER_config_get_denom (kcfg,
     682             :                               ct,
     683             :                               "fee_deposit",
     684             :                               &params->fee_deposit))
     685             :   {
     686           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     687             :                                ct,
     688             :                                "fee_deposit");
     689           0 :     return GNUNET_SYSERR;
     690             :   }
     691          22 :   if (GNUNET_OK !=
     692          22 :       TALER_config_get_denom (kcfg,
     693             :                               ct,
     694             :                               "fee_refresh",
     695             :                               &params->fee_refresh))
     696             :   {
     697           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     698             :                                ct,
     699             :                                "fee_refresh");
     700           0 :     return GNUNET_SYSERR;
     701             :   }
     702          22 :   if (GNUNET_OK !=
     703          22 :       TALER_config_get_denom (kcfg,
     704             :                               ct,
     705             :                               "fee_refund",
     706             :                               &params->fee_refund))
     707             :   {
     708           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     709             :                                ct,
     710             :                                "fee_refund");
     711           0 :     return GNUNET_SYSERR;
     712             :   }
     713             : 
     714          22 :   dir = get_cointype_dir (params);
     715          22 :   get_anchor (dir,
     716             :               params->duration_withdraw,
     717             :               params->duration_overlap,
     718             :               &params->anchor);
     719          22 :   return GNUNET_OK;
     720             : }
     721             : 
     722             : 
     723             : /**
     724             :  * Initialize the private and public key information structure for
     725             :  * signing coins into existence.  Generates the private signing key
     726             :  * and signes it together with the coin's meta data using the master
     727             :  * signing key.
     728             :  *
     729             :  * @param params parameters used to initialize the @a dki
     730             :  * @param[out] dki initialized according to @a params
     731             :  */
     732             : static void
     733         112 : create_denomkey_issue (const struct CoinTypeParams *params,
     734             :                        struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
     735             : {
     736             :   dki->denom_priv.rsa_private_key
     737         112 :     = GNUNET_CRYPTO_rsa_private_key_create (params->rsa_keysize);
     738         112 :   GNUNET_assert (NULL != dki->denom_priv.rsa_private_key);
     739             :   dki->denom_pub.rsa_public_key
     740         112 :     = GNUNET_CRYPTO_rsa_private_key_get_public (dki->denom_priv.rsa_private_key);
     741         112 :   GNUNET_CRYPTO_rsa_public_key_hash (dki->denom_pub.rsa_public_key,
     742             :                                      &dki->issue.properties.denom_hash);
     743         112 :   dki->issue.properties.master = master_public_key;
     744         112 :   dki->issue.properties.start = GNUNET_TIME_absolute_hton (params->anchor);
     745         112 :   dki->issue.properties.expire_withdraw =
     746         112 :       GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor,
     747             :                                                            params->duration_withdraw));
     748         112 :   dki->issue.properties.expire_deposit =
     749         112 :     GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor,
     750             :                                                          params->duration_spend));
     751         112 :   dki->issue.properties.expire_legal =
     752         112 :     GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor,
     753             :                                                          params->duration_legal));
     754         112 :   TALER_amount_hton (&dki->issue.properties.value,
     755             :                      &params->value);
     756         112 :   TALER_amount_hton (&dki->issue.properties.fee_withdraw,
     757             :                      &params->fee_withdraw);
     758         112 :   TALER_amount_hton (&dki->issue.properties.fee_deposit,
     759             :                      &params->fee_deposit);
     760         112 :   TALER_amount_hton (&dki->issue.properties.fee_refresh,
     761             :                      &params->fee_refresh);
     762         112 :   TALER_amount_hton (&dki->issue.properties.fee_refund,
     763             :                      &params->fee_refund);
     764             :   dki->issue.properties.purpose.purpose
     765         112 :     = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY);
     766             :   dki->issue.properties.purpose.size
     767         112 :     = htonl (sizeof (struct TALER_DenominationKeyValidityPS));
     768         112 :   GNUNET_assert (GNUNET_OK ==
     769             :                  GNUNET_CRYPTO_eddsa_sign (&master_priv.eddsa_priv,
     770             :                                            &dki->issue.properties.purpose,
     771             :                                            &dki->issue.signature.eddsa_signature));
     772         112 : }
     773             : 
     774             : 
     775             : /**
     776             :  * Generate new coin signing keys for the coin type of the given @a
     777             :  * coin_alias.
     778             :  *
     779             :  * @param cls a `int *`, to be set to #GNUNET_SYSERR on failure
     780             :  * @param coin_alias name of the coin's section in the configuration
     781             :  */
     782             : static void
     783         182 : exchange_keys_update_cointype (void *cls,
     784             :                                const char *coin_alias)
     785             : {
     786         182 :   int *ret = cls;
     787             :   struct CoinTypeParams p;
     788             :   const char *dkf;
     789             :   struct TALER_EXCHANGEDB_DenominationKeyIssueInformation denomkey_issue;
     790             : 
     791         182 :   if (0 != strncasecmp (coin_alias,
     792             :                         "coin_",
     793             :                         strlen ("coin_")))
     794         320 :     return; /* not a coin definition */
     795          22 :   if (GNUNET_OK !=
     796          22 :       get_cointype_params (coin_alias,
     797             :                            &p))
     798             :   {
     799           0 :     *ret = GNUNET_SYSERR;
     800           0 :     return;
     801             :   }
     802          22 :   if (GNUNET_OK !=
     803          22 :       GNUNET_DISK_directory_create (get_cointype_dir (&p)))
     804             :   {
     805           0 :     *ret = GNUNET_SYSERR;
     806           0 :     return;
     807             :   }
     808             : 
     809         156 :   while (p.anchor.abs_value_us < lookahead_sign_stamp.abs_value_us)
     810             :   {
     811         112 :     dkf = get_cointype_file (&p,
     812             :                              p.anchor);
     813         112 :     GNUNET_break (GNUNET_YES != GNUNET_DISK_file_test (dkf));
     814         112 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     815             :                 "Generating denomination key for type `%s', start %s at %s\n",
     816             :                 coin_alias,
     817             :                 GNUNET_STRINGS_absolute_time_to_string (p.anchor),
     818             :                 dkf);
     819         112 :     create_denomkey_issue (&p,
     820             :                            &denomkey_issue);
     821         112 :     if (GNUNET_OK !=
     822         112 :         TALER_EXCHANGEDB_denomination_key_write (dkf,
     823             :                                                  &denomkey_issue))
     824             :     {
     825           0 :       fprintf (stderr,
     826             :                "Failed to write denomination key information to file `%s'.\n",
     827             :                dkf);
     828           0 :       *ret = GNUNET_SYSERR;
     829           0 :       GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key);
     830           0 :       GNUNET_CRYPTO_rsa_public_key_free (denomkey_issue.denom_pub.rsa_public_key);
     831           0 :       return;
     832             :     }
     833         125 :     if ( (NULL != auditor_output_file) &&
     834             :          (1 !=
     835          13 :           fwrite (&denomkey_issue.issue.properties,
     836             :                   sizeof (struct TALER_DenominationKeyValidityPS),
     837             :                   1,
     838             :                   auditor_output_file)) )
     839             :     {
     840           0 :       fprintf (stderr,
     841             :                "Failed to write denomination key information to %s: %s\n",
     842             :                auditorrequestfile,
     843           0 :                STRERROR (errno));
     844           0 :       *ret = GNUNET_SYSERR;
     845           0 :       GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key);
     846           0 :       GNUNET_CRYPTO_rsa_public_key_free (denomkey_issue.denom_pub.rsa_public_key);
     847           0 :       return;
     848             :     }
     849         112 :     GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key);
     850         112 :     GNUNET_CRYPTO_rsa_public_key_free (denomkey_issue.denom_pub.rsa_public_key);
     851         112 :     p.anchor = GNUNET_TIME_absolute_add (p.anchor,
     852             :                                          p.duration_withdraw);
     853         112 :     p.anchor = GNUNET_TIME_absolute_subtract (p.anchor,
     854             :                                               p.duration_overlap);
     855             :   }
     856             : }
     857             : 
     858             : 
     859             : /**
     860             :  * Update all of the denomination keys of the exchange.
     861             :  *
     862             :  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
     863             :  */
     864             : static int
     865           8 : exchange_keys_update_denomkeys ()
     866             : {
     867             :   int ok;
     868             : 
     869           8 :   ok = GNUNET_OK;
     870           8 :   GNUNET_CONFIGURATION_iterate_sections (kcfg,
     871             :                                          &exchange_keys_update_cointype,
     872             :                                          &ok);
     873           8 :   return ok;
     874             : }
     875             : 
     876             : 
     877             : /**
     878             :  * Sign @a af with @a priv
     879             :  *
     880             :  * @param[in,out] af fee structure to sign
     881             :  * @param wireplugin name of the plugin for which we sign
     882             :  * @param priv private key to use for signing
     883             :  */
     884             : static void
     885          26 : sign_af (struct TALER_EXCHANGEDB_AggregateFees *af,
     886             :          const char *wireplugin,
     887             :          const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
     888             : {
     889             :   struct TALER_MasterWireFeePS wf;
     890             : 
     891          26 :   TALER_EXCHANGEDB_fees_2_wf (wireplugin,
     892             :                               af,
     893             :                               &wf);
     894          26 :   GNUNET_assert (GNUNET_OK ==
     895             :                  GNUNET_CRYPTO_eddsa_sign (priv,
     896             :                                            &wf.purpose,
     897             :                                            &af->master_sig.eddsa_signature));
     898          26 : }
     899             : 
     900             : 
     901             : /**
     902             :  * Output the wire fee structure.  Must be run after #max_duration_spend
     903             :  * was initialized.
     904             :  *
     905             :  * @param cls pointer to `int`, set to #GNUNET_SYSERR on error
     906             :  * @param wiremethod method to write fees for
     907             :  */
     908             : static void
     909          13 : create_wire_fee_for_method (void *cls,
     910             :                             const char *wiremethod)
     911             : {
     912          13 :   int *ret = cls;
     913             :   struct TALER_EXCHANGEDB_AggregateFees *af_head;
     914             :   struct TALER_EXCHANGEDB_AggregateFees *af_tail;
     915             :   unsigned int year;
     916             :   struct GNUNET_TIME_Absolute last_date;
     917             :   struct GNUNET_TIME_Absolute start_date;
     918             :   struct GNUNET_TIME_Absolute end_date;
     919             :   char yearstr[12];
     920             :   char *fn;
     921             :   char *section;
     922             : 
     923          13 :   if (GNUNET_OK != *ret)
     924           0 :     return;
     925          13 :   last_date = GNUNET_TIME_absolute_add (lookahead_sign_stamp,
     926             :                                         max_duration_spend);
     927          13 :   GNUNET_asprintf (&section,
     928             :                    "exchange-wire-%s",
     929             :                    wiremethod);
     930          13 :   GNUNET_asprintf (&fn,
     931             :                    "%s%s.fee",
     932             :                    feedir,
     933             :                    wiremethod);
     934          13 :   af_head = NULL;
     935          13 :   af_tail = NULL;
     936          13 :   year = GNUNET_TIME_get_current_year ();
     937          13 :   start_date = GNUNET_TIME_year_to_time (year);
     938          13 :   while (start_date.abs_value_us < last_date.abs_value_us)
     939             :   {
     940             :     struct TALER_EXCHANGEDB_AggregateFees *af;
     941             :     char *opt;
     942             :     char *amounts;
     943             : 
     944          27 :     GNUNET_snprintf (yearstr,
     945             :                      sizeof (yearstr),
     946             :                      "%u",
     947             :                      year);
     948          27 :     end_date = GNUNET_TIME_year_to_time (year + 1);
     949          27 :     af = GNUNET_new (struct TALER_EXCHANGEDB_AggregateFees);
     950          27 :     af->start_date = start_date;
     951          27 :     af->end_date = end_date;
     952             : 
     953             :     /* handle wire fee */
     954          27 :     GNUNET_asprintf (&opt,
     955             :                      "wire-fee-%u",
     956             :                      year);
     957          27 :     if (GNUNET_OK !=
     958          27 :         GNUNET_CONFIGURATION_get_value_string (kcfg,
     959             :                                                section,
     960             :                                                opt,
     961             :                                                &amounts))
     962             :     {
     963           1 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     964             :                                  section,
     965             :                                  opt);
     966           1 :       *ret = GNUNET_SYSERR;
     967           1 :       GNUNET_free (opt);
     968           1 :       break;
     969             :     }
     970          26 :     if (GNUNET_OK !=
     971          26 :         TALER_string_to_amount (amounts,
     972             :                                 &af->wire_fee))
     973             :     {
     974           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     975             :                   "Invalid amount `%s' specified in `%s' under `%s'\n",
     976             :                   amounts,
     977             :                   wiremethod,
     978             :                   opt);
     979           0 :       *ret = GNUNET_SYSERR;
     980           0 :       GNUNET_free (amounts);
     981           0 :       GNUNET_free (opt);
     982           0 :       break;
     983             :     }
     984          26 :     GNUNET_free (amounts);
     985          26 :     GNUNET_free (opt);
     986             : 
     987             :     /* handle closing fee */
     988          26 :     GNUNET_asprintf (&opt,
     989             :                      "closing-fee-%u",
     990             :                      year);
     991          26 :     if (GNUNET_OK !=
     992          26 :         GNUNET_CONFIGURATION_get_value_string (kcfg,
     993             :                                                section,
     994             :                                                opt,
     995             :                                                &amounts))
     996             :     {
     997           0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     998             :                                  section,
     999             :                                  opt);
    1000           0 :       *ret = GNUNET_SYSERR;
    1001           0 :       GNUNET_free (opt);
    1002           0 :       break;
    1003             :     }
    1004          26 :     if (GNUNET_OK !=
    1005          26 :         TALER_string_to_amount (amounts,
    1006             :                                 &af->closing_fee))
    1007             :     {
    1008           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1009             :                   "Invalid amount `%s' specified in `%s' under `%s'\n",
    1010             :                   amounts,
    1011             :                   wiremethod,
    1012             :                   opt);
    1013           0 :       *ret = GNUNET_SYSERR;
    1014           0 :       GNUNET_free (amounts);
    1015           0 :       GNUNET_free (opt);
    1016           0 :       break;
    1017             :     }
    1018          26 :     GNUNET_free (amounts);
    1019             : 
    1020          26 :     GNUNET_free (opt);
    1021          26 :     sign_af (af,
    1022             :              wiremethod,
    1023             :              &master_priv.eddsa_priv);
    1024          26 :     if (NULL == af_tail)
    1025          12 :       af_head = af;
    1026             :     else
    1027          14 :       af_tail->next = af;
    1028          26 :     af_tail = af;
    1029          26 :     start_date = end_date;
    1030          26 :     year++;
    1031             :   }
    1032          25 :   if ( (GNUNET_OK == *ret) &&
    1033             :        (GNUNET_OK !=
    1034          12 :         TALER_EXCHANGEDB_fees_write (fn,
    1035             :                                      wiremethod,
    1036             :                                      af_head)) )
    1037           0 :     *ret = GNUNET_SYSERR;
    1038          13 :   GNUNET_free (section);
    1039          13 :   GNUNET_free (fn);
    1040          13 :   TALER_EXCHANGEDB_fees_free (af_head);
    1041             : }
    1042             : 
    1043             : 
    1044             : /**
    1045             :  * Output the wire fee structure.  Must be run after #max_duration_spend
    1046             :  * was initialized.
    1047             :  *
    1048             :  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
    1049             :  */
    1050             : static int
    1051           8 : create_wire_fees ()
    1052             : {
    1053             :   int ret;
    1054             : 
    1055           8 :   ret = GNUNET_OK;
    1056           8 :   TALER_WIRE_find_enabled (kcfg,
    1057             :                            &create_wire_fee_for_method,
    1058             :                            &ret);
    1059           8 :   return ret;
    1060             : }
    1061             : 
    1062             : 
    1063             : /**
    1064             :  * Closure for functions processing a request to revoke a denomination
    1065             :  * public key and request the wallets to initiate /payback.
    1066             :  */
    1067             : struct RevokeClosure
    1068             : {
    1069             :   /**
    1070             :    * Hash of the denomination public key to revoke.
    1071             :    */
    1072             :   const struct GNUNET_HashCode *hc;
    1073             : 
    1074             :   /**
    1075             :    * Base directory for keys.
    1076             :    */
    1077             :   char *basedir;
    1078             : 
    1079             :   /**
    1080             :    * Set to #GNUNET_OK if we found a matching key,
    1081             :    * Set to #GNUNET_SYSERR on error.
    1082             :    */
    1083             :   int ok;
    1084             : };
    1085             : 
    1086             : 
    1087             : 
    1088             : /**
    1089             :  * Revoke denomination keys matching the given hash.
    1090             :  *
    1091             :  * @param cls a `struct RevokeClosure` with information about what to revoke
    1092             :  * @param dki the denomination key
    1093             :  * @param alias coin alias
    1094             :  * @param revocation_master_sig non-NULL if @a dki was revoked
    1095             :  * @return #GNUNET_OK to continue to iterate,
    1096             :  *  #GNUNET_NO to stop iteration with no error,
    1097             :  *  #GNUNET_SYSERR to abort iteration with error!
    1098             :  */
    1099             : static int
    1100          10 : exchange_keys_revoke_by_dki (void *cls,
    1101             :                              const char *alias,
    1102             :                              const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
    1103             :                              const struct TALER_MasterSignatureP *revocation_master_sig)
    1104             : {
    1105          10 :   struct RevokeClosure *rc = cls;
    1106             : 
    1107          10 :   if (NULL != revocation_master_sig)
    1108           1 :     return GNUNET_OK; /* refuse to do it twice */
    1109           9 :   if (0 != memcmp (rc->hc,
    1110           9 :                    &dki->issue.properties.denom_hash,
    1111             :                    sizeof (struct GNUNET_HashCode)))
    1112           7 :     return GNUNET_OK;
    1113           2 :   rc->ok = GNUNET_OK;
    1114           2 :   if (GNUNET_OK !=
    1115           2 :       TALER_EXCHANGEDB_denomination_key_revoke (rc->basedir,
    1116             :                                                 alias,
    1117             :                                                 dki,
    1118             :                                                 &master_priv))
    1119             :   {
    1120           0 :     rc->ok = GNUNET_SYSERR;
    1121           0 :     return GNUNET_SYSERR;
    1122             :   }
    1123           2 :   return GNUNET_NO;
    1124             : }
    1125             : 
    1126             : 
    1127             : /**
    1128             :  * Revoke the denomination key matching @a hc and request /payback to be
    1129             :  * initiated.
    1130             :  *
    1131             :  * @param hc denomination key hash to revoke
    1132             :  * @return #GNUNET_OK on success,
    1133             :  *         #GNUNET_NO if @a hc was not found
    1134             :  *         #GNUNET_SYSERR on error
    1135             :  */
    1136             : static int
    1137           2 : revoke_denomination (const struct GNUNET_HashCode *hc)
    1138             : {
    1139             :   struct RevokeClosure rc;
    1140             : 
    1141           2 :   rc.hc = hc;
    1142           2 :   rc.ok = GNUNET_NO;
    1143           2 :   if (GNUNET_OK !=
    1144           2 :       GNUNET_CONFIGURATION_get_value_filename (kcfg,
    1145             :                                                "exchange",
    1146             :                                                "KEYDIR",
    1147             :                                                &rc.basedir))
    1148             :   {
    1149           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1150             :                                "exchange",
    1151             :                                "KEYDIR");
    1152           0 :     return GNUNET_SYSERR;
    1153             :   }
    1154           2 :   if (-1 ==
    1155           2 :       TALER_EXCHANGEDB_denomination_keys_iterate (rc.basedir,
    1156             :                                                   &master_public_key,
    1157             :                                                   &exchange_keys_revoke_by_dki,
    1158             :                                                   &rc))
    1159             :   {
    1160           0 :     GNUNET_break (0);
    1161           0 :     return GNUNET_SYSERR;
    1162             :   }
    1163           2 :   GNUNET_free (rc.basedir);
    1164           2 :   return rc.ok;
    1165             : }
    1166             : 
    1167             : 
    1168             : /**
    1169             :  * Main function that will be run.
    1170             :  *
    1171             :  * @param cls closure
    1172             :  * @param args remaining command-line arguments
    1173             :  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
    1174             :  * @param cfg configuration
    1175             :  */
    1176             : static void
    1177           8 : run (void *cls,
    1178             :      char *const *args,
    1179             :      const char *cfgfile,
    1180             :      const struct GNUNET_CONFIGURATION_Handle *cfg)
    1181             : {
    1182             :   static struct GNUNET_HashCode zero;
    1183             :   struct GNUNET_TIME_Relative lookahead_sign;
    1184             :   struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv;
    1185             : 
    1186           8 :   kcfg = cfg;
    1187           8 :   if (NULL == feedir)
    1188             :   {
    1189           8 :     if (GNUNET_OK !=
    1190           8 :         GNUNET_CONFIGURATION_get_value_filename (kcfg,
    1191             :                                                  "exchangedb",
    1192             :                                                  "WIREFEE_BASE_DIR",
    1193             :                                                  &feedir))
    1194             :     {
    1195           0 :       fprintf (stderr,
    1196             :                "Wire fee directory not given in neither configuration nor command-line\n");
    1197           0 :       global_ret = 1;
    1198           1 :       return;
    1199             :     }
    1200             :   }
    1201           8 :   if (GNUNET_OK !=
    1202           8 :       GNUNET_DISK_directory_create (feedir))
    1203             :   {
    1204           0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
    1205             :                               "mkdir",
    1206             :                               feedir);
    1207           0 :     global_ret = 1;
    1208           0 :     return;
    1209             :   }
    1210           8 :   GNUNET_TIME_round_abs (&now);
    1211          16 :   if ( (NULL == masterkeyfile) &&
    1212             :        (GNUNET_OK !=
    1213           8 :         GNUNET_CONFIGURATION_get_value_filename (kcfg,
    1214             :                                                  "exchange",
    1215             :                                                  "MASTER_PRIV_FILE",
    1216             :                                                  &masterkeyfile)) )
    1217             :   {
    1218           0 :     fprintf (stderr,
    1219             :              "Master key file not given in neither configuration nor command-line\n");
    1220           0 :     global_ret = 1;
    1221           0 :     return;
    1222             :   }
    1223           8 :   if (GNUNET_OK !=
    1224           8 :       GNUNET_CONFIGURATION_get_value_filename (kcfg,
    1225             :                                                "exchange",
    1226             :                                                "KEYDIR",
    1227             :                                                &exchange_directory))
    1228             :   {
    1229           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1230             :                                "exchange",
    1231             :                                "KEYDIR");
    1232           0 :     global_ret = 1;
    1233           0 :     return;
    1234             :   }
    1235           8 :   if (GNUNET_YES != GNUNET_DISK_file_test (masterkeyfile))
    1236           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1237             :                 "Exchange master private key `%s' does not exist yet, creating it!\n",
    1238             :                 masterkeyfile);
    1239           8 :   eddsa_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (masterkeyfile);
    1240           8 :   if (NULL == eddsa_priv)
    1241             :   {
    1242           0 :     fprintf (stderr,
    1243             :              "Failed to initialize master key from file `%s'\n",
    1244             :              masterkeyfile);
    1245           0 :     global_ret = 1;
    1246           0 :     return;
    1247             :   }
    1248           8 :   master_priv.eddsa_priv = *eddsa_priv;
    1249           8 :   GNUNET_free (eddsa_priv);
    1250           8 :   GNUNET_CRYPTO_eddsa_key_get_public (&master_priv.eddsa_priv,
    1251             :                                       &master_public_key.eddsa_pub);
    1252             : 
    1253           8 :   if (NULL != auditorrequestfile)
    1254             :   {
    1255           3 :     auditor_output_file = FOPEN (auditorrequestfile,
    1256             :                                  "w");
    1257           3 :     if (NULL == auditor_output_file)
    1258             :     {
    1259           0 :       fprintf (stderr,
    1260             :                "Failed to open `%s' for writing: %s\n",
    1261             :                auditorrequestfile,
    1262           0 :                STRERROR (errno));
    1263           0 :       global_ret = 1;
    1264           0 :       return;
    1265             :     }
    1266             :   }
    1267             : 
    1268             :   /* check if key from file matches the one from the configuration */
    1269             :   {
    1270             :     struct TALER_MasterPublicKeyP master_public_key_from_cfg;
    1271             : 
    1272           8 :     if (GNUNET_OK !=
    1273           8 :         GNUNET_CONFIGURATION_get_data (kcfg,
    1274             :                                        "exchange",
    1275             :                                        "master_public_key",
    1276             :                                        &master_public_key_from_cfg,
    1277             :                                        sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
    1278             :     {
    1279           0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1280             :                                  "exchange",
    1281             :                                  "master_public_key");
    1282           0 :       global_ret = 1;
    1283           0 :       return;
    1284             :     }
    1285           8 :     if (0 !=
    1286           8 :         memcmp (&master_public_key,
    1287             :                 &master_public_key_from_cfg,
    1288             :                 sizeof (struct TALER_MasterPublicKeyP)))
    1289             :     {
    1290           0 :       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    1291             :                                  "exchange",
    1292             :                                  "master_public_key",
    1293             :                                  _("does not match with private key"));
    1294           0 :       global_ret = 1;
    1295           0 :       return;
    1296             :     }
    1297             :   }
    1298             : 
    1299           8 :   if (GNUNET_OK !=
    1300           8 :       GNUNET_CONFIGURATION_get_value_time (kcfg,
    1301             :                                            "exchange_keys",
    1302             :                                            "lookahead_sign",
    1303             :                                            &lookahead_sign))
    1304             :   {
    1305           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1306             :                                "exchange_keys",
    1307             :                                "lookahead_sign");
    1308           0 :     global_ret = 1;
    1309           0 :     return;
    1310             :   }
    1311           8 :   if (0 == lookahead_sign.rel_value_us)
    1312             :   {
    1313           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    1314             :                                "exchange_keys",
    1315             :                                "lookahead_sign",
    1316             :                                _("must not be zero"));
    1317           0 :     global_ret = 1;
    1318           0 :     return;
    1319             :   }
    1320           8 :   GNUNET_TIME_round_rel (&lookahead_sign);
    1321           8 :   lookahead_sign_stamp = GNUNET_TIME_absolute_add (now,
    1322             :                                                    lookahead_sign);
    1323             : 
    1324             : 
    1325             :   /* finally, do actual work */
    1326           8 :   if (GNUNET_OK != exchange_keys_update_signkeys ())
    1327             :   {
    1328           0 :     global_ret = 1;
    1329           0 :     return;
    1330             :   }
    1331           8 :   if (GNUNET_OK != exchange_keys_update_denomkeys ())
    1332             :   {
    1333           0 :     global_ret = 1;
    1334           0 :     return;
    1335             :   }
    1336           8 :   if (GNUNET_OK != create_wire_fees ())
    1337             :   {
    1338           1 :     global_ret = 1;
    1339           1 :     return;
    1340             :   }
    1341           7 :   if ( (0 != memcmp (&zero,
    1342             :                      &revoke_dkh,
    1343           2 :                      sizeof (zero))) &&
    1344             :        (GNUNET_OK !=
    1345           2 :         revoke_denomination (&revoke_dkh)) )
    1346             :   {
    1347           0 :     global_ret = 1;
    1348           0 :     return;
    1349             :   }
    1350             : }
    1351             : 
    1352             : 
    1353             : /**
    1354             :  * The main function of the taler-exchange-keyup tool.  This tool is used
    1355             :  * to create the signing and denomination keys for the exchange.  It uses
    1356             :  * the long-term offline private key and writes the (additional) key
    1357             :  * files to the respective exchange directory (from where they can then be
    1358             :  * copied to the online server).  Note that we need (at least) the
    1359             :  * most recent generated previous keys so as to align the validity
    1360             :  * periods.
    1361             :  *
    1362             :  * @param argc number of arguments from the command line
    1363             :  * @param argv command line arguments
    1364             :  * @return 0 ok, 1 on error
    1365             :  */
    1366             : int
    1367           8 : main (int argc,
    1368             :       char *const *argv)
    1369             : {
    1370           8 :   struct GNUNET_GETOPT_CommandLineOption options[] = {
    1371             :     GNUNET_GETOPT_option_filename ('m',
    1372             :                                    "master-key",
    1373             :                                    "FILENAME",
    1374             :                                    "master key file (private key)",
    1375             :                                    &masterkeyfile),
    1376             :     GNUNET_GETOPT_option_filename ('f',
    1377             :                                    "feedir",
    1378             :                                    "DIRNAME",
    1379             :                                    "directory where to write wire transfer fee structure",
    1380             :                                    &feedir),
    1381             :     GNUNET_GETOPT_option_filename ('o',
    1382             :                                    "output",
    1383             :                                    "FILENAME",
    1384             :                                    "auditor denomination key signing request file to create",
    1385             :                                    &auditorrequestfile),
    1386             :     GNUNET_GETOPT_option_base32_auto ('r',
    1387             :                                       "revoke",
    1388             :                                       "DKH",
    1389             :                                       "revoke denomination key hash (DKH) and request wallets to initiate /payback",
    1390             :                                       &revoke_dkh),
    1391             :     GNUNET_GETOPT_option_absolute_time ('t',
    1392             :                                         "time",
    1393             :                                         "TIMESTAMP",
    1394             :                                         "pretend it is a different time for the update",
    1395             :                                         &now),
    1396             :     GNUNET_GETOPT_OPTION_END
    1397             :   };
    1398             : 
    1399           8 :   GNUNET_assert (GNUNET_OK ==
    1400             :                  GNUNET_log_setup ("taler-exchange-keyup",
    1401             :                                    "WARNING",
    1402             :                                    NULL));
    1403           8 :   now = GNUNET_TIME_absolute_get ();
    1404           8 :   if (GNUNET_OK !=
    1405           8 :       GNUNET_PROGRAM_run (argc, argv,
    1406             :                          "taler-exchange-keyup",
    1407             :                           "Setup signing and denomination keys for a Taler exchange",
    1408             :                           options,
    1409             :                           &run, NULL))
    1410           0 :     return 1;
    1411           8 :   if (NULL != auditor_output_file)
    1412             :   {
    1413           3 :     FCLOSE (auditor_output_file);
    1414           3 :     auditor_output_file = NULL;
    1415             :   }
    1416           8 :   return global_ret;
    1417             : }
    1418             : 
    1419             : /* end of taler-exchange-keyup.c */

Generated by: LCOV version 1.13