LCOV - code coverage report
Current view: top level - lib - exchange_api_management_get_keys.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 113 161 70.2 %
Date: 2025-06-05 21:03:14 Functions: 4 4 100.0 %

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

Generated by: LCOV version 1.16