LCOV - code coverage report
Current view: top level - exchangedb - exchangedb_denomkeys.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 91 114 79.8 %
Date: 2017-11-25 11:31:41 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2017 Inria & 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 exchangedb/exchangedb_denomkeys.c
      18             :  * @brief I/O operations for the Exchange's denomination private keys
      19             :  * @author Florian Dold
      20             :  * @author Benedikt Mueller
      21             :  * @author Sree Harsha Totakura
      22             :  * @author Christian Grothoff
      23             :  */
      24             : #include "platform.h"
      25             : #include "taler_exchangedb_lib.h"
      26             : 
      27             : 
      28             : /**
      29             :  * Mark the given denomination key as revoked and request the wallets
      30             :  * to initiate /payback.
      31             :  *
      32             :  * @param exchange_base_dir base directory for the exchange,
      33             :  *                      the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS
      34             :  *                      subdirectory
      35             :  * @param alias coin alias
      36             :  * @param dki the denomination key to revoke
      37             :  * @param mpriv master private key to sign
      38             :  * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure.
      39             :  */
      40             : int
      41           3 : TALER_EXCHANGEDB_denomination_key_revoke (const char *exchange_base_dir,
      42             :                                           const char *alias,
      43             :                                           const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
      44             :                                           const struct TALER_MasterPrivateKeyP *mpriv)
      45             : {
      46             :   struct GNUNET_TIME_Absolute start;
      47             :   struct TALER_MasterDenominationKeyRevocation rm;
      48             :   struct TALER_MasterSignatureP msig;
      49             :   char *fn;
      50             :   struct GNUNET_DISK_FileHandle *fh;
      51             :   ssize_t wrote;
      52             :   int ret;
      53             : 
      54           3 :   ret = GNUNET_SYSERR;
      55           3 :   start = GNUNET_TIME_absolute_ntoh (dki->issue.properties.start);
      56           3 :   GNUNET_asprintf (&fn,
      57             :                    "%s" DIR_SEPARATOR_STR
      58             :                    TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS DIR_SEPARATOR_STR
      59             :                    "%s" DIR_SEPARATOR_STR
      60             :                    "%llu.rev",
      61             :                    exchange_base_dir,
      62             :                    alias,
      63           3 :                    (unsigned long long) start.abs_value_us);
      64             : 
      65           3 :   rm.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED);
      66           3 :   rm.purpose.size = htonl (sizeof (rm));
      67           3 :   rm.h_denom_pub = dki->issue.properties.denom_hash;
      68           3 :   GNUNET_assert (GNUNET_OK ==
      69             :                  GNUNET_CRYPTO_eddsa_sign (&mpriv->eddsa_priv,
      70             :                                            &rm.purpose,
      71             :                                            &msig.eddsa_signature));
      72           3 :   if (NULL == (fh = GNUNET_DISK_file_open
      73             :                (fn,
      74             :                 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_TRUNCATE,
      75             :                 GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)))
      76           0 :     goto cleanup;
      77           3 :   if (GNUNET_SYSERR ==
      78             :       (wrote = GNUNET_DISK_file_write (fh,
      79             :                                        &msig,
      80             :                                        sizeof (msig))))
      81           0 :     goto cleanup;
      82           3 :   if (wrote != sizeof (msig))
      83           0 :     goto cleanup;
      84           3 :   ret = GNUNET_OK;
      85             : cleanup:
      86           3 :   if (NULL != fh)
      87           3 :     (void) GNUNET_DISK_file_close (fh);
      88           3 :   GNUNET_free (fn);
      89           3 :   return ret;
      90             : }
      91             : 
      92             : 
      93             : /**
      94             :  * Import a denomination key from the given file.
      95             :  *
      96             :  * @param filename the file to import the key from
      97             :  * @param[out] dki set to the imported denomination key
      98             :  * @return #GNUNET_OK upon success;
      99             :  *         #GNUNET_SYSERR upon failure
     100             :  */
     101             : int
     102          44 : TALER_EXCHANGEDB_denomination_key_read (const char *filename,
     103             :                                         struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
     104             : {
     105             :   uint64_t size;
     106             :   size_t offset;
     107             :   void *data;
     108             :   struct GNUNET_CRYPTO_RsaPrivateKey *priv;
     109             : 
     110          44 :   if (GNUNET_OK !=
     111          44 :       GNUNET_DISK_file_size (filename,
     112             :                              &size,
     113             :                              GNUNET_YES,
     114             :                              GNUNET_YES))
     115             :   {
     116           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     117             :                 "Skipping inaccessable denomination key file `%s'\n",
     118             :                 filename);
     119           0 :     return GNUNET_SYSERR;
     120             :   }
     121          44 :   offset = sizeof (struct TALER_EXCHANGEDB_DenominationKeyInformationP);
     122          44 :   if (size <= offset)
     123             :   {
     124           0 :     GNUNET_break (0);
     125           0 :     return GNUNET_SYSERR;
     126             :   }
     127          44 :   data = GNUNET_malloc (size);
     128          44 :   if (size !=
     129          44 :       GNUNET_DISK_fn_read (filename,
     130             :                            data,
     131             :                            size))
     132             :   {
     133           0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
     134             :                               "read",
     135             :                               filename);
     136           0 :     GNUNET_free (data);
     137           0 :     return GNUNET_SYSERR;
     138             :   }
     139          44 :   if (NULL ==
     140          44 :       (priv = GNUNET_CRYPTO_rsa_private_key_decode (data + offset,
     141             :                                                     size - offset)))
     142             :   {
     143           0 :     GNUNET_free (data);
     144           0 :     return GNUNET_SYSERR;
     145             :   }
     146          44 :   GNUNET_assert (NULL == dki->denom_priv.rsa_private_key);
     147          44 :   dki->denom_priv.rsa_private_key = priv;
     148             :   dki->denom_pub.rsa_public_key
     149          44 :     = GNUNET_CRYPTO_rsa_private_key_get_public (priv);
     150          44 :   memcpy (&dki->issue,
     151             :           data,
     152             :           offset);
     153          44 :   GNUNET_free (data);
     154          44 :   return GNUNET_OK;
     155             : }
     156             : 
     157             : 
     158             : /**
     159             :  * Exports a denomination key to the given file.
     160             :  *
     161             :  * @param filename the file where to write the denomination key
     162             :  * @param dki the denomination key
     163             :  * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure.
     164             :  */
     165             : int
     166         113 : TALER_EXCHANGEDB_denomination_key_write (const char *filename,
     167             :                                          const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
     168             : {
     169             :   char *priv_enc;
     170             :   size_t priv_enc_size;
     171             :   struct GNUNET_DISK_FileHandle *fh;
     172             :   ssize_t wrote;
     173             :   size_t wsize;
     174             :   int ret;
     175             : 
     176         113 :   fh = NULL;
     177             :   priv_enc_size
     178         113 :     = GNUNET_CRYPTO_rsa_private_key_encode (dki->denom_priv.rsa_private_key,
     179             :                                             &priv_enc);
     180         113 :   ret = GNUNET_SYSERR;
     181         113 :   if (GNUNET_OK !=
     182         113 :       GNUNET_DISK_directory_create_for_file (filename))
     183           0 :     return GNUNET_SYSERR;
     184         113 :   if (NULL == (fh = GNUNET_DISK_file_open
     185             :                (filename,
     186             :                 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_TRUNCATE,
     187             :                 GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)))
     188           0 :     goto cleanup;
     189         113 :   wsize = sizeof (struct TALER_EXCHANGEDB_DenominationKeyInformationP);
     190         113 :   if (GNUNET_SYSERR == (wrote = GNUNET_DISK_file_write (fh,
     191         113 :                                                         &dki->issue,
     192             :                                                         wsize)))
     193           0 :     goto cleanup;
     194         113 :   if (wrote != wsize)
     195           0 :     goto cleanup;
     196         113 :   if (GNUNET_SYSERR ==
     197         113 :       (wrote = GNUNET_DISK_file_write (fh,
     198             :                                        priv_enc,
     199             :                                        priv_enc_size)))
     200           0 :     goto cleanup;
     201         113 :   if (wrote != priv_enc_size)
     202           0 :     goto cleanup;
     203         113 :   ret = GNUNET_OK;
     204             :  cleanup:
     205         113 :   GNUNET_free_non_null (priv_enc);
     206         113 :   if (NULL != fh)
     207         113 :     (void) GNUNET_DISK_file_close (fh);
     208         113 :   return ret;
     209             : }
     210             : 
     211             : 
     212             : /**
     213             :  * Closure for #denomkeys_iterate_keydir_iter() and
     214             :  * #denomkeys_iterate_topdir_iter().
     215             :  */
     216             : struct DenomkeysIterateContext
     217             : {
     218             : 
     219             :   /**
     220             :    * Set to the name of the directory below the top-level directory
     221             :    * during the call to #denomkeys_iterate_keydir_iter().
     222             :    */
     223             :   const char *alias;
     224             : 
     225             :   /**
     226             :    * Master public key to use to validate revocations.
     227             :    */
     228             :   const struct TALER_MasterPublicKeyP *master_pub;
     229             : 
     230             :   /**
     231             :    * Function to call on each denomination key.
     232             :    */
     233             :   TALER_EXCHANGEDB_DenominationKeyIterator it;
     234             : 
     235             :   /**
     236             :    * Closure for @e it.
     237             :    */
     238             :   void *it_cls;
     239             : };
     240             : 
     241             : 
     242             : /**
     243             :  * Decode the denomination key in the given file @a filename and call
     244             :  * the callback in @a cls with the information.
     245             :  *
     246             :  * @param cls the `struct DenomkeysIterateContext *`
     247             :  * @param filename name of a file that should contain
     248             :  *                 a denomination key
     249             :  * @return #GNUNET_OK to continue to iterate
     250             :  *         #GNUNET_NO to abort iteration with success
     251             :  *         #GNUNET_SYSERR to abort iteration with failure
     252             :  */
     253             : static int
     254          48 : denomkeys_iterate_keydir_iter (void *cls,
     255             :                                const char *filename)
     256             : {
     257          48 :   struct DenomkeysIterateContext *dic = cls;
     258             :   struct TALER_EXCHANGEDB_DenominationKeyIssueInformation issue;
     259             :   int ret;
     260             :   char *rev;
     261             :   struct TALER_MasterSignatureP msig;
     262             :   struct TALER_MasterDenominationKeyRevocation rm;
     263             :   const struct TALER_MasterSignatureP *revoked;
     264             : 
     265          96 :   if ( (strlen(filename) > strlen (".rev")) &&
     266          48 :        (0 == strcmp (&filename[strlen(filename) - strlen (".rev")],
     267             :                      ".rev")) )
     268           5 :     return GNUNET_OK; /* ignore revocation files _here_; we'll try for them just below */
     269             : 
     270          43 :   memset (&issue, 0, sizeof (issue));
     271          43 :   if (GNUNET_OK !=
     272          43 :       TALER_EXCHANGEDB_denomination_key_read (filename,
     273             :                                               &issue))
     274             :   {
     275           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     276             :                 "Invalid denomkey file: '%s'\n",
     277             :                 filename);
     278           0 :     return GNUNET_OK;
     279             :   }
     280             :   /* check for revocation file */
     281          43 :   GNUNET_asprintf (&rev,
     282             :                    "%s.rev",
     283             :                    filename);
     284          43 :   revoked = NULL;
     285          43 :   if (GNUNET_YES == GNUNET_DISK_file_test (rev))
     286             :   {
     287             :     /* Check if revocation is valid... */
     288           5 :     if (sizeof (msig) !=
     289           5 :         GNUNET_DISK_fn_read (rev,
     290             :                              &msig,
     291             :                              sizeof (msig)))
     292             :     {
     293           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     294             :                   _("Invalid revocation file `%s' found and ignored (bad size)\n"),
     295             :                   rev);
     296             :     }
     297             :     else
     298             :     {
     299           5 :       rm.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED);
     300           5 :       rm.purpose.size = htonl (sizeof (rm));
     301           5 :       rm.h_denom_pub = issue.issue.properties.denom_hash;
     302           5 :       if (GNUNET_OK !=
     303           5 :           GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED,
     304             :                                       &rm.purpose,
     305             :                                       &msig.eddsa_signature,
     306           5 :                                       &dic->master_pub->eddsa_pub))
     307             :       {
     308           0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     309             :                     _("Invalid revocation file `%s' found and ignored (bad signature)\n"),
     310             :                     rev);
     311             :       }
     312             :       else
     313             :       {
     314           5 :         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     315             :                     "Denomination key `%s' was revoked!\n",
     316             :                    filename);
     317           5 :         revoked = &msig;
     318             :       }
     319             :     }
     320             :   }
     321          43 :   GNUNET_free (rev);
     322          43 :   ret = dic->it (dic->it_cls,
     323             :                  dic->alias,
     324             :                  &issue,
     325             :                  revoked);
     326          43 :   GNUNET_CRYPTO_rsa_private_key_free (issue.denom_priv.rsa_private_key);
     327          43 :   GNUNET_CRYPTO_rsa_public_key_free (issue.denom_pub.rsa_public_key);
     328          43 :   return ret;
     329             : }
     330             : 
     331             : 
     332             : /**
     333             :  * Function called on each subdirectory in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS.  Will
     334             :  * call the #denomkeys_iterate_keydir_iter() on each file in the
     335             :  * subdirectory.
     336             :  *
     337             :  * @param cls the `struct DenomkeysIterateContext *`
     338             :  * @param filename name of the subdirectory to scan
     339             :  * @return #GNUNET_OK on success,
     340             :  *         #GNUNET_SYSERR if we need to abort
     341             :  */
     342             : static int
     343          33 : denomkeys_iterate_topdir_iter (void *cls,
     344             :                                const char *filename)
     345             : {
     346          33 :   struct DenomkeysIterateContext *dic = cls;
     347             : 
     348          33 :   dic->alias = GNUNET_STRINGS_get_short_name (filename);
     349          33 :   if (0 > GNUNET_DISK_directory_scan (filename,
     350             :                                       &denomkeys_iterate_keydir_iter,
     351             :                                       dic))
     352           0 :     return GNUNET_SYSERR;
     353          33 :   return GNUNET_OK;
     354             : }
     355             : 
     356             : 
     357             : /**
     358             :  * Call @a it for each denomination key found in the @a exchange_base_dir.
     359             :  *
     360             :  * @param exchange_base_dir base directory for the exchange,
     361             :  *                      the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS
     362             :  *                      subdirectory
     363             :  * @param master_pub master public key (used to check revocations)
     364             :  * @param it function to call on each denomination key found
     365             :  * @param it_cls closure for @a it
     366             :  * @return -1 on error, 0 if no files were found, otherwise
     367             :  *         a positive number (however, even with a positive
     368             :  *         number it is possible that @a it was never called
     369             :  *         as maybe none of the files were well-formed)
     370             :  */
     371             : int
     372          10 : TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir,
     373             :                                             const struct TALER_MasterPublicKeyP *master_pub,
     374             :                                             TALER_EXCHANGEDB_DenominationKeyIterator it,
     375             :                                             void *it_cls)
     376             : {
     377             :   char *dir;
     378             :   struct DenomkeysIterateContext dic;
     379             :   int ret;
     380             : 
     381          10 :   GNUNET_asprintf (&dir,
     382             :                    "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS,
     383             :                    exchange_base_dir);
     384          10 :   dic.master_pub = master_pub;
     385          10 :   dic.it = it;
     386          10 :   dic.it_cls = it_cls;
     387          10 :   ret = GNUNET_DISK_directory_scan (dir,
     388             :                                     &denomkeys_iterate_topdir_iter,
     389             :                                     &dic);
     390          10 :   GNUNET_free (dir);
     391          10 :   return ret;
     392             : }
     393             : 
     394             : 
     395             : /* end of exchangedb_denomkeys.c */

Generated by: LCOV version 1.13