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 (13425B)


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