summaryrefslogtreecommitdiff
path: root/src/wire
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-03-19 15:23:11 +0100
committerChristian Grothoff <christian@grothoff.org>2016-03-19 15:23:11 +0100
commit0d1eced630f4ed05ad95fdbb4354fd428c9cdbf6 (patch)
tree0ed4d6f189ed72287a0e003446c87a2b6db70c1a /src/wire
parentd229f78da3b0b7f851d3541f59651b4f600c879d (diff)
downloadexchange-0d1eced630f4ed05ad95fdbb4354fd428c9cdbf6.tar.gz
exchange-0d1eced630f4ed05ad95fdbb4354fd428c9cdbf6.tar.bz2
exchange-0d1eced630f4ed05ad95fdbb4354fd428c9cdbf6.zip
first refactoring of JSON logic to address #4150 and #4237
Diffstat (limited to 'src/wire')
-rw-r--r--src/wire/Makefile.am3
-rw-r--r--src/wire/plugin_wire_sepa.c151
-rw-r--r--src/wire/plugin_wire_template.c6
-rw-r--r--src/wire/plugin_wire_test.c119
-rw-r--r--src/wire/test_sepa_wireformat.c40
5 files changed, 220 insertions, 99 deletions
diff --git a/src/wire/Makefile.am b/src/wire/Makefile.am
index eb2e893fa..67a559a36 100644
--- a/src/wire/Makefile.am
+++ b/src/wire/Makefile.am
@@ -36,7 +36,9 @@ libtaler_plugin_wire_sepa_la_LIBADD = \
$(LTLIBINTL)
libtaler_plugin_wire_sepa_la_LDFLAGS = \
$(TALER_PLUGIN_LDFLAGS) \
+ $(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetjson \
-lgnunetutil $(XLIB)
@@ -75,4 +77,3 @@ test_sepa_wireformat_LDADD = \
-ljansson \
libtalerwire.la \
$(top_builddir)/src/util/libtalerutil.la
-
diff --git a/src/wire/plugin_wire_sepa.c b/src/wire/plugin_wire_sepa.c
index 4d902f962..904afa9bf 100644
--- a/src/wire/plugin_wire_sepa.c
+++ b/src/wire/plugin_wire_sepa.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2016 GNUnet e.V.
+ Copyright (C) 2016 GNUnet e.V. & Inria
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -23,6 +23,8 @@
*/
#include "platform.h"
#include "taler_wire_plugin.h"
+#include "taler_signatures.h"
+#include <gnunet/gnunet_json_lib.h>
/**
@@ -58,6 +60,8 @@ sepa_amount_round (void *cls,
struct SepaClosure *sc = cls;
uint32_t delta;
+ if (NULL == sc->currency)
+ return GNUNET_SYSERR;
if (0 != strcasecmp (amount->currency,
sc->currency))
{
@@ -348,41 +352,115 @@ validate_iban (const char *iban)
/**
+ * Verify that the signature in the @a json for /wire/sepa is valid.
+ *
+ * @param json json reply with the signature
+ * @param master_pub public key of the exchange to verify against
+ * @return #GNUNET_SYSERR if @a json is invalid,
+ * #GNUNET_NO if the method is unknown,
+ * #GNUNET_OK if the json is valid
+ */
+static int
+verify_wire_sepa_signature_ok (const json_t *json,
+ const struct TALER_MasterPublicKeyP *master_pub)
+{
+ struct TALER_MasterSignatureP exchange_sig;
+ struct TALER_MasterWireSepaDetailsPS mp;
+ const char *receiver_name;
+ const char *iban;
+ const char *bic;
+ struct GNUNET_HashContext *hc;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("sig", &exchange_sig),
+ GNUNET_JSON_spec_string ("receiver_name", &receiver_name),
+ GNUNET_JSON_spec_string ("iban", &iban),
+ GNUNET_JSON_spec_string ("bic", &bic),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (NULL == master_pub)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Skipping signature check as master public key not given\n");
+ return GNUNET_OK;
+ }
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json, spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ mp.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SEPA_DETAILS);
+ mp.purpose.size = htonl (sizeof (struct TALER_MasterWireSepaDetailsPS));
+ hc = GNUNET_CRYPTO_hash_context_start ();
+ GNUNET_CRYPTO_hash_context_read (hc,
+ receiver_name,
+ strlen (receiver_name) + 1);
+ GNUNET_CRYPTO_hash_context_read (hc,
+ iban,
+ strlen (iban) + 1);
+ GNUNET_CRYPTO_hash_context_read (hc,
+ bic,
+ strlen (bic) + 1);
+ GNUNET_CRYPTO_hash_context_finish (hc,
+ &mp.h_sepa_details);
+
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SEPA_DETAILS,
+ &mp.purpose,
+ &exchange_sig.eddsa_signature,
+ &master_pub->eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_JSON_parse_free (spec);
+ return GNUNET_OK;
+}
+
+
+/**
* Check if the given wire format JSON object is correctly formatted
*
+ * @param cls the @e cls of this struct with the plugin-specific state
* @param wire the JSON wire format object
+ * @param master_pub public key of the exchange to verify against
* @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
*/
static int
-sepa_wire_validate (const json_t *wire)
+sepa_wire_validate (void *cls,
+ const json_t *wire,
+ const struct TALER_MasterPublicKeyP *master_pub)
{
json_error_t error;
const char *type;
const char *iban;
const char *name;
const char *bic;
- uint64_t r;
- const char *address;
if (0 != json_unpack_ex
((json_t *) wire,
- &error, JSON_STRICT,
+ &error, 0,
"{"
- "s:s," /* TYPE: sepa */
- "s:s," /* IBAN: iban */
- "s:s," /* name: beneficiary name */
- "s:s," /* BIC: beneficiary bank's BIC */
- "s:i," /* r: random 64-bit integer nounce */
- "s:s" /* address: address of the beneficiary */
+ "s:s," /* type: sepa */
+ "s:s," /* iban: IBAN */
+ "s:s," /* receiver_name: beneficiary name */
+ "s:s" /* bic: beneficiary bank's BIC */
"}",
"type", &type,
- "IBAN", &iban,
- "name", &name,
- "bic", &bic,
- "r", &r,
- "address", &address))
+ "iban", &iban,
+ "receiver_name", &name,
+ "bic", &bic))
{
- TALER_json_warn (error);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "JSON parsing failed at %s:%u: %s (%s)\n",
+ __FILE__, __LINE__,
+ error.text, error.source);
+ json_dumpf (wire, stderr, 0);
+ fprintf (stderr, "\n");
return GNUNET_SYSERR;
}
if (0 != strcasecmp (type,
@@ -400,6 +478,15 @@ sepa_wire_validate (const json_t *wire)
iban);
return GNUNET_NO;
}
+ /* FIXME: don't parse again, integrate properly... */
+ if (GNUNET_OK !=
+ verify_wire_sepa_signature_ok (wire,
+ master_pub))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Signature invalid\n");
+ return GNUNET_NO;
+ }
return GNUNET_YES;
}
@@ -499,19 +586,21 @@ libtaler_plugin_wire_sepa_init (void *cls)
struct TALER_WIRE_Plugin *plugin;
sc = GNUNET_new (struct SepaClosure);
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "exchange",
- "CURRENCY",
- &sc->currency))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange",
- "CURRENCY");
- GNUNET_free (sc);
- return NULL;
- }
-
+ if (NULL != cfg)
+ {
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchange",
+ "CURRENCY",
+ &sc->currency))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "CURRENCY");
+ GNUNET_free (sc);
+ return NULL;
+ }
+ }
plugin = GNUNET_new (struct TALER_WIRE_Plugin);
plugin->cls = sc;
plugin->amount_round = &sepa_amount_round;
@@ -536,7 +625,7 @@ libtaler_plugin_wire_sepa_done (void *cls)
struct TALER_WIRE_Plugin *plugin = cls;
struct SepaClosure *sc = plugin->cls;
- GNUNET_free (sc->currency);
+ GNUNET_free_non_null (sc->currency);
GNUNET_free (sc);
GNUNET_free (plugin);
return NULL;
diff --git a/src/wire/plugin_wire_template.c b/src/wire/plugin_wire_template.c
index 2e9512e57..91b380c38 100644
--- a/src/wire/plugin_wire_template.c
+++ b/src/wire/plugin_wire_template.c
@@ -76,11 +76,15 @@ template_amount_round (void *cls,
/**
* Check if the given wire format JSON object is correctly formatted
*
+ * @param cls the @e cls of this struct with the plugin-specific state
* @param wire the JSON wire format object
+ * @param master_pub public key of the exchange to verify against
* @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
*/
static int
-template_wire_validate (const json_t *wire)
+template_wire_validate (void *cls,
+ const json_t *wire,
+ const struct TALER_MasterPublicKeyP *master_pub)
{
GNUNET_break (0);
return GNUNET_SYSERR;
diff --git a/src/wire/plugin_wire_test.c b/src/wire/plugin_wire_test.c
index 1d19edf57..70cf82462 100644
--- a/src/wire/plugin_wire_test.c
+++ b/src/wire/plugin_wire_test.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2016 GNUnet e.V.
+ Copyright (C) 2016 GNUnet e.V. & Inria
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -215,6 +215,8 @@ test_amount_round (void *cls,
struct TestClosure *tc = cls;
uint32_t delta;
+ if (NULL == tc->currency)
+ return GNUNET_SYSERR; /* not configured with currency */
if (0 != strcasecmp (amount->currency,
tc->currency))
{
@@ -235,11 +237,15 @@ test_amount_round (void *cls,
* Right now, the only thing we require is a field
* "account_number" which must contain a positive 53-bit integer.
*
+ * @param cls the @e cls of this struct with the plugin-specific state
* @param wire the JSON wire format object
+ * @param master_pub public key of the exchange to verify against
* @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
*/
static int
-test_wire_validate (const json_t *wire)
+test_wire_validate (void *cls,
+ const json_t *wire,
+ const struct TALER_MasterPublicKeyP *master_pub)
{
json_error_t error;
json_int_t account_no;
@@ -368,7 +374,9 @@ test_prepare_wire_transfer (void *cls,
struct TALER_WIRE_PrepareHandle *pth;
if (GNUNET_YES !=
- test_wire_validate (wire))
+ test_wire_validate (cls,
+ wire,
+ NULL))
{
GNUNET_break (0);
return NULL;
@@ -456,6 +464,8 @@ test_execute_wire_transfer (void *cls,
json_int_t account_no;
struct BufFormatP bf;
+ if (NULL == tc->bank)
+ return NULL; /* not initialized with configuration, cannot do transfers */
if ( (buf_size <= sizeof (struct BufFormatP)) ||
('\0' != buf[buf_size -1]) )
{
@@ -476,7 +486,9 @@ test_execute_wire_transfer (void *cls,
return NULL;
}
GNUNET_assert (GNUNET_YES ==
- test_wire_validate (wire));
+ test_wire_validate (NULL,
+ wire,
+ NULL));
if (0 !=
json_unpack_ex (wire,
&error,
@@ -545,53 +557,56 @@ libtaler_plugin_wire_test_init (void *cls)
struct TALER_WIRE_Plugin *plugin;
char *uri;
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "wire-test",
- "BANK_URI",
- &uri))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "wire-test",
- "BANK_URI");
- return NULL;
- }
tc = GNUNET_new (struct TestClosure);
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (cfg,
- "wire-test",
- "BANK_ACCOUNT_NO_OUTGOING",
- &tc->exchange_account_no))
+ if (NULL != cfg)
{
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "wire-test",
- "BANK_ACCOUNT_NO_OUTGOING");
- GNUNET_free (uri);
- GNUNET_free (tc);
- return NULL;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "exchange",
- "CURRENCY",
- &tc->currency))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange",
- "CURRENCY");
- GNUNET_free (uri);
- GNUNET_free (tc);
- return NULL;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "wire-test",
+ "BANK_URI",
+ &uri))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "wire-test",
+ "BANK_URI");
+ GNUNET_free (tc);
+ return NULL;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg,
+ "wire-test",
+ "BANK_ACCOUNT_NO_OUTGOING",
+ &tc->exchange_account_no))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "wire-test",
+ "BANK_ACCOUNT_NO_OUTGOING");
+ GNUNET_free (uri);
+ GNUNET_free (tc);
+ return NULL;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchange",
+ "CURRENCY",
+ &tc->currency))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "CURRENCY");
+ GNUNET_free (uri);
+ GNUNET_free (tc);
+ return NULL;
+ }
+ tc->bank = TALER_BANK_init (uri);
+ if (NULL == tc->bank)
+ {
+ GNUNET_break (0);
+ GNUNET_free (tc->currency);
+ GNUNET_free (tc);
+ return NULL;
+ }
}
- tc->bank = TALER_BANK_init (uri);
- if (NULL == tc->bank)
- {
- GNUNET_break (0);
- GNUNET_free (tc->currency);
- GNUNET_free (tc);
- return NULL;
- }
-
plugin = GNUNET_new (struct TALER_WIRE_Plugin);
plugin->cls = tc;
plugin->amount_round = &test_amount_round;
@@ -621,8 +636,12 @@ libtaler_plugin_wire_test_done (void *cls)
GNUNET_SCHEDULER_cancel (tc->bt);
tc->bt = NULL;
}
- TALER_BANK_fini (tc->bank);
- GNUNET_free (tc->currency);
+ if (NULL != tc->bank)
+ {
+ TALER_BANK_fini (tc->bank);
+ tc->bank = NULL;
+ }
+ GNUNET_free_non_null (tc->currency);
GNUNET_free (tc);
GNUNET_free (plugin);
return NULL;
diff --git a/src/wire/test_sepa_wireformat.c b/src/wire/test_sepa_wireformat.c
index 5081cbe86..f016cf635 100644
--- a/src/wire/test_sepa_wireformat.c
+++ b/src/wire/test_sepa_wireformat.c
@@ -28,37 +28,37 @@
/* Valid SEPA data */
static const char * const valid_wire_str =
"{ \"type\":\"SEPA\", \
-\"IBAN\":\"DE67830654080004822650\", \
-\"name\":\"GNUnet e.V.\", \
+\"iban\":\"DE67830654080004822650\", \
+\"receiver_name\":\"GNUnet e.V.\", \
\"bic\":\"GENODEF1SLR\", \
-\"r\":123456789, \
+\"salt\":\"123456789\", \
\"address\": \"foobar\"}";
/* IBAN has wrong country code */
static const char * const invalid_wire_str =
"{ \"type\":\"SEPA\", \
-\"IBAN\":\"XX67830654080004822650\", \
-\"name\":\"GNUnet e.V.\", \
+\"iban\":\"XX67830654080004822650\", \
+\"receiver_name\":\"GNUnet e.V.\", \
\"bic\":\"GENODEF1SLR\", \
-\"r\":123456789, \
+\"salt\":\"123456789\", \
\"address\": \"foobar\"}";
/* IBAN has wrong checksum */
static const char * const invalid_wire_str2 =
"{ \"type\":\"SEPA\", \
-\"IBAN\":\"DE67830654080004822651\", \
-\"name\":\"GNUnet e.V.\", \
+\"iban\":\"DE67830654080004822651\", \
+\"receiver_name\":\"GNUnet e.V.\", \
\"bic\":\"GENODEF1SLR\", \
-\"r\":123456789, \
+\"salt\":\"123456789\", \
\"address\": \"foobar\"}";
/* Unsupported wireformat type */
static const char * const unsupported_wire_str =
"{ \"type\":\"unsupported\", \
-\"IBAN\":\"DE67830654080004822650\", \
-\"name\":\"GNUnet e.V.\", \
+\"iban\":\"DE67830654080004822650\", \
+\"receiver_name\":\"GNUnet e.V.\", \
\"bic\":\"GENODEF1SLR\", \
-\"r\":123456789, \
+\"salt\":\"123456789\", \
\"address\": \"foobar\"}";
@@ -85,16 +85,24 @@ main(int argc,
GNUNET_assert (NULL != plugin);
(void) memset(&error, 0, sizeof(error));
GNUNET_assert (NULL != (wire = json_loads (unsupported_wire_str, 0, NULL)));
- GNUNET_assert (GNUNET_YES != plugin->wire_validate (wire));
+ GNUNET_assert (GNUNET_YES != plugin->wire_validate (NULL,
+ wire,
+ NULL));
json_decref (wire);
GNUNET_assert (NULL != (wire = json_loads (invalid_wire_str, 0, NULL)));
- GNUNET_assert (GNUNET_NO == plugin->wire_validate (wire));
+ GNUNET_assert (GNUNET_NO == plugin->wire_validate (NULL,
+ wire,
+ NULL));
json_decref (wire);
GNUNET_assert (NULL != (wire = json_loads (invalid_wire_str2, 0, NULL)));
- GNUNET_assert (GNUNET_NO == plugin->wire_validate (wire));
+ GNUNET_assert (GNUNET_NO == plugin->wire_validate (NULL,
+ wire,
+ NULL));
json_decref (wire);
GNUNET_assert (NULL != (wire = json_loads (valid_wire_str, 0, &error)));
- ret = plugin->wire_validate (wire);
+ ret = plugin->wire_validate (NULL,
+ wire,
+ NULL);
json_decref (wire);
TALER_WIRE_plugin_unload (plugin);
GNUNET_CONFIGURATION_destroy (cfg);