LCOV - code coverage report
Current view: top level - exchange-tools - taler-exchange-keyup.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 300 410 73.2 %
Date: 2017-11-25 11:31:41 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 charac˘er, !nd"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             : 
     292         156 :   hash_coin_type (p, &hash);
     293         156 :   hash_str = GNUNET_STRINGS_data_to_string_alloc (&hash,
     294             :                                                   sizeof (struct GNUNET_HashCode));
     295         156 :   GNUNET_assert (NULL != hash_str);
     296         156 :   GNUNET_assert (HASH_CUTOFF <= strlen (hash_str) + 1);
     297         156 :   hash_str[HASH_CUTOFF] = 0;
     298             : 
     299         156 :   val_str = TALER_amount_to_string (&p->value);
     300         156 :   GNUNET_assert (NULL != val_str);
     301        1201 :   for (size_t 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             :   long long int bval;
     367             : 
     368          36 :   base = GNUNET_STRINGS_get_short_name (filename);
     369          36 :   bval = strtoll (base,
     370             :                   &end,
     371             :                   10);
     372          72 :   if ( (NULL == end) ||
     373          71 :        (0 != *end) ||
     374             :        (0 > bval) )
     375             :   {
     376           1 :     fprintf(stderr,
     377             :             "Ignoring unexpected file `%s'.\n",
     378             :             filename);
     379           1 :     return GNUNET_OK;
     380             :   }
     381          35 :   stamp.abs_value_us = (uint64_t) bval;
     382          35 :   *anchor = GNUNET_TIME_absolute_max (stamp,
     383             :                                       *anchor);
     384          35 :   return GNUNET_OK;
     385             : }
     386             : 
     387             : 
     388             : /**
     389             :  * Get the timestamp where the first new key should be generated.
     390             :  * Relies on correctly named key files (as we do not parse them,
     391             :  * but just look at the filenames to "guess" at their contents).
     392             :  *
     393             :  * @param dir directory that should contain the existing keys
     394             :  * @param duration how long is one key valid (for signing)?
     395             :  * @param overlap what's the overlap between the keys validity period?
     396             :  * @param[out] anchor the timestamp where the first new key should be generated
     397             :  */
     398             : static void
     399          30 : get_anchor (const char *dir,
     400             :             struct GNUNET_TIME_Relative duration,
     401             :             struct GNUNET_TIME_Relative overlap,
     402             :             struct GNUNET_TIME_Absolute *anchor)
     403             : {
     404          30 :   GNUNET_assert (0 == duration.rel_value_us % 1000000);
     405          30 :   GNUNET_assert (0 == overlap.rel_value_us % 1000000);
     406          30 :   if (GNUNET_YES !=
     407          30 :       GNUNET_DISK_directory_test (dir,
     408             :                                   GNUNET_YES))
     409             :   {
     410          10 :     *anchor = now;
     411          10 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     412             :                 "No existing keys found, starting with fresh key set.\n");
     413          10 :     return;
     414             :   }
     415          20 :   *anchor = GNUNET_TIME_UNIT_ZERO_ABS;
     416          20 :   if (-1 ==
     417          20 :       GNUNET_DISK_directory_scan (dir,
     418             :                                   &get_anchor_iter,
     419             :                                   anchor))
     420             :   {
     421           0 :     *anchor = now;
     422           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     423             :                 "No existing keys found, starting with fresh key set.\n");
     424           0 :     return;
     425             :   }
     426             : 
     427          40 :   if ((GNUNET_TIME_absolute_add (*anchor,
     428          20 :                                  duration)).abs_value_us < now.abs_value_us)
     429             :   {
     430           3 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     431             :                 "Existing keys are way too old, starting with fresh key set.\n");
     432           3 :     *anchor = now;
     433             :   }
     434          17 :   else if (anchor->abs_value_us != now.abs_value_us)
     435             :   {
     436             :     /* Real starting time is the last start time + duration - overlap */
     437          17 :     *anchor = GNUNET_TIME_absolute_add (*anchor,
     438             :                                         duration);
     439          17 :     *anchor = GNUNET_TIME_absolute_subtract (*anchor,
     440             :                                              overlap);
     441             :   }
     442             :   /* anchor is now the stamp where we need to create a new key */
     443             : }
     444             : 
     445             : 
     446             : /**
     447             :  * Create a exchange signing key (for signing exchange messages, not for coins)
     448             :  * and assert its correctness by signing it with the master key.
     449             :  *
     450             :  * @param start start time of the validity period for the key
     451             :  * @param duration how long should the key be valid
     452             :  * @param end when do all signatures by this key expire
     453             :  * @param[out] pi set to the signing key information
     454             :  */
     455             : static void
     456          11 : create_signkey_issue_priv (struct GNUNET_TIME_Absolute start,
     457             :                            struct GNUNET_TIME_Relative duration,
     458             :                            struct GNUNET_TIME_Absolute end,
     459             :                            struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP *pi)
     460             : {
     461             :   struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
     462          11 :   struct TALER_ExchangeSigningKeyValidityPS *issue = &pi->issue;
     463             : 
     464          11 :   priv = GNUNET_CRYPTO_eddsa_key_create ();
     465          11 :   pi->signkey_priv.eddsa_priv = *priv;
     466          11 :   GNUNET_free (priv);
     467          11 :   issue->master_public_key = master_public_key;
     468          11 :   issue->start = GNUNET_TIME_absolute_hton (start);
     469          11 :   issue->expire = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (start,
     470             :                                                                        duration));
     471          11 :   issue->end = GNUNET_TIME_absolute_hton (end);
     472          11 :   GNUNET_CRYPTO_eddsa_key_get_public (&pi->signkey_priv.eddsa_priv,
     473             :                                       &issue->signkey_pub.eddsa_pub);
     474          11 :   issue->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY);
     475          11 :   issue->purpose.size = htonl (sizeof (struct TALER_ExchangeSigningKeyValidityPS) -
     476             :                                offsetof (struct TALER_ExchangeSigningKeyValidityPS,
     477             :                                          purpose));
     478             : 
     479          11 :   GNUNET_assert (GNUNET_OK ==
     480             :                  GNUNET_CRYPTO_eddsa_sign (&master_priv.eddsa_priv,
     481             :                                            &issue->purpose,
     482             :                                            &issue->signature.eddsa_signature));
     483          11 : }
     484             : 
     485             : 
     486             : /**
     487             :  * Generate signing keys starting from the last key found to
     488             :  * the lookahead time.
     489             :  *
     490             :  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
     491             :  */
     492             : static int
     493           8 : exchange_keys_update_signkeys ()
     494             : {
     495             :   struct GNUNET_TIME_Relative signkey_duration;
     496             :   struct GNUNET_TIME_Relative legal_duration;
     497             :   struct GNUNET_TIME_Absolute anchor;
     498             :   char *signkey_dir;
     499             : 
     500           8 :   if (GNUNET_OK !=
     501           8 :       GNUNET_CONFIGURATION_get_value_time (kcfg,
     502             :                                            "exchange_keys",
     503             :                                            "signkey_duration",
     504             :                                            &signkey_duration))
     505             :   {
     506           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     507             :                                "exchange_keys",
     508             :                                "signkey_duration");
     509           0 :     return GNUNET_SYSERR;
     510             :   }
     511           8 :   if (GNUNET_OK !=
     512           8 :       GNUNET_CONFIGURATION_get_value_time (kcfg,
     513             :                                            "exchange_keys",
     514             :                                            "legal_duration",
     515             :                                            &legal_duration))
     516             :   {
     517           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     518             :                                "exchange_keys",
     519             :                                "legal_duration",
     520             :                                "fails to specify valid timeframe");
     521           0 :     return GNUNET_SYSERR;
     522             :   }
     523           8 :   if (signkey_duration.rel_value_us > legal_duration.rel_value_us)
     524             :   {
     525           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     526             :                                "exchange_keys",
     527             :                                "legal_duration",
     528             :                                "must be longer than signkey_duration");
     529           0 :     return GNUNET_SYSERR;
     530             :   }
     531           8 :   GNUNET_TIME_round_rel (&signkey_duration);
     532           8 :   GNUNET_asprintf (&signkey_dir,
     533             :                    "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_SIGNING_KEYS,
     534             :                    exchange_directory);
     535             :   /* make sure the directory exists */
     536           8 :   if (GNUNET_OK !=
     537           8 :       GNUNET_DISK_directory_create (signkey_dir))
     538             :   {
     539           0 :     fprintf (stderr,
     540             :              "Failed to create signing key directory\n");
     541           0 :     GNUNET_free (signkey_dir);
     542           0 :     return GNUNET_SYSERR;
     543             :   }
     544             : 
     545           8 :   get_anchor (signkey_dir,
     546             :               signkey_duration,
     547             :               GNUNET_TIME_UNIT_ZERO /* no overlap for signing keys */,
     548             :               &anchor);
     549           8 :   GNUNET_free (signkey_dir);
     550             : 
     551          27 :   while (anchor.abs_value_us < lookahead_sign_stamp.abs_value_us)
     552             :   {
     553             :     struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP signkey_issue;
     554             :     struct GNUNET_TIME_Absolute end;
     555             : 
     556          11 :     end = GNUNET_TIME_absolute_add (anchor,
     557             :                                     legal_duration);
     558          11 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     559             :                 "Generating signing key for %s.\n",
     560             :                 GNUNET_STRINGS_absolute_time_to_string (anchor));
     561          11 :     create_signkey_issue_priv (anchor,
     562             :                                signkey_duration,
     563             :                                end,
     564             :                                &signkey_issue);
     565          11 :     if (GNUNET_OK !=
     566          11 :         TALER_EXCHANGEDB_signing_key_write (exchange_directory,
     567             :                                             anchor,
     568             :                                             &signkey_issue))
     569           0 :       return GNUNET_SYSERR;
     570          11 :     anchor = GNUNET_TIME_absolute_add (anchor,
     571             :                                        signkey_duration);
     572             :   }
     573           8 :   return GNUNET_OK;
     574             : }
     575             : 
     576             : 
     577             : /**
     578             :  * Parse configuration for coin type parameters.  Also determines
     579             :  * our anchor by looking at the existing coins of the same type.
     580             :  *
     581             :  * @param ct section in the configuration file giving the coin type parameters
     582             :  * @param[out] params set to the coin parameters from the configuration
     583             :  * @return #GNUNET_OK on success, #GNUNET_SYSERR if the configuration is invalid
     584             :  */
     585             : static int
     586          22 : get_cointype_params (const char *ct,
     587             :                      struct CoinTypeParams *params)
     588             : {
     589             :   const char *dir;
     590             :   unsigned long long rsa_keysize;
     591             : 
     592          22 :   if (GNUNET_OK !=
     593          22 :       GNUNET_CONFIGURATION_get_value_time (kcfg,
     594             :                                            ct,
     595             :                                            "duration_withdraw",
     596             :                                            &params->duration_withdraw))
     597             :   {
     598           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     599             :                                ct,
     600             :                                "duration_withdraw");
     601           0 :     return GNUNET_SYSERR;
     602             :   }
     603          22 :   GNUNET_TIME_round_rel (&params->duration_withdraw);
     604          22 :   if (GNUNET_OK !=
     605          22 :       GNUNET_CONFIGURATION_get_value_time (kcfg,
     606             :                                            ct,
     607             :                                            "duration_spend",
     608             :                                            &params->duration_spend))
     609             :   {
     610           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     611             :                                ct,
     612             :                                "duration_spend");
     613           0 :     return GNUNET_SYSERR;
     614             :   }
     615          22 :   GNUNET_TIME_round_rel (&params->duration_spend);
     616          22 :   max_duration_spend = GNUNET_TIME_relative_max (max_duration_spend,
     617             :                                                  params->duration_spend);
     618          22 :   if (GNUNET_OK !=
     619          22 :       GNUNET_CONFIGURATION_get_value_time (kcfg,
     620             :                                            ct,
     621             :                                            "duration_legal",
     622             :                                            &params->duration_legal))
     623             :   {
     624           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     625             :                                ct,
     626             :                                "duration_legal");
     627           0 :     return GNUNET_SYSERR;
     628             :   }
     629          22 :   GNUNET_TIME_round_rel (&params->duration_legal);
     630          22 :   if (GNUNET_OK !=
     631          22 :       GNUNET_CONFIGURATION_get_value_time (kcfg,
     632             :                                            ct,
     633             :                                            "duration_overlap",
     634             :                                            &params->duration_overlap))
     635             :   {
     636           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     637             :                                ct,
     638             :                                "exchange_denom_duration_overlap");
     639           0 :     return GNUNET_SYSERR;
     640             :   }
     641          22 :   GNUNET_TIME_round_rel (&params->duration_overlap);
     642          22 :   if (GNUNET_OK !=
     643          22 :       GNUNET_CONFIGURATION_get_value_number (kcfg,
     644             :                                              ct,
     645             :                                              "rsa_keysize",
     646             :                                              &rsa_keysize))
     647             :   {
     648           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     649             :                                ct,
     650             :                                "rsa_keysize");
     651           0 :     return GNUNET_SYSERR;
     652             :   }
     653          44 :   if ( (rsa_keysize > 4 * 2048) ||
     654          22 :        (rsa_keysize < 1024) )
     655             :   {
     656           0 :     fprintf (stderr,
     657             :              "Given RSA keysize %llu outside of permitted range\n",
     658             :              rsa_keysize);
     659           0 :     return GNUNET_SYSERR;
     660             :   }
     661          22 :   params->rsa_keysize = (unsigned int) rsa_keysize;
     662          22 :   if (GNUNET_OK !=
     663          22 :       TALER_config_get_denom (kcfg,
     664             :                               ct,
     665             :                               "value",
     666             :                               &params->value))
     667             :   {
     668           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     669             :                                ct,
     670             :                                "value");
     671           0 :     return GNUNET_SYSERR;
     672             :   }
     673          22 :   if (GNUNET_OK !=
     674          22 :       TALER_config_get_denom (kcfg,
     675             :                               ct,
     676             :                               "fee_withdraw",
     677             :                               &params->fee_withdraw))
     678             :   {
     679           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     680             :                                ct,
     681             :                                "fee_withdraw");
     682           0 :     return GNUNET_SYSERR;
     683             :   }
     684          22 :   if (GNUNET_OK !=
     685          22 :       TALER_config_get_denom (kcfg,
     686             :                               ct,
     687             :                               "fee_deposit",
     688             :                               &params->fee_deposit))
     689             :   {
     690           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     691             :                                ct,
     692             :                                "fee_deposit");
     693           0 :     return GNUNET_SYSERR;
     694             :   }
     695          22 :   if (GNUNET_OK !=
     696          22 :       TALER_config_get_denom (kcfg,
     697             :                               ct,
     698             :                               "fee_refresh",
     699             :                               &params->fee_refresh))
     700             :   {
     701           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     702             :                                ct,
     703             :                                "fee_refresh");
     704           0 :     return GNUNET_SYSERR;
     705             :   }
     706          22 :   if (GNUNET_OK !=
     707          22 :       TALER_config_get_denom (kcfg,
     708             :                               ct,
     709             :                               "fee_refund",
     710             :                               &params->fee_refund))
     711             :   {
     712           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     713             :                                ct,
     714             :                                "fee_refund");
     715           0 :     return GNUNET_SYSERR;
     716             :   }
     717             : 
     718          22 :   dir = get_cointype_dir (params);
     719          22 :   get_anchor (dir,
     720             :               params->duration_withdraw,
     721             :               params->duration_overlap,
     722             :               &params->anchor);
     723          22 :   return GNUNET_OK;
     724             : }
     725             : 
     726             : 
     727             : /**
     728             :  * Initialize the private and public key information structure for
     729             :  * signing coins into existence.  Generates the private signing key
     730             :  * and signes it together with the coin's meta data using the master
     731             :  * signing key.
     732             :  *
     733             :  * @param params parameters used to initialize the @a dki
     734             :  * @param[out] dki initialized according to @a params
     735             :  */
     736             : static void
     737         112 : create_denomkey_issue (const struct CoinTypeParams *params,
     738             :                        struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
     739             : {
     740             :   dki->denom_priv.rsa_private_key
     741         112 :     = GNUNET_CRYPTO_rsa_private_key_create (params->rsa_keysize);
     742         112 :   GNUNET_assert (NULL != dki->denom_priv.rsa_private_key);
     743             :   dki->denom_pub.rsa_public_key
     744         112 :     = GNUNET_CRYPTO_rsa_private_key_get_public (dki->denom_priv.rsa_private_key);
     745         112 :   GNUNET_CRYPTO_rsa_public_key_hash (dki->denom_pub.rsa_public_key,
     746             :                                      &dki->issue.properties.denom_hash);
     747         112 :   dki->issue.properties.master = master_public_key;
     748         112 :   dki->issue.properties.start = GNUNET_TIME_absolute_hton (params->anchor);
     749         112 :   dki->issue.properties.expire_withdraw =
     750         112 :       GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor,
     751             :                                                            params->duration_withdraw));
     752         112 :   dki->issue.properties.expire_deposit =
     753         112 :     GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor,
     754             :                                                          params->duration_spend));
     755         112 :   dki->issue.properties.expire_legal =
     756         112 :     GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor,
     757             :                                                          params->duration_legal));
     758         112 :   TALER_amount_hton (&dki->issue.properties.value,
     759             :                      &params->value);
     760         112 :   TALER_amount_hton (&dki->issue.properties.fee_withdraw,
     761             :                      &params->fee_withdraw);
     762         112 :   TALER_amount_hton (&dki->issue.properties.fee_deposit,
     763             :                      &params->fee_deposit);
     764         112 :   TALER_amount_hton (&dki->issue.properties.fee_refresh,
     765             :                      &params->fee_refresh);
     766         112 :   TALER_amount_hton (&dki->issue.properties.fee_refund,
     767             :                      &params->fee_refund);
     768             :   dki->issue.properties.purpose.purpose
     769         112 :     = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY);
     770             :   dki->issue.properties.purpose.size
     771         112 :     = htonl (sizeof (struct TALER_DenominationKeyValidityPS));
     772         112 :   GNUNET_assert (GNUNET_OK ==
     773             :                  GNUNET_CRYPTO_eddsa_sign (&master_priv.eddsa_priv,
     774             :                                            &dki->issue.properties.purpose,
     775             :                                            &dki->issue.signature.eddsa_signature));
     776         112 : }
     777             : 
     778             : 
     779             : /**
     780             :  * Generate new coin signing keys for the coin type of the given @a
     781             :  * coin_alias.
     782             :  *
     783             :  * @param cls a `int *`, to be set to #GNUNET_SYSERR on failure
     784             :  * @param coin_alias name of the coin's section in the configuration
     785             :  */
     786             : static void
     787         182 : exchange_keys_update_cointype (void *cls,
     788             :                                const char *coin_alias)
     789             : {
     790         182 :   int *ret = cls;
     791             :   struct CoinTypeParams p;
     792             :   const char *dkf;
     793             :   struct TALER_EXCHANGEDB_DenominationKeyIssueInformation denomkey_issue;
     794             : 
     795         182 :   if (0 != strncasecmp (coin_alias,
     796             :                         "coin_",
     797             :                         strlen ("coin_")))
     798         320 :     return; /* not a coin definition */
     799          22 :   if (GNUNET_OK !=
     800          22 :       get_cointype_params (coin_alias,
     801             :                            &p))
     802             :   {
     803           0 :     *ret = GNUNET_SYSERR;
     804           0 :     return;
     805             :   }
     806          22 :   if (GNUNET_OK !=
     807          22 :       GNUNET_DISK_directory_create (get_cointype_dir (&p)))
     808             :   {
     809           0 :     *ret = GNUNET_SYSERR;
     810           0 :     return;
     811             :   }
     812             : 
     813         156 :   while (p.anchor.abs_value_us < lookahead_sign_stamp.abs_value_us)
     814             :   {
     815         112 :     dkf = get_cointype_file (&p,
     816             :                              p.anchor);
     817         112 :     GNUNET_break (GNUNET_YES != GNUNET_DISK_file_test (dkf));
     818         112 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     819             :                 "Generating denomination key for type `%s', start %s at %s\n",
     820             :                 coin_alias,
     821             :                 GNUNET_STRINGS_absolute_time_to_string (p.anchor),
     822             :                 dkf);
     823         112 :     create_denomkey_issue (&p,
     824             :                            &denomkey_issue);
     825         112 :     if (GNUNET_OK !=
     826         112 :         TALER_EXCHANGEDB_denomination_key_write (dkf,
     827             :                                                  &denomkey_issue))
     828             :     {
     829           0 :       fprintf (stderr,
     830             :                "Failed to write denomination key information to file `%s'.\n",
     831             :                dkf);
     832           0 :       *ret = GNUNET_SYSERR;
     833           0 :       GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key);
     834           0 :       GNUNET_CRYPTO_rsa_public_key_free (denomkey_issue.denom_pub.rsa_public_key);
     835           0 :       return;
     836             :     }
     837         125 :     if ( (NULL != auditor_output_file) &&
     838             :          (1 !=
     839          13 :           fwrite (&denomkey_issue.issue.properties,
     840             :                   sizeof (struct TALER_DenominationKeyValidityPS),
     841             :                   1,
     842             :                   auditor_output_file)) )
     843             :     {
     844           0 :       fprintf (stderr,
     845             :                "Failed to write denomination key information to %s: %s\n",
     846             :                auditorrequestfile,
     847           0 :                STRERROR (errno));
     848           0 :       *ret = GNUNET_SYSERR;
     849           0 :       GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key);
     850           0 :       GNUNET_CRYPTO_rsa_public_key_free (denomkey_issue.denom_pub.rsa_public_key);
     851           0 :       return;
     852             :     }
     853         112 :     GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key);
     854         112 :     GNUNET_CRYPTO_rsa_public_key_free (denomkey_issue.denom_pub.rsa_public_key);
     855         112 :     p.anchor = GNUNET_TIME_absolute_add (p.anchor,
     856             :                                          p.duration_withdraw);
     857         112 :     p.anchor = GNUNET_TIME_absolute_subtract (p.anchor,
     858             :                                               p.duration_overlap);
     859             :   }
     860             : }
     861             : 
     862             : 
     863             : /**
     864             :  * Update all of the denomination keys of the exchange.
     865             :  *
     866             :  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
     867             :  */
     868             : static int
     869           8 : exchange_keys_update_denomkeys ()
     870             : {
     871             :   int ok;
     872             : 
     873           8 :   ok = GNUNET_OK;
     874           8 :   GNUNET_CONFIGURATION_iterate_sections (kcfg,
     875             :                                          &exchange_keys_update_cointype,
     876             :                                          &ok);
     877           8 :   return ok;
     878             : }
     879             : 
     880             : 
     881             : /**
     882             :  * Sign @a af with @a priv
     883             :  *
     884             :  * @param[in,out] af fee structure to sign
     885             :  * @param wireplugin name of the plugin for which we sign
     886             :  * @param priv private key to use for signing
     887             :  */
     888             : static void
     889          26 : sign_af (struct TALER_EXCHANGEDB_AggregateFees *af,
     890             :          const char *wireplugin,
     891             :          const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
     892             : {
     893             :   struct TALER_MasterWireFeePS wf;
     894             : 
     895          26 :   TALER_EXCHANGEDB_fees_2_wf (wireplugin,
     896             :                               af,
     897             :                               &wf);
     898          26 :   GNUNET_assert (GNUNET_OK ==
     899             :                  GNUNET_CRYPTO_eddsa_sign (priv,
     900             :                                            &wf.purpose,
     901             :                                            &af->master_sig.eddsa_signature));
     902          26 : }
     903             : 
     904             : 
     905             : /**
     906             :  * Output the wire fee structure.  Must be run after #max_duration_spend
     907             :  * was initialized.
     908             :  *
     909             :  * @param cls pointer to `int`, set to #GNUNET_SYSERR on error
     910             :  * @param wiremethod method to write fees for
     911             :  */
     912             : static void
     913          13 : create_wire_fee_for_method (void *cls,
     914             :                             const char *wiremethod)
     915             : {
     916          13 :   int *ret = cls;
     917             :   struct TALER_EXCHANGEDB_AggregateFees *af_head;
     918             :   struct TALER_EXCHANGEDB_AggregateFees *af_tail;
     919             :   unsigned int year;
     920             :   struct GNUNET_TIME_Absolute last_date;
     921             :   struct GNUNET_TIME_Absolute start_date;
     922             :   struct GNUNET_TIME_Absolute end_date;
     923             :   char yearstr[12];
     924             :   char *fn;
     925             :   char *section;
     926             : 
     927          13 :   if (GNUNET_OK != *ret)
     928           0 :     return;
     929          13 :   last_date = GNUNET_TIME_absolute_add (lookahead_sign_stamp,
     930             :                                         max_duration_spend);
     931          13 :   GNUNET_asprintf (&section,
     932             :                    "exchange-wire-%s",
     933             :                    wiremethod);
     934          13 :   GNUNET_asprintf (&fn,
     935             :                    "%s%s.fee",
     936             :                    feedir,
     937             :                    wiremethod);
     938          13 :   af_head = NULL;
     939          13 :   af_tail = NULL;
     940          13 :   year = GNUNET_TIME_get_current_year ();
     941          13 :   start_date = GNUNET_TIME_year_to_time (year);
     942          13 :   while (start_date.abs_value_us < last_date.abs_value_us)
     943             :   {
     944             :     struct TALER_EXCHANGEDB_AggregateFees *af;
     945             :     char *opt;
     946             :     char *amounts;
     947             : 
     948          27 :     GNUNET_snprintf (yearstr,
     949             :                      sizeof (yearstr),
     950             :                      "%u",
     951             :                      year);
     952          27 :     end_date = GNUNET_TIME_year_to_time (year + 1);
     953          27 :     af = GNUNET_new (struct TALER_EXCHANGEDB_AggregateFees);
     954          27 :     af->start_date = start_date;
     955          27 :     af->end_date = end_date;
     956             : 
     957             :     /* handle wire fee */
     958          27 :     GNUNET_asprintf (&opt,
     959             :                      "wire-fee-%u",
     960             :                      year);
     961          27 :     if (GNUNET_OK !=
     962          27 :         GNUNET_CONFIGURATION_get_value_string (kcfg,
     963             :                                                section,
     964             :                                                opt,
     965             :                                                &amounts))
     966             :     {
     967           1 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     968             :                                  section,
     969             :                                  opt);
     970           1 :       *ret = GNUNET_SYSERR;
     971           1 :       GNUNET_free (opt);
     972           1 :       break;
     973             :     }
     974          26 :     if (GNUNET_OK !=
     975          26 :         TALER_string_to_amount (amounts,
     976             :                                 &af->wire_fee))
     977             :     {
     978           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     979             :                   "Invalid amount `%s' specified in `%s' under `%s'\n",
     980             :                   amounts,
     981             :                   wiremethod,
     982             :                   opt);
     983           0 :       *ret = GNUNET_SYSERR;
     984           0 :       GNUNET_free (amounts);
     985           0 :       GNUNET_free (opt);
     986           0 :       break;
     987             :     }
     988          26 :     GNUNET_free (amounts);
     989          26 :     GNUNET_free (opt);
     990             : 
     991             :     /* handle closing fee */
     992          26 :     GNUNET_asprintf (&opt,
     993             :                      "closing-fee-%u",
     994             :                      year);
     995          26 :     if (GNUNET_OK !=
     996          26 :         GNUNET_CONFIGURATION_get_value_string (kcfg,
     997             :                                                section,
     998             :                                                opt,
     999             :                                                &amounts))
    1000             :     {
    1001           0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1002             :                                  section,
    1003             :                                  opt);
    1004           0 :       *ret = GNUNET_SYSERR;
    1005           0 :       GNUNET_free (opt);
    1006           0 :       break;
    1007             :     }
    1008          26 :     if (GNUNET_OK !=
    1009          26 :         TALER_string_to_amount (amounts,
    1010             :                                 &af->closing_fee))
    1011             :     {
    1012           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1013             :                   "Invalid amount `%s' specified in `%s' under `%s'\n",
    1014             :                   amounts,
    1015             :                   wiremethod,
    1016             :                   opt);
    1017           0 :       *ret = GNUNET_SYSERR;
    1018           0 :       GNUNET_free (amounts);
    1019           0 :       GNUNET_free (opt);
    1020           0 :       break;
    1021             :     }
    1022          26 :     GNUNET_free (amounts);
    1023             : 
    1024          26 :     GNUNET_free (opt);
    1025          26 :     sign_af (af,
    1026             :              wiremethod,
    1027             :              &master_priv.eddsa_priv);
    1028          26 :     if (NULL == af_tail)
    1029          12 :       af_head = af;
    1030             :     else
    1031          14 :       af_tail->next = af;
    1032          26 :     af_tail = af;
    1033          26 :     start_date = end_date;
    1034          26 :     year++;
    1035             :   }
    1036          25 :   if ( (GNUNET_OK == *ret) &&
    1037             :        (GNUNET_OK !=
    1038          12 :         TALER_EXCHANGEDB_fees_write (fn,
    1039             :                                      wiremethod,
    1040             :                                      af_head)) )
    1041           0 :     *ret = GNUNET_SYSERR;
    1042          13 :   GNUNET_free (section);
    1043          13 :   GNUNET_free (fn);
    1044          13 :   TALER_EXCHANGEDB_fees_free (af_head);
    1045             : }
    1046             : 
    1047             : 
    1048             : /**
    1049             :  * Output the wire fee structure.  Must be run after #max_duration_spend
    1050             :  * was initialized.
    1051             :  *
    1052             :  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
    1053             :  */
    1054             : static int
    1055           8 : create_wire_fees ()
    1056             : {
    1057             :   int ret;
    1058             : 
    1059           8 :   ret = GNUNET_OK;
    1060           8 :   TALER_WIRE_find_enabled (kcfg,
    1061             :                            &create_wire_fee_for_method,
    1062             :                            &ret);
    1063           8 :   return ret;
    1064             : }
    1065             : 
    1066             : 
    1067             : /**
    1068             :  * Closure for functions processing a request to revoke a denomination
    1069             :  * public key and request the wallets to initiate /payback.
    1070             :  */
    1071             : struct RevokeClosure
    1072             : {
    1073             :   /**
    1074             :    * Hash of the denomination public key to revoke.
    1075             :    */
    1076             :   const struct GNUNET_HashCode *hc;
    1077             : 
    1078             :   /**
    1079             :    * Base directory for keys.
    1080             :    */
    1081             :   char *basedir;
    1082             : 
    1083             :   /**
    1084             :    * Set to #GNUNET_OK if we found a matching key,
    1085             :    * Set to #GNUNET_SYSERR on error.
    1086             :    */
    1087             :   int ok;
    1088             : };
    1089             : 
    1090             : 
    1091             : 
    1092             : /**
    1093             :  * Revoke denomination keys matching the given hash.
    1094             :  *
    1095             :  * @param cls a `struct RevokeClosure` with information about what to revoke
    1096             :  * @param dki the denomination key
    1097             :  * @param alias coin alias
    1098             :  * @param revocation_master_sig non-NULL if @a dki was revoked
    1099             :  * @return #GNUNET_OK to continue to iterate,
    1100             :  *  #GNUNET_NO to stop iteration with no error,
    1101             :  *  #GNUNET_SYSERR to abort iteration with error!
    1102             :  */
    1103             : static int
    1104          10 : exchange_keys_revoke_by_dki (void *cls,
    1105             :                              const char *alias,
    1106             :                              const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
    1107             :                              const struct TALER_MasterSignatureP *revocation_master_sig)
    1108             : {
    1109          10 :   struct RevokeClosure *rc = cls;
    1110             : 
    1111          10 :   if (NULL != revocation_master_sig)
    1112           1 :     return GNUNET_OK; /* refuse to do it twice */
    1113           9 :   if (0 != memcmp (rc->hc,
    1114           9 :                    &dki->issue.properties.denom_hash,
    1115             :                    sizeof (struct GNUNET_HashCode)))
    1116           7 :     return GNUNET_OK;
    1117           2 :   rc->ok = GNUNET_OK;
    1118           2 :   if (GNUNET_OK !=
    1119           2 :       TALER_EXCHANGEDB_denomination_key_revoke (rc->basedir,
    1120             :                                                 alias,
    1121             :                                                 dki,
    1122             :                                                 &master_priv))
    1123             :   {
    1124           0 :     rc->ok = GNUNET_SYSERR;
    1125           0 :     return GNUNET_SYSERR;
    1126             :   }
    1127           2 :   return GNUNET_NO;
    1128             : }
    1129             : 
    1130             : 
    1131             : /**
    1132             :  * Revoke the denomination key matching @a hc and request /payback to be
    1133             :  * initiated.
    1134             :  *
    1135             :  * @param hc denomination key hash to revoke
    1136             :  * @return #GNUNET_OK on success,
    1137             :  *         #GNUNET_NO if @a hc was not found
    1138             :  *         #GNUNET_SYSERR on error
    1139             :  */
    1140             : static int
    1141           2 : revoke_denomination (const struct GNUNET_HashCode *hc)
    1142             : {
    1143             :   struct RevokeClosure rc;
    1144             : 
    1145           2 :   rc.hc = hc;
    1146           2 :   rc.ok = GNUNET_NO;
    1147           2 :   if (GNUNET_OK !=
    1148           2 :       GNUNET_CONFIGURATION_get_value_filename (kcfg,
    1149             :                                                "exchange",
    1150             :                                                "KEYDIR",
    1151             :                                                &rc.basedir))
    1152             :   {
    1153           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1154             :                                "exchange",
    1155             :                                "KEYDIR");
    1156           0 :     return GNUNET_SYSERR;
    1157             :   }
    1158           2 :   if (-1 ==
    1159           2 :       TALER_EXCHANGEDB_denomination_keys_iterate (rc.basedir,
    1160             :                                                   &master_public_key,
    1161             :                                                   &exchange_keys_revoke_by_dki,
    1162             :                                                   &rc))
    1163             :   {
    1164           0 :     GNUNET_break (0);
    1165           0 :     return GNUNET_SYSERR;
    1166             :   }
    1167           2 :   GNUNET_free (rc.basedir);
    1168           2 :   return rc.ok;
    1169             : }
    1170             : 
    1171             : 
    1172             : /**
    1173             :  * Main function that will be run.
    1174             :  *
    1175             :  * @param cls closure
    1176             :  * @param args remaining command-line arguments
    1177             :  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
    1178             :  * @param cfg configuration
    1179             :  */
    1180             : static void
    1181           8 : run (void *cls,
    1182             :      char *const *args,
    1183             :      const char *cfgfile,
    1184             :      const struct GNUNET_CONFIGURATION_Handle *cfg)
    1185             : {
    1186             :   static struct GNUNET_HashCode zero;
    1187             :   struct GNUNET_TIME_Relative lookahead_sign;
    1188             :   struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv;
    1189             : 
    1190           8 :   kcfg = cfg;
    1191           8 :   if (NULL == feedir)
    1192             :   {
    1193           8 :     if (GNUNET_OK !=
    1194           8 :         GNUNET_CONFIGURATION_get_value_filename (kcfg,
    1195             :                                                  "exchangedb",
    1196             :                                                  "WIREFEE_BASE_DIR",
    1197             :                                                  &feedir))
    1198             :     {
    1199           0 :       fprintf (stderr,
    1200             :                "Wire fee directory not given in neither configuration nor command-line\n");
    1201           0 :       global_ret = 1;
    1202           1 :       return;
    1203             :     }
    1204             :   }
    1205           8 :   if (GNUNET_OK !=
    1206           8 :       GNUNET_DISK_directory_create (feedir))
    1207             :   {
    1208           0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
    1209             :                               "mkdir",
    1210             :                               feedir);
    1211           0 :     global_ret = 1;
    1212           0 :     return;
    1213             :   }
    1214           8 :   GNUNET_TIME_round_abs (&now);
    1215          16 :   if ( (NULL == masterkeyfile) &&
    1216             :        (GNUNET_OK !=
    1217           8 :         GNUNET_CONFIGURATION_get_value_filename (kcfg,
    1218             :                                                  "exchange",
    1219             :                                                  "MASTER_PRIV_FILE",
    1220             :                                                  &masterkeyfile)) )
    1221             :   {
    1222           0 :     fprintf (stderr,
    1223             :              "Master key file not given in neither configuration nor command-line\n");
    1224           0 :     global_ret = 1;
    1225           0 :     return;
    1226             :   }
    1227           8 :   if (GNUNET_OK !=
    1228           8 :       GNUNET_CONFIGURATION_get_value_filename (kcfg,
    1229             :                                                "exchange",
    1230             :                                                "KEYDIR",
    1231             :                                                &exchange_directory))
    1232             :   {
    1233           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1234             :                                "exchange",
    1235             :                                "KEYDIR");
    1236           0 :     global_ret = 1;
    1237           0 :     return;
    1238             :   }
    1239           8 :   if (GNUNET_YES != GNUNET_DISK_file_test (masterkeyfile))
    1240           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1241             :                 "Exchange master private key `%s' does not exist yet, creating it!\n",
    1242             :                 masterkeyfile);
    1243           8 :   eddsa_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (masterkeyfile);
    1244           8 :   if (NULL == eddsa_priv)
    1245             :   {
    1246           0 :     fprintf (stderr,
    1247             :              "Failed to initialize master key from file `%s'\n",
    1248             :              masterkeyfile);
    1249           0 :     global_ret = 1;
    1250           0 :     return;
    1251             :   }
    1252           8 :   master_priv.eddsa_priv = *eddsa_priv;
    1253           8 :   GNUNET_free (eddsa_priv);
    1254           8 :   GNUNET_CRYPTO_eddsa_key_get_public (&master_priv.eddsa_priv,
    1255             :                                       &master_public_key.eddsa_pub);
    1256             : 
    1257           8 :   if (NULL != auditorrequestfile)
    1258             :   {
    1259           3 :     auditor_output_file = FOPEN (auditorrequestfile,
    1260             :                                  "w");
    1261           3 :     if (NULL == auditor_output_file)
    1262             :     {
    1263           0 :       fprintf (stderr,
    1264             :                "Failed to open `%s' for writing: %s\n",
    1265             :                auditorrequestfile,
    1266           0 :                STRERROR (errno));
    1267           0 :       global_ret = 1;
    1268           0 :       return;
    1269             :     }
    1270             :   }
    1271             : 
    1272             :   /* check if key from file matches the one from the configuration */
    1273             :   {
    1274             :     struct TALER_MasterPublicKeyP master_public_key_from_cfg;
    1275             : 
    1276           8 :     if (GNUNET_OK !=
    1277           8 :         GNUNET_CONFIGURATION_get_data (kcfg,
    1278             :                                        "exchange",
    1279             :                                        "master_public_key",
    1280             :                                        &master_public_key_from_cfg,
    1281             :                                        sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
    1282             :     {
    1283           0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1284             :                                  "exchange",
    1285             :                                  "master_public_key");
    1286           0 :       global_ret = 1;
    1287           0 :       return;
=sxan class="lineNum">    1288             :     }
    1289           8 :     if (0 !=
    1290           8 :         memcmp (&master_public_key,
    1291             :                 &master_public_key_from_cfg,
    1292             :                 sizeof (struct TALER_MasterPublicKeyP)))
    1293             :     {
    1294           0 :       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    1295             :                                  "exchange",
    1296             :                                  "master_public_key",
    1297             :                                  _("does not match with private key"));
    1298           0 :       global_ret = 1;
    1299           0 :       return;
    1300             :     }
    1301             :   }
    1302             : 
    1303           8 :   if (GNUNET_OK !=
    1304           8 :       GNUNET_CONFIGURATION_get_value_time (kcfg,
    1305             :                                            "exchange_keys",
    1306             :                                            "lookahead_sign",
    1307             :                                            &lookahead_sign))
    1308             :   {
    1309           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1310             :                                "exchange_keys",
    1311             :                                "lookahead_sign");
    1312           0 :     global_ret = 1;
    1313           0 :     return;
    1314             :   }
    1315           8 :   if (0 == lookahead_sign.rel_value_us)
    1316             :   {
    1317           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    1318             :                                "exchange_keys",
    1319             :                                "lookahead_sign",
    1320             :                                _("must not be zero"));
    1321           0 :     global_ret = 1;
    1322           0 :     return;
    1323             :   }
    1324           8 :   GNUNET_TIME_round_rel (&lookahead_sign);
    1325           8 :   lookahead_sign_stamp = GNUNET_TIME_absolute_add (now,
    1326             :                                                    lookahead_sign);
    1327             : 
    1328             : 
    1329             :   /* finally, do actual work */
    1330           8 :   if (GNUNET_OK != exchange_keys_update_signkeys ())
    1331             :   {
    1332           0 :     global_ret = 1;
    1333           0 :     return;
    1334             :   }
    1335           8 :   if (GNUNET_OK != exchange_keys_update_denomkeys ())
    1336             :   {
    1337           0 :     global_ret = 1;
    1338           0 :     return;
    1339             :   }
    1340           8 :   if (GNUNET_OK != create_wire_fees ())
    1341             :   {
    1342           1 :     global_ret = 1;
    1343           1 :     return;
    1344             :   }
    1345           7 :   if ( (0 != memcmp (&zero,
    1346             :                      &revoke_dkh,
    1347           2 :                      sizeof (zero))) &&
    1348             :        (GNUNET_OK !=
    1349           2 :         revoke_denomination (&revoke_dkh)) )
    1350             :   {
    1351           0 :     global_ret = 1;
    1352           0 :     return;
    1353             :   }
    1354             : }
    1355             : 
    1356             : 
    1357             : /**
    1358             :  * The main function of the taler-exchange-keyup tool.  This tool is used
    1359             :  * to create the signing and denomination keys for the exchange.  It uses
    1360             :  * the long-term offline private key and writes the (additional) key
    1361             :  * files to the respective exchange directory (from where they can then be
    1362             :  * copied to the online server).  Note that we need (at least) the
    1363             :  * most recent generated previous keys so as to align the validity
    1364             :  * periods.
    1365             :  *
    1366             :  * @param argc number of arguments from the command line
    1367             :  * @param argv command line arguments
    1368             :  * @return 0 ok, 1 on error
    1369             :  */
    1370             : int
    1371           8 : main (int argc,
    1372             :       char *const *argv)
    1373             : {
    137<           8 :   struct GNUNET_GETOPT_CommandLineOption options[] = {
    1375             :     GNUNET_GETOPT_option_filename ('m',
    1376             :                                    "master-key",
    1377             :                                    "FILENAME",
    1378             :                                    "master key file (private key)",
    1379             :                                    &masterkeyfile),
    1380             :     GNUNET_GETOPT_option_filename ('f',
    1381             :                                    "feedir",
    1382             :                                    "DIRNAME",
    1383             :                                    "directory where to write wire transfer fee structure",
    1384             :                                    &feedir),
    1385             :     GNUNET_GETOPT_option_filename ('o',
    1386             :                                    "output",
    1387             :                                    "FILENAME",
    1388             :                                    "auditor denomination key signing request file to create",
    1389             :                                    &auditorrequestfile),
    1390             :     GNUNET_GETOPT_option_base32_auto ('r',
    1391             :                                       "revoke",
    1392             :                                       "DKH",
    1393             :                                       "revoke denomination key hash (DKH) and request wallets to initiate /payback",
    1394             :                                       &revoke_dkh),
    1395             :     GNUNET_GETOPT_option_absolute_time ('t',
    1396             :                                         "time",
    1397             :                                         "TIMESTAMP",
    1398             :                                         "pretend it is a different time for the update",
    1399             :                                         &now),
    1400             :     GNUNET_GETOPT_OPTION_END
    1401             :   };
    1402             : 
    1403           8 :   GNUNET_assert (GNUNET_OK ==
    1404             :                  GNUNET_log_setup ("taler-exchange-keyup",
    1405             :                                    "WARNING",
    1406             :                                    NULL));
    1407           8 :   now = GNUNET_TIME_absolute_get ();
    1408           8 :   if (GNUNET_OK !=
    1409           8 :       GNUNET_PROGRAM_run (argc, argv,
    1410             :                          "taler-exchange-keyup",
    1411             :                           "Setup signing and denomination keys for a Taler exchange",
    1412             :                           options,
    1413             :                           &run, NULL))
    1414           0 :     return 1;
    1415           8 :   if (NULL != auditor_output_file)
    1416             :   {
    1417           3 :     FCLOSE (auditor_output_file);
    1418           3 :     auditor_output_file = NULL;
    1419             :   }
    1420           8 :   return global_ret;
    1421             : }
    1422             : 
    1423             : /* end of taler-exchange-keyup.c */

Generated by: LCOV version 1.13