From daae3d3ddf1cbee4761a6a2c0066732fb4723fb0 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 2 Apr 2016 20:58:22 +0200 Subject: [PATCH] change taler-exchange-sepa to a more generic taler-exchange-wire tool using the wire plugins (#4237) --- doc/Makefile.am | 1 + doc/taler-exchange-sepa.1 | 41 ----- doc/taler-exchange-wire.1 | 38 +++++ src/exchange-tools/Makefile.am | 10 +- src/exchange-tools/taler-exchange-sepa.c | 189 --------------------- src/exchange-tools/taler-exchange-wire.c | 201 +++++++++++++++++++++++ src/include/taler_signatures.h | 13 +- src/include/taler_wire_plugin.h | 18 ++ src/wire/plugin_wire_sepa.c | 132 ++++++++++++--- src/wire/plugin_wire_template.c | 23 +++ src/wire/plugin_wire_test.c | 93 +++++++++++ 11 files changed, 499 insertions(+), 260 deletions(-) delete mode 100644 doc/taler-exchange-sepa.1 create mode 100644 doc/taler-exchange-wire.1 delete mode 100644 src/exchange-tools/taler-exchange-sepa.c create mode 100644 src/exchange-tools/taler-exchange-wire.c diff --git a/doc/Makefile.am b/doc/Makefile.am index 5a9de87a0..0ccd84746 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -10,6 +10,7 @@ man_MANS = \ taler-exchange-keyup.1 \ taler-exchange-keycheck.1 \ taler-exchange-reservemod.1 \ + taler-exchange-wire.1 \ taler.conf.5 EXTRA_DIST = \ diff --git a/doc/taler-exchange-sepa.1 b/doc/taler-exchange-sepa.1 deleted file mode 100644 index b24828d96..000000000 --- a/doc/taler-exchange-sepa.1 +++ /dev/null @@ -1,41 +0,0 @@ -.TH TALER\-EXCHANGE\-SEPA 1 "Apr 22, 2015" "GNU Taler" - -.SH NAME -taler\-exchange\-sepa \- Create the master-key signed response to /wire/sepa. - -.SH SYNOPSIS -.B taler\-exchange\-sepa -.RI [ options ] -.br - -.SH DESCRIPTION -\fBtaler\-exchange\-sepa\fP is used to create the exchange's reply to a /wire/sepa request. It converts the bank details into the appropriate signed response. This needs to be done using the long-term offline master key. - -.SH OPTIONS -.B -.IP "\-b BIC, \-\-bic=BIC" -Specifies the BIC code to use. -.B -.IP "\-i IBAN, \-\-iban=IBAN" -Specifies the IBAN to use. -.B -.IP "\-n NAME, \-\-name=NAME" -Specifies the name of the account holder. -.B -.IP "\-m MASTERKEYFILE, \-\-master=MASTERKEYFILE" -Specifies the name of the file containing the exchange's master key. -.B -.IP "\-o FILENAME, \-\-output=FILENAME" -Where to write the SEPA_RESPONSE_FILE. -.B -.IP "\-h, \-\-help" -Print short help on options. -.B -.IP "\-v, \-\-version" -Print version information. - -.SH BUGS -Report bugs by using Mantis or by sending electronic mail to - -.SH "SEE ALSO" -\fBtaler\-exchange\-httpd\fP(1), \fBtaler.conf\fP(5) diff --git a/doc/taler-exchange-wire.1 b/doc/taler-exchange-wire.1 new file mode 100644 index 000000000..546d8eb74 --- /dev/null +++ b/doc/taler-exchange-wire.1 @@ -0,0 +1,38 @@ +.TH TALER\-EXCHANGE\-WIRE 1 "Apr 2, 2016" "GNU Taler" + +.SH NAME +taler\-exchange\-wire \- Create the master-key signed responses to /wire. + +.SH SYNOPSIS +.B taler\-exchange\-wire +.RI [ options ] +.br + +.SH DESCRIPTION +\fBtaler\-exchange\-wire\fP is used to create the exchange's reply to a /wire request. It converts the bank details into the appropriate signed response. This needs to be done using the long-term offline master key. + +.SH OPTIONS +.B +.IP "\-j JSON, \-\-json=JSON" +Gives JSON with all of the relevant account details in a method-specific format. +.B +.IP "\-t METHOD, \-\-type=METHOD" +Specifies the wire transfer method to use. Common are 'test' and 'sepa'. +.B +.IP "\-m MASTERKEYFILE, \-\-master=MASTERKEYFILE" +Specifies the name of the file containing the exchange's master key. +.B +.IP "\-o FILENAME, \-\-output=FILENAME" +Where to write the SEPA_RESPONSE_FILE. +.B +.IP "\-h, \-\-help" +Print short help on options. +.B +.IP "\-v, \-\-version" +Print version information. + +.SH BUGS +Report bugs by using Mantis or by sending electronic mail to + +.SH "SEE ALSO" +\fBtaler\-exchange\-httpd\fP(1), \fBtaler.conf\fP(5) diff --git a/src/exchange-tools/Makefile.am b/src/exchange-tools/Makefile.am index fda9cefa3..feb3c314f 100644 --- a/src/exchange-tools/Makefile.am +++ b/src/exchange-tools/Makefile.am @@ -11,7 +11,7 @@ bin_PROGRAMS = \ taler-exchange-keyup \ taler-exchange-keycheck \ taler-exchange-reservemod \ - taler-exchange-sepa \ + taler-exchange-wire \ taler-exchange-dbinit taler_exchange_keyup_SOURCES = \ @@ -33,15 +33,15 @@ taler_auditor_sign_LDADD = \ -lgnunetutil $(XLIB) -taler_exchange_sepa_SOURCES = \ - taler-exchange-sepa.c -taler_exchange_sepa_LDADD = \ +taler_exchange_wire_SOURCES = \ + taler-exchange-wire.c +taler_exchange_wire_LDADD = \ $(LIBGCRYPT_LIBS) \ $(top_builddir)/src/util/libtalerutil.la \ -lgnunetjson \ -lgnunetutil \ -ljansson $(XLIB) -taler_exchange_sepa_LDFLAGS = $(POSTGRESQL_LDFLAGS) +taler_exchange_wire_LDFLAGS = $(POSTGRESQL_LDFLAGS) taler_exchange_keycheck_SOURCES = \ taler-exchange-keycheck.c diff --git a/src/exchange-tools/taler-exchange-sepa.c b/src/exchange-tools/taler-exchange-sepa.c deleted file mode 100644 index 1bfb49132..000000000 --- a/src/exchange-tools/taler-exchange-sepa.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2015 GNUnet e.V. - - 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 - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see -*/ -/** - * @file taler-exchange-sepa.c - * @brief Create signed response for /wire/sepa requests. - * @author Christian Grothoff - */ -#include -#include -#include -#include "taler_crypto_lib.h" -#include "taler_signatures.h" - - -/** - * Filename of the master private key. - */ -static char *masterkeyfile; - -/** - * Account holder name. - */ -static char *sepa_name; - -/** - * Account holder address. - */ -static char *sepa_address; - -/** - * IBAN number. - */ -static char *iban; - -/** - * BIC number. - */ -static char *bic; - -/** - * Where to write the result. - */ -static char *output_filename; - - -/** - * The main function of the taler-exchange-sepa tool. This tool is used - * to sign the SEPA bank account details using the master key. - * - * @param argc number of arguments from the command line - * @param argv command line arguments - * @return 0 ok, 1 on error - */ -int -main (int argc, - char *const *argv) -{ - static const struct GNUNET_GETOPT_CommandLineOption options[] = { - {'a', "address", "ADDRESS", - "account holder address", 1, - &GNUNET_GETOPT_set_string, &sepa_address}, - {'b', "bic", "BICCODE", - "bank BIC code", 1, - &GNUNET_GETOPT_set_string, &bic}, - {'i', "iban", "IBAN", - "IBAN number of the account", 1, - &GNUNET_GETOPT_set_string, &iban}, - {'m', "master-key", "FILE", - "master key file (private key)", 1, - &GNUNET_GETOPT_set_filename, &masterkeyfile}, - {'n', "name", "NAME", - "name of the account holder", 1, - &GNUNET_GETOPT_set_string, &sepa_name}, - {'o', "output", "FILE", - "where to write the result", 1, - &GNUNET_GETOPT_set_filename, &output_filename}, - TALER_GETOPT_OPTION_HELP ("Setup /wire/sepa response"), - GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION), - GNUNET_GETOPT_OPTION_END - }; - struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv; - struct TALER_MasterWireSepaDetailsPS wsd; - struct TALER_MasterSignatureP sig; - struct GNUNET_HashContext *hc; - json_t *reply; - char *json_str; - struct GNUNET_HashCode salt; - - GNUNET_assert (GNUNET_OK == - GNUNET_log_setup ("taler-exchange-sepa", - "WARNING", - NULL)); - - if (GNUNET_GETOPT_run ("taler-exchange-sepa", - options, - argc, argv) < 0) - return 1; - if (NULL == masterkeyfile) - { - fprintf (stderr, - "Master key file not given\n"); - return 1; - } - eddsa_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (masterkeyfile); - if (NULL == eddsa_priv) - { - fprintf (stderr, - "Failed to initialize master key from file `%s'\n", - masterkeyfile); - return 1; - } - if ( (NULL == sepa_address) || - (NULL == iban) || - (NULL == sepa_name) || - (NULL == bic) ) - { - fprintf (stderr, - "Required arguments missing\n"); - return 1; - } - - /* Compute message to sign */ - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, - &salt, - sizeof (salt)); - hc = GNUNET_CRYPTO_hash_context_start (); - 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); - wsd.purpose.size = htonl (sizeof (wsd)); - wsd.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SEPA_DETAILS); - GNUNET_CRYPTO_hash_context_finish (hc, - &wsd.h_sepa_details); - GNUNET_CRYPTO_eddsa_sign (eddsa_priv, - &wsd.purpose, - &sig.eddsa_signature); - GNUNET_free (eddsa_priv); - - /* build JSON message */ - reply = json_pack ("{s:s, s:s, s:s, s:s, s:s, s:o, s:o}", - "type", "sepa", - "address", sepa_address, - "receiver_name", sepa_name, - "iban", iban, - "bic", bic, - "salt", GNUNET_JSON_from_data (&salt, - sizeof (salt)), - "sig", GNUNET_JSON_from_data (&sig, - sizeof (sig))); - GNUNET_assert (NULL != reply); - - /* dump result to stdout */ - json_str = json_dumps (reply, JSON_INDENT(2)); - GNUNET_assert (NULL != json_str); - - if (NULL != output_filename) - { - fclose (stdout); - stdout = fopen (output_filename, - "w+"); - } - fprintf (stdout, - "%s", - json_str); - fflush (stdout); - free (json_str); - return 0; -} - -/* end of taler-exchange-sepa.c */ diff --git a/src/exchange-tools/taler-exchange-wire.c b/src/exchange-tools/taler-exchange-wire.c new file mode 100644 index 000000000..3bea78f67 --- /dev/null +++ b/src/exchange-tools/taler-exchange-wire.c @@ -0,0 +1,201 @@ +/* + This file is part of TALER + Copyright (C) 2015, 2016 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 + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see +*/ +/** + * @file taler-exchange-wire.c + * @brief Create signed response for /wire requests. + * @author Christian Grothoff + */ +#include +#include +#include +#include "taler_crypto_lib.h" +#include "taler_wire_plugin.h" +#include "taler_signatures.h" + + +/** + * Filename of the master private key. + */ +static char *masterkeyfile; + +/** + * Account holder information in JSON format. + */ +static char *json_in; + +/** + * Which wire method is this for? + */ +static char *method; + +/** + * Where to write the result. + */ +static char *output_filename; + + +/** + * The main function of the taler-exchange-sepa tool. This tool is used + * to sign the SEPA bank account details using the master key. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, + char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'j', "json", "JSON", + "account information in JSON format", 1, + &GNUNET_GETOPT_set_string, &json_in}, + {'m', "master-key", "FILE", + "master key file (private key)", 1, + &GNUNET_GETOPT_set_filename, &masterkeyfile}, + {'t', "type", "METHOD", + "which wire transfer method (i.e. 'test' or 'sepa') is this for?", 1, + &GNUNET_GETOPT_set_filename, &method}, + {'o', "output", "FILE", + "where to write the result", 1, + &GNUNET_GETOPT_set_filename, &output_filename}, + TALER_GETOPT_OPTION_HELP ("Setup /wire response"), + GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION), + GNUNET_GETOPT_OPTION_END + }; + struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv; + struct TALER_MasterPrivateKeyP key; + struct TALER_MasterSignatureP sig; + json_t *j; + json_error_t err; + char *json_out; + struct GNUNET_HashCode salt; + char *lib_name; + struct TALER_WIRE_Plugin *plugin; + + GNUNET_assert (GNUNET_OK == + GNUNET_log_setup ("taler-exchange-wire", + "WARNING", + NULL)); + + if (GNUNET_GETOPT_run ("taler-exchange-wire", + options, + argc, argv) < 0) + return 1; + if (NULL == masterkeyfile) + { + fprintf (stderr, + "Master key file not given\n"); + return 1; + } + eddsa_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (masterkeyfile); + if (NULL == eddsa_priv) + { + fprintf (stderr, + "Failed to initialize master key from file `%s'\n", + masterkeyfile); + return 1; + } + if (NULL == json_in) + { + fprintf (stderr, + "Required -j argument missing\n"); + return 1; + } + if (NULL == method) + { + fprintf (stderr, + "Required -t argument missing\n"); + return 1; + } + j = json_loads (json_in, + JSON_REJECT_DUPLICATES, + &err); + if (NULL == j) + { + fprintf (stderr, + "Failed to parse JSON: %s (at offset %u)\n", + err.text, + (unsigned int) err.position); + return 1; + } + key.eddsa_priv = *eddsa_priv; + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, + &salt, + sizeof (salt)); + (void) GNUNET_asprintf (&lib_name, + "libtaler_plugin_wire_%s", + method); + plugin = GNUNET_PLUGIN_load (lib_name, + NULL); + if (NULL == plugin) + { + GNUNET_free (lib_name); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Wire transfer method `%s' not supported\n", + method); + return 1; + } + plugin->library_name = lib_name; + if (GNUNET_OK != + plugin->sign_wire_details (plugin->cls, + j, + &key, + &salt, + &sig)) + { + /* sign function should have logged applicable errors */ + json_decref (j); + GNUNET_PLUGIN_unload (lib_name, + plugin); + GNUNET_free (lib_name); + return 1; + } + GNUNET_PLUGIN_unload (lib_name, + plugin); + GNUNET_free (lib_name); + GNUNET_free (eddsa_priv); + + /* add signature and salt to JSON message */ + json_object_set_new (j, + "salt", + GNUNET_JSON_from_data (&salt, + sizeof (salt))); + json_object_set_new (j, + "sig", + GNUNET_JSON_from_data (&sig, + sizeof (sig))); + + /* dump result to stdout */ + json_out = json_dumps (j, JSON_INDENT(2)); + json_decref (j); + GNUNET_assert (NULL != json_out); + + if (NULL != output_filename) + { + fclose (stdout); + stdout = fopen (output_filename, + "w+"); + } + fprintf (stdout, + "%s", + json_out); + fflush (stdout); + free (json_out); + return 0; +} + +/* end of taler-exchange-wire.c */ diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h index 23bdaa578..587cdcee5 100644 --- a/src/include/taler_signatures.h +++ b/src/include/taler_signatures.h @@ -69,10 +69,16 @@ /** * Signature where the Exchange confirms its SEPA details in - * the /wire/sepa response. + * the /wire response. */ #define TALER_SIGNATURE_MASTER_SEPA_DETAILS 1026 +/** + * Signature where the Exchange confirms its TEST details in + * the /wire response. + */ +#define TALER_SIGNATURE_MASTER_TEST_DETAILS 1027 + /*********************************************/ /* Exchange online signatures (with signing key) */ @@ -762,11 +768,12 @@ struct TALER_RefreshCommitLinkP * @brief Information signed by the exchange's master * key affirming the SEPA details for the exchange. */ -struct TALER_MasterWireSepaDetailsPS +struct TALER_MasterWireDetailsPS { /** - * Purpose is #TALER_SIGNATURE_MASTER_SEPA_DETAILS. + * Purpose is #TALER_SIGNATURE_MASTER_SEPA_DETAILS or + * #TALER_SIGNATURE_MASTER_TEST_DETAILS. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; diff --git a/src/include/taler_wire_plugin.h b/src/include/taler_wire_plugin.h index e166558a7..9b2bc8fde 100644 --- a/src/include/taler_wire_plugin.h +++ b/src/include/taler_wire_plugin.h @@ -113,6 +113,24 @@ struct TALER_WIRE_Plugin const char *account_name); + /** + * 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 + */ + int + (*sign_wire_details)(void *cls, + const json_t *in, + const struct TALER_MasterPrivateKeyP *key, + const struct GNUNET_HashCode *salt, + struct TALER_MasterSignatureP *sig); + + /** * Check if the given wire format JSON object is correctly formatted * 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;