LCOV - code coverage report
Current view: top level - lib - exchange_api_management_get_keys.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 106 133 79.7 %
Date: 2021-08-30 06:43:37 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14