From 0430d6fb031d1713a39a996068387c3ab2c36c2d Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 9 Jan 2015 18:18:59 +0100 Subject: moving structs relevant for signatures into taler_signatures.h, splitting of private keys that are not in messages; moving test_hash_context to GNUnet --- src/Makefile.am | 2 +- src/include/Makefile.am | 1 - src/include/taler_mint_service.h | 45 +- src/include/taler_signatures.h | 143 ++++- src/include/taler_types.h | 120 ---- src/lib/Makefile.am | 34 ++ src/lib/mint_api.c | 1120 +++++++++++++++++++++++++++++++++ src/lib/test_mint_api.c | 211 +++++++ src/mint/Makefile.am | 44 +- src/mint/mint.h | 80 +-- src/mint/mint_api.c | 1121 ---------------------------------- src/mint/mint_common.c | 29 +- src/mint/mint_db.h | 27 +- src/mint/taler-mint-httpd.c | 1 - src/mint/taler-mint-httpd_deposit.c | 1 - src/mint/taler-mint-httpd_keys.c | 41 +- src/mint/taler-mint-httpd_keys.h | 4 +- src/mint/taler-mint-httpd_refresh.c | 10 +- src/mint/taler-mint-httpd_withdraw.c | 13 +- src/mint/taler-mint-keycheck.c | 50 +- src/mint/taler-mint-keyup.c | 65 +- src/mint/test_mint_api.c | 211 ------- src/mint/test_mint_common.c | 10 +- src/util/Makefile.am | 6 - src/util/test_hash_context.c | 48 -- 25 files changed, 1705 insertions(+), 1732 deletions(-) delete mode 100644 src/include/taler_types.h create mode 100644 src/lib/Makefile.am create mode 100644 src/lib/mint_api.c create mode 100644 src/lib/test_mint_api.c delete mode 100644 src/mint/mint_api.c delete mode 100644 src/mint/test_mint_api.c delete mode 100644 src/util/test_hash_context.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 485c4f9d7..ed9c9c2bf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,2 +1,2 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/include -SUBDIRS = include util mint +SUBDIRS = include util mint lib diff --git a/src/include/Makefile.am b/src/include/Makefile.am index c95940ea2..ebdf8561d 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am @@ -7,5 +7,4 @@ talerinclude_HEADERS = \ taler_mint_service.h \ taler_rsa.h \ taler_signatures.h \ - taler_types.h \ taler_util.h diff --git a/src/include/taler_mint_service.h b/src/include/taler_mint_service.h index ee3b30e39..a9d27982f 100644 --- a/src/include/taler_mint_service.h +++ b/src/include/taler_mint_service.h @@ -3,23 +3,21 @@ (C) 2014 Christian Grothoff (and other contributing authors) 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 + terms of the GNU Affero 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. + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - You should have received a copy of the GNU General Public License along with + You should have received a copy of the GNU Affero General Public License along with TALER; see the file COPYING. If not, If not, see */ - /** * @file include/taler_mint_service.h - * @brief C interface to the mint's HTTP API - * @author Sree Harsha Totakura + * @brief C interface of libtalermint, a C library to use mint's HTTP API + * @author Sree Harsha Totakura */ - #ifndef _TALER_MINT_SERVICE_H #define _TALER_MINT_SERVICE_H @@ -166,8 +164,9 @@ struct TALER_MINT_KeysGetHandle; * @param emsg if the asynchronous call could not be completed due to an error, * this parameter contains a human readable error message */ -typedef void (*TALER_MINT_ContinuationCallback) (void *cls, - const char *emsg); +typedef void +(*TALER_MINT_ContinuationCallback) (void *cls, + const char *emsg); /** * Functions of this type are called to provide the retrieved signing and @@ -180,9 +179,10 @@ typedef void (*TALER_MINT_ContinuationCallback) (void *cls, * @param denom_keys NULL-terminated array of pointers to the mint's * denomination keys; will be NULL if no signing keys are retrieved. */ -typedef void (*TALER_MINT_KeysGetCallback) (void *cls, - struct TALER_MINT_SigningPublicKey **sign_keys, - struct TALER_MINT_DenomPublicKey **denom_keys); +typedef void +(*TALER_MINT_KeysGetCallback) (void *cls, + struct TALER_MINT_SigningPublicKey **sign_keys, + struct TALER_MINT_DenomPublicKey **denom_keys); /** @@ -190,15 +190,18 @@ typedef void (*TALER_MINT_KeysGetCallback) (void *cls, * * @param mint handle to the mint * @param cb the callback to call with the keys - * @param cls closure for the above callback + * @param cb_cls closure for the @a cb callback * @param cont_cb the callback to call after completing this asynchronous call - * @param cont_cls the closure for the continuation callback + * @param cont_cls the closure for the @a cont_cb callback * @return a handle to this asynchronous call; NULL upon eror */ struct TALER_MINT_KeysGetHandle * TALER_MINT_keys_get (struct TALER_MINT_Handle *mint, - TALER_MINT_KeysGetCallback cb, void *cls, - TALER_MINT_ContinuationCallback cont_cb, void *cont_cls); + TALER_MINT_KeysGetCallback cb, + void *cb_cls, + TALER_MINT_ContinuationCallback cont_cb, + void *cont_cls); + /** * Cancel the asynchronous call initiated by TALER_MINT_keys_get(). This should @@ -229,10 +232,12 @@ struct TALER_MINT_DepositHandle; * @param emsg in case of unsuccessful deposit, this contains a human readable * explanation. */ -typedef void (*TALER_MINT_DepositResultCallback) (void *cls, - int status, - json_t *obj, - char *emsg); +typedef void +(*TALER_MINT_DepositResultCallback) (void *cls, + int status, + json_t *obj, + char *emsg); + /** * Submit a deposit permission to the mint and get the mint's response diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h index 8c142f61f..238a915c1 100644 --- a/src/include/taler_signatures.h +++ b/src/include/taler_signatures.h @@ -13,18 +13,25 @@ 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-mint-keyup.c - * @brief Update the mint's keys for coins and signatures, - * using the mint's offline master key. + * @file taler_signatures.h + * @brief message formats and signature constants used to define + * the binary formats of signatures in Taler * @author Florian Dold * @author Benedikt Mueller + * + * This file should define the constants and C structs that one + * needs to know to implement Taler clients (wallets or merchants) + * that need to produce or verify Taler signatures. */ #ifndef TALER_SIGNATURES_H #define TALER_SIGNATURES_H +#include +#include "taler_rsa.h" + + /** * Purpose for signing public keys signed * by the mint master key. @@ -102,5 +109,133 @@ */ #define TALER_SIGNATURE_INCREMENTAL_DEPOSIT 202 + + +GNUNET_NETWORK_STRUCT_BEGIN + + +/** + * Request to withdraw coins from a reserve. + */ +struct TALER_WithdrawRequest +{ + /** + * Signature over the rest of the message + * by the withdraw public key. + */ + struct GNUNET_CRYPTO_EddsaSignature sig; + + /** + * Purpose must be #TALER_SIGNATURE_WITHDRAW. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Reserve public key. + */ + struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub; + + /** + * Denomination public key for the coin that is withdrawn. + * FIXME: change to the hash of the public key (so this + * is fixed-size). + */ + struct TALER_RSA_PublicKeyBinaryEncoded denomination_pub; + + /** + * Purpose containing coin's blinded public key. + * + * FIXME: this should be explicitly a variable-size field with the + * (blinded) message to be signed by the Mint. + */ + struct TALER_RSA_BlindedSignaturePurpose coin_envelope; +}; + + + +/** + * FIXME + */ +struct TALER_MINT_SignKeyIssue +{ + struct GNUNET_CRYPTO_EddsaSignature signature; + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_CRYPTO_EddsaPublicKey master_pub; + struct GNUNET_TIME_AbsoluteNBO start; + struct GNUNET_TIME_AbsoluteNBO expire; + struct GNUNET_CRYPTO_EddsaPublicKey signkey_pub; +}; + + +/** + * FIXME + */ +struct TALER_MINT_DenomKeyIssue +{ + struct GNUNET_CRYPTO_EddsaSignature signature; + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_CRYPTO_EddsaPublicKey master; + struct GNUNET_TIME_AbsoluteNBO start; + struct GNUNET_TIME_AbsoluteNBO expire_withdraw; + struct GNUNET_TIME_AbsoluteNBO expire_spend; + struct TALER_RSA_PublicKeyBinaryEncoded denom_pub; + struct TALER_AmountNBO value; + struct TALER_AmountNBO fee_withdraw; + struct TALER_AmountNBO fee_deposit; + struct TALER_AmountNBO fee_refresh; +}; + + +/** + * FIXME + */ +struct RefreshMeltSignatureBody +{ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_HashCode melt_hash; +}; + +/** + * FIXME + */ +struct RefreshCommitSignatureBody +{ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_HashCode commit_hash; +}; + + +/** + * FIXME + */ +struct RefreshCommitResponseSignatureBody +{ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + uint16_t noreveal_index; +}; + + +/** + * FIXME + */ +struct RefreshMeltResponseSignatureBody +{ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_HashCode melt_response_hash; +}; + + +/** + * FIXME + */ +struct RefreshMeltConfirmSignRequestBody +{ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_CRYPTO_EddsaPublicKey session_pub; +}; + + +GNUNET_NETWORK_STRUCT_END + #endif diff --git a/src/include/taler_types.h b/src/include/taler_types.h deleted file mode 100644 index c6c2c0209..000000000 --- a/src/include/taler_types.h +++ /dev/null @@ -1,120 +0,0 @@ -/** - * @file include/types.h - * @brief This files defines the various data and message types in TALER. - * @author Sree Harsha Totakura - * @author Florian Dold - */ - -#ifndef TYPES_H_ -#define TYPES_H_ - -#include "taler_rsa.h" - - -/** - * Public information about a coin. - */ -struct TALER_CoinPublicInfo -{ - /** - * The coin's public key. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub; - - /* - * The public key signifying the coin's denomination. - */ - struct TALER_RSA_PublicKeyBinaryEncoded denom_pub; - - /** - * Signature over coin_pub by denom_pub. - */ - struct TALER_RSA_Signature denom_sig; -}; - - -/** - * Request to withdraw coins from a reserve. - */ -struct TALER_WithdrawRequest -{ - /** - * Signature over the rest of the message - * by the withdraw public key. - */ - struct GNUNET_CRYPTO_EddsaSignature sig; - - /** - * Purpose must be TALER_SIGNATURE_WITHDRAW. - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - - /** - * Reserve public key. - */ - struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub; - - /** - * Denomination public key for the coin that is withdrawn. - */ - struct TALER_RSA_PublicKeyBinaryEncoded denomination_pub; - - /** - * Purpose containing coin's blinded public key. - */ - struct TALER_RSA_BlindedSignaturePurpose coin_envelope; -}; - - - -/** - * Data type for messages - */ -struct TALER_MessageHeader -{ - /** - * The type of the message in Network-byte order (NBO) - */ - uint16_t type; - - /** - * The size of the message in NBO - */ - uint16_t size; -}; - -/*****************/ -/* Message types */ -/*****************/ - -/** - * The message type of a blind signature - */ -#define TALER_MSG_TYPE_BLINDED_SIGNATURE 1 - -/** - * The message type of a blinded message - */ -#define TALER_MSG_TYPE_BLINDED_MESSAGE 2 - -/** - * The message type of an unblinded signature - * @FIXME: Not currently used - */ -#define TALER_MSG_TYPE_UNBLINDED_SIGNATURE 3 - -/** - * The type of a blinding residue message - * @FIXME: Not currently used - */ -#define TALER_MSG_TYPE_BLINDING_RESIDUE 4 - -/** - * The type of a message containing the blinding factor - */ -#define TALER_MSG_TYPE_BLINDING_FACTOR 5 - - -#endif /* TYPES_H_ */ - -/* end of include/types.h */ diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am new file mode 100644 index 000000000..5c740fe29 --- /dev/null +++ b/src/lib/Makefile.am @@ -0,0 +1,34 @@ +AM_CPPFLAGS = -I$(top_srcdir)/src/include $(POSTGRESQL_CPPFLAGS) + +lib_LTLIBRARIES = \ + libtalermint.la + +libtalermint_la_LDFLAGS = \ + $(POSTGRESQL_LDFLAGS) \ + -version-info 0:0:0 \ + -no-undefined + +libtalermint_la_SOURCES = \ + mint_api.c + +libtalermint_la_LIBADD = \ + -lgnunetutil \ + -ljansson \ + -lcurl + +libtalermint_la_LDFLAGS = \ + -version-info 0:0:0 \ + -no-undefined + +check_PROGRAMS = \ + test_mint_api + +test_mint_api_SOURCES = \ + test_mint_api.c +test_mint_api_LDADD = \ + libtalermint.la \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/util/libtalerutil.la \ + -lgnunetutil \ + -ljansson + diff --git a/src/lib/mint_api.c b/src/lib/mint_api.c new file mode 100644 index 000000000..10f4e48b4 --- /dev/null +++ b/src/lib/mint_api.c @@ -0,0 +1,1120 @@ +/* + This file is part of TALER + (C) 2014 Christian Grothoff (and other contributing authors) + + 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 mint/mint_api.c + * @brief Implementation of the client interface to mint's HTTP API + * @author Sree Harsha Totakura + */ +#include "platform.h" +#include +#include +#include +#include "taler_mint_service.h" +#include "taler_signatures.h" + + +#define CURL_STRERROR(TYPE, FUNCTION, CODE) \ + GNUNET_log (TYPE, "cURL function `%s' has failed at `%s:%d' with error: %s", \ + FUNCTION, __FILE__, __LINE__, curl_easy_strerror (CODE)); + + + +/** + * Print JSON parsing related error information + */ +#define JSON_WARN(error) \ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \ + "JSON parsing failed at %s:%u: %s (%s)", \ + __FILE__, __LINE__, error.text, error.source) + +/** + * Failsafe flag + */ +static int fail; + +/** + * Context + */ +struct TALER_MINT_Context +{ + /** + * CURL multi handle + */ + CURLM *multi; + + /** + * CURL share handle + */ + CURLSH *share; + + /** + * Perform task handle + */ + struct GNUNET_SCHEDULER_Task *perform_task; +}; + +/** + * Type of requests we currently have + */ +enum RequestType +{ + /** + * No request + */ + REQUEST_TYPE_NONE, + + /** + * Current request is to receive mint's keys + */ + REQUEST_TYPE_KEYSGET, + + /** + * Current request is to submit a deposit permission and get its status + */ + REQUEST_TYPE_DEPOSIT +}; + + +/** + * Handle to the mint + */ +struct TALER_MINT_Handle +{ + /** + * The context of this handle + */ + struct TALER_MINT_Context *ctx; + + /** + * The hostname of the mint + */ + char *hostname; + + /** + * The CURL handle + */ + CURL *curl; + + /** + * Error buffer for CURL + */ + char emsg[CURL_ERROR_SIZE]; + + /** + * Download buffer + */ + void *buf; + + /** + * The currently active request + */ + union { + /** + * Used to denote no request if set to NULL + */ + void *none; + + /** + * Denom keys get request if REQUEST_TYPE_KEYSGET + */ + struct TALER_MINT_KeysGetHandle *keys_get; + + /** + * Deposit request if REQUEST_TYPE_DEPOSIT + */ + struct TALER_MINT_DepositHandle *deposit; + } req; + + /** + * The size of the download buffer + */ + size_t buf_size; + + /** + * Active request type + */ + enum RequestType req_type; + + /** + * The service port of the mint + */ + uint16_t port; + + /** + * Are we connected to the mint? + */ + uint8_t connected; + +}; + + +/** + * A handle to get the keys of a mint + */ +struct TALER_MINT_KeysGetHandle +{ + /** + * The connection to mint this request handle will use + */ + struct TALER_MINT_Handle *mint; + + /** + * The url for this handle + */ + char *url; + + TALER_MINT_KeysGetCallback cb; + void *cls; + + TALER_MINT_ContinuationCallback cont_cb; + void *cont_cls; +}; + + +/** + * A handle to submit a deposit permission and get its status + */ +struct TALER_MINT_DepositHandle +{ + /** + *The connection to mint this request handle will use + */ + struct TALER_MINT_Handle *mint; + + /** + * The url for this handle + */ + char *url; + + TALER_MINT_DepositResultCallback cb; + void *cls; + + char *json_enc; + + struct curl_slist *headers; + +}; + + +/** + * Parses the timestamp encoded as ASCII string as UNIX timstamp. + * + * @param abs successfully parsed timestamp will be returned thru this parameter + * @param tstamp_enc the ASCII encoding of the timestamp + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ +static int +parse_timestamp (struct GNUNET_TIME_Absolute *abs, const char *tstamp_enc) +{ + unsigned long tstamp; + + if (1 != sscanf (tstamp_enc, "%lu", &tstamp)) + return GNUNET_SYSERR; + *abs = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get_zero_ (), + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, tstamp)); + return GNUNET_OK; +} + + +#define EXITIF(cond) \ + do { \ + if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ + } while (0) + + + +static int +parse_json_signkey (struct TALER_MINT_SigningPublicKey **_sign_key, + json_t *sign_key_obj, + struct GNUNET_CRYPTO_EddsaPublicKey *master_key) +{ + json_t *valid_from_obj; + json_t *valid_until_obj; + json_t *key_obj; + json_t *sig_obj; + const char *valid_from_enc; + const char *valid_until_enc; + const char *key_enc; + const char *sig_enc; + struct TALER_MINT_SigningPublicKey *sign_key; + struct TALER_MINT_SignKeyIssue sign_key_issue; + struct GNUNET_CRYPTO_EddsaSignature sig; + struct GNUNET_TIME_Absolute valid_from; + struct GNUNET_TIME_Absolute valid_until; + + EXITIF (JSON_OBJECT != json_typeof (sign_key_obj)); + EXITIF (NULL == (valid_from_obj = json_object_get (sign_key_obj, + "stamp_start"))); + EXITIF (NULL == (valid_until_obj = json_object_get (sign_key_obj, + "stamp_expire"))); + EXITIF (NULL == (key_obj = json_object_get (sign_key_obj, "key"))); + EXITIF (NULL == (sig_obj = json_object_get (sign_key_obj, "master_sig"))); + EXITIF (NULL == (valid_from_enc = json_string_value (valid_from_obj))); + EXITIF (NULL == (valid_until_enc = json_string_value (valid_until_obj))); + EXITIF (NULL == (key_enc = json_string_value (key_obj))); + EXITIF (NULL == (sig_enc = json_string_value (sig_obj))); + EXITIF (GNUNET_SYSERR == parse_timestamp (&valid_from, + valid_from_enc)); + EXITIF (GNUNET_SYSERR == parse_timestamp (&valid_until, + valid_until_enc)); + EXITIF (52 != strlen (key_enc)); /* strlen(base32(char[32])) = 52 */ + EXITIF (103 != strlen (sig_enc)); /* strlen(base32(char[64])) = 103 */ + EXITIF (GNUNET_OK != GNUNET_STRINGS_string_to_data (sig_enc, 103, + &sig, sizeof (sig))); + (void) memset (&sign_key_issue, 0, sizeof (sign_key_issue)); + EXITIF (GNUNET_SYSERR == + GNUNET_CRYPTO_eddsa_public_key_from_string (key_enc, + 52, + &sign_key_issue.signkey_pub)); + sign_key_issue.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNKEY); + sign_key_issue.purpose.size = + htonl (sizeof (sign_key_issue) + - offsetof (struct TALER_MINT_SignKeyIssue, purpose)); + sign_key_issue.master_pub = *master_key; + sign_key_issue.start = GNUNET_TIME_absolute_hton (valid_from); + sign_key_issue.expire = GNUNET_TIME_absolute_hton (valid_until); + EXITIF (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNKEY, + &sign_key_issue.purpose, + &sig, + master_key)); + sign_key = GNUNET_new (struct TALER_MINT_SigningPublicKey); + sign_key->valid_from = valid_from; + sign_key->valid_until = valid_until; + sign_key->key = sign_key_issue.signkey_pub; + *_sign_key = sign_key; + return GNUNET_OK; + + EXITIF_exit: + return GNUNET_SYSERR; +} + + +static int +parse_json_amount (json_t *amount_obj, struct TALER_Amount *amt) +{ + json_t *obj; + const char *currency_str; + int value; + int fraction; + + EXITIF (NULL == (obj = json_object_get (amount_obj, "currency"))); + EXITIF (NULL == (currency_str = json_string_value (obj))); + EXITIF (NULL == (obj = json_object_get (amount_obj, "value"))); + EXITIF (JSON_INTEGER != json_typeof (obj)); + EXITIF (0 > (value = json_integer_value (obj))); + EXITIF (NULL == (obj = json_object_get (amount_obj, "fraction"))); + EXITIF (JSON_INTEGER != json_typeof (obj)); + EXITIF (0 > (fraction = json_integer_value (obj))); + (void) memset (amt->currency, 0, sizeof (amt->currency)); + (void) strncpy (amt->currency, currency_str, sizeof (amt->currency) - 1); + amt->value = (uint32_t) value; + amt->fraction = (uint32_t) fraction; + return GNUNET_OK; + + EXITIF_exit: + return GNUNET_SYSERR; +} + +static int +parse_json_denomkey (struct TALER_MINT_DenomPublicKey **_denom_key, + json_t *denom_key_obj, + struct GNUNET_CRYPTO_EddsaPublicKey *master_key) +{ + json_t *obj; + const char *sig_enc; + const char *deposit_valid_until_enc; + const char *withdraw_valid_until_enc; + const char *valid_from_enc; + const char *key_enc; + struct TALER_MINT_DenomPublicKey *denom_key; + struct GNUNET_TIME_Absolute valid_from; + struct GNUNET_TIME_Absolute withdraw_valid_until; + struct GNUNET_TIME_Absolute deposit_valid_until; + struct TALER_Amount value; + struct TALER_Amount fee_withdraw; + struct TALER_Amount fee_deposit; + struct TALER_Amount fee_refresh; + struct TALER_MINT_DenomKeyIssue denom_key_issue; + struct GNUNET_CRYPTO_EddsaSignature sig; + + EXITIF (JSON_OBJECT != json_typeof (denom_key_obj)); + EXITIF (NULL == (obj = json_object_get (denom_key_obj, "master_sig"))); + EXITIF (NULL == (sig_enc = json_string_value (obj))); + EXITIF (103 != strlen (sig_enc)); + EXITIF (GNUNET_OK != GNUNET_STRINGS_string_to_data (sig_enc, 103, + &sig, sizeof (sig))); + EXITIF (NULL == (obj = json_object_get (denom_key_obj, "stamp_expire_deposit"))); + EXITIF (NULL == (deposit_valid_until_enc = json_string_value (obj))); + EXITIF (NULL == (obj = json_object_get (denom_key_obj, "stamp_expire_withdraw"))); + EXITIF (NULL == (withdraw_valid_until_enc = json_string_value (obj))); + EXITIF (NULL == (obj = json_object_get (denom_key_obj, "stamp_start"))); + EXITIF (NULL == (valid_from_enc = json_string_value (obj))); + EXITIF (NULL == (obj = json_object_get (denom_key_obj, "denom_pub"))); + EXITIF (NULL == (key_enc = json_string_value (obj))); + EXITIF (52 != strlen (key_enc)); /* strlen(base32(char[32])) = 52 */ + EXITIF (GNUNET_SYSERR == parse_timestamp (&valid_from, valid_from_enc)); + EXITIF (GNUNET_SYSERR == parse_timestamp (&withdraw_valid_until, + withdraw_valid_until_enc)); + EXITIF (GNUNET_SYSERR == parse_timestamp (&deposit_valid_until, + deposit_valid_until_enc)); + + (void) memset (&denom_key_issue, 0, sizeof (denom_key_issue)); + EXITIF (GNUNET_OK != GNUNET_STRINGS_string_to_data (key_enc, 52, + &denom_key_issue.denom_pub, + sizeof (struct TALER_RSA_PublicKeyBinaryEncoded))); + EXITIF (NULL == (obj = json_object_get (denom_key_obj, "value"))); + EXITIF (GNUNET_SYSERR == parse_json_amount (obj, &value)); + EXITIF (NULL == (obj = json_object_get (denom_key_obj, "fee_withdraw"))); + EXITIF (GNUNET_SYSERR == parse_json_amount (obj, &fee_withdraw)); + EXITIF (NULL == (obj = json_object_get (denom_key_obj, "fee_deposit"))); + EXITIF (GNUNET_SYSERR == parse_json_amount (obj, &fee_deposit)); + EXITIF (NULL == (obj = json_object_get (denom_key_obj, "fee_refresh"))); + EXITIF (GNUNET_SYSERR == parse_json_amount (obj, &fee_refresh)); + denom_key_issue.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOM); + denom_key_issue.purpose.size = htonl + (sizeof (struct TALER_MINT_DenomKeyIssue) - + offsetof (struct TALER_MINT_DenomKeyIssue, purpose)); + 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_spend = GNUNET_TIME_absolute_hton (deposit_valid_until); + denom_key_issue.value = TALER_amount_hton (value); + denom_key_issue.fee_withdraw = TALER_amount_hton (fee_withdraw); + denom_key_issue.fee_deposit = TALER_amount_hton (fee_deposit); + denom_key_issue.fee_refresh = TALER_amount_hton (fee_refresh); + EXITIF (GNUNET_SYSERR == + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOM, + &denom_key_issue.purpose, + &sig, + master_key)); + denom_key = GNUNET_new (struct TALER_MINT_DenomPublicKey); + denom_key->key = denom_key_issue.denom_pub; + denom_key->valid_from = valid_from; + denom_key->withdraw_valid_until = withdraw_valid_until; + denom_key->deposit_valid_until = deposit_valid_until; + denom_key->value = value; + denom_key->fee_withdraw = fee_withdraw; + denom_key->fee_deposit = fee_deposit; + denom_key->fee_refresh = fee_refresh; + *_denom_key = denom_key; + return GNUNET_OK; + + EXITIF_exit: + return GNUNET_SYSERR; +} + +static int +parse_response_keys_get (const char *in, size_t size, + struct TALER_MINT_SigningPublicKey ***_sign_keys, + unsigned int *_n_sign_keys, + struct TALER_MINT_DenomPublicKey ***_denom_keys, + unsigned int *_n_denom_keys) +{ + json_t *resp_obj; + struct TALER_MINT_DenomPublicKey **denom_keys; + struct GNUNET_CRYPTO_EddsaPublicKey master_key; + struct GNUNET_TIME_Absolute list_issue_date; + struct TALER_MINT_SigningPublicKey **sign_keys; + unsigned int n_denom_keys; + unsigned int n_sign_keys; + json_error_t error; + unsigned int index; + int OK; + + denom_keys = NULL; + n_denom_keys = 0; + sign_keys = NULL; + n_sign_keys = 0; + OK = 0; + resp_obj = json_loadb (in, size, + JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK, + &error); + if (NULL == resp_obj) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse received data as JSON object\n"); + return GNUNET_SYSERR; + } + + EXITIF (JSON_OBJECT != json_typeof (resp_obj)); + { + /* parse the master public key */ + json_t *master_key_obj; + const char *master_key_enc; + + EXITIF (NULL == (master_key_obj = json_object_get (resp_obj, "master_pub"))); + EXITIF (NULL == (master_key_enc = json_string_value (master_key_obj))); + EXITIF (52 != strlen (master_key_enc)); /* strlen(base32(char[32])) = 52 */ + EXITIF (GNUNET_OK != + GNUNET_CRYPTO_eddsa_public_key_from_string (master_key_enc, + 52, + &master_key)); + } + { + /* parse the issue date of the response */ + json_t *list_issue_date_obj; + const char *tstamp_enc; + + EXITIF (NULL == (list_issue_date_obj = + json_object_get(resp_obj, "list_issue_date"))); + EXITIF (NULL == (tstamp_enc = json_string_value (list_issue_date_obj))); + EXITIF (GNUNET_SYSERR == parse_timestamp (&list_issue_date, tstamp_enc)); + } + { + /* parse the signing keys */ + json_t *sign_keys_array; + json_t *sign_key_obj; + + EXITIF (NULL == (sign_keys_array = + json_object_get (resp_obj, "signkeys"))); + EXITIF (JSON_ARRAY != json_typeof (sign_keys_array)); + EXITIF (0 == (n_sign_keys = json_array_size (sign_keys_array))); + sign_keys = GNUNET_malloc (sizeof (struct TALER_MINT_SigningPublicKey *) + * (n_sign_keys + 1)); + index = 0; + json_array_foreach (sign_keys_array, index, sign_key_obj) { + EXITIF (GNUNET_SYSERR == parse_json_signkey (&sign_keys[index], + sign_key_obj, + &master_key)); + } + } + { + /* parse the denomination keys */ + json_t *denom_keys_array; + json_t *denom_key_obj; + + EXITIF (NULL == (denom_keys_array = json_object_get (resp_obj, "denoms"))); + EXITIF (JSON_ARRAY != json_typeof (denom_keys_array)); + EXITIF (0 == (n_denom_keys = json_array_size (denom_keys_array))); + denom_keys = GNUNET_malloc (sizeof (struct TALER_MINT_DenomPublicKey *) + * (n_denom_keys + 1)); + index = 0; + json_array_foreach (denom_keys_array, index, denom_key_obj) { + EXITIF (GNUNET_SYSERR == parse_json_denomkey (&denom_keys[index], + denom_key_obj, + &master_key)); + } + } + OK = 1; + + EXITIF_exit: + json_decref (resp_obj); + if (!OK) + { + if (NULL != sign_keys) + { + for (index=0; NULL != sign_keys[index]; index++) + GNUNET_free_non_null (sign_keys[index]); + GNUNET_free (sign_keys); + } + if (NULL != denom_keys) + { + for (index=0; NULL != denom_keys[index]; index++) + GNUNET_free_non_null (denom_keys[index]); + GNUNET_free (denom_keys); + } + return GNUNET_SYSERR; + } + + *_sign_keys = sign_keys; + *_n_sign_keys = n_sign_keys; + *_denom_keys = denom_keys; + *_n_denom_keys = n_denom_keys; + return GNUNET_OK; +} + + +int +parse_deposit_response (void *buf, size_t size, int *r_status, json_t **r_obj) +{ + json_t *obj; + const char *status_str; + json_error_t error; + + status_str = NULL; + obj = NULL; + obj = json_loadb (buf, size, + JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK, &error); + if (NULL == obj) + { + JSON_WARN (error); + return GNUNET_SYSERR; + } + EXITIF (-1 == json_unpack (obj, "{s:s}", "status", &status_str)); + LOG_DEBUG ("Received deposit response: %s from mint\n", status_str); + if (0 == strcmp ("DEPOSIT_OK", status_str)) + *r_status = 1; + else if (0 == strcmp ("DEPOSIT_QUEUED", status_str)) + *r_status = 2; + else + *r_status = 0; + *r_obj = obj; + + return GNUNET_OK; + EXITIF_exit: + json_decref (obj); + return GNUNET_SYSERR; +} + +#undef EXITIF + +static void +mint_connect (struct TALER_MINT_Handle *mint) +{ + struct TALER_MINT_Context *ctx = mint->ctx; + + GNUNET_assert (0 == mint->connected); + GNUNET_assert (CURLM_OK == curl_multi_add_handle (ctx->multi, mint->curl)); + mint->connected = GNUNET_YES; +} + +static void +mint_disconnect (struct TALER_MINT_Handle *mint) +{ + struct TALER_MINT_Context *ctx = mint->ctx; + + GNUNET_assert (GNUNET_YES == mint->connected); + GNUNET_break (CURLM_OK == curl_multi_remove_handle (ctx->multi, + mint->curl)); + mint->connected = GNUNET_NO; + GNUNET_free_non_null (mint->buf); + mint->buf = NULL; + mint->buf_size = 0; + mint->req_type = REQUEST_TYPE_NONE; + mint->req.none = NULL; +} + +static void +cleanup_keys_get (struct TALER_MINT_KeysGetHandle *gh) +{ + GNUNET_free (gh->url); + GNUNET_free (gh); +} + +static void +cleanup_deposit (struct TALER_MINT_DepositHandle *dh) +{ + curl_slist_free_all (dh->headers); + GNUNET_free_non_null (dh->json_enc); + GNUNET_free (dh->url); + GNUNET_free (dh); +} + +static void +request_failed (struct TALER_MINT_Handle *mint, long resp_code) +{ + switch (mint->req_type) + { + case REQUEST_TYPE_NONE: + GNUNET_assert (0); + break; + case REQUEST_TYPE_KEYSGET: + { + struct TALER_MINT_KeysGetHandle *gh = mint->req.keys_get; + TALER_MINT_ContinuationCallback cont_cb; + void *cont_cls; + GNUNET_assert (NULL != gh); + cont_cb = gh->cont_cb; + cont_cls = gh->cont_cls; + cleanup_keys_get (gh); + mint_disconnect (mint); + cont_cb (cont_cls, mint->emsg); + } + break; + case REQUEST_TYPE_DEPOSIT: + { + struct TALER_MINT_DepositHandle *dh = mint->req.deposit; + TALER_MINT_DepositResultCallback cb = dh->cb; + void *cls = dh->cls; + GNUNET_assert (NULL != dh); + cleanup_deposit (dh); + mint_disconnect (mint); + cb (cls, 0, NULL, mint->emsg); + } + break; + } +} + +static void +request_succeeded (struct TALER_MINT_Handle *mint, long resp_code) +{ + char *emsg; + + emsg = NULL; + switch (mint->req_type) + { + case REQUEST_TYPE_NONE: + GNUNET_assert (0); + break; + case REQUEST_TYPE_KEYSGET: + { + struct TALER_MINT_KeysGetHandle *gh = mint->req.keys_get; + TALER_MINT_ContinuationCallback cont_cb; + void *cont_cls; + struct TALER_MINT_SigningPublicKey **sign_keys; + struct TALER_MINT_DenomPublicKey **denom_keys; + unsigned int n_sign_keys; + unsigned int n_denom_keys; + + GNUNET_assert (NULL != gh); + cont_cb = gh->cont_cb; + cont_cls = gh->cont_cls; + if (200 == resp_code) + { + /* parse JSON object from the mint->buf which is of size mint->buf_size */ + if (GNUNET_OK == + parse_response_keys_get (mint->buf, mint->buf_size, + &sign_keys, &n_sign_keys, + &denom_keys, &n_denom_keys)) + gh->cb (gh->cls, sign_keys, denom_keys); + else + emsg = GNUNET_strdup ("Error parsing response"); + } + else + GNUNET_asprintf (&emsg, "Failed with response code: %ld", resp_code); + cleanup_keys_get (gh); + mint_disconnect (mint); + cont_cb (cont_cls, emsg); + } + break; + case REQUEST_TYPE_DEPOSIT: + { + struct TALER_MINT_DepositHandle *dh = mint->req.deposit; + TALER_MINT_DepositResultCallback cb; + void *cls; + int status; + json_t *obj; + + GNUNET_assert (NULL != dh); + obj = NULL; + cb = dh->cb; + cls = dh->cls; + status = 0; + if (200 == resp_code) + { + /* parse JSON object from the mint->buf which is of size mint->buf_size */ + if (GNUNET_OK != + parse_deposit_response (mint->buf, mint->buf_size, + &status, &obj)) + emsg = GNUNET_strdup ("Error parsing response"); + } + else + GNUNET_asprintf (&emsg, "Failed with response code: %ld", resp_code); + cleanup_deposit (dh); + mint_disconnect (mint); + cb (cls, status, obj, emsg); + } + break; + } + GNUNET_free_non_null (emsg); +} + + +static void +do_perform (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +static void +perform (struct TALER_MINT_Context *ctx) +{ + fd_set fd_rs; + fd_set fd_ws; + struct GNUNET_NETWORK_FDSet rs; + struct GNUNET_NETWORK_FDSet ws; + CURLMsg *cmsg; + struct TALER_MINT_Handle *mint; + long timeout; + long resp_code; + static unsigned int n_old; + int n_running; + int n_completed; + int max_fd; + + n_completed = 0; + curl_multi_perform (ctx->multi, &n_running); + GNUNET_assert (0 <= n_running); + if ((0 == n_running) || (n_running < n_old)) + { + /* some requests were completed -- handle them */ + while (NULL != (cmsg = curl_multi_info_read (ctx->multi, &n_completed))) + { + GNUNET_break (CURLMSG_DONE == cmsg->msg); /* curl only has CURLMSG_DONE */ + GNUNET_assert (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle, + CURLINFO_PRIVATE, + (char *) &mint)); + GNUNET_assert (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle, + CURLINFO_RESPONSE_CODE, + &resp_code)); + GNUNET_assert (ctx == mint->ctx); /* did we get the correct one? */ + if (CURLE_OK == cmsg->data.result) + request_succeeded (mint, resp_code); + else + request_failed (mint, resp_code); + } + } + n_old = n_running; + /* reschedule perform() */ + if (0 != n_old) + { + FD_ZERO (&fd_rs); + FD_ZERO (&fd_ws); + GNUNET_assert (CURLM_OK == curl_multi_fdset (ctx->multi, + &fd_rs, + &fd_ws, + NULL, + &max_fd)); + if (-1 == max_fd) + { + ctx->perform_task = GNUNET_SCHEDULER_add_delayed + (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &do_perform, ctx); + return; + } + GNUNET_assert (CURLM_OK == curl_multi_timeout (ctx->multi, &timeout)); + if (-1 == timeout) + { + timeout = 1000 * 60 * 5; + } + GNUNET_NETWORK_fdset_zero (&rs); + GNUNET_NETWORK_fdset_zero (&ws); + GNUNET_NETWORK_fdset_copy_native (&rs, &fd_rs, max_fd + 1); + GNUNET_NETWORK_fdset_copy_native (&ws, &fd_ws, max_fd + 1); + ctx->perform_task = GNUNET_SCHEDULER_add_select + (GNUNET_SCHEDULER_PRIORITY_KEEP, + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, timeout), + &rs, &ws, + &do_perform, ctx); + } +} + + +static void +do_perform (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TALER_MINT_Context *ctx = cls; + + GNUNET_assert (NULL != ctx->perform_task); + ctx->perform_task = NULL; + perform (ctx); +} + +static void +perform_now (struct TALER_MINT_Context *ctx) +{ + if (NULL != ctx->perform_task) + { + GNUNET_SCHEDULER_cancel (ctx->perform_task); + ctx->perform_task = NULL; + } + ctx->perform_task = GNUNET_SCHEDULER_add_now (&do_perform, ctx); +} + + +/* This function gets called by libcurl as soon as there is data received that */ +/* needs to be saved. The size of the data pointed to by ptr is size */ +/* multiplied with nmemb, it will not be zero terminated. Return the number */ +/* of bytes actually taken care of. If that amount differs from the amount passed */ +/* to your function, it'll signal an error to the library. This will abort the */ +/* transfer and return CURLE_WRITE_ERROR. */ + +/* From 7.18.0, the function can return CURL_WRITEFUNC_PAUSE which then will */ +/* cause writing to this connection to become paused. See */ +/* curl_easy_pause(3) for further details. */ + +/* This function may be called with zero bytes data if the transferred file is */ +/* empty. */ + +/* Set this option to NULL to get the internal default function. The internal */ +/* default function will write the data to the FILE * given with */ +/* CURLOPT_WRITEDATA. */ + +/* Set the userdata argument with the CURLOPT_WRITEDATA option. */ + +/* The callback function will be passed as much data as possible in all invokes, */ +/* but you cannot possibly make any assumptions. It may be one byte, it may be */ +/* thousands. The maximum amount of body data that can be passed to the write */ +/* callback is defined in the curl.h header file: CURL_MAX_WRITE_SIZE (the usual */ +/* default is 16K). If you however have CURLOPT_HEADER set, which sends */ +/* header data to the write callback, you can get up to */ +/* CURL_MAX_HTTP_HEADER bytes of header data passed into it. This usually */ +/* means 100K. */ +static size_t +download (char *bufptr, size_t size, size_t nitems, void *cls) +{ + struct TALER_MINT_Handle *mint = cls; + size_t msize; + void *buf; + + if (0 == size * nitems) + { + /* file is empty */ + return 0; + } + msize = size * nitems; + mint->buf = GNUNET_realloc (mint->buf, mint->buf_size + msize); + buf = mint->buf + mint->buf_size; + memcpy (buf, bufptr, msize); + mint->buf_size += msize; + return msize; +} + + +/** + * Initialise a connection to the mint. + * + * @param ctx the context + * @param hostname the hostname of the mint + * @param port the point where the mint's HTTP service is running. + * @param mint_key the public key of the mint. This is used to verify the + * responses of the mint. + * @return the mint handle; NULL upon error + */ +struct TALER_MINT_Handle * +TALER_MINT_connect (struct TALER_MINT_Context *ctx, + const char *hostname, + uint16_t port, + struct GNUNET_CRYPTO_EddsaPublicKey *mint_key) +{ + struct TALER_MINT_Handle *mint; + + mint = GNUNET_new (struct TALER_MINT_Handle); + mint->ctx = ctx; + mint->hostname = GNUNET_strdup (hostname); + mint->port = (0 != port) ? port : 80; + mint->curl = curl_easy_init (); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (mint->curl, CURLOPT_SHARE, ctx->share)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (mint->curl, CURLOPT_ERRORBUFFER, mint->emsg)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (mint->curl, CURLOPT_WRITEFUNCTION, &download)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (mint->curl, CURLOPT_WRITEDATA, mint)); + GNUNET_assert (CURLE_OK == curl_easy_setopt (mint->curl, CURLOPT_PRIVATE, mint)); + return mint; +} + +/** + * Disconnect from the mint + * + * @param mint the mint handle + */ +void +TALER_MINT_disconnect (struct TALER_MINT_Handle *mint) +{ + if (GNUNET_YES == mint->connected) + mint_disconnect (mint); + curl_easy_cleanup (mint->curl); + GNUNET_free (mint->hostname); + GNUNET_free (mint); +} + +/** + * Get the signing and denomination key of the mint. + * + * @param mint handle to the mint + * @param cb the callback to call with each retrieved denomination key + * @param cls closure for the above callback + * @param cont_cb the callback to call after completing this asynchronous call + * @param cont_cls the closure for the continuation callback + * @return a handle to this asynchronous call; NULL upon eror + */ +struct TALER_MINT_KeysGetHandle * +TALER_MINT_keys_get (struct TALER_MINT_Handle *mint, + TALER_MINT_KeysGetCallback cb, void *cls, + TALER_MINT_ContinuationCallback cont_cb, void *cont_cls) +{ + struct TALER_MINT_KeysGetHandle *gh; + + GNUNET_assert (REQUEST_TYPE_NONE == mint->req_type); + gh = GNUNET_new (struct TALER_MINT_KeysGetHandle); + gh->mint = mint; + mint->req_type = REQUEST_TYPE_KEYSGET; + mint->req.keys_get = gh; + gh->cb = cb; + gh->cls = cls; + gh->cont_cb = cont_cb; + gh->cont_cls = cont_cls; + GNUNET_asprintf (&gh->url, "http://%s:%hu/keys", mint->hostname, mint->port); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (mint->curl, CURLOPT_URL, gh->url)); + if (GNUNET_NO == mint->connected) + mint_connect (mint); + perform_now (mint->ctx); + return gh; +} + + +/** + * Cancel the asynchronous call initiated by TALER_MINT_keys_get(). This + * should not be called if either of the @a TALER_MINT_KeysGetCallback or + * @a TALER_MINT_ContinuationCallback passed to TALER_MINT_keys_get() have + * been called. + * + * @param get the handle for retrieving the keys + */ +void +TALER_MINT_keys_get_cancel (struct TALER_MINT_KeysGetHandle *get) +{ + struct TALER_MINT_Handle *mint = get->mint; + + mint_disconnect (mint); + cleanup_keys_get (get); +} + +/** + * Submit a deposit permission to the mint and get the mint's response + * + * @param mint the mint handle + * @param cb the callback to call when a reply for this request is available + * @param cls closure for the above callback + * @param deposit_obj the deposit permission received from the customer along + * with the wireformat JSON object + * @return a handle for this request; NULL if the JSON object could not be + * parsed or is of incorrect format or any other error. In this case, + * the callback is not called. + */ +struct TALER_MINT_DepositHandle * +TALER_MINT_deposit_submit_json (struct TALER_MINT_Handle *mint, + TALER_MINT_DepositResultCallback cb, + void *cls, + json_t *deposit_obj) +{ + struct TALER_MINT_DepositHandle *dh; + + GNUNET_assert (REQUEST_TYPE_NONE == mint->req_type); + dh = GNUNET_new (struct TALER_MINT_DepositHandle); + dh->mint = mint; + mint->req_type = REQUEST_TYPE_DEPOSIT; + mint->req.deposit = dh; + dh->cb = cb; + dh->cls = cls; + GNUNET_asprintf (&dh->url, "http://%s:%hu/deposit", mint->hostname, mint->port); + GNUNET_assert (NULL != (dh->json_enc = json_dumps (deposit_obj, JSON_COMPACT))); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (mint->curl, CURLOPT_URL, dh->url)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (mint->curl, CURLOPT_POSTFIELDS, + dh->json_enc)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (mint->curl, CURLOPT_POSTFIELDSIZE, + strlen (dh->json_enc))); + GNUNET_assert (NULL != (dh->headers = + curl_slist_append (dh->headers, "Content-Type: application/json"))); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (mint->curl, CURLOPT_HTTPHEADER, dh->headers)); + if (GNUNET_NO == mint->connected) + mint_connect (mint); + perform_now (mint->ctx); + return dh; +} + + +/** + * Cancel a deposit permission request. This function cannot be used on a + * request handle if a response is already served for it. + * + * @param the deposit permission request handle + */ +void +TALER_MINT_deposit_submit_cancel (struct TALER_MINT_DepositHandle *deposit) +{ + struct TALER_MINT_Handle *mint = deposit->mint; + + mint_disconnect (mint); + cleanup_deposit (deposit); +} + + +/** + * Initialise this library. This function should be called before using any of + * the following functions. + * + * @return library context + */ +struct TALER_MINT_Context * +TALER_MINT_init () +{ + struct TALER_MINT_Context *ctx; + CURLM *multi; + CURLSH *share; + + if (fail) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "cURL was not initialised properly\n"); + return NULL; + } + if (NULL == (multi = curl_multi_init ())) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot create a cURL multi handle\n"); + return NULL; + } + if (NULL == (share = curl_share_init ())) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot create a cURL share handle\n"); + return NULL; + } + ctx = GNUNET_new (struct TALER_MINT_Context); + ctx->multi = multi; + ctx->share = share; + return ctx; +} + + +/** + * Cleanup library initialisation resources. This function should be called + * after using this library to cleanup the resources occupied during library's + * initialisation. + * + * @param ctx the library context + */ +void +TALER_MINT_cleanup (struct TALER_MINT_Context *ctx) +{ + curl_share_cleanup (ctx->share); + curl_multi_cleanup (ctx->multi); + if (NULL != ctx->perform_task) + { + GNUNET_break (0); /* investigate why this happens */ + GNUNET_SCHEDULER_cancel (ctx->perform_task); + } + GNUNET_free (ctx); +} + + +__attribute__ ((constructor)) +void +TALER_MINT_constructor__ (void) +{ + CURLcode ret; + if (CURLE_OK != (ret = curl_global_init (CURL_GLOBAL_DEFAULT))) + { + CURL_STRERROR (GNUNET_ERROR_TYPE_ERROR, "curl_global_init", ret); + fail = 1; + } +} + +__attribute__ ((destructor)) +void +TALER_MINT_destructor__ (void) +{ + if (fail) + return; + curl_global_cleanup (); +} diff --git a/src/lib/test_mint_api.c b/src/lib/test_mint_api.c new file mode 100644 index 000000000..8eb2761dc --- /dev/null +++ b/src/lib/test_mint_api.c @@ -0,0 +1,211 @@ +/* + This file is part of TALER + (C) 2014 Christian Grothoff (and other contributing authors) + + 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 mint/test_mint_api.c + * @brief testcase to test mint's HTTP API interface + * @author Sree Harsha Totakura + */ + +#include "platform.h" +#include "taler_util.h" +#include "taler_mint_service.h" + +struct TALER_MINT_Context *ctx; + +struct TALER_MINT_Handle *mint; + +struct TALER_MINT_KeysGetHandle *dkey_get; + +struct TALER_MINT_DepositHandle *dh; + +static struct GNUNET_SCHEDULER_Task *shutdown_task; + +static int result; + + +static void +do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + shutdown_task = NULL; + if (NULL != dkey_get) + TALER_MINT_keys_get_cancel (dkey_get); + dkey_get = NULL; + if (NULL != dh) + TALER_MINT_deposit_submit_cancel (dh); + dh = NULL; + TALER_MINT_disconnect (mint); + mint = NULL; + TALER_MINT_cleanup (ctx); + ctx = NULL; +} + + +/** + * Callbacks of this type are used to serve the result of submitting a deposit + * permission object to a mint + * + * @param cls closure + * @param status 1 for successful deposit, 2 for retry, 0 for failure + * @param obj the received JSON object; can be NULL if it cannot be constructed + * from the reply + * @param emsg in case of unsuccessful deposit, this contains a human readable + * explanation. + */ +static void +deposit_status (void *cls, + int status, + json_t *obj, + char *emsg) +{ + char *json_enc; + + dh = NULL; + json_enc = NULL; + if (NULL != obj) + { + json_enc = json_dumps (obj, JSON_INDENT(2)); + fprintf (stderr, "%s", json_enc); + } + if (1 == status) + result = GNUNET_OK; + else + GNUNET_break (0); + if (NULL != emsg) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Deposit failed: %s\n", emsg); + GNUNET_SCHEDULER_shutdown (); +} +/** + * Functions of this type are called to signal completion of an asynchronous call. + * + * @param cls closure + * @param emsg if the asynchronous call could not be completed due to an error, + * this parameter contains a human readable error message + */ +static void +cont (void *cls, const char *emsg) +{ + json_t *dp; + char rnd_32[32]; + char rnd_64[64]; + char *enc_32; + char *enc_64; + + GNUNET_assert (NULL == cls); + dkey_get = NULL; + if (NULL != emsg) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg); + + enc_32 = TALER_data_to_string_alloc (rnd_32, sizeof (rnd_32)); + enc_64 = TALER_data_to_string_alloc (rnd_64, sizeof (rnd_64)); + dp = json_pack ("{s:s s:o s:s s:s s:s s:s s:s s:s s:s s:s}", + "type", "DIRECT_DEPOSIT", + "wire", json_pack ("{s:s}", "type", "SEPA"), + "C", enc_32, + "K", enc_32, + "ubsig", enc_64, + "M", enc_32, + "H_a", enc_64, + "H_wire", enc_64, + "csig", enc_64, + "m", "B1C5GP2RB1C5G"); + GNUNET_free (enc_32); + GNUNET_free (enc_64); + dh = TALER_MINT_deposit_submit_json (mint, + deposit_status, + NULL, + dp); + json_decref (dp); +} + + +/** + * Functions of this type are called to provide the retrieved signing and + * denomination keys of the mint. No TALER_MINT_*() functions should be called + * in this callback. + * + * @param cls closure passed to TALER_MINT_keys_get() + * @param sign_keys NULL-terminated array of pointers to the mint's signing + * keys. NULL if no signing keys are retrieved. + * @param denom_keys NULL-terminated array of pointers to the mint's + * denomination keys; will be NULL if no signing keys are retrieved. + */ +static void +read_denom_key (void *cls, + struct TALER_MINT_SigningPublicKey **sign_keys, + struct TALER_MINT_DenomPublicKey **denom_keys) +{ + unsigned int cnt; + GNUNET_assert (NULL == cls); +#define ERR(cond) do { if(!(cond)) break; GNUNET_break (0); return; } while (0) + ERR (NULL == sign_keys); + ERR (NULL == denom_keys); + for (cnt = 0; NULL != sign_keys[cnt]; cnt++) + GNUNET_free (sign_keys[cnt]); + ERR (0 == cnt); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read %u signing keys\n", cnt); + GNUNET_free (sign_keys); + for (cnt = 0; NULL != denom_keys[cnt]; cnt++) + GNUNET_free (denom_keys[cnt]); + ERR (0 == cnt); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read %u denomination keys\n", cnt); + GNUNET_free (denom_keys); +#undef ERR + return; +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param config configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *config) +{ + ctx = TALER_MINT_init (); + mint = TALER_MINT_connect (ctx, "localhost", 4241, NULL); + GNUNET_assert (NULL != mint); + dkey_get = TALER_MINT_keys_get (mint, + &read_denom_key, NULL, + &cont, NULL); + GNUNET_assert (NULL != dkey_get); + shutdown_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 5), + &do_shutdown, NULL); +} + +int +main (int argc, char * const *argv) +{ + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + result = GNUNET_SYSERR; + if (GNUNET_OK != + GNUNET_PROGRAM_run (argc, argv, "test-mint-api", + gettext_noop + ("Testcase to test mint's HTTP API interface"), + options, &run, NULL)) + return 3; + return (GNUNET_OK == result) ? 0 : 1; +} diff --git a/src/mint/Makefile.am b/src/mint/Makefile.am index d0a58812e..eff126a07 100644 --- a/src/mint/Makefile.am +++ b/src/mint/Makefile.am @@ -1,35 +1,22 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/include $(POSTGRESQL_CPPFLAGS) lib_LTLIBRARIES = \ - libtalermint.la \ - libtalermintapi.la + libtalermint_common.la -libtalermint_la_SOURCES = \ +libtalermint_common_la_SOURCES = \ mint_common.c \ mint_db.c -libtalermint_la_LIBADD = \ +libtalermint_common_la_LIBADD = \ $(top_builddir)/src/util/libtalerutil.la \ -lgnunetutil \ -lpq -libtalermint_la_LDFLAGS = \ +libtalermint_common_la_LDFLAGS = \ $(POSTGRESQL_LDFLAGS) \ -version-info 0:0:0 \ -no-undefined -libtalermintapi_la_SOURCES = \ - mint_api.c - -libtalermintapi_la_LIBADD = \ - -lgnunetutil \ - -ljansson \ - -lcurl - -libtalermintapi_la_LDFLAGS = \ - -version-info 0:0:0 \ - -no-undefined - bin_PROGRAMS = \ taler-mint-keyup \ @@ -44,7 +31,7 @@ taler_mint_keyup_SOURCES = \ taler_mint_keyup_LDADD = \ $(LIBGCRYPT_LIBS) \ $(top_builddir)/src/util/libtalerutil.la \ - $(top_builddir)/src/mint/libtalermint.la \ + $(top_builddir)/src/mint/libtalermint_common.la \ -lpq \ -lgnunetutil taler_mint_keyup_LDFLAGS = $(POSTGRESQL_LDFLAGS) @@ -56,7 +43,7 @@ taler_mint_keycheck_SOURCES = \ taler_mint_keycheck_LDADD = \ $(LIBGCRYPT_LIBS) \ $(top_builddir)/src/util/libtalerutil.la \ - $(top_builddir)/src/mint/libtalermint.la \ + $(top_builddir)/src/mint/libtalermint_common.la \ -lgnunetutil \ -lpq taler_mint_keycheck_LDFLAGS = $(POSTGRESQL_LDFLAGS) @@ -66,7 +53,7 @@ taler_mint_reservemod_SOURCES = \ taler_mint_reservemod_LDADD = \ $(LIBGCRYPT_LIBS) \ $(top_builddir)/src/util/libtalerutil.la \ - $(top_builddir)/src/mint/libtalermint.la \ + $(top_builddir)/src/mint/libtalermint_common.la \ -lpq \ -lgnunetutil taler_mint_reservemod_LDFLAGS = \ @@ -83,7 +70,7 @@ taler_mint_httpd_SOURCES = \ taler_mint_httpd_LDADD = \ $(LIBGCRYPT_LIBS) \ $(top_builddir)/src/util/libtalerutil.la \ - $(top_builddir)/src/mint/libtalermint.la \ + $(top_builddir)/src/mint/libtalermint_common.la \ -lpq \ -lmicrohttpd \ -ljansson \ @@ -98,28 +85,19 @@ taler_mint_dbinit_SOURCES = \ taler_mint_dbinit_LDADD = \ $(LIBGCRYPT_LIBS) \ $(top_builddir)/src/util/libtalerutil.la \ - $(top_builddir)/src/mint/libtalermint.la \ + $(top_builddir)/src/mint/libtalermint_common.la \ -lpq \ -lgnunetutil taler_mint_dbinit_LDFLAGS = $(POSTGRESQL_LDFLAGS) check_PROGRAMS = \ - test-mint-api \ test-mint-deposits \ test-mint-common -test_mint_api_SOURCES = test_mint_api.c -test_mint_api_LDADD = \ - libtalermintapi.la \ - $(LIBGCRYPT_LIBS) \ - $(top_builddir)/src/util/libtalerutil.la \ - -lgnunetutil \ - -ljansson - test_mint_deposits_SOURCES = \ test_mint_deposits.c test_mint_deposits_LDADD = \ - libtalermint.la \ + libtalermint_common.la \ $(top_srcdir)/src/util/libtalerutil.la \ -lgnunetutil \ -lpq @@ -127,6 +105,6 @@ test_mint_deposits_LDADD = \ test_mint_common_SOURCES = \ test_mint_common.c test_mint_common_LDADD = \ - libtalermint.la \ + libtalermint_common.la \ $(top_srcdir)/src/util/libtalerutil.la \ -lgnunetutil diff --git a/src/mint/mint.h b/src/mint/mint.h index 5adce03c6..644a9d292 100644 --- a/src/mint/mint.h +++ b/src/mint/mint.h @@ -29,81 +29,37 @@ #include #include "taler_util.h" #include "taler_rsa.h" +#include "taler_signatures.h" #define DIR_SIGNKEYS "signkeys" #define DIR_DENOMKEYS "denomkeys" -GNUNET_NETWORK_STRUCT_BEGIN - - /** - * FIXME + * On disk format used for a mint signing key. + * Includes the private key followed by the signed + * issue message. */ -struct TALER_MINT_SignKeyIssue +struct TALER_MINT_SignKeyIssuePriv { struct GNUNET_CRYPTO_EddsaPrivateKey signkey_priv; - struct GNUNET_CRYPTO_EddsaSignature signature; - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_CRYPTO_EddsaPublicKey master_pub; - struct GNUNET_TIME_AbsoluteNBO start; - struct GNUNET_TIME_AbsoluteNBO expire; - struct GNUNET_CRYPTO_EddsaPublicKey signkey_pub; + struct TALER_MINT_SignKeyIssue issue; }; -struct TALER_MINT_DenomKeyIssue + + +struct TALER_MINT_DenomKeyIssuePriv { /** * The private key of the denomination. Will be NULL if the private key is * not available. */ struct TALER_RSA_PrivateKey *denom_priv; - struct GNUNET_CRYPTO_EddsaSignature signature; - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_CRYPTO_EddsaPublicKey master; - struct GNUNET_TIME_AbsoluteNBO start; - struct GNUNET_TIME_AbsoluteNBO expire_withdraw; - struct GNUNET_TIME_AbsoluteNBO expire_spend; - struct TALER_RSA_PublicKeyBinaryEncoded denom_pub; - struct TALER_AmountNBO value; - struct TALER_AmountNBO fee_withdraw; - struct TALER_AmountNBO fee_deposit; - struct TALER_AmountNBO fee_refresh; -}; - -struct RefreshMeltSignatureBody -{ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_HashCode melt_hash; -}; - -struct RefreshCommitSignatureBody -{ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_HashCode commit_hash; -}; - -struct RefreshCommitResponseSignatureBody -{ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - uint16_t noreveal_index; -}; - -struct RefreshMeltResponseSignatureBody -{ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_HashCode melt_response_hash; + struct TALER_MINT_DenomKeyIssue issue; }; -struct RefreshMeltConfirmSignRequestBody -{ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_CRYPTO_EddsaPublicKey session_pub; -}; - -GNUNET_NETWORK_STRUCT_END @@ -116,8 +72,9 @@ GNUNET_NETWORK_STRUCT_END * #GNUNET_NO to stop iteration with no error, * #GNUNET_SYSERR to abort iteration with error! */ -typedef int (*TALER_MINT_SignkeyIterator)(void *cls, - const struct TALER_MINT_SignKeyIssue *ski); +typedef int +(*TALER_MINT_SignkeyIterator)(void *cls, + const struct TALER_MINT_SignKeyIssuePriv *ski); /** * Iterator for denomination keys. @@ -129,9 +86,10 @@ typedef int (*TALER_MINT_SignkeyIterator)(void *cls, * #GNUNET_NO to stop iteration with no error, * #GNUNET_SYSERR to abort iteration with error! */ -typedef int (*TALER_MINT_DenomkeyIterator)(void *cls, - const char *alias, - const struct TALER_MINT_DenomKeyIssue *dki); +typedef int +(*TALER_MINT_DenomkeyIterator)(void *cls, + const char *alias, + const struct TALER_MINT_DenomKeyIssuePriv *dki); @@ -160,7 +118,7 @@ TALER_MINT_denomkeys_iterate (const char *mint_base_dir, */ int TALER_MINT_write_denom_key (const char *filename, - const struct TALER_MINT_DenomKeyIssue *dki); + const struct TALER_MINT_DenomKeyIssuePriv *dki); /** @@ -172,7 +130,7 @@ TALER_MINT_write_denom_key (const char *filename, */ int TALER_MINT_read_denom_key (const char *filename, - struct TALER_MINT_DenomKeyIssue *dki); + struct TALER_MINT_DenomKeyIssuePriv *dki); /** diff --git a/src/mint/mint_api.c b/src/mint/mint_api.c deleted file mode 100644 index b8d42b274..000000000 --- a/src/mint/mint_api.c +++ /dev/null @@ -1,1121 +0,0 @@ -/* - This file is part of TALER - (C) 2014 Christian Grothoff (and other contributing authors) - - 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 mint/mint_api.c - * @brief Implementation of the client interface to mint's HTTP API - * @author Sree Harsha Totakura - */ - -#include "platform.h" -#include -#include -#include -#include "taler_mint_service.h" -#include "taler_signatures.h" -#include "mint.h" - -#define CURL_STRERROR(TYPE, FUNCTION, CODE) \ - GNUNET_log (TYPE, "cURL function `%s' has failed at `%s:%d' with error: %s", \ - FUNCTION, __FILE__, __LINE__, curl_easy_strerror (CODE)); - - - -/** - * Print JSON parsing related error information - */ -#define JSON_WARN(error) \ - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \ - "JSON parsing failed at %s:%u: %s (%s)", \ - __FILE__, __LINE__, error.text, error.source) - -/** - * Failsafe flag - */ -static int fail; - -/** - * Context - */ -struct TALER_MINT_Context -{ - /** - * CURL multi handle - */ - CURLM *multi; - - /** - * CURL share handle - */ - CURLSH *share; - - /** - * Perform task handle - */ - struct GNUNET_SCHEDULER_Task *perform_task; -}; - -/** - * Type of requests we currently have - */ -enum RequestType -{ - /** - * No request - */ - REQUEST_TYPE_NONE, - - /** - * Current request is to receive mint's keys - */ - REQUEST_TYPE_KEYSGET, - - /** - * Current request is to submit a deposit permission and get its status - */ - REQUEST_TYPE_DEPOSIT -}; - - -/** - * Handle to the mint - */ -struct TALER_MINT_Handle -{ - /** - * The context of this handle - */ - struct TALER_MINT_Context *ctx; - - /** - * The hostname of the mint - */ - char *hostname; - - /** - * The CURL handle - */ - CURL *curl; - - /** - * Error buffer for CURL - */ - char emsg[CURL_ERROR_SIZE]; - - /** - * Download buffer - */ - void *buf; - - /** - * The currently active request - */ - union { - /** - * Used to denote no request if set to NULL - */ - void *none; - - /** - * Denom keys get request if REQUEST_TYPE_KEYSGET - */ - struct TALER_MINT_KeysGetHandle *keys_get; - - /** - * Deposit request if REQUEST_TYPE_DEPOSIT - */ - struct TALER_MINT_DepositHandle *deposit; - } req; - - /** - * The size of the download buffer - */ - size_t buf_size; - - /** - * Active request type - */ - enum RequestType req_type; - - /** - * The service port of the mint - */ - uint16_t port; - - /** - * Are we connected to the mint? - */ - uint8_t connected; - -}; - - -/** - * A handle to get the keys of a mint - */ -struct TALER_MINT_KeysGetHandle -{ - /** - * The connection to mint this request handle will use - */ - struct TALER_MINT_Handle *mint; - - /** - * The url for this handle - */ - char *url; - - TALER_MINT_KeysGetCallback cb; - void *cls; - - TALER_MINT_ContinuationCallback cont_cb; - void *cont_cls; -}; - - -/** - * A handle to submit a deposit permission and get its status - */ -struct TALER_MINT_DepositHandle -{ - /** - *The connection to mint this request handle will use - */ - struct TALER_MINT_Handle *mint; - - /** - * The url for this handle - */ - char *url; - - TALER_MINT_DepositResultCallback cb; - void *cls; - - char *json_enc; - - struct curl_slist *headers; - -}; - - -/** - * Parses the timestamp encoded as ASCII string as UNIX timstamp. - * - * @param abs successfully parsed timestamp will be returned thru this parameter - * @param tstamp_enc the ASCII encoding of the timestamp - * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure - */ -static int -parse_timestamp (struct GNUNET_TIME_Absolute *abs, const char *tstamp_enc) -{ - unsigned long tstamp; - - if (1 != sscanf (tstamp_enc, "%lu", &tstamp)) - return GNUNET_SYSERR; - *abs = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get_zero_ (), - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, tstamp)); - return GNUNET_OK; -} - - -#define EXITIF(cond) \ - do { \ - if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ - } while (0) - - - -static int -parse_json_signkey (struct TALER_MINT_SigningPublicKey **_sign_key, - json_t *sign_key_obj, - struct GNUNET_CRYPTO_EddsaPublicKey *master_key) -{ - json_t *valid_from_obj; - json_t *valid_until_obj; - json_t *key_obj; - json_t *sig_obj; - const char *valid_from_enc; - const char *valid_until_enc; - const char *key_enc; - const char *sig_enc; - struct TALER_MINT_SigningPublicKey *sign_key; - struct TALER_MINT_SignKeyIssue sign_key_issue; - struct GNUNET_CRYPTO_EddsaSignature sig; - struct GNUNET_TIME_Absolute valid_from; - struct GNUNET_TIME_Absolute valid_until; - - EXITIF (JSON_OBJECT != json_typeof (sign_key_obj)); - EXITIF (NULL == (valid_from_obj = json_object_get (sign_key_obj, - "stamp_start"))); - EXITIF (NULL == (valid_until_obj = json_object_get (sign_key_obj, - "stamp_expire"))); - EXITIF (NULL == (key_obj = json_object_get (sign_key_obj, "key"))); - EXITIF (NULL == (sig_obj = json_object_get (sign_key_obj, "master_sig"))); - EXITIF (NULL == (valid_from_enc = json_string_value (valid_from_obj))); - EXITIF (NULL == (valid_until_enc = json_string_value (valid_until_obj))); - EXITIF (NULL == (key_enc = json_string_value (key_obj))); - EXITIF (NULL == (sig_enc = json_string_value (sig_obj))); - EXITIF (GNUNET_SYSERR == parse_timestamp (&valid_from, - valid_from_enc)); - EXITIF (GNUNET_SYSERR == parse_timestamp (&valid_until, - valid_until_enc)); - EXITIF (52 != strlen (key_enc)); /* strlen(base32(char[32])) = 52 */ - EXITIF (103 != strlen (sig_enc)); /* strlen(base32(char[64])) = 103 */ - EXITIF (GNUNET_OK != GNUNET_STRINGS_string_to_data (sig_enc, 103, - &sig, sizeof (sig))); - (void) memset (&sign_key_issue, 0, sizeof (sign_key_issue)); - EXITIF (GNUNET_SYSERR == - GNUNET_CRYPTO_eddsa_public_key_from_string (key_enc, - 52, - &sign_key_issue.signkey_pub)); - sign_key_issue.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNKEY); - sign_key_issue.purpose.size = - htonl (sizeof (sign_key_issue) - - offsetof (struct TALER_MINT_SignKeyIssue, purpose)); - sign_key_issue.master_pub = *master_key; - sign_key_issue.start = GNUNET_TIME_absolute_hton (valid_from); - sign_key_issue.expire = GNUNET_TIME_absolute_hton (valid_until); - EXITIF (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNKEY, - &sign_key_issue.purpose, - &sig, - master_key)); - sign_key = GNUNET_new (struct TALER_MINT_SigningPublicKey); - sign_key->valid_from = valid_from; - sign_key->valid_until = valid_until; - sign_key->key = sign_key_issue.signkey_pub; - *_sign_key = sign_key; - return GNUNET_OK; - - EXITIF_exit: - return GNUNET_SYSERR; -} - - -static int -parse_json_amount (json_t *amount_obj, struct TALER_Amount *amt) -{ - json_t *obj; - const char *currency_str; - int value; - int fraction; - - EXITIF (NULL == (obj = json_object_get (amount_obj, "currency"))); - EXITIF (NULL == (currency_str = json_string_value (obj))); - EXITIF (NULL == (obj = json_object_get (amount_obj, "value"))); - EXITIF (JSON_INTEGER != json_typeof (obj)); - EXITIF (0 > (value = json_integer_value (obj))); - EXITIF (NULL == (obj = json_object_get (amount_obj, "fraction"))); - EXITIF (JSON_INTEGER != json_typeof (obj)); - EXITIF (0 > (fraction = json_integer_value (obj))); - (void) memset (amt->currency, 0, sizeof (amt->currency)); - (void) strncpy (amt->currency, currency_str, sizeof (amt->currency) - 1); - amt->value = (uint32_t) value; - amt->fraction = (uint32_t) fraction; - return GNUNET_OK; - - EXITIF_exit: - return GNUNET_SYSERR; -} - -static int -parse_json_denomkey (struct TALER_MINT_DenomPublicKey **_denom_key, - json_t *denom_key_obj, - struct GNUNET_CRYPTO_EddsaPublicKey *master_key) -{ - json_t *obj; - const char *sig_enc; - const char *deposit_valid_until_enc; - const char *withdraw_valid_until_enc; - const char *valid_from_enc; - const char *key_enc; - struct TALER_MINT_DenomPublicKey *denom_key; - struct GNUNET_TIME_Absolute valid_from; - struct GNUNET_TIME_Absolute withdraw_valid_until; - struct GNUNET_TIME_Absolute deposit_valid_until; - struct TALER_Amount value; - struct TALER_Amount fee_withdraw; - struct TALER_Amount fee_deposit; - struct TALER_Amount fee_refresh; - struct TALER_MINT_DenomKeyIssue denom_key_issue; - struct GNUNET_CRYPTO_EddsaSignature sig; - - EXITIF (JSON_OBJECT != json_typeof (denom_key_obj)); - EXITIF (NULL == (obj = json_object_get (denom_key_obj, "master_sig"))); - EXITIF (NULL == (sig_enc = json_string_value (obj))); - EXITIF (103 != strlen (sig_enc)); - EXITIF (GNUNET_OK != GNUNET_STRINGS_string_to_data (sig_enc, 103, - &sig, sizeof (sig))); - EXITIF (NULL == (obj = json_object_get (denom_key_obj, "stamp_expire_deposit"))); - EXITIF (NULL == (deposit_valid_until_enc = json_string_value (obj))); - EXITIF (NULL == (obj = json_object_get (denom_key_obj, "stamp_expire_withdraw"))); - EXITIF (NULL == (withdraw_valid_until_enc = json_string_value (obj))); - EXITIF (NULL == (obj = json_object_get (denom_key_obj, "stamp_start"))); - EXITIF (NULL == (valid_from_enc = json_string_value (obj))); - EXITIF (NULL == (obj = json_object_get (denom_key_obj, "denom_pub"))); - EXITIF (NULL == (key_enc = json_string_value (obj))); - EXITIF (52 != strlen (key_enc)); /* strlen(base32(char[32])) = 52 */ - EXITIF (GNUNET_SYSERR == parse_timestamp (&valid_from, valid_from_enc)); - EXITIF (GNUNET_SYSERR == parse_timestamp (&withdraw_valid_until, - withdraw_valid_until_enc)); - EXITIF (GNUNET_SYSERR == parse_timestamp (&deposit_valid_until, - deposit_valid_until_enc)); - - (void) memset (&denom_key_issue, 0, sizeof (denom_key_issue)); - EXITIF (GNUNET_OK != GNUNET_STRINGS_string_to_data (key_enc, 52, - &denom_key_issue.denom_pub, - sizeof (struct TALER_RSA_PublicKeyBinaryEncoded))); - EXITIF (NULL == (obj = json_object_get (denom_key_obj, "value"))); - EXITIF (GNUNET_SYSERR == parse_json_amount (obj, &value)); - EXITIF (NULL == (obj = json_object_get (denom_key_obj, "fee_withdraw"))); - EXITIF (GNUNET_SYSERR == parse_json_amount (obj, &fee_withdraw)); - EXITIF (NULL == (obj = json_object_get (denom_key_obj, "fee_deposit"))); - EXITIF (GNUNET_SYSERR == parse_json_amount (obj, &fee_deposit)); - EXITIF (NULL == (obj = json_object_get (denom_key_obj, "fee_refresh"))); - EXITIF (GNUNET_SYSERR == parse_json_amount (obj, &fee_refresh)); - denom_key_issue.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOM); - denom_key_issue.purpose.size = htonl - (sizeof (struct TALER_MINT_DenomKeyIssue) - - offsetof (struct TALER_MINT_DenomKeyIssue, purpose)); - 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_spend = GNUNET_TIME_absolute_hton (deposit_valid_until); - denom_key_issue.value = TALER_amount_hton (value); - denom_key_issue.fee_withdraw = TALER_amount_hton (fee_withdraw); - denom_key_issue.fee_deposit = TALER_amount_hton (fee_deposit); - denom_key_issue.fee_refresh = TALER_amount_hton (fee_refresh); - EXITIF (GNUNET_SYSERR == - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOM, - &denom_key_issue.purpose, - &sig, - master_key)); - denom_key = GNUNET_new (struct TALER_MINT_DenomPublicKey); - denom_key->key = denom_key_issue.denom_pub; - denom_key->valid_from = valid_from; - denom_key->withdraw_valid_until = withdraw_valid_until; - denom_key->deposit_valid_until = deposit_valid_until; - denom_key->value = value; - denom_key->fee_withdraw = fee_withdraw; - denom_key->fee_deposit = fee_deposit; - denom_key->fee_refresh = fee_refresh; - *_denom_key = denom_key; - return GNUNET_OK; - - EXITIF_exit: - return GNUNET_SYSERR; -} - -static int -parse_response_keys_get (const char *in, size_t size, - struct TALER_MINT_SigningPublicKey ***_sign_keys, - unsigned int *_n_sign_keys, - struct TALER_MINT_DenomPublicKey ***_denom_keys, - unsigned int *_n_denom_keys) -{ - json_t *resp_obj; - struct TALER_MINT_DenomPublicKey **denom_keys; - struct GNUNET_CRYPTO_EddsaPublicKey master_key; - struct GNUNET_TIME_Absolute list_issue_date; - struct TALER_MINT_SigningPublicKey **sign_keys; - unsigned int n_denom_keys; - unsigned int n_sign_keys; - json_error_t error; - unsigned int index; - int OK; - - denom_keys = NULL; - n_denom_keys = 0; - sign_keys = NULL; - n_sign_keys = 0; - OK = 0; - resp_obj = json_loadb (in, size, - JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK, - &error); - if (NULL == resp_obj) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse received data as JSON object\n"); - return GNUNET_SYSERR; - } - - EXITIF (JSON_OBJECT != json_typeof (resp_obj)); - { - /* parse the master public key */ - json_t *master_key_obj; - const char *master_key_enc; - - EXITIF (NULL == (master_key_obj = json_object_get (resp_obj, "master_pub"))); - EXITIF (NULL == (master_key_enc = json_string_value (master_key_obj))); - EXITIF (52 != strlen (master_key_enc)); /* strlen(base32(char[32])) = 52 */ - EXITIF (GNUNET_OK != - GNUNET_CRYPTO_eddsa_public_key_from_string (master_key_enc, - 52, - &master_key)); - } - { - /* parse the issue date of the response */ - json_t *list_issue_date_obj; - const char *tstamp_enc; - - EXITIF (NULL == (list_issue_date_obj = - json_object_get(resp_obj, "list_issue_date"))); - EXITIF (NULL == (tstamp_enc = json_string_value (list_issue_date_obj))); - EXITIF (GNUNET_SYSERR == parse_timestamp (&list_issue_date, tstamp_enc)); - } - { - /* parse the signing keys */ - json_t *sign_keys_array; - json_t *sign_key_obj; - - EXITIF (NULL == (sign_keys_array = - json_object_get (resp_obj, "signkeys"))); - EXITIF (JSON_ARRAY != json_typeof (sign_keys_array)); - EXITIF (0 == (n_sign_keys = json_array_size (sign_keys_array))); - sign_keys = GNUNET_malloc (sizeof (struct TALER_MINT_SigningPublicKey *) - * (n_sign_keys + 1)); - index = 0; - json_array_foreach (sign_keys_array, index, sign_key_obj) { - EXITIF (GNUNET_SYSERR == parse_json_signkey (&sign_keys[index], - sign_key_obj, - &master_key)); - } - } - { - /* parse the denomination keys */ - json_t *denom_keys_array; - json_t *denom_key_obj; - - EXITIF (NULL == (denom_keys_array = json_object_get (resp_obj, "denoms"))); - EXITIF (JSON_ARRAY != json_typeof (denom_keys_array)); - EXITIF (0 == (n_denom_keys = json_array_size (denom_keys_array))); - denom_keys = GNUNET_malloc (sizeof (struct TALER_MINT_DenomPublicKey *) - * (n_denom_keys + 1)); - index = 0; - json_array_foreach (denom_keys_array, index, denom_key_obj) { - EXITIF (GNUNET_SYSERR == parse_json_denomkey (&denom_keys[index], - denom_key_obj, - &master_key)); - } - } - OK = 1; - - EXITIF_exit: - json_decref (resp_obj); - if (!OK) - { - if (NULL != sign_keys) - { - for (index=0; NULL != sign_keys[index]; index++) - GNUNET_free_non_null (sign_keys[index]); - GNUNET_free (sign_keys); - } - if (NULL != denom_keys) - { - for (index=0; NULL != denom_keys[index]; index++) - GNUNET_free_non_null (denom_keys[index]); - GNUNET_free (denom_keys); - } - return GNUNET_SYSERR; - } - - *_sign_keys = sign_keys; - *_n_sign_keys = n_sign_keys; - *_denom_keys = denom_keys; - *_n_denom_keys = n_denom_keys; - return GNUNET_OK; -} - - -int -parse_deposit_response (void *buf, size_t size, int *r_status, json_t **r_obj) -{ - json_t *obj; - const char *status_str; - json_error_t error; - - status_str = NULL; - obj = NULL; - obj = json_loadb (buf, size, - JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK, &error); - if (NULL == obj) - { - JSON_WARN (error); - return GNUNET_SYSERR; - } - EXITIF (-1 == json_unpack (obj, "{s:s}", "status", &status_str)); - LOG_DEBUG ("Received deposit response: %s from mint\n", status_str); - if (0 == strcmp ("DEPOSIT_OK", status_str)) - *r_status = 1; - else if (0 == strcmp ("DEPOSIT_QUEUED", status_str)) - *r_status = 2; - else - *r_status = 0; - *r_obj = obj; - - return GNUNET_OK; - EXITIF_exit: - json_decref (obj); - return GNUNET_SYSERR; -} - -#undef EXITIF - -static void -mint_connect (struct TALER_MINT_Handle *mint) -{ - struct TALER_MINT_Context *ctx = mint->ctx; - - GNUNET_assert (0 == mint->connected); - GNUNET_assert (CURLM_OK == curl_multi_add_handle (ctx->multi, mint->curl)); - mint->connected = GNUNET_YES; -} - -static void -mint_disconnect (struct TALER_MINT_Handle *mint) -{ - struct TALER_MINT_Context *ctx = mint->ctx; - - GNUNET_assert (GNUNET_YES == mint->connected); - GNUNET_break (CURLM_OK == curl_multi_remove_handle (ctx->multi, - mint->curl)); - mint->connected = GNUNET_NO; - GNUNET_free_non_null (mint->buf); - mint->buf = NULL; - mint->buf_size = 0; - mint->req_type = REQUEST_TYPE_NONE; - mint->req.none = NULL; -} - -static void -cleanup_keys_get (struct TALER_MINT_KeysGetHandle *gh) -{ - GNUNET_free (gh->url); - GNUNET_free (gh); -} - -static void -cleanup_deposit (struct TALER_MINT_DepositHandle *dh) -{ - curl_slist_free_all (dh->headers); - GNUNET_free_non_null (dh->json_enc); - GNUNET_free (dh->url); - GNUNET_free (dh); -} - -static void -request_failed (struct TALER_MINT_Handle *mint, long resp_code) -{ - switch (mint->req_type) - { - case REQUEST_TYPE_NONE: - GNUNET_assert (0); - break; - case REQUEST_TYPE_KEYSGET: - { - struct TALER_MINT_KeysGetHandle *gh = mint->req.keys_get; - TALER_MINT_ContinuationCallback cont_cb; - void *cont_cls; - GNUNET_assert (NULL != gh); - cont_cb = gh->cont_cb; - cont_cls = gh->cont_cls; - cleanup_keys_get (gh); - mint_disconnect (mint); - cont_cb (cont_cls, mint->emsg); - } - break; - case REQUEST_TYPE_DEPOSIT: - { - struct TALER_MINT_DepositHandle *dh = mint->req.deposit; - TALER_MINT_DepositResultCallback cb = dh->cb; - void *cls = dh->cls; - GNUNET_assert (NULL != dh); - cleanup_deposit (dh); - mint_disconnect (mint); - cb (cls, 0, NULL, mint->emsg); - } - break; - } -} - -static void -request_succeeded (struct TALER_MINT_Handle *mint, long resp_code) -{ - char *emsg; - - emsg = NULL; - switch (mint->req_type) - { - case REQUEST_TYPE_NONE: - GNUNET_assert (0); - break; - case REQUEST_TYPE_KEYSGET: - { - struct TALER_MINT_KeysGetHandle *gh = mint->req.keys_get; - TALER_MINT_ContinuationCallback cont_cb; - void *cont_cls; - struct TALER_MINT_SigningPublicKey **sign_keys; - struct TALER_MINT_DenomPublicKey **denom_keys; - unsigned int n_sign_keys; - unsigned int n_denom_keys; - - GNUNET_assert (NULL != gh); - cont_cb = gh->cont_cb; - cont_cls = gh->cont_cls; - if (200 == resp_code) - { - /* parse JSON object from the mint->buf which is of size mint->buf_size */ - if (GNUNET_OK == - parse_response_keys_get (mint->buf, mint->buf_size, - &sign_keys, &n_sign_keys, - &denom_keys, &n_denom_keys)) - gh->cb (gh->cls, sign_keys, denom_keys); - else - emsg = GNUNET_strdup ("Error parsing response"); - } - else - GNUNET_asprintf (&emsg, "Failed with response code: %ld", resp_code); - cleanup_keys_get (gh); - mint_disconnect (mint); - cont_cb (cont_cls, emsg); - } - break; - case REQUEST_TYPE_DEPOSIT: - { - struct TALER_MINT_DepositHandle *dh = mint->req.deposit; - TALER_MINT_DepositResultCallback cb; - void *cls; - int status; - json_t *obj; - - GNUNET_assert (NULL != dh); - obj = NULL; - cb = dh->cb; - cls = dh->cls; - status = 0; - if (200 == resp_code) - { - /* parse JSON object from the mint->buf which is of size mint->buf_size */ - if (GNUNET_OK != - parse_deposit_response (mint->buf, mint->buf_size, - &status, &obj)) - emsg = GNUNET_strdup ("Error parsing response"); - } - else - GNUNET_asprintf (&emsg, "Failed with response code: %ld", resp_code); - cleanup_deposit (dh); - mint_disconnect (mint); - cb (cls, status, obj, emsg); - } - break; - } - GNUNET_free_non_null (emsg); -} - - -static void -do_perform (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - -static void -perform (struct TALER_MINT_Context *ctx) -{ - fd_set fd_rs; - fd_set fd_ws; - struct GNUNET_NETWORK_FDSet rs; - struct GNUNET_NETWORK_FDSet ws; - CURLMsg *cmsg; - struct TALER_MINT_Handle *mint; - long timeout; - long resp_code; - static unsigned int n_old; - int n_running; - int n_completed; - int max_fd; - - n_completed = 0; - curl_multi_perform (ctx->multi, &n_running); - GNUNET_assert (0 <= n_running); - if ((0 == n_running) || (n_running < n_old)) - { - /* some requests were completed -- handle them */ - while (NULL != (cmsg = curl_multi_info_read (ctx->multi, &n_completed))) - { - GNUNET_break (CURLMSG_DONE == cmsg->msg); /* curl only has CURLMSG_DONE */ - GNUNET_assert (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle, - CURLINFO_PRIVATE, - (char *) &mint)); - GNUNET_assert (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle, - CURLINFO_RESPONSE_CODE, - &resp_code)); - GNUNET_assert (ctx == mint->ctx); /* did we get the correct one? */ - if (CURLE_OK == cmsg->data.result) - request_succeeded (mint, resp_code); - else - request_failed (mint, resp_code); - } - } - n_old = n_running; - /* reschedule perform() */ - if (0 != n_old) - { - FD_ZERO (&fd_rs); - FD_ZERO (&fd_ws); - GNUNET_assert (CURLM_OK == curl_multi_fdset (ctx->multi, - &fd_rs, - &fd_ws, - NULL, - &max_fd)); - if (-1 == max_fd) - { - ctx->perform_task = GNUNET_SCHEDULER_add_delayed - (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100), - &do_perform, ctx); - return; - } - GNUNET_assert (CURLM_OK == curl_multi_timeout (ctx->multi, &timeout)); - if (-1 == timeout) - { - timeout = 1000 * 60 * 5; - } - GNUNET_NETWORK_fdset_zero (&rs); - GNUNET_NETWORK_fdset_zero (&ws); - GNUNET_NETWORK_fdset_copy_native (&rs, &fd_rs, max_fd + 1); - GNUNET_NETWORK_fdset_copy_native (&ws, &fd_ws, max_fd + 1); - ctx->perform_task = GNUNET_SCHEDULER_add_select - (GNUNET_SCHEDULER_PRIORITY_KEEP, - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, timeout), - &rs, &ws, - &do_perform, ctx); - } -} - - -static void -do_perform (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct TALER_MINT_Context *ctx = cls; - - GNUNET_assert (NULL != ctx->perform_task); - ctx->perform_task = NULL; - perform (ctx); -} - -static void -perform_now (struct TALER_MINT_Context *ctx) -{ - if (NULL != ctx->perform_task) - { - GNUNET_SCHEDULER_cancel (ctx->perform_task); - ctx->perform_task = NULL; - } - ctx->perform_task = GNUNET_SCHEDULER_add_now (&do_perform, ctx); -} - - -/* This function gets called by libcurl as soon as there is data received that */ -/* needs to be saved. The size of the data pointed to by ptr is size */ -/* multiplied with nmemb, it will not be zero terminated. Return the number */ -/* of bytes actually taken care of. If that amount differs from the amount passed */ -/* to your function, it'll signal an error to the library. This will abort the */ -/* transfer and return CURLE_WRITE_ERROR. */ - -/* From 7.18.0, the function can return CURL_WRITEFUNC_PAUSE which then will */ -/* cause writing to this connection to become paused. See */ -/* curl_easy_pause(3) for further details. */ - -/* This function may be called with zero bytes data if the transferred file is */ -/* empty. */ - -/* Set this option to NULL to get the internal default function. The internal */ -/* default function will write the data to the FILE * given with */ -/* CURLOPT_WRITEDATA. */ - -/* Set the userdata argument with the CURLOPT_WRITEDATA option. */ - -/* The callback function will be passed as much data as possible in all invokes, */ -/* but you cannot possibly make any assumptions. It may be one byte, it may be */ -/* thousands. The maximum amount of body data that can be passed to the write */ -/* callback is defined in the curl.h header file: CURL_MAX_WRITE_SIZE (the usual */ -/* default is 16K). If you however have CURLOPT_HEADER set, which sends */ -/* header data to the write callback, you can get up to */ -/* CURL_MAX_HTTP_HEADER bytes of header data passed into it. This usually */ -/* means 100K. */ -static size_t -download (char *bufptr, size_t size, size_t nitems, void *cls) -{ - struct TALER_MINT_Handle *mint = cls; - size_t msize; - void *buf; - - if (0 == size * nitems) - { - /* file is empty */ - return 0; - } - msize = size * nitems; - mint->buf = GNUNET_realloc (mint->buf, mint->buf_size + msize); - buf = mint->buf + mint->buf_size; - memcpy (buf, bufptr, msize); - mint->buf_size += msize; - return msize; -} - - -/** - * Initialise a connection to the mint. - * - * @param ctx the context - * @param hostname the hostname of the mint - * @param port the point where the mint's HTTP service is running. - * @param mint_key the public key of the mint. This is used to verify the - * responses of the mint. - * @return the mint handle; NULL upon error - */ -struct TALER_MINT_Handle * -TALER_MINT_connect (struct TALER_MINT_Context *ctx, - const char *hostname, - uint16_t port, - struct GNUNET_CRYPTO_EddsaPublicKey *mint_key) -{ - struct TALER_MINT_Handle *mint; - - mint = GNUNET_new (struct TALER_MINT_Handle); - mint->ctx = ctx; - mint->hostname = GNUNET_strdup (hostname); - mint->port = (0 != port) ? port : 80; - mint->curl = curl_easy_init (); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (mint->curl, CURLOPT_SHARE, ctx->share)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (mint->curl, CURLOPT_ERRORBUFFER, mint->emsg)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (mint->curl, CURLOPT_WRITEFUNCTION, &download)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (mint->curl, CURLOPT_WRITEDATA, mint)); - GNUNET_assert (CURLE_OK == curl_easy_setopt (mint->curl, CURLOPT_PRIVATE, mint)); - return mint; -} - -/** - * Disconnect from the mint - * - * @param mint the mint handle - */ -void -TALER_MINT_disconnect (struct TALER_MINT_Handle *mint) -{ - if (GNUNET_YES == mint->connected) - mint_disconnect (mint); - curl_easy_cleanup (mint->curl); - GNUNET_free (mint->hostname); - GNUNET_free (mint); -} - -/** - * Get the signing and denomination key of the mint. - * - * @param mint handle to the mint - * @param cb the callback to call with each retrieved denomination key - * @param cls closure for the above callback - * @param cont_cb the callback to call after completing this asynchronous call - * @param cont_cls the closure for the continuation callback - * @return a handle to this asynchronous call; NULL upon eror - */ -struct TALER_MINT_KeysGetHandle * -TALER_MINT_keys_get (struct TALER_MINT_Handle *mint, - TALER_MINT_KeysGetCallback cb, void *cls, - TALER_MINT_ContinuationCallback cont_cb, void *cont_cls) -{ - struct TALER_MINT_KeysGetHandle *gh; - - GNUNET_assert (REQUEST_TYPE_NONE == mint->req_type); - gh = GNUNET_new (struct TALER_MINT_KeysGetHandle); - gh->mint = mint; - mint->req_type = REQUEST_TYPE_KEYSGET; - mint->req.keys_get = gh; - gh->cb = cb; - gh->cls = cls; - gh->cont_cb = cont_cb; - gh->cont_cls = cont_cls; - GNUNET_asprintf (&gh->url, "http://%s:%hu/keys", mint->hostname, mint->port); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (mint->curl, CURLOPT_URL, gh->url)); - if (GNUNET_NO == mint->connected) - mint_connect (mint); - perform_now (mint->ctx); - return gh; -} - - -/** - * Cancel the asynchronous call initiated by TALER_MINT_keys_get(). This - * should not be called if either of the @a TALER_MINT_KeysGetCallback or - * @a TALER_MINT_ContinuationCallback passed to TALER_MINT_keys_get() have - * been called. - * - * @param get the handle for retrieving the keys - */ -void -TALER_MINT_keys_get_cancel (struct TALER_MINT_KeysGetHandle *get) -{ - struct TALER_MINT_Handle *mint = get->mint; - - mint_disconnect (mint); - cleanup_keys_get (get); -} - -/** - * Submit a deposit permission to the mint and get the mint's response - * - * @param mint the mint handle - * @param cb the callback to call when a reply for this request is available - * @param cls closure for the above callback - * @param deposit_obj the deposit permission received from the customer along - * with the wireformat JSON object - * @return a handle for this request; NULL if the JSON object could not be - * parsed or is of incorrect format or any other error. In this case, - * the callback is not called. - */ -struct TALER_MINT_DepositHandle * -TALER_MINT_deposit_submit_json (struct TALER_MINT_Handle *mint, - TALER_MINT_DepositResultCallback cb, - void *cls, - json_t *deposit_obj) -{ - struct TALER_MINT_DepositHandle *dh; - - GNUNET_assert (REQUEST_TYPE_NONE == mint->req_type); - dh = GNUNET_new (struct TALER_MINT_DepositHandle); - dh->mint = mint; - mint->req_type = REQUEST_TYPE_DEPOSIT; - mint->req.deposit = dh; - dh->cb = cb; - dh->cls = cls; - GNUNET_asprintf (&dh->url, "http://%s:%hu/deposit", mint->hostname, mint->port); - GNUNET_assert (NULL != (dh->json_enc = json_dumps (deposit_obj, JSON_COMPACT))); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (mint->curl, CURLOPT_URL, dh->url)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (mint->curl, CURLOPT_POSTFIELDS, - dh->json_enc)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (mint->curl, CURLOPT_POSTFIELDSIZE, - strlen (dh->json_enc))); - GNUNET_assert (NULL != (dh->headers = - curl_slist_append (dh->headers, "Content-Type: application/json"))); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (mint->curl, CURLOPT_HTTPHEADER, dh->headers)); - if (GNUNET_NO == mint->connected) - mint_connect (mint); - perform_now (mint->ctx); - return dh; -} - - -/** - * Cancel a deposit permission request. This function cannot be used on a - * request handle if a response is already served for it. - * - * @param the deposit permission request handle - */ -void -TALER_MINT_deposit_submit_cancel (struct TALER_MINT_DepositHandle *deposit) -{ - struct TALER_MINT_Handle *mint = deposit->mint; - - mint_disconnect (mint); - cleanup_deposit (deposit); -} - - -/** - * Initialise this library. This function should be called before using any of - * the following functions. - * - * @return library context - */ -struct TALER_MINT_Context * -TALER_MINT_init () -{ - struct TALER_MINT_Context *ctx; - CURLM *multi; - CURLSH *share; - - if (fail) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "cURL was not initialised properly\n"); - return NULL; - } - if (NULL == (multi = curl_multi_init ())) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot create a cURL multi handle\n"); - return NULL; - } - if (NULL == (share = curl_share_init ())) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot create a cURL share handle\n"); - return NULL; - } - ctx = GNUNET_new (struct TALER_MINT_Context); - ctx->multi = multi; - ctx->share = share; - return ctx; -} - - -/** - * Cleanup library initialisation resources. This function should be called - * after using this library to cleanup the resources occupied during library's - * initialisation. - * - * @param ctx the library context - */ -void -TALER_MINT_cleanup (struct TALER_MINT_Context *ctx) -{ - curl_share_cleanup (ctx->share); - curl_multi_cleanup (ctx->multi); - if (NULL != ctx->perform_task) - { - GNUNET_break (0); /* investigate why this happens */ - GNUNET_SCHEDULER_cancel (ctx->perform_task); - } - GNUNET_free (ctx); -} - - -__attribute__ ((constructor)) -void -TALER_MINT_constructor__ (void) -{ - CURLcode ret; - if (CURLE_OK != (ret = curl_global_init (CURL_GLOBAL_DEFAULT))) - { - CURL_STRERROR (GNUNET_ERROR_TYPE_ERROR, "curl_global_init", ret); - fail = 1; - } -} - -__attribute__ ((destructor)) -void -TALER_MINT_destructor__ (void) -{ - if (fail) - return; - curl_global_cleanup (); -} diff --git a/src/mint/mint_common.c b/src/mint/mint_common.c index 4afbf072b..734085e7b 100644 --- a/src/mint/mint_common.c +++ b/src/mint/mint_common.c @@ -47,11 +47,12 @@ signkeys_iterate_dir_iter (void *cls, struct SignkeysIterateContext *skc = cls; ssize_t nread; - struct TALER_MINT_SignKeyIssue issue; + struct TALER_MINT_SignKeyIssuePriv issue; + nread = GNUNET_DISK_fn_read (filename, &issue, - sizeof (struct TALER_MINT_SignKeyIssue)); - if (nread != sizeof (struct TALER_MINT_SignKeyIssue)) + sizeof (struct TALER_MINT_SignKeyIssuePriv)); + if (nread != sizeof (struct TALER_MINT_SignKeyIssuePriv)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid signkey file: '%s'\n", filename); return GNUNET_OK; @@ -87,7 +88,7 @@ TALER_MINT_signkeys_iterate (const char *mint_base_dir, */ int TALER_MINT_read_denom_key (const char *filename, - struct TALER_MINT_DenomKeyIssue *dki) + struct TALER_MINT_DenomKeyIssuePriv *dki) { uint64_t size; size_t offset; @@ -97,8 +98,8 @@ TALER_MINT_read_denom_key (const char *filename, ret = GNUNET_SYSERR; data = NULL; - offset = sizeof (struct TALER_MINT_DenomKeyIssue) - - offsetof (struct TALER_MINT_DenomKeyIssue, signature); + offset = sizeof (struct TALER_MINT_DenomKeyIssuePriv) + - offsetof (struct TALER_MINT_DenomKeyIssuePriv, issue.signature); if (GNUNET_OK != GNUNET_DISK_file_size (filename, &size, GNUNET_YES, @@ -117,7 +118,7 @@ TALER_MINT_read_denom_key (const char *filename, if (NULL == (priv = TALER_RSA_decode_key (data + offset, size - offset))) goto cleanup; dki->denom_priv = priv; - (void) memcpy (&dki->signature, data, offset); + memcpy (&dki->issue.signature, data, offset); ret = GNUNET_OK; cleanup: @@ -135,7 +136,7 @@ TALER_MINT_read_denom_key (const char *filename, */ int TALER_MINT_write_denom_key (const char *filename, - const struct TALER_MINT_DenomKeyIssue *dki) + const struct TALER_MINT_DenomKeyIssuePriv *dki) { struct TALER_RSA_PrivateKeyBinaryEncoded *priv_enc; struct GNUNET_DISK_FileHandle *fh; @@ -153,10 +154,10 @@ TALER_MINT_write_denom_key (const char *filename, goto cleanup; if (NULL == (priv_enc = TALER_RSA_encode_key (dki->denom_priv))) goto cleanup; - wsize = sizeof (struct TALER_MINT_DenomKeyIssue) - - offsetof (struct TALER_MINT_DenomKeyIssue, signature); + wsize = sizeof (struct TALER_MINT_DenomKeyIssuePriv) + - offsetof (struct TALER_MINT_DenomKeyIssuePriv, issue.signature); if (GNUNET_SYSERR == (wrote = GNUNET_DISK_file_write (fh, - &dki->signature, + &dki->issue.signature, wsize))) goto cleanup; if (wrote != wsize) @@ -183,11 +184,13 @@ denomkeys_iterate_keydir_iter (void *cls, { struct DenomkeysIterateContext *dic = cls; - struct TALER_MINT_DenomKeyIssue issue; + struct TALER_MINT_DenomKeyIssuePriv issue; if (GNUNET_OK != TALER_MINT_read_denom_key (filename, &issue)) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid denomkey file: '%s'\n", filename); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid denomkey file: '%s'\n", + filename); return GNUNET_OK; } return dic->it (dic->it_cls, dic->alias, &issue); diff --git a/src/mint/mint_db.h b/src/mint/mint_db.h index 4f47aac1c..eb7a105cb 100644 --- a/src/mint/mint_db.h +++ b/src/mint/mint_db.h @@ -26,10 +26,35 @@ #include #include #include "taler_util.h" -#include "taler_types.h" #include "taler_rsa.h" +/** + * Public information about a coin. + */ +struct TALER_CoinPublicInfo +{ + /** + * The coin's public key. + */ + struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub; + + /* + * The public key signifying the coin's denomination. + */ + struct TALER_RSA_PublicKeyBinaryEncoded denom_pub; + + /** + * Signature over coin_pub by denom_pub. + */ + struct TALER_RSA_Signature denom_sig; +}; + + + + + + /** * Reserve row. Corresponds to table 'reserves' in * the mint's database. diff --git a/src/mint/taler-mint-httpd.c b/src/mint/taler-mint-httpd.c index 1734e61ef..14dfa657c 100644 --- a/src/mint/taler-mint-httpd.c +++ b/src/mint/taler-mint-httpd.c @@ -29,7 +29,6 @@ #include #include "mint.h" #include "mint_db.h" -#include "taler_types.h" #include "taler_signatures.h" #include "taler_rsa.h" #include "taler_json_lib.h" diff --git a/src/mint/taler-mint-httpd_deposit.c b/src/mint/taler-mint-httpd_deposit.c index 2f6c3bc8f..b8bcc87db 100644 --- a/src/mint/taler-mint-httpd_deposit.c +++ b/src/mint/taler-mint-httpd_deposit.c @@ -28,7 +28,6 @@ #include #include "mint.h" #include "mint_db.h" -#include "taler_types.h" #include "taler_signatures.h" #include "taler_rsa.h" #include "taler_json_lib.h" diff --git a/src/mint/taler-mint-httpd_keys.c b/src/mint/taler-mint-httpd_keys.c index ce8bdf6e0..6d6e9468d 100644 --- a/src/mint/taler-mint-httpd_keys.c +++ b/src/mint/taler-mint-httpd_keys.c @@ -28,7 +28,6 @@ #include #include "mint.h" #include "mint_db.h" -#include "taler_types.h" #include "taler_signatures.h" #include "taler_rsa.h" #include "taler_json_lib.h" @@ -145,7 +144,7 @@ TALER_MINT_conf_duration_provide () static int reload_keys_denom_iter (void *cls, const char *alias, - const struct TALER_MINT_DenomKeyIssue *dki) + const struct TALER_MINT_DenomKeyIssuePriv *dki) { struct MintKeyState *ctx = cls; struct GNUNET_TIME_Absolute stamp_provide; @@ -155,28 +154,30 @@ reload_keys_denom_iter (void *cls, stamp_provide = GNUNET_TIME_absolute_add (ctx->reload_time, TALER_MINT_conf_duration_provide ()); - if (GNUNET_TIME_absolute_ntoh (dki->expire_spend).abs_value_us < ctx->reload_time.abs_value_us) + if (GNUNET_TIME_absolute_ntoh (dki->issue.expire_spend).abs_value_us < ctx->reload_time.abs_value_us) { // this key is expired return GNUNET_OK; } - if (GNUNET_TIME_absolute_ntoh (dki->start).abs_value_us > stamp_provide.abs_value_us) + if (GNUNET_TIME_absolute_ntoh (dki->issue.start).abs_value_us > stamp_provide.abs_value_us) { // we are to early for this key return GNUNET_OK; } - GNUNET_CRYPTO_hash (&dki->denom_pub, sizeof (struct GNUNET_CRYPTO_EddsaPublicKey), &denom_key_hash); + GNUNET_CRYPTO_hash (&dki->issue.denom_pub, + sizeof (struct GNUNET_CRYPTO_EddsaPublicKey), + &denom_key_hash); res = GNUNET_CONTAINER_multihashmap_put (ctx->denomkey_map, &denom_key_hash, - GNUNET_memdup (dki, sizeof (struct TALER_MINT_DenomKeyIssue)), + GNUNET_memdup (dki, sizeof (struct TALER_MINT_DenomKeyIssuePriv)), GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); if (GNUNET_OK != res) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Duplicate denomination key\n"); json_array_append_new (ctx->denom_keys_array, - denom_key_issue_to_json (dki)); + denom_key_issue_to_json (&dki->issue)); return GNUNET_OK; } @@ -193,20 +194,20 @@ reload_keys_denom_iter (void *cls, */ static int reload_keys_sign_iter (void *cls, - const struct TALER_MINT_SignKeyIssue *ski) + const struct TALER_MINT_SignKeyIssuePriv *ski) { struct MintKeyState *ctx = cls; struct GNUNET_TIME_Absolute stamp_provide; stamp_provide = GNUNET_TIME_absolute_add (ctx->reload_time, TALER_MINT_conf_duration_provide (cfg)); - if (GNUNET_TIME_absolute_ntoh (ski->expire).abs_value_us < ctx->reload_time.abs_value_us) + if (GNUNET_TIME_absolute_ntoh (ski->issue.expire).abs_value_us < ctx->reload_time.abs_value_us) { // this key is expired return GNUNET_OK; } - if (GNUNET_TIME_absolute_ntoh (ski->start).abs_value_us > stamp_provide.abs_value_us) + if (GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us > stamp_provide.abs_value_us) { // we are to early for this key return GNUNET_OK; @@ -214,16 +215,16 @@ reload_keys_sign_iter (void *cls, // the signkey is valid for now, check // if it's more recent than the current one! - if (GNUNET_TIME_absolute_ntoh (ctx->current_sign_key_issue.start).abs_value_us > - GNUNET_TIME_absolute_ntoh (ski->start).abs_value_us) + if (GNUNET_TIME_absolute_ntoh (ctx->current_sign_key_issue.issue.start).abs_value_us > + GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us) ctx->current_sign_key_issue = *ski; ctx->next_reload = GNUNET_TIME_absolute_min (ctx->next_reload, - GNUNET_TIME_absolute_ntoh (ski->expire)); + GNUNET_TIME_absolute_ntoh (ski->issue.expire)); json_array_append_new (ctx->sign_keys_array, - sign_key_issue_to_json (ski)); + sign_key_issue_to_json (&ski->issue)); return GNUNET_OK; } @@ -334,14 +335,16 @@ TALER_MINT_key_state_acquire (void) * @return the denomination key issue, * or NULL if denom_pub could not be found */ -struct TALER_MINT_DenomKeyIssue * +struct TALER_MINT_DenomKeyIssuePriv * TALER_MINT_get_denom_key (const struct MintKeyState *key_state, const struct TALER_RSA_PublicKeyBinaryEncoded *denom_pub) { - struct TALER_MINT_DenomKeyIssue *issue; + struct TALER_MINT_DenomKeyIssuePriv *issue; struct GNUNET_HashCode hash; - GNUNET_CRYPTO_hash (denom_pub, sizeof (struct TALER_RSA_PublicKeyBinaryEncoded), &hash); + GNUNET_CRYPTO_hash (denom_pub, + sizeof (struct TALER_RSA_PublicKeyBinaryEncoded), + &hash); issue = GNUNET_CONTAINER_multihashmap_get (key_state->denomkey_map, &hash); return issue; } @@ -361,7 +364,7 @@ int TALER_MINT_test_coin_valid (const struct MintKeyState *key_state, struct TALER_CoinPublicInfo *coin_public_info) { - struct TALER_MINT_DenomKeyIssue *dki; + struct TALER_MINT_DenomKeyIssuePriv *dki; dki = TALER_MINT_get_denom_key (key_state, &coin_public_info->denom_pub); if (NULL == dki) @@ -369,7 +372,7 @@ TALER_MINT_test_coin_valid (const struct MintKeyState *key_state, if (GNUNET_OK != TALER_RSA_verify (&coin_public_info->coin_pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey), &coin_public_info->denom_sig, - &dki->denom_pub)) + &dki->issue.denom_pub)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "coin signature is invalid\n"); diff --git a/src/mint/taler-mint-httpd_keys.h b/src/mint/taler-mint-httpd_keys.h index 640a9c916..4fd3d0bdd 100644 --- a/src/mint/taler-mint-httpd_keys.h +++ b/src/mint/taler-mint-httpd_keys.h @@ -62,7 +62,7 @@ struct MintKeyState /** * Mint signing key that should be used currently. */ - struct TALER_MINT_SignKeyIssue current_sign_key_issue; + struct TALER_MINT_SignKeyIssuePriv current_sign_key_issue; /** * Cached JSON text that the mint will send for @@ -105,7 +105,7 @@ TALER_MINT_key_state_acquire (void); * @return the denomination key issue, * or NULL if denom_pub could not be found */ -struct TALER_MINT_DenomKeyIssue * +struct TALER_MINT_DenomKeyIssuePriv * TALER_MINT_get_denom_key (const struct MintKeyState *key_state, const struct TALER_RSA_PublicKeyBinaryEncoded *denom_pub); diff --git a/src/mint/taler-mint-httpd_refresh.c b/src/mint/taler-mint-httpd_refresh.c index 5a9cf1eac..888e7de3b 100644 --- a/src/mint/taler-mint-httpd_refresh.c +++ b/src/mint/taler-mint-httpd_refresh.c @@ -28,7 +28,6 @@ #include #include "mint.h" #include "mint_db.h" -#include "taler_types.h" #include "taler_signatures.h" #include "taler_rsa.h" #include "taler_json_lib.h" @@ -152,10 +151,11 @@ refresh_accept_denoms (struct MHD_Connection *connection, if (GNUNET_OK != res) return res; - dki = TALER_MINT_get_denom_key (key_state, &denom_pub); + dki = &(TALER_MINT_get_denom_key (key_state, &denom_pub)->issue); GNUNET_CRYPTO_hash_context_read (hash_context, - &denom_pub, sizeof (struct TALER_RSA_PublicKeyBinaryEncoded)); + &denom_pub, + sizeof (struct TALER_RSA_PublicKeyBinaryEncoded)); cost = TALER_amount_add (TALER_amount_ntoh (dki->value), TALER_amount_ntoh (dki->fee_withdraw)); @@ -353,7 +353,7 @@ refresh_accept_melts (struct MHD_Connection *connection, GNUNET_CRYPTO_hash_context_read (hash_context, &coin_public_info.coin_pub, sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); - dki = TALER_MINT_get_denom_key (key_state, &coin_public_info.denom_pub); + dki = &(TALER_MINT_get_denom_key (key_state, &coin_public_info.denom_pub)->issue); if (NULL == dki) return (MHD_YES == request_send_json_pack (connection, MHD_HTTP_NOT_FOUND, @@ -1344,7 +1344,7 @@ TALER_MINT_handler_refresh_reveal (struct RequestHandler *rh, { struct RefreshCommitCoin commit_coin; struct TALER_RSA_PublicKeyBinaryEncoded denom_pub; - struct TALER_MINT_DenomKeyIssue *dki; + struct TALER_MINT_DenomKeyIssuePriv *dki; struct TALER_RSA_Signature ev_sig; res = TALER_MINT_DB_get_refresh_commit_coin (db_conn, diff --git a/src/mint/taler-mint-httpd_withdraw.c b/src/mint/taler-mint-httpd_withdraw.c index 0fd418540..22024e80e 100644 --- a/src/mint/taler-mint-httpd_withdraw.c +++ b/src/mint/taler-mint-httpd_withdraw.c @@ -28,7 +28,6 @@ #include #include "mint.h" #include "mint_db.h" -#include "taler_types.h" #include "taler_signatures.h" #include "taler_rsa.h" #include "taler_json_lib.h" @@ -79,7 +78,7 @@ static void sign_reserve (struct Reserve *reserve, struct MintKeyState *key_state) { - reserve->status_sign_pub = key_state->current_sign_key_issue.signkey_pub; + reserve->status_sign_pub = key_state->current_sign_key_issue.issue.signkey_pub; reserve->status_sig_purpose.purpose = htonl (TALER_SIGNATURE_RESERVE_STATUS); reserve->status_sig_purpose.size = htonl (sizeof (struct Reserve) - offsetof (struct Reserve, status_sig_purpose)); @@ -151,7 +150,7 @@ TALER_MINT_handler_withdraw_status (struct RequestHandler *rh, return MHD_NO; } key_state = TALER_MINT_key_state_acquire (); - if (0 != memcmp (&key_state->current_sign_key_issue.signkey_pub, + if (0 != memcmp (&key_state->current_sign_key_issue.issue.signkey_pub, &reserve.status_sign_pub, sizeof (struct GNUNET_CRYPTO_EddsaPublicKey))) { @@ -230,7 +229,7 @@ TALER_MINT_handler_withdraw_sign (struct RequestHandler *rh, struct Reserve reserve; struct MintKeyState *key_state; struct CollectableBlindcoin collectable; - struct TALER_MINT_DenomKeyIssue *dki; + struct TALER_MINT_DenomKeyIssuePriv *dki; struct TALER_RSA_Signature ev_sig; struct TALER_Amount amount_required; @@ -342,16 +341,16 @@ TALER_MINT_handler_withdraw_sign (struct RequestHandler *rh, key_state = TALER_MINT_key_state_acquire (); dki = TALER_MINT_get_denom_key (key_state, - &wsrd.denomination_pub); + &wsrd.denomination_pub); TALER_MINT_key_state_release (key_state); if (NULL == dki) return request_send_json_pack (connection, MHD_HTTP_NOT_FOUND, "{s:s}", "error", "Denomination not found"); - amount_required = TALER_amount_ntoh (dki->value); + amount_required = TALER_amount_ntoh (dki->issue.value); amount_required = TALER_amount_add (amount_required, - TALER_amount_ntoh (dki->fee_withdraw)); + TALER_amount_ntoh (dki->issue.fee_withdraw)); if (0 < TALER_amount_cmp (amount_required, TALER_amount_ntoh (reserve.balance))) diff --git a/src/mint/taler-mint-keycheck.c b/src/mint/taler-mint-keycheck.c index c6186859c..419baf501 100644 --- a/src/mint/taler-mint-keycheck.c +++ b/src/mint/taler-mint-keycheck.c @@ -32,19 +32,20 @@ static struct GNUNET_CONFIGURATION_Handle *kcfg; static int -signkeys_iter (void *cls, const struct TALER_MINT_SignKeyIssue *ski) +signkeys_iter (void *cls, const struct TALER_MINT_SignKeyIssuePriv *ski) { struct GNUNET_TIME_Absolute start; printf ("iterating over key for start time %s\n", - GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (ski->start))); + GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (ski->issue.start))); - start = GNUNET_TIME_absolute_ntoh (ski->start); + start = GNUNET_TIME_absolute_ntoh (ski->issue.start); - if (ntohl (ski->purpose.size) != + if (ntohl (ski->issue.purpose.size) != (sizeof (struct TALER_MINT_SignKeyIssue) - offsetof (struct TALER_MINT_SignKeyIssue, purpose))) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Signkey with start %s has invalid purpose field (timestamp: %llu)\n", + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Signkey with start %s has invalid purpose field (timestamp: %llu)\n", GNUNET_STRINGS_absolute_time_to_string (start), (long long) start.abs_value_us); return GNUNET_SYSERR; @@ -52,15 +53,16 @@ signkeys_iter (void *cls, const struct TALER_MINT_SignKeyIssue *ski) if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNKEY, - &ski->purpose, - &ski->signature, - &ski->master_pub)) + &ski->issue.purpose, + &ski->issue.signature, + &ski->issue.master_pub)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Signkey with start %s has invalid signature (timestamp: %llu)\n", GNUNET_STRINGS_absolute_time_to_string (start), (long long) start.abs_value_us); return GNUNET_SYSERR; } + /* FIXME: what about private key matching the public key? */ printf ("key valid\n"); return GNUNET_OK; } @@ -75,16 +77,17 @@ mint_signkeys_check () } -static int denomkeys_iter (void *cls, - const char *alias, - const struct TALER_MINT_DenomKeyIssue *dki) +static int +denomkeys_iter (void *cls, + const char *alias, + const struct TALER_MINT_DenomKeyIssuePriv *dki) { struct GNUNET_TIME_Absolute start; - start = GNUNET_TIME_absolute_ntoh (dki->start); + start = GNUNET_TIME_absolute_ntoh (dki->issue.start); - if (ntohl (dki->purpose.size) != - (sizeof (struct TALER_MINT_DenomKeyIssue) - offsetof (struct TALER_MINT_DenomKeyIssue, purpose))) + if (ntohl (dki->issue.purpose.size) != + (sizeof (struct TALER_MINT_DenomKeyIssuePriv) - offsetof (struct TALER_MINT_DenomKeyIssuePriv, issue.purpose))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Denomkey for '%s' with start %s has invalid purpose field (timestamp: %llu)\n", alias, @@ -93,12 +96,14 @@ static int denomkeys_iter (void *cls, return GNUNET_SYSERR; } - if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOM, - &dki->purpose, - &dki->signature, - &dki->master)) + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOM, + &dki->issue.purpose, + &dki->issue.signature, + &dki->issue.master)) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Denomkey for '%s'with start %s has invalid signature (timestamp: %llu)\n", + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Denomkey for '%s'with start %s has invalid signature (timestamp: %llu)\n", alias, GNUNET_STRINGS_absolute_time_to_string (start), (long long) start.abs_value_us); @@ -113,7 +118,8 @@ static int denomkeys_iter (void *cls, static int mint_denomkeys_check () { - if (0 > TALER_MINT_denomkeys_iterate (mintdir, denomkeys_iter, NULL)) + if (0 > TALER_MINT_denomkeys_iterate (mintdir, + &denomkeys_iter, NULL)) return GNUNET_NO; return GNUNET_OK; } @@ -148,11 +154,11 @@ main (int argc, char *const *argv) GNUNET_assert (GNUNET_OK == GNUNET_log_setup ("taler-mint-keycheck", "WARNING", NULL)); - if (GNUNET_GETOPT_run ("taler-mint-keyup", options, argc, argv) < 0) + if (GNUNET_GETOPT_run ("taler-mint-keyup", options, argc, argv) < 0) return 1; if (NULL == mintdir) { - fprintf (stderr, "mint directory not given\n"); + fprintf (stderr, "mint directory not given\n"); return 1; } diff --git a/src/mint/taler-mint-keyup.c b/src/mint/taler-mint-keyup.c index 8a1a77882..263618ade 100644 --- a/src/mint/taler-mint-keyup.c +++ b/src/mint/taler-mint-keyup.c @@ -292,26 +292,27 @@ get_anchor (const char *dir, } static void -create_signkey_issue (struct GNUNET_TIME_Absolute start, - struct GNUNET_TIME_Relative duration, - struct TALER_MINT_SignKeyIssue *issue) +create_signkey_issue_priv (struct GNUNET_TIME_Absolute start, + struct GNUNET_TIME_Relative duration, + struct TALER_MINT_SignKeyIssuePriv *pi) { struct GNUNET_CRYPTO_EddsaPrivateKey *priv; + struct TALER_MINT_SignKeyIssue *issue = &pi->issue; priv = GNUNET_CRYPTO_eddsa_key_create (); GNUNET_assert (NULL != priv); - issue->signkey_priv = *priv; + pi->signkey_priv = *priv; GNUNET_free (priv); issue->master_pub = *master_pub; issue->start = GNUNET_TIME_absolute_hton (start); issue->expire = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (start, duration)); - GNUNET_CRYPTO_eddsa_key_get_public (&issue->signkey_priv, &issue->signkey_pub); + GNUNET_CRYPTO_eddsa_key_get_public (&pi->signkey_priv, &issue->signkey_pub); issue->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNKEY); issue->purpose.size = htonl (sizeof (struct TALER_MINT_SignKeyIssue) - offsetof (struct TALER_MINT_SignKeyIssue, purpose)); - if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (master_priv, &issue->purpose, &issue->signature)) + if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (master_priv, &issue->purpose, &issue->signature)) { GNUNET_abort (); } @@ -354,10 +355,10 @@ mint_keys_update_signkeys () skf = get_signkey_file (anchor); if (GNUNET_YES != GNUNET_DISK_file_test (skf)) { - struct TALER_MINT_SignKeyIssue signkey_issue; + struct TALER_MINT_SignKeyIssuePriv signkey_issue; ssize_t nwrite; printf ("Generating signing key for %s.\n", GNUNET_STRINGS_absolute_time_to_string (anchor)); - create_signkey_issue (anchor, signkey_duration, &signkey_issue); + create_signkey_issue_priv (anchor, signkey_duration, &signkey_issue); nwrite = GNUNET_DISK_fn_write (skf, &signkey_issue, sizeof (struct TALER_MINT_SignKeyIssue), (GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_USER_READ)); if (nwrite != sizeof (struct TALER_MINT_SignKeyIssue)) @@ -430,28 +431,32 @@ get_cointype_params (const char *ct, struct CoinTypeParams *params) static void -create_denomkey_issue (struct CoinTypeParams *params, struct TALER_MINT_DenomKeyIssue *dki) +create_denomkey_issue (struct CoinTypeParams *params, + struct TALER_MINT_DenomKeyIssuePriv *dki) { GNUNET_assert (NULL != (dki->denom_priv = TALER_RSA_key_create ())); - TALER_RSA_key_get_public (dki->denom_priv, &dki->denom_pub); - dki->master = *master_pub; - dki->start = GNUNET_TIME_absolute_hton (params->anchor); - dki->expire_withdraw = - GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor, + TALER_RSA_key_get_public (dki->denom_priv, &dki->issue.denom_pub); + dki->issue.master = *master_pub; + dki->issue.start = GNUNET_TIME_absolute_hton (params->anchor); + dki->issue.expire_withdraw = + GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor, params->duration_withdraw)); - dki->expire_spend = - GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor, + dki->issue.expire_spend = + GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor, params->duration_spend)); - dki->value = TALER_amount_hton (params->value); - dki->fee_withdraw = TALER_amount_hton (params->fee_withdraw); - dki->fee_deposit = TALER_amount_hton (params->fee_deposit); - dki->fee_refresh = TALER_amount_hton (params->fee_refresh); - - dki->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOM); - dki->purpose.size = htonl (sizeof (struct TALER_MINT_DenomKeyIssue) - offsetof (struct TALER_MINT_DenomKeyIssue, purpose)); - - if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (master_priv, &dki->purpose, &dki->signature)) - { + dki->issue.value = TALER_amount_hton (params->value); + dki->issue.fee_withdraw = TALER_amount_hton (params->fee_withdraw); + dki->issue.fee_deposit = TALER_amount_hton (params->fee_deposit); + dki->issue.fee_refresh = TALER_amount_hton (params->fee_refresh); + + dki->issue.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOM); + dki->issue.purpose.size = htonl (sizeof (struct TALER_MINT_DenomKeyIssuePriv) - offsetof (struct TALER_MINT_DenomKeyIssuePriv, issue.purpose)); + + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_sign (master_priv, + &dki->issue.purpose, + &dki->issue.signature)) + { GNUNET_abort (); } } @@ -484,7 +489,7 @@ mint_keys_update_cointype (const char *coin_alias) if (GNUNET_YES != GNUNET_DISK_file_test (dkf)) { - struct TALER_MINT_DenomKeyIssue denomkey_issue; + struct TALER_MINT_DenomKeyIssuePriv denomkey_issue; int ret; printf ("Generating denomination key for type '%s', start %s.\n", coin_alias, GNUNET_STRINGS_absolute_time_to_string (p.anchor)); @@ -589,11 +594,11 @@ main (int argc, char *const *argv) GNUNET_assert (GNUNET_OK == GNUNET_log_setup ("taler-mint-keyup", "WARNING", NULL)); - if (GNUNET_GETOPT_run ("taler-mint-keyup", options, argc, argv) < 0) + if (GNUNET_GETOPT_run ("taler-mint-keyup", options, argc, argv) < 0) return 1; if (NULL == mintdir) { - fprintf (stderr, "mint directory not given\n"); + fprintf (stderr, "mint directory not given\n"); return 1; } @@ -601,7 +606,7 @@ main (int argc, char *const *argv) { if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_absolute (pretend_time_str, &now)) { - fprintf (stderr, "timestamp invalid\n"); + fprintf (stderr, "timestamp invalid\n"); return 1; } } diff --git a/src/mint/test_mint_api.c b/src/mint/test_mint_api.c deleted file mode 100644 index 965d607f5..000000000 --- a/src/mint/test_mint_api.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - This file is part of TALER - (C) 2014 Christian Grothoff (and other contributing authors) - - 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 mint/test_mint_api.c - * @brief testcase to test mint's HTTP API interface - * @author Sree Harsha Totakura - */ - -#include "platform.h" -#include "taler_util.h" -#include "taler_mint_service.h" - -struct TALER_MINT_Context *ctx; - -struct TALER_MINT_Handle *mint; - -struct TALER_MINT_KeysGetHandle *dkey_get; - -struct TALER_MINT_DepositHandle *dh; - -static GNUNET_SCHEDULER_TaskIdentifier shutdown_task; - -static int result; - - -static void -do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - shutdown_task = GNUNET_SCHEDULER_NO_TASK; - if (NULL != dkey_get) - TALER_MINT_keys_get_cancel (dkey_get); - dkey_get = NULL; - if (NULL != dh) - TALER_MINT_deposit_submit_cancel (dh); - dh = NULL; - TALER_MINT_disconnect (mint); - mint = NULL; - TALER_MINT_cleanup (ctx); - ctx = NULL; -} - - -/** - * Callbacks of this type are used to serve the result of submitting a deposit - * permission object to a mint - * - * @param cls closure - * @param status 1 for successful deposit, 2 for retry, 0 for failure - * @param obj the received JSON object; can be NULL if it cannot be constructed - * from the reply - * @param emsg in case of unsuccessful deposit, this contains a human readable - * explanation. - */ -static void -deposit_status (void *cls, - int status, - json_t *obj, - char *emsg) -{ - char *json_enc; - - dh = NULL; - json_enc = NULL; - if (NULL != obj) - { - json_enc = json_dumps (obj, JSON_INDENT(2)); - fprintf (stderr, "%s", json_enc); - } - if (1 == status) - result = GNUNET_OK; - else - GNUNET_break (0); - if (NULL != emsg) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Deposit failed: %s\n", emsg); - GNUNET_SCHEDULER_shutdown (); -} -/** - * Functions of this type are called to signal completion of an asynchronous call. - * - * @param cls closure - * @param emsg if the asynchronous call could not be completed due to an error, - * this parameter contains a human readable error message - */ -static void -cont (void *cls, const char *emsg) -{ - json_t *dp; - char rnd_32[32]; - char rnd_64[64]; - char *enc_32; - char *enc_64; - - GNUNET_assert (NULL == cls); - dkey_get = NULL; - if (NULL != emsg) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg); - - enc_32 = TALER_data_to_string_alloc (rnd_32, sizeof (rnd_32)); - enc_64 = TALER_data_to_string_alloc (rnd_64, sizeof (rnd_64)); - dp = json_pack ("{s:s s:o s:s s:s s:s s:s s:s s:s s:s s:s}", - "type", "DIRECT_DEPOSIT", - "wire", json_pack ("{s:s}", "type", "SEPA"), - "C", enc_32, - "K", enc_32, - "ubsig", enc_64, - "M", enc_32, - "H_a", enc_64, - "H_wire", enc_64, - "csig", enc_64, - "m", "B1C5GP2RB1C5G"); - GNUNET_free (enc_32); - GNUNET_free (enc_64); - dh = TALER_MINT_deposit_submit_json (mint, - deposit_status, - NULL, - dp); - json_decref (dp); -} - - -/** - * Functions of this type are called to provide the retrieved signing and - * denomination keys of the mint. No TALER_MINT_*() functions should be called - * in this callback. - * - * @param cls closure passed to TALER_MINT_keys_get() - * @param sign_keys NULL-terminated array of pointers to the mint's signing - * keys. NULL if no signing keys are retrieved. - * @param denom_keys NULL-terminated array of pointers to the mint's - * denomination keys; will be NULL if no signing keys are retrieved. - */ -static void -read_denom_key (void *cls, - struct TALER_MINT_SigningPublicKey **sign_keys, - struct TALER_MINT_DenomPublicKey **denom_keys) -{ - unsigned int cnt; - GNUNET_assert (NULL == cls); -#define ERR(cond) do { if(!(cond)) break; GNUNET_break (0); return; } while (0) - ERR (NULL == sign_keys); - ERR (NULL == denom_keys); - for (cnt = 0; NULL != sign_keys[cnt]; cnt++) - GNUNET_free (sign_keys[cnt]); - ERR (0 == cnt); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read %u signing keys\n", cnt); - GNUNET_free (sign_keys); - for (cnt = 0; NULL != denom_keys[cnt]; cnt++) - GNUNET_free (denom_keys[cnt]); - ERR (0 == cnt); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read %u denomination keys\n", cnt); - GNUNET_free (denom_keys); -#undef ERR - return; -} - - -/** - * Main function that will be run by the scheduler. - * - * @param cls closure - * @param args remaining command-line arguments - * @param cfgfile name of the configuration file used (for saving, can be NULL!) - * @param config configuration - */ -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *config) -{ - ctx = TALER_MINT_init (); - mint = TALER_MINT_connect (ctx, "localhost", 4241, NULL); - GNUNET_assert (NULL != mint); - dkey_get = TALER_MINT_keys_get (mint, - &read_denom_key, NULL, - &cont, NULL); - GNUNET_assert (NULL != dkey_get); - shutdown_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 5), - &do_shutdown, NULL); -} - -int -main (int argc, char * const *argv) -{ - static struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - - result = GNUNET_SYSERR; - if (GNUNET_OK != - GNUNET_PROGRAM_run (argc, argv, "test-mint-api", - gettext_noop - ("Testcase to test mint's HTTP API interface"), - options, &run, NULL)) - return 3; - return (GNUNET_OK == result) ? 0 : 1; -} diff --git a/src/mint/test_mint_common.c b/src/mint/test_mint_common.c index b7cad3ea4..d4bbb6c46 100644 --- a/src/mint/test_mint_common.c +++ b/src/mint/test_mint_common.c @@ -33,9 +33,9 @@ int main (int argc, const char *const argv[]) { - struct TALER_MINT_DenomKeyIssue dki; + struct TALER_MINT_DenomKeyIssuePriv dki; struct TALER_RSA_PrivateKeyBinaryEncoded *enc; - struct TALER_MINT_DenomKeyIssue dki_read; + struct TALER_MINT_DenomKeyIssuePriv dki_read; struct TALER_RSA_PrivateKeyBinaryEncoded *enc_read; char *tmpfile; @@ -48,7 +48,7 @@ main (int argc, const char *const argv[]) dki.denom_priv = NULL; dki_read.denom_priv = NULL; GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, - &dki.signature, + &dki.issue.signature, sizeof (dki) - offsetof (struct TALER_MINT_DenomKeyIssue, signature)); dki.denom_priv = TALER_RSA_key_create (); @@ -61,8 +61,8 @@ main (int argc, const char *const argv[]) EXITIF (0 != memcmp (enc, enc_read, ntohs(enc->len))); - EXITIF (0 != memcmp (&dki.signature, - &dki_read.signature, + EXITIF (0 != memcmp (&dki.issue.signature, + &dki_read.issue.signature, sizeof (dki) - offsetof (struct TALER_MINT_DenomKeyIssue, signature))); ret = 0; diff --git a/src/util/Makefile.am b/src/util/Makefile.am index b74e90da9..480b07a70 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -22,17 +22,11 @@ libtalerutil_la_LDFLAGS = \ -export-dynamic -no-undefined check_PROGRAMS = \ - test-hash-context \ test-rsa TESTS = \ $(check_PROGRAMS) -test_hash_context_SOURCES = test_hash_context.c -test_hash_context_CPPFLAGS = $(AM_CPPFLAGS) $(LIBGCRYPT_CFLAGS) -test_hash_context_LDADD = libtalerutil.la \ - -lgnunetutil $(LIBGCRYPT_LIBS) - test_rsa_SOURCES = test_rsa.c test_rsa_LDADD = libtalerutil.la \ -lgnunetutil $(LIBGCRYPT_LIBS) diff --git a/src/util/test_hash_context.c b/src/util/test_hash_context.c deleted file mode 100644 index 4b94e7ffa..000000000 --- a/src/util/test_hash_context.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - This file is part of TALER - (C) 2014 Christian Grothoff (and other contributing authors) - - 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 util/test_hash_context.c - * @brief test case for incremental hashing - * @author Florian Dold - */ - -#include "platform.h" -#include "taler_util.h" -#include - -#define LEN 1234 - -int main() -{ - char data[1234]; - struct GNUNET_HashCode hc1; - struct GNUNET_HashCode hc2; - struct GNUNET_HashContext hctx; - - memset (data, 42, LEN); - - GNUNET_CRYPTO_hash_context_start (&hctx); - GNUNET_CRYPTO_hash_context_read (&hctx, data, LEN); - GNUNET_CRYPTO_hash_context_finish (&hctx, &hc1); - - GNUNET_CRYPTO_hash (data, LEN, &hc2); - - if (0 == memcmp (&hc1, &hc2, sizeof (struct GNUNET_HashCode))) - return 0; - return 1; -} - -- cgit v1.2.3