aboutsummaryrefslogtreecommitdiff
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
parentf9347d23953f771689d339b544370d3f9fdd97ba (diff)
downloadexchange-ed51946442e5e22a7dea68f14ff2bf563503c755.tar.gz
exchange-ed51946442e5e22a7dea68f14ff2bf563503c755.zip
more code refactoring to separate parsing, db and response generation nicely
-rw-r--r--src/include/taler_json_lib.h20
-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
-rw-r--r--src/util/json.c28
13 files changed, 647 insertions, 528 deletions
diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h
index b224c4b33..ec354cce7 100644
--- a/src/include/taler_json_lib.h
+++ b/src/include/taler_json_lib.h
@@ -27,8 +27,7 @@
27 27
28 28
29/** 29/**
30 * Convert a TALER amount to a JSON 30 * Convert a TALER amount to a JSON object.
31 * object.
32 * 31 *
33 * @param amount the amount 32 * @param amount the amount
34 * @return a json object describing the amount 33 * @return a json object describing the amount
@@ -47,6 +46,17 @@ json_t *
47TALER_JSON_from_abs (struct GNUNET_TIME_Absolute stamp); 46TALER_JSON_from_abs (struct GNUNET_TIME_Absolute stamp);
48 47
49 48
49/**
50 * Convert a signature (with purpose) to a JSON object representation.
51 *
52 * @param purpose purpose of the signature
53 * @param signature the signature
54 * @return the JSON reporesentation of the signature with purpose
55 */
56json_t *
57TALER_JSON_from_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
58 const struct GNUNET_CRYPTO_EddsaSignature *signature);
59
50 60
51/** 61/**
52 * Convert binary data to a JSON string 62 * Convert binary data to a JSON string
@@ -65,7 +75,7 @@ TALER_JSON_from_data (const void *data, size_t size);
65 * 75 *
66 * @param json the json object representing Amount 76 * @param json the json object representing Amount
67 * @param r_amount where the amount has to be written 77 * @param r_amount where the amount has to be written
68 * @return GNUNET_OK upon successful parsing; GNUNET_SYSERR upon error 78 * @return #GNUNET_OK upon successful parsing; GNUNET_SYSERR upon error
69 */ 79 */
70int 80int
71TALER_JSON_to_amount (json_t *json, 81TALER_JSON_to_amount (json_t *json,
@@ -76,7 +86,7 @@ TALER_JSON_to_amount (json_t *json,
76 * 86 *
77 * @param json the json object representing absolute time in seconds 87 * @param json the json object representing absolute time in seconds
78 * @param r_abs where the time has to be written 88 * @param r_abs where the time has to be written
79 * @return GNUNET_OK upon successful parsing; GNUNET_SYSERR upon error 89 * @return #GNUNET_OK upon successful parsing; GNUNET_SYSERR upon error
80 */ 90 */
81int 91int
82TALER_JSON_to_abs (json_t *json, 92TALER_JSON_to_abs (json_t *json,
@@ -88,7 +98,7 @@ TALER_JSON_to_abs (json_t *json,
88 * @param json the json object representing data 98 * @param json the json object representing data
89 * @param out the pointer to hold the parsed data. 99 * @param out the pointer to hold the parsed data.
90 * @param out_size the size of r_data. 100 * @param out_size the size of r_data.
91 * @return GNUNET_OK upon successful parsing; GNUNET_SYSERR upon error 101 * @return #GNUNET_OK upon successful parsing; GNUNET_SYSERR upon error
92 */ 102 */
93int 103int
94TALER_JSON_to_data (json_t *json, 104TALER_JSON_to_data (json_t *json,
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 @@
13 You should have received a copy of the GNU General Public License along with 13 You should have received a copy of the GNU General Public License along with
14 TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> 14 TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
15*/ 15*/
16
17/** 16/**
18 * @file taler_mint.h 17 * @file mint.h
19 * @brief Common functionality for the mint 18 * @brief Common functionality for the mint
20 * @author Florian Dold 19 * @author Florian Dold
21 * @author Benedikt Mueller 20 * @author Benedikt Mueller
21 *
22 * TODO:
23 * - revisit and document `struct Deposit` members.
22 */ 24 */
23
24#ifndef _MINT_H 25#ifndef _MINT_H
25#define _MINT_H 26#define _MINT_H
26 27
@@ -55,11 +56,195 @@ struct TALER_MINT_DenomKeyIssuePriv
55 * not available. 56 * not available.
56 */ 57 */
57 struct TALER_RSA_PrivateKey *denom_priv; 58 struct TALER_RSA_PrivateKey *denom_priv;
59
58 struct TALER_MINT_DenomKeyIssue issue; 60 struct TALER_MINT_DenomKeyIssue issue;
59}; 61};
60 62
61 63
62 64
65/**
66 * Public information about a coin.
67 */
68struct TALER_CoinPublicInfo
69{
70 /**
71 * The coin's public key.
72 */
73 struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub;
74
75 /*
76 * The public key signifying the coin's denomination.
77 */
78 struct TALER_RSA_PublicKeyBinaryEncoded denom_pub;
79
80 /**
81 * Signature over coin_pub by denom_pub.
82 */
83 struct TALER_RSA_Signature denom_sig;
84};
85
86
87
88
89
90
91
92struct CollectableBlindcoin
93{
94 struct TALER_RSA_BlindedSignaturePurpose ev;
95 struct TALER_RSA_Signature ev_sig;
96 struct TALER_RSA_PublicKeyBinaryEncoded denom_pub;
97 struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
98 struct GNUNET_CRYPTO_EddsaSignature reserve_sig;
99};
100
101
102struct RefreshSession
103{
104 int has_commit_sig;
105 struct GNUNET_CRYPTO_EddsaSignature commit_sig;
106 struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
107 uint16_t num_oldcoins;
108 uint16_t num_newcoins;
109 uint16_t kappa;
110 uint16_t noreveal_index;
111 uint8_t reveal_ok;
112};
113
114
115#define TALER_REFRESH_SHARED_SECRET_LENGTH (sizeof (struct GNUNET_HashCode))
116#define TALER_REFRESH_LINK_LENGTH (sizeof (struct LinkData))
117
118struct RefreshCommitLink
119{
120 struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
121 struct GNUNET_CRYPTO_EcdsaPublicKey transfer_pub;
122 uint16_t cnc_index;
123 uint16_t oldcoin_index;
124 char shared_secret_enc[sizeof (struct GNUNET_HashCode)];
125};
126
127struct LinkData
128{
129 struct GNUNET_CRYPTO_EcdsaPrivateKey coin_priv;
130 struct TALER_RSA_BlindingKeyBinaryEncoded bkey_enc;
131};
132
133
134GNUNET_NETWORK_STRUCT_BEGIN
135
136struct SharedSecretEnc
137{
138 char data[TALER_REFRESH_SHARED_SECRET_LENGTH];
139};
140
141
142struct LinkDataEnc
143{
144 char data[sizeof (struct LinkData)];
145};
146
147GNUNET_NETWORK_STRUCT_END
148
149struct RefreshCommitCoin
150{
151 struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
152 struct TALER_RSA_BlindedSignaturePurpose coin_ev;
153 uint16_t cnc_index;
154 uint16_t newcoin_index;
155 char link_enc[sizeof (struct LinkData)];
156};
157
158
159struct KnownCoin
160{
161 struct TALER_CoinPublicInfo public_info;
162 struct TALER_Amount expended_balance;
163 int is_refreshed;
164 /**
165 * Refreshing session, only valid if
166 * is_refreshed==1.
167 */
168 struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub;
169};
170
171
172/**
173 * Specification for a /deposit operation.
174 */
175struct Deposit
176{
177 /* FIXME: should be TALER_CoinPublicInfo */
178 struct GNUNET_CRYPTO_EddsaPublicKey coin_pub;
179
180 struct TALER_RSA_PublicKeyBinaryEncoded denom_pub;
181
182 struct TALER_RSA_Signature coin_sig;
183
184 struct TALER_RSA_Signature ubsig;
185
186 /**
187 * Type of the deposit (also purpose of the signature). Either
188 * #TALER_SIGNATURE_DEPOSIT or #TALER_SIGNATURE_INCREMENTAL_DEPOSIT.
189 */
190 struct TALER_RSA_SignaturePurpose purpose;
191
192 uint64_t transaction_id;
193
194 struct TALER_AmountNBO amount;
195
196 struct GNUNET_CRYPTO_EddsaPublicKey merchant_pub;
197
198 struct GNUNET_HashCode h_contract;
199
200 struct GNUNET_HashCode h_wire;
201
202 /* TODO: uint16_t wire_size */
203 char wire[]; /* string encoded wire JSON object */
204
205};
206
207
208/**
209 * Reserve row. Corresponds to table 'reserves' in the mint's
210 * database. FIXME: not sure this is how we want to store this
211 * information. Also, may currently used in different ways in the
212 * code, so we might need to separate the struct into different ones
213 * depending on the context it is used in.
214 */
215struct Reserve
216{
217 /**
218 * Signature over the purse.
219 * Only valid if (blind_session_missing==GNUNET_YES).
220 */
221 struct GNUNET_CRYPTO_EddsaSignature status_sig;
222 /**
223 * Signature with purpose TALER_SIGNATURE_PURSE.
224 * Only valid if (blind_session_missing==GNUNET_YES).
225 */
226 struct GNUNET_CRYPTO_EccSignaturePurpose status_sig_purpose;
227 /**
228 * Signing key used to sign the purse.
229 * Only valid if (blind_session_missing==GNUNET_YES).
230 */
231 struct GNUNET_CRYPTO_EddsaPublicKey status_sign_pub;
232 /**
233 * Withdraw public key, identifies the purse.
234 * Only the customer knows the corresponding private key.
235 */
236 struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
237 /**
238 * Remaining balance in the purse.
239 */
240 struct TALER_AmountNBO balance;
241
242 /**
243 * Expiration date for the purse.
244 */
245 struct GNUNET_TIME_AbsoluteNBO expiration;
246};
247
63 248
64 249
65 250
@@ -153,4 +338,3 @@ TALER_TALER_DB_extract_amount_nbo (PGresult *result, unsigned int row,
153 int indices[3], struct TALER_AmountNBO *denom_nbo); 338 int indices[3], struct TALER_AmountNBO *denom_nbo);
154 339
155#endif /* _MINT_H */ 340#endif /* _MINT_H */
156
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 @@
29#include "taler_util.h" 29#include "taler_util.h"
30#include "taler_rsa.h" 30#include "taler_rsa.h"
31#include "taler-mint-httpd_db.h" 31#include "taler-mint-httpd_db.h"
32#include "mint.h"
32 33
33/**
34 * Public information about a coin.
35 */
36struct TALER_CoinPublicInfo
37{
38 /**
39 * The coin's public key.
40 */
41 struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub;
42
43 /*
44 * The public key signifying the coin's denomination.
45 */
46 struct TALER_RSA_PublicKeyBinaryEncoded denom_pub;
47
48 /**
49 * Signature over coin_pub by denom_pub.
50 */
51 struct TALER_RSA_Signature denom_sig;
52};
53
54
55
56
57
58
59/**
60 * Reserve row. Corresponds to table 'reserves' in
61 * the mint's database.
62 */
63struct Reserve
64{
65 /**
66 * Signature over the purse.
67 * Only valid if (blind_session_missing==GNUNET_YES).
68 */
69 struct GNUNET_CRYPTO_EddsaSignature status_sig;
70 /**
71 * Signature with purpose TALER_SIGNATURE_PURSE.
72 * Only valid if (blind_session_missing==GNUNET_YES).
73 */
74 struct GNUNET_CRYPTO_EccSignaturePurpose status_sig_purpose;
75 /**
76 * Signing key used to sign the purse.
77 * Only valid if (blind_session_missing==GNUNET_YES).
78 */
79 struct GNUNET_CRYPTO_EddsaPublicKey status_sign_pub;
80 /**
81 * Withdraw public key, identifies the purse.
82 * Only the customer knows the corresponding private key.
83 */
84 struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
85 /**
86 * Remaining balance in the purse.
87 */
88 struct TALER_AmountNBO balance;
89
90 /**
91 * Expiration date for the purse.
92 */
93 struct GNUNET_TIME_AbsoluteNBO expiration;
94};
95
96
97struct CollectableBlindcoin
98{
99 struct TALER_RSA_BlindedSignaturePurpose ev;
100 struct TALER_RSA_Signature ev_sig;
101 struct TALER_RSA_PublicKeyBinaryEncoded denom_pub;
102 struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
103 struct GNUNET_CRYPTO_EddsaSignature reserve_sig;
104};
105
106
107struct RefreshSession
108{
109 int has_commit_sig;
110 struct GNUNET_CRYPTO_EddsaSignature commit_sig;
111 struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
112 uint16_t num_oldcoins;
113 uint16_t num_newcoins;
114 uint16_t kappa;
115 uint16_t noreveal_index;
116 uint8_t reveal_ok;
117};
118
119
120#define TALER_REFRESH_SHARED_SECRET_LENGTH (sizeof (struct GNUNET_HashCode))
121#define TALER_REFRESH_LINK_LENGTH (sizeof (struct LinkData))
122
123struct RefreshCommitLink
124{
125 struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
126 struct GNUNET_CRYPTO_EcdsaPublicKey transfer_pub;
127 uint16_t cnc_index;
128 uint16_t oldcoin_index;
129 char shared_secret_enc[sizeof (struct GNUNET_HashCode)];
130};
131
132struct LinkData
133{
134 struct GNUNET_CRYPTO_EcdsaPrivateKey coin_priv;
135 struct TALER_RSA_BlindingKeyBinaryEncoded bkey_enc;
136};
137
138
139GNUNET_NETWORK_STRUCT_BEGIN
140
141struct SharedSecretEnc
142{
143 char data[TALER_REFRESH_SHARED_SECRET_LENGTH];
144};
145
146
147struct LinkDataEnc
148{
149 char data[sizeof (struct LinkData)];
150};
151
152GNUNET_NETWORK_STRUCT_END
153
154struct RefreshCommitCoin
155{
156 struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
157 struct TALER_RSA_BlindedSignaturePurpose coin_ev;
158 uint16_t cnc_index;
159 uint16_t newcoin_index;
160 char link_enc[sizeof (struct LinkData)];
161};
162
163
164struct KnownCoin
165{
166 struct TALER_CoinPublicInfo public_info;
167 struct TALER_Amount expended_balance;
168 int is_refreshed;
169 /**
170 * Refreshing session, only valid if
171 * is_refreshed==1.
172 */
173 struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub;
174};
175 34
176int 35int
177TALER_MINT_DB_prepare (PGconn *db_conn); 36TALER_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 @@
28#include <libpq-fe.h> 28#include <libpq-fe.h>
29#include <pthread.h> 29#include <pthread.h>
30#include "mint.h" 30#include "mint.h"
31#include "mint_db.h"
32#include "taler_signatures.h" 31#include "taler_signatures.h"
33#include "taler_rsa.h" 32#include "taler_rsa.h"
34#include "taler_json_lib.h" 33#include "taler_json_lib.h"
@@ -38,6 +37,7 @@
38#include "taler-mint-httpd_deposit.h" 37#include "taler-mint-httpd_deposit.h"
39#include "taler-mint-httpd_withdraw.h" 38#include "taler-mint-httpd_withdraw.h"
40#include "taler-mint-httpd_refresh.h" 39#include "taler-mint-httpd_refresh.h"
40#include "mint_db.h"
41 41
42 42
43/** 43/**
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 @@
25 * - /deposit: check for leaks 25 * - /deposit: check for leaks
26 */ 26 */
27#include "platform.h" 27#include "platform.h"
28#include <pthread.h>
29#include <jansson.h>
28#include "taler-mint-httpd_db.h" 30#include "taler-mint-httpd_db.h"
29#include "taler_signatures.h" 31#include "taler_signatures.h"
32#include "taler-mint-httpd_keys.h"
30#include "taler-mint-httpd_responses.h" 33#include "taler-mint-httpd_responses.h"
31#include "mint_db.h" 34#include "mint_db.h"
32#include "mint.h" 35#include "mint.h"
33#include <pthread.h> 36#include "taler_json_lib.h"
34 37
35 38
36/** 39/**
@@ -48,43 +51,39 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
48 const struct Deposit *deposit) 51 const struct Deposit *deposit)
49{ 52{
50 PGconn *db_conn; 53 PGconn *db_conn;
54 struct Deposit *existing_deposit;
55 int res;
51 56
52 if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) 57 if (NULL == (db_conn = TALER_MINT_DB_get_connection ()))
53 { 58 {
54 GNUNET_break (0); 59 GNUNET_break (0);
55 return TALER_MINT_reply_internal_error (connection, 60 return TALER_MINT_reply_internal_error (connection,
56 "Failed to connect to database\n"); 61 "Failed to connect to database");
57 } 62 }
58 63 res = TALER_MINT_DB_get_deposit (db_conn,
64 &deposit->coin_pub,
65 &existing_deposit);
66 if (GNUNET_YES == res)
59 { 67 {
60 struct Deposit *existing_deposit; 68 // FIXME: memory leak
61 int res; 69 // FIXME: memcmp will not actually work here
62 70 if (0 == memcmp (existing_deposit, deposit, sizeof (struct Deposit)))
63 res = TALER_MINT_DB_get_deposit (db_conn, 71 return TALER_MINT_reply_deposit_success (connection, deposit);
64 &deposit->coin_pub, 72 // FIXME: in the future, check if there's enough credits
65 &existing_deposit); 73 // left on the coin. For now: refuse
66 if (GNUNET_YES == res) 74 // FIXME: return more information here
67 { 75 return TALER_MINT_reply_json_pack (connection,
68 // FIXME: memory leak 76 MHD_HTTP_FORBIDDEN,
69 // FIXME: memcmp will not actually work here 77 "{s:s}",
70 if (0 == memcmp (existing_deposit, deposit, sizeof (struct Deposit))) 78 "error",
71 return TALER_MINT_reply_deposit_success (connection, deposit); 79 "double spending");
72 // FIXME: in the future, check if there's enough credits 80 }
73 // left on the coin. For now: refuse
74 // FIXME: return more information here
75 return TALER_MINT_reply_json_pack (connection,
76 MHD_HTTP_FORBIDDEN,
77 "{s:s}",
78 "error",
79 "double spending");
80 }
81 81
82 if (GNUNET_SYSERR == res) 82 if (GNUNET_SYSERR == res)
83 { 83 {
84 GNUNET_break (0); 84 GNUNET_break (0);
85 /* FIXME: return error message to client via MHD! */ 85 /* FIXME: return error message to client via MHD! */
86 return MHD_NO; 86 return MHD_NO;
87 }
88 } 87 }
89 88
90 { 89 {
@@ -133,3 +132,228 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
133 TALER_MINT_DB_commit (db_conn); 132 TALER_MINT_DB_commit (db_conn);
134 return TALER_MINT_reply_deposit_success (connection, deposit); 133 return TALER_MINT_reply_deposit_success (connection, deposit);
135} 134}
135
136
137/**
138 * Sign a reserve's status with the current signing key.
139 * FIXME: not sure why we do this. Should just return
140 * existing list of operations on the reserve.
141 *
142 * @param reserve the reserve to sign
143 * @param key_state the key state containing the current
144 * signing private key
145 */
146static void
147sign_reserve (struct Reserve *reserve,
148 struct MintKeyState *key_state)
149{
150 reserve->status_sign_pub = key_state->current_sign_key_issue.issue.signkey_pub;
151 reserve->status_sig_purpose.purpose = htonl (TALER_SIGNATURE_RESERVE_STATUS);
152 reserve->status_sig_purpose.size = htonl (sizeof (struct Reserve) -
153 offsetof (struct Reserve, status_sig_purpose));
154 GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv,
155 &reserve->status_sig_purpose,
156 &reserve->status_sig);
157}
158
159
160/**
161 * Execute a /withdraw/status.
162 *
163 * @param connection the MHD connection to handle
164 * @param reserve_pub public key of the reserve to check
165 * @return MHD result code
166 */
167int
168TALER_MINT_db_execute_withdraw_status (struct MHD_Connection *connection,
169 const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub)
170{
171 PGconn *db_conn;
172 int res;
173 struct Reserve reserve;
174 struct MintKeyState *key_state;
175 int must_update = GNUNET_NO;
176
177
178 if (NULL == (db_conn = TALER_MINT_DB_get_connection ()))
179 {
180 GNUNET_break (0);
181 return TALER_MINT_reply_internal_error (connection,
182 "Failed to connect to database");
183 }
184 res = TALER_MINT_DB_get_reserve (db_conn,
185 reserve_pub,
186 &reserve);
187 /* check if these are really the matching error codes,
188 seems odd... */
189 if (GNUNET_SYSERR == res)
190 return TALER_MINT_reply_json_pack (connection,
191 MHD_HTTP_NOT_FOUND,
192 "{s:s}",
193 "error",
194 "Reserve not found");
195 if (GNUNET_OK != res)
196 {
197 GNUNET_break (0);
198 return TALER_MINT_reply_internal_error (connection,
199 "Internal error");
200 }
201 key_state = TALER_MINT_key_state_acquire ();
202 if (0 != memcmp (&key_state->current_sign_key_issue.issue.signkey_pub,
203 &reserve.status_sign_pub,
204 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
205 {
206 sign_reserve (&reserve, key_state);
207 must_update = GNUNET_YES;
208 }
209 if ((GNUNET_YES == must_update) &&
210 (GNUNET_OK != TALER_MINT_DB_update_reserve (db_conn, &reserve, !must_update)))
211 {
212 GNUNET_break (0);
213 return MHD_YES;
214 }
215 return TALER_MINT_reply_withdraw_status_success (connection,
216 &reserve);
217}
218
219
220/**
221 * Execute a /withdraw/sign.
222 *
223 * @param connection the MHD connection to handle
224 * @param wsrd_ro details about the withdraw request
225 * @return MHD result code
226 */
227int
228TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
229 const struct TALER_WithdrawRequest *wsrd_ro)
230{
231 PGconn *db_conn;
232 struct Reserve reserve;
233 struct MintKeyState *key_state;
234 struct CollectableBlindcoin collectable;
235 struct TALER_MINT_DenomKeyIssuePriv *dki;
236 struct TALER_RSA_Signature ev_sig;
237 struct TALER_Amount amount_required;
238 /* FIXME: the fact that we do this here is a sign that we
239 need to have different versions of this struct for
240 the different places it is used! */
241 struct TALER_WithdrawRequest wsrd = *wsrd_ro;
242 int res;
243
244 if (NULL == (db_conn = TALER_MINT_DB_get_connection ()))
245 {
246 // FIXME: return 'internal error'?
247 GNUNET_break (0);
248 return MHD_NO;
249 }
250
251
252 res = TALER_MINT_DB_get_collectable_blindcoin (db_conn,
253 &wsrd.coin_envelope,
254 &collectable);
255 if (GNUNET_SYSERR == res)
256 {
257 // FIXME: return 'internal error'
258 GNUNET_break (0);
259 return MHD_NO;
260 }
261
262 /* Don't sign again if we have already signed the coin */
263 if (GNUNET_YES == res)
264 return TALER_MINT_reply_withdraw_sign_success (connection,
265 &collectable);
266 GNUNET_assert (GNUNET_NO == res);
267 res = TALER_MINT_DB_get_reserve (db_conn,
268 &wsrd.reserve_pub,
269 &reserve);
270 if (GNUNET_SYSERR == res)
271 {
272 // FIXME: return 'internal error'
273 GNUNET_break (0);
274 return MHD_NO;
275 }
276 if (GNUNET_NO == res)
277 return TALER_MINT_reply_json_pack (connection,
278 MHD_HTTP_NOT_FOUND,
279 "{s:s}",
280 "error",
281 "Reserve not found");
282
283 // fill out all the missing info in the request before
284 // we can check the signature on the request
285
286 wsrd.purpose.purpose = htonl (TALER_SIGNATURE_WITHDRAW);
287 wsrd.purpose.size = htonl (sizeof (struct TALER_WithdrawRequest) -
288 offsetof (struct TALER_WithdrawRequest, purpose));
289
290 if (GNUNET_OK !=
291 GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WITHDRAW,
292 &wsrd.purpose,
293 &wsrd.sig,
294 &wsrd.reserve_pub))
295 return TALER_MINT_reply_json_pack (connection,
296 MHD_HTTP_UNAUTHORIZED,
297 "{s:s}",
298 "error", "Invalid Signature");
299
300 key_state = TALER_MINT_key_state_acquire ();
301 dki = TALER_MINT_get_denom_key (key_state,
302 &wsrd.denomination_pub);
303 TALER_MINT_key_state_release (key_state);
304 if (NULL == dki)
305 return TALER_MINT_reply_json_pack (connection,
306 MHD_HTTP_NOT_FOUND,
307 "{s:s}",
308 "error",
309 "Denomination not found");
310
311 amount_required = TALER_amount_ntoh (dki->issue.value);
312 amount_required = TALER_amount_add (amount_required,
313 TALER_amount_ntoh (dki->issue.fee_withdraw));
314
315 if (0 < TALER_amount_cmp (amount_required,
316 TALER_amount_ntoh (reserve.balance)))
317 return TALER_MINT_reply_json_pack (connection,
318 MHD_HTTP_PAYMENT_REQUIRED,
319 "{s:s}",
320 "error",
321 "Insufficient funds");
322 if (GNUNET_OK !=
323 TALER_RSA_sign (dki->denom_priv,
324 &wsrd.coin_envelope,
325 sizeof (struct TALER_RSA_BlindedSignaturePurpose),
326 &ev_sig))
327 {
328 // FIXME: return 'internal error'
329 GNUNET_break (0);
330 return MHD_NO;
331 }
332
333 reserve.balance = TALER_amount_hton (TALER_amount_subtract (TALER_amount_ntoh (reserve.balance),
334 amount_required));
335 if (GNUNET_OK !=
336 TALER_MINT_DB_update_reserve (db_conn,
337 &reserve,
338 GNUNET_YES))
339 {
340 // FIXME: return 'internal error'
341 GNUNET_break (0);
342 return MHD_NO;
343 }
344
345 collectable.ev = wsrd.coin_envelope;
346 collectable.ev_sig = ev_sig;
347 collectable.reserve_pub = wsrd.reserve_pub;
348 collectable.reserve_sig = wsrd.sig;
349 if (GNUNET_OK !=
350 TALER_MINT_DB_insert_collectable_blindcoin (db_conn,
351 &collectable))
352 {
353 // FIXME: return 'internal error'
354 GNUNET_break (0);
355 return GNUNET_NO;;
356 }
357 return TALER_MINT_reply_withdraw_sign_success (connection,
358 &collectable);
359}
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 @@
17 * @file mint/taler-mint_httpd_db.h 17 * @file mint/taler-mint_httpd_db.h
18 * @brief Mint-specific database access 18 * @brief Mint-specific database access
19 * @author Chrisitan Grothoff 19 * @author Chrisitan Grothoff
20 *
21 * TODO:
22 * - revisit and document `struct Deposit` members.
23 */ 20 */
24#ifndef TALER_MINT_HTTPD_DB_H 21#ifndef TALER_MINT_HTTPD_DB_H
25#define TALER_MINT_HTTPD_DB_H 22#define TALER_MINT_HTTPD_DB_H
@@ -29,46 +26,13 @@
29#include <gnunet/gnunet_util_lib.h> 26#include <gnunet/gnunet_util_lib.h>
30#include "taler_util.h" 27#include "taler_util.h"
31#include "taler_rsa.h" 28#include "taler_rsa.h"
29#include "taler-mint-httpd_keys.h"
30#include "mint.h"
32 31
33 32
34/**
35 * Specification for a /deposit operation.
36 */
37struct Deposit
38{
39 /* FIXME: should be TALER_CoinPublicInfo */
40 struct GNUNET_CRYPTO_EddsaPublicKey coin_pub;
41
42 struct TALER_RSA_PublicKeyBinaryEncoded denom_pub;
43
44 struct TALER_RSA_Signature coin_sig;
45
46 struct TALER_RSA_Signature ubsig;
47
48 /**
49 * Type of the deposit (also purpose of the signature). Either
50 * #TALER_SIGNATURE_DEPOSIT or #TALER_SIGNATURE_INCREMENTAL_DEPOSIT.
51 */
52 struct TALER_RSA_SignaturePurpose purpose;
53
54 uint64_t transaction_id;
55
56 struct TALER_AmountNBO amount;
57
58 struct GNUNET_CRYPTO_EddsaPublicKey merchant_pub;
59
60 struct GNUNET_HashCode h_contract;
61
62 struct GNUNET_HashCode h_wire;
63
64 /* TODO: uint16_t wire_size */
65 char wire[]; /* string encoded wire JSON object */
66
67};
68
69 33
70/** 34/**
71 * Execute a deposit. The validity of the coin and signature 35 * Execute a /deposit. The validity of the coin and signature
72 * have already been checked. The database must now check that 36 * have already been checked. The database must now check that
73 * the coin is not (double or over) spent, and execute the 37 * the coin is not (double or over) spent, and execute the
74 * transaction (record details, generate success or failure response). 38 * transaction (record details, generate success or failure response).
@@ -82,4 +46,28 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
82 const struct Deposit *deposit); 46 const struct Deposit *deposit);
83 47
84 48
49/**
50 * Execute a /withdraw/status.
51 *
52 * @param connection the MHD connection to handle
53 * @param reserve_pub public key of the reserve to check
54 * @return MHD result code
55 */
56int
57TALER_MINT_db_execute_withdraw_status (struct MHD_Connection *connection,
58 const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub);
59
60
61/**
62 * Execute a /withdraw/sign.
63 *
64 * @param connection the MHD connection to handle
65 * @param wsrd details about the withdraw request
66 * @return MHD result code
67 */
68int
69TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
70 const struct TALER_WithdrawRequest *wsrd);
71
72
85#endif /* _NEURO_MINT_DB_H */ 73#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 @@
27#include <libpq-fe.h> 27#include <libpq-fe.h>
28#include <pthread.h> 28#include <pthread.h>
29#include "mint.h" 29#include "mint.h"
30#include "mint_db.h"
31#include "taler_signatures.h" 30#include "taler_signatures.h"
32#include "taler_rsa.h" 31#include "taler_rsa.h"
33#include "taler_json_lib.h" 32#include "taler_json_lib.h"
@@ -35,6 +34,7 @@
35#include "taler-mint-httpd_keys.h" 34#include "taler-mint-httpd_keys.h"
36 35
37 36
37
38/** 38/**
39 * Mint key state. Never use directly, instead access via 39 * Mint key state. Never use directly, instead access via
40 * #TALER_MINT_key_state_acquire and #TALER_MINT_key_state_release. 40 * #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 @@
26#include <gnunet/gnunet_util_lib.h> 26#include <gnunet/gnunet_util_lib.h>
27#include <microhttpd.h> 27#include <microhttpd.h>
28#include "taler-mint-httpd.h" 28#include "taler-mint-httpd.h"
29 29#include "mint.h"
30 30
31/** 31/**
32 * Snapshot of the (coin and signing) 32 * 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 @@
19 * @author Florian Dold 19 * @author Florian Dold
20 * @author Benedikt Mueller 20 * @author Benedikt Mueller
21 * @author Christian Grothoff 21 * @author Christian Grothoff
22 *
23 * TODO:
24 * - split properly into parsing, DB-ops and response generation
22 */ 25 */
23#include "platform.h" 26#include "platform.h"
24#include <gnunet/gnunet_util_lib.h> 27#include <gnunet/gnunet_util_lib.h>
@@ -70,6 +73,9 @@ sign_as_json (struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
70} 73}
71 74
72 75
76/**
77 * FIXME: document!
78 */
73static int 79static int
74link_iter (void *cls, 80link_iter (void *cls,
75 const struct LinkDataEnc *link_data_enc, 81 const struct LinkDataEnc *link_data_enc,
@@ -246,9 +252,9 @@ check_confirm_signature (struct MHD_Connection *connection,
246 * 252 *
247 * @param connection the connection to send error responses to 253 * @param connection the connection to send error responses to
248 * @param root the JSON object to extract the coin info from 254 * @param root the JSON object to extract the coin info from
249 * @return GNUNET_YES if coin public info in JSON was valid 255 * @return #GNUNET_YES if coin public info in JSON was valid
250 * GNUNET_NO otherwise 256 * #GNUNET_NO otherwise
251 * GNUNET_SYSERR on internal error 257 * #GNUNET_SYSERR on internal error
252 */ 258 */
253static int 259static int
254request_json_require_coin_public_info (struct MHD_Connection *connection, 260request_json_require_coin_public_info (struct MHD_Connection *connection,
@@ -298,9 +304,9 @@ request_json_require_coin_public_info (struct MHD_Connection *connection,
298 * @param root the JSON object 304 * @param root the JSON object
299 * @param hash_context the hash context that will receive 305 * @param hash_context the hash context that will receive
300 * the coin public keys of the melted coin 306 * the coin public keys of the melted coin
301 * @return a GNUnet result code, GNUNET_OK on success, 307 * @return #GNUNET_OK on success,
302 * GNUNET_NO if an error message was generated, 308 * #GNUNET_NO if an error message was generated,
303 * GNUNET_SYSERR on internal errors (no response generated) 309 * #GNUNET_SYSERR on internal errors (no response generated)
304 */ 310 */
305static int 311static int
306refresh_accept_melts (struct MHD_Connection *connection, 312refresh_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 @@
26 * TODO: 26 * TODO:
27 * - when generating /deposit reply, do include signature of mint 27 * - when generating /deposit reply, do include signature of mint
28 * to say that we accepted it (check reply format) 28 * to say that we accepted it (check reply format)
29 * - when generating /withdraw/status reply, which signature do
30 * we use there? Might want to instead return *all* signatures on the
31 * existig withdraw operations, instead of Mint's signature
32 * (check reply format, adjust `struct Reserve` if needed)
29 */ 33 */
30#include "platform.h" 34#include "platform.h"
31#include "taler-mint-httpd_responses.h" 35#include "taler-mint-httpd_responses.h"
36#include "taler_json_lib.h"
32 37
33 38
34/** 39/**
@@ -229,4 +234,61 @@ TALER_MINT_reply_deposit_success (struct MHD_Connection *connection,
229 "DEPOSIT_OK"); 234 "DEPOSIT_OK");
230} 235}
231 236
237
238/**
239 * Send reserve status information to client.
240 *
241 * @param connection connection to the client
242 * @param reserve reserve status information to return
243 * @return MHD result code
244 */
245int
246TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection,
247 const struct Reserve *reserve)
248{
249 json_t *json;
250
251 /* Convert the public information of a reserve (i.e.
252 excluding private key) to a JSON object. */
253 json = json_object ();
254 json_object_set_new (json,
255 "balance",
256 TALER_JSON_from_amount (TALER_amount_ntoh (reserve->balance)));
257 json_object_set_new (json,
258 "expiration",
259 TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (reserve->expiration)));
260 json_object_set_new (json,
261 "signature",
262 TALER_JSON_from_sig (&reserve->status_sig_purpose,
263 &reserve->status_sig));
264
265 return TALER_MINT_reply_json (connection,
266 json,
267 MHD_HTTP_OK);
268}
269
270
271/**
272 * Send blinded coin information to client.
273 *
274 * @param connection connection to the client
275 * @param collectable blinded coin to return
276 * @return MHD result code
277 */
278int
279TALER_MINT_reply_withdraw_sign_success (struct MHD_Connection *connection,
280 const struct CollectableBlindcoin *collectable)
281{
282 json_t *root = json_object ();
283
284 json_object_set_new (root, "ev_sig",
285 TALER_JSON_from_data (&collectable->ev_sig,
286 sizeof (struct TALER_RSA_Signature)));
287 return TALER_MINT_reply_json (connection,
288 root,
289 MHD_HTTP_OK);
290}
291
292
293
232/* end of taler-mint-httpd_responses.c */ 294/* 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 @@
31#include <libpq-fe.h> 31#include <libpq-fe.h>
32#include <pthread.h> 32#include <pthread.h>
33#include "taler-mint-httpd.h" 33#include "taler-mint-httpd.h"
34#include "taler-mint-httpd_db.h"
34#include "taler-mint-httpd_mhd.h" 35#include "taler-mint-httpd_mhd.h"
35#include "mint_db.h"
36 36
37 37
38/** 38/**
@@ -135,5 +135,28 @@ TALER_MINT_reply_deposit_success (struct MHD_Connection *connection,
135 const struct Deposit *deposit); 135 const struct Deposit *deposit);
136 136
137 137
138/**
139 * Send reserve status information to client.
140 *
141 * @param connection connection to the client
142 * @param reserve reserve status information to return
143 * @return MHD result code
144 */
145int
146TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection,
147 const struct Reserve *reserve);
148
149
150/**
151 * Send blinded coin information to client.
152 *
153 * @param connection connection to the client
154 * @param collectable blinded coin to return
155 * @return MHD result code
156 */
157int
158TALER_MINT_reply_withdraw_sign_success (struct MHD_Connection *connection,
159 const struct CollectableBlindcoin *collectable);
160
138 161
139#endif 162#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 @@
19 * @author Florian Dold 19 * @author Florian Dold
20 * @author Benedikt Mueller 20 * @author Benedikt Mueller
21 * @author Christian Grothoff 21 * @author Christian Grothoff
22 *
23 * TODO:
24 * - support variable-size RSA keys
22 */ 25 */
23#include "platform.h" 26#include "platform.h"
24#include <gnunet/gnunet_util_lib.h> 27#include <gnunet/gnunet_util_lib.h>
@@ -33,63 +36,13 @@
33#include "taler_json_lib.h" 36#include "taler_json_lib.h"
34#include "taler-mint-httpd_parsing.h" 37#include "taler-mint-httpd_parsing.h"
35#include "taler-mint-httpd_keys.h" 38#include "taler-mint-httpd_keys.h"
39#include "taler-mint-httpd_db.h"
36#include "taler-mint-httpd_mhd.h" 40#include "taler-mint-httpd_mhd.h"
37#include "taler-mint-httpd_withdraw.h" 41#include "taler-mint-httpd_withdraw.h"
38#include "taler-mint-httpd_responses.h" 42#include "taler-mint-httpd_responses.h"
39 43
40 44
41/** 45/**
42 * Convert a signature (with purpose) to
43 * a JSON object representation.
44 *
45 * @param purpose purpose of the signature
46 * @param signature the signature
47 * @return the JSON reporesentation of the signature with purpose
48 */
49static json_t *
50sig_to_json (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
51 const struct GNUNET_CRYPTO_EddsaSignature *signature)
52{
53 json_t *root;
54 json_t *el;
55
56 root = json_object ();
57
58 el = json_integer ((json_int_t) ntohl (purpose->size));
59 json_object_set_new (root, "size", el);
60
61 el = json_integer ((json_int_t) ntohl (purpose->purpose));
62 json_object_set_new (root, "purpose", el);
63
64 el = TALER_JSON_from_data (signature, sizeof (struct GNUNET_CRYPTO_EddsaSignature));
65 json_object_set_new (root, "sig", el);
66
67 return root;
68}
69
70
71/**
72 * Sign a reserve's status with the current signing key.
73 *
74 * @param reserve the reserve to sign
75 * @param key_state the key state containing the current
76 * signing private key
77 */
78static void
79sign_reserve (struct Reserve *reserve,
80 struct MintKeyState *key_state)
81{
82 reserve->status_sign_pub = key_state->current_sign_key_issue.issue.signkey_pub;
83 reserve->status_sig_purpose.purpose = htonl (TALER_SIGNATURE_RESERVE_STATUS);
84 reserve->status_sig_purpose.size = htonl (sizeof (struct Reserve) -
85 offsetof (struct Reserve, status_sig_purpose));
86 GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv,
87 &reserve->status_sig_purpose,
88 &reserve->status_sig);
89}
90
91
92/**
93 * Handle a "/withdraw/status" request 46 * Handle a "/withdraw/status" request
94 * 47 *
95 * @param rh context of the handler 48 * @param rh context of the handler
@@ -107,100 +60,18 @@ TALER_MINT_handler_withdraw_status (struct RequestHandler *rh,
107 size_t *upload_data_size) 60 size_t *upload_data_size)
108{ 61{
109 struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub; 62 struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
110 PGconn *db_conn;
111 int res; 63 int res;
112 struct Reserve reserve;
113 struct MintKeyState *key_state;
114 int must_update = GNUNET_NO;
115 json_t *json;
116 64
117 res = TALER_MINT_mhd_request_arg_data (connection, 65 res = TALER_MINT_mhd_request_arg_data (connection,
118 "reserve_pub", 66 "reserve_pub",
119 &reserve_pub, 67 &reserve_pub,
120 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); 68 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
121 if (GNUNET_SYSERR == res)
122 {
123 // FIXME: return 'internal error'
124 GNUNET_break (0);
125 return MHD_NO;
126 }
127 if (GNUNET_OK != res)
128 return MHD_YES;
129 if (NULL == (db_conn = TALER_MINT_DB_get_connection ()))
130 {
131 // FIXME: return 'internal error'?
132 GNUNET_break (0);
133 return MHD_NO;
134 }
135 res = TALER_MINT_DB_get_reserve (db_conn,
136 &reserve_pub,
137 &reserve);
138 if (GNUNET_SYSERR == res) 69 if (GNUNET_SYSERR == res)
139 return TALER_MINT_reply_json_pack (connection, 70 return MHD_NO; /* internal error */
140 MHD_HTTP_NOT_FOUND, 71 if (GNUNET_NO == res)
141 "{s:s}", 72 return MHD_YES; /* parse error */
142 "error", 73 return TALER_MINT_db_execute_withdraw_status (connection,
143 "Reserve not found"); 74 &reserve_pub);
144 if (GNUNET_OK != res)
145 {
146 // FIXME: return 'internal error'?
147 GNUNET_break (0);
148 return MHD_NO;
149 }
150 key_state = TALER_MINT_key_state_acquire ();
151 if (0 != memcmp (&key_state->current_sign_key_issue.issue.signkey_pub,
152 &reserve.status_sign_pub,
153 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
154 {
155 sign_reserve (&reserve, key_state);
156 must_update = GNUNET_YES;
157 }
158 if ((GNUNET_YES == must_update) &&
159 (GNUNET_OK != TALER_MINT_DB_update_reserve (db_conn, &reserve, !must_update)))
160 {
161 GNUNET_break (0);
162 return MHD_YES;
163 }
164
165 /* Convert the public information of a reserve (i.e.
166 excluding private key) to a JSON object. */
167 json = json_object ();
168 json_object_set_new (json,
169 "balance",
170 TALER_JSON_from_amount (TALER_amount_ntoh (reserve.balance)));
171 json_object_set_new (json,
172 "expiration",
173 TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (reserve.expiration)));
174 json_object_set_new (json,
175 "signature",
176 sig_to_json (&reserve.status_sig_purpose,
177 &reserve.status_sig));
178
179 return TALER_MINT_reply_json (connection,
180 json,
181 MHD_HTTP_OK);
182}
183
184
185/**
186 * Send positive, normal response for "/withdraw/sign".
187 *
188 * @param connection the connection to send the response to
189 * @param collectable the collectable blindcoin (i.e. the blindly signed coin)
190 * @return a MHD result code
191 */
192static int
193helper_withdraw_sign_send_reply (struct MHD_Connection *connection,
194 const struct CollectableBlindcoin *collectable)
195{
196 json_t *root = json_object ();
197
198 json_object_set_new (root, "ev_sig",
199 TALER_JSON_from_data (&collectable->ev_sig,
200 sizeof (struct TALER_RSA_Signature)));
201 return TALER_MINT_reply_json (connection,
202 root,
203 MHD_HTTP_OK);
204} 75}
205 76
206 77
@@ -223,180 +94,44 @@ TALER_MINT_handler_withdraw_sign (struct RequestHandler *rh,
223{ 94{
224 struct TALER_WithdrawRequest wsrd; 95 struct TALER_WithdrawRequest wsrd;
225 int res; 96 int res;
226 PGconn *db_conn;
227 struct Reserve reserve;
228 struct MintKeyState *key_state;
229 struct CollectableBlindcoin collectable;
230 struct TALER_MINT_DenomKeyIssuePriv *dki;
231 struct TALER_RSA_Signature ev_sig;
232 struct TALER_Amount amount_required;
233 97
234 memset (&wsrd,
235 0,
236 sizeof (struct TALER_WithdrawRequest));
237 res = TALER_MINT_mhd_request_arg_data (connection, 98 res = TALER_MINT_mhd_request_arg_data (connection,
238 "reserve_pub", 99 "reserve_pub",
239 &wsrd.reserve_pub, 100 &wsrd.reserve_pub,
240 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); 101 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
241 if (GNUNET_SYSERR == res) 102 if (GNUNET_SYSERR == res)
242 { 103 return MHD_NO; /* internal error */
243 // FIXME: return 'internal error'? 104 if (GNUNET_NO == res)
244 GNUNET_break (0); 105 return MHD_YES; /* invalid request */
245 return MHD_NO; 106
246 } 107 /* FIXME: handle variable-size signing keys! */
247 if (GNUNET_OK != res)
248 return MHD_YES;
249 res = TALER_MINT_mhd_request_arg_data (connection, 108 res = TALER_MINT_mhd_request_arg_data (connection,
250 "denom_pub", 109 "denom_pub",
251 &wsrd.denomination_pub, 110 &wsrd.denomination_pub,
252 sizeof (struct TALER_RSA_PublicKeyBinaryEncoded)); 111 sizeof (struct TALER_RSA_PublicKeyBinaryEncoded));
253 if (GNUNET_SYSERR == res) 112 if (GNUNET_SYSERR == res)
254 { 113 return MHD_NO; /* internal error */
255 // FIXME: return 'internal error'? 114 if (GNUNET_NO == res)
256 GNUNET_break (0); 115 return MHD_YES; /* invalid request */
257 return MHD_NO;
258 }
259 if (GNUNET_OK != res)
260 return MHD_YES;
261 res = TALER_MINT_mhd_request_arg_data (connection, 116 res = TALER_MINT_mhd_request_arg_data (connection,
262 "coin_ev", 117 "coin_ev",
263 &wsrd.coin_envelope, 118 &wsrd.coin_envelope,
264 sizeof (struct TALER_RSA_Signature)); 119 sizeof (struct TALER_RSA_Signature));
265 if (GNUNET_SYSERR == res) 120 if (GNUNET_SYSERR == res)
266 { 121 return MHD_NO; /* internal error */
267 // FIXME: return 'internal error'? 122 if (GNUNET_NO == res)
268 GNUNET_break (0); 123 return MHD_YES; /* invalid request */
269 return MHD_NO;
270 }
271 if (GNUNET_OK != res)
272 return MHD_YES;
273 res = TALER_MINT_mhd_request_arg_data (connection, 124 res = TALER_MINT_mhd_request_arg_data (connection,
274 "reserve_sig", 125 "reserve_sig",
275 &wsrd.sig, 126 &wsrd.sig,
276 sizeof (struct GNUNET_CRYPTO_EddsaSignature)); 127 sizeof (struct GNUNET_CRYPTO_EddsaSignature));
277 if (GNUNET_SYSERR == res) 128 if (GNUNET_SYSERR == res)
278 { 129 return MHD_NO; /* internal error */
279 // FIXME: return 'internal error'?
280 GNUNET_break (0);
281 return MHD_NO;
282 }
283 if (GNUNET_OK != res)
284 return MHD_YES;
285
286 if (NULL == (db_conn = TALER_MINT_DB_get_connection ()))
287 {
288 // FIXME: return 'internal error'?
289 GNUNET_break (0);
290 return MHD_NO;
291 }
292
293 res = TALER_MINT_DB_get_collectable_blindcoin (db_conn,
294 &wsrd.coin_envelope,
295 &collectable);
296 if (GNUNET_SYSERR == res)
297 {
298 // FIXME: return 'internal error'
299 GNUNET_break (0);
300 return MHD_NO;
301 }
302
303 /* Don't sign again if we have already signed the coin */
304 if (GNUNET_YES == res)
305 return helper_withdraw_sign_send_reply (connection,
306 &collectable);
307 GNUNET_assert (GNUNET_NO == res);
308 res = TALER_MINT_DB_get_reserve (db_conn,
309 &wsrd.reserve_pub,
310 &reserve);
311 if (GNUNET_SYSERR == res)
312 {
313 // FIXME: return 'internal error'
314 GNUNET_break (0);
315 return MHD_NO;
316 }
317 if (GNUNET_NO == res) 130 if (GNUNET_NO == res)
318 return TALER_MINT_reply_json_pack (connection, 131 return MHD_YES; /* invalid request */
319 MHD_HTTP_NOT_FOUND,
320 "{s:s}",
321 "error",
322 "Reserve not found");
323
324 // fill out all the missing info in the request before
325 // we can check the signature on the request
326
327 wsrd.purpose.purpose = htonl (TALER_SIGNATURE_WITHDRAW);
328 wsrd.purpose.size = htonl (sizeof (struct TALER_WithdrawRequest) -
329 offsetof (struct TALER_WithdrawRequest, purpose));
330
331 if (GNUNET_OK !=
332 GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WITHDRAW,
333 &wsrd.purpose,
334 &wsrd.sig,
335 &wsrd.reserve_pub))
336 return TALER_MINT_reply_json_pack (connection,
337 MHD_HTTP_UNAUTHORIZED,
338 "{s:s}",
339 "error", "Invalid Signature");
340
341 key_state = TALER_MINT_key_state_acquire ();
342 dki = TALER_MINT_get_denom_key (key_state,
343 &wsrd.denomination_pub);
344 TALER_MINT_key_state_release (key_state);
345 if (NULL == dki)
346 return TALER_MINT_reply_json_pack (connection,
347 MHD_HTTP_NOT_FOUND,
348 "{s:s}",
349 "error",
350 "Denomination not found");
351
352 amount_required = TALER_amount_ntoh (dki->issue.value);
353 amount_required = TALER_amount_add (amount_required,
354 TALER_amount_ntoh (dki->issue.fee_withdraw));
355
356 if (0 < TALER_amount_cmp (amount_required,
357 TALER_amount_ntoh (reserve.balance)))
358 return TALER_MINT_reply_json_pack (connection,
359 MHD_HTTP_PAYMENT_REQUIRED,
360 "{s:s}",
361 "error",
362 "Insufficient funds");
363 if (GNUNET_OK !=
364 TALER_RSA_sign (dki->denom_priv,
365 &wsrd.coin_envelope,
366 sizeof (struct TALER_RSA_BlindedSignaturePurpose),
367 &ev_sig))
368 {
369 // FIXME: return 'internal error'
370 GNUNET_break (0);
371 return MHD_NO;
372 }
373
374 reserve.balance = TALER_amount_hton (TALER_amount_subtract (TALER_amount_ntoh (reserve.balance),
375 amount_required));
376 if (GNUNET_OK !=
377 TALER_MINT_DB_update_reserve (db_conn,
378 &reserve,
379 GNUNET_YES))
380 {
381 // FIXME: return 'internal error'
382 GNUNET_break (0);
383 return MHD_NO;
384 }
385 132
386 collectable.ev = wsrd.coin_envelope; 133 return TALER_MINT_db_execute_withdraw_sign (connection,
387 collectable.ev_sig = ev_sig; 134 &wsrd);
388 collectable.reserve_pub = wsrd.reserve_pub;
389 collectable.reserve_sig = wsrd.sig;
390 if (GNUNET_OK !=
391 TALER_MINT_DB_insert_collectable_blindcoin (db_conn,
392 &collectable))
393 {
394 // FIXME: return 'internal error'
395 GNUNET_break (0);
396 return GNUNET_NO;;
397 }
398 return helper_withdraw_sign_send_reply (connection,
399 &collectable);
400} 135}
401 136
402/* end of taler-mint-httpd_withdraw.c */ 137/* end of taler-mint-httpd_withdraw.c */
diff --git a/src/util/json.c b/src/util/json.c
index 269e6cf26..d66c95c43 100644
--- a/src/util/json.c
+++ b/src/util/json.c
@@ -90,6 +90,34 @@ TALER_JSON_from_abs (struct GNUNET_TIME_Absolute stamp)
90} 90}
91 91
92 92
93/**
94 * Convert a signature (with purpose) to a JSON object representation.
95 *
96 * @param purpose purpose of the signature
97 * @param signature the signature
98 * @return the JSON reporesentation of the signature with purpose
99 */
100json_t *
101TALER_JSON_from_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
102 const struct GNUNET_CRYPTO_EddsaSignature *signature)
103{
104 json_t *root;
105 json_t *el;
106
107 root = json_object ();
108
109 el = json_integer ((json_int_t) ntohl (purpose->size));
110 json_object_set_new (root, "size", el);
111
112 el = json_integer ((json_int_t) ntohl (purpose->purpose));
113 json_object_set_new (root, "purpose", el);
114
115 el = TALER_JSON_from_data (signature, sizeof (struct GNUNET_CRYPTO_EddsaSignature));
116 json_object_set_new (root, "sig", el);
117
118 return root;
119}
120
93 121
94/** 122/**
95 * Convert binary data to a JSON string 123 * Convert binary data to a JSON string