Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2015-2022 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU General Public License as published by the Free Software
7 : Foundation; either version 3, or (at your option) any later version.
8 :
9 : TALER is distributed in the hope that it will be useful, but WITHOUT ANY
10 : WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 : A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : TALER; see the file COPYING. If not, see
15 : <http://www.gnu.org/licenses/>
16 : */
17 : /**
18 : * @file lib/exchange_api_common.c
19 : * @brief common functions for the exchange API
20 : * @author Christian Grothoff
21 : */
22 : #include "platform.h"
23 : #include "taler_json_lib.h"
24 : #include <gnunet/gnunet_curl_lib.h>
25 : #include "exchange_api_common.h"
26 : #include "exchange_api_handle.h"
27 : #include "taler_signatures.h"
28 :
29 :
30 : /**
31 : * Context for history entry helpers.
32 : */
33 : struct HistoryParseContext
34 : {
35 :
36 : /**
37 : * Exchange we use.
38 : */
39 : struct TALER_EXCHANGE_Handle *exchange;
40 :
41 : /**
42 : * Our reserve public key.
43 : */
44 : const struct TALER_ReservePublicKeyP *reserve_pub;
45 :
46 : /**
47 : * Array of UUIDs.
48 : */
49 : struct GNUNET_HashCode *uuids;
50 :
51 : /**
52 : * Where to sum up total inbound amounts.
53 : */
54 : struct TALER_Amount *total_in;
55 :
56 : /**
57 : * Where to sum up total outbound amounts.
58 : */
59 : struct TALER_Amount *total_out;
60 :
61 : /**
62 : * Number of entries already used in @e uuids.
63 : */
64 : unsigned int uuid_off;
65 : };
66 :
67 :
68 : /**
69 : * Type of a function called to parse a reserve history
70 : * entry @a rh.
71 : *
72 : * @param[in,out] rh where to write the result
73 : * @param[in,out] uc UUID context for duplicate detection
74 : * @param transaction the transaction to parse
75 : * @return #GNUNET_OK on success
76 : */
77 : typedef enum GNUNET_GenericReturnValue
78 : (*ParseHelper)(struct TALER_EXCHANGE_ReserveHistoryEntry *rh,
79 : struct HistoryParseContext *uc,
80 : const json_t *transaction);
81 :
82 :
83 : /**
84 : * Parse "credit" reserve history entry.
85 : *
86 : * @param[in,out] rh entry to parse
87 : * @param uc our context
88 : * @param transaction the transaction to parse
89 : * @return #GNUNET_OK on success
90 : */
91 : static enum GNUNET_GenericReturnValue
92 0 : parse_credit (struct TALER_EXCHANGE_ReserveHistoryEntry *rh,
93 : struct HistoryParseContext *uc,
94 : const json_t *transaction)
95 : {
96 : const char *wire_url;
97 : uint64_t wire_reference;
98 : struct GNUNET_TIME_Timestamp timestamp;
99 : struct GNUNET_JSON_Specification withdraw_spec[] = {
100 0 : GNUNET_JSON_spec_uint64 ("wire_reference",
101 : &wire_reference),
102 0 : GNUNET_JSON_spec_timestamp ("timestamp",
103 : ×tamp),
104 0 : GNUNET_JSON_spec_string ("sender_account_url",
105 : &wire_url),
106 0 : GNUNET_JSON_spec_end ()
107 : };
108 :
109 0 : rh->type = TALER_EXCHANGE_RTT_CREDIT;
110 0 : if (0 >
111 0 : TALER_amount_add (uc->total_in,
112 0 : uc->total_in,
113 0 : &rh->amount))
114 : {
115 : /* overflow in history already!? inconceivable! Bad exchange! */
116 0 : GNUNET_break_op (0);
117 0 : return GNUNET_SYSERR;
118 : }
119 0 : if (GNUNET_OK !=
120 0 : GNUNET_JSON_parse (transaction,
121 : withdraw_spec,
122 : NULL, NULL))
123 : {
124 0 : GNUNET_break_op (0);
125 0 : return GNUNET_SYSERR;
126 : }
127 0 : rh->details.in_details.sender_url = GNUNET_strdup (wire_url);
128 0 : rh->details.in_details.wire_reference = wire_reference;
129 0 : rh->details.in_details.timestamp = timestamp;
130 0 : return GNUNET_OK;
131 : }
132 :
133 :
134 : /**
135 : * Parse "credit" reserve history entry.
136 : *
137 : * @param[in,out] rh entry to parse
138 : * @param uc our context
139 : * @param transaction the transaction to parse
140 : * @return #GNUNET_OK on success
141 : */
142 : static enum GNUNET_GenericReturnValue
143 0 : parse_withdraw (struct TALER_EXCHANGE_ReserveHistoryEntry *rh,
144 : struct HistoryParseContext *uc,
145 : const json_t *transaction)
146 : {
147 : struct TALER_ReserveSignatureP sig;
148 : struct TALER_DenominationHashP h_denom_pub;
149 : struct TALER_BlindedCoinHashP bch;
150 : struct TALER_Amount withdraw_fee;
151 : struct GNUNET_JSON_Specification withdraw_spec[] = {
152 0 : GNUNET_JSON_spec_fixed_auto ("reserve_sig",
153 : &sig),
154 0 : TALER_JSON_spec_amount_any ("withdraw_fee",
155 : &withdraw_fee),
156 0 : GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
157 : &h_denom_pub),
158 0 : GNUNET_JSON_spec_fixed_auto ("h_coin_envelope",
159 : &bch),
160 0 : GNUNET_JSON_spec_end ()
161 : };
162 :
163 0 : rh->type = TALER_EXCHANGE_RTT_WITHDRAWAL;
164 0 : if (GNUNET_OK !=
165 0 : GNUNET_JSON_parse (transaction,
166 : withdraw_spec,
167 : NULL, NULL))
168 : {
169 0 : GNUNET_break_op (0);
170 0 : return GNUNET_SYSERR;
171 : }
172 :
173 : /* Check that the signature is a valid withdraw request */
174 0 : if (GNUNET_OK !=
175 0 : TALER_wallet_withdraw_verify (&h_denom_pub,
176 0 : &rh->amount,
177 : &bch,
178 : uc->reserve_pub,
179 : &sig))
180 : {
181 0 : GNUNET_break_op (0);
182 0 : GNUNET_JSON_parse_free (withdraw_spec);
183 0 : return GNUNET_SYSERR;
184 : }
185 : /* check that withdraw fee matches expectations! */
186 : {
187 : const struct TALER_EXCHANGE_Keys *key_state;
188 : const struct TALER_EXCHANGE_DenomPublicKey *dki;
189 :
190 0 : key_state = TALER_EXCHANGE_get_keys (uc->exchange);
191 0 : dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state,
192 : &h_denom_pub);
193 0 : if ( (GNUNET_YES !=
194 0 : TALER_amount_cmp_currency (&withdraw_fee,
195 0 : &dki->fees.withdraw)) ||
196 : (0 !=
197 0 : TALER_amount_cmp (&withdraw_fee,
198 : &dki->fees.withdraw)) )
199 : {
200 0 : GNUNET_break_op (0);
201 0 : GNUNET_JSON_parse_free (withdraw_spec);
202 0 : return GNUNET_SYSERR;
203 : }
204 0 : rh->details.withdraw.fee = withdraw_fee;
205 : }
206 : rh->details.withdraw.out_authorization_sig
207 0 : = json_object_get (transaction,
208 : "signature");
209 : /* Check check that the same withdraw transaction
210 : isn't listed twice by the exchange. We use the
211 : "uuid" array to remember the hashes of all
212 : signatures, and compare the hashes to find
213 : duplicates. */
214 0 : GNUNET_CRYPTO_hash (&sig,
215 : sizeof (sig),
216 0 : &uc->uuids[uc->uuid_off]);
217 0 : for (unsigned int i = 0; i<uc->uuid_off; i++)
218 : {
219 0 : if (0 == GNUNET_memcmp (&uc->uuids[uc->uuid_off],
220 : &uc->uuids[i]))
221 : {
222 0 : GNUNET_break_op (0);
223 0 : GNUNET_JSON_parse_free (withdraw_spec);
224 0 : return GNUNET_SYSERR;
225 : }
226 : }
227 0 : uc->uuid_off++;
228 :
229 0 : if (0 >
230 0 : TALER_amount_add (uc->total_out,
231 0 : uc->total_out,
232 0 : &rh->amount))
233 : {
234 : /* overflow in history already!? inconceivable! Bad exchange! */
235 0 : GNUNET_break_op (0);
236 0 : GNUNET_JSON_parse_free (withdraw_spec);
237 0 : return GNUNET_SYSERR;
238 : }
239 0 : return GNUNET_OK;
240 : }
241 :
242 :
243 : /**
244 : * Parse "recoup" reserve history entry.
245 : *
246 : * @param[in,out] rh entry to parse
247 : * @param uc our context
248 : * @param transaction the transaction to parse
249 : * @return #GNUNET_OK on success
250 : */
251 : static enum GNUNET_GenericReturnValue
252 0 : parse_recoup (struct TALER_EXCHANGE_ReserveHistoryEntry *rh,
253 : struct HistoryParseContext *uc,
254 : const json_t *transaction)
255 : {
256 : const struct TALER_EXCHANGE_Keys *key_state;
257 : struct GNUNET_JSON_Specification recoup_spec[] = {
258 0 : GNUNET_JSON_spec_fixed_auto ("coin_pub",
259 : &rh->details.recoup_details.coin_pub),
260 0 : GNUNET_JSON_spec_fixed_auto ("exchange_sig",
261 : &rh->details.recoup_details.exchange_sig),
262 0 : GNUNET_JSON_spec_fixed_auto ("exchange_pub",
263 : &rh->details.recoup_details.exchange_pub),
264 0 : GNUNET_JSON_spec_timestamp ("timestamp",
265 : &rh->details.recoup_details.timestamp),
266 0 : GNUNET_JSON_spec_end ()
267 : };
268 :
269 0 : rh->type = TALER_EXCHANGE_RTT_RECOUP;
270 0 : if (GNUNET_OK !=
271 0 : GNUNET_JSON_parse (transaction,
272 : recoup_spec,
273 : NULL, NULL))
274 : {
275 0 : GNUNET_break_op (0);
276 0 : return GNUNET_SYSERR;
277 : }
278 0 : key_state = TALER_EXCHANGE_get_keys (uc->exchange);
279 0 : if (GNUNET_OK !=
280 0 : TALER_EXCHANGE_test_signing_key (key_state,
281 0 : &rh->details.
282 : recoup_details.exchange_pub))
283 : {
284 0 : GNUNET_break_op (0);
285 0 : return GNUNET_SYSERR;
286 : }
287 0 : if (GNUNET_OK !=
288 0 : TALER_exchange_online_confirm_recoup_verify (
289 : rh->details.recoup_details.timestamp,
290 0 : &rh->amount,
291 0 : &rh->details.recoup_details.coin_pub,
292 : uc->reserve_pub,
293 0 : &rh->details.recoup_details.exchange_pub,
294 0 : &rh->details.recoup_details.exchange_sig))
295 : {
296 0 : GNUNET_break_op (0);
297 0 : return GNUNET_SYSERR;
298 : }
299 0 : if (0 >
300 0 : TALER_amount_add (uc->total_in,
301 0 : uc->total_in,
302 0 : &rh->amount))
303 : {
304 : /* overflow in history already!? inconceivable! Bad exchange! */
305 0 : GNUNET_break_op (0);
306 0 : return GNUNET_SYSERR;
307 : }
308 0 : return GNUNET_OK;
309 : }
310 :
311 :
312 : /**
313 : * Parse "closing" reserve history entry.
314 : *
315 : * @param[in,out] rh entry to parse
316 : * @param uc our context
317 : * @param transaction the transaction to parse
318 : * @return #GNUNET_OK on success
319 : */
320 : static enum GNUNET_GenericReturnValue
321 0 : parse_closing (struct TALER_EXCHANGE_ReserveHistoryEntry *rh,
322 : struct HistoryParseContext *uc,
323 : const json_t *transaction)
324 : {
325 : const struct TALER_EXCHANGE_Keys *key_state;
326 : struct GNUNET_JSON_Specification closing_spec[] = {
327 0 : GNUNET_JSON_spec_string (
328 : "receiver_account_details",
329 : &rh->details.close_details.receiver_account_details),
330 0 : GNUNET_JSON_spec_fixed_auto ("wtid",
331 : &rh->details.close_details.wtid),
332 0 : GNUNET_JSON_spec_fixed_auto ("exchange_sig",
333 : &rh->details.close_details.exchange_sig),
334 0 : GNUNET_JSON_spec_fixed_auto ("exchange_pub",
335 : &rh->details.close_details.exchange_pub),
336 0 : TALER_JSON_spec_amount_any ("closing_fee",
337 : &rh->details.close_details.fee),
338 0 : GNUNET_JSON_spec_timestamp ("timestamp",
339 : &rh->details.close_details.timestamp),
340 0 : GNUNET_JSON_spec_end ()
341 : };
342 :
343 0 : rh->type = TALER_EXCHANGE_RTT_CLOSE;
344 0 : if (GNUNET_OK !=
345 0 : GNUNET_JSON_parse (transaction,
346 : closing_spec,
347 : NULL, NULL))
348 : {
349 0 : GNUNET_break_op (0);
350 0 : return GNUNET_SYSERR;
351 : }
352 0 : key_state = TALER_EXCHANGE_get_keys (uc->exchange);
353 0 : if (GNUNET_OK !=
354 0 : TALER_EXCHANGE_test_signing_key (
355 : key_state,
356 0 : &rh->details.close_details.exchange_pub))
357 : {
358 0 : GNUNET_break_op (0);
359 0 : return GNUNET_SYSERR;
360 : }
361 0 : if (GNUNET_OK !=
362 0 : TALER_exchange_online_reserve_closed_verify (
363 : rh->details.close_details.timestamp,
364 0 : &rh->amount,
365 0 : &rh->details.close_details.fee,
366 : rh->details.close_details.receiver_account_details,
367 0 : &rh->details.close_details.wtid,
368 : uc->reserve_pub,
369 0 : &rh->details.close_details.exchange_pub,
370 0 : &rh->details.close_details.exchange_sig))
371 : {
372 0 : GNUNET_break_op (0);
373 0 : return GNUNET_SYSERR;
374 : }
375 0 : if (0 >
376 0 : TALER_amount_add (uc->total_out,
377 0 : uc->total_out,
378 0 : &rh->amount))
379 : {
380 : /* overflow in history already!? inconceivable! Bad exchange! */
381 0 : GNUNET_break_op (0);
382 0 : return GNUNET_SYSERR;
383 : }
384 0 : return GNUNET_OK;
385 : }
386 :
387 :
388 : /**
389 : * Parse "merge" reserve history entry.
390 : *
391 : * @param[in,out] rh entry to parse
392 : * @param uc our context
393 : * @param transaction the transaction to parse
394 : * @return #GNUNET_OK on success
395 : */
396 : static enum GNUNET_GenericReturnValue
397 0 : parse_merge (struct TALER_EXCHANGE_ReserveHistoryEntry *rh,
398 : struct HistoryParseContext *uc,
399 : const json_t *transaction)
400 : {
401 : uint32_t flags32;
402 : struct GNUNET_JSON_Specification merge_spec[] = {
403 0 : GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
404 : &rh->details.merge_details.h_contract_terms),
405 0 : GNUNET_JSON_spec_fixed_auto ("merge_pub",
406 : &rh->details.merge_details.merge_pub),
407 0 : GNUNET_JSON_spec_fixed_auto ("purse_pub",
408 : &rh->details.merge_details.purse_pub),
409 0 : GNUNET_JSON_spec_uint32 ("min_age",
410 : &rh->details.merge_details.min_age),
411 0 : GNUNET_JSON_spec_uint32 ("flags",
412 : &flags32),
413 0 : GNUNET_JSON_spec_fixed_auto ("reserve_sig",
414 : &rh->details.merge_details.reserve_sig),
415 0 : TALER_JSON_spec_amount_any ("purse_fee",
416 : &rh->details.merge_details.purse_fee),
417 0 : GNUNET_JSON_spec_timestamp ("merge_timestamp",
418 : &rh->details.merge_details.merge_timestamp),
419 0 : GNUNET_JSON_spec_timestamp ("purse_expiration",
420 : &rh->details.merge_details.purse_expiration),
421 0 : GNUNET_JSON_spec_bool ("merged",
422 : &rh->details.merge_details.merged),
423 0 : GNUNET_JSON_spec_end ()
424 : };
425 :
426 0 : rh->type = TALER_EXCHANGE_RTT_MERGE;
427 0 : if (GNUNET_OK !=
428 0 : GNUNET_JSON_parse (transaction,
429 : merge_spec,
430 : NULL, NULL))
431 : {
432 0 : GNUNET_break_op (0);
433 0 : return GNUNET_SYSERR;
434 : }
435 0 : rh->details.merge_details.flags =
436 : (enum TALER_WalletAccountMergeFlags) flags32;
437 0 : if (GNUNET_OK !=
438 0 : TALER_wallet_account_merge_verify (
439 : rh->details.merge_details.merge_timestamp,
440 0 : &rh->details.merge_details.purse_pub,
441 : rh->details.merge_details.purse_expiration,
442 0 : &rh->details.merge_details.h_contract_terms,
443 0 : &rh->amount,
444 0 : &rh->details.merge_details.purse_fee,
445 : rh->details.merge_details.min_age,
446 : rh->details.merge_details.flags,
447 : uc->reserve_pub,
448 0 : &rh->details.merge_details.reserve_sig))
449 : {
450 0 : GNUNET_break_op (0);
451 0 : return GNUNET_SYSERR;
452 : }
453 0 : if (rh->details.merge_details.merged)
454 : {
455 0 : if (0 >
456 0 : TALER_amount_add (uc->total_in,
457 0 : uc->total_in,
458 0 : &rh->amount))
459 : {
460 : /* overflow in history already!? inconceivable! Bad exchange! */
461 0 : GNUNET_break_op (0);
462 0 : return GNUNET_SYSERR;
463 : }
464 : }
465 : else
466 : {
467 0 : if (0 >
468 0 : TALER_amount_add (uc->total_out,
469 0 : uc->total_out,
470 0 : &rh->details.merge_details.purse_fee))
471 : {
472 : /* overflow in history already!? inconceivable! Bad exchange! */
473 0 : GNUNET_break_op (0);
474 0 : return GNUNET_SYSERR;
475 : }
476 : }
477 0 : return GNUNET_OK;
478 : }
479 :
480 :
481 : /**
482 : * Parse "history" reserve history entry.
483 : *
484 : * @param[in,out] rh entry to parse
485 : * @param uc our context
486 : * @param transaction the transaction to parse
487 : * @return #GNUNET_OK on success
488 : */
489 : static enum GNUNET_GenericReturnValue
490 0 : parse_history (struct TALER_EXCHANGE_ReserveHistoryEntry *rh,
491 : struct HistoryParseContext *uc,
492 : const json_t *transaction)
493 : {
494 : struct GNUNET_JSON_Specification history_spec[] = {
495 0 : GNUNET_JSON_spec_fixed_auto ("reserve_sig",
496 : &rh->details.history_details.reserve_sig),
497 0 : GNUNET_JSON_spec_timestamp ("request_timestamp",
498 : &rh->details.history_details.request_timestamp),
499 0 : GNUNET_JSON_spec_end ()
500 : };
501 :
502 0 : rh->type = TALER_EXCHANGE_RTT_HISTORY;
503 0 : if (GNUNET_OK !=
504 0 : GNUNET_JSON_parse (transaction,
505 : history_spec,
506 : NULL, NULL))
507 : {
508 0 : GNUNET_break_op (0);
509 0 : return GNUNET_SYSERR;
510 : }
511 0 : if (GNUNET_OK !=
512 0 : TALER_wallet_reserve_history_verify (
513 : rh->details.history_details.request_timestamp,
514 0 : &rh->amount,
515 : uc->reserve_pub,
516 0 : &rh->details.history_details.reserve_sig))
517 : {
518 0 : GNUNET_break_op (0);
519 0 : return GNUNET_SYSERR;
520 : }
521 0 : if (0 >
522 0 : TALER_amount_add (uc->total_out,
523 0 : uc->total_out,
524 0 : &rh->amount))
525 : {
526 : /* overflow in history already!? inconceivable! Bad exchange! */
527 0 : GNUNET_break_op (0);
528 0 : return GNUNET_SYSERR;
529 : }
530 0 : return GNUNET_OK;
531 : }
532 :
533 :
534 : enum GNUNET_GenericReturnValue
535 0 : TALER_EXCHANGE_parse_reserve_history (
536 : struct TALER_EXCHANGE_Handle *exchange,
537 : const json_t *history,
538 : const struct TALER_ReservePublicKeyP *reserve_pub,
539 : const char *currency,
540 : struct TALER_Amount *total_in,
541 : struct TALER_Amount *total_out,
542 : unsigned int history_length,
543 : struct TALER_EXCHANGE_ReserveHistoryEntry *rhistory)
544 0 : {
545 : const struct
546 : {
547 : const char *type;
548 : ParseHelper helper;
549 0 : } map[] = {
550 : { "CREDIT", &parse_credit },
551 : { "WITHDRAW", &parse_withdraw },
552 : { "RECOUP", &parse_recoup },
553 : { "MERGE", &parse_merge },
554 : { "CLOSING", &parse_closing },
555 : { "HISTORY", &parse_history },
556 : { NULL, NULL }
557 : };
558 0 : struct GNUNET_HashCode uuid[history_length];
559 0 : struct HistoryParseContext uc = {
560 : .exchange = exchange,
561 : .reserve_pub = reserve_pub,
562 : .uuids = uuid,
563 : .total_in = total_in,
564 : .total_out = total_out
565 : };
566 :
567 0 : GNUNET_assert (GNUNET_OK ==
568 : TALER_amount_set_zero (currency,
569 : total_in));
570 0 : GNUNET_assert (GNUNET_OK ==
571 : TALER_amount_set_zero (currency,
572 : total_out));
573 0 : for (unsigned int off = 0; off<history_length; off++)
574 : {
575 0 : struct TALER_EXCHANGE_ReserveHistoryEntry *rh = &rhistory[off];
576 : json_t *transaction;
577 : struct TALER_Amount amount;
578 : const char *type;
579 : struct GNUNET_JSON_Specification hist_spec[] = {
580 0 : GNUNET_JSON_spec_string ("type",
581 : &type),
582 0 : TALER_JSON_spec_amount_any ("amount",
583 : &amount),
584 : /* 'wire' and 'signature' are optional depending on 'type'! */
585 0 : GNUNET_JSON_spec_end ()
586 : };
587 0 : bool found = false;
588 :
589 0 : transaction = json_array_get (history,
590 : off);
591 0 : if (GNUNET_OK !=
592 0 : GNUNET_JSON_parse (transaction,
593 : hist_spec,
594 : NULL, NULL))
595 : {
596 0 : GNUNET_break_op (0);
597 0 : json_dumpf (transaction,
598 : stderr,
599 : JSON_INDENT (2));
600 0 : return GNUNET_SYSERR;
601 : }
602 0 : rh->amount = amount;
603 0 : if (GNUNET_YES !=
604 0 : TALER_amount_cmp_currency (&amount,
605 : total_in))
606 : {
607 0 : GNUNET_break_op (0);
608 0 : return GNUNET_SYSERR;
609 : }
610 0 : for (unsigned int i = 0; NULL != map[i].type; i++)
611 : {
612 0 : if (0 == strcasecmp (map[i].type,
613 : type))
614 : {
615 0 : found = true;
616 0 : if (GNUNET_OK !=
617 0 : map[i].helper (rh,
618 : &uc,
619 : transaction))
620 : {
621 0 : GNUNET_break_op (0);
622 0 : return GNUNET_SYSERR;
623 : }
624 0 : break;
625 : }
626 : }
627 0 : if (! found)
628 : {
629 : /* unexpected 'type', protocol incompatibility, complain! */
630 0 : GNUNET_break_op (0);
631 0 : return GNUNET_SYSERR;
632 : }
633 : }
634 0 : return GNUNET_OK;
635 : }
636 :
637 :
638 : void
639 0 : TALER_EXCHANGE_free_reserve_history (
640 : struct TALER_EXCHANGE_ReserveHistoryEntry *rhistory,
641 : unsigned int len)
642 : {
643 0 : for (unsigned int i = 0; i<len; i++)
644 : {
645 0 : switch (rhistory[i].type)
646 : {
647 0 : case TALER_EXCHANGE_RTT_CREDIT:
648 0 : GNUNET_free (rhistory[i].details.in_details.sender_url);
649 0 : break;
650 0 : case TALER_EXCHANGE_RTT_WITHDRAWAL:
651 0 : break;
652 0 : case TALER_EXCHANGE_RTT_RECOUP:
653 0 : break;
654 0 : case TALER_EXCHANGE_RTT_CLOSE:
655 0 : break;
656 0 : case TALER_EXCHANGE_RTT_HISTORY:
657 0 : break;
658 0 : case TALER_EXCHANGE_RTT_MERGE:
659 0 : break;
660 : }
661 0 : }
662 0 : GNUNET_free (rhistory);
663 0 : }
664 :
665 :
666 : /**
667 : * Context for coin helpers.
668 : */
669 : struct CoinHistoryParseContext
670 : {
671 :
672 : /**
673 : * Denomination of the coin.
674 : */
675 : const struct TALER_EXCHANGE_DenomPublicKey *dk;
676 :
677 : /**
678 : * Our coin public key.
679 : */
680 : const struct TALER_CoinSpendPublicKeyP *coin_pub;
681 :
682 : /**
683 : * Where to sum up total refunds.
684 : */
685 : struct TALER_Amount rtotal;
686 :
687 : /**
688 : * Total amount encountered.
689 : */
690 : struct TALER_Amount *total;
691 :
692 : };
693 :
694 :
695 : /**
696 : * Signature of functions that operate on one of
697 : * the coin's history entries.
698 : *
699 : * @param[in,out] pc overall context
700 : * @param amount main amount of this operation
701 : * @param transaction JSON details for the operation
702 : * @return #GNUNET_SYSERR on error,
703 : * #GNUNET_OK to add, #GNUNET_NO to subtract
704 : */
705 : typedef enum GNUNET_GenericReturnValue
706 : (*CoinCheckHelper)(struct CoinHistoryParseContext *pc,
707 : const struct TALER_Amount *amount,
708 : json_t *transaction);
709 :
710 :
711 : /**
712 : * Handle deposit entry in the coin's history.
713 : *
714 : * @param[in,out] pc overall context
715 : * @param amount main amount of this operation
716 : * @param transaction JSON details for the operation
717 : * @return #GNUNET_SYSERR on error,
718 : * #GNUNET_OK to add, #GNUNET_NO to subtract
719 : */
720 : static enum GNUNET_GenericReturnValue
721 0 : help_deposit (struct CoinHistoryParseContext *pc,
722 : const struct TALER_Amount *amount,
723 : json_t *transaction)
724 : {
725 : struct TALER_MerchantWireHashP h_wire;
726 : struct TALER_PrivateContractHashP h_contract_terms;
727 : // struct TALER_ExtensionContractHashP h_extensions; // FIXME #7270!
728 : struct GNUNET_TIME_Timestamp wallet_timestamp;
729 : struct TALER_MerchantPublicKeyP merchant_pub;
730 0 : struct GNUNET_TIME_Timestamp refund_deadline = {0};
731 : struct TALER_CoinSpendSignatureP sig;
732 : struct TALER_AgeCommitmentHash hac;
733 : bool no_hac;
734 : struct TALER_Amount deposit_fee;
735 : struct GNUNET_JSON_Specification spec[] = {
736 0 : GNUNET_JSON_spec_fixed_auto ("coin_sig",
737 : &sig),
738 0 : GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
739 : &h_contract_terms),
740 0 : GNUNET_JSON_spec_fixed_auto ("h_wire",
741 : &h_wire),
742 0 : GNUNET_JSON_spec_mark_optional (
743 : GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
744 : &hac),
745 : &no_hac),
746 0 : GNUNET_JSON_spec_timestamp ("timestamp",
747 : &wallet_timestamp),
748 0 : GNUNET_JSON_spec_mark_optional (
749 : GNUNET_JSON_spec_timestamp ("refund_deadline",
750 : &refund_deadline),
751 : NULL),
752 0 : TALER_JSON_spec_amount_any ("deposit_fee",
753 : &deposit_fee),
754 0 : GNUNET_JSON_spec_fixed_auto ("merchant_pub",
755 : &merchant_pub),
756 0 : GNUNET_JSON_spec_end ()
757 : };
758 :
759 0 : if (GNUNET_OK !=
760 0 : GNUNET_JSON_parse (transaction,
761 : spec,
762 : NULL, NULL))
763 : {
764 0 : GNUNET_break_op (0);
765 0 : return GNUNET_SYSERR;
766 : }
767 0 : if (GNUNET_OK !=
768 0 : TALER_wallet_deposit_verify (
769 : amount,
770 : &deposit_fee,
771 : &h_wire,
772 : &h_contract_terms,
773 : no_hac ? NULL : &hac,
774 : NULL /* h_extensions! */,
775 0 : &pc->dk->h_key,
776 : wallet_timestamp,
777 : &merchant_pub,
778 : refund_deadline,
779 : pc->coin_pub,
780 : &sig))
781 : {
782 0 : GNUNET_break_op (0);
783 0 : return GNUNET_SYSERR;
784 : }
785 0 : if (NULL != pc->dk)
786 : {
787 : /* check that deposit fee matches our expectations from /keys! */
788 0 : if ( (GNUNET_YES !=
789 0 : TALER_amount_cmp_currency (&deposit_fee,
790 0 : &pc->dk->fees.deposit)) ||
791 : (0 !=
792 0 : TALER_amount_cmp (&deposit_fee,
793 0 : &pc->dk->fees.deposit)) )
794 : {
795 0 : GNUNET_break_op (0);
796 0 : return GNUNET_SYSERR;
797 : }
798 : }
799 0 : return GNUNET_YES;
800 : }
801 :
802 :
803 : /**
804 : * Handle melt entry in the coin's history.
805 : *
806 : * @param[in,out] pc overall context
807 : * @param amount main amount of this operation
808 : * @param transaction JSON details for the operation
809 : * @return #GNUNET_SYSERR on error,
810 : * #GNUNET_OK to add, #GNUNET_NO to subtract
811 : */
812 : static enum GNUNET_GenericReturnValue
813 0 : help_melt (struct CoinHistoryParseContext *pc,
814 : const struct TALER_Amount *amount,
815 : json_t *transaction)
816 : {
817 : struct TALER_CoinSpendSignatureP sig;
818 : struct TALER_RefreshCommitmentP rc;
819 : struct TALER_AgeCommitmentHash h_age_commitment;
820 : bool no_hac;
821 : struct TALER_Amount melt_fee;
822 : struct GNUNET_JSON_Specification spec[] = {
823 0 : GNUNET_JSON_spec_fixed_auto ("coin_sig",
824 : &sig),
825 0 : GNUNET_JSON_spec_fixed_auto ("rc",
826 : &rc),
827 0 : GNUNET_JSON_spec_mark_optional (
828 : GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
829 : &h_age_commitment),
830 : &no_hac),
831 0 : TALER_JSON_spec_amount_any ("melt_fee",
832 : &melt_fee),
833 0 : GNUNET_JSON_spec_end ()
834 : };
835 :
836 0 : if (GNUNET_OK !=
837 0 : GNUNET_JSON_parse (transaction,
838 : spec,
839 : NULL, NULL))
840 : {
841 0 : GNUNET_break_op (0);
842 0 : return GNUNET_SYSERR;
843 : }
844 :
845 : /* check that melt fee matches our expectations from /keys! */
846 0 : if ( (GNUNET_YES !=
847 0 : TALER_amount_cmp_currency (&melt_fee,
848 0 : &pc->dk->fees.refresh)) ||
849 : (0 !=
850 0 : TALER_amount_cmp (&melt_fee,
851 0 : &pc->dk->fees.refresh)) )
852 : {
853 0 : GNUNET_break_op (0);
854 0 : return GNUNET_SYSERR;
855 : }
856 0 : if (GNUNET_OK !=
857 0 : TALER_wallet_melt_verify (
858 : amount,
859 : &melt_fee,
860 : &rc,
861 0 : &pc->dk->h_key,
862 : no_hac
863 : ? NULL
864 : : &h_age_commitment,
865 : pc->coin_pub,
866 : &sig))
867 : {
868 0 : GNUNET_break_op (0);
869 0 : return GNUNET_SYSERR;
870 : }
871 0 : return GNUNET_YES;
872 : }
873 :
874 :
875 : /**
876 : * Handle refund entry in the coin's history.
877 : *
878 : * @param[in,out] pc overall context
879 : * @param amount main amount of this operation
880 : * @param transaction JSON details for the operation
881 : * @return #GNUNET_SYSERR on error,
882 : * #GNUNET_OK to add, #GNUNET_NO to subtract
883 : */
884 : static enum GNUNET_GenericReturnValue
885 0 : help_refund (struct CoinHistoryParseContext *pc,
886 : const struct TALER_Amount *amount,
887 : json_t *transaction)
888 : {
889 : struct TALER_PrivateContractHashP h_contract_terms;
890 : struct TALER_MerchantPublicKeyP merchant_pub;
891 : struct TALER_MerchantSignatureP sig;
892 : struct TALER_Amount refund_fee;
893 : struct TALER_Amount sig_amount;
894 : uint64_t rtransaction_id;
895 : struct GNUNET_JSON_Specification spec[] = {
896 0 : TALER_JSON_spec_amount_any ("refund_fee",
897 : &refund_fee),
898 0 : GNUNET_JSON_spec_fixed_auto ("merchant_sig",
899 : &sig),
900 0 : GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
901 : &h_contract_terms),
902 0 : GNUNET_JSON_spec_fixed_auto ("merchant_pub",
903 : &merchant_pub),
904 0 : GNUNET_JSON_spec_uint64 ("rtransaction_id",
905 : &rtransaction_id),
906 0 : GNUNET_JSON_spec_end ()
907 : };
908 :
909 0 : if (GNUNET_OK !=
910 0 : GNUNET_JSON_parse (transaction,
911 : spec,
912 : NULL, NULL))
913 : {
914 0 : GNUNET_break_op (0);
915 0 : return GNUNET_SYSERR;
916 : }
917 0 : if (0 >
918 0 : TALER_amount_add (&sig_amount,
919 : &refund_fee,
920 : amount))
921 : {
922 0 : GNUNET_break_op (0);
923 0 : return GNUNET_SYSERR;
924 : }
925 0 : if (GNUNET_OK !=
926 0 : TALER_merchant_refund_verify (pc->coin_pub,
927 : &h_contract_terms,
928 : rtransaction_id,
929 : &sig_amount,
930 : &merchant_pub,
931 : &sig))
932 : {
933 0 : GNUNET_break_op (0);
934 0 : return GNUNET_SYSERR;
935 : }
936 : /* NOTE: theoretically, we could also check that the given
937 : merchant_pub and h_contract_terms appear in the
938 : history under deposits. However, there is really no benefit
939 : for the exchange to lie here, so not checking is probably OK
940 : (an auditor ought to check, though). Then again, we similarly
941 : had no reason to check the merchant's signature (other than a
942 : well-formendess check). */
943 :
944 : /* check that refund fee matches our expectations from /keys! */
945 0 : if ( (GNUNET_YES !=
946 0 : TALER_amount_cmp_currency (&refund_fee,
947 0 : &pc->dk->fees.refund)) ||
948 : (0 !=
949 0 : TALER_amount_cmp (&refund_fee,
950 0 : &pc->dk->fees.refund)) )
951 : {
952 0 : GNUNET_break_op (0);
953 0 : return GNUNET_SYSERR;
954 : }
955 0 : return GNUNET_NO;
956 : }
957 :
958 :
959 : /**
960 : * Handle recoup entry in the coin's history.
961 : *
962 : * @param[in,out] pc overall context
963 : * @param amount main amount of this operation
964 : * @param transaction JSON details for the operation
965 : * @return #GNUNET_SYSERR on error,
966 : * #GNUNET_OK to add, #GNUNET_NO to subtract
967 : */
968 : static enum GNUNET_GenericReturnValue
969 0 : help_recoup (struct CoinHistoryParseContext *pc,
970 : const struct TALER_Amount *amount,
971 : json_t *transaction)
972 : {
973 : struct TALER_ReservePublicKeyP reserve_pub;
974 : struct GNUNET_TIME_Timestamp timestamp;
975 : union TALER_DenominationBlindingKeyP coin_bks;
976 : struct TALER_ExchangePublicKeyP exchange_pub;
977 : struct TALER_ExchangeSignatureP exchange_sig;
978 : struct TALER_CoinSpendSignatureP coin_sig;
979 : struct GNUNET_JSON_Specification spec[] = {
980 0 : GNUNET_JSON_spec_fixed_auto ("exchange_sig",
981 : &exchange_sig),
982 0 : GNUNET_JSON_spec_fixed_auto ("exchange_pub",
983 : &exchange_pub),
984 0 : GNUNET_JSON_spec_fixed_auto ("reserve_pub",
985 : &reserve_pub),
986 0 : GNUNET_JSON_spec_fixed_auto ("coin_sig",
987 : &coin_sig),
988 0 : GNUNET_JSON_spec_fixed_auto ("coin_blind",
989 : &coin_bks),
990 0 : GNUNET_JSON_spec_timestamp ("timestamp",
991 : ×tamp),
992 0 : GNUNET_JSON_spec_end ()
993 : };
994 :
995 0 : if (GNUNET_OK !=
996 0 : GNUNET_JSON_parse (transaction,
997 : spec,
998 : NULL, NULL))
999 : {
1000 0 : GNUNET_break_op (0);
1001 0 : return GNUNET_SYSERR;
1002 : }
1003 0 : if (GNUNET_OK !=
1004 0 : TALER_exchange_online_confirm_recoup_verify (
1005 : timestamp,
1006 : amount,
1007 : pc->coin_pub,
1008 : &reserve_pub,
1009 : &exchange_pub,
1010 : &exchange_sig))
1011 : {
1012 0 : GNUNET_break_op (0);
1013 0 : return GNUNET_SYSERR;
1014 : }
1015 0 : if (GNUNET_OK !=
1016 0 : TALER_wallet_recoup_verify (&pc->dk->h_key,
1017 : &coin_bks,
1018 : pc->coin_pub,
1019 : &coin_sig))
1020 : {
1021 0 : GNUNET_break_op (0);
1022 0 : return GNUNET_SYSERR;
1023 : }
1024 0 : return GNUNET_YES;
1025 : }
1026 :
1027 :
1028 : /**
1029 : * Handle recoup-refresh entry in the coin's history.
1030 : *
1031 : * @param[in,out] pc overall context
1032 : * @param amount main amount of this operation
1033 : * @param transaction JSON details for the operation
1034 : * @return #GNUNET_SYSERR on error,
1035 : * #GNUNET_OK to add, #GNUNET_NO to subtract
1036 : */
1037 : static enum GNUNET_GenericReturnValue
1038 0 : help_recoup_refresh (struct CoinHistoryParseContext *pc,
1039 : const struct TALER_Amount *amount,
1040 : json_t *transaction)
1041 : {
1042 : /* This is the coin that was subjected to a recoup,
1043 : the value being credited to the old coin. */
1044 : struct TALER_CoinSpendPublicKeyP old_coin_pub;
1045 : union TALER_DenominationBlindingKeyP coin_bks;
1046 : struct GNUNET_TIME_Timestamp timestamp;
1047 : struct TALER_ExchangePublicKeyP exchange_pub;
1048 : struct TALER_ExchangeSignatureP exchange_sig;
1049 : struct TALER_CoinSpendSignatureP coin_sig;
1050 : struct GNUNET_JSON_Specification spec[] = {
1051 0 : GNUNET_JSON_spec_fixed_auto ("exchange_sig",
1052 : &exchange_sig),
1053 0 : GNUNET_JSON_spec_fixed_auto ("exchange_pub",
1054 : &exchange_pub),
1055 0 : GNUNET_JSON_spec_fixed_auto ("coin_sig",
1056 : &coin_sig),
1057 0 : GNUNET_JSON_spec_fixed_auto ("old_coin_pub",
1058 : &old_coin_pub),
1059 0 : GNUNET_JSON_spec_fixed_auto ("coin_blind",
1060 : &coin_bks),
1061 0 : GNUNET_JSON_spec_timestamp ("timestamp",
1062 : ×tamp),
1063 0 : GNUNET_JSON_spec_end ()
1064 : };
1065 :
1066 0 : if (GNUNET_OK !=
1067 0 : GNUNET_JSON_parse (transaction,
1068 : spec,
1069 : NULL, NULL))
1070 : {
1071 0 : GNUNET_break_op (0);
1072 0 : return GNUNET_SYSERR;
1073 : }
1074 0 : if (GNUNET_OK !=
1075 0 : TALER_exchange_online_confirm_recoup_refresh_verify (
1076 : timestamp,
1077 : amount,
1078 : pc->coin_pub,
1079 : &old_coin_pub,
1080 : &exchange_pub,
1081 : &exchange_sig))
1082 : {
1083 0 : GNUNET_break_op (0);
1084 0 : return GNUNET_SYSERR;
1085 : }
1086 0 : if (GNUNET_OK !=
1087 0 : TALER_wallet_recoup_verify (&pc->dk->h_key,
1088 : &coin_bks,
1089 : pc->coin_pub,
1090 : &coin_sig))
1091 : {
1092 0 : GNUNET_break_op (0);
1093 0 : return GNUNET_SYSERR;
1094 : }
1095 0 : return GNUNET_YES;
1096 : }
1097 :
1098 :
1099 : /**
1100 : * Handle old coin recoup entry in the coin's history.
1101 : *
1102 : * @param[in,out] pc overall context
1103 : * @param amount main amount of this operation
1104 : * @param transaction JSON details for the operation
1105 : * @return #GNUNET_SYSERR on error,
1106 : * #GNUNET_OK to add, #GNUNET_NO to subtract
1107 : */
1108 : static enum GNUNET_GenericReturnValue
1109 0 : help_old_coin_recoup (struct CoinHistoryParseContext *pc,
1110 : const struct TALER_Amount *amount,
1111 : json_t *transaction)
1112 : {
1113 : /* This is the coin that was credited in a recoup,
1114 : the value being credited to the this coin. */
1115 : struct TALER_ExchangePublicKeyP exchange_pub;
1116 : struct TALER_ExchangeSignatureP exchange_sig;
1117 : struct TALER_CoinSpendPublicKeyP new_coin_pub;
1118 : struct GNUNET_TIME_Timestamp timestamp;
1119 : struct GNUNET_JSON_Specification spec[] = {
1120 0 : GNUNET_JSON_spec_fixed_auto ("exchange_sig",
1121 : &exchange_sig),
1122 0 : GNUNET_JSON_spec_fixed_auto ("exchange_pub",
1123 : &exchange_pub),
1124 0 : GNUNET_JSON_spec_fixed_auto ("coin_pub",
1125 : &new_coin_pub),
1126 0 : GNUNET_JSON_spec_timestamp ("timestamp",
1127 : ×tamp),
1128 0 : GNUNET_JSON_spec_end ()
1129 : };
1130 :
1131 0 : if (GNUNET_OK !=
1132 0 : GNUNET_JSON_parse (transaction,
1133 : spec,
1134 : NULL, NULL))
1135 : {
1136 0 : GNUNET_break_op (0);
1137 0 : return GNUNET_SYSERR;
1138 : }
1139 0 : if (GNUNET_OK !=
1140 0 : TALER_exchange_online_confirm_recoup_refresh_verify (
1141 : timestamp,
1142 : amount,
1143 : &new_coin_pub,
1144 : pc->coin_pub,
1145 : &exchange_pub,
1146 : &exchange_sig))
1147 : {
1148 0 : GNUNET_break_op (0);
1149 0 : return GNUNET_SYSERR;
1150 : }
1151 0 : return GNUNET_NO;
1152 : }
1153 :
1154 :
1155 : /**
1156 : * Handle purse deposit entry in the coin's history.
1157 : *
1158 : * @param[in,out] pc overall context
1159 : * @param amount main amount of this operation
1160 : * @param transaction JSON details for the operation
1161 : * @return #GNUNET_SYSERR on error,
1162 : * #GNUNET_OK to add, #GNUNET_NO to subtract
1163 : */
1164 : static enum GNUNET_GenericReturnValue
1165 0 : help_purse_deposit (struct CoinHistoryParseContext *pc,
1166 : const struct TALER_Amount *amount,
1167 : json_t *transaction)
1168 : {
1169 : struct TALER_PurseContractPublicKeyP purse_pub;
1170 : struct TALER_CoinSpendSignatureP coin_sig;
1171 : const char *exchange_base_url;
1172 : bool refunded;
1173 0 : struct TALER_AgeCommitmentHash phac = { 0 };
1174 : struct GNUNET_JSON_Specification spec[] = {
1175 0 : GNUNET_JSON_spec_fixed_auto ("purse_pub",
1176 : &purse_pub),
1177 0 : GNUNET_JSON_spec_fixed_auto ("coin_sig",
1178 : &coin_sig),
1179 0 : GNUNET_JSON_spec_mark_optional (
1180 : GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
1181 : &coin_sig),
1182 : NULL),
1183 0 : GNUNET_JSON_spec_string ("exchange_base_url",
1184 : &exchange_base_url),
1185 0 : GNUNET_JSON_spec_mark_optional (
1186 : GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
1187 : &phac),
1188 : NULL),
1189 0 : GNUNET_JSON_spec_bool ("refunded",
1190 : &refunded),
1191 0 : GNUNET_JSON_spec_end ()
1192 : };
1193 :
1194 0 : if (GNUNET_OK !=
1195 0 : GNUNET_JSON_parse (transaction,
1196 : spec,
1197 : NULL, NULL))
1198 : {
1199 0 : GNUNET_break_op (0);
1200 0 : return GNUNET_SYSERR;
1201 : }
1202 0 : if (GNUNET_OK !=
1203 0 : TALER_wallet_purse_deposit_verify (
1204 : exchange_base_url,
1205 : &purse_pub,
1206 : amount,
1207 0 : &pc->dk->h_key,
1208 : &phac,
1209 : pc->coin_pub,
1210 : &coin_sig))
1211 : {
1212 0 : GNUNET_break_op (0);
1213 0 : return GNUNET_SYSERR;
1214 : }
1215 0 : if (refunded)
1216 : {
1217 : /* We add the amount to refunds here, the original
1218 : deposit will be added to the balance later because
1219 : we still return GNUNET_YES, thus effectively
1220 : cancelling out this operation with respect to
1221 : the final balance. */
1222 0 : if (0 >
1223 0 : TALER_amount_add (&pc->rtotal,
1224 0 : &pc->rtotal,
1225 : amount))
1226 : {
1227 : /* overflow in refund history? inconceivable! Bad exchange! */
1228 0 : GNUNET_break_op (0);
1229 0 : return GNUNET_SYSERR;
1230 : }
1231 : }
1232 0 : return GNUNET_YES;
1233 : }
1234 :
1235 :
1236 : enum GNUNET_GenericReturnValue
1237 0 : TALER_EXCHANGE_verify_coin_history (
1238 : const struct TALER_EXCHANGE_DenomPublicKey *dk,
1239 : const struct TALER_CoinSpendPublicKeyP *coin_pub,
1240 : json_t *history,
1241 : struct TALER_Amount *total)
1242 : {
1243 0 : const char *currency = dk->value.currency;
1244 : const struct
1245 : {
1246 : const char *type;
1247 : CoinCheckHelper helper;
1248 0 : } map[] = {
1249 : { "DEPOSIT", &help_deposit },
1250 : { "MELT", &help_melt },
1251 : { "REFUND", &help_refund },
1252 : { "RECOUP", &help_recoup },
1253 : { "RECOUP-REFRESH", &help_recoup_refresh },
1254 : { "OLD-COIN-RECOUP", &help_old_coin_recoup },
1255 : { "PURSE-DEPOSIT", &help_purse_deposit },
1256 : { NULL, NULL }
1257 : };
1258 0 : struct CoinHistoryParseContext pc = {
1259 : .dk = dk,
1260 : .coin_pub = coin_pub,
1261 : .total = total
1262 : };
1263 : size_t len;
1264 :
1265 0 : if (NULL == history)
1266 : {
1267 0 : GNUNET_break_op (0);
1268 0 : return GNUNET_SYSERR;
1269 : }
1270 0 : len = json_array_size (history);
1271 0 : if (0 == len)
1272 : {
1273 0 : GNUNET_break_op (0);
1274 0 : return GNUNET_SYSERR;
1275 : }
1276 0 : GNUNET_assert (GNUNET_OK ==
1277 : TALER_amount_set_zero (currency,
1278 : total));
1279 0 : GNUNET_assert (GNUNET_OK ==
1280 : TALER_amount_set_zero (currency,
1281 : &pc.rtotal));
1282 0 : for (size_t off = 0; off<len; off++)
1283 : {
1284 : enum GNUNET_GenericReturnValue add;
1285 : json_t *transaction;
1286 : struct TALER_Amount amount;
1287 : const char *type;
1288 : struct GNUNET_JSON_Specification spec_glob[] = {
1289 0 : TALER_JSON_spec_amount_any ("amount",
1290 : &amount),
1291 0 : GNUNET_JSON_spec_string ("type",
1292 : &type),
1293 0 : GNUNET_JSON_spec_end ()
1294 : };
1295 :
1296 0 : transaction = json_array_get (history,
1297 : off);
1298 0 : if (GNUNET_OK !=
1299 0 : GNUNET_JSON_parse (transaction,
1300 : spec_glob,
1301 : NULL, NULL))
1302 : {
1303 0 : GNUNET_break_op (0);
1304 0 : return GNUNET_SYSERR;
1305 : }
1306 0 : if (GNUNET_YES !=
1307 0 : TALER_amount_cmp_currency (&amount,
1308 : &pc.rtotal))
1309 : {
1310 0 : GNUNET_break_op (0);
1311 0 : return GNUNET_SYSERR;
1312 : }
1313 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1314 : "Operation of type %s with amount %s\n",
1315 : type,
1316 : TALER_amount2s (&amount));
1317 0 : add = GNUNET_SYSERR;
1318 0 : for (unsigned int i = 0; NULL != map[i].type; i++)
1319 : {
1320 0 : if (0 == strcasecmp (type,
1321 : map[i].type))
1322 : {
1323 0 : add = map[i].helper (&pc,
1324 : &amount,
1325 : transaction);
1326 0 : break;
1327 : }
1328 : }
1329 0 : switch (add)
1330 : {
1331 0 : case GNUNET_SYSERR:
1332 : /* entry type not supported, new version on server? */
1333 0 : GNUNET_break_op (0);
1334 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1335 : "Unexpected type `%s' in response\n",
1336 : type);
1337 0 : return GNUNET_SYSERR;
1338 0 : case GNUNET_YES:
1339 : /* This amount should be added to the total */
1340 0 : if (0 >
1341 0 : TALER_amount_add (total,
1342 : total,
1343 : &amount))
1344 : {
1345 : /* overflow in history already!? inconceivable! Bad exchange! */
1346 0 : GNUNET_break_op (0);
1347 0 : return GNUNET_SYSERR;
1348 : }
1349 0 : break;
1350 0 : case GNUNET_NO:
1351 : /* This amount should be subtracted from the total.
1352 :
1353 : However, for the implementation, we first *add* up all of
1354 : these negative amounts, as we might get refunds before
1355 : deposits from a semi-evil exchange. Then, at the end, we do
1356 : the subtraction by calculating "total = total - rtotal" */
1357 0 : if (0 >
1358 0 : TALER_amount_add (&pc.rtotal,
1359 : &pc.rtotal,
1360 : &amount))
1361 : {
1362 : /* overflow in refund history? inconceivable! Bad exchange! */
1363 0 : GNUNET_break_op (0);
1364 0 : return GNUNET_SYSERR;
1365 : }
1366 0 : break;
1367 : } /* end of switch(add) */
1368 0 : }
1369 : /* Finally, subtract 'rtotal' from total to handle the subtractions */
1370 0 : if (0 >
1371 0 : TALER_amount_subtract (total,
1372 : total,
1373 : &pc.rtotal))
1374 : {
1375 : /* underflow in history? inconceivable! Bad exchange! */
1376 0 : GNUNET_break_op (0);
1377 0 : return GNUNET_SYSERR;
1378 : }
1379 0 : return GNUNET_OK;
1380 : }
1381 :
1382 :
1383 : const struct TALER_EXCHANGE_SigningPublicKey *
1384 0 : TALER_EXCHANGE_get_signing_key_info (
1385 : const struct TALER_EXCHANGE_Keys *keys,
1386 : const struct TALER_ExchangePublicKeyP *exchange_pub)
1387 : {
1388 0 : for (unsigned int i = 0; i<keys->num_sign_keys; i++)
1389 : {
1390 0 : const struct TALER_EXCHANGE_SigningPublicKey *spk
1391 0 : = &keys->sign_keys[i];
1392 :
1393 0 : if (0 == GNUNET_memcmp (exchange_pub,
1394 : &spk->key))
1395 0 : return spk;
1396 : }
1397 0 : return NULL;
1398 : }
1399 :
1400 :
1401 : enum GNUNET_GenericReturnValue
1402 0 : TALER_EXCHANGE_check_purse_create_conflict_ (
1403 : const struct TALER_PurseContractSignatureP *cpurse_sig,
1404 : const struct TALER_PurseContractPublicKeyP *purse_pub,
1405 : const json_t *proof)
1406 : {
1407 : struct TALER_Amount amount;
1408 : uint32_t min_age;
1409 : struct GNUNET_TIME_Timestamp purse_expiration;
1410 : struct TALER_PurseContractSignatureP purse_sig;
1411 : struct TALER_PrivateContractHashP h_contract_terms;
1412 : struct TALER_PurseMergePublicKeyP merge_pub;
1413 : struct GNUNET_JSON_Specification spec[] = {
1414 0 : TALER_JSON_spec_amount_any ("amount",
1415 : &amount),
1416 0 : GNUNET_JSON_spec_uint32 ("min_age",
1417 : &min_age),
1418 0 : GNUNET_JSON_spec_timestamp ("purse_expiration",
1419 : &purse_expiration),
1420 0 : GNUNET_JSON_spec_fixed_auto ("purse_sig",
1421 : &purse_sig),
1422 0 : GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
1423 : &h_contract_terms),
1424 0 : GNUNET_JSON_spec_fixed_auto ("merge_pub",
1425 : &merge_pub),
1426 0 : GNUNET_JSON_spec_end ()
1427 : };
1428 :
1429 0 : if (GNUNET_OK !=
1430 0 : GNUNET_JSON_parse (proof,
1431 : spec,
1432 : NULL, NULL))
1433 : {
1434 0 : GNUNET_break_op (0);
1435 0 : return GNUNET_SYSERR;
1436 : }
1437 0 : if (GNUNET_OK !=
1438 0 : TALER_wallet_purse_create_verify (purse_expiration,
1439 : &h_contract_terms,
1440 : &merge_pub,
1441 : min_age,
1442 : &amount,
1443 : purse_pub,
1444 : &purse_sig))
1445 : {
1446 0 : GNUNET_break_op (0);
1447 0 : return GNUNET_SYSERR;
1448 : }
1449 0 : if (0 ==
1450 0 : GNUNET_memcmp (&purse_sig,
1451 : cpurse_sig))
1452 : {
1453 : /* Must be the SAME data, not a conflict! */
1454 0 : GNUNET_break_op (0);
1455 0 : return GNUNET_SYSERR;
1456 : }
1457 0 : return GNUNET_OK;
1458 : }
1459 :
1460 :
1461 : enum GNUNET_GenericReturnValue
1462 0 : TALER_EXCHANGE_check_purse_merge_conflict_ (
1463 : const struct TALER_PurseMergeSignatureP *cmerge_sig,
1464 : const struct TALER_PurseMergePublicKeyP *merge_pub,
1465 : const struct TALER_PurseContractPublicKeyP *purse_pub,
1466 : const char *exchange_url,
1467 : const json_t *proof)
1468 : {
1469 : struct TALER_PurseMergeSignatureP merge_sig;
1470 : struct GNUNET_TIME_Timestamp merge_timestamp;
1471 0 : const char *partner_url = NULL;
1472 : struct TALER_ReservePublicKeyP reserve_pub;
1473 : struct GNUNET_JSON_Specification spec[] = {
1474 0 : GNUNET_JSON_spec_mark_optional (
1475 : GNUNET_JSON_spec_string ("partner_url",
1476 : &partner_url),
1477 : NULL),
1478 0 : GNUNET_JSON_spec_timestamp ("merge_timestamp",
1479 : &merge_timestamp),
1480 0 : GNUNET_JSON_spec_fixed_auto ("merge_sig",
1481 : &merge_sig),
1482 0 : GNUNET_JSON_spec_fixed_auto ("reserve_pub",
1483 : &reserve_pub),
1484 0 : GNUNET_JSON_spec_end ()
1485 : };
1486 : char *payto_uri;
1487 :
1488 0 : if (GNUNET_OK !=
1489 0 : GNUNET_JSON_parse (proof,
1490 : spec,
1491 : NULL, NULL))
1492 : {
1493 0 : GNUNET_break_op (0);
1494 0 : return GNUNET_SYSERR;
1495 : }
1496 0 : if (NULL == partner_url)
1497 0 : partner_url = exchange_url;
1498 0 : payto_uri = TALER_reserve_make_payto (partner_url,
1499 : &reserve_pub);
1500 0 : if (GNUNET_OK !=
1501 0 : TALER_wallet_purse_merge_verify (
1502 : payto_uri,
1503 : merge_timestamp,
1504 : purse_pub,
1505 : merge_pub,
1506 : &merge_sig))
1507 : {
1508 0 : GNUNET_break_op (0);
1509 0 : GNUNET_free (payto_uri);
1510 0 : return GNUNET_SYSERR;
1511 : }
1512 0 : GNUNET_free (payto_uri);
1513 0 : if (0 ==
1514 0 : GNUNET_memcmp (&merge_sig,
1515 : cmerge_sig))
1516 : {
1517 : /* Must be the SAME data, not a conflict! */
1518 0 : GNUNET_break_op (0);
1519 0 : return GNUNET_SYSERR;
1520 : }
1521 0 : return GNUNET_OK;
1522 : }
1523 :
1524 :
1525 : enum GNUNET_GenericReturnValue
1526 0 : TALER_EXCHANGE_check_purse_coin_conflict_ (
1527 : const struct TALER_PurseContractPublicKeyP *purse_pub,
1528 : const char *exchange_url,
1529 : const json_t *proof,
1530 : struct TALER_DenominationHashP *h_denom_pub,
1531 : struct TALER_AgeCommitmentHash *phac,
1532 : struct TALER_CoinSpendPublicKeyP *coin_pub,
1533 : struct TALER_CoinSpendSignatureP *coin_sig)
1534 : {
1535 0 : const char *partner_url = NULL;
1536 : struct TALER_Amount amount;
1537 : struct GNUNET_JSON_Specification spec[] = {
1538 0 : GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
1539 : h_denom_pub),
1540 0 : GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
1541 : phac),
1542 0 : GNUNET_JSON_spec_fixed_auto ("coin_sig",
1543 : coin_sig),
1544 0 : GNUNET_JSON_spec_fixed_auto ("coin_pub",
1545 : coin_pub),
1546 0 : GNUNET_JSON_spec_mark_optional (
1547 : GNUNET_JSON_spec_string ("partner_url",
1548 : &partner_url),
1549 : NULL),
1550 0 : TALER_JSON_spec_amount_any ("amount",
1551 : &amount),
1552 0 : GNUNET_JSON_spec_end ()
1553 : };
1554 :
1555 0 : if (GNUNET_OK !=
1556 0 : GNUNET_JSON_parse (proof,
1557 : spec,
1558 : NULL, NULL))
1559 : {
1560 0 : GNUNET_break_op (0);
1561 0 : return GNUNET_SYSERR;
1562 : }
1563 0 : if (NULL == partner_url)
1564 0 : partner_url = exchange_url;
1565 0 : if (GNUNET_OK !=
1566 0 : TALER_wallet_purse_deposit_verify (
1567 : partner_url,
1568 : purse_pub,
1569 : &amount,
1570 : h_denom_pub,
1571 : phac,
1572 : coin_pub,
1573 : coin_sig))
1574 : {
1575 0 : GNUNET_break_op (0);
1576 0 : return GNUNET_SYSERR;
1577 : }
1578 0 : return GNUNET_OK;
1579 : }
1580 :
1581 :
1582 : enum GNUNET_GenericReturnValue
1583 0 : TALER_EXCHANGE_check_purse_econtract_conflict_ (
1584 : const struct TALER_PurseContractSignatureP *ccontract_sig,
1585 : const struct TALER_PurseContractPublicKeyP *purse_pub,
1586 : const json_t *proof)
1587 : {
1588 : struct TALER_ContractDiffiePublicP contract_pub;
1589 : struct TALER_PurseContractSignatureP contract_sig;
1590 : struct GNUNET_HashCode h_econtract;
1591 : struct GNUNET_JSON_Specification spec[] = {
1592 0 : GNUNET_JSON_spec_fixed_auto ("h_econtract",
1593 : &h_econtract),
1594 0 : GNUNET_JSON_spec_fixed_auto ("econtract_sig",
1595 : &contract_sig),
1596 0 : GNUNET_JSON_spec_fixed_auto ("contract_pub",
1597 : &contract_pub),
1598 0 : GNUNET_JSON_spec_end ()
1599 : };
1600 :
1601 0 : if (GNUNET_OK !=
1602 0 : GNUNET_JSON_parse (proof,
1603 : spec,
1604 : NULL, NULL))
1605 : {
1606 0 : GNUNET_break_op (0);
1607 0 : return GNUNET_SYSERR;
1608 : }
1609 0 : if (GNUNET_OK !=
1610 0 : TALER_wallet_econtract_upload_verify2 (
1611 : &h_econtract,
1612 : &contract_pub,
1613 : purse_pub,
1614 : &contract_sig))
1615 : {
1616 0 : GNUNET_break_op (0);
1617 0 : return GNUNET_SYSERR;
1618 : }
1619 0 : if (0 ==
1620 0 : GNUNET_memcmp (&contract_sig,
1621 : ccontract_sig))
1622 : {
1623 : /* Must be the SAME data, not a conflict! */
1624 0 : GNUNET_break_op (0);
1625 0 : return GNUNET_SYSERR;
1626 : }
1627 0 : return GNUNET_OK;
1628 : }
1629 :
1630 :
1631 : enum GNUNET_GenericReturnValue
1632 0 : TALER_EXCHANGE_check_coin_amount_conflict_ (
1633 : const struct TALER_EXCHANGE_Keys *keys,
1634 : const json_t *proof,
1635 : struct TALER_CoinSpendPublicKeyP *coin_pub,
1636 : struct TALER_Amount *remaining)
1637 : {
1638 : json_t *history;
1639 : struct TALER_Amount total;
1640 : struct TALER_DenominationHashP h_denom_pub;
1641 : const struct TALER_EXCHANGE_DenomPublicKey *dki;
1642 : struct GNUNET_JSON_Specification spec[] = {
1643 0 : GNUNET_JSON_spec_fixed_auto ("coin_pub",
1644 : coin_pub),
1645 0 : GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
1646 : &h_denom_pub),
1647 0 : GNUNET_JSON_spec_json ("history",
1648 : &history),
1649 0 : GNUNET_JSON_spec_end ()
1650 : };
1651 :
1652 0 : if (GNUNET_OK !=
1653 0 : GNUNET_JSON_parse (proof,
1654 : spec,
1655 : NULL, NULL))
1656 : {
1657 0 : GNUNET_break_op (0);
1658 0 : return GNUNET_SYSERR;
1659 : }
1660 0 : dki = TALER_EXCHANGE_get_denomination_key_by_hash (
1661 : keys,
1662 : &h_denom_pub);
1663 0 : if (NULL == dki)
1664 : {
1665 0 : GNUNET_break_op (0);
1666 0 : return GNUNET_SYSERR;
1667 : }
1668 0 : if (GNUNET_OK !=
1669 0 : TALER_EXCHANGE_verify_coin_history (dki,
1670 : coin_pub,
1671 : history,
1672 : &total))
1673 : {
1674 0 : GNUNET_break_op (0);
1675 0 : json_decref (history);
1676 0 : return GNUNET_SYSERR;
1677 : }
1678 0 : json_decref (history);
1679 0 : if (0 >
1680 0 : TALER_amount_subtract (remaining,
1681 : &dki->value,
1682 : &total))
1683 : {
1684 : /* Strange 'proof': coin was double-spent
1685 : before our transaction?! */
1686 0 : GNUNET_break_op (0);
1687 0 : return GNUNET_SYSERR;
1688 : }
1689 0 : return GNUNET_OK;
1690 : }
1691 :
1692 :
1693 : /**
1694 : * Verify that @a coin_sig does NOT appear in
1695 : * the history of @a proof and thus whatever transaction
1696 : * is authorized by @a coin_sig is a conflict with
1697 : * @a proof.
1698 : *
1699 : * @param proof a proof to check
1700 : * @param coin_sig signature that must not be in @a proof
1701 : * @return #GNUNET_OK if @a coin_sig is not in @a proof
1702 : */
1703 : enum GNUNET_GenericReturnValue
1704 0 : TALER_EXCHANGE_check_coin_signature_conflict_ (
1705 : const json_t *proof,
1706 : const struct TALER_CoinSpendSignatureP *coin_sig)
1707 : {
1708 : json_t *history;
1709 : size_t off;
1710 : json_t *entry;
1711 :
1712 0 : history = json_object_get (proof,
1713 : "history");
1714 0 : if (NULL == history)
1715 : {
1716 0 : GNUNET_break (0);
1717 0 : return GNUNET_SYSERR;
1718 : }
1719 0 : json_array_foreach (history, off, entry)
1720 : {
1721 : struct TALER_CoinSpendSignatureP cs;
1722 : struct GNUNET_JSON_Specification spec[] = {
1723 0 : GNUNET_JSON_spec_fixed_auto ("coin_sig",
1724 : &cs),
1725 0 : GNUNET_JSON_spec_end ()
1726 : };
1727 :
1728 0 : if (GNUNET_OK !=
1729 0 : GNUNET_JSON_parse (entry,
1730 : spec,
1731 : NULL, NULL))
1732 0 : continue; /* entry without coin signature */
1733 0 : if (0 ==
1734 0 : GNUNET_memcmp (&cs,
1735 : coin_sig))
1736 : {
1737 0 : GNUNET_break_op (0);
1738 0 : return GNUNET_SYSERR;
1739 : }
1740 : }
1741 0 : return GNUNET_OK;
1742 : }
1743 :
1744 :
1745 : enum GNUNET_GenericReturnValue
1746 0 : TALER_EXCHANGE_check_coin_denomination_conflict_ (
1747 : const json_t *proof,
1748 : const struct TALER_DenominationHashP *ch_denom_pub)
1749 : {
1750 : struct TALER_DenominationHashP h_denom_pub;
1751 : struct GNUNET_JSON_Specification spec[] = {
1752 0 : GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
1753 : &h_denom_pub),
1754 0 : GNUNET_JSON_spec_end ()
1755 : };
1756 :
1757 0 : if (GNUNET_OK !=
1758 0 : GNUNET_JSON_parse (proof,
1759 : spec,
1760 : NULL, NULL))
1761 : {
1762 0 : GNUNET_break_op (0);
1763 0 : return GNUNET_SYSERR;
1764 : }
1765 0 : if (0 ==
1766 0 : GNUNET_memcmp (ch_denom_pub,
1767 : &h_denom_pub))
1768 : {
1769 0 : GNUNET_break_op (0);
1770 0 : return GNUNET_OK;
1771 : }
1772 : /* indeed, proof with different denomination key provided */
1773 0 : return GNUNET_OK;
1774 : }
1775 :
1776 :
1777 : enum GNUNET_GenericReturnValue
1778 0 : TALER_EXCHANGE_check_coin_conflict_ (
1779 : const struct TALER_EXCHANGE_Keys *keys,
1780 : const json_t *proof,
1781 : const struct TALER_EXCHANGE_DenomPublicKey *dk,
1782 : const struct TALER_CoinSpendPublicKeyP *coin_pub,
1783 : const struct TALER_CoinSpendSignatureP *coin_sig,
1784 : const struct TALER_Amount *required)
1785 : {
1786 : enum TALER_ErrorCode ec;
1787 :
1788 0 : ec = TALER_JSON_get_error_code (proof);
1789 0 : switch (ec)
1790 : {
1791 0 : case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
1792 : {
1793 : struct TALER_Amount left;
1794 : struct TALER_CoinSpendPublicKeyP pcoin_pub;
1795 :
1796 0 : if (GNUNET_OK !=
1797 0 : TALER_EXCHANGE_check_coin_amount_conflict_ (
1798 : keys,
1799 : proof,
1800 : &pcoin_pub,
1801 : &left))
1802 : {
1803 0 : GNUNET_break_op (0);
1804 0 : return GNUNET_SYSERR;
1805 : }
1806 0 : if (0 !=
1807 0 : GNUNET_memcmp (&pcoin_pub,
1808 : coin_pub))
1809 : {
1810 : /* conflict is for a different coin! */
1811 0 : GNUNET_break_op (0);
1812 0 : return GNUNET_SYSERR;
1813 : }
1814 0 : if (-1 !=
1815 0 : TALER_amount_cmp (&left,
1816 : required))
1817 : {
1818 : /* Balance was sufficient after all; recoup MAY have still been possible */
1819 0 : GNUNET_break_op (0);
1820 0 : return GNUNET_SYSERR;
1821 : }
1822 0 : if (GNUNET_OK !=
1823 0 : TALER_EXCHANGE_check_coin_signature_conflict_ (
1824 : proof,
1825 : coin_sig))
1826 : {
1827 : /* Not a conflicting transaction: ours is included! */
1828 0 : GNUNET_break_op (0);
1829 0 : return GNUNET_SYSERR;
1830 : }
1831 0 : break;
1832 : }
1833 0 : case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
1834 : {
1835 : struct TALER_Amount left;
1836 : struct TALER_CoinSpendPublicKeyP pcoin_pub;
1837 :
1838 0 : if (GNUNET_OK !=
1839 0 : TALER_EXCHANGE_check_coin_amount_conflict_ (
1840 : keys,
1841 : proof,
1842 : &pcoin_pub,
1843 : &left))
1844 : {
1845 0 : GNUNET_break_op (0);
1846 0 : return GNUNET_SYSERR;
1847 : }
1848 0 : if (0 !=
1849 0 : GNUNET_memcmp (&pcoin_pub,
1850 : coin_pub))
1851 : {
1852 : /* conflict is for a different coin! */
1853 0 : GNUNET_break_op (0);
1854 0 : return GNUNET_SYSERR;
1855 : }
1856 0 : if (GNUNET_OK !=
1857 0 : TALER_EXCHANGE_check_coin_denomination_conflict_ (
1858 : proof,
1859 : &dk->h_key))
1860 : {
1861 : /* Eh, same denomination, hence no conflict */
1862 0 : GNUNET_break_op (0);
1863 0 : return GNUNET_SYSERR;
1864 : }
1865 0 : break;
1866 : }
1867 0 : default:
1868 0 : GNUNET_break_op (0);
1869 0 : return GNUNET_SYSERR;
1870 : }
1871 0 : return GNUNET_OK;
1872 : }
1873 :
1874 :
1875 : enum GNUNET_GenericReturnValue
1876 0 : TALER_EXCHANGE_get_min_denomination_ (
1877 : const struct TALER_EXCHANGE_Keys *keys,
1878 : struct TALER_Amount *min)
1879 : {
1880 0 : bool have_min = false;
1881 0 : for (unsigned int i = 0; i<keys->num_denom_keys; i++)
1882 : {
1883 0 : const struct TALER_EXCHANGE_DenomPublicKey *dk = &keys->denom_keys[i];
1884 :
1885 0 : if (! have_min)
1886 : {
1887 0 : *min = dk->value;
1888 0 : have_min = true;
1889 0 : continue;
1890 : }
1891 0 : if (1 != TALER_amount_cmp (min,
1892 : &dk->value))
1893 0 : continue;
1894 0 : *min = dk->value;
1895 : }
1896 0 : if (! have_min)
1897 : {
1898 0 : GNUNET_break (0);
1899 0 : return GNUNET_SYSERR;
1900 : }
1901 0 : return GNUNET_OK;
1902 : }
1903 :
1904 :
1905 : enum GNUNET_GenericReturnValue
1906 0 : TALER_EXCHANGE_verify_deposit_signature_ (
1907 : const struct TALER_EXCHANGE_DepositContractDetail *dcd,
1908 : const struct TALER_ExtensionContractHashP *ech,
1909 : const struct TALER_MerchantWireHashP *h_wire,
1910 : const struct TALER_EXCHANGE_CoinDepositDetail *cdd,
1911 : const struct TALER_EXCHANGE_DenomPublicKey *dki)
1912 : {
1913 0 : if (GNUNET_OK !=
1914 0 : TALER_wallet_deposit_verify (&cdd->amount,
1915 : &dki->fees.deposit,
1916 : h_wire,
1917 : &dcd->h_contract_terms,
1918 : &cdd->h_age_commitment,
1919 : ech,
1920 : &cdd->h_denom_pub,
1921 : dcd->timestamp,
1922 : &dcd->merchant_pub,
1923 : dcd->refund_deadline,
1924 : &cdd->coin_pub,
1925 : &cdd->coin_sig))
1926 : {
1927 0 : GNUNET_break_op (0);
1928 0 : TALER_LOG_WARNING ("Invalid coin signature on /deposit request!\n");
1929 0 : TALER_LOG_DEBUG ("... amount_with_fee was %s\n",
1930 : TALER_amount2s (&cdd->amount));
1931 0 : TALER_LOG_DEBUG ("... deposit_fee was %s\n",
1932 : TALER_amount2s (&dki->fees.deposit));
1933 0 : return GNUNET_SYSERR;
1934 : }
1935 :
1936 : /* check coin signature */
1937 : {
1938 0 : struct TALER_CoinPublicInfo coin_info = {
1939 : .coin_pub = cdd->coin_pub,
1940 : .denom_pub_hash = cdd->h_denom_pub,
1941 : .denom_sig = cdd->denom_sig,
1942 : .h_age_commitment = cdd->h_age_commitment,
1943 : };
1944 :
1945 0 : if (GNUNET_YES !=
1946 0 : TALER_test_coin_valid (&coin_info,
1947 : &dki->key))
1948 : {
1949 0 : GNUNET_break_op (0);
1950 0 : TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
1951 0 : return GNUNET_SYSERR;
1952 : }
1953 : }
1954 :
1955 : /* Check coin does make a contribution */
1956 0 : if (0 < TALER_amount_cmp (&dki->fees.deposit,
1957 : &cdd->amount))
1958 : {
1959 0 : GNUNET_break_op (0);
1960 0 : TALER_LOG_WARNING ("Deposit amount smaller than fee\n");
1961 0 : return GNUNET_SYSERR;
1962 : }
1963 0 : return GNUNET_OK;
1964 : }
1965 :
1966 :
1967 : /* end of exchange_api_common.c */
|