gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-exchange] branch master updated (20c0c01d -> 18c12f62)


From: gnunet
Subject: [taler-exchange] branch master updated (20c0c01d -> 18c12f62)
Date: Tue, 15 Dec 2020 21:09:39 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a change to branch master
in repository exchange.

    from 20c0c01d fix new /keys shutdown sequence
     new 97cbf8bd log
     new 18c12f62 misc new /keys management related bugfixes

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/exchange-tools/taler-exchange-offline.c        |   8 +-
 src/exchange/taler-exchange-httpd.c                |  12 +-
 src/exchange/taler-exchange-httpd_keys.c           | 279 +++++++++++++--------
 src/exchange/taler-exchange-httpd_keys.h           |  63 ++++-
 .../taler-exchange-httpd_management_post_keys.c    |  14 +-
 src/lib/exchange_api_management_post_keys.c        |   4 +
 6 files changed, 256 insertions(+), 124 deletions(-)

diff --git a/src/exchange-tools/taler-exchange-offline.c 
b/src/exchange-tools/taler-exchange-offline.c
index 0fbcd672..28bbbe02 100644
--- a/src/exchange-tools/taler-exchange-offline.c
+++ b/src/exchange-tools/taler-exchange-offline.c
@@ -635,8 +635,8 @@ denom_revocation_cb (
                 "Upload failed for command %u with status %u: %s (%s)\n",
                 (unsigned int) drr->idx,
                 hr->http_status,
-                TALER_ErrorCode_get_hint (hr->ec),
-                hr->hint);
+                hr->hint,
+                TALER_JSON_get_error_hint (hr->reply));
     global_ret = 10;
   }
   GNUNET_CONTAINER_DLL_remove (drr_head,
@@ -724,8 +724,8 @@ signkey_revocation_cb (
                 "Upload failed for command %u with status %u: %s (%s)\n",
                 (unsigned int) srr->idx,
                 hr->http_status,
-                TALER_ErrorCode_get_hint (hr->ec),
-                hr->hint);
+                hr->hint,
+                TALER_JSON_get_error_hint (hr->reply));
     global_ret = 10;
   }
   GNUNET_CONTAINER_DLL_remove (srr_head,
diff --git a/src/exchange/taler-exchange-httpd.c 
b/src/exchange/taler-exchange-httpd.c
index 6009672f..eb9d7c46 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -696,7 +696,7 @@ handle_post_auditors (const struct TEH_RequestHandler *rh,
 
   if ( (NULL == args[0]) ||
        (NULL == args[1]) ||
-       (NULL != args[0]) )
+       (NULL != args[2]) )
   {
     GNUNET_break_op (0);
     return r404 (connection, "/auditors/$AUDITOR_PUB/$H_DENOM_PUB");
@@ -1476,12 +1476,7 @@ run_main_loop (int fh,
   }
 
   atexit (&write_stats);
-  ret = TEH_keys_init ();
-  if (GNUNET_OK == ret)
-  {
-    ret = TEH_loop_run ();
-    TEH_loop_done ();
-  }
+  ret = TEH_loop_run ();
   switch (ret)
   {
   case GNUNET_OK:
@@ -1696,6 +1691,9 @@ main (int argc,
   if (GNUNET_OK !=
       TEH_WIRE_init ())
     return 42;
+  if (GNUNET_OK !=
+      TEH_keys_init ())
+    return 43;
   ret = TEH_loop_init ();
   if (GNUNET_OK == ret)
   {
diff --git a/src/exchange/taler-exchange-httpd_keys.c 
b/src/exchange/taler-exchange-httpd_keys.c
index d51e8b3d..e955cd95 100644
--- a/src/exchange/taler-exchange-httpd_keys.c
+++ b/src/exchange/taler-exchange-httpd_keys.c
@@ -293,6 +293,12 @@ struct TEH_KeyStateHandle
    */
   struct GNUNET_TIME_Absolute next_reload;
 
+  /**
+   * True if #finish_keys_response() was not yet run and this key state
+   * is only suitable for the /management/keys API.
+   */
+  bool management_only;
+
 };
 
 
@@ -888,7 +894,10 @@ TEH_keys_init ()
   if (0 !=
       pthread_key_create (&key_state,
                           &destroy_key_state_cb))
+  {
+    GNUNET_break (0);
     return GNUNET_SYSERR;
+  }
   key_state_available = true;
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
@@ -1124,87 +1133,6 @@ auditor_denom_cb (
 }
 
 
-/**
- * Create a key state.
- *
- * @param[in] hs helper state to (re)use, NULL if not available
- * @return NULL on error (i.e. failed to access database)
- */
-static struct TEH_KeyStateHandle *
-build_key_state (struct HelperState *hs)
-{
-  struct TEH_KeyStateHandle *ksh;
-  enum GNUNET_DB_QueryStatus qs;
-
-  ksh = GNUNET_new (struct TEH_KeyStateHandle);
-  ksh->reload_time = GNUNET_TIME_absolute_get ();
-  GNUNET_TIME_round_abs (&ksh->reload_time);
-  /* We must use the key_generation from when we STARTED the process! */
-  ksh->key_generation = key_generation;
-  if (NULL == hs)
-  {
-    if (GNUNET_OK !=
-        setup_key_helpers (&ksh->helpers))
-    {
-      GNUNET_free (ksh);
-      return NULL;
-    }
-  }
-  else
-  {
-    ksh->helpers = *hs;
-  }
-  ksh->denomkey_map = GNUNET_CONTAINER_multihashmap_create (1024,
-                                                            GNUNET_YES);
-  ksh->signkey_map = GNUNET_CONTAINER_multipeermap_create (32,
-                                                           GNUNET_NO /* MUST 
be NO! */);
-  ksh->auditors = json_array ();
-  /* NOTE: fetches master-signed signkeys, but ALSO those that were revoked! */
-  qs = TEH_plugin->iterate_denominations (TEH_plugin->cls,
-                                          &denomination_info_cb,
-                                          ksh);
-  if (qs < 0)
-  {
-    GNUNET_break (0);
-    destroy_key_state (ksh,
-                       true);
-    return NULL;
-  }
-  /* NOTE: ONLY fetches non-revoked AND master-signed signkeys! */
-  qs = TEH_plugin->iterate_active_signkeys (TEH_plugin->cls,
-                                            &signkey_info_cb,
-                                            ksh);
-  if (qs < 0)
-  {
-    GNUNET_break (0);
-    destroy_key_state (ksh,
-                       true);
-    return NULL;
-  }
-  qs = TEH_plugin->iterate_active_auditors (TEH_plugin->cls,
-                                            &auditor_info_cb,
-                                            ksh);
-  if (qs < 0)
-  {
-    GNUNET_break (0);
-    destroy_key_state (ksh,
-                       true);
-    return NULL;
-  }
-  qs = TEH_plugin->iterate_auditor_denominations (TEH_plugin->cls,
-                                                  &auditor_denom_cb,
-                                                  ksh);
-  if (qs < 0)
-  {
-    GNUNET_break (0);
-    destroy_key_state (ksh,
-                       true);
-    return NULL;
-  }
-  return ksh;
-}
-
-
 /**
  * Closure for #add_sign_key_cb.
  */
@@ -1448,6 +1376,9 @@ create_krd (struct TEH_KeyStateHandle *ksh,
   struct TALER_ExchangeSignatureP exchange_sig;
   json_t *keys;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Creating /keys at cherry pick date %s\n",
+              GNUNET_STRINGS_absolute_time_to_string (last_cpd));
   /* Sign hash over denomination keys */
   {
     struct TALER_ExchangeKeySetPS ks = {
@@ -1459,9 +1390,10 @@ create_krd (struct TEH_KeyStateHandle *ksh,
     enum TALER_ErrorCode ec;
 
     if (TALER_EC_NONE !=
-        (ec = TEH_keys_exchange_sign (&ks,
-                                      &exchange_pub,
-                                      &exchange_sig)))
+        (ec = TEH_keys_exchange_sign2 (ksh,
+                                       &ks,
+                                       &exchange_pub,
+                                       &exchange_sig)))
     {
       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                   "Could not create key response data: cannot sign (%s)\n",
@@ -1541,7 +1473,7 @@ create_krd (struct TEH_KeyStateHandle *ksh,
 
 
 /**
- * Update the "/keys" responses in @a ksh up to @a now into the future.
+ * Update the "/keys" responses in @a ksh, computing the detailed replies.
  *
  * This function is to recompute all (including cherry-picked) responses we
  * might want to return, based on the state already in @a ksh.
@@ -1550,7 +1482,7 @@ create_krd (struct TEH_KeyStateHandle *ksh,
  * @return #GNUNET_OK on success
  */
 static int
-update_keys_response (struct TEH_KeyStateHandle *ksh)
+finish_keys_response (struct TEH_KeyStateHandle *ksh)
 {
   json_t *recoup;
   struct SignKeyCtx sctx;
@@ -1683,10 +1615,109 @@ update_keys_response (struct TEH_KeyStateHandle *ksh)
   json_decref (sctx.signkeys);
   json_decref (recoup);
   json_decref (denoms);
+  ksh->management_only = false;
   return GNUNET_OK;
 }
 
 
+/**
+ * Create a key state.
+ *
+ * @param[in] hs helper state to (re)use, NULL if not available
+ * @param management_only if we should NOT run 'finish_keys_response()'
+ *                  because we only need the state for the /management/keys API
+ * @return NULL on error (i.e. failed to access database)
+ */
+static struct TEH_KeyStateHandle *
+build_key_state (struct HelperState *hs,
+                 bool management_only)
+{
+  struct TEH_KeyStateHandle *ksh;
+  enum GNUNET_DB_QueryStatus qs;
+
+  ksh = GNUNET_new (struct TEH_KeyStateHandle);
+  ksh->reload_time = GNUNET_TIME_absolute_get ();
+  GNUNET_TIME_round_abs (&ksh->reload_time);
+  /* We must use the key_generation from when we STARTED the process! */
+  ksh->key_generation = key_generation;
+  if (NULL == hs)
+  {
+    if (GNUNET_OK !=
+        setup_key_helpers (&ksh->helpers))
+    {
+      GNUNET_free (ksh);
+      return NULL;
+    }
+  }
+  else
+  {
+    ksh->helpers = *hs;
+  }
+  ksh->denomkey_map = GNUNET_CONTAINER_multihashmap_create (1024,
+                                                            GNUNET_YES);
+  ksh->signkey_map = GNUNET_CONTAINER_multipeermap_create (32,
+                                                           GNUNET_NO /* MUST 
be NO! */);
+  ksh->auditors = json_array ();
+  /* NOTE: fetches master-signed signkeys, but ALSO those that were revoked! */
+  qs = TEH_plugin->iterate_denominations (TEH_plugin->cls,
+                                          &denomination_info_cb,
+                                          ksh);
+  if (qs < 0)
+  {
+    GNUNET_break (0);
+    destroy_key_state (ksh,
+                       true);
+    return NULL;
+  }
+  /* NOTE: ONLY fetches non-revoked AND master-signed signkeys! */
+  qs = TEH_plugin->iterate_active_signkeys (TEH_plugin->cls,
+                                            &signkey_info_cb,
+                                            ksh);
+  if (qs < 0)
+  {
+    GNUNET_break (0);
+    destroy_key_state (ksh,
+                       true);
+    return NULL;
+  }
+  qs = TEH_plugin->iterate_active_auditors (TEH_plugin->cls,
+                                            &auditor_info_cb,
+                                            ksh);
+  if (qs < 0)
+  {
+    GNUNET_break (0);
+    destroy_key_state (ksh,
+                       true);
+    return NULL;
+  }
+  qs = TEH_plugin->iterate_auditor_denominations (TEH_plugin->cls,
+                                                  &auditor_denom_cb,
+                                                  ksh);
+  if (qs < 0)
+  {
+    GNUNET_break (0);
+    destroy_key_state (ksh,
+                       true);
+    return NULL;
+  }
+  if (management_only)
+  {
+    ksh->management_only = true;
+    return ksh;
+  }
+  if (GNUNET_OK !=
+      finish_keys_response (ksh))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Could not finish /keys response (likely no signing keys 
available yet)\n");
+    destroy_key_state (ksh,
+                       true);
+    return NULL;
+  }
+  return ksh;
+}
+
+
 void
 TEH_keys_update_states ()
 {
@@ -1696,8 +1727,16 @@ TEH_keys_update_states ()
 }
 
 
-struct TEH_KeyStateHandle *
-TEH_get_key_state (void)
+/**
+ * Obtain the key state for the current thread. Should ONLY be used
+ * directly if @a management_only is true. Otherwise use #TEH_get_key_state().
+ *
+ * @param management_only if we should NOT run 'finish_keys_response()'
+ *                  because we only need the state for the /management/keys API
+ * @return NULL on error
+ */
+static struct TEH_KeyStateHandle *
+get_key_state (bool management_only)
 {
   struct TEH_KeyStateHandle *old_ksh;
   struct TEH_KeyStateHandle *ksh;
@@ -1706,7 +1745,8 @@ TEH_get_key_state (void)
   old_ksh = pthread_getspecific (key_state);
   if (NULL == old_ksh)
   {
-    ksh = build_key_state (NULL);
+    ksh = build_key_state (NULL,
+                           management_only);
     if (NULL == ksh)
       return NULL;
     if (0 != pthread_setspecific (key_state,
@@ -1721,7 +1761,12 @@ TEH_get_key_state (void)
   }
   if (old_ksh->key_generation < key_generation)
   {
-    ksh = build_key_state (&old_ksh->helpers);
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Rebuilding /keys, generation upgrade from %llu to %llu\n",
+                (unsigned long long) old_ksh->key_generation,
+                (unsigned long long) key_generation);
+    ksh = build_key_state (&old_ksh->helpers,
+                           management_only);
     if (0 != pthread_setspecific (key_state,
                                   ksh))
     {
@@ -1741,6 +1786,24 @@ TEH_get_key_state (void)
 }
 
 
+struct TEH_KeyStateHandle *
+TEH_get_key_state (void)
+{
+  struct TEH_KeyStateHandle *ksh;
+
+  ksh = get_key_state (false);
+  if (NULL == ksh)
+    return NULL;
+  if (ksh->management_only)
+  {
+    if (GNUNET_OK !=
+        finish_keys_response (ksh))
+      return NULL;
+  }
+  return ksh;
+}
+
+
 struct TEH_DenominationKey *
 TEH_keys_denomination_by_hash (const struct GNUNET_HashCode *h_denom_pub,
                                enum TALER_ErrorCode *ec,
@@ -1823,13 +1886,12 @@ TEH_keys_denomination_revoke (const struct 
GNUNET_HashCode *h_denom_pub)
 
 
 enum TALER_ErrorCode
-TEH_keys_exchange_sign_ (const struct
-                         GNUNET_CRYPTO_EccSignaturePurpose *purpose,
-                         struct TALER_ExchangePublicKeyP *pub,
-                         struct TALER_ExchangeSignatureP *sig)
+TEH_keys_exchange_sign_ (
+  const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+  struct TALER_ExchangePublicKeyP *pub,
+  struct TALER_ExchangeSignatureP *sig)
 {
   struct TEH_KeyStateHandle *ksh;
-  enum TALER_ErrorCode ec;
 
   ksh = TEH_get_key_state ();
   if (NULL == ksh)
@@ -1840,6 +1902,22 @@ TEH_keys_exchange_sign_ (const struct
                 "Cannot sign request, no valid signing keys available.\n");
     return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
   }
+  return TEH_keys_exchange_sign2_ (ksh,
+                                   purpose,
+                                   pub,
+                                   sig);
+}
+
+
+enum TALER_ErrorCode
+TEH_keys_exchange_sign2_ (
+  struct TEH_KeyStateHandle *ksh,
+  const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+  struct TALER_ExchangePublicKeyP *pub,
+  struct TALER_ExchangeSignatureP *sig)
+{
+  enum TALER_ErrorCode ec;
+
   ec = TALER_CRYPTO_helper_esign_sign_ (ksh->helpers.esh,
                                         purpose,
                                         pub,
@@ -1964,11 +2042,6 @@ TEH_keys_get_handler (const struct TEH_RequestHandler 
*rh,
     {
       return suspend_request (connection);
     }
-    if (GNUNET_OK !=
-        update_keys_response (ksh))
-    {
-      return suspend_request (connection);
-    }
     krd = bsearch (&last_issue_date,
                    ksh->krd_array,
                    ksh->krd_array_length,
@@ -2145,7 +2218,7 @@ TEH_keys_load_fees (const struct GNUNET_HashCode 
*h_denom_pub,
   struct HelperDenomination *hd;
   int ok;
 
-  ksh = TEH_get_key_state ();
+  ksh = get_key_state (true);
   if (NULL == ksh)
   {
     GNUNET_break (0);
@@ -2177,7 +2250,7 @@ TEH_keys_get_timing (const struct 
TALER_ExchangePublicKeyP *exchange_pub,
   struct HelperSignkey *hsk;
   struct GNUNET_PeerIdentity pid;
 
-  ksh = TEH_get_key_state ();
+  ksh = get_key_state (true);
   if (NULL == ksh)
   {
     GNUNET_break (0);
@@ -2347,7 +2420,7 @@ TEH_keys_management_get_handler (const struct 
TEH_RequestHandler *rh,
   struct TEH_KeyStateHandle *ksh;
   json_t *reply;
 
-  ksh = TEH_get_key_state ();
+  ksh = get_key_state (true);
   if (NULL == ksh)
   {
     GNUNET_break (0);
diff --git a/src/exchange/taler-exchange-httpd_keys.h 
b/src/exchange/taler-exchange-httpd_keys.h
index 1bdabd0f..54dc8c73 100644
--- a/src/exchange/taler-exchange-httpd_keys.h
+++ b/src/exchange/taler-exchange-httpd_keys.h
@@ -217,10 +217,31 @@ TEH_resume_keys_requests (bool do_shutdown);
  * @return #TALER_EC_NONE on success
  */
 enum TALER_ErrorCode
-TEH_keys_exchange_sign_ (const struct
-                         GNUNET_CRYPTO_EccSignaturePurpose *purpose,
-                         struct TALER_ExchangePublicKeyP *pub,
-                         struct TALER_ExchangeSignatureP *sig);
+TEH_keys_exchange_sign_ (
+  const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+  struct TALER_ExchangePublicKeyP *pub,
+  struct TALER_ExchangeSignatureP *sig);
+
+
+/**
+ * Sign the message in @a purpose with the exchange's signing key.
+ *
+ * The @a purpose data is the beginning of the data of which the signature is
+ * to be created. The `size` field in @a purpose must correctly indicate the
+ * number of bytes of the data structure, including its header.  Use
+ * #TEH_keys_exchange_sign() instead of calling this function directly!
+ *
+ * @param purpose the message to sign
+ * @param[out] pub set to the current public signing key of the exchange
+ * @param[out] sig signature over purpose using current signing key
+ * @return #TALER_EC_NONE on success
+ */
+enum TALER_ErrorCode
+TEH_keys_exchange_sign2_ (
+  struct TEH_KeyStateHandle *ksh,
+  const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+  struct TALER_ExchangePublicKeyP *pub,
+  struct TALER_ExchangeSignatureP *sig);
 
 
 /**
@@ -250,6 +271,40 @@ TEH_keys_exchange_sign_ (const struct
   })
 
 
+/**
+ * @ingroup crypto
+ * @brief EdDSA sign a given block.
+ *
+ * The @a ps data must be a fixed-size struct for which the signature is to be
+ * created. The `size` field in @a ps->purpose must correctly indicate the
+ * number of bytes of the data structure, including its header.
+ *
+ * This allows requesting multiple denominations with the same @a ksh which
+ * thus will remain valid until the next call to
+ * #TEH_keys_denomination_by_hash() or #TEH_get_key_state() or
+ * #TEH_keys_exchange_sign().
+ *
+ * @param ksh key state to use
+ * @param ps packed struct with what to sign, MUST begin with a purpose
+ * @param[out] pub where to store the public key to use for the signing
+ * @param[out] sig where to write the signature
+ * @return #TALER_EC_NONE on success
+ */
+#define TEH_keys_exchange_sign2(ksh,ps,pub,sig)       \
+  ({                                                  \
+    /* check size is set correctly */                 \
+    GNUNET_assert (htonl ((ps)->purpose.size) ==      \
+                   sizeof (*ps));                     \
+    /* check 'ps' begins with the purpose */          \
+    GNUNET_static_assert (((void*) (ps)) ==           \
+                          ((void*) &(ps)->purpose));  \
+    TEH_keys_exchange_sign2_ (ksh,                    \
+                              &(ps)->purpose,         \
+                              pub,                     \
+                              sig);                    \
+  })
+
+
 /**
  * Revoke the given exchange's signing key.
  * This function should be called AFTER the database was
diff --git a/src/exchange/taler-exchange-httpd_management_post_keys.c 
b/src/exchange/taler-exchange-httpd_management_post_keys.c
index 84ec1f53..df044b6d 100644
--- a/src/exchange/taler-exchange-httpd_management_post_keys.c
+++ b/src/exchange/taler-exchange-httpd_management_post_keys.c
@@ -157,7 +157,7 @@ add_keys (void *cls,
           MHD_HTTP_NOT_FOUND,
           TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN,
           GNUNET_h2s (&akc->d_sigs[i].h_denom_pub));
-        return qs;
+        return GNUNET_DB_STATUS_HARD_ERROR;
       }
     }
     else
@@ -183,11 +183,12 @@ add_keys (void *cls,
             &akc->d_sigs[i].master_sig))
       {
         GNUNET_break_op (0);
-        return TALER_MHD_reply_with_error (
+        *mhd_ret = TALER_MHD_reply_with_error (
           connection,
           MHD_HTTP_FORBIDDEN,
-          TALER_EC_EXCHANGE_MANAGEMENT_KEYS_SIGNKEY_ADD_SIGNATURE_INVALID,
+          TALER_EC_EXCHANGE_MANAGEMENT_KEYS_DENOMKEY_ADD_SIGNATURE_INVALID,
           GNUNET_h2s (&akc->d_sigs[i].h_denom_pub));
+        return GNUNET_DB_STATUS_HARD_ERROR;
       }
     }
     if (is_active)
@@ -253,7 +254,7 @@ add_keys (void *cls,
           MHD_HTTP_NOT_FOUND,
           TALER_EC_EXCHANGE_MANAGEMENT_KEYS_SIGNKEY_UNKNOWN,
           TALER_B2S (&akc->s_sigs[i].exchange_pub));
-        return qs;
+        return GNUNET_DB_STATUS_HARD_ERROR;
       }
     }
     else
@@ -273,11 +274,12 @@ add_keys (void *cls,
             &akc->s_sigs[i].master_sig))
       {
         GNUNET_break_op (0);
-        return TALER_MHD_reply_with_error (
+        *mhd_ret = TALER_MHD_reply_with_error (
           connection,
           MHD_HTTP_FORBIDDEN,
-          TALER_EC_EXCHANGE_MANAGEMENT_KEYS_DENOMKEY_ADD_SIGNATURE_INVALID,
+          TALER_EC_EXCHANGE_MANAGEMENT_KEYS_SIGNKEY_ADD_SIGNATURE_INVALID,
           GNUNET_h2s (&akc->d_sigs[i].h_denom_pub));
+        return GNUNET_DB_STATUS_HARD_ERROR;
       }
     }
     if (is_active)
diff --git a/src/lib/exchange_api_management_post_keys.c 
b/src/lib/exchange_api_management_post_keys.c
index b885df7f..7b37bb0c 100644
--- a/src/lib/exchange_api_management_post_keys.c
+++ b/src/lib/exchange_api_management_post_keys.c
@@ -95,6 +95,10 @@ handle_post_keys_finished (void *cls,
     hr.ec = TALER_JSON_get_error_code (json);
     hr.hint = TALER_JSON_get_error_hint (json);
     break;
+  case MHD_HTTP_NOT_FOUND:
+    hr.ec = TALER_JSON_get_error_code (json);
+    hr.hint = TALER_JSON_get_error_hint (json);
+    break;
   default:
     /* unexpected response code */
     GNUNET_break_op (0);

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]