LCOV - code coverage report
Current view: top level - exchange - taler-exchange-httpd_management_post_keys.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 99 199 49.7 %
Date: 2025-07-14 11:22:44 Functions: 3 5 60.0 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2020-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 Affero 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 Affero General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU Affero General Public License along with
      14             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : /**
      17             :  * @file taler-exchange-httpd_management_post_keys.c
      18             :  * @brief Handle request to POST /management/keys
      19             :  * @author Christian Grothoff
      20             :  */
      21             : #include "taler/platform.h"
      22             : #include <gnunet/gnunet_util_lib.h>
      23             : #include <gnunet/gnunet_json_lib.h>
      24             : #include <jansson.h>
      25             : #include <microhttpd.h>
      26             : #include <pthread.h>
      27             : #include "taler/taler_json_lib.h"
      28             : #include "taler/taler_mhd_lib.h"
      29             : #include "taler/taler_signatures.h"
      30             : #include "taler-exchange-httpd_keys.h"
      31             : #include "taler-exchange-httpd_management.h"
      32             : #include "taler-exchange-httpd_responses.h"
      33             : 
      34             : 
      35             : /**
      36             :  * Denomination signature provided.
      37             :  */
      38             : struct DenomSig
      39             : {
      40             :   /**
      41             :    * Hash of a denomination public key.
      42             :    */
      43             :   struct TALER_DenominationHashP h_denom_pub;
      44             : 
      45             :   /**
      46             :    * Master signature for the @e h_denom_pub.
      47             :    */
      48             :   struct TALER_MasterSignatureP master_sig;
      49             : 
      50             :   /**
      51             :    * Fee structure for this key, as per our configuration.
      52             :    */
      53             :   struct TALER_EXCHANGEDB_DenominationKeyMetaData meta;
      54             : 
      55             :   /**
      56             :    * The full public key.
      57             :    */
      58             :   struct TALER_DenominationPublicKey denom_pub;
      59             : 
      60             : };
      61             : 
      62             : 
      63             : /**
      64             :  * Signkey signature provided.
      65             :  */
      66             : struct SigningSig
      67             : {
      68             :   /**
      69             :    * Online signing key of the exchange.
      70             :    */
      71             :   struct TALER_ExchangePublicKeyP exchange_pub;
      72             : 
      73             :   /**
      74             :    * Master signature for the @e exchange_pub.
      75             :    */
      76             :   struct TALER_MasterSignatureP master_sig;
      77             : 
      78             :   /**
      79             :    * Our meta data on this key.
      80             :    */
      81             :   struct TALER_EXCHANGEDB_SignkeyMetaData meta;
      82             : 
      83             : };
      84             : 
      85             : 
      86             : /**
      87             :  * Closure for the #add_keys transaction.
      88             :  */
      89             : struct AddKeysContext
      90             : {
      91             : 
      92             :   /**
      93             :    * Array of @e nd_sigs denomination signatures.
      94             :    */
      95             :   struct DenomSig *d_sigs;
      96             : 
      97             :   /**
      98             :    * Array of @e ns_sigs signkey signatures.
      99             :    */
     100             :   struct SigningSig *s_sigs;
     101             : 
     102             :   /**
     103             :    * Our key state.
     104             :    */
     105             :   struct TEH_KeyStateHandle *ksh;
     106             : 
     107             :   /**
     108             :    * Length of the d_sigs array.
     109             :    */
     110             :   unsigned int nd_sigs;
     111             : 
     112             :   /**
     113             :    * Length of the n_sigs array.
     114             :    */
     115             :   unsigned int ns_sigs;
     116             : 
     117             : };
     118             : 
     119             : 
     120             : /**
     121             :  * Compare meta-data of two denomination keys for equality,
     122             :  * except for the "serial" number.
     123             :  *
     124             :  * @param m1 meta data to compare to @a m2
     125             :  * @param m2 meta data to compare to @a m1
     126             :  * @return true if both are equal
     127             :  */
     128             : static bool
     129           0 : denomination_meta_cmp (
     130             :   const struct TALER_EXCHANGEDB_DenominationKeyMetaData *m1,
     131             :   const struct TALER_EXCHANGEDB_DenominationKeyMetaData *m2)
     132             : {
     133           0 :   if ( (GNUNET_TIME_timestamp_cmp (m1->start,
     134             :                                    !=,
     135           0 :                                    m2->start)) ||
     136           0 :        (GNUNET_TIME_timestamp_cmp (m1->expire_withdraw,
     137             :                                    !=,
     138           0 :                                    m2->expire_withdraw)) ||
     139           0 :        (GNUNET_TIME_timestamp_cmp (m1->expire_deposit,
     140             :                                    !=,
     141           0 :                                    m2->expire_deposit)) ||
     142           0 :        (GNUNET_TIME_timestamp_cmp (m1->expire_legal,
     143             :                                    !=,
     144             :                                    m2->expire_legal)) )
     145           0 :     return false;
     146           0 :   if (0 !=
     147           0 :       TALER_amount_cmp (&m1->value,
     148             :                         &m2->value))
     149           0 :     return false;
     150           0 :   if (0 !=
     151           0 :       GNUNET_memcmp (&m1->fees,
     152             :                      &m2->fees))
     153           0 :     return false;
     154           0 :   if (m1->age_mask.bits !=
     155           0 :       m2->age_mask.bits)
     156           0 :     return false;
     157           0 :   return true;
     158             : }
     159             : 
     160             : 
     161             : /**
     162             :  * Compare meta-data of two signing keys for equality.
     163             :  *
     164             :  * @param m1 meta data to compare to @a m2
     165             :  * @param m2 meta data to compare to @a m1
     166             :  * @return true if both are equal
     167             :  */
     168             : static bool
     169           0 : signkey_meta_cmp (
     170             :   const struct TALER_EXCHANGEDB_SignkeyMetaData *m1,
     171             :   const struct TALER_EXCHANGEDB_SignkeyMetaData *m2)
     172             : {
     173           0 :   if ( (GNUNET_TIME_timestamp_cmp (m1->start,
     174             :                                    !=,
     175           0 :                                    m2->start)) ||
     176           0 :        (GNUNET_TIME_timestamp_cmp (m1->expire_sign,
     177             :                                    !=,
     178           0 :                                    m2->expire_sign)) ||
     179           0 :        (GNUNET_TIME_timestamp_cmp (m1->expire_legal,
     180             :                                    !=,
     181             :                                    m2->expire_legal)) )
     182           0 :     return false;
     183           0 :   return true;
     184             : }
     185             : 
     186             : 
     187             : /**
     188             :  * Function implementing database transaction to add offline signing keys.
     189             :  * Runs the transaction logic; IF it returns a non-error code, the transaction
     190             :  * logic MUST NOT queue a MHD response.  IF it returns an hard error, the
     191             :  * transaction logic MUST queue a MHD response and set @a mhd_ret.  IF it
     192             :  * returns the soft error code, the function MAY be called again to retry and
     193             :  * MUST not queue a MHD response.
     194             :  *
     195             :  * @param cls closure with a `struct AddKeysContext`
     196             :  * @param connection MHD request which triggered the transaction
     197             :  * @param[out] mhd_ret set to MHD response status for @a connection,
     198             :  *             if transaction failed (!)
     199             :  * @return transaction status
     200             :  */
     201             : static enum GNUNET_DB_QueryStatus
     202          21 : add_keys (void *cls,
     203             :           struct MHD_Connection *connection,
     204             :           MHD_RESULT *mhd_ret)
     205             : {
     206          21 :   struct AddKeysContext *akc = cls;
     207             : 
     208             :   /* activate all denomination keys */
     209        6241 :   for (unsigned int i = 0; i<akc->nd_sigs; i++)
     210             :   {
     211        6220 :     struct DenomSig *d = &akc->d_sigs[i];
     212             :     enum GNUNET_DB_QueryStatus qs;
     213             :     struct TALER_EXCHANGEDB_DenominationKeyMetaData meta;
     214             : 
     215             :     /* For idempotency, check if the key is already active */
     216        6220 :     qs = TEH_plugin->lookup_denomination_key (
     217        6220 :       TEH_plugin->cls,
     218        6220 :       &d->h_denom_pub,
     219             :       &meta);
     220        6220 :     if (qs < 0)
     221             :     {
     222           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     223           0 :         return qs;
     224           0 :       GNUNET_break (0);
     225           0 :       *mhd_ret = TALER_MHD_reply_with_error (connection,
     226             :                                              MHD_HTTP_INTERNAL_SERVER_ERROR,
     227             :                                              TALER_EC_GENERIC_DB_FETCH_FAILED,
     228             :                                              "lookup denomination key");
     229           0 :       return qs;
     230             :     }
     231        6220 :     if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
     232             :     {
     233           0 :       if (! denomination_meta_cmp (&d->meta,
     234             :                                    &meta))
     235             :       {
     236           0 :         GNUNET_break_op (0);
     237           0 :         *mhd_ret = TALER_MHD_reply_with_error (
     238             :           connection,
     239             :           MHD_HTTP_CONFLICT,
     240             :           TALER_EC_EXCHANGE_MANAGEMENT_CONFLICTING_DENOMINATION_META_DATA,
     241             :           "conflicting meta data previously set for the same denomination key");
     242           0 :         return GNUNET_DB_STATUS_HARD_ERROR;
     243             :       }
     244           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     245             :                   "Denomination key %s already active, skipping\n",
     246             :                   GNUNET_h2s (&d->h_denom_pub.hash));
     247           0 :       continue; /* skip, already known */
     248             :     }
     249             : 
     250        6220 :     qs = TEH_plugin->add_denomination_key (
     251        6220 :       TEH_plugin->cls,
     252        6220 :       &d->h_denom_pub,
     253        6220 :       &d->denom_pub,
     254        6220 :       &d->meta,
     255        6220 :       &d->master_sig);
     256        6220 :     if (qs < 0)
     257             :     {
     258           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     259           0 :         return qs;
     260           0 :       GNUNET_break (0);
     261           0 :       *mhd_ret = TALER_MHD_reply_with_error (connection,
     262             :                                              MHD_HTTP_INTERNAL_SERVER_ERROR,
     263             :                                              TALER_EC_GENERIC_DB_STORE_FAILED,
     264             :                                              "activate denomination key");
     265           0 :       return qs;
     266             :     }
     267        6220 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     268             :                 "Added offline signature for denomination `%s'\n",
     269             :                 GNUNET_h2s (&d->h_denom_pub.hash));
     270        6220 :     GNUNET_assert (0 != qs);
     271             :   }
     272             : 
     273          88 :   for (unsigned int i = 0; i<akc->ns_sigs; i++)
     274             :   {
     275          67 :     struct SigningSig *s = &akc->s_sigs[i];
     276             :     enum GNUNET_DB_QueryStatus qs;
     277             :     struct TALER_EXCHANGEDB_SignkeyMetaData meta;
     278             : 
     279          67 :     qs = TEH_plugin->lookup_signing_key (
     280          67 :       TEH_plugin->cls,
     281          67 :       &s->exchange_pub,
     282             :       &meta);
     283          67 :     if (qs < 0)
     284             :     {
     285           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     286           0 :         return qs;
     287           0 :       GNUNET_break (0);
     288           0 :       *mhd_ret = TALER_MHD_reply_with_error (connection,
     289             :                                              MHD_HTTP_INTERNAL_SERVER_ERROR,
     290             :                                              TALER_EC_GENERIC_DB_FETCH_FAILED,
     291             :                                              "lookup signing key");
     292           0 :       return qs;
     293             :     }
     294          67 :     if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
     295             :     {
     296           0 :       if (! signkey_meta_cmp (&s->meta,
     297             :                               &meta))
     298             :       {
     299           0 :         GNUNET_break_op (0);
     300           0 :         *mhd_ret = TALER_MHD_reply_with_error (
     301             :           connection,
     302             :           MHD_HTTP_CONFLICT,
     303             :           TALER_EC_EXCHANGE_MANAGEMENT_CONFLICTING_SIGNKEY_META_DATA,
     304             :           "conflicting meta data previously set for the same signing key");
     305           0 :         return GNUNET_DB_STATUS_HARD_ERROR;
     306             :       }
     307           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     308             :                   "Signing key %s already active, skipping\n",
     309             :                   TALER_B2S (&s->exchange_pub));
     310           0 :       continue;   /* skip, already known */
     311             :     }
     312          67 :     qs = TEH_plugin->activate_signing_key (
     313          67 :       TEH_plugin->cls,
     314          67 :       &s->exchange_pub,
     315          67 :       &s->meta,
     316          67 :       &s->master_sig);
     317          67 :     if (qs < 0)
     318             :     {
     319           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     320           0 :         return qs;
     321           0 :       GNUNET_break (0);
     322           0 :       *mhd_ret = TALER_MHD_reply_with_error (connection,
     323             :                                              MHD_HTTP_INTERNAL_SERVER_ERROR,
     324             :                                              TALER_EC_GENERIC_DB_STORE_FAILED,
     325             :                                              "activate signing key");
     326           0 :       return qs;
     327             :     }
     328          67 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     329             :                 "Added offline signature for signing key `%s'\n",
     330             :                 TALER_B2S (&s->exchange_pub));
     331          67 :     GNUNET_assert (0 != qs);
     332             :   }
     333          21 :   return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; /* only 'success', so >=0, matters here */
     334             : }
     335             : 
     336             : 
     337             : /**
     338             :  * Clean up state in @a akc, but do not free @a akc itself
     339             :  *
     340             :  * @param[in,out] akc state to clean up
     341             :  */
     342             : static void
     343          21 : cleanup_akc (struct AddKeysContext *akc)
     344             : {
     345        6241 :   for (unsigned int i = 0; i<akc->nd_sigs; i++)
     346             :   {
     347        6220 :     struct DenomSig *d = &akc->d_sigs[i];
     348             : 
     349        6220 :     TALER_denom_pub_free (&d->denom_pub);
     350             :   }
     351          21 :   GNUNET_free (akc->d_sigs);
     352          21 :   GNUNET_free (akc->s_sigs);
     353          21 : }
     354             : 
     355             : 
     356             : MHD_RESULT
     357          21 : TEH_handler_management_post_keys (
     358             :   struct MHD_Connection *connection,
     359             :   const json_t *root)
     360             : {
     361          21 :   struct AddKeysContext akc = { 0 };
     362             :   const json_t *denom_sigs;
     363             :   const json_t *signkey_sigs;
     364             :   struct GNUNET_JSON_Specification spec[] = {
     365          21 :     GNUNET_JSON_spec_array_const ("denom_sigs",
     366             :                                   &denom_sigs),
     367          21 :     GNUNET_JSON_spec_array_const ("signkey_sigs",
     368             :                                   &signkey_sigs),
     369          21 :     GNUNET_JSON_spec_end ()
     370             :   };
     371             :   MHD_RESULT ret;
     372             : 
     373             :   {
     374             :     enum GNUNET_GenericReturnValue res;
     375             : 
     376          21 :     res = TALER_MHD_parse_json_data (connection,
     377             :                                      root,
     378             :                                      spec);
     379          21 :     if (GNUNET_SYSERR == res)
     380           0 :       return MHD_NO; /* hard failure */
     381          21 :     if (GNUNET_NO == res)
     382           0 :       return MHD_YES; /* failure */
     383             :   }
     384          21 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     385             :               "Received POST /management/keys request\n");
     386             : 
     387          21 :   akc.ksh = TEH_keys_get_state_for_management_only (); /* may start its own transaction, thus must be done here, before we run ours! */
     388          21 :   if (NULL == akc.ksh)
     389             :   {
     390           0 :     GNUNET_break_op (0);
     391           0 :     return TALER_MHD_reply_with_error (
     392             :       connection,
     393             :       MHD_HTTP_INTERNAL_SERVER_ERROR,
     394             :       TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
     395             :       "no key state (not even for management)");
     396             :   }
     397             : 
     398          21 :   akc.nd_sigs = json_array_size (denom_sigs);
     399          21 :   akc.d_sigs = GNUNET_new_array (akc.nd_sigs,
     400             :                                  struct DenomSig);
     401        6241 :   for (unsigned int i = 0; i<akc.nd_sigs; i++)
     402             :   {
     403        6220 :     struct DenomSig *d = &akc.d_sigs[i];
     404             :     struct GNUNET_JSON_Specification ispec[] = {
     405        6220 :       GNUNET_JSON_spec_fixed_auto ("master_sig",
     406             :                                    &d->master_sig),
     407        6220 :       GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
     408             :                                    &d->h_denom_pub),
     409        6220 :       GNUNET_JSON_spec_end ()
     410             :     };
     411             :     enum GNUNET_GenericReturnValue res;
     412             : 
     413        6220 :     res = TALER_MHD_parse_json_data (connection,
     414        6220 :                                      json_array_get (denom_sigs,
     415             :                                                      i),
     416             :                                      ispec);
     417        6220 :     if (GNUNET_OK != res)
     418             :     {
     419           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     420             :                   "Failure to handle /management/keys\n");
     421           0 :       cleanup_akc (&akc);
     422           0 :       return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
     423             :     }
     424             : 
     425        6220 :     res = TEH_keys_load_fees (akc.ksh,
     426        6220 :                               &d->h_denom_pub,
     427             :                               &d->denom_pub,
     428             :                               &d->meta);
     429        6220 :     switch (res)
     430             :     {
     431           0 :     case GNUNET_SYSERR:
     432           0 :       ret = TALER_MHD_reply_with_error (
     433             :         connection,
     434             :         MHD_HTTP_INTERNAL_SERVER_ERROR,
     435             :         TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,
     436           0 :         GNUNET_h2s (&d->h_denom_pub.hash));
     437           0 :       cleanup_akc (&akc);
     438           0 :       return ret;
     439           0 :     case GNUNET_NO:
     440           0 :       ret = TALER_MHD_reply_with_error (
     441             :         connection,
     442             :         MHD_HTTP_NOT_FOUND,
     443             :         TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN,
     444           0 :         GNUNET_h2s (&d->h_denom_pub.hash));
     445           0 :       cleanup_akc (&akc);
     446           0 :       return ret;
     447        6220 :     case GNUNET_OK:
     448        6220 :       break;
     449             :     }
     450             :     /* check signature is valid */
     451        6220 :     TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
     452        6220 :     if (GNUNET_OK !=
     453        6220 :         TALER_exchange_offline_denom_validity_verify (
     454        6220 :           &d->h_denom_pub,
     455             :           d->meta.start,
     456             :           d->meta.expire_withdraw,
     457             :           d->meta.expire_deposit,
     458             :           d->meta.expire_legal,
     459        6220 :           &d->meta.value,
     460        6220 :           &d->meta.fees,
     461             :           &TEH_master_public_key,
     462        6220 :           &d->master_sig))
     463             :     {
     464           0 :       GNUNET_break_op (0);
     465           0 :       ret = TALER_MHD_reply_with_error (
     466             :         connection,
     467             :         MHD_HTTP_FORBIDDEN,
     468             :         TALER_EC_EXCHANGE_MANAGEMENT_KEYS_DENOMKEY_ADD_SIGNATURE_INVALID,
     469           0 :         GNUNET_h2s (&d->h_denom_pub.hash));
     470           0 :       cleanup_akc (&akc);
     471           0 :       return ret;
     472             :     }
     473             :   }
     474             : 
     475          21 :   akc.ns_sigs = json_array_size (signkey_sigs);
     476          21 :   akc.s_sigs = GNUNET_new_array (akc.ns_sigs,
     477             :                                  struct SigningSig);
     478          88 :   for (unsigned int i = 0; i<akc.ns_sigs; i++)
     479             :   {
     480          67 :     struct SigningSig *s = &akc.s_sigs[i];
     481             :     struct GNUNET_JSON_Specification ispec[] = {
     482          67 :       GNUNET_JSON_spec_fixed_auto ("master_sig",
     483             :                                    &s->master_sig),
     484          67 :       GNUNET_JSON_spec_fixed_auto ("exchange_pub",
     485             :                                    &s->exchange_pub),
     486          67 :       GNUNET_JSON_spec_end ()
     487             :     };
     488             :     enum GNUNET_GenericReturnValue res;
     489             : 
     490          67 :     res = TALER_MHD_parse_json_data (connection,
     491          67 :                                      json_array_get (signkey_sigs,
     492             :                                                      i),
     493             :                                      ispec);
     494          67 :     if (GNUNET_OK != res)
     495             :     {
     496           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     497             :                   "Failure to handle /management/keys\n");
     498           0 :       cleanup_akc (&akc);
     499           0 :       return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
     500             :     }
     501          67 :     res = TEH_keys_get_timing (&s->exchange_pub,
     502             :                                &s->meta);
     503          67 :     switch (res)
     504             :     {
     505           0 :     case GNUNET_SYSERR:
     506           0 :       ret = TALER_MHD_reply_with_error (
     507             :         connection,
     508             :         MHD_HTTP_INTERNAL_SERVER_ERROR,
     509             :         TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,
     510           0 :         TALER_B2S (&s->exchange_pub));
     511           0 :       cleanup_akc (&akc);
     512           0 :       return ret;
     513           0 :     case GNUNET_NO:
     514             :       /* For idempotency, check if the key is already active */
     515           0 :       ret = TALER_MHD_reply_with_error (
     516             :         connection,
     517             :         MHD_HTTP_NOT_FOUND,
     518             :         TALER_EC_EXCHANGE_MANAGEMENT_KEYS_SIGNKEY_UNKNOWN,
     519           0 :         TALER_B2S (&s->exchange_pub));
     520           0 :       cleanup_akc (&akc);
     521           0 :       return ret;
     522          67 :     case GNUNET_OK:
     523          67 :       break;
     524             :     }
     525             : 
     526             :     /* check signature is valid */
     527          67 :     TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
     528          67 :     if (GNUNET_OK !=
     529          67 :         TALER_exchange_offline_signkey_validity_verify (
     530          67 :           &s->exchange_pub,
     531             :           s->meta.start,
     532             :           s->meta.expire_sign,
     533             :           s->meta.expire_legal,
     534             :           &TEH_master_public_key,
     535          67 :           &s->master_sig))
     536             :     {
     537           0 :       GNUNET_break_op (0);
     538           0 :       ret = TALER_MHD_reply_with_error (
     539             :         connection,
     540             :         MHD_HTTP_FORBIDDEN,
     541             :         TALER_EC_EXCHANGE_MANAGEMENT_KEYS_SIGNKEY_ADD_SIGNATURE_INVALID,
     542           0 :         TALER_B2S (&s->exchange_pub));
     543           0 :       cleanup_akc (&akc);
     544           0 :       return ret;
     545             :     }
     546             :   }
     547          21 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     548             :               "Received %u denomination and %u signing key signatures\n",
     549             :               akc.nd_sigs,
     550             :               akc.ns_sigs);
     551             :   {
     552             :     enum GNUNET_GenericReturnValue res;
     553             : 
     554          21 :     res = TEH_DB_run_transaction (connection,
     555             :                                   "add keys",
     556             :                                   TEH_MT_REQUEST_OTHER,
     557             :                                   &ret,
     558             :                                   &add_keys,
     559             :                                   &akc);
     560          21 :     cleanup_akc (&akc);
     561          21 :     if (GNUNET_SYSERR == res)
     562           0 :       return ret;
     563             :   }
     564          21 :   TEH_keys_update_states ();
     565          21 :   return TALER_MHD_reply_static (
     566             :     connection,
     567             :     MHD_HTTP_NO_CONTENT,
     568             :     NULL,
     569             :     NULL,
     570             :     0);
     571             : }
     572             : 
     573             : 
     574             : /* end of taler-exchange-httpd_management_management_post_keys.c */

Generated by: LCOV version 1.16