exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

exchange_api_get-management-keys.c (13349B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2015-2026 Taler Systems SA
      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
     15   <http://www.gnu.org/licenses/>
     16 */
     17 /**
     18  * @file lib/exchange_api_get-management-keys.c
     19  * @brief functions to obtain future online keys of the exchange
     20  * @author Christian Grothoff
     21  */
     22 #include "taler/taler_json_lib.h"
     23 #include <gnunet/gnunet_curl_lib.h>
     24 #include <microhttpd.h>
     25 #include "taler/exchange/get-management-keys.h"
     26 #include "exchange_api_curl_defaults.h"
     27 #include "taler/taler_signatures.h"
     28 #include "taler/taler_curl_lib.h"
     29 #include "taler/taler_util.h"
     30 
     31 /**
     32  * Set to 1 for extra debug logging.
     33  */
     34 #define DEBUG 0
     35 
     36 
     37 /**
     38  * @brief Handle for a GET /management/keys request.
     39  */
     40 struct TALER_EXCHANGE_GetManagementKeysHandle
     41 {
     42 
     43   /**
     44    * The base URL for this request.
     45    */
     46   char *base_url;
     47 
     48   /**
     49    * The full URL for this request, set during _start.
     50    */
     51   char *url;
     52 
     53   /**
     54    * Handle for the request.
     55    */
     56   struct GNUNET_CURL_Job *job;
     57 
     58   /**
     59    * Function to call with the result.
     60    */
     61   TALER_EXCHANGE_GetManagementKeysCallback cb;
     62 
     63   /**
     64    * Closure for @a cb.
     65    */
     66   TALER_EXCHANGE_GET_MANAGEMENT_KEYS_RESULT_CLOSURE *cb_cls;
     67 
     68   /**
     69    * Reference to the execution context.
     70    */
     71   struct GNUNET_CURL_Context *ctx;
     72 
     73 };
     74 
     75 
     76 /**
     77  * Handle the case that the response was of type #MHD_HTTP_OK.
     78  *
     79  * @param[in,out] gmkh request handle
     80  * @param response the response
     81  * @return #GNUNET_OK if the response was well-formed
     82  */
     83 static enum GNUNET_GenericReturnValue
     84 handle_ok (struct TALER_EXCHANGE_GetManagementKeysHandle *gmkh,
     85            const json_t *response)
     86 {
     87   struct TALER_EXCHANGE_GetManagementKeysResponse gkr = {
     88     .hr.http_status = MHD_HTTP_OK,
     89     .hr.reply = response,
     90   };
     91   struct TALER_EXCHANGE_FutureKeys *fk
     92     = &gkr.details.ok.keys;
     93   const json_t *sk;
     94   const json_t *dk;
     95   bool ok;
     96   struct GNUNET_JSON_Specification spec[] = {
     97     GNUNET_JSON_spec_array_const ("future_denoms",
     98                                   &dk),
     99     GNUNET_JSON_spec_array_const ("future_signkeys",
    100                                   &sk),
    101     GNUNET_JSON_spec_fixed_auto ("master_pub",
    102                                  &fk->master_pub),
    103     GNUNET_JSON_spec_fixed_auto ("denom_secmod_public_key",
    104                                  &fk->denom_secmod_public_key),
    105     GNUNET_JSON_spec_fixed_auto ("denom_secmod_cs_public_key",
    106                                  &fk->denom_secmod_cs_public_key),
    107     GNUNET_JSON_spec_fixed_auto ("signkey_secmod_public_key",
    108                                  &fk->signkey_secmod_public_key),
    109     GNUNET_JSON_spec_end ()
    110   };
    111 
    112   if (GNUNET_OK !=
    113       GNUNET_JSON_parse (response,
    114                          spec,
    115                          NULL, NULL))
    116   {
    117     GNUNET_break_op (0);
    118     return GNUNET_SYSERR;
    119   }
    120   fk->num_sign_keys = json_array_size (sk);
    121   fk->num_denom_keys = json_array_size (dk);
    122   fk->sign_keys = GNUNET_new_array (
    123     fk->num_sign_keys,
    124     struct TALER_EXCHANGE_FutureSigningPublicKey);
    125   fk->denom_keys = GNUNET_new_array (
    126     fk->num_denom_keys,
    127     struct TALER_EXCHANGE_FutureDenomPublicKey);
    128   ok = true;
    129   for (unsigned int i = 0; i < fk->num_sign_keys; i++)
    130   {
    131     json_t *j = json_array_get (sk,
    132                                 i);
    133     struct TALER_EXCHANGE_FutureSigningPublicKey *sign_key
    134       = &fk->sign_keys[i];
    135     struct GNUNET_JSON_Specification ispec[] = {
    136       GNUNET_JSON_spec_fixed_auto ("key",
    137                                    &sign_key->key),
    138       GNUNET_JSON_spec_fixed_auto ("signkey_secmod_sig",
    139                                    &sign_key->signkey_secmod_sig),
    140       GNUNET_JSON_spec_timestamp ("stamp_start",
    141                                   &sign_key->valid_from),
    142       GNUNET_JSON_spec_timestamp ("stamp_expire",
    143                                   &sign_key->valid_until),
    144       GNUNET_JSON_spec_timestamp ("stamp_end",
    145                                   &sign_key->valid_legal),
    146       GNUNET_JSON_spec_end ()
    147     };
    148 
    149     if (GNUNET_OK !=
    150         GNUNET_JSON_parse (j,
    151                            ispec,
    152                            NULL, NULL))
    153     {
    154       GNUNET_break_op (0);
    155       ok = false;
    156       break;
    157     }
    158     {
    159       struct GNUNET_TIME_Relative duration
    160         = GNUNET_TIME_absolute_get_difference (sign_key->valid_from.abs_time,
    161                                                sign_key->valid_until.abs_time);
    162 
    163       if (GNUNET_OK !=
    164           TALER_exchange_secmod_eddsa_verify (
    165             &sign_key->key,
    166             sign_key->valid_from,
    167             duration,
    168             &fk->signkey_secmod_public_key,
    169             &sign_key->signkey_secmod_sig))
    170       {
    171         GNUNET_break_op (0);
    172         ok = false;
    173         break;
    174       }
    175     }
    176   }
    177   for (unsigned int i = 0; i < fk->num_denom_keys; i++)
    178   {
    179     json_t *j = json_array_get (dk,
    180                                 i);
    181     struct TALER_EXCHANGE_FutureDenomPublicKey *denom_key
    182       = &fk->denom_keys[i];
    183     const char *section_name;
    184     struct GNUNET_JSON_Specification ispec[] = {
    185       TALER_JSON_spec_amount_any ("value",
    186                                   &denom_key->value),
    187       GNUNET_JSON_spec_timestamp ("stamp_start",
    188                                   &denom_key->valid_from),
    189       GNUNET_JSON_spec_timestamp ("stamp_expire_withdraw",
    190                                   &denom_key->withdraw_valid_until),
    191       GNUNET_JSON_spec_timestamp ("stamp_expire_deposit",
    192                                   &denom_key->expire_deposit),
    193       GNUNET_JSON_spec_timestamp ("stamp_expire_legal",
    194                                   &denom_key->expire_legal),
    195       TALER_JSON_spec_denom_pub ("denom_pub",
    196                                  &denom_key->key),
    197       TALER_JSON_spec_amount_any ("fee_withdraw",
    198                                   &denom_key->fee_withdraw),
    199       TALER_JSON_spec_amount_any ("fee_deposit",
    200                                   &denom_key->fee_deposit),
    201       TALER_JSON_spec_amount_any ("fee_refresh",
    202                                   &denom_key->fee_refresh),
    203       TALER_JSON_spec_amount_any ("fee_refund",
    204                                   &denom_key->fee_refund),
    205       GNUNET_JSON_spec_fixed_auto ("denom_secmod_sig",
    206                                    &denom_key->denom_secmod_sig),
    207       GNUNET_JSON_spec_string ("section_name",
    208                                &section_name),
    209       GNUNET_JSON_spec_end ()
    210     };
    211 
    212     if (GNUNET_OK !=
    213         GNUNET_JSON_parse (j,
    214                            ispec,
    215                            NULL, NULL))
    216     {
    217       GNUNET_break_op (0);
    218 #if DEBUG
    219       json_dumpf (j,
    220                   stderr,
    221                   JSON_INDENT (2));
    222 #endif
    223       ok = false;
    224       break;
    225     }
    226 
    227     {
    228       struct TALER_DenominationHashP h_denom_pub;
    229       struct GNUNET_TIME_Relative duration
    230         = GNUNET_TIME_absolute_get_difference (
    231             denom_key->valid_from.abs_time,
    232             denom_key->withdraw_valid_until.abs_time);
    233 
    234       TALER_denom_pub_hash (&denom_key->key,
    235                             &h_denom_pub);
    236       switch (denom_key->key.bsign_pub_key->cipher)
    237       {
    238       case GNUNET_CRYPTO_BSA_RSA:
    239         {
    240           struct TALER_RsaPubHashP h_rsa;
    241 
    242           TALER_rsa_pub_hash (
    243             denom_key->key.bsign_pub_key->details.rsa_public_key,
    244             &h_rsa);
    245           if (GNUNET_OK !=
    246               TALER_exchange_secmod_rsa_verify (&h_rsa,
    247                                                 section_name,
    248                                                 denom_key->valid_from,
    249                                                 duration,
    250                                                 &fk->denom_secmod_public_key,
    251                                                 &denom_key->denom_secmod_sig))
    252           {
    253             GNUNET_break_op (0);
    254             ok = false;
    255             break;
    256           }
    257         }
    258         break;
    259       case GNUNET_CRYPTO_BSA_CS:
    260         {
    261           struct TALER_CsPubHashP h_cs;
    262 
    263           TALER_cs_pub_hash (
    264             &denom_key->key.bsign_pub_key->details.cs_public_key,
    265             &h_cs);
    266           if (GNUNET_OK !=
    267               TALER_exchange_secmod_cs_verify (&h_cs,
    268                                                section_name,
    269                                                denom_key->valid_from,
    270                                                duration,
    271                                                &fk->denom_secmod_cs_public_key,
    272                                                &denom_key->denom_secmod_sig))
    273           {
    274             GNUNET_break_op (0);
    275             ok = false;
    276             break;
    277           }
    278         }
    279         break;
    280       default:
    281         GNUNET_break_op (0);
    282         ok = false;
    283         break;
    284       }
    285     }
    286     if (! ok)
    287       break;
    288   }
    289   if (ok)
    290   {
    291     gmkh->cb (gmkh->cb_cls,
    292               &gkr);
    293   }
    294   for (unsigned int i = 0; i < fk->num_denom_keys; i++)
    295     TALER_denom_pub_free (&fk->denom_keys[i].key);
    296   GNUNET_free (fk->sign_keys);
    297   GNUNET_free (fk->denom_keys);
    298   return (ok) ? GNUNET_OK : GNUNET_SYSERR;
    299 }
    300 
    301 
    302 /**
    303  * Function called when we're done processing the
    304  * HTTP GET /management/keys request.
    305  *
    306  * @param cls the `struct TALER_EXCHANGE_GetManagementKeysHandle`
    307  * @param response_code HTTP response code, 0 on error
    308  * @param response response body, NULL if not in JSON
    309  */
    310 static void
    311 handle_get_keys_finished (void *cls,
    312                           long response_code,
    313                           const void *response)
    314 {
    315   struct TALER_EXCHANGE_GetManagementKeysHandle *gmkh = cls;
    316   const json_t *json = response;
    317   struct TALER_EXCHANGE_GetManagementKeysResponse gkr = {
    318     .hr.http_status = (unsigned int) response_code,
    319     .hr.reply = json
    320   };
    321 
    322   gmkh->job = NULL;
    323   switch (response_code)
    324   {
    325   case MHD_HTTP_OK:
    326     if (GNUNET_OK ==
    327         handle_ok (gmkh,
    328                    response))
    329     {
    330       gmkh->cb = NULL;
    331     }
    332     else
    333     {
    334       response_code = 0;
    335     }
    336     break;
    337   case MHD_HTTP_NOT_FOUND:
    338     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    339                 "Server did not find handler at `%s'. Did you configure the correct exchange base URL?\n",
    340                 gmkh->url);
    341     if (NULL != json)
    342     {
    343       gkr.hr.ec = TALER_JSON_get_error_code (json);
    344       gkr.hr.hint = TALER_JSON_get_error_hint (json);
    345     }
    346     else
    347     {
    348       gkr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    349       gkr.hr.hint = TALER_ErrorCode_get_hint (gkr.hr.ec);
    350     }
    351     break;
    352   default:
    353     /* unexpected response code */
    354     if (NULL != json)
    355     {
    356       gkr.hr.ec = TALER_JSON_get_error_code (json);
    357       gkr.hr.hint = TALER_JSON_get_error_hint (json);
    358     }
    359     else
    360     {
    361       gkr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    362       gkr.hr.hint = TALER_ErrorCode_get_hint (gkr.hr.ec);
    363     }
    364     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    365                 "Unexpected response code %u/%d for exchange management get keys\n",
    366                 (unsigned int) response_code,
    367                 (int) gkr.hr.ec);
    368     break;
    369   }
    370   if (NULL != gmkh->cb)
    371   {
    372     gmkh->cb (gmkh->cb_cls,
    373               &gkr);
    374     gmkh->cb = NULL;
    375   }
    376   TALER_EXCHANGE_get_management_keys_cancel (gmkh);
    377 }
    378 
    379 
    380 struct TALER_EXCHANGE_GetManagementKeysHandle *
    381 TALER_EXCHANGE_get_management_keys_create (
    382   struct GNUNET_CURL_Context *ctx,
    383   const char *url)
    384 {
    385   struct TALER_EXCHANGE_GetManagementKeysHandle *gmkh;
    386 
    387   gmkh = GNUNET_new (struct TALER_EXCHANGE_GetManagementKeysHandle);
    388   gmkh->ctx = ctx;
    389   gmkh->base_url = GNUNET_strdup (url);
    390   return gmkh;
    391 }
    392 
    393 
    394 enum TALER_ErrorCode
    395 TALER_EXCHANGE_get_management_keys_start (
    396   struct TALER_EXCHANGE_GetManagementKeysHandle *gmkh,
    397   TALER_EXCHANGE_GetManagementKeysCallback cb,
    398   TALER_EXCHANGE_GET_MANAGEMENT_KEYS_RESULT_CLOSURE *cb_cls)
    399 {
    400   CURL *eh;
    401 
    402   gmkh->cb = cb;
    403   gmkh->cb_cls = cb_cls;
    404   gmkh->url = TALER_url_join (gmkh->base_url,
    405                               "management/keys",
    406                               NULL);
    407   if (NULL == gmkh->url)
    408   {
    409     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    410                 "Could not construct request URL.\n");
    411     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    412   }
    413   eh = TALER_EXCHANGE_curl_easy_get_ (gmkh->url);
    414   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    415               "Requesting URL '%s'\n",
    416               gmkh->url);
    417   gmkh->job = GNUNET_CURL_job_add (gmkh->ctx,
    418                                    eh,
    419                                    &handle_get_keys_finished,
    420                                    gmkh);
    421   if (NULL == gmkh->job)
    422   {
    423     GNUNET_free (gmkh->url);
    424     gmkh->url = NULL;
    425     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    426   }
    427   return TALER_EC_NONE;
    428 }
    429 
    430 
    431 void
    432 TALER_EXCHANGE_get_management_keys_cancel (
    433   struct TALER_EXCHANGE_GetManagementKeysHandle *gmkh)
    434 {
    435   if (NULL != gmkh->job)
    436   {
    437     GNUNET_CURL_job_cancel (gmkh->job);
    438     gmkh->job = NULL;
    439   }
    440   GNUNET_free (gmkh->url);
    441   GNUNET_free (gmkh->base_url);
    442   GNUNET_free (gmkh);
    443 }
    444 
    445 
    446 /* end of exchange_api_get-management-keys.c */