summaryrefslogtreecommitdiff
path: root/src/mint
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-01-19 21:53:23 +0100
committerChristian Grothoff <christian@grothoff.org>2015-01-19 21:53:23 +0100
commited51946442e5e22a7dea68f14ff2bf563503c755 (patch)
treebcdca621df102a52337ff7348dc262be43a48514 /src/mint
parentf9347d23953f771689d339b544370d3f9fdd97ba (diff)
downloadexchange-ed51946442e5e22a7dea68f14ff2bf563503c755.tar.gz
exchange-ed51946442e5e22a7dea68f14ff2bf563503c755.tar.bz2
exchange-ed51946442e5e22a7dea68f14ff2bf563503c755.zip
more code refactoring to separate parsing, db and response generation nicely
Diffstat (limited to 'src/mint')
-rw-r--r--src/mint/mint.h192
-rw-r--r--src/mint/mint_db.h143
-rw-r--r--src/mint/taler-mint-httpd.c2
-rw-r--r--src/mint/taler-mint-httpd_db.c278
-rw-r--r--src/mint/taler-mint-httpd_db.h66
-rw-r--r--src/mint/taler-mint-httpd_keys.c2
-rw-r--r--src/mint/taler-mint-httpd_keys.h2
-rw-r--r--src/mint/taler-mint-httpd_refresh.c18
-rw-r--r--src/mint/taler-mint-httpd_responses.c62
-rw-r--r--src/mint/taler-mint-httpd_responses.h25
-rw-r--r--src/mint/taler-mint-httpd_withdraw.c337
11 files changed, 604 insertions, 523 deletions
diff --git a/src/mint/mint.h b/src/mint/mint.h
index 644a9d292..39dda7d5f 100644
--- a/src/mint/mint.h
+++ b/src/mint/mint.h
@@ -13,14 +13,15 @@
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
*/
-
/**
- * @file taler_mint.h
+ * @file mint.h
* @brief Common functionality for the mint
* @author Florian Dold
* @author Benedikt Mueller
+ *
+ * TODO:
+ * - revisit and document `struct Deposit` members.
*/
-
#ifndef _MINT_H
#define _MINT_H
@@ -55,11 +56,195 @@ struct TALER_MINT_DenomKeyIssuePriv
* not available.
*/
struct TALER_RSA_PrivateKey *denom_priv;
+
struct TALER_MINT_DenomKeyIssue issue;
};
+/**
+ * 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;
+};
+
+
+
+
+
+
+
+struct CollectableBlindcoin
+{
+ struct TALER_RSA_BlindedSignaturePurpose ev;
+ struct TALER_RSA_Signature ev_sig;
+ struct TALER_RSA_PublicKeyBinaryEncoded denom_pub;
+ struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
+ struct GNUNET_CRYPTO_EddsaSignature reserve_sig;
+};
+
+
+struct RefreshSession
+{
+ int has_commit_sig;
+ struct GNUNET_CRYPTO_EddsaSignature commit_sig;
+ struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
+ uint16_t num_oldcoins;
+ uint16_t num_newcoins;
+ uint16_t kappa;
+ uint16_t noreveal_index;
+ uint8_t reveal_ok;
+};
+
+
+#define TALER_REFRESH_SHARED_SECRET_LENGTH (sizeof (struct GNUNET_HashCode))
+#define TALER_REFRESH_LINK_LENGTH (sizeof (struct LinkData))
+
+struct RefreshCommitLink
+{
+ struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
+ struct GNUNET_CRYPTO_EcdsaPublicKey transfer_pub;
+ uint16_t cnc_index;
+ uint16_t oldcoin_index;
+ char shared_secret_enc[sizeof (struct GNUNET_HashCode)];
+};
+
+struct LinkData
+{
+ struct GNUNET_CRYPTO_EcdsaPrivateKey coin_priv;
+ struct TALER_RSA_BlindingKeyBinaryEncoded bkey_enc;
+};
+
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+struct SharedSecretEnc
+{
+ char data[TALER_REFRESH_SHARED_SECRET_LENGTH];
+};
+
+
+struct LinkDataEnc
+{
+ char data[sizeof (struct LinkData)];
+};
+
+GNUNET_NETWORK_STRUCT_END
+
+struct RefreshCommitCoin
+{
+ struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
+ struct TALER_RSA_BlindedSignaturePurpose coin_ev;
+ uint16_t cnc_index;
+ uint16_t newcoin_index;
+ char link_enc[sizeof (struct LinkData)];
+};
+
+
+struct KnownCoin
+{
+ struct TALER_CoinPublicInfo public_info;
+ struct TALER_Amount expended_balance;
+ int is_refreshed;
+ /**
+ * Refreshing session, only valid if
+ * is_refreshed==1.
+ */
+ struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub;
+};
+
+
+/**
+ * Specification for a /deposit operation.
+ */
+struct Deposit
+{
+ /* FIXME: should be TALER_CoinPublicInfo */
+ struct GNUNET_CRYPTO_EddsaPublicKey coin_pub;
+
+ struct TALER_RSA_PublicKeyBinaryEncoded denom_pub;
+
+ struct TALER_RSA_Signature coin_sig;
+
+ struct TALER_RSA_Signature ubsig;
+
+ /**
+ * Type of the deposit (also purpose of the signature). Either
+ * #TALER_SIGNATURE_DEPOSIT or #TALER_SIGNATURE_INCREMENTAL_DEPOSIT.
+ */
+ struct TALER_RSA_SignaturePurpose purpose;
+
+ uint64_t transaction_id;
+
+ struct TALER_AmountNBO amount;
+
+ struct GNUNET_CRYPTO_EddsaPublicKey merchant_pub;
+
+ struct GNUNET_HashCode h_contract;
+
+ struct GNUNET_HashCode h_wire;
+
+ /* TODO: uint16_t wire_size */
+ char wire[]; /* string encoded wire JSON object */
+
+};
+
+
+/**
+ * Reserve row. Corresponds to table 'reserves' in the mint's
+ * database. FIXME: not sure this is how we want to store this
+ * information. Also, may currently used in different ways in the
+ * code, so we might need to separate the struct into different ones
+ * depending on the context it is used in.
+ */
+struct Reserve
+{
+ /**
+ * Signature over the purse.
+ * Only valid if (blind_session_missing==GNUNET_YES).
+ */
+ struct GNUNET_CRYPTO_EddsaSignature status_sig;
+ /**
+ * Signature with purpose TALER_SIGNATURE_PURSE.
+ * Only valid if (blind_session_missing==GNUNET_YES).
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose status_sig_purpose;
+ /**
+ * Signing key used to sign the purse.
+ * Only valid if (blind_session_missing==GNUNET_YES).
+ */
+ struct GNUNET_CRYPTO_EddsaPublicKey status_sign_pub;
+ /**
+ * Withdraw public key, identifies the purse.
+ * Only the customer knows the corresponding private key.
+ */
+ struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
+ /**
+ * Remaining balance in the purse.
+ */
+ struct TALER_AmountNBO balance;
+
+ /**
+ * Expiration date for the purse.
+ */
+ struct GNUNET_TIME_AbsoluteNBO expiration;
+};
+
@@ -153,4 +338,3 @@ TALER_TALER_DB_extract_amount_nbo (PGresult *result, unsigned int row,
int indices[3], struct TALER_AmountNBO *denom_nbo);
#endif /* _MINT_H */
-
diff --git a/src/mint/mint_db.h b/src/mint/mint_db.h
index 5fab7c02a..d5a74a45d 100644
--- a/src/mint/mint_db.h
+++ b/src/mint/mint_db.h
@@ -29,149 +29,8 @@
#include "taler_util.h"
#include "taler_rsa.h"
#include "taler-mint-httpd_db.h"
+#include "mint.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.
- */
-struct Reserve
-{
- /**
- * Signature over the purse.
- * Only valid if (blind_session_missing==GNUNET_YES).
- */
- struct GNUNET_CRYPTO_EddsaSignature status_sig;
- /**
- * Signature with purpose TALER_SIGNATURE_PURSE.
- * Only valid if (blind_session_missing==GNUNET_YES).
- */
- struct GNUNET_CRYPTO_EccSignaturePurpose status_sig_purpose;
- /**
- * Signing key used to sign the purse.
- * Only valid if (blind_session_missing==GNUNET_YES).
- */
- struct GNUNET_CRYPTO_EddsaPublicKey status_sign_pub;
- /**
- * Withdraw public key, identifies the purse.
- * Only the customer knows the corresponding private key.
- */
- struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
- /**
- * Remaining balance in the purse.
- */
- struct TALER_AmountNBO balance;
-
- /**
- * Expiration date for the purse.
- */
- struct GNUNET_TIME_AbsoluteNBO expiration;
-};
-
-
-struct CollectableBlindcoin
-{
- struct TALER_RSA_BlindedSignaturePurpose ev;
- struct TALER_RSA_Signature ev_sig;
- struct TALER_RSA_PublicKeyBinaryEncoded denom_pub;
- struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
- struct GNUNET_CRYPTO_EddsaSignature reserve_sig;
-};
-
-
-struct RefreshSession
-{
- int has_commit_sig;
- struct GNUNET_CRYPTO_EddsaSignature commit_sig;
- struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
- uint16_t num_oldcoins;
- uint16_t num_newcoins;
- uint16_t kappa;
- uint16_t noreveal_index;
- uint8_t reveal_ok;
-};
-
-
-#define TALER_REFRESH_SHARED_SECRET_LENGTH (sizeof (struct GNUNET_HashCode))
-#define TALER_REFRESH_LINK_LENGTH (sizeof (struct LinkData))
-
-struct RefreshCommitLink
-{
- struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
- struct GNUNET_CRYPTO_EcdsaPublicKey transfer_pub;
- uint16_t cnc_index;
- uint16_t oldcoin_index;
- char shared_secret_enc[sizeof (struct GNUNET_HashCode)];
-};
-
-struct LinkData
-{
- struct GNUNET_CRYPTO_EcdsaPrivateKey coin_priv;
- struct TALER_RSA_BlindingKeyBinaryEncoded bkey_enc;
-};
-
-
-GNUNET_NETWORK_STRUCT_BEGIN
-
-struct SharedSecretEnc
-{
- char data[TALER_REFRESH_SHARED_SECRET_LENGTH];
-};
-
-
-struct LinkDataEnc
-{
- char data[sizeof (struct LinkData)];
-};
-
-GNUNET_NETWORK_STRUCT_END
-
-struct RefreshCommitCoin
-{
- struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
- struct TALER_RSA_BlindedSignaturePurpose coin_ev;
- uint16_t cnc_index;
- uint16_t newcoin_index;
- char link_enc[sizeof (struct LinkData)];
-};
-
-
-struct KnownCoin
-{
- struct TALER_CoinPublicInfo public_info;
- struct TALER_Amount expended_balance;
- int is_refreshed;
- /**
- * Refreshing session, only valid if
- * is_refreshed==1.
- */
- struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub;
-};
int
TALER_MINT_DB_prepare (PGconn *db_conn);
diff --git a/src/mint/taler-mint-httpd.c b/src/mint/taler-mint-httpd.c
index 2c3b3d2e1..9dc03cdea 100644
--- a/src/mint/taler-mint-httpd.c
+++ b/src/mint/taler-mint-httpd.c
@@ -28,7 +28,6 @@
#include <libpq-fe.h>
#include <pthread.h>
#include "mint.h"
-#include "mint_db.h"
#include "taler_signatures.h"
#include "taler_rsa.h"
#include "taler_json_lib.h"
@@ -38,6 +37,7 @@
#include "taler-mint-httpd_deposit.h"
#include "taler-mint-httpd_withdraw.h"
#include "taler-mint-httpd_refresh.h"
+#include "mint_db.h"
/**
diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c
index 7a78f93ea..f3a22911c 100644
--- a/src/mint/taler-mint-httpd_db.c
+++ b/src/mint/taler-mint-httpd_db.c
@@ -25,12 +25,15 @@
* - /deposit: check for leaks
*/
#include "platform.h"
+#include <pthread.h>
+#include <jansson.h>
#include "taler-mint-httpd_db.h"
#include "taler_signatures.h"
+#include "taler-mint-httpd_keys.h"
#include "taler-mint-httpd_responses.h"
#include "mint_db.h"
#include "mint.h"
-#include <pthread.h>
+#include "taler_json_lib.h"
/**
@@ -48,43 +51,39 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
const struct Deposit *deposit)
{
PGconn *db_conn;
+ struct Deposit *existing_deposit;
+ int res;
if (NULL == (db_conn = TALER_MINT_DB_get_connection ()))
{
GNUNET_break (0);
return TALER_MINT_reply_internal_error (connection,
- "Failed to connect to database\n");
+ "Failed to connect to database");
}
-
+ res = TALER_MINT_DB_get_deposit (db_conn,
+ &deposit->coin_pub,
+ &existing_deposit);
+ if (GNUNET_YES == res)
{
- struct Deposit *existing_deposit;
- int res;
-
- res = TALER_MINT_DB_get_deposit (db_conn,
- &deposit->coin_pub,
- &existing_deposit);
- if (GNUNET_YES == res)
- {
- // FIXME: memory leak
- // FIXME: memcmp will not actually work here
- if (0 == memcmp (existing_deposit, deposit, sizeof (struct Deposit)))
- return TALER_MINT_reply_deposit_success (connection, deposit);
- // FIXME: in the future, check if there's enough credits
- // left on the coin. For now: refuse
- // FIXME: return more information here
- return TALER_MINT_reply_json_pack (connection,
- MHD_HTTP_FORBIDDEN,
- "{s:s}",
- "error",
- "double spending");
- }
+ // FIXME: memory leak
+ // FIXME: memcmp will not actually work here
+ if (0 == memcmp (existing_deposit, deposit, sizeof (struct Deposit)))
+ return TALER_MINT_reply_deposit_success (connection, deposit);
+ // FIXME: in the future, check if there's enough credits
+ // left on the coin. For now: refuse
+ // FIXME: return more information here
+ return TALER_MINT_reply_json_pack (connection,
+ MHD_HTTP_FORBIDDEN,
+ "{s:s}",
+ "error",
+ "double spending");
+ }
- if (GNUNET_SYSERR == res)
- {
+ if (GNUNET_SYSERR == res)
+ {
GNUNET_break (0);
/* FIXME: return error message to client via MHD! */
return MHD_NO;
- }
}
{
@@ -133,3 +132,228 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
TALER_MINT_DB_commit (db_conn);
return TALER_MINT_reply_deposit_success (connection, deposit);
}
+
+
+/**
+ * Sign a reserve's status with the current signing key.
+ * FIXME: not sure why we do this. Should just return
+ * existing list of operations on the reserve.
+ *
+ * @param reserve the reserve to sign
+ * @param key_state the key state containing the current
+ * signing private key
+ */
+static void
+sign_reserve (struct Reserve *reserve,
+ struct MintKeyState *key_state)
+{
+ 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));
+ GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv,
+ &reserve->status_sig_purpose,
+ &reserve->status_sig);
+}
+
+
+/**
+ * Execute a /withdraw/status.
+ *
+ * @param connection the MHD connection to handle
+ * @param reserve_pub public key of the reserve to check
+ * @return MHD result code
+ */
+int
+TALER_MINT_db_execute_withdraw_status (struct MHD_Connection *connection,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub)
+{
+ PGconn *db_conn;
+ int res;
+ struct Reserve reserve;
+ struct MintKeyState *key_state;
+ int must_update = GNUNET_NO;
+
+
+ if (NULL == (db_conn = TALER_MINT_DB_get_connection ()))
+ {
+ GNUNET_break (0);
+ return TALER_MINT_reply_internal_error (connection,
+ "Failed to connect to database");
+ }
+ res = TALER_MINT_DB_get_reserve (db_conn,
+ reserve_pub,
+ &reserve);
+ /* check if these are really the matching error codes,
+ seems odd... */
+ if (GNUNET_SYSERR == res)
+ return TALER_MINT_reply_json_pack (connection,
+ MHD_HTTP_NOT_FOUND,
+ "{s:s}",
+ "error",
+ "Reserve not found");
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break (0);
+ return TALER_MINT_reply_internal_error (connection,
+ "Internal error");
+ }
+ key_state = TALER_MINT_key_state_acquire ();
+ if (0 != memcmp (&key_state->current_sign_key_issue.issue.signkey_pub,
+ &reserve.status_sign_pub,
+ sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
+ {
+ sign_reserve (&reserve, key_state);
+ must_update = GNUNET_YES;
+ }
+ if ((GNUNET_YES == must_update) &&
+ (GNUNET_OK != TALER_MINT_DB_update_reserve (db_conn, &reserve, !must_update)))
+ {
+ GNUNET_break (0);
+ return MHD_YES;
+ }
+ return TALER_MINT_reply_withdraw_status_success (connection,
+ &reserve);
+}
+
+
+/**
+ * Execute a /withdraw/sign.
+ *
+ * @param connection the MHD connection to handle
+ * @param wsrd_ro details about the withdraw request
+ * @return MHD result code
+ */
+int
+TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
+ const struct TALER_WithdrawRequest *wsrd_ro)
+{
+ PGconn *db_conn;
+ struct Reserve reserve;
+ struct MintKeyState *key_state;
+ struct CollectableBlindcoin collectable;
+ struct TALER_MINT_DenomKeyIssuePriv *dki;
+ struct TALER_RSA_Signature ev_sig;
+ struct TALER_Amount amount_required;
+ /* FIXME: the fact that we do this here is a sign that we
+ need to have different versions of this struct for
+ the different places it is used! */
+ struct TALER_WithdrawRequest wsrd = *wsrd_ro;
+ int res;
+
+ if (NULL == (db_conn = TALER_MINT_DB_get_connection ()))
+ {
+ // FIXME: return 'internal error'?
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+
+
+ res = TALER_MINT_DB_get_collectable_blindcoin (db_conn,
+ &wsrd.coin_envelope,
+ &collectable);
+ if (GNUNET_SYSERR == res)
+ {
+ // FIXME: return 'internal error'
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+
+ /* Don't sign again if we have already signed the coin */
+ if (GNUNET_YES == res)
+ return TALER_MINT_reply_withdraw_sign_success (connection,
+ &collectable);
+ GNUNET_assert (GNUNET_NO == res);
+ res = TALER_MINT_DB_get_reserve (db_conn,
+ &wsrd.reserve_pub,
+ &reserve);
+ if (GNUNET_SYSERR == res)
+ {
+ // FIXME: return 'internal error'
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ if (GNUNET_NO == res)
+ return TALER_MINT_reply_json_pack (connection,
+ MHD_HTTP_NOT_FOUND,
+ "{s:s}",
+ "error",
+ "Reserve not found");
+
+ // fill out all the missing info in the request before
+ // we can check the signature on the request
+
+ wsrd.purpose.purpose = htonl (TALER_SIGNATURE_WITHDRAW);
+ wsrd.purpose.size = htonl (sizeof (struct TALER_WithdrawRequest) -
+ offsetof (struct TALER_WithdrawRequest, purpose));
+
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WITHDRAW,
+ &wsrd.purpose,
+ &wsrd.sig,
+ &wsrd.reserve_pub))
+ return TALER_MINT_reply_json_pack (connection,
+ MHD_HTTP_UNAUTHORIZED,
+ "{s:s}",
+ "error", "Invalid Signature");
+
+ key_state = TALER_MINT_key_state_acquire ();
+ dki = TALER_MINT_get_denom_key (key_state,
+ &wsrd.denomination_pub);
+ TALER_MINT_key_state_release (key_state);
+ if (NULL == dki)
+ return TALER_MINT_reply_json_pack (connection,
+ MHD_HTTP_NOT_FOUND,
+ "{s:s}",
+ "error",
+ "Denomination not found");
+
+ amount_required = TALER_amount_ntoh (dki->issue.value);
+ amount_required = TALER_amount_add (amount_required,
+ TALER_amount_ntoh (dki->issue.fee_withdraw));
+
+ if (0 < TALER_amount_cmp (amount_required,
+ TALER_amount_ntoh (reserve.balance)))
+ return TALER_MINT_reply_json_pack (connection,
+ MHD_HTTP_PAYMENT_REQUIRED,
+ "{s:s}",
+ "error",
+ "Insufficient funds");
+ if (GNUNET_OK !=
+ TALER_RSA_sign (dki->denom_priv,
+ &wsrd.coin_envelope,
+ sizeof (struct TALER_RSA_BlindedSignaturePurpose),
+ &ev_sig))
+ {
+ // FIXME: return 'internal error'
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+
+ reserve.balance = TALER_amount_hton (TALER_amount_subtract (TALER_amount_ntoh (reserve.balance),
+ amount_required));
+ if (GNUNET_OK !=
+ TALER_MINT_DB_update_reserve (db_conn,
+ &reserve,
+ GNUNET_YES))
+ {
+ // FIXME: return 'internal error'
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+
+ collectable.ev = wsrd.coin_envelope;
+ collectable.ev_sig = ev_sig;
+ collectable.reserve_pub = wsrd.reserve_pub;
+ collectable.reserve_sig = wsrd.sig;
+ if (GNUNET_OK !=
+ TALER_MINT_DB_insert_collectable_blindcoin (db_conn,
+ &collectable))
+ {
+ // FIXME: return 'internal error'
+ GNUNET_break (0);
+ return GNUNET_NO;;
+ }
+ return TALER_MINT_reply_withdraw_sign_success (connection,
+ &collectable);
+}
diff --git a/src/mint/taler-mint-httpd_db.h b/src/mint/taler-mint-httpd_db.h
index 1829f3d37..a479576da 100644
--- a/src/mint/taler-mint-httpd_db.h
+++ b/src/mint/taler-mint-httpd_db.h
@@ -17,9 +17,6 @@
* @file mint/taler-mint_httpd_db.h
* @brief Mint-specific database access
* @author Chrisitan Grothoff
- *
- * TODO:
- * - revisit and document `struct Deposit` members.
*/
#ifndef TALER_MINT_HTTPD_DB_H
#define TALER_MINT_HTTPD_DB_H
@@ -29,46 +26,13 @@
#include <gnunet/gnunet_util_lib.h>
#include "taler_util.h"
#include "taler_rsa.h"
+#include "taler-mint-httpd_keys.h"
+#include "mint.h"
-/**
- * Specification for a /deposit operation.
- */
-struct Deposit
-{
- /* FIXME: should be TALER_CoinPublicInfo */
- struct GNUNET_CRYPTO_EddsaPublicKey coin_pub;
-
- struct TALER_RSA_PublicKeyBinaryEncoded denom_pub;
-
- struct TALER_RSA_Signature coin_sig;
-
- struct TALER_RSA_Signature ubsig;
-
- /**
- * Type of the deposit (also purpose of the signature). Either
- * #TALER_SIGNATURE_DEPOSIT or #TALER_SIGNATURE_INCREMENTAL_DEPOSIT.
- */
- struct TALER_RSA_SignaturePurpose purpose;
-
- uint64_t transaction_id;
-
- struct TALER_AmountNBO amount;
-
- struct GNUNET_CRYPTO_EddsaPublicKey merchant_pub;
-
- struct GNUNET_HashCode h_contract;
-
- struct GNUNET_HashCode h_wire;
-
- /* TODO: uint16_t wire_size */
- char wire[]; /* string encoded wire JSON object */
-
-};
-
/**
- * Execute a deposit. The validity of the coin and signature
+ * Execute a /deposit. The validity of the coin and signature
* have already been checked. The database must now check that
* the coin is not (double or over) spent, and execute the
* transaction (record details, generate success or failure response).
@@ -82,4 +46,28 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
const struct Deposit *deposit);
+/**
+ * Execute a /withdraw/status.
+ *
+ * @param connection the MHD connection to handle
+ * @param reserve_pub public key of the reserve to check
+ * @return MHD result code
+ */
+int
+TALER_MINT_db_execute_withdraw_status (struct MHD_Connection *connection,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub);
+
+
+/**
+ * Execute a /withdraw/sign.
+ *
+ * @param connection the MHD connection to handle
+ * @param wsrd details about the withdraw request
+ * @return MHD result code
+ */
+int
+TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
+ const struct TALER_WithdrawRequest *wsrd);
+
+
#endif /* _NEURO_MINT_DB_H */
diff --git a/src/mint/taler-mint-httpd_keys.c b/src/mint/taler-mint-httpd_keys.c
index 149e44d3f..8db32cd83 100644
--- a/src/mint/taler-mint-httpd_keys.c
+++ b/src/mint/taler-mint-httpd_keys.c
@@ -27,7 +27,6 @@
#include <libpq-fe.h>
#include <pthread.h>
#include "mint.h"
-#include "mint_db.h"
#include "taler_signatures.h"
#include "taler_rsa.h"
#include "taler_json_lib.h"
@@ -35,6 +34,7 @@
#include "taler-mint-httpd_keys.h"
+
/**
* Mint key state. Never use directly, instead access via
* #TALER_MINT_key_state_acquire and #TALER_MINT_key_state_release.
diff --git a/src/mint/taler-mint-httpd_keys.h b/src/mint/taler-mint-httpd_keys.h
index 4fd3d0bdd..c156cff66 100644
--- a/src/mint/taler-mint-httpd_keys.h
+++ b/src/mint/taler-mint-httpd_keys.h
@@ -26,7 +26,7 @@
#include <gnunet/gnunet_util_lib.h>
#include <microhttpd.h>
#include "taler-mint-httpd.h"
-
+#include "mint.h"
/**
* Snapshot of the (coin and signing)
diff --git a/src/mint/taler-mint-httpd_refresh.c b/src/mint/taler-mint-httpd_refresh.c
index ab21e814c..883da8a85 100644
--- a/src/mint/taler-mint-httpd_refresh.c
+++ b/src/mint/taler-mint-httpd_refresh.c
@@ -19,6 +19,9 @@
* @author Florian Dold
* @author Benedikt Mueller
* @author Christian Grothoff
+ *
+ * TODO:
+ * - split properly into parsing, DB-ops and response generation
*/
#include "platform.h"
#include <gnunet/gnunet_util_lib.h>
@@ -70,6 +73,9 @@ sign_as_json (struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
}
+/**
+ * FIXME: document!
+ */
static int
link_iter (void *cls,
const struct LinkDataEnc *link_data_enc,
@@ -246,9 +252,9 @@ check_confirm_signature (struct MHD_Connection *connection,
*
* @param connection the connection to send error responses to
* @param root the JSON object to extract the coin info from
- * @return GNUNET_YES if coin public info in JSON was valid
- * GNUNET_NO otherwise
- * GNUNET_SYSERR on internal error
+ * @return #GNUNET_YES if coin public info in JSON was valid
+ * #GNUNET_NO otherwise
+ * #GNUNET_SYSERR on internal error
*/
static int
request_json_require_coin_public_info (struct MHD_Connection *connection,
@@ -298,9 +304,9 @@ request_json_require_coin_public_info (struct MHD_Connection *connection,
* @param root the JSON object
* @param hash_context the hash context that will receive
* the coin public keys of the melted coin
- * @return a GNUnet result code, GNUNET_OK on success,
- * GNUNET_NO if an error message was generated,
- * GNUNET_SYSERR on internal errors (no response generated)
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO if an error message was generated,
+ * #GNUNET_SYSERR on internal errors (no response generated)
*/
static int
refresh_accept_melts (struct MHD_Connection *connection,
diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c
index 6ae219b63..78e239b7c 100644
--- a/src/mint/taler-mint-httpd_responses.c
+++ b/src/mint/taler-mint-httpd_responses.c
@@ -26,9 +26,14 @@
* TODO:
* - when generating /deposit reply, do include signature of mint
* to say that we accepted it (check reply format)
+ * - when generating /withdraw/status reply, which signature do
+ * we use there? Might want to instead return *all* signatures on the
+ * existig withdraw operations, instead of Mint's signature
+ * (check reply format, adjust `struct Reserve` if needed)
*/
#include "platform.h"
#include "taler-mint-httpd_responses.h"
+#include "taler_json_lib.h"
/**
@@ -229,4 +234,61 @@ TALER_MINT_reply_deposit_success (struct MHD_Connection *connection,
"DEPOSIT_OK");
}
+
+/**
+ * Send reserve status information to client.
+ *
+ * @param connection connection to the client
+ * @param reserve reserve status information to return
+ * @return MHD result code
+ */
+int
+TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection,
+ const struct Reserve *reserve)
+{
+ json_t *json;
+
+ /* Convert the public information of a reserve (i.e.
+ excluding private key) to a JSON object. */
+ json = json_object ();
+ json_object_set_new (json,
+ "balance",
+ TALER_JSON_from_amount (TALER_amount_ntoh (reserve->balance)));
+ json_object_set_new (json,
+ "expiration",
+ TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (reserve->expiration)));
+ json_object_set_new (json,
+ "signature",
+ TALER_JSON_from_sig (&reserve->status_sig_purpose,
+ &reserve->status_sig));
+
+ return TALER_MINT_reply_json (connection,
+ json,
+ MHD_HTTP_OK);
+}
+
+
+/**
+ * Send blinded coin information to client.
+ *
+ * @param connection connection to the client
+ * @param collectable blinded coin to return
+ * @return MHD result code
+ */
+int
+TALER_MINT_reply_withdraw_sign_success (struct MHD_Connection *connection,
+ const struct CollectableBlindcoin *collectable)
+{
+ json_t *root = json_object ();
+
+ json_object_set_new (root, "ev_sig",
+ TALER_JSON_from_data (&collectable->ev_sig,
+ sizeof (struct TALER_RSA_Signature)));
+ return TALER_MINT_reply_json (connection,
+ root,
+ MHD_HTTP_OK);
+}
+
+
+
/* end of taler-mint-httpd_responses.c */
diff --git a/src/mint/taler-mint-httpd_responses.h b/src/mint/taler-mint-httpd_responses.h
index 6dd8cda90..ce7557e1d 100644
--- a/src/mint/taler-mint-httpd_responses.h
+++ b/src/mint/taler-mint-httpd_responses.h
@@ -31,8 +31,8 @@
#include <libpq-fe.h>
#include <pthread.h>
#include "taler-mint-httpd.h"
+#include "taler-mint-httpd_db.h"
#include "taler-mint-httpd_mhd.h"
-#include "mint_db.h"
/**
@@ -135,5 +135,28 @@ TALER_MINT_reply_deposit_success (struct MHD_Connection *connection,
const struct Deposit *deposit);
+/**
+ * Send reserve status information to client.
+ *
+ * @param connection connection to the client
+ * @param reserve reserve status information to return
+ * @return MHD result code
+ */
+int
+TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection,
+ const struct Reserve *reserve);
+
+
+/**
+ * Send blinded coin information to client.
+ *
+ * @param connection connection to the client
+ * @param collectable blinded coin to return
+ * @return MHD result code
+ */
+int
+TALER_MINT_reply_withdraw_sign_success (struct MHD_Connection *connection,
+ const struct CollectableBlindcoin *collectable);
+
#endif
diff --git a/src/mint/taler-mint-httpd_withdraw.c b/src/mint/taler-mint-httpd_withdraw.c
index cc0de7f6f..5259c7fbf 100644
--- a/src/mint/taler-mint-httpd_withdraw.c
+++ b/src/mint/taler-mint-httpd_withdraw.c
@@ -19,6 +19,9 @@
* @author Florian Dold
* @author Benedikt Mueller
* @author Christian Grothoff
+ *
+ * TODO:
+ * - support variable-size RSA keys
*/
#include "platform.h"
#include <gnunet/gnunet_util_lib.h>
@@ -33,63 +36,13 @@
#include "taler_json_lib.h"
#include "taler-mint-httpd_parsing.h"
#include "taler-mint-httpd_keys.h"
+#include "taler-mint-httpd_db.h"
#include "taler-mint-httpd_mhd.h"
#include "taler-mint-httpd_withdraw.h"
#include "taler-mint-httpd_responses.h"
/**
- * Convert a signature (with purpose) to
- * a JSON object representation.
- *
- * @param purpose purpose of the signature
- * @param signature the signature
- * @return the JSON reporesentation of the signature with purpose
- */
-static json_t *
-sig_to_json (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
- const struct GNUNET_CRYPTO_EddsaSignature *signature)
-{
- json_t *root;
- json_t *el;
-
- root = json_object ();
-
- el = json_integer ((json_int_t) ntohl (purpose->size));
- json_object_set_new (root, "size", el);
-
- el = json_integer ((json_int_t) ntohl (purpose->purpose));
- json_object_set_new (root, "purpose", el);
-
- el = TALER_JSON_from_data (signature, sizeof (struct GNUNET_CRYPTO_EddsaSignature));
- json_object_set_new (root, "sig", el);
-
- return root;
-}
-
-
-/**
- * Sign a reserve's status with the current signing key.
- *
- * @param reserve the reserve to sign
- * @param key_state the key state containing the current
- * signing private key
- */
-static void
-sign_reserve (struct Reserve *reserve,
- struct MintKeyState *key_state)
-{
- 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));
- GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv,
- &reserve->status_sig_purpose,
- &reserve->status_sig);
-}
-
-
-/**
* Handle a "/withdraw/status" request
*
* @param rh context of the handler
@@ -107,100 +60,18 @@ TALER_MINT_handler_withdraw_status (struct RequestHandler *rh,
size_t *upload_data_size)
{
struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
- PGconn *db_conn;
int res;
- struct Reserve reserve;
- struct MintKeyState *key_state;
- int must_update = GNUNET_NO;
- json_t *json;
res = TALER_MINT_mhd_request_arg_data (connection,
- "reserve_pub",
- &reserve_pub,
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
- if (GNUNET_SYSERR == res)
- {
- // FIXME: return 'internal error'
- GNUNET_break (0);
- return MHD_NO;
- }
- if (GNUNET_OK != res)
- return MHD_YES;
- if (NULL == (db_conn = TALER_MINT_DB_get_connection ()))
- {
- // FIXME: return 'internal error'?
- GNUNET_break (0);
- return MHD_NO;
- }
- res = TALER_MINT_DB_get_reserve (db_conn,
- &reserve_pub,
- &reserve);
+ "reserve_pub",
+ &reserve_pub,
+ sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
if (GNUNET_SYSERR == res)
- return TALER_MINT_reply_json_pack (connection,
- MHD_HTTP_NOT_FOUND,
- "{s:s}",
- "error",
- "Reserve not found");
- if (GNUNET_OK != res)
- {
- // FIXME: return 'internal error'?
- GNUNET_break (0);
- return MHD_NO;
- }
- key_state = TALER_MINT_key_state_acquire ();
- if (0 != memcmp (&key_state->current_sign_key_issue.issue.signkey_pub,
- &reserve.status_sign_pub,
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
- {
- sign_reserve (&reserve, key_state);
- must_update = GNUNET_YES;
- }
- if ((GNUNET_YES == must_update) &&
- (GNUNET_OK != TALER_MINT_DB_update_reserve (db_conn, &reserve, !must_update)))
- {
- GNUNET_break (0);
- return MHD_YES;
- }
-
- /* Convert the public information of a reserve (i.e.
- excluding private key) to a JSON object. */
- json = json_object ();
- json_object_set_new (json,
- "balance",
- TALER_JSON_from_amount (TALER_amount_ntoh (reserve.balance)));
- json_object_set_new (json,
- "expiration",
- TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (reserve.expiration)));
- json_object_set_new (json,
- "signature",
- sig_to_json (&reserve.status_sig_purpose,
- &reserve.status_sig));
-
- return TALER_MINT_reply_json (connection,
- json,
- MHD_HTTP_OK);
-}
-
-
-/**
- * Send positive, normal response for "/withdraw/sign".
- *
- * @param connection the connection to send the response to
- * @param collectable the collectable blindcoin (i.e. the blindly signed coin)
- * @return a MHD result code
- */
-static int
-helper_withdraw_sign_send_reply (struct MHD_Connection *connection,
- const struct CollectableBlindcoin *collectable)
-{
- json_t *root = json_object ();
-
- json_object_set_new (root, "ev_sig",
- TALER_JSON_from_data (&collectable->ev_sig,
- sizeof (struct TALER_RSA_Signature)));
- return TALER_MINT_reply_json (connection,
- root,
- MHD_HTTP_OK);
+ return MHD_NO; /* internal error */
+ if (GNUNET_NO == res)
+ return MHD_YES; /* parse error */
+ return TALER_MINT_db_execute_withdraw_status (connection,
+ &reserve_pub);
}
@@ -223,180 +94,44 @@ TALER_MINT_handler_withdraw_sign (struct RequestHandler *rh,
{
struct TALER_WithdrawRequest wsrd;
int res;
- PGconn *db_conn;
- struct Reserve reserve;
- struct MintKeyState *key_state;
- struct CollectableBlindcoin collectable;
- struct TALER_MINT_DenomKeyIssuePriv *dki;
- struct TALER_RSA_Signature ev_sig;
- struct TALER_Amount amount_required;
- memset (&wsrd,
- 0,
- sizeof (struct TALER_WithdrawRequest));
res = TALER_MINT_mhd_request_arg_data (connection,
- "reserve_pub",
- &wsrd.reserve_pub,
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
+ "reserve_pub",
+ &wsrd.reserve_pub,
+ sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
if (GNUNET_SYSERR == res)
- {
- // FIXME: return 'internal error'?
- GNUNET_break (0);
- return MHD_NO;
- }
- if (GNUNET_OK != res)
- return MHD_YES;
+ return MHD_NO; /* internal error */
+ if (GNUNET_NO == res)
+ return MHD_YES; /* invalid request */
+
+ /* FIXME: handle variable-size signing keys! */
res = TALER_MINT_mhd_request_arg_data (connection,
"denom_pub",
&wsrd.denomination_pub,
sizeof (struct TALER_RSA_PublicKeyBinaryEncoded));
if (GNUNET_SYSERR == res)
- {
- // FIXME: return 'internal error'?
- GNUNET_break (0);
- return MHD_NO;
- }
- if (GNUNET_OK != res)
- return MHD_YES;
+ return MHD_NO; /* internal error */
+ if (GNUNET_NO == res)
+ return MHD_YES; /* invalid request */
res = TALER_MINT_mhd_request_arg_data (connection,
- "coin_ev",
- &wsrd.coin_envelope,
- sizeof (struct TALER_RSA_Signature));
+ "coin_ev",
+ &wsrd.coin_envelope,
+ sizeof (struct TALER_RSA_Signature));
if (GNUNET_SYSERR == res)
- {
- // FIXME: return 'internal error'?
- GNUNET_break (0);
- return MHD_NO;
- }
- if (GNUNET_OK != res)
- return MHD_YES;
+ return MHD_NO; /* internal error */
+ if (GNUNET_NO == res)
+ return MHD_YES; /* invalid request */
res = TALER_MINT_mhd_request_arg_data (connection,
- "reserve_sig",
- &wsrd.sig,
- sizeof (struct GNUNET_CRYPTO_EddsaSignature));
+ "reserve_sig",
+ &wsrd.sig,
+ sizeof (struct GNUNET_CRYPTO_EddsaSignature));
if (GNUNET_SYSERR == res)
- {
- // FIXME: return 'internal error'?
- GNUNET_break (0);
- return MHD_NO;
- }
- if (GNUNET_OK != res)
- return MHD_YES;
-
- if (NULL == (db_conn = TALER_MINT_DB_get_connection ()))
- {
- // FIXME: return 'internal error'?
- GNUNET_break (0);
- return MHD_NO;
- }
-
- res = TALER_MINT_DB_get_collectable_blindcoin (db_conn,
- &wsrd.coin_envelope,
- &collectable);
- if (GNUNET_SYSERR == res)
- {
- // FIXME: return 'internal error'
- GNUNET_break (0);
- return MHD_NO;
- }
-
- /* Don't sign again if we have already signed the coin */
- if (GNUNET_YES == res)
- return helper_withdraw_sign_send_reply (connection,
- &collectable);
- GNUNET_assert (GNUNET_NO == res);
- res = TALER_MINT_DB_get_reserve (db_conn,
- &wsrd.reserve_pub,
- &reserve);
- if (GNUNET_SYSERR == res)
- {
- // FIXME: return 'internal error'
- GNUNET_break (0);
- return MHD_NO;
- }
+ return MHD_NO; /* internal error */
if (GNUNET_NO == res)
- return TALER_MINT_reply_json_pack (connection,
- MHD_HTTP_NOT_FOUND,
- "{s:s}",
- "error",
- "Reserve not found");
-
- // fill out all the missing info in the request before
- // we can check the signature on the request
-
- wsrd.purpose.purpose = htonl (TALER_SIGNATURE_WITHDRAW);
- wsrd.purpose.size = htonl (sizeof (struct TALER_WithdrawRequest) -
- offsetof (struct TALER_WithdrawRequest, purpose));
-
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WITHDRAW,
- &wsrd.purpose,
- &wsrd.sig,
- &wsrd.reserve_pub))
- return TALER_MINT_reply_json_pack (connection,
- MHD_HTTP_UNAUTHORIZED,
- "{s:s}",
- "error", "Invalid Signature");
-
- key_state = TALER_MINT_key_state_acquire ();
- dki = TALER_MINT_get_denom_key (key_state,
- &wsrd.denomination_pub);
- TALER_MINT_key_state_release (key_state);
- if (NULL == dki)
- return TALER_MINT_reply_json_pack (connection,
- MHD_HTTP_NOT_FOUND,
- "{s:s}",
- "error",
- "Denomination not found");
-
- amount_required = TALER_amount_ntoh (dki->issue.value);
- amount_required = TALER_amount_add (amount_required,
- TALER_amount_ntoh (dki->issue.fee_withdraw));
-
- if (0 < TALER_amount_cmp (amount_required,
- TALER_amount_ntoh (reserve.balance)))
- return TALER_MINT_reply_json_pack (connection,
- MHD_HTTP_PAYMENT_REQUIRED,
- "{s:s}",
- "error",
- "Insufficient funds");
- if (GNUNET_OK !=
- TALER_RSA_sign (dki->denom_priv,
- &wsrd.coin_envelope,
- sizeof (struct TALER_RSA_BlindedSignaturePurpose),
- &ev_sig))
- {
- // FIXME: return 'internal error'
- GNUNET_break (0);
- return MHD_NO;
- }
-
- reserve.balance = TALER_amount_hton (TALER_amount_subtract (TALER_amount_ntoh (reserve.balance),
- amount_required));
- if (GNUNET_OK !=
- TALER_MINT_DB_update_reserve (db_conn,
- &reserve,
- GNUNET_YES))
- {
- // FIXME: return 'internal error'
- GNUNET_break (0);
- return MHD_NO;
- }
+ return MHD_YES; /* invalid request */
- collectable.ev = wsrd.coin_envelope;
- collectable.ev_sig = ev_sig;
- collectable.reserve_pub = wsrd.reserve_pub;
- collectable.reserve_sig = wsrd.sig;
- if (GNUNET_OK !=
- TALER_MINT_DB_insert_collectable_blindcoin (db_conn,
- &collectable))
- {
- // FIXME: return 'internal error'
- GNUNET_break (0);
- return GNUNET_NO;;
- }
- return helper_withdraw_sign_send_reply (connection,
- &collectable);
+ return TALER_MINT_db_execute_withdraw_sign (connection,
+ &wsrd);
}
/* end of taler-mint-httpd_withdraw.c */