Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2023 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it
6 : under the terms of the GNU General Public License as published
7 : by the Free Software Foundation; either version 3, or (at your
8 : option) any later version.
9 :
10 : TALER is distributed in the hope that it will be useful, but
11 : WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU General Public License for more details.
14 :
15 : You should have received a copy of the GNU General Public
16 : License along with TALER; see the file COPYING. If not, see
17 : <http://www.gnu.org/licenses/>
18 : */
19 :
20 : /**
21 : * @file lib/exchange_api_handle.c
22 : * @brief Implementation of the "handle" component of the exchange's HTTP API
23 : * @author Sree Harsha Totakura <sreeharsha@totakura.in>
24 : * @author Christian Grothoff
25 : */
26 : #include "taler/platform.h"
27 : #include <microhttpd.h>
28 : #include <gnunet/gnunet_curl_lib.h>
29 : #include "taler/taler_json_lib.h"
30 : #include "taler/taler_exchange_service.h"
31 : #include "taler/taler_auditor_service.h"
32 : #include "taler/taler_signatures.h"
33 : #include "taler/taler_extensions.h"
34 : #include "exchange_api_handle.h"
35 : #include "exchange_api_curl_defaults.h"
36 : #include "taler/backoff.h"
37 : #include "taler/taler_curl_lib.h"
38 :
39 : /**
40 : * Which version of the Taler protocol is implemented
41 : * by this library? Used to determine compatibility.
42 : */
43 : #define EXCHANGE_PROTOCOL_CURRENT 33
44 :
45 : /**
46 : * How many versions are we backwards compatible with?
47 : */
48 : #define EXCHANGE_PROTOCOL_AGE 7
49 :
50 : /**
51 : * Set to 1 for extra debug logging.
52 : */
53 : #define DEBUG 0
54 :
55 : /**
56 : * Current version for (local) JSON serialization of persisted
57 : * /keys data.
58 : */
59 : #define EXCHANGE_SERIALIZATION_FORMAT_VERSION 0
60 :
61 : /**
62 : * How far off do we allow key lifetimes to be?
63 : */
64 : #define LIFETIME_TOLERANCE GNUNET_TIME_UNIT_HOURS
65 :
66 : /**
67 : * Element in the `struct SignatureContext` array.
68 : */
69 : struct SignatureElement
70 : {
71 :
72 : /**
73 : * Offset of the denomination in the group array,
74 : * for sorting (2nd rank, ascending).
75 : */
76 : unsigned int offset;
77 :
78 : /**
79 : * Offset of the group in the denominations array,
80 : * for sorting (2nd rank, ascending).
81 : */
82 : unsigned int group_offset;
83 :
84 : /**
85 : * Pointer to actual master signature to hash over.
86 : */
87 : struct TALER_MasterSignatureP master_sig;
88 : };
89 :
90 : /**
91 : * Context for collecting the array of master signatures
92 : * needed to verify the exchange_sig online signature.
93 : */
94 : struct SignatureContext
95 : {
96 : /**
97 : * Array of signatures to hash over.
98 : */
99 : struct SignatureElement *elements;
100 :
101 : /**
102 : * Write offset in the @e elements array.
103 : */
104 : unsigned int elements_pos;
105 :
106 : /**
107 : * Allocated space for @e elements.
108 : */
109 : unsigned int elements_size;
110 : };
111 :
112 :
113 : /**
114 : * Determine order to sort two elements by before
115 : * we hash the master signatures. Used for
116 : * sorting with qsort().
117 : *
118 : * @param a pointer to a `struct SignatureElement`
119 : * @param b pointer to a `struct SignatureElement`
120 : * @return 0 if equal, -1 if a < b, 1 if a > b.
121 : */
122 : static int
123 1960 : signature_context_sort_cb (const void *a,
124 : const void *b)
125 : {
126 1960 : const struct SignatureElement *sa = a;
127 1960 : const struct SignatureElement *sb = b;
128 :
129 1960 : if (sa->group_offset < sb->group_offset)
130 1170 : return -1;
131 790 : if (sa->group_offset > sb->group_offset)
132 0 : return 1;
133 790 : if (sa->offset < sb->offset)
134 790 : return -1;
135 0 : if (sa->offset > sb->offset)
136 0 : return 1;
137 : /* We should never have two disjoint elements
138 : with same time and offset */
139 0 : GNUNET_assert (sa == sb);
140 0 : return 0;
141 : }
142 :
143 :
144 : /**
145 : * Append a @a master_sig to the @a sig_ctx using the
146 : * given attributes for (later) sorting.
147 : *
148 : * @param[in,out] sig_ctx signature context to update
149 : * @param group_offset offset for the group
150 : * @param offset offset for the entry
151 : * @param master_sig master signature for the entry
152 : */
153 : static void
154 816 : append_signature (struct SignatureContext *sig_ctx,
155 : unsigned int group_offset,
156 : unsigned int offset,
157 : const struct TALER_MasterSignatureP *master_sig)
158 : {
159 : struct SignatureElement *element;
160 : unsigned int new_size;
161 :
162 816 : if (sig_ctx->elements_pos == sig_ctx->elements_size)
163 : {
164 34 : if (0 == sig_ctx->elements_size)
165 34 : new_size = 1024;
166 : else
167 0 : new_size = sig_ctx->elements_size * 2;
168 34 : GNUNET_array_grow (sig_ctx->elements,
169 : sig_ctx->elements_size,
170 : new_size);
171 : }
172 816 : element = &sig_ctx->elements[sig_ctx->elements_pos++];
173 816 : element->offset = offset;
174 816 : element->group_offset = group_offset;
175 816 : element->master_sig = *master_sig;
176 816 : }
177 :
178 :
179 : /**
180 : * Frees @a wfm array.
181 : *
182 : * @param wfm fee array to release
183 : * @param wfm_len length of the @a wfm array
184 : */
185 : static void
186 42 : free_fees (struct TALER_EXCHANGE_WireFeesByMethod *wfm,
187 : unsigned int wfm_len)
188 : {
189 84 : for (unsigned int i = 0; i<wfm_len; i++)
190 : {
191 42 : struct TALER_EXCHANGE_WireFeesByMethod *wfmi = &wfm[i];
192 :
193 126 : while (NULL != wfmi->fees_head)
194 : {
195 84 : struct TALER_EXCHANGE_WireAggregateFees *fe
196 : = wfmi->fees_head;
197 :
198 84 : wfmi->fees_head = fe->next;
199 84 : GNUNET_free (fe);
200 : }
201 42 : GNUNET_free (wfmi->method);
202 : }
203 42 : GNUNET_free (wfm);
204 42 : }
205 :
206 :
207 : /**
208 : * Parse wire @a fees and return array.
209 : *
210 : * @param master_pub master public key to use to check signatures
211 : * @param currency currency amounts are expected in
212 : * @param fees json AggregateTransferFee to parse
213 : * @param[out] fees_len set to length of returned array
214 : * @return NULL on error
215 : */
216 : static struct TALER_EXCHANGE_WireFeesByMethod *
217 42 : parse_fees (const struct TALER_MasterPublicKeyP *master_pub,
218 : const char *currency,
219 : const json_t *fees,
220 : unsigned int *fees_len)
221 : {
222 : struct TALER_EXCHANGE_WireFeesByMethod *fbm;
223 42 : size_t fbml = json_object_size (fees);
224 42 : unsigned int i = 0;
225 : const char *key;
226 : const json_t *fee_array;
227 :
228 42 : if (UINT_MAX < fbml)
229 : {
230 0 : GNUNET_break (0);
231 0 : return NULL;
232 : }
233 42 : fbm = GNUNET_new_array (fbml,
234 : struct TALER_EXCHANGE_WireFeesByMethod);
235 42 : *fees_len = (unsigned int) fbml;
236 84 : json_object_foreach ((json_t *) fees, key, fee_array) {
237 42 : struct TALER_EXCHANGE_WireFeesByMethod *fe = &fbm[i++];
238 : size_t idx;
239 : json_t *fee;
240 :
241 42 : fe->method = GNUNET_strdup (key);
242 42 : fe->fees_head = NULL;
243 126 : json_array_foreach (fee_array, idx, fee)
244 : {
245 : struct TALER_EXCHANGE_WireAggregateFees *wa
246 84 : = GNUNET_new (struct TALER_EXCHANGE_WireAggregateFees);
247 : struct GNUNET_JSON_Specification spec[] = {
248 84 : GNUNET_JSON_spec_fixed_auto ("sig",
249 : &wa->master_sig),
250 84 : TALER_JSON_spec_amount ("wire_fee",
251 : currency,
252 : &wa->fees.wire),
253 84 : TALER_JSON_spec_amount ("closing_fee",
254 : currency,
255 : &wa->fees.closing),
256 84 : GNUNET_JSON_spec_timestamp ("start_date",
257 : &wa->start_date),
258 84 : GNUNET_JSON_spec_timestamp ("end_date",
259 : &wa->end_date),
260 84 : GNUNET_JSON_spec_end ()
261 : };
262 :
263 84 : wa->next = fe->fees_head;
264 84 : fe->fees_head = wa;
265 84 : if (GNUNET_OK !=
266 84 : GNUNET_JSON_parse (fee,
267 : spec,
268 : NULL,
269 : NULL))
270 : {
271 0 : GNUNET_break_op (0);
272 0 : free_fees (fbm,
273 : i);
274 0 : return NULL;
275 : }
276 84 : if (GNUNET_OK !=
277 84 : TALER_exchange_offline_wire_fee_verify (
278 : key,
279 : wa->start_date,
280 : wa->end_date,
281 84 : &wa->fees,
282 : master_pub,
283 84 : &wa->master_sig))
284 : {
285 0 : GNUNET_break_op (0);
286 0 : free_fees (fbm,
287 : i);
288 0 : return NULL;
289 : }
290 : } /* for all fees over time */
291 : } /* for all methods */
292 42 : GNUNET_assert (i == fbml);
293 42 : return fbm;
294 : }
295 :
296 :
297 : void
298 84 : TALER_EXCHANGE_get_auditors_for_dc_ (
299 : struct TALER_EXCHANGE_Keys *keys,
300 : TEAH_AuditorCallback ac,
301 : void *ac_cls)
302 : {
303 84 : if (0 == keys->num_auditors)
304 : {
305 52 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
306 : "No auditor available. Not submitting deposit confirmations.\n")
307 : ;
308 52 : return;
309 : }
310 64 : for (unsigned int i = 0; i<keys->num_auditors; i++)
311 : {
312 32 : const struct TALER_EXCHANGE_AuditorInformation *auditor
313 32 : = &keys->auditors[i];
314 :
315 32 : ac (ac_cls,
316 32 : auditor->auditor_url,
317 : &auditor->auditor_pub);
318 : }
319 : }
320 :
321 :
322 : #define EXITIF(cond) \
323 : do { \
324 : if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
325 : } while (0)
326 :
327 :
328 : /**
329 : * Parse a exchange's signing key encoded in JSON.
330 : *
331 : * @param[out] sign_key where to return the result
332 : * @param check_sigs should we check signatures?
333 : * @param sign_key_obj json to parse
334 : * @param master_key master key to use to verify signature
335 : * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
336 : * invalid or the @a sign_key_obj is malformed.
337 : */
338 : static enum GNUNET_GenericReturnValue
339 45 : parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key,
340 : bool check_sigs,
341 : const json_t *sign_key_obj,
342 : const struct TALER_MasterPublicKeyP *master_key)
343 : {
344 : struct GNUNET_JSON_Specification spec[] = {
345 45 : GNUNET_JSON_spec_fixed_auto ("master_sig",
346 : &sign_key->master_sig),
347 45 : GNUNET_JSON_spec_fixed_auto ("key",
348 : &sign_key->key),
349 45 : GNUNET_JSON_spec_timestamp ("stamp_start",
350 : &sign_key->valid_from),
351 45 : GNUNET_JSON_spec_timestamp ("stamp_expire",
352 : &sign_key->valid_until),
353 45 : GNUNET_JSON_spec_timestamp ("stamp_end",
354 : &sign_key->valid_legal),
355 45 : GNUNET_JSON_spec_end ()
356 : };
357 :
358 45 : if (GNUNET_OK !=
359 45 : GNUNET_JSON_parse (sign_key_obj,
360 : spec,
361 : NULL, NULL))
362 : {
363 0 : GNUNET_break_op (0);
364 0 : return GNUNET_SYSERR;
365 : }
366 45 : if (! check_sigs)
367 8 : return GNUNET_OK;
368 37 : if (GNUNET_OK !=
369 37 : TALER_exchange_offline_signkey_validity_verify (
370 37 : &sign_key->key,
371 : sign_key->valid_from,
372 : sign_key->valid_until,
373 : sign_key->valid_legal,
374 : master_key,
375 37 : &sign_key->master_sig))
376 : {
377 0 : GNUNET_break_op (0);
378 0 : return GNUNET_SYSERR;
379 : }
380 37 : return GNUNET_OK;
381 : }
382 :
383 :
384 : /**
385 : * Parse a exchange's denomination key encoded in JSON partially.
386 : *
387 : * Only the values for master_sig, timestamps and the cipher-specific public
388 : * key are parsed. All other fields (fees, age_mask, value) MUST have been set
389 : * prior to calling this function, otherwise the signature verification
390 : * performed within this function will fail.
391 : *
392 : * @param[out] denom_key where to return the result
393 : * @param cipher cipher type to parse
394 : * @param check_sigs should we check signatures?
395 : * @param denom_key_obj json to parse
396 : * @param master_key master key to use to verify signature
397 : * @param group_offset offset for the group
398 : * @param index index of this denomination key in the group
399 : * @param sig_ctx where to write details about encountered
400 : * master signatures, NULL if not used
401 : * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
402 : * invalid or the json malformed.
403 : */
404 : static enum GNUNET_GenericReturnValue
405 921 : parse_json_denomkey_partially (
406 : struct TALER_EXCHANGE_DenomPublicKey *denom_key,
407 : enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher,
408 : bool check_sigs,
409 : const json_t *denom_key_obj,
410 : struct TALER_MasterPublicKeyP *master_key,
411 : unsigned int group_offset,
412 : unsigned int index,
413 : struct SignatureContext *sig_ctx)
414 : {
415 : struct GNUNET_JSON_Specification spec[] = {
416 921 : GNUNET_JSON_spec_fixed_auto ("master_sig",
417 : &denom_key->master_sig),
418 921 : GNUNET_JSON_spec_timestamp ("stamp_expire_deposit",
419 : &denom_key->expire_deposit),
420 921 : GNUNET_JSON_spec_timestamp ("stamp_expire_withdraw",
421 : &denom_key->withdraw_valid_until),
422 921 : GNUNET_JSON_spec_timestamp ("stamp_start",
423 : &denom_key->valid_from),
424 921 : GNUNET_JSON_spec_timestamp ("stamp_expire_legal",
425 : &denom_key->expire_legal),
426 921 : GNUNET_JSON_spec_mark_optional (
427 : GNUNET_JSON_spec_bool ("lost",
428 : &denom_key->lost),
429 : NULL),
430 921 : TALER_JSON_spec_denom_pub_cipher (NULL,
431 : cipher,
432 : &denom_key->key),
433 921 : GNUNET_JSON_spec_end ()
434 : };
435 :
436 921 : if (GNUNET_OK !=
437 921 : GNUNET_JSON_parse (denom_key_obj,
438 : spec,
439 : NULL, NULL))
440 : {
441 0 : GNUNET_break_op (0);
442 0 : return GNUNET_SYSERR;
443 : }
444 921 : TALER_denom_pub_hash (&denom_key->key,
445 : &denom_key->h_key);
446 921 : if (NULL != sig_ctx)
447 816 : append_signature (sig_ctx,
448 : group_offset,
449 : index,
450 816 : &denom_key->master_sig);
451 921 : if (! check_sigs)
452 105 : return GNUNET_OK;
453 816 : EXITIF (GNUNET_SYSERR ==
454 : TALER_exchange_offline_denom_validity_verify (
455 : &denom_key->h_key,
456 : denom_key->valid_from,
457 : denom_key->withdraw_valid_until,
458 : denom_key->expire_deposit,
459 : denom_key->expire_legal,
460 : &denom_key->value,
461 : &denom_key->fees,
462 : master_key,
463 : &denom_key->master_sig));
464 816 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
465 : "Learned denomination key %s\n",
466 : GNUNET_h2s (&denom_key->h_key.hash));
467 816 : return GNUNET_OK;
468 0 : EXITIF_exit:
469 0 : GNUNET_JSON_parse_free (spec);
470 : /* invalidate denom_key, just to be sure */
471 0 : memset (denom_key,
472 : 0,
473 : sizeof (*denom_key));
474 0 : return GNUNET_SYSERR;
475 : }
476 :
477 :
478 : /**
479 : * Parse a exchange's auditor information encoded in JSON.
480 : *
481 : * @param[out] auditor where to return the result
482 : * @param check_sigs should we check signatures
483 : * @param auditor_obj json to parse
484 : * @param key_data information about denomination keys
485 : * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
486 : * invalid or the json malformed.
487 : */
488 : static enum GNUNET_GenericReturnValue
489 12 : parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
490 : bool check_sigs,
491 : const json_t *auditor_obj,
492 : const struct TALER_EXCHANGE_Keys *key_data)
493 : {
494 : const json_t *keys;
495 : json_t *key;
496 : size_t off;
497 : size_t pos;
498 : const char *auditor_url;
499 : const char *auditor_name;
500 : struct GNUNET_JSON_Specification spec[] = {
501 12 : GNUNET_JSON_spec_fixed_auto ("auditor_pub",
502 : &auditor->auditor_pub),
503 12 : TALER_JSON_spec_web_url ("auditor_url",
504 : &auditor_url),
505 12 : GNUNET_JSON_spec_string ("auditor_name",
506 : &auditor_name),
507 12 : GNUNET_JSON_spec_array_const ("denomination_keys",
508 : &keys),
509 12 : GNUNET_JSON_spec_end ()
510 : };
511 :
512 12 : if (GNUNET_OK !=
513 12 : GNUNET_JSON_parse (auditor_obj,
514 : spec,
515 : NULL, NULL))
516 : {
517 0 : GNUNET_break_op (0);
518 : #if DEBUG
519 : json_dumpf (auditor_obj,
520 : stderr,
521 : JSON_INDENT (2));
522 : #endif
523 0 : return GNUNET_SYSERR;
524 : }
525 12 : auditor->auditor_url = GNUNET_strdup (auditor_url);
526 12 : auditor->auditor_name = GNUNET_strdup (auditor_name);
527 : auditor->denom_keys
528 12 : = GNUNET_new_array (json_array_size (keys),
529 : struct TALER_EXCHANGE_AuditorDenominationInfo);
530 12 : pos = 0;
531 12 : json_array_foreach (keys, off, key) {
532 : struct TALER_AuditorSignatureP auditor_sig;
533 : struct TALER_DenominationHashP denom_h;
534 0 : const struct TALER_EXCHANGE_DenomPublicKey *dk = NULL;
535 0 : unsigned int dk_off = UINT_MAX;
536 : struct GNUNET_JSON_Specification kspec[] = {
537 0 : GNUNET_JSON_spec_fixed_auto ("auditor_sig",
538 : &auditor_sig),
539 0 : GNUNET_JSON_spec_fixed_auto ("denom_pub_h",
540 : &denom_h),
541 0 : GNUNET_JSON_spec_end ()
542 : };
543 :
544 0 : if (GNUNET_OK !=
545 0 : GNUNET_JSON_parse (key,
546 : kspec,
547 : NULL, NULL))
548 : {
549 0 : GNUNET_break_op (0);
550 0 : continue;
551 : }
552 0 : for (unsigned int j = 0; j<key_data->num_denom_keys; j++)
553 : {
554 0 : if (0 == GNUNET_memcmp (&denom_h,
555 : &key_data->denom_keys[j].h_key))
556 : {
557 0 : dk = &key_data->denom_keys[j];
558 0 : dk_off = j;
559 0 : break;
560 : }
561 : }
562 0 : if (NULL == dk)
563 : {
564 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
565 : "Auditor signed denomination %s, which we do not know. Ignoring signature.\n",
566 : GNUNET_h2s (&denom_h.hash));
567 0 : continue;
568 : }
569 0 : if (check_sigs)
570 : {
571 0 : if (GNUNET_OK !=
572 0 : TALER_auditor_denom_validity_verify (
573 : auditor_url,
574 : &dk->h_key,
575 : &key_data->master_pub,
576 : dk->valid_from,
577 : dk->withdraw_valid_until,
578 : dk->expire_deposit,
579 : dk->expire_legal,
580 : &dk->value,
581 : &dk->fees,
582 0 : &auditor->auditor_pub,
583 : &auditor_sig))
584 : {
585 0 : GNUNET_break_op (0);
586 0 : return GNUNET_SYSERR;
587 : }
588 : }
589 0 : auditor->denom_keys[pos].denom_key_offset = dk_off;
590 0 : auditor->denom_keys[pos].auditor_sig = auditor_sig;
591 0 : pos++;
592 : }
593 12 : if (pos > UINT_MAX)
594 : {
595 0 : GNUNET_break (0);
596 0 : return GNUNET_SYSERR;
597 : }
598 12 : auditor->num_denom_keys = (unsigned int) pos;
599 12 : return GNUNET_OK;
600 : }
601 :
602 :
603 : /**
604 : * Parse a exchange's global fee information encoded in JSON.
605 : *
606 : * @param[out] gf where to return the result
607 : * @param check_sigs should we check signatures
608 : * @param fee_obj json to parse
609 : * @param key_data already parsed information about the exchange
610 : * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
611 : * invalid or the json malformed.
612 : */
613 : static enum GNUNET_GenericReturnValue
614 84 : parse_global_fee (struct TALER_EXCHANGE_GlobalFee *gf,
615 : bool check_sigs,
616 : const json_t *fee_obj,
617 : const struct TALER_EXCHANGE_Keys *key_data)
618 : {
619 : struct GNUNET_JSON_Specification spec[] = {
620 84 : GNUNET_JSON_spec_timestamp ("start_date",
621 : &gf->start_date),
622 84 : GNUNET_JSON_spec_timestamp ("end_date",
623 : &gf->end_date),
624 84 : GNUNET_JSON_spec_relative_time ("purse_timeout",
625 : &gf->purse_timeout),
626 84 : GNUNET_JSON_spec_relative_time ("history_expiration",
627 : &gf->history_expiration),
628 84 : GNUNET_JSON_spec_uint32 ("purse_account_limit",
629 : &gf->purse_account_limit),
630 84 : TALER_JSON_SPEC_GLOBAL_FEES (key_data->currency,
631 : &gf->fees),
632 84 : GNUNET_JSON_spec_fixed_auto ("master_sig",
633 : &gf->master_sig),
634 84 : GNUNET_JSON_spec_end ()
635 : };
636 :
637 84 : if (GNUNET_OK !=
638 84 : GNUNET_JSON_parse (fee_obj,
639 : spec,
640 : NULL, NULL))
641 : {
642 0 : GNUNET_break_op (0);
643 : #if DEBUG
644 : json_dumpf (fee_obj,
645 : stderr,
646 : JSON_INDENT (2));
647 : #endif
648 0 : return GNUNET_SYSERR;
649 : }
650 84 : if (check_sigs)
651 : {
652 68 : if (GNUNET_OK !=
653 68 : TALER_exchange_offline_global_fee_verify (
654 : gf->start_date,
655 : gf->end_date,
656 68 : &gf->fees,
657 : gf->purse_timeout,
658 : gf->history_expiration,
659 : gf->purse_account_limit,
660 : &key_data->master_pub,
661 68 : &gf->master_sig))
662 : {
663 0 : GNUNET_break_op (0);
664 0 : GNUNET_JSON_parse_free (spec);
665 0 : return GNUNET_SYSERR;
666 : }
667 : }
668 84 : GNUNET_JSON_parse_free (spec);
669 84 : return GNUNET_OK;
670 : }
671 :
672 :
673 : /**
674 : * Compare two denomination keys. Ignores revocation data.
675 : *
676 : * @param denom1 first denomination key
677 : * @param denom2 second denomination key
678 : * @return 0 if the two keys are equal (not necessarily
679 : * the same object), non-zero otherwise.
680 : */
681 : static unsigned int
682 16856 : denoms_cmp (const struct TALER_EXCHANGE_DenomPublicKey *denom1,
683 : const struct TALER_EXCHANGE_DenomPublicKey *denom2)
684 : {
685 : struct TALER_EXCHANGE_DenomPublicKey tmp1;
686 : struct TALER_EXCHANGE_DenomPublicKey tmp2;
687 :
688 16856 : if (0 !=
689 16856 : TALER_denom_pub_cmp (&denom1->key,
690 : &denom2->key))
691 8600 : return 1;
692 8256 : tmp1 = *denom1;
693 8256 : tmp2 = *denom2;
694 8256 : tmp1.revoked = false;
695 8256 : tmp2.revoked = false;
696 8256 : memset (&tmp1.key,
697 : 0,
698 : sizeof (tmp1.key));
699 8256 : memset (&tmp2.key,
700 : 0,
701 : sizeof (tmp2.key));
702 8256 : return GNUNET_memcmp (&tmp1,
703 : &tmp2);
704 : }
705 :
706 :
707 : /**
708 : * Decode the JSON array in @a hard_limits from the /keys response
709 : * and store the data in `hard_limits` array the @a key_data.
710 : *
711 : * @param[in] hard_limits JSON array to parse
712 : * @param[out] key_data where to store the results we decoded
713 : * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
714 : * (malformed JSON)
715 : */
716 : static enum GNUNET_GenericReturnValue
717 42 : parse_hard_limits (const json_t *hard_limits,
718 : struct TALER_EXCHANGE_Keys *key_data)
719 : {
720 : json_t *obj;
721 : size_t off;
722 :
723 : key_data->hard_limits_length
724 42 : = (unsigned int) json_array_size (hard_limits);
725 42 : if ( ((size_t) key_data->hard_limits_length)
726 42 : != json_array_size (hard_limits))
727 : {
728 0 : GNUNET_break (0);
729 0 : return GNUNET_SYSERR;
730 : }
731 : key_data->hard_limits
732 42 : = GNUNET_new_array (key_data->hard_limits_length,
733 : struct TALER_EXCHANGE_AccountLimit);
734 :
735 42 : json_array_foreach (hard_limits, off, obj)
736 : {
737 0 : struct TALER_EXCHANGE_AccountLimit *al
738 0 : = &key_data->hard_limits[off];
739 : struct GNUNET_JSON_Specification spec[] = {
740 0 : TALER_JSON_spec_kycte ("operation_type",
741 : &al->operation_type),
742 0 : TALER_JSON_spec_amount_any ("threshold",
743 : &al->threshold),
744 0 : GNUNET_JSON_spec_relative_time ("timeframe",
745 : &al->timeframe),
746 0 : GNUNET_JSON_spec_mark_optional (
747 : GNUNET_JSON_spec_bool ("soft_limit",
748 : &al->soft_limit),
749 : NULL),
750 0 : GNUNET_JSON_spec_end ()
751 : };
752 :
753 0 : if (GNUNET_OK !=
754 0 : GNUNET_JSON_parse (obj,
755 : spec,
756 : NULL, NULL))
757 : {
758 0 : GNUNET_break_op (0);
759 0 : return GNUNET_SYSERR;
760 : }
761 : }
762 42 : return GNUNET_OK;
763 : }
764 :
765 :
766 : /**
767 : * Decode the JSON array in @a zero_limits from the /keys response
768 : * and store the data in `zero_limits` array the @a key_data.
769 : *
770 : * @param[in] zero_limits JSON array to parse
771 : * @param[out] key_data where to store the results we decoded
772 : * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
773 : * (malformed JSON)
774 : */
775 : static enum GNUNET_GenericReturnValue
776 42 : parse_zero_limits (const json_t *zero_limits,
777 : struct TALER_EXCHANGE_Keys *key_data)
778 : {
779 : json_t *obj;
780 : size_t off;
781 :
782 : key_data->zero_limits_length
783 42 : = (unsigned int) json_array_size (zero_limits);
784 42 : if ( ((size_t) key_data->zero_limits_length)
785 42 : != json_array_size (zero_limits))
786 : {
787 0 : GNUNET_break (0);
788 0 : return GNUNET_SYSERR;
789 : }
790 : key_data->zero_limits
791 42 : = GNUNET_new_array (key_data->zero_limits_length,
792 : struct TALER_EXCHANGE_ZeroLimitedOperation);
793 :
794 65 : json_array_foreach (zero_limits, off, obj)
795 : {
796 23 : struct TALER_EXCHANGE_ZeroLimitedOperation *zol
797 23 : = &key_data->zero_limits[off];
798 : struct GNUNET_JSON_Specification spec[] = {
799 23 : TALER_JSON_spec_kycte ("operation_type",
800 : &zol->operation_type),
801 23 : GNUNET_JSON_spec_end ()
802 : };
803 :
804 23 : if (GNUNET_OK !=
805 23 : GNUNET_JSON_parse (obj,
806 : spec,
807 : NULL, NULL))
808 : {
809 0 : GNUNET_break_op (0);
810 0 : return GNUNET_SYSERR;
811 : }
812 : }
813 42 : return GNUNET_OK;
814 : }
815 :
816 :
817 : /**
818 : * Parse the wads (partner exchange) array from /keys and store the
819 : * data in @a key_data.
820 : *
821 : * @param[in] wads_array JSON array to parse
822 : * @param check_sig true if we should verify signatures
823 : * @param[out] key_data where to store the results
824 : * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
825 : */
826 : static enum GNUNET_GenericReturnValue
827 42 : parse_wads (const json_t *wads_array,
828 : bool check_sig,
829 : struct TALER_EXCHANGE_Keys *key_data)
830 : {
831 42 : size_t n = json_array_size (wads_array);
832 : json_t *wad_obj;
833 : size_t index;
834 :
835 42 : if (n > UINT_MAX)
836 : {
837 0 : GNUNET_break (0);
838 0 : return GNUNET_SYSERR;
839 : }
840 42 : if (0 == n)
841 42 : return GNUNET_OK;
842 0 : key_data->num_wad_partners = (unsigned int) n;
843 : key_data->wad_partners
844 0 : = GNUNET_new_array (n,
845 : struct TALER_EXCHANGE_WadPartner);
846 0 : json_array_foreach (wads_array, index, wad_obj)
847 : {
848 0 : struct TALER_EXCHANGE_WadPartner *wp
849 0 : = &key_data->wad_partners[index];
850 : const char *partner_base_url;
851 : struct GNUNET_JSON_Specification spec[] = {
852 0 : TALER_JSON_spec_web_url ("partner_base_url",
853 : &partner_base_url),
854 0 : GNUNET_JSON_spec_fixed_auto ("partner_master_pub",
855 : &wp->partner_master_pub),
856 0 : TALER_JSON_spec_amount ("wad_fee",
857 0 : key_data->currency,
858 : &wp->wad_fee),
859 0 : GNUNET_JSON_spec_relative_time ("wad_frequency",
860 : &wp->wad_frequency),
861 0 : GNUNET_JSON_spec_timestamp ("start_date",
862 : &wp->start_date),
863 0 : GNUNET_JSON_spec_timestamp ("end_date",
864 : &wp->end_date),
865 0 : GNUNET_JSON_spec_fixed_auto ("master_sig",
866 : &wp->master_sig),
867 0 : GNUNET_JSON_spec_end ()
868 : };
869 :
870 0 : if (GNUNET_OK !=
871 0 : GNUNET_JSON_parse (wad_obj,
872 : spec,
873 : NULL, NULL))
874 : {
875 0 : GNUNET_break_op (0);
876 0 : return GNUNET_SYSERR;
877 : }
878 0 : wp->partner_base_url = GNUNET_strdup (partner_base_url);
879 0 : if (check_sig &&
880 : GNUNET_OK !=
881 0 : TALER_exchange_offline_partner_details_verify (
882 0 : &wp->partner_master_pub,
883 : wp->start_date,
884 : wp->end_date,
885 : wp->wad_frequency,
886 0 : &wp->wad_fee,
887 : partner_base_url,
888 0 : &key_data->master_pub,
889 0 : &wp->master_sig))
890 : {
891 0 : GNUNET_break_op (0);
892 0 : return GNUNET_SYSERR;
893 : }
894 : }
895 0 : return GNUNET_OK;
896 : }
897 :
898 :
899 : /**
900 : * Decode the JSON in @a resp_obj from the /keys response
901 : * and store the data in the @a key_data.
902 : *
903 : * @param[in] resp_obj JSON object to parse
904 : * @param check_sig true if we should check the signature
905 : * @param[out] key_data where to store the results we decoded
906 : * @param[out] vc where to store version compatibility data
907 : * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
908 : * (malformed JSON)
909 : */
910 : enum GNUNET_GenericReturnValue
911 42 : TALER_EXCHANGE_decode_keys_json_ (
912 : const json_t *resp_obj,
913 : bool check_sig,
914 : struct TALER_EXCHANGE_Keys *key_data,
915 : enum TALER_EXCHANGE_VersionCompatibility *vc)
916 : {
917 : struct TALER_ExchangeSignatureP exchange_sig;
918 : struct TALER_ExchangePublicKeyP exchange_pub;
919 42 : const json_t *wblwk = NULL;
920 : const json_t *global_fees;
921 : const json_t *sign_keys_array;
922 : const json_t *denominations_by_group;
923 : const json_t *auditors_array;
924 42 : const json_t *recoup_array = NULL;
925 42 : const json_t *manifests = NULL;
926 42 : bool no_extensions = false;
927 42 : bool no_signature = false;
928 : const json_t *accounts;
929 : const json_t *fees;
930 : const json_t *wads;
931 42 : const char *shopping_url = NULL;
932 42 : const char *open_banking_gateway = NULL;
933 42 : const char *wire_transfer_gateway = NULL;
934 42 : const char *bank_compliance_language = NULL;
935 42 : struct SignatureContext sig_ctx = { 0 };
936 :
937 42 : if (JSON_OBJECT != json_typeof (resp_obj))
938 : {
939 0 : GNUNET_break_op (0);
940 0 : return GNUNET_SYSERR;
941 : }
942 : #if DEBUG
943 : json_dumpf (resp_obj,
944 : stderr,
945 : JSON_INDENT (2));
946 : #endif
947 : /* check the version first */
948 : {
949 : struct TALER_JSON_ProtocolVersion pv;
950 : struct GNUNET_JSON_Specification spec[] = {
951 42 : TALER_JSON_spec_version ("version",
952 : &pv),
953 42 : GNUNET_JSON_spec_end ()
954 : };
955 :
956 42 : if (GNUNET_OK !=
957 42 : GNUNET_JSON_parse (resp_obj,
958 : spec,
959 : NULL, NULL))
960 : {
961 0 : GNUNET_break_op (0);
962 0 : return GNUNET_SYSERR;
963 : }
964 42 : *vc = TALER_EXCHANGE_VC_MATCH;
965 42 : if (EXCHANGE_PROTOCOL_CURRENT < pv.current)
966 : {
967 0 : *vc |= TALER_EXCHANGE_VC_NEWER;
968 0 : if (EXCHANGE_PROTOCOL_CURRENT < pv.current - pv.age)
969 0 : *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE;
970 : }
971 42 : if (EXCHANGE_PROTOCOL_CURRENT > pv.current)
972 : {
973 42 : *vc |= TALER_EXCHANGE_VC_OLDER;
974 42 : if (EXCHANGE_PROTOCOL_CURRENT - EXCHANGE_PROTOCOL_AGE > pv.current)
975 0 : *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE;
976 : }
977 : }
978 :
979 : {
980 : const char *ver;
981 : const char *currency;
982 : const char *asset_type;
983 : struct GNUNET_JSON_Specification mspec[] = {
984 42 : GNUNET_JSON_spec_fixed_auto (
985 : "exchange_sig",
986 : &exchange_sig),
987 42 : GNUNET_JSON_spec_fixed_auto (
988 : "exchange_pub",
989 : &exchange_pub),
990 42 : GNUNET_JSON_spec_fixed_auto (
991 : "master_public_key",
992 : &key_data->master_pub),
993 42 : GNUNET_JSON_spec_array_const ("accounts",
994 : &accounts),
995 42 : GNUNET_JSON_spec_object_const ("wire_fees",
996 : &fees),
997 42 : GNUNET_JSON_spec_array_const ("wads",
998 : &wads),
999 42 : GNUNET_JSON_spec_timestamp (
1000 : "list_issue_date",
1001 : &key_data->list_issue_date),
1002 42 : GNUNET_JSON_spec_relative_time (
1003 : "reserve_closing_delay",
1004 : &key_data->reserve_closing_delay),
1005 42 : GNUNET_JSON_spec_string (
1006 : "currency",
1007 : ¤cy),
1008 42 : GNUNET_JSON_spec_string (
1009 : "asset_type",
1010 : &asset_type),
1011 42 : GNUNET_JSON_spec_array_const (
1012 : "global_fees",
1013 : &global_fees),
1014 42 : GNUNET_JSON_spec_array_const (
1015 : "signkeys",
1016 : &sign_keys_array),
1017 42 : GNUNET_JSON_spec_array_const (
1018 : "denominations",
1019 : &denominations_by_group),
1020 42 : GNUNET_JSON_spec_mark_optional (
1021 : GNUNET_JSON_spec_array_const (
1022 : "recoup",
1023 : &recoup_array),
1024 : NULL),
1025 42 : GNUNET_JSON_spec_array_const (
1026 : "auditors",
1027 : &auditors_array),
1028 42 : GNUNET_JSON_spec_bool (
1029 : "kyc_enabled",
1030 : &key_data->kyc_enabled),
1031 42 : GNUNET_JSON_spec_mark_optional (
1032 : GNUNET_JSON_spec_object_const ("extensions",
1033 : &manifests),
1034 : &no_extensions),
1035 42 : GNUNET_JSON_spec_mark_optional (
1036 42 : GNUNET_JSON_spec_fixed_auto (
1037 : "extensions_sig",
1038 : &key_data->extensions_sig),
1039 : &no_signature),
1040 42 : GNUNET_JSON_spec_string ("version",
1041 : &ver),
1042 42 : GNUNET_JSON_spec_mark_optional (
1043 : GNUNET_JSON_spec_array_const (
1044 : "wallet_balance_limit_without_kyc",
1045 : &wblwk),
1046 : NULL),
1047 42 : GNUNET_JSON_spec_mark_optional (
1048 : GNUNET_JSON_spec_string ("shopping_url",
1049 : &shopping_url),
1050 : NULL),
1051 42 : GNUNET_JSON_spec_mark_optional (
1052 : GNUNET_JSON_spec_string ("open_banking_gateway",
1053 : &open_banking_gateway),
1054 : NULL),
1055 42 : GNUNET_JSON_spec_mark_optional (
1056 : GNUNET_JSON_spec_string ("wire_transfer_gateway",
1057 : &wire_transfer_gateway),
1058 : NULL),
1059 42 : GNUNET_JSON_spec_mark_optional (
1060 : GNUNET_JSON_spec_string ("bank_compliance_language",
1061 : &bank_compliance_language),
1062 : NULL),
1063 42 : GNUNET_JSON_spec_mark_optional (
1064 : GNUNET_JSON_spec_bool ("disable_direct_deposit",
1065 : &key_data->disable_direct_deposit),
1066 : NULL),
1067 42 : GNUNET_JSON_spec_end ()
1068 : };
1069 : const char *emsg;
1070 : unsigned int eline;
1071 :
1072 42 : if (GNUNET_OK !=
1073 42 : GNUNET_JSON_parse (resp_obj,
1074 : (check_sig) ? mspec : &mspec[2],
1075 : &emsg,
1076 : &eline))
1077 : {
1078 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1079 : "Parsing /keys failed for `%s' (%u)\n",
1080 : emsg,
1081 : eline);
1082 0 : EXITIF (1);
1083 : }
1084 : {
1085 42 : const json_t *hard_limits = NULL;
1086 42 : const json_t *zero_limits = NULL;
1087 42 : bool no_tiny_amount = false;
1088 : struct GNUNET_JSON_Specification sspec[] = {
1089 42 : TALER_JSON_spec_currency_specification (
1090 : "currency_specification",
1091 : currency,
1092 : &key_data->cspec),
1093 42 : TALER_JSON_spec_amount (
1094 : "stefan_abs",
1095 : currency,
1096 : &key_data->stefan_abs),
1097 42 : TALER_JSON_spec_amount (
1098 : "stefan_log",
1099 : currency,
1100 : &key_data->stefan_log),
1101 42 : GNUNET_JSON_spec_mark_optional (
1102 : TALER_JSON_spec_amount (
1103 : "tiny_amount",
1104 : currency,
1105 : &key_data->tiny_amount),
1106 : &no_tiny_amount),
1107 42 : GNUNET_JSON_spec_mark_optional (
1108 : GNUNET_JSON_spec_array_const (
1109 : "hard_limits",
1110 : &hard_limits),
1111 : NULL),
1112 42 : GNUNET_JSON_spec_mark_optional (
1113 : GNUNET_JSON_spec_array_const (
1114 : "zero_limits",
1115 : &zero_limits),
1116 : NULL),
1117 42 : GNUNET_JSON_spec_double (
1118 : "stefan_lin",
1119 : &key_data->stefan_lin),
1120 42 : GNUNET_JSON_spec_end ()
1121 : };
1122 :
1123 42 : if (GNUNET_OK !=
1124 42 : GNUNET_JSON_parse (resp_obj,
1125 : sspec,
1126 : &emsg,
1127 : &eline))
1128 : {
1129 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1130 : "Parsing /keys failed for `%s' (%u)\n",
1131 : emsg,
1132 : eline);
1133 0 : EXITIF (1);
1134 : }
1135 84 : if ( (NULL != hard_limits) &&
1136 : (GNUNET_OK !=
1137 42 : parse_hard_limits (hard_limits,
1138 : key_data)) )
1139 : {
1140 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1141 : "Parsing hard limits of /keys failed\n");
1142 0 : EXITIF (1);
1143 : }
1144 84 : if ( (NULL != zero_limits) &&
1145 : (GNUNET_OK !=
1146 42 : parse_zero_limits (zero_limits,
1147 : key_data)) )
1148 : {
1149 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1150 : "Parsing hard limits of /keys failed\n");
1151 0 : EXITIF (1);
1152 : }
1153 42 : key_data->tiny_amount_available = ! no_tiny_amount;
1154 : }
1155 :
1156 42 : key_data->currency = GNUNET_strdup (currency);
1157 42 : key_data->version = GNUNET_strdup (ver);
1158 42 : key_data->asset_type = GNUNET_strdup (asset_type);
1159 42 : if (NULL != shopping_url)
1160 0 : key_data->shopping_url = GNUNET_strdup (shopping_url);
1161 42 : if (NULL != open_banking_gateway)
1162 0 : key_data->open_banking_gateway = GNUNET_strdup (open_banking_gateway);
1163 42 : if (NULL != wire_transfer_gateway)
1164 0 : key_data->wire_transfer_gateway = GNUNET_strdup (wire_transfer_gateway);
1165 42 : if (NULL != bank_compliance_language)
1166 : key_data->bank_compliance_language
1167 0 : = GNUNET_strdup (bank_compliance_language);
1168 42 : if (! no_extensions)
1169 23 : key_data->extensions = json_incref ((json_t *) manifests);
1170 : }
1171 :
1172 : /* parse the global fees */
1173 42 : EXITIF (json_array_size (global_fees) > UINT_MAX);
1174 : key_data->num_global_fees
1175 42 : = (unsigned int) json_array_size (global_fees);
1176 42 : if (0 != key_data->num_global_fees)
1177 : {
1178 : json_t *global_fee;
1179 : size_t index;
1180 :
1181 : key_data->global_fees
1182 42 : = GNUNET_new_array (key_data->num_global_fees,
1183 : struct TALER_EXCHANGE_GlobalFee);
1184 126 : json_array_foreach (global_fees, index, global_fee)
1185 : {
1186 84 : EXITIF (GNUNET_SYSERR ==
1187 : parse_global_fee (&key_data->global_fees[index],
1188 : check_sig,
1189 : global_fee,
1190 : key_data));
1191 : }
1192 : }
1193 :
1194 : /* parse the signing keys */
1195 42 : EXITIF (json_array_size (sign_keys_array) > UINT_MAX);
1196 : key_data->num_sign_keys
1197 42 : = (unsigned int) json_array_size (sign_keys_array);
1198 42 : if (0 != key_data->num_sign_keys)
1199 : {
1200 : json_t *sign_key_obj;
1201 : size_t index;
1202 :
1203 : key_data->sign_keys
1204 42 : = GNUNET_new_array (key_data->num_sign_keys,
1205 : struct TALER_EXCHANGE_SigningPublicKey);
1206 87 : json_array_foreach (sign_keys_array, index, sign_key_obj) {
1207 45 : EXITIF (GNUNET_SYSERR ==
1208 : parse_json_signkey (&key_data->sign_keys[index],
1209 : check_sig,
1210 : sign_key_obj,
1211 : &key_data->master_pub));
1212 : }
1213 : }
1214 :
1215 : /* Parse balance limits */
1216 42 : if (NULL != wblwk)
1217 : {
1218 42 : EXITIF (json_array_size (wblwk) > UINT_MAX);
1219 : key_data->wblwk_length
1220 42 : = (unsigned int) json_array_size (wblwk);
1221 : key_data->wallet_balance_limit_without_kyc
1222 42 : = GNUNET_new_array (key_data->wblwk_length,
1223 : struct TALER_Amount);
1224 43 : for (unsigned int i = 0; i<key_data->wblwk_length; i++)
1225 : {
1226 1 : struct TALER_Amount *a = &key_data->wallet_balance_limit_without_kyc[i];
1227 1 : const json_t *aj = json_array_get (wblwk,
1228 : i);
1229 : struct GNUNET_JSON_Specification spec[] = {
1230 1 : TALER_JSON_spec_amount (NULL,
1231 1 : key_data->currency,
1232 : a),
1233 1 : GNUNET_JSON_spec_end ()
1234 : };
1235 :
1236 1 : EXITIF (GNUNET_OK !=
1237 : GNUNET_JSON_parse (aj,
1238 : spec,
1239 : NULL, NULL));
1240 : }
1241 : }
1242 :
1243 : /* Parse wire accounts */
1244 84 : key_data->fees = parse_fees (&key_data->master_pub,
1245 42 : key_data->currency,
1246 : fees,
1247 : &key_data->fees_len);
1248 42 : EXITIF (NULL == key_data->fees);
1249 : /* parse accounts */
1250 42 : EXITIF (json_array_size (accounts) > UINT_MAX);
1251 42 : GNUNET_array_grow (key_data->accounts,
1252 : key_data->accounts_len,
1253 : json_array_size (accounts));
1254 42 : EXITIF (GNUNET_OK !=
1255 : TALER_EXCHANGE_parse_accounts (&key_data->master_pub,
1256 : accounts,
1257 : key_data->accounts_len,
1258 : key_data->accounts));
1259 :
1260 42 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1261 : "Parsed %u wire accounts from JSON\n",
1262 : key_data->accounts_len);
1263 :
1264 : /* Parse wad partners */
1265 42 : EXITIF (GNUNET_OK !=
1266 : parse_wads (wads,
1267 : check_sig,
1268 : key_data));
1269 :
1270 :
1271 : /* Parse the supported extension(s): age-restriction. */
1272 : /* FIXME[Oec]: maybe lift all this into a FP in TALER_Extension ? */
1273 42 : if (! no_extensions)
1274 : {
1275 23 : if (no_signature)
1276 : {
1277 23 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1278 : "found extensions without signature\n");
1279 : }
1280 : else
1281 : {
1282 : /* We have an extensions object. Verify its signature. */
1283 0 : EXITIF (GNUNET_OK !=
1284 : TALER_extensions_verify_manifests_signature (
1285 : manifests,
1286 : &key_data->extensions_sig,
1287 : &key_data->master_pub));
1288 :
1289 : /* Parse and set the the configuration of the extensions accordingly */
1290 0 : EXITIF (GNUNET_OK !=
1291 : TALER_extensions_load_manifests (manifests));
1292 : }
1293 :
1294 : /* Assuming we might have now a new value for age_mask, set it in key_data */
1295 23 : key_data->age_mask = TALER_extensions_get_age_restriction_mask ();
1296 : }
1297 :
1298 : /*
1299 : * Parse the denomination keys, merging with the
1300 : * possibly EXISTING array as required (/keys cherry picking).
1301 : *
1302 : * The denominations are grouped by common values of
1303 : * {cipher, value, fee, age_mask}.
1304 : */
1305 : {
1306 : json_t *group_obj;
1307 : unsigned int group_idx;
1308 :
1309 291 : json_array_foreach (denominations_by_group,
1310 : group_idx,
1311 : group_obj)
1312 : {
1313 : /* First, parse { cipher, fees, value, age_mask, hash } of the current
1314 : group. */
1315 249 : struct TALER_DenominationGroup group = {0};
1316 : const json_t *denom_keys_array;
1317 : struct GNUNET_JSON_Specification group_spec[] = {
1318 249 : TALER_JSON_spec_denomination_group (NULL,
1319 249 : key_data->currency,
1320 : &group),
1321 249 : GNUNET_JSON_spec_array_const ("denoms",
1322 : &denom_keys_array),
1323 249 : GNUNET_JSON_spec_end ()
1324 : };
1325 : json_t *denom_key_obj;
1326 : unsigned int index;
1327 :
1328 249 : EXITIF (GNUNET_SYSERR ==
1329 : GNUNET_JSON_parse (group_obj,
1330 : group_spec,
1331 : NULL,
1332 : NULL));
1333 :
1334 : /* Now, parse the individual denominations */
1335 1170 : json_array_foreach (denom_keys_array,
1336 : index,
1337 : denom_key_obj)
1338 : {
1339 : /* Set the common fields from the group for this particular
1340 : denomination. Required to make the validity check inside
1341 : parse_json_denomkey_partially pass */
1342 921 : struct TALER_EXCHANGE_DenomPublicKey dk = {
1343 : .value = group.value,
1344 : .fees = group.fees,
1345 : .key.age_mask = group.age_mask
1346 : };
1347 921 : bool found = false;
1348 :
1349 921 : EXITIF (GNUNET_SYSERR ==
1350 : parse_json_denomkey_partially (&dk,
1351 : group.cipher,
1352 : check_sig,
1353 : denom_key_obj,
1354 : &key_data->master_pub,
1355 : group_idx,
1356 : index,
1357 : check_sig
1358 : ? &sig_ctx
1359 : : NULL));
1360 921 : for (unsigned int j = 0;
1361 17751 : j<key_data->num_denom_keys;
1362 16830 : j++)
1363 : {
1364 16856 : if (0 == denoms_cmp (&dk,
1365 16856 : &key_data->denom_keys[j]))
1366 : {
1367 26 : found = true;
1368 26 : break;
1369 : }
1370 : }
1371 :
1372 921 : if (found)
1373 : {
1374 : /* 0:0:0 did not support /keys cherry picking */
1375 26 : TALER_LOG_DEBUG ("Skipping denomination key: already know it\n");
1376 26 : TALER_denom_pub_free (&dk.key);
1377 26 : continue;
1378 : }
1379 :
1380 895 : if (key_data->denom_keys_size == key_data->num_denom_keys)
1381 131 : GNUNET_array_grow (key_data->denom_keys,
1382 : key_data->denom_keys_size,
1383 : key_data->denom_keys_size * 2 + 2);
1384 895 : GNUNET_assert (key_data->denom_keys_size >
1385 : key_data->num_denom_keys);
1386 895 : GNUNET_assert (key_data->num_denom_keys < UINT_MAX);
1387 895 : key_data->denom_keys[key_data->num_denom_keys++] = dk;
1388 :
1389 : /* Update "last_denom_issue_date" */
1390 895 : TALER_LOG_DEBUG ("Adding denomination key that is valid_until %s\n",
1391 : GNUNET_TIME_timestamp2s (dk.valid_from));
1392 : key_data->last_denom_issue_date
1393 895 : = GNUNET_TIME_timestamp_max (key_data->last_denom_issue_date,
1394 : dk.valid_from);
1395 : }; /* end of json_array_foreach over denominations */
1396 : } /* end of json_array_foreach over groups of denominations */
1397 : } /* end of scope for group_ojb/group_idx */
1398 :
1399 : /* parse the auditor information */
1400 : {
1401 : json_t *auditor_info;
1402 : unsigned int index;
1403 :
1404 : /* Merge with the existing auditor information we have (/keys cherry picking) */
1405 54 : json_array_foreach (auditors_array, index, auditor_info)
1406 : {
1407 : struct TALER_EXCHANGE_AuditorInformation ai;
1408 12 : bool found = false;
1409 :
1410 12 : memset (&ai,
1411 : 0,
1412 : sizeof (ai));
1413 12 : EXITIF (GNUNET_SYSERR ==
1414 : parse_json_auditor (&ai,
1415 : check_sig,
1416 : auditor_info,
1417 : key_data));
1418 12 : for (unsigned int j = 0; j<key_data->num_auditors; j++)
1419 : {
1420 0 : struct TALER_EXCHANGE_AuditorInformation *aix = &key_data->auditors[j];
1421 :
1422 0 : if (0 == GNUNET_memcmp (&ai.auditor_pub,
1423 : &aix->auditor_pub))
1424 : {
1425 0 : found = true;
1426 : /* Merge denomination key signatures of downloaded /keys into existing
1427 : auditor information 'aix'. */
1428 0 : TALER_LOG_DEBUG (
1429 : "Merging %u new audited keys with %u known audited keys\n",
1430 : aix->num_denom_keys,
1431 : ai.num_denom_keys);
1432 0 : for (unsigned int i = 0; i<ai.num_denom_keys; i++)
1433 : {
1434 0 : bool kfound = false;
1435 :
1436 0 : for (unsigned int k = 0; k<aix->num_denom_keys; k++)
1437 : {
1438 0 : if (aix->denom_keys[k].denom_key_offset ==
1439 0 : ai.denom_keys[i].denom_key_offset)
1440 : {
1441 0 : kfound = true;
1442 0 : break;
1443 : }
1444 : }
1445 0 : if (! kfound)
1446 0 : GNUNET_array_append (aix->denom_keys,
1447 : aix->num_denom_keys,
1448 : ai.denom_keys[i]);
1449 : }
1450 0 : break;
1451 : }
1452 : }
1453 12 : if (found)
1454 : {
1455 0 : GNUNET_array_grow (ai.denom_keys,
1456 : ai.num_denom_keys,
1457 : 0);
1458 0 : GNUNET_free (ai.auditor_url);
1459 0 : GNUNET_free (ai.auditor_name);
1460 0 : continue; /* we are done */
1461 : }
1462 12 : if (key_data->auditors_size == key_data->num_auditors)
1463 12 : GNUNET_array_grow (key_data->auditors,
1464 : key_data->auditors_size,
1465 : key_data->auditors_size * 2 + 2);
1466 12 : GNUNET_assert (key_data->auditors_size >
1467 : key_data->num_auditors);
1468 12 : GNUNET_assert (NULL != ai.auditor_url);
1469 12 : GNUNET_assert (key_data->num_auditors < UINT_MAX);
1470 12 : key_data->auditors[key_data->num_auditors++] = ai;
1471 : };
1472 : }
1473 :
1474 : /* parse the revocation/recoup information */
1475 42 : if (NULL != recoup_array)
1476 : {
1477 : json_t *recoup_info;
1478 : unsigned int index;
1479 :
1480 42 : json_array_foreach (recoup_array, index, recoup_info)
1481 : {
1482 : struct TALER_DenominationHashP h_denom_pub;
1483 : struct GNUNET_JSON_Specification spec[] = {
1484 0 : GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
1485 : &h_denom_pub),
1486 0 : GNUNET_JSON_spec_end ()
1487 : };
1488 :
1489 0 : EXITIF (GNUNET_OK !=
1490 : GNUNET_JSON_parse (recoup_info,
1491 : spec,
1492 : NULL, NULL));
1493 0 : for (unsigned int j = 0;
1494 0 : j<key_data->num_denom_keys;
1495 0 : j++)
1496 : {
1497 0 : if (0 == GNUNET_memcmp (&h_denom_pub,
1498 : &key_data->denom_keys[j].h_key))
1499 : {
1500 0 : key_data->denom_keys[j].revoked = true;
1501 0 : break;
1502 : }
1503 : }
1504 : }
1505 : }
1506 :
1507 42 : if (check_sig)
1508 : {
1509 : struct GNUNET_HashContext *hash_context;
1510 : struct GNUNET_HashCode hc;
1511 :
1512 34 : hash_context = GNUNET_CRYPTO_hash_context_start ();
1513 34 : qsort (sig_ctx.elements,
1514 34 : sig_ctx.elements_pos,
1515 : sizeof (struct SignatureElement),
1516 : &signature_context_sort_cb);
1517 850 : for (unsigned int i = 0; i<sig_ctx.elements_pos; i++)
1518 : {
1519 816 : struct SignatureElement *element = &sig_ctx.elements[i];
1520 :
1521 816 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1522 : "Adding %u,%u,%s\n",
1523 : element->group_offset,
1524 : element->offset,
1525 : TALER_B2S (&element->master_sig));
1526 816 : GNUNET_CRYPTO_hash_context_read (hash_context,
1527 816 : &element->master_sig,
1528 : sizeof (element->master_sig));
1529 : }
1530 34 : GNUNET_array_grow (sig_ctx.elements,
1531 : sig_ctx.elements_size,
1532 : 0);
1533 34 : GNUNET_CRYPTO_hash_context_finish (hash_context,
1534 : &hc);
1535 34 : EXITIF (GNUNET_OK !=
1536 : TALER_EXCHANGE_test_signing_key (key_data,
1537 : &exchange_pub));
1538 34 : EXITIF (GNUNET_OK !=
1539 : TALER_exchange_online_key_set_verify (
1540 : key_data->list_issue_date,
1541 : &hc,
1542 : &exchange_pub,
1543 : &exchange_sig));
1544 : }
1545 42 : return GNUNET_OK;
1546 :
1547 0 : EXITIF_exit:
1548 0 : *vc = TALER_EXCHANGE_VC_PROTOCOL_ERROR;
1549 0 : return GNUNET_SYSERR;
1550 : }
1551 :
1552 :
1553 : enum GNUNET_GenericReturnValue
1554 185 : TALER_EXCHANGE_test_signing_key (
1555 : const struct TALER_EXCHANGE_Keys *keys,
1556 : const struct TALER_ExchangePublicKeyP *pub)
1557 : {
1558 : struct GNUNET_TIME_Absolute now;
1559 :
1560 : /* we will check using a tolerance of 1h for the time */
1561 185 : now = GNUNET_TIME_absolute_get ();
1562 186 : for (unsigned int i = 0; i<keys->num_sign_keys; i++)
1563 186 : if ( (GNUNET_TIME_absolute_cmp (
1564 : keys->sign_keys[i].valid_from.abs_time,
1565 : <=,
1566 : GNUNET_TIME_absolute_add (now,
1567 185 : LIFETIME_TOLERANCE))) &&
1568 185 : (GNUNET_TIME_absolute_cmp (
1569 : keys->sign_keys[i].valid_until.abs_time,
1570 : >,
1571 : GNUNET_TIME_absolute_subtract (now,
1572 185 : LIFETIME_TOLERANCE))) &&
1573 185 : (0 == GNUNET_memcmp (pub,
1574 : &keys->sign_keys[i].key)) )
1575 185 : return GNUNET_OK;
1576 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1577 : "Signing key not valid at time %s\n",
1578 : GNUNET_TIME_absolute2s (now));
1579 0 : return GNUNET_SYSERR;
1580 : }
1581 :
1582 :
1583 : const struct TALER_EXCHANGE_DenomPublicKey *
1584 30 : TALER_EXCHANGE_get_denomination_key (
1585 : const struct TALER_EXCHANGE_Keys *keys,
1586 : const struct TALER_DenominationPublicKey *pk)
1587 : {
1588 102 : for (unsigned int i = 0; i<keys->num_denom_keys; i++)
1589 102 : if (0 ==
1590 102 : TALER_denom_pub_cmp (pk,
1591 102 : &keys->denom_keys[i].key))
1592 30 : return &keys->denom_keys[i];
1593 0 : return NULL;
1594 : }
1595 :
1596 :
1597 : const struct TALER_EXCHANGE_GlobalFee *
1598 13 : TALER_EXCHANGE_get_global_fee (
1599 : const struct TALER_EXCHANGE_Keys *keys,
1600 : struct GNUNET_TIME_Timestamp ts)
1601 : {
1602 13 : for (unsigned int i = 0; i<keys->num_global_fees; i++)
1603 : {
1604 13 : const struct TALER_EXCHANGE_GlobalFee *gf = &keys->global_fees[i];
1605 :
1606 13 : if (GNUNET_TIME_timestamp_cmp (ts,
1607 : >=,
1608 13 : gf->start_date) &&
1609 13 : GNUNET_TIME_timestamp_cmp (ts,
1610 : <,
1611 : gf->end_date))
1612 13 : return gf;
1613 : }
1614 0 : return NULL;
1615 : }
1616 :
1617 :
1618 : struct TALER_EXCHANGE_DenomPublicKey *
1619 72 : TALER_EXCHANGE_copy_denomination_key (
1620 : const struct TALER_EXCHANGE_DenomPublicKey *key)
1621 : {
1622 : struct TALER_EXCHANGE_DenomPublicKey *copy;
1623 :
1624 72 : copy = GNUNET_new (struct TALER_EXCHANGE_DenomPublicKey);
1625 72 : *copy = *key;
1626 72 : TALER_denom_pub_copy (©->key,
1627 : &key->key);
1628 72 : return copy;
1629 : }
1630 :
1631 :
1632 : void
1633 72 : TALER_EXCHANGE_destroy_denomination_key (
1634 : struct TALER_EXCHANGE_DenomPublicKey *key)
1635 : {
1636 72 : TALER_denom_pub_free (&key->key);
1637 72 : GNUNET_free (key);
1638 72 : }
1639 :
1640 :
1641 : const struct TALER_EXCHANGE_DenomPublicKey *
1642 113 : TALER_EXCHANGE_get_denomination_key_by_hash (
1643 : const struct TALER_EXCHANGE_Keys *keys,
1644 : const struct TALER_DenominationHashP *hc)
1645 : {
1646 : /* FIXME-optimization: should we maybe use a hash map here? */
1647 2424 : for (unsigned int i = 0; i<keys->num_denom_keys; i++)
1648 2424 : if (0 == GNUNET_memcmp (hc,
1649 : &keys->denom_keys[i].h_key))
1650 113 : return &keys->denom_keys[i];
1651 0 : return NULL;
1652 : }
1653 :
1654 :
1655 : struct TALER_EXCHANGE_Keys *
1656 377 : TALER_EXCHANGE_keys_incref (struct TALER_EXCHANGE_Keys *keys)
1657 : {
1658 377 : GNUNET_assert (keys->rc < UINT_MAX);
1659 377 : keys->rc++;
1660 377 : return keys;
1661 : }
1662 :
1663 :
1664 : void
1665 473 : TALER_EXCHANGE_keys_decref (struct TALER_EXCHANGE_Keys *keys)
1666 : {
1667 473 : if (NULL == keys)
1668 54 : return;
1669 419 : GNUNET_assert (0 < keys->rc);
1670 419 : keys->rc--;
1671 419 : if (0 != keys->rc)
1672 377 : return;
1673 42 : GNUNET_array_grow (keys->sign_keys,
1674 : keys->num_sign_keys,
1675 : 0);
1676 1042 : for (unsigned int i = 0; i<keys->num_denom_keys; i++)
1677 1000 : TALER_denom_pub_free (&keys->denom_keys[i].key);
1678 42 : keys->num_denom_keys = 0;
1679 42 : GNUNET_array_grow (keys->denom_keys,
1680 : keys->denom_keys_size,
1681 : 0);
1682 56 : for (unsigned int i = 0; i<keys->num_auditors; i++)
1683 : {
1684 14 : GNUNET_array_grow (keys->auditors[i].denom_keys,
1685 : keys->auditors[i].num_denom_keys,
1686 : 0);
1687 14 : GNUNET_free (keys->auditors[i].auditor_url);
1688 14 : GNUNET_free (keys->auditors[i].auditor_name);
1689 : }
1690 42 : GNUNET_array_grow (keys->auditors,
1691 : keys->auditors_size,
1692 : 0);
1693 42 : TALER_EXCHANGE_free_accounts (keys->accounts_len,
1694 : keys->accounts);
1695 42 : GNUNET_array_grow (keys->accounts,
1696 : keys->accounts_len,
1697 : 0);
1698 42 : free_fees (keys->fees,
1699 : keys->fees_len);
1700 42 : GNUNET_array_grow (keys->hard_limits,
1701 : keys->hard_limits_length,
1702 : 0);
1703 42 : GNUNET_array_grow (keys->zero_limits,
1704 : keys->zero_limits_length,
1705 : 0);
1706 42 : json_decref (keys->extensions);
1707 42 : GNUNET_free (keys->cspec.name);
1708 42 : json_decref (keys->cspec.map_alt_unit_names);
1709 42 : GNUNET_array_grow (keys->cspec.common_amounts,
1710 : keys->cspec.num_common_amounts,
1711 : 0);
1712 42 : GNUNET_free (keys->wallet_balance_limit_without_kyc);
1713 42 : GNUNET_free (keys->version);
1714 42 : GNUNET_free (keys->currency);
1715 42 : GNUNET_free (keys->asset_type);
1716 42 : GNUNET_free (keys->shopping_url);
1717 42 : GNUNET_free (keys->open_banking_gateway);
1718 42 : GNUNET_free (keys->wire_transfer_gateway);
1719 42 : GNUNET_free (keys->bank_compliance_language);
1720 42 : for (unsigned int i = 0; i < keys->num_wad_partners; i++)
1721 0 : GNUNET_free (keys->wad_partners[i].partner_base_url);
1722 42 : GNUNET_free (keys->wad_partners);
1723 42 : GNUNET_free (keys->global_fees);
1724 42 : GNUNET_free (keys->exchange_url);
1725 42 : GNUNET_free (keys);
1726 : }
1727 :
1728 :
1729 : struct TALER_EXCHANGE_Keys *
1730 8 : TALER_EXCHANGE_keys_from_json (const json_t *j)
1731 : {
1732 : const json_t *jkeys;
1733 : const char *url;
1734 : uint32_t version;
1735 8 : struct GNUNET_TIME_Timestamp expire
1736 : = GNUNET_TIME_UNIT_ZERO_TS;
1737 : struct GNUNET_JSON_Specification spec[] = {
1738 8 : GNUNET_JSON_spec_uint32 ("version",
1739 : &version),
1740 8 : GNUNET_JSON_spec_object_const ("keys",
1741 : &jkeys),
1742 8 : TALER_JSON_spec_web_url ("exchange_url",
1743 : &url),
1744 8 : GNUNET_JSON_spec_mark_optional (
1745 : GNUNET_JSON_spec_timestamp ("expire",
1746 : &expire),
1747 : NULL),
1748 8 : GNUNET_JSON_spec_end ()
1749 : };
1750 : struct TALER_EXCHANGE_Keys *keys;
1751 : enum TALER_EXCHANGE_VersionCompatibility compat;
1752 :
1753 8 : if (NULL == j)
1754 0 : return NULL;
1755 8 : if (GNUNET_OK !=
1756 8 : GNUNET_JSON_parse (j,
1757 : spec,
1758 : NULL, NULL))
1759 : {
1760 0 : GNUNET_break_op (0);
1761 0 : return NULL;
1762 : }
1763 8 : if (0 != version)
1764 : {
1765 0 : return NULL; /* unsupported version */
1766 : }
1767 8 : keys = GNUNET_new (struct TALER_EXCHANGE_Keys);
1768 8 : if (GNUNET_OK !=
1769 8 : TALER_EXCHANGE_decode_keys_json_ (jkeys,
1770 : false,
1771 : keys,
1772 : &compat))
1773 : {
1774 0 : GNUNET_break (0);
1775 0 : return NULL;
1776 : }
1777 8 : keys->rc = 1;
1778 8 : keys->key_data_expiration = expire;
1779 8 : keys->exchange_url = GNUNET_strdup (url);
1780 8 : return keys;
1781 : }
1782 :
1783 :
1784 : /**
1785 : * Data we track per denomination group.
1786 : */
1787 : struct GroupData
1788 : {
1789 : /**
1790 : * The json blob with the group meta-data and list of denominations
1791 : */
1792 : json_t *json;
1793 :
1794 : /**
1795 : * Meta data for this group.
1796 : */
1797 : struct TALER_DenominationGroup meta;
1798 : };
1799 :
1800 :
1801 : /**
1802 : * Add denomination group represented by @a value
1803 : * to list of denominations in @a cls. Also frees
1804 : * the @a value.
1805 : *
1806 : * @param[in,out] cls a `json_t *` with an array to build
1807 : * @param key unused
1808 : * @param value a `struct GroupData *`
1809 : * @return #GNUNET_OK (continue to iterate)
1810 : */
1811 : static enum GNUNET_GenericReturnValue
1812 26 : add_grp (void *cls,
1813 : const struct GNUNET_HashCode *key,
1814 : void *value)
1815 : {
1816 26 : json_t *denominations_by_group = cls;
1817 26 : struct GroupData *gd = value;
1818 : const char *cipher;
1819 : json_t *ge;
1820 26 : bool age_restricted = gd->meta.age_mask.bits != 0;
1821 :
1822 : (void) key;
1823 26 : switch (gd->meta.cipher)
1824 : {
1825 13 : case GNUNET_CRYPTO_BSA_RSA:
1826 13 : cipher = age_restricted ? "RSA+age_restricted" : "RSA";
1827 13 : break;
1828 13 : case GNUNET_CRYPTO_BSA_CS:
1829 13 : cipher = age_restricted ? "CS+age_restricted" : "CS";
1830 13 : break;
1831 0 : default:
1832 0 : GNUNET_assert (false);
1833 : }
1834 :
1835 26 : ge = GNUNET_JSON_PACK (
1836 : GNUNET_JSON_pack_string ("cipher",
1837 : cipher),
1838 : GNUNET_JSON_pack_array_steal ("denoms",
1839 : gd->json),
1840 : TALER_JSON_PACK_DENOM_FEES ("fee",
1841 : &gd->meta.fees),
1842 : GNUNET_JSON_pack_allow_null (
1843 : age_restricted
1844 : ? GNUNET_JSON_pack_uint64 ("age_mask",
1845 : gd->meta.age_mask.bits)
1846 : : GNUNET_JSON_pack_string ("dummy",
1847 : NULL)),
1848 : TALER_JSON_pack_amount ("value",
1849 : &gd->meta.value));
1850 26 : GNUNET_assert (0 ==
1851 : json_array_append_new (denominations_by_group,
1852 : ge));
1853 26 : GNUNET_free (gd);
1854 26 : return GNUNET_OK;
1855 : }
1856 :
1857 :
1858 : /**
1859 : * Convert array of account restrictions @a ars to JSON.
1860 : *
1861 : * @param ar_len length of @a ars
1862 : * @param ars account restrictions to convert
1863 : * @return JSON representation
1864 : */
1865 : static json_t *
1866 16 : ar_to_json (unsigned int ar_len,
1867 : const struct TALER_EXCHANGE_AccountRestriction ars[static ar_len])
1868 16 : {
1869 : json_t *rval;
1870 :
1871 16 : rval = json_array ();
1872 16 : GNUNET_assert (NULL != rval);
1873 16 : for (unsigned int i = 0; i<ar_len; i++)
1874 : {
1875 0 : const struct TALER_EXCHANGE_AccountRestriction *ar = &ars[i];
1876 :
1877 0 : switch (ar->type)
1878 : {
1879 0 : case TALER_EXCHANGE_AR_INVALID:
1880 0 : GNUNET_break (0);
1881 0 : json_decref (rval);
1882 0 : return NULL;
1883 0 : case TALER_EXCHANGE_AR_DENY:
1884 0 : GNUNET_assert (
1885 : 0 ==
1886 : json_array_append_new (
1887 : rval,
1888 : GNUNET_JSON_PACK (
1889 : GNUNET_JSON_pack_string ("type",
1890 : "deny"))));
1891 0 : break;
1892 0 : case TALER_EXCHANGE_AR_REGEX:
1893 0 : GNUNET_assert (
1894 : 0 ==
1895 : json_array_append_new (
1896 : rval,
1897 : GNUNET_JSON_PACK (
1898 : GNUNET_JSON_pack_string (
1899 : "type",
1900 : "regex"),
1901 : GNUNET_JSON_pack_string (
1902 : "payto_regex",
1903 : ar->details.regex.posix_egrep),
1904 : GNUNET_JSON_pack_string (
1905 : "human_hint",
1906 : ar->details.regex.human_hint),
1907 : GNUNET_JSON_pack_object_incref (
1908 : "human_hint_i18n",
1909 : (json_t *) ar->details.regex.human_hint_i18n)
1910 : )));
1911 0 : break;
1912 : }
1913 : }
1914 16 : return rval;
1915 : }
1916 :
1917 :
1918 : json_t *
1919 8 : TALER_EXCHANGE_keys_to_json (const struct TALER_EXCHANGE_Keys *kd)
1920 : {
1921 : struct GNUNET_TIME_Timestamp now;
1922 : json_t *keys;
1923 : json_t *signkeys;
1924 : json_t *denominations_by_group;
1925 : json_t *auditors;
1926 : json_t *recoup;
1927 : json_t *wire_fees;
1928 : json_t *accounts;
1929 : json_t *global_fees;
1930 8 : json_t *wblwk = NULL;
1931 : json_t *wads_json;
1932 : json_t *hard_limits;
1933 : json_t *zero_limits;
1934 :
1935 8 : now = GNUNET_TIME_timestamp_get ();
1936 8 : signkeys = json_array ();
1937 8 : GNUNET_assert (NULL != signkeys);
1938 16 : for (unsigned int i = 0; i<kd->num_sign_keys; i++)
1939 : {
1940 8 : const struct TALER_EXCHANGE_SigningPublicKey *sk = &kd->sign_keys[i];
1941 : json_t *signkey;
1942 :
1943 8 : if (GNUNET_TIME_timestamp_cmp (now,
1944 : >,
1945 : sk->valid_until))
1946 0 : continue; /* skip keys that have expired */
1947 8 : signkey = GNUNET_JSON_PACK (
1948 : GNUNET_JSON_pack_data_auto ("key",
1949 : &sk->key),
1950 : GNUNET_JSON_pack_data_auto ("master_sig",
1951 : &sk->master_sig),
1952 : GNUNET_JSON_pack_timestamp ("stamp_start",
1953 : sk->valid_from),
1954 : GNUNET_JSON_pack_timestamp ("stamp_expire",
1955 : sk->valid_until),
1956 : GNUNET_JSON_pack_timestamp ("stamp_end",
1957 : sk->valid_legal));
1958 8 : GNUNET_assert (NULL != signkey);
1959 8 : GNUNET_assert (0 ==
1960 : json_array_append_new (signkeys,
1961 : signkey));
1962 : }
1963 :
1964 8 : denominations_by_group = json_array ();
1965 8 : GNUNET_assert (NULL != denominations_by_group);
1966 : {
1967 : struct GNUNET_CONTAINER_MultiHashMap *dbg;
1968 :
1969 8 : dbg = GNUNET_CONTAINER_multihashmap_create (128,
1970 : false);
1971 113 : for (unsigned int i = 0; i<kd->num_denom_keys; i++)
1972 : {
1973 105 : const struct TALER_EXCHANGE_DenomPublicKey *dk = &kd->denom_keys[i];
1974 105 : struct TALER_DenominationGroup meta = {
1975 105 : .cipher = dk->key.bsign_pub_key->cipher,
1976 : .value = dk->value,
1977 : .fees = dk->fees,
1978 : .age_mask = dk->key.age_mask
1979 : };
1980 : struct GNUNET_HashCode key;
1981 : struct GroupData *gd;
1982 : json_t *denom;
1983 : struct GNUNET_JSON_PackSpec key_spec;
1984 :
1985 105 : if (GNUNET_TIME_timestamp_cmp (now,
1986 : >,
1987 : dk->expire_deposit))
1988 0 : continue; /* skip keys that have expired */
1989 105 : TALER_denomination_group_get_key (&meta,
1990 : &key);
1991 105 : gd = GNUNET_CONTAINER_multihashmap_get (dbg,
1992 : &key);
1993 105 : if (NULL == gd)
1994 : {
1995 26 : gd = GNUNET_new (struct GroupData);
1996 26 : gd->meta = meta;
1997 26 : gd->json = json_array ();
1998 26 : GNUNET_assert (NULL != gd->json);
1999 26 : GNUNET_assert (
2000 : GNUNET_OK ==
2001 : GNUNET_CONTAINER_multihashmap_put (dbg,
2002 : &key,
2003 : gd,
2004 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2005 :
2006 : }
2007 105 : switch (meta.cipher)
2008 : {
2009 52 : case GNUNET_CRYPTO_BSA_RSA:
2010 : key_spec =
2011 52 : GNUNET_JSON_pack_rsa_public_key (
2012 : "rsa_pub",
2013 52 : dk->key.bsign_pub_key->details.rsa_public_key);
2014 52 : break;
2015 53 : case GNUNET_CRYPTO_BSA_CS:
2016 : key_spec =
2017 53 : GNUNET_JSON_pack_data_varsize (
2018 : "cs_pub",
2019 53 : &dk->key.bsign_pub_key->details.cs_public_key,
2020 : sizeof (dk->key.bsign_pub_key->details.cs_public_key));
2021 53 : break;
2022 0 : default:
2023 0 : GNUNET_assert (false);
2024 : }
2025 105 : denom = GNUNET_JSON_PACK (
2026 : GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
2027 : dk->expire_deposit),
2028 : GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
2029 : dk->withdraw_valid_until),
2030 : GNUNET_JSON_pack_timestamp ("stamp_start",
2031 : dk->valid_from),
2032 : GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
2033 : dk->expire_legal),
2034 : GNUNET_JSON_pack_data_auto ("master_sig",
2035 : &dk->master_sig),
2036 : key_spec
2037 : );
2038 105 : GNUNET_assert (0 ==
2039 : json_array_append_new (gd->json,
2040 : denom));
2041 : }
2042 8 : GNUNET_CONTAINER_multihashmap_iterate (dbg,
2043 : &add_grp,
2044 : denominations_by_group);
2045 8 : GNUNET_CONTAINER_multihashmap_destroy (dbg);
2046 : }
2047 :
2048 8 : auditors = json_array ();
2049 8 : GNUNET_assert (NULL != auditors);
2050 10 : for (unsigned int i = 0; i<kd->num_auditors; i++)
2051 : {
2052 2 : const struct TALER_EXCHANGE_AuditorInformation *ai = &kd->auditors[i];
2053 : json_t *a;
2054 : json_t *adenoms;
2055 :
2056 2 : adenoms = json_array ();
2057 2 : GNUNET_assert (NULL != adenoms);
2058 2 : for (unsigned int j = 0; j<ai->num_denom_keys; j++)
2059 : {
2060 0 : const struct TALER_EXCHANGE_AuditorDenominationInfo *adi =
2061 0 : &ai->denom_keys[j];
2062 0 : const struct TALER_EXCHANGE_DenomPublicKey *dk =
2063 0 : &kd->denom_keys[adi->denom_key_offset];
2064 : json_t *k;
2065 :
2066 0 : GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys);
2067 0 : if (GNUNET_TIME_timestamp_cmp (now,
2068 : >,
2069 : dk->expire_deposit))
2070 0 : continue; /* skip auditor signatures for denomination keys that have expired */
2071 0 : GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys);
2072 0 : k = GNUNET_JSON_PACK (
2073 : GNUNET_JSON_pack_data_auto ("denom_pub_h",
2074 : &dk->h_key),
2075 : GNUNET_JSON_pack_data_auto ("auditor_sig",
2076 : &adi->auditor_sig));
2077 0 : GNUNET_assert (0 ==
2078 : json_array_append_new (adenoms,
2079 : k));
2080 : }
2081 :
2082 2 : a = GNUNET_JSON_PACK (
2083 : GNUNET_JSON_pack_data_auto ("auditor_pub",
2084 : &ai->auditor_pub),
2085 : GNUNET_JSON_pack_string ("auditor_url",
2086 : ai->auditor_url),
2087 : GNUNET_JSON_pack_string ("auditor_name",
2088 : ai->auditor_name),
2089 : GNUNET_JSON_pack_array_steal ("denomination_keys",
2090 : adenoms));
2091 2 : GNUNET_assert (0 ==
2092 : json_array_append_new (auditors,
2093 : a));
2094 : }
2095 :
2096 8 : global_fees = json_array ();
2097 8 : GNUNET_assert (NULL != global_fees);
2098 24 : for (unsigned int i = 0; i<kd->num_global_fees; i++)
2099 : {
2100 16 : const struct TALER_EXCHANGE_GlobalFee *gf
2101 16 : = &kd->global_fees[i];
2102 :
2103 16 : if (GNUNET_TIME_absolute_is_past (gf->end_date.abs_time))
2104 0 : continue;
2105 16 : GNUNET_assert (
2106 : 0 ==
2107 : json_array_append_new (
2108 : global_fees,
2109 : GNUNET_JSON_PACK (
2110 : GNUNET_JSON_pack_timestamp ("start_date",
2111 : gf->start_date),
2112 : GNUNET_JSON_pack_timestamp ("end_date",
2113 : gf->end_date),
2114 : TALER_JSON_PACK_GLOBAL_FEES (&gf->fees),
2115 : GNUNET_JSON_pack_time_rel ("history_expiration",
2116 : gf->history_expiration),
2117 : GNUNET_JSON_pack_time_rel ("purse_timeout",
2118 : gf->purse_timeout),
2119 : GNUNET_JSON_pack_uint64 ("purse_account_limit",
2120 : gf->purse_account_limit),
2121 : GNUNET_JSON_pack_data_auto ("master_sig",
2122 : &gf->master_sig))));
2123 : }
2124 :
2125 8 : accounts = json_array ();
2126 8 : GNUNET_assert (NULL != accounts);
2127 16 : for (unsigned int i = 0; i<kd->accounts_len; i++)
2128 : {
2129 8 : const struct TALER_EXCHANGE_WireAccount *acc
2130 8 : = &kd->accounts[i];
2131 : json_t *credit_restrictions;
2132 : json_t *debit_restrictions;
2133 :
2134 : credit_restrictions
2135 8 : = ar_to_json (acc->credit_restrictions_length,
2136 8 : acc->credit_restrictions);
2137 8 : GNUNET_assert (NULL != credit_restrictions);
2138 : debit_restrictions
2139 8 : = ar_to_json (acc->debit_restrictions_length,
2140 8 : acc->debit_restrictions);
2141 8 : GNUNET_assert (NULL != debit_restrictions);
2142 8 : GNUNET_assert (
2143 : 0 ==
2144 : json_array_append_new (
2145 : accounts,
2146 : GNUNET_JSON_PACK (
2147 : TALER_JSON_pack_full_payto ("payto_uri",
2148 : acc->fpayto_uri),
2149 : GNUNET_JSON_pack_allow_null (
2150 : GNUNET_JSON_pack_string ("conversion_url",
2151 : acc->conversion_url)),
2152 : GNUNET_JSON_pack_int64 ("priority",
2153 : acc->priority),
2154 : GNUNET_JSON_pack_allow_null (
2155 : GNUNET_JSON_pack_string ("bank_label",
2156 : acc->bank_label)),
2157 : GNUNET_JSON_pack_array_steal ("debit_restrictions",
2158 : debit_restrictions),
2159 : GNUNET_JSON_pack_array_steal ("credit_restrictions",
2160 : credit_restrictions),
2161 : GNUNET_JSON_pack_data_auto ("master_sig",
2162 : &acc->master_sig))));
2163 : }
2164 8 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2165 : "Serialized %u/%u wire accounts to JSON\n",
2166 : (unsigned int) json_array_size (accounts),
2167 : kd->accounts_len);
2168 :
2169 8 : wire_fees = json_object ();
2170 8 : GNUNET_assert (NULL != wire_fees);
2171 16 : for (unsigned int i = 0; i<kd->fees_len; i++)
2172 : {
2173 8 : const struct TALER_EXCHANGE_WireFeesByMethod *fbw
2174 8 : = &kd->fees[i];
2175 : json_t *wf;
2176 :
2177 8 : wf = json_array ();
2178 8 : GNUNET_assert (NULL != wf);
2179 8 : for (struct TALER_EXCHANGE_WireAggregateFees *p = fbw->fees_head;
2180 24 : NULL != p;
2181 16 : p = p->next)
2182 : {
2183 16 : GNUNET_assert (
2184 : 0 ==
2185 : json_array_append_new (
2186 : wf,
2187 : GNUNET_JSON_PACK (
2188 : TALER_JSON_pack_amount ("wire_fee",
2189 : &p->fees.wire),
2190 : TALER_JSON_pack_amount ("closing_fee",
2191 : &p->fees.closing),
2192 : GNUNET_JSON_pack_timestamp ("start_date",
2193 : p->start_date),
2194 : GNUNET_JSON_pack_timestamp ("end_date",
2195 : p->end_date),
2196 : GNUNET_JSON_pack_data_auto ("sig",
2197 : &p->master_sig))));
2198 : }
2199 8 : GNUNET_assert (0 ==
2200 : json_object_set_new (wire_fees,
2201 : fbw->method,
2202 : wf));
2203 : }
2204 :
2205 8 : recoup = json_array ();
2206 8 : GNUNET_assert (NULL != recoup);
2207 113 : for (unsigned int i = 0; i<kd->num_denom_keys; i++)
2208 : {
2209 105 : const struct TALER_EXCHANGE_DenomPublicKey *dk
2210 105 : = &kd->denom_keys[i];
2211 105 : if (! dk->revoked)
2212 105 : continue;
2213 0 : GNUNET_assert (0 ==
2214 : json_array_append_new (
2215 : recoup,
2216 : GNUNET_JSON_PACK (
2217 : GNUNET_JSON_pack_data_auto ("h_denom_pub",
2218 : &dk->h_key))));
2219 : }
2220 :
2221 8 : wblwk = json_array ();
2222 8 : GNUNET_assert (NULL != wblwk);
2223 8 : for (unsigned int i = 0; i<kd->wblwk_length; i++)
2224 : {
2225 0 : const struct TALER_Amount *a = &kd->wallet_balance_limit_without_kyc[i];
2226 :
2227 0 : GNUNET_assert (0 ==
2228 : json_array_append_new (
2229 : wblwk,
2230 : TALER_JSON_from_amount (a)));
2231 : }
2232 :
2233 8 : hard_limits = json_array ();
2234 8 : for (unsigned int i = 0; i < kd->hard_limits_length; i++)
2235 : {
2236 0 : const struct TALER_EXCHANGE_AccountLimit *al
2237 0 : = &kd->hard_limits[i];
2238 : json_t *j;
2239 :
2240 0 : j = GNUNET_JSON_PACK (
2241 : TALER_JSON_pack_amount ("threshold",
2242 : &al->threshold),
2243 : GNUNET_JSON_pack_time_rel ("timeframe",
2244 : al->timeframe),
2245 : TALER_JSON_pack_kycte ("operation_type",
2246 : al->operation_type),
2247 : GNUNET_JSON_pack_bool ("soft_limit",
2248 : al->soft_limit)
2249 : );
2250 0 : GNUNET_assert (0 ==
2251 : json_array_append_new (
2252 : hard_limits,
2253 : j));
2254 : }
2255 :
2256 8 : zero_limits = json_array ();
2257 10 : for (unsigned int i = 0; i < kd->zero_limits_length; i++)
2258 : {
2259 2 : const struct TALER_EXCHANGE_ZeroLimitedOperation *zol
2260 2 : = &kd->zero_limits[i];
2261 : json_t *j;
2262 :
2263 2 : j = GNUNET_JSON_PACK (
2264 : TALER_JSON_pack_kycte ("operation_type",
2265 : zol->operation_type)
2266 : );
2267 2 : GNUNET_assert (0 ==
2268 : json_array_append_new (
2269 : zero_limits,
2270 : j));
2271 : }
2272 :
2273 8 : wads_json = json_array ();
2274 8 : GNUNET_assert (NULL != wads_json);
2275 8 : for (unsigned int i = 0; i < kd->num_wad_partners; i++)
2276 : {
2277 0 : const struct TALER_EXCHANGE_WadPartner *wp
2278 0 : = &kd->wad_partners[i];
2279 :
2280 0 : GNUNET_assert (
2281 : 0 ==
2282 : json_array_append_new (
2283 : wads_json,
2284 : GNUNET_JSON_PACK (
2285 : GNUNET_JSON_pack_string ("partner_base_url",
2286 : wp->partner_base_url),
2287 : GNUNET_JSON_pack_data_auto ("partner_master_pub",
2288 : &wp->partner_master_pub),
2289 : TALER_JSON_pack_amount ("wad_fee",
2290 : &wp->wad_fee),
2291 : GNUNET_JSON_pack_time_rel ("wad_frequency",
2292 : wp->wad_frequency),
2293 : GNUNET_JSON_pack_timestamp ("start_date",
2294 : wp->start_date),
2295 : GNUNET_JSON_pack_timestamp ("end_date",
2296 : wp->end_date),
2297 : GNUNET_JSON_pack_data_auto ("master_sig",
2298 : &wp->master_sig))));
2299 : }
2300 :
2301 8 : keys = GNUNET_JSON_PACK (
2302 : GNUNET_JSON_pack_string ("version",
2303 : kd->version),
2304 : GNUNET_JSON_pack_string ("currency",
2305 : kd->currency),
2306 : GNUNET_JSON_pack_object_steal ("currency_specification",
2307 : TALER_JSON_currency_specs_to_json (
2308 : &kd->cspec)),
2309 : TALER_JSON_pack_amount ("stefan_abs",
2310 : &kd->stefan_abs),
2311 : TALER_JSON_pack_amount ("stefan_log",
2312 : &kd->stefan_log),
2313 : GNUNET_JSON_pack_double ("stefan_lin",
2314 : kd->stefan_lin),
2315 : GNUNET_JSON_pack_allow_null (
2316 : kd->tiny_amount_available
2317 : ? TALER_JSON_pack_amount ("tiny_amount",
2318 : &kd->tiny_amount)
2319 : : GNUNET_JSON_pack_string ("dummy",
2320 : NULL)),
2321 : GNUNET_JSON_pack_string ("asset_type",
2322 : kd->asset_type),
2323 : GNUNET_JSON_pack_allow_null (
2324 : GNUNET_JSON_pack_string ("shopping_url",
2325 : kd->shopping_url)),
2326 : GNUNET_JSON_pack_allow_null (
2327 : GNUNET_JSON_pack_string ("open_banking_gateway",
2328 : kd->open_banking_gateway)),
2329 : GNUNET_JSON_pack_allow_null (
2330 : GNUNET_JSON_pack_string ("wire_transfer_gateway",
2331 : kd->wire_transfer_gateway)),
2332 : GNUNET_JSON_pack_allow_null (
2333 : GNUNET_JSON_pack_string ("bank_compliance_language",
2334 : kd->bank_compliance_language)),
2335 : GNUNET_JSON_pack_bool ("disable_direct_deposit",
2336 : kd->disable_direct_deposit),
2337 : GNUNET_JSON_pack_data_auto ("master_public_key",
2338 : &kd->master_pub),
2339 : GNUNET_JSON_pack_time_rel ("reserve_closing_delay",
2340 : kd->reserve_closing_delay),
2341 : GNUNET_JSON_pack_timestamp ("list_issue_date",
2342 : kd->list_issue_date),
2343 : GNUNET_JSON_pack_array_steal ("global_fees",
2344 : global_fees),
2345 : GNUNET_JSON_pack_array_steal ("signkeys",
2346 : signkeys),
2347 : GNUNET_JSON_pack_object_steal ("wire_fees",
2348 : wire_fees),
2349 : GNUNET_JSON_pack_array_steal ("accounts",
2350 : accounts),
2351 : GNUNET_JSON_pack_array_steal ("wads",
2352 : wads_json),
2353 : GNUNET_JSON_pack_array_steal ("hard_limits",
2354 : hard_limits),
2355 : GNUNET_JSON_pack_array_steal ("zero_limits",
2356 : zero_limits),
2357 : GNUNET_JSON_pack_array_steal ("denominations",
2358 : denominations_by_group),
2359 : GNUNET_JSON_pack_allow_null (
2360 : GNUNET_JSON_pack_array_steal ("recoup",
2361 : recoup)),
2362 : GNUNET_JSON_pack_array_steal ("auditors",
2363 : auditors),
2364 : GNUNET_JSON_pack_bool ("kyc_enabled",
2365 : kd->kyc_enabled),
2366 : GNUNET_JSON_pack_allow_null (
2367 : GNUNET_JSON_pack_object_incref ("extensions",
2368 : kd->extensions)),
2369 : GNUNET_JSON_pack_allow_null (
2370 : GNUNET_is_zero (&kd->extensions_sig)
2371 : ? GNUNET_JSON_pack_string ("dummy",
2372 : NULL)
2373 : : GNUNET_JSON_pack_data_auto ("extensions_sig",
2374 : &kd->extensions_sig)),
2375 : GNUNET_JSON_pack_allow_null (
2376 : GNUNET_JSON_pack_array_steal ("wallet_balance_limit_without_kyc",
2377 : wblwk))
2378 :
2379 : );
2380 8 : return GNUNET_JSON_PACK (
2381 : GNUNET_JSON_pack_uint64 ("version",
2382 : EXCHANGE_SERIALIZATION_FORMAT_VERSION),
2383 : GNUNET_JSON_pack_allow_null (
2384 : GNUNET_JSON_pack_timestamp ("expire",
2385 : kd->key_data_expiration)),
2386 : GNUNET_JSON_pack_string ("exchange_url",
2387 : kd->exchange_url),
2388 : GNUNET_JSON_pack_object_steal ("keys",
2389 : keys));
2390 : }
2391 :
2392 :
2393 : /* end of exchange_api_handle.c */
|