From daae3d3ddf1cbee4761a6a2c0066732fb4723fb0 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 2 Apr 2016 20:58:22 +0200 Subject: change taler-exchange-sepa to a more generic taler-exchange-wire tool using the wire plugins (#4237) --- src/wire/plugin_wire_sepa.c | 132 +++++++++++++++++++++++++++++++++------- src/wire/plugin_wire_template.c | 23 +++++++ src/wire/plugin_wire_test.c | 93 ++++++++++++++++++++++++++++ 3 files changed, 226 insertions(+), 22 deletions(-) (limited to 'src/wire') diff --git a/src/wire/plugin_wire_sepa.c b/src/wire/plugin_wire_sepa.c index 995436725..466e450be 100644 --- a/src/wire/plugin_wire_sepa.c +++ b/src/wire/plugin_wire_sepa.c @@ -351,6 +351,42 @@ validate_iban (const char *iban) } +/** + * Compute purpose for signing. + * + * @param sepa_name name of the account holder + * @param iban bank account number in IBAN format + * @param bic bank identifier + * @param[out] mp purpose to be signed + */ +static void +compute_purpose (const char *sepa_name, + const char *iban, + const char *bic, + struct TALER_MasterWireDetailsPS *wsd) +{ + struct GNUNET_HashContext *hc; + + wsd->purpose.size = htonl (sizeof (struct TALER_MasterWireDetailsPS)); + wsd->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SEPA_DETAILS); + hc = GNUNET_CRYPTO_hash_context_start (); + GNUNET_CRYPTO_hash_context_read (hc, + "sepa", + strlen ("sepa") + 1); + GNUNET_CRYPTO_hash_context_read (hc, + sepa_name, + strlen (sepa_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, + &wsd->h_sepa_details); +} + + /** * Verify that the signature in the @a json for /wire/sepa is valid. * @@ -365,14 +401,13 @@ 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; + struct TALER_MasterWireDetailsPS mp; + const char *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 ("name", &name), GNUNET_JSON_spec_string ("iban", &iban), GNUNET_JSON_spec_string ("bic", &bic), GNUNET_JSON_spec_end() @@ -391,22 +426,10 @@ verify_wire_sepa_signature_ok (const json_t *json, 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); - + compute_purpose (name, + iban, + bic, + &mp); if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SEPA_DETAILS, &mp.purpose, @@ -447,12 +470,12 @@ sepa_wire_validate (void *cls, "{" "s:s," /* type: sepa */ "s:s," /* iban: IBAN */ - "s:s," /* receiver_name: beneficiary name */ + "s:s," /* name: beneficiary name */ "s:s" /* bic: beneficiary bank's BIC */ "}", "type", &type, "iban", &iban, - "receiver_name", &name, + "name", &name, "bic", &bic)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -548,6 +571,70 @@ sepa_get_wire_details (void *cls, } +/** + * Sign wire transfer details in the plugin-specific format. + * + * @param cls closure + * @param in wire transfer details in JSON format + * @param key private signing key to use + * @param salt salt to add + * @param[out] sig where to write the signature + * @return #GNUNET_OK on success + */ +static int +sepa_sign_wire_details (void *cls, + const json_t *in, + const struct TALER_MasterPrivateKeyP *key, + const struct GNUNET_HashCode *salt, + struct TALER_MasterSignatureP *sig) +{ + struct TALER_MasterWireDetailsPS wsd; + const char *sepa_name; + const char *iban; + const char *bic; + const char *type; + json_error_t err; + + if (0 != + json_unpack_ex ((json_t *) in, + &err, + 0 /* flags */, + "{s:s, s:s, s:s, s:s}", + "type", &type, + "name", &sepa_name, + "iban", &iban, + "bic", &bic)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to unpack JSON: %s (at %u)\n", + err.text, + err.position); + return GNUNET_SYSERR; + } + if (0 != strcmp (type, + "sepa")) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`type' must be `sepa' for SEPA wire details\n"); + return GNUNET_SYSERR; + } + if (1 != validate_iban (iban)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "IBAN invalid in SEPA wire details\n"); + return GNUNET_SYSERR; + } + compute_purpose (sepa_name, + iban, + bic, + &wsd); + GNUNET_CRYPTO_eddsa_sign (&key->eddsa_priv, + &wsd.purpose, + &sig->eddsa_signature); + return GNUNET_OK; +} + + /** * Prepare for exeuction of a wire transfer. * @@ -662,6 +749,7 @@ libtaler_plugin_wire_sepa_init (void *cls) plugin->cls = sc; plugin->amount_round = &sepa_amount_round; plugin->get_wire_details = &sepa_get_wire_details; + plugin->sign_wire_details = &sepa_sign_wire_details; plugin->wire_validate = &sepa_wire_validate; plugin->prepare_wire_transfer = &sepa_prepare_wire_transfer; plugin->prepare_wire_transfer_cancel = &sepa_prepare_wire_transfer_cancel; diff --git a/src/wire/plugin_wire_template.c b/src/wire/plugin_wire_template.c index fd6fbfbe9..46908c297 100644 --- a/src/wire/plugin_wire_template.c +++ b/src/wire/plugin_wire_template.c @@ -171,6 +171,28 @@ template_execute_wire_transfer (void *cls, } +/** + * Sign wire transfer details in the plugin-specific format. + * + * @param cls closure + * @param in wire transfer details in JSON format + * @param key private signing key to use + * @param salt salt to add + * @param[out] sig where to write the signature + * @return #GNUNET_OK on success + */ +static int +template_sign_wire_details (void *cls, + const json_t *in, + const struct TALER_MasterPrivateKeyP *key, + const struct GNUNET_HashCode *salt, + struct TALER_MasterSignatureP *sig) +{ + GNUNET_break (0); + return GNUNET_SYSERR; +} + + /** * Abort execution of a wire transfer. For example, because we are * shutting down. Note that if an execution is aborted, it may or @@ -236,6 +258,7 @@ libtaler_plugin_wire_template_init (void *cls) plugin->cls = tc; plugin->amount_round = &template_amount_round; plugin->get_wire_details = &template_get_wire_details; + plugin->sign_wire_details = &template_sign_wire_details; plugin->wire_validate = &template_wire_validate; plugin->prepare_wire_transfer = &template_prepare_wire_transfer; plugin->prepare_wire_transfer_cancel = &template_prepare_wire_transfer_cancel; diff --git a/src/wire/plugin_wire_test.c b/src/wire/plugin_wire_test.c index 304380721..8c03d155e 100644 --- a/src/wire/plugin_wire_test.c +++ b/src/wire/plugin_wire_test.c @@ -22,6 +22,7 @@ #include "platform.h" #include "taler_wire_plugin.h" #include "taler_bank_service.h" +#include "taler_signatures.h" /* only for HTTP status codes */ #include @@ -285,6 +286,38 @@ test_get_wire_details (void *cls, } +/** + * Compute purpose for signing. + * + * @param account number of the account + * @param bank_uri URI of the bank + * @param[out] mp purpose to be signed + */ +static void +compute_purpose (uint64_t account, + const char *bank_uri, + struct TALER_MasterWireDetailsPS *wsd) +{ + struct GNUNET_HashContext *hc; + uint64_t n = GNUNET_htonll (account); + + wsd->purpose.size = htonl (sizeof (struct TALER_MasterWireDetailsPS)); + wsd->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_TEST_DETAILS); + hc = GNUNET_CRYPTO_hash_context_start (); + GNUNET_CRYPTO_hash_context_read (hc, + "test", + strlen ("test") + 1); + GNUNET_CRYPTO_hash_context_read (hc, + &n, + sizeof (n)); + GNUNET_CRYPTO_hash_context_read (hc, + bank_uri, + strlen (bank_uri) + 1); + GNUNET_CRYPTO_hash_context_finish (hc, + &wsd->h_sepa_details); +} + + /** * Check if the given wire format JSON object is correctly formatted. * Right now, the only thing we require is a field @@ -319,6 +352,10 @@ test_wire_validate (void *cls, GNUNET_break (0); return GNUNET_SYSERR; } + /* FIXME: should check signature here in the future! + (note: right now the sig is not properly provided + by the exchange due to the way account data is + specified in the configuration) */ return GNUNET_YES; } @@ -510,6 +547,61 @@ execute_cb (void *cls, } +/** + * Sign wire transfer details in the plugin-specific format. + * + * @param cls closure + * @param in wire transfer details in JSON format + * @param key private signing key to use + * @param salt salt to add + * @param[out] sig where to write the signature + * @return #GNUNET_OK on success + */ +static int +test_sign_wire_details (void *cls, + const json_t *in, + const struct TALER_MasterPrivateKeyP *key, + const struct GNUNET_HashCode *salt, + struct TALER_MasterSignatureP *sig) +{ + struct TALER_MasterWireDetailsPS wsd; + const char *bank_uri; + const char *type; + json_int_t account; + json_error_t err; + + if (0 != + json_unpack_ex ((json_t *) in, + &err, + 0 /* flags */, + "{s:s, s:s, s:I}", + "type", &type, + "bank_uri", &bank_uri, + "account_number", &account)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to unpack JSON: %s (at %u)\n", + err.text, + err.position); + return GNUNET_SYSERR; + } + if (0 != strcmp (type, + "test")) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`type' must be `test' for test wire details\n"); + return GNUNET_SYSERR; + } + compute_purpose (account, + bank_uri, + &wsd); + GNUNET_CRYPTO_eddsa_sign (&key->eddsa_priv, + &wsd.purpose, + &sig->eddsa_signature); + return GNUNET_OK; +} + + /** * Execute a wire transfer. * @@ -682,6 +774,7 @@ libtaler_plugin_wire_test_init (void *cls) plugin->cls = tc; plugin->amount_round = &test_amount_round; plugin->get_wire_details = &test_get_wire_details; + plugin->sign_wire_details = &test_sign_wire_details; plugin->wire_validate = &test_wire_validate; plugin->prepare_wire_transfer = &test_prepare_wire_transfer; plugin->prepare_wire_transfer_cancel = &test_prepare_wire_transfer_cancel; -- cgit v1.2.3