gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [taler-exchange] branch master updated (c09c9009 -> 16b0c65


From: gnunet
Subject: [GNUnet-SVN] [taler-exchange] branch master updated (c09c9009 -> 16b0c654)
Date: Sat, 13 Oct 2018 19:45:58 +0200

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

grothoff pushed a change to branch master
in repository exchange.

    from c09c9009 implement deserialization logic for #5136
     new 85e22419 fix issue with 'meta' not being initialized - by getting rid 
of it
     new c0d75d4b fix memory leaks
     new bf9e376c wrong offset, last coin is #3, not #4
     new a3819642 style fix: always put parens on macros
     new 3605d964 indentation fix
     new 504017bc intermediate patch towards implementing #5136
     new 16b0c654 keep a most sigs around when serializing

The 7 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-lib/exchange_api_handle.c             | 529 ++++++++++++++-------
 .../test_exchange_api_keys_cherry_picking_new.c    |   3 +-
 src/exchange-lib/test_exchange_api_new.c           |   2 +-
 src/exchange-lib/testing_api_cmd_batch.c           |  13 +-
 .../testing_api_cmd_exec_auditor-sign.c            |   5 +-
 src/exchange-lib/testing_api_cmd_refresh.c         |   2 +-
 src/exchange-lib/testing_api_helpers.c             |   9 +-
 src/exchange-lib/testing_api_loop.c                |  53 ++-
 src/exchange-lib/testing_api_trait_cmd.c           |   2 +-
 src/exchange/taler-exchange-httpd_keystate.c       |  87 ++--
 src/include/taler_exchange_service.h               |  49 +-
 src/include/taler_testing_lib.h                    |  18 +-
 12 files changed, 538 insertions(+), 234 deletions(-)

diff --git a/src/exchange-lib/exchange_api_handle.c 
b/src/exchange-lib/exchange_api_handle.c
index 3891ee9c..2397bf98 100644
--- a/src/exchange-lib/exchange_api_handle.c
+++ b/src/exchange-lib/exchange_api_handle.c
@@ -41,6 +41,12 @@
  */
 #define TALER_PROTOCOL_AGE 0
 
+/**
+ * Current version for (local) JSON serialization of persisted 
+ * /keys data.
+ */ 
+#define TALER_SERIALIZATION_FORMAT_VERSION 0
+
 
 /**
  * Log error related to CURL operations.
@@ -205,6 +211,7 @@ free_keys_request (struct KeysRequest *kr)
  * Parse a exchange's signing key encoded in JSON.
  *
  * @param[out] sign_key where to return the result
+ * @param check_sigs should we check signatures?
  * @param[in] sign_key_obj json to parse
  * @param master_key master key to use to verify signature
  * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
@@ -212,25 +219,22 @@ free_keys_request (struct KeysRequest *kr)
  */
 static int
 parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key,
+                   int check_sigs,
                     json_t *sign_key_obj,
                     const struct TALER_MasterPublicKeyP *master_key)
 {
   struct TALER_ExchangeSigningKeyValidityPS sign_key_issue;
-  struct GNUNET_CRYPTO_EddsaSignature sig;
-  struct GNUNET_TIME_Absolute valid_from;
-  struct GNUNET_TIME_Absolute valid_until;
-  struct GNUNET_TIME_Absolute valid_legal;
   struct GNUNET_JSON_Specification spec[] = {
     GNUNET_JSON_spec_fixed_auto ("master_sig",
-                                 &sig),
+                                 &sign_key->master_sig),
     GNUNET_JSON_spec_fixed_auto ("key",
-                                 &sign_key_issue.signkey_pub),
+                                 &sign_key->key),
     GNUNET_JSON_spec_absolute_time ("stamp_start",
-                                    &valid_from),
+                                    &sign_key->valid_from),
     GNUNET_JSON_spec_absolute_time ("stamp_expire",
-                                    &valid_until),
+                                    &sign_key->valid_until),
     GNUNET_JSON_spec_absolute_time ("stamp_end",
-                                    &valid_legal),
+                                    &sign_key->valid_legal),
     GNUNET_JSON_spec_end()
   };
 
@@ -243,27 +247,27 @@ parse_json_signkey (struct 
TALER_EXCHANGE_SigningPublicKey *sign_key,
     return GNUNET_SYSERR;
   }
 
+  if (! check_sigs)
+    return GNUNET_OK;
+  sign_key_issue.signkey_pub = sign_key->key;
   sign_key_issue.purpose.purpose = htonl 
(TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY);
   sign_key_issue.purpose.size =
     htonl (sizeof (struct TALER_ExchangeSigningKeyValidityPS)
-           - offsetof (struct TALER_ExchangeSigningKeyValidityPS,
-                       purpose));
+          - offsetof (struct TALER_ExchangeSigningKeyValidityPS,
+                      purpose));
   sign_key_issue.master_public_key = *master_key;
-  sign_key_issue.start = GNUNET_TIME_absolute_hton (valid_from);
-  sign_key_issue.expire = GNUNET_TIME_absolute_hton (valid_until);
-  sign_key_issue.end = GNUNET_TIME_absolute_hton (valid_legal);
+  sign_key_issue.start = GNUNET_TIME_absolute_hton (sign_key->valid_from);
+  sign_key_issue.expire = GNUNET_TIME_absolute_hton (sign_key->valid_until);
+  sign_key_issue.end = GNUNET_TIME_absolute_hton (sign_key->valid_legal);
   if (GNUNET_OK !=
       GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY,
-                                  &sign_key_issue.purpose,
-                                  &sig,
-                                  &master_key->eddsa_pub))
+                                 &sign_key_issue.purpose,
+                                 &sign_key->master_sig.eddsa_signature,
+                                 &master_key->eddsa_pub))
   {
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
   }
-  sign_key->valid_from = valid_from;
-  sign_key->valid_until = valid_until;
-  sign_key->key = sign_key_issue.signkey_pub;
   return GNUNET_OK;
 }
 
@@ -272,6 +276,7 @@ parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey 
*sign_key,
  * Parse a exchange's denomination key encoded in JSON.
  *
  * @param[out] denom_key where to return the result
+ * @param check_sigs should we check signatures?
  * @param[in] denom_key_obj json to parse
  * @param master_key master key to use to verify signature
  * @param hash_context where to accumulate data for signature verification
@@ -280,99 +285,82 @@ parse_json_signkey (struct 
TALER_EXCHANGE_SigningPublicKey *sign_key,
  */
 static int
 parse_json_denomkey (struct TALER_EXCHANGE_DenomPublicKey *denom_key,
+                    int check_sigs,
                      json_t *denom_key_obj,
                      struct TALER_MasterPublicKeyP *master_key,
                      struct GNUNET_HashContext *hash_context)
 {
-  struct GNUNET_TIME_Absolute valid_from;
-  struct GNUNET_TIME_Absolute withdraw_valid_until;
-  struct GNUNET_TIME_Absolute expire_deposit;
-  struct GNUNET_TIME_Absolute expire_legal;
-  struct TALER_Amount value;
-  struct TALER_Amount fee_withdraw;
-  struct TALER_Amount fee_deposit;
-  struct TALER_Amount fee_refresh;
-  struct TALER_Amount fee_refund;
   struct TALER_DenominationKeyValidityPS denom_key_issue;
-  struct GNUNET_CRYPTO_RsaPublicKey *pk;
-  struct GNUNET_CRYPTO_EddsaSignature sig;
   struct GNUNET_JSON_Specification spec[] = {
     GNUNET_JSON_spec_fixed_auto ("master_sig",
-                                &sig),
+                                &denom_key->master_sig),
     GNUNET_JSON_spec_absolute_time ("stamp_expire_deposit",
-                                   &expire_deposit),
+                                   &denom_key->expire_deposit),
     GNUNET_JSON_spec_absolute_time ("stamp_expire_withdraw",
-                                   &withdraw_valid_until),
+                                   &denom_key->withdraw_valid_until),
     GNUNET_JSON_spec_absolute_time ("stamp_start",
-                                   &valid_from),
+                                   &denom_key->valid_from),
     GNUNET_JSON_spec_absolute_time ("stamp_expire_legal",
-                                   &expire_legal),
+                                   &denom_key->expire_legal),
     TALER_JSON_spec_amount ("value",
-                           &value),
+                           &denom_key->value),
     TALER_JSON_spec_amount ("fee_withdraw",
-                           &fee_withdraw),
+                           &denom_key->fee_withdraw),
     TALER_JSON_spec_amount ("fee_deposit",
-                           &fee_deposit),
+                           &denom_key->fee_deposit),
     TALER_JSON_spec_amount ("fee_refresh",
-                           &fee_refresh),
+                           &denom_key->fee_refresh),
     TALER_JSON_spec_amount ("fee_refund",
-                           &fee_refund),
+                           &denom_key->fee_refund),
     GNUNET_JSON_spec_rsa_public_key ("denom_pub",
-                             &pk),
+                                    &denom_key->key.rsa_public_key),
     GNUNET_JSON_spec_end()
   };
 
   if (GNUNET_OK !=
       GNUNET_JSON_parse (denom_key_obj,
-                         spec, NULL, NULL))
+                         spec,
+                        NULL, NULL))
   {
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
   }
 
+  GNUNET_CRYPTO_rsa_public_key_hash (denom_key->key.rsa_public_key,
+                                     &denom_key->h_key);
+  if (! check_sigs)
+    return GNUNET_OK;
   memset (&denom_key_issue,
-          0,
-          sizeof (denom_key_issue));
-  GNUNET_CRYPTO_rsa_public_key_hash (pk,
-                                     &denom_key_issue.denom_hash);
+         0,
+         sizeof (denom_key_issue));
   denom_key_issue.purpose.purpose
     = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY);
   denom_key_issue.purpose.size
     = htonl (sizeof (struct TALER_DenominationKeyValidityPS));
   denom_key_issue.master = *master_key;
-  denom_key_issue.start = GNUNET_TIME_absolute_hton (valid_from);
-  denom_key_issue.expire_withdraw = GNUNET_TIME_absolute_hton 
(withdraw_valid_until);
-  denom_key_issue.expire_deposit = GNUNET_TIME_absolute_hton (expire_deposit);
-  denom_key_issue.expire_legal = GNUNET_TIME_absolute_hton (expire_legal);
+  denom_key_issue.denom_hash = denom_key->h_key;
+  denom_key_issue.start = GNUNET_TIME_absolute_hton (denom_key->valid_from);
+  denom_key_issue.expire_withdraw = GNUNET_TIME_absolute_hton 
(denom_key->withdraw_valid_until);
+  denom_key_issue.expire_deposit = GNUNET_TIME_absolute_hton 
(denom_key->expire_deposit);
+  denom_key_issue.expire_legal = GNUNET_TIME_absolute_hton 
(denom_key->expire_legal);
   TALER_amount_hton (&denom_key_issue.value,
-                     &value);
+                    &denom_key->value);
   TALER_amount_hton (&denom_key_issue.fee_withdraw,
-                     &fee_withdraw);
+                    &denom_key->fee_withdraw);
   TALER_amount_hton (&denom_key_issue.fee_deposit,
-                     &fee_deposit);
+                      &denom_key->fee_deposit);
   TALER_amount_hton (&denom_key_issue.fee_refresh,
-                     &fee_refresh);
+                    &denom_key->fee_refresh);
   TALER_amount_hton (&denom_key_issue.fee_refund,
-                     &fee_refund);
+                    &denom_key->fee_refund);
   EXITIF (GNUNET_SYSERR ==
-          GNUNET_CRYPTO_eddsa_verify 
(TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY,
-                                      &denom_key_issue.purpose,
-                                      &sig,
-                                      &master_key->eddsa_pub));
+         GNUNET_CRYPTO_eddsa_verify 
(TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY,
+                                     &denom_key_issue.purpose,
+                                     &denom_key->master_sig.eddsa_signature,
+                                     &master_key->eddsa_pub));
   GNUNET_CRYPTO_hash_context_read (hash_context,
-                                   &denom_key_issue.denom_hash,
-                                   sizeof (struct GNUNET_HashCode));
-  denom_key->key.rsa_public_key = pk;
-  denom_key->h_key = denom_key_issue.denom_hash;
-  denom_key->valid_from = valid_from;
-  denom_key->withdraw_valid_until = withdraw_valid_until;
-  denom_key->expire_deposit = expire_deposit;
-  denom_key->expire_legal = expire_legal;
-  denom_key->value = value;
-  denom_key->fee_withdraw = fee_withdraw;
-  denom_key->fee_deposit = fee_deposit;
-  denom_key->fee_refresh = fee_refresh;
-  denom_key->fee_refund = fee_refund;
+                                  &denom_key_issue.denom_hash,
+                                  sizeof (struct GNUNET_HashCode));
   return GNUNET_OK;
 
  EXITIF_exit:
@@ -385,6 +373,7 @@ parse_json_denomkey (struct TALER_EXCHANGE_DenomPublicKey 
*denom_key,
  * Parse a exchange's auditor information encoded in JSON.
  *
  * @param[out] auditor where to return the result
+ * @param check_sig should we check signatures
  * @param[in] auditor_obj json to parse
  * @param key_data information about denomination keys
  * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
@@ -392,6 +381,7 @@ parse_json_denomkey (struct TALER_EXCHANGE_DenomPublicKey 
*denom_key,
  */
 static int
 parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
+                   int check_sigs,
                     json_t *auditor_obj,
                     const struct TALER_EXCHANGE_Keys *key_data)
 {
@@ -428,8 +418,8 @@ parse_json_auditor (struct 
TALER_EXCHANGE_AuditorInformation *auditor,
                       &kv.auditor_url_hash);
   kv.master = key_data->master_pub;
   len = json_array_size (keys);
-  auditor->denom_key_offsets = GNUNET_new_array (len,
-                                                 unsigned int);
+  auditor->denom_keys = GNUNET_new_array (len,
+                                         struct 
TALER_EXCHANGE_AuditorDenominationInfo);
   i = 0;
   off = 0;
   json_array_foreach (keys, i, key) {
@@ -438,10 +428,10 @@ parse_json_auditor (struct 
TALER_EXCHANGE_AuditorInformation *auditor,
     const struct TALER_EXCHANGE_DenomPublicKey *dk;
     unsigned int dk_off;
     struct GNUNET_JSON_Specification kspec[] = {
-      GNUNET_JSON_spec_fixed_auto ("denom_pub_h",
-                                   &denom_h),
       GNUNET_JSON_spec_fixed_auto ("auditor_sig",
                                    &auditor_sig),
+      GNUNET_JSON_spec_fixed_auto ("denom_pub_h",
+                                   &denom_h),
       GNUNET_JSON_spec_end()
     };
 
@@ -471,33 +461,37 @@ parse_json_auditor (struct 
TALER_EXCHANGE_AuditorInformation *auditor,
       GNUNET_break_op (0);
       continue;
     }
-    kv.start = GNUNET_TIME_absolute_hton (dk->valid_from);
-    kv.expire_withdraw = GNUNET_TIME_absolute_hton (dk->withdraw_valid_until);
-    kv.expire_deposit = GNUNET_TIME_absolute_hton (dk->expire_deposit);
-    kv.expire_legal = GNUNET_TIME_absolute_hton (dk->expire_legal);
-    TALER_amount_hton (&kv.value,
-                       &dk->value);
-    TALER_amount_hton (&kv.fee_withdraw,
-                       &dk->fee_withdraw);
-    TALER_amount_hton (&kv.fee_deposit,
-                       &dk->fee_deposit);
-    TALER_amount_hton (&kv.fee_refresh,
-                       &dk->fee_refresh);
-    TALER_amount_hton (&kv.fee_refund,
-                       &dk->fee_refund);
-    kv.denom_hash = dk->h_key;
-
-    if (GNUNET_OK !=
-        GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS,
-                                    &kv.purpose,
-                                    &auditor_sig.eddsa_sig,
-                                    &auditor->auditor_pub.eddsa_pub))
+    if (check_sigs)
     {
-      GNUNET_break_op (0);
-      GNUNET_JSON_parse_free (spec);
-      return GNUNET_SYSERR;
+      kv.start = GNUNET_TIME_absolute_hton (dk->valid_from);
+      kv.expire_withdraw = GNUNET_TIME_absolute_hton 
(dk->withdraw_valid_until);
+      kv.expire_deposit = GNUNET_TIME_absolute_hton (dk->expire_deposit);
+      kv.expire_legal = GNUNET_TIME_absolute_hton (dk->expire_legal);
+      TALER_amount_hton (&kv.value,
+                       &dk->value);
+      TALER_amount_hton (&kv.fee_withdraw,
+                        &dk->fee_withdraw);
+      TALER_amount_hton (&kv.fee_deposit,
+                        &dk->fee_deposit);
+      TALER_amount_hton (&kv.fee_refresh,
+                        &dk->fee_refresh);
+      TALER_amount_hton (&kv.fee_refund,
+                        &dk->fee_refund);
+      kv.denom_hash = dk->h_key;
+      
+      if (GNUNET_OK !=
+         GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS,
+                                     &kv.purpose,
+                                     &auditor_sig.eddsa_sig,
+                                     &auditor->auditor_pub.eddsa_pub))
+      {
+       GNUNET_break_op (0);
+       GNUNET_JSON_parse_free (spec);
+       return GNUNET_SYSERR;
+      }
     }
-    auditor->denom_key_offsets[off] = dk_off;
+    auditor->denom_keys[off].denom_key_offset = dk_off;
+    auditor->denom_keys[off].auditor_sig = auditor_sig;
     off++;
   }
   auditor->num_denom_keys = off;
@@ -511,24 +505,39 @@ parse_json_auditor (struct 
TALER_EXCHANGE_AuditorInformation *auditor,
  * in the @a key_data.
  *
  * @param[in] resp_obj JSON object to parse
+ * @param check_sig #GNUNET_YES if we should check the signature
  * @param[out] key_data where to store the results we decoded
  * @param[out] where to store version compatibility data
  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (malformed JSON)
  */
 static int
 decode_keys_json (const json_t *resp_obj,
+                 int check_sig,
                   struct TALER_EXCHANGE_Keys *key_data,
                  enum TALER_EXCHANGE_VersionCompatibility *vc)
 {
-  struct GNUNET_TIME_Absolute list_issue_date;
   struct GNUNET_TIME_Absolute last_denom_issue_date;
   struct TALER_ExchangeSignatureP sig;
-  struct TALER_ExchangeKeySetPS ks;
   struct GNUNET_HashContext *hash_context;
   struct TALER_ExchangePublicKeyP pub;
   unsigned int age;
   unsigned int revision;
   unsigned int current;
+  struct GNUNET_JSON_Specification mspec[] = {
+    GNUNET_JSON_spec_fixed_auto ("eddsa_sig",
+                                &sig),
+    GNUNET_JSON_spec_fixed_auto ("eddsa_pub",
+                                &pub),
+    /* sig and pub must be first, as we skip those if 
+       check_sig is false! */
+    GNUNET_JSON_spec_fixed_auto ("master_public_key",
+                                &key_data->master_pub),
+    GNUNET_JSON_spec_absolute_time ("list_issue_date",
+                                   &key_data->list_issue_date),
+    GNUNET_JSON_spec_relative_time ("reserve_closing_delay",
+                                   &key_data->reserve_closing_delay),
+    GNUNET_JSON_spec_end()
+  };
 
   if (JSON_OBJECT != json_typeof (resp_obj))
   {
@@ -577,29 +586,17 @@ decode_keys_json (const json_t *resp_obj,
     key_data->version = GNUNET_strdup (ver);
   }
 
-  /* parse the master public key and issue date of the response */
-  hash_context = GNUNET_CRYPTO_hash_context_start ();
-  {
-    struct GNUNET_JSON_Specification spec[] = {
-      GNUNET_JSON_spec_fixed_auto ("master_public_key",
-                                   &key_data->master_pub),
-      GNUNET_JSON_spec_fixed_auto ("eddsa_sig",
-                                   &sig),
-      GNUNET_JSON_spec_fixed_auto ("eddsa_pub",
-                                   &pub),
-      GNUNET_JSON_spec_absolute_time ("list_issue_date",
-                                      &list_issue_date),
-      GNUNET_JSON_spec_relative_time ("reserve_closing_delay",
-                                      &key_data->reserve_closing_delay),
-      GNUNET_JSON_spec_end()
-    };
-
-    EXITIF (GNUNET_OK !=
-            GNUNET_JSON_parse (resp_obj,
-                               spec,
-                               NULL, NULL));
-  }
+  EXITIF (GNUNET_OK !=
+         GNUNET_JSON_parse (resp_obj,
+                            (check_sig) ? mspec : &mspec[2],
+                            NULL, NULL));
 
+  /* parse the master public key and issue date of the response */
+  if (check_sig) 
+    hash_context = GNUNET_CRYPTO_hash_context_start ();
+  else
+    hash_context = NULL;
+  
   /* parse the signing keys */
   {
     json_t *sign_keys_array;
@@ -619,6 +616,7 @@ decode_keys_json (const json_t *resp_obj,
     json_array_foreach (sign_keys_array, index, sign_key_obj) {
       EXITIF (GNUNET_SYSERR ==
               parse_json_signkey (&key_data->sign_keys[index],
+                                 check_sig,
                                   sign_key_obj,
                                   &key_data->master_pub));
     }
@@ -644,6 +642,7 @@ decode_keys_json (const json_t *resp_obj,
 
       EXITIF (GNUNET_SYSERR ==
               parse_json_denomkey (&dk,
+                                  check_sig,
                                    denom_key_obj,
                                    &key_data->master_pub,
                                    hash_context));
@@ -684,7 +683,8 @@ decode_keys_json (const json_t *resp_obj,
     unsigned int index;
 
     EXITIF (NULL == (auditors_array =
-                     json_object_get (resp_obj, "auditors")));
+                     json_object_get (resp_obj,
+                                     "auditors")));
     EXITIF (JSON_ARRAY != json_typeof (auditors_array));
 
     /* Merge with the existing auditor information we have (/keys cherry 
picking) */
@@ -693,8 +693,12 @@ decode_keys_json (const json_t *resp_obj,
       struct TALER_EXCHANGE_AuditorInformation ai;
       bool found = false;
 
+      memset (&ai,
+             0,
+             sizeof (ai));
       EXITIF (GNUNET_SYSERR ==
               parse_json_auditor (&ai,
+                                 check_sig,
                                   auditor_info,
                                   key_data));
       for (unsigned int j=0;j<key_data->num_auditors;j++)
@@ -708,12 +712,12 @@ decode_keys_json (const json_t *resp_obj,
          found = true;
           /* Merge denomination key signatures of downloaded /keys into 
existing
              auditor information 'aix'. */
-          GNUNET_array_grow (aix->denom_key_offsets,
+          GNUNET_array_grow (aix->denom_keys,
                              aix->num_denom_keys,
                              aix->num_denom_keys + ai.num_denom_keys);
-          memcpy (&aix->denom_key_offsets[aix->num_denom_keys - 
ai.num_denom_keys],
-                  ai.denom_key_offsets,
-                  ai.num_denom_keys * sizeof (unsigned int));
+          memcpy (&aix->denom_keys[aix->num_denom_keys - ai.num_denom_keys],
+                  ai.denom_keys,
+                  ai.num_denom_keys * sizeof (struct 
TALER_EXCHANGE_AuditorDenominationInfo));
          break;
        }
       }
@@ -727,21 +731,26 @@ decode_keys_json (const json_t *resp_obj,
     };
   }
 
-  /* Validate signature... */
-  ks.purpose.size = htonl (sizeof (ks));
-  ks.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_KEY_SET);
-  ks.list_issue_date = GNUNET_TIME_absolute_hton (list_issue_date);
-  GNUNET_CRYPTO_hash_context_finish (hash_context,
-                                     &ks.hc);
-  hash_context = NULL;
-  EXITIF (GNUNET_OK !=
-          TALER_EXCHANGE_test_signing_key (key_data,
-                                          &pub));
-  EXITIF (GNUNET_OK !=
-          GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_KEY_SET,
-                                      &ks.purpose,
-                                      &sig.eddsa_signature,
-                                      &pub.eddsa_pub));
+  if (check_sig)
+  {
+    struct TALER_ExchangeKeySetPS ks;
+
+    /* Validate signature... */
+    ks.purpose.size = htonl (sizeof (ks));
+    ks.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_KEY_SET);
+    ks.list_issue_date = GNUNET_TIME_absolute_hton (key_data->list_issue_date);
+    GNUNET_CRYPTO_hash_context_finish (hash_context,
+                                      &ks.hc);
+    hash_context = NULL;
+    EXITIF (GNUNET_OK !=
+           TALER_EXCHANGE_test_signing_key (key_data,
+                                            &pub));
+    EXITIF (GNUNET_OK !=
+           GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_KEY_SET,
+                                       &ks.purpose,
+                                       &sig.eddsa_signature,
+                                       &pub.eddsa_pub));
+  }
   return GNUNET_OK;
  EXITIF_exit:
 
@@ -769,7 +778,7 @@ free_key_data (struct TALER_EXCHANGE_Keys *key_data)
                      0);
   for (unsigned int i=0;i<key_data->num_auditors;i++)
   {
-    GNUNET_array_grow (key_data->auditors[i].denom_key_offsets,
+    GNUNET_array_grow (key_data->auditors[i].denom_keys,
                        key_data->auditors[i].num_denom_keys,
                        0);
     GNUNET_free (key_data->auditors[i].auditor_url);
@@ -885,20 +894,37 @@ keys_completed_cb (void *cls,
 
       anew->auditor_pub = aold->auditor_pub;
       anew->auditor_url = GNUNET_strdup (aold->auditor_url);
-      GNUNET_array_grow (anew->denom_key_offsets,
+      GNUNET_array_grow (anew->denom_keys,
                          anew->num_denom_keys,
                          aold->num_denom_keys);
-      memcpy (anew->denom_key_offsets,
-              aold->denom_key_offsets,
-              aold->num_denom_keys * sizeof (unsigned int));
+      memcpy (anew->denom_keys,
+              aold->denom_keys,
+              aold->num_denom_keys * sizeof (struct 
TALER_EXCHANGE_AuditorDenominationInfo));
     }
 
     if (GNUNET_OK !=
         decode_keys_json (resp_obj,
+                         GNUNET_YES,
                           &kd,
                          &vc))
     {
       response_code = 0;
+      for (unsigned int i=0;i<kd.num_auditors;i++)
+      {
+       struct TALER_EXCHANGE_AuditorInformation *anew = &kd.auditors[i];
+
+       GNUNET_array_grow (anew->denom_keys,
+                          anew->num_denom_keys,
+                          0);
+       GNUNET_free (anew->auditor_url);
+      }
+      GNUNET_free (kd.auditors);
+      kd.auditors = NULL;
+      for (unsigned int i=0;i<kd_old.num_denom_keys;i++)
+       GNUNET_CRYPTO_rsa_public_key_free (kd.denom_keys[i].key.rsa_public_key);
+      GNUNET_array_grow (kd.denom_keys,
+                        kd.denom_keys_size,
+                        0);
       break;
     }
     json_decref (exchange->key_data_raw);
@@ -918,16 +944,16 @@ keys_completed_cb (void *cls,
     exchange->kr = NULL;
     free_keys_request (kr);
     exchange->state = MHS_FAILED;
-    /* notify application that we failed */
-    exchange->cert_cb (exchange->cert_cb_cls,
-                       NULL,
-                      vc);
     if (NULL != exchange->key_data_raw)
     {
       json_decref (exchange->key_data_raw);
       exchange->key_data_raw = NULL;
     }
     free_key_data (&kd_old);
+    /* notify application that we failed */
+    exchange->cert_cb (exchange->cert_cb_cls,
+                       NULL,
+                      vc);
     return;
   }
 
@@ -1117,8 +1143,11 @@ deserialize_data (struct TALER_EXCHANGE_Handle *exchange,
   enum TALER_EXCHANGE_VersionCompatibility vc;
   json_t *keys;
   const char *url;
+  uint32_t version;
   struct GNUNET_TIME_Absolute expire;
   struct GNUNET_JSON_Specification spec[] = {
+    GNUNET_JSON_spec_uint32 ("version",
+                            &version),
     GNUNET_JSON_spec_json ("keys",
                           &keys),
     GNUNET_JSON_spec_string ("url",
@@ -1139,6 +1168,8 @@ deserialize_data (struct TALER_EXCHANGE_Handle *exchange,
     GNUNET_break_op (0);
     return;
   }
+  if (0 != version)
+    return; /* unsupported version */
   if (0 != strcmp (url,
                   exchange->url))
     {
@@ -1150,6 +1181,7 @@ deserialize_data (struct TALER_EXCHANGE_Handle *exchange,
           sizeof (struct TALER_EXCHANGE_Keys));
   if (GNUNET_OK !=
       decode_keys_json (keys,
+                       GNUNET_NO,
                        &key_data,
                        &vc))
     {
@@ -1181,7 +1213,160 @@ deserialize_data (struct TALER_EXCHANGE_Handle 
*exchange,
 json_t *
 TALER_EXCHANGE_serialize_data (struct TALER_EXCHANGE_Handle *exchange)
 {
-  return NULL;
+  const struct TALER_EXCHANGE_Keys *kd = &exchange->key_data;
+  struct GNUNET_TIME_Absolute now;
+  json_t *keys;
+  json_t *signkeys;
+  json_t *denoms;
+  json_t *auditors;
+
+  now = GNUNET_TIME_absolute_get ();
+  signkeys = json_array ();
+  for (unsigned int i=0;i<kd->num_sign_keys;i++)
+  {
+    const struct TALER_EXCHANGE_SigningPublicKey *sk = &kd->sign_keys[i];
+    json_t *signkey;
+    
+    if (now.abs_value_us > sk->valid_until.abs_value_us)
+      continue; /* skip keys that have expired */
+    signkey = json_pack ("{s:o, s:o, s:o, s:o, s:o}",
+                        "key",
+                        GNUNET_JSON_from_data_auto (&sk->key),
+                        "master_sig",
+                        GNUNET_JSON_from_data_auto (&sk->master_sig),
+                        "stamp_start",
+                        GNUNET_JSON_from_time_abs (sk->valid_from),
+                        "stamp_expire",
+                        GNUNET_JSON_from_time_abs (sk->valid_until),
+                        "stamp_end",
+                        GNUNET_JSON_from_time_abs (sk->valid_legal));
+    if (NULL == signkey)
+    {
+      GNUNET_break (0);
+      continue;
+    }
+    json_array_append_new (signkeys,
+                          signkey);
+  }             
+  denoms = json_array ();
+  for (unsigned int i=0;i<kd->num_denom_keys;i++)
+  {
+    const struct TALER_EXCHANGE_DenomPublicKey *dk = &kd->denom_keys[i];
+    json_t *denom;
+    
+    if (now.abs_value_us > dk->expire_deposit.abs_value_us)
+      continue; /* skip keys that have expired */
+    denom = json_pack ("{s:o, s:o, s:o, s:o, s:o "
+                      ",s:o, s:o, s:o, s:o, s:o "
+                      ,"s:o}",
+                      "stamp_expire_deposit",
+                      GNUNET_JSON_from_time_abs (dk->expire_deposit),
+                      "stamp_expire_withdraw",
+                      GNUNET_JSON_from_time_abs (dk->withdraw_valid_until),
+                      "stamp_start",
+                      GNUNET_JSON_from_time_abs (dk->valid_from),
+                      "stamp_expire_legal",
+                      GNUNET_JSON_from_time_abs (dk->expire_legal),
+                      "value",
+                      TALER_JSON_from_amount (&dk->value),
+                      "fee_withdraw",
+                      /* #6 */
+                      TALER_JSON_from_amount (&dk->fee_withdraw),
+                      "fee_deposit",
+                      TALER_JSON_from_amount (&dk->fee_deposit),
+                      "fee_refresh",
+                      TALER_JSON_from_amount (&dk->fee_refresh),
+                      "fee_refund",
+                      TALER_JSON_from_amount (&dk->fee_refund),
+                      "master_sig",
+                      GNUNET_JSON_from_data_auto (&dk->master_sig),
+                      /* #10 */
+                      "denom_pub",
+                      GNUNET_JSON_from_rsa_public_key 
(dk->key.rsa_public_key));
+    if (NULL == denom)
+    {
+      GNUNET_break (0);
+      continue;
+    }
+    json_array_append_new (denoms,
+                          denom);
+  }             
+  auditors = json_array ();
+  for (unsigned int i=0;i<kd->num_auditors;i++)
+  {
+    const struct TALER_EXCHANGE_AuditorInformation *ai = &kd->auditors[i];
+    json_t *a;
+    json_t *adenoms; 
+
+    adenoms = json_array ();
+    for (unsigned int j=0;j<ai->num_denom_keys;j++)
+    {
+      const struct TALER_EXCHANGE_AuditorDenominationInfo *adi = 
&ai->denom_keys[j];
+      const struct TALER_EXCHANGE_DenomPublicKey *dk = 
&kd->denom_keys[adi->denom_key_offset];
+      json_t *k;
+
+      GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys);
+      k = json_pack ("{s:o, s:o}",
+                    "denom_pub_h",
+                    GNUNET_JSON_from_data_auto (&dk->h_key),
+                    "auditor_sig",
+                    GNUNET_JSON_from_data_auto (&adi->auditor_sig));
+      if (NULL == k)
+      {
+       GNUNET_break (0);
+       continue;
+      }
+      json_array_append_new (adenoms,
+                            k);
+    }
+    
+    a = json_pack ("{s:s, s:o, s:o}",
+                  "auditor_pub",
+                  GNUNET_JSON_from_data_auto (&ai->auditor_pub),
+                  "auditor_url",
+                  ai->auditor_url,
+                  "denomination_keys",
+                  adenoms);
+    if (NULL == a)
+    {
+      GNUNET_break (0);
+      continue;
+    }
+    json_array_append_new (auditors,
+                          a);
+  }             
+  keys = json_pack ("{s:s, s:o, s:o, s:o, s:o"
+                   ",s:o, s:o}",
+                   /* 1 */
+                   "version", 
+                   kd->version,
+                   "master_public_key",
+                   GNUNET_JSON_from_data_auto (&kd->master_pub),
+                   "reserve_closing_delay",
+                   GNUNET_JSON_from_time_rel (kd->reserve_closing_delay),
+                   "list_issue_date",
+                   GNUNET_JSON_from_time_abs (kd->list_issue_date),
+                   "signkeys",
+                   signkeys,
+                   /* #6 */
+                   "denoms",
+                   denoms,
+                   "auditors",
+                   auditors);
+  if (NULL == keys)
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
+  return json_pack ("{s:I, s:o, s:s, s:o}",
+                   "version",
+                   (json_int_t) TALER_SERIALIZATION_FORMAT_VERSION,
+                   "expire",
+                   GNUNET_JSON_from_time_abs (exchange->key_data_expiration),
+                   "url",
+                   exchange->url,
+                   "keys",
+                   keys);
 }
 
 
@@ -1221,24 +1406,24 @@ TALER_EXCHANGE_connect (struct GNUNET_CURL_Context *ctx,
   va_start (ap, cert_cb_cls);
   while (TALER_EXCHANGE_OPTION_END !=
         (opt = va_arg (ap, int)))
+  {
+    switch (opt) {
+    case TALER_EXCHANGE_OPTION_END:
+      GNUNET_assert (0);
+      break;
+    case TALER_EXCHANGE_OPTION_DATA:
     {
-      switch (opt) {
-      case TALER_EXCHANGE_OPTION_END:
-       GNUNET_assert (0);
-       break;
-      case TALER_EXCHANGE_OPTION_DATA:
-       {
-         const json_t *data = va_arg (ap, const json_t *);
-
-         deserialize_data (exchange,
-                           data);
-         break;
-       }
-      default:
-       GNUNET_assert (0);
-       break;
-      }
+      const json_t *data = va_arg (ap, const json_t *);
+      
+      deserialize_data (exchange,
+                       data);
+      break;
     }
+    default:
+      GNUNET_assert (0);
+      break;
+    }
+  }
   va_end (ap);
   return exchange;
 }
diff --git a/src/exchange-lib/test_exchange_api_keys_cherry_picking_new.c 
b/src/exchange-lib/test_exchange_api_keys_cherry_picking_new.c
index cee26dee..b45ef864 100644
--- a/src/exchange-lib/test_exchange_api_keys_cherry_picking_new.c
+++ b/src/exchange-lib/test_exchange_api_keys_cherry_picking_new.c
@@ -105,7 +105,8 @@ run (void *cls,
     TALER_TESTING_cmd_end ()
   };
 
-  TALER_TESTING_run (is, commands);
+  TALER_TESTING_run (is,
+                    commands);
 }
 
 
diff --git a/src/exchange-lib/test_exchange_api_new.c 
b/src/exchange-lib/test_exchange_api_new.c
index 41da319a..06b13e51 100644
--- a/src/exchange-lib/test_exchange_api_new.c
+++ b/src/exchange-lib/test_exchange_api_new.c
@@ -350,7 +350,7 @@ run (void *cls,
      */
     TALER_TESTING_cmd_deposit
       ("refresh-deposit-refreshed-1b", is->exchange,
-       "refresh-reveal-1", 4,
+       "refresh-reveal-1", 3,
        TALER_TESTING_make_wire_details (43,
                                         fakebank_url),
        "{\"items\":[{\"name\":\"ice cream\",\
diff --git a/src/exchange-lib/testing_api_cmd_batch.c 
b/src/exchange-lib/testing_api_cmd_batch.c
index 738012b8..e4d11ae5 100644
--- a/src/exchange-lib/testing_api_cmd_batch.c
+++ b/src/exchange-lib/testing_api_cmd_batch.c
@@ -156,7 +156,6 @@ TALER_TESTING_cmd_batch (const char *label,
   struct BatchState *bs;
   unsigned int i;
 
-  cmd.meta = GNUNET_YES;
   bs = GNUNET_new (struct BatchState);
   bs->batch_ip = -1;
 
@@ -179,3 +178,15 @@ TALER_TESTING_cmd_batch (const char *label,
 
   return cmd;
 }
+
+
+/**
+ * Test if this command is a batch command.
+ *
+ * @return false if not, true if it is a batch command
+ */
+int
+TALER_TESTING_cmd_is_batch (const struct TALER_TESTING_Command *cmd)
+{
+  return cmd->run == &batch_run;
+}
diff --git a/src/exchange-lib/testing_api_cmd_exec_auditor-sign.c 
b/src/exchange-lib/testing_api_cmd_exec_auditor-sign.c
index feebaaeb..48791efb 100644
--- a/src/exchange-lib/testing_api_cmd_exec_auditor-sign.c
+++ b/src/exchange-lib/testing_api_cmd_exec_auditor-sign.c
@@ -103,7 +103,8 @@ auditor_sign_run (void *cls,
      "%s/.local/share/taler/auditors/auditor-%llu.out",
      test_home_dir,
      (unsigned long long) now.abs_value_us);
-
+  GNUNET_free (test_home_dir);
+  
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_string (cfg,
                                              "exchange",
@@ -134,7 +135,7 @@ auditor_sign_run (void *cls,
      "-r", "auditor.in",
      "-o", ass->signed_keys_out,
      NULL);
-
+  GNUNET_free (exchange_master_pub);
   if (NULL == ass->auditor_sign_proc)
   {
     GNUNET_break (0);
diff --git a/src/exchange-lib/testing_api_cmd_refresh.c 
b/src/exchange-lib/testing_api_cmd_refresh.c
index 43c42a17..982b4d29 100644
--- a/src/exchange-lib/testing_api_cmd_refresh.c
+++ b/src/exchange-lib/testing_api_cmd_refresh.c
@@ -1190,7 +1190,7 @@ refresh_reveal_traits (void *cls,
 {
   struct RefreshRevealState *rrs = cls;
   unsigned int num_coins = rrs->num_fresh_coins;
-#define NUM_TRAITS (num_coins * 3) + 3
+#define NUM_TRAITS ((num_coins * 3) + 3)
   struct TALER_TESTING_Trait traits[NUM_TRAITS];
 
   /* Making coin privs traits */
diff --git a/src/exchange-lib/testing_api_helpers.c 
b/src/exchange-lib/testing_api_helpers.c
index 2e2f10e6..62eb6abe 100644
--- a/src/exchange-lib/testing_api_helpers.c
+++ b/src/exchange-lib/testing_api_helpers.c
@@ -434,6 +434,7 @@ TALER_TESTING_setup_with_exchange (TALER_TESTING_Main 
main_cb,
                                  "exchange",
                                  "PORT");
       GNUNET_CONFIGURATION_destroy (cfg);
+      GNUNET_free (serve);
       return GNUNET_NO;
     }
 
@@ -444,9 +445,11 @@ TALER_TESTING_setup_with_exchange (TALER_TESTING_Main 
main_cb,
       fprintf (stderr,
                "Required port %llu not available, skipping.\n",
             port);
+      GNUNET_free (serve);
       return GNUNET_NO;
     }
   }
+  GNUNET_free (serve);
   exchanged = GNUNET_OS_start_process (GNUNET_NO,
                                        GNUNET_OS_INHERIT_STD_ALL,
                                        NULL, NULL, NULL,
@@ -471,8 +474,12 @@ TALER_TESTING_setup_with_exchange (TALER_TESTING_Main 
main_cb,
   GNUNET_CONFIGURATION_destroy (cfg);
 
   if (0 != TALER_TESTING_wait_exchange_ready (base_url))
+  {
+    GNUNET_free (base_url);
     return 77;
-
+  }
+  GNUNET_free (base_url);
+  
   /* NOTE: this blocks.  */
   result = TALER_TESTING_setup (main_cb,
                                 main_cb_cls,
diff --git a/src/exchange-lib/testing_api_loop.c 
b/src/exchange-lib/testing_api_loop.c
index 8309d812..52bf9173 100644
--- a/src/exchange-lib/testing_api_loop.c
+++ b/src/exchange-lib/testing_api_loop.c
@@ -66,7 +66,7 @@ TALER_TESTING_interpreter_lookup_command
                        label)) )
       return cmd;
 
-    if (GNUNET_YES == cmd->meta)
+    if (TALER_TESTING_cmd_is_batch (cmd))
     {
 #define BATCH_INDEX 1
       struct TALER_TESTING_Command *batch;
@@ -173,17 +173,17 @@ TALER_TESTING_interpreter_next (struct 
TALER_TESTING_Interpreter *is)
   struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
 
   if (GNUNET_SYSERR == is->result)
-    return; /* ignore, we already failed! */
-  if (GNUNET_YES == cmd->meta)
+    return; /* ignore, we already failled! */
+  if (TALER_TESTING_cmd_is_batch (cmd))
   {
-    #define CURRENT_BATCH_SUBCMD_INDEX 0
+#define CURRENT_BATCH_SUBCMD_INDEX 0
     struct TALER_TESTING_Command *sub_cmd;
 
     GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_cmd
       (cmd, CURRENT_BATCH_SUBCMD_INDEX, &sub_cmd));
 
-      if (NULL == sub_cmd->label)
-        is->ip++;
+    if (NULL == sub_cmd->label)
+      is->ip++;
   }
   else
     is->ip++;
@@ -204,6 +204,8 @@ TALER_TESTING_interpreter_next (struct 
TALER_TESTING_Interpreter *is)
 
 /**
  * Current command failed, clean up and fail the test case.
+ *
+ * @param is interpreter of the test
  */
 void
 TALER_TESTING_interpreter_fail
@@ -363,7 +365,7 @@ maint_child_death (void *cls)
   struct GNUNET_OS_Process **processp;
   char c[16];
 
-  if (GNUNET_YES == cmd->meta)
+  if (TALER_TESTING_cmd_is_batch (cmd))
   {
     struct TALER_TESTING_Command *batch_cmd;
     GNUNET_assert
@@ -465,9 +467,14 @@ TALER_TESTING_run2 (struct TALER_TESTING_Interpreter *is,
                     struct GNUNET_TIME_Relative timeout)
 {
   unsigned int i;
+
+  if (NULL != is->timeout_task)
+  {
+    GNUNET_SCHEDULER_cancel (is->timeout_task);
+    is->timeout_task = NULL;
+  }
   /* get the number of commands */
   for (i=0;NULL != commands[i].label;i++) ;
-
   is->commands = GNUNET_new_array (i + 1,
                                    struct TALER_TESTING_Command);
   memcpy (is->commands,
@@ -488,7 +495,6 @@ TALER_TESTING_run2 (struct TALER_TESTING_Interpreter *is,
  * defined into the "run" method that returns after
  * having scheduled the test interpreter.
  *
- *
  * @param is the interpreter state
  * @param commands the list of command to execute
  */
@@ -643,6 +649,29 @@ main_wrapper_exchange_agnostic (void *cls)
 
 
 /**
+ * Function run when the test is aborted before we launch the actual
+ * interpreter.  Cleans up our state.
+ *
+ * @param cls the main context
+ */
+static void
+do_abort (void *cls)
+{
+  struct MainContext *main_ctx = cls;
+  struct TALER_TESTING_Interpreter *is = main_ctx->is;
+
+  is->timeout_task = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Executing abort prior to interpreter launch\n");
+  if (NULL != is->exchange)
+  {
+    TALER_EXCHANGE_disconnect (is->exchange);
+    is->exchange = NULL;
+  }
+}
+
+
+/**
  * Initialize scheduler loop and curl context for the testcase,
  * and responsible to run the "run" method.
  *
@@ -676,6 +705,8 @@ main_wrapper_exchange_connect (void *cls)
     return;
   }
   main_ctx->exchange_url = exchange_url;
+  is->timeout_task = GNUNET_SCHEDULER_add_shutdown (&do_abort,
+                                                   main_ctx);
   GNUNET_assert (NULL !=
                  (is->exchange = TALER_EXCHANGE_connect (is->ctx,
                                                          exchange_url,
@@ -732,8 +763,8 @@ TALER_TESTING_setup (TALER_TESTING_Main main_cb,
                               GNUNET_NO, GNUNET_NO);
   GNUNET_assert (NULL != sigpipe);
   shc_chld = GNUNET_SIGNAL_handler_install
-    (GNUNET_SIGCHLD, &sighandler_child_death);
-
+    (GNUNET_SIGCHLD,
+     &sighandler_child_death);
   is.ctx = GNUNET_CURL_init
     (&GNUNET_CURL_gnunet_scheduler_reschedule,
      &is.rc);
diff --git a/src/exchange-lib/testing_api_trait_cmd.c 
b/src/exchange-lib/testing_api_trait_cmd.c
index 9f7c8d5c..8e796219 100644
--- a/src/exchange-lib/testing_api_trait_cmd.c
+++ b/src/exchange-lib/testing_api_trait_cmd.c
@@ -37,7 +37,7 @@
  * @param cmd command to extract the command from.
  * @param index always zero.  Commands offering this
  *        kind of traits do not need this index.  For
- *        example, a "meta" CMD returns always the
+ *        example, a "batch" CMD returns always the
  *        CMD currently being executed.
  * @param cmd_[out] where to write the wire details.
  *
diff --git a/src/exchange/taler-exchange-httpd_keystate.c 
b/src/exchange/taler-exchange-httpd_keystate.c
index 6c2d342b..2e1a85f8 100644
--- a/src/exchange/taler-exchange-httpd_keystate.c
+++ b/src/exchange/taler-exchange-httpd_keystate.c
@@ -280,6 +280,26 @@ struct TEH_KS_StateHandle
 };
 
 
+
+/**
+ * Exchange key state.  This is the long-term, read-only internal global state,
+ * which the various threads "lock" to use in read-only ways.  We eventually
+ * create a completely new object "on the side" and then start to return
+ * the new read-only object to threads that ask. Once none of the threads
+ * use the previous object (RC drops to zero), we discard it.
+ *
+ * Thus, this instance should never be used directly, instead reserve
+ * access via #TEH_KS_acquire() and release it via #TEH_KS_release().
+ */
+static struct TEH_KS_StateHandle *internal_key_state;
+
+/**
+ * Mutex protecting access to #internal_key_state.
+ */
+static pthread_mutex_t internal_key_state_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+
 /* ************************** Clean up logic *********************** */
 
 
@@ -373,6 +393,10 @@ static void
 ks_release (struct TEH_KS_StateHandle *key_state)
 {
   GNUNET_assert (0 < key_state->refcnt);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "KS release called (%p/%d)\n",
+             key_state,
+             key_state->refcnt);
   key_state->refcnt--;
   if (0 == key_state->refcnt)
   {
@@ -404,6 +428,7 @@ ks_release (struct TEH_KS_StateHandle *key_state)
     GNUNET_array_grow (key_state->krd_array,
                        key_state->krd_array_length,
                        0);
+    GNUNET_assert (key_state != internal_key_state);
     GNUNET_free (key_state);
   }
 }
@@ -1604,25 +1629,6 @@ make_fresh_key_state ()
 /* ************************** Persistent part ********************** */
 
 /**
- * Exchange key state.  This is the long-term, read-only internal global state,
- * which the various threads "lock" to use in read-only ways.  We eventually
- * create a completely new object "on the side" and then start to return
- * the new read-only object to threads that ask. Once none of the threads
- * use the previous object (RC drops to zero), we discard it.
- *
- * Thus, this instance should never be used directly, instead reserve
- * access via #TEH_KS_acquire() and release it via #TEH_KS_release().
- */
-static struct TEH_KS_StateHandle *internal_key_state;
-
-/**
- * Mutex protecting access to #internal_key_state.
- */
-static pthread_mutex_t internal_key_state_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-
-
-/**
  * Release key state, free if necessary (if reference count gets to zero).
  *
  * @param location name of the function in which the lock is acquired
@@ -1634,8 +1640,10 @@ TEH_KS_release_ (const char *location,
 {
   GNUNET_assert (0 == pthread_mutex_lock (&internal_key_state_mutex));
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "KS released at %s\n",
-              location);
+              "KS released at %s (%p/%d)\n",
+              location,
+             key_state,
+             key_state->refcnt);
   ks_release (key_state);
   GNUNET_assert (0 == pthread_mutex_unlock (&internal_key_state_mutex));
 }
@@ -1654,22 +1662,43 @@ TEH_KS_acquire_ (const char *location)
 {
   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
   struct TEH_KS_StateHandle *key_state;
+  unsigned int rcd;
 
   GNUNET_assert (0 == pthread_mutex_lock (&internal_key_state_mutex));
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "KS acquired at %s\n",
-              location);
+  rcd = 0;
   if ( (NULL != internal_key_state) &&
        (internal_key_state->next_reload.abs_value_us <= now.abs_value_us) )
   {
-    ks_release (internal_key_state);
+    struct TEH_KS_StateHandle *ks = internal_key_state;
+    
     internal_key_state = NULL;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "KS released in acquire due to expiration\n");
+    ks_release (ks);
+    rcd = 1; /* remember that we released 'internal_key_state' */
   }
   if (NULL == internal_key_state)
+  {
     internal_key_state = make_fresh_key_state ();
+    /* bump RC by 1 if we released internal_key_state above */
+    internal_key_state->refcnt += rcd;
+  }
   key_state = internal_key_state;
   if (NULL != key_state)
+  {
     key_state->refcnt++;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "KS acquired at %s (%p/%d)\n",
+               location,
+               key_state,
+               key_state->refcnt);
+  }
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+               "KS acquire failed at %s\n",
+               location);
+  }
   GNUNET_assert (0 == pthread_mutex_unlock (&internal_key_state_mutex));
 
   return key_state;
@@ -1876,8 +1905,10 @@ TEH_KS_loop (void)
                 "(re-)loading keys\n");
     if (NULL != internal_key_state)
     {
-      TEH_KS_release (internal_key_state);
+      struct TEH_KS_StateHandle *ks = internal_key_state;
+
       internal_key_state = NULL;
+      TEH_KS_release (ks);
     }
     /* This will re-initialize 'internal_key_state' with
        an initial refcnt of 1 */
@@ -1944,8 +1975,10 @@ TEH_KS_free ()
 {
   if (NULL != internal_key_state)
   {
-    TEH_KS_release (internal_key_state);
+    struct TEH_KS_StateHandle *ks = internal_key_state;
+    
     internal_key_state = NULL;
+    TEH_KS_release (ks);
   }
 }
 
diff --git a/src/include/taler_exchange_service.h 
b/src/include/taler_exchange_service.h
index 1ddd7c13..f4038751 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -63,14 +63,24 @@ struct TALER_EXCHANGE_SigningPublicKey
   struct TALER_ExchangePublicKeyP key;
 
   /**
+   * Signature over this signing key by the exchange's master signature.
+   */
+  struct TALER_MasterSignatureP master_sig;
+  
+  /**
    * Validity start time
    */
   struct GNUNET_TIME_Absolute valid_from;
 
   /**
-   * Validity expiration time
+   * Validity expiration time (how long the exchange may use it).
    */
   struct GNUNET_TIME_Absolute valid_until;
+
+  /**
+   * Validity expiration time for legal disputes.
+   */
+  struct GNUNET_TIME_Absolute valid_legal;
 };
 
 
@@ -90,6 +100,11 @@ struct TALER_EXCHANGE_DenomPublicKey
   struct GNUNET_HashCode h_key;
 
   /**
+   * Exchange's master signature over this denomination record.
+   */
+  struct TALER_MasterSignatureP master_sig;
+  
+  /**
    * Timestamp indicating when the denomination key becomes valid
    */
   struct GNUNET_TIME_Absolute valid_from;
@@ -142,6 +157,27 @@ struct TALER_EXCHANGE_DenomPublicKey
 
 
 /**
+ * Information we track per denomination audited by the auditor.
+ */
+struct TALER_EXCHANGE_AuditorDenominationInfo
+{
+
+  /**
+   * Signature by the auditor affirming that it is monitoring this
+   * denomination.
+   */
+  struct TALER_AuditorSignatureP auditor_sig;
+  
+  /**
+   * Offsets into the key's main `denom_keys` array identifying the
+   * denomination being audited by this auditor.
+   */
+  unsigned int denom_key_offset;
+
+};
+
+
+/**
  * @brief Information we get from the exchange about auditors.
  */
 struct TALER_EXCHANGE_AuditorInformation
@@ -164,16 +200,15 @@ struct TALER_EXCHANGE_AuditorInformation
   char *auditor_url;
 
   /**
-   * Number of denomination keys audited by this auditor.
+   * Array of length @a num_denom_keys with the denomination
+   * keys audited by this auditor. 
    */
-  unsigned int num_denom_keys;
+  struct TALER_EXCHANGE_AuditorDenominationInfo *denom_keys;
 
   /**
-   * Array of length @a num_denom_keys with the denomination
-   * keys audited by this auditor.  Offsets into the
-   * key's main `denom_keys` array.
+   * Number of denomination keys audited by this auditor.
    */
-  unsigned int *denom_key_offsets;
+  unsigned int num_denom_keys;
 };
 
 
diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h
index 97189a55..9d5b6438 100644
--- a/src/include/taler_testing_lib.h
+++ b/src/include/taler_testing_lib.h
@@ -314,17 +314,9 @@ struct TALER_TESTING_Command
             const char *trait,
             unsigned int index);
 
-
-  /**
-   * Has GNUNET_YES if the command is a "meta" one.  Meta
-   * commands are those that takes arrays of commands and
-   * execute them.  Are used to group testing commands in
-   * order to improve readability of test cases.
-   */
-  unsigned int meta;
-
 };
 
+
 /**
  * Lookup command by label.
  *
@@ -1253,6 +1245,14 @@ TALER_TESTING_cmd_batch (const char *label,
                          struct TALER_TESTING_Command *batch);
 
 
+/**
+ * Test if this command is a batch command.
+ *
+ * @return false if not, true if it is a batch command
+ */
+int
+TALER_TESTING_cmd_is_batch (const struct TALER_TESTING_Command *cmd);
+
 
 /* *** Generic trait logic for implementing traits ********* */
 

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

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