Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2022 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify
6 : it under the terms of the GNU Affero General Public License as
7 : published by the Free Software Foundation; either version 3,
8 : or (at your option) any later version.
9 :
10 : TALER is distributed in the hope that it will be useful,
11 : but WITHOUT ANY WARRANTY; without even the implied warranty
12 : of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 : See the GNU Affero General Public License for more details.
14 :
15 : You should have received a copy of the GNU Affero General
16 : Public License along with TALER; see the file COPYING. If not,
17 : see <http://www.gnu.org/licenses/>
18 : */
19 : /**
20 : * @file taler-exchange-httpd_csr.c
21 : * @brief Handle /csr requests
22 : * @author Lucien Heuzeveldt
23 : * @author Gian Demarmles
24 : */
25 : #include "platform.h"
26 : #include <gnunet/gnunet_util_lib.h>
27 : #include <jansson.h>
28 : #include "taler_json_lib.h"
29 : #include "taler_mhd_lib.h"
30 : #include "taler-exchange-httpd_csr.h"
31 : #include "taler-exchange-httpd_responses.h"
32 : #include "taler-exchange-httpd_keys.h"
33 :
34 :
35 : MHD_RESULT
36 0 : TEH_handler_csr_melt (struct TEH_RequestContext *rc,
37 : const json_t *root,
38 : const char *const args[])
39 : {
40 : struct TALER_RefreshMasterSecretP rms;
41 : unsigned int csr_requests_num;
42 : json_t *csr_requests;
43 : struct GNUNET_JSON_Specification spec[] = {
44 0 : GNUNET_JSON_spec_fixed_auto ("rms",
45 : &rms),
46 0 : GNUNET_JSON_spec_json ("nks",
47 : &csr_requests),
48 0 : GNUNET_JSON_spec_end ()
49 : };
50 : enum TALER_ErrorCode ec;
51 : struct TEH_DenominationKey *dk;
52 :
53 : (void) args;
54 : /* parse input */
55 : {
56 : enum GNUNET_GenericReturnValue res;
57 :
58 0 : res = TALER_MHD_parse_json_data (rc->connection,
59 : root,
60 : spec);
61 0 : if (GNUNET_OK != res)
62 0 : return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
63 : }
64 0 : csr_requests_num = json_array_size (csr_requests);
65 0 : if ( (TALER_MAX_FRESH_COINS <= csr_requests_num) ||
66 : (0 == csr_requests_num) )
67 : {
68 0 : GNUNET_JSON_parse_free (spec);
69 0 : return TALER_MHD_reply_with_error (
70 : rc->connection,
71 : MHD_HTTP_BAD_REQUEST,
72 : TALER_EC_EXCHANGE_GENERIC_NEW_DENOMS_ARRAY_SIZE_EXCESSIVE,
73 : NULL);
74 : }
75 :
76 0 : {
77 0 : struct TALER_ExchangeWithdrawValues ewvs[csr_requests_num];
78 :
79 0 : {
80 0 : struct TALER_CsNonce nonces[csr_requests_num];
81 0 : struct TALER_DenominationHashP denom_pub_hashes[csr_requests_num];
82 :
83 0 : for (unsigned int i = 0; i < csr_requests_num; i++)
84 : {
85 : uint32_t coin_off;
86 0 : struct TALER_DenominationHashP *denom_pub_hash = &denom_pub_hashes[i];
87 : struct GNUNET_JSON_Specification csr_spec[] = {
88 0 : GNUNET_JSON_spec_uint32 ("coin_offset",
89 : &coin_off),
90 0 : GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
91 : denom_pub_hash),
92 0 : GNUNET_JSON_spec_end ()
93 : };
94 : enum GNUNET_GenericReturnValue res;
95 :
96 0 : res = TALER_MHD_parse_json_array (rc->connection,
97 : csr_requests,
98 : csr_spec,
99 : i,
100 : -1);
101 0 : if (GNUNET_OK != res)
102 : {
103 0 : GNUNET_JSON_parse_free (spec);
104 0 : return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
105 : }
106 0 : TALER_cs_refresh_nonce_derive (&rms,
107 : coin_off,
108 : &nonces[i]);
109 : }
110 0 : GNUNET_JSON_parse_free (spec);
111 :
112 0 : for (unsigned int i = 0; i < csr_requests_num; i++)
113 : {
114 0 : const struct TALER_CsNonce *nonce = &nonces[i];
115 0 : const struct TALER_DenominationHashP *denom_pub_hash =
116 : &denom_pub_hashes[i];
117 0 : struct TALER_DenominationCSPublicRPairP *r_pub
118 : = &ewvs[i].details.cs_values;
119 :
120 0 : ewvs[i].cipher = TALER_DENOMINATION_CS;
121 : /* check denomination referenced by denom_pub_hash */
122 : {
123 : struct TEH_KeyStateHandle *ksh;
124 :
125 0 : ksh = TEH_keys_get_state ();
126 0 : if (NULL == ksh)
127 : {
128 0 : return TALER_MHD_reply_with_error (rc->connection,
129 : MHD_HTTP_INTERNAL_SERVER_ERROR,
130 : TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
131 : NULL);
132 : }
133 0 : dk = TEH_keys_denomination_by_hash2 (ksh,
134 : denom_pub_hash,
135 : NULL,
136 : NULL);
137 0 : if (NULL == dk)
138 : {
139 0 : return TEH_RESPONSE_reply_unknown_denom_pub_hash (
140 : rc->connection,
141 0 : &denom_pub_hash[i]);
142 : }
143 0 : if (GNUNET_TIME_absolute_is_past (dk->meta.expire_withdraw.abs_time))
144 : {
145 : /* This denomination is past the expiration time for withdraws/refreshes*/
146 0 : return TEH_RESPONSE_reply_expired_denom_pub_hash (
147 : rc->connection,
148 : denom_pub_hash,
149 : TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
150 : "csr-melt");
151 : }
152 0 : if (GNUNET_TIME_absolute_is_future (dk->meta.start.abs_time))
153 : {
154 : /* This denomination is not yet valid, no need to check
155 : for idempotency! */
156 0 : return TEH_RESPONSE_reply_expired_denom_pub_hash (
157 : rc->connection,
158 : denom_pub_hash,
159 : TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE,
160 : "csr-melt");
161 : }
162 0 : if (dk->recoup_possible)
163 : {
164 : /* This denomination has been revoked */
165 0 : return TEH_RESPONSE_reply_expired_denom_pub_hash (
166 : rc->connection,
167 : denom_pub_hash,
168 : TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED,
169 : "csr-melt");
170 : }
171 0 : if (TALER_DENOMINATION_CS != dk->denom_pub.cipher)
172 : {
173 : /* denomination is valid but not for CS */
174 0 : return TEH_RESPONSE_reply_invalid_denom_cipher_for_operation (
175 : rc->connection,
176 : denom_pub_hash);
177 : }
178 : }
179 :
180 : /* derive r_pub */
181 : // FIXME-#7272: bundle all requests into one derivation request (TEH_keys_..., crypto helper, security module)
182 0 : ec = TEH_keys_denomination_cs_r_pub_melt (denom_pub_hash,
183 : nonce,
184 : r_pub);
185 0 : if (TALER_EC_NONE != ec)
186 : {
187 0 : GNUNET_break (0);
188 0 : return TALER_MHD_reply_with_ec (rc->connection,
189 : ec,
190 : NULL);
191 : }
192 : }
193 : }
194 :
195 : /* send response */
196 : {
197 : json_t *csr_response_ewvs;
198 : json_t *csr_response;
199 :
200 0 : csr_response_ewvs = json_array ();
201 0 : for (unsigned int i = 0; i < csr_requests_num; i++)
202 : {
203 : json_t *csr_obj;
204 :
205 0 : csr_obj = GNUNET_JSON_PACK (
206 : TALER_JSON_pack_exchange_withdraw_values ("ewv",
207 : &ewvs[i]));
208 0 : GNUNET_assert (NULL != csr_obj);
209 0 : GNUNET_assert (0 ==
210 : json_array_append_new (csr_response_ewvs,
211 : csr_obj));
212 : }
213 0 : csr_response = GNUNET_JSON_PACK (
214 : GNUNET_JSON_pack_array_steal ("ewvs",
215 : csr_response_ewvs));
216 0 : GNUNET_assert (NULL != csr_response);
217 0 : return TALER_MHD_reply_json_steal (rc->connection,
218 : csr_response,
219 : MHD_HTTP_OK);
220 : }
221 : }
222 : }
223 :
224 :
225 : MHD_RESULT
226 0 : TEH_handler_csr_withdraw (struct TEH_RequestContext *rc,
227 : const json_t *root,
228 : const char *const args[])
229 : {
230 : struct TALER_CsNonce nonce;
231 : struct TALER_DenominationHashP denom_pub_hash;
232 0 : struct TALER_ExchangeWithdrawValues ewv = {
233 : .cipher = TALER_DENOMINATION_CS
234 : };
235 : struct GNUNET_JSON_Specification spec[] = {
236 0 : GNUNET_JSON_spec_fixed ("nonce",
237 : &nonce,
238 : sizeof (struct TALER_CsNonce)),
239 0 : GNUNET_JSON_spec_fixed ("denom_pub_hash",
240 : &denom_pub_hash,
241 : sizeof (struct TALER_DenominationHashP)),
242 0 : GNUNET_JSON_spec_end ()
243 : };
244 : struct TEH_DenominationKey *dk;
245 :
246 : (void) args;
247 : {
248 : enum GNUNET_GenericReturnValue res;
249 :
250 0 : res = TALER_MHD_parse_json_data (rc->connection,
251 : root,
252 : spec);
253 0 : if (GNUNET_OK != res)
254 0 : return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
255 : }
256 :
257 : {
258 : struct TEH_KeyStateHandle *ksh;
259 :
260 0 : ksh = TEH_keys_get_state ();
261 0 : if (NULL == ksh)
262 : {
263 0 : return TALER_MHD_reply_with_error (rc->connection,
264 : MHD_HTTP_INTERNAL_SERVER_ERROR,
265 : TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
266 : NULL);
267 : }
268 0 : dk = TEH_keys_denomination_by_hash2 (ksh,
269 : &denom_pub_hash,
270 : NULL,
271 : NULL);
272 0 : if (NULL == dk)
273 : {
274 0 : return TEH_RESPONSE_reply_unknown_denom_pub_hash (
275 : rc->connection,
276 : &denom_pub_hash);
277 : }
278 0 : if (GNUNET_TIME_absolute_is_past (dk->meta.expire_withdraw.abs_time))
279 : {
280 : /* This denomination is past the expiration time for withdraws/refreshes*/
281 0 : return TEH_RESPONSE_reply_expired_denom_pub_hash (
282 : rc->connection,
283 : &denom_pub_hash,
284 : TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
285 : "csr-withdraw");
286 : }
287 0 : if (GNUNET_TIME_absolute_is_future (dk->meta.start.abs_time))
288 : {
289 : /* This denomination is not yet valid, no need to check
290 : for idempotency! */
291 0 : return TEH_RESPONSE_reply_expired_denom_pub_hash (
292 : rc->connection,
293 : &denom_pub_hash,
294 : TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE,
295 : "csr-withdraw");
296 : }
297 0 : if (dk->recoup_possible)
298 : {
299 : /* This denomination has been revoked */
300 0 : return TEH_RESPONSE_reply_expired_denom_pub_hash (
301 : rc->connection,
302 : &denom_pub_hash,
303 : TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED,
304 : "csr-withdraw");
305 : }
306 0 : if (TALER_DENOMINATION_CS != dk->denom_pub.cipher)
307 : {
308 : /* denomination is valid but not for CS */
309 0 : return TEH_RESPONSE_reply_invalid_denom_cipher_for_operation (
310 : rc->connection,
311 : &denom_pub_hash);
312 : }
313 : }
314 :
315 : /* derive r_pub */
316 : {
317 : enum TALER_ErrorCode ec;
318 :
319 0 : ec = TEH_keys_denomination_cs_r_pub_withdraw (&denom_pub_hash,
320 : &nonce,
321 : &ewv.details.cs_values);
322 0 : if (TALER_EC_NONE != ec)
323 : {
324 0 : GNUNET_break (0);
325 0 : return TALER_MHD_reply_with_ec (rc->connection,
326 : ec,
327 : NULL);
328 : }
329 : }
330 :
331 : {
332 : json_t *csr_obj;
333 :
334 0 : csr_obj = GNUNET_JSON_PACK (
335 : TALER_JSON_pack_exchange_withdraw_values ("ewv",
336 : &ewv));
337 0 : GNUNET_assert (NULL != csr_obj);
338 0 : return TALER_MHD_reply_json_steal (rc->connection,
339 : csr_obj,
340 : MHD_HTTP_OK);
341 : }
342 : }
343 :
344 :
345 : /* end of taler-exchange-httpd_csr.c */
|